UNPKG

@finos/legend-application-pure-ide

Version:
192 lines 13.6 kB
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime"; /** * 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 { forwardRef, useRef, useState } from 'react'; import { observer } from 'mobx-react-lite'; import { ElementConceptAttribute, PropertyConceptAttribute, ConceptType, } from '../../server/models/ConceptTree.js'; import { flowResult } from 'mobx'; import { FileCoordinate } from '../../server/models/File.js'; import { useApplicationStore } from '@finos/legend-application'; import { BlankPanelContent, clsx, ContextMenu, PanelLoadingIndicator, TreeView, ChevronDownIcon, ChevronRightIcon, CircleNotchIcon, RefreshIcon, CompressIcon, MenuContent, MenuContentItem, MenuContentDivider, } from '@finos/legend-art'; import { guaranteeType, isNonNullable } from '@finos/legend-shared'; import { useDrag } from 'react-dnd'; import { usePureIDEStore } from '../PureIDEStoreProvider.js'; import { getConceptIcon } from '../shared/ConceptIconUtils.js'; import { RenameConceptPrompt } from './RenameConceptPrompt.js'; import { extractElementNameFromPath } from '@finos/legend-graph'; import { MoveElementPrompt } from './MoveElementPrompt.js'; const ConceptExplorerContextMenu = observer(forwardRef(function ConceptExplorerContextMenu(props, ref) { const { node, viewConceptSource } = props; const nodeAttribute = node.data.li_attr; const nodeType = nodeAttribute.pureType; const ideStore = usePureIDEStore(); const applicationStore = useApplicationStore(); const renameConcept = () => ideStore.conceptTreeState.setNodeForRenameConcept(node); const moveElement = () => ideStore.conceptTreeState.setNodeForMoveElement(node); const runTests = () => { flowResult(ideStore.executeTests(node.data.li_attr.pureId)).catch(applicationStore.alertUnhandledError); }; const findUsages = () => { if (nodeAttribute instanceof ElementConceptAttribute || nodeAttribute instanceof PropertyConceptAttribute) { ideStore.findUsagesFromCoordinate(new FileCoordinate(nodeAttribute.file, Number.parseInt(nodeAttribute.line, 10), Number.parseInt(nodeAttribute.column, 10))); } }; const viewSource = () => viewConceptSource(node); const serviceJSON = () => { applicationStore.navigationService.navigator.visitAddress(`${ideStore.client.baseUrl}/execute?func=${nodeAttribute.pureId}&mode=${ideStore.client.mode}`); }; const copyPath = () => { applicationStore.clipboardService .copyTextToClipboard(nodeAttribute.pureId) .catch(applicationStore.alertUnhandledError); }; return (_jsxs(MenuContent, { ref: ref, children: [nodeAttribute.pureType !== ConceptType.PROPERTY && nodeAttribute.pureType !== ConceptType.QUALIFIED_PROPERTY && (_jsx(MenuContentItem, { onClick: copyPath, children: "Copy Path" })), nodeType === ConceptType.PACKAGE && (_jsxs(_Fragment, { children: [_jsx(MenuContentItem, { onClick: runTests, children: "Run Tests" }), _jsx(MenuContentItem, { onClick: () => ideStore.setPCTRunPath(node.data.li_attr.pureId), children: "Run PCTs" })] })), nodeType === ConceptType.FUNCTION && (_jsxs(_Fragment, { children: [_jsx(MenuContentItem, { onClick: serviceJSON, children: "Service (JSON)" }), _jsx(MenuContentItem, { onClick: () => { if (node.data.pct) { ideStore.setPCTRunPath(node.data.li_attr.pureId); } else { runTests(); } }, disabled: !node.data.test, children: "Run Test" })] })), (nodeAttribute instanceof PropertyConceptAttribute || nodeAttribute instanceof ElementConceptAttribute) && (_jsx(MenuContentItem, { onClick: findUsages, children: "Find Usages" })), nodeType !== ConceptType.PACKAGE && (_jsx(MenuContentItem, { onClick: viewSource, children: "View Source" })), _jsx(MenuContentDivider, {}), _jsx(MenuContentItem, { onClick: renameConcept, children: "Rename" }), nodeAttribute instanceof ElementConceptAttribute && (_jsx(MenuContentItem, { onClick: moveElement, children: "Move" }))] })); })); export var CONCEPT_TREE_DND_TYPE; (function (CONCEPT_TREE_DND_TYPE) { CONCEPT_TREE_DND_TYPE["UNSUPPORTED"] = "UNSUPPORTED"; CONCEPT_TREE_DND_TYPE["CLASS"] = "CLASS"; })(CONCEPT_TREE_DND_TYPE || (CONCEPT_TREE_DND_TYPE = {})); const ConceptTreeNodeContainer = (props) => { const { node, level, stepPaddingInRem, onNodeSelect, innerProps } = props; const [isSelectedFromContextMenu, setIsSelectedFromContextMenu] = useState(false); const { onNodeOpen, onNodeExpand, onNodeCompress, viewConceptSource } = innerProps; const isAssociationPropertyNode = node.parent && node.data.li_attr instanceof PropertyConceptAttribute && node.data.li_attr.classPath !== node.parent.id; const isExpandable = [ConceptType.PACKAGE, ConceptType.CLASS].includes(node.data.li_attr.pureType); const nodeLabel = node.data.li_attr.pureType === ConceptType.QUALIFIED_PROPERTY ? (_jsxs(_Fragment, { children: [node.label, _jsx("span", { className: "explorer__package-tree__node__label__tag", children: "(...)" })] })) : isAssociationPropertyNode ? (_jsxs(_Fragment, { children: [node.label, _jsx("span", { className: "explorer__package-tree__node__label__tag", children: extractElementNameFromPath(guaranteeType(node.data.li_attr, PropertyConceptAttribute) .classPath) })] })) : node.label.includes('(') ? (_jsxs(_Fragment, { children: [node.label.substring(0, node.label.indexOf('(')), _jsx("span", { className: "explorer__package-tree__node__label__tag", children: node.label.substring(node.label.indexOf('(')) })] })) : (node.label); const selectNode = (event) => { event.stopPropagation(); event.preventDefault(); onNodeSelect?.(node); }; const onContextMenuOpen = () => setIsSelectedFromContextMenu(true); const onContextMenuClose = () => setIsSelectedFromContextMenu(false); const toggleExpansion = () => { if (node.isLoading) { return; } if (node.isOpen) { onNodeCompress(node); } else { onNodeExpand(node); } }; const onDoubleClick = () => { if (node.isLoading) { return; } if (isExpandable) { toggleExpansion(); } onNodeSelect?.(node); onNodeOpen(node); }; const [, dragConnector] = useDrag(() => ({ type: node.data.li_attr.pureType === 'Class' ? CONCEPT_TREE_DND_TYPE.CLASS : CONCEPT_TREE_DND_TYPE.UNSUPPORTED, item: node.data, }), [node]); const ref = useRef(null); dragConnector(ref); return (_jsx(ContextMenu, { content: _jsx(ConceptExplorerContextMenu, { node: node, viewConceptSource: viewConceptSource }), menuProps: { elevation: 7 }, onOpen: onContextMenuOpen, onClose: onContextMenuClose, children: _jsxs("div", { id: node.id, className: clsx('tree-view__node__container explorer__package-tree__node__container', { 'explorer__package-tree__node__container--selected-from-context-menu': !node.isSelected && isSelectedFromContextMenu, }, { 'explorer__package-tree__node__container--selected': node.isSelected, }), onClick: selectNode, ref: ref, onDoubleClick: onDoubleClick, style: { paddingLeft: `${level * (stepPaddingInRem ?? 1)}rem`, display: 'flex', }, children: [_jsxs("div", { className: "tree-view__node__icon explorer__package-tree__node__icon", children: [node.isLoading && (_jsx("div", { className: "explorer__package-tree__node__icon__expand explorer__package-tree__node__icon__expand--is-loading", children: _jsx(CircleNotchIcon, {}) })), !node.isLoading && (_jsx("div", { className: "explorer__package-tree__node__icon__expand", onClick: toggleExpansion, children: !isExpandable ? (_jsx("div", {})) : node.isOpen ? (_jsx(ChevronDownIcon, {})) : (_jsx(ChevronRightIcon, {})) })), _jsx("div", { className: clsx('explorer__package-tree__node__icon__type', { 'explorer__package-tree__node__icon__type--property-from-association': isAssociationPropertyNode, }), children: getConceptIcon(node.data.li_attr.pureType) })] }), _jsx("button", { className: "tree-view__node__label explorer__package-tree__node__label", tabIndex: -1, children: nodeLabel })] }) })); }; const FileExplorerTree = observer(() => { const ideStore = usePureIDEStore(); const applicationStore = useApplicationStore(); const treeState = ideStore.conceptTreeState; const treeData = ideStore.conceptTreeState.getTreeData(); const onNodeSelect = (node) => treeState.setSelectedNode(node); const onNodeOpen = (node) => { flowResult(treeState.openNode(node)).catch(applicationStore.alertUnhandledError); }; const onNodeExpand = (node) => { flowResult(treeState.expandNode(node)).catch(applicationStore.alertUnhandledError); }; const onNodeCompress = (node) => { node.isOpen = false; treeState.refreshTree(); }; const getChildNodes = (node) => { if (node.isLoading || !node.childrenIds) { return []; } return node.childrenIds .map((childId) => treeData.nodes.get(childId)) .filter(isNonNullable); }; const deselectTreeNode = () => treeState.setSelectedNode(undefined); const viewConceptSource = (node) => { const nodeAttribute = node.data.li_attr; if (nodeAttribute instanceof ElementConceptAttribute || nodeAttribute instanceof PropertyConceptAttribute) { flowResult(ideStore.directoryTreeState.revealPath(nodeAttribute.file, { forceOpenExplorerPanel: true, coordinate: new FileCoordinate(nodeAttribute.file, Number.parseInt(nodeAttribute.line, 10), Number.parseInt(nodeAttribute.column, 10)), })).catch(applicationStore.alertUnhandledError); } }; return (_jsxs("div", { className: "explorer__content", onClick: deselectTreeNode, children: [_jsx(TreeView, { components: { TreeNodeContainer: ConceptTreeNodeContainer, }, treeData: treeData, onNodeSelect: onNodeSelect, getChildNodes: getChildNodes, innerProps: { onNodeOpen, onNodeExpand, onNodeCompress, viewConceptSource, } }), treeState.nodeForRenameConcept && (_jsx(RenameConceptPrompt, { node: treeState.nodeForRenameConcept })), treeState.nodeForMoveElement && (_jsx(MoveElementPrompt, { node: treeState.nodeForMoveElement }))] })); }); export const ConceptTreeExplorer = observer(() => { const ideStore = usePureIDEStore(); const applicationStore = useApplicationStore(); const treeState = ideStore.conceptTreeState; const refreshTree = () => { flowResult(treeState.refreshTreeData()).catch(applicationStore.alertUnhandledError); }; const collapseTree = () => { const treeData = treeState.getTreeData(); treeData.nodes.forEach((node) => { node.isOpen = false; }); treeState.setSelectedNode(undefined); treeState.refreshTree(); }; return (_jsxs("div", { className: "panel explorer", children: [_jsx("div", { className: "panel__header side-bar__header", children: _jsx("div", { className: "panel__header__title", children: _jsx("div", { className: "panel__header__title__content side-bar__header__title__content", children: "CONCEPTS" }) }) }), _jsx("div", { className: "panel__content side-bar__content", children: _jsxs("div", { className: "panel explorer", children: [_jsxs("div", { className: "panel__header explorer__header", children: [_jsx("div", { className: "panel__header__title" }), _jsxs("div", { className: "panel__header__actions", children: [_jsx("button", { className: "panel__header__action explorer__btn__refresh", onClick: refreshTree, title: "Refresh Tree", children: _jsx(RefreshIcon, {}) }), _jsx("button", { className: "panel__header__action", onClick: collapseTree, title: "Collapse All", children: _jsx(CompressIcon, {}) })] })] }), _jsxs("div", { className: "panel__content explorer__content__container", children: [_jsx(PanelLoadingIndicator, { isLoading: treeState.loadInitialDataState.isInProgress }), treeState.loadInitialDataState.hasSucceeded && (_jsx(FileExplorerTree, {})), !treeState.loadInitialDataState.hasSucceeded && treeState.statusText && (_jsx("div", { className: "explorer__content__container__message", children: treeState.statusText })), treeState.loadInitialDataState.hasFailed && (_jsx(BlankPanelContent, { children: "Failed to build concept tree. Make sure graph compiles" }))] })] }) })] })); }); //# sourceMappingURL=ConceptTreeExplorer.js.map