@finos/legend-application-marketplace 0.2.24 → 0.2.26

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 (34) hide show
  1. package/lib/components/MarketplaceSearchFiltersPanel/MarketplaceSearchFiltersPanel.d.ts.map +1 -1
  2. package/lib/components/MarketplaceSearchFiltersPanel/MarketplaceSearchFiltersPanel.js +2 -11
  3. package/lib/components/MarketplaceSearchFiltersPanel/MarketplaceSearchFiltersPanel.js.map +1 -1
  4. package/lib/components/__test-utils__/TEST_DATA__ContractErrors.d.ts +88 -0
  5. package/lib/components/__test-utils__/TEST_DATA__ContractErrors.d.ts.map +1 -0
  6. package/lib/components/__test-utils__/TEST_DATA__ContractErrors.js +178 -0
  7. package/lib/components/__test-utils__/TEST_DATA__ContractErrors.js.map +1 -0
  8. package/lib/index.css +1 -1
  9. package/lib/package.json +1 -1
  10. package/lib/stores/LegendMarketplaceBaseStore.d.ts +2 -2
  11. package/lib/stores/LegendMarketplaceBaseStore.d.ts.map +1 -1
  12. package/lib/stores/LegendMarketplaceBaseStore.js.map +1 -1
  13. package/lib/stores/lakehouse/LegendMarketplaceProductViewerStore.d.ts.map +1 -1
  14. package/lib/stores/lakehouse/LegendMarketplaceProductViewerStore.js +3 -3
  15. package/lib/stores/lakehouse/LegendMarketplaceProductViewerStore.js.map +1 -1
  16. package/lib/stores/lakehouse/dataProducts/ProductCardState.js +3 -3
  17. package/lib/stores/lakehouse/dataProducts/ProductCardState.js.map +1 -1
  18. package/lib/stores/lakehouse/entitlements/EntitlementsDashboardState.d.ts +3 -17
  19. package/lib/stores/lakehouse/entitlements/EntitlementsDashboardState.d.ts.map +1 -1
  20. package/lib/stores/lakehouse/entitlements/EntitlementsDashboardState.js +20 -195
  21. package/lib/stores/lakehouse/entitlements/EntitlementsDashboardState.js.map +1 -1
  22. package/lib/utils/LakehouseUtils.d.ts +1 -2
  23. package/lib/utils/LakehouseUtils.d.ts.map +1 -1
  24. package/lib/utils/LakehouseUtils.js +2 -31
  25. package/lib/utils/LakehouseUtils.js.map +1 -1
  26. package/package.json +8 -8
  27. package/src/components/MarketplaceSearchFiltersPanel/MarketplaceSearchFiltersPanel.tsx +0 -32
  28. package/src/components/__test-utils__/TEST_DATA__ContractErrors.ts +252 -0
  29. package/src/stores/LegendMarketplaceBaseStore.ts +1 -1
  30. package/src/stores/lakehouse/LegendMarketplaceProductViewerStore.ts +3 -5
  31. package/src/stores/lakehouse/dataProducts/ProductCardState.ts +3 -3
  32. package/src/stores/lakehouse/entitlements/EntitlementsDashboardState.ts +41 -302
  33. package/src/utils/LakehouseUtils.tsx +1 -80
  34. package/tsconfig.json +1 -0
@@ -15,20 +15,15 @@
15
15
  */
16
16
 
17
17
  import {
18
+ type GeneratorFn,
19
+ type PlainObject,
18
20
  ActionState,
19
21
  assertErrorThrown,
20
22
  guaranteeNonNullable,
21
- guaranteeType,
22
- HttpStatus,
23
23
  isNonNullable,
24
- NetworkClientError,
25
- type GeneratorFn,
26
- type PlainObject,
27
24
  } from '@finos/legend-shared';
28
25
  import { deserialize } from 'serializr';
29
26
  import {
30
- type PureProtocolProcessorPlugin,
31
- type V1_DataProduct,
32
27
  type V1_EnrichedUserApprovalStatus,
33
28
  type V1_LiteDataContract,
34
29
  type V1_LiteDataContractWithUserStatus,
@@ -36,26 +31,24 @@ import {
36
31
  type V1_TaskStatus,
37
32
  type V1_ContractUserEventRecord,
38
33
  type V1_TaskStatusChangeResponse,
39
- RawLambda,
40
- V1_DataProductAccessor,
41
- V1_deserializeDataContractResponse,
42
34
  type V1_DataRequestWithWorkflow,
35
+ type V1_DataRequestsWithWorkflowResponse,
36
+ V1_deserializeDataContractResponse,
43
37
  V1_entitlementsDataProductDetailsResponseToDataProductDetails,
44
- V1_IngestDefinitionAccessor,
45
- V1_LakehouseAccessPoint,
46
38
  V1_liteDataContractWithUserStatusModelSchema,
47
39
  V1_pendingTasksResponseModelSchema,
48
- V1_PureGraphManager,
49
- V1_resolveAccessorsFromRawLambda,
50
- V1_ResourceType,
51
- V1_SdlcDeploymentDataProductOrigin,
52
40
  V1_TaskStatusChangeResponseModelSchema,
53
41
  V1_transformDataContractToLiteDatacontract,
54
42
  V1_deserializeDataRequestsWithWorkflowResponse,
55
- type V1_DataRequestsWithWorkflowResponse,
56
43
  } from '@finos/legend-graph';
57
- import { DEFAULT_TAB_SIZE } from '@finos/legend-application';
58
- import type { ContractErrorLayer } from '@finos/legend-extension-dsl-data-product';
44
+ import {
45
+ type ContractErrorLayer,
46
+ type LakehouseContractSyncStatusResponse,
47
+ buildSyncErrorLayer,
48
+ buildContractErrorsRoot,
49
+ getContractAPGCoordinates,
50
+ getUnverifiedIngestDefinitionsForAPG,
51
+ } from '@finos/legend-extension-dsl-data-product';
59
52
  import {
60
53
  makeObservable,
61
54
  flow,
@@ -65,97 +58,9 @@ import {
65
58
  computed,
66
59
  } from 'mobx';
67
60
  import {
68
- TEST_USER,
69
61
  type LakehouseEntitlementsStore,
62
+ TEST_USER,
70
63
  } from './LakehouseEntitlementsStore.js';
71
- import { getDataProductFromDetails } from '../../../utils/LakehouseUtils.js';
72
-
73
- export enum ContractSyncStatus {
74
- NEVER_SYNCED = 'NEVER_SYNCED',
75
- NOT_FULLY_SYNCED = 'NOT_FULLY_SYNCED',
76
- }
77
-
78
- export type LakehouseContractSyncStatusResponse = {
79
- status: string;
80
- unsyncedUsers?: { username: string }[];
81
- unsyncedAccessPoints?: { accessPointName: string }[];
82
- unsyncedTargetAccounts?: string[];
83
- };
84
-
85
- const collectIngestSpecPathsFromOriginDp = (
86
- rootDataProduct: V1_DataProduct,
87
- accessPointGroupId: string,
88
- graphManager: V1_PureGraphManager,
89
- plugins: PureProtocolProcessorPlugin[],
90
- ): Set<string> => {
91
- const dpPath = `${rootDataProduct.package}::${rootDataProduct.name}`;
92
- const targetApg = rootDataProduct.accessPointGroups.find(
93
- (apg) => apg.id === accessPointGroupId,
94
- );
95
- if (!targetApg) {
96
- throw new Error(
97
- `Access point group '${accessPointGroupId}' not found in data product '${dpPath}'`,
98
- );
99
- }
100
- const specs = new Set<string>();
101
- const visited = new Set<string>();
102
- const worklist: string[] = [accessPointGroupId];
103
-
104
- const collectFromApg = (apgId: string): void => {
105
- const apg = rootDataProduct.accessPointGroups.find((g) => g.id === apgId);
106
- if (!apg) {
107
- return;
108
- }
109
- for (const accessPoint of apg.accessPoints) {
110
- if (!(accessPoint instanceof V1_LakehouseAccessPoint)) {
111
- continue;
112
- }
113
- const visitKey = `${dpPath}::${accessPoint.id}`;
114
- if (visited.has(visitKey)) {
115
- continue;
116
- }
117
- visited.add(visitKey);
118
-
119
- const rawLambda = new RawLambda(
120
- accessPoint.func.parameters,
121
- accessPoint.func.body,
122
- );
123
- const accessors =
124
- V1_resolveAccessorsFromRawLambda(rawLambda, graphManager, plugins) ??
125
- [];
126
- for (const accessor of accessors) {
127
- if (accessor instanceof V1_IngestDefinitionAccessor) {
128
- const specPath = accessor.path[0];
129
- if (specPath) {
130
- specs.add(specPath);
131
- }
132
- } else if (accessor instanceof V1_DataProductAccessor) {
133
- const refDpPath = accessor.path[0];
134
- const refApId = accessor.path[1];
135
- if (!refDpPath || !refApId) {
136
- continue;
137
- }
138
- if (refDpPath !== dpPath) {
139
- continue;
140
- }
141
- const refApg = rootDataProduct.accessPointGroups.find((g) =>
142
- g.accessPoints.some((ap) => ap.id === refApId),
143
- );
144
- if (refApg && !worklist.includes(refApg.id)) {
145
- worklist.push(refApg.id);
146
- }
147
- }
148
- }
149
- }
150
- };
151
-
152
- while (worklist.length > 0) {
153
- const apgId = guaranteeNonNullable(worklist.shift());
154
- collectFromApg(apgId);
155
- }
156
-
157
- return specs;
158
- };
159
64
 
160
65
  export class ContractCreatedByUserDetails {
161
66
  readonly contractResultLite: V1_LiteDataContract;
@@ -531,158 +436,37 @@ export class EntitlementsDashboardState {
531
436
  return didToEnvType;
532
437
  }
533
438
 
534
- async getUnverifiedIngestDefinitions(
439
+ async getContractIngestErrors(
535
440
  contractId: string,
536
441
  token: string | undefined,
537
- ): Promise<string[]> {
538
- const entitlementsStore = this.lakehouseEntitlementsStore;
539
- const baseStore = entitlementsStore.marketplaceBaseStore;
540
- const applicationStore = entitlementsStore.applicationStore;
442
+ ): Promise<ContractErrorLayer | undefined> {
443
+ const baseStore = this.lakehouseEntitlementsStore.marketplaceBaseStore;
541
444
  const plugins =
542
- applicationStore.pluginManager.getPureProtocolProcessorPlugins();
543
- const contractClient = entitlementsStore.lakehouseContractServerClient;
544
-
545
- const PROD_ENV = 'prod';
546
- const SDLC_DEPLOYMENT = 'alloy-git';
547
-
548
- try {
549
- const liteContract = await (async () => {
550
- try {
551
- const rawContractResponse = await contractClient.getDataContract(
552
- contractId,
553
- false,
554
- token,
555
- );
556
- const dataContract = V1_deserializeDataContractResponse(
557
- rawContractResponse,
558
- plugins,
559
- )[0]?.dataContract;
560
- if (!dataContract) {
561
- return undefined;
562
- }
563
- return V1_transformDataContractToLiteDatacontract(dataContract);
564
- } catch (error) {
565
- assertErrorThrown(error);
566
- return undefined;
567
- }
568
- })();
569
- if (!liteContract) {
570
- return [];
571
- }
572
-
573
- const accessPointGroupId =
574
- liteContract.resourceType === V1_ResourceType.ACCESS_POINT_GROUP
575
- ? (liteContract.accessPointGroup ?? undefined)
576
- : undefined;
577
- if (!accessPointGroupId) {
578
- return [];
579
- }
580
-
581
- const dpDetails = await (async () => {
582
- try {
583
- const raw = await contractClient.getDataProductByIdAndDID(
584
- liteContract.resourceId,
585
- liteContract.deploymentId,
586
- token,
587
- );
588
- return V1_entitlementsDataProductDetailsResponseToDataProductDetails(
589
- raw,
590
- )[0];
591
- } catch (error) {
592
- assertErrorThrown(error);
593
- return undefined;
594
- }
595
- })();
596
- if (!dpDetails) {
597
- return [];
598
- }
599
-
600
- if (!(dpDetails.origin instanceof V1_SdlcDeploymentDataProductOrigin)) {
601
- return [];
602
- }
603
-
604
- const graphManager = new V1_PureGraphManager(
605
- applicationStore.pluginManager,
606
- applicationStore.logService,
607
- baseStore.remoteEngine,
608
- );
609
- await graphManager.initialize(
610
- {
611
- env: applicationStore.config.env,
612
- tabSize: DEFAULT_TAB_SIZE,
613
- clientConfig: {
614
- baseUrl: applicationStore.config.engineServerUrl,
615
- },
616
- },
617
- { engine: baseStore.remoteEngine },
618
- );
619
-
620
- const v1DataProduct = await getDataProductFromDetails(
621
- dpDetails,
622
- graphManager,
445
+ this.lakehouseEntitlementsStore.applicationStore.pluginManager.getPureProtocolProcessorPlugins();
446
+ const apg = await getContractAPGCoordinates(
447
+ contractId,
448
+ baseStore.lakehouseContractServerClient,
449
+ plugins,
450
+ token,
451
+ );
452
+ if (!apg) {
453
+ return undefined;
454
+ }
455
+ const unverifiedIngestDefinitions =
456
+ await getUnverifiedIngestDefinitionsForAPG(
457
+ apg,
623
458
  baseStore,
624
- );
625
- if (!v1DataProduct) {
626
- return [];
627
- }
628
-
629
- const specs = collectIngestSpecPathsFromOriginDp(
630
- v1DataProduct,
631
- accessPointGroupId,
632
- graphManager,
633
459
  plugins,
460
+ () => baseStore.createInitializedGraphManager(),
461
+ token,
634
462
  );
635
- if (specs.size === 0) {
636
- return [];
637
- }
638
-
639
- const ingestEnvironment =
640
- await baseStore.lakehouseDataProductService.getOrFetchEnvironmentForDID(
641
- liteContract.deploymentId,
642
- token,
643
- );
644
- const ingestServerUrl = ingestEnvironment?.ingestServerUrl;
645
- if (ingestServerUrl === undefined) {
646
- return [];
647
- }
648
-
649
- const sdlcOrigin = guaranteeType(
650
- dpDetails.origin,
651
- V1_SdlcDeploymentDataProductOrigin,
652
- );
653
- const gav = `${sdlcOrigin.group}~${sdlcOrigin.artifact}`;
654
- const specsToVerify = Array.from(specs, (specPath) => ({
655
- specPath,
656
- urn: `urn:lakehouse:${PROD_ENV}:ingest:definition:${SDLC_DEPLOYMENT}:${gav}~${specPath}`,
657
- }));
658
-
659
- const ingestClient = baseStore.lakehouseIngestServerClient;
660
- const settled = await Promise.all(
661
- specsToVerify.map(async (entry) => {
662
- try {
663
- await ingestClient.getIngestDefinitionDetail(
664
- entry.urn,
665
- ingestServerUrl,
666
- token,
667
- );
668
- return undefined;
669
- } catch (error) {
670
- assertErrorThrown(error);
671
- if (
672
- error instanceof NetworkClientError &&
673
- error.response.status === HttpStatus.NOT_FOUND
674
- ) {
675
- return entry.specPath;
676
- }
677
- return undefined;
678
- }
679
- }),
680
- );
681
- return settled.filter(isNonNullable);
682
- } catch (error) {
683
- assertErrorThrown(error);
684
- return [];
463
+ if (unverifiedIngestDefinitions.length === 0) {
464
+ return undefined;
685
465
  }
466
+ return {
467
+ title: `Ingest${unverifiedIngestDefinitions.length === 1 ? '' : 's'} Not Found:`,
468
+ errorItems: unverifiedIngestDefinitions,
469
+ };
686
470
  }
687
471
 
688
472
  async getContractSyncErrors(
@@ -695,39 +479,7 @@ export class EntitlementsDashboardState {
695
479
  contractId,
696
480
  token,
697
481
  )) as LakehouseContractSyncStatusResponse;
698
-
699
- const status = response.status.toUpperCase();
700
-
701
- if (status === ContractSyncStatus.NEVER_SYNCED) {
702
- return { title: 'Sync Error: Contract Never Synced' };
703
- }
704
-
705
- if (status === ContractSyncStatus.NOT_FULLY_SYNCED) {
706
- const unsyncedUsers =
707
- response.unsyncedUsers?.map((user) => user.username) ?? [];
708
- const unsyncedAccessPoints =
709
- response.unsyncedAccessPoints?.map(
710
- (accessPoint) => accessPoint.accessPointName,
711
- ) ?? [];
712
- const unsyncedTargetAccounts = response.unsyncedTargetAccounts ?? [];
713
-
714
- const syncGroupingLayers: ContractErrorLayer[] = [
715
- { title: 'Users', errorItems: unsyncedUsers },
716
- { title: 'Target Accounts', errorItems: unsyncedTargetAccounts },
717
- { title: 'Access Points', errorItems: unsyncedAccessPoints },
718
- ].filter((layer) => layer.errorItems.length > 0);
719
-
720
- if (syncGroupingLayers.length === 0) {
721
- return undefined;
722
- }
723
-
724
- return {
725
- title: 'Unsynced Entities',
726
- childLayers: syncGroupingLayers,
727
- };
728
- }
729
-
730
- return undefined;
482
+ return buildSyncErrorLayer(response);
731
483
  } catch (error) {
732
484
  assertErrorThrown(error);
733
485
  return undefined;
@@ -739,26 +491,13 @@ export class EntitlementsDashboardState {
739
491
  token: string | undefined,
740
492
  checkSyncStatus = false,
741
493
  ): Promise<ContractErrorLayer | undefined> {
742
- const [unverifiedIngestDefinitions, syncErrorsLayer] = await Promise.all([
743
- this.getUnverifiedIngestDefinitions(contractId, token),
494
+ const [ingestErrorsLayer, syncErrorsLayer] = await Promise.all([
495
+ this.getContractIngestErrors(contractId, token),
744
496
  checkSyncStatus
745
497
  ? this.getContractSyncErrors(contractId, token)
746
498
  : Promise.resolve(undefined),
747
499
  ]);
748
-
749
- const childLayers: ContractErrorLayer[] = [
750
- unverifiedIngestDefinitions.length > 0
751
- ? {
752
- title: `Ingest${unverifiedIngestDefinitions.length === 1 ? '' : 's'} Not Found`,
753
- errorItems: unverifiedIngestDefinitions,
754
- }
755
- : undefined,
756
- syncErrorsLayer,
757
- ].filter(isNonNullable);
758
-
759
- return childLayers.length > 0
760
- ? { title: 'Contract Errors', childLayers }
761
- : undefined;
500
+ return buildContractErrorsRoot([ingestErrorsLayer, syncErrorsLayer]);
762
501
  }
763
502
 
764
503
  filterByUserEnvironment(
@@ -18,23 +18,15 @@ import {
18
18
  type GraphManagerState,
19
19
  type V1_EntitlementsDataProductDetails,
20
20
  type V1_PureGraphManager,
21
- type V1_DataProduct,
22
21
  V1_AdHocDeploymentDataProductOrigin,
23
- V1_dataProductModelSchema,
24
22
  V1_SdlcDeploymentDataProductOrigin,
25
- CORE_PURE_PATH,
26
23
  } from '@finos/legend-graph';
27
- import {
28
- ActionState,
29
- guaranteeNonNullable,
30
- type PlainObject,
31
- } from '@finos/legend-shared';
24
+ import { ActionState, type PlainObject } from '@finos/legend-shared';
32
25
  import {
33
26
  type ProjectVersionEntities,
34
27
  resolveVersion,
35
28
  } from '@finos/legend-server-depot';
36
29
  import type { Entity } from '@finos/legend-storage';
37
- import { deserialize } from 'serializr';
38
30
  import type { LegendMarketplaceBaseStore } from '../stores/LegendMarketplaceBaseStore.js';
39
31
 
40
32
  export const buildGraphForDataProduct = async (
@@ -77,74 +69,3 @@ export const buildGraphForDataProduct = async (
77
69
  );
78
70
  }
79
71
  };
80
-
81
- export const getDataProductFromDetails = async (
82
- details: V1_EntitlementsDataProductDetails,
83
- graphManager: V1_PureGraphManager,
84
- marketplaceBaseStore: LegendMarketplaceBaseStore,
85
- ): Promise<V1_DataProduct | undefined> => {
86
- if (details.origin instanceof V1_SdlcDeploymentDataProductOrigin) {
87
- const rawEntities =
88
- (await marketplaceBaseStore.depotServerClient.getVersionEntities(
89
- details.origin.group,
90
- details.origin.artifact,
91
- resolveVersion(details.origin.version),
92
- CORE_PURE_PATH.DATA_PRODUCT,
93
- )) as {
94
- artifactId: string;
95
- entity: Entity;
96
- groupId: string;
97
- versionId: string;
98
- versionedEntity: boolean;
99
- }[];
100
- const entities = rawEntities.map((entity) =>
101
- deserialize(
102
- V1_dataProductModelSchema(
103
- graphManager.pluginManager.getPureProtocolProcessorPlugins(),
104
- ),
105
- entity.entity.content,
106
- ),
107
- );
108
- const matchingEntities = entities.filter(
109
- (entity) => entity.name.toLowerCase() === details.id.toLowerCase(),
110
- );
111
- if (matchingEntities.length === 0) {
112
- throw new Error(
113
- `No data product found with name ${details.id} in project`,
114
- );
115
- } else if (matchingEntities.length > 1) {
116
- throw new Error(
117
- `Multiple data products found with name ${details.id} in project`,
118
- );
119
- }
120
- return matchingEntities[0];
121
- } else if (details.origin instanceof V1_AdHocDeploymentDataProductOrigin) {
122
- const entities: Entity[] = await graphManager.pureCodeToEntities(
123
- details.origin.definition,
124
- );
125
- const elements = entities
126
- .filter((e) => e.classifierPath === CORE_PURE_PATH.DATA_PRODUCT)
127
- .map((entity) =>
128
- deserialize(
129
- V1_dataProductModelSchema(
130
- graphManager.pluginManager.getPureProtocolProcessorPlugins(),
131
- ),
132
- entity.content,
133
- ),
134
- );
135
- const matchingEntities = elements.filter(
136
- (element) => element.name.toLowerCase() === details.id.toLowerCase(),
137
- );
138
- if (matchingEntities.length > 1) {
139
- throw new Error(
140
- `Multiple data products found with name ${details.id} in deployed definition`,
141
- );
142
- }
143
- return guaranteeNonNullable(
144
- matchingEntities[0],
145
- `No data product found with name ${details.id} in deployed definition`,
146
- );
147
- } else {
148
- return undefined;
149
- }
150
- };
package/tsconfig.json CHANGED
@@ -63,6 +63,7 @@
63
63
  "./src/application/__test-utils__/LegendMarketplaceApplicationTestUtils.ts",
64
64
  "./src/application/extensions/Core_LegendMarketplace_LegendApplicationPlugin.ts",
65
65
  "./src/components/ProviderCard/orderProfileUtils.ts",
66
+ "./src/components/__test-utils__/TEST_DATA__ContractErrors.ts",
66
67
  "./src/components/__test-utils__/TEST_DATA__DataAPIs.ts",
67
68
  "./src/components/__test-utils__/TEST_DATA__LakehouseData.ts",
68
69
  "./src/components/__test-utils__/TEST_DATA__LakehouseSearchResultData.ts",