Merge pull request #15484 from ahmedhamidawan/tool_submission_route_back

Create ToolSuccess route and refactor component
This commit is contained in:
Dannon
2023-02-02 21:49:26 -05:00
committed by GitHub
8 changed files with 190 additions and 125 deletions
+10 -13
View File
@@ -10,12 +10,6 @@
<div v-if="showEntryPoints">
<ToolEntryPoints v-for="job in entryPoints" :key="job.id" :job-id="job.id" />
</div>
<ToolSuccess
v-if="showSuccess"
:job-def="jobDef"
:job-response="jobResponse"
:tool-name="toolName" />
<Webhook v-if="showSuccess" type="tool" :tool-id="jobDef.tool_id" />
<b-modal v-model="showError" size="sm" :title="errorTitle | l" scrollable ok-only>
<b-alert v-if="errorMessage" show variant="danger">
{{ errorMessage }}
@@ -108,7 +102,8 @@
<script>
import { getGalaxyInstance } from "app";
import { useHistoryItemsStore } from "stores/history/historyItemsStore";
import { mapState } from "pinia";
import { useJobStore } from "stores/jobStore";
import { mapState, mapActions } from "pinia";
import { getToolFormData, updateToolFormData, submitJob } from "./services";
import { allowCachedJobs } from "./utilities";
import { refreshContentsWrapper } from "utils/data";
@@ -120,10 +115,8 @@ import LoadingSpan from "components/LoadingSpan";
import FormDisplay from "components/Form/FormDisplay";
import FormElement from "components/Form/FormElement";
import ToolEntryPoints from "components/ToolEntryPoints/ToolEntryPoints";
import ToolSuccess from "./ToolSuccess";
import ToolRecommendation from "../ToolRecommendation";
import UserHistories from "components/providers/UserHistories";
import Webhook from "components/Common/Webhook";
import Heading from "components/Common/Heading";
export default {
@@ -136,10 +129,8 @@ export default {
ToolCard,
FormElement,
ToolEntryPoints,
ToolSuccess,
ToolRecommendation,
UserHistories,
Webhook,
Heading,
},
props: {
@@ -168,7 +159,6 @@ export default {
showForm: false,
showEntryPoints: false,
showRecommendation: false,
showSuccess: false,
showError: false,
showExecuting: false,
formConfig: {},
@@ -239,6 +229,7 @@ export default {
});
},
methods: {
...mapActions(useJobStore, ["saveLatestResponse"]),
emailAllowed(config, user) {
return config.server_mail_configured && !user.isAnonymous;
},
@@ -332,9 +323,15 @@ export default {
const nJobs = jobResponse && jobResponse.jobs ? jobResponse.jobs.length : 0;
if (nJobs > 0) {
this.showForm = false;
this.showSuccess = true;
this.jobDef = jobDef;
this.jobResponse = jobResponse;
const response = {
jobDef: this.jobDef,
jobResponse: this.jobResponse,
toolName: this.toolName,
};
this.saveLatestResponse(response);
this.$router.push(`/jobs/submission/success`);
} else {
this.showError = true;
this.showForm = true;
+40 -77
View File
@@ -1,79 +1,42 @@
<template>
<div class="donemessagelarge">
<p>
Started tool <b>{{ toolName }}</b> and successfully added {{ nJobsText }} to the queue.
</p>
<p>The tool uses {{ nInputsText }}:</p>
<ul>
<li v-for="item of inputs" :key="item.hid">
<b>{{ item.hid }}: {{ item.name }}</b>
</li>
</ul>
<p>It produces {{ nOutputsText }}:</p>
<ul>
<li v-for="item of jobResponse.outputs" :key="item.hid">
<b>{{ item.hid }}: {{ item.name }}</b>
</li>
</ul>
<p>
You can check the status of queued jobs and view the resulting data by refreshing the History panel. When
the job has been run the status will change from 'running' to 'finished' if completed successfully or
'error' if problems were encountered.
</p>
</div>
</template>
<script setup lang="ts">
import { computed, onMounted } from "vue";
import { useJobStore } from "@/stores/jobStore";
import { useRouter } from "vue-router/composables";
import { getGalaxyInstance } from "@/app";
import ToolEntryPoints from "@/components/ToolEntryPoints/ToolEntryPoints.vue";
import ToolSuccessMessage from "./ToolSuccessMessage.vue";
import ToolRecommendation from "../ToolRecommendation.vue";
import Webhook from "@/components/Common/Webhook.vue";
<script>
export default {
props: {
jobDef: {
type: Object,
required: true,
},
jobResponse: {
type: Object,
required: true,
},
toolName: {
type: String,
required: true,
},
},
computed: {
inputs() {
const inputs = [];
const index = {};
for (const i in this.jobDef.inputs) {
const input = this.jobDef.inputs[i];
if (input && Array.isArray(input.values)) {
for (const j of input.values) {
if (j.src && !index[j.id]) {
inputs.push(j);
index[j.id] = true;
}
}
}
}
return inputs;
},
nInputs() {
return this.inputs.length;
},
nOutputs() {
return this.jobResponse && this.jobResponse.outputs ? this.jobResponse.outputs.length : 0;
},
nJobs() {
return this.jobResponse && this.jobResponse.jobs ? this.jobResponse.jobs.length : 0;
},
nJobsText() {
return this.nJobs > 1 ? `${this.nJobs} jobs` : `1 job`;
},
nInputsText() {
return this.nInputs > 1 ? `${this.nInputs} inputs` : `this input`;
},
nOutputsText() {
return this.nOutputs > 1 ? `${this.nOutputs} outputs` : `this output`;
},
},
};
const jobStore = useJobStore();
const router = useRouter();
const responseVal = computed(() => jobStore.getLatestResponse);
/* lifecyle */
onMounted(() => {
// no response means no ToolForm ran in this session (nothing in store)
if (Object.keys(responseVal.value).length === 0) {
router.push(`/`);
}
});
const jobDef = computed(() => responseVal.value.jobDef);
const jobResponse = computed(() => responseVal.value.jobResponse);
const toolName = computed(() => responseVal.value.toolName);
// getGalaxyInstance is not reactive
const configEnableRecommendations = getGalaxyInstance().config.enable_tool_recommendations;
const showRecommendation: boolean = [true, "true"].includes(configEnableRecommendations);
</script>
<template>
<section v-if="jobResponse && jobDef">
<div v-if="jobResponse.produces_entry_points">
<ToolEntryPoints v-for="job in jobResponse.jobs" :key="job.id" :job-id="job.id" />
</div>
<ToolSuccessMessage :job-def="jobDef" :job-response="jobResponse" :tool-name="toolName" />
<Webhook type="tool" :tool-id="jobDef.tool_id" />
<ToolRecommendation v-if="showRecommendation" :tool-id="jobDef.tool_id" />
</section>
</template>
@@ -0,0 +1,79 @@
<template>
<div class="donemessagelarge">
<p>
Started tool <b>{{ toolName }}</b> and successfully added {{ nJobsText }} to the queue.
</p>
<p>The tool uses {{ nInputsText }}:</p>
<ul>
<li v-for="item of inputs" :key="item.hid">
<b>{{ item.hid }}: {{ item.name }}</b>
</li>
</ul>
<p>It produces {{ nOutputsText }}:</p>
<ul>
<li v-for="item of jobResponse.outputs" :key="item.hid">
<b>{{ item.hid }}: {{ item.name }}</b>
</li>
</ul>
<p>
You can check the status of queued jobs and view the resulting data by refreshing the History panel. When
the job has been run the status will change from 'running' to 'finished' if completed successfully or
'error' if problems were encountered.
</p>
</div>
</template>
<script>
export default {
props: {
jobDef: {
type: Object,
required: true,
},
jobResponse: {
type: Object,
required: true,
},
toolName: {
type: String,
required: true,
},
},
computed: {
inputs() {
const inputs = [];
const index = {};
for (const i in this.jobDef.inputs) {
const input = this.jobDef.inputs[i];
if (input && Array.isArray(input.values)) {
for (const j of input.values) {
if (j.src && !index[j.id]) {
inputs.push(j);
index[j.id] = true;
}
}
}
}
return inputs;
},
nInputs() {
return this.inputs.length;
},
nOutputs() {
return this.jobResponse && this.jobResponse.outputs ? this.jobResponse.outputs.length : 0;
},
nJobs() {
return this.jobResponse && this.jobResponse.jobs ? this.jobResponse.jobs.length : 0;
},
nJobsText() {
return this.nJobs > 1 ? `${this.nJobs} jobs` : `1 job`;
},
nInputsText() {
return this.nInputs > 1 ? `${this.nInputs} inputs` : `this input`;
},
nOutputsText() {
return this.nOutputs > 1 ? `${this.nOutputs} outputs` : `this output`;
},
},
};
</script>
+6
View File
@@ -46,6 +46,7 @@ import Sharing from "components/Sharing/Sharing";
import StoredWorkflowInvocations from "components/Workflow/StoredWorkflowInvocations";
import ToolsJson from "components/ToolsView/ToolsSchemaJson/ToolsJson";
import ToolsList from "components/ToolsList/ToolsList";
import ToolSuccess from "components/Tool/ToolSuccess";
import TourList from "components/Tour/TourList";
import TourRunner from "components/Tour/TourRunner";
import TrsImport from "components/Workflow/Import/TrsImport";
@@ -252,6 +253,11 @@ export function getRouter(Galaxy) {
path: "interactivetool_entry_points/list",
component: InteractiveTools,
},
{
path: "jobs/submission/success",
component: ToolSuccess,
props: true,
},
{
path: "jobs/:jobId/view",
component: JobDetails,
-2
View File
@@ -21,7 +21,6 @@ import { configStore } from "./configStore";
import { toolStore } from "./toolStore";
import { datasetPathDestinationStore } from "./datasetPathDestinationStore";
import { datasetExtFilesStore } from "./datasetExtFilesStore";
import { jobStore } from "./jobStore";
import { collectionAttributesStore } from "./collectionAttributesStore";
import { panelStore } from "./panelStore";
@@ -61,7 +60,6 @@ export function createStore() {
dataset: datasetStore,
datasetExtFiles: datasetExtFilesStore,
datasetPathDestination: datasetPathDestinationStore,
informationStore: jobStore,
invocations: invocationStore,
jobMetrics: jobMetricsStore,
gridSearch: gridSearchStore,
-33
View File
@@ -1,33 +0,0 @@
export const state = {
job: {},
};
import Vue from "vue";
import { getAppRoot } from "onload/loadConfig";
import axios from "axios";
const getters = {
job: (state) => (jobId) => {
return state.job[jobId];
},
};
const actions = {
fetchJob: async ({ commit }, jobId) => {
const { data } = await axios.get(`${getAppRoot()}api/jobs/${jobId}?full=true`);
commit("saveJobForJobId", { jobId, job: data });
},
};
const mutations = {
saveJobForJobId: (state, { jobId, job }) => {
Vue.set(state.job, jobId, job);
},
};
export const jobStore = {
state,
getters,
actions,
mutations,
};
+54
View File
@@ -0,0 +1,54 @@
/**
* Requests jobs
* Requests response generated by a tool run
*/
import { defineStore } from "pinia";
import Vue from "vue";
import { getAppRoot } from "@/onload/loadConfig";
import axios from "axios";
/* interfaces */
interface Job {
id: string;
}
interface JobDef {
tool_id: string;
}
interface JobResponse {
produces_entry_points: boolean;
jobs: Array<Job>;
}
interface ResponseVal {
jobDef: JobDef;
jobResponse: JobResponse;
toolName: string;
}
export const useJobStore = defineStore("jobStore", {
state: () => ({
jobs: {} as { [index: string]: Job },
response: {} as ResponseVal,
}),
getters: {
getJob: (state) => {
return (jobId: string) => state.jobs[jobId];
},
getLatestResponse: (state) => {
return state.response;
},
},
actions: {
async fetchJob(jobId: string) {
const { data } = await axios.get(`${getAppRoot()}api/jobs/${jobId}?full=true`);
this.saveJobForJobId(jobId, data);
},
// Setters
saveJobForJobId(jobId: string, job: Job) {
Vue.set(this.jobs, jobId, job);
},
saveLatestResponse(response: ResponseVal) {
this.response = response;
},
},
});