Skip to content

Commit 8336e04

Browse files
authored
DataProduct NativeModelAccess in studio graph and marketplace (#4755)
* DataProduct NativeModelAccess in studio graph and marketplace * Fix failing tests on undefined dp artifact
1 parent d7a1619 commit 8336e04

File tree

21 files changed

+1503
-20
lines changed

21 files changed

+1503
-20
lines changed

.changeset/cool-days-ask.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@finos/legend-lego': patch
3+
---
4+
5+
Add optional title to ModelDocumentationViewer

.changeset/floppy-games-bathe.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@finos/legend-graph': patch
3+
---
4+
5+
DataProduct NativeModelAccess in studio graph

.changeset/old-peas-walk.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@finos/legend-extension-dsl-diagram': patch
3+
---
4+
5+
Add optional title to DiagramViewer

.changeset/sharp-olives-knock.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@finos/legend-extension-dsl-data-product': patch
3+
---
4+
5+
DataProduct viewer - sampleQueries and model documentation
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
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 { observer } from 'mobx-react-lite';
18+
import { useRef, useEffect, useState } from 'react';
19+
import { ChevronDownIcon, ChevronRightIcon } from '@finos/legend-art';
20+
import type { DataProductViewerState } from '../../stores/DataProduct/DataProductViewerState.js';
21+
import { generateAnchorForSection } from '../../stores/ProductViewerNavigation.js';
22+
import { CodeEditor } from '@finos/legend-lego/code-editor';
23+
import {
24+
CODE_EDITOR_LANGUAGE,
25+
CODE_EDITOR_THEME,
26+
} from '@finos/legend-code-editor';
27+
import {
28+
V1_InLineSampleQueryInfo,
29+
V1_PackageableElementSampleQueryInfo,
30+
} from '@finos/legend-graph';
31+
import { useApplicationStore } from '@finos/legend-application';
32+
33+
const SampleQueryItem = observer(
34+
(props: {
35+
query: V1_InLineSampleQueryInfo | V1_PackageableElementSampleQueryInfo;
36+
}) => {
37+
const { query } = props;
38+
const applicationStore = useApplicationStore();
39+
const [isExpanded, setIsExpanded] = useState(false);
40+
const darkMode =
41+
!applicationStore.layoutService.TEMPORARY__isLightColorThemeEnabled;
42+
43+
const queryGrammar =
44+
query instanceof V1_InLineSampleQueryInfo
45+
? query.queryGrammar
46+
: undefined;
47+
48+
return (
49+
<div className="data-product__viewer__sample-query__item">
50+
<button
51+
className="data-product__viewer__sample-query__item__header"
52+
onClick={() => setIsExpanded(!isExpanded)}
53+
tabIndex={-1}
54+
>
55+
<div className="data-product__viewer__sample-query__item__header__icon">
56+
{isExpanded ? <ChevronDownIcon /> : <ChevronRightIcon />}
57+
</div>
58+
<div className="data-product__viewer__sample-query__item__header__content">
59+
<div className="data-product__viewer__sample-query__item__header__title">
60+
{query.title}
61+
</div>
62+
{query.description && (
63+
<div className="data-product__viewer__sample-query__item__header__description">
64+
{query.description}
65+
</div>
66+
)}
67+
</div>
68+
</button>
69+
{isExpanded && queryGrammar && (
70+
<div className="data-product__viewer__sample-query__item__content">
71+
<div className="data-product__viewer__sample-query__item__content__query">
72+
<CodeEditor
73+
language={CODE_EDITOR_LANGUAGE.PURE}
74+
inputValue={queryGrammar}
75+
isReadOnly={true}
76+
hideMinimap={true}
77+
hideGutter={true}
78+
lightTheme={
79+
darkMode
80+
? CODE_EDITOR_THEME.BUILT_IN__VSCODE_DARK
81+
: CODE_EDITOR_THEME.BUILT_IN__VSCODE_LIGHT
82+
}
83+
/>
84+
</div>
85+
</div>
86+
)}
87+
{isExpanded &&
88+
query instanceof V1_PackageableElementSampleQueryInfo && (
89+
<div className="data-product__viewer__sample-query__item__content">
90+
<div className="data-product__viewer__sample-query__item__content__info">
91+
Query Path: {query.queryPath}
92+
</div>
93+
</div>
94+
)}
95+
</div>
96+
);
97+
},
98+
);
99+
100+
export const DataProductSampleQueries = observer(
101+
(props: { dataProductViewerState: DataProductViewerState }) => {
102+
const { dataProductViewerState } = props;
103+
const sectionRef = useRef<HTMLDivElement>(null);
104+
const anchor = generateAnchorForSection('SAMPLE_QUERIES');
105+
106+
useEffect(() => {
107+
if (sectionRef.current) {
108+
dataProductViewerState.layoutState.setWikiPageAnchor(
109+
anchor,
110+
sectionRef.current,
111+
);
112+
}
113+
return () =>
114+
dataProductViewerState.layoutState.unsetWikiPageAnchor(anchor);
115+
}, [dataProductViewerState, anchor]);
116+
117+
if (dataProductViewerState.getSampleQueries().length === 0) {
118+
return null;
119+
}
120+
121+
return (
122+
<div
123+
ref={sectionRef}
124+
className="data-product__viewer__wiki__section data-product__viewer__sample-queries"
125+
>
126+
<div className="data-product__viewer__wiki__section__header">
127+
<div className="data-product__viewer__wiki__section__header__label">
128+
Sample Queries
129+
</div>
130+
</div>
131+
<div className="data-product__viewer__sample-queries__content">
132+
{dataProductViewerState.getSampleQueries().map((query) => {
133+
if (
134+
query instanceof V1_InLineSampleQueryInfo ||
135+
query instanceof V1_PackageableElementSampleQueryInfo
136+
) {
137+
return <SampleQueryItem key={query.id} query={query} />;
138+
}
139+
return null;
140+
})}
141+
</div>
142+
</div>
143+
);
144+
},
145+
);

packages/legend-extension-dsl-data-product/src/components/ProductWiki.tsx

Lines changed: 72 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ import { Chip, Stack } from '@mui/material';
4343
import { V1_ExternalDataProductType } from '@finos/legend-graph';
4444
import { prettyCONSTName } from '@finos/legend-shared';
4545
import { ModelsDocumentation } from '@finos/legend-lego/model-documentation';
46+
import { DataProductSampleQueries } from './DataProduct/DataProductSampleQueries.js';
4647
import { DiagramViewer } from '@finos/legend-extension-dsl-diagram';
4748

4849
export const ProductWikiPlaceholder: React.FC<{ message: string }> = (
@@ -248,16 +249,19 @@ export const ProductWiki = observer(
248249
(productDataAccessState instanceof DataProductDataAccessState ||
249250
productDataAccessState === undefined) && (
250251
<>
251-
<DataProducteDataAccess
252-
dataProductViewerState={productViewerState}
253-
dataProductDataAccessState={productDataAccessState}
254-
/>
252+
{productViewerState.product.accessPointGroups.length > 0 && (
253+
<DataProducteDataAccess
254+
dataProductViewerState={productViewerState}
255+
dataProductDataAccessState={productDataAccessState}
256+
/>
257+
)}
255258
{productViewerState.isVDP && (
256259
<ProductVendorInfo productViewerState={productViewerState} />
257260
)}
258261
{productViewerState.getModelAccessPointGroup() &&
259262
productViewerState.modelsDocumentationState && (
260263
<ModelsDocumentation
264+
title={'Model Access Point Group Model Documentation'}
261265
modelsDocumentationState={
262266
productViewerState.modelsDocumentationState
263267
}
@@ -266,8 +270,11 @@ export const ProductWiki = observer(
266270
)}
267271
{productViewerState.getModelAccessPointGroup() && (
268272
<DiagramViewer
273+
title={'Model Access Point Group Diagrams'}
269274
applicationStore={productViewerState.applicationStore}
270-
diagramViewerState={productViewerState.diagramViewerState}
275+
diagramViewerState={
276+
productViewerState.modelAccessPointGroupDiagramViewerState
277+
}
271278
actions={{
272279
onViewClassDocumentation: (classPath) =>
273280
productViewerState.modelsDocumentationState?.viewClassDocumentation(
@@ -305,6 +312,66 @@ export const ProductWiki = observer(
305312
}}
306313
/>
307314
)}
315+
{productViewerState.dataProductArtifact?.nativeModelAccess && (
316+
<>
317+
{productViewerState.nativeModelAccessDocumentationState && (
318+
<ModelsDocumentation
319+
title={'Native Model Access Model Documentation'}
320+
modelsDocumentationState={
321+
productViewerState.nativeModelAccessDocumentationState
322+
}
323+
applicationStore={productViewerState.applicationStore}
324+
/>
325+
)}
326+
{productViewerState.nativeModelAccessDiagramViewerState && (
327+
<DiagramViewer
328+
title={'Native Model Access Diagrams'}
329+
applicationStore={productViewerState.applicationStore}
330+
diagramViewerState={
331+
productViewerState.nativeModelAccessDiagramViewerState
332+
}
333+
actions={{
334+
onViewClassDocumentation: (classPath) =>
335+
productViewerState.nativeModelAccessDocumentationState?.viewClassDocumentation(
336+
classPath,
337+
),
338+
hasClassDocumentation: (classPath) =>
339+
productViewerState.nativeModelAccessDocumentationState?.hasClassDocumentation(
340+
classPath,
341+
) ?? false,
342+
onSyncZoneWithNavigation: (diagram) => {
343+
productViewerState.syncZoneWithNavigation(
344+
generateAnchorForDiagram(diagram),
345+
);
346+
},
347+
onGenerateAnchorForActivity: (activity) => {
348+
return generateAnchorForSection(activity);
349+
},
350+
onChangeZone: (zone, force) => {
351+
productViewerState.changeZone(zone, force);
352+
},
353+
onSetWikiPageAnchor: (
354+
anchorKey: string,
355+
element: HTMLElement,
356+
) => {
357+
productViewerState.layoutState.setWikiPageAnchor(
358+
anchorKey,
359+
element,
360+
);
361+
},
362+
onUnsetWikiPageAnchor: (anchorKey: string) => {
363+
productViewerState.layoutState.unsetWikiPageAnchor(
364+
anchorKey,
365+
);
366+
},
367+
}}
368+
/>
369+
)}
370+
<DataProductSampleQueries
371+
dataProductViewerState={productViewerState}
372+
/>
373+
</>
374+
)}
308375
<DataProductSupportInfo
309376
dataProductViewerState={productViewerState}
310377
/>

0 commit comments

Comments
 (0)