/** * 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 { useEditorStore } from '../../EditorStoreProvider.js'; import { DATA_TAB_TYPE, type EmbeddedDataEditorState, PackageableDataEditorState, } from '../../../../stores/editor/editor-state/element-editor-state/data/DataEditorState.js'; import { CaretDownIcon, clsx, ControlledDropdownMenu, InfoCircleIcon, LockIcon, MenuContent, MenuContentItem, PanelContentLists, PanelDropZone, PlusIcon, } from '@finos/legend-art'; import { prettyCONSTName } from '@finos/legend-shared'; import { type TaggedValue, type StereotypeReference, StereotypeExplicitReference, Profile, stub_Stereotype, stub_Profile, stub_TaggedValue, stub_Tag, } from '@finos/legend-graph'; import { annotatedElement_addStereotype, annotatedElement_addTaggedValue, annotatedElement_deleteStereotype, annotatedElement_deleteTaggedValue, } from '../../../../stores/graph-modifier/DomainGraphModifierHelper.js'; import { useDrop } from 'react-dnd'; import { CORE_DND_TYPE, type UMLEditorElementDropTarget, type ElementDragSource, } from '../../../../stores/editor/utils/DnDUtils.js'; import { TaggedValueDragPreviewLayer, TaggedValueEditor, } from '../uml-editor/TaggedValueEditor.js'; import { useCallback, useEffect, useRef } from 'react'; import { StereotypeDragPreviewLayer, StereotypeSelector, } from '../uml-editor/StereotypeSelector.js'; import { externalFormatData_setContentType, externalFormatData_setData, } from '../../../../stores/graph-modifier/DSL_Data_GraphModifierHelper.js'; import type { ExternalFormatDataState } from '../../../../stores/editor/editor-state/element-editor-state/data/EmbeddedDataState.js'; import { renderEmbeddedDataEditor } from './EmbeddedDataEditor.js'; import { useApplicationNavigationContext, useApplicationStore, } from '@finos/legend-application'; import { LEGEND_STUDIO_APPLICATION_NAVIGATION_CONTEXT_KEY } from '../../../../__lib__/LegendStudioApplicationNavigationContext.js'; import { LEGEND_STUDIO_DOCUMENTATION_KEY } from '../../../../__lib__/LegendStudioDocumentation.js'; import { CodeEditor } from '@finos/legend-lego/code-editor'; import { getEditorLanguageForFormat } from '../../../../stores/editor/editor-state/ArtifactGenerationViewerState.js'; export const ExternalFormatDataEditor = observer( (props: { externalFormatDataState: ExternalFormatDataState; isReadOnly: boolean; }) => { const { externalFormatDataState, isReadOnly } = props; const editorStore = useEditorStore(); const typeNameRef = useRef(null); const changeData = (val: string): void => externalFormatData_setData(externalFormatDataState.embeddedData, val); useEffect(() => { if (!isReadOnly) { typeNameRef.current?.focus(); } }, [isReadOnly]); const contentTypeOptions = editorStore.graphState.graphGenerationState.externalFormatState .formatContentTypes; const onContentTypeChange = (val: string): void => externalFormatData_setContentType( externalFormatDataState.embeddedData, val, ); const language = getEditorLanguageForFormat( editorStore.graphState.graphGenerationState.externalFormatState.getFormatTypeForContentType( externalFormatDataState.embeddedData.contentType, ), ); return (
{isReadOnly && (
)}
{externalFormatDataState.label()}
{contentTypeOptions.map((contentType) => ( onContentTypeChange(contentType)} > {contentType} ))} } menuProps={{ anchorOrigin: { vertical: 'bottom', horizontal: 'right' }, transformOrigin: { vertical: 'top', horizontal: 'right' }, }} >
{externalFormatDataState.embeddedData.contentType}
); }, ); export const EmbeddedDataEditor = observer( (props: { embeddedDataEditorState: EmbeddedDataEditorState; isReadOnly: boolean; }) => { const { embeddedDataEditorState, isReadOnly } = props; const embeddedDataState = embeddedDataEditorState.embeddedDataState; return (
{renderEmbeddedDataEditor(embeddedDataState, isReadOnly)}
); }, ); export const DataElementEditor = observer(() => { const editorStore = useEditorStore(); const applicationStore = useApplicationStore(); const editorState = editorStore.tabManagerState.getCurrentEditorState( PackageableDataEditorState, ); const dataElement = editorState.data; const isReadOnly = editorState.isReadOnly; const selectedTab = editorState.selectedTab; const changeTab = (tab: DATA_TAB_TYPE): (() => void) => (): void => editorState.setSelectedTab(tab); const addStereotype = (): void => { annotatedElement_addStereotype( dataElement, StereotypeExplicitReference.create(stub_Stereotype(stub_Profile())), ); }; const addTaggedValue = (): void => { annotatedElement_addTaggedValue( dataElement, stub_TaggedValue(stub_Tag(stub_Profile())), ); }; const deleteTaggedValue = (val: TaggedValue): (() => void) => (): void => annotatedElement_deleteTaggedValue(dataElement, val); const _deleteStereotype = (val: StereotypeReference): (() => void) => (): void => annotatedElement_deleteStereotype(dataElement, val); const handleDropTaggedValue = useCallback( (item: UMLEditorElementDropTarget): void => { if (!isReadOnly && item.data.packageableElement instanceof Profile) { annotatedElement_addTaggedValue( dataElement, stub_TaggedValue(stub_Tag(item.data.packageableElement)), ); } }, [dataElement, isReadOnly], ); const [{ isTaggedValueDragOver }, taggedValueDropConnector] = useDrop< ElementDragSource, void, { isTaggedValueDragOver: boolean } >( () => ({ accept: [CORE_DND_TYPE.PROJECT_EXPLORER_PROFILE], drop: (item) => handleDropTaggedValue(item), collect: (monitor) => ({ isTaggedValueDragOver: monitor.isOver({ shallow: true }), }), }), [handleDropTaggedValue], ); const handleDropStereotype = useCallback( (item: UMLEditorElementDropTarget): void => { if (!isReadOnly && item.data.packageableElement instanceof Profile) { annotatedElement_addStereotype( dataElement, StereotypeExplicitReference.create( stub_Stereotype(item.data.packageableElement), ), ); } }, [dataElement, isReadOnly], ); const [{ isStereotypeDragOver }, stereotypeDropConnector] = useDrop< ElementDragSource, void, { isStereotypeDragOver: boolean } >( () => ({ accept: [CORE_DND_TYPE.PROJECT_EXPLORER_PROFILE], drop: (item) => handleDropStereotype(item), collect: (monitor) => ({ isStereotypeDragOver: monitor.isOver({ shallow: true }), }), }), [handleDropStereotype], ); const seeDocumentation = (): void => applicationStore.assistantService.openDocumentationEntry( LEGEND_STUDIO_DOCUMENTATION_KEY.QUESTION_HOW_TO_CREATE_A_DATA_ELEMENT, ); useApplicationNavigationContext( LEGEND_STUDIO_APPLICATION_NAVIGATION_CONTEXT_KEY.DATA_ELEMENT_EDITOR, ); return (
{isReadOnly && (
)}
Data Element
{dataElement.name}
{Object.values(DATA_TAB_TYPE).map((tab) => (
{prettyCONSTName(tab)}
))}
{selectedTab === DATA_TAB_TYPE.GENERAL && ( )} {selectedTab === DATA_TAB_TYPE.STEREOTYPES && ( <>
{isReadOnly && (
)}
Stereotypes
{dataElement.stereotypes.map((stereotype) => ( ))}
)} {selectedTab === DATA_TAB_TYPE.TAGGED_VALUES && ( <>
{isReadOnly && (
)}
Tagged Values
{dataElement.taggedValues.map((taggedValue) => ( ))}
)}
); });