Allow users to view invocations for a particular workflow.

This commit is contained in:
John Chilton
2022-04-28 10:37:54 -04:00
parent 24fecc704f
commit 51e6813e8e
7 changed files with 113 additions and 3 deletions
@@ -8,7 +8,7 @@ import { parseISO, formatDistanceToNow } from "date-fns";
const localVue = getLocalVue();
describe("Invocations.vue without invocation", () => {
describe("Invocations.vue without invocations", () => {
let axiosMock;
let wrapper;
let propsData;
@@ -38,6 +38,38 @@ describe("Invocations.vue without invocation", () => {
});
});
describe("Invocations.vue for a workflow invocations", () => {
let axiosMock;
let wrapper;
let propsData;
beforeEach(async () => {
axiosMock = new MockAdapter(axios);
axiosMock.onAny().reply(200, [], { total_matches: "0" });
propsData = {
ownerGrid: false,
storedWorkflowName: "My Workflow",
storedWorkflowId: "abcde145678",
};
wrapper = mount(Invocations, {
propsData,
localVue,
});
});
afterEach(() => {
axiosMock.restore();
});
it("title should be shown", async () => {
expect(wrapper.find("#invocations-title").text()).toBe("Workflow Invocations for My Workflow");
});
it("no invocations message should be shown when not loading", async () => {
expect(wrapper.find("#no-invocations").exists()).toBe(true);
});
});
describe("Invocations.vue with invocation", () => {
let wrapper;
let propsData;
+21 -2
View File
@@ -1,7 +1,7 @@
<template>
<div class="invocations-list">
<h2 class="mb-3">
<span id="invocations-title">Workflow Invocations</span>
<span id="invocations-title">{{ title }}</span>
</h2>
<b-alert v-if="headerMessage" variant="info" show>
{{ headerMessage }}
@@ -22,7 +22,7 @@
<template v-slot:empty>
<loading-span v-if="loading" message="Loading workflow invocations" />
<b-alert v-else id="no-invocations" variant="info" show>
{{ noInvocationsMessage }}
{{ effectiveNoInvocationsMessage }}
</b-alert>
</template>
<template v-slot:row-details="row">
@@ -108,6 +108,8 @@ export default {
headerMessage: { type: String, default: "" },
ownerGrid: { type: Boolean, default: true },
userId: { type: String, default: null },
storedWorkflowId: { type: String, default: null },
storedWorkflowName: { type: String, default: null },
},
data() {
const fields = [
@@ -133,6 +135,20 @@ export default {
apiUrl() {
return `${getAppRoot()}api/invocations`;
},
title() {
let title = `Workflow Invocations`;
if (this.storedWorkflowName) {
title += ` for ${this.storedWorkflowName}`;
}
return title;
},
effectiveNoInvocationsMessage() {
let message = this.noInvocationsMessage;
if (this.storedWorkflowName) {
message += ` for ${this.storedWorkflowName}`;
}
return message;
},
},
watch: {
invocationItems: function (promise) {
@@ -157,6 +173,9 @@ export default {
provider(ctx) {
ctx.apiUrl = this.apiUrl;
const extraParams = this.ownerGrid ? {} : { include_terminal: false };
if (this.storedWorkflowId) {
extraParams["workflow_id"] = this.storedWorkflowId;
}
if (this.userId) {
extraParams["user_id"] = this.userId;
}
@@ -0,0 +1,30 @@
<template>
<CurrentUser v-slot="{ user }">
<StoredWorkflowDetailsProvider :storedWorkflowId="storedWorkflowId" v-slot="{ result: item, loading }">
<Invocations
v-if="!loading && user.id"
:user-id="user.id"
:stored-workflow-id="item.id"
:stored-workflow-name="item.name" />
</StoredWorkflowDetailsProvider>
</CurrentUser>
</template>
<script>
import Invocations from "components/Workflow/Invocations";
import CurrentUser from "components/providers/CurrentUser";
import { StoredWorkflowDetailsProvider } from "components/providers/StoredWorkflowsProvider";
export default {
props: {
storedWorkflowId: {
type: String,
required: true,
},
},
components: {
CurrentUser,
Invocations,
StoredWorkflowDetailsProvider,
},
};
</script>
@@ -41,6 +41,10 @@
<span class="fa fa-copy fa-fw mr-1" />
<span>Copy</span>
</a>
<a class="dropdown-item" :href="urlInvocations">
<span class="fa fa-list fa-fw mr-1" />
<span>Invocations</span>
</a>
<a class="dropdown-item" :href="urlDownload">
<span class="fa fa-download fa-fw mr-1" />
<span>Download</span>
@@ -103,6 +107,9 @@ export default {
urlView() {
return `${getAppRoot()}workflow/display_by_id?id=${this.workflow.id}`;
},
urlInvocations() {
return `${getAppRoot()}workflows/${this.workflow.id}/invocations`;
},
urlViewShared() {
return `${getAppRoot()}workflow/display_by_username_and_slug?username=${this.workflow.owner}&slug=${
this.workflow.slug
@@ -1,5 +1,8 @@
import axios from "axios";
import { getAppRoot } from "onload/loadConfig";
import { cleanPaginationParameters } from "./utils";
import { SingleQueryProvider } from "components/providers/SingleQueryProvider";
import { rethrowSimple } from "utils/simple-error";
export function storedWorkflowsProvider(ctx, callback, extraParams = {}) {
const { apiUrl, ...requestParams } = ctx;
@@ -15,3 +18,15 @@ export function storedWorkflowsProvider(ctx, callback, extraParams = {}) {
return items || [];
});
}
async function storedWorkflowDetails({ storedWorkflowId }) {
const url = `${getAppRoot()}api/workflows/${storedWorkflowId}?instance=true`;
try {
const { data } = await axios.get(url);
return data;
} catch (e) {
rethrowSimple(e);
}
}
export const StoredWorkflowDetailsProvider = SingleQueryProvider(storedWorkflowDetails);
@@ -38,6 +38,7 @@ import HistoryView from "components/HistoryView";
import WorkflowInvocationReport from "components/Workflow/InvocationReport";
import WorkflowRun from "components/Workflow/Run/WorkflowRun";
import UserInvocations from "components/Workflow/UserInvocations";
import StoredWorkflowInvocations from "components/Workflow/StoredWorkflowInvocations";
import ToolsView from "components/ToolsView/ToolsView";
import ToolsJson from "components/ToolsView/ToolsSchemaJson/ToolsJson";
import HistoryList from "mvc/history/history-list";
@@ -90,6 +91,7 @@ export const getAnalysisRouter = (Galaxy) => {
"(/)workflows/invocations/report": "show_workflow_invocation_report",
// "(/)workflows/invocations/view_bco": "show_invocation_bco",
"(/)workflows/list_published(/)": "show_workflows_published",
"(/)workflows(/)(:stored_workflow_id)(/)/invocations": "show_invocations_for_stored_workflow",
"(/)workflows/create(/)": "show_workflows_create",
"(/)histories(/)citations(/)": "show_history_citations",
"(/)histories(/)rename(/)": "show_histories_rename",
@@ -248,6 +250,10 @@ export const getAnalysisRouter = (Galaxy) => {
this._display_vue_helper(UserInvocations, {});
},
show_invocations_for_stored_workflow: function (stored_workflow_id) {
this._display_vue_helper(StoredWorkflowInvocations, { storedWorkflowId: stored_workflow_id });
},
show_history_structure: function () {
this._display_vue_helper(DisplayStructure, { id: QueryStringParsing.get(" id: ") });
},
+1
View File
@@ -251,6 +251,7 @@ def app_pair(global_conf, load_app_kwds=None, wsgi_preflight=True, **kwargs):
webapp.add_client_route("/workflows/trs_search")
webapp.add_client_route("/workflows/invocations")
webapp.add_client_route("/workflows/sharing")
webapp.add_client_route("/workflows/{stored_workflow_id}/invocations")
webapp.add_client_route("/workflows/invocations/report")
# webapp.add_client_route('/workflows/invocations/view_bco')
webapp.add_client_route("/custom_builds")