Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[24.2] Fix inconsistent tab handling in invocation view #19298

Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script setup lang="ts">
import { BButtonGroup, BCol, BContainer, BRow } from "bootstrap-vue";
import { BAlert, BButtonGroup, BCol, BContainer, BRow } from "bootstrap-vue";
import type { VisualizationSpec } from "vega-embed";
import { computed, ref, watch } from "vue";
import { type ComputedRef } from "vue";
Expand All @@ -8,16 +8,16 @@ import { type components, GalaxyApi } from "@/api";
import { getAppRoot } from "@/onload/loadConfig";
import { errorMessageAsString } from "@/utils/simple-error";

import LoadingSpan from "../LoadingSpan.vue";
import HelpText from "@/components/Help/HelpText.vue";

const VegaWrapper = () => import("./VegaWrapper.vue");

const props = defineProps({
invocationId: {
type: String,
required: true,
},
});
interface Props {
invocationId: string;
notTerminal?: boolean;
}
const props = defineProps<Props>();

const groupBy = ref<"tool_id" | "step_id">("tool_id");
const timing = ref<"seconds" | "minutes" | "hours">("seconds");
Expand All @@ -44,7 +44,11 @@ async function fetchMetrics() {
}
}

watch(props, () => fetchMetrics(), { immediate: true });
watch(
() => props.invocationId,
() => fetchMetrics(),
{ immediate: true }
);

function itemToX(item: components["schemas"]["WorkflowJobMetric"]) {
if (groupBy.value === "tool_id") {
Expand Down Expand Up @@ -380,6 +384,9 @@ const groupByInTitles = computed(() => {

<template>
<div>
<BAlert v-if="props.notTerminal" variant="warning" show>
<LoadingSpan message="Metrics will update and change as the workflow progresses." />
</BAlert>
<BContainer>
<BRow align-h="end" class="mb-2">
<BButtonGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const selectors = {
bAlertStub: "balert-stub",
spanElement: "span",
invocationReportTab: '[titleitemclass="invocation-report-tab"]',
invocationExportTab: '[titleitemclass="invocation-export-tab"]',
fullPageHeading: "anonymous-stub[h1='true']",
};

Expand Down Expand Up @@ -177,16 +178,20 @@ describe("WorkflowInvocationState check invocation and job terminal states", ()
});
});

describe("WorkflowInvocationState check 'Report' tab disabled state and header", () => {
it("determines that 'Report' tab is disabled for non-terminal invocation", async () => {
describe("WorkflowInvocationState check 'Report' and 'Export' tab disabled state and header", () => {
it("for non-terminal invocation", async () => {
const wrapper = await mountWorkflowInvocationState("non-terminal-id");
const reportTab = wrapper.find(selectors.invocationReportTab);
expect(reportTab.attributes("disabled")).toBe("true");
const exportTab = wrapper.find(selectors.invocationExportTab);
expect(exportTab.attributes("disabled")).toBe("true");
});
it("determines that 'Report' tab is not disabled for terminal invocation", async () => {
it("for terminal invocation", async () => {
const wrapper = await mountWorkflowInvocationState(invocationData.id);
const reportTab = wrapper.find(selectors.invocationReportTab);
expect(reportTab.attributes("disabled")).toBeUndefined();
const exportTab = wrapper.find(selectors.invocationExportTab);
expect(exportTab.attributes("disabled")).toBeUndefined();
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,22 +67,22 @@ watch(
);

const workflowStore = useWorkflowStore();
const reportTabDisabled = computed(
const tabsDisabled = computed(
() =>
!invocationStateSuccess.value ||
!invocation.value ||
!workflowStore.getStoredWorkflowByInstanceId(invocation.value.workflow_id)
);

/** Tooltip message for the report tab when it is disabled */
const disabledReportTooltip = computed(() => {
/** Tooltip message for the a tab when it is disabled */
const disabledTabTooltip = computed(() => {
const state = invocationState.value;
if (state != "scheduled") {
return `This workflow is not currently scheduled. The current state is ${state}. Once the workflow is fully scheduled and jobs have complete this option will become available.`;
return `This workflow is not currently scheduled. The current state is ${state}. Once the workflow is fully scheduled and jobs have complete any disabled tabs will become available.`;
} else if (runningCount.value != 0) {
return `The workflow invocation still contains ${runningCount.value} running job(s). Once these jobs have completed this option will become available.`;
return `The workflow invocation still contains ${runningCount.value} running job(s). Once these jobs have completed any disabled tabs will become available.`;
} else {
return "Steps for this workflow are still running. A report will be available once complete.";
return "Steps for this workflow are still running. Any disabled tabs will be available once complete.";
}
});

Expand Down Expand Up @@ -332,45 +332,43 @@ async function onCancel() {
</BTab> -->
<BTab
v-if="!props.isSubworkflow"
title="Report"
title-item-class="invocation-report-tab"
:disabled="reportTabDisabled"
:disabled="tabsDisabled"
:lazy="reportLazy"
:active.sync="reportActive">
<template v-slot:title>
<span>Report</span>
<BBadge
v-if="reportTabDisabled"
v-b-tooltip.hover.noninteractive
:title="disabledReportTooltip"
variant="warning">
<FontAwesomeIcon :icon="faExclamation" />
</BBadge>
</template>
<InvocationReport v-if="invocationStateSuccess" :invocation-id="invocation.id" />
</BTab>
<BTab title="Export" title-item-class="invocation-export-tab" lazy>
<BTab title="Export" title-item-class="invocation-export-tab" :disabled="tabsDisabled" lazy>
<div v-if="invocationAndJobTerminal">
<WorkflowInvocationExportOptions :invocation-id="invocation.id" />
</div>
<BAlert v-else variant="info" show>
<LoadingSpan message="Waiting to complete invocation" />
</BAlert>
</BTab>
<BTab title="Metrics" :lazy="true">
<WorkflowInvocationMetrics :invocation-id="invocation.id"></WorkflowInvocationMetrics>
<WorkflowInvocationMetrics :invocation-id="invocation.id" :not-terminal="!invocationAndJobTerminal" />
</BTab>
<template v-slot:tabs-end>
<BButton
v-if="!props.isFullPage && !invocationAndJobTerminal"
v-b-tooltip.noninteractive.hover
class="ml-auto my-1"
title="Cancel scheduling of workflow invocation"
data-description="cancel invocation button"
size="sm"
@click="onCancel">
<FontAwesomeIcon :icon="faTimes" fixed-width />
Cancel Workflow
</BButton>
<div class="ml-auto d-flex align-items-center">
<BBadge
v-if="tabsDisabled"
v-b-tooltip.hover.noninteractive
class="mr-1"
:title="disabledTabTooltip"
variant="primary">
<FontAwesomeIcon :icon="faExclamation" />
</BBadge>
<BButton
v-if="!props.isFullPage && !invocationAndJobTerminal"
v-b-tooltip.noninteractive.hover
class="my-1"
title="Cancel scheduling of workflow invocation"
data-description="cancel invocation button"
size="sm"
@click="onCancel">
<FontAwesomeIcon :icon="faTimes" fixed-width />
Cancel Workflow
</BButton>
</div>
</template>
</BTabs>
</div>
Expand All @@ -387,9 +385,10 @@ async function onCancel() {

<style lang="scss">
// To show the tooltip on the disabled report tab badge
.invocation-report-tab {
.invocation-report-tab,
.invocation-export-tab {
.nav-link.disabled {
pointer-events: auto !important;
background-color: #e9edf0;
}
}
</style>
Expand Down
2 changes: 2 additions & 0 deletions lib/galaxy_test/selenium/test_workflow_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ class TestWorkflowRun(SeleniumTestCase, UsesHistoryItemAssertions, RunsWorkflows
def test_workflow_export_file_rocrate(self):
self._setup_simple_invocation_for_export_testing()
invocations = self.components.invocations
self.workflow_run_wait_for_ok(hid=2)
invocations.export_tab.wait_for_and_click()
self.screenshot("invocation_export_formats")
invocations.export_output_format(type="ro-crate").wait_for_and_click()
Expand All @@ -60,6 +61,7 @@ def test_workflow_export_file_rocrate(self):
def test_workflow_export_file_native(self):
self._setup_simple_invocation_for_export_testing()
invocations = self.components.invocations
self.workflow_run_wait_for_ok(hid=2)
invocations.export_tab.wait_for_and_click()
self.screenshot("invocation_export_formats")
invocations.export_output_format(type="default-file").wait_for_and_click()
Expand Down
Loading