/** * 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 { type QuerySetupActionConfiguration, LegendQueryApplicationPlugin, QuerySetupActionTag, } from '../stores/LegendQueryApplicationPlugin.js'; import packageJson from '../../package.json' with { type: 'json' }; import type { QuerySetupLandingPageStore } from '../stores/QuerySetupStore.js'; import { ArrowCircleUpIcon, Button, CaretDownIcon, DroidIcon, ControlledDropdownMenu, InfoCircleIcon, ManageSearchIcon, MenuContent, MenuContentItem, MenuContentItemIcon, MenuContentItemLabel, PlusIcon, RobotIcon, SaveAsIcon, SaveCurrIcon, SquareIcon, CubeIcon, CopyIcon, MoreVerticalIcon, } from '@finos/legend-art'; import { EXTERNAL_APPLICATION_NAVIGATION__generateNewDataCubeUrl, generateCloneServiceQuerySetupRoute, generateCreateMappingQuerySetupRoute, generateEditExistingQuerySetupRoute, generateLoadProjectServiceQuerySetup, generateMappingQueryCreatorRoute, generateQueryProductionizerSetupRoute, generateUpdateExistingServiceQuerySetup, LEGEND_QUERY_ROUTE_PATTERN, } from '../__lib__/LegendQueryNavigation.js'; import { type ApplicationPageEntry, type LegendApplicationSetup, ActionAlertActionType, ActionAlertType, } from '@finos/legend-application'; import { CloneQueryServiceSetup } from './CloneQueryServiceSetup.js'; import { QueryProductionizerSetup } from './QueryProductionizerSetup.js'; import { UpdateExistingServiceQuerySetup } from './UpdateExistingServiceQuerySetup.js'; import { LoadProjectServiceQuerySetup } from './LoadProjectServiceQuerySetup.js'; import { CODE_EDITOR_LANGUAGE, setupPureLanguageService, } from '@finos/legend-code-editor'; import { generateDataSpaceQueryCreatorRoute, generateDataSpaceQuerySetupRoute, } from '../__lib__/DSL_DataSpace_LegendQueryNavigation.js'; import { type QueryBuilderState, type QueryBuilderHeaderActionConfiguration, type QueryBuilderMenuActionConfiguration, type QueryBuilderPropagateExecutionContextChangeHelper, QUERY_BUILDER_SUPPORTED_GET_ALL_FUNCTIONS, type QueryExportUsageConfiguration, type TemplateQueryPanelContentRenderer, DataProductQueryBuilderState, } from '@finos/legend-query-builder'; import { ExistingQueryEditorStore, QueryBuilderActionConfig_QueryApplication, type QueryEditorStore, } from '../stores/QueryEditorStore.js'; import { DataSpaceQueryBuilderState, generateDataSpaceTemplateQueryPromotionRoute, } from '@finos/legend-extension-dsl-data-space/application'; import { createGraphBuilderReport, GRAPH_MANAGER_EVENT, PackageableElementPointerType, resolvePackagePathAndElementName, RuntimePointer, V1_EngineRuntime, V1_Mapping, V1_PackageableElementPointer, V1_PackageableRuntime, V1_PureGraphManager, } from '@finos/legend-graph'; import { LegendQueryTelemetryHelper } from '../__lib__/LegendQueryTelemetryHelper.js'; import { StoreProjectData } from '@finos/legend-server-depot'; import { ActionState, assertErrorThrown, buildUrl, guaranteeNonNullable, guaranteeType, LogEvent, StopWatch, uniq, } from '@finos/legend-shared'; import { parseProjectIdentifier } from '@finos/legend-storage'; import { QueryEditorExistingQueryHeader } from './QueryEditor.js'; import { DataSpaceTemplateQueryCreatorStore } from '../stores/data-space/DataSpaceTemplateQueryCreatorStore.js'; import { createViewSDLCProjectHandler } from '../stores/data-space/DataSpaceQueryBuilderHelper.js'; import { DataProductQueryCreatorStore } from '../stores/data-space/DataProductQueryCreatorStore.js'; import { CodeEditor, configureCodeEditorComponent, } from '@finos/legend-lego/code-editor'; import { resolveUsableDataSpaceClasses, V1_DataSpace, V1_DataSpaceExecutionContext, } from '@finos/legend-extension-dsl-data-space/graph'; import { flowResult } from 'mobx'; import { LEGEND_QUERY_APP_EVENT } from '../__lib__/LegendQueryEvent.js'; import { observer } from 'mobx-react-lite'; import { useQueryEditorStore } from './QueryEditorStoreProvider.js'; import { useLegendQueryApplicationStore } from './LegendQueryFrameworkProvider.js'; import { LegendQueryDataSpaceQueryBuilderState } from '../stores/data-space/query-builder/LegendQueryDataSpaceQueryBuilderState.js'; import { LegendQueryDataProductQueryBuilderState } from '../stores/data-product/query-builder/LegendQueryDataProductQueryBuilderState.js'; import { IngestLegendQueryBuilderState } from '../stores/ingest/IngestLegendQueryBuilderState.js'; import { renderDataProductSampleQueryPanelContent } from './data-product/DataProductSampleQueryPanel.js'; export const QUERY_DATACUBE_USAGE_TITLE = 'Legend DataCube'; const QUERY_DATACUBE_SOURCE_TYPE = 'legendQuery'; const CopyButton: React.FC<{ onClick: () => void }> = ({ onClick }) => ( ); const MoreButton: React.FC = () => ( ); const generateDataCubeUrl = ( queryEditorStore: QueryEditorStore, ): string | undefined => { if ( queryEditorStore instanceof ExistingQueryEditorStore && queryEditorStore.query && queryEditorStore.applicationStore.config.dataCubeApplicationUrl ) { return EXTERNAL_APPLICATION_NAVIGATION__generateNewDataCubeUrl( queryEditorStore.applicationStore.config.dataCubeApplicationUrl, { _type: QUERY_DATACUBE_SOURCE_TYPE, queryId: queryEditorStore.query.id, }, ); } return undefined; }; export const QueryDataCubeUsage = observer(() => { const applicationStore = useLegendQueryApplicationStore(); const queryEditorStore = useQueryEditorStore(); const getDataCubeUrl = (): string => { const errorMsg = 'Legend DataCube URL could not be created\n\nEnsure the following:\n1)You are working with a saved query\n2)Typed TDS is enabled (Advanced > Enable Typed TDS)'; return generateDataCubeUrl(queryEditorStore) ?? errorMsg; }; return (
{ applicationStore.clipboardService .copyTextToClipboard(getDataCubeUrl()) .catch(applicationStore.alertUnhandledError); }} />
); }); export class Core_LegendQueryApplicationPlugin extends LegendQueryApplicationPlugin { static NAME = packageJson.extensions.applicationQueryPlugin; constructor() { super(Core_LegendQueryApplicationPlugin.NAME, packageJson.version); } override getExtraApplicationSetups(): LegendApplicationSetup[] { return [ async (applicationStore) => { await configureCodeEditorComponent(applicationStore); setupPureLanguageService({}); }, ]; } override getExtraApplicationPageEntries(): ApplicationPageEntry[] { return [ { key: 'clone-service-query-setup-application-page', addressPatterns: [LEGEND_QUERY_ROUTE_PATTERN.CLONE_SERVICE_QUERY_SETUP], renderer: () => , }, { key: 'query-productionizer-setup-application-page', addressPatterns: [ LEGEND_QUERY_ROUTE_PATTERN.QUERY_PRODUCTIONIZER_SETUP, ], renderer: () => , }, { key: 'update-existing-service-query-setup-application-page', addressPatterns: [ LEGEND_QUERY_ROUTE_PATTERN.UPDATE_EXISTING_SERVICE_QUERY_SETUP, ], renderer: () => , }, { key: 'load-project-service-query-setup-application-page', addressPatterns: [ LEGEND_QUERY_ROUTE_PATTERN.LOAD_PROJECT_SERVICE_QUERY_SETUP, ], renderer: () => , }, ]; } override getExtraQuerySetupActionConfigurations(): QuerySetupActionConfiguration[] { return [ { key: 'open-existing-query', isAdvanced: false, isCreateAction: false, action: async (setupStore: QuerySetupLandingPageStore) => { setupStore.applicationStore.navigationService.navigator.goToLocation( generateEditExistingQuerySetupRoute(), ); }, label: 'Open an existing query', className: 'query-setup__landing-page__action--existing-query', icon: ( ), }, { key: 'create-mapping-query', isAdvanced: true, isCreateAction: true, action: async (setupStore: QuerySetupLandingPageStore) => { setupStore.applicationStore.navigationService.navigator.goToLocation( generateCreateMappingQuerySetupRoute(), ); }, label: 'Create new query on a mapping', className: 'query-setup__landing-page__action--create-mapping-query', icon: , }, { key: 'clone-service-query', isAdvanced: true, isCreateAction: true, action: async (setupStore: QuerySetupLandingPageStore) => { setupStore.applicationStore.navigationService.navigator.goToLocation( generateCloneServiceQuerySetupRoute(), ); }, label: 'Clone an existing service query', className: 'query-setup__landing-page__action--service-query', icon: , }, // sdlc { key: 'update-existing-service-query', isAdvanced: false, isCreateAction: false, tag: QuerySetupActionTag.PRODUCTIONIZATION, action: async (setupStore: QuerySetupLandingPageStore) => { setupStore.applicationStore.navigationService.navigator.goToLocation( generateUpdateExistingServiceQuerySetup(), ); }, label: 'Update an existing service query', className: 'query-setup__landing-page__action--service-query', icon: , }, { key: 'open-project-service-query', isAdvanced: true, isCreateAction: false, tag: QuerySetupActionTag.PRODUCTIONIZATION, action: async (setupStore: QuerySetupLandingPageStore) => { setupStore.applicationStore.navigationService.navigator.goToLocation( generateLoadProjectServiceQuerySetup(), ); }, label: 'Open service query from a project', className: 'query-setup__landing-page__action--service-query', icon: , }, { key: 'productionize-query', isAdvanced: false, isCreateAction: true, tag: QuerySetupActionTag.PRODUCTIONIZATION, action: async (setupStore: QuerySetupLandingPageStore) => { setupStore.applicationStore.navigationService.navigator.goToLocation( generateQueryProductionizerSetupRoute(), ); }, label: 'Productionize an existing query', className: 'query-setup__landing-page__action--productionize-query', icon: , }, // data product { key: 'create-query-from-data-space', isAdvanced: false, isCreateAction: true, action: async (setupStore) => { setupStore.applicationStore.navigationService.navigator.goToLocation( generateDataSpaceQuerySetupRoute(), ); }, label: 'Create query from data product', className: 'query-setup__landing-page__action--data-space', icon: ( ), }, ]; } getExtraQueryUsageConfigurations(): QueryExportUsageConfiguration[] { return [ { key: QUERY_DATACUBE_USAGE_TITLE, title: QUERY_DATACUBE_USAGE_TITLE, icon: , renderer: () => , }, ]; } getExtraQueryBuilderExportMenuActionConfigurations?(): QueryBuilderMenuActionConfiguration[] { return [ { key: 'promote-as-template-query', title: 'Promote Curated Template query...', label: 'Curated Template Query', disableFunc: (queryBuilderState): boolean => { if ( queryBuilderState.workflowState.actionConfig instanceof QueryBuilderActionConfig_QueryApplication ) { const editorStore = queryBuilderState.workflowState.actionConfig.editorStore; if ( editorStore instanceof ExistingQueryEditorStore && queryBuilderState instanceof DataSpaceQueryBuilderState ) { return false; } } return true; }, onClick: (queryBuilderState): void => { if ( queryBuilderState.workflowState.actionConfig instanceof QueryBuilderActionConfig_QueryApplication ) { const editorStore = queryBuilderState.workflowState.actionConfig.editorStore; const proceedCuratedTemplateQueryPromotion = async (): Promise => { if ( !( editorStore instanceof ExistingQueryEditorStore && queryBuilderState instanceof DataSpaceQueryBuilderState ) ) { return; } // fetch project data const project = StoreProjectData.serialization.fromJson( await editorStore.depotServerClient.getProject( editorStore.lightQuery.groupId, editorStore.lightQuery.artifactId, ), ); // find the matching SDLC instance const projectIDPrefix = parseProjectIdentifier( project.projectId, ).prefix; const matchingSDLCEntry = editorStore.applicationStore.config.studioInstances.find( (entry) => entry.sdlcProjectIDPrefix === projectIDPrefix, ); if (matchingSDLCEntry) { editorStore.applicationStore.navigationService.navigator.visitAddress( buildUrl([ editorStore.applicationStore.config.studioApplicationUrl, generateDataSpaceTemplateQueryPromotionRoute( editorStore.lightQuery.groupId, editorStore.lightQuery.artifactId, editorStore.lightQuery.versionId, queryBuilderState.dataSpace.path, editorStore.lightQuery.id, ), ]), ); } else { editorStore.applicationStore.notificationService.notifyWarning( `Can't find the corresponding SDLC instance to productionize the query`, ); } }; queryBuilderState.changeDetectionState.alertUnsavedChanges(() => { proceedCuratedTemplateQueryPromotion().catch( editorStore.applicationStore.alertUnhandledError, ); }); } }, icon: , disableMessage: 'Requires saved query', }, { key: 'legend-datacube-query', title: 'Launch Legend DataCube...', label: 'Legend DataCube', disableFunc: (queryBuilderState): boolean => { if ( queryBuilderState.workflowState.actionConfig instanceof QueryBuilderActionConfig_QueryApplication ) { const editorStore = queryBuilderState.workflowState.actionConfig.editorStore; return !(editorStore instanceof ExistingQueryEditorStore); } return true; }, onClick: (queryBuilderState): void => { if ( queryBuilderState.workflowState.actionConfig instanceof QueryBuilderActionConfig_QueryApplication ) { const editorStore = queryBuilderState.workflowState.actionConfig.editorStore; const dataCubeUrl = generateDataCubeUrl(editorStore); if (dataCubeUrl) { editorStore.applicationStore.navigationService.navigator.visitAddress( dataCubeUrl, ); } if ( editorStore instanceof ExistingQueryEditorStore && editorStore.query ) { const query = editorStore.query; LegendQueryTelemetryHelper.logEvent_HostedDataCubeLaunched( editorStore.applicationStore.telemetryService, { query: { name: query.name, id: query.id, groupId: query.groupId, artifactId: query.artifactId, versionId: query.versionId, }, }, ); } } }, icon: , disableMessage: 'Requires saved query', }, ]; } getExtraQueryBuilderHelpMenuActionConfigurations?(): QueryBuilderMenuActionConfiguration[] { return [ { key: 'about-query-info', title: 'Get Query Info', label: 'About Query Info', disableFunc: (queryBuilderState): boolean => { if ( queryBuilderState.workflowState.actionConfig instanceof QueryBuilderActionConfig_QueryApplication ) { const editorStore = queryBuilderState.workflowState.actionConfig.editorStore; if (editorStore instanceof ExistingQueryEditorStore) { return false; } } return true; }, onClick: (queryBuilderState): void => { if ( queryBuilderState.workflowState.actionConfig instanceof QueryBuilderActionConfig_QueryApplication ) { const editorStore = queryBuilderState.workflowState.actionConfig.editorStore; if (editorStore instanceof ExistingQueryEditorStore) { editorStore.updateState.setShowQueryInfo(true); } } }, icon: , }, { key: 'about-query-sdlc-project', title: 'Go to Project', label: 'Go to Project', disableFunc: (queryBuilderState): boolean => { if ( queryBuilderState.workflowState.actionConfig instanceof QueryBuilderActionConfig_QueryApplication ) { const editorStore = queryBuilderState.workflowState.actionConfig.editorStore; if (editorStore instanceof ExistingQueryEditorStore) { return false; } } return true; }, onClick: (queryBuilderState): void => { if ( queryBuilderState.workflowState.actionConfig instanceof QueryBuilderActionConfig_QueryApplication ) { const editorStore = queryBuilderState.workflowState.actionConfig.editorStore; LegendQueryTelemetryHelper.logEvent_QueryViewSdlcProjectLaunched( editorStore.applicationStore.telemetryService, ); const projectInfo = editorStore.getProjectInfo(); if (projectInfo) { const { groupId, artifactId } = projectInfo; createViewSDLCProjectHandler( editorStore.applicationStore, editorStore.depotServerClient, )(groupId, artifactId, undefined).catch( editorStore.applicationStore.alertUnhandledError, ); } } }, icon: , }, { key: 'about-legend-query', title: 'About Legend Query', label: 'About Legend Query', onClick: (queryBuilderState): void => { if ( queryBuilderState.workflowState.actionConfig instanceof QueryBuilderActionConfig_QueryApplication ) { const editorStore = queryBuilderState.workflowState.actionConfig.editorStore; editorStore.setShowAppInfo(true); } }, icon: , }, { key: 'about-dataspace', title: 'About Data Product', label: 'About Data Product', disableFunc: (queryBuilderState): boolean => { if ( queryBuilderState.workflowState.actionConfig instanceof QueryBuilderActionConfig_QueryApplication ) { const editorStore = queryBuilderState.workflowState.actionConfig.editorStore; if ( (editorStore instanceof ExistingQueryEditorStore && queryBuilderState instanceof DataSpaceQueryBuilderState) || editorStore instanceof DataSpaceTemplateQueryCreatorStore || editorStore instanceof DataProductQueryCreatorStore || queryBuilderState instanceof DataProductQueryBuilderState ) { return false; } } return true; }, onClick: (queryBuilderState): void => { if ( queryBuilderState.workflowState.actionConfig instanceof QueryBuilderActionConfig_QueryApplication ) { const editorStore = queryBuilderState.workflowState.actionConfig.editorStore; if (queryBuilderState instanceof DataSpaceQueryBuilderState) { editorStore.setShowDataspaceInfo(true); } else if ( queryBuilderState instanceof DataProductQueryBuilderState ) { editorStore.setShowDataProductInfo(true); } } }, icon: , }, { key: 'about-ingest', title: 'About Ingest', label: 'About Ingestion Data Set', disableFunc: (queryBuilderState): boolean => !(queryBuilderState instanceof IngestLegendQueryBuilderState), onClick: (queryBuilderState): void => { if ( queryBuilderState.workflowState.actionConfig instanceof QueryBuilderActionConfig_QueryApplication && queryBuilderState instanceof IngestLegendQueryBuilderState ) { queryBuilderState.workflowState.actionConfig.editorStore.setShowIngestInfo( true, ); } }, icon: , }, ]; } getExtraQueryBuilderHeaderActionConfigurations?(): QueryBuilderHeaderActionConfiguration[] { return [ { key: 'load-query', category: 0, renderer: (queryBuilderState): React.ReactNode => { if ( queryBuilderState.workflowState.actionConfig instanceof QueryBuilderActionConfig_QueryApplication ) { const editorStore = queryBuilderState.workflowState.actionConfig.editorStore; const openQueryLoader = (): void => { editorStore.queryLoaderState.setQueryLoaderDialogOpen(true); }; return ( ); } return undefined; }, }, { key: 'new-query', category: 0, renderer: (queryBuilderState): React.ReactNode => { if ( queryBuilderState.workflowState.actionConfig instanceof QueryBuilderActionConfig_QueryApplication ) { const editorStore = queryBuilderState.workflowState.actionConfig.editorStore; const handleNewQuery = (): void => { if (editorStore instanceof ExistingQueryEditorStore) { const query = editorStore.query; if (query) { if (queryBuilderState instanceof DataSpaceQueryBuilderState) { editorStore.applicationStore.navigationService.navigator.goToLocation( generateDataSpaceQueryCreatorRoute( query.groupId, query.artifactId, query.versionId, queryBuilderState.dataSpace.path, queryBuilderState.executionContext.name, undefined, undefined, ), ); } else { const mapping = editorStore.queryBuilderState?.executionContextState .mapping; const runtime = editorStore.queryBuilderState?.executionContextState .runtimeValue; if (mapping && runtime instanceof RuntimePointer) { editorStore.applicationStore.navigationService.navigator.goToLocation( generateMappingQueryCreatorRoute( query.groupId, query.artifactId, query.versionId, mapping.path, runtime.packageableRuntime.value.path, ), ); } } } } else { if ( queryBuilderState.changeHistoryState.canUndo || queryBuilderState.changeHistoryState.canRedo ) { queryBuilderState.applicationStore.alertService.setActionAlertInfo( { message: 'Current query will be lost when creating a new query. Do you still want to proceed?', type: ActionAlertType.CAUTION, actions: [ { label: 'Proceed', type: ActionAlertActionType.PROCEED_WITH_CAUTION, handler: queryBuilderState.applicationStore.guardUnhandledError( async () => { queryBuilderState.resetQueryContent(); queryBuilderState.setGetAllFunction( QUERY_BUILDER_SUPPORTED_GET_ALL_FUNCTIONS.GET_ALL, ); queryBuilderState.milestoningState.updateMilestoningConfiguration(); }, ), }, { label: 'Cancel', type: ActionAlertActionType.PROCEED, default: true, }, ], }, ); } else { queryBuilderState.resetQueryContent(); queryBuilderState.setGetAllFunction( QUERY_BUILDER_SUPPORTED_GET_ALL_FUNCTIONS.GET_ALL, ); queryBuilderState.milestoningState.updateMilestoningConfiguration(); } } }; return ( ); } return undefined; }, }, { key: 'save-combo', category: 0, renderer: (queryBuilderState): React.ReactNode => { if ( queryBuilderState.workflowState.actionConfig instanceof QueryBuilderActionConfig_QueryApplication ) { const editorStore = queryBuilderState.workflowState.actionConfig.editorStore; const openSaveQueryModal = (): void => { if (editorStore.canPersistToSavedQuery) { if (editorStore instanceof ExistingQueryEditorStore) { editorStore.updateState.showSaveModal(); } else { editorStore.queryCreatorState.open(undefined); } } }; const handleQuerySaveAs = (): void => { if (editorStore.canPersistToSavedQuery) { editorStore.queryCreatorState.open( editorStore instanceof ExistingQueryEditorStore ? editorStore.query : undefined, ); } }; return (
Save As New Query } >
); } return undefined; }, }, ]; } getExtraQueryBuilderHeaderTitleConfigurations?(): QueryBuilderHeaderActionConfiguration { return { key: 'query-title', category: 0, renderer: (queryBuilderState): React.ReactNode => { if ( queryBuilderState.workflowState.actionConfig instanceof QueryBuilderActionConfig_QueryApplication ) { const editorStore = queryBuilderState.workflowState.actionConfig.editorStore; const renderQueryTitle = (): React.ReactNode => { if (editorStore instanceof ExistingQueryEditorStore) { return ( ); } else if ( editorStore instanceof DataSpaceTemplateQueryCreatorStore ) { return (
{editorStore.templateQueryTitle}
template
); } return (
Unsaved Query
); }; return (
{renderQueryTitle()}
); } return undefined; }, }; } getExtraQueryBuilderPropagateExecutionContextChangeHelper?(): QueryBuilderPropagateExecutionContextChangeHelper[] { return [ ( queryBuilderState: QueryBuilderState, isGraphBuildingNotRequired?: boolean, ): (() => Promise) | undefined => { /** * Propagation after changing the execution context: * - The mapping will be updated to the mapping of the execution context * - The runtime will be updated to the default runtime of the execution context * - If no class is chosen, try to choose a compatible class * - If the chosen class is compatible with the new selected execution context mapping, do nothing, otherwise, try to choose a compatible class */ const propagateExecutionContextChange = async (): Promise => { const dataSpaceQueryBuilderState = guaranteeType( queryBuilderState, DataSpaceQueryBuilderState, ); const mapping = dataSpaceQueryBuilderState.executionContext.mapping.value; const mappingModelCoverageAnalysisResult = dataSpaceQueryBuilderState.dataSpaceAnalysisResult?.mappingToMappingCoverageResult?.get( mapping.path, ); const editorStore = ( queryBuilderState.workflowState .actionConfig as QueryBuilderActionConfig_QueryApplication ).editorStore; if ( dataSpaceQueryBuilderState.dataSpaceAnalysisResult && mappingModelCoverageAnalysisResult ) { if ( !isGraphBuildingNotRequired && dataSpaceQueryBuilderState.isLightGraphEnabled ) { const supportBuildMinimalGraph = editorStore.applicationStore.config.options .TEMPORARY__enableMinimalGraph; if ( editorStore.enableMinialGraphForDataSpaceLoadingPerformance && supportBuildMinimalGraph ) { try { const stopWatch = new StopWatch(); const graph = dataSpaceQueryBuilderState.graphManagerState.createNewGraph(); const graph_buildReport = createGraphBuilderReport(); const graphManager = guaranteeType( dataSpaceQueryBuilderState.graphManagerState.graphManager, V1_PureGraphManager, ); // Create dummy mappings and runtimes // TODO?: these stubbed mappings and runtimes are not really useful that useful, so either we should // simplify the model here or potentially refactor the backend analytics endpoint to return these as model const mappingModels = uniq( Array.from( dataSpaceQueryBuilderState.dataSpaceAnalysisResult.executionContextsIndex.values(), ).map((context) => context.mapping), ).map((m) => { const _mapping = new V1_Mapping(); const [packagePath, name] = resolvePackagePathAndElementName(m.path); _mapping.package = packagePath; _mapping.name = name; return graphManager.elementProtocolToEntity(_mapping); }); const runtimeModels = uniq( Array.from( dataSpaceQueryBuilderState.dataSpaceAnalysisResult.executionContextsIndex.values(), ) .map((context) => context.defaultRuntime) .concat( Array.from( dataSpaceQueryBuilderState.dataSpaceAnalysisResult.executionContextsIndex.values(), ).flatMap((val) => val.compatibleRuntimes), ), ).map((r) => { const runtime = new V1_PackageableRuntime(); const [packagePath, name] = resolvePackagePathAndElementName(r.path); runtime.package = packagePath; runtime.name = name; runtime.runtimeValue = new V1_EngineRuntime(); return graphManager.elementProtocolToEntity(runtime); }); // The Data Product entity is excluded from AnalyticsResult.Json to reduce the JSON size // because all its information can be found in V1_DataSpaceAnalysisResult. // Therefore, we are building a simple v1_DataSpace entity based on V1_DataSpaceAnalysisResult. const dataspaceProtocol = new V1_DataSpace(); dataspaceProtocol.name = dataSpaceQueryBuilderState.dataSpaceAnalysisResult.name; dataspaceProtocol.package = dataSpaceQueryBuilderState.dataSpaceAnalysisResult.package; dataspaceProtocol.supportInfo = dataSpaceQueryBuilderState.dataSpaceAnalysisResult.supportInfo; dataspaceProtocol.executionContexts = Array.from( dataSpaceQueryBuilderState.dataSpaceAnalysisResult .executionContextsIndex, ).map(([key, execContext]) => { const contextProtocol = new V1_DataSpaceExecutionContext(); contextProtocol.name = execContext.name; contextProtocol.title = execContext.title; contextProtocol.description = execContext.description; contextProtocol.mapping = new V1_PackageableElementPointer( PackageableElementPointerType.MAPPING, execContext.mapping.path, ); contextProtocol.defaultRuntime = new V1_PackageableElementPointer( PackageableElementPointerType.RUNTIME, execContext.defaultRuntime.path, ); return contextProtocol; }); dataspaceProtocol.defaultExecutionContext = dataSpaceQueryBuilderState.dataSpaceAnalysisResult.defaultExecutionContext.name; dataspaceProtocol.title = dataSpaceQueryBuilderState.dataSpaceAnalysisResult.title; dataspaceProtocol.description = dataSpaceQueryBuilderState.dataSpaceAnalysisResult.description; const dataspaceEntity = graphManager.elementProtocolToEntity(dataspaceProtocol); const graphEntities = guaranteeNonNullable( mappingModelCoverageAnalysisResult.entities, ) .concat(mappingModels) .concat(runtimeModels) .concat(dataspaceEntity) // NOTE: if an element could be found in the graph already it means it comes from system // so we could rid of it .filter( (el) => !graph.getNullableElement(el.path, false) && !el.path.startsWith('meta::'), ); let option; if ( dataSpaceQueryBuilderState instanceof LegendQueryDataSpaceQueryBuilderState ) { option = dataSpaceQueryBuilderState.sdlc; } await dataSpaceQueryBuilderState.graphManagerState.graphManager.buildGraph( graph, graphEntities, ActionState.create(), option ? { origin: option, } : {}, graph_buildReport, ); dataSpaceQueryBuilderState.graphManagerState.graph = graph; const dependency_buildReport = createGraphBuilderReport(); // report stopWatch.record( GRAPH_MANAGER_EVENT.INITIALIZE_GRAPH__SUCCESS, ); const graphBuilderReportData = { timings: dataSpaceQueryBuilderState.applicationStore.timeService.finalizeTimingsRecord( stopWatch, ), dependencies: dependency_buildReport, dependenciesCount: dataSpaceQueryBuilderState.graphManagerState.graph .dependencyManager.numberOfDependencies, graph: graph_buildReport, }; editorStore.logBuildGraphMetrics(graphBuilderReportData); dataSpaceQueryBuilderState.applicationStore.logService.info( LogEvent.create( GRAPH_MANAGER_EVENT.INITIALIZE_GRAPH__SUCCESS, ), graphBuilderReportData, ); } catch (error) { assertErrorThrown(error); editorStore.applicationStore.logService.error( LogEvent.create(LEGEND_QUERY_APP_EVENT.GENERIC_FAILURE), error, ); editorStore.graphManagerState.graph = editorStore.graphManagerState.createNewGraph(); await flowResult(editorStore.buildFullGraph()); } } else { editorStore.graphManagerState.graph = editorStore.graphManagerState.createNewGraph(); await flowResult(editorStore.buildFullGraph()); } } dataSpaceQueryBuilderState.explorerState.mappingModelCoverageAnalysisResult = mappingModelCoverageAnalysisResult; } const compatibleClasses = resolveUsableDataSpaceClasses( dataSpaceQueryBuilderState.dataSpace, mapping, dataSpaceQueryBuilderState.graphManagerState, dataSpaceQueryBuilderState, ); dataSpaceQueryBuilderState.changeMapping(mapping); dataSpaceQueryBuilderState.changeRuntime( new RuntimePointer( dataSpaceQueryBuilderState.executionContext.defaultRuntime, ), ); // if there is no chosen class or the chosen one is not compatible // with the mapping then pick a compatible class if possible if ( !dataSpaceQueryBuilderState.sourceClass || !compatibleClasses.includes(dataSpaceQueryBuilderState.sourceClass) ) { const possibleNewClass = compatibleClasses[0]; if (possibleNewClass) { dataSpaceQueryBuilderState.changeSourceElement(possibleNewClass); } } dataSpaceQueryBuilderState.explorerState.refreshTreeData(); }; if ( queryBuilderState instanceof DataSpaceQueryBuilderState && queryBuilderState.workflowState.actionConfig instanceof QueryBuilderActionConfig_QueryApplication ) { return propagateExecutionContextChange; } return undefined; }, ]; } // TODO: create plugin for DataProducts getExtraTemplateQueryPanelContentRenderer(): TemplateQueryPanelContentRenderer[] { return [ (queryBuilderState: QueryBuilderState): React.ReactNode => { if ( queryBuilderState instanceof LegendQueryDataProductQueryBuilderState ) { return renderDataProductSampleQueryPanelContent(queryBuilderState); } return undefined; }, ]; } }