@finos/legend-application-marketplace
Version:
Legend Marketplace application core
948 lines (910 loc) • 34.7 kB
text/typescript
/**
* 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.');
}
}