@finos/legend-application-pure-ide
Version:
Legend Pure IDE application core
192 lines • 13.6 kB
JavaScript
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