@finos/legend-application-studio 28.19.7 → 28.19.9
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.
- package/lib/components/editor/editor-group/connection-editor/DatabaseEditorHelper.d.ts +1 -0
- package/lib/components/editor/editor-group/connection-editor/DatabaseEditorHelper.d.ts.map +1 -1
- package/lib/components/editor/editor-group/connection-editor/DatabaseEditorHelper.js +29 -1
- package/lib/components/editor/editor-group/connection-editor/DatabaseEditorHelper.js.map +1 -1
- package/lib/components/editor/editor-group/dataProduct/DataPoductEditor.js +2 -2
- package/lib/components/editor/editor-group/function-activator/SnowflakeM2MUdfFunctionActivatorEditor.js +1 -1
- package/lib/components/editor/editor-group/function-activator/SnowflakeM2MUdfFunctionActivatorEditor.js.map +1 -1
- package/lib/components/editor/editor-group/mapping-editor/ClassMappingEditor.d.ts +2 -1
- package/lib/components/editor/editor-group/mapping-editor/ClassMappingEditor.d.ts.map +1 -1
- package/lib/components/editor/editor-group/mapping-editor/ClassMappingEditor.js +6 -1
- package/lib/components/editor/editor-group/mapping-editor/ClassMappingEditor.js.map +1 -1
- package/lib/components/editor/editor-group/mapping-editor/InstanceSetImplementationEditor.d.ts.map +1 -1
- package/lib/components/editor/editor-group/mapping-editor/InstanceSetImplementationEditor.js +7 -2
- package/lib/components/editor/editor-group/mapping-editor/InstanceSetImplementationEditor.js.map +1 -1
- package/lib/components/editor/editor-group/mapping-editor/InstanceSetImplementationSourceSelectorModal.d.ts.map +1 -1
- package/lib/components/editor/editor-group/mapping-editor/InstanceSetImplementationSourceSelectorModal.js +14 -1
- package/lib/components/editor/editor-group/mapping-editor/InstanceSetImplementationSourceSelectorModal.js.map +1 -1
- package/lib/components/editor/editor-group/mapping-editor/PropertyMappingsEditor.d.ts.map +1 -1
- package/lib/components/editor/editor-group/mapping-editor/PropertyMappingsEditor.js +6 -1
- package/lib/components/editor/editor-group/mapping-editor/PropertyMappingsEditor.js.map +1 -1
- package/lib/components/editor/editor-group/mapping-editor/RelationFunctionPropertyMappingEditor.d.ts +25 -0
- package/lib/components/editor/editor-group/mapping-editor/RelationFunctionPropertyMappingEditor.d.ts.map +1 -0
- package/lib/components/editor/editor-group/mapping-editor/RelationFunctionPropertyMappingEditor.js +64 -0
- package/lib/components/editor/editor-group/mapping-editor/RelationFunctionPropertyMappingEditor.js.map +1 -0
- package/lib/components/editor/editor-group/mapping-editor/RelationTypeTree.d.ts +38 -0
- package/lib/components/editor/editor-group/mapping-editor/RelationTypeTree.d.ts.map +1 -0
- package/lib/components/editor/editor-group/mapping-editor/RelationTypeTree.js +140 -0
- package/lib/components/editor/editor-group/mapping-editor/RelationTypeTree.js.map +1 -0
- package/lib/index.css +1 -1
- package/lib/package.json +1 -1
- package/lib/stores/editor/editor-state/element-editor-state/mapping/MappingEditorState.d.ts.map +1 -1
- package/lib/stores/editor/editor-state/element-editor-state/mapping/MappingEditorState.js +19 -7
- package/lib/stores/editor/editor-state/element-editor-state/mapping/MappingEditorState.js.map +1 -1
- package/lib/stores/editor/editor-state/element-editor-state/mapping/MappingElementDecorator.d.ts.map +1 -1
- package/lib/stores/editor/editor-state/element-editor-state/mapping/MappingElementDecorator.js +37 -3
- package/lib/stores/editor/editor-state/element-editor-state/mapping/MappingElementDecorator.js.map +1 -1
- package/lib/stores/editor/editor-state/element-editor-state/mapping/RelationFunctionInstanceSetImplementationState.d.ts +47 -0
- package/lib/stores/editor/editor-state/element-editor-state/mapping/RelationFunctionInstanceSetImplementationState.d.ts.map +1 -0
- package/lib/stores/editor/editor-state/element-editor-state/mapping/RelationFunctionInstanceSetImplementationState.js +112 -0
- package/lib/stores/editor/editor-state/element-editor-state/mapping/RelationFunctionInstanceSetImplementationState.js.map +1 -0
- package/lib/stores/editor/editor-state/element-editor-state/mapping/testable/MappingTestingHelper.d.ts.map +1 -1
- package/lib/stores/editor/editor-state/element-editor-state/mapping/testable/MappingTestingHelper.js +1 -0
- package/lib/stores/editor/editor-state/element-editor-state/mapping/testable/MappingTestingHelper.js.map +1 -1
- package/lib/stores/graph-modifier/STO_RelationFunction_GraphModifierHelper.d.ts +19 -0
- package/lib/stores/graph-modifier/STO_RelationFunction_GraphModifierHelper.d.ts.map +1 -0
- package/lib/stores/graph-modifier/STO_RelationFunction_GraphModifierHelper.js +22 -0
- package/lib/stores/graph-modifier/STO_RelationFunction_GraphModifierHelper.js.map +1 -0
- package/package.json +14 -14
- package/src/components/editor/editor-group/connection-editor/DatabaseEditorHelper.tsx +43 -0
- package/src/components/editor/editor-group/dataProduct/DataPoductEditor.tsx +2 -2
- package/src/components/editor/editor-group/function-activator/SnowflakeM2MUdfFunctionActivatorEditor.tsx +1 -1
- package/src/components/editor/editor-group/mapping-editor/ClassMappingEditor.tsx +7 -0
- package/src/components/editor/editor-group/mapping-editor/InstanceSetImplementationEditor.tsx +21 -0
- package/src/components/editor/editor-group/mapping-editor/InstanceSetImplementationSourceSelectorModal.tsx +17 -0
- package/src/components/editor/editor-group/mapping-editor/PropertyMappingsEditor.tsx +22 -0
- package/src/components/editor/editor-group/mapping-editor/RelationFunctionPropertyMappingEditor.tsx +127 -0
- package/src/components/editor/editor-group/mapping-editor/RelationTypeTree.tsx +257 -0
- package/src/stores/editor/editor-state/element-editor-state/mapping/MappingEditorState.ts +37 -10
- package/src/stores/editor/editor-state/element-editor-state/mapping/MappingElementDecorator.ts +70 -2
- package/src/stores/editor/editor-state/element-editor-state/mapping/RelationFunctionInstanceSetImplementationState.ts +172 -0
- package/src/stores/editor/editor-state/element-editor-state/mapping/testable/MappingTestingHelper.ts +1 -0
- package/src/stores/graph-modifier/STO_RelationFunction_GraphModifierHelper.ts +39 -0
- package/tsconfig.json +4 -0
@@ -43,6 +43,8 @@ import {
|
|
43
43
|
getAllRecordTypes,
|
44
44
|
PackageableElement,
|
45
45
|
FlatData,
|
46
|
+
ConcreteFunctionDefinition,
|
47
|
+
CORE_PURE_PATH,
|
46
48
|
} from '@finos/legend-graph';
|
47
49
|
import { isNonNullable, UnsupportedOperationError } from '@finos/legend-shared';
|
48
50
|
import { flowResult } from 'mobx';
|
@@ -63,6 +65,8 @@ export const getMappingElementSourceFilterText = (
|
|
63
65
|
return val._OWNER.name;
|
64
66
|
} else if (val instanceof TableAlias) {
|
65
67
|
return `${val.relation.ownerReference.value.path}.${val.relation.value.schema.name}.${val.relation.value.name}`;
|
68
|
+
} else if (val instanceof ConcreteFunctionDefinition) {
|
69
|
+
return `${val.functionName}`;
|
66
70
|
}
|
67
71
|
throw new UnsupportedOperationError();
|
68
72
|
};
|
@@ -84,6 +88,8 @@ export const getSourceElementLabel = (srcElement: unknown): string => {
|
|
84
88
|
? ''
|
85
89
|
: `${srcElement.relation.value.schema.name}.`
|
86
90
|
}${srcElement.relation.value.name}`;
|
91
|
+
} else if (srcElement instanceof ConcreteFunctionDefinition) {
|
92
|
+
sourceLabel = srcElement.name;
|
87
93
|
}
|
88
94
|
return sourceLabel;
|
89
95
|
};
|
@@ -108,6 +114,11 @@ export const buildMappingElementSourceOption = (
|
|
108
114
|
}${source.relation.value.name}`,
|
109
115
|
value: source,
|
110
116
|
};
|
117
|
+
} else if (source instanceof ConcreteFunctionDefinition) {
|
118
|
+
return {
|
119
|
+
label: `${source.functionName}`,
|
120
|
+
value: source,
|
121
|
+
};
|
111
122
|
}
|
112
123
|
return null;
|
113
124
|
};
|
@@ -147,6 +158,12 @@ export const InstanceSetImplementationSourceSelectorModal = observer(
|
|
147
158
|
getAllRecordTypes,
|
148
159
|
),
|
149
160
|
)
|
161
|
+
.concat(
|
162
|
+
editorStore.graphManagerState.usableFunctions.filter(
|
163
|
+
(def) =>
|
164
|
+
def.returnType.value.rawType.path === CORE_PURE_PATH.RELATION,
|
165
|
+
),
|
166
|
+
)
|
150
167
|
.concat(
|
151
168
|
editorStore.graphManagerState.usableDatabases
|
152
169
|
.flatMap((e) =>
|
@@ -63,6 +63,7 @@ import {
|
|
63
63
|
RootRelationalInstanceSetImplementation,
|
64
64
|
MULTIPLICITY_INFINITE,
|
65
65
|
type Multiplicity,
|
66
|
+
RelationFunctionInstanceSetImplementation,
|
66
67
|
} from '@finos/legend-graph';
|
67
68
|
import { useApplicationStore } from '@finos/legend-application';
|
68
69
|
import {
|
@@ -76,6 +77,11 @@ import {
|
|
76
77
|
} from '../../../../stores/editor/utils/ModelClassifierUtils.js';
|
77
78
|
import type { DSL_Mapping_LegendStudioApplicationPlugin_Extension } from '../../../../stores/extensions/DSL_Mapping_LegendStudioApplicationPlugin_Extension.js';
|
78
79
|
import { Fragment } from 'react';
|
80
|
+
import { RelationFunctionPropertyMappingEditor } from './RelationFunctionPropertyMappingEditor.js';
|
81
|
+
import type {
|
82
|
+
RelationFunctionInstanceSetImplementationState,
|
83
|
+
RelationFunctionPropertyMappingState,
|
84
|
+
} from '../../../../stores/editor/editor-state/element-editor-state/mapping/RelationFunctionInstanceSetImplementationState.js';
|
79
85
|
|
80
86
|
const MultiplicityBadge: React.FC<{
|
81
87
|
multiplicity: Multiplicity;
|
@@ -320,6 +326,22 @@ export const PropertyMappingEditor = observer(
|
|
320
326
|
setImplementationHasParserError={setImplementationHasParserError}
|
321
327
|
/>
|
322
328
|
);
|
329
|
+
} else if (
|
330
|
+
instanceSetImplementation instanceof
|
331
|
+
RelationFunctionInstanceSetImplementation
|
332
|
+
) {
|
333
|
+
return (
|
334
|
+
<RelationFunctionPropertyMappingEditor
|
335
|
+
isReadOnly={isReadOnly}
|
336
|
+
relationInstanceSetImplementationState={
|
337
|
+
instanceSetImplementationState as RelationFunctionInstanceSetImplementationState
|
338
|
+
}
|
339
|
+
relationPropertyMappingState={
|
340
|
+
propertyMappingState as RelationFunctionPropertyMappingState
|
341
|
+
}
|
342
|
+
setImplementationHasParserError={setImplementationHasParserError}
|
343
|
+
/>
|
344
|
+
);
|
323
345
|
} else {
|
324
346
|
const extraPropertyMappingEditorRenderers = editorStore.pluginManager
|
325
347
|
.getApplicationPlugins()
|
package/src/components/editor/editor-group/mapping-editor/RelationFunctionPropertyMappingEditor.tsx
ADDED
@@ -0,0 +1,127 @@
|
|
1
|
+
/**
|
2
|
+
* Copyright (c) 2025-present, Goldman Sachs
|
3
|
+
*
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
* you may not use this file except in compliance with the License.
|
6
|
+
* You may obtain a copy of the License at
|
7
|
+
*
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
*
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
* See the License for the specific language governing permissions and
|
14
|
+
* limitations under the License.
|
15
|
+
*/
|
16
|
+
|
17
|
+
import { useCallback, useRef } from 'react';
|
18
|
+
import { observer } from 'mobx-react-lite';
|
19
|
+
import { InlineLambdaEditor } from '@finos/legend-query-builder';
|
20
|
+
import type {
|
21
|
+
RelationFunctionInstanceSetImplementationState,
|
22
|
+
RelationFunctionPropertyMappingState,
|
23
|
+
} from '../../../../stores/editor/editor-state/element-editor-state/mapping/RelationFunctionInstanceSetImplementationState.js';
|
24
|
+
import { type ConnectDropTarget, useDrop } from 'react-dnd';
|
25
|
+
import {
|
26
|
+
getClassPropertyType,
|
27
|
+
CLASS_PROPERTY_TYPE,
|
28
|
+
} from '../../../../stores/editor/utils/ModelClassifierUtils.js';
|
29
|
+
import { RelationTypeDragSource } from './RelationTypeTree.js';
|
30
|
+
import { CORE_DND_TYPE } from '../../../../stores/editor/utils/DnDUtils.js';
|
31
|
+
import { guaranteeNonNullable } from '@finos/legend-shared';
|
32
|
+
|
33
|
+
const SimplePropertyMappingEditor = observer(
|
34
|
+
(props: {
|
35
|
+
propertyMappingState: RelationFunctionPropertyMappingState;
|
36
|
+
dropConnector?: ConnectDropTarget;
|
37
|
+
transformProps: {
|
38
|
+
disableTransform: boolean;
|
39
|
+
forceBackdrop: boolean;
|
40
|
+
};
|
41
|
+
isReadOnly: boolean;
|
42
|
+
}) => {
|
43
|
+
const { propertyMappingState, dropConnector, transformProps } = props;
|
44
|
+
const ref = useRef<HTMLDivElement>(null);
|
45
|
+
dropConnector?.(ref);
|
46
|
+
return (
|
47
|
+
<div className="property-mapping-editor__entry__container">
|
48
|
+
<div ref={ref} className="property-mapping-editor__entry">
|
49
|
+
<InlineLambdaEditor
|
50
|
+
disabled={transformProps.disableTransform}
|
51
|
+
lambdaEditorState={propertyMappingState}
|
52
|
+
forceBackdrop={transformProps.forceBackdrop}
|
53
|
+
/>
|
54
|
+
</div>
|
55
|
+
</div>
|
56
|
+
);
|
57
|
+
},
|
58
|
+
);
|
59
|
+
|
60
|
+
export const RelationFunctionPropertyMappingEditor = observer(
|
61
|
+
(props: {
|
62
|
+
relationPropertyMappingState: RelationFunctionPropertyMappingState;
|
63
|
+
relationInstanceSetImplementationState: RelationFunctionInstanceSetImplementationState;
|
64
|
+
setImplementationHasParserError: boolean;
|
65
|
+
isReadOnly: boolean;
|
66
|
+
}) => {
|
67
|
+
const {
|
68
|
+
relationPropertyMappingState: relationPropertyMappingState,
|
69
|
+
relationInstanceSetImplementationState:
|
70
|
+
relationInstanceSetImplementationState,
|
71
|
+
setImplementationHasParserError,
|
72
|
+
isReadOnly,
|
73
|
+
} = props;
|
74
|
+
const disableEditingTransform =
|
75
|
+
relationInstanceSetImplementationState.isConvertingTransformLambdaObjects ||
|
76
|
+
isReadOnly;
|
77
|
+
// Drag and Drop
|
78
|
+
const handleDrop = useCallback(
|
79
|
+
(droppedItem: RelationTypeDragSource): void => {
|
80
|
+
if (!disableEditingTransform) {
|
81
|
+
if (droppedItem instanceof RelationTypeDragSource) {
|
82
|
+
const toAppend = guaranteeNonNullable(droppedItem.data).id;
|
83
|
+
if (toAppend) {
|
84
|
+
relationPropertyMappingState.setLambdaString(
|
85
|
+
relationPropertyMappingState.lambdaString + toAppend,
|
86
|
+
);
|
87
|
+
}
|
88
|
+
}
|
89
|
+
}
|
90
|
+
},
|
91
|
+
[disableEditingTransform, relationPropertyMappingState],
|
92
|
+
);
|
93
|
+
const [, dropConnector] = useDrop<RelationTypeDragSource>(
|
94
|
+
() => ({
|
95
|
+
accept: [CORE_DND_TYPE.PROJECT_EXPLORER_FUNCTION],
|
96
|
+
drop: (item) => handleDrop(item),
|
97
|
+
}),
|
98
|
+
[handleDrop],
|
99
|
+
);
|
100
|
+
const transformProps = {
|
101
|
+
disableTransform:
|
102
|
+
relationInstanceSetImplementationState.isConvertingTransformLambdaObjects,
|
103
|
+
forceBackdrop: setImplementationHasParserError,
|
104
|
+
};
|
105
|
+
|
106
|
+
switch (
|
107
|
+
getClassPropertyType(
|
108
|
+
relationPropertyMappingState.propertyMapping.property.value.genericType
|
109
|
+
.value.rawType,
|
110
|
+
)
|
111
|
+
) {
|
112
|
+
case CLASS_PROPERTY_TYPE.UNIT:
|
113
|
+
case CLASS_PROPERTY_TYPE.MEASURE:
|
114
|
+
case CLASS_PROPERTY_TYPE.PRIMITIVE:
|
115
|
+
return (
|
116
|
+
<SimplePropertyMappingEditor
|
117
|
+
propertyMappingState={relationPropertyMappingState}
|
118
|
+
dropConnector={dropConnector}
|
119
|
+
transformProps={transformProps}
|
120
|
+
isReadOnly={isReadOnly}
|
121
|
+
/>
|
122
|
+
);
|
123
|
+
default:
|
124
|
+
return null;
|
125
|
+
}
|
126
|
+
},
|
127
|
+
);
|
@@ -0,0 +1,257 @@
|
|
1
|
+
/**
|
2
|
+
* Copyright (c) 2025-present, Goldman Sachs
|
3
|
+
*
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
* you may not use this file except in compliance with the License.
|
6
|
+
* You may obtain a copy of the License at
|
7
|
+
*
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
*
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
* See the License for the specific language governing permissions and
|
14
|
+
* limitations under the License.
|
15
|
+
*/
|
16
|
+
|
17
|
+
import { useState, useEffect, useRef } from 'react';
|
18
|
+
import { useDrag } from 'react-dnd';
|
19
|
+
import {
|
20
|
+
type TreeNodeContainerProps,
|
21
|
+
type TreeData,
|
22
|
+
type TreeNodeData,
|
23
|
+
TreeView,
|
24
|
+
ChevronDownIcon,
|
25
|
+
ChevronRightIcon,
|
26
|
+
} from '@finos/legend-art';
|
27
|
+
import {
|
28
|
+
addUniqueEntry,
|
29
|
+
assertErrorThrown,
|
30
|
+
isNonNullable,
|
31
|
+
} from '@finos/legend-shared';
|
32
|
+
import {
|
33
|
+
type Type,
|
34
|
+
RawLambda,
|
35
|
+
type ConcreteFunctionDefinition,
|
36
|
+
} from '@finos/legend-graph';
|
37
|
+
import { renderColumnTypeIconFromType } from '../connection-editor/DatabaseEditorHelper.js';
|
38
|
+
import { CORE_DND_TYPE } from '../../../../stores/editor/utils/DnDUtils.js';
|
39
|
+
import type { EditorStore } from '../../../../stores/editor/EditorStore.js';
|
40
|
+
|
41
|
+
export class RelationColumnTypeTreeNodeData implements TreeNodeData {
|
42
|
+
id: string;
|
43
|
+
label: string;
|
44
|
+
isSelected?: boolean;
|
45
|
+
isOpen?: boolean;
|
46
|
+
childrenIds?: string[];
|
47
|
+
columnName: string;
|
48
|
+
columnType: string;
|
49
|
+
|
50
|
+
constructor(
|
51
|
+
id: string,
|
52
|
+
label: string,
|
53
|
+
columnName: string,
|
54
|
+
columnType: string,
|
55
|
+
) {
|
56
|
+
this.id = id;
|
57
|
+
this.label = label;
|
58
|
+
this.columnName = columnName;
|
59
|
+
this.columnType = columnType;
|
60
|
+
}
|
61
|
+
}
|
62
|
+
|
63
|
+
const getColumnTreeNodeData = (
|
64
|
+
columnName: string,
|
65
|
+
columnType: string,
|
66
|
+
): RelationColumnTypeTreeNodeData => {
|
67
|
+
const columnNode = new RelationColumnTypeTreeNodeData(
|
68
|
+
columnName,
|
69
|
+
columnName,
|
70
|
+
columnName,
|
71
|
+
columnType,
|
72
|
+
);
|
73
|
+
return columnNode;
|
74
|
+
};
|
75
|
+
|
76
|
+
const getRelationTypeTreeData = async (
|
77
|
+
relation: ConcreteFunctionDefinition,
|
78
|
+
editorStore: EditorStore,
|
79
|
+
) => {
|
80
|
+
const rootIds: string[] = [];
|
81
|
+
const nodes = new Map<string, RelationColumnTypeTreeNodeData>();
|
82
|
+
// columns
|
83
|
+
// throw an error if more than one in concrete function definition
|
84
|
+
const lambda = new RawLambda(
|
85
|
+
relation.parameters.map((parameter) =>
|
86
|
+
editorStore.graphManagerState.graphManager.serializeRawValueSpecification(
|
87
|
+
parameter,
|
88
|
+
),
|
89
|
+
),
|
90
|
+
relation.expressionSequence,
|
91
|
+
);
|
92
|
+
try {
|
93
|
+
const relationType =
|
94
|
+
await editorStore.graphManagerState.graphManager.getLambdaRelationType(
|
95
|
+
lambda,
|
96
|
+
editorStore.graphManagerState.graph,
|
97
|
+
);
|
98
|
+
relationType.columns.forEach((column) => {
|
99
|
+
const columnNode = getColumnTreeNodeData(column.name, column.type);
|
100
|
+
addUniqueEntry(rootIds, columnNode.id);
|
101
|
+
nodes.set(columnNode.id, columnNode);
|
102
|
+
});
|
103
|
+
} catch (error) {
|
104
|
+
assertErrorThrown(error);
|
105
|
+
editorStore.applicationStore.alertUnhandledError(error);
|
106
|
+
}
|
107
|
+
|
108
|
+
return { rootIds, nodes };
|
109
|
+
};
|
110
|
+
|
111
|
+
export class RelationTypeDragSource {
|
112
|
+
data: RelationColumnTypeTreeNodeData | undefined;
|
113
|
+
|
114
|
+
constructor(data: RelationColumnTypeTreeNodeData) {
|
115
|
+
this.data = data;
|
116
|
+
}
|
117
|
+
}
|
118
|
+
|
119
|
+
const RelationTypeTreeNodeContainer: React.FC<
|
120
|
+
TreeNodeContainerProps<
|
121
|
+
RelationColumnTypeTreeNodeData,
|
122
|
+
{ selectedType?: Type | undefined }
|
123
|
+
>
|
124
|
+
> = (props) => {
|
125
|
+
const { node, level, stepPaddingInRem, onNodeSelect } = props;
|
126
|
+
const [, dragConnector] = useDrag(
|
127
|
+
() => ({
|
128
|
+
type: CORE_DND_TYPE.PROJECT_EXPLORER_FUNCTION,
|
129
|
+
item: new RelationTypeDragSource(node),
|
130
|
+
}),
|
131
|
+
[node],
|
132
|
+
);
|
133
|
+
const ref = useRef<HTMLDivElement>(null);
|
134
|
+
dragConnector(ref);
|
135
|
+
|
136
|
+
const isExpandable = Boolean(node.childrenIds?.length);
|
137
|
+
const selectNode = (): void => onNodeSelect?.(node);
|
138
|
+
const nodeTypeIcon = renderColumnTypeIconFromType(node.columnType);
|
139
|
+
const nodeExpandIcon = isExpandable ? (
|
140
|
+
node.isOpen ? (
|
141
|
+
<ChevronDownIcon />
|
142
|
+
) : (
|
143
|
+
<ChevronRightIcon />
|
144
|
+
)
|
145
|
+
) : (
|
146
|
+
<div />
|
147
|
+
);
|
148
|
+
|
149
|
+
return (
|
150
|
+
<div
|
151
|
+
className="tree-view__node__container"
|
152
|
+
onClick={selectNode}
|
153
|
+
ref={ref}
|
154
|
+
style={{
|
155
|
+
paddingLeft: `${(level - 1) * (stepPaddingInRem ?? 1)}rem`,
|
156
|
+
display: 'flex',
|
157
|
+
}}
|
158
|
+
>
|
159
|
+
<div className="tree-view__node__icon">
|
160
|
+
<div className="tree-view__node__expand-icon">{nodeExpandIcon}</div>
|
161
|
+
<div className="type-tree__type-icon">{nodeTypeIcon}</div>
|
162
|
+
</div>
|
163
|
+
<div className="tree-view__node__label type-tree__node__label">
|
164
|
+
<button tabIndex={-1} title={`${node.id}`}>
|
165
|
+
{node.label}
|
166
|
+
</button>
|
167
|
+
{node instanceof RelationColumnTypeTreeNodeData && (
|
168
|
+
<div className="type-tree__node__type">
|
169
|
+
<button
|
170
|
+
className="type-tree__node__type__label"
|
171
|
+
// TODO: match type
|
172
|
+
// className={clsx('type-tree__node__type__label', {
|
173
|
+
// 'type-tree__node__type__label--highlighted':
|
174
|
+
// primitiveType && primitiveType === selectedType,
|
175
|
+
// })}
|
176
|
+
tabIndex={-1}
|
177
|
+
title="Column Type"
|
178
|
+
>
|
179
|
+
{node.columnType.split('::').pop()}
|
180
|
+
</button>
|
181
|
+
</div>
|
182
|
+
)}
|
183
|
+
</div>
|
184
|
+
</div>
|
185
|
+
);
|
186
|
+
};
|
187
|
+
|
188
|
+
export const RelationTypeTree: React.FC<{
|
189
|
+
relation: ConcreteFunctionDefinition;
|
190
|
+
editorStore: EditorStore;
|
191
|
+
selectedType?: Type | undefined;
|
192
|
+
}> = (props) => {
|
193
|
+
const { relation, selectedType, editorStore } = props;
|
194
|
+
// NOTE: We only need to compute this once so we use lazy initial state syntax
|
195
|
+
// See https://reactjs.org/docs/hooks-reference.html#lazy-initial-
|
196
|
+
const [treeData, setTreeData] = useState(
|
197
|
+
{} as TreeData<RelationColumnTypeTreeNodeData>,
|
198
|
+
);
|
199
|
+
const [loading, setLoading] = useState(false);
|
200
|
+
|
201
|
+
const onNodeSelect = (node: RelationColumnTypeTreeNodeData): void => {
|
202
|
+
//TODO: check for child nodes in this case
|
203
|
+
setTreeData({ ...treeData });
|
204
|
+
};
|
205
|
+
|
206
|
+
const getChildNodes = (
|
207
|
+
node: RelationColumnTypeTreeNodeData,
|
208
|
+
): RelationColumnTypeTreeNodeData[] => {
|
209
|
+
if (!node.childrenIds) {
|
210
|
+
return [];
|
211
|
+
}
|
212
|
+
const childrenNodes = node.childrenIds
|
213
|
+
.map((id) => treeData.nodes.get(id))
|
214
|
+
.filter(isNonNullable)
|
215
|
+
// sort so that column nodes come before join nodes
|
216
|
+
.sort((a, b) => a.label.localeCompare(b.label))
|
217
|
+
.sort(
|
218
|
+
(a, b) =>
|
219
|
+
(b instanceof RelationColumnTypeTreeNodeData ? 1 : 0) -
|
220
|
+
(a instanceof RelationColumnTypeTreeNodeData ? 1 : 0),
|
221
|
+
);
|
222
|
+
return childrenNodes;
|
223
|
+
};
|
224
|
+
|
225
|
+
useEffect(() => {
|
226
|
+
const fetchTypeTreeData = async () => {
|
227
|
+
try {
|
228
|
+
const response = await getRelationTypeTreeData(relation, editorStore);
|
229
|
+
setTreeData(response);
|
230
|
+
setLoading(true);
|
231
|
+
} catch (error) {
|
232
|
+
assertErrorThrown(error);
|
233
|
+
setLoading(false);
|
234
|
+
}
|
235
|
+
};
|
236
|
+
fetchTypeTreeData()
|
237
|
+
.then()
|
238
|
+
.catch((error) => assertErrorThrown(error));
|
239
|
+
}, [relation, editorStore]);
|
240
|
+
|
241
|
+
if (loading) {
|
242
|
+
return (
|
243
|
+
<TreeView
|
244
|
+
components={{
|
245
|
+
TreeNodeContainer: RelationTypeTreeNodeContainer,
|
246
|
+
}}
|
247
|
+
treeData={treeData}
|
248
|
+
getChildNodes={getChildNodes}
|
249
|
+
onNodeSelect={onNodeSelect}
|
250
|
+
innerProps={{
|
251
|
+
selectedType,
|
252
|
+
}}
|
253
|
+
/>
|
254
|
+
);
|
255
|
+
}
|
256
|
+
return <div></div>;
|
257
|
+
};
|
@@ -103,6 +103,7 @@ import {
|
|
103
103
|
ModelStore,
|
104
104
|
INTERNAL__UnknownSetImplementation,
|
105
105
|
RelationFunctionInstanceSetImplementation,
|
106
|
+
ConcreteFunctionDefinition,
|
106
107
|
} from '@finos/legend-graph';
|
107
108
|
import type {
|
108
109
|
DSL_Mapping_LegendStudioApplicationPlugin_Extension,
|
@@ -127,6 +128,8 @@ import { LambdaEditorState } from '@finos/legend-query-builder';
|
|
127
128
|
import type { MappingEditorTabState } from './MappingTabManagerState.js';
|
128
129
|
import { MappingTestableState } from './testable/MappingTestableState.js';
|
129
130
|
import { MappingTestMigrationState } from './legacy/MappingTestMigrationState.js';
|
131
|
+
import { relationFunction_setRelationFunction } from '../../../../graph-modifier/STO_RelationFunction_GraphModifierHelper.js';
|
132
|
+
import { RelationFunctionInstanceSetImplementationState } from './RelationFunctionInstanceSetImplementationState.js';
|
130
133
|
|
131
134
|
export interface MappingExplorerTreeNodeData extends TreeNodeData {
|
132
135
|
mappingElement: MappingElement;
|
@@ -312,12 +315,10 @@ export const getMappingElementSource = (
|
|
312
315
|
mappingElement.mainSetImplementation,
|
313
316
|
plugins,
|
314
317
|
);
|
315
|
-
}
|
316
|
-
// TODO: We could probably return the relation function used for the mapping here once we implement the form mode support for it
|
317
|
-
else if (
|
318
|
+
} else if (
|
318
319
|
mappingElement instanceof RelationFunctionInstanceSetImplementation
|
319
320
|
) {
|
320
|
-
return
|
321
|
+
return mappingElement.relationFunction;
|
321
322
|
}
|
322
323
|
const extraMappingElementSourceExtractors = plugins.flatMap(
|
323
324
|
(plugin) =>
|
@@ -907,12 +908,7 @@ export class MappingEditorState extends ElementEditorState {
|
|
907
908
|
);
|
908
909
|
return;
|
909
910
|
}
|
910
|
-
|
911
|
-
this.editorStore.applicationStore.notificationService.notifyUnsupportedFeature(
|
912
|
-
'Relation Function mapping editor',
|
913
|
-
);
|
914
|
-
return;
|
915
|
-
}
|
911
|
+
|
916
912
|
// Open mapping element from included mapping in another mapping editor tab
|
917
913
|
if (mappingElement._PARENT !== this.element) {
|
918
914
|
this.editorStore.graphEditorMode.openElement(mappingElement._PARENT);
|
@@ -1005,6 +1001,20 @@ export class MappingEditorState extends ElementEditorState {
|
|
1005
1001
|
rootRelationalSetImp_setMainTableAlias(setImplementation, newSource);
|
1006
1002
|
sourceUpdated = true;
|
1007
1003
|
}
|
1004
|
+
} else if (
|
1005
|
+
setImplementation instanceof RelationFunctionInstanceSetImplementation
|
1006
|
+
) {
|
1007
|
+
if (
|
1008
|
+
newSource instanceof ConcreteFunctionDefinition &&
|
1009
|
+
!getEmbeddedSetImplementations(setImplementation).length
|
1010
|
+
) {
|
1011
|
+
relationFunction_setRelationFunction(
|
1012
|
+
setImplementation,
|
1013
|
+
newSource,
|
1014
|
+
this.editorStore.changeDetectionState.observerContext,
|
1015
|
+
);
|
1016
|
+
sourceUpdated = true;
|
1017
|
+
}
|
1008
1018
|
} else {
|
1009
1019
|
const extraInstanceSetImplementationSourceUpdaters =
|
1010
1020
|
this.editorStore.pluginManager
|
@@ -1056,6 +1066,16 @@ export class MappingEditorState extends ElementEditorState {
|
|
1056
1066
|
);
|
1057
1067
|
newRootRelationalInstanceSetImplementation.mainTableAlias = newSource;
|
1058
1068
|
newSetImp = newRootRelationalInstanceSetImplementation;
|
1069
|
+
} else if (newSource instanceof ConcreteFunctionDefinition) {
|
1070
|
+
const relationFunctionSetImpl =
|
1071
|
+
new RelationFunctionInstanceSetImplementation(
|
1072
|
+
setImplementation.id,
|
1073
|
+
this.mapping,
|
1074
|
+
setImplementation.class,
|
1075
|
+
setImplementation.root,
|
1076
|
+
);
|
1077
|
+
relationFunctionSetImpl.relationFunction = newSource;
|
1078
|
+
newSetImp = relationFunctionSetImpl;
|
1059
1079
|
} else {
|
1060
1080
|
throw new UnsupportedOperationError(
|
1061
1081
|
`Can't use the specified class mapping source`,
|
@@ -1221,6 +1241,13 @@ export class MappingEditorState extends ElementEditorState {
|
|
1221
1241
|
this.editorStore,
|
1222
1242
|
mappingElement,
|
1223
1243
|
);
|
1244
|
+
} else if (
|
1245
|
+
mappingElement instanceof RelationFunctionInstanceSetImplementation
|
1246
|
+
) {
|
1247
|
+
return new RelationFunctionInstanceSetImplementationState(
|
1248
|
+
this.editorStore,
|
1249
|
+
mappingElement,
|
1250
|
+
);
|
1224
1251
|
}
|
1225
1252
|
const extraMappingElementStateCreators = this.editorStore.pluginManager
|
1226
1253
|
.getApplicationPlugins()
|
package/src/stores/editor/editor-state/element-editor-state/mapping/MappingElementDecorator.ts
CHANGED
@@ -37,6 +37,7 @@ import {
|
|
37
37
|
type InstanceSetImplementation,
|
38
38
|
type INTERNAL__UnresolvedSetImplementation,
|
39
39
|
type Mapping,
|
40
|
+
type RelationColumn,
|
40
41
|
getAllClassMappings,
|
41
42
|
PurePropertyMapping,
|
42
43
|
EmbeddedFlatDataPropertyMapping,
|
@@ -66,6 +67,7 @@ import {
|
|
66
67
|
SetImplementationExplicitReference,
|
67
68
|
type INTERNAL__UnknownSetImplementation,
|
68
69
|
type RelationFunctionInstanceSetImplementation,
|
70
|
+
RelationFunctionPropertyMapping,
|
69
71
|
} from '@finos/legend-graph';
|
70
72
|
import type { EditorStore } from '../../../EditorStore.js';
|
71
73
|
import {
|
@@ -79,6 +81,7 @@ import {
|
|
79
81
|
} from '../../../../graph-modifier/DSL_Mapping_GraphModifierHelper.js';
|
80
82
|
import { rootRelationalSetImp_setPropertyMappings } from '../../../../graph-modifier/STO_Relational_GraphModifierHelper.js';
|
81
83
|
import type { DSL_Mapping_LegendStudioApplicationPlugin_Extension } from '../../../../extensions/DSL_Mapping_LegendStudioApplicationPlugin_Extension.js';
|
84
|
+
import { isStubbed_RelationColumn } from '../../../../graph-modifier/STO_RelationFunction_GraphModifierHelper.js';
|
82
85
|
|
83
86
|
/**
|
84
87
|
* Iterate through all properties (including supertypes' properties) of the set implementation
|
@@ -662,7 +665,65 @@ export class MappingElementDecorator implements SetImplementationVisitor<void> {
|
|
662
665
|
visit_RelationFunctionInstanceSetImplementation(
|
663
666
|
setImplementation: RelationFunctionInstanceSetImplementation,
|
664
667
|
): void {
|
665
|
-
|
668
|
+
const decoratePropertyMapping = (
|
669
|
+
propertyMappings: RelationFunctionPropertyMapping[] | undefined,
|
670
|
+
property: Property,
|
671
|
+
): RelationFunctionPropertyMapping[] => {
|
672
|
+
const existingPropertyMappings = (propertyMappings ?? []).filter((pm) => {
|
673
|
+
if (pm instanceof RelationFunctionPropertyMapping) {
|
674
|
+
return !isStubbed_RelationColumn(pm.column);
|
675
|
+
}
|
676
|
+
return false;
|
677
|
+
});
|
678
|
+
const propertyType = property.genericType.value.rawType;
|
679
|
+
if (
|
680
|
+
propertyType instanceof PrimitiveType ||
|
681
|
+
propertyType instanceof Unit ||
|
682
|
+
propertyType instanceof Measure
|
683
|
+
) {
|
684
|
+
if (existingPropertyMappings.length) {
|
685
|
+
// TODO?: do we want to check the type of the property mapping here?
|
686
|
+
return existingPropertyMappings;
|
687
|
+
}
|
688
|
+
const newPropertyMapping = new RelationFunctionPropertyMapping(
|
689
|
+
setImplementation,
|
690
|
+
PropertyExplicitReference.create(property),
|
691
|
+
SetImplementationExplicitReference.create(setImplementation),
|
692
|
+
undefined,
|
693
|
+
{} as RelationColumn,
|
694
|
+
);
|
695
|
+
return [newPropertyMapping];
|
696
|
+
} else if (propertyType instanceof Enumeration) {
|
697
|
+
// TODO: add changes
|
698
|
+
} else if (propertyType instanceof Class) {
|
699
|
+
// TODO: add change
|
700
|
+
}
|
701
|
+
return [];
|
702
|
+
};
|
703
|
+
const propertyMappingsBeforeDecoration =
|
704
|
+
setImplementation.propertyMappings as RelationFunctionPropertyMapping[];
|
705
|
+
const decoratedPropertyMappings =
|
706
|
+
getDecoratedSetImplementationPropertyMappings<RelationFunctionPropertyMapping>(
|
707
|
+
setImplementation,
|
708
|
+
decoratePropertyMapping,
|
709
|
+
);
|
710
|
+
instanceSetImplementation_setPropertyMappings(
|
711
|
+
setImplementation,
|
712
|
+
decoratedPropertyMappings.concat(
|
713
|
+
// NOTE: here, we remove some low-quality property mappings
|
714
|
+
// i.e. stubbed property mappings from before adding new decorated property mappings
|
715
|
+
propertyMappingsBeforeDecoration
|
716
|
+
.filter(
|
717
|
+
(propertyMapping) =>
|
718
|
+
!isStubbed_RelationColumn(propertyMapping.column),
|
719
|
+
)
|
720
|
+
.filter(
|
721
|
+
(propertyMapping) =>
|
722
|
+
!decoratedPropertyMappings.includes(propertyMapping),
|
723
|
+
),
|
724
|
+
),
|
725
|
+
this.editorStore.changeDetectionState.observerContext,
|
726
|
+
);
|
666
727
|
}
|
667
728
|
}
|
668
729
|
|
@@ -814,6 +875,13 @@ export class MappingElementDecorationCleaner
|
|
814
875
|
visit_RelationFunctionInstanceSetImplementation(
|
815
876
|
setImplementation: RelationFunctionInstanceSetImplementation,
|
816
877
|
): void {
|
817
|
-
|
878
|
+
instanceSetImplementation_setPropertyMappings(
|
879
|
+
setImplementation,
|
880
|
+
setImplementation.propertyMappings.filter(
|
881
|
+
(propertyMapping) =>
|
882
|
+
propertyMapping instanceof RelationFunctionPropertyMapping,
|
883
|
+
),
|
884
|
+
this.editorStore.changeDetectionState.observerContext,
|
885
|
+
);
|
818
886
|
}
|
819
887
|
}
|