From 4996f8b7e123b381561f8ff7c8efed4083a3da5d Mon Sep 17 00:00:00 2001 From: John Chilton Date: Thu, 29 Feb 2024 16:57:39 -0500 Subject: [PATCH 1/5] Remove unneeded mixin. This was refactored and the refactored components needs the mixin only I think. xref https://github.com/galaxyproject/galaxy/commit/e28914705e0a4d445c6fc35e0d696ce05f1a6433 --- .../WorkflowInvocationState/WorkflowInvocationState.vue | 2 -- 1 file changed, 2 deletions(-) diff --git a/client/src/components/WorkflowInvocationState/WorkflowInvocationState.vue b/client/src/components/WorkflowInvocationState/WorkflowInvocationState.vue index 3230d485af21..037a7a698c27 100644 --- a/client/src/components/WorkflowInvocationState/WorkflowInvocationState.vue +++ b/client/src/components/WorkflowInvocationState/WorkflowInvocationState.vue @@ -30,7 +30,6 @@ diff --git a/client/src/components/JobStates/mixin.js b/client/src/components/JobStates/mixin.js deleted file mode 100644 index f40ad8d5e521..000000000000 --- a/client/src/components/JobStates/mixin.js +++ /dev/null @@ -1,47 +0,0 @@ -/* VueJS mixin with computed properties from a base jobStatesSummary property for summarizing job states */ -export default { - computed: { - isNew() { - return !this.jobStatesSummary || this.jobStatesSummary.new(); - }, - isErrored() { - return this.jobStatesSummary && this.jobStatesSummary.errored(); - }, - isPopulationFailed() { - return this.jobStatesSummary && this.jobStatesSummary.populationFailed(); - }, - isTerminal() { - return this.jobStatesSummary && this.jobStatesSummary.terminal(); - }, - jobCount() { - return !this.jobStatesSummary ? null : this.jobStatesSummary.jobCount(); - }, - jobsStr() { - const jobCount = this.jobCount; - return jobCount && jobCount > 1 ? `${jobCount} jobs` : `a job`; - }, - runningCount() { - return this.countStates(["running"]); - }, - okCount() { - return this.countStates(["ok", "skipped"]); - }, - errorCount() { - return this.countStates(["error", "deleted"]); - }, - newCount() { - return this.jobCount - this.okCount - this.runningCount - this.errorCount; - }, - }, - methods: { - countStates(states) { - let count = 0; - if (this.jobStatesSummary && this.jobStatesSummary.hasDetails()) { - for (const state of states) { - count += this.jobStatesSummary.states()[state] || 0; - } - } - return count; - }, - }, -}; diff --git a/client/src/components/JobStates/wait.js b/client/src/components/JobStates/wait.js index adae902a84c6..956d44d41cb7 100644 --- a/client/src/components/JobStates/wait.js +++ b/client/src/components/JobStates/wait.js @@ -1,6 +1,6 @@ import axios from "axios"; +import { ERROR_STATES, NON_TERMINAL_STATES } from "components/WorkflowInvocationState/util"; import { getAppRoot } from "onload/loadConfig"; -import JOB_STATES_MODEL from "utils/job-states-model"; export function waitOnJob(jobId, onStateUpdate = null, interval = 1000) { // full=true to capture standard error on last iteration for building @@ -14,9 +14,9 @@ export function waitOnJob(jobId, onStateUpdate = null, interval = 1000) { if (onStateUpdate !== null) { onStateUpdate(state); } - if (JOB_STATES_MODEL.NON_TERMINAL_STATES.indexOf(state) !== -1) { + if (NON_TERMINAL_STATES.indexOf(state) !== -1) { setTimeout(checkCondition, interval, resolve, reject); - } else if (JOB_STATES_MODEL.ERROR_STATES.indexOf(state) !== -1) { + } else if (ERROR_STATES.indexOf(state) !== -1) { reject(jobResponse); } else { resolve(jobResponse); diff --git a/client/src/components/RuleCollectionBuilder.vue b/client/src/components/RuleCollectionBuilder.vue index ba9e57ea7424..2b452512a9d9 100644 --- a/client/src/components/RuleCollectionBuilder.vue +++ b/client/src/components/RuleCollectionBuilder.vue @@ -585,11 +585,11 @@ import SaveRules from "components/RuleBuilder/SaveRules"; import StateDiv from "components/RuleBuilder/StateDiv"; import Select2 from "components/Select2"; import UploadUtils from "components/Upload/utils"; +import { ERROR_STATES, NON_TERMINAL_STATES } from "components/WorkflowInvocationState/util"; import $ from "jquery"; import { getAppRoot } from "onload/loadConfig"; import _ from "underscore"; import { refreshContentsWrapper } from "utils/data"; -import JobStatesModel from "utils/job-states-model"; import _l from "utils/localization"; import Vue from "vue"; @@ -1337,9 +1337,9 @@ export default { const handleJobShow = (jobResponse) => { const state = jobResponse.data.state; this.waitingJobState = state; - if (JobStatesModel.NON_TERMINAL_STATES.indexOf(state) !== -1) { + if (NON_TERMINAL_STATES.indexOf(state) !== -1) { setTimeout(doJobCheck, 1000); - } else if (JobStatesModel.ERROR_STATES.indexOf(state) !== -1) { + } else if (ERROR_STATES.indexOf(state) !== -1) { this.state = "error"; this.errorMessage = "Unknown error encountered while running your upload job, this could be a server issue or a problem with the upload definition."; diff --git a/client/src/components/WorkflowInvocationState/WorkflowInvocationState.test.ts b/client/src/components/WorkflowInvocationState/WorkflowInvocationState.test.ts index cae244c78bd3..c61108f4a5f6 100644 --- a/client/src/components/WorkflowInvocationState/WorkflowInvocationState.test.ts +++ b/client/src/components/WorkflowInvocationState/WorkflowInvocationState.test.ts @@ -34,7 +34,7 @@ async function mountWorkflowInvocationState(invocation: WorkflowInvocation | nul }, computed: { invocation: () => invocation, - jobStatesSummary: () => new JOB_STATES_MODEL.JobStatesSummary(invocationJobsSummaryById), + jobStatesSummary: () => invocationJobsSummaryById, }, pinia, localVue, diff --git a/client/src/components/WorkflowInvocationState/WorkflowInvocationState.vue b/client/src/components/WorkflowInvocationState/WorkflowInvocationState.vue index 037a7a698c27..2b734f4bcfb2 100644 --- a/client/src/components/WorkflowInvocationState/WorkflowInvocationState.vue +++ b/client/src/components/WorkflowInvocationState/WorkflowInvocationState.vue @@ -31,11 +31,11 @@ + - diff --git a/client/src/components/WorkflowInvocationState/util.ts b/client/src/components/WorkflowInvocationState/util.ts new file mode 100644 index 000000000000..bbda2253e933 --- /dev/null +++ b/client/src/components/WorkflowInvocationState/util.ts @@ -0,0 +1,71 @@ +import { InvocationJobsSummary } from "@/api/invocations"; + +export const NON_TERMINAL_STATES = ["new", "queued", "running", "waiting"]; +export const ERROR_STATES = ["error", "deleted"]; +export const TERMINAL_STATES = ["ok", "skipped"].concat(ERROR_STATES); +export const POPULATED_STATE_FAILED = "failed"; + +function countStates(jobSummary: InvocationJobsSummary | null, queryStates: string[]): number { + let count = 0; + const states = jobSummary?.states; + if (states) { + for (const state of queryStates) { + count += jobSummary.states[state] || 0; + } + } + return count; +} + +export function jobCount(jobSummary: InvocationJobsSummary | null) { + const states = jobSummary?.states; + let count = 0; + if (states) { + for (const index in states) { + const stateCount = states[index]; + if (stateCount) { + count += stateCount; + } + } + } + return count; +} + +export function okCount(jobSummary: InvocationJobsSummary): number { + return countStates(jobSummary, ["ok", "skipped"]); +} + +export function runningCount(jobSummary: InvocationJobsSummary): number { + return countStates(jobSummary, ["running"]); +} + +export function numTerminal(jobSummary: InvocationJobsSummary): number { + return countStates(jobSummary, TERMINAL_STATES); +} + +export function errorCount(jobSummary: InvocationJobsSummary): number { + return countStates(jobSummary, ERROR_STATES); +} + +function isNew(jobSummary: InvocationJobsSummary) { + return jobSummary.populated_state && jobSummary.populated_state == "new"; +} + +function anyWithStates(jobSummary: InvocationJobsSummary, queryStates: string[]) { + const states = jobSummary.states; + for (const index in queryStates) { + const state: string = queryStates[index] as string; + if ((states[state] || 0) > 0) { + return true; + } + } + return false; +} + +export function isTerminal(jobSummary: InvocationJobsSummary) { + if (isNew(jobSummary)) { + return false; + } else { + const anyNonTerminal = anyWithStates(jobSummary, NON_TERMINAL_STATES); + return !anyNonTerminal; + } +} diff --git a/client/src/components/admin/JobsList.vue b/client/src/components/admin/JobsList.vue index 25045f328325..98a3a782874d 100644 --- a/client/src/components/admin/JobsList.vue +++ b/client/src/components/admin/JobsList.vue @@ -101,8 +101,8 @@ import JobsTable from "components/admin/JobsTable"; import Heading from "components/Common/Heading"; import filtersMixin from "components/Indices/filtersMixin"; import { jobsProvider } from "components/providers/JobProvider"; +import { NON_TERMINAL_STATES } from "components/WorkflowInvocationState/util"; import { getAppRoot } from "onload/loadConfig"; -import JOB_STATES_MODEL from "utils/job-states-model"; import { errorMessageAsString } from "utils/simple-error"; import { commonJobFields } from "./JobFields"; @@ -211,7 +211,7 @@ export default { const unfinishedJobs = []; const finishedJobs = []; newVal.forEach((item) => { - if (JOB_STATES_MODEL.NON_TERMINAL_STATES.includes(item.state)) { + if (NON_TERMINAL_STATES.includes(item.state)) { unfinishedJobs.push(item); } else { finishedJobs.push(item); diff --git a/client/src/components/providers/utils.js b/client/src/components/providers/utils.js index 04d0626ace8b..7ac65b87c039 100644 --- a/client/src/components/providers/utils.js +++ b/client/src/components/providers/utils.js @@ -1,8 +1,8 @@ +import { NON_TERMINAL_STATES } from "components/WorkflowInvocationState/util"; import { snakeCase } from "lodash"; -import JOB_STATES_MODEL from "utils/job-states-model"; export function stateIsTerminal(result) { - return !JOB_STATES_MODEL.NON_TERMINAL_STATES.includes(result.state); + return !NON_TERMINAL_STATES.includes(result.state); } export const HasAttributesMixin = { diff --git a/client/src/utils/job-states-model.js b/client/src/utils/job-states-model.js deleted file mode 100644 index 73fbbc4782c4..000000000000 --- a/client/src/utils/job-states-model.js +++ /dev/null @@ -1,101 +0,0 @@ -import Backbone from "backbone"; -import { getAppRoot } from "onload/loadConfig"; - -var NON_TERMINAL_STATES = ["new", "queued", "running", "waiting"]; -var ERROR_STATES = ["error", "deleted"]; -var TERMINAL_STATES = ["ok", "skipped"].concat(ERROR_STATES); -const POPULATED_STATE_FAILED = "failed"; -/** Fetch state on add or just wait for polling to start. */ -var FETCH_STATE_ON_ADD = false; - -var JobStatesSummary = Backbone.Model.extend({ - url: function () { - return `${getAppRoot()}api/histories/${this.attributes.history_id}/contents/dataset_collections/${ - this.attributes.collection_id - }/jobs_summary`; - }, - - hasDetails: function () { - return this.has("populated_state"); - }, - - new: function () { - return !this.hasDetails() || this.get("populated_state") == "new"; - }, - - populationFailed: function () { - return this.get("populated_state") === POPULATED_STATE_FAILED; - }, - - errored: function () { - return this.populationFailed() || this.anyWithStates(ERROR_STATES); - }, - - states: function () { - return this.get("states") || {}; - }, - - anyWithState: function (queryState) { - return (this.states()[queryState] || 0) > 0; - }, - - anyWithStates: function (queryStates) { - var states = this.states(); - for (var index in queryStates) { - if ((states[queryStates[index]] || 0) > 0) { - return true; - } - } - return false; - }, - - numWithStates: function (queryStates) { - var states = this.states(); - var count = 0; - for (var index in queryStates) { - count += states[queryStates[index]] || 0; - } - return count; - }, - - numInError: function () { - return this.numWithStates(ERROR_STATES); - }, - - numTerminal: function () { - return this.numWithStates(TERMINAL_STATES); - }, - - running: function () { - return this.anyWithState("running"); - }, - - terminal: function () { - if (this.new()) { - return false; - } else { - var anyNonTerminal = this.anyWithStates(NON_TERMINAL_STATES); - return !anyNonTerminal; - } - }, - - jobCount: function () { - var states = this.states(); - var count = 0; - for (var index in states) { - count += states[index]; - } - return count; - }, - - toString: function () { - return `JobStatesSummary(id=${this.get("id")})`; - }, -}); - -export default { - JobStatesSummary, - FETCH_STATE_ON_ADD, - NON_TERMINAL_STATES, - ERROR_STATES, -}; From 853fb92c9c85296e79d50b20b898a34f43bba2ca Mon Sep 17 00:00:00 2001 From: John Chilton Date: Mon, 4 Mar 2024 18:20:03 -0500 Subject: [PATCH 4/5] Cleanup invocation typing a bit. --- client/src/api/invocations.ts | 9 +++------ .../WorkflowInvocationSummary.vue | 4 ++-- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/client/src/api/invocations.ts b/client/src/api/invocations.ts index 2a10cf62d20e..88c34695fb8c 100644 --- a/client/src/api/invocations.ts +++ b/client/src/api/invocations.ts @@ -4,17 +4,14 @@ import { getAppRoot } from "@/onload"; import { ApiResponse, components, fetcher } from "./schema"; -// TODO: rename... -export type WorkflowInvocationSummary = components["schemas"]["WorkflowInvocationElementView"]; +export type WorkflowInvocationElementView = components["schemas"]["WorkflowInvocationElementView"]; +export type WorkflowInvocationCollectionView = components["schemas"]["WorkflowInvocationCollectionView"]; export type InvocationJobsSummary = components["schemas"]["InvocationJobsResponse"]; export type InvocationStep = components["schemas"]["InvocationStep"]; export const invocationsFetcher = fetcher.path("/api/invocations").method("get").create(); -// TODO: Replace these interfaces with real schema models after https://github.com/galaxyproject/galaxy/pull/16707 is merged -export interface WorkflowInvocation { - id: string; -} +export type WorkflowInvocation = WorkflowInvocationElementView | WorkflowInvocationCollectionView; export interface WorkflowInvocationJobsSummary { id: string; diff --git a/client/src/components/WorkflowInvocationState/WorkflowInvocationSummary.vue b/client/src/components/WorkflowInvocationState/WorkflowInvocationSummary.vue index ccc0c001d780..28ddeaa0eae1 100644 --- a/client/src/components/WorkflowInvocationState/WorkflowInvocationSummary.vue +++ b/client/src/components/WorkflowInvocationState/WorkflowInvocationSummary.vue @@ -1,7 +1,7 @@