From b5b32c782dfb59bbe9286e9f8fa5acf6e95f3ffc Mon Sep 17 00:00:00 2001 From: kelly-thai <89568879+kelly-thai@users.noreply.github.com> Date: Mon, 14 Oct 2024 15:31:01 -0500 Subject: [PATCH] Added stereotypes to activators (#3598) --- .changeset/fuzzy-lobsters-shave.md | 6 + .../HostedServiceFunctionActivatorEditor.tsx | 821 +++++++++++------- ...stedServiceFunctionActivatorEditorState.ts | 23 +- .../changeDetection/DomainObserverHelper.ts | 4 + 4 files changed, 542 insertions(+), 312 deletions(-) create mode 100644 .changeset/fuzzy-lobsters-shave.md diff --git a/.changeset/fuzzy-lobsters-shave.md b/.changeset/fuzzy-lobsters-shave.md new file mode 100644 index 0000000000..b5a78db850 --- /dev/null +++ b/.changeset/fuzzy-lobsters-shave.md @@ -0,0 +1,6 @@ +--- +'@finos/legend-application-studio': patch +'@finos/legend-graph': patch +--- + +Adding ability to add stereotypes and tagged values to function activators. New tabs have been added to the activator form and changes from text mode will be reflected as well. diff --git a/packages/legend-application-studio/src/components/editor/editor-group/function-activator/HostedServiceFunctionActivatorEditor.tsx b/packages/legend-application-studio/src/components/editor/editor-group/function-activator/HostedServiceFunctionActivatorEditor.tsx index 0b45cbe16b..0a532fef02 100644 --- a/packages/legend-application-studio/src/components/editor/editor-group/function-activator/HostedServiceFunctionActivatorEditor.tsx +++ b/packages/legend-application-studio/src/components/editor/editor-group/function-activator/HostedServiceFunctionActivatorEditor.tsx @@ -28,11 +28,21 @@ import { CustomSelectorInput, PencilIcon, ErrorIcon, + clsx, + PlusIcon, } from '@finos/legend-art'; import { DeploymentOwner, + Profile, + StereotypeExplicitReference, + type StereotypeReference, + type TaggedValue, UserList, generateFunctionPrettyName, + stub_Profile, + stub_Stereotype, + stub_Tag, + stub_TaggedValue, validate_ServicePattern, } from '@finos/legend-graph'; import { observer } from 'mobx-react-lite'; @@ -43,6 +53,7 @@ import { OWNERSHIP_OPTIONS, type HostedServiceOwnerOption, MINIMUM_HOSTED_SERVICE_OWNERS, + ACTIVATOR_EDITOR_TAB, } from '../../../../stores/editor/editor-state/element-editor-state/function-activator/HostedServiceFunctionActivatorEditorState.js'; import { hostedService_setAutoActivateUpdates, @@ -56,10 +67,30 @@ import { activator_deleteValueFromUserOwnership, activator_addUserOwner, } from '../../../../stores/graph-modifier/DSL_FunctionActivator_GraphModifierHelper.js'; -import { useEffect, useMemo, useRef, useState } from 'react'; +import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { LEGEND_STUDIO_TEST_ID } from '../../../../__lib__/LegendStudioTesting.js'; -import { debounce } from '@finos/legend-shared'; +import { debounce, prettyCONSTName } from '@finos/legend-shared'; import { flowResult } from 'mobx'; +import { + annotatedElement_addStereotype, + annotatedElement_addTaggedValue, + annotatedElement_deleteStereotype, + annotatedElement_deleteTaggedValue, +} from '../../../../stores/graph-modifier/DomainGraphModifierHelper.js'; +import { + CORE_DND_TYPE, + type ElementDragSource, + type UMLEditorElementDropTarget, +} from '../../../../stores/editor/utils/DnDUtils.js'; +import { useDrop } from 'react-dnd'; +import { + TaggedValueDragPreviewLayer, + TaggedValueEditor, +} from '../uml-editor/TaggedValueEditor.js'; +import { + StereotypeDragPreviewLayer, + StereotypeSelector, +} from '../uml-editor/StereotypeSelector.js'; type UserOption = { label: string; value: string }; @@ -69,7 +100,102 @@ export const HostedServiceFunctionActivatorEditor = observer(() => { const editorState = editorStore.tabManagerState.getCurrentEditorState( HostedServiceFunctionActivatorEditorState, ); + const activatorElement = editorState.element; const isReadOnly = editorState.isReadOnly; + const selectedTab = editorState.selectedTab; + let addButtonTitle = ''; + switch (selectedTab) { + case ACTIVATOR_EDITOR_TAB.TAGGED_VALUES: + addButtonTitle = 'Add tagged value'; + break; + case ACTIVATOR_EDITOR_TAB.STEREOTYPES: + addButtonTitle = 'Add stereotype'; + break; + default: + break; + } + + // Tagged Values and Stereotype + const add = (): void => { + if (!isReadOnly) { + if (selectedTab === ACTIVATOR_EDITOR_TAB.TAGGED_VALUES) { + annotatedElement_addTaggedValue( + activatorElement, + stub_TaggedValue(stub_Tag(stub_Profile())), + ); + } else if (selectedTab === ACTIVATOR_EDITOR_TAB.STEREOTYPES) { + annotatedElement_addStereotype( + activatorElement, + StereotypeExplicitReference.create(stub_Stereotype(stub_Profile())), + ); + } + } + }; + const handleDropTaggedValue = useCallback( + (item: UMLEditorElementDropTarget): void => { + if (!isReadOnly && item.data.packageableElement instanceof Profile) { + annotatedElement_addTaggedValue( + activatorElement, + stub_TaggedValue(stub_Tag(item.data.packageableElement)), + ); + } + }, + [activatorElement, isReadOnly], + ); + const [{ isTaggedValueDragOver }, dropTaggedValueRef] = 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( + activatorElement, + StereotypeExplicitReference.create( + stub_Stereotype(item.data.packageableElement), + ), + ); + } + }, + [activatorElement, isReadOnly], + ); + const [{ isStereotypeDragOver }, dropStereotypeRef] = 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 _deleteStereotype = + (val: StereotypeReference): (() => void) => + (): void => + annotatedElement_deleteStereotype(activatorElement, val); + const _deleteTaggedValue = + (val: TaggedValue): (() => void) => + (): void => + annotatedElement_deleteTaggedValue(activatorElement, val); + const changeTab = + (tab: ACTIVATOR_EDITOR_TAB): (() => void) => + (): void => + editorState.setSelectedTab(tab); + const activator = editorState.activator; const ownership = activator.ownership; const visitFunction = (): void => @@ -269,250 +395,358 @@ export const HostedServiceFunctionActivatorEditor = observer(() => { editorState.deployState.isInProgress, )} /> - -
-
- Rest Service Activator -
-
- - -
-
- - - Specifies the URL pattern of the service (e.g. /myService/ - {`{param}`} - ) - - } - update={(value: string | undefined): void => { - updatePattern(value ?? ''); - }} - validate={getValidationMessage} - value={pattern} - /> - - -
-
- Parameters + {prettyCONSTName(tab)}
-
- URL parameters (each must be surrounded by curly braces) will be - passed as arguments for the execution query. Note that if the - service is configured to use multi-execution, one of the URL - parameters must be chosen as the execution key. + ))} +
+ {selectedTab !== ACTIVATOR_EDITOR_TAB.DEFINITION && ( + + )} +
+ + {selectedTab === ACTIVATOR_EDITOR_TAB.DEFINITION && ( +
+
+
+ Rest Service Activator +
+
+ + +
-
- {!activator.patternParameters.length && ( -
- No parameter + + + Specifies the URL pattern of the service (e.g. /myService/ + {`{param}`} + ) + + } + update={(value: string | undefined): void => { + updatePattern(value ?? ''); + }} + validate={getValidationMessage} + value={pattern} + /> + + +
+
+ Parameters +
+
+ URL parameters (each must be surrounded by curly braces) + will be passed as arguments for the execution query. Note + that if the service is configured to use multi-execution, + one of the URL parameters must be chosen as the execution + key.
- )} - {Boolean(activator.patternParameters.length) && - activator.patternParameters.map((parameter) => ( -
-
- {parameter} +
+ {!activator.patternParameters.length && ( +
+ No parameter
-
- -
-
- ))} -
-
- - -
-
- Function -
-
-
-
-
- +
+ {parameter} +
+
+ +
+
+ ))} +
- - -
-
- - -
-
- Documentation -
-
{`Provide a brief description of the service's functionalities and usage`}
-