UNPKG

@finos/legend-application-marketplace

Version:
503 lines (470 loc) 16.6 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 { createModelSchema, custom, list, optional, primitive, } from 'serializr'; import { type PlainObject, assertNonNullable, guaranteeNonEmptyString, guaranteeNonNullable, SerializationFactory, usingModelSchema, } from '@finos/legend-shared'; import { type LegendApplicationConfigurationData, type LegendApplicationConfigurationInput, LegendApplicationConfig, } from '@finos/legend-application'; import type { AuthProviderProps } from 'react-oidc-context'; import { DataProductConfig } from '@finos/legend-extension-dsl-data-product'; import { LegendMarketplaceEnv } from '../stores/LegendMarketplaceEnvState.js'; import { type LegendAIConfig, DEFAULT_LEGEND_AI_CONFIG, } from '@finos/legend-lego/legend-ai'; class LegendMarketplaceApplicationCoreOptions { dataProductConfig: DataProductConfig | undefined; newsletterUrl: string | undefined; historicalNewsletterUrl: string | undefined; generalInquiriesUrl: string | undefined; requestInternalAppUrl: string | undefined; /** * Used for any features that are still in development */ showDevFeatures = false; highlightedDataProducts: Record<string, string> | undefined; /** * Default search suggestions to show when the search bar is empty or has no autosuggest results */ defaultSearchSuggestions: string[] | undefined; /** * Default suggested queries to show in the AI chat welcome screen */ defaultAISuggestedQueries: string[] | undefined; private static readonly serialization = new SerializationFactory( createModelSchema(LegendMarketplaceApplicationCoreOptions, { dataProductConfig: optional( usingModelSchema(DataProductConfig.serialization.schema), ), newsletterUrl: optional(primitive()), showDevFeatures: optional(primitive()), highlightedDataProducts: optional( custom( (value) => value, (value) => value as Record<string, string> | undefined, ), ), historicalNewsletterUrl: optional(primitive()), generalInquiriesUrl: optional(primitive()), requestInternalAppUrl: optional(primitive()), defaultSearchSuggestions: optional(list(primitive())), defaultAISuggestedQueries: optional(list(primitive())), }), ); static create( configData: PlainObject<LegendMarketplaceApplicationCoreOptions>, ): LegendMarketplaceApplicationCoreOptions { return LegendMarketplaceApplicationCoreOptions.serialization.fromJson( configData, ); } } export interface LegendMarketplaceOidcConfig { redirectPath: string; silentRedirectPath: string; authProviderProps: AuthProviderProps; } type LegendStudioApplicationInstanceConfigurationData = { sdlcProjectIDPrefix: string; url: string; }; export interface LegendMarketplaceApplicationConfigurationData extends LegendApplicationConfigurationData { marketplace: { url: string; subscriptionUrl: string; dataProductEnv: string; adjacentEnvUrl?: string; userSearchUrl?: string | undefined; userProfileImageUrl?: string | undefined; oidcConfig?: LegendMarketplaceOidcConfig | undefined; }; depot: { url: string }; terminal: { url: string }; engine: { url: string; queryUrl?: string; }; lakehouse?: { url: string; platformUrl?: string; workflowUrl: string; permitWorkflowUrl?: string; entitlements: { applicationDirectoryUrl: string; applicationIDUrl: string; }; }; assets: { baseUrl: string; productImageMap: Record<string, string>; }; studio: { url: string; instances: LegendStudioApplicationInstanceConfigurationData[]; }; query: { url: string; }; powerBi: { url: string; }; datacube: { url: string; }; registry?: { url: string; }; legendServices?: { url: string; }; legendAI?: { enabled: boolean; llmServiceUrl?: string; llmModelName?: string; llmModelOptions?: string[]; sqlExecutionUrl?: string; orchestratorUrl?: string; orchestratorAuthToken?: string; maxJudgeAttempts?: number; lakehouseEnvironment?: string; enghubDocUrl?: string; enthubRequestAccessUrl?: string; }; } export class LegendLakehouseEntitlementsConfig { applicationDirectoryUrl: string; applicationIDUrl: string; constructor(applicationDirectoryUrl: string, applicationIDUrl: string) { this.applicationDirectoryUrl = applicationDirectoryUrl; this.applicationIDUrl = applicationIDUrl; } } export class LegendMarketplaceApplicationConfig extends LegendApplicationConfig { readonly options = new LegendMarketplaceApplicationCoreOptions(); readonly marketplaceServerUrl: string; readonly marketplaceSubscriptionUrl: string; readonly dataProductEnv: LegendMarketplaceEnv; readonly adjacentEnvUrl: string | undefined; readonly marketplaceUserSearchUrl?: string | undefined; readonly marketplaceUserProfileImageUrl?: string | undefined; readonly marketplaceOidcConfig?: LegendMarketplaceOidcConfig | undefined; readonly engineServerUrl: string; readonly registryUrl: string | undefined; readonly legendServicesUrl: string | undefined; readonly datacubeApplicationUrl: string; readonly engineQueryServerUrl?: string | undefined; readonly terminalServerUrl: string; readonly depotServerUrl: string; readonly lakehouseServerUrl: string; readonly lakehousePlatformUrl: string; readonly lakehouseWorkflowServerUrl: string; readonly lakehousePermitWorkflowServerUrl: string | undefined; readonly lakehouseEntitlementsConfig: | LegendLakehouseEntitlementsConfig | undefined; readonly studioApplicationUrl: string; readonly studioInstances: LegendStudioApplicationInstanceConfigurationData[] = []; readonly queryApplicationUrl: string; readonly powerBiUrl: string; readonly assetsBaseUrl: string; readonly assetsProductImageMap: Record<string, string>; readonly legendAIConfig: LegendAIConfig; constructor( input: LegendApplicationConfigurationInput<LegendMarketplaceApplicationConfigurationData>, ) { super(input); // marketplace assertNonNullable( input.configData.marketplace, `Can't configure application: 'marketplace' field is missing`, ); this.marketplaceServerUrl = LegendApplicationConfig.resolveAbsoluteUrl( guaranteeNonEmptyString( input.configData.marketplace.url, `Can't configure application: 'marketplace.url' field is missing or empty`, ), ); this.marketplaceSubscriptionUrl = LegendApplicationConfig.resolveAbsoluteUrl( guaranteeNonEmptyString( input.configData.marketplace.subscriptionUrl, `Can't configure application: 'marketplace.marketplaceSubscriptionUrl' field is missing or empty`, ), ); if (!input.configData.marketplace.dataProductEnv) { throw new Error( `Can't configure application: 'marketplace.dataProductEnv' field is missing or empty`, ); } switch (input.configData.marketplace.dataProductEnv) { case 'prod': this.dataProductEnv = LegendMarketplaceEnv.PRODUCTION; break; case 'prod-par': this.dataProductEnv = LegendMarketplaceEnv.PRODUCTION_PARALLEL; break; case 'dev': this.dataProductEnv = LegendMarketplaceEnv.DEVELOPMENT; break; default: throw new Error( `Can't configure application: 'marketplace.dataProductEnv' field must be 'prod', 'prod-par', or 'dev'`, ); } this.adjacentEnvUrl = input.configData.marketplace.adjacentEnvUrl; if (input.configData.marketplace.userSearchUrl) { this.marketplaceUserSearchUrl = LegendApplicationConfig.resolveAbsoluteUrl( guaranteeNonEmptyString( input.configData.marketplace.userSearchUrl, `Can't configure application: 'marketplace.userSearchUrl' field is missing or empty`, ), ); } if (input.configData.marketplace.userProfileImageUrl) { this.marketplaceUserProfileImageUrl = LegendApplicationConfig.resolveAbsoluteUrl( guaranteeNonEmptyString( input.configData.marketplace.userProfileImageUrl, `Can't configure application: 'marketplace.userProfileImageUrl' field is missing or empty`, ), ); } this.marketplaceOidcConfig = input.configData.marketplace.oidcConfig; // engine assertNonNullable( input.configData.engine, `Can't configure application: 'engine' field is missing`, ); this.engineServerUrl = LegendApplicationConfig.resolveAbsoluteUrl( guaranteeNonEmptyString( input.configData.engine.url, `Can't configure application: 'engine.url' field is missing or empty`, ), ); if (input.configData.engine.queryUrl) { this.engineQueryServerUrl = LegendApplicationConfig.resolveAbsoluteUrl( input.configData.engine.queryUrl, ); } // depot assertNonNullable( input.configData.depot, `Can't configure application: 'depot' field is missing`, ); this.depotServerUrl = LegendApplicationConfig.resolveAbsoluteUrl( guaranteeNonEmptyString( input.configData.depot.url, `Can't configure application: 'depot.url' field is missing or empty`, ), ); // Terminal assertNonNullable( input.configData.terminal, `Can't configure application: 'terminal' field is missing`, ); this.terminalServerUrl = LegendApplicationConfig.resolveAbsoluteUrl( guaranteeNonEmptyString( input.configData.terminal.url, `Can't configure application: 'terminal.url' field is missing or empty`, ), ); // assets assertNonNullable( input.configData.assets, `Can't configure application: 'assets' field is missing`, ); this.assetsBaseUrl = guaranteeNonEmptyString( input.configData.assets.baseUrl, `Can't configure application: 'assets.baseUrl' field is missing or empty`, ); this.assetsProductImageMap = guaranteeNonNullable( input.configData.assets.productImageMap, `Can't configure application: 'assets.productImageMap' field is missing`, ); // lakehouse assertNonNullable( input.configData.lakehouse, `Can't configure application: 'lakehouse' field is missing`, ); this.lakehouseServerUrl = LegendApplicationConfig.resolveAbsoluteUrl( guaranteeNonEmptyString( input.configData.lakehouse.url, `Can't configure application: 'lakehouse.url' field is missing or empty`, ), ); this.lakehousePlatformUrl = LegendApplicationConfig.resolveAbsoluteUrl( guaranteeNonEmptyString( input.configData.lakehouse.platformUrl, `Can't configure application: 'lakehouse.platformUrl' field is missing or empty`, ), ); this.lakehouseWorkflowServerUrl = LegendApplicationConfig.resolveAbsoluteUrl( guaranteeNonEmptyString( input.configData.lakehouse.workflowUrl, `Can't configure application: 'lakehouse.workflowUrl' field is missing or empty`, ), ); this.lakehousePermitWorkflowServerUrl = input.configData.lakehouse .permitWorkflowUrl ? LegendApplicationConfig.resolveAbsoluteUrl( input.configData.lakehouse.permitWorkflowUrl, ) : undefined; this.lakehouseEntitlementsConfig = new LegendLakehouseEntitlementsConfig( guaranteeNonEmptyString( input.configData.lakehouse.entitlements.applicationDirectoryUrl, `Can't configure application: 'lakehouse.entitlements.applicationDirectoryUrl' field is missing or empty`, ), guaranteeNonEmptyString( input.configData.lakehouse.entitlements.applicationIDUrl, `Can't configure application: 'lakehouse.entitlements.applicationIDUrl' field is missing or empty`, ), ); // studio assertNonNullable( input.configData.studio, `Can't configure application: 'studio' field is missing`, ); this.studioApplicationUrl = LegendApplicationConfig.resolveAbsoluteUrl( guaranteeNonEmptyString( input.configData.studio.url, `Can't configure application: 'studio.url' field is missing or empty`, ), ); this.studioInstances = guaranteeNonNullable( input.configData.studio.instances, `Can't configure application: 'studio.instances' field is missing`, ); // query assertNonNullable( input.configData.query, `Can't configure application: 'query' field is missing`, ); this.queryApplicationUrl = LegendApplicationConfig.resolveAbsoluteUrl( guaranteeNonEmptyString( input.configData.query.url, `Can't configure application: 'query.url' field is missing or empty`, ), ); // datacube assertNonNullable( input.configData.datacube, `Can't configure application: 'datacube' field is missing`, ); this.datacubeApplicationUrl = LegendApplicationConfig.resolveAbsoluteUrl( guaranteeNonEmptyString( input.configData.datacube.url, `Can't configure application: 'datacube.url' field is missing or empty`, ), ); // Power BI assertNonNullable( input.configData.powerBi, `Can't configure application: 'powerBi' field is missing`, ); this.powerBiUrl = LegendApplicationConfig.resolveAbsoluteUrl( guaranteeNonEmptyString( input.configData.powerBi.url, `Can't configure application: 'powerBi.url' field is missing or empty`, ), ); // registry if (input.configData.registry?.url) { this.registryUrl = LegendApplicationConfig.resolveAbsoluteUrl( input.configData.registry.url, ); } // Legend services if (input.configData.legendServices?.url) { this.legendServicesUrl = LegendApplicationConfig.resolveAbsoluteUrl( input.configData.legendServices.url, ); } this.legendAIConfig = LegendMarketplaceApplicationConfig.buildLegendAIConfig( input.configData.legendAI, this.marketplaceServerUrl, this.engineServerUrl, this.dataProductEnv, ); // options this.options = LegendMarketplaceApplicationCoreOptions.create( input.configData.extensions?.core ?? {}, ); } private static buildLegendAIConfig( legendAIData: LegendMarketplaceApplicationConfigurationData['legendAI'], marketplaceSearchUrl: string, engineServerUrl: string, dataProductEnv: LegendMarketplaceEnv, ): LegendAIConfig { if (!legendAIData) { return DEFAULT_LEGEND_AI_CONFIG; } return { ...DEFAULT_LEGEND_AI_CONFIG, enabled: legendAIData.enabled, llmServiceUrl: legendAIData.llmServiceUrl, llmModelName: legendAIData.llmModelName, ...(legendAIData.llmModelOptions === undefined ? {} : { llmModelOptions: legendAIData.llmModelOptions }), sqlExecutionUrl: legendAIData.sqlExecutionUrl, orchestratorUrl: legendAIData.orchestratorUrl ? LegendApplicationConfig.resolveAbsoluteUrl( legendAIData.orchestratorUrl, ) : undefined, marketplaceSearchUrl, engineUrl: engineServerUrl, ...(legendAIData.orchestratorAuthToken === undefined ? {} : { orchestratorAuthToken: legendAIData.orchestratorAuthToken }), ...(legendAIData.maxJudgeAttempts === undefined ? {} : { maxJudgeAttempts: legendAIData.maxJudgeAttempts }), lakehouseEnvironment: legendAIData.lakehouseEnvironment ?? dataProductEnv, ...(legendAIData.enghubDocUrl === undefined ? {} : { enghubDocUrl: legendAIData.enghubDocUrl }), ...(legendAIData.enthubRequestAccessUrl === undefined ? {} : { enthubRequestAccessUrl: legendAIData.enthubRequestAccessUrl }), }; } override getDefaultApplicationStorageKey(): string { return 'legend-marketplace'; } }