From 3469dda0e12a87187d3b43637de66a33052d3e4d Mon Sep 17 00:00:00 2001 From: luyaguari3 Date: Mon, 1 Nov 2021 22:41:17 -0400 Subject: [PATCH] minor fixes --- .../src/SDLCServerClient.ts | 32 +- .../editor/side-bar/WorkspaceWorkflows.tsx | 128 +++--- .../sidebar-state/WorkspaceWorkflowsState.ts | 394 +++++++++--------- 3 files changed, 295 insertions(+), 259 deletions(-) diff --git a/packages/legend-server-sdlc/src/SDLCServerClient.ts b/packages/legend-server-sdlc/src/SDLCServerClient.ts index fc4c8a3864d..53c79010912 100644 --- a/packages/legend-server-sdlc/src/SDLCServerClient.ts +++ b/packages/legend-server-sdlc/src/SDLCServerClient.ts @@ -367,7 +367,7 @@ export class SDLCServerClient extends AbstractServerClient { projectId: string, workspace: Workspace | undefined, workflowId: string, - ): Promise[]> => + ): Promise> => this.networkClient.get(this._workflow(projectId, workspace, workflowId)); getWorkflows = ( projectId: string, @@ -382,30 +382,30 @@ export class SDLCServerClient extends AbstractServerClient { undefined, { status, revisionIds, limit }, ); - getWorkflowJobs = ( + getWorkflowsByRevision = ( projectId: string, workspace: Workspace | undefined, - workflowId: string, - status: WorkflowStatus | undefined, - revisionIds: string[] | undefined, - limit: number | undefined, + revisionId: string | RevisionAlias, ): Promise[]> => this.networkClient.get( - this._workflowJobs(projectId, workspace, workflowId), + this._workflows(projectId, workspace), undefined, undefined, - { status, revisionIds, limit }, + { revisionId }, ); - getWorkflowsByRevision = ( + getWorkflowJobs = ( projectId: string, workspace: Workspace | undefined, - revisionId: string | RevisionAlias, - ): Promise[]> => + workflowId: string, + status: WorkflowStatus | undefined, + revisionIds: string[] | undefined, + limit: number | undefined, + ): Promise[]> => this.networkClient.get( - this._workflows(projectId, workspace), + this._workflowJobs(projectId, workspace, workflowId), undefined, undefined, - { revisionId }, + { status, revisionIds, limit }, ); getWorkflowJob = ( projectId: string, @@ -439,7 +439,7 @@ export class SDLCServerClient extends AbstractServerClient { projectId: string, workspace: Workspace | undefined, workflowJob: WorkflowJob, - ): Promise => + ): Promise> => this.networkClient.post( `${this._workflowJob( projectId, @@ -452,7 +452,7 @@ export class SDLCServerClient extends AbstractServerClient { projectId: string, workspace: Workspace | undefined, workflowJob: WorkflowJob, - ): Promise => + ): Promise> => this.networkClient.post( `${this._workflowJob( projectId, @@ -465,7 +465,7 @@ export class SDLCServerClient extends AbstractServerClient { projectId: string, workspace: Workspace | undefined, workflowJob: WorkflowJob, - ): Promise => + ): Promise> => this.networkClient.post( `${this._workflowJob( projectId, diff --git a/packages/legend-studio/src/components/editor/side-bar/WorkspaceWorkflows.tsx b/packages/legend-studio/src/components/editor/side-bar/WorkspaceWorkflows.tsx index bc94fcc7bce..fe4d2181bdc 100644 --- a/packages/legend-studio/src/components/editor/side-bar/WorkspaceWorkflows.tsx +++ b/packages/legend-studio/src/components/editor/side-bar/WorkspaceWorkflows.tsx @@ -49,12 +49,17 @@ import type { WorkflowExplorerTreeNodeData, WorkflowLogState, WorkspaceWorkflowsState, + WorkspaceWorkflowState, } from '../../../stores/sidebar-state/WorkspaceWorkflowsState'; import { WorkflowJobTreeNodeData, WorkflowTreeNodeData, } from '../../../stores/sidebar-state/WorkspaceWorkflowsState'; -import { guaranteeType, isNonNullable } from '@finos/legend-shared'; +import { + guaranteeNonNullable, + guaranteeType, + isNonNullable, +} from '@finos/legend-shared'; import { Dialog } from '@material-ui/core'; import { StudioTextInputEditor } from '../../shared/StudioTextInputEditor'; @@ -188,21 +193,21 @@ const WorkflowJobLogsViewer = observer( logState: WorkflowLogState; }) => { const { workflowState, logState } = props; - const job = logState.job; + const job = guaranteeNonNullable(logState.job); const jobIsInProgress = job.status === WorkflowJobStatus.IN_PROGRESS; const closeLogViewer = (): void => { - workflowState.setWorkflowJobLogState(undefined); - flowResult(workflowState.refreshWorkflows()).catch( + logState.closeModal(); + flowResult(workflowState.fetchAllWorkspaceWorkflows()).catch( workflowState.editorStore.applicationStore.alertIllegalUnhandledError, ); }; const refreshLogs = (): void => { - logState.refreshJobLogs(); + logState.refreshJobLogs(job); }; const logs = logState.logs; return (
+
{`Logs for ${job.name} #${job.id}`}
@@ -248,13 +256,14 @@ const WorkflowJobLogsViewer = observer( const WorkflowExplorerContextMenu = observer( ( props: { - workflowState: WorkspaceWorkflowsState; + workflowsState: WorkspaceWorkflowsState; + workflowState: WorkspaceWorkflowState; node: WorkflowExplorerTreeNodeData; treeData: TreeData; }, ref: React.Ref, ) => { - const { node, workflowState, treeData } = props; + const { node, workflowsState, workflowState, treeData } = props; const retryJob = (): void => { if (node instanceof WorkflowJobTreeNodeData) { workflowState.retryJob(node.workflowJob, treeData); @@ -267,7 +276,7 @@ const WorkflowExplorerContextMenu = observer( }; const viewLogs = (): void => { if (node instanceof WorkflowJobTreeNodeData) { - workflowState.viewJobLogs(node.workflowJob); + workflowsState.logState.viewJobLogs(node.workflowJob); } }; const visitWeburl = (): void => { @@ -311,13 +320,14 @@ const WorkflowTreeNodeContainer: React.FC< TreeNodeContainerProps< WorkflowExplorerTreeNodeData, { - workflowState: WorkspaceWorkflowsState; + workflowsState: WorkspaceWorkflowsState; + workflowState: WorkspaceWorkflowState; treeData: TreeData; } > > = (props) => { const { node, level, stepPaddingInRem, onNodeSelect } = props; - const { workflowState, treeData } = props.innerProps; + const { workflowsState, treeData, workflowState } = props.innerProps; const expandIcon = !(node instanceof WorkflowTreeNodeData) ? (
) : node.isOpen ? ( @@ -336,6 +346,7 @@ const WorkflowTreeNodeContainer: React.FC< { const editorStore = useEditorStore(); const applicationStore = useApplicationStore(); - const workflowState = editorStore.workspaceWorkflowsState; - const workflowTreeData = workflowState.workflowTreeData; - const isDispatchingAction = workflowState.isExecutingWorkflowRequest; + const workflowsState = editorStore.workspaceWorkflowsState; + const logState = workflowsState.logState; + const isDispatchingAction = + workflowsState.fetchWorkflowsState.isInProgress || + Boolean( + workflowsState.workflowStates.find((e) => e.isExecutingWorkflowRequest), + ); const refresh = applicationStore.guaranteeSafeAction(() => - flowResult(workflowState.refreshWorkflows()), + flowResult(workflowsState.fetchAllWorkspaceWorkflows()), ); - const onNodeSelect = (node: WorkflowExplorerTreeNodeData): void => { - if (workflowTreeData) { - workflowState.onTreeNodeSelect(node, workflowTreeData); - } - }; - - const getChildNodes = ( - node: WorkflowExplorerTreeNodeData, - ): WorkflowExplorerTreeNodeData[] => { - if ( - node.childrenIds && - node instanceof WorkflowTreeNodeData && - workflowTreeData - ) { - return node.childrenIds - .map((id) => workflowTreeData.nodes.get(id)) - .filter(isNonNullable); - } - return []; - }; - useEffect(() => { - flowResult(workflowState.fetchAllWorkspaceWorkflows()).catch( + flowResult(workflowsState.fetchAllWorkspaceWorkflows()).catch( applicationStore.alertIllegalUnhandledError, ); - }, [applicationStore, workflowState]); + }, [applicationStore, workflowsState]); return (
@@ -462,7 +456,7 @@ export const WorkspaceWorkflows = observer(() => { isDispatchingAction, }, )} - disabled={isDispatchingAction || !workflowTreeData} + disabled={isDispatchingAction} onClick={refresh} tabIndex={-1} title="Refresh" @@ -482,30 +476,50 @@ export const WorkspaceWorkflows = observer(() => { className="side-bar__panel__header__changes-count" data-testid={STUDIO_TEST_ID.SIDEBAR_PANEL_HEADER__CHANGES_COUNT} > - {workflowState.workflows.length} + {workflowsState.workflowStates.length}
- {workflowTreeData && ( - - )} + {workflowsState.workflowStates.map((workflowState) => { + const onNodeSelect = ( + node: WorkflowExplorerTreeNodeData, + ): void => { + workflowState.onTreeNodeSelect(node, workflowState.treeData); + }; + const getChildNodes = ( + node: WorkflowExplorerTreeNodeData, + ): WorkflowExplorerTreeNodeData[] => { + if (node.childrenIds && node instanceof WorkflowTreeNodeData) { + return node.childrenIds + .map((id) => workflowState.treeData.nodes.get(id)) + .filter(isNonNullable); + } + return []; + }; + + return ( + + ); + })}
- {workflowState.workflowJobLogState && ( + {logState.job && ( )}
diff --git a/packages/legend-studio/src/stores/sidebar-state/WorkspaceWorkflowsState.ts b/packages/legend-studio/src/stores/sidebar-state/WorkspaceWorkflowsState.ts index f7f09f439d0..5fa437a5d6d 100644 --- a/packages/legend-studio/src/stores/sidebar-state/WorkspaceWorkflowsState.ts +++ b/packages/legend-studio/src/stores/sidebar-state/WorkspaceWorkflowsState.ts @@ -21,9 +21,11 @@ import type { EditorStore } from '../EditorStore'; import type { EditorSdlcState } from '../EditorSdlcState'; import type { GeneratorFn, PlainObject } from '@finos/legend-shared'; import { + uuid, assertErrorThrown, LogEvent, isNonNullable, + ActionState, } from '@finos/legend-shared'; import { WorkflowJob, Workflow } from '@finos/legend-server-sdlc'; @@ -38,31 +40,24 @@ export abstract class WorkflowExplorerTreeNodeData implements TreeNodeData { this.label = label; } } +const getWorkflowNodeId = (workflowId: string): string => + `workflow_${workflowId}`; +const getJobId = (jobId: string): string => `job_${jobId}`; export class WorkflowTreeNodeData extends WorkflowExplorerTreeNodeData { workflow: Workflow; constructor(workflow: Workflow) { - super(workflow.id, workflow.id); + super(getWorkflowNodeId(workflow.id), workflow.id); this.workflow = workflow; } } export class WorkflowJobTreeNodeData extends WorkflowExplorerTreeNodeData { workflowJob: WorkflowJob; constructor(workflowJob: WorkflowJob) { - super(workflowJob.id, workflowJob.name); + super(getJobId(workflowJob.id), workflowJob.name); this.workflowJob = workflowJob; } } -const addWorkflowNodeToTree = ( - workflow: Workflow, - treeData: TreeData, -): WorkflowTreeNodeData => { - const node = new WorkflowTreeNodeData(workflow); - treeData.rootIds.push(node.id); - treeData.nodes.set(node.id, node); - return node; -}; - const addWorkflowJobNodeToTree = ( workflowJob: WorkflowJob, workflowNode: WorkflowTreeNodeData, @@ -79,22 +74,12 @@ const addWorkflowJobNodeToTree = ( return node; }; -const getWorkflowExplorerTreeNodeData = ( - workflows: Workflow[], -): TreeData => { - const rootIds: string[] = []; - const nodes = new Map(); - const treeData = { rootIds, nodes }; - workflows.forEach((w) => addWorkflowNodeToTree(w, treeData)); - return treeData; -}; - const updateWorkflowJobData = ( workflowJobs: WorkflowJob[], workflowId: string, treeData: TreeData, ): void => { - const workflowNode = treeData.nodes.get(workflowId); + const workflowNode = treeData.nodes.get(getWorkflowNodeId(workflowId)); if (workflowNode instanceof WorkflowTreeNodeData) { workflowNode.childrenIds?.forEach((id) => treeData.nodes.delete(id)); workflowNode.childrenIds = []; @@ -106,44 +91,84 @@ const updateWorkflowJobData = ( export class WorkflowLogState { editorStore: EditorStore; - job: WorkflowJob; + sdlcState: EditorSdlcState; + job: WorkflowJob | undefined; logs: string; - constructor(editorStore: EditorStore, job: WorkflowJob, logs: string) { + fetchJobLogState = ActionState.create(); + + constructor( + editorStore: EditorStore, + sdlcState: EditorSdlcState, + job: WorkflowJob | undefined, + logs: string | undefined, + ) { makeAutoObservable(this, { editorStore: false, job: observable, logs: observable, + setLogs: action, + setJob: action, }); this.editorStore = editorStore; + this.sdlcState = sdlcState; this.job = job; - this.logs = logs; + this.logs = logs ?? ''; } setLogs(val: string): void { this.logs = val; } - setJob(val: WorkflowJob): void { + setJob(val: WorkflowJob | undefined): void { this.job = val; } - *refreshJobLogs(): GeneratorFn { + closeModal(): void { + this.setJob(undefined); + this.setLogs(''); + } + + *refreshJobLogs(workflowJob: WorkflowJob): GeneratorFn { try { + this.fetchJobLogState.inProgress(); const job = WorkflowJob.serialization.fromJson( (yield this.editorStore.sdlcServerClient.getWorkflowJob( this.editorStore.sdlcState.activeProject.projectId, this.editorStore.sdlcState.activeWorkspace, - this.job, + workflowJob, )) as PlainObject, ); + this.setJob(job); const logs = (yield this.editorStore.sdlcServerClient.getWorkflowJobLogs( this.editorStore.sdlcState.activeProject.projectId, this.editorStore.sdlcState.activeWorkspace, - this.job, + job, + )) as string; + this.setLogs(logs); + this.fetchJobLogState.pass(); + } catch (error) { + assertErrorThrown(error); + this.editorStore.applicationStore.log.error( + LogEvent.create(STUDIO_LOG_EVENT.SDLC_MANAGER_FAILURE), + error, + ); + this.editorStore.applicationStore.notifyError(error); + this.fetchJobLogState.fail(); + } + } + + *viewJobLogs(workflowJob: WorkflowJob): GeneratorFn { + try { + this.setJob(workflowJob); + this.fetchJobLogState.inProgress(); + const logs = (yield this.editorStore.sdlcServerClient.getWorkflowJobLogs( + this.sdlcState.activeProject.projectId, + this.sdlcState.activeWorkspace, + workflowJob, )) as string; - this.setJob(job); this.setLogs(logs); + this.fetchJobLogState.pass(); } catch (error) { assertErrorThrown(error); this.editorStore.applicationStore.log.error( @@ -151,146 +176,54 @@ export class WorkflowLogState { error, ); this.editorStore.applicationStore.notifyError(error); + this.fetchJobLogState.fail(); } } } -export class WorkspaceWorkflowsState { +export class WorkspaceWorkflowState { + uuid = uuid(); editorStore: EditorStore; sdlcState: EditorSdlcState; + treeData: TreeData; isExecutingWorkflowRequest = false; - workflows: Workflow[] = []; - workflowTreeData: TreeData | undefined; - workflowJobLogState: WorkflowLogState | undefined; - constructor(editorStore: EditorStore, sdlcState: EditorSdlcState) { + constructor( + editorStore: EditorStore, + sdlcState: EditorSdlcState, + workflow: Workflow, + jobs: WorkflowJob[] | undefined, + ) { makeAutoObservable(this, { editorStore: false, - sdlcState: false, - workflowTreeData: observable, + treeData: observable.ref, setWorkflowTreeData: action, - setWorkflowJobLogState: action, - workflowJobLogState: observable, }); this.editorStore = editorStore; this.sdlcState = sdlcState; + this.treeData = this.buildTreeData(workflow, jobs); } - setWorkflowTreeData( - val: TreeData | undefined, - ): void { - this.workflowTreeData = val; - } - - setWorkflowJobLogState(val: WorkflowLogState | undefined): void { - this.workflowJobLogState = val; - } - - *fetchAllWorkspaceWorkflows(): GeneratorFn { - try { - this.isExecutingWorkflowRequest = true; - const workflows = ( - (yield this.editorStore.sdlcServerClient.getWorkflows( - this.sdlcState.activeProject.projectId, - this.sdlcState.activeWorkspace, - undefined, - undefined, - undefined, - )) as PlainObject[] - ).map((workflow) => Workflow.serialization.fromJson(workflow)); - this.setWorkflowTreeData(getWorkflowExplorerTreeNodeData(workflows)); - } catch (error) { - assertErrorThrown(error); - this.editorStore.applicationStore.log.error( - LogEvent.create(STUDIO_LOG_EVENT.SDLC_MANAGER_FAILURE), - error, - ); - this.editorStore.applicationStore.notifyError(error); - } finally { - this.isExecutingWorkflowRequest = false; - } - } - - *refreshWorkflows(): GeneratorFn { - try { - this.isExecutingWorkflowRequest = true; - const workflows = ( - (yield this.editorStore.sdlcServerClient.getWorkflows( - this.sdlcState.activeProject.projectId, - this.sdlcState.activeWorkspace, - undefined, - undefined, - undefined, - )) as PlainObject[] - ).map((workflow) => Workflow.serialization.fromJson(workflow)); - const treeData = getWorkflowExplorerTreeNodeData(workflows); - // refetch open nodes - const currentTreeData = this.workflowTreeData; - if (currentTreeData) { - const openNodeIds = Array.from(currentTreeData.nodes.values()) - .filter((n) => n.isOpen) - .map((n) => n.id); - const workflowToJobsMap = new Map(); - yield Promise.all( - workflows - .filter((workflow) => openNodeIds.includes(workflow.id)) - .map((workflow) => - this.editorStore.sdlcServerClient - .getWorkflowJobs( - this.sdlcState.activeProject.projectId, - this.sdlcState.activeWorkspace, - workflow.id, - undefined, - undefined, - undefined, - ) - .then((jobs: PlainObject[]) => - workflowToJobsMap.set( - workflow.id, - jobs.map((x) => WorkflowJob.serialization.fromJson(x)), - ), - ), - ), - ); - workflowToJobsMap.forEach((jobs, workflowId) => - updateWorkflowJobData(jobs, workflowId, treeData), - ); - treeData.nodes.forEach((node) => { - if (openNodeIds.includes(node.id)) { - node.isOpen = true; - } - }); - } - this.setWorkflowTreeData({ ...treeData }); - } catch (error) { - assertErrorThrown(error); - this.editorStore.applicationStore.log.error( - LogEvent.create(STUDIO_LOG_EVENT.SDLC_MANAGER_FAILURE), - error, - ); - this.editorStore.applicationStore.notifyError(error); - } finally { - this.isExecutingWorkflowRequest = false; - } + setWorkflowTreeData(val: TreeData): void { + this.treeData = val; } - *refreshWorkflow( - workflowId: string, - treeData: TreeData, - ): GeneratorFn { - const node = treeData.nodes.get(workflowId); - if (node instanceof WorkflowTreeNodeData) { - const workflow = Workflow.serialization.fromJson( - (yield this.editorStore.sdlcServerClient.getWorkflow( - this.sdlcState.activeProject.projectId, - this.sdlcState.activeWorkspace, - workflowId, - )) as PlainObject, - ); - node.workflow = workflow; + buildTreeData( + workflow: Workflow, + jobs: WorkflowJob[] | undefined, + ): TreeData { + const rootIds: string[] = []; + const nodes = new Map(); + const treeData = { rootIds, nodes }; + const workflowNode = new WorkflowTreeNodeData(workflow); + treeData.rootIds.push(workflowNode.id); + treeData.nodes.set(workflowNode.id, workflowNode); + if (jobs) { + workflowNode.isOpen = true; + updateWorkflowJobData(jobs, workflow.id, treeData); } - yield flowResult(this.fetchAllWorkspaceWorkJobs(workflowId, treeData)); + return treeData; } *fetchAllWorkspaceWorkJobs( @@ -323,6 +256,33 @@ export class WorkspaceWorkflowsState { } } + *onTreeNodeSelect( + node: WorkflowExplorerTreeNodeData, + treeData: TreeData, + ): GeneratorFn { + if (node instanceof WorkflowTreeNodeData) { + if (!node.childrenIds) { + yield flowResult( + this.fetchAllWorkspaceWorkJobs(node.workflow.id, treeData), + ); + } + node.isOpen = !node.isOpen; + } + this.setWorkflowTreeData({ ...treeData }); + } + + getChildNodes( + node: WorkflowExplorerTreeNodeData, + treeData: TreeData, + ): WorkflowExplorerTreeNodeData[] { + if (node.childrenIds && node instanceof WorkflowTreeNodeData) { + return node.childrenIds + .map((id) => treeData.nodes.get(id)) + .filter(isNonNullable); + } + return []; + } + *cancelJob( workflowJob: WorkflowJob, treeData: TreeData, @@ -347,6 +307,24 @@ export class WorkspaceWorkflowsState { } } + *refreshWorkflow( + workflowId: string, + treeData: TreeData, + ): GeneratorFn { + const node = treeData.nodes.get(getWorkflowNodeId(workflowId)); + if (node instanceof WorkflowTreeNodeData) { + const workflow = Workflow.serialization.fromJson( + (yield this.editorStore.sdlcServerClient.getWorkflow( + this.sdlcState.activeProject.projectId, + this.sdlcState.activeWorkspace, + workflowId, + )) as PlainObject, + ); + node.workflow = workflow; + } + yield flowResult(this.fetchAllWorkspaceWorkJobs(workflowId, treeData)); + } + *retryJob( workflowJob: WorkflowJob, treeData: TreeData, @@ -370,45 +348,90 @@ export class WorkspaceWorkflowsState { this.isExecutingWorkflowRequest = false; } } +} - *onTreeNodeSelect( - node: WorkflowExplorerTreeNodeData, - treeData: TreeData, - ): GeneratorFn { - if (node instanceof WorkflowTreeNodeData) { - if (!node.childrenIds) { - yield flowResult( - this.fetchAllWorkspaceWorkJobs(node.workflow.id, treeData), - ); - } - node.isOpen = !node.isOpen; - } - this.setWorkflowTreeData({ ...treeData }); - } +export class WorkspaceWorkflowsState { + editorStore: EditorStore; + sdlcState: EditorSdlcState; + fetchWorkflowsState = ActionState.create(); + logState: WorkflowLogState; + workflowStates: WorkspaceWorkflowState[] = []; - getChildNodes( - node: WorkflowExplorerTreeNodeData, - treeData: TreeData, - ): WorkflowExplorerTreeNodeData[] { - if (node.childrenIds && node instanceof WorkflowTreeNodeData) { - return node.childrenIds - .map((id) => treeData.nodes.get(id)) - .filter(isNonNullable); - } - return []; + constructor(editorStore: EditorStore, sdlcState: EditorSdlcState) { + makeAutoObservable(this, { + editorStore: false, + sdlcState: false, + fetchWorkflowsState: observable, + logState: observable, + }); + + this.editorStore = editorStore; + this.sdlcState = sdlcState; + this.logState = new WorkflowLogState( + this.editorStore, + this.sdlcState, + undefined, + undefined, + ); } - *viewJobLogs(workflowJob: WorkflowJob): GeneratorFn { + *fetchAllWorkspaceWorkflows(): GeneratorFn { try { - this.isExecutingWorkflowRequest = true; - const logs = (yield this.editorStore.sdlcServerClient.getWorkflowJobLogs( - this.sdlcState.activeProject.projectId, - this.sdlcState.activeWorkspace, - workflowJob, - )) as string; - this.setWorkflowJobLogState( - new WorkflowLogState(this.editorStore, workflowJob, logs), + this.fetchWorkflowsState.inProgress(); + // NOTE: this network call can take a while, so we might consider limiting the number of workflows to 10 or so + const workflows = ( + (yield this.editorStore.sdlcServerClient.getWorkflows( + this.sdlcState.activeProject.projectId, + this.sdlcState.activeWorkspace, + undefined, + undefined, + undefined, + )) as PlainObject[] + ).map((workflow) => Workflow.serialization.fromJson(workflow)); + const openWorkflowIds = this.workflowStates + .map((workflowState) => + Array.from(workflowState.treeData.nodes.values()), + ) + .flat() + .filter( + (node: WorkflowExplorerTreeNodeData): node is WorkflowTreeNodeData => + node instanceof WorkflowTreeNodeData, + ) + .filter((node) => node.isOpen) + .map((node) => node.workflow.id); + const workflowToJobsMap = new Map(); + yield Promise.all( + workflows + .filter((workflow) => openWorkflowIds.includes(workflow.id)) + // NOTE: this network call can take a while, so we might consider limiting the number of workflows to 10 or so + .map((workflow) => + this.editorStore.sdlcServerClient + .getWorkflowJobs( + this.sdlcState.activeProject.projectId, + this.sdlcState.activeWorkspace, + workflow.id, + undefined, + undefined, + undefined, + ) + .then((jobs: PlainObject[]) => + workflowToJobsMap.set( + workflow.id, + jobs.map((x) => WorkflowJob.serialization.fromJson(x)), + ), + ), + ), ); + this.workflowStates = workflows.map( + (workflow) => + new WorkspaceWorkflowState( + this.editorStore, + this.sdlcState, + workflow, + workflowToJobsMap.get(workflow.id), + ), + ); + this.fetchWorkflowsState.pass(); } catch (error) { assertErrorThrown(error); this.editorStore.applicationStore.log.error( @@ -416,8 +439,7 @@ export class WorkspaceWorkflowsState { error, ); this.editorStore.applicationStore.notifyError(error); - } finally { - this.isExecutingWorkflowRequest = false; + this.fetchWorkflowsState.fail(); } } }