@finos/legend-extension-dsl-data-space 10.4.258 → 10.4.260
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/DataSpaceDescription.d.ts +5 -0
- package/lib/components/DataSpaceDescription.d.ts.map +1 -1
- package/lib/components/DataSpaceDescription.js +39 -0
- package/lib/components/DataSpaceDescription.js.map +1 -1
- package/lib/components/DataSpaceExecutionContextViewer.d.ts +1 -6
- package/lib/components/DataSpaceExecutionContextViewer.d.ts.map +1 -1
- package/lib/components/DataSpaceExecutionContextViewer.js +12 -16
- package/lib/components/DataSpaceExecutionContextViewer.js.map +1 -1
- package/lib/components/DataSpaceLakehouseAccess.d.ts +22 -0
- package/lib/components/DataSpaceLakehouseAccess.d.ts.map +1 -0
- package/lib/components/DataSpaceLakehouseAccess.js +127 -0
- package/lib/components/DataSpaceLakehouseAccess.js.map +1 -0
- package/lib/components/DataSpaceQuickStart.d.ts.map +1 -1
- package/lib/components/DataSpaceQuickStart.js +3 -2
- package/lib/components/DataSpaceQuickStart.js.map +1 -1
- package/lib/components/DataSpaceViewer.d.ts.map +1 -1
- package/lib/components/DataSpaceViewer.js +7 -13
- package/lib/components/DataSpaceViewer.js.map +1 -1
- package/lib/components/DataSpaceWiki.d.ts.map +1 -1
- package/lib/components/DataSpaceWiki.js +3 -2
- package/lib/components/DataSpaceWiki.js.map +1 -1
- package/lib/graph-manager/protocol/pure/v1/V1_DSL_DataSpace_PureGraphManagerExtension.js +2 -2
- package/lib/graph-manager/protocol/pure/v1/V1_DSL_DataSpace_PureGraphManagerExtension.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/DataSpaceLayoutState.d.ts.map +1 -1
- package/lib/stores/DataSpaceLayoutState.js +3 -3
- package/lib/stores/DataSpaceLayoutState.js.map +1 -1
- package/lib/stores/DataSpaceViewerNavigation.d.ts +1 -0
- package/lib/stores/DataSpaceViewerNavigation.d.ts.map +1 -1
- package/lib/stores/DataSpaceViewerNavigation.js +1 -0
- package/lib/stores/DataSpaceViewerNavigation.js.map +1 -1
- package/lib/stores/DataSpaceViewerState.d.ts +3 -0
- package/lib/stores/DataSpaceViewerState.d.ts.map +1 -1
- package/lib/stores/DataSpaceViewerState.js +28 -2
- package/lib/stores/DataSpaceViewerState.js.map +1 -1
- package/package.json +8 -8
- package/src/components/DataSpaceDescription.tsx +86 -0
- package/src/components/DataSpaceExecutionContextViewer.tsx +41 -44
- package/src/components/DataSpaceLakehouseAccess.tsx +449 -0
- package/src/components/DataSpaceQuickStart.tsx +22 -11
- package/src/components/DataSpaceViewer.tsx +2 -55
- package/src/components/DataSpaceWiki.tsx +7 -1
- package/src/graph-manager/protocol/pure/v1/V1_DSL_DataSpace_PureGraphManagerExtension.ts +2 -2
- package/src/stores/DataSpaceLayoutState.ts +5 -6
- package/src/stores/DataSpaceViewerNavigation.ts +1 -0
- package/src/stores/DataSpaceViewerState.ts +36 -2
- package/tsconfig.json +1 -0
|
@@ -0,0 +1,449 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026-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 { useEffect, useMemo, useRef, useState } from 'react';
|
|
19
|
+
import {
|
|
20
|
+
Button,
|
|
21
|
+
ButtonGroup,
|
|
22
|
+
IconButton,
|
|
23
|
+
Menu,
|
|
24
|
+
MenuItem,
|
|
25
|
+
Tooltip,
|
|
26
|
+
} from '@mui/material';
|
|
27
|
+
import {
|
|
28
|
+
CaretDownIcon,
|
|
29
|
+
ExpandMoreIcon,
|
|
30
|
+
RefreshIcon,
|
|
31
|
+
clsx,
|
|
32
|
+
} from '@finos/legend-art';
|
|
33
|
+
import {
|
|
34
|
+
extractElementNameFromPath,
|
|
35
|
+
type V1_AccessPointGroup,
|
|
36
|
+
} from '@finos/legend-graph';
|
|
37
|
+
import {
|
|
38
|
+
AccessPointGroupAccess,
|
|
39
|
+
CollapsibleWikiSection,
|
|
40
|
+
DataProductAPGAccessRequestControl,
|
|
41
|
+
EntitlementsDataContractCreator,
|
|
42
|
+
type DataProductAPGState,
|
|
43
|
+
} from '@finos/legend-extension-dsl-data-product';
|
|
44
|
+
import { type DataSpaceViewerState } from '../stores/DataSpaceViewerState.js';
|
|
45
|
+
import type { DataSpaceDataProductAccessState } from '../stores/DataSpaceDataProductAccessState.js';
|
|
46
|
+
import { DataSpaceMarkdownTextViewer } from './DataSpaceMarkdownTextViewer.js';
|
|
47
|
+
import { resolveOpenDataProductAction } from './DataSpaceExecutionContextViewer.js';
|
|
48
|
+
import {
|
|
49
|
+
DATA_SPACE_VIEWER_ACTIVITY_MODE,
|
|
50
|
+
generateAnchorForActivity,
|
|
51
|
+
} from '../stores/DataSpaceViewerNavigation.js';
|
|
52
|
+
|
|
53
|
+
const isEntitled = (access: AccessPointGroupAccess): boolean =>
|
|
54
|
+
access === AccessPointGroupAccess.APPROVED ||
|
|
55
|
+
access === AccessPointGroupAccess.ENTERPRISE;
|
|
56
|
+
|
|
57
|
+
const getBulkRequestTargetApgStates = (
|
|
58
|
+
accessState: DataSpaceDataProductAccessState,
|
|
59
|
+
): DataProductAPGState[] => {
|
|
60
|
+
const apgStates = accessState.dataProductViewerState?.apgStates ?? [];
|
|
61
|
+
return apgStates.filter((state) => !isEntitled(state.access));
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const getContractableApgStates = (
|
|
65
|
+
accessState: DataSpaceDataProductAccessState,
|
|
66
|
+
): DataProductAPGState[] => {
|
|
67
|
+
const apgStates = accessState.dataProductViewerState?.apgStates ?? [];
|
|
68
|
+
return apgStates.filter(
|
|
69
|
+
(state) => state.access !== AccessPointGroupAccess.ENTERPRISE,
|
|
70
|
+
);
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const DataSpaceLakehouseAccessRequestButton = observer(
|
|
74
|
+
(props: {
|
|
75
|
+
accessState: DataSpaceDataProductAccessState;
|
|
76
|
+
onRequestForSelf: () => void;
|
|
77
|
+
onRequestForOthers: () => void;
|
|
78
|
+
}) => {
|
|
79
|
+
const { accessState, onRequestForSelf, onRequestForOthers } = props;
|
|
80
|
+
const buttonGroupRef = useRef<HTMLDivElement>(null);
|
|
81
|
+
const [isMenuOpen, setIsMenuOpen] = useState<boolean>(false);
|
|
82
|
+
const apgStates = accessState.dataProductViewerState?.apgStates;
|
|
83
|
+
if (!apgStates || apgStates.length === 0) {
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
const total = apgStates.length;
|
|
87
|
+
const entitled = apgStates.filter((state) =>
|
|
88
|
+
isEntitled(state.access),
|
|
89
|
+
).length;
|
|
90
|
+
const pending = apgStates.filter(
|
|
91
|
+
(state) =>
|
|
92
|
+
state.access === AccessPointGroupAccess.SUBMITTED_FOR_APPROVALS ||
|
|
93
|
+
state.access === AccessPointGroupAccess.PENDING_MANAGER_APPROVAL ||
|
|
94
|
+
state.access === AccessPointGroupAccess.PENDING_DATA_OWNER_APPROVAL,
|
|
95
|
+
).length;
|
|
96
|
+
const hasAllAccess = entitled >= total;
|
|
97
|
+
const requestableTargets = getBulkRequestTargetApgStates(accessState);
|
|
98
|
+
const primaryDisabled = hasAllAccess || requestableTargets.length === 0;
|
|
99
|
+
const forOthersTargets = getContractableApgStates(accessState);
|
|
100
|
+
const showForOthers = forOthersTargets.length > 0;
|
|
101
|
+
const primaryTooltip = hasAllAccess
|
|
102
|
+
? `You have access to all ${total} Access Point Group${total === 1 ? '' : 's'} under this Data Product required to access this DataSpace.`
|
|
103
|
+
: `Request access to the Access Point Groups under this Data Product required to access this DataSpace. ${entitled} of ${total} granted${pending > 0 ? `, ${pending} pending approval` : ''}.`;
|
|
104
|
+
return (
|
|
105
|
+
<>
|
|
106
|
+
<ButtonGroup
|
|
107
|
+
variant="contained"
|
|
108
|
+
color={hasAllAccess ? 'success' : 'primary'}
|
|
109
|
+
ref={buttonGroupRef}
|
|
110
|
+
className="data-space__viewer__lakehouse-access__group__request-btn"
|
|
111
|
+
>
|
|
112
|
+
<Tooltip title={primaryTooltip} arrow={true}>
|
|
113
|
+
<span>
|
|
114
|
+
<Button
|
|
115
|
+
disabled={!hasAllAccess && primaryDisabled}
|
|
116
|
+
onClick={hasAllAccess ? undefined : onRequestForSelf}
|
|
117
|
+
sx={{
|
|
118
|
+
height: '100%',
|
|
119
|
+
cursor: hasAllAccess ? 'default' : undefined,
|
|
120
|
+
borderTopRightRadius: showForOthers ? 0 : undefined,
|
|
121
|
+
borderBottomRightRadius: showForOthers ? 0 : undefined,
|
|
122
|
+
}}
|
|
123
|
+
>
|
|
124
|
+
{hasAllAccess
|
|
125
|
+
? 'Access Granted'
|
|
126
|
+
: `Request Access (${entitled} / ${total})`}
|
|
127
|
+
</Button>
|
|
128
|
+
</span>
|
|
129
|
+
</Tooltip>
|
|
130
|
+
{showForOthers && (
|
|
131
|
+
<Button
|
|
132
|
+
size="small"
|
|
133
|
+
onClick={() => setIsMenuOpen((prev) => !prev)}
|
|
134
|
+
title="More options"
|
|
135
|
+
>
|
|
136
|
+
<CaretDownIcon />
|
|
137
|
+
</Button>
|
|
138
|
+
)}
|
|
139
|
+
</ButtonGroup>
|
|
140
|
+
{showForOthers && (
|
|
141
|
+
<Menu
|
|
142
|
+
anchorEl={buttonGroupRef.current}
|
|
143
|
+
open={isMenuOpen}
|
|
144
|
+
onClose={() => setIsMenuOpen(false)}
|
|
145
|
+
>
|
|
146
|
+
<MenuItem
|
|
147
|
+
onClick={() => {
|
|
148
|
+
onRequestForOthers();
|
|
149
|
+
setIsMenuOpen(false);
|
|
150
|
+
}}
|
|
151
|
+
>
|
|
152
|
+
Request Access for Others
|
|
153
|
+
</MenuItem>
|
|
154
|
+
</Menu>
|
|
155
|
+
)}
|
|
156
|
+
</>
|
|
157
|
+
);
|
|
158
|
+
},
|
|
159
|
+
);
|
|
160
|
+
|
|
161
|
+
const DataSpaceLakehouseAccessGroup = observer(
|
|
162
|
+
(props: {
|
|
163
|
+
viewerState: DataSpaceViewerState;
|
|
164
|
+
dataProductPath: string;
|
|
165
|
+
initiallyCollapsed: boolean;
|
|
166
|
+
}) => {
|
|
167
|
+
const { viewerState, dataProductPath, initiallyCollapsed } = props;
|
|
168
|
+
const [isCollapsed, setIsCollapsed] = useState<boolean>(initiallyCollapsed);
|
|
169
|
+
const [bulkRequestMode, setBulkRequestMode] = useState<
|
|
170
|
+
'self' | 'others' | undefined
|
|
171
|
+
>(undefined);
|
|
172
|
+
const accessState = viewerState.getDataProductAccessState(dataProductPath);
|
|
173
|
+
const isReadOnly = accessState === undefined;
|
|
174
|
+
const readOnlyApgIds: string[] = useMemo(() => {
|
|
175
|
+
if (!isReadOnly) {
|
|
176
|
+
return [];
|
|
177
|
+
}
|
|
178
|
+
const dp =
|
|
179
|
+
viewerState.graphManagerState.graph.getOwnNullableDataProduct(
|
|
180
|
+
dataProductPath,
|
|
181
|
+
);
|
|
182
|
+
return dp?.accessPointGroups.map((group) => group.id) ?? [];
|
|
183
|
+
}, [dataProductPath, isReadOnly, viewerState.graphManagerState.graph]);
|
|
184
|
+
const tokenProvider =
|
|
185
|
+
viewerState.mappingProviderAccessConfig?.tokenProvider ??
|
|
186
|
+
((): undefined => undefined);
|
|
187
|
+
const apgStates = accessState?.dataProductViewerState?.apgStates ?? [];
|
|
188
|
+
const isLoading = accessState?.initializingState.isInProgress ?? false;
|
|
189
|
+
const hasError =
|
|
190
|
+
accessState?.errorMessage !== undefined && apgStates.length === 0;
|
|
191
|
+
const displayedCount = isReadOnly
|
|
192
|
+
? readOnlyApgIds.length
|
|
193
|
+
: apgStates.length;
|
|
194
|
+
|
|
195
|
+
const bulkTargetApgStates = accessState
|
|
196
|
+
? bulkRequestMode === 'others'
|
|
197
|
+
? getContractableApgStates(accessState)
|
|
198
|
+
: getBulkRequestTargetApgStates(accessState)
|
|
199
|
+
: [];
|
|
200
|
+
const bulkTargetApgs: V1_AccessPointGroup[] = bulkTargetApgStates.map(
|
|
201
|
+
(state) => state.apg,
|
|
202
|
+
);
|
|
203
|
+
|
|
204
|
+
const representativeApgState: DataProductAPGState | undefined =
|
|
205
|
+
bulkTargetApgStates[0];
|
|
206
|
+
|
|
207
|
+
const onOpenDataProduct = resolveOpenDataProductAction(
|
|
208
|
+
viewerState,
|
|
209
|
+
dataProductPath,
|
|
210
|
+
);
|
|
211
|
+
|
|
212
|
+
return (
|
|
213
|
+
<div className="data-space__viewer__lakehouse-access__group">
|
|
214
|
+
<div className="data-space__viewer__lakehouse-access__group__header-row">
|
|
215
|
+
<button
|
|
216
|
+
className="data-space__viewer__lakehouse-access__group__caret-btn"
|
|
217
|
+
tabIndex={-1}
|
|
218
|
+
onClick={(): void => setIsCollapsed((prev) => !prev)}
|
|
219
|
+
title={isCollapsed ? 'Expand' : 'Collapse'}
|
|
220
|
+
>
|
|
221
|
+
<ExpandMoreIcon
|
|
222
|
+
className={clsx(
|
|
223
|
+
'data-space__viewer__lakehouse-access__group__caret',
|
|
224
|
+
{
|
|
225
|
+
'data-space__viewer__lakehouse-access__group__caret--collapsed':
|
|
226
|
+
isCollapsed,
|
|
227
|
+
},
|
|
228
|
+
)}
|
|
229
|
+
/>
|
|
230
|
+
</button>
|
|
231
|
+
<div className="data-space__viewer__lakehouse-access__group__header">
|
|
232
|
+
{onOpenDataProduct ? (
|
|
233
|
+
<button
|
|
234
|
+
type="button"
|
|
235
|
+
className="data-space__viewer__lakehouse-access__group__label data-space__viewer__lakehouse-access__group__label--clickable"
|
|
236
|
+
title={`Open Data Product: ${dataProductPath}`}
|
|
237
|
+
onClick={onOpenDataProduct}
|
|
238
|
+
>
|
|
239
|
+
{extractElementNameFromPath(dataProductPath)}
|
|
240
|
+
</button>
|
|
241
|
+
) : (
|
|
242
|
+
<span
|
|
243
|
+
className="data-space__viewer__lakehouse-access__group__label"
|
|
244
|
+
title={dataProductPath}
|
|
245
|
+
>
|
|
246
|
+
{extractElementNameFromPath(dataProductPath)}
|
|
247
|
+
</span>
|
|
248
|
+
)}
|
|
249
|
+
<span className="data-space__viewer__lakehouse-access__group__count">
|
|
250
|
+
{displayedCount}
|
|
251
|
+
</span>
|
|
252
|
+
</div>
|
|
253
|
+
{!isReadOnly && (
|
|
254
|
+
<div className="data-space__viewer__lakehouse-access__group__actions">
|
|
255
|
+
{!hasError && (
|
|
256
|
+
<DataSpaceLakehouseAccessRequestButton
|
|
257
|
+
accessState={accessState}
|
|
258
|
+
onRequestForSelf={(): void => setBulkRequestMode('self')}
|
|
259
|
+
onRequestForOthers={(): void => setBulkRequestMode('others')}
|
|
260
|
+
/>
|
|
261
|
+
)}
|
|
262
|
+
<IconButton
|
|
263
|
+
className="data-space__viewer__lakehouse-access__group__refresh-btn"
|
|
264
|
+
size="small"
|
|
265
|
+
color="primary"
|
|
266
|
+
title="Refresh Data Product access"
|
|
267
|
+
disabled={accessState.initializingState.isInProgress}
|
|
268
|
+
onClick={(): void =>
|
|
269
|
+
viewerState.refreshDataProductAccessState(dataProductPath)
|
|
270
|
+
}
|
|
271
|
+
>
|
|
272
|
+
<RefreshIcon />
|
|
273
|
+
</IconButton>
|
|
274
|
+
</div>
|
|
275
|
+
)}
|
|
276
|
+
</div>
|
|
277
|
+
{!isCollapsed && (
|
|
278
|
+
<div className="data-space__viewer__lakehouse-access__group__rows">
|
|
279
|
+
{isReadOnly ? (
|
|
280
|
+
readOnlyApgIds.length === 0 ? (
|
|
281
|
+
<div className="data-space__viewer__lakehouse-access__row">
|
|
282
|
+
<span className="data-space__viewer__lakehouse-access__row__unavailable">
|
|
283
|
+
Data Product is not available in the local project — Access
|
|
284
|
+
Point Groups cannot be listed in preview.
|
|
285
|
+
</span>
|
|
286
|
+
</div>
|
|
287
|
+
) : (
|
|
288
|
+
readOnlyApgIds.map((apgId) => (
|
|
289
|
+
<div
|
|
290
|
+
key={apgId}
|
|
291
|
+
className="data-space__viewer__lakehouse-access__row"
|
|
292
|
+
>
|
|
293
|
+
<span
|
|
294
|
+
className="data-space__viewer__lakehouse-access__row__apg"
|
|
295
|
+
title={apgId}
|
|
296
|
+
>
|
|
297
|
+
{apgId}
|
|
298
|
+
</span>
|
|
299
|
+
</div>
|
|
300
|
+
))
|
|
301
|
+
)
|
|
302
|
+
) : hasError ? (
|
|
303
|
+
<div
|
|
304
|
+
className="data-space__viewer__lakehouse-access__row"
|
|
305
|
+
title={accessState.errorMessage}
|
|
306
|
+
>
|
|
307
|
+
<span className="data-space__viewer__lakehouse-access__row__unavailable">
|
|
308
|
+
Unavailable
|
|
309
|
+
</span>
|
|
310
|
+
</div>
|
|
311
|
+
) : isLoading && apgStates.length === 0 ? (
|
|
312
|
+
<div className="data-space__viewer__lakehouse-access__row">
|
|
313
|
+
<span className="data-space__viewer__lakehouse-access__row__loading">
|
|
314
|
+
Loading...
|
|
315
|
+
</span>
|
|
316
|
+
</div>
|
|
317
|
+
) : (
|
|
318
|
+
apgStates.map((apgState) => (
|
|
319
|
+
<div
|
|
320
|
+
key={apgState.apg.id}
|
|
321
|
+
className="data-space__viewer__lakehouse-access__row"
|
|
322
|
+
>
|
|
323
|
+
<span
|
|
324
|
+
className="data-space__viewer__lakehouse-access__row__apg"
|
|
325
|
+
title={apgState.apg.id}
|
|
326
|
+
>
|
|
327
|
+
{apgState.apg.id}
|
|
328
|
+
</span>
|
|
329
|
+
<div className="data-space__viewer__lakehouse-access__row__actions">
|
|
330
|
+
{accessState.dataAccessState && (
|
|
331
|
+
<DataProductAPGAccessRequestControl
|
|
332
|
+
apgState={apgState}
|
|
333
|
+
dataAccessState={accessState.dataAccessState}
|
|
334
|
+
tokenProvider={tokenProvider}
|
|
335
|
+
/>
|
|
336
|
+
)}
|
|
337
|
+
</div>
|
|
338
|
+
</div>
|
|
339
|
+
))
|
|
340
|
+
)}
|
|
341
|
+
</div>
|
|
342
|
+
)}
|
|
343
|
+
{bulkRequestMode !== undefined &&
|
|
344
|
+
accessState?.dataAccessState &&
|
|
345
|
+
representativeApgState &&
|
|
346
|
+
bulkTargetApgs.length > 0 && (
|
|
347
|
+
<EntitlementsDataContractCreator
|
|
348
|
+
open={true}
|
|
349
|
+
onClose={(): void => setBulkRequestMode(undefined)}
|
|
350
|
+
tokenProvider={tokenProvider}
|
|
351
|
+
apgState={representativeApgState}
|
|
352
|
+
dataAccessState={accessState.dataAccessState}
|
|
353
|
+
overrideTargetApgs={bulkTargetApgs}
|
|
354
|
+
headerContent={
|
|
355
|
+
<>
|
|
356
|
+
Submit access request for{' '}
|
|
357
|
+
<span className="marketplace-lakehouse-text__emphasis">
|
|
358
|
+
{bulkTargetApgs.length}
|
|
359
|
+
</span>{' '}
|
|
360
|
+
Access Point Group
|
|
361
|
+
{bulkTargetApgs.length === 1 ? '' : 's'} in{' '}
|
|
362
|
+
<span className="marketplace-lakehouse-text__emphasis">
|
|
363
|
+
{accessState.dataAccessState.dataProductViewerState.product
|
|
364
|
+
.title ?? extractElementNameFromPath(dataProductPath)}
|
|
365
|
+
</span>{' '}
|
|
366
|
+
Data Product
|
|
367
|
+
</>
|
|
368
|
+
}
|
|
369
|
+
/>
|
|
370
|
+
)}
|
|
371
|
+
</div>
|
|
372
|
+
);
|
|
373
|
+
},
|
|
374
|
+
);
|
|
375
|
+
|
|
376
|
+
const DataSpaceLakehouseAccessPanel = observer(
|
|
377
|
+
(props: {
|
|
378
|
+
viewerState: DataSpaceViewerState;
|
|
379
|
+
dataProductPaths: string[];
|
|
380
|
+
}) => {
|
|
381
|
+
const { viewerState, dataProductPaths } = props;
|
|
382
|
+
return (
|
|
383
|
+
<>
|
|
384
|
+
<div className="data-space__viewer__lakehouse-access__description">
|
|
385
|
+
<DataSpaceMarkdownTextViewer
|
|
386
|
+
value={
|
|
387
|
+
"The following Data Products are required to access this DataSpace. Products you don't have access to can be requested below."
|
|
388
|
+
}
|
|
389
|
+
/>
|
|
390
|
+
</div>
|
|
391
|
+
<div className="data-space__viewer__lakehouse-access">
|
|
392
|
+
<div className="data-space__viewer__lakehouse-access__header">
|
|
393
|
+
Data Product Access
|
|
394
|
+
</div>
|
|
395
|
+
{dataProductPaths.map((dataProductPath) => (
|
|
396
|
+
<DataSpaceLakehouseAccessGroup
|
|
397
|
+
key={dataProductPath}
|
|
398
|
+
viewerState={viewerState}
|
|
399
|
+
dataProductPath={dataProductPath}
|
|
400
|
+
initiallyCollapsed={true}
|
|
401
|
+
/>
|
|
402
|
+
))}
|
|
403
|
+
</div>
|
|
404
|
+
</>
|
|
405
|
+
);
|
|
406
|
+
},
|
|
407
|
+
);
|
|
408
|
+
|
|
409
|
+
export const DataSpaceLakehouseAccess = observer(
|
|
410
|
+
(props: { dataSpaceViewerState: DataSpaceViewerState }) => {
|
|
411
|
+
const { dataSpaceViewerState } = props;
|
|
412
|
+
const sectionRef = useRef<HTMLDivElement>(null);
|
|
413
|
+
const anchor = generateAnchorForActivity(
|
|
414
|
+
DATA_SPACE_VIEWER_ACTIVITY_MODE.DATASPACE_LAKEHOUSE_ACCESS,
|
|
415
|
+
);
|
|
416
|
+
|
|
417
|
+
useEffect(() => {
|
|
418
|
+
if (sectionRef.current) {
|
|
419
|
+
dataSpaceViewerState.layoutState.setWikiPageAnchor(
|
|
420
|
+
anchor,
|
|
421
|
+
sectionRef.current,
|
|
422
|
+
);
|
|
423
|
+
}
|
|
424
|
+
return () => dataSpaceViewerState.layoutState.unsetWikiPageAnchor(anchor);
|
|
425
|
+
}, [dataSpaceViewerState, anchor]);
|
|
426
|
+
|
|
427
|
+
const dataProductPaths = dataSpaceViewerState.referencedDataProductPaths;
|
|
428
|
+
|
|
429
|
+
if (dataProductPaths.length === 0) {
|
|
430
|
+
return null;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
return (
|
|
434
|
+
<div ref={sectionRef} className="viewer__wiki__section">
|
|
435
|
+
<CollapsibleWikiSection
|
|
436
|
+
viewerState={dataSpaceViewerState}
|
|
437
|
+
section={DATA_SPACE_VIEWER_ACTIVITY_MODE.DATASPACE_LAKEHOUSE_ACCESS}
|
|
438
|
+
>
|
|
439
|
+
<div className="viewer__wiki__section__content">
|
|
440
|
+
<DataSpaceLakehouseAccessPanel
|
|
441
|
+
viewerState={dataSpaceViewerState}
|
|
442
|
+
dataProductPaths={dataProductPaths}
|
|
443
|
+
/>
|
|
444
|
+
</div>
|
|
445
|
+
</CollapsibleWikiSection>
|
|
446
|
+
</div>
|
|
447
|
+
);
|
|
448
|
+
},
|
|
449
|
+
);
|
|
@@ -46,7 +46,7 @@ import {
|
|
|
46
46
|
LakehouseDataProductExecutableAccessorInfo,
|
|
47
47
|
} from '../graph-manager/action/analytics/DataSpaceAnalysis.js';
|
|
48
48
|
import { DataSpaceMarkdownTextViewer } from './DataSpaceMarkdownTextViewer.js';
|
|
49
|
-
import {
|
|
49
|
+
import { resolveOpenDataProductAction } from './DataSpaceExecutionContextViewer.js';
|
|
50
50
|
import type { DSL_DataSpace_LegendApplicationPlugin_Extension } from '../stores/DSL_DataSpace_LegendApplicationPlugin_Extension.js';
|
|
51
51
|
import { useEffect, useRef, useState } from 'react';
|
|
52
52
|
import { DataSpaceWikiPlaceholder } from './DataSpacePlaceholder.js';
|
|
@@ -227,6 +227,10 @@ const DataSpaceDataProductAccessPanel = observer(
|
|
|
227
227
|
const accessState = viewerState.getDataProductAccessState(
|
|
228
228
|
group.dataProductPath,
|
|
229
229
|
);
|
|
230
|
+
const onOpenDataProduct = resolveOpenDataProductAction(
|
|
231
|
+
viewerState,
|
|
232
|
+
group.dataProductPath,
|
|
233
|
+
);
|
|
230
234
|
return (
|
|
231
235
|
<div
|
|
232
236
|
key={group.dataProductPath}
|
|
@@ -250,21 +254,28 @@ const DataSpaceDataProductAccessPanel = observer(
|
|
|
250
254
|
/>
|
|
251
255
|
</button>
|
|
252
256
|
<div className="data-space__viewer__quickstart__tds__apg-access__group__header">
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
257
|
+
{onOpenDataProduct ? (
|
|
258
|
+
<button
|
|
259
|
+
type="button"
|
|
260
|
+
className="data-space__viewer__quickstart__tds__apg-access__group__label data-space__viewer__quickstart__tds__apg-access__group__label--clickable"
|
|
261
|
+
title={`Open Data Product: ${group.dataProductPath}`}
|
|
262
|
+
onClick={onOpenDataProduct}
|
|
263
|
+
>
|
|
264
|
+
{extractElementNameFromPath(group.dataProductPath)}
|
|
265
|
+
</button>
|
|
266
|
+
) : (
|
|
267
|
+
<span
|
|
268
|
+
className="data-space__viewer__quickstart__tds__apg-access__group__label"
|
|
269
|
+
title={group.dataProductPath}
|
|
270
|
+
>
|
|
271
|
+
{extractElementNameFromPath(group.dataProductPath)}
|
|
272
|
+
</span>
|
|
273
|
+
)}
|
|
259
274
|
<span className="data-space__viewer__quickstart__tds__apg-access__group__count">
|
|
260
275
|
{group.accessPointGroupIds.length}
|
|
261
276
|
</span>
|
|
262
277
|
</div>
|
|
263
278
|
<div className="data-space__viewer__quickstart__tds__apg-access__group__actions">
|
|
264
|
-
<DataSpaceOpenDataProductButton
|
|
265
|
-
dataSpaceViewerState={viewerState}
|
|
266
|
-
dataProductPath={group.dataProductPath}
|
|
267
|
-
/>
|
|
268
279
|
{accessState && (
|
|
269
280
|
<IconButton
|
|
270
281
|
className="data-space__viewer__quickstart__tds__apg-access__group__refresh-btn"
|
|
@@ -20,7 +20,6 @@ import {
|
|
|
20
20
|
CaretUpIcon,
|
|
21
21
|
ControlledDropdownMenu,
|
|
22
22
|
MenuContent,
|
|
23
|
-
MenuContentDivider,
|
|
24
23
|
MenuContentItem,
|
|
25
24
|
MoreVerticalIcon,
|
|
26
25
|
PlayIcon,
|
|
@@ -36,15 +35,11 @@ import { DataSpaceWiki } from './DataSpaceWiki.js';
|
|
|
36
35
|
import { DataSpaceViewerActivityBar } from './DataSpaceViewerActivityBar.js';
|
|
37
36
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
38
37
|
import { DATA_SPACE_WIKI_PAGE_SECTIONS } from '../stores/DataSpaceLayoutState.js';
|
|
39
|
-
import {
|
|
40
|
-
DATA_SPACE_VIEWER_ACTIVITY_MODE,
|
|
41
|
-
generateAnchorForActivity,
|
|
42
|
-
} from '../stores/DataSpaceViewerNavigation.js';
|
|
38
|
+
import { DATA_SPACE_VIEWER_ACTIVITY_MODE } from '../stores/DataSpaceViewerNavigation.js';
|
|
43
39
|
import { DataSpacePlaceholderPanel } from './DataSpacePlaceholder.js';
|
|
44
40
|
import { useApplicationStore } from '@finos/legend-application';
|
|
45
41
|
import { DataSpaceLegendAIIntegration } from './DataSpaceLegendAIIntegration.js';
|
|
46
42
|
import { DSL_DATASPACE_EVENT } from '../__lib__/DSL_DataSpace_Event.js';
|
|
47
|
-
import { guaranteeNonNullable } from '@finos/legend-shared';
|
|
48
43
|
import { DataSpaceQualityEmote } from './DataSpaceQualityEmote.js';
|
|
49
44
|
|
|
50
45
|
const DataSpaceHeader = observer(
|
|
@@ -194,29 +189,6 @@ const DataSpaceHeader = observer(
|
|
|
194
189
|
title="More Actions..."
|
|
195
190
|
content={
|
|
196
191
|
<MenuContent>
|
|
197
|
-
{dataSpaceViewerState.currentExecutionContext && (
|
|
198
|
-
<>
|
|
199
|
-
<MenuContentItem
|
|
200
|
-
onClick={() =>
|
|
201
|
-
dataSpaceViewerState.queryDataSpace(
|
|
202
|
-
guaranteeNonNullable(
|
|
203
|
-
dataSpaceViewerState.currentExecutionContext,
|
|
204
|
-
).name,
|
|
205
|
-
)
|
|
206
|
-
}
|
|
207
|
-
>
|
|
208
|
-
Query Data Space
|
|
209
|
-
</MenuContentItem>
|
|
210
|
-
<MenuContentDivider />
|
|
211
|
-
</>
|
|
212
|
-
)}
|
|
213
|
-
<MenuContentItem
|
|
214
|
-
onClick={() =>
|
|
215
|
-
dataSpaceViewerState.viewProject(analysisResult.path)
|
|
216
|
-
}
|
|
217
|
-
>
|
|
218
|
-
View Project
|
|
219
|
-
</MenuContentItem>
|
|
220
192
|
<MenuContentItem
|
|
221
193
|
onClick={() => {
|
|
222
194
|
dataSpaceViewerState
|
|
@@ -224,32 +196,7 @@ const DataSpaceHeader = observer(
|
|
|
224
196
|
.catch(applicationStore.alertUnhandledError);
|
|
225
197
|
}}
|
|
226
198
|
>
|
|
227
|
-
View
|
|
228
|
-
</MenuContentItem>
|
|
229
|
-
<MenuContentDivider />
|
|
230
|
-
<MenuContentItem
|
|
231
|
-
onClick={() => {
|
|
232
|
-
const documentationUrl =
|
|
233
|
-
analysisResult.supportInfo?.documentationUrl;
|
|
234
|
-
if (documentationUrl) {
|
|
235
|
-
applicationStore.navigationService.navigator.visitAddress(
|
|
236
|
-
documentationUrl,
|
|
237
|
-
);
|
|
238
|
-
}
|
|
239
|
-
}}
|
|
240
|
-
>
|
|
241
|
-
Read Documentation
|
|
242
|
-
</MenuContentItem>
|
|
243
|
-
<MenuContentItem
|
|
244
|
-
onClick={() =>
|
|
245
|
-
dataSpaceViewerState.changeZone(
|
|
246
|
-
generateAnchorForActivity(
|
|
247
|
-
DATA_SPACE_VIEWER_ACTIVITY_MODE.SUPPORT,
|
|
248
|
-
),
|
|
249
|
-
)
|
|
250
|
-
}
|
|
251
|
-
>
|
|
252
|
-
Get Help
|
|
199
|
+
View Project
|
|
253
200
|
</MenuContentItem>
|
|
254
201
|
</MenuContent>
|
|
255
202
|
}
|
|
@@ -18,7 +18,11 @@ import type { DataSpaceViewerState } from '../stores/DataSpaceViewerState.js';
|
|
|
18
18
|
import { observer } from 'mobx-react-lite';
|
|
19
19
|
import { DataSpaceQuickStart } from './DataSpaceQuickStart.js';
|
|
20
20
|
import { DataSpaceDataAccess } from './DataSpaceDataAccess.js';
|
|
21
|
-
import {
|
|
21
|
+
import {
|
|
22
|
+
DataSpaceDescription,
|
|
23
|
+
DataSpaceWikiBadges,
|
|
24
|
+
} from './DataSpaceDescription.js';
|
|
25
|
+
import { DataSpaceLakehouseAccess } from './DataSpaceLakehouseAccess.js';
|
|
22
26
|
import { useEffect } from 'react';
|
|
23
27
|
import { ModelsDocumentation } from '@finos/legend-lego/model-documentation';
|
|
24
28
|
import { DiagramViewer } from '@finos/legend-extension-dsl-diagram';
|
|
@@ -57,7 +61,9 @@ export const DataSpaceWiki = observer(
|
|
|
57
61
|
|
|
58
62
|
return (
|
|
59
63
|
<div className="data-space__viewer__wiki">
|
|
64
|
+
<DataSpaceWikiBadges dataSpaceViewerState={dataSpaceViewerState} />
|
|
60
65
|
<DataSpaceDescription dataSpaceViewerState={dataSpaceViewerState} />
|
|
66
|
+
<DataSpaceLakehouseAccess dataSpaceViewerState={dataSpaceViewerState} />
|
|
61
67
|
<DiagramViewer
|
|
62
68
|
diagramViewerState={dataSpaceViewerState.diagramViewerState}
|
|
63
69
|
actions={{
|
|
@@ -50,7 +50,7 @@ import {
|
|
|
50
50
|
V1_MappingModelCoveragePartition,
|
|
51
51
|
V1_getGenericTypeFullPath,
|
|
52
52
|
V1_buildFullPath,
|
|
53
|
-
|
|
53
|
+
V1_LakehouseBaseRuntime,
|
|
54
54
|
V1_packageableRuntimeModelSchema,
|
|
55
55
|
V1_RelationType,
|
|
56
56
|
GenericType,
|
|
@@ -514,7 +514,7 @@ export class V1_DSL_DataSpace_PureGraphManagerExtension extends DSL_DataSpace_Pu
|
|
|
514
514
|
V1_packageableRuntimeModelSchema,
|
|
515
515
|
runtimeEntity.content,
|
|
516
516
|
);
|
|
517
|
-
if (runtimeProtocol.runtimeValue instanceof
|
|
517
|
+
if (runtimeProtocol.runtimeValue instanceof V1_LakehouseBaseRuntime) {
|
|
518
518
|
dataSpaceAnalysisResult.__INTERNAL__useRelationTDS = true;
|
|
519
519
|
}
|
|
520
520
|
}
|
|
@@ -28,16 +28,13 @@ import { BaseLayoutState } from '@finos/legend-extension-dsl-data-product';
|
|
|
28
28
|
|
|
29
29
|
export const DATA_SPACE_WIKI_PAGE_SECTIONS = [
|
|
30
30
|
DATA_SPACE_VIEWER_ACTIVITY_MODE.DESCRIPTION,
|
|
31
|
+
DATA_SPACE_VIEWER_ACTIVITY_MODE.DATASPACE_LAKEHOUSE_ACCESS,
|
|
31
32
|
DATA_SPACE_VIEWER_ACTIVITY_MODE.DIAGRAM_VIEWER,
|
|
32
33
|
DATA_SPACE_VIEWER_ACTIVITY_MODE.MODELS_DOCUMENTATION,
|
|
33
34
|
DATA_SPACE_VIEWER_ACTIVITY_MODE.QUICK_START,
|
|
34
35
|
DATA_SPACE_VIEWER_ACTIVITY_MODE.DATA_ACCESS,
|
|
35
36
|
];
|
|
36
37
|
|
|
37
|
-
const DATA_SPACE_WIKI_PAGE_ANCHORS = DATA_SPACE_WIKI_PAGE_SECTIONS.map(
|
|
38
|
-
(activity) => generateAnchorForActivity(activity),
|
|
39
|
-
);
|
|
40
|
-
|
|
41
38
|
export class DataSpaceLayoutState extends BaseLayoutState {
|
|
42
39
|
private dataSpaceViewerState!: DataSpaceViewerState;
|
|
43
40
|
|
|
@@ -53,7 +50,9 @@ export class DataSpaceLayoutState extends BaseLayoutState {
|
|
|
53
50
|
}
|
|
54
51
|
|
|
55
52
|
protected getValidAnchors(): string[] {
|
|
56
|
-
return
|
|
53
|
+
return this.dataSpaceViewerState.wikiPageSectionsToRender.map((activity) =>
|
|
54
|
+
generateAnchorForActivity(activity),
|
|
55
|
+
);
|
|
57
56
|
}
|
|
58
57
|
|
|
59
58
|
protected get expectedGridCount(): number {
|
|
@@ -63,7 +62,7 @@ export class DataSpaceLayoutState extends BaseLayoutState {
|
|
|
63
62
|
override get isWikiPageFullyRendered(): boolean {
|
|
64
63
|
return (
|
|
65
64
|
super.isWikiPageFullyRendered &&
|
|
66
|
-
|
|
65
|
+
this.dataSpaceViewerState.wikiPageSectionsToRender.includes(
|
|
67
66
|
this.dataSpaceViewerState.currentActivity,
|
|
68
67
|
)
|
|
69
68
|
);
|
|
@@ -20,6 +20,7 @@ import type { DiagramAnalysisResult } from '@finos/legend-extension-dsl-diagram'
|
|
|
20
20
|
|
|
21
21
|
export enum DATA_SPACE_VIEWER_ACTIVITY_MODE {
|
|
22
22
|
DESCRIPTION = 'description',
|
|
23
|
+
DATASPACE_LAKEHOUSE_ACCESS = 'dataspace-lakehouse-access',
|
|
23
24
|
DIAGRAM_VIEWER = 'diagram-viewer',
|
|
24
25
|
MODELS_DOCUMENTATION = 'models-documentation',
|
|
25
26
|
QUICK_START = 'quick-start',
|