UNPKG

@finos/legend-application-studio

Version:
208 lines 18.5 kB
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime"; /** * 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 React, { useEffect } from 'react'; import { observer } from 'mobx-react-lite'; import { ServicePureExecutionState } from '../../../../stores/editor/editor-state/element-editor-state/service/ServiceExecutionState.js'; import { Dialog, PanelLoadingIndicator, PlayIcon, ControlledDropdownMenu, MenuContent, CaretDownIcon, MenuContentItem, PauseCircleIcon, PencilIcon, Modal, ModalBody, ModalFooter, ModalFooterButton, ModalHeader, } from '@finos/legend-art'; import { assertErrorThrown, guaranteeNonNullable, returnUndefOnError, } from '@finos/legend-shared'; import { flowResult } from 'mobx'; import { useEditorStore } from '../../EditorStoreProvider.js'; import { KeyedExecutionParameter, MultiExecutionParameters, PureExecution, } from '@finos/legend-graph'; import { ServiceQueryBuilderState, LambdaParameterValuesEditor, QueryBuilderTextEditorMode, QueryLoaderDialog, ExecutionPlanViewer, QueryBuilderAdvancedWorkflowState, QueryBuilderActionConfig, LineageViewer, } from '@finos/legend-query-builder'; import { ProjectViewerEditorMode } from '../../../../stores/project-view/ProjectViewerEditorMode.js'; import { useLegendStudioApplicationStore } from '../../../LegendStudioFrameworkProvider.js'; import { SNAPSHOT_ALIAS, SNAPSHOT_VERSION_ALIAS, } from '@finos/legend-server-depot'; import { CODE_EDITOR_LANGUAGE } from '@finos/legend-code-editor'; import { CodeEditor } from '@finos/legend-lego/code-editor'; import { EXTERNAL_APPLICATION_NAVIGATION__generateServiceQueryCreatorUrl } from '../../../../__lib__/LegendStudioNavigation.js'; import { pureExecution_setFunction } from '../../../../stores/graph-modifier/DSL_Service_GraphModifierHelper.js'; import { ServiceEditorState } from '../../../../stores/editor/editor-state/element-editor-state/service/ServiceEditorState.js'; const ServiceExecutionResultViewer = observer((props) => { const { executionState } = props; const applicationStore = executionState.editorStore.applicationStore; // execution const executionResultText = executionState.executionResultText; const closeExecutionResultViewer = () => executionState.setExecutionResultText(undefined); return (_jsx(Dialog, { open: Boolean(executionResultText), onClose: closeExecutionResultViewer, classes: { root: 'editor-modal__root-container', container: 'editor-modal__container', paper: 'editor-modal__content', }, children: _jsxs(Modal, { darkMode: !applicationStore.layoutService.TEMPORARY__isLightColorThemeEnabled, className: "editor-modal", children: [_jsx(ModalHeader, { title: "Execution Result" }), _jsx(ModalBody, { children: _jsx(CodeEditor, { inputValue: executionResultText ?? '', isReadOnly: true, language: CODE_EDITOR_LANGUAGE.JSON }) }), _jsx(ModalFooter, { children: _jsx(ModalFooterButton, { className: "modal__footer__close-btn", onClick: closeExecutionResultViewer, text: "Close", type: "secondary" }) })] }) })); }); export const ServiceExecutionQueryEditor = observer((props) => { const { executionState, isReadOnly } = props; const applicationStore = useLegendStudioApplicationStore(); const editorStore = useEditorStore(); const queryState = executionState.queryState; const embeddedQueryBuilderState = editorStore.embeddedQueryBuilderState; const service = executionState.serviceEditorState.service; // actions const editWithQueryBuilder = (openInTextMode = false) => applicationStore.guardUnhandledError(async () => { const selectedExecutionState = executionState.selectedExecutionContextState; await flowResult(embeddedQueryBuilderState.setEmbeddedQueryBuilderConfiguration({ setupQueryBuilderState: async () => { const sourceInfo = { service: service.path, ...editorStore.editorMode.getSourceInfo(), }; const queryBuilderState = new ServiceQueryBuilderState(embeddedQueryBuilderState.editorStore.applicationStore, embeddedQueryBuilderState.editorStore.graphManagerState, QueryBuilderAdvancedWorkflowState.INSTANCE, QueryBuilderActionConfig.INSTANCE, service, undefined, selectedExecutionState?.executionContext instanceof KeyedExecutionParameter ? selectedExecutionState.executionContext.key : undefined, undefined, undefined, embeddedQueryBuilderState.editorStore.applicationStore.config.options.queryBuilderConfig, sourceInfo); queryBuilderState.initializeWithQuery(executionState.execution.func); if (openInTextMode) { queryBuilderState.textEditorState.openModal(QueryBuilderTextEditorMode.TEXT); } return queryBuilderState; }, actionConfigs: [ { key: 'save-query-btn', renderer: (queryBuilderState) => { const save = applicationStore.guardUnhandledError(async () => { try { const rawLambda = queryBuilderState.buildQuery(); await flowResult(executionState.queryState.updateLamba(rawLambda)); applicationStore.notificationService.notifySuccess(`Service query is updated`); embeddedQueryBuilderState.setEmbeddedQueryBuilderConfiguration(undefined); } catch (error) { assertErrorThrown(error); applicationStore.notificationService.notifyError(`Can't save query: ${error.message}`); } }); return (_jsx("button", { className: "query-builder__dialog__header__custom-action", tabIndex: -1, disabled: isReadOnly, onClick: save, children: "Save Query" })); }, }, ], disableCompile: true, })); executionState.setOpeningQueryEditor(false); }); const importQuery = () => queryState.queryLoaderState.setQueryLoaderDialogOpen(true); const runQuery = applicationStore.guardUnhandledError(() => flowResult(executionState.handleRunQuery())); const executionIsRunning = executionState.isRunningQuery || executionState.isGeneratingPlan; const cancelQuery = applicationStore.guardUnhandledError(() => flowResult(executionState.cancelQuery())); const generatePlan = applicationStore.guardUnhandledError(() => flowResult(executionState.generatePlan(false))); const generateLineage = applicationStore.guardUnhandledError(() => flowResult(executionState.generateLineage())); const debugPlanGeneration = applicationStore.guardUnhandledError(() => flowResult(executionState.generatePlan(true))); const openServiceCubeViewer = editorStore.applicationStore.guardUnhandledError(async () => { await executionState.handleOpeningDataCube(service, editorStore); }); const openQueryInLegendQuery = () => { if (!applicationStore.config.queryApplicationUrl) { return; } let projectGAV; if (editorStore.editorMode instanceof ProjectViewerEditorMode) { const viewerEditorMode = editorStore.editorMode; // for Achive mode if (viewerEditorMode.viewerStore.projectGAVCoordinates) { projectGAV = viewerEditorMode.viewerStore.projectGAVCoordinates; } else { // for other viewer modes, if no version we use project `HEAD` projectGAV = { groupId: editorStore.projectConfigurationEditorState .currentProjectConfiguration.groupId, artifactId: editorStore.projectConfigurationEditorState .currentProjectConfiguration.artifactId, versionId: viewerEditorMode.viewerStore.version?.id.id ?? SNAPSHOT_VERSION_ALIAS, }; } } else { const currentWorkSpaceId = editorStore.sdlcState.currentWorkspace?.workspaceId; projectGAV = { groupId: editorStore.projectConfigurationEditorState .currentProjectConfiguration.groupId, artifactId: editorStore.projectConfigurationEditorState .currentProjectConfiguration.artifactId, versionId: editorStore.sdlcState.projectPublishedVersions.includes(`${currentWorkSpaceId}-${SNAPSHOT_ALIAS}`) ? `${currentWorkSpaceId}-${SNAPSHOT_ALIAS}` : SNAPSHOT_VERSION_ALIAS, }; } applicationStore.navigationService.navigator.visitAddress(EXTERNAL_APPLICATION_NAVIGATION__generateServiceQueryCreatorUrl(applicationStore.config.queryApplicationUrl, projectGAV.groupId, projectGAV.artifactId, projectGAV.versionId, service.path)); }; // convert to string useEffect(() => { flowResult(queryState.convertLambdaObjectToGrammarString({ pretty: true })).catch(applicationStore.alertUnhandledError); }, [applicationStore, queryState]); return (_jsxs("div", { className: "panel service-execution-query-editor", children: [_jsxs("div", { className: "panel__header", children: [_jsx("div", { className: "panel__header__title", children: _jsx("div", { className: "panel__header__title__label service-editor__execution__label--query", children: "query" }) }), _jsxs("div", { className: "panel__header__actions", children: [_jsxs("div", { className: "btn__dropdown-combo btn__dropdown-combo--primary", children: [_jsxs("button", { className: "btn__dropdown-combo__label", onClick: editWithQueryBuilder(), title: "Edit Query", tabIndex: -1, children: [_jsx(PencilIcon, { className: "btn__dropdown-combo__label__icon" }), _jsx("div", { className: "btn__dropdown-combo__label__title", children: "Edit Query" })] }), _jsx(ControlledDropdownMenu, { className: "btn__dropdown-combo__dropdown-btn", content: _jsx(MenuContent, { children: _jsx(MenuContentItem, { className: "btn__dropdown-combo__option", onClick: editWithQueryBuilder(true), children: "Text Mode" }) }), menuProps: { anchorOrigin: { vertical: 'bottom', horizontal: 'right' }, transformOrigin: { vertical: 'top', horizontal: 'right' }, }, children: _jsx(CaretDownIcon, {}) })] }), _jsx("div", { className: "btn__dropdown-combo btn__dropdown-combo--primary", children: executionState.isRunningQuery ? (_jsx("button", { className: "btn__dropdown-combo__canceler", onClick: cancelQuery, tabIndex: -1, children: _jsxs("div", { className: "btn--dark btn--caution btn__dropdown-combo__canceler__label", children: [_jsx(PauseCircleIcon, { className: "btn__dropdown-combo__canceler__label__icon" }), _jsx("div", { className: "btn__dropdown-combo__canceler__label__title", children: "Stop" })] }) })) : (_jsxs(_Fragment, { children: [_jsxs("button", { className: "btn__dropdown-combo__label", onClick: runQuery, title: "Run Query", disabled: executionIsRunning, tabIndex: -1, children: [_jsx(PlayIcon, { className: "btn__dropdown-combo__label__icon" }), _jsx("div", { className: "btn__dropdown-combo__label__title", children: "Run Query" })] }), _jsx(ControlledDropdownMenu, { className: "btn__dropdown-combo__dropdown-btn", disabled: executionIsRunning, content: _jsxs(MenuContent, { children: [_jsx(MenuContentItem, { className: "btn__dropdown-combo__option", onClick: generatePlan, children: "Generate Plan" }), _jsx(MenuContentItem, { className: "btn__dropdown-combo__option", onClick: generateLineage, children: "View Lineage" }), _jsx(MenuContentItem, { className: "btn__dropdown-combo__option", onClick: debugPlanGeneration, children: "Debug" })] }), menuProps: { anchorOrigin: { vertical: 'bottom', horizontal: 'right' }, transformOrigin: { vertical: 'top', horizontal: 'right' }, }, children: _jsx(CaretDownIcon, {}) })] })) }), _jsx("div", { className: "btn__dropdown-combo btn__dropdown-combo--primary", children: _jsx("button", { className: "btn__dropdown-combo__label", onClick: openServiceCubeViewer, title: "Data Cube (BETA)", disabled: executionIsRunning, tabIndex: -1, children: _jsx("div", { className: "btn__dropdown-combo__label__title", children: "Data Cube" }) }) }), _jsxs(ControlledDropdownMenu, { className: "btn__dropdown-combo", disabled: executionIsRunning, content: _jsxs(MenuContent, { children: [_jsx(MenuContentItem, { className: "btn__dropdown-combo__option", onClick: importQuery, children: "Import Query" }), _jsx(MenuContentItem, { className: "btn__dropdown-combo__option", onClick: openQueryInLegendQuery, disabled: !applicationStore.config.queryApplicationUrl, children: "Create an Ad-hoc Query" })] }), menuProps: { anchorOrigin: { vertical: 'bottom', horizontal: 'right' }, transformOrigin: { vertical: 'top', horizontal: 'right' }, }, children: [_jsx("div", { className: "btn__dropdown-combo__label", children: _jsx("div", { className: "btn__dropdown-combo__label__title", children: "Advanced" }) }), _jsx("div", { className: "btn__dropdown-combo__dropdown-btn", children: _jsx(CaretDownIcon, {}) })] })] })] }), _jsxs("div", { className: "panel__content property-mapping-editor__entry__container", children: [_jsx(PanelLoadingIndicator, { isLoading: executionState.isOpeningQueryEditor || executionIsRunning }), _jsx("div", { className: "service-execution-query-editor__content", children: _jsx(CodeEditor, { inputValue: queryState.lambdaString, isReadOnly: true, language: CODE_EDITOR_LANGUAGE.PURE }) }), queryState.queryLoaderState.isQueryLoaderDialogOpen && (_jsx(QueryLoaderDialog, { queryLoaderState: queryState.queryLoaderState, title: "import query" })), _jsx(ExecutionPlanViewer, { executionPlanState: executionState.executionPlanState }), _jsx(LineageViewer, { lineageState: executionState.lineageState }), _jsx(ServiceExecutionResultViewer, { executionState: executionState }), executionState.parametersState.parameterValuesEditorState .showModal && (_jsx(LambdaParameterValuesEditor, { graph: executionState.editorStore.graphManagerState.graph, observerContext: executionState.editorStore.changeDetectionState.observerContext, lambdaParametersState: executionState.parametersState }))] })] })); }); export const queryService = async (service, editorStore) => { const embeddedQueryBuilderState = editorStore.embeddedQueryBuilderState; const applicationStore = editorStore.applicationStore; const execution = service.execution instanceof PureExecution ? service.execution : undefined; const selectedExec = execution instanceof MultiExecutionParameters ? execution.singleExecutionParameters[0]?.key : undefined; const sourceInfo = { service: service.path, ...editorStore.editorMode.getSourceInfo(), }; await flowResult(embeddedQueryBuilderState.setEmbeddedQueryBuilderConfiguration({ setupQueryBuilderState: async () => { const queryBuilderState = new ServiceQueryBuilderState(embeddedQueryBuilderState.editorStore.applicationStore, embeddedQueryBuilderState.editorStore.graphManagerState, QueryBuilderAdvancedWorkflowState.INSTANCE, QueryBuilderActionConfig.INSTANCE, service, undefined, selectedExec, undefined, undefined, embeddedQueryBuilderState.editorStore.applicationStore.config.options.queryBuilderConfig, sourceInfo); if (execution) { queryBuilderState.initializeWithQuery(execution.func); } return queryBuilderState; }, actionConfigs: [ { key: 'save-query-btn', renderer: (queryBuilderState) => { const save = applicationStore.guardUnhandledError(async () => { try { const rawLambda = queryBuilderState.buildQuery(); const serviceState = returnUndefOnError(() => editorStore.tabManagerState.getCurrentEditorState(ServiceEditorState)); if (serviceState?.service === service && serviceState.executionState instanceof ServicePureExecutionState) { await flowResult(serviceState.executionState.queryState.updateLamba(rawLambda)); } else { pureExecution_setFunction(guaranteeNonNullable(execution, 'Service execution expected to be a pure execution'), rawLambda); } applicationStore.notificationService.notifySuccess(`Service query is updated`); embeddedQueryBuilderState.setEmbeddedQueryBuilderConfiguration(undefined); } catch (error) { assertErrorThrown(error); applicationStore.notificationService.notifyError(`Can't save query: ${error.message}`); } }); return (_jsx("button", { className: "query-builder__dialog__header__custom-action", tabIndex: -1, disabled: editorStore.disableGraphEditing, onClick: save, children: "Save Query" })); }, }, ], })); }; //# sourceMappingURL=ServiceExecutionQueryEditor.js.map