UNPKG

@finos/legend-studio

Version:
285 lines 15.8 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 { useRef } from 'react'; import { LEGEND_STUDIO_TEST_ID } from '../../LegendStudioTestID.js'; import { observer } from 'mobx-react-lite'; import { NewPackageableRuntimeDriver, NewPackageableConnectionDriver, NewPureModelConnectionDriver, NewFileGenerationDriver, resolvePackageAndElementName, CONNECTION_TYPE, NewDataElementDriver, NewServiceDriver, } from '../../../stores/editor/NewElementState.js'; import { Dialog, compareLabelFn, CustomSelectorInput } from '@finos/legend-art'; import { prettyCONSTName } from '@finos/legend-shared'; import { useEditorStore } from '../EditorStoreProvider.js'; import { ELEMENT_PATH_DELIMITER, } from '@finos/legend-graph'; import { flowResult } from 'mobx'; import { getPackageableElementOptionalFormatter, useApplicationStore, } from '@finos/legend-application'; import { PACKAGEABLE_ELEMENT_TYPE } from '../../../stores/shared/ModelUtil.js'; import { EmbeddedDataType } from '../../../stores/editor-state/ExternalFormatState.js'; export const getElementTypeLabel = (editorStore, type) => { switch (type) { case PACKAGEABLE_ELEMENT_TYPE.PACKAGE: case PACKAGEABLE_ELEMENT_TYPE.CLASS: case PACKAGEABLE_ELEMENT_TYPE.ENUMERATION: case PACKAGEABLE_ELEMENT_TYPE.ASSOCIATION: case PACKAGEABLE_ELEMENT_TYPE.MEASURE: case PACKAGEABLE_ELEMENT_TYPE.PROFILE: case PACKAGEABLE_ELEMENT_TYPE.FUNCTION: case PACKAGEABLE_ELEMENT_TYPE.MAPPING: case PACKAGEABLE_ELEMENT_TYPE.CONNECTION: case PACKAGEABLE_ELEMENT_TYPE.RUNTIME: case PACKAGEABLE_ELEMENT_TYPE.SERVICE: return type.toLowerCase(); case PACKAGEABLE_ELEMENT_TYPE.FLAT_DATA_STORE: return 'flat-data store'; case PACKAGEABLE_ELEMENT_TYPE.DATABASE: return 'relational database'; case PACKAGEABLE_ELEMENT_TYPE.SERVICE_STORE: return 'service store'; case PACKAGEABLE_ELEMENT_TYPE.FILE_GENERATION: return 'file generation'; case PACKAGEABLE_ELEMENT_TYPE.GENERATION_SPECIFICATION: return 'generation specification'; case PACKAGEABLE_ELEMENT_TYPE.DATA: return 'data'; default: { if (type) { const extraElementTypeLabelGetters = editorStore.pluginManager .getApplicationPlugins() .flatMap((plugin) => plugin.getExtraElementTypeLabelGetters?.() ?? []); for (const typeLabelGetter of extraElementTypeLabelGetters) { const label = typeLabelGetter(type); if (label) { return label; } } return type.toLowerCase(); } return undefined; } } }; const buildElementTypeOption = (type) => ({ label: type, value: type, }); const NewDataElementDriverEditor = observer(() => { const editorStore = useEditorStore(); const newDataELementDriver = editorStore.newElementState.getNewElementDriver(NewDataElementDriver); const selectedOption = newDataELementDriver.embeddedDataOption ? { label: prettyCONSTName(newDataELementDriver.embeddedDataOption.label), value: newDataELementDriver.embeddedDataOption.value, } : undefined; const extraOptionTypes = editorStore.pluginManager .getApplicationPlugins() .flatMap((plugin) => plugin.getExtraEmbeddedDataTypeOptions?.() ?? []); let options = Object.values(EmbeddedDataType) .filter((type) => type !== EmbeddedDataType.DATA_ELEMENT) .map((typeOption) => ({ label: prettyCONSTName(typeOption), value: typeOption, })); options = options.concat(extraOptionTypes); const onTypeSelectionChange = (val) => { if (!val) { newDataELementDriver.setEmbeddedDataOption(undefined); } else { newDataELementDriver.setEmbeddedDataOption(val); } }; return (_jsx("div", { className: "explorer__new-element-modal__driver", children: _jsx(CustomSelectorInput, { className: "explorer__new-element-modal__driver__dropdown", options: options, onChange: onTypeSelectionChange, value: selectedOption, darkMode: true }) })); }); const NewRuntimeDriverEditor = observer(() => { const editorStore = useEditorStore(); const newRuntimeDriver = editorStore.newElementState.getNewElementDriver(NewPackageableRuntimeDriver); // mapping const mapping = newRuntimeDriver.mapping; const mappingOptions = editorStore.mappingOptions; const selectedMappingOption = { label: mapping?.path ?? '', value: mapping }; const onMappingSelectionChange = (val) => { if (val.value !== mapping) { newRuntimeDriver.setMapping(val.value); } }; if (!mapping) { // TODO: show warning return _jsx("div", { children: "no mapping found" }); } return (_jsx("div", { className: "explorer__new-element-modal__driver", children: _jsx(CustomSelectorInput, { className: "explorer__new-element-modal__driver__dropdown", options: mappingOptions, onChange: onMappingSelectionChange, value: selectedMappingOption, darkMode: true }) })); }); const NewPureModelConnectionDriverEditor = observer((props) => { const { newConnectionDriver, newConnectionValueDriver } = props; const editorStore = useEditorStore(); // store const store = newConnectionDriver.store; let storeOptions = [ { label: 'ModelStore', value: undefined }, ]; storeOptions = storeOptions.concat(editorStore.storeOptions.slice().sort(compareLabelFn)); const selectedStoreOption = { label: store?.path ?? 'ModelStore', value: store, }; const onStoreSelectionChange = (val) => newConnectionDriver.setStore(val.value); // class const _class = newConnectionValueDriver.class; const classOptions = editorStore.classOptions.slice().sort(compareLabelFn); const selectedClassOption = _class ? { label: _class.path, value: _class } : null; const onClassSelectionChange = (val) => { if (val) { newConnectionValueDriver.setClass(val.value); } }; if (!_class) { // TODO: show warning return _jsx("div", { children: "no class found" }); } return (_jsxs(_Fragment, { children: [_jsx("div", { className: "explorer__new-element-modal__driver", children: _jsx(CustomSelectorInput, { className: "explorer__new-element-modal__driver__dropdown", options: storeOptions, onChange: onStoreSelectionChange, value: selectedStoreOption, darkMode: true }) }), _jsx("div", { className: "explorer__new-element-modal__driver", children: _jsx(CustomSelectorInput, { className: "sub-panel__content__form__section__dropdown panel__content__form__section__dropdown", options: classOptions, onChange: onClassSelectionChange, value: selectedClassOption, darkMode: true, formatOptionLabel: getPackageableElementOptionalFormatter({ darkMode: true, }) }) })] })); }); const NewConnectionValueDriverEditor = observer(() => { const editorStore = useEditorStore(); const newConnectionDriver = editorStore.newElementState.getNewElementDriver(NewPackageableConnectionDriver); const newConnectionValueDriver = newConnectionDriver.newConnectionValueDriver; if (newConnectionValueDriver instanceof NewPureModelConnectionDriver) { return (_jsx(NewPureModelConnectionDriverEditor, { newConnectionDriver: newConnectionDriver, newConnectionValueDriver: newConnectionValueDriver })); } return null; }); const NewConnectionDriverEditor = observer(() => { const editorStore = useEditorStore(); const newConnectionDriver = editorStore.newElementState.getNewElementDriver(NewPackageableConnectionDriver); // type const currentConnectionType = newConnectionDriver.geDriverConnectionType(); const currentConnectionTypeOption = { label: prettyCONSTName(currentConnectionType), value: currentConnectionType, }; const connectionOptions = Object.values(CONNECTION_TYPE).map((e) => ({ label: prettyCONSTName(e), value: e, })); const onConnectionChange = (val) => { if (val?.value && currentConnectionTypeOption.value !== val.value) { newConnectionDriver.changeConnectionState(val.value); } }; return (_jsxs(_Fragment, { children: [_jsx("div", { className: "explorer__new-element-modal__driver", children: _jsx(CustomSelectorInput, { className: "explorer__new-element-modal__driver__dropdown", options: connectionOptions, onChange: onConnectionChange, value: currentConnectionTypeOption, darkMode: true }) }), _jsx(NewConnectionValueDriverEditor, {})] })); }); const NewServiceDriverEditor = observer(() => { const editorStore = useEditorStore(); const newServiceDriver = editorStore.newElementState.getNewElementDriver(NewServiceDriver); // mapping const currentMappingOption = newServiceDriver.mappingOption; const mappingOptions = editorStore.mappingOptions; const onMappingChange = (val) => { if (!val) { newServiceDriver.setMappingOption(undefined); } else { newServiceDriver.setMappingOption(val); } }; return (_jsx("div", { className: "explorer__new-element-modal__driver", children: _jsx(CustomSelectorInput, { className: "explorer__new-element-modal__driver__dropdown", options: mappingOptions, onChange: onMappingChange, value: currentMappingOption, darkMode: true }) })); }); const NewFileGenerationDriverEditor = observer(() => { const editorStore = useEditorStore(); const newConnectionDriver = editorStore.newElementState.getNewElementDriver(NewFileGenerationDriver); const options = editorStore.graphState.graphGenerationState .fileGenerationConfigurationOptions; const onTypeSelectionChange = (val) => { if (!val) { newConnectionDriver.setTypeOption(undefined); } else { newConnectionDriver.setTypeOption(val); } }; return (_jsx("div", { className: "explorer__new-element-modal__driver", children: _jsx(CustomSelectorInput, { className: "sub-panel__content__form__section__dropdown explorer__new-element-modal__driver__dropdown", options: options, onChange: onTypeSelectionChange, value: newConnectionDriver.typeOption }) })); }); const renderNewElementDriver = (type, editorStore) => { switch (type) { case PACKAGEABLE_ELEMENT_TYPE.RUNTIME: return _jsx(NewRuntimeDriverEditor, {}); case PACKAGEABLE_ELEMENT_TYPE.CONNECTION: return _jsx(NewConnectionDriverEditor, {}); case PACKAGEABLE_ELEMENT_TYPE.FILE_GENERATION: return _jsx(NewFileGenerationDriverEditor, {}); case PACKAGEABLE_ELEMENT_TYPE.DATA: return _jsx(NewDataElementDriverEditor, {}); case PACKAGEABLE_ELEMENT_TYPE.SERVICE: return _jsx(NewServiceDriverEditor, {}); default: { const extraNewElementDriverEditorCreators = editorStore.pluginManager .getApplicationPlugins() .flatMap((plugin) => plugin.getExtraNewElementDriverEditorRenderers?.() ?? []); for (const creator of extraNewElementDriverEditorCreators) { const editor = creator(type); if (editor) { return editor; } } return null; } } }; // TODO: investigate the potential approach of VSCode to have inline input in the tree to create element quickly export const CreateNewElementModal = observer(() => { const editorStore = useEditorStore(); const applicationStore = useApplicationStore(); const newElementState = editorStore.newElementState; const selectedPackage = newElementState.selectedPackage; // Name const name = newElementState.name; const handleNameChange = (event) => newElementState.setName(event.target.value); const elementNameInputRef = useRef(null); // Type const typeOptions = [PACKAGEABLE_ELEMENT_TYPE.PACKAGE] .concat(editorStore.getSupportedElementTypes()) .filter( // NOTE: we can only create package in root (type) => selectedPackage !== editorStore.graphManagerState.graph.root || type === PACKAGEABLE_ELEMENT_TYPE.PACKAGE) .map(buildElementTypeOption); const selectedTypeOption = buildElementTypeOption(newElementState.type); const handleTypeChange = (val) => newElementState.setElementType(val.value); // Submit button const closeModal = () => newElementState.closeModal(); const [packagePath, elementName] = resolvePackageAndElementName(selectedPackage, selectedPackage === editorStore.graphManagerState.graph.root, name); const resolvedPackage = editorStore.graphManagerState.graph.getNullablePackage(packagePath); const needsToOverride = Boolean(resolvedPackage?.children.find((child) => child.name === elementName)); const isDisabled = !name || needsToOverride || !newElementState.isValid; const save = applicationStore.guardUnhandledError(() => flowResult(newElementState.save())); const handleEnter = () => { newElementState.setName(''); elementNameInputRef.current?.focus(); }; const handleSubmit = (event) => { event.preventDefault(); save(); }; if (!newElementState.showModal) { return null; } return (_jsx(Dialog, { open: newElementState.showModal, onClose: closeModal, TransitionProps: { onEnter: handleEnter, }, classes: { container: 'search-modal__container' }, PaperProps: { classes: { root: 'search-modal__inner-container' } }, children: _jsxs("form", { "data-testid": LEGEND_STUDIO_TEST_ID.NEW_ELEMENT_MODAL, onSubmit: handleSubmit, className: "modal modal--dark search-modal", children: [_jsxs("div", { className: "modal__title", children: ["Create a New", ' ', getElementTypeLabel(editorStore, newElementState.type) ?? 'element'] }), _jsxs("div", { children: [newElementState.showType && (_jsx(CustomSelectorInput, { options: typeOptions, disabled: typeOptions.length === 1, onChange: handleTypeChange, value: selectedTypeOption, isClearable: false })), _jsx("input", { className: "input--dark explorer__new-element-modal__name-input", ref: elementNameInputRef, spellCheck: false, value: name, onChange: handleNameChange, placeholder: `Enter a name, use ${ELEMENT_PATH_DELIMITER} to create new package(s) for the ${getElementTypeLabel(editorStore, newElementState.type) ?? 'element'}` }), renderNewElementDriver(newElementState.type, editorStore)] }), _jsxs("div", { className: "search-modal__actions", children: [_jsx("button", { type: "button", className: "btn btn--dark", onClick: closeModal, children: "Cancel" }), _jsx("button", { className: "btn btn--dark", disabled: isDisabled, children: "Create" })] })] }) })); }); //# sourceMappingURL=CreateNewElementModal.js.map