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.1] Allow running and editing workflows for specific versions #18378

Merged
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
5 changes: 5 additions & 0 deletions client/src/api/schema/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8555,6 +8555,11 @@ export interface components {
* @default false
*/
use_cached_job?: boolean | null;
/**
* Version
* @description The version of the workflow to invoke.
*/
version?: number | null;
};
/**
* ItemTagsCreatePayload
Expand Down
4 changes: 3 additions & 1 deletion client/src/components/Workflow/Editor/Index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -774,7 +774,9 @@ export default {
this.report.markdown = markdown;
},
onRun() {
const runUrl = `/workflows/run?id=${this.id}`;
const runUrl = `/workflows/run?id=${this.id}${
this.version !== undefined ? `&version=${this.version}` : ""
}`;
this.onNavigate(runUrl);
},
async onNavigate(url, forceSave = false, ignoreChanges = false) {
Expand Down
10 changes: 7 additions & 3 deletions client/src/components/Workflow/Run/WorkflowRun.vue
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,14 @@ const router = useRouter();

interface Props {
workflowId: string;
version?: string;
preferSimpleForm?: boolean;
simpleFormTargetHistory?: string;
simpleFormUseJobCache?: boolean;
}

const props = withDefaults(defineProps<Props>(), {
version: undefined,
preferSimpleForm: false,
simpleFormTargetHistory: "current",
simpleFormUseJobCache: false,
Expand All @@ -49,7 +51,9 @@ const workflowName = ref("");
const workflowModel: any = ref(null);

const currentHistoryId = computed(() => historyStore.currentHistoryId);
const editorLink = computed(() => `/workflows/edit?id=${props.workflowId}`);
const editorLink = computed(
() => `/workflows/edit?id=${props.workflowId}${props.version ? `&version=${props.version}` : ""}`
);
const historyStatusKey = computed(() => `${currentHistoryId.value}_${lastUpdateTime.value}`);
const isOwner = computed(() => currentUser.value?.username === workflowModel.value.runData.owner);
const lastUpdateTime = computed(() => historyItemsStore.lastUpdateTime);
Expand All @@ -74,7 +78,7 @@ function handleSubmissionError(error: string) {
}

function loadRun() {
getRunData(props.workflowId)
getRunData(props.workflowId, props.version || undefined)
.then((runData) => {
const incomingModel = new WorkflowRunModel(runData);
simpleForm.value = props.preferSimpleForm;
Expand Down Expand Up @@ -116,7 +120,7 @@ function loadRun() {
}

async function onImport() {
const response = await copyWorkflow(props.workflowId, workflowModel.value.runData.owner);
const response = await copyWorkflow(props.workflowId, workflowModel.value.runData.owner, props.version);
router.push(`/workflows/edit?id=${response.id}`);
}

Expand Down
3 changes: 2 additions & 1 deletion client/src/components/Workflow/Run/WorkflowRunForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
</span>
</BAlert>
<div class="h4 clearfix mb-3">
<b>Workflow: {{ model.name }}</b>
<b>Workflow: {{ model.name }}</b> <i>(version: {{ model.runData.version + 1 }})</i>
<ButtonSpinner
id="run-workflow"
class="float-right"
Expand Down Expand Up @@ -231,6 +231,7 @@ export default {
// the user is already warned if tool versions are wrong,
// they can still choose to invoke the workflow anyway.
require_exact_tool_versions: false,
version: this.model.runData.version,
};

console.debug("WorkflowRunForm::onExecute()", "Ready for submission.", jobDef);
Expand Down
3 changes: 2 additions & 1 deletion client/src/components/Workflow/Run/WorkflowRunFormSimple.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
or send the results to a new one using the run settings ⚙️
</span>
</BAlert>
<b>Workflow: {{ model.name }}</b>
<b>Workflow: {{ model.name }}</b> <i>(version: {{ model.runData.version + 1 }})</i>
<ButtonSpinner
id="run-workflow"
:wait="waitingForRequest"
Expand Down Expand Up @@ -200,6 +200,7 @@ export default {
batch: true,
use_cached_job: this.useCachedJobs,
require_exact_tool_versions: false,
version: this.model.runData.version,
};
if (this.sendToNewHistory) {
data.new_history_name = this.model.name;
Expand Down
8 changes: 6 additions & 2 deletions client/src/components/Workflow/Run/services.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,13 @@ import { rethrowSimple } from "utils/simple-error";
* for implementation). This contains the data needed to render the UI for workflows.
*
* @param {String} workflowId - (Stored?) Workflow ID to fetch data for.
* @param {String} version - Version of the workflow to fetch.
*/
export async function getRunData(workflowId) {
const url = `${getAppRoot()}api/workflows/${workflowId}/download?style=run`;
export async function getRunData(workflowId, version = null) {
let url = `${getAppRoot()}api/workflows/${workflowId}/download?style=run`;
if (version) {
url += `&version=${version}`;
}
try {
const response = await axios.get(url);
return response.data;
Expand Down
10 changes: 8 additions & 2 deletions client/src/components/Workflow/WorkflowRunButton.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { library } from "@fortawesome/fontawesome-svg-core";
import { faPlay } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
import { BButton } from "bootstrap-vue";
import { computed } from "vue";

library.add(faPlay);

Expand All @@ -11,9 +12,14 @@ interface Props {
full?: boolean;
title?: string;
disabled?: boolean;
version?: number;
}

defineProps<Props>();
const props = defineProps<Props>();

const runPath = computed(
() => `/workflows/run?id=${props.id}${props.version !== undefined ? `&version=${props.version}` : ""}`
);
</script>

<template>
Expand All @@ -25,7 +31,7 @@ defineProps<Props>();
variant="primary"
size="sm"
:disabled="disabled"
:to="`/workflows/run?id=${id}`">
:to="runPath">
<FontAwesomeIcon :icon="faPlay" fixed-width />

<span v-if="full" v-localize>Run</span>
Expand Down
8 changes: 6 additions & 2 deletions client/src/components/Workflow/workflows.services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,12 @@ export async function updateWorkflow(id: string, changes: object): Promise<Workf
return data;
}

export async function copyWorkflow(id: string, currentOwner: string): Promise<Workflow> {
const { data: workflowData } = await axios.get(withPrefix(`/api/workflows/${id}/download`));
export async function copyWorkflow(id: string, currentOwner: string, version?: string): Promise<Workflow> {
let path = `/api/workflows/${id}/download`;
if (version) {
path += `?version=${version}`;
}
const { data: workflowData } = await axios.get(withPrefix(path));

workflowData.name = `Copy of ${workflowData.name}`;
const currentUsername = useUserStore().currentUser?.username;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ function getWorkflowName() {
size="sm"
variant="secondary"
:disabled="isDeletedWorkflow"
:to="`/workflows/edit?id=${getWorkflowId()}`">
:to="`/workflows/edit?id=${getWorkflowId()}&version=${workflowVersion}`">
<FontAwesomeIcon :icon="faEdit" />
<span v-localize>Edit</span>
</BButton>
Expand All @@ -218,7 +218,8 @@ function getWorkflowName() {
: 'This workflow has been deleted.'
"
:disabled="isDeletedWorkflow"
full />
full
:version="workflowVersion" />
</BButtonGroup>
</div>
</div>
Expand Down
2 changes: 2 additions & 0 deletions client/src/entry/analysis/modules/Home.vue
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ export default {
},
workflowParams() {
const workflowId = this.query.workflow_id;
const version = this.query.version;
let preferSimpleForm = this.config.simplified_workflow_run_ui == "prefer";
const preferSimpleFormOverride = this.query.simplified_workflow_run_ui;
if (preferSimpleFormOverride == "prefer") {
Expand All @@ -68,6 +69,7 @@ export default {
const simpleFormUseJobCache = this.config.simplified_workflow_run_ui_job_cache == "on";
return {
workflowId,
version,
preferSimpleForm,
simpleFormTargetHistory,
simpleFormUseJobCache,
Expand Down
5 changes: 5 additions & 0 deletions client/src/entry/analysis/modules/WorkflowEditor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export default {
return {
storedWorkflowId: null,
workflowId: null,
version: null,
editorConfig: null,
editorReloadKey: 0,
};
Expand All @@ -46,6 +47,7 @@ export default {

this.storedWorkflowId = Query.get("id");
this.workflowId = Query.get("workflow_id");
this.version = Query.get("version");

const params = {};

Expand All @@ -54,6 +56,9 @@ export default {
} else if (this.storedWorkflowId) {
params.id = this.storedWorkflowId;
}
if (this.version) {
params.version = this.version;
}

this.editorConfig = await urlData({ url: "/workflow/editor", params });

Expand Down
5 changes: 4 additions & 1 deletion client/src/entry/analysis/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -659,7 +659,10 @@ export function getRouter(Galaxy) {
redirect: redirectAnon(),
props: (route) => ({
config: Galaxy.config,
query: { workflow_id: route.query.id },
query: {
workflow_id: route.query.id,
version: route.query.version,
},
}),
},
{
Expand Down
3 changes: 3 additions & 0 deletions lib/galaxy/managers/workflows.py
Original file line number Diff line number Diff line change
Expand Up @@ -919,6 +919,9 @@ def to_format_2(wf_dict, **kwds):
raise exceptions.RequestParameterInvalidException(f"Unknown workflow style {style}")
if version is not None:
wf_dict["version"] = version
# If returning a run-form workflow for a specific version, use that version's name
if style == "run":
wf_dict["name"] = workflow.name
else:
wf_dict["version"] = len(stored.workflows) - 1
return wf_dict
Expand Down
5 changes: 5 additions & 0 deletions lib/galaxy/schema/workflows.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ class GetTargetHistoryPayload(Model):

class InvokeWorkflowPayload(GetTargetHistoryPayload):
# TODO - Are the descriptions correct?
version: Optional[int] = Field(
None,
title="Version",
description="The version of the workflow to invoke.",
)
instance: Optional[bool] = Field(
False,
title="Is instance",
Expand Down
3 changes: 2 additions & 1 deletion lib/galaxy/webapps/galaxy/services/workflows.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,8 @@ def invoke_workflow(
# Get workflow + accessibility check.
by_stored_id = not payload.instance
stored_workflow = self._workflows_manager.get_stored_accessible_workflow(trans, workflow_id, by_stored_id)
workflow = stored_workflow.latest_workflow
version = payload.version
workflow = stored_workflow.get_internal_version(version)
run_configs = build_workflow_run_configs(trans, workflow, payload.model_dump(exclude_unset=True))
is_batch = payload.batch
if not is_batch and len(run_configs) != 1:
Expand Down
Loading