mirror of
https://github.com/galaxyproject/galaxy.git
synced 2026-10-24 02:04:04 +08:00
Merge pull request #20369 from ahmedhamidawan/sync_invocation_error_below_graph
[25.0] Make invocation errors more compact
This commit is contained in:
@@ -1,12 +1,16 @@
|
||||
<script setup lang="ts">
|
||||
import { faExternalLinkAlt } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
|
||||
import { storeToRefs } from "pinia";
|
||||
import { computed } from "vue";
|
||||
|
||||
import type { InvocationMessage } from "@/api/invocations";
|
||||
import type { InvocationMessage, WorkflowInvocationElementView } from "@/api/invocations";
|
||||
import { useWorkflowInstance } from "@/composables/useWorkflowInstance";
|
||||
import { useWorkflowStateStore } from "@/stores/workflowEditorStateStore";
|
||||
|
||||
import GCard from "../Common/GCard.vue";
|
||||
import WorkflowStepTitle from "./WorkflowStepTitle.vue";
|
||||
import GenericHistoryItem from "@/components/History/Content/GenericItem.vue";
|
||||
import JobInformation from "@/components/JobInformation/JobInformation.vue";
|
||||
import WorkflowInvocationStep from "@/components/WorkflowInvocationState/WorkflowInvocationStep.vue";
|
||||
|
||||
type ReasonToLevel = {
|
||||
history_deleted: "cancel";
|
||||
@@ -44,17 +48,18 @@ const levelClasses = {
|
||||
error: "errormessage",
|
||||
};
|
||||
|
||||
interface Invocation {
|
||||
workflow_id: string;
|
||||
state: string;
|
||||
}
|
||||
|
||||
interface InvocationMessageProps {
|
||||
invocationMessage: InvocationMessage;
|
||||
invocation: Invocation;
|
||||
invocation: WorkflowInvocationElementView;
|
||||
storeId: string;
|
||||
}
|
||||
|
||||
const props = defineProps<InvocationMessageProps>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: "view-step", stepId: number): void;
|
||||
}>();
|
||||
|
||||
const levelClass = computed(() => levelClasses[level[props.invocationMessage.reason]]);
|
||||
|
||||
const workflow = computed(() => {
|
||||
@@ -76,6 +81,12 @@ const workflowStep = computed(() => {
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
const invocationStep = computed(() => {
|
||||
if (workflowStep.value) {
|
||||
return props.invocation.steps[workflowStep.value.id];
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
|
||||
const dependentWorkflowStep = computed(() => {
|
||||
if ("dependent_workflow_step_id" in props.invocationMessage && workflow.value) {
|
||||
@@ -86,6 +97,15 @@ const dependentWorkflowStep = computed(() => {
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
const dependentInvocationStep = computed(() => {
|
||||
if (dependentWorkflowStep.value) {
|
||||
return props.invocation.steps[dependentWorkflowStep.value.id];
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
|
||||
// This is used to indicate on the step cards whether the step is currently active in the invocation graph.\
|
||||
const { activeNodeId } = storeToRefs(useWorkflowStateStore(props.storeId));
|
||||
|
||||
const jobId = computed(() => "job_id" in props.invocationMessage && props.invocationMessage.job_id);
|
||||
const HdaId = computed(() => "hda_id" in props.invocationMessage && props.invocationMessage.hda_id);
|
||||
@@ -175,6 +195,11 @@ const infoString = computed(() => {
|
||||
return reason;
|
||||
}
|
||||
});
|
||||
|
||||
function openJobInNewTab(jobId: string) {
|
||||
const url = `/jobs/${jobId}/view`;
|
||||
window.open(url, "_blank");
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -182,31 +207,68 @@ const infoString = computed(() => {
|
||||
<div :class="levelClass" style="text-align: center">
|
||||
{{ infoString }}
|
||||
</div>
|
||||
<div v-if="dependentWorkflowStep">
|
||||
Problem occurred at this step:
|
||||
<WorkflowInvocationStep
|
||||
:invocation="invocation"
|
||||
:workflow="workflow"
|
||||
:workflow-step="dependentWorkflowStep"></WorkflowInvocationStep>
|
||||
</div>
|
||||
<div v-if="workflowStep">
|
||||
{{ stepDescription }}
|
||||
<WorkflowInvocationStep
|
||||
:invocation="invocation"
|
||||
:workflow="workflow"
|
||||
:workflow-step="workflowStep"></WorkflowInvocationStep>
|
||||
</div>
|
||||
<div v-if="HdaId">
|
||||
This dataset failed:
|
||||
<GenericHistoryItem :item-id="HdaId" item-src="hda" />
|
||||
</div>
|
||||
<div v-if="HdcaId">
|
||||
This dataset collection failed:
|
||||
<GenericHistoryItem :item-id="HdcaId" item-src="hdca" />
|
||||
</div>
|
||||
<div v-if="jobId">
|
||||
This job failed:
|
||||
<JobInformation :job_id="jobId" />
|
||||
<div class="invocation-error-grid d-flex flex-wrap">
|
||||
<GCard
|
||||
v-if="dependentWorkflowStep"
|
||||
clickable
|
||||
:current="activeNodeId === dependentWorkflowStep.id"
|
||||
grid-view
|
||||
@click="emit('view-step', dependentWorkflowStep.id)">
|
||||
Problem occurred at this step:
|
||||
<strong>
|
||||
<WorkflowStepTitle
|
||||
:step-index="dependentWorkflowStep.id"
|
||||
:step-label="
|
||||
dependentInvocationStep?.workflow_step_label || `Step ${dependentWorkflowStep.id + 1}`
|
||||
"
|
||||
:step-type="dependentWorkflowStep.type"
|
||||
:step-tool-id="dependentWorkflowStep.tool_id"
|
||||
:step-subworkflow-id="
|
||||
'workflow_id' in dependentWorkflowStep ? dependentWorkflowStep.workflow_id : null
|
||||
" />
|
||||
</strong>
|
||||
</GCard>
|
||||
<GCard
|
||||
v-if="workflowStep"
|
||||
clickable
|
||||
:current="activeNodeId === workflowStep.id"
|
||||
grid-view
|
||||
@click="emit('view-step', workflowStep.id)">
|
||||
{{ stepDescription }}:
|
||||
<strong>
|
||||
<WorkflowStepTitle
|
||||
:step-index="workflowStep.id"
|
||||
:step-label="invocationStep?.workflow_step_label || `Step ${workflowStep.id + 1}`"
|
||||
:step-type="workflowStep.type"
|
||||
:step-tool-id="workflowStep.tool_id"
|
||||
:step-subworkflow-id="'workflow_id' in workflowStep ? workflowStep.workflow_id : null" />
|
||||
</strong>
|
||||
</GCard>
|
||||
<GCard v-if="HdaId" grid-view>
|
||||
This dataset failed:
|
||||
<GenericHistoryItem :item-id="HdaId" item-src="hda" />
|
||||
</GCard>
|
||||
<GCard v-if="HdcaId" grid-view>
|
||||
This dataset collection failed:
|
||||
<GenericHistoryItem :item-id="HdcaId" item-src="hdca" />
|
||||
</GCard>
|
||||
<GCard v-if="jobId" clickable grid-view @click="openJobInNewTab(jobId)">
|
||||
<span>
|
||||
This job failed: <strong> {{ jobId }} </strong>
|
||||
</span>
|
||||
<i>
|
||||
Click to view job details in a new tab
|
||||
<FontAwesomeIcon :icon="faExternalLinkAlt" />
|
||||
</i>
|
||||
</GCard>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "_breakpoints.scss";
|
||||
|
||||
.invocation-error-grid {
|
||||
container: cards-list / inline-size;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
<script setup lang="ts">
|
||||
import { BAlert } from "bootstrap-vue";
|
||||
import { computed } from "vue";
|
||||
import { storeToRefs } from "pinia";
|
||||
import { computed, nextTick, ref } from "vue";
|
||||
|
||||
import type { WorkflowInvocationElementView } from "@/api/invocations";
|
||||
import { useWorkflowInstance } from "@/composables/useWorkflowInstance";
|
||||
import { useWorkflowStateStore } from "@/stores/workflowEditorStateStore";
|
||||
import { withPrefix } from "@/utils/redirect";
|
||||
|
||||
import ExternalLink from "../ExternalLink.vue";
|
||||
@@ -23,11 +25,27 @@ const props = defineProps<Props>();
|
||||
|
||||
const { workflow, loading, error } = useWorkflowInstance(props.invocation.workflow_id);
|
||||
|
||||
const invocationGraph = ref<InstanceType<typeof InvocationGraph> | null>(null);
|
||||
|
||||
const uniqueMessages = computed(() => {
|
||||
const messages = props.invocation.messages || [];
|
||||
const uniqueMessagesSet = new Set(messages.map((message) => JSON.stringify(message)));
|
||||
return Array.from(uniqueMessagesSet).map((message) => JSON.parse(message)) as typeof messages;
|
||||
});
|
||||
|
||||
// TODO: Refactor so that `storeId` is only defined here, and then used in all children components/composables.
|
||||
const storeId = computed(() => `invocation-${props.invocation.id}`);
|
||||
const stateStore = useWorkflowStateStore(storeId.value);
|
||||
const { activeNodeId } = storeToRefs(stateStore);
|
||||
|
||||
async function showStep(stepId: number) {
|
||||
if (invocationGraph.value) {
|
||||
activeNodeId.value = stepId;
|
||||
await nextTick();
|
||||
const graphSelector = invocationGraph.value?.$el?.querySelector(".invocation-graph");
|
||||
graphSelector?.scrollIntoView({ behavior: "smooth", block: "start" });
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -44,7 +62,9 @@ const uniqueMessages = computed(() => {
|
||||
:key="message.reason"
|
||||
class="steps-progress my-1 w-100"
|
||||
:invocation-message="message"
|
||||
:invocation="invocation">
|
||||
:invocation="invocation"
|
||||
:store-id="storeId"
|
||||
@view-step="showStep">
|
||||
</InvocationMessage>
|
||||
</div>
|
||||
<!-- Once the workflow for the invocation has been loaded, display the graph -->
|
||||
@@ -56,6 +76,7 @@ const uniqueMessages = computed(() => {
|
||||
</BAlert>
|
||||
<div v-else-if="workflow && !isSubworkflow">
|
||||
<InvocationGraph
|
||||
ref="invocationGraph"
|
||||
class="mt-1"
|
||||
data-description="workflow invocation graph"
|
||||
:invocation="invocation"
|
||||
|
||||
@@ -11,8 +11,8 @@ interface WorkflowInvocationStepTitleProps {
|
||||
stepIndex: number;
|
||||
stepLabel?: string;
|
||||
stepType: string;
|
||||
stepToolId?: string;
|
||||
stepSubworkflowId?: string;
|
||||
stepToolId?: string | null;
|
||||
stepSubworkflowId?: string | null;
|
||||
}
|
||||
|
||||
const props = defineProps<WorkflowInvocationStepTitleProps>();
|
||||
|
||||
Reference in New Issue
Block a user