diff --git a/backend/analysis/api.py b/backend/analysis/api.py index 0b5ad353c8ee2a5e1517008b70c343c33e72059a..2bbe6634f5a508b9958262d3376ef448138085da 100644 --- a/backend/analysis/api.py +++ b/backend/analysis/api.py @@ -2,7 +2,7 @@ import os from tempfile import mkstemp from django.conf import settings -from ninja import Router, File +from ninja import Router, File, Form from ninja.files import UploadedFile from django_to_galaxy.models import GalaxyInstance @@ -23,6 +23,7 @@ from django.http import JsonResponse, FileResponse from analysis.model_schemas import ( AnalysisOutSchema, AnalysisInSchema, + AnalysisPayload, Error, GeneOutSchema, HmmerOutSchema, @@ -63,11 +64,13 @@ def login(request): @router.post("add", response={200: AnalysisOutSchema, 503: Error}) def add( request, + payload: AnalysisPayload = Form(...), genomefile: UploadedFile = File(...), ): fd, genome_path = mkstemp( prefix="defense-finder-", suffix="-sequences-input.fasta", dir="/uploaded-files" ) + with open(genome_path, "wb+") as f: for chunk in genomefile.chunks(): f.write(chunk) @@ -91,7 +94,8 @@ def add( input_files = [ genome_path, ] - params = {} + + params = {"1": payload.dict()} analysis = aw.invoke(session, input_files, params, f"{genomefile.name}") return analysis @@ -100,6 +104,7 @@ def add( @router.post("add-example", response={200: AnalysisOutSchema, 503: Error}) def add_example( request, + payload: AnalysisPayload, ): request.session.set_expiry(session_expiry) if request.session.session_key: @@ -117,12 +122,12 @@ def add_example( is_galaxy_online = aw.analysis_owner.galaxy_instance.is_online() if not is_galaxy_online: return 503, {"message": "The Galaxy instance is offline"} - print(settings.BASE_DIR) input_files = [ f"{settings.BASE_DIR}/analysis/data/GCF_000005845.faa", ] - params = {} + params = {"1": payload.dict()} + analysis = aw.invoke(session, input_files, params, "GCF_000005845.faa") return analysis diff --git a/backend/analysis/model_schemas.py b/backend/analysis/model_schemas.py index 7df65d0ca7459690aacffb89c290dca4c2b22083..ecfe7c1dd56e6f9e7ae1de3eb594b74ed6b523f3 100644 --- a/backend/analysis/model_schemas.py +++ b/backend/analysis/model_schemas.py @@ -62,6 +62,10 @@ class Error(Schema): message: str +class AnalysisPayload(Schema): + antidefensefinder: bool + + class GeneOutSchema(ModelSchema): genes: List[GeneEntry] diff --git a/backend/analysis/models.py b/backend/analysis/models.py index a3c831b6a38b304c271aa0b13d56fccbdca04692..6c0ed6c29f5948f654d1458c359bab341d73960b 100644 --- a/backend/analysis/models.py +++ b/backend/analysis/models.py @@ -75,6 +75,7 @@ class AnalysisWorkflow(Workflow): history, datamap, params = self.prepare_invocation( session, input_files, params, history_name ) + print(params) galaxy_inv = self.galaxy_workflow.invoke( datamap, history=history.galaxy_history, params=params ) diff --git a/backend/analysis/schemas.py b/backend/analysis/schemas.py index db4ce9d154ca611f9164b28810a6b0c32f60ab01..85c1b9fe67804a236051bbb1cf7192c4ec94ca65 100644 --- a/backend/analysis/schemas.py +++ b/backend/analysis/schemas.py @@ -4,6 +4,7 @@ from ninja import Schema class GeneEntry(Schema): replicon: str + activity: Optional[str] hit_id: str gene_name: str hit_pos: int @@ -30,6 +31,7 @@ class GeneEntry(Schema): class SystemEntry(Schema): sys_id: str type: str + activity: Optional[str] subtype: str sys_beg: str sys_end: str diff --git a/backend/poetry.lock b/backend/poetry.lock index cadcff4180946868fdc6f8cbb36ec8361a40db33..5f8d3b9d632558d6bdd1a23a4d2ff2837cef3b0e 100644 --- a/backend/poetry.lock +++ b/backend/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand. [[package]] name = "appdirs" @@ -359,13 +359,13 @@ test = ["black", "django-stubs", "flake8", "isort", "mypy (==0.931)", "psycopg2- [[package]] name = "django-to-galaxy" -version = "0.6.4" +version = "0.6.9" description = "Django extension that eases communication with Galaxy instance to execute workflows." optional = false -python-versions = ">=3.9,<4.0" +python-versions = "<4.0,>=3.9" files = [ - {file = "django_to_galaxy-0.6.4-py3-none-any.whl", hash = "sha256:5e813d45eba6cbb5dab4737c2d5b464f46f33119e2828148860b842a4a272ef8"}, - {file = "django_to_galaxy-0.6.4.tar.gz", hash = "sha256:27e7026b276c8b18fb84715b3a8a6b6f06d63d9994b6d00bc118ca7d53127722"}, + {file = "django_to_galaxy-0.6.9-py3-none-any.whl", hash = "sha256:12fde5b9067ae967bbdf412f177f5e67e6b25a1f995639b3ed31170f77282826"}, + {file = "django_to_galaxy-0.6.9.tar.gz", hash = "sha256:2f9506905069a093fb76adea8b5de57bc64a12f438dbce88179918997e0f7f0e"}, ] [package.dependencies] @@ -979,4 +979,4 @@ zstd = ["zstandard (>=0.18.0)"] [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "0178257066e14753b45a43635af1b8fb9ab5f4773148e50f2ae63573f08e98b7" +content-hash = "096a9a4ca3a3446ca43aa8ac13a60c8f9856b9395e379397167f50e66d7c6587" diff --git a/backend/pyproject.toml b/backend/pyproject.toml index 684756c6a271798c4c052f1fac5f97f9a05bf089..5ade0929ad784a8886f5e6da09bcaef8769e32af 100644 --- a/backend/pyproject.toml +++ b/backend/pyproject.toml @@ -9,7 +9,7 @@ readme = "README.md" python = "^3.10" django-ninja = "^0.22.2" psycopg = {extras = ["binary"], version = "^3.1.9"} -django-to-galaxy = "^0.6.4" +django-to-galaxy = "^0.6.9" django-environ = "^0.10.0" gunicorn = "^21.2.0" biopython = "^1.83" diff --git a/frontend/components/AnalysisResultDataTable.vue b/frontend/components/AnalysisResultDataTable.vue index 423921ae0602bd1dd304fd077ffec303b3277dc2..4a1f5f8163b012db6bd4f94e2d99c9a5eaab7112 100644 --- a/frontend/components/AnalysisResultDataTable.vue +++ b/frontend/components/AnalysisResultDataTable.vue @@ -64,7 +64,11 @@ const dataTableProps = computed(() => { <v-card-text> <v-data-table v-model:items-per-page="itemsPerPage" v-bind="dataTableProps"> <template #[`item.type`]="{ item }"> - <v-chip :href="item?.href ? item.href : undefined" target="_blank"> + <v-chip v-if="item.activity === 'Defense'" :href="item?.href ? item.href : undefined" + target="_blank"> + {{ item.type }} + </v-chip> + <v-chip v-else> {{ item.type }} </v-chip> </template> diff --git a/frontend/components/SubmitAnalysis.vue b/frontend/components/SubmitAnalysis.vue index b284b9490a58e590fa634aed01abc8338beb7c80..6df871ca152cfb98d73b650a315070aefdadc63a 100644 --- a/frontend/components/SubmitAnalysis.vue +++ b/frontend/components/SubmitAnalysis.vue @@ -6,6 +6,7 @@ const uppyComponentRef = ref(null) const tab = ref<"local" | "paste">("null") const maxSequenceLength = ref(10000) const { csrfToken } = await useCsrfToken() +const antiDefenseSystem = ref(false) const { handleSubmit } = useForm({ validationSchema: { // files(value) { @@ -32,6 +33,9 @@ async function addExample() { try { await $fetch('/dfapi/analysis/add-example', { method: 'POST', + body: { + antidefensefinder: toValue(antiDefenseSystem) + }, headers: { "X-CSRFToken": csrfToken.value } }) await navigateTo("/analyses/") @@ -44,10 +48,12 @@ async function addExample() { } const submit = handleSubmit(async (values) => { + console.log("dans le submit") loading.value = true const formData = new FormData(); const blob = new Blob([toValue(sequence)], { type: 'text/plain' }) formData.append('genomefile', blob, 'pasted-sequence.fasta') + formData.append('antidefensefinder', toValue(antiDefenseSystem).toString()) try { await $fetch('/dfapi/analysis/add', { method: 'POST', @@ -80,18 +86,27 @@ const submit = handleSubmit(async (values) => { <UppyGenomeUpload v-model="files.value.value" ref="uppyComponentRef" class="mb-2" /> </v-window-item> <v-window-item value="paste"> - <v-form @submit.prevent="submit"> - <v-textarea v-model="sequence" :error-messages="sequenceErrorMessage" :count="maxSequenceLength" - label="Fasta sequences" variant="filled" auto-grow></v-textarea> - <v-btn type="submit" :loading="loading">Submit</v-btn> - </v-form> + <v-card flat> + <v-card-text> + <v-form @submit.prevent="submit"> + <v-switch v-model="antiDefenseSystem" color="primary" label="anti defense system" + hide-details="auto" class="mx-0"></v-switch> + <v-textarea v-model="sequence" :error-messages="sequenceErrorMessage" :count="maxSequenceLength" + label="Fasta sequences" variant="filled" auto-grow></v-textarea> + <v-btn type="submit" :loading="loading">Submit</v-btn> + </v-form> + </v-card-text> + </v-card> </v-window-item> <v-window-item value="example"> <v-card flat color="transparent"> <v-card-text> You can try an example with Escherichia coli str. K-12 substr. MG1655 proteins (<a target="_blank" href="https://www.ncbi.nlm.nih.gov/datasets/genome/GCF_000005845.2">GCF_000005845.2</a>) - + </v-card-text> + <v-card-text> + <v-switch v-model="antiDefenseSystem" color="primary" label="anti defense system" + hide-details="auto"></v-switch> </v-card-text> <v-card-actions> <v-btn variant="elevated" density="default" size="default" :slim="false" rounded="xl" diff --git a/frontend/components/UppyGenomeUpload.vue b/frontend/components/UppyGenomeUpload.vue index 848b5b9176efb069be658d09a96e4d62fe86c999..70138677663673d41152dfca4a9afce3870e0eb2 100644 --- a/frontend/components/UppyGenomeUpload.vue +++ b/frontend/components/UppyGenomeUpload.vue @@ -28,11 +28,13 @@ const router = useRouter(); const { width } = useDisplay(); const emit = defineEmits(['update:modelValue']) const { csrfToken } = await useCsrfToken() - +const antiDefenseSystem = ref(false) +const hasAddFiles = ref(false) +const uploading = ref(false) const uppyCovar = new Uppy({ - autoProceed: true, + autoProceed: false, restrictions: { maxFileSize: 10000000 }, - // meta: { name: props.analysisName } + meta: { antidefensefinder: toValue(antiDefenseSystem) } }) // .use(DragDrop, { target: '#drag-drop' }) .use(XHR, { @@ -48,21 +50,43 @@ const uppyCovar = new Uppy({ // router.push() } }) + .on('file-added', (file) => { + const files = uppyCovar.getFiles() + if (files.length > 0) hasAddFiles.value = true + if (files.length === 0) hasAddFiles.value = false + }) + .on("upload", () => { + uploading.value = true + }) + // complete + .on("complete", () => { + uploading.value = false + }) + .on('error', (error) => { + uploading.value = false + }) .on("file-removed", (file, reason) => { const files = uppyCovar.getFiles() const emitObject = (files.length === 0) ? undefined : files + if (emitObject === undefined) hasAddFiles.value = false emit('update:modelValue', emitObject) }) - // .on("error", (error) => { - // console.log(error) - // throw createError("uppy error") - // }); + const themeUppy = computed(() => { return theme.global.current.value.dark ? 'dark' : "light" }) +watch(antiDefenseSystem, () => { + uppyCovar.setMeta({ antidefensefinder: toValue(antiDefenseSystem) }) +}) + +async function runAnalysis() { + console.log('run analsysis') + await uppyCovar.upload() + +} defineExpose({ uppyCovar, @@ -71,17 +95,27 @@ defineExpose({ </script> <template> <v-card flat> - <Dashboard :uppy="uppyCovar" :props="{ - inline: true, - hideUploadButton: false, - theme: themeUppy, - width, - height: 300, - metaFields: [{ - id: 'uppy-genome-upload', - name: 'genome', - placeholder: 'Genomes' - }], - }" /> + <v-card-text> + <v-form @submit.prevent="runAnalysis"> + + <v-switch v-model="antiDefenseSystem" color="primary" label="anti defense system" + hide-details="auto" class="ml-1"></v-switch> + + <Dashboard :uppy="uppyCovar" :props="{ + inline: true, + hideUploadButton: true, + theme: themeUppy, + width, + height: 300, + metaFields: [{ + id: 'uppy-genome-upload', + name: 'genome', + placeholder: 'Genomes' + }], + }" /> + + <v-btn type="submit" :disabled="!hasAddFiles" :loading="uploading">Submit</v-btn> + </v-form> + </v-card-text> </v-card> </template> \ No newline at end of file diff --git a/frontend/components/tableResults/GenesTable.vue b/frontend/components/tableResults/GenesTable.vue index 4c3ea83a5522bbc1b24e4f8069e5b83308876d01..4ac05986955c3a7a303126ad5f708459107ca801 100644 --- a/frontend/components/tableResults/GenesTable.vue +++ b/frontend/components/tableResults/GenesTable.vue @@ -28,6 +28,7 @@ const headers = ref([ { title: "Replicon", align: "end", key: "replicon" }, { title: "Position", align: "end", key: "hit_pos" }, { title: "Model fqn", align: "end", key: "model_fqn" }, + { title: "Activity", align: "end", key: "activity"}, { title: "System id", align: "end", key: "sys_id" }, { title: "System loci", align: "end", key: "sys_loci" }, { title: "locus_num", align: "end", key: "locus_num" }, diff --git a/frontend/components/tableResults/SystemsTable.vue b/frontend/components/tableResults/SystemsTable.vue index 1a8ed3dfe7bd63dfd7bb32d731011496c44d6e56..621a40418691be29cf432d6f87af28d080151af1 100644 --- a/frontend/components/tableResults/SystemsTable.vue +++ b/frontend/components/tableResults/SystemsTable.vue @@ -31,6 +31,7 @@ const groupBy = ref([ ]) const headers = ref([ { title: "System id", align: "end", key: "sys_id", fixed: true, }, + { title: "Activity", align: "end", key: "activity"}, { title: "type", align: "end", key: "type", }, { title: "subtype", align: "end", key: "subtype" }, { title: "sys_beg", align: "end", key: "sys_beg" },