UNPKG

@finos/legend-application-studio

Version:
380 lines 17.3 kB
/** * Copyright (c) 2020-present, Goldman Sachs * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import { observable, action, flowResult, makeObservable, flow } from 'mobx'; import { LEGEND_STUDIO_APP_EVENT } from '../../../__lib__/LegendStudioEvent.js'; import { uuid, assertErrorThrown, LogEvent, ActionState, filterByType, } from '@finos/legend-shared'; import { WorkflowJob, Workflow } from '@finos/legend-server-sdlc'; export class WorkflowExplorerTreeNodeData { isSelected; isOpen; id; label; childrenIds; constructor(id, label) { this.id = id; this.label = label; } } const getWorkflowNodeId = (workflowId) => `workflow_${workflowId}`; const getJobId = (jobId) => `job_${jobId}`; export class WorkflowTreeNodeData extends WorkflowExplorerTreeNodeData { workflow; constructor(workflow) { super(getWorkflowNodeId(workflow.id), workflow.id); this.workflow = workflow; } } export class WorkflowJobTreeNodeData extends WorkflowExplorerTreeNodeData { workflowJob; constructor(workflowJob) { super(getJobId(workflowJob.id), workflowJob.name); this.workflowJob = workflowJob; } } const addWorkflowJobNodeToTree = (workflowJob, workflowNode, treeData) => { const node = new WorkflowJobTreeNodeData(workflowJob); if (workflowNode.childrenIds) { workflowNode.childrenIds.push(node.id); } else { workflowNode.childrenIds = [node.id]; } treeData.nodes.set(node.id, node); return node; }; const updateWorkflowJobData = (workflowJobs, workflowId, treeData) => { const workflowNode = treeData.nodes.get(getWorkflowNodeId(workflowId)); if (workflowNode instanceof WorkflowTreeNodeData) { workflowNode.childrenIds?.forEach((id) => treeData.nodes.delete(id)); workflowNode.childrenIds = []; workflowJobs.forEach((job) => addWorkflowJobNodeToTree(job, workflowNode, treeData)); } }; export class WorkflowLogState { editorStore; workflowManagerState; fetchJobLogState = ActionState.create(); job; logs; constructor(editorStore, workflowManagerState, job, logs) { makeObservable(this, { job: observable, logs: observable, setLogs: action, setJob: action, closeModal: action, refreshJobLogs: flow, viewJobLogs: flow, }); this.editorStore = editorStore; this.workflowManagerState = workflowManagerState; this.job = job; this.logs = logs ?? ''; } setLogs(val) { this.logs = val; } setJob(val) { this.job = val; } closeModal() { this.setJob(undefined); this.setLogs(''); } *refreshJobLogs(workflowJob) { try { this.fetchJobLogState.inProgress(); const job = (yield flowResult(this.workflowManagerState.getJob(workflowJob))); this.setJob(job); const logs = (yield flowResult(this.workflowManagerState.getJobLogs(workflowJob))); this.setLogs(logs); this.fetchJobLogState.pass(); } catch (error) { assertErrorThrown(error); this.editorStore.applicationStore.logService.error(LogEvent.create(LEGEND_STUDIO_APP_EVENT.SDLC_MANAGER_FAILURE), error); this.editorStore.applicationStore.notificationService.notifyError(error); this.fetchJobLogState.fail(); } } *viewJobLogs(workflowJob) { try { this.setJob(workflowJob); this.fetchJobLogState.inProgress(); const logs = (yield flowResult(this.workflowManagerState.getJobLogs(workflowJob))); this.setLogs(logs); this.fetchJobLogState.pass(); } catch (error) { assertErrorThrown(error); this.editorStore.applicationStore.logService.error(LogEvent.create(LEGEND_STUDIO_APP_EVENT.SDLC_MANAGER_FAILURE), error); this.editorStore.applicationStore.notificationService.notifyError(error); this.fetchJobLogState.fail(); } } } export class WorkflowState { uuid = uuid(); editorStore; workflowManagerState; treeData; isExecutingWorkflowRequest = false; constructor(editorStore, workflowManagerState, workflow, jobs) { makeObservable(this, { treeData: observable.ref, isExecutingWorkflowRequest: observable, setWorkflowTreeData: action, fetchAllWorkspaceWorkJobs: flow, onTreeNodeSelect: flow, cancelJob: flow, refreshWorkflow: flow, retryJob: flow, runManualJob: flow, }); this.editorStore = editorStore; this.workflowManagerState = workflowManagerState; this.treeData = this.buildTreeData(workflow, jobs); } setWorkflowTreeData(val) { this.treeData = val; } buildTreeData(workflow, jobs) { const rootIds = []; 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); } return treeData; } *fetchAllWorkspaceWorkJobs(workflowId, treeData) { try { this.isExecutingWorkflowRequest = true; const workflowJobs = (yield flowResult(this.workflowManagerState.getJobs(workflowId))).sort((a, b) => a.createdAt.getTime() - b.createdAt.getTime()); updateWorkflowJobData(workflowJobs, workflowId, treeData); this.setWorkflowTreeData({ ...treeData }); } catch (error) { assertErrorThrown(error); this.editorStore.applicationStore.logService.error(LogEvent.create(LEGEND_STUDIO_APP_EVENT.SDLC_MANAGER_FAILURE), error); this.editorStore.applicationStore.notificationService.notifyError(error); } finally { this.isExecutingWorkflowRequest = false; } } *onTreeNodeSelect(node, treeData) { if (node instanceof WorkflowTreeNodeData) { if (!node.childrenIds) { yield flowResult(this.fetchAllWorkspaceWorkJobs(node.workflow.id, treeData)); } node.isOpen = !node.isOpen; } this.setWorkflowTreeData({ ...treeData }); } *cancelJob(workflowJob, treeData) { try { this.isExecutingWorkflowRequest = true; this.workflowManagerState.cancelJob(workflowJob); yield flowResult(this.refreshWorkflow(workflowJob.workflowId, treeData)); } catch (error) { assertErrorThrown(error); this.editorStore.applicationStore.logService.error(LogEvent.create(LEGEND_STUDIO_APP_EVENT.SDLC_MANAGER_FAILURE), error); this.editorStore.applicationStore.notificationService.notifyError(error); } finally { this.isExecutingWorkflowRequest = false; } } *refreshWorkflow(workflowId, treeData) { const node = treeData.nodes.get(getWorkflowNodeId(workflowId)); if (node instanceof WorkflowTreeNodeData) { const workflow = (yield flowResult(this.workflowManagerState.getWorkflow(workflowId))); node.workflow = workflow; } yield flowResult(this.fetchAllWorkspaceWorkJobs(workflowId, treeData)); } *retryJob(workflowJob, treeData) { try { this.isExecutingWorkflowRequest = true; yield flowResult(this.workflowManagerState.retryJob(workflowJob)); yield flowResult(this.refreshWorkflow(workflowJob.workflowId, treeData)); } catch (error) { assertErrorThrown(error); this.editorStore.applicationStore.logService.error(LogEvent.create(LEGEND_STUDIO_APP_EVENT.SDLC_MANAGER_FAILURE), error); this.editorStore.applicationStore.notificationService.notifyError(error); } finally { this.isExecutingWorkflowRequest = false; } } *runManualJob(workflowJob, treeData) { try { this.isExecutingWorkflowRequest = true; yield flowResult(this.workflowManagerState.runManualJob(workflowJob)); yield flowResult(this.refreshWorkflow(workflowJob.workflowId, treeData)); } catch (error) { assertErrorThrown(error); this.editorStore.applicationStore.logService.error(LogEvent.create(LEGEND_STUDIO_APP_EVENT.SDLC_MANAGER_FAILURE), error); this.editorStore.applicationStore.notificationService.notifyError(error); } finally { this.isExecutingWorkflowRequest = false; } } } export class WorkflowManagerState { editorStore; sdlcState; fetchWorkflowsState = ActionState.create(); logState; workflowStates = []; constructor(editorStore, sdlcState) { makeObservable(this, { logState: observable, workflowStates: observable, fetchAllWorkflows: flow, getWorkflows: flow, getWorkflow: flow, getJobs: flow, getJob: flow, retryJob: flow, cancelJob: flow, runManualJob: flow, getJobLogs: flow, }); this.editorStore = editorStore; this.sdlcState = sdlcState; this.logState = new WorkflowLogState(this.editorStore, this, undefined, undefined); } *fetchAllWorkflows() { try { 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 flowResult(this.getWorkflows())); const openWorkflowIds = this.workflowStates .map((workflowState) => Array.from(workflowState.treeData.nodes.values())) .flat() .filter(filterByType(WorkflowTreeNodeData)) .filter((node) => node.isOpen) .map((node) => node.workflow.id); const jobsIndex = 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) => flowResult(this.getJobs(workflow.id)).then((jobs) => jobsIndex.set(workflow.id, jobs.toSorted((a, b) => a.createdAt.getTime() - b.createdAt.getTime()))))); this.workflowStates = workflows.map((workflow) => new WorkflowState(this.editorStore, this, workflow, jobsIndex.get(workflow.id))); this.fetchWorkflowsState.pass(); } catch (error) { assertErrorThrown(error); this.editorStore.applicationStore.logService.error(LogEvent.create(LEGEND_STUDIO_APP_EVENT.SDLC_MANAGER_FAILURE), error); this.editorStore.applicationStore.notificationService.notifyError(error); this.fetchWorkflowsState.fail(); } } } export class WorkspaceWorkflowManagerState extends WorkflowManagerState { *getJobs(workflowId) { return (yield this.editorStore.sdlcServerClient.getWorkflowJobs(this.sdlcState.activeProject.projectId, this.sdlcState.activeWorkspace, workflowId, undefined, undefined, undefined)).map((v) => WorkflowJob.serialization.fromJson(v)); } *getJob(job) { return (yield this.editorStore.sdlcServerClient.getWorkflowJob(this.sdlcState.activeProject.projectId, this.sdlcState.activeWorkspace, job)).map((v) => WorkflowJob.serialization.fromJson(v)); } *getWorkflows() { return (yield this.editorStore.sdlcServerClient.getWorkflows(this.sdlcState.activeProject.projectId, this.sdlcState.activeWorkspace, undefined, undefined, undefined)).map((v) => Workflow.serialization.fromJson(v)); } *getWorkflow(workflowId) { return Workflow.serialization.fromJson((yield this.editorStore.sdlcServerClient.getWorkflow(this.sdlcState.activeProject.projectId, this.sdlcState.activeWorkspace, workflowId))); } *retryJob(workflowJob) { (yield this.editorStore.sdlcServerClient.retryWorkflowJob(this.sdlcState.activeProject.projectId, this.sdlcState.activeWorkspace, workflowJob)); } *runManualJob(workflowJob) { (yield this.editorStore.sdlcServerClient.runManualWorkflowJob(this.sdlcState.activeProject.projectId, this.sdlcState.activeWorkspace, workflowJob)); } *cancelJob(workflowJob) { (yield this.editorStore.sdlcServerClient.cancelWorkflowJob(this.sdlcState.activeProject.projectId, this.sdlcState.activeWorkspace, workflowJob)); } *getJobLogs(workflowJob) { return (yield this.editorStore.sdlcServerClient.getWorkflowJobLogs(this.sdlcState.activeProject.projectId, this.sdlcState.activeWorkspace, workflowJob)); } } export class ProjectVersionWorkflowManagerState extends WorkflowManagerState { version; constructor(editorStore, sdlcState, version) { super(editorStore, sdlcState); this.version = version; } *getJobs(workflowId) { return (yield this.editorStore.sdlcServerClient.getWorkflowJobsByVersion(this.sdlcState.activeProject.projectId, this.version.id.id, workflowId, undefined, undefined, undefined)).map((v) => WorkflowJob.serialization.fromJson(v)); } *getJob(job) { return (yield this.editorStore.sdlcServerClient.getWorkflowJobByVersion(this.sdlcState.activeProject.projectId, this.version.id.id, job)).map((v) => WorkflowJob.serialization.fromJson(v)); } *getWorkflows() { return (yield this.editorStore.sdlcServerClient.getWorkflowsByVersion(this.sdlcState.activeProject.projectId, this.version.id.id, undefined, undefined, undefined)).map((v) => Workflow.serialization.fromJson(v)); } *getWorkflow(workflowId) { return Workflow.serialization.fromJson((yield this.editorStore.sdlcServerClient.getWorkflowByVersion(this.sdlcState.activeProject.projectId, this.version.id.id, workflowId))); } *retryJob(workflowJob) { (yield this.editorStore.sdlcServerClient.retryWorkflowJobByVersion(this.sdlcState.activeProject.projectId, this.version.id.id, workflowJob)); } *runManualJob(workflowJob) { (yield this.editorStore.sdlcServerClient.runManualWorkflowJobByVersion(this.sdlcState.activeProject.projectId, this.version.id.id, workflowJob)); } *cancelJob(workflowJob) { (yield this.editorStore.sdlcServerClient.cancelWorkflowJobByVersion(this.sdlcState.activeProject.projectId, this.version.id.id, workflowJob)); } *getJobLogs(workflowJob) { return (yield this.editorStore.sdlcServerClient.getWorkflowJobLogsByVersion(this.sdlcState.activeProject.projectId, this.version.id.id, workflowJob)); } } export class ProjectWorkflowManagerState extends WorkflowManagerState { *getJobs(workflowId) { return (yield this.editorStore.sdlcServerClient.getWorkflowJobs(this.sdlcState.activeProject.projectId, undefined, workflowId, undefined, undefined, undefined)).map((v) => WorkflowJob.serialization.fromJson(v)); } *getJob(job) { return (yield this.editorStore.sdlcServerClient.getWorkflowJob(this.sdlcState.activeProject.projectId, undefined, job)).map((v) => WorkflowJob.serialization.fromJson(v)); } *getWorkflows() { return (yield this.editorStore.sdlcServerClient.getWorkflows(this.sdlcState.activeProject.projectId, undefined, undefined, undefined, undefined)).map((v) => Workflow.serialization.fromJson(v)); } *getWorkflow(workflowId) { return Workflow.serialization.fromJson((yield this.editorStore.sdlcServerClient.getWorkflow(this.sdlcState.activeProject.projectId, undefined, workflowId))); } *retryJob(workflowJob) { (yield this.editorStore.sdlcServerClient.retryWorkflowJob(this.sdlcState.activeProject.projectId, undefined, workflowJob)); } *runManualJob(workflowJob) { (yield this.editorStore.sdlcServerClient.runManualWorkflowJob(this.sdlcState.activeProject.projectId, undefined, workflowJob)); } *cancelJob(workflowJob) { (yield this.editorStore.sdlcServerClient.cancelWorkflowJob(this.sdlcState.activeProject.projectId, undefined, workflowJob)); } *getJobLogs(workflowJob) { return (yield this.editorStore.sdlcServerClient.getWorkflowJobLogs(this.sdlcState.activeProject.projectId, undefined, workflowJob)); } } //# sourceMappingURL=WorkflowManagerState.js.map