From 7e515a6504e1b94d97c91a73d136e1029fefd828 Mon Sep 17 00:00:00 2001 From: John Chilton Date: Fri, 10 Nov 2023 11:50:06 -0500 Subject: [PATCH] Fix workflow report to target right workflow version. There was a past jmchilton todo in the code base about it. Directives that might target particular versions of a workflow (so workflow_display and workflow_image) now can take a workflow_version attribute and when these things are auto-populated for workflow invocations - they are populated with the right version for the invocation. --- .../Elements/Workflow/WorkflowDisplay.vue | 10 ++++- .../Elements/Workflow/WorkflowImage.vue | 8 +++- .../components/Markdown/MarkdownContainer.vue | 6 ++- lib/galaxy/managers/markdown_parse.py | 4 +- lib/galaxy/managers/markdown_util.py | 44 +++++++++++++------ lib/galaxy/managers/workflows.py | 5 ++- lib/galaxy/model/__init__.py | 10 +++++ .../webapps/galaxy/controllers/workflow.py | 10 ++++- test/unit/workflows/test_workflow_markdown.py | 2 +- 9 files changed, 76 insertions(+), 23 deletions(-) diff --git a/client/src/components/Markdown/Elements/Workflow/WorkflowDisplay.vue b/client/src/components/Markdown/Elements/Workflow/WorkflowDisplay.vue index 3dbe80206a3c..329af572b8a0 100644 --- a/client/src/components/Markdown/Elements/Workflow/WorkflowDisplay.vue +++ b/client/src/components/Markdown/Elements/Workflow/WorkflowDisplay.vue @@ -10,11 +10,13 @@ import LoadingSpan from "@/components/LoadingSpan.vue"; interface WorkflowDisplayProps { workflowId: string; + workflowVersion?: string; embedded?: boolean; expanded?: boolean; } const props = withDefaults(defineProps(), { + workflowVersion: null, embedded: false, expanded: false, }); @@ -31,7 +33,13 @@ const loading = ref(true); const workflowName = computed(() => (itemContent.value ? itemContent.value.name : "...")); const downloadUrl = computed(() => withPrefix(`/api/workflows/${props.workflowId}/download?format=json-download`)); const importUrl = computed(() => withPrefix(`/workflow/imp?id=${props.workflowId}`)); -const itemUrl = computed(() => withPrefix(`/api/workflows/${props.workflowId}/download?style=preview`)); +const itemUrl = computed(() => { + let extra = ""; + if (props.workflowVersion) { + extra = `&version=${props.workflowVersion}`; + } + return withPrefix(`/api/workflows/${props.workflowId}/download?style=preview${extra}`); +}); onMounted(async () => { axios diff --git a/client/src/components/Markdown/Elements/Workflow/WorkflowImage.vue b/client/src/components/Markdown/Elements/Workflow/WorkflowImage.vue index 3ebf725ed304..6c8886cf8c4c 100644 --- a/client/src/components/Markdown/Elements/Workflow/WorkflowImage.vue +++ b/client/src/components/Markdown/Elements/Workflow/WorkflowImage.vue @@ -5,15 +5,21 @@ import { getAppRoot } from "@/onload/loadConfig"; interface WorkflowImageProps { workflowId: string; + workflowVersion?: string; size?: string; } const props = withDefaults(defineProps(), { size: "lg", + workflowVersion: null, }); const src = computed(() => { - return `${getAppRoot()}workflow/gen_image?id=${props.workflowId}&embed=true`; + let extraArgs = ""; + if (props.workflowVersion) { + extraArgs = `&version=${props.workflowVersion}`; + } + return `${getAppRoot()}workflow/gen_image?id=${props.workflowId}&embed=true${extraArgs}`; }); const width = computed(() => { const size = props.size; diff --git a/client/src/components/Markdown/MarkdownContainer.vue b/client/src/components/Markdown/MarkdownContainer.vue index f73b37934f12..c338743a39e2 100644 --- a/client/src/components/Markdown/MarkdownContainer.vue +++ b/client/src/components/Markdown/MarkdownContainer.vue @@ -83,7 +83,10 @@ const isVisible = computed(() => !isCollapsible.value || toggle.value);
{{ time }}
- +
@@ -131,6 +134,7 @@ const isVisible = computed(() => !isCollapsible.value || toggle.value); Optional[str]: + arg_pattern = re.compile(rf"{arg_name}=\s*{ARG_VAL_CAPTURED_REGEX}\s*") + match = re.search(arg_pattern, line) + if not match: + return None + value = match.group(1) + return value + + def _remap_galaxy_markdown_calls(func, markdown): def _remap_container(container): matching_line = None diff --git a/lib/galaxy/managers/workflows.py b/lib/galaxy/managers/workflows.py index 51a4d85d3777..357ec0deae7c 100644 --- a/lib/galaxy/managers/workflows.py +++ b/lib/galaxy/managers/workflows.py @@ -361,9 +361,10 @@ def check_security(self, trans, has_workflow, check_ownership=True, check_access return True - def get_workflow_svg_from_id(self, trans, id, for_embed=False) -> bytes: + def get_workflow_svg_from_id(self, trans, id, version=None, for_embed=False) -> bytes: stored = self.get_stored_accessible_workflow(trans, id) - return self.get_workflow_svg(trans, stored.latest_workflow, for_embed=for_embed) + workflow = stored.get_internal_version(version) + return self.get_workflow_svg(trans, workflow, for_embed=for_embed) def get_workflow_svg(self, trans, workflow, for_embed=False) -> bytes: try: diff --git a/lib/galaxy/model/__init__.py b/lib/galaxy/model/__init__.py index 503dd31b6d8c..d0a643af91f9 100644 --- a/lib/galaxy/model/__init__.py +++ b/lib/galaxy/model/__init__.py @@ -7358,6 +7358,12 @@ def get_internal_version(self, version): raise Exception("Version does not exist") return list(reversed(self.workflows))[version] + def version_of(self, workflow): + for version, workflow_instance in enumerate(reversed(self.workflows)): + if workflow_instance.id == workflow.id: + return version + raise KeyError("Failed to find a version of target workflow instance in stored workflow.") + def show_in_tool_panel(self, user_id): sa_session = object_session(self) stmt = ( @@ -7552,6 +7558,10 @@ def copy(self, user=None): copied_workflow.steps = copied_steps return copied_workflow + @property + def version(self): + return self.stored_workflow.version_of(self) + def log_str(self): extra = "" if self.stored_workflow: diff --git a/lib/galaxy/webapps/galaxy/controllers/workflow.py b/lib/galaxy/webapps/galaxy/controllers/workflow.py index b401e500c541..8cf8d5f629bc 100644 --- a/lib/galaxy/webapps/galaxy/controllers/workflow.py +++ b/lib/galaxy/webapps/galaxy/controllers/workflow.py @@ -326,10 +326,16 @@ def annotate_async(self, trans, id, new_annotation=None, **kwargs): @web.expose @web.require_login("use Galaxy workflows") - def gen_image(self, trans, id, embed="false", **kwargs): + def gen_image(self, trans, id, embed="false", version="", **kwargs): embed = util.asbool(embed) + if version: + version_int_or_none = int(version) + else: + version_int_or_none = None try: - s = trans.app.workflow_manager.get_workflow_svg_from_id(trans, id, for_embed=embed) + s = trans.app.workflow_manager.get_workflow_svg_from_id( + trans, id, version=version_int_or_none, for_embed=embed + ) trans.response.set_content_type("image/svg+xml") return s except Exception as e: diff --git a/test/unit/workflows/test_workflow_markdown.py b/test/unit/workflows/test_workflow_markdown.py index 114860760704..381fc4069506 100644 --- a/test/unit/workflows/test_workflow_markdown.py +++ b/test/unit/workflows/test_workflow_markdown.py @@ -17,7 +17,7 @@ def test_workflow_section_expansion(): """ galaxy_markdown = resolved_markdown(workflow_markdown) assert "## Workflow\n" in galaxy_markdown - assert "```galaxy\nworkflow_display(workflow_id=342)\n```\n" in galaxy_markdown + assert "```galaxy\nworkflow_display(workflow_id=342,workflow_checkpoint=0)\n```\n" in galaxy_markdown def test_inputs_section_expansion():