UNPKG

@finos/legend-application-studio

Version:
177 lines 11.7 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 { PackageableElementExplicitReference, PureSingleExecution, Service, ConcreteFunctionDefinition, Multiplicity, resolvePackagePathAndElementName, ELEMENT_PATH_DELIMITER, RawVariableExpression, getFunctionSignature, GenericTypeExplicitReference, GenericType, } from '@finos/legend-graph'; import { ClassQueryBuilderState, QueryBuilderAdvancedWorkflowState, } from '@finos/legend-query-builder'; import { assertErrorThrown, guaranteeNonNullable, prettyCONSTName, } from '@finos/legend-shared'; import { flowResult } from 'mobx'; import { observer } from 'mobx-react-lite'; import { useRef, useState } from 'react'; import { service_initNewService, service_setExecution, } from '../../../../stores/graph-modifier/DSL_Service_GraphModifierHelper.js'; import { useEditorStore } from '../../EditorStoreProvider.js'; import { NewServiceModal } from '../service-editor/NewServiceModal.js'; import { CaretDownIcon, Dialog, ControlledDropdownMenu, MenuContent, MenuContentItem, MenuContentItemLabel, ModalTitle, PanelDivider, PanelFormSection, PanelFormValidatedTextField, } from '@finos/legend-art'; const promoteQueryToService = async (packagePath, serviceName, embeddedQueryBuilderState, queryBuilderState) => { const editorStore = embeddedQueryBuilderState.editorStore; const applicationStore = editorStore.applicationStore; try { const mapping = guaranteeNonNullable(queryBuilderState.executionContextState.mapping, 'Mapping is required to create service execution'); const runtime = guaranteeNonNullable(queryBuilderState.executionContextState.runtimeValue, 'Runtime is required to create service execution'); const query = queryBuilderState.buildQuery(); const service = new Service(serviceName); service_initNewService(service); service_setExecution(service, new PureSingleExecution(query, service, PackageableElementExplicitReference.create(mapping), runtime), editorStore.changeDetectionState.observerContext); await flowResult(editorStore.graphEditorMode.addElement(service, packagePath, true)); await flowResult(embeddedQueryBuilderState.setEmbeddedQueryBuilderConfiguration(undefined)).catch(applicationStore.alertUnhandledError); applicationStore.notificationService.notifySuccess(`Service '${service.name}' created`); } catch (error) { assertErrorThrown(error); applicationStore.notificationService.notifyError(error); } }; export const promoteQueryToFunction = async (packagePath, functionName, embeddedQueryBuilderState, queryBuilderState) => { const editorStore = embeddedQueryBuilderState.editorStore; const applicationStore = editorStore.applicationStore; try { const query = queryBuilderState.buildFromQuery(); const returnType = queryBuilderState.getQueryReturnType(); const _function = new ConcreteFunctionDefinition(functionName, // use functionName for now and it will be reset after composing _function.parameters and _function.returnType GenericTypeExplicitReference.create(new GenericType(returnType)), Multiplicity.ONE); // we will copy the body of the query to the body of the function and extract the parameters out // to the function parameters _function.expressionSequence = query.body; _function.parameters = queryBuilderState.parametersState.parameterStates.map((e) => new RawVariableExpression(e.parameter.name, e.parameter.multiplicity, PackageableElementExplicitReference.create(guaranteeNonNullable(e.parameter.genericType?.value.rawType)))); // reset function name to be function signature _function.name = functionName + getFunctionSignature(_function); await flowResult(editorStore.graphEditorMode.addElement(_function, packagePath, true)); await flowResult(embeddedQueryBuilderState.setEmbeddedQueryBuilderConfiguration(undefined)).catch(applicationStore.alertUnhandledError); applicationStore.notificationService.notifySuccess(`Function '${_function.name}' created`); } catch (error) { assertErrorThrown(error); applicationStore.notificationService.notifyError(error); } }; var PROMOTE_QUERY_TYPE; (function (PROMOTE_QUERY_TYPE) { PROMOTE_QUERY_TYPE["FUNCTION"] = "FUNCTION"; PROMOTE_QUERY_TYPE["SERVICE"] = "SERVICE"; })(PROMOTE_QUERY_TYPE || (PROMOTE_QUERY_TYPE = {})); export const NewFunctionModal = observer((props) => { const { isReadOnly, close, _class, showModal, promoteToFunction } = props; const editorStore = useEditorStore(); const applicationStore = editorStore.applicationStore; const nameRef = useRef(null); const defaultFunctionname = _class ? `${_class.name}_QueryFunction` : `QueryFunction`; const [functionPath, setFunctionPath] = useState(defaultFunctionname); const [packagePath, funcName] = resolvePackagePathAndElementName(functionPath, _class?.package?.path ?? 'model::functions'); const [isValid, setIsValid] = useState(true); const handleEnter = () => nameRef.current?.focus(); const create = () => { if (functionPath && !isReadOnly && isValid) { promoteToFunction(packagePath, funcName) .then(() => close()) .catch(applicationStore.alertUnhandledError); } }; const validateElementDoesNotAlreadyExist = (myFunctionName) => { const elementAlreadyExists = editorStore.graphManagerState.graph.allOwnElements .map((s) => s.path) .includes(packagePath + ELEMENT_PATH_DELIMITER + myFunctionName); if (!elementAlreadyExists) { return undefined; } else { return 'Element with same path already exists'; } }; const changeValue = (value) => { setFunctionPath(value); }; return (_jsx(Dialog, { open: showModal, onClose: close, TransitionProps: { onEnter: handleEnter, }, PaperProps: { classes: { root: 'search-modal__inner-container', }, }, children: _jsxs("form", { onSubmit: (event) => { event.preventDefault(); create(); }, className: "modal search-modal modal--dark", children: [_jsx(ModalTitle, { title: "Promote to Function" }), _jsx(PanelFormValidatedTextField, { ref: nameRef, isReadOnly: isReadOnly ?? false, update: (value) => { changeValue(value ?? ''); }, validate: validateElementDoesNotAlreadyExist, onValidate: (issue) => setIsValid(!issue), value: functionPath, placeholder: `Enter a name, use ${ELEMENT_PATH_DELIMITER} to create new package(s) for the function` }), _jsx(PanelDivider, {}), _jsx(PanelFormSection, { children: _jsx("div", { className: "search-modal__actions", children: _jsx("button", { className: "btn btn--dark", disabled: Boolean(isReadOnly) || !isValid, onClick: create, children: "Create" }) }) })] }) })); }); const PromoteToServiceQueryBuilderAction = observer((props) => { const { queryBuilderState } = props; const editorStore = useEditorStore(); const queryBuilderExtension = editorStore.embeddedQueryBuilderState; const [promoteQueryModal, setPromoteQueryType] = useState(undefined); const showPromoteQueryModal = (type) => setPromoteQueryType(type); const closeNewServiceModal = () => setPromoteQueryType(undefined); const allowPromotion = Boolean(queryBuilderState.executionContextState.mapping && queryBuilderState.executionContextState.runtimeValue && !queryBuilderState.allValidationIssues.length); const renderSaveAsModal = () => { if (promoteQueryModal === PROMOTE_QUERY_TYPE.SERVICE && queryBuilderState.executionContextState.mapping) { const promoteToService = async (packagePath, serviceName) => { if (allowPromotion) { await promoteQueryToService(packagePath, serviceName, queryBuilderExtension, queryBuilderState); } }; return (_jsx(NewServiceModal, { mapping: queryBuilderState.executionContextState.mapping, close: closeNewServiceModal, showModal: true, promoteToService: promoteToService })); } else if (promoteQueryModal === PROMOTE_QUERY_TYPE.FUNCTION) { const promoteToFunction = async (packagePath, serviceName) => { if (allowPromotion) { await promoteQueryToFunction(packagePath, serviceName, queryBuilderExtension, queryBuilderState); } }; return (_jsx(NewFunctionModal, { _class: queryBuilderState.class, close: closeNewServiceModal, showModal: true, promoteToFunction: promoteToFunction })); } return null; }; return (_jsxs(_Fragment, { children: [_jsxs(ControlledDropdownMenu, { className: "query-builder__dialog__header__custom-action", title: "Promote Query...", content: _jsx(MenuContent, { children: Object.values(PROMOTE_QUERY_TYPE).map((type) => (_jsx(MenuContentItem, { disabled: !allowPromotion, onClick: () => showPromoteQueryModal(type), children: _jsx(MenuContentItemLabel, { className: "query-builder__sub-header__menu-content", children: prettyCONSTName(type) }) }, type))) }), menuProps: { anchorOrigin: { vertical: 'bottom', horizontal: 'right' }, transformOrigin: { vertical: 'top', horizontal: 'right' }, elevation: 7, }, children: [_jsx("div", { className: "query-builder__sub-header__custom-action__label", children: "Save As..." }), _jsx(CaretDownIcon, { className: "query-builder__sub-header__custom-action__icon" })] }), renderSaveAsModal()] })); }); export const queryClass = async (_class, editorStore) => { const embeddedQueryBuilderState = editorStore.embeddedQueryBuilderState; await flowResult(embeddedQueryBuilderState.setEmbeddedQueryBuilderConfiguration({ setupQueryBuilderState: async () => { const queryBuilderState = new ClassQueryBuilderState(embeddedQueryBuilderState.editorStore.applicationStore, embeddedQueryBuilderState.editorStore.graphManagerState, QueryBuilderAdvancedWorkflowState.INSTANCE, editorStore.applicationStore.config.options.queryBuilderConfig, editorStore.editorMode.getSourceInfo()); queryBuilderState.changeClass(_class); queryBuilderState.propagateClassChange(_class); return queryBuilderState; }, // TODO: when we modularize DSL service, we will create an extension // mechanism for this action config // See https://github.com/finos/legend-studio/issues/65 actionConfigs: [ { key: 'promote-to-service-btn', renderer: (queryBuilderState) => (_jsx(PromoteToServiceQueryBuilderAction, { queryBuilderState: queryBuilderState })), }, ], })); }; //# sourceMappingURL=ClassQueryBuilder.js.map