From e93ea2a665910be3d81292d46c9745ac962cf3ff Mon Sep 17 00:00:00 2001 From: John Chilton Date: Sat, 17 Feb 2024 13:37:36 -0500 Subject: [PATCH] Display workflow invocation counts. Performance: Workflows render fine without the data, data is fetched asynchronously from other queries, joins only happen across a couple of fields that are all indexed, avoiding serializing objects and such - the SQL is quite low-level. --- client/src/api/schema/schema.ts | 39 +++++++++++++++++++ client/src/api/workflows.ts | 2 + .../Workflow/WorkflowInvocationsCount.vue | 33 ++++++++++++++++ lib/galaxy/model/__init__.py | 15 +++++++ lib/galaxy/schema/schema.py | 3 ++ lib/galaxy/webapps/galaxy/api/workflows.py | 33 +++++++++++----- .../webapps/galaxy/services/workflows.py | 16 ++++++-- test/unit/data/test_galaxy_mapping.py | 18 +++++++++ 8 files changed, 147 insertions(+), 12 deletions(-) diff --git a/client/src/api/schema/schema.ts b/client/src/api/schema/schema.ts index b888d567942d..75c9b078677c 100644 --- a/client/src/api/schema/schema.ts +++ b/client/src/api/schema/schema.ts @@ -1793,6 +1793,10 @@ export interface paths { /** Add the deleted flag to a workflow. */ delete: operations["delete_workflow_api_workflows__workflow_id__delete"]; }; + "/api/workflows/{workflow_id}/counts": { + /** Get state counts for accessible workflow. */ + get: operations["workflows__invocation_counts"]; + }; "/api/workflows/{workflow_id}/disable_link_access": { /** * Makes this item inaccessible by a URL link. @@ -9559,6 +9563,10 @@ export interface components { */ url: string; }; + /** RootModel[Dict[str, int]] */ + RootModel_Dict_str__int__: { + [key: string]: number | undefined; + }; /** SearchJobsPayload */ SearchJobsPayload: { /** @@ -21503,6 +21511,37 @@ export interface operations { }; }; }; + workflows__invocation_counts: { + /** Get state counts for accessible workflow. */ + parameters: { + /** @description Is provided workflow id for Workflow instead of StoredWorkflow? */ + query?: { + 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": components["schemas"]["RootModel_Dict_str__int__"]; + }; + }; + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"]; + }; + }; + }; + }; disable_link_access_api_workflows__workflow_id__disable_link_access_put: { /** * Makes this item inaccessible by a URL link. diff --git a/client/src/api/workflows.ts b/client/src/api/workflows.ts index 168e85ed00c4..0febc403426d 100644 --- a/client/src/api/workflows.ts +++ b/client/src/api/workflows.ts @@ -1,3 +1,5 @@ import { fetcher } from "@/api/schema"; export const workflowsFetcher = fetcher.path("/api/workflows").method("get").create(); + +export const invocationCountsFetcher = fetcher.path("/api/workflows/{workflow_id}/counts").method("get").create(); diff --git a/client/src/components/Workflow/WorkflowInvocationsCount.vue b/client/src/components/Workflow/WorkflowInvocationsCount.vue index 16c150ab605e..a55638142380 100644 --- a/client/src/components/Workflow/WorkflowInvocationsCount.vue +++ b/client/src/components/Workflow/WorkflowInvocationsCount.vue @@ -2,8 +2,10 @@ import { library } from "@fortawesome/fontawesome-svg-core"; import { faClock, faSitemap } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome"; +import { onMounted, ref } from "vue"; import { useRouter } from "vue-router/composables"; +import { invocationCountsFetcher } from "@/api/workflows"; import localize from "@/utils/localization"; library.add(faClock, faSitemap); @@ -16,6 +18,21 @@ const props = defineProps(); const router = useRouter(); +const count = ref(undefined); + +async function initCounts() { + const { data } = await invocationCountsFetcher({ workflow_id: props.workflow.id }); + let allCounts = 0; + for (const stateCount of Object.values(data)) { + if (stateCount) { + allCounts += stateCount; + } + } + count.value = allCounts; +} + +onMounted(initCounts); + function onInvocations() { router.push(`/workflows/${props.workflow.id}/invocations`); } @@ -23,7 +40,23 @@ function onInvocations() {