UNPKG

@finos/legend-application-marketplace

Version:
948 lines (910 loc) 34.7 kB
/** * Copyright (c) 2020-present, Goldman Sachs * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import { DEFAULT_TAB_SIZE, type CommandRegistrar, } from '@finos/legend-application'; import { DepotScope, isSnapshotVersion, projectIdHandlerFunc, resolveVersion, StoredSummaryEntity, StoreProjectData, VersionedProjectData, type DepotServerClient, } from '@finos/legend-server-depot'; import { action, computed, flow, makeObservable, observable } from 'mobx'; import type { LegendMarketplaceApplicationStore, LegendMarketplaceBaseStore, } from '../LegendMarketplaceBaseStore.js'; import { ActionState, assertErrorThrown, guaranteeNonNullable, guaranteeType, isNonNullable, type GeneratorFn, type PlainObject, } from '@finos/legend-shared'; import { type V1_IngestEnvironment, buildDataProductArtifactGeneration, CORE_PURE_PATH, DataProductArtifactGeneration, GraphDataWithOrigin, GraphManagerState, InMemoryGraphData, LegendSDLC, V1_AppDirLevel, V1_DataProduct, V1_DataProductArtifactGeneration, V1_dataProductModelSchema, V1_deserializeIngestEnvironment, V1_deserializePackageableElement, V1_IngestEnvironmentClassification, V1_PureGraphManager, V1_SandboxDataProductDeploymentResponse, } from '@finos/legend-graph'; import { deserialize } from 'serializr'; import { GAV_DELIMITER, generateGAVCoordinates, parseGAVCoordinates, type Entity, type StoredFileGeneration, } from '@finos/legend-storage'; import { DataProductViewerState } from './DataProductViewerState.js'; import { EXTERNAL_APPLICATION_NAVIGATION__generateIngestEnvironemntUrl, EXTERNAL_APPLICATION_NAVIGATION__generateStudioSDLCProjectViewUrl, } from '../../__lib__/LegendMarketplaceNavigation.js'; import type { AuthContextProps } from 'react-oidc-context'; import type { LakehouseContractServerClient } from '@finos/legend-server-marketplace'; import { DataProductEntity, DataProductState, SandboxDataProductState, type BaseDataProductState, } from './dataProducts/DataProducts.js'; import { TMP__DummyDataProducts } from '../../pages/Lakehouse/TMP__Data/TMP__DummyDataProducts.js'; import { type LakehousePlatformServerClient, type LakehouseIngestServerClient, IngestDeploymentServerConfig, } from '@finos/legend-server-lakehouse'; import { LegendMarketplaceUserDataHelper } from '../../__lib__/LegendMarketplaceUserDataHelper.js'; const ARTIFACT_GENERATION_DAT_PRODUCT_KEY = 'dataProduct'; export enum DataProductFilterType { DEPLOY_TYPE = 'DEPLOY_TYPE', ENVIRONMENT_CLASSIFICATION = 'ENVIRONMENT_CLASSIFICATION', } export enum DeployType { SDLC = 'SDLC', SANDBOX = 'SANDBOX', } export interface DataProductFilterConfig { sdlcDeployFilter: boolean; sandboxDeployFilter: boolean; devEnvironmentClassificationFilter: boolean; prodParallelEnvironmentClassificationFilter: boolean; prodEnvironmentClassificationFilter: boolean; } class DataProductFilters { sdlcDeployFilter: boolean; sandboxDeployFilter: boolean; devEnvironmentClassificationFilter: boolean; prodParallelEnvironmentClassificationFilter: boolean; prodEnvironmentClassificationFilter: boolean; search?: string | undefined; constructor( defaultBooleanFilters: DataProductFilterConfig, search?: string | undefined, ) { makeObservable(this, { sdlcDeployFilter: observable, sandboxDeployFilter: observable, devEnvironmentClassificationFilter: observable, prodParallelEnvironmentClassificationFilter: observable, prodEnvironmentClassificationFilter: observable, search: observable, }); this.sdlcDeployFilter = defaultBooleanFilters.sdlcDeployFilter; this.sandboxDeployFilter = defaultBooleanFilters.sandboxDeployFilter; this.devEnvironmentClassificationFilter = defaultBooleanFilters.devEnvironmentClassificationFilter; this.prodParallelEnvironmentClassificationFilter = defaultBooleanFilters.prodParallelEnvironmentClassificationFilter; this.prodEnvironmentClassificationFilter = defaultBooleanFilters.prodEnvironmentClassificationFilter; this.search = search; } static default(): DataProductFilters { return new DataProductFilters( { sdlcDeployFilter: true, sandboxDeployFilter: true, devEnvironmentClassificationFilter: false, prodParallelEnvironmentClassificationFilter: false, prodEnvironmentClassificationFilter: true, }, undefined, ); } get currentFilterValues(): DataProductFilterConfig { return { sdlcDeployFilter: this.sdlcDeployFilter, sandboxDeployFilter: this.sandboxDeployFilter, devEnvironmentClassificationFilter: this.devEnvironmentClassificationFilter, prodParallelEnvironmentClassificationFilter: this.prodParallelEnvironmentClassificationFilter, prodEnvironmentClassificationFilter: this.prodEnvironmentClassificationFilter, }; } } export enum DataProductSort { NAME_ALPHABETICAL = 'Name A-Z', NAME_REVERSE_ALPHABETICAL = 'Name Z-A', } export class MarketplaceLakehouseStore implements CommandRegistrar { readonly marketplaceBaseStore: LegendMarketplaceBaseStore; readonly applicationStore: LegendMarketplaceApplicationStore; readonly depotServerClient: DepotServerClient; readonly lakehouseContractServerClient: LakehouseContractServerClient; readonly lakehousePlatformServerClient: LakehousePlatformServerClient; readonly lakehouseIngestServerClient: LakehouseIngestServerClient; // To consolidate all versions of a data product, we use a map from group:artifact:path to a DataProductState object, which contains // a map of all the verions of the data product. productStatesMap: Map<string, DataProductState>; lakehouseIngestEnvironmentSummaries: IngestDeploymentServerConfig[] = []; lakehouseIngestEnvironmentsByDID: Map<string, IngestDeploymentServerConfig> = new Map<string, IngestDeploymentServerConfig>(); lakehouseIngestEnvironmentDetails: V1_IngestEnvironment[] = []; sandboxDataProductStates: SandboxDataProductState[] = []; loadingProductsState = ActionState.create(); loadingLakehouseEnvironmentSummariesState = ActionState.create(); loadingLakehouseEnvironmentsByDIDState = ActionState.create(); loadingLakehouseEnvironmentDetailsState = ActionState.create(); loadingSandboxDataProductStates = ActionState.create(); filter: DataProductFilters; sort: DataProductSort = DataProductSort.NAME_ALPHABETICAL; dataProductViewer: DataProductViewerState | undefined; // Temporary state for dummy data products dummyDataProductStates: DataProductState[] = TMP__DummyDataProducts.map( (dataProduct) => { const dataProductEntity = new DataProductEntity( '', '', '1.0', dataProduct.path, ); dataProductEntity.setProduct(dataProduct); const dataProductState = new DataProductState(this); dataProductState.setProductEntity('1.0', dataProductEntity); dataProductState.setSelectedVersion('1.0'); return dataProductState; }, ); constructor( marketplaceBaseStore: LegendMarketplaceBaseStore, lakehouseServerClient: LakehouseContractServerClient, lakehousePlatformServerClient: LakehousePlatformServerClient, lakehouseIngestServerClient: LakehouseIngestServerClient, depotServerClient: DepotServerClient, ) { this.marketplaceBaseStore = marketplaceBaseStore; this.applicationStore = marketplaceBaseStore.applicationStore; this.lakehouseContractServerClient = lakehouseServerClient; this.lakehousePlatformServerClient = lakehousePlatformServerClient; this.lakehouseIngestServerClient = lakehouseIngestServerClient; this.depotServerClient = depotServerClient; this.productStatesMap = new Map<string, DataProductState>(); const savedFilterConfig = LegendMarketplaceUserDataHelper.getSavedDataProductFilterConfig( this.applicationStore.userDataService, ); this.filter = savedFilterConfig ? new DataProductFilters(savedFilterConfig, undefined) : DataProductFilters.default(); makeObservable(this, { init: flow, initWithProduct: flow, initWithSandboxProduct: flow, productStatesMap: observable, sandboxDataProductStates: observable, lakehouseIngestEnvironmentSummaries: observable, lakehouseIngestEnvironmentsByDID: observable, lakehouseIngestEnvironmentDetails: observable, dataProductViewer: observable, handleFilterChange: action, handleSearch: action, filterSortProducts: computed, setDataProductViewerState: action, setLakehouseIngestEnvironmentSummaries: action, setLakehouseIngestEnvironmentsByDID: action, setLakehouseIngestEnvironmentDetails: action, setSandboxDataProductStates: action, filter: observable, sort: observable, setSort: action, }); } get filterSortProducts(): BaseDataProductState[] | undefined { return ( Array.from(this.productStatesMap.values()) as BaseDataProductState[] ) .concat( this.loadingLakehouseEnvironmentsByDIDState.isInProgress ? [] : this.sandboxDataProductStates, ) .concat(this.dummyDataProductStates) .filter((baseDataProductState) => { if (!baseDataProductState.isInitialized) { return false; } // Check if product matches deploy type filter const deployMatch = (this.filter.sdlcDeployFilter && baseDataProductState instanceof DataProductState) || (this.filter.sandboxDeployFilter && baseDataProductState instanceof SandboxDataProductState) || // TMP always include dummy data products (baseDataProductState instanceof DataProductState && this.dummyDataProductStates.includes(baseDataProductState)); // Check if product matches environment classification filter const environmentClassification = baseDataProductState instanceof SandboxDataProductState && baseDataProductState.dataProductArtifact?.dataProduct.deploymentId ? baseDataProductState.state.lakehouseIngestEnvironmentsByDID.get( baseDataProductState.dataProductArtifact.dataProduct .deploymentId, )?.environmentClassification : undefined; const environmentClassificationMatch = environmentClassification === undefined || (this.filter.devEnvironmentClassificationFilter && environmentClassification === V1_IngestEnvironmentClassification.DEV) || (this.filter.prodParallelEnvironmentClassificationFilter && environmentClassification === V1_IngestEnvironmentClassification.PROD_PARALLEL) || (this.filter.prodEnvironmentClassificationFilter && environmentClassification === V1_IngestEnvironmentClassification.PROD); // Check if product title matches search filter const dataProductTitle = baseDataProductState.title; const titleMatch = this.filter.search === undefined || this.filter.search === '' || dataProductTitle .toLowerCase() .includes(this.filter.search.toLowerCase()); return deployMatch && environmentClassificationMatch && titleMatch; }) .sort((a, b) => { if (this.sort === DataProductSort.NAME_ALPHABETICAL) { return a.title.localeCompare(b.title); } else { return b.title.localeCompare(a.title); } }); } setLakehouseIngestEnvironmentSummaries( summaries: IngestDeploymentServerConfig[], ): void { this.lakehouseIngestEnvironmentSummaries = summaries; } setLakehouseIngestEnvironmentsByDID( environmentsByDID: Map<string, IngestDeploymentServerConfig>, ): void { this.lakehouseIngestEnvironmentsByDID = environmentsByDID; } setLakehouseIngestEnvironmentDetails( environmentDetails: V1_IngestEnvironment[], ): void { this.lakehouseIngestEnvironmentDetails = environmentDetails; } setSandboxDataProductStates( sandboxDataProductStates: SandboxDataProductState[], ): void { this.sandboxDataProductStates = sandboxDataProductStates; } setDataProductViewerState(val: DataProductViewerState | undefined): void { this.dataProductViewer = val; } handleFilterChange( filterType: DataProductFilterType, val: DeployType | V1_IngestEnvironmentClassification | undefined, ): void { if (filterType === DataProductFilterType.DEPLOY_TYPE) { if (val === DeployType.SDLC) { this.filter.sdlcDeployFilter = !this.filter.sdlcDeployFilter; } else if (val === DeployType.SANDBOX) { this.filter.sandboxDeployFilter = !this.filter.sandboxDeployFilter; } } else { if (val === V1_IngestEnvironmentClassification.DEV) { this.filter.devEnvironmentClassificationFilter = !this.filter.devEnvironmentClassificationFilter; } else if (val === V1_IngestEnvironmentClassification.PROD_PARALLEL) { this.filter.prodParallelEnvironmentClassificationFilter = !this.filter.prodParallelEnvironmentClassificationFilter; } else if (val === V1_IngestEnvironmentClassification.PROD) { this.filter.prodEnvironmentClassificationFilter = !this.filter.prodEnvironmentClassificationFilter; } } LegendMarketplaceUserDataHelper.saveDataProductFilterConfig( this.applicationStore.userDataService, this.filter.currentFilterValues, ); } handleSearch(query: string | undefined) { this.filter.search = query; } setSort(sort: DataProductSort): void { this.sort = sort; } async fetchDataProducts(): Promise<void> { try { this.loadingProductsState.inProgress(); // we will show both released and snapshot versions for now to support deployment via workspaces const dataProductEntitySummaries = ( await Promise.all([ this.depotServerClient.getEntitiesSummaryByClassifier( CORE_PURE_PATH.DATA_PRODUCT, { scope: DepotScope.RELEASES, summary: true, }, ), this.depotServerClient.getEntitiesSummaryByClassifier( CORE_PURE_PATH.DATA_PRODUCT, { scope: DepotScope.SNAPSHOT, summary: true, }, ), ]) ) .flat() .map((e: PlainObject<StoredSummaryEntity>) => StoredSummaryEntity.serialization.fromJson(e), ); // Store summary information in the product state map dataProductEntitySummaries.forEach((entitySummary) => { const key = generateGAVCoordinates( entitySummary.groupId, entitySummary.artifactId, undefined, ) + GAV_DELIMITER + entitySummary.path; if (!this.productStatesMap.has(key)) { this.productStatesMap.set(key, new DataProductState(this)); } const productState = guaranteeNonNullable( this.productStatesMap.get(key), ); productState.setProductEntity( entitySummary.versionId, new DataProductEntity( entitySummary.groupId, entitySummary.artifactId, entitySummary.versionId, entitySummary.path, ), ); }); // Set the currentProductEntity for each product state to the latest version (or if no released versions, just pick the first snapshot version) this.productStatesMap.forEach((dataProductState) => { const productEntities = Array.from( dataProductState.productEntityMap.values(), ); const latestReleasedEntity = productEntities .filter((entity) => !isSnapshotVersion(entity.versionId)) .sort((a, b) => b.versionId.localeCompare(a.versionId))[0]; if (latestReleasedEntity) { dataProductState.setSelectedVersion(latestReleasedEntity.versionId); } else if (productEntities[0]) { dataProductState.setSelectedVersion(productEntities[0].versionId); } }); this.loadingProductsState.complete(); // Fetch the data product content for each entity summary and update the product state map. await Promise.all( // TODO: explore a different way to get data product content to avoid overloading metadata server // as the number of data products increases. dataProductEntitySummaries.map(async (entitySummary) => { const key = generateGAVCoordinates( entitySummary.groupId, entitySummary.artifactId, undefined, ) + GAV_DELIMITER + entitySummary.path; const dataProductEntity = this.productStatesMap .get(key) ?.productEntityMap.get(entitySummary.versionId); if (dataProductEntity) { dataProductEntity.loadingEntityState.inProgress(); try { const entity = await this.depotServerClient.getVersionEntity( entitySummary.groupId, entitySummary.artifactId, entitySummary.versionId, entitySummary.path, ); const dataProduct = guaranteeType( V1_deserializePackageableElement( entity.content as PlainObject<V1_DataProduct>, [], ), V1_DataProduct, ); dataProductEntity.setProduct(dataProduct); } finally { dataProductEntity.loadingEntityState.complete(); } } }), ); } catch (error) { assertErrorThrown(error); this.applicationStore.notificationService.notifyError( `Unable to load products: ${error.message}`, ); this.loadingProductsState.fail(); } } async fetchLakehouseEnvironmentSummaries( token: string | undefined, ): Promise<void> { try { this.loadingLakehouseEnvironmentSummariesState.inProgress(); const discoveryEnvironments = ( await this.lakehousePlatformServerClient.getIngestEnvironmentSummaries( token, ) ).map((e: PlainObject<IngestDeploymentServerConfig>) => IngestDeploymentServerConfig.serialization.fromJson(e), ); this.setLakehouseIngestEnvironmentSummaries(discoveryEnvironments); this.loadingLakehouseEnvironmentSummariesState.complete(); } catch (error) { assertErrorThrown(error); this.applicationStore.notificationService.notifyError( `Unable to load lakehouse environment summaries: ${error.message}`, ); this.loadingLakehouseEnvironmentSummariesState.fail(); } } async fetchLakehouseEnvironmentSummary( ingestEnvironmentUrn: string, token: string | undefined, ): Promise<IngestDeploymentServerConfig | undefined> { try { const rawResponse = await this.lakehousePlatformServerClient.getIngestEnvironmentSummary( ingestEnvironmentUrn, token, ); const response = IngestDeploymentServerConfig.serialization.fromJson(rawResponse); return response; } catch (error) { assertErrorThrown(error); this.applicationStore.notificationService.notifyError( `Unable to load lakehouse environment summary: ${error.message}`, ); return undefined; } } async fetchLakehouseEnvironmentsByDID( dids: string[], token: string | undefined, ): Promise<void> { try { this.loadingLakehouseEnvironmentsByDIDState.inProgress(); const didsAndEnvironments = await Promise.all( dids.map(async (did) => { return [ did, IngestDeploymentServerConfig.serialization.fromJson( await this.lakehousePlatformServerClient.findProducerServer( parseInt(did), V1_AppDirLevel.DEPLOYMENT, token, ), ), ] as [string, IngestDeploymentServerConfig]; }), ); const didToEnvironment = new Map<string, IngestDeploymentServerConfig>( this.lakehouseIngestEnvironmentsByDID, ); didsAndEnvironments.forEach(([did, environment]) => { didToEnvironment.set(did, environment); }); this.setLakehouseIngestEnvironmentsByDID(didToEnvironment); this.loadingLakehouseEnvironmentsByDIDState.complete(); } catch (error) { assertErrorThrown(error); this.applicationStore.notificationService.notifyError( `Unable to load lakehouse environments by DID: ${error.message}`, ); this.loadingLakehouseEnvironmentsByDIDState.fail(); } } async fetchLakehouseEnvironmentDetails( token: string | undefined, ): Promise<void> { try { this.loadingLakehouseEnvironmentDetailsState.inProgress(); const ingestEnvironments: V1_IngestEnvironment[] = await Promise.all( this.lakehouseIngestEnvironmentSummaries.map(async (discoveryEnv) => { const env = await this.lakehouseIngestServerClient.getIngestEnvironment( discoveryEnv.ingestServerUrl, token, ); return V1_deserializeIngestEnvironment(env); }), ); this.setLakehouseIngestEnvironmentDetails(ingestEnvironments); this.loadingLakehouseEnvironmentDetailsState.complete(); } catch (error) { assertErrorThrown(error); this.applicationStore.notificationService.notifyError( `Unable to load lakehouse environment details: ${error.message}`, ); this.loadingLakehouseEnvironmentSummariesState.fail(); } } async fetchSandboxDataProducts(token: string | undefined): Promise<void> { try { this.loadingSandboxDataProductStates.inProgress(); const ingestUrnsAndRawResponses: { ingestEnvironmentUrn: string; response: PlainObject<V1_SandboxDataProductDeploymentResponse>; }[] = ( await Promise.all( this.lakehouseIngestEnvironmentSummaries.map(async (env) => { try { const response = await this.lakehouseIngestServerClient.getDeployedIngestDefinitions( env.ingestServerUrl, token, ); return { ingestEnvironmentUrn: env.ingestEnvironmentUrn, response, }; } catch { return undefined; } }), ) ) .flat() .filter(isNonNullable) as { ingestEnvironmentUrn: string; response: PlainObject<V1_SandboxDataProductDeploymentResponse>; }[]; const ingestUrnsAndDataProducts = ingestUrnsAndRawResponses .map((ingestUrnAndResponse) => V1_SandboxDataProductDeploymentResponse.serialization .fromJson(ingestUrnAndResponse.response) .deployedDataProducts.map((deployedDataProduct) => ({ ingestEnvironmentUrn: ingestUrnAndResponse.ingestEnvironmentUrn, dataProduct: deployedDataProduct, })), ) .flat(); const sandboxDataProductStates: SandboxDataProductState[] = ingestUrnsAndDataProducts.map( (ingestUrlAndDataProduct) => new SandboxDataProductState( this, ingestUrlAndDataProduct.ingestEnvironmentUrn, ingestUrlAndDataProduct.dataProduct, ), ); this.setSandboxDataProductStates(sandboxDataProductStates); this.loadingSandboxDataProductStates.complete(); } catch (error) { assertErrorThrown(error); this.applicationStore.notificationService.notifyError( `Unable to fetch sandbox data products: ${error.message}`, ); this.loadingSandboxDataProductStates.fail(); } } *init(auth: AuthContextProps): GeneratorFn<void> { yield Promise.all([ (async () => { if (!this.loadingProductsState.hasCompleted) { await this.fetchDataProducts(); } })(), (async () => { if (!this.loadingLakehouseEnvironmentSummariesState.hasCompleted) { await this.fetchLakehouseEnvironmentSummaries( auth.user?.access_token, ); await Promise.all([ (async () => { await this.fetchSandboxDataProducts(auth.user?.access_token); await this.fetchLakehouseEnvironmentsByDID( this.sandboxDataProductStates .map( (state) => state.dataProductArtifact?.dataProduct.deploymentId, ) .filter(isNonNullable), auth.user?.access_token, ); })(), this.fetchLakehouseEnvironmentDetails(auth.user?.access_token), ]); } })(), ]); } *initWithProduct( gav: string, path: string, auth: AuthContextProps, ): GeneratorFn<void> { try { this.loadingProductsState.inProgress(); const projectData = VersionedProjectData.serialization.fromJson( parseGAVCoordinates(gav) as unknown as PlainObject, ); const storeProject = new StoreProjectData(); storeProject.groupId = projectData.groupId; storeProject.artifactId = projectData.artifactId; const v1DataProduct = deserialize( V1_dataProductModelSchema, ( (yield this.depotServerClient.getVersionEntity( projectData.groupId, projectData.artifactId, resolveVersion(projectData.versionId), path, )) as Entity ).content, ); const files = (yield this.depotServerClient.getGenerationFilesByType( storeProject, resolveVersion(projectData.versionId), ARTIFACT_GENERATION_DAT_PRODUCT_KEY, )) as StoredFileGeneration[]; const fileGen = files.filter((e) => e.path === v1DataProduct.path)[0] ?.file.content; let parsed: DataProductArtifactGeneration | undefined = undefined; if (fileGen) { const content: PlainObject = JSON.parse(fileGen) as PlainObject; const gen = DataProductArtifactGeneration.serialization.fromJson(content); gen.content = content; parsed = gen; } const stateViewer = new DataProductViewerState( this.applicationStore, this, new GraphManagerState( this.applicationStore.pluginManager, this.applicationStore.logService, ), this.lakehouseContractServerClient, projectData, v1DataProduct, false, parsed, { retrieveGraphData: () => { const sdlc = new LegendSDLC( projectData.groupId, projectData.artifactId, projectData.versionId, ); return new GraphDataWithOrigin(sdlc); }, viewSDLCProject: () => { return projectIdHandlerFunc( projectData.groupId, projectData.artifactId, projectData.versionId, this.depotServerClient, (projectId: string, resolvedId: string) => { const studioUrl = guaranteeNonNullable( this.applicationStore.config.studioServerUrl, 'studio url required', ); this.applicationStore.navigationService.navigator.visitAddress( EXTERNAL_APPLICATION_NAVIGATION__generateStudioSDLCProjectViewUrl( studioUrl, projectId, resolvedId, path, ), ); }, ); }, onZoneChange: undefined, }, ); this.setDataProductViewerState(stateViewer); stateViewer.fetchContracts(auth.user?.access_token); this.loadingProductsState.complete(); if (!this.loadingLakehouseEnvironmentSummariesState.hasCompleted) { yield this.fetchLakehouseEnvironmentSummaries(auth.user?.access_token); } if (!this.loadingLakehouseEnvironmentDetailsState.hasCompleted) { yield this.fetchLakehouseEnvironmentDetails(auth.user?.access_token); } } catch (error) { assertErrorThrown(error); this.applicationStore.notificationService.notifyError( `Unable to load product ${path}: ${error.message}`, ); this.loadingProductsState.fail(); } } *initWithSandboxProduct( ingestEnvironmentUrn: string, path: string, auth: AuthContextProps, ): GeneratorFn<void> { try { this.loadingProductsState.inProgress(); const ingestServerUrl: string = guaranteeNonNullable( this.lakehouseIngestEnvironmentSummaries.find( (summary) => summary.ingestEnvironmentUrn === ingestEnvironmentUrn, )?.ingestServerUrl ?? ((yield this.fetchLakehouseEnvironmentSummary( ingestEnvironmentUrn, auth.user?.access_token, ))?.ingestServerUrl as string), `Unable to find ingest server URL for environment ${ingestEnvironmentUrn}`, ); const rawSandboxDataProductResponse: PlainObject<V1_SandboxDataProductDeploymentResponse> = (yield this.lakehouseIngestServerClient.getDeployedIngestDefinitions( ingestServerUrl, auth.user?.access_token, )) as PlainObject<V1_SandboxDataProductDeploymentResponse>; const sandboxDataProduct = guaranteeNonNullable( V1_SandboxDataProductDeploymentResponse.serialization .fromJson(rawSandboxDataProductResponse) .deployedDataProducts.find( (dataProduct) => dataProduct.artifact.dataProduct.path === path, ), `Unable to find data product ${path} deployed at ${ingestServerUrl}`, ); yield Promise.all([ (async () => { const graphManager = new V1_PureGraphManager( this.applicationStore.pluginManager, this.applicationStore.logService, this.marketplaceBaseStore.remoteEngine, ); await graphManager.initialize( { env: this.applicationStore.config.env, tabSize: DEFAULT_TAB_SIZE, clientConfig: { baseUrl: this.applicationStore.config.engineServerUrl, }, }, { engine: this.marketplaceBaseStore.remoteEngine }, ); const graphManagerState = new GraphManagerState( this.applicationStore.pluginManager, this.applicationStore.logService, ); const entities: Entity[] = await graphManager.pureCodeToEntities( sandboxDataProduct.definition, ); await graphManager.buildGraph( graphManagerState.graph, entities, ActionState.create(), ); const v1_DataProduct = guaranteeType( guaranteeNonNullable( graphManager.elementToProtocol( graphManagerState.graph.getElement( sandboxDataProduct.artifact.dataProduct.path, ), ), `Unable to find ${sandboxDataProduct.artifact.dataProduct.path} in deployed definition`, ), V1_DataProduct, `${sandboxDataProduct.artifact.dataProduct.path} is not a data product`, ); const stateViewer = new DataProductViewerState( this.applicationStore, this, graphManagerState, this.lakehouseContractServerClient, VersionedProjectData.serialization.fromJson({ groupId: '', artifactId: '', versionId: '', }), v1_DataProduct, true, buildDataProductArtifactGeneration({ ...V1_DataProductArtifactGeneration.serialization.toJson( sandboxDataProduct.artifact, ), content: V1_DataProductArtifactGeneration.serialization.toJson( sandboxDataProduct.artifact, ), }), { retrieveGraphData: () => { return new InMemoryGraphData(graphManagerState.graph); }, viewSDLCProject: () => { throw new Error('Project does not exist in SDLC'); }, viewIngestEnvironment: () => this.applicationStore.navigationService.navigator.visitAddress( EXTERNAL_APPLICATION_NAVIGATION__generateIngestEnvironemntUrl( ingestServerUrl, ), ), }, ); this.setDataProductViewerState(stateViewer); stateViewer.fetchContracts(auth.user?.access_token); })(), this.fetchLakehouseEnvironmentsByDID( [sandboxDataProduct.artifact.dataProduct.deploymentId], auth.user?.access_token, ), ]); this.loadingProductsState.complete(); if (!this.loadingLakehouseEnvironmentSummariesState.hasCompleted) { yield this.fetchLakehouseEnvironmentSummaries(auth.user?.access_token); } if (!this.loadingLakehouseEnvironmentDetailsState.hasCompleted) { yield this.fetchLakehouseEnvironmentDetails(auth.user?.access_token); } } catch (error) { assertErrorThrown(error); this.applicationStore.notificationService.notifyError( `Unable to load product ${path}: ${error.message}`, ); this.loadingProductsState.fail(); } } registerCommands(): void { throw new Error('Method not implemented.'); } deregisterCommands(): void { throw new Error('Method not implemented.'); } }