Skip to content

Commit 0b3436d

Browse files
authored
Merge pull request galaxyproject#22144 from ahmedhamidawan/toggle_step_display_in_invocation_view
Show step/tool form for currently active step in invocation view
2 parents 9ae7928 + 4be0e12 commit 0b3436d

2 files changed

Lines changed: 93 additions & 2 deletions

File tree

client/src/components/Workflow/Invocation/Graph/InvocationGraph.vue

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ function toggleDetailedView() {
241241
</div>
242242
<BCard v-if="activeNodeId !== null && activeStep" ref="stepCard" class="invocation-step-card mt-2" no-body>
243243
<BCardHeader
244-
class="d-flex justify-content-between align-items-center px-3 py-1"
244+
class="invocation-step-header"
245245
:class="activeNodeId !== null ? steps[activeNodeId]?.headerClass : ''">
246246
<WorkflowInvocationStepHeader
247247
class="w-100 pr-2"
@@ -340,4 +340,14 @@ function toggleDetailedView() {
340340
z-index: 150;
341341
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
342342
}
343+
344+
.invocation-step-header {
345+
display: flex;
346+
justify-content: space-between;
347+
align-items: center;
348+
padding: var(--spacing) var(--spacing-4);
349+
position: sticky;
350+
top: 0;
351+
z-index: 100;
352+
}
343353
</style>

client/src/components/WorkflowInvocationState/WorkflowInvocationStep.vue

Lines changed: 82 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
<script setup lang="ts">
22
import { faTimesCircle } from "@fortawesome/free-regular-svg-icons";
3-
import { faInfoCircle } from "@fortawesome/free-solid-svg-icons";
3+
import { faInfoCircle, faWrench } from "@fortawesome/free-solid-svg-icons";
44
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
5+
import axios from "axios";
56
import { BAlert } from "bootstrap-vue";
67
import { computed, onUnmounted, ref, watch } from "vue";
78
89
import type { WorkflowInvocationElementView } from "@/api/invocations";
910
import type { WorkflowStepTyped } from "@/api/workflows";
11+
import { useDatatypesMapper } from "@/composables/datatypesMapper";
1012
import type { GraphStep } from "@/composables/useInvocationGraph";
13+
import { getAppRoot } from "@/onload/loadConfig";
1114
import { useInvocationStore } from "@/stores/invocationStore";
1215
1316
import Heading from "../Common/Heading.vue";
@@ -20,6 +23,8 @@ import GTab from "@/components/BaseComponents/GTab.vue";
2023
import GTabs from "@/components/BaseComponents/GTabs.vue";
2124
import GenericHistoryItem from "@/components/History/Content/GenericItem.vue";
2225
import LoadingSpan from "@/components/LoadingSpan.vue";
26+
import FormDefault from "@/components/Workflow/Editor/Forms/FormDefault.vue";
27+
import FormTool from "@/components/Workflow/Editor/Forms/FormTool.vue";
2328
2429
const TERMINAL_JOB_STATES = ["ok", "error", "deleted", "paused"];
2530
@@ -41,8 +46,11 @@ const emit = defineEmits<{
4146
}>();
4247
4348
const invocationStore = useInvocationStore();
49+
const { datatypes } = useDatatypesMapper();
4450
4551
const localExpanded = ref(Boolean(props.expanded));
52+
const stepConfigData = ref<Record<string, any> | null>(null);
53+
const loadingStepConfig = ref(false);
4654
const stepFetchInterval = ref<any>(undefined);
4755
4856
const computedExpanded = computed({
@@ -143,6 +151,43 @@ const jobsTabTitle = computed(() => {
143151
return "No jobs";
144152
});
145153
154+
const activeStepWithConfig = computed(() => {
155+
// graphStep is the full editor-format step (already has config_form with correct values)
156+
if (props.graphStep?.config_form) {
157+
return props.graphStep as any;
158+
}
159+
// If the graphStep doesn't have config_form, we may be able to get it from stepConfigData (fetched when user clicks on Step Config tab)
160+
if (!stepConfigData.value) {
161+
return null;
162+
}
163+
const step = props.graphStep ?? (props.workflowStep as any);
164+
return {
165+
...step,
166+
config_form: stepConfigData.value.config_form,
167+
inputs: stepConfigData.value.inputs ?? step.inputs,
168+
outputs: stepConfigData.value.outputs ?? step.outputs,
169+
} as any;
170+
});
171+
172+
async function fetchStepConfig() {
173+
// graphStep already has config_form — no fetch needed
174+
if (props.graphStep?.config_form || stepConfigData.value || loadingStepConfig.value) {
175+
return;
176+
}
177+
loadingStepConfig.value = true;
178+
try {
179+
const step = props.graphStep ?? props.workflowStep;
180+
const { data } = await axios.post(`${getAppRoot()}api/workflows/build_module`, {
181+
type: step.type,
182+
content_id: "content_id" in step ? step.content_id : step.tool_id,
183+
tool_state: "tool_state" in step ? step.tool_state : {},
184+
});
185+
stepConfigData.value = data;
186+
} finally {
187+
loadingStepConfig.value = false;
188+
}
189+
}
190+
146191
function toggleStep() {
147192
computedExpanded.value = !computedExpanded.value;
148193
}
@@ -174,6 +219,13 @@ onUnmounted(() => {
174219
</div>
175220

176221
<div v-if="computedExpanded" class="portlet-content">
222+
<div
223+
v-if="props.workflowStep.annotation"
224+
class="mb-2 bg-light rounded p-2"
225+
:class="{ 'mt-2': !props.inGraphView }">
226+
{{ props.workflowStep.annotation }}
227+
</div>
228+
177229
<div v-if="isReady && invocationStepId !== undefined">
178230
<div style="min-width: 1">
179231
<BAlert v-if="loading" variant="info" show>
@@ -278,6 +330,26 @@ onUnmounted(() => {
278330
</div>
279331
</div>
280332
</GTab>
333+
334+
<GTab
335+
:class="{ 'invocation-view-step-config': props.inGraphView }"
336+
lazy
337+
@click="fetchStepConfig">
338+
<template v-slot:title>
339+
<FontAwesomeIcon :icon="faWrench" />
340+
<span v-localize>Step Config</span>
341+
</template>
342+
<BAlert v-if="loadingStepConfig" show>
343+
<LoadingSpan message="Loading step configuration" />
344+
</BAlert>
345+
<fieldset v-else-if="activeStepWithConfig" disabled>
346+
<FormTool
347+
v-if="workflowStepType === 'tool'"
348+
:step="activeStepWithConfig"
349+
:datatypes="datatypes" />
350+
<FormDefault v-else :step="activeStepWithConfig" :datatypes="datatypes" />
351+
</fieldset>
352+
</GTab>
281353
</GTabs>
282354
</div>
283355
</div>
@@ -302,4 +374,13 @@ onUnmounted(() => {
302374
opacity: 0.8;
303375
}
304376
}
377+
378+
.invocation-view-step-config {
379+
:deep(.tool-header) {
380+
position: unset;
381+
}
382+
:deep(.ui-form-header-underlay) {
383+
display: none;
384+
}
385+
}
305386
</style>

0 commit comments

Comments
 (0)