diff --git a/.changeset/brave-monkeys-remain.md b/.changeset/brave-monkeys-remain.md
new file mode 100644
index 0000000000..4ef777352b
--- /dev/null
+++ b/.changeset/brave-monkeys-remain.md
@@ -0,0 +1,29 @@
+---
+'@finos/legend-extension-dsl-data-space-studio': patch
+'@finos/legend-extension-store-service-store': patch
+'@finos/legend-vscode-extension-dependencies': patch
+'@finos/legend-application-repl-deployment': patch
+'@finos/legend-extension-store-relational': patch
+'@finos/legend-server-showcase-deployment': patch
+'@finos/legend-extension-dsl-persistence': patch
+'@finos/legend-extension-store-flat-data': patch
+'@finos/legend-extension-dsl-data-space': patch
+'@finos/legend-extension-dsl-diagram': patch
+'@finos/legend-extension-dsl-service': patch
+'@finos/legend-application-pure-ide': patch
+'@finos/legend-extension-assortment': patch
+'@finos/legend-application-studio': patch
+'@finos/legend-extension-dsl-text': patch
+'@finos/legend-application-query': patch
+'@finos/legend-application-repl': patch
+'@finos/legend-server-showcase': patch
+'@finos/legend-query-builder': patch
+'@finos/legend-application': patch
+'@finos/legend-server-sdlc': patch
+'@finos/legend-dev-utils': patch
+'@finos/stylelint-config-legend-studio': patch
+'@finos/legend-shared': patch
+'@finos/legend-graph': patch
+'@finos/legend-lego': patch
+'@finos/legend-art': patch
+---
diff --git a/.changeset/cool-mayflies-warn.md b/.changeset/cool-mayflies-warn.md
new file mode 100644
index 0000000000..740ef399f4
--- /dev/null
+++ b/.changeset/cool-mayflies-warn.md
@@ -0,0 +1,17 @@
+---
+'@finos/legend-extension-store-service-store': patch
+'@finos/legend-application-repl-deployment': patch
+'@finos/legend-extension-dsl-data-space': patch
+'@finos/legend-extension-dsl-diagram': patch
+'@finos/legend-application-pure-ide': patch
+'@finos/legend-application-studio': patch
+'@finos/legend-extension-dsl-text': patch
+'@finos/legend-application-query': patch
+'@finos/legend-application-repl': patch
+'@finos/legend-query-builder': patch
+'@finos/legend-dev-utils': patch
+'@finos/stylelint-config-legend-studio': patch
+'@finos/legend-shared': patch
+'@finos/legend-lego': patch
+'@finos/legend-art': patch
+---
diff --git a/.changeset/grumpy-pens-hear.md b/.changeset/grumpy-pens-hear.md
new file mode 100644
index 0000000000..2d3b153f59
--- /dev/null
+++ b/.changeset/grumpy-pens-hear.md
@@ -0,0 +1,4 @@
+---
+'@finos/legend-application-repl': patch
+'@finos/legend-art': patch
+---
diff --git a/.changeset/poor-ligers-teach.md b/.changeset/poor-ligers-teach.md
new file mode 100644
index 0000000000..e5c1944636
--- /dev/null
+++ b/.changeset/poor-ligers-teach.md
@@ -0,0 +1,8 @@
+---
+'@finos/legend-application-repl-deployment': patch
+'@finos/legend-application-repl': patch
+'@finos/legend-query-builder': patch
+'@finos/legend-dev-utils': patch
+'@finos/legend-shared': patch
+'@finos/legend-art': patch
+---
diff --git a/.changeset/short-keys-flash.md b/.changeset/short-keys-flash.md
new file mode 100644
index 0000000000..bd9a24ee65
--- /dev/null
+++ b/.changeset/short-keys-flash.md
@@ -0,0 +1,5 @@
+---
+'@finos/legend-application-repl-deployment': patch
+'@finos/legend-application-repl': patch
+'@finos/legend-art': patch
+---
diff --git a/.vscode/copyright.code-snippets b/.vscode/copyright.code-snippets
new file mode 100644
index 0000000000..7dbec1c5a0
--- /dev/null
+++ b/.vscode/copyright.code-snippets
@@ -0,0 +1,7 @@
+{
+ "Print to console": {
+ "prefix": ["copyright"],
+ "body": ["/**\n * Copyright (c) 2020-present, Goldman Sachs\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n"],
+ "description": "Add copyright header",
+ },
+}
diff --git a/fixtures/legend-mock-server/package.json b/fixtures/legend-mock-server/package.json
index 08d32e1c30..8983c50a74 100644
--- a/fixtures/legend-mock-server/package.json
+++ b/fixtures/legend-mock-server/package.json
@@ -27,7 +27,7 @@
},
"dependencies": {
"@fastify/cors": "9.0.1",
- "fastify": "4.28.0"
+ "fastify": "4.28.1"
},
"devDependencies": {
"@finos/legend-dev-utils": "workspace:*",
diff --git a/package.json b/package.json
index 049973b0c4..d0b5cdad0a 100644
--- a/package.json
+++ b/package.json
@@ -43,6 +43,7 @@
"fix:format": "prettier --write --loglevel=warn \"(scripts|docs)/**/*.{md,json,mjs,cjs,js,ts,tsx,html,scss,css}\" \"packages/*/**/*.{md,json,mjs,cjs,js,ts,tsx,html,scss,css}\" && yarn sort-package-json \"package.json\" \"packages/*/package.json\"",
"fix:js": "cross-env NODE_ENV=production FORCE_COLOR=1 eslint --cache --cache-location ./build/.eslintcache \"scripts/**/*.{mjs,cjs,js,ts,tsx}\" --report-unused-disable-directives --fix && cross-env FORCE_COLOR=1 yarn workspaces foreach --all --parallel --exclude legend-studio -vv run lint:js --fix",
"fix:style": "yarn lint:style --fix",
+ "fix:watchman": "node ./scripts/test/fixWatchman.js",
"git:install-hooks": "husky install",
"git:pre-commit": "lint-staged --config ./package.json",
"git:upstream:setup": "git remote add upstream https://github.com/finos/legend-studio.git",
@@ -99,14 +100,14 @@
"@finos/eslint-plugin-legend-studio": "workspace:*",
"@finos/legend-dev-utils": "workspace:*",
"@finos/stylelint-config-legend-studio": "workspace:*",
- "@types/node": "20.14.8",
+ "@types/node": "20.14.9",
"chalk": "5.3.0",
"cross-env": "7.0.3",
"envinfo": "7.13.0",
"eslint": "8.57.0",
"fs-extra": "11.2.0",
"husky": "9.0.11",
- "inquirer": "9.2.23",
+ "inquirer": "9.3.2",
"jest": "29.7.0",
"lint-staged": "15.2.7",
"micromatch": "4.0.7",
@@ -118,7 +119,7 @@
"semver": "7.6.2",
"sort-package-json": "2.10.0",
"stylelint": "16.6.1",
- "typedoc": "0.26.2",
+ "typedoc": "0.26.3",
"typescript": "5.5.2",
"yargs": "17.7.2"
},
diff --git a/packages/legend-application-pure-ide/package.json b/packages/legend-application-pure-ide/package.json
index bf24165519..9cd90f9b61 100644
--- a/packages/legend-application-pure-ide/package.json
+++ b/packages/legend-application-pure-ide/package.json
@@ -51,7 +51,7 @@
"@finos/legend-shared": "workspace:*",
"@types/react": "18.3.3",
"@types/react-dom": "18.3.0",
- "mobx": "6.12.4",
+ "mobx": "6.12.5",
"mobx-react-lite": "4.0.7",
"monaco-editor": "0.50.0",
"react": "18.3.1",
diff --git a/packages/legend-application-pure-ide/src/components/editor-group/DiagramEditor.tsx b/packages/legend-application-pure-ide/src/components/editor-group/DiagramEditor.tsx
index de7909fa32..91483f9e40 100644
--- a/packages/legend-application-pure-ide/src/components/editor-group/DiagramEditor.tsx
+++ b/packages/legend-application-pure-ide/src/components/editor-group/DiagramEditor.tsx
@@ -41,7 +41,7 @@ import {
clsx,
DistributeHorizontalIcon,
DistributeVerticalIcon,
- DropdownMenu,
+ ControlledDropdownMenu,
GoToFileIcon,
MenuContent,
MenuContentDivider,
@@ -276,7 +276,7 @@ const DiagramEditorHeader = observer(
-
-
+
-
-
+
);
}
diff --git a/packages/legend-application-query/src/components/QueryEditor.tsx b/packages/legend-application-query/src/components/QueryEditor.tsx
index dd3d4f244b..f521ae9dac 100644
--- a/packages/legend-application-query/src/components/QueryEditor.tsx
+++ b/packages/legend-application-query/src/components/QueryEditor.tsx
@@ -18,7 +18,7 @@ import {
Dialog,
PanelLoadingIndicator,
BlankPanelContent,
- DropdownMenu,
+ ControlledDropdownMenu,
MenuContent,
MenuContentItem,
MenuIcon,
@@ -622,7 +622,7 @@ export const QueryEditor = observer(() => {
- {
}
>
-
+
Legend Query
diff --git a/packages/legend-application-query/src/components/QuerySetup.tsx b/packages/legend-application-query/src/components/QuerySetup.tsx
index 0953de8378..76cf3d9197 100644
--- a/packages/legend-application-query/src/components/QuerySetup.tsx
+++ b/packages/legend-application-query/src/components/QuerySetup.tsx
@@ -20,7 +20,7 @@ import {
QuestionCircleIcon,
CogIcon,
MoreHorizontalIcon,
- DropdownMenu,
+ ControlledDropdownMenu,
PencilIcon,
ThinChevronDownIcon,
CircleIcon,
@@ -214,7 +214,7 @@ const QuerySetupActionGroup = observer(
)}
{(!tag || setupStore.tagToFocus === tag) && (
- }
@@ -229,7 +229,7 @@ const QuerySetupActionGroup = observer(
)}
-
+
)}
diff --git a/packages/legend-application-repl-deployment/repl.config.js b/packages/legend-application-repl-deployment/repl.config.js
index d489951ded..febd292998 100644
--- a/packages/legend-application-repl-deployment/repl.config.js
+++ b/packages/legend-application-repl-deployment/repl.config.js
@@ -29,11 +29,11 @@ export default {
*/
baseUrl: '/repl/',
/**
- * `isRelativePathSupported` [boolean, optional]
+ * `useRelativePath` [boolean, optional]
* Boolean flag to check if your website supports resolution of relative
* paths for resources
*/
- isRelativePathSupported: true,
+ useRelativePath: true,
/**
* `devServerOptions` [object, optional]
* Options to override `webpack-dev-server` configs.
diff --git a/packages/legend-application-repl-deployment/src/index.html b/packages/legend-application-repl-deployment/src/index.html
index 311f144f2f..4885d86929 100644
--- a/packages/legend-application-repl-deployment/src/index.html
+++ b/packages/legend-application-repl-deployment/src/index.html
@@ -1,7 +1,7 @@
-
▦ Legend DataCube
+
⊞ Legend DataCube
{
const dataCubeStore = useREPLStore();
- const dataCubeState = dataCubeStore.dataCubeState;
+ const dataCube = dataCubeStore.dataCube;
return (
-
-
-
-
-
dataCubeState.editor.openPanel()}
- >
- Pivot
-
-
- Filter
-
+
+
+
+
+
+
dataCube.editor.openPanel()}
+ >
+
+ Properties
+
+
+
+
+
+ {dataCube.runningTaskes.size > 0 && (
+
+ )}
+
+
);
});
const DataCubeTitleBar = observer(() => {
const dataCubeStore = useREPLStore();
- const dataCubeState = dataCubeStore.dataCubeState;
+ const dataCube = dataCubeStore.dataCube;
return (
-
{dataCubeState.editor.generalPropertiesPanel.name}
+
{dataCube.core.name}
{/* TODO: @akphi - add save icon */}
@@ -63,11 +86,11 @@ export const DataCube = observer(() => {
const dataCubeStore = useREPLStore();
const ref = useRef
(null);
const applicationStore = useApplicationStore();
- const dataCubeState = dataCubeStore.dataCubeState;
+ const dataCube = dataCubeStore.dataCube;
useEffect(() => {
- dataCubeState.initialize().catch(applicationStore.logUnhandledError);
- }, [dataCubeState, applicationStore]);
+ dataCube.initialize().catch(applicationStore.logUnhandledError);
+ }, [dataCube, applicationStore]);
return (
{
- {dataCubeState.editor.isPanelOpen && (
-
- )}
+ {dataCube.editor.isPanelOpen && }
);
});
diff --git a/packages/legend-application-repl/src/components/dataCube/editor/DataCubeEditor.tsx b/packages/legend-application-repl/src/components/dataCube/editor/DataCubeEditor.tsx
index dc51a066f9..c506434616 100644
--- a/packages/legend-application-repl/src/components/dataCube/editor/DataCubeEditor.tsx
+++ b/packages/legend-application-repl/src/components/dataCube/editor/DataCubeEditor.tsx
@@ -28,6 +28,7 @@ import { DataCubeEditorFilterPanel } from './DataCubeEditorFilterPanel.js';
import { DataCubeEditorExtendedColumnsPanel } from './DataCubeEditorExtendedColumnsPanel.js';
import { DataCubeEditorCodePanel } from './DataCubeEditorCodePanel.js';
import { DataCubeEditorColumnPropertiesPanel } from './DataCubeEditorColumnPropertiesPanel.js';
+import { DataCubeEditorDeveloperPanel } from './DataCubeEditorDeveloperPanel.js';
const __DATA_CUBE_EDITOR_HEADER_CLASS_NAME = 'data-cube__editor__header';
const PANEL_DEFAULT_OFFSET = 50;
@@ -46,7 +47,7 @@ export const DataCubeEditor = observer(
height: PANEL_DEFAULT_HEIGHT,
});
const replStore = useREPLStore();
- const editor = replStore.dataCubeState.editor;
+ const editor = replStore.dataCube.editor;
const selectedTab = editor.currentTab;
const tabs = [
DATA_CUBE_EDITOR_TAB.COLUMNS,
@@ -58,6 +59,7 @@ export const DataCubeEditor = observer(
DATA_CUBE_EDITOR_TAB.GENERAL_PROPERTIES,
DATA_CUBE_EDITOR_TAB.COLUMN_PROPERTIES,
DATA_CUBE_EDITOR_TAB.CODE,
+ DATA_CUBE_EDITOR_TAB.DEVELOPER,
];
useEffect(() => {
@@ -204,6 +206,9 @@ export const DataCubeEditor = observer(
{selectedTab === DATA_CUBE_EDITOR_TAB.CODE && (
)}
+ {selectedTab === DATA_CUBE_EDITOR_TAB.DEVELOPER && (
+
+ )}
diff --git a/packages/legend-application-repl/src/components/dataCube/editor/DataCubeEditorCodePanel.tsx b/packages/legend-application-repl/src/components/dataCube/editor/DataCubeEditorCodePanel.tsx
index 71123ad46a..66607b384f 100644
--- a/packages/legend-application-repl/src/components/dataCube/editor/DataCubeEditorCodePanel.tsx
+++ b/packages/legend-application-repl/src/components/dataCube/editor/DataCubeEditorCodePanel.tsx
@@ -143,7 +143,7 @@ import { useREPLStore } from '../../REPLStoreProvider.js';
export const DataCubeEditorCodePanel = observer(() => {
const replStore = useREPLStore();
- const panel = replStore.dataCubeState.editor.sortsPanel;
+ const panel = replStore.dataCube.editor.sortsPanel;
// const executeLambda = (): void => {
// // TODO: @akphi
// // flowResult(dataCubeState.executeLambda()).catch(
@@ -154,7 +154,7 @@ export const DataCubeEditorCodePanel = observer(() => {
useEffect(() => {}, [panel]); // TODO: @akphi - remove this dummy useEffect
return (
-
+
diff --git a/packages/legend-application-repl/src/components/dataCube/editor/DataCubeEditorColumnPropertiesPanel.tsx b/packages/legend-application-repl/src/components/dataCube/editor/DataCubeEditorColumnPropertiesPanel.tsx
index 8da287a8c6..f3445de141 100644
--- a/packages/legend-application-repl/src/components/dataCube/editor/DataCubeEditorColumnPropertiesPanel.tsx
+++ b/packages/legend-application-repl/src/components/dataCube/editor/DataCubeEditorColumnPropertiesPanel.tsx
@@ -14,19 +14,78 @@
* limitations under the License.
*/
-import { DataCubeIcon } from '@finos/legend-art';
+import { cn, DataCubeIcon, useDropdownMenu } from '@finos/legend-art';
import { observer } from 'mobx-react-lite';
import { useREPLStore } from '../../REPLStoreProvider.js';
-import { useEffect } from 'react';
+import {
+ DataCubeEditorCheckbox,
+ DataCubeEditorColorPickerButton,
+ DataCubeEditorDropdownMenu,
+ DataCubeEditorDropdownMenuItem,
+ DataCubeEditorDropdownMenuItemSeparator,
+ DataCubeEditorDropdownMenuTrigger,
+ DataCubeEditorNumberInput,
+ DataCubeEditorTextInput,
+ WIP_Badge,
+} from './DataCubeEditorShared.js';
+import {
+ DataCubeAggregateFunction,
+ DataCubeColumnDataType,
+ DataCubeColumnPinPlacement,
+ DataCubeFont,
+ DataCubeFontFormatUnderlinedVariant,
+ DataCubeFontTextAlignment,
+ DataCubeNumberScale,
+ DEFAULT_BACKGROUND_COLOR,
+ DEFAULT_COLUMN_MAX_WIDTH,
+ DEFAULT_COLUMN_MIN_WIDTH,
+ DEFAULT_COLUMN_WIDTH,
+ DEFAULT_ERROR_FOREGROUND_COLOR,
+ DEFAULT_FOREGROUND_COLOR,
+ DEFAULT_NEGATIVE_FOREGROUND_COLOR,
+ DEFAULT_ZERO_FOREGROUND_COLOR,
+} from '../../../stores/dataCube/core/DataCubeQueryEngine.js';
export const DataCubeEditorColumnPropertiesPanel = observer(() => {
const replStore = useREPLStore();
- const panel = replStore.dataCubeState.editor.sortsPanel;
-
- useEffect(() => {}, [panel]); // TODO: @akphi - remove this dummy useEffect
+ const dataCube = replStore.dataCube;
+ const panel = dataCube.editor.columnPropertiesPanel;
+ const selectedColumn = panel.selectedColumn;
+ const [openColumnsDropdown, closeColumnsDropdown, columnsDropdownProps] =
+ useDropdownMenu();
+ const [
+ openAggregationTypeDropdown,
+ closeAggregationTypeDropdown,
+ aggregationTypeDropdownProps,
+ ] = useDropdownMenu();
+ const [
+ openNumberScaleDropdown,
+ closeNumberScaleDropdown,
+ numberScaleDropdownProps,
+ ] = useDropdownMenu();
+ const [
+ openFontFamilyDropdown,
+ closeFontFamilyDropdown,
+ fontFamilyDropdownProps,
+ ] = useDropdownMenu();
+ const [
+ openFontSizeDropdown,
+ closeFontSizeDropdown,
+ openFontSizeDropdownProps,
+ ] = useDropdownMenu();
+ const [
+ openFontFormatUnderlinedVariantDropdown,
+ closeFontFormatUnderlinedVariantDropdown,
+ fontFormatUnderlinedVariantDropdownProps,
+ ] = useDropdownMenu();
+ const [
+ openColumnPinDropdown,
+ closeColumnPinDropdown,
+ columnPinDropdownProps,
+ ] = useDropdownMenu();
return (
-
+
@@ -36,7 +95,778 @@ export const DataCubeEditorColumnPropertiesPanel = observer(() => {
Column Properties
-
+
+
+
+
+ Choose Column:
+
+
+ {selectedColumn?.name ?? '(None)'}
+
+
+ {panel.columns.map((column) => (
+ {
+ panel.setSelectedColumnName(column.name);
+ closeColumnsDropdown();
+ }}
+ >
+ {column.name}
+
+ ))}
+
+ {selectedColumn && (
+ // TODO: if this is an extended column, show the info and link it
+ // e.g. `Extended Column (Leaf)`, `Extended Column (Group)`
+ // with arrow button to go to the extended column editor
+ <>
+
+
+
+ {selectedColumn.dataType}
+
+
+ {selectedColumn.kind}
+
+
+ >
+ )}
+
+
+
+
+ {selectedColumn && (
+ <>
+
+
+ Display Name:
+
+
{
+ const value = event.target.value.trim();
+ selectedColumn.setDisplayName(
+ value !== '' ? value : undefined,
+ );
+ }}
+ />
+
+
+ {selectedColumn.dataType === DataCubeColumnDataType.NUMBER && (
+ <>
+
+
+ Number Format:
+
+
{
+ selectedColumn.setDecimals(value);
+ }}
+ />
+
+ Decimal places
+
+
+ selectedColumn.setDisplayCommas(
+ !selectedColumn.displayCommas,
+ )
+ }
+ />
+
+ selectedColumn.setNegativeNumberInParens(
+ !selectedColumn.negativeNumberInParens,
+ )
+ }
+ />
+
+
+
+
+ Number Scale:
+
+
+ {selectedColumn.numberScale ?? '(None)'}
+
+
+ {[
+ undefined,
+ DataCubeNumberScale.PERCENT,
+ DataCubeNumberScale.BASIS_POINT,
+ DataCubeNumberScale.THOUSANDS,
+ DataCubeNumberScale.MILLIONS,
+ DataCubeNumberScale.BILLIONS,
+ DataCubeNumberScale.AUTO,
+ ].map((scale) => (
+ {
+ selectedColumn.setNumberScale(scale);
+ closeNumberScaleDropdown();
+ }}
+ >
+ {scale ?? '(None)'}
+
+ ))}
+
+
+
+
+
+ Aggregation Type:
+
+
+ {selectedColumn.aggregateFunction ?? '(None)'}
+
+
+ {[
+ DataCubeAggregateFunction.SUM,
+ DataCubeAggregateFunction.AVERAGE,
+ DataCubeAggregateFunction.COUNT,
+ DataCubeAggregateFunction.MIN,
+ DataCubeAggregateFunction.MAX,
+ ].map((fn) => (
+ {
+ selectedColumn.setAggregateFunction(fn);
+ closeAggregationTypeDropdown();
+ }}
+ >
+ {fn}
+
+ ))}
+
+
+
+
+ Weight Column:
+
+
+ {selectedColumn.weightColumn ?? '(None)'}
+
+
+
+
+
+
+ Exclude from HPivot?
+
+
+ selectedColumn.setExcludedFromHPivot(
+ !selectedColumn.excludedFromHPivot,
+ )
+ }
+ disabled={true}
+ />
+
+
+ >
+ )}
+
+ {selectedColumn.dataType === DataCubeColumnDataType.TEXT && (
+ <>
+
+
+ Dislay as Link?
+
+
+ selectedColumn.setDisplayAsLink(
+ !selectedColumn.displayAsLink,
+ )
+ }
+ />
+
+ >
+ )}
+
+
+
+
+
+ Font:
+
+
+ {selectedColumn.fontFamily}
+
+
+ {[
+ DataCubeFont.ARIAL,
+ DataCubeFont.ROBOTO,
+ DataCubeFont.ROBOTO_CONDENSED,
+ ].map((font) => (
+ {
+ selectedColumn.setFontFamily(font);
+ closeFontFamilyDropdown();
+ }}
+ >
+ {font}
+
+ ))}
+
+ {[
+ DataCubeFont.GEORGIA,
+ DataCubeFont.ROBOTO_SERIF,
+ DataCubeFont.TIMES_NEW_ROMAN,
+ ].map((font) => (
+ {
+ selectedColumn.setFontFamily(font);
+ closeFontFamilyDropdown();
+ }}
+ >
+ {font}
+
+ ))}
+
+ {[
+ DataCubeFont.JERBRAINS_MONO,
+ DataCubeFont.ROBOTO_MONO,
+ DataCubeFont.UBUNTU_MONO,
+ ].map((font) => (
+ {
+ selectedColumn.setFontFamily(font);
+ closeFontFamilyDropdown();
+ }}
+ >
+ {font}
+
+ ))}
+
+
+
+ {selectedColumn.fontSize}
+
+
+ {[
+ 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 16, 18, 20, 22, 24, 26,
+ 28, 32, 36, 48, 72,
+ ].map((size) => (
+ {
+ selectedColumn.setFontSize(size);
+ closeFontSizeDropdown();
+ }}
+ >
+ {size}
+
+ ))}
+
+
+
+
+ selectedColumn.setFontBold(!selectedColumn.fontBold)
+ }
+ >
+
+
+
+ selectedColumn.setFontItalic(!selectedColumn.fontItalic)
+ }
+ >
+
+
+
+ selectedColumn.setFontUnderlined(
+ selectedColumn.fontUnderlined === undefined
+ ? DataCubeFontFormatUnderlinedVariant.SOLID
+ : undefined,
+ )
+ }
+ >
+
+
+
+
+
+
+ {[
+ DataCubeFontFormatUnderlinedVariant.SOLID,
+ DataCubeFontFormatUnderlinedVariant.DASHED,
+ DataCubeFontFormatUnderlinedVariant.DOTTED,
+ DataCubeFontFormatUnderlinedVariant.DOUBLE,
+ DataCubeFontFormatUnderlinedVariant.WAVY,
+ ].map((variant) => (
+ {
+ selectedColumn.setFontUnderlined(variant);
+ closeFontFormatUnderlinedVariantDropdown();
+ }}
+ >
+
+
+
+
+ ))}
+
+
+ selectedColumn.setFontStrikethrough(
+ !selectedColumn.fontStrikethrough,
+ )
+ }
+ >
+
+
+
+
+
+
+ selectedColumn.setTextAlign(
+ DataCubeFontTextAlignment.LEFT,
+ )
+ }
+ >
+
+
+
+ selectedColumn.setTextAlign(
+ DataCubeFontTextAlignment.CENTER,
+ )
+ }
+ >
+
+
+
+ selectedColumn.setTextAlign(
+ DataCubeFontTextAlignment.RIGHT,
+ )
+ }
+ >
+
+
+
+
+
+
+
+ Colors:
+
+
+
+
+
+ Normal
+
+
+ Negative
+
+
+ Zero
+
+
+ Error
+
+
+
+
+ Foreground:
+
+
+
+ selectedColumn.setForegroundColor(value)
+ }
+ />
+
+
+
+ selectedColumn.setForegroundNegativeColor(value)
+ }
+ />
+
+
+
+ selectedColumn.setForegroundZeroColor(value)
+ }
+ />
+
+
+
+ selectedColumn.setForegroundErrorColor(value)
+ }
+ />
+
+
+
+
+ Background:
+
+
+
+ selectedColumn.setBackgroundColor(value)
+ }
+ />
+
+
+
+ selectedColumn.setBackgroundNegativeColor(value)
+ }
+ />
+
+
+
+ selectedColumn.setBackgroundZeroColor(value)
+ }
+ />
+
+
+
+ selectedColumn.setBackgroundErrorColor(value)
+ }
+ />
+
+
+
+
+
+
+
+ Hide from View?
+
+
+ selectedColumn.setHideFromView(!selectedColumn.hideFromView)
+ }
+ disabled={true}
+ />
+
+
+
+
+
+ Pin:
+
+
+ {selectedColumn.pinned ?? '(None)'}
+
+
+ {[
+ undefined,
+ DataCubeColumnPinPlacement.LEFT,
+ DataCubeColumnPinPlacement.RIGHT,
+ ].map((placement) => (
+ {
+ selectedColumn.setPinned(placement);
+ closeColumnPinDropdown();
+ }}
+ >
+ {placement ?? '(None)'}
+
+ ))}
+
+
+
+
+
+ Width:
+
+
{
+ if (
+ selectedColumn.fixedWidth === undefined &&
+ selectedColumn.minWidth === undefined &&
+ selectedColumn.maxWidth === undefined
+ ) {
+ selectedColumn.setFixedWidth(DEFAULT_COLUMN_WIDTH);
+ selectedColumn.setMinWidth(undefined);
+ selectedColumn.setMaxWidth(undefined);
+ } else {
+ selectedColumn.setFixedWidth(undefined);
+ selectedColumn.setMinWidth(undefined);
+ selectedColumn.setMaxWidth(undefined);
+ }
+ }}
+ />
+
+ {
+ selectedColumn.setFixedWidth(
+ selectedColumn.fixedWidth !== undefined
+ ? undefined
+ : DEFAULT_COLUMN_WIDTH,
+ );
+ selectedColumn.setMinWidth(undefined);
+ selectedColumn.setMaxWidth(undefined);
+ }}
+ />
+
+ value !== undefined && value > 0}
+ value={selectedColumn.fixedWidth}
+ setValue={(value) => {
+ selectedColumn.setFixedWidth(value);
+ }}
+ disabled={
+ selectedColumn.minWidth !== undefined ||
+ selectedColumn.maxWidth !== undefined
+ }
+ />
+
+ {
+ if (
+ selectedColumn.minWidth === undefined &&
+ selectedColumn.maxWidth === undefined
+ ) {
+ selectedColumn.setMinWidth(DEFAULT_COLUMN_MIN_WIDTH);
+ selectedColumn.setMaxWidth(DEFAULT_COLUMN_MAX_WIDTH);
+ selectedColumn.setFixedWidth(undefined);
+ } else {
+ selectedColumn.setMinWidth(undefined);
+ selectedColumn.setMaxWidth(undefined);
+ selectedColumn.setFixedWidth(undefined);
+ }
+ }}
+ />
+
+ value !== undefined && value > 0}
+ value={selectedColumn.minWidth}
+ setValue={(value) => {
+ selectedColumn.setMinWidth(value);
+ }}
+ disabled={selectedColumn.fixedWidth !== undefined}
+ />
+
+
+ value !== undefined &&
+ value >= (selectedColumn.minWidth ?? 0)
+ }
+ value={selectedColumn.maxWidth}
+ setValue={(value) => {
+ selectedColumn.setMaxWidth(value);
+ }}
+ disabled={selectedColumn.fixedWidth !== undefined}
+ />
+
+
+
+
+ Blur Content?
+
+
selectedColumn.setBlur(!selectedColumn.blur)}
+ disabled={true}
+ />
+
+
+ >
+ )}
+
+
);
});
diff --git a/packages/legend-application-repl/src/components/dataCube/editor/DataCubeEditorColumnsPanel.tsx b/packages/legend-application-repl/src/components/dataCube/editor/DataCubeEditorColumnsPanel.tsx
index 8efde0b831..8bc57afd5f 100644
--- a/packages/legend-application-repl/src/components/dataCube/editor/DataCubeEditorColumnsPanel.tsx
+++ b/packages/legend-application-repl/src/components/dataCube/editor/DataCubeEditorColumnsPanel.tsx
@@ -21,12 +21,12 @@ import { useEffect } from 'react';
export const DataCubeEditorColumnsPanel = observer(() => {
const replStore = useREPLStore();
- const panel = replStore.dataCubeState.editor.sortsPanel;
+ const panel = replStore.dataCube.editor.sortsPanel;
useEffect(() => {}, [panel]); // TODO: @akphi - remove this dummy useEffect
return (
-
+
diff --git a/packages/legend-application-repl/src/components/dataCube/editor/DataCubeEditorColumnsSelector.tsx b/packages/legend-application-repl/src/components/dataCube/editor/DataCubeEditorColumnsSelector.tsx
index 27e2bbc3c9..a8ef07503a 100644
--- a/packages/legend-application-repl/src/components/dataCube/editor/DataCubeEditorColumnsSelector.tsx
+++ b/packages/legend-application-repl/src/components/dataCube/editor/DataCubeEditorColumnsSelector.tsx
@@ -15,20 +15,21 @@
*/
import { observer } from 'mobx-react-lite';
-import { DataCubeIcon } from '@finos/legend-art';
+import { cn, DataCubeIcon } from '@finos/legend-art';
import type {
ColDef,
ColDefField,
GridApi,
- IRowNode,
+ ModelUpdatedEvent,
RowDragEndEvent,
SelectionChangedEvent,
} from '@ag-grid-community/core';
-import { useCallback, useEffect, useState } from 'react';
+import { useCallback, useEffect, useRef, useState } from 'react';
import {
AgGridReact,
type AgGridReactProps,
type CustomCellRendererProps,
+ type CustomNoRowsOverlayProps,
} from '@ag-grid-community/react';
import { ClientSideRowModelModule } from '@ag-grid-community/client-side-row-model';
import type {
@@ -36,6 +37,10 @@ import type {
DataCubeEditorColumnsSelectorState,
} from '../../../stores/dataCube/editor/DataCubeEditorColumnsSelectorState.js';
import { isNonNullable } from '@finos/legend-shared';
+import {
+ getDataForAllFilteredNodes,
+ getDataForAllNodes,
+} from '../../../stores/dataCube/grid/DataCubeGridClientEngine.js';
function getBaseGridProps<
T extends DataCubeEditorColumnsSelectorColumnState,
@@ -55,7 +60,50 @@ function getBaseGridProps<
headerHeight: 20,
suppressRowHoverHighlight: false,
reactiveCustomComponents: true, // TODO: remove on v32 as this would be default to `true` then
- noRowsOverlayComponent: () =>
,
+ noRowsOverlayComponent: (
+ params: CustomNoRowsOverlayProps
& {
+ violationSeverity?: 'warning' | 'error' | undefined;
+ },
+ ) => {
+ if (params.api.getQuickFilter()) {
+ return (
+
+ );
+ }
+ if (params.violationSeverity) {
+ return (
+
+
+
+
+ No columns selected
+
+ );
+ }
+ return
;
+ },
+ // Show no rows overlay when there are no search results
+ // See https://stackoverflow.com/a/72637410
+ onModelUpdated: (event: ModelUpdatedEvent) => {
+ event.api.getDisplayedRowCount() === 0
+ ? event.api.showNoRowsOverlay()
+ : event.api.hideOverlay();
+ },
};
}
@@ -80,14 +128,54 @@ function getBaseColumnDef<
}
return (params.rowNode?.data as T).name;
},
+ getQuickFilterText: (params) => params.value,
};
}
+/**
+ * Move this display to a separate component to avoid re-rendering the header too frequently
+ */
+const ColumnsSearchResultCountBadge = observer(
+ function ColumnsSearchResultCountBadge<
+ T extends DataCubeEditorColumnsSelectorColumnState,
+ >(props: {
+ selector: DataCubeEditorColumnsSelectorState;
+ gridApi: GridApi;
+ scope: 'available' | 'selected';
+ }) {
+ const { selector, gridApi, scope } = props;
+ return (
+
+ {`${getDataForAllFilteredNodes(gridApi).length}/${scope === 'available' ? selector.availableColumns.length : selector.selectedColumns.length}`}
+
+ {scope === 'available'
+ ? // subscribing to the search text to trigger re-render as it changes
+ selector.availableColumnsSearchText
+ : selector.selectedColumnsSearchText}
+
+
+ );
+ },
+);
+
export const DataCubeEditorColumnsSelector = observer(
function DataCubeEditorColumnsSelector<
T extends DataCubeEditorColumnsSelectorColumnState,
- >(props: { selector: DataCubeEditorColumnsSelectorState }) {
- const { selector } = props;
+ >(props: {
+ selector: DataCubeEditorColumnsSelectorState;
+ extraColumnComponent?:
+ | React.FC<{
+ selector: DataCubeEditorColumnsSelectorState;
+ column: T;
+ }>
+ | undefined;
+ noColumnsSelectedViolationSeverity?: 'warning' | 'error' | undefined;
+ }) {
+ const {
+ selector,
+ extraColumnComponent,
+ noColumnsSelectedViolationSeverity,
+ } = props;
const [selectedAvailableColumns, setSelectedAvailableColumns] = useState<
T[]
>([]);
@@ -98,6 +186,10 @@ export const DataCubeEditorColumnsSelector = observer(
useState(null);
const [selectedColumnsGridApi, setSelectedColumnsGridApi] =
useState(null);
+ const searchAvailableColumnsInputRef = useRef(
+ null,
+ );
+ const searchSelectedColumnsInputRef = useRef(null);
/**
* Since we use managed row dragging for selected columns,
@@ -107,16 +199,11 @@ export const DataCubeEditorColumnsSelector = observer(
*/
const onSelectedColumnsDragStop = useCallback(
(params: RowDragEndEvent) => {
- const newRowData: T[] = [];
- params.api.forEachNode((node: IRowNode) => {
- if (node.data) {
- newRowData.push(node.data);
- }
- });
- selector.setSelectedColumns(newRowData);
+ const newData = getDataForAllNodes(params.api);
+ selector.setSelectedColumns(newData);
selector.setAvailableColumns(
selector.availableColumns.filter(
- (column) => !newRowData.includes(column),
+ (column) => !newData.includes(column),
),
);
},
@@ -154,17 +241,16 @@ export const DataCubeEditorColumnsSelector = observer(
if (event.overIndex === -1) {
return;
}
- const newRowData: T[] = [];
- event.api.forEachNode((node: IRowNode) => {
- if (node.data) {
- newRowData.push(node.data);
- }
- });
- selector.setSelectedColumns(newRowData);
+ const newData = getDataForAllNodes(event.api);
+ selector.setSelectedColumns(newData);
},
[selector],
);
+ /**
+ * Setup row drop zones for each grid to be the other
+ * See https://www.ag-grid.com/react-data-grid/row-dragging-to-grid/
+ */
useEffect(() => {
if (!availableColumnsGridApi || !selectedColumnsGridApi) {
return;
@@ -196,7 +282,7 @@ export const DataCubeEditorColumnsSelector = observer(
]);
return (
-
+
Available columns:
@@ -204,12 +290,35 @@ export const DataCubeEditorColumnsSelector = observer(
+ selector.setAvailableColumnsSearchText(event.target.value)
+ }
+ onKeyDown={(event) => {
+ if (event.code === 'Escape') {
+ event.stopPropagation();
+ searchAvailableColumnsInputRef.current?.select();
+ selector.setAvailableColumnsSearchText('');
+ }
+ }}
/>
+
{
+ selector.setAvailableColumnsSearchText('');
+ searchAvailableColumnsInputRef.current?.focus();
+ }}
+ >
+
+
setAvailableColumnsGridApi(params.api)}
- rowData={selector.availableColumns}
onSelectionChanged={(event: SelectionChangedEvent) => {
setSelectedAvailableColumns(
event.api
@@ -227,23 +335,43 @@ export const DataCubeEditorColumnsSelector = observer(
.filter(isNonNullable),
);
}}
+ // Using ag-grid quick filter is a cheap way to implement search
+ quickFilterText={selector.availableColumnsSearchText}
+ rowData={selector.availableColumns}
columnDefs={[
{
...getBaseColumnDef(),
+ /**
+ * Support double-click to add all (filtered by search) columns
+ */
headerComponent: (params: CustomCellRendererProps) => (
- {
- // TODO: scope this by the current search
+ // The columns being moved are scoped by the current search
+ const filteredData = getDataForAllFilteredNodes(
+ params.api,
+ );
selector.setSelectedColumns([
...selector.selectedColumns,
- ...selector.availableColumns,
+ ...filteredData,
]);
- selector.setAvailableColumns([]);
+ selector.setAvailableColumns(
+ selector.availableColumns.filter(
+ (column) => !filteredData.includes(column),
+ ),
+ );
params.api.clearFocusedCell();
}}
- >{`[All Columns]`}
+ >
+ {`[All Columns]`}
+
+
),
cellRenderer: (params: CustomCellRendererProps) => {
const data = params.data;
@@ -252,7 +380,7 @@ export const DataCubeEditorColumnsSelector = observer(
}
return (
{
selector.setSelectedColumns([
@@ -267,7 +395,15 @@ export const DataCubeEditorColumnsSelector = observer(
params.api.clearFocusedCell();
}}
>
- {data.name}
+
+ {data.name}
+
+
+ {extraColumnComponent?.({
+ selector,
+ column: data,
+ }) ?? null}
+
);
},
@@ -280,40 +416,66 @@ export const DataCubeEditorColumnsSelector = observer(
{
- // TODO: scope this by the current search
+ if (!availableColumnsGridApi) {
+ return;
+ }
+ // The columns being moved are scoped by the current search
+ const filteredData = getDataForAllFilteredNodes(
+ availableColumnsGridApi,
+ );
+ const columnsToMove = selectedAvailableColumns.filter(
+ (column) => filteredData.includes(column),
+ );
selector.setSelectedColumns([
...selector.selectedColumns,
- ...selectedAvailableColumns,
+ ...columnsToMove,
]);
selector.setAvailableColumns(
selector.availableColumns.filter(
- (column) => !selectedAvailableColumns.includes(column),
+ (column) => !columnsToMove.includes(column),
),
);
- availableColumnsGridApi?.clearFocusedCell();
+ availableColumnsGridApi.clearFocusedCell();
}}
disabled={selectedAvailableColumns.length === 0}
>
{
- // TODO: scope this by the current search
+ if (!selectedColumnsGridApi) {
+ return;
+ }
+ // The columns being moved are scoped by the current search
+ const filteredData = getDataForAllFilteredNodes(
+ selectedColumnsGridApi,
+ );
+ const columnsToMove = selectedSelectedColumns.filter((column) =>
+ filteredData.includes(column),
+ );
selector.setAvailableColumns([
...selector.availableColumns,
- ...selectedSelectedColumns,
+ ...columnsToMove,
]);
selector.setSelectedColumns(
selector.selectedColumns.filter(
- (column) => !selectedSelectedColumns.includes(column),
+ (column) => !columnsToMove.includes(column),
),
);
- selectedColumnsGridApi?.clearFocusedCell();
+ selectedColumnsGridApi.clearFocusedCell();
}}
disabled={selectedSelectedColumns.length === 0}
>
@@ -327,11 +489,33 @@ export const DataCubeEditorColumnsSelector = observer(
+ selector.setSelectedColumnsSearchText(event.target.value)
+ }
+ onKeyDown={(event) => {
+ if (event.code === 'Escape') {
+ event.stopPropagation();
+ selector.setSelectedColumnsSearchText('');
+ }
+ }}
/>
+
{
+ selector.setSelectedColumnsSearchText('');
+ searchSelectedColumnsInputRef.current?.focus();
+ }}
+ >
+
+
(),
+ /**
+ * Support double-click to remove all (filtered by search) columns
+ */
headerComponent: (params: CustomCellRendererProps) => (
- {
- // TODO: scope this by the current search
+ // The columns being moved are scoped by the current search
+ const filteredData = getDataForAllFilteredNodes(
+ params.api,
+ );
selector.setAvailableColumns([
...selector.availableColumns,
- ...selector.selectedColumns,
+ ...filteredData,
]);
- selector.setSelectedColumns([]);
+ selector.setSelectedColumns(
+ selector.selectedColumns.filter(
+ (column) => !filteredData.includes(column),
+ ),
+ );
params.api.clearFocusedCell();
}}
- >{`[All Columns]`}
+ >
+ {`[All Columns]`}
+
+
),
cellRenderer: (params: CustomCellRendererProps) => {
const data = params.data;
@@ -377,7 +583,7 @@ export const DataCubeEditorColumnsSelector = observer(
}
return (
{
selector.setAvailableColumns([
@@ -392,7 +598,15 @@ export const DataCubeEditorColumnsSelector = observer(
params.api.clearFocusedCell();
}}
>
- {data.name}
+
+ {data.name}
+
+
+ {extraColumnComponent?.({
+ selector,
+ column: data,
+ }) ?? null}
+
);
},
diff --git a/packages/legend-application-repl/src/components/dataCube/editor/DataCubeEditorDeveloperPanel.tsx b/packages/legend-application-repl/src/components/dataCube/editor/DataCubeEditorDeveloperPanel.tsx
new file mode 100644
index 0000000000..418fb88558
--- /dev/null
+++ b/packages/legend-application-repl/src/components/dataCube/editor/DataCubeEditorDeveloperPanel.tsx
@@ -0,0 +1,41 @@
+/**
+ * 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 { DataCubeIcon } from '@finos/legend-art';
+import { observer } from 'mobx-react-lite';
+import { useREPLStore } from '../../REPLStoreProvider.js';
+import { useEffect } from 'react';
+
+export const DataCubeEditorDeveloperPanel = observer(() => {
+ const replStore = useREPLStore();
+ const panel = replStore.dataCube.editor.sortsPanel;
+
+ useEffect(() => {}, [panel]); // TODO: @akphi - remove this dummy useEffect
+
+ return (
+
+ );
+});
diff --git a/packages/legend-application-repl/src/components/dataCube/editor/DataCubeEditorExtendedColumnsPanel.tsx b/packages/legend-application-repl/src/components/dataCube/editor/DataCubeEditorExtendedColumnsPanel.tsx
index c0dac62d14..658cd90a61 100644
--- a/packages/legend-application-repl/src/components/dataCube/editor/DataCubeEditorExtendedColumnsPanel.tsx
+++ b/packages/legend-application-repl/src/components/dataCube/editor/DataCubeEditorExtendedColumnsPanel.tsx
@@ -21,12 +21,12 @@ import { useEffect } from 'react';
export const DataCubeEditorExtendedColumnsPanel = observer(() => {
const replStore = useREPLStore();
- const panel = replStore.dataCubeState.editor.sortsPanel;
+ const panel = replStore.dataCube.editor.sortsPanel;
useEffect(() => {}, [panel]); // TODO: @akphi - remove this dummy useEffect
return (
-
+
diff --git a/packages/legend-application-repl/src/components/dataCube/editor/DataCubeEditorFilterPanel.tsx b/packages/legend-application-repl/src/components/dataCube/editor/DataCubeEditorFilterPanel.tsx
index db4292e73c..822e5d4812 100644
--- a/packages/legend-application-repl/src/components/dataCube/editor/DataCubeEditorFilterPanel.tsx
+++ b/packages/legend-application-repl/src/components/dataCube/editor/DataCubeEditorFilterPanel.tsx
@@ -21,12 +21,12 @@ import { useEffect } from 'react';
export const DataCubeEditorFilterPanel = observer(() => {
const replStore = useREPLStore();
- const panel = replStore.dataCubeState.editor.sortsPanel;
+ const panel = replStore.dataCube.editor.sortsPanel;
useEffect(() => {}, [panel]); // TODO: @akphi - remove this dummy useEffect
return (
-
+
diff --git a/packages/legend-application-repl/src/components/dataCube/editor/DataCubeEditorGeneralPropertiesPanel.tsx b/packages/legend-application-repl/src/components/dataCube/editor/DataCubeEditorGeneralPropertiesPanel.tsx
index 5507ac2d46..0c9ba467ce 100644
--- a/packages/legend-application-repl/src/components/dataCube/editor/DataCubeEditorGeneralPropertiesPanel.tsx
+++ b/packages/legend-application-repl/src/components/dataCube/editor/DataCubeEditorGeneralPropertiesPanel.tsx
@@ -16,14 +16,69 @@
import { observer } from 'mobx-react-lite';
import { useREPLStore } from '../../REPLStoreProvider.js';
-import { DataCubeIcon } from '@finos/legend-art';
+import { cn, DataCubeIcon, useDropdownMenu } from '@finos/legend-art';
+import {
+ DataCubeFont,
+ DataCubeFontFormatUnderlinedVariant,
+ DataCubeFontTextAlignment,
+ DataCubeNumberScale,
+ DataCubeSelectionStat,
+ DEFAULT_BACKGROUND_COLOR,
+ DEFAULT_ERROR_FOREGROUND_COLOR,
+ DEFAULT_FOREGROUND_COLOR,
+ DEFAULT_NEGATIVE_FOREGROUND_COLOR,
+ DEFAULT_ROW_HIGHLIGHT_BACKGROUND_COLOR,
+ DEFAULT_ZERO_FOREGROUND_COLOR,
+} from '../../../stores/dataCube/core/DataCubeQueryEngine.js';
+import {
+ DataCubeEditorCheckbox,
+ DataCubeEditorColorPickerButton,
+ DataCubeEditorDropdownMenu,
+ DataCubeEditorDropdownMenuItem,
+ DataCubeEditorDropdownMenuItemSeparator,
+ DataCubeEditorDropdownMenuTrigger,
+ DataCubeEditorTextInput,
+ DataCubeEditorNumberInput,
+ WIP_Badge,
+} from './DataCubeEditorShared.js';
export const DataCubeEditorGeneralPropertiesPanel = observer(() => {
const replStore = useREPLStore();
- const panel = replStore.dataCubeState.editor.generalPropertiesPanel;
+ const panel = replStore.dataCube.editor.generalPropertiesPanel;
+ const configuration = panel.configuration;
+ const [
+ openInitialExpandLevelDropdown,
+ closeInitialExpandLevelDropdown,
+ initialExpandLevelDropdownProps,
+ ] = useDropdownMenu();
+ const [
+ openNumberScaleDropdown,
+ closeNumberScaleDropdown,
+ numberScaleDropdownProps,
+ ] = useDropdownMenu();
+ const [
+ openSelectionStatDropdown,
+ closeSelectionStatDropdown,
+ selectionStatDropdownProps,
+ ] = useDropdownMenu();
+ const [
+ openFontFamilyDropdown,
+ closeFontFamilyDropdown,
+ fontFamilyDropdownProps,
+ ] = useDropdownMenu();
+ const [
+ openFontSizeDropdown,
+ closeFontSizeDropdown,
+ openFontSizeDropdownProps,
+ ] = useDropdownMenu();
+ const [
+ openFontFormatUnderlinedVariantDropdown,
+ closeFontFormatUnderlinedVariantDropdown,
+ fontFormatUnderlinedVariantDropdownProps,
+ ] = useDropdownMenu();
return (
-
+
@@ -32,16 +87,630 @@ export const DataCubeEditorGeneralPropertiesPanel = observer(() => {
General Properties
-
-
-
Report Title:
-
{
- panel.setName(event.target.value);
- }}
- />
+
+
+
+
+ Report Title:
+
+
{
+ panel.setName(event.target.value);
+ }}
+ />
+
+
+
+
+ Initially Expand to Level:
+
+
+ {configuration.initialExpandLevel ?? '(None)'}
+
+
+ {[undefined, 1, 2, 3, 4, 5, 6, 7, 8].map((level) => (
+ {
+ configuration.setInitialExpandLevel(level);
+ closeInitialExpandLevelDropdown();
+ }}
+ >
+ {level ?? '(None)'}
+
+ ))}
+
+
+
+
+
+
+ Show Root Aggregation?
+
+
+ configuration.setShowRootAggregation(
+ !configuration.showRootAggregation,
+ )
+ }
+ disabled={true}
+ />
+
+
+
+
+
+ Show Leaf Count?
+
+
+ configuration.setShowLeafCount(!configuration.showLeafCount)
+ }
+ />
+
+
+
+
+ Show Lines?
+
+
+ configuration.setShowTreeLine(!configuration.showTreeLine)
+ }
+ />
+
+ configuration.setShowHorizontalGridLine(
+ !configuration.showHorizontalGridLine,
+ )
+ }
+ />
+
+ configuration.setShowVerticalGridLine(
+ !configuration.showVerticalGridLine,
+ )
+ }
+ />
+
+
+
+
+ Default Number Scale:
+
+
+ {configuration.numberScale ?? '(None)'}
+
+
+ {[
+ undefined,
+ DataCubeNumberScale.PERCENT,
+ DataCubeNumberScale.BASIS_POINT,
+ DataCubeNumberScale.THOUSANDS,
+ DataCubeNumberScale.MILLIONS,
+ DataCubeNumberScale.BILLIONS,
+ DataCubeNumberScale.AUTO,
+ ].map((scale) => (
+ {
+ configuration.setNumberScale(scale);
+ closeNumberScaleDropdown();
+ }}
+ >
+ {scale ?? '(None)'}
+
+ ))}
+
+
+
+
+
+ Show Selection Stats:
+
+
+ {'(None)'}
+
+
+ {[
+ DataCubeSelectionStat.SUM,
+ DataCubeSelectionStat.AVERAGE,
+ DataCubeSelectionStat.COUNT,
+ DataCubeSelectionStat.MIN,
+ DataCubeSelectionStat.MAX,
+ ].map((operation) => (
+ {
+ // TODO
+ closeSelectionStatDropdown();
+ }}
+ >
+ ))}
+
+
+
+
+
+
+ Row Limit:
+
+
+ value !== undefined && (value === -1 || value > 0)
+ }
+ setValue={(value) => panel.setLimit(value ?? -1)}
+ />
+
+ Truncate result to this many rows at every level. Use -1 for
+ unlimited.
+
+
+
+
+
+
+ configuration.setShowWarningForTruncatedResult(
+ !configuration.showWarningForTruncatedResult,
+ )
+ }
+ />
+
+
+
+
+
+
+ Default Font:
+
+
+ {configuration.defaultFontFamily}
+
+
+ {[
+ DataCubeFont.ARIAL,
+ DataCubeFont.ROBOTO,
+ DataCubeFont.ROBOTO_CONDENSED,
+ ].map((font) => (
+ {
+ configuration.setDefaultFontFamily(font);
+ closeFontFamilyDropdown();
+ }}
+ >
+ {font}
+
+ ))}
+
+ {[
+ DataCubeFont.GEORGIA,
+ DataCubeFont.ROBOTO_SERIF,
+ DataCubeFont.TIMES_NEW_ROMAN,
+ ].map((font) => (
+ {
+ configuration.setDefaultFontFamily(font);
+ closeFontFamilyDropdown();
+ }}
+ >
+ {font}
+
+ ))}
+
+ {[
+ DataCubeFont.JERBRAINS_MONO,
+ DataCubeFont.ROBOTO_MONO,
+ DataCubeFont.UBUNTU_MONO,
+ ].map((font) => (
+ {
+ configuration.setDefaultFontFamily(font);
+ closeFontFamilyDropdown();
+ }}
+ >
+ {font}
+
+ ))}
+
+
+
+ {configuration.defaultFontSize}
+
+
+ {[
+ 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 16, 18, 20, 22, 24, 26, 28,
+ 32, 36, 48, 72,
+ ].map((size) => (
+ {
+ configuration.setDefaultFontSize(size);
+ closeFontSizeDropdown();
+ }}
+ >
+ {size}
+
+ ))}
+
+
+
+
+ configuration.setDefaultFontBold(
+ !configuration.defaultFontBold,
+ )
+ }
+ >
+
+
+
+ configuration.setDefaultFontItalic(
+ !configuration.defaultFontItalic,
+ )
+ }
+ >
+
+
+
+ configuration.setDefaultFontUnderlined(
+ configuration.defaultFontUnderlined === undefined
+ ? DataCubeFontFormatUnderlinedVariant.SOLID
+ : undefined,
+ )
+ }
+ >
+
+
+
+
+
+
+ {[
+ DataCubeFontFormatUnderlinedVariant.SOLID,
+ DataCubeFontFormatUnderlinedVariant.DASHED,
+ DataCubeFontFormatUnderlinedVariant.DOTTED,
+ DataCubeFontFormatUnderlinedVariant.DOUBLE,
+ DataCubeFontFormatUnderlinedVariant.WAVY,
+ ].map((variant) => (
+ {
+ configuration.setDefaultFontUnderlined(variant);
+ closeFontFormatUnderlinedVariantDropdown();
+ }}
+ >
+
+
+
+
+ ))}
+
+
+ configuration.setDefaultFontStrikethrough(
+ !configuration.defaultFontStrikethrough,
+ )
+ }
+ >
+
+
+
+
+
+
+ configuration.setDefaultTextAlign(
+ DataCubeFontTextAlignment.LEFT,
+ )
+ }
+ >
+
+
+
+ configuration.setDefaultTextAlign(
+ DataCubeFontTextAlignment.CENTER,
+ )
+ }
+ >
+
+
+
+ configuration.setDefaultTextAlign(
+ DataCubeFontTextAlignment.RIGHT,
+ )
+ }
+ >
+
+
+
+
+
+
+
+ Default Colors:
+
+
+
+
+
+ Normal
+
+
+ Negative
+
+
+ Zero
+
+
+ Error
+
+
+
+
+ Foreground:
+
+
+
+ configuration.setDefaultForegroundColor(value)
+ }
+ />
+
+
+
+ configuration.setDefaultForegroundNegativeColor(value)
+ }
+ />
+
+
+
+ configuration.setDefaultForegroundZeroColor(value)
+ }
+ />
+
+
+
+ configuration.setDefaultForegroundErrorColor(value)
+ }
+ />
+
+
+
+
+ Background:
+
+
+
+ configuration.setDefaultBackgroundColor(value)
+ }
+ />
+
+
+
+ configuration.setDefaultBackgroundNegativeColor(value)
+ }
+ />
+
+
+
+ configuration.setDefaultBackgroundZeroColor(value)
+ }
+ />
+
+
+
+ configuration.setDefaultBackgroundErrorColor(value)
+ }
+ />
+
+
+
+
+
+
+
+ Hightlight Rows:
+
+
+ configuration.setAlternateRows(!configuration.alternateRows)
+ }
+ />
+ value !== undefined && value > 0}
+ value={configuration.alternateRowsCount}
+ setValue={(value) =>
+ configuration.setAlternateRowsCount(value ?? 1)
+ }
+ />
+ {`row(s)`}
+
+ configuration.setDefaultBackgroundErrorColor(value)
+ }
+ />
+
+
);
diff --git a/packages/legend-application-repl/src/components/dataCube/editor/DataCubeEditorHPivotsPanel.tsx b/packages/legend-application-repl/src/components/dataCube/editor/DataCubeEditorHPivotsPanel.tsx
index e39df680d2..6350180d5c 100644
--- a/packages/legend-application-repl/src/components/dataCube/editor/DataCubeEditorHPivotsPanel.tsx
+++ b/packages/legend-application-repl/src/components/dataCube/editor/DataCubeEditorHPivotsPanel.tsx
@@ -21,12 +21,12 @@ import { useEffect } from 'react';
export const DataCubeEditorHPivotsPanel = observer(() => {
const replStore = useREPLStore();
- const panel = replStore.dataCubeState.editor.sortsPanel;
+ const panel = replStore.dataCube.editor.sortsPanel;
useEffect(() => {}, [panel]); // TODO: @akphi - remove this dummy useEffect
return (
-
+
diff --git a/packages/legend-application-repl/src/components/dataCube/editor/DataCubeEditorShared.tsx b/packages/legend-application-repl/src/components/dataCube/editor/DataCubeEditorShared.tsx
new file mode 100644
index 0000000000..73ba560fec
--- /dev/null
+++ b/packages/legend-application-repl/src/components/dataCube/editor/DataCubeEditorShared.tsx
@@ -0,0 +1,448 @@
+/**
+ * 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 {
+ BasePopover,
+ Checkbox,
+ cn,
+ DataCubeIcon,
+ DropdownMenu,
+ DropdownMenuItem,
+ HexAlphaColorPicker,
+ HexColorInput,
+ TailwindCSSPalette,
+ type CheckboxProps,
+ type DropdownMenuItemProps,
+ type DropdownMenuProps,
+ type TailwindCSSColorScale,
+ type TailwindCSSColorScaleKey,
+} from '@finos/legend-art';
+import { toNumber } from '@finos/legend-shared';
+import React, { forwardRef, useEffect, useState } from 'react';
+
+export function WIP_Badge() {
+ return (
+
+ WIP
+
+ );
+}
+
+export const DataCubeEditorNumberInput = forwardRef(
+ function DataCubeEditorBaseNumberInput(
+ props: React.InputHTMLAttributes
& {
+ min?: number | undefined;
+ max?: number | undefined;
+ step?: number | undefined;
+ isValid?: (value: number | undefined) => boolean;
+ isDecimal?: boolean | undefined;
+ defaultValue?: number | undefined;
+ value: number | undefined;
+ setValue: (value?: number | undefined) => void;
+ className?: string | undefined;
+ },
+ ref: React.Ref,
+ ) {
+ const {
+ min,
+ max,
+ step,
+ value,
+ setValue,
+ isValid,
+ isDecimal,
+ defaultValue,
+ disabled,
+ className,
+ } = props;
+ const [inputValue, setInputValue] = useState(value ?? '');
+
+ useEffect(() => {
+ setInputValue(value ?? '');
+ }, [value]);
+
+ return (
+ {
+ const newInputValue = event.target.value;
+ setInputValue(newInputValue);
+ const numericValue = isDecimal
+ ? toNumber(newInputValue)
+ : parseInt(newInputValue, 10);
+ if (
+ isNaN(numericValue) ||
+ // NOTE: `toNumber` parses empty string as `0`, which is not what we want, so we want to do the explicit check here
+ !newInputValue ||
+ (isValid !== undefined
+ ? !isValid(numericValue)
+ : (min !== undefined && numericValue < min) ||
+ (max !== undefined && numericValue > max))
+ ) {
+ return;
+ }
+ setValue(numericValue);
+ }}
+ onBlur={() => {
+ const numericValue = isDecimal
+ ? toNumber(inputValue)
+ : parseInt(inputValue.toString(), 10);
+ if (
+ isNaN(numericValue) ||
+ // NOTE: `toNumber` parses empty string as `0`, which is not what we want, so we want to do the explicit check here
+ !inputValue ||
+ (isValid !== undefined
+ ? !isValid(numericValue)
+ : (min !== undefined && numericValue < min) ||
+ (max !== undefined && numericValue > max))
+ ) {
+ setValue(defaultValue);
+ setInputValue(defaultValue ?? '');
+ } else {
+ setInputValue(value ?? '');
+ }
+ }}
+ />
+ );
+ },
+);
+
+export function DataCubeEditorTextInput(
+ props: React.InputHTMLAttributes,
+) {
+ const { className, ...otherProps } = props;
+ return (
+
+ );
+}
+
+export function DataCubeEditorCheckbox(
+ props: CheckboxProps & {
+ label?: React.ReactNode;
+ onChange: () => void;
+ },
+) {
+ const { label, className, onChange, disabled, ...otherProps } = props;
+ return (
+ <>
+ }
+ checkedIcon={ }
+ disableRipple={true}
+ classes={{
+ root: cn(
+ // Make sure the icons used have consistent stroke width with other components' borders
+ // and that the left side is offseted to align well with other components
+ 'p-0 text-neutral-600 [&_*]:stroke-[1.5px] -ml-[1px]',
+ className,
+ ),
+ checked: 'data-cube-editor-checkbox--checked',
+ disabled: 'data-cube-editor-checkbox--disabled',
+ }}
+ onChange={onChange}
+ disabled={disabled}
+ {...otherProps}
+ />
+ {Boolean(label) && (
+
+ {label}
+
+ )}
+ >
+ );
+}
+
+export function DataCubeEditorDropdownMenuTrigger(
+ props: React.ButtonHTMLAttributes,
+) {
+ const { children, className, ...otherProps } = props;
+ return (
+
+ {props.children}
+
+
+
+
+ );
+}
+
+export function DataCubeEditorDropdownMenu(props: DropdownMenuProps) {
+ const { className, ...otherProps } = props;
+ return (
+
+ );
+}
+
+export function DataCubeEditorDropdownMenuItem(props: DropdownMenuItemProps) {
+ const { className, ...otherProps } = props;
+ return (
+
+ );
+}
+
+export function DataCubeEditorDropdownMenuItemSeparator() {
+ return
;
+}
+
+function DataCubeEditorColorPicker(props: {
+ color: string;
+ onChange: (value: string) => void;
+ onClose: () => void;
+ defaultColor?: string | undefined;
+}) {
+ const { onChange, onClose, defaultColor } = props;
+ const [color, setColor] = useState(props.color);
+
+ return (
+
+
+
+
+
+ {(
+ [
+ 'slate',
+ 'neutral',
+ 'red',
+ 'orange',
+ 'amber',
+ 'yellow',
+ 'lime',
+ 'green',
+ 'emerald',
+ 'teal',
+ 'sky',
+ 'blue',
+ 'indigo',
+ 'violet',
+ 'purple',
+ 'fuchsia',
+ 'pink',
+ 'rose',
+ ] as TailwindCSSColorScaleKey[]
+ ).map((scale) => (
+
+ {(
+ [
+ 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950,
+ ] as (keyof TailwindCSSColorScale)[]
+ ).map((level) => (
+ {
+ setColor(TailwindCSSPalette[scale][level]);
+ }}
+ />
+ ))}
+
+ ))}
+
+
+
+ {[
+ // Colors from Better Colors - https://clrs.cc/
+ '#000000',
+ '#111111',
+ '#AAAAAA',
+ '#DDDDDD',
+ '#FFFFFF',
+ '#FF4136',
+ '#FF851B',
+ '#FFDC00',
+ '#01FF70',
+ '#2ECC40',
+ '#3D9970',
+ '#39CCCC',
+ '#7FDBFF',
+ '#0074D9',
+ '#001F3F',
+ '#B10DC9',
+ '#F012BE',
+ '#85144B',
+ ].map((_color) => (
+
+ {
+ setColor(_color);
+ }}
+ />
+
+ ))}
+
+
+
+
+
+
+ {defaultColor !== undefined && (
+ {
+ setColor(defaultColor);
+ }}
+ >
+ Reset
+
+ )}
+ {
+ onClose();
+ }}
+ >
+ Cancel
+
+ {
+ onChange(color);
+ onClose();
+ }}
+ >
+ OK
+
+
+
+
+ );
+}
+
+export function DataCubeEditorColorPickerButton(props: {
+ color: string;
+ onChange: (value: string) => void;
+ className?: string | undefined;
+ disabled?: boolean | undefined;
+ defaultColor?: string | undefined;
+}) {
+ const { color, onChange, className, disabled, defaultColor } = props;
+ const [anchorEl, setAnchorEl] = useState(null);
+ return (
+ <>
+ {
+ setAnchorEl(event.currentTarget);
+ }}
+ disabled={disabled}
+ >
+
+
+ {Boolean(anchorEl) && (
+ setAnchorEl(null)}
+ >
+ setAnchorEl(null)}
+ defaultColor={defaultColor}
+ />
+
+ )}
+ >
+ );
+}
diff --git a/packages/legend-application-repl/src/components/dataCube/editor/DataCubeEditorSortsPanel.tsx b/packages/legend-application-repl/src/components/dataCube/editor/DataCubeEditorSortsPanel.tsx
index 073852b44d..9b17dafb8a 100644
--- a/packages/legend-application-repl/src/components/dataCube/editor/DataCubeEditorSortsPanel.tsx
+++ b/packages/legend-application-repl/src/components/dataCube/editor/DataCubeEditorSortsPanel.tsx
@@ -15,16 +15,112 @@
*/
import { observer } from 'mobx-react-lite';
-import { DataCubeIcon } from '@finos/legend-art';
+import {
+ DataCubeIcon,
+ useDropdownMenu,
+ DropdownMenuItem,
+ DropdownMenu,
+} from '@finos/legend-art';
import { useREPLStore } from '../../REPLStoreProvider.js';
import { DataCubeEditorColumnsSelector } from './DataCubeEditorColumnsSelector.js';
+import type { DataCubeEditorColumnsSelectorState } from '../../../stores/dataCube/editor/DataCubeEditorColumnsSelectorState.js';
+import type { DataCubeEditorSortColumnState } from '../../../stores/dataCube/editor/DataCubeEditorSortsPanelState.js';
+import { DataCubeQuerySnapshotSortOperation } from '../../../stores/dataCube/core/DataCubeQuerySnapshot.js';
+import { IllegalStateError } from '@finos/legend-shared';
+import { WIP_Badge } from './DataCubeEditorShared.js';
+
+function getSortDirectionLabel(operation: DataCubeQuerySnapshotSortOperation) {
+ switch (operation) {
+ case DataCubeQuerySnapshotSortOperation.ASCENDING:
+ return 'Ascending';
+ case DataCubeQuerySnapshotSortOperation.DESCENDING:
+ return 'Descending';
+ default:
+ throw new IllegalStateError(`Unsupported sort operation '${operation}'`);
+ }
+}
+
+const SortDirectionDropdown = observer(
+ (props: {
+ selector: DataCubeEditorColumnsSelectorState;
+ column: DataCubeEditorSortColumnState;
+ }) => {
+ const { column } = props;
+ const [openMenu, closeMenu, menuProps] = useDropdownMenu();
+
+ return (
+
+
+ {getSortDirectionLabel(column.operation)}
+
+
{
+ event.stopPropagation();
+ openMenu(event);
+ }}
+ onClick={(event) => event.stopPropagation()}
+ >
+ {getSortDirectionLabel(column.operation)}
+
+
+
+
+
+ {
+ column.setOperation(DataCubeQuerySnapshotSortOperation.ASCENDING);
+ closeMenu();
+ }}
+ >
+ Ascending
+
+
+ {`Ascending (abs)`}
+
+
+ {
+ column.setOperation(
+ DataCubeQuerySnapshotSortOperation.DESCENDING,
+ );
+ closeMenu();
+ }}
+ >
+ Descending
+
+
+ {`Descending (abs)`}
+
+
+
+
+ );
+ },
+);
export const DataCubeEditorSortsPanel = observer(() => {
const replStore = useREPLStore();
- const panel = replStore.dataCubeState.editor.sortsPanel;
+ const panel = replStore.dataCube.editor.sortsPanel;
return (
-
+
@@ -34,7 +130,10 @@ export const DataCubeEditorSortsPanel = observer(() => {
-
+ }
+ />
);
diff --git a/packages/legend-application-repl/src/components/dataCube/editor/DataCubeEditorVPivotsPanel.tsx b/packages/legend-application-repl/src/components/dataCube/editor/DataCubeEditorVPivotsPanel.tsx
index 778a0aab07..496aab524d 100644
--- a/packages/legend-application-repl/src/components/dataCube/editor/DataCubeEditorVPivotsPanel.tsx
+++ b/packages/legend-application-repl/src/components/dataCube/editor/DataCubeEditorVPivotsPanel.tsx
@@ -21,12 +21,12 @@ import { useEffect } from 'react';
export const DataCubeEditorVPivotsPanel = observer(() => {
const replStore = useREPLStore();
- const panel = replStore.dataCubeState.editor.sortsPanel;
+ const panel = replStore.dataCube.editor.sortsPanel;
useEffect(() => {}, [panel]); // TODO: @akphi - remove this dummy useEffect
return (
-
+
diff --git a/packages/legend-application-repl/src/components/dataCube/grid/DataCubeGrid.tsx b/packages/legend-application-repl/src/components/dataCube/grid/DataCubeGrid.tsx
index 8500efb449..c334b3e072 100644
--- a/packages/legend-application-repl/src/components/dataCube/grid/DataCubeGrid.tsx
+++ b/packages/legend-application-repl/src/components/dataCube/grid/DataCubeGrid.tsx
@@ -19,6 +19,7 @@ import { LicenseManager } from '@ag-grid-enterprise/core';
import { ClientSideRowModelModule } from '@ag-grid-community/client-side-row-model';
import { ServerSideRowModelModule } from '@ag-grid-enterprise/server-side-row-model';
import { RowGroupingModule } from '@ag-grid-enterprise/row-grouping';
+import { ClipboardModule } from '@ag-grid-enterprise/clipboard';
import { MenuModule } from '@ag-grid-enterprise/menu';
import { AgGridReact } from '@ag-grid-community/react';
import { useEffect, useState } from 'react';
@@ -26,9 +27,11 @@ import { useREPLStore } from '../../REPLStoreProvider.js';
import { DataCubeIcon, Switch, cn } from '@finos/legend-art';
import {
INTERNAL__GRID_CLIENT_HEADER_HEIGHT,
- INTERNAL__GRID_CLIENT_ROW_BUFFER,
INTERNAL__GRID_CLIENT_ROW_HEIGHT,
} from '../../../stores/dataCube/grid/DataCubeGridClientEngine.js';
+import { RangeSelectionModule } from '@ag-grid-enterprise/range-selection';
+import { buildGridMenu } from './menu/DataCubeGridMenu.js';
+import { DEFAULT_ROW_BUFFER } from '../../../stores/dataCube/core/DataCubeQueryEngine.js';
// NOTE: This is a workaround to prevent ag-grid license key check from flooding the console screen
// with its stack trace in Chrome.
@@ -42,9 +45,8 @@ console.error = (message?: unknown, ...agrs: unknown[]): void => {
export const DataCubeGrid = observer(() => {
const replStore = useREPLStore();
- const dataCubeState = replStore.dataCubeState;
- const grid = dataCubeState.grid;
-
+ const dataCube = replStore.dataCube;
+ const grid = dataCube.grid;
const [scrollHintText, setScrollHintText] = useState('');
useEffect(() => {
@@ -57,44 +59,46 @@ export const DataCubeGrid = observer(() => {
{
- grid.configureClient(params.api);
- // restore original error logging
- console.error = __INTERNAL__original_console_error; // eslint-disable-line no-console
- }}
// -------------------------------------- ROW GROUPING --------------------------------------
rowGroupPanelShow="always"
suppressScrollOnNewData={true}
groupDisplayType="custom" // keeps the column set stable even when row grouping is used
suppressRowGroupHidesColumns={true} // keeps the column set stable even when row grouping is used
+ // Keeps the columns stable even when aggregation is used
+ suppressAggFuncInHeader={true}
// -------------------------------------- PIVOT --------------------------------------
// pivotPanelShow="always"
// pivotMode={true}
- // -------------------------------------- SERVER SIDE ROW MODEL --------------------------------------
- rowModelType="serverSide"
- serverSideDatasource={grid.clientDataSource}
- // -------------------------------------- GENERIC --------------------------------------
- suppressBrowserResizeObserver={true}
- animateRows={false} // improve performance
- // NOTE: since we shrink the spacing, more rows can be shown, as such, setting higher row
- // buffer will improve scrolling performance, but compromise initial load and various
- // actions performance
- rowBuffer={INTERNAL__GRID_CLIENT_ROW_BUFFER}
- rowHeight={INTERNAL__GRID_CLIENT_ROW_HEIGHT}
- headerHeight={INTERNAL__GRID_CLIENT_HEADER_HEIGHT}
+ // -------------------------------------- SORT --------------------------------------
// Force multi-sorting since this is what the query supports anyway
alwaysMultiSort={true}
- // Keeps the columns stable even when aggregation is used
- suppressAggFuncInHeader={true}
+ // -------------------------------------- DISPLAY & INTERACTION --------------------------------------
+ className="ag-theme-balham"
+ rowHeight={INTERNAL__GRID_CLIENT_ROW_HEIGHT}
+ headerHeight={INTERNAL__GRID_CLIENT_HEADER_HEIGHT}
+ suppressBrowserResizeObserver={true}
+ reactiveCustomComponents={true} // TODO: remove on v32 as this would be default to `true` then
+ noRowsOverlayComponent={() => (
+
+ )}
+ loadingOverlayComponent={() => (
+
+ )}
+ preventDefaultOnContextMenu={true}
+ columnMenu="new" // ensure context menu works on header
+ getContextMenuItems={buildGridMenu}
+ getMainMenuItems={buildGridMenu}
+ enableRangeSelection={true}
// Show cursor position when scrolling
onBodyScroll={(event) => {
const rowCount = event.api.getDisplayedRowCount();
@@ -108,8 +112,37 @@ export const DataCubeGrid = observer(() => {
Math.floor(range.bottom / INTERNAL__GRID_CLIENT_ROW_HEIGHT),
);
setScrollHintText(`${start}-${end}/${rowCount}`);
+ event.api.hidePopupMenu(); // hide context-menu while scrolling
}}
onBodyScrollEnd={() => setScrollHintText('')}
+ // -------------------------------------- SERVER SIDE ROW MODEL --------------------------------------
+ rowModelType="serverSide"
+ serverSideDatasource={grid.clientDataSource}
+ // -------------------------------------- PERFORMANCE --------------------------------------
+ // NOTE: since we shrink the spacing, more rows can be shown, as such, setting higher row
+ // buffer will improve scrolling performance, but compromise initial load and various
+ // actions performance
+ rowBuffer={DEFAULT_ROW_BUFFER}
+ animateRows={false} // improve performance
+ // -------------------------------------- SETUP --------------------------------------
+ modules={[
+ // community
+ ClientSideRowModelModule,
+ // enterprise
+ ServerSideRowModelModule,
+ RowGroupingModule,
+ MenuModule,
+ ClipboardModule,
+ RangeSelectionModule,
+ ]}
+ onGridReady={(params): void => {
+ grid.configureClient(params.api);
+ // restore original error logging
+ console.error = __INTERNAL__original_console_error; // eslint-disable-line no-console
+ }}
+ context={{
+ dataCube,
+ }}
/>
diff --git a/packages/legend-application-repl/src/components/dataCube/grid/DataCubeGridShared.tsx b/packages/legend-application-repl/src/components/dataCube/grid/DataCubeGridShared.tsx
new file mode 100644
index 0000000000..2e5c4a06ba
--- /dev/null
+++ b/packages/legend-application-repl/src/components/dataCube/grid/DataCubeGridShared.tsx
@@ -0,0 +1,41 @@
+/**
+ * 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 {
+ useGridMenuItem,
+ type CustomMenuItemProps,
+} from '@ag-grid-community/react';
+import { WIP_Badge } from '../editor/DataCubeEditorShared.js';
+
+export function WIP_GridMenuItem({ name, subMenu }: CustomMenuItemProps) {
+ useGridMenuItem({
+ configureDefaults: () => true,
+ });
+
+ return (
+
+
+
+ {name}
+
+
+
+
+ {subMenu && }
+
+
+ );
+}
diff --git a/packages/legend-application-repl/src/components/dataCube/grid/menu/DataCubeGridMenu.tsx b/packages/legend-application-repl/src/components/dataCube/grid/menu/DataCubeGridMenu.tsx
new file mode 100644
index 0000000000..bdcdf24c69
--- /dev/null
+++ b/packages/legend-application-repl/src/components/dataCube/grid/menu/DataCubeGridMenu.tsx
@@ -0,0 +1,394 @@
+/**
+ * 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 {
+ GetContextMenuItemsParams,
+ GetMainMenuItemsParams,
+ MenuItemDef,
+} from '@ag-grid-community/core';
+import type { DataCubeState } from '../../../../stores/dataCube/DataCubeState.js';
+import { buildGridSortsMenu } from './DataCubeGridSortsMenu.js';
+import { WIP_GridMenuItem } from '../DataCubeGridShared.js';
+
+export function buildGridMenu(
+ params:
+ | GetContextMenuItemsParams
+ | GetMainMenuItemsParams,
+): (string | MenuItemDef)[] {
+ const context = params.context;
+ const dataCube = context.dataCube;
+ const editor = dataCube.editor;
+ const column = params.column ?? undefined;
+ const value: unknown = 'value' in params ? params.value : undefined;
+
+ const result: (string | MenuItemDef)[] = [
+ {
+ name: 'Export',
+ menuItem: WIP_GridMenuItem,
+ cssClasses: ['!opacity-100'],
+ subMenu: [
+ {
+ name: 'HTML',
+ menuItem: WIP_GridMenuItem,
+ cssClasses: ['!opacity-100'],
+ disabled: true,
+ },
+ {
+ name: 'Plain Text',
+ menuItem: WIP_GridMenuItem,
+ cssClasses: ['!opacity-100'],
+ disabled: true,
+ },
+ {
+ name: 'PDF',
+ menuItem: WIP_GridMenuItem,
+ cssClasses: ['!opacity-100'],
+ disabled: true,
+ },
+ {
+ name: 'Excel',
+ menuItem: WIP_GridMenuItem,
+ cssClasses: ['!opacity-100'],
+ disabled: true,
+ },
+ {
+ name: 'CSV',
+ menuItem: WIP_GridMenuItem,
+ cssClasses: ['!opacity-100'],
+ disabled: true,
+ },
+ 'separator',
+ {
+ name: 'DataCube Specification',
+ menuItem: WIP_GridMenuItem,
+ cssClasses: ['!opacity-100'],
+ disabled: true,
+ },
+ ],
+ },
+ {
+ name: 'Email',
+ menuItem: WIP_GridMenuItem,
+ cssClasses: ['!opacity-100'],
+ subMenu: [
+ {
+ name: 'HTML',
+ menuItem: WIP_GridMenuItem,
+ cssClasses: ['!opacity-100'],
+ disabled: true,
+ },
+ {
+ name: 'Plain Text',
+ menuItem: WIP_GridMenuItem,
+ cssClasses: ['!opacity-100'],
+ disabled: true,
+ },
+ 'separator',
+ {
+ name: 'HTML Attachment',
+ menuItem: WIP_GridMenuItem,
+ cssClasses: ['!opacity-100'],
+ disabled: true,
+ },
+ {
+ name: 'Plain Text',
+ menuItem: WIP_GridMenuItem,
+ cssClasses: ['!opacity-100'],
+ disabled: true,
+ },
+ {
+ name: 'PDF Attachment',
+ menuItem: WIP_GridMenuItem,
+ cssClasses: ['!opacity-100'],
+ disabled: true,
+ },
+ {
+ name: 'Excel Attachment',
+ menuItem: WIP_GridMenuItem,
+ cssClasses: ['!opacity-100'],
+ disabled: true,
+ },
+ {
+ name: 'CSV Attachment',
+ menuItem: WIP_GridMenuItem,
+ cssClasses: ['!opacity-100'],
+ disabled: true,
+ },
+ {
+ name: 'DataCube Specification Attachment',
+ menuItem: WIP_GridMenuItem,
+ cssClasses: ['!opacity-100'],
+ disabled: true,
+ },
+ ],
+ },
+ {
+ name: 'Copy',
+ menuItem: WIP_GridMenuItem,
+ cssClasses: ['!opacity-100'],
+ subMenu: [
+ {
+ name: 'Plain Text',
+ menuItem: WIP_GridMenuItem,
+ cssClasses: ['!opacity-100'],
+ disabled: true,
+ },
+ {
+ name: 'Selected Row(s) as Plain Text',
+ menuItem: WIP_GridMenuItem,
+ cssClasses: ['!opacity-100'],
+ disabled: true,
+ },
+ {
+ name: 'Selected Column as Plain Text',
+ menuItem: WIP_GridMenuItem,
+ cssClasses: ['!opacity-100'],
+ disabled: true,
+ },
+ ],
+ },
+ 'separator',
+ buildGridSortsMenu(editor, column, value),
+ {
+ name: 'Filter',
+ menuItem: WIP_GridMenuItem,
+ disabled: true,
+ cssClasses: ['!opacity-100'],
+ subMenu: [
+ ...(column && value
+ ? [
+ {
+ name: `Add Filter: ${column.getColId()} = {value}`,
+ menuItem: WIP_GridMenuItem,
+ cssClasses: ['!opacity-100'],
+ disabled: true,
+ },
+ {
+ name: `More Filters on ${column.getColId()}...`,
+ menuItem: WIP_GridMenuItem,
+ cssClasses: ['!opacity-100'],
+ disabled: true,
+ subMenu: [], // TODO
+ },
+ 'separator',
+ ]
+ : []),
+ {
+ name: 'Filters...',
+ },
+ {
+ name: 'Clear All Filters',
+ },
+ ],
+ },
+ {
+ name: 'Pivot',
+ menuItem: WIP_GridMenuItem,
+ disabled: true,
+ cssClasses: ['!opacity-100'],
+ subMenu: [
+ ...(column
+ ? [
+ {
+ name: `VPivot on ${column.getColId()}`,
+ menuItem: WIP_GridMenuItem,
+ cssClasses: ['!opacity-100'],
+ disabled: true,
+ },
+ {
+ name: `Add VPivot on ${column.getColId()}`,
+ menuItem: WIP_GridMenuItem,
+ cssClasses: ['!opacity-100'],
+ disabled: true,
+ },
+ {
+ name: `Remove VPivot on ${column.getColId()}`,
+ menuItem: WIP_GridMenuItem,
+ cssClasses: ['!opacity-100'],
+ disabled: true,
+ },
+ 'separator',
+ ]
+ : []),
+ {
+ name: `Clear All VPivots`,
+ menuItem: WIP_GridMenuItem,
+ cssClasses: ['!opacity-100'],
+ disabled: true,
+ },
+ ],
+ },
+ {
+ name: 'Heatmap',
+ menuItem: WIP_GridMenuItem,
+ cssClasses: ['!opacity-100'],
+ disabled: !column,
+ subMenu: column
+ ? [
+ {
+ name: `Add to ${column.getColId()}`,
+ menuItem: WIP_GridMenuItem,
+ cssClasses: ['!opacity-100'],
+ disabled: true,
+ },
+ {
+ name: `Remove from ${column.getColId()}`,
+ menuItem: WIP_GridMenuItem,
+ cssClasses: ['!opacity-100'],
+ disabled: true,
+ },
+ ]
+ : [],
+ },
+ {
+ name: 'Extended Columns',
+ menuItem: WIP_GridMenuItem,
+ cssClasses: ['!opacity-100'],
+ disabled: true,
+ subMenu: [
+ {
+ name: `Add New Column...`,
+ menuItem: WIP_GridMenuItem,
+ cssClasses: ['!opacity-100'],
+ disabled: true,
+ },
+ {
+ name: `Edit {column}`,
+ menuItem: WIP_GridMenuItem,
+ cssClasses: ['!opacity-100'],
+ disabled: true,
+ },
+ {
+ name: `Remove {column}`,
+ menuItem: WIP_GridMenuItem,
+ cssClasses: ['!opacity-100'],
+ disabled: true,
+ },
+ ],
+ },
+ {
+ name: 'Custom Groupings',
+ menuItem: WIP_GridMenuItem,
+ cssClasses: ['!opacity-100'],
+ disabled: true,
+ subMenu: [
+ {
+ name: `Add New Grouping...`,
+ menuItem: WIP_GridMenuItem,
+ cssClasses: ['!opacity-100'],
+ disabled: true,
+ },
+ {
+ name: `Edit {column}`,
+ menuItem: WIP_GridMenuItem,
+ cssClasses: ['!opacity-100'],
+ disabled: true,
+ },
+ {
+ name: `Remove {column}`,
+ menuItem: WIP_GridMenuItem,
+ cssClasses: ['!opacity-100'],
+ disabled: true,
+ },
+ ],
+ },
+ 'separator',
+ {
+ name: 'Resize',
+ menuItem: WIP_GridMenuItem,
+ cssClasses: ['!opacity-100'],
+ disabled: true,
+ subMenu: [
+ {
+ name: `Size to Fit Content`,
+ menuItem: WIP_GridMenuItem,
+ cssClasses: ['!opacity-100'],
+ disabled: true,
+ },
+ {
+ name: `Autosize`,
+ menuItem: WIP_GridMenuItem,
+ cssClasses: ['!opacity-100'],
+ disabled: true,
+ },
+ 'separator',
+ {
+ name: `Autosize All Columns`,
+ menuItem: WIP_GridMenuItem,
+ cssClasses: ['!opacity-100'],
+ disabled: true,
+ },
+ ],
+ },
+ {
+ name: 'Pin',
+ menuItem: WIP_GridMenuItem,
+ cssClasses: ['!opacity-100'],
+ disabled: true,
+ subMenu: [
+ {
+ name: `Pin Left`,
+ menuItem: WIP_GridMenuItem,
+ cssClasses: ['!opacity-100'],
+ disabled: true,
+ },
+ {
+ name: `Pin Right`,
+ menuItem: WIP_GridMenuItem,
+ cssClasses: ['!opacity-100'],
+ disabled: true,
+ },
+ 'separator',
+ {
+ name: `Remove Pinning`,
+ menuItem: WIP_GridMenuItem,
+ cssClasses: ['!opacity-100'],
+ disabled: true,
+ },
+ ],
+ },
+ {
+ name: 'Hide',
+ menuItem: WIP_GridMenuItem,
+ cssClasses: ['!opacity-100'],
+ disabled: true,
+ },
+ 'separator',
+ {
+ name: 'Show Plot...',
+ menuItem: WIP_GridMenuItem,
+ cssClasses: ['!opacity-100'],
+ disabled: true,
+ },
+ {
+ name: 'Show TreeMap...',
+ menuItem: WIP_GridMenuItem,
+ cssClasses: ['!opacity-100'],
+ disabled: true,
+ },
+ 'separator',
+ {
+ name: 'Properties...',
+ disabled: editor.isPanelOpen,
+ action: () => {
+ if (!editor.isPanelOpen) {
+ editor.openPanel();
+ }
+ },
+ },
+ ];
+ return result;
+}
diff --git a/packages/legend-application-repl/src/components/dataCube/grid/menu/DataCubeGridSortsMenu.tsx b/packages/legend-application-repl/src/components/dataCube/grid/menu/DataCubeGridSortsMenu.tsx
new file mode 100644
index 0000000000..113ccfc69c
--- /dev/null
+++ b/packages/legend-application-repl/src/components/dataCube/grid/menu/DataCubeGridSortsMenu.tsx
@@ -0,0 +1,120 @@
+/**
+ * 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 { Column, MenuItemDef } from '@ag-grid-community/core';
+import type { DataCubeEditorState } from '../../../../stores/dataCube/editor/DataCubeEditorState.js';
+import { DataCubeQuerySnapshotSortOperation } from '../../../../stores/dataCube/core/DataCubeQuerySnapshot.js';
+import { WIP_GridMenuItem } from '../DataCubeGridShared.js';
+
+export function buildGridSortsMenu(
+ editor: DataCubeEditorState,
+ column: Column | undefined,
+ value: unknown,
+): MenuItemDef {
+ if (!column) {
+ return {
+ name: 'Sort',
+ disabled: true,
+ subMenu: [],
+ };
+ }
+
+ return {
+ name: 'Sort',
+ subMenu: [
+ {
+ name: 'Ascending',
+ disabled: !editor.sortsPanel.getActionableSortColumn(
+ column.getColId(),
+ DataCubeQuerySnapshotSortOperation.ASCENDING,
+ ),
+ action: () =>
+ editor.sortsPanel.sortByColumn(
+ column.getColId(),
+ DataCubeQuerySnapshotSortOperation.ASCENDING,
+ ),
+ },
+ {
+ name: 'Ascending Absolute',
+ menuItem: WIP_GridMenuItem,
+ cssClasses: ['!opacity-100'],
+ disabled: true,
+ },
+ {
+ name: 'Descending',
+ disabled: !editor.sortsPanel.getActionableSortColumn(
+ column.getColId(),
+ DataCubeQuerySnapshotSortOperation.DESCENDING,
+ ),
+ action: () =>
+ editor.sortsPanel.sortByColumn(
+ column.getColId(),
+ DataCubeQuerySnapshotSortOperation.DESCENDING,
+ ),
+ },
+ {
+ name: 'Descending Absolute',
+ menuItem: WIP_GridMenuItem,
+ cssClasses: ['!opacity-100'],
+ disabled: true,
+ },
+ 'separator',
+ {
+ name: 'Add Ascending',
+ disabled: !editor.sortsPanel.getActionableSortColumn(
+ column.getColId(),
+ DataCubeQuerySnapshotSortOperation.ASCENDING,
+ ),
+ action: () =>
+ editor.sortsPanel.addSortByColumn(
+ column.getColId(),
+ DataCubeQuerySnapshotSortOperation.ASCENDING,
+ ),
+ },
+ {
+ name: 'Add Ascending Absolute',
+ menuItem: WIP_GridMenuItem,
+ cssClasses: ['!opacity-100'],
+ disabled: true,
+ },
+ {
+ name: 'Add Descending',
+ disabled: !editor.sortsPanel.getActionableSortColumn(
+ column.getColId(),
+ DataCubeQuerySnapshotSortOperation.DESCENDING,
+ ),
+ action: () =>
+ editor.sortsPanel.addSortByColumn(
+ column.getColId(),
+ DataCubeQuerySnapshotSortOperation.DESCENDING,
+ ),
+ },
+ {
+ name: 'Add Descending Absolute',
+ menuItem: WIP_GridMenuItem,
+ cssClasses: ['!opacity-100'],
+ disabled: true,
+ },
+ 'separator',
+ {
+ name: 'Clear All Sorts',
+ disabled:
+ editor.sortsPanel.columnsSelector.selectedColumns.length === 0,
+ action: () => editor.sortsPanel.clearAllSorts(),
+ },
+ ],
+ };
+}
diff --git a/packages/legend-application-repl/src/server/models/DataCubeQuery.ts b/packages/legend-application-repl/src/server/models/DataCubeQuery.ts
index 5cb08b1bd6..09924c5b0f 100644
--- a/packages/legend-application-repl/src/server/models/DataCubeQuery.ts
+++ b/packages/legend-application-repl/src/server/models/DataCubeQuery.ts
@@ -97,21 +97,17 @@ function serializeQuerySource(
);
}
-export class DataCubeConfiguration {
- // TODO
-}
-
export class DataCubeQuery {
name!: string;
query!: string;
partialQuery!: string;
source!: DataCubeQuerySource;
- configuration!: DataCubeConfiguration;
+ configuration?: PlainObject | undefined;
constructor(
name: string,
query: string,
- configuration: DataCubeConfiguration,
+ configuration?: PlainObject | undefined,
) {
this.name = name;
this.query = query;
diff --git a/packages/legend-application-repl/src/stores/dataCube/DataCubeState.ts b/packages/legend-application-repl/src/stores/dataCube/DataCubeState.ts
index f7d39711c8..a7b0c42943 100644
--- a/packages/legend-application-repl/src/stores/dataCube/DataCubeState.ts
+++ b/packages/legend-application-repl/src/stores/dataCube/DataCubeState.ts
@@ -17,12 +17,28 @@
import type { REPLStore } from './REPLStore.js';
import { DataCubeGridState } from './grid/DataCubeGridState.js';
import { DataCubeEditorState } from './editor/DataCubeEditorState.js';
-import { ActionState, assertErrorThrown } from '@finos/legend-shared';
+import { assertErrorThrown, uuid } from '@finos/legend-shared';
import { DataCubeEngine } from './core/DataCubeEngine.js';
import { DataCubeQuerySnapshotManager } from './core/DataCubeQuerySnapshotManager.js';
import type { LegendREPLApplicationStore } from '../LegendREPLBaseStore.js';
import { DataCubeCoreState } from './core/DataCubeCoreState.js';
import { validateAndBuildQuerySnapshot } from './core/DataCubeQuerySnapshotBuilder.js';
+import { action, makeObservable, observable } from 'mobx';
+
+export class DataCubeTask {
+ uuid = uuid();
+ name: string;
+ startTime = Date.now();
+ endTime?: number | undefined;
+
+ constructor(name: string) {
+ this.name = name;
+ }
+
+ end(): void {
+ this.endTime = Date.now();
+ }
+}
export class DataCubeState {
readonly replStore: REPLStore;
@@ -34,9 +50,15 @@ export class DataCubeState {
readonly grid: DataCubeGridState;
readonly editor: DataCubeEditorState;
- readonly initState = ActionState.create();
+ readonly runningTaskes = new Map();
constructor(replStore: REPLStore) {
+ makeObservable(this, {
+ runningTaskes: observable,
+ newTask: action,
+ endTask: action,
+ });
+
this.replStore = replStore;
this.application = replStore.applicationStore;
this.engine = new DataCubeEngine(this.replStore.client);
@@ -48,8 +70,20 @@ export class DataCubeState {
this.editor = new DataCubeEditorState(this);
}
+ newTask(name: string): DataCubeTask {
+ const task = new DataCubeTask(name);
+ this.runningTaskes.set(task.uuid, task);
+ return task;
+ }
+
+ endTask(task: DataCubeTask): DataCubeTask {
+ task.end();
+ this.runningTaskes.delete(task.uuid);
+ return task;
+ }
+
async initialize(): Promise {
- this.initState.inProgress();
+ const task = this.newTask('Initializing');
try {
await Promise.all(
[this.core, this.editor, this.grid].map(async (state) => {
@@ -65,11 +99,11 @@ export class DataCubeState {
);
initialSnapshot.timestamp = result.timestamp;
this.snapshotManager.broadcastSnapshot(initialSnapshot);
- this.initState.complete();
} catch (error: unknown) {
assertErrorThrown(error);
this.application.notificationService.notifyError(error);
- this.initState.fail();
+ } finally {
+ this.endTask(task);
}
}
}
diff --git a/packages/legend-application-repl/src/stores/dataCube/REPLStore.ts b/packages/legend-application-repl/src/stores/dataCube/REPLStore.ts
index ae1fd4d73d..b03f21bb87 100644
--- a/packages/legend-application-repl/src/stores/dataCube/REPLStore.ts
+++ b/packages/legend-application-repl/src/stores/dataCube/REPLStore.ts
@@ -25,11 +25,11 @@ export class REPLStore {
readonly client: REPLServerClient;
// TODO: when we support multi-view, we would need to support multiple states
- dataCubeState!: DataCubeState;
+ dataCube!: DataCubeState;
constructor(applicationStore: LegendREPLApplicationStore) {
makeObservable(this, {
- dataCubeState: observable,
+ dataCube: observable,
});
this.applicationStore = applicationStore;
this.client = new REPLServerClient(
@@ -40,6 +40,6 @@ export class REPLStore {
: this.applicationStore.config.replUrl,
}),
);
- this.dataCubeState = new DataCubeState(this);
+ this.dataCube = new DataCubeState(this);
}
}
diff --git a/packages/legend-application-repl/src/stores/dataCube/core/DataCubeConfiguration.ts b/packages/legend-application-repl/src/stores/dataCube/core/DataCubeConfiguration.ts
new file mode 100644
index 0000000000..bbcc6327d9
--- /dev/null
+++ b/packages/legend-application-repl/src/stores/dataCube/core/DataCubeConfiguration.ts
@@ -0,0 +1,200 @@
+/**
+ * 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 { TailwindCSSPalette } from '@finos/legend-art';
+import {
+ DataCubeColumnKind,
+ DataCubeFont,
+ DataCubeFontTextAlignment,
+ DEFAULT_ROW_BUFFER,
+ DEFAULT_BACKGROUND_COLOR,
+ DEFAULT_ERROR_FOREGROUND_COLOR,
+ DEFAULT_FOREGROUND_COLOR,
+ DEFAULT_NEGATIVE_FOREGROUND_COLOR,
+ DEFAULT_ROW_HIGHLIGHT_BACKGROUND_COLOR,
+ DEFAULT_ZERO_FOREGROUND_COLOR,
+ type DataCubeFontFormatUnderlinedVariant,
+ type DataCubeNumberScale,
+ type DataCubeSelectionStat,
+ type DataCubeColumnPinPlacement,
+} from './DataCubeQueryEngine.js';
+import { SerializationFactory, usingModelSchema } from '@finos/legend-shared';
+import { createModelSchema, list, optional, primitive } from 'serializr';
+
+export class DataCubeColumnConfiguration {
+ name: string;
+ type: string;
+
+ kind: DataCubeColumnKind = DataCubeColumnKind.DIMENSION;
+ displayName?: string | undefined;
+
+ decimals?: number | undefined;
+ displayCommas = false;
+ negativeNumberInParens = false;
+ numberScale?: DataCubeNumberScale | undefined;
+
+ hPivotSortFunction?: string | undefined;
+
+ fontFamily = DataCubeFont.ROBOTO;
+ fontSize = 8;
+ fontBold = false;
+ fontItalic = false;
+ fontUnderlined?: DataCubeFontFormatUnderlinedVariant | undefined = undefined;
+ fontStrikethrough = false;
+ textAlign = DataCubeFontTextAlignment.LEFT;
+ foregroundColor = TailwindCSSPalette.black;
+ foregroundNegativeColor = DEFAULT_NEGATIVE_FOREGROUND_COLOR;
+ foregroundZeroColor = DEFAULT_ZERO_FOREGROUND_COLOR;
+ foregroundErrorColor = DEFAULT_ERROR_FOREGROUND_COLOR;
+ backgroundColor = DEFAULT_BACKGROUND_COLOR;
+ backgroundNegativeColor = DEFAULT_BACKGROUND_COLOR;
+ backgroundZeroColor = DEFAULT_BACKGROUND_COLOR;
+ backgroundErrorColor = DEFAULT_BACKGROUND_COLOR;
+
+ blur = false;
+ hideFromView = false;
+
+ fixedWidth?: number | undefined;
+ minWidth?: number | undefined;
+ maxWidth?: number | undefined;
+ pinned?: DataCubeColumnPinPlacement | undefined;
+ displayAsLink = false;
+
+ constructor(name: string, type: string) {
+ this.name = name;
+ this.type = type;
+ }
+
+ static readonly serialization = new SerializationFactory(
+ createModelSchema(DataCubeColumnConfiguration, {
+ backgroundColor: primitive(),
+ backgroundErrorColor: primitive(),
+ backgroundNegativeColor: primitive(),
+ backgroundZeroColor: primitive(),
+ decimals: optional(primitive()),
+ displayAsLink: primitive(),
+ displayCommas: primitive(),
+ displayName: optional(primitive()),
+ fixedWidth: optional(primitive()),
+ foregroundColor: primitive(),
+ foregroundErrorColor: primitive(),
+ foregroundNegativeColor: primitive(),
+ foregroundZeroColor: primitive(),
+ fontBold: primitive(),
+ fontFamily: primitive(),
+ fontItalic: primitive(),
+ fontSize: primitive(),
+ fontStrikethrough: primitive(),
+ fontUnderlined: optional(primitive()),
+ hPivotSortFunction: optional(primitive()),
+ kind: primitive(),
+ maxWidth: optional(primitive()),
+ minWidth: optional(primitive()),
+ name: primitive(),
+ negativeNumberInParens: primitive(),
+ numberScale: optional(primitive()),
+ pinned: optional(primitive()),
+ textAlign: primitive(),
+ type: primitive(),
+ }),
+ );
+}
+
+export class DataCubeConfiguration {
+ description?: string | undefined;
+ columns: DataCubeColumnConfiguration[] = [];
+
+ showTreeLine = true;
+ showHorizontalGridLine = false;
+ showVerticalGridLine = false;
+ defaultFontFamily = DataCubeFont.ROBOTO;
+ defaultFontSize = 12;
+ defaultFontBold = false;
+ defaultFontItalic = false;
+ defaultFontUnderlined?: DataCubeFontFormatUnderlinedVariant | undefined =
+ undefined;
+ defaultFontStrikethrough = false;
+ defaultTextAlign = DataCubeFontTextAlignment.LEFT;
+ defaultForegroundColor = DEFAULT_FOREGROUND_COLOR;
+ defaultForegroundNegativeColor = DEFAULT_NEGATIVE_FOREGROUND_COLOR;
+ defaultForegroundZeroColor = DEFAULT_ZERO_FOREGROUND_COLOR;
+ defaultForegroundErrorColor = DEFAULT_ERROR_FOREGROUND_COLOR;
+ defaultBackgroundColor = DEFAULT_BACKGROUND_COLOR;
+ defaultBackgroundNegativeColor = DEFAULT_BACKGROUND_COLOR;
+ defaultBackgroundZeroColor = DEFAULT_BACKGROUND_COLOR;
+ defaultBackgroundErrorColor = DEFAULT_BACKGROUND_COLOR;
+ alternateRows = true;
+ alternateRowsColor = DEFAULT_ROW_HIGHLIGHT_BACKGROUND_COLOR;
+ alternateRowsCount = 1;
+
+ // manualRefresh: boolean;
+ numberScale?: DataCubeNumberScale | undefined;
+ selectionStats: DataCubeSelectionStat[] = [];
+
+ showWarningForTruncatedResult = true;
+
+ // aggregation
+ initialExpandLevel?: number | undefined;
+ showRootAggregation = false;
+ showLeafCount = true;
+ addPivotTotalColumn = true;
+ addPivotTotalColumnOnLeft = true;
+ treeGroupSortFunction?: string | undefined;
+
+ // advanced
+ rowBuffer = DEFAULT_ROW_BUFFER;
+
+ static readonly serialization = new SerializationFactory(
+ createModelSchema(DataCubeConfiguration, {
+ addPivotTotalColumn: primitive(),
+ addPivotTotalColumnOnLeft: primitive(),
+ alternateRows: primitive(),
+ alternateRowsColor: primitive(),
+ alternateRowsCount: primitive(),
+ columns: list(
+ usingModelSchema(DataCubeColumnConfiguration.serialization.schema),
+ ),
+ defaultBackgroundColor: primitive(),
+ defaultBackgroundErrorColor: primitive(),
+ defaultBackgroundNegativeColor: primitive(),
+ defaultBackgroundZeroColor: primitive(),
+ defaultFontBold: primitive(),
+ defaultFontFamily: primitive(),
+ defaultFontItalic: primitive(),
+ defaultFontSize: primitive(),
+ defaultFontStrikethrough: primitive(),
+ defaultFontUnderlined: optional(primitive()),
+ defaultForegroundColor: primitive(),
+ defaultForegroundErrorColor: primitive(),
+ defaultForegroundNegativeColor: primitive(),
+ defaultForegroundZeroColor: primitive(),
+ defaultTextAlign: primitive(),
+ description: optional(primitive()),
+ initialExpandLevel: optional(primitive()),
+
+ numberScale: optional(primitive()),
+ rowBuffer: primitive(),
+ selectionStats: list(primitive()),
+ showHorizontalGridLine: primitive(),
+ showLeafCount: primitive(),
+ showRootAggregation: primitive(),
+ showTreeLine: primitive(),
+ showVerticalGridLine: primitive(),
+ showWarningForTruncatedResult: primitive(),
+ treeGroupSortFunction: optional(primitive()),
+ }),
+ );
+}
diff --git a/packages/legend-application-repl/src/stores/dataCube/core/DataCubeConfigurationBuilder.ts b/packages/legend-application-repl/src/stores/dataCube/core/DataCubeConfigurationBuilder.ts
new file mode 100644
index 0000000000..0469265056
--- /dev/null
+++ b/packages/legend-application-repl/src/stores/dataCube/core/DataCubeConfigurationBuilder.ts
@@ -0,0 +1,56 @@
+/**
+ * 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 { PRIMITIVE_TYPE } from '@finos/legend-graph';
+import {
+ DataCubeColumnConfiguration,
+ DataCubeConfiguration,
+} from './DataCubeConfiguration.js';
+import { DataCubeColumnKind } from './DataCubeQueryEngine.js';
+
+export function buildDefaultColumnConfiguration(column: {
+ name: string;
+ type: string;
+}): DataCubeColumnConfiguration {
+ const { name, type } = column;
+ const config = new DataCubeColumnConfiguration(name, type);
+ switch (type) {
+ case PRIMITIVE_TYPE.NUMBER:
+ case PRIMITIVE_TYPE.INTEGER:
+ case PRIMITIVE_TYPE.DECIMAL:
+ case PRIMITIVE_TYPE.FLOAT: {
+ config.kind = DataCubeColumnKind.MEASURE;
+ config.decimals = type === PRIMITIVE_TYPE.INTEGER ? 0 : 2;
+ config.displayCommas = true;
+ config.negativeNumberInParens = true;
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ return config;
+}
+
+export function buildDefaultConfiguration(
+ columns: { name: string; type: string }[],
+): DataCubeConfiguration {
+ const configuration = new DataCubeConfiguration();
+ configuration.columns = columns.map((column) =>
+ buildDefaultColumnConfiguration(column),
+ );
+ return configuration;
+}
diff --git a/packages/legend-application-repl/src/stores/dataCube/core/DataCubeCoreState.ts b/packages/legend-application-repl/src/stores/dataCube/core/DataCubeCoreState.ts
index e7b0abfb7c..bec83196c3 100644
--- a/packages/legend-application-repl/src/stores/dataCube/core/DataCubeCoreState.ts
+++ b/packages/legend-application-repl/src/stores/dataCube/core/DataCubeCoreState.ts
@@ -18,13 +18,13 @@ import { action, makeObservable, observable } from 'mobx';
import type { DataCubeState } from '../DataCubeState.js';
import { DataCubeQuerySnapshotSubscriber } from './DataCubeQuerySnapshotSubscriber.js';
import type { DataCubeQuerySnapshot } from './DataCubeQuerySnapshot.js';
-import { DATA_CUBE_DEFAULT_REPORT_NAME } from '../DataCubeDefaultConfig.js';
import type { DataCubeQuery } from '../../../server/models/DataCubeQuery.js';
import { formatDate } from '@finos/legend-shared';
+import { DEFAULT_REPORT_NAME } from './DataCubeQueryEngine.js';
export class DataCubeCoreState extends DataCubeQuerySnapshotSubscriber {
baseQuery!: DataCubeQuery;
- name = DATA_CUBE_DEFAULT_REPORT_NAME;
+ name = DEFAULT_REPORT_NAME;
private startTime?: number | undefined;
constructor(dataCube: DataCubeState) {
@@ -47,7 +47,7 @@ export class DataCubeCoreState extends DataCubeQuerySnapshotSubscriber {
this.startTime = snapshot.timestamp;
}
this.application.layoutService.setWindowTitle(
- `\u25A6 ${data.name}${this.startTime ? ` - ${formatDate(new Date(this.startTime), 'HH:mm:ss EEE MMM dd yyyy')}` : ''}`,
+ `\u229E ${data.name}${this.startTime ? ` - ${formatDate(new Date(this.startTime), 'HH:mm:ss EEE MMM dd yyyy')}` : ''}`,
);
}
diff --git a/packages/legend-application-repl/src/stores/dataCube/core/DataCubeQueryBuilder.ts b/packages/legend-application-repl/src/stores/dataCube/core/DataCubeQueryBuilder.ts
index dd99acebb1..dd803bccfd 100644
--- a/packages/legend-application-repl/src/stores/dataCube/core/DataCubeQueryBuilder.ts
+++ b/packages/legend-application-repl/src/stores/dataCube/core/DataCubeQueryBuilder.ts
@@ -51,7 +51,7 @@ import {
type DataCubeQuerySnapshotFilterCondition,
type DataCubeQuerySnapshotFilter,
type DataCubeQuerySnapshot,
- DataCubeQuerySnapshotSortDirection,
+ DataCubeQuerySnapshotSortOperation,
DataCubeQuerySnapshotFilterOperation,
DataCubeQueryFilterGroupOperation,
_findCol,
@@ -347,6 +347,17 @@ export function buildExecutableQuery(
);
}
+ // --------------------------------- SELECT ---------------------------------
+
+ if (data.selectColumns.length) {
+ _process(
+ 'select',
+ _function(_name(DataCubeFunction.SELECT), [
+ _cols(data.selectColumns.map((col) => _colSpec(col.name))),
+ ]),
+ );
+ }
+
// --------------------------------- FILTER ---------------------------------
if (data.filter) {
@@ -398,17 +409,6 @@ export function buildExecutableQuery(
);
}
- // --------------------------------- SELECT ---------------------------------
-
- if (data.selectColumns.length) {
- _process(
- 'select',
- _function(_name(DataCubeFunction.SELECT), [
- _cols(data.selectColumns.map((col) => _colSpec(col.name))),
- ]),
- );
- }
-
// --------------------------------- SORT ---------------------------------
if (data.sortColumns.length) {
@@ -419,7 +419,7 @@ export function buildExecutableQuery(
data.sortColumns.map((col) =>
_function(
_name(
- col.direction === DataCubeQuerySnapshotSortDirection.ASCENDING
+ col.operation === DataCubeQuerySnapshotSortOperation.ASCENDING
? DataCubeFunction.ASC
: DataCubeFunction.DESC,
),
diff --git a/packages/legend-application-repl/src/stores/dataCube/core/DataCubeQueryEngine.ts b/packages/legend-application-repl/src/stores/dataCube/core/DataCubeQueryEngine.ts
index 080c8c5adc..9136fbf8ab 100644
--- a/packages/legend-application-repl/src/stores/dataCube/core/DataCubeQueryEngine.ts
+++ b/packages/legend-application-repl/src/stores/dataCube/core/DataCubeQueryEngine.ts
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-import type { V1_AppliedFunction } from '@finos/legend-graph';
+import { TailwindCSSPalette } from '@finos/legend-art';
+import { PRIMITIVE_TYPE, type V1_AppliedFunction } from '@finos/legend-graph';
export enum DataCubeFunction {
// relation
@@ -62,11 +63,15 @@ export enum DataCubeFunction {
MAX = 'meta::pure::functions::collection::max',
MIN = 'meta::pure::functions::collection::min',
SUM = 'meta::pure::functions::math::sum',
- STD_DEV_POPULATION = 'meta::pure::functions::math::stdDevPopulation',
- STD_DEV_SAMPLE = 'meta::pure::functions::math::stdDevSample',
- UNIQUE_VALUE_ONLY = 'meta::pure::functions::collection::uniqueValueOnly',
+ STDDEV_POP = 'meta::pure::functions::math::stdDevPopulation',
+ STDDEV_SAMP = 'meta::pure::functions::math::stdDevSample',
+ VAR_POP = 'meta::pure::functions::math::variancePopulation',
+ VAR_SAMP = 'meta::pure::functions::math::varianceSample',
+ // UNIQUE_VALUE_ONLY = 'meta::pure::functions::collection::uniqueValueOnly',
+ // PERCENTILE = 'meta::pure::functions::math::percentile',
}
+export const DEFAULT_REPORT_NAME = 'New Report';
export const DEFAULT_LAMBDA_VARIABLE_NAME = 'x';
export const PIVOT_COLUMN_NAME_VALUE_SEPARATOR = '__|__';
@@ -74,6 +79,7 @@ export const PIVOT_COLUMN_NAME_VALUE_SEPARATOR = '__|__';
// when no aggregate is specified in groupBy() or pivot()
export const INTERNAL__FILLER_COUNT_AGG_COLUMN_NAME =
'INTERNAL__filler_count_agg_column';
+export const DEFAULT_ROW_BUFFER = 50;
export type DataCubeQueryFunctionMap = {
leafExtend?: V1_AppliedFunction | undefined;
@@ -88,3 +94,129 @@ export type DataCubeQueryFunctionMap = {
sort?: V1_AppliedFunction | undefined;
limit?: V1_AppliedFunction | undefined;
};
+
+export enum DataCubeNumberScale {
+ BASIS_POINT = 'Basis Points (bp)',
+ PERCENT = 'Percent (%)',
+ THOUSANDS = 'Thousands (k)',
+ MILLIONS = 'Millions (m)',
+ BILLIONS = 'Billions (b)',
+ AUTO = 'Auto (k/m/b)',
+}
+
+export enum DataCubeSelectionStat {
+ COUNT = 'Count',
+ SUM = 'Sum',
+ MIN = 'Min',
+ MAX = 'Max',
+ AVERAGE = 'Average',
+}
+
+export enum DataCubeFont {
+ // sans-serif
+ ARIAL = 'Arial',
+ ROBOTO = 'Roboto',
+ ROBOTO_CONDENSED = 'Roboto Condensed',
+
+ // serif
+ TIMES_NEW_ROMAN = 'Times New Roman',
+ GEORGIA = 'Georgia',
+ ROBOTO_SERIF = 'Roboto Serif',
+
+ // monospaced
+ JERBRAINS_MONO = 'Jetbrains Mono',
+ ROBOTO_MONO = 'Roboto Mono',
+ UBUNTU_MONO = 'Ubuntu Mono',
+}
+
+export enum DataCubeFontTextAlignment {
+ CENTER = 'Center',
+ LEFT = 'Left',
+ RIGHT = 'Right',
+}
+
+export enum DataCubeColumnPinPlacement {
+ LEFT = 'Left',
+ RIGHT = 'Right',
+}
+
+export enum DataCubeColumnDataType {
+ NUMBER = 'number',
+ DATE = 'date',
+ TEXT = 'text',
+}
+
+export function getDataType(type: string): DataCubeColumnDataType {
+ switch (type) {
+ case PRIMITIVE_TYPE.NUMBER:
+ case PRIMITIVE_TYPE.INTEGER:
+ case PRIMITIVE_TYPE.DECIMAL:
+ case PRIMITIVE_TYPE.FLOAT:
+ return DataCubeColumnDataType.NUMBER;
+ case PRIMITIVE_TYPE.DATE:
+ case PRIMITIVE_TYPE.DATETIME:
+ case PRIMITIVE_TYPE.STRICTDATE:
+ return DataCubeColumnDataType.DATE;
+ case PRIMITIVE_TYPE.STRING:
+ default:
+ return DataCubeColumnDataType.TEXT;
+ }
+}
+
+export const DEFAULT_FOREGROUND_COLOR = TailwindCSSPalette.black;
+export const DEFAULT_BACKGROUND_COLOR = TailwindCSSPalette.white;
+export const DEFAULT_ROW_HIGHLIGHT_BACKGROUND_COLOR =
+ TailwindCSSPalette.sky[100];
+export const DEFAULT_NEGATIVE_FOREGROUND_COLOR = TailwindCSSPalette.red[500];
+export const DEFAULT_ZERO_FOREGROUND_COLOR = TailwindCSSPalette.neutral[400];
+export const DEFAULT_ERROR_FOREGROUND_COLOR = TailwindCSSPalette.blue[600];
+export const DEFAULT_COLUMN_WIDTH = 300;
+export const DEFAULT_COLUMN_MIN_WIDTH = 100;
+export const DEFAULT_COLUMN_MAX_WIDTH = undefined;
+
+export enum DataCubeFontFormatUnderlinedVariant {
+ SOLID = 'Solid',
+ DASHED = 'Dashed',
+ DOTTED = 'Dotted',
+ DOUBLE = 'Double',
+ WAVY = 'Wavy',
+}
+
+export enum DataCubeColumnKind {
+ MEASURE = 'Measure',
+ DIMENSION = 'Dimension',
+}
+
+export enum DataCubeAggregateFunction {
+ SUM = 'sum',
+ AVERAGE = 'avg',
+ COUNT = 'count',
+ MIN = 'min',
+ MAX = 'max',
+ // UNIQUE = 'uniq',
+ FIRST = 'first',
+ LAST = 'last',
+ MEDIAN = 'median',
+ VAR_POP = 'var_samp',
+ VAR_SAMP = 'var_pop',
+ STDDEV_POP = 'stddev_pop',
+ STDDEV_SAMP = 'stddev_samp',
+ // STANDARD_ERROR = 'stderr',
+ // NULL = 'null',
+ // ssq
+ // countvalid
+ // countnull
+ // uniqunstrict
+ // minmagnitude
+ // maxmagnitude
+ // commonprefix
+ // commonprefixunstrict
+ // strjoin
+ // strjoinuniq
+ // splitjoin
+ // daterange
+ // wavg
+ // wstderr
+ // wsum
+ // custom
+}
diff --git a/packages/legend-application-repl/src/stores/dataCube/core/DataCubeQuerySnapshot.ts b/packages/legend-application-repl/src/stores/dataCube/core/DataCubeQuerySnapshot.ts
index b176ad16b4..af277344ec 100644
--- a/packages/legend-application-repl/src/stores/dataCube/core/DataCubeQuerySnapshot.ts
+++ b/packages/legend-application-repl/src/stores/dataCube/core/DataCubeQuerySnapshot.ts
@@ -15,10 +15,12 @@
*/
import type { V1_Lambda, V1_ValueSpecification } from '@finos/legend-graph';
-import type { DataCubeConfiguration } from '../../../server/models/DataCubeQuery.js';
+import type { DataCubeConfiguration } from './DataCubeConfiguration.js';
import {
IllegalStateError,
guaranteeNonNullable,
+ hashObject,
+ pruneObject,
uuid,
type PlainObject,
type Writable,
@@ -54,7 +56,7 @@ export enum DataCubeQuerySnapshotFilterOperation {
ENDS_WITH = 'endsWith',
}
-export enum DataCubeQuerySnapshotSortDirection {
+export enum DataCubeQuerySnapshotSortOperation {
ASCENDING = 'ascending',
DESCENDING = 'descending',
}
@@ -90,7 +92,7 @@ export type DataCubeQuerySnapshotExtendedColumn =
};
export type DataCubeQuerySnapshotSortColumn = DataCubeQuerySnapshotColumn & {
- direction: DataCubeQuerySnapshotSortDirection;
+ operation: DataCubeQuerySnapshotSortOperation;
};
export type DataCubeQuerySnapshotAggregateColumn =
@@ -113,7 +115,7 @@ export type DataCubeQuerySnapshotData = {
name: string;
runtime: string;
sourceQuery: PlainObject;
- configuration: DataCubeConfiguration;
+ configuration: PlainObject;
originalColumns: DataCubeQuerySnapshotColumn[];
leafExtendedColumns: DataCubeQuerySnapshotExtendedColumn[];
filter?: DataCubeQuerySnapshotFilter | undefined;
@@ -138,11 +140,14 @@ export class DataCubeQuerySnapshot {
timestamp = Date.now();
readonly data: DataCubeQuerySnapshotData;
+ private _finalized = false;
+ private _hashCode?: string | undefined;
+
private constructor(
name: string,
runtime: string,
sourceQuery: PlainObject,
- configuration: DataCubeConfiguration,
+ configuration: PlainObject,
) {
this.data = {
name,
@@ -165,7 +170,7 @@ export class DataCubeQuerySnapshot {
name: string,
runtime: string,
sourceQuery: PlainObject,
- configuration: DataCubeConfiguration,
+ configuration: PlainObject,
) {
return new DataCubeQuerySnapshot(name, runtime, sourceQuery, configuration);
}
@@ -204,6 +209,38 @@ export class DataCubeQuerySnapshot {
throw new IllegalStateError(`Unknown stage '${stage}'`);
}
}
+
+ isFinalized(): boolean {
+ return this._finalized;
+ }
+
+ finalize(): DataCubeQuerySnapshot {
+ if (this._finalized) {
+ return this;
+ }
+ this._hashCode = this.computeHashCode();
+ this._finalized = true;
+ return this;
+ }
+
+ get hashCode(): string {
+ if (!this._finalized || !this._hashCode) {
+ throw new IllegalStateError('Snapshot is not finalized');
+ }
+ return this._hashCode;
+ }
+
+ /**
+ * NOTE: if this becomes a performance bottleneck, we can consider
+ * more granular hashing strategy
+ *
+ * Here, we are just hashing the raw object, but we must ensure
+ * to properly prune the snapshot data object before hashing
+ * else there would be mismatch
+ */
+ private computeHashCode(): string {
+ return hashObject(pruneObject(this.data));
+ }
}
export function _findCol(
diff --git a/packages/legend-application-repl/src/stores/dataCube/core/DataCubeQuerySnapshotBuilder.ts b/packages/legend-application-repl/src/stores/dataCube/core/DataCubeQuerySnapshotBuilder.ts
index 7bb351e38f..10d896d189 100644
--- a/packages/legend-application-repl/src/stores/dataCube/core/DataCubeQuerySnapshotBuilder.ts
+++ b/packages/legend-application-repl/src/stores/dataCube/core/DataCubeQuerySnapshotBuilder.ts
@@ -36,7 +36,7 @@ import {
import type { DataCubeQuery } from '../../../server/models/DataCubeQuery.js';
import {
DataCubeQuerySnapshot,
- DataCubeQuerySnapshotSortDirection,
+ DataCubeQuerySnapshotSortOperation,
type DataCubeQuerySnapshotColumn,
} from './DataCubeQuerySnapshot.js';
import {
@@ -50,6 +50,8 @@ import {
DataCubeFunction,
type DataCubeQueryFunctionMap,
} from './DataCubeQueryEngine.js';
+import { DataCubeConfiguration } from './DataCubeConfiguration.js';
+import { buildDefaultConfiguration } from './DataCubeConfigurationBuilder.js';
// --------------------------------- UTILITIES ---------------------------------
@@ -133,12 +135,12 @@ const _FUNCTION_SEQUENCE_COMPOSITION_PATTERN: {
required?: boolean | undefined;
}[] = [
{ func: DataCubeFunction.EXTEND },
+ { func: DataCubeFunction.SELECT },
{ func: DataCubeFunction.FILTER },
{ func: DataCubeFunction.GROUP_BY },
{ func: DataCubeFunction.PIVOT },
{ func: DataCubeFunction.CAST },
{ func: DataCubeFunction.EXTEND },
- { func: DataCubeFunction.SELECT },
{ func: DataCubeFunction.SORT },
{ func: DataCubeFunction.LIMIT },
];
@@ -269,19 +271,19 @@ function extractFunctionMap(
}
}
+ const select = sequence.find((func) =>
+ matchFunctionName(func.function, DataCubeFunction.SELECT),
+ );
const filter = sequence.find((func) =>
matchFunctionName(func.function, DataCubeFunction.FILTER),
);
const groupBy = sequence.find((func) =>
matchFunctionName(func.function, DataCubeFunction.GROUP_BY),
);
- const select = sequence.find((func) =>
- matchFunctionName(func.function, DataCubeFunction.SELECT),
- );
const pivot = sequence.find((func) =>
matchFunctionName(func.function, DataCubeFunction.PIVOT),
);
- const cast = sequence.find((func) =>
+ const pivotCast = sequence.find((func) =>
matchFunctionName(func.function, DataCubeFunction.CAST),
);
const sort = sequence.find((func) =>
@@ -292,12 +294,12 @@ function extractFunctionMap(
);
return {
leafExtend,
+ select,
filter,
groupBy,
pivot,
- pivotCast: cast,
+ pivotCast,
groupExtend,
- select,
sort,
limit,
};
@@ -326,7 +328,7 @@ export function validateAndBuildQuerySnapshot(
baseQuery.name,
baseQuery.source.runtime,
V1_serializeValueSpecification(sourceQuery, []),
- baseQuery.configuration,
+ {},
);
const data = snapshot.data;
const colsMap = new Map();
@@ -335,12 +337,25 @@ export function validateAndBuildQuerySnapshot(
// --------------------------------- SOURCE ---------------------------------
- data.originalColumns = baseQuery.source.columns;
+ data.originalColumns = baseQuery.source.columns.map((col) => ({
+ name: col.name,
+ type: col.type,
+ }));
data.originalColumns.map((col) => colsMap.set(col.name, col));
// --------------------------------- LEAF EXTEND ---------------------------------
// TODO: @akphi - implement this
+ // --------------------------------- SELECT ---------------------------------
+
+ if (funcMap.select) {
+ data.selectColumns = _colSpecArrayParam(funcMap.select, 0).colSpecs.map(
+ (colSpec) => ({
+ ..._col(colSpec),
+ }),
+ );
+ }
+
// --------------------------------- FILTER ---------------------------------
// TODO: @akphi - implement this
@@ -367,25 +382,15 @@ export function validateAndBuildQuerySnapshot(
]);
return {
..._col(_colSpecParam(sortColFunc, 0)),
- direction:
+ operation:
_name(sortColFunc.function) === DataCubeFunction.ASC
- ? DataCubeQuerySnapshotSortDirection.ASCENDING
- : DataCubeQuerySnapshotSortDirection.DESCENDING,
+ ? DataCubeQuerySnapshotSortOperation.ASCENDING
+ : DataCubeQuerySnapshotSortOperation.DESCENDING,
};
},
);
}
- // --------------------------------- SELECT ---------------------------------
-
- if (funcMap.select) {
- data.selectColumns = _colSpecArrayParam(funcMap.select, 0).colSpecs.map(
- (colSpec) => ({
- ..._col(colSpec),
- }),
- );
- }
-
// --------------------------------- LIMIT ---------------------------------
if (funcMap.limit) {
@@ -394,5 +399,21 @@ export function validateAndBuildQuerySnapshot(
data.limit = value.value;
}
- return snapshot;
+ // --------------------------------- CONFIGURATION ---------------------------------
+ // The data query takes precedence over the configuration, we do this for 2 reasons
+ // 1. The purpose of the configuration is to provide the layout and styling
+ // customization on top of the data query result grid. If conflicts happen between
+ // the configuration and the query, we will reconciliate by modifying the configuration
+ // 2. The configuration when missing, can be generated from default presets. This helps
+ // helps with use cases where the query might comes from a different source, such as
+ // Studio or Query, or another part of Engine.
+
+ const configuration = baseQuery.configuration
+ ? DataCubeConfiguration.serialization.fromJson(baseQuery.configuration)
+ : buildDefaultConfiguration(baseQuery.source.columns);
+ // TODO: @akphi - implement this
+ data.configuration =
+ DataCubeConfiguration.serialization.toJson(configuration);
+
+ return snapshot.finalize();
}
diff --git a/packages/legend-application-repl/src/stores/dataCube/core/DataCubeQuerySnapshotManager.ts b/packages/legend-application-repl/src/stores/dataCube/core/DataCubeQuerySnapshotManager.ts
index 4edd4ce5dd..4fcf3453a3 100644
--- a/packages/legend-application-repl/src/stores/dataCube/core/DataCubeQuerySnapshotManager.ts
+++ b/packages/legend-application-repl/src/stores/dataCube/core/DataCubeQuerySnapshotManager.ts
@@ -26,7 +26,7 @@ import {
} from '@finos/legend-shared';
import type { DataCubeQuery } from '../../../server/models/DataCubeQuery.js';
-// TODO: use this when we implement undo/redo
+// TODO: set a stack depth when we implement undo/redo
// const DATA_CUBE_MAX_SNAPSHOT_COUNT = 100;
export class DataCubeQuerySnapshotManager {
@@ -77,6 +77,13 @@ export class DataCubeQuerySnapshotManager {
}
broadcastSnapshot(snapshot: DataCubeQuerySnapshot): void {
+ if (!snapshot.isFinalized()) {
+ this.dataCube.application.logService.error(
+ LogEvent.create(APPLICATION_EVENT.ILLEGAL_APPLICATION_STATE_OCCURRED),
+ `Snapshot must be finalized before broadcasting`,
+ );
+ return;
+ }
this.snapshots.push(snapshot);
this.subscribers.forEach((subscriber) => {
const currentSnapshot = subscriber.getLatestSnapshot();
@@ -87,7 +94,7 @@ export class DataCubeQuerySnapshotManager {
LogEvent.create(
APPLICATION_EVENT.ILLEGAL_APPLICATION_STATE_OCCURRED,
),
- `Subscribers receiving and applying new snapshot should be handled gracefully`,
+ `Error occured while subscribers receiving and applying new snapshot should be handled gracefully`,
error,
);
});
diff --git a/packages/legend-application-repl/src/stores/dataCube/core/__tests__/DataCubeQueryAnalyzer.repl-test.ts b/packages/legend-application-repl/src/stores/dataCube/core/__tests__/DataCubeQueryAnalyzer.repl-test.ts
index 6ec469eadf..7d94b53ff9 100644
--- a/packages/legend-application-repl/src/stores/dataCube/core/__tests__/DataCubeQueryAnalyzer.repl-test.ts
+++ b/packages/legend-application-repl/src/stores/dataCube/core/__tests__/DataCubeQueryAnalyzer.repl-test.ts
@@ -57,8 +57,8 @@ const cases: BaseSnapshotAnalysisTestCase[] = [
'',
],
[
- 'Valid: Usage - Column Selection: extend()->filter()->select()->sort()->limit()',
- 'extend(~[a:x|1])->filter(x|$x.a==1)->select(~[a])->sort([ascending(~a)])->limit(10)',
+ 'Valid: Usage - Column Selection: extend()->select()->filter()->sort()->limit()',
+ 'extend(~[a:x|1])->select(~[a])->filter(x|$x.a==1)->sort([ascending(~a)])->limit(10)',
['a:Integer'],
'',
],
@@ -106,7 +106,7 @@ const cases: BaseSnapshotAnalysisTestCase[] = [
'Invalid: Unsupported function composition: filter()->extend()->filter()',
'filter(x|$x.a==1)->extend(~[a:x|1])->filter(x|$x.a==1)',
[],
- 'Unsupported function composition filter()->extend()->filter() (supported composition: extend()->filter()->groupBy()->pivot()->cast()->extend()->select()->sort()->limit())',
+ 'Unsupported function composition filter()->extend()->filter() (supported composition: extend()->select()->filter()->groupBy()->pivot()->cast()->extend()->sort()->limit())',
],
[
'Invalid: Group-level extend() used when no aggregation/grouping presents',
@@ -145,7 +145,7 @@ describe(unitTest('Analyze and build base snapshot'), () => {
await ENGINE_TEST_SUPPORT__grammarToJSON_valueSpecification(code),
[],
);
- const baseQuery = new DataCubeQuery('', '', {});
+ const baseQuery = new DataCubeQuery('', '', undefined);
baseQuery.source = new DataCubeQuerySourceREPLExecutedQuery();
baseQuery.partialQuery = code;
baseQuery.source.query = '';
diff --git a/packages/legend-application-repl/src/stores/dataCube/editor/DataCubeEditorCodePanelState.ts b/packages/legend-application-repl/src/stores/dataCube/editor/DataCubeEditorCodePanelState.ts
index 64b360123c..1347813a4e 100644
--- a/packages/legend-application-repl/src/stores/dataCube/editor/DataCubeEditorCodePanelState.ts
+++ b/packages/legend-application-repl/src/stores/dataCube/editor/DataCubeEditorCodePanelState.ts
@@ -29,6 +29,7 @@ import {
SourceInformation,
V1_ParserError,
} from '@finos/legend-graph';
+import type { DataCubeEditorState } from './DataCubeEditorState.js';
class DataCubeQueryEditorState {
uuid = uuid();
@@ -79,11 +80,12 @@ class DataCubeQueryEditorState {
export class DataCubeEditorCodePanelState {
readonly dataCube!: DataCubeState;
+ readonly editor: DataCubeEditorState;
queryEditorState!: DataCubeQueryEditorState;
currentSubQuery?: string | undefined;
- constructor(dataCube: DataCubeState) {
+ constructor(editor: DataCubeEditorState) {
makeObservable(this, {
currentSubQuery: observable,
queryEditorState: observable,
@@ -91,7 +93,8 @@ export class DataCubeEditorCodePanelState {
parseQuery: flow,
});
- this.dataCube = dataCube;
+ this.editor = editor;
+ this.dataCube = editor.dataCube;
this.queryEditorState = new DataCubeQueryEditorState('');
}
diff --git a/packages/legend-application-repl/src/stores/dataCube/editor/DataCubeEditorColumnPropertiesPanelState.ts b/packages/legend-application-repl/src/stores/dataCube/editor/DataCubeEditorColumnPropertiesPanelState.ts
new file mode 100644
index 0000000000..0d7ad991f9
--- /dev/null
+++ b/packages/legend-application-repl/src/stores/dataCube/editor/DataCubeEditorColumnPropertiesPanelState.ts
@@ -0,0 +1,82 @@
+/**
+ * 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 { action, computed, makeObservable, observable } from 'mobx';
+import type { DataCubeState } from '../DataCubeState.js';
+import type { DataCubeQuerySnapshot } from '../core/DataCubeQuerySnapshot.js';
+import type { DataCubeQueryEditorPanelState } from './DataCubeEditorPanelState.js';
+import type { DataCubeEditorState } from './DataCubeEditorState.js';
+import { DataCubeMutableColumnConfiguration } from './DataCubeMutableConfiguration.js';
+import { getNonNullableEntry, type PlainObject } from '@finos/legend-shared';
+
+export class DataCubeEditorColumnPropertiesPanelState
+ implements DataCubeQueryEditorPanelState
+{
+ readonly dataCube!: DataCubeState;
+ readonly editor!: DataCubeEditorState;
+
+ columns: DataCubeMutableColumnConfiguration[] = [];
+ selectedColumnName?: string | undefined;
+
+ constructor(editor: DataCubeEditorState) {
+ makeObservable(this, {
+ columns: observable,
+ setColumns: action,
+
+ selectedColumnName: observable,
+ setSelectedColumnName: action,
+ selectedColumn: computed,
+ });
+
+ this.editor = editor;
+ this.dataCube = editor.dataCube;
+ }
+
+ setColumns(val: DataCubeMutableColumnConfiguration[]): void {
+ this.columns = val;
+ }
+
+ setSelectedColumnName(val: string | undefined): void {
+ this.selectedColumnName = val;
+ }
+
+ get selectedColumn(): DataCubeMutableColumnConfiguration | undefined {
+ return this.columns.find(
+ (column) => column.name === this.selectedColumnName,
+ );
+ }
+
+ applySnaphot(snapshot: DataCubeQuerySnapshot): void {
+ this.setColumns(
+ (snapshot.data.configuration as { columns: PlainObject[] }).columns.map(
+ (column) => DataCubeMutableColumnConfiguration.create(column),
+ ),
+ );
+ if (!this.selectedColumn && this.columns.length) {
+ this.setSelectedColumnName(getNonNullableEntry(this.columns, 0).name);
+ }
+ }
+
+ buildSnapshot(
+ newSnapshot: DataCubeQuerySnapshot,
+ baseSnapshot: DataCubeQuerySnapshot,
+ ): void {
+ newSnapshot.data.configuration = {
+ ...newSnapshot.data.configuration,
+ columns: this.columns.map((column) => column.serialize()),
+ };
+ }
+}
diff --git a/packages/legend-application-repl/src/stores/dataCube/editor/DataCubeEditorColumnsSelectorState.ts b/packages/legend-application-repl/src/stores/dataCube/editor/DataCubeEditorColumnsSelectorState.ts
index 948dd9d7d3..937895942a 100644
--- a/packages/legend-application-repl/src/stores/dataCube/editor/DataCubeEditorColumnsSelectorState.ts
+++ b/packages/legend-application-repl/src/stores/dataCube/editor/DataCubeEditorColumnsSelectorState.ts
@@ -18,6 +18,9 @@ import { makeObservable, observable, action } from 'mobx';
export abstract class DataCubeEditorColumnsSelectorColumnState {
abstract get name(): string;
+ resetWhenMadeAvailable(): void {
+ // do nothing
+ }
}
export class DataCubeEditorColumnsSelectorState<
@@ -45,6 +48,7 @@ export class DataCubeEditorColumnsSelectorState<
this.availableColumns = val
.slice()
.sort((a, b) => a.name.localeCompare(b.name));
+ this.availableColumns.forEach((column) => column.resetWhenMadeAvailable());
}
setSelectedColumns(val: T[]): void {
@@ -58,4 +62,12 @@ export class DataCubeEditorColumnsSelectorState<
setSelectedColumnsSearchText(val: string): void {
this.selectedColumnsSearchText = val;
}
+
+ getAvailableColumn(colName: string): T | undefined {
+ return this.availableColumns.find((col) => col.name === colName);
+ }
+
+ getSelectedColumn(colName: string): T | undefined {
+ return this.selectedColumns.find((col) => col.name === colName);
+ }
}
diff --git a/packages/legend-application-repl/src/stores/dataCube/editor/DataCubeEditorGeneralPropertiesPanelState.ts b/packages/legend-application-repl/src/stores/dataCube/editor/DataCubeEditorGeneralPropertiesPanelState.ts
index e0e0d78add..6a37ba11ee 100644
--- a/packages/legend-application-repl/src/stores/dataCube/editor/DataCubeEditorGeneralPropertiesPanelState.ts
+++ b/packages/legend-application-repl/src/stores/dataCube/editor/DataCubeEditorGeneralPropertiesPanelState.ts
@@ -18,63 +18,66 @@ import { action, makeObservable, observable } from 'mobx';
import type { DataCubeState } from '../DataCubeState.js';
import type { DataCubeQuerySnapshot } from '../core/DataCubeQuerySnapshot.js';
import type { DataCubeQueryEditorPanelState } from './DataCubeEditorPanelState.js';
+import type { DataCubeEditorState } from './DataCubeEditorState.js';
+import { DataCubeMutableConfiguration } from './DataCubeMutableConfiguration.js';
export class DataCubeEditorGeneralPropertiesPanelState
implements DataCubeQueryEditorPanelState
{
readonly dataCube!: DataCubeState;
+ readonly editor!: DataCubeEditorState;
+
name = '';
limit = -1;
+ configuration = new DataCubeMutableConfiguration();
- constructor(dataCube: DataCubeState) {
- this.dataCube = dataCube;
-
+ constructor(editor: DataCubeEditorState) {
makeObservable(this, {
name: observable,
setName: action,
limit: observable,
setLimit: action,
+
+ configuration: observable,
+ setConfiguration: action,
});
+
+ this.editor = editor;
+ this.dataCube = editor.dataCube;
}
setName(val: string): void {
this.name = val;
}
- setLimit(val: number | undefined): void {
- this.limit = Math.round(val === undefined || val < 0 ? -1 : val);
+ setLimit(val: number): void {
+ this.limit = val;
+ }
+
+ setConfiguration(val: DataCubeMutableConfiguration): void {
+ this.configuration = val;
}
applySnaphot(snapshot: DataCubeQuerySnapshot): void {
this.setName(snapshot.data.name);
- this.setLimit(snapshot.data.limit);
+ this.setLimit(
+ snapshot.data.limit !== undefined && snapshot.data.limit > 0
+ ? snapshot.data.limit
+ : -1,
+ );
+ this.setConfiguration(
+ DataCubeMutableConfiguration.create(snapshot.data.configuration),
+ );
}
buildSnapshot(
newSnapshot: DataCubeQuerySnapshot,
baseSnapshot: DataCubeQuerySnapshot,
- ): boolean {
- const data = baseSnapshot.data;
- // name
- if (this.name !== data.name) {
- data.name = this.name;
- return true;
- }
-
- // limit
- if (data.limit === undefined) {
- if (this.limit !== -1) {
- data.limit = this.limit;
- return true;
- }
- } else {
- if (this.limit !== data.limit) {
- data.limit = this.limit;
- return true;
- }
- }
-
- return false;
+ ): void {
+ const data = newSnapshot.data;
+ data.name = this.name;
+ data.limit = this.limit <= 0 ? undefined : this.limit;
+ data.configuration = this.configuration.serialize();
}
}
diff --git a/packages/legend-application-repl/src/stores/dataCube/editor/DataCubeEditorHPivotPanelState.ts b/packages/legend-application-repl/src/stores/dataCube/editor/DataCubeEditorHPivotPanelState.ts
new file mode 100644
index 0000000000..719028a302
--- /dev/null
+++ b/packages/legend-application-repl/src/stores/dataCube/editor/DataCubeEditorHPivotPanelState.ts
@@ -0,0 +1,43 @@
+/**
+ * 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 { DataCubeState } from '../DataCubeState.js';
+import type { DataCubeQuerySnapshot } from '../core/DataCubeQuerySnapshot.js';
+import type { DataCubeQueryEditorPanelState } from './DataCubeEditorPanelState.js';
+import type { DataCubeEditorState } from './DataCubeEditorState.js';
+
+export class DataCubeEditorGeneralPropertiesPanelState
+ implements DataCubeQueryEditorPanelState
+{
+ readonly dataCube!: DataCubeState;
+ readonly editor!: DataCubeEditorState;
+
+ constructor(editor: DataCubeEditorState) {
+ this.editor = editor;
+ this.dataCube = editor.dataCube;
+ }
+
+ applySnaphot(snapshot: DataCubeQuerySnapshot): void {
+ // TODO
+ }
+
+ buildSnapshot(
+ newSnapshot: DataCubeQuerySnapshot,
+ baseSnapshot: DataCubeQuerySnapshot,
+ ): void {
+ // TODO
+ }
+}
diff --git a/packages/legend-application-repl/src/stores/dataCube/editor/DataCubeEditorPanelState.ts b/packages/legend-application-repl/src/stores/dataCube/editor/DataCubeEditorPanelState.ts
index a2f39df9f5..7804f6b446 100644
--- a/packages/legend-application-repl/src/stores/dataCube/editor/DataCubeEditorPanelState.ts
+++ b/packages/legend-application-repl/src/stores/dataCube/editor/DataCubeEditorPanelState.ts
@@ -29,5 +29,5 @@ export interface DataCubeQueryEditorPanelState {
buildSnapshot(
newSnapshot: DataCubeQuerySnapshot,
baseSnapshot: DataCubeQuerySnapshot,
- ): boolean;
+ ): void;
}
diff --git a/packages/legend-application-repl/src/stores/dataCube/editor/DataCubeEditorSortsPanelState.ts b/packages/legend-application-repl/src/stores/dataCube/editor/DataCubeEditorSortsPanelState.ts
index 6763fdb2f0..4bdcd778f2 100644
--- a/packages/legend-application-repl/src/stores/dataCube/editor/DataCubeEditorSortsPanelState.ts
+++ b/packages/legend-application-repl/src/stores/dataCube/editor/DataCubeEditorSortsPanelState.ts
@@ -17,44 +17,47 @@
import { action, makeObservable, observable } from 'mobx';
import type { DataCubeState } from '../DataCubeState.js';
import {
- DataCubeQuerySnapshotSortDirection,
+ DataCubeQuerySnapshotSortOperation,
_getCol,
type DataCubeQuerySnapshot,
type DataCubeQuerySnapshotColumn,
- type DataCubeQuerySnapshotSortColumn,
} from '../core/DataCubeQuerySnapshot.js';
import type { DataCubeQueryEditorPanelState } from './DataCubeEditorPanelState.js';
-import { deepEqual } from '@finos/legend-shared';
import {
DataCubeEditorColumnsSelectorColumnState,
DataCubeEditorColumnsSelectorState,
} from './DataCubeEditorColumnsSelectorState.js';
+import type { DataCubeEditorState } from './DataCubeEditorState.js';
export class DataCubeEditorSortColumnState extends DataCubeEditorColumnsSelectorColumnState {
readonly column: DataCubeQuerySnapshotColumn;
- direction: DataCubeQuerySnapshotSortDirection;
+ operation: DataCubeQuerySnapshotSortOperation;
constructor(
column: DataCubeQuerySnapshotColumn,
- direction: DataCubeQuerySnapshotSortDirection,
+ direction: DataCubeQuerySnapshotSortOperation,
) {
super();
makeObservable(this, {
- direction: observable,
- setDirection: action,
+ operation: observable,
+ setOperation: action,
});
this.column = column;
- this.direction = direction;
+ this.operation = direction;
}
get name(): string {
return this.column.name;
}
- setDirection(val: DataCubeQuerySnapshotSortDirection): void {
- this.direction = val;
+ override resetWhenMadeAvailable(): void {
+ this.setOperation(DataCubeQuerySnapshotSortOperation.ASCENDING);
+ }
+
+ setOperation(val: DataCubeQuerySnapshotSortOperation): void {
+ this.operation = val;
}
}
@@ -62,13 +65,82 @@ export class DataCubeEditorSortsPanelState
implements DataCubeQueryEditorPanelState
{
readonly dataCube!: DataCubeState;
+ readonly editor!: DataCubeEditorState;
readonly columnsSelector!: DataCubeEditorColumnsSelectorState;
- constructor(dataCube: DataCubeState) {
- this.dataCube = dataCube;
+ constructor(editor: DataCubeEditorState) {
+ this.editor = editor;
+ this.dataCube = editor.dataCube;
this.columnsSelector = new DataCubeEditorColumnsSelectorState();
}
+ getActionableSortColumn(
+ colName: string,
+ operation: DataCubeQuerySnapshotSortOperation,
+ ): DataCubeEditorSortColumnState | undefined {
+ let column = this.columnsSelector.getAvailableColumn(colName);
+ if (!column) {
+ const selectedColumn = this.columnsSelector.getSelectedColumn(colName);
+ if (selectedColumn && selectedColumn.operation !== operation) {
+ column = selectedColumn;
+ }
+ }
+ return column;
+ }
+
+ sortByColumn(
+ colName: string,
+ operation: DataCubeQuerySnapshotSortOperation,
+ ): void {
+ const column = this.getActionableSortColumn(colName, operation);
+ if (!column) {
+ return;
+ }
+ column.setOperation(operation);
+
+ this.columnsSelector.setAvailableColumns(
+ [
+ ...this.columnsSelector.availableColumns,
+ ...this.columnsSelector.selectedColumns,
+ ].filter((col) => col.name !== colName),
+ );
+ this.columnsSelector.setSelectedColumns([column]);
+ this.editor.applyChanges();
+ }
+
+ addSortByColumn(
+ colName: string,
+ operation: DataCubeQuerySnapshotSortOperation,
+ ): void {
+ const column = this.getActionableSortColumn(colName, operation);
+ if (!column) {
+ return;
+ }
+ column.setOperation(operation);
+
+ this.columnsSelector.setAvailableColumns(
+ this.columnsSelector.availableColumns.filter(
+ (col) => col.name !== colName,
+ ),
+ );
+ this.columnsSelector.setSelectedColumns([
+ ...this.columnsSelector.selectedColumns,
+ column,
+ ]);
+ this.editor.applyChanges();
+ }
+
+ clearAllSorts(): void {
+ if (this.columnsSelector.selectedColumns.length !== 0) {
+ this.columnsSelector.setAvailableColumns([
+ ...this.columnsSelector.availableColumns,
+ ...this.columnsSelector.selectedColumns,
+ ]);
+ this.columnsSelector.setSelectedColumns([]);
+ this.editor.applyChanges();
+ }
+ }
+
applySnaphot(snapshot: DataCubeQuerySnapshot): void {
const columns = snapshot.stageCols('sort');
const sortColumns = snapshot.data.sortColumns;
@@ -81,7 +153,7 @@ export class DataCubeEditorSortsPanelState
(col) =>
new DataCubeEditorSortColumnState(
_getCol(columns, col.name),
- DataCubeQuerySnapshotSortDirection.ASCENDING,
+ DataCubeQuerySnapshotSortOperation.ASCENDING,
),
),
);
@@ -90,7 +162,7 @@ export class DataCubeEditorSortsPanelState
(col) =>
new DataCubeEditorSortColumnState(
_getCol(columns, col.name),
- col.direction,
+ col.operation,
),
),
);
@@ -99,18 +171,13 @@ export class DataCubeEditorSortsPanelState
buildSnapshot(
newSnapshot: DataCubeQuerySnapshot,
baseSnapshot: DataCubeQuerySnapshot,
- ): boolean {
- const newSortColumns: DataCubeQuerySnapshotSortColumn[] =
- this.columnsSelector.selectedColumns.map((sortInfo) => ({
+ ): void {
+ newSnapshot.data.sortColumns = this.columnsSelector.selectedColumns.map(
+ (sortInfo) => ({
name: sortInfo.column.name,
type: sortInfo.column.type,
- direction: sortInfo.direction,
- }));
-
- if (!deepEqual(newSortColumns, baseSnapshot.data.sortColumns)) {
- newSnapshot.data.sortColumns = newSortColumns;
- return true;
- }
- return false;
+ operation: sortInfo.operation,
+ }),
+ );
}
}
diff --git a/packages/legend-application-repl/src/stores/dataCube/editor/DataCubeEditorState.ts b/packages/legend-application-repl/src/stores/dataCube/editor/DataCubeEditorState.ts
index 81d268eea0..73d4fe9814 100644
--- a/packages/legend-application-repl/src/stores/dataCube/editor/DataCubeEditorState.ts
+++ b/packages/legend-application-repl/src/stores/dataCube/editor/DataCubeEditorState.ts
@@ -22,6 +22,7 @@ import { DataCubeQuerySnapshotSubscriber } from '../core/DataCubeQuerySnapshotSu
import { type DataCubeQuerySnapshot } from '../core/DataCubeQuerySnapshot.js';
import { guaranteeNonNullable } from '@finos/legend-shared';
import { DataCubeEditorGeneralPropertiesPanelState } from './DataCubeEditorGeneralPropertiesPanelState.js';
+import { DataCubeEditorColumnPropertiesPanelState } from './DataCubeEditorColumnPropertiesPanelState.js';
export enum DATA_CUBE_EDITOR_TAB {
COLUMNS = 'Columns',
@@ -33,13 +34,13 @@ export enum DATA_CUBE_EDITOR_TAB {
GENERAL_PROPERTIES = 'General Properties',
COLUMN_PROPERTIES = 'Column Properties',
CODE = 'Code',
- // DEVELOPER_OPTIONS = 'Developer',
- // PIVOT_LAYOUT = 'Pivot Layout',
+ DEVELOPER = 'Developer',
}
export class DataCubeEditorState extends DataCubeQuerySnapshotSubscriber {
readonly sortsPanel: DataCubeEditorSortsPanelState;
readonly generalPropertiesPanel: DataCubeEditorGeneralPropertiesPanelState;
+ readonly columnPropertiesPanel: DataCubeEditorColumnPropertiesPanelState;
readonly codePanel: DataCubeEditorCodePanelState;
isPanelOpen = false;
@@ -59,11 +60,14 @@ export class DataCubeEditorState extends DataCubeQuerySnapshotSubscriber {
closePanel: action,
});
- this.sortsPanel = new DataCubeEditorSortsPanelState(this.dataCube);
+ this.sortsPanel = new DataCubeEditorSortsPanelState(this);
this.generalPropertiesPanel = new DataCubeEditorGeneralPropertiesPanelState(
- this.dataCube,
+ this,
);
- this.codePanel = new DataCubeEditorCodePanelState(this.dataCube);
+ this.columnPropertiesPanel = new DataCubeEditorColumnPropertiesPanelState(
+ this,
+ );
+ this.codePanel = new DataCubeEditorCodePanelState(this);
}
openPanel(): void {
@@ -82,12 +86,14 @@ export class DataCubeEditorState extends DataCubeQuerySnapshotSubscriber {
const baseSnapshot = guaranteeNonNullable(this.getLatestSnapshot());
const snapshot = baseSnapshot.clone();
- const createNew = [
- this.sortsPanel.buildSnapshot(snapshot, baseSnapshot),
- this.generalPropertiesPanel.buildSnapshot(snapshot, baseSnapshot),
- ].some(Boolean);
+ this.sortsPanel.buildSnapshot(snapshot, baseSnapshot);
+ // NOTE: snapshot must be processed first to build the container configuration
+ // before proceeding to process the columns' configuration
+ this.generalPropertiesPanel.buildSnapshot(snapshot, baseSnapshot);
+ this.columnPropertiesPanel.buildSnapshot(snapshot, baseSnapshot);
- if (createNew) {
+ snapshot.finalize();
+ if (snapshot.hashCode !== baseSnapshot.hashCode) {
this.publishSnapshot(snapshot);
}
}
@@ -95,6 +101,7 @@ export class DataCubeEditorState extends DataCubeQuerySnapshotSubscriber {
override async applySnapshot(snapshot: DataCubeQuerySnapshot): Promise {
this.sortsPanel.applySnaphot(snapshot);
this.generalPropertiesPanel.applySnaphot(snapshot);
+ this.columnPropertiesPanel.applySnaphot(snapshot);
}
override async initialize(): Promise {
diff --git a/packages/legend-application-repl/src/stores/dataCube/editor/DataCubeMutableConfiguration.ts b/packages/legend-application-repl/src/stores/dataCube/editor/DataCubeMutableConfiguration.ts
new file mode 100644
index 0000000000..f540b4568b
--- /dev/null
+++ b/packages/legend-application-repl/src/stores/dataCube/editor/DataCubeMutableConfiguration.ts
@@ -0,0 +1,533 @@
+/**
+ * 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 {
+ getDataType,
+ type DataCubeColumnKind,
+ type DataCubeFont,
+ type DataCubeAggregateFunction,
+ type DataCubeNumberScale,
+ type DataCubeSelectionStat,
+ type DataCubeFontFormatUnderlinedVariant,
+ type DataCubeFontTextAlignment,
+ type DataCubeColumnDataType,
+ type DataCubeColumnPinPlacement,
+} from '../core/DataCubeQueryEngine.js';
+import { type PlainObject, type Writable } from '@finos/legend-shared';
+import { makeObservable, observable, action } from 'mobx';
+import {
+ DataCubeColumnConfiguration,
+ DataCubeConfiguration,
+} from '../core/DataCubeConfiguration.js';
+
+export class DataCubeMutableColumnConfiguration extends DataCubeColumnConfiguration {
+ aggregateFunction?: DataCubeAggregateFunction | undefined;
+ weightColumn?: string | undefined;
+ excludedFromHPivot = true;
+
+ readonly dataType!: DataCubeColumnDataType;
+
+ static create(
+ json: PlainObject,
+ ): DataCubeMutableColumnConfiguration {
+ const configuration = Object.assign(
+ new DataCubeMutableColumnConfiguration('', ''),
+ DataCubeColumnConfiguration.serialization.fromJson(json),
+ );
+ (configuration as Writable).dataType =
+ getDataType(configuration.type);
+
+ makeObservable(configuration, {
+ kind: observable,
+ setKind: action,
+
+ displayName: observable,
+ setDisplayName: action,
+
+ decimals: observable,
+ setDecimals: action,
+
+ displayCommas: observable,
+ setDisplayCommas: action,
+
+ negativeNumberInParens: observable,
+ setNegativeNumberInParens: action,
+
+ numberScale: observable,
+ setNumberScale: action,
+
+ hPivotSortFunction: observable,
+ setHPivotSortFunction: action,
+
+ fontFamily: observable,
+ setFontFamily: action,
+
+ fontSize: observable,
+ setFontSize: action,
+
+ fontBold: observable,
+ setFontBold: action,
+
+ fontItalic: observable,
+ setFontItalic: action,
+
+ fontUnderlined: observable,
+ setFontUnderlined: action,
+
+ fontStrikethrough: observable,
+ setFontStrikethrough: action,
+
+ textAlign: observable,
+ setTextAlign: action,
+
+ foregroundColor: observable,
+ setForegroundColor: action,
+
+ foregroundNegativeColor: observable,
+ setForegroundNegativeColor: action,
+
+ foregroundZeroColor: observable,
+ setForegroundZeroColor: action,
+
+ foregroundErrorColor: observable,
+ setForegroundErrorColor: action,
+
+ backgroundColor: observable,
+ setBackgroundColor: action,
+
+ backgroundNegativeColor: observable,
+ setBackgroundNegativeColor: action,
+
+ backgroundZeroColor: observable,
+ setBackgroundZeroColor: action,
+
+ backgroundErrorColor: observable,
+ setBackgroundErrorColor: action,
+
+ blur: observable,
+ setBlur: action,
+
+ hideFromView: observable,
+ setHideFromView: action,
+
+ aggregateFunction: observable,
+ setAggregateFunction: action,
+
+ weightColumn: observable,
+ setWeightColumn: action,
+
+ excludedFromHPivot: observable,
+ setExcludedFromHPivot: action,
+
+ fixedWidth: observable,
+ setFixedWidth: action,
+
+ minWidth: observable,
+ setMinWidth: action,
+
+ maxWidth: observable,
+ setMaxWidth: action,
+
+ pinned: observable,
+ setPinned: action,
+
+ displayAsLink: observable,
+ setDisplayAsLink: action,
+ });
+
+ return configuration;
+ }
+
+ serialize(): PlainObject {
+ return DataCubeColumnConfiguration.serialization.toJson(this);
+ }
+
+ setKind(value: DataCubeColumnKind): void {
+ this.kind = value;
+ }
+
+ setDisplayName(value: string | undefined): void {
+ this.displayName = value;
+ }
+
+ setDecimals(value: number | undefined): void {
+ this.decimals = value;
+ }
+
+ setDisplayCommas(value: boolean): void {
+ this.displayCommas = value;
+ }
+
+ setNegativeNumberInParens(value: boolean): void {
+ this.negativeNumberInParens = value;
+ }
+
+ setNumberScale(value: DataCubeNumberScale | undefined): void {
+ this.numberScale = value;
+ }
+
+ setHPivotSortFunction(value: string | undefined): void {
+ this.hPivotSortFunction = value;
+ }
+
+ setFontFamily(value: DataCubeFont): void {
+ this.fontFamily = value;
+ }
+
+ setFontSize(value: number): void {
+ this.fontSize = value;
+ }
+
+ setFontBold(value: boolean): void {
+ this.fontBold = value;
+ }
+
+ setFontItalic(value: boolean): void {
+ this.fontItalic = value;
+ }
+
+ setFontUnderlined(
+ value: DataCubeFontFormatUnderlinedVariant | undefined,
+ ): void {
+ this.fontUnderlined = value;
+ }
+
+ setTextAlign(value: DataCubeFontTextAlignment): void {
+ this.textAlign = value;
+ }
+
+ setFontStrikethrough(value: boolean): void {
+ this.fontStrikethrough = value;
+ }
+
+ setForegroundColor(value: string): void {
+ this.foregroundColor = value;
+ }
+
+ setForegroundNegativeColor(value: string): void {
+ this.foregroundNegativeColor = value;
+ }
+
+ setForegroundZeroColor(value: string): void {
+ this.foregroundZeroColor = value;
+ }
+
+ setForegroundErrorColor(value: string): void {
+ this.foregroundErrorColor = value;
+ }
+
+ setBackgroundColor(value: string): void {
+ this.backgroundColor = value;
+ }
+
+ setBackgroundNegativeColor(value: string): void {
+ this.backgroundNegativeColor = value;
+ }
+
+ setBackgroundZeroColor(value: string): void {
+ this.backgroundZeroColor = value;
+ }
+
+ setBackgroundErrorColor(value: string): void {
+ this.backgroundErrorColor = value;
+ }
+
+ setBlur(value: boolean): void {
+ this.blur = value;
+ }
+
+ setHideFromView(value: boolean): void {
+ this.hideFromView = value;
+ }
+
+ setFixedWidth(value: number | undefined): void {
+ this.fixedWidth = value;
+ }
+
+ setMinWidth(value: number | undefined): void {
+ this.minWidth = value;
+ }
+
+ setMaxWidth(value: number | undefined): void {
+ this.maxWidth = value;
+ }
+
+ setPinned(value: DataCubeColumnPinPlacement | undefined): void {
+ this.pinned = value;
+ }
+
+ setDisplayAsLink(value: boolean): void {
+ this.displayAsLink = value;
+ }
+
+ setAggregateFunction(value: DataCubeAggregateFunction | undefined): void {
+ this.aggregateFunction = value;
+ }
+
+ setWeightColumn(value: string | undefined): void {
+ this.weightColumn = value;
+ }
+
+ setExcludedFromHPivot(value: boolean): void {
+ this.excludedFromHPivot = value;
+ }
+}
+
+export class DataCubeMutableConfiguration extends DataCubeConfiguration {
+ static create(
+ json: PlainObject,
+ ): DataCubeMutableConfiguration {
+ const configuration = Object.assign(
+ new DataCubeMutableConfiguration(),
+ DataCubeConfiguration.serialization.fromJson(json),
+ );
+ configuration.columns = [];
+
+ makeObservable(configuration, {
+ description: observable,
+ setDescription: action,
+
+ showTreeLine: observable,
+ setShowTreeLine: action,
+
+ showHorizontalGridLine: observable,
+ setShowHorizontalGridLine: action,
+
+ showVerticalGridLine: observable,
+ setShowVerticalGridLine: action,
+
+ defaultFontFamily: observable,
+ setDefaultFontFamily: action,
+
+ defaultFontSize: observable,
+ setDefaultFontSize: action,
+
+ defaultFontBold: observable,
+ setDefaultFontBold: action,
+
+ defaultFontItalic: observable,
+ setDefaultFontItalic: action,
+
+ defaultFontUnderlined: observable,
+ setDefaultFontUnderlined: action,
+
+ defaultFontStrikethrough: observable,
+ setDefaultFontStrikethrough: action,
+
+ defaultTextAlign: observable,
+ setDefaultTextAlign: action,
+
+ defaultForegroundColor: observable,
+ setDefaultForegroundColor: action,
+
+ defaultForegroundNegativeColor: observable,
+ setDefaultForegroundNegativeColor: action,
+
+ defaultForegroundZeroColor: observable,
+ setDefaultForegroundZeroColor: action,
+
+ defaultForegroundErrorColor: observable,
+ setDefaultForegroundErrorColor: action,
+
+ defaultBackgroundColor: observable,
+ setDefaultBackgroundColor: action,
+
+ defaultBackgroundNegativeColor: observable,
+ setDefaultBackgroundNegativeColor: action,
+
+ defaultBackgroundZeroColor: observable,
+ setDefaultBackgroundZeroColor: action,
+
+ defaultBackgroundErrorColor: observable,
+ setDefaultBackgroundErrorColor: action,
+
+ alternateRows: observable,
+ setAlternateRows: action,
+
+ alternateRowsColor: observable,
+ setAlternateRowsColor: action,
+
+ alternateRowsCount: observable,
+ setAlternateRowsCount: action,
+
+ numberScale: observable,
+ setNumberScale: action,
+
+ selectionStats: observable,
+ setSelectionStats: action,
+
+ rowBuffer: observable,
+ setRowBuffer: action,
+
+ showWarningForTruncatedResult: observable,
+ setShowWarningForTruncatedResult: action,
+
+ initialExpandLevel: observable,
+ setInitialExpandLevel: action,
+
+ showRootAggregation: observable,
+ setShowRootAggregation: action,
+
+ showLeafCount: observable,
+ setShowLeafCount: action,
+
+ addPivotTotalColumn: observable,
+ setAddPivotTotalColumn: action,
+
+ addPivotTotalColumnOnLeft: observable,
+ setAddPivotTotalColumnOnLeft: action,
+
+ treeGroupSortFunction: observable,
+ setTreeGroupSortFunction: action,
+ });
+
+ return configuration;
+ }
+
+ serialize(): PlainObject {
+ return DataCubeConfiguration.serialization.toJson(this);
+ }
+
+ setDescription(value: string | undefined): void {
+ this.description = value;
+ }
+
+ setShowTreeLine(value: boolean): void {
+ this.showTreeLine = value;
+ }
+
+ setShowHorizontalGridLine(value: boolean): void {
+ this.showHorizontalGridLine = value;
+ }
+
+ setShowVerticalGridLine(value: boolean): void {
+ this.showVerticalGridLine = value;
+ }
+
+ setDefaultFontFamily(value: DataCubeFont): void {
+ this.defaultFontFamily = value;
+ }
+
+ setDefaultFontSize(value: number): void {
+ this.defaultFontSize = value;
+ }
+
+ setDefaultFontBold(value: boolean): void {
+ this.defaultFontBold = value;
+ }
+
+ setDefaultFontItalic(value: boolean): void {
+ this.defaultFontItalic = value;
+ }
+
+ setDefaultFontUnderlined(
+ value: DataCubeFontFormatUnderlinedVariant | undefined,
+ ): void {
+ this.defaultFontUnderlined = value;
+ }
+
+ setDefaultFontStrikethrough(value: boolean): void {
+ this.defaultFontStrikethrough = value;
+ }
+
+ setDefaultTextAlign(value: DataCubeFontTextAlignment): void {
+ this.defaultTextAlign = value;
+ }
+
+ setDefaultForegroundColor(value: string): void {
+ this.defaultForegroundColor = value;
+ }
+
+ setDefaultForegroundNegativeColor(value: string): void {
+ this.defaultForegroundNegativeColor = value;
+ }
+
+ setDefaultForegroundZeroColor(value: string): void {
+ this.defaultForegroundZeroColor = value;
+ }
+
+ setDefaultForegroundErrorColor(value: string): void {
+ this.defaultForegroundErrorColor = value;
+ }
+
+ setDefaultBackgroundColor(value: string): void {
+ this.defaultBackgroundColor = value;
+ }
+
+ setDefaultBackgroundNegativeColor(value: string): void {
+ this.defaultBackgroundNegativeColor = value;
+ }
+
+ setDefaultBackgroundZeroColor(value: string): void {
+ this.defaultBackgroundZeroColor = value;
+ }
+
+ setDefaultBackgroundErrorColor(value: string): void {
+ this.defaultBackgroundErrorColor = value;
+ }
+
+ setAlternateRows(value: boolean): void {
+ this.alternateRows = value;
+ }
+
+ setAlternateRowsColor(value: string): void {
+ this.alternateRowsColor = value;
+ }
+
+ setAlternateRowsCount(value: number): void {
+ this.alternateRowsCount = value;
+ }
+
+ setNumberScale(value: DataCubeNumberScale | undefined): void {
+ this.numberScale = value;
+ }
+
+ setSelectionStats(value: DataCubeSelectionStat[]): void {
+ this.selectionStats = value;
+ }
+
+ setRowBuffer(value: number): void {
+ this.rowBuffer = value;
+ }
+
+ setShowWarningForTruncatedResult(value: boolean): void {
+ this.showWarningForTruncatedResult = value;
+ }
+
+ setInitialExpandLevel(value: number | undefined): void {
+ this.initialExpandLevel = value;
+ }
+
+ setShowRootAggregation(value: boolean): void {
+ this.showRootAggregation = value;
+ }
+
+ setShowLeafCount(value: boolean): void {
+ this.showLeafCount = value;
+ }
+
+ setAddPivotTotalColumn(value: boolean): void {
+ this.addPivotTotalColumn = value;
+ }
+
+ setAddPivotTotalColumnOnLeft(value: boolean): void {
+ this.addPivotTotalColumnOnLeft = value;
+ }
+
+ setTreeGroupSortFunction(value: string | undefined): void {
+ this.treeGroupSortFunction = value;
+ }
+}
diff --git a/packages/legend-application-repl/src/stores/dataCube/grid/DataCubeGridClientEngine.ts b/packages/legend-application-repl/src/stores/dataCube/grid/DataCubeGridClientEngine.ts
index b5e863e4f7..85365903a5 100644
--- a/packages/legend-application-repl/src/stores/dataCube/grid/DataCubeGridClientEngine.ts
+++ b/packages/legend-application-repl/src/stores/dataCube/grid/DataCubeGridClientEngine.ts
@@ -15,6 +15,8 @@
*/
import type {
+ GridApi,
+ IRowNode,
IServerSideDatasource,
IServerSideGetRowsParams,
} from '@ag-grid-community/core';
@@ -39,7 +41,6 @@ type GridClientRowData = {
export const INTERNAL__GRID_CLIENT_HEADER_HEIGHT = 24;
export const INTERNAL__GRID_CLIENT_ROW_HEIGHT = 20;
-export const INTERNAL__GRID_CLIENT_ROW_BUFFER = 50;
export const INTERNAL__GRID_CLIENT_TREE_COLUMN_ID = 'INTERNAL__tree';
export const INTERNAL__GRID_CLIENT_ROW_GROUPING_COUNT_AGG_COLUMN_ID =
'INTERNAL__count';
@@ -57,6 +58,30 @@ export enum GridClientAggregateOperation {
AVERAGE = 'avg',
}
+export function getDataForAllNodes(client: GridApi): T[] {
+ const rows: T[] = [];
+ client.forEachNode((node: IRowNode) => {
+ if (node.data) {
+ rows.push(node.data);
+ }
+ });
+ return rows;
+}
+
+/**
+ * NOTE: this method does not work for server-side row model.
+ * It only works when client-side filter is being applied
+ */
+export function getDataForAllFilteredNodes(client: GridApi): T[] {
+ const rows: T[] = [];
+ client.forEachNodeAfterFilter((node: IRowNode) => {
+ if (node.data) {
+ rows.push(node.data);
+ }
+ });
+ return rows;
+}
+
function TDStoRowData(tds: TabularDataSet): GridClientRowData[] {
return tds.rows.map((_row, rowIdx) => {
const row: GridClientRowData = {};
@@ -88,6 +113,8 @@ export class DataCubeGridClientServerSideDataSource
async fetchRows(
params: IServerSideGetRowsParams,
): Promise {
+ const task = this.grid.dataCube.newTask('Fetching data');
+
// ------------------------------ GRID OPTIONS ------------------------------
// Here, we make adjustments to the grid display in response to the new
// request, in case the grid action has not impacted the layout in an
@@ -109,8 +136,10 @@ export class DataCubeGridClientServerSideDataSource
// ------------------------------ SNAPSHOT ------------------------------
const currentSnapshot = guaranteeNonNullable(this.grid.getLatestSnapshot());
+ // TODO: when we support pivoting, we should make a quick call to check for columns
+ // created by pivots and specify them as cast columns when pivot is activated
const syncedSnapshot = buildQuerySnapshot(params.request, currentSnapshot);
- if (syncedSnapshot.uuid !== currentSnapshot.uuid) {
+ if (syncedSnapshot.hashCode !== currentSnapshot.hashCode) {
this.grid.publishSnapshot(syncedSnapshot);
}
@@ -161,6 +190,8 @@ export class DataCubeGridClientServerSideDataSource
assertErrorThrown(error);
this.grid.dataCube.application.notificationService.notifyError(error);
params.fail();
+ } finally {
+ this.grid.dataCube.endTask(task);
}
}
diff --git a/packages/legend-application-repl/src/stores/dataCube/grid/DataCubeGridQueryBuilder.ts b/packages/legend-application-repl/src/stores/dataCube/grid/DataCubeGridQueryBuilder.ts
index 92502932ce..a28a6ea9ac 100644
--- a/packages/legend-application-repl/src/stores/dataCube/grid/DataCubeGridQueryBuilder.ts
+++ b/packages/legend-application-repl/src/stores/dataCube/grid/DataCubeGridQueryBuilder.ts
@@ -139,16 +139,6 @@ export function generateRowGroupingDrilldownExecutableQueryPostProcessor(
// --------------------------------- PIVOT ---------------------------------
// TODO: @akphi - implement this and CAST
-
- // --------------------------------- SELECT ---------------------------------
- if (funcMap.select && drilldownValues.length < groupBy.columns.length) {
- funcMap.select.parameters = [
- _cols([
- ...data.selectColumns.map((col) => _colSpec(col.name)),
- _colSpec(INTERNAL__GRID_CLIENT_ROW_GROUPING_COUNT_AGG_COLUMN_ID),
- ]),
- ];
- }
}
};
}
diff --git a/packages/legend-application-repl/src/stores/dataCube/grid/DataCubeGridQuerySnapshotAnalyzer.tsx b/packages/legend-application-repl/src/stores/dataCube/grid/DataCubeGridQuerySnapshotAnalyzer.tsx
index e523414b12..edd2fcd4f5 100644
--- a/packages/legend-application-repl/src/stores/dataCube/grid/DataCubeGridQuerySnapshotAnalyzer.tsx
+++ b/packages/legend-application-repl/src/stores/dataCube/grid/DataCubeGridQuerySnapshotAnalyzer.tsx
@@ -23,7 +23,7 @@
import {
DataCubeQuerySnapshotAggregateFunction,
- DataCubeQuerySnapshotSortDirection,
+ DataCubeQuerySnapshotSortOperation,
_findCol,
type DataCubeQuerySnapshot,
type DataCubeQuerySnapshotColumn,
@@ -95,7 +95,7 @@ function _sortSpec(snapshot: DataCubeQuerySnapshot, colName: string) {
}
return {
sort:
- sortCol.direction === DataCubeQuerySnapshotSortDirection.ASCENDING
+ sortCol.operation === DataCubeQuerySnapshotSortOperation.ASCENDING
? GridClientSortDirection.ASCENDING
: GridClientSortDirection.DESCENDING,
sortIndex: sortColumns.indexOf(sortCol),
@@ -161,9 +161,10 @@ export function generateGridOptionsFromSnapshot(
lockPosition: true,
cellStyle: {
flex: 1,
- 'justify-content': 'space-between',
+ justifyContent: 'space-between',
display: 'flex',
},
+ sortable: false, // TODO: @akphi - we can support this in the configuration
} satisfies ColDef,
...data.selectColumns.map(
(col) =>
diff --git a/packages/legend-application-repl/src/stores/dataCube/grid/DataCubeGridQuerySnapshotBuilder.ts b/packages/legend-application-repl/src/stores/dataCube/grid/DataCubeGridQuerySnapshotBuilder.ts
index 620c4848a4..ede914c35c 100644
--- a/packages/legend-application-repl/src/stores/dataCube/grid/DataCubeGridQuerySnapshotBuilder.ts
+++ b/packages/legend-application-repl/src/stores/dataCube/grid/DataCubeGridQuerySnapshotBuilder.ts
@@ -24,15 +24,12 @@
import type { IServerSideGetRowsRequest } from '@ag-grid-community/core';
import {
type DataCubeQuerySnapshot,
- type DataCubeQuerySnapshotSortColumn,
- DataCubeQuerySnapshotSortDirection,
+ DataCubeQuerySnapshotSortOperation,
_getCol,
DataCubeQuerySnapshotAggregateFunction,
- type DataCubeQuerySnapshotGroupBy,
} from '../core/DataCubeQuerySnapshot.js';
import {
IllegalStateError,
- deepEqual,
guaranteeNonNullable,
isNonNullable,
} from '@finos/legend-shared';
@@ -68,15 +65,16 @@ export function buildQuerySnapshot(
request: IServerSideGetRowsRequest,
baseSnapshot: DataCubeQuerySnapshot,
): DataCubeQuerySnapshot {
- let createNew = false;
+ const snapshot = baseSnapshot.clone();
- // --------------------------------- GROUP BY ---------------------------------
+ // --------------------------------- SELECT ---------------------------------
+ // TODO: @akphi - Implement this
- let groupBy: undefined | DataCubeQuerySnapshotGroupBy = undefined;
+ // --------------------------------- GROUP BY ---------------------------------
if (request.rowGroupCols.length) {
const availableCols = baseSnapshot.stageCols('aggregation');
- groupBy = {
+ snapshot.data.groupBy = {
columns: request.rowGroupCols.map((col) => ({
name: col.id,
type: _getCol(availableCols, col.id).type,
@@ -89,39 +87,21 @@ export function buildQuerySnapshot(
function: _aggFunc(col.aggFunc as GridClientAggregateOperation),
})),
};
+ } else {
+ snapshot.data.groupBy = undefined;
}
// --------------------------------- SORT ---------------------------------
- let sortColumns: DataCubeQuerySnapshotSortColumn[] = [];
- if (request.sortModel.length) {
- const availableCols = baseSnapshot.stageCols('sort');
- sortColumns = request.sortModel.map((item) => ({
- ..._getCol(availableCols, item.colId),
- direction:
- item.sort === GridClientSortDirection.ASCENDING
- ? DataCubeQuerySnapshotSortDirection.ASCENDING
- : DataCubeQuerySnapshotSortDirection.DESCENDING,
- }));
- }
-
- // --------------------------------- SELECT ---------------------------------
- // TODO: @akphi - Implement this
+ snapshot.data.sortColumns = request.sortModel.map((item) => ({
+ ..._getCol(baseSnapshot.stageCols('sort'), item.colId),
+ operation:
+ item.sort === GridClientSortDirection.ASCENDING
+ ? DataCubeQuerySnapshotSortOperation.ASCENDING
+ : DataCubeQuerySnapshotSortOperation.DESCENDING,
+ }));
// --------------------------------- FINALIZE ---------------------------------
- if (
- !deepEqual(sortColumns, baseSnapshot.data.sortColumns) ||
- !deepEqual(groupBy, baseSnapshot.data.groupBy)
- ) {
- createNew = true;
- }
-
- if (createNew) {
- const newSnapshot = baseSnapshot.clone();
- newSnapshot.data.sortColumns = sortColumns;
- newSnapshot.data.groupBy = groupBy;
- return newSnapshot;
- }
- return baseSnapshot;
+ return snapshot.finalize();
}
diff --git a/packages/legend-application-repl/style/_repl.scss b/packages/legend-application-repl/style/_repl.scss
new file mode 100644
index 0000000000..97e89501d4
--- /dev/null
+++ b/packages/legend-application-repl/style/_repl.scss
@@ -0,0 +1,231 @@
+/**
+ * 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 url('@ag-grid-community/styles/ag-grid.css');
+@import url('@ag-grid-community/styles/ag-theme-balham.css');
+
+// ---------------------------------------- NORMALIZE ----------------------------------------
+
+html {
+ box-sizing: border-box;
+ font-family: Roboto, sans-serif;
+}
+
+body {
+ // default font size is 12px everywhere to make the app more compact
+ font-size: 12px;
+}
+
+::-webkit-scrollbar-track {
+ background: transparent;
+}
+
+::-webkit-scrollbar-corner {
+ background: transparent;
+}
+
+::-webkit-scrollbar-thumb {
+ background: #00000010;
+ border: 0.2rem solid transparent;
+ background-clip: content-box;
+ border-radius: 0.4rem;
+}
+
+::-webkit-scrollbar-thumb:hover {
+ background: #00000020;
+ border: 0.2rem solid transparent;
+ background-clip: content-box;
+ border-radius: 0.4rem;
+}
+
+::-webkit-scrollbar-thumb:window-inactive {
+ background: #00000005;
+}
+
+// ---------------------------------------- RESET ----------------------------------------
+
+input:focus-visible,
+button:focus-visible {
+ outline-color: var(--tw-color-sky-600);
+ outline-offset: -1px;
+ outline-width: 1.5px;
+ outline-style: solid;
+}
+
+.MuiCheckbox-root.Mui-focusVisible svg {
+ outline-color: var(--tw-color-sky-600);
+ outline-offset: -2px;
+ outline-width: 1.5px;
+ outline-style: solid;
+}
+
+.data-cube-editor-checkbox--checked svg {
+ color: var(--tw-color-neutral-600);
+}
+
+.data-cube-editor-checkbox--disabled svg {
+ color: var(--tw-color-neutral-300);
+}
+
+// ---------------------------------------- CUSTOMIZE ----------------------------------------
+
+.data-cube-color-picker {
+ .react-colorful {
+ width: 270px;
+ height: 100px;
+ border-radius: 2px;
+ border: 0.5px solid var(--tw-color-neutral-600);
+ }
+
+ .react-colorful__saturation {
+ border-radius: 2px 2px 0 0;
+ }
+
+ .react-colorful__pointer {
+ width: 12px;
+ height: 12px;
+ }
+
+ .react-colorful__hue {
+ height: 12px;
+ }
+
+ .react-colorful__last-control {
+ border-radius: 0 0 2px 2px;
+ height: 12px;
+ }
+}
+
+.data-cube-color-picker--disabled {
+ background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' version='1.1' preserveAspectRatio='none' viewBox='0 0 100 100' %3E%3Cpath d='M1 0 L0 1 L99 100 L100 99' stroke-width='4' stroke='%23e5e5e5' /%3E%3C/svg%3E");
+}
+
+.data-cube-grid .ag-theme-balham {
+ --ag-input-focus-border-color: var(--tw-color-sky-600);
+ --ag-balham-active-color: var(--tw-color-sky-600);
+ --ag-range-selection-border-color: var(--tw-color-sky-600);
+ --ag-range-selection-highlight-color: var(
+ --tw-color-sky-50
+ ); // color for the brief highlight animation when cells are copied
+
+ --ag-border-color: var(--tw-color-neutral-200);
+ --ag-header-background-color: var(--tw-color-neutral-100);
+ --ag-header-height: 24px;
+ --ag-row-height: 20px;
+ --ag-font-size: 12px;
+ --ag-grid-size: 1px;
+ --ag-icon-size: 12px;
+ --ag-font-family: 'Roboto', sans-serif;
+ --ag-icon-font-color: var(--tw-color-neutral-500);
+ --ag-row-border-color: transparent;
+ --ag-header-foreground-color: var(--tw-color-black);
+ --ag-odd-row-background-color: var(--tw-color-white);
+ --ag-row-hover-color: #d4d4d415; // tailwind neutral 300
+ // NOTE: These are icons taken from Tabler and URI encoded
+ // See https://yoksel.github.io/url-encoder/
+ // See https://tablericons.com/
+ // See https://github.com/tabler/tabler-icons
+ --ag-icon-font-code-group: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' class='icon icon-tabler icon-tabler-table-column' width='12' height='12' viewBox='0 0 24 24' stroke-width='1.5' stroke='%23000000' fill='none' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath stroke='none' d='M0 0h24v24H0z' fill='none'/%3E%3Cpath d='M3 5a2 2 0 0 1 2 -2h14a2 2 0 0 1 2 2v14a2 2 0 0 1 -2 2h-14a2 2 0 0 1 -2 -2v-14z' /%3E%3Cpath d='M10 10h11' /%3E%3Cpath d='M10 3v18' /%3E%3Cpath d='M9 3l-6 6' /%3E%3Cpath d='M10 7l-7 7' /%3E%3Cpath d='M10 12l-7 7' /%3E%3Cpath d='M10 17l-4 4' /%3E%3C/svg%3E");
+ --ag-icon-font-code-pivot: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' class='icon icon-tabler icon-tabler-table-row' width='12' height='12' viewBox='0 0 24 24' stroke-width='1.5' stroke='%23000000' fill='none' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath stroke='none' d='M0 0h24v24H0z' fill='none'/%3E%3Cpath d='M3 5a2 2 0 0 1 2 -2h14a2 2 0 0 1 2 2v14a2 2 0 0 1 -2 2h-14a2 2 0 0 1 -2 -2v-14z' /%3E%3Cpath d='M9 3l-6 6' /%3E%3Cpath d='M14 3l-7 7' /%3E%3Cpath d='M19 3l-7 7' /%3E%3Cpath d='M21 6l-4 4' /%3E%3Cpath d='M3 10h18' /%3E%3Cpath d='M10 10v11' /%3E%3C/svg%3E");
+
+ .ag-column-drop-cell {
+ height: 16px;
+ display: flex;
+ align-items: center;
+
+ .ag-column-drop-cell-text {
+ height: 16px;
+ }
+ }
+
+ .ag-column-drop-empty-message.ag-column-drop-horizontal-empty-message {
+ font-size: 0;
+ }
+
+ .ag-column-drop-list.ag-column-drop-horizontal-list[aria-label='Row Groups']
+ .ag-column-drop-empty-message.ag-column-drop-horizontal-empty-message::after {
+ content: 'Drag columns here to set vertical pivots';
+ font-size: 11px;
+ }
+
+ .ag-column-drop-list.ag-column-drop-horizontal-list[aria-label='Column Labels']
+ .ag-column-drop-empty-message.ag-column-drop-horizontal-empty-message::after {
+ content: 'Drag columns here to set horizontal pivots';
+ font-size: 11px;
+ }
+
+ .ag-header-cell-label .ag-sort-order {
+ font-size: 10px;
+ margin-left: 5px;
+ margin-right: -2px;
+ color: var(--tw-color-neutral-500);
+ font-weight: 500;
+ }
+
+ .ag-menu-list {
+ min-width: 120px;
+ }
+
+ .ag-menu-option-icon {
+ padding: 5px 5px 0;
+ }
+
+ .ag-menu-option-part {
+ padding: 5px 2px;
+ }
+
+ .ag-menu-option-popup-pointer {
+ padding: 5px 5px 5px 0;
+ }
+
+ // TODO: cell/range selection color
+}
+
+.data-cube-column-selector .ag-theme-balham {
+ --ag-balham-active-color: var(--tw-color-sky-600);
+ --ag-input-focus-border-color: var(--tw-color-sky-600);
+ --ag-range-selection-border-color: var(--tw-color-sky-600);
+ --ag-selected-row-background-color: var(--tw-color-sky-200);
+ --ag-border-color: var(--tw-color-white);
+ --ag-header-background-color: var(--tw-color-white);
+ --ag-header-height: 20px;
+ --ag-row-height: 20px;
+ --ag-font-size: 12px;
+ --ag-grid-size: 1px;
+ --ag-icon-size: 12px;
+ --ag-font-family: 'Roboto', sans-serif;
+ --ag-icon-font-color: var(--tw-color-neutral-500);
+ --ag-row-border-color: transparent;
+ --ag-header-foreground-color: var(--tw-color-black);
+ --ag-row-hover-color: #d4d4d415; // tailwind neutral 300
+ --ag-header-column-separator-display: none;
+
+ .ag-header-cell {
+ padding-left: 20px;
+ }
+
+ // ag-grid header always comes with a big padding, we want to suppress that
+ .ag-header-cell:focus-visible::after {
+ width: 100%;
+ height: 100%;
+ top: 0;
+ left: 0;
+ }
+
+ .ag-drag-handle.ag-row-drag {
+ margin-right: 5px;
+ }
+}
diff --git a/packages/legend-application-repl/style/index.scss b/packages/legend-application-repl/style/index.scss
index d10f639d76..716d5b1ace 100644
--- a/packages/legend-application-repl/style/index.scss
+++ b/packages/legend-application-repl/style/index.scss
@@ -14,131 +14,4 @@
* limitations under the License.
*/
-@import url('@ag-grid-community/styles/ag-grid.css');
-@import url('@ag-grid-community/styles/ag-theme-balham.css');
-
-input:focus-visible,
-button:focus-visible {
- outline-color: var(--tw-color-sky-600);
- outline-offset: -1px;
- outline-width: 1.5px;
- outline-style: solid;
-}
-
-body {
- // default font size is 12px everywhere to make the app more compact
- font-size: 12px;
-}
-
-::-webkit-scrollbar-track {
- background: transparent;
-}
-
-::-webkit-scrollbar-corner {
- background: transparent;
-}
-
-::-webkit-scrollbar-thumb {
- background: #00000010;
- border: 0.2rem solid transparent;
- background-clip: content-box;
- border-radius: 0.4rem;
-}
-
-::-webkit-scrollbar-thumb:hover {
- background: #00000020;
- border: 0.2rem solid transparent;
- background-clip: content-box;
- border-radius: 0.4rem;
-}
-
-::-webkit-scrollbar-thumb:window-inactive {
- background: #00000005;
-}
-
-.data-cube-grid .ag-theme-balham {
- --ag-input-focus-border-color: var(--tw-color-sky-600);
- --ag-balham-active-color: var(--tw-color-sky-600);
- --ag-range-selection-border-color: var(--tw-color-sky-600);
- --ag-border-color: var(--tw-color-neutral-200);
- --ag-header-background-color: var(--tw-color-neutral-100);
- --ag-header-height: 24px;
- --ag-row-height: 20px;
- --ag-font-size: 12px;
- --ag-grid-size: 1px;
- --ag-icon-size: 12px;
- --ag-icon-font-color: var(--tw-color-neutral-500);
- --ag-row-border-color: transparent;
- --ag-header-foreground-color: var(--tw-color-black);
- --ag-odd-row-background-color: var(--tw-color-white);
- --ag-row-hover-color: #d4d4d415; // tailwind neutral 300
- // NOTE: These are icons taken from Tabler and URI encoded
- // See https://yoksel.github.io/url-encoder/
- // See https://tablericons.com/
- // See https://github.com/tabler/tabler-icons
- --ag-icon-font-code-group: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' class='icon icon-tabler icon-tabler-table-column' width='12' height='12' viewBox='0 0 24 24' stroke-width='1.5' stroke='%23000000' fill='none' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath stroke='none' d='M0 0h24v24H0z' fill='none'/%3E%3Cpath d='M3 5a2 2 0 0 1 2 -2h14a2 2 0 0 1 2 2v14a2 2 0 0 1 -2 2h-14a2 2 0 0 1 -2 -2v-14z' /%3E%3Cpath d='M10 10h11' /%3E%3Cpath d='M10 3v18' /%3E%3Cpath d='M9 3l-6 6' /%3E%3Cpath d='M10 7l-7 7' /%3E%3Cpath d='M10 12l-7 7' /%3E%3Cpath d='M10 17l-4 4' /%3E%3C/svg%3E");
- --ag-icon-font-code-pivot: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' class='icon icon-tabler icon-tabler-table-row' width='12' height='12' viewBox='0 0 24 24' stroke-width='1.5' stroke='%23000000' fill='none' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath stroke='none' d='M0 0h24v24H0z' fill='none'/%3E%3Cpath d='M3 5a2 2 0 0 1 2 -2h14a2 2 0 0 1 2 2v14a2 2 0 0 1 -2 2h-14a2 2 0 0 1 -2 -2v-14z' /%3E%3Cpath d='M9 3l-6 6' /%3E%3Cpath d='M14 3l-7 7' /%3E%3Cpath d='M19 3l-7 7' /%3E%3Cpath d='M21 6l-4 4' /%3E%3Cpath d='M3 10h18' /%3E%3Cpath d='M10 10v11' /%3E%3C/svg%3E");
-
- .ag-column-drop-cell {
- height: 16px;
- display: flex;
- align-items: center;
-
- .ag-column-drop-cell-text {
- height: 16px;
- }
- }
-
- .ag-column-drop-empty-message.ag-column-drop-horizontal-empty-message {
- font-size: 0;
- }
-
- .ag-column-drop-list.ag-column-drop-horizontal-list[aria-label='Row Groups']
- .ag-column-drop-empty-message.ag-column-drop-horizontal-empty-message::after {
- content: 'Drag columns here to set vertical pivots';
- font-size: 11px;
- }
-
- .ag-column-drop-list.ag-column-drop-horizontal-list[aria-label='Column Labels']
- .ag-column-drop-empty-message.ag-column-drop-horizontal-empty-message::after {
- content: 'Drag columns here to set horizontal pivots';
- font-size: 11px;
- }
-
- // TODO: cell/range selection color
-}
-
-.data-cube-column-selector .ag-theme-balham {
- --ag-balham-active-color: var(--tw-color-sky-600);
- --ag-input-focus-border-color: var(--tw-color-sky-600);
- --ag-range-selection-border-color: var(--tw-color-sky-600);
- --ag-selected-row-background-color: var(--tw-color-sky-200);
- --ag-border-color: var(--tw-color-white);
- --ag-header-background-color: var(--tw-color-white);
- --ag-header-height: 20px;
- --ag-row-height: 20px;
- --ag-font-size: 12px;
- --ag-grid-size: 1px;
- --ag-icon-size: 12px;
- --ag-icon-font-color: var(--tw-color-neutral-500);
- --ag-row-border-color: transparent;
- --ag-header-foreground-color: var(--tw-color-black);
- --ag-row-hover-color: #d4d4d415; // tailwind neutral 300
- --ag-header-column-separator-display: none;
-
- .ag-header-cell {
- padding-left: 20px;
- }
-
- // ag-grid header always comes with a big padding, we want to suppress that
- .ag-header-cell:focus-visible::after {
- width: 100%;
- height: 100%;
- top: 0;
- left: 0;
- }
-
- .ag-drag-handle.ag-row-drag {
- margin-right: 5px;
- }
-}
+@forward 'repl';
diff --git a/packages/legend-application-studio/package.json b/packages/legend-application-studio/package.json
index 62ca613152..b6f8ac403f 100644
--- a/packages/legend-application-studio/package.json
+++ b/packages/legend-application-studio/package.json
@@ -60,7 +60,7 @@
"@types/react": "18.3.3",
"@types/react-dom": "18.3.0",
"fast-xml-parser": "4.4.0",
- "mobx": "6.12.4",
+ "mobx": "6.12.5",
"mobx-react-lite": "4.0.7",
"mobx-utils": "6.0.8",
"monaco-editor": "0.50.0",
diff --git a/packages/legend-application-studio/src/components/editor/ActivityBar.tsx b/packages/legend-application-studio/src/components/editor/ActivityBar.tsx
index 8f67918a3e..d00fffcd47 100644
--- a/packages/legend-application-studio/src/components/editor/ActivityBar.tsx
+++ b/packages/legend-application-studio/src/components/editor/ActivityBar.tsx
@@ -24,7 +24,7 @@ import {
import { LEGEND_STUDIO_TEST_ID } from '../../__lib__/LegendStudioTesting.js';
import {
clsx,
- DropdownMenu,
+ ControlledDropdownMenu,
RepoIcon,
MenuContent,
MenuContentItem,
@@ -115,7 +115,7 @@ export const ActivityBarMenu: React.FC = () => {
return (
<>
- {
}
>
-
+
>
@@ -431,7 +431,7 @@ export const ActivityBar = observer(() => {
>
- }
@@ -442,7 +442,7 @@ export const ActivityBar = observer(() => {
}}
>
-
+
);
});
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 570e61419a..711c0b93bb 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
@@ -19,7 +19,7 @@ import { observer } from 'mobx-react-lite';
import {
type SelectComponent,
compareLabelFn,
- DropdownMenu,
+ ControlledDropdownMenu,
NonBlockingDialog,
createFilter,
CustomSelectorInput,
@@ -106,7 +106,7 @@ export const ProjectSearchCommand = observer(() => {
className="search-modal"
>
{currentTabState instanceof ElementEditorState && (
- {
{currentTabState.generationModeState?.label ??
currentTabState.editMode}
-
+
)}
{currentTabState instanceof EntityDiffViewState && (
-
{
{currentTabState.diffMode}
-
+
)}
diff --git a/packages/legend-application-studio/src/components/editor/editor-group/GrammarTextEditor.tsx b/packages/legend-application-studio/src/components/editor/editor-group/GrammarTextEditor.tsx
index 1f967930f9..0a9feb3bbe 100644
--- a/packages/legend-application-studio/src/components/editor/editor-group/GrammarTextEditor.tsx
+++ b/packages/legend-application-studio/src/components/editor/editor-group/GrammarTextEditor.tsx
@@ -30,7 +30,7 @@ import {
MenuContentItem,
PanelLoadingIndicator,
CaretDownIcon,
- DropdownMenu,
+ ControlledDropdownMenu,
MenuContentItemIcon,
CheckIcon,
MenuContentItemLabel,
@@ -1251,7 +1251,7 @@ export const GrammarTextEditor = observer(() => {
- {
Advanced
-
+
diff --git a/packages/legend-application-studio/src/components/editor/editor-group/ModelImporter.tsx b/packages/legend-application-studio/src/components/editor/editor-group/ModelImporter.tsx
index 841b72ee6b..d2d2b519ff 100644
--- a/packages/legend-application-studio/src/components/editor/editor-group/ModelImporter.tsx
+++ b/packages/legend-application-studio/src/components/editor/editor-group/ModelImporter.tsx
@@ -25,7 +25,7 @@ import {
} from '../../../stores/editor/editor-state/ModelImporterState.js';
import { prettyCONSTName } from '@finos/legend-shared';
import {
- DropdownMenu,
+ ControlledDropdownMenu,
MenuContent,
MenuContentItem,
CaretDownIcon,
@@ -230,7 +230,7 @@ export const ModelImporter = observer(() => {
-
@@ -317,7 +317,7 @@ export const ModelImporter = observer(() => {
-
+
{modelImportEditorState.allowHardReplace && (
-
-
+
diff --git a/packages/legend-application-studio/src/components/editor/editor-group/connection-editor/post-processor-editor/MapperPostProcessorEditor.tsx b/packages/legend-application-studio/src/components/editor/editor-group/connection-editor/post-processor-editor/MapperPostProcessorEditor.tsx
index 0e80205968..368b9908c5 100644
--- a/packages/legend-application-studio/src/components/editor/editor-group/connection-editor/post-processor-editor/MapperPostProcessorEditor.tsx
+++ b/packages/legend-application-studio/src/components/editor/editor-group/connection-editor/post-processor-editor/MapperPostProcessorEditor.tsx
@@ -24,7 +24,7 @@ import {
ContextMenu,
MenuContent,
MenuContentItem,
- DropdownMenu,
+ ControlledDropdownMenu,
PanelListSelectorItem,
BlankPanelContent,
ResizablePanelSplitterLine,
@@ -137,7 +137,7 @@ export const MapperPostProcessorEditor = observer(
-
-
+
diff --git a/packages/legend-application-studio/src/components/editor/editor-group/data-editor/DataElementEditor.tsx b/packages/legend-application-studio/src/components/editor/editor-group/data-editor/DataElementEditor.tsx
index 93d57bbdf3..bfc8b830b3 100644
--- a/packages/legend-application-studio/src/components/editor/editor-group/data-editor/DataElementEditor.tsx
+++ b/packages/legend-application-studio/src/components/editor/editor-group/data-editor/DataElementEditor.tsx
@@ -24,7 +24,7 @@ import {
import {
CaretDownIcon,
clsx,
- DropdownMenu,
+ ControlledDropdownMenu,
InfoCircleIcon,
LockIcon,
MenuContent,
@@ -123,7 +123,7 @@ export const ExternalFormatDataEditor = observer(
-
-
+
diff --git a/packages/legend-application-studio/src/components/editor/editor-group/data-editor/EmbeddedDataEditor.tsx b/packages/legend-application-studio/src/components/editor/editor-group/data-editor/EmbeddedDataEditor.tsx
index d35b50ec75..fd6c940ac9 100644
--- a/packages/legend-application-studio/src/components/editor/editor-group/data-editor/EmbeddedDataEditor.tsx
+++ b/packages/legend-application-studio/src/components/editor/editor-group/data-editor/EmbeddedDataEditor.tsx
@@ -21,7 +21,7 @@ import {
CaretDownIcon,
clsx,
CustomSelectorInput,
- DropdownMenu,
+ ControlledDropdownMenu,
LockIcon,
LongArrowRightIcon,
MenuContent,
@@ -122,7 +122,7 @@ export const ExternalFormatDataEditor = observer(
>
-
-
+
diff --git a/packages/legend-application-studio/src/components/editor/editor-group/function-activator/FunctionEditor.tsx b/packages/legend-application-studio/src/components/editor/editor-group/function-activator/FunctionEditor.tsx
index 5a6a56fd44..1e077e052f 100644
--- a/packages/legend-application-studio/src/components/editor/editor-group/function-activator/FunctionEditor.tsx
+++ b/packages/legend-application-studio/src/components/editor/editor-group/function-activator/FunctionEditor.tsx
@@ -51,7 +51,7 @@ import {
ModalBody,
ModalFooter,
CaretDownIcon,
- DropdownMenu,
+ ControlledDropdownMenu,
BlankPanelContent,
MenuContent,
MenuContentItem,
@@ -1377,7 +1377,7 @@ export const FunctionEditor = observer(() => {
Run
-
{
}}
>
-
+
>
)}
diff --git a/packages/legend-application-studio/src/components/editor/editor-group/mapping-editor/MappingExecutionBuilder.tsx b/packages/legend-application-studio/src/components/editor/editor-group/mapping-editor/MappingExecutionBuilder.tsx
index 91738f4646..ac7dee2c1b 100644
--- a/packages/legend-application-studio/src/components/editor/editor-group/mapping-editor/MappingExecutionBuilder.tsx
+++ b/packages/legend-application-studio/src/components/editor/editor-group/mapping-editor/MappingExecutionBuilder.tsx
@@ -31,7 +31,7 @@ import {
FlaskIcon,
ResizablePanelSplitterLine,
compareLabelFn,
- DropdownMenu,
+ ControlledDropdownMenu,
MenuContent,
MenuContentItem,
CaretDownIcon,
@@ -560,7 +560,7 @@ const RelationalMappingExecutionInputDataTypeSelector = observer(
};
return (
-
-
+
);
},
);
@@ -819,7 +819,7 @@ export const MappingExecutionBuilder = observer(
Run Query
-
-
+
>
)}
diff --git a/packages/legend-application-studio/src/components/editor/editor-group/mapping-editor/MappingTestableEditor.tsx b/packages/legend-application-studio/src/components/editor/editor-group/mapping-editor/MappingTestableEditor.tsx
index 4aa475cb18..ca87fd08f0 100644
--- a/packages/legend-application-studio/src/components/editor/editor-group/mapping-editor/MappingTestableEditor.tsx
+++ b/packages/legend-application-studio/src/components/editor/editor-group/mapping-editor/MappingTestableEditor.tsx
@@ -42,7 +42,7 @@ import {
compareLabelFn,
CustomSelectorInput,
Dialog,
- DropdownMenu,
+ ControlledDropdownMenu,
MenuContent,
MenuContentItem,
Modal,
@@ -704,7 +704,7 @@ const MappingTestSuiteQueryEditor = observer(
Edit Query
-
@@ -728,7 +728,7 @@ const MappingTestSuiteQueryEditor = observer(
}}
>
-
+
diff --git a/packages/legend-application-studio/src/components/editor/editor-group/mapping-editor/legacy/DEPRECATED__MappingTestEditor.tsx b/packages/legend-application-studio/src/components/editor/editor-group/mapping-editor/legacy/DEPRECATED__MappingTestEditor.tsx
index 62fe845a2d..aaf830bd16 100644
--- a/packages/legend-application-studio/src/components/editor/editor-group/mapping-editor/legacy/DEPRECATED__MappingTestEditor.tsx
+++ b/packages/legend-application-studio/src/components/editor/editor-group/mapping-editor/legacy/DEPRECATED__MappingTestEditor.tsx
@@ -34,7 +34,7 @@ import {
ResizablePanel,
ResizablePanelSplitter,
ResizablePanelSplitterLine,
- DropdownMenu,
+ ControlledDropdownMenu,
MenuContent,
MenuContentItem,
CaretDownIcon,
@@ -274,7 +274,7 @@ const MappingTestQueryEditor = observer(
Edit Query
-
@@ -298,7 +298,7 @@ const MappingTestQueryEditor = observer(
}}
>
-
+
@@ -434,7 +434,7 @@ const RelationalMappingTestInputDataTypeSelector = observer(
relationalInputData_setInputType(inputDataState.inputData, val);
};
return (
-
-
+
);
},
);
@@ -814,7 +814,7 @@ export const DEPRECATED__MappingTestEditor = observer(
Run Test
-
-
+
>
)}
diff --git a/packages/legend-application-studio/src/components/editor/editor-group/project-configuration-editor/ProjectDependencyEditor.tsx b/packages/legend-application-studio/src/components/editor/editor-group/project-configuration-editor/ProjectDependencyEditor.tsx
index 13d2baa582..e033bde7a8 100644
--- a/packages/legend-application-studio/src/components/editor/editor-group/project-configuration-editor/ProjectDependencyEditor.tsx
+++ b/packages/legend-application-studio/src/components/editor/editor-group/project-configuration-editor/ProjectDependencyEditor.tsx
@@ -27,7 +27,7 @@ import {
CustomSelectorInput,
TimesIcon,
Dialog,
- DropdownMenu,
+ ControlledDropdownMenu,
CaretDownIcon,
MenuContentItem,
MenuContent,
@@ -932,7 +932,7 @@ const ProjectVersionDependencyEditor = observer(
!applicationStore.layoutService.TEMPORARY__isLightColorThemeEnabled
}
/>
-
@@ -958,7 +958,7 @@ const ProjectVersionDependencyEditor = observer(
}
>
Go to...
-
+
-
@@ -336,7 +336,7 @@ export const ServiceExecutionQueryEditor = observer(
}}
>
-
+
{executionState.isRunningQuery ? (
@@ -366,7 +366,7 @@ export const ServiceExecutionQueryEditor = observer(
Run Query
-
-
+
>
)}
-
-
+
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 f1ba81e319..e689f2358e 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
@@ -21,7 +21,7 @@ import {
ContextMenu,
CustomSelectorInput,
Dialog,
- DropdownMenu,
+ ControlledDropdownMenu,
InfoCircleIcon,
MaskIcon,
MenuContent,
@@ -549,7 +549,7 @@ export const ConnectionTestDataEditor = observer(
Generate
-
@@ -581,7 +581,7 @@ export const ConnectionTestDataEditor = observer(
}}
>
-
+
-
-
+
{renderSaveAsModal()}
>
);
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 2ad678491e..a74c7ac714 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
@@ -32,7 +32,7 @@ import {
MenuContentItemIcon,
MenuContentItemLabel,
ContextMenu,
- DropdownMenu,
+ ControlledDropdownMenu,
PanelLoadingIndicator,
BlankPanelContent,
TreeView,
@@ -405,7 +405,7 @@ const SampleDataGenerator = observer(() => {
>
-
{
-
+
{
)}
{!editorStore.disableGraphEditing && (
-
{
}}
>
-
+
)}
-
-
+
{(globalTestRunnerState.testableStates ?? []).map((testableState) => {
diff --git a/packages/legend-application-studio/src/components/project-reviewer/ProjectReviewerPanel.tsx b/packages/legend-application-studio/src/components/project-reviewer/ProjectReviewerPanel.tsx
index 67e765f1da..70995ba71c 100644
--- a/packages/legend-application-studio/src/components/project-reviewer/ProjectReviewerPanel.tsx
+++ b/packages/legend-application-studio/src/components/project-reviewer/ProjectReviewerPanel.tsx
@@ -17,7 +17,7 @@
import { observer } from 'mobx-react-lite';
import {
clsx,
- DropdownMenu,
+ ControlledDropdownMenu,
ContextMenu,
TimesIcon,
MenuContentItem,
@@ -154,7 +154,7 @@ export const ProjectReviewerPanel = observer(() => {
{currentTabState instanceof EntityDiffViewState && (
-
{
{currentTabState.diffMode}
-
+
)}
diff --git a/packages/legend-application/package.json b/packages/legend-application/package.json
index b0e7d82e6a..dd59060934 100644
--- a/packages/legend-application/package.json
+++ b/packages/legend-application/package.json
@@ -51,7 +51,7 @@
"@types/react-dom": "18.3.0",
"@types/react-router-dom": "5.3.3",
"history": "5.3.0",
- "mobx": "6.12.4",
+ "mobx": "6.12.5",
"mobx-react-lite": "4.0.7",
"react": "18.3.1",
"react-dnd": "16.0.1",
diff --git a/packages/legend-art/package.json b/packages/legend-art/package.json
index 6beaeaafe2..6c425975ac 100644
--- a/packages/legend-art/package.json
+++ b/packages/legend-art/package.json
@@ -26,7 +26,8 @@
"./markdown/test/MockedReactMarkdown.js": "./lib/markdown/__test-utils__/MockedReactMarkdown.js",
"./markdown/test/MockedRemarkGFM.js": "./lib/markdown/__test-utils__/MockedRemarkGFM.js",
"./lib/index.css": "./lib/index.css",
- "./lib/normalize.css": "./lib/normalize.css"
+ "./lib/normalize.css": "./lib/normalize.css",
+ "./lib/fonts.css": "./lib/fonts.css"
},
"module": "lib/index.js",
"types": "lib/index.d.ts",
@@ -50,19 +51,24 @@
"@emotion/react": "11.11.4",
"@emotion/styled": "11.11.5",
"@finos/legend-shared": "workspace:*",
+ "@fontsource/jetbrains-mono": "5.0.20",
"@fontsource/raleway": "5.0.19",
"@fontsource/roboto": "5.0.13",
"@fontsource/roboto-condensed": "5.0.16",
"@fontsource/roboto-mono": "5.0.18",
- "@mui/material": "5.15.20",
+ "@fontsource/roboto-serif": "5.0.13",
+ "@fontsource/ubuntu-mono": "5.0.20",
+ "@mui/material": "5.15.21",
"@types/react": "18.3.3",
"@types/react-select": "4.0.18",
"@types/react-window": "1.8.8",
"clsx": "2.1.1",
+ "color-parse": "2.0.2",
"mermaid": "10.9.1",
- "mobx": "6.12.4",
+ "mobx": "6.12.5",
"mobx-react-lite": "4.0.7",
"react": "18.3.1",
+ "react-colorful": "5.6.1",
"react-dnd": "16.0.1",
"react-dnd-html5-backend": "16.0.1",
"react-dom": "18.3.1",
diff --git a/packages/legend-art/src/button/Button.tsx b/packages/legend-art/src/button/Button.tsx
index 9604518aea..7a62f2f2ca 100644
--- a/packages/legend-art/src/button/Button.tsx
+++ b/packages/legend-art/src/button/Button.tsx
@@ -66,3 +66,5 @@ export const Button: React.FC<{
);
};
+
+export { Checkbox, type CheckboxProps } from '@mui/material';
diff --git a/packages/legend-application-repl/src/stores/dataCube/DataCubeDefaultConfig.ts b/packages/legend-art/src/color/ColorPicker.ts
similarity index 86%
rename from packages/legend-application-repl/src/stores/dataCube/DataCubeDefaultConfig.ts
rename to packages/legend-art/src/color/ColorPicker.ts
index eafd69f266..874554f806 100644
--- a/packages/legend-application-repl/src/stores/dataCube/DataCubeDefaultConfig.ts
+++ b/packages/legend-art/src/color/ColorPicker.ts
@@ -14,4 +14,8 @@
* limitations under the License.
*/
-export const DATA_CUBE_DEFAULT_REPORT_NAME = 'New Report';
+export {
+ HexColorPicker,
+ HexAlphaColorPicker,
+ HexColorInput,
+} from 'react-colorful';
diff --git a/packages/legend-art/src/color/TailwindCSSPalette.ts b/packages/legend-art/src/color/TailwindCSSPalette.ts
index 98008d6c9e..c4ba61dc4c 100644
--- a/packages/legend-art/src/color/TailwindCSSPalette.ts
+++ b/packages/legend-art/src/color/TailwindCSSPalette.ts
@@ -16,9 +16,13 @@
// Clone Tailwind CSS color palette to use for component code
// Source: https://github.com/tailwindlabs/tailwindcss/blob/master/src/public/colors.js
+
+export type TailwindCSSColorScaleKey = keyof typeof TailwindCSSPalette;
+export type TailwindCSSColorScale = (typeof TailwindCSSPalette)['slate'];
+
export const TailwindCSSPalette = {
- black: '#000',
- white: '#fff',
+ black: '#000000',
+ white: '#ffffff',
slate: {
50: '#f8fafc',
100: '#f1f5f9',
diff --git a/packages/legend-art/src/icon/DataCubeIcon.tsx b/packages/legend-art/src/icon/DataCubeIcon.tsx
index d00ffd80d8..67119e8691 100644
--- a/packages/legend-art/src/icon/DataCubeIcon.tsx
+++ b/packages/legend-art/src/icon/DataCubeIcon.tsx
@@ -18,8 +18,20 @@
// merging them in the main icon registry, we should review them
import { GoBrowser, GoPin, GoX } from 'react-icons/go';
-import { MdOutlineInsertPageBreak } from 'react-icons/md';
-import { PiMouseScroll } from 'react-icons/pi';
+import { GrCheckbox, GrCheckboxSelected } from 'react-icons/gr';
+import {
+ MdOutlineFormatBold,
+ MdOutlineFormatItalic,
+ MdOutlineStrikethroughS,
+ MdOutlineFormatUnderlined,
+ MdOutlineInsertPageBreak,
+} from 'react-icons/md';
+import {
+ PiMouseScroll,
+ PiTextAlignCenter,
+ PiTextAlignLeft,
+ PiTextAlignRight,
+} from 'react-icons/pi';
import {
TbBook,
TbCube,
@@ -44,17 +56,33 @@ import {
TbChevronLeft,
TbChevronRight,
TbSearch,
+ TbAlertTriangle,
+ TbExclamationCircle,
+ TbCaretDownFilled,
+ TbLoader2,
+ TbSettingsBolt,
+ TbSettings,
} from 'react-icons/tb';
export const DataCubeIcon = {
+ AdvancedSettings: TbSettingsBolt,
+ CaretDown: TbCaretDownFilled,
+ Checkbox: GrCheckbox,
+ CheckboxSelected: GrCheckboxSelected,
ChevronLeft: TbChevronLeft,
ChevronRight: TbChevronRight,
Code: TbCode,
Cube: TbCube,
Documentation: TbBook,
+ FontBold: MdOutlineFormatBold,
+ FontItalic: MdOutlineFormatItalic,
+ FontUnderlined: MdOutlineFormatUnderlined,
+ FontStrikethrough: MdOutlineStrikethroughS,
+ Loader: TbLoader2,
Note: TbNote,
Pin: GoPin,
Search: TbSearch,
+ Settings: TbSettings,
Table: TbTable,
TableColumn: TbFreezeColumn,
TableColumnOptions__Settings: TbSettingsFilled,
@@ -73,6 +101,11 @@ export const DataCubeIcon = {
TableRowColumn: TbFreezeRowColumn,
TableScroll: PiMouseScroll,
TableSort: TbTableDown,
+ TextAlignLeft: PiTextAlignLeft,
+ TextAlignCenter: PiTextAlignCenter,
+ TextAlignRight: PiTextAlignRight,
Window: GoBrowser,
X: GoX,
+ Warning: TbAlertTriangle,
+ WarningCircle: TbExclamationCircle,
};
diff --git a/packages/legend-art/src/index.ts b/packages/legend-art/src/index.ts
index cb4295a538..232b9656ad 100644
--- a/packages/legend-art/src/index.ts
+++ b/packages/legend-art/src/index.ts
@@ -42,6 +42,7 @@ export * from './dialog/Modal.js';
export * from './divider/Divider.js';
+export * from './menu/BaseMenu.js';
export * from './menu/MenuContent.js';
export * from './menu/ContextMenu.js';
export * from './menu/DropdownMenu.js';
@@ -78,3 +79,6 @@ export * from './utils/ComponentUtils.js';
export * from './markdown/MarkdownTextViewer.js';
export * from './Interaction.js';
+
+export * from './color/TailwindCSSPalette.js';
+export * from './color/ColorPicker.js';
diff --git a/packages/legend-art/src/menu/BaseMenu.tsx b/packages/legend-art/src/menu/BaseMenu.tsx
index ecf6c51380..a902e53bfa 100644
--- a/packages/legend-art/src/menu/BaseMenu.tsx
+++ b/packages/legend-art/src/menu/BaseMenu.tsx
@@ -14,9 +14,13 @@
* limitations under the License.
*/
-import { type MenuProps as MuiMenuProps, Menu as MuiMenu } from '@mui/material';
+import {
+ type MenuProps as MuiMenuProps,
+ Menu as MuiMenu,
+ MenuItem as MuiMenuItem,
+} from '@mui/material';
-export const BaseMenu: React.FC
= (props) => {
+export const Menu: React.FC = (props) => {
const { children, classes, ...otherProps } = props;
return (
@@ -33,3 +37,5 @@ export const BaseMenu: React.FC = (props) => {
);
};
+
+export { MuiMenuItem as BaseMenuItem, MuiMenu as BaseMenu };
diff --git a/packages/legend-art/src/menu/ContextMenu.tsx b/packages/legend-art/src/menu/ContextMenu.tsx
index 941494815e..ae5052c2a9 100644
--- a/packages/legend-art/src/menu/ContextMenu.tsx
+++ b/packages/legend-art/src/menu/ContextMenu.tsx
@@ -16,7 +16,7 @@
import { useState, useRef } from 'react';
import type { MenuProps as MuiMenuProps } from '@mui/material';
-import { BaseMenu } from './BaseMenu.js';
+import { Menu } from './BaseMenu.js';
export const ContextMenu: React.FC<{
children: React.ReactNode;
@@ -100,7 +100,7 @@ export const ContextMenu: React.FC<{
onContextMenu={onContextMenu}
>
{children}
-
{isOpen && content}
-
+
);
};
diff --git a/packages/legend-art/src/menu/DropdownMenu.tsx b/packages/legend-art/src/menu/DropdownMenu.tsx
index bf05d68205..46f52c39a0 100644
--- a/packages/legend-art/src/menu/DropdownMenu.tsx
+++ b/packages/legend-art/src/menu/DropdownMenu.tsx
@@ -15,10 +15,10 @@
*/
import { useEffect, useRef, useState } from 'react';
-import type { MenuProps as MuiMenuProps } from '@mui/material';
-import { BaseMenu } from './BaseMenu.js';
+import type { MenuItemProps, MenuProps as MuiMenuProps } from '@mui/material';
+import { BaseMenu, BaseMenuItem, Menu } from './BaseMenu.js';
-export const DropdownMenu: React.FC<{
+export const ControlledDropdownMenu: React.FC<{
children: React.ReactNode;
open?: boolean | undefined;
menuProps?: Partial
| undefined;
@@ -28,6 +28,7 @@ export const DropdownMenu: React.FC<{
title?: string | undefined;
onOpen?: (() => void) | undefined;
onClose?: (() => void) | undefined;
+ useCapture?: boolean | undefined;
}> = (props) => {
const {
open,
@@ -39,6 +40,7 @@ export const DropdownMenu: React.FC<{
disabled,
onClose,
onOpen,
+ useCapture,
} = props;
const triggerRef = useRef(null);
const [anchorEl, setAnchorEl] = useState(null);
@@ -48,12 +50,7 @@ export const DropdownMenu: React.FC<{
if (disabled) {
return;
}
- if (anchorEl) {
- // if the trigger is clicked and the menu is already opened, close it
- onClose?.();
- setAnchorEl(null);
- } else if (triggerRef.current) {
- // if the trigger is clicked, open the dropdown menu
+ if (triggerRef.current) {
onOpen?.();
setAnchorEl(triggerRef.current);
}
@@ -73,30 +70,115 @@ export const DropdownMenu: React.FC<{
}, [anchorEl, open]);
return (
-
- {children}
-
+ {
+ event.stopPropagation();
+ },
+ }
+ : { onClick: onTriggerClick })}
+ title={title}
+ >
+ {children}
+
+ {
+ onClose?.();
+ setAnchorEl(null);
+ }}
{...menuProps}
>
{content}
-
-
+
+ >
);
};
+
+export function useDropdownMenu() {
+ const [anchorEl, setAnchorEl] = useState(null);
+ return [
+ (event: React.MouseEvent) => setAnchorEl(event.currentTarget),
+ () => setAnchorEl(null),
+ {
+ anchorEl,
+ onClose: () => setAnchorEl(null),
+ },
+ ] as const;
+}
+
+export type DropdownMenuProps = {
+ children: React.ReactNode;
+ anchorEl: Element | null;
+ onClose: () => void;
+ className?: string | undefined;
+ menuProps?: Partial | undefined;
+};
+
+export function DropdownMenu(props: DropdownMenuProps) {
+ const { menuProps, children, onClose, anchorEl } = props;
+
+ if (!anchorEl) {
+ return null;
+ }
+ return (
+
+ {children}
+
+ );
+}
+
+export type DropdownMenuItemProps = MenuItemProps;
+
+export function DropdownMenuItem(props: DropdownMenuItemProps) {
+ return (
+
+ );
+}
diff --git a/packages/legend-art/style/fonts.scss b/packages/legend-art/style/fonts.scss
new file mode 100644
index 0000000000..fb7156761d
--- /dev/null
+++ b/packages/legend-art/style/fonts.scss
@@ -0,0 +1,49 @@
+/**
+ * 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.
+ */
+
+// Used by the application
+@import url('@fontsource/roboto/100.css');
+// @import url('@fontsource/roboto/200.css');
+@import url('@fontsource/roboto/300.css');
+@import url('@fontsource/roboto/400.css');
+@import url('@fontsource/roboto/500.css');
+// @import url('@fontsource/roboto/600.css');
+@import url('@fontsource/roboto/700.css');
+// @import url('@fontsource/roboto/800.css');
+@import url('@fontsource/roboto/900.css');
+
+@import url('@fontsource/roboto-mono/100.css');
+@import url('@fontsource/roboto-mono/200.css');
+@import url('@fontsource/roboto-mono/300.css');
+@import url('@fontsource/roboto-mono/400.css');
+@import url('@fontsource/roboto-mono/500.css');
+@import url('@fontsource/roboto-mono/600.css');
+@import url('@fontsource/roboto-mono/700.css');
+// @import url('@fontsource/roboto-mono/800.css');
+// @import url('@fontsource/roboto-mono/900.css');
+
+// Used for rendering the grid per configuration
+@import url('@fontsource/roboto-condensed/400.css');
+@import url('@fontsource/roboto-condensed/700.css');
+
+@import url('@fontsource/roboto-serif/400.css');
+@import url('@fontsource/roboto-serif/700.css');
+
+@import url('@fontsource/ubuntu-mono/400.css');
+@import url('@fontsource/ubuntu-mono/700.css');
+
+@import url('@fontsource/jetbrains-mono/400.css');
+@import url('@fontsource/jetbrains-mono/700.css');
diff --git a/packages/legend-dev-utils/WebpackConfigUtils.js b/packages/legend-dev-utils/WebpackConfigUtils.js
index 483efb59f7..20740daf46 100644
--- a/packages/legend-dev-utils/WebpackConfigUtils.js
+++ b/packages/legend-dev-utils/WebpackConfigUtils.js
@@ -45,7 +45,7 @@ export const getBaseWebpackConfig = (
arg,
dirname,
{ babelConfigPath },
- isRelativePathSupported,
+ useRelativePath,
) => {
if (!dirname) {
throw new Error(`\`dirname\` is required to build Webpack config`);
@@ -126,7 +126,7 @@ export const getBaseWebpackConfig = (
use: [
{
loader: MiniCssExtractPlugin.loader,
- options: isRelativePathSupported
+ options: useRelativePath
? {
publicPath: '../',
}
@@ -260,7 +260,7 @@ export const getWebAppBaseWebpackConfig = (
{
babelConfigPath,
},
- appConfig.isRelativePathSupported,
+ appConfig.useRelativePath,
);
validateAppConfig(appConfig, dirname);
@@ -288,7 +288,7 @@ export const getWebAppBaseWebpackConfig = (
}`,
publicPath: isEnvDevelopment
? '/'
- : appConfig.isRelativePathSupported
+ : appConfig.useRelativePath
? './'
: appConfig.baseUrl,
filename: `${staticPath}/${
diff --git a/packages/legend-dev-utils/package.json b/packages/legend-dev-utils/package.json
index 7743ff3f0c..e37eb83003 100644
--- a/packages/legend-dev-utils/package.json
+++ b/packages/legend-dev-utils/package.json
@@ -83,7 +83,7 @@
"mini-css-extract-plugin": "2.9.0",
"monaco-editor": "0.50.0",
"monaco-editor-webpack-plugin": "7.1.0",
- "postcss": "8.4.38",
+ "postcss": "8.4.39",
"postcss-loader": "8.1.1",
"react-refresh": "0.14.2",
"resolve": "1.22.8",
diff --git a/packages/legend-extension-assortment/package.json b/packages/legend-extension-assortment/package.json
index eafc41ac41..10761f27c8 100644
--- a/packages/legend-extension-assortment/package.json
+++ b/packages/legend-extension-assortment/package.json
@@ -49,7 +49,7 @@
"@finos/legend-lego": "workspace:*",
"@finos/legend-shared": "workspace:*",
"@types/react": "18.3.3",
- "mobx": "6.12.4",
+ "mobx": "6.12.5",
"mobx-react-lite": "4.0.7",
"react": "18.3.1",
"serializr": "3.0.2"
diff --git a/packages/legend-extension-dsl-data-space-studio/package.json b/packages/legend-extension-dsl-data-space-studio/package.json
index a5056a406e..b7a4707b09 100644
--- a/packages/legend-extension-dsl-data-space-studio/package.json
+++ b/packages/legend-extension-dsl-data-space-studio/package.json
@@ -50,7 +50,7 @@
"@finos/legend-server-depot": "workspace:*",
"@finos/legend-server-sdlc": "workspace:*",
"@finos/legend-shared": "workspace:*",
- "mobx": "6.12.4",
+ "mobx": "6.12.5",
"mobx-react-lite": "4.0.7"
},
"devDependencies": {
diff --git a/packages/legend-extension-dsl-data-space/package.json b/packages/legend-extension-dsl-data-space/package.json
index 5b1fa0d674..e48778551d 100644
--- a/packages/legend-extension-dsl-data-space/package.json
+++ b/packages/legend-extension-dsl-data-space/package.json
@@ -54,7 +54,7 @@
"@finos/legend-shared": "workspace:*",
"@finos/legend-storage": "workspace:*",
"@types/react": "18.3.3",
- "mobx": "6.12.4",
+ "mobx": "6.12.5",
"mobx-react-lite": "4.0.7",
"react": "18.3.1",
"react-dom": "18.3.1",
diff --git a/packages/legend-extension-dsl-data-space/src/components/DataSpaceDiagramViewer.tsx b/packages/legend-extension-dsl-data-space/src/components/DataSpaceDiagramViewer.tsx
index 3fb098446c..f10e86a1bd 100644
--- a/packages/legend-extension-dsl-data-space/src/components/DataSpaceDiagramViewer.tsx
+++ b/packages/legend-extension-dsl-data-space/src/components/DataSpaceDiagramViewer.tsx
@@ -23,7 +23,7 @@ import {
ContextMenu,
CustomSelectorInput,
DescriptionIcon,
- DropdownMenu,
+ ControlledDropdownMenu,
MenuContent,
MenuContentDivider,
MenuContentItem,
@@ -432,7 +432,7 @@ const DataSpaceDiagramViewerHeader = observer(
-
-
+
>
)}
diff --git a/packages/legend-extension-dsl-data-space/src/components/DataSpaceModelsDocumentation.tsx b/packages/legend-extension-dsl-data-space/src/components/DataSpaceModelsDocumentation.tsx
index fc88f829ac..7d3a5bbd33 100644
--- a/packages/legend-extension-dsl-data-space/src/components/DataSpaceModelsDocumentation.tsx
+++ b/packages/legend-extension-dsl-data-space/src/components/DataSpaceModelsDocumentation.tsx
@@ -22,7 +22,7 @@ import {
ChevronRightIcon,
ClockIcon,
CogIcon,
- DropdownMenu,
+ ControlledDropdownMenu,
FilterIcon,
InfoCircleIcon,
MenuContent,
@@ -281,7 +281,7 @@ const ElementContentCellRenderer = observer(
-
-
+
);
@@ -326,7 +326,7 @@ const ElementContentCellRenderer = observer(
-
-
+
);
@@ -368,7 +368,7 @@ const ElementContentCellRenderer = observer(
-
-
+
);
@@ -454,7 +454,7 @@ const SubElementDocContentCellRenderer = observer(
-
-
+
);
@@ -496,7 +496,7 @@ const SubElementDocContentCellRenderer = observer(
-
-
+
);
diff --git a/packages/legend-extension-dsl-data-space/src/components/DataSpaceViewer.tsx b/packages/legend-extension-dsl-data-space/src/components/DataSpaceViewer.tsx
index 8e52d864a7..eee24e7aba 100644
--- a/packages/legend-extension-dsl-data-space/src/components/DataSpaceViewer.tsx
+++ b/packages/legend-extension-dsl-data-space/src/components/DataSpaceViewer.tsx
@@ -18,7 +18,7 @@ import { observer } from 'mobx-react-lite';
import {
CaretDownIcon,
CaretUpIcon,
- DropdownMenu,
+ ControlledDropdownMenu,
MenuContent,
MenuContentDivider,
MenuContentItem,
@@ -88,7 +88,7 @@ const DataSpaceHeader = observer(
)}
-
-
-
+
-
+
diff --git a/packages/legend-extension-dsl-data-space/src/components/DataSpaceViewerActivityBar.tsx b/packages/legend-extension-dsl-data-space/src/components/DataSpaceViewerActivityBar.tsx
index 8ba02c8566..a47f274594 100644
--- a/packages/legend-extension-dsl-data-space/src/components/DataSpaceViewerActivityBar.tsx
+++ b/packages/legend-extension-dsl-data-space/src/components/DataSpaceViewerActivityBar.tsx
@@ -32,7 +32,7 @@ import {
MenuContent,
MenuContentItem,
MenuIcon,
- DropdownMenu,
+ ControlledDropdownMenu,
DataReadyIcon,
SparkleIcon,
} from '@finos/legend-art';
@@ -55,7 +55,7 @@ const ActivityBarMenu = observer(
return (
<>
-
-
+
>
);
diff --git a/packages/legend-extension-dsl-data-space/src/components/query-builder/DataSpaceQueryBuilder.tsx b/packages/legend-extension-dsl-data-space/src/components/query-builder/DataSpaceQueryBuilder.tsx
index 7665e9129c..e0fb5b3e5f 100644
--- a/packages/legend-extension-dsl-data-space/src/components/query-builder/DataSpaceQueryBuilder.tsx
+++ b/packages/legend-extension-dsl-data-space/src/components/query-builder/DataSpaceQueryBuilder.tsx
@@ -17,7 +17,7 @@
import {
CustomSelectorInput,
createFilter,
- DropdownMenu,
+ ControlledDropdownMenu,
MenuContentItem,
MenuContent,
MenuContentItemIcon,
@@ -229,7 +229,7 @@ const DataSpaceQueryBuilderSetupPanelContent = observer(
-
-
+
diff --git a/packages/legend-extension-dsl-diagram/package.json b/packages/legend-extension-dsl-diagram/package.json
index 1b81678583..0472447bd4 100644
--- a/packages/legend-extension-dsl-diagram/package.json
+++ b/packages/legend-extension-dsl-diagram/package.json
@@ -54,7 +54,7 @@
"@finos/legend-shared": "workspace:*",
"@finos/legend-storage": "workspace:*",
"@types/react": "18.3.3",
- "mobx": "6.12.4",
+ "mobx": "6.12.5",
"mobx-react-lite": "4.0.7",
"react": "18.3.1",
"react-dnd": "16.0.1",
diff --git a/packages/legend-extension-dsl-diagram/src/components/studio/DiagramEditor.tsx b/packages/legend-extension-dsl-diagram/src/components/studio/DiagramEditor.tsx
index 709d02504a..03e2c7fbaa 100644
--- a/packages/legend-extension-dsl-diagram/src/components/studio/DiagramEditor.tsx
+++ b/packages/legend-extension-dsl-diagram/src/components/studio/DiagramEditor.tsx
@@ -44,7 +44,7 @@ import {
createFilter,
CustomSelectorInput,
KeyboardIcon,
- DropdownMenu,
+ ControlledDropdownMenu,
MenuContent,
MenuContentDivider,
MenuContentItem,
@@ -1401,7 +1401,7 @@ const DiagramEditorHeader = observer(
-
-
+
{
)}
- {
-
+
{isPreviewSupported ? (
-
-
+
diff --git a/packages/legend-graph/package.json b/packages/legend-graph/package.json
index 4c1922d7f1..86845af4a2 100644
--- a/packages/legend-graph/package.json
+++ b/packages/legend-graph/package.json
@@ -42,7 +42,7 @@
"dependencies": {
"@finos/legend-shared": "workspace:*",
"@finos/legend-storage": "workspace:*",
- "mobx": "6.12.4",
+ "mobx": "6.12.5",
"serializr": "3.0.2"
},
"devDependencies": {
diff --git a/packages/legend-lego/package.json b/packages/legend-lego/package.json
index 9cf3e577fc..68ee84fbf0 100644
--- a/packages/legend-lego/package.json
+++ b/packages/legend-lego/package.json
@@ -70,7 +70,7 @@
"@types/css-font-loading-module": "0.0.13",
"@types/react": "18.3.3",
"@types/react-dom": "18.3.0",
- "mobx": "6.12.4",
+ "mobx": "6.12.5",
"mobx-react-lite": "4.0.7",
"monaco-editor": "0.50.0",
"react": "18.3.1",
diff --git a/packages/legend-lego/src/application/TabManager.tsx b/packages/legend-lego/src/application/TabManager.tsx
index 35bc656511..e08205c472 100644
--- a/packages/legend-lego/src/application/TabManager.tsx
+++ b/packages/legend-lego/src/application/TabManager.tsx
@@ -19,7 +19,7 @@ import {
clsx,
ContextMenu,
DragPreviewLayer,
- DropdownMenu,
+ ControlledDropdownMenu,
MenuContent,
MenuContentItem,
PanelEntryDropZonePlaceholder,
@@ -212,7 +212,7 @@ const Tab = observer(
const TabMenu = observer((props: { managerTabState: TabManagerState }) => {
const { managerTabState } = props;
return (
- {
}}
>
-
+
);
});
diff --git a/packages/legend-query-builder/package.json b/packages/legend-query-builder/package.json
index 680c72160d..3b1f225507 100644
--- a/packages/legend-query-builder/package.json
+++ b/packages/legend-query-builder/package.json
@@ -54,8 +54,8 @@
"@types/react": "18.3.3",
"@types/react-dom": "18.3.0",
"chart.js": "4.4.3",
- "mathjs": "13.0.0",
- "mobx": "6.12.4",
+ "mathjs": "13.0.1",
+ "mobx": "6.12.5",
"mobx-react-lite": "4.0.7",
"monaco-editor": "0.50.0",
"react": "18.3.1",
diff --git a/packages/legend-query-builder/src/components/QueryBuilder.tsx b/packages/legend-query-builder/src/components/QueryBuilder.tsx
index a0d5a8ed3e..091993b13f 100644
--- a/packages/legend-query-builder/src/components/QueryBuilder.tsx
+++ b/packages/legend-query-builder/src/components/QueryBuilder.tsx
@@ -21,7 +21,7 @@ import {
ResizablePanel,
ResizablePanelSplitter,
HackerIcon,
- DropdownMenu,
+ ControlledDropdownMenu,
MenuContent,
MenuContentItem,
MenuContentItemIcon,
@@ -602,7 +602,7 @@ export const QueryBuilder = observer(
{actionConfig.renderer(queryBuilderState)}
))}
-
-
-
+
@@ -960,7 +960,7 @@ export const QueryBuilder = observer(
Help...
-
+
diff --git a/packages/legend-query-builder/src/components/QueryLoader.tsx b/packages/legend-query-builder/src/components/QueryLoader.tsx
index 2fe3a90478..e29ac1b509 100644
--- a/packages/legend-query-builder/src/components/QueryLoader.tsx
+++ b/packages/legend-query-builder/src/components/QueryLoader.tsx
@@ -26,7 +26,7 @@ import {
clsx,
SearchIcon,
TimesIcon,
- DropdownMenu,
+ ControlledDropdownMenu,
MenuContent,
MenuContentItem,
BlankPanelContent,
@@ -474,7 +474,7 @@ export const QueryLoader = observer(
-
-
+
@@ -555,7 +555,7 @@ export const QueryLoader = observer(
{templateQuery.description}
-
-
+
diff --git a/packages/legend-query-builder/src/components/execution-plan/ExecutionPlanViewer.tsx b/packages/legend-query-builder/src/components/execution-plan/ExecutionPlanViewer.tsx
index b158ea13e2..c122f5eb27 100644
--- a/packages/legend-query-builder/src/components/execution-plan/ExecutionPlanViewer.tsx
+++ b/packages/legend-query-builder/src/components/execution-plan/ExecutionPlanViewer.tsx
@@ -28,7 +28,7 @@ import {
ChevronRightIcon,
MenuContentItem,
MenuContent,
- DropdownMenu,
+ ControlledDropdownMenu,
BlankPanelContent,
PanelContent,
ModalHeader,
@@ -684,7 +684,7 @@ const ExecutionPlanViewPanel = observer(
{executionPlanState.selectedNode.label}
-
{executionPlanState.viewMode}
-
+
{executionPlanState.viewMode === EXECUTION_PLAN_VIEW_MODE.JSON &&
diff --git a/packages/legend-query-builder/src/components/explorer/QueryBuilderExplorerPanel.tsx b/packages/legend-query-builder/src/components/explorer/QueryBuilderExplorerPanel.tsx
index 9940025e1e..d51aa3afff 100644
--- a/packages/legend-query-builder/src/components/explorer/QueryBuilderExplorerPanel.tsx
+++ b/packages/legend-query-builder/src/components/explorer/QueryBuilderExplorerPanel.tsx
@@ -26,7 +26,7 @@ import {
Dialog,
TreeView,
BlankPanelContent,
- DropdownMenu,
+ ControlledDropdownMenu,
ContextMenu,
MenuContent,
MenuContentItem,
@@ -928,7 +928,7 @@ export const QueryBuilderExplorerPanel = observer(
-
-
+
{propertySearchPanelState.isSearchPanelOpen && (
)}
-
-
+
diff --git a/packages/legend-query-builder/src/components/fetch-structure/QueryBuilderPostFilterPanel.tsx b/packages/legend-query-builder/src/components/fetch-structure/QueryBuilderPostFilterPanel.tsx
index 84c11b2b32..e3bb97bf28 100644
--- a/packages/legend-query-builder/src/components/fetch-structure/QueryBuilderPostFilterPanel.tsx
+++ b/packages/legend-query-builder/src/components/fetch-structure/QueryBuilderPostFilterPanel.tsx
@@ -24,7 +24,7 @@ import {
ChevronRightIcon,
clsx,
ContextMenu,
- DropdownMenu,
+ ControlledDropdownMenu,
FilledTriangleIcon,
MenuContent,
MenuContentItem,
@@ -525,7 +525,7 @@ const QueryBuilderPostFilterConditionEditor = observer(
colState={node.condition.leftConditionValue}
/>
-
-
+
{renderRightVal()}
@@ -1081,7 +1081,7 @@ const QueryBuilderPostFilterPanelContent = observer(
)}
-
-
+
@@ -1196,7 +1196,7 @@ const QueryBuilderPostFilterPanelContent = observer(
className="query-builder-post-filter-tree__free-drop-zone"
label="Add post-filter to main group"
>
- <>>{' '}
+ <>>
)}
diff --git a/packages/legend-query-builder/src/components/fetch-structure/QueryBuilderTDSPanel.tsx b/packages/legend-query-builder/src/components/fetch-structure/QueryBuilderTDSPanel.tsx
index 883617f826..8fab099855 100644
--- a/packages/legend-query-builder/src/components/fetch-structure/QueryBuilderTDSPanel.tsx
+++ b/packages/legend-query-builder/src/components/fetch-structure/QueryBuilderTDSPanel.tsx
@@ -21,7 +21,7 @@ import {
BlankPanelPlaceholder,
CalculatorIcon,
TimesIcon,
- DropdownMenu,
+ ControlledDropdownMenu,
MenuContent,
MenuContentItem,
CaretDownIcon,
@@ -1044,7 +1044,7 @@ const QueryBuilderProjectionColumnEditor = observer(
)}
-
-
+
diff --git a/packages/legend-query-builder/src/components/fetch-structure/QueryBuilderTDSWindowPanel.tsx b/packages/legend-query-builder/src/components/fetch-structure/QueryBuilderTDSWindowPanel.tsx
index 5c73d901ee..c75297b036 100644
--- a/packages/legend-query-builder/src/components/fetch-structure/QueryBuilderTDSWindowPanel.tsx
+++ b/packages/legend-query-builder/src/components/fetch-structure/QueryBuilderTDSWindowPanel.tsx
@@ -20,7 +20,7 @@ import {
PanelContent,
PanelDropZone,
BlankPanelPlaceholder,
- DropdownMenu,
+ ControlledDropdownMenu,
InputWithInlineValidation,
MenuContent,
MenuContentItem,
@@ -439,7 +439,7 @@ const QueryBuilderWindowColumnModalEditor = observer(
>
{selectedOperatorState.operator.getLabel()}
-
-
+
@@ -553,7 +553,7 @@ const QueryBuilderWindowColumnModalEditor = observer(
{selectedSortBy.sortType.toLowerCase()}
)}
-
-
+
@@ -1007,7 +1007,7 @@ const QueryBuilderWindowColumnEditor = observer(
>
{operationState.operator.getLabel()}
-
-
+
@@ -1132,7 +1132,7 @@ const QueryBuilderWindowColumnEditor = observer(
{sortByState.sortType.toLowerCase()}
)}
-
-
+
diff --git a/packages/legend-query-builder/src/components/filter/QueryBuilderFilterPanel.tsx b/packages/legend-query-builder/src/components/filter/QueryBuilderFilterPanel.tsx
index 488ae2219c..fa5d9fd38d 100644
--- a/packages/legend-query-builder/src/components/filter/QueryBuilderFilterPanel.tsx
+++ b/packages/legend-query-builder/src/components/filter/QueryBuilderFilterPanel.tsx
@@ -28,7 +28,7 @@ import {
type TreeNodeViewProps,
clsx,
ContextMenu,
- DropdownMenu,
+ ControlledDropdownMenu,
MenuContent,
MenuContentItem,
BlankPanelPlaceholder,
@@ -828,7 +828,7 @@ const QueryBuilderFilterConditionEditor = observer(
propertyExpressionState={node.condition.propertyExpressionState}
/>
-
-
+
{node.condition.value && (
diff --git a/packages/legend-query-builder/src/components/result/QueryBuilderResultPanel.tsx b/packages/legend-query-builder/src/components/result/QueryBuilderResultPanel.tsx
index c3fc8f657e..05b3440c55 100644
--- a/packages/legend-query-builder/src/components/result/QueryBuilderResultPanel.tsx
+++ b/packages/legend-query-builder/src/components/result/QueryBuilderResultPanel.tsx
@@ -17,7 +17,7 @@
import {
BlankPanelContent,
PlayIcon,
- DropdownMenu,
+ ControlledDropdownMenu,
MenuContent,
MenuContentItem,
CaretDownIcon,
@@ -517,7 +517,7 @@ export const QueryBuilderResultPanel = observer(
Run Query
-
-
+
>
)}
-
-
+
{resultState.isQueryUsageViewerOpened && (
)}
diff --git a/packages/legend-server-sdlc/package.json b/packages/legend-server-sdlc/package.json
index 29ff5aa9d3..06f43a395d 100644
--- a/packages/legend-server-sdlc/package.json
+++ b/packages/legend-server-sdlc/package.json
@@ -41,7 +41,7 @@
"dependencies": {
"@finos/legend-shared": "workspace:*",
"@finos/legend-storage": "workspace:*",
- "mobx": "6.12.4",
+ "mobx": "6.12.5",
"serializr": "3.0.2"
},
"devDependencies": {
diff --git a/packages/legend-server-showcase-deployment/package.json b/packages/legend-server-showcase-deployment/package.json
index e05e714ab0..666e2ee36d 100644
--- a/packages/legend-server-showcase-deployment/package.json
+++ b/packages/legend-server-showcase-deployment/package.json
@@ -53,7 +53,7 @@
"@fastify/cors": "9.0.1",
"@finos/legend-server-showcase": "workspace:*",
"@finos/legend-shared": "workspace:*",
- "fastify": "4.28.0"
+ "fastify": "4.28.1"
},
"devDependencies": {
"@finos/legend-dev-utils": "workspace:*",
diff --git a/packages/legend-server-showcase/package.json b/packages/legend-server-showcase/package.json
index 05e0504ec7..6cbcfdab5c 100644
--- a/packages/legend-server-showcase/package.json
+++ b/packages/legend-server-showcase/package.json
@@ -39,8 +39,8 @@
},
"dependencies": {
"@finos/legend-shared": "workspace:*",
- "fastify": "4.28.0",
- "mobx": "6.12.4",
+ "fastify": "4.28.1",
+ "mobx": "6.12.5",
"serializr": "3.0.2",
"yaml": "2.4.5"
},
diff --git a/packages/legend-shared/package.json b/packages/legend-shared/package.json
index ffa674b3b5..93600ba298 100644
--- a/packages/legend-shared/package.json
+++ b/packages/legend-shared/package.json
@@ -48,12 +48,13 @@
"@types/seedrandom": "3.0.8",
"@types/uuid": "10.0.0",
"date-fns": "3.6.0",
+ "deep-object-diff": "^1.1.9",
"fuse.js": "7.0.0",
"hash.js": "1.1.7",
"http-status-codes": "2.3.0",
"lodash-es": "4.17.21",
"lossless-json": "4.0.1",
- "mobx": "6.12.4",
+ "mobx": "6.12.5",
"object-hash": "3.0.0",
"pako": "2.1.0",
"papaparse": "5.4.1",
diff --git a/packages/legend-shared/src/CommonUtils.ts b/packages/legend-shared/src/CommonUtils.ts
index a2087f0f96..19d4c07980 100644
--- a/packages/legend-shared/src/CommonUtils.ts
+++ b/packages/legend-shared/src/CommonUtils.ts
@@ -30,6 +30,7 @@ import {
type DebouncedFunc,
isObject,
} from 'lodash-es';
+import { diff as deepDiff } from 'deep-object-diff';
import { UnsupportedOperationError } from './error/ErrorUtils.js';
import { format as prettyPrintObject } from 'pretty-format';
import { assertTrue, guaranteeNonNullable } from './error/AssertionUtils.js';
@@ -40,6 +41,7 @@ export {
clone,
deepClone,
deepEqual,
+ deepDiff,
findLast,
isEmpty,
pickBy,
@@ -47,6 +49,7 @@ export {
uniq,
debounce,
throttle,
+ toNumber,
type DebouncedFunc,
};
diff --git a/packages/legend-shared/src/network/NetworkUtils.ts b/packages/legend-shared/src/network/NetworkUtils.ts
index 6c5efce5f2..dc7e775aa4 100644
--- a/packages/legend-shared/src/network/NetworkUtils.ts
+++ b/packages/legend-shared/src/network/NetworkUtils.ts
@@ -43,7 +43,7 @@ export const URL_SEPARATOR = '/';
* Reference: https://uibakery.io/regex-library/url
*/
const URL_REGEX = new RegExp(
- '^https?://(?:www.)?[-a-zA-Z0-9@:%._+~#=]{1,256}.[a-zA-Z0-9()]{1,6}\\b(?:[-a-zA-Z0-9()@:%_+.~#?&/=]*)$',
+ '^(?:https?|ssh|ftp|file)://(?:www.)?[-a-zA-Z0-9@:%._+~#=]{1,256}.[a-zA-Z0-9()]{1,6}\\b(?:[-a-zA-Z0-9()@:%_+.~#?&/=]*)$',
);
export const HttpStatus = StatusCodes;
export const CHARSET = 'charset=utf-8';
diff --git a/packages/legend-vscode-extension-dependencies/package.json b/packages/legend-vscode-extension-dependencies/package.json
index 426449e20d..ff42b1495d 100644
--- a/packages/legend-vscode-extension-dependencies/package.json
+++ b/packages/legend-vscode-extension-dependencies/package.json
@@ -44,6 +44,7 @@
"@finos/legend-storage": "workspace:*"
},
"devDependencies": {
+ "@babel/core": "7.24.7",
"@finos/legend-dev-utils": "workspace:*",
"@rollup/plugin-babel": "6.0.4",
"@rollup/plugin-commonjs": "26.0.1",
@@ -57,7 +58,7 @@
"rollup": "4.18.0",
"rollup-plugin-flow": "1.1.1",
"rollup-plugin-import-css": "3.5.0",
- "typescript": "5.4.5"
+ "typescript": "5.5.2"
},
"publishConfig": {
"directory": "build/publishContent"
diff --git a/packages/stylelint-config/package.json b/packages/stylelint-config/package.json
index a811170529..2a16c701ff 100644
--- a/packages/stylelint-config/package.json
+++ b/packages/stylelint-config/package.json
@@ -29,7 +29,7 @@
"publish:snapshot": "node ../../scripts/release/publishDevSnapshot.js"
},
"dependencies": {
- "postcss": "8.4.38",
+ "postcss": "8.4.39",
"postcss-scss": "4.0.9",
"stylelint-config-standard": "36.0.1",
"stylelint-scss": "6.3.2"
@@ -40,7 +40,7 @@
"rimraf": "5.0.7"
},
"peerDependencies": {
- "stylelint": "^15.0.0"
+ "stylelint": ">16.0.0"
},
"publishConfig": {
"directory": "build/publishContent"
diff --git a/scripts/test/fixWatchman.js b/scripts/test/fixWatchman.js
new file mode 100644
index 0000000000..e38cab91e7
--- /dev/null
+++ b/scripts/test/fixWatchman.js
@@ -0,0 +1,27 @@
+/**
+ * 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 { resolve, dirname } from 'path';
+import { execSync } from 'child_process';
+import { fileURLToPath } from 'url';
+
+const __dirname = dirname(fileURLToPath(import.meta.url));
+
+// avoid watchman recrawl
+// See https://facebook.github.io/watchman/docs/troubleshooting.html#recrawl
+// TODO: do we need to do this every time we re-run dev script? or should we find a way to
+// reduce workload for watchman?
+execSync(`watchman watch-del '${resolve(__dirname, '../../')}'`);
diff --git a/yarn.lock b/yarn.lock
index 38d741d6e3..b277effecf 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1635,7 +1635,7 @@ __metadata:
languageName: node
linkType: hard
-"@babel/runtime@npm:7.24.7, @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.23.9, @babel/runtime@npm:^7.24.1, @babel/runtime@npm:^7.24.6, @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.24.7, @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.23.9, @babel/runtime@npm:^7.24.1, @babel/runtime@npm:^7.24.7, @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.24.7
resolution: "@babel/runtime@npm:7.24.7"
dependencies:
@@ -1975,28 +1975,28 @@ __metadata:
linkType: hard
"@csstools/css-parser-algorithms@npm:^2.6.3":
- version: 2.6.3
- resolution: "@csstools/css-parser-algorithms@npm:2.6.3"
+ version: 2.7.0
+ resolution: "@csstools/css-parser-algorithms@npm:2.7.0"
peerDependencies:
- "@csstools/css-tokenizer": ^2.3.1
- checksum: 10/b893e284ebcccf37d7928be31be94fb0d6725defc544b39892d5e59ed5950b413366491817539b0add08deb9fc258c57588053d4436f84b7bd3b43bfeee67bb1
+ "@csstools/css-tokenizer": ^2.3.2
+ checksum: 10/b9c01c0d0b360434debc20e2767bf4fb2a469e479a41bdaf908b0b626ae58a265deda07825a4cb3ddb8aab63c4bfdd6f594ad368fef43471ee2f9aa364f09077
languageName: node
linkType: hard
"@csstools/css-tokenizer@npm:^2.3.1":
- version: 2.3.1
- resolution: "@csstools/css-tokenizer@npm:2.3.1"
- checksum: 10/25c8643151667bfc2ce653174786d9f97fea93aa38d48432937bc634d8478dfa03e5e6ad18d3fff3d6fa245e9f6578f87ca07d9fd764a274702e4bb8dd34dede
+ version: 2.3.2
+ resolution: "@csstools/css-tokenizer@npm:2.3.2"
+ checksum: 10/0dee283818a4ed6480ba076dc18c842844d8d3b9e771005710606785e3163c39107a2af1ccffd2847fdec947abdcbd93deec8a924a7f1b317ac2de24e185e2a1
languageName: node
linkType: hard
"@csstools/media-query-list-parser@npm:^2.1.11":
- version: 2.1.11
- resolution: "@csstools/media-query-list-parser@npm:2.1.11"
+ version: 2.1.12
+ resolution: "@csstools/media-query-list-parser@npm:2.1.12"
peerDependencies:
- "@csstools/css-parser-algorithms": ^2.6.3
- "@csstools/css-tokenizer": ^2.3.1
- checksum: 10/23ede5583c6f1f51ec45b9293fcaf1ecac0f69c7ea750bfe2245926a66a6ae8f7dea8b3604fc4a5b8be4a25c1bccf519a357bf926d486a7ff479e89685011ff4
+ "@csstools/css-parser-algorithms": ^2.7.0
+ "@csstools/css-tokenizer": ^2.3.2
+ checksum: 10/ee22ee6ffd0a8922fc5e1d985b338fb13dead051cdadc9835b94e1183db5aeb33e184f25caeb2f05935fb61dd96e11601c6ef4001fb625195e51c4ec7a82cbb3
languageName: node
linkType: hard
@@ -2181,9 +2181,9 @@ __metadata:
linkType: hard
"@eslint-community/regexpp@npm:^4.10.0, @eslint-community/regexpp@npm:^4.6.1":
- version: 4.10.1
- resolution: "@eslint-community/regexpp@npm:4.10.1"
- checksum: 10/54f13817caf90545502d7a19e1b61df79087aee9584342ffc558b6d067530764a47f1c484f493f43e2c70cfdff59ccfd5f26df2af298c4ad528469e599bd1d53
+ version: 4.11.0
+ resolution: "@eslint-community/regexpp@npm:4.11.0"
+ checksum: 10/f053f371c281ba173fe6ee16dbc4fe544c84870d58035ccca08dba7f6ce1830d895ce3237a0db89ba37616524775dca82f1c502066b58e2d5712d7f87f5ba17c
languageName: node
linkType: hard
@@ -2346,7 +2346,7 @@ __metadata:
cross-env: "npm:7.0.3"
eslint: "npm:8.57.0"
jest: "npm:29.7.0"
- mobx: "npm:6.12.4"
+ mobx: "npm:6.12.5"
mobx-react-lite: "npm:4.0.7"
monaco-editor: "npm:0.50.0"
npm-run-all: "npm:4.1.5"
@@ -2432,7 +2432,7 @@ __metadata:
cross-env: "npm:7.0.3"
eslint: "npm:8.57.0"
jest: "npm:29.7.0"
- mobx: "npm:6.12.4"
+ mobx: "npm:6.12.5"
mobx-react-lite: "npm:4.0.7"
npm-run-all: "npm:4.1.5"
react: "npm:18.3.1"
@@ -2477,8 +2477,10 @@ __metadata:
"@ag-grid-community/core": "npm:31.3.2"
"@ag-grid-community/react": "npm:31.3.2"
"@ag-grid-community/styles": "npm:31.3.2"
+ "@ag-grid-enterprise/clipboard": "npm:31.3.2"
"@ag-grid-enterprise/core": "npm:31.3.2"
"@ag-grid-enterprise/menu": "npm:31.3.2"
+ "@ag-grid-enterprise/range-selection": "npm:31.3.2"
"@ag-grid-enterprise/row-grouping": "npm:31.3.2"
"@ag-grid-enterprise/server-side-row-model": "npm:31.3.2"
"@finos/legend-application": "workspace:*"
@@ -2494,7 +2496,7 @@ __metadata:
cross-env: "npm:7.0.3"
eslint: "npm:8.57.0"
jest: "npm:29.7.0"
- mobx: "npm:6.12.4"
+ mobx: "npm:6.12.5"
mobx-react-lite: "npm:4.0.7"
monaco-editor: "npm:0.50.0"
npm-run-all: "npm:4.1.5"
@@ -2583,7 +2585,7 @@ __metadata:
eslint: "npm:8.57.0"
fast-xml-parser: "npm:4.4.0"
jest: "npm:29.7.0"
- mobx: "npm:6.12.4"
+ mobx: "npm:6.12.5"
mobx-react-lite: "npm:4.0.7"
mobx-utils: "npm:6.0.8"
monaco-editor: "npm:0.50.0"
@@ -2617,7 +2619,7 @@ __metadata:
eslint: "npm:8.57.0"
history: "npm:5.3.0"
jest: "npm:29.7.0"
- mobx: "npm:6.12.4"
+ mobx: "npm:6.12.5"
mobx-react-lite: "npm:4.0.7"
npm-run-all: "npm:4.1.5"
react: "npm:18.3.1"
@@ -2649,25 +2651,30 @@ __metadata:
"@emotion/styled": "npm:11.11.5"
"@finos/legend-dev-utils": "workspace:*"
"@finos/legend-shared": "workspace:*"
+ "@fontsource/jetbrains-mono": "npm:5.0.20"
"@fontsource/raleway": "npm:5.0.19"
"@fontsource/roboto": "npm:5.0.13"
"@fontsource/roboto-condensed": "npm:5.0.16"
"@fontsource/roboto-mono": "npm:5.0.18"
+ "@fontsource/roboto-serif": "npm:5.0.13"
+ "@fontsource/ubuntu-mono": "npm:5.0.20"
"@jest/globals": "npm:29.7.0"
- "@mui/material": "npm:5.15.20"
+ "@mui/material": "npm:5.15.21"
"@types/react": "npm:18.3.3"
"@types/react-resizable": "npm:3.0.7"
"@types/react-select": "npm:4.0.18"
"@types/react-window": "npm:1.8.8"
clsx: "npm:2.1.1"
+ color-parse: "npm:2.0.2"
cross-env: "npm:7.0.3"
eslint: "npm:8.57.0"
jest: "npm:29.7.0"
mermaid: "npm:10.9.1"
- mobx: "npm:6.12.4"
+ mobx: "npm:6.12.5"
mobx-react-lite: "npm:4.0.7"
npm-run-all: "npm:4.1.5"
react: "npm:18.3.1"
+ react-colorful: "npm:5.6.1"
react-dnd: "npm:16.0.1"
react-dnd-html5-backend: "npm:16.0.1"
react-dom: "npm:18.3.1"
@@ -2729,7 +2736,7 @@ __metadata:
mini-css-extract-plugin: "npm:2.9.0"
monaco-editor: "npm:0.50.0"
monaco-editor-webpack-plugin: "npm:7.1.0"
- postcss: "npm:8.4.38"
+ postcss: "npm:8.4.39"
postcss-loader: "npm:8.1.1"
react-refresh: "npm:0.14.2"
resolve: "npm:1.22.8"
@@ -2757,7 +2764,7 @@ __metadata:
cross-env: "npm:7.0.3"
eslint: "npm:8.57.0"
jest: "npm:29.7.0"
- mobx: "npm:6.12.4"
+ mobx: "npm:6.12.5"
mobx-react-lite: "npm:4.0.7"
npm-run-all: "npm:4.1.5"
react: "npm:18.3.1"
@@ -2787,7 +2794,7 @@ __metadata:
cross-env: "npm:7.0.3"
eslint: "npm:8.57.0"
jest: "npm:29.7.0"
- mobx: "npm:6.12.4"
+ mobx: "npm:6.12.5"
mobx-react-lite: "npm:4.0.7"
npm-run-all: "npm:4.1.5"
rimraf: "npm:5.0.7"
@@ -2818,7 +2825,7 @@ __metadata:
cross-env: "npm:7.0.3"
eslint: "npm:8.57.0"
jest: "npm:29.7.0"
- mobx: "npm:6.12.4"
+ mobx: "npm:6.12.5"
mobx-react-lite: "npm:4.0.7"
npm-run-all: "npm:4.1.5"
react: "npm:18.3.1"
@@ -2851,7 +2858,7 @@ __metadata:
cross-env: "npm:7.0.3"
eslint: "npm:8.57.0"
jest: "npm:29.7.0"
- mobx: "npm:6.12.4"
+ mobx: "npm:6.12.5"
mobx-react-lite: "npm:4.0.7"
npm-run-all: "npm:4.1.5"
react: "npm:18.3.1"
@@ -2883,7 +2890,7 @@ __metadata:
cross-env: "npm:7.0.3"
eslint: "npm:8.57.0"
jest: "npm:29.7.0"
- mobx: "npm:6.12.4"
+ mobx: "npm:6.12.5"
npm-run-all: "npm:4.1.5"
react: "npm:18.3.1"
rimraf: "npm:5.0.7"
@@ -2916,7 +2923,7 @@ __metadata:
cross-env: "npm:7.0.3"
eslint: "npm:8.57.0"
jest: "npm:29.7.0"
- mobx: "npm:6.12.4"
+ mobx: "npm:6.12.5"
mobx-react-lite: "npm:4.0.7"
npm-run-all: "npm:4.1.5"
react: "npm:18.3.1"
@@ -2947,7 +2954,7 @@ __metadata:
cross-env: "npm:7.0.3"
eslint: "npm:8.57.0"
jest: "npm:29.7.0"
- mobx: "npm:6.12.4"
+ mobx: "npm:6.12.5"
mobx-react-lite: "npm:4.0.7"
npm-run-all: "npm:4.1.5"
react: "npm:18.3.1"
@@ -2976,7 +2983,7 @@ __metadata:
cross-env: "npm:7.0.3"
eslint: "npm:8.57.0"
jest: "npm:29.7.0"
- mobx: "npm:6.12.4"
+ mobx: "npm:6.12.5"
mobx-react-lite: "npm:4.0.7"
npm-run-all: "npm:4.1.5"
react: "npm:18.3.1"
@@ -3005,7 +3012,7 @@ __metadata:
cross-env: "npm:7.0.3"
eslint: "npm:8.57.0"
jest: "npm:29.7.0"
- mobx: "npm:6.12.4"
+ mobx: "npm:6.12.5"
mobx-react-lite: "npm:4.0.7"
npm-run-all: "npm:4.1.5"
react: "npm:18.3.1"
@@ -3035,7 +3042,7 @@ __metadata:
cross-env: "npm:7.0.3"
eslint: "npm:8.57.0"
jest: "npm:29.7.0"
- mobx: "npm:6.12.4"
+ mobx: "npm:6.12.5"
mobx-react-lite: "npm:4.0.7"
npm-run-all: "npm:4.1.5"
react: "npm:18.3.1"
@@ -3077,7 +3084,7 @@ __metadata:
"@finos/legend-dev-utils": "workspace:*"
cross-env: "npm:7.0.3"
eslint: "npm:8.57.0"
- fastify: "npm:4.28.0"
+ fastify: "npm:4.28.1"
nodemon: "npm:3.1.4"
npm-run-all: "npm:4.1.5"
rimraf: "npm:5.0.7"
@@ -3097,7 +3104,7 @@ __metadata:
cross-env: "npm:7.0.3"
eslint: "npm:8.57.0"
jest: "npm:29.7.0"
- mobx: "npm:6.12.4"
+ mobx: "npm:6.12.5"
npm-run-all: "npm:4.1.5"
rimraf: "npm:5.0.7"
serializr: "npm:3.0.2"
@@ -3148,7 +3155,7 @@ __metadata:
cross-env: "npm:7.0.3"
eslint: "npm:8.57.0"
jest: "npm:29.7.0"
- mobx: "npm:6.12.4"
+ mobx: "npm:6.12.5"
mobx-react-lite: "npm:4.0.7"
monaco-editor: "npm:0.50.0"
npm-run-all: "npm:4.1.5"
@@ -3212,8 +3219,8 @@ __metadata:
cross-env: "npm:7.0.3"
eslint: "npm:8.57.0"
jest: "npm:29.7.0"
- mathjs: "npm:13.0.0"
- mobx: "npm:6.12.4"
+ mathjs: "npm:13.0.1"
+ mobx: "npm:6.12.5"
mobx-react-lite: "npm:4.0.7"
monaco-editor: "npm:0.50.0"
npm-run-all: "npm:4.1.5"
@@ -3260,7 +3267,7 @@ __metadata:
cross-env: "npm:7.0.3"
eslint: "npm:8.57.0"
jest: "npm:29.7.0"
- mobx: "npm:6.12.4"
+ mobx: "npm:6.12.5"
npm-run-all: "npm:4.1.5"
rimraf: "npm:5.0.7"
serializr: "npm:3.0.2"
@@ -3279,7 +3286,7 @@ __metadata:
"@jest/globals": "npm:29.7.0"
cross-env: "npm:7.0.3"
eslint: "npm:8.57.0"
- fastify: "npm:4.28.0"
+ fastify: "npm:4.28.1"
jest: "npm:29.7.0"
nodemon: "npm:3.1.4"
npm-run-all: "npm:4.1.5"
@@ -3300,9 +3307,9 @@ __metadata:
"@jest/globals": "npm:29.7.0"
cross-env: "npm:7.0.3"
eslint: "npm:8.57.0"
- fastify: "npm:4.28.0"
+ fastify: "npm:4.28.1"
jest: "npm:29.7.0"
- mobx: "npm:6.12.4"
+ mobx: "npm:6.12.5"
npm-run-all: "npm:4.1.5"
rimraf: "npm:5.0.7"
serializr: "npm:3.0.2"
@@ -3326,6 +3333,7 @@ __metadata:
"@types/uuid": "npm:10.0.0"
cross-env: "npm:7.0.3"
date-fns: "npm:3.6.0"
+ deep-object-diff: "npm:^1.1.9"
eslint: "npm:8.57.0"
fuse.js: "npm:7.0.0"
hash.js: "npm:1.1.7"
@@ -3334,7 +3342,7 @@ __metadata:
lodash: "npm:4.17.21"
lodash-es: "npm:4.17.21"
lossless-json: "npm:4.0.1"
- mobx: "npm:6.12.4"
+ mobx: "npm:6.12.5"
npm-run-all: "npm:4.1.5"
object-hash: "npm:3.0.0"
pako: "npm:2.1.0"
@@ -3370,6 +3378,7 @@ __metadata:
version: 0.0.0-use.local
resolution: "@finos/legend-vscode-extension-dependencies@workspace:packages/legend-vscode-extension-dependencies"
dependencies:
+ "@babel/core": "npm:7.24.7"
"@finos/legend-application-studio": "workspace:*"
"@finos/legend-dev-utils": "workspace:*"
"@finos/legend-extension-dsl-diagram": "workspace:*"
@@ -3388,7 +3397,7 @@ __metadata:
rollup: "npm:4.18.0"
rollup-plugin-flow: "npm:1.1.1"
rollup-plugin-import-css: "npm:3.5.0"
- typescript: "npm:5.4.5"
+ typescript: "npm:5.5.2"
languageName: unknown
linkType: soft
@@ -3398,51 +3407,58 @@ __metadata:
dependencies:
cross-env: "npm:7.0.3"
eslint: "npm:8.57.0"
- postcss: "npm:8.4.38"
+ postcss: "npm:8.4.39"
postcss-scss: "npm:4.0.9"
rimraf: "npm:5.0.7"
stylelint-config-standard: "npm:36.0.1"
stylelint-scss: "npm:6.3.2"
peerDependencies:
- stylelint: ^15.0.0
+ stylelint: ">16.0.0"
languageName: unknown
linkType: soft
-"@floating-ui/core@npm:^1.0.0":
- version: 1.6.2
- resolution: "@floating-ui/core@npm:1.6.2"
+"@floating-ui/core@npm:^1.6.0":
+ version: 1.6.4
+ resolution: "@floating-ui/core@npm:1.6.4"
dependencies:
- "@floating-ui/utils": "npm:^0.2.0"
- checksum: 10/5c940ef3d397aa23f859ecb033bda408dde20820af3f82090a889c35a99826cfaa7864e8131b9906a26b2c04f31fa468538a28d0715b34de541e0776e0f82d03
+ "@floating-ui/utils": "npm:^0.2.4"
+ checksum: 10/589430cbff4bac90b9b891e2c94c57dc113d39ac163552f547d9e4c7d21f09997b9d33e82ec717759caee678c47f845f14a3f28df6f029fcfcf3ad803ba4eb7c
languageName: node
linkType: hard
"@floating-ui/dom@npm:^1.0.0":
- version: 1.6.5
- resolution: "@floating-ui/dom@npm:1.6.5"
+ version: 1.6.7
+ resolution: "@floating-ui/dom@npm:1.6.7"
dependencies:
- "@floating-ui/core": "npm:^1.0.0"
- "@floating-ui/utils": "npm:^0.2.0"
- checksum: 10/d421e7f239e9af5a2a4c7a560c29b8ce1f29398c411c8e3bd0c33a2ce800e13a378749a1606e4f6b460830f4007c459792534821013262d24d1385476b1ba48d
+ "@floating-ui/core": "npm:^1.6.0"
+ "@floating-ui/utils": "npm:^0.2.4"
+ checksum: 10/a6a42bfd243c311f6040043808a6549c1db45fa36138b81cb1e615170d61fd2daf4f37accc1df3e0189405d97e3d71b12de39879c9d58ccf181c982b69cf6cf9
languageName: node
linkType: hard
"@floating-ui/react-dom@npm:^2.0.8":
- version: 2.1.0
- resolution: "@floating-ui/react-dom@npm:2.1.0"
+ version: 2.1.1
+ resolution: "@floating-ui/react-dom@npm:2.1.1"
dependencies:
"@floating-ui/dom": "npm:^1.0.0"
peerDependencies:
react: ">=16.8.0"
react-dom: ">=16.8.0"
- checksum: 10/15be0714379c271ff01347e7c9bcdba96d6b39f3960697380e23de9b9d59fb91ba07bc75b8bdb12d72da7a9272191a9ce73f843a0d5f89939caa9f3137acd8ec
+ checksum: 10/cafabfb5dd0b25547863520b3bcf6faee7f087d0c3187a8779910a6838d496bf494f237bf1fe883bbfae1a7fcc399611ae52377b696065d8118bd7c1b9c0d253
languageName: node
linkType: hard
-"@floating-ui/utils@npm:^0.2.0":
- version: 0.2.2
- resolution: "@floating-ui/utils@npm:0.2.2"
- checksum: 10/28d900d2f0876b40c7090f55724700eeac608862e59110b7b14731223218cf7ce125b2091f34103edf4b0f779166151bbca21256b856236235a2be996548ed38
+"@floating-ui/utils@npm:^0.2.4":
+ version: 0.2.4
+ resolution: "@floating-ui/utils@npm:0.2.4"
+ checksum: 10/7662d7a4ae39c0287e026f666297a3d28c80e588251c8c59ff66938a0aead47d380bbb9018629bd63a98f399c3919ec689d5448a5c48ffc176d545ddef705df1
+ languageName: node
+ linkType: hard
+
+"@fontsource/jetbrains-mono@npm:5.0.20":
+ version: 5.0.20
+ resolution: "@fontsource/jetbrains-mono@npm:5.0.20"
+ checksum: 10/18c3ff2c1245c8d34e93e9bb000bfb3685b5be405f61f218fdbeeedd6ace1dc6d03df6d470535e9614bcbb29b675a221fd1c53d35d550ad773a1ef7031995840
languageName: node
linkType: hard
@@ -3467,6 +3483,13 @@ __metadata:
languageName: node
linkType: hard
+"@fontsource/roboto-serif@npm:5.0.13":
+ version: 5.0.13
+ resolution: "@fontsource/roboto-serif@npm:5.0.13"
+ checksum: 10/f1280caf1518e046acb5eebeebef5136501f6e166b049022654a587369603f9d6db8e715008a27d25ea4372a1092aec3ca43235e25a032e6564e5558a7c0b480
+ languageName: node
+ linkType: hard
+
"@fontsource/roboto@npm:5.0.13":
version: 5.0.13
resolution: "@fontsource/roboto@npm:5.0.13"
@@ -3474,6 +3497,13 @@ __metadata:
languageName: node
linkType: hard
+"@fontsource/ubuntu-mono@npm:5.0.20":
+ version: 5.0.20
+ resolution: "@fontsource/ubuntu-mono@npm:5.0.20"
+ checksum: 10/ca2a3d3b39da20186de7eecb5e6f517f74b97e00bae70fc74aaa6a7364df1de2459571ebe380a48323ee3694476dfa385b068dcecba251a671ff0bf9baacfec9
+ languageName: node
+ linkType: hard
+
"@humanwhocodes/config-array@npm:^0.11.14":
version: 0.11.14
resolution: "@humanwhocodes/config-array@npm:0.11.14"
@@ -3875,15 +3905,6 @@ __metadata:
languageName: node
linkType: hard
-"@ljharb/through@npm:^2.3.13":
- version: 2.3.13
- resolution: "@ljharb/through@npm:2.3.13"
- dependencies:
- call-bind: "npm:^1.0.7"
- checksum: 10/6150c6c43a726d52c26863ed6dc4ab54fa7cf625c81463a5ddec86278c99e23bf94dfc99ebf09a9ac3191332d4a27344e092f7e07f252b8cd600e2b38e645870
- languageName: node
- linkType: hard
-
"@manypkg/find-root@npm:^1.1.0":
version: 1.1.0
resolution: "@manypkg/find-root@npm:1.1.0"
@@ -3932,20 +3953,20 @@ __metadata:
languageName: node
linkType: hard
-"@mui/core-downloads-tracker@npm:^5.15.20":
- version: 5.15.20
- resolution: "@mui/core-downloads-tracker@npm:5.15.20"
- checksum: 10/8cc71169ce1201c5a37fad6c5c58739850694e90c7bda636c692d47a79fd4c7884eab2c24b0084d6732a3d28c9a4a6d222dd5747f9d91f5075614700a3a3282a
+"@mui/core-downloads-tracker@npm:^5.15.21":
+ version: 5.15.21
+ resolution: "@mui/core-downloads-tracker@npm:5.15.21"
+ checksum: 10/c6f8e2350597833a96593f65e5081930a1006b645be6a34750e93e15e111eeca6973562b42688f5d6393a050401b7196d58c2aa2de96a112ac27fb998411742a
languageName: node
linkType: hard
-"@mui/material@npm:5.15.20":
- version: 5.15.20
- resolution: "@mui/material@npm:5.15.20"
+"@mui/material@npm:5.15.21":
+ version: 5.15.21
+ resolution: "@mui/material@npm:5.15.21"
dependencies:
"@babel/runtime": "npm:^7.23.9"
"@mui/base": "npm:5.0.0-beta.40"
- "@mui/core-downloads-tracker": "npm:^5.15.20"
+ "@mui/core-downloads-tracker": "npm:^5.15.21"
"@mui/system": "npm:^5.15.20"
"@mui/types": "npm:^7.2.14"
"@mui/utils": "npm:^5.15.20"
@@ -3968,7 +3989,7 @@ __metadata:
optional: true
"@types/react":
optional: true
- checksum: 10/1e568f82334b3a556bd248130238746bcd59951aad654e43c0df292076fae6799172113c3e2eb93fffaf49bd81023fbee0494b073e8808400ad00bea9f030e9b
+ checksum: 10/3369cb1d0ddd790de2d972dd5a2039eb2cd26e35ff1c515308d0d03929f9ded02d2ba3038551d94258ac5d5dc9a4433ca76ad60f81573346aa0d69075d72f403
languageName: node
linkType: hard
@@ -4547,10 +4568,10 @@ __metadata:
languageName: node
linkType: hard
-"@shikijs/core@npm:1.9.0":
- version: 1.9.0
- resolution: "@shikijs/core@npm:1.9.0"
- checksum: 10/ec07699742f0561ab4d2fb07715397183cbed23ca42e082b14e9e5f85eb7f8647897f69698d003d8c6a1b8682da0af77861b3a2f78d366eef7581bae4415142c
+"@shikijs/core@npm:1.10.0":
+ version: 1.10.0
+ resolution: "@shikijs/core@npm:1.10.0"
+ checksum: 10/301436c7c4cb048b8683af74eb306fe728112e231b17e56f3c7b28f82ac664c3b56f620e54bdfc9cfd99cbab486ec29ce98e1123d22bdc43a896c4f73b9aa7d8
languageName: node
linkType: hard
@@ -4939,9 +4960,9 @@ __metadata:
linkType: hard
"@types/lodash@npm:*":
- version: 4.17.5
- resolution: "@types/lodash@npm:4.17.5"
- checksum: 10/10e2e9cbeb16998026f4071f9f5f2a38b651eba15302f512e0b8ab904c07c197ca0282d2821f64e53c2b692d7046af0a1ce3ead190fb077cbe4036948fce1924
+ version: 4.17.6
+ resolution: "@types/lodash@npm:4.17.6"
+ checksum: 10/6d3a68b3e795381f4aaf946855134d24eeb348ad5d66e9a44461d30026da82b215d55b92b70486d811ca45d54d4ab956aa2dced37fd04e19d49afe160ae3da2e
languageName: node
linkType: hard
@@ -4993,12 +5014,12 @@ __metadata:
languageName: node
linkType: hard
-"@types/node@npm:*, @types/node@npm:20.14.8":
- version: 20.14.8
- resolution: "@types/node@npm:20.14.8"
+"@types/node@npm:*, @types/node@npm:20.14.9":
+ version: 20.14.9
+ resolution: "@types/node@npm:20.14.9"
dependencies:
undici-types: "npm:~5.26.4"
- checksum: 10/73822f66f269ce865df7e2f586787ac7444bd1169fd265cbed1e851b72787f1170517c5b616e0308ec2fbc0934ec6403b0f28d4152acbb0486071aec41167d51
+ checksum: 10/f313b06c79be92f5d3541159ef813b9fc606941f951ecf826e940658c6d4952755ca2f06277b746326cef0697ed79a04676ecde053d32e1121b3352c8168d2e9
languageName: node
linkType: hard
@@ -6591,9 +6612,9 @@ __metadata:
linkType: hard
"caniuse-lite@npm:^1.0.0, caniuse-lite@npm:^1.0.30001599, caniuse-lite@npm:^1.0.30001629":
- version: 1.0.30001636
- resolution: "caniuse-lite@npm:1.0.30001636"
- checksum: 10/9e6c5ab4c20df31df36720dda77cf6a781549ac2ad844bc0a416b327a793da21486358a1f85fdd6c39e22d336f70aac3b0e232f5f228cdff0ceb6e3e1c5e98fd
+ version: 1.0.30001639
+ resolution: "caniuse-lite@npm:1.0.30001639"
+ checksum: 10/c163080e08982de60b37d51130f088e9f8a745533621675694f0b079f53529308168adb0966051139ff71c75af439b2ce150b7142cff15aac421cbfd126bd481
languageName: node
linkType: hard
@@ -6604,7 +6625,7 @@ __metadata:
languageName: node
linkType: hard
-"chalk@npm:5.3.0, chalk@npm:^5.2.0, chalk@npm:^5.3.0, chalk@npm:~5.3.0":
+"chalk@npm:5.3.0, chalk@npm:^5.2.0, chalk@npm:~5.3.0":
version: 5.3.0
resolution: "chalk@npm:5.3.0"
checksum: 10/6373caaab21bd64c405bfc4bd9672b145647fc9482657b5ea1d549b3b2765054e9d3d928870cdf764fb4aad67555f5061538ff247b8310f110c5c888d92397ea
@@ -6904,6 +6925,22 @@ __metadata:
languageName: node
linkType: hard
+"color-name@npm:^2.0.0":
+ version: 2.0.0
+ resolution: "color-name@npm:2.0.0"
+ checksum: 10/10a1addae41de2987d6b90dbd3cfade266c2e6f680ce21749911df4493b4fae07654862c6b5358bdd13e155461acb4eedaa5e0ba172bf13542cdcca10866cf2b
+ languageName: node
+ linkType: hard
+
+"color-parse@npm:2.0.2":
+ version: 2.0.2
+ resolution: "color-parse@npm:2.0.2"
+ dependencies:
+ color-name: "npm:^2.0.0"
+ checksum: 10/64963587057e024edbce3f009e73e69b1d1b31d6f9955eed853748b8cb14d4e3bb49064da9c7452a22f5326a1197fa6c483483a53868e815f4cba30b6b1c36cc
+ languageName: node
+ linkType: hard
+
"colord@npm:^2.9.3":
version: 2.9.3
resolution: "colord@npm:2.9.3"
@@ -7442,9 +7479,9 @@ __metadata:
linkType: hard
"cytoscape@npm:^3.28.1":
- version: 3.29.2
- resolution: "cytoscape@npm:3.29.2"
- checksum: 10/986b5126a73267cddefdc33a20556889a91365e98324a35a4714cda6efd1af51ae442689db41d4c23b2340a84471bbffeea720c0d3b3e68d6659f9744a08af1a
+ version: 3.30.0
+ resolution: "cytoscape@npm:3.30.0"
+ checksum: 10/4361004b7f944b82ee26407fe834982e67e83331d1b38b97e075b6960d88eeaf3b1b8c12983e8097cf04a97e8b17a6cee64d7fdcffc8b67d4d92f931b7f66e7c
languageName: node
linkType: hard
@@ -7955,6 +7992,13 @@ __metadata:
languageName: node
linkType: hard
+"deep-object-diff@npm:^1.1.9":
+ version: 1.1.9
+ resolution: "deep-object-diff@npm:1.1.9"
+ checksum: 10/b9771cc1ca08a34e408309eaab967bd2ab697684abdfa1262f4283ced8230a9ace966322f356364ff71a785c6e9cc356b7596582e900da5726e6b87d4b2a1463
+ languageName: node
+ linkType: hard
+
"deepmerge@npm:^4.2.2":
version: 4.3.1
resolution: "deepmerge@npm:4.3.1"
@@ -8368,9 +8412,9 @@ __metadata:
linkType: hard
"electron-to-chromium@npm:^1.4.796":
- version: 1.4.810
- resolution: "electron-to-chromium@npm:1.4.810"
- checksum: 10/425de710336094330fd026cc2cfa0b383bfc9a49a2f575ceec2ac76198663ff95d0109bb45b243a43f0bf0f91a2e9c2768693a136d0968ae59728d5e8eea22ef
+ version: 1.4.815
+ resolution: "electron-to-chromium@npm:1.4.815"
+ checksum: 10/84f59b76b1ac16fe1f359720bdaeadcbce34825a7e79e3551ceec6b52d4021e7bd8a56a2cfa4197ba353331df18d0bc2ab449e08c5599eb1b2a7aacaba56f711
languageName: node
linkType: hard
@@ -8600,9 +8644,9 @@ __metadata:
linkType: hard
"es-module-lexer@npm:^1.2.1":
- version: 1.5.3
- resolution: "es-module-lexer@npm:1.5.3"
- checksum: 10/2d80297e955f52ec6a4c7c7683ec2ee80b33c61b46af4f6ed3ef8feab16ba10fd4798141132b3fd0f5e2edb36abd4ad50c63cf3e26da2cca1c56debc68816c44
+ version: 1.5.4
+ resolution: "es-module-lexer@npm:1.5.4"
+ checksum: 10/f29c7c97a58eb17640dcbd71bd6ef754ad4f58f95c3073894573d29dae2cad43ecd2060d97ed5b866dfb7804d5590fb7de1d2c5339a5fceae8bd60b580387fc5
languageName: node
linkType: hard
@@ -9272,9 +9316,9 @@ __metadata:
languageName: node
linkType: hard
-"fastify@npm:4.28.0":
- version: 4.28.0
- resolution: "fastify@npm:4.28.0"
+"fastify@npm:4.28.1":
+ version: 4.28.1
+ resolution: "fastify@npm:4.28.1"
dependencies:
"@fastify/ajv-compiler": "npm:^3.5.0"
"@fastify/error": "npm:^3.4.0"
@@ -9292,7 +9336,7 @@ __metadata:
secure-json-parse: "npm:^2.7.0"
semver: "npm:^7.5.4"
toad-cache: "npm:^3.3.0"
- checksum: 10/8f3991b1ae2b5248ca9fb09f57f0fc083ca3ca26ab418fb2b0b768c5cec5c01aa4aaa9e7697018457a5f53fe43d74747bac2393509eeac96bb535d5cbba4e062
+ checksum: 10/8a749dd540609579258cd0471c521696ed16bf66e34d46babbbed9d9a184bd7a378c2ec87a233e382071c1c91b223db0a1ad1a7f9dc8a8f2240aaf8e173ed597
languageName: node
linkType: hard
@@ -9875,8 +9919,8 @@ __metadata:
linkType: hard
"globby@npm:^14.0.0":
- version: 14.0.1
- resolution: "globby@npm:14.0.1"
+ version: 14.0.2
+ resolution: "globby@npm:14.0.2"
dependencies:
"@sindresorhus/merge-streams": "npm:^2.1.0"
fast-glob: "npm:^3.3.2"
@@ -9884,7 +9928,7 @@ __metadata:
path-type: "npm:^5.0.0"
slash: "npm:^5.1.0"
unicorn-magic: "npm:^0.1.0"
- checksum: 10/b36f57afc45a857a884d82657603c7e1663b1e6f3f9afbeb53d12e42230469fc5b26a7e14a01e51086f3f25c138f58a7002036fcc8f3ca054097b6dd7c71d639
+ checksum: 10/67660da70fc1223f7170c1a62ba6c373385e9e39765d952b6518606dec15ed8c7958e9dae6ba5752a31dbc1e9126f146938b830ad680fe794141734ffc3fbb75
languageName: node
linkType: hard
@@ -10312,12 +10356,12 @@ __metadata:
linkType: hard
"https-proxy-agent@npm:^7.0.1":
- version: 7.0.4
- resolution: "https-proxy-agent@npm:7.0.4"
+ version: 7.0.5
+ resolution: "https-proxy-agent@npm:7.0.5"
dependencies:
agent-base: "npm:^7.0.2"
debug: "npm:4"
- checksum: 10/405fe582bba461bfe5c7e2f8d752b384036854488b828ae6df6a587c654299cbb2c50df38c4b6ab303502c3c5e029a793fbaac965d1e86ee0be03faceb554d63
+ checksum: 10/6679d46159ab3f9a5509ee80c3a3fc83fba3a920a5e18d32176c3327852c3c00ad640c0c4210a8fd70ea3c4a6d3a1b375bf01942516e7df80e2646bdc77658ab
languageName: node
linkType: hard
@@ -10487,18 +10531,14 @@ __metadata:
languageName: node
linkType: hard
-"inquirer@npm:9.2.23":
- version: 9.2.23
- resolution: "inquirer@npm:9.2.23"
+"inquirer@npm:9.3.2":
+ version: 9.3.2
+ resolution: "inquirer@npm:9.3.2"
dependencies:
"@inquirer/figures": "npm:^1.0.3"
- "@ljharb/through": "npm:^2.3.13"
ansi-escapes: "npm:^4.3.2"
- chalk: "npm:^5.3.0"
- cli-cursor: "npm:^3.1.0"
cli-width: "npm:^4.1.0"
external-editor: "npm:^3.1.0"
- lodash: "npm:^4.17.21"
mute-stream: "npm:1.0.0"
ora: "npm:^5.4.1"
run-async: "npm:^3.0.0"
@@ -10506,7 +10546,8 @@ __metadata:
string-width: "npm:^4.2.3"
strip-ansi: "npm:^6.0.1"
wrap-ansi: "npm:^6.2.0"
- checksum: 10/ccc05c4d64ee583ac6d1ad602ae1b76c25da6d6ca8923bbac9158f76bad2eb9c628b5b5201b135fcc32f9651ed1b9ed99e6489f9afa5f00db443447f1f9ad391
+ yoctocolors-cjs: "npm:^2.1.1"
+ checksum: 10/a19e5fc3c0c802b38d1130a67e5d7062e698994e9f7334d56a36a5bca4539be80f136ebe02e2dbe4caa50620ea64827494b96919425bb1db089e807e17c96d43
languageName: node
linkType: hard
@@ -11116,15 +11157,15 @@ __metadata:
linkType: hard
"istanbul-lib-instrument@npm:^6.0.0":
- version: 6.0.2
- resolution: "istanbul-lib-instrument@npm:6.0.2"
+ version: 6.0.3
+ resolution: "istanbul-lib-instrument@npm:6.0.3"
dependencies:
"@babel/core": "npm:^7.23.9"
"@babel/parser": "npm:^7.23.9"
"@istanbuljs/schema": "npm:^0.1.3"
istanbul-lib-coverage: "npm:^3.2.0"
semver: "npm:^7.5.4"
- checksum: 10/3aee19be199350182827679a137e1df142a306e9d7e20bb5badfd92ecc9023a7d366bc68e7c66e36983654a02a67401d75d8debf29fc6d4b83670fde69a594fc
+ checksum: 10/aa5271c0008dfa71b6ecc9ba1e801bf77b49dc05524e8c30d58aaf5b9505e0cd12f25f93165464d4266a518c5c75284ecb598fbd89fec081ae77d2c9d3327695
languageName: node
linkType: hard
@@ -12008,14 +12049,14 @@ __metadata:
"@finos/eslint-plugin-legend-studio": "workspace:*"
"@finos/legend-dev-utils": "workspace:*"
"@finos/stylelint-config-legend-studio": "workspace:*"
- "@types/node": "npm:20.14.8"
+ "@types/node": "npm:20.14.9"
chalk: "npm:5.3.0"
cross-env: "npm:7.0.3"
envinfo: "npm:7.13.0"
eslint: "npm:8.57.0"
fs-extra: "npm:11.2.0"
husky: "npm:9.0.11"
- inquirer: "npm:9.2.23"
+ inquirer: "npm:9.3.2"
jest: "npm:29.7.0"
lint-staged: "npm:15.2.7"
micromatch: "npm:4.0.7"
@@ -12027,7 +12068,7 @@ __metadata:
semver: "npm:7.6.2"
sort-package-json: "npm:2.10.0"
stylelint: "npm:16.6.1"
- typedoc: "npm:0.26.2"
+ typedoc: "npm:0.26.3"
typescript: "npm:5.5.2"
yargs: "npm:17.7.2"
languageName: unknown
@@ -12315,9 +12356,9 @@ __metadata:
linkType: hard
"lru-cache@npm:^10.0.1, lru-cache@npm:^10.2.0":
- version: 10.2.2
- resolution: "lru-cache@npm:10.2.2"
- checksum: 10/ff1a496d30b5eaec2c9079080965bb0cede203cf878371f7033a007f1e54cd4aa13cc8abf7ccec4c994a83a22ed5476e83a55bb57cc07e6c1547a42937e42c37
+ version: 10.3.0
+ resolution: "lru-cache@npm:10.3.0"
+ checksum: 10/37e921aedbd1f4062475d9fa6760391fa7adfaaee3a5a6cbedd1d6d0b46705c14012312c1edb2b13f119eae6584a48f73c158d118828d42475b44a7abf7d05ab
languageName: node
linkType: hard
@@ -12426,11 +12467,11 @@ __metadata:
languageName: node
linkType: hard
-"mathjs@npm:13.0.0":
- version: 13.0.0
- resolution: "mathjs@npm:13.0.0"
+"mathjs@npm:13.0.1":
+ version: 13.0.1
+ resolution: "mathjs@npm:13.0.1"
dependencies:
- "@babel/runtime": "npm:^7.24.6"
+ "@babel/runtime": "npm:^7.24.7"
complex.js: "npm:^2.1.1"
decimal.js: "npm:^10.4.3"
escape-latex: "npm:^1.2.0"
@@ -12438,10 +12479,10 @@ __metadata:
javascript-natural-sort: "npm:^0.7.1"
seedrandom: "npm:^3.0.5"
tiny-emitter: "npm:^2.1.0"
- typed-function: "npm:^4.1.1"
+ typed-function: "npm:^4.2.1"
bin:
mathjs: bin/cli.js
- checksum: 10/dff62ad0d9ad9c6f566e91b4cf304173d5d3ec1545f21ca1e4140691ca49a82b846abf8e540c34dabb1e7acd1d5474b654c5860a6b3f7c3175bc5bfc3dfbc759
+ checksum: 10/abb53cdd1ed9668cedae08e696d02b1836e6c0598d89dfb346435559a42959192a445ebfb60fa5482f9dde528ab601ffe200bd0a01c910cf795a2582ea98082c
languageName: node
linkType: hard
@@ -13450,12 +13491,12 @@ __metadata:
languageName: node
linkType: hard
-"minimatch@npm:^9.0.4":
- version: 9.0.4
- resolution: "minimatch@npm:9.0.4"
+"minimatch@npm:^9.0.4, minimatch@npm:^9.0.5":
+ version: 9.0.5
+ resolution: "minimatch@npm:9.0.5"
dependencies:
brace-expansion: "npm:^2.0.1"
- checksum: 10/4cdc18d112b164084513e890d6323370db14c22249d536ad1854539577a895e690a27513dc346392f61a4a50afbbd8abc88f3f25558bfbbbb862cd56508b20f5
+ checksum: 10/dd6a8927b063aca6d910b119e1f2df6d2ce7d36eab91de83167dd136bb85e1ebff97b0d3de1cb08bd1f7e018ca170b4962479fefab5b2a69e2ae12cb2edc8348
languageName: node
linkType: hard
@@ -13594,10 +13635,10 @@ __metadata:
languageName: node
linkType: hard
-"mobx@npm:6.12.4":
- version: 6.12.4
- resolution: "mobx@npm:6.12.4"
- checksum: 10/9096633b2a350e7908c193ae385fa6caf121bf8d963c9a1c068f6196b7b0396b2ed02e30254e669ae36e44ce9760e4ce85746c7f32b5adc84e26feeb3f0ba2cc
+"mobx@npm:6.12.5":
+ version: 6.12.5
+ resolution: "mobx@npm:6.12.5"
+ checksum: 10/af03258be314120153cb33953aad5cfb6e639e8536f3374d77dfad2244376c228f960b157e4133c97b8b8b6d552c6e369dff05ce43c8e2f2fe17066b0d060cb3
languageName: node
linkType: hard
@@ -15097,14 +15138,14 @@ __metadata:
languageName: node
linkType: hard
-"postcss@npm:8.4.38, postcss@npm:^8.4.23, postcss@npm:^8.4.33, postcss@npm:^8.4.38":
- version: 8.4.38
- resolution: "postcss@npm:8.4.38"
+"postcss@npm:8.4.39, postcss@npm:^8.4.23, postcss@npm:^8.4.33, postcss@npm:^8.4.38":
+ version: 8.4.39
+ resolution: "postcss@npm:8.4.39"
dependencies:
nanoid: "npm:^3.3.7"
- picocolors: "npm:^1.0.0"
+ picocolors: "npm:^1.0.1"
source-map-js: "npm:^1.2.0"
- checksum: 10/6e44a7ed835ffa9a2b096e8d3e5dfc6bcf331a25c48aeb862dd54e3aaecadf814fa22be224fd308f87d08adf2299164f88c5fd5ab1c4ef6cbd693ceb295377f4
+ checksum: 10/ad9c1add892c96433b9a5502878201ede4a20c4ce02d056251f61f8d9a3e5426dab3683fe5a086edfa78a1a19f2b4988c8cea02c5122136d29758cb5a17e2621
languageName: node
linkType: hard
@@ -15479,6 +15520,16 @@ __metadata:
languageName: node
linkType: hard
+"react-colorful@npm:5.6.1":
+ version: 5.6.1
+ resolution: "react-colorful@npm:5.6.1"
+ peerDependencies:
+ react: ">=16.8.0"
+ react-dom: ">=16.8.0"
+ checksum: 10/3e02ba013454818d0c323949bd961fb2c19ac18130dfc67a4032aa5b03787c5ffe7ff159c4b97dc3475072d576828ca0c4b8e8ce85b55eaf484180596cdf0403
+ languageName: node
+ linkType: hard
+
"react-dnd-html5-backend@npm:16.0.1":
version: 16.0.1
resolution: "react-dnd-html5-backend@npm:16.0.1"
@@ -16742,12 +16793,12 @@ __metadata:
languageName: node
linkType: hard
-"shiki@npm:^1.9.0":
- version: 1.9.0
- resolution: "shiki@npm:1.9.0"
+"shiki@npm:^1.9.1":
+ version: 1.10.0
+ resolution: "shiki@npm:1.10.0"
dependencies:
- "@shikijs/core": "npm:1.9.0"
- checksum: 10/ce5648b4e1a5e5e81e54e01ec9dc94cf324530f460058f29f1e5e464dbf096fee2194fbef38b29128a747f783f9134531991316b01ed168f65d0617dabf84c33
+ "@shikijs/core": "npm:1.10.0"
+ checksum: 10/e5c844acece5eef2b796d63040ff9655fbd1070d10c50726eebaddc0506b9bdaee7fc28c7299168ef1a4eb9007db7e928bd03a80d3918c37df0fe3a96363d66b
languageName: node
linkType: hard
@@ -16882,17 +16933,17 @@ __metadata:
linkType: hard
"socks-proxy-agent@npm:^8.0.3":
- version: 8.0.3
- resolution: "socks-proxy-agent@npm:8.0.3"
+ version: 8.0.4
+ resolution: "socks-proxy-agent@npm:8.0.4"
dependencies:
agent-base: "npm:^7.1.1"
debug: "npm:^4.3.4"
- socks: "npm:^2.7.1"
- checksum: 10/c2112c66d6322e497d68e913c3780f3683237fd394bfd480b9283486a86e36095d0020db96145d88f8ccd9cc73261b98165b461f9c1bf5dc17abfe75c18029ce
+ socks: "npm:^2.8.3"
+ checksum: 10/c8e7c2b398338b49a0a0f4d2bae5c0602aeeca6b478b99415927b6c5db349ca258448f2c87c6958ebf83eea17d42cbc5d1af0bfecb276cac10b9658b0f07f7d7
languageName: node
linkType: hard
-"socks@npm:^2.7.1":
+"socks@npm:^2.8.3":
version: 2.8.3
resolution: "socks@npm:2.8.3"
dependencies:
@@ -17192,13 +17243,13 @@ __metadata:
linkType: hard
"string-width@npm:^7.0.0":
- version: 7.1.0
- resolution: "string-width@npm:7.1.0"
+ version: 7.2.0
+ resolution: "string-width@npm:7.2.0"
dependencies:
emoji-regex: "npm:^10.3.0"
get-east-asian-width: "npm:^1.0.0"
strip-ansi: "npm:^7.1.0"
- checksum: 10/a183573fe7209e0d294f661846d33f8caf72aa86d983e5b48a0ed45ab15bcccb02c6f0344b58b571988871105457137b8207855ea536827dbc4a376a0f31bf8f
+ checksum: 10/42f9e82f61314904a81393f6ef75b832c39f39761797250de68c041d8ba4df2ef80db49ab6cd3a292923a6f0f409b8c9980d120f7d32c820b4a8a84a2598a295
languageName: node
linkType: hard
@@ -17870,11 +17921,11 @@ __metadata:
linkType: hard
"tree-dump@npm:^1.0.1":
- version: 1.0.1
- resolution: "tree-dump@npm:1.0.1"
+ version: 1.0.2
+ resolution: "tree-dump@npm:1.0.2"
peerDependencies:
tslib: 2
- checksum: 10/b19d0ce73d62dc8c83e3fae7a96c2ae77db4bebfacd6e2b225eb5c867d3fdf21ea790c64795a1777cb8e38816ea72ae12a46c76811a5e9f0d31182484f02a6da
+ checksum: 10/ddcde4da9ded8edc2fa77fc9153ef8d7fba9cd5f813db27c30c7039191b50e1512b7106f0f4fe7ccaa3aa69f85b4671eda7ed0b9f9d34781eb26ebe4593ad4eb
languageName: node
linkType: hard
@@ -18040,37 +18091,27 @@ __metadata:
languageName: node
linkType: hard
-"typed-function@npm:^4.1.1":
+"typed-function@npm:^4.2.1":
version: 4.2.1
resolution: "typed-function@npm:4.2.1"
checksum: 10/2218d6e4a56c414c2d9c1e3cf2f0d26d6a8848d3e875cbd0eec5a791c25c4ee182cb488a6077b45b110334de7bd7f44fb049feac9e5216bef3172c22acbbf501
languageName: node
linkType: hard
-"typedoc@npm:0.26.2":
- version: 0.26.2
- resolution: "typedoc@npm:0.26.2"
+"typedoc@npm:0.26.3":
+ version: 0.26.3
+ resolution: "typedoc@npm:0.26.3"
dependencies:
lunr: "npm:^2.3.9"
markdown-it: "npm:^14.1.0"
- minimatch: "npm:^9.0.4"
- shiki: "npm:^1.9.0"
+ minimatch: "npm:^9.0.5"
+ shiki: "npm:^1.9.1"
yaml: "npm:^2.4.5"
peerDependencies:
typescript: 4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x || 5.5.x
bin:
typedoc: bin/typedoc
- checksum: 10/f7cbe3e4a7635fe8fef9aacd62eedf72ff008548eebdcfc9a8b8ffea3cb6c06846230a022f436ba006bf11bf669b1e7fcf375349410e1f2d920b42531cd1f5b4
- languageName: node
- linkType: hard
-
-"typescript@npm:5.4.5":
- version: 5.4.5
- resolution: "typescript@npm:5.4.5"
- bin:
- tsc: bin/tsc
- tsserver: bin/tsserver
- checksum: 10/d04a9e27e6d83861f2126665aa8d84847e8ebabcea9125b9ebc30370b98cb38b5dff2508d74e2326a744938191a83a69aa9fddab41f193ffa43eabfdf3f190a5
+ checksum: 10/55473079de55140d29299b449c0c8de6da1c6c76553bae17c11d1be9e4521612c5f0d9d5a6ee4e18ba7103f79de9ff98223fa0fb2d0e09b2bd535e54efe3d08d
languageName: node
linkType: hard
@@ -18084,16 +18125,6 @@ __metadata:
languageName: node
linkType: hard
-"typescript@patch:typescript@npm%3A5.4.5#optional!builtin":
- version: 5.4.5
- resolution: "typescript@patch:typescript@npm%3A5.4.5#optional!builtin::version=5.4.5&hash=5adc0c"
- bin:
- tsc: bin/tsc
- tsserver: bin/tsserver
- checksum: 10/760f7d92fb383dbf7dee2443bf902f4365db2117f96f875cf809167f6103d55064de973db9f78fe8f31ec08fff52b2c969aee0d310939c0a3798ec75d0bca2e1
- languageName: node
- linkType: hard
-
"typescript@patch:typescript@npm%3A5.5.2#optional!builtin":
version: 5.5.2
resolution: "typescript@patch:typescript@npm%3A5.5.2#optional!builtin::version=5.5.2&hash=b45daf"
@@ -19138,9 +19169,16 @@ __metadata:
linkType: hard
"yocto-queue@npm:^1.0.0":
- version: 1.0.0
- resolution: "yocto-queue@npm:1.0.0"
- checksum: 10/2cac84540f65c64ccc1683c267edce396b26b1e931aa429660aefac8fbe0188167b7aee815a3c22fa59a28a58d898d1a2b1825048f834d8d629f4c2a5d443801
+ version: 1.1.1
+ resolution: "yocto-queue@npm:1.1.1"
+ checksum: 10/f2e05b767ed3141e6372a80af9caa4715d60969227f38b1a4370d60bffe153c9c5b33a862905609afc9b375ec57cd40999810d20e5e10229a204e8bde7ef255c
+ languageName: node
+ linkType: hard
+
+"yoctocolors-cjs@npm:^2.1.1":
+ version: 2.1.1
+ resolution: "yoctocolors-cjs@npm:2.1.1"
+ checksum: 10/d7cbb833eb2fac85e38f5efeaf163ad2d468b7795eef595f034183a404253767d06ec6075e44ab0414436a7bbf5e4aad524e5a3f380dafbbd24e971a4ee51d37
languageName: node
linkType: hard