@finos/legend-extension-dsl-data-product 0.0.19 → 0.0.21

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 (30) hide show
  1. package/lib/components/DataProduct/DataContract/EntitlementsDataContractViewer.d.ts +1 -2
  2. package/lib/components/DataProduct/DataContract/EntitlementsDataContractViewer.d.ts.map +1 -1
  3. package/lib/components/DataProduct/DataContract/EntitlementsDataContractViewer.js +64 -18
  4. package/lib/components/DataProduct/DataContract/EntitlementsDataContractViewer.js.map +1 -1
  5. package/lib/components/DataProduct/DataProductDataAccess.d.ts.map +1 -1
  6. package/lib/components/DataProduct/DataProductDataAccess.js +37 -5
  7. package/lib/components/DataProduct/DataProductDataAccess.js.map +1 -1
  8. package/lib/components/__test-utils__/TEST_DATA__LakehouseContractData.d.ts +4 -2
  9. package/lib/components/__test-utils__/TEST_DATA__LakehouseContractData.d.ts.map +1 -1
  10. package/lib/components/__test-utils__/TEST_DATA__LakehouseContractData.js +130 -1
  11. package/lib/components/__test-utils__/TEST_DATA__LakehouseContractData.js.map +1 -1
  12. package/lib/components/__test-utils__/TEST_DATA__LakehouseDataProducts.js +3 -3
  13. package/lib/components/__test-utils__/TEST_DATA__LakehouseDataProducts.js.map +1 -1
  14. package/lib/index.css +1 -1
  15. package/lib/package.json +1 -1
  16. package/lib/stores/DataProduct/DataProductAccessPointState.d.ts +4 -1
  17. package/lib/stores/DataProduct/DataProductAccessPointState.d.ts.map +1 -1
  18. package/lib/stores/DataProduct/DataProductAccessPointState.js +19 -0
  19. package/lib/stores/DataProduct/DataProductAccessPointState.js.map +1 -1
  20. package/lib/stores/DataProduct/EntitlementsDataContractViewerState.d.ts +10 -3
  21. package/lib/stores/DataProduct/EntitlementsDataContractViewerState.d.ts.map +1 -1
  22. package/lib/stores/DataProduct/EntitlementsDataContractViewerState.js +38 -9
  23. package/lib/stores/DataProduct/EntitlementsDataContractViewerState.js.map +1 -1
  24. package/package.json +9 -9
  25. package/src/components/DataProduct/DataContract/EntitlementsDataContractViewer.tsx +289 -150
  26. package/src/components/DataProduct/DataProductDataAccess.tsx +43 -4
  27. package/src/components/__test-utils__/TEST_DATA__LakehouseContractData.ts +137 -2
  28. package/src/components/__test-utils__/TEST_DATA__LakehouseDataProducts.ts +3 -3
  29. package/src/stores/DataProduct/DataProductAccessPointState.ts +25 -0
  30. package/src/stores/DataProduct/EntitlementsDataContractViewerState.ts +64 -13
@@ -22,6 +22,7 @@ import {
22
22
  Box,
23
23
  Button,
24
24
  Dialog,
25
+ DialogActions,
25
26
  DialogContent,
26
27
  DialogTitle,
27
28
  IconButton,
@@ -47,17 +48,20 @@ import {
47
48
  V1_ContractUserEventPrivilegeManagerPayload,
48
49
  V1_ResourceType,
49
50
  V1_UserApprovalStatus,
51
+ V1_UserType,
50
52
  } from '@finos/legend-graph';
51
53
  import React, { useCallback, useEffect, useMemo, useState } from 'react';
52
54
  import {
53
55
  type UserSearchService,
54
56
  ActionState,
57
+ assertErrorThrown,
55
58
  formatDate,
56
59
  lodashCapitalize,
57
60
  } from '@finos/legend-shared';
58
61
  import { flowResult } from 'mobx';
59
62
  import { useAuth } from 'react-oidc-context';
60
63
  import {
64
+ ArrowUpFromBracketIcon,
61
65
  CloseIcon,
62
66
  CopyIcon,
63
67
  CubesLoadingIndicator,
@@ -75,7 +79,6 @@ import {
75
79
  import { UserRenderer } from '../../UserRenderer/UserRenderer.js';
76
80
  import { isContractInTerminalState } from '../../../utils/DataContractUtils.js';
77
81
  import type { GenericLegendApplicationStore } from '@finos/legend-application';
78
- import type { DataProductAPGState } from '../../../stores/DataProduct/DataProductAPGState.js';
79
82
 
80
83
  const AssigneesList = (props: {
81
84
  userIds: string[];
@@ -167,6 +170,91 @@ const TaskApprovalView = (props: {
167
170
  }
168
171
  };
169
172
 
173
+ const ContractEscalationModal = (props: {
174
+ open: boolean;
175
+ onClose: () => void;
176
+ currentViewer: EntitlementsDataContractViewerState;
177
+ selectedUser: string | undefined;
178
+ refresh: () => Promise<void>;
179
+ }) => {
180
+ const { open, onClose, currentViewer, selectedUser, refresh } = props;
181
+
182
+ const auth = useAuth();
183
+ const [isLoading, setIsLoading] = useState(false);
184
+
185
+ if (!selectedUser) {
186
+ return (
187
+ <Dialog open={open} onClose={onClose} fullWidth={true} maxWidth="sm">
188
+ <DialogContent className="marketplace-lakehouse-entitlements__data-contract-viewer__escalation__content">
189
+ <div>
190
+ Can&apos;t escalate privilege manager approval request. No user
191
+ selected.
192
+ </div>
193
+ </DialogContent>
194
+ <DialogActions>
195
+ <Button onClick={onClose} variant="outlined" disabled={isLoading}>
196
+ Close
197
+ </Button>
198
+ </DialogActions>
199
+ </Dialog>
200
+ );
201
+ }
202
+
203
+ const handleEscalate = async () => {
204
+ setIsLoading(true);
205
+ try {
206
+ await currentViewer.lakehouseContractServerClient.escalateUserOnContract(
207
+ currentViewer.liteContract.guid,
208
+ selectedUser,
209
+ false,
210
+ auth.user?.access_token,
211
+ );
212
+ currentViewer.applicationStore.notificationService.notifySuccess(
213
+ 'Successfully escalated contract request',
214
+ );
215
+ // eslint-disable-next-line no-void
216
+ void refresh();
217
+ onClose();
218
+ } catch (error) {
219
+ assertErrorThrown(error);
220
+ currentViewer.applicationStore.alertUnhandledError(error);
221
+ } finally {
222
+ setIsLoading(false);
223
+ }
224
+ };
225
+
226
+ return (
227
+ <Dialog open={open} onClose={onClose} fullWidth={true} maxWidth="sm">
228
+ <DialogContent className="marketplace-lakehouse-entitlements__data-contract-viewer__escalation__content">
229
+ <CubesLoadingIndicator isLoading={isLoading}>
230
+ <CubesLoadingIndicatorIcon />
231
+ </CubesLoadingIndicator>
232
+ {!isLoading && (
233
+ <div>
234
+ Are you sure you want to escalate the privilege manager approval
235
+ request?
236
+ </div>
237
+ )}
238
+ </DialogContent>
239
+ <DialogActions>
240
+ <Button
241
+ onClick={() => {
242
+ // eslint-disable-next-line no-void
243
+ void handleEscalate();
244
+ }}
245
+ variant="contained"
246
+ disabled={isLoading}
247
+ >
248
+ Escalate
249
+ </Button>
250
+ <Button onClick={onClose} variant="outlined" disabled={isLoading}>
251
+ Cancel
252
+ </Button>
253
+ </DialogActions>
254
+ </Dialog>
255
+ );
256
+ };
257
+
170
258
  export const EntitlementsDataContractViewer = observer(
171
259
  (props: {
172
260
  open: boolean;
@@ -174,20 +262,20 @@ export const EntitlementsDataContractViewer = observer(
174
262
  currentViewer: EntitlementsDataContractViewerState;
175
263
  getContractTaskUrl: (taskId: string) => string;
176
264
  getDataProductUrl: (dataProductId: string, deploymentId: number) => string;
177
- apgState?: DataProductAPGState | undefined;
178
265
  initialSelectedUser?: string | undefined;
266
+ onRefresh?: (() => void) | (() => Promise<void>);
179
267
  }) => {
180
268
  const {
181
269
  open,
182
270
  currentViewer,
183
271
  getContractTaskUrl,
184
272
  getDataProductUrl,
185
- apgState,
186
273
  onClose,
187
274
  initialSelectedUser,
275
+ onRefresh,
188
276
  } = props;
189
277
  const auth = useAuth();
190
- const consumer = currentViewer.value.consumer;
278
+ const consumer = currentViewer.liteContract.consumer;
191
279
 
192
280
  // We try to get the target users from the associated tasks first, since the
193
281
  // tasks are what drive the timeline view. If there are no associated tasks,
@@ -244,6 +332,7 @@ export const EntitlementsDataContractViewer = observer(
244
332
  string | undefined
245
333
  >(initialSelectedUser ?? targetUsers?.[0]);
246
334
  const [isLoading, setIsLoading] = useState(false);
335
+ const [showEscalationModal, setShowEscalationModal] = useState(false);
247
336
 
248
337
  useEffect(() => {
249
338
  if (!currentViewer.initializationState.hasCompleted) {
@@ -267,18 +356,13 @@ export const EntitlementsDataContractViewer = observer(
267
356
 
268
357
  const refresh = async (): Promise<void> => {
269
358
  setIsLoading(true);
270
- if (apgState?.associatedUserContract) {
271
- apgState.fetchUserAccessStatus(
272
- apgState.associatedUserContract.guid,
273
- currentViewer.lakehouseContractServerClient,
274
- auth.user?.access_token,
275
- );
276
- }
277
359
  currentViewer.initializationState = ActionState.create();
360
+ await onRefresh?.();
278
361
  };
279
362
 
280
363
  if (
281
- currentViewer.value.resourceType !== V1_ResourceType.ACCESS_POINT_GROUP
364
+ currentViewer.liteContract.resourceType !==
365
+ V1_ResourceType.ACCESS_POINT_GROUP
282
366
  ) {
283
367
  return (
284
368
  <Dialog open={true} onClose={onClose} fullWidth={true} maxWidth="md">
@@ -291,15 +375,15 @@ export const EntitlementsDataContractViewer = observer(
291
375
  </IconButton>
292
376
  <DialogContent className="marketplace-lakehouse-entitlements__data-contract-viewer__content">
293
377
  Unable to display data contract request details for resource of type{' '}
294
- {currentViewer.value.resourceType} on data product{' '}
295
- {currentViewer.value.resourceId}.
378
+ {currentViewer.liteContract.resourceType} on data product{' '}
379
+ {currentViewer.liteContract.resourceId}.
296
380
  </DialogContent>
297
381
  </Dialog>
298
382
  );
299
383
  }
300
384
 
301
- const dataProduct = currentViewer.value.resourceId;
302
- const accessPointGroup = currentViewer.value.accessPointGroup;
385
+ const dataProduct = currentViewer.liteContract.resourceId;
386
+ const accessPointGroup = currentViewer.liteContract.accessPointGroup;
303
387
  const privilegeManagerApprovalTask = currentViewer.associatedTasks?.find(
304
388
  (task) =>
305
389
  task.rec.consumer === selectedTargetUser &&
@@ -314,6 +398,28 @@ export const EntitlementsDataContractViewer = observer(
314
398
  privilegeManagerApprovalTask?.rec.status ===
315
399
  V1_UserApprovalStatus.PENDING ||
316
400
  dataOwnerApprovalTask?.rec.status === V1_UserApprovalStatus.PENDING;
401
+ const showEscalationButton =
402
+ selectedTargetUser ===
403
+ currentViewer.applicationStore.identityService.currentUser ||
404
+ (selectedTargetUser !== undefined &&
405
+ currentViewer.getContractUserType(selectedTargetUser) ===
406
+ V1_UserType.SYSTEM_ACCOUNT);
407
+ const isContractEscalated =
408
+ privilegeManagerApprovalTask?.rec.isEscalated === true;
409
+ const canEscalateContract = showEscalationButton && !isContractEscalated;
410
+
411
+ const copyContractId = (): void => {
412
+ currentViewer.applicationStore.clipboardService
413
+ .copyTextToClipboard(currentViewer.liteContract.guid)
414
+ .then(() =>
415
+ currentViewer.applicationStore.notificationService.notifySuccess(
416
+ 'Contract ID Copied to Clipboard',
417
+ undefined,
418
+ 2500,
419
+ ),
420
+ )
421
+ .catch(currentViewer.applicationStore.alertUnhandledError);
422
+ };
317
423
 
318
424
  const copyTaskLink = (text: string): void => {
319
425
  currentViewer.applicationStore.clipboardService
@@ -360,6 +466,24 @@ export const EntitlementsDataContractViewer = observer(
360
466
  >
361
467
  <CopyIcon />
362
468
  </IconButton>
469
+ {showEscalationButton && (
470
+ <span
471
+ title={
472
+ canEscalateContract
473
+ ? 'Escalate request'
474
+ : isContractEscalated
475
+ ? 'Request has already been escalated'
476
+ : 'Cannot escalate request'
477
+ }
478
+ >
479
+ <IconButton
480
+ onClick={() => setShowEscalationModal(true)}
481
+ disabled={!canEscalateContract}
482
+ >
483
+ <ArrowUpFromBracketIcon />
484
+ </IconButton>
485
+ </span>
486
+ )}
363
487
  </>
364
488
  ) : (
365
489
  <>Privilege Manager Approval</>
@@ -443,144 +567,159 @@ export const EntitlementsDataContractViewer = observer(
443
567
  ];
444
568
 
445
569
  return (
446
- <Dialog open={open} onClose={onClose} fullWidth={true} maxWidth="md">
447
- <DialogTitle>
448
- {isContractInProgressForUser ? 'Pending ' : ''}Data Contract Request
449
- </DialogTitle>
450
- <IconButton onClick={onClose} className="marketplace-dialog-close-btn">
451
- <CloseIcon />
452
- </IconButton>
453
- <DialogContent className="marketplace-lakehouse-entitlements__data-contract-viewer__content">
454
- <CubesLoadingIndicator isLoading={isLoading}>
455
- <CubesLoadingIndicatorIcon />
456
- </CubesLoadingIndicator>
457
- {!isLoading && (
458
- <>
459
- <div>
460
- Access request for{' '}
461
- <span className="marketplace-lakehouse-text__emphasis">
462
- {accessPointGroup}
463
- </span>{' '}
464
- Access Point Group in{' '}
465
- <Link
466
- className="marketplace-lakehouse-text__emphasis"
467
- href={getDataProductUrl(
468
- dataProduct,
469
- currentViewer.value.deploymentId,
470
- )}
471
- target="_blank"
472
- rel="noopener noreferrer"
473
- >
474
- {dataProduct}
475
- </Link>{' '}
476
- Data Product
477
- </div>
478
- <Box className="marketplace-lakehouse-entitlements__data-contract-viewer__metadata">
479
- <div className="marketplace-lakehouse-entitlements__data-contract-viewer__metadata__ordered-by">
480
- <b>Ordered By: </b>
481
- <UserRenderer
482
- userId={currentViewer.value.createdBy}
483
- applicationStore={currentViewer.applicationStore}
484
- userSearchService={currentViewer.userSearchService}
485
- />
570
+ <>
571
+ <Dialog open={open} onClose={onClose} fullWidth={true} maxWidth="md">
572
+ <DialogTitle>
573
+ {isContractInProgressForUser ? 'Pending ' : ''}Data Contract Request
574
+ </DialogTitle>
575
+ <IconButton
576
+ onClick={onClose}
577
+ className="marketplace-dialog-close-btn"
578
+ >
579
+ <CloseIcon />
580
+ </IconButton>
581
+ <DialogContent className="marketplace-lakehouse-entitlements__data-contract-viewer__content">
582
+ <CubesLoadingIndicator isLoading={isLoading}>
583
+ <CubesLoadingIndicatorIcon />
584
+ </CubesLoadingIndicator>
585
+ {!isLoading && (
586
+ <>
587
+ <div>
588
+ Access request for{' '}
589
+ <span className="marketplace-lakehouse-text__emphasis">
590
+ {accessPointGroup}
591
+ </span>{' '}
592
+ Access Point Group in{' '}
593
+ <Link
594
+ className="marketplace-lakehouse-text__emphasis"
595
+ href={getDataProductUrl(
596
+ dataProduct,
597
+ currentViewer.liteContract.deploymentId,
598
+ )}
599
+ target="_blank"
600
+ rel="noopener noreferrer"
601
+ >
602
+ {dataProduct}
603
+ </Link>{' '}
604
+ Data Product
486
605
  </div>
487
- <div className="marketplace-lakehouse-entitlements__data-contract-viewer__metadata__ordered-for">
488
- <b>
489
- Ordered For
490
- <Tooltip
491
- className="marketplace-lakehouse-entitlements__data-contract-viewer__metadata__ordered-for__tooltip__icon"
492
- title={
493
- <>
494
- Contract consumer type:{' '}
495
- {getOrganizationalScopeTypeName(
496
- consumer,
497
- currentViewer.applicationStore.pluginManager.getApplicationPlugins(),
498
- )}
499
- {getOrganizationalScopeTypeDetails(
500
- consumer,
501
- currentViewer.applicationStore.pluginManager.getApplicationPlugins(),
502
- )}
503
- </>
504
- }
505
- >
506
- <InfoCircleIcon />
507
- </Tooltip>
508
- :{' '}
509
- </b>
510
- {targetUsers !== undefined ? (
511
- targetUsers.length === 1 ? (
512
- <UserRenderer
513
- key={targetUsers[0]}
514
- userId={targetUsers[0]}
515
- applicationStore={currentViewer.applicationStore}
516
- userSearchService={currentViewer.userSearchService}
517
- />
518
- ) : (
519
- <Select
520
- value={selectedTargetUser}
521
- onChange={(event) =>
522
- setSelectedTargetUser(event.target.value)
606
+ <Box className="marketplace-lakehouse-entitlements__data-contract-viewer__metadata">
607
+ <div className="marketplace-lakehouse-entitlements__data-contract-viewer__metadata__ordered-by">
608
+ <b>Ordered By: </b>
609
+ <UserRenderer
610
+ userId={currentViewer.liteContract.createdBy}
611
+ applicationStore={currentViewer.applicationStore}
612
+ userSearchService={currentViewer.userSearchService}
613
+ />
614
+ </div>
615
+ <div className="marketplace-lakehouse-entitlements__data-contract-viewer__metadata__ordered-for">
616
+ <b>
617
+ Ordered For
618
+ <Tooltip
619
+ className="marketplace-lakehouse-entitlements__data-contract-viewer__metadata__ordered-for__tooltip__icon"
620
+ title={
621
+ <>
622
+ Contract consumer type:{' '}
623
+ {getOrganizationalScopeTypeName(
624
+ consumer,
625
+ currentViewer.applicationStore.pluginManager.getApplicationPlugins(),
626
+ )}
627
+ {getOrganizationalScopeTypeDetails(
628
+ consumer,
629
+ currentViewer.applicationStore.pluginManager.getApplicationPlugins(),
630
+ )}
631
+ </>
523
632
  }
524
- size="small"
525
- className="marketplace-lakehouse-entitlements__data-contract-viewer__metadata__ordered-for__select"
526
633
  >
527
- {targetUserSelectItems}
528
- </Select>
529
- )
530
- ) : (
531
- stringifyOrganizationalScope(consumer)
532
- )}
533
- </div>
534
- <div>
535
- <b>Business Justification: </b>
536
- {currentViewer.value.description}
537
- </div>
538
- </Box>
539
- {!isContractInTerminalState(currentViewer.value) && (
540
- <Box className="marketplace-lakehouse-entitlements__data-contract-viewer__refresh-btn">
541
- <Button
542
- size="small"
543
- variant="outlined"
544
- startIcon={<RefreshIcon />}
545
- onClick={() => {
546
- // eslint-disable-next-line no-void
547
- void refresh();
548
- }}
549
- >
550
- Refresh
551
- </Button>
552
- </Box>
553
- )}
554
- <Box className="marketplace-lakehouse-entitlements__data-contract-viewer__timeline">
555
- <Timeline>
556
- {steps.map((step, index) => (
557
- <TimelineItem key={step.key}>
558
- <TimelineOppositeContent className="marketplace-lakehouse-entitlements__data-contract-viewer__timeline__content">
559
- {step.label}
560
- </TimelineOppositeContent>
561
- <TimelineSeparator>
562
- <TimelineDot
563
- color={step.isDeniedStep ? 'error' : 'primary'}
564
- variant={
565
- step.isCompleteOrActive ? 'filled' : 'outlined'
566
- }
634
+ <InfoCircleIcon />
635
+ </Tooltip>
636
+ :{' '}
637
+ </b>
638
+ {targetUsers !== undefined ? (
639
+ targetUsers.length === 1 ? (
640
+ <UserRenderer
641
+ key={targetUsers[0]}
642
+ userId={targetUsers[0]}
643
+ applicationStore={currentViewer.applicationStore}
644
+ userSearchService={currentViewer.userSearchService}
567
645
  />
568
- {index < steps.length - 1 && <TimelineConnector />}
569
- </TimelineSeparator>
570
- <TimelineContent className="marketplace-lakehouse-entitlements__data-contract-viewer__timeline__content">
571
- {step.description}
572
- </TimelineContent>
573
- </TimelineItem>
574
- ))}
575
- </Timeline>
576
- </Box>
577
- </>
578
- )}
579
- <Box className="marketplace-lakehouse-entitlements__data-contract-viewer__footer">
580
- Contract ID: {currentViewer.value.guid}
581
- </Box>
582
- </DialogContent>
583
- </Dialog>
646
+ ) : (
647
+ <Select
648
+ value={selectedTargetUser}
649
+ onChange={(event) =>
650
+ setSelectedTargetUser(event.target.value)
651
+ }
652
+ size="small"
653
+ className="marketplace-lakehouse-entitlements__data-contract-viewer__metadata__ordered-for__select"
654
+ >
655
+ {targetUserSelectItems}
656
+ </Select>
657
+ )
658
+ ) : (
659
+ stringifyOrganizationalScope(consumer)
660
+ )}
661
+ </div>
662
+ <div>
663
+ <b>Business Justification: </b>
664
+ {currentViewer.liteContract.description}
665
+ </div>
666
+ </Box>
667
+ {!isContractInTerminalState(currentViewer.liteContract) && (
668
+ <Box className="marketplace-lakehouse-entitlements__data-contract-viewer__refresh-btn">
669
+ <Button
670
+ size="small"
671
+ variant="outlined"
672
+ startIcon={<RefreshIcon />}
673
+ onClick={() => {
674
+ // eslint-disable-next-line no-void
675
+ void refresh();
676
+ }}
677
+ >
678
+ Refresh
679
+ </Button>
680
+ </Box>
681
+ )}
682
+ <Box className="marketplace-lakehouse-entitlements__data-contract-viewer__timeline">
683
+ <Timeline>
684
+ {steps.map((step, index) => (
685
+ <TimelineItem key={step.key}>
686
+ <TimelineOppositeContent className="marketplace-lakehouse-entitlements__data-contract-viewer__timeline__content">
687
+ {step.label}
688
+ </TimelineOppositeContent>
689
+ <TimelineSeparator>
690
+ <TimelineDot
691
+ color={step.isDeniedStep ? 'error' : 'primary'}
692
+ variant={
693
+ step.isCompleteOrActive ? 'filled' : 'outlined'
694
+ }
695
+ />
696
+ {index < steps.length - 1 && <TimelineConnector />}
697
+ </TimelineSeparator>
698
+ <TimelineContent className="marketplace-lakehouse-entitlements__data-contract-viewer__timeline__content">
699
+ {step.description}
700
+ </TimelineContent>
701
+ </TimelineItem>
702
+ ))}
703
+ </Timeline>
704
+ </Box>
705
+ </>
706
+ )}
707
+ <Box className="marketplace-lakehouse-entitlements__data-contract-viewer__footer">
708
+ Contract ID: {currentViewer.liteContract.guid}
709
+ <IconButton onClick={() => copyContractId()}>
710
+ <CopyIcon />
711
+ </IconButton>
712
+ </Box>
713
+ </DialogContent>
714
+ </Dialog>
715
+ <ContractEscalationModal
716
+ open={showEscalationModal && canEscalateContract}
717
+ onClose={() => setShowEscalationModal(false)}
718
+ currentViewer={currentViewer}
719
+ selectedUser={selectedTargetUser}
720
+ refresh={refresh}
721
+ />
722
+ </>
584
723
  );
585
724
  },
586
725
  );
@@ -38,6 +38,7 @@ import {
38
38
  import {
39
39
  type V1_RelationTypeColumn,
40
40
  extractElementNameFromPath,
41
+ V1_AccessPointGroupReference,
41
42
  V1_AdHocDeploymentDataProductOrigin,
42
43
  V1_AppliedFunction,
43
44
  V1_AppliedProperty,
@@ -352,6 +353,27 @@ const AccessPointTable = observer(
352
353
  }`
353
354
  : '',
354
355
  },
356
+ {
357
+ headerName: 'Column Sample Values',
358
+ flex: 1,
359
+ wrapText: true,
360
+ autoHeight: true,
361
+ valueGetter: (_params) => {
362
+ if (!_params.data || !accessPointState.relationElement) {
363
+ return 'No sample values provided';
364
+ }
365
+ const columnName = _params.data.name;
366
+ const columnIndex =
367
+ accessPointState.relationElement.columns.indexOf(columnName);
368
+ if (columnIndex === -1) {
369
+ return 'No sample values provided';
370
+ }
371
+ const sampleValues = accessPointState.relationElement.rows
372
+ .map((row) => row.values[columnIndex])
373
+ .filter((value) => value !== undefined);
374
+ return sampleValues.join(', ');
375
+ },
376
+ },
355
377
  ];
356
378
 
357
379
  return (
@@ -456,13 +478,15 @@ const AccessPointTable = observer(
456
478
  <Box className="data-product__viewer__more-info__container">
457
479
  {selectedTab === DataProductTabs.COLUMNS && (
458
480
  <>
459
- {accessPointState.fetchingRelationTypeState.isInProgress ? (
481
+ {accessPointState.fetchingRelationTypeState.isInProgress ||
482
+ accessPointState.fetchingRelationElement.isInProgress ? (
460
483
  <Box className="data-product__viewer__more-info__loading-indicator">
461
484
  <CubesLoadingIndicator isLoading={true}>
462
485
  <CubesLoadingIndicatorIcon />
463
486
  </CubesLoadingIndicator>
464
487
  </Box>
465
- ) : accessPointState.fetchingRelationTypeState.hasCompleted ? (
488
+ ) : accessPointState.fetchingRelationTypeState.hasCompleted &&
489
+ accessPointState.fetchingRelationElement.hasCompleted ? (
466
490
  <Box
467
491
  className={clsx(
468
492
  'data-product__viewer__more-info__columns-grid ag-theme-balham',
@@ -567,18 +591,25 @@ export const DataProductAccessPointGroupViewer = observer(
567
591
  const requestAccessButtonGroupRef = useRef<HTMLDivElement | null>(null);
568
592
 
569
593
  const entitlementsDataContractViewerState = useMemo(() => {
570
- return dataAccessState?.dataContract
594
+ return dataAccessState?.dataContract &&
595
+ dataAccessState.dataContract.resource instanceof
596
+ V1_AccessPointGroupReference &&
597
+ dataAccessState.dataContract.resource.accessPointGroup ===
598
+ apgState.apg.id
571
599
  ? new EntitlementsDataContractViewerState(
572
600
  V1_transformDataContractToLiteDatacontract(
573
601
  dataAccessState.dataContract,
574
602
  ),
575
603
  apgState.applicationStore,
576
604
  dataAccessState.lakehouseContractServerClient,
605
+ apgState.dataProductViewerState.graphManagerState,
577
606
  apgState.dataProductViewerState.userSearchService,
578
607
  )
579
608
  : undefined;
580
609
  }, [
610
+ apgState.apg.id,
581
611
  apgState.applicationStore,
612
+ apgState.dataProductViewerState.graphManagerState,
582
613
  apgState.dataProductViewerState.userSearchService,
583
614
  dataAccessState?.dataContract,
584
615
  dataAccessState?.lakehouseContractServerClient,
@@ -821,7 +852,15 @@ export const DataProductAccessPointGroupViewer = observer(
821
852
  open={true}
822
853
  onClose={() => dataAccessState.setDataContract(undefined)}
823
854
  currentViewer={entitlementsDataContractViewerState}
824
- apgState={apgState}
855
+ onRefresh={() => {
856
+ if (apgState.associatedUserContract) {
857
+ apgState.fetchUserAccessStatus(
858
+ apgState.associatedUserContract.guid,
859
+ dataAccessState.lakehouseContractServerClient,
860
+ auth.user?.access_token,
861
+ );
862
+ }
863
+ }}
825
864
  getContractTaskUrl={dataAccessState.getContractTaskUrl}
826
865
  getDataProductUrl={dataAccessState.getDataProductUrl}
827
866
  />