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

Refactor workflow step display stuff toward TS & reuse. #17004

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import { isEmpty } from "@/utils/utils";

import WorkflowTree from "./WorkflowTree.vue";
import LoadingSpan from "@/components/LoadingSpan.vue";
import WorkflowStepIcon from "@/components/WorkflowInvocationState/WorkflowStepIcon.vue";
import WorkflowStepTitle from "@/components/WorkflowInvocationState/WorkflowStepTitle.vue";

interface WorkflowDisplayProps {
workflowId: string;
Expand Down Expand Up @@ -94,7 +96,13 @@ onMounted(async () => {
</b-alert>
<div v-if="itemContent !== null">
<div v-for="step in itemContent?.steps" :key="step.order_index" class="mb-2">
<div>Step {{ step.order_index + 1 }}: {{ step.label }}</div>
<WorkflowStepIcon v-if="step.type" :step-type="step.type" />
<WorkflowStepTitle
:step-tool-id="step.tool_id"
:step-subworkflow-id="step.subworkflow_id"
:step-label="step.label"
:step-type="step.type"
:step-index="step.order_index" />
<WorkflowTree :input="step" :skip-head="true" />
</div>
</div>
Expand Down
12 changes: 9 additions & 3 deletions client/src/components/Workflow/icons.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
import { library } from "@fortawesome/fontawesome-svg-core";
import { faFile } from "@fortawesome/free-regular-svg-icons";
import { faFolderOpen, faPause, faPencilAlt, faSitemap, faWrench } from "@fortawesome/free-solid-svg-icons";

library.add(faWrench, faFile, faSitemap, faPencilAlt, faPause, faFolderOpen);

export default {
tool: "fa-wrench",
data_input: "fa-file-o",
data_collection_input: "fa-folder-o",
data_input: "fa-file-o fa-file", // fa-file-o for older FontAwesome, fa-file is the only thing I could find newer font awesome
data_collection_input: "fa-folder-o fa-folder-open",
subworkflow: "fa-sitemap fa-rotate-270",
parameter_input: "fa-pencil",
parameter_input: "fa-pencil-alt", // fa-pencil for older FontAwesome, fa-pencil-alt for newer
pause: "fa-pause",
};
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@
<div class="d-flex" :data-step="workflowStep.id">
<div class="ui-portlet-section" style="width: 100%">
<div class="portlet-header portlet-title portlet-operations cursor-pointer" @click="toggleStep">
<i :class="'portlet-title-icon fa mr-1 ' + stepIcon"></i>
<WorkflowStepIcon class="portlet-title-icon" :step-type="workflowStepType" />
<span class="portlet-title-text">
<u class="step-title">{{ stepLabel }}</u>
<u class="step-title">
<WorkflowStepTitle v-bind="titleProps(workflowStep.id)" />
</u>
</span>
<FontAwesomeIcon class="float-right" :icon="expanded ? 'fa-chevron-up' : 'fa-chevron-down'" />
</div>
Expand Down Expand Up @@ -61,7 +63,7 @@
<li
v-for="stepInput in Object.values(workflowStep.input_steps)"
:key="stepInput.source_step">
{{ labelForWorkflowStep(stepInput.source_step) }}
<WorkflowStepTitle v-bind="titleProps(stepInput.source_step)" />
</li>
</ul>
</div>
Expand Down Expand Up @@ -91,14 +93,12 @@ import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
import GenericHistoryItem from "components/History/Content/GenericItem";
import LoadingSpan from "components/LoadingSpan";
import { InvocationStepProvider } from "components/providers";
import WorkflowIcons from "components/Workflow/icons";
import { mapActions, mapState } from "pinia";
import { useToolStore } from "stores/toolStore";
import { useWorkflowStore } from "stores/workflowStore";
import { mapActions as vuexMapActions, mapGetters } from "vuex";

import JobStep from "./JobStep";
import ParameterStep from "./ParameterStep";
import WorkflowStepIcon from "./WorkflowStepIcon";
import WorkflowStepTitle from "./WorkflowStepTitle";

library.add(faChevronUp, faChevronDown);

Expand All @@ -110,6 +110,8 @@ export default {
ParameterStep,
InvocationStepProvider,
GenericHistoryItem,
WorkflowStepIcon,
WorkflowStepTitle,
WorkflowInvocationState: () => import("components/WorkflowInvocationState/WorkflowInvocationState"),
},
props: {
Expand All @@ -124,8 +126,6 @@ export default {
};
},
computed: {
...mapState(useWorkflowStore, ["getStoredWorkflowByInstanceId"]),
...mapState(useToolStore, ["getToolForId", "getToolNameById"]),
...mapGetters(["getInvocationStepById"]),
isReady() {
return this.invocation.steps.length > 0;
Expand All @@ -142,59 +142,23 @@ export default {
isDataStep() {
return ["data_input", "data_collection_input"].includes(this.workflowStepType);
},
stepIcon() {
return WorkflowIcons[this.workflowStepType];
},
stepLabel() {
return this.labelForWorkflowStep(this.workflowStep.id);
},
},
created() {
this.fetchTool();
this.fetchSubworkflow();
},
methods: {
...mapActions(useWorkflowStore, ["fetchWorkflowForInstanceId"]),
...mapActions(useToolStore, ["fetchToolForId"]),
...vuexMapActions(["fetchInvocationStepById"]),
fetchTool() {
if (this.workflowStep.tool_id && !this.getToolForId(this.workflowStep.tool_id)) {
this.fetchToolForId(this.workflowStep.tool_id);
}
},
fetchSubworkflow() {
if (this.workflowStep.workflow_id) {
this.fetchWorkflowForInstanceId(this.workflowStep.workflow_id);
}
},
toggleStep() {
this.expanded = !this.expanded;
},
labelForWorkflowStep(stepIndex) {
titleProps(stepIndex) {
const invocationStep = this.invocation.steps[stepIndex];
const workflowStep = this.workflow.steps[stepIndex];
const oneBasedStepIndex = stepIndex + 1;
if (invocationStep && invocationStep.workflow_step_label) {
return `Step ${oneBasedStepIndex}: ${invocationStep.workflow_step_label}`;
}
const workflowStepType = workflowStep.type;
switch (workflowStepType) {
case "tool":
return `Step ${oneBasedStepIndex}: ${this.getToolNameById(workflowStep.tool_id)}`;
case "subworkflow": {
const subworkflow = this.getStoredWorkflowByInstanceId(workflowStep.workflow_id);
const label = subworkflow ? subworkflow.name : "Subworkflow";
return `Step ${oneBasedStepIndex}: ${label}`;
}
case "parameter_input":
return `Step ${oneBasedStepIndex}: Parameter input`;
case "data_input":
return `Step ${oneBasedStepIndex}: Data input`;
case "data_collection_input":
return `Step ${oneBasedStepIndex}: Data collection input`;
default:
return `Step ${oneBasedStepIndex}: Unknown step type '${workflowStepType}'`;
}
const rval = {
stepIndex: stepIndex,
stepLabel: invocationStep && invocationStep.workflow_step_label,
stepType: workflowStep.type,
stepToolId: workflowStep.tool_id,
stepSubworkflowId: workflowStep.workflow_id,
};
return rval;
},
},
};
Expand Down
20 changes: 20 additions & 0 deletions client/src/components/WorkflowInvocationState/WorkflowStepIcon.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<script lang="ts" setup>
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
import { computed } from "vue";

import WorkflowIcons from "@/components/Workflow/icons";

interface WorkflowStepIconProps {
stepType: "tool" | "data_input" | "data_collection_input" | "subworkflow" | "parameter_input" | "pause";
}

const props = defineProps<WorkflowStepIconProps>();

const stepIcon = computed(() => {
return WorkflowIcons[props.stepType];
});
</script>

<template>
<FontAwesomeIcon class="mr-1" :icon="stepIcon" />
</template>
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<script setup lang="ts">
import { computed, watch } from "vue";

import { useToolStore } from "@/stores/toolStore";
import { useWorkflowStore } from "@/stores/workflowStore";

interface WorkflowInvocationStepTitleProps {
stepIndex: number;
stepLabel?: string;
stepType: string;
stepToolId?: string;
stepSubworkflowId?: string;
}

const props = defineProps<WorkflowInvocationStepTitleProps>();

const workflowStore = useWorkflowStore();
const toolStore = useToolStore();

const subWorkflow = computed(() => {
if (props.stepSubworkflowId) {
return workflowStore.getStoredWorkflowByInstanceId(props.stepSubworkflowId);
}
return null;
});
const toolName = computed(() => {
if (props.stepToolId) {
return toolStore.getToolNameById(props.stepToolId);
}
return "";
});

const title = computed(() => {
const oneBasedStepIndex = props.stepIndex + 1;
if (props.stepLabel) {
return `Step ${oneBasedStepIndex}: ${props.stepLabel}`;
}
const workflowStepType = props.stepType;
switch (workflowStepType) {
case "tool":
return `Step ${oneBasedStepIndex}: ${toolName.value}`;
case "subworkflow": {
const subworkflow = subWorkflow.value;
const label = subworkflow ? subworkflow.name : "Subworkflow";
return `Step ${oneBasedStepIndex}: ${label}`;
}
case "parameter_input":
return `Step ${oneBasedStepIndex}: Parameter input`;
case "data_input":
return `Step ${oneBasedStepIndex}: Data input`;
case "data_collection_input":
return `Step ${oneBasedStepIndex}: Data collection input`;
default:
return `Step ${oneBasedStepIndex}: Unknown step type '${workflowStepType}'`;
}
});

function initStores() {
if (props.stepToolId && !toolStore.getToolForId(props.stepToolId)) {
toolStore.fetchToolForId(props.stepToolId);
}

if (props.stepSubworkflowId) {
workflowStore.fetchWorkflowForInstanceId(props.stepSubworkflowId);
}
}

watch(
props,
() => {
initStores();
},
{ immediate: true }
);
</script>

<template>
<span>{{ title }}</span>
</template>
1 change: 1 addition & 0 deletions lib/galaxy/managers/workflows.py
Original file line number Diff line number Diff line change
Expand Up @@ -1122,6 +1122,7 @@ def do_inputs(inputs, values, prefix, step, other_values=None):
for step in workflow.steps:
step_dict = {}
step_dict["order_index"] = step.order_index
step_dict["type"] = step.type
if step.annotations:
step_dict["annotation"] = step.annotations[0].annotation
try:
Expand Down
Loading