@finos/legend-studio
Version:
285 lines • 15.8 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 { 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