/** * 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 { ArrowLeftIcon, ArrowRightIcon, BlankPanelContent, clsx, CustomSelectorInput, PanelLoadingIndicator, } from '@finos/legend-art'; import { ActionState, assertErrorThrown, guaranteeNonNullable, guaranteeType, compareSemVerVersions, } from '@finos/legend-shared'; import { flowResult } from 'mobx'; import { observer, useLocalObservable } from 'mobx-react-lite'; import { useContext, useEffect, useState } from 'react'; import { generateMappingQueryCreatorRoute, generateQuerySetupRoute, } from '../__lib__/LegendQueryNavigation.js'; import { LATEST_VERSION_ALIAS } from '@finos/legend-server-depot'; import { useApplicationStore } from '@finos/legend-application'; import { useLegendQueryApplicationStore, useLegendQueryBaseStore, } from './LegendQueryFrameworkProvider.js'; import { CreateMappingQuerySetupStore } from '../stores/CreateMappingQuerySetupStore.js'; import { BaseQuerySetup, BaseQuerySetupStoreContext, buildProjectOption, buildVersionOption, type ProjectOption, type VersionOption, } from './QuerySetup.js'; import type { Mapping, PackageableRuntime } from '@finos/legend-graph'; import { buildElementOption, getPackageableElementOptionFormatter, type PackageableElementOption, } from '@finos/legend-lego/graph-editor'; const CreateMappingQuerySetupStoreProvider: React.FC<{ children: React.ReactNode; }> = ({ children }) => { const applicationStore = useLegendQueryApplicationStore(); const baseStore = useLegendQueryBaseStore(); const store = useLocalObservable( () => new CreateMappingQuerySetupStore( applicationStore, baseStore.depotServerClient, ), ); return ( {children} ); }; const useCreateMappingQuerySetupStore = (): CreateMappingQuerySetupStore => guaranteeType( useContext(BaseQuerySetupStoreContext), CreateMappingQuerySetupStore, `Can't find query setup store in context`, ); const CreateMappingQuerySetupContent = observer(() => { const setupStore = useCreateMappingQuerySetupStore(); const applicationStore = useApplicationStore(); const depotServerClient = setupStore.depotServerClient; const [fetchSelectedProjectVersionsStatus] = useState(ActionState.create()); // actions const back = (): void => { applicationStore.navigationService.navigator.goToLocation( generateQuerySetupRoute(), ); }; const next = (): void => { if ( setupStore.currentProject && setupStore.currentVersionId && setupStore.currentMapping && setupStore.currentRuntime ) { applicationStore.navigationService.navigator.goToLocation( generateMappingQueryCreatorRoute( setupStore.currentProject.groupId, setupStore.currentProject.artifactId, setupStore.currentVersionId, setupStore.currentMapping.path, setupStore.currentRuntime.path, ), ); } }; const canProceed = setupStore.currentProject && setupStore.currentVersionId && setupStore.currentMapping && setupStore.currentRuntime; // project const projectOptions = setupStore.projects.map(buildProjectOption); const selectedProjectOption = setupStore.currentProject ? buildProjectOption(setupStore.currentProject) : null; const projectSelectorPlaceholder = setupStore.loadProjectsState.isInProgress ? 'Loading projects' : setupStore.loadProjectsState.hasFailed ? 'Error fetching projects' : setupStore.projects.length ? 'Choose a project' : 'You have no projects, please create or acquire access for at least one'; const onProjectOptionChange = async ( option: ProjectOption | null, ): Promise => { if (option?.value !== setupStore.currentProject) { setupStore.setCurrentProject(option?.value); // cascade setupStore.setCurrentVersionId(undefined); setupStore.setCurrentMapping(undefined); setupStore.setCurrentRuntime(undefined); setupStore.setCurrentProjectVersions([]); try { fetchSelectedProjectVersionsStatus.inProgress(); const versions = await depotServerClient.getVersions( guaranteeNonNullable(option?.value.groupId), guaranteeNonNullable(option?.value.artifactId), true, ); setupStore.setCurrentProjectVersions(versions); } catch (error) { assertErrorThrown(error); applicationStore.notificationService.notifyError(error); } finally { fetchSelectedProjectVersionsStatus.reset(); } } }; // version const versionOptions = [ LATEST_VERSION_ALIAS, ...(setupStore.currentProjectVersions ?? []), ] .toSorted((v1, v2) => compareSemVerVersions(v2, v1)) .map(buildVersionOption); const selectedVersionOption = setupStore.currentVersionId ? buildVersionOption(setupStore.currentVersionId) : null; const versionSelectorPlaceholder = !setupStore.currentProject ? 'No project selected' : 'Choose a version'; const onVersionOptionChange = async ( option: VersionOption | null, ): Promise => { if (option?.value !== setupStore.currentVersionId) { setupStore.setCurrentVersionId(option?.value); // cascade setupStore.setCurrentMapping(undefined); setupStore.setCurrentRuntime(undefined); if (setupStore.currentProject && setupStore.currentVersionId) { await flowResult( setupStore.surveyMappingRuntimeCompatibility( setupStore.currentProject, setupStore.currentVersionId, ), ).catch(applicationStore.alertUnhandledError); } } }; // mapping const mappingOptions = setupStore.mappingRuntimeCompatibilitySurveyResult.map( (result) => buildElementOption(result.mapping), ); const selectedMappingOption = setupStore.currentMapping ? { label: setupStore.currentMapping.name, value: setupStore.currentMapping, } : null; const onMappingOptionChange = ( option: PackageableElementOption | null, ): void => { setupStore.setCurrentMapping(option?.value); // cascade if (setupStore.currentMapping) { setupStore.setCurrentRuntime(setupStore.compatibleRuntimes[0]); } else { setupStore.setCurrentRuntime(undefined); } }; // runtime const runtimeOptions = setupStore.compatibleRuntimes.map(buildElementOption); const selectedRuntimeOption = setupStore.currentRuntime ? { label: setupStore.currentRuntime.name, value: setupStore.currentRuntime, } : null; const runtimeSelectorPlaceholder = !setupStore.currentMapping ? 'No mapping specified' : runtimeOptions.length ? 'Choose a runtime' : 'No runtime available'; const onRuntimeOptionChange = ( option: PackageableElementOption | null, ): void => { setupStore.setCurrentRuntime(option?.value); }; useEffect(() => { flowResult(setupStore.loadProjects()).catch( applicationStore.alertUnhandledError, ); }, [setupStore, applicationStore]); return (
Creating a new query...
Project
{ onProjectOptionChange(option).catch( applicationStore.alertUnhandledError, ); }} value={selectedProjectOption} placeholder={projectSelectorPlaceholder} isClearable={true} escapeClearsValue={true} darkMode={ !applicationStore.layoutService .TEMPORARY__isLightColorThemeEnabled } />
Version
{ onVersionOptionChange(option).catch( applicationStore.alertUnhandledError, ); }} value={selectedVersionOption} placeholder={ fetchSelectedProjectVersionsStatus.isInProgress ? 'Fetching project versions' : versionSelectorPlaceholder } isClearable={true} escapeClearsValue={true} darkMode={ !applicationStore.layoutService .TEMPORARY__isLightColorThemeEnabled } />
{(!setupStore.currentProject || !setupStore.currentVersionId || !setupStore.surveyMappingRuntimeCompatibilityState .hasSucceeded) && (
{setupStore.surveyMappingRuntimeCompatibilityState.isInProgress ? `Surveying runtime and mapping compatibility...` : setupStore.surveyMappingRuntimeCompatibilityState.hasFailed ? `Can't load runtime and mapping` : 'Project and version must be specified'}
)} {setupStore.currentProject && setupStore.currentVersionId && setupStore.surveyMappingRuntimeCompatibilityState.hasSucceeded && ( <>
Mapping
Runtime
)}
); }); export const CreateMappingQuerySetup: React.FC = () => ( );