@finos/legend-application-studio
Version:
Legend Studio application core
193 lines • 12.3 kB
JavaScript
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, CORE_PURE_PATH, requireTypeArugments, } from '@finos/legend-graph';
import { ClassQueryBuilderState, QueryBuilderAdvancedWorkflowState, QueryBuilderEmbeddedFromExecutionContextState, } 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 {
let query;
if (queryBuilderState.executionContextState instanceof
QueryBuilderEmbeddedFromExecutionContextState) {
query = queryBuilderState.buildQuery();
}
else {
query = queryBuilderState.buildFromQuery();
}
const returnType = queryBuilderState.getQueryReturnType();
const _genericType = new GenericType(returnType);
if (requireTypeArugments(returnType)) {
_genericType.typeArguments = [
GenericTypeExplicitReference.create(new GenericType(editorStore.graphManagerState.graph.getType(CORE_PURE_PATH.ANY))),
];
}
const _function = new ConcreteFunctionDefinition(functionName, // use functionName for now and it will be reset after composing _function.parameters and _function.returnType
GenericTypeExplicitReference.create(_genericType), 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, slotProps: {
transition: {
onEnter: handleEnter,
},
paper: {
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