@finos/legend-extension-dsl-data-space-studio
Version:
Legend extension for Data Space DSL - Studio
178 lines • 18.9 kB
JavaScript
import { jsx as _jsx, 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 { CORE_DND_TYPE, useEditorStore, } from '@finos/legend-application-studio';
import { observer } from 'mobx-react-lite';
import { useDrop } from 'react-dnd';
import { DataSpaceEditorState } from '../stores/DataSpaceEditorState.js';
import { BlankPanelPlaceholder, clsx, ContextMenu, CustomSelectorInput, Dialog, ErrorIcon, ExclamationTriangleIcon, InputWithInlineValidation, LongArrowRightIcon, MenuContent, MenuContentItem, ModalTitle, PanelContent, PanelDropZone, PanelHeader, PanelHeaderActionItem, PanelHeaderActions, PlusIcon, PURE_MappingIcon, PURE_RuntimeIcon, ResizablePanel, ResizablePanelGroup, ResizablePanelSplitter, ResizablePanelSplitterLine, } from '@finos/legend-art';
import { Mapping, PackageableElementExplicitReference, PackageableRuntime, validate_PureExecutionMapping, } from '@finos/legend-graph';
import { dataSpace_setExecutionContextDefaultRuntime, dataSpace_setExecutionContextMapping, dataSpace_setExecutionContextTitle, dataSpace_setExecutionContextDescription, } from '../stores/studio/DSL_DataSpace_GraphModifierHelper.js';
import { guaranteeNonNullable } from '@finos/legend-shared';
import { forwardRef, useCallback, useState } from 'react';
import { buildElementOption, } from '@finos/legend-lego/graph-editor';
const DataSpaceExecutionContextConfigurationEditor = observer((props) => {
const { executionContextState, executionContext } = props;
const isReadOnly = executionContextState.dataSpaceEditorState.isReadOnly;
const editorStore = executionContextState.editorStore;
const applicationStore = editorStore.applicationStore;
// Mapping
// TODO: this is not generic error handling, as there could be other problems
// with mapping, we need to genericize this
const isMappingEmpty = validate_PureExecutionMapping(executionContext.mapping.value);
const mapping = executionContext.mapping.value;
const mappingOptions = editorStore.graphManagerState.usableMappings.map(buildElementOption);
const noMappingLabel = (_jsxs("div", { className: "service-execution-editor__configuration__mapping-option--empty", title: isMappingEmpty?.messages.join('\n') ?? '', children: [_jsx("div", { className: "service-execution-editor__configuration__mapping-option--empty__label", children: "(none)" }), _jsx(ErrorIcon, {})] }));
const selectedMappingOption = {
value: mapping,
label: isMappingEmpty ? noMappingLabel : mapping.path,
};
const onMappingSelectionChange = (val) => {
if (val.value !== mapping) {
dataSpace_setExecutionContextMapping(executionContext, PackageableElementExplicitReference.create(val.value));
executionContextState.autoSelectRuntimeOnMappingChange(val.value);
}
};
const visitMapping = () => editorStore.graphEditorMode.openElement(mapping);
// Runtime
const defaultRuntime = executionContext.defaultRuntime;
// NOTE: for now, only include runtime associated with the mapping
// TODO?: Should we bring the runtime compatibility check from query to here?
const runtimes = editorStore.graphManagerState.graph.runtimes.filter((rt) => rt.runtimeValue.mappings.map((m) => m.value).includes(mapping));
const runtimeOptions = runtimes.map((rt) => ({
label: rt.path,
value: PackageableElementExplicitReference.create(rt),
}));
const runtimePointerWarning = !runtimes.includes(defaultRuntime.value) // if the runtime does not belong to the chosen mapping
? `runtime is not associated with specified mapping '${mapping.path}'`
: undefined;
const selectedRuntimeOption = {
value: defaultRuntime,
label: (_jsxs("div", { className: "service-execution-editor__configuration__runtime-option__pointer", title: undefined, children: [_jsx("div", { className: clsx('service-execution-editor__configuration__runtime-option__pointer__label', {
'service-execution-editor__configuration__runtime-option__pointer__label--with-warning': Boolean(runtimePointerWarning),
}), children: defaultRuntime.value.path }), runtimePointerWarning && (_jsx("div", { className: "service-execution-editor__configuration__runtime-option__pointer__warning", title: runtimePointerWarning, children: _jsx(ExclamationTriangleIcon, {}) }))] })),
};
const onRuntimeSelectionChange = (val) => {
if (val.value?.value !== defaultRuntime.value &&
val.value !== undefined) {
dataSpace_setExecutionContextDefaultRuntime(executionContext, val.value);
}
};
const visitRuntime = () => {
editorStore.graphEditorMode.openElement(defaultRuntime.value);
};
// DnD
const handleMappingOrRuntimeDrop = useCallback((item) => {
const element = item.data.packageableElement;
if (!isReadOnly) {
if (element instanceof Mapping) {
dataSpace_setExecutionContextMapping(executionContext, PackageableElementExplicitReference.create(element));
executionContextState.autoSelectRuntimeOnMappingChange(element);
}
else if (element instanceof PackageableRuntime &&
element.runtimeValue.mappings.map((m) => m.value).includes(mapping)) {
dataSpace_setExecutionContextDefaultRuntime(executionContext, PackageableElementExplicitReference.create(element));
}
}
}, [isReadOnly, mapping, executionContextState, executionContext]);
const [{ isMappingOrRuntimeDragOver }, dropConnector] = useDrop(() => ({
accept: [
CORE_DND_TYPE.PROJECT_EXPLORER_MAPPING,
CORE_DND_TYPE.PROJECT_EXPLORER_RUNTIME,
],
drop: (item) => handleMappingOrRuntimeDrop(item),
collect: (monitor) => ({
isMappingOrRuntimeDragOver: monitor.isOver({ shallow: true }),
}),
}), [handleMappingOrRuntimeDrop]);
return (_jsx(PanelContent, { children: _jsx(PanelDropZone, { dropTargetConnector: dropConnector, isDragOver: isMappingOrRuntimeDragOver && !isReadOnly, children: _jsxs("div", { className: "service-execution-editor__configuration__items", children: [_jsxs("div", { className: "service-execution-editor__configuration__item", children: [_jsx("div", { className: "btn--sm service-execution-editor__configuration__item__label", children: _jsx(PURE_MappingIcon, {}) }), _jsx(CustomSelectorInput, { className: "panel__content__form__section__dropdown service-execution-editor__configuration__item__dropdown", disabled: isReadOnly, options: mappingOptions, onChange: onMappingSelectionChange, value: selectedMappingOption, darkMode: !applicationStore.layoutService
.TEMPORARY__isLightColorThemeEnabled, hasError: Boolean(isMappingEmpty) }), _jsx("button", { className: "btn--dark btn--sm service-execution-editor__configuration__item__btn", onClick: visitMapping, tabIndex: -1, title: "See mapping", disabled: Boolean(isMappingEmpty), children: _jsx(LongArrowRightIcon, {}) })] }), _jsxs("div", { className: "service-execution-editor__configuration__item", children: [_jsx("div", { className: "btn--sm service-execution-editor__configuration__item__label", children: _jsx(PURE_RuntimeIcon, {}) }), _jsx(CustomSelectorInput, { className: "panel__content__form__section__dropdown service-execution-editor__configuration__item__dropdown", disabled: isReadOnly, options: runtimeOptions, onChange: onRuntimeSelectionChange, value: selectedRuntimeOption, darkMode: !applicationStore.layoutService
.TEMPORARY__isLightColorThemeEnabled }), _jsx("button", { className: "btn--sm btn--dark service-execution-editor__configuration__item__btn", onClick: visitRuntime, tabIndex: -1, title: "See runtime", children: _jsx(LongArrowRightIcon, {}) })] }), _jsxs("div", { className: "execution-context-editor__form-section", children: [_jsx("div", { className: "execution-context-editor__form-section__label", children: "Title" }), _jsx("div", { className: "execution-context-editor__form-section__content", children: _jsx("input", { className: "execution-context-editor__form-section__content__input panel__content__form__section__input", spellCheck: false, disabled: isReadOnly, value: executionContext.title ?? '', onChange: (event) => dataSpace_setExecutionContextTitle(executionContext, event.target.value) }) })] }), _jsxs("div", { className: "execution-context-editor__form-section", children: [_jsx("div", { className: "execution-context-editor__form-section__label", children: "Description" }), _jsx("div", { className: "execution-context-editor__form-section__content", children: _jsx("textarea", { className: "execution-context-editor__form-section__content__textarea panel__content__form__section__input", spellCheck: false, disabled: isReadOnly, value: executionContext.description ?? '', onChange: (event) => dataSpace_setExecutionContextDescription(executionContext, event.target.value), rows: 4 }) })] })] }) }) }));
});
export const NewExecutionContextModal = observer((props) => {
const { executionState, isReadOnly } = props;
const [name, setName] = useState('');
const validationMessage = name === ''
? `Execution context name can't be empty`
: executionState.executionContexts.find((e) => e.name === name)
? 'Execution context name already exists'
: undefined;
const closeModal = () => executionState.setNewExecutionContextModal(false);
const onChange = (event) => {
setName(event.target.value);
};
return (_jsx(Dialog, { open: executionState.newExecutionContextModal, onClose: closeModal, classes: { container: 'search-modal__container' }, slotProps: {
paper: {
classes: { root: 'search-modal__inner-container' },
},
}, children: _jsxs("form", { onSubmit: (event) => {
event.preventDefault();
executionState.addExecutionContext(name);
setName('');
closeModal();
}, className: "modal modal--dark search-modal", children: [_jsx(ModalTitle, { title: "New Execution Context" }), _jsx("div", { className: "service-execution-editor__change__modal", children: _jsx(InputWithInlineValidation, { className: "service-execution-editor__input input-group__input", spellCheck: false, value: name, onChange: onChange, placeholder: "Key execution name", error: validationMessage }) }), _jsx("div", { className: "search-modal__actions", children: _jsx("button", { className: "btn btn--dark", disabled: isReadOnly || Boolean(validationMessage), children: "Add" }) })] }) }));
});
export const RenameModal = observer((props) => {
const { val, isReadOnly, showModal, closeModal, setValue, executionContext, } = props;
const [inputValue, setInputValue] = useState(val);
const changeValue = (event) => {
setInputValue(event.target.value);
};
return (_jsx(Dialog, { open: showModal, onClose: closeModal, classes: { container: 'search-modal__container' }, slotProps: {
paper: {
classes: { root: 'search-modal__inner-container' },
},
}, children: _jsxs("form", { onSubmit: (event) => {
event.preventDefault();
setValue(inputValue);
closeModal();
}, className: "modal modal--dark search-modal", children: [_jsx(ModalTitle, { title: "Edit Execution Context" }), _jsxs("div", { className: "execution-context-editor__form-section", children: [_jsx("div", { className: "execution-context-editor__form-section__label", children: "Key" }), _jsx("div", { className: "execution-context-editor__form-section__content", children: _jsx("input", { className: "execution-context-editor__form-section__content__input panel__content__form__section__input", spellCheck: false, disabled: isReadOnly, value: inputValue, onChange: changeValue }) })] }), _jsxs("div", { className: "execution-context-editor__form-section", children: [_jsx("div", { className: "execution-context-editor__form-section__label", children: "Title" }), _jsx("div", { className: "execution-context-editor__form-section__content", children: _jsx("input", { className: "execution-context-editor__form-section__content__input panel__content__form__section__input", spellCheck: false, disabled: isReadOnly, value: executionContext.title ?? '', onChange: (event) => dataSpace_setExecutionContextTitle(executionContext, event.target.value) }) })] }), _jsxs("div", { className: "execution-context-editor__form-section", children: [_jsx("div", { className: "execution-context-editor__form-section__label", children: "Description" }), _jsx("div", { className: "execution-context-editor__form-section__content", children: _jsx("textarea", { className: "execution-context-editor__form-section__content__textarea panel__content__form__section__input", spellCheck: false, disabled: isReadOnly, value: executionContext.description ?? '', onChange: (event) => dataSpace_setExecutionContextDescription(executionContext, event.target.value), rows: 4 }) })] }), _jsx("div", { className: "search-modal__actions", children: _jsx("button", { className: "btn btn--dark", disabled: isReadOnly, children: "Done" }) })] }) }));
});
const ExecutionContextMenu = observer(forwardRef(function TestContainerContextMenu(props, ref) {
const { dataSpaceExecutionContextState, dataSpaceExecutionContext } = props;
const rename = () => {
dataSpaceExecutionContextState.setExecutionContextToRename(dataSpaceExecutionContext);
};
const remove = () => {
dataSpaceExecutionContextState.removeExecutionContext(dataSpaceExecutionContext);
};
const add = () => {
dataSpaceExecutionContextState.setNewExecutionContextModal(true);
};
return (_jsxs(MenuContent, { ref: ref, children: [_jsx(MenuContentItem, { onClick: rename, children: "Rename" }), _jsx(MenuContentItem, { onClick: remove, children: "Delete" }), _jsx(MenuContentItem, { onClick: add, children: "Create a new key" })] }));
}));
const ExecutionContextItem = observer((props) => {
const { dataSpaceExecutionContextState, dataSpaceExecutionContext, isReadOnly, } = props;
const [isSelectedFromContextMenu, setIsSelectedFromContextMenu] = useState(false);
const isActive = dataSpaceExecutionContextState.selectedExecutionContext ===
dataSpaceExecutionContext;
const openKeyedExecution = () => dataSpaceExecutionContextState.setSelectedExecutionContext(dataSpaceExecutionContext);
const onContextMenuOpen = () => setIsSelectedFromContextMenu(true);
const onContextMenuClose = () => setIsSelectedFromContextMenu(false);
return (_jsx(ContextMenu, { className: clsx('service-multi-execution-editor__item', {
'service-multi-execution-editor__item--selected-from-context-menu': !isActive && isSelectedFromContextMenu,
}, { 'service-multi-execution-editor__item--active': isActive }), disabled: isReadOnly, content: _jsx(ExecutionContextMenu, { dataSpaceExecutionContextState: dataSpaceExecutionContextState, dataSpaceExecutionContext: dataSpaceExecutionContext, isReadOnly: isReadOnly }), menuProps: { elevation: 7 }, onOpen: onContextMenuOpen, onClose: onContextMenuClose, children: _jsx("button", { className: clsx('service-multi-execution-editor__item__label'), onClick: openKeyedExecution, tabIndex: -1, children: dataSpaceExecutionContext.name }) }));
});
export const DataSpaceExecutionContextEditor = observer(() => {
const editorStore = useEditorStore();
const dataSpaceState = editorStore.tabManagerState.getCurrentEditorState(DataSpaceEditorState);
const executionContextState = dataSpaceState.executionContextState;
const addExecutionKey = () => {
executionContextState.setNewExecutionContextModal(true);
};
return (_jsx("div", { className: "service-execution-editor__execution", children: _jsxs(ResizablePanelGroup, { orientation: "vertical", children: [_jsxs(ResizablePanel, { size: 300, minSize: 200, children: [_jsxs("div", { className: "service-multi-execution-editor__panel", children: [_jsxs(PanelHeader, { children: [_jsx("div", { className: "panel__header__title", children: _jsx("div", { className: "panel__header__title__content", children: "Execution Contexts" }) }), _jsx(PanelHeaderActions, { children: _jsx(PanelHeaderActionItem, { disabled: dataSpaceState.isReadOnly, onClick: addExecutionKey, title: "Add an execution context", children: _jsx(PlusIcon, {}) }) })] }), executionContextState.executionContexts.map((executionContext) => (_jsx(ExecutionContextItem, { dataSpaceExecutionContextState: executionContextState, dataSpaceExecutionContext: executionContext, isReadOnly: dataSpaceState.isReadOnly }, executionContext.name))), !executionContextState.executionContexts.length && (_jsx(BlankPanelPlaceholder, { text: "Add an execution context", onClick: addExecutionKey, clickActionType: "add", tooltipText: "Click to add an execution context" }))] }), executionContextState.newExecutionContextModal && (_jsx(NewExecutionContextModal, { executionState: executionContextState, isReadOnly: dataSpaceState.isReadOnly })), executionContextState.executionContextToRename && (_jsx(RenameModal, { val: executionContextState.executionContextToRename.name, isReadOnly: dataSpaceState.isReadOnly, showModal: true, closeModal: () => executionContextState.setExecutionContextToRename(undefined), setValue: (val) => executionContextState.renameExecutionContext(guaranteeNonNullable(executionContextState.executionContextToRename), val), executionContext: executionContextState.executionContextToRename }))] }), _jsx(ResizablePanelSplitter, { children: _jsx(ResizablePanelSplitterLine, { color: "var(--color-dark-grey-200)" }) }), _jsx(ResizablePanel, { minSize: 56, children: executionContextState.selectedExecutionContext ? (_jsx(DataSpaceExecutionContextConfigurationEditor, { executionContextState: executionContextState, executionContext: executionContextState.selectedExecutionContext })) : (_jsx(BlankPanelPlaceholder, { text: "Add an execution context", onClick: addExecutionKey, clickActionType: "add", tooltipText: "Click to add an execution context" })) })] }) }));
});
//# sourceMappingURL=DataSpaceExecutionContextEditor.js.map