UNPKG

@finos/legend-application-studio

Version:
352 lines 17.8 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 { action, observable, makeObservable } from 'mobx'; import { LogEvent, IllegalStateError, isNonNullable, UnsupportedOperationError, guaranteeNonNullable, ActionState, } from '@finos/legend-shared'; import { getDependenciesPackableElementTreeData, getPackableElementTreeData, openNode, openNodeById, openNodes, populatePackageTreeNodeChildren, } from './utils/PackageTreeUtils.js'; import { LEGEND_STUDIO_APP_EVENT } from '../../__lib__/LegendStudioEvent.js'; import { getFileSystemTreeData, } from './utils/FileSystemTreeUtils.js'; import { ROOT_PACKAGE_NAME, Package, Unit, PrimitiveType, getElementRootPackage, isDependencyElement, } from '@finos/legend-graph'; import { APPLICATION_EVENT } from '@finos/legend-application'; import { DatabaseBuilderWizardState } from './editor-state/element-editor-state/connection/DatabaseBuilderWizardState.js'; import { DatabaseModelBuilderState } from './editor-state/element-editor-state/connection/DatabaseModelBuilderState.js'; export var ExplorerTreeRootPackageLabel; (function (ExplorerTreeRootPackageLabel) { ExplorerTreeRootPackageLabel["FILE_GENERATION"] = "generated-files"; ExplorerTreeRootPackageLabel["MODEL_GENERATION"] = "generated-models"; ExplorerTreeRootPackageLabel["SYSTEM"] = "system"; ExplorerTreeRootPackageLabel["PROJECT_DEPENDENCY"] = "dependencies"; })(ExplorerTreeRootPackageLabel || (ExplorerTreeRootPackageLabel = {})); export class ExplorerTreeState { editorStore; buildState = ActionState.create(); treeData; generationTreeData; systemTreeData; legalTreeData; dependencyTreeData; selectedNode; artifactsGenerationTreeData; elementToRename; classToGenerateSampleData; databaseBuilderState; databaseModelBuilderState; constructor(editorStore) { makeObservable(this, { treeData: observable.ref, generationTreeData: observable.ref, systemTreeData: observable.ref, legalTreeData: observable.ref, dependencyTreeData: observable.ref, artifactsGenerationTreeData: observable.ref, selectedNode: observable.ref, elementToRename: observable, classToGenerateSampleData: observable, databaseBuilderState: observable, databaseModelBuilderState: observable, setTreeData: action, setGenerationTreeData: action, setSystemTreeData: action, setLegalTreeData: action, setDependencyTreeData: action, setArtifactsGenerationTreeData: action, setSelectedNode: action, setElementToRename: action, setClassToGenerateSampleData: action, build: action, buildImmutableModelTrees: action, buildTreeInTextMode: action, buildDatabaseModels: action, openExplorerTreeNodes: action, reprocess: action, buildDatabase: action, setDatabaseBuilderState: action, onTreeNodeSelect: action, openNode: action, }); this.editorStore = editorStore; } getTreeData(rootPackageName = ROOT_PACKAGE_NAME.MAIN) { let treeData; switch (rootPackageName) { case ROOT_PACKAGE_NAME.MODEL_GENERATION: treeData = this.generationTreeData; break; case ROOT_PACKAGE_NAME.SYSTEM: treeData = this.systemTreeData; break; case ROOT_PACKAGE_NAME.PROJECT_DEPENDENCY_ROOT: treeData = this.dependencyTreeData; break; default: treeData = this.treeData; } if (!treeData || !this.buildState.hasCompleted) { this.editorStore.applicationStore.logService.error(LogEvent.create(APPLICATION_EVENT.ILLEGAL_APPLICATION_STATE_OCCURRED), `Can't get explorer tree data for root package '${rootPackageName}' as it hasn't been initialized`); throw new IllegalStateError(`Can't get explorer tree data for root package '${rootPackageName}' as it hasn't been initialized`); } return treeData; } getSelectedNodePackage() { if (!this.selectedNode) { return this.editorStore.graphManagerState.graph.root; } return this.selectedNode.packageableElement instanceof Package ? this.selectedNode.packageableElement : (this.selectedNode.packageableElement.package ?? this.editorStore.graphManagerState.graph.root); } setTreeData(data) { this.treeData = data; } setGenerationTreeData(data) { this.generationTreeData = data; } setSystemTreeData(data) { this.systemTreeData = data; } setLegalTreeData(data) { this.legalTreeData = data; } setDependencyTreeData(data) { this.dependencyTreeData = data; } setArtifactsGenerationTreeData(data) { this.artifactsGenerationTreeData = data; } setElementToRename(val) { this.elementToRename = val; } setClassToGenerateSampleData(val) { this.classToGenerateSampleData = val; } setDatabaseBuilderState(val) { this.databaseBuilderState = val; } buildDatabase(val, isReadOnly) { const dbBuilderState = new DatabaseBuilderWizardState(this.editorStore, val, isReadOnly); dbBuilderState.setShowModal(true); this.setDatabaseBuilderState(dbBuilderState); } setDatabaseModelBuilderState(val) { this.databaseModelBuilderState = val; } buildDatabaseModels(val, isReadOnly) { const dbBuilderState = new DatabaseModelBuilderState(this.editorStore, val, isReadOnly, this.editorStore.graphManagerState.graph); dbBuilderState.setShowModal(true); this.setDatabaseModelBuilderState(dbBuilderState); } setSelectedNode(node) { if (this.selectedNode) { this.selectedNode.isSelected = false; } if (node) { node.isSelected = true; } this.selectedNode = node; } build() { this.buildState.reset(); this.treeData = getPackableElementTreeData(this.editorStore, this.editorStore.graphManagerState.graph.root, ''); this.generationTreeData = getPackableElementTreeData(this.editorStore, this.editorStore.graphManagerState.graph.generationModel.root, ExplorerTreeRootPackageLabel.MODEL_GENERATION); this.artifactsGenerationTreeData = getFileSystemTreeData(this.editorStore.graphState.graphGenerationState.rootFileDirectory, ExplorerTreeRootPackageLabel.FILE_GENERATION); this.setSelectedNode(undefined); this.buildState.complete(); } buildTreeInTextMode() { this.buildState.reset(); if (!this.systemTreeData) { this.systemTreeData = getPackableElementTreeData(this.editorStore, this.editorStore.graphManagerState.systemModel.root, ExplorerTreeRootPackageLabel.SYSTEM); } if (!this.dependencyTreeData) { this.dependencyTreeData = getDependenciesPackableElementTreeData(this.editorStore, this.editorStore.graphManagerState.graph.dependencyManager.roots, ExplorerTreeRootPackageLabel.PROJECT_DEPENDENCY); } this.treeData = getPackableElementTreeData(this.editorStore, this.editorStore.graphManagerState.graph.root, ''); this.generationTreeData = getPackableElementTreeData(this.editorStore, this.editorStore.graphManagerState.graph.generationModel.root, ExplorerTreeRootPackageLabel.MODEL_GENERATION); this.artifactsGenerationTreeData = getFileSystemTreeData(this.editorStore.graphState.graphGenerationState.rootFileDirectory, ExplorerTreeRootPackageLabel.FILE_GENERATION); this.setSelectedNode(undefined); this.buildState.complete(); } buildImmutableModelTrees() { this.systemTreeData = getPackableElementTreeData(this.editorStore, this.editorStore.graphManagerState.systemModel.root, ExplorerTreeRootPackageLabel.SYSTEM); this.dependencyTreeData = getDependenciesPackableElementTreeData(this.editorStore, this.editorStore.graphManagerState.graph.dependencyManager.roots, ExplorerTreeRootPackageLabel.PROJECT_DEPENDENCY); } openExplorerTreeNodes(mainTreeOpenedNodeIds, generationTreeOpenedNodeIds, selectedNodeId) { // Main tree { const openElements = new Set(mainTreeOpenedNodeIds .map((id) => this.editorStore.graphManagerState.graph.getNullableElement(id, true)) .filter(isNonNullable)); openNodes(this.editorStore, this.editorStore.graphManagerState.graph.root, openElements, guaranteeNonNullable(this.treeData)); } // Generated tree { const openElements = new Set(generationTreeOpenedNodeIds .map((id) => this.editorStore.graphManagerState.graph.generationModel.getOwnNullableElement(id, true)) .filter(isNonNullable)); openNodes(this.editorStore, this.editorStore.graphManagerState.graph.generationModel.root, openElements, guaranteeNonNullable(this.generationTreeData)); if (generationTreeOpenedNodeIds.includes(ROOT_PACKAGE_NAME.MODEL_GENERATION)) { openNodeById(ROOT_PACKAGE_NAME.MODEL_GENERATION, this.generationTreeData); } } { if (selectedNodeId) { const element = this.editorStore.graphManagerState.graph.getNullableElement(selectedNodeId); if (element) { const openingNode = openNode(this.editorStore, element, guaranteeNonNullable(this.treeData)) ?? openNode(this.editorStore, element, guaranteeNonNullable(this.generationTreeData)); // ?? openNode(element, this.systemTreeData) // ?? openNode(element, this.legalTreeData) // ?? openNode(element, this.dependencyTreeData); this.setSelectedNode(openingNode); } else { this.setSelectedNode(undefined); } } } } /** * FIXME: this method should be replaced altogether as this could potentially cause memory leak when we `replace` the graph * When we refresh the graph (after compilation in text mode for example), we want to reprocess the app to * preserve the status of the explorer tree (opening nodes, selected nodes, etc.) * * @risk memory-leak */ reprocess() { this.buildState.reset(); if (!this.systemTreeData) { this.systemTreeData = getPackableElementTreeData(this.editorStore, this.editorStore.graphManagerState.systemModel.root, ExplorerTreeRootPackageLabel.SYSTEM); } if (!this.dependencyTreeData) { this.dependencyTreeData = getDependenciesPackableElementTreeData(this.editorStore, this.editorStore.graphManagerState.graph.dependencyManager.roots, ExplorerTreeRootPackageLabel.PROJECT_DEPENDENCY); } // Main tree { const openedTreeNodeIds = this.treeData ? Array.from(this.treeData.nodes.values()) .filter((node) => node.isOpen) .map((node) => node.id) : []; this.treeData = getPackableElementTreeData(this.editorStore, this.editorStore.graphManagerState.graph.root, ''); const openElements = new Set(openedTreeNodeIds .map((id) => this.editorStore.graphManagerState.graph.getNullableElement(id, true)) .filter(isNonNullable)); openNodes(this.editorStore, this.editorStore.graphManagerState.graph.root, openElements, this.treeData); } // Generated tree { const openedTreeNodeIds = this.generationTreeData ? Array.from(this.generationTreeData.nodes.values()) .filter((node) => node.isOpen) .map((node) => node.id) : []; this.generationTreeData = getPackableElementTreeData(this.editorStore, this.editorStore.graphManagerState.graph.generationModel.root, ExplorerTreeRootPackageLabel.MODEL_GENERATION); const openElements = new Set(openedTreeNodeIds .map((id) => this.editorStore.graphManagerState.graph.generationModel.getOwnNullableElement(id, true)) .filter(isNonNullable)); openNodes(this.editorStore, this.editorStore.graphManagerState.graph.generationModel.root, openElements, this.generationTreeData); if (openedTreeNodeIds.includes(ROOT_PACKAGE_NAME.MODEL_GENERATION)) { openNodeById(ROOT_PACKAGE_NAME.MODEL_GENERATION, this.generationTreeData); } } // File generation tree // TODO: fix this so it does proper reprocessing, right now it just rebuilds this.artifactsGenerationTreeData = getFileSystemTreeData(this.editorStore.graphState.graphGenerationState.rootFileDirectory, ExplorerTreeRootPackageLabel.FILE_GENERATION); if (this.selectedNode) { const element = this.editorStore.graphManagerState.graph.getNullableElement(this.selectedNode.id); if (element) { const openingNode = openNode(this.editorStore, element, this.treeData) ?? openNode(this.editorStore, element, this.generationTreeData); // ?? openNode(element, this.systemTreeData) // ?? openNode(element, this.legalTreeData) // ?? openNode(element, this.dependencyTreeData); this.setSelectedNode(openingNode); } else { this.setSelectedNode(undefined); } } this.setTreeData({ ...this.treeData }); this.setGenerationTreeData({ ...this.generationTreeData }); this.buildState.complete(); } onTreeNodeSelect = (node, treeData, rootPackageName = ROOT_PACKAGE_NAME.MAIN) => { // Open non-package element if (!(node.packageableElement instanceof Package)) { this.editorStore.graphEditorMode.openElement(node.packageableElement); } // Expand package element if (node.childrenIds?.length) { node.isOpen = !node.isOpen; if (node.packageableElement instanceof Package) { populatePackageTreeNodeChildren(this.editorStore, node, treeData, rootPackageName === ROOT_PACKAGE_NAME.PROJECT_DEPENDENCY_ROOT); } } this.setSelectedNode(node); switch (rootPackageName) { case ROOT_PACKAGE_NAME.MODEL_GENERATION: this.setGenerationTreeData({ ...treeData }); break; case ROOT_PACKAGE_NAME.SYSTEM: this.setSystemTreeData({ ...treeData }); break; case ROOT_PACKAGE_NAME.PROJECT_DEPENDENCY_ROOT: this.setDependencyTreeData({ ...treeData }); break; default: this.setTreeData({ ...treeData }); } }; /** * Given an element we open the node depending on what package tree corresponds to it */ openNode(element) { if (element instanceof PrimitiveType || element instanceof Unit) { throw new UnsupportedOperationError(`Can't open package tree node for element`, element); } const rootPackageName = getElementRootPackage(element).name; let opened = false; if (rootPackageName === ROOT_PACKAGE_NAME.MAIN && this.treeData) { const openingNode = openNode(this.editorStore, element, this.treeData); this.setSelectedNode(openingNode); opened = true; } else if (rootPackageName === ROOT_PACKAGE_NAME.MODEL_GENERATION && this.generationTreeData) { const openingNode = openNode(this.editorStore, element, this.generationTreeData); this.setSelectedNode(openingNode); opened = true; } else if (rootPackageName === ROOT_PACKAGE_NAME.SYSTEM && this.systemTreeData) { const openingNode = openNode(this.editorStore, element, this.systemTreeData); this.setSelectedNode(openingNode); opened = true; } else if (isDependencyElement(element) && this.dependencyTreeData) { const openingNode = openNode(this.editorStore, element, this.dependencyTreeData, undefined, true); this.setSelectedNode(openingNode); opened = true; } if (!opened) { this.editorStore.applicationStore.logService.error(LogEvent.create(LEGEND_STUDIO_APP_EVENT.PACKAGE_TREE_BUILDER_FAILURE), `Can't open package tree node for element '${element.path}' with root package '${rootPackageName}'`); } } getArtifactsGenerationTreeData() { return guaranteeNonNullable(this.artifactsGenerationTreeData, 'File generation tree data has not been initialized'); } } //# sourceMappingURL=ExplorerTreeState.js.map