diff --git a/client/src/components/History/CurrentHistory/HistoryNavigation.test.js b/client/src/components/History/CurrentHistory/HistoryNavigation.test.js index e96b45d0c03..798e7e55b52 100644 --- a/client/src/components/History/CurrentHistory/HistoryNavigation.test.js +++ b/client/src/components/History/CurrentHistory/HistoryNavigation.test.js @@ -15,6 +15,7 @@ const expectedOptions = [ "Export Tool Citations", "Export History to File", "Extract Workflow", + "Show Invocations", "Share or Publish", "Set Permissions", "Make Private", diff --git a/client/src/components/History/CurrentHistory/HistoryNavigation.vue b/client/src/components/History/CurrentHistory/HistoryNavigation.vue index 4650262e70f..9ad0e697038 100644 --- a/client/src/components/History/CurrentHistory/HistoryNavigation.vue +++ b/client/src/components/History/CurrentHistory/HistoryNavigation.vue @@ -104,6 +104,14 @@ Extract Workflow + + + Show Invocations + + @@ -16,7 +16,7 @@ class="sharing-indicator-shared" size="sm" variant="link" - :title="'Search more workflows shared with me' | localize" + :title="'Search more items shared with me' | localize" @click.prevent="$emit('filter', 'is:shared_with_me')"> diff --git a/client/src/components/Markdown/Markdown.vue b/client/src/components/Markdown/Markdown.vue index e9ee7582c04..3ea876b4167 100644 --- a/client/src/components/Markdown/Markdown.vue +++ b/client/src/components/Markdown/Markdown.vue @@ -6,30 +6,32 @@ + size="sm" + title="Generate PDF"> + + Edit - Galaxy {{ markdownConfig.model_class }} - - Title: {{ markdownConfig.title || markdownConfig.model_class }} - - Created by {{ markdownConfig.username }} + Galaxy {{ markdownConfig.model_class }} + + + Title: {{ markdownConfig.title || markdownConfig.model_class }} + - Published with Galaxy {{ version }} on {{ time }} - Identifier {{ markdownConfig.id }} + Generated with Galaxy {{ version }} on {{ time }} + Identifier: {{ markdownConfig.id }} @@ -242,9 +244,6 @@ export default { content: content, }; }, - onDownload() { - window.location.href = this.exportLink; - }, }, }; diff --git a/client/src/components/StsDownloadButton.test.js b/client/src/components/StsDownloadButton.test.js index af99f7c0ed1..1cc178a6afa 100644 --- a/client/src/components/StsDownloadButton.test.js +++ b/client/src/components/StsDownloadButton.test.js @@ -47,10 +47,12 @@ describe("StsDownloadButton", () => { }); it("should fallback to a URL if tasks not enabled", async () => { + const windowSpy = jest.spyOn(window, "open"); + windowSpy.mockImplementation(() => {}); const wrapper = await mountStsDownloadButtonWrapper(NO_TASKS_CONFIG); wrapper.vm.onDownload(NO_TASKS_CONFIG); await flushPromises(); - expect(window.location).toBeAt(FALLBACK_URL); + expect(window.open).toBeCalled(); }); it("should poll until ready", async () => { diff --git a/client/src/components/StsDownloadButton.vue b/client/src/components/StsDownloadButton.vue index a7e9456b847..da28b3aaf54 100644 --- a/client/src/components/StsDownloadButton.vue +++ b/client/src/components/StsDownloadButton.vue @@ -5,8 +5,10 @@ v-b-tooltip.hover.bottom :title="title" :variant="variant" + :size="size" role="button" @click="onDownload(config)"> + Generate @@ -57,6 +59,10 @@ export default { type: String, default: null, }, + size: { + type: String, + default: "md", + }, }, data() { return { @@ -76,7 +82,7 @@ export default { }, onDownload(config) { if (!config.enable_celery_tasks) { - window.location.assign(withPrefix(this.fallbackUrl)); + window.open(withPrefix(this.fallbackUrl)); } else { this.waiting = true; axios diff --git a/client/src/components/Workflow/HistoryInvocations.vue b/client/src/components/Workflow/HistoryInvocations.vue new file mode 100644 index 00000000000..9ee9ae687c4 --- /dev/null +++ b/client/src/components/Workflow/HistoryInvocations.vue @@ -0,0 +1,27 @@ + + + + + + diff --git a/client/src/components/Workflow/InvocationReport.vue b/client/src/components/Workflow/InvocationReport.vue index 0acbdbc0c91..5e644068ffe 100644 --- a/client/src/components/Workflow/InvocationReport.vue +++ b/client/src/components/Workflow/InvocationReport.vue @@ -5,6 +5,7 @@ :markdown-config="markdownConfig" :enable_beta_markdown_export="config.enable_beta_markdown_export" :export-link="exportUrl" + :download-endpoint="stsUrl(config)" @onEdit="onEdit" /> @@ -60,6 +61,9 @@ export default { onEdit() { window.location = withPrefix(`/pages/create?invocation_id=${this.invocationId}`); }, + stsUrl(config) { + return `${this.dataUrl}/prepare_download`; + }, }, }; diff --git a/client/src/components/Workflow/InvocationsList.test.js b/client/src/components/Workflow/InvocationsList.test.js index eed58f6d305..ee1c570b6e5 100644 --- a/client/src/components/Workflow/InvocationsList.test.js +++ b/client/src/components/Workflow/InvocationsList.test.js @@ -66,7 +66,11 @@ describe("InvocationsList.vue", () => { describe("for a workflow with an empty invocation list", () => { beforeEach(async () => { - axiosMock.onAny().reply(200, [], { total_matches: "0" }); + axiosMock + .onGet("/api/invocations", { + params: { limit: 50, offset: 0, include_terminal: false, workflow_id: "abcde145678" }, + }) + .reply(200, [], { total_matches: "0" }); const propsData = { ownerGrid: false, storedWorkflowName: "My Workflow", @@ -80,12 +84,47 @@ describe("InvocationsList.vue", () => { }); it("title should be shown", async () => { - expect(wrapper.find("#invocations-title").text()).toBe("Workflow Invocations for My Workflow"); + expect(wrapper.find("#invocations-title").text()).toBe('Workflow Invocations for workflow "My Workflow"'); }); it("no invocations message should be shown when not loading", async () => { expect(wrapper.find("#no-invocations").exists()).toBe(true); }); + + it("should not render pager", async () => { + expect(wrapper.find(".gx-invocations-grid-pager").exists()).toBeFalsy(); + }); + }); + + describe("for a history with an empty invocation list", () => { + beforeEach(async () => { + axiosMock + .onGet("/api/invocations", { + params: { limit: 50, offset: 0, include_terminal: false, history_id: "abcde145678" }, + }) + .reply(200, [], { total_matches: "0" }); + const propsData = { + ownerGrid: false, + historyName: "My History", + historyId: "abcde145678", + }; + wrapper = mount(InvocationsList, { + propsData, + localVue, + }); + }); + + it("title should be shown", async () => { + expect(wrapper.find("#invocations-title").text()).toBe('Workflow Invocations for history "My History"'); + }); + + it("no invocations message should be shown when not loading", async () => { + expect(wrapper.find("#no-invocations").exists()).toBe(true); + }); + + it("should not render pager", async () => { + expect(wrapper.find(".gx-invocations-grid-pager").exists()).toBeFalsy(); + }); }); describe("with invocation", () => { @@ -132,11 +171,8 @@ describe("InvocationsList.vue", () => { expect(columns.at(3).text()).toBe( formatDistanceToNow(parseISO(`${mockInvocationData.create_time}Z`), { addSuffix: true }) ); - expect(columns.at(4).text()).toBe( - formatDistanceToNow(parseISO(`${mockInvocationData.update_time}Z`), { addSuffix: true }) - ); - expect(columns.at(5).text()).toBe("scheduled"); - expect(columns.at(6).text()).toBe(""); + expect(columns.at(4).text()).toBe("scheduled"); + expect(columns.at(5).text()).toBe(""); }); it("toggles detail rendering", async () => { @@ -161,5 +197,45 @@ describe("InvocationsList.vue", () => { await wrapper.find(".workflow-run").trigger("click"); expect(window.location).toBeAt("workflows/run?id=workflowId"); }); + + it("should not render pager", async () => { + expect(wrapper.find(".gx-invocations-grid-pager").exists()).toBeFalsy(); + }); + }); + + describe("paginations", () => { + beforeEach(async () => { + axiosMock + .onGet("/api/invocations", { params: { limit: 1, offset: 0, include_terminal: false } }) + .reply(200, [mockInvocationData], { total_matches: "3" }); + const propsData = { + ownerGrid: false, + loading: false, + defaultPerPage: 1, + }; + wrapper = mount(InvocationsList, { + propsData, + computed: { + getWorkflowNameByInstanceId: (state) => (id) => "workflow name", + getWorkflowByInstanceId: (state) => (id) => { + return { id: "workflowId" }; + }, + getHistoryById: (state) => (id) => { + return { id: "historyId" }; + }, + getHistoryNameById: () => () => "history name", + }, + stubs: { + "workflow-invocation-state": { + template: "", + }, + }, + localVue, + }); + }); + + it("title should render pager", async () => { + expect(wrapper.find(".gx-invocations-grid-pager").exists()).toBeTruthy(); + }); }); }); diff --git a/client/src/components/Workflow/InvocationsList.vue b/client/src/components/Workflow/InvocationsList.vue index d478551d1f8..1d251697dcb 100644 --- a/client/src/components/Workflow/InvocationsList.vue +++ b/client/src/components/Workflow/InvocationsList.vue @@ -6,13 +6,12 @@ {{ headerMessage }} - {{ message }} + {{ message }} @@ -23,7 +22,10 @@ - Invocation: {{ row.item.id }} + Last updated: ; + Invocation ID: {{ row.item.id }} @@ -32,14 +34,14 @@ @@ -52,7 +54,7 @@ {{ getHistoryNameById(data.item.history_id) }} @@ -73,7 +75,7 @@ @@ -82,7 +84,6 @@
{{ row.item.id }}