@finos/legend-application-studio 28.19.22 → 28.19.24
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/dataProduct/DataPoductEditor.d.ts.map +1 -1
- package/lib/components/editor/editor-group/dataProduct/DataPoductEditor.js +64 -15
- package/lib/components/editor/editor-group/dataProduct/DataPoductEditor.js.map +1 -1
- package/lib/index.css +2 -2
- package/lib/index.css.map +1 -1
- package/lib/package.json +1 -1
- package/lib/stores/editor/editor-state/element-editor-state/dataProduct/DataProductEditorState.d.ts +2 -0
- package/lib/stores/editor/editor-state/element-editor-state/dataProduct/DataProductEditorState.d.ts.map +1 -1
- package/lib/stores/editor/editor-state/element-editor-state/dataProduct/DataProductEditorState.js +6 -0
- package/lib/stores/editor/editor-state/element-editor-state/dataProduct/DataProductEditorState.js.map +1 -1
- package/lib/stores/graph-modifier/DSL_DataProduct_GraphModifierHelper.d.ts.map +1 -1
- package/lib/stores/graph-modifier/DSL_DataProduct_GraphModifierHelper.js +5 -5
- package/lib/stores/graph-modifier/DSL_DataProduct_GraphModifierHelper.js.map +1 -1
- package/package.json +7 -7
- package/src/components/editor/editor-group/dataProduct/DataPoductEditor.tsx +169 -18
- package/src/stores/editor/editor-state/element-editor-state/dataProduct/DataProductEditorState.ts +8 -0
- package/src/stores/graph-modifier/DSL_DataProduct_GraphModifierHelper.ts +12 -4
@@ -70,6 +70,7 @@ import {
|
|
70
70
|
EyeIcon,
|
71
71
|
CloseEyeIcon,
|
72
72
|
Checkbox,
|
73
|
+
BugIcon,
|
73
74
|
} from '@finos/legend-art';
|
74
75
|
import React, {
|
75
76
|
useRef,
|
@@ -90,6 +91,9 @@ import {
|
|
90
91
|
type DataProduct,
|
91
92
|
type LakehouseAccessPoint,
|
92
93
|
StereotypeExplicitReference,
|
94
|
+
type V1_DataProductArtifactAccessPointGroup,
|
95
|
+
type V1_DataProductArtifactAccessPointImplementation,
|
96
|
+
type V1_DataProductArtifactGeneration,
|
93
97
|
} from '@finos/legend-graph';
|
94
98
|
import {
|
95
99
|
accessPointGroup_setDescription,
|
@@ -162,6 +166,7 @@ const HoverTextArea: React.FC<HoverTextAreaProps> = ({
|
|
162
166
|
onMouseOver={handleMouseOver}
|
163
167
|
onMouseOut={handleMouseOut}
|
164
168
|
className={clsx(className)}
|
169
|
+
style={{ whiteSpace: 'pre-line' }}
|
165
170
|
>
|
166
171
|
{text}
|
167
172
|
</div>
|
@@ -190,7 +195,7 @@ const AccessPointTitle = observer(
|
|
190
195
|
};
|
191
196
|
const updateAccessPointName: React.ChangeEventHandler<HTMLTextAreaElement> =
|
192
197
|
action((event) => {
|
193
|
-
if (
|
198
|
+
if (event.target.value.match(/^[0-9a-zA-Z_]+$/)) {
|
194
199
|
accessPoint.id = event.target.value;
|
195
200
|
}
|
196
201
|
});
|
@@ -211,8 +216,13 @@ const AccessPointTitle = observer(
|
|
211
216
|
}}
|
212
217
|
/>
|
213
218
|
) : (
|
214
|
-
<div
|
215
|
-
|
219
|
+
<div
|
220
|
+
className="access-point-editor__name__label"
|
221
|
+
onClick={handleNameEdit}
|
222
|
+
title="Click to edit access point title"
|
223
|
+
style={{ flex: '1 1 auto' }}
|
224
|
+
>
|
225
|
+
{accessPoint.id}
|
216
226
|
</div>
|
217
227
|
);
|
218
228
|
},
|
@@ -225,7 +235,7 @@ const AccessPointClassification = observer(
|
|
225
235
|
}) => {
|
226
236
|
const { accessPoint, groupState } = props;
|
227
237
|
const applicationStore = useEditorStore().applicationStore;
|
228
|
-
const CHOOSE_CLASSIFICATION = '
|
238
|
+
const CHOOSE_CLASSIFICATION = 'Classification';
|
229
239
|
const updateAccessPointClassificationTextbox: React.ChangeEventHandler<HTMLTextAreaElement> =
|
230
240
|
action((event) => {
|
231
241
|
accessPoint.classification = event.target.value;
|
@@ -282,7 +292,15 @@ const AccessPointClassification = observer(
|
|
282
292
|
return (
|
283
293
|
<div className="access-point-editor__classification">
|
284
294
|
{classificationOptions.length > 1 ? (
|
285
|
-
<div
|
295
|
+
<div
|
296
|
+
style={{
|
297
|
+
borderWidth: 'thin',
|
298
|
+
borderColor:
|
299
|
+
currentClassification.label === CHOOSE_CLASSIFICATION
|
300
|
+
? 'var(--color-red-300)'
|
301
|
+
: 'transparent',
|
302
|
+
}}
|
303
|
+
>
|
286
304
|
<CustomSelectorInput
|
287
305
|
className="explorer__new-element-modal__driver__dropdown"
|
288
306
|
options={classificationOptions}
|
@@ -323,6 +341,62 @@ const AccessPointClassification = observer(
|
|
323
341
|
},
|
324
342
|
);
|
325
343
|
|
344
|
+
const AccessPointGenerationViewer = observer(
|
345
|
+
(props: {
|
346
|
+
accessPointState: LakehouseAccessPointState;
|
347
|
+
generationOutput: string;
|
348
|
+
}) => {
|
349
|
+
const { accessPointState, generationOutput } = props;
|
350
|
+
const editorStore = accessPointState.state.state.editorStore;
|
351
|
+
const closeDebug = (): void => {
|
352
|
+
accessPointState.setShowDebug(false);
|
353
|
+
};
|
354
|
+
|
355
|
+
return (
|
356
|
+
<Dialog
|
357
|
+
open={accessPointState.showDebug}
|
358
|
+
onClose={closeDebug}
|
359
|
+
classes={{
|
360
|
+
root: 'editor-modal__root-container',
|
361
|
+
container: 'editor-modal__container',
|
362
|
+
paper: 'editor-modal__content',
|
363
|
+
}}
|
364
|
+
>
|
365
|
+
<Modal
|
366
|
+
className="editor-modal"
|
367
|
+
darkMode={
|
368
|
+
!editorStore.applicationStore.layoutService
|
369
|
+
.TEMPORARY__isLightColorThemeEnabled
|
370
|
+
}
|
371
|
+
>
|
372
|
+
<ModalHeader
|
373
|
+
title={`${accessPointState.accessPoint.id} Plan Generation`}
|
374
|
+
/>
|
375
|
+
<ModalBody>
|
376
|
+
<div className="panel__content execution-plan-viewer__panel__content">
|
377
|
+
<CodeEditor
|
378
|
+
inputValue={generationOutput}
|
379
|
+
isReadOnly={true}
|
380
|
+
language={CODE_EDITOR_LANGUAGE.JSON}
|
381
|
+
hidePadding={true}
|
382
|
+
hideMinimap={true}
|
383
|
+
/>
|
384
|
+
</div>
|
385
|
+
</ModalBody>
|
386
|
+
<ModalFooter>
|
387
|
+
<ModalFooterButton
|
388
|
+
title="Close plan generation modal"
|
389
|
+
onClick={closeDebug}
|
390
|
+
text="Close"
|
391
|
+
type="secondary"
|
392
|
+
/>
|
393
|
+
</ModalFooter>
|
394
|
+
</Modal>
|
395
|
+
</Dialog>
|
396
|
+
);
|
397
|
+
},
|
398
|
+
);
|
399
|
+
|
326
400
|
export const LakehouseDataProductAcccessPointEditor = observer(
|
327
401
|
(props: {
|
328
402
|
accessPointState: LakehouseAccessPointState;
|
@@ -339,6 +413,7 @@ export const LakehouseDataProductAcccessPointEditor = observer(
|
|
339
413
|
const [editingDescription, setEditingDescription] = useState(false);
|
340
414
|
const [isHovering, setIsHovering] = useState(false);
|
341
415
|
const ref = useRef<HTMLDivElement>(null);
|
416
|
+
const [debugOutput, setDebugOutput] = useState('');
|
342
417
|
|
343
418
|
const handleDescriptionEdit = () => setEditingDescription(true);
|
344
419
|
const handleDescriptionBlur = () => {
|
@@ -361,6 +436,51 @@ export const LakehouseDataProductAcccessPointEditor = observer(
|
|
361
436
|
},
|
362
437
|
);
|
363
438
|
|
439
|
+
const debugPlanGeneration = async (): Promise<void> => {
|
440
|
+
try {
|
441
|
+
const generatedArtifacts =
|
442
|
+
await editorStore.graphManagerState.graphManager.generateArtifacts(
|
443
|
+
editorStore.graphManagerState.graph,
|
444
|
+
editorStore.graphEditorMode.getGraphTextInputOption(),
|
445
|
+
[groupState.state.elementPath],
|
446
|
+
);
|
447
|
+
const dataProductExtension = 'dataProduct';
|
448
|
+
const dataProductArtifact = generatedArtifacts.values.filter(
|
449
|
+
(artifact) => artifact.extension === dataProductExtension,
|
450
|
+
);
|
451
|
+
const dataProductContent =
|
452
|
+
dataProductArtifact[0]?.artifactsByExtensionElements[0]?.files[0]
|
453
|
+
?.content ?? null;
|
454
|
+
|
455
|
+
if (dataProductContent) {
|
456
|
+
const contentJson = JSON.parse(
|
457
|
+
dataProductContent,
|
458
|
+
) as V1_DataProductArtifactGeneration;
|
459
|
+
const apPlanGeneration = contentJson.accessPointGroups
|
460
|
+
.find(
|
461
|
+
(group: V1_DataProductArtifactAccessPointGroup) =>
|
462
|
+
group.id === groupState.value.id,
|
463
|
+
)
|
464
|
+
?.accessPointImplementations.find(
|
465
|
+
(
|
466
|
+
apImplementation: V1_DataProductArtifactAccessPointImplementation,
|
467
|
+
) => apImplementation.id === accessPoint.id,
|
468
|
+
);
|
469
|
+
|
470
|
+
setDebugOutput(JSON.stringify(apPlanGeneration, null, 2));
|
471
|
+
accessPointState.setShowDebug(true);
|
472
|
+
} else {
|
473
|
+
throw new Error(
|
474
|
+
'Could not find contents of this data product artifact',
|
475
|
+
);
|
476
|
+
}
|
477
|
+
} catch (error) {
|
478
|
+
editorStore.applicationStore.notificationService.notifyError(
|
479
|
+
`Failed to fetch access point plan generation: ${error}`,
|
480
|
+
);
|
481
|
+
}
|
482
|
+
};
|
483
|
+
|
364
484
|
const handleRemoveAccessPoint = (): void => {
|
365
485
|
editorStore.applicationStore.alertService.setActionAlertInfo({
|
366
486
|
message: `Are you sure you want to delete Access Point ${accessPoint.id}?`,
|
@@ -461,7 +581,19 @@ export const LakehouseDataProductAcccessPointEditor = observer(
|
|
461
581
|
style={{ padding: 0, margin: 0 }}
|
462
582
|
/>
|
463
583
|
<Tooltip
|
464
|
-
title=
|
584
|
+
title={
|
585
|
+
<div
|
586
|
+
style={{
|
587
|
+
maxWidth: '400px',
|
588
|
+
whiteSpace: 'normal',
|
589
|
+
wordWrap: 'break-word',
|
590
|
+
}}
|
591
|
+
>
|
592
|
+
Marking as "reproducible" means consumers can
|
593
|
+
consistently retrieve the exact historical data as it
|
594
|
+
existed at any specific Lakehouse batch.
|
595
|
+
</div>
|
596
|
+
}
|
465
597
|
arrow={true}
|
466
598
|
placement={'top'}
|
467
599
|
>
|
@@ -526,10 +658,11 @@ export const LakehouseDataProductAcccessPointEditor = observer(
|
|
526
658
|
placeholder="Access Point description"
|
527
659
|
onBlur={handleDescriptionBlur}
|
528
660
|
style={{
|
529
|
-
|
530
|
-
resize: 'none',
|
661
|
+
resize: 'vertical',
|
531
662
|
padding: '0.25rem',
|
532
663
|
marginLeft: '0.5rem',
|
664
|
+
marginTop: '0.5rem',
|
665
|
+
height: 'auto',
|
533
666
|
}}
|
534
667
|
/>
|
535
668
|
) : (
|
@@ -573,18 +706,36 @@ export const LakehouseDataProductAcccessPointEditor = observer(
|
|
573
706
|
</div>
|
574
707
|
</div>
|
575
708
|
<button
|
576
|
-
className="access-point-editor__generic-entry__remove-
|
709
|
+
className="access-point-editor__generic-entry__remove-btn__debug"
|
577
710
|
onClick={() => {
|
578
|
-
|
711
|
+
debugPlanGeneration().catch(
|
712
|
+
editorStore.applicationStore.alertUnhandledError,
|
713
|
+
);
|
579
714
|
}}
|
580
715
|
tabIndex={-1}
|
581
|
-
title="
|
716
|
+
title="AP Plan Generation"
|
582
717
|
>
|
583
|
-
<
|
718
|
+
<BugIcon />
|
584
719
|
</button>
|
585
720
|
</div>
|
586
721
|
</div>
|
587
722
|
</div>
|
723
|
+
<button
|
724
|
+
className="access-point-editor__generic-entry__remove-btn"
|
725
|
+
onClick={() => {
|
726
|
+
handleRemoveAccessPoint();
|
727
|
+
}}
|
728
|
+
tabIndex={-1}
|
729
|
+
title="Remove"
|
730
|
+
>
|
731
|
+
<TimesIcon />
|
732
|
+
</button>
|
733
|
+
{accessPointState.showDebug && (
|
734
|
+
<AccessPointGenerationViewer
|
735
|
+
accessPointState={accessPointState}
|
736
|
+
generationOutput={debugOutput}
|
737
|
+
/>
|
738
|
+
)}
|
588
739
|
</div>
|
589
740
|
</PanelDnDEntry>
|
590
741
|
);
|
@@ -724,7 +875,7 @@ const AccessPointGroupEditor = observer(
|
|
724
875
|
setIsHoveringName(false);
|
725
876
|
};
|
726
877
|
const updateGroupName = (val: string): void => {
|
727
|
-
if (val
|
878
|
+
if (val.match(/^[0-9a-zA-Z_]+$/)) {
|
728
879
|
accessPointGroup_setName(groupState.value, val);
|
729
880
|
}
|
730
881
|
};
|
@@ -821,8 +972,8 @@ const AccessPointGroupEditor = observer(
|
|
821
972
|
onBlur={handleDescriptionBlur}
|
822
973
|
style={{
|
823
974
|
overflow: 'hidden',
|
824
|
-
resize: 'none',
|
825
975
|
padding: '0.25rem',
|
976
|
+
height: 'auto',
|
826
977
|
}}
|
827
978
|
/>
|
828
979
|
) : (
|
@@ -1385,25 +1536,25 @@ const SupportTab = observer(
|
|
1385
1536
|
</div>
|
1386
1537
|
<PanelFormTextField
|
1387
1538
|
name="Documentation URL"
|
1388
|
-
value={product.supportInfo?.
|
1539
|
+
value={product.supportInfo?.documentation?.url ?? ''}
|
1389
1540
|
update={updateSupportInfoDocumentationUrl}
|
1390
1541
|
placeholder="Enter Documentation URL"
|
1391
1542
|
/>
|
1392
1543
|
<PanelFormTextField
|
1393
1544
|
name="Website"
|
1394
|
-
value={product.supportInfo?.website}
|
1545
|
+
value={product.supportInfo?.website?.url ?? ''}
|
1395
1546
|
update={updateSupportInfoWebsite}
|
1396
1547
|
placeholder="Enter Website"
|
1397
1548
|
/>
|
1398
1549
|
<PanelFormTextField
|
1399
1550
|
name="FAQ URL"
|
1400
|
-
value={product.supportInfo?.faqUrl}
|
1551
|
+
value={product.supportInfo?.faqUrl?.url}
|
1401
1552
|
update={updateSupportInfoFaqUrl}
|
1402
1553
|
placeholder="Enter FAQ URL"
|
1403
1554
|
/>
|
1404
1555
|
<PanelFormTextField
|
1405
1556
|
name="Support URL"
|
1406
|
-
value={product.supportInfo?.supportUrl}
|
1557
|
+
value={product.supportInfo?.supportUrl?.url ?? ''}
|
1407
1558
|
update={updateSupportInfoSupportUrl}
|
1408
1559
|
placeholder="Enter Support URL"
|
1409
1560
|
/>
|
package/src/stores/editor/editor-state/element-editor-state/dataProduct/DataProductEditorState.ts
CHANGED
@@ -214,14 +214,22 @@ export class LakehouseAccessPointState extends AccessPointState {
|
|
214
214
|
declare accessPoint: LakehouseAccessPoint;
|
215
215
|
lambdaState: AccessPointLambdaEditorState;
|
216
216
|
|
217
|
+
showDebug = false;
|
218
|
+
|
217
219
|
constructor(val: LakehouseAccessPoint, editorState: AccessPointGroupState) {
|
218
220
|
super(val, editorState);
|
219
221
|
makeObservable(this, {
|
220
222
|
lambdaState: observable,
|
223
|
+
showDebug: observable,
|
224
|
+
setShowDebug: action,
|
221
225
|
});
|
222
226
|
this.accessPoint = val;
|
223
227
|
this.lambdaState = new AccessPointLambdaEditorState(this);
|
224
228
|
}
|
229
|
+
|
230
|
+
setShowDebug(value: boolean): void {
|
231
|
+
this.showDebug = value;
|
232
|
+
}
|
225
233
|
}
|
226
234
|
|
227
235
|
export class AccessPointGroupState {
|
@@ -25,6 +25,8 @@ import {
|
|
25
25
|
observe_Email,
|
26
26
|
SupportInfo,
|
27
27
|
type LakehouseAccessPoint,
|
28
|
+
observer_DataProductLink,
|
29
|
+
DataProductLink,
|
28
30
|
} from '@finos/legend-graph';
|
29
31
|
import { addUniqueEntry, deleteEntry, swapEntry } from '@finos/legend-shared';
|
30
32
|
import { action } from 'mobx';
|
@@ -122,25 +124,31 @@ export const dataProduct_setSupportInfoIfAbsent = action(
|
|
122
124
|
|
123
125
|
export const supportInfo_setDocumentationUrl = action(
|
124
126
|
(supportInfo: SupportInfo, documentationUrl: string) => {
|
125
|
-
supportInfo.
|
127
|
+
supportInfo.documentation = observer_DataProductLink(
|
128
|
+
new DataProductLink(documentationUrl),
|
129
|
+
);
|
126
130
|
},
|
127
131
|
);
|
128
132
|
|
129
133
|
export const supportInfo_setWebsite = action(
|
130
134
|
(supportInfo: SupportInfo, website: string) => {
|
131
|
-
supportInfo.website =
|
135
|
+
supportInfo.website = observer_DataProductLink(
|
136
|
+
new DataProductLink(website),
|
137
|
+
);
|
132
138
|
},
|
133
139
|
);
|
134
140
|
|
135
141
|
export const supportInfo_setFaqUrl = action(
|
136
142
|
(supportInfo: SupportInfo, faqUrl: string) => {
|
137
|
-
supportInfo.faqUrl = faqUrl;
|
143
|
+
supportInfo.faqUrl = observer_DataProductLink(new DataProductLink(faqUrl));
|
138
144
|
},
|
139
145
|
);
|
140
146
|
|
141
147
|
export const supportInfo_setSupportUrl = action(
|
142
148
|
(supportInfo: SupportInfo, supportUrl: string) => {
|
143
|
-
supportInfo.supportUrl =
|
149
|
+
supportInfo.supportUrl = observer_DataProductLink(
|
150
|
+
new DataProductLink(supportUrl),
|
151
|
+
);
|
144
152
|
},
|
145
153
|
);
|
146
154
|
|