UNPKG

@finos/legend-application-studio

Version:
315 lines 12 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 { flow, observable, makeObservable, flowResult, action } from 'mobx'; import { ActionState, assertErrorThrown, LogEvent, isNonNullable, uuid, } from '@finos/legend-shared'; import { ProjectDependencyCoordinates, buildConflictsPaths, buildDependencyReport, RawProjectDependencyReport, } from '@finos/legend-server-depot'; import { LEGEND_STUDIO_APP_EVENT } from '../../../../__lib__/LegendStudioEvent.js'; export class ProjectDependencyConflictTreeNodeData { id; label; childrenIds; isSelected; isOpen; constructor(id) { this.id = id; this.label = id; } } export class ConflictTreeNodeData extends ProjectDependencyConflictTreeNodeData { conflict; constructor(conflict) { super(`${conflict.groupId}:${conflict.artifactId}`); this.conflict = conflict; } get description() { return this.id; } } export class ConflictVersionNodeData extends ProjectDependencyConflictTreeNodeData { versionConflict; constructor(conflict) { super(`${conflict.version.groupId}:${conflict.version.artifactId}.${conflict.version.versionId}`); this.versionConflict = conflict; this.label = this.versionConflict.version.versionId; } get description() { return this.id; } } export class ProjectDependencyTreeNodeData extends ProjectDependencyConflictTreeNodeData { value; constructor(id, value) { super(id); this.value = value; this.label = value.artifactId; } get description() { return `${this.value.groupId}:${this.value.artifactId}:${this.value.versionId}`; } } export const buildDependencyNodeChildren = (parentNode, treeNodes) => { if (!parentNode.childrenIds) { const value = parentNode.value; const childrenNodes = value.dependencies.map((projectVersion) => { const childId = `${parentNode.id}.${projectVersion.id}`; const childNode = new ProjectDependencyTreeNodeData(childId, projectVersion); treeNodes.set(childId, childNode); return childNode; }); parentNode.childrenIds = childrenNodes.map((c) => c.id); } }; const findRootNode = (versionNode, treeData) => { if (!treeData.rootIds.includes(versionNode.id)) { return undefined; } return Array.from(treeData.nodes.values()).find((node) => node.id === versionNode.id && node.value === versionNode); }; const walkNode = (node, visited, treeData) => { if (!visited.has(node.value)) { node.isOpen = true; buildDependencyNodeChildren(node, treeData.nodes); visited.add(node.value); node.childrenIds ?.map((nodeId) => treeData.nodes.get(nodeId)) .filter(isNonNullable) .forEach((n) => walkNode(n, visited, treeData)); } else { buildDependencyNodeChildren(node, treeData.nodes); } }; export const openAllDependencyNodesInTree = (treeData, graph) => { const visited = new Set(); graph.rootNodes .map((node) => findRootNode(node, treeData)) .filter(isNonNullable) .forEach((node) => walkNode(node, visited, treeData)); }; const buildDependencyTreeData = (report) => { const nodes = new Map(); const rootNodes = report.graph.rootNodes.map((versionNode) => { const node = new ProjectDependencyTreeNodeData(versionNode.id, versionNode); nodes.set(node.id, node); buildDependencyNodeChildren(node, nodes); return node; }); const rootIds = rootNodes.map((node) => node.id); return { rootIds, nodes }; }; const buildFlattenDependencyTreeData = (report) => { const nodes = new Map(); const rootIds = []; Array.from(report.graph.nodes.entries()).forEach(([key, value]) => { const id = value.id; const node = new ProjectDependencyTreeNodeData(id, value); nodes.set(id, node); rootIds.push(id); buildDependencyNodeChildren(node, nodes); }); return { rootIds, nodes }; }; export var DEPENDENCY_REPORT_TAB; (function (DEPENDENCY_REPORT_TAB) { DEPENDENCY_REPORT_TAB["EXPLORER"] = "EXPLORER"; DEPENDENCY_REPORT_TAB["CONFLICTS"] = "CONFLICTS"; })(DEPENDENCY_REPORT_TAB || (DEPENDENCY_REPORT_TAB = {})); const buildTreeDataFromConflictVersion = (conflictVersionNode, nodes) => conflictVersionNode.versionConflict.pathsToVersion .map((path, idx) => { if (!path.length) { return undefined; } const pathIterator = path.values(); let rootNode; let parentNode; let currentVersion; while ((currentVersion = pathIterator.next().value)) { const id = parentNode ? `${parentNode.id}.${currentVersion.id}` : `path${idx}_${currentVersion.id}`; const node = new ProjectDependencyTreeNodeData(id, currentVersion); node.childrenIds = []; nodes.set(id, node); if (parentNode) { parentNode.childrenIds = [node.id]; } else { rootNode = node; } parentNode = node; } return rootNode; }) .filter(isNonNullable); const buildTreeDataFromConflict = (conflict, paths) => { const rootNode = new ConflictTreeNodeData(conflict); const rootIds = [rootNode.id]; const nodes = new Map(); nodes.set(rootNode.id, rootNode); const versionConflictNodes = paths.map((versionConflict) => { const projectVersionNode = new ConflictVersionNodeData(versionConflict); nodes.set(projectVersionNode.id, projectVersionNode); const pathNodes = buildTreeDataFromConflictVersion(projectVersionNode, nodes); projectVersionNode.childrenIds = pathNodes.map((n) => n.id); return projectVersionNode; }); rootNode.childrenIds = versionConflictNodes.map((n) => n.id); return { rootIds, nodes }; }; export class ProjectDependencyConflictState { uuid = uuid(); report; conflict; paths; treeData; constructor(report, conflict, paths) { makeObservable(this, { treeData: observable.ref, setTreeData: action, }); this.report = report; this.conflict = conflict; this.paths = paths; this.treeData = buildTreeDataFromConflict(conflict, paths); } setTreeData(treeData) { this.treeData = treeData; } get versionNodes() { return this.paths.map((e) => e.version); } } export class ProjectDependencyEditorState { configState; editorStore; isReadOnly; reportTab; fetchingDependencyInfoState = ActionState.create(); dependencyReport; dependencyTreeData; flattenDependencyTreeData; conflictStates; expandConflictsState = ActionState.create(); buildConflictPathState = ActionState.create(); constructor(configState, editorStore) { makeObservable(this, { dependencyReport: observable, fetchingDependencyInfoState: observable, dependencyTreeData: observable.ref, flattenDependencyTreeData: observable.ref, conflictStates: observable, reportTab: observable, expandConflictsState: observable, buildConflictPathState: observable, setReportTab: action, expandAllConflicts: action, setFlattenDependencyTreeData: action, clearTrees: action, setTreeData: action, setDependencyTreeData: action, buildConflictPaths: action, setConflictStates: action, fetchDependencyReport: flow, }); this.configState = configState; this.editorStore = editorStore; this.isReadOnly = editorStore.isInViewerMode; } expandAllConflicts() { if (this.conflictStates) { this.expandConflictsState.inProgress(); this.conflictStates.forEach((c) => { const treeData = c.treeData; Array.from(treeData.nodes.values()).forEach((n) => (n.isOpen = true)); }); this.conflictStates.forEach((c) => { c.setTreeData({ ...c.treeData }); }); this.expandConflictsState.complete(); } } setTreeData(treeData, flattenView) { if (flattenView) { this.setFlattenDependencyTreeData(treeData); } else { this.setDependencyTreeData(treeData); } } setReportTab(tab) { this.reportTab = tab; } setDependencyTreeData(tree) { this.dependencyTreeData = tree; } setConflictStates(val) { this.conflictStates = val; } setFlattenDependencyTreeData(tree) { this.flattenDependencyTreeData = tree; } get projectConfiguration() { return this.configState.projectConfiguration; } *fetchDependencyReport() { try { this.fetchingDependencyInfoState.inProgress(); this.dependencyReport = undefined; this.clearTrees(); this.setConflictStates(undefined); if (this.projectConfiguration?.projectDependencies) { const dependencyCoordinates = (yield flowResult(this.editorStore.graphState.buildProjectDependencyCoordinates(this.projectConfiguration.projectDependencies))); const dependencyInfoRaw = (yield this.editorStore.depotServerClient.analyzeDependencyTree(dependencyCoordinates.map((e) => ProjectDependencyCoordinates.serialization.toJson(e)))); const rawdependencyReport = RawProjectDependencyReport.serialization.fromJson(dependencyInfoRaw); const report = buildDependencyReport(rawdependencyReport); this.dependencyReport = report; this.setDependencyTreeData(buildDependencyTreeData(report)); this.setFlattenDependencyTreeData(buildFlattenDependencyTreeData(report)); } this.fetchingDependencyInfoState.complete(); } catch (error) { assertErrorThrown(error); this.fetchingDependencyInfoState.fail(); this.dependencyReport = undefined; this.editorStore.applicationStore.logService.error(LogEvent.create(LEGEND_STUDIO_APP_EVENT.DEPOT_MANAGER_FAILURE), error); } } buildConflictPaths() { const report = this.dependencyReport; if (report) { this.setConflictStates(undefined); this.buildConflictPathState.inProgress(); try { report.conflictInfo = buildConflictsPaths(report); const conflictStates = Array.from(report.conflictInfo.entries()).map(([conflict, paths]) => new ProjectDependencyConflictState(report, conflict, paths)); this.setConflictStates(conflictStates); this.buildConflictPathState.complete(); } catch (error) { assertErrorThrown(error); this.setConflictStates([]); this.buildConflictPathState.fail(); this.editorStore.applicationStore.notificationService.notifyError(`Unable to build conflict paths ${error.message}`); } } } clearTrees() { this.flattenDependencyTreeData = undefined; this.dependencyTreeData = undefined; } } //# sourceMappingURL=ProjectDependencyEditorState.js.map