From 0601660170483ad21301f42d08273128cb0fa8d4 Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Mon, 26 Feb 2024 19:31:00 +0100 Subject: [PATCH 01/89] Add set_workflow_menu method to service layer of the Workflows API --- lib/galaxy/webapps/galaxy/api/workflows.py | 62 ++++++++-------------- 1 file changed, 22 insertions(+), 40 deletions(-) diff --git a/lib/galaxy/webapps/galaxy/api/workflows.py b/lib/galaxy/webapps/galaxy/api/workflows.py index 5de6e9d9b47c..15e90f52cbcb 100644 --- a/lib/galaxy/webapps/galaxy/api/workflows.py +++ b/lib/galaxy/webapps/galaxy/api/workflows.py @@ -78,6 +78,8 @@ ) from galaxy.schema.workflows import ( InvokeWorkflowPayload, + SetWorkflowMenuPayload, + SetWorkflowMenuSummary, StoredWorkflowDetailed, ) from galaxy.structured_app import StructuredApp @@ -144,46 +146,6 @@ def __init__(self, app: StructuredApp): self.workflow_contents_manager = app.workflow_contents_manager self.tool_recommendations = recommendations.ToolRecommendations() - @expose_api - def set_workflow_menu(self, trans: GalaxyWebTransaction, payload=None, **kwd): - """ - Save workflow menu to be shown in the tool panel - PUT /api/workflows/menu - """ - payload = payload or {} - user = trans.user - workflow_ids = payload.get("workflow_ids") - if workflow_ids is None: - workflow_ids = [] - elif not isinstance(workflow_ids, list): - workflow_ids = [workflow_ids] - workflow_ids_decoded = [] - # Decode the encoded workflow ids - for ids in workflow_ids: - workflow_ids_decoded.append(trans.security.decode_id(ids)) - session = trans.sa_session - # This explicit remove seems like a hack, need to figure out - # how to make the association do it automatically. - for m in user.stored_workflow_menu_entries: - session.delete(m) - user.stored_workflow_menu_entries = [] - # To ensure id list is unique - seen_workflow_ids = set() - for wf_id in workflow_ids_decoded: - if wf_id in seen_workflow_ids: - continue - else: - seen_workflow_ids.add(wf_id) - m = model.StoredWorkflowMenuEntry() - m.stored_workflow = session.get(model.StoredWorkflow, wf_id) - - user.stored_workflow_menu_entries.append(m) - with transaction(session): - session.commit() - message = "Menu updated." - trans.set_message(message) - return {"message": message, "status": "done"} - @expose_api def create(self, trans: GalaxyWebTransaction, payload=None, **kwd): """ @@ -890,6 +852,15 @@ def __get_stored_workflow(self, trans, workflow_id, **kwd): ), ] +SetWorkflowMenuBody = Annotated[ + Optional[SetWorkflowMenuPayload], + Body( + default=None, + title="Set workflow menu", + description="The values to set a workflow menu.", + ), +] + @router.cbv class FastAPIWorkflows: @@ -1007,6 +978,17 @@ def unpublish( """Removes this item from the published list and return the current sharing status.""" return self.service.shareable_service.unpublish(trans, workflow_id) + @router.put( + "/api/workflows/menu", + summary="Save workflow menu to be shown in the tool panel", + ) + def set_workflow_menu( + self, + payload: SetWorkflowMenuBody, + trans: ProvidesHistoryContext = DependsOnTrans, + ) -> SetWorkflowMenuSummary: + return self.service.set_workflow_menu(payload, trans) + @router.put( "/api/workflows/{workflow_id}/share_with_users", summary="Share this item with specific users.", From 39f40a4db3c48aa45548473bfd28f88e859b4927 Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Mon, 26 Feb 2024 19:31:37 +0100 Subject: [PATCH 02/89] Create pydantic models for the set_workflow_menu operation of the WorkflowsAPI --- lib/galaxy/schema/workflows.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/lib/galaxy/schema/workflows.py b/lib/galaxy/schema/workflows.py index f679fd47818d..b8e1aadaab3b 100644 --- a/lib/galaxy/schema/workflows.py +++ b/lib/galaxy/schema/workflows.py @@ -12,6 +12,7 @@ field_validator, ) +from galaxy.schema.fields import DecodedDatabaseIdField from galaxy.schema.schema import ( AnnotationField, InputDataCollectionStep, @@ -228,3 +229,24 @@ class StoredWorkflowDetailed(StoredWorkflowSummary): title="Source Metadata", description="The source metadata of the workflow.", ) + + +class SetWorkflowMenuPayload(Model): + workflow_ids: Union[List[DecodedDatabaseIdField], DecodedDatabaseIdField] = Field( + ..., + title="Workflow IDs", + description="The list of workflow IDs to set the menu entry for.", + ) + + +class SetWorkflowMenuSummary(Model): + message: Optional[Any] = Field( + ..., + title="Message", + description="The message of the operation.", + ) + status: str = Field( + ..., + title="Status", + description="The status of the operation.", + ) From 51b382991e3023e183b5572184e237e3dc810698 Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Mon, 26 Feb 2024 19:32:29 +0100 Subject: [PATCH 03/89] Refactor set_workflow_menu operation to FastAPI --- .../webapps/galaxy/services/workflows.py | 43 ++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/lib/galaxy/webapps/galaxy/services/workflows.py b/lib/galaxy/webapps/galaxy/services/workflows.py index 72414b169abf..72dd77e2b4be 100644 --- a/lib/galaxy/webapps/galaxy/services/workflows.py +++ b/lib/galaxy/webapps/galaxy/services/workflows.py @@ -10,9 +10,13 @@ from galaxy import ( exceptions, + model, web, ) -from galaxy.managers.context import ProvidesUserContext +from galaxy.managers.context import ( + ProvidesHistoryContext, + ProvidesUserContext, +) from galaxy.managers.workflows import ( RefactorResponse, WorkflowContentsManager, @@ -28,6 +32,8 @@ ) from galaxy.schema.workflows import ( InvokeWorkflowPayload, + SetWorkflowMenuPayload, + SetWorkflowMenuSummary, StoredWorkflowDetailed, ) from galaxy.util.tool_shed.tool_shed_registry import Registry @@ -221,6 +227,41 @@ def refactor( stored_workflow = self._workflows_manager.get_stored_workflow(trans, workflow_id, by_stored_id=not instance) return self._workflow_contents_manager.refactor(trans, stored_workflow, payload) + def set_workflow_menu( + self, + payload: Union[SetWorkflowMenuPayload, None], + trans: ProvidesHistoryContext, + ) -> SetWorkflowMenuSummary: + user = trans.user + if payload: + workflow_ids = payload.workflow_ids + if not isinstance(workflow_ids, list): + workflow_ids = [workflow_ids] + else: + workflow_ids = [] + session = trans.sa_session + # This explicit remove seems like a hack, need to figure out + # how to make the association do it automatically. + for m in user.stored_workflow_menu_entries: + session.delete(m) + user.stored_workflow_menu_entries = [] + # To ensure id list is unique + seen_workflow_ids = set() + for wf_id in workflow_ids: + if wf_id in seen_workflow_ids: + continue + else: + seen_workflow_ids.add(wf_id) + m = model.StoredWorkflowMenuEntry() + m.stored_workflow = session.get(model.StoredWorkflow, wf_id) + + user.stored_workflow_menu_entries.append(m) + with transaction(session): + session.commit() + message = "Menu updated." + trans.set_message(message) + return SetWorkflowMenuSummary(message=message, status="done") + def show_workflow(self, trans, workflow_id, instance, legacy, version) -> StoredWorkflowDetailed: stored_workflow = self._workflows_manager.get_stored_workflow(trans, workflow_id, by_stored_id=not instance) if stored_workflow.importable is False and stored_workflow.user != trans.user and not trans.user_is_admin: From db06f257f4996c7245a28201dc8fa6b05ae940a2 Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Mon, 26 Feb 2024 19:32:48 +0100 Subject: [PATCH 04/89] Remove the mapping to the legacy route --- lib/galaxy/webapps/galaxy/buildapp.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/galaxy/webapps/galaxy/buildapp.py b/lib/galaxy/webapps/galaxy/buildapp.py index 1e40c414f740..7850fda37462 100644 --- a/lib/galaxy/webapps/galaxy/buildapp.py +++ b/lib/galaxy/webapps/galaxy/buildapp.py @@ -592,9 +592,6 @@ def populate_api_routes(webapp, app): webapp.mapper.resource("visualization", "visualizations", path_prefix="/api") webapp.mapper.resource("plugins", "plugins", path_prefix="/api") webapp.mapper.connect("/api/workflows/build_module", action="build_module", controller="workflows") - webapp.mapper.connect( - "/api/workflows/menu", action="set_workflow_menu", controller="workflows", conditions=dict(method=["PUT"]) - ) webapp.mapper.resource("workflow", "workflows", path_prefix="/api") # ---- visualizations registry ---- generic template renderer From e02a6c0b5b26c26c705aad62b4febcb1ff619794 Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Tue, 27 Feb 2024 17:34:06 +0100 Subject: [PATCH 05/89] Add TODO --- lib/galaxy/webapps/galaxy/services/workflows.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/galaxy/webapps/galaxy/services/workflows.py b/lib/galaxy/webapps/galaxy/services/workflows.py index 72dd77e2b4be..e1ea3cdf68d4 100644 --- a/lib/galaxy/webapps/galaxy/services/workflows.py +++ b/lib/galaxy/webapps/galaxy/services/workflows.py @@ -229,7 +229,7 @@ def refactor( def set_workflow_menu( self, - payload: Union[SetWorkflowMenuPayload, None], + payload: Optional[SetWorkflowMenuPayload], trans: ProvidesHistoryContext, ) -> SetWorkflowMenuSummary: user = trans.user @@ -259,7 +259,8 @@ def set_workflow_menu( with transaction(session): session.commit() message = "Menu updated." - trans.set_message(message) + # TODO - It seems like this populates a mako template, is it necessary? + # trans.set_message(message) return SetWorkflowMenuSummary(message=message, status="done") def show_workflow(self, trans, workflow_id, instance, legacy, version) -> StoredWorkflowDetailed: From 913799151162fbc701ed0a886506bca6c7f22eda Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Tue, 27 Feb 2024 17:35:19 +0100 Subject: [PATCH 06/89] Type payload of set_workflow_menu operation properly --- lib/galaxy/webapps/galaxy/api/workflows.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/galaxy/webapps/galaxy/api/workflows.py b/lib/galaxy/webapps/galaxy/api/workflows.py index 15e90f52cbcb..079bf2ca5589 100644 --- a/lib/galaxy/webapps/galaxy/api/workflows.py +++ b/lib/galaxy/webapps/galaxy/api/workflows.py @@ -855,7 +855,6 @@ def __get_stored_workflow(self, trans, workflow_id, **kwd): SetWorkflowMenuBody = Annotated[ Optional[SetWorkflowMenuPayload], Body( - default=None, title="Set workflow menu", description="The values to set a workflow menu.", ), @@ -984,7 +983,7 @@ def unpublish( ) def set_workflow_menu( self, - payload: SetWorkflowMenuBody, + payload: SetWorkflowMenuBody = None, trans: ProvidesHistoryContext = DependsOnTrans, ) -> SetWorkflowMenuSummary: return self.service.set_workflow_menu(payload, trans) From e40f26551d182a5776d87f82785dde2432ddd5b8 Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Tue, 27 Feb 2024 18:25:05 +0100 Subject: [PATCH 07/89] Mark HistoryId query param as invocation specific --- lib/galaxy/webapps/galaxy/api/workflows.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/galaxy/webapps/galaxy/api/workflows.py b/lib/galaxy/webapps/galaxy/api/workflows.py index 079bf2ca5589..9bd1b093a4a5 100644 --- a/lib/galaxy/webapps/galaxy/api/workflows.py +++ b/lib/galaxy/webapps/galaxy/api/workflows.py @@ -1156,7 +1156,7 @@ def show_workflow( ), ] -HistoryIdQueryParam = Annotated[ +InvocationsHistoryIdQueryParam = Annotated[ Optional[DecodedDatabaseIdField], Query( title="History ID", @@ -1265,7 +1265,7 @@ def index_invocations( self, response: Response, workflow_id: WorkflowIdQueryParam = None, - history_id: HistoryIdQueryParam = None, + history_id: InvocationsHistoryIdQueryParam = None, job_id: JobIdQueryParam = None, user_id: UserIdQueryParam = None, sort_by: InvocationsSortByQueryParam = None, @@ -1319,7 +1319,7 @@ def index_workflow_invocations( self, response: Response, workflow_id: StoredWorkflowIDPathParam, - history_id: HistoryIdQueryParam = None, + history_id: InvocationsHistoryIdQueryParam = None, job_id: JobIdQueryParam = None, user_id: UserIdQueryParam = None, sort_by: InvocationsSortByQueryParam = None, From 26a83946798948501b9871699928fc5eb091738c Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Wed, 28 Feb 2024 09:21:29 +0100 Subject: [PATCH 08/89] Refactor workflow_dict operation to FastAPI --- lib/galaxy/webapps/galaxy/api/workflows.py | 96 +++++++++++----------- 1 file changed, 46 insertions(+), 50 deletions(-) diff --git a/lib/galaxy/webapps/galaxy/api/workflows.py b/lib/galaxy/webapps/galaxy/api/workflows.py index 9bd1b093a4a5..1208746da3d9 100644 --- a/lib/galaxy/webapps/galaxy/api/workflows.py +++ b/lib/galaxy/webapps/galaxy/api/workflows.py @@ -22,6 +22,7 @@ status, ) from gxformat2.yaml import ordered_dump +from markupsafe import escape from pydantic import ( UUID1, UUID4, @@ -282,56 +283,6 @@ def create(self, trans: GalaxyWebTransaction, payload=None, **kwd): # This was already raised above, but just in case... raise exceptions.RequestParameterMissingException("No method for workflow creation supplied.") - @expose_api_raw_anonymous_and_sessionless - def workflow_dict(self, trans: GalaxyWebTransaction, workflow_id, **kwd): - """ - GET /api/workflows/{encoded_workflow_id}/download - - Returns a selected workflow. - - :type style: str - :param style: Style of export. The default is 'export', which is the meant to be used - with workflow import endpoints. Other formats such as 'instance', 'editor', - 'run' are more tied to the GUI and should not be considered stable APIs. - The default format for 'export' is specified by the - admin with the `default_workflow_export_format` config - option. Style can be specified as either 'ga' or 'format2' directly - to be explicit about which format to download. - - :param instance: true if fetch by Workflow ID instead of StoredWorkflow id, false - by default. - :type instance: boolean - """ - stored_workflow = self.__get_stored_accessible_workflow(trans, workflow_id, **kwd) - - style = kwd.get("style", "export") - download_format = kwd.get("format") - version = kwd.get("version") - history = None - if history_id := kwd.get("history_id"): - history = self.history_manager.get_accessible( - self.decode_id(history_id), trans.user, current_history=trans.history - ) - ret_dict = self.workflow_contents_manager.workflow_to_dict( - trans, stored_workflow, style=style, version=version, history=history - ) - if download_format == "json-download": - sname = stored_workflow.name - sname = "".join(c in util.FILENAME_VALID_CHARS and c or "_" for c in sname)[0:150] - if ret_dict.get("format-version", None) == "0.1": - extension = "ga" - else: - extension = "gxwf.json" - trans.response.headers["Content-Disposition"] = ( - f'attachment; filename="Galaxy-Workflow-{sname}.{extension}"' - ) - trans.response.set_content_type("application/galaxy-archive") - - if style == "format2" and download_format != "json-download": - return ordered_dump(ret_dict) - else: - return format_return_as_json(ret_dict, pretty=True) - @expose_api def import_new_workflow_deprecated(self, trans: GalaxyWebTransaction, payload, **kwd): """ @@ -834,6 +785,30 @@ def __get_stored_workflow(self, trans, workflow_id, **kwd): description="Set this to true to skip joining workflow step counts and optimize the resulting index query. Response objects will not contain step counts.", ) +StyleQueryParam = Annotated[ + Optional[str], + Query( + title="Style of export", + description="The default is 'export', which is the meant to be used with workflow import endpoints. Other formats such as 'instance', 'editor', 'run' are more tied to the GUI and should not be considered stable APIs. The default format for 'export' is specified by the admin with the `default_workflow_export_format` config option. Style can be specified as either 'ga' or 'format2' directly to be explicit about which format to download.", + ), +] + +FormatQueryParam = Annotated[ + Optional[str], + Query( + title="Format", + description="The format to download the workflow in.", + ), +] + +WorkflowsHistoryIDQueryParam = Annotated[ + Optional[DecodedDatabaseIdField], + Query( + title="History ID", + description="The history id to import a workflow from.", + ), +] + InvokeWorkflowBody = Annotated[ InvokeWorkflowPayload, Body( @@ -916,6 +891,27 @@ def sharing( """Return the sharing status of the item.""" return self.service.shareable_service.sharing(trans, workflow_id) + @router.get( + "/api/workflows/{workflow_id}/download", + summary="Returns a selected workflow.", + ) + # Preserve the following download route for now for dependent applications -- deprecate at some point + @router.get( + "/api/workflows/download/{workflow_id}", + summary="Returns a selected workflow.", + ) + def workflow_dict( + self, + workflow_id: StoredWorkflowIDPathParam, + history_id: WorkflowsHistoryIDQueryParam = None, + style: StyleQueryParam = "export", + format: FormatQueryParam = None, + version: VersionQueryParam = None, + instance: InstanceQueryParam = False, + trans: ProvidesUserContext = DependsOnTrans, + ): + return self.service.download_workflow(trans, workflow_id, history_id, style, format, version, instance) + @router.put( "/api/workflows/{workflow_id}/enable_link_access", summary="Makes this item accessible by a URL link.", From f425223f98287bc1041b6788e8030392ef3d2867 Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Wed, 28 Feb 2024 09:21:49 +0100 Subject: [PATCH 09/89] Create service method for workflow_dict operation --- .../webapps/galaxy/services/workflows.py | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/lib/galaxy/webapps/galaxy/services/workflows.py b/lib/galaxy/webapps/galaxy/services/workflows.py index e1ea3cdf68d4..cb4bf7fdf211 100644 --- a/lib/galaxy/webapps/galaxy/services/workflows.py +++ b/lib/galaxy/webapps/galaxy/services/workflows.py @@ -8,15 +8,19 @@ Union, ) +from gxformat2._yaml import ordered_dump + from galaxy import ( exceptions, model, + util, web, ) from galaxy.managers.context import ( ProvidesHistoryContext, ProvidesUserContext, ) +from galaxy.managers.histories import HistoryManager from galaxy.managers.workflows import ( RefactorResponse, WorkflowContentsManager, @@ -37,6 +41,7 @@ StoredWorkflowDetailed, ) from galaxy.util.tool_shed.tool_shed_registry import Registry +from galaxy.web import format_return_as_json from galaxy.webapps.galaxy.services.base import ServiceBase from galaxy.webapps.galaxy.services.notifications import NotificationService from galaxy.webapps.galaxy.services.sharable import ShareableService @@ -58,12 +63,39 @@ def __init__( serializer: WorkflowSerializer, tool_shed_registry: Registry, notification_service: NotificationService, + history_manager: HistoryManager, ): self._workflows_manager = workflows_manager self._workflow_contents_manager = workflow_contents_manager self._serializer = serializer self.shareable_service = ShareableService(workflows_manager, serializer, notification_service) self._tool_shed_registry = tool_shed_registry + self._history_manager = history_manager + + def download_workflow(self, trans, workflow_id, history_id, style, format, version, instance): + stored_workflow = self._workflows_manager.get_stored_workflow(trans, workflow_id, by_stored_id=not instance) + history = None + if history_id: + history = self._history_manager.get_accessible(history_id, trans.user, current_history=trans.history) + ret_dict = self._workflow_contents_manager.workflow_to_dict( + trans, stored_workflow, style=style, version=version, history=history + ) + if format == "json-download": + sname = stored_workflow.name + sname = "".join(c in util.FILENAME_VALID_CHARS and c or "_" for c in sname)[0:150] + if ret_dict.get("format-version", None) == "0.1": + extension = "ga" + else: + extension = "gxwf.json" + trans.response.headers["Content-Disposition"] = ( + f'attachment; filename="Galaxy-Workflow-{sname}.{extension}"' + ) + trans.response.set_content_type("application/galaxy-archive") + + if style == "format2" and format != "json-download": + return ordered_dump(ret_dict) + else: + return ret_dict def index( self, From b5b84f82b248808f4be5f1fa60fad382ff113d27 Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Wed, 28 Feb 2024 09:22:04 +0100 Subject: [PATCH 10/89] Remove mapping to legacy routes --- lib/galaxy/webapps/galaxy/buildapp.py | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/lib/galaxy/webapps/galaxy/buildapp.py b/lib/galaxy/webapps/galaxy/buildapp.py index 7850fda37462..8c75e4aee4e3 100644 --- a/lib/galaxy/webapps/galaxy/buildapp.py +++ b/lib/galaxy/webapps/galaxy/buildapp.py @@ -622,21 +622,6 @@ def populate_api_routes(webapp, app): action="import_new_workflow_deprecated", conditions=dict(method=["POST"]), ) - webapp.mapper.connect( - "workflow_dict", - "/api/workflows/{workflow_id}/download", - controller="workflows", - action="workflow_dict", - conditions=dict(method=["GET"]), - ) - # Preserve the following download route for now for dependent applications -- deprecate at some point - webapp.mapper.connect( - "workflow_dict", - "/api/workflows/download/{workflow_id}", - controller="workflows", - action="workflow_dict", - conditions=dict(method=["GET"]), - ) # Deprecated in favor of POST /api/workflows with shared_workflow_id in payload. webapp.mapper.connect( "import_shared_workflow_deprecated", From e202eef449bac49126f2997929f5140bb1c92e64 Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Wed, 28 Feb 2024 09:23:12 +0100 Subject: [PATCH 11/89] Regenerate the client schema --- client/src/api/schema/schema.ts | 84 +++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/client/src/api/schema/schema.ts b/client/src/api/schema/schema.ts index 373d5d14556b..24c823257d4c 100644 --- a/client/src/api/schema/schema.ts +++ b/client/src/api/schema/schema.ts @@ -4874,6 +4874,10 @@ export interface paths { patch?: never; trace?: never; }; + "/api/workflows/download/{workflow_id}": { + /** Returns a selected workflow. */ + get: operations["workflow_dict_api_workflows_download__workflow_id__get"]; + }; "/api/workflows/menu": { parameters: { query?: never; @@ -4946,6 +4950,10 @@ export interface paths { patch?: never; trace?: never; }; + "/api/workflows/{workflow_id}/download": { + /** Returns a selected workflow. */ + get: operations["workflow_dict_api_workflows__workflow_id__download_get"]; + }; "/api/workflows/{workflow_id}/enable_link_access": { parameters: { query?: never; @@ -32750,6 +32758,44 @@ export interface operations { }; }; }; + workflow_dict_api_workflows_download__workflow_id__get: { + /** Returns a selected workflow. */ + parameters: { + /** @description The history id to import a workflow from. */ + /** @description The default is 'export', which is the meant to be used with workflow import endpoints. Other formats such as 'instance', 'editor', 'run' are more tied to the GUI and should not be considered stable APIs. The default format for 'export' is specified by the admin with the `default_workflow_export_format` config option. Style can be specified as either 'ga' or 'format2' directly to be explicit about which format to download. */ + /** @description The format to download the workflow in. */ + /** @description The version of the workflow to fetch. */ + query?: { + history_id?: string | null; + style?: string | null; + format?: string | null; + version?: number | null; + instance?: boolean | null; + }; + /** @description The user ID that will be used to effectively make this API call. Only admins and designated users can make API calls on behalf of other users. */ + header?: { + "run-as"?: string | null; + }; + /** @description The encoded database identifier of the Stored Workflow. */ + path: { + workflow_id: string; + }; + }; + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": Record; + }; + }; + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"]; + }; + }; + }; + }; get_workflow_menu_api_workflows_menu_get: { parameters: { query?: { @@ -32985,6 +33031,44 @@ export interface operations { }; }; }; + workflow_dict_api_workflows__workflow_id__download_get: { + /** Returns a selected workflow. */ + parameters: { + /** @description The history id to import a workflow from. */ + /** @description The default is 'export', which is the meant to be used with workflow import endpoints. Other formats such as 'instance', 'editor', 'run' are more tied to the GUI and should not be considered stable APIs. The default format for 'export' is specified by the admin with the `default_workflow_export_format` config option. Style can be specified as either 'ga' or 'format2' directly to be explicit about which format to download. */ + /** @description The format to download the workflow in. */ + /** @description The version of the workflow to fetch. */ + query?: { + history_id?: string | null; + style?: string | null; + format?: string | null; + version?: number | null; + instance?: boolean | null; + }; + /** @description The user ID that will be used to effectively make this API call. Only admins and designated users can make API calls on behalf of other users. */ + header?: { + "run-as"?: string | null; + }; + /** @description The encoded database identifier of the Stored Workflow. */ + path: { + workflow_id: string; + }; + }; + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": Record; + }; + }; + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"]; + }; + }; + }; + }; enable_link_access_api_workflows__workflow_id__enable_link_access_put: { parameters: { query?: never; From 0e77c3b9e31e38211f6f4f48057a8f337de14c11 Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Thu, 29 Feb 2024 14:58:29 +0100 Subject: [PATCH 12/89] Remove unused internal method in legacy WorkflowsAPIController --- lib/galaxy/webapps/galaxy/api/workflows.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/galaxy/webapps/galaxy/api/workflows.py b/lib/galaxy/webapps/galaxy/api/workflows.py index 1208746da3d9..f3fd899c8d8e 100644 --- a/lib/galaxy/webapps/galaxy/api/workflows.py +++ b/lib/galaxy/webapps/galaxy/api/workflows.py @@ -647,10 +647,6 @@ def _import_tools_if_needed(self, trans, workflow_create_options, raw_workflow_d changeset_revision = item["changeset_revision"] irm.install(tool_shed_url, name, owner, changeset_revision, install_options) - def __get_stored_accessible_workflow(self, trans, workflow_id, **kwd): - instance = util.string_as_bool(kwd.get("instance", "false")) - return self.workflow_manager.get_stored_accessible_workflow(trans, workflow_id, by_stored_id=not instance) - def __get_stored_workflow(self, trans, workflow_id, **kwd): instance = util.string_as_bool(kwd.get("instance", "false")) return self.workflow_manager.get_stored_workflow(trans, workflow_id, by_stored_id=not instance) From 2c67981105848a3a93be7009fe29d6dcf930e9ae Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Thu, 29 Feb 2024 14:59:10 +0100 Subject: [PATCH 13/89] Use the correct get_workflow method from WorkflowsManager --- lib/galaxy/webapps/galaxy/services/workflows.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/galaxy/webapps/galaxy/services/workflows.py b/lib/galaxy/webapps/galaxy/services/workflows.py index cb4bf7fdf211..9beb42dff665 100644 --- a/lib/galaxy/webapps/galaxy/services/workflows.py +++ b/lib/galaxy/webapps/galaxy/services/workflows.py @@ -8,6 +8,7 @@ Union, ) +from fastapi.responses import PlainTextResponse from gxformat2._yaml import ordered_dump from galaxy import ( @@ -73,7 +74,9 @@ def __init__( self._history_manager = history_manager def download_workflow(self, trans, workflow_id, history_id, style, format, version, instance): - stored_workflow = self._workflows_manager.get_stored_workflow(trans, workflow_id, by_stored_id=not instance) + stored_workflow = self._workflows_manager.get_stored_accessible_workflow( + trans, workflow_id, by_stored_id=not instance + ) history = None if history_id: history = self._history_manager.get_accessible(history_id, trans.user, current_history=trans.history) From 6014151532b7ec9f83d290a2ce95d8d72e4ab09e Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Thu, 29 Feb 2024 18:09:39 +0100 Subject: [PATCH 14/89] Type yaml return of download_workflow method --- lib/galaxy/webapps/galaxy/services/workflows.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/galaxy/webapps/galaxy/services/workflows.py b/lib/galaxy/webapps/galaxy/services/workflows.py index 9beb42dff665..32640af47cca 100644 --- a/lib/galaxy/webapps/galaxy/services/workflows.py +++ b/lib/galaxy/webapps/galaxy/services/workflows.py @@ -42,7 +42,6 @@ StoredWorkflowDetailed, ) from galaxy.util.tool_shed.tool_shed_registry import Registry -from galaxy.web import format_return_as_json from galaxy.webapps.galaxy.services.base import ServiceBase from galaxy.webapps.galaxy.services.notifications import NotificationService from galaxy.webapps.galaxy.services.sharable import ShareableService @@ -96,7 +95,7 @@ def download_workflow(self, trans, workflow_id, history_id, style, format, versi trans.response.set_content_type("application/galaxy-archive") if style == "format2" and format != "json-download": - return ordered_dump(ret_dict) + return PlainTextResponse(ordered_dump(ret_dict)) else: return ret_dict From 0474eef1750a60d746ab1588c7b1c527f9305a39 Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Sun, 3 Mar 2024 17:26:18 +0100 Subject: [PATCH 15/89] Add pydantic models for return of workflow_dict operation --- lib/galaxy/schema/workflows.py | 327 +++++++++++++++++++++++++++++++++ 1 file changed, 327 insertions(+) diff --git a/lib/galaxy/schema/workflows.py b/lib/galaxy/schema/workflows.py index b8e1aadaab3b..5543c6a9d290 100644 --- a/lib/galaxy/schema/workflows.py +++ b/lib/galaxy/schema/workflows.py @@ -11,6 +11,7 @@ Field, field_validator, ) +from typing_extensions import Annotated from galaxy.schema.fields import DecodedDatabaseIdField from galaxy.schema.schema import ( @@ -27,8 +28,17 @@ SubworkflowStep, ToolStep, WorkflowInput, + WorkflowModuleType, ) +WorkflowAnnotationField = Annotated[ + Optional[str], + Field( + title="Annotation", + description="An annotation to provide details or to help understand the purpose and usage of this item.", + ), +] + class GetTargetHistoryPayload(Model): # TODO - Are the descriptions correct? @@ -250,3 +260,320 @@ class SetWorkflowMenuSummary(Model): title="Status", description="The status of the operation.", ) + + +class WorkflowDictPreviewSteps(Model): + order_index: int = Field( + ..., + title="Order Index", + description="The order index of the step.", + ) + type: WorkflowModuleType = Field( + ..., + title="Type", + description="The type of workflow module.", + ) + annotation: WorkflowAnnotationField = None + label: str = Field( + ..., + title="Label", + description="The label of the step.", + ) + tool_id: Optional[str] = Field( + None, title="Tool ID", description="The unique name of the tool associated with this step." + ) + tool_version: Optional[str] = Field( + None, title="Tool Version", description="The version of the tool associated with this step." + ) + inputs: List[Dict[str, Any]] = Field( + ..., + title="Inputs", + description="The inputs of the step.", + ) + errors: Optional[List[str]] = Field( + None, + title="Errors", + description="Any errors associated with the subworkflow.", + ) + + +class WorkflowDictEditorSteps(Model): + id: int = Field( + ..., + title="ID", + description="The order index of the step.", + ) + type: WorkflowModuleType = Field( + ..., + title="Type", + description="The type of workflow module.", + ) + label: str = Field( + ..., + title="Label", + description="The label of the step.", + ) + content_id: Optional[str] = Field( + None, + title="Content ID", + description="The identifier for the content of the step.", + ) + name: Optional[str] = Field( + None, + title="Name", + description="The name of the step.", + ) + tool_state: Optional[Dict[str, Any]] = Field( + None, + title="Tool State", + description="The state of the step's tool.", + ) + errors: Optional[List[str]] = Field( + None, + title="Errors", + description="Any errors associated with the step.", + ) + inputs: Optional[List[Dict[str, Any]]] = Field( + None, + title="Inputs", + description="The inputs of the step.", + ) + outputs: Optional[List[Dict[str, Any]]] = Field( + None, + title="Outputs", + description="The outputs of the step.", + ) + config_form: Optional[Dict[str, Any]] = Field( + None, + title="Config Form", + description="The configuration form for the step.", + ) + annotation: WorkflowAnnotationField + post_job_actions: Optional[Dict[str, Any]] = Field( + None, + title="Post Job Actions", + description="A dictionary of post-job actions for the step.", + ) + uuid: Optional[str] = Field( + None, + title="UUID", + description="The UUID of the step.", + ) + when: Optional[str] = Field( + None, + title="When", + description="The when expression for the step.", + ) + workflow_outputs: Optional[List[Dict[str, Any]]] = Field( + None, + title="Workflow Outputs", + description="A list of workflow outputs for the step.", + ) + tooltip: Optional[str] = Field( + None, + title="Tooltip", + description="The tooltip for the step.", + ) + input_connections: Optional[Dict[str, Any]] = Field( + None, + title="Input Connections", + description="A dictionary representing the input connections for the step.", + ) + position: Optional[Dict[str, Any]] = Field( + None, + title="Position", + description="The position of the step.", + ) + tool_version: Optional[str] = Field( + None, + title="Tool Version", + description="The version of the step's tool.", + ) + + +# TODO - This is missing some fields - see manager line 1006 +class WorkflowDictRunSteps(Model): + inputs: List[Dict[str, Any]] = Field( + ..., + title="Inputs", + description="The inputs of the step.", + ) + when: Optional[str] = Field( + None, + title="When", + description="The when expression for the step.", + ) + replacement_parameters: Optional[List[Dict[str, Any]]] = Field( + None, + title="Replacement Parameters", + description="Informal replacement parameters for the step.", + ) + step_type: WorkflowModuleType = Field( + ..., + title="Step Type", + description="The type of the step.", + ) + step_label: str = Field( + ..., + title="Step Label", + description="The label of the step.", + ) + step_name: str = Field( + ..., + title="Step Name", + description="The name of the step's module.", + ) + step_version: Optional[str] = Field( + None, + title="Step Version", + description="The version of the step's module.", + ) + step_index: int = Field( + ..., + title="Step Index", + description="The order index of the step.", + ) + output_connections: List[Dict[str, Any]] = Field( + ..., + title="Output Connections", + description="A list of dictionaries representing the output connections of the step.", + ) + annotation: WorkflowAnnotationField = None + messages: Optional[List[str]] = Field( + None, + title="Messages", + description="Upgrade messages for the step.", + ) + # TODO - can further specify post_job_actions - look at code in manager + post_job_actions: Optional[List[Dict[str, Any]]] = Field( + None, + title="Post Job Actions", + description="A list of dictionaries representing the post-job actions for the step.", + ) + + +class WorkflowDictBaseModel(Model): + name: str = Field( + ..., + title="Name", + description="The name of the workflow.", + ) + version: int = Field( + ..., + title="Version", + description="The version of the workflow.", + ) + + +class WorkflowDictPreviewSummary(WorkflowDictBaseModel): + steps: List[WorkflowDictPreviewSteps] = Field( + ..., + title="Steps", + description="A dictionary with information about all the steps of the workflow.", + ) + + +class WorkflowDictEditorSummary(WorkflowDictBaseModel): + upgrade_messages: Dict[int, str] = Field( + ..., + title="Upgrade Messages", + description="Upgrade messages for each step in the workflow.", + ) + report: Dict[str, Any] = Field( + ..., + title="Report", + description="The reports configuration for the workflow.", + ) + comments: List[Dict[str, Any]] = Field( + ..., + title="Comments", + description="Comments on the workflow.", + ) + annotation: WorkflowAnnotationField + license: Optional[str] = Field( + None, + title="License", + description="The license information for the workflow.", + ) + creator: Optional[Dict[str, Any]] = Field( + None, + title="Creator", + description="Metadata about the creator of the workflow.", + ) + source_metadata: Optional[Dict[str, Any]] = Field( + None, + title="Source Metadata", + description="Metadata about the source of the workflow", + ) + steps: Dict[int, WorkflowDictEditorSteps] = Field( + ..., + title="Steps", + description="A dictionary with information about all the steps of the workflow.", + ) + + +class WorkflowDictRunSummary(WorkflowDictBaseModel): + id: Optional[str] = Field( + None, + title="ID", + description="The encoded ID of the stored workflow.", + ) + history_id: Optional[str] = Field( + None, + title="History ID", + description="The encoded ID of the history associated with the workflow (or None if not applicable).", + ) + step_version_changes: Optional[List[Dict[str, Any]]] = Field( + None, + title="Step Version Changes", + description="A list of version changes for the workflow steps.", + ) + has_upgrade_messages: Optional[bool] = Field( + None, + title="Has Upgrade Messages", + description="A boolean indicating whether the workflow has upgrade messages.", + ) + workflow_resource_parameters: Optional[Dict[str, Any]] = Field( + None, + title="Workflow Resource Parameters", + description="The resource parameters of the workflow.", + ) + steps: List[WorkflowDictRunSteps] = Field( + ..., + title="Steps", + description="A dictionary with information about all the steps of the workflow.", + ) + + +class WorkflowDictExportSummary(WorkflowDictBaseModel): + a_galaxy_workflow: Optional[bool] = Field( + None, + title="A Galaxy Workflow", + description="Is a Galaxy workflow.", + ) + format_version: Optional[str] = Field( + None, + title="Format Version", + description="The version of the workflow format being used.", + ) + annotation: WorkflowAnnotationField + tags: Optional[List[str]] = Field( + None, + title="Tags", + description="The tags associated with the workflow.", + ) + uuid: Optional[str] = Field( + None, + title="UUID", + description="The UUID (Universally Unique Identifier) of the workflow, represented as a string.", + ) + comments: Optional[List[Dict[str, Any]]] = Field( + None, + title="Comments", + description="A list of dictionaries representing comments associated with the workflow.", + ) + report: Optional[Dict[str, Any]] = Field( + None, + title="Report", + description="The configuration for generating a report for the workflow.", + ) From 8d400fa6066465368d04910bcb86bf17c0a191cb Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Sun, 3 Mar 2024 17:26:41 +0100 Subject: [PATCH 16/89] Type return of download method --- .../webapps/galaxy/services/workflows.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/lib/galaxy/webapps/galaxy/services/workflows.py b/lib/galaxy/webapps/galaxy/services/workflows.py index 32640af47cca..55e15f0ba1bf 100644 --- a/lib/galaxy/webapps/galaxy/services/workflows.py +++ b/lib/galaxy/webapps/galaxy/services/workflows.py @@ -40,6 +40,9 @@ SetWorkflowMenuPayload, SetWorkflowMenuSummary, StoredWorkflowDetailed, + WorkflowDictEditorSummary, + WorkflowDictPreviewSummary, + WorkflowDictRunSummary, ) from galaxy.util.tool_shed.tool_shed_registry import Registry from galaxy.webapps.galaxy.services.base import ServiceBase @@ -96,6 +99,22 @@ def download_workflow(self, trans, workflow_id, history_id, style, format, versi if style == "format2" and format != "json-download": return PlainTextResponse(ordered_dump(ret_dict)) + elif style == "export": + return ret_dict + elif style == "editor": + return WorkflowDictEditorSummary(**ret_dict) + elif style == ("legacy" or "instance"): + return StoredWorkflowDetailed(**ret_dict) + elif style == "run": + return WorkflowDictRunSummary(**ret_dict) + elif style == "preview": + return WorkflowDictPreviewSummary(**ret_dict) + elif style == "format2": + return ret_dict + elif style == "format2_wrapped_yaml": + return ret_dict + elif style == "ga": + return ret_dict else: return ret_dict From 183b27d870d594a33bf83ca112b5d4ae5d944cc5 Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Mon, 11 Mar 2024 11:50:26 +0100 Subject: [PATCH 17/89] Add return model --- lib/galaxy/webapps/galaxy/services/workflows.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/galaxy/webapps/galaxy/services/workflows.py b/lib/galaxy/webapps/galaxy/services/workflows.py index 55e15f0ba1bf..f318158ff736 100644 --- a/lib/galaxy/webapps/galaxy/services/workflows.py +++ b/lib/galaxy/webapps/galaxy/services/workflows.py @@ -41,6 +41,7 @@ SetWorkflowMenuSummary, StoredWorkflowDetailed, WorkflowDictEditorSummary, + WorkflowDictExportSummary, WorkflowDictPreviewSummary, WorkflowDictRunSummary, ) @@ -96,11 +97,10 @@ def download_workflow(self, trans, workflow_id, history_id, style, format, versi f'attachment; filename="Galaxy-Workflow-{sname}.{extension}"' ) trans.response.set_content_type("application/galaxy-archive") - + if style == "export": + style = style = self._workflow_contents_manager.app.config.default_workflow_export_format if style == "format2" and format != "json-download": return PlainTextResponse(ordered_dump(ret_dict)) - elif style == "export": - return ret_dict elif style == "editor": return WorkflowDictEditorSummary(**ret_dict) elif style == ("legacy" or "instance"): @@ -114,7 +114,7 @@ def download_workflow(self, trans, workflow_id, history_id, style, format, versi elif style == "format2_wrapped_yaml": return ret_dict elif style == "ga": - return ret_dict + return WorkflowDictExportSummary(**ret_dict) else: return ret_dict From 6325d206b9d63001472da40fa9fef4620eed3e88 Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Mon, 11 Mar 2024 11:51:52 +0100 Subject: [PATCH 18/89] Make label optional in steps model of editor and run workflowdictsummary --- lib/galaxy/schema/workflows.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/galaxy/schema/workflows.py b/lib/galaxy/schema/workflows.py index 5543c6a9d290..8e3e8e51d58f 100644 --- a/lib/galaxy/schema/workflows.py +++ b/lib/galaxy/schema/workflows.py @@ -308,8 +308,8 @@ class WorkflowDictEditorSteps(Model): title="Type", description="The type of workflow module.", ) - label: str = Field( - ..., + label: Optional[str] = Field( + None, title="Label", description="The label of the step.", ) @@ -413,8 +413,8 @@ class WorkflowDictRunSteps(Model): title="Step Type", description="The type of the step.", ) - step_label: str = Field( - ..., + step_label: Optional[str] = Field( + None, title="Step Label", description="The label of the step.", ) From fd4c5c46f997c78697ba33c8bcece732e89bd682 Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Mon, 11 Mar 2024 14:54:19 +0100 Subject: [PATCH 19/89] Add step model for WorkflowDictExportSummary --- lib/galaxy/schema/workflows.py | 155 ++++++++++++++++++++++++++++++++- 1 file changed, 154 insertions(+), 1 deletion(-) diff --git a/lib/galaxy/schema/workflows.py b/lib/galaxy/schema/workflows.py index 8e3e8e51d58f..9b68126baab0 100644 --- a/lib/galaxy/schema/workflows.py +++ b/lib/galaxy/schema/workflows.py @@ -13,6 +13,7 @@ ) from typing_extensions import Annotated +from galaxy.model import InputConnDictType from galaxy.schema.fields import DecodedDatabaseIdField from galaxy.schema.schema import ( AnnotationField, @@ -452,6 +453,138 @@ class WorkflowDictRunSteps(Model): ) +class WorkflowDictExportSteps(Model): + id: int = Field( + ..., + title="ID", + description="The order index of the step.", + ) + type: WorkflowModuleType = Field( + ..., + title="Type", + description="The type of the step.", + ) + content_id: Optional[str] = Field( + None, + title="Content ID", + description="The content ID of the step.", + ) + tool_id: Optional[str] = Field( + None, + title="Tool ID", + description="The tool ID associated with the step (applicable only if the step type is 'tool').", + ) + tool_version: Optional[str] = Field( + None, + title="Tool Version", + description="The version of the tool associated with the step.", + ) + name: str = Field( + ..., + title="Name", + description="The name of the step.", + ) + tool_state: Optional[str] = Field( + None, + title="Tool State", + description="The serialized state of the tool associated with the step.", + ) + errors: Optional[str] = Field( + None, + title="Errors", + description="Any errors associated with the step.", + ) + uuid: str = Field( + ..., + title="UUID", + description="The UUID (Universally Unique Identifier) of the step.", + ) + label: Optional[str] = Field( + None, + title="Label", + description="The label of the step (optional).", + ) + annotation: WorkflowAnnotationField = Field( + None, + title="Annotation", + description="The annotation associated with the step.", + ) + when: Optional[str] = Field( + None, + title="When", + description="The when expression of the step.", + ) + # TODO - can be modeled see manager line 1483 or below + tool_shed_repository: Optional[Dict[str, Any]] = Field( + None, + title="Tool Shed Repository", + description="Information about the tool shed repository associated with the tool.", + ) + # "name" (type: str): The name of the tool shed repository. + # "owner" (type: str): The owner of the tool shed repository. + # "changeset_revision" (type: str): The changeset revision of the tool shed repository. + # "tool_shed" (type: str): The tool shed URL. + tool_representation: Optional[Dict[str, Any]] = Field( + None, + title="Tool Representation", + description="The representation of the tool associated with the step.", + ) + # TODO - can be modeled see manager line 1500 + post_job_actions: Optional[Dict[str, Any]] = Field( + None, + title="Post Job Actions", + description="A dictionary containing post-job actions associated with the step.", + ) + # TODO - can also be WorkflowDictExportSummary see manager line 1512 + subworkflow: Optional[Dict[str, Any]] = Field( + None, + title="Sub Workflow", + description="The sub-workflow associated with the step.", + ) + # TODO - can be modeled see manager line 1516 -1532 + inputs: Optional[List[Dict[str, Any]]] = Field( + None, + title="Inputs", + description="The inputs of the step.", + ) + # TODO - can be modeled see manager line 1535 and 1543 + workflow_outputs: Optional[List[Dict[str, Any]]] = Field( + None, + title="Workflow Outputs", + description="A list of workflow outputs for the step.", + ) + # TODO - can be modeled see manager line 1546 + outputs: Optional[List[Dict[str, Any]]] = Field( + None, + title="Outputs", + description="The outputs of the step.", + ) + # TODO - can be modeled see manager line 1551 + in_parameter: Optional[Dict[str, Any]] = Field( + None, title="In", description="The input connections of the step.", alias="in" + ) + input_connections: Optional[InputConnDictType] = Field( + None, + title="Input Connections", + description="The input connections of the step.", + ) + position: Optional[Any] = Field( + None, + title="Position", + description="The position of the step.", + ) + + +# "post_job_actions" (type: dict): Dictionary containing post-job actions associated with the step. + +# The keys are a combination of action_type and output_name. +# The values are dictionaries with the following items: +# "action_type" (type: str): The type of the post-job action. +# "output_name" (type: str): The name of the output associated with the post-job action. +# "action_arguments" (type: str): The arguments of the post-job action. +# These items provide detailed information about each step in the workflow, including the step type, associated tools, errors, and annotations. + + class WorkflowDictBaseModel(Model): name: str = Field( ..., @@ -546,7 +679,7 @@ class WorkflowDictRunSummary(WorkflowDictBaseModel): class WorkflowDictExportSummary(WorkflowDictBaseModel): - a_galaxy_workflow: Optional[bool] = Field( + a_galaxy_workflow: Optional[str] = Field( None, title="A Galaxy Workflow", description="Is a Galaxy workflow.", @@ -577,3 +710,23 @@ class WorkflowDictExportSummary(WorkflowDictBaseModel): title="Report", description="The configuration for generating a report for the workflow.", ) + creator: Optional[Dict[str, Any]] = Field( + None, + title="Creator", + description="Metadata about the creator of the workflow.", + ) + license: Optional[str] = Field( + None, + title="License", + description="The license information for the workflow.", + ) + source_metadata: Optional[Dict[str, Any]] = Field( + None, + title="Source Metadata", + description="Metadata about the source of the workflow.", + ) + steps: Dict[int, WorkflowDictExportSteps] = Field( + ..., + title="Steps", + description="A dictionary with information about all the steps of the workflow.", + ) From 6e7c6dd36b9d0bdb4e48df3045ee9e6765463db0 Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Mon, 11 Mar 2024 20:18:30 +0100 Subject: [PATCH 20/89] Change type of input_connections field in step model for WorkflowExportSummary --- lib/galaxy/schema/workflows.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/galaxy/schema/workflows.py b/lib/galaxy/schema/workflows.py index 9b68126baab0..35a654b8770c 100644 --- a/lib/galaxy/schema/workflows.py +++ b/lib/galaxy/schema/workflows.py @@ -13,7 +13,6 @@ ) from typing_extensions import Annotated -from galaxy.model import InputConnDictType from galaxy.schema.fields import DecodedDatabaseIdField from galaxy.schema.schema import ( AnnotationField, @@ -563,7 +562,7 @@ class WorkflowDictExportSteps(Model): in_parameter: Optional[Dict[str, Any]] = Field( None, title="In", description="The input connections of the step.", alias="in" ) - input_connections: Optional[InputConnDictType] = Field( + input_connections: Optional[Dict[str, Union[Dict[str, Any], List[Dict[str, Any]]]]] = Field( None, title="Input Connections", description="The input connections of the step.", From 1db0e5d129cecd6692dd642bc480ddac82a8b85e Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Wed, 13 Mar 2024 21:32:24 +0100 Subject: [PATCH 21/89] Add pydantic model for workflowdict in format2 version --- lib/galaxy/schema/workflows.py | 78 +++++++++++++++++++++++++++++----- 1 file changed, 68 insertions(+), 10 deletions(-) diff --git a/lib/galaxy/schema/workflows.py b/lib/galaxy/schema/workflows.py index 35a654b8770c..049be60247e9 100644 --- a/lib/galaxy/schema/workflows.py +++ b/lib/galaxy/schema/workflows.py @@ -574,16 +574,6 @@ class WorkflowDictExportSteps(Model): ) -# "post_job_actions" (type: dict): Dictionary containing post-job actions associated with the step. - -# The keys are a combination of action_type and output_name. -# The values are dictionaries with the following items: -# "action_type" (type: str): The type of the post-job action. -# "output_name" (type: str): The name of the output associated with the post-job action. -# "action_arguments" (type: str): The arguments of the post-job action. -# These items provide detailed information about each step in the workflow, including the step type, associated tools, errors, and annotations. - - class WorkflowDictBaseModel(Model): name: str = Field( ..., @@ -729,3 +719,71 @@ class WorkflowDictExportSummary(WorkflowDictBaseModel): title="Steps", description="A dictionary with information about all the steps of the workflow.", ) + + +class WorkflowDictFormat2Summary(Model): + workflow_class: str = Field( + ..., + title="Class", + description="The class of the workflow.", + alias="class", + ) + label: Optional[str] = Field( + None, + title="Label", + description="The label or name of the workflow.", + ) + creator: Optional[Dict[str, Any]] = Field( + None, + title="Creator", + description="Metadata about the creator of the workflow.", + ) + license: Optional[str] = Field( + None, + title="License", + description="The license information for the workflow.", + ) + release: Optional[str] = Field( + None, + title="Release", + description="The release information for the workflow.", + ) + tags: Optional[List[str]] = Field( + None, + title="Tags", + description="The tags associated with the workflow.", + ) + uuid: Optional[str] = Field( + None, + title="UUID", + description="The UUID (Universally Unique Identifier) of the workflow, represented as a string.", + ) + report: Optional[Dict[str, Any]] = Field( + None, + title="Report", + description="The configuration for generating a report for the workflow.", + ) + inputs: Optional[Dict[str, Any]] = Field( + None, + title="Inputs", + description="A dictionary representing the inputs of the workflow.", + ) + outputs: Optional[Dict[str, Any]] = Field( + None, + title="Outputs", + description="A dictionary representing the outputs of the workflow.", + ) + # TODO - step into line 888 in manager + steps: Dict[str, Any] = Field( + ..., + title="Steps", + description="A dictionary representing the steps of the workflow.", + ) + + +class WorkflowDictFormat2WrappedYamlSummary(Model): + yaml_content: str = Field( + ..., + title="YAML Content", + description="The content of the workflow in YAML format.", + ) From e084b8e4821183bb400d6ffd61e615aff31cc6a6 Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Wed, 13 Mar 2024 21:33:12 +0100 Subject: [PATCH 22/89] Add pydantic models to return of workflow_dict operation --- lib/galaxy/webapps/galaxy/api/workflows.py | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/lib/galaxy/webapps/galaxy/api/workflows.py b/lib/galaxy/webapps/galaxy/api/workflows.py index f3fd899c8d8e..4fa6ca6c9aab 100644 --- a/lib/galaxy/webapps/galaxy/api/workflows.py +++ b/lib/galaxy/webapps/galaxy/api/workflows.py @@ -82,6 +82,12 @@ SetWorkflowMenuPayload, SetWorkflowMenuSummary, StoredWorkflowDetailed, + WorkflowDictEditorSummary, + WorkflowDictExportSummary, + WorkflowDictFormat2Summary, + WorkflowDictFormat2WrappedYamlSummary, + WorkflowDictPreviewSummary, + WorkflowDictRunSummary, ) from galaxy.structured_app import StructuredApp from galaxy.tool_shed.galaxy_install.install_manager import InstallRepositoryManager @@ -831,6 +837,16 @@ def __get_stored_workflow(self, trans, workflow_id, **kwd): ), ] +DownloadWorkflowSummary = Union[ + WorkflowDictEditorSummary, + StoredWorkflowDetailed, + WorkflowDictRunSummary, + WorkflowDictPreviewSummary, + WorkflowDictFormat2Summary, + WorkflowDictExportSummary, + WorkflowDictFormat2WrappedYamlSummary, +] + @router.cbv class FastAPIWorkflows: @@ -890,11 +906,13 @@ def sharing( @router.get( "/api/workflows/{workflow_id}/download", summary="Returns a selected workflow.", + response_model_exclude_unset=True, ) # Preserve the following download route for now for dependent applications -- deprecate at some point @router.get( "/api/workflows/download/{workflow_id}", summary="Returns a selected workflow.", + response_model_exclude_unset=True, ) def workflow_dict( self, @@ -905,7 +923,7 @@ def workflow_dict( version: VersionQueryParam = None, instance: InstanceQueryParam = False, trans: ProvidesUserContext = DependsOnTrans, - ): + ) -> DownloadWorkflowSummary: return self.service.download_workflow(trans, workflow_id, history_id, style, format, version, instance) @router.put( From 37c8a9ad9e7686c4dcd01418814fbdf997873acd Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Wed, 13 Mar 2024 21:34:05 +0100 Subject: [PATCH 23/89] Add further typing to return of download_workflow method --- lib/galaxy/webapps/galaxy/services/workflows.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/galaxy/webapps/galaxy/services/workflows.py b/lib/galaxy/webapps/galaxy/services/workflows.py index f318158ff736..cfacfd756bb8 100644 --- a/lib/galaxy/webapps/galaxy/services/workflows.py +++ b/lib/galaxy/webapps/galaxy/services/workflows.py @@ -42,6 +42,8 @@ StoredWorkflowDetailed, WorkflowDictEditorSummary, WorkflowDictExportSummary, + WorkflowDictFormat2Summary, + WorkflowDictFormat2WrappedYamlSummary, WorkflowDictPreviewSummary, WorkflowDictRunSummary, ) @@ -110,13 +112,13 @@ def download_workflow(self, trans, workflow_id, history_id, style, format, versi elif style == "preview": return WorkflowDictPreviewSummary(**ret_dict) elif style == "format2": - return ret_dict + return WorkflowDictFormat2Summary(**ret_dict) elif style == "format2_wrapped_yaml": - return ret_dict + return WorkflowDictFormat2WrappedYamlSummary(**ret_dict) elif style == "ga": return WorkflowDictExportSummary(**ret_dict) else: - return ret_dict + raise exceptions.RequestParameterInvalidException(f"Unknown workflow style {style}") def index( self, From a08dee5b6837f8569fa0c4f3822e29df06ce9d83 Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Wed, 13 Mar 2024 21:35:16 +0100 Subject: [PATCH 24/89] Regenerate the client schema --- client/src/api/schema/schema.ts | 591 +++++++++++++++++++++++++++++++- 1 file changed, 589 insertions(+), 2 deletions(-) diff --git a/client/src/api/schema/schema.ts b/client/src/api/schema/schema.ts index 24c823257d4c..27f62c7dea99 100644 --- a/client/src/api/schema/schema.ts +++ b/client/src/api/schema/schema.ts @@ -16888,6 +16888,579 @@ export interface components { * @default [] */ VisualizationSummaryList: components["schemas"]["VisualizationSummary"][]; + /** WorkflowDictEditorSteps */ + WorkflowDictEditorSteps: { + /** + * Annotation + * @description An annotation to provide details or to help understand the purpose and usage of this item. + */ + annotation: string | null; + /** + * Config Form + * @description The configuration form for the step. + */ + config_form?: Record | null; + /** + * Content ID + * @description The identifier for the content of the step. + */ + content_id?: string | null; + /** + * Errors + * @description Any errors associated with the step. + */ + errors?: string[] | null; + /** + * ID + * @description The order index of the step. + */ + id: number; + /** + * Input Connections + * @description A dictionary representing the input connections for the step. + */ + input_connections?: Record | null; + /** + * Inputs + * @description The inputs of the step. + */ + inputs?: Record[] | null; + /** + * Label + * @description The label of the step. + */ + label?: string | null; + /** + * Name + * @description The name of the step. + */ + name?: string | null; + /** + * Outputs + * @description The outputs of the step. + */ + outputs?: Record[] | null; + /** + * Position + * @description The position of the step. + */ + position?: Record | null; + /** + * Post Job Actions + * @description A dictionary of post-job actions for the step. + */ + post_job_actions?: Record | null; + /** + * Tool State + * @description The state of the step's tool. + */ + tool_state?: Record | null; + /** + * Tool Version + * @description The version of the step's tool. + */ + tool_version?: string | null; + /** + * Tooltip + * @description The tooltip for the step. + */ + tooltip?: string | null; + /** + * Type + * @description The type of workflow module. + */ + type: components["schemas"]["WorkflowModuleType"]; + /** + * UUID + * @description The UUID of the step. + */ + uuid?: string | null; + /** + * When + * @description The when expression for the step. + */ + when?: string | null; + /** + * Workflow Outputs + * @description A list of workflow outputs for the step. + */ + workflow_outputs?: Record[] | null; + }; + /** WorkflowDictEditorSummary */ + WorkflowDictEditorSummary: { + /** + * Annotation + * @description An annotation to provide details or to help understand the purpose and usage of this item. + */ + annotation: string | null; + /** + * Comments + * @description Comments on the workflow. + */ + comments: Record[]; + /** + * Creator + * @description Metadata about the creator of the workflow. + */ + creator?: Record | null; + /** + * License + * @description The license information for the workflow. + */ + license?: string | null; + /** + * Name + * @description The name of the workflow. + */ + name: string; + /** + * Report + * @description The reports configuration for the workflow. + */ + report: Record; + /** + * Source Metadata + * @description Metadata about the source of the workflow + */ + source_metadata?: Record | null; + /** + * Steps + * @description A dictionary with information about all the steps of the workflow. + */ + steps: { + [key: string]: components["schemas"]["WorkflowDictEditorSteps"] | undefined; + }; + /** + * Upgrade Messages + * @description Upgrade messages for each step in the workflow. + */ + upgrade_messages: { + [key: string]: string | undefined; + }; + /** + * Version + * @description The version of the workflow. + */ + version: number; + }; + /** WorkflowDictExportSteps */ + WorkflowDictExportSteps: { + /** + * Annotation + * @description The annotation associated with the step. + */ + annotation?: string | null; + /** + * Content ID + * @description The content ID of the step. + */ + content_id?: string | null; + /** + * Errors + * @description Any errors associated with the step. + */ + errors?: string | null; + /** + * ID + * @description The order index of the step. + */ + id: number; + /** + * In + * @description The input connections of the step. + */ + in?: Record | null; + /** + * Input Connections + * @description The input connections of the step. + */ + input_connections?: { + [key: string]: (Record | Record[]) | undefined; + } | null; + /** + * Inputs + * @description The inputs of the step. + */ + inputs?: Record[] | null; + /** + * Label + * @description The label of the step (optional). + */ + label?: string | null; + /** + * Name + * @description The name of the step. + */ + name: string; + /** + * Outputs + * @description The outputs of the step. + */ + outputs?: Record[] | null; + /** + * Position + * @description The position of the step. + */ + position?: Record | null; + /** + * Post Job Actions + * @description A dictionary containing post-job actions associated with the step. + */ + post_job_actions?: Record | null; + /** + * Sub Workflow + * @description The sub-workflow associated with the step. + */ + subworkflow?: Record | null; + /** + * Tool ID + * @description The tool ID associated with the step (applicable only if the step type is 'tool'). + */ + tool_id?: string | null; + /** + * Tool Representation + * @description The representation of the tool associated with the step. + */ + tool_representation?: Record | null; + /** + * Tool Shed Repository + * @description Information about the tool shed repository associated with the tool. + */ + tool_shed_repository?: Record | null; + /** + * Tool State + * @description The serialized state of the tool associated with the step. + */ + tool_state?: string | null; + /** + * Tool Version + * @description The version of the tool associated with the step. + */ + tool_version?: string | null; + /** + * Type + * @description The type of the step. + */ + type: components["schemas"]["WorkflowModuleType"]; + /** + * UUID + * @description The UUID (Universally Unique Identifier) of the step. + */ + uuid: string; + /** + * When + * @description The when expression of the step. + */ + when?: string | null; + /** + * Workflow Outputs + * @description A list of workflow outputs for the step. + */ + workflow_outputs?: Record[] | null; + }; + /** WorkflowDictExportSummary */ + WorkflowDictExportSummary: { + /** + * A Galaxy Workflow + * @description Is a Galaxy workflow. + */ + a_galaxy_workflow?: string | null; + /** + * Annotation + * @description An annotation to provide details or to help understand the purpose and usage of this item. + */ + annotation: string | null; + /** + * Comments + * @description A list of dictionaries representing comments associated with the workflow. + */ + comments?: Record[] | null; + /** + * Creator + * @description Metadata about the creator of the workflow. + */ + creator?: Record | null; + /** + * Format Version + * @description The version of the workflow format being used. + */ + format_version?: string | null; + /** + * License + * @description The license information for the workflow. + */ + license?: string | null; + /** + * Name + * @description The name of the workflow. + */ + name: string; + /** + * Report + * @description The configuration for generating a report for the workflow. + */ + report?: Record | null; + /** + * Source Metadata + * @description Metadata about the source of the workflow. + */ + source_metadata?: Record | null; + /** + * Steps + * @description A dictionary with information about all the steps of the workflow. + */ + steps: { + [key: string]: components["schemas"]["WorkflowDictExportSteps"] | undefined; + }; + /** + * Tags + * @description The tags associated with the workflow. + */ + tags?: string[] | null; + /** + * UUID + * @description The UUID (Universally Unique Identifier) of the workflow, represented as a string. + */ + uuid?: string | null; + /** + * Version + * @description The version of the workflow. + */ + version: number; + }; + /** WorkflowDictFormat2Summary */ + WorkflowDictFormat2Summary: { + /** + * Class + * @description The class of the workflow. + */ + class: string; + /** + * Creator + * @description Metadata about the creator of the workflow. + */ + creator?: Record | null; + /** + * Inputs + * @description A dictionary representing the inputs of the workflow. + */ + inputs?: Record | null; + /** + * Label + * @description The label or name of the workflow. + */ + label?: string | null; + /** + * License + * @description The license information for the workflow. + */ + license?: string | null; + /** + * Outputs + * @description A dictionary representing the outputs of the workflow. + */ + outputs?: Record | null; + /** + * Release + * @description The release information for the workflow. + */ + release?: string | null; + /** + * Report + * @description The configuration for generating a report for the workflow. + */ + report?: Record | null; + /** + * Steps + * @description A dictionary representing the steps of the workflow. + */ + steps: Record; + /** + * Tags + * @description The tags associated with the workflow. + */ + tags?: string[] | null; + /** + * UUID + * @description The UUID (Universally Unique Identifier) of the workflow, represented as a string. + */ + uuid?: string | null; + }; + /** WorkflowDictFormat2WrappedYamlSummary */ + WorkflowDictFormat2WrappedYamlSummary: { + /** + * YAML Content + * @description The content of the workflow in YAML format. + */ + yaml_content: string; + }; + /** WorkflowDictPreviewSteps */ + WorkflowDictPreviewSteps: { + /** + * Annotation + * @description An annotation to provide details or to help understand the purpose and usage of this item. + */ + annotation?: string | null; + /** + * Errors + * @description Any errors associated with the subworkflow. + */ + errors?: string[] | null; + /** + * Inputs + * @description The inputs of the step. + */ + inputs: Record[]; + /** + * Label + * @description The label of the step. + */ + label: string; + /** + * Order Index + * @description The order index of the step. + */ + order_index: number; + /** + * Tool ID + * @description The unique name of the tool associated with this step. + */ + tool_id?: string | null; + /** + * Tool Version + * @description The version of the tool associated with this step. + */ + tool_version?: string | null; + /** + * Type + * @description The type of workflow module. + */ + type: components["schemas"]["WorkflowModuleType"]; + }; + /** WorkflowDictPreviewSummary */ + WorkflowDictPreviewSummary: { + /** + * Name + * @description The name of the workflow. + */ + name: string; + /** + * Steps + * @description A dictionary with information about all the steps of the workflow. + */ + steps: components["schemas"]["WorkflowDictPreviewSteps"][]; + /** + * Version + * @description The version of the workflow. + */ + version: number; + }; + /** WorkflowDictRunSteps */ + WorkflowDictRunSteps: { + /** + * Annotation + * @description An annotation to provide details or to help understand the purpose and usage of this item. + */ + annotation?: string | null; + /** + * Inputs + * @description The inputs of the step. + */ + inputs: Record[]; + /** + * Messages + * @description Upgrade messages for the step. + */ + messages?: string[] | null; + /** + * Output Connections + * @description A list of dictionaries representing the output connections of the step. + */ + output_connections: Record[]; + /** + * Post Job Actions + * @description A list of dictionaries representing the post-job actions for the step. + */ + post_job_actions?: Record[] | null; + /** + * Replacement Parameters + * @description Informal replacement parameters for the step. + */ + replacement_parameters?: Record[] | null; + /** + * Step Index + * @description The order index of the step. + */ + step_index: number; + /** + * Step Label + * @description The label of the step. + */ + step_label?: string | null; + /** + * Step Name + * @description The name of the step's module. + */ + step_name: string; + /** + * Step Type + * @description The type of the step. + */ + step_type: components["schemas"]["WorkflowModuleType"]; + /** + * Step Version + * @description The version of the step's module. + */ + step_version?: string | null; + /** + * When + * @description The when expression for the step. + */ + when?: string | null; + }; + /** WorkflowDictRunSummary */ + WorkflowDictRunSummary: { + /** + * Has Upgrade Messages + * @description A boolean indicating whether the workflow has upgrade messages. + */ + has_upgrade_messages?: boolean | null; + /** + * History ID + * @description The encoded ID of the history associated with the workflow (or None if not applicable). + */ + history_id?: string | null; + /** + * ID + * @description The encoded ID of the stored workflow. + */ + id?: string | null; + /** + * Name + * @description The name of the workflow. + */ + name: string; + /** + * Step Version Changes + * @description A list of version changes for the workflow steps. + */ + step_version_changes?: Record[] | null; + /** + * Steps + * @description A dictionary with information about all the steps of the workflow. + */ + steps: components["schemas"]["WorkflowDictRunSteps"][]; + /** + * Version + * @description The version of the workflow. + */ + version: number; + /** + * Workflow Resource Parameters + * @description The resource parameters of the workflow. + */ + workflow_resource_parameters?: Record | null; + }; /** WorkflowInput */ WorkflowInput: { /** @@ -32785,7 +33358,14 @@ export interface operations { /** @description Successful Response */ 200: { content: { - "application/json": Record; + "application/json": + | components["schemas"]["WorkflowDictEditorSummary"] + | components["schemas"]["StoredWorkflowDetailed"] + | components["schemas"]["WorkflowDictRunSummary"] + | components["schemas"]["WorkflowDictPreviewSummary"] + | components["schemas"]["WorkflowDictFormat2Summary"] + | components["schemas"]["WorkflowDictExportSummary"] + | components["schemas"]["WorkflowDictFormat2WrappedYamlSummary"]; }; }; /** @description Validation Error */ @@ -33058,7 +33638,14 @@ export interface operations { /** @description Successful Response */ 200: { content: { - "application/json": Record; + "application/json": + | components["schemas"]["WorkflowDictEditorSummary"] + | components["schemas"]["StoredWorkflowDetailed"] + | components["schemas"]["WorkflowDictRunSummary"] + | components["schemas"]["WorkflowDictPreviewSummary"] + | components["schemas"]["WorkflowDictFormat2Summary"] + | components["schemas"]["WorkflowDictExportSummary"] + | components["schemas"]["WorkflowDictFormat2WrappedYamlSummary"]; }; }; /** @description Validation Error */ From 41f9c3b5aa4e7eff80d570af7b19abb33b976a16 Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Thu, 14 Mar 2024 20:33:20 +0100 Subject: [PATCH 25/89] Properly type creator in pydantic models of workflowdict operation --- lib/galaxy/schema/workflows.py | 33 +++++++++++++-------------------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/lib/galaxy/schema/workflows.py b/lib/galaxy/schema/workflows.py index 049be60247e9..412235b9a2ac 100644 --- a/lib/galaxy/schema/workflows.py +++ b/lib/galaxy/schema/workflows.py @@ -39,6 +39,15 @@ ), ] +WorkflowCreator = Annotated[ + Optional[List[Union[Person, Organization]]], + Field( + None, + title="Creator", + description=("Additional information about the creator (or multiple creators) of this workflow."), + ), +] + class GetTargetHistoryPayload(Model): # TODO - Are the descriptions correct? @@ -198,11 +207,7 @@ class StoredWorkflowDetailed(StoredWorkflowSummary): inputs: Dict[int, WorkflowInput] = Field( {}, title="Inputs", description="A dictionary containing information about all the inputs of the workflow." ) - creator: Optional[List[Union[Person, Organization]]] = Field( - None, - title="Creator", - description=("Additional information about the creator (or multiple creators) of this workflow."), - ) + creator: WorkflowCreator steps: Dict[ int, Union[ @@ -617,11 +622,7 @@ class WorkflowDictEditorSummary(WorkflowDictBaseModel): title="License", description="The license information for the workflow.", ) - creator: Optional[Dict[str, Any]] = Field( - None, - title="Creator", - description="Metadata about the creator of the workflow.", - ) + creator: WorkflowCreator source_metadata: Optional[Dict[str, Any]] = Field( None, title="Source Metadata", @@ -699,11 +700,7 @@ class WorkflowDictExportSummary(WorkflowDictBaseModel): title="Report", description="The configuration for generating a report for the workflow.", ) - creator: Optional[Dict[str, Any]] = Field( - None, - title="Creator", - description="Metadata about the creator of the workflow.", - ) + creator: WorkflowCreator license: Optional[str] = Field( None, title="License", @@ -733,11 +730,7 @@ class WorkflowDictFormat2Summary(Model): title="Label", description="The label or name of the workflow.", ) - creator: Optional[Dict[str, Any]] = Field( - None, - title="Creator", - description="Metadata about the creator of the workflow.", - ) + creator: WorkflowCreator license: Optional[str] = Field( None, title="License", From 25d39c3010301b700649a509577fd50fafaaa063 Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Thu, 14 Mar 2024 20:34:37 +0100 Subject: [PATCH 26/89] Add alias for format_version field in pydantic model of workflowdict operation --- lib/galaxy/schema/workflows.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/galaxy/schema/workflows.py b/lib/galaxy/schema/workflows.py index 412235b9a2ac..20a60f51ce2a 100644 --- a/lib/galaxy/schema/workflows.py +++ b/lib/galaxy/schema/workflows.py @@ -676,6 +676,7 @@ class WorkflowDictExportSummary(WorkflowDictBaseModel): ) format_version: Optional[str] = Field( None, + alias="format-version", title="Format Version", description="The version of the workflow format being used.", ) From 79ff4650c87928c24f66cd6266870ed005051c21 Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Thu, 14 Mar 2024 21:02:08 +0100 Subject: [PATCH 27/89] Regenerate the client schema --- lib/galaxy/schema/schema.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/galaxy/schema/schema.py b/lib/galaxy/schema/schema.py index 427777fa319d..c4f3bc9e0407 100644 --- a/lib/galaxy/schema/schema.py +++ b/lib/galaxy/schema/schema.py @@ -2612,6 +2612,7 @@ class SubworkflowStepToExport(WorkflowStepToExportBase): ) +# TODO - move to schema of workflow class WorkflowToExport(Model): a_galaxy_workflow: str = Field( # Is this meant to be a bool instead? "true", title="Galaxy Workflow", description="Whether this workflow is a Galaxy Workflow." From b15262e01b3ff6fcf9b1c9d30122ca31bcc8471b Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Thu, 14 Mar 2024 22:27:40 +0100 Subject: [PATCH 28/89] Create base model for step models of WorkflowSummary models --- lib/galaxy/schema/workflows.py | 242 +++++++++++---------------------- 1 file changed, 77 insertions(+), 165 deletions(-) diff --git a/lib/galaxy/schema/workflows.py b/lib/galaxy/schema/workflows.py index 20a60f51ce2a..c79f29daf296 100644 --- a/lib/galaxy/schema/workflows.py +++ b/lib/galaxy/schema/workflows.py @@ -267,113 +267,123 @@ class SetWorkflowMenuSummary(Model): ) -class WorkflowDictPreviewSteps(Model): - order_index: int = Field( - ..., - title="Order Index", - description="The order index of the step.", - ) +class WorkflowDictStepsBase(Model): type: WorkflowModuleType = Field( ..., title="Type", - description="The type of workflow module.", + alias="step_type", + description="The type of the module that represents a step in the workflow.", ) - annotation: WorkflowAnnotationField = None - label: str = Field( - ..., + # fields below are not in all models initially, but as they were optional in all + # models that had them I think it should be no problem to put them here + # in the base in order to avoid code duplication + when: Optional[str] = Field( + None, + title="When", + description="The when expression for the step.", + ) + label: Optional[str] = Field( + None, + alias="step_label", title="Label", description="The label of the step.", ) - tool_id: Optional[str] = Field( - None, title="Tool ID", description="The unique name of the tool associated with this step." + # TODO - could be modeled further see manager + post_job_actions: Optional[Union[Dict[str, Any], List[Dict[str, Any]]]] = Field( + None, + title="Post Job Actions", + description="A dictionary of post-job actions for the step.", ) tool_version: Optional[str] = Field( - None, title="Tool Version", description="The version of the tool associated with this step." - ) - inputs: List[Dict[str, Any]] = Field( - ..., - title="Inputs", - description="The inputs of the step.", + None, + title="Tool Version", + description="The version of the tool associated with the step.", ) - errors: Optional[List[str]] = Field( + errors: Optional[Union[List[str], str]] = Field( None, title="Errors", - description="Any errors associated with the subworkflow.", + description="Any errors associated with the step.", + ) + tool_id: Optional[str] = Field( + None, + title="Tool ID", + description="The tool ID associated with the step.", + ) + position: Optional[Any] = Field( + None, + title="Position", + description="The position of the step.", + ) + # TODO - can be modeled further see manager + outputs: Optional[List[Dict[str, Any]]] = Field( + None, + title="Outputs", + description="The outputs of the step.", + ) + tool_state: Optional[Union[Dict[str, Any], str]] = Field( + None, + title="Tool State", + description="The state of the tool associated with the step", + ) + content_id: Optional[str] = Field( + None, + title="Content ID", + description="The content ID of the step.", + ) + # TODO - could be modeled further see manager + workflow_outputs: Optional[List[Dict[str, Any]]] = Field( + None, + title="Workflow Outputs", + description="A list of workflow outputs for the step.", ) -class WorkflowDictEditorSteps(Model): - id: int = Field( +class WorkflowDictPreviewSteps(WorkflowDictStepsBase): + order_index: int = Field( ..., - title="ID", + title="Order Index", description="The order index of the step.", ) - type: WorkflowModuleType = Field( + annotation: WorkflowAnnotationField = None + label: str = Field( ..., - title="Type", - description="The type of workflow module.", - ) - label: Optional[str] = Field( - None, title="Label", description="The label of the step.", ) - content_id: Optional[str] = Field( - None, - title="Content ID", - description="The identifier for the content of the step.", + inputs: List[Dict[str, Any]] = Field( + ..., + title="Inputs", + description="The inputs of the step.", + ) + + +class WorkflowDictEditorSteps(WorkflowDictStepsBase): + id: int = Field( + ..., + title="ID", + description="The order index of the step.", ) name: Optional[str] = Field( None, title="Name", description="The name of the step.", ) - tool_state: Optional[Dict[str, Any]] = Field( - None, - title="Tool State", - description="The state of the step's tool.", - ) - errors: Optional[List[str]] = Field( - None, - title="Errors", - description="Any errors associated with the step.", - ) inputs: Optional[List[Dict[str, Any]]] = Field( None, title="Inputs", description="The inputs of the step.", ) - outputs: Optional[List[Dict[str, Any]]] = Field( - None, - title="Outputs", - description="The outputs of the step.", - ) config_form: Optional[Dict[str, Any]] = Field( None, title="Config Form", description="The configuration form for the step.", ) annotation: WorkflowAnnotationField - post_job_actions: Optional[Dict[str, Any]] = Field( - None, - title="Post Job Actions", - description="A dictionary of post-job actions for the step.", - ) uuid: Optional[str] = Field( None, title="UUID", description="The UUID of the step.", ) - when: Optional[str] = Field( - None, - title="When", - description="The when expression for the step.", - ) - workflow_outputs: Optional[List[Dict[str, Any]]] = Field( - None, - title="Workflow Outputs", - description="A list of workflow outputs for the step.", - ) tooltip: Optional[str] = Field( None, title="Tooltip", @@ -384,45 +394,20 @@ class WorkflowDictEditorSteps(Model): title="Input Connections", description="A dictionary representing the input connections for the step.", ) - position: Optional[Dict[str, Any]] = Field( - None, - title="Position", - description="The position of the step.", - ) - tool_version: Optional[str] = Field( - None, - title="Tool Version", - description="The version of the step's tool.", - ) -# TODO - This is missing some fields - see manager line 1006 -class WorkflowDictRunSteps(Model): +# TODO - This is potentially missing some fields, when step type is tool - see manager line 1006 - TODO +class WorkflowDictRunSteps(WorkflowDictStepsBase): inputs: List[Dict[str, Any]] = Field( ..., title="Inputs", description="The inputs of the step.", ) - when: Optional[str] = Field( - None, - title="When", - description="The when expression for the step.", - ) replacement_parameters: Optional[List[Dict[str, Any]]] = Field( None, title="Replacement Parameters", description="Informal replacement parameters for the step.", ) - step_type: WorkflowModuleType = Field( - ..., - title="Step Type", - description="The type of the step.", - ) - step_label: Optional[str] = Field( - None, - title="Step Label", - description="The label of the step.", - ) step_name: str = Field( ..., title="Step Name", @@ -449,75 +434,25 @@ class WorkflowDictRunSteps(Model): title="Messages", description="Upgrade messages for the step.", ) - # TODO - can further specify post_job_actions - look at code in manager - post_job_actions: Optional[List[Dict[str, Any]]] = Field( - None, - title="Post Job Actions", - description="A list of dictionaries representing the post-job actions for the step.", - ) -class WorkflowDictExportSteps(Model): +class WorkflowDictExportSteps(WorkflowDictStepsBase): id: int = Field( ..., title="ID", description="The order index of the step.", ) - type: WorkflowModuleType = Field( - ..., - title="Type", - description="The type of the step.", - ) - content_id: Optional[str] = Field( - None, - title="Content ID", - description="The content ID of the step.", - ) - tool_id: Optional[str] = Field( - None, - title="Tool ID", - description="The tool ID associated with the step (applicable only if the step type is 'tool').", - ) - tool_version: Optional[str] = Field( - None, - title="Tool Version", - description="The version of the tool associated with the step.", - ) name: str = Field( ..., title="Name", description="The name of the step.", ) - tool_state: Optional[str] = Field( - None, - title="Tool State", - description="The serialized state of the tool associated with the step.", - ) - errors: Optional[str] = Field( - None, - title="Errors", - description="Any errors associated with the step.", - ) uuid: str = Field( ..., title="UUID", description="The UUID (Universally Unique Identifier) of the step.", ) - label: Optional[str] = Field( - None, - title="Label", - description="The label of the step (optional).", - ) - annotation: WorkflowAnnotationField = Field( - None, - title="Annotation", - description="The annotation associated with the step.", - ) - when: Optional[str] = Field( - None, - title="When", - description="The when expression of the step.", - ) + annotation: WorkflowAnnotationField = None # TODO - can be modeled see manager line 1483 or below tool_shed_repository: Optional[Dict[str, Any]] = Field( None, @@ -533,12 +468,6 @@ class WorkflowDictExportSteps(Model): title="Tool Representation", description="The representation of the tool associated with the step.", ) - # TODO - can be modeled see manager line 1500 - post_job_actions: Optional[Dict[str, Any]] = Field( - None, - title="Post Job Actions", - description="A dictionary containing post-job actions associated with the step.", - ) # TODO - can also be WorkflowDictExportSummary see manager line 1512 subworkflow: Optional[Dict[str, Any]] = Field( None, @@ -551,18 +480,6 @@ class WorkflowDictExportSteps(Model): title="Inputs", description="The inputs of the step.", ) - # TODO - can be modeled see manager line 1535 and 1543 - workflow_outputs: Optional[List[Dict[str, Any]]] = Field( - None, - title="Workflow Outputs", - description="A list of workflow outputs for the step.", - ) - # TODO - can be modeled see manager line 1546 - outputs: Optional[List[Dict[str, Any]]] = Field( - None, - title="Outputs", - description="The outputs of the step.", - ) # TODO - can be modeled see manager line 1551 in_parameter: Optional[Dict[str, Any]] = Field( None, title="In", description="The input connections of the step.", alias="in" @@ -572,11 +489,6 @@ class WorkflowDictExportSteps(Model): title="Input Connections", description="The input connections of the step.", ) - position: Optional[Any] = Field( - None, - title="Position", - description="The position of the step.", - ) class WorkflowDictBaseModel(Model): From c22d28527c7ad10d8c4d6d8c7c75cd96e7b82acf Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Thu, 14 Mar 2024 22:28:46 +0100 Subject: [PATCH 29/89] Regenerate the client schema --- client/src/api/schema/schema.ts | 192 +++++++++++++++++++++++--------- 1 file changed, 139 insertions(+), 53 deletions(-) diff --git a/client/src/api/schema/schema.ts b/client/src/api/schema/schema.ts index 27f62c7dea99..ab324b451aab 100644 --- a/client/src/api/schema/schema.ts +++ b/client/src/api/schema/schema.ts @@ -16902,14 +16902,14 @@ export interface components { config_form?: Record | null; /** * Content ID - * @description The identifier for the content of the step. + * @description The content ID of the step. */ content_id?: string | null; /** * Errors * @description Any errors associated with the step. */ - errors?: string[] | null; + errors?: string[] | string | null; /** * ID * @description The order index of the step. @@ -16925,11 +16925,6 @@ export interface components { * @description The inputs of the step. */ inputs?: Record[] | null; - /** - * Label - * @description The label of the step. - */ - label?: string | null; /** * Name * @description The name of the step. @@ -16949,15 +16944,30 @@ export interface components { * Post Job Actions * @description A dictionary of post-job actions for the step. */ - post_job_actions?: Record | null; + post_job_actions?: Record | Record[] | null; + /** + * Label + * @description The label of the step. + */ + step_label?: string | null; + /** + * Type + * @description The type of the module that represents a step in the workflow. + */ + step_type: components["schemas"]["WorkflowModuleType"]; + /** + * Tool ID + * @description The tool ID associated with the step. + */ + tool_id?: string | null; /** * Tool State - * @description The state of the step's tool. + * @description The state of the tool associated with the step */ - tool_state?: Record | null; + tool_state?: Record | string | null; /** * Tool Version - * @description The version of the step's tool. + * @description The version of the tool associated with the step. */ tool_version?: string | null; /** @@ -16965,11 +16975,6 @@ export interface components { * @description The tooltip for the step. */ tooltip?: string | null; - /** - * Type - * @description The type of workflow module. - */ - type: components["schemas"]["WorkflowModuleType"]; /** * UUID * @description The UUID of the step. @@ -17000,9 +17005,11 @@ export interface components { comments: Record[]; /** * Creator - * @description Metadata about the creator of the workflow. + * @description Additional information about the creator (or multiple creators) of this workflow. */ - creator?: Record | null; + creator?: + | (components["schemas"]["Person"] | components["schemas"]["galaxy__schema__schema__Organization"])[] + | null; /** * License * @description The license information for the workflow. @@ -17047,7 +17054,7 @@ export interface components { WorkflowDictExportSteps: { /** * Annotation - * @description The annotation associated with the step. + * @description An annotation to provide details or to help understand the purpose and usage of this item. */ annotation?: string | null; /** @@ -17059,7 +17066,7 @@ export interface components { * Errors * @description Any errors associated with the step. */ - errors?: string | null; + errors?: string[] | string | null; /** * ID * @description The order index of the step. @@ -17082,11 +17089,6 @@ export interface components { * @description The inputs of the step. */ inputs?: Record[] | null; - /** - * Label - * @description The label of the step (optional). - */ - label?: string | null; /** * Name * @description The name of the step. @@ -17104,9 +17106,19 @@ export interface components { position?: Record | null; /** * Post Job Actions - * @description A dictionary containing post-job actions associated with the step. + * @description A dictionary of post-job actions for the step. */ - post_job_actions?: Record | null; + post_job_actions?: Record | Record[] | null; + /** + * Label + * @description The label of the step. + */ + step_label?: string | null; + /** + * Type + * @description The type of the module that represents a step in the workflow. + */ + step_type: components["schemas"]["WorkflowModuleType"]; /** * Sub Workflow * @description The sub-workflow associated with the step. @@ -17114,7 +17126,7 @@ export interface components { subworkflow?: Record | null; /** * Tool ID - * @description The tool ID associated with the step (applicable only if the step type is 'tool'). + * @description The tool ID associated with the step. */ tool_id?: string | null; /** @@ -17129,19 +17141,14 @@ export interface components { tool_shed_repository?: Record | null; /** * Tool State - * @description The serialized state of the tool associated with the step. + * @description The state of the tool associated with the step */ - tool_state?: string | null; + tool_state?: Record | string | null; /** * Tool Version * @description The version of the tool associated with the step. */ tool_version?: string | null; - /** - * Type - * @description The type of the step. - */ - type: components["schemas"]["WorkflowModuleType"]; /** * UUID * @description The UUID (Universally Unique Identifier) of the step. @@ -17149,7 +17156,7 @@ export interface components { uuid: string; /** * When - * @description The when expression of the step. + * @description The when expression for the step. */ when?: string | null; /** @@ -17177,14 +17184,16 @@ export interface components { comments?: Record[] | null; /** * Creator - * @description Metadata about the creator of the workflow. + * @description Additional information about the creator (or multiple creators) of this workflow. */ - creator?: Record | null; + creator?: + | (components["schemas"]["Person"] | components["schemas"]["galaxy__schema__schema__Organization"])[] + | null; /** * Format Version * @description The version of the workflow format being used. */ - format_version?: string | null; + "format-version"?: string | null; /** * License * @description The license information for the workflow. @@ -17237,9 +17246,11 @@ export interface components { class: string; /** * Creator - * @description Metadata about the creator of the workflow. + * @description Additional information about the creator (or multiple creators) of this workflow. */ - creator?: Record | null; + creator?: + | (components["schemas"]["Person"] | components["schemas"]["galaxy__schema__schema__Organization"])[] + | null; /** * Inputs * @description A dictionary representing the inputs of the workflow. @@ -17301,11 +17312,16 @@ export interface components { * @description An annotation to provide details or to help understand the purpose and usage of this item. */ annotation?: string | null; + /** + * Content ID + * @description The content ID of the step. + */ + content_id?: string | null; /** * Errors - * @description Any errors associated with the subworkflow. + * @description Any errors associated with the step. */ - errors?: string[] | null; + errors?: string[] | string | null; /** * Inputs * @description The inputs of the step. @@ -17321,21 +17337,51 @@ export interface components { * @description The order index of the step. */ order_index: number; + /** + * Outputs + * @description The outputs of the step. + */ + outputs?: Record[] | null; + /** + * Position + * @description The position of the step. + */ + position?: Record | null; + /** + * Post Job Actions + * @description A dictionary of post-job actions for the step. + */ + post_job_actions?: Record | Record[] | null; + /** + * Type + * @description The type of the module that represents a step in the workflow. + */ + step_type: components["schemas"]["WorkflowModuleType"]; /** * Tool ID - * @description The unique name of the tool associated with this step. + * @description The tool ID associated with the step. */ tool_id?: string | null; + /** + * Tool State + * @description The state of the tool associated with the step + */ + tool_state?: Record | string | null; /** * Tool Version - * @description The version of the tool associated with this step. + * @description The version of the tool associated with the step. */ tool_version?: string | null; /** - * Type - * @description The type of workflow module. + * When + * @description The when expression for the step. + */ + when?: string | null; + /** + * Workflow Outputs + * @description A list of workflow outputs for the step. */ - type: components["schemas"]["WorkflowModuleType"]; + workflow_outputs?: Record[] | null; }; /** WorkflowDictPreviewSummary */ WorkflowDictPreviewSummary: { @@ -17362,6 +17408,16 @@ export interface components { * @description An annotation to provide details or to help understand the purpose and usage of this item. */ annotation?: string | null; + /** + * Content ID + * @description The content ID of the step. + */ + content_id?: string | null; + /** + * Errors + * @description Any errors associated with the step. + */ + errors?: string[] | string | null; /** * Inputs * @description The inputs of the step. @@ -17377,11 +17433,21 @@ export interface components { * @description A list of dictionaries representing the output connections of the step. */ output_connections: Record[]; + /** + * Outputs + * @description The outputs of the step. + */ + outputs?: Record[] | null; + /** + * Position + * @description The position of the step. + */ + position?: Record | null; /** * Post Job Actions - * @description A list of dictionaries representing the post-job actions for the step. + * @description A dictionary of post-job actions for the step. */ - post_job_actions?: Record[] | null; + post_job_actions?: Record | Record[] | null; /** * Replacement Parameters * @description Informal replacement parameters for the step. @@ -17393,7 +17459,7 @@ export interface components { */ step_index: number; /** - * Step Label + * Label * @description The label of the step. */ step_label?: string | null; @@ -17403,8 +17469,8 @@ export interface components { */ step_name: string; /** - * Step Type - * @description The type of the step. + * Type + * @description The type of the module that represents a step in the workflow. */ step_type: components["schemas"]["WorkflowModuleType"]; /** @@ -17412,11 +17478,31 @@ export interface components { * @description The version of the step's module. */ step_version?: string | null; + /** + * Tool ID + * @description The tool ID associated with the step. + */ + tool_id?: string | null; + /** + * Tool State + * @description The state of the tool associated with the step + */ + tool_state?: Record | string | null; + /** + * Tool Version + * @description The version of the tool associated with the step. + */ + tool_version?: string | null; /** * When * @description The when expression for the step. */ when?: string | null; + /** + * Workflow Outputs + * @description A list of workflow outputs for the step. + */ + workflow_outputs?: Record[] | null; }; /** WorkflowDictRunSummary */ WorkflowDictRunSummary: { From 1ccf7153c661e4d57b17a14930a0d9396c7feb80 Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Fri, 15 Mar 2024 21:04:23 +0100 Subject: [PATCH 30/89] Create base model for step models of WorkflowSummary models --- lib/galaxy/schema/workflows.py | 125 +++++++++++++++++---------------- 1 file changed, 66 insertions(+), 59 deletions(-) diff --git a/lib/galaxy/schema/workflows.py b/lib/galaxy/schema/workflows.py index c79f29daf296..4e00897f1fa1 100644 --- a/lib/galaxy/schema/workflows.py +++ b/lib/galaxy/schema/workflows.py @@ -28,7 +28,6 @@ SubworkflowStep, ToolStep, WorkflowInput, - WorkflowModuleType, ) WorkflowAnnotationField = Annotated[ @@ -268,26 +267,11 @@ class SetWorkflowMenuSummary(Model): class WorkflowDictStepsBase(Model): - type: WorkflowModuleType = Field( - ..., - title="Type", - alias="step_type", - description="The type of the module that represents a step in the workflow.", - ) - # fields below are not in all models initially, but as they were optional in all - # models that had them I think it should be no problem to put them here - # in the base in order to avoid code duplication when: Optional[str] = Field( None, title="When", description="The when expression for the step.", ) - label: Optional[str] = Field( - None, - alias="step_label", - title="Label", - description="The label of the step.", - ) # TODO - could be modeled further see manager post_job_actions: Optional[Union[Dict[str, Any], List[Dict[str, Any]]]] = Field( None, @@ -338,7 +322,70 @@ class WorkflowDictStepsBase(Model): ) -class WorkflowDictPreviewSteps(WorkflowDictStepsBase): +class WorkflowDictStepsExtendedBase(WorkflowDictStepsBase): + type: str = Field( + ..., + title="Type", + description="The type of the module that represents a step in the workflow.", + ) + label: Optional[str] = Field( + None, + title="Label", + description="The label of the step.", + ) + + +# TODO - This is potentially missing some fields, when step type is tool - see manager line 1006 - TODO +class WorkflowDictRunSteps(WorkflowDictStepsBase): + inputs: List[Dict[str, Any]] = Field( + ..., + title="Inputs", + description="The inputs of the step.", + ) + replacement_parameters: Optional[List[Dict[str, Any]]] = Field( + None, + title="Replacement Parameters", + description="Informal replacement parameters for the step.", + ) + step_name: str = Field( + ..., + title="Step Name", + description="The name of the step's module.", + ) + step_version: Optional[str] = Field( + None, + title="Step Version", + description="The version of the step's module.", + ) + step_index: int = Field( + ..., + title="Step Index", + description="The order index of the step.", + ) + output_connections: List[Dict[str, Any]] = Field( + ..., + title="Output Connections", + description="A list of dictionaries representing the output connections of the step.", + ) + annotation: WorkflowAnnotationField = None + messages: Optional[List[str]] = Field( + None, + title="Messages", + description="Upgrade messages for the step.", + ) + step_type: str = Field( + ..., + title="Step Type", + description="The type of the step.", + ) + step_label: Optional[str] = Field( + None, + title="Step Label", + description="The label of the step.", + ) + + +class WorkflowDictPreviewSteps(WorkflowDictStepsExtendedBase): order_index: int = Field( ..., title="Order Index", @@ -357,7 +404,7 @@ class WorkflowDictPreviewSteps(WorkflowDictStepsBase): ) -class WorkflowDictEditorSteps(WorkflowDictStepsBase): +class WorkflowDictEditorSteps(WorkflowDictStepsExtendedBase): id: int = Field( ..., title="ID", @@ -396,47 +443,7 @@ class WorkflowDictEditorSteps(WorkflowDictStepsBase): ) -# TODO - This is potentially missing some fields, when step type is tool - see manager line 1006 - TODO -class WorkflowDictRunSteps(WorkflowDictStepsBase): - inputs: List[Dict[str, Any]] = Field( - ..., - title="Inputs", - description="The inputs of the step.", - ) - replacement_parameters: Optional[List[Dict[str, Any]]] = Field( - None, - title="Replacement Parameters", - description="Informal replacement parameters for the step.", - ) - step_name: str = Field( - ..., - title="Step Name", - description="The name of the step's module.", - ) - step_version: Optional[str] = Field( - None, - title="Step Version", - description="The version of the step's module.", - ) - step_index: int = Field( - ..., - title="Step Index", - description="The order index of the step.", - ) - output_connections: List[Dict[str, Any]] = Field( - ..., - title="Output Connections", - description="A list of dictionaries representing the output connections of the step.", - ) - annotation: WorkflowAnnotationField = None - messages: Optional[List[str]] = Field( - None, - title="Messages", - description="Upgrade messages for the step.", - ) - - -class WorkflowDictExportSteps(WorkflowDictStepsBase): +class WorkflowDictExportSteps(WorkflowDictStepsExtendedBase): id: int = Field( ..., title="ID", From 71e91881c79ebfc67bdb28ae10fb096867f3f5aa Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Fri, 15 Mar 2024 21:04:40 +0100 Subject: [PATCH 31/89] Regenerate the client schema --- client/src/api/schema/schema.ts | 58 ++++++++++++++++----------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/client/src/api/schema/schema.ts b/client/src/api/schema/schema.ts index ab324b451aab..946e1b67bff1 100644 --- a/client/src/api/schema/schema.ts +++ b/client/src/api/schema/schema.ts @@ -16925,6 +16925,11 @@ export interface components { * @description The inputs of the step. */ inputs?: Record[] | null; + /** + * Label + * @description The label of the step. + */ + label?: string | null; /** * Name * @description The name of the step. @@ -16945,16 +16950,6 @@ export interface components { * @description A dictionary of post-job actions for the step. */ post_job_actions?: Record | Record[] | null; - /** - * Label - * @description The label of the step. - */ - step_label?: string | null; - /** - * Type - * @description The type of the module that represents a step in the workflow. - */ - step_type: components["schemas"]["WorkflowModuleType"]; /** * Tool ID * @description The tool ID associated with the step. @@ -16975,6 +16970,11 @@ export interface components { * @description The tooltip for the step. */ tooltip?: string | null; + /** + * Type + * @description The type of the module that represents a step in the workflow. + */ + type: string; /** * UUID * @description The UUID of the step. @@ -17089,6 +17089,11 @@ export interface components { * @description The inputs of the step. */ inputs?: Record[] | null; + /** + * Label + * @description The label of the step. + */ + label?: string | null; /** * Name * @description The name of the step. @@ -17109,16 +17114,6 @@ export interface components { * @description A dictionary of post-job actions for the step. */ post_job_actions?: Record | Record[] | null; - /** - * Label - * @description The label of the step. - */ - step_label?: string | null; - /** - * Type - * @description The type of the module that represents a step in the workflow. - */ - step_type: components["schemas"]["WorkflowModuleType"]; /** * Sub Workflow * @description The sub-workflow associated with the step. @@ -17149,6 +17144,11 @@ export interface components { * @description The version of the tool associated with the step. */ tool_version?: string | null; + /** + * Type + * @description The type of the module that represents a step in the workflow. + */ + type: string; /** * UUID * @description The UUID (Universally Unique Identifier) of the step. @@ -17352,11 +17352,6 @@ export interface components { * @description A dictionary of post-job actions for the step. */ post_job_actions?: Record | Record[] | null; - /** - * Type - * @description The type of the module that represents a step in the workflow. - */ - step_type: components["schemas"]["WorkflowModuleType"]; /** * Tool ID * @description The tool ID associated with the step. @@ -17372,6 +17367,11 @@ export interface components { * @description The version of the tool associated with the step. */ tool_version?: string | null; + /** + * Type + * @description The type of the module that represents a step in the workflow. + */ + type: string; /** * When * @description The when expression for the step. @@ -17459,7 +17459,7 @@ export interface components { */ step_index: number; /** - * Label + * Step Label * @description The label of the step. */ step_label?: string | null; @@ -17469,10 +17469,10 @@ export interface components { */ step_name: string; /** - * Type - * @description The type of the module that represents a step in the workflow. + * Step Type + * @description The type of the step. */ - step_type: components["schemas"]["WorkflowModuleType"]; + step_type: string; /** * Step Version * @description The version of the step's module. From 8051440bdcdf29a93736d3ae80733ba1a30af25e Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Mon, 18 Mar 2024 16:54:54 +0100 Subject: [PATCH 32/89] Add annotation field to pydantic model of workflow_dict operation --- lib/galaxy/schema/workflows.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/galaxy/schema/workflows.py b/lib/galaxy/schema/workflows.py index 4e00897f1fa1..5aa62bc090e7 100644 --- a/lib/galaxy/schema/workflows.py +++ b/lib/galaxy/schema/workflows.py @@ -692,6 +692,7 @@ class WorkflowDictFormat2Summary(Model): title="Steps", description="A dictionary representing the steps of the workflow.", ) + doc: WorkflowAnnotationField = None class WorkflowDictFormat2WrappedYamlSummary(Model): From 68048d96d33d4b98454b0c53b312e6aa67a5e6c2 Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Mon, 18 Mar 2024 16:58:13 +0100 Subject: [PATCH 33/89] Regenerate the client schema --- client/src/api/schema/schema.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/client/src/api/schema/schema.ts b/client/src/api/schema/schema.ts index 946e1b67bff1..be4ae0bdc6f7 100644 --- a/client/src/api/schema/schema.ts +++ b/client/src/api/schema/schema.ts @@ -17251,6 +17251,11 @@ export interface components { creator?: | (components["schemas"]["Person"] | components["schemas"]["galaxy__schema__schema__Organization"])[] | null; + /** + * Annotation + * @description An annotation to provide details or to help understand the purpose and usage of this item. + */ + doc?: string | null; /** * Inputs * @description A dictionary representing the inputs of the workflow. From 3b4f5ba80f7126dec1af759f5da5e7ecbb4bd3fc Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Wed, 20 Mar 2024 23:13:18 +0100 Subject: [PATCH 34/89] Fix typing of error field in base of step models of workflowdictsummary models --- lib/galaxy/schema/workflows.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/galaxy/schema/workflows.py b/lib/galaxy/schema/workflows.py index 5aa62bc090e7..77904b9f6e0d 100644 --- a/lib/galaxy/schema/workflows.py +++ b/lib/galaxy/schema/workflows.py @@ -283,7 +283,7 @@ class WorkflowDictStepsBase(Model): title="Tool Version", description="The version of the tool associated with the step.", ) - errors: Optional[Union[List[str], str]] = Field( + errors: Optional[Union[List[str], str, Dict[str, Any]]] = Field( None, title="Errors", description="Any errors associated with the step.", From b88dd00ac3379eb48dbe754dc52dc21adcadf015 Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Wed, 20 Mar 2024 23:32:10 +0100 Subject: [PATCH 35/89] Fix typing in WorkflowDictFormat2WrappedYamlSummary model --- lib/galaxy/schema/workflows.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/galaxy/schema/workflows.py b/lib/galaxy/schema/workflows.py index 77904b9f6e0d..383166df5845 100644 --- a/lib/galaxy/schema/workflows.py +++ b/lib/galaxy/schema/workflows.py @@ -696,7 +696,7 @@ class WorkflowDictFormat2Summary(Model): class WorkflowDictFormat2WrappedYamlSummary(Model): - yaml_content: str = Field( + yaml_content: Any = Field( ..., title="YAML Content", description="The content of the workflow in YAML format.", From 56ed6dd24ff7c8b73ca599f36bee9feecb95d207 Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Thu, 21 Mar 2024 21:21:10 +0100 Subject: [PATCH 36/89] Add test for set_workflow_menu operation from WorfklowAPI --- lib/galaxy_test/api/test_workflows.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/galaxy_test/api/test_workflows.py b/lib/galaxy_test/api/test_workflows.py index 0b3b38de88fd..0651973b5553 100644 --- a/lib/galaxy_test/api/test_workflows.py +++ b/lib/galaxy_test/api/test_workflows.py @@ -870,6 +870,15 @@ def test_update_tags(self): update_response = self._update_workflow(workflow_id, update_payload).json() assert update_response["tags"] == [] + def test_set_workflow_menu(self): + original_name = "test update name" + workflow_object = self.workflow_populator.load_workflow(name=original_name) + upload_response = self.__test_upload(workflow=workflow_object, name=original_name) + workflow = upload_response.json() + workflow_id = workflow["id"] + response = self._put(f"/api/workflows/menu", {"workflow_ids": workflow_id}, json=True) + self._assert_status_code_is(response, 200) + def test_update_name(self): original_name = "test update name" workflow_object = self.workflow_populator.load_workflow(name=original_name) From 01f9265735010ae652f97de078e1bd821395b6cc Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Thu, 21 Mar 2024 22:22:25 +0100 Subject: [PATCH 37/89] Refine descriptions in pydantic models for workflow_dict operation --- lib/galaxy/schema/workflows.py | 72 +++++++++++++++++----------------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/lib/galaxy/schema/workflows.py b/lib/galaxy/schema/workflows.py index 383166df5845..74381ba0bbe6 100644 --- a/lib/galaxy/schema/workflows.py +++ b/lib/galaxy/schema/workflows.py @@ -276,7 +276,7 @@ class WorkflowDictStepsBase(Model): post_job_actions: Optional[Union[Dict[str, Any], List[Dict[str, Any]]]] = Field( None, title="Post Job Actions", - description="A dictionary of post-job actions for the step.", + description="Set of actions that will be run when the job finishes.", ) tool_version: Optional[str] = Field( None, @@ -286,17 +286,17 @@ class WorkflowDictStepsBase(Model): errors: Optional[Union[List[str], str, Dict[str, Any]]] = Field( None, title="Errors", - description="Any errors associated with the step.", + description="An message indicating possible errors in the step.", ) tool_id: Optional[str] = Field( None, title="Tool ID", - description="The tool ID associated with the step.", + description="The unique name of the tool associated with this step.", ) position: Optional[Any] = Field( None, title="Position", - description="The position of the step.", + description="Layout position of this step in the graph", ) # TODO - can be modeled further see manager outputs: Optional[List[Dict[str, Any]]] = Field( @@ -318,7 +318,7 @@ class WorkflowDictStepsBase(Model): workflow_outputs: Optional[List[Dict[str, Any]]] = Field( None, title="Workflow Outputs", - description="A list of workflow outputs for the step.", + description="Workflow outputs associated with this step.", ) @@ -347,11 +347,7 @@ class WorkflowDictRunSteps(WorkflowDictStepsBase): title="Replacement Parameters", description="Informal replacement parameters for the step.", ) - step_name: str = Field( - ..., - title="Step Name", - description="The name of the step's module.", - ) + step_name: str = Field(..., title="Step Name", description="The descriptive name of the module or step.") step_version: Optional[str] = Field( None, title="Step Version", @@ -365,7 +361,7 @@ class WorkflowDictRunSteps(WorkflowDictStepsBase): output_connections: List[Dict[str, Any]] = Field( ..., title="Output Connections", - description="A list of dictionaries representing the output connections of the step.", + description="The output connections of the step.", ) annotation: WorkflowAnnotationField = None messages: Optional[List[str]] = Field( @@ -408,12 +404,12 @@ class WorkflowDictEditorSteps(WorkflowDictStepsExtendedBase): id: int = Field( ..., title="ID", - description="The order index of the step.", + description="The identifier of the step. It matches the index order of the step inside the workflow.", ) name: Optional[str] = Field( None, title="Name", - description="The name of the step.", + description="The descriptive name of the module or step.", ) inputs: Optional[List[Dict[str, Any]]] = Field( None, @@ -429,7 +425,8 @@ class WorkflowDictEditorSteps(WorkflowDictStepsExtendedBase): uuid: Optional[str] = Field( None, title="UUID", - description="The UUID of the step.", + description="Universal unique identifier of the workflow.", + # description="The UUID (Universally Unique Identifier) of the step.", ) tooltip: Optional[str] = Field( None, @@ -439,7 +436,7 @@ class WorkflowDictEditorSteps(WorkflowDictStepsExtendedBase): input_connections: Optional[Dict[str, Any]] = Field( None, title="Input Connections", - description="A dictionary representing the input connections for the step.", + description="The input connections for the step.", ) @@ -447,17 +444,18 @@ class WorkflowDictExportSteps(WorkflowDictStepsExtendedBase): id: int = Field( ..., title="ID", - description="The order index of the step.", + description="The identifier of the step. It matches the index order of the step inside the workflow.", ) name: str = Field( ..., title="Name", - description="The name of the step.", + description="The descriptive name of the module or step.", ) uuid: str = Field( ..., title="UUID", - description="The UUID (Universally Unique Identifier) of the step.", + description="Universal unique identifier of the workflow.", + # description="The UUID (Universally Unique Identifier) of the step.", ) annotation: WorkflowAnnotationField = None # TODO - can be modeled see manager line 1483 or below @@ -479,7 +477,7 @@ class WorkflowDictExportSteps(WorkflowDictStepsExtendedBase): subworkflow: Optional[Dict[str, Any]] = Field( None, title="Sub Workflow", - description="The sub-workflow associated with the step.", + description="Full information about the subworkflow associated with this step.", ) # TODO - can be modeled see manager line 1516 -1532 inputs: Optional[List[Dict[str, Any]]] = Field( @@ -507,7 +505,7 @@ class WorkflowDictBaseModel(Model): version: int = Field( ..., title="Version", - description="The version of the workflow.", + description="The version of the workflow represented by an incremental number.", ) @@ -515,7 +513,7 @@ class WorkflowDictPreviewSummary(WorkflowDictBaseModel): steps: List[WorkflowDictPreviewSteps] = Field( ..., title="Steps", - description="A dictionary with information about all the steps of the workflow.", + description="Information about all the steps of the workflow.", ) @@ -539,7 +537,7 @@ class WorkflowDictEditorSummary(WorkflowDictBaseModel): license: Optional[str] = Field( None, title="License", - description="The license information for the workflow.", + description="SPDX Identifier of the license associated with this workflow.", ) creator: WorkflowCreator source_metadata: Optional[Dict[str, Any]] = Field( @@ -550,7 +548,7 @@ class WorkflowDictEditorSummary(WorkflowDictBaseModel): steps: Dict[int, WorkflowDictEditorSteps] = Field( ..., title="Steps", - description="A dictionary with information about all the steps of the workflow.", + description="Information about all the steps of the workflow.", ) @@ -558,22 +556,24 @@ class WorkflowDictRunSummary(WorkflowDictBaseModel): id: Optional[str] = Field( None, title="ID", - description="The encoded ID of the stored workflow.", + # description="The encoded ID of the stored workflow.", + description="TODO", ) history_id: Optional[str] = Field( None, title="History ID", - description="The encoded ID of the history associated with the workflow (or None if not applicable).", + # description="The encoded ID of the history associated with the workflow (or None if not applicable).", + description="TODO", ) step_version_changes: Optional[List[Dict[str, Any]]] = Field( None, title="Step Version Changes", - description="A list of version changes for the workflow steps.", + description="Version changes for the workflow steps.", ) has_upgrade_messages: Optional[bool] = Field( None, title="Has Upgrade Messages", - description="A boolean indicating whether the workflow has upgrade messages.", + description="Whether the workflow has upgrade messages.", ) workflow_resource_parameters: Optional[Dict[str, Any]] = Field( None, @@ -583,7 +583,7 @@ class WorkflowDictRunSummary(WorkflowDictBaseModel): steps: List[WorkflowDictRunSteps] = Field( ..., title="Steps", - description="A dictionary with information about all the steps of the workflow.", + description="Information about all the steps of the workflow.", ) @@ -591,7 +591,7 @@ class WorkflowDictExportSummary(WorkflowDictBaseModel): a_galaxy_workflow: Optional[str] = Field( None, title="A Galaxy Workflow", - description="Is a Galaxy workflow.", + description="Whether this workflow is a Galaxy Workflow.", ) format_version: Optional[str] = Field( None, @@ -613,7 +613,7 @@ class WorkflowDictExportSummary(WorkflowDictBaseModel): comments: Optional[List[Dict[str, Any]]] = Field( None, title="Comments", - description="A list of dictionaries representing comments associated with the workflow.", + description="Comments associated with the workflow.", ) report: Optional[Dict[str, Any]] = Field( None, @@ -624,7 +624,7 @@ class WorkflowDictExportSummary(WorkflowDictBaseModel): license: Optional[str] = Field( None, title="License", - description="The license information for the workflow.", + description="SPDX Identifier of the license associated with this workflow.", ) source_metadata: Optional[Dict[str, Any]] = Field( None, @@ -634,7 +634,7 @@ class WorkflowDictExportSummary(WorkflowDictBaseModel): steps: Dict[int, WorkflowDictExportSteps] = Field( ..., title="Steps", - description="A dictionary with information about all the steps of the workflow.", + description="Information about all the steps of the workflow.", ) @@ -654,7 +654,7 @@ class WorkflowDictFormat2Summary(Model): license: Optional[str] = Field( None, title="License", - description="The license information for the workflow.", + description="SPDX Identifier of the license associated with this workflow.", ) release: Optional[str] = Field( None, @@ -679,18 +679,18 @@ class WorkflowDictFormat2Summary(Model): inputs: Optional[Dict[str, Any]] = Field( None, title="Inputs", - description="A dictionary representing the inputs of the workflow.", + description="The inputs of the workflow.", ) outputs: Optional[Dict[str, Any]] = Field( None, title="Outputs", - description="A dictionary representing the outputs of the workflow.", + description="The outputs of the workflow.", ) # TODO - step into line 888 in manager steps: Dict[str, Any] = Field( ..., title="Steps", - description="A dictionary representing the steps of the workflow.", + description="Information about all the steps of the workflow.", ) doc: WorkflowAnnotationField = None From b2f68a1c5929dce9d74da82f9e1a2091875209d0 Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Thu, 21 Mar 2024 22:31:52 +0100 Subject: [PATCH 38/89] Move old and unused WorkflowToExport model to workflow schema file --- lib/galaxy/schema/schema.py | 116 -------------------------------- lib/galaxy/schema/workflows.py | 117 +++++++++++++++++++++++++++++++++ 2 files changed, 117 insertions(+), 116 deletions(-) diff --git a/lib/galaxy/schema/schema.py b/lib/galaxy/schema/schema.py index c4f3bc9e0407..07b1ddcb7249 100644 --- a/lib/galaxy/schema/schema.py +++ b/lib/galaxy/schema/schema.py @@ -23,7 +23,6 @@ BeforeValidator, ConfigDict, Field, - Json, model_validator, RootModel, UUID4, @@ -2491,71 +2490,6 @@ class WorkflowStepLayoutPosition(Model): InvocationsStateCounts = RootModel[Dict[str, int]] -class WorkflowStepToExportBase(Model): - id: int = Field( - ..., - title="ID", - description="The identifier of the step. It matches the index order of the step inside the workflow.", - ) - type: str = Field(..., title="Type", description="The type of workflow module.") - name: str = Field(..., title="Name", description="The descriptive name of the module or step.") - annotation: Optional[str] = AnnotationField - tool_id: Optional[str] = Field( # Duplicate of `content_id` or viceversa? - None, title="Tool ID", description="The unique name of the tool associated with this step." - ) - uuid: UUID4 = Field( - ..., - title="UUID", - description="Universal unique identifier of the workflow.", - ) - label: Optional[str] = Field( - None, - title="Label", - ) - inputs: List[Input] = Field( - ..., - title="Inputs", - description="TODO", - ) - outputs: List[Output] = Field( - ..., - title="Outputs", - description="TODO", - ) - input_connections: Dict[str, InputConnection] = Field( - {}, - title="Input Connections", - description="TODO", - ) - position: WorkflowStepLayoutPosition = Field( - ..., - title="Position", - description="Layout position of this step in the graph", - ) - workflow_outputs: List[WorkflowOutput] = Field( - [], title="Workflow Outputs", description="Workflow outputs associated with this step." - ) - - -class WorkflowStepToExport(WorkflowStepToExportBase): - content_id: Optional[str] = Field( # Duplicate of `tool_id` or viceversa? - None, title="Content ID", description="TODO" - ) - tool_version: Optional[str] = Field( - None, title="Tool Version", description="The version of the tool associated with this step." - ) - tool_state: Json = Field( - ..., - title="Tool State", - description="JSON string containing the serialized representation of the persistable state of the step.", - ) - errors: Optional[str] = Field( - None, - title="Errors", - description="An message indicating possible errors in the step.", - ) - - class ToolShedRepositorySummary(Model): name: str = Field( ..., @@ -2597,56 +2531,6 @@ class PostJobAction(Model): ) -class WorkflowToolStepToExport(WorkflowStepToExportBase): - tool_shed_repository: ToolShedRepositorySummary = Field( - ..., title="Tool Shed Repository", description="Information about the origin repository of this tool." - ) - post_job_actions: Dict[str, PostJobAction] = Field( - ..., title="Post-job Actions", description="Set of actions that will be run when the job finish." - ) - - -class SubworkflowStepToExport(WorkflowStepToExportBase): - subworkflow: "WorkflowToExport" = Field( - ..., title="Subworkflow", description="Full information about the subworkflow associated with this step." - ) - - -# TODO - move to schema of workflow -class WorkflowToExport(Model): - a_galaxy_workflow: str = Field( # Is this meant to be a bool instead? - "true", title="Galaxy Workflow", description="Whether this workflow is a Galaxy Workflow." - ) - format_version: str = Field( - "0.1", - alias="format-version", # why this field uses `-` instead of `_`? - title="Galaxy Workflow", - description="Whether this workflow is a Galaxy Workflow.", - ) - name: str = Field(..., title="Name", description="The name of the workflow.") - annotation: Optional[str] = AnnotationField - tags: TagCollection - uuid: Optional[UUID4] = Field( - None, - title="UUID", - description="Universal unique identifier of the workflow.", - ) - creator: Optional[List[Union[Person, Organization]]] = Field( - None, - title="Creator", - description=("Additional information about the creator (or multiple creators) of this workflow."), - ) - license: Optional[str] = Field( - None, title="License", description="SPDX Identifier of the license associated with this workflow." - ) - version: int = Field( - ..., title="Version", description="The version of the workflow represented by an incremental number." - ) - steps: Dict[int, Union[SubworkflowStepToExport, WorkflowToolStepToExport, WorkflowStepToExport]] = Field( - {}, title="Steps", description="A dictionary with information about all the steps of the workflow." - ) - - # Roles ----------------------------------------------------------------- RoleIdField = Annotated[EncodedDatabaseIdField, Field(title="ID", description="Encoded ID of the role")] diff --git a/lib/galaxy/schema/workflows.py b/lib/galaxy/schema/workflows.py index 74381ba0bbe6..9d57da280c78 100644 --- a/lib/galaxy/schema/workflows.py +++ b/lib/galaxy/schema/workflows.py @@ -701,3 +701,120 @@ class WorkflowDictFormat2WrappedYamlSummary(Model): title="YAML Content", description="The content of the workflow in YAML format.", ) + + +""" +class WorkflowStepToExportBase(Model): + id: int = Field( + ..., + title="ID", + description="The identifier of the step. It matches the index order of the step inside the workflow.", + ) + type: str = Field(..., title="Type", description="The type of workflow module.") + name: str = Field(..., title="Name", description="The descriptive name of the module or step.") + annotation: Optional[str] = AnnotationField + tool_id: Optional[str] = Field( # Duplicate of `content_id` or viceversa? + None, title="Tool ID", description="The unique name of the tool associated with this step." + ) + uuid: UUID4 = Field( + ..., + title="UUID", + description="Universal unique identifier of the workflow.", + ) + label: Optional[str] = Field( + None, + title="Label", + ) + inputs: List[Input] = Field( + ..., + title="Inputs", + description="TODO", + ) + outputs: List[Output] = Field( + ..., + title="Outputs", + description="TODO", + ) + input_connections: Dict[str, InputConnection] = Field( + {}, + title="Input Connections", + description="TODO", + ) + position: WorkflowStepLayoutPosition = Field( + ..., + title="Position", + description="Layout position of this step in the graph", + ) + workflow_outputs: List[WorkflowOutput] = Field( + [], title="Workflow Outputs", description="Workflow outputs associated with this step." + ) + + +class WorkflowStepToExport(WorkflowStepToExportBase): + content_id: Optional[str] = Field( # Duplicate of `tool_id` or viceversa? + None, title="Content ID", description="TODO" + ) + tool_version: Optional[str] = Field( + None, title="Tool Version", description="The version of the tool associated with this step." + ) + tool_state: Json = Field( + ..., + title="Tool State", + description="JSON string containing the serialized representation of the persistable state of the step.", + ) + errors: Optional[str] = Field( + None, + title="Errors", + description="An message indicating possible errors in the step.", + ) + + +class WorkflowToolStepToExport(WorkflowStepToExportBase): + tool_shed_repository: ToolShedRepositorySummary = Field( + ..., title="Tool Shed Repository", description="Information about the origin repository of this tool." + ) + post_job_actions: Dict[str, PostJobAction] = Field( + ..., title="Post-job Actions", description="Set of actions that will be run when the job finish." + ) + + +class SubworkflowStepToExport(WorkflowStepToExportBase): + subworkflow: "WorkflowToExport" = Field( + ..., title="Subworkflow", description="Full information about the subworkflow associated with this step." + ) + + +# TODO - move to schema of workflow +class WorkflowToExport(Model): + a_galaxy_workflow: str = Field( # Is this meant to be a bool instead? + "true", title="Galaxy Workflow", description="Whether this workflow is a Galaxy Workflow." + ) + format_version: str = Field( + "0.1", + alias="format-version", # why this field uses `-` instead of `_`? + title="Galaxy Workflow", + description="Whether this workflow is a Galaxy Workflow.", + ) + name: str = Field(..., title="Name", description="The name of the workflow.") + annotation: Optional[str] = AnnotationField + tags: TagCollection + uuid: Optional[UUID4] = Field( + None, + title="UUID", + description="Universal unique identifier of the workflow.", + ) + creator: Optional[List[Union[Person, Organization]]] = Field( + None, + title="Creator", + description=("Additional information about the creator (or multiple creators) of this workflow."), + ) + license: Optional[str] = Field( + None, title="License", description="SPDX Identifier of the license associated with this workflow." + ) + version: int = Field( + ..., title="Version", description="The version of the workflow represented by an incremental number." + ) + steps: Dict[int, Union[SubworkflowStepToExport, WorkflowToolStepToExport, WorkflowStepToExport]] = Field( + {}, title="Steps", description="A dictionary with information about all the steps of the workflow." + ) +""" From f7eb565bf882a01121de6dde304d40fa62daee21 Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Thu, 21 Mar 2024 22:32:22 +0100 Subject: [PATCH 39/89] Fix style error in test_set_workflow_menu --- lib/galaxy_test/api/test_workflows.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/galaxy_test/api/test_workflows.py b/lib/galaxy_test/api/test_workflows.py index 0651973b5553..0a9de8ba0e78 100644 --- a/lib/galaxy_test/api/test_workflows.py +++ b/lib/galaxy_test/api/test_workflows.py @@ -876,7 +876,7 @@ def test_set_workflow_menu(self): upload_response = self.__test_upload(workflow=workflow_object, name=original_name) workflow = upload_response.json() workflow_id = workflow["id"] - response = self._put(f"/api/workflows/menu", {"workflow_ids": workflow_id}, json=True) + response = self._put("/api/workflows/menu", {"workflow_ids": workflow_id}, json=True) self._assert_status_code_is(response, 200) def test_update_name(self): From 1869a925cb8eee468594e82d3ddf0b96c10081ed Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Thu, 21 Mar 2024 22:33:54 +0100 Subject: [PATCH 40/89] Regenerate the client schema --- client/src/api/schema/schema.ts | 100 ++++++++++++++++---------------- 1 file changed, 50 insertions(+), 50 deletions(-) diff --git a/client/src/api/schema/schema.ts b/client/src/api/schema/schema.ts index be4ae0bdc6f7..8c74d93e5ff0 100644 --- a/client/src/api/schema/schema.ts +++ b/client/src/api/schema/schema.ts @@ -16907,17 +16907,17 @@ export interface components { content_id?: string | null; /** * Errors - * @description Any errors associated with the step. + * @description An message indicating possible errors in the step. */ errors?: string[] | string | null; /** * ID - * @description The order index of the step. + * @description The identifier of the step. It matches the index order of the step inside the workflow. */ id: number; /** * Input Connections - * @description A dictionary representing the input connections for the step. + * @description The input connections for the step. */ input_connections?: Record | null; /** @@ -16932,7 +16932,7 @@ export interface components { label?: string | null; /** * Name - * @description The name of the step. + * @description The descriptive name of the module or step. */ name?: string | null; /** @@ -16942,17 +16942,17 @@ export interface components { outputs?: Record[] | null; /** * Position - * @description The position of the step. + * @description Layout position of this step in the graph */ position?: Record | null; /** * Post Job Actions - * @description A dictionary of post-job actions for the step. + * @description Set of actions that will be run when the job finishes. */ post_job_actions?: Record | Record[] | null; /** * Tool ID - * @description The tool ID associated with the step. + * @description The unique name of the tool associated with this step. */ tool_id?: string | null; /** @@ -16977,7 +16977,7 @@ export interface components { type: string; /** * UUID - * @description The UUID of the step. + * @description Universal unique identifier of the workflow. */ uuid?: string | null; /** @@ -16987,7 +16987,7 @@ export interface components { when?: string | null; /** * Workflow Outputs - * @description A list of workflow outputs for the step. + * @description Workflow outputs associated with this step. */ workflow_outputs?: Record[] | null; }; @@ -17012,7 +17012,7 @@ export interface components { | null; /** * License - * @description The license information for the workflow. + * @description SPDX Identifier of the license associated with this workflow. */ license?: string | null; /** @@ -17032,7 +17032,7 @@ export interface components { source_metadata?: Record | null; /** * Steps - * @description A dictionary with information about all the steps of the workflow. + * @description Information about all the steps of the workflow. */ steps: { [key: string]: components["schemas"]["WorkflowDictEditorSteps"] | undefined; @@ -17046,7 +17046,7 @@ export interface components { }; /** * Version - * @description The version of the workflow. + * @description The version of the workflow represented by an incremental number. */ version: number; }; @@ -17064,12 +17064,12 @@ export interface components { content_id?: string | null; /** * Errors - * @description Any errors associated with the step. + * @description An message indicating possible errors in the step. */ errors?: string[] | string | null; /** * ID - * @description The order index of the step. + * @description The identifier of the step. It matches the index order of the step inside the workflow. */ id: number; /** @@ -17096,7 +17096,7 @@ export interface components { label?: string | null; /** * Name - * @description The name of the step. + * @description The descriptive name of the module or step. */ name: string; /** @@ -17106,22 +17106,22 @@ export interface components { outputs?: Record[] | null; /** * Position - * @description The position of the step. + * @description Layout position of this step in the graph */ position?: Record | null; /** * Post Job Actions - * @description A dictionary of post-job actions for the step. + * @description Set of actions that will be run when the job finishes. */ post_job_actions?: Record | Record[] | null; /** * Sub Workflow - * @description The sub-workflow associated with the step. + * @description Full information about the subworkflow associated with this step. */ subworkflow?: Record | null; /** * Tool ID - * @description The tool ID associated with the step. + * @description The unique name of the tool associated with this step. */ tool_id?: string | null; /** @@ -17151,7 +17151,7 @@ export interface components { type: string; /** * UUID - * @description The UUID (Universally Unique Identifier) of the step. + * @description Universal unique identifier of the workflow. */ uuid: string; /** @@ -17161,7 +17161,7 @@ export interface components { when?: string | null; /** * Workflow Outputs - * @description A list of workflow outputs for the step. + * @description Workflow outputs associated with this step. */ workflow_outputs?: Record[] | null; }; @@ -17169,7 +17169,7 @@ export interface components { WorkflowDictExportSummary: { /** * A Galaxy Workflow - * @description Is a Galaxy workflow. + * @description Whether this workflow is a Galaxy Workflow. */ a_galaxy_workflow?: string | null; /** @@ -17179,7 +17179,7 @@ export interface components { annotation: string | null; /** * Comments - * @description A list of dictionaries representing comments associated with the workflow. + * @description Comments associated with the workflow. */ comments?: Record[] | null; /** @@ -17196,7 +17196,7 @@ export interface components { "format-version"?: string | null; /** * License - * @description The license information for the workflow. + * @description SPDX Identifier of the license associated with this workflow. */ license?: string | null; /** @@ -17216,7 +17216,7 @@ export interface components { source_metadata?: Record | null; /** * Steps - * @description A dictionary with information about all the steps of the workflow. + * @description Information about all the steps of the workflow. */ steps: { [key: string]: components["schemas"]["WorkflowDictExportSteps"] | undefined; @@ -17233,7 +17233,7 @@ export interface components { uuid?: string | null; /** * Version - * @description The version of the workflow. + * @description The version of the workflow represented by an incremental number. */ version: number; }; @@ -17258,7 +17258,7 @@ export interface components { doc?: string | null; /** * Inputs - * @description A dictionary representing the inputs of the workflow. + * @description The inputs of the workflow. */ inputs?: Record | null; /** @@ -17268,12 +17268,12 @@ export interface components { label?: string | null; /** * License - * @description The license information for the workflow. + * @description SPDX Identifier of the license associated with this workflow. */ license?: string | null; /** * Outputs - * @description A dictionary representing the outputs of the workflow. + * @description The outputs of the workflow. */ outputs?: Record | null; /** @@ -17288,7 +17288,7 @@ export interface components { report?: Record | null; /** * Steps - * @description A dictionary representing the steps of the workflow. + * @description Information about all the steps of the workflow. */ steps: Record; /** @@ -17324,7 +17324,7 @@ export interface components { content_id?: string | null; /** * Errors - * @description Any errors associated with the step. + * @description An message indicating possible errors in the step. */ errors?: string[] | string | null; /** @@ -17349,17 +17349,17 @@ export interface components { outputs?: Record[] | null; /** * Position - * @description The position of the step. + * @description Layout position of this step in the graph */ position?: Record | null; /** * Post Job Actions - * @description A dictionary of post-job actions for the step. + * @description Set of actions that will be run when the job finishes. */ post_job_actions?: Record | Record[] | null; /** * Tool ID - * @description The tool ID associated with the step. + * @description The unique name of the tool associated with this step. */ tool_id?: string | null; /** @@ -17384,7 +17384,7 @@ export interface components { when?: string | null; /** * Workflow Outputs - * @description A list of workflow outputs for the step. + * @description Workflow outputs associated with this step. */ workflow_outputs?: Record[] | null; }; @@ -17397,12 +17397,12 @@ export interface components { name: string; /** * Steps - * @description A dictionary with information about all the steps of the workflow. + * @description Information about all the steps of the workflow. */ steps: components["schemas"]["WorkflowDictPreviewSteps"][]; /** * Version - * @description The version of the workflow. + * @description The version of the workflow represented by an incremental number. */ version: number; }; @@ -17420,7 +17420,7 @@ export interface components { content_id?: string | null; /** * Errors - * @description Any errors associated with the step. + * @description An message indicating possible errors in the step. */ errors?: string[] | string | null; /** @@ -17435,7 +17435,7 @@ export interface components { messages?: string[] | null; /** * Output Connections - * @description A list of dictionaries representing the output connections of the step. + * @description The output connections of the step. */ output_connections: Record[]; /** @@ -17445,12 +17445,12 @@ export interface components { outputs?: Record[] | null; /** * Position - * @description The position of the step. + * @description Layout position of this step in the graph */ position?: Record | null; /** * Post Job Actions - * @description A dictionary of post-job actions for the step. + * @description Set of actions that will be run when the job finishes. */ post_job_actions?: Record | Record[] | null; /** @@ -17470,7 +17470,7 @@ export interface components { step_label?: string | null; /** * Step Name - * @description The name of the step's module. + * @description The descriptive name of the module or step. */ step_name: string; /** @@ -17485,7 +17485,7 @@ export interface components { step_version?: string | null; /** * Tool ID - * @description The tool ID associated with the step. + * @description The unique name of the tool associated with this step. */ tool_id?: string | null; /** @@ -17505,7 +17505,7 @@ export interface components { when?: string | null; /** * Workflow Outputs - * @description A list of workflow outputs for the step. + * @description Workflow outputs associated with this step. */ workflow_outputs?: Record[] | null; }; @@ -17513,17 +17513,17 @@ export interface components { WorkflowDictRunSummary: { /** * Has Upgrade Messages - * @description A boolean indicating whether the workflow has upgrade messages. + * @description Whether the workflow has upgrade messages. */ has_upgrade_messages?: boolean | null; /** * History ID - * @description The encoded ID of the history associated with the workflow (or None if not applicable). + * @description TODO */ history_id?: string | null; /** * ID - * @description The encoded ID of the stored workflow. + * @description TODO */ id?: string | null; /** @@ -17533,17 +17533,17 @@ export interface components { name: string; /** * Step Version Changes - * @description A list of version changes for the workflow steps. + * @description Version changes for the workflow steps. */ step_version_changes?: Record[] | null; /** * Steps - * @description A dictionary with information about all the steps of the workflow. + * @description Information about all the steps of the workflow. */ steps: components["schemas"]["WorkflowDictRunSteps"][]; /** * Version - * @description The version of the workflow. + * @description The version of the workflow represented by an incremental number. */ version: number; /** From abbf5077e1547f81df35a84b896fd5b32ffd2f53 Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Sun, 24 Mar 2024 17:45:45 +0100 Subject: [PATCH 41/89] Add type to uuid field --- lib/galaxy/schema/workflows.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/lib/galaxy/schema/workflows.py b/lib/galaxy/schema/workflows.py index 9d57da280c78..6ada191aa4d2 100644 --- a/lib/galaxy/schema/workflows.py +++ b/lib/galaxy/schema/workflows.py @@ -10,6 +10,7 @@ from pydantic import ( Field, field_validator, + UUID4, ) from typing_extensions import Annotated @@ -422,11 +423,10 @@ class WorkflowDictEditorSteps(WorkflowDictStepsExtendedBase): description="The configuration form for the step.", ) annotation: WorkflowAnnotationField - uuid: Optional[str] = Field( + uuid: Optional[UUID4] = Field( None, title="UUID", description="Universal unique identifier of the workflow.", - # description="The UUID (Universally Unique Identifier) of the step.", ) tooltip: Optional[str] = Field( None, @@ -451,11 +451,10 @@ class WorkflowDictExportSteps(WorkflowDictStepsExtendedBase): title="Name", description="The descriptive name of the module or step.", ) - uuid: str = Field( + uuid: UUID4 = Field( ..., title="UUID", description="Universal unique identifier of the workflow.", - # description="The UUID (Universally Unique Identifier) of the step.", ) annotation: WorkflowAnnotationField = None # TODO - can be modeled see manager line 1483 or below @@ -605,10 +604,10 @@ class WorkflowDictExportSummary(WorkflowDictBaseModel): title="Tags", description="The tags associated with the workflow.", ) - uuid: Optional[str] = Field( + uuid: Optional[UUID4] = Field( None, title="UUID", - description="The UUID (Universally Unique Identifier) of the workflow, represented as a string.", + description="The UUID (Universally Unique Identifier) of the workflow.", ) comments: Optional[List[Dict[str, Any]]] = Field( None, @@ -666,10 +665,10 @@ class WorkflowDictFormat2Summary(Model): title="Tags", description="The tags associated with the workflow.", ) - uuid: Optional[str] = Field( + uuid: Optional[UUID4] = Field( None, title="UUID", - description="The UUID (Universally Unique Identifier) of the workflow, represented as a string.", + description="The UUID (Universally Unique Identifier) of the workflow.", ) report: Optional[Dict[str, Any]] = Field( None, From 2086457753a3c5a8007d6ca1b24a9ca09b0d8a8e Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Sun, 24 Mar 2024 18:09:41 +0100 Subject: [PATCH 42/89] Move workflow specific model to the workflow schema file --- lib/galaxy/schema/schema.py | 73 ------------------------------- lib/galaxy/schema/workflows.py | 78 +++++++++++++++++++++++++++++++++- 2 files changed, 77 insertions(+), 74 deletions(-) diff --git a/lib/galaxy/schema/schema.py b/lib/galaxy/schema/schema.py index 07b1ddcb7249..1eed7730a80f 100644 --- a/lib/galaxy/schema/schema.py +++ b/lib/galaxy/schema/schema.py @@ -2276,42 +2276,6 @@ class StoredWorkflowSummary(Model, WithModelClass): ) -class WorkflowInput(Model): - label: Optional[str] = Field( - ..., - title="Label", - description="Label of the input.", - ) - value: Optional[Any] = Field( - ..., - title="Value", - description="TODO", - ) - uuid: Optional[UUID4] = Field( - ..., - title="UUID", - description="Universal unique identifier of the input.", - ) - - -class WorkflowOutput(Model): - label: Optional[str] = Field( - None, - title="Label", - description="Label of the output.", - ) - output_name: str = Field( - ..., - title="Output Name", - description="The name assigned to the output.", - ) - uuid: Optional[UUID4] = Field( - None, - title="UUID", - description="Universal unique identifier of the output.", - ) - - class InputStep(Model): source_step: int = Field( ..., @@ -2450,43 +2414,6 @@ class Person(Creator): ) -class Input(Model): - name: str = Field(..., title="Name", description="The name of the input.") - description: str = Field(..., title="Description", description="The annotation or description of the input.") - - -class Output(Model): - name: str = Field(..., title="Name", description="The name of the output.") - type: str = Field(..., title="Type", description="The extension or type of output.") - - -class InputConnection(Model): - id: int = Field(..., title="ID", description="The identifier of the input.") - output_name: str = Field( - ..., - title="Output Name", - description="The name assigned to the output.", - ) - input_subworkflow_step_id: Optional[int] = Field( - None, - title="Input Subworkflow Step ID", - description="TODO", - ) - - -class WorkflowStepLayoutPosition(Model): - """Position and dimensions of the workflow step represented by a box on the graph.""" - - bottom: int = Field(..., title="Bottom", description="Position in pixels of the bottom of the box.") - top: int = Field(..., title="Top", description="Position in pixels of the top of the box.") - left: int = Field(..., title="Left", description="Left margin or left-most position of the box.") - right: int = Field(..., title="Right", description="Right margin or right-most position of the box.") - x: int = Field(..., title="X", description="Horizontal pixel coordinate of the top right corner of the box.") - y: int = Field(..., title="Y", description="Vertical pixel coordinate of the top right corner of the box.") - height: int = Field(..., title="Height", description="Height of the box in pixels.") - width: int = Field(..., title="Width", description="Width of the box in pixels.") - - InvocationsStateCounts = RootModel[Dict[str, int]] diff --git a/lib/galaxy/schema/workflows.py b/lib/galaxy/schema/workflows.py index 6ada191aa4d2..82b0432ae7b0 100644 --- a/lib/galaxy/schema/workflows.py +++ b/lib/galaxy/schema/workflows.py @@ -28,7 +28,6 @@ StoredWorkflowSummary, SubworkflowStep, ToolStep, - WorkflowInput, ) WorkflowAnnotationField = Annotated[ @@ -49,6 +48,83 @@ ] +class Input(Model): + name: str = Field(..., title="Name", description="The name of the input.") + description: str = Field(..., title="Description", description="The annotation or description of the input.") + + +class Output(Model): + name: str = Field(..., title="Name", description="The name of the output.") + type: str = Field(..., title="Type", description="The extension or type of output.") + + +class InputConnection(Model): + id: int = Field(..., title="ID", description="The identifier of the input.") + output_name: str = Field( + ..., + title="Output Name", + description="The name assigned to the output.", + ) + input_subworkflow_step_id: Optional[int] = Field( + None, + title="Input Subworkflow Step ID", + description="TODO", + ) + + +class WorkflowStepLayoutPosition(Model): + """Position and dimensions of the workflow step represented by a box on the graph.""" + + bottom: Optional[int] = Field(None, title="Bottom", description="Position in pixels of the bottom of the box.") + top: Optional[int] = Field(None, title="Top", description="Position in pixels of the top of the box.") + left: Optional[int] = Field(None, title="Left", description="Left margin or left-most position of the box.") + right: Optional[int] = Field(None, title="Right", description="Right margin or right-most position of the box.") + x: Optional[int] = Field( + None, title="X", description="Horizontal pixel coordinate of the top right corner of the box." + ) + y: Optional[int] = Field( + None, title="Y", description="Vertical pixel coordinate of the top right corner of the box." + ) + height: Optional[int] = Field(None, title="Height", description="Height of the box in pixels.") + width: Optional[int] = Field(None, title="Width", description="Width of the box in pixels.") + + +class WorkflowInput(Model): + label: Optional[str] = Field( + ..., + title="Label", + description="Label of the input.", + ) + value: Optional[Any] = Field( + ..., + title="Value", + description="TODO", + ) + uuid: Optional[UUID4] = Field( + ..., + title="UUID", + description="Universal unique identifier of the input.", + ) + + +class WorkflowOutput(Model): + label: Optional[str] = Field( + None, + title="Label", + description="Label of the output.", + ) + output_name: str = Field( + ..., + title="Output Name", + description="The name assigned to the output.", + ) + uuid: Optional[UUID4] = Field( + None, + title="UUID", + description="Universal unique identifier of the output.", + ) + + class GetTargetHistoryPayload(Model): # TODO - Are the descriptions correct? history: Optional[str] = Field( From 3eed847cb2fad2d29890cdf46b60f66ef5158295 Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Sun, 24 Mar 2024 18:18:26 +0100 Subject: [PATCH 43/89] Add typing to position field in base model of workflowdictsteps --- lib/galaxy/schema/workflows.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/galaxy/schema/workflows.py b/lib/galaxy/schema/workflows.py index 82b0432ae7b0..b742785076cc 100644 --- a/lib/galaxy/schema/workflows.py +++ b/lib/galaxy/schema/workflows.py @@ -76,8 +76,8 @@ class WorkflowStepLayoutPosition(Model): """Position and dimensions of the workflow step represented by a box on the graph.""" bottom: Optional[int] = Field(None, title="Bottom", description="Position in pixels of the bottom of the box.") - top: Optional[int] = Field(None, title="Top", description="Position in pixels of the top of the box.") - left: Optional[int] = Field(None, title="Left", description="Left margin or left-most position of the box.") + top: int = Field(..., title="Top", description="Position in pixels of the top of the box.") + left: int = Field(..., title="Left", description="Left margin or left-most position of the box.") right: Optional[int] = Field(None, title="Right", description="Right margin or right-most position of the box.") x: Optional[int] = Field( None, title="X", description="Horizontal pixel coordinate of the top right corner of the box." @@ -370,7 +370,7 @@ class WorkflowDictStepsBase(Model): title="Tool ID", description="The unique name of the tool associated with this step.", ) - position: Optional[Any] = Field( + position: Optional[WorkflowStepLayoutPosition] = Field( None, title="Position", description="Layout position of this step in the graph", From 162503a01d79273d08f5210dfb78e8002db53299 Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Sun, 24 Mar 2024 18:37:23 +0100 Subject: [PATCH 44/89] Add further typing to step models of workflowdict --- lib/galaxy/schema/workflows.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/galaxy/schema/workflows.py b/lib/galaxy/schema/workflows.py index b742785076cc..4fd3d54dc3a4 100644 --- a/lib/galaxy/schema/workflows.py +++ b/lib/galaxy/schema/workflows.py @@ -391,8 +391,7 @@ class WorkflowDictStepsBase(Model): title="Content ID", description="The content ID of the step.", ) - # TODO - could be modeled further see manager - workflow_outputs: Optional[List[Dict[str, Any]]] = Field( + workflow_outputs: Optional[List[WorkflowOutput]] = Field( None, title="Workflow Outputs", description="Workflow outputs associated with this step.", @@ -564,7 +563,7 @@ class WorkflowDictExportSteps(WorkflowDictStepsExtendedBase): in_parameter: Optional[Dict[str, Any]] = Field( None, title="In", description="The input connections of the step.", alias="in" ) - input_connections: Optional[Dict[str, Union[Dict[str, Any], List[Dict[str, Any]]]]] = Field( + input_connections: Optional[Dict[str, Union[InputConnection, List[InputConnection]]]] = Field( None, title="Input Connections", description="The input connections of the step.", From e11bc7584a9250135a4753674a9c96bae2569a02 Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Wed, 27 Mar 2024 15:08:06 +0100 Subject: [PATCH 45/89] Allow float type for fields WorkflowStepLayoutPosition model --- lib/galaxy/schema/workflows.py | 60 +++++++++++++++++++++++++++------- 1 file changed, 48 insertions(+), 12 deletions(-) diff --git a/lib/galaxy/schema/workflows.py b/lib/galaxy/schema/workflows.py index 4fd3d54dc3a4..dcb9b119fdbd 100644 --- a/lib/galaxy/schema/workflows.py +++ b/lib/galaxy/schema/workflows.py @@ -75,18 +75,54 @@ class InputConnection(Model): class WorkflowStepLayoutPosition(Model): """Position and dimensions of the workflow step represented by a box on the graph.""" - bottom: Optional[int] = Field(None, title="Bottom", description="Position in pixels of the bottom of the box.") - top: int = Field(..., title="Top", description="Position in pixels of the top of the box.") - left: int = Field(..., title="Left", description="Left margin or left-most position of the box.") - right: Optional[int] = Field(None, title="Right", description="Right margin or right-most position of the box.") - x: Optional[int] = Field( - None, title="X", description="Horizontal pixel coordinate of the top right corner of the box." - ) - y: Optional[int] = Field( - None, title="Y", description="Vertical pixel coordinate of the top right corner of the box." - ) - height: Optional[int] = Field(None, title="Height", description="Height of the box in pixels.") - width: Optional[int] = Field(None, title="Width", description="Width of the box in pixels.") + bottom: Optional[Union[int, float]] = Field( + None, + title="Bottom", + description="Position of the bottom of the box.", + # description="Position in pixels of the bottom of the box.", + ) + top: Union[int, float] = Field( + ..., + title="Top", + description="Position of the top of the box.", + # description="Position in pixels of the top of the box.", + ) + left: Union[int, float] = Field( + ..., + title="Left", + description="Left margin or left-most position of the box.", + # description="Left margin or left-most position of the box.", + ) + right: Optional[Union[int, float]] = Field( + None, + title="Right", + description="Right margin or right-most position of the box.", + # description="Right margin or right-most position of the box.", + ) + x: Optional[Union[int, float]] = Field( + None, + title="X", + description="Horizontal coordinate of the top right corner of the box.", + # description="Horizontal pixel coordinate of the top right corner of the box.", + ) + y: Optional[Union[int, float]] = Field( + None, + title="Y", + description="Vertical coordinate of the top right corner of the box.", + # description="Vertical pixel coordinate of the top right corner of the box.", + ) + height: Optional[Union[int, float]] = Field( + None, + title="Height", + description="Height of the box.", + # description="Height of the box in pixels.", + ) + width: Optional[Union[int, float]] = Field( + None, + title="Width", + description="Width of the box.", + # description="Width of the box in pixels.", + ) class WorkflowInput(Model): From dd97e0383060d39afba23d6fc3bc597ad11810e5 Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Wed, 27 Mar 2024 15:14:18 +0100 Subject: [PATCH 46/89] Allow str as replacement_parameter in WorkflowDictRunSteps model --- lib/galaxy/schema/workflows.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/galaxy/schema/workflows.py b/lib/galaxy/schema/workflows.py index dcb9b119fdbd..3daaee7a2400 100644 --- a/lib/galaxy/schema/workflows.py +++ b/lib/galaxy/schema/workflows.py @@ -454,7 +454,7 @@ class WorkflowDictRunSteps(WorkflowDictStepsBase): title="Inputs", description="The inputs of the step.", ) - replacement_parameters: Optional[List[Dict[str, Any]]] = Field( + replacement_parameters: Optional[List[Union[str, Dict[str, Any]]]] = Field( None, title="Replacement Parameters", description="Informal replacement parameters for the step.", From fdd14c07e5986f48805b5dc30959089db1450b96 Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Thu, 28 Mar 2024 12:10:43 +0100 Subject: [PATCH 47/89] Allow str type for step_version_changes field in WorkflowDictRunSummary model --- lib/galaxy/schema/workflows.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/galaxy/schema/workflows.py b/lib/galaxy/schema/workflows.py index 3daaee7a2400..90e45dc61eb2 100644 --- a/lib/galaxy/schema/workflows.py +++ b/lib/galaxy/schema/workflows.py @@ -675,7 +675,7 @@ class WorkflowDictRunSummary(WorkflowDictBaseModel): # description="The encoded ID of the history associated with the workflow (or None if not applicable).", description="TODO", ) - step_version_changes: Optional[List[Dict[str, Any]]] = Field( + step_version_changes: Optional[List[Union[str, Dict[str, Any]]]] = Field( None, title="Step Version Changes", description="Version changes for the workflow steps.", From 79ddcfc93846378a91d6ce0621c471da96249651 Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Fri, 29 Mar 2024 13:23:27 +0100 Subject: [PATCH 48/89] Move workflow specific models to the workflow schema file --- lib/galaxy/schema/schema.py | 41 ---------------------------------- lib/galaxy/schema/workflows.py | 41 ++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 41 deletions(-) diff --git a/lib/galaxy/schema/schema.py b/lib/galaxy/schema/schema.py index 1eed7730a80f..a47d1fb63c0c 100644 --- a/lib/galaxy/schema/schema.py +++ b/lib/galaxy/schema/schema.py @@ -2417,47 +2417,6 @@ class Person(Creator): InvocationsStateCounts = RootModel[Dict[str, int]] -class ToolShedRepositorySummary(Model): - name: str = Field( - ..., - title="Name", - description="The name of the repository.", - ) - owner: str = Field( - ..., - title="Owner", - description="The owner of the repository.", - ) - changeset_revision: str = Field( - ..., - title="Changeset Revision", - description="TODO", - ) - tool_shed: str = Field( - ..., - title="Tool Shed", - description="The Tool Shed base URL.", - ) - - -class PostJobAction(Model): - action_type: str = Field( - ..., - title="Action Type", - description="The type of action to run.", - ) - output_name: str = Field( - ..., - title="Output Name", - description="The name of the output that will be affected by the action.", - ) - action_arguments: Dict[str, Any] = Field( - ..., - title="Action Arguments", - description="Any additional arguments needed by the action.", - ) - - # Roles ----------------------------------------------------------------- RoleIdField = Annotated[EncodedDatabaseIdField, Field(title="ID", description="Encoded ID of the role")] diff --git a/lib/galaxy/schema/workflows.py b/lib/galaxy/schema/workflows.py index 90e45dc61eb2..254de81834fa 100644 --- a/lib/galaxy/schema/workflows.py +++ b/lib/galaxy/schema/workflows.py @@ -161,6 +161,47 @@ class WorkflowOutput(Model): ) +class ToolShedRepositorySummary(Model): + name: str = Field( + ..., + title="Name", + description="The name of the repository.", + ) + owner: str = Field( + ..., + title="Owner", + description="The owner of the repository.", + ) + changeset_revision: str = Field( + ..., + title="Changeset Revision", + description="TODO", + ) + tool_shed: str = Field( + ..., + title="Tool Shed", + description="The Tool Shed base URL.", + ) + + +class PostJobAction(Model): + action_type: str = Field( + ..., + title="Action Type", + description="The type of action to run.", + ) + output_name: str = Field( + ..., + title="Output Name", + description="The name of the output that will be affected by the action.", + ) + action_arguments: Dict[str, Any] = Field( + ..., + title="Action Arguments", + description="Any additional arguments needed by the action.", + ) + + class GetTargetHistoryPayload(Model): # TODO - Are the descriptions correct? history: Optional[str] = Field( From 4efb80cd264b213232fad1ada0f2711dd876e08c Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Fri, 29 Mar 2024 13:53:29 +0100 Subject: [PATCH 49/89] Refine tpying in pydantic models of workflow_dict operation --- lib/galaxy/schema/workflows.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/lib/galaxy/schema/workflows.py b/lib/galaxy/schema/workflows.py index 254de81834fa..654812c75ae5 100644 --- a/lib/galaxy/schema/workflows.py +++ b/lib/galaxy/schema/workflows.py @@ -27,6 +27,7 @@ PreferredObjectStoreIdField, StoredWorkflowSummary, SubworkflowStep, + TagCollection, ToolStep, ) @@ -200,6 +201,11 @@ class PostJobAction(Model): title="Action Arguments", description="Any additional arguments needed by the action.", ) + short_str: Optional[str] = Field( + None, + title="Short String", + description="A short string representation of the action.", + ) class GetTargetHistoryPayload(Model): @@ -426,8 +432,7 @@ class WorkflowDictStepsBase(Model): title="When", description="The when expression for the step.", ) - # TODO - could be modeled further see manager - post_job_actions: Optional[Union[Dict[str, Any], List[Dict[str, Any]]]] = Field( + post_job_actions: Optional[Union[PostJobAction, List[PostJobAction]]] = Field( None, title="Post Job Actions", description="Set of actions that will be run when the job finishes.", @@ -609,16 +614,11 @@ class WorkflowDictExportSteps(WorkflowDictStepsExtendedBase): description="Universal unique identifier of the workflow.", ) annotation: WorkflowAnnotationField = None - # TODO - can be modeled see manager line 1483 or below - tool_shed_repository: Optional[Dict[str, Any]] = Field( + tool_shed_repository: Optional[ToolShedRepositorySummary] = Field( None, title="Tool Shed Repository", description="Information about the tool shed repository associated with the tool.", ) - # "name" (type: str): The name of the tool shed repository. - # "owner" (type: str): The owner of the tool shed repository. - # "changeset_revision" (type: str): The changeset revision of the tool shed repository. - # "tool_shed" (type: str): The tool shed URL. tool_representation: Optional[Dict[str, Any]] = Field( None, title="Tool Representation", @@ -630,8 +630,7 @@ class WorkflowDictExportSteps(WorkflowDictStepsExtendedBase): title="Sub Workflow", description="Full information about the subworkflow associated with this step.", ) - # TODO - can be modeled see manager line 1516 -1532 - inputs: Optional[List[Dict[str, Any]]] = Field( + inputs: Optional[List[Input]] = Field( None, title="Inputs", description="The inputs of the step.", @@ -745,13 +744,14 @@ class WorkflowDictExportSummary(WorkflowDictBaseModel): description="Whether this workflow is a Galaxy Workflow.", ) format_version: Optional[str] = Field( + # "0.1", None, alias="format-version", title="Format Version", description="The version of the workflow format being used.", ) annotation: WorkflowAnnotationField - tags: Optional[List[str]] = Field( + tags: Optional[TagCollection] = Field( None, title="Tags", description="The tags associated with the workflow.", @@ -812,7 +812,7 @@ class WorkflowDictFormat2Summary(Model): title="Release", description="The release information for the workflow.", ) - tags: Optional[List[str]] = Field( + tags: Optional[TagCollection] = Field( None, title="Tags", description="The tags associated with the workflow.", @@ -881,7 +881,7 @@ class WorkflowStepToExportBase(Model): title="Inputs", description="TODO", ) - outputs: List[Output] = Field( + outputs: List[Output] = Field( # TODO not yet used in models above ..., title="Outputs", description="TODO", From 2b9a93cda99648854a0f30c82797942dc1e64972 Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Mon, 1 Apr 2024 15:27:02 +0200 Subject: [PATCH 50/89] Type in_parameter field in WorkflowDictExportSteps with new model and add more comments --- lib/galaxy/schema/workflows.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/lib/galaxy/schema/workflows.py b/lib/galaxy/schema/workflows.py index 654812c75ae5..11f291eece20 100644 --- a/lib/galaxy/schema/workflows.py +++ b/lib/galaxy/schema/workflows.py @@ -54,6 +54,7 @@ class Input(Model): description: str = Field(..., title="Description", description="The annotation or description of the input.") +# TODO - Not in use class Output(Model): name: str = Field(..., title="Name", description="The name of the output.") type: str = Field(..., title="Type", description="The extension or type of output.") @@ -208,6 +209,15 @@ class PostJobAction(Model): ) +class StepIn(Model): + # TODO - add proper type and description - see _workflow_to_dict_export in manager for more details + default: Any = Field( + ..., + title="Default", + description="TODO", + ) + + class GetTargetHistoryPayload(Model): # TODO - Are the descriptions correct? history: Optional[str] = Field( @@ -447,7 +457,7 @@ class WorkflowDictStepsBase(Model): title="Errors", description="An message indicating possible errors in the step.", ) - tool_id: Optional[str] = Field( + tool_id: Optional[str] = Field( # Duplicate of `content_id` or viceversa? None, title="Tool ID", description="The unique name of the tool associated with this step.", @@ -463,6 +473,7 @@ class WorkflowDictStepsBase(Model): title="Outputs", description="The outputs of the step.", ) + # TODO - could be JSON type but works like tool_state: Optional[Union[Dict[str, Any], str]] = Field( None, title="Tool State", @@ -635,8 +646,7 @@ class WorkflowDictExportSteps(WorkflowDictStepsExtendedBase): title="Inputs", description="The inputs of the step.", ) - # TODO - can be modeled see manager line 1551 - in_parameter: Optional[Dict[str, Any]] = Field( + in_parameter: Optional[Dict[str, StepIn]] = Field( None, title="In", description="The input connections of the step.", alias="in" ) input_connections: Optional[Dict[str, Union[InputConnection, List[InputConnection]]]] = Field( From 8d53fbbe51c45cc179da382b175ed02bab8c6949 Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Mon, 1 Apr 2024 18:56:12 +0200 Subject: [PATCH 51/89] Adjsut typing of field post_job_actions in model WorkflowDictStepsBase --- lib/galaxy/schema/workflows.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/galaxy/schema/workflows.py b/lib/galaxy/schema/workflows.py index 11f291eece20..3be81c89c661 100644 --- a/lib/galaxy/schema/workflows.py +++ b/lib/galaxy/schema/workflows.py @@ -442,7 +442,7 @@ class WorkflowDictStepsBase(Model): title="When", description="The when expression for the step.", ) - post_job_actions: Optional[Union[PostJobAction, List[PostJobAction]]] = Field( + post_job_actions: Optional[Union[List[PostJobAction], Dict[str, PostJobAction]]] = Field( None, title="Post Job Actions", description="Set of actions that will be run when the job finishes.", From 8da95925827ac7d6e670b3edfc67396a852b3dc9 Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Fri, 12 Apr 2024 17:27:09 +0200 Subject: [PATCH 52/89] Remove comments --- lib/galaxy/schema/workflows.py | 117 --------------------------------- 1 file changed, 117 deletions(-) diff --git a/lib/galaxy/schema/workflows.py b/lib/galaxy/schema/workflows.py index 3be81c89c661..c9ee0371a31a 100644 --- a/lib/galaxy/schema/workflows.py +++ b/lib/galaxy/schema/workflows.py @@ -862,120 +862,3 @@ class WorkflowDictFormat2WrappedYamlSummary(Model): title="YAML Content", description="The content of the workflow in YAML format.", ) - - -""" -class WorkflowStepToExportBase(Model): - id: int = Field( - ..., - title="ID", - description="The identifier of the step. It matches the index order of the step inside the workflow.", - ) - type: str = Field(..., title="Type", description="The type of workflow module.") - name: str = Field(..., title="Name", description="The descriptive name of the module or step.") - annotation: Optional[str] = AnnotationField - tool_id: Optional[str] = Field( # Duplicate of `content_id` or viceversa? - None, title="Tool ID", description="The unique name of the tool associated with this step." - ) - uuid: UUID4 = Field( - ..., - title="UUID", - description="Universal unique identifier of the workflow.", - ) - label: Optional[str] = Field( - None, - title="Label", - ) - inputs: List[Input] = Field( - ..., - title="Inputs", - description="TODO", - ) - outputs: List[Output] = Field( # TODO not yet used in models above - ..., - title="Outputs", - description="TODO", - ) - input_connections: Dict[str, InputConnection] = Field( - {}, - title="Input Connections", - description="TODO", - ) - position: WorkflowStepLayoutPosition = Field( - ..., - title="Position", - description="Layout position of this step in the graph", - ) - workflow_outputs: List[WorkflowOutput] = Field( - [], title="Workflow Outputs", description="Workflow outputs associated with this step." - ) - - -class WorkflowStepToExport(WorkflowStepToExportBase): - content_id: Optional[str] = Field( # Duplicate of `tool_id` or viceversa? - None, title="Content ID", description="TODO" - ) - tool_version: Optional[str] = Field( - None, title="Tool Version", description="The version of the tool associated with this step." - ) - tool_state: Json = Field( - ..., - title="Tool State", - description="JSON string containing the serialized representation of the persistable state of the step.", - ) - errors: Optional[str] = Field( - None, - title="Errors", - description="An message indicating possible errors in the step.", - ) - - -class WorkflowToolStepToExport(WorkflowStepToExportBase): - tool_shed_repository: ToolShedRepositorySummary = Field( - ..., title="Tool Shed Repository", description="Information about the origin repository of this tool." - ) - post_job_actions: Dict[str, PostJobAction] = Field( - ..., title="Post-job Actions", description="Set of actions that will be run when the job finish." - ) - - -class SubworkflowStepToExport(WorkflowStepToExportBase): - subworkflow: "WorkflowToExport" = Field( - ..., title="Subworkflow", description="Full information about the subworkflow associated with this step." - ) - - -# TODO - move to schema of workflow -class WorkflowToExport(Model): - a_galaxy_workflow: str = Field( # Is this meant to be a bool instead? - "true", title="Galaxy Workflow", description="Whether this workflow is a Galaxy Workflow." - ) - format_version: str = Field( - "0.1", - alias="format-version", # why this field uses `-` instead of `_`? - title="Galaxy Workflow", - description="Whether this workflow is a Galaxy Workflow.", - ) - name: str = Field(..., title="Name", description="The name of the workflow.") - annotation: Optional[str] = AnnotationField - tags: TagCollection - uuid: Optional[UUID4] = Field( - None, - title="UUID", - description="Universal unique identifier of the workflow.", - ) - creator: Optional[List[Union[Person, Organization]]] = Field( - None, - title="Creator", - description=("Additional information about the creator (or multiple creators) of this workflow."), - ) - license: Optional[str] = Field( - None, title="License", description="SPDX Identifier of the license associated with this workflow." - ) - version: int = Field( - ..., title="Version", description="The version of the workflow represented by an incremental number." - ) - steps: Dict[int, Union[SubworkflowStepToExport, WorkflowToolStepToExport, WorkflowStepToExport]] = Field( - {}, title="Steps", description="A dictionary with information about all the steps of the workflow." - ) -""" From ec2da0f0409cb53ccb4bf89fdfd2ebc0070af789 Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Mon, 15 Apr 2024 15:24:07 +0200 Subject: [PATCH 53/89] Refine return models of the workflow_dict operation from the WorkflowAPI --- lib/galaxy/schema/workflows.py | 90 ++++++++++++++++++++-------------- 1 file changed, 52 insertions(+), 38 deletions(-) diff --git a/lib/galaxy/schema/workflows.py b/lib/galaxy/schema/workflows.py index c9ee0371a31a..c38f2e0b33f8 100644 --- a/lib/galaxy/schema/workflows.py +++ b/lib/galaxy/schema/workflows.py @@ -1,4 +1,5 @@ import json +from enum import Enum from typing import ( Any, Dict, @@ -12,9 +13,15 @@ field_validator, UUID4, ) -from typing_extensions import Annotated +from typing_extensions import ( + Annotated, + Literal, +) -from galaxy.schema.fields import DecodedDatabaseIdField +from galaxy.schema.fields import ( + DecodedDatabaseIdField, + EncodedDatabaseIdField, +) from galaxy.schema.schema import ( AnnotationField, InputDataCollectionStep, @@ -30,6 +37,7 @@ TagCollection, ToolStep, ) +from galaxy.schema.workflow.comments import WorkflowCommentModel WorkflowAnnotationField = Annotated[ Optional[str], @@ -49,6 +57,12 @@ ] +class GalaxyWorkflowIdentifiers(str, Enum): + true = "true" + zero_point_one = "0.1" + galaxy_workflow = "GalaxyWorkflow" + + class Input(Model): name: str = Field(..., title="Name", description="The name of the input.") description: str = Field(..., title="Description", description="The annotation or description of the input.") @@ -211,6 +225,7 @@ class PostJobAction(Model): class StepIn(Model): # TODO - add proper type and description - see _workflow_to_dict_export in manager for more details + # or class WorkflowStepInput default: Any = Field( ..., title="Default", @@ -635,8 +650,7 @@ class WorkflowDictExportSteps(WorkflowDictStepsExtendedBase): title="Tool Representation", description="The representation of the tool associated with the step.", ) - # TODO - can also be WorkflowDictExportSummary see manager line 1512 - subworkflow: Optional[Dict[str, Any]] = Field( + subworkflow: Optional["WorkflowDictExportSummary"] = Field( None, title="Sub Workflow", description="Full information about the subworkflow associated with this step.", @@ -646,9 +660,7 @@ class WorkflowDictExportSteps(WorkflowDictStepsExtendedBase): title="Inputs", description="The inputs of the step.", ) - in_parameter: Optional[Dict[str, StepIn]] = Field( - None, title="In", description="The input connections of the step.", alias="in" - ) + in_parameter: Optional[Dict[str, StepIn]] = Field(None, title="In", description="TODO", alias="in") input_connections: Optional[Dict[str, Union[InputConnection, List[InputConnection]]]] = Field( None, title="Input Connections", @@ -683,25 +695,26 @@ class WorkflowDictEditorSummary(WorkflowDictBaseModel): title="Upgrade Messages", description="Upgrade messages for each step in the workflow.", ) + # TODO - can this be modeled further? see manager method _workflow_to_dict_editor report: Dict[str, Any] = Field( ..., title="Report", description="The reports configuration for the workflow.", ) - comments: List[Dict[str, Any]] = Field( + comments: List[WorkflowCommentModel] = Field( ..., title="Comments", description="Comments on the workflow.", ) annotation: WorkflowAnnotationField license: Optional[str] = Field( - None, + ..., title="License", description="SPDX Identifier of the license associated with this workflow.", ) creator: WorkflowCreator source_metadata: Optional[Dict[str, Any]] = Field( - None, + ..., title="Source Metadata", description="Metadata about the source of the workflow", ) @@ -713,30 +726,28 @@ class WorkflowDictEditorSummary(WorkflowDictBaseModel): class WorkflowDictRunSummary(WorkflowDictBaseModel): - id: Optional[str] = Field( - None, + id: EncodedDatabaseIdField = Field( + ..., title="ID", - # description="The encoded ID of the stored workflow.", - description="TODO", + description="The encoded ID of the stored workflow.", ) - history_id: Optional[str] = Field( + history_id: Optional[EncodedDatabaseIdField] = Field( None, title="History ID", - # description="The encoded ID of the history associated with the workflow (or None if not applicable).", - description="TODO", + description="The encoded ID of the history associated with the workflow.", ) - step_version_changes: Optional[List[Union[str, Dict[str, Any]]]] = Field( - None, + step_version_changes: List[Union[str, Dict[str, Any]]] = Field( + ..., title="Step Version Changes", description="Version changes for the workflow steps.", ) - has_upgrade_messages: Optional[bool] = Field( - None, + has_upgrade_messages: bool = Field( + ..., title="Has Upgrade Messages", description="Whether the workflow has upgrade messages.", ) workflow_resource_parameters: Optional[Dict[str, Any]] = Field( - None, + ..., title="Workflow Resource Parameters", description="The resource parameters of the workflow.", ) @@ -748,21 +759,22 @@ class WorkflowDictRunSummary(WorkflowDictBaseModel): class WorkflowDictExportSummary(WorkflowDictBaseModel): - a_galaxy_workflow: Optional[str] = Field( - None, + a_galaxy_workflow: Literal[GalaxyWorkflowIdentifiers.true] = Field( + # a_galaxy_workflow: str = Field( + ..., title="A Galaxy Workflow", description="Whether this workflow is a Galaxy Workflow.", ) - format_version: Optional[str] = Field( - # "0.1", - None, + format_version: Literal[GalaxyWorkflowIdentifiers.zero_point_one] = Field( + # format_version: str = Field( + ..., alias="format-version", title="Format Version", description="The version of the workflow format being used.", ) annotation: WorkflowAnnotationField - tags: Optional[TagCollection] = Field( - None, + tags: TagCollection = Field( + ..., title="Tags", description="The tags associated with the workflow.", ) @@ -771,8 +783,8 @@ class WorkflowDictExportSummary(WorkflowDictBaseModel): title="UUID", description="The UUID (Universally Unique Identifier) of the workflow.", ) - comments: Optional[List[Dict[str, Any]]] = Field( - None, + comments: List[Dict[str, Any]] = Field( + ..., title="Comments", description="Comments associated with the workflow.", ) @@ -800,7 +812,7 @@ class WorkflowDictExportSummary(WorkflowDictBaseModel): class WorkflowDictFormat2Summary(Model): - workflow_class: str = Field( + workflow_class: Literal[GalaxyWorkflowIdentifiers.galaxy_workflow] = Field( ..., title="Class", description="The class of the workflow.", @@ -837,17 +849,17 @@ class WorkflowDictFormat2Summary(Model): title="Report", description="The configuration for generating a report for the workflow.", ) - inputs: Optional[Dict[str, Any]] = Field( - None, + inputs: Dict[str, Any] = Field( + ..., title="Inputs", description="The inputs of the workflow.", ) - outputs: Optional[Dict[str, Any]] = Field( - None, + outputs: Dict[str, Any] = Field( + ..., title="Outputs", description="The outputs of the workflow.", ) - # TODO - step into line 888 in manager + # TODO - can be modeled further see manager method workflow_to_dict steps: Dict[str, Any] = Field( ..., title="Steps", @@ -857,8 +869,10 @@ class WorkflowDictFormat2Summary(Model): class WorkflowDictFormat2WrappedYamlSummary(Model): + # TODO What type is this? yaml_content: Any = Field( ..., title="YAML Content", - description="The content of the workflow in YAML format.", + # description="Safe and ordered dump of YAML to stream", + description="The content of the workflow in YAML .", ) From 3621fcfdfb4e0512107d1541af20d423d4c84dc0 Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Mon, 15 Apr 2024 15:31:09 +0200 Subject: [PATCH 54/89] Remove comments --- lib/galaxy/schema/workflows.py | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/lib/galaxy/schema/workflows.py b/lib/galaxy/schema/workflows.py index c38f2e0b33f8..8e462e848a60 100644 --- a/lib/galaxy/schema/workflows.py +++ b/lib/galaxy/schema/workflows.py @@ -95,49 +95,41 @@ class WorkflowStepLayoutPosition(Model): None, title="Bottom", description="Position of the bottom of the box.", - # description="Position in pixels of the bottom of the box.", ) top: Union[int, float] = Field( ..., title="Top", description="Position of the top of the box.", - # description="Position in pixels of the top of the box.", ) left: Union[int, float] = Field( ..., title="Left", description="Left margin or left-most position of the box.", - # description="Left margin or left-most position of the box.", ) right: Optional[Union[int, float]] = Field( None, title="Right", description="Right margin or right-most position of the box.", - # description="Right margin or right-most position of the box.", ) x: Optional[Union[int, float]] = Field( None, title="X", description="Horizontal coordinate of the top right corner of the box.", - # description="Horizontal pixel coordinate of the top right corner of the box.", ) y: Optional[Union[int, float]] = Field( None, title="Y", description="Vertical coordinate of the top right corner of the box.", - # description="Vertical pixel coordinate of the top right corner of the box.", ) height: Optional[Union[int, float]] = Field( None, title="Height", description="Height of the box.", - # description="Height of the box in pixels.", ) width: Optional[Union[int, float]] = Field( None, title="Width", description="Width of the box.", - # description="Width of the box in pixels.", ) @@ -238,19 +230,16 @@ class GetTargetHistoryPayload(Model): history: Optional[str] = Field( None, title="History", - # description="The encoded history id - passed exactly like this 'hist_id=...' - to import the workflow into. Or the name of the new history to import the workflow into.", description="The encoded history id - passed exactly like this 'hist_id=...' - into which to import. Or the name of the new history into which to import.", ) history_id: Optional[str] = Field( None, title="History ID", - # description="The history to import the workflow into.", description="The encoded history id into which to import.", ) new_history_name: Optional[str] = Field( None, title="New History Name", - # description="The name of the new history to import the workflow into.", description="The name of the new history into which to import.", ) From 51824e8538b024a7e2f2cb2756f2d882767f2dfc Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Tue, 16 Apr 2024 09:23:09 +0200 Subject: [PATCH 55/89] Refine return models of the workflow_dict operation from the WorkflowAPI --- lib/galaxy/schema/workflows.py | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/lib/galaxy/schema/workflows.py b/lib/galaxy/schema/workflows.py index 8e462e848a60..1ad1a8fbf3ee 100644 --- a/lib/galaxy/schema/workflows.py +++ b/lib/galaxy/schema/workflows.py @@ -57,10 +57,11 @@ ] -class GalaxyWorkflowIdentifiers(str, Enum): +class GalaxyWorkflowStrAttributes(str, Enum): true = "true" zero_point_one = "0.1" galaxy_workflow = "GalaxyWorkflow" + no_tags = "" class Input(Model): @@ -639,6 +640,7 @@ class WorkflowDictExportSteps(WorkflowDictStepsExtendedBase): title="Tool Representation", description="The representation of the tool associated with the step.", ) + # subworkflow: Optional[Dict[str, Any]] = Field( subworkflow: Optional["WorkflowDictExportSummary"] = Field( None, title="Sub Workflow", @@ -663,6 +665,9 @@ class WorkflowDictBaseModel(Model): title="Name", description="The name of the workflow.", ) + + +class WorkflowDictExtendedBaseModel(WorkflowDictBaseModel): version: int = Field( ..., title="Version", @@ -670,7 +675,7 @@ class WorkflowDictBaseModel(Model): ) -class WorkflowDictPreviewSummary(WorkflowDictBaseModel): +class WorkflowDictPreviewSummary(WorkflowDictExtendedBaseModel): steps: List[WorkflowDictPreviewSteps] = Field( ..., title="Steps", @@ -678,7 +683,7 @@ class WorkflowDictPreviewSummary(WorkflowDictBaseModel): ) -class WorkflowDictEditorSummary(WorkflowDictBaseModel): +class WorkflowDictEditorSummary(WorkflowDictExtendedBaseModel): upgrade_messages: Dict[int, str] = Field( ..., title="Upgrade Messages", @@ -714,7 +719,7 @@ class WorkflowDictEditorSummary(WorkflowDictBaseModel): ) -class WorkflowDictRunSummary(WorkflowDictBaseModel): +class WorkflowDictRunSummary(WorkflowDictExtendedBaseModel): id: EncodedDatabaseIdField = Field( ..., title="ID", @@ -748,13 +753,18 @@ class WorkflowDictRunSummary(WorkflowDictBaseModel): class WorkflowDictExportSummary(WorkflowDictBaseModel): - a_galaxy_workflow: Literal[GalaxyWorkflowIdentifiers.true] = Field( + a_galaxy_workflow: Literal[GalaxyWorkflowStrAttributes.true] = Field( # a_galaxy_workflow: str = Field( ..., title="A Galaxy Workflow", description="Whether this workflow is a Galaxy Workflow.", ) - format_version: Literal[GalaxyWorkflowIdentifiers.zero_point_one] = Field( + version: Optional[int] = Field( + None, + title="Version", + description="The version of the workflow represented by an incremental number.", + ) + format_version: Literal[GalaxyWorkflowStrAttributes.zero_point_one] = Field( # format_version: str = Field( ..., alias="format-version", @@ -762,7 +772,7 @@ class WorkflowDictExportSummary(WorkflowDictBaseModel): description="The version of the workflow format being used.", ) annotation: WorkflowAnnotationField - tags: TagCollection = Field( + tags: Union[TagCollection, Literal[GalaxyWorkflowStrAttributes.no_tags]] = Field( ..., title="Tags", description="The tags associated with the workflow.", @@ -801,7 +811,7 @@ class WorkflowDictExportSummary(WorkflowDictBaseModel): class WorkflowDictFormat2Summary(Model): - workflow_class: Literal[GalaxyWorkflowIdentifiers.galaxy_workflow] = Field( + workflow_class: Literal[GalaxyWorkflowStrAttributes.galaxy_workflow] = Field( ..., title="Class", description="The class of the workflow.", From d54d6c4fd4b00cb4761ccfd72815cb22f95e1243 Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Wed, 17 Apr 2024 10:13:38 +0200 Subject: [PATCH 56/89] Refine return models of the workflow_dict operation from the WorkflowAPI and add tool specific step model for runsummary model --- lib/galaxy/schema/workflows.py | 230 ++++++++++++++++++++++++++++----- 1 file changed, 201 insertions(+), 29 deletions(-) diff --git a/lib/galaxy/schema/workflows.py b/lib/galaxy/schema/workflows.py index 1ad1a8fbf3ee..a346dbe06211 100644 --- a/lib/galaxy/schema/workflows.py +++ b/lib/galaxy/schema/workflows.py @@ -1,5 +1,4 @@ import json -from enum import Enum from typing import ( Any, Dict, @@ -18,10 +17,7 @@ Literal, ) -from galaxy.schema.fields import ( - DecodedDatabaseIdField, - EncodedDatabaseIdField, -) +from galaxy.schema.fields import DecodedDatabaseIdField from galaxy.schema.schema import ( AnnotationField, InputDataCollectionStep, @@ -57,13 +53,6 @@ ] -class GalaxyWorkflowStrAttributes(str, Enum): - true = "true" - zero_point_one = "0.1" - galaxy_workflow = "GalaxyWorkflow" - no_tags = "" - - class Input(Model): name: str = Field(..., title="Name", description="The name of the input.") description: str = Field(..., title="Description", description="The annotation or description of the input.") @@ -472,13 +461,11 @@ class WorkflowDictStepsBase(Model): title="Position", description="Layout position of this step in the graph", ) - # TODO - can be modeled further see manager outputs: Optional[List[Dict[str, Any]]] = Field( None, title="Outputs", description="The outputs of the step.", ) - # TODO - could be JSON type but works like tool_state: Optional[Union[Dict[str, Any], str]] = Field( None, title="Tool State", @@ -510,7 +497,7 @@ class WorkflowDictStepsExtendedBase(WorkflowDictStepsBase): # TODO - This is potentially missing some fields, when step type is tool - see manager line 1006 - TODO -class WorkflowDictRunSteps(WorkflowDictStepsBase): +class WorkflowDictRunStep(WorkflowDictStepsBase): inputs: List[Dict[str, Any]] = Field( ..., title="Inputs", @@ -555,7 +542,193 @@ class WorkflowDictRunSteps(WorkflowDictStepsBase): ) -class WorkflowDictPreviewSteps(WorkflowDictStepsExtendedBase): +class WorkflowDictRunToolStep(WorkflowDictRunStep): + model_class: Literal["tool"] = Field( + ..., + title="Model Class", + description="The model class of the tool step.", + # description="The model class of the step, given it is a tool.", + ) + id: str = Field( + ..., + title="ID", + description="The identifier of the tool step.", + ) + name: str = Field( + ..., + title="Name", + description="The name of the tool step.", + ) + version: str = Field( + ..., + title="Version", + description="The version of the tool step.", + ) + description: str = Field( + ..., + title="Description", + description="The description of the tool step.", + ) + labels: List[str] = Field( + ..., + title="Labels", + description="The labels of the tool step.", + ) + edam_operations: List[str] = Field( + ..., + title="EDAM Operations", + description="The EDAM operations of the tool step.", + ) + edam_topics: List[str] = Field( + ..., + title="EDAM Topics", + description="The EDAM topics of the tool step.", + ) + hidden: str = Field( + ..., + title="Hidden", + description="The hidden status of the tool step.", + ) + is_workflow_compatible: bool = Field( + ..., + title="Is Workflow Compatible", + description="Indicates if the tool step is compatible with workflows.", + ) + xrefs: List[str] = Field( + ..., + title="XRefs", + description="The cross-references of the tool step.", + ) + panel_section_id: str = Field( + ..., + title="Panel Section ID", + description="The panel section ID of the tool step.", + ) + panel_section_name: str = Field( + ..., + title="Panel Section Name", + description="The panel section name of the tool step.", + ) + form_style: str = Field( + ..., + title="Form Style", + description="The form style of the tool step.", + ) + help: str = Field( + ..., + title="Help", + description="The help of the tool step.", + ) + citations: bool = Field( + ..., + title="Citations", + description="The citations of the tool step.", + ) + sharable_url: Optional[str] = Field( + None, + title="Sharable URL", + description="The sharable URL of the tool step.", + ) + message: str = Field( + ..., + title="Message", + description="The message of the tool step.", + ) + warnings: Optional[str] = Field( + None, + title="Warnings", + description="The warnings of the tool step.", + ) + versions: List[str] = Field( + ..., + title="Versions", + description="The versions of the tool step.", + ) + requirements: List[str] = Field( + ..., + title="Requirements", + description="The requirements of the tool step.", + ) + tool_errors: Optional[str] = Field( + None, + title="Tool Errors", + description="An message indicating possible errors in the tool step.", + ) + state_inputs: Dict[str, Any] = Field( + ..., + title="State Inputs", + description="The state inputs of the tool step.", + ) + job_id: Optional[str] = Field( + None, + title="Job ID", + description="The ID of the job associated with the tool step.", + ) + job_remap: Optional[str] = Field( + None, + title="Job Remap", + description="The remap of the job associated with the tool step.", + ) + history_id: str = Field( + ..., + title="History ID", + description="The ID of the history associated with the tool step.", + ) + display: bool = Field( + ..., + title="Display", + description="Indicates if the tool step should be displayed.", + ) + action: str = Field( + ..., + title="Action", + description="The action of the tool step.", + ) + license: Optional[str] = Field( + None, + title="License", + description="The license of the tool step.", + ) + creator: Optional[str] = Field( + None, + title="Creator", + description="The creator of the tool step.", + ) + method: str = Field( + ..., + title="Method", + description="The method of the tool step.", + ) + enctype: str = Field( + ..., + title="Enctype", + description="The enctype of the tool step.", + ) + tool_shed_repository: Optional[ToolShedRepositorySummary] = Field( + None, + title="Tool Shed Repository", + description="Information about the tool shed repository associated with the tool.", + ) + link: Optional[str] = Field( + None, + title="Link", + description="The link of the tool step.", + ) + # TODO - see lib/galaxy/tools/__init__.py - class Tool - to_dict for further typing + min_width: Optional[Any] = Field( + None, + title="Min Width", + description="The minimum width of the tool step.", + ) + # TODO - see lib/galaxy/tools/__init__.py - class Tool - to_dict for further typing + target: Optional[Any] = Field( + None, + title="Target", + description="The target of the tool step.", + ) + + +class WorkflowDictPreviewStep(WorkflowDictStepsExtendedBase): order_index: int = Field( ..., title="Order Index", @@ -574,7 +747,7 @@ class WorkflowDictPreviewSteps(WorkflowDictStepsExtendedBase): ) -class WorkflowDictEditorSteps(WorkflowDictStepsExtendedBase): +class WorkflowDictEditorStep(WorkflowDictStepsExtendedBase): id: int = Field( ..., title="ID", @@ -613,7 +786,7 @@ class WorkflowDictEditorSteps(WorkflowDictStepsExtendedBase): ) -class WorkflowDictExportSteps(WorkflowDictStepsExtendedBase): +class WorkflowDictExportStep(WorkflowDictStepsExtendedBase): id: int = Field( ..., title="ID", @@ -640,7 +813,6 @@ class WorkflowDictExportSteps(WorkflowDictStepsExtendedBase): title="Tool Representation", description="The representation of the tool associated with the step.", ) - # subworkflow: Optional[Dict[str, Any]] = Field( subworkflow: Optional["WorkflowDictExportSummary"] = Field( None, title="Sub Workflow", @@ -676,7 +848,7 @@ class WorkflowDictExtendedBaseModel(WorkflowDictBaseModel): class WorkflowDictPreviewSummary(WorkflowDictExtendedBaseModel): - steps: List[WorkflowDictPreviewSteps] = Field( + steps: List[WorkflowDictPreviewStep] = Field( ..., title="Steps", description="Information about all the steps of the workflow.", @@ -712,7 +884,7 @@ class WorkflowDictEditorSummary(WorkflowDictExtendedBaseModel): title="Source Metadata", description="Metadata about the source of the workflow", ) - steps: Dict[int, WorkflowDictEditorSteps] = Field( + steps: Dict[int, WorkflowDictEditorStep] = Field( ..., title="Steps", description="Information about all the steps of the workflow.", @@ -720,12 +892,12 @@ class WorkflowDictEditorSummary(WorkflowDictExtendedBaseModel): class WorkflowDictRunSummary(WorkflowDictExtendedBaseModel): - id: EncodedDatabaseIdField = Field( + id: str = Field( ..., title="ID", description="The encoded ID of the stored workflow.", ) - history_id: Optional[EncodedDatabaseIdField] = Field( + history_id: Optional[str] = Field( None, title="History ID", description="The encoded ID of the history associated with the workflow.", @@ -745,7 +917,7 @@ class WorkflowDictRunSummary(WorkflowDictExtendedBaseModel): title="Workflow Resource Parameters", description="The resource parameters of the workflow.", ) - steps: List[WorkflowDictRunSteps] = Field( + steps: List[Union[WorkflowDictRunToolStep, WorkflowDictRunStep]] = Field( ..., title="Steps", description="Information about all the steps of the workflow.", @@ -753,7 +925,7 @@ class WorkflowDictRunSummary(WorkflowDictExtendedBaseModel): class WorkflowDictExportSummary(WorkflowDictBaseModel): - a_galaxy_workflow: Literal[GalaxyWorkflowStrAttributes.true] = Field( + a_galaxy_workflow: Literal["true"] = Field( # a_galaxy_workflow: str = Field( ..., title="A Galaxy Workflow", @@ -764,7 +936,7 @@ class WorkflowDictExportSummary(WorkflowDictBaseModel): title="Version", description="The version of the workflow represented by an incremental number.", ) - format_version: Literal[GalaxyWorkflowStrAttributes.zero_point_one] = Field( + format_version: Literal["0.1"] = Field( # format_version: str = Field( ..., alias="format-version", @@ -772,7 +944,7 @@ class WorkflowDictExportSummary(WorkflowDictBaseModel): description="The version of the workflow format being used.", ) annotation: WorkflowAnnotationField - tags: Union[TagCollection, Literal[GalaxyWorkflowStrAttributes.no_tags]] = Field( + tags: Union[TagCollection, Literal[""]] = Field( ..., title="Tags", description="The tags associated with the workflow.", @@ -803,7 +975,7 @@ class WorkflowDictExportSummary(WorkflowDictBaseModel): title="Source Metadata", description="Metadata about the source of the workflow.", ) - steps: Dict[int, WorkflowDictExportSteps] = Field( + steps: Dict[int, WorkflowDictExportStep] = Field( ..., title="Steps", description="Information about all the steps of the workflow.", @@ -811,7 +983,7 @@ class WorkflowDictExportSummary(WorkflowDictBaseModel): class WorkflowDictFormat2Summary(Model): - workflow_class: Literal[GalaxyWorkflowStrAttributes.galaxy_workflow] = Field( + workflow_class: Literal["GalaxyWorkflow"] = Field( ..., title="Class", description="The class of the workflow.", From f5bc8785ea07aba94859cd18b6c976791ee5e14c Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Wed, 17 Apr 2024 10:14:57 +0200 Subject: [PATCH 57/89] Remove comment --- lib/galaxy/schema/workflows.py | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/galaxy/schema/workflows.py b/lib/galaxy/schema/workflows.py index a346dbe06211..71a18d6671c3 100644 --- a/lib/galaxy/schema/workflows.py +++ b/lib/galaxy/schema/workflows.py @@ -496,7 +496,6 @@ class WorkflowDictStepsExtendedBase(WorkflowDictStepsBase): ) -# TODO - This is potentially missing some fields, when step type is tool - see manager line 1006 - TODO class WorkflowDictRunStep(WorkflowDictStepsBase): inputs: List[Dict[str, Any]] = Field( ..., From bc3288de864e31ef13efbe20bb4d19f4b21e9afb Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Sat, 4 May 2024 18:09:59 +0200 Subject: [PATCH 58/89] Remove unused imports --- lib/galaxy/webapps/galaxy/api/workflows.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/galaxy/webapps/galaxy/api/workflows.py b/lib/galaxy/webapps/galaxy/api/workflows.py index 4fa6ca6c9aab..6da9f55faacb 100644 --- a/lib/galaxy/webapps/galaxy/api/workflows.py +++ b/lib/galaxy/webapps/galaxy/api/workflows.py @@ -94,11 +94,16 @@ from galaxy.tools import recommendations from galaxy.tools.parameters import populate_state from galaxy.tools.parameters.workflow_utils import workflow_building_modes +<<<<<<< HEAD from galaxy.web import ( expose_api, expose_api_raw_anonymous_and_sessionless, format_return_as_json, ) +======= +from galaxy.util.sanitize_html import sanitize_html +from galaxy.web import expose_api +>>>>>>> Remove unused imports from galaxy.webapps.base.controller import ( SharableMixin, url_for, From b576477d4c6dad256ac102d92631eeeff180361b Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Thu, 23 May 2024 15:17:12 +0200 Subject: [PATCH 59/89] Apply suggested changes --- lib/galaxy/schema/workflows.py | 17 +++++------------ lib/galaxy/webapps/galaxy/api/workflows.py | 2 +- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/lib/galaxy/schema/workflows.py b/lib/galaxy/schema/workflows.py index 71a18d6671c3..a2f14c5b5fc3 100644 --- a/lib/galaxy/schema/workflows.py +++ b/lib/galaxy/schema/workflows.py @@ -53,23 +53,17 @@ ] -class Input(Model): +class WorkflowDictExportStepInput(Model): name: str = Field(..., title="Name", description="The name of the input.") description: str = Field(..., title="Description", description="The annotation or description of the input.") -# TODO - Not in use -class Output(Model): - name: str = Field(..., title="Name", description="The name of the output.") - type: str = Field(..., title="Type", description="The extension or type of output.") - - class InputConnection(Model): - id: int = Field(..., title="ID", description="The identifier of the input.") + id: int = Field(..., title="ID", description="The order index of the step.") output_name: str = Field( ..., title="Output Name", - description="The name assigned to the output.", + description="The output name of the input step that serves as the source for this connection.", ) input_subworkflow_step_id: Optional[int] = Field( None, @@ -132,7 +126,6 @@ class WorkflowInput(Model): value: Optional[Any] = Field( ..., title="Value", - description="TODO", ) uuid: Optional[UUID4] = Field( ..., @@ -150,7 +143,7 @@ class WorkflowOutput(Model): output_name: str = Field( ..., title="Output Name", - description="The name assigned to the output.", + description="The name of the step output.", ) uuid: Optional[UUID4] = Field( None, @@ -817,7 +810,7 @@ class WorkflowDictExportStep(WorkflowDictStepsExtendedBase): title="Sub Workflow", description="Full information about the subworkflow associated with this step.", ) - inputs: Optional[List[Input]] = Field( + inputs: Optional[List[WorkflowDictExportStepInput]] = Field( None, title="Inputs", description="The inputs of the step.", diff --git a/lib/galaxy/webapps/galaxy/api/workflows.py b/lib/galaxy/webapps/galaxy/api/workflows.py index 6da9f55faacb..9ff3aff99eee 100644 --- a/lib/galaxy/webapps/galaxy/api/workflows.py +++ b/lib/galaxy/webapps/galaxy/api/workflows.py @@ -796,7 +796,7 @@ def __get_stored_workflow(self, trans, workflow_id, **kwd): Optional[str], Query( title="Style of export", - description="The default is 'export', which is the meant to be used with workflow import endpoints. Other formats such as 'instance', 'editor', 'run' are more tied to the GUI and should not be considered stable APIs. The default format for 'export' is specified by the admin with the `default_workflow_export_format` config option. Style can be specified as either 'ga' or 'format2' directly to be explicit about which format to download.", + description="The default is 'export', which is meant to be used with workflow import endpoints. Other formats such as 'instance', 'editor', 'run' are tied to the GUI and should not be considered stable APIs. The default format for 'export' is specified by the admin with the `default_workflow_export_format` config option. Style can be specified as either 'ga' or 'format2' directly to be explicit about which format to download.", ), ] From dcf005e7094c2d9fd81a0d0fb35b8423307af45e Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Thu, 23 May 2024 15:20:02 +0200 Subject: [PATCH 60/89] Remove the description from fields, where the description equals to TODO --- lib/galaxy/schema/workflows.py | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/lib/galaxy/schema/workflows.py b/lib/galaxy/schema/workflows.py index a2f14c5b5fc3..6956e909a38f 100644 --- a/lib/galaxy/schema/workflows.py +++ b/lib/galaxy/schema/workflows.py @@ -68,7 +68,6 @@ class InputConnection(Model): input_subworkflow_step_id: Optional[int] = Field( None, title="Input Subworkflow Step ID", - description="TODO", ) @@ -166,7 +165,6 @@ class ToolShedRepositorySummary(Model): changeset_revision: str = Field( ..., title="Changeset Revision", - description="TODO", ) tool_shed: str = Field( ..., @@ -204,7 +202,6 @@ class StepIn(Model): default: Any = Field( ..., title="Default", - description="TODO", ) @@ -253,7 +250,6 @@ class InvokeWorkflowPayload(GetTargetHistoryPayload): True, title="Require Exact Tool Versions", description="If true, exact tool versions are required for workflow invocation.", - # description="TODO", ) allow_tool_state_corrections: Optional[bool] = Field( False, @@ -295,27 +291,22 @@ def inputs_string_to_json(cls, v): inputs: Optional[Dict[str, Any]] = Field( None, title="Inputs", - description="TODO", ) ds_map: Optional[Dict[str, Dict[str, Any]]] = Field( {}, title="Dataset Map", - description="TODO", ) resource_params: Optional[Dict[str, Any]] = Field( {}, title="Resource Parameters", - description="TODO", ) replacement_params: Optional[Dict[str, Any]] = Field( {}, title="Replacement Parameters", - description="TODO", ) step_parameters: Optional[Dict[str, Any]] = Field( None, title="Step Parameters", - description="TODO", ) no_add_to_history: Optional[bool] = Field( False, @@ -337,7 +328,6 @@ def inputs_string_to_json(cls, v): None, title="Effective Outputs", # lib/galaxy/workflow/run_request.py - see line 455 - description="TODO", ) preferred_intermediate_object_store_id: Optional[str] = Field( None, @@ -815,7 +805,7 @@ class WorkflowDictExportStep(WorkflowDictStepsExtendedBase): title="Inputs", description="The inputs of the step.", ) - in_parameter: Optional[Dict[str, StepIn]] = Field(None, title="In", description="TODO", alias="in") + in_parameter: Optional[Dict[str, StepIn]] = Field(None, title="In", alias="in") input_connections: Optional[Dict[str, Union[InputConnection, List[InputConnection]]]] = Field( None, title="Input Connections", From 523ab4c3f87c65836d3d1bbb9a1ea1773deb6d49 Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Thu, 23 May 2024 17:04:07 +0200 Subject: [PATCH 61/89] Limit type of field x and y fields in WorkflowStepLayoutPosition to integer --- lib/galaxy/schema/workflows.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/galaxy/schema/workflows.py b/lib/galaxy/schema/workflows.py index 6956e909a38f..8a71a0fa027d 100644 --- a/lib/galaxy/schema/workflows.py +++ b/lib/galaxy/schema/workflows.py @@ -94,12 +94,12 @@ class WorkflowStepLayoutPosition(Model): title="Right", description="Right margin or right-most position of the box.", ) - x: Optional[Union[int, float]] = Field( + x: Optional[int] = Field( None, title="X", description="Horizontal coordinate of the top right corner of the box.", ) - y: Optional[Union[int, float]] = Field( + y: Optional[int] = Field( None, title="Y", description="Vertical coordinate of the top right corner of the box.", From 22638bab3db3882da20718b2058de54eb32884cb Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Wed, 20 Mar 2024 23:33:29 +0100 Subject: [PATCH 62/89] Regenerate the client schema --- client/src/api/schema/schema.ts | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/client/src/api/schema/schema.ts b/client/src/api/schema/schema.ts index 8c74d93e5ff0..55ce36f6ea40 100644 --- a/client/src/api/schema/schema.ts +++ b/client/src/api/schema/schema.ts @@ -33729,14 +33729,7 @@ export interface operations { /** @description Successful Response */ 200: { content: { - "application/json": - | components["schemas"]["WorkflowDictEditorSummary"] - | components["schemas"]["StoredWorkflowDetailed"] - | components["schemas"]["WorkflowDictRunSummary"] - | components["schemas"]["WorkflowDictPreviewSummary"] - | components["schemas"]["WorkflowDictFormat2Summary"] - | components["schemas"]["WorkflowDictExportSummary"] - | components["schemas"]["WorkflowDictFormat2WrappedYamlSummary"]; + "application/json": Record; }; }; /** @description Validation Error */ From 4cac26ec4fa28d641efa1fc9121cc6f386cbff89 Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Fri, 12 Apr 2024 17:19:32 +0200 Subject: [PATCH 63/89] Refactor the update operation --- lib/galaxy/webapps/galaxy/api/workflows.py | 164 +++------------------ 1 file changed, 17 insertions(+), 147 deletions(-) diff --git a/lib/galaxy/webapps/galaxy/api/workflows.py b/lib/galaxy/webapps/galaxy/api/workflows.py index 9ff3aff99eee..59fe8df066cd 100644 --- a/lib/galaxy/webapps/galaxy/api/workflows.py +++ b/lib/galaxy/webapps/galaxy/api/workflows.py @@ -32,7 +32,6 @@ from galaxy import ( exceptions, - model, util, ) from galaxy.files.uris import ( @@ -44,11 +43,9 @@ ProvidesUserContext, ) from galaxy.managers.workflows import ( - MissingToolsException, RefactorRequest, RefactorResponse, WorkflowCreateOptions, - WorkflowUpdateOptions, ) from galaxy.model.base import transaction from galaxy.model.item_attrs import UsesAnnotations @@ -88,22 +85,20 @@ WorkflowDictFormat2WrappedYamlSummary, WorkflowDictPreviewSummary, WorkflowDictRunSummary, + WorkflowUpdatePayload, ) from galaxy.structured_app import StructuredApp from galaxy.tool_shed.galaxy_install.install_manager import InstallRepositoryManager from galaxy.tools import recommendations from galaxy.tools.parameters import populate_state from galaxy.tools.parameters.workflow_utils import workflow_building_modes -<<<<<<< HEAD +from galaxy.util.sanitize_html import sanitize_html +from galaxy.version import VERSION from galaxy.web import ( expose_api, expose_api_raw_anonymous_and_sessionless, format_return_as_json, ) -======= -from galaxy.util.sanitize_html import sanitize_html -from galaxy.web import expose_api ->>>>>>> Remove unused imports from galaxy.webapps.base.controller import ( SharableMixin, url_for, @@ -308,145 +303,6 @@ def import_new_workflow_deprecated(self, trans: GalaxyWebTransaction, payload, * """ return self.__api_import_new_workflow(trans, payload, **kwd) - @expose_api - def update(self, trans: GalaxyWebTransaction, id, payload, **kwds): - """ - PUT /api/workflows/{id} - - Update the workflow stored with ``id``. - - :type id: str - :param id: the encoded id of the workflow to update - :param instance: true if fetch by Workflow ID instead of StoredWorkflow id, false by default. - :type instance: boolean - :type payload: dict - :param payload: a dictionary containing any or all the - - :workflow: - - the json description of the workflow as would be - produced by GET workflows//download or - given to `POST workflows` - - The workflow contents will be updated to target this. - - :name: - - optional string name for the workflow, if not present in payload, - name defaults to existing name - - :annotation: - - optional string annotation for the workflow, if not present in payload, - annotation defaults to existing annotation - - :menu_entry: - - optional boolean marking if the workflow should appear in the user\'s menu, - if not present, workflow menu entries are not modified - - :tags: - - optional list containing list of tags to add to the workflow (overwriting - existing tags), if not present, tags are not modified - - :from_tool_form: - - True iff encoded state coming in is encoded for the tool form. - - - :rtype: dict - :returns: serialized version of the workflow - """ - stored_workflow = self.__get_stored_workflow(trans, id, **kwds) - workflow_dict = payload.get("workflow", {}) - workflow_dict.update({k: v for k, v in payload.items() if k not in workflow_dict}) - if workflow_dict: - require_flush = False - raw_workflow_description = self.__normalize_workflow(trans, workflow_dict) - workflow_dict = raw_workflow_description.as_dict - new_workflow_name = workflow_dict.get("name") - old_workflow = stored_workflow.latest_workflow - name_updated = new_workflow_name and new_workflow_name != stored_workflow.name - steps_updated = "steps" in workflow_dict - if name_updated and not steps_updated: - sanitized_name = new_workflow_name or old_workflow.name - if not sanitized_name: - raise exceptions.MessageException("Workflow must have a valid name.") - workflow = old_workflow.copy(user=trans.user) - workflow.stored_workflow = stored_workflow - workflow.name = sanitized_name - stored_workflow.name = sanitized_name - stored_workflow.latest_workflow = workflow - trans.sa_session.add(workflow, stored_workflow) - require_flush = True - - if "hidden" in workflow_dict and stored_workflow.hidden != workflow_dict["hidden"]: - stored_workflow.hidden = workflow_dict["hidden"] - require_flush = True - - if "published" in workflow_dict and stored_workflow.published != workflow_dict["published"]: - stored_workflow.published = workflow_dict["published"] - require_flush = True - - if "importable" in workflow_dict and stored_workflow.importable != workflow_dict["importable"]: - stored_workflow.importable = workflow_dict["importable"] - require_flush = True - - if "annotation" in workflow_dict and not steps_updated: - newAnnotation = workflow_dict["annotation"] - self.add_item_annotation(trans.sa_session, trans.user, stored_workflow, newAnnotation) - require_flush = True - - if "menu_entry" in workflow_dict or "show_in_tool_panel" in workflow_dict: - show_in_panel = workflow_dict.get("menu_entry") or workflow_dict.get("show_in_tool_panel") - stored_workflow_menu_entries = trans.user.stored_workflow_menu_entries - decoded_id = trans.security.decode_id(id) - if show_in_panel: - workflow_ids = [wf.stored_workflow_id for wf in stored_workflow_menu_entries] - if decoded_id not in workflow_ids: - menu_entry = model.StoredWorkflowMenuEntry() - menu_entry.stored_workflow = stored_workflow - stored_workflow_menu_entries.append(menu_entry) - trans.sa_session.add(menu_entry) - require_flush = True - else: - # remove if in list - entries = {x.stored_workflow_id: x for x in stored_workflow_menu_entries} - if decoded_id in entries: - stored_workflow_menu_entries.remove(entries[decoded_id]) - require_flush = True - # set tags - if "tags" in workflow_dict: - trans.tag_handler.set_tags_from_list( - user=trans.user, - item=stored_workflow, - new_tags_list=workflow_dict["tags"], - ) - - if require_flush: - with transaction(trans.sa_session): - trans.sa_session.commit() - - if "steps" in workflow_dict or "comments" in workflow_dict: - try: - workflow_update_options = WorkflowUpdateOptions(**payload) - workflow, errors = self.workflow_contents_manager.update_workflow_from_raw_description( - trans, - stored_workflow, - raw_workflow_description, - workflow_update_options, - ) - except MissingToolsException: - raise exceptions.MessageException( - "This workflow contains missing tools. It cannot be saved until they have been removed from the workflow or installed." - ) - - else: - message = "Updating workflow requires dictionary containing 'workflow' attribute with new JSON description." - raise exceptions.RequestParameterInvalidException(message) - return self.workflow_contents_manager.workflow_to_dict(trans, stored_workflow, style="instance") - @expose_api def build_module(self, trans: GalaxyWebTransaction, payload=None): """ @@ -1031,6 +887,20 @@ def set_slug( self.service.shareable_service.set_slug(trans, workflow_id, payload) return Response(status_code=status.HTTP_204_NO_CONTENT) + @router.put( + "/api/workflows/{workflow_id}", + summary="Update the workflow stored with the ``id``", + name="update_workflow", + ) + def update( + self, + workflow_id: StoredWorkflowIDPathParam, + payload: WorkflowUpdatePayload, + instance: InstanceQueryParam = False, + trans: ProvidesHistoryContext = DependsOnTrans, + ): + return self.service.update_workflow(trans, payload, instance, workflow_id) + @router.delete( "/api/workflows/{workflow_id}", summary="Add the deleted flag to a workflow.", From 78067bb24eaacd2557d4b6456729d039dbc3dc44 Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Fri, 12 Apr 2024 17:20:04 +0200 Subject: [PATCH 64/89] Add pydantic model for payload update operation --- lib/galaxy/schema/workflows.py | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/lib/galaxy/schema/workflows.py b/lib/galaxy/schema/workflows.py index 8a71a0fa027d..14bc0864638a 100644 --- a/lib/galaxy/schema/workflows.py +++ b/lib/galaxy/schema/workflows.py @@ -1029,3 +1029,34 @@ class WorkflowDictFormat2WrappedYamlSummary(Model): # description="Safe and ordered dump of YAML to stream", description="The content of the workflow in YAML .", ) + + +class WorkflowUpdatePayload(Model): + workflow: Any = Field( + ..., + title="Workflow", + description="The json description of the workflow as would be produced by GET workflows//download or given to `POST workflows`", + ) + name: Optional[str] = Field( + None, + title="Name", + description="String name for the workflow, if not present in payload, name defaults to existing name", + ) + annotation: Optional[str] = Field( + None, + title="Annotation", + description="String annotation for the workflow, if not present in payload, annotation defaults to existing annotation", + ) + menu_entry: Optional[bool] = Field( + None, + title="Menu Entry", + description="Boolean marking if the workflow should appear in the user's menu, if not present, workflow menu entries are not modified", + ) + tags: Optional[List[str]] = Field( + None, + title="Tags", + description="List containing list of tags to add to the workflow (overwriting existing tags), if not present, tags are not modified", + ) + from_tool_form: Optional[bool] = Field( + None, title="From Tool Form", description="True iff encoded state coming in is encoded for the tool form." + ) From 469f21afe5908d5be6dcbb69597c85c4dc55da08 Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Fri, 12 Apr 2024 17:20:24 +0200 Subject: [PATCH 65/89] Remove the mapping to the legacy route --- lib/galaxy/webapps/galaxy/buildapp.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/lib/galaxy/webapps/galaxy/buildapp.py b/lib/galaxy/webapps/galaxy/buildapp.py index 8c75e4aee4e3..cb2237decb7d 100644 --- a/lib/galaxy/webapps/galaxy/buildapp.py +++ b/lib/galaxy/webapps/galaxy/buildapp.py @@ -670,12 +670,6 @@ def populate_api_routes(webapp, app): # action="import_tool_version", # conditions=dict(method=["POST"]), # ) - webapp.mapper.connect( - "/api/workflows/{encoded_workflow_id}", - controller="workflows", - action="update", - conditions=dict(method=["PUT"]), - ) webapp.mapper.connect( "/api/workflows", controller="workflows", From 3eab46f5b5a9d0771be4edc92801a2c7f3c0b53f Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Fri, 12 Apr 2024 17:21:02 +0200 Subject: [PATCH 66/89] Add method for update operation from Workflows API --- .../webapps/galaxy/services/workflows.py | 103 ++++++++++++++++++ 1 file changed, 103 insertions(+) diff --git a/lib/galaxy/webapps/galaxy/services/workflows.py b/lib/galaxy/webapps/galaxy/services/workflows.py index cfacfd756bb8..524322bfdbcb 100644 --- a/lib/galaxy/webapps/galaxy/services/workflows.py +++ b/lib/galaxy/webapps/galaxy/services/workflows.py @@ -23,13 +23,16 @@ ) from galaxy.managers.histories import HistoryManager from galaxy.managers.workflows import ( + MissingToolsException, RefactorResponse, WorkflowContentsManager, WorkflowSerializer, WorkflowsManager, + WorkflowUpdateOptions, ) from galaxy.model import StoredWorkflow from galaxy.model.base import transaction +from galaxy.model.item_attrs import UsesAnnotations from galaxy.schema.invocation import WorkflowInvocationResponse from galaxy.schema.schema import ( InvocationsStateCounts, @@ -46,7 +49,9 @@ WorkflowDictFormat2WrappedYamlSummary, WorkflowDictPreviewSummary, WorkflowDictRunSummary, + WorkflowUpdatePayload, ) +from galaxy.util.sanitize_html import sanitize_html from galaxy.util.tool_shed.tool_shed_registry import Registry from galaxy.webapps.galaxy.services.base import ServiceBase from galaxy.webapps.galaxy.services.notifications import NotificationService @@ -70,6 +75,7 @@ def __init__( tool_shed_registry: Registry, notification_service: NotificationService, history_manager: HistoryManager, + uses_annotations: UsesAnnotations, ): self._workflows_manager = workflows_manager self._workflow_contents_manager = workflow_contents_manager @@ -77,6 +83,7 @@ def __init__( self.shareable_service = ShareableService(workflows_manager, serializer, notification_service) self._tool_shed_registry = tool_shed_registry self._history_manager = history_manager + self._uses_annotations = uses_annotations def download_workflow(self, trans, workflow_id, history_id, style, format, version, instance): stored_workflow = self._workflows_manager.get_stored_accessible_workflow( @@ -354,3 +361,99 @@ def __get_full_shed_url(self, url): if url in shed_url: return shed_url return None + + def update_workflow( + self, + trans: ProvidesHistoryContext, + payload: WorkflowUpdatePayload, + instance: Optional[bool], + workflow_id: int, + ): + stored_workflow = self._workflows_manager.get_stored_workflow(trans, workflow_id, by_stored_id=not instance) + workflow_dict = payload.model_dump(exclude_unset=True) + if workflow_dict: + require_flush = False + raw_workflow_description = self._workflow_contents_manager.normalize_workflow_format(trans, workflow_dict) + workflow_dict = raw_workflow_description.as_dict + new_workflow_name = workflow_dict.get("name") + old_workflow = stored_workflow.latest_workflow + name_updated = new_workflow_name and new_workflow_name != stored_workflow.name + steps_updated = "steps" in workflow_dict + if name_updated and not steps_updated: + sanitized_name = sanitize_html(new_workflow_name or old_workflow.name) + if not sanitized_name: + raise exceptions.MessageException("Workflow must have a valid name.") + workflow = old_workflow.copy(user=trans.user) + workflow.stored_workflow = stored_workflow + workflow.name = sanitized_name + stored_workflow.name = sanitized_name + stored_workflow.latest_workflow = workflow + trans.sa_session.add(workflow, stored_workflow) + require_flush = True + + if "hidden" in workflow_dict and stored_workflow.hidden != workflow_dict["hidden"]: + stored_workflow.hidden = workflow_dict["hidden"] + require_flush = True + + if "published" in workflow_dict and stored_workflow.published != workflow_dict["published"]: + stored_workflow.published = workflow_dict["published"] + require_flush = True + + if "importable" in workflow_dict and stored_workflow.importable != workflow_dict["importable"]: + stored_workflow.importable = workflow_dict["importable"] + require_flush = True + + if "annotation" in workflow_dict and not steps_updated: + newAnnotation = sanitize_html(workflow_dict["annotation"]) + self._uses_annotations.add_item_annotation(trans.sa_session, trans.user, stored_workflow, newAnnotation) + require_flush = True + + if "menu_entry" in workflow_dict or "show_in_tool_panel" in workflow_dict: + show_in_panel = workflow_dict.get("menu_entry") or workflow_dict.get("show_in_tool_panel") + stored_workflow_menu_entries = trans.user.stored_workflow_menu_entries + if show_in_panel: + workflow_ids = [wf.stored_workflow_id for wf in stored_workflow_menu_entries] + if workflow_id not in workflow_ids: + menu_entry = model.StoredWorkflowMenuEntry() + menu_entry.stored_workflow = stored_workflow + stored_workflow_menu_entries.append(menu_entry) + trans.sa_session.add(menu_entry) + require_flush = True + else: + # remove if in list + entries = {x.stored_workflow_id: x for x in stored_workflow_menu_entries} + if workflow_id in entries: + stored_workflow_menu_entries.remove(entries[workflow_id]) + require_flush = True + # set tags + if "tags" in workflow_dict: + trans.tag_handler.set_tags_from_list( + user=trans.user, + item=stored_workflow, + new_tags_list=workflow_dict["tags"], + ) + + if require_flush: + with transaction(trans.sa_session): + trans.sa_session.commit() + + if "steps" in workflow_dict or "comments" in workflow_dict: + try: + workflow_update_options = WorkflowUpdateOptions(**payload.model_dump(exclude_unset=True)) + workflow, errors = self._workflow_contents_manager.update_workflow_from_raw_description( + trans, + stored_workflow, + raw_workflow_description, + workflow_update_options, + ) + except MissingToolsException: + raise exceptions.MessageException( + "This workflow contains missing tools. It cannot be saved until they have been removed from the workflow or installed." + ) + + else: + message = "Updating workflow requires dictionary containing 'workflow' attribute with new JSON description." + raise exceptions.RequestParameterInvalidException(message) + return StoredWorkflowDetailed( + **self._workflow_contents_manager.workflow_to_dict(trans, stored_workflow, style="instance") + ) From 051de86cfe78e141bda3da6ef03c10e4364dfc9f Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Fri, 12 Apr 2024 17:25:57 +0200 Subject: [PATCH 67/89] Add pydantic model for create operation --- lib/galaxy/schema/workflows.py | 78 ++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/lib/galaxy/schema/workflows.py b/lib/galaxy/schema/workflows.py index 14bc0864638a..2ac369ecbeff 100644 --- a/lib/galaxy/schema/workflows.py +++ b/lib/galaxy/schema/workflows.py @@ -1060,3 +1060,81 @@ class WorkflowUpdatePayload(Model): from_tool_form: Optional[bool] = Field( None, title="From Tool Form", description="True iff encoded state coming in is encoded for the tool form." ) + + +class WorkflowCreatePayload(Model): + archive_file: Optional[Any] = Field( + None, + title="Archive File", + description="A file containing a workflow archive to be imported.", + ) + archive_source: Optional[str] = Field( + None, + title="Archive Source", + description="A URL or file path pointing to a workflow archive to be imported.", + ) + from_history_id: Optional[str] = Field( + None, + title="From History ID", + description="The ID of a history from which to extract a workflow.", + ) + job_ids: Optional[List[str]] = Field( + None, + title="Job IDs", + description="If from_history_id is set, this is an optional list of job IDs to include when extracting a workflow from history.", + ) + dataset_ids: Optional[List[str]] = Field( + None, + title="Dataset IDs", + description="If from_history_id is set, this is an optional list of HDA 'hid's corresponding to workflow inputs when extracting a workflow from history.", + ) + dataset_collection_ids: Optional[List[str]] = Field( + None, + title="Dataset Collection IDs", + description="If from_history_id is set, this is an optional list of HDCA 'hid's corresponding to workflow inputs when extracting a workflow from history.", + ) + workflow_name: Optional[str] = Field( + None, + title="Workflow Name", + description="If from_history_id is set, this is the name of the workflow to create when extracting a workflow from history.", + ) + from_path: Optional[str] = Field( + None, + title="From Path", + description="A path from which to import a workflow.", + ) + object_id: Optional[str] = Field( + None, + title="Object ID", + description="If from_path is set, this is an optional object ID to include when importing a workflow from a path.", + ) + shared_workflow_id: Optional[str] = Field( + None, + title="Shared Workflow ID", + description="The ID of a shared workflow to import.", + ) + workflow: Optional[Dict[str, Any]] = Field( + None, + title="Workflow", + description="A dictionary containing information about a new workflow to import.", + ) + trs_url: Optional[str] = Field( + None, + title="TRS URL", + description="If archive_source is set to 'trs_tool', this is the URL of the Tool Registry Service (TRS) from which to import a workflow.", + ) + trs_server: Optional[str] = Field( + None, + title="TRS Server", + description="If archive_source is set to 'trs_tool', this is the server of the Tool Registry Service (TRS) from which to import a workflow.", + ) + trs_tool_id: Optional[str] = Field( + None, + title="TRS Tool ID", + description="If archive_source is set to 'trs_tool', this is the ID of the tool in the Tool Registry Service (TRS) from which to import a workflow.", + ) + trs_version_id: Optional[str] = Field( + None, + title="TRS Version ID", + description="If archive_source is set to 'trs_tool', this is the version ID of the tool in the Tool Registry Service (TRS) from which to import a workflow.", + ) From a81a69d92251adaccf5c7a41322cfaf6e14d5f2b Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Tue, 7 May 2024 17:17:22 +0200 Subject: [PATCH 68/89] Remove unused imports --- lib/galaxy/webapps/galaxy/api/workflows.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/lib/galaxy/webapps/galaxy/api/workflows.py b/lib/galaxy/webapps/galaxy/api/workflows.py index 59fe8df066cd..ff3b6719d759 100644 --- a/lib/galaxy/webapps/galaxy/api/workflows.py +++ b/lib/galaxy/webapps/galaxy/api/workflows.py @@ -92,13 +92,7 @@ from galaxy.tools import recommendations from galaxy.tools.parameters import populate_state from galaxy.tools.parameters.workflow_utils import workflow_building_modes -from galaxy.util.sanitize_html import sanitize_html -from galaxy.version import VERSION -from galaxy.web import ( - expose_api, - expose_api_raw_anonymous_and_sessionless, - format_return_as_json, -) +from galaxy.web import expose_api from galaxy.webapps.base.controller import ( SharableMixin, url_for, From 8e3d21bcb072932058ee9db5017523bb4daa4fd1 Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Fri, 10 May 2024 10:25:06 +0200 Subject: [PATCH 69/89] Add pydantic model to return of update operation --- lib/galaxy/webapps/galaxy/api/workflows.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/galaxy/webapps/galaxy/api/workflows.py b/lib/galaxy/webapps/galaxy/api/workflows.py index ff3b6719d759..2e9c59b125d3 100644 --- a/lib/galaxy/webapps/galaxy/api/workflows.py +++ b/lib/galaxy/webapps/galaxy/api/workflows.py @@ -892,7 +892,7 @@ def update( payload: WorkflowUpdatePayload, instance: InstanceQueryParam = False, trans: ProvidesHistoryContext = DependsOnTrans, - ): + ) -> StoredWorkflowDetailed: return self.service.update_workflow(trans, payload, instance, workflow_id) @router.delete( From 341ee157e6c9cb899ef8f8f7056e0e2921f868b7 Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Fri, 10 May 2024 11:10:00 +0200 Subject: [PATCH 70/89] Fix creating worfklow_dict in the service method of update operation --- lib/galaxy/webapps/galaxy/services/workflows.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/galaxy/webapps/galaxy/services/workflows.py b/lib/galaxy/webapps/galaxy/services/workflows.py index 524322bfdbcb..051281004efa 100644 --- a/lib/galaxy/webapps/galaxy/services/workflows.py +++ b/lib/galaxy/webapps/galaxy/services/workflows.py @@ -370,7 +370,9 @@ def update_workflow( workflow_id: int, ): stored_workflow = self._workflows_manager.get_stored_workflow(trans, workflow_id, by_stored_id=not instance) - workflow_dict = payload.model_dump(exclude_unset=True) + payload_dict = payload.model_dump(exclude_unset=True) + workflow_dict = payload_dict.get("workflow", {}) + workflow_dict.update({k: v for k, v in payload_dict.items() if k not in workflow_dict}) if workflow_dict: require_flush = False raw_workflow_description = self._workflow_contents_manager.normalize_workflow_format(trans, workflow_dict) @@ -439,7 +441,7 @@ def update_workflow( if "steps" in workflow_dict or "comments" in workflow_dict: try: - workflow_update_options = WorkflowUpdateOptions(**payload.model_dump(exclude_unset=True)) + workflow_update_options = WorkflowUpdateOptions(**payload_dict) workflow, errors = self._workflow_contents_manager.update_workflow_from_raw_description( trans, stored_workflow, From 577aa151872267cf4142d1f7f69c03f01b9e00c9 Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Fri, 10 May 2024 22:07:19 +0200 Subject: [PATCH 71/89] Add missing fields to payload of update operation --- lib/galaxy/schema/workflows.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/lib/galaxy/schema/workflows.py b/lib/galaxy/schema/workflows.py index 2ac369ecbeff..27ad12f90a25 100644 --- a/lib/galaxy/schema/workflows.py +++ b/lib/galaxy/schema/workflows.py @@ -1032,25 +1032,25 @@ class WorkflowDictFormat2WrappedYamlSummary(Model): class WorkflowUpdatePayload(Model): - workflow: Any = Field( - ..., + workflow: Optional[Any] = Field( + None, title="Workflow", - description="The json description of the workflow as would be produced by GET workflows//download or given to `POST workflows`", + description="The json description of the workflow as would be produced by GET workflows//download or given to `POST workflows`. The workflow contents will be updated to target this.", ) name: Optional[str] = Field( None, title="Name", - description="String name for the workflow, if not present in payload, name defaults to existing name", + description="Name for the workflow, if not present in payload, name defaults to existing name", ) annotation: Optional[str] = Field( None, title="Annotation", - description="String annotation for the workflow, if not present in payload, annotation defaults to existing annotation", + description="Annotation for the workflow, if not present in payload, annotation defaults to existing annotation", ) menu_entry: Optional[bool] = Field( None, title="Menu Entry", - description="Boolean marking if the workflow should appear in the user's menu, if not present, workflow menu entries are not modified", + description="Flag indicating if the workflow should appear in the user's menu, if not present, workflow menu entries are not modified", ) tags: Optional[List[str]] = Field( None, @@ -1060,6 +1060,12 @@ class WorkflowUpdatePayload(Model): from_tool_form: Optional[bool] = Field( None, title="From Tool Form", description="True iff encoded state coming in is encoded for the tool form." ) + published: Optional[bool] = Field( + None, + ) + importable: Optional[bool] = Field( + None, + ) class WorkflowCreatePayload(Model): From e09ed1cb2f990d3007b863a82c709ec00bc1a9a5 Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Sat, 11 May 2024 16:56:41 +0200 Subject: [PATCH 72/89] Change instance that will be passed to sa_session via add in service method of update operation --- lib/galaxy/webapps/galaxy/services/workflows.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/galaxy/webapps/galaxy/services/workflows.py b/lib/galaxy/webapps/galaxy/services/workflows.py index 051281004efa..25918d02beab 100644 --- a/lib/galaxy/webapps/galaxy/services/workflows.py +++ b/lib/galaxy/webapps/galaxy/services/workflows.py @@ -390,7 +390,12 @@ def update_workflow( workflow.name = sanitized_name stored_workflow.name = sanitized_name stored_workflow.latest_workflow = workflow - trans.sa_session.add(workflow, stored_workflow) + + # TODO MyPy complains about this line, but it seems to be working + # trans.sa_session.add(workflow, stored_workflow) + # TODO: This also appears to work. Is it better? + trans.sa_session.add(workflow) + require_flush = True if "hidden" in workflow_dict and stored_workflow.hidden != workflow_dict["hidden"]: From c2c15222724ea17f9e7928d5b3b30983921f7dbe Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Tue, 14 May 2024 21:58:56 +0200 Subject: [PATCH 73/89] Add json key word to tests --- lib/galaxy_test/api/test_workflows.py | 18 ++++++++++-------- lib/galaxy_test/base/populators.py | 2 +- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/lib/galaxy_test/api/test_workflows.py b/lib/galaxy_test/api/test_workflows.py index 0a9de8ba0e78..1a7fd67e4b27 100644 --- a/lib/galaxy_test/api/test_workflows.py +++ b/lib/galaxy_test/api/test_workflows.py @@ -789,9 +789,11 @@ def __test_upload( data["import_tools"] = import_tools if use_deprecated_route: route = "workflows/upload" + upload_response = self._post(route, data=data) else: route = "workflows" - upload_response = self._post(route, data=data) + upload_response = self._post(route, data=data, json=True) + # upload_response = self._post(route, data=data) if assert_ok: self._assert_status_code_is(upload_response, 200) self._assert_user_has_workflow_with_name(name) @@ -1149,7 +1151,7 @@ def test_not_importable_prevents_import(self): def test_url_import(self): url = "https://raw.githubusercontent.com/galaxyproject/galaxy/release_19.09/test/base/data/test_workflow_1.ga" - workflow_id = self._post("workflows", data={"archive_source": url}).json()["id"] + workflow_id = self._post("workflows", data={"archive_source": url}, json=True).json()["id"] workflow = self._download_workflow(workflow_id) assert "TestWorkflow1" in workflow["name"] assert ( @@ -1158,7 +1160,7 @@ def test_url_import(self): def test_base64_import(self): base64_url = "base64://" + base64.b64encode(workflow_str.encode("utf-8")).decode("utf-8") - response = self._post("workflows", data={"archive_source": base64_url}) + response = self._post("workflows", data={"archive_source": base64_url}, json=True) response.raise_for_status() workflow_id = response.json()["id"] workflow = self._download_workflow(workflow_id) @@ -1198,7 +1200,7 @@ def test_trs_import_from_dockstore_trs_url(self): "%23workflow%2Fgithub.com%2Fjmchilton%2Fgalaxy-workflow-dockstore-example-1%2Fmycoolworkflow/" "versions/master", } - workflow_id = self._post("workflows", data=trs_payload).json()["id"] + workflow_id = self._post("workflows", data=trs_payload, json=True).json()["id"] original_workflow = self._download_workflow(workflow_id) assert "Test Workflow" in original_workflow["name"] assert ( @@ -1231,7 +1233,7 @@ def test_trs_import_from_workflowhub_trs_url(self): "archive_source": "trs_tool", "trs_url": "https://workflowhub.eu/ga4gh/trs/v2/tools/109/versions/5", } - workflow_id = self._post("workflows", data=trs_payload).json()["id"] + workflow_id = self._post("workflows", data=trs_payload, json=True).json()["id"] original_workflow = self._download_workflow(workflow_id) assert "COVID-19: variation analysis reporting" in original_workflow["name"] assert original_workflow.get("source_metadata").get("trs_tool_id") == "109" @@ -5424,13 +5426,13 @@ def _step_map(self, workflow): return step_map def test_empty_create(self): - response = self._post("workflows") + response = self._post("workflows", json=True) self._assert_status_code_is(response, 400) self._assert_error_code_is(response, error_codes.error_codes_by_name["USER_REQUEST_MISSING_PARAMETER"]) def test_invalid_create_multiple_types(self): data = {"shared_workflow_id": "1234567890abcdef", "from_history_id": "1234567890abcdef"} - response = self._post("workflows", data) + response = self._post("workflows", data=data, json=True) self._assert_status_code_is(response, 400) self._assert_error_code_is(response, error_codes.error_codes_by_name["USER_REQUEST_INVALID_PARAMETER"]) @@ -7390,7 +7392,7 @@ def test_workflow_from_path_requires_admin(self): path_as_uri = f"file://{workflow_path}" import_data = dict(archive_source=path_as_uri) - import_response = self._post("workflows", data=import_data) + import_response = self._post("workflows", data=import_data, json=True) self._assert_status_code_is(import_response, 403) self._assert_error_code_is(import_response, error_codes.error_codes_by_name["ADMIN_REQUIRED"]) finally: diff --git a/lib/galaxy_test/base/populators.py b/lib/galaxy_test/base/populators.py index 1104e94b1dbf..ccf1908ea1be 100644 --- a/lib/galaxy_test/base/populators.py +++ b/lib/galaxy_test/base/populators.py @@ -1735,7 +1735,7 @@ def import_workflow_from_path_raw(self, from_path: str, object_id: Optional[str] from_path=from_path, object_id=object_id, ) - import_response = self._post("workflows", data=data) + import_response = self._post("workflows", data=data, json=True) return import_response def import_workflow_from_path(self, from_path: str, object_id: Optional[str] = None) -> str: From 6bd134c107357ae0a245214e1219497e559f07a8 Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Tue, 14 May 2024 22:01:46 +0200 Subject: [PATCH 74/89] Extend the payload model of the create oepration --- lib/galaxy/schema/workflows.py | 42 ++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/lib/galaxy/schema/workflows.py b/lib/galaxy/schema/workflows.py index 27ad12f90a25..a582a2595a51 100644 --- a/lib/galaxy/schema/workflows.py +++ b/lib/galaxy/schema/workflows.py @@ -1069,16 +1069,7 @@ class WorkflowUpdatePayload(Model): class WorkflowCreatePayload(Model): - archive_file: Optional[Any] = Field( - None, - title="Archive File", - description="A file containing a workflow archive to be imported.", - ) - archive_source: Optional[str] = Field( - None, - title="Archive Source", - description="A URL or file path pointing to a workflow archive to be imported.", - ) + # TODO - Description comes from previous endpoint from_history_id: Optional[str] = Field( None, title="From History ID", @@ -1104,11 +1095,25 @@ class WorkflowCreatePayload(Model): title="Workflow Name", description="If from_history_id is set, this is the name of the workflow to create when extracting a workflow from history.", ) + # TODO - New descriptions added by me + archive_file: Optional[Any] = Field( + None, + title="Archive File", + description="A file containing a workflow archive to be imported.", + ) + archive_source: Optional[str] = Field( + None, + title="Archive Source", + description="A URL or file path pointing to a workflow archive to be imported.", + ) from_path: Optional[str] = Field( None, title="From Path", description="A path from which to import a workflow.", ) + import_tools: Optional[bool] = Field( + None, + ) object_id: Optional[str] = Field( None, title="Object ID", @@ -1119,11 +1124,6 @@ class WorkflowCreatePayload(Model): title="Shared Workflow ID", description="The ID of a shared workflow to import.", ) - workflow: Optional[Dict[str, Any]] = Field( - None, - title="Workflow", - description="A dictionary containing information about a new workflow to import.", - ) trs_url: Optional[str] = Field( None, title="TRS URL", @@ -1144,3 +1144,15 @@ class WorkflowCreatePayload(Model): title="TRS Version ID", description="If archive_source is set to 'trs_tool', this is the version ID of the tool in the Tool Registry Service (TRS) from which to import a workflow.", ) + workflow: Optional[Dict[str, Any]] = Field( + None, + title="Workflow", + description="A dictionary containing information about a new workflow to import.", + ) + + @field_validator("workflow", mode="before") + @classmethod + def decode_json(cls, v): + if isinstance(v, str): + return json.loads(v) + return v From 2b601708dca350c320705497ee5c6537ceb8364c Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Tue, 14 May 2024 22:06:53 +0200 Subject: [PATCH 75/89] Refactor the create operation and move several helper methods to the service layer --- lib/galaxy/webapps/galaxy/api/workflows.py | 305 +---------------- .../webapps/galaxy/services/workflows.py | 319 ++++++++++++++++++ 2 files changed, 334 insertions(+), 290 deletions(-) diff --git a/lib/galaxy/webapps/galaxy/api/workflows.py b/lib/galaxy/webapps/galaxy/api/workflows.py index 2e9c59b125d3..1b71da98d467 100644 --- a/lib/galaxy/webapps/galaxy/api/workflows.py +++ b/lib/galaxy/webapps/galaxy/api/workflows.py @@ -2,9 +2,7 @@ API operations for Workflows """ -import json import logging -import os from io import BytesIO from typing import ( Any, @@ -21,8 +19,6 @@ Response, status, ) -from gxformat2.yaml import ordered_dump -from markupsafe import escape from pydantic import ( UUID1, UUID4, @@ -34,10 +30,6 @@ exceptions, util, ) -from galaxy.files.uris import ( - stream_url_to_str, - validate_uri_access, -) from galaxy.managers.context import ( ProvidesHistoryContext, ProvidesUserContext, @@ -45,9 +37,7 @@ from galaxy.managers.workflows import ( RefactorRequest, RefactorResponse, - WorkflowCreateOptions, ) -from galaxy.model.base import transaction from galaxy.model.item_attrs import UsesAnnotations from galaxy.schema.fields import DecodedDatabaseIdField from galaxy.schema.invocation import ( @@ -79,6 +69,7 @@ SetWorkflowMenuPayload, SetWorkflowMenuSummary, StoredWorkflowDetailed, + WorkflowCreatePayload, WorkflowDictEditorSummary, WorkflowDictExportSummary, WorkflowDictFormat2Summary, @@ -88,14 +79,12 @@ WorkflowUpdatePayload, ) from galaxy.structured_app import StructuredApp -from galaxy.tool_shed.galaxy_install.install_manager import InstallRepositoryManager from galaxy.tools import recommendations from galaxy.tools.parameters import populate_state from galaxy.tools.parameters.workflow_utils import workflow_building_modes from galaxy.web import expose_api from galaxy.webapps.base.controller import ( SharableMixin, - url_for, UsesStoredWorkflowMixin, ) from galaxy.webapps.base.webapp import GalaxyWebTransaction @@ -122,7 +111,6 @@ WorkflowIndexPayload, WorkflowsService, ) -from galaxy.workflow.extract import extract_workflow from galaxy.workflow.modules import module_factory log = logging.getLogger(__name__) @@ -147,142 +135,6 @@ def __init__(self, app: StructuredApp): self.workflow_contents_manager = app.workflow_contents_manager self.tool_recommendations = recommendations.ToolRecommendations() - @expose_api - def create(self, trans: GalaxyWebTransaction, payload=None, **kwd): - """ - POST /api/workflows - - Create workflows in various ways. - - :param from_history_id: Id of history to extract a workflow from. - :type from_history_id: str - - :param job_ids: If from_history_id is set - optional list of jobs to include when extracting a workflow from history - :type job_ids: str - - :param dataset_ids: If from_history_id is set - optional list of HDA "hid"s corresponding to workflow inputs when extracting a workflow from history - :type dataset_ids: str - - :param dataset_collection_ids: If from_history_id is set - optional list of HDCA "hid"s corresponding to workflow inputs when extracting a workflow from history - :type dataset_collection_ids: str - - :param workflow_name: If from_history_id is set - name of the workflow to create when extracting a workflow from history - :type workflow_name: str - - """ - ways_to_create = { - "archive_file", - "archive_source", - "from_history_id", - "from_path", - "shared_workflow_id", - "workflow", - } - - if trans.user_is_bootstrap_admin: - raise exceptions.RealUserRequiredException("Only real users can create or run workflows.") - - if payload is None or len(ways_to_create.intersection(payload)) == 0: - message = f"One parameter among - {', '.join(ways_to_create)} - must be specified" - raise exceptions.RequestParameterMissingException(message) - - if len(ways_to_create.intersection(payload)) > 1: - message = f"Only one parameter among - {', '.join(ways_to_create)} - must be specified" - raise exceptions.RequestParameterInvalidException(message) - - if "archive_source" in payload or "archive_file" in payload: - archive_source = payload.get("archive_source") - archive_file = payload.get("archive_file") - archive_data = None - if archive_source: - validate_uri_access(archive_source, trans.user_is_admin, trans.app.config.fetch_url_allowlist_ips) - if archive_source.startswith("file://"): - workflow_src = {"src": "from_path", "path": archive_source[len("file://") :]} - payload["workflow"] = workflow_src - return self.__api_import_new_workflow(trans, payload, **kwd) - elif archive_source == "trs_tool": - server = None - trs_tool_id = None - trs_version_id = None - import_source = None - if "trs_url" in payload: - parts = self.app.trs_proxy.match_url(payload["trs_url"]) - if parts: - server = self.app.trs_proxy.server_from_url(parts["trs_base_url"]) - trs_tool_id = parts["tool_id"] - trs_version_id = parts["version_id"] - payload["trs_tool_id"] = trs_tool_id - payload["trs_version_id"] = trs_version_id - else: - raise exceptions.MessageException("Invalid TRS URL.") - else: - trs_server = payload.get("trs_server") - server = self.app.trs_proxy.get_server(trs_server) - trs_tool_id = payload.get("trs_tool_id") - trs_version_id = payload.get("trs_version_id") - - archive_data = server.get_version_descriptor(trs_tool_id, trs_version_id) - else: - try: - archive_data = stream_url_to_str( - archive_source, trans.app.file_sources, prefix="gx_workflow_download" - ) - import_source = "URL" - except Exception: - raise exceptions.MessageException(f"Failed to open URL '{archive_source}'.") - elif hasattr(archive_file, "file"): - uploaded_file = archive_file.file - uploaded_file_name = uploaded_file.name - if os.path.getsize(os.path.abspath(uploaded_file_name)) > 0: - archive_data = util.unicodify(uploaded_file.read()) - import_source = "uploaded file" - else: - raise exceptions.MessageException("You attempted to upload an empty file.") - else: - raise exceptions.MessageException("Please provide a URL or file.") - return self.__api_import_from_archive(trans, archive_data, import_source, payload=payload) - - if "from_history_id" in payload: - from_history_id = payload.get("from_history_id") - from_history_id = self.decode_id(from_history_id) - history = self.history_manager.get_accessible(from_history_id, trans.user, current_history=trans.history) - - job_ids = [self.decode_id(_) for _ in payload.get("job_ids", [])] - dataset_ids = payload.get("dataset_ids", []) - dataset_collection_ids = payload.get("dataset_collection_ids", []) - workflow_name = payload["workflow_name"] - stored_workflow = extract_workflow( - trans=trans, - user=trans.user, - history=history, - job_ids=job_ids, - dataset_ids=dataset_ids, - dataset_collection_ids=dataset_collection_ids, - workflow_name=workflow_name, - ) - item = stored_workflow.to_dict(value_mapper={"id": trans.security.encode_id}) - item["url"] = url_for("workflow", id=item["id"]) - return item - - if "from_path" in payload: - from_path = payload.get("from_path") - object_id = payload.get("object_id") - workflow_src = {"src": "from_path", "path": from_path} - if object_id is not None: - workflow_src["object_id"] = object_id - payload["workflow"] = workflow_src - return self.__api_import_new_workflow(trans, payload, **kwd) - - if "shared_workflow_id" in payload: - workflow_id = payload["shared_workflow_id"] - return self.__api_import_shared_workflow(trans, workflow_id, payload) - - if "workflow" in payload: - return self.__api_import_new_workflow(trans, payload, **kwd) - - # This was already raised above, but just in case... - raise exceptions.RequestParameterMissingException("No method for workflow creation supplied.") - @expose_api def import_new_workflow_deprecated(self, trans: GalaxyWebTransaction, payload, **kwd): """ @@ -295,7 +147,7 @@ def import_new_workflow_deprecated(self, trans: GalaxyWebTransaction, payload, * Deprecated in favor to POST /api/workflows with encoded 'workflow' in payload the same way. """ - return self.__api_import_new_workflow(trans, payload, **kwd) + return self.service._api_import_new_workflow(trans, payload, **kwd) @expose_api def build_module(self, trans: GalaxyWebTransaction, payload=None): @@ -351,63 +203,6 @@ def get_tool_predictions(self, trans: ProvidesUserContext, payload, **kwd): # # -- Helper methods -- # - def __api_import_from_archive(self, trans: GalaxyWebTransaction, archive_data, source=None, payload=None): - payload = payload or {} - try: - data = json.loads(archive_data) - except Exception: - if "GalaxyWorkflow" in archive_data: - data = {"yaml_content": archive_data} - else: - raise exceptions.MessageException("The data content does not appear to be a valid workflow.") - if not data: - raise exceptions.MessageException("The data content is missing.") - raw_workflow_description = self.__normalize_workflow(trans, data) - workflow_create_options = WorkflowCreateOptions(**payload) - workflow, missing_tool_tups = self._workflow_from_dict( - trans, raw_workflow_description, workflow_create_options, source=source - ) - workflow_id = workflow.id - workflow = workflow.latest_workflow - - response = { - "message": f"Workflow '{workflow.name}' imported successfully.", - "status": "success", - "id": trans.security.encode_id(workflow_id), - } - if workflow.has_errors: - response["message"] = "Imported, but some steps in this workflow have validation errors." - response["status"] = "error" - elif len(workflow.steps) == 0: - response["message"] = "Imported, but this workflow has no steps." - response["status"] = "error" - elif workflow.has_cycles: - response["message"] = "Imported, but this workflow contains cycles." - response["status"] = "error" - return response - - def __api_import_new_workflow(self, trans: GalaxyWebTransaction, payload, **kwd): - data = payload["workflow"] - raw_workflow_description = self.__normalize_workflow(trans, data) - workflow_create_options = WorkflowCreateOptions(**payload) - workflow, missing_tool_tups = self._workflow_from_dict( - trans, - raw_workflow_description, - workflow_create_options, - ) - # galaxy workflow newly created id - workflow_id = workflow.id - # api encoded, id - encoded_id = trans.security.encode_id(workflow_id) - item = workflow.to_dict(value_mapper={"id": trans.security.encode_id}) - item["annotations"] = [x.annotation for x in workflow.annotations] - item["url"] = url_for("workflow", id=encoded_id) - item["owner"] = workflow.user.username - item["number_of_steps"] = len(workflow.latest_workflow.steps) - return item - - def __normalize_workflow(self, trans: GalaxyWebTransaction, as_dict): - return self.workflow_contents_manager.normalize_workflow_format(trans, as_dict) @expose_api def import_shared_workflow_deprecated(self, trans: GalaxyWebTransaction, payload, **kwd): @@ -424,89 +219,7 @@ def import_shared_workflow_deprecated(self, trans: GalaxyWebTransaction, payload workflow_id = payload.get("workflow_id", None) if workflow_id is None: raise exceptions.ObjectAttributeMissingException("Missing required parameter 'workflow_id'.") - self.__api_import_shared_workflow(trans, workflow_id, payload) - - def __api_import_shared_workflow(self, trans: GalaxyWebTransaction, workflow_id, payload, **kwd): - try: - stored_workflow = self.get_stored_workflow(trans, workflow_id, check_ownership=False) - except Exception: - raise exceptions.ObjectNotFound("Malformed workflow id specified.") - if stored_workflow.importable is False: - raise exceptions.ItemAccessibilityException( - "The owner of this workflow has disabled imports via this link." - ) - elif stored_workflow.deleted: - raise exceptions.ItemDeletionException("You can't import this workflow because it has been deleted.") - imported_workflow = self._import_shared_workflow(trans, stored_workflow) - item = imported_workflow.to_dict(value_mapper={"id": trans.security.encode_id}) - encoded_id = trans.security.encode_id(imported_workflow.id) - item["url"] = url_for("workflow", id=encoded_id) - return item - - def _workflow_from_dict(self, trans, data, workflow_create_options, source=None): - """Creates a workflow from a dict. - - Created workflow is stored in the database and returned. - """ - publish = workflow_create_options.publish - importable = workflow_create_options.is_importable - if publish and not importable: - raise exceptions.RequestParameterInvalidException("Published workflow must be importable.") - - workflow_contents_manager = self.app.workflow_contents_manager - raw_workflow_description = workflow_contents_manager.ensure_raw_description(data) - created_workflow = workflow_contents_manager.build_workflow_from_raw_description( - trans, - raw_workflow_description, - workflow_create_options, - source=source, - ) - if importable: - self._make_item_accessible(trans.sa_session, created_workflow.stored_workflow) - with transaction(trans.sa_session): - trans.sa_session.commit() - - self._import_tools_if_needed(trans, workflow_create_options, raw_workflow_description) - return created_workflow.stored_workflow, created_workflow.missing_tools - - def _import_tools_if_needed(self, trans, workflow_create_options, raw_workflow_description): - if not workflow_create_options.import_tools: - return - - if not trans.user_is_admin: - raise exceptions.AdminRequiredException() - - data = raw_workflow_description.as_dict - - tools = {} - for key in data["steps"]: - item = data["steps"][key] - if item is not None: - if "tool_shed_repository" in item: - tool_shed_repository = item["tool_shed_repository"] - if ( - "owner" in tool_shed_repository - and "changeset_revision" in tool_shed_repository - and "name" in tool_shed_repository - and "tool_shed" in tool_shed_repository - ): - toolstr = ( - tool_shed_repository["owner"] - + tool_shed_repository["changeset_revision"] - + tool_shed_repository["name"] - + tool_shed_repository["tool_shed"] - ) - tools[toolstr] = tool_shed_repository - - irm = InstallRepositoryManager(self.app) - install_options = workflow_create_options.install_options - for k in tools: - item = tools[k] - tool_shed_url = f"https://{item['tool_shed']}/" - name = item["name"] - owner = item["owner"] - changeset_revision = item["changeset_revision"] - irm.install(tool_shed_url, name, owner, changeset_revision, install_options) + self.service._api_import_shared_workflow(trans, workflow_id, payload) def __get_stored_workflow(self, trans, workflow_id, **kwd): instance = util.string_as_bool(kwd.get("instance", "false")) @@ -907,6 +620,18 @@ def delete_workflow( self.service.delete(trans, workflow_id) return Response(status_code=status.HTTP_204_NO_CONTENT) + @router.post( + "/api/workflows", + summary="Create workflows in various ways", + name="create_workflow", + ) + def create( + self, + payload: WorkflowCreatePayload, + trans: ProvidesUserContext = DependsOnTrans, + ): + return self.service.create(trans, payload) + @router.post( "/api/workflows/{workflow_id}/undelete", summary="Remove the deleted flag from a workflow.", diff --git a/lib/galaxy/webapps/galaxy/services/workflows.py b/lib/galaxy/webapps/galaxy/services/workflows.py index 25918d02beab..672899845cf7 100644 --- a/lib/galaxy/webapps/galaxy/services/workflows.py +++ b/lib/galaxy/webapps/galaxy/services/workflows.py @@ -1,4 +1,6 @@ +import json import logging +import os from typing import ( Any, Dict, @@ -10,6 +12,7 @@ from fastapi.responses import PlainTextResponse from gxformat2._yaml import ordered_dump +from markupsafe import escape from galaxy import ( exceptions, @@ -17,6 +20,10 @@ util, web, ) +from galaxy.files.uris import ( + stream_url_to_str, + validate_uri_access, +) from galaxy.managers.context import ( ProvidesHistoryContext, ProvidesUserContext, @@ -26,6 +33,7 @@ MissingToolsException, RefactorResponse, WorkflowContentsManager, + WorkflowCreateOptions, WorkflowSerializer, WorkflowsManager, WorkflowUpdateOptions, @@ -51,11 +59,18 @@ WorkflowDictRunSummary, WorkflowUpdatePayload, ) +from galaxy.tool_shed.galaxy_install.install_manager import InstallRepositoryManager from galaxy.util.sanitize_html import sanitize_html from galaxy.util.tool_shed.tool_shed_registry import Registry +from galaxy.webapps.base.controller import ( + SharableMixin, + url_for, + UsesStoredWorkflowMixin, +) from galaxy.webapps.galaxy.services.base import ServiceBase from galaxy.webapps.galaxy.services.notifications import NotificationService from galaxy.webapps.galaxy.services.sharable import ShareableService +from galaxy.workflow.extract import extract_workflow from galaxy.workflow.run import queue_invoke from galaxy.workflow.run_request import build_workflow_run_configs @@ -76,6 +91,8 @@ def __init__( notification_service: NotificationService, history_manager: HistoryManager, uses_annotations: UsesAnnotations, + uses_stored_workflow_mix_in: UsesStoredWorkflowMixin, + sharable_mixin: SharableMixin, ): self._workflows_manager = workflows_manager self._workflow_contents_manager = workflow_contents_manager @@ -84,6 +101,8 @@ def __init__( self._tool_shed_registry = tool_shed_registry self._history_manager = history_manager self._uses_annotations = uses_annotations + self._uses_stored_workflow_mix_in = uses_stored_workflow_mix_in + self._sharable_mixin = sharable_mixin def download_workflow(self, trans, workflow_id, history_id, style, format, version, instance): stored_workflow = self._workflows_manager.get_stored_accessible_workflow( @@ -464,3 +483,303 @@ def update_workflow( return StoredWorkflowDetailed( **self._workflow_contents_manager.workflow_to_dict(trans, stored_workflow, style="instance") ) + + def create( + self, + trans, + payload=None, + ): + payload = payload.model_dump(exclude_unset=True) + ways_to_create = { + "archive_file", + "archive_source", + "from_history_id", + "from_path", + "shared_workflow_id", + "workflow", + } + + if trans.user_is_bootstrap_admin: + raise exceptions.RealUserRequiredException("Only real users can create or run workflows.") + + if payload is None or len(ways_to_create.intersection(payload)) == 0: + # Workflow is not propelry received + message = f"One parameter among - {', '.join(ways_to_create)} - must be specified" + raise exceptions.RequestParameterMissingException(message) + + if len(ways_to_create.intersection(payload)) > 1: + message = f"Only one parameter among - {', '.join(ways_to_create)} - must be specified" + raise exceptions.RequestParameterInvalidException(message) + + if "archive_source" in payload or "archive_file" in payload: + archive_source = payload.get("archive_source") + archive_file = payload.get("archive_file") + archive_data = None + if archive_source: + validate_uri_access(archive_source, trans.user_is_admin, trans.app.config.fetch_url_allowlist_ips) + if archive_source.startswith("file://"): + workflow_src = {"src": "from_path", "path": archive_source[len("file://") :]} + payload["workflow"] = workflow_src + return self._api_import_new_workflow(trans, payload) + elif archive_source == "trs_tool": + server = None + trs_tool_id = None + trs_version_id = None + import_source = None + if "trs_url" in payload: + # parts = self.app.trs_proxy.match_url(payload["trs_url"]) + parts = trans.app.trs_proxy.match_url(payload["trs_url"]) + if parts: + # server = self.app.trs_proxy.server_from_url(parts["trs_base_url"]) + server = trans.app.trs_proxy.server_from_url(parts["trs_base_url"]) + trs_tool_id = parts["tool_id"] + trs_version_id = parts["version_id"] + payload["trs_tool_id"] = trs_tool_id + payload["trs_version_id"] = trs_version_id + else: + raise exceptions.MessageException("Invalid TRS URL.") + else: + trs_server = payload.get("trs_server") + # server = self.app.trs_proxy.get_server(trs_server) + server = trans.app.trs_proxy.get_server(trs_server) + trs_tool_id = payload.get("trs_tool_id") + trs_version_id = payload.get("trs_version_id") + + archive_data = server.get_version_descriptor(trs_tool_id, trs_version_id) + else: + try: + archive_data = stream_url_to_str( + archive_source, trans.app.file_sources, prefix="gx_workflow_download" + ) + import_source = "URL" + except Exception: + raise exceptions.MessageException(f"Failed to open URL '{escape(archive_source)}'.") + elif hasattr(archive_file, "file"): + uploaded_file = archive_file.file + uploaded_file_name = uploaded_file.name + if os.path.getsize(os.path.abspath(uploaded_file_name)) > 0: + archive_data = util.unicodify(uploaded_file.read()) + import_source = "uploaded file" + else: + raise exceptions.MessageException("You attempted to upload an empty file.") + else: + raise exceptions.MessageException("Please provide a URL or file.") + return self.__api_import_from_archive(trans, archive_data, import_source, payload=payload) + + if "from_history_id" in payload: + from_history_id = payload.get("from_history_id") + from_history_id = self.decode_id(from_history_id) + history = self._history_manager.get_accessible(from_history_id, trans.user, current_history=trans.history) + + job_ids = [self.decode_id(_) for _ in payload.get("job_ids", [])] + dataset_ids = payload.get("dataset_ids", []) + dataset_collection_ids = payload.get("dataset_collection_ids", []) + workflow_name = payload["workflow_name"] + stored_workflow = extract_workflow( + trans=trans, + user=trans.user, + history=history, + job_ids=job_ids, + dataset_ids=dataset_ids, + dataset_collection_ids=dataset_collection_ids, + workflow_name=workflow_name, + ) + item = stored_workflow.to_dict(value_mapper={"id": trans.security.encode_id}) + item["url"] = url_for("workflow", id=item["id"]) + return item + + if "from_path" in payload: + from_path = payload.get("from_path") + object_id = payload.get("object_id") + workflow_src = {"src": "from_path", "path": from_path} + if object_id is not None: + workflow_src["object_id"] = object_id + payload["workflow"] = workflow_src + return self._api_import_new_workflow(trans, payload) + + if "shared_workflow_id" in payload: + workflow_id = payload["shared_workflow_id"] + return self._api_import_shared_workflow(trans, workflow_id, payload) + + if "workflow" in payload: + a = self._api_import_new_workflow(trans, payload) + return a + + # This was already raised above, but just in case... + raise exceptions.RequestParameterMissingException("No method for workflow creation supplied.") + + def _api_import_new_workflow( + self, + trans, + payload, + **kwd, + ): + data = payload["workflow"] + raw_workflow_description = self.__normalize_workflow(trans, data) + workflow_create_options = WorkflowCreateOptions(**payload) + workflow, missing_tool_tups = self.__workflow_from_dict( + trans, + raw_workflow_description, + workflow_create_options, + ) + # galaxy workflow newly created id + workflow_id = workflow.id + # api encoded, id + encoded_id = trans.security.encode_id(workflow_id) + item = workflow.to_dict(value_mapper={"id": trans.security.encode_id}) + item["annotations"] = [x.annotation for x in workflow.annotations] + item["url"] = url_for("workflow", id=encoded_id) + item["owner"] = workflow.user.username + item["number_of_steps"] = len(workflow.latest_workflow.steps) + return item + + def _api_import_shared_workflow( + self, + trans, + workflow_id, + payload, + **kwd, + ): + try: + stored_workflow = self._uses_stored_workflow_mix_in.get_stored_workflow( + trans, workflow_id, check_ownership=False + ) + except Exception: + raise exceptions.ObjectNotFound("Malformed workflow id specified.") + if stored_workflow.importable is False: + raise exceptions.ItemAccessibilityException( + "The owner of this workflow has disabled imports via this link." + ) + elif stored_workflow.deleted: + raise exceptions.ItemDeletionException("You can't import this workflow because it has been deleted.") + imported_workflow = self._uses_stored_workflow_mix_in._import_shared_workflow(trans, stored_workflow) + item = imported_workflow.to_dict(value_mapper={"id": trans.security.encode_id}) + encoded_id = trans.security.encode_id(imported_workflow.id) + item["url"] = url_for("workflow", id=encoded_id) + return item + + def __api_import_from_archive( + self, + trans, + archive_data, + source=None, + payload=None, + ): + payload = payload or {} + try: + data = json.loads(archive_data) + except Exception: + if "GalaxyWorkflow" in archive_data: + data = {"yaml_content": archive_data} + else: + raise exceptions.MessageException("The data content does not appear to be a valid workflow.") + if not data: + raise exceptions.MessageException("The data content is missing.") + raw_workflow_description = self.__normalize_workflow(trans, data) + workflow_create_options = WorkflowCreateOptions(**payload) + workflow, missing_tool_tups = self.__workflow_from_dict( + trans, raw_workflow_description, workflow_create_options, source=source + ) + workflow_id = workflow.id + workflow = workflow.latest_workflow + + response = { + "message": f"Workflow '{escape(workflow.name)}' imported successfully.", + "status": "success", + "id": trans.security.encode_id(workflow_id), + } + if workflow.has_errors: + response["message"] = "Imported, but some steps in this workflow have validation errors." + response["status"] = "error" + elif len(workflow.steps) == 0: + response["message"] = "Imported, but this workflow has no steps." + response["status"] = "error" + elif workflow.has_cycles: + response["message"] = "Imported, but this workflow contains cycles." + response["status"] = "error" + return response + + def __workflow_from_dict( + self, + trans, + data, + workflow_create_options, + source=None, + ): + """Creates a workflow from a dict. + + Created workflow is stored in the database and returned. + """ + publish = workflow_create_options.publish + importable = workflow_create_options.is_importable + if publish and not importable: + raise exceptions.RequestParameterInvalidException("Published workflow must be importable.") + + # workflow_contents_manager = self.app.workflow_contents_manager + workflow_contents_manager = trans.app.workflow_contents_manager + raw_workflow_description = workflow_contents_manager.ensure_raw_description(data) + created_workflow = workflow_contents_manager.build_workflow_from_raw_description( + trans, + raw_workflow_description, + workflow_create_options, + source=source, + ) + if importable: + self._sharable_mixin._make_item_accessible(trans.sa_session, created_workflow.stored_workflow) + with transaction(trans.sa_session): + trans.sa_session.commit() + + self.__import_tools_if_needed(trans, workflow_create_options, raw_workflow_description) + return created_workflow.stored_workflow, created_workflow.missing_tools + + def __import_tools_if_needed( + self, + trans, + workflow_create_options, + raw_workflow_description, + ): + if not workflow_create_options.import_tools: + return + + if not trans.user_is_admin: + raise exceptions.AdminRequiredException() + + data = raw_workflow_description.as_dict + + tools = {} + for key in data["steps"]: + item = data["steps"][key] + if item is not None: + if "tool_shed_repository" in item: + tool_shed_repository = item["tool_shed_repository"] + if ( + "owner" in tool_shed_repository + and "changeset_revision" in tool_shed_repository + and "name" in tool_shed_repository + and "tool_shed" in tool_shed_repository + ): + toolstr = ( + tool_shed_repository["owner"] + + tool_shed_repository["changeset_revision"] + + tool_shed_repository["name"] + + tool_shed_repository["tool_shed"] + ) + tools[toolstr] = tool_shed_repository + + # irm = InstallRepositoryManager(self.app) + irm = InstallRepositoryManager(trans.app) + install_options = workflow_create_options.install_options + for k in tools: + item = tools[k] + tool_shed_url = f"https://{item['tool_shed']}/" + name = item["name"] + owner = item["owner"] + changeset_revision = item["changeset_revision"] + irm.install(tool_shed_url, name, owner, changeset_revision, install_options) + + def __normalize_workflow( + self, + trans, + as_dict, + ): + return self._workflow_contents_manager.normalize_workflow_format(trans, as_dict) From ce1d00d58bc63930a11c2670773b940aaafa7743 Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Thu, 16 May 2024 17:52:15 +0200 Subject: [PATCH 76/89] Add json keyword when posting to route 'workflows' in tests --- lib/galaxy_test/api/test_tags.py | 2 +- lib/galaxy_test/api/test_workflow_extraction.py | 2 +- lib/galaxy_test/api/test_workflows.py | 5 +++-- lib/galaxy_test/base/populators.py | 2 +- lib/galaxy_test/selenium/framework.py | 2 +- 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/lib/galaxy_test/api/test_tags.py b/lib/galaxy_test/api/test_tags.py index 776f95db147d..21c1ecf77d7c 100644 --- a/lib/galaxy_test/api/test_tags.py +++ b/lib/galaxy_test/api/test_tags.py @@ -140,7 +140,7 @@ def create_item(self) -> str: data = dict( workflow=json.dumps(workflow), ) - upload_response = self._post("workflows", data=data) + upload_response = self._post("workflows", data=data, json=True) self._assert_status_code_is(upload_response, 200) return upload_response.json()["id"] diff --git a/lib/galaxy_test/api/test_workflow_extraction.py b/lib/galaxy_test/api/test_workflow_extraction.py index ada641171af6..839fb7756952 100644 --- a/lib/galaxy_test/api/test_workflow_extraction.py +++ b/lib/galaxy_test/api/test_workflow_extraction.py @@ -602,7 +602,7 @@ def _extract_and_download_workflow(self, history_id: str, **extract_payload): if isinstance(value, list): extract_payload[key] = dumps(value) - create_workflow_response = self._post("workflows", data=extract_payload) + create_workflow_response = self._post("workflows", data=extract_payload, json=True) self._assert_status_code_is(create_workflow_response, 200) new_workflow_id = create_workflow_response.json()["id"] diff --git a/lib/galaxy_test/api/test_workflows.py b/lib/galaxy_test/api/test_workflows.py index 1a7fd67e4b27..23e8579c24d4 100644 --- a/lib/galaxy_test/api/test_workflows.py +++ b/lib/galaxy_test/api/test_workflows.py @@ -1173,7 +1173,7 @@ def test_trs_import(self): "trs_tool_id": "#workflow/github.com/jmchilton/galaxy-workflow-dockstore-example-1/mycoolworkflow", "trs_version_id": "master", } - workflow_id = self._post("workflows", data=trs_payload).json()["id"] + workflow_id = self._post("workflows", data=trs_payload, json=True).json()["id"] original_workflow = self._download_workflow(workflow_id) assert "Test Workflow" in original_workflow["name"] assert original_workflow.get("source_metadata").get("trs_tool_id") == trs_payload["trs_tool_id"] @@ -7533,12 +7533,13 @@ def __import_workflow(self, workflow_id, deprecated_route=False): import_data = dict( workflow_id=workflow_id, ) + return self._post(route, import_data) else: route = "workflows" import_data = dict( shared_workflow_id=workflow_id, ) - return self._post(route, import_data) + return self._post(route, import_data, json=True) def _show_workflow(self, workflow_id): show_response = self._get(f"workflows/{workflow_id}") diff --git a/lib/galaxy_test/base/populators.py b/lib/galaxy_test/base/populators.py index ccf1908ea1be..dc2bc1008d23 100644 --- a/lib/galaxy_test/base/populators.py +++ b/lib/galaxy_test/base/populators.py @@ -2283,7 +2283,7 @@ def import_workflow(self, workflow, **kwds) -> Dict[str, Any]: "workflow": workflow_str, } data.update(**kwds) - upload_response = self._post("workflows", data=data) + upload_response = self._post("workflows", data=data, json=True) assert upload_response.status_code == 200, upload_response.content return upload_response.json() diff --git a/lib/galaxy_test/selenium/framework.py b/lib/galaxy_test/selenium/framework.py index 310c88c88053..8d242fe2004b 100644 --- a/lib/galaxy_test/selenium/framework.py +++ b/lib/galaxy_test/selenium/framework.py @@ -819,7 +819,7 @@ def import_workflow(self, workflow: dict, **kwds) -> dict: "workflow": workflow_str, } data.update(**kwds) - upload_response = self._post("workflows", data=data) + upload_response = self._post("workflows", data=data, json=True) upload_response.raise_for_status() return upload_response.json() From 322d34c30e5b87a8515dd6511a3d06b60ce6fdb1 Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Sat, 25 May 2024 16:38:31 +0200 Subject: [PATCH 77/89] Add more fields to field_validator that decodes json fields in payload of create method --- lib/galaxy/schema/workflows.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/galaxy/schema/workflows.py b/lib/galaxy/schema/workflows.py index a582a2595a51..ec03eff35e5d 100644 --- a/lib/galaxy/schema/workflows.py +++ b/lib/galaxy/schema/workflows.py @@ -1150,7 +1150,7 @@ class WorkflowCreatePayload(Model): description="A dictionary containing information about a new workflow to import.", ) - @field_validator("workflow", mode="before") + @field_validator("workflow", "dataset_ids", "dataset_collection_ids", "job_ids", mode="before") @classmethod def decode_json(cls, v): if isinstance(v, str): From 3fb8457bf3d7948ff71859d7654375b589c69409 Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Sun, 26 May 2024 15:25:50 +0200 Subject: [PATCH 78/89] Allow integer type for some id fields in payload model of create operation --- lib/galaxy/schema/workflows.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/galaxy/schema/workflows.py b/lib/galaxy/schema/workflows.py index ec03eff35e5d..810402647154 100644 --- a/lib/galaxy/schema/workflows.py +++ b/lib/galaxy/schema/workflows.py @@ -1075,17 +1075,17 @@ class WorkflowCreatePayload(Model): title="From History ID", description="The ID of a history from which to extract a workflow.", ) - job_ids: Optional[List[str]] = Field( + job_ids: Optional[List[Union[str, int]]] = Field( None, title="Job IDs", description="If from_history_id is set, this is an optional list of job IDs to include when extracting a workflow from history.", ) - dataset_ids: Optional[List[str]] = Field( + dataset_ids: Optional[Union[str, int]] = Field( None, title="Dataset IDs", description="If from_history_id is set, this is an optional list of HDA 'hid's corresponding to workflow inputs when extracting a workflow from history.", ) - dataset_collection_ids: Optional[List[str]] = Field( + dataset_collection_ids: Optional[Union[str, int]] = Field( None, title="Dataset Collection IDs", description="If from_history_id is set, this is an optional list of HDCA 'hid's corresponding to workflow inputs when extracting a workflow from history.", From 51dc9a7a784b8f4faaffe4ad7fb0f0a97089e7a6 Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Sun, 26 May 2024 15:28:25 +0200 Subject: [PATCH 79/89] Add possibility to load app from trans in get_stored_workflow method --- lib/galaxy/webapps/base/controller.py | 7 +++++-- lib/galaxy/webapps/galaxy/services/workflows.py | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/galaxy/webapps/base/controller.py b/lib/galaxy/webapps/base/controller.py index 83c3ae620560..1274a8a00603 100644 --- a/lib/galaxy/webapps/base/controller.py +++ b/lib/galaxy/webapps/base/controller.py @@ -1114,10 +1114,13 @@ class UsesStoredWorkflowMixin(SharableItemSecurityMixin, UsesAnnotations): slug_builder = SlugBuilder() - def get_stored_workflow(self, trans, id, check_ownership=True, check_accessible=False): + def get_stored_workflow(self, trans, id, check_ownership=True, check_accessible=False, app_by_trans=False): """Get a StoredWorkflow from the database by id, verifying ownership.""" # Load workflow from database - workflow_contents_manager = workflows.WorkflowsManager(self.app) + if app_by_trans: + workflow_contents_manager = workflows.WorkflowsManager(trans.app) + else: + workflow_contents_manager = workflows.WorkflowsManager(self.app) workflow = workflow_contents_manager.get_stored_workflow(trans=trans, workflow_id=id) if not workflow: diff --git a/lib/galaxy/webapps/galaxy/services/workflows.py b/lib/galaxy/webapps/galaxy/services/workflows.py index 672899845cf7..0911cc73c12b 100644 --- a/lib/galaxy/webapps/galaxy/services/workflows.py +++ b/lib/galaxy/webapps/galaxy/services/workflows.py @@ -642,7 +642,7 @@ def _api_import_shared_workflow( ): try: stored_workflow = self._uses_stored_workflow_mix_in.get_stored_workflow( - trans, workflow_id, check_ownership=False + trans, workflow_id, check_ownership=False, app_by_trans=True ) except Exception: raise exceptions.ObjectNotFound("Malformed workflow id specified.") From 0a0b709c804d5b8540f51d9edfb0336acb899371 Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Sun, 26 May 2024 15:31:30 +0200 Subject: [PATCH 80/89] Remove leftovers from debugging create method in workflow service layer --- lib/galaxy/webapps/galaxy/services/workflows.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/galaxy/webapps/galaxy/services/workflows.py b/lib/galaxy/webapps/galaxy/services/workflows.py index 0911cc73c12b..f95ed634d645 100644 --- a/lib/galaxy/webapps/galaxy/services/workflows.py +++ b/lib/galaxy/webapps/galaxy/services/workflows.py @@ -602,8 +602,7 @@ def create( return self._api_import_shared_workflow(trans, workflow_id, payload) if "workflow" in payload: - a = self._api_import_new_workflow(trans, payload) - return a + return self._api_import_new_workflow(trans, payload) # This was already raised above, but just in case... raise exceptions.RequestParameterMissingException("No method for workflow creation supplied.") From 5572717c8d88ac8865e371645b82e9cbf5b11305 Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Sun, 26 May 2024 15:32:12 +0200 Subject: [PATCH 81/89] Remove unused internal method of WorkflowAPIController --- lib/galaxy/webapps/galaxy/api/workflows.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/galaxy/webapps/galaxy/api/workflows.py b/lib/galaxy/webapps/galaxy/api/workflows.py index 1b71da98d467..553a5dfa4a8a 100644 --- a/lib/galaxy/webapps/galaxy/api/workflows.py +++ b/lib/galaxy/webapps/galaxy/api/workflows.py @@ -221,10 +221,6 @@ def import_shared_workflow_deprecated(self, trans: GalaxyWebTransaction, payload raise exceptions.ObjectAttributeMissingException("Missing required parameter 'workflow_id'.") self.service._api_import_shared_workflow(trans, workflow_id, payload) - def __get_stored_workflow(self, trans, workflow_id, **kwd): - instance = util.string_as_bool(kwd.get("instance", "false")) - return self.workflow_manager.get_stored_workflow(trans, workflow_id, by_stored_id=not instance) - StoredWorkflowIDPathParam = Annotated[ DecodedDatabaseIdField, From f867f1aadf3d4cfb623edaee2b748d48d48d970d Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Wed, 29 May 2024 12:22:35 +0200 Subject: [PATCH 82/89] Fix typing of id fields in payload of create opperation --- lib/galaxy/schema/workflows.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/galaxy/schema/workflows.py b/lib/galaxy/schema/workflows.py index 810402647154..56d75fba0e8d 100644 --- a/lib/galaxy/schema/workflows.py +++ b/lib/galaxy/schema/workflows.py @@ -1080,12 +1080,12 @@ class WorkflowCreatePayload(Model): title="Job IDs", description="If from_history_id is set, this is an optional list of job IDs to include when extracting a workflow from history.", ) - dataset_ids: Optional[Union[str, int]] = Field( + dataset_ids: Optional[List[Union[str, int]]] = Field( None, title="Dataset IDs", description="If from_history_id is set, this is an optional list of HDA 'hid's corresponding to workflow inputs when extracting a workflow from history.", ) - dataset_collection_ids: Optional[Union[str, int]] = Field( + dataset_collection_ids: Optional[List[Union[str, int]]] = Field( None, title="Dataset Collection IDs", description="If from_history_id is set, this is an optional list of HDCA 'hid's corresponding to workflow inputs when extracting a workflow from history.", From 049f6ec89a94c427cd6b6b2eb05fad92074e685e Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Wed, 29 May 2024 12:27:07 +0200 Subject: [PATCH 83/89] Fix typing of field upgrade_messages in one of the return models of the workflow_dict operation --- lib/galaxy/schema/workflows.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/galaxy/schema/workflows.py b/lib/galaxy/schema/workflows.py index 56d75fba0e8d..baf4ba818ab2 100644 --- a/lib/galaxy/schema/workflows.py +++ b/lib/galaxy/schema/workflows.py @@ -838,7 +838,7 @@ class WorkflowDictPreviewSummary(WorkflowDictExtendedBaseModel): class WorkflowDictEditorSummary(WorkflowDictExtendedBaseModel): - upgrade_messages: Dict[int, str] = Field( + upgrade_messages: Dict[int, Union[str, Dict[str, str]]] = Field( ..., title="Upgrade Messages", description="Upgrade messages for each step in the workflow.", From 27c533f2e7dc8ea00885ea3c3706aa5570e4628d Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Wed, 29 May 2024 12:56:39 +0200 Subject: [PATCH 84/89] Fix typing of field upgrade_messages in return model of workflow_dict operation --- lib/galaxy/schema/workflows.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/galaxy/schema/workflows.py b/lib/galaxy/schema/workflows.py index baf4ba818ab2..8228e1339f2f 100644 --- a/lib/galaxy/schema/workflows.py +++ b/lib/galaxy/schema/workflows.py @@ -838,7 +838,7 @@ class WorkflowDictPreviewSummary(WorkflowDictExtendedBaseModel): class WorkflowDictEditorSummary(WorkflowDictExtendedBaseModel): - upgrade_messages: Dict[int, Union[str, Dict[str, str]]] = Field( + upgrade_messages: Dict[int, Union[str, Dict[str, Union[str, Dict[str, str]]]]] = Field( ..., title="Upgrade Messages", description="Upgrade messages for each step in the workflow.", From 2cf5bacea05c609e6b91900b8d2a8071e2cd3f4f Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Sun, 2 Jun 2024 16:10:58 +0200 Subject: [PATCH 85/89] Reuse unused import --- lib/galaxy/webapps/galaxy/api/workflows.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/lib/galaxy/webapps/galaxy/api/workflows.py b/lib/galaxy/webapps/galaxy/api/workflows.py index 553a5dfa4a8a..63ddae7b824d 100644 --- a/lib/galaxy/webapps/galaxy/api/workflows.py +++ b/lib/galaxy/webapps/galaxy/api/workflows.py @@ -26,10 +26,7 @@ from starlette.responses import StreamingResponse from typing_extensions import Annotated -from galaxy import ( - exceptions, - util, -) +from galaxy import exceptions from galaxy.managers.context import ( ProvidesHistoryContext, ProvidesUserContext, From 0af65148a162db5f175098aa377b045fc51d221c Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Sun, 2 Jun 2024 16:11:22 +0200 Subject: [PATCH 86/89] Add more fields to the payload of the create method --- lib/galaxy/schema/workflows.py | 51 ++++++++++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 3 deletions(-) diff --git a/lib/galaxy/schema/workflows.py b/lib/galaxy/schema/workflows.py index 8228e1339f2f..3ec8e79a3f59 100644 --- a/lib/galaxy/schema/workflows.py +++ b/lib/galaxy/schema/workflows.py @@ -1068,6 +1068,7 @@ class WorkflowUpdatePayload(Model): ) +# TODO Think if these are really all optional class WorkflowCreatePayload(Model): # TODO - Description comes from previous endpoint from_history_id: Optional[str] = Field( @@ -1111,9 +1112,6 @@ class WorkflowCreatePayload(Model): title="From Path", description="A path from which to import a workflow.", ) - import_tools: Optional[bool] = Field( - None, - ) object_id: Optional[str] = Field( None, title="Object ID", @@ -1156,3 +1154,50 @@ def decode_json(cls, v): if isinstance(v, str): return json.loads(v) return v + + # TODO - these fields are only used, when creating a WorkflowCreateOptions + # Descriptions are taken from the WorkflowCreateOptions class + from_tool_form: Optional[bool] = Field( + default=None, + description="If True, assume all tool state coming from generated form instead of potentially simpler json stored in DB/exported", + ) + exact_tools: Optional[bool] = Field( + default=None, description="If False, allow running with less exact tool versions" + ) + import_tools: Optional[bool] = Field( + None, + ) + allow_missing_tools: Optional[bool] = Field( + None, + ) + dry_run: Optional[bool] = Field( + None, + ) + publish: Optional[bool] = Field( + None, + ) + importable: Optional[bool] = Field( + None, + ) + install_repository_dependencies: Optional[bool] = Field( + None, + ) + install_resolver_dependencies: Optional[bool] = Field( + None, + ) + install_tool_dependencies: Optional[bool] = Field( + None, + ) + new_tool_panel_section_label: Optional[str] = Field( + None, + ) + tool_panel_section_id: Optional[str] = Field( + None, + ) + shed_tool_conf: Optional[str] = Field( + None, + ) + # TODO Type further + tool_panel_section_mapping: Optional[Dict[Any, Any]] = Field( + None, + ) From 01d9e3ad3688ea7c54aca76e9fdb5d5f116362df Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Sun, 2 Jun 2024 18:03:53 +0200 Subject: [PATCH 87/89] Add more fields to the payload of the create method --- lib/galaxy/schema/workflows.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/galaxy/schema/workflows.py b/lib/galaxy/schema/workflows.py index 3ec8e79a3f59..3c5b81cdbc66 100644 --- a/lib/galaxy/schema/workflows.py +++ b/lib/galaxy/schema/workflows.py @@ -1157,6 +1157,10 @@ def decode_json(cls, v): # TODO - these fields are only used, when creating a WorkflowCreateOptions # Descriptions are taken from the WorkflowCreateOptions class + fill_defaults: Optional[bool] = Field( + None, + description="Fill in default tool state when updating, may change tool_state", + ) from_tool_form: Optional[bool] = Field( default=None, description="If True, assume all tool state coming from generated form instead of potentially simpler json stored in DB/exported", @@ -1164,7 +1168,7 @@ def decode_json(cls, v): exact_tools: Optional[bool] = Field( default=None, description="If False, allow running with less exact tool versions" ) - import_tools: Optional[bool] = Field( + update_stored_workflow_attributes: Optional[bool] = Field( None, ) allow_missing_tools: Optional[bool] = Field( @@ -1173,6 +1177,9 @@ def decode_json(cls, v): dry_run: Optional[bool] = Field( None, ) + import_tools: Optional[bool] = Field( + None, + ) publish: Optional[bool] = Field( None, ) From 1ed46486e3dbb3c6fbdb07d3bc0f3b40c5ad8d7b Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Mon, 3 Jun 2024 22:59:25 +0200 Subject: [PATCH 88/89] Decode fields job_ids and from_history_id in payload model instead of in service method of the create operation --- lib/galaxy/schema/workflows.py | 4 ++-- lib/galaxy/webapps/galaxy/services/workflows.py | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/galaxy/schema/workflows.py b/lib/galaxy/schema/workflows.py index 3c5b81cdbc66..261bf615d520 100644 --- a/lib/galaxy/schema/workflows.py +++ b/lib/galaxy/schema/workflows.py @@ -1071,12 +1071,12 @@ class WorkflowUpdatePayload(Model): # TODO Think if these are really all optional class WorkflowCreatePayload(Model): # TODO - Description comes from previous endpoint - from_history_id: Optional[str] = Field( + from_history_id: Optional[DecodedDatabaseIdField] = Field( None, title="From History ID", description="The ID of a history from which to extract a workflow.", ) - job_ids: Optional[List[Union[str, int]]] = Field( + job_ids: Optional[List[DecodedDatabaseIdField]] = Field( None, title="Job IDs", description="If from_history_id is set, this is an optional list of job IDs to include when extracting a workflow from history.", diff --git a/lib/galaxy/webapps/galaxy/services/workflows.py b/lib/galaxy/webapps/galaxy/services/workflows.py index f95ed634d645..6a2bee30363e 100644 --- a/lib/galaxy/webapps/galaxy/services/workflows.py +++ b/lib/galaxy/webapps/galaxy/services/workflows.py @@ -568,10 +568,11 @@ def create( if "from_history_id" in payload: from_history_id = payload.get("from_history_id") - from_history_id = self.decode_id(from_history_id) + # from_history_id = self.decode_id(from_history_id) history = self._history_manager.get_accessible(from_history_id, trans.user, current_history=trans.history) - job_ids = [self.decode_id(_) for _ in payload.get("job_ids", [])] + # job_ids = [self.decode_id(_) for _ in payload.get("job_ids", [])] + job_ids = payload.get("job_ids", []) dataset_ids = payload.get("dataset_ids", []) dataset_collection_ids = payload.get("dataset_collection_ids", []) workflow_name = payload["workflow_name"] From bdbc8f4118ca0a327df08e750a788622837315a8 Mon Sep 17 00:00:00 2001 From: heisner-tillman Date: Fri, 6 Sep 2024 14:11:18 +0200 Subject: [PATCH 89/89] Regenerate the client schema --- client/src/api/schema/schema.ts | 1236 ++++++++++++++++++++++++++++--- 1 file changed, 1129 insertions(+), 107 deletions(-) diff --git a/client/src/api/schema/schema.ts b/client/src/api/schema/schema.ts index 55ce36f6ea40..bdad3cf43b2e 100644 --- a/client/src/api/schema/schema.ts +++ b/client/src/api/schema/schema.ts @@ -4867,7 +4867,8 @@ export interface paths { */ get: operations["index_api_workflows_get"]; put?: never; - post?: never; + /** Create workflows in various ways */ + post: operations["create_workflow_api_workflows_post"]; delete?: never; options?: never; head?: never; @@ -4875,8 +4876,21 @@ export interface paths { trace?: never; }; "/api/workflows/download/{workflow_id}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; /** Returns a selected workflow. */ get: operations["workflow_dict_api_workflows_download__workflow_id__get"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; }; "/api/workflows/menu": { parameters: { @@ -4887,7 +4901,8 @@ export interface paths { }; /** Get workflows present in the tools panel. */ get: operations["get_workflow_menu_api_workflows_menu_get"]; - put?: never; + /** Save workflow menu to be shown in the tool panel */ + put: operations["set_workflow_menu_api_workflows_menu_put"]; post?: never; delete?: never; options?: never; @@ -4904,7 +4919,8 @@ export interface paths { }; /** Displays information needed to run a workflow. */ get: operations["show_workflow_api_workflows__workflow_id__get"]; - put?: never; + /** Update the workflow stored with the ``id`` */ + put: operations["update_workflow_api_workflows__workflow_id__put"]; post?: never; /** Add the deleted flag to a workflow. */ delete: operations["delete_workflow_api_workflows__workflow_id__delete"]; @@ -4951,8 +4967,21 @@ export interface paths { trace?: never; }; "/api/workflows/{workflow_id}/download": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; /** Returns a selected workflow. */ get: operations["workflow_dict_api_workflows__workflow_id__download_get"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; }; "/api/workflows/{workflow_id}/enable_link_access": { parameters: { @@ -8944,6 +8973,97 @@ export interface components { */ update_time: string; }; + /** FrameComment */ + FrameComment: { + /** + * Child Comments + * @description A list of ids (see `id`) of all Comments which are encompassed by this Frame + */ + child_comments?: number[] | null; + /** + * Child Steps + * @description A list of ids of all Steps (see WorkflowStep.id) which are encompassed by this Frame + */ + child_steps?: number[] | null; + /** + * Color + * @description Color this comment is displayed as. The exact color hex is determined by the client + * @enum {string} + */ + color: "none" | "black" | "blue" | "turquoise" | "green" | "lime" | "orange" | "yellow" | "red" | "pink"; + data: components["schemas"]["FrameCommentData"]; + /** + * Id + * @description Unique identifier for this comment. Determined by the comments order + */ + id: number; + /** + * Position + * @description [x, y] position of this comment in the Workflow + */ + position: [number, number]; + /** + * Size + * @description [width, height] size of this comment + */ + size: [number, number]; + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + type: "frame"; + }; + /** FrameCommentData */ + FrameCommentData: { + /** + * Title + * @description The Frames title + */ + title: string; + }; + /** FreehandComment */ + FreehandComment: { + /** + * Color + * @description Color this comment is displayed as. The exact color hex is determined by the client + * @enum {string} + */ + color: "none" | "black" | "blue" | "turquoise" | "green" | "lime" | "orange" | "yellow" | "red" | "pink"; + data: components["schemas"]["FreehandCommentData"]; + /** + * Id + * @description Unique identifier for this comment. Determined by the comments order + */ + id: number; + /** + * Position + * @description [x, y] position of this comment in the Workflow + */ + position: [number, number]; + /** + * Size + * @description [width, height] size of this comment + */ + size: [number, number]; + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + type: "freehand"; + }; + /** FreehandCommentData */ + FreehandCommentData: { + /** + * Line + * @description List of [x, y] coordinates determining the unsmoothed line. Smoothing is done client-side using Catmull-Rom + */ + line: [number, number][]; + /** + * Thickness + * @description Width of the Line in pixels + */ + thickness: number; + }; /** FtpImportElement */ FtpImportElement: { /** Md5 */ @@ -11143,6 +11263,21 @@ export interface components { */ uri: string; }; + /** InputConnection */ + InputConnection: { + /** + * ID + * @description The order index of the step. + */ + id: number; + /** Input Subworkflow Step ID */ + input_subworkflow_step_id?: number | null; + /** + * Output Name + * @description The output name of the input step that serves as the source for this connection. + */ + output_name: string; + }; /** InputDataCollectionStep */ InputDataCollectionStep: { /** @@ -12050,16 +12185,12 @@ export interface components { batch: boolean | null; /** * Dataset Map - * @description TODO * @default {} */ ds_map: { [key: string]: Record; } | null; - /** - * Effective Outputs - * @description TODO - */ + /** Effective Outputs */ effective_outputs?: unknown | null; /** * History @@ -12071,10 +12202,7 @@ export interface components { * @description The encoded history id into which to import. */ history_id?: string | null; - /** - * Inputs - * @description TODO - */ + /** Inputs */ inputs?: Record | null; /** * Inputs By @@ -12133,7 +12261,6 @@ export interface components { preferred_outputs_object_store_id?: string | null; /** * Replacement Parameters - * @description TODO * @default {} */ replacement_params: Record | null; @@ -12145,7 +12272,6 @@ export interface components { require_exact_tool_versions: boolean | null; /** * Resource Parameters - * @description TODO * @default {} */ resource_params: Record | null; @@ -12154,10 +12280,7 @@ export interface components { * @description Scheduler to use for workflow invocation. */ scheduler?: string | null; - /** - * Step Parameters - * @description TODO - */ + /** Step Parameters */ step_parameters?: Record | null; /** * Use cached job @@ -13258,6 +13381,44 @@ export interface components { * @enum {string} */ MandatoryNotificationCategory: "broadcast"; + /** MarkdownComment */ + MarkdownComment: { + /** + * Color + * @description Color this comment is displayed as. The exact color hex is determined by the client + * @enum {string} + */ + color: "none" | "black" | "blue" | "turquoise" | "green" | "lime" | "orange" | "yellow" | "red" | "pink"; + data: components["schemas"]["MarkdownCommentData"]; + /** + * Id + * @description Unique identifier for this comment. Determined by the comments order + */ + id: number; + /** + * Position + * @description [x, y] position of this comment in the Workflow + */ + position: [number, number]; + /** + * Size + * @description [width, height] size of this comment + */ + size: [number, number]; + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + type: "markdown"; + }; + /** MarkdownCommentData */ + MarkdownCommentData: { + /** + * Text + * @description The unrendered source Markdown for this Comment + */ + text: string; + }; /** MaterializeDatasetInstanceAPIRequest */ MaterializeDatasetInstanceAPIRequest: { /** @@ -14235,6 +14396,29 @@ export interface components { /** Top */ top: number; }; + /** PostJobAction */ + PostJobAction: { + /** + * Action Arguments + * @description Any additional arguments needed by the action. + */ + action_arguments: Record; + /** + * Action Type + * @description The type of action to run. + */ + action_type: string; + /** + * Output Name + * @description The name of the output that will be affected by the action. + */ + output_name: string; + /** + * Short String + * @description A short string representation of the action. + */ + short_str?: string | null; + }; /** PrepareStoreDownloadPayload */ PrepareStoreDownloadPayload: { /** @@ -14907,6 +15091,27 @@ export interface components { */ new_slug: string; }; + /** SetWorkflowMenuPayload */ + SetWorkflowMenuPayload: { + /** + * Workflow IDs + * @description The list of workflow IDs to set the menu entry for. + */ + workflow_ids: string[] | string; + }; + /** SetWorkflowMenuSummary */ + SetWorkflowMenuSummary: { + /** + * Message + * @description The message of the operation. + */ + message: unknown | null; + /** + * Status + * @description The status of the operation. + */ + status: string; + }; /** ShareHistoryExtra */ ShareHistoryExtra: { /** @@ -15322,6 +15527,11 @@ export interface components { * @enum {string} */ Src: "url" | "pasted" | "files" | "path" | "composite" | "ftp_import" | "server_dir"; + /** StepIn */ + StepIn: { + /** Default */ + default: unknown; + }; /** StepReferenceByLabel */ StepReferenceByLabel: { /** @@ -15752,6 +15962,59 @@ export interface components { */ type: "string"; }; + /** TextComment */ + TextComment: { + /** + * Color + * @description Color this comment is displayed as. The exact color hex is determined by the client + * @enum {string} + */ + color: "none" | "black" | "blue" | "turquoise" | "green" | "lime" | "orange" | "yellow" | "red" | "pink"; + data: components["schemas"]["TextCommentData"]; + /** + * Id + * @description Unique identifier for this comment. Determined by the comments order + */ + id: number; + /** + * Position + * @description [x, y] position of this comment in the Workflow + */ + position: [number, number]; + /** + * Size + * @description [width, height] size of this comment + */ + size: [number, number]; + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + type: "text"; + }; + /** TextCommentData */ + TextCommentData: { + /** + * Bold + * @description If the Comments text is bold. Absent is interpreted as false + */ + bold?: boolean | null; + /** + * Italic + * @description If the Comments text is italic. Absent is interpreted as false + */ + italic?: boolean | null; + /** + * Size + * @description Relative size (1 -> 100%) of the text compared to the default text sitz + */ + size: number; + /** + * Text + * @description The plaintext text of this comment + */ + text: string; + }; /** ToolDataDetails */ ToolDataDetails: { /** @@ -15832,6 +16095,26 @@ export interface components { */ values: string; }; + /** ToolShedRepositorySummary */ + ToolShedRepositorySummary: { + /** Changeset Revision */ + changeset_revision: string; + /** + * Name + * @description The name of the repository. + */ + name: string; + /** + * Owner + * @description The owner of the repository. + */ + owner: string; + /** + * Tool Shed + * @description The Tool Shed base URL. + */ + tool_shed: string; + }; /** ToolStep */ ToolStep: { /** @@ -16888,8 +17171,133 @@ export interface components { * @default [] */ VisualizationSummaryList: components["schemas"]["VisualizationSummary"][]; - /** WorkflowDictEditorSteps */ - WorkflowDictEditorSteps: { + /** WorkflowCommentModel */ + WorkflowCommentModel: + | components["schemas"]["TextComment"] + | components["schemas"]["MarkdownComment"] + | components["schemas"]["FrameComment"] + | components["schemas"]["FreehandComment"]; + /** WorkflowCreatePayload */ + WorkflowCreatePayload: { + /** Allow Missing Tools */ + allow_missing_tools?: boolean | null; + /** + * Archive File + * @description A file containing a workflow archive to be imported. + */ + archive_file?: unknown | null; + /** + * Archive Source + * @description A URL or file path pointing to a workflow archive to be imported. + */ + archive_source?: string | null; + /** + * Dataset Collection IDs + * @description If from_history_id is set, this is an optional list of HDCA 'hid's corresponding to workflow inputs when extracting a workflow from history. + */ + dataset_collection_ids?: (string | number)[] | null; + /** + * Dataset IDs + * @description If from_history_id is set, this is an optional list of HDA 'hid's corresponding to workflow inputs when extracting a workflow from history. + */ + dataset_ids?: (string | number)[] | null; + /** Dry Run */ + dry_run?: boolean | null; + /** + * Exact Tools + * @description If False, allow running with less exact tool versions + */ + exact_tools?: boolean | null; + /** + * Fill Defaults + * @description Fill in default tool state when updating, may change tool_state + */ + fill_defaults?: boolean | null; + /** + * From History ID + * @description The ID of a history from which to extract a workflow. + */ + from_history_id?: string | null; + /** + * From Path + * @description A path from which to import a workflow. + */ + from_path?: string | null; + /** + * From Tool Form + * @description If True, assume all tool state coming from generated form instead of potentially simpler json stored in DB/exported + */ + from_tool_form?: boolean | null; + /** Import Tools */ + import_tools?: boolean | null; + /** Importable */ + importable?: boolean | null; + /** Install Repository Dependencies */ + install_repository_dependencies?: boolean | null; + /** Install Resolver Dependencies */ + install_resolver_dependencies?: boolean | null; + /** Install Tool Dependencies */ + install_tool_dependencies?: boolean | null; + /** + * Job IDs + * @description If from_history_id is set, this is an optional list of job IDs to include when extracting a workflow from history. + */ + job_ids?: string[] | null; + /** New Tool Panel Section Label */ + new_tool_panel_section_label?: string | null; + /** + * Object ID + * @description If from_path is set, this is an optional object ID to include when importing a workflow from a path. + */ + object_id?: string | null; + /** Publish */ + publish?: boolean | null; + /** + * Shared Workflow ID + * @description The ID of a shared workflow to import. + */ + shared_workflow_id?: string | null; + /** Shed Tool Conf */ + shed_tool_conf?: string | null; + /** Tool Panel Section Id */ + tool_panel_section_id?: string | null; + /** Tool Panel Section Mapping */ + tool_panel_section_mapping?: Record | null; + /** + * TRS Server + * @description If archive_source is set to 'trs_tool', this is the server of the Tool Registry Service (TRS) from which to import a workflow. + */ + trs_server?: string | null; + /** + * TRS Tool ID + * @description If archive_source is set to 'trs_tool', this is the ID of the tool in the Tool Registry Service (TRS) from which to import a workflow. + */ + trs_tool_id?: string | null; + /** + * TRS URL + * @description If archive_source is set to 'trs_tool', this is the URL of the Tool Registry Service (TRS) from which to import a workflow. + */ + trs_url?: string | null; + /** + * TRS Version ID + * @description If archive_source is set to 'trs_tool', this is the version ID of the tool in the Tool Registry Service (TRS) from which to import a workflow. + */ + trs_version_id?: string | null; + /** Update Stored Workflow Attributes */ + update_stored_workflow_attributes?: boolean | null; + /** + * Workflow + * @description A dictionary containing information about a new workflow to import. + */ + workflow?: Record | null; + /** + * Workflow Name + * @description If from_history_id is set, this is the name of the workflow to create when extracting a workflow from history. + */ + workflow_name?: string | null; + }; + /** WorkflowDictEditorStep */ + WorkflowDictEditorStep: { /** * Annotation * @description An annotation to provide details or to help understand the purpose and usage of this item. @@ -16909,7 +17317,7 @@ export interface components { * Errors * @description An message indicating possible errors in the step. */ - errors?: string[] | string | null; + errors?: string[] | string | Record | null; /** * ID * @description The identifier of the step. It matches the index order of the step inside the workflow. @@ -16944,12 +17352,17 @@ export interface components { * Position * @description Layout position of this step in the graph */ - position?: Record | null; + position?: components["schemas"]["WorkflowStepLayoutPosition"] | null; /** * Post Job Actions * @description Set of actions that will be run when the job finishes. */ - post_job_actions?: Record | Record[] | null; + post_job_actions?: + | components["schemas"]["PostJobAction"][] + | { + [key: string]: components["schemas"]["PostJobAction"]; + } + | null; /** * Tool ID * @description The unique name of the tool associated with this step. @@ -16989,7 +17402,7 @@ export interface components { * Workflow Outputs * @description Workflow outputs associated with this step. */ - workflow_outputs?: Record[] | null; + workflow_outputs?: components["schemas"]["WorkflowOutput"][] | null; }; /** WorkflowDictEditorSummary */ WorkflowDictEditorSummary: { @@ -17002,7 +17415,7 @@ export interface components { * Comments * @description Comments on the workflow. */ - comments: Record[]; + comments: components["schemas"]["WorkflowCommentModel"][]; /** * Creator * @description Additional information about the creator (or multiple creators) of this workflow. @@ -17014,7 +17427,7 @@ export interface components { * License * @description SPDX Identifier of the license associated with this workflow. */ - license?: string | null; + license: string | null; /** * Name * @description The name of the workflow. @@ -17029,20 +17442,28 @@ export interface components { * Source Metadata * @description Metadata about the source of the workflow */ - source_metadata?: Record | null; + source_metadata: Record | null; /** * Steps * @description Information about all the steps of the workflow. */ steps: { - [key: string]: components["schemas"]["WorkflowDictEditorSteps"] | undefined; + [key: string]: components["schemas"]["WorkflowDictEditorStep"]; }; /** * Upgrade Messages * @description Upgrade messages for each step in the workflow. */ upgrade_messages: { - [key: string]: string | undefined; + [key: string]: + | string + | { + [key: string]: + | string + | { + [key: string]: string; + }; + }; }; /** * Version @@ -17050,8 +17471,8 @@ export interface components { */ version: number; }; - /** WorkflowDictExportSteps */ - WorkflowDictExportSteps: { + /** WorkflowDictExportStep */ + WorkflowDictExportStep: { /** * Annotation * @description An annotation to provide details or to help understand the purpose and usage of this item. @@ -17066,29 +17487,28 @@ export interface components { * Errors * @description An message indicating possible errors in the step. */ - errors?: string[] | string | null; + errors?: string[] | string | Record | null; /** * ID * @description The identifier of the step. It matches the index order of the step inside the workflow. */ id: number; - /** - * In - * @description The input connections of the step. - */ - in?: Record | null; + /** In */ + in?: { + [key: string]: components["schemas"]["StepIn"]; + } | null; /** * Input Connections * @description The input connections of the step. */ input_connections?: { - [key: string]: (Record | Record[]) | undefined; + [key: string]: components["schemas"]["InputConnection"] | components["schemas"]["InputConnection"][]; } | null; /** * Inputs * @description The inputs of the step. */ - inputs?: Record[] | null; + inputs?: components["schemas"]["WorkflowDictExportStepInput"][] | null; /** * Label * @description The label of the step. @@ -17108,17 +17528,22 @@ export interface components { * Position * @description Layout position of this step in the graph */ - position?: Record | null; + position?: components["schemas"]["WorkflowStepLayoutPosition"] | null; /** * Post Job Actions * @description Set of actions that will be run when the job finishes. */ - post_job_actions?: Record | Record[] | null; + post_job_actions?: + | components["schemas"]["PostJobAction"][] + | { + [key: string]: components["schemas"]["PostJobAction"]; + } + | null; /** * Sub Workflow * @description Full information about the subworkflow associated with this step. */ - subworkflow?: Record | null; + subworkflow?: components["schemas"]["WorkflowDictExportSummary"] | null; /** * Tool ID * @description The unique name of the tool associated with this step. @@ -17133,7 +17558,7 @@ export interface components { * Tool Shed Repository * @description Information about the tool shed repository associated with the tool. */ - tool_shed_repository?: Record | null; + tool_shed_repository?: components["schemas"]["ToolShedRepositorySummary"] | null; /** * Tool State * @description The state of the tool associated with the step @@ -17151,6 +17576,7 @@ export interface components { type: string; /** * UUID + * Format: uuid4 * @description Universal unique identifier of the workflow. */ uuid: string; @@ -17163,15 +17589,30 @@ export interface components { * Workflow Outputs * @description Workflow outputs associated with this step. */ - workflow_outputs?: Record[] | null; + workflow_outputs?: components["schemas"]["WorkflowOutput"][] | null; + }; + /** WorkflowDictExportStepInput */ + WorkflowDictExportStepInput: { + /** + * Description + * @description The annotation or description of the input. + */ + description: string; + /** + * Name + * @description The name of the input. + */ + name: string; }; /** WorkflowDictExportSummary */ WorkflowDictExportSummary: { /** * A Galaxy Workflow * @description Whether this workflow is a Galaxy Workflow. + * @constant + * @enum {string} */ - a_galaxy_workflow?: string | null; + a_galaxy_workflow: "true"; /** * Annotation * @description An annotation to provide details or to help understand the purpose and usage of this item. @@ -17181,7 +17622,7 @@ export interface components { * Comments * @description Comments associated with the workflow. */ - comments?: Record[] | null; + comments: Record[]; /** * Creator * @description Additional information about the creator (or multiple creators) of this workflow. @@ -17192,8 +17633,10 @@ export interface components { /** * Format Version * @description The version of the workflow format being used. + * @constant + * @enum {string} */ - "format-version"?: string | null; + "format-version": "0.1"; /** * License * @description SPDX Identifier of the license associated with this workflow. @@ -17219,31 +17662,33 @@ export interface components { * @description Information about all the steps of the workflow. */ steps: { - [key: string]: components["schemas"]["WorkflowDictExportSteps"] | undefined; + [key: string]: components["schemas"]["WorkflowDictExportStep"]; }; /** * Tags * @description The tags associated with the workflow. */ - tags?: string[] | null; + tags: components["schemas"]["TagCollection"] | ""; /** * UUID - * @description The UUID (Universally Unique Identifier) of the workflow, represented as a string. + * @description The UUID (Universally Unique Identifier) of the workflow. */ uuid?: string | null; /** * Version * @description The version of the workflow represented by an incremental number. */ - version: number; + version?: number | null; }; /** WorkflowDictFormat2Summary */ WorkflowDictFormat2Summary: { /** * Class * @description The class of the workflow. + * @constant + * @enum {string} */ - class: string; + class: "GalaxyWorkflow"; /** * Creator * @description Additional information about the creator (or multiple creators) of this workflow. @@ -17260,7 +17705,7 @@ export interface components { * Inputs * @description The inputs of the workflow. */ - inputs?: Record | null; + inputs: Record; /** * Label * @description The label or name of the workflow. @@ -17275,7 +17720,7 @@ export interface components { * Outputs * @description The outputs of the workflow. */ - outputs?: Record | null; + outputs: Record; /** * Release * @description The release information for the workflow. @@ -17295,10 +17740,10 @@ export interface components { * Tags * @description The tags associated with the workflow. */ - tags?: string[] | null; + tags?: components["schemas"]["TagCollection"] | null; /** * UUID - * @description The UUID (Universally Unique Identifier) of the workflow, represented as a string. + * @description The UUID (Universally Unique Identifier) of the workflow. */ uuid?: string | null; }; @@ -17306,12 +17751,12 @@ export interface components { WorkflowDictFormat2WrappedYamlSummary: { /** * YAML Content - * @description The content of the workflow in YAML format. + * @description The content of the workflow in YAML . */ - yaml_content: string; + yaml_content: unknown; }; - /** WorkflowDictPreviewSteps */ - WorkflowDictPreviewSteps: { + /** WorkflowDictPreviewStep */ + WorkflowDictPreviewStep: { /** * Annotation * @description An annotation to provide details or to help understand the purpose and usage of this item. @@ -17326,7 +17771,7 @@ export interface components { * Errors * @description An message indicating possible errors in the step. */ - errors?: string[] | string | null; + errors?: string[] | string | Record | null; /** * Inputs * @description The inputs of the step. @@ -17351,12 +17796,17 @@ export interface components { * Position * @description Layout position of this step in the graph */ - position?: Record | null; + position?: components["schemas"]["WorkflowStepLayoutPosition"] | null; /** * Post Job Actions * @description Set of actions that will be run when the job finishes. */ - post_job_actions?: Record | Record[] | null; + post_job_actions?: + | components["schemas"]["PostJobAction"][] + | { + [key: string]: components["schemas"]["PostJobAction"]; + } + | null; /** * Tool ID * @description The unique name of the tool associated with this step. @@ -17386,7 +17836,7 @@ export interface components { * Workflow Outputs * @description Workflow outputs associated with this step. */ - workflow_outputs?: Record[] | null; + workflow_outputs?: components["schemas"]["WorkflowOutput"][] | null; }; /** WorkflowDictPreviewSummary */ WorkflowDictPreviewSummary: { @@ -17399,15 +17849,15 @@ export interface components { * Steps * @description Information about all the steps of the workflow. */ - steps: components["schemas"]["WorkflowDictPreviewSteps"][]; + steps: components["schemas"]["WorkflowDictPreviewStep"][]; /** * Version * @description The version of the workflow represented by an incremental number. */ version: number; }; - /** WorkflowDictRunSteps */ - WorkflowDictRunSteps: { + /** WorkflowDictRunStep */ + WorkflowDictRunStep: { /** * Annotation * @description An annotation to provide details or to help understand the purpose and usage of this item. @@ -17422,7 +17872,7 @@ export interface components { * Errors * @description An message indicating possible errors in the step. */ - errors?: string[] | string | null; + errors?: string[] | string | Record | null; /** * Inputs * @description The inputs of the step. @@ -17447,17 +17897,22 @@ export interface components { * Position * @description Layout position of this step in the graph */ - position?: Record | null; + position?: components["schemas"]["WorkflowStepLayoutPosition"] | null; /** * Post Job Actions * @description Set of actions that will be run when the job finishes. */ - post_job_actions?: Record | Record[] | null; + post_job_actions?: + | components["schemas"]["PostJobAction"][] + | { + [key: string]: components["schemas"]["PostJobAction"]; + } + | null; /** * Replacement Parameters * @description Informal replacement parameters for the step. */ - replacement_parameters?: Record[] | null; + replacement_parameters?: (string | Record)[] | null; /** * Step Index * @description The order index of the step. @@ -17507,7 +17962,7 @@ export interface components { * Workflow Outputs * @description Workflow outputs associated with this step. */ - workflow_outputs?: Record[] | null; + workflow_outputs?: components["schemas"]["WorkflowOutput"][] | null; }; /** WorkflowDictRunSummary */ WorkflowDictRunSummary: { @@ -17515,17 +17970,17 @@ export interface components { * Has Upgrade Messages * @description Whether the workflow has upgrade messages. */ - has_upgrade_messages?: boolean | null; + has_upgrade_messages: boolean; /** * History ID - * @description TODO + * @description The encoded ID of the history associated with the workflow. */ history_id?: string | null; /** * ID - * @description TODO + * @description The encoded ID of the stored workflow. */ - id?: string | null; + id: string; /** * Name * @description The name of the workflow. @@ -17535,22 +17990,312 @@ export interface components { * Step Version Changes * @description Version changes for the workflow steps. */ - step_version_changes?: Record[] | null; + step_version_changes: (string | Record)[]; /** * Steps * @description Information about all the steps of the workflow. */ - steps: components["schemas"]["WorkflowDictRunSteps"][]; + steps: (components["schemas"]["WorkflowDictRunToolStep"] | components["schemas"]["WorkflowDictRunStep"])[]; /** * Version * @description The version of the workflow represented by an incremental number. */ - version: number; + version: number; + /** + * Workflow Resource Parameters + * @description The resource parameters of the workflow. + */ + workflow_resource_parameters: Record | null; + }; + /** WorkflowDictRunToolStep */ + WorkflowDictRunToolStep: { + /** + * Action + * @description The action of the tool step. + */ + action: string; + /** + * Annotation + * @description An annotation to provide details or to help understand the purpose and usage of this item. + */ + annotation?: string | null; + /** + * Citations + * @description The citations of the tool step. + */ + citations: boolean; + /** + * Content ID + * @description The content ID of the step. + */ + content_id?: string | null; + /** + * Creator + * @description The creator of the tool step. + */ + creator?: string | null; + /** + * Description + * @description The description of the tool step. + */ + description: string; + /** + * Display + * @description Indicates if the tool step should be displayed. + */ + display: boolean; + /** + * EDAM Operations + * @description The EDAM operations of the tool step. + */ + edam_operations: string[]; + /** + * EDAM Topics + * @description The EDAM topics of the tool step. + */ + edam_topics: string[]; + /** + * Enctype + * @description The enctype of the tool step. + */ + enctype: string; + /** + * Errors + * @description An message indicating possible errors in the step. + */ + errors?: string[] | string | Record | null; + /** + * Form Style + * @description The form style of the tool step. + */ + form_style: string; + /** + * Help + * @description The help of the tool step. + */ + help: string; + /** + * Hidden + * @description The hidden status of the tool step. + */ + hidden: string; + /** + * History ID + * @description The ID of the history associated with the tool step. + */ + history_id: string; + /** + * ID + * @description The identifier of the tool step. + */ + id: string; + /** + * Inputs + * @description The inputs of the step. + */ + inputs: Record[]; + /** + * Is Workflow Compatible + * @description Indicates if the tool step is compatible with workflows. + */ + is_workflow_compatible: boolean; + /** + * Job ID + * @description The ID of the job associated with the tool step. + */ + job_id?: string | null; + /** + * Job Remap + * @description The remap of the job associated with the tool step. + */ + job_remap?: string | null; + /** + * Labels + * @description The labels of the tool step. + */ + labels: string[]; + /** + * License + * @description The license of the tool step. + */ + license?: string | null; + /** + * Link + * @description The link of the tool step. + */ + link?: string | null; + /** + * Message + * @description The message of the tool step. + */ + message: string; + /** + * Messages + * @description Upgrade messages for the step. + */ + messages?: string[] | null; + /** + * Method + * @description The method of the tool step. + */ + method: string; + /** + * Min Width + * @description The minimum width of the tool step. + */ + min_width?: unknown | null; + /** + * Model Class + * @description The model class of the tool step. + * @constant + * @enum {string} + */ + model_class: "tool"; + /** + * Name + * @description The name of the tool step. + */ + name: string; + /** + * Output Connections + * @description The output connections of the step. + */ + output_connections: Record[]; + /** + * Outputs + * @description The outputs of the step. + */ + outputs?: Record[] | null; + /** + * Panel Section ID + * @description The panel section ID of the tool step. + */ + panel_section_id: string; + /** + * Panel Section Name + * @description The panel section name of the tool step. + */ + panel_section_name: string; + /** + * Position + * @description Layout position of this step in the graph + */ + position?: components["schemas"]["WorkflowStepLayoutPosition"] | null; + /** + * Post Job Actions + * @description Set of actions that will be run when the job finishes. + */ + post_job_actions?: + | components["schemas"]["PostJobAction"][] + | { + [key: string]: components["schemas"]["PostJobAction"]; + } + | null; + /** + * Replacement Parameters + * @description Informal replacement parameters for the step. + */ + replacement_parameters?: (string | Record)[] | null; + /** + * Requirements + * @description The requirements of the tool step. + */ + requirements: string[]; + /** + * Sharable URL + * @description The sharable URL of the tool step. + */ + sharable_url?: string | null; + /** + * State Inputs + * @description The state inputs of the tool step. + */ + state_inputs: Record; + /** + * Step Index + * @description The order index of the step. + */ + step_index: number; + /** + * Step Label + * @description The label of the step. + */ + step_label?: string | null; + /** + * Step Name + * @description The descriptive name of the module or step. + */ + step_name: string; + /** + * Step Type + * @description The type of the step. + */ + step_type: string; + /** + * Step Version + * @description The version of the step's module. + */ + step_version?: string | null; + /** + * Target + * @description The target of the tool step. + */ + target?: unknown | null; + /** + * Tool Errors + * @description An message indicating possible errors in the tool step. + */ + tool_errors?: string | null; + /** + * Tool ID + * @description The unique name of the tool associated with this step. + */ + tool_id?: string | null; + /** + * Tool Shed Repository + * @description Information about the tool shed repository associated with the tool. + */ + tool_shed_repository?: components["schemas"]["ToolShedRepositorySummary"] | null; + /** + * Tool State + * @description The state of the tool associated with the step + */ + tool_state?: Record | string | null; + /** + * Tool Version + * @description The version of the tool associated with the step. + */ + tool_version?: string | null; + /** + * Version + * @description The version of the tool step. + */ + version: string; + /** + * Versions + * @description The versions of the tool step. + */ + versions: string[]; + /** + * Warnings + * @description The warnings of the tool step. + */ + warnings?: string | null; + /** + * When + * @description The when expression for the step. + */ + when?: string | null; + /** + * Workflow Outputs + * @description Workflow outputs associated with this step. + */ + workflow_outputs?: components["schemas"]["WorkflowOutput"][] | null; /** - * Workflow Resource Parameters - * @description The resource parameters of the workflow. + * XRefs + * @description The cross-references of the tool step. */ - workflow_resource_parameters?: Record | null; + xrefs: string[]; }; /** WorkflowInput */ WorkflowInput: { @@ -17564,10 +18309,7 @@ export interface components { * @description Universal unique identifier of the input. */ uuid: string | null; - /** - * Value - * @description TODO - */ + /** Value */ value: unknown | null; }; /** WorkflowInvocationCollectionView */ @@ -17743,6 +18485,107 @@ export interface components { [key: string]: number; }; }; + /** WorkflowOutput */ + WorkflowOutput: { + /** + * Label + * @description Label of the output. + */ + label?: string | null; + /** + * Output Name + * @description The name of the step output. + */ + output_name: string; + /** + * UUID + * @description Universal unique identifier of the output. + */ + uuid?: string | null; + }; + /** + * WorkflowStepLayoutPosition + * @description Position and dimensions of the workflow step represented by a box on the graph. + */ + WorkflowStepLayoutPosition: { + /** + * Bottom + * @description Position of the bottom of the box. + */ + bottom?: number | null; + /** + * Height + * @description Height of the box. + */ + height?: number | null; + /** + * Left + * @description Left margin or left-most position of the box. + */ + left: number; + /** + * Right + * @description Right margin or right-most position of the box. + */ + right?: number | null; + /** + * Top + * @description Position of the top of the box. + */ + top: number; + /** + * Width + * @description Width of the box. + */ + width?: number | null; + /** + * X + * @description Horizontal coordinate of the top right corner of the box. + */ + x?: number | null; + /** + * Y + * @description Vertical coordinate of the top right corner of the box. + */ + y?: number | null; + }; + /** WorkflowUpdatePayload */ + WorkflowUpdatePayload: { + /** + * Annotation + * @description Annotation for the workflow, if not present in payload, annotation defaults to existing annotation + */ + annotation?: string | null; + /** + * From Tool Form + * @description True iff encoded state coming in is encoded for the tool form. + */ + from_tool_form?: boolean | null; + /** Importable */ + importable?: boolean | null; + /** + * Menu Entry + * @description Flag indicating if the workflow should appear in the user's menu, if not present, workflow menu entries are not modified + */ + menu_entry?: boolean | null; + /** + * Name + * @description Name for the workflow, if not present in payload, name defaults to existing name + */ + name?: string | null; + /** Published */ + published?: boolean | null; + /** + * Tags + * @description List containing list of tags to add to the workflow (overwriting existing tags), if not present, tags are not modified + */ + tags?: string[] | null; + /** + * Workflow + * @description The json description of the workflow as would be produced by GET workflows//download or given to `POST workflows`. The workflow contents will be updated to target this. + */ + workflow?: unknown | null; + }; /** WriteInvocationStoreToPayload */ WriteInvocationStoreToPayload: { /** @@ -33422,32 +34265,81 @@ export interface operations { }; }; }; + create_workflow_api_workflows_post: { + parameters: { + query?: never; + header?: { + /** @description The user ID that will be used to effectively make this API call. Only admins and designated users can make API calls on behalf of other users. */ + "run-as"?: string | null; + }; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["WorkflowCreatePayload"]; + }; + }; + responses: { + /** @description Successful Response */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": unknown; + }; + }; + /** @description Request Error */ + "4XX": { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["MessageExceptionModel"]; + }; + }; + /** @description Server Error */ + "5XX": { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["MessageExceptionModel"]; + }; + }; + }; + }; workflow_dict_api_workflows_download__workflow_id__get: { - /** Returns a selected workflow. */ parameters: { - /** @description The history id to import a workflow from. */ - /** @description The default is 'export', which is the meant to be used with workflow import endpoints. Other formats such as 'instance', 'editor', 'run' are more tied to the GUI and should not be considered stable APIs. The default format for 'export' is specified by the admin with the `default_workflow_export_format` config option. Style can be specified as either 'ga' or 'format2' directly to be explicit about which format to download. */ - /** @description The format to download the workflow in. */ - /** @description The version of the workflow to fetch. */ query?: { + /** @description The history id to import a workflow from. */ history_id?: string | null; + /** @description The default is 'export', which is meant to be used with workflow import endpoints. Other formats such as 'instance', 'editor', 'run' are tied to the GUI and should not be considered stable APIs. The default format for 'export' is specified by the admin with the `default_workflow_export_format` config option. Style can be specified as either 'ga' or 'format2' directly to be explicit about which format to download. */ style?: string | null; + /** @description The format to download the workflow in. */ format?: string | null; + /** @description The version of the workflow to fetch. */ version?: number | null; instance?: boolean | null; }; - /** @description The user ID that will be used to effectively make this API call. Only admins and designated users can make API calls on behalf of other users. */ header?: { + /** @description The user ID that will be used to effectively make this API call. Only admins and designated users can make API calls on behalf of other users. */ "run-as"?: string | null; }; - /** @description The encoded database identifier of the Stored Workflow. */ path: { + /** @description The encoded database identifier of the Stored Workflow. */ workflow_id: string; }; + cookie?: never; }; + requestBody?: never; responses: { /** @description Successful Response */ 200: { + headers: { + [name: string]: unknown; + }; content: { "application/json": | components["schemas"]["WorkflowDictEditorSummary"] @@ -33459,10 +34351,22 @@ export interface operations { | components["schemas"]["WorkflowDictFormat2WrappedYamlSummary"]; }; }; - /** @description Validation Error */ - 422: { + /** @description Request Error */ + "4XX": { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["MessageExceptionModel"]; + }; + }; + /** @description Server Error */ + "5XX": { + headers: { + [name: string]: unknown; + }; content: { - "application/json": components["schemas"]["HTTPValidationError"]; + "application/json": components["schemas"]["MessageExceptionModel"]; }; }; }; @@ -33517,6 +34421,51 @@ export interface operations { }; }; }; + set_workflow_menu_api_workflows_menu_put: { + parameters: { + query?: never; + header?: { + /** @description The user ID that will be used to effectively make this API call. Only admins and designated users can make API calls on behalf of other users. */ + "run-as"?: string | null; + }; + path?: never; + cookie?: never; + }; + requestBody?: { + content: { + "application/json": components["schemas"]["SetWorkflowMenuPayload"] | null; + }; + }; + responses: { + /** @description Successful Response */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["SetWorkflowMenuSummary"]; + }; + }; + /** @description Request Error */ + "4XX": { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["MessageExceptionModel"]; + }; + }; + /** @description Server Error */ + "5XX": { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["MessageExceptionModel"]; + }; + }; + }; + }; show_workflow_api_workflows__workflow_id__get: { parameters: { query?: { @@ -33567,6 +34516,56 @@ export interface operations { }; }; }; + update_workflow_api_workflows__workflow_id__put: { + parameters: { + query?: { + instance?: boolean | null; + }; + header?: { + /** @description The user ID that will be used to effectively make this API call. Only admins and designated users can make API calls on behalf of other users. */ + "run-as"?: string | null; + }; + path: { + /** @description The encoded database identifier of the Stored Workflow. */ + workflow_id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["WorkflowUpdatePayload"]; + }; + }; + responses: { + /** @description Successful Response */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["StoredWorkflowDetailed"]; + }; + }; + /** @description Request Error */ + "4XX": { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["MessageExceptionModel"]; + }; + }; + /** @description Server Error */ + "5XX": { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["MessageExceptionModel"]; + }; + }; + }; + }; delete_workflow_api_workflows__workflow_id__delete: { parameters: { query?: never; @@ -33703,39 +34702,62 @@ export interface operations { }; }; workflow_dict_api_workflows__workflow_id__download_get: { - /** Returns a selected workflow. */ parameters: { - /** @description The history id to import a workflow from. */ - /** @description The default is 'export', which is the meant to be used with workflow import endpoints. Other formats such as 'instance', 'editor', 'run' are more tied to the GUI and should not be considered stable APIs. The default format for 'export' is specified by the admin with the `default_workflow_export_format` config option. Style can be specified as either 'ga' or 'format2' directly to be explicit about which format to download. */ - /** @description The format to download the workflow in. */ - /** @description The version of the workflow to fetch. */ query?: { + /** @description The history id to import a workflow from. */ history_id?: string | null; + /** @description The default is 'export', which is meant to be used with workflow import endpoints. Other formats such as 'instance', 'editor', 'run' are tied to the GUI and should not be considered stable APIs. The default format for 'export' is specified by the admin with the `default_workflow_export_format` config option. Style can be specified as either 'ga' or 'format2' directly to be explicit about which format to download. */ style?: string | null; + /** @description The format to download the workflow in. */ format?: string | null; + /** @description The version of the workflow to fetch. */ version?: number | null; instance?: boolean | null; }; - /** @description The user ID that will be used to effectively make this API call. Only admins and designated users can make API calls on behalf of other users. */ header?: { + /** @description The user ID that will be used to effectively make this API call. Only admins and designated users can make API calls on behalf of other users. */ "run-as"?: string | null; }; - /** @description The encoded database identifier of the Stored Workflow. */ path: { + /** @description The encoded database identifier of the Stored Workflow. */ workflow_id: string; }; + cookie?: never; }; + requestBody?: never; responses: { /** @description Successful Response */ 200: { + headers: { + [name: string]: unknown; + }; content: { - "application/json": Record; + "application/json": + | components["schemas"]["WorkflowDictEditorSummary"] + | components["schemas"]["StoredWorkflowDetailed"] + | components["schemas"]["WorkflowDictRunSummary"] + | components["schemas"]["WorkflowDictPreviewSummary"] + | components["schemas"]["WorkflowDictFormat2Summary"] + | components["schemas"]["WorkflowDictExportSummary"] + | components["schemas"]["WorkflowDictFormat2WrappedYamlSummary"]; + }; + }; + /** @description Request Error */ + "4XX": { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["MessageExceptionModel"]; }; }; - /** @description Validation Error */ - 422: { + /** @description Server Error */ + "5XX": { + headers: { + [name: string]: unknown; + }; content: { - "application/json": components["schemas"]["HTTPValidationError"]; + "application/json": components["schemas"]["MessageExceptionModel"]; }; }; };