diff --git a/client-nuxt/components/RunAnalysisForm.vue b/client-nuxt/components/RunAnalysisForm.vue index 45ecbff61cb65f69147f44bd027f687e168573da..2e16b4efbe2b8a9c69b26af195fbd92185194a3a 100644 --- a/client-nuxt/components/RunAnalysisForm.vue +++ b/client-nuxt/components/RunAnalysisForm.vue @@ -1,69 +1,151 @@ <template> - <div v-if="workflowId"> + <v-card flat color="transparent"> <error-alert v-if="error" :error-message="error"></error-alert> + <v-card-text> + <ValidationObserver ref="observer" v-slot="{ invalid }"> + <v-stepper v-model="step" vertical flat color="transparent"> + <ValidationProvider + v-slot="{ errors }" + name="experiment" + rules="requiredExperiment" + > + <v-stepper-step + :complete="step > 1" + step="1" + editable + :rules="[() => errors.length < 1]" + > + Select an experiment + <small>{{ errors[0] }}</small> + </v-stepper-step> + <v-stepper-content step="1"> + <v-card flat color="transparent"> + <v-card-text> + <v-data-table + v-model="analysis.experiments" + :headers="headers" + :items="experiments" + :single-select="singleSelect" + item-key="id" + show-select + class="elevation-1" + > + </v-data-table> + <span>{{ errors[0] }}</span> + </v-card-text> + <v-card-actions> + <v-btn + v-if="analysis.experiments && analysis.experiments.length" + color="primary" + @click="step = 2" + >Continue</v-btn + > + </v-card-actions> + </v-card> + </v-stepper-content> + </ValidationProvider> + <template v-if="workflows"> + <v-stepper-step :complete="step > 2" step="2" editable> + Select a workflow + </v-stepper-step> + <v-stepper-content step="2"> + <v-card flat color="transparent"> + <workflow-item-groups + v-model="workflow" + :workflows="detailedWorkflows" + @selection="getWorkflowParameters" + ></workflow-item-groups> + <v-card-actions> + <v-btn v-if="workflow" color="primary" @click="step = 3" + >Continue</v-btn + ></v-card-actions + > + </v-card> + </v-stepper-content> + </template> + <v-stepper-step :step="lastWorkflowStep" + >Set workflow parameters</v-stepper-step + > + <v-stepper-content :step="lastWorkflowStep" + ><v-form v-model="valid" @submit.prevent="submit"> + <v-card flat color="transparent"> + <v-card-text> + <ValidationProvider + v-slot="{ errors }" + name="Name" + rules="required|max:50" + > + <v-text-field + v-model="analysis.name" + :counter="50" + :error-messages="errors" + label="Analyis Name" + hint="Set the analysis name" + persistent-hint + outlined + required + ></v-text-field> + </ValidationProvider> + </v-card-text> + <!-- <v-card-title>Set workflow parameters</v-card-title> --> + <v-card-text> + <v-expansion-panels focusable> + <v-expansion-panel + v-for="param in toolsInputs" + :key="param.stepId" + > + <v-expansion-panel-header color="" + >{{ param.name }} + </v-expansion-panel-header> - <ValidationObserver ref="observer" v-slot="{ invalid }"> - <v-form v-model="valid" @submit.prevent="submit"> - <ValidationProvider - v-slot="{ errors }" - name="Name" - rules="required|max:50" - > - <v-text-field - v-model="analysis.name" - :counter="50" - :error-messages="errors" - label="Name" - required - ></v-text-field> - </ValidationProvider> - - <v-data-table - v-model="analysis.experiments" - :headers="headers" - :items="experiments" - :single-select="singleSelect" - item-key="id" - show-select - class="elevation-1" - > - </v-data-table> - - <v-expansion-panels focusable> - <v-expansion-panel v-for="param in toolsInputs" :key="param.stepId"> - <v-expansion-panel-header>{{ - param.name - }}</v-expansion-panel-header> - <v-expansion-panel-content v-if="workflowParameters"> - <div v-for="input in param.inputs" :key="input.name" class="mt-5"> - <select-tool-parameter - v-if=" - input.model_class == 'SelectToolParameter' && - workflowParameters[param.stepId][input.name] - " - v-model="workflowParameters[param.stepId][input.name]" - :input="input" - /> - <integer-tool-parameter - v-if=" - input.model_class == 'IntegerToolParameter' && - workflowParameters[param.stepId][input.name] - " - v-model="workflowParameters[param.stepId][input.name]" - :input="input" - /> - </div> - </v-expansion-panel-content> - </v-expansion-panel> - </v-expansion-panels> - - <v-btn type="submit" color="primary" class="mt-4" :disabled="invalid" - >Run</v-btn - > - </v-form> - </ValidationObserver> + <v-expansion-panel-content v-if="workflowParameters"> + <div + v-for="input in param.inputs" + :key="input.name" + class="mt-5" + > + <select-tool-parameter + v-if=" + input.model_class == 'SelectToolParameter' && + workflowParameters[param.stepId][input.name] + " + v-model=" + workflowParameters[param.stepId][input.name] + " + :input="input" + /> + <integer-tool-parameter + v-if=" + input.model_class == 'IntegerToolParameter' && + workflowParameters[param.stepId][input.name] + " + v-model=" + workflowParameters[param.stepId][input.name] + " + :input="input" + /> + </div> + </v-expansion-panel-content> + </v-expansion-panel> + </v-expansion-panels> + </v-card-text> + <v-card-actions> + <v-btn + type="submit" + color="primary" + class="mt-4" + :disabled="invalid" + >Run</v-btn + > + </v-card-actions> + </v-card> + </v-form></v-stepper-content + > + </v-stepper> + </ValidationObserver> + </v-card-text> <ProgressBar :waiting="waiting" message="Starting Analysis" /> - </div> + </v-card> </template> <script> @@ -75,7 +157,7 @@ import { setInteractionMode, } from 'vee-validate' import ProgressBar from '@/components/ProgressBar' - +import WorkflowItemGroups from '@/components/WorkflowItemGroups' import ErrorAlert from '@/components/ErrorAlert' import SelectToolParameter from '~/components/GalaxyForm/SelectToolParameter.vue' import IntegerToolParameter from '~/components/GalaxyForm/IntegerToolParameter.vue' @@ -85,7 +167,10 @@ extend('required', { ...required, message: '{_field_} can not be empty', }) - +extend('requiredExperiment', { + ...required, + message: 'You must select one {_field_}', +}) extend('max', { ...max, message: '{_field_} may not be greater than {length} characters', @@ -98,19 +183,24 @@ export default { ValidationObserver, ErrorAlert, ProgressBar, + WorkflowItemGroups, }, props: { projectId: { type: Number, required: true }, experiments: { type: Array, required: true }, - workflowId: { type: String, required: true }, - workflowParameters: { type: Object, default: () => null }, + workflows: { type: Array, default: () => null }, + preselectedWorkflowId: { type: String, default: null }, + preselectedWorkflowParameters: { type: Object, default: () => null }, analysis: { type: Object, default: () => ({ name: '', galaxy_history_id: '', experiments: [] }), }, + // toolsInputs: { type: Array, default: () => [] }, }, data() { return { + step: 1, + workflow: null, error: null, waiting: false, valid: false, @@ -121,6 +211,7 @@ export default { ], singleSelect: true, workflowTools: null, + workflowParameters: null, } }, computed: { @@ -141,28 +232,70 @@ export default { .filter((tool) => tool.inputs.length > 0) : [] }, - // toolsInputsFiltred() { - // return this.toolsInputs - // .map((tool) => { - // tool.inputs = tool.inputs.filter( - // (input) => input.model_class !== 'DataToolParameter' - // ) - // return tool - // }) - // .filter((tool) => tool.inputs.length > 0) - // }, + workflowId() { + if (this.workflow) { + return this.workflow.id + } + if (this.preselectedWorkflowId) { + return this.preselectedWorkflowId + } + return null + }, + detailedWorkflows() { + return this.workflows + ? this.workflows.map((w) => w.details) + : this.workflows + }, + lastWorkflowStep() { + return this.workflows ? 3 : 2 + }, }, - async mounted() { - try { - this.workflowTools = await this.$axios.$get( - `/api/workflow-tools/${this.workflowId}/` - ) - } catch (error) {} + mounted() { + if (this.workflowId) { + this.getWorkflowTools() + } + if (this.preselectedWorkflowParameters) { + this.workflowParameters = this.preselectedWorkflowParameters + } }, + // updated() { + // console.log('UPDATED hook in RunanalysisFrom') + // this.getWorkflowTools() + // }, methods: { isSelect(modelClass) { return modelClass === 'SelectToolParameter' }, + async getWorkflowTools() { + try { + this.workflowTools = await this.$axios.$get( + `/api/workflow-tools/${this.workflowId}/` + ) + } catch (error) { + this.error = error + this.workflowTools = null + } + }, + async getWorkflowParameters() { + try { + const wfParams = await this.$axios.$get( + `/api/workflow-default-parameters/${this.workflowId}/` + ) + this.workflowParameters = Object.keys(wfParams).reduce( + (acc, stepId) => { + if (Object.keys(wfParams[stepId]).length > 0) { + acc[stepId] = { ...wfParams[stepId] } + } + return acc + }, + {} + ) + this.getWorkflowTools() + } catch (error) { + this.error = error + this.workflowParameters = null + } + }, async submit() { try { this.waiting = true diff --git a/client-nuxt/pages/projects/_id/analysis/_analysisId/copy.vue b/client-nuxt/pages/projects/_id/analysis/_analysisId/copy.vue index 628e6b33c4000f99276d98f13fe015fcba105923..913c0ab51f48e1503093ce7e22e21697c6aa851e 100644 --- a/client-nuxt/pages/projects/_id/analysis/_analysisId/copy.vue +++ b/client-nuxt/pages/projects/_id/analysis/_analysisId/copy.vue @@ -4,12 +4,11 @@ <v-card-text> <RunAnalysisForm - v-if="workflowId" - :workflow-id="workflowId" :project-id="projectId" :experiments="experiments" - :workflow-parameters="wfJobParams" :analysis="analysisCopy" + :preselected-workflow-id="workflowId" + :preselected-workflow-parameters="wfJobParams" /> </v-card-text> </v-card> diff --git a/client-nuxt/pages/projects/_id/analysis/add.vue b/client-nuxt/pages/projects/_id/analysis/add.vue index 07f8e93d6b573364d543b06fd6fe57716d9c980e..b2629e8a25df139ebf16f7a6e222b349553ad55c 100644 --- a/client-nuxt/pages/projects/_id/analysis/add.vue +++ b/client-nuxt/pages/projects/_id/analysis/add.vue @@ -1,7 +1,6 @@ <template> - <v-card> - <error-alert v-if="error" :error-message="error"></error-alert> - <v-toolbar dense flat> + <v-card color="transparent"> + <v-toolbar dense elevation="2"> <v-btn class="mr-3" nuxt text x-small @click="goToAnalysisListRoute()"> <v-icon left>mdi-arrow-left</v-icon>Analysis</v-btn > @@ -10,32 +9,21 @@ Run Analysis</v-toolbar-title > </v-toolbar> - <v-card-text> - <v-select - v-model="workflow" - :items="workflowItems" - label="Select a workflow" - @change="getWorkflowParameters" - ></v-select> - </v-card-text> - <v-card-text> - <RunAnalysisForm - v-if="workflowId" - :experiments="experiments" - :workflow-id="workflowId" - :project-id="projectId" - :workflow-parameters="workflowParameters" - /> - </v-card-text> + <RunAnalysisForm + :workflows="workflows" + :experiments="experiments" + :project-id="projectId" + /> </v-card> </template> <script> -import ErrorAlert from '@/components/ErrorAlert' import RunAnalysisForm from '~/components/RunAnalysisForm.vue' export default { - components: { RunAnalysisForm, ErrorAlert }, + components: { + RunAnalysisForm, + }, async asyncData({ params, $axios, route }) { const experiments = await $axios.$get( `/api/projects/${route.params.id}/experiments` @@ -51,26 +39,14 @@ export default { } }) const workflows = await $axios.$get('/api/cc-qtl-workflows/') + return { experiments: await Promise.all(expWithVarTypes), projectId: parseInt(params.id), workflows, } }, - data() { - return { error: null, workflow: null, workflowParameters: null } - }, - computed: { - workflowItems() { - return this.workflows.map((w) => ({ - value: w, - text: `${w.name} : ${w.tags.join('-')}`, - })) - }, - workflowId() { - return this?.workflow?.id - }, - }, + methods: { analysisListRoute() { return { @@ -81,25 +57,6 @@ export default { goToAnalysisListRoute() { this.$router.push(this.analysisListRoute()) }, - async getWorkflowParameters() { - try { - const wfParams = await this.$axios.$get( - `/api/workflow-default-parameters/${this.workflowId}/` - ) - this.workflowParameters = Object.keys(wfParams).reduce( - (acc, stepId) => { - if (Object.keys(wfParams[stepId]).length > 0) { - acc[stepId] = { ...wfParams[stepId] } - } - return acc - }, - {} - ) - } catch (error) { - this.error = error - this.workflowParameters = null - } - }, }, } </script>