@finos/legend-extension-dsl-data-space
Version:
Legend extension for Data Space DSL
170 lines • 19.5 kB
JavaScript
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } 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 { AnchorLinkIcon, CaretDownIcon, CenterFocusIcon, CircleIcon, CloseIcon, ContextMenu, CustomSelectorInput, DescriptionIcon, ControlledDropdownMenu, MenuContent, MenuContentDivider, MenuContentItem, MousePointerIcon, MoveIcon, ShapesIcon, ThinChevronDownIcon, ThinChevronLeftIcon, ThinChevronRightIcon, ThinChevronUpIcon, ZoomInIcon, ZoomOutIcon, clsx, useResizeDetector, createFilter, } from '@finos/legend-art';
import {} from '../stores/DataSpaceViewerState.js';
import { observer } from 'mobx-react-lite';
import { forwardRef, useEffect, useRef } from 'react';
import {} from '@finos/legend-extension-dsl-diagram/graph';
import { DIAGRAM_INTERACTION_MODE, DIAGRAM_RELATIONSHIP_EDIT_MODE, DIAGRAM_ZOOM_LEVELS, DiagramRenderer, } from '@finos/legend-extension-dsl-diagram/application';
import { DataSpaceWikiPlaceholder } from './DataSpacePlaceholder.js';
import { at } from '@finos/legend-shared';
import { DataSpaceMarkdownTextViewer } from './DataSpaceMarkdownTextViewer.js';
import { useCommands } from '@finos/legend-application';
import { DATA_SPACE_VIEWER_ACTIVITY_MODE, generateAnchorForActivity, generateAnchorForDiagram, } from '../stores/DataSpaceViewerNavigation.js';
const DataSpaceDiagramCanvas = observer(forwardRef(function DataSpaceDiagramCanvas(props, _ref) {
const { dataSpaceViewerState, diagram } = props;
const diagramViewerState = dataSpaceViewerState.diagramViewerState;
const ref = _ref;
const descriptionText = diagramViewerState.currentDiagram?.description;
const { width, height } = useResizeDetector({
refreshMode: 'debounce',
refreshRate: 50,
targetRef: ref,
});
useEffect(() => {
diagramViewerState.setExpandDescription(false);
}, [diagramViewerState, diagramViewerState.currentDiagram]);
useEffect(() => {
const renderer = new DiagramRenderer(ref.current, diagram);
diagramViewerState.setDiagramRenderer(renderer);
diagramViewerState.setupDiagramRenderer();
renderer.render({ initial: true });
}, [ref, diagramViewerState, diagram]);
useEffect(() => {
if (diagramViewerState.isDiagramRendererInitialized) {
diagramViewerState.diagramRenderer.refresh();
}
}, [diagramViewerState, width, height]);
// actions
const queryClass = () => {
if (diagramViewerState.contextMenuClassView) {
dataSpaceViewerState.queryClass(diagramViewerState.contextMenuClassView.class.value);
}
};
const viewClassDocumentation = () => {
if (diagramViewerState.contextMenuClassView &&
dataSpaceViewerState.modelsDocumentationState.hasClassDocumentation(diagramViewerState.contextMenuClassView.class.value.path)) {
dataSpaceViewerState.modelsDocumentationState.viewClassDocumentation(diagramViewerState.contextMenuClassView.class.value.path);
dataSpaceViewerState.changeZone(generateAnchorForActivity(DATA_SPACE_VIEWER_ACTIVITY_MODE.MODELS_DOCUMENTATION));
}
};
return (_jsxs(ContextMenu, { className: "data-space__viewer__diagram-viewer__canvas", content: _jsxs(MenuContent, { children: [_jsx(MenuContentItem, { onClick: queryClass, disabled: !diagramViewerState.contextMenuClassView, children: "Query" }), _jsx(MenuContentItem, { onClick: viewClassDocumentation, disabled: !diagramViewerState.contextMenuClassView ||
!dataSpaceViewerState.modelsDocumentationState.hasClassDocumentation(diagramViewerState.contextMenuClassView.class.value.path), children: "See Model Documentation" })] }), disabled: !diagramViewerState.contextMenuClassView, menuProps: { elevation: 7 }, onClose: () => diagramViewerState.setContextMenuClassView(undefined), children: [diagramViewerState.showDescription && (_jsxs("div", { className: clsx('data-space__viewer__diagram-viewer__description', {
'data-space__viewer__diagram-viewer__description--expanded': diagramViewerState.expandDescription,
}), children: [_jsx("button", { className: "data-space__viewer__diagram-viewer__description__close-btn", tabIndex: -1, title: "Hide Description", onClick: () => diagramViewerState.setShowDescription(false), children: _jsx(CloseIcon, {}) }), _jsx("div", { className: "data-space__viewer__diagram-viewer__description__title", children: diagramViewerState.currentDiagram?.title
? diagramViewerState.currentDiagram.title
: 'Untitled' }), _jsx("div", { className: "data-space__viewer__diagram-viewer__description__content", children: descriptionText ? (_jsx(DataSpaceMarkdownTextViewer, { value: descriptionText })) : (_jsx("div", { className: "data-space__viewer__diagram-viewer__description__content__placeholder", children: "(not specified)" })) }), _jsx("button", { className: "data-space__viewer__diagram-viewer__description__expand-btn", tabIndex: -1, title: diagramViewerState.expandDescription ? 'Collapse' : 'Expand', onClick: () => diagramViewerState.setExpandDescription(!diagramViewerState.expandDescription), children: diagramViewerState.expandDescription ? (_jsx(ThinChevronUpIcon, {})) : (_jsx(ThinChevronDownIcon, {})) })] })), _jsx("div", { ref: ref, className: clsx('diagram-canvas', diagramViewerState.diagramCursorClass), tabIndex: 0 })] }));
}));
const buildDiagramOption = (diagram) => ({
label: (_jsxs("div", { className: "data-space__viewer__diagram-viewer__header__navigation__selector__label", children: [_jsx(ShapesIcon, { className: "data-space__viewer__diagram-viewer__header__navigation__selector__icon" }), _jsx("div", { className: "data-space__viewer__diagram-viewer__header__navigation__selector__title", children: diagram.title ? diagram.title : 'Untitled' })] })),
value: diagram,
});
const DataSpaceDiagramViewerHeader = observer((props) => {
const { dataSpaceViewerState } = props;
const applicationStore = dataSpaceViewerState.applicationStore;
const diagramViewerState = dataSpaceViewerState.diagramViewerState;
const diagramOptions = dataSpaceViewerState.dataSpaceAnalysisResult.diagrams.map(buildDiagramOption);
const selectedDiagramOption = diagramViewerState.currentDiagram
? buildDiagramOption(diagramViewerState.currentDiagram)
: null;
const onDiagramOptionChange = (option) => {
if (option.value !== diagramViewerState.currentDiagram) {
diagramViewerState.setCurrentDiagram(option.value);
}
};
const diagramFilterOption = createFilter({
ignoreCase: true,
ignoreAccents: false,
stringify: (option) => option.data.value.title,
});
const createModeSwitcher = (editMode, relationshipMode) => () => diagramViewerState.diagramRenderer.changeMode(editMode, relationshipMode);
const createCenterZoomer = (zoomLevel) => () => {
diagramViewerState.diagramRenderer.zoomCenter(zoomLevel / 100);
};
const zoomToFit = () => diagramViewerState.diagramRenderer.zoomToFit();
return (_jsxs("div", { className: "data-space__viewer__diagram-viewer__header", children: [_jsxs("div", { className: "data-space__viewer__diagram-viewer__header__navigation", children: [_jsx(CustomSelectorInput, { className: "data-space__viewer__diagram-viewer__header__navigation__selector", options: diagramOptions, onChange: onDiagramOptionChange, value: selectedDiagramOption, placeholder: "Search for a diagram", darkMode: !applicationStore.layoutService
.TEMPORARY__isLightColorThemeEnabled, filterOption: diagramFilterOption }), _jsx("div", { className: "data-space__viewer__diagram-viewer__header__navigation__pager", children: _jsx("input", { className: "data-space__viewer__diagram-viewer__header__navigation__pager__input input--dark", value: diagramViewerState.currentDiagramIndex, type: "number", onChange: (event) => {
const value = parseInt(event.target.value, 10);
if (isNaN(value) ||
value < 1 ||
value >
dataSpaceViewerState.dataSpaceAnalysisResult.diagrams.length) {
return;
}
diagramViewerState.setCurrentDiagram(at(dataSpaceViewerState.dataSpaceAnalysisResult.diagrams, value - 1));
} }) }), _jsxs("div", { className: "data-space__viewer__diagram-viewer__header__navigation__pager__count", children: ["/", dataSpaceViewerState.dataSpaceAnalysisResult.diagrams.length] })] }), _jsx("div", { className: "data-space__viewer__diagram-viewer__header__actions", children: diagramViewerState.isDiagramRendererInitialized && (_jsxs(_Fragment, { children: [_jsxs("div", { className: "data-space__viewer__diagram-viewer__header__group", children: [_jsx("button", { className: "data-space__viewer__diagram-viewer__header__tool", tabIndex: -1, onClick: () => {
if (diagramViewerState.currentDiagram) {
dataSpaceViewerState.syncZoneWithNavigation(generateAnchorForDiagram(diagramViewerState.currentDiagram));
}
}, title: "Copy Link", children: _jsx(AnchorLinkIcon, {}) }), _jsx("button", { className: "data-space__viewer__diagram-viewer__header__tool", tabIndex: -1, onClick: () => diagramViewerState.diagramRenderer.recenter(), title: "Recenter (R)", children: _jsx(CenterFocusIcon, { className: "data-space__viewer__diagram-viewer__icon--recenter" }) }), _jsx("button", { className: clsx('data-space__viewer__diagram-viewer__header__tool', {
'data-space__viewer__diagram-viewer__header__tool--active': diagramViewerState.showDescription,
}), tabIndex: -1, onClick: () => diagramViewerState.setShowDescription(!diagramViewerState.showDescription), title: "Toggle Description (D)", children: _jsx(DescriptionIcon, { className: "data-space__viewer__diagram-viewer__icon--description" }) })] }), _jsx("div", { className: "data-space__viewer__diagram-viewer__header__group__separator" }), _jsxs("div", { className: "data-space__viewer__diagram-viewer__header__group", children: [_jsx("button", { className: clsx('data-space__viewer__diagram-viewer__header__tool', {
'data-space__viewer__diagram-viewer__header__tool--active': diagramViewerState.diagramRenderer.interactionMode ===
DIAGRAM_INTERACTION_MODE.LAYOUT,
}), tabIndex: -1, onClick: createModeSwitcher(DIAGRAM_INTERACTION_MODE.LAYOUT, DIAGRAM_RELATIONSHIP_EDIT_MODE.NONE), title: "View Tool (V)", children: _jsx(MousePointerIcon, { className: "data-space__viewer__diagram-viewer__icon--layout" }) }), _jsx("button", { className: clsx('data-space__viewer__diagram-viewer__header__tool', {
'data-space__viewer__diagram-viewer__header__tool--active': diagramViewerState.diagramRenderer.interactionMode ===
DIAGRAM_INTERACTION_MODE.PAN,
}), tabIndex: -1, onClick: createModeSwitcher(DIAGRAM_INTERACTION_MODE.PAN, DIAGRAM_RELATIONSHIP_EDIT_MODE.NONE), title: "Pan Tool (M)", children: _jsx(MoveIcon, { className: "data-space__viewer__diagram-viewer__icon--pan" }) }), _jsx("button", { className: clsx('data-space__viewer__diagram-viewer__header__tool', {
'data-space__viewer__diagram-viewer__header__tool--active': diagramViewerState.diagramRenderer.interactionMode ===
DIAGRAM_INTERACTION_MODE.ZOOM_IN,
}), tabIndex: -1, title: "Zoom In (Z)", onClick: createModeSwitcher(DIAGRAM_INTERACTION_MODE.ZOOM_IN, DIAGRAM_RELATIONSHIP_EDIT_MODE.NONE), children: _jsx(ZoomInIcon, { className: "data-space__viewer__diagram-viewer__icon--zoom-in" }) }), _jsx("button", { className: clsx('data-space__viewer__diagram-viewer__header__tool', {
'data-space__viewer__diagram-viewer__header__tool--active': diagramViewerState.diagramRenderer.interactionMode ===
DIAGRAM_INTERACTION_MODE.ZOOM_OUT,
}), tabIndex: -1, title: "Zoom Out (Z)", onClick: createModeSwitcher(DIAGRAM_INTERACTION_MODE.ZOOM_OUT, DIAGRAM_RELATIONSHIP_EDIT_MODE.NONE), children: _jsx(ZoomOutIcon, { className: "data-space__viewer__diagram-viewer__icon--zoom-out" }) })] }), _jsx("div", { className: "data-space__viewer__diagram-viewer__header__group__separator" }), _jsxs(ControlledDropdownMenu, { className: "data-space__viewer__diagram-viewer__header__group data-space__viewer__diagram-viewer__header__dropdown", title: "Zoom...", content: _jsxs(MenuContent, { children: [_jsx(MenuContentItem, { className: "data-space__viewer__diagram-viewer__header__zoomer__dropdown__menu__item", onClick: zoomToFit, children: "Fit" }), _jsx(MenuContentDivider, {}), DIAGRAM_ZOOM_LEVELS.map((zoomLevel) => (_jsxs(MenuContentItem, { className: "data-space__viewer__diagram-viewer__header__zoomer__dropdown__menu__item", onClick: createCenterZoomer(zoomLevel), children: [zoomLevel, "%"] }, zoomLevel)))] }), menuProps: {
anchorOrigin: { vertical: 'bottom', horizontal: 'right' },
transformOrigin: { vertical: 'top', horizontal: 'right' },
elevation: 7,
}, children: [_jsxs("div", { className: "data-space__viewer__diagram-viewer__header__dropdown__label data-space__viewer__diagram-viewer__header__zoomer__dropdown__label", children: [Math.round(diagramViewerState.diagramRenderer.zoom * 100), "%"] }), _jsx("div", { className: "data-space__viewer__diagram-viewer__header__dropdown__trigger data-space__viewer__diagram-viewer__header__zoomer__dropdown__trigger", children: _jsx(CaretDownIcon, {}) })] })] })) })] }));
});
export const DataSpaceDiagramViewer = observer((props) => {
const { dataSpaceViewerState } = props;
const diagramViewerState = dataSpaceViewerState.diagramViewerState;
const analysisResult = dataSpaceViewerState.dataSpaceAnalysisResult;
const sectionRef = useRef(null);
const anchor = generateAnchorForActivity(DATA_SPACE_VIEWER_ACTIVITY_MODE.DIAGRAM_VIEWER);
useCommands(diagramViewerState);
useEffect(() => {
if (sectionRef.current) {
dataSpaceViewerState.layoutState.setWikiPageAnchor(anchor, sectionRef.current);
}
return () => dataSpaceViewerState.layoutState.unsetWikiPageAnchor(anchor);
}, [dataSpaceViewerState, anchor]);
const diagramCanvasRef = useRef(null);
const previousDiagram = diagramViewerState.previousDiagram;
const nextDiagram = diagramViewerState.nextDiagram;
const showPreviousDiagram = () => {
if (previousDiagram) {
diagramViewerState.setCurrentDiagram(previousDiagram);
dataSpaceViewerState.syncZoneWithNavigation(generateAnchorForDiagram(previousDiagram));
}
};
const showNextDiagram = () => {
if (nextDiagram) {
diagramViewerState.setCurrentDiagram(nextDiagram);
dataSpaceViewerState.syncZoneWithNavigation(generateAnchorForDiagram(nextDiagram));
}
};
return (_jsxs("div", { ref: sectionRef, className: "data-space__viewer__wiki__section", children: [_jsx("div", { className: "data-space__viewer__wiki__section__header", children: _jsxs("div", { className: "data-space__viewer__wiki__section__header__label", children: ["Diagrams", _jsx("button", { className: "data-space__viewer__wiki__section__header__anchor", tabIndex: -1, onClick: () => dataSpaceViewerState.changeZone(anchor, true), children: _jsx(AnchorLinkIcon, {}) })] }) }), _jsxs("div", { className: "data-space__viewer__wiki__section__content", children: [analysisResult.diagrams.length > 0 && (_jsxs("div", { className: "data-space__viewer__diagram-viewer", children: [_jsx(DataSpaceDiagramViewerHeader, { dataSpaceViewerState: dataSpaceViewerState }), _jsx("div", { className: "data-space__viewer__diagram-viewer__carousel", children: _jsxs("div", { className: "data-space__viewer__diagram-viewer__carousel__frame", children: [_jsx("div", { className: "data-space__viewer__diagram-viewer__carousel__frame__display", children: diagramViewerState.currentDiagram && (_jsx(DataSpaceDiagramCanvas, { dataSpaceViewerState: dataSpaceViewerState, diagram: diagramViewerState.currentDiagram.diagram, ref: diagramCanvasRef })) }), _jsx("button", { className: "data-space__viewer__diagram-viewer__carousel__frame__navigator data-space__viewer__diagram-viewer__carousel__frame__navigator--back", tabIndex: -1, title: `Previous - ${previousDiagram?.title
? previousDiagram.title
: '(untitled)'} (⇦)`, disabled: !previousDiagram, onClick: showPreviousDiagram, children: _jsx(ThinChevronLeftIcon, {}) }), _jsx("button", { className: "data-space__viewer__diagram-viewer__carousel__frame__navigator data-space__viewer__diagram-viewer__carousel__frame__navigator--next", tabIndex: -1, title: `Next - ${nextDiagram?.title ? nextDiagram.title : '(untitled)'} (⇨)`, disabled: !nextDiagram, onClick: showNextDiagram, children: _jsx(ThinChevronRightIcon, {}) }), _jsx("div", { className: "data-space__viewer__diagram-viewer__carousel__frame__indicators", children: _jsx("div", { className: "data-space__viewer__diagram-viewer__carousel__frame__indicators__notch", children: analysisResult.diagrams.map((diagram) => (_jsx("button", { className: clsx('data-space__viewer__diagram-viewer__carousel__frame__indicator', {
'data-space__viewer__diagram-viewer__carousel__frame__indicator--active': diagramViewerState.currentDiagram === diagram,
}), title: `View Diagram - ${diagram.title ? diagram.title : '(untitled)'}`, onClick: () => {
diagramViewerState.setCurrentDiagram(diagram);
dataSpaceViewerState.syncZoneWithNavigation(generateAnchorForDiagram(diagram));
}, children: _jsx(CircleIcon, {}) }, diagram.uuid))) }) })] }) })] })), !analysisResult.diagrams.length && (_jsx(DataSpaceWikiPlaceholder, { message: "(not specified)" }))] })] }));
});
//# sourceMappingURL=DataSpaceDiagramViewer.js.map