From 965e54537dd89549a752a1c218e2ace900e6fa46 Mon Sep 17 00:00:00 2001 From: An Phi Date: Fri, 26 May 2023 13:42:24 -0400 Subject: [PATCH] add support for SQL playground (#2270) * minor cleanups around INTERNAL__rawDependencyEntities * sql panel: add basic wiring * BREAKING: remove execution input collectors and send full graph data * function editor: support running query * add icon to editor tab header * database builder: restyle and cleanup code * db builder: minor styling improvements * sql playground: add basic support * sql playground: improve with keyboard support * TEMP: attempt to add auto-suggestion to SQL playground (but failed) * bump dependencies * fix tests * bump dependencies --- .changeset/fast-horses-provide.md | 18 + .changeset/loud-pets-enjoy.md | 5 + .changeset/metal-peaches-roll.md | 7 + .changeset/orange-crabs-dream.md | 18 + fixtures/legend-mock-server/package.json | 2 +- package.json | 4 +- packages/babel-preset/package.json | 6 +- packages/eslint-plugin/package.json | 2 +- .../package.json | 2 +- .../package.json | 2 +- .../src/components/QueryEditor.tsx | 2 +- .../scripts/setup.js | 1 + .../package.json | 2 +- .../legend-application-studio/package.json | 2 +- ...egendStudioApplicationNavigationContext.ts | 2 + .../STO_Relational_LegendStudioCommand.ts} | 23 +- .../LegendStudioApplicationConfig.ts | 7 + .../src/components/ElementIconUtils.tsx | 31 +- .../command-center/ProjectSearchCommand.tsx | 4 +- .../editor/editor-group/EditorGroup.tsx | 42 +- .../editor/editor-group/FunctionEditor.tsx | 150 ++- .../GenerationSpecificationEditor.tsx | 2 +- ...TERNAL__UnknownFunctionActivatorEdtior.tsx | 39 +- .../editor/editor-group/RuntimeEditor.tsx | 2 +- .../__tests__/EditorGroup.test.tsx | 14 +- .../connection-editor/DatabaseBuilder.tsx | 343 ++++--- .../RelationalDatabaseConnectionEditor.tsx | 4 +- .../FileGenerationEditor.tsx | 2 +- ...SL_ExternalFormat_BindingElementEditor.tsx | 2 +- .../mapping-editor/ClassMappingEditor.tsx | 2 +- .../mapping-editor/MappingExplorer.tsx | 4 +- .../mapping-editor/PropertyMappingsEditor.tsx | 2 +- .../ServiceExecutionQueryEditor.tsx | 18 +- .../testable/ServiceTestDataEditor.tsx | 4 +- .../uml-editor/AssociationEditor.tsx | 4 +- .../editor-group/uml-editor/ClassEditor.tsx | 8 +- .../editor/panel-group/PanelGroup.tsx | 38 +- .../editor/panel-group/SQLPlaygroundPanel.tsx | 766 +++++++++++++++ .../components/editor/side-bar/Explorer.tsx | 8 +- .../side-bar/testable/GlobalTestRunner.tsx | 2 +- .../Core_LegendStudioApplicationPlugin.tsx | 12 +- .../src/stores/editor/EditorConfig.ts | 1 + .../src/stores/editor/EditorStore.ts | 4 + .../stores/editor/GraphEditFormModeState.ts | 1 + .../FunctionEditorState.ts | 320 ++++++- .../ProtocolValueBuilderState.ts | 13 +- .../connection/DatabaseBuilderState.ts | 511 +++++----- .../service/ServiceExecutionState.ts | 42 +- .../service/testable/ServiceTestDataState.ts | 18 +- .../panel-group/SQLPlaygroundPanelState.ts | 485 ++++++++++ .../components/editor/_database-builder.scss | 166 ++-- .../components/editor/_editor-group.scss | 35 +- .../editor/_function-activator-editor.scss | 10 + .../components/editor/_function-editor.scss | 101 ++ .../style/components/editor/_panel-group.scss | 25 +- .../{_console-panel.scss => _console.scss} | 0 .../editor/panel-group/_sql-playground.scss | 261 ++++++ .../package.json | 2 +- packages/legend-art/src/icon/Icon.ts | 3 +- .../legend-art/src/panel/PanelDropZone.tsx | 5 +- packages/legend-dev-utils/package.json | 6 +- ...L_DataSpace_PureProtocolProcessorPlugin.ts | 16 - .../components/query/ServiceRegisterModal.tsx | 2 +- .../graph-manager/AbstractPureGraphManager.ts | 11 +- .../action/generation/DatabaseBuilderInput.ts | 11 +- .../pure/PureProtocolProcessorPlugin.ts | 23 - ...ernalFormat_PureProtocolProcessorPlugin.ts | 15 - .../protocol/pure/v1/V1_PureGraphManager.ts | 178 ++-- .../protocol/pure/v1/engine/V1_Engine.ts | 21 +- .../pure/v1/engine/V1_EngineServerClient.ts | 21 +- .../engine/execution/V1_RawSQLExecuteInput.ts | 52 ++ .../generation/V1_DatabaseBuilderInput.ts | 19 +- .../model/context/V1_PureModelContextData.ts | 4 +- .../V1_PureProtocolSerialization.ts | 2 +- .../graph/helpers/STO_Relational_Helper.ts | 13 + .../src/application/TabManager.tsx | 3 + .../src/code-editor/CodeEditorTheme.ts | 9 +- packages/legend-shared/src/CommonUtils.ts | 8 +- yarn.lock | 878 ++++++++++++------ 79 files changed, 3782 insertions(+), 1121 deletions(-) create mode 100644 .changeset/fast-horses-provide.md create mode 100644 .changeset/loud-pets-enjoy.md create mode 100644 .changeset/metal-peaches-roll.md create mode 100644 .changeset/orange-crabs-dream.md rename packages/legend-application-studio/{style/components/editor/panel-group/_dev-tool.scss => src/__lib__/STO_Relational_LegendStudioCommand.ts} (53%) create mode 100644 packages/legend-application-studio/src/components/editor/panel-group/SQLPlaygroundPanel.tsx create mode 100644 packages/legend-application-studio/src/stores/editor/panel-group/SQLPlaygroundPanelState.ts rename packages/legend-application-studio/style/components/editor/panel-group/{_console-panel.scss => _console.scss} (100%) create mode 100644 packages/legend-application-studio/style/components/editor/panel-group/_sql-playground.scss create mode 100644 packages/legend-graph/src/graph-manager/protocol/pure/v1/engine/execution/V1_RawSQLExecuteInput.ts diff --git a/.changeset/fast-horses-provide.md b/.changeset/fast-horses-provide.md new file mode 100644 index 0000000000..7d522952f9 --- /dev/null +++ b/.changeset/fast-horses-provide.md @@ -0,0 +1,18 @@ +--- +'@finos/legend-application-pure-ide-deployment': patch +'@finos/legend-application-taxonomy-deployment': patch +'@finos/legend-application-studio-deployment': patch +'@finos/legend-application-query-deployment': patch +'@finos/legend-application-studio-bootstrap': patch +'@finos/legend-extension-dsl-data-space': patch +'@finos/legend-extension-dsl-service': patch +'@finos/legend-application-studio': patch +'@finos/legend-application-query': patch +'@finos/legend-dev-utils': patch +'@finos/eslint-plugin-legend-studio': patch +'@finos/legend-shared': patch +'@finos/babel-preset-legend-studio': patch +'@finos/legend-graph': patch +'@finos/legend-lego': patch +'@finos/legend-art': patch +--- diff --git a/.changeset/loud-pets-enjoy.md b/.changeset/loud-pets-enjoy.md new file mode 100644 index 0000000000..c66e769003 --- /dev/null +++ b/.changeset/loud-pets-enjoy.md @@ -0,0 +1,5 @@ +--- +'@finos/legend-graph': major +--- + +**BREAKING CHANGE:** Remove `PureProtocolProcessorPlugin.V1_getExtraExecutionInputCollectors()` and simplified the mechanism where we collect graph data for execution input: now we just send the full graph and do no filtering. diff --git a/.changeset/metal-peaches-roll.md b/.changeset/metal-peaches-roll.md new file mode 100644 index 0000000000..df0ad9c998 --- /dev/null +++ b/.changeset/metal-peaches-roll.md @@ -0,0 +1,7 @@ +--- +'@finos/legend-application-studio-bootstrap': patch +'@finos/legend-extension-dsl-data-space': patch +'@finos/legend-application-studio': patch +'@finos/legend-shared': patch +'@finos/legend-graph': patch +--- diff --git a/.changeset/orange-crabs-dream.md b/.changeset/orange-crabs-dream.md new file mode 100644 index 0000000000..7d522952f9 --- /dev/null +++ b/.changeset/orange-crabs-dream.md @@ -0,0 +1,18 @@ +--- +'@finos/legend-application-pure-ide-deployment': patch +'@finos/legend-application-taxonomy-deployment': patch +'@finos/legend-application-studio-deployment': patch +'@finos/legend-application-query-deployment': patch +'@finos/legend-application-studio-bootstrap': patch +'@finos/legend-extension-dsl-data-space': patch +'@finos/legend-extension-dsl-service': patch +'@finos/legend-application-studio': patch +'@finos/legend-application-query': patch +'@finos/legend-dev-utils': patch +'@finos/eslint-plugin-legend-studio': patch +'@finos/legend-shared': patch +'@finos/babel-preset-legend-studio': patch +'@finos/legend-graph': patch +'@finos/legend-lego': patch +'@finos/legend-art': patch +--- diff --git a/fixtures/legend-mock-server/package.json b/fixtures/legend-mock-server/package.json index 3e9159c7ac..76009ad7eb 100644 --- a/fixtures/legend-mock-server/package.json +++ b/fixtures/legend-mock-server/package.json @@ -26,7 +26,7 @@ "start": "node lib/index.js" }, "dependencies": { - "@fastify/cors": "8.2.1", + "@fastify/cors": "8.3.0", "fastify": "4.17.0" }, "devDependencies": { diff --git a/package.json b/package.json index c999a8fd3f..a21e1e7b43 100644 --- a/package.json +++ b/package.json @@ -89,13 +89,13 @@ "devDependencies": { "@actions/core": "1.10.0", "@actions/github": "5.1.1", - "@babel/core": "7.21.8", + "@babel/core": "7.22.1", "@changesets/cli": "2.26.1", "@finos/babel-preset-legend-studio": "workspace:*", "@finos/eslint-plugin-legend-studio": "workspace:*", "@finos/legend-dev-utils": "workspace:*", "@finos/stylelint-config-legend-studio": "workspace:*", - "@types/node": "20.2.3", + "@types/node": "20.2.4", "chalk": "5.2.0", "cross-env": "7.0.3", "envinfo": "7.8.1", diff --git a/packages/babel-preset/package.json b/packages/babel-preset/package.json index 02d4e0bb9d..9b7d5d1d04 100644 --- a/packages/babel-preset/package.json +++ b/packages/babel-preset/package.json @@ -31,10 +31,10 @@ }, "dependencies": { "@babel/helper-plugin-utils": "7.21.5", - "@babel/preset-env": "7.21.5", - "@babel/preset-react": "7.18.6", + "@babel/preset-env": "7.22.1", + "@babel/preset-react": "7.22.0", "@babel/preset-typescript": "7.21.5", - "@babel/runtime": "7.21.5", + "@babel/runtime": "7.22.0", "react-refresh": "0.14.0" }, "devDependencies": { diff --git a/packages/eslint-plugin/package.json b/packages/eslint-plugin/package.json index 21c2a20365..a87669d84a 100644 --- a/packages/eslint-plugin/package.json +++ b/packages/eslint-plugin/package.json @@ -30,7 +30,7 @@ "publish:snapshot": "node ../../scripts/release/publishDevSnapshot.js" }, "dependencies": { - "@babel/core": "7.21.8", + "@babel/core": "7.22.1", "@babel/eslint-parser": "7.21.8", "@typescript-eslint/eslint-plugin": "5.59.7", "@typescript-eslint/parser": "5.59.7", diff --git a/packages/legend-application-pure-ide-deployment/package.json b/packages/legend-application-pure-ide-deployment/package.json index 6a7a82f293..b85469d822 100644 --- a/packages/legend-application-pure-ide-deployment/package.json +++ b/packages/legend-application-pure-ide-deployment/package.json @@ -51,7 +51,7 @@ "npm-run-all": "4.1.5", "rimraf": "5.0.1", "typescript": "5.0.4", - "webpack": "5.84.0", + "webpack": "5.84.1", "webpack-bundle-analyzer": "4.8.0", "webpack-cli": "5.1.1", "webpack-dev-server": "4.15.0" diff --git a/packages/legend-application-query-deployment/package.json b/packages/legend-application-query-deployment/package.json index 1fe5e6ea35..26427230ba 100644 --- a/packages/legend-application-query-deployment/package.json +++ b/packages/legend-application-query-deployment/package.json @@ -44,7 +44,7 @@ "npm-run-all": "4.1.5", "rimraf": "5.0.1", "typescript": "5.0.4", - "webpack": "5.84.0", + "webpack": "5.84.1", "webpack-bundle-analyzer": "4.8.0", "webpack-cli": "5.1.1", "webpack-dev-server": "4.15.0" diff --git a/packages/legend-application-query/src/components/QueryEditor.tsx b/packages/legend-application-query/src/components/QueryEditor.tsx index cbb3799dcf..e5714ca921 100644 --- a/packages/legend-application-query/src/components/QueryEditor.tsx +++ b/packages/legend-application-query/src/components/QueryEditor.tsx @@ -164,7 +164,7 @@ const CreateQueryDialog = observer(() => { { core: { TEMPORARY__enableMappingTestableEditor: false, TEMPORARY__enableFunctionActivatorSupport: false, + TEMPORARY__enableRawSQLExecutor: false, }, }, undefined, diff --git a/packages/legend-application-studio-deployment/package.json b/packages/legend-application-studio-deployment/package.json index 6f1b5571f1..a0205b0e9a 100644 --- a/packages/legend-application-studio-deployment/package.json +++ b/packages/legend-application-studio-deployment/package.json @@ -44,7 +44,7 @@ "npm-run-all": "4.1.5", "rimraf": "5.0.1", "typescript": "5.0.4", - "webpack": "5.84.0", + "webpack": "5.84.1", "webpack-bundle-analyzer": "4.8.0", "webpack-cli": "5.1.1", "webpack-dev-server": "4.15.0" diff --git a/packages/legend-application-studio/package.json b/packages/legend-application-studio/package.json index 71cc507c7b..801b2c303b 100644 --- a/packages/legend-application-studio/package.json +++ b/packages/legend-application-studio/package.json @@ -67,7 +67,7 @@ "react-dnd": "16.0.1", "react-dom": "18.2.0", "serializr": "3.0.2", - "yaml": "2.3.0" + "yaml": "2.3.1" }, "devDependencies": { "@finos/legend-dev-utils": "workspace:*", diff --git a/packages/legend-application-studio/src/__lib__/LegendStudioApplicationNavigationContext.ts b/packages/legend-application-studio/src/__lib__/LegendStudioApplicationNavigationContext.ts index 9765b06faf..338e078efa 100644 --- a/packages/legend-application-studio/src/__lib__/LegendStudioApplicationNavigationContext.ts +++ b/packages/legend-application-studio/src/__lib__/LegendStudioApplicationNavigationContext.ts @@ -57,4 +57,6 @@ export enum LEGEND_STUDIO_APPLICATION_NAVIGATION_CONTEXT_KEY { SERVICE_EDITOR_TEST = 'studio.editor.service-editor.test', DATA_ELEMENT_EDITOR = 'studio.editor.data-element-editor', + + SQL_PLAYGROUND = 'studio.editor.panel-group.sql-playground', } diff --git a/packages/legend-application-studio/style/components/editor/panel-group/_dev-tool.scss b/packages/legend-application-studio/src/__lib__/STO_Relational_LegendStudioCommand.ts similarity index 53% rename from packages/legend-application-studio/style/components/editor/panel-group/_dev-tool.scss rename to packages/legend-application-studio/src/__lib__/STO_Relational_LegendStudioCommand.ts index 98c96fe972..71f6a9b4fe 100644 --- a/packages/legend-application-studio/style/components/editor/panel-group/_dev-tool.scss +++ b/packages/legend-application-studio/src/__lib__/STO_Relational_LegendStudioCommand.ts @@ -14,16 +14,17 @@ * limitations under the License. */ -@use 'mixins' as *; +import type { CommandConfigData } from '@finos/legend-application'; -.console-panel { - height: 100%; - width: 100%; - padding: 1.5rem 1rem; - - &__content { - @include flexHSpaceBetween; - - padding: 0 1rem; - } +export enum STO_RELATIONAL_LEGEND_STUDIO_COMMAND_KEY { + SQL_PLAYGROUND_EXECUTE = 'editor.panel-group.sql-playground.execute', } + +export const STO_RELATIONAL_LEGEND_STUDIO_COMMAND_CONFIG: CommandConfigData = { + [STO_RELATIONAL_LEGEND_STUDIO_COMMAND_KEY.SQL_PLAYGROUND_EXECUTE]: { + title: 'Execute SQL (SQL Playground)', + defaultKeyboardShortcut: 'Control+Enter', + additionalKeyboardShortcuts: ['Meta+Enter'], + when: 'When SQL playground is active', + }, +}; diff --git a/packages/legend-application-studio/src/application/LegendStudioApplicationConfig.ts b/packages/legend-application-studio/src/application/LegendStudioApplicationConfig.ts index e898eeecca..ecf0de1956 100644 --- a/packages/legend-application-studio/src/application/LegendStudioApplicationConfig.ts +++ b/packages/legend-application-studio/src/application/LegendStudioApplicationConfig.ts @@ -74,6 +74,12 @@ class LegendStudioApplicationCoreOptions { */ TEMPORARY__enableFunctionActivatorSupport = false; + /** + * This flag can be removed when the support for raw SQL execution is official + * See https://github.com/finos/legend-engine/pull/1841 + */ + TEMPORARY__enableRawSQLExecutor = false; + /** * Indicates whether we should render the new mapping testable editor or the deprecated legacy editor. * This flag will be removed once the editor for testable editor is agreed on. @@ -98,6 +104,7 @@ class LegendStudioApplicationCoreOptions { projectCreationGroupIdSuggestion: optional(primitive()), TEMPORARY__preserveSectionIndex: optional(primitive()), TEMPORARY__enableFunctionActivatorSupport: optional(primitive()), + TEMPORARY__enableRawSQLExecutor: optional(primitive()), TEMPORARY__enableMappingTestableEditor: optional(primitive()), TEMPORARY__serviceRegistrationConfig: list( object(ServiceRegistrationEnvironmentConfig), diff --git a/packages/legend-application-studio/src/components/ElementIconUtils.tsx b/packages/legend-application-studio/src/components/ElementIconUtils.tsx index eab3ff57fa..b56eb5f4e1 100644 --- a/packages/legend-application-studio/src/components/ElementIconUtils.tsx +++ b/packages/legend-application-studio/src/components/ElementIconUtils.tsx @@ -45,10 +45,19 @@ import { } from '@finos/legend-art'; import { PACKAGEABLE_ELEMENT_TYPE } from '../stores/editor/utils/ModelClassifierUtils.js'; +/** + * NOTE: eventually we would like to remove this function and just a generic mechanism to + * get element icon given the metamodel, we can also simplify the plugins a lot. + * Technically, the only time we need to check icon for a type classifier is when we create + * a new element + */ export const getElementTypeIcon = ( - editorStore: EditorStore, type: string | undefined, - element?: PackageableElement | undefined, + editorStore: EditorStore, + options?: { + element?: PackageableElement | undefined; + returnEmptyForUnknown?: boolean | undefined; + }, ): React.ReactNode => { switch (type) { case PACKAGEABLE_ELEMENT_TYPE.PRIMITIVE: @@ -98,7 +107,7 @@ export const getElementTypeIcon = ( ).getExtraElementIconGetters?.() ?? [], ); for (const iconGetter of extraElementIconGetters) { - const elementIcon = iconGetter(type, element); + const elementIcon = iconGetter(type, options?.element); if (elementIcon) { return elementIcon; } @@ -107,24 +116,30 @@ export const getElementTypeIcon = ( // NOTE: this is temporary until we properly refactor this function to check element instead of // the type classifier value, but to be fair, this is not a bad way to do it since this acts // as a catch all block, we can check for `abstract` element here - if (element instanceof FunctionActivator) { + if (options?.element instanceof FunctionActivator) { return ; } - return ; + return options?.returnEmptyForUnknown ? null : ( + + ); } } }; export const getElementIcon = ( - editorStore: EditorStore, element: PackageableElement | undefined, + editorStore: EditorStore, + options?: { returnEmptyForUnknown?: boolean | undefined }, ): React.ReactNode => getElementTypeIcon( - editorStore, element ? returnUndefOnError(() => editorStore.graphState.getPackageableElementType(element), ) : undefined, - element, + editorStore, + { + element, + returnEmptyForUnknown: options?.returnEmptyForUnknown, + }, ); diff --git a/packages/legend-application-studio/src/components/editor/command-center/ProjectSearchCommand.tsx b/packages/legend-application-studio/src/components/editor/command-center/ProjectSearchCommand.tsx index 91c3844cdb..11ab54fcf1 100644 --- a/packages/legend-application-studio/src/components/editor/command-center/ProjectSearchCommand.tsx +++ b/packages/legend-application-studio/src/components/editor/command-center/ProjectSearchCommand.tsx @@ -117,7 +117,7 @@ export const ProjectSearchCommand = observer(() => { className="project-search-command__option" onClick={changeType(type)} > - {getElementTypeIcon(editorStore, type)} + {getElementTypeIcon(type, editorStore)} ))} @@ -125,7 +125,7 @@ export const ProjectSearchCommand = observer(() => { >
{elementType ? ( - getElementTypeIcon(editorStore, elementType) + getElementTypeIcon(elementType, editorStore) ) : ( )} diff --git a/packages/legend-application-studio/src/components/editor/editor-group/EditorGroup.tsx b/packages/legend-application-studio/src/components/editor/editor-group/EditorGroup.tsx index e33dca786b..0e3e407a6c 100644 --- a/packages/legend-application-studio/src/components/editor/editor-group/EditorGroup.tsx +++ b/packages/legend-application-studio/src/components/editor/editor-group/EditorGroup.tsx @@ -24,6 +24,7 @@ import { PlusIcon, ArrowsAltHIcon, useResizeDetector, + GenericTextFileIcon, } from '@finos/legend-art'; import { MappingEditor } from './mapping-editor/MappingEditor.js'; import { UMLEditor } from './uml-editor/UMLEditor.js'; @@ -75,6 +76,7 @@ import { ElementXTGenerationEditor } from './element-generation-editor/ElementXT import { TabManager, type TabState } from '@finos/legend-lego/application'; import { INTERNAL__UnknownFunctionActivatorEdtiorState } from '../../../stores/editor/editor-state/element-editor-state/INTERNAL__UnknownFunctionActivatorEditorState.js'; import { INTERNAL__UnknownFunctionActivatorEdtior } from './INTERNAL__UnknownFunctionActivatorEdtior.js'; +import { getElementIcon } from '../../ElementIconUtils.js'; export const ViewerEditorGroupSplashScreen: React.FC = () => { const commandListWidth = 300; @@ -322,6 +324,15 @@ export const EditorGroup = observer(() => { if (editorState instanceof EntityDiffViewState) { return (
+
+ {editorState.element ? ( + getElementIcon(editorState.element, editorStore, { + returnEmptyForUnknown: true, + }) ?? + ) : ( + + )} +
{editorState.label}
({getPrettyLabelForRevision(editorState.fromRevision)} @@ -337,6 +348,9 @@ export const EditorGroup = observer(() => { } else if (editorState instanceof EntityChangeConflictEditorState) { return (
+
+ +
{editorState.label}
{editorState.isReadOnly ? '(Merge Preview)' : '(Merged)'} @@ -344,7 +358,33 @@ export const EditorGroup = observer(() => {
); } - return editorState.label; + + return ( +
+
+ {editorState instanceof ElementEditorState ? ( + getElementIcon(editorState.element, editorStore, { + returnEmptyForUnknown: true, + }) ?? + ) : ( + + )} +
+
+ {editorState.label} +
+ {editorState instanceof ElementEditorState && + editorStore.tabManagerState.tabs.filter( + (tab) => + tab instanceof ElementEditorState && + tab.label === editorState.label, + ).length > 1 && ( +
+ {editorState.element.path} +
+ )} +
+ ); }; if (!currentTabState) { diff --git a/packages/legend-application-studio/src/components/editor/editor-group/FunctionEditor.tsx b/packages/legend-application-studio/src/components/editor/editor-group/FunctionEditor.tsx index 724dace402..633eb434c3 100644 --- a/packages/legend-application-studio/src/components/editor/editor-group/FunctionEditor.tsx +++ b/packages/legend-application-studio/src/components/editor/editor-group/FunctionEditor.tsx @@ -58,6 +58,8 @@ import { MenuContent, MenuContentItem, Modal, + PauseCircleIcon, + PlayIcon, } from '@finos/legend-art'; import { LEGEND_STUDIO_TEST_ID } from '../../../__lib__/LegendStudioTesting.js'; import { @@ -124,11 +126,19 @@ import { rawVariableExpression_setType, } from '../../../stores/graph-modifier/RawValueSpecificationGraphModifierHelper.js'; import { LEGEND_STUDIO_APPLICATION_NAVIGATION_CONTEXT_KEY } from '../../../__lib__/LegendStudioApplicationNavigationContext.js'; -import { LambdaEditor } from '@finos/legend-query-builder'; +import { + ExecutionPlanViewer, + LambdaEditor, + LambdaParameterValuesEditor, +} from '@finos/legend-query-builder'; import type { EditorStore } from '../../../stores/editor/EditorStore.js'; import { graph_renameElement } from '../../../stores/graph-modifier/GraphModifierHelper.js'; import { ProtocolValueBuilder } from './ProtocolValueBuilder.js'; import type { ProtocolValueBuilderState } from '../../../stores/editor/editor-state/element-editor-state/ProtocolValueBuilderState.js'; +import { + CODE_EDITOR_LANGUAGE, + CodeEditor, +} from '@finos/legend-lego/code-editor'; enum FUNCTION_PARAMETER_TYPE { CLASS = 'CLASS', @@ -360,7 +370,7 @@ const ParameterBasicEditor = observer( > {typeName !== FUNCTION_PARAMETER_TYPE.PRIMITIVE && (
- {getElementIcon(editorStore, paramType)} + {getElementIcon(paramType, editorStore)}
)}
@@ -398,7 +408,7 @@ const ParameterBasicEditor = observer( > {typeName !== FUNCTION_PARAMETER_TYPE.PRIMITIVE && (
- {getElementIcon(editorStore, paramType)} + {getElementIcon(paramType, editorStore)}
)}
@@ -555,7 +565,7 @@ const ReturnTypeEditor = observer( > {typeName !== FUNCTION_PARAMETER_TYPE.PRIMITIVE && (
- {getElementIcon(editorStore, returnType.value)} + {getElementIcon(returnType.value, editorStore)}
)}
@@ -593,7 +603,7 @@ const ReturnTypeEditor = observer( > {typeName !== FUNCTION_PARAMETER_TYPE.PRIMITIVE && (
- {getElementIcon(editorStore, returnType.value)} + {getElementIcon(returnType.value, editorStore)}
)}
@@ -862,6 +872,47 @@ const FunctionActivatorContentBuilder = observer( }, ); +const ExecutionResultViewer = observer( + (props: { functionEditorState: FunctionEditorState }) => { + const { functionEditorState } = props; + // execution + const executionResultText = functionEditorState.executionResultText; + const closeExecutionResultViewer = (): void => + functionEditorState.setExecutionResultText(undefined); + + return ( + + + + + + + + + + + + ); + }, +); + export const FunctionEditor = observer(() => { const editorStore = useEditorStore(); const applicationStore = useApplicationStore(); @@ -968,6 +1019,25 @@ export const FunctionEditor = observer(() => { ); }; + const runQuery = applicationStore.guardUnhandledError(() => + flowResult(functionEditorState.handleRunQuery()), + ); + + const executionIsRunning = + functionEditorState.isRunningQuery || functionEditorState.isGeneratingPlan; + + const cancelQuery = applicationStore.guardUnhandledError(() => + flowResult(functionEditorState.cancelQuery()), + ); + + const generatePlan = applicationStore.guardUnhandledError(() => + flowResult(functionEditorState.generatePlan(false)), + ); + + const debugPlanGeneration = applicationStore.guardUnhandledError(() => + flowResult(functionEditorState.generatePlan(true)), + ); + useEffect(() => { flowResult( functionEditorState.functionDefinitionEditorState.convertLambdaObjectToGrammarString( @@ -1012,6 +1082,61 @@ export const FunctionEditor = observer(() => { ))}
+ {functionEditorState.isRunningQuery ? ( + + ) : ( +
+ + + + Generate Plan + + + Debug + + + } + menuProps={{ + anchorOrigin: { vertical: 'bottom', horizontal: 'right' }, + transformOrigin: { vertical: 'top', horizontal: 'right' }, + }} + > + + +
+ )} {editorStore.applicationStore.config.options .TEMPORARY__enableFunctionActivatorSupport && ( <> @@ -1203,6 +1328,21 @@ export const FunctionEditor = observer(() => { ))}
)} + + + {functionEditorState.parametersState.parameterValuesEditorState + .showModal && ( + + )}
diff --git a/packages/legend-application-studio/src/components/editor/editor-group/GenerationSpecificationEditor.tsx b/packages/legend-application-studio/src/components/editor/editor-group/GenerationSpecificationEditor.tsx index c208b9db89..4a8ade17c0 100644 --- a/packages/legend-application-studio/src/components/editor/editor-group/GenerationSpecificationEditor.tsx +++ b/packages/legend-application-studio/src/components/editor/editor-group/GenerationSpecificationEditor.tsx @@ -187,7 +187,7 @@ const ModelGenerationItem = observer( showPlaceholder={isBeingDragged} >
- {getElementIcon(editorStore, modelGeneration)} + {getElementIcon(modelGeneration, editorStore)}
{ {functionFieldDocumentation}
)} - +
+ + +
diff --git a/packages/legend-application-studio/src/components/editor/editor-group/RuntimeEditor.tsx b/packages/legend-application-studio/src/components/editor/editor-group/RuntimeEditor.tsx index 8c9c3effcb..24a21d229f 100644 --- a/packages/legend-application-studio/src/components/editor/editor-group/RuntimeEditor.tsx +++ b/packages/legend-application-studio/src/components/editor/editor-group/RuntimeEditor.tsx @@ -261,7 +261,7 @@ const getRuntimeExplorerTreeNodeIcon = ( } else if (node.data instanceof Connection) { return ; } - return getElementIcon(editorStore, node.data); + return getElementIcon(node.data, editorStore); }; const getRuntimeExplorerTreeNodeTooltipText = ( diff --git a/packages/legend-application-studio/src/components/editor/editor-group/__tests__/EditorGroup.test.tsx b/packages/legend-application-studio/src/components/editor/editor-group/__tests__/EditorGroup.test.tsx index d4ffa245fc..0359ead800 100644 --- a/packages/legend-application-studio/src/components/editor/editor-group/__tests__/EditorGroup.test.tsx +++ b/packages/legend-application-studio/src/components/editor/editor-group/__tests__/EditorGroup.test.tsx @@ -23,6 +23,7 @@ import { getByTestId, queryByText, getByTitle, + getAllByTestId, } from '@testing-library/react'; import TEST_DATA__m2mGraphEntities from '../../../../stores/editor/__tests__/TEST_DATA__M2MGraphEntities.json'; import { integrationTest } from '@finos/legend-shared/test'; @@ -32,6 +33,7 @@ import { TEST__setUpEditorWithDefaultSDLCData, } from '../../__test-utils__/EditorComponentTestUtils.js'; import { LEGEND_STUDIO_TEST_ID } from '../../../../__lib__/LegendStudioTesting.js'; +import { TAB_MANAGER__TAB_TEST_ID } from '@finos/legend-lego/application'; let renderResult: RenderResult; @@ -96,12 +98,14 @@ test(integrationTest('Test navigation between element states'), async () => { .forEach((openElement) => getByText(editorGroupHeader, openElement)); // test closing of tabs + const tabs = getAllByTestId(editorGroupHeader, TAB_MANAGER__TAB_TEST_ID); const closeTabs = ['Firm', 'Degree', 'TestEnumeration']; - closeTabs.forEach((tab) => { - const text = getByText(editorGroupHeader, tab); - const parent = text.parentElement as HTMLElement; - const deleteButton = getByTitle(parent, 'Close'); - fireEvent.click(deleteButton); + tabs.forEach((tab) => { + if (!closeTabs.some((tabLabel) => tab.textContent?.includes(tabLabel))) { + return; + } + const closeButton = getByTitle(tab, 'Close'); + fireEvent.click(closeButton); }); closeTabs.forEach((tab) => expect(queryByText(editorGroupHeader, tab)).toBeNull(), diff --git a/packages/legend-application-studio/src/components/editor/editor-group/connection-editor/DatabaseBuilder.tsx b/packages/legend-application-studio/src/components/editor/editor-group/connection-editor/DatabaseBuilder.tsx index 5aaa647c95..3405774114 100644 --- a/packages/legend-application-studio/src/components/editor/editor-group/connection-editor/DatabaseBuilder.tsx +++ b/packages/legend-application-studio/src/components/editor/editor-group/connection-editor/DatabaseBuilder.tsx @@ -33,6 +33,15 @@ import { EmptyCircleIcon, PanelContent, Modal, + ModalHeader, + ModalBody, + ModalFooter, + ModalTitle, + ModalHeaderActions, + TimesIcon, + ModalFooterButton, + BlankPanelContent, + KeyIcon, } from '@finos/legend-art'; import { useEffect } from 'react'; import { @@ -43,7 +52,7 @@ import { SchemaDatabaseBuilderTreeNodeData, TableDatabaseBuilderTreeNodeData, } from '../../../../stores/editor/editor-state/element-editor-state/connection/DatabaseBuilderState.js'; -import { capitalize } from '@finos/legend-shared'; +import { noop } from '@finos/legend-shared'; import { useApplicationStore, useConditionedApplicationNavigationContext, @@ -57,106 +66,121 @@ import { } from '@finos/legend-lego/code-editor'; import { stringifyDataType } from '@finos/legend-graph'; -const getNodeIcon = (node: DatabaseBuilderTreeNodeData): React.ReactNode => { +const getDatabaseSchemaNodeIcon = ( + node: DatabaseBuilderTreeNodeData, +): React.ReactNode => { if (node instanceof SchemaDatabaseBuilderTreeNodeData) { - return ; + return ( +
+ +
+ ); } else if (node instanceof TableDatabaseBuilderTreeNodeData) { - return ; + return ( +
+ +
+ ); } else if (node instanceof ColumnDatabaseBuilderTreeNodeData) { return renderColumnTypeIcon(node.column.type); } return null; }; -const DatabaseBuilderTreeNodeContainer: React.FC< - TreeNodeContainerProps< - DatabaseBuilderTreeNodeData, - { - toggleCheckedNode: (node: DatabaseBuilderTreeNodeData) => void; - isPartiallySelected: (node: DatabaseBuilderTreeNodeData) => boolean; - } - > -> = (props) => { - const { node, level, stepPaddingInRem, onNodeSelect, innerProps } = props; - const { toggleCheckedNode, isPartiallySelected } = innerProps; - const isExpandable = - Boolean(!node.childrenIds || node.childrenIds.length) && - !(node instanceof ColumnDatabaseBuilderTreeNodeData); - const nodeExpandIcon = isExpandable ? ( - node.isOpen ? ( - +const DatabaseBuilderTreeNodeContainer = observer( + ( + props: TreeNodeContainerProps< + DatabaseBuilderTreeNodeData, + { + toggleCheckedNode: (node: DatabaseBuilderTreeNodeData) => void; + isPartiallySelected: (node: DatabaseBuilderTreeNodeData) => boolean; + } + >, + ) => { + const { node, level, stepPaddingInRem, onNodeSelect, innerProps } = props; + const { toggleCheckedNode, isPartiallySelected } = innerProps; + const isExpandable = + Boolean(!node.childrenIds || node.childrenIds.length) && + !(node instanceof ColumnDatabaseBuilderTreeNodeData); + const nodeExpandIcon = isExpandable ? ( + node.isOpen ? ( + + ) : ( + + ) ) : ( - - ) - ) : ( -
- ); - const nodeTypeIcon = getNodeIcon(node); - const toggleCheck = (): void => toggleCheckedNode(node); - const toggleExpandNode = (): void => { - onNodeSelect?.(node); - if (!isExpandable) { - toggleCheck(); - } - }; +
+ ); + const nodeTypeIcon = getDatabaseSchemaNodeIcon(node); + const toggleExpandNode = (): void => { + onNodeSelect?.(node); + if (!isExpandable) { + toggleCheckedNode(node); + } + }; + const isPrimaryKeyColumn = + node instanceof ColumnDatabaseBuilderTreeNodeData && + node.owner.primaryKey.includes(node.column); - const renderCheckedIcon = ( - _node: DatabaseBuilderTreeNodeData, - ): React.ReactNode => { - if (_node instanceof ColumnDatabaseBuilderTreeNodeData) { - return null; - } else if (isPartiallySelected(_node)) { - return ; - } else if (_node.isChecked) { - return ; - } - return ; - }; + const renderCheckedIcon = ( + _node: DatabaseBuilderTreeNodeData, + ): React.ReactNode => { + if (_node instanceof ColumnDatabaseBuilderTreeNodeData) { + return null; + } else if (isPartiallySelected(_node)) { + return ; + } else if (_node.isChecked) { + return ; + } + return ; + }; - return ( -
-
-
- {nodeExpandIcon} -
-
- {renderCheckedIcon(node)} -
-
- {nodeTypeIcon} -
-
+ return (
- {node.label} - {node instanceof ColumnDatabaseBuilderTreeNodeData && ( -
-
- {stringifyDataType(node.column.type)} -
+
+
+ {nodeExpandIcon}
- )} +
{ + event.stopPropagation(); + toggleCheckedNode(node); + }} + > + {renderCheckedIcon(node)} +
+
{nodeTypeIcon}
+
+
+ {node.label} + {node instanceof ColumnDatabaseBuilderTreeNodeData && ( +
+
+ {stringifyDataType(node.column.type)} +
+
+ )} + {isPrimaryKeyColumn && ( +
+ +
+ )} +
-
- ); -}; + ); + }, +); export const DatabaseBuilderExplorer = observer( (props: { @@ -200,6 +224,7 @@ export const DatabaseBuilderExplorer = observer( }; return ( { const { databaseBuilderState, isReadOnly } = props; const applicationStore = useApplicationStore(); - const buildDb = applicationStore.guardUnhandledError(() => - flowResult(databaseBuilderState.buildDatabaseWithTreeData()), + const preview = applicationStore.guardUnhandledError(() => + flowResult(databaseBuilderState.previewDatabaseModel()), ); const saveOrUpdateDatabase = applicationStore.guardUnhandledError(() => flowResult(databaseBuilderState.createOrUpdateDatabase()), @@ -247,7 +272,7 @@ export const DatabaseBuilder = observer( }; useEffect(() => { - flowResult(databaseBuilderState.fetchSchemaDefinitions()).catch( + flowResult(databaseBuilderState.fetchDatabaseMetadata()).catch( applicationStore.alertUnhandledError, ); }, [databaseBuilderState, applicationStore]); @@ -260,17 +285,28 @@ export const DatabaseBuilder = observer( return ( -
-
- Build Database -
-
-
+ + + + + + + @@ -278,32 +314,11 @@ export const DatabaseBuilder = observer(
- database explorer + schema explorer
-
-
- {capitalize('target database path')} -
-
- {'path of target database'} -
- -
{databaseBuilderState.treeData && ( -
+
-
builder
-
-
- - +
+ database model +
- +
+
+
+ Target Database Path +
+ +
+
+ {databaseBuilderState.databaseGrammarCode && ( + + )} + {!databaseBuilderState.databaseGrammarCode && ( + + No database preview + + )} +
+
-
+ + + + Preview + + + {databaseBuilderState.currentDatabase + ? 'Update Database' + : 'Build Database'} + +
); diff --git a/packages/legend-application-studio/src/components/editor/editor-group/connection-editor/RelationalDatabaseConnectionEditor.tsx b/packages/legend-application-studio/src/components/editor/editor-group/connection-editor/RelationalDatabaseConnectionEditor.tsx index e8dde3039b..75b8586231 100644 --- a/packages/legend-application-studio/src/components/editor/editor-group/connection-editor/RelationalDatabaseConnectionEditor.tsx +++ b/packages/legend-application-studio/src/components/editor/editor-group/connection-editor/RelationalDatabaseConnectionEditor.tsx @@ -1645,7 +1645,7 @@ const RelationalConnectionGeneralEditor = observer(
- Database type + Database Type
- Database type + Database Type
{getElementIcon( - editorStore, value instanceof PackageableElementReference ? value.value : undefined, + editorStore, )}
} diff --git a/packages/legend-application-studio/src/components/editor/editor-group/external-format-editor/DSL_ExternalFormat_BindingElementEditor.tsx b/packages/legend-application-studio/src/components/editor/editor-group/external-format-editor/DSL_ExternalFormat_BindingElementEditor.tsx index 150d2c0b96..5e0f252489 100644 --- a/packages/legend-application-studio/src/components/editor/editor-group/external-format-editor/DSL_ExternalFormat_BindingElementEditor.tsx +++ b/packages/legend-application-studio/src/components/editor/editor-group/external-format-editor/DSL_ExternalFormat_BindingElementEditor.tsx @@ -79,7 +79,7 @@ const ModelUnitPackagableElementEntryEditor = observer(
{
- {getElementIcon(editorStore, elementRef.value)} + {getElementIcon(elementRef.value, editorStore)}
}
diff --git a/packages/legend-application-studio/src/components/editor/editor-group/mapping-editor/ClassMappingEditor.tsx b/packages/legend-application-studio/src/components/editor/editor-group/mapping-editor/ClassMappingEditor.tsx index 78e0647070..ab14be2ae0 100644 --- a/packages/legend-application-studio/src/components/editor/editor-group/mapping-editor/ClassMappingEditor.tsx +++ b/packages/legend-application-studio/src/components/editor/editor-group/mapping-editor/ClassMappingEditor.tsx @@ -209,7 +209,7 @@ export const ClassMappingEditor = observer( {sourceName && (
- {getElementTypeIcon(editorStore, sourceType)} + {getElementTypeIcon(sourceType, editorStore)}
{sourceName} diff --git a/packages/legend-application-studio/src/components/editor/editor-group/mapping-editor/MappingExplorer.tsx b/packages/legend-application-studio/src/components/editor/editor-group/mapping-editor/MappingExplorer.tsx index 82dc30c670..5bddbf86f2 100644 --- a/packages/legend-application-studio/src/components/editor/editor-group/mapping-editor/MappingExplorer.tsx +++ b/packages/legend-application-studio/src/components/editor/editor-group/mapping-editor/MappingExplorer.tsx @@ -276,7 +276,7 @@ export const MappingElementExplorer = observer( }'`} >
- {getElementIcon(editorStore, mappingElementTarget)} + {getElementIcon(mappingElementTarget, editorStore)}
{getMappingElementLabel(mappingElement, editorStore).value} @@ -384,7 +384,7 @@ const MappingElementTreeNodeContainer = observer( {nodeExpandIcon}
- {getElementIcon(editorStore, mappingElementTarget)} + {getElementIcon(mappingElementTarget, editorStore)}
{getMappingElementLabel(mappingElement, editorStore).value} diff --git a/packages/legend-application-studio/src/components/editor/editor-group/mapping-editor/PropertyMappingsEditor.tsx b/packages/legend-application-studio/src/components/editor/editor-group/mapping-editor/PropertyMappingsEditor.tsx index 7d72137b30..bf50911e0c 100644 --- a/packages/legend-application-studio/src/components/editor/editor-group/mapping-editor/PropertyMappingsEditor.tsx +++ b/packages/legend-application-studio/src/components/editor/editor-group/mapping-editor/PropertyMappingsEditor.tsx @@ -398,7 +398,7 @@ export const PropertyMappingEditor = observer( > {propertyBasicType !== CLASS_PROPERTY_TYPE.PRIMITIVE && (
- {getElementIcon(editorStore, propertyRawType)} + {getElementIcon(propertyRawType, editorStore)}
)}
diff --git a/packages/legend-application-studio/src/components/editor/editor-group/service-editor/ServiceExecutionQueryEditor.tsx b/packages/legend-application-studio/src/components/editor/editor-group/service-editor/ServiceExecutionQueryEditor.tsx index 866836f995..11851bca3b 100644 --- a/packages/legend-application-studio/src/components/editor/editor-group/service-editor/ServiceExecutionQueryEditor.tsx +++ b/packages/legend-application-studio/src/components/editor/editor-group/service-editor/ServiceExecutionQueryEditor.tsx @@ -88,7 +88,7 @@ const ServiceExecutionResultViewer = observer(
- - {queryState.queryLoaderState.isQueryLoaderDialogOpen && ( )} - {executionState.parameterState.parameterValuesEditorState + + + {executionState.parametersState.parameterValuesEditorState .showModal && ( )}
diff --git a/packages/legend-application-studio/src/components/editor/editor-group/service-editor/testable/ServiceTestDataEditor.tsx b/packages/legend-application-studio/src/components/editor/editor-group/service-editor/testable/ServiceTestDataEditor.tsx index 7b99f86730..f4a8e087a3 100644 --- a/packages/legend-application-studio/src/components/editor/editor-group/service-editor/testable/ServiceTestDataEditor.tsx +++ b/packages/legend-application-studio/src/components/editor/editor-group/service-editor/testable/ServiceTestDataEditor.tsx @@ -165,7 +165,7 @@ export const ConnectionTestDataEditor = observer( isReadOnly={isReadOnly} embeddedDataEditorState={connectionTestDataState.embeddedEditorState} /> - {connectionTestDataState.parameterState.parameterValuesEditorState + {connectionTestDataState.parametersState.parameterValuesEditorState .showModal && ( )}
diff --git a/packages/legend-application-studio/src/components/editor/editor-group/uml-editor/AssociationEditor.tsx b/packages/legend-application-studio/src/components/editor/editor-group/uml-editor/AssociationEditor.tsx index 874978daae..c5de376ce9 100644 --- a/packages/legend-application-studio/src/components/editor/editor-group/uml-editor/AssociationEditor.tsx +++ b/packages/legend-application-studio/src/components/editor/editor-group/uml-editor/AssociationEditor.tsx @@ -263,7 +263,7 @@ const AssociationPropertyBasicEditor = observer( > {propertyTypeName !== CLASS_PROPERTY_TYPE.PRIMITIVE && (
- {getElementIcon(editorStore, propertyType)} + {getElementIcon(propertyType, editorStore)}
)}
@@ -314,7 +314,7 @@ const AssociationPropertyBasicEditor = observer( > {propertyTypeName !== CLASS_PROPERTY_TYPE.PRIMITIVE && (
- {getElementIcon(editorStore, propertyType)} + {getElementIcon(propertyType, editorStore)}
)}
diff --git a/packages/legend-application-studio/src/components/editor/editor-group/uml-editor/ClassEditor.tsx b/packages/legend-application-studio/src/components/editor/editor-group/uml-editor/ClassEditor.tsx index 89b9a0e625..efa122f00f 100644 --- a/packages/legend-application-studio/src/components/editor/editor-group/uml-editor/ClassEditor.tsx +++ b/packages/legend-application-studio/src/components/editor/editor-group/uml-editor/ClassEditor.tsx @@ -354,7 +354,7 @@ const PropertyBasicEditor = observer( > {propertyTypeName !== CLASS_PROPERTY_TYPE.PRIMITIVE && (
- {getElementIcon(editorStore, propertyType)} + {getElementIcon(propertyType, editorStore)}
)}
@@ -395,7 +395,7 @@ const PropertyBasicEditor = observer( > {propertyTypeName !== CLASS_PROPERTY_TYPE.PRIMITIVE && (
- {getElementIcon(editorStore, propertyType)} + {getElementIcon(propertyType, editorStore)}
)}
@@ -723,7 +723,7 @@ const DerivedPropertyBasicEditor = observer( > {propertyTypeName !== CLASS_PROPERTY_TYPE.PRIMITIVE && (
- {getElementIcon(editorStore, propertyType)} + {getElementIcon(propertyType, editorStore)}
)}
@@ -764,7 +764,7 @@ const DerivedPropertyBasicEditor = observer( > {propertyTypeName !== CLASS_PROPERTY_TYPE.PRIMITIVE && (
- {getElementIcon(editorStore, propertyType)} + {getElementIcon(propertyType, editorStore)}
)}
diff --git a/packages/legend-application-studio/src/components/editor/panel-group/PanelGroup.tsx b/packages/legend-application-studio/src/components/editor/panel-group/PanelGroup.tsx index f535d59d1e..543c7b2ca4 100644 --- a/packages/legend-application-studio/src/components/editor/panel-group/PanelGroup.tsx +++ b/packages/legend-application-studio/src/components/editor/panel-group/PanelGroup.tsx @@ -26,6 +26,7 @@ import { PanelHeader, PanelHeaderActions, PanelHeaderActionItem, + SparkleIcon, } from '@finos/legend-art'; import { ConsolePanel } from './ConsolePanel.js'; import { PANEL_MODE } from '../../../stores/editor/EditorConfig.js'; @@ -33,6 +34,17 @@ import { isNonNullable } from '@finos/legend-shared'; import { DevToolPanel } from './DevToolPanel.js'; import { useEditorStore } from '../EditorStoreProvider.js'; import { ProblemsPanel } from './ProblemsPanel.js'; +import { SQLPlaygroundPanel } from './SQLPlaygroundPanel.js'; +import { GraphEditFormModeState } from '../../../stores/editor/GraphEditFormModeState.js'; + +export const PanelGroupItemExperimentalBadge: React.FC = () => ( +
+ +
+); export const PanelGroup = observer(() => { const editorStore = useEditorStore(); @@ -51,6 +63,7 @@ export const PanelGroup = observer(() => { icon?: React.ReactNode; isVisible: boolean; counter?: number; + experimental?: boolean; }; } = { [PANEL_MODE.CONSOLE]: { @@ -58,6 +71,7 @@ export const PanelGroup = observer(() => { name: 'CONSOLE', icon: undefined, isVisible: true, + experimental: true, }, [PANEL_MODE.DEV_TOOL]: { mode: PANEL_MODE.DEV_TOOL, @@ -72,11 +86,23 @@ export const PanelGroup = observer(() => { isVisible: true, counter: editorStore.graphState.problems.length, }, + [PANEL_MODE.SQL_PLAYGROUND]: { + mode: PANEL_MODE.SQL_PLAYGROUND, + name: 'SQL PLAYGROUND', + icon: undefined, + isVisible: editorStore.graphEditorMode instanceof GraphEditFormModeState, + experimental: true, + }, }; - const tabsToShow = Object.values(PANEL_MODE).filter( - (tab) => isNonNullable(tabs[tab]) && tabs[tab].isVisible, - ); + const tabsToShow = Object.values(PANEL_MODE) + .filter((tab) => isNonNullable(tabs[tab]) && tabs[tab].isVisible) + .filter( + (tab) => + tab !== PANEL_MODE.SQL_PLAYGROUND || + editorStore.applicationStore.config.options + .TEMPORARY__enableRawSQLExecutor, + ); const isTabVisible = (tabType: PANEL_MODE): boolean => editorStore.activePanelMode === tabType && tabsToShow.includes(tabType); @@ -117,6 +143,7 @@ export const PanelGroup = observer(() => { /> )}
+ {tab.experimental && } ))}
@@ -157,6 +184,11 @@ export const PanelGroup = observer(() => {
)} + {isTabVisible(PANEL_MODE.SQL_PLAYGROUND) && ( +
+ +
+ )}
); diff --git a/packages/legend-application-studio/src/components/editor/panel-group/SQLPlaygroundPanel.tsx b/packages/legend-application-studio/src/components/editor/panel-group/SQLPlaygroundPanel.tsx new file mode 100644 index 0000000000..172c28713b --- /dev/null +++ b/packages/legend-application-studio/src/components/editor/panel-group/SQLPlaygroundPanel.tsx @@ -0,0 +1,766 @@ +/** + * 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 { observer } from 'mobx-react-lite'; +import { + type TreeNodeContainerProps, + ResizablePanelGroup, + ResizablePanel, + ResizablePanelSplitter, + clsx, + TreeView, + PURE_DatabaseSchemaIcon, + PURE_DatabaseTableIcon, + ChevronDownIcon, + ChevronRightIcon, + KeyIcon, + CustomSelectorInput, + type SelectComponent, + createFilter, + PURE_ConnectionIcon, + BlankPanelPlaceholder, + PanelDropZone, + ResizablePanelSplitterLine, + PlayIcon, + PanelLoadingIndicator, + BlankPanelContent, + TrashIcon, +} from '@finos/legend-art'; +import React, { useCallback, useEffect, useRef, useState } from 'react'; +import { + useApplicationStore, + useCommands, + useConditionedApplicationNavigationContext, +} from '@finos/legend-application'; +import { flowResult } from 'mobx'; +import { + CODE_EDITOR_LANGUAGE, + CODE_EDITOR_THEME, + getBaseCodeEditorOptions, +} from '@finos/legend-lego/code-editor'; +import { + editor as monacoEditorAPI, + languages as monacoLanguagesAPI, + type IDisposable, + type IPosition, +} from 'monaco-editor'; +import { + PackageableConnection, + RelationalDatabaseConnection, + guaranteeRelationalDatabaseConnection, + stringifyDataType, +} from '@finos/legend-graph'; +import { LEGEND_STUDIO_APPLICATION_NAVIGATION_CONTEXT_KEY } from '../../../__lib__/LegendStudioApplicationNavigationContext.js'; +import { + DatabaseSchemaExplorerTreeColumnNodeData, + DatabaseSchemaExplorerTreeSchemaNodeData, + DatabaseSchemaExplorerTreeTableNodeData, + type DatabaseSchemaExplorerTreeData, + type DatabaseSchemaExplorerTreeNodeData, + type SQLPlaygroundPanelState, +} from '../../../stores/editor/panel-group/SQLPlaygroundPanelState.js'; +import { renderColumnTypeIcon } from '../editor-group/connection-editor/DatabaseEditorHelper.js'; +import { useEditorStore } from '../EditorStoreProvider.js'; +import { PANEL_MODE } from '../../../stores/editor/EditorConfig.js'; +import { useDrag, useDrop } from 'react-dnd'; +import { + CORE_DND_TYPE, + type ElementDragSource, +} from '../../../stores/editor/utils/DnDUtils.js'; +import { DataGrid } from '@finos/legend-lego/data-grid'; +import { + getNonNullableEntry, + getNullableEntry, + getNullableLastEntry, + isNonNullable, + isString, + parseCSVString, +} from '@finos/legend-shared'; + +const getDatabaseSchemaNodeIcon = ( + node: DatabaseSchemaExplorerTreeNodeData, +): React.ReactNode => { + if (node instanceof DatabaseSchemaExplorerTreeSchemaNodeData) { + return ( +
+ +
+ ); + } else if (node instanceof DatabaseSchemaExplorerTreeTableNodeData) { + return ( +
+ +
+ ); + } else if (node instanceof DatabaseSchemaExplorerTreeColumnNodeData) { + return renderColumnTypeIcon(node.column.type); + } + return null; +}; + +const DATABASE_NODE_DND_TYPE = 'DATABASE_NODE_DND_TYPE'; +type DatabaseNodeDragType = { text: string }; + +const DatabaseSchemaExplorerTreeNodeContainer: React.FC< + TreeNodeContainerProps< + DatabaseSchemaExplorerTreeNodeData, + { + // empty + } + > +> = (props) => { + const { node, level, stepPaddingInRem, onNodeSelect } = props; + const isExpandable = + Boolean(!node.childrenIds || node.childrenIds.length) && + !(node instanceof DatabaseSchemaExplorerTreeColumnNodeData); + const nodeExpandIcon = isExpandable ? ( + node.isOpen ? ( + + ) : ( + + ) + ) : ( +
+ ); + const [, nodeDragRef] = useDrag( + () => ({ + type: DATABASE_NODE_DND_TYPE, + item: { + text: + node instanceof DatabaseSchemaExplorerTreeTableNodeData + ? `${node.owner.name}.${node.label}` + : node.label, + }, + }), + [node], + ); + const nodeTypeIcon = getDatabaseSchemaNodeIcon(node); + const toggleExpandNode = (): void => onNodeSelect?.(node); + const isPrimaryKeyColumn = + node instanceof DatabaseSchemaExplorerTreeColumnNodeData && + node.owner.primaryKey.includes(node.column); + + return ( +
+
+
+ {nodeExpandIcon} +
+
+ {nodeTypeIcon} +
+
+
+ {node.label} + {node instanceof DatabaseSchemaExplorerTreeColumnNodeData && ( +
+
+ {stringifyDataType(node.column.type)} +
+
+ )} + {isPrimaryKeyColumn && ( +
+ +
+ )} +
+
+ ); +}; + +export const DatabaseSchemaExplorer = observer( + (props: { + treeData: DatabaseSchemaExplorerTreeData; + playgroundState: SQLPlaygroundPanelState; + }) => { + const { treeData, playgroundState } = props; + const applicationStore = useApplicationStore(); + + const onNodeSelect = (node: DatabaseSchemaExplorerTreeNodeData): void => { + flowResult(playgroundState.onNodeSelect(node, treeData)).catch( + applicationStore.alertUnhandledError, + ); + }; + + const getChildNodes = ( + node: DatabaseSchemaExplorerTreeNodeData, + ): DatabaseSchemaExplorerTreeNodeData[] => + playgroundState + .getChildNodes(node, treeData) + ?.sort((a, b) => a.label.localeCompare(b.label)) ?? []; + + return ( + + ); + }, +); + +type RelationalDatabaseConnectionOption = { + label: React.ReactNode; + value: PackageableConnection; +}; +const buildRelationalDatabaseConnectionOption = ( + connection: PackageableConnection, +): RelationalDatabaseConnectionOption => { + const connectionValue = guaranteeRelationalDatabaseConnection(connection); + return { + value: connection, + label: ( +
+
+ {connection.name} +
+
+ {connectionValue.type} +
+
+ ), + }; +}; + +// List of most popular SQL keywords +// See https://www.w3schools.com/sql/sql_ref_keywords.asp +const SQL_KEYWORDS = [ + 'AND', + 'AS', + 'ASC', + 'BETWEEN', + 'DESC', + 'DISTINCT', + 'EXEC', + 'EXISTS', + 'FROM', + 'FULL OUTER JOIN', + 'GROUP BY', + 'HAVING', + 'IN', + 'INNER JOIN', + 'IS NULL', + 'IS NOT NULL', + 'JOIN', + 'LEFT JOIN', + 'LIKE', + 'LIMIT', + 'NOT', + 'NOT NULL', + 'OR', + 'ORDER BY', + 'OUTER JOIN', + 'RIGHT JOIN', + 'SELECT', + 'SELECT DISTINCT', + 'SELECT INTO', + 'SELECT TOP', + 'TOP', + 'UNION', + 'UNION ALL', + 'UNIQUE', + 'WHERE', +]; + +const getKeySuggestions = async ( + position: IPosition, + model: monacoEditorAPI.ITextModel, + // ideStore: PureIDEStore, +): Promise => + // const importPaths = getCurrentSectionImportPaths(position, model); + // const isUsingArrowFunction = Boolean( + // model + // .getLineContent(position.lineNumber) + // .substring(0, position.column - 1) + // .match(ARROW_FUNCTION_USAGE_PATTERN), + // ); + // const isUsingConstructor = Boolean( + // model + // .getLineContent(position.lineNumber) + // .substring(0, position.column - 1) + // .match(CONSTRUCTOR_USAGE_PATTERN), + // ); + + // let suggestions: ElementSuggestion[] = []; + // try { + // suggestions = ( + // await ideStore.client.getSuggestionsForIdentifier( + // importPaths, + // isUsingConstructor + // ? [ConceptType.CLASS] + // : isUsingArrowFunction + // ? [ConceptType.FUNCTION, ConceptType.NATIVE_FUNCTION] + // : [], + // ) + // ).map((child) => deserialize(ElementSuggestion, child)); + // } catch { + // // do nothing: provide no suggestions when error ocurred + // } + SQL_KEYWORDS.map( + (keyword) => + ({ + label: keyword, + kind: monacoLanguagesAPI.CompletionItemKind.Keyword, + // filterText: keyword.pureName, + insertTextRules: + monacoLanguagesAPI.CompletionItemInsertTextRule.InsertAsSnippet, + insertText: keyword, + // attempt to push package suggestions to the bottom of the list + // sortText: + // type === ConceptType.PACKAGE + // ? `zzzz_${keyword.text}` + // : keyword.text, + } as monacoLanguagesAPI.CompletionItem), + ); + +const PlaygroundSQLCodeEditor = observer(() => { + const editorStore = useEditorStore(); + const playgroundState = editorStore.sqlPlaygroundState; + const applicationStore = useApplicationStore(); + const codeEditorRef = useRef(null); + const [editor, setEditor] = useState< + monacoEditorAPI.IStandaloneCodeEditor | undefined + >(); + const sqlConstructSuggestionProviderDisposer = useRef< + IDisposable | undefined + >(undefined); + const sqlIdentifierSuggestionProviderDisposer = useRef< + IDisposable | undefined + >(undefined); + + const executeRawSQL = (): void => { + flowResult(playgroundState.executeRawSQL()).catch( + applicationStore.alertUnhandledError, + ); + }; + const reset = (): void => { + playgroundState.resetSQL(); + }; + + useEffect(() => { + if (!editor && codeEditorRef.current) { + const element = codeEditorRef.current; + const newEditor = monacoEditorAPI.create(element, { + ...getBaseCodeEditorOptions(), + theme: CODE_EDITOR_THEME.DEFAULT_DARK, + language: CODE_EDITOR_LANGUAGE.PURE, + wordSeparators: '`~!@#%^&*()-=+[{]}\\|;:\'",.<>/?', // omit $ from default word separators + padding: { + top: 10, + }, + automaticLayout: true, + // quickSuggestions: true, + + quickSuggestions: { + comments: 'on', + other: 'on', + strings: 'on', // <=== + }, + // suggest + wordBasedSuggestions: false, + }); + + newEditor.onDidChangeModelContent(() => { + const currentVal = newEditor.getValue(); + playgroundState.setSQLText(currentVal); + }); + + // Restore the editor model and view state + newEditor.setModel(playgroundState.sqlEditorTextModel); + if (playgroundState.sqlEditorViewState) { + newEditor.restoreViewState(playgroundState.sqlEditorViewState); + } + newEditor.focus(); // focus on the editor initially + playgroundState.setSQLEditor(newEditor); + setEditor(newEditor); + } + }, [playgroundState, applicationStore, editor]); + + useCommands(playgroundState); + + // suggestions + sqlConstructSuggestionProviderDisposer.current?.dispose(); + sqlConstructSuggestionProviderDisposer.current = + monacoLanguagesAPI.registerCompletionItemProvider( + CODE_EDITOR_LANGUAGE.SQL, + { + triggerCharacters: ['.'], + provideCompletionItems: async (model, position, context) => { + const suggestions: monacoLanguagesAPI.CompletionItem[] = []; + // console.log('comodo'); + // if ( + // context.triggerKind === + // monacoLanguagesAPI.CompletionTriggerKind.TriggerCharacter + // ) { + // switch (context.triggerCharacter) { + // case '.': { + // suggestions = suggestions.concat( + // await getAttributeSuggestions(position, model, ideStore), + // ); + // break; + // } + // default: + // break; + // } + // } + + return { suggestions }; + }, + }, + ); + + sqlIdentifierSuggestionProviderDisposer.current?.dispose(); + sqlIdentifierSuggestionProviderDisposer.current = + monacoLanguagesAPI.registerCompletionItemProvider( + CODE_EDITOR_LANGUAGE.PURE, + { + triggerCharacters: [], + provideCompletionItems: async (model, position, context) => { + let suggestions: monacoLanguagesAPI.CompletionItem[] = []; + if ( + context.triggerKind === + monacoLanguagesAPI.CompletionTriggerKind.Invoke + ) { + // suggestions + suggestions = suggestions.concat( + await getKeySuggestions(position, model), + ); + } + + return { suggestions }; + }, + }, + ); + + // clean up + useEffect( + () => (): void => { + if (editor) { + // persist editor view state (cursor, scroll, etc.) to restore on re-open + playgroundState.setSQLEditorViewState( + editor.saveViewState() ?? undefined, + ); + // NOTE: dispose the editor to prevent potential memory-leak + editor.dispose(); + } + + sqlConstructSuggestionProviderDisposer.current?.dispose(); + sqlIdentifierSuggestionProviderDisposer.current?.dispose(); + }, + [playgroundState, editor], + ); + + const handleDatabaseNodeDrop = useCallback( + (item: DatabaseNodeDragType): void => { + if (isString(item.text)) { + if (playgroundState.sqlEditor) { + const currentValue = playgroundState.sqlEditorTextModel.getValue(); + const lines = currentValue.split('\n'); + const position = playgroundState.sqlEditor.getPosition() ?? { + lineNumber: lines.length, + column: getNullableLastEntry(lines)?.length ?? 0, + }; + playgroundState.sqlEditor.executeEdits('', [ + { + range: { + startLineNumber: position.lineNumber, + startColumn: position.column, + endLineNumber: position.lineNumber, + endColumn: position.column, + }, + text: item.text, + forceMoveMarkers: true, + }, + ]); + playgroundState.setSQLText( + playgroundState.sqlEditorTextModel.getValue(), + ); + } + } + }, + [playgroundState], + ); + const [{ isDatabaseNodeDragOver }, dropConnector] = useDrop< + DatabaseNodeDragType, + void, + { isDatabaseNodeDragOver: boolean } + >( + () => ({ + accept: DATABASE_NODE_DND_TYPE, + drop: (item): void => handleDatabaseNodeDrop(item), + collect: (monitor) => ({ + isDatabaseNodeDragOver: monitor.isOver({ shallow: true }), + }), + }), + [handleDatabaseNodeDrop], + ); + + return ( +
+ +
+
+ + +
+
+ +
+
+
+ +
+ ); +}); + +const parseExecutionResultData = ( + data: string, +): { rowData: Record[]; columns: string[] } | undefined => { + const lines = data.split('\n').filter((line) => line.trim().length); + if (lines.length) { + const columns = parseCSVString(getNonNullableEntry(lines, 0)) ?? []; + const rowData = lines + .slice(1) + .map((item) => { + const rowItems = parseCSVString(item); + if (!rowItems) { + return undefined; + } + const row: Record = {}; + columns.forEach((column, idx) => { + row[column] = getNullableEntry(rowItems, idx) ?? ''; + }); + return row; + }) + .filter(isNonNullable); + return { rowData, columns }; + } + return undefined; +}; + +const PlayGroundSQLExecutionResultGrid = observer( + (props: { result: string }) => { + const { result } = props; + const data = parseExecutionResultData(result); + + if (!data) { + return ( + {`Can't parse result, displaying raw form:\n${result}`} + ); + } + return ( +
+ No results
`} + alwaysShowVerticalScroll={true} + suppressFieldDotNotation={true} + columnDefs={data.columns.map((column) => ({ + minWidth: 50, + sortable: true, + resizable: true, + headerName: column, + field: column, + flex: 1, + }))} + /> +
+ ); + }, +); + +type SQLPlaygroundPanelDropTarget = ElementDragSource; + +export const SQLPlaygroundPanel = observer(() => { + const editorStore = useEditorStore(); + const playgroundState = editorStore.sqlPlaygroundState; + const applicationStore = useApplicationStore(); + + // connection + const connectionSelectorRef = useRef(null); + const connectionFilterOption = createFilter({ + ignoreCase: true, + ignoreAccents: false, + stringify: (option: RelationalDatabaseConnectionOption): string => + option.value.path, + }); + const connectionOptions = editorStore.graphManagerState.usableConnections + .filter( + (connection) => + connection.connectionValue instanceof RelationalDatabaseConnection, + ) + .map(buildRelationalDatabaseConnectionOption); + const selectedConnectionOption = playgroundState.connection + ? buildRelationalDatabaseConnectionOption(playgroundState.connection) + : null; + const changeConnection = (val: RelationalDatabaseConnectionOption): void => { + if (val.value === playgroundState.connection) { + return; + } + playgroundState.setConnection(val.value); + }; + + const handleConnectionDrop = useCallback( + (item: SQLPlaygroundPanelDropTarget): void => { + if (item.data.packageableElement instanceof PackageableConnection) { + if ( + item.data.packageableElement.connectionValue instanceof + RelationalDatabaseConnection + ) { + playgroundState.setConnection(item.data.packageableElement); + } else { + applicationStore.notificationService.notifyWarning( + `Can't use SQL playground with non-relational database connection`, + ); + } + } + }, + [playgroundState, applicationStore], + ); + const [{ isConnectionDragOver }, dropConnector] = useDrop< + ElementDragSource, + void, + { isConnectionDragOver: boolean } + >( + () => ({ + accept: CORE_DND_TYPE.PROJECT_EXPLORER_CONNECTION, + drop: (item) => handleConnectionDrop(item), + collect: (monitor) => ({ + isConnectionDragOver: monitor.isOver({ shallow: true }), + }), + }), + [handleConnectionDrop], + ); + + useEffect(() => { + flowResult(playgroundState.fetchDatabaseMetadata()).catch( + applicationStore.alertUnhandledError, + ); + }, [playgroundState, applicationStore, playgroundState.connection]); + + useConditionedApplicationNavigationContext( + LEGEND_STUDIO_APPLICATION_NAVIGATION_CONTEXT_KEY.SQL_PLAYGROUND, + editorStore.activePanelMode === PANEL_MODE.SQL_PLAYGROUND, + ); + + return ( + +
+ {playgroundState.connection && ( + + +
+
+
+ +
+ +
+
+ {playgroundState.treeData && ( + + )} +
+
+
+ + +
+ + + + + + + + + {playgroundState.sqlExecutionResult !== undefined && ( + + )} + {playgroundState.sqlExecutionResult === undefined && ( +
+ )} + + +
+
+
+ )} + {!playgroundState.connection && ( + + )} +
+ + ); +}); diff --git a/packages/legend-application-studio/src/components/editor/side-bar/Explorer.tsx b/packages/legend-application-studio/src/components/editor/side-bar/Explorer.tsx index 27ebb5749b..ac352c78d2 100644 --- a/packages/legend-application-studio/src/components/editor/side-bar/Explorer.tsx +++ b/packages/legend-application-studio/src/components/editor/side-bar/Explorer.tsx @@ -100,6 +100,7 @@ import { type PackageableElement, PackageableConnection, RelationalDatabaseConnection, + guaranteeRelationalDatabaseConnection, } from '@finos/legend-graph'; import { useApplicationStore } from '@finos/legend-application'; import { @@ -122,7 +123,6 @@ import { CODE_EDITOR_LANGUAGE, CodeEditor, } from '@finos/legend-lego/code-editor'; -import { guaranteeRelationalDatabaseConnection } from '../../../stores/editor/editor-state/element-editor-state/connection/DatabaseBuilderState.js'; import { DatabaseBuilder } from '../editor-group/connection-editor/DatabaseBuilder.js'; const ElementRenamer = observer(() => { @@ -684,7 +684,7 @@ const ExplorerContextMenu = observer( {elementTypes.map((type) => ( - {getElementTypeIcon(editorStore, type)} + {getElementTypeIcon(type, editorStore)} New {toTitleCase(getElementTypeLabel(editorStore, type))}... @@ -844,7 +844,7 @@ const PackageTreeNodeContainer = observer(
) ) : ( - getElementIcon(editorStore, node.packageableElement) + getElementIcon(node.packageableElement, editorStore) ); const selectNode = (): void => onNodeSelect?.(node); const onContextMenuOpen = (): void => setIsSelectedFromContextMenu(true); @@ -925,7 +925,7 @@ const ExplorerDropdownMenu = observer(() => { {elementTypes.map((type) => ( - {getElementTypeIcon(editorStore, type)} + {getElementTypeIcon(type, editorStore)} New {toTitleCase(getElementTypeLabel(editorStore, type))}... diff --git a/packages/legend-application-studio/src/components/editor/side-bar/testable/GlobalTestRunner.tsx b/packages/legend-application-studio/src/components/editor/side-bar/testable/GlobalTestRunner.tsx index 31d1850541..b83ce7f970 100644 --- a/packages/legend-application-studio/src/components/editor/side-bar/testable/GlobalTestRunner.tsx +++ b/packages/legend-application-studio/src/components/editor/side-bar/testable/GlobalTestRunner.tsx @@ -317,10 +317,10 @@ const TestableTreeNodeContainer: React.FC< node instanceof TestableTreeNodeData ? node.testableMetadata.testable instanceof PackageableElement ? getElementTypeIcon( - editorStore, editorStore.graphState.getPackageableElementType( node.testableMetadata.testable, ), + editorStore, ) : null : null; diff --git a/packages/legend-application-studio/src/components/extensions/Core_LegendStudioApplicationPlugin.tsx b/packages/legend-application-studio/src/components/extensions/Core_LegendStudioApplicationPlugin.tsx index 55500861ba..da1bbc3269 100644 --- a/packages/legend-application-studio/src/components/extensions/Core_LegendStudioApplicationPlugin.tsx +++ b/packages/legend-application-studio/src/components/extensions/Core_LegendStudioApplicationPlugin.tsx @@ -39,6 +39,7 @@ import { configureCodeEditorComponent, setupPureLanguageService, } from '@finos/legend-lego/code-editor'; +import { STO_RELATIONAL_LEGEND_STUDIO_COMMAND_CONFIG } from '../../__lib__/STO_Relational_LegendStudioCommand.js'; export class Core_LegendStudioApplicationPlugin extends LegendStudioApplicationPlugin { static NAME = packageJson.extensions.applicationStudioPlugin; @@ -66,9 +67,14 @@ export class Core_LegendStudioApplicationPlugin extends LegendStudioApplicationP } override getExtraKeyedCommandConfigEntries(): KeyedCommandConfigEntry[] { - return collectKeyedCommandConfigEntriesFromConfig( - LEGEND_STUDIO_COMMAND_CONFIG, - ); + return [ + ...collectKeyedCommandConfigEntriesFromConfig( + LEGEND_STUDIO_COMMAND_CONFIG, + ), + ...collectKeyedCommandConfigEntriesFromConfig( + STO_RELATIONAL_LEGEND_STUDIO_COMMAND_CONFIG, + ), + ]; } override getExtraRequiredDocumentationKeys(): string[] { diff --git a/packages/legend-application-studio/src/stores/editor/EditorConfig.ts b/packages/legend-application-studio/src/stores/editor/EditorConfig.ts index 9c57a33170..41eb817f78 100644 --- a/packages/legend-application-studio/src/stores/editor/EditorConfig.ts +++ b/packages/legend-application-studio/src/stores/editor/EditorConfig.ts @@ -43,6 +43,7 @@ export enum PANEL_MODE { CONSOLE = 'COMPILE', DEV_TOOL = 'DEV_TOOL', PROBLEMS = 'PROBLEMS', + SQL_PLAYGROUND = 'SQL_PLAYGROUND', } export enum ELEMENT_NATIVE_VIEW_MODE { diff --git a/packages/legend-application-studio/src/stores/editor/EditorStore.ts b/packages/legend-application-studio/src/stores/editor/EditorStore.ts index 0a65503e5d..63364d8fd9 100644 --- a/packages/legend-application-studio/src/stores/editor/EditorStore.ts +++ b/packages/legend-application-studio/src/stores/editor/EditorStore.ts @@ -101,6 +101,7 @@ import { GraphEditFormModeState } from './GraphEditFormModeState.js'; import type { GraphEditorMode } from './GraphEditorMode.js'; import { GraphEditGrammarModeState } from './GraphEditGrammarModeState.js'; import { GlobalBulkServiceRegistrationState } from './sidebar-state/BulkServiceRegistrationState.js'; +import { SQLPlaygroundPanelState } from './panel-group/SQLPlaygroundPanelState.js'; export abstract class EditorExtensionState { /** @@ -149,6 +150,7 @@ export class EditorStore implements CommandRegistrar { conflictResolutionState: WorkspaceUpdateConflictResolutionState; globalBulkServiceRegistrationState: GlobalBulkServiceRegistrationState; devToolState: DevToolPanelState; + sqlPlaygroundState: SQLPlaygroundPanelState; modelImporterState: ModelImporterState; projectConfigurationEditorState: ProjectConfigurationEditorState; @@ -227,6 +229,7 @@ export class EditorStore implements CommandRegistrar { this.graphEditorMode = new GraphEditFormModeState(this); this.changeDetectionState = new ChangeDetectionState(this, this.graphState); this.devToolState = new DevToolPanelState(this); + this.sqlPlaygroundState = new SQLPlaygroundPanelState(this); this.embeddedQueryBuilderState = new EmbeddedQueryBuilderState(this); // side bar panels this.explorerTreeState = new ExplorerTreeState(this); @@ -937,6 +940,7 @@ export class EditorStore implements CommandRegistrar { case GRAPH_EDITOR_MODE.GRAMMAR_TEXT: { const graphEditorMode = new GraphEditGrammarModeState(this); try { + yield flowResult(this.graphEditorMode.onLeave(fallbackOptions)); yield flowResult( graphEditorMode.cleanupBeforeEntering(fallbackOptions), ); diff --git a/packages/legend-application-studio/src/stores/editor/GraphEditFormModeState.ts b/packages/legend-application-studio/src/stores/editor/GraphEditFormModeState.ts index cedbdae70c..809c5c515e 100644 --- a/packages/legend-application-studio/src/stores/editor/GraphEditFormModeState.ts +++ b/packages/legend-application-studio/src/stores/editor/GraphEditFormModeState.ts @@ -577,6 +577,7 @@ export class GraphEditFormModeState extends GraphEditorMode { } *onLeave(): GeneratorFn { + this.editorStore.sqlPlaygroundState.setConnection(undefined); return; } diff --git a/packages/legend-application-studio/src/stores/editor/editor-state/element-editor-state/FunctionEditorState.ts b/packages/legend-application-studio/src/stores/editor/editor-state/element-editor-state/FunctionEditorState.ts index 004a2440fb..f19b306e82 100644 --- a/packages/legend-application-studio/src/stores/editor/editor-state/element-editor-state/FunctionEditorState.ts +++ b/packages/legend-application-studio/src/stores/editor/editor-state/element-editor-state/FunctionEditorState.ts @@ -14,7 +14,14 @@ * limitations under the License. */ -import { computed, observable, action, makeObservable } from 'mobx'; +import { + computed, + observable, + action, + makeObservable, + flow, + flowResult, +} from 'mobx'; import type { EditorStore } from '../../EditorStore.js'; import { type GeneratorFn, @@ -22,6 +29,9 @@ import { LogEvent, guaranteeType, assertType, + StopWatch, + stringifyLosslessJSON, + filterByType, } from '@finos/legend-shared'; import { ElementEditorState } from './ElementEditorState.js'; import { @@ -34,9 +44,26 @@ import { RawLambda, buildSourceInformationSourceId, isStubbed_PackageableElement, + type ExecutionResult, + type RawExecutionPlan, + reportGraphAnalytics, + buildLambdaVariableExpressions, + VariableExpression, + observe_ValueSpecification, } from '@finos/legend-graph'; -import { LambdaEditorState } from '@finos/legend-query-builder'; +import { + ExecutionPlanState, + LambdaEditorState, + LambdaParameterState, + LambdaParametersState, + PARAMETER_SUBMIT_ACTION, + QUERY_BUILDER_EVENT, + QueryBuilderTelemetryHelper, + buildExecutionParameterValues, + getExecutionQueryFromRawLambda, +} from '@finos/legend-query-builder'; import { FunctionActivatorBuilderState } from './FunctionActivatorBuilderState.js'; +import { DEFAULT_TAB_SIZE } from '@finos/legend-application'; export enum FUNCTION_EDITOR_TAB { DEFINITION = 'DEFINITION', @@ -105,7 +132,7 @@ export class FunctionDefinitionEditorState extends LambdaEditorState { const lambdas = new Map(); const functionLamba = new RawLambda( [], - this.functionElement.expressionSequence as object, + this.functionElement.expressionSequence, ); lambdas.set(this.lambdaId, functionLamba); const isolatedLambdas = @@ -154,12 +181,74 @@ export class FunctionDefinitionEditorState extends LambdaEditorState { } } +export class FunctionParametersState extends LambdaParametersState { + readonly functionEditorState: FunctionEditorState; + + constructor(functionEditorState: FunctionEditorState) { + super(); + makeObservable(this, { + parameterValuesEditorState: observable, + parameterStates: observable, + addParameter: action, + removeParameter: action, + openModal: action, + build: action, + setParameters: action, + }); + this.functionEditorState = functionEditorState; + } + + openModal(query: RawLambda): void { + this.parameterStates = this.build(query); + this.parameterValuesEditorState.open( + (): Promise => + flowResult(this.functionEditorState.runQuery()).catch( + this.functionEditorState.editorStore.applicationStore + .alertUnhandledError, + ), + PARAMETER_SUBMIT_ACTION.RUN, + ); + } + + build(query: RawLambda): LambdaParameterState[] { + const parameters = buildLambdaVariableExpressions( + query, + this.functionEditorState.editorStore.graphManagerState, + ) + .map((parameter) => + observe_ValueSpecification( + parameter, + this.functionEditorState.editorStore.changeDetectionState + .observerContext, + ), + ) + .filter(filterByType(VariableExpression)); + const states = parameters.map((variable) => { + const parmeterState = new LambdaParameterState( + variable, + this.functionEditorState.editorStore.changeDetectionState.observerContext, + this.functionEditorState.editorStore.graphManagerState.graph, + ); + parmeterState.mockParameterValue(); + return parmeterState; + }); + return states; + } +} + export class FunctionEditorState extends ElementEditorState { readonly functionDefinitionEditorState: FunctionDefinitionEditorState; readonly activatorBuilderState: FunctionActivatorBuilderState; selectedTab: FUNCTION_EDITOR_TAB; + isRunningQuery = false; + isGeneratingPlan = false; + executionResultText?: string | undefined; // NOTE: stored as lossless JSON string + executionPlanState: ExecutionPlanState; + parametersState: FunctionParametersState; + queryRunPromise: Promise | undefined = undefined; + constructor(editorStore: EditorStore, element: PackageableElement) { super(editorStore, element); @@ -168,6 +257,16 @@ export class FunctionEditorState extends ElementEditorState { functionElement: computed, setSelectedTab: action, reprocess: action, + isRunningQuery: observable, + isGeneratingPlan: observable, + executionResultText: observable, + executionPlanState: observable, + setExecutionResultText: action, + setIsRunningQuery: action, + runQuery: flow, + generatePlan: flow, + handleRunQuery: flow, + cancelQuery: flow, }); assertType( @@ -181,6 +280,11 @@ export class FunctionEditorState extends ElementEditorState { this.editorStore, ); this.activatorBuilderState = new FunctionActivatorBuilderState(this); + this.executionPlanState = new ExecutionPlanState( + this.editorStore.applicationStore, + this.editorStore.graphManagerState, + ); + this.parametersState = new FunctionParametersState(this); } get functionElement(): ConcreteFunctionDefinition { @@ -231,4 +335,214 @@ export class FunctionEditorState extends ElementEditorState { functionEditorState.selectedTab = this.selectedTab; return functionEditorState; } + + setIsRunningQuery(val: boolean): void { + this.isRunningQuery = val; + } + + setExecutionResultText = (executionResult: string | undefined): void => { + this.executionResultText = executionResult; + }; + + setQueryRunPromise = ( + promise: Promise | undefined, + ): void => { + this.queryRunPromise = promise; + }; + + get query(): RawLambda { + return new RawLambda( + this.functionElement.parameters.map((parameter) => + this.editorStore.graphManagerState.graphManager.serializeRawValueSpecification( + parameter, + ), + ), + this.functionElement.expressionSequence, + ); + } + + *generatePlan(debug: boolean): GeneratorFn { + if (this.isGeneratingPlan) { + return; + } + try { + const query = this.query; + this.isGeneratingPlan = true; + let rawPlan: RawExecutionPlan; + + const stopWatch = new StopWatch(); + const report = reportGraphAnalytics( + this.editorStore.graphManagerState.graph, + ); + + if (debug) { + QueryBuilderTelemetryHelper.logEvent_ExecutionPlanDebugLaunched( + this.editorStore.applicationStore.telemetryService, + ); + const debugResult = + (yield this.editorStore.graphManagerState.graphManager.debugExecutionPlanGeneration( + query, + undefined, + undefined, + this.editorStore.graphManagerState.graph, + report, + )) as { plan: RawExecutionPlan; debug: string }; + rawPlan = debugResult.plan; + this.executionPlanState.setDebugText(debugResult.debug); + } else { + QueryBuilderTelemetryHelper.logEvent_ExecutionPlanGenerationLaunched( + this.editorStore.applicationStore.telemetryService, + ); + rawPlan = + (yield this.editorStore.graphManagerState.graphManager.generateExecutionPlan( + query, + undefined, + undefined, + this.editorStore.graphManagerState.graph, + report, + )) as object; + } + + stopWatch.record(); + try { + this.executionPlanState.setRawPlan(rawPlan); + const plan = + this.editorStore.graphManagerState.graphManager.buildExecutionPlan( + rawPlan, + this.editorStore.graphManagerState.graph, + ); + this.executionPlanState.setPlan(plan); + } catch { + // do nothing + } + stopWatch.record(QUERY_BUILDER_EVENT.BUILD_EXECUTION_PLAN__SUCCESS); + + // report + report.timings = + this.editorStore.applicationStore.timeService.finalizeTimingsRecord( + stopWatch, + report.timings, + ); + if (debug) { + QueryBuilderTelemetryHelper.logEvent_ExecutionPlanDebugSucceeded( + this.editorStore.applicationStore.telemetryService, + report, + ); + } else { + QueryBuilderTelemetryHelper.logEvent_ExecutionPlanGenerationSucceeded( + this.editorStore.applicationStore.telemetryService, + report, + ); + } + } catch (error) { + assertErrorThrown(error); + this.editorStore.applicationStore.logService.error( + LogEvent.create(GRAPH_MANAGER_EVENT.EXECUTION_FAILURE), + error, + ); + this.editorStore.applicationStore.notificationService.notifyError(error); + } finally { + this.isGeneratingPlan = false; + } + } + + *handleRunQuery(): GeneratorFn { + if (this.isRunningQuery) { + return; + } + const query = this.query; + const parameters = (query.parameters ?? []) as object[]; + if (parameters.length) { + this.parametersState.openModal(query); + } else { + this.runQuery(); + } + } + + *runQuery(): GeneratorFn { + if (this.isRunningQuery) { + return; + } + + QueryBuilderTelemetryHelper.logEvent_QueryRunLaunched( + this.editorStore.applicationStore.telemetryService, + ); + + let promise; + try { + this.isRunningQuery = true; + const stopWatch = new StopWatch(); + const report = reportGraphAnalytics( + this.editorStore.graphManagerState.graph, + ); + promise = this.editorStore.graphManagerState.graphManager.runQuery( + getExecutionQueryFromRawLambda( + this.query, + this.parametersState.parameterStates, + this.editorStore.graphManagerState, + ), + undefined, + undefined, + this.editorStore.graphManagerState.graph, + { + useLosslessParse: true, + parameterValues: buildExecutionParameterValues( + this.parametersState.parameterStates, + this.editorStore.graphManagerState, + ), + }, + report, + ); + this.setQueryRunPromise(promise); + const result = (yield promise) as ExecutionResult; + if (this.queryRunPromise === promise) { + this.setExecutionResultText( + stringifyLosslessJSON(result, undefined, DEFAULT_TAB_SIZE), + ); + this.parametersState.setParameters([]); + // report + report.timings = + this.editorStore.applicationStore.timeService.finalizeTimingsRecord( + stopWatch, + report.timings, + ); + QueryBuilderTelemetryHelper.logEvent_QueryRunSucceeded( + this.editorStore.applicationStore.telemetryService, + report, + ); + } + } catch (error) { + // When user cancels the query by calling the cancelQuery api, it will throw an exeuction failure error. + // For now, we don't want to notify users about this failure. Therefore we check to ensure the promise is still the same one. + // When cancelled the query, we set the queryRunPromise as undefined. + this.editorStore.applicationStore.logService.error( + LogEvent.create(GRAPH_MANAGER_EVENT.EXECUTION_FAILURE), + error, + ); + if (this.queryRunPromise === promise) { + assertErrorThrown(error); + this.editorStore.applicationStore.notificationService.notifyError( + error, + ); + } + } finally { + this.isRunningQuery = false; + } + } + + *cancelQuery(): GeneratorFn { + this.setIsRunningQuery(false); + this.setQueryRunPromise(undefined); + try { + yield this.editorStore.graphManagerState.graphManager.cancelUserExecutions( + true, + ); + } catch (error) { + // Don't notify users about success or failure + this.editorStore.applicationStore.logService.error( + LogEvent.create(GRAPH_MANAGER_EVENT.EXECUTION_FAILURE), + error, + ); + } + } } diff --git a/packages/legend-application-studio/src/stores/editor/editor-state/element-editor-state/ProtocolValueBuilderState.ts b/packages/legend-application-studio/src/stores/editor/editor-state/element-editor-state/ProtocolValueBuilderState.ts index 3683f418e5..2a58791015 100644 --- a/packages/legend-application-studio/src/stores/editor/editor-state/element-editor-state/ProtocolValueBuilderState.ts +++ b/packages/legend-application-studio/src/stores/editor/editor-state/element-editor-state/ProtocolValueBuilderState.ts @@ -25,7 +25,12 @@ import { type Property, classHasCycle, } from '@finos/legend-graph'; -import { isString, uuid, type PlainObject } from '@finos/legend-shared'; +import { + isString, + uuid, + type PlainObject, + prettyCONSTName, +} from '@finos/legend-shared'; import type { TreeData, TreeNodeData } from '@finos/legend-art'; export abstract class ProtocolValueFieldNode implements TreeNodeData { @@ -331,7 +336,11 @@ export class ProtocolValueBuilderState { break; } case PRIMITIVE_TYPE.STRING: { - value[property.name] = ''; + // NOTE: this just provides some default value, and they are not necessarily sensible + // perhaps, we can create a mechanism for this class where we can inject value to fields + // but that might violate the generic usage principle of this builder as this builder's + // user should be relatively agnostic to the extension they are picking + value[property.name] = prettyCONSTName(property.name); break; } case PRIMITIVE_TYPE.DATE: diff --git a/packages/legend-application-studio/src/stores/editor/editor-state/element-editor-state/connection/DatabaseBuilderState.ts b/packages/legend-application-studio/src/stores/editor/editor-state/element-editor-state/connection/DatabaseBuilderState.ts index d62bc34974..584ec84050 100644 --- a/packages/legend-application-studio/src/stores/editor/editor-state/element-editor-state/connection/DatabaseBuilderState.ts +++ b/packages/legend-application-studio/src/stores/editor/editor-state/element-editor-state/connection/DatabaseBuilderState.ts @@ -28,16 +28,22 @@ import { isNonNullable, filterByType, ActionState, - guaranteeType, + getNonNullableEntry, } from '@finos/legend-shared'; -import { observable, action, makeObservable, flow, flowResult } from 'mobx'; +import { + observable, + action, + makeObservable, + flow, + flowResult, + computed, +} from 'mobx'; import { LEGEND_STUDIO_APP_EVENT } from '../../../../../__lib__/LegendStudioEvent.js'; import type { EditorStore } from '../../../EditorStore.js'; import { type Schema, - type PackageableElement, type Table, - RelationalDatabaseConnection, + type RelationalDatabaseConnection, DatabaseBuilderInput, DatabasePattern, TargetDatabase, @@ -50,19 +56,10 @@ import { getSchema, getNullableSchema, getNullableTable, - PackageableConnection, } from '@finos/legend-graph'; import { connection_setStore } from '../../../../graph-modifier/DSL_Mapping_GraphModifierHelper.js'; import { GraphEditFormModeState } from '../../../GraphEditFormModeState.js'; -export const guaranteeRelationalDatabaseConnection = ( - val: PackageableElement | undefined, -): RelationalDatabaseConnection => - guaranteeType( - guaranteeType(val, PackageableConnection).connectionValue, - RelationalDatabaseConnection, - ); - export abstract class DatabaseBuilderTreeNodeData implements TreeNodeData { isOpen?: boolean | undefined; id: string; @@ -72,35 +69,52 @@ export abstract class DatabaseBuilderTreeNodeData implements TreeNodeData { isChecked = false; constructor(id: string, label: string, parentId: string | undefined) { + makeObservable(this, { + isChecked: observable, + setChecked: action, + }); + this.id = id; this.label = label; this.parentId = parentId; } + + setChecked(val: boolean): void { + this.isChecked = val; + } } export class SchemaDatabaseBuilderTreeNodeData extends DatabaseBuilderTreeNodeData { schema: Schema; - constructor(id: string, parentId: string | undefined, schema: Schema) { - super(id, schema.name, parentId); + constructor(id: string, schema: Schema) { + super(id, schema.name, undefined); this.schema = schema; } } export class TableDatabaseBuilderTreeNodeData extends DatabaseBuilderTreeNodeData { + override parentId: string; + owner: Schema; table: Table; - constructor(id: string, parentId: string | undefined, table: Table) { + constructor(id: string, parentId: string, owner: Schema, table: Table) { super(id, table.name, parentId); + this.parentId = parentId; + this.owner = owner; this.table = table; } } export class ColumnDatabaseBuilderTreeNodeData extends DatabaseBuilderTreeNodeData { + override parentId: string; + owner: Table; column: Column; - constructor(id: string, parentId: string | undefined, column: Column) { + constructor(id: string, parentId: string, owner: Table, column: Column) { super(id, column.name, parentId); + this.parentId = parentId; + this.owner = owner; this.column = column; } } @@ -110,54 +124,61 @@ export interface DatabaseBuilderTreeData database: Database; } -const WILDCARD = '%'; +const DEFAULT_DATABASE_PATH = 'store::MyDatabase'; export class DatabaseBuilderState { - editorStore: EditorStore; - connection: RelationalDatabaseConnection; + readonly editorStore: EditorStore; + readonly connection: RelationalDatabaseConnection; + readonly isReadOnly: boolean; + showModal = false; databaseGrammarCode = ''; isBuildingDatabase = false; isSavingDatabase = false; targetDatabasePath: string; treeData?: DatabaseBuilderTreeData | undefined; - isReadOnly: boolean; constructor( editorStore: EditorStore, connection: RelationalDatabaseConnection, isReadOnly: boolean, ) { - makeObservable< - DatabaseBuilderState, - 'buildDatabaseFromInput' | 'buildDatabaseGrammar' - >(this, { + makeObservable(this, { showModal: observable, targetDatabasePath: observable, isBuildingDatabase: observable, databaseGrammarCode: observable, isSavingDatabase: observable, + currentDatabase: computed, setTargetDatabasePath: action, setShowModal: action, setDatabaseGrammarCode: action, setTreeData: action, treeData: observable, onNodeSelect: flow, - buildDatabaseGrammar: flow, - buildDatabaseFromInput: flow, - buildDatabaseWithTreeData: flow, + generateDatabase: flow, + previewDatabaseModel: flow, createOrUpdateDatabase: flow, - fetchSchemaDefinitions: flow, + fetchDatabaseMetadata: flow, fetchSchemaMetadata: flow, fetchTableMetadata: flow, }); this.connection = connection; this.editorStore = editorStore; - this.targetDatabasePath = this.currentDatabase?.path ?? 'store::MyDatabase'; + this.targetDatabasePath = + this.currentDatabase?.path ?? DEFAULT_DATABASE_PATH; this.isReadOnly = isReadOnly; } + get currentDatabase(): Database | undefined { + const store = this.connection.store.value; + if (store instanceof Database && !isStubbed_PackageableElement(store)) { + return store; + } + return undefined; + } + setShowModal(val: boolean): void { this.showModal = val; } @@ -206,10 +227,10 @@ export class DatabaseBuilderState { node: DatabaseBuilderTreeNodeData, treeData: DatabaseBuilderTreeData, ): void { - node.isChecked = !node.isChecked; + node.setChecked(!node.isChecked); if (node instanceof SchemaDatabaseBuilderTreeNodeData) { - this.getChildNodes(node, treeData)?.forEach((n) => { - n.isChecked = node.isChecked; + this.getChildNodes(node, treeData)?.forEach((childNode) => { + childNode.setChecked(node.isChecked); }); } else if (node instanceof TableDatabaseBuilderTreeNodeData) { if (node.parentId) { @@ -220,7 +241,7 @@ export class DatabaseBuilderState { (e) => e.isChecked === node.isChecked, ) ) { - parent.isChecked = node.isChecked; + parent.setChecked(node.isChecked); } } } @@ -228,46 +249,42 @@ export class DatabaseBuilderState { this.setTreeData({ ...treeData }); } - private buildNonEnrichedDbBuilderInput( - schema?: string, - ): DatabaseBuilderInput { - const databaseBuilderInput = new DatabaseBuilderInput(this.connection); - const [packagePath, databaseName] = this.getDatabasePackageAndName(); - databaseBuilderInput.targetDatabase = new TargetDatabase( - packagePath, - databaseName, - ); - databaseBuilderInput.config.maxTables = undefined; - databaseBuilderInput.config.enrichTables = Boolean(schema); - databaseBuilderInput.config.patterns = [ - new DatabasePattern(schema ?? WILDCARD, WILDCARD), - ]; - return databaseBuilderInput; - } - - *fetchSchemaDefinitions(): GeneratorFn { + *fetchDatabaseMetadata(): GeneratorFn { try { this.isBuildingDatabase = true; - const databaseBuilderInput = this.buildNonEnrichedDbBuilderInput(); - const database = (yield flowResult( - this.buildDatabaseFromInput(databaseBuilderInput), + const databaseBuilderInput = new DatabaseBuilderInput(this.connection); + const [packagePath, databaseName] = this.getDatabasePackageAndName(); + databaseBuilderInput.targetDatabase = new TargetDatabase( + packagePath, + databaseName, + ); + databaseBuilderInput.config.maxTables = undefined; + databaseBuilderInput.config.enrichTables = false; + databaseBuilderInput.config.patterns = [ + new DatabasePattern(undefined, undefined), + ]; + const database = (yield this.buildIntermediateDatabase( + databaseBuilderInput, )) as Database; + const rootIds: string[] = []; const nodes = new Map(); database.schemas .slice() .sort((schemaA, schemaB) => schemaA.name.localeCompare(schemaB.name)) - .forEach((dbSchema) => { - const schemaId = dbSchema.name; + .forEach((schema) => { + const schemaId = schema.name; rootIds.push(schemaId); const schemaNode = new SchemaDatabaseBuilderTreeNodeData( schemaId, - undefined, - dbSchema, + schema, ); - schemaNode.isChecked = Boolean( - this.currentDatabase?.schemas.find( - (cSchema) => cSchema.name === dbSchema.name, + + schemaNode.setChecked( + Boolean( + this.currentDatabase?.schemas.find( + (cSchema) => cSchema.name === schema.name, + ), ), ); nodes.set(schemaId, schemaNode); @@ -292,13 +309,23 @@ export class DatabaseBuilderState { ): GeneratorFn { try { this.isBuildingDatabase = true; + const schema = schemaNode.schema; - const databaseBuilderInput = this.buildNonEnrichedDbBuilderInput( - schema.name, + const databaseBuilderInput = new DatabaseBuilderInput(this.connection); + const [packagePath, databaseName] = this.getDatabasePackageAndName(); + databaseBuilderInput.targetDatabase = new TargetDatabase( + packagePath, + databaseName, ); - const database = (yield flowResult( - this.buildDatabaseFromInput(databaseBuilderInput), + databaseBuilderInput.config.maxTables = undefined; + databaseBuilderInput.config.enrichTables = true; + databaseBuilderInput.config.patterns = [ + new DatabasePattern(schema.name, undefined), + ]; + const database = (yield this.buildIntermediateDatabase( + databaseBuilderInput, )) as Database; + const tables = getSchema(database, schema.name).tables; const childrenIds = schemaNode.childrenIds ?? []; schema.tables = tables; @@ -311,6 +338,7 @@ export class DatabaseBuilderState { const tableNode = new TableDatabaseBuilderTreeNodeData( tableId, schemaNode.id, + schema, table, ); @@ -319,13 +347,15 @@ export class DatabaseBuilderState { this.currentDatabase, schema.name, ); - tableNode.isChecked = Boolean( - matchingSchema - ? getNullableTable(matchingSchema, table.name) - : undefined, + tableNode.setChecked( + Boolean( + matchingSchema + ? getNullableTable(matchingSchema, table.name) + : undefined, + ), ); } else { - tableNode.isChecked = false; + tableNode.setChecked(false); } treeData.nodes.set(tableId, tableNode); @@ -350,6 +380,8 @@ export class DatabaseBuilderState { treeData: DatabaseBuilderTreeData, ): GeneratorFn { try { + this.isBuildingDatabase = true; + const databaseBuilderInput = new DatabaseBuilderInput(this.connection); const [packagePath, databaseName] = resolvePackagePathAndElementName( this.targetDatabasePath, @@ -358,21 +390,46 @@ export class DatabaseBuilderState { packagePath, databaseName, ); + const table = tableNode.table; const config = databaseBuilderInput.config; config.maxTables = undefined; config.enrichTables = true; config.enrichColumns = true; config.enrichPrimaryKeys = true; - const table = tableNode.table; config.patterns = [new DatabasePattern(table.schema.name, table.name)]; - const database = (yield flowResult( - this.buildDatabaseFromInput(databaseBuilderInput), + const database = (yield this.buildIntermediateDatabase( + databaseBuilderInput, )) as Database; + const enrichedTable = database.schemas .find((s) => table.schema.name === s.name) ?.tables.find((t) => t.name === table.name); if (enrichedTable) { - this.addColumnsNodeToTableNode(tableNode, enrichedTable, treeData); + table.primaryKey = enrichedTable.primaryKey; + const columns = enrichedTable.columns.filter(filterByType(Column)); + tableNode.table.columns = columns; + tableNode.childrenIds?.forEach((childId) => + treeData.nodes.delete(childId), + ); + tableNode.childrenIds = undefined; + const childrenIds: string[] = []; + const tableId = tableNode.id; + columns + .slice() + .sort((colA, colB) => colA.name.localeCompare(colB.name)) + .forEach((column) => { + const columnId = `${tableId}.${column.name}`; + const columnNode = new ColumnDatabaseBuilderTreeNodeData( + columnId, + tableId, + table, + column, + ); + column.owner = tableNode.table; + treeData.nodes.set(columnId, columnNode); + addUniqueEntry(childrenIds, columnId); + }); + tableNode.childrenIds = childrenIds; } } catch (error) { assertErrorThrown(error); @@ -386,44 +443,6 @@ export class DatabaseBuilderState { } } - private addColumnsNodeToTableNode( - tableNode: TableDatabaseBuilderTreeNodeData, - enrichedTable: Table, - treeData: DatabaseBuilderTreeData, - ): void { - const columns = enrichedTable.columns.filter(filterByType(Column)); - tableNode.table.columns = columns; - this.removeChildren(tableNode, treeData); - const childrenIds: string[] = []; - const tableId = tableNode.id; - columns - .slice() - .sort((colA, colB) => colA.name.localeCompare(colB.name)) - .forEach((c) => { - const columnId = `${tableId}.${c.name}`; - const columnNode = new ColumnDatabaseBuilderTreeNodeData( - columnId, - tableId, - c, - ); - c.owner = tableNode.table; - treeData.nodes.set(columnId, columnNode); - addUniqueEntry(childrenIds, columnId); - }); - tableNode.childrenIds = childrenIds; - } - - private removeChildren( - node: DatabaseBuilderTreeNodeData, - treeData: DatabaseBuilderTreeData, - ): void { - const currentChildren = node.childrenIds; - if (currentChildren) { - currentChildren.forEach((c) => treeData.nodes.delete(c)); - node.childrenIds = undefined; - } - } - private getDatabasePackageAndName(): [string, string] { if (this.currentDatabase) { return [ @@ -442,60 +461,95 @@ export class DatabaseBuilderState { ); } - *buildDatabaseWithTreeData(): GeneratorFn { + async buildIntermediateDatabase( + databaseBuilderInput: DatabaseBuilderInput, + ): Promise { + const entities = + await this.editorStore.graphManagerState.graphManager.buildDatabase( + databaseBuilderInput, + ); + const graph = this.editorStore.graphManagerState.createNewGraph(); + await this.editorStore.graphManagerState.graphManager.buildGraph( + graph, + entities, + ActionState.create(), + ); + return getNonNullableEntry( + graph.ownDatabases, + 0, + 'Expected one database to be generated from input', + ); + } + + *generateDatabase(): GeneratorFn { try { - if (this.treeData) { - const dbTreeData = this.treeData; - this.isBuildingDatabase = true; - const databaseBuilderInput = new DatabaseBuilderInput(this.connection); - const [packagePath, databaseName] = this.getDatabasePackageAndName(); - databaseBuilderInput.targetDatabase = new TargetDatabase( - packagePath, - databaseName, - ); - const config = databaseBuilderInput.config; - config.maxTables = undefined; - config.enrichTables = true; - config.enrichColumns = true; - config.enrichPrimaryKeys = true; - dbTreeData.rootIds - .map((e) => dbTreeData.nodes.get(e)) - .filter(isNonNullable) - .forEach((schemaNode) => { - if (schemaNode instanceof SchemaDatabaseBuilderTreeNodeData) { - const tableNodes = this.getChildNodes(schemaNode, dbTreeData); - const allChecked = tableNodes?.every((t) => t.isChecked === true); - if ( - allChecked || - (schemaNode.isChecked && !schemaNode.childrenIds) - ) { - config.patterns.push( - new DatabasePattern(schemaNode.schema.name, WILDCARD), - ); - } else { - tableNodes?.forEach((t) => { - if ( - t instanceof TableDatabaseBuilderTreeNodeData && - t.isChecked - ) { - config.patterns.push( - new DatabasePattern(schemaNode.schema.name, t.table.name), - ); - } - }); - } + this.isBuildingDatabase = true; + + const treeData = guaranteeNonNullable(this.treeData); + const databaseBuilderInput = new DatabaseBuilderInput(this.connection); + const [packagePath, databaseName] = this.getDatabasePackageAndName(); + databaseBuilderInput.targetDatabase = new TargetDatabase( + packagePath, + databaseName, + ); + const config = databaseBuilderInput.config; + config.maxTables = undefined; + config.enrichTables = true; + config.enrichColumns = true; + config.enrichPrimaryKeys = true; + treeData.rootIds + .map((e) => treeData.nodes.get(e)) + .filter(isNonNullable) + .forEach((schemaNode) => { + if (schemaNode instanceof SchemaDatabaseBuilderTreeNodeData) { + const tableNodes = this.getChildNodes(schemaNode, treeData); + const allChecked = tableNodes?.every((t) => t.isChecked === true); + if ( + allChecked || + (schemaNode.isChecked && !schemaNode.childrenIds) + ) { + config.patterns.push( + new DatabasePattern(schemaNode.schema.name, undefined), + ); + } else { + tableNodes?.forEach((t) => { + if ( + t instanceof TableDatabaseBuilderTreeNodeData && + t.isChecked + ) { + config.patterns.push( + new DatabasePattern(schemaNode.schema.name, t.table.name), + ); + } + }); } - }); - const entities = - (yield this.editorStore.graphManagerState.graphManager.buildDatabase( - databaseBuilderInput, - )) as Entity[]; - const dbGrammar = - (yield this.editorStore.graphManagerState.graphManager.entitiesToPureCode( - entities, - )) as string; - this.setDatabaseGrammarCode(dbGrammar); - } + } + }); + const entities = + (yield this.editorStore.graphManagerState.graphManager.buildDatabase( + databaseBuilderInput, + )) as Entity[]; + return getNonNullableEntry( + entities, + 0, + 'Expected a database to be generated', + ); + } finally { + this.isBuildingDatabase = false; + } + } + + *previewDatabaseModel(): GeneratorFn { + if (!this.treeData) { + return; + } + + try { + this.setDatabaseGrammarCode( + (yield this.editorStore.graphManagerState.graphManager.entitiesToPureCode( + [(yield flowResult(this.generateDatabase())) as Entity], + )) as string, + ); } catch (error) { assertErrorThrown(error); this.editorStore.applicationStore.logService.error( @@ -508,65 +562,26 @@ export class DatabaseBuilderState { } } - private getSchemasFromTreeNode(tree: DatabaseBuilderTreeData): Schema[] { - return Array.from(tree.nodes.values()) - .map((e) => { - if (e instanceof SchemaDatabaseBuilderTreeNodeData) { - return e.schema; - } - return undefined; - }) - .filter(isNonNullable); - } - - private *buildDatabaseGrammar(grammar: string): GeneratorFn { - const entities = - (yield this.editorStore.graphManagerState.graphManager.pureCodeToEntities( - grammar, - )) as Entity[]; - const dbGraph = this.editorStore.graphManagerState.createNewGraph(); - (yield this.editorStore.graphManagerState.graphManager.buildGraph( - dbGraph, - entities, - ActionState.create(), - )) as Entity[]; - assertTrue( - dbGraph.ownDatabases.length === 1, - 'Expected one database to be generated from grammar', - ); - return dbGraph.ownDatabases[0] as Database; - } - - private *buildDatabaseFromInput( - databaseBuilderInput: DatabaseBuilderInput, - ): GeneratorFn { - const entities = - (yield this.editorStore.graphManagerState.graphManager.buildDatabase( - databaseBuilderInput, - )) as Entity[]; - const dbGraph = this.editorStore.graphManagerState.createNewGraph(); - (yield this.editorStore.graphManagerState.graphManager.buildGraph( - dbGraph, - entities, - ActionState.create(), - )) as Entity[]; - assertTrue( - dbGraph.ownDatabases.length === 1, - 'Expected one database to be generated from input', - ); - return dbGraph.ownDatabases[0] as Database; - } - *createOrUpdateDatabase(): GeneratorFn { + if (!this.treeData) { + return; + } + try { this.isSavingDatabase = true; - assertNonEmptyString( - this.databaseGrammarCode, - 'Database grammar is empty', + + const graph = this.editorStore.graphManagerState.createNewGraph(); + (yield this.editorStore.graphManagerState.graphManager.buildGraph( + graph, + [(yield flowResult(this.generateDatabase())) as Entity], + ActionState.create(), + )) as Entity[]; + const database = getNonNullableEntry( + graph.ownDatabases, + 0, + 'Expected one database to be generated from input', ); - const database = (yield flowResult( - this.buildDatabaseGrammar(this.databaseGrammarCode), - )) as Database; + let currentDatabase: Database; const isUpdating = Boolean(this.currentDatabase); if (!this.currentDatabase) { @@ -590,22 +605,27 @@ export class DatabaseBuilderState { } else { currentDatabase = this.currentDatabase; } - if (this.treeData) { - const schemas = this.getSchemasFromTreeNode(this.treeData); - this.updateDatabase(currentDatabase, database, schemas); - this.editorStore.applicationStore.notificationService.notifySuccess( - `Database successfully '${isUpdating ? 'updated' : 'created'}.`, + const schemas = Array.from(this.treeData.nodes.values()) + .map((schemaNode) => { + if (schemaNode instanceof SchemaDatabaseBuilderTreeNodeData) { + return schemaNode.schema; + } + return undefined; + }) + .filter(isNonNullable); + this.updateDatabase(currentDatabase, database, schemas); + this.editorStore.applicationStore.notificationService.notifySuccess( + `Database successfully '${isUpdating ? 'updated' : 'created'}.`, + ); + this.fetchDatabaseMetadata(); + if (isUpdating) { + yield flowResult( + this.editorStore + .getGraphEditorMode(GraphEditFormModeState) + .globalCompile({ + message: `Can't compile graph after editing database. Redirecting you to text mode`, + }), ); - this.fetchSchemaDefinitions(); - if (isUpdating) { - yield flowResult( - this.editorStore - .getGraphEditorMode(GraphEditFormModeState) - .globalCompile({ - message: `Can't compile graph after editing database. Redirecting you to text mode`, - }), - ); - } } this.setShowModal(false); } catch (error) { @@ -622,24 +642,25 @@ export class DatabaseBuilderState { updateDatabase( current: Database, - generatedDb: Database, + generatedDatabase: Database, allSchemas: Schema[], ): void { - // remove shemas not defined + // remove undefined schemas current.schemas = current.schemas.filter((schema) => { if ( - allSchemas.find((c) => c.name === schema.name) && - !generatedDb.schemas.find((c) => c.name === schema.name) + allSchemas.find((item) => item.name === schema.name) && + !generatedDatabase.schemas.find((c) => c.name === schema.name) ) { return false; } return true; }); + // update existing schemas - generatedDb.schemas.forEach((schema) => { + generatedDatabase.schemas.forEach((schema) => { (schema as Writable)._OWNER = current; const currentSchemaIndex = current.schemas.findIndex( - (c) => c.name === schema.name, + (item) => item.name === schema.name, ); if (currentSchemaIndex !== -1) { current.schemas[currentSchemaIndex] = schema; @@ -648,12 +669,4 @@ export class DatabaseBuilderState { } }); } - - get currentDatabase(): Database | undefined { - const store = this.connection.store.value; - if (store instanceof Database && !isStubbed_PackageableElement(store)) { - return store; - } - return undefined; - } } diff --git a/packages/legend-application-studio/src/stores/editor/editor-state/element-editor-state/service/ServiceExecutionState.ts b/packages/legend-application-studio/src/stores/editor/editor-state/element-editor-state/service/ServiceExecutionState.ts index e4ef775996..84c5080457 100644 --- a/packages/legend-application-studio/src/stores/editor/editor-state/element-editor-state/service/ServiceExecutionState.ts +++ b/packages/legend-application-studio/src/stores/editor/editor-state/element-editor-state/service/ServiceExecutionState.ts @@ -110,7 +110,7 @@ const QUERY_ROUTE_PATTERN = Object.freeze({ UPDATE_PROJECT_SERVICE_QUERY: `/update-project-service-query/:${DSL_SERVICE_PATH_PARAM_TOKEN.PROJECT_ID}/:${DSL_SERVICE_PATH_PARAM_TOKEN.GROUP_WORKSPACE_ID}/:${DSL_SERVICE_PATH_PARAM_TOKEN.SERVICE_PATH}`, }); -export class ServiceExecutionParameterState extends LambdaParametersState { +export class ServiceExecutionParametersState extends LambdaParametersState { executionState: ServicePureExecutionState; constructor(executionState: ServicePureExecutionState) { @@ -164,9 +164,10 @@ export class ServiceExecutionParameterState extends LambdaParametersState { } export abstract class ServiceExecutionState { - editorStore: EditorStore; - serviceEditorState: ServiceEditorState; - execution: ServiceExecution; + readonly editorStore: EditorStore; + readonly serviceEditorState: ServiceEditorState; + readonly execution: ServiceExecution; + constructor( editorStore: EditorStore, serviceEditorState: ServiceEditorState, @@ -180,6 +181,7 @@ export abstract class ServiceExecutionState { this.execution = execution; this.serviceEditorState = serviceEditorState; } + abstract get serviceExecutionParameters(): | { query: RawLambda; mapping: Mapping; runtime: Runtime } | undefined; @@ -447,17 +449,17 @@ export class KeyedExecutionContextState extends ServiceExecutionContextState { } export abstract class ServicePureExecutionState extends ServiceExecutionState { - queryState: ServicePureExecutionQueryState; declare execution: PureExecution; + queryState: ServicePureExecutionQueryState; selectedExecutionContextState: ServiceExecutionContextState | undefined; runtimeEditorState?: RuntimeEditorState | undefined; + isOpeningQueryEditor = false; + showChangeExecModal = false; isRunningQuery = false; isGeneratingPlan = false; - isOpeningQueryEditor = false; executionResultText?: string | undefined; // NOTE: stored as lossless JSON string executionPlanState: ExecutionPlanState; - parameterState: ServiceExecutionParameterState; - showChangeExecModal = false; + readonly parametersState: ServiceExecutionParametersState; queryRunPromise: Promise | undefined = undefined; constructor( @@ -479,7 +481,7 @@ export abstract class ServicePureExecutionState extends ServiceExecutionState { this.editorStore.applicationStore, this.editorStore.graphManagerState, ); - this.parameterState = new ServiceExecutionParameterState(this); + this.parametersState = new ServiceExecutionParametersState(this); } abstract changeExecution(): void; @@ -606,7 +608,7 @@ export abstract class ServicePureExecutionState extends ServiceExecutionState { const query = this.queryState.query; const parameters = (query.parameters ?? []) as object[]; if (parameters.length) { - this.parameterState.openModal(query); + this.parametersState.openModal(query); } else { this.runQuery(); } @@ -629,14 +631,18 @@ export abstract class ServicePureExecutionState extends ServiceExecutionState { this.editorStore.graphManagerState.graph, ); promise = this.editorStore.graphManagerState.graphManager.runQuery( - this.getExecutionQuery(), + getExecutionQueryFromRawLambda( + this.queryState.query, + this.parametersState.parameterStates, + this.editorStore.graphManagerState, + ), this.selectedExecutionContextState?.executionContext.mapping.value, this.selectedExecutionContextState?.executionContext.runtime, this.editorStore.graphManagerState.graph, { useLosslessParse: true, parameterValues: buildExecutionParameterValues( - this.parameterState.parameterStates, + this.parametersState.parameterStates, this.editorStore.graphManagerState, ), }, @@ -648,7 +654,7 @@ export abstract class ServicePureExecutionState extends ServiceExecutionState { this.setExecutionResultText( stringifyLosslessJSON(result, undefined, DEFAULT_TAB_SIZE), ); - this.parameterState.setParameters([]); + this.parametersState.setParameters([]); // report report.timings = this.editorStore.applicationStore.timeService.finalizeTimingsRecord( @@ -695,14 +701,6 @@ export abstract class ServicePureExecutionState extends ServiceExecutionState { } } - getExecutionQuery(): RawLambda { - return getExecutionQueryFromRawLambda( - this.queryState.query, - this.parameterState.parameterStates, - this.editorStore.graphManagerState, - ); - } - get serviceExecutionParameters(): | { query: RawLambda; mapping: Mapping; runtime: Runtime } | undefined { @@ -832,7 +830,6 @@ export class InlineServicePureExecutionState extends ServicePureExecutionState { executionResultText: observable, executionPlanState: observable, showChangeExecModal: observable, - parameterState: observable, setExecutionResultText: action, setQueryState: action, updateExecutionQuery: action, @@ -879,7 +876,6 @@ export class SingleServicePureExecutionState extends ServicePureExecutionState { executionResultText: observable, executionPlanState: observable, showChangeExecModal: observable, - parameterState: observable, multiExecutionKey: observable, setExecutionResultText: action, closeRuntimeEditor: action, diff --git a/packages/legend-application-studio/src/stores/editor/editor-state/element-editor-state/service/testable/ServiceTestDataState.ts b/packages/legend-application-studio/src/stores/editor/editor-state/element-editor-state/service/testable/ServiceTestDataState.ts index 306f159ab5..3505b25753 100644 --- a/packages/legend-application-studio/src/stores/editor/editor-state/element-editor-state/service/testable/ServiceTestDataState.ts +++ b/packages/legend-application-studio/src/stores/editor/editor-state/element-editor-state/service/testable/ServiceTestDataState.ts @@ -74,7 +74,7 @@ import { getExecutionQueryFromRawLambda, } from '@finos/legend-query-builder'; -export class ServiceTestDataParameterState extends LambdaParametersState { +export class ServiceTestDataParametersState extends LambdaParametersState { connectionTestDataState: ConnectionTestDataState; constructor(connectionTestDataState: ConnectionTestDataState) { @@ -137,10 +137,11 @@ export class ServiceTestDataParameterState extends LambdaParametersState { export class ConnectionTestDataState { readonly editorStore: EditorStore; readonly testDataState: ServiceTestDataState; - connectionData: ConnectionTestData; - parameterState: ServiceTestDataParameterState; + readonly connectionData: ConnectionTestData; + readonly parametersState: ServiceTestDataParametersState; + readonly generatingTestDataState = ActionState.create(); + embeddedEditorState: EmbeddedDataEditorState; - generatingTestDataState = ActionState.create(); anonymizeGeneratedData = true; constructor( @@ -149,7 +150,6 @@ export class ConnectionTestDataState { ) { makeObservable(this, { generatingTestDataState: observable, - parameterState: observable, embeddedEditorState: observable, anonymizeGeneratedData: observable, setAnonymizeGeneratedData: action, @@ -163,7 +163,7 @@ export class ConnectionTestDataState { this.testDataState.editorStore, connectionData.testData, ); - this.parameterState = new ServiceTestDataParameterState(this); + this.parametersState = new ServiceTestDataParametersState(this); } get identifiedConnection(): IdentifiedConnection | undefined { return this.getAllIdentifiedConnections().find( @@ -195,7 +195,7 @@ export class ConnectionTestDataState { (yield this.editorStore.graphManagerState.graphManager.generateExecuteTestData( getExecutionQueryFromRawLambda( serviceExecutionParameters.query, - this.parameterState.parameterStates, + this.parametersState.parameterStates, this.editorStore.graphManagerState, ), [], @@ -205,7 +205,7 @@ export class ConnectionTestDataState { { anonymizeGeneratedData: this.anonymizeGeneratedData, parameterValues: buildExecutionParameterValues( - this.parameterState.parameterStates, + this.parametersState.parameterStates, this.editorStore.graphManagerState, ), }, @@ -255,7 +255,7 @@ export class ConnectionTestDataState { const parameters = (serviceExecutionParameters.query.parameters ?? []) as object[]; if (parameters.length > 0) { - this.parameterState.openModal(serviceExecutionParameters); + this.parametersState.openModal(serviceExecutionParameters); return; } else { yield flowResult( diff --git a/packages/legend-application-studio/src/stores/editor/panel-group/SQLPlaygroundPanelState.ts b/packages/legend-application-studio/src/stores/editor/panel-group/SQLPlaygroundPanelState.ts new file mode 100644 index 0000000000..c3d4cb3f0a --- /dev/null +++ b/packages/legend-application-studio/src/stores/editor/panel-group/SQLPlaygroundPanelState.ts @@ -0,0 +1,485 @@ +/** + * 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 type { TreeData, TreeNodeData } from '@finos/legend-art'; +import { + type GeneratorFn, + assertErrorThrown, + LogEvent, + addUniqueEntry, + isNonNullable, + filterByType, + ActionState, + getNonNullableEntry, + getNullableLastEntry, +} from '@finos/legend-shared'; +import { observable, makeObservable, flow, flowResult, action } from 'mobx'; +import { editor as monacoEditorAPI } from 'monaco-editor'; +import { + type Schema, + type Table, + type Database, + type PackageableConnection, + DatabaseBuilderInput, + DatabasePattern, + TargetDatabase, + Column, + getSchema, + guaranteeRelationalDatabaseConnection, + GRAPH_MANAGER_EVENT, +} from '@finos/legend-graph'; +import type { EditorStore } from '../EditorStore.js'; +import { LEGEND_STUDIO_APP_EVENT } from '../../../__lib__/LegendStudioEvent.js'; +import { + CODE_EDITOR_LANGUAGE, + moveCursorToPosition, +} from '@finos/legend-lego/code-editor'; +import type { CommandRegistrar } from '@finos/legend-application'; +import { STO_RELATIONAL_LEGEND_STUDIO_COMMAND_KEY } from '../../../__lib__/STO_Relational_LegendStudioCommand.js'; +import { PANEL_MODE } from '../EditorConfig.js'; + +export abstract class DatabaseSchemaExplorerTreeNodeData + implements TreeNodeData +{ + isOpen?: boolean | undefined; + id: string; + label: string; + parentId?: string | undefined; + childrenIds?: string[] | undefined; + + constructor(id: string, label: string, parentId: string | undefined) { + this.id = id; + this.label = label; + this.parentId = parentId; + } +} + +export class DatabaseSchemaExplorerTreeSchemaNodeData extends DatabaseSchemaExplorerTreeNodeData { + schema: Schema; + + constructor(id: string, schema: Schema) { + super(id, schema.name, undefined); + this.schema = schema; + } +} + +export class DatabaseSchemaExplorerTreeTableNodeData extends DatabaseSchemaExplorerTreeNodeData { + override parentId: string; + owner: Schema; + table: Table; + + constructor(id: string, parentId: string, owner: Schema, table: Table) { + super(id, table.name, parentId); + this.parentId = parentId; + this.owner = owner; + this.table = table; + } +} + +export class DatabaseSchemaExplorerTreeColumnNodeData extends DatabaseSchemaExplorerTreeNodeData { + override parentId: string; + owner: Table; + column: Column; + + constructor(id: string, parentId: string, owner: Table, column: Column) { + super(id, column.name, parentId); + this.parentId = parentId; + this.owner = owner; + this.column = column; + } +} + +export interface DatabaseSchemaExplorerTreeData + extends TreeData { + database: Database; +} + +const DUMMY_DATABASE_PACKAGE = 'dummy'; +const DUMMY_DATABASE_NAME = 'DummyDB'; +const DEFAULT_SQL_TEXT = `--Start building your SQL. Note that you can also drag-and-drop nodes from schema explorer\n`; + +export class SQLPlaygroundPanelState implements CommandRegistrar { + readonly editorStore: EditorStore; + + isFetchingSchema = false; + isExecutingRawSQL = false; + + connection?: PackageableConnection | undefined; + treeData?: DatabaseSchemaExplorerTreeData | undefined; + readonly sqlEditorTextModel: monacoEditorAPI.ITextModel; + sqlEditor?: monacoEditorAPI.IStandaloneCodeEditor | undefined; + sqlEditorViewState?: monacoEditorAPI.ICodeEditorViewState | undefined; + sqlText = DEFAULT_SQL_TEXT; + sqlExecutionResult?: string | undefined; + + constructor(editorStore: EditorStore) { + makeObservable(this, { + isFetchingSchema: observable, + isExecutingRawSQL: observable, + connection: observable, + treeData: observable, + sqlText: observable, + resetSQL: action, + sqlExecutionResult: observable, + sqlEditor: observable.ref, + sqlEditorViewState: observable.ref, + setTreeData: action, + setConnection: action, + setSQLEditor: action, + setSQLEditorViewState: action, + setSQLText: action, + onNodeSelect: flow, + fetchDatabaseMetadata: flow, + fetchSchemaMetadata: flow, + fetchTableMetadata: flow, + executeRawSQL: flow, + }); + + this.editorStore = editorStore; + this.sqlEditorTextModel = monacoEditorAPI.createModel( + this.sqlText, + CODE_EDITOR_LANGUAGE.SQL, + ); + } + + setTreeData(val?: DatabaseSchemaExplorerTreeData): void { + this.treeData = val; + } + + setConnection(val: PackageableConnection | undefined): void { + this.connection = val; + this.sqlEditorTextModel.setValue(DEFAULT_SQL_TEXT); + } + + setSQLText(val: string): void { + this.sqlText = val; + } + + setSQLEditor(val: monacoEditorAPI.IStandaloneCodeEditor | undefined): void { + this.sqlEditor = val; + if (val) { + const lines = this.sqlText.split('\n'); + moveCursorToPosition(val, { + lineNumber: lines.length, + column: getNullableLastEntry(lines)?.length ?? 0, + }); + } + } + + resetSQL(): void { + this.setSQLText(DEFAULT_SQL_TEXT); + this.sqlEditorTextModel.setValue(DEFAULT_SQL_TEXT); + this.sqlExecutionResult = undefined; + } + + setSQLEditorViewState( + val: monacoEditorAPI.ICodeEditorViewState | undefined, + ): void { + this.sqlEditorViewState = val; + } + + registerCommands(): void { + this.editorStore.applicationStore.commandService.registerCommand({ + key: STO_RELATIONAL_LEGEND_STUDIO_COMMAND_KEY.SQL_PLAYGROUND_EXECUTE, + trigger: () => + this.editorStore.isInitialized && + this.editorStore.activePanelMode === PANEL_MODE.SQL_PLAYGROUND && + Boolean(this.connection) && + Boolean(this.sqlText.length), + action: () => { + flowResult(this.executeRawSQL()).catch( + this.editorStore.applicationStore.alertUnhandledError, + ); + }, + }); + } + + deregisterCommands(): void { + [STO_RELATIONAL_LEGEND_STUDIO_COMMAND_KEY.SQL_PLAYGROUND_EXECUTE].forEach( + (key) => + this.editorStore.applicationStore.commandService.deregisterCommand(key), + ); + } + + *onNodeSelect( + node: DatabaseSchemaExplorerTreeNodeData, + treeData: DatabaseSchemaExplorerTreeData, + ): GeneratorFn { + if ( + node instanceof DatabaseSchemaExplorerTreeSchemaNodeData && + !node.childrenIds + ) { + yield flowResult(this.fetchSchemaMetadata(node, treeData)); + } else if ( + node instanceof DatabaseSchemaExplorerTreeTableNodeData && + !node.childrenIds + ) { + yield flowResult(this.fetchTableMetadata(node, treeData)); + } + node.isOpen = !node.isOpen; + this.setTreeData({ ...treeData }); + } + + getChildNodes( + node: DatabaseSchemaExplorerTreeNodeData, + treeData: DatabaseSchemaExplorerTreeData, + ): DatabaseSchemaExplorerTreeNodeData[] | undefined { + return node.childrenIds + ?.map((n) => treeData.nodes.get(n)) + .filter(isNonNullable); + } + + *fetchDatabaseMetadata(): GeneratorFn { + if (!this.connection) { + return; + } + + try { + this.isFetchingSchema = true; + + const databaseBuilderInput = new DatabaseBuilderInput( + guaranteeRelationalDatabaseConnection(this.connection), + ); + databaseBuilderInput.targetDatabase = new TargetDatabase( + DUMMY_DATABASE_PACKAGE, + DUMMY_DATABASE_NAME, + ); + databaseBuilderInput.config.maxTables = undefined; + databaseBuilderInput.config.enrichTables = false; + databaseBuilderInput.config.patterns = [ + new DatabasePattern(undefined, undefined), + ]; + + const database = (yield this.buildIntermediateDatabase( + databaseBuilderInput, + )) as Database; + const rootIds: string[] = []; + const nodes = new Map(); + database.schemas + .slice() + .sort((schemaA, schemaB) => schemaA.name.localeCompare(schemaB.name)) + .forEach((dbSchema) => { + const schemaId = dbSchema.name; + rootIds.push(schemaId); + const schemaNode = new DatabaseSchemaExplorerTreeSchemaNodeData( + schemaId, + dbSchema, + ); + nodes.set(schemaId, schemaNode); + }); + const treeData = { rootIds, nodes, database }; + this.setTreeData(treeData); + } catch (error) { + assertErrorThrown(error); + this.editorStore.applicationStore.logService.error( + LogEvent.create(LEGEND_STUDIO_APP_EVENT.DATABASE_BUILDER_FAILURE), + error, + ); + this.editorStore.applicationStore.notificationService.notifyError(error); + } finally { + this.isFetchingSchema = false; + } + } + + *fetchSchemaMetadata( + schemaNode: DatabaseSchemaExplorerTreeSchemaNodeData, + treeData: DatabaseSchemaExplorerTreeData, + ): GeneratorFn { + if (!this.connection) { + return; + } + + try { + this.isFetchingSchema = true; + + const schema = schemaNode.schema; + const databaseBuilderInput = new DatabaseBuilderInput( + guaranteeRelationalDatabaseConnection(this.connection), + ); + databaseBuilderInput.targetDatabase = new TargetDatabase( + DUMMY_DATABASE_PACKAGE, + DUMMY_DATABASE_NAME, + ); + databaseBuilderInput.config.maxTables = undefined; + databaseBuilderInput.config.enrichTables = true; + databaseBuilderInput.config.patterns = [ + new DatabasePattern(schema.name, undefined), + ]; + + const database = (yield this.buildIntermediateDatabase( + databaseBuilderInput, + )) as Database; + const tables = getSchema(database, schema.name).tables; + const childrenIds = schemaNode.childrenIds ?? []; + schema.tables = tables; + tables + .slice() + .sort((tableA, tableB) => tableA.name.localeCompare(tableB.name)) + .forEach((table) => { + table.schema = schema; + const tableId = `${schema.name}.${table.name}`; + const tableNode = new DatabaseSchemaExplorerTreeTableNodeData( + tableId, + schemaNode.id, + schema, + table, + ); + treeData.nodes.set(tableId, tableNode); + addUniqueEntry(childrenIds, tableId); + }); + schemaNode.childrenIds = childrenIds; + this.setTreeData({ ...treeData }); + } catch (error) { + assertErrorThrown(error); + this.editorStore.applicationStore.logService.error( + LogEvent.create(LEGEND_STUDIO_APP_EVENT.DATABASE_BUILDER_FAILURE), + error, + ); + this.editorStore.applicationStore.notificationService.notifyError(error); + } finally { + this.isFetchingSchema = false; + } + } + + *fetchTableMetadata( + tableNode: DatabaseSchemaExplorerTreeTableNodeData, + treeData: DatabaseSchemaExplorerTreeData, + ): GeneratorFn { + if (!this.connection) { + return; + } + + try { + this.isFetchingSchema = true; + + const table = tableNode.table; + const databaseBuilderInput = new DatabaseBuilderInput( + guaranteeRelationalDatabaseConnection(this.connection), + ); + databaseBuilderInput.targetDatabase = new TargetDatabase( + DUMMY_DATABASE_PACKAGE, + DUMMY_DATABASE_NAME, + ); + const config = databaseBuilderInput.config; + config.maxTables = undefined; + config.enrichTables = true; + config.enrichColumns = true; + config.enrichPrimaryKeys = true; + config.patterns = [new DatabasePattern(table.schema.name, table.name)]; + const database = (yield this.buildIntermediateDatabase( + databaseBuilderInput, + )) as Database; + + const enrichedTable = database.schemas + .find((schema) => table.schema.name === schema.name) + ?.tables.find((t) => t.name === table.name); + if (enrichedTable) { + table.primaryKey = enrichedTable.primaryKey; + const columns = enrichedTable.columns.filter(filterByType(Column)); + tableNode.table.columns = columns; + tableNode.childrenIds?.forEach((c) => treeData.nodes.delete(c)); + tableNode.childrenIds = undefined; + const childrenIds: string[] = []; + const tableId = tableNode.id; + columns + .slice() + .sort((colA, colB) => colA.name.localeCompare(colB.name)) + .forEach((col) => { + const columnId = `${tableId}.${col.name}`; + const columnNode = new DatabaseSchemaExplorerTreeColumnNodeData( + columnId, + tableId, + table, + col, + ); + col.owner = tableNode.table; + treeData.nodes.set(columnId, columnNode); + addUniqueEntry(childrenIds, columnId); + }); + tableNode.childrenIds = childrenIds; + } + } catch (error) { + assertErrorThrown(error); + this.editorStore.applicationStore.logService.error( + LogEvent.create(LEGEND_STUDIO_APP_EVENT.DATABASE_BUILDER_FAILURE), + error, + ); + this.editorStore.applicationStore.notificationService.notifyError(error); + } finally { + this.isFetchingSchema = false; + } + } + + /** + * This will build the intermediate database from the specified + * schema exploration input; this information can be further used + * to enrich the explorer tree + */ + private async buildIntermediateDatabase( + input: DatabaseBuilderInput, + ): Promise { + const entities = + await this.editorStore.graphManagerState.graphManager.buildDatabase( + input, + ); + const graph = this.editorStore.graphManagerState.createNewGraph(); + await this.editorStore.graphManagerState.graphManager.buildGraph( + graph, + entities, + ActionState.create(), + ); + return getNonNullableEntry( + graph.ownDatabases, + 0, + 'Expected one database to be generated from input', + ); + } + + *executeRawSQL(): GeneratorFn { + if (!this.connection || this.isExecutingRawSQL) { + return; + } + + try { + this.isExecutingRawSQL = true; + + let sql = this.sqlText; + const currentSelection = this.sqlEditor?.getSelection(); + if (currentSelection) { + const selectionValue = + this.sqlEditorTextModel.getValueInRange(currentSelection); + if (selectionValue.trim() !== '') { + sql = selectionValue; + } + } + + this.sqlExecutionResult = + (yield this.editorStore.graphManagerState.graphManager.executeRawSQL( + guaranteeRelationalDatabaseConnection(this.connection), + sql, + )) as string; + } catch (error) { + assertErrorThrown(error); + this.editorStore.applicationStore.logService.error( + LogEvent.create(GRAPH_MANAGER_EVENT.EXECUTION_FAILURE), + error, + ); + this.editorStore.applicationStore.notificationService.notifyError(error); + } finally { + this.isExecutingRawSQL = false; + } + } +} diff --git a/packages/legend-application-studio/style/components/editor/_database-builder.scss b/packages/legend-application-studio/style/components/editor/_database-builder.scss index 2aa10b7e78..4e4f59a6fe 100644 --- a/packages/legend-application-studio/style/components/editor/_database-builder.scss +++ b/packages/legend-application-studio/style/components/editor/_database-builder.scss @@ -17,11 +17,20 @@ @use 'mixins' as *; .database-builder { - width: 100rem; - border: 0.1rem solid var(--color-blue-200); - padding: 2rem; - height: 80rem; - overflow: auto; + height: 100%; + width: 100%; + + &__container { + height: 80vh; + width: 80vw; + } + + &__content { + height: calc(100% - 8.6rem); + width: 100%; + position: relative; + padding: 0; + } .panel { height: 100%; @@ -65,46 +74,7 @@ } &__action--btn { - @include flexCenter; - - border-radius: 0.1rem; - padding: 0.5rem; - background: var(--color-blue-200); - color: var(--color-light-grey-50); - - &:hover { - background: var(--color-blue-180); - } - - &[disabled] { - background: var(--color-dark-grey-200); - color: var(--color-dark-grey-500); - } - - &:focus { - outline: 0.1rem solid var(--color-blue-200); - outline-offset: 0.1rem; - } - } - - &__generate--btn { - margin-right: 0.3rem; - } - - &__heading { - display: flex; - margin-bottom: 1rem; - - &__label { - font-size: 2rem; - font-weight: bold; - } - } - - &__content { - position: relative; - height: 100%; - width: 100%; + width: 15rem; } &__node--selected { @@ -112,20 +82,35 @@ } &__config { + height: 100%; + border-right: 0.1rem solid var(--color-dark-grey-100); + &__content { + height: 100%; + width: 100%; padding: 1rem; + overflow: overlay; } + } + &__modeller { height: 100%; width: 100%; - border-right: 0.1rem solid var(--color-dark-grey-100); - &__properties { - padding: 0 0 0 1rem; + &__path { + height: 8rem; + padding: 1rem; + } + + &__preview { + border-top: 0.1rem solid var(--color-dark-grey-100); + height: calc(100% - 8rem); + width: 100%; + position: relative; } } - &__generated { + &__model { .panel { &__header__actions { @include flexVCenter; @@ -170,52 +155,13 @@ &__type-icon { @include flexHCenter; - width: 1.5rem; - min-width: 1.5rem; + width: 1.8rem; + min-width: 1.8rem; } - &__node__content { - @include flexVCenter; - - height: 100%; - width: calc(100% - 3.3rem); - } - - &__node__actions { - @include flexVCenter; - - height: 100%; - padding-right: 0.5rem; - } - - &__node__action { - @include flexCenter; - - width: 2.8rem; - height: 2.8rem; - - svg { - color: var(--color-light-grey-400); - } - - &:hover { - svg { - color: var(--color-light-grey-200); - } - } - } - - &__node__icon { - width: 4.5rem; - min-width: 4.5rem; - } - - &__expand-icon, - &__type-icon { - @include flexHCenter; - - width: 1.5rem; - min-width: 1.5rem; + &__node__icon__group { + width: 5.4rem; + min-width: 5.4rem; } &__expand-icon svg { @@ -224,14 +170,26 @@ &__node__label { display: flex; + user-select: none; + color: var(--color-light-grey-200); + font-size: 1.3rem; } - &__node__sub-type, &__node__type { @include flexVCenter; } - &__node__sub-type__label, + &__node__pk { + @include flexVCenter; + + margin-left: 0.5rem; + + svg { + font-size: 1.2rem; + color: var(--color-light-grey-200); + } + } + &__node__type__label { @include flexVCenter; @@ -241,17 +199,19 @@ padding: 0 0.5rem; height: 1.6rem; font-weight: 500; - } - - &__node__type__label { background: var(--color-dark-grey-250); color: var(--color-light-grey-200); + user-select: none; } - &__node__sub-type__label { - background: var(--color-light-grey-400); - color: var(--color-dark-grey-250); - border-radius: 0.2rem 1.4rem 1.4rem 0.2rem; - padding-right: 0.7rem; + &__icon { + &--schema svg { + color: var(--color-lime-75); + } + + &--table svg { + font-size: 1.6rem; + color: var(--color-magenta-100); + } } } diff --git a/packages/legend-application-studio/style/components/editor/_editor-group.scss b/packages/legend-application-studio/style/components/editor/_editor-group.scss index e8a1623b0e..c4abbf62f6 100644 --- a/packages/legend-application-studio/style/components/editor/_editor-group.scss +++ b/packages/legend-application-studio/style/components/editor/_editor-group.scss @@ -40,6 +40,39 @@ overflow: hidden; } + &__header__tab { + @include flexVCenter; + + &__icon { + &--file { + color: var(--color-file); + } + + &--readonly { + margin-left: 0.5rem; + font-size: 1rem; + color: var(--color-dark-grey-350); + } + } + + &__label { + margin-left: 0.5rem; + } + + &__path { + @include flexVCenter; + + color: var(--color-dark-grey-350); + margin-left: 0.5rem; + border-radius: 0.2rem; + font-size: 1rem; + padding: 0 0.5rem; + height: 1.6rem; + font-weight: 500; + font-family: 'Roboto Mono', monospace; + } + } + &__text-mode__tab { @include flexVCenter; @@ -227,7 +260,7 @@ @include flexVCenter; &__element-name { - margin-right: 0.5rem; + margin: 0 0.5rem; } &__text { diff --git a/packages/legend-application-studio/style/components/editor/_function-activator-editor.scss b/packages/legend-application-studio/style/components/editor/_function-activator-editor.scss index 526259378c..f1954d0272 100644 --- a/packages/legend-application-studio/style/components/editor/_function-activator-editor.scss +++ b/packages/legend-application-studio/style/components/editor/_function-activator-editor.scss @@ -66,4 +66,14 @@ height: calc(100% - 5rem); overflow: auto; } + + &__function-pointer { + @include flexVCenter; + + &__visit-btn { + height: 2.8rem; + width: 2.8rem; + margin-left: 0.5rem; + } + } } diff --git a/packages/legend-application-studio/style/components/editor/_function-editor.scss b/packages/legend-application-studio/style/components/editor/_function-editor.scss index 367867eca0..cd73943dfc 100644 --- a/packages/legend-application-studio/style/components/editor/_function-editor.scss +++ b/packages/legend-application-studio/style/components/editor/_function-editor.scss @@ -265,4 +265,105 @@ height: 100%; width: 100%; } + + &__execution { + &__stop-btn { + @include flexVCenter; + + height: 100%; + width: 12rem; + margin: 0 0.3rem; + + &__label { + @include flexVCenter; + + height: 2.2rem; + width: 12rem; + padding: 1rem; + border-radius: 0.2rem 0 0 0.2rem; + justify-content: left; + } + + &__label__icon { + font-size: 1.2rem; + color: var(--color-light-grey-180); + } + + &__label__title { + margin-left: 0.7rem; + color: var(--color-light-grey-180); + font-size: 1.2rem; + font-weight: 500; + } + + &__label:hover &__label__icon, + &__label:hover &__label__title { + color: var(--color-light-grey-50); + } + } + + &__action-btn { + @include flexVCenter; + + height: 100%; + margin: 0 0.3rem; + + &__label { + @include flexVCenter; + + height: 2.2rem; + background: var(--color-blue-200); + padding: 1rem; + border-radius: 0.2rem 0 0 0.2rem; + } + + &__label__icon { + font-size: 1.2rem; + color: var(--color-light-grey-180); + } + + &__label__title { + margin-left: 0.7rem; + color: var(--color-light-grey-180); + font-size: 1.2rem; + font-weight: 500; + } + + &__dropdown-btn { + @include flexCenter; + + height: 2.2rem; + width: 2rem; + background: var(--color-blue-200); + border-radius: 0 0.2rem 0.2rem 0; + border-left: 0.1rem solid var(--color-dark-shade-280); + + svg { + color: var(--color-light-grey-180); + } + } + + &__label:hover &__label__icon, + &__label:hover &__label__title, + &__dropdown-btn:hover svg { + color: var(--color-light-grey-50); + } + + &__option { + text-align: left; + width: 12rem; + } + + &__label[disabled], + &__dropdown-btn[disabled] { + background: var(--color-dark-grey-250); + } + + &__label[disabled] &__label__icon, + &__label[disabled] &__label__title, + &__dropdown-btn[disabled] svg { + color: var(--color-dark-grey-500); + } + } + } } diff --git a/packages/legend-application-studio/style/components/editor/_panel-group.scss b/packages/legend-application-studio/style/components/editor/_panel-group.scss index 6c9932023e..c753fa807e 100644 --- a/packages/legend-application-studio/style/components/editor/_panel-group.scss +++ b/packages/legend-application-studio/style/components/editor/_panel-group.scss @@ -16,8 +16,8 @@ @use 'mixins' as *; -@forward 'panel-group/console-panel'; -@forward 'panel-group/dev-tool'; +@forward 'panel-group/console'; +@forward 'panel-group/sql-playground'; .panel-group { width: 100%; @@ -25,6 +25,7 @@ top: 0; left: 0; z-index: 1; + border-top: 0.1rem solid var(--color-dark-grey-250); .panel { &__header { @@ -52,14 +53,15 @@ height: 3.4rem; font-size: 1.2rem; margin: 0 1rem; + padding: 0 0.5rem; font-weight: 500; - border-bottom: 0.3rem solid var(--color-dark-grey-50); + border-bottom: 0.2rem solid var(--color-dark-grey-50); color: var(--color-dark-grey-400); } &__header__tab--active { color: var(--color-light-grey-200); - border-bottom: 0.3rem solid var(--color-yellow-300); + border-bottom: 0.2rem solid var(--color-yellow-300); } &__header__tab__icon svg { @@ -82,6 +84,21 @@ margin-left: 0.5rem; } + &__header__tab__experimental-badge { + @include flexCenter; + + height: 1.2rem; + width: 1.2rem; + border-radius: 50%; + background: var(--color-mauve-50); + margin-left: 0.5rem; + + svg { + font-size: 1rem; + color: var(--color-dark-grey-50); + } + } + &__problems__stale-warning { @include flexVCenter; diff --git a/packages/legend-application-studio/style/components/editor/panel-group/_console-panel.scss b/packages/legend-application-studio/style/components/editor/panel-group/_console.scss similarity index 100% rename from packages/legend-application-studio/style/components/editor/panel-group/_console-panel.scss rename to packages/legend-application-studio/style/components/editor/panel-group/_console.scss diff --git a/packages/legend-application-studio/style/components/editor/panel-group/_sql-playground.scss b/packages/legend-application-studio/style/components/editor/panel-group/_sql-playground.scss new file mode 100644 index 0000000000..313fafa284 --- /dev/null +++ b/packages/legend-application-studio/style/components/editor/panel-group/_sql-playground.scss @@ -0,0 +1,261 @@ +/** + * 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. + */ + +@use 'mixins' as *; + +.sql-playground { + height: 100%; + width: 100%; + + &__config { + height: 100%; + border-right: 0.1rem solid var(--color-dark-grey-100); + } + + &__config__connection-selector { + display: flex; + height: 5rem; + padding: 1rem; + border-bottom: 0.1rem solid var(--color-dark-grey-100); + + &__icon { + @include flexCenter; + @include flexConstantDimension; + + height: 2.8rem; + width: 2.8rem; + margin-right: 0.5rem; + background: var(--color-dark-grey-200); + border-radius: 0.2rem; + } + + &__input { + width: 100%; + } + + &__option { + display: flex; + + &__label { + @include flexVCenter; + + height: 1.8rem; + } + + &__type { + @include flexVCenter; + + color: var(--color-dark-grey-250); + background: var(--color-dark-grey-400); + margin-left: 0.5rem; + border-radius: 0.2rem; + font-size: 1rem; + padding: 0 0.5rem; + height: 1.6rem; + font-weight: 500; + } + } + } + + &__config__schema-explorer { + height: calc(100% - 5rem); + padding: 1rem 0; + overflow: overlay; + } + + &__code-editor { + display: flex; + flex-direction: column; + height: 100%; + width: 100%; + + &__header { + @include flexVCenter; + + height: 2.8rem; + border-bottom: 0.1rem solid var(--color-dark-grey-100); + justify-content: flex-end; + + &__actions { + display: flex; + } + + &__action { + @include flexCenter; + + height: 2.8rem; + width: 2.8rem; + + svg { + color: var(--color-dark-grey-400); + } + + &:hover svg { + color: var(--color-light-grey-400); + } + } + } + + &__content { + height: calc(100% - 2.8rem); + } + } +} + +.sql-playground__database-schema-explorer-tree { + height: 100%; + width: 100%; + display: flex; + flex-direction: column; + + &__container { + height: calc(100% - 3.4rem); + width: 100%; + padding: 0.5rem 0; + } + + &__node__container { + display: flex; + width: 100%; + height: 2.8rem; + + &:hover { + background: var(--color-dark-blue-shade-100); + } + } + + &__expand-icon, + &__type-icon { + @include flexHCenter; + + width: 1.8rem; + min-width: 1.8rem; + } + + &__node__icon__group { + width: 3.6rem; + min-width: 3.6rem; + } + + &__expand-icon svg { + font-size: 1.2rem; + } + + &__node__label { + display: flex; + user-select: none; + color: var(--color-light-grey-200); + font-size: 1.3rem; + } + + &__node__type { + @include flexVCenter; + } + + &__node__pk { + @include flexVCenter; + + margin-left: 0.5rem; + + svg { + font-size: 1.2rem; + color: var(--color-light-grey-200); + } + } + + &__node__type__label { + @include flexVCenter; + + margin-left: 0.5rem; + border-radius: 0.2rem; + font-size: 1rem; + padding: 0 0.5rem; + height: 1.6rem; + font-weight: 500; + background: var(--color-dark-grey-250); + color: var(--color-light-grey-200); + user-select: none; + } + + &__icon { + &--schema svg { + color: var(--color-lime-75); + } + + &--table svg { + font-size: 1.6rem; + color: var(--color-magenta-100); + } + } +} + +.sql-playground__result__grid { + height: 100%; + width: 100%; + + &--empty { + @include flexCenter; + + padding: 1rem 1.5rem; + font-weight: 500; + border-radius: 0.5rem; + background: var(--color-dark-grey-50); + color: var(--color-dark-grey-300); + } + + // NOTE: we need to ensure the specificity here in case a later imported ag-theme-balham-dark + // might override our theme customization here + &.ag-theme-balham-dark { + --ag-font-family: 'Roboto'; + + // Customize ag-grid theme + // See https://www.ag-grid.com/javascript-grid-themes-customising/#customising-themes + --ag-border-color: var(--color-dark-grey-200); + --ag-background-color: var(--color-dark-grey-50); + --ag-foreground-color: var(--color-light-grey-200); + --ag-header-background-color: var(--color-dark-grey-100); + --ag-header-foreground-color: var(--color-light-grey-50); + --ag-balham-active-color: var(--color-blue-200); + --ag-odd-row-background-color: var(--color-dark-grey-50); + --ag-even-row-background-color: var(--color-dark-grey-50); + --ag-row-hover-color: var(--color-dark-blue-shade-100); + --ag-row-border-color: var(--color-dark-grey-200); + } + + .ag-header-cell-text { + font-weight: 500; + } + + .ag-cell-value { + word-break: break-word; + } + + .ag-center-cols-viewport { + // stripped background for remaining height of the grid when there are not enough rows + // See https://css-tricks.com/stripes-css/ + background: repeating-linear-gradient( + 135deg, + var(--color-dark-grey-50), + var(--color-dark-grey-50) 0.5rem, + var(--color-dark-grey-80) 0.5rem, + var(--color-dark-grey-80) 1rem + ); + } + + ::-webkit-scrollbar-track-piece { + background: transparent; + } +} diff --git a/packages/legend-application-taxonomy-deployment/package.json b/packages/legend-application-taxonomy-deployment/package.json index 6073cbeda9..c701861fc7 100644 --- a/packages/legend-application-taxonomy-deployment/package.json +++ b/packages/legend-application-taxonomy-deployment/package.json @@ -44,7 +44,7 @@ "npm-run-all": "4.1.5", "rimraf": "5.0.1", "typescript": "5.0.4", - "webpack": "5.84.0", + "webpack": "5.84.1", "webpack-bundle-analyzer": "4.8.0", "webpack-cli": "5.1.1", "webpack-dev-server": "4.15.0" diff --git a/packages/legend-art/src/icon/Icon.ts b/packages/legend-art/src/icon/Icon.ts index 39733df2df..13bf63ea18 100644 --- a/packages/legend-art/src/icon/Icon.ts +++ b/packages/legend-art/src/icon/Icon.ts @@ -151,7 +151,6 @@ export const FaceSadTearIcon = FA.FaRegSadTear; export const BusinessTimeIcon = FA.FaBusinessTime; // to be reviewed/combined export const DatabaseIcon = FA.FaDatabase; export const ServerIcon = FA.FaServer; -export const TableIcon = FA.FaTable; export const ArchiveIcon = FA.FaArchive; export const BrainIcon = FA.FaBrain; export const DocumentationIcon = FA.FaBookOpen; @@ -215,6 +214,7 @@ export const WandIcon = VSC.VscWand; export const CollapseTreeIcon = VSC.VscCollapseAll; export const ExpandTreeIcon = VSC.VscExpandAll; export const SerializeIcon = VSC.VscJson; +export const TableIcon = VSC.VscTable; const GO = ReactIcons.GO; export const ChevronDownIcon = GO.GoChevronDown; @@ -265,6 +265,7 @@ export const ThinChevronDownIcon = BS.BsChevronDown; export const ThinChevronRightIcon = BS.BsChevronRight; export const ThinChevronLeftIcon = BS.BsChevronLeft; export const QuestionSquareIcon = BS.BsQuestionSquare; +export const GenericTextFileIcon = BS.BsTextLeft; const BI = ReactIcons.BI; export const ShapeTriangleIcon = BI.BiShapeTriangle; diff --git a/packages/legend-art/src/panel/PanelDropZone.tsx b/packages/legend-art/src/panel/PanelDropZone.tsx index 6fa7632a85..01a040259e 100644 --- a/packages/legend-art/src/panel/PanelDropZone.tsx +++ b/packages/legend-art/src/panel/PanelDropZone.tsx @@ -30,10 +30,11 @@ export const PanelDropZone: React.FC<{ children: React.ReactNode; isDragOver: boolean; dropTargetConnector: ConnectDropTarget; + className?: string; }> = (props) => { - const { children, isDragOver, dropTargetConnector } = props; + const { children, isDragOver, dropTargetConnector, className } = props; return ( -
+
{isDragOver &&
}
{children}
diff --git a/packages/legend-dev-utils/package.json b/packages/legend-dev-utils/package.json index 5f1d4317ee..0c1fa7f27f 100644 --- a/packages/legend-dev-utils/package.json +++ b/packages/legend-dev-utils/package.json @@ -49,7 +49,7 @@ "test:watch": "jest --watch" }, "dependencies": { - "@babel/core": "7.21.8", + "@babel/core": "7.22.1", "@changesets/assemble-release-plan": "5.2.3", "@changesets/changelog-github": "0.4.8", "@changesets/config": "2.3.0", @@ -83,13 +83,13 @@ "monaco-editor": "0.38.0", "monaco-editor-webpack-plugin": "7.0.1", "postcss": "8.4.23", - "postcss-loader": "7.3.0", + "postcss-loader": "7.3.1", "react-refresh": "0.14.0", "resolve": "1.22.2", "sass": "1.62.1", "sass-loader": "13.3.0", "typescript": "5.0.4", - "webpack": "5.84.0" + "webpack": "5.84.1" }, "devDependencies": { "cross-env": "7.0.3", diff --git a/packages/legend-extension-dsl-data-space/src/graph-manager/protocol/pure/DSL_DataSpace_PureProtocolProcessorPlugin.ts b/packages/legend-extension-dsl-data-space/src/graph-manager/protocol/pure/DSL_DataSpace_PureProtocolProcessorPlugin.ts index d61e68333a..237e13732e 100644 --- a/packages/legend-extension-dsl-data-space/src/graph-manager/protocol/pure/DSL_DataSpace_PureProtocolProcessorPlugin.ts +++ b/packages/legend-extension-dsl-data-space/src/graph-manager/protocol/pure/DSL_DataSpace_PureProtocolProcessorPlugin.ts @@ -55,7 +55,6 @@ import { DataSpaceElementPointer, } from '../../../graph/metamodel/pure/model/packageableElements/dataSpace/DSL_DataSpace_DataSpace.js'; import { - type PureModel, type PackageableElement, type V1_ElementProtocolClassifierPathGetter, type V1_ElementProtocolDeserializer, @@ -90,7 +89,6 @@ import { type V1_MappingIncludeTransformer, type V1_MappingIncludeProtocolSerializer, type V1_MappingIncludeProtocolDeserializer, - type V1_ExecutionInputCollector, type V1_MappingIncludeIdentifierBuilder, } from '@finos/legend-graph'; import { V1_resolveDiagram } from '@finos/legend-extension-dsl-diagram/graph'; @@ -481,20 +479,6 @@ export class DSL_DataSpace_PureProtocolProcessorPlugin }, ]; } - - override V1_getExtraExecutionInputCollectors(): V1_ExecutionInputCollector[] { - return [ - ( - graph: PureModel, - protocolGraph: V1_PureModelContextData, - ): V1_PackageableElement[] => - // TODO: bring back when issue with not including services as part of the execution collections is resolved - // protocolGraph.elements.filter( - // (element) => element instanceof V1_DataSpace, - // ), - [], - ]; - } } export const extractDataSpaceTaxonomyNodes = ( diff --git a/packages/legend-extension-dsl-service/src/components/query/ServiceRegisterModal.tsx b/packages/legend-extension-dsl-service/src/components/query/ServiceRegisterModal.tsx index 01171a0037..4bbf1bb3a0 100644 --- a/packages/legend-extension-dsl-service/src/components/query/ServiceRegisterModal.tsx +++ b/packages/legend-extension-dsl-service/src/components/query/ServiceRegisterModal.tsx @@ -253,7 +253,7 @@ const ServiceRegisterModal = observer(
; /** - * TODO: Move this to store relational extension + * TODO: Move these to store relational extension * * @modularize * See https://github.com/finos/legend-studio/issues/65 */ - abstract buildDatabase( - databaseBuilderInput: DatabaseBuilderInput, - ): Promise; + abstract buildDatabase(input: DatabaseBuilderInput): Promise; + abstract executeRawSQL( + connection: RelationalDatabaseConnection, + sql: string, + ): Promise; // ------------------------------------------- Function ------------------------------------------- diff --git a/packages/legend-graph/src/graph-manager/action/generation/DatabaseBuilderInput.ts b/packages/legend-graph/src/graph-manager/action/generation/DatabaseBuilderInput.ts index c9fb95f7e2..fa9a8ccf4d 100644 --- a/packages/legend-graph/src/graph-manager/action/generation/DatabaseBuilderInput.ts +++ b/packages/legend-graph/src/graph-manager/action/generation/DatabaseBuilderInput.ts @@ -16,15 +16,20 @@ import type { RelationalDatabaseConnection } from '../../../graph/metamodel/pure/packageableElements/store/relational/connection/RelationalDatabaseConnection.js'; +const DATABASE_BUILDER_WILDCARD_PATTERN = '%'; + export class DatabasePattern { schemaPattern = ''; tablePattern = ''; escapeSchemaPattern?: boolean | undefined; escapeTablePattern?: boolean | undefined; - constructor(schemaPattern: string, tablePattern: string) { - this.schemaPattern = schemaPattern; - this.tablePattern = tablePattern; + constructor( + schemaPattern: string | undefined, + tablePattern: string | undefined, + ) { + this.schemaPattern = schemaPattern ?? DATABASE_BUILDER_WILDCARD_PATTERN; + this.tablePattern = tablePattern ?? DATABASE_BUILDER_WILDCARD_PATTERN; } } diff --git a/packages/legend-graph/src/graph-manager/protocol/pure/PureProtocolProcessorPlugin.ts b/packages/legend-graph/src/graph-manager/protocol/pure/PureProtocolProcessorPlugin.ts index 6cbf24bcd7..a4b556072c 100644 --- a/packages/legend-graph/src/graph-manager/protocol/pure/PureProtocolProcessorPlugin.ts +++ b/packages/legend-graph/src/graph-manager/protocol/pure/PureProtocolProcessorPlugin.ts @@ -19,7 +19,6 @@ import type { PackageableElement } from '../../../graph/metamodel/pure/packageab import type { V1_PackageableElement } from './v1/model/packageableElements/V1_PackageableElement.js'; import type { V1_ElementBuilder } from './v1/transformation/pureGraph/to/V1_ElementBuilder.js'; import type { V1_PureModelContextData } from './v1/model/context/V1_PureModelContextData.js'; -import type { PureModel } from '../../../graph/PureModel.js'; import type { V1_GraphTransformerContext } from './v1/transformation/pureGraph/from/V1_GraphTransformerContext.js'; import type { V1_ValueSpecification } from './v1/model/valueSpecification/V1_ValueSpecification.js'; import type { V1_GraphBuilderContext } from './v1/transformation/pureGraph/to/V1_GraphBuilderContext.js'; @@ -64,21 +63,6 @@ export type V1_FunctionExpressionBuilder = ( processingContext: V1_ProcessingContext, ) => SimpleFunctionExpression | undefined; -export type V1_ExecutionInputCollector = ( - graph: PureModel, - protocolGraph: V1_PureModelContextData, -) => V1_PackageableElement[]; - -export type V1_MappingModelCoverageAnalysisInputCollector = ( - graph: PureModel, - protocolGraph: V1_PureModelContextData, -) => V1_PackageableElement[]; - -export type V1_MappingModelRuntimeCompatibilityAnalysisInputCollector = ( - graph: PureModel, - protocolGraph: V1_PureModelContextData, -) => V1_PackageableElement[]; - export type V1_PropertyExpressionTypeInferrer = ( variable: ValueSpecification | undefined, ) => Type | undefined; @@ -198,13 +182,6 @@ export abstract class PureProtocolProcessorPlugin extends AbstractPlugin { */ V1_getExtraFunctionExpressionBuilders?(): V1_FunctionExpressionBuilder[]; - /** - * Get the list of collectors of graph elements to build execution input. - * - * In particular, these collectors are used to produce the minimal graph that is needed for such execution. - */ - V1_getExtraExecutionInputCollectors?(): V1_ExecutionInputCollector[]; - /** * Get the list of type inferrers for property expression. */ diff --git a/packages/legend-graph/src/graph-manager/protocol/pure/extensions/DSL_ExternalFormat_PureProtocolProcessorPlugin.ts b/packages/legend-graph/src/graph-manager/protocol/pure/extensions/DSL_ExternalFormat_PureProtocolProcessorPlugin.ts index 0cfb041276..0a72c2b03f 100644 --- a/packages/legend-graph/src/graph-manager/protocol/pure/extensions/DSL_ExternalFormat_PureProtocolProcessorPlugin.ts +++ b/packages/legend-graph/src/graph-manager/protocol/pure/extensions/DSL_ExternalFormat_PureProtocolProcessorPlugin.ts @@ -23,7 +23,6 @@ import { guaranteeNonNullable, } from '@finos/legend-shared'; import { deserialize, serialize } from 'serializr'; -import type { PureModel } from '../../../../graph/PureModel.js'; import { getOwnBinding, getOwnSchemaSet, @@ -50,10 +49,8 @@ import { type V1_ElementProtocolDeserializer, type V1_ElementProtocolSerializer, type V1_ElementTransformer, - type V1_ExecutionInputCollector, PureProtocolProcessorPlugin, } from '../PureProtocolProcessorPlugin.js'; -import type { V1_PureModelContextData } from '../v1/model/context/V1_PureModelContextData.js'; import type { V1_Connection } from '../v1/model/packageableElements/connection/V1_Connection.js'; import { V1_ExternalFormatConnection } from '../v1/model/packageableElements/externalFormat/connection/V1_DSL_ExternalFormat_ExternalFormatConnection.js'; import { V1_UrlStream } from '../v1/model/packageableElements/externalFormat/connection/V1_DSL_ExternalFormat_UrlStream.js'; @@ -292,18 +289,6 @@ export class DSL_ExternalFormat_PureProtocolProcessorPlugin ]; } - override V1_getExtraExecutionInputCollectors(): V1_ExecutionInputCollector[] { - return [ - ( - graph: PureModel, - protocolGraph: V1_PureModelContextData, - ): V1_PackageableElement[] => - protocolGraph.elements.filter( - (element) => element instanceof V1_SchemaSet, - ), - ]; - } - V1_getExtraConnectionBuilders(): V1_ConnectionBuilder[] { return [ ( diff --git a/packages/legend-graph/src/graph-manager/protocol/pure/v1/V1_PureGraphManager.ts b/packages/legend-graph/src/graph-manager/protocol/pure/v1/V1_PureGraphManager.ts index f4466b76c1..2afdcc0fae 100644 --- a/packages/legend-graph/src/graph-manager/protocol/pure/v1/V1_PureGraphManager.ts +++ b/packages/legend-graph/src/graph-manager/protocol/pure/v1/V1_PureGraphManager.ts @@ -37,7 +37,6 @@ import { addUniqueEntry, uuid, deleteEntry, - uniq, IllegalStateError, filterByType, isString, @@ -158,7 +157,6 @@ import { V1_DatabaseBuilderConfig, V1_DatabaseBuilderInput, V1_DatabasePattern, - V1_setupDatabaseBuilderInputSerialization, V1_TargetDatabase, } from './engine/generation/V1_DatabaseBuilderInput.js'; import { V1_transformRelationalDatabaseConnection } from './transformation/pureGraph/from/V1_ConnectionTransformer.js'; @@ -301,7 +299,6 @@ import { } from '../../../GraphData.js'; import type { DEPRECATED__MappingTest } from '../../../../graph/metamodel/pure/packageableElements/mapping/DEPRECATED__MappingTest.js'; import { DEPRECATED__validate_MappingTest } from '../../../action/validation/DSL_Mapping_ValidationHelper.js'; -import { V1_SERVICE_ELEMENT_PROTOCOL_TYPE } from './transformation/pureProtocol/serializationHelpers/V1_ServiceSerializationHelper.js'; import { V1_INTERNAL__UnknownPackageableElement } from './model/packageableElements/V1_INTERNAL__UnknownPackageableElement.js'; import type { SourceInformation } from '../../../action/SourceInformation.js'; import type { V1_SourceInformation } from './model/V1_SourceInformation.js'; @@ -310,6 +307,8 @@ import { FunctionActivatorConfiguration } from '../../../action/functionActivato import { V1_FunctionActivatorInput } from './engine/functionActivator/V1_FunctionActivatorInput.js'; import { V1_FunctionActivator } from './model/packageableElements/function/V1_FunctionActivator.js'; import { V1_INTERNAL__UnknownFunctionActivator } from './model/packageableElements/function/V1_INTERNAL__UnknownFunctionActivator.js'; +import type { RelationalDatabaseConnection } from '../../../../STO_Relational_Exports.js'; +import { V1_RawSQLExecuteInput } from './engine/execution/V1_RawSQLExecuteInput.js'; class V1_PureModelContextDataIndex { elements: V1_PackageableElement[] = []; @@ -355,10 +354,12 @@ const mergePureModelContextData = ( const mergedData = new V1_PureModelContextData(); for (const _data of data) { mergedData.elements = mergedData.elements.concat(_data.elements); - mergedData.INTERNAL__rawDependencyEntities = - mergedData.INTERNAL__rawDependencyEntities.concat( - _data.INTERNAL__rawDependencyEntities, - ); + const rawDependencyEntities = ( + mergedData.INTERNAL__rawDependencyEntities ?? [] + ).concat(_data.INTERNAL__rawDependencyEntities ?? []); + mergedData.INTERNAL__rawDependencyEntities = rawDependencyEntities.length + ? rawDependencyEntities + : undefined; mergedData.serializer = _data.serializer ?? mergedData.serializer; mergedData.origin = _data.origin ?? mergedData.origin; } @@ -546,9 +547,6 @@ export class V1_PureGraphManager extends AbstractPureGraphManager { V1_setupLegacyRuntimeSerialization( this.pluginManager.getPureProtocolProcessorPlugins(), ); - V1_setupDatabaseBuilderInputSerialization( - this.pluginManager.getPureProtocolProcessorPlugins(), - ); } TEMPORARY__getEngineConfig(): TEMPORARY__AbstractEngineConfig { @@ -2336,7 +2334,7 @@ export class V1_PureGraphManager extends AbstractPureGraphManager { graphData: GraphData, ): V1_PureModelContext { if (graphData instanceof InMemoryGraphData) { - return this.buildExecutionInputGraphData(graphData.graph); + return this.getFullGraphModelData(graphData.graph); } else if (graphData instanceof GraphDataWithOrigin) { return this.buildPureModelSDLCPointer( graphData.origin, @@ -2360,7 +2358,7 @@ export class V1_PureGraphManager extends AbstractPureGraphManager { this.createExecutionInputWithPureModelContext( graph.origin ? this.buildPureModelSDLCPointer(graph.origin, undefined) - : this.buildExecutionInputGraphData(graph), + : this.getFullGraphModelData(graph), mapping, lambda, runtime, @@ -2406,52 +2404,6 @@ export class V1_PureGraphManager extends AbstractPureGraphManager { return executeInput; }; - private buildExecutionInputGraphData( - graph: PureModel, - ): V1_PureModelContextData { - /** - * NOTE: to lessen network load, we might need to think of a way to only include relevant part of the pure model context data here - * - * Graph data models can be classified based on dependency hieararchy: - * 1. Building blocks: models that all other models depend on: e.g. domain models, connections, etc. - * 2. Consumers: models that depends on other models: e.g. mapping, service, etc. - * 3. Unrelated: models that depends on nothing and vice versa: e.g. text - * - * It would be great if we can provide a way to walk the mapping to select only relevant part, but the problem is we cannot really walk the lambda - * object to identify relevant classes yet. so the more economical way to to base on the classification above and the knowledge about hierarchy between - * models (e.g. service can use mapping, runtime, connection, store, etc.) we can roughly prune the graph model data by group. Following is an example - * for mapping used for execution, but this can generalized if we introduce hierarchy/ranking for model type - */ - const graphData = this.getFullGraphModelData(graph); - const prunedGraphData = this.prunePureModelContextData( - graphData, - (element) => - element instanceof V1_Class || - element instanceof V1_Enumeration || - element instanceof V1_Profile || - element instanceof V1_Association || - element instanceof V1_ConcreteFunctionDefinition || - element instanceof V1_FunctionActivator || - element instanceof V1_Measure || - element instanceof V1_Store || - element instanceof V1_PackageableConnection || - element instanceof V1_PackageableRuntime || - element instanceof V1_Mapping, - undefined, - ); - const extraExecutionElements = this.pluginManager - .getPureProtocolProcessorPlugins() - .flatMap( - (element) => element.V1_getExtraExecutionInputCollectors?.() ?? [], - ) - .flatMap((getter) => getter(graph, graphData)); - prunedGraphData.elements = uniq([ - ...prunedGraphData.elements, - ...extraExecutionElements, - ]); - return prunedGraphData; - } - async runQuery( lambda: RawLambda, mapping: Mapping, @@ -2504,7 +2456,7 @@ export class V1_PureGraphManager extends AbstractPureGraphManager { const stopWatch = new StopWatch(); const pureModelContext = graph.origin ? this.buildPureModelSDLCPointer(graph.origin, undefined) - : this.buildExecutionInputGraphData(graph); + : this.getFullGraphModelData(graph); stopWatch.record(GRAPH_MANAGER_EVENT.V1_ENGINE_OPERATION_INPUT__SUCCESS); await Promise.all( tests.map((t) => @@ -2649,7 +2601,7 @@ export class V1_PureGraphManager extends AbstractPureGraphManager { this.createExecutionInputWithPureModelContext( graph.origin ? this.buildPureModelSDLCPointer(graph.origin, undefined) - : this.buildExecutionInputGraphData(graph), + : this.getFullGraphModelData(graph), mapping, lambda, runtime, @@ -2811,7 +2763,7 @@ export class V1_PureGraphManager extends AbstractPureGraphManager { input.mapping = mapping.path; input.model = graph.origin ? this.buildPureModelSDLCPointer(graph.origin, undefined) - : this.buildExecutionInputGraphData(graph); + : this.getFullGraphModelData(graph); return V1_buildModelCoverageAnalysisResult( await this.engine.analyzeMappingModelCoverage(input), mapping, @@ -2940,7 +2892,28 @@ export class V1_PureGraphManager extends AbstractPureGraphManager { ); dbBuilderInput.config = config; return this.pureModelContextDataToEntities( - await this.engine.buildDatabase(dbBuilderInput), + await this.engine.buildDatabase( + dbBuilderInput, + this.pluginManager.getPureProtocolProcessorPlugins(), + ), + ); + } + + override async executeRawSQL( + connection: RelationalDatabaseConnection, + sql: string, + ): Promise { + const input = new V1_RawSQLExecuteInput(); + input.connection = V1_transformRelationalDatabaseConnection( + connection, + new V1_GraphTransformerContextBuilder( + this.pluginManager.getPureProtocolProcessorPlugins(), + ).build(), + ); + input.sql = sql; + return this.engine.executeRawSQL( + input, + this.pluginManager.getPureProtocolProcessorPlugins(), ); } @@ -3052,8 +3025,10 @@ export class V1_PureGraphManager extends AbstractPureGraphManager { ); switch (executionMode) { case ServiceExecutionMode.FULL_INTERACTIVE: { - const data = this.createServiceRegistrationInputGraphData(graph); - data.elements.push(this.elementToProtocol(service)); + const data = this.TEMPORARY__prepareGraphDataForServiceRegistration( + this.getFullGraphModelData(graph), + this.elementToProtocol(service), + ); data.origin = new V1_PureModelContextPointer(protocol); input = data; break; @@ -3282,28 +3257,25 @@ export class V1_PureGraphManager extends AbstractPureGraphManager { ); } - // NOTE: We almost should never be poking into dependency entities. However for service registration the input - // expects only one service in the graph data. Perhaps, the service registration API should be modified to accept - // service as a parameter outside the model - private pruneServicesFromGraphForRegistration = ( + // NOTE: This is somewhat hacky: service registration the input expects only the first service in the graph data + // to be the service used for registration. + // TODO: the service registration API should be modified to accept service as a parameter outside the model + private TEMPORARY__prepareGraphDataForServiceRegistration = ( graphData: V1_PureModelContextData, - ): V1_PureModelContextData => - this.prunePureModelContextData( - graphData, - (element: V1_PackageableElement) => !(element instanceof V1_Service), - (entity: Entity) => { - const content = entity.content as { _type: string }; - return content._type !== V1_SERVICE_ELEMENT_PROTOCOL_TYPE; - }, - ); - - private createServiceRegistrationInputGraphData = ( - graph: PureModel, + service: V1_Service, ): V1_PureModelContextData => { - const graphData = this.getFullGraphModelData(graph); - const prunedGraphData = - this.pruneServicesFromGraphForRegistration(graphData); - return prunedGraphData; + graphData.elements = graphData.elements.filter( + (element) => element.path !== service.path, + ); + // insert the service as the first element so it gets indexed first + graphData.elements.unshift(service); + if (graphData.INTERNAL__rawDependencyEntities) { + graphData.INTERNAL__rawDependencyEntities = + graphData.INTERNAL__rawDependencyEntities.filter( + (entity) => entity.path !== service.path, + ); + } + return graphData; }; private createBulkServiceRegistrationInput = ( @@ -3313,12 +3285,13 @@ export class V1_PureGraphManager extends AbstractPureGraphManager { const graphData = this.getFullGraphModelData(graph); const results: ServiceRegistrationInput[] = []; services.forEach((service) => { - const prunedGraphData = - this.pruneServicesFromGraphForRegistration(graphData); - prunedGraphData.elements.push( - this.elementToProtocol(service), - ); - results.push({ service: service, context: prunedGraphData }); + results.push({ + service: service, + context: this.TEMPORARY__prepareGraphDataForServiceRegistration( + graphData, + this.elementToProtocol(service), + ), + }); }); return results; }; @@ -3388,22 +3361,6 @@ export class V1_PureGraphManager extends AbstractPureGraphManager { return entity; }; - private prunePureModelContextData = ( - data: V1_PureModelContextData, - elementFilter?: (val: V1_PackageableElement) => boolean, - entityFilter?: (entity: Entity) => boolean, - ): V1_PureModelContextData => { - const prunedGraphData = new V1_PureModelContextData(); - prunedGraphData.elements = data.elements.filter((element) => - elementFilter ? elementFilter(element) : true, - ); - prunedGraphData.INTERNAL__rawDependencyEntities = - data.INTERNAL__rawDependencyEntities.filter((entity) => - entityFilter ? entityFilter(entity) : true, - ); - return prunedGraphData; - }; - private buildPureModelSDLCPointer( origin: GraphDataOrigin, clientVersion: string | undefined, @@ -3547,10 +3504,13 @@ export class V1_PureGraphManager extends AbstractPureGraphManager { ...contextData1.elements, ...contextData2.elements, ]; - contextData1.INTERNAL__rawDependencyEntities = [ - ...contextData1.INTERNAL__rawDependencyEntities, - ...contextData2.INTERNAL__rawDependencyEntities, + const rawDependencyEntities = [ + ...(contextData1.INTERNAL__rawDependencyEntities ?? []), + ...(contextData2.INTERNAL__rawDependencyEntities ?? []), ]; + contextData1.INTERNAL__rawDependencyEntities = rawDependencyEntities.length + ? rawDependencyEntities + : undefined; return contextData1; } diff --git a/packages/legend-graph/src/graph-manager/protocol/pure/v1/engine/V1_Engine.ts b/packages/legend-graph/src/graph-manager/protocol/pure/v1/engine/V1_Engine.ts index 217ebcdc71..cb9fc8c0b1 100644 --- a/packages/legend-graph/src/graph-manager/protocol/pure/v1/engine/V1_Engine.ts +++ b/packages/legend-graph/src/graph-manager/protocol/pure/v1/engine/V1_Engine.ts @@ -65,7 +65,10 @@ import { V1_buildParserError, } from './V1_EngineHelper.js'; import { V1_LightQuery, V1_Query } from './query/V1_Query.js'; -import { V1_DatabaseBuilderInput } from './generation/V1_DatabaseBuilderInput.js'; +import { + type V1_DatabaseBuilderInput, + V1_serializeDatabaseBuilderInput, +} from './generation/V1_DatabaseBuilderInput.js'; import type { V1_ServiceConfigurationInfo } from './service/V1_ServiceConfiguration.js'; import { V1_ExecuteInput, @@ -117,6 +120,10 @@ import type { ClassifierPathMapping } from '../../../../action/protocol/Classifi import { V1_FunctionActivatorInfo } from './functionActivator/V1_FunctionActivatorInfo.js'; import { V1_FunctionActivatorError } from './functionActivator/V1_FunctionActivatorError.js'; import { V1_FunctionActivatorInput } from './functionActivator/V1_FunctionActivatorInput.js'; +import { + V1_serializeRawSQLExecuteInput, + type V1_RawSQLExecuteInput, +} from './execution/V1_RawSQLExecuteInput.js'; class V1_EngineConfig extends TEMPORARY__AbstractEngineConfig { private engine: V1_Engine; @@ -859,14 +866,24 @@ export class V1_Engine { async buildDatabase( input: V1_DatabaseBuilderInput, + plugins: PureProtocolProcessorPlugin[], ): Promise { return V1_deserializePureModelContextData( await this.engineServerClient.buildDatabase( - serialize(V1_DatabaseBuilderInput, input), + V1_serializeDatabaseBuilderInput(input, plugins), ), ); } + async executeRawSQL( + input: V1_RawSQLExecuteInput, + plugins: PureProtocolProcessorPlugin[], + ): Promise { + return this.engineServerClient.executeRawSQL( + V1_serializeRawSQLExecuteInput(input, plugins), + ); + } + // ------------------------------------------- Function ------------------------------------------- async getAvailableFunctionActivators(): Promise { diff --git a/packages/legend-graph/src/graph-manager/protocol/pure/v1/engine/V1_EngineServerClient.ts b/packages/legend-graph/src/graph-manager/protocol/pure/v1/engine/V1_EngineServerClient.ts index 649745ab44..fae294fbde 100644 --- a/packages/legend-graph/src/graph-manager/protocol/pure/v1/engine/V1_EngineServerClient.ts +++ b/packages/legend-graph/src/graph-manager/protocol/pure/v1/engine/V1_EngineServerClient.ts @@ -67,6 +67,8 @@ import type { ClassifierPathMapping } from '../../../../action/protocol/Classifi import type { V1_FunctionActivatorInfo } from './functionActivator/V1_FunctionActivatorInfo.js'; import type { V1_FunctionActivatorError } from './functionActivator/V1_FunctionActivatorError.js'; import type { V1_FunctionActivatorInput } from './functionActivator/V1_FunctionActivatorInput.js'; +import type { V1_DatabaseBuilderInput } from './generation/V1_DatabaseBuilderInput.js'; +import type { V1_RawSQLExecuteInput } from './execution/V1_RawSQLExecuteInput.js'; enum CORE_ENGINE_ACTIVITY_TRACE { GRAMMAR_TO_JSON = 'transform Pure code to protocol', @@ -99,6 +101,9 @@ enum CORE_ENGINE_ACTIVITY_TRACE { MAPPING_MODEL_COVERAGE_ANALYTICS = 'mapping model coverage analytics', SURVEY_DATASET_ANALYTICS = 'survey dataset analytics', STORE_ENTITLEMENT_ANALYTICS = 'store entitlement analytics', + + DATABASE_SCHEMA_EXPLORATION = 'database schema exploration', + DATABASE_RAW_SQL_EXECUTION = 'database raw SQL execution', } type GrammarParserBatchInputEntry = { @@ -622,15 +627,27 @@ export class V1_EngineServerClient extends AbstractServerClient { ); _databaseUtilities = (): string => `${this._pure()}/utilities/database`; + buildDatabase = ( - input: PlainObject, + input: PlainObject, ): Promise> => this.postWithTracing( - this.getTraceData(CORE_ENGINE_ACTIVITY_TRACE.GENERATE_EXECUTION_PLAN), + this.getTraceData(CORE_ENGINE_ACTIVITY_TRACE.DATABASE_SCHEMA_EXPLORATION), `${this._databaseUtilities()}/schemaExploration`, input, ); + executeRawSQL = ( + input: PlainObject, + ): Promise => + this.postWithTracing( + this.getTraceData(CORE_ENGINE_ACTIVITY_TRACE.DATABASE_RAW_SQL_EXECUTION), + `${this._databaseUtilities()}/executeRawSQL`, + input, + {}, + { [HttpHeader.ACCEPT]: ContentType.TEXT_PLAIN }, + ); + // ------------------------------------------- Function --------------------------------------- _functionActivator = (): string => `${this.baseUrl}/functionActivator`; diff --git a/packages/legend-graph/src/graph-manager/protocol/pure/v1/engine/execution/V1_RawSQLExecuteInput.ts b/packages/legend-graph/src/graph-manager/protocol/pure/v1/engine/execution/V1_RawSQLExecuteInput.ts new file mode 100644 index 0000000000..25881484a1 --- /dev/null +++ b/packages/legend-graph/src/graph-manager/protocol/pure/v1/engine/execution/V1_RawSQLExecuteInput.ts @@ -0,0 +1,52 @@ +/** + * 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 { + createModelSchema, + primitive, + custom, + serialize, + type ModelSchema, +} from 'serializr'; +import { type PlainObject } from '@finos/legend-shared'; +import { + V1_serializeConnectionValue, + V1_deserializeConnectionValue, +} from '../../transformation/pureProtocol/serializationHelpers/V1_ConnectionSerializationHelper.js'; +import type { V1_RelationalDatabaseConnection } from '../../model/packageableElements/store/relational/connection/V1_RelationalDatabaseConnection.js'; +import type { PureProtocolProcessorPlugin } from '../../../PureProtocolProcessorPlugin.js'; + +export class V1_RawSQLExecuteInput { + connection!: V1_RelationalDatabaseConnection; + sql!: string; +} + +const createRawSQLExecuteInpuModelSchema = ( + plugins: PureProtocolProcessorPlugin[], +): ModelSchema => + createModelSchema(V1_RawSQLExecuteInput, { + connection: custom( + (val) => V1_serializeConnectionValue(val, false, plugins), + (val) => V1_deserializeConnectionValue(val, false, plugins), + ), + sql: primitive(), + }); + +export const V1_serializeRawSQLExecuteInput = ( + value: V1_RawSQLExecuteInput, + plugins: PureProtocolProcessorPlugin[], +): PlainObject => + serialize(createRawSQLExecuteInpuModelSchema(plugins), value); diff --git a/packages/legend-graph/src/graph-manager/protocol/pure/v1/engine/generation/V1_DatabaseBuilderInput.ts b/packages/legend-graph/src/graph-manager/protocol/pure/v1/engine/generation/V1_DatabaseBuilderInput.ts index 1e2779e70e..c0dbeb866a 100644 --- a/packages/legend-graph/src/graph-manager/protocol/pure/v1/engine/generation/V1_DatabaseBuilderInput.ts +++ b/packages/legend-graph/src/graph-manager/protocol/pure/v1/engine/generation/V1_DatabaseBuilderInput.ts @@ -20,8 +20,14 @@ import { custom, list, optional, + serialize, + type ModelSchema, } from 'serializr'; -import { SerializationFactory, usingModelSchema } from '@finos/legend-shared'; +import { + SerializationFactory, + usingModelSchema, + type PlainObject, +} from '@finos/legend-shared'; import { V1_serializeConnectionValue, V1_deserializeConnectionValue, @@ -81,9 +87,9 @@ export class V1_DatabaseBuilderInput { targetDatabase!: V1_TargetDatabase; } -export const V1_setupDatabaseBuilderInputSerialization = ( +const createDatabaseBuilderInputModelSchema = ( plugins: PureProtocolProcessorPlugin[], -): void => { +): ModelSchema => createModelSchema(V1_DatabaseBuilderInput, { config: usingModelSchema(V1_DatabaseBuilderConfig.serialization.schema), connection: custom( @@ -92,4 +98,9 @@ export const V1_setupDatabaseBuilderInputSerialization = ( ), targetDatabase: usingModelSchema(V1_TargetDatabase.serialization.schema), }); -}; + +export const V1_serializeDatabaseBuilderInput = ( + value: V1_DatabaseBuilderInput, + plugins: PureProtocolProcessorPlugin[], +): PlainObject => + serialize(createDatabaseBuilderInputModelSchema(plugins), value); diff --git a/packages/legend-graph/src/graph-manager/protocol/pure/v1/model/context/V1_PureModelContextData.ts b/packages/legend-graph/src/graph-manager/protocol/pure/v1/model/context/V1_PureModelContextData.ts index f9e796a8ae..b30c7e5e40 100644 --- a/packages/legend-graph/src/graph-manager/protocol/pure/v1/model/context/V1_PureModelContextData.ts +++ b/packages/legend-graph/src/graph-manager/protocol/pure/v1/model/context/V1_PureModelContextData.ts @@ -25,9 +25,9 @@ export class V1_PureModelContextData extends V1_PureModelContext { serializer?: V1_Protocol | undefined; elements: V1_PackageableElement[] = []; /** - * we use this to hold serialized elements as entities to save on transforming/serializing immutable entities + * We use this to hold serialized elements as entities to save on transforming/serializing immutable entities * * @discrepancy model */ - INTERNAL__rawDependencyEntities: Entity[] = []; + INTERNAL__rawDependencyEntities?: Entity[] | undefined; } diff --git a/packages/legend-graph/src/graph-manager/protocol/pure/v1/transformation/pureProtocol/V1_PureProtocolSerialization.ts b/packages/legend-graph/src/graph-manager/protocol/pure/v1/transformation/pureProtocol/V1_PureProtocolSerialization.ts index 93519ee019..69b0d3a4cb 100644 --- a/packages/legend-graph/src/graph-manager/protocol/pure/v1/transformation/pureProtocol/V1_PureProtocolSerialization.ts +++ b/packages/legend-graph/src/graph-manager/protocol/pure/v1/transformation/pureProtocol/V1_PureProtocolSerialization.ts @@ -196,7 +196,7 @@ export const V1_serializePureModelContext = ( return serialize(V1_pureModelContextPointerModelSchema, pureModelContext); } else if (pureModelContext instanceof V1_PureModelContextData) { const rawPMCD = V1_serializePureModelContextData(pureModelContext); - if (pureModelContext.INTERNAL__rawDependencyEntities.length) { + if (pureModelContext.INTERNAL__rawDependencyEntities?.length) { rawPMCD.elements = [ ...(rawPMCD as { elements: PlainObject[] }).elements, ...pureModelContext.INTERNAL__rawDependencyEntities.map( diff --git a/packages/legend-graph/src/graph/helpers/STO_Relational_Helper.ts b/packages/legend-graph/src/graph/helpers/STO_Relational_Helper.ts index 246f2da777..5bb8aca53d 100644 --- a/packages/legend-graph/src/graph/helpers/STO_Relational_Helper.ts +++ b/packages/legend-graph/src/graph/helpers/STO_Relational_Helper.ts @@ -39,6 +39,8 @@ import { VarBinary, Binary, Bit, + BigInt, + Date, Numeric, Decimal, Double, @@ -51,7 +53,10 @@ import { Other, SemiStructured, Json, + RelationalDatabaseConnection, } from '../../STO_Relational_Exports.js'; +import type { PackageableElement } from '../metamodel/pure/packageableElements/PackageableElement.js'; +import { PackageableConnection } from '../metamodel/pure/packageableElements/connection/PackageableConnection.js'; const collectIncludedDatabases = ( results: Set, @@ -224,3 +229,11 @@ export const stringifyDataType = (type: RelationalDataType): string => { } return '(UNKNOWN)'; }; + +export const guaranteeRelationalDatabaseConnection = ( + val: PackageableElement | undefined, +): RelationalDatabaseConnection => + guaranteeType( + guaranteeType(val, PackageableConnection).connectionValue, + RelationalDatabaseConnection, + ); diff --git a/packages/legend-lego/src/application/TabManager.tsx b/packages/legend-lego/src/application/TabManager.tsx index 146c5b292b..bc685634da 100644 --- a/packages/legend-lego/src/application/TabManager.tsx +++ b/packages/legend-lego/src/application/TabManager.tsx @@ -35,6 +35,8 @@ type TabDragSource = { tab: TabState; }; +export const TAB_MANAGER__TAB_TEST_ID = 'tab-manager__tab'; + const horizontalToVerticalScroll: React.WheelEventHandler = (event) => { // if scrolling is more horizontal than vertical, there's nothing much to do, the OS should handle it just fine // else, intercept @@ -164,6 +166,7 @@ const Tab = observer( return (
(array: T[], idx: number): T | undefined => { } return array.length > idx ? array[idx] : undefined; }; -export const getNonNullableEntry = (array: T[], idx: number): T => { +export const getNonNullableEntry = ( + array: T[], + idx: number, + message?: string | undefined, +): T => { assertTrue(0 <= idx && idx < array.length, `Index out of bound: ${idx}`); - return guaranteeNonNullable(array[idx]); + return guaranteeNonNullable(array[idx], message); }; /** diff --git a/yarn.lock b/yarn.lock index 32b663dd08..16d8c9a210 100644 --- a/yarn.lock +++ b/yarn.lock @@ -91,14 +91,44 @@ __metadata: languageName: node linkType: hard -"@babel/compat-data@npm:^7.17.7, @babel/compat-data@npm:^7.20.5, @babel/compat-data@npm:^7.21.5": +"@babel/compat-data@npm:^7.17.7, @babel/compat-data@npm:^7.21.5": version: 7.21.9 resolution: "@babel/compat-data@npm:7.21.9" checksum: df97be04955c0801f5a23846f79a100660aa98f9433cfd1fad8f53ecd9f3454538e78522e86275939aa8aa7d6f9e32f23f94bc04ae843f7246b7cd4bffe3a175 languageName: node linkType: hard -"@babel/core@npm:7.21.8, @babel/core@npm:^7.11.6, @babel/core@npm:^7.12.3": +"@babel/compat-data@npm:^7.22.0": + version: 7.22.0 + resolution: "@babel/compat-data@npm:7.22.0" + checksum: 6e5d8c2c6f1598c6d6301ca853180030810ef2e81f73f531147c5ebfef711867b80e9ebe344e9529cc3843a4b5b398f3973f6a88addd827acf2226dfabb11c11 + languageName: node + linkType: hard + +"@babel/core@npm:7.22.1": + version: 7.22.1 + resolution: "@babel/core@npm:7.22.1" + dependencies: + "@ampproject/remapping": ^2.2.0 + "@babel/code-frame": ^7.21.4 + "@babel/generator": ^7.22.0 + "@babel/helper-compilation-targets": ^7.22.1 + "@babel/helper-module-transforms": ^7.22.1 + "@babel/helpers": ^7.22.0 + "@babel/parser": ^7.22.0 + "@babel/template": ^7.21.9 + "@babel/traverse": ^7.22.1 + "@babel/types": ^7.22.0 + convert-source-map: ^1.7.0 + debug: ^4.1.0 + gensync: ^1.0.0-beta.2 + json5: ^2.2.2 + semver: ^6.3.0 + checksum: bbe45e791f223a7e692d2ea6597a73f48050abd24b119c85c48ac6504c30ce63343a2ea3f79b5847bf4b409ddd8a68b6cdc4f0272ded1d2ef6f6b1e9663432f0 + languageName: node + linkType: hard + +"@babel/core@npm:^7.11.6, @babel/core@npm:^7.12.3": version: 7.21.8 resolution: "@babel/core@npm:7.21.8" dependencies: @@ -147,6 +177,18 @@ __metadata: languageName: node linkType: hard +"@babel/generator@npm:^7.22.0": + version: 7.22.0 + resolution: "@babel/generator@npm:7.22.0" + dependencies: + "@babel/types": ^7.22.0 + "@jridgewell/gen-mapping": ^0.3.2 + "@jridgewell/trace-mapping": ^0.3.17 + jsesc: ^2.5.1 + checksum: 48b96cb24d1ac90d5629324123f35fc241386359d39822d80e6db89f83d1444e802142d4e8b81b49ab4095362d71a7af648d3ee3735707e9b38ee69676712c12 + languageName: node + linkType: hard + "@babel/helper-annotate-as-pure@npm:^7.18.6": version: 7.18.6 resolution: "@babel/helper-annotate-as-pure@npm:7.18.6" @@ -180,7 +222,22 @@ __metadata: languageName: node linkType: hard -"@babel/helper-create-class-features-plugin@npm:^7.18.6, @babel/helper-create-class-features-plugin@npm:^7.21.0": +"@babel/helper-compilation-targets@npm:^7.22.1": + version: 7.22.1 + resolution: "@babel/helper-compilation-targets@npm:7.22.1" + dependencies: + "@babel/compat-data": ^7.22.0 + "@babel/helper-validator-option": ^7.21.0 + browserslist: ^4.21.3 + lru-cache: ^5.1.1 + semver: ^6.3.0 + peerDependencies: + "@babel/core": ^7.0.0 + checksum: a686a01bd3288cf95ca26faa27958d34c04e2501c4b0858c3a6558776dec20317b5635f33d64c5a635b6fbdfe462a85c30d4bfa0ae7e7ffe3467e4d06442d7c8 + languageName: node + linkType: hard + +"@babel/helper-create-class-features-plugin@npm:^7.21.0": version: 7.21.8 resolution: "@babel/helper-create-class-features-plugin@npm:7.21.8" dependencies: @@ -199,7 +256,26 @@ __metadata: languageName: node linkType: hard -"@babel/helper-create-regexp-features-plugin@npm:^7.18.6, @babel/helper-create-regexp-features-plugin@npm:^7.20.5": +"@babel/helper-create-class-features-plugin@npm:^7.22.0": + version: 7.22.0 + resolution: "@babel/helper-create-class-features-plugin@npm:7.22.0" + dependencies: + "@babel/helper-annotate-as-pure": ^7.18.6 + "@babel/helper-environment-visitor": ^7.21.5 + "@babel/helper-function-name": ^7.21.0 + "@babel/helper-member-expression-to-functions": ^7.22.0 + "@babel/helper-optimise-call-expression": ^7.18.6 + "@babel/helper-replace-supers": ^7.21.5 + "@babel/helper-skip-transparent-expression-wrappers": ^7.20.0 + "@babel/helper-split-export-declaration": ^7.18.6 + semver: ^6.3.0 + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 317916a14eaa264da8c89e16b00206e046a0ed1090943bdd1327599b72369a9f296e01b4186520ea40acba5fbebd357b7f4a1a480ea59bad7ff99dc9218c69d1 + languageName: node + linkType: hard + +"@babel/helper-create-regexp-features-plugin@npm:^7.18.6": version: 7.21.8 resolution: "@babel/helper-create-regexp-features-plugin@npm:7.21.8" dependencies: @@ -212,9 +288,22 @@ __metadata: languageName: node linkType: hard -"@babel/helper-define-polyfill-provider@npm:^0.3.3": - version: 0.3.3 - resolution: "@babel/helper-define-polyfill-provider@npm:0.3.3" +"@babel/helper-create-regexp-features-plugin@npm:^7.22.0": + version: 7.22.0 + resolution: "@babel/helper-create-regexp-features-plugin@npm:7.22.0" + dependencies: + "@babel/helper-annotate-as-pure": ^7.18.6 + regexpu-core: ^5.3.1 + semver: ^6.3.0 + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 9f4e14c85af7bda84cef4c518602454a16a2c739185dc31d055cfe9403545b12b59f345f7263c87a2f9420dd6a6c56e33cabe24597590d0d6d0e027eff006521 + languageName: node + linkType: hard + +"@babel/helper-define-polyfill-provider@npm:^0.4.0": + version: 0.4.0 + resolution: "@babel/helper-define-polyfill-provider@npm:0.4.0" dependencies: "@babel/helper-compilation-targets": ^7.17.7 "@babel/helper-plugin-utils": ^7.16.7 @@ -224,7 +313,7 @@ __metadata: semver: ^6.1.2 peerDependencies: "@babel/core": ^7.4.0-0 - checksum: 8e3fe75513302e34f6d92bd67b53890e8545e6c5bca8fe757b9979f09d68d7e259f6daea90dc9e01e332c4f8781bda31c5fe551c82a277f9bc0bec007aed497c + checksum: 5dca4c5e78457c5ced366bea601efa4e8c69bf5d53b0fe540283897575c49b1b88191c8ef062110de9046e886703ed3270fcda3a87f0886cdbb549204d3ff63f languageName: node linkType: hard @@ -235,6 +324,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-environment-visitor@npm:^7.22.1": + version: 7.22.1 + resolution: "@babel/helper-environment-visitor@npm:7.22.1" + checksum: a6b4bb5505453bff95518d361ac1de393f0029aeb8b690c70540f4317934c53c43cc4afcda8c752ffa8c272e63ed6b929a56eca28e4978424177b24238b21bf9 + languageName: node + linkType: hard + "@babel/helper-function-name@npm:^7.18.9, @babel/helper-function-name@npm:^7.19.0, @babel/helper-function-name@npm:^7.21.0": version: 7.21.0 resolution: "@babel/helper-function-name@npm:7.21.0" @@ -263,6 +359,15 @@ __metadata: languageName: node linkType: hard +"@babel/helper-member-expression-to-functions@npm:^7.22.0": + version: 7.22.0 + resolution: "@babel/helper-member-expression-to-functions@npm:7.22.0" + dependencies: + "@babel/types": ^7.22.0 + checksum: c6b9c175fd37156fdac14752171135385925fdca6621c046183b3da99a30b35901b4f5a5fcd63aa9d20536898660e40ad1181c29bc7f2f06a6bdf0b44b5c60ec + languageName: node + linkType: hard + "@babel/helper-module-imports@npm:^7.16.7, @babel/helper-module-imports@npm:^7.18.6, @babel/helper-module-imports@npm:^7.21.4": version: 7.21.4 resolution: "@babel/helper-module-imports@npm:7.21.4" @@ -288,6 +393,38 @@ __metadata: languageName: node linkType: hard +"@babel/helper-module-transforms@npm:^7.22.0": + version: 7.22.0 + resolution: "@babel/helper-module-transforms@npm:7.22.0" + dependencies: + "@babel/helper-environment-visitor": ^7.21.5 + "@babel/helper-module-imports": ^7.21.4 + "@babel/helper-simple-access": ^7.21.5 + "@babel/helper-split-export-declaration": ^7.18.6 + "@babel/helper-validator-identifier": ^7.19.1 + "@babel/template": ^7.21.9 + "@babel/traverse": ^7.22.0 + "@babel/types": ^7.22.0 + checksum: 47380be9819166f2285ef395671ac7a6cec04deb608a64292c8023c491ff8514b33a785cb760d82beebb8f9cb8a13b02d00517adde024876a33e0d4c44515acd + languageName: node + linkType: hard + +"@babel/helper-module-transforms@npm:^7.22.1": + version: 7.22.1 + resolution: "@babel/helper-module-transforms@npm:7.22.1" + dependencies: + "@babel/helper-environment-visitor": ^7.22.1 + "@babel/helper-module-imports": ^7.21.4 + "@babel/helper-simple-access": ^7.21.5 + "@babel/helper-split-export-declaration": ^7.18.6 + "@babel/helper-validator-identifier": ^7.19.1 + "@babel/template": ^7.21.9 + "@babel/traverse": ^7.22.1 + "@babel/types": ^7.22.0 + checksum: dfa084211a93c9f0174ab07385fdbf7831bbf5c1ff3d4f984effc489f48670825ad8b817b9e9d2ec6492fde37ed6518c15944e9dd7a60b43a3d9874c9250f5f8 + languageName: node + linkType: hard + "@babel/helper-optimise-call-expression@npm:^7.18.6": version: 7.18.6 resolution: "@babel/helper-optimise-call-expression@npm:7.18.6" @@ -373,7 +510,7 @@ __metadata: languageName: node linkType: hard -"@babel/helper-validator-option@npm:^7.18.6, @babel/helper-validator-option@npm:^7.21.0": +"@babel/helper-validator-option@npm:^7.21.0": version: 7.21.0 resolution: "@babel/helper-validator-option@npm:7.21.0" checksum: 8ece4c78ffa5461fd8ab6b6e57cc51afad59df08192ed5d84b475af4a7193fc1cb794b59e3e7be64f3cdc4df7ac78bf3dbb20c129d7757ae078e6279ff8c2f07 @@ -403,6 +540,17 @@ __metadata: languageName: node linkType: hard +"@babel/helpers@npm:^7.22.0": + version: 7.22.0 + resolution: "@babel/helpers@npm:7.22.0" + dependencies: + "@babel/template": ^7.21.9 + "@babel/traverse": ^7.22.0 + "@babel/types": ^7.22.0 + checksum: abb5889252b7b91df63ac34e552503efc2f62e67f6c840e54f5554fbc217724ab0c28ba02727ca58723aeb22c6552b6fb59dfb993d5564bab7dec696957c5442 + languageName: node + linkType: hard + "@babel/highlight@npm:^7.18.6": version: 7.18.6 resolution: "@babel/highlight@npm:7.18.6" @@ -423,6 +571,15 @@ __metadata: languageName: node linkType: hard +"@babel/parser@npm:^7.22.0": + version: 7.22.0 + resolution: "@babel/parser@npm:7.22.0" + bin: + parser: ./bin/babel-parser.js + checksum: 1b6528eca79c18e2186ef430ed2fe1144080bd84a995289c1f9ae61341057f2ad6ea60ccf947b0edde053b32e0c87d981911de6ef28ab7c16b8ed8537664e7c9 + languageName: node + linkType: hard + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:^7.18.6": version: 7.18.6 resolution: "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:7.18.6" @@ -434,179 +591,16 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@npm:^7.20.7": - version: 7.20.7 - resolution: "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@npm:7.20.7" +"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@npm:^7.22.0": + version: 7.22.0 + resolution: "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@npm:7.22.0" dependencies: - "@babel/helper-plugin-utils": ^7.20.2 + "@babel/helper-plugin-utils": ^7.21.5 "@babel/helper-skip-transparent-expression-wrappers": ^7.20.0 - "@babel/plugin-proposal-optional-chaining": ^7.20.7 + "@babel/plugin-transform-optional-chaining": ^7.22.0 peerDependencies: "@babel/core": ^7.13.0 - checksum: d610f532210bee5342f5b44a12395ccc6d904e675a297189bc1e401cc185beec09873da523466d7fec34ae1574f7a384235cba1ccc9fe7b89ba094167897c845 - languageName: node - linkType: hard - -"@babel/plugin-proposal-async-generator-functions@npm:^7.20.7": - version: 7.20.7 - resolution: "@babel/plugin-proposal-async-generator-functions@npm:7.20.7" - dependencies: - "@babel/helper-environment-visitor": ^7.18.9 - "@babel/helper-plugin-utils": ^7.20.2 - "@babel/helper-remap-async-to-generator": ^7.18.9 - "@babel/plugin-syntax-async-generators": ^7.8.4 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 111109ee118c9e69982f08d5e119eab04190b36a0f40e22e873802d941956eee66d2aa5a15f5321e51e3f9aa70a91136451b987fe15185ef8cc547ac88937723 - languageName: node - linkType: hard - -"@babel/plugin-proposal-class-properties@npm:^7.18.6": - version: 7.18.6 - resolution: "@babel/plugin-proposal-class-properties@npm:7.18.6" - dependencies: - "@babel/helper-create-class-features-plugin": ^7.18.6 - "@babel/helper-plugin-utils": ^7.18.6 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 49a78a2773ec0db56e915d9797e44fd079ab8a9b2e1716e0df07c92532f2c65d76aeda9543883916b8e0ff13606afeffa67c5b93d05b607bc87653ad18a91422 - languageName: node - linkType: hard - -"@babel/plugin-proposal-class-static-block@npm:^7.21.0": - version: 7.21.0 - resolution: "@babel/plugin-proposal-class-static-block@npm:7.21.0" - dependencies: - "@babel/helper-create-class-features-plugin": ^7.21.0 - "@babel/helper-plugin-utils": ^7.20.2 - "@babel/plugin-syntax-class-static-block": ^7.14.5 - peerDependencies: - "@babel/core": ^7.12.0 - checksum: 236c0ad089e7a7acab776cc1d355330193314bfcd62e94e78f2df35817c6144d7e0e0368976778afd6b7c13e70b5068fa84d7abbf967d4f182e60d03f9ef802b - languageName: node - linkType: hard - -"@babel/plugin-proposal-dynamic-import@npm:^7.18.6": - version: 7.18.6 - resolution: "@babel/plugin-proposal-dynamic-import@npm:7.18.6" - dependencies: - "@babel/helper-plugin-utils": ^7.18.6 - "@babel/plugin-syntax-dynamic-import": ^7.8.3 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 96b1c8a8ad8171d39e9ab106be33bde37ae09b22fb2c449afee9a5edf3c537933d79d963dcdc2694d10677cb96da739cdf1b53454e6a5deab9801f28a818bb2f - languageName: node - linkType: hard - -"@babel/plugin-proposal-export-namespace-from@npm:^7.18.9": - version: 7.18.9 - resolution: "@babel/plugin-proposal-export-namespace-from@npm:7.18.9" - dependencies: - "@babel/helper-plugin-utils": ^7.18.9 - "@babel/plugin-syntax-export-namespace-from": ^7.8.3 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 84ff22bacc5d30918a849bfb7e0e90ae4c5b8d8b65f2ac881803d1cf9068dffbe53bd657b0e4bc4c20b4db301b1c85f1e74183cf29a0dd31e964bd4e97c363ef - languageName: node - linkType: hard - -"@babel/plugin-proposal-json-strings@npm:^7.18.6": - version: 7.18.6 - resolution: "@babel/plugin-proposal-json-strings@npm:7.18.6" - dependencies: - "@babel/helper-plugin-utils": ^7.18.6 - "@babel/plugin-syntax-json-strings": ^7.8.3 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 25ba0e6b9d6115174f51f7c6787e96214c90dd4026e266976b248a2ed417fe50fddae72843ffb3cbe324014a18632ce5648dfac77f089da858022b49fd608cb3 - languageName: node - linkType: hard - -"@babel/plugin-proposal-logical-assignment-operators@npm:^7.20.7": - version: 7.20.7 - resolution: "@babel/plugin-proposal-logical-assignment-operators@npm:7.20.7" - dependencies: - "@babel/helper-plugin-utils": ^7.20.2 - "@babel/plugin-syntax-logical-assignment-operators": ^7.10.4 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: cdd7b8136cc4db3f47714d5266f9e7b592a2ac5a94a5878787ce08890e97c8ab1ca8e94b27bfeba7b0f2b1549a026d9fc414ca2196de603df36fb32633bbdc19 - languageName: node - linkType: hard - -"@babel/plugin-proposal-nullish-coalescing-operator@npm:^7.18.6": - version: 7.18.6 - resolution: "@babel/plugin-proposal-nullish-coalescing-operator@npm:7.18.6" - dependencies: - "@babel/helper-plugin-utils": ^7.18.6 - "@babel/plugin-syntax-nullish-coalescing-operator": ^7.8.3 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 949c9ddcdecdaec766ee610ef98f965f928ccc0361dd87cf9f88cf4896a6ccd62fce063d4494778e50da99dea63d270a1be574a62d6ab81cbe9d85884bf55a7d - languageName: node - linkType: hard - -"@babel/plugin-proposal-numeric-separator@npm:^7.18.6": - version: 7.18.6 - resolution: "@babel/plugin-proposal-numeric-separator@npm:7.18.6" - dependencies: - "@babel/helper-plugin-utils": ^7.18.6 - "@babel/plugin-syntax-numeric-separator": ^7.10.4 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: f370ea584c55bf4040e1f78c80b4eeb1ce2e6aaa74f87d1a48266493c33931d0b6222d8cee3a082383d6bb648ab8d6b7147a06f974d3296ef3bc39c7851683ec - languageName: node - linkType: hard - -"@babel/plugin-proposal-object-rest-spread@npm:^7.20.7": - version: 7.20.7 - resolution: "@babel/plugin-proposal-object-rest-spread@npm:7.20.7" - dependencies: - "@babel/compat-data": ^7.20.5 - "@babel/helper-compilation-targets": ^7.20.7 - "@babel/helper-plugin-utils": ^7.20.2 - "@babel/plugin-syntax-object-rest-spread": ^7.8.3 - "@babel/plugin-transform-parameters": ^7.20.7 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 1329db17009964bc644484c660eab717cb3ca63ac0ab0f67c651a028d1bc2ead51dc4064caea283e46994f1b7221670a35cbc0b4beb6273f55e915494b5aa0b2 - languageName: node - linkType: hard - -"@babel/plugin-proposal-optional-catch-binding@npm:^7.18.6": - version: 7.18.6 - resolution: "@babel/plugin-proposal-optional-catch-binding@npm:7.18.6" - dependencies: - "@babel/helper-plugin-utils": ^7.18.6 - "@babel/plugin-syntax-optional-catch-binding": ^7.8.3 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 7b5b39fb5d8d6d14faad6cb68ece5eeb2fd550fb66b5af7d7582402f974f5bc3684641f7c192a5a57e0f59acfae4aada6786be1eba030881ddc590666eff4d1e - languageName: node - linkType: hard - -"@babel/plugin-proposal-optional-chaining@npm:^7.20.7, @babel/plugin-proposal-optional-chaining@npm:^7.21.0": - version: 7.21.0 - resolution: "@babel/plugin-proposal-optional-chaining@npm:7.21.0" - dependencies: - "@babel/helper-plugin-utils": ^7.20.2 - "@babel/helper-skip-transparent-expression-wrappers": ^7.20.0 - "@babel/plugin-syntax-optional-chaining": ^7.8.3 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 11c5449e01b18bb8881e8e005a577fa7be2fe5688e2382c8822d51f8f7005342a301a46af7b273b1f5645f9a7b894c428eee8526342038a275ef6ba4c8d8d746 - languageName: node - linkType: hard - -"@babel/plugin-proposal-private-methods@npm:^7.18.6": - version: 7.18.6 - resolution: "@babel/plugin-proposal-private-methods@npm:7.18.6" - dependencies: - "@babel/helper-create-class-features-plugin": ^7.18.6 - "@babel/helper-plugin-utils": ^7.18.6 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 22d8502ee96bca99ad2c8393e8493e2b8d4507576dd054490fd8201a36824373440106f5b098b6d821b026c7e72b0424ff4aeca69ed5f42e48f029d3a156d5ad + checksum: 71e93d6d0159da3338716cdd1e06a43c60f4c197d70b526e9898bd07b548b9c7979ca635c965f1894a258f5fdfa175d8f8e2d1daa084f340c6b8b970b26f3678 languageName: node linkType: hard @@ -624,7 +618,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-proposal-unicode-property-regex@npm:^7.18.6, @babel/plugin-proposal-unicode-property-regex@npm:^7.4.4": +"@babel/plugin-proposal-unicode-property-regex@npm:^7.4.4": version: 7.18.6 resolution: "@babel/plugin-proposal-unicode-property-regex@npm:7.18.6" dependencies: @@ -713,6 +707,17 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-syntax-import-attributes@npm:^7.22.0": + version: 7.22.0 + resolution: "@babel/plugin-syntax-import-attributes@npm:7.22.0" + dependencies: + "@babel/helper-plugin-utils": ^7.21.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: a81bdb1daab63af7795e4e0c9ad99df3ba16cac085227d27cf0a24748bd58da852000dbe3b1f6cf18f8bf89703643ad087a96b57c3029c23fb07d1b73215a7ff + languageName: node + linkType: hard + "@babel/plugin-syntax-import-meta@npm:^7.10.4, @babel/plugin-syntax-import-meta@npm:^7.8.3": version: 7.10.4 resolution: "@babel/plugin-syntax-import-meta@npm:7.10.4" @@ -845,6 +850,18 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-syntax-unicode-sets-regex@npm:^7.18.6": + version: 7.18.6 + resolution: "@babel/plugin-syntax-unicode-sets-regex@npm:7.18.6" + dependencies: + "@babel/helper-create-regexp-features-plugin": ^7.18.6 + "@babel/helper-plugin-utils": ^7.18.6 + peerDependencies: + "@babel/core": ^7.0.0 + checksum: a651d700fe63ff0ddfd7186f4ebc24447ca734f114433139e3c027bc94a900d013cf1ef2e2db8430425ba542e39ae160c3b05f06b59fd4656273a3df97679e9c + languageName: node + linkType: hard + "@babel/plugin-transform-arrow-functions@npm:^7.21.5": version: 7.21.5 resolution: "@babel/plugin-transform-arrow-functions@npm:7.21.5" @@ -856,6 +873,20 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-async-generator-functions@npm:^7.22.0": + version: 7.22.0 + resolution: "@babel/plugin-transform-async-generator-functions@npm:7.22.0" + dependencies: + "@babel/helper-environment-visitor": ^7.21.5 + "@babel/helper-plugin-utils": ^7.21.5 + "@babel/helper-remap-async-to-generator": ^7.18.9 + "@babel/plugin-syntax-async-generators": ^7.8.4 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: ad4bff12e1aa8ea11a393714cf2d44909a7ee1145f9f1d84bc62beef605136e482b2ad3c901d8ef638dfc05fbae0ee7f76f44d81d57f486c70bfde0dcdeab138 + languageName: node + linkType: hard + "@babel/plugin-transform-async-to-generator@npm:^7.20.7": version: 7.20.7 resolution: "@babel/plugin-transform-async-to-generator@npm:7.20.7" @@ -891,6 +922,31 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-class-properties@npm:^7.22.0": + version: 7.22.0 + resolution: "@babel/plugin-transform-class-properties@npm:7.22.0" + dependencies: + "@babel/helper-create-class-features-plugin": ^7.22.0 + "@babel/helper-plugin-utils": ^7.21.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 29c2c231e8aadd1fb9c2daabaaff8311a14a4f39ddafa8cb46722d388b351b5f5ec0e392d54f5493ca3ace96d93aeb6292f1d0e3df5b24050e3fa55e5b7f56b3 + languageName: node + linkType: hard + +"@babel/plugin-transform-class-static-block@npm:^7.22.0": + version: 7.22.0 + resolution: "@babel/plugin-transform-class-static-block@npm:7.22.0" + dependencies: + "@babel/helper-create-class-features-plugin": ^7.22.0 + "@babel/helper-plugin-utils": ^7.21.5 + "@babel/plugin-syntax-class-static-block": ^7.14.5 + peerDependencies: + "@babel/core": ^7.12.0 + checksum: 2f8910d64936ce3e5a2e2ec6adf024eba87a4fe3c1a283e77c5fe61d8ba98be7c7dca8be2a39625ac3d6083588b5aef308ad88e9a5db22b8b8c40b8e888b2a8e + languageName: node + linkType: hard + "@babel/plugin-transform-classes@npm:^7.21.0": version: 7.21.0 resolution: "@babel/plugin-transform-classes@npm:7.21.0" @@ -956,6 +1012,18 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-dynamic-import@npm:^7.22.1": + version: 7.22.1 + resolution: "@babel/plugin-transform-dynamic-import@npm:7.22.1" + dependencies: + "@babel/helper-plugin-utils": ^7.21.5 + "@babel/plugin-syntax-dynamic-import": ^7.8.3 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: e322a08f01cedddcd7c70aa6a74342e900df39ab13dbaa2c8175af660b1786dd26b582546fc37e16bec47181931963e173ff53ffd7c41d5f54687da5f8d457bb + languageName: node + linkType: hard + "@babel/plugin-transform-exponentiation-operator@npm:^7.18.6": version: 7.18.6 resolution: "@babel/plugin-transform-exponentiation-operator@npm:7.18.6" @@ -968,6 +1036,18 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-export-namespace-from@npm:^7.22.0": + version: 7.22.0 + resolution: "@babel/plugin-transform-export-namespace-from@npm:7.22.0" + dependencies: + "@babel/helper-plugin-utils": ^7.21.5 + "@babel/plugin-syntax-export-namespace-from": ^7.8.3 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: cef82e2305746a501b6596bb2fa6d831d5668d6ac769d188b0f4a8d5597b6bc3699d04c945c34d2581944465dc2e12ede69babce918a1dc9f351ad372b1818d4 + languageName: node + linkType: hard + "@babel/plugin-transform-for-of@npm:^7.21.5": version: 7.21.5 resolution: "@babel/plugin-transform-for-of@npm:7.21.5" @@ -992,6 +1072,18 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-json-strings@npm:^7.22.0": + version: 7.22.0 + resolution: "@babel/plugin-transform-json-strings@npm:7.22.0" + dependencies: + "@babel/helper-plugin-utils": ^7.21.5 + "@babel/plugin-syntax-json-strings": ^7.8.3 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: e9d75e8bb67096d7fdf93d2947e2cf119db813c281c8bde7a61c5b16fc758f2bba2642ca0fb8ef77b9450ae821772f386c66c15e4a156cae7b9fe9127db9f779 + languageName: node + linkType: hard + "@babel/plugin-transform-literals@npm:^7.18.9": version: 7.18.9 resolution: "@babel/plugin-transform-literals@npm:7.18.9" @@ -1003,6 +1095,18 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-logical-assignment-operators@npm:^7.22.0": + version: 7.22.0 + resolution: "@babel/plugin-transform-logical-assignment-operators@npm:7.22.0" + dependencies: + "@babel/helper-plugin-utils": ^7.21.5 + "@babel/plugin-syntax-logical-assignment-operators": ^7.10.4 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 41a5c82fca8ac4cbed67e7d863f29dd402dc8bbd35346e569263e22c46416945863d386cdd5ed0b4d4ae3316389d34b8e9bb2946679a0b1e80ca1f98a04718ff + languageName: node + linkType: hard + "@babel/plugin-transform-member-expression-literals@npm:^7.18.6": version: 7.18.6 resolution: "@babel/plugin-transform-member-expression-literals@npm:7.18.6" @@ -1039,17 +1143,17 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-modules-systemjs@npm:^7.20.11": - version: 7.20.11 - resolution: "@babel/plugin-transform-modules-systemjs@npm:7.20.11" +"@babel/plugin-transform-modules-systemjs@npm:^7.22.0": + version: 7.22.0 + resolution: "@babel/plugin-transform-modules-systemjs@npm:7.22.0" dependencies: "@babel/helper-hoist-variables": ^7.18.6 - "@babel/helper-module-transforms": ^7.20.11 - "@babel/helper-plugin-utils": ^7.20.2 + "@babel/helper-module-transforms": ^7.22.0 + "@babel/helper-plugin-utils": ^7.21.5 "@babel/helper-validator-identifier": ^7.19.1 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 4546c47587f88156d66c7eb7808e903cf4bb3f6ba6ac9bc8e3af2e29e92eb9f0b3f44d52043bfd24eb25fa7827fd7b6c8bfeac0cac7584e019b87e1ecbd0e673 + checksum: b12aefc9f522f88a242ae21d109fbf278a5b4e8cd2a5c71d1adc12abeabfbed486bc85c1e7a0105a212fd5cd26e94f10ea68df2f3bd87dc2d0f9952c7b29aa13 languageName: node linkType: hard @@ -1065,26 +1169,65 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-named-capturing-groups-regex@npm:^7.20.5": - version: 7.20.5 - resolution: "@babel/plugin-transform-named-capturing-groups-regex@npm:7.20.5" +"@babel/plugin-transform-named-capturing-groups-regex@npm:^7.22.0": + version: 7.22.0 + resolution: "@babel/plugin-transform-named-capturing-groups-regex@npm:7.22.0" dependencies: - "@babel/helper-create-regexp-features-plugin": ^7.20.5 - "@babel/helper-plugin-utils": ^7.20.2 + "@babel/helper-create-regexp-features-plugin": ^7.22.0 + "@babel/helper-plugin-utils": ^7.21.5 peerDependencies: "@babel/core": ^7.0.0 - checksum: 528c95fb1087e212f17e1c6456df041b28a83c772b9c93d2e407c9d03b72182b0d9d126770c1d6e0b23aab052599ceaf25ed6a2c0627f4249be34a83f6fae853 + checksum: 482db98466170f514f7e19cf71ffc2a3bb39ef6d6d3fca457e6a46b6f180796eda5cabfeee403736eef433fbab122d9457dea705a7c7367a4a8fb0191027b591 languageName: node linkType: hard -"@babel/plugin-transform-new-target@npm:^7.18.6": - version: 7.18.6 - resolution: "@babel/plugin-transform-new-target@npm:7.18.6" +"@babel/plugin-transform-new-target@npm:^7.22.0": + version: 7.22.0 + resolution: "@babel/plugin-transform-new-target@npm:7.22.0" dependencies: - "@babel/helper-plugin-utils": ^7.18.6 + "@babel/helper-plugin-utils": ^7.21.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 826e1a105dfe7e7097054242fe7bae1af5475681760fa8042b353c44a13d824a164bf7c53e32c421d9bf37f27f128878bc908f455a5800763d3a4d9d3abb43c8 + languageName: node + linkType: hard + +"@babel/plugin-transform-nullish-coalescing-operator@npm:^7.22.0": + version: 7.22.0 + resolution: "@babel/plugin-transform-nullish-coalescing-operator@npm:7.22.0" + dependencies: + "@babel/helper-plugin-utils": ^7.21.5 + "@babel/plugin-syntax-nullish-coalescing-operator": ^7.8.3 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: e70753f6947636f8e211ac8699397ef4eea30ef376f8bad5dacec828810bee5b5dcd7a7aeb4c201f5718557dbe56023513a1f6681c013de8f1e96024d1c02520 + languageName: node + linkType: hard + +"@babel/plugin-transform-numeric-separator@npm:^7.22.0": + version: 7.22.0 + resolution: "@babel/plugin-transform-numeric-separator@npm:7.22.0" + dependencies: + "@babel/helper-plugin-utils": ^7.21.5 + "@babel/plugin-syntax-numeric-separator": ^7.10.4 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: bd780e14f46af55d0ae8503b3cb81ca86dcc73ed782f177e74f498fff934754f9e9911df1f8f3bd123777eed7c1c1af4d66abab87c8daae5403e7719a6b845d1 + checksum: 087dfab2e69acde3bfaea3e6d614f94229d84b35e9e0c512c43e517b94603a379d2ef508a0f0343db2c5bba85a95d14a19277173142396aaafb1d89be22e3bd5 + languageName: node + linkType: hard + +"@babel/plugin-transform-object-rest-spread@npm:^7.22.0": + version: 7.22.0 + resolution: "@babel/plugin-transform-object-rest-spread@npm:7.22.0" + dependencies: + "@babel/compat-data": ^7.22.0 + "@babel/helper-compilation-targets": ^7.21.5 + "@babel/helper-plugin-utils": ^7.21.5 + "@babel/plugin-syntax-object-rest-spread": ^7.8.3 + "@babel/plugin-transform-parameters": ^7.22.0 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 8fd2129f18eb6d2f2ca55e7e6615ebcd86a8fd2867dc6fc2a9aa1f93a5c81c96fa8d2fd67555403cdeaae7621dc3af61eea53d25f9a328a9952260310f42b11f languageName: node linkType: hard @@ -1100,14 +1243,65 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-parameters@npm:^7.20.7, @babel/plugin-transform-parameters@npm:^7.21.3": - version: 7.21.3 - resolution: "@babel/plugin-transform-parameters@npm:7.21.3" +"@babel/plugin-transform-optional-catch-binding@npm:^7.22.0": + version: 7.22.0 + resolution: "@babel/plugin-transform-optional-catch-binding@npm:7.22.0" dependencies: - "@babel/helper-plugin-utils": ^7.20.2 + "@babel/helper-plugin-utils": ^7.21.5 + "@babel/plugin-syntax-optional-catch-binding": ^7.8.3 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: c92128d7b1fcf54e2cab186c196bbbf55a9a6de11a83328dc2602649c9dc6d16ef73712beecd776cd49bfdc624b5f56740f4a53568d3deb9505ec666bc869da3 + checksum: acc3fdf3d471f881141a0eb2c40cf69b5fc8dbff52fdcebbb53457ad9b0845479ce53491822a1dedcdfc2547e80f8f22acbee7823fd8b6d5a8ebd1c008279a50 + languageName: node + linkType: hard + +"@babel/plugin-transform-optional-chaining@npm:^7.22.0": + version: 7.22.0 + resolution: "@babel/plugin-transform-optional-chaining@npm:7.22.0" + dependencies: + "@babel/helper-plugin-utils": ^7.21.5 + "@babel/helper-skip-transparent-expression-wrappers": ^7.20.0 + "@babel/plugin-syntax-optional-chaining": ^7.8.3 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: b75ae97f26cca3928bbe841849fd900b2a768ed7a7a7c4fc9965d3863eea0c62fae126699ef416104e6aaf758ba5f9fce9077da4c5db2add3aabf9e864f44686 + languageName: node + linkType: hard + +"@babel/plugin-transform-parameters@npm:^7.22.0": + version: 7.22.0 + resolution: "@babel/plugin-transform-parameters@npm:7.22.0" + dependencies: + "@babel/helper-plugin-utils": ^7.21.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: eab2e3aeaf17c708f513d1a93e7666a0353bd60275259762470d457625844860649806bd6849c28b2050bde798e3bf9eb0dff0fdcbcbd1ebffeb73c90622211d + languageName: node + linkType: hard + +"@babel/plugin-transform-private-methods@npm:^7.22.0": + version: 7.22.0 + resolution: "@babel/plugin-transform-private-methods@npm:7.22.0" + dependencies: + "@babel/helper-create-class-features-plugin": ^7.22.0 + "@babel/helper-plugin-utils": ^7.21.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 597b649a0cd6547d092e2a1b5b70d1dee83f8bac709210b20b3a7642960c750ac8d4b3f6ed194e3d8b7923decd0df7a0db01b086768b12b0504db2f6333f36ec + languageName: node + linkType: hard + +"@babel/plugin-transform-private-property-in-object@npm:^7.22.0": + version: 7.22.0 + resolution: "@babel/plugin-transform-private-property-in-object@npm:7.22.0" + dependencies: + "@babel/helper-annotate-as-pure": ^7.18.6 + "@babel/helper-create-class-features-plugin": ^7.22.0 + "@babel/helper-plugin-utils": ^7.21.5 + "@babel/plugin-syntax-private-property-in-object": ^7.14.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 491d135eab41512d63b8baf3016439e6263dd0610fa032895bd2329fc275ee29f4bbf173da47a430bacec595918d02d5353734a1f5500a7af58027a560529da0 languageName: node linkType: hard @@ -1159,6 +1353,21 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-react-jsx@npm:^7.22.0": + version: 7.22.0 + resolution: "@babel/plugin-transform-react-jsx@npm:7.22.0" + dependencies: + "@babel/helper-annotate-as-pure": ^7.18.6 + "@babel/helper-module-imports": ^7.21.4 + "@babel/helper-plugin-utils": ^7.21.5 + "@babel/plugin-syntax-jsx": ^7.21.4 + "@babel/types": ^7.22.0 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 7d4e9a7357730d1471404105f0e745ab6143ab5d3ea54eec67796ad732df131fa3177d333491cf2ba74cc27a2119b87f2c3ebb081dffd7048d9eac30fcf170e4 + languageName: node + linkType: hard + "@babel/plugin-transform-react-pure-annotations@npm:^7.18.6": version: 7.18.6 resolution: "@babel/plugin-transform-react-pure-annotations@npm:7.18.6" @@ -1275,6 +1484,18 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-unicode-property-regex@npm:^7.22.0": + version: 7.22.0 + resolution: "@babel/plugin-transform-unicode-property-regex@npm:7.22.0" + dependencies: + "@babel/helper-create-regexp-features-plugin": ^7.22.0 + "@babel/helper-plugin-utils": ^7.21.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 19c67034453de3d63e5958609cb617f22d4c1f4f7e30dfac3a1ebdf5190b605ace0565aa507b483d2722935be37c5e91d8307c5acdb70527949e9556a9ac4efa + languageName: node + linkType: hard + "@babel/plugin-transform-unicode-regex@npm:^7.18.6": version: 7.18.6 resolution: "@babel/plugin-transform-unicode-regex@npm:7.18.6" @@ -1287,37 +1508,36 @@ __metadata: languageName: node linkType: hard -"@babel/preset-env@npm:7.21.5": - version: 7.21.5 - resolution: "@babel/preset-env@npm:7.21.5" +"@babel/plugin-transform-unicode-sets-regex@npm:^7.22.0": + version: 7.22.0 + resolution: "@babel/plugin-transform-unicode-sets-regex@npm:7.22.0" dependencies: - "@babel/compat-data": ^7.21.5 - "@babel/helper-compilation-targets": ^7.21.5 + "@babel/helper-create-regexp-features-plugin": ^7.22.0 + "@babel/helper-plugin-utils": ^7.21.5 + peerDependencies: + "@babel/core": ^7.0.0 + checksum: a31b65f05dbe83266191998fcc4f73e60f7a392e3510bfb59407dd9954e4e8e37ecdcb343729df5172241859020d6b8fdc5130ad0fd7aac8df4adabed7b9a0ac + languageName: node + linkType: hard + +"@babel/preset-env@npm:7.22.1": + version: 7.22.1 + resolution: "@babel/preset-env@npm:7.22.1" + dependencies: + "@babel/compat-data": ^7.22.0 + "@babel/helper-compilation-targets": ^7.22.1 "@babel/helper-plugin-utils": ^7.21.5 "@babel/helper-validator-option": ^7.21.0 "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": ^7.18.6 - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": ^7.20.7 - "@babel/plugin-proposal-async-generator-functions": ^7.20.7 - "@babel/plugin-proposal-class-properties": ^7.18.6 - "@babel/plugin-proposal-class-static-block": ^7.21.0 - "@babel/plugin-proposal-dynamic-import": ^7.18.6 - "@babel/plugin-proposal-export-namespace-from": ^7.18.9 - "@babel/plugin-proposal-json-strings": ^7.18.6 - "@babel/plugin-proposal-logical-assignment-operators": ^7.20.7 - "@babel/plugin-proposal-nullish-coalescing-operator": ^7.18.6 - "@babel/plugin-proposal-numeric-separator": ^7.18.6 - "@babel/plugin-proposal-object-rest-spread": ^7.20.7 - "@babel/plugin-proposal-optional-catch-binding": ^7.18.6 - "@babel/plugin-proposal-optional-chaining": ^7.21.0 - "@babel/plugin-proposal-private-methods": ^7.18.6 + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": ^7.22.0 "@babel/plugin-proposal-private-property-in-object": ^7.21.0 - "@babel/plugin-proposal-unicode-property-regex": ^7.18.6 "@babel/plugin-syntax-async-generators": ^7.8.4 "@babel/plugin-syntax-class-properties": ^7.12.13 "@babel/plugin-syntax-class-static-block": ^7.14.5 "@babel/plugin-syntax-dynamic-import": ^7.8.3 "@babel/plugin-syntax-export-namespace-from": ^7.8.3 "@babel/plugin-syntax-import-assertions": ^7.20.0 + "@babel/plugin-syntax-import-attributes": ^7.22.0 "@babel/plugin-syntax-import-meta": ^7.10.4 "@babel/plugin-syntax-json-strings": ^7.8.3 "@babel/plugin-syntax-logical-assignment-operators": ^7.10.4 @@ -1328,28 +1548,43 @@ __metadata: "@babel/plugin-syntax-optional-chaining": ^7.8.3 "@babel/plugin-syntax-private-property-in-object": ^7.14.5 "@babel/plugin-syntax-top-level-await": ^7.14.5 + "@babel/plugin-syntax-unicode-sets-regex": ^7.18.6 "@babel/plugin-transform-arrow-functions": ^7.21.5 + "@babel/plugin-transform-async-generator-functions": ^7.22.0 "@babel/plugin-transform-async-to-generator": ^7.20.7 "@babel/plugin-transform-block-scoped-functions": ^7.18.6 "@babel/plugin-transform-block-scoping": ^7.21.0 + "@babel/plugin-transform-class-properties": ^7.22.0 + "@babel/plugin-transform-class-static-block": ^7.22.0 "@babel/plugin-transform-classes": ^7.21.0 "@babel/plugin-transform-computed-properties": ^7.21.5 "@babel/plugin-transform-destructuring": ^7.21.3 "@babel/plugin-transform-dotall-regex": ^7.18.6 "@babel/plugin-transform-duplicate-keys": ^7.18.9 + "@babel/plugin-transform-dynamic-import": ^7.22.1 "@babel/plugin-transform-exponentiation-operator": ^7.18.6 + "@babel/plugin-transform-export-namespace-from": ^7.22.0 "@babel/plugin-transform-for-of": ^7.21.5 "@babel/plugin-transform-function-name": ^7.18.9 + "@babel/plugin-transform-json-strings": ^7.22.0 "@babel/plugin-transform-literals": ^7.18.9 + "@babel/plugin-transform-logical-assignment-operators": ^7.22.0 "@babel/plugin-transform-member-expression-literals": ^7.18.6 "@babel/plugin-transform-modules-amd": ^7.20.11 "@babel/plugin-transform-modules-commonjs": ^7.21.5 - "@babel/plugin-transform-modules-systemjs": ^7.20.11 + "@babel/plugin-transform-modules-systemjs": ^7.22.0 "@babel/plugin-transform-modules-umd": ^7.18.6 - "@babel/plugin-transform-named-capturing-groups-regex": ^7.20.5 - "@babel/plugin-transform-new-target": ^7.18.6 + "@babel/plugin-transform-named-capturing-groups-regex": ^7.22.0 + "@babel/plugin-transform-new-target": ^7.22.0 + "@babel/plugin-transform-nullish-coalescing-operator": ^7.22.0 + "@babel/plugin-transform-numeric-separator": ^7.22.0 + "@babel/plugin-transform-object-rest-spread": ^7.22.0 "@babel/plugin-transform-object-super": ^7.18.6 - "@babel/plugin-transform-parameters": ^7.21.3 + "@babel/plugin-transform-optional-catch-binding": ^7.22.0 + "@babel/plugin-transform-optional-chaining": ^7.22.0 + "@babel/plugin-transform-parameters": ^7.22.0 + "@babel/plugin-transform-private-methods": ^7.22.0 + "@babel/plugin-transform-private-property-in-object": ^7.22.0 "@babel/plugin-transform-property-literals": ^7.18.6 "@babel/plugin-transform-regenerator": ^7.21.5 "@babel/plugin-transform-reserved-words": ^7.18.6 @@ -1359,17 +1594,19 @@ __metadata: "@babel/plugin-transform-template-literals": ^7.18.9 "@babel/plugin-transform-typeof-symbol": ^7.18.9 "@babel/plugin-transform-unicode-escapes": ^7.21.5 + "@babel/plugin-transform-unicode-property-regex": ^7.22.0 "@babel/plugin-transform-unicode-regex": ^7.18.6 + "@babel/plugin-transform-unicode-sets-regex": ^7.22.0 "@babel/preset-modules": ^0.1.5 - "@babel/types": ^7.21.5 - babel-plugin-polyfill-corejs2: ^0.3.3 - babel-plugin-polyfill-corejs3: ^0.6.0 - babel-plugin-polyfill-regenerator: ^0.4.1 - core-js-compat: ^3.25.1 + "@babel/types": ^7.22.0 + babel-plugin-polyfill-corejs2: ^0.4.1 + babel-plugin-polyfill-corejs3: ^0.8.1 + babel-plugin-polyfill-regenerator: ^0.5.0 + core-js-compat: ^3.30.2 semver: ^6.3.0 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 86e167f3a351c89f8cd1409262481ece6ddc085b76147e801530ce29d60b1cfda8b264b1efd1ae27b8181b073a923c7161f21e2ebc0a41d652d717b10cf1c829 + checksum: bd227a25ec2f4ea3a62a80118c0c1497f213c1407fc115a5f2b441ddc30c0076f16a4251da8f5a77bc6e8c5805bf51ab826340b671f36177f5d696c5e87abc0c languageName: node linkType: hard @@ -1388,19 +1625,19 @@ __metadata: languageName: node linkType: hard -"@babel/preset-react@npm:7.18.6": - version: 7.18.6 - resolution: "@babel/preset-react@npm:7.18.6" +"@babel/preset-react@npm:7.22.0": + version: 7.22.0 + resolution: "@babel/preset-react@npm:7.22.0" dependencies: - "@babel/helper-plugin-utils": ^7.18.6 - "@babel/helper-validator-option": ^7.18.6 + "@babel/helper-plugin-utils": ^7.21.5 + "@babel/helper-validator-option": ^7.21.0 "@babel/plugin-transform-react-display-name": ^7.18.6 - "@babel/plugin-transform-react-jsx": ^7.18.6 + "@babel/plugin-transform-react-jsx": ^7.22.0 "@babel/plugin-transform-react-jsx-development": ^7.18.6 "@babel/plugin-transform-react-pure-annotations": ^7.18.6 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 540d9cf0a0cc0bb07e6879994e6fb7152f87dafbac880b56b65e2f528134c7ba33e0cd140b58700c77b2ebf4c81fa6468fed0ba391462d75efc7f8c1699bb4c3 + checksum: dbedf4cb365e3d40348c7ae8eeed393cf5e4faddeb7e6e88bbb2266f0eb7c170e49aabf372c9af360dfd9bc80aa0d28d65f6c28e0306a022fa9adc6ce6f3e717 languageName: node linkType: hard @@ -1426,7 +1663,16 @@ __metadata: languageName: node linkType: hard -"@babel/runtime@npm:7.21.5, @babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.12.0, @babel/runtime@npm:^7.12.13, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.2.0, @babel/runtime@npm:^7.20.1, @babel/runtime@npm:^7.21.0, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.7.6, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.8.7, @babel/runtime@npm:^7.9.2": +"@babel/runtime@npm:7.22.0": + version: 7.22.0 + resolution: "@babel/runtime@npm:7.22.0" + dependencies: + regenerator-runtime: ^0.13.11 + checksum: fa60a963f33de98baf55179b8b4b986d7ed4b97ec4f725e976fd3ecd6f3005096d9df4ef3cd4a6ce46105d619c7cb086567bcf272e4596a63e66ef9b36463bcb + languageName: node + linkType: hard + +"@babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.12.0, @babel/runtime@npm:^7.12.13, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.2.0, @babel/runtime@npm:^7.20.1, @babel/runtime@npm:^7.21.0, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.7.6, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.8.7, @babel/runtime@npm:^7.9.2": version: 7.21.5 resolution: "@babel/runtime@npm:7.21.5" dependencies: @@ -1435,7 +1681,7 @@ __metadata: languageName: node linkType: hard -"@babel/template@npm:^7.18.10, @babel/template@npm:^7.20.7, @babel/template@npm:^7.3.3": +"@babel/template@npm:^7.18.10, @babel/template@npm:^7.20.7, @babel/template@npm:^7.21.9, @babel/template@npm:^7.3.3": version: 7.21.9 resolution: "@babel/template@npm:7.21.9" dependencies: @@ -1464,6 +1710,42 @@ __metadata: languageName: node linkType: hard +"@babel/traverse@npm:^7.22.0": + version: 7.22.0 + resolution: "@babel/traverse@npm:7.22.0" + dependencies: + "@babel/code-frame": ^7.21.4 + "@babel/generator": ^7.22.0 + "@babel/helper-environment-visitor": ^7.21.5 + "@babel/helper-function-name": ^7.21.0 + "@babel/helper-hoist-variables": ^7.18.6 + "@babel/helper-split-export-declaration": ^7.18.6 + "@babel/parser": ^7.22.0 + "@babel/types": ^7.22.0 + debug: ^4.1.0 + globals: ^11.1.0 + checksum: 4c36bda5347d45fd8d0ca85f92e5f42c94e2acbeaf01174159ee3d70a6f7e135e4d4777c9a51ac3e36f7e6ddbc9b313eae097a35cc6f136ac53987070d5d4c88 + languageName: node + linkType: hard + +"@babel/traverse@npm:^7.22.1": + version: 7.22.1 + resolution: "@babel/traverse@npm:7.22.1" + dependencies: + "@babel/code-frame": ^7.21.4 + "@babel/generator": ^7.22.0 + "@babel/helper-environment-visitor": ^7.22.1 + "@babel/helper-function-name": ^7.21.0 + "@babel/helper-hoist-variables": ^7.18.6 + "@babel/helper-split-export-declaration": ^7.18.6 + "@babel/parser": ^7.22.0 + "@babel/types": ^7.22.0 + debug: ^4.1.0 + globals: ^11.1.0 + checksum: 5761837f9ce9b6ec2fe851ce76c6048d4fc11fc5be13218b7492849e42497ea957dafd2b84ab673aaabf31ac26ddc79c298d2a0fcff79ebdfc5c204cb35071a1 + languageName: node + linkType: hard + "@babel/types@npm:^7.0.0, @babel/types@npm:^7.18.6, @babel/types@npm:^7.18.9, @babel/types@npm:^7.20.0, @babel/types@npm:^7.20.5, @babel/types@npm:^7.20.7, @babel/types@npm:^7.21.0, @babel/types@npm:^7.21.4, @babel/types@npm:^7.21.5, @babel/types@npm:^7.3.0, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4, @babel/types@npm:^7.8.3": version: 7.21.5 resolution: "@babel/types@npm:7.21.5" @@ -1475,6 +1757,17 @@ __metadata: languageName: node linkType: hard +"@babel/types@npm:^7.22.0": + version: 7.22.0 + resolution: "@babel/types@npm:7.22.0" + dependencies: + "@babel/helper-string-parser": ^7.21.5 + "@babel/helper-validator-identifier": ^7.19.1 + to-fast-properties: ^2.0.0 + checksum: 6ba43536f362170d1be58aa8f975210fc042729128e9db286c7a107a1ca3e096994ad741e1cda85b2ae10d02e363d189f826ceee6178a884cc638935c99e2003 + languageName: node + linkType: hard + "@bcoe/v8-coverage@npm:^0.2.3": version: 0.2.3 resolution: "@bcoe/v8-coverage@npm:0.2.3" @@ -1987,13 +2280,13 @@ __metadata: languageName: node linkType: hard -"@fastify/cors@npm:8.2.1": - version: 8.2.1 - resolution: "@fastify/cors@npm:8.2.1" +"@fastify/cors@npm:8.3.0": + version: 8.3.0 + resolution: "@fastify/cors@npm:8.3.0" dependencies: fastify-plugin: ^4.0.0 mnemonist: 0.39.5 - checksum: 219edf11ad8397c7c00ac605c2c084f7dd929a13d95255013612275d195971bd23de1a8cf23304ded8bbe0066e2ea3c7f3c5b7ee0b14af2daed2071f0ed5609a + checksum: f487b5a8823264c3db58e99df020e38ada524514d60f2c5c2e01b994519545e2fc9481006d98e485b40e536b9b89f72af9061d9377b8e93f6ce07b14d40164a2 languageName: node linkType: hard @@ -2025,10 +2318,10 @@ __metadata: resolution: "@finos/babel-preset-legend-studio@workspace:packages/babel-preset" dependencies: "@babel/helper-plugin-utils": 7.21.5 - "@babel/preset-env": 7.21.5 - "@babel/preset-react": 7.18.6 + "@babel/preset-env": 7.22.1 + "@babel/preset-react": 7.22.0 "@babel/preset-typescript": 7.21.5 - "@babel/runtime": 7.21.5 + "@babel/runtime": 7.22.0 cross-env: 7.0.3 eslint: 8.41.0 react-refresh: 0.14.0 @@ -2043,7 +2336,7 @@ __metadata: version: 0.0.0-use.local resolution: "@finos/eslint-plugin-legend-studio@workspace:packages/eslint-plugin" dependencies: - "@babel/core": 7.21.8 + "@babel/core": 7.22.1 "@babel/eslint-parser": 7.21.8 "@typescript-eslint/eslint-plugin": 5.59.7 "@typescript-eslint/parser": 5.59.7 @@ -2077,7 +2370,7 @@ __metadata: npm-run-all: 4.1.5 rimraf: 5.0.1 typescript: 5.0.4 - webpack: 5.84.0 + webpack: 5.84.1 webpack-bundle-analyzer: 4.8.0 webpack-cli: 5.1.1 webpack-dev-server: 4.15.0 @@ -2160,7 +2453,7 @@ __metadata: npm-run-all: 4.1.5 rimraf: 5.0.1 typescript: 5.0.4 - webpack: 5.84.0 + webpack: 5.84.1 webpack-bundle-analyzer: 4.8.0 webpack-cli: 5.1.1 webpack-dev-server: 4.15.0 @@ -2245,7 +2538,7 @@ __metadata: npm-run-all: 4.1.5 rimraf: 5.0.1 typescript: 5.0.4 - webpack: 5.84.0 + webpack: 5.84.1 webpack-bundle-analyzer: 4.8.0 webpack-cli: 5.1.1 webpack-dev-server: 4.15.0 @@ -2287,7 +2580,7 @@ __metadata: sass: 1.62.1 serializr: 3.0.2 typescript: 5.0.4 - yaml: 2.3.0 + yaml: 2.3.1 peerDependencies: react: ^18.0.0 languageName: unknown @@ -2330,7 +2623,7 @@ __metadata: npm-run-all: 4.1.5 rimraf: 5.0.1 typescript: 5.0.4 - webpack: 5.84.0 + webpack: 5.84.1 webpack-bundle-analyzer: 4.8.0 webpack-cli: 5.1.1 webpack-dev-server: 4.15.0 @@ -2458,7 +2751,7 @@ __metadata: version: 0.0.0-use.local resolution: "@finos/legend-dev-utils@workspace:packages/legend-dev-utils" dependencies: - "@babel/core": 7.21.8 + "@babel/core": 7.22.1 "@changesets/assemble-release-plan": 5.2.3 "@changesets/changelog-github": 0.4.8 "@changesets/config": 2.3.0 @@ -2494,14 +2787,14 @@ __metadata: monaco-editor: 0.38.0 monaco-editor-webpack-plugin: 7.0.1 postcss: 8.4.23 - postcss-loader: 7.3.0 + postcss-loader: 7.3.1 react-refresh: 0.14.0 resolve: 1.22.2 rimraf: 5.0.1 sass: 1.62.1 sass-loader: 13.3.0 typescript: 5.0.4 - webpack: 5.84.0 + webpack: 5.84.1 languageName: unknown linkType: soft @@ -2874,7 +3167,7 @@ __metadata: version: 0.0.0-use.local resolution: "@finos/legend-fixture-mock-server@workspace:fixtures/legend-mock-server" dependencies: - "@fastify/cors": 8.2.1 + "@fastify/cors": 8.3.0 "@finos/legend-dev-utils": "workspace:*" cross-env: 7.0.3 eslint: 8.41.0 @@ -4352,13 +4645,20 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:*, @types/node@npm:20.2.3": +"@types/node@npm:*": version: 20.2.3 resolution: "@types/node@npm:20.2.3" checksum: 576065e8fc1fa45798c8f59a6bf809169582d04abc2e25fab1a048ffc734975b9992ae31be0d960cf705a21fb37112f7fcde11aa322beddf7491e73d5a5a988c languageName: node linkType: hard +"@types/node@npm:20.2.4": + version: 20.2.4 + resolution: "@types/node@npm:20.2.4" + checksum: 6bc45fdc1c1c0c0e03ca9aded926a5ce0f5e8154ae476a996f22832c530a8c909cfa2979b0b08c506477e836910f8b888bbe6eb9ebb698c4cd6f1f602456a9d4 + languageName: node + linkType: hard + "@types/node@npm:^12.7.1": version: 12.20.55 resolution: "@types/node@npm:12.20.55" @@ -5530,39 +5830,39 @@ __metadata: languageName: node linkType: hard -"babel-plugin-polyfill-corejs2@npm:^0.3.3": - version: 0.3.3 - resolution: "babel-plugin-polyfill-corejs2@npm:0.3.3" +"babel-plugin-polyfill-corejs2@npm:^0.4.1": + version: 0.4.1 + resolution: "babel-plugin-polyfill-corejs2@npm:0.4.1" dependencies: "@babel/compat-data": ^7.17.7 - "@babel/helper-define-polyfill-provider": ^0.3.3 + "@babel/helper-define-polyfill-provider": ^0.4.0 semver: ^6.1.1 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 7db3044993f3dddb3cc3d407bc82e640964a3bfe22de05d90e1f8f7a5cb71460011ab136d3c03c6c1ba428359ebf635688cd6205e28d0469bba221985f5c6179 + checksum: f2b9bfec71914899b6e028441db565e1a2f2bc8208738c0fd7093e36fa6232cb803577751a745a0a30484928fcff65b3dad2c124bf9d956c3de19c26a1355a5e languageName: node linkType: hard -"babel-plugin-polyfill-corejs3@npm:^0.6.0": - version: 0.6.0 - resolution: "babel-plugin-polyfill-corejs3@npm:0.6.0" +"babel-plugin-polyfill-corejs3@npm:^0.8.1": + version: 0.8.1 + resolution: "babel-plugin-polyfill-corejs3@npm:0.8.1" dependencies: - "@babel/helper-define-polyfill-provider": ^0.3.3 - core-js-compat: ^3.25.1 + "@babel/helper-define-polyfill-provider": ^0.4.0 + core-js-compat: ^3.30.1 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 470bb8c59f7c0912bd77fe1b5a2e72f349b3f65bbdee1d60d6eb7e1f4a085c6f24b2dd5ab4ac6c2df6444a96b070ef6790eccc9edb6a2668c60d33133bfb62c6 + checksum: c23a581973c141a4687126cf964981180ef27e3eb0b34b911161db4f5caf9ba7ff60bee0ebe46d650ba09e03a6a3ac2cd6a6ae5f4f5363a148470e5cd8447df2 languageName: node linkType: hard -"babel-plugin-polyfill-regenerator@npm:^0.4.1": - version: 0.4.1 - resolution: "babel-plugin-polyfill-regenerator@npm:0.4.1" +"babel-plugin-polyfill-regenerator@npm:^0.5.0": + version: 0.5.0 + resolution: "babel-plugin-polyfill-regenerator@npm:0.5.0" dependencies: - "@babel/helper-define-polyfill-provider": ^0.3.3 + "@babel/helper-define-polyfill-provider": ^0.4.0 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: ab0355efbad17d29492503230387679dfb780b63b25408990d2e4cf421012dae61d6199ddc309f4d2409ce4e9d3002d187702700dd8f4f8770ebbba651ed066c + checksum: ef2bcffc7c9a5e4426fc2dbf89bf3a46999a8415c21cd741c3ab3cb4b5ab804aaa3d71ef733f0eda1bcc0b91d9d80f98d33983a66dab9b8bed166ec38f8f8ad1 languageName: node linkType: hard @@ -6397,7 +6697,7 @@ __metadata: languageName: node linkType: hard -"core-js-compat@npm:^3.25.1": +"core-js-compat@npm:^3.30.1, core-js-compat@npm:^3.30.2": version: 3.30.2 resolution: "core-js-compat@npm:3.30.2" dependencies: @@ -10513,13 +10813,13 @@ __metadata: dependencies: "@actions/core": 1.10.0 "@actions/github": 5.1.1 - "@babel/core": 7.21.8 + "@babel/core": 7.22.1 "@changesets/cli": 2.26.1 "@finos/babel-preset-legend-studio": "workspace:*" "@finos/eslint-plugin-legend-studio": "workspace:*" "@finos/legend-dev-utils": "workspace:*" "@finos/stylelint-config-legend-studio": "workspace:*" - "@types/node": 20.2.3 + "@types/node": 20.2.4 chalk: 5.2.0 cross-env: 7.0.3 envinfo: 7.8.1 @@ -12897,9 +13197,9 @@ __metadata: languageName: node linkType: hard -"postcss-loader@npm:7.3.0": - version: 7.3.0 - resolution: "postcss-loader@npm:7.3.0" +"postcss-loader@npm:7.3.1": + version: 7.3.1 + resolution: "postcss-loader@npm:7.3.1" dependencies: cosmiconfig: ^8.1.3 jiti: ^1.18.2 @@ -12908,7 +13208,7 @@ __metadata: peerDependencies: postcss: ^7.0.0 || ^8.0.1 webpack: ^5.0.0 - checksum: f09fe68bde5f686c264cc96c51bcdc0be00c55e856d73161ce86b302fdd503098fe5c9172231eb3b316a1969080101a4c46463bda784b408d4a4cb15e7b01fc5 + checksum: a8e0b8a078f309b1e90d0f947190ea24659c7ea2b922389b773c4983b116dfdf0a87b915e4c7477c7db99a5014c34d41cc1975b37075772ea2e6da3d0bbc0ca6 languageName: node linkType: hard @@ -16453,9 +16753,9 @@ __metadata: languageName: node linkType: hard -"webpack@npm:5.84.0": - version: 5.84.0 - resolution: "webpack@npm:5.84.0" +"webpack@npm:5.84.1": + version: 5.84.1 + resolution: "webpack@npm:5.84.1" dependencies: "@types/eslint-scope": ^3.7.3 "@types/estree": ^1.0.0 @@ -16486,7 +16786,7 @@ __metadata: optional: true bin: webpack: bin/webpack.js - checksum: 5837983d81d55edf621317f23de3a7ae49bbf24c9f8605beeba35ea62be5cc4b3b63ace0ec9785912b9ffe70fd969e613597fae21b2334a3913054c41189ef75 + checksum: 646b645df5badf2dac2ddd0193c9e9a177d51283d18f918eead36a0cdf7b750c4111d9ac11d9825c1334cbd0a6fb8f82628fbfb90d0066f927265dd11b47b192 languageName: node linkType: hard @@ -16836,10 +17136,10 @@ __metadata: languageName: node linkType: hard -"yaml@npm:2.3.0": - version: 2.3.0 - resolution: "yaml@npm:2.3.0" - checksum: 9c3d16c226472041fbdc9fb55e1645786d3a3e8d4fde67a502ed7bfbd9067b811e466679db590a0731b4405d4a3bef1f35d098fb650d2cf4bc24732fc829b961 +"yaml@npm:2.3.1": + version: 2.3.1 + resolution: "yaml@npm:2.3.1" + checksum: 2c7bc9a7cd4c9f40d3b0b0a98e370781b68b8b7c4515720869aced2b00d92f5da1762b4ffa947f9e795d6cd6b19f410bd4d15fdd38aca7bd96df59bd9486fb54 languageName: node linkType: hard