@finos/legend-application-studio 13.0.3 → 13.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (204) hide show
  1. package/lib/components/editor/command/project-search.css +1 -1
  2. package/lib/components/editor/command/project-search.css.map +1 -1
  3. package/lib/components/editor/command-center/ProjectSearchCommand.d.ts.map +1 -1
  4. package/lib/components/editor/command-center/ProjectSearchCommand.js +11 -3
  5. package/lib/components/editor/command-center/ProjectSearchCommand.js.map +1 -1
  6. package/lib/components/editor/edit-panel/FunctionEditor.d.ts.map +1 -1
  7. package/lib/components/editor/edit-panel/FunctionEditor.js +41 -34
  8. package/lib/components/editor/edit-panel/FunctionEditor.js.map +1 -1
  9. package/lib/components/editor/edit-panel/GenerationSpecificationEditor.d.ts.map +1 -1
  10. package/lib/components/editor/edit-panel/GenerationSpecificationEditor.js +35 -54
  11. package/lib/components/editor/edit-panel/GenerationSpecificationEditor.js.map +1 -1
  12. package/lib/components/editor/edit-panel/GrammarTextEditor.d.ts.map +1 -1
  13. package/lib/components/editor/edit-panel/GrammarTextEditor.js +2 -2
  14. package/lib/components/editor/edit-panel/GrammarTextEditor.js.map +1 -1
  15. package/lib/components/editor/edit-panel/RuntimeEditor.d.ts.map +1 -1
  16. package/lib/components/editor/edit-panel/RuntimeEditor.js +11 -20
  17. package/lib/components/editor/edit-panel/RuntimeEditor.js.map +1 -1
  18. package/lib/components/editor/edit-panel/connection-editor/RelationalDatabaseConnectionEditor.d.ts.map +1 -1
  19. package/lib/components/editor/edit-panel/connection-editor/RelationalDatabaseConnectionEditor.js +10 -2
  20. package/lib/components/editor/edit-panel/connection-editor/RelationalDatabaseConnectionEditor.js.map +1 -1
  21. package/lib/components/editor/edit-panel/data-editor/DataElementEditor.d.ts.map +1 -1
  22. package/lib/components/editor/edit-panel/data-editor/DataElementEditor.js +4 -8
  23. package/lib/components/editor/edit-panel/data-editor/DataElementEditor.js.map +1 -1
  24. package/lib/components/editor/edit-panel/data-editor/RelationalCSVDataEditor.js +1 -1
  25. package/lib/components/editor/edit-panel/data-editor/RelationalCSVDataEditor.js.map +1 -1
  26. package/lib/components/editor/edit-panel/element-generation-editor/FileGenerationEditor.d.ts.map +1 -1
  27. package/lib/components/editor/edit-panel/element-generation-editor/FileGenerationEditor.js +3 -7
  28. package/lib/components/editor/edit-panel/element-generation-editor/FileGenerationEditor.js.map +1 -1
  29. package/lib/components/editor/edit-panel/external-format-editor/BindingElementEditor.d.ts.map +1 -1
  30. package/lib/components/editor/edit-panel/external-format-editor/BindingElementEditor.js +2 -2
  31. package/lib/components/editor/edit-panel/external-format-editor/BindingElementEditor.js.map +1 -1
  32. package/lib/components/editor/edit-panel/external-format-editor/SchemaSetElementEditor.js +1 -1
  33. package/lib/components/editor/edit-panel/external-format-editor/SchemaSetElementEditor.js.map +1 -1
  34. package/lib/components/editor/edit-panel/mapping-editor/EnumerationMappingEditor.d.ts.map +1 -1
  35. package/lib/components/editor/edit-panel/mapping-editor/EnumerationMappingEditor.js +2 -9
  36. package/lib/components/editor/edit-panel/mapping-editor/EnumerationMappingEditor.js.map +1 -1
  37. package/lib/components/editor/edit-panel/mapping-editor/FlatDataPropertyMappingEditor.d.ts.map +1 -1
  38. package/lib/components/editor/edit-panel/mapping-editor/FlatDataPropertyMappingEditor.js +3 -4
  39. package/lib/components/editor/edit-panel/mapping-editor/FlatDataPropertyMappingEditor.js.map +1 -1
  40. package/lib/components/editor/edit-panel/mapping-editor/InstanceSetImplementationEditor.d.ts.map +1 -1
  41. package/lib/components/editor/edit-panel/mapping-editor/InstanceSetImplementationEditor.js +3 -10
  42. package/lib/components/editor/edit-panel/mapping-editor/InstanceSetImplementationEditor.js.map +1 -1
  43. package/lib/components/editor/edit-panel/mapping-editor/MappingExecutionBuilder.d.ts.map +1 -1
  44. package/lib/components/editor/edit-panel/mapping-editor/MappingExecutionBuilder.js +4 -10
  45. package/lib/components/editor/edit-panel/mapping-editor/MappingExecutionBuilder.js.map +1 -1
  46. package/lib/components/editor/edit-panel/mapping-editor/MappingExplorer.js +7 -9
  47. package/lib/components/editor/edit-panel/mapping-editor/MappingExplorer.js.map +1 -1
  48. package/lib/components/editor/edit-panel/mapping-editor/MappingTestEditor.d.ts.map +1 -1
  49. package/lib/components/editor/edit-panel/mapping-editor/MappingTestEditor.js +3 -6
  50. package/lib/components/editor/edit-panel/mapping-editor/MappingTestEditor.js.map +1 -1
  51. package/lib/components/editor/edit-panel/mapping-editor/MappingTestsExplorer.d.ts.map +1 -1
  52. package/lib/components/editor/edit-panel/mapping-editor/MappingTestsExplorer.js +7 -8
  53. package/lib/components/editor/edit-panel/mapping-editor/MappingTestsExplorer.js.map +1 -1
  54. package/lib/components/editor/edit-panel/mapping-editor/NewMappingElementModal.d.ts.map +1 -1
  55. package/lib/components/editor/edit-panel/mapping-editor/NewMappingElementModal.js +1 -3
  56. package/lib/components/editor/edit-panel/mapping-editor/NewMappingElementModal.js.map +1 -1
  57. package/lib/components/editor/edit-panel/mapping-editor/OperationSetImplementationEditor.d.ts.map +1 -1
  58. package/lib/components/editor/edit-panel/mapping-editor/OperationSetImplementationEditor.js +5 -7
  59. package/lib/components/editor/edit-panel/mapping-editor/OperationSetImplementationEditor.js.map +1 -1
  60. package/lib/components/editor/edit-panel/mapping-editor/PurePropertyMappingEditor.d.ts.map +1 -1
  61. package/lib/components/editor/edit-panel/mapping-editor/PurePropertyMappingEditor.js +3 -4
  62. package/lib/components/editor/edit-panel/mapping-editor/PurePropertyMappingEditor.js.map +1 -1
  63. package/lib/components/editor/edit-panel/mapping-editor/relational/RelationalPropertyMappingEditor.d.ts.map +1 -1
  64. package/lib/components/editor/edit-panel/mapping-editor/relational/RelationalPropertyMappingEditor.js +1 -1
  65. package/lib/components/editor/edit-panel/mapping-editor/relational/RelationalPropertyMappingEditor.js.map +1 -1
  66. package/lib/components/editor/edit-panel/service-editor/ServiceExecutionEditor.d.ts.map +1 -1
  67. package/lib/components/editor/edit-panel/service-editor/ServiceExecutionEditor.js +3 -5
  68. package/lib/components/editor/edit-panel/service-editor/ServiceExecutionEditor.js.map +1 -1
  69. package/lib/components/editor/edit-panel/service-editor/testable/ServiceTestDataEditor.d.ts.map +1 -1
  70. package/lib/components/editor/edit-panel/service-editor/testable/ServiceTestDataEditor.js +6 -4
  71. package/lib/components/editor/edit-panel/service-editor/testable/ServiceTestDataEditor.js.map +1 -1
  72. package/lib/components/editor/edit-panel/service-editor/testable/ServiceTestableEditor.js +1 -1
  73. package/lib/components/editor/edit-panel/service-editor/testable/ServiceTestableEditor.js.map +1 -1
  74. package/lib/components/editor/edit-panel/uml-editor/AssociationEditor.d.ts.map +1 -1
  75. package/lib/components/editor/edit-panel/uml-editor/AssociationEditor.js +6 -12
  76. package/lib/components/editor/edit-panel/uml-editor/AssociationEditor.js.map +1 -1
  77. package/lib/components/editor/edit-panel/uml-editor/ClassEditor.d.ts.map +1 -1
  78. package/lib/components/editor/edit-panel/uml-editor/ClassEditor.js +156 -62
  79. package/lib/components/editor/edit-panel/uml-editor/ClassEditor.js.map +1 -1
  80. package/lib/components/editor/edit-panel/uml-editor/EnumerationEditor.d.ts.map +1 -1
  81. package/lib/components/editor/edit-panel/uml-editor/EnumerationEditor.js +39 -21
  82. package/lib/components/editor/edit-panel/uml-editor/EnumerationEditor.js.map +1 -1
  83. package/lib/components/editor/edit-panel/uml-editor/ProfileEditor.d.ts.map +1 -1
  84. package/lib/components/editor/edit-panel/uml-editor/ProfileEditor.js +62 -9
  85. package/lib/components/editor/edit-panel/uml-editor/ProfileEditor.js.map +1 -1
  86. package/lib/components/editor/edit-panel/uml-editor/PropertyEditor.d.ts.map +1 -1
  87. package/lib/components/editor/edit-panel/uml-editor/PropertyEditor.js +4 -8
  88. package/lib/components/editor/edit-panel/uml-editor/PropertyEditor.js.map +1 -1
  89. package/lib/components/editor/edit-panel/uml-editor/StereotypeSelector.d.ts +7 -1
  90. package/lib/components/editor/edit-panel/uml-editor/StereotypeSelector.d.ts.map +1 -1
  91. package/lib/components/editor/edit-panel/uml-editor/StereotypeSelector.js +33 -5
  92. package/lib/components/editor/edit-panel/uml-editor/StereotypeSelector.js.map +1 -1
  93. package/lib/components/editor/edit-panel/uml-editor/TaggedValueEditor.d.ts +7 -1
  94. package/lib/components/editor/edit-panel/uml-editor/TaggedValueEditor.d.ts.map +1 -1
  95. package/lib/components/editor/edit-panel/uml-editor/TaggedValueEditor.js +35 -7
  96. package/lib/components/editor/edit-panel/uml-editor/TaggedValueEditor.js.map +1 -1
  97. package/lib/components/editor/side-bar/CreateNewElementModal.d.ts.map +1 -1
  98. package/lib/components/editor/side-bar/CreateNewElementModal.js +2 -3
  99. package/lib/components/editor/side-bar/CreateNewElementModal.js.map +1 -1
  100. package/lib/components/editor/side-bar/Explorer.d.ts.map +1 -1
  101. package/lib/components/editor/side-bar/Explorer.js +8 -9
  102. package/lib/components/editor/side-bar/Explorer.js.map +1 -1
  103. package/lib/components/shared/StudioLambdaEditor.d.ts +1 -0
  104. package/lib/components/shared/StudioLambdaEditor.d.ts.map +1 -1
  105. package/lib/components/shared/StudioLambdaEditor.js +2 -2
  106. package/lib/components/shared/StudioLambdaEditor.js.map +1 -1
  107. package/lib/index.css +2 -2
  108. package/lib/index.css.map +1 -1
  109. package/lib/package.json +5 -5
  110. package/lib/stores/EditorStore.d.ts.map +1 -1
  111. package/lib/stores/EditorStore.js +7 -7
  112. package/lib/stores/EditorStore.js.map +1 -1
  113. package/lib/stores/editor/NewElementState.d.ts.map +1 -1
  114. package/lib/stores/editor/NewElementState.js +12 -5
  115. package/lib/stores/editor/NewElementState.js.map +1 -1
  116. package/lib/stores/editor-state/GenerationSpecificationEditorState.d.ts +0 -2
  117. package/lib/stores/editor-state/GenerationSpecificationEditorState.d.ts.map +1 -1
  118. package/lib/stores/editor-state/GenerationSpecificationEditorState.js +1 -8
  119. package/lib/stores/editor-state/GenerationSpecificationEditorState.js.map +1 -1
  120. package/lib/stores/editor-state/element-editor-state/ElementEditorState.d.ts.map +1 -1
  121. package/lib/stores/editor-state/element-editor-state/ElementEditorState.js +2 -4
  122. package/lib/stores/editor-state/element-editor-state/ElementEditorState.js.map +1 -1
  123. package/lib/stores/editor-state/element-editor-state/connection/ConnectionEditorState.d.ts +2 -1
  124. package/lib/stores/editor-state/element-editor-state/connection/ConnectionEditorState.d.ts.map +1 -1
  125. package/lib/stores/editor-state/element-editor-state/connection/ConnectionEditorState.js +9 -1
  126. package/lib/stores/editor-state/element-editor-state/connection/ConnectionEditorState.js.map +1 -1
  127. package/lib/stores/editor-state/element-editor-state/mapping/MappingEditorState.js +1 -1
  128. package/lib/stores/editor-state/element-editor-state/mapping/MappingEditorState.js.map +1 -1
  129. package/lib/stores/editor-state/element-editor-state/mapping/MappingExecutionState.js +1 -1
  130. package/lib/stores/editor-state/element-editor-state/mapping/MappingExecutionState.js.map +1 -1
  131. package/lib/stores/editor-state/element-editor-state/service/ServiceExecutionState.d.ts.map +1 -1
  132. package/lib/stores/editor-state/element-editor-state/service/ServiceExecutionState.js +1 -1
  133. package/lib/stores/editor-state/element-editor-state/service/ServiceExecutionState.js.map +1 -1
  134. package/lib/stores/editor-state/element-editor-state/service/testable/ServiceTestDataState.d.ts.map +1 -1
  135. package/lib/stores/editor-state/element-editor-state/service/testable/ServiceTestDataState.js +2 -2
  136. package/lib/stores/editor-state/element-editor-state/service/testable/ServiceTestDataState.js.map +1 -1
  137. package/lib/stores/editor-state/element-editor-state/service/testable/ServiceTestEditorState.d.ts.map +1 -1
  138. package/lib/stores/editor-state/element-editor-state/service/testable/ServiceTestEditorState.js +3 -3
  139. package/lib/stores/editor-state/element-editor-state/service/testable/ServiceTestEditorState.js.map +1 -1
  140. package/lib/stores/graphModifier/DomainGraphModifierHelper.d.ts +10 -0
  141. package/lib/stores/graphModifier/DomainGraphModifierHelper.d.ts.map +1 -1
  142. package/lib/stores/graphModifier/DomainGraphModifierHelper.js +31 -1
  143. package/lib/stores/graphModifier/DomainGraphModifierHelper.js.map +1 -1
  144. package/lib/stores/graphModifier/StoreRelational_GraphModifierHelper.d.ts +2 -1
  145. package/lib/stores/graphModifier/StoreRelational_GraphModifierHelper.d.ts.map +1 -1
  146. package/lib/stores/graphModifier/StoreRelational_GraphModifierHelper.js +3 -0
  147. package/lib/stores/graphModifier/StoreRelational_GraphModifierHelper.js.map +1 -1
  148. package/lib/stores/shared/DnDUtil.d.ts +1 -2
  149. package/lib/stores/shared/DnDUtil.d.ts.map +1 -1
  150. package/lib/stores/shared/DnDUtil.js +0 -2
  151. package/lib/stores/shared/DnDUtil.js.map +1 -1
  152. package/lib/stores/shared/testable/TestableUtils.d.ts.map +1 -1
  153. package/lib/stores/shared/testable/TestableUtils.js +2 -3
  154. package/lib/stores/shared/testable/TestableUtils.js.map +1 -1
  155. package/package.json +13 -13
  156. package/src/components/editor/command-center/ProjectSearchCommand.tsx +13 -2
  157. package/src/components/editor/edit-panel/FunctionEditor.tsx +220 -152
  158. package/src/components/editor/edit-panel/GenerationSpecificationEditor.tsx +154 -184
  159. package/src/components/editor/edit-panel/GrammarTextEditor.tsx +4 -5
  160. package/src/components/editor/edit-panel/RuntimeEditor.tsx +89 -90
  161. package/src/components/editor/edit-panel/connection-editor/RelationalDatabaseConnectionEditor.tsx +36 -0
  162. package/src/components/editor/edit-panel/data-editor/DataElementEditor.tsx +57 -40
  163. package/src/components/editor/edit-panel/data-editor/RelationalCSVDataEditor.tsx +1 -1
  164. package/src/components/editor/edit-panel/element-generation-editor/FileGenerationEditor.tsx +50 -45
  165. package/src/components/editor/edit-panel/external-format-editor/BindingElementEditor.tsx +36 -32
  166. package/src/components/editor/edit-panel/external-format-editor/SchemaSetElementEditor.tsx +1 -1
  167. package/src/components/editor/edit-panel/mapping-editor/EnumerationMappingEditor.tsx +46 -41
  168. package/src/components/editor/edit-panel/mapping-editor/FlatDataPropertyMappingEditor.tsx +9 -7
  169. package/src/components/editor/edit-panel/mapping-editor/InstanceSetImplementationEditor.tsx +18 -21
  170. package/src/components/editor/edit-panel/mapping-editor/MappingExecutionBuilder.tsx +39 -29
  171. package/src/components/editor/edit-panel/mapping-editor/MappingExplorer.tsx +39 -39
  172. package/src/components/editor/edit-panel/mapping-editor/MappingTestEditor.tsx +23 -15
  173. package/src/components/editor/edit-panel/mapping-editor/MappingTestsExplorer.tsx +40 -38
  174. package/src/components/editor/edit-panel/mapping-editor/NewMappingElementModal.tsx +1 -3
  175. package/src/components/editor/edit-panel/mapping-editor/OperationSetImplementationEditor.tsx +48 -45
  176. package/src/components/editor/edit-panel/mapping-editor/PurePropertyMappingEditor.tsx +12 -8
  177. package/src/components/editor/edit-panel/mapping-editor/relational/RelationalPropertyMappingEditor.tsx +2 -3
  178. package/src/components/editor/edit-panel/service-editor/ServiceExecutionEditor.tsx +75 -72
  179. package/src/components/editor/edit-panel/service-editor/testable/ServiceTestDataEditor.tsx +63 -36
  180. package/src/components/editor/edit-panel/service-editor/testable/ServiceTestableEditor.tsx +1 -1
  181. package/src/components/editor/edit-panel/uml-editor/AssociationEditor.tsx +56 -45
  182. package/src/components/editor/edit-panel/uml-editor/ClassEditor.tsx +812 -504
  183. package/src/components/editor/edit-panel/uml-editor/EnumerationEditor.tsx +209 -113
  184. package/src/components/editor/edit-panel/uml-editor/ProfileEditor.tsx +184 -52
  185. package/src/components/editor/edit-panel/uml-editor/PropertyEditor.tsx +62 -39
  186. package/src/components/editor/edit-panel/uml-editor/StereotypeSelector.tsx +137 -52
  187. package/src/components/editor/edit-panel/uml-editor/TaggedValueEditor.tsx +171 -88
  188. package/src/components/editor/side-bar/CreateNewElementModal.tsx +2 -1
  189. package/src/components/editor/side-bar/Explorer.tsx +11 -15
  190. package/src/components/shared/StudioLambdaEditor.tsx +3 -0
  191. package/src/stores/EditorStore.ts +7 -6
  192. package/src/stores/editor/NewElementState.ts +12 -5
  193. package/src/stores/editor-state/GenerationSpecificationEditorState.ts +1 -15
  194. package/src/stores/editor-state/element-editor-state/ElementEditorState.ts +2 -3
  195. package/src/stores/editor-state/element-editor-state/connection/ConnectionEditorState.ts +10 -0
  196. package/src/stores/editor-state/element-editor-state/mapping/MappingEditorState.ts +1 -1
  197. package/src/stores/editor-state/element-editor-state/mapping/MappingExecutionState.ts +1 -1
  198. package/src/stores/editor-state/element-editor-state/service/ServiceExecutionState.ts +1 -0
  199. package/src/stores/editor-state/element-editor-state/service/testable/ServiceTestDataState.ts +2 -1
  200. package/src/stores/editor-state/element-editor-state/service/testable/ServiceTestEditorState.ts +12 -3
  201. package/src/stores/graphModifier/DomainGraphModifierHelper.ts +92 -0
  202. package/src/stores/graphModifier/StoreRelational_GraphModifierHelper.ts +10 -0
  203. package/src/stores/shared/DnDUtil.ts +0 -2
  204. package/src/stores/shared/testable/TestableUtils.ts +4 -3
@@ -14,10 +14,9 @@
14
14
  * limitations under the License.
15
15
  */
16
16
 
17
- import { useState, useEffect, useCallback } from 'react';
17
+ import { useState, useEffect, useCallback, useRef } from 'react';
18
18
  import { observer } from 'mobx-react-lite';
19
19
  import { isNonNullable, prettyCONSTName } from '@finos/legend-shared';
20
- import { useDrop } from 'react-dnd';
21
20
  import {
22
21
  CORE_DND_TYPE,
23
22
  type ElementDragSource,
@@ -41,13 +40,26 @@ import {
41
40
  ArrowCircleRightIcon,
42
41
  FireIcon,
43
42
  StickArrowCircleRightIcon,
43
+ PanelEntryDragHandle,
44
+ PanelEntryDropZonePlaceholder,
45
+ DragPreviewLayer,
46
+ useDragPreviewLayer,
47
+ PanelDropZone,
44
48
  } from '@finos/legend-art';
45
49
  import { LEGEND_STUDIO_TEST_ID } from '../../../LegendStudioTestID.js';
46
50
  import { PropertyEditor } from './PropertyEditor.js';
47
- import { StereotypeSelector } from './StereotypeSelector.js';
51
+ import {
52
+ StereotypeSelector,
53
+ StereotypeDragPreviewLayer,
54
+ } from './StereotypeSelector.js';
55
+ import {
56
+ TaggedValueEditor,
57
+ TaggedValueDragPreviewLayer,
58
+ } from './TaggedValueEditor.js';
48
59
  import { UML_EDITOR_TAB } from '../../../../stores/editor-state/element-editor-state/UMLEditorState.js';
49
60
  import { ClassEditorState } from '../../../../stores/editor-state/element-editor-state/ClassEditorState.js';
50
61
  import { flowResult } from 'mobx';
62
+ import { type DropTargetMonitor, useDrop, useDrag } from 'react-dnd';
51
63
  import { useEditorStore } from '../../EditorStoreProvider.js';
52
64
  import {
53
65
  type StereotypeReference,
@@ -79,6 +91,7 @@ import {
79
91
  getAllSuperclasses,
80
92
  getAllClassConstraints,
81
93
  getAllClassDerivedProperties,
94
+ isElementReadOnly,
82
95
  } from '@finos/legend-graph';
83
96
  import { StudioLambdaEditor } from '../../../shared/StudioLambdaEditor.js';
84
97
  import {
@@ -109,6 +122,10 @@ import {
109
122
  property_setName,
110
123
  property_setGenericType,
111
124
  property_setMultiplicity,
125
+ class_swapProperties,
126
+ class_swapDerivedProperties,
127
+ class_swapConstraints,
128
+ class_swapSuperTypes,
112
129
  setGenericTypeReferenceValue,
113
130
  } from '../../../../stores/graphModifier/DomainGraphModifierHelper.js';
114
131
  import {
@@ -116,7 +133,12 @@ import {
116
133
  getClassPropertyType,
117
134
  } from '../../../../stores/shared/ModelUtil.js';
118
135
  import { LEGEND_STUDIO_APPLICATION_NAVIGATION_CONTEXT_KEY } from '../../../../stores/LegendStudioApplicationNavigationContext.js';
119
- import { TaggedValueEditor } from './TaggedValueEditor.js';
136
+
137
+ type ClassPropertyDragSource = {
138
+ property: Property;
139
+ };
140
+
141
+ const CLASS_PROPERTY_DND_TYPE = 'CLASS_PROPERTY';
120
142
 
121
143
  const PropertyBasicEditor = observer(
122
144
  (props: {
@@ -126,7 +148,9 @@ const PropertyBasicEditor = observer(
126
148
  deleteProperty: () => void;
127
149
  isReadOnly: boolean;
128
150
  }) => {
151
+ const ref = useRef<HTMLDivElement>(null);
129
152
  const { property, _class, editorState, deleteProperty, isReadOnly } = props;
153
+
130
154
  const editorStore = useEditorStore();
131
155
  const isInheritedProperty =
132
156
  property._OWNER instanceof Class && property._OWNER !== _class;
@@ -136,6 +160,7 @@ const PropertyBasicEditor = observer(
136
160
  _class.properties.filter((p) => p.name === val.name).length >= 2;
137
161
  const selectProperty = (): void =>
138
162
  editorState.setSelectedProperty(property);
163
+
139
164
  // Name
140
165
  const changeValue: React.ChangeEventHandler<HTMLInputElement> = (event) => {
141
166
  property_setName(property, event.target.value);
@@ -193,6 +218,51 @@ const PropertyBasicEditor = observer(
193
218
  setUpperBound(event.target.value);
194
219
  updateMultiplicity(lowerBound, event.target.value);
195
220
  };
221
+
222
+ // Drag and Drop
223
+ const handleHover = useCallback(
224
+ (item: ClassPropertyDragSource): void => {
225
+ const draggingProperty = item.property;
226
+ const hoveredProperty = property;
227
+ class_swapProperties(_class, draggingProperty, hoveredProperty);
228
+ },
229
+ [_class, property],
230
+ );
231
+
232
+ const [{ isBeingDraggedProperty }, dropConnector] = useDrop<
233
+ ClassPropertyDragSource,
234
+ void,
235
+ { isBeingDraggedProperty: Property | undefined }
236
+ >(
237
+ () => ({
238
+ accept: [CLASS_PROPERTY_DND_TYPE],
239
+ hover: (item) => handleHover(item),
240
+ collect: (
241
+ monitor,
242
+ ): {
243
+ isBeingDraggedProperty: Property | undefined;
244
+ } => ({
245
+ isBeingDraggedProperty:
246
+ monitor.getItem<ClassPropertyDragSource | null>()?.property,
247
+ }),
248
+ }),
249
+ [handleHover],
250
+ );
251
+ const isBeingDragged = property === isBeingDraggedProperty;
252
+
253
+ const [, dragConnector, dragPreviewConnector] =
254
+ useDrag<ClassPropertyDragSource>(
255
+ () => ({
256
+ type: CLASS_PROPERTY_DND_TYPE,
257
+ item: () => ({
258
+ property: property,
259
+ }),
260
+ }),
261
+ [property],
262
+ );
263
+ dragConnector(dropConnector(ref));
264
+ useDragPreviewLayer(dragPreviewConnector);
265
+
196
266
  // Other
197
267
  const openElement = (): void => {
198
268
  if (!(propertyType instanceof PrimitiveType)) {
@@ -206,180 +276,191 @@ const PropertyBasicEditor = observer(
206
276
  const visitOwner = (): void => editorStore.openElement(property._OWNER);
207
277
 
208
278
  return (
209
- <div className="property-basic-editor">
210
- {isIndirectProperty && (
211
- <div className="property-basic-editor__name--with-lock">
212
- <div className="property-basic-editor__name--with-lock__icon">
213
- <LockIcon />
214
- </div>
215
- <span className="property-basic-editor__name--with-lock__name">
216
- {property.name}
217
- </span>
218
- </div>
219
- )}
220
- {!isIndirectProperty && (
221
- <div className="input-group__input property-basic-editor__input">
222
- <InputWithInlineValidation
223
- className="property-basic-editor__input--with-validation input-group__input"
224
- disabled={isReadOnly}
225
- value={property.name}
226
- spellCheck={false}
227
- onChange={changeValue}
228
- placeholder={`Property name`}
229
- validationErrorMessage={
230
- isPropertyDuplicated(property)
231
- ? 'Duplicated property'
232
- : undefined
233
- }
234
- />
235
- </div>
236
- )}
237
- {!isIndirectProperty && !isReadOnly && isEditingType && (
238
- <CustomSelectorInput
239
- className="property-basic-editor__type"
240
- options={propertyTypeOptions}
241
- onChange={changePropertyType}
242
- value={selectedPropertyType}
243
- placeholder={'Choose a data type or enumeration'}
244
- filterOption={filterOption}
245
- formatOptionLabel={getPackageableElementOptionFormatter({
246
- graphManagerState: editorStore.graphManagerState,
247
- })}
248
- />
249
- )}
250
- {!isIndirectProperty && !isReadOnly && !isEditingType && (
251
- <div
252
- className={clsx(
253
- 'property-basic-editor__type',
254
- 'property-basic-editor__type--show-click-hint',
255
- `background--${propertyTypeName.toLowerCase()}`,
256
- {
257
- 'property-basic-editor__type--has-visit-btn':
258
- propertyTypeName !== CLASS_PROPERTY_TYPE.PRIMITIVE,
259
- },
279
+ <div ref={ref} className="property-basic-editor__container">
280
+ <PanelEntryDropZonePlaceholder showPlaceholder={isBeingDragged}>
281
+ <div className="property-basic-editor">
282
+ {!isIndirectProperty && <PanelEntryDragHandle />}
283
+ {isIndirectProperty && (
284
+ <div className="property-basic-editor__name property-basic-editor__name--with-lock">
285
+ <div className="property-basic-editor__name--with-lock__icon">
286
+ <LockIcon />
287
+ </div>
288
+ <span className="property-basic-editor__name--with-lock__name">
289
+ {property.name}
290
+ </span>
291
+ </div>
260
292
  )}
261
- >
262
- {propertyTypeName !== CLASS_PROPERTY_TYPE.PRIMITIVE && (
263
- <div className="property-basic-editor__type__abbr">
264
- {getElementIcon(editorStore, propertyType)}
293
+ {!isIndirectProperty && (
294
+ <div className="input-group__input property-basic-editor__input">
295
+ <InputWithInlineValidation
296
+ className="property-basic-editor__input--with-validation input-group__input"
297
+ disabled={isReadOnly}
298
+ value={property.name}
299
+ spellCheck={false}
300
+ onChange={changeValue}
301
+ placeholder={`Property name`}
302
+ validationErrorMessage={
303
+ isPropertyDuplicated(property)
304
+ ? 'Duplicated property'
305
+ : undefined
306
+ }
307
+ />
265
308
  </div>
266
309
  )}
267
- <div className="property-basic-editor__type__label">
268
- {propertyType.name}
269
- </div>
270
- <div
271
- data-testid={
272
- LEGEND_STUDIO_TEST_ID.PROPERTY_BASIC_EDITOR__TYPE__LABEL_HOVER
273
- }
274
- className="property-basic-editor__type__label property-basic-editor__type__label--hover"
275
- onClick={(): void => setIsEditingType(true)}
276
- >
277
- Click to edit
310
+ {!isIndirectProperty && !isReadOnly && isEditingType && (
311
+ <CustomSelectorInput
312
+ className="property-basic-editor__type"
313
+ options={propertyTypeOptions}
314
+ onChange={changePropertyType}
315
+ value={selectedPropertyType}
316
+ placeholder={'Choose a data type or enumeration'}
317
+ filterOption={filterOption}
318
+ formatOptionLabel={getPackageableElementOptionFormatter({})}
319
+ />
320
+ )}
321
+ {!isIndirectProperty && !isReadOnly && !isEditingType && (
322
+ <div
323
+ className={clsx(
324
+ 'property-basic-editor__type',
325
+ 'property-basic-editor__type--show-click-hint',
326
+ `background--${propertyTypeName.toLowerCase()}`,
327
+ {
328
+ 'property-basic-editor__type--has-visit-btn':
329
+ propertyTypeName !== CLASS_PROPERTY_TYPE.PRIMITIVE,
330
+ },
331
+ )}
332
+ >
333
+ {propertyTypeName !== CLASS_PROPERTY_TYPE.PRIMITIVE && (
334
+ <div className="property-basic-editor__type__abbr">
335
+ {getElementIcon(editorStore, propertyType)}
336
+ </div>
337
+ )}
338
+ <div className="property-basic-editor__type__label">
339
+ {propertyType.name}
340
+ </div>
341
+ <div
342
+ data-testid={
343
+ LEGEND_STUDIO_TEST_ID.PROPERTY_BASIC_EDITOR__TYPE__LABEL_HOVER
344
+ }
345
+ className="property-basic-editor__type__label property-basic-editor__type__label--hover"
346
+ onClick={(): void => setIsEditingType(true)}
347
+ >
348
+ Click to edit
349
+ </div>
350
+ {propertyTypeName !== CLASS_PROPERTY_TYPE.PRIMITIVE && (
351
+ <button
352
+ data-testid={LEGEND_STUDIO_TEST_ID.TYPE_VISIT}
353
+ className="property-basic-editor__type__visit-btn"
354
+ onClick={openElement}
355
+ tabIndex={-1}
356
+ title={'Visit element'}
357
+ >
358
+ <ArrowCircleRightIcon />
359
+ </button>
360
+ )}
361
+ </div>
362
+ )}
363
+ {(isIndirectProperty || isReadOnly) && (
364
+ <div
365
+ className={clsx(
366
+ 'property-basic-editor__type',
367
+ `background--${propertyTypeName.toLowerCase()}`,
368
+ {
369
+ 'property-basic-editor__type--has-visit-btn':
370
+ propertyTypeName !== CLASS_PROPERTY_TYPE.PRIMITIVE,
371
+ },
372
+ )}
373
+ >
374
+ {propertyTypeName !== CLASS_PROPERTY_TYPE.PRIMITIVE && (
375
+ <div className="property-basic-editor__type__abbr">
376
+ {getElementIcon(editorStore, propertyType)}
377
+ </div>
378
+ )}
379
+ <div className="property-basic-editor__type__label">
380
+ {propertyType.name}
381
+ </div>
382
+ {propertyTypeName !== CLASS_PROPERTY_TYPE.PRIMITIVE && (
383
+ <button
384
+ data-testid={LEGEND_STUDIO_TEST_ID.TYPE_VISIT}
385
+ className="property-basic-editor__type__visit-btn"
386
+ onClick={openElement}
387
+ tabIndex={-1}
388
+ title={'Visit element'}
389
+ >
390
+ <ArrowCircleRightIcon />
391
+ </button>
392
+ )}
393
+ </div>
394
+ )}
395
+ <div className="property-basic-editor__multiplicity">
396
+ <input
397
+ className="property-basic-editor__multiplicity-bound"
398
+ disabled={isIndirectProperty || isReadOnly}
399
+ spellCheck={false}
400
+ value={lowerBound}
401
+ onChange={changeLowerBound}
402
+ />
403
+ <div className="property-basic-editor__multiplicity__range">
404
+ ..
405
+ </div>
406
+ <input
407
+ className="property-basic-editor__multiplicity-bound"
408
+ disabled={isIndirectProperty || isReadOnly}
409
+ spellCheck={false}
410
+ value={upperBound}
411
+ onChange={changeUpperBound}
412
+ />
278
413
  </div>
279
- {propertyTypeName !== CLASS_PROPERTY_TYPE.PRIMITIVE && (
414
+ {!isIndirectProperty && (
280
415
  <button
281
- data-testid={LEGEND_STUDIO_TEST_ID.TYPE_VISIT}
282
- className="property-basic-editor__type__visit-btn"
283
- onClick={openElement}
416
+ className="uml-element-editor__basic__detail-btn"
417
+ onClick={selectProperty}
284
418
  tabIndex={-1}
285
- title={'Visit element'}
419
+ title={'See detail'}
286
420
  >
287
- <ArrowCircleRightIcon />
421
+ <LongArrowRightIcon />
288
422
  </button>
289
423
  )}
290
- </div>
291
- )}
292
- {(isIndirectProperty || isReadOnly) && (
293
- <div
294
- className={clsx(
295
- 'property-basic-editor__type',
296
- `background--${propertyTypeName.toLowerCase()}`,
297
- {
298
- 'property-basic-editor__type--has-visit-btn':
299
- propertyTypeName !== CLASS_PROPERTY_TYPE.PRIMITIVE,
300
- },
424
+ {isIndirectProperty && (
425
+ <button
426
+ className="uml-element-editor__visit-parent-element-btn"
427
+ onClick={visitOwner}
428
+ tabIndex={-1}
429
+ title={`Visit ${
430
+ isInheritedProperty ? 'super type class' : 'association'
431
+ } '${property._OWNER.path}'`}
432
+ >
433
+ <ArrowCircleRightIcon />
434
+ </button>
301
435
  )}
302
- >
303
- {propertyTypeName !== CLASS_PROPERTY_TYPE.PRIMITIVE && (
304
- <div className="property-basic-editor__type__abbr">
305
- {getElementIcon(editorStore, propertyType)}
306
- </div>
436
+ {isIndirectProperty && (
437
+ <div className="property-basic-editor__locked-property-end-block"></div>
307
438
  )}
308
- <div className="property-basic-editor__type__label">
309
- {propertyType.name}
310
- </div>
311
- {propertyTypeName !== CLASS_PROPERTY_TYPE.PRIMITIVE && (
439
+ {!isIndirectProperty && !isReadOnly && (
312
440
  <button
313
- data-testid={LEGEND_STUDIO_TEST_ID.TYPE_VISIT}
314
- className="property-basic-editor__type__visit-btn"
315
- onClick={openElement}
441
+ className={clsx('uml-element-editor__remove-btn', {
442
+ 'uml-element-editor__remove-btn--hidden': isIndirectProperty,
443
+ })}
444
+ onClick={deleteProperty}
316
445
  tabIndex={-1}
317
- title={'Visit element'}
446
+ title={'Remove'}
318
447
  >
319
- <ArrowCircleRightIcon />
448
+ <TimesIcon />
320
449
  </button>
321
450
  )}
322
451
  </div>
323
- )}
324
- <div className="property-basic-editor__multiplicity">
325
- <input
326
- className="property-basic-editor__multiplicity-bound"
327
- disabled={isIndirectProperty || isReadOnly}
328
- spellCheck={false}
329
- value={lowerBound}
330
- onChange={changeLowerBound}
331
- />
332
- <div className="property-basic-editor__multiplicity__range">..</div>
333
- <input
334
- className="property-basic-editor__multiplicity-bound"
335
- disabled={isIndirectProperty || isReadOnly}
336
- spellCheck={false}
337
- value={upperBound}
338
- onChange={changeUpperBound}
339
- />
340
- </div>
341
- {!isIndirectProperty && (
342
- <button
343
- className="uml-element-editor__basic__detail-btn"
344
- onClick={selectProperty}
345
- tabIndex={-1}
346
- title={'See detail'}
347
- >
348
- <LongArrowRightIcon />
349
- </button>
350
- )}
351
- {isIndirectProperty && (
352
- <button
353
- className="uml-element-editor__visit-parent-element-btn"
354
- onClick={visitOwner}
355
- tabIndex={-1}
356
- title={`Visit ${
357
- isInheritedProperty ? 'super type class' : 'association'
358
- } '${property._OWNER.path}'`}
359
- >
360
- <ArrowCircleRightIcon />
361
- </button>
362
- )}
363
- {isIndirectProperty && (
364
- <div className="property-basic-editor__locked-property-end-block"></div>
365
- )}
366
- {!isIndirectProperty && !isReadOnly && (
367
- <button
368
- className={clsx('uml-element-editor__remove-btn', {
369
- 'uml-element-editor__remove-btn--hidden': isIndirectProperty,
370
- })}
371
- onClick={deleteProperty}
372
- tabIndex={-1}
373
- title={'Remove'}
374
- >
375
- <TimesIcon />
376
- </button>
377
- )}
452
+ </PanelEntryDropZonePlaceholder>
378
453
  </div>
379
454
  );
380
455
  },
381
456
  );
382
457
 
458
+ type ClassDerivedPropertyDragSource = {
459
+ derivedProperty: DerivedProperty;
460
+ };
461
+
462
+ const CLASS_DERIVED_PROPERTY_DND_TYPE = 'CLASS_DERIVED_PROPERTY';
463
+
383
464
  const DerivedPropertyBasicEditor = observer(
384
465
  (props: {
385
466
  _class: Class;
@@ -388,6 +469,7 @@ const DerivedPropertyBasicEditor = observer(
388
469
  deleteDerivedProperty: () => void;
389
470
  isReadOnly: boolean;
390
471
  }) => {
472
+ const ref = useRef<HTMLDivElement>(null);
391
473
  const {
392
474
  derivedProperty,
393
475
  _class,
@@ -464,6 +546,68 @@ const DerivedPropertyBasicEditor = observer(
464
546
  setUpperBound(event.target.value);
465
547
  updateMultiplicity(lowerBound, event.target.value);
466
548
  };
549
+
550
+ // Drag and Drop
551
+ const handleHover = useCallback(
552
+ (
553
+ item: ClassDerivedPropertyDragSource,
554
+ monitor: DropTargetMonitor,
555
+ ): void => {
556
+ const draggingProperty = item.derivedProperty;
557
+ const hoveredProperty = derivedProperty;
558
+
559
+ const dragIndex = _class.derivedProperties.findIndex(
560
+ (e) => e === item.derivedProperty,
561
+ );
562
+ const hoverIndex = _class.derivedProperties.findIndex(
563
+ (e) => e === derivedProperty,
564
+ );
565
+ // move the item being hovered on when the dragged item position is beyond the its middle point
566
+ const hoverBoundingReact = ref.current?.getBoundingClientRect();
567
+ const distanceThreshold =
568
+ ((hoverBoundingReact?.bottom ?? 0) - (hoverBoundingReact?.top ?? 0)) /
569
+ 2;
570
+ const dragDistance =
571
+ (monitor.getClientOffset()?.y ?? 0) - (hoverBoundingReact?.top ?? 0);
572
+ if (dragIndex < hoverIndex && dragDistance < distanceThreshold) {
573
+ return;
574
+ }
575
+ class_swapDerivedProperties(_class, draggingProperty, hoveredProperty);
576
+ },
577
+ [_class, derivedProperty],
578
+ );
579
+
580
+ const [{ isBeingDraggedDerivedProperty }, dropConnector] = useDrop<
581
+ ClassDerivedPropertyDragSource,
582
+ void,
583
+ { isBeingDraggedDerivedProperty: DerivedProperty | undefined }
584
+ >(
585
+ () => ({
586
+ accept: [CLASS_DERIVED_PROPERTY_DND_TYPE],
587
+ hover: (item, monitor): void => handleHover(item, monitor),
588
+ collect: (monitor) => ({
589
+ isBeingDraggedDerivedProperty:
590
+ monitor.getItem<ClassDerivedPropertyDragSource | null>()
591
+ ?.derivedProperty,
592
+ }),
593
+ }),
594
+ [handleHover],
595
+ );
596
+ const isBeingDragged = derivedProperty === isBeingDraggedDerivedProperty;
597
+
598
+ const [, dragConnector, dragPreviewConnector] =
599
+ useDrag<ClassDerivedPropertyDragSource>(
600
+ () => ({
601
+ type: CLASS_DERIVED_PROPERTY_DND_TYPE,
602
+ item: () => ({
603
+ derivedProperty: derivedProperty,
604
+ }),
605
+ }),
606
+ [derivedProperty],
607
+ );
608
+ dragConnector(dropConnector(ref));
609
+ useDragPreviewLayer(dragPreviewConnector);
610
+
467
611
  // Action
468
612
  const onLambdaEditorFocus = (): void =>
469
613
  applicationStore.navigationContextService.push(
@@ -486,187 +630,202 @@ const DerivedPropertyBasicEditor = observer(
486
630
  });
487
631
 
488
632
  return (
489
- <div
490
- className={clsx('derived-property-editor', {
491
- backdrop__element:
492
- dpState.parserError && !isInheritedProperty && !isReadOnly,
493
- })}
494
- >
495
- <div className="property-basic-editor">
496
- {isInheritedProperty && (
497
- <div className="property-basic-editor__name--with-lock">
498
- <div className="property-basic-editor__name--with-lock__icon">
499
- <LockIcon />
500
- </div>
501
- <span className="property-basic-editor__name--with-lock__name">
502
- {derivedProperty.name}
503
- </span>
504
- </div>
505
- )}
506
- {!isInheritedProperty && (
507
- <input
508
- disabled={isReadOnly}
509
- spellCheck={false}
510
- className="property-basic-editor__name property-basic-editor__qualififed-property__name"
511
- value={derivedProperty.name}
512
- placeholder="Property name"
513
- onChange={changeValue}
514
- />
515
- )}
516
- {!isInheritedProperty && !isReadOnly && isEditingType && (
517
- <CustomSelectorInput
518
- className="property-basic-editor__type property-basic-editor__qualififed-property__type"
519
- options={propertyTypeOptions}
520
- onChange={changePropertyType}
521
- value={selectedPropertyType}
522
- placeholder="Choose a data type or enumeration"
523
- filterOption={filterOption}
524
- formatOptionLabel={getPackageableElementOptionFormatter({
525
- graphManagerState: editorStore.graphManagerState,
526
- })}
527
- />
528
- )}
529
- {!isInheritedProperty && !isReadOnly && !isEditingType && (
530
- <div
531
- className={clsx(
532
- 'property-basic-editor__type',
533
- 'property-basic-editor__type--show-click-hint',
534
- `background--${propertyTypeName.toLowerCase()}`,
535
- {
536
- 'property-basic-editor__type--has-visit-btn':
537
- propertyTypeName !== CLASS_PROPERTY_TYPE.PRIMITIVE,
538
- },
633
+ <div ref={ref} className="derived-property-editor__container">
634
+ <PanelEntryDropZonePlaceholder
635
+ showPlaceholder={isBeingDragged}
636
+ className="derived-property-editor__dnd__placeholder"
637
+ >
638
+ <div
639
+ className={clsx('derived-property-editor', {
640
+ backdrop__element:
641
+ dpState.parserError && !isInheritedProperty && !isReadOnly,
642
+ })}
643
+ >
644
+ <div className="property-basic-editor">
645
+ {isInheritedProperty && (
646
+ <div className="property-basic-editor__name property-basic-editor__name--with-lock">
647
+ <div className="property-basic-editor__name--with-lock__icon">
648
+ <LockIcon />
649
+ </div>
650
+ <span className="property-basic-editor__name--with-lock__name">
651
+ {derivedProperty.name}
652
+ </span>
653
+ </div>
539
654
  )}
540
- >
541
- {propertyTypeName !== CLASS_PROPERTY_TYPE.PRIMITIVE && (
542
- <div className="property-basic-editor__type__abbr">
543
- {getElementIcon(editorStore, propertyType)}
655
+ {!isInheritedProperty && <PanelEntryDragHandle />}
656
+ {!isInheritedProperty && (
657
+ <input
658
+ disabled={isReadOnly}
659
+ spellCheck={false}
660
+ className="property-basic-editor__name property-basic-editor__qualififed-property__name"
661
+ value={derivedProperty.name}
662
+ placeholder="Property name"
663
+ onChange={changeValue}
664
+ />
665
+ )}
666
+ {!isInheritedProperty && !isReadOnly && isEditingType && (
667
+ <CustomSelectorInput
668
+ className="property-basic-editor__type property-basic-editor__qualififed-property__type"
669
+ options={propertyTypeOptions}
670
+ onChange={changePropertyType}
671
+ value={selectedPropertyType}
672
+ placeholder="Choose a data type or enumeration"
673
+ filterOption={filterOption}
674
+ formatOptionLabel={getPackageableElementOptionFormatter({})}
675
+ />
676
+ )}
677
+ {!isInheritedProperty && !isReadOnly && !isEditingType && (
678
+ <div
679
+ className={clsx(
680
+ 'property-basic-editor__type',
681
+ 'property-basic-editor__type--show-click-hint',
682
+ `background--${propertyTypeName.toLowerCase()}`,
683
+ {
684
+ 'property-basic-editor__type--has-visit-btn':
685
+ propertyTypeName !== CLASS_PROPERTY_TYPE.PRIMITIVE,
686
+ },
687
+ )}
688
+ >
689
+ {propertyTypeName !== CLASS_PROPERTY_TYPE.PRIMITIVE && (
690
+ <div className="property-basic-editor__type__abbr">
691
+ {getElementIcon(editorStore, propertyType)}
692
+ </div>
693
+ )}
694
+ <div className="property-basic-editor__type__label">
695
+ {propertyType.name}
696
+ </div>
697
+ <div
698
+ data-testid={
699
+ LEGEND_STUDIO_TEST_ID.PROPERTY_BASIC_EDITOR__TYPE__LABEL_HOVER
700
+ }
701
+ className="property-basic-editor__type__label property-basic-editor__type__label--hover"
702
+ onClick={(): void => setIsEditingType(true)}
703
+ >
704
+ Click to edit
705
+ </div>
706
+ {propertyTypeName !== CLASS_PROPERTY_TYPE.PRIMITIVE && (
707
+ <button
708
+ data-testid={LEGEND_STUDIO_TEST_ID.TYPE_VISIT}
709
+ className="property-basic-editor__type__visit-btn"
710
+ onClick={openElement}
711
+ tabIndex={-1}
712
+ title="Visit element"
713
+ >
714
+ <ArrowCircleRightIcon />
715
+ </button>
716
+ )}
544
717
  </div>
545
718
  )}
546
- <div className="property-basic-editor__type__label">
547
- {propertyType.name}
548
- </div>
549
- <div
550
- data-testid={
551
- LEGEND_STUDIO_TEST_ID.PROPERTY_BASIC_EDITOR__TYPE__LABEL_HOVER
552
- }
553
- className="property-basic-editor__type__label property-basic-editor__type__label--hover"
554
- onClick={(): void => setIsEditingType(true)}
555
- >
556
- Click to edit
719
+ {(isInheritedProperty || isReadOnly) && (
720
+ <div
721
+ className={clsx(
722
+ 'property-basic-editor__type',
723
+ `background--${propertyTypeName.toLowerCase()}`,
724
+ {
725
+ 'property-basic-editor__type--has-visit-btn':
726
+ propertyTypeName !== CLASS_PROPERTY_TYPE.PRIMITIVE,
727
+ },
728
+ )}
729
+ >
730
+ {propertyTypeName !== CLASS_PROPERTY_TYPE.PRIMITIVE && (
731
+ <div className="property-basic-editor__type__abbr">
732
+ {getElementIcon(editorStore, propertyType)}
733
+ </div>
734
+ )}
735
+ <div className="property-basic-editor__type__label">
736
+ {propertyType.name}
737
+ </div>
738
+ {propertyTypeName !== CLASS_PROPERTY_TYPE.PRIMITIVE && (
739
+ <button
740
+ data-testid={LEGEND_STUDIO_TEST_ID.TYPE_VISIT}
741
+ className="property-basic-editor__type__visit-btn"
742
+ onClick={openElement}
743
+ tabIndex={-1}
744
+ title="Visit element"
745
+ >
746
+ <ArrowCircleRightIcon />
747
+ </button>
748
+ )}
749
+ </div>
750
+ )}
751
+ <div className="property-basic-editor__multiplicity">
752
+ <input
753
+ className="property-basic-editor__multiplicity-bound"
754
+ spellCheck={false}
755
+ disabled={isInheritedProperty || isReadOnly}
756
+ value={lowerBound}
757
+ onChange={changeLowerBound}
758
+ />
759
+ <div className="property-basic-editor__multiplicity__range">
760
+ ..
761
+ </div>
762
+ <input
763
+ className="property-basic-editor__multiplicity-bound"
764
+ spellCheck={false}
765
+ disabled={isInheritedProperty || isReadOnly}
766
+ value={upperBound}
767
+ onChange={changeUpperBound}
768
+ />
557
769
  </div>
558
- {propertyTypeName !== CLASS_PROPERTY_TYPE.PRIMITIVE && (
770
+ {!isInheritedProperty && (
559
771
  <button
560
- data-testid={LEGEND_STUDIO_TEST_ID.TYPE_VISIT}
561
- className="property-basic-editor__type__visit-btn"
562
- onClick={openElement}
772
+ className="uml-element-editor__basic__detail-btn"
773
+ onClick={selectDerivedProperty}
563
774
  tabIndex={-1}
564
- title="Visit element"
775
+ title="See detail"
565
776
  >
566
- <ArrowCircleRightIcon />
777
+ <LongArrowRightIcon />
567
778
  </button>
568
779
  )}
569
- </div>
570
- )}
571
- {(isInheritedProperty || isReadOnly) && (
572
- <div
573
- className={clsx(
574
- 'property-basic-editor__type',
575
- `background--${propertyTypeName.toLowerCase()}`,
576
- {
577
- 'property-basic-editor__type--has-visit-btn':
578
- propertyTypeName !== CLASS_PROPERTY_TYPE.PRIMITIVE,
579
- },
580
- )}
581
- >
582
- {propertyTypeName !== CLASS_PROPERTY_TYPE.PRIMITIVE && (
583
- <div className="property-basic-editor__type__abbr">
584
- {getElementIcon(editorStore, propertyType)}
585
- </div>
586
- )}
587
- <div className="property-basic-editor__type__label">
588
- {propertyType.name}
589
- </div>
590
- {propertyTypeName !== CLASS_PROPERTY_TYPE.PRIMITIVE && (
780
+ {isInheritedProperty && (
591
781
  <button
592
- data-testid={LEGEND_STUDIO_TEST_ID.TYPE_VISIT}
593
- className="property-basic-editor__type__visit-btn"
594
- onClick={openElement}
782
+ className="uml-element-editor__visit-parent-element-btn"
783
+ onClick={visitOwner}
595
784
  tabIndex={-1}
596
- title="Visit element"
785
+ title={`Visit super type class ${derivedProperty._OWNER.path}`}
597
786
  >
598
787
  <ArrowCircleRightIcon />
599
788
  </button>
600
789
  )}
790
+ {!isInheritedProperty && !isReadOnly && (
791
+ <button
792
+ className={clsx('uml-element-editor__remove-btn', {
793
+ 'uml-element-editor__remove-btn--hidden':
794
+ isInheritedProperty,
795
+ })}
796
+ onClick={remove}
797
+ tabIndex={-1}
798
+ title="Remove"
799
+ >
800
+ <TimesIcon />
801
+ </button>
802
+ )}
601
803
  </div>
602
- )}
603
- <div className="property-basic-editor__multiplicity">
604
- <input
605
- className="property-basic-editor__multiplicity-bound"
606
- spellCheck={false}
607
- disabled={isInheritedProperty || isReadOnly}
608
- value={lowerBound}
609
- onChange={changeLowerBound}
610
- />
611
- <div className="property-basic-editor__multiplicity__range">..</div>
612
- <input
613
- className="property-basic-editor__multiplicity-bound"
614
- spellCheck={false}
615
- disabled={isInheritedProperty || isReadOnly}
616
- value={upperBound}
617
- onChange={changeUpperBound}
804
+ <StudioLambdaEditor
805
+ disabled={
806
+ editorState.classState
807
+ .isConvertingDerivedPropertyLambdaObjects ||
808
+ isInheritedProperty ||
809
+ isReadOnly
810
+ }
811
+ lambdaEditorState={dpState}
812
+ forceBackdrop={hasParserError}
813
+ expectedType={propertyType}
814
+ onEditorFocusEventHandler={onLambdaEditorFocus}
618
815
  />
619
816
  </div>
620
- {!isInheritedProperty && (
621
- <button
622
- className="uml-element-editor__basic__detail-btn"
623
- onClick={selectDerivedProperty}
624
- tabIndex={-1}
625
- title="See detail"
626
- >
627
- <LongArrowRightIcon />
628
- </button>
629
- )}
630
- {isInheritedProperty && (
631
- <button
632
- className="uml-element-editor__visit-parent-element-btn"
633
- onClick={visitOwner}
634
- tabIndex={-1}
635
- title={`Visit super type class ${derivedProperty._OWNER.path}`}
636
- >
637
- <ArrowCircleRightIcon />
638
- </button>
639
- )}
640
- {!isInheritedProperty && !isReadOnly && (
641
- <button
642
- className={clsx('uml-element-editor__remove-btn', {
643
- 'uml-element-editor__remove-btn--hidden': isInheritedProperty,
644
- })}
645
- onClick={remove}
646
- tabIndex={-1}
647
- title="Remove"
648
- >
649
- <TimesIcon />
650
- </button>
651
- )}
652
- </div>
653
- <div onFocus={onLambdaEditorFocus}>
654
- <StudioLambdaEditor
655
- disabled={
656
- editorState.classState.isConvertingDerivedPropertyLambdaObjects ||
657
- isInheritedProperty ||
658
- isReadOnly
659
- }
660
- lambdaEditorState={dpState}
661
- forceBackdrop={hasParserError}
662
- expectedType={propertyType}
663
- />
664
- </div>
817
+ </PanelEntryDropZonePlaceholder>
665
818
  </div>
666
819
  );
667
820
  },
668
821
  );
669
822
 
823
+ type ClassConstraintDragSource = {
824
+ constraint: Constraint;
825
+ };
826
+
827
+ const CLASS_CONSTRAINT_DND_TYPE = 'CLASS_CONSTRAINT';
828
+
670
829
  const ConstraintEditor = observer(
671
830
  (props: {
672
831
  editorState: ClassEditorState;
@@ -675,6 +834,7 @@ const ConstraintEditor = observer(
675
834
  deleteConstraint: () => void;
676
835
  isReadOnly: boolean;
677
836
  }) => {
837
+ const ref = useRef<HTMLDivElement>(null);
678
838
  const { constraint, _class, deleteConstraint, editorState, isReadOnly } =
679
839
  props;
680
840
  const editorStore = useEditorStore();
@@ -688,6 +848,49 @@ const ConstraintEditor = observer(
688
848
  // Name
689
849
  const changeName: React.ChangeEventHandler<HTMLInputElement> = (event) =>
690
850
  constraint_setName(constraint, event.target.value);
851
+
852
+ // Drag and Drop
853
+ const handleHover = useCallback(
854
+ (item: ClassConstraintDragSource): void => {
855
+ const draggingProperty = item.constraint;
856
+ const hoveredProperty = constraint;
857
+ class_swapConstraints(_class, draggingProperty, hoveredProperty);
858
+ },
859
+ [_class, constraint],
860
+ );
861
+
862
+ const [{ isBeingDraggedConstraint }, dropConnector] = useDrop<
863
+ ClassConstraintDragSource,
864
+ void,
865
+ { isBeingDraggedConstraint: Constraint | undefined }
866
+ >(
867
+ () => ({
868
+ accept: [CLASS_CONSTRAINT_DND_TYPE],
869
+ hover: (item) => handleHover(item),
870
+ collect: (
871
+ monitor,
872
+ ): { isBeingDraggedConstraint: Constraint | undefined } => ({
873
+ isBeingDraggedConstraint:
874
+ monitor.getItem<ClassConstraintDragSource | null>()?.constraint,
875
+ }),
876
+ }),
877
+ [handleHover],
878
+ );
879
+ const isBeingDragged = constraint === isBeingDraggedConstraint;
880
+
881
+ const [, dragConnector, dragPreviewConnector] =
882
+ useDrag<ClassConstraintDragSource>(
883
+ () => ({
884
+ type: CLASS_CONSTRAINT_DND_TYPE,
885
+ item: () => ({
886
+ constraint: constraint,
887
+ }),
888
+ }),
889
+ [constraint],
890
+ );
891
+ dragConnector(dropConnector(ref));
892
+ useDragPreviewLayer(dragPreviewConnector);
893
+
691
894
  // Actions
692
895
  const onLambdaEditorFocus = (): void =>
693
896
  applicationStore.navigationContextService.push(
@@ -704,73 +907,86 @@ const ConstraintEditor = observer(
704
907
  const visitOwner = (): void => editorStore.openElement(constraint._OWNER);
705
908
 
706
909
  return (
707
- <div
708
- className={clsx('constraint-editor', {
709
- backdrop__element: constraintState.parserError,
710
- })}
711
- >
712
- <div className="constraint-editor__content">
713
- {isInheritedConstraint && (
714
- <div className="constraint-editor__content__name--with-lock">
715
- <div className="constraint-editor__content__name--with-lock__icon">
716
- <LockIcon />
717
- </div>
718
- <span className="constraint-editor__content__name--with-lock__name">
719
- {constraint.name}
720
- </span>
910
+ <div ref={ref} className="constraint-editor__container">
911
+ <PanelEntryDropZonePlaceholder
912
+ showPlaceholder={isBeingDragged}
913
+ className="constraint-editor__dnd__placeholder"
914
+ >
915
+ <div
916
+ className={clsx('constraint-editor', {
917
+ backdrop__element: constraintState.parserError,
918
+ })}
919
+ >
920
+ <div className="constraint-editor__content">
921
+ {!isInheritedConstraint && <PanelEntryDragHandle />}
922
+ {isInheritedConstraint && (
923
+ <div className="constraint-editor__content__name--with-lock">
924
+ <div className="constraint-editor__content__name--with-lock__icon">
925
+ <LockIcon />
926
+ </div>
927
+ <span className="constraint-editor__content__name--with-lock__name">
928
+ {constraint.name}
929
+ </span>
930
+ </div>
931
+ )}
932
+ {!isInheritedConstraint && (
933
+ <input
934
+ className="constraint-editor__content__name"
935
+ spellCheck={false}
936
+ disabled={isReadOnly || isInheritedConstraint}
937
+ value={constraint.name}
938
+ onChange={changeName}
939
+ placeholder="Constraint name"
940
+ />
941
+ )}
942
+ {isInheritedConstraint && (
943
+ <button
944
+ className="uml-element-editor__visit-parent-element-btn"
945
+ onClick={visitOwner}
946
+ tabIndex={-1}
947
+ title={`Visit super type class ${constraint._OWNER.path}`}
948
+ >
949
+ <ArrowCircleRightIcon />
950
+ </button>
951
+ )}
952
+ {!isInheritedConstraint && !isReadOnly && (
953
+ <button
954
+ className="uml-element-editor__remove-btn"
955
+ disabled={isInheritedConstraint}
956
+ onClick={remove}
957
+ tabIndex={-1}
958
+ title="Remove"
959
+ >
960
+ <TimesIcon />
961
+ </button>
962
+ )}
721
963
  </div>
722
- )}
723
- {!isInheritedConstraint && (
724
- <input
725
- className="constraint-editor__content__name"
726
- spellCheck={false}
727
- disabled={isReadOnly || isInheritedConstraint}
728
- value={constraint.name}
729
- onChange={changeName}
730
- placeholder="Constraint name"
964
+ <StudioLambdaEditor
965
+ disabled={
966
+ editorState.classState.isConvertingConstraintLambdaObjects ||
967
+ isReadOnly ||
968
+ isInheritedConstraint
969
+ }
970
+ lambdaEditorState={constraintState}
971
+ forceBackdrop={hasParserError}
972
+ expectedType={editorStore.graphManagerState.graph.getPrimitiveType(
973
+ PRIMITIVE_TYPE.BOOLEAN,
974
+ )}
975
+ onEditorFocusEventHandler={onLambdaEditorFocus}
731
976
  />
732
- )}
733
- {isInheritedConstraint && (
734
- <button
735
- className="uml-element-editor__visit-parent-element-btn"
736
- onClick={visitOwner}
737
- tabIndex={-1}
738
- title={`Visit super type class ${constraint._OWNER.path}`}
739
- >
740
- <ArrowCircleRightIcon />
741
- </button>
742
- )}
743
- {!isInheritedConstraint && !isReadOnly && (
744
- <button
745
- className="uml-element-editor__remove-btn"
746
- disabled={isInheritedConstraint}
747
- onClick={remove}
748
- tabIndex={-1}
749
- title="Remove"
750
- >
751
- <TimesIcon />
752
- </button>
753
- )}
754
- </div>
755
- <div onFocus={onLambdaEditorFocus}>
756
- <StudioLambdaEditor
757
- disabled={
758
- editorState.classState.isConvertingConstraintLambdaObjects ||
759
- isReadOnly ||
760
- isInheritedConstraint
761
- }
762
- lambdaEditorState={constraintState}
763
- forceBackdrop={hasParserError}
764
- expectedType={editorStore.graphManagerState.graph.getPrimitiveType(
765
- PRIMITIVE_TYPE.BOOLEAN,
766
- )}
767
- />
768
- </div>
977
+ </div>
978
+ </PanelEntryDropZonePlaceholder>
769
979
  </div>
770
980
  );
771
981
  },
772
982
  );
773
983
 
984
+ type ClassSuperTypeDragSource = {
985
+ superType: GenericTypeReference;
986
+ };
987
+
988
+ const CLASS_SUPER_TYPE_DND_TYPE = 'CLASS_SUPER_TYPE';
989
+
774
990
  const SuperTypeEditor = observer(
775
991
  (props: {
776
992
  _class: Class;
@@ -778,6 +994,7 @@ const SuperTypeEditor = observer(
778
994
  deleteSuperType: () => void;
779
995
  isReadOnly: boolean;
780
996
  }) => {
997
+ const ref = useRef<HTMLDivElement>(null);
781
998
  const { superType, _class, deleteSuperType, isReadOnly } = props;
782
999
  const editorStore = useEditorStore();
783
1000
  // Type
@@ -791,6 +1008,47 @@ const SuperTypeEditor = observer(
791
1008
  // Ensure there is no loop (might be expensive)
792
1009
  !getAllSuperclasses(classOption.value).includes(_class),
793
1010
  );
1011
+
1012
+ // Drag and Drop
1013
+ const handleHover = useCallback(
1014
+ (item: ClassSuperTypeDragSource): void => {
1015
+ const draggingProperty = item.superType;
1016
+ const hoveredProperty = superType;
1017
+ class_swapSuperTypes(_class, draggingProperty, hoveredProperty);
1018
+ },
1019
+ [_class, superType],
1020
+ );
1021
+
1022
+ const [{ isBeingDraggedSupertype }, dropConnector] = useDrop<
1023
+ ClassSuperTypeDragSource,
1024
+ void,
1025
+ { isBeingDraggedSupertype: GenericTypeReference | undefined }
1026
+ >(
1027
+ () => ({
1028
+ accept: [CLASS_SUPER_TYPE_DND_TYPE],
1029
+ hover: (item) => handleHover(item),
1030
+ collect: (monitor) => ({
1031
+ isBeingDraggedSupertype:
1032
+ monitor.getItem<ClassSuperTypeDragSource | null>()?.superType,
1033
+ }),
1034
+ }),
1035
+ [handleHover],
1036
+ );
1037
+ const isBeingDragged = superType === isBeingDraggedSupertype;
1038
+
1039
+ const [, dragConnector, dragPreviewConnector] =
1040
+ useDrag<ClassSuperTypeDragSource>(
1041
+ () => ({
1042
+ type: CLASS_SUPER_TYPE_DND_TYPE,
1043
+ item: () => ({
1044
+ superType: superType,
1045
+ }),
1046
+ }),
1047
+ [superType],
1048
+ );
1049
+ dragConnector(dropConnector(ref));
1050
+ useDragPreviewLayer(dragPreviewConnector);
1051
+
794
1052
  const rawType = superType.value.rawType;
795
1053
  const filterOption = createFilter({
796
1054
  ignoreCase: true,
@@ -804,38 +1062,41 @@ const SuperTypeEditor = observer(
804
1062
  const visitDerivationSource = (): void => editorStore.openElement(rawType);
805
1063
 
806
1064
  return (
807
- <div className="super-type-editor">
808
- <CustomSelectorInput
809
- className="super-type-editor__class"
810
- disabled={isReadOnly}
811
- options={superTypeOptions}
812
- onChange={changeType}
813
- value={selectedType}
814
- placeholder={'Choose a class'}
815
- filterOption={filterOption}
816
- formatOptionLabel={getPackageableElementOptionFormatter({
817
- graphManagerState: editorStore.graphManagerState,
818
- })}
819
- />
820
- <button
821
- className="uml-element-editor__basic__detail-btn"
822
- onClick={visitDerivationSource}
823
- tabIndex={-1}
824
- title={'Visit super type'}
825
- >
826
- <LongArrowRightIcon />
827
- </button>
828
- {!isReadOnly && (
829
- <button
830
- className="uml-element-editor__remove-btn"
831
- disabled={isReadOnly}
832
- onClick={deleteSuperType}
833
- tabIndex={-1}
834
- title={'Remove'}
835
- >
836
- <TimesIcon />
837
- </button>
838
- )}
1065
+ <div ref={ref} className="super-type-editor__container">
1066
+ <PanelEntryDropZonePlaceholder showPlaceholder={isBeingDragged}>
1067
+ <div className="super-type-editor">
1068
+ <PanelEntryDragHandle />
1069
+ <CustomSelectorInput
1070
+ className="super-type-editor__class"
1071
+ disabled={isReadOnly}
1072
+ options={superTypeOptions}
1073
+ onChange={changeType}
1074
+ value={selectedType}
1075
+ placeholder={'Choose a class'}
1076
+ filterOption={filterOption}
1077
+ formatOptionLabel={getPackageableElementOptionFormatter({})}
1078
+ />
1079
+ <button
1080
+ className="uml-element-editor__basic__detail-btn"
1081
+ onClick={visitDerivationSource}
1082
+ tabIndex={-1}
1083
+ title={'Visit super type'}
1084
+ >
1085
+ <LongArrowRightIcon />
1086
+ </button>
1087
+ {!isReadOnly && (
1088
+ <button
1089
+ className="uml-element-editor__remove-btn"
1090
+ disabled={isReadOnly}
1091
+ onClick={deleteSuperType}
1092
+ tabIndex={-1}
1093
+ title={'Remove'}
1094
+ >
1095
+ <TimesIcon />
1096
+ </button>
1097
+ )}
1098
+ </div>
1099
+ </PanelEntryDropZonePlaceholder>
839
1100
  </div>
840
1101
  );
841
1102
  },
@@ -854,6 +1115,7 @@ const PropertiesEditor = observer(
854
1115
  editorState.setSelectedProperty(undefined);
855
1116
  }
856
1117
  };
1118
+
857
1119
  const indirectProperties = getAllClassProperties(_class)
858
1120
  .filter((property) => !_class.properties.includes(property))
859
1121
  .sort((p1, p2) => p1.name.localeCompare(p2.name))
@@ -873,14 +1135,18 @@ const PropertiesEditor = observer(
873
1135
  },
874
1136
  [_class, isReadOnly],
875
1137
  );
876
- const [{ isPropertyDragOver }, dropPropertyRef] = useDrop(
1138
+ const [{ isPropertyDragOver }, dropPropertyRef] = useDrop<
1139
+ ElementDragSource,
1140
+ void,
1141
+ { isPropertyDragOver: boolean }
1142
+ >(
877
1143
  () => ({
878
1144
  accept: [
879
1145
  CORE_DND_TYPE.PROJECT_EXPLORER_CLASS,
880
1146
  CORE_DND_TYPE.PROJECT_EXPLORER_ENUMERATION,
881
1147
  ],
882
- drop: (item: ElementDragSource): void => handleDropProperty(item),
883
- collect: (monitor): { isPropertyDragOver: boolean } => ({
1148
+ drop: (item) => handleDropProperty(item),
1149
+ collect: (monitor) => ({
884
1150
  isPropertyDragOver: monitor.isOver({ shallow: true }),
885
1151
  }),
886
1152
  }),
@@ -892,23 +1158,29 @@ const PropertiesEditor = observer(
892
1158
  );
893
1159
 
894
1160
  return (
895
- <div
896
- ref={dropPropertyRef}
897
- className={clsx('panel__content__lists', {
898
- 'panel__content__lists--dnd-over': isPropertyDragOver && !isReadOnly,
899
- })}
1161
+ <PanelDropZone
1162
+ isDragOver={isPropertyDragOver && !isReadOnly}
1163
+ dropTargetConnector={dropPropertyRef}
900
1164
  >
901
- {_class.properties.concat(indirectProperties).map((property) => (
902
- <PropertyBasicEditor
903
- key={property._UUID}
904
- property={property}
905
- _class={_class}
906
- editorState={editorState}
907
- deleteProperty={deleteProperty(property)}
908
- isReadOnly={isReadOnly}
1165
+ <div className="panel__content__lists">
1166
+ <DragPreviewLayer
1167
+ labelGetter={(item: ClassPropertyDragSource): string =>
1168
+ item.property.name === '' ? '(unknown)' : item.property.name
1169
+ }
1170
+ types={[CLASS_PROPERTY_DND_TYPE]}
909
1171
  />
910
- ))}
911
- </div>
1172
+ {_class.properties.concat(indirectProperties).map((property) => (
1173
+ <PropertyBasicEditor
1174
+ key={property._UUID}
1175
+ property={property}
1176
+ _class={_class}
1177
+ editorState={editorState}
1178
+ deleteProperty={deleteProperty(property)}
1179
+ isReadOnly={isReadOnly}
1180
+ />
1181
+ ))}
1182
+ </div>
1183
+ </PanelDropZone>
912
1184
  );
913
1185
  },
914
1186
  );
@@ -946,15 +1218,18 @@ const DerviedPropertiesEditor = observer(
946
1218
  },
947
1219
  [_class, classState, isReadOnly],
948
1220
  );
949
- const [{ isDerivedPropertyDragOver }, dropDerivedPropertyRef] = useDrop(
1221
+ const [{ isDerivedPropertyDragOver }, dropDerivedPropertyRef] = useDrop<
1222
+ ElementDragSource,
1223
+ void,
1224
+ { isDerivedPropertyDragOver: boolean }
1225
+ >(
950
1226
  () => ({
951
1227
  accept: [
952
1228
  CORE_DND_TYPE.PROJECT_EXPLORER_CLASS,
953
1229
  CORE_DND_TYPE.PROJECT_EXPLORER_ENUMERATION,
954
1230
  ],
955
- drop: (item: ElementDragSource): void =>
956
- handleDropDerivedProperty(item),
957
- collect: (monitor): { isDerivedPropertyDragOver: boolean } => ({
1231
+ drop: (item) => handleDropDerivedProperty(item),
1232
+ collect: (monitor) => ({
958
1233
  isDerivedPropertyDragOver: monitor.isOver({ shallow: true }),
959
1234
  }),
960
1235
  }),
@@ -966,29 +1241,36 @@ const DerviedPropertiesEditor = observer(
966
1241
  );
967
1242
 
968
1243
  return (
969
- <div
970
- ref={dropDerivedPropertyRef}
971
- className={clsx('panel__content__lists', {
972
- 'panel__content__lists--dnd-over':
973
- isDerivedPropertyDragOver && !isReadOnly,
974
- })}
1244
+ <PanelDropZone
1245
+ isDragOver={isDerivedPropertyDragOver && !isReadOnly}
1246
+ dropTargetConnector={dropDerivedPropertyRef}
975
1247
  >
976
- {_class.derivedProperties
977
- .concat(indirectDerivedProperties)
978
- .filter((dp): dp is DerivedProperty =>
979
- Boolean(classState.getNullableDerivedPropertyState(dp)),
980
- )
981
- .map((dp) => (
982
- <DerivedPropertyBasicEditor
983
- key={dp._UUID}
984
- derivedProperty={dp}
985
- _class={_class}
986
- editorState={editorState}
987
- deleteDerivedProperty={deleteDerivedProperty(dp)}
988
- isReadOnly={isReadOnly}
989
- />
990
- ))}
991
- </div>
1248
+ <div className="panel__content__lists">
1249
+ <DragPreviewLayer
1250
+ labelGetter={(item: ClassDerivedPropertyDragSource): string =>
1251
+ item.derivedProperty.name === ''
1252
+ ? '(unknown)'
1253
+ : item.derivedProperty.name
1254
+ }
1255
+ types={[CLASS_DERIVED_PROPERTY_DND_TYPE]}
1256
+ />
1257
+ {_class.derivedProperties
1258
+ .concat(indirectDerivedProperties)
1259
+ .filter((dp): dp is DerivedProperty =>
1260
+ Boolean(classState.getNullableDerivedPropertyState(dp)),
1261
+ )
1262
+ .map((dp) => (
1263
+ <DerivedPropertyBasicEditor
1264
+ key={dp._UUID}
1265
+ derivedProperty={dp}
1266
+ _class={_class}
1267
+ editorState={editorState}
1268
+ deleteDerivedProperty={deleteDerivedProperty(dp)}
1269
+ isReadOnly={isReadOnly}
1270
+ />
1271
+ ))}
1272
+ </div>
1273
+ </PanelDropZone>
992
1274
  );
993
1275
  },
994
1276
  );
@@ -1015,6 +1297,12 @@ const ConstraintsEditor = observer(
1015
1297
 
1016
1298
  return (
1017
1299
  <div className="panel__content__lists">
1300
+ <DragPreviewLayer
1301
+ labelGetter={(item: ClassConstraintDragSource): string =>
1302
+ item.constraint.name === '' ? '(unknown)' : item.constraint.name
1303
+ }
1304
+ types={[CLASS_CONSTRAINT_DND_TYPE]}
1305
+ />
1018
1306
  {_class.constraints
1019
1307
  .concat(inheritedConstraints)
1020
1308
  .filter((constraint): constraint is Constraint =>
@@ -1072,14 +1360,18 @@ const SupertypesEditor = observer(
1072
1360
  },
1073
1361
  [_class, isReadOnly],
1074
1362
  );
1075
- const [{ isSuperTypeDragOver }, dropSuperTypeRef] = useDrop(
1363
+ const [{ isSuperTypeDragOver }, dropSuperTypeRef] = useDrop<
1364
+ ElementDragSource,
1365
+ void,
1366
+ { isSuperTypeDragOver: boolean }
1367
+ >(
1076
1368
  () => ({
1077
1369
  accept: [
1078
1370
  CORE_DND_TYPE.PROJECT_EXPLORER_CLASS,
1079
1371
  CORE_DND_TYPE.PROJECT_EXPLORER_ENUMERATION,
1080
1372
  ],
1081
- drop: (item: ElementDragSource): void => handleDropSuperType(item),
1082
- collect: (monitor): { isSuperTypeDragOver: boolean } => ({
1373
+ drop: (item) => handleDropSuperType(item),
1374
+ collect: (monitor) => ({
1083
1375
  isSuperTypeDragOver: monitor.isOver({ shallow: true }),
1084
1376
  }),
1085
1377
  }),
@@ -1091,22 +1383,28 @@ const SupertypesEditor = observer(
1091
1383
  );
1092
1384
 
1093
1385
  return (
1094
- <div
1095
- ref={dropSuperTypeRef}
1096
- className={clsx('panel__content__lists', {
1097
- 'panel__content__lists--dnd-over': isSuperTypeDragOver && !isReadOnly,
1098
- })}
1386
+ <PanelDropZone
1387
+ isDragOver={isSuperTypeDragOver && !isReadOnly}
1388
+ dropTargetConnector={dropSuperTypeRef}
1099
1389
  >
1100
- {_class.generalizations.map((superType) => (
1101
- <SuperTypeEditor
1102
- key={superType.value._UUID}
1103
- superType={superType}
1104
- _class={_class}
1105
- deleteSuperType={deleteSuperType(superType)}
1106
- isReadOnly={isReadOnly}
1390
+ <div className="panel__content__lists">
1391
+ <DragPreviewLayer
1392
+ labelGetter={(item: ClassSuperTypeDragSource): string =>
1393
+ item.superType.value.rawType.name
1394
+ }
1395
+ types={[CLASS_SUPER_TYPE_DND_TYPE]}
1107
1396
  />
1108
- ))}
1109
- </div>
1397
+ {_class.generalizations.map((superType) => (
1398
+ <SuperTypeEditor
1399
+ key={superType.value._UUID}
1400
+ superType={superType}
1401
+ _class={_class}
1402
+ deleteSuperType={deleteSuperType(superType)}
1403
+ isReadOnly={isReadOnly}
1404
+ />
1405
+ ))}
1406
+ </div>
1407
+ </PanelDropZone>
1110
1408
  );
1111
1409
  },
1112
1410
  );
@@ -1132,11 +1430,15 @@ const TaggedValuesEditor = observer(
1132
1430
  },
1133
1431
  [_class, isReadOnly],
1134
1432
  );
1135
- const [{ isTaggedValueDragOver }, dropTaggedValueRef] = useDrop(
1433
+ const [{ isTaggedValueDragOver }, dropTaggedValueRef] = useDrop<
1434
+ ElementDragSource,
1435
+ void,
1436
+ { isTaggedValueDragOver: boolean }
1437
+ >(
1136
1438
  () => ({
1137
1439
  accept: [CORE_DND_TYPE.PROJECT_EXPLORER_PROFILE],
1138
- drop: (item: ElementDragSource): void => handleDropTaggedValue(item),
1139
- collect: (monitor): { isTaggedValueDragOver: boolean } => ({
1440
+ drop: (item) => handleDropTaggedValue(item),
1441
+ collect: (monitor) => ({
1140
1442
  isTaggedValueDragOver: monitor.isOver({ shallow: true }),
1141
1443
  }),
1142
1444
  }),
@@ -1144,22 +1446,23 @@ const TaggedValuesEditor = observer(
1144
1446
  );
1145
1447
 
1146
1448
  return (
1147
- <div
1148
- ref={dropTaggedValueRef}
1149
- className={clsx('panel__content__lists', {
1150
- 'panel__content__lists--dnd-over':
1151
- isTaggedValueDragOver && !isReadOnly,
1152
- })}
1449
+ <PanelDropZone
1450
+ isDragOver={isTaggedValueDragOver && !isReadOnly}
1451
+ dropTargetConnector={dropTaggedValueRef}
1153
1452
  >
1154
- {_class.taggedValues.map((taggedValue) => (
1155
- <TaggedValueEditor
1156
- key={taggedValue._UUID}
1157
- taggedValue={taggedValue}
1158
- deleteValue={deleteTaggedValue(taggedValue)}
1159
- isReadOnly={isReadOnly}
1160
- />
1161
- ))}
1162
- </div>
1453
+ <div className="panel__content__lists">
1454
+ <TaggedValueDragPreviewLayer />
1455
+ {_class.taggedValues.map((taggedValue) => (
1456
+ <TaggedValueEditor
1457
+ annotatedElement={_class}
1458
+ key={taggedValue._UUID}
1459
+ taggedValue={taggedValue}
1460
+ deleteValue={deleteTaggedValue(taggedValue)}
1461
+ isReadOnly={isReadOnly}
1462
+ />
1463
+ ))}
1464
+ </div>
1465
+ </PanelDropZone>
1163
1466
  );
1164
1467
  },
1165
1468
  );
@@ -1187,11 +1490,15 @@ const StereotypesEditor = observer(
1187
1490
  },
1188
1491
  [_class, isReadOnly],
1189
1492
  );
1190
- const [{ isStereotypeDragOver }, dropStereotypeRef] = useDrop(
1493
+ const [{ isStereotypeDragOver }, dropStereotypeRef] = useDrop<
1494
+ ElementDragSource,
1495
+ void,
1496
+ { isStereotypeDragOver: boolean }
1497
+ >(
1191
1498
  () => ({
1192
1499
  accept: [CORE_DND_TYPE.PROJECT_EXPLORER_PROFILE],
1193
- drop: (item: ElementDragSource): void => handleDropStereotype(item),
1194
- collect: (monitor): { isStereotypeDragOver: boolean } => ({
1500
+ drop: (item) => handleDropStereotype(item),
1501
+ collect: (monitor) => ({
1195
1502
  isStereotypeDragOver: monitor.isOver({ shallow: true }),
1196
1503
  }),
1197
1504
  }),
@@ -1199,22 +1506,23 @@ const StereotypesEditor = observer(
1199
1506
  );
1200
1507
 
1201
1508
  return (
1202
- <div
1203
- ref={dropStereotypeRef}
1204
- className={clsx('panel__content__lists', {
1205
- 'panel__content__lists--dnd-over':
1206
- isStereotypeDragOver && !isReadOnly,
1207
- })}
1509
+ <PanelDropZone
1510
+ isDragOver={isStereotypeDragOver && !isReadOnly}
1511
+ dropTargetConnector={dropStereotypeRef}
1208
1512
  >
1209
- {_class.stereotypes.map((stereotype) => (
1210
- <StereotypeSelector
1211
- key={stereotype.value._UUID}
1212
- stereotype={stereotype}
1213
- deleteStereotype={deleteStereotype(stereotype)}
1214
- isReadOnly={isReadOnly}
1215
- />
1216
- ))}
1217
- </div>
1513
+ <div className="panel__content__lists">
1514
+ <StereotypeDragPreviewLayer />
1515
+ {_class.stereotypes.map((stereotype) => (
1516
+ <StereotypeSelector
1517
+ key={stereotype._UUID}
1518
+ annotatedElement={_class}
1519
+ stereotype={stereotype}
1520
+ deleteStereotype={deleteStereotype(stereotype)}
1521
+ isReadOnly={isReadOnly}
1522
+ />
1523
+ ))}
1524
+ </div>
1525
+ </PanelDropZone>
1218
1526
  );
1219
1527
  },
1220
1528
  );
@@ -1228,7 +1536,7 @@ export const ClassFormEditor = observer(
1228
1536
  const { _class, editorState, onHashChange } = props;
1229
1537
  const editorStore = useEditorStore();
1230
1538
  const applicationStore = useApplicationStore();
1231
- const classHash = editorStore.graphManagerState.isElementReadOnly(_class)
1539
+ const classHash = isElementReadOnly(_class)
1232
1540
  ? undefined
1233
1541
  : applicationStore.notifyAndReturnAlternativeOnError(
1234
1542
  () => _class.hashCode,