UNPKG

@finos/legend-application-studio

Version:
174 lines 14.4 kB
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 { observer } from 'mobx-react-lite'; import { PurePropertyMappingEditor } from './PurePropertyMappingEditor.js'; import { getElementIcon } from '../../../ElementIconUtils.js'; import { MappingEditorState, } from '../../../../stores/editor/editor-state/element-editor-state/mapping/MappingEditorState.js'; import { PurePropertyMappingState, PureInstanceSetImplementationState, } from '../../../../stores/editor/editor-state/element-editor-state/mapping/PureInstanceSetImplementationState.js'; import { clsx, ArrowCircleRightIcon, TimesCircleIcon, TimesIcon, AsteriskIcon, } from '@finos/legend-art'; import { guaranteeType } from '@finos/legend-shared'; import { FlatDataInstanceSetImplementationState, } from '../../../../stores/editor/editor-state/element-editor-state/mapping/FlatDataInstanceSetImplementationState.js'; import { FlatDataPropertyMappingEditor } from './FlatDataPropertyMappingEditor.js'; import { RelationalPropertyMappingEditor } from './relational/RelationalPropertyMappingEditor.js'; import { useEditorStore } from '../../EditorStoreProvider.js'; import { getRootSetImplementation, Class, SetImplementation, PrimitiveType, PureInstanceSetImplementation, EmbeddedFlatDataPropertyMapping, OperationSetImplementation, FlatDataInstanceSetImplementation, RootRelationalInstanceSetImplementation, MULTIPLICITY_INFINITE, } from '@finos/legend-graph'; import { useApplicationStore } from '@finos/legend-application'; import { instanceSetImplementation_deletePropertyMapping, setImpl_nominateRoot, setImplementation_setRoot, } from '../../../../stores/graph-modifier/DSL_Mapping_GraphModifierHelper.js'; import { CLASS_PROPERTY_TYPE, getClassPropertyType, } from '../../../../stores/editor/utils/ModelClassifierUtils.js'; import { Fragment } from 'react'; const MultiplicityBadge = (props) => { const { multiplicity } = props; const isRequired = multiplicity.lowerBound && multiplicity.lowerBound > 0; const tooltipText = `${isRequired ? '[required]' : '[optional]'}${isRequired ? ` minimum: ${multiplicity.lowerBound}` : ''} maximum: ${multiplicity.upperBound ?? MULTIPLICITY_INFINITE}`; return (_jsx("div", { className: `multiplicity-badge ${isRequired ? 'multiplicity-badge--required' : ''}`, title: tooltipText, children: multiplicity.upperBound ? null : _jsx(AsteriskIcon, {}) })); }; export const getExpectedReturnType = (targetSetImplementation) => { if (targetSetImplementation instanceof PureInstanceSetImplementation) { return targetSetImplementation.srcClass?.value; } else if (targetSetImplementation instanceof OperationSetImplementation) { return targetSetImplementation.class.value; } else { return undefined; } }; const GenericPropertyMappingEditorEntry = observer((props) => { const { children, instanceSetImplementationState, propertyMappingStates, propertyMappingState, propertyBasicType, } = props; const removePropertyMapping = (pm) => { instanceSetImplementation_deletePropertyMapping(instanceSetImplementationState.mappingElement, pm); instanceSetImplementationState.decorate(); }; return (_jsxs("div", { className: "property-mapping-editor__generic-entry", children: [children, propertyMappingStates.length > 1 && propertyBasicType !== CLASS_PROPERTY_TYPE.CLASS && (_jsx("button", { className: "property-mapping-editor__generic-entry__remove-btn", onClick: () => removePropertyMapping(propertyMappingState.propertyMapping), tabIndex: -1, title: "Remove", children: _jsx(TimesIcon, {}) }))] })); }); export const PropertyMappingEditor = observer((props) => { const { instanceSetImplementationState, property, isReadOnly } = props; const instanceSetImplementation = instanceSetImplementationState.mappingElement; const validationErrorMessage = instanceSetImplementation.propertyMappings.filter((pm) => pm.property.value === property).length > 1 && !(property.genericType.value.rawType instanceof Class) ? 'Only one property mapping should exist per property of type other than class (e.g. primitive, measure, enumeration)' : undefined; const editorStore = useEditorStore(); const applicationStore = useApplicationStore(); const mappingEditorState = editorStore.tabManagerState.getCurrentEditorState(MappingEditorState); const propertyRawType = property.genericType.value.rawType; const propertyBasicType = getClassPropertyType(propertyRawType); const isEmbedded = instanceSetImplementation._isEmbedded; // Parser Error const propertyMappingStates = instanceSetImplementationState.propertyMappingStates.filter((pm) => pm.propertyMapping.property.value === property); const propertyHasParserError = Boolean(propertyMappingStates.find((pm) => pm.parserError)); const setImplementationHasParserError = Boolean(instanceSetImplementationState.propertyMappingStates.find((pm) => pm.parserError)); /** * TODO: revisit this behavior now that we have more types of property mapping to support * e.g. embedded, target set implementation, etc. * See https://github.com/finos/legend-studio/issues/310 * * @modularize * TODO: modularize this for other types * See https://github.com/finos/legend-studio/issues/65 */ const visitOrCreateMappingElement = () => { if (propertyRawType instanceof Class) { if (instanceSetImplementation instanceof PureInstanceSetImplementation) { const rootMappingElement = getRootSetImplementation(mappingEditorState.mapping, propertyRawType); if (rootMappingElement) { if (!rootMappingElement.root.value) { setImplementation_setRoot(rootMappingElement, true); } const parent = rootMappingElement._PARENT; if (parent !== mappingEditorState.element) { // TODO: think more about this flow. Right now we open the mapping element in the parent mapping editorStore.graphEditorMode.openElement(parent); editorStore.tabManagerState .getCurrentEditorState(MappingEditorState) .openMappingElement(rootMappingElement, false); } { mappingEditorState.openMappingElement(rootMappingElement, true); } } else { if (!isReadOnly) { mappingEditorState.createMappingElement({ target: property.genericType.value.rawType, showTarget: false, openInAdjacentTab: true, postSubmitAction: (newSetImpl) => { // Make this set implementation the new root if (newSetImpl instanceof SetImplementation) { setImpl_nominateRoot(newSetImpl); } }, }); } } } else if (instanceSetImplementationState instanceof FlatDataInstanceSetImplementationState) { if (propertyMappingStates.length === 1 && propertyMappingStates[0]?.propertyMapping instanceof EmbeddedFlatDataPropertyMapping) { mappingEditorState.openMappingElement(propertyMappingStates[0].propertyMapping, true); } else if (!propertyMappingStates.length) { const embedded = instanceSetImplementationState.addEmbeddedPropertyMapping(property); mappingEditorState.openMappingElement(embedded, true); } } else { applicationStore.notificationService.notifyWarning(`Can't visit mapping element for type '${propertyRawType.name}'`); } } }; const renderPropertyMappingEntry = (propertyMappingState) => { if (instanceSetImplementation instanceof PureInstanceSetImplementation) { return (_jsx(PurePropertyMappingEditor, { isReadOnly: isReadOnly, pureInstanceSetImplementationState: guaranteeType(instanceSetImplementationState, PureInstanceSetImplementationState), purePropertyMappingState: guaranteeType(propertyMappingState, PurePropertyMappingState), setImplementationHasParserError: setImplementationHasParserError })); } else if (instanceSetImplementation instanceof FlatDataInstanceSetImplementation || instanceSetImplementation instanceof EmbeddedFlatDataPropertyMapping) { return (_jsx(FlatDataPropertyMappingEditor, { isReadOnly: isReadOnly, flatDataInstanceSetImplementationState: instanceSetImplementationState, flatDataPropertyMappingState: propertyMappingState, setImplementationHasParserError: setImplementationHasParserError })); } else if (instanceSetImplementation instanceof RootRelationalInstanceSetImplementation) { return (_jsx(RelationalPropertyMappingEditor, { isReadOnly: isReadOnly, relationalInstanceSetImplementationState: instanceSetImplementationState, relationalPropertyMappingState: propertyMappingState, setImplementationHasParserError: setImplementationHasParserError })); } else { const extraPropertyMappingEditorRenderers = editorStore.pluginManager .getApplicationPlugins() .flatMap((plugin) => plugin.getExtraPropertyMappingEditorRenderers?.() ?? []); for (const renderer of extraPropertyMappingEditorRenderers) { const renderedPropertyMappingEditor = renderer(instanceSetImplementationState, propertyMappingState); if (renderedPropertyMappingEditor) { return (_jsx(Fragment, { children: renderedPropertyMappingEditor }, propertyMappingState.uuid)); } } return (_jsx("div", { className: "property-mapping-editor__entry--unsupported", children: "Unsupported property mapping" }, propertyMappingState.uuid)); } }; return (_jsxs("div", { className: clsx('property-mapping-editor', { backdrop__element: propertyHasParserError, }), children: [_jsxs("div", { className: "property-mapping-editor__metadata", children: [_jsxs("div", { className: clsx('property-mapping-editor__name', { 'property-mapping-editor__name--with-validation': Boolean(validationErrorMessage), }), children: [_jsx("div", { className: "property-mapping-editor__name__label", children: property.name }), validationErrorMessage && (_jsx("div", { className: "property-mapping-editor__name--with-validation__indicator", title: validationErrorMessage, children: _jsx(TimesCircleIcon, {}) }))] }), _jsxs("div", { className: "property-mapping-editor__info", children: [_jsxs("div", { className: clsx('property-mapping-editor__type', `background--${propertyBasicType.toLowerCase()}`, { 'property-mapping-editor__type--has-visit-btn': propertyBasicType === CLASS_PROPERTY_TYPE.CLASS, }), title: propertyRawType instanceof PrimitiveType ? undefined : propertyRawType.path, children: [propertyBasicType !== CLASS_PROPERTY_TYPE.PRIMITIVE && (_jsx("div", { className: "property-mapping-editor__type__abbr", children: getElementIcon(propertyRawType, editorStore) })), _jsx("div", { className: "property-mapping-editor__type__label", children: propertyRawType.name }), propertyBasicType === CLASS_PROPERTY_TYPE.CLASS && (_jsx("button", { className: "property-mapping-editor__type__visit-btn", onClick: visitOrCreateMappingElement, tabIndex: -1, title: "Visit mapping element", children: _jsx(ArrowCircleRightIcon, {}) }))] }), _jsx("div", { className: "property-mapping-editor__multiplicity", children: _jsx(MultiplicityBadge, { multiplicity: property.multiplicity }) })] })] }), _jsxs("div", { className: "property-mapping-editor__content", children: [propertyMappingStates.map((propertyMappingState) => (_jsx(GenericPropertyMappingEditorEntry, { instanceSetImplementationState: instanceSetImplementationState, propertyBasicType: propertyBasicType, propertyMappingStates: propertyMappingStates, propertyMappingState: propertyMappingState, children: renderPropertyMappingEntry(propertyMappingState) }, propertyMappingState.uuid))), propertyBasicType === CLASS_PROPERTY_TYPE.CLASS && !propertyMappingStates.length && (_jsxs(_Fragment, { children: [isEmbedded && (_jsxs("div", { className: "property-mapping-editor__entry--empty", children: ["Click", _jsx("button", { className: "property-mapping-editor__entry--empty__visit-btn", onClick: visitOrCreateMappingElement, tabIndex: -1, title: "Create mapping element", children: _jsx(ArrowCircleRightIcon, {}) }), `to create an embedded class mapping for property '${property.name}'.`] })), !isEmbedded && (_jsxs("div", { className: "property-mapping-editor__entry--empty", children: ["No set implementation found. Click", _jsx("button", { className: "property-mapping-editor__entry--empty__visit-btn", onClick: visitOrCreateMappingElement, tabIndex: -1, title: "Create mapping element", children: _jsx(ArrowCircleRightIcon, {}) }), `to create a root class mapping for '${propertyRawType.name}'.`] }))] }))] })] })); }); //# sourceMappingURL=PropertyMappingsEditor.js.map