/** * 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 { useApplicationStore } from '@finos/legend-application'; import { AnchorLinkIcon, CheckIcon, compareLabelFn, ControlledDropdownMenu, createFilter, CustomSelectorInput, MenuContent, MenuContentItem, MenuContentItemIcon, MenuContentItemLabel, MoreVerticalIcon, PanelHeader, PanelHeaderActionItem, PanelHeaderActions, SearchIcon, } from '@finos/legend-art'; import { ResolvedDataSpaceEntityWithOrigin, resolveUsableDataSpaceClasses, } from '@finos/legend-extension-dsl-data-space/application'; import { buildExecutionContextOption, DataSpaceAdvancedSearchModal, type ExecutionContextOption, } from '@finos/legend-extension-dsl-data-space/application-query'; import { getMappingCompatibleRuntimes, PackageableElementExplicitReference, RuntimePointer, type PackageableRuntime, type Runtime, } from '@finos/legend-graph'; import { buildRuntimeValueOption, getRuntimeOptionFormatter, QueryBuilderClassSelector, } from '@finos/legend-query-builder'; import { guaranteeNonNullable, guaranteeType } from '@finos/legend-shared'; import { DepotEntityWithOrigin } from '@finos/legend-storage'; import { flowResult } from 'mobx'; import { observer } from 'mobx-react-lite'; import { useEffect } from 'react'; import type { DataProductWithLegacyOption } from '../../stores/data-space/DataProductSelectorState.js'; import { formatDataProductOrSpaceOptionLabel } from '../shared/LegendQueryDataProductOptionLabel.js'; import type { LegendQueryDataSpaceQueryBuilderState } from '../../stores/data-space/query-builder/LegendQueryDataSpaceQueryBuilderState.js'; const resolveExecutionContextRuntimes = ( queryBuilderState: LegendQueryDataSpaceQueryBuilderState, ): PackageableRuntime[] => { if (queryBuilderState.dataSpaceAnalysisResult) { const executionContext = Array.from( queryBuilderState.dataSpaceAnalysisResult.executionContextsIndex.values(), ).find( (e) => e.mapping.path === queryBuilderState.executionContext.mapping.value.path, ); return guaranteeNonNullable(executionContext).compatibleRuntimes; } return getMappingCompatibleRuntimes( queryBuilderState.executionContext.mapping.value, queryBuilderState.graphManagerState.usableRuntimes, ); }; /** * LegendQuery-specific DataSpace query builder setup panel. Unlike the base * DataSpaceQueryBuilderSetupPanelContent, this component explicitly knows about * both legacy data spaces and data products as combined options in the first * dropdown, mirroring the same awareness in LegendQueryDataProductQueryBuilderState. */ const LegendQueryDataSpaceQueryBuilderSetupPanelContent = observer( (props: { queryBuilderState: LegendQueryDataSpaceQueryBuilderState }) => { const { queryBuilderState } = props; const applicationStore = useApplicationStore(); // combined first dropdown: legacy data spaces + data products from depot const legacyOptions = queryBuilderState.dataSpaceOptions; // applies prioritizeEntityFunc const productOptions: DataProductWithLegacyOption[] = ( queryBuilderState.productSelectorState.dataProducts ?? [] ).map((e) => ({ label: e.name, value: e })); const allOptions: DataProductWithLegacyOption[] = [ ...legacyOptions, ...productOptions, ]; const selectedOption = queryBuilderState.selectedDataSpaceOption; const onOptionChange = ( option: DataProductWithLegacyOption | null, ): void => { if (!option) { return; } const value = option.value; if (value instanceof ResolvedDataSpaceEntityWithOrigin) { queryBuilderState.queryChatState?.abort(); queryBuilderState .onDataSpaceChange(value) .catch(queryBuilderState.applicationStore.alertUnhandledError); } else if (value instanceof DepotEntityWithOrigin) { queryBuilderState.queryChatState?.abort(); queryBuilderState.onDataProductChange(value); } }; const openDataSpaceAdvancedSearch = (): void => { if (queryBuilderState.isAdvancedDataSpaceSearchEnabled) { queryBuilderState.showAdvancedSearchPanel(queryBuilderState.dataSpace); } }; // execution context const executionContextOptions = queryBuilderState.dataSpace.executionContexts .map(buildExecutionContextOption) .sort(compareLabelFn); const showExecutionContextOptions = executionContextOptions.length > 1; const selectedExecutionContextOption = buildExecutionContextOption( queryBuilderState.executionContext, ); const onExecutionContextOptionChange = async ( option: ExecutionContextOption, ): Promise => { if (option.value === queryBuilderState.executionContext) { return; } const currentMapping = queryBuilderState.executionContext.mapping.value.path; queryBuilderState.setExecutionContext(option.value); await queryBuilderState.propagateExecutionContextChange( currentMapping === option.value.mapping.value.path, ); queryBuilderState.onExecutionContextChange?.(option.value); }; const handleExecutionContextOptionChange = ( option: ExecutionContextOption, ): void => { flowResult(onExecutionContextOptionChange(option)); }; // runtime const runtimeOptions = resolveExecutionContextRuntimes(queryBuilderState) .map( (rt) => new RuntimePointer(PackageableElementExplicitReference.create(rt)), ) .map(buildRuntimeValueOption) .sort(compareLabelFn); const selectedRuntimeOption = queryBuilderState.executionContextState .runtimeValue ? buildRuntimeValueOption( queryBuilderState.executionContextState.runtimeValue, ) : null; const changeRuntime = (option: { value: Runtime }): void => { if ( option.value === queryBuilderState.executionContextState.runtimeValue ) { return; } queryBuilderState.changeRuntime(option.value); queryBuilderState.onRuntimeChange?.(option.value); }; const runtimeFilterOption = createFilter({ ignoreCase: true, ignoreAccents: false, stringify: (option: { data: { value: Runtime } }): string => guaranteeType(option.data.value, RuntimePointer).packageableRuntime .value.path, }); // class const classes = resolveUsableDataSpaceClasses( queryBuilderState.dataSpace, queryBuilderState.executionContext.mapping.value, queryBuilderState.graphManagerState, queryBuilderState, ); useEffect(() => { flowResult(queryBuilderState.loadEntities()).catch( applicationStore.alertUnhandledError, ); }, [queryBuilderState, applicationStore]); const copyDataSpaceLinkToClipboard = (): void => { if (queryBuilderState.isDataSpaceLinkable) { queryBuilderState.copyDataSpaceLinkToClipboard(); } }; return (
queryBuilderState.setShowRuntimeSelector( !queryBuilderState.showRuntimeSelector, ) } > {queryBuilderState.showRuntimeSelector ? ( ) : null} Show Runtime Selector } menuProps={{ anchorOrigin: { vertical: 'bottom', horizontal: 'right' }, transformOrigin: { vertical: 'top', horizontal: 'right' }, }} >
{queryBuilderState.isAdvancedDataSpaceSearchEnabled && ( <> {queryBuilderState.advancedSearchState && ( queryBuilderState.hideAdvancedSearchPanel()} /> )} )}
{Boolean(showExecutionContextOptions) && (
)} {queryBuilderState.showRuntimeSelector && (
)}
); }, ); export const renderLegendQueryDataSpaceQueryBuilderSetupPanelContent = ( queryBuilderState: LegendQueryDataSpaceQueryBuilderState, ): React.ReactNode => ( );