From f10d7ed3221ca565682a2c7bbf11ddee9bceb4a1 Mon Sep 17 00:00:00 2001 From: heswell Date: Mon, 18 Dec 2023 10:47:07 +0000 Subject: [PATCH 01/38] allow more recent react versions (#1082) * allow more recent react versions * allow more recent react versions * allow more recent react versions --- vuu-ui/package-lock.json | 95 ++++++++++--------- vuu-ui/packages/vuu-data-ag-grid/package.json | 2 +- vuu-ui/packages/vuu-data-react/package.json | 2 +- vuu-ui/packages/vuu-datatable/package.json | 4 +- vuu-ui/packages/vuu-filters/package.json | 4 +- vuu-ui/packages/vuu-layout/package.json | 4 +- vuu-ui/packages/vuu-popups/package.json | 4 +- vuu-ui/packages/vuu-shell/package.json | 4 +- vuu-ui/packages/vuu-table-extras/package.json | 4 +- vuu-ui/packages/vuu-table/package.json | 4 +- vuu-ui/packages/vuu-ui-controls/package.json | 4 +- vuu-ui/packages/vuu-utils/package.json | 4 +- .../sample-apps/app-vuu-example/package.json | 4 +- .../feature-basket-trading/package.json | 4 +- .../feature-filter-table/package.json | 4 +- .../feature-instrument-tiles/package.json | 4 +- .../sample-apps/feature-template/package.json | 4 +- vuu-ui/showcase/package.json | 4 +- 18 files changed, 80 insertions(+), 79 deletions(-) diff --git a/vuu-ui/package-lock.json b/vuu-ui/package-lock.json index ead0139b7..3c748c82c 100644 --- a/vuu-ui/package-lock.json +++ b/vuu-ui/package-lock.json @@ -16,14 +16,14 @@ "dependencies": { "@types/jest": "^26.0.20", "@types/node": "^14.14.35", - "@types/react": "^17.0.2", - "@types/react-dom": "^17.0.2", + "@types/react": ">=17.0.2", + "@types/react-dom": ">=17.0.2", "@typescript-eslint/parser": "^5.41.0", "classnames": "^2.3.1", "clsx": "^1.2.1", "html-to-image": "^1.11.11", - "react": "^17.0.2", - "react-dom": "^17.0.2", + "react": ">=17.0.2", + "react-dom": ">=17.0.2", "recoil": "^0.1.3", "semver": "^7.5.2" }, @@ -2082,14 +2082,12 @@ "node_modules/@thomaschaplin/cusip-generator": { "version": "1.0.22", "resolved": "https://registry.npmjs.org/@thomaschaplin/cusip-generator/-/cusip-generator-1.0.22.tgz", - "integrity": "sha512-162DBgkPGQI0otk/aW8z7XjyYM1fEOUf+p4yiEgJZhKupSWuwSNcsIcAi4fDZvP/XkI/pBF83aXUlYkWFMqA2Q==", - "dev": true + "integrity": "sha512-162DBgkPGQI0otk/aW8z7XjyYM1fEOUf+p4yiEgJZhKupSWuwSNcsIcAi4fDZvP/XkI/pBF83aXUlYkWFMqA2Q==" }, "node_modules/@thomaschaplin/isin-generator": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@thomaschaplin/isin-generator/-/isin-generator-1.0.3.tgz", "integrity": "sha512-M1vm7MsTdLhOybs21dR1M0/aUAwpM2B7qZvcVMTzxBxnjzwaqCr1EtxMUjecCOoxViIA6A/HO7emlfKUGODBNQ==", - "dev": true, "dependencies": { "@thomaschaplin/cusip-generator": "^1.0.1" } @@ -11765,7 +11763,7 @@ "@finos/vuu-utils": "0.0.26" }, "peerDependencies": { - "react": "^17.0.2" + "react": ">=17.0.2" } }, "packages/vuu-data-react": { @@ -11785,13 +11783,16 @@ "@finos/vuu-table-types": "0.0.26" }, "peerDependencies": { - "react": "^17.0.2" + "react": ">=17.0.2" } }, "packages/vuu-data-test": { "name": "@finos/vuu-data-test", "version": "0.0.26", "license": "Apache-2.0", + "dependencies": { + "@thomaschaplin/isin-generator": "1.0.3" + }, "devDependencies": { "@finos/vuu-data": "0.0.26", "@finos/vuu-table-types": "0.0.26" @@ -11854,8 +11855,8 @@ }, "peerDependencies": { "classnames": "^2.2.6", - "react": "^17.0.2", - "react-dom": "^17.0.2" + "react": ">=17.0.2", + "react-dom": ">=17.0.2" } }, "packages/vuu-filter-parser": { @@ -11897,8 +11898,8 @@ "@types/uuid": "^9.0.2" }, "peerDependencies": { - "react": "^17.0.2", - "react-dom": "^17.0.2" + "react": ">=17.0.2", + "react-dom": ">=17.0.2" } }, "packages/vuu-filters/node_modules/uuid": { @@ -11928,8 +11929,8 @@ }, "peerDependencies": { "classnames": "^2.2.6", - "react": "^17.0.2", - "react-dom": "^17.0.2" + "react": ">=17.0.2", + "react-dom": ">=17.0.2" } }, "packages/vuu-popups": { @@ -11949,8 +11950,8 @@ }, "peerDependencies": { "classnames": "^2.2.6", - "react": "^17.0.2", - "react-dom": "^17.0.2" + "react": ">=17.0.2", + "react-dom": ">=17.0.2" } }, "packages/vuu-protocol-types": { @@ -11977,8 +11978,8 @@ }, "peerDependencies": { "classnames": "^2.2.6", - "react": "^17.0.2", - "react-dom": "^17.0.2" + "react": ">=17.0.2", + "react-dom": ">=17.0.2" } }, "packages/vuu-table": { @@ -12000,8 +12001,8 @@ }, "peerDependencies": { "classnames": "^2.2.6", - "react": "^17.0.2", - "react-dom": "^17.0.2" + "react": ">=17.0.2", + "react-dom": ">=17.0.2" } }, "packages/vuu-table-extras": { @@ -12027,8 +12028,8 @@ }, "peerDependencies": { "classnames": "^2.2.6", - "react": "^17.0.2", - "react-dom": "^17.0.2" + "react": ">=17.0.2", + "react-dom": ">=17.0.2" } }, "packages/vuu-table-extras/node_modules/@lezer/lr": { @@ -12039,6 +12040,7 @@ } }, "packages/vuu-table-types": { + "name": "@finos/vuu-table-types", "version": "0.0.26", "license": "Apache-2.0", "devDependencies": { @@ -12066,8 +12068,8 @@ }, "peerDependencies": { "classnames": "^2.2.6", - "react": "^17.0.2", - "react-dom": "^17.0.2" + "react": ">=17.0.2", + "react-dom": ">=17.0.2" } }, "packages/vuu-utils": { @@ -12080,8 +12082,8 @@ "@finos/vuu-table-types": "0.0.26" }, "peerDependencies": { - "react": "^17.0.2", - "react-dom": "^17.0.2" + "react": ">=17.0.2", + "react-dom": ">=17.0.2" } }, "sample-apps/app-vuu-basket-trader": { @@ -12123,8 +12125,8 @@ "@salt-ds/core": "1.8.0", "@salt-ds/lab": "1.0.0-alpha.15", "classnames": "^2.3.1", - "react": "^17.0.2", - "react-dom": "^17.0.2" + "react": ">=17.0.2", + "react-dom": ">=17.0.2" }, "devDependencies": {}, "engines": { @@ -12157,8 +12159,8 @@ }, "peerDependencies": { "classnames": "^2.3.1", - "react": "^17.0.2", - "react-dom": "^17.0.2" + "react": ">=17.0.2", + "react-dom": ">=17.0.2" } }, "sample-apps/feature-filter-table": { @@ -12188,8 +12190,8 @@ }, "peerDependencies": { "classnames": "^2.3.1", - "react": "^17.0.2", - "react-dom": "^17.0.2" + "react": ">=17.0.2", + "react-dom": ">=17.0.2" } }, "sample-apps/feature-instrument-tiles": { @@ -12219,8 +12221,8 @@ }, "peerDependencies": { "classnames": "^2.3.1", - "react": "^17.0.2", - "react-dom": "^17.0.2" + "react": ">=17.0.2", + "react-dom": ">=17.0.2" } }, "sample-apps/feature-template": { @@ -12250,8 +12252,8 @@ }, "peerDependencies": { "classnames": "^2.3.1", - "react": "^17.0.2", - "react-dom": "^17.0.2" + "react": ">=17.0.2", + "react-dom": ">=17.0.2" } }, "sample-apps/feature-vuu-blotter": { @@ -12333,8 +12335,8 @@ "@salt-ds/lab": "1.0.0-alpha.15", "@salt-ds/theme": "1.7.1", "classnames": "^2.3.1", - "react": "^17.0.2", - "react-dom": "^17.0.2", + "react": ">=17.0.2", + "react-dom": ">=17.0.2", "react-router-dom": "^6.2.1" }, "devDependencies": { @@ -13080,8 +13082,8 @@ "@salt-ds/theme": "1.7.1", "@thomaschaplin/isin-generator": "^1.0.3", "classnames": "^2.3.1", - "react": "^17.0.2", - "react-dom": "^17.0.2", + "react": ">=17.0.2", + "react-dom": ">=17.0.2", "react-router-dom": "^6.2.1" } }, @@ -13137,7 +13139,8 @@ "version": "file:packages/vuu-data-test", "requires": { "@finos/vuu-data": "0.0.26", - "@finos/vuu-table-types": "0.0.26" + "@finos/vuu-table-types": "0.0.26", + "@thomaschaplin/isin-generator": "1.0.3" } }, "@finos/vuu-data-types": { @@ -13903,14 +13906,12 @@ "@thomaschaplin/cusip-generator": { "version": "1.0.22", "resolved": "https://registry.npmjs.org/@thomaschaplin/cusip-generator/-/cusip-generator-1.0.22.tgz", - "integrity": "sha512-162DBgkPGQI0otk/aW8z7XjyYM1fEOUf+p4yiEgJZhKupSWuwSNcsIcAi4fDZvP/XkI/pBF83aXUlYkWFMqA2Q==", - "dev": true + "integrity": "sha512-162DBgkPGQI0otk/aW8z7XjyYM1fEOUf+p4yiEgJZhKupSWuwSNcsIcAi4fDZvP/XkI/pBF83aXUlYkWFMqA2Q==" }, "@thomaschaplin/isin-generator": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@thomaschaplin/isin-generator/-/isin-generator-1.0.3.tgz", "integrity": "sha512-M1vm7MsTdLhOybs21dR1M0/aUAwpM2B7qZvcVMTzxBxnjzwaqCr1EtxMUjecCOoxViIA6A/HO7emlfKUGODBNQ==", - "dev": true, "requires": { "@thomaschaplin/cusip-generator": "^1.0.1" } @@ -14618,8 +14619,8 @@ "@salt-ds/core": "1.8.0", "@salt-ds/lab": "1.0.0-alpha.15", "classnames": "^2.3.1", - "react": "^17.0.2", - "react-dom": "^17.0.2" + "react": ">=17.0.2", + "react-dom": ">=17.0.2" } }, "arch": { diff --git a/vuu-ui/packages/vuu-data-ag-grid/package.json b/vuu-ui/packages/vuu-data-ag-grid/package.json index f179ce0a4..aa1d35dfa 100644 --- a/vuu-ui/packages/vuu-data-ag-grid/package.json +++ b/vuu-ui/packages/vuu-data-ag-grid/package.json @@ -18,6 +18,6 @@ "@finos/vuu-utils": "0.0.26" }, "peerDependencies": { - "react": "^17.0.2" + "react": ">=17.0.2" } } diff --git a/vuu-ui/packages/vuu-data-react/package.json b/vuu-ui/packages/vuu-data-react/package.json index 048d88a6c..9056d8b20 100644 --- a/vuu-ui/packages/vuu-data-react/package.json +++ b/vuu-ui/packages/vuu-data-react/package.json @@ -22,6 +22,6 @@ "@finos/vuu-utils": "0.0.26" }, "peerDependencies": { - "react": "^17.0.2" + "react": ">=17.0.2" } } diff --git a/vuu-ui/packages/vuu-datatable/package.json b/vuu-ui/packages/vuu-datatable/package.json index f2edaae4c..f8f51f33d 100644 --- a/vuu-ui/packages/vuu-datatable/package.json +++ b/vuu-ui/packages/vuu-datatable/package.json @@ -21,7 +21,7 @@ }, "peerDependencies": { "classnames": "^2.2.6", - "react": "^17.0.2", - "react-dom": "^17.0.2" + "react": ">=17.0.2", + "react-dom": ">=17.0.2" } } diff --git a/vuu-ui/packages/vuu-filters/package.json b/vuu-ui/packages/vuu-filters/package.json index e7e0ab976..9a7e02e49 100644 --- a/vuu-ui/packages/vuu-filters/package.json +++ b/vuu-ui/packages/vuu-filters/package.json @@ -27,7 +27,7 @@ "uuid": "9.0.0" }, "peerDependencies": { - "react": "^17.0.2", - "react-dom": "^17.0.2" + "react": ">=17.0.2", + "react-dom": ">=17.0.2" } } diff --git a/vuu-ui/packages/vuu-layout/package.json b/vuu-ui/packages/vuu-layout/package.json index 62d410a7a..764ef8bbe 100644 --- a/vuu-ui/packages/vuu-layout/package.json +++ b/vuu-ui/packages/vuu-layout/package.json @@ -21,7 +21,7 @@ }, "peerDependencies": { "classnames": "^2.2.6", - "react": "^17.0.2", - "react-dom": "^17.0.2" + "react": ">=17.0.2", + "react-dom": ">=17.0.2" } } diff --git a/vuu-ui/packages/vuu-popups/package.json b/vuu-ui/packages/vuu-popups/package.json index 3b6dff1f3..8e5056850 100644 --- a/vuu-ui/packages/vuu-popups/package.json +++ b/vuu-ui/packages/vuu-popups/package.json @@ -22,7 +22,7 @@ }, "peerDependencies": { "classnames": "^2.2.6", - "react": "^17.0.2", - "react-dom": "^17.0.2" + "react": ">=17.0.2", + "react-dom": ">=17.0.2" } } diff --git a/vuu-ui/packages/vuu-shell/package.json b/vuu-ui/packages/vuu-shell/package.json index e64a8c5a8..2bfd27d39 100644 --- a/vuu-ui/packages/vuu-shell/package.json +++ b/vuu-ui/packages/vuu-shell/package.json @@ -24,7 +24,7 @@ }, "peerDependencies": { "classnames": "^2.2.6", - "react": "^17.0.2", - "react-dom": "^17.0.2" + "react": ">=17.0.2", + "react-dom": ">=17.0.2" } } diff --git a/vuu-ui/packages/vuu-table-extras/package.json b/vuu-ui/packages/vuu-table-extras/package.json index cb033461e..663fc2f0d 100644 --- a/vuu-ui/packages/vuu-table-extras/package.json +++ b/vuu-ui/packages/vuu-table-extras/package.json @@ -28,8 +28,8 @@ }, "peerDependencies": { "classnames": "^2.2.6", - "react": "^17.0.2", - "react-dom": "^17.0.2" + "react": ">=17.0.2", + "react-dom": ">=17.0.2" }, "type": "module" } diff --git a/vuu-ui/packages/vuu-table/package.json b/vuu-ui/packages/vuu-table/package.json index b852b632c..860db5516 100644 --- a/vuu-ui/packages/vuu-table/package.json +++ b/vuu-ui/packages/vuu-table/package.json @@ -23,7 +23,7 @@ }, "peerDependencies": { "classnames": "^2.2.6", - "react": "^17.0.2", - "react-dom": "^17.0.2" + "react": ">=17.0.2", + "react-dom": ">=17.0.2" } } diff --git a/vuu-ui/packages/vuu-ui-controls/package.json b/vuu-ui/packages/vuu-ui-controls/package.json index 9bbf380eb..ab65e62ad 100644 --- a/vuu-ui/packages/vuu-ui-controls/package.json +++ b/vuu-ui/packages/vuu-ui-controls/package.json @@ -21,7 +21,7 @@ }, "peerDependencies": { "classnames": "^2.2.6", - "react": "^17.0.2", - "react-dom": "^17.0.2" + "react": ">=17.0.2", + "react-dom": ">=17.0.2" } } diff --git a/vuu-ui/packages/vuu-utils/package.json b/vuu-ui/packages/vuu-utils/package.json index 9302ed323..99ac90d59 100644 --- a/vuu-ui/packages/vuu-utils/package.json +++ b/vuu-ui/packages/vuu-utils/package.json @@ -16,7 +16,7 @@ "@finos/vuu-protocol-types": "0.0.26" }, "peerDependencies": { - "react": "^17.0.2", - "react-dom": "^17.0.2" + "react": ">=17.0.2", + "react-dom": ">=17.0.2" } } diff --git a/vuu-ui/sample-apps/app-vuu-example/package.json b/vuu-ui/sample-apps/app-vuu-example/package.json index c95685008..0d95ab50b 100644 --- a/vuu-ui/sample-apps/app-vuu-example/package.json +++ b/vuu-ui/sample-apps/app-vuu-example/package.json @@ -27,8 +27,8 @@ "@finos/vuu-shell": "0.0.26", "@finos/vuu-utils": "0.0.26", "classnames": "^2.3.1", - "react": "^17.0.2", - "react-dom": "^17.0.2" + "react": ">=17.0.2", + "react-dom": ">=17.0.2" }, "engines": { "node": ">=16.0.0" diff --git a/vuu-ui/sample-apps/feature-basket-trading/package.json b/vuu-ui/sample-apps/feature-basket-trading/package.json index 74fefb227..1b9186a88 100644 --- a/vuu-ui/sample-apps/feature-basket-trading/package.json +++ b/vuu-ui/sample-apps/feature-basket-trading/package.json @@ -34,8 +34,8 @@ }, "peerDependencies": { "classnames": "^2.3.1", - "react": "^17.0.2", - "react-dom": "^17.0.2" + "react": ">=17.0.2", + "react-dom": ">=17.0.2" }, "engines": { "node": ">=16.0.0" diff --git a/vuu-ui/sample-apps/feature-filter-table/package.json b/vuu-ui/sample-apps/feature-filter-table/package.json index 4bb804700..fad2317e1 100644 --- a/vuu-ui/sample-apps/feature-filter-table/package.json +++ b/vuu-ui/sample-apps/feature-filter-table/package.json @@ -34,8 +34,8 @@ }, "peerDependencies": { "classnames": "^2.3.1", - "react": "^17.0.2", - "react-dom": "^17.0.2" + "react": ">=17.0.2", + "react-dom": ">=17.0.2" }, "engines": { "node": ">=16.0.0" diff --git a/vuu-ui/sample-apps/feature-instrument-tiles/package.json b/vuu-ui/sample-apps/feature-instrument-tiles/package.json index 19b1c2d69..c310989c9 100644 --- a/vuu-ui/sample-apps/feature-instrument-tiles/package.json +++ b/vuu-ui/sample-apps/feature-instrument-tiles/package.json @@ -34,8 +34,8 @@ }, "peerDependencies": { "classnames": "^2.3.1", - "react": "^17.0.2", - "react-dom": "^17.0.2" + "react": ">=17.0.2", + "react-dom": ">=17.0.2" }, "engines": { "node": ">=16.0.0" diff --git a/vuu-ui/sample-apps/feature-template/package.json b/vuu-ui/sample-apps/feature-template/package.json index 5a07fbb94..1c2775545 100644 --- a/vuu-ui/sample-apps/feature-template/package.json +++ b/vuu-ui/sample-apps/feature-template/package.json @@ -34,8 +34,8 @@ }, "peerDependencies": { "classnames": "^2.3.1", - "react": "^17.0.2", - "react-dom": "^17.0.2" + "react": ">=17.0.2", + "react-dom": ">=17.0.2" }, "engines": { "node": ">=16.0.0" diff --git a/vuu-ui/showcase/package.json b/vuu-ui/showcase/package.json index ac4e7527c..24e81ce2d 100644 --- a/vuu-ui/showcase/package.json +++ b/vuu-ui/showcase/package.json @@ -29,8 +29,8 @@ "@salt-ds/lab": "1.0.0-alpha.15", "@salt-ds/theme": "1.7.1", "classnames": "^2.3.1", - "react": "^17.0.2", - "react-dom": "^17.0.2", + "react": ">=17.0.2", + "react-dom": ">=17.0.2", "react-router-dom": "^6.2.1" }, "devDependencies": { From c755ffe00579ccdc040dcb830d8612d66fe6b4a1 Mon Sep 17 00:00:00 2001 From: pling-scottlogic <79100986+pling-scottlogic@users.noreply.github.com> Date: Wed, 20 Dec 2023 16:22:49 +0000 Subject: [PATCH 02/38] VUU-333: Improve Cypress Selectors (#1079) * SLVUU-49: Improve selectors for screenshot test * SLVUU-49: Implement POM for ShellWithNewTheme * SLVUU-49: Implement POM for SaveLayoutDialog and LayoutList * SLVUU-49: Use existing function to format date * SLVUU-49: Give accessible name to context menu buttons * SLVUU-49: Rename layouts tab list * SLVUU-49: Improve user flow to get layout tile Includes refactor of LayoutList: - Extract LayoutTile from LayoutList - Nest grouped lists inside overall list - Add accessible selectors * SLVUU-49: Convert cypress files to Typescript * SLVUU-49: Wrap LayoutTile with list item * SLVUU-49: Rename tab list * SLVUU-49: Include .ts files in tsconfig.json * SLVUU-49: Refactor POM * SLVUU-49: Refactor LayoutTile * SLVUU-49: Extract LayoutTile --- vuu-ui/cypress.config.ts | 7 +++ .../e2e/layout-management/screenshot.cy.js | 29 ------------ .../e2e/layout-management/screenshot.cy.ts | 25 +++++++++++ vuu-ui/cypress/pages/SaveLayoutDialog.ts | 21 +++++++++ vuu-ui/cypress/pages/ShellWithNewTheme.ts | 44 +++++++++++++++++++ vuu-ui/cypress/tsconfig.json | 2 +- .../packages/vuu-layout/src/stack/Stack.tsx | 1 + .../src/layout-management/LayoutList.tsx | 37 +++++++--------- .../src/layout-management/LayoutTile.css | 28 ++++++++++++ .../src/layout-management/LayoutTile.tsx | 33 ++++++++++++++ .../vuu-shell/src/left-nav/LeftNav.tsx | 4 +- .../vuu-ui-controls/src/tabstrip/TabMenu.tsx | 1 + .../vuu-ui-controls/src/tabstrip/Tabstrip.tsx | 1 + .../Layout/LayoutsBrowser.examples.tsx | 4 +- 14 files changed, 181 insertions(+), 56 deletions(-) delete mode 100644 vuu-ui/cypress/e2e/layout-management/screenshot.cy.js create mode 100644 vuu-ui/cypress/e2e/layout-management/screenshot.cy.ts create mode 100644 vuu-ui/cypress/pages/SaveLayoutDialog.ts create mode 100644 vuu-ui/cypress/pages/ShellWithNewTheme.ts create mode 100644 vuu-ui/packages/vuu-shell/src/layout-management/LayoutTile.css create mode 100644 vuu-ui/packages/vuu-shell/src/layout-management/LayoutTile.tsx diff --git a/vuu-ui/cypress.config.ts b/vuu-ui/cypress.config.ts index 978b48e13..563f11cd6 100644 --- a/vuu-ui/cypress.config.ts +++ b/vuu-ui/cypress.config.ts @@ -82,6 +82,13 @@ export default defineConfig({ // eslint-disable-next-line @typescript-eslint/no-unused-vars setupNodeEvents(on, config) { // implement node event listeners here + on("task", { + log(message: string) { + console.log(message); + + return null; + }, + }); }, chromeWebSecurity: false, defaultCommandTimeout: 10000, diff --git a/vuu-ui/cypress/e2e/layout-management/screenshot.cy.js b/vuu-ui/cypress/e2e/layout-management/screenshot.cy.js deleted file mode 100644 index db03b177b..000000000 --- a/vuu-ui/cypress/e2e/layout-management/screenshot.cy.js +++ /dev/null @@ -1,29 +0,0 @@ -import "cypress-iframe"; -import { SHELL_WITH_NEW_THEME_URL } from "../../support/e2e/constants"; - -context("Screenshot", () => { - beforeEach(() => { - cy.visit(SHELL_WITH_NEW_THEME_URL); - }); - - // TODO (#VUU24): Improve test alignment with the user flow - it("Takes a screenshot of the current layout and displays it in the save layout dialog", () => { - // TODO (#VUU24): Improve selector - cy.get("#tab1-tab").then((tab) => { - cy.wrap(tab).findByRole("button").click(); - }); - - // TODO (#VUU24): Improve selector - cy.findByRole("menuitem", { name: "Save Layout" }).click(); - - // TODO (#VUU24): Don't find by classname, use an accessible selector - cy.get(".saveLayoutPanel-panelContainer").then((dialog) => { - cy.wrap(dialog) - .find("img") - .should("be.visible") - .and(($img) => { - expect($img[0].naturalWidth).to.be.greaterThan(0); - }); - }); - }); -}); diff --git a/vuu-ui/cypress/e2e/layout-management/screenshot.cy.ts b/vuu-ui/cypress/e2e/layout-management/screenshot.cy.ts new file mode 100644 index 000000000..6a72c3cbc --- /dev/null +++ b/vuu-ui/cypress/e2e/layout-management/screenshot.cy.ts @@ -0,0 +1,25 @@ +import "cypress-iframe"; +import { ShellWithNewTheme } from "../../pages/ShellWithNewTheme"; +import { SaveLayoutDialog } from "../../pages/SaveLayoutDialog"; + +const page = new ShellWithNewTheme(); +const dialog = new SaveLayoutDialog(); + +context("Screenshot", () => { + beforeEach(() => { + page.visit(); + }); + + it("Takes a screenshot of the current layout and displays it in the save layout dialog", () => { + page.getContextMenuButton().click(); + page.getSaveLayoutButton().click(); + + dialog + .getScreenshot() + .should("be.visible") + .and(($img: JQuery) => { + const img = $img[0] as HTMLImageElement; + expect(img.naturalWidth).to.be.greaterThan(0); + }); + }); +}); diff --git a/vuu-ui/cypress/pages/SaveLayoutDialog.ts b/vuu-ui/cypress/pages/SaveLayoutDialog.ts new file mode 100644 index 000000000..282c15d2b --- /dev/null +++ b/vuu-ui/cypress/pages/SaveLayoutDialog.ts @@ -0,0 +1,21 @@ +export class SaveLayoutDialog { + getScreenshot: () => Cypress.Chainable> = () => { + return cy.findByAltText("screenshot of current layout"); + } + + getGroupField: () => Cypress.Chainable> = () => { + return cy.findByRole("combobox", { name: "Group" }); + } + + getNameField: () => Cypress.Chainable> = () => { + return cy.findByRole("textbox", { name: "Layout Name" }); + } + + getSaveButton: () => Cypress.Chainable> = () => { + return cy.findByRole("dialog").findByRole("button", { name: "Save" }); + } + + getCancelButton: () => Cypress.Chainable> = () => { + return cy.findByRole("dialog").findByRole("button", { name: "Cancel" }); + } +} diff --git a/vuu-ui/cypress/pages/ShellWithNewTheme.ts b/vuu-ui/cypress/pages/ShellWithNewTheme.ts new file mode 100644 index 000000000..f073b23fe --- /dev/null +++ b/vuu-ui/cypress/pages/ShellWithNewTheme.ts @@ -0,0 +1,44 @@ +import { formatDate } from "@finos/vuu-utils"; +import { SHELL_WITH_NEW_THEME_URL } from "../support/e2e/constants"; + +export class ShellWithNewTheme { + visit: () => void = () => { + cy.visit(SHELL_WITH_NEW_THEME_URL); + } + + getContextMenuButton: () => Cypress.Chainable> = () => { + return cy + .findByRole("tablist", { name: "data tabs" }) + .findAllByRole("tab") + .first() + .findByRole("button", { name: "context menu" }); + } + + getSaveLayoutButton: () => Cypress.Chainable> = () => { + return cy.findByRole("menuitem", { name: "Save Layout" }); + } + + getMyLayoutsButton: () => Cypress.Chainable> = () => { + return cy.findByRole("tab", { name: "MY LAYOUTS" }); + } + + getLayoutTile: ( + layoutName: string, + group: string, + creator: string, + date: Date + ) => Cypress.Chainable> = ( + layoutName: string, + group: string, + creator: string, + date: Date + ) => { + const layoutTileName = `${layoutName} ${creator}, ${formatDate(date)}`; + + return cy + .findByRole("listbox", { name: "my layouts" }) + .findByRole("list", { name: group }) + .findByRole("listitem", { name: layoutTileName }) + .findByRole("button"); + } +} diff --git a/vuu-ui/cypress/tsconfig.json b/vuu-ui/cypress/tsconfig.json index 8f4e0883e..6f53146a4 100644 --- a/vuu-ui/cypress/tsconfig.json +++ b/vuu-ui/cypress/tsconfig.json @@ -6,5 +6,5 @@ "./support" ] }, - "include": ["**/*.tsx", "../cypress.d.ts"] + "include": ["**/*.ts", "**/*.tsx", "../cypress.d.ts"] } diff --git a/vuu-ui/packages/vuu-layout/src/stack/Stack.tsx b/vuu-ui/packages/vuu-layout/src/stack/Stack.tsx index c9ad2a635..5203675d6 100644 --- a/vuu-ui/packages/vuu-layout/src/stack/Stack.tsx +++ b/vuu-ui/packages/vuu-layout/src/stack/Stack.tsx @@ -138,6 +138,7 @@ export const Stack = forwardRef(function Stack( allowDragDrop={TabstripProps.allowDragDrop !== false} animateSelectionThumb className={cx("vuuTabHeader", tabstripClassName)} + aria-label="data tabs" keyBoardActivation={keyBoardActivation} onActiveChange={onTabSelectionChanged} onAddTab={onAddTab} diff --git a/vuu-ui/packages/vuu-shell/src/layout-management/LayoutList.tsx b/vuu-ui/packages/vuu-shell/src/layout-management/LayoutList.tsx index 82721ccd5..fdd926dd6 100644 --- a/vuu-ui/packages/vuu-shell/src/layout-management/LayoutList.tsx +++ b/vuu-ui/packages/vuu-shell/src/layout-management/LayoutList.tsx @@ -2,6 +2,7 @@ import { HTMLAttributes } from "react"; import { List } from "@finos/vuu-ui-controls"; import { LayoutMetadata } from "./layoutTypes"; import { useLayoutManager } from "./useLayoutManager"; +import { LayoutTile } from "./LayoutTile"; import "./LayoutList.css"; @@ -11,7 +12,7 @@ type LayoutGroups = { const classBase = "vuuLayoutList"; -export const LayoutsList = (props: HTMLAttributes) => { +export const LayoutList = (props: HTMLAttributes) => { const { layoutMetadata, loadLayoutById } = useLayoutManager(); const handleLoadLayout = (layoutId?: string) => { @@ -34,7 +35,12 @@ export const LayoutsList = (props: HTMLAttributes) => { }, {}); return ( -
+
My Layouts
height="auto" @@ -43,29 +49,16 @@ export const LayoutsList = (props: HTMLAttributes) => { if (!item) return <>; const [groupName, layoutMetadata] = item; return ( - <> +
{groupName}
{layoutMetadata.map((metadata) => ( -
handleLoadLayout(metadata?.id)} - > - -
-
- {metadata?.name} -
-
-
{`${metadata?.user}, ${metadata?.created}`}
-
-
-
+ ))} - +
); }} /> diff --git a/vuu-ui/packages/vuu-shell/src/layout-management/LayoutTile.css b/vuu-ui/packages/vuu-shell/src/layout-management/LayoutTile.css new file mode 100644 index 000000000..7f77107fc --- /dev/null +++ b/vuu-ui/packages/vuu-shell/src/layout-management/LayoutTile.css @@ -0,0 +1,28 @@ +.vuuLayoutTile-layoutTile { + display: flex; + align-items: center; + gap: 8px; + padding: 8px 0px; + flex: 1 1 auto; + cursor: pointer; +} + +.vuuLayoutTile-layoutName { + color: var(--light-text-primary, #15171B); + font-weight: 600; + line-height: 133.333%; + text-transform: capitalize; +} + +.vuuLayoutTile-screenshot { + width: 60px; + height: 45.6px; + border: 1px solid #D6D7DA; +} + +.vuuLayoutTile-layoutDetails { + color: var(--light-text-secondary, #606477); + font-size: 10px; + font-weight: 600; + line-height: 150%; +} diff --git a/vuu-ui/packages/vuu-shell/src/layout-management/LayoutTile.tsx b/vuu-ui/packages/vuu-shell/src/layout-management/LayoutTile.tsx new file mode 100644 index 000000000..7311b3410 --- /dev/null +++ b/vuu-ui/packages/vuu-shell/src/layout-management/LayoutTile.tsx @@ -0,0 +1,33 @@ +import { LayoutMetadata } from "./layoutTypes"; + +import "./LayoutTile.css"; + +const classBase = "vuuLayoutTile"; + +type LayoutTileProps = { + metadata: LayoutMetadata; + handleLoadLayout: (layoutId?: string) => void; +}; + +export const LayoutTile = (props: LayoutTileProps) => { + const { metadata, handleLoadLayout } = props; + + return ( +
+
handleLoadLayout(metadata?.id)} + > + +
+
{metadata?.name}
+
+
{`${metadata?.user}, ${metadata?.created}`}
+
+
+
+
+ ); +}; diff --git a/vuu-ui/packages/vuu-shell/src/left-nav/LeftNav.tsx b/vuu-ui/packages/vuu-shell/src/left-nav/LeftNav.tsx index d6ca3515b..e2cf8b132 100644 --- a/vuu-ui/packages/vuu-shell/src/left-nav/LeftNav.tsx +++ b/vuu-ui/packages/vuu-shell/src/left-nav/LeftNav.tsx @@ -3,7 +3,7 @@ import { Stack, useLayoutProviderDispatch } from "@finos/vuu-layout"; import { LayoutResizeAction } from "@finos/vuu-layout/src/layout-reducer"; import { Tab, Tabstrip } from "@finos/vuu-ui-controls"; import cx from "classnames"; -import { LayoutsList } from "../layout-management"; +import { LayoutList } from "../layout-management"; import { CSSProperties, HTMLAttributes, useCallback, useState } from "react"; import { FeatureProps } from "../feature"; import { FeatureList } from "../feature-list"; @@ -182,7 +182,7 @@ export const LeftNav = (props: LeftNavProps) => {
- +
diff --git a/vuu-ui/packages/vuu-ui-controls/src/tabstrip/TabMenu.tsx b/vuu-ui/packages/vuu-ui-controls/src/tabstrip/TabMenu.tsx index e4d1bfe94..f7f883039 100644 --- a/vuu-ui/packages/vuu-ui-controls/src/tabstrip/TabMenu.tsx +++ b/vuu-ui/packages/vuu-ui-controls/src/tabstrip/TabMenu.tsx @@ -69,6 +69,7 @@ export const TabMenu = ({ menuOptions={menuOptions} onMenuClose={onMenuClose} tabIndex={-1} + aria-label="context menu" /> ); }; diff --git a/vuu-ui/packages/vuu-ui-controls/src/tabstrip/Tabstrip.tsx b/vuu-ui/packages/vuu-ui-controls/src/tabstrip/Tabstrip.tsx index 1ebb1a1f8..af892686c 100644 --- a/vuu-ui/packages/vuu-ui-controls/src/tabstrip/Tabstrip.tsx +++ b/vuu-ui/packages/vuu-ui-controls/src/tabstrip/Tabstrip.tsx @@ -142,6 +142,7 @@ export const Tabstrip = ({ overflowIcon="more-horiz" ref={rootRef} style={style} + role="tablist" > {tabs} diff --git a/vuu-ui/showcase/src/examples/Layout/LayoutsBrowser.examples.tsx b/vuu-ui/showcase/src/examples/Layout/LayoutsBrowser.examples.tsx index e63027602..d44d1ea58 100644 --- a/vuu-ui/showcase/src/examples/Layout/LayoutsBrowser.examples.tsx +++ b/vuu-ui/showcase/src/examples/Layout/LayoutsBrowser.examples.tsx @@ -1,11 +1,11 @@ -import { LayoutsList, LayoutManagementProvider } from "@finos/vuu-shell"; +import { LayoutList, LayoutManagementProvider } from "@finos/vuu-shell"; let displaySequence = 0; export const LayoutsBrowser = (): JSX.Element => { return ( - + ); }; From e510ba3bfea592edf72565bb16ce01b86109e0e9 Mon Sep 17 00:00:00 2001 From: Vasco <98337074+vferraro-scottlogic@users.noreply.github.com> Date: Thu, 21 Dec 2023 10:29:07 +0000 Subject: [PATCH 03/38] VUU-333: Improve Screenshot Functionality (#1076) * SLVUU-101 improve take screenshot functionality * SLVUU-101 tidy up takescreenshot code * SLVUU-101 fix unit tests * SLVUU-101 remove redundant css class and styling * SLVUU-101 extract ternary operation in useMemo * SLVUU-101 add comment to takeScreenshot filter --- .../LocalLayoutPersistenceManager.test.ts | 2 +- .../RemoteLayoutPersistenceManager.test.ts | 2 +- .../src/layout-management/SaveLayoutPanel.css | 10 +++-- .../src/layout-management/SaveLayoutPanel.tsx | 43 ++++++++++++------- .../vuu-utils/src/screenshot-utils.ts | 40 ++++++++++------- .../vuu-utils/test/screenshot-utils.test.ts | 32 +++++++------- .../test}/utils.ts | 0 7 files changed, 76 insertions(+), 53 deletions(-) rename vuu-ui/packages/{vuu-layout/test/layout-persistence => vuu-utils/test}/utils.ts (100%) diff --git a/vuu-ui/packages/vuu-layout/test/layout-persistence/LocalLayoutPersistenceManager.test.ts b/vuu-ui/packages/vuu-layout/test/layout-persistence/LocalLayoutPersistenceManager.test.ts index 4a36e1cc8..61fc9d912 100644 --- a/vuu-ui/packages/vuu-layout/test/layout-persistence/LocalLayoutPersistenceManager.test.ts +++ b/vuu-ui/packages/vuu-layout/test/layout-persistence/LocalLayoutPersistenceManager.test.ts @@ -8,7 +8,7 @@ import { saveLocalEntity, } from "../../../vuu-filters/src/local-config"; import { formatDate } from "@finos/vuu-utils"; -import { expectPromiseRejectsWithError } from "./utils"; +import { expectPromiseRejectsWithError } from "@finos/vuu-utils/test/utils"; vi.mock("@finos/vuu-filters", async () => { return { diff --git a/vuu-ui/packages/vuu-layout/test/layout-persistence/RemoteLayoutPersistenceManager.test.ts b/vuu-ui/packages/vuu-layout/test/layout-persistence/RemoteLayoutPersistenceManager.test.ts index 213d1e6a9..1691aee09 100644 --- a/vuu-ui/packages/vuu-layout/test/layout-persistence/RemoteLayoutPersistenceManager.test.ts +++ b/vuu-ui/packages/vuu-layout/test/layout-persistence/RemoteLayoutPersistenceManager.test.ts @@ -7,7 +7,7 @@ import { import { LayoutMetadata, LayoutMetadataDto } from "@finos/vuu-shell"; import { LayoutJSON } from "../../src/layout-reducer"; import { v4 as uuidv4 } from "uuid"; -import { expectPromiseRejectsWithError } from "./utils"; +import { expectPromiseRejectsWithError } from "@finos/vuu-utils/test/utils"; const persistence = new RemoteLayoutPersistenceManager(); const mockFetch = vi.fn(); diff --git a/vuu-ui/packages/vuu-shell/src/layout-management/SaveLayoutPanel.css b/vuu-ui/packages/vuu-shell/src/layout-management/SaveLayoutPanel.css index f7c7a3fde..ec315b1ac 100644 --- a/vuu-ui/packages/vuu-shell/src/layout-management/SaveLayoutPanel.css +++ b/vuu-ui/packages/vuu-shell/src/layout-management/SaveLayoutPanel.css @@ -9,6 +9,12 @@ --saltText-color: var(--text-secondary-foreground, #606477); } +.spinner{ + width: 100px; + height:100px; + background-image: var(--svg-spinner); +} + .saveLayoutPanel-panelContainer { display: flex; flex-direction: column; @@ -69,13 +75,9 @@ } .saveLayoutPanel-screenshot { - display: flex; - justify-content: center; - align-items: center; background: lightgray 50% / cover no-repeat; width: 273px; height: 186px; - flex-shrink: 0; } .saveLayoutPanel-buttonsContainer { diff --git a/vuu-ui/packages/vuu-shell/src/layout-management/SaveLayoutPanel.tsx b/vuu-ui/packages/vuu-shell/src/layout-management/SaveLayoutPanel.tsx index a86abd873..72678d4cf 100644 --- a/vuu-ui/packages/vuu-shell/src/layout-management/SaveLayoutPanel.tsx +++ b/vuu-ui/packages/vuu-shell/src/layout-management/SaveLayoutPanel.tsx @@ -1,7 +1,7 @@ -import { ChangeEvent, useEffect, useState } from "react"; -import { Input, Button, FormField, FormFieldLabel, Text } from "@salt-ds/core"; -import { ComboBox, Checkbox, RadioButton } from "@finos/vuu-ui-controls"; +import { Checkbox, ComboBox, RadioButton } from "@finos/vuu-ui-controls"; import { takeScreenshot } from "@finos/vuu-utils"; +import { Button, FormField, FormFieldLabel, Input, Text } from "@salt-ds/core"; +import { ChangeEvent, useEffect, useMemo, useState } from "react"; import { LayoutMetadataDto } from "./layoutTypes"; import "./SaveLayoutPanel.css"; @@ -32,12 +32,17 @@ export const SaveLayoutPanel = (props: SaveLayoutPanelProps) => { const [checkValues, setCheckValues] = useState([]); const [radioValue, setRadioValue] = useState(radioValues[0]); const [screenshot, setScreenshot] = useState(); + const [screenshotErrorMessage, setScreenshotErrorMessage] = useState(); useEffect(() => { if (componentId) { - takeScreenshot(document.getElementById(componentId) as HTMLElement).then( - (screenshot) => setScreenshot(screenshot) - ); + takeScreenshot(document.getElementById(componentId) as HTMLElement) + .then((screenshot) => { + setScreenshot(screenshot); + }) + .catch((error: Error) => { + setScreenshotErrorMessage(error.message); + }); } }, [componentId]); @@ -50,6 +55,22 @@ export const SaveLayoutPanel = (props: SaveLayoutPanelProps) => { }); }; + const screenshotContent = useMemo(() => { + if (screenshot) { + return ( + screenshot of current layout + ); + } + if (screenshotErrorMessage) { + return {screenshotErrorMessage}; + } + return
; + }, [screenshot, screenshotErrorMessage]); + return (
@@ -119,15 +140,7 @@ export const SaveLayoutPanel = (props: SaveLayoutPanelProps) => {
- {screenshot ? ( - screenshot of current layout - ) : ( - No screenshot available - )} + {screenshotContent}
diff --git a/vuu-ui/packages/vuu-utils/src/screenshot-utils.ts b/vuu-ui/packages/vuu-utils/src/screenshot-utils.ts index 1cee30205..bcfde9ae3 100644 --- a/vuu-ui/packages/vuu-utils/src/screenshot-utils.ts +++ b/vuu-ui/packages/vuu-utils/src/screenshot-utils.ts @@ -2,22 +2,30 @@ import { toPng } from "html-to-image"; /** * Takes a screenshot of the given node and returns the base64 encoded image url - * @param node Node to take screenshot of + * @param node HTMLElement to take screenshot of * @returns Base64 encoded image url */ -export async function takeScreenshot(node: HTMLElement) { - - const screenshot = await toPng(node, { cacheBust: true }) - .then((dataUrl) => { - return dataUrl; +export const takeScreenshot = (node: HTMLElement): Promise => { + return new Promise((resolve, reject) => { + toPng(node, { + cacheBust: true, + filter: (child) => + // remove content of table rows + child.nodeType === Node.TEXT_NODE || + child.getAttribute("role") !== "row", }) - .catch((err) => { - console.error("Error taking screenshot", err); - return undefined; - }); - - if (!screenshot) { - return undefined; - } - return screenshot; -} + .then((screenshot) => { + if (!screenshot) { + reject(new Error("No Screenshot available")); + } + resolve(screenshot); + }) + .catch((error: Error) => { + console.error( + "the following error occurred while taking a screenshot of a DOMNode", + error + ); + reject(new Error("Error taking screenshot")); + }); + }); +}; diff --git a/vuu-ui/packages/vuu-utils/test/screenshot-utils.test.ts b/vuu-ui/packages/vuu-utils/test/screenshot-utils.test.ts index 9809fde58..c45b65a12 100644 --- a/vuu-ui/packages/vuu-utils/test/screenshot-utils.test.ts +++ b/vuu-ui/packages/vuu-utils/test/screenshot-utils.test.ts @@ -1,38 +1,38 @@ import { takeScreenshot } from "../src/screenshot-utils"; import { describe, expect, it, vi } from "vitest"; +import { expectPromiseRejectsWithError } from "./utils"; +import htmlToImage from "html-to-image"; -/** - * The default environment in Vitest is a Node.js environment. If you are building a web application, you can use browser-like environment through either jsdom or happy-dom instead - * @vitest-environment happy-dom - */ +const node = document.createElement("div"); describe("takeScreenshot", () => { it("returns a string when toPng() promise is resolved", async () => { const placeholderImage = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAZAAAACWCAYAAADwkd5lAAAAAXNSR0IArs4c6QAADyRJREFUeF7tnLmLVE0Xh6tBxhmYwFlAnEwT/wEDcUk0MNdAwSUwUEQRBNFA3DEQFEFEFFwC9S9RQwWZRA3UZBRkFhBhXIL5qOt7+7vT0z11l6pbp6qehuZ1+tZy6jnn1q/Oud1vZ3p6eunPnz9qZGQkew8NDSleEIAABCAAgV4CWisWFxezt9aKzszMzNLk5KSan5/P3vo1Pj6evRETAggCEIBA2gS0aPTTh9nZ2X8CMjU11SX08+fPbuPR0dFMSMbGxlSn00mbIquHAAQgkAiBpaUltbCwkGmB1oQ8qdCakL++fv26UkDyi2UGSIQly4QABCCQBIEqCcSqAlKkNSiFocSVREyxSAhAIGICdff30gJSZFdFoSJmztIgAAEIBEvARoWploBQ4go2ZjAcAhBInIDNBKCRgFDiSjwSWT4EIBAEgbolKtPirAkIJS4Taq5DAAIQaI+AjRKVyVonAkKJy4Sd6xCAAATcELBZojJZ6FRAKHGZ8HMdAhCAQHMCrkpUJstaExBKXCZXcB0CEIBAeQJtlKhM1ngREEpcJrdwHQIQgEB/Am2WqEw+8CoglLhM7uE6BCAAAaV8lahM7MUICCUuk6u4DgEIpERAQonKxFukgFDiMrmN6xCAQKwEJJWoTIxFCwglLpP7uA4BCMRAQGqJysQ2GAGhxGVyJdchAIGQCIRQojLxDFJAKHGZ3Mp1CEBAKoGQSlQmhkELCCUuk3u5DgEISCAQaonKxC4aAaHEZXI11yEAgTYJxFCiMvGKUkAocZncznUIQMAVgZhKVCZGUQsIJS6T+7kOAQjYIBBricrEJhkBocRlCgWuQwACVQikUKIy8UhSQChxmcKC6xCAwCACKZWoTFGQtIBQ4jKFB9chAAFNINUSlcn7CEgfQpwwTGHDdQjET4ASldnHCMgqjAggcwDRAgKxEeAAWd6jCEhJVqSwJUHRDAIBEuD+ruc0BKQGN04oNaDRBQLCCFBhaO4QBKQBQwKwATy6QsATAQ6A9sAjIJZYkgJbAskwEHBAgPvTAVSlFALigCsnHAdQGRICFQlQIagIrEZzBKQGtLJdCOCypGgHAXsEOMDZY2kaCQExEbJ0nRTaEkiGgUAfAtxffsICAfHAnROSB+hMGR0BMnz/LkVAPPqAG8AjfKYOlgAHMDmuQ0CE+IIUXIgjMEMkAe4PkW7hW1gS3cIJS6JXsKltAmTobROvPh8ZSHVmrfXgBmoNNRMJIsABSpAzDKYgIIH4ihQ+EEdhZi0CxHctbN47ISDeXVDdAE5o1ZnRQx4BMmx5PqlqEQJSlZig9tyAgpyBKaUJcAAqjUp8QwREvIvKGUgJoBwnWvkhQHz64e56VgTENWEP43PC8wCdKVcQIEOOPygQkIh9zA0csXMFL40DjGDnWDYNAbEMVOpwlBCkeiYOu4ivOPxYdRUISFViEbTnhBiBEwUsgQxXgBM8m4CAeHaAz+nZAHzSD3duDiDh+s625QiIbaKBjkcJIlDHtWQ28dES6MCmQUACc1gb5nLCbIOy/DnIUOX7yLeFCIhvDwienw1EsHMcmsYBwiHcyIZGQCJzqKvlUMJwRVbGuPhXhh9CswIBCc1jAuzlhCrACRZMIMO0ADHxIRCQxAOgyfLZgJrQ89eXA4A/9rHNjIDE5lFP66EE4gl8yWnxT0lQNKtEAAGphIvGZQhwwi1DyX0bMkT3jFOfAQFJPQIcrp8NzCHcVYZGwP1wT3FWBCRFr3tYMyUUt9Dh65Yvo/cngIAQGa0T4IRsBzkZnh2OjFKfAAJSnx09GxJgA6wHEAGux41e9gkgIPaZMmINApRgVocGnxpBRRfnBBAQ54iZoCoBTtj/iJGhVY0c2rdNAAFpmzjzlSaQ6gaKgJYOERp6JoCAeHYA05cjEHsJJ/b1lfMyrUIjgICE5jHsVbGc0FPNsAjheAggIPH4MrmVhLoBxyKAyQUcC15BAAEhKKIgIL0EJN2+KIKARbROAAFpHTkTuiYg5YQfaobk2j+MHw8BBCQeX7KSHgK+NnApAkZAQMA1AQTENWHGF0HAdQnJ9fgiIGIEBHoIICCERHIEbGUIvjKc5BzGgsUSQEDEugbDXBOoKwC2BMj1+hgfAq4JICCuCTN+EARMJSjT9SAWiZEQsEwAAbEMlOHCJ5BnGHNzc2p4eDhb0O/fv9X4+Hj2Hh0dDX+RrAACFgggIBYgMkRcBIolqrVr12aL+/Xrl5qYmEBA4nI1q2lIAAFpCJDucRAwlahM1+OgwCogUI0AAlKNF60jIsBD9IicyVK8EEBAvGBnUp8EbH2Lqq4A+Vw7c0PAJoFv376pzszMzNLU1JTNcRkLAqIIuC5BuR5fFEyMgcB/BBAQQiFaAr4yBFsZTrSOYWHREKCEFY0rWUhOQMoG7kvAiAQItEWADKQt0szjlID0EpJ0+5w6h8GjJUAGEq1r419YqCd8KRlS/BHCCl0TIANxTZjxrROIZQMOVQCtO5QBgyVABhKs69IyPPYSUOzrSyta01ktApKOr4Nbaaon9FgyrOACDoMrE0BAKiOjg2sCbKD/CKcqoK7ji/HtEeAZiD2WjNSAACWc1eHBp0Fw0dUZAQTEGVoGNhHghG0i1P86GVo9bvSyT4ASln2mjGggwAZoJ0QQYDscGaU+AQSkPjt6ViBACaYCrBpN4VsDGl0aE0BAGiNkgEEEOCH7iQ0yPD/cU5yVZyApet3xmtnAHAMuOTwCXhIUzWoTIAOpjY6ORQKUUGTHA/6R7Z9QrUNAQvWcALs54QpwQg0TyBBrQKNLXwKUsAiMygTYgCojE9mBA4BItwRlFBlIUO7yZywlEH/s25gZ/7ZBOb45yEDi86m1FXFCtYYyqIHIMINyl1djyUC84pc5ORuITL+0bRUHiLaJhzcfAhKez5xYTAnDCdZoBiU+onGl1YUgIFZxhjUYJ8yw/CXFWjJUKZ7wbwfPQPz7oHUL2ABaRx7lhBxAonRrpUUhIJVwhduYEkS4vgvBcuIrBC/Zt5ESln2mYkbkhCjGFUkZQoabjrsRkAh9zQ0coVMDXBIHmACdVtFkBKQiMKnNKSFI9Qx2aQLEZ5xxwDOQgP3KCS9g5yVsOhlyPM4nAwnQl9yAAToNk1cQ4AAUflAgIIH4kBJAII7CzFoEiO9a2Lx3ooTl3QWDDeCEJtg5mOaMABm2M7TWByYDsY60+YDcQM0ZMkL4BDhAyfchGYgQH5HCC3EEZogkwP0h0i2KDMSjXzhheYTP1MESIEOX4zoExIMvuAE8QGfK6AhwAPPvUkpYLfmAFLwl0EyTJAHuLz9uR0AccueE5BAuQ0NgAAEy/PZCAwFxwJoAdgCVISFQkQAHuIrAajTnGUgNaP26kEJbAskwEHBAgPvTAVSlFBlIA66ccBrAoysEPBGgQmAPPBlIDZYEYA1odIGAMAIcAJs7hAykJENS4JKgaAaBAAlwf9dzGhnIKtw4odQLKnpBIGQCVBjKew8B6cOKACofQLSEQKwEOECaPUsJ6z9GpLDmYKEFBFIlwP7Q3/NJZyCcMFLdDlg3BOoToELxf3ZJZiAEQP2bh54QgMA/AhxAVTr/N15SUG57CEDAFYFU95eoS1icEFzdLowLAQgMIpBShSNKAUnJgdzGEICATAIpHGCjeQaSagop89bBKghAoEgg1v0paAFJQeG5DSEAgbgIxFQhCbKEFZMD4ro1WA0EIFCWQAwH4GAykFhTwLLBRjsIQCBeAqHub6IzkBgUOt6QZ2UQgIALAiFVWERmICEBdBFAjAkBCEAghAO0mAwk1BSOMIcABCDgmoDU/dGrgISgsK4Dg/EhAAEIVCEgqULjpYQlCUAVx9EWAhCAgG0C169fz4a8ePFid2j92aVLl7K/X716pbZv39699uLFC3Xo0KHs7wcPHqjdu3crvaeOj49n79HR0YEmLi4uqjNnzqjDhw93x8w/e/jwYbfftWvXuvZ8+PBB7d+/X717904dP35c3blzR42MjGRtW8tApKZgtoOB8SAAAQiUJfD69Wu1Y8cOVdyw9WdaQLRQvH//vvvviYkJpTfz06dPq7t372ZT5P/euHGjmp+fz976lYvJ0NBQ15SiUBRFaW5uTp06dUpduXJFbd68eZnpeZ+dO3eqvXv3ZuKj/33w4MGsndMMhBJV2TCiHQQgkBoBvTlfvnw5O9lrEckzkGJG0psxaFF5+fJlNwvQbTdt2tTd0DXDfhWe79+/qwMHDqitW7eqL1++ZHPlWY0WJS0e9+7dU1qkiq+iYGlx0eL27Nmz7vxOMhBKVKndCqwXAhCoSkCLgX59+vQp+6/e1Isnfn3K7/27t9yV/3327NksO9CvvMT0/Plz9fTpU3Xz5k2ls4x169apDRs2qGPHji0TkF5RKK6jmA1pcen921oGQomqavjQHgIQSJWA3tAvXLigbty4oe7fv79CQIrPKIpZRm/GoUVIC1Cv+GzZsqVb3tKZQ74/67bnzp1T58+fV3v27FG6xFV8pqIN0Z/rz3LBKGYcvdlKowyEElWq4c+6IQCBJgS0EOzatSsrI61WstJzlBUQ3bb4wFtnIPmzitxWLVy6lHXixIms9KUfuD958iR7dpJnLnq+mZmZ7O+3b98uK1lZERBKVE1Ch74QgEDKBPQm/PjxY3X16tXs20z9BCR/UF22hNX7Da5cAPJvSxUFRIuKbr9t2za1sLCQiUfxW1y6b/5wfnZ2dtlD/NolLEpUKYc8a4cABGwR6C0Z5ePmX5G9detW98F4v4foecmqNzvRf+sN/uTJk2r9+vXqyJEjfTOQXECKXw0u7u+fP39Wjx49ykprP378WPaAvdJDdEpUtkKGcSAAAQj0J9D7YLzO13j1cw5dnsrFYXJyctkzkH4ZiBaQfg/t9Vd6x8bGst+arFmzRt2+fTv7rcm+ffvKfY2XEhWhDgEIQKAdAk1+SJg/58jFQ4tCXs7SmY5+AJ4/ENerKYpMnoH0/pAwz4SGh4ezEtebN2+y34l8/PhRHT16NPu674ofEmrFMv0QpR2czAIBCEAAApIIDHqEoQWpMz09vfT3799MVbTqFH+92Ol0lC5lFV/6M/0qft7kMz3WoP5157Yx5qC5+629rJ1lx+wXPDmj3vlXa9s7X29bn2PWmdu09n5jrhbDpvEk3cTYAgEJBLSY6KxFv7VW/A8L/q17HrcSiwAAAABJRU5ErkJggg=="; - - // We need to mock the html-to-image package because the web API operations it relies on (e.g. canvas.toDataUrl) are not available in the test environment - const htmlToImage = await import("html-to-image"); htmlToImage.toPng = vi.fn().mockResolvedValue(placeholderImage); - const node = document.createElement("div"); - const screenshot = await takeScreenshot(node); expect(typeof screenshot).toEqual("string"); }); - it("returns undefined when toPng() promise is rejected", async () => { - // We need to mock the html-to-image package because the web API operations it relies on (e.g. canvas.toDataUrl) are not available in the test environment - const htmlToImage = await import("html-to-image"); + it("rejects with error message when toPng() promise is rejected", async () => { + htmlToImage.toPng = vi.fn().mockRejectedValue({}); - const node = document.createElement("div"); - const screenshot = await takeScreenshot(node); + expectPromiseRejectsWithError( + () => takeScreenshot(node), + "Error taking screenshot" + ); + }); - console.log(screenshot); + it("rejects with error message when toPng() resolves with falsey value", async () => { + htmlToImage.toPng = vi.fn().mockResolvedValue(undefined); - expect(screenshot).toBeUndefined(); + expectPromiseRejectsWithError( + () => takeScreenshot(node), + "No Screenshot available" + ); }); }); diff --git a/vuu-ui/packages/vuu-layout/test/layout-persistence/utils.ts b/vuu-ui/packages/vuu-utils/test/utils.ts similarity index 100% rename from vuu-ui/packages/vuu-layout/test/layout-persistence/utils.ts rename to vuu-ui/packages/vuu-utils/test/utils.ts From 11bca1006fbe872c572a5fcb6e7951c417951c87 Mon Sep 17 00:00:00 2001 From: heswell Date: Thu, 21 Dec 2023 11:12:56 +0000 Subject: [PATCH 04/38] Table package refactor (#1083) * all packages typecheck * fix all type issues * omit build script from semgrep * omit build script from semgrep * fix final type issues * bump version of salt * WIP * refactor dialog to use native html element, discard scrim * WIP table styling * fix styling issues in checkbox, switch * rename KatoutPersistende to Persistence * add misisng hook dependency * fix persistence manager tests broken by file rename * move screenshot utils from utils to shell * move from classnames to clsx * fix classnames import --- .semgrepignore | 3 +- vuu-ui/package-lock.json | 1669 ++++++++++++++--- vuu-ui/package.json | 8 +- .../src/ViewportRowModelDataSource.ts | 5 +- .../src/useViewportRowModel.ts | 30 +- vuu-ui/packages/vuu-data-local/package.json | 21 + .../src/array-data-source/aggregate-utils.ts | 0 .../array-data-source/array-data-source.ts | 50 +- .../src/array-data-source/array-data-utils.ts | 3 +- .../src/array-data-source/group-utils.ts | 0 .../src/array-data-source/sort-utils.ts | 0 vuu-ui/packages/vuu-data-local/src/index.ts | 2 + .../src/json-data-source}/json-data-source.ts | 30 +- .../tsconfig.json | 0 .../vuu-data-react/src/hooks/useDataSource.ts | 7 +- .../src/hooks/useLookupValues.ts | 4 +- .../src/hooks/useServerConnectionQuality.ts | 2 +- .../src/hooks/useServerConnectionStatus.ts | 3 +- .../src/hooks/useTypeaheadSuggestions.ts | 2 +- .../src/hooks/useVuuMenuActions.ts | 12 +- .../vuu-data-react/src/hooks/useVuuTables.ts | 5 +- .../{vuu-data => vuu-data-remote}/README.md | 0 .../package.json | 2 +- .../src/authenticate.ts | 0 .../src/connection-manager.ts | 36 +- .../src/connectionTypes.ts | 0 .../src/constants.ts | 0 .../vuu-data-remote/src/data-source.ts | 86 + .../src/index.ts | 5 +- .../vuu-data-remote/src/inlined-worker.js | 8 + .../src/message-utils.ts | 38 +- .../array-backed-moving-window.ts | 0 .../src/server-proxy/messages.ts | 0 .../src/server-proxy/rpc-services.ts | 0 .../src/server-proxy/server-proxy.ts | 66 +- .../src/server-proxy/viewport.ts | 54 +- .../src/vuu-data-source.ts} | 53 +- .../src/websocket-connection.ts | 6 +- .../src/worker.ts | 20 +- .../test/array-backed-moving-window.test.js | 0 .../test/global-mocks.ts | 0 .../test/message-utils.test.ts | 0 .../test/remote-data-source.test.ts | 42 +- .../test/server-proxy-throttle.test.ts | 0 .../test/server-proxy.test.ts | 0 .../test/test-utils.ts | 0 .../test/viewport.test.ts | 0 .../test/websocket-connection.test.ts | 0 vuu-ui/packages/vuu-data-remote/tsconfig.json | 6 + vuu-ui/packages/vuu-data-test/src/Table.ts | 2 +- .../src/TickingArrayDataSource.ts | 19 +- .../src/basket/basket-schemas.ts | 2 +- vuu-ui/packages/vuu-data-test/src/schemas.ts | 2 +- .../src/simul/reference-data/instruments.ts | 2 +- .../vuu-data-test/src/simul/simul-schemas.ts | 2 +- .../packages/vuu-data-test/src/vuu-modules.ts | 4 +- vuu-ui/packages/vuu-data-types/index.d.ts | 676 ++++++- vuu-ui/packages/vuu-data/src/data-source.ts | 604 ------ .../packages/vuu-data/src/inlined-worker.js | 8 - .../vuu-data/src/vuuUIMessageTypes.ts | 388 ---- vuu-ui/packages/vuu-datatable/package.json | 2 +- .../src/filter-table/FilterTable.tsx | 2 +- .../src/json-table/JsonTable.tsx | 2 +- vuu-ui/packages/vuu-filters/package.json | 3 +- .../vuu-filters/src/filter-bar/FilterBar.tsx | 5 +- .../src/filter-bar/useFilterBar.ts | 2 +- .../vuu-filters/src/filter-bar/useFilters.ts | 6 +- .../src/filter-clause/ExpandoCombobox.tsx | 2 +- .../src/filter-clause/FilterClauseEditor.tsx | 4 +- .../filter-clause/useFilterClauseEditor.ts | 7 +- .../src/filter-input/useCodeMirrorEditor.ts | 2 +- .../src/filter-pill-menu/FilterPillMenu.tsx | 2 +- .../src/filter-pill/FilterPill.tsx | 7 +- vuu-ui/packages/vuu-icons/index.css | 2 +- vuu-ui/packages/vuu-layout/package.json | 8 +- .../vuu-layout/src/DraggableLayout.tsx | 2 +- .../vuu-layout/src/dock-layout/DockLayout.tsx | 2 +- .../vuu-layout/src/dock-layout/Drawer.tsx | 2 +- .../vuu-layout/src/drag-drop/DropMenu.tsx | 2 +- .../vuu-layout/src/flexbox/Flexbox.tsx | 2 +- .../vuu-layout/src/flexbox/FluidGrid.tsx | 2 +- .../vuu-layout/src/flexbox/Splitter.tsx | 2 +- vuu-ui/packages/vuu-layout/src/index.ts | 1 - .../src/layout-header/ActionButton.tsx | 27 +- .../vuu-layout/src/layout-header/Header.tsx | 2 +- .../src/layout-persistence/index.ts | 5 - .../vuu-layout/src/layout-view/View.tsx | 4 +- .../layout-view/useViewActionDispatcher.ts | 2 +- .../measured-container/MeasuredContainer.tsx | 2 +- .../overflow-container/OverflowContainer.tsx | 5 +- .../useOverflowContainer.ts | 7 +- .../vuu-layout/src/palette/Palette.tsx | 2 +- .../src/placeholder/LayoutStartPanel.tsx | 2 +- .../src/placeholder/Placeholder.tsx | 4 +- .../packages/vuu-layout/src/stack/Stack.tsx | 4 +- .../vuu-layout/src/stack/StackLayout.tsx | 4 +- .../vuu-layout/src/toolbar/Toolbar.tsx | 15 +- .../vuu-layout/src/toolbar/useToolbar.ts | 3 +- .../devtools-tree/layout-tree-viewer.jsx | 2 +- .../vuu-layout/src/utils/react-utils.ts | 32 +- vuu-ui/packages/vuu-popups/package.json | 11 +- .../src/dialog-header/DialogHeader.tsx | 2 +- .../packages/vuu-popups/src/dialog/Dialog.css | 2 + .../packages/vuu-popups/src/dialog/Dialog.tsx | 89 +- .../vuu-popups/src/menu/ContextMenu.tsx | 14 +- .../packages/vuu-popups/src/menu/MenuList.css | 3 +- .../packages/vuu-popups/src/menu/MenuList.tsx | 6 +- .../vuu-popups/src/menu/useContextMenu.tsx | 6 +- .../notifications/NotificationsProvider.tsx | 6 +- .../vuu-popups/src/popup-menu/PopupMenu.tsx | 13 +- .../packages/vuu-popups/src/popup/Popup.tsx | 3 +- .../vuu-popups/src/popup/popup-service.ts | 2 +- .../src/popup/useAnchoredPosition.ts | 2 +- .../src/portal-deprecated/render-portal.tsx | 2 +- .../packages/vuu-popups/src/portal/Portal.tsx | 33 +- .../packages/vuu-popups/src/prompt/Prompt.tsx | 4 +- .../vuu-popups/src/tooltip/Tooltip.tsx | 2 +- .../vuu-popups/src/tooltip/useTooltip.ts | 2 +- vuu-ui/packages/vuu-shell/package.json | 9 +- .../vuu-shell/src/ShellContextProvider.tsx | 6 +- .../vuu-shell/src/app-header/AppHeader.tsx | 6 +- .../ConnectionStatusIcon.tsx | 93 +- .../src/density-switch/DensitySwitch.tsx | 40 - .../vuu-shell/src/density-switch/index.ts | 1 - vuu-ui/packages/vuu-shell/src/index.ts | 2 - .../src/layout-management/SaveLayoutPanel.tsx | 6 +- .../layout-management}/screenshot-utils.ts | 4 +- .../layout-management/useLayoutManager.tsx | 18 +- .../vuu-shell/src/left-nav/LeftNav.tsx | 6 +- .../vuu-shell/src/login/LoginPanel.tsx | 2 +- .../LocalPersistenceManager.ts} | 19 +- .../PersistenceManager.ts} | 4 +- .../RemotePersistenceManager.ts} | 13 +- .../defaultApplicationJson.ts | 2 +- .../src/persistence-management/index.ts | 5 + .../useLayoutContextMenuItems.tsx | 10 +- .../SessionEditingForm.tsx | 34 +- .../context-panel/ContextPanel.tsx | 2 +- .../shell-layouts/side-panel/SidePanel.tsx | 2 +- vuu-ui/packages/vuu-shell/src/shell.tsx | 27 +- .../vuu-shell/src/theme-provider/index.ts | 1 - .../src/theme-switch/ThemeSwitch.tsx | 4 +- .../vuu-shell/src/user-profile/UserPanel.css | 26 - .../vuu-shell/src/user-profile/UserPanel.tsx | 103 - .../src/user-profile/UserProfile.css | 3 - .../src/user-profile/UserProfile.tsx | 39 - .../vuu-shell/src/user-profile/index.ts | 1 - .../LocalLayoutPersistenceManager.test.ts | 8 +- .../RemoteLayoutPersistenceManager.test.ts | 8 +- .../screenshot-utils.test.ts | 6 +- .../test/layout-persistence/utils.ts | 8 + vuu-ui/packages/vuu-table-extras/package.json | 7 +- .../background-cell/BackgroundCell.tsx | 2 +- .../dropdown-cell/DropdownCell.css | 0 .../dropdown-cell/DropdownCell.tsx | 2 +- .../src/cell-renderers/dropdown-cell/index.ts | 0 .../src/cell-renderers/index.ts | 2 + .../cell-renderers/lookup-cell/LookupCell.tsx | 2 +- .../src/cell-renderers/lookup-cell/index.ts | 0 .../progress-cell/ProgressCell.tsx | 2 +- .../useColumnExpressionSuggestionProvider.ts | 10 +- .../ColumnExpressionPanel.tsx | 3 +- .../ColumnFormattingPanel.tsx | 2 +- .../NumericFormattingSettings.tsx | 3 +- .../src/column-list/ColumnList.tsx | 9 +- .../src/column-settings/ColumnNameLabel.tsx | 2 +- .../column-settings/ColumnSettingsPanel.tsx | 15 +- .../src/column-settings/useColumnSettings.ts | 2 +- .../src/datasource-stats/DatasourceStats.tsx | 6 +- vuu-ui/packages/vuu-table-extras/src/index.ts | 1 - .../src/table-settings/TableSettingsPanel.tsx | 16 +- .../src/table-settings/useTableSettings.ts | 11 +- vuu-ui/packages/vuu-table-types/index.d.ts | 53 +- vuu-ui/packages/vuu-table/package.json | 15 +- vuu-ui/packages/vuu-table/src/Row.tsx | 4 +- vuu-ui/packages/vuu-table/src/Table.css | 2 + vuu-ui/packages/vuu-table/src/Table.tsx | 33 +- .../vuu-table/src/cell-renderers/index.ts | 2 - .../cell-renderers/input-cell/InputCell.tsx | 5 +- .../cell-renderers/toggle-cell/ToggleCell.tsx | 2 +- .../column-header-pill/ColumnHeaderPill.tsx | 2 +- .../vuu-table/src/column-menu/ColumnMenu.tsx | 2 +- .../column-resizing/useTableColumnResize.tsx | 13 +- .../buildContextMenuDescriptors.ts | 7 +- .../context-menu/useHandleTableContextMenu.ts | 7 +- .../src/header-cell/GroupHeaderCellNext.tsx | 9 +- .../vuu-table/src/header-cell/HeaderCell.tsx | 22 +- .../vuu-table/src/table-cell/TableCell.css | 24 +- .../src/table-cell/TableGroupCell.tsx | 2 +- .../packages/vuu-table/src/table-dom-utils.ts | 2 +- .../src/table-header/TableHeader.tsx | 6 +- vuu-ui/packages/vuu-table/src/useCell.ts | 2 +- .../packages/vuu-table/src/useDataSource.ts | 11 +- vuu-ui/packages/vuu-table/src/useSelection.ts | 13 +- vuu-ui/packages/vuu-table/src/useTable.ts | 29 +- .../src/useTableAndColumnSettings.ts | 9 +- .../vuu-table/src/useTableContextMenu.ts | 3 +- .../packages/vuu-table/src/useTableModel.ts | 19 +- .../vuu-table/src/useVirtualViewport.ts | 2 +- .../vuu-theme/css/components/checkbox.css | 4 +- .../vuu-theme/css/components/switch.css | 11 +- .../vuu-theme/css/palette/neutral.css | 2 +- vuu-ui/packages/vuu-ui-controls/package.json | 8 +- .../src/combo-box/ComboBox.tsx | 4 +- .../src/combo-box/useCombobox.ts | 2 +- .../cycle-state-button/CycleStateButton.tsx | 2 +- .../src/drag-drop/Draggable.tsx | 2 +- .../vuu-ui-controls/src/dropdown/Dropdown.tsx | 4 +- .../src/dropdown/DropdownBase.tsx | 6 +- .../src/dropdown/DropdownButton.tsx | 2 +- .../src/editable-label/EditableLabel.tsx | 2 +- .../src/editable/useEditableText.ts | 2 +- .../src/expando-input/ExpandoInput.tsx | 4 +- .../vuu-ui-controls/src/inputs/Checkbox.tsx | 18 +- .../instrument-picker/InstrumentPicker.tsx | 12 +- .../src/instrument-picker/useDataSource.ts | 7 +- .../instrument-picker/useInstrumentPicker.ts | 3 +- .../instrument-search/InstrumentSearch.tsx | 16 +- .../src/instrument-search/useDataSource.ts | 7 +- .../instrument-search/useInstrumentSearch.ts | 40 +- .../vuu-ui-controls/src/list/CheckboxIcon.tsx | 2 +- .../vuu-ui-controls/src/list/ChevronIcon.tsx | 6 +- .../vuu-ui-controls/src/list/List.tsx | 17 +- .../vuu-ui-controls/src/list/ListItem.tsx | 2 +- .../vuu-ui-controls/src/list/RadioIcon.tsx | 7 +- .../vuu-ui-controls/src/list/useList.ts | 2 +- .../src/price-ticker/PriceTicker.tsx | 2 +- .../vuu-ui-controls/src/tabstrip/Tab.tsx | 2 +- .../vuu-ui-controls/src/tabstrip/TabMenu.tsx | 10 +- .../vuu-ui-controls/src/tabstrip/Tabstrip.tsx | 5 +- .../vuu-ui-controls/src/tree/Tree.tsx | 2 +- .../src/vuu-input/VuuInput.tsx | 7 +- vuu-ui/packages/vuu-utils/package.json | 4 +- .../src}/ThemeProvider.tsx | 4 +- vuu-ui/packages/vuu-utils/src/column-utils.ts | 38 +- .../vuu-utils/src/component-registry.ts | 30 +- .../vuu-utils/src/datasource-action-utils.ts | 31 + .../vuu-utils/src/datasource-utils.ts | 257 +++ .../packages/vuu-utils/src/date/formatter.ts | 1 - .../packages/vuu-utils/src/event-emitter.ts | 12 +- vuu-ui/packages/vuu-utils/src/index.ts | 6 +- vuu-ui/packages/vuu-utils/src/row-utils.ts | 2 +- .../packages/vuu-utils/src/selection-utils.ts | 6 +- vuu-ui/packages/vuu-utils/src/useId.ts | 6 + .../vuu-utils/src/useLayoutEffectSkipFirst.ts | 16 + .../packages/vuu-utils/test/row-utils.test.ts | 2 +- vuu-ui/sample-apps/app-vuu-example/demo.tsx | 4 +- vuu-ui/sample-apps/app-vuu-example/login.tsx | 6 +- .../sample-apps/app-vuu-example/package.json | 4 +- .../session-editing/session-table-config.ts | 2 +- .../app-vuu-example/src/useFeatures.ts | 2 +- .../src/useRpcResponseHandler.tsx | 9 +- .../feature-basket-trading/package.json | 14 +- .../src/VuuBasketTradingFeature.tsx | 2 +- .../src/basket-selector/BasketSelector.tsx | 14 +- .../src/basket-selector/BasketSelectorRow.tsx | 2 +- .../src/basket-table-edit/BasketTableEdit.tsx | 2 +- .../src/basket-table-live/BasketTableLive.tsx | 2 +- .../src/basket-toolbar/BasketMenu.tsx | 2 +- .../src/basket-toolbar/BasketToolbar.tsx | 2 +- .../ColHeaderAddSymbol.tsx | 29 +- .../progress-cell/ProgressCell.tsx | 2 +- .../cell-renderers/status-cell/StatusCell.tsx | 2 +- .../src/new-basket-panel/NewBasketPanel.tsx | 4 +- .../src/new-basket-panel/useNewBasketPanel.ts | 57 +- .../src/useBasketTrading.tsx | 18 +- .../src/useBasketTradingDatasources.ts | 62 +- .../feature-filter-table/package.json | 4 +- .../src/VuuFilterTableFeature.tsx | 6 +- .../src/useFilterTable.tsx | 21 +- .../src/useSessionDataSource.ts | 14 +- .../feature-instrument-tiles/package.json | 4 +- .../src/VuuInstrumentTilesFeature.tsx | 10 +- .../src/useDataSource.ts | 2 +- .../sample-apps/feature-template/package.json | 4 +- .../src/VuuTemplateFeature.tsx | 8 +- vuu-ui/sample-apps/standalone-table/index.tsx | 5 + .../sample-apps/standalone-table/package.json | 28 + .../standalone-table/public/index.html | 14 + .../standalone-table/scripts/.eslintrc.json | 15 + .../standalone-table/scripts/build.mjs | 107 ++ .../sample-apps/standalone-table/src/App.css | 8 + .../sample-apps/standalone-table/src/App.tsx | 37 + .../standalone-table/src/table-custom.css | 3 + .../standalone-table/tsconfig.json | 6 + vuu-ui/scripts/build-all.mjs | 2 +- vuu-ui/scripts/esbuild.mjs | 1 - vuu-ui/scripts/launch-table.mjs | 11 + vuu-ui/scripts/publish.mjs | 3 +- vuu-ui/showcase/package.json | 7 +- vuu-ui/showcase/src/App.tsx | 22 +- .../src/examples/Apps/NewTheme.examples.tsx | 25 +- .../Layout/DraggableLayout.examples.tsx | 2 +- .../Performance/Performance.examples.tsx | 13 +- .../src/examples/Popups/Dialog.examples.tsx | 1 + .../Shell/ConnectionMetrics.examples.tsx | 6 +- .../Shell/ConnectionStatus.examples.tsx | 2 +- .../Shell/SessionTableEditing.examples.tsx | 15 +- .../examples/Shell/ThemeSwitch.examples.tsx | 3 +- .../examples/Shell/components/ThemedPanel.tsx | 7 +- .../examples/ShowcaseControls/Tree.data.ts | 497 ++--- .../ShowcaseControls/Tree.examples.tsx | 19 +- .../src/examples/Table/SIMUL.examples.tsx | 6 +- .../src/examples/Table/Table.examples.tsx | 11 +- .../examples/Table/TableLayout.examples.tsx | 9 +- .../src/examples/Table/TableList.examples.tsx | 2 +- .../TableSettings/TableSettings.examples.tsx | 3 +- .../examples/UiControls/Dropdown.examples.tsx | 5 +- .../examples/UiControls/ListVisualizer.tsx | 2 +- .../VuuFeatures/BasketSelector.examples.tsx | 8 +- .../examples/html/components/DockLayout.tsx | 2 +- .../examples/html/components/GridLayout.tsx | 2 +- .../src/examples/popups/Tooltip.examples.tsx | 4 +- .../src/examples/salt/Checkbox.examples.tsx | 39 + .../src/examples/salt/Switch.examples.tsx | 39 + vuu-ui/showcase/src/examples/salt/index.ts | 2 + .../showcase/src/examples/utils/mock-data.ts | 56 - .../utils/useAutoLoginToVuuServer.tsx | 2 +- .../src/examples/utils/useTestDataSource.ts | 8 +- .../src/features/BasketTrading.feature.tsx | 23 +- vuu-ui/showcase/src/index.css | 7 + vuu-ui/showcase/src/index.tsx | 7 +- vuu-ui/tsconfig.json | 7 +- 323 files changed, 4299 insertions(+), 3052 deletions(-) create mode 100644 vuu-ui/packages/vuu-data-local/package.json rename vuu-ui/packages/{vuu-data => vuu-data-local}/src/array-data-source/aggregate-utils.ts (100%) rename vuu-ui/packages/{vuu-data => vuu-data-local}/src/array-data-source/array-data-source.ts (98%) rename vuu-ui/packages/{vuu-data => vuu-data-local}/src/array-data-source/array-data-utils.ts (94%) rename vuu-ui/packages/{vuu-data => vuu-data-local}/src/array-data-source/group-utils.ts (100%) rename vuu-ui/packages/{vuu-data => vuu-data-local}/src/array-data-source/sort-utils.ts (100%) create mode 100644 vuu-ui/packages/vuu-data-local/src/index.ts rename vuu-ui/packages/{vuu-data/src => vuu-data-local/src/json-data-source}/json-data-source.ts (97%) rename vuu-ui/packages/{vuu-data => vuu-data-local}/tsconfig.json (100%) rename vuu-ui/packages/{vuu-data => vuu-data-remote}/README.md (100%) rename vuu-ui/packages/{vuu-data => vuu-data-remote}/package.json (93%) rename vuu-ui/packages/{vuu-data => vuu-data-remote}/src/authenticate.ts (100%) rename vuu-ui/packages/{vuu-data => vuu-data-remote}/src/connection-manager.ts (97%) rename vuu-ui/packages/{vuu-data => vuu-data-remote}/src/connectionTypes.ts (100%) rename vuu-ui/packages/{vuu-data => vuu-data-remote}/src/constants.ts (100%) create mode 100644 vuu-ui/packages/vuu-data-remote/src/data-source.ts rename vuu-ui/packages/{vuu-data => vuu-data-remote}/src/index.ts (56%) create mode 100644 vuu-ui/packages/vuu-data-remote/src/inlined-worker.js rename vuu-ui/packages/{vuu-data => vuu-data-remote}/src/message-utils.ts (76%) rename vuu-ui/packages/{vuu-data => vuu-data-remote}/src/server-proxy/array-backed-moving-window.ts (100%) rename vuu-ui/packages/{vuu-data => vuu-data-remote}/src/server-proxy/messages.ts (100%) rename vuu-ui/packages/{vuu-data => vuu-data-remote}/src/server-proxy/rpc-services.ts (100%) rename vuu-ui/packages/{vuu-data => vuu-data-remote}/src/server-proxy/server-proxy.ts (98%) rename vuu-ui/packages/{vuu-data => vuu-data-remote}/src/server-proxy/viewport.ts (99%) rename vuu-ui/packages/{vuu-data/src/remote-data-source.ts => vuu-data-remote/src/vuu-data-source.ts} (97%) rename vuu-ui/packages/{vuu-data => vuu-data-remote}/src/websocket-connection.ts (98%) rename vuu-ui/packages/{vuu-data => vuu-data-remote}/src/worker.ts (94%) rename vuu-ui/packages/{vuu-data => vuu-data-remote}/test/array-backed-moving-window.test.js (100%) rename vuu-ui/packages/{vuu-data => vuu-data-remote}/test/global-mocks.ts (100%) rename vuu-ui/packages/{vuu-data => vuu-data-remote}/test/message-utils.test.ts (100%) rename vuu-ui/packages/{vuu-data => vuu-data-remote}/test/remote-data-source.test.ts (92%) rename vuu-ui/packages/{vuu-data => vuu-data-remote}/test/server-proxy-throttle.test.ts (100%) rename vuu-ui/packages/{vuu-data => vuu-data-remote}/test/server-proxy.test.ts (100%) rename vuu-ui/packages/{vuu-data => vuu-data-remote}/test/test-utils.ts (100%) rename vuu-ui/packages/{vuu-data => vuu-data-remote}/test/viewport.test.ts (100%) rename vuu-ui/packages/{vuu-data => vuu-data-remote}/test/websocket-connection.test.ts (100%) create mode 100644 vuu-ui/packages/vuu-data-remote/tsconfig.json delete mode 100644 vuu-ui/packages/vuu-data/src/data-source.ts delete mode 100644 vuu-ui/packages/vuu-data/src/inlined-worker.js delete mode 100644 vuu-ui/packages/vuu-data/src/vuuUIMessageTypes.ts delete mode 100644 vuu-ui/packages/vuu-layout/src/layout-persistence/index.ts delete mode 100644 vuu-ui/packages/vuu-shell/src/density-switch/DensitySwitch.tsx delete mode 100644 vuu-ui/packages/vuu-shell/src/density-switch/index.ts rename vuu-ui/packages/{vuu-utils/src => vuu-shell/src/layout-management}/screenshot-utils.ts (92%) rename vuu-ui/packages/{vuu-layout/src/layout-persistence/LocalLayoutPersistenceManager.ts => vuu-shell/src/persistence-management/LocalPersistenceManager.ts} (96%) rename vuu-ui/packages/{vuu-layout/src/layout-persistence/LayoutPersistenceManager.ts => vuu-shell/src/persistence-management/PersistenceManager.ts} (94%) rename vuu-ui/packages/{vuu-layout/src/layout-persistence/RemoteLayoutPersistenceManager.ts => vuu-shell/src/persistence-management/RemotePersistenceManager.ts} (94%) rename vuu-ui/packages/{vuu-layout/src/layout-persistence => vuu-shell/src/persistence-management}/defaultApplicationJson.ts (94%) create mode 100644 vuu-ui/packages/vuu-shell/src/persistence-management/index.ts rename vuu-ui/packages/{vuu-layout/src/layout-persistence => vuu-shell/src/persistence-management}/useLayoutContextMenuItems.tsx (98%) delete mode 100644 vuu-ui/packages/vuu-shell/src/theme-provider/index.ts delete mode 100644 vuu-ui/packages/vuu-shell/src/user-profile/UserPanel.css delete mode 100644 vuu-ui/packages/vuu-shell/src/user-profile/UserPanel.tsx delete mode 100644 vuu-ui/packages/vuu-shell/src/user-profile/UserProfile.css delete mode 100644 vuu-ui/packages/vuu-shell/src/user-profile/UserProfile.tsx delete mode 100644 vuu-ui/packages/vuu-shell/src/user-profile/index.ts rename vuu-ui/packages/{vuu-layout => vuu-shell}/test/layout-persistence/LocalLayoutPersistenceManager.test.ts (98%) rename vuu-ui/packages/{vuu-layout => vuu-shell}/test/layout-persistence/RemoteLayoutPersistenceManager.test.ts (97%) rename vuu-ui/packages/{vuu-utils/test => vuu-shell/test/layout-persistence}/screenshot-utils.test.ts (97%) create mode 100644 vuu-ui/packages/vuu-shell/test/layout-persistence/utils.ts rename vuu-ui/packages/{vuu-table => vuu-table-extras}/src/cell-renderers/dropdown-cell/DropdownCell.css (100%) rename vuu-ui/packages/{vuu-table => vuu-table-extras}/src/cell-renderers/dropdown-cell/DropdownCell.tsx (94%) rename vuu-ui/packages/{vuu-table => vuu-table-extras}/src/cell-renderers/dropdown-cell/index.ts (100%) rename vuu-ui/packages/{vuu-table => vuu-table-extras}/src/cell-renderers/lookup-cell/LookupCell.tsx (87%) rename vuu-ui/packages/{vuu-table => vuu-table-extras}/src/cell-renderers/lookup-cell/index.ts (100%) rename vuu-ui/packages/{vuu-table-extras => vuu-table}/src/useTableAndColumnSettings.ts (95%) rename vuu-ui/packages/{vuu-shell/src/theme-provider => vuu-utils/src}/ThemeProvider.tsx (97%) create mode 100644 vuu-ui/packages/vuu-utils/src/datasource-action-utils.ts create mode 100644 vuu-ui/packages/vuu-utils/src/datasource-utils.ts create mode 100644 vuu-ui/packages/vuu-utils/src/useId.ts create mode 100644 vuu-ui/packages/vuu-utils/src/useLayoutEffectSkipFirst.ts create mode 100644 vuu-ui/sample-apps/standalone-table/index.tsx create mode 100644 vuu-ui/sample-apps/standalone-table/package.json create mode 100644 vuu-ui/sample-apps/standalone-table/public/index.html create mode 100644 vuu-ui/sample-apps/standalone-table/scripts/.eslintrc.json create mode 100644 vuu-ui/sample-apps/standalone-table/scripts/build.mjs create mode 100644 vuu-ui/sample-apps/standalone-table/src/App.css create mode 100644 vuu-ui/sample-apps/standalone-table/src/App.tsx create mode 100644 vuu-ui/sample-apps/standalone-table/src/table-custom.css create mode 100644 vuu-ui/sample-apps/standalone-table/tsconfig.json create mode 100644 vuu-ui/scripts/launch-table.mjs create mode 100644 vuu-ui/showcase/src/examples/salt/Checkbox.examples.tsx create mode 100644 vuu-ui/showcase/src/examples/salt/Switch.examples.tsx delete mode 100644 vuu-ui/showcase/src/examples/utils/mock-data.ts diff --git a/.semgrepignore b/.semgrepignore index 7674ce98a..9f52e4cbc 100644 --- a/.semgrepignore +++ b/.semgrepignore @@ -5,7 +5,7 @@ example/main/src/main/resources/certs/cert.pem vuu/src/main/resources/www/ws-example.html example/order/src/main/scala/org/finos/vuu/provider/simulation/SimulatedBigInstrumentsProvider.scala vuu/src/main/scala/org/finos/vuu/provider/simulation/SimulatedBigInstrumentsProvider.scala -vuu-ui/packages/vuu-data/src/array-data-source/group-utils.ts +vuu-ui/packages/vuu-data-local/src/array-data-source/group-utils.ts vuu-ui/packages/vuu-datagrid-extras/src/column-expression-input/column-language-parser/walkExpressionTree.ts vuu-ui/packages/vuu-layout/src/layout-persistence/RemoteLayoutPersistenceManager.ts vuu-ui/packages/vuu-popups/src/menu/useContextMenu.tsx @@ -20,6 +20,7 @@ vuu/src/test/scala/org/finos/vuu/viewport/CreateViewPortScenarioTest.scala vuu/src/test/scala/org/finos/vuu/net/ws/WebSocketServerClientTest.scala vuu/src/test/scala/org/finos/vuu/net/rpc/RpcModuleTest.scala vuu/src/test/resources/ws.html +vuu-ui/sample-apps/standalone-table/scripts/build.mjs vuu-ui/sample-apps/app-vuu-basket-trader/scripts/build.mjs vuu-ui/sample-apps/app-vuu-example/scripts/build.mjs vuu-ui/showcase/scripts/build-docs.mjs diff --git a/vuu-ui/package-lock.json b/vuu-ui/package-lock.json index 3c748c82c..ed0257218 100644 --- a/vuu-ui/package-lock.json +++ b/vuu-ui/package-lock.json @@ -14,17 +14,16 @@ "showcase" ], "dependencies": { + "@salt-ds/core": "1.13.2", "@types/jest": "^26.0.20", "@types/node": "^14.14.35", - "@types/react": ">=17.0.2", - "@types/react-dom": ">=17.0.2", + "@types/react": "^17.0.2", + "@types/react-dom": "^17.0.2", "@typescript-eslint/parser": "^5.41.0", - "classnames": "^2.3.1", - "clsx": "^1.2.1", + "clsx": "^2.0.0", "html-to-image": "^1.11.11", - "react": ">=17.0.2", - "react-dom": ">=17.0.2", - "recoil": "^0.1.3", + "react": "^17.0.2", + "react-dom": "^17.0.2", "semver": "^7.5.2" }, "bin": { @@ -54,6 +53,7 @@ "happy-dom": "^10.10.0", "open": "^8.4.0", "prettier": "2.8.4", + "serve": "^14.2.1", "stylelint": "^15.0.0", "tinycolor2": "1.4.2", "typescript": "4.9.5", @@ -1232,10 +1232,18 @@ "resolved": "packages/vuu-data-ag-grid", "link": true }, + "node_modules/@finos/vuu-data-local": { + "resolved": "packages/vuu-data-local", + "link": true + }, "node_modules/@finos/vuu-data-react": { "resolved": "packages/vuu-data-react", "link": true }, + "node_modules/@finos/vuu-data-remote": { + "resolved": "packages/vuu-data-remote", + "link": true + }, "node_modules/@finos/vuu-data-test": { "resolved": "packages/vuu-data-test", "link": true @@ -1244,10 +1252,6 @@ "resolved": "packages/vuu-data-types", "link": true }, - "node_modules/@finos/vuu-datagrid": { - "resolved": "packages/vuu-datagrid", - "link": true - }, "node_modules/@finos/vuu-datatable": { "resolved": "packages/vuu-datatable", "link": true @@ -1793,13 +1797,13 @@ } }, "node_modules/@salt-ds/core": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/@salt-ds/core/-/core-1.8.0.tgz", - "integrity": "sha512-Na8/PEQdb93i6UvYeIn6PhLqjF3k7EbAI+/4zkHO/XeqCBGkRxK3EMibEPkw4Zwfw5PQZbDKgPxknW53aWP0AA==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@salt-ds/core/-/core-1.13.2.tgz", + "integrity": "sha512-dBw4QErYpNgfj0wL2kKeZtdoiRXS6ZFgXHSh37yBHrP/QIqFNmhwCAWGR84OgNgetU6FhKvKSSgknwyHAK0fcg==", "dependencies": { "@floating-ui/react": "^0.23.0", - "@salt-ds/icons": "^1.6.0", - "@salt-ds/styles": "^0.1.1", + "@salt-ds/icons": "^1.9.0", + "@salt-ds/styles": "^0.2.0", "@salt-ds/window": "^0.1.1", "clsx": "^2.0.0" }, @@ -1815,11 +1819,11 @@ } }, "node_modules/@salt-ds/core/node_modules/@salt-ds/icons": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@salt-ds/icons/-/icons-1.6.0.tgz", - "integrity": "sha512-/9c1L5LyU5cPxaYDyywDu8VnpvOvnaDmuLr/BWLEdyzxSzXTDfcIPtSgpaSaPadubvnnE9mhXdNknLyTqjNXZg==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@salt-ds/icons/-/icons-1.9.0.tgz", + "integrity": "sha512-82PnI/9KStt/owSTV/+vxH5AkJaYDEKuJrBbzeC2axxipv8ydbToTaCn6usLOSTm9CQ04rzMFPNcWQSpGUHtjA==", "dependencies": { - "@salt-ds/styles": "^0.1.1", + "@salt-ds/styles": "^0.2.0", "@salt-ds/window": "^0.1.1", "clsx": "^2.0.0" }, @@ -1834,23 +1838,10 @@ } } }, - "node_modules/@salt-ds/core/node_modules/clsx": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz", - "integrity": "sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==", - "engines": { - "node": ">=6" - } - }, - "node_modules/@salt-ds/icons": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/@salt-ds/icons/-/icons-1.5.1.tgz", - "integrity": "sha512-yBWRk3hcmYKrPTPQTvJsg4K3TBIvtoznaVIeYj8Gg6zy14s4gUN9N4PH9xix0pNgyCFGgluHUTiUKG6AcyGVkA==", - "dependencies": { - "@salt-ds/styles": "^0.1.1", - "@salt-ds/window": "^0.1.1", - "clsx": "^2.0.0" - }, + "node_modules/@salt-ds/core/node_modules/@salt-ds/styles": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@salt-ds/styles/-/styles-0.2.0.tgz", + "integrity": "sha512-tPd/XK1PFkPkBsYwh4fhDbo997eaev6row9aaz/sPM0FpEpU8nbvQRhxtr8iA/S4Q5hCj0xrk/jGTuK40V13oQ==", "peerDependencies": { "@types/react": ">=16.14.0", "react": ">=16.14.0", @@ -1862,14 +1853,6 @@ } } }, - "node_modules/@salt-ds/icons/node_modules/clsx": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz", - "integrity": "sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==", - "engines": { - "node": ">=6" - } - }, "node_modules/@salt-ds/lab": { "version": "1.0.0-alpha.15", "resolved": "https://registry.npmjs.org/@salt-ds/lab/-/lab-1.0.0-alpha.15.tgz", @@ -1925,14 +1908,6 @@ } } }, - "node_modules/@salt-ds/lab/node_modules/clsx": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz", - "integrity": "sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==", - "engines": { - "node": ">=6" - } - }, "node_modules/@salt-ds/styles": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/@salt-ds/styles/-/styles-0.1.1.tgz", @@ -2862,6 +2837,12 @@ "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", "dev": true }, + "node_modules/@zeit/schemas": { + "version": "2.29.0", + "resolved": "https://registry.npmjs.org/@zeit/schemas/-/schemas-2.29.0.tgz", + "integrity": "sha512-g5QiLIfbg3pLuYUJPlisNKY+epQJTcMDsOnVNkscrDP1oi7vmJnzOANYJI/1pZcVJ6umUkBv3aFtlg1UvUHGzA==", + "dev": true + }, "node_modules/abab": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", @@ -2870,6 +2851,19 @@ "optional": true, "peer": true }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dev": true, + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/acorn": { "version": "8.10.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", @@ -2940,6 +2934,15 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/ansi-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "dev": true, + "dependencies": { + "string-width": "^4.1.0" + } + }, "node_modules/ansi-colors": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", @@ -3008,6 +3011,12 @@ } ] }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "dev": true + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -3318,6 +3327,131 @@ "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", "dev": true }, + "node_modules/boxen": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-7.0.0.tgz", + "integrity": "sha512-j//dBVuyacJbvW+tvZ9HuH03fZ46QcaKvvhZickZqtB271DxJ7SNRSNxrV/dZX0085m7hISRZWbzWlJvx/rHSg==", + "dev": true, + "dependencies": { + "ansi-align": "^3.0.1", + "camelcase": "^7.0.0", + "chalk": "^5.0.1", + "cli-boxes": "^3.0.0", + "string-width": "^5.1.2", + "type-fest": "^2.13.0", + "widest-line": "^4.0.1", + "wrap-ansi": "^8.0.1" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/boxen/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/boxen/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/boxen/node_modules/camelcase": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-7.0.1.tgz", + "integrity": "sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==", + "dev": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/boxen/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/boxen/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/boxen/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/boxen/node_modules/type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "dev": true, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/boxen/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -3403,6 +3537,15 @@ "node": "*" } }, + "node_modules/bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/cac": { "version": "6.7.14", "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", @@ -3550,6 +3693,82 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/chalk-template": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/chalk-template/-/chalk-template-0.4.0.tgz", + "integrity": "sha512-/ghrgmhfY8RaSdeo43hNXxpoHAtxdbskUHjPpfqUWGttFgycUhYPGx3YZBCnUCvOa7Doivn1IZec3DEGFoMgLg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/chalk-template?sponsor=1" + } + }, + "node_modules/chalk-template/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/chalk-template/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk-template/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/chalk-template/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/chalk-template/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/character-entities": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", @@ -3626,11 +3845,6 @@ "node": ">=8" } }, - "node_modules/classnames": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz", - "integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==" - }, "node_modules/clean-stack": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", @@ -3640,6 +3854,18 @@ "node": ">=6" } }, + "node_modules/cli-boxes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz", + "integrity": "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/cli-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", @@ -3702,34 +3928,95 @@ } ] }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "node_modules/clipboardy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/clipboardy/-/clipboardy-3.0.0.tgz", + "integrity": "sha512-Su+uU5sr1jkUy1sGRpLKjKrvEOVXgSgiSInwa/qeID6aJ07yh+5NWc3h2QfjHjBnfX4LhtFcuAWKUsJ3r+fjbg==", "dev": true, "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" + "arch": "^2.2.0", + "execa": "^5.1.1", + "is-wsl": "^2.2.0" }, "engines": { - "node": ">=12" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/clsx": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", - "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", + "node_modules/clipboardy/node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, "engines": { - "node": ">=6" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "node_modules/clipboardy/node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "dev": true, - "dependencies": { + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/clipboardy/node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/clsx": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz", + "integrity": "sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==", + "engines": { + "node": ">=6" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { "color-name": "1.1.3" } }, @@ -3791,6 +4078,57 @@ "node": ">=4.0.0" } }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dev": true, + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dev": true, + "dependencies": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/compression/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, "node_modules/compute-scroll-into-view": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-3.0.3.tgz", @@ -3801,6 +4139,15 @@ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, + "node_modules/content-disposition": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "integrity": "sha512-kRGRZw3bLlFISDBgwTSA1TMBFN6J6GWDeubmDE3AF+3+yXL8hTWv8r5rkLbqYXY4RjPk/EzHnClI3zQf1cFmHA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/convert-source-map": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", @@ -4262,6 +4609,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true, + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -4377,6 +4733,12 @@ "node": ">=12" } }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, "node_modules/ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", @@ -5200,6 +5562,21 @@ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==" }, + "node_modules/fast-url-parser": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/fast-url-parser/-/fast-url-parser-1.1.3.tgz", + "integrity": "sha512-5jOCVXADYNuRkKFzNJ0dCCewsZiYo0dz8QNYljkOpFC6r2U4OBmKtvm/Tsuh4w1YYdDqDb31a8TVhBJ2OJKdqQ==", + "dev": true, + "dependencies": { + "punycode": "^1.3.2" + } + }, + "node_modules/fast-url-parser/node_modules/punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", + "dev": true + }, "node_modules/fastest-levenshtein": { "version": "1.0.16", "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", @@ -6411,6 +6788,18 @@ "node": ">=0.10.0" } }, + "node_modules/is-port-reachable": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-port-reachable/-/is-port-reachable-4.0.0.tgz", + "integrity": "sha512-9UoipoxYmSk6Xy7QFgRv2HDyaysmgSG75TFQs6S+3pDM7ZhKTF/bskZV+0UlABHzKjNVhPjYCLfeZUEg1wXxig==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-potential-custom-element-name": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", @@ -8270,6 +8659,15 @@ "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", "dev": true }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/no-scroll": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/no-scroll/-/no-scroll-2.1.1.tgz", @@ -8483,6 +8881,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -8665,6 +9072,12 @@ "node": ">=0.10.0" } }, + "node_modules/path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==", + "dev": true + }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -8679,6 +9092,12 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, + "node_modules/path-to-regexp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-2.2.1.tgz", + "integrity": "sha512-gu9bD6Ta5bwGrrU8muHzVOBFFREpp2iRkVfhBJahwJ6p6Xw20SjT0MxLnwkjOibQmGSYhiUnf2FLe7k+jcFmGQ==", + "dev": true + }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -8999,6 +9418,45 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/range-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", + "integrity": "sha512-kA5WQoNVo4t9lNx2kQNFCxKeBl5IbbSNBl1M/tLkw9WCn+hxNBAW5Qh8gdhs63CJnhjJ2zQWFoqPJP2sK1AV5A==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc/node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, + "node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/react": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", @@ -9168,22 +9626,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/recoil": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/recoil/-/recoil-0.1.3.tgz", - "integrity": "sha512-/Rm7wN7jqCjhtFK1TgtK0V115SUXNu6d4QYvwxWNLydib0QChSmpB6U8CaHoRPS0MFWtAIsD/IFjpbfk/OYm7Q==", - "peerDependencies": { - "react": ">=16.13.1" - }, - "peerDependenciesMeta": { - "react-dom": { - "optional": true - }, - "react-native": { - "optional": true - } - } - }, "node_modules/redent": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/redent/-/redent-4.0.0.tgz", @@ -9234,6 +9676,28 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/registry-auth-token": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.3.2.tgz", + "integrity": "sha512-JL39c60XlzCVgNrO+qq68FoNb56w/m7JYvGR2jT5iR1xBrUA3Mfx5Twk5rqTThPmQKMWydGmq8oFtDlxfrmxnQ==", + "dev": true, + "dependencies": { + "rc": "^1.1.6", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/registry-url": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-3.1.0.tgz", + "integrity": "sha512-ZbgR5aZEdf4UKZVBPYIgaglBmSF2Hi94s2PcIHhRGFjKYu+chjJdYfHn4rt3hB6eCKLJ8giVIIfgMa1ehDfZKA==", + "dev": true, + "dependencies": { + "rc": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/remark-mdx": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/remark-mdx/-/remark-mdx-2.3.0.tgz", @@ -9573,6 +10037,102 @@ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, + "node_modules/serve": { + "version": "14.2.1", + "resolved": "https://registry.npmjs.org/serve/-/serve-14.2.1.tgz", + "integrity": "sha512-48er5fzHh7GCShLnNyPBRPEjs2I6QBozeGr02gaacROiyS/8ARADlj595j39iZXAqBbJHH/ivJJyPRWY9sQWZA==", + "dev": true, + "dependencies": { + "@zeit/schemas": "2.29.0", + "ajv": "8.11.0", + "arg": "5.0.2", + "boxen": "7.0.0", + "chalk": "5.0.1", + "chalk-template": "0.4.0", + "clipboardy": "3.0.0", + "compression": "1.7.4", + "is-port-reachable": "4.0.0", + "serve-handler": "6.1.5", + "update-check": "1.5.4" + }, + "bin": { + "serve": "build/main.js" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/serve-handler": { + "version": "6.1.5", + "resolved": "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.5.tgz", + "integrity": "sha512-ijPFle6Hwe8zfmBxJdE+5fta53fdIY0lHISJvuikXB3VYFafRjMRpOffSPvCYsbKyBA7pvy9oYr/BT1O3EArlg==", + "dev": true, + "dependencies": { + "bytes": "3.0.0", + "content-disposition": "0.5.2", + "fast-url-parser": "1.1.3", + "mime-types": "2.1.18", + "minimatch": "3.1.2", + "path-is-inside": "1.0.2", + "path-to-regexp": "2.2.1", + "range-parser": "1.2.0" + } + }, + "node_modules/serve-handler/node_modules/mime-db": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", + "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-handler/node_modules/mime-types": { + "version": "2.1.18", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", + "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", + "dev": true, + "dependencies": { + "mime-db": "~1.33.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve/node_modules/ajv": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/serve/node_modules/chalk": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.0.1.tgz", + "integrity": "sha512-Fo07WOYGqMfCWHOzSXOt2CxDbC6skS/jO9ynEcmpANMoPrD+W1r1K6Vx7iNm+AQmETU1Xr2t+n8nzkV9t6xh3w==", + "dev": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/serve/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -9764,6 +10324,10 @@ "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", "dev": true }, + "node_modules/standalone-table": { + "resolved": "sample-apps/standalone-table", + "link": true + }, "node_modules/std-env": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.3.3.tgz", @@ -10704,6 +11268,16 @@ "browserslist": ">= 4.21.0" } }, + "node_modules/update-check": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/update-check/-/update-check-1.5.4.tgz", + "integrity": "sha512-5YHsflzHP4t1G+8WGPlvKbJEbAJGCgw+Em+dGR1KmBUbr1J36SJBqlHLjR7oob7sco5hWHGQVcr9B2poIVDDTQ==", + "dev": true, + "dependencies": { + "registry-auth-token": "3.3.2", + "registry-url": "3.1.0" + } + }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -10765,6 +11339,15 @@ "spdx-expression-parse": "^3.0.0" } }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/verror": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", @@ -11525,6 +12108,71 @@ "node": ">=8" } }, + "node_modules/widest-line": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-4.0.1.tgz", + "integrity": "sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==", + "dev": true, + "dependencies": { + "string-width": "^5.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/widest-line/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/widest-line/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/widest-line/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/widest-line/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -11766,6 +12414,20 @@ "react": ">=17.0.2" } }, + "packages/vuu-data-local": { + "name": "@finos/vuu-data-local", + "version": "0.0.26", + "license": "Apache-2.0", + "dependencies": { + "@finos/vuu-utils": "0.0.26" + }, + "devDependencies": { + "@finos/vuu-data-types": "0.0.26", + "@finos/vuu-filter-types": "0.0.26", + "@finos/vuu-protocol-types": "0.0.26", + "@finos/vuu-table-types": "0.0.26" + } + }, "packages/vuu-data-react": { "name": "@finos/vuu-data-react", "version": "0.0.26", @@ -11786,6 +12448,21 @@ "react": ">=17.0.2" } }, + "packages/vuu-data-remote": { + "name": "@finos/vuu-data-remote", + "version": "0.0.26", + "license": "Apache-2.0", + "dependencies": { + "@finos/vuu-filter-parser": "0.0.26", + "@finos/vuu-utils": "0.0.26" + }, + "devDependencies": { + "@finos/vuu-data-types": "0.0.26", + "@finos/vuu-filter-types": "0.0.26", + "@finos/vuu-protocol-types": "0.0.26", + "@finos/vuu-table-types": "0.0.26" + } + }, "packages/vuu-data-test": { "name": "@finos/vuu-data-test", "version": "0.0.26", @@ -11810,6 +12487,7 @@ "packages/vuu-datagrid": { "name": "@finos/vuu-datagrid", "version": "0.0.26", + "extraneous": true, "license": "Apache-2.0", "devDependencies": { "@finos/vuu-filter-types": "0.0.26", @@ -11854,7 +12532,7 @@ "@finos/vuu-utils": "0.0.26" }, "peerDependencies": { - "classnames": "^2.2.6", + "clsx": "^2.0.0", "react": ">=17.0.2", "react-dom": ">=17.0.2" } @@ -11887,8 +12565,7 @@ "@finos/vuu-popups": "0.0.26", "@finos/vuu-ui-controls": "0.0.26", "@finos/vuu-utils": "0.0.26", - "@salt-ds/core": "1.8.0", - "@salt-ds/lab": "1.0.0-alpha.15", + "@salt-ds/core": "1.13.2", "uuid": "9.0.0" }, "devDependencies": { @@ -11919,16 +12596,17 @@ "version": "0.0.26", "license": "Apache-2.0", "dependencies": { + "@finos/vuu-data-types": "0.0.26", "@finos/vuu-filters": "0.0.26", "@finos/vuu-popups": "0.0.26", "@finos/vuu-table": "0.0.26", "@finos/vuu-table-extras": "0.0.26", "@finos/vuu-ui-controls": "0.0.26", "@finos/vuu-utils": "0.0.26", - "@salt-ds/core": "1.8.0" + "@salt-ds/core": "1.13.2" }, "peerDependencies": { - "classnames": "^2.2.6", + "clsx": "^2.0.0", "react": ">=17.0.2", "react-dom": ">=17.0.2" } @@ -11938,18 +12616,14 @@ "version": "0.0.26", "license": "Apache-2.0", "dependencies": { - "@finos/vuu-data": "0.0.26", "@finos/vuu-data-types": "0.0.26", "@finos/vuu-layout": "0.0.26", - "@finos/vuu-shell": "0.0.26", "@finos/vuu-ui-controls": "0.0.26", "@finos/vuu-utils": "0.0.26", - "@salt-ds/core": "1.8.0", - "@salt-ds/icons": "1.5.1", - "@salt-ds/lab": "1.0.0-alpha.15" + "@salt-ds/core": "1.13.2" }, "peerDependencies": { - "classnames": "^2.2.6", + "clsx": "^2.0.0", "react": ">=17.0.2", "react-dom": ">=17.0.2" } @@ -11972,12 +12646,11 @@ "@finos/vuu-table-extras": "0.0.26", "@finos/vuu-ui-controls": "0.0.26", "@finos/vuu-utils": "0.0.26", - "@salt-ds/core": "1.8.0", - "@salt-ds/icons": "1.5.1", - "@salt-ds/lab": "1.0.0-alpha.15" + "@salt-ds/core": "1.13.2", + "html-to-image": "^1.11.11" }, "peerDependencies": { - "classnames": "^2.2.6", + "clsx": "^2.0.0", "react": ">=17.0.2", "react-dom": ">=17.0.2" } @@ -11987,20 +12660,19 @@ "version": "0.0.26", "license": "Apache-2.0", "dependencies": { - "@finos/vuu-data": "0.0.26", - "@finos/vuu-data-react": "0.0.26", - "@finos/vuu-data-types": "0.0.26", "@finos/vuu-layout": "0.0.26", "@finos/vuu-popups": "0.0.26", - "@finos/vuu-table-extras": "0.0.26", "@finos/vuu-ui-controls": "0.0.26", "@finos/vuu-utils": "0.0.26", - "@salt-ds/core": "1.8.0", - "@salt-ds/icons": "1.5.1", - "@salt-ds/lab": "1.0.0-alpha.15" + "@salt-ds/core": "1.13.2" + }, + "devDependencies": { + "@finos/vuu-data-types": "0.0.26", + "@finos/vuu-protocol-types": "0.0.26", + "@finos/vuu-table-types": "0.0.26" }, "peerDependencies": { - "classnames": "^2.2.6", + "clsx": "^2.0.0", "react": ">=17.0.2", "react-dom": ">=17.0.2" } @@ -12011,23 +12683,22 @@ "license": "Apache-2.0", "dependencies": { "@finos/vuu-codemirror": "0.0.26", - "@finos/vuu-data": "0.0.26", "@finos/vuu-data-react": "0.0.26", + "@finos/vuu-data-types": "0.0.26", "@finos/vuu-layout": "0.0.26", "@finos/vuu-popups": "0.0.26", "@finos/vuu-table-types": "0.0.26", "@finos/vuu-ui-controls": "0.0.26", "@finos/vuu-utils": "0.0.26", "@lezer/lr": "1.3.4", - "@salt-ds/core": "1.8.0", - "@salt-ds/lab": "1.0.0-alpha.15" + "@salt-ds/core": "1.13.2" }, "devDependencies": { "@finos/vuu-filter-types": "0.0.26", "@finos/vuu-protocol-types": "0.0.26" }, "peerDependencies": { - "classnames": "^2.2.6", + "clsx": "^2.0.0", "react": ">=17.0.2", "react-dom": ">=17.0.2" } @@ -12057,17 +12728,16 @@ "version": "0.0.26", "license": "Apache-2.0", "dependencies": { - "@finos/vuu-data": "0.0.26", "@finos/vuu-data-types": "0.0.26", "@finos/vuu-layout": "0.0.26", "@finos/vuu-popups": "0.0.26", "@finos/vuu-table": "0.0.26", "@finos/vuu-table-types": "0.0.26", "@finos/vuu-utils": "0.0.26", - "@salt-ds/core": "1.8.0" + "@salt-ds/core": "1.13.2" }, "peerDependencies": { - "classnames": "^2.2.6", + "clsx": "^2.0.0", "react": ">=17.0.2", "react-dom": ">=17.0.2" } @@ -12077,6 +12747,7 @@ "version": "0.0.26", "license": "Apache-2.0", "devDependencies": { + "@finos/vuu-data-types": "0.0.26", "@finos/vuu-filter-types": "0.0.26", "@finos/vuu-protocol-types": "0.0.26", "@finos/vuu-table-types": "0.0.26" @@ -12122,9 +12793,9 @@ "@finos/vuu-table-types": "0.0.26", "@finos/vuu-utils": "0.0.26", "@fontsource/open-sans": "^4.5.13", - "@salt-ds/core": "1.8.0", + "@salt-ds/core": "1.13.2", "@salt-ds/lab": "1.0.0-alpha.15", - "classnames": "^2.3.1", + "clsx": "^2.0.0", "react": ">=17.0.2", "react-dom": ">=17.0.2" }, @@ -12139,26 +12810,28 @@ "dependencies": { "@finos/vuu-data": "0.0.26", "@finos/vuu-data-react": "0.0.26", - "@finos/vuu-filter-types": "0.0.26", "@finos/vuu-filters": "0.0.26", "@finos/vuu-layout": "0.0.26", "@finos/vuu-popups": "0.0.26", - "@finos/vuu-protocol-types": "0.0.26", "@finos/vuu-shell": "0.0.26", "@finos/vuu-table": "0.0.26", "@finos/vuu-table-extras": "0.0.26", - "@finos/vuu-table-types": "0.0.26", "@finos/vuu-theme": "0.0.26", "@finos/vuu-utils": "0.0.26", - "@salt-ds/core": "1.8.0", + "@salt-ds/core": "1.13.2", "@salt-ds/lab": "1.0.0-alpha.15" }, - "devDependencies": {}, + "devDependencies": { + "@finos/vuu-data-types": "0.0.26", + "@finos/vuu-filter-types": "0.0.26", + "@finos/vuu-protocol-types": "0.0.26", + "@finos/vuu-table-types": "0.0.26" + }, "engines": { "node": ">=16.0.0" }, "peerDependencies": { - "classnames": "^2.3.1", + "clsx": "^2.0.0", "react": ">=17.0.2", "react-dom": ">=17.0.2" } @@ -12181,7 +12854,7 @@ "@finos/vuu-table-types": "0.0.26", "@finos/vuu-theme": "0.0.26", "@finos/vuu-utils": "0.0.26", - "@salt-ds/core": "1.8.0", + "@salt-ds/core": "1.13.2", "@salt-ds/lab": "1.0.0-alpha.15" }, "devDependencies": {}, @@ -12189,7 +12862,7 @@ "node": ">=16.0.0" }, "peerDependencies": { - "classnames": "^2.3.1", + "clsx": "^2.0.0", "react": ">=17.0.2", "react-dom": ">=17.0.2" } @@ -12212,7 +12885,7 @@ "@finos/vuu-table-types": "0.0.26", "@finos/vuu-theme": "0.0.26", "@finos/vuu-utils": "0.0.26", - "@salt-ds/core": "1.8.0", + "@salt-ds/core": "1.13.2", "@salt-ds/lab": "1.0.0-alpha.15" }, "devDependencies": {}, @@ -12220,7 +12893,7 @@ "node": ">=16.0.0" }, "peerDependencies": { - "classnames": "^2.3.1", + "clsx": "^2.0.0", "react": ">=17.0.2", "react-dom": ">=17.0.2" } @@ -12243,7 +12916,7 @@ "@finos/vuu-table-types": "0.0.26", "@finos/vuu-theme": "0.0.26", "@finos/vuu-utils": "0.0.26", - "@salt-ds/core": "1.8.0", + "@salt-ds/core": "1.13.2", "@salt-ds/lab": "1.0.0-alpha.15" }, "devDependencies": {}, @@ -12251,7 +12924,7 @@ "node": ">=16.0.0" }, "peerDependencies": { - "classnames": "^2.3.1", + "clsx": "^2.0.0", "react": ">=17.0.2", "react-dom": ">=17.0.2" } @@ -12317,6 +12990,21 @@ "react-dom": "^17.0.2" } }, + "sample-apps/standalone-table": { + "version": "0.0.26", + "license": "Apache-2.0", + "dependencies": { + "@finos/vuu-table": "0.0.26", + "@fontsource/open-sans": "^4.5.13", + "clsx": "^2.0.0", + "react": ">=17.0.2", + "react-dom": ">=17.0.2" + }, + "devDependencies": {}, + "engines": { + "node": ">=16.0.0" + } + }, "showcase": { "name": "@finos/showcase", "version": "0.0.26", @@ -12325,16 +13013,13 @@ "@faker-js/faker": "^8.0.2", "@finos/vuu-data-ag-grid": "0.0.26", "@finos/vuu-data-test": "0.0.26", - "@finos/vuu-datagrid": "0.0.26", "@finos/vuu-filters": "0.0.26", "@finos/vuu-layout": "0.0.26", "@finos/vuu-theme": "0.0.26", "@finos/vuu-utils": "0.0.26", - "@salt-ds/core": "1.8.0", - "@salt-ds/icons": "1.5.1", - "@salt-ds/lab": "1.0.0-alpha.15", + "@salt-ds/core": "1.13.2", "@salt-ds/theme": "1.7.1", - "classnames": "^2.3.1", + "clsx": "^2.0.0", "react": ">=17.0.2", "react-dom": ">=17.0.2", "react-router-dom": "^6.2.1" @@ -13070,18 +13755,15 @@ "@faker-js/faker": "^8.0.2", "@finos/vuu-data-ag-grid": "0.0.26", "@finos/vuu-data-test": "0.0.26", - "@finos/vuu-datagrid": "0.0.26", "@finos/vuu-filters": "0.0.26", "@finos/vuu-layout": "0.0.26", "@finos/vuu-theme": "0.0.26", "@finos/vuu-utils": "0.0.26", "@mdx-js/esbuild": "^2.3.0", - "@salt-ds/core": "1.8.0", - "@salt-ds/icons": "1.5.1", - "@salt-ds/lab": "1.0.0-alpha.15", + "@salt-ds/core": "1.13.2", "@salt-ds/theme": "1.7.1", "@thomaschaplin/isin-generator": "^1.0.3", - "classnames": "^2.3.1", + "clsx": "^2.0.0", "react": ">=17.0.2", "react-dom": ">=17.0.2", "react-router-dom": "^6.2.1" @@ -13122,6 +13804,16 @@ "@finos/vuu-utils": "0.0.26" } }, + "@finos/vuu-data-local": { + "version": "file:packages/vuu-data-local", + "requires": { + "@finos/vuu-data-types": "0.0.26", + "@finos/vuu-filter-types": "0.0.26", + "@finos/vuu-protocol-types": "0.0.26", + "@finos/vuu-table-types": "0.0.26", + "@finos/vuu-utils": "0.0.26" + } + }, "@finos/vuu-data-react": { "version": "file:packages/vuu-data-react", "requires": { @@ -13135,6 +13827,17 @@ "@finos/vuu-utils": "0.0.26" } }, + "@finos/vuu-data-remote": { + "version": "file:packages/vuu-data-remote", + "requires": { + "@finos/vuu-data-types": "0.0.26", + "@finos/vuu-filter-parser": "0.0.26", + "@finos/vuu-filter-types": "0.0.26", + "@finos/vuu-protocol-types": "0.0.26", + "@finos/vuu-table-types": "0.0.26", + "@finos/vuu-utils": "0.0.26" + } + }, "@finos/vuu-data-test": { "version": "file:packages/vuu-data-test", "requires": { @@ -13150,14 +13853,6 @@ "@finos/vuu-protocol-types": "0.0.26" } }, - "@finos/vuu-datagrid": { - "version": "file:packages/vuu-datagrid", - "requires": { - "@finos/vuu-filter-types": "0.0.26", - "@finos/vuu-protocol-types": "0.0.26", - "@finos/vuu-table-types": "0.0.26" - } - }, "@finos/vuu-datatable": { "version": "file:packages/vuu-datatable", "requires": { @@ -13197,8 +13892,7 @@ "@finos/vuu-table-types": "0.0.26", "@finos/vuu-ui-controls": "0.0.26", "@finos/vuu-utils": "0.0.26", - "@salt-ds/core": "1.8.0", - "@salt-ds/lab": "1.0.0-alpha.15", + "@salt-ds/core": "1.13.2", "@types/uuid": "^9.0.2", "uuid": "9.0.0" }, @@ -13214,27 +13908,24 @@ "@finos/vuu-layout": { "version": "file:packages/vuu-layout", "requires": { + "@finos/vuu-data-types": "0.0.26", "@finos/vuu-filters": "0.0.26", "@finos/vuu-popups": "0.0.26", "@finos/vuu-table": "0.0.26", "@finos/vuu-table-extras": "0.0.26", "@finos/vuu-ui-controls": "0.0.26", "@finos/vuu-utils": "0.0.26", - "@salt-ds/core": "1.8.0" + "@salt-ds/core": "1.13.2" } }, "@finos/vuu-popups": { "version": "file:packages/vuu-popups", "requires": { - "@finos/vuu-data": "0.0.26", "@finos/vuu-data-types": "0.0.26", "@finos/vuu-layout": "0.0.26", - "@finos/vuu-shell": "0.0.26", "@finos/vuu-ui-controls": "0.0.26", "@finos/vuu-utils": "0.0.26", - "@salt-ds/core": "1.8.0", - "@salt-ds/icons": "1.5.1", - "@salt-ds/lab": "1.0.0-alpha.15" + "@salt-ds/core": "1.13.2" } }, "@finos/vuu-protocol-types": { @@ -13251,33 +13942,29 @@ "@finos/vuu-table-extras": "0.0.26", "@finos/vuu-ui-controls": "0.0.26", "@finos/vuu-utils": "0.0.26", - "@salt-ds/core": "1.8.0", - "@salt-ds/icons": "1.5.1", - "@salt-ds/lab": "1.0.0-alpha.15" + "@salt-ds/core": "1.13.2", + "html-to-image": "^1.11.11" } }, "@finos/vuu-table": { "version": "file:packages/vuu-table", "requires": { - "@finos/vuu-data": "0.0.26", - "@finos/vuu-data-react": "0.0.26", "@finos/vuu-data-types": "0.0.26", "@finos/vuu-layout": "0.0.26", "@finos/vuu-popups": "0.0.26", - "@finos/vuu-table-extras": "0.0.26", + "@finos/vuu-protocol-types": "0.0.26", + "@finos/vuu-table-types": "0.0.26", "@finos/vuu-ui-controls": "0.0.26", "@finos/vuu-utils": "0.0.26", - "@salt-ds/core": "1.8.0", - "@salt-ds/icons": "1.5.1", - "@salt-ds/lab": "1.0.0-alpha.15" + "@salt-ds/core": "1.13.2" } }, "@finos/vuu-table-extras": { "version": "file:packages/vuu-table-extras", "requires": { "@finos/vuu-codemirror": "0.0.26", - "@finos/vuu-data": "0.0.26", "@finos/vuu-data-react": "0.0.26", + "@finos/vuu-data-types": "0.0.26", "@finos/vuu-filter-types": "0.0.26", "@finos/vuu-layout": "0.0.26", "@finos/vuu-popups": "0.0.26", @@ -13286,8 +13973,7 @@ "@finos/vuu-ui-controls": "0.0.26", "@finos/vuu-utils": "0.0.26", "@lezer/lr": "1.3.4", - "@salt-ds/core": "1.8.0", - "@salt-ds/lab": "1.0.0-alpha.15" + "@salt-ds/core": "1.13.2" }, "dependencies": { "@lezer/lr": { @@ -13310,19 +13996,19 @@ "@finos/vuu-ui-controls": { "version": "file:packages/vuu-ui-controls", "requires": { - "@finos/vuu-data": "0.0.26", "@finos/vuu-data-types": "0.0.26", "@finos/vuu-layout": "0.0.26", "@finos/vuu-popups": "0.0.26", "@finos/vuu-table": "0.0.26", "@finos/vuu-table-types": "0.0.26", "@finos/vuu-utils": "0.0.26", - "@salt-ds/core": "1.8.0" + "@salt-ds/core": "1.13.2" } }, "@finos/vuu-utils": { "version": "file:packages/vuu-utils", "requires": { + "@finos/vuu-data-types": "0.0.26", "@finos/vuu-filter-types": "0.0.26", "@finos/vuu-protocol-types": "0.0.26", "@finos/vuu-table-types": "0.0.26" @@ -13714,48 +14400,32 @@ "integrity": "sha512-7Lcn7IqGMV+vizMPoEl5F0XDshcdDYtMI6uJLQdQz5CfZAwy3vvGKYSUk789qndt5dEC4HfSjviSYlSoHGL2+A==" }, "@salt-ds/core": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/@salt-ds/core/-/core-1.8.0.tgz", - "integrity": "sha512-Na8/PEQdb93i6UvYeIn6PhLqjF3k7EbAI+/4zkHO/XeqCBGkRxK3EMibEPkw4Zwfw5PQZbDKgPxknW53aWP0AA==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@salt-ds/core/-/core-1.13.2.tgz", + "integrity": "sha512-dBw4QErYpNgfj0wL2kKeZtdoiRXS6ZFgXHSh37yBHrP/QIqFNmhwCAWGR84OgNgetU6FhKvKSSgknwyHAK0fcg==", "requires": { "@floating-ui/react": "^0.23.0", - "@salt-ds/icons": "^1.6.0", - "@salt-ds/styles": "^0.1.1", + "@salt-ds/icons": "^1.9.0", + "@salt-ds/styles": "^0.2.0", "@salt-ds/window": "^0.1.1", "clsx": "^2.0.0" }, "dependencies": { "@salt-ds/icons": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@salt-ds/icons/-/icons-1.6.0.tgz", - "integrity": "sha512-/9c1L5LyU5cPxaYDyywDu8VnpvOvnaDmuLr/BWLEdyzxSzXTDfcIPtSgpaSaPadubvnnE9mhXdNknLyTqjNXZg==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@salt-ds/icons/-/icons-1.9.0.tgz", + "integrity": "sha512-82PnI/9KStt/owSTV/+vxH5AkJaYDEKuJrBbzeC2axxipv8ydbToTaCn6usLOSTm9CQ04rzMFPNcWQSpGUHtjA==", "requires": { - "@salt-ds/styles": "^0.1.1", + "@salt-ds/styles": "^0.2.0", "@salt-ds/window": "^0.1.1", "clsx": "^2.0.0" } }, - "clsx": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz", - "integrity": "sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==" - } - } - }, - "@salt-ds/icons": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/@salt-ds/icons/-/icons-1.5.1.tgz", - "integrity": "sha512-yBWRk3hcmYKrPTPQTvJsg4K3TBIvtoznaVIeYj8Gg6zy14s4gUN9N4PH9xix0pNgyCFGgluHUTiUKG6AcyGVkA==", - "requires": { - "@salt-ds/styles": "^0.1.1", - "@salt-ds/window": "^0.1.1", - "clsx": "^2.0.0" - }, - "dependencies": { - "clsx": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz", - "integrity": "sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==" + "@salt-ds/styles": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@salt-ds/styles/-/styles-0.2.0.tgz", + "integrity": "sha512-tPd/XK1PFkPkBsYwh4fhDbo997eaev6row9aaz/sPM0FpEpU8nbvQRhxtr8iA/S4Q5hCj0xrk/jGTuK40V13oQ==", + "requires": {} } } }, @@ -13793,11 +14463,6 @@ "@salt-ds/window": "^0.1.1", "clsx": "^2.0.0" } - }, - "clsx": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz", - "integrity": "sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==" } } }, @@ -14522,6 +15187,12 @@ } } }, + "@zeit/schemas": { + "version": "2.29.0", + "resolved": "https://registry.npmjs.org/@zeit/schemas/-/schemas-2.29.0.tgz", + "integrity": "sha512-g5QiLIfbg3pLuYUJPlisNKY+epQJTcMDsOnVNkscrDP1oi7vmJnzOANYJI/1pZcVJ6umUkBv3aFtlg1UvUHGzA==", + "dev": true + }, "abab": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", @@ -14530,6 +15201,16 @@ "optional": true, "peer": true }, + "accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dev": true, + "requires": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + } + }, "acorn": { "version": "8.10.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", @@ -14579,6 +15260,15 @@ "uri-js": "^4.2.2" } }, + "ansi-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "dev": true, + "requires": { + "string-width": "^4.1.0" + } + }, "ansi-colors": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", @@ -14616,9 +15306,9 @@ "@finos/vuu-table-types": "0.0.26", "@finos/vuu-utils": "0.0.26", "@fontsource/open-sans": "^4.5.13", - "@salt-ds/core": "1.8.0", + "@salt-ds/core": "1.13.2", "@salt-ds/lab": "1.0.0-alpha.15", - "classnames": "^2.3.1", + "clsx": "^2.0.0", "react": ">=17.0.2", "react-dom": ">=17.0.2" } @@ -14629,6 +15319,12 @@ "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==", "dev": true }, + "arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "dev": true + }, "argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -14843,18 +15539,97 @@ "tweetnacl": "^0.14.3" } }, - "blob-util": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/blob-util/-/blob-util-2.0.2.tgz", - "integrity": "sha512-T7JQa+zsXXEa6/8ZhHcQEW1UFfVM49Ts65uBkFL6fz2QmrElqmbajIDJvuA0tEhRe5eIjpV9ZF+0RfZR9voJFQ==", - "dev": true - }, - "bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", - "dev": true - }, + "blob-util": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/blob-util/-/blob-util-2.0.2.tgz", + "integrity": "sha512-T7JQa+zsXXEa6/8ZhHcQEW1UFfVM49Ts65uBkFL6fz2QmrElqmbajIDJvuA0tEhRe5eIjpV9ZF+0RfZR9voJFQ==", + "dev": true + }, + "bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true + }, + "boxen": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-7.0.0.tgz", + "integrity": "sha512-j//dBVuyacJbvW+tvZ9HuH03fZ46QcaKvvhZickZqtB271DxJ7SNRSNxrV/dZX0085m7hISRZWbzWlJvx/rHSg==", + "dev": true, + "requires": { + "ansi-align": "^3.0.1", + "camelcase": "^7.0.0", + "chalk": "^5.0.1", + "cli-boxes": "^3.0.0", + "string-width": "^5.1.2", + "type-fest": "^2.13.0", + "widest-line": "^4.0.1", + "wrap-ansi": "^8.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true + }, + "ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true + }, + "camelcase": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-7.0.1.tgz", + "integrity": "sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==", + "dev": true + }, + "emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "requires": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + } + }, + "strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "requires": { + "ansi-regex": "^6.0.1" + } + }, + "type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "dev": true + }, + "wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "requires": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + } + } + } + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -14900,6 +15675,12 @@ "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", "dev": true }, + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "dev": true + }, "cac": { "version": "6.7.14", "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", @@ -14992,6 +15773,60 @@ "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", "dev": true }, + "chalk-template": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/chalk-template/-/chalk-template-0.4.0.tgz", + "integrity": "sha512-/ghrgmhfY8RaSdeo43hNXxpoHAtxdbskUHjPpfqUWGttFgycUhYPGx3YZBCnUCvOa7Doivn1IZec3DEGFoMgLg==", + "dev": true, + "requires": { + "chalk": "^4.1.2" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, "character-entities": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", @@ -15037,17 +15872,18 @@ "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", "dev": true }, - "classnames": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz", - "integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==" - }, "clean-stack": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", "dev": true }, + "cli-boxes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz", + "integrity": "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==", + "dev": true + }, "cli-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", @@ -15082,6 +15918,48 @@ "resolved": "https://registry.npmjs.org/clipboard-copy/-/clipboard-copy-4.0.1.tgz", "integrity": "sha512-wOlqdqziE/NNTUJsfSgXmBMIrYmfd5V0HCGsR8uAKHcg+h9NENWINcfRjtWGU77wDHC8B8ijV4hMTGYbrKovng==" }, + "clipboardy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/clipboardy/-/clipboardy-3.0.0.tgz", + "integrity": "sha512-Su+uU5sr1jkUy1sGRpLKjKrvEOVXgSgiSInwa/qeID6aJ07yh+5NWc3h2QfjHjBnfX4LhtFcuAWKUsJ3r+fjbg==", + "dev": true, + "requires": { + "arch": "^2.2.0", + "execa": "^5.1.1", + "is-wsl": "^2.2.0" + }, + "dependencies": { + "execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + } + }, + "get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true + }, + "human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true + } + } + }, "cliui": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", @@ -15094,9 +15972,9 @@ } }, "clsx": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", - "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz", + "integrity": "sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==" }, "color-convert": { "version": "1.9.3", @@ -15152,6 +16030,53 @@ "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==", "dev": true }, + "compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dev": true, + "requires": { + "mime-db": ">= 1.43.0 < 2" + } + }, + "compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dev": true, + "requires": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + } + } + }, "compute-scroll-into-view": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-3.0.3.tgz", @@ -15162,6 +16087,12 @@ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, + "content-disposition": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "integrity": "sha512-kRGRZw3bLlFISDBgwTSA1TMBFN6J6GWDeubmDE3AF+3+yXL8hTWv8r5rkLbqYXY4RjPk/EzHnClI3zQf1cFmHA==", + "dev": true + }, "convert-source-map": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", @@ -15504,6 +16435,12 @@ "which-typed-array": "^1.1.9" } }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true + }, "deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -15586,6 +16523,12 @@ "webidl-conversions": "^7.0.0" } }, + "eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, "ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", @@ -16200,6 +17143,23 @@ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==" }, + "fast-url-parser": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/fast-url-parser/-/fast-url-parser-1.1.3.tgz", + "integrity": "sha512-5jOCVXADYNuRkKFzNJ0dCCewsZiYo0dz8QNYljkOpFC6r2U4OBmKtvm/Tsuh4w1YYdDqDb31a8TVhBJ2OJKdqQ==", + "dev": true, + "requires": { + "punycode": "^1.3.2" + }, + "dependencies": { + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", + "dev": true + } + } + }, "fastest-levenshtein": { "version": "1.0.16", "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", @@ -16228,6 +17188,7 @@ "requires": { "@finos/vuu-data": "0.0.26", "@finos/vuu-data-react": "0.0.26", + "@finos/vuu-data-types": "0.0.26", "@finos/vuu-filter-types": "0.0.26", "@finos/vuu-filters": "0.0.26", "@finos/vuu-layout": "0.0.26", @@ -16239,7 +17200,7 @@ "@finos/vuu-table-types": "0.0.26", "@finos/vuu-theme": "0.0.26", "@finos/vuu-utils": "0.0.26", - "@salt-ds/core": "1.8.0", + "@salt-ds/core": "1.13.2", "@salt-ds/lab": "1.0.0-alpha.15" } }, @@ -16259,7 +17220,7 @@ "@finos/vuu-table-types": "0.0.26", "@finos/vuu-theme": "0.0.26", "@finos/vuu-utils": "0.0.26", - "@salt-ds/core": "1.8.0", + "@salt-ds/core": "1.13.2", "@salt-ds/lab": "1.0.0-alpha.15" } }, @@ -16279,7 +17240,7 @@ "@finos/vuu-table-types": "0.0.26", "@finos/vuu-theme": "0.0.26", "@finos/vuu-utils": "0.0.26", - "@salt-ds/core": "1.8.0", + "@salt-ds/core": "1.13.2", "@salt-ds/lab": "1.0.0-alpha.15" } }, @@ -16299,7 +17260,7 @@ "@finos/vuu-table-types": "0.0.26", "@finos/vuu-theme": "0.0.26", "@finos/vuu-utils": "0.0.26", - "@salt-ds/core": "1.8.0", + "@salt-ds/core": "1.13.2", "@salt-ds/lab": "1.0.0-alpha.15" } }, @@ -17115,6 +18076,12 @@ "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", "dev": true }, + "is-port-reachable": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-port-reachable/-/is-port-reachable-4.0.0.tgz", + "integrity": "sha512-9UoipoxYmSk6Xy7QFgRv2HDyaysmgSG75TFQs6S+3pDM7ZhKTF/bskZV+0UlABHzKjNVhPjYCLfeZUEg1wXxig==", + "dev": true + }, "is-potential-custom-element-name": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", @@ -18399,6 +19366,12 @@ "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", "dev": true }, + "negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true + }, "no-scroll": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/no-scroll/-/no-scroll-2.1.1.tgz", @@ -18544,6 +19517,12 @@ "es-abstract": "^1.20.4" } }, + "on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "dev": true + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -18671,6 +19650,12 @@ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" }, + "path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==", + "dev": true + }, "path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -18682,6 +19667,12 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, + "path-to-regexp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-2.2.1.tgz", + "integrity": "sha512-gu9bD6Ta5bwGrrU8muHzVOBFFREpp2iRkVfhBJahwJ6p6Xw20SjT0MxLnwkjOibQmGSYhiUnf2FLe7k+jcFmGQ==", + "dev": true + }, "path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -18903,6 +19894,38 @@ "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", "dev": true }, + "range-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", + "integrity": "sha512-kA5WQoNVo4t9lNx2kQNFCxKeBl5IbbSNBl1M/tLkw9WCn+hxNBAW5Qh8gdhs63CJnhjJ2zQWFoqPJP2sK1AV5A==", + "dev": true + }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "dev": true + } + } + }, "react": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", @@ -19020,12 +20043,6 @@ } } }, - "recoil": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/recoil/-/recoil-0.1.3.tgz", - "integrity": "sha512-/Rm7wN7jqCjhtFK1TgtK0V115SUXNu6d4QYvwxWNLydib0QChSmpB6U8CaHoRPS0MFWtAIsD/IFjpbfk/OYm7Q==", - "requires": {} - }, "redent": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/redent/-/redent-4.0.0.tgz", @@ -19060,6 +20077,25 @@ "functions-have-names": "^1.2.3" } }, + "registry-auth-token": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.3.2.tgz", + "integrity": "sha512-JL39c60XlzCVgNrO+qq68FoNb56w/m7JYvGR2jT5iR1xBrUA3Mfx5Twk5rqTThPmQKMWydGmq8oFtDlxfrmxnQ==", + "dev": true, + "requires": { + "rc": "^1.1.6", + "safe-buffer": "^5.0.1" + } + }, + "registry-url": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-3.1.0.tgz", + "integrity": "sha512-ZbgR5aZEdf4UKZVBPYIgaglBmSF2Hi94s2PcIHhRGFjKYu+chjJdYfHn4rt3hB6eCKLJ8giVIIfgMa1ehDfZKA==", + "dev": true, + "requires": { + "rc": "^1.0.1" + } + }, "remark-mdx": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/remark-mdx/-/remark-mdx-2.3.0.tgz", @@ -19300,6 +20336,84 @@ } } }, + "serve": { + "version": "14.2.1", + "resolved": "https://registry.npmjs.org/serve/-/serve-14.2.1.tgz", + "integrity": "sha512-48er5fzHh7GCShLnNyPBRPEjs2I6QBozeGr02gaacROiyS/8ARADlj595j39iZXAqBbJHH/ivJJyPRWY9sQWZA==", + "dev": true, + "requires": { + "@zeit/schemas": "2.29.0", + "ajv": "8.11.0", + "arg": "5.0.2", + "boxen": "7.0.0", + "chalk": "5.0.1", + "chalk-template": "0.4.0", + "clipboardy": "3.0.0", + "compression": "1.7.4", + "is-port-reachable": "4.0.0", + "serve-handler": "6.1.5", + "update-check": "1.5.4" + }, + "dependencies": { + "ajv": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "chalk": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.0.1.tgz", + "integrity": "sha512-Fo07WOYGqMfCWHOzSXOt2CxDbC6skS/jO9ynEcmpANMoPrD+W1r1K6Vx7iNm+AQmETU1Xr2t+n8nzkV9t6xh3w==", + "dev": true + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + } + } + }, + "serve-handler": { + "version": "6.1.5", + "resolved": "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.5.tgz", + "integrity": "sha512-ijPFle6Hwe8zfmBxJdE+5fta53fdIY0lHISJvuikXB3VYFafRjMRpOffSPvCYsbKyBA7pvy9oYr/BT1O3EArlg==", + "dev": true, + "requires": { + "bytes": "3.0.0", + "content-disposition": "0.5.2", + "fast-url-parser": "1.1.3", + "mime-types": "2.1.18", + "minimatch": "3.1.2", + "path-is-inside": "1.0.2", + "path-to-regexp": "2.2.1", + "range-parser": "1.2.0" + }, + "dependencies": { + "mime-db": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", + "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==", + "dev": true + }, + "mime-types": { + "version": "2.1.18", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", + "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", + "dev": true, + "requires": { + "mime-db": "~1.33.0" + } + } + } + }, "shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -19451,6 +20565,16 @@ "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", "dev": true }, + "standalone-table": { + "version": "file:sample-apps/standalone-table", + "requires": { + "@finos/vuu-table": "0.0.26", + "@fontsource/open-sans": "^4.5.13", + "clsx": "^2.0.0", + "react": ">=17.0.2", + "react-dom": ">=17.0.2" + } + }, "std-env": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.3.3.tgz", @@ -20137,6 +21261,16 @@ "picocolors": "^1.0.0" } }, + "update-check": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/update-check/-/update-check-1.5.4.tgz", + "integrity": "sha512-5YHsflzHP4t1G+8WGPlvKbJEbAJGCgw+Em+dGR1KmBUbr1J36SJBqlHLjR7oob7sco5hWHGQVcr9B2poIVDDTQ==", + "dev": true, + "requires": { + "registry-auth-token": "3.3.2", + "registry-url": "3.1.0" + } + }, "uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -20189,6 +21323,12 @@ "spdx-expression-parse": "^3.0.0" } }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "dev": true + }, "verror": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", @@ -20588,6 +21728,49 @@ "stackback": "0.0.2" } }, + "widest-line": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-4.0.1.tgz", + "integrity": "sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==", + "dev": true, + "requires": { + "string-width": "^5.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true + }, + "emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "requires": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + } + }, + "strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "requires": { + "ansi-regex": "^6.0.1" + } + } + } + }, "wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", diff --git a/vuu-ui/package.json b/vuu-ui/package.json index 6511b5ef5..163e04a49 100644 --- a/vuu-ui/package.json +++ b/vuu-ui/package.json @@ -19,10 +19,12 @@ "format": "prettier --write './**/*.{js,,mjs,jsx,css,md,json}' --config ./.prettierrc", "build": "node ./scripts/build-all.mjs", "build:app": "cd sample-apps/app-vuu-example && node scripts/build.mjs", + "build:table": "cd sample-apps/standalone-table && node scripts/build.mjs", "build:packages": "npm run build -- --cjs --license && npm run type-defs", "build:packages:debug": "npm run build -- --cjs --debug && npm run type-defs -- --debug", "build:salt": "node ./scripts/build-salt.mjs", "launch:demo": "node ./scripts/launch-app.mjs", + "launch:table": "node ./scripts/launch-table.mjs", "launch:demo:electron": "cd tools/electron && node ./node_modules/.bin/electron .", "launch:showcase": " cd showcase && node scripts/launch.mjs", "deploy:websocket-test": "node ./tools/deploy-websocket-test.mjs", @@ -41,17 +43,16 @@ "typecheck": "tsc --noEmit --project tsconfig-typecheck.json" }, "dependencies": { + "@salt-ds/core": "1.13.2", "@types/jest": "^26.0.20", "@types/node": "^14.14.35", "@types/react": "^17.0.2", "@types/react-dom": "^17.0.2", "@typescript-eslint/parser": "^5.41.0", - "classnames": "^2.3.1", - "clsx": "^1.2.1", + "clsx": "^2.0.0", "html-to-image": "^1.11.11", "react": "^17.0.2", "react-dom": "^17.0.2", - "recoil": "^0.1.3", "semver": "^7.5.2" }, "devDependencies": { @@ -78,6 +79,7 @@ "happy-dom": "^10.10.0", "open": "^8.4.0", "prettier": "2.8.4", + "serve": "^14.2.1", "stylelint": "^15.0.0", "tinycolor2": "1.4.2", "typescript": "4.9.5", diff --git a/vuu-ui/packages/vuu-data-ag-grid/src/ViewportRowModelDataSource.ts b/vuu-ui/packages/vuu-data-ag-grid/src/ViewportRowModelDataSource.ts index 3bb7f2c4a..decca8b38 100644 --- a/vuu-ui/packages/vuu-data-ag-grid/src/ViewportRowModelDataSource.ts +++ b/vuu-ui/packages/vuu-data-ag-grid/src/ViewportRowModelDataSource.ts @@ -1,16 +1,17 @@ import { DataSource, DataSourceConfig, - isVuuFeatureAction, SubscribeCallback, VuuFeatureMessage, -} from "@finos/vuu-data"; +} from "@finos/vuu-data-types"; +import {} from "@finos/vuu-data-remote"; import { Filter } from "@finos/vuu-filter-types"; import { VuuGroupBy, VuuSort } from "@finos/vuu-protocol-types"; import { buildColumnMap, ColumnMap, itemsOrOrderChanged, + isVuuFeatureAction, metadataKeys, } from "@finos/vuu-utils"; import { AgDataWindow } from "./AgDataWindow"; diff --git a/vuu-ui/packages/vuu-data-ag-grid/src/useViewportRowModel.ts b/vuu-ui/packages/vuu-data-ag-grid/src/useViewportRowModel.ts index 36fd4f937..b9a121599 100644 --- a/vuu-ui/packages/vuu-data-ag-grid/src/useViewportRowModel.ts +++ b/vuu-ui/packages/vuu-data-ag-grid/src/useViewportRowModel.ts @@ -1,15 +1,3 @@ -import { - DataSourceConfig, - isViewportMenusAction, - isVisualLinksAction, - MenuRpcResponse, - RemoteDataSource, - RpcResponseHandler, - VuuFeatureMessage, - VuuUIMessageInRPCEditReject, - VuuUIMessageInRPCEditResponse, -} from "@finos/vuu-data"; - import { MenuActionConfig, SuggestionFetcher, @@ -18,10 +6,17 @@ import { VuuMenuActionHandler, VuuServerMenuOptions, } from "@finos/vuu-data-react"; +import { VuuDataSource } from "@finos/vuu-data-remote"; -import { ColumnDescriptor } from "@finos/vuu-table-types"; +import { RpcResponseHandler, VuuFeatureMessage } from "@finos/vuu-data-types"; import { VuuGroupBy, VuuMenu, VuuTable } from "@finos/vuu-protocol-types"; -import { buildColumnMap, itemsOrOrderChanged } from "@finos/vuu-utils"; +import { ColumnDescriptor } from "@finos/vuu-table-types"; +import { + buildColumnMap, + isViewportMenusAction, + isVisualLinksAction, + itemsOrOrderChanged, +} from "@finos/vuu-utils"; import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { AgData } from "./AgDataWindow"; import { @@ -91,7 +86,7 @@ export const agSortChangedEventToVuuSortDef = (evt: AgSortChangedEvent) => { export interface ViewportRowModelHookProps { columns?: ColumnDescriptor[]; - dataSource: RemoteDataSource; + dataSource: VuuDataSource; onFeatureEnabled?: (message: VuuFeatureMessage) => void; onRpcResponse?: RpcResponseHandler; vuuMenuActionHandler?: VuuMenuActionHandler; @@ -101,9 +96,8 @@ type GroupByConfigChange = { groupBy: VuuGroupBy; }; -const hasGroupByChange = ( - message?: Partial -): message is GroupByConfigChange => Array.isArray(message?.groupBy); +const hasGroupByChange = (message?: unknown): message is GroupByConfigChange => + Array.isArray((message as GroupByConfigChange).groupBy); export const useViewportRowModel = ({ columns, diff --git a/vuu-ui/packages/vuu-data-local/package.json b/vuu-ui/packages/vuu-data-local/package.json new file mode 100644 index 000000000..9bf3e826d --- /dev/null +++ b/vuu-ui/packages/vuu-data-local/package.json @@ -0,0 +1,21 @@ +{ + "name": "@finos/vuu-data-local", + "version": "0.0.26", + "main": "src/index.ts", + "author": "heswell", + "license": "Apache-2.0", + "scripts": { + "build": "node ../../scripts/run-build.mjs", + "test": "vitest run", + "type-defs": "node ../../scripts/build-type-defs.mjs" + }, + "devDependencies": { + "@finos/vuu-data-types": "0.0.26", + "@finos/vuu-table-types": "0.0.26", + "@finos/vuu-filter-types": "0.0.26", + "@finos/vuu-protocol-types": "0.0.26" + }, + "dependencies": { + "@finos/vuu-utils": "0.0.26" + } +} diff --git a/vuu-ui/packages/vuu-data/src/array-data-source/aggregate-utils.ts b/vuu-ui/packages/vuu-data-local/src/array-data-source/aggregate-utils.ts similarity index 100% rename from vuu-ui/packages/vuu-data/src/array-data-source/aggregate-utils.ts rename to vuu-ui/packages/vuu-data-local/src/array-data-source/aggregate-utils.ts diff --git a/vuu-ui/packages/vuu-data/src/array-data-source/array-data-source.ts b/vuu-ui/packages/vuu-data-local/src/array-data-source/array-data-source.ts similarity index 98% rename from vuu-ui/packages/vuu-data/src/array-data-source/array-data-source.ts rename to vuu-ui/packages/vuu-data-local/src/array-data-source/array-data-source.ts index 32db5b321..7ff25ff35 100644 --- a/vuu-ui/packages/vuu-data/src/array-data-source/array-data-source.ts +++ b/vuu-ui/packages/vuu-data-local/src/array-data-source/array-data-source.ts @@ -1,5 +1,20 @@ -import { DataSourceFilter, DataSourceRow } from "@finos/vuu-data-types"; -import { ColumnDescriptor, Selection } from "@finos/vuu-table-types"; +import { + DataSource, + DataSourceConfig, + DataSourceConstructorProps, + DataSourceEvents, + DataSourceFilter, + DataSourceRow, + DataSourceStatus, + MenuRpcResponse, + Selection, + SubscribeCallback, + SubscribeProps, + TableSchema, + VuuUIMessageInRPCEditReject, + VuuUIMessageInRPCEditResponse, + WithFullConfig, +} from "@finos/vuu-data-types"; import { filterPredicate, parseFilter } from "@finos/vuu-filter-parser"; import { ClientToServerEditRpc, @@ -12,12 +27,18 @@ import { VuuRowDataItemType, VuuSort, } from "@finos/vuu-protocol-types"; +import { ColumnDescriptor } from "@finos/vuu-table-types"; import { buildColumnMap, ColumnMap, + configChanged, EventEmitter, getAddedItems, getMissingItems, + groupByChanged, + hasFilter, + hasGroupBy, + hasSort, KeySet, logger, metadataKeys, @@ -25,34 +46,13 @@ import { rangeNewItems, resetRange, uuid, -} from "@finos/vuu-utils"; -import { - configChanged, - DataSource, - DataSourceConfig, - DataSourceConstructorProps, - DataSourceEvents, - DataSourceStatus, - groupByChanged, - hasFilter, - hasGroupBy, - hasSort, - SubscribeCallback, - SubscribeProps, vanillaConfig, withConfigDefaults, - WithFullConfig, -} from "../data-source"; -import { TableSchema } from "../message-utils"; -import { - MenuRpcResponse, - VuuUIMessageInRPCEditReject, - VuuUIMessageInRPCEditResponse, -} from "../vuuUIMessageTypes"; +} from "@finos/vuu-utils"; import { aggregateData } from "./aggregate-utils"; +import { buildDataToClientMap, toClientRow } from "./array-data-utils"; import { collapseGroup, expandGroup, GroupMap, groupRows } from "./group-utils"; import { sortRows } from "./sort-utils"; -import { buildDataToClientMap, toClientRow } from "./array-data-utils"; const { KEY } = metadataKeys; diff --git a/vuu-ui/packages/vuu-data/src/array-data-source/array-data-utils.ts b/vuu-ui/packages/vuu-data-local/src/array-data-source/array-data-utils.ts similarity index 94% rename from vuu-ui/packages/vuu-data/src/array-data-source/array-data-utils.ts rename to vuu-ui/packages/vuu-data-local/src/array-data-source/array-data-utils.ts index f38c81ff1..894b785b4 100644 --- a/vuu-ui/packages/vuu-data/src/array-data-source/array-data-utils.ts +++ b/vuu-ui/packages/vuu-data-local/src/array-data-source/array-data-utils.ts @@ -1,5 +1,4 @@ -import { DataSourceRow } from "@finos/vuu-data-types"; -import { Selection } from "@finos/vuu-table-types"; +import { DataSourceRow, Selection } from "@finos/vuu-data-types"; import { ColumnMap, getSelectionStatus, diff --git a/vuu-ui/packages/vuu-data/src/array-data-source/group-utils.ts b/vuu-ui/packages/vuu-data-local/src/array-data-source/group-utils.ts similarity index 100% rename from vuu-ui/packages/vuu-data/src/array-data-source/group-utils.ts rename to vuu-ui/packages/vuu-data-local/src/array-data-source/group-utils.ts diff --git a/vuu-ui/packages/vuu-data/src/array-data-source/sort-utils.ts b/vuu-ui/packages/vuu-data-local/src/array-data-source/sort-utils.ts similarity index 100% rename from vuu-ui/packages/vuu-data/src/array-data-source/sort-utils.ts rename to vuu-ui/packages/vuu-data-local/src/array-data-source/sort-utils.ts diff --git a/vuu-ui/packages/vuu-data-local/src/index.ts b/vuu-ui/packages/vuu-data-local/src/index.ts new file mode 100644 index 000000000..59509f61a --- /dev/null +++ b/vuu-ui/packages/vuu-data-local/src/index.ts @@ -0,0 +1,2 @@ +export * from "./array-data-source/array-data-source"; +export * from "./json-data-source/json-data-source"; diff --git a/vuu-ui/packages/vuu-data/src/json-data-source.ts b/vuu-ui/packages/vuu-data-local/src/json-data-source/json-data-source.ts similarity index 97% rename from vuu-ui/packages/vuu-data/src/json-data-source.ts rename to vuu-ui/packages/vuu-data-local/src/json-data-source/json-data-source.ts index 2ecd2d5c2..52ae71db8 100644 --- a/vuu-ui/packages/vuu-data/src/json-data-source.ts +++ b/vuu-ui/packages/vuu-data-local/src/json-data-source/json-data-source.ts @@ -1,4 +1,4 @@ -import { ColumnDescriptor, Selection } from "@finos/vuu-table-types"; +import { ColumnDescriptor } from "@finos/vuu-table-types"; import { LinkDescriptorWithLabel, VuuGroupBy, @@ -9,17 +9,9 @@ import { ClientToServerEditRpc, VuuRowDataItemType, } from "@finos/vuu-protocol-types"; -import { DataSourceFilter, DataSourceRow } from "@finos/vuu-data-types"; import { - EventEmitter, - isSelected, - JsonData, - jsonToDataSourceRows, - KeySet, - metadataKeys, - uuid, -} from "@finos/vuu-utils"; -import type { + DataSourceFilter, + DataSourceRow, DataSource, DataSourceConstructorProps, DataSourceEvents, @@ -27,13 +19,21 @@ import type { SubscribeCallback, SubscribeProps, WithFullConfig, -} from "./data-source"; -import { vanillaConfig } from "./data-source"; -import { + Selection, MenuRpcResponse, VuuUIMessageInRPCEditReject, VuuUIMessageInRPCEditResponse, -} from "./vuuUIMessageTypes"; +} from "@finos/vuu-data-types"; +import { + EventEmitter, + isSelected, + JsonData, + jsonToDataSourceRows, + KeySet, + metadataKeys, + uuid, + vanillaConfig, +} from "@finos/vuu-utils"; const NULL_SCHEMA = { columns: [], key: "", table: { module: "", table: "" } }; diff --git a/vuu-ui/packages/vuu-data/tsconfig.json b/vuu-ui/packages/vuu-data-local/tsconfig.json similarity index 100% rename from vuu-ui/packages/vuu-data/tsconfig.json rename to vuu-ui/packages/vuu-data-local/tsconfig.json diff --git a/vuu-ui/packages/vuu-data-react/src/hooks/useDataSource.ts b/vuu-ui/packages/vuu-data-react/src/hooks/useDataSource.ts index bba3b6fb9..80a067a81 100644 --- a/vuu-ui/packages/vuu-data-react/src/hooks/useDataSource.ts +++ b/vuu-ui/packages/vuu-data-react/src/hooks/useDataSource.ts @@ -1,6 +1,9 @@ // TODO is this hook needed ? it is currently used only in a vuu salt story -import { DataSource, SubscribeCallback } from "@finos/vuu-data"; -import { DataSourceRow } from "@finos/vuu-data-types"; +import { + DataSource, + DataSourceRow, + SubscribeCallback, +} from "@finos/vuu-data-types"; import { VuuRange } from "@finos/vuu-protocol-types"; import { getFullRange, metadataKeys, WindowRange } from "@finos/vuu-utils"; import { useCallback, useEffect, useMemo, useRef, useState } from "react"; diff --git a/vuu-ui/packages/vuu-data-react/src/hooks/useLookupValues.ts b/vuu-ui/packages/vuu-data-react/src/hooks/useLookupValues.ts index 750535edc..863e9d2b3 100644 --- a/vuu-ui/packages/vuu-data-react/src/hooks/useLookupValues.ts +++ b/vuu-ui/packages/vuu-data-react/src/hooks/useLookupValues.ts @@ -3,7 +3,7 @@ import { ListOption, LookupTableDetails, } from "@finos/vuu-table-types"; -import { RemoteDataSource } from "@finos/vuu-data"; +import { VuuDataSource } from "@finos/vuu-data-remote"; import { useShellContext } from "@finos/vuu-shell"; import { buildColumnMap, @@ -29,7 +29,7 @@ const loadLookupValues = ({ const promise: Promise = new Promise((resolve) => { const columns = [valueColumn, labelColumn]; const columnMap = buildColumnMap(columns); - const dataSource = new RemoteDataSource({ + const dataSource = new VuuDataSource({ bufferSize: 0, table, }); diff --git a/vuu-ui/packages/vuu-data-react/src/hooks/useServerConnectionQuality.ts b/vuu-ui/packages/vuu-data-react/src/hooks/useServerConnectionQuality.ts index e6b985910..052a9926e 100644 --- a/vuu-ui/packages/vuu-data-react/src/hooks/useServerConnectionQuality.ts +++ b/vuu-ui/packages/vuu-data-react/src/hooks/useServerConnectionQuality.ts @@ -1,5 +1,5 @@ import { useCallback, useEffect, useState } from "react"; -import { ConnectionManager } from "@finos/vuu-data"; +import { ConnectionManager } from "@finos/vuu-data-remote"; export const useServerConnectionQuality = () => { const [messagesPerSecond, setMessagesPerSecond] = useState(0); diff --git a/vuu-ui/packages/vuu-data-react/src/hooks/useServerConnectionStatus.ts b/vuu-ui/packages/vuu-data-react/src/hooks/useServerConnectionStatus.ts index 7654d9393..6f80c0862 100644 --- a/vuu-ui/packages/vuu-data-react/src/hooks/useServerConnectionStatus.ts +++ b/vuu-ui/packages/vuu-data-react/src/hooks/useServerConnectionStatus.ts @@ -1,5 +1,6 @@ import { useCallback, useEffect, useState } from "react"; -import { ConnectionManager, ConnectionStatusMessage } from "@finos/vuu-data"; +import { ConnectionManager } from "@finos/vuu-data-remote"; +import { ConnectionStatusMessage } from "@finos/vuu-data-types"; export const useServerConnectionStatus = () => { const [connectionStatus, setConnectionStatus] = useState("disconnected"); diff --git a/vuu-ui/packages/vuu-data-react/src/hooks/useTypeaheadSuggestions.ts b/vuu-ui/packages/vuu-data-react/src/hooks/useTypeaheadSuggestions.ts index 69fa72802..1d673ca79 100644 --- a/vuu-ui/packages/vuu-data-react/src/hooks/useTypeaheadSuggestions.ts +++ b/vuu-ui/packages/vuu-data-react/src/hooks/useTypeaheadSuggestions.ts @@ -5,7 +5,7 @@ import { VuuTable, } from "@finos/vuu-protocol-types"; import { useCallback } from "react"; -import { makeRpcCall } from "@finos/vuu-data"; +import { makeRpcCall } from "@finos/vuu-data-remote"; export type SuggestionFetcher = (params: TypeaheadParams) => Promise; diff --git a/vuu-ui/packages/vuu-data-react/src/hooks/useVuuMenuActions.ts b/vuu-ui/packages/vuu-data-react/src/hooks/useVuuMenuActions.ts index 1c23861f1..3dfbc4c21 100644 --- a/vuu-ui/packages/vuu-data-react/src/hooks/useVuuMenuActions.ts +++ b/vuu-ui/packages/vuu-data-react/src/hooks/useVuuMenuActions.ts @@ -1,18 +1,17 @@ import { + ContextMenuItemDescriptor, DataSource, + DataSourceRow, DataSourceVisualLinkCreatedMessage, + MenuActionHandler, + MenuBuilder, MenuRpcResponse, ViewportRpcResponse, VuuUIMessageInRPCEditReject, VuuUIMessageInRPCEditResponse, -} from "@finos/vuu-data"; -import { - ContextMenuItemDescriptor, - DataSourceRow, - MenuActionHandler, - MenuBuilder, } from "@finos/vuu-data-types"; import { getFilterPredicate } from "@finos/vuu-filter-parser"; +import type { MenuActionClosePopup } from "@finos/vuu-popups"; import { ClientToServerMenuCellRPC, ClientToServerMenuRowRPC, @@ -29,7 +28,6 @@ import { isGroupMenuItemDescriptor, metadataKeys, } from "@finos/vuu-utils"; -import type { MenuActionClosePopup } from "@finos/vuu-popups"; import { useCallback } from "react"; export const addRowsFromInstruments = "addRowsFromInstruments"; diff --git a/vuu-ui/packages/vuu-data-react/src/hooks/useVuuTables.ts b/vuu-ui/packages/vuu-data-react/src/hooks/useVuuTables.ts index fa8f4c33f..b987e660a 100644 --- a/vuu-ui/packages/vuu-data-react/src/hooks/useVuuTables.ts +++ b/vuu-ui/packages/vuu-data-react/src/hooks/useVuuTables.ts @@ -1,6 +1,7 @@ -import { getServerAPI, TableSchema } from "@finos/vuu-data"; +import { getServerAPI } from "@finos/vuu-data-remote"; +import { TableSchema } from "@finos/vuu-data-types"; import { VuuTable } from "@finos/vuu-protocol-types"; -import { useCallback, useEffect, useMemo, useState } from "react"; +import { useCallback, useEffect, useState } from "react"; export const useVuuTables = () => { const [tables, setTables] = useState | undefined>(); diff --git a/vuu-ui/packages/vuu-data/README.md b/vuu-ui/packages/vuu-data-remote/README.md similarity index 100% rename from vuu-ui/packages/vuu-data/README.md rename to vuu-ui/packages/vuu-data-remote/README.md diff --git a/vuu-ui/packages/vuu-data/package.json b/vuu-ui/packages/vuu-data-remote/package.json similarity index 93% rename from vuu-ui/packages/vuu-data/package.json rename to vuu-ui/packages/vuu-data-remote/package.json index cea774552..7eadb0376 100644 --- a/vuu-ui/packages/vuu-data/package.json +++ b/vuu-ui/packages/vuu-data-remote/package.json @@ -1,5 +1,5 @@ { - "name": "@finos/vuu-data", + "name": "@finos/vuu-data-remote", "version": "0.0.26", "main": "src/index.ts", "author": "heswell", diff --git a/vuu-ui/packages/vuu-data/src/authenticate.ts b/vuu-ui/packages/vuu-data-remote/src/authenticate.ts similarity index 100% rename from vuu-ui/packages/vuu-data/src/authenticate.ts rename to vuu-ui/packages/vuu-data-remote/src/authenticate.ts diff --git a/vuu-ui/packages/vuu-data/src/connection-manager.ts b/vuu-ui/packages/vuu-data-remote/src/connection-manager.ts similarity index 97% rename from vuu-ui/packages/vuu-data/src/connection-manager.ts rename to vuu-ui/packages/vuu-data-remote/src/connection-manager.ts index 5448196c8..be52a03ff 100644 --- a/vuu-ui/packages/vuu-data/src/connection-manager.ts +++ b/vuu-ui/packages/vuu-data-remote/src/connection-manager.ts @@ -1,3 +1,15 @@ +import { + ConnectionStatusMessage, + DataSourceCallbackMessage, + ServerProxySubscribeMessage, + TableSchema, + VuuUIMessageIn, + VuuUIMessageInRPC, + VuuUIMessageInTableList, + VuuUIMessageInTableMeta, + VuuUIMessageOut, + WebSocketProtocol, +} from "@finos/vuu-data-types"; import { ClientToServerMenuRPC, ClientToServerTableList, @@ -10,32 +22,18 @@ import { import { EventEmitter, getLoggingConfigForWorker, - uuid, -} from "@finos/vuu-utils"; -import { - DataSourceCallbackMessage, - shouldMessageBeRoutedToDataSource as messageShouldBeRoutedToDataSource, -} from "./data-source"; -import * as Message from "./server-proxy/messages"; -import { - ConnectionStatusMessage, isConnectionQualityMetrics, isConnectionStatusMessage, isTableSchema, messageHasResult, - ServerProxySubscribeMessage, - VuuUIMessageIn, - VuuUIMessageInRPC, - VuuUIMessageInTableList, - VuuUIMessageInTableMeta, - VuuUIMessageOut, -} from "./vuuUIMessageTypes"; + uuid, +} from "@finos/vuu-utils"; +import { shouldMessageBeRoutedToDataSource as messageShouldBeRoutedToDataSource } from "./data-source"; +import * as Message from "./server-proxy/messages"; // Note: inlined-worker is a generated file, it must be built +import { ConnectionQualityMetrics } from "@finos/vuu-data-types"; import { workerSourceCode } from "./inlined-worker"; -import { ConnectionQualityMetrics } from "./vuuUIMessageTypes"; -import { WebSocketProtocol } from "./websocket-connection"; -import { TableSchema } from "./message-utils"; const workerBlob = new Blob([getLoggingConfigForWorker() + workerSourceCode], { type: "text/javascript", diff --git a/vuu-ui/packages/vuu-data/src/connectionTypes.ts b/vuu-ui/packages/vuu-data-remote/src/connectionTypes.ts similarity index 100% rename from vuu-ui/packages/vuu-data/src/connectionTypes.ts rename to vuu-ui/packages/vuu-data-remote/src/connectionTypes.ts diff --git a/vuu-ui/packages/vuu-data/src/constants.ts b/vuu-ui/packages/vuu-data-remote/src/constants.ts similarity index 100% rename from vuu-ui/packages/vuu-data/src/constants.ts rename to vuu-ui/packages/vuu-data-remote/src/constants.ts diff --git a/vuu-ui/packages/vuu-data-remote/src/data-source.ts b/vuu-ui/packages/vuu-data-remote/src/data-source.ts new file mode 100644 index 000000000..246b3846f --- /dev/null +++ b/vuu-ui/packages/vuu-data-remote/src/data-source.ts @@ -0,0 +1,86 @@ +import { + DataSourceCallbackMessage, + DataSourceConfig, + DataSourceConfigMessage, + DataSourceDataSizeMessage, +} from "@finos/vuu-data-types"; +import { + ServerToClientBody, + ServerToClientMenuSessionTableAction, + VuuTable, +} from "@finos/vuu-protocol-types"; + +export const isSizeOnly = ( + message: DataSourceCallbackMessage +): message is DataSourceDataSizeMessage => + message.type === "viewport-update" && message.mode === "size-only"; + +export const toDataSourceConfig = ( + message: DataSourceConfigMessage +): DataSourceConfig => { + switch (message.type) { + case "aggregate": + return { aggregations: message.aggregations }; + case "columns": + return { columns: message.columns }; + case "filter": + return { filter: message.filter }; + case "groupBy": + return { groupBy: message.groupBy }; + case "sort": + return { sort: message.sort }; + case "config": + return message.config; + } +}; + +const datasourceMessages = [ + "config", + "aggregate", + "viewport-update", + "columns", + "debounce-begin", + "disabled", + "enabled", + "filter", + "groupBy", + "vuu-link-created", + "vuu-link-removed", + "vuu-links", + "vuu-menu", + "sort", + "subscribed", +]; + +export const shouldMessageBeRoutedToDataSource = ( + message: unknown +): message is DataSourceCallbackMessage => { + const type = (message as DataSourceCallbackMessage).type; + return datasourceMessages.includes(type); +}; + +export const isDataSourceConfigMessage = ( + message: DataSourceCallbackMessage +): message is DataSourceConfigMessage => + ["config", "aggregate", "columns", "filter", "groupBy", "sort"].includes( + message.type + ); + +export const isSessionTableActionMessage = ( + messageBody: ServerToClientBody +): messageBody is ServerToClientMenuSessionTableAction => + messageBody.type === "VIEW_PORT_MENU_RESP" && + messageBody.action !== null && + isSessionTable(messageBody.action.table); + +export const isSessionTable = (table?: unknown) => { + if ( + table !== null && + typeof table === "object" && + "table" in table && + "module" in table + ) { + return (table as VuuTable).table.startsWith("session"); + } + return false; +}; diff --git a/vuu-ui/packages/vuu-data/src/index.ts b/vuu-ui/packages/vuu-data-remote/src/index.ts similarity index 56% rename from vuu-ui/packages/vuu-data/src/index.ts rename to vuu-ui/packages/vuu-data-remote/src/index.ts index cdd32b612..ee1570327 100644 --- a/vuu-ui/packages/vuu-data/src/index.ts +++ b/vuu-ui/packages/vuu-data-remote/src/index.ts @@ -4,7 +4,4 @@ export type { ServerAPI } from "./connection-manager"; export * from "./constants"; export * from "./data-source"; export * from "./message-utils"; -export * from "./array-data-source/array-data-source"; -export * from "./json-data-source"; -export * from "./remote-data-source"; -export * from "./vuuUIMessageTypes"; +export * from "./vuu-data-source"; diff --git a/vuu-ui/packages/vuu-data-remote/src/inlined-worker.js b/vuu-ui/packages/vuu-data-remote/src/inlined-worker.js new file mode 100644 index 000000000..87a6ac889 --- /dev/null +++ b/vuu-ui/packages/vuu-data-remote/src/inlined-worker.js @@ -0,0 +1,8 @@ +export const workerSourceCode = ` +var ie=(r,e,t)=>{if(!e.has(r))throw TypeError("Cannot "+t)};var m=(r,e,t)=>(ie(r,e,"read from private field"),t?t.call(r):e.get(r)),ae=(r,e,t)=>{if(e.has(r))throw TypeError("Cannot add the same private member more than once");e instanceof WeakSet?e.add(r):e.set(r,t)},ue=(r,e,t,s)=>(ie(r,e,"write to private field"),s?s.call(r,t):e.set(r,t),t);function le(r,e,t=[],s=[]){for(let n=0,o=r.length;n{var e,t;if(((e=globalThis.document)==null?void 0:e.cookie)!==void 0)return(t=globalThis.document.cookie.split("; ").find(s=>s.startsWith(\`\${r}=\`)))==null?void 0:t.split("=")[1]};function G({from:r,to:e},t=0,s=Number.MAX_SAFE_INTEGER){if(t===0)return sr>=e&&r=this.to||tr.type==="connection-status",de=r=>r.type==="connection-metrics";var ge=r=>"viewport"in r;var Qe=["error","warn","info","debug"],Ye=r=>typeof r=="string"&&Qe.includes(r),Ze="error",P=()=>{},Xe="error",{loggingLevel:L=Xe}=et(),b=r=>{let e=L==="debug",t=e||L==="info",s=t||L==="warn",n=s||L==="error",o=t?p=>console.info(\`[\${r}] \${p}\`):P,i=s?p=>console.warn(\`[\${r}] \${p}\`):P,u=e?p=>console.debug(\`[\${r}] \${p}\`):P;return{errorEnabled:n,error:n?p=>console.error(\`[\${r}] \${p}\`):P}};function et(){return typeof loggingSettings<"u"?loggingSettings:{loggingLevel:tt()}}function tt(){let r=ce("vuu-logging-level");return Ye(r)?r:Ze}var{debug:st,debugEnabled:nt}=b("range-monitor"),k=class{constructor(e){this.source=e;this.range={from:0,to:0};this.timestamp=0}isSet(){return this.timestamp!==0}set({from:e,to:t}){let{timestamp:s}=this;if(this.range.from=e,this.range.to=t,this.timestamp=performance.now(),s)nt&&st(\`<\${this.source}> [\${e}-\${t}], \${(this.timestamp-s).toFixed(0)} ms elapsed\`);else return 0}};var O=class{constructor(e){this.keys=new Map,this.free=[],this.nextKeyValue=0,this.reset(e)}next(){return this.free.length>0?this.free.pop():this.nextKeyValue++}reset({from:e,to:t}){this.keys.forEach((n,o)=>{(o=t)&&(this.free.push(n),this.keys.delete(o))});let s=t-e;this.keys.size+this.free.length>s&&(this.free.length=Math.max(0,s-this.keys.size));for(let n=e;nthis.keys.size&&(this.nextKeyValue=this.keys.size)}keyFor(e){let t=this.keys.get(e);if(t===void 0)throw console.log(\`key not found + keys: \${this.toDebugString()} + free : \${this.free.join(",")} + \`),Error(\`KeySet, no key found for rowIndex \${e}\`);return t}toDebugString(){return Array.from(this.keys.entries()).map((e,t)=>\`\${e}=>\${t}\`).join(",")}};var{SELECTED:\$t}=\$,w={False:0,True:1,First:2,Last:4};var rt=(r,e)=>e>=r[0]&&e<=r[1],ot=w.True+w.First+w.Last,it=w.True+w.First,at=w.True+w.Last,z=(r,e)=>{for(let t of r)if(typeof t=="number"){if(t===e)return ot}else if(rt(t,e))return e===t[0]?it:e===t[1]?at:w.True;return w.False};var fe=r=>{if(r.every(t=>typeof t=="number"))return r;let e=[];for(let t of r)if(typeof t=="number")e.push(t);else for(let s=t[0];s<=t[1];s++)e.push(s);return e};var he=r=>r.type==="VIEW_PORT_MENU_RESP"&&r.action!==null&&x(r.action.table),x=r=>r!==null&&typeof r=="object"&&"table"in r&&"module"in r?r.table.startsWith("session"):!1;var ut=["VIEW_PORT_MENUS_SELECT_RPC","VIEW_PORT_MENU_TABLE_RPC","VIEW_PORT_MENU_ROW_RPC","VIEW_PORT_MENU_CELL_RPC","VP_EDIT_CELL_RPC","VP_EDIT_ROW_RPC","VP_EDIT_ADD_ROW_RPC","VP_EDIT_DELETE_CELL_RPC","VP_EDIT_DELETE_ROW_RPC","VP_EDIT_SUBMIT_FORM_RPC"],me=r=>ut.includes(r.type),Ce=r=>r.type==="VIEW_PORT_RPC_CALL",A=({requestId:r,...e})=>[r,e],Re=r=>{let e=r.at(0);if(e.updateType==="SIZE"){if(r.length===1)return r;e=r.at(1)}let t=r.at(-1);return[e,t]},Se=r=>{let e={};for(let t of r)(e[t.viewPortId]||(e[t.viewPortId]=[])).push(t);return e};var H=({columns:r,dataTypes:e,key:t,table:s})=>({table:s,columns:r.map((n,o)=>({name:n,serverDataType:e[o]})),key:t});var Te="CHANGE_VP_SUCCESS";var be="CLOSE_TREE_NODE",Ee="CLOSE_TREE_SUCCESS";var we="CREATE_VP",Ve="DISABLE_VP",ve="DISABLE_VP_SUCCESS";var ye="ENABLE_VP",Me="ENABLE_VP_SUCCESS";var K="GET_VP_VISUAL_LINKS",_e="GET_VIEW_PORT_MENUS";var De="HB",Ie="HB_RESP",Pe="LOGIN",Le="OPEN_TREE_NODE",ke="OPEN_TREE_SUCCESS";var Oe="REMOVE_VP";var xe="SET_SELECTION_SUCCESS";var Ne=r=>{switch(r){case"TypeAheadRpcHandler":return"TYPEAHEAD";default:return"SIMUL"}};var Ue=[],R=b("array-backed-moving-window");function lt(r,e){if(!e||e.data.length!==r.data.length||e.sel!==r.sel)return!1;for(let t=0;t{var t;if((t=R.info)==null||t.call(R,\`setRowCount \${e}\`),e{let s=this.bufferSize*.25;return m(this,f).to-t0&&e-m(this,f).from0&&this.clientRange.from+this.rowsWithinRange===this.rowCount}outOfRange(e,t){let{from:s,to:n}=this.range;if(t=n)return!0}setAtIndex(e){let{rowIndex:t}=e,s=t-m(this,f).from;if(lt(e,this.internalData[s]))return!1;let n=this.isWithinClientRange(t);return(n||this.isWithinRange(t))&&(!this.internalData[s]&&n&&(this.rowsWithinRange+=1),this.internalData[s]=e),n}getAtIndex(e){return m(this,f).isWithin(e)&&this.internalData[e-m(this,f).from]!=null?this.internalData[e-m(this,f).from]:void 0}isWithinRange(e){return m(this,f).isWithin(e)}isWithinClientRange(e){return this.clientRange.isWithin(e)}setClientRange(e,t){var p;(p=R.debug)==null||p.call(R,\`setClientRange \${e} - \${t}\`);let s=this.clientRange.from,n=Math.min(this.clientRange.to,this.rowCount);if(e===s&&t===n)return[!1,Ue];let o=this.clientRange.copy();this.clientRange.from=e,this.clientRange.to=t,this.rowsWithinRange=0;for(let a=e;ao.to){let a=Math.max(e,o.to);i=this.internalData.slice(a-u,t-u)}else{let a=Math.min(o.from,t);i=this.internalData.slice(e-u,a-u)}return[this.bufferBreakout(e,t),i]}setRange(e,t){var s,n;if(e!==m(this,f).from||t!==m(this,f).to){(s=R.debug)==null||s.call(R,\`setRange \${e} - \${t}\`);let[o,i]=m(this,f).overlap(e,t),u=new Array(t-e);this.rowsWithinRange=0;for(let c=o;c=0;o--)if(e[o]!==void 0){n=e[o];break}return s&&n?[s.rowIndex,n.rowIndex]:[-1,-1]}};f=new WeakMap;var ct=[],{debug:h,debugEnabled:U,error:pt,info:d,infoEnabled:dt,warn:M}=b("viewport"),gt=({rowKey:r,updateType:e})=>e==="U"&&!r.startsWith("\$root"),W=[void 0,void 0],ft={count:0,mode:void 0,size:0,ts:0},q=class{constructor({aggregations:e,bufferSize:t=50,columns:s,filter:n,groupBy:o=[],table:i,range:u,sort:c,title:p,viewport:a,visualLink:l},g){this.batchMode=!0;this.hasUpdates=!1;this.pendingUpdates=[];this.pendingOperations=new Map;this.pendingRangeRequests=[];this.rowCountChanged=!1;this.selectedRows=[];this.useBatchMode=!0;this.lastUpdateStatus=ft;this.updateThrottleTimer=void 0;this.rangeMonitor=new k("ViewPort");this.disabled=!1;this.isTree=!1;this.status="";this.suspended=!1;this.suspendTimer=null;this.setLastSizeOnlyUpdateSize=e=>{this.lastUpdateStatus.size=e};this.setLastUpdate=e=>{let{ts:t,mode:s}=this.lastUpdateStatus,n=0;if(s===e){let o=Date.now();this.lastUpdateStatus.count+=1,this.lastUpdateStatus.ts=o,n=t===0?0:o-t}else this.lastUpdateStatus.count=1,this.lastUpdateStatus.ts=0,n=0;return this.lastUpdateStatus.mode=e,n};this.rangeRequestAlreadyPending=e=>{let{bufferSize:t}=this,s=t*.25,{from:n}=e;for(let{from:o,to:i}of this.pendingRangeRequests)if(n>=o&&n{this.updateThrottleTimer=void 0,this.lastUpdateStatus.count=3,this.postMessageToClient({clientViewportId:this.clientViewportId,mode:"size-only",size:this.lastUpdateStatus.size,type:"viewport-update"})};this.shouldThrottleMessage=e=>{let t=this.setLastUpdate(e);return e==="size-only"&&t>0&&t<500&&this.lastUpdateStatus.count>3};this.throttleMessage=e=>this.shouldThrottleMessage(e)?(d==null||d("throttling updates setTimeout to 2000"),this.updateThrottleTimer===void 0&&(this.updateThrottleTimer=setTimeout(this.sendThrottledSizeMessage,2e3)),!0):(this.updateThrottleTimer!==void 0&&(clearTimeout(this.updateThrottleTimer),this.updateThrottleTimer=void 0),!1);this.getNewRowCount=()=>{if(this.rowCountChanged&&this.dataWindow)return this.rowCountChanged=!1,this.dataWindow.rowCount};this.aggregations=e,this.bufferSize=t,this.clientRange=u,this.clientViewportId=a,this.columns=s,this.filter=n,this.groupBy=o,this.keys=new O(u),this.pendingLinkedParent=l,this.table=i,this.sort=c,this.title=p,dt&&(d==null||d(\`constructor #\${a} \${i.table} bufferSize=\${t}\`)),this.dataWindow=new N(this.clientRange,u,this.bufferSize),this.postMessageToClient=g}get hasUpdatesToProcess(){return this.suspended?!1:this.rowCountChanged||this.hasUpdates}get size(){var e;return(e=this.dataWindow.rowCount)!=null?e:0}subscribe(){let{filter:e}=this.filter;return this.status=this.status==="subscribed"?"resubscribing":"subscribing",{type:we,table:this.table,range:G(this.clientRange,this.bufferSize),aggregations:this.aggregations,columns:this.columns,sort:this.sort,groupBy:this.groupBy,filterSpec:{filter:e}}}handleSubscribed({viewPortId:e,aggregations:t,columns:s,filterSpec:n,range:o,sort:i,groupBy:u},c){return this.serverViewportId=e,this.status="subscribed",this.aggregations=t,this.columns=s,this.groupBy=u,this.isTree=u&&u.length>0,this.dataWindow.setRange(o.from,o.to),{aggregations:t,type:"subscribed",clientViewportId:this.clientViewportId,columns:s,filter:n,groupBy:u,range:o,sort:i,tableSchema:c}}awaitOperation(e,t){this.pendingOperations.set(e,t)}completeOperation(e,...t){var u;let{clientViewportId:s,pendingOperations:n}=this,o=n.get(e);if(!o){pt(\`no matching operation found to complete for requestId \${e}\`);return}let{type:i}=o;if(d==null||d(\`completeOperation \${i}\`),n.delete(e),i==="CHANGE_VP_RANGE"){let[c,p]=t;(u=this.dataWindow)==null||u.setRange(c,p);for(let a=this.pendingRangeRequests.length-1;a>=0;a--){let l=this.pendingRangeRequests[a];if(l.requestId===e){l.acked=!0;break}else M==null||M("range requests sent faster than they are being ACKed")}}else if(i==="config"){let{aggregations:c,columns:p,filter:a,groupBy:l,sort:g}=o.data;return this.aggregations=c,this.columns=p,this.filter=a,this.groupBy=l,this.sort=g,l.length>0?this.isTree=!0:this.isTree&&(this.isTree=!1),h==null||h(\`config change confirmed, isTree : \${this.isTree}\`),{clientViewportId:s,type:i,config:o.data}}else{if(i==="groupBy")return this.isTree=o.data.length>0,this.groupBy=o.data,h==null||h(\`groupBy change confirmed, isTree : \${this.isTree}\`),{clientViewportId:s,type:i,groupBy:o.data};if(i==="columns")return this.columns=o.data,{clientViewportId:s,type:i,columns:o.data};if(i==="filter")return this.filter=o.data,{clientViewportId:s,type:i,filter:o.data};if(i==="aggregate")return this.aggregations=o.data,{clientViewportId:s,type:"aggregate",aggregations:this.aggregations};if(i==="sort")return this.sort=o.data,{clientViewportId:s,type:i,sort:this.sort};if(i!=="selection"){if(i==="disable")return this.disabled=!0,{type:"disabled",clientViewportId:s};if(i==="enable")return this.disabled=!1,{type:"enabled",clientViewportId:s};if(i==="CREATE_VISUAL_LINK"){let[c,p,a]=t;return this.linkedParent={colName:c,parentViewportId:p,parentColName:a},this.pendingLinkedParent=void 0,{type:"vuu-link-created",clientViewportId:s,colName:c,parentViewportId:p,parentColName:a}}else if(i==="REMOVE_VISUAL_LINK")return this.linkedParent=void 0,{type:"vuu-link-removed",clientViewportId:s}}}}rangeRequest(e,t){U&&this.rangeMonitor.set(t);let s="CHANGE_VP_RANGE";if(this.dataWindow){let[n,o]=this.dataWindow.setClientRange(t.from,t.to),i,u=this.dataWindow.rowCount||void 0,c=n&&!this.rangeRequestAlreadyPending(t)?{type:s,viewPortId:this.serverViewportId,...G(t,this.bufferSize,u)}:null;if(c){U&&(h==null||h(\`create CHANGE_VP_RANGE: [\${c.from} - \${c.to}]\`)),this.awaitOperation(e,{type:s});let a=this.pendingRangeRequests.at(-1);if(a)if(a.acked)console.warn("Range Request before previous request is filled");else{let{from:l,to:g}=a;this.dataWindow.outOfRange(l,g)?i={clientViewportId:this.clientViewportId,type:"debounce-begin"}:M==null||M("Range Request before previous request is acked")}this.pendingRangeRequests.push({...c,requestId:e}),this.useBatchMode&&(this.batchMode=!0)}else o.length>0&&(this.batchMode=!1);this.keys.reset(this.dataWindow.clientRange);let p=this.isTree?j:J;return o.length?[c,o.map(a=>p(a,this.keys,this.selectedRows))]:i?[c,void 0,i]:[c]}else return[null]}setLinks(e){return this.links=e,[{type:"vuu-links",links:e,clientViewportId:this.clientViewportId},this.pendingLinkedParent]}setMenu(e){return{type:"vuu-menu",menu:e,clientViewportId:this.clientViewportId}}openTreeNode(e,t){return this.useBatchMode&&(this.batchMode=!0),{type:Le,vpId:this.serverViewportId,treeKey:t.key}}closeTreeNode(e,t){return this.useBatchMode&&(this.batchMode=!0),{type:be,vpId:this.serverViewportId,treeKey:t.key}}createLink(e,t,s,n){let o={type:"CREATE_VISUAL_LINK",parentVpId:s,childVpId:this.serverViewportId,parentColumnName:n,childColumnName:t};return this.awaitOperation(e,o),this.useBatchMode&&(this.batchMode=!0),o}removeLink(e){let t={type:"REMOVE_VISUAL_LINK",childVpId:this.serverViewportId};return this.awaitOperation(e,t),t}suspend(){this.suspended=!0,d==null||d("suspend")}resume(){return this.suspended=!1,U&&(h==null||h(\`resume: \${this.currentData()}\`)),[this.size,this.currentData()]}currentData(){let e=[];if(this.dataWindow){let t=this.dataWindow.getData(),{keys:s}=this,n=this.isTree?j:J;for(let o of t)o&&e.push(n(o,s,this.selectedRows))}return e}enable(e){return this.awaitOperation(e,{type:"enable"}),d==null||d(\`enable: \${this.serverViewportId}\`),{type:ye,viewPortId:this.serverViewportId}}disable(e){return this.awaitOperation(e,{type:"disable"}),d==null||d(\`disable: \${this.serverViewportId}\`),this.suspended=!1,{type:Ve,viewPortId:this.serverViewportId}}columnRequest(e,t){return this.awaitOperation(e,{type:"columns",data:t}),h==null||h(\`columnRequest: \${t}\`),this.createRequest({columns:t})}filterRequest(e,t){this.awaitOperation(e,{type:"filter",data:t}),this.useBatchMode&&(this.batchMode=!0);let{filter:s}=t;return d==null||d(\`filterRequest: \${s}\`),this.createRequest({filterSpec:{filter:s}})}setConfig(e,t){this.awaitOperation(e,{type:"config",data:t});let{filter:s,...n}=t;return this.useBatchMode&&(this.batchMode=!0),U?h==null||h(\`setConfig \${JSON.stringify(t)}\`):d==null||d("setConfig"),this.createRequest({...n,filterSpec:typeof(s==null?void 0:s.filter)=="string"?{filter:s.filter}:{filter:""}},!0)}aggregateRequest(e,t){return this.awaitOperation(e,{type:"aggregate",data:t}),d==null||d(\`aggregateRequest: \${t}\`),this.createRequest({aggregations:t})}sortRequest(e,t){return this.awaitOperation(e,{type:"sort",data:t}),d==null||d(\`sortRequest: \${JSON.stringify(t.sortDefs)}\`),this.createRequest({sort:t})}groupByRequest(e,t=ct){var s;return this.awaitOperation(e,{type:"groupBy",data:t}),this.useBatchMode&&(this.batchMode=!0),this.isTree||(s=this.dataWindow)==null||s.clear(),this.createRequest({groupBy:t})}selectRequest(e,t){return this.selectedRows=t,this.awaitOperation(e,{type:"selection",data:t}),d==null||d(\`selectRequest: \${t}\`),{type:"SET_SELECTION",vpId:this.serverViewportId,selection:fe(t)}}removePendingRangeRequest(e,t){for(let s=this.pendingRangeRequests.length-1;s>=0;s--){let{from:n,to:o}=this.pendingRangeRequests[s],i=!0;if(e>=n&&en&&t0){e=[],t="update";for(let i of this.pendingUpdates)e.push(o(i,s,n));this.pendingUpdates.length=0}else{let i=this.dataWindow.getData();if(this.dataWindow.hasAllRowsWithinRange){e=[],t="batch";for(let u of i)e.push(o(u,s,n));this.batchMode=!1}}this.hasUpdates=!1}return this.throttleMessage(t)?W:[e,t]}createRequest(e,t=!1){return t?{type:"CHANGE_VP",viewPortId:this.serverViewportId,...e}:{type:"CHANGE_VP",viewPortId:this.serverViewportId,aggregations:this.aggregations,columns:this.columns,sort:this.sort,groupBy:this.groupBy,filterSpec:{filter:this.filter.filter},...e}}},J=({rowIndex:r,rowKey:e,sel:t,data:s},n,o)=>[r,n.keyFor(r),!0,!1,0,0,e,t?z(o,r):0].concat(s),j=({rowIndex:r,rowKey:e,sel:t,data:s},n,o)=>{let[i,u,,c,,p,...a]=s;return[r,n.keyFor(r),c,u,i,p,e,t?z(o,r):0].concat(a)};var We=1;var{debug:V,debugEnabled:Q,error:_,info:T,infoEnabled:ht,warn:Y}=b("server-proxy"),C=()=>\`\${We++}\`,mt={},Ct=r=>r.disabled!==!0&&r.suspended!==!0,Rt={type:"NO_ACTION"},St=(r,e,t)=>r.map(s=>s.parentVpId===e?{...s,label:t}:s);function Tt(r,e){return r.map(t=>{let{parentVpId:s}=t,n=e.get(s);if(n)return{...t,parentClientVpId:n.clientViewportId,label:n.title};throw Error("addLabelsToLinks viewport not found")})}var F=class{constructor(e,t){this.authToken="";this.user="user";this.pendingRequests=new Map;this.queuedRequests=[];this.cachedTableMetaRequests=new Map;this.cachedTableSchemas=new Map;this.connection=e,this.postMessageToClient=t,this.viewports=new Map,this.mapClientToServerViewport=new Map}async reconnect(){await this.login(this.authToken);let[e,t]=le(Array.from(this.viewports.values()),Ct);this.viewports.clear(),this.mapClientToServerViewport.clear();let s=n=>{n.forEach(o=>{let{clientViewportId:i}=o;this.viewports.set(i,o),this.sendMessageToServer(o.subscribe(),i)})};s(e),setTimeout(()=>{s(t)},2e3)}async login(e,t="user"){if(e)return this.authToken=e,this.user=t,new Promise((s,n)=>{this.sendMessageToServer({type:Pe,token:this.authToken,user:t},""),this.pendingLogin={resolve:s,reject:n}});this.authToken===""&&_("login, cannot login until auth token has been obtained")}subscribe(e){if(this.mapClientToServerViewport.has(e.viewport))_(\`spurious subscribe call \${e.viewport}\`);else{let t=this.getTableMeta(e.table),s=new q(e,this.postMessageToClient);this.viewports.set(e.viewport,s);let n=this.awaitResponseToMessage(s.subscribe(),e.viewport);Promise.all([n,t]).then(([i,u])=>{let{viewPortId:c}=i,{status:p}=s;e.viewport!==c&&(this.viewports.delete(e.viewport),this.viewports.set(c,s)),this.mapClientToServerViewport.set(e.viewport,c);let a=s.handleSubscribed(i,u);a&&(this.postMessageToClient(a),Q&&V(\`post DataSourceSubscribedMessage to client: \${JSON.stringify(a)}\`)),s.disabled&&this.disableViewport(s),this.queuedRequests.length>0&&this.processQueuedRequests(),p==="subscribing"&&!x(s.table)&&(this.sendMessageToServer({type:K,vpId:c}),this.sendMessageToServer({type:_e,vpId:c}),Array.from(this.viewports.entries()).filter(([l,{disabled:g}])=>l!==c&&!g).forEach(([l])=>{this.sendMessageToServer({type:K,vpId:l})}))})}}processQueuedRequests(){let e={};for(;this.queuedRequests.length;){let t=this.queuedRequests.pop();if(t){let{clientViewportId:s,message:n,requestId:o}=t;if(n.type==="CHANGE_VP_RANGE"){if(e.CHANGE_VP_RANGE)continue;e.CHANGE_VP_RANGE=!0;let i=this.mapClientToServerViewport.get(s);i&&this.sendMessageToServer({...n,viewPortId:i},o)}}}}unsubscribe(e){let t=this.mapClientToServerViewport.get(e);t?(T==null||T(\`Unsubscribe Message (Client to Server): + \${t}\`),this.sendMessageToServer({type:Oe,viewPortId:t})):_(\`failed to unsubscribe client viewport \${e}, viewport not found\`)}getViewportForClient(e,t=!0){let s=this.mapClientToServerViewport.get(e);if(s){let n=this.viewports.get(s);if(n)return n;if(t)throw Error(\`Viewport not found for client viewport \${e}\`);return null}else{if(this.viewports.has(e))return this.viewports.get(e);if(t)throw Error(\`Viewport server id not found for client viewport \${e}\`);return null}}setViewRange(e,t){let s=C(),[n,o,i]=e.rangeRequest(s,t.range);T==null||T(\`setViewRange \${t.range.from} - \${t.range.to}\`),n&&(this.sendIfReady(n,s,e.status==="subscribed")||this.queuedRequests.push({clientViewportId:t.viewport,message:n,requestId:s})),o?(T==null||T(\`setViewRange \${o.length} rows returned from cache\`),this.postMessageToClient({mode:"batch",type:"viewport-update",clientViewportId:e.clientViewportId,rows:o})):i&&this.postMessageToClient(i)}setConfig(e,t){let s=C(),n=e.setConfig(s,t.config);this.sendIfReady(n,s,e.status==="subscribed")}aggregate(e,t){let s=C(),n=e.aggregateRequest(s,t.aggregations);this.sendIfReady(n,s,e.status==="subscribed")}sort(e,t){let s=C(),n=e.sortRequest(s,t.sort);this.sendIfReady(n,s,e.status==="subscribed")}groupBy(e,t){let s=C(),n=e.groupByRequest(s,t.groupBy);this.sendIfReady(n,s,e.status==="subscribed")}filter(e,t){let s=C(),{filter:n}=t,o=e.filterRequest(s,n);this.sendIfReady(o,s,e.status==="subscribed")}setColumns(e,t){let s=C(),{columns:n}=t,o=e.columnRequest(s,n);this.sendIfReady(o,s,e.status==="subscribed")}setTitle(e,t){e&&(e.title=t.title,this.updateTitleOnVisualLinks(e))}select(e,t){let s=C(),{selected:n}=t,o=e.selectRequest(s,n);this.sendIfReady(o,s,e.status==="subscribed")}disableViewport(e){let t=C(),s=e.disable(t);this.sendIfReady(s,t,e.status==="subscribed")}enableViewport(e){if(e.disabled){let t=C(),s=e.enable(t);this.sendIfReady(s,t,e.status==="subscribed")}}suspendViewport(e){e.suspend(),e.suspendTimer=setTimeout(()=>{T==null||T("suspendTimer expired, escalate suspend to disable"),this.disableViewport(e)},3e3)}resumeViewport(e){e.suspendTimer&&(V==null||V("clear suspend timer"),clearTimeout(e.suspendTimer),e.suspendTimer=null);let[t,s]=e.resume();V==null||V(\`resumeViewport size \${t}, \${s.length} rows sent to client\`),this.postMessageToClient({clientViewportId:e.clientViewportId,mode:"batch",rows:s,size:t,type:"viewport-update"})}openTreeNode(e,t){if(e.serverViewportId){let s=C();this.sendIfReady(e.openTreeNode(s,t),s,e.status==="subscribed")}}closeTreeNode(e,t){if(e.serverViewportId){let s=C();this.sendIfReady(e.closeTreeNode(s,t),s,e.status==="subscribed")}}createLink(e,t){let{parentClientVpId:s,parentColumnName:n,childColumnName:o}=t,i=C(),u=this.mapClientToServerViewport.get(s);if(u){let c=e.createLink(i,o,u,n);this.sendMessageToServer(c,i)}else _("ServerProxy unable to create link, viewport not found")}removeLink(e){let t=C(),s=e.removeLink(t);this.sendMessageToServer(s,t)}updateTitleOnVisualLinks(e){var n;let{serverViewportId:t,title:s}=e;for(let o of this.viewports.values())if(o!==e&&o.links&&t&&s&&(n=o.links)!=null&&n.some(i=>i.parentVpId===t)){let[i]=o.setLinks(St(o.links,t,s));this.postMessageToClient(i)}}removeViewportFromVisualLinks(e){var t;for(let s of this.viewports.values())if((t=s.links)!=null&&t.some(({parentVpId:n})=>n===e)){let[n]=s.setLinks(s.links.filter(({parentVpId:o})=>o!==e));this.postMessageToClient(n)}}menuRpcCall(e){let t=this.getViewportForClient(e.vpId,!1);if(t!=null&&t.serverViewportId){let[s,n]=A(e);this.sendMessageToServer({...n,vpId:t.serverViewportId},s)}}viewportRpcCall(e){let t=this.getViewportForClient(e.vpId,!1);if(t!=null&&t.serverViewportId){let[s,n]=A(e);this.sendMessageToServer({...n,vpId:t.serverViewportId,namedParams:{}},s)}}rpcCall(e){let[t,s]=A(e),n=Ne(s.service);this.sendMessageToServer(s,t,{module:n})}handleMessageFromClient(e){var t;if(ge(e))if(e.type==="disable"){let s=this.getViewportForClient(e.viewport,!1);return s!==null?this.disableViewport(s):void 0}else{let s=this.getViewportForClient(e.viewport);switch(e.type){case"setViewRange":return this.setViewRange(s,e);case"config":return this.setConfig(s,e);case"aggregate":return this.aggregate(s,e);case"sort":return this.sort(s,e);case"groupBy":return this.groupBy(s,e);case"filter":return this.filter(s,e);case"select":return this.select(s,e);case"suspend":return this.suspendViewport(s);case"resume":return this.resumeViewport(s);case"enable":return this.enableViewport(s);case"openTreeNode":return this.openTreeNode(s,e);case"closeTreeNode":return this.closeTreeNode(s,e);case"createLink":return this.createLink(s,e);case"removeLink":return this.removeLink(s);case"setColumns":return this.setColumns(s,e);case"setTitle":return this.setTitle(s,e);default:}}else{if(Ce(e))return this.viewportRpcCall(e);if(me(e))return this.menuRpcCall(e);{let{type:s,requestId:n}=e;switch(s){case"GET_TABLE_LIST":{(t=this.tableList)!=null||(this.tableList=this.awaitResponseToMessage({type:s},n)),this.tableList.then(o=>{this.postMessageToClient({type:"TABLE_LIST_RESP",tables:o.tables,requestId:n})});return}case"GET_TABLE_META":{this.getTableMeta(e.table,n).then(o=>{o&&this.postMessageToClient({type:"TABLE_META_RESP",tableSchema:o,requestId:n})});return}case"RPC_CALL":return this.rpcCall(e);default:}}}_(\`Vuu ServerProxy Unexpected message from client \${JSON.stringify(e)}\`)}getTableMeta(e,t=C()){if(x(e))return Promise.resolve(void 0);let s=\`\${e.module}:\${e.table}\`,n=this.cachedTableMetaRequests.get(s);return n||(n=this.awaitResponseToMessage({type:"GET_TABLE_META",table:e},t),this.cachedTableMetaRequests.set(s,n)),n==null?void 0:n.then(o=>this.cacheTableMeta(o))}awaitResponseToMessage(e,t=C()){return new Promise((s,n)=>{this.sendMessageToServer(e,t),this.pendingRequests.set(t,{reject:n,resolve:s})})}sendIfReady(e,t,s=!0){return s&&this.sendMessageToServer(e,t),s}sendMessageToServer(e,t=\`\${We++}\`,s=mt){let{module:n="CORE"}=s;this.authToken&&this.connection.send({requestId:t,sessionId:this.sessionId,token:this.authToken,user:this.user,module:n,body:e})}handleMessageFromServer(e){var u;let{body:t,requestId:s,sessionId:n}=e,o=this.pendingRequests.get(s);if(o){let{resolve:a}=o;this.pendingRequests.delete(s),a(t);return}let{viewports:i}=this;switch(t.type){case De:this.sendMessageToServer({type:Ie,ts:+new Date},"NA");break;case"LOGIN_SUCCESS":if(n)this.sessionId=n,(u=this.pendingLogin)==null||u.resolve(n),this.pendingLogin=void 0;else throw Error("LOGIN_SUCCESS did not provide sessionId");break;case"REMOVE_VP_SUCCESS":{let a=i.get(t.viewPortId);a&&(this.mapClientToServerViewport.delete(a.clientViewportId),i.delete(t.viewPortId),this.removeViewportFromVisualLinks(t.viewPortId))}break;case xe:{let a=this.viewports.get(t.vpId);a&&a.completeOperation(s)}break;case Te:case ve:if(i.has(t.viewPortId)){let a=this.viewports.get(t.viewPortId);if(a){let l=a.completeOperation(s);l!==void 0&&(this.postMessageToClient(l),Q&&V(\`postMessageToClient \${JSON.stringify(l)}\`))}}break;case Me:{let a=this.viewports.get(t.viewPortId);if(a){let l=a.completeOperation(s);if(l){this.postMessageToClient(l);let[g,S]=a.resume();this.postMessageToClient({clientViewportId:a.clientViewportId,mode:"batch",rows:S,size:g,type:"viewport-update"})}}}break;case"TABLE_ROW":{let a=Se(t.rows);for(let[l,g]of Object.entries(a)){let S=i.get(l);S?S.updateRows(g):Y==null||Y(\`TABLE_ROW message received for non registered viewport \${l}\`)}this.processUpdates()}break;case"CHANGE_VP_RANGE_SUCCESS":{let a=this.viewports.get(t.viewPortId);if(a){let{from:l,to:g}=t;a.completeOperation(s,l,g)}}break;case ke:case Ee:break;case"CREATE_VISUAL_LINK_SUCCESS":{let a=this.viewports.get(t.childVpId),l=this.viewports.get(t.parentVpId);if(a&&l){let{childColumnName:g,parentColumnName:S}=t,I=a.completeOperation(s,g,l.clientViewportId,S);I&&this.postMessageToClient(I)}}break;case"REMOVE_VISUAL_LINK_SUCCESS":{let a=this.viewports.get(t.childVpId);if(a){let l=a.completeOperation(s);l&&this.postMessageToClient(l)}}break;case"VP_VISUAL_LINKS_RESP":{let a=this.getActiveLinks(t.links),l=this.viewports.get(t.vpId);if(a.length&&l){let g=Tt(a,this.viewports),[S,I]=l.setLinks(g);if(this.postMessageToClient(S),I){let{link:ne,parentClientVpId:Ke}=I,re=C(),oe=this.mapClientToServerViewport.get(Ke);if(oe){let Je=l.createLink(re,ne.fromColumn,oe,ne.toColumn);this.sendMessageToServer(Je,re)}}}}break;case"VIEW_PORT_MENUS_RESP":if(t.menu.name){let a=this.viewports.get(t.vpId);if(a){let l=a.setMenu(t.menu);this.postMessageToClient(l)}}break;case"VP_EDIT_RPC_RESPONSE":this.postMessageToClient({action:t.action,requestId:s,rpcName:t.rpcName,type:"VP_EDIT_RPC_RESPONSE"});break;case"VP_EDIT_RPC_REJECT":this.viewports.get(t.vpId)&&this.postMessageToClient({requestId:s,type:"VP_EDIT_RPC_REJECT",error:t.error});break;case"VIEW_PORT_MENU_REJ":{console.log("send menu error back to client");let{error:a,rpcName:l,vpId:g}=t,S=this.viewports.get(g);S&&this.postMessageToClient({clientViewportId:S.clientViewportId,error:a,rpcName:l,type:"VIEW_PORT_MENU_REJ",requestId:s});break}case"VIEW_PORT_MENU_RESP":if(he(t)){let{action:a,rpcName:l}=t;this.awaitResponseToMessage({type:"GET_TABLE_META",table:a.table}).then(g=>{let S=H(g);this.postMessageToClient({rpcName:l,type:"VIEW_PORT_MENU_RESP",action:{...a,tableSchema:S},tableAlreadyOpen:this.isTableOpen(a.table),requestId:s})})}else{let{action:a}=t;this.postMessageToClient({type:"VIEW_PORT_MENU_RESP",action:a||Rt,tableAlreadyOpen:a!==null&&this.isTableOpen(a.table),requestId:s})}break;case"RPC_RESP":{let{method:a,result:l}=t;this.postMessageToClient({type:"RPC_RESP",method:a,result:l,requestId:s})}break;case"VIEW_PORT_RPC_REPONSE":{let{method:a,action:l}=t;this.postMessageToClient({type:"VIEW_PORT_RPC_RESPONSE",rpcName:a,action:l,requestId:s})}break;case"ERROR":_(t.msg);break;default:ht&&T(\`handleMessageFromServer \${t.type}.\`)}}cacheTableMeta(e){let{module:t,table:s}=e.table,n=\`\${t}:\${s}\`,o=this.cachedTableSchemas.get(n);return o||(o=H(e),this.cachedTableSchemas.set(n,o)),o}isTableOpen(e){if(e){let t=e.table;for(let s of this.viewports.values())if(!s.suspended&&s.table.table===t)return!0}}getActiveLinks(e){return e.filter(t=>{let s=this.viewports.get(t.parentVpId);return s&&!s.suspended})}processUpdates(){this.viewports.forEach(e=>{var t;if(e.hasUpdatesToProcess){let s=e.getClientRows();if(s!==W){let[n,o]=s,i=e.getNewRowCount();(i!==void 0||n&&n.length>0)&&(Q&&V(\`postMessageToClient #\${e.clientViewportId} viewport-update \${o}, \${(t=n==null?void 0:n.length)!=null?t:"no"} rows, size \${i}\`),o&&this.postMessageToClient({clientViewportId:e.clientViewportId,mode:o,rows:n,size:i,type:"viewport-update"}))}}})}};var{debug:us,debugEnabled:ls,error:qe,info:E,infoEnabled:bt,warn:D}=b("websocket-connection"),Fe="ws",Et=r=>r.startsWith(Fe+"://")||r.startsWith(Fe+"s://"),Ge={},X=Symbol("setWebsocket"),B=Symbol("connectionCallback");async function ze(r,e,t,s=10,n=5){return Ge[r]={status:"connecting",connect:{allowed:n,remaining:n},reconnect:{allowed:s,remaining:s}},He(r,e,t)}async function Z(r){throw Error("connection broken")}async function He(r,e,t,s){let{status:n,connect:o,reconnect:i}=Ge[r],u=n==="connecting"?o:i;try{t({type:"connection-status",status:"connecting"});let c=typeof s<"u",p=await Vt(r,e);console.info("%c\u26A1 %cconnected","font-size: 24px;color: green;font-weight: bold;","color:green; font-size: 14px;"),s!==void 0&&s[X](p);let a=s!=null?s:new ee(p,r,e,t),l=c?"reconnected":"connection-open-awaiting-session";return t({type:"connection-status",status:l}),a.status=l,u.remaining=u.allowed,a}catch{let p=--u.remaining>0;if(t({type:"connection-status",status:"disconnected",reason:"failed to connect",retry:p}),p)return wt(r,e,t,s,2e3);throw Error("Failed to establish connection")}}var wt=(r,e,t,s,n)=>new Promise(o=>{setTimeout(()=>{o(He(r,e,t,s))},n)}),Vt=(r,e)=>new Promise((t,s)=>{let n=Et(r)?r:\`wss://\${r}\`;bt&&e!==void 0&&E(\`WebSocket Protocol \${e==null?void 0:e.toString()}\`);let o=new WebSocket(n,e);o.onopen=()=>t(o),o.onerror=i=>s(i)}),Be=()=>{D==null||D("Connection cannot be closed, socket not yet opened")},\$e=r=>{D==null||D(\`Message cannot be sent, socket closed \${r.body.type}\`)},vt=r=>{try{return JSON.parse(r)}catch{throw Error(\`Error parsing JSON response from server \${r}\`)}},ee=class{constructor(e,t,s,n){this.close=Be;this.requiresLogin=!0;this.send=\$e;this.status="ready";this.messagesCount=0;this.connectionMetricsInterval=null;this.handleWebsocketMessage=e=>{let t=vt(e.data);this.messagesCount+=1,this[B](t)};this.url=t,this.protocol=s,this[B]=n,this[X](e)}reconnect(){Z(this)}[(B,X)](e){let t=this[B];e.onmessage=o=>{this.status="connected",e.onmessage=this.handleWebsocketMessage,this.handleWebsocketMessage(o)},this.connectionMetricsInterval=setInterval(()=>{t({type:"connection-metrics",messagesLength:this.messagesCount}),this.messagesCount=0},2e3),e.onerror=()=>{qe("\u26A1 connection error"),t({type:"connection-status",status:"disconnected",reason:"error"}),this.connectionMetricsInterval&&(clearInterval(this.connectionMetricsInterval),this.connectionMetricsInterval=null),this.status==="connection-open-awaiting-session"?qe("Websocket connection lost before Vuu session established, check websocket configuration"):this.status!=="closed"&&(Z(this),this.send=n)},e.onclose=()=>{E==null||E("\u26A1 connection close"),t({type:"connection-status",status:"disconnected",reason:"close"}),this.connectionMetricsInterval&&(clearInterval(this.connectionMetricsInterval),this.connectionMetricsInterval=null),this.status!=="closed"&&(Z(this),this.send=n)};let s=o=>{e.send(JSON.stringify(o))},n=o=>{E==null||E(\`TODO queue message until websocket reconnected \${o.body.type}\`)};this.send=s,this.close=()=>{this.status="closed",e.close(),this.close=Be,this.send=\$e,E==null||E("close websocket")}}};var y,{info:te,infoEnabled:se}=b("worker");async function yt(r,e,t,s,n,o,i){let u=await ze(r,e,c=>{de(c)?postMessage({type:"connection-metrics",messages:c}):pe(c)?(n(c),c.status==="reconnected"&&y.reconnect()):y.handleMessageFromServer(c)},o,i);y=new F(u,c=>Mt(c)),u.requiresLogin&&await y.login(t,s)}function Mt(r){postMessage(r)}var _t=async({data:r})=>{switch(r.type){case"connect":await yt(r.url,r.protocol,r.token,r.username,postMessage,r.retryLimitDisconnect,r.retryLimitStartup),postMessage({type:"connected"});break;case"subscribe":se&&te(\`client subscribe: \${JSON.stringify(r)}\`),y.subscribe(r);break;case"unsubscribe":se&&te(\`client unsubscribe: \${JSON.stringify(r)}\`),y.unsubscribe(r.viewport);break;default:se&&te(\`client message: \${JSON.stringify(r)}\`),y.handleMessageFromClient(r)}};self.addEventListener("message",_t);postMessage({type:"ready"}); + +`; \ No newline at end of file diff --git a/vuu-ui/packages/vuu-data/src/message-utils.ts b/vuu-ui/packages/vuu-data-remote/src/message-utils.ts similarity index 76% rename from vuu-ui/packages/vuu-data/src/message-utils.ts rename to vuu-ui/packages/vuu-data-remote/src/message-utils.ts index c01d27e17..07647817e 100644 --- a/vuu-ui/packages/vuu-data/src/message-utils.ts +++ b/vuu-ui/packages/vuu-data-remote/src/message-utils.ts @@ -1,13 +1,17 @@ +import { + SchemaColumn, + TableSchema, + VuuUIMessageOut, + WithRequestId, +} from "@finos/vuu-data-types"; import { ClientToServerMenuRPC, ClientToServerViewportRpcCall, - VuuColumnDataType, VuuRow, VuuRpcRequest, VuuTable, VuuTableMeta, } from "@finos/vuu-protocol-types"; -import { VuuUIMessageOut } from "./vuuUIMessageTypes"; const MENU_RPC_TYPES = [ "VIEW_PORT_MENUS_SELECT_RPC", @@ -35,8 +39,6 @@ export const isVuuRpcRequest = ( ): message is ClientToServerViewportRpcCall => message["type"] === "VIEW_PORT_RPC_CALL"; -export type WithRequestId = T & { requestId: string }; - export const stripRequestId = ({ requestId, ...rest @@ -68,38 +70,10 @@ export const groupRowsByViewport = (rows: VuuRow[]): ViewportRowMap => { return result; }; -export type SchemaColumn = { - name: string; - serverDataType: VuuColumnDataType; -}; - export interface VuuTableMetaWithTable extends VuuTableMeta { table: VuuTable; } -export type TableSchema = { - columns: SchemaColumn[]; - key: string; - table: VuuTable; -}; - -// Sort TableScheas by module -export const byModule = (schema1: TableSchema, schema2: TableSchema) => { - const m1 = schema1.table.module.toLowerCase(); - const m2 = schema2.table.module.toLowerCase(); - if (m1 < m2) { - return -1; - } else if (m1 > m2) { - return 1; - } else if (schema1.table.table < schema2.table.table) { - return -1; - } else if (schema1.table.table > schema2.table.table) { - return 1; - } else { - return 0; - } -}; - export const getColumnByName = ( schema: TableSchema, name?: string diff --git a/vuu-ui/packages/vuu-data/src/server-proxy/array-backed-moving-window.ts b/vuu-ui/packages/vuu-data-remote/src/server-proxy/array-backed-moving-window.ts similarity index 100% rename from vuu-ui/packages/vuu-data/src/server-proxy/array-backed-moving-window.ts rename to vuu-ui/packages/vuu-data-remote/src/server-proxy/array-backed-moving-window.ts diff --git a/vuu-ui/packages/vuu-data/src/server-proxy/messages.ts b/vuu-ui/packages/vuu-data-remote/src/server-proxy/messages.ts similarity index 100% rename from vuu-ui/packages/vuu-data/src/server-proxy/messages.ts rename to vuu-ui/packages/vuu-data-remote/src/server-proxy/messages.ts diff --git a/vuu-ui/packages/vuu-data/src/server-proxy/rpc-services.ts b/vuu-ui/packages/vuu-data-remote/src/server-proxy/rpc-services.ts similarity index 100% rename from vuu-ui/packages/vuu-data/src/server-proxy/rpc-services.ts rename to vuu-ui/packages/vuu-data-remote/src/server-proxy/rpc-services.ts diff --git a/vuu-ui/packages/vuu-data/src/server-proxy/server-proxy.ts b/vuu-ui/packages/vuu-data-remote/src/server-proxy/server-proxy.ts similarity index 98% rename from vuu-ui/packages/vuu-data/src/server-proxy/server-proxy.ts rename to vuu-ui/packages/vuu-data-remote/src/server-proxy/server-proxy.ts index 0af1dc051..b346c62c1 100644 --- a/vuu-ui/packages/vuu-data/src/server-proxy/server-proxy.ts +++ b/vuu-ui/packages/vuu-data-remote/src/server-proxy/server-proxy.ts @@ -1,40 +1,11 @@ -import { - ClientToServerBody, - ClientToServerMenuRPC, - ClientToServerMessage, - ClientToServerViewportRpcCall, - LinkDescriptorWithLabel, - ServerToClientCreateViewPortSuccess, - ServerToClientMessage, - ServerToClientTableList, - ServerToClientTableMeta, - VuuLinkDescriptor, - VuuRpcRequest, - VuuTable, -} from "@finos/vuu-protocol-types"; -import { logger, partition } from "@finos/vuu-utils"; -import { Connection } from "../connectionTypes"; import { DataSourceCallbackMessage, DataSourceVisualLinkCreatedMessage, DataSourceVisualLinkRemovedMessage, -} from "../data-source"; -import { - createSchemaFromTableMetadata, - groupRowsByViewport, - isVuuMenuRpcRequest, - isVuuRpcRequest, - stripRequestId, - TableSchema, - WithRequestId, -} from "../message-utils"; -import { - isSessionTable, - isSessionTableActionMessage, - isViewporttMessage as isViewportMessage, NoAction, OpenDialogAction, ServerProxySubscribeMessage, + TableSchema, VuuUIMessageIn, VuuUIMessageOut, VuuUIMessageOutAggregate, @@ -52,7 +23,32 @@ import { VuuUIMessageOutSubscribe, VuuUIMessageOutUnsubscribe, VuuUIMessageOutViewRange, -} from "../vuuUIMessageTypes"; + WithRequestId, +} from "@finos/vuu-data-types"; +import { + ClientToServerBody, + ClientToServerMenuRPC, + ClientToServerMessage, + ClientToServerViewportRpcCall, + LinkDescriptorWithLabel, + ServerToClientCreateViewPortSuccess, + ServerToClientMessage, + ServerToClientTableList, + ServerToClientTableMeta, + VuuLinkDescriptor, + VuuRpcRequest, + VuuTable, +} from "@finos/vuu-protocol-types"; +import { isViewporttMessage, logger, partition } from "@finos/vuu-utils"; +import { Connection } from "../connectionTypes"; +import { isSessionTable, isSessionTableActionMessage } from "../data-source"; +import { + createSchemaFromTableMetadata, + groupRowsByViewport, + isVuuMenuRpcRequest, + isVuuRpcRequest, + stripRequestId, +} from "../message-utils"; import * as Message from "./messages"; import { getRpcServiceModule } from "./rpc-services"; import { NO_DATA_UPDATE, Viewport } from "./viewport"; @@ -622,7 +618,7 @@ export class ServerProxy { | WithRequestId | WithRequestId ) { - if (isViewportMessage(message)) { + if (isViewporttMessage(message)) { if (message.type === "disable") { // Viewport may already have been unsubscribed const viewport = this.getViewportForClient(message.viewport, false); @@ -670,9 +666,11 @@ export class ServerProxy { } } } else if (isVuuRpcRequest(message)) { - return this.viewportRpcCall(message); + return this.viewportRpcCall( + message as WithRequestId + ); } else if (isVuuMenuRpcRequest(message)) { - return this.menuRpcCall(message); + return this.menuRpcCall(message as WithRequestId); } else { const { type, requestId } = message; switch (type) { diff --git a/vuu-ui/packages/vuu-data/src/server-proxy/viewport.ts b/vuu-ui/packages/vuu-data-remote/src/server-proxy/viewport.ts similarity index 99% rename from vuu-ui/packages/vuu-data/src/server-proxy/viewport.ts rename to vuu-ui/packages/vuu-data-remote/src/server-proxy/viewport.ts index 286c38ca9..be38e4c95 100644 --- a/vuu-ui/packages/vuu-data/src/server-proxy/viewport.ts +++ b/vuu-ui/packages/vuu-data-remote/src/server-proxy/viewport.ts @@ -1,5 +1,29 @@ -import { DataSourceFilter, DataSourceRow } from "@finos/vuu-data-types"; -import { Selection } from "@finos/vuu-table-types"; +import { + DataSourceFilter, + DataSourceRow, + DataSourceAggregateMessage, + DataSourceCallbackMessage, + DataSourceColumnsMessage, + DataSourceDebounceRequest, + DataSourceDisabledMessage, + DataSourceEnabledMessage, + DataSourceFilterMessage, + DataSourceGroupByMessage, + DataSourceMenusMessage, + DataSourceSetConfigMessage, + DataSourceSortMessage, + DataSourceSubscribedMessage, + DataSourceVisualLinkCreatedMessage, + DataSourceVisualLinkRemovedMessage, + DataSourceVisualLinksMessage, + DataUpdateMode, + Selection, + TableSchema, + WithFullConfig, + ServerProxySubscribeMessage, + VuuUIMessageOutOpenTreeNode, + VuuUIMessageOutCloseTreeNode, +} from "@finos/vuu-data-types"; import { ClientToServerChangeViewPort, ClientToServerCloseTreeNode, @@ -29,31 +53,7 @@ import { logger, RangeMonitor, } from "@finos/vuu-utils"; -import { - DataSourceAggregateMessage, - DataSourceCallbackMessage, - DataSourceColumnsMessage, - DataSourceDebounceRequest, - DataSourceDisabledMessage, - DataSourceEnabledMessage, - DataSourceFilterMessage, - DataSourceGroupByMessage, - DataSourceMenusMessage, - DataSourceSetConfigMessage, - DataSourceSortMessage, - DataSourceSubscribedMessage, - DataSourceVisualLinkCreatedMessage, - DataSourceVisualLinkRemovedMessage, - DataSourceVisualLinksMessage, - DataUpdateMode, - WithFullConfig, -} from "../data-source"; -import { getFirstAndLastRows, TableSchema } from "../message-utils"; -import { - ServerProxySubscribeMessage, - VuuUIMessageOutCloseTreeNode, - VuuUIMessageOutOpenTreeNode, -} from "../vuuUIMessageTypes"; +import { getFirstAndLastRows } from "../message-utils"; import { ArrayBackedMovingWindow } from "./array-backed-moving-window"; import * as Message from "./messages"; diff --git a/vuu-ui/packages/vuu-data/src/remote-data-source.ts b/vuu-ui/packages/vuu-data-remote/src/vuu-data-source.ts similarity index 97% rename from vuu-ui/packages/vuu-data/src/remote-data-source.ts rename to vuu-ui/packages/vuu-data-remote/src/vuu-data-source.ts index 119b690c3..5f5558ea8 100644 --- a/vuu-ui/packages/vuu-data/src/remote-data-source.ts +++ b/vuu-ui/packages/vuu-data-remote/src/vuu-data-source.ts @@ -1,5 +1,20 @@ -import { DataSourceFilter, DataSourceRow } from "@finos/vuu-data-types"; -import { Selection } from "@finos/vuu-table-types"; +import { + DataSource, + DataSourceCallbackMessage, + DataSourceConfig, + DataSourceConstructorProps, + DataSourceEvents, + DataSourceFilter, + DataSourceRow, + DataSourceStatus, + OptimizeStrategy, + RpcResponse, + Selection, + SubscribeCallback, + SubscribeProps, + TableSchema, + WithFullConfig, +} from "@finos/vuu-data-types"; import { ClientToServerEditRpc, ClientToServerMenuRPC, @@ -17,50 +32,34 @@ import { import { parseFilter } from "@finos/vuu-filter-parser"; import { + configChanged, debounce, EventEmitter, + isViewportMenusAction, + isVisualLinksAction, itemsOrOrderChanged, logger, metadataKeys, throttle, uuid, -} from "@finos/vuu-utils"; -import { getServerAPI, ServerAPI } from "./connection-manager"; -import { - configChanged, - DataSource, - DataSourceCallbackMessage, - DataSourceConfig, - DataSourceConstructorProps, - DataSourceEvents, - DataSourceStatus, - isDataSourceConfigMessage, - OptimizeStrategy, - RpcResponse, - SubscribeCallback, - SubscribeProps, vanillaConfig, withConfigDefaults, - WithFullConfig, -} from "./data-source"; +} from "@finos/vuu-utils"; +import { getServerAPI, ServerAPI } from "./connection-manager"; +import { isDataSourceConfigMessage } from "./data-source"; -import { - isViewportMenusAction, - isVisualLinksAction, - MenuRpcResponse, -} from "./vuuUIMessageTypes"; -import { TableSchema } from "./message-utils"; +import { MenuRpcResponse } from "@finos/vuu-data-types"; type RangeRequest = (range: VuuRange) => void; -const { info } = logger("RemoteDataSource"); +const { info } = logger("VuuDataSource"); const { KEY } = metadataKeys; /*----------------------------------------------------------------- A RemoteDataSource manages a single subscription via the ServerProxy ----------------------------------------------------------------*/ -export class RemoteDataSource +export class VuuDataSource extends EventEmitter implements DataSource { diff --git a/vuu-ui/packages/vuu-data/src/websocket-connection.ts b/vuu-ui/packages/vuu-data-remote/src/websocket-connection.ts similarity index 98% rename from vuu-ui/packages/vuu-data/src/websocket-connection.ts rename to vuu-ui/packages/vuu-data-remote/src/websocket-connection.ts index 604138cbd..96c311405 100644 --- a/vuu-ui/packages/vuu-data/src/websocket-connection.ts +++ b/vuu-ui/packages/vuu-data-remote/src/websocket-connection.ts @@ -4,12 +4,12 @@ import { } from "@finos/vuu-protocol-types"; import { Connection } from "./connectionTypes"; import { logger } from "@finos/vuu-utils"; - import { ConnectionQualityMetrics, ConnectionStatus, ConnectionStatusMessage, -} from "./vuuUIMessageTypes"; + WebSocketProtocol, +} from "@finos/vuu-data-types"; export type ConnectionMessage = | ServerToClientMessage @@ -17,8 +17,6 @@ export type ConnectionMessage = | ConnectionQualityMetrics; export type ConnectionCallback = (msg: ConnectionMessage) => void; -export type WebSocketProtocol = string | string[] | undefined; - const { debug, debugEnabled, error, info, infoEnabled, warn } = logger( "websocket-connection" ); diff --git a/vuu-ui/packages/vuu-data/src/worker.ts b/vuu-ui/packages/vuu-data-remote/src/worker.ts similarity index 94% rename from vuu-ui/packages/vuu-data/src/worker.ts rename to vuu-ui/packages/vuu-data-remote/src/worker.ts index 0bab408d7..540e3aa83 100644 --- a/vuu-ui/packages/vuu-data/src/worker.ts +++ b/vuu-ui/packages/vuu-data-remote/src/worker.ts @@ -1,20 +1,20 @@ -import { - connect as connectWebsocket, - WebSocketProtocol, -} from "./websocket-connection"; -import { ServerProxy } from "./server-proxy/server-proxy"; import { ConnectionStatusMessage, - isConnectionQualityMetrics, - isConnectionStatusMessage, VuuUIMessageOut, -} from "./vuuUIMessageTypes"; + WebSocketProtocol, + WithRequestId, +} from "@finos/vuu-data-types"; import { ClientToServerMenuRPC, VuuRpcRequest, } from "@finos/vuu-protocol-types"; -import { WithRequestId } from "./message-utils"; -import { logger } from "@finos/vuu-utils"; +import { + isConnectionQualityMetrics, + isConnectionStatusMessage, + logger, +} from "@finos/vuu-utils"; +import { ServerProxy } from "./server-proxy/server-proxy"; +import { connect as connectWebsocket } from "./websocket-connection"; let server: ServerProxy; diff --git a/vuu-ui/packages/vuu-data/test/array-backed-moving-window.test.js b/vuu-ui/packages/vuu-data-remote/test/array-backed-moving-window.test.js similarity index 100% rename from vuu-ui/packages/vuu-data/test/array-backed-moving-window.test.js rename to vuu-ui/packages/vuu-data-remote/test/array-backed-moving-window.test.js diff --git a/vuu-ui/packages/vuu-data/test/global-mocks.ts b/vuu-ui/packages/vuu-data-remote/test/global-mocks.ts similarity index 100% rename from vuu-ui/packages/vuu-data/test/global-mocks.ts rename to vuu-ui/packages/vuu-data-remote/test/global-mocks.ts diff --git a/vuu-ui/packages/vuu-data/test/message-utils.test.ts b/vuu-ui/packages/vuu-data-remote/test/message-utils.test.ts similarity index 100% rename from vuu-ui/packages/vuu-data/test/message-utils.test.ts rename to vuu-ui/packages/vuu-data-remote/test/message-utils.test.ts diff --git a/vuu-ui/packages/vuu-data/test/remote-data-source.test.ts b/vuu-ui/packages/vuu-data-remote/test/remote-data-source.test.ts similarity index 92% rename from vuu-ui/packages/vuu-data/test/remote-data-source.test.ts rename to vuu-ui/packages/vuu-data-remote/test/remote-data-source.test.ts index 8c956e6c9..6be4c4d21 100644 --- a/vuu-ui/packages/vuu-data/test/remote-data-source.test.ts +++ b/vuu-ui/packages/vuu-data-remote/test/remote-data-source.test.ts @@ -4,9 +4,9 @@ import "./global-mocks"; import { beforeEach, describe, expect, it, vi } from "vitest"; import * as connectionExports from "../src/connection-manager"; //---------------------------------------------------- +import { DataSourceConfig } from "@finos/vuu-data-types"; import { LinkDescriptorWithLabel, VuuSortCol } from "@finos/vuu-protocol-types"; -import { RemoteDataSource } from "../src/remote-data-source"; -import { DataSourceConfig } from "../src/data-source"; +import { VuuDataSource } from "../src/vuu-data-source"; const defaultSubscribeOptions = { aggregations: [], @@ -30,7 +30,7 @@ describe("RemoteDataSource", () => { it("cannot be created without table", () => { try { // @ts-ignore - new RemoteDataSource(); + new VuuDataSource(); throw Error("RemoteDataSource was created without table"); } catch (err) { expect(err).toBeDefined(); @@ -40,7 +40,7 @@ describe("RemoteDataSource", () => { } try { // @ts-ignore - new RemoteDataSource({}); + new VuuDataSource({}); throw Error("RemoteDataSource was created without table"); } catch (err) { expect(err).toBeDefined(); @@ -50,7 +50,7 @@ describe("RemoteDataSource", () => { } try { // @ts-ignore - new RemoteDataSource({ + new VuuDataSource({ bufferSize: 100, aggregations: [], columns: ["test1", "test2"], @@ -64,7 +64,7 @@ describe("RemoteDataSource", () => { }); it("requires only Table for successful construction", () => { - const dataSource = new RemoteDataSource({ + const dataSource = new VuuDataSource({ table: { module: "SIMUL", table: "instruments" }, }); expect(dataSource).toBeDefined(); @@ -76,7 +76,7 @@ describe("RemoteDataSource", () => { const sort = { sortDefs: [{ column: "col1", sortType: "A" } as VuuSortCol], }; - const dataSource = new RemoteDataSource({ + const dataSource = new VuuDataSource({ columns, filter, sort, @@ -102,7 +102,7 @@ describe("RemoteDataSource", () => { }); }) ); - const dataSource = new RemoteDataSource({ table }); + const dataSource = new VuuDataSource({ table }); await dataSource.subscribe({}, callback); expect(serverSubscribe).toHaveBeenCalledWith( @@ -126,7 +126,7 @@ describe("RemoteDataSource", () => { // @ts-ignore () => resolvedPromise ); - const dataSource = new RemoteDataSource({ table }); + const dataSource = new VuuDataSource({ table }); await dataSource.subscribe({}, callback); @@ -152,7 +152,7 @@ describe("RemoteDataSource", () => { }); vi.spyOn(connectionExports, "getServerAPI").mockImplementation(() => pr); - const dataSource = new RemoteDataSource({ table }); + const dataSource = new VuuDataSource({ table }); setTimeout(() => resolvePromise({ subscribe: serverSubscribe }), 50); @@ -195,7 +195,7 @@ describe("RemoteDataSource", () => { // @ts-ignore () => resolvedPromise ); - const dataSource = new RemoteDataSource({ + const dataSource = new VuuDataSource({ aggregations, bufferSize: 200, columns, @@ -247,7 +247,7 @@ describe("RemoteDataSource", () => { // @ts-ignore () => resolvedPromise ); - const dataSource = new RemoteDataSource({ + const dataSource = new VuuDataSource({ aggregations, columns, filter, @@ -298,7 +298,7 @@ describe("RemoteDataSource", () => { }); vi.spyOn(connectionExports, "getServerAPI").mockImplementation(() => pr); - const dataSource = new RemoteDataSource({ table }); + const dataSource = new VuuDataSource({ table }); setTimeout(() => { // dataSource is blocked inside subscribe function, awaiting server ... @@ -336,7 +336,7 @@ describe("RemoteDataSource", () => { // @ts-ignore () => Promise.resolve({ send: serverSend, subscribe: callback }) ); - const dataSource = new RemoteDataSource({ table, viewport: "vp1" }); + const dataSource = new VuuDataSource({ table, viewport: "vp1" }); await dataSource.subscribe({}, callback); const range = { from: 0, to: 20 }; @@ -354,7 +354,7 @@ describe("RemoteDataSource", () => { // @ts-ignore () => Promise.resolve({ send: serverSend, subscribe: callback }) ); - const dataSource = new RemoteDataSource({ table, viewport: "vp1" }); + const dataSource = new VuuDataSource({ table, viewport: "vp1" }); await dataSource.subscribe({}, callback); const aggregations = [{ column: "col1", aggType: 1 } as const]; @@ -373,7 +373,7 @@ describe("RemoteDataSource", () => { // @ts-ignore () => Promise.resolve({ send: serverSend, subscribe: callback }) ); - const dataSource = new RemoteDataSource({ table, viewport: "vp1" }); + const dataSource = new VuuDataSource({ table, viewport: "vp1" }); await dataSource.subscribe({}, callback); const columns = ["col1", "col2"]; @@ -391,7 +391,7 @@ describe("RemoteDataSource", () => { // @ts-ignore () => Promise.resolve({ send: serverSend, subscribe: callback }) ); - const dataSource = new RemoteDataSource({ table, viewport: "vp1" }); + const dataSource = new VuuDataSource({ table, viewport: "vp1" }); await dataSource.subscribe({}, callback); const filter = { filter: 'exchange="SETS"' }; @@ -409,7 +409,7 @@ describe("RemoteDataSource", () => { // @ts-ignore () => Promise.resolve({ send: serverSend, subscribe: callback }) ); - const dataSource = new RemoteDataSource({ table, viewport: "vp1" }); + const dataSource = new VuuDataSource({ table, viewport: "vp1" }); await dataSource.subscribe({}, callback); const groupBy = ["col1", "col2"]; @@ -428,7 +428,7 @@ describe("RemoteDataSource", () => { // @ts-ignore () => Promise.resolve({ send: serverSend, subscribe: callback }) ); - const dataSource = new RemoteDataSource({ table, viewport: "vp1" }); + const dataSource = new VuuDataSource({ table, viewport: "vp1" }); await dataSource.subscribe({}, callback); let config: DataSourceConfig = { @@ -474,7 +474,7 @@ describe("RemoteDataSource", () => { // @ts-ignore () => Promise.resolve({ send: serverSend, subscribe: callback }) ); - const dataSource = new RemoteDataSource({ table, viewport: "vp1" }); + const dataSource = new VuuDataSource({ table, viewport: "vp1" }); await dataSource.subscribe({}, callback); const config: DataSourceConfig = { @@ -509,7 +509,7 @@ describe("RemoteDataSource", () => { // @ts-ignore () => Promise.resolve({ send: serverSend, subscribe: callback }) ); - const dataSource = new RemoteDataSource({ table, viewport: "vp1" }); + const dataSource = new VuuDataSource({ table, viewport: "vp1" }); await dataSource.subscribe({}, callback); const config: DataSourceConfig = { diff --git a/vuu-ui/packages/vuu-data/test/server-proxy-throttle.test.ts b/vuu-ui/packages/vuu-data-remote/test/server-proxy-throttle.test.ts similarity index 100% rename from vuu-ui/packages/vuu-data/test/server-proxy-throttle.test.ts rename to vuu-ui/packages/vuu-data-remote/test/server-proxy-throttle.test.ts diff --git a/vuu-ui/packages/vuu-data/test/server-proxy.test.ts b/vuu-ui/packages/vuu-data-remote/test/server-proxy.test.ts similarity index 100% rename from vuu-ui/packages/vuu-data/test/server-proxy.test.ts rename to vuu-ui/packages/vuu-data-remote/test/server-proxy.test.ts diff --git a/vuu-ui/packages/vuu-data/test/test-utils.ts b/vuu-ui/packages/vuu-data-remote/test/test-utils.ts similarity index 100% rename from vuu-ui/packages/vuu-data/test/test-utils.ts rename to vuu-ui/packages/vuu-data-remote/test/test-utils.ts diff --git a/vuu-ui/packages/vuu-data/test/viewport.test.ts b/vuu-ui/packages/vuu-data-remote/test/viewport.test.ts similarity index 100% rename from vuu-ui/packages/vuu-data/test/viewport.test.ts rename to vuu-ui/packages/vuu-data-remote/test/viewport.test.ts diff --git a/vuu-ui/packages/vuu-data/test/websocket-connection.test.ts b/vuu-ui/packages/vuu-data-remote/test/websocket-connection.test.ts similarity index 100% rename from vuu-ui/packages/vuu-data/test/websocket-connection.test.ts rename to vuu-ui/packages/vuu-data-remote/test/websocket-connection.test.ts diff --git a/vuu-ui/packages/vuu-data-remote/tsconfig.json b/vuu-ui/packages/vuu-data-remote/tsconfig.json new file mode 100644 index 000000000..db9582a16 --- /dev/null +++ b/vuu-ui/packages/vuu-data-remote/tsconfig.json @@ -0,0 +1,6 @@ +{ +"extends": "../../tsconfig.json", +"compilerOptions":{ + "composite": true +}, +} diff --git a/vuu-ui/packages/vuu-data-test/src/Table.ts b/vuu-ui/packages/vuu-data-test/src/Table.ts index c06f8eabc..f69981219 100644 --- a/vuu-ui/packages/vuu-data-test/src/Table.ts +++ b/vuu-ui/packages/vuu-data-test/src/Table.ts @@ -1,4 +1,4 @@ -import { SchemaColumn, TableSchema } from "@finos/vuu-data"; +import { SchemaColumn, TableSchema } from "@finos/vuu-data-types"; import { VuuRowDataItemType, VuuTable } from "@finos/vuu-protocol-types"; import { ColumnMap, EventEmitter } from "@finos/vuu-utils"; import { UpdateGenerator } from "./rowUpdates"; diff --git a/vuu-ui/packages/vuu-data-test/src/TickingArrayDataSource.ts b/vuu-ui/packages/vuu-data-test/src/TickingArrayDataSource.ts index 9432b3ed1..435bc6cd1 100644 --- a/vuu-ui/packages/vuu-data-test/src/TickingArrayDataSource.ts +++ b/vuu-ui/packages/vuu-data-test/src/TickingArrayDataSource.ts @@ -1,23 +1,22 @@ import { ArrayDataSource, - ArrayDataSourceConstructorProps, - MenuRpcResponse, - RpcResponse, + ArrayDataSourceConstructorProps +} from "@finos/vuu-data-local"; +import { + DataSourceRow, MenuRpcResponse, RpcResponse, + SelectionItem, SubscribeCallback, - SubscribeProps, - VuuUIMessageInRPCEditReject, - VuuUIMessageInRPCEditResponse, -} from "@finos/vuu-data"; -import { DataSourceRow } from "@finos/vuu-data-types"; + SubscribeProps, VuuUIMessageInRPCEditReject, + VuuUIMessageInRPCEditResponse +} from "@finos/vuu-data-types"; import { ClientToServerEditRpc, ClientToServerMenuRPC, ClientToServerViewportRpcCall, VuuMenu, VuuRange, - VuuRowDataItemType, + VuuRowDataItemType } from "@finos/vuu-protocol-types"; -import { SelectionItem } from "@finos/vuu-table-types"; import { metadataKeys } from "@finos/vuu-utils"; import { makeSuggestions } from "./makeSuggestions"; import { Table } from "./Table"; diff --git a/vuu-ui/packages/vuu-data-test/src/basket/basket-schemas.ts b/vuu-ui/packages/vuu-data-test/src/basket/basket-schemas.ts index b6e6d6274..122586490 100644 --- a/vuu-ui/packages/vuu-data-test/src/basket/basket-schemas.ts +++ b/vuu-ui/packages/vuu-data-test/src/basket/basket-schemas.ts @@ -1,4 +1,4 @@ -import { TableSchema } from "@finos/vuu-data"; +import { TableSchema } from "@finos/vuu-data-types"; export type BasketsTableName = | "algoType" diff --git a/vuu-ui/packages/vuu-data-test/src/schemas.ts b/vuu-ui/packages/vuu-data-test/src/schemas.ts index 79adf5250..c8d729305 100644 --- a/vuu-ui/packages/vuu-data-test/src/schemas.ts +++ b/vuu-ui/packages/vuu-data-test/src/schemas.ts @@ -1,4 +1,4 @@ -import { TableSchema } from "@finos/vuu-data"; +import { TableSchema } from "@finos/vuu-data-types"; import { type BasketsTableName, schemas as basketSchemas, diff --git a/vuu-ui/packages/vuu-data-test/src/simul/reference-data/instruments.ts b/vuu-ui/packages/vuu-data-test/src/simul/reference-data/instruments.ts index e818d9d42..95a20b993 100644 --- a/vuu-ui/packages/vuu-data-test/src/simul/reference-data/instruments.ts +++ b/vuu-ui/packages/vuu-data-test/src/simul/reference-data/instruments.ts @@ -49,7 +49,7 @@ const randomPrice = () => { const start = performance.now(); // Create 10_000 Instruments for (const char of chars) { - for (let i = 0; i < 10_000; i++) { + for (let i = 0; i < 10_00; i++) { const char2 = chars[random(0, chars.length - 1)]; const char3 = chars[random(0, chars.length - 1)]; const char4 = chars[random(0, chars.length - 1)]; diff --git a/vuu-ui/packages/vuu-data-test/src/simul/simul-schemas.ts b/vuu-ui/packages/vuu-data-test/src/simul/simul-schemas.ts index 35f4f29e9..dde8a4a1d 100644 --- a/vuu-ui/packages/vuu-data-test/src/simul/simul-schemas.ts +++ b/vuu-ui/packages/vuu-data-test/src/simul/simul-schemas.ts @@ -1,5 +1,5 @@ -import type { TableSchema } from "@finos/vuu-data"; import type { ColumnDescriptor } from "@finos/vuu-table-types"; +import { TableSchema } from "@finos/vuu-data-types"; export type SimulTableName = | "instruments" diff --git a/vuu-ui/packages/vuu-data-test/src/vuu-modules.ts b/vuu-ui/packages/vuu-data-test/src/vuu-modules.ts index 2e8386293..61f9c58d6 100644 --- a/vuu-ui/packages/vuu-data-test/src/vuu-modules.ts +++ b/vuu-ui/packages/vuu-data-test/src/vuu-modules.ts @@ -1,5 +1,5 @@ -import { DataSource } from "@finos/vuu-data"; -import { SuggestionFetcher } from "packages/vuu-data-react/src"; +import { DataSource } from "@finos/vuu-data-types"; +import { SuggestionFetcher } from "@finos/vuu-data-react"; import basketModule from "./basket/basket-module"; import { BasketsTableName } from "./basket/basket-schemas"; import simulModule from "./simul/simul-module"; diff --git a/vuu-ui/packages/vuu-data-types/index.d.ts b/vuu-ui/packages/vuu-data-types/index.d.ts index a0efbbfd7..abe5e071b 100644 --- a/vuu-ui/packages/vuu-data-types/index.d.ts +++ b/vuu-ui/packages/vuu-data-types/index.d.ts @@ -1,6 +1,36 @@ -import { VuuFilter, VuuRowDataItemType } from "@finos/vuu-protocol-types"; -import { Filter } from "@finos/vuu-filter-types"; -import { MenuActionClosePopup } from "@finos/vuu-popups"; +import type { Filter } from "@finos/vuu-filter-types"; +import type { MenuActionClosePopup } from "@finos/vuu-popups"; +import type { + ClientToServerEditRpc, + ClientToServerMenuRPC, + ClientToServerViewportRpcCall, + VuuAggregation, + VuuColumnDataType, + VuuColumns, + VuuDataRowDto, + VuuFilter, + VuuGroupBy, + VuuLinkDescriptor, + VuuMenu, + VuuRowDataItemType, + VuuSort, + VuuTable, +} from "@finos/vuu-protocol-types"; +import type { IEventEmitter } from "@finos/vuu-utils"; +import type { + DataSourceFilter, + MenuRpcResponse, + Selection, + TableSchema, +} from "@finos/vuu-data-types"; +import type { + ClientToServerTableList, + ClientToServerTableMeta, + LinkDescriptorWithLabel, + ServerToClientViewportRpcResponse, + TypeAheadMethod, + VuuRange, +} from "@finos/vuu-protocol-types"; export interface DataSourceFilter extends VuuFilter { filterStruct?: Filter; @@ -46,13 +76,155 @@ export interface ContextMenuLeafItemDescriptor extends ContextMenuItemBase { options?: unknown; } +export type ContextMenuItemDescriptor = + | ContextMenuLeafItemDescriptor + | ContextMenuGroupItemDescriptor; + export interface ContextMenuGroupItemDescriptor extends ContextMenuItemBase { children: ContextMenuItemDescriptor[]; } -export type ContextMenuItemDescriptor = - | ContextMenuLeafItemDescriptor - | ContextMenuGroupItemDescriptor; +export interface MessageWithClientViewportId { + clientViewportId: string; +} + +export interface DataSourceAggregateMessage + extends MessageWithClientViewportId { + aggregations: VuuAggregation[]; + type: "aggregate"; +} + +export type DataUpdateMode = "batch" | "update" | "size-only"; + +export interface DataSourceDataMessage extends MessageWithClientViewportId { + mode: DataUpdateMode; + rows?: DataSourceRow[]; + size?: number; + type: "viewport-update"; +} + +export interface DataSourceDataSizeMessage extends MessageWithClientViewportId { + mode: "size-only"; + size: number; + type: "viewport-update"; +} + +export interface DataSourceDisabledMessage extends MessageWithClientViewportId { + type: "disabled"; +} + +export interface DataSourceEnabledMessage extends MessageWithClientViewportId { + type: "enabled"; +} + +export interface DataSourceColumnsMessage extends MessageWithClientViewportId { + type: "columns"; + columns: VuuColumns; +} +export interface DataSourceFilterMessage extends MessageWithClientViewportId { + type: "filter"; + filter: DataSourceFilter; +} +export interface DataSourceGroupByMessage extends MessageWithClientViewportId { + type: "groupBy"; + groupBy: VuuGroupBy | undefined; +} + +export interface DataSourceSetConfigMessage + extends MessageWithClientViewportId { + type: "config"; + config: WithFullConfig; +} + +export interface DataSourceDebounceRequest extends MessageWithClientViewportId { + type: "debounce-begin"; +} + +export interface DataSourceMenusMessage extends MessageWithClientViewportId { + type: "vuu-menu"; + menu: VuuMenu; +} + +export interface DataSourceSortMessage extends MessageWithClientViewportId { + type: "sort"; + sort: VuuSort; +} + +export interface DataSourceSubscribedMessage + extends MessageWithClientViewportId { + aggregations: VuuAggregation[]; + columns: VuuColumns; + filter: DataSourceFilter; + groupBy: VuuGroupBy; + range: VuuRange; + sort: VuuSort; + tableSchema: Readonly; + type: "subscribed"; +} + +export interface DataSourceVisualLinkCreatedMessage + extends MessageWithClientViewportId { + colName: string; + parentViewportId: string; + parentColName: string; + type: "vuu-link-created"; +} + +export interface DataSourceVisualLinkRemovedMessage + extends MessageWithClientViewportId { + type: "vuu-link-removed"; +} + +export interface DataSourceVisualLinksMessage + extends MessageWithClientViewportId { + type: "vuu-links"; + links: VuuLinkDescriptor[]; +} + +export type VuuFeatureInvocationMessage = + | DataSourceVisualLinkCreatedMessage + | DataSourceVisualLinkRemovedMessage; + +export type VuuFeatureMessage = + | DataSourceMenusMessage + | DataSourceVisualLinksMessage; + +export type DataSourceConfigMessage = + | DataSourceAggregateMessage + | DataSourceColumnsMessage + | DataSourceFilterMessage + | DataSourceGroupByMessage + | DataSourceSortMessage + | DataSourceSetConfigMessage; + +export type DataSourceCallbackMessage = + | DataSourceConfigMessage + | DataSourceColumnsMessage + | DataSourceDataMessage + | DataSourceDebounceRequest + | DataSourceDisabledMessage + | DataSourceEnabledMessage + | DataSourceMenusMessage + | DataSourceSubscribedMessage + | DataSourceVisualLinkCreatedMessage + | DataSourceVisualLinkRemovedMessage + | DataSourceVisualLinksMessage; + +export type ConfigChangeColumnsMessage = { + type: "columns"; + columns?: ColumnDescriptor[]; +}; + +export type ConfigChangeMessage = + | ConfigChangeColumnsMessage + | DataSourceAggregateMessage + | DataSourceFilterMessage + | DataSourceGroupByMessage + | DataSourceSortMessage + | DataSourceVisualLinkCreatedMessage + | DataSourceVisualLinkRemovedMessage; + +export type ConfigChangeHandler = (msg: ConfigChangeMessage) => void; /** * MenuBuilder describes a factory function that creates @@ -82,3 +254,495 @@ export interface ContextMenuContextType { menuBuilders: MenuBuilder[]; menuActionHandler: MenuActionHandler; } + +export type SchemaColumn = { + name: string; + serverDataType: VuuColumnDataType; +}; + +export type TableSchema = { + columns: SchemaColumn[]; + key: string; + table: VuuTable; +}; + +/** + * Described the configuration values that should typically be + * persisted across sessions. + */ +export interface WithFullConfig { + readonly aggregations: VuuAggregation[]; + readonly columns: string[]; + readonly filter: DataSourceFilter; + readonly groupBy: VuuGroupBy; + readonly sort: VuuSort; + readonly visualLink?: LinkDescriptorWithLabel; +} + +export interface DataSourceConfig extends Partial { + visualLink?: LinkDescriptorWithLabel; +} + +export interface WithGroupBy extends DataSourceConfig { + groupBy: VuuGroupBy; +} +export interface WithFilter extends DataSourceConfig { + filter: DataSourceFilter; +} +export interface WithSort extends DataSourceConfig { + sort: VuuSort; +} + +export interface DataSourceConstructorProps extends DataSourceConfig { + bufferSize?: number; + table: VuuTable; + title?: string; + viewport?: string; +} + +export interface SubscribeProps { + viewport?: string; + columns?: string[]; + aggregations?: VuuAggregation[]; + range?: VuuRange; + sort?: VuuSort; + groupBy?: VuuGroupBy; + filter?: DataSourceFilter; + title?: string; +} + +export type SubscribeCallback = (message: DataSourceCallbackMessage) => void; +export type OptimizeStrategy = "none" | "throttle" | "debounce"; + +export type DataSourceEvents = { + config: (config: DataSourceConfig | undefined, confirmed?: boolean) => void; + optimize: (optimize: OptimizeStrategy) => void; + range: (range: VuuRange) => void; + resize: (size: number) => void; +}; + +/** + * return Promise indicates success + * return Promise indicates failure + */ +export type DataSourceEditHandler = ( + row: DataSourceRow, + columnName: string, + value: VuuRowDataItemType +) => Promise; + +export type DataSourceDeleteHandler = (key: string) => Promise; +export type DataSourceInsertHandler = ( + key: string, + data: VuuDataRowDto +) => Promise; + +export type RpcResponse = + | MenuRpcResponse + | VuuUIMessageInRPCEditReject + | VuuUIMessageInRPCEditResponse + | ViewportRpcResponse; + +export type RpcResponseHandler = (response: RpcResponse) => boolean; + +export type RowSearchPredicate = (row: DataSourceRow) => boolean; + +export type DataSourceStatus = + | "disabled" + | "disabling" + | "enabled" + | "enabling" + | "initialising" + | "subscribing" + | "subscribed" + | "suspended" + | "unsubscribed"; + +export interface TypeaheadSuggestionProvider { + getTypeaheadSuggestions: ( + columnName: string, + pattern?: string + ) => Promise; +} + +export type RangeTuple = [from: number, to: number]; +export type SelectionItem = number | RangeTuple; +export type Selection = SelectionItem[]; +export type SelectionChangeHandler = (selection: Selection) => void; + +export interface DataSource + extends IEventEmitter, + Partial { + aggregations: VuuAggregation[]; + applyEdit: DataSourceEditHandler; + /** + * set config without triggering config event. Use this method when initialising + * a dataSource that has been restored from session state. The dataSource will + * not yet be subscribed. Triggering the config event is unnecessary and might + * cause a React exception if the event were to cause a render. + * @param config DataSourceConfig + * @returns true if config has been applied (will not be if existig config is same) + */ + applyConfig: (config: DataSourceConfig) => true | undefined; + closeTreeNode: (key: string, cascade?: boolean) => void; + columns: string[]; + config: DataSourceConfig; + status: DataSourceStatus; + /** + * + * Similar to disable but intended for pauses of very short duration (default is 3 seconds). Although + * the dataSource will stop sending messages until resumed, it will not disconnect from a remote server. + * It will preserve subscription to the remote server and continue to apply updates to cached data. It + * just won't send updates through to the UI thread (until resumed). Useful in edge cases such as where a + * component is dragged to a new location. When dropped, the component will be unmounted and very quickly + * remounted by React. For the duration of this operation, we suspend updates . Updating an unmounted + * React component would cause a React error. + * If an suspend is requested and not resumed within 3 seconds, it will automatically be promoted to a disable., + */ + suspend?: () => void; + resume?: () => void; + + deleteRow?: DataSourceDeleteHandler; + + /** + * For a dataSource that has been previously disabled and is currently in disabled state , this will restore + * the subscription to active status. Fresh data will be dispatched to client. The enable call optionally + * accepts the same subscribe callback as subscribe. This allows a completely new instance of a component to + * assume ownership of a subscription and receive all messages. + */ + enable?: (callback?: SubscribeCallback) => void; + /** + * Disables this subscription. A datasource will send no further messages until re-enabled. Example usage + * might be for a component displayed within a set of Tabs. If user switches to another tab, the dataSource + * of the component that is no longer visible can be disabled until it is made visible again. + */ + disable?: () => void; + filter: DataSourceFilter; + + /** + * Only implemented on JSON DataSource + * @param depth + * @param visibleOnly + * @returns + */ + getChildRows?: (rowKey: string) => DataSourceRow[]; + /** + * Only implemented on JSON DataSource + * @param depth + * @param visibleOnly + * @returns + */ + getRowsAtDepth?: (depth: number, visibleOnly?: boolean) => DataSourceRow[]; + groupBy: VuuGroupBy; + insertRow?: DataSourceInsertHandler; + links?: LinkDescriptorWithLabel[]; + menu?: VuuMenu; + menuRpcCall: ( + rpcRequest: Omit | ClientToServerEditRpc + ) => Promise; + rpcCall?: ( + message: Omit + ) => Promise; + openTreeNode: (key: string) => void; + range: VuuRange; + select: SelectionChangeHandler; + readonly selectedRowsCount: number; + readonly size: number; + sort: VuuSort; + subscribe: ( + props: SubscribeProps, + callback: SubscribeCallback + ) => Promise; + table?: VuuTable; + readonly tableSchema?: TableSchema; + title?: string; + unsubscribe: () => void; + viewport?: string; + visualLink?: LinkDescriptorWithLabel; +} + +export interface MenuRpcResponse { + action: MenuRpcAction; + error?: string; + requestId: string; + rpcName?: string; + tableAlreadyOpen?: boolean; + type: "VIEW_PORT_MENU_RESP"; +} + +export interface OpenDialogAction { + type: "OPEN_DIALOG_ACTION"; + tableSchema?: TableSchema; + table?: VuuTable; +} +export interface NoAction { + type: "NO_ACTION"; +} + +export declare type MenuRpcAction = OpenDialogAction | NoAction; + +export type ConnectionStatus = + | "connecting" + | "connection-open-awaiting-session" + | "connected" + | "disconnected" + | "reconnected"; + +export interface ConnectionStatusMessage { + type: "connection-status"; + reason?: string; + retry?: boolean; + status: ConnectionStatus; +} + +export interface ConnectionQualityMetrics { + type: "connection-metrics"; + messagesLength: number; +} + +export interface ServerProxySubscribeMessage { + aggregations: VuuAggregation[]; + bufferSize?: number; + columns: VuuColumns; + filter: DataSourceFilter; + groupBy: VuuGroupBy; + range: VuuRange; + sort: VuuSort; + table: VuuTable; + title?: string; + viewport: string; + visualLink?: LinkDescriptorWithLabel; +} + +// export type VuuUIMessageInConnectionStatus = { +// type: 'connection-status'; +// }; + +export type VuuUIMessageInConnected = { + type: "connected"; +}; + +export type VuuUIMessageInWorkerReady = { + type: "ready"; +}; + +export interface ViewportMessageIn { + clientViewportId: string; +} + +// TODO use generic to type result +export interface VuuUIMessageInRPC { + method: string; + result: unknown; + requestId: string; + type: "RPC_RESP"; +} + +export interface VuuUIMessageInRPCEditReject { + error: string; + requestId?: string; + type: "VP_EDIT_RPC_REJECT"; +} + +export interface VuuUIMessageInRPCEditResponse { + action: unknown; + requestId: string; + rpcName: string; + type: "VP_EDIT_RPC_RESPONSE"; +} + +export interface VuuUIMessageInTableList { + requestId: string; + type: "TABLE_LIST_RESP"; + tables: VuuTable[]; +} +export interface VuuUIMessageInTableMeta { + requestId: string; + tableSchema: TableSchema; + type: "TABLE_META_RESP"; +} +export interface ViewportRpcResponse { + action: ServerToClientViewportRpcResponse["action"]; + requestId: string; + rpcName?: string; + type: "VIEW_PORT_RPC_RESPONSE"; +} +export interface MenuRpcReject extends ViewportMessageIn { + error?: string; + requestId: string; + rpcName?: string; + type: "VIEW_PORT_MENU_REJ"; +} + +export interface VuuUIMessageInMenuRej { + error: string; + requestId: string; + rpcName: string; + type: "VIEW_PORT_MENU_REJ"; +} + +export type VuuUIMessageIn = + | VuuUIMessageInConnected + | VuuUIMessageInWorkerReady + | VuuUIMessageInRPC + | ViewportRpcResponse + | MenuRpcResponse + | MenuRpcReject + | VuuUIMessageInTableList + | VuuUIMessageInTableMeta + | VuuUIMessageInRPCEditReject + | VuuUIMessageInRPCEditResponse; + +export type WebSocketProtocol = string | string[] | undefined; + +export interface VuuUIMessageOutConnect { + protocol: WebSocketProtocol; + type: "connect"; + token: string; + url: string; + username?: string; + retryLimitDisconnect?: number; + retryLimitStartup?: number; +} + +export interface VuuUIMessageOutSubscribe extends ServerProxySubscribeMessage { + type: "subscribe"; +} + +export interface VuuUIMessageOutUnsubscribe { + type: "unsubscribe"; + viewport: string; +} +export interface VuuUIMessageOutSuspend { + type: "suspend"; + viewport: string; +} +export interface VuuUIMessageOutResume { + type: "resume"; + viewport: string; +} + +export interface ViewportMessageOut { + viewport: string; +} + +export interface RequestMessage { + requestId: string; +} + +export interface VuuUIMessageOutColumns extends ViewportMessageOut { + type: "setColumns"; + columns: string[]; +} +export interface VuuUIMessageOutViewRange extends ViewportMessageOut { + type: "setViewRange"; + range: { + from: number; + to: number; + }; +} +export interface VuuUIMessageOutAggregate extends ViewportMessageOut { + aggregations: VuuAggregation[]; + type: "aggregate"; +} +export interface VuuUIMessageOutCloseTreeNode extends ViewportMessageOut { + key: string; + type: "closeTreeNode"; +} +export interface VuuUIMessageOutCreateLink extends ViewportMessageOut { + childColumnName: string; + parentColumnName: string; + parentClientVpId: string; + type: "createLink"; +} +export interface VuuUIMessageOutRemoveLink extends ViewportMessageOut { + type: "removeLink"; +} +export interface VuuUIMessageOutSetTitle extends ViewportMessageOut { + title: string; + type: "setTitle"; +} + +export interface VuuUIMessageOutDisable extends ViewportMessageOut { + type: "disable"; +} +export interface VuuUIMessageOutEnable extends ViewportMessageOut { + type: "enable"; +} +export interface VuuUIMessageOutOpenTreeNode extends ViewportMessageOut { + key: string; + type: "openTreeNode"; +} +export interface VuuUIMessageOutResume extends ViewportMessageOut { + type: "resume"; +} + +export interface VuuUIMessageOutSelect extends ViewportMessageOut { + selected: Selection; + type: "select"; +} +export interface VuuUIMessageOutSelectAll extends ViewportMessageOut { + type: "selectAll"; +} +export interface VuuUIMessageOutSelectNone extends ViewportMessageOut { + type: "selectNone"; +} + +export interface VuuUIMessageOutSort extends ViewportMessageOut { + sort: VuuSort; + type: "sort"; +} +export interface VuuUIMessageOutSuspend extends ViewportMessageOut { + type: "suspend"; +} + +export interface VuuUIMessageOutFilter extends ViewportMessageOut { + filter: DataSourceFilter; + type: "filter"; +} +export interface VuuUIMessageOutGroupby extends ViewportMessageOut { + groupBy: VuuGroupBy; + type: "groupBy"; +} + +export interface VuuUIMessageOutConfig extends ViewportMessageOut { + config: WithFullConfig; + type: "config"; +} + +export type VuuUIMessageOutViewport = + | VuuUIMessageOutAggregate + | VuuUIMessageOutCloseTreeNode + | VuuUIMessageOutColumns + | VuuUIMessageOutConfig + | VuuUIMessageOutCreateLink + | VuuUIMessageOutFilter + | VuuUIMessageOutDisable + | VuuUIMessageOutEnable + | VuuUIMessageOutGroupby + | VuuUIMessageOutOpenTreeNode + | VuuUIMessageOutRemoveLink + | VuuUIMessageOutResume + | VuuUIMessageOutSelect + | VuuUIMessageOutSelectAll + | VuuUIMessageOutSelectNone + | VuuUIMessageOutSetTitle + | VuuUIMessageOutSuspend + | VuuUIMessageOutSort + | VuuUIMessageOutViewRange; + +export interface TypeAheadRpcRequest { + method: TypeAheadMethod; + params: [VuuTable, ...string[]]; + type: "RPC_CALL"; +} + +export type WithRequestId = T & { requestId: string }; + +export type VuuUIMessageOut = + | VuuUIMessageOutConnect + | VuuUIMessageOutSubscribe + | VuuUIMessageOutUnsubscribe + | VuuUIMessageOutViewport + | WithRequestId + | WithRequestId; diff --git a/vuu-ui/packages/vuu-data/src/data-source.ts b/vuu-ui/packages/vuu-data/src/data-source.ts deleted file mode 100644 index 6fcd40d5e..000000000 --- a/vuu-ui/packages/vuu-data/src/data-source.ts +++ /dev/null @@ -1,604 +0,0 @@ -import { DataSourceFilter, DataSourceRow } from "@finos/vuu-data-types"; -import { - ColumnDescriptor, - SelectionChangeHandler, -} from "@finos/vuu-table-types"; -import { - ClientToServerEditRpc, - ClientToServerMenuRPC, - ClientToServerViewportRpcCall, - LinkDescriptorWithLabel, - VuuAggregation, - VuuColumns, - VuuDataRowDto, - VuuFilter, - VuuGroupBy, - VuuLinkDescriptor, - VuuMenu, - VuuRange, - VuuRowDataItemType, - VuuSort, - VuuTable, -} from "@finos/vuu-protocol-types"; -import { EventEmitter } from "@finos/vuu-utils"; -import { TableSchema } from "./message-utils"; -import { - MenuRpcResponse, - ViewportRpcResponse, - VuuUIMessageInRPCEditReject, - VuuUIMessageInRPCEditResponse, -} from "./vuuUIMessageTypes"; - -export interface MessageWithClientViewportId { - clientViewportId: string; -} -// GridModelActions -export interface DataSourceAggregateMessage - extends MessageWithClientViewportId { - aggregations: VuuAggregation[]; - type: "aggregate"; -} - -export type DataUpdateMode = "batch" | "update" | "size-only"; -export interface DataSourceDataMessage extends MessageWithClientViewportId { - mode: DataUpdateMode; - rows?: DataSourceRow[]; - size?: number; - type: "viewport-update"; -} - -export interface DataSourceDataSizeMessage extends MessageWithClientViewportId { - mode: "size-only"; - size: number; - type: "viewport-update"; -} - -export interface DataSourceDebounceRequest extends MessageWithClientViewportId { - type: "debounce-begin"; -} - -export const isSizeOnly = ( - message: DataSourceCallbackMessage -): message is DataSourceDataSizeMessage => - message.type === "viewport-update" && message.mode === "size-only"; - -export interface DataSourceDisabledMessage extends MessageWithClientViewportId { - type: "disabled"; -} - -export interface DataSourceEnabledMessage extends MessageWithClientViewportId { - type: "enabled"; -} - -export interface DataSourceColumnsMessage extends MessageWithClientViewportId { - type: "columns"; - columns: VuuColumns; -} -export interface DataSourceFilterMessage extends MessageWithClientViewportId { - type: "filter"; - filter: DataSourceFilter; -} -export interface DataSourceGroupByMessage extends MessageWithClientViewportId { - type: "groupBy"; - groupBy: VuuGroupBy | undefined; -} -export interface DataSourceSetConfigMessage - extends MessageWithClientViewportId { - type: "config"; - config: WithFullConfig; -} - -export interface DataSourceMenusMessage extends MessageWithClientViewportId { - type: "vuu-menu"; - menu: VuuMenu; -} - -export interface DataSourceSortMessage extends MessageWithClientViewportId { - type: "sort"; - sort: VuuSort; -} - -export type DataSourceConfigMessage = - | DataSourceAggregateMessage - | DataSourceColumnsMessage - | DataSourceFilterMessage - | DataSourceGroupByMessage - | DataSourceSortMessage - | DataSourceSetConfigMessage; - -export const toDataSourceConfig = ( - message: DataSourceConfigMessage -): DataSourceConfig => { - switch (message.type) { - case "aggregate": - return { aggregations: message.aggregations }; - case "columns": - return { columns: message.columns }; - case "filter": - return { filter: message.filter }; - case "groupBy": - return { groupBy: message.groupBy }; - case "sort": - return { sort: message.sort }; - case "config": - return message.config; - } -}; - -const exactlyTheSame = (a: unknown, b: unknown) => { - if (a === b) { - return true; - } else if (a === undefined && b === undefined) { - return true; - } else { - return false; - } -}; - -type DataConfigPredicate = ( - config: DataSourceConfig, - newConfig: DataSourceConfig -) => boolean; - -const equivalentFilter: DataConfigPredicate = ( - { filter: f1 }, - { filter: f2 } -) => - (f1 === undefined && f2?.filter === "") || - (f2 === undefined && f1?.filter === ""); - -export const filterChanged: DataConfigPredicate = (c1, c2) => { - if (equivalentFilter(c1, c2)) { - return false; - } else { - return c1.filter?.filter !== c2.filter?.filter; - } -}; - -const equivalentSort: DataConfigPredicate = ({ sort: s1 }, { sort: s2 }) => - (s1 === undefined && s2?.sortDefs.length === 0) || - (s2 === undefined && s1?.sortDefs.length === 0); - -const sortChanged: DataConfigPredicate = (config, newConfig) => { - const { sort: s1 } = config; - const { sort: s2 } = newConfig; - if (exactlyTheSame(s1, s2) || equivalentSort(config, newConfig)) { - return false; - } else if (s1 === undefined || s2 === undefined) { - return true; - } else if (s1?.sortDefs.length !== s2?.sortDefs.length) { - return true; - } - return s1.sortDefs.some( - ({ column, sortType }, i) => - column !== s2.sortDefs[i].column || sortType !== s2.sortDefs[i].sortType - ); -}; - -export const hasGroupBy = (config?: DataSourceConfig): config is WithGroupBy => - config !== undefined && - config.groupBy !== undefined && - config.groupBy.length > 0; - -export const hasFilter = (config?: DataSourceConfig): config is WithFilter => - config?.filter !== undefined && config.filter.filter.length > 0; - -export const hasSort = (config?: DataSourceConfig): config is WithSort => - config?.sort !== undefined && - Array.isArray(config.sort?.sortDefs) && - config.sort.sortDefs.length > 0; - -const equivalentGroupBy: DataConfigPredicate = ( - { groupBy: val1 }, - { groupBy: val2 } -) => - (val1 === undefined && val2?.length === 0) || - (val2 === undefined && val1?.length === 0); - -export const groupByChanged: DataConfigPredicate = (config, newConfig) => { - const { groupBy: g1 } = config; - const { groupBy: g2 } = newConfig; - if (exactlyTheSame(g1, g2) || equivalentGroupBy(config, newConfig)) { - return false; - } else if (g1 === undefined || g2 === undefined) { - return true; - } else if (g1?.length !== g2?.length) { - return true; - } - return g1.some((column, i) => column !== g2?.[i]); -}; - -const equivalentColumns: DataConfigPredicate = ( - { columns: cols1 }, - { columns: cols2 } -) => - (cols1 === undefined && cols2?.length === 0) || - (cols2 === undefined && cols1?.length === 0); - -export const columnsChanged: DataConfigPredicate = (config, newConfig) => { - const { columns: cols1 } = config; - const { columns: cols2 } = newConfig; - - if (exactlyTheSame(cols1, cols2) || equivalentColumns(config, newConfig)) { - return false; - } else if (cols1 === undefined || cols2 === undefined) { - return true; - } else if (cols1?.length !== cols2?.length) { - return true; - } - return cols1.some((column, i) => column !== cols2?.[i]); -}; - -const equivalentAggregations: DataConfigPredicate = ( - { aggregations: agg1 }, - { aggregations: agg2 } -) => - (agg1 === undefined && agg2?.length === 0) || - (agg2 === undefined && agg1?.length === 0); - -const aggregationsChanged: DataConfigPredicate = (config, newConfig) => { - const { aggregations: agg1 } = config; - const { aggregations: agg2 } = newConfig; - if (exactlyTheSame(agg1, agg2) || equivalentAggregations(config, newConfig)) { - return false; - } else if (agg1 === undefined || agg2 === undefined) { - return true; - } else if (agg1.length !== agg2.length) { - return true; - } - return agg1.some( - ({ column, aggType }, i) => - column !== agg2[i].column || aggType !== agg2[i].aggType - ); -}; -const visualLinkChanged: DataConfigPredicate = () => { - // TODO - return false; -}; - -export const configChanged = ( - config: DataSourceConfig | undefined, - newConfig: DataSourceConfig | undefined -) => { - if (exactlyTheSame(config, newConfig)) { - return false; - } - - if (config === undefined || newConfig === undefined) { - return true; - } - - return ( - columnsChanged(config, newConfig) || - filterChanged(config, newConfig) || - sortChanged(config, newConfig) || - groupByChanged(config, newConfig) || - aggregationsChanged(config, newConfig) || - visualLinkChanged(config, newConfig) - ); -}; - -export interface DataSourceSubscribedMessage - extends MessageWithClientViewportId, - MessageWithClientViewportId { - aggregations: VuuAggregation[]; - columns: VuuColumns; - filter: DataSourceFilter; - groupBy: VuuGroupBy; - range: VuuRange; - sort: VuuSort; - tableSchema: Readonly; - type: "subscribed"; -} - -export interface DataSourceVisualLinkCreatedMessage - extends MessageWithClientViewportId { - colName: string; - parentViewportId: string; - parentColName: string; - type: "vuu-link-created"; -} - -export interface DataSourceVisualLinkRemovedMessage - extends MessageWithClientViewportId { - type: "vuu-link-removed"; -} - -export interface DataSourceVisualLinksMessage - extends MessageWithClientViewportId { - type: "vuu-links"; - links: VuuLinkDescriptor[]; -} - -export type VuuFeatureMessage = - | DataSourceMenusMessage - | DataSourceVisualLinksMessage; - -export type VuuFeatureInvocationMessage = - | DataSourceVisualLinkCreatedMessage - | DataSourceVisualLinkRemovedMessage; - -export type DataSourceCallbackMessage = - | DataSourceConfigMessage - | DataSourceColumnsMessage - | DataSourceDataMessage - | DataSourceDebounceRequest - | DataSourceDisabledMessage - | DataSourceEnabledMessage - | DataSourceMenusMessage - | DataSourceSubscribedMessage - | DataSourceVisualLinkCreatedMessage - | DataSourceVisualLinkRemovedMessage - | DataSourceVisualLinksMessage; - -const datasourceMessages = [ - "config", - "aggregate", - "viewport-update", - "columns", - "debounce-begin", - "disabled", - "enabled", - "filter", - "groupBy", - "vuu-link-created", - "vuu-link-removed", - "vuu-links", - "vuu-menu", - "sort", - "subscribed", -]; - -export type ConfigChangeColumnsMessage = { - type: "columns"; - columns?: ColumnDescriptor[]; -}; - -export type ConfigChangeMessage = - | ConfigChangeColumnsMessage - | DataSourceAggregateMessage - | DataSourceFilterMessage - | DataSourceGroupByMessage - | DataSourceSortMessage - | DataSourceVisualLinkCreatedMessage - | DataSourceVisualLinkRemovedMessage; - -export type ConfigChangeHandler = (msg: ConfigChangeMessage) => void; - -export const shouldMessageBeRoutedToDataSource = ( - message: unknown -): message is DataSourceCallbackMessage => { - const type = (message as DataSourceCallbackMessage).type; - return datasourceMessages.includes(type); -}; - -export const isDataSourceConfigMessage = ( - message: DataSourceCallbackMessage -): message is DataSourceConfigMessage => - ["config", "aggregate", "columns", "filter", "groupBy", "sort"].includes( - message.type - ); - -/** - * Described the configuration values that should typically be - * persisted across sessions. - */ -export interface WithFullConfig { - readonly aggregations: VuuAggregation[]; - readonly columns: string[]; - readonly filter: DataSourceFilter; - readonly groupBy: VuuGroupBy; - readonly sort: VuuSort; - readonly visualLink?: LinkDescriptorWithLabel; -} - -export const NoFilter: VuuFilter = { filter: "" }; -export const NoSort: VuuSort = { sortDefs: [] }; - -export const vanillaConfig: WithFullConfig = { - aggregations: [], - columns: [], - filter: NoFilter, - groupBy: [], - sort: NoSort, -}; - -export const withConfigDefaults = ( - config: DataSourceConfig -): WithFullConfig & { visualLink?: LinkDescriptorWithLabel } => { - if ( - config.aggregations && - config.columns && - config.filter && - config.groupBy && - config.sort - ) { - return config as WithFullConfig; - } else { - const { - aggregations = [], - columns = [], - filter = { filter: "" }, - groupBy = [], - sort = { sortDefs: [] }, - visualLink, - } = config; - - return { - aggregations, - columns, - filter, - groupBy, - sort, - visualLink, - }; - } -}; - -export interface DataSourceConfig extends Partial { - visualLink?: LinkDescriptorWithLabel; -} - -export interface WithGroupBy extends DataSourceConfig { - groupBy: VuuGroupBy; -} -export interface WithFilter extends DataSourceConfig { - filter: DataSourceFilter; -} -export interface WithSort extends DataSourceConfig { - sort: VuuSort; -} - -export interface DataSourceConstructorProps extends DataSourceConfig { - bufferSize?: number; - table: VuuTable; - title?: string; - viewport?: string; -} - -export interface SubscribeProps { - viewport?: string; - columns?: string[]; - aggregations?: VuuAggregation[]; - range?: VuuRange; - sort?: VuuSort; - groupBy?: VuuGroupBy; - filter?: DataSourceFilter; - title?: string; -} - -export type SubscribeCallback = (message: DataSourceCallbackMessage) => void; -export type OptimizeStrategy = "none" | "throttle" | "debounce"; - -export type DataSourceEvents = { - config: (config: DataSourceConfig | undefined, confirmed?: boolean) => void; - optimize: (optimize: OptimizeStrategy) => void; - range: (range: VuuRange) => void; - resize: (size: number) => void; -}; - -/** - * return Promise indicates success - * return Promise indicates failure - */ -export type DataSourceEditHandler = ( - row: DataSourceRow, - columnName: string, - value: VuuRowDataItemType -) => Promise; - -export type DataSourceDeleteHandler = (key: string) => Promise; -export type DataSourceInsertHandler = ( - key: string, - data: VuuDataRowDto -) => Promise; - -export type RpcResponse = - | MenuRpcResponse - | VuuUIMessageInRPCEditReject - | VuuUIMessageInRPCEditResponse - | ViewportRpcResponse; - -export type RpcResponseHandler = (response: RpcResponse) => boolean; - -export type RowSearchPredicate = (row: DataSourceRow) => boolean; - -export type DataSourceStatus = - | "disabled" - | "disabling" - | "enabled" - | "enabling" - | "initialising" - | "subscribing" - | "subscribed" - | "suspended" - | "unsubscribed"; - -export interface TypeaheadSuggestionProvider { - getTypeaheadSuggestions: ( - columnName: string, - pattern?: string - ) => Promise; -} - -export const isTypeaheadSuggestionProvider = ( - source: unknown -): source is TypeaheadSuggestionProvider => - typeof (source as TypeaheadSuggestionProvider)["getTypeaheadSuggestions"] === - "function"; - -export interface DataSource - extends EventEmitter, - Partial { - aggregations: VuuAggregation[]; - applyEdit: DataSourceEditHandler; - /** - * set config without triggering config event. Use this method when initialising - * a dataSource that has been restored from session state. The dataSource will - * not yet be subscribed. Triggering the config event is unnecessary and might - * cause a React exception if the event were to cause a render. - * @param config DataSourceConfig - * @returns true if config has been applied (will not be if existig config is same) - */ - applyConfig: (config: DataSourceConfig) => true | undefined; - closeTreeNode: (key: string, cascade?: boolean) => void; - columns: string[]; - config: DataSourceConfig; - status: DataSourceStatus; - /** - * - * Similar to disable but intended for pauses of very short duration (default is 3 seconds). Although - * the dataSource will stop sending messages until resumed, it will not disconnect from a remote server. - * It will preserve subscription to the remote server and continue to apply updates to cached data. It - * just won't send updates through to the UI thread (until resumed). Useful in edge cases such as where a - * component is dragged to a new location. When dropped, the component will be unmounted and very quickly - * remounted by React. For the duration of this operation, we suspend updates . Updating an unmounted - * React component would cause a React error. - * If an suspend is requested and not resumed within 3 seconds, it will automatically be promoted to a disable., - */ - suspend?: () => void; - resume?: () => void; - - deleteRow?: DataSourceDeleteHandler; - - /** - * For a dataSource that has been previously disabled and is currently in disabled state , this will restore - * the subscription to active status. Fresh data will be dispatched to client. The enable call optionally - * accepts the same subscribe callback as subscribe. This allows a completely new instance of a component to - * assume ownership of a subscription and receive all messages. - */ - enable?: (callback?: SubscribeCallback) => void; - /** - * Disables this subscription. A datasource will send no further messages until re-enabled. Example usage - * might be for a component displayed within a set of Tabs. If user switches to another tab, the dataSource - * of the component that is no longer visible can be disabled until it is made visible again. - */ - disable?: () => void; - filter: DataSourceFilter; - groupBy: VuuGroupBy; - insertRow?: DataSourceInsertHandler; - links?: LinkDescriptorWithLabel[]; - menu?: VuuMenu; - menuRpcCall: ( - rpcRequest: Omit | ClientToServerEditRpc - ) => Promise; - rpcCall?: ( - message: Omit - ) => Promise; - openTreeNode: (key: string) => void; - range: VuuRange; - select: SelectionChangeHandler; - readonly selectedRowsCount: number; - readonly size: number; - sort: VuuSort; - subscribe: ( - props: SubscribeProps, - callback: SubscribeCallback - ) => Promise; - table?: VuuTable; - readonly tableSchema?: TableSchema; - title?: string; - unsubscribe: () => void; - viewport?: string; - visualLink?: LinkDescriptorWithLabel; -} diff --git a/vuu-ui/packages/vuu-data/src/inlined-worker.js b/vuu-ui/packages/vuu-data/src/inlined-worker.js deleted file mode 100644 index 3d014b01e..000000000 --- a/vuu-ui/packages/vuu-data/src/inlined-worker.js +++ /dev/null @@ -1,8 +0,0 @@ -export const workerSourceCode = ` -var de=(s,e,t)=>{if(!e.has(s))throw TypeError("Cannot "+t)};var d=(s,e,t)=>(de(s,e,"read from private field"),t?t.call(s):e.get(s)),k=(s,e,t)=>{if(e.has(s))throw TypeError("Cannot add the same private member more than once");e instanceof WeakSet?e.add(s):e.set(s,t)},ge=(s,e,t,n)=>(de(s,e,"write to private field"),n?n.call(s,t):e.set(s,t),t);function fe(s,e,t=[],n=[]){for(let r=0,o=s.length;r{var e,t;if(((e=globalThis.document)==null?void 0:e.cookie)!==void 0)return(t=globalThis.document.cookie.split("; ").find(n=>n.startsWith(\`\${s}=\`)))==null?void 0:t.split("=")[1]};function K({from:s,to:e},t=0,n=Number.MAX_SAFE_INTEGER){if(t===0)return ns>=e&&s=this.to||ts.replaceAll("/",".")},"dd/mm/yyyy":{locale:"en-GB",options:{...I}},"dd MMM yyyy":{locale:"en-GB",options:{...I,month:"short"}},"dd MMMM yyyy":{locale:"en-GB",options:{...I,month:"long"}},"mm/dd/yyyy":{locale:"en-US",options:{...I}},"MMM dd, yyyy":{locale:"en-US",options:{...I,month:"short"}},"MMMM dd, yyyy":{locale:"en-US",options:{...I,month:"long"}}},Rn={...ut,...at};var ct=["error","warn","info","debug"],pt=s=>typeof s=="string"&&ct.includes(s),dt="error",A=()=>{},gt="error",{loggingLevel:U=gt}=ft(),w=s=>{let e=U==="debug",t=e||U==="info",n=t||U==="warn",r=n||U==="error",o=t?p=>console.info(\`[\${s}] \${p}\`):A,i=n?p=>console.warn(\`[\${s}] \${p}\`):A,u=e?p=>console.debug(\`[\${s}] \${p}\`):A;return{errorEnabled:r,error:r?p=>console.error(\`[\${s}] \${p}\`):A}};function ft(){return typeof loggingSettings<"u"?loggingSettings:{loggingLevel:mt()}}function mt(){let s=me("vuu-logging-level");return pt(s)?s:dt}var{debug:ht,debugEnabled:Ct}=w("range-monitor"),F=class{constructor(e){this.source=e;this.range={from:0,to:0};this.timestamp=0}isSet(){return this.timestamp!==0}set({from:e,to:t}){let{timestamp:n}=this;if(this.range.from=e,this.range.to=t,this.timestamp=performance.now(),n)Ct&&ht(\`<\${this.source}> [\${e}-\${t}], \${(this.timestamp-n).toFixed(0)} ms elapsed\`);else return 0}};function be(s){return Array.isArray(s)}function bt(s){return!Array.isArray(s)}var R,Re=class{constructor(){k(this,R,new Map)}addListener(e,t){let n=d(this,R).get(e);n?be(n)?n.push(t):bt(n)&&d(this,R).set(e,[n,t]):d(this,R).set(e,t)}removeListener(e,t){if(!d(this,R).has(e))return;let n=d(this,R).get(e),r=-1;if(n===t)d(this,R).delete(e);else if(Array.isArray(n)){for(let o=length;o-- >0;)if(n[o]===t){r=o;break}if(r<0)return;n.length===1?(n.length=0,d(this,R).delete(e)):n.splice(r,1)}}removeAllListeners(e){e&&d(this,R).has(e)?d(this,R).delete(e):e===void 0&&d(this,R).clear()}emit(e,...t){if(d(this,R)){let n=d(this,R).get(e);n&&this.invokeHandler(n,t)}}once(e,t){let n=(...r)=>{this.removeListener(e,n),t(...r)};this.on(e,n)}on(e,t){this.addListener(e,t)}hasListener(e,t){let n=d(this,R).get(e);return Array.isArray(n)?n.includes(t):n===t}invokeHandler(e,t){if(be(e))e.slice().forEach(n=>this.invokeHandler(n,t));else switch(t.length){case 0:e();break;case 1:e(t[0]);break;case 2:e(t[0],t[1]);break;default:e.call(null,...t)}}};R=new WeakMap;var N=String.fromCharCode(8200),f=String.fromCharCode(8199);var Ln={DIGIT:f,TWO_DIGITS:f+f,THREE_DIGITS:f+f+f,FULL_PADDING:[null,N+f,N+f+f,N+f+f+f,N+f+f+f+f]};var _n=f+f+f+f+f+f+f+f+f;var{COUNT:rr}=V;var W=class{constructor(e){this.keys=new Map,this.free=[],this.nextKeyValue=0,this.reset(e)}next(){return this.free.length>0?this.free.pop():this.nextKeyValue++}reset({from:e,to:t}){this.keys.forEach((r,o)=>{(o=t)&&(this.free.push(r),this.keys.delete(o))});let n=t-e;this.keys.size+this.free.length>n&&(this.free.length=Math.max(0,n-this.keys.size));for(let r=e;rthis.keys.size&&(this.nextKeyValue=this.keys.size)}keyFor(e){let t=this.keys.get(e);if(t===void 0)throw console.log(\`key not found - keys: \${this.toDebugString()} - free : \${this.free.join(",")} - \`),Error(\`KeySet, no key found for rowIndex \${e}\`);return t}toDebugString(){return Array.from(this.keys.entries()).map((e,t)=>\`\${e}=>\${t}\`).join(",")}};var{IDX:pr}=V;var{SELECTED:fr}=V,M={False:0,True:1,First:2,Last:4};var Rt=(s,e)=>e>=s[0]&&e<=s[1],Tt=M.True+M.First+M.Last,yt=M.True+M.First,St=M.True+M.Last,Q=(s,e)=>{for(let t of s)if(typeof t=="number"){if(t===e)return Tt}else if(Rt(t,e))return e===t[0]?yt:e===t[1]?St:M.True;return M.False};var Te=s=>{if(s.every(t=>typeof t=="number"))return s;let e=[];for(let t of s)if(typeof t=="number")e.push(t);else for(let n=t[0];n<=t[1];n++)e.push(n);return e};var wt=(()=>{let s=0,e=()=>\`0000\${(Math.random()*36**4<<0).toString(36)}\`.slice(-4);return()=>(s+=1,\`u\${e()}\${s}\`)})();var{debug:Ks,debugEnabled:Qs,error:we,info:E,infoEnabled:vt,warn:P}=w("websocket-connection"),Ee="ws",It=s=>s.startsWith(Ee+"://")||s.startsWith(Ee+"s://"),xe={},Z=Symbol("setWebsocket"),q=Symbol("connectionCallback");async function ve(s,e,t,n=10,r=5){return xe[s]={status:"connecting",connect:{allowed:r,remaining:r},reconnect:{allowed:n,remaining:n}},Ie(s,e,t)}async function Y(s){throw Error("connection broken")}async function Ie(s,e,t,n){let{status:r,connect:o,reconnect:i}=xe[s],u=r==="connecting"?o:i;try{t({type:"connection-status",status:"connecting"});let c=typeof n<"u",p=await Pt(s,e);console.info("%c\u26A1 %cconnected","font-size: 24px;color: green;font-weight: bold;","color:green; font-size: 14px;"),n!==void 0&&n[Z](p);let a=n!=null?n:new ee(p,s,e,t),l=c?"reconnected":"connection-open-awaiting-session";return t({type:"connection-status",status:l}),a.status=l,u.remaining=u.allowed,a}catch{let p=--u.remaining>0;if(t({type:"connection-status",status:"disconnected",reason:"failed to connect",retry:p}),p)return Dt(s,e,t,n,2e3);throw Error("Failed to establish connection")}}var Dt=(s,e,t,n,r)=>new Promise(o=>{setTimeout(()=>{o(Ie(s,e,t,n))},r)}),Pt=(s,e)=>new Promise((t,n)=>{let r=It(s)?s:\`wss://\${s}\`;vt&&e!==void 0&&E(\`WebSocket Protocol \${e==null?void 0:e.toString()}\`);let o=new WebSocket(r,e);o.onopen=()=>t(o),o.onerror=i=>n(i)}),Ve=()=>{P==null||P("Connection cannot be closed, socket not yet opened")},Me=s=>{P==null||P(\`Message cannot be sent, socket closed \${s.body.type}\`)},Lt=s=>{try{return JSON.parse(s)}catch{throw Error(\`Error parsing JSON response from server \${s}\`)}},ee=class{constructor(e,t,n,r){this.close=Ve;this.requiresLogin=!0;this.send=Me;this.status="ready";this.messagesCount=0;this.connectionMetricsInterval=null;this.handleWebsocketMessage=e=>{let t=Lt(e.data);this.messagesCount+=1,this[q](t)};this.url=t,this.protocol=n,this[q]=r,this[Z](e)}reconnect(){Y(this)}[(q,Z)](e){let t=this[q];e.onmessage=o=>{this.status="connected",e.onmessage=this.handleWebsocketMessage,this.handleWebsocketMessage(o)},this.connectionMetricsInterval=setInterval(()=>{t({type:"connection-metrics",messagesLength:this.messagesCount}),this.messagesCount=0},2e3),e.onerror=()=>{we("\u26A1 connection error"),t({type:"connection-status",status:"disconnected",reason:"error"}),this.connectionMetricsInterval&&(clearInterval(this.connectionMetricsInterval),this.connectionMetricsInterval=null),this.status==="connection-open-awaiting-session"?we("Websocket connection lost before Vuu session established, check websocket configuration"):this.status!=="closed"&&(Y(this),this.send=r)},e.onclose=()=>{E==null||E("\u26A1 connection close"),t({type:"connection-status",status:"disconnected",reason:"close"}),this.connectionMetricsInterval&&(clearInterval(this.connectionMetricsInterval),this.connectionMetricsInterval=null),this.status!=="closed"&&(Y(this),this.send=r)};let n=o=>{e.send(JSON.stringify(o))},r=o=>{E==null||E(\`TODO queue message until websocket reconnected \${o.body.type}\`)};this.send=n,this.close=()=>{this.status="closed",e.close(),this.close=Ve,this.send=Me,E==null||E("close websocket")}}};var _t=["VIEW_PORT_MENUS_SELECT_RPC","VIEW_PORT_MENU_TABLE_RPC","VIEW_PORT_MENU_ROW_RPC","VIEW_PORT_MENU_CELL_RPC","VP_EDIT_CELL_RPC","VP_EDIT_ROW_RPC","VP_EDIT_ADD_ROW_RPC","VP_EDIT_DELETE_CELL_RPC","VP_EDIT_DELETE_ROW_RPC","VP_EDIT_SUBMIT_FORM_RPC"],De=s=>_t.includes(s.type),Pe=s=>s.type==="VIEW_PORT_RPC_CALL",\$=({requestId:s,...e})=>[s,e],Le=s=>{let e=s.at(0);if(e.updateType==="SIZE"){if(s.length===1)return s;e=s.at(1)}let t=s.at(-1);return[e,t]},_e=s=>{let e={};for(let t of s)(e[t.viewPortId]||(e[t.viewPortId]=[])).push(t);return e};var te=({columns:s,dataTypes:e,key:t,table:n})=>({table:n,columns:s.map((r,o)=>({name:r,serverDataType:e[o]})),key:t});var Oe=s=>s.type==="connection-status",ke=s=>s.type==="connection-metrics";var Ae=s=>"viewport"in s,Ue=s=>s.type==="VIEW_PORT_MENU_RESP"&&s.action!==null&&G(s.action.table),G=s=>s!==null&&typeof s=="object"&&"table"in s&&"module"in s?s.table.startsWith("session"):!1;var Fe="CHANGE_VP_SUCCESS";var Ne="CLOSE_TREE_NODE",We="CLOSE_TREE_SUCCESS";var qe="CREATE_VP",\$e="DISABLE_VP",Ge="DISABLE_VP_SUCCESS";var Be="ENABLE_VP",He="ENABLE_VP_SUCCESS";var ne="GET_VP_VISUAL_LINKS",je="GET_VIEW_PORT_MENUS";var ze="HB",Je="HB_RESP",Ke="LOGIN",Qe="OPEN_TREE_NODE",Xe="OPEN_TREE_SUCCESS";var Ye="REMOVE_VP";var Ze="SET_SELECTION_SUCCESS";var tt=s=>{switch(s){case"TypeAheadRpcHandler":return"TYPEAHEAD";default:return"SIMUL"}};var nt=[],T=w("array-backed-moving-window");function Ot(s,e){if(!e||e.data.length!==s.data.length||e.sel!==s.sel)return!1;for(let t=0;t{var t;if((t=T.info)==null||t.call(T,\`setRowCount \${e}\`),e{let n=this.bufferSize*.25;return d(this,h).to-t0&&e-d(this,h).from0&&this.clientRange.from+this.rowsWithinRange===this.rowCount}outOfRange(e,t){let{from:n,to:r}=this.range;if(t=r)return!0}setAtIndex(e){let{rowIndex:t}=e,n=t-d(this,h).from;if(Ot(e,this.internalData[n]))return!1;let r=this.isWithinClientRange(t);return(r||this.isWithinRange(t))&&(!this.internalData[n]&&r&&(this.rowsWithinRange+=1),this.internalData[n]=e),r}getAtIndex(e){return d(this,h).isWithin(e)&&this.internalData[e-d(this,h).from]!=null?this.internalData[e-d(this,h).from]:void 0}isWithinRange(e){return d(this,h).isWithin(e)}isWithinClientRange(e){return this.clientRange.isWithin(e)}setClientRange(e,t){var p;(p=T.debug)==null||p.call(T,\`setClientRange \${e} - \${t}\`);let n=this.clientRange.from,r=Math.min(this.clientRange.to,this.rowCount);if(e===n&&t===r)return[!1,nt];let o=this.clientRange.copy();this.clientRange.from=e,this.clientRange.to=t,this.rowsWithinRange=0;for(let a=e;ao.to){let a=Math.max(e,o.to);i=this.internalData.slice(a-u,t-u)}else{let a=Math.min(o.from,t);i=this.internalData.slice(e-u,a-u)}return[this.bufferBreakout(e,t),i]}setRange(e,t){var n,r;if(e!==d(this,h).from||t!==d(this,h).to){(n=T.debug)==null||n.call(T,\`setRange \${e} - \${t}\`);let[o,i]=d(this,h).overlap(e,t),u=new Array(t-e);this.rowsWithinRange=0;for(let c=o;c=0;o--)if(e[o]!==void 0){r=e[o];break}return n&&r?[n.rowIndex,r.rowIndex]:[-1,-1]}};h=new WeakMap;var kt=[],{debug:C,debugEnabled:H,error:At,info:g,infoEnabled:Ut,warn:L}=w("viewport"),Ft=({rowKey:s,updateType:e})=>e==="U"&&!s.startsWith("\$root"),j=[void 0,void 0],Nt={count:0,mode:void 0,size:0,ts:0},z=class{constructor({aggregations:e,bufferSize:t=50,columns:n,filter:r,groupBy:o=[],table:i,range:u,sort:c,title:p,viewport:a,visualLink:l},m){this.batchMode=!0;this.hasUpdates=!1;this.pendingUpdates=[];this.pendingOperations=new Map;this.pendingRangeRequests=[];this.rowCountChanged=!1;this.selectedRows=[];this.useBatchMode=!0;this.lastUpdateStatus=Nt;this.updateThrottleTimer=void 0;this.rangeMonitor=new F("ViewPort");this.disabled=!1;this.isTree=!1;this.status="";this.suspended=!1;this.suspendTimer=null;this.setLastSizeOnlyUpdateSize=e=>{this.lastUpdateStatus.size=e};this.setLastUpdate=e=>{let{ts:t,mode:n}=this.lastUpdateStatus,r=0;if(n===e){let o=Date.now();this.lastUpdateStatus.count+=1,this.lastUpdateStatus.ts=o,r=t===0?0:o-t}else this.lastUpdateStatus.count=1,this.lastUpdateStatus.ts=0,r=0;return this.lastUpdateStatus.mode=e,r};this.rangeRequestAlreadyPending=e=>{let{bufferSize:t}=this,n=t*.25,{from:r}=e;for(let{from:o,to:i}of this.pendingRangeRequests)if(r>=o&&r{this.updateThrottleTimer=void 0,this.lastUpdateStatus.count=3,this.postMessageToClient({clientViewportId:this.clientViewportId,mode:"size-only",size:this.lastUpdateStatus.size,type:"viewport-update"})};this.shouldThrottleMessage=e=>{let t=this.setLastUpdate(e);return e==="size-only"&&t>0&&t<500&&this.lastUpdateStatus.count>3};this.throttleMessage=e=>this.shouldThrottleMessage(e)?(g==null||g("throttling updates setTimeout to 2000"),this.updateThrottleTimer===void 0&&(this.updateThrottleTimer=setTimeout(this.sendThrottledSizeMessage,2e3)),!0):(this.updateThrottleTimer!==void 0&&(clearTimeout(this.updateThrottleTimer),this.updateThrottleTimer=void 0),!1);this.getNewRowCount=()=>{if(this.rowCountChanged&&this.dataWindow)return this.rowCountChanged=!1,this.dataWindow.rowCount};this.aggregations=e,this.bufferSize=t,this.clientRange=u,this.clientViewportId=a,this.columns=n,this.filter=r,this.groupBy=o,this.keys=new W(u),this.pendingLinkedParent=l,this.table=i,this.sort=c,this.title=p,Ut&&(g==null||g(\`constructor #\${a} \${i.table} bufferSize=\${t}\`)),this.dataWindow=new B(this.clientRange,u,this.bufferSize),this.postMessageToClient=m}get hasUpdatesToProcess(){return this.suspended?!1:this.rowCountChanged||this.hasUpdates}get size(){var e;return(e=this.dataWindow.rowCount)!=null?e:0}subscribe(){let{filter:e}=this.filter;return this.status=this.status==="subscribed"?"resubscribing":"subscribing",{type:qe,table:this.table,range:K(this.clientRange,this.bufferSize),aggregations:this.aggregations,columns:this.columns,sort:this.sort,groupBy:this.groupBy,filterSpec:{filter:e}}}handleSubscribed({viewPortId:e,aggregations:t,columns:n,filterSpec:r,range:o,sort:i,groupBy:u},c){return this.serverViewportId=e,this.status="subscribed",this.aggregations=t,this.columns=n,this.groupBy=u,this.isTree=u&&u.length>0,this.dataWindow.setRange(o.from,o.to),{aggregations:t,type:"subscribed",clientViewportId:this.clientViewportId,columns:n,filter:r,groupBy:u,range:o,sort:i,tableSchema:c}}awaitOperation(e,t){this.pendingOperations.set(e,t)}completeOperation(e,...t){var u;let{clientViewportId:n,pendingOperations:r}=this,o=r.get(e);if(!o){At(\`no matching operation found to complete for requestId \${e}\`);return}let{type:i}=o;if(g==null||g(\`completeOperation \${i}\`),r.delete(e),i==="CHANGE_VP_RANGE"){let[c,p]=t;(u=this.dataWindow)==null||u.setRange(c,p);for(let a=this.pendingRangeRequests.length-1;a>=0;a--){let l=this.pendingRangeRequests[a];if(l.requestId===e){l.acked=!0;break}else L==null||L("range requests sent faster than they are being ACKed")}}else if(i==="config"){let{aggregations:c,columns:p,filter:a,groupBy:l,sort:m}=o.data;return this.aggregations=c,this.columns=p,this.filter=a,this.groupBy=l,this.sort=m,l.length>0?this.isTree=!0:this.isTree&&(this.isTree=!1),C==null||C(\`config change confirmed, isTree : \${this.isTree}\`),{clientViewportId:n,type:i,config:o.data}}else{if(i==="groupBy")return this.isTree=o.data.length>0,this.groupBy=o.data,C==null||C(\`groupBy change confirmed, isTree : \${this.isTree}\`),{clientViewportId:n,type:i,groupBy:o.data};if(i==="columns")return this.columns=o.data,{clientViewportId:n,type:i,columns:o.data};if(i==="filter")return this.filter=o.data,{clientViewportId:n,type:i,filter:o.data};if(i==="aggregate")return this.aggregations=o.data,{clientViewportId:n,type:"aggregate",aggregations:this.aggregations};if(i==="sort")return this.sort=o.data,{clientViewportId:n,type:i,sort:this.sort};if(i!=="selection"){if(i==="disable")return this.disabled=!0,{type:"disabled",clientViewportId:n};if(i==="enable")return this.disabled=!1,{type:"enabled",clientViewportId:n};if(i==="CREATE_VISUAL_LINK"){let[c,p,a]=t;return this.linkedParent={colName:c,parentViewportId:p,parentColName:a},this.pendingLinkedParent=void 0,{type:"vuu-link-created",clientViewportId:n,colName:c,parentViewportId:p,parentColName:a}}else if(i==="REMOVE_VISUAL_LINK")return this.linkedParent=void 0,{type:"vuu-link-removed",clientViewportId:n}}}}rangeRequest(e,t){H&&this.rangeMonitor.set(t);let n="CHANGE_VP_RANGE";if(this.dataWindow){let[r,o]=this.dataWindow.setClientRange(t.from,t.to),i,u=this.dataWindow.rowCount||void 0,c=r&&!this.rangeRequestAlreadyPending(t)?{type:n,viewPortId:this.serverViewportId,...K(t,this.bufferSize,u)}:null;if(c){H&&(C==null||C(\`create CHANGE_VP_RANGE: [\${c.from} - \${c.to}]\`)),this.awaitOperation(e,{type:n});let a=this.pendingRangeRequests.at(-1);if(a)if(a.acked)console.warn("Range Request before previous request is filled");else{let{from:l,to:m}=a;this.dataWindow.outOfRange(l,m)?i={clientViewportId:this.clientViewportId,type:"debounce-begin"}:L==null||L("Range Request before previous request is acked")}this.pendingRangeRequests.push({...c,requestId:e}),this.useBatchMode&&(this.batchMode=!0)}else o.length>0&&(this.batchMode=!1);this.keys.reset(this.dataWindow.clientRange);let p=this.isTree?se:re;return o.length?[c,o.map(a=>p(a,this.keys,this.selectedRows))]:i?[c,void 0,i]:[c]}else return[null]}setLinks(e){return this.links=e,[{type:"vuu-links",links:e,clientViewportId:this.clientViewportId},this.pendingLinkedParent]}setMenu(e){return{type:"vuu-menu",menu:e,clientViewportId:this.clientViewportId}}openTreeNode(e,t){return this.useBatchMode&&(this.batchMode=!0),{type:Qe,vpId:this.serverViewportId,treeKey:t.key}}closeTreeNode(e,t){return this.useBatchMode&&(this.batchMode=!0),{type:Ne,vpId:this.serverViewportId,treeKey:t.key}}createLink(e,t,n,r){let o={type:"CREATE_VISUAL_LINK",parentVpId:n,childVpId:this.serverViewportId,parentColumnName:r,childColumnName:t};return this.awaitOperation(e,o),this.useBatchMode&&(this.batchMode=!0),o}removeLink(e){let t={type:"REMOVE_VISUAL_LINK",childVpId:this.serverViewportId};return this.awaitOperation(e,t),t}suspend(){this.suspended=!0,g==null||g("suspend")}resume(){return this.suspended=!1,H&&(C==null||C(\`resume: \${this.currentData()}\`)),[this.size,this.currentData()]}currentData(){let e=[];if(this.dataWindow){let t=this.dataWindow.getData(),{keys:n}=this,r=this.isTree?se:re;for(let o of t)o&&e.push(r(o,n,this.selectedRows))}return e}enable(e){return this.awaitOperation(e,{type:"enable"}),g==null||g(\`enable: \${this.serverViewportId}\`),{type:Be,viewPortId:this.serverViewportId}}disable(e){return this.awaitOperation(e,{type:"disable"}),g==null||g(\`disable: \${this.serverViewportId}\`),this.suspended=!1,{type:\$e,viewPortId:this.serverViewportId}}columnRequest(e,t){return this.awaitOperation(e,{type:"columns",data:t}),C==null||C(\`columnRequest: \${t}\`),this.createRequest({columns:t})}filterRequest(e,t){this.awaitOperation(e,{type:"filter",data:t}),this.useBatchMode&&(this.batchMode=!0);let{filter:n}=t;return g==null||g(\`filterRequest: \${n}\`),this.createRequest({filterSpec:{filter:n}})}setConfig(e,t){this.awaitOperation(e,{type:"config",data:t});let{filter:n,...r}=t;return this.useBatchMode&&(this.batchMode=!0),H?C==null||C(\`setConfig \${JSON.stringify(t)}\`):g==null||g("setConfig"),this.createRequest({...r,filterSpec:typeof(n==null?void 0:n.filter)=="string"?{filter:n.filter}:{filter:""}},!0)}aggregateRequest(e,t){return this.awaitOperation(e,{type:"aggregate",data:t}),g==null||g(\`aggregateRequest: \${t}\`),this.createRequest({aggregations:t})}sortRequest(e,t){return this.awaitOperation(e,{type:"sort",data:t}),g==null||g(\`sortRequest: \${JSON.stringify(t.sortDefs)}\`),this.createRequest({sort:t})}groupByRequest(e,t=kt){var n;return this.awaitOperation(e,{type:"groupBy",data:t}),this.useBatchMode&&(this.batchMode=!0),this.isTree||(n=this.dataWindow)==null||n.clear(),this.createRequest({groupBy:t})}selectRequest(e,t){return this.selectedRows=t,this.awaitOperation(e,{type:"selection",data:t}),g==null||g(\`selectRequest: \${t}\`),{type:"SET_SELECTION",vpId:this.serverViewportId,selection:Te(t)}}removePendingRangeRequest(e,t){for(let n=this.pendingRangeRequests.length-1;n>=0;n--){let{from:r,to:o}=this.pendingRangeRequests[n],i=!0;if(e>=r&&er&&t0){e=[],t="update";for(let i of this.pendingUpdates)e.push(o(i,n,r));this.pendingUpdates.length=0}else{let i=this.dataWindow.getData();if(this.dataWindow.hasAllRowsWithinRange){e=[],t="batch";for(let u of i)e.push(o(u,n,r));this.batchMode=!1}}this.hasUpdates=!1}return this.throttleMessage(t)?j:[e,t]}createRequest(e,t=!1){return t?{type:"CHANGE_VP",viewPortId:this.serverViewportId,...e}:{type:"CHANGE_VP",viewPortId:this.serverViewportId,aggregations:this.aggregations,columns:this.columns,sort:this.sort,groupBy:this.groupBy,filterSpec:{filter:this.filter.filter},...e}}},re=({rowIndex:s,rowKey:e,sel:t,data:n},r,o)=>[s,r.keyFor(s),!0,!1,0,0,e,t?Q(o,s):0].concat(n),se=({rowIndex:s,rowKey:e,sel:t,data:n},r,o)=>{let[i,u,,c,,p,...a]=n;return[s,r.keyFor(s),c,u,i,p,e,t?Q(o,s):0].concat(a)};var rt=1;var{debug:x,debugEnabled:oe,error:_,info:S,infoEnabled:Wt,warn:ie}=w("server-proxy"),b=()=>\`\${rt++}\`,qt={},\$t=s=>s.disabled!==!0&&s.suspended!==!0,Gt={type:"NO_ACTION"},Bt=(s,e,t)=>s.map(n=>n.parentVpId===e?{...n,label:t}:n);function Ht(s,e){return s.map(t=>{let{parentVpId:n}=t,r=e.get(n);if(r)return{...t,parentClientVpId:r.clientViewportId,label:r.title};throw Error("addLabelsToLinks viewport not found")})}var J=class{constructor(e,t){this.authToken="";this.user="user";this.pendingRequests=new Map;this.queuedRequests=[];this.cachedTableMetaRequests=new Map;this.cachedTableSchemas=new Map;this.connection=e,this.postMessageToClient=t,this.viewports=new Map,this.mapClientToServerViewport=new Map}async reconnect(){await this.login(this.authToken);let[e,t]=fe(Array.from(this.viewports.values()),\$t);this.viewports.clear(),this.mapClientToServerViewport.clear();let n=r=>{r.forEach(o=>{let{clientViewportId:i}=o;this.viewports.set(i,o),this.sendMessageToServer(o.subscribe(),i)})};n(e),setTimeout(()=>{n(t)},2e3)}async login(e,t="user"){if(e)return this.authToken=e,this.user=t,new Promise((n,r)=>{this.sendMessageToServer({type:Ke,token:this.authToken,user:t},""),this.pendingLogin={resolve:n,reject:r}});this.authToken===""&&_("login, cannot login until auth token has been obtained")}subscribe(e){if(this.mapClientToServerViewport.has(e.viewport))_(\`spurious subscribe call \${e.viewport}\`);else{let t=this.getTableMeta(e.table),n=new z(e,this.postMessageToClient);this.viewports.set(e.viewport,n);let r=this.awaitResponseToMessage(n.subscribe(),e.viewport);Promise.all([r,t]).then(([i,u])=>{let{viewPortId:c}=i,{status:p}=n;e.viewport!==c&&(this.viewports.delete(e.viewport),this.viewports.set(c,n)),this.mapClientToServerViewport.set(e.viewport,c);let a=n.handleSubscribed(i,u);a&&(this.postMessageToClient(a),oe&&x(\`post DataSourceSubscribedMessage to client: \${JSON.stringify(a)}\`)),n.disabled&&this.disableViewport(n),this.queuedRequests.length>0&&this.processQueuedRequests(),p==="subscribing"&&!G(n.table)&&(this.sendMessageToServer({type:ne,vpId:c}),this.sendMessageToServer({type:je,vpId:c}),Array.from(this.viewports.entries()).filter(([l,{disabled:m}])=>l!==c&&!m).forEach(([l])=>{this.sendMessageToServer({type:ne,vpId:l})}))})}}processQueuedRequests(){let e={};for(;this.queuedRequests.length;){let t=this.queuedRequests.pop();if(t){let{clientViewportId:n,message:r,requestId:o}=t;if(r.type==="CHANGE_VP_RANGE"){if(e.CHANGE_VP_RANGE)continue;e.CHANGE_VP_RANGE=!0;let i=this.mapClientToServerViewport.get(n);i&&this.sendMessageToServer({...r,viewPortId:i},o)}}}}unsubscribe(e){let t=this.mapClientToServerViewport.get(e);t?(S==null||S(\`Unsubscribe Message (Client to Server): - \${t}\`),this.sendMessageToServer({type:Ye,viewPortId:t})):_(\`failed to unsubscribe client viewport \${e}, viewport not found\`)}getViewportForClient(e,t=!0){let n=this.mapClientToServerViewport.get(e);if(n){let r=this.viewports.get(n);if(r)return r;if(t)throw Error(\`Viewport not found for client viewport \${e}\`);return null}else{if(this.viewports.has(e))return this.viewports.get(e);if(t)throw Error(\`Viewport server id not found for client viewport \${e}\`);return null}}setViewRange(e,t){let n=b(),[r,o,i]=e.rangeRequest(n,t.range);S==null||S(\`setViewRange \${t.range.from} - \${t.range.to}\`),r&&(this.sendIfReady(r,n,e.status==="subscribed")||this.queuedRequests.push({clientViewportId:t.viewport,message:r,requestId:n})),o?(S==null||S(\`setViewRange \${o.length} rows returned from cache\`),this.postMessageToClient({mode:"batch",type:"viewport-update",clientViewportId:e.clientViewportId,rows:o})):i&&this.postMessageToClient(i)}setConfig(e,t){let n=b(),r=e.setConfig(n,t.config);this.sendIfReady(r,n,e.status==="subscribed")}aggregate(e,t){let n=b(),r=e.aggregateRequest(n,t.aggregations);this.sendIfReady(r,n,e.status==="subscribed")}sort(e,t){let n=b(),r=e.sortRequest(n,t.sort);this.sendIfReady(r,n,e.status==="subscribed")}groupBy(e,t){let n=b(),r=e.groupByRequest(n,t.groupBy);this.sendIfReady(r,n,e.status==="subscribed")}filter(e,t){let n=b(),{filter:r}=t,o=e.filterRequest(n,r);this.sendIfReady(o,n,e.status==="subscribed")}setColumns(e,t){let n=b(),{columns:r}=t,o=e.columnRequest(n,r);this.sendIfReady(o,n,e.status==="subscribed")}setTitle(e,t){e&&(e.title=t.title,this.updateTitleOnVisualLinks(e))}select(e,t){let n=b(),{selected:r}=t,o=e.selectRequest(n,r);this.sendIfReady(o,n,e.status==="subscribed")}disableViewport(e){let t=b(),n=e.disable(t);this.sendIfReady(n,t,e.status==="subscribed")}enableViewport(e){if(e.disabled){let t=b(),n=e.enable(t);this.sendIfReady(n,t,e.status==="subscribed")}}suspendViewport(e){e.suspend(),e.suspendTimer=setTimeout(()=>{S==null||S("suspendTimer expired, escalate suspend to disable"),this.disableViewport(e)},3e3)}resumeViewport(e){e.suspendTimer&&(x==null||x("clear suspend timer"),clearTimeout(e.suspendTimer),e.suspendTimer=null);let[t,n]=e.resume();x==null||x(\`resumeViewport size \${t}, \${n.length} rows sent to client\`),this.postMessageToClient({clientViewportId:e.clientViewportId,mode:"batch",rows:n,size:t,type:"viewport-update"})}openTreeNode(e,t){if(e.serverViewportId){let n=b();this.sendIfReady(e.openTreeNode(n,t),n,e.status==="subscribed")}}closeTreeNode(e,t){if(e.serverViewportId){let n=b();this.sendIfReady(e.closeTreeNode(n,t),n,e.status==="subscribed")}}createLink(e,t){let{parentClientVpId:n,parentColumnName:r,childColumnName:o}=t,i=b(),u=this.mapClientToServerViewport.get(n);if(u){let c=e.createLink(i,o,u,r);this.sendMessageToServer(c,i)}else _("ServerProxy unable to create link, viewport not found")}removeLink(e){let t=b(),n=e.removeLink(t);this.sendMessageToServer(n,t)}updateTitleOnVisualLinks(e){var r;let{serverViewportId:t,title:n}=e;for(let o of this.viewports.values())if(o!==e&&o.links&&t&&n&&(r=o.links)!=null&&r.some(i=>i.parentVpId===t)){let[i]=o.setLinks(Bt(o.links,t,n));this.postMessageToClient(i)}}removeViewportFromVisualLinks(e){var t;for(let n of this.viewports.values())if((t=n.links)!=null&&t.some(({parentVpId:r})=>r===e)){let[r]=n.setLinks(n.links.filter(({parentVpId:o})=>o!==e));this.postMessageToClient(r)}}menuRpcCall(e){let t=this.getViewportForClient(e.vpId,!1);if(t!=null&&t.serverViewportId){let[n,r]=\$(e);this.sendMessageToServer({...r,vpId:t.serverViewportId},n)}}viewportRpcCall(e){let t=this.getViewportForClient(e.vpId,!1);if(t!=null&&t.serverViewportId){let[n,r]=\$(e);this.sendMessageToServer({...r,vpId:t.serverViewportId,namedParams:{}},n)}}rpcCall(e){let[t,n]=\$(e),r=tt(n.service);this.sendMessageToServer(n,t,{module:r})}handleMessageFromClient(e){var t;if(Ae(e))if(e.type==="disable"){let n=this.getViewportForClient(e.viewport,!1);return n!==null?this.disableViewport(n):void 0}else{let n=this.getViewportForClient(e.viewport);switch(e.type){case"setViewRange":return this.setViewRange(n,e);case"config":return this.setConfig(n,e);case"aggregate":return this.aggregate(n,e);case"sort":return this.sort(n,e);case"groupBy":return this.groupBy(n,e);case"filter":return this.filter(n,e);case"select":return this.select(n,e);case"suspend":return this.suspendViewport(n);case"resume":return this.resumeViewport(n);case"enable":return this.enableViewport(n);case"openTreeNode":return this.openTreeNode(n,e);case"closeTreeNode":return this.closeTreeNode(n,e);case"createLink":return this.createLink(n,e);case"removeLink":return this.removeLink(n);case"setColumns":return this.setColumns(n,e);case"setTitle":return this.setTitle(n,e);default:}}else{if(Pe(e))return this.viewportRpcCall(e);if(De(e))return this.menuRpcCall(e);{let{type:n,requestId:r}=e;switch(n){case"GET_TABLE_LIST":{(t=this.tableList)!=null||(this.tableList=this.awaitResponseToMessage({type:n},r)),this.tableList.then(o=>{this.postMessageToClient({type:"TABLE_LIST_RESP",tables:o.tables,requestId:r})});return}case"GET_TABLE_META":{this.getTableMeta(e.table,r).then(o=>{o&&this.postMessageToClient({type:"TABLE_META_RESP",tableSchema:o,requestId:r})});return}case"RPC_CALL":return this.rpcCall(e);default:}}}_(\`Vuu ServerProxy Unexpected message from client \${JSON.stringify(e)}\`)}getTableMeta(e,t=b()){if(G(e))return Promise.resolve(void 0);let n=\`\${e.module}:\${e.table}\`,r=this.cachedTableMetaRequests.get(n);return r||(r=this.awaitResponseToMessage({type:"GET_TABLE_META",table:e},t),this.cachedTableMetaRequests.set(n,r)),r==null?void 0:r.then(o=>this.cacheTableMeta(o))}awaitResponseToMessage(e,t=b()){return new Promise((n,r)=>{this.sendMessageToServer(e,t),this.pendingRequests.set(t,{reject:r,resolve:n})})}sendIfReady(e,t,n=!0){return n&&this.sendMessageToServer(e,t),n}sendMessageToServer(e,t=\`\${rt++}\`,n=qt){let{module:r="CORE"}=n;this.authToken&&this.connection.send({requestId:t,sessionId:this.sessionId,token:this.authToken,user:this.user,module:r,body:e})}handleMessageFromServer(e){var u;let{body:t,requestId:n,sessionId:r}=e,o=this.pendingRequests.get(n);if(o){let{resolve:a}=o;this.pendingRequests.delete(n),a(t);return}let{viewports:i}=this;switch(t.type){case ze:this.sendMessageToServer({type:Je,ts:+new Date},"NA");break;case"LOGIN_SUCCESS":if(r)this.sessionId=r,(u=this.pendingLogin)==null||u.resolve(r),this.pendingLogin=void 0;else throw Error("LOGIN_SUCCESS did not provide sessionId");break;case"REMOVE_VP_SUCCESS":{let a=i.get(t.viewPortId);a&&(this.mapClientToServerViewport.delete(a.clientViewportId),i.delete(t.viewPortId),this.removeViewportFromVisualLinks(t.viewPortId))}break;case Ze:{let a=this.viewports.get(t.vpId);a&&a.completeOperation(n)}break;case Fe:case Ge:if(i.has(t.viewPortId)){let a=this.viewports.get(t.viewPortId);if(a){let l=a.completeOperation(n);l!==void 0&&(this.postMessageToClient(l),oe&&x(\`postMessageToClient \${JSON.stringify(l)}\`))}}break;case He:{let a=this.viewports.get(t.viewPortId);if(a){let l=a.completeOperation(n);if(l){this.postMessageToClient(l);let[m,y]=a.resume();this.postMessageToClient({clientViewportId:a.clientViewportId,mode:"batch",rows:y,size:m,type:"viewport-update"})}}}break;case"TABLE_ROW":{let a=_e(t.rows);for(let[l,m]of Object.entries(a)){let y=i.get(l);y?y.updateRows(m):ie==null||ie(\`TABLE_ROW message received for non registered viewport \${l}\`)}this.processUpdates()}break;case"CHANGE_VP_RANGE_SUCCESS":{let a=this.viewports.get(t.viewPortId);if(a){let{from:l,to:m}=t;a.completeOperation(n,l,m)}}break;case Xe:case We:break;case"CREATE_VISUAL_LINK_SUCCESS":{let a=this.viewports.get(t.childVpId),l=this.viewports.get(t.parentVpId);if(a&&l){let{childColumnName:m,parentColumnName:y}=t,O=a.completeOperation(n,m,l.clientViewportId,y);O&&this.postMessageToClient(O)}}break;case"REMOVE_VISUAL_LINK_SUCCESS":{let a=this.viewports.get(t.childVpId);if(a){let l=a.completeOperation(n);l&&this.postMessageToClient(l)}}break;case"VP_VISUAL_LINKS_RESP":{let a=this.getActiveLinks(t.links),l=this.viewports.get(t.vpId);if(a.length&&l){let m=Ht(a,this.viewports),[y,O]=l.setLinks(m);if(this.postMessageToClient(y),O){let{link:le,parentClientVpId:st}=O,ce=b(),pe=this.mapClientToServerViewport.get(st);if(pe){let ot=l.createLink(ce,le.fromColumn,pe,le.toColumn);this.sendMessageToServer(ot,ce)}}}}break;case"VIEW_PORT_MENUS_RESP":if(t.menu.name){let a=this.viewports.get(t.vpId);if(a){let l=a.setMenu(t.menu);this.postMessageToClient(l)}}break;case"VP_EDIT_RPC_RESPONSE":this.postMessageToClient({action:t.action,requestId:n,rpcName:t.rpcName,type:"VP_EDIT_RPC_RESPONSE"});break;case"VP_EDIT_RPC_REJECT":this.viewports.get(t.vpId)&&this.postMessageToClient({requestId:n,type:"VP_EDIT_RPC_REJECT",error:t.error});break;case"VIEW_PORT_MENU_REJ":{console.log("send menu error back to client");let{error:a,rpcName:l,vpId:m}=t,y=this.viewports.get(m);y&&this.postMessageToClient({clientViewportId:y.clientViewportId,error:a,rpcName:l,type:"VIEW_PORT_MENU_REJ",requestId:n});break}case"VIEW_PORT_MENU_RESP":if(Ue(t)){let{action:a,rpcName:l}=t;this.awaitResponseToMessage({type:"GET_TABLE_META",table:a.table}).then(m=>{let y=te(m);this.postMessageToClient({rpcName:l,type:"VIEW_PORT_MENU_RESP",action:{...a,tableSchema:y},tableAlreadyOpen:this.isTableOpen(a.table),requestId:n})})}else{let{action:a}=t;this.postMessageToClient({type:"VIEW_PORT_MENU_RESP",action:a||Gt,tableAlreadyOpen:a!==null&&this.isTableOpen(a.table),requestId:n})}break;case"RPC_RESP":{let{method:a,result:l}=t;this.postMessageToClient({type:"RPC_RESP",method:a,result:l,requestId:n})}break;case"VIEW_PORT_RPC_REPONSE":{let{method:a,action:l}=t;this.postMessageToClient({type:"VIEW_PORT_RPC_RESPONSE",rpcName:a,action:l,requestId:n})}break;case"ERROR":_(t.msg);break;default:Wt&&S(\`handleMessageFromServer \${t.type}.\`)}}cacheTableMeta(e){let{module:t,table:n}=e.table,r=\`\${t}:\${n}\`,o=this.cachedTableSchemas.get(r);return o||(o=te(e),this.cachedTableSchemas.set(r,o)),o}isTableOpen(e){if(e){let t=e.table;for(let n of this.viewports.values())if(!n.suspended&&n.table.table===t)return!0}}getActiveLinks(e){return e.filter(t=>{let n=this.viewports.get(t.parentVpId);return n&&!n.suspended})}processUpdates(){this.viewports.forEach(e=>{var t;if(e.hasUpdatesToProcess){let n=e.getClientRows();if(n!==j){let[r,o]=n,i=e.getNewRowCount();(i!==void 0||r&&r.length>0)&&(oe&&x(\`postMessageToClient #\${e.clientViewportId} viewport-update \${o}, \${(t=r==null?void 0:r.length)!=null?t:"no"} rows, size \${i}\`),o&&this.postMessageToClient({clientViewportId:e.clientViewportId,mode:o,rows:r,size:i,type:"viewport-update"}))}}})}};var D,{info:ae,infoEnabled:ue}=w("worker");async function jt(s,e,t,n,r,o,i){let u=await ve(s,e,c=>{ke(c)?postMessage({type:"connection-metrics",messages:c}):Oe(c)?(r(c),c.status==="reconnected"&&D.reconnect()):D.handleMessageFromServer(c)},o,i);D=new J(u,c=>zt(c)),u.requiresLogin&&await D.login(t,n)}function zt(s){postMessage(s)}var Jt=async({data:s})=>{switch(s.type){case"connect":await jt(s.url,s.protocol,s.token,s.username,postMessage,s.retryLimitDisconnect,s.retryLimitStartup),postMessage({type:"connected"});break;case"subscribe":ue&&ae(\`client subscribe: \${JSON.stringify(s)}\`),D.subscribe(s);break;case"unsubscribe":ue&&ae(\`client unsubscribe: \${JSON.stringify(s)}\`),D.unsubscribe(s.viewport);break;default:ue&&ae(\`client message: \${JSON.stringify(s)}\`),D.handleMessageFromClient(s)}};self.addEventListener("message",Jt);postMessage({type:"ready"}); - -`; \ No newline at end of file diff --git a/vuu-ui/packages/vuu-data/src/vuuUIMessageTypes.ts b/vuu-ui/packages/vuu-data/src/vuuUIMessageTypes.ts deleted file mode 100644 index b603d8f9c..000000000 --- a/vuu-ui/packages/vuu-data/src/vuuUIMessageTypes.ts +++ /dev/null @@ -1,388 +0,0 @@ -import { - ClientToServerTableList, - ClientToServerTableMeta, - LinkDescriptorWithLabel, - ServerToClientBody, - ServerToClientMenuSessionTableAction, - ServerToClientViewportRpcResponse, - TypeAheadMethod, - VuuAggregation, - VuuColumns, - VuuGroupBy, - VuuRange, - VuuSort, - VuuTable, -} from "@finos/vuu-protocol-types"; -import { DataSourceFilter } from "@finos/vuu-data-types"; -import { TableSchema, WithRequestId } from "./message-utils"; -import { - DataSourceMenusMessage, - DataSourceVisualLinkCreatedMessage, - DataSourceVisualLinkRemovedMessage, - DataSourceVisualLinksMessage, - RpcResponse, - VuuFeatureInvocationMessage, - VuuFeatureMessage, - WithFullConfig, -} from "./data-source"; -import { GridAction, Selection } from "@finos/vuu-table-types"; -import { WebSocketProtocol } from "./websocket-connection"; - -export interface OpenDialogAction { - type: "OPEN_DIALOG_ACTION"; - tableSchema?: TableSchema; - table?: VuuTable; -} -export interface NoAction { - type: "NO_ACTION"; -} - -export declare type MenuRpcAction = OpenDialogAction | NoAction; - -export type ConnectionStatus = - | "connecting" - | "connection-open-awaiting-session" - | "connected" - | "disconnected" - | "reconnected"; - -export interface ConnectionStatusMessage { - type: "connection-status"; - reason?: string; - retry?: boolean; - status: ConnectionStatus; -} - -export const isConnectionStatusMessage = ( - msg: object | ConnectionStatusMessage -): msg is ConnectionStatusMessage => - (msg as ConnectionStatusMessage).type === "connection-status"; - -export interface ConnectionQualityMetrics { - type: "connection-metrics"; - messagesLength: number; -} - -export const isConnectionQualityMetrics = ( - msg: object -): msg is ConnectionQualityMetrics => - (msg as ConnectionQualityMetrics).type === "connection-metrics"; - -export interface ServerProxySubscribeMessage { - aggregations: VuuAggregation[]; - bufferSize?: number; - columns: VuuColumns; - filter: DataSourceFilter; - groupBy: VuuGroupBy; - range: VuuRange; - sort: VuuSort; - table: VuuTable; - title?: string; - viewport: string; - visualLink?: LinkDescriptorWithLabel; -} - -// export type VuuUIMessageInConnectionStatus = { -// type: 'connection-status'; -// }; - -export type VuuUIMessageInConnected = { - type: "connected"; -}; - -export type VuuUIMessageInWorkerReady = { - type: "ready"; -}; - -export interface ViewportMessageIn { - clientViewportId: string; -} - -// TODO use generic to type result -export interface VuuUIMessageInRPC { - method: string; - result: unknown; - requestId: string; - type: "RPC_RESP"; -} - -export interface VuuUIMessageInRPCEditReject { - error: string; - requestId?: string; - type: "VP_EDIT_RPC_REJECT"; -} - -export interface VuuUIMessageInRPCEditResponse { - action: unknown; - requestId: string; - rpcName: string; - type: "VP_EDIT_RPC_RESPONSE"; -} - -export const messageHasResult = (msg: object): msg is VuuUIMessageInRPC => - typeof (msg as VuuUIMessageInRPC).result !== "undefined"; - -export const isTableSchema = ( - message: VuuUIMessageIn -): message is VuuUIMessageInTableMeta => message.type === "TABLE_META_RESP"; - -export interface VuuUIMessageInTableList { - requestId: string; - type: "TABLE_LIST_RESP"; - tables: VuuTable[]; -} -export interface VuuUIMessageInTableMeta { - requestId: string; - tableSchema: TableSchema; - type: "TABLE_META_RESP"; -} -export interface MenuRpcResponse { - action: MenuRpcAction; - error?: string; - requestId: string; - rpcName?: string; - tableAlreadyOpen?: boolean; - type: "VIEW_PORT_MENU_RESP"; -} -export interface ViewportRpcResponse { - action: ServerToClientViewportRpcResponse["action"]; - requestId: string; - rpcName?: string; - type: "VIEW_PORT_RPC_RESPONSE"; -} -export interface MenuRpcReject extends ViewportMessageIn { - error?: string; - requestId: string; - rpcName?: string; - type: "VIEW_PORT_MENU_REJ"; -} - -export interface VuuUIMessageInMenuRej { - error: string; - requestId: string; - rpcName: string; - type: "VIEW_PORT_MENU_REJ"; -} - -export type VuuUIMessageIn = - | VuuUIMessageInConnected - | VuuUIMessageInWorkerReady - | VuuUIMessageInRPC - | ViewportRpcResponse - | MenuRpcResponse - | MenuRpcReject - | VuuUIMessageInTableList - | VuuUIMessageInTableMeta - | VuuUIMessageInRPCEditReject - | VuuUIMessageInRPCEditResponse; - -export const isErrorResponse = ( - response?: RpcResponse -): response is VuuUIMessageInRPCEditReject => - response !== undefined && "error" in response; - -export const hasAction = ( - response?: RpcResponse -): response is MenuRpcResponse | VuuUIMessageInRPCEditResponse => - response != undefined && "action" in response; - -export interface VuuUIMessageOutConnect { - protocol: WebSocketProtocol; - type: "connect"; - token: string; - url: string; - username?: string; - retryLimitDisconnect?: number; - retryLimitStartup?: number; -} - -export interface VuuUIMessageOutSubscribe extends ServerProxySubscribeMessage { - type: "subscribe"; -} - -export interface VuuUIMessageOutUnsubscribe { - type: "unsubscribe"; - viewport: string; -} -export interface VuuUIMessageOutSuspend { - type: "suspend"; - viewport: string; -} -export interface VuuUIMessageOutResume { - type: "resume"; - viewport: string; -} - -export interface ViewportMessageOut { - viewport: string; -} - -export interface RequestMessage { - requestId: string; -} - -export interface VuuUIMessageOutColumns extends ViewportMessageOut { - type: "setColumns"; - columns: string[]; -} -export interface VuuUIMessageOutViewRange extends ViewportMessageOut { - type: "setViewRange"; - range: { - from: number; - to: number; - }; -} -export interface VuuUIMessageOutAggregate extends ViewportMessageOut { - aggregations: VuuAggregation[]; - type: "aggregate"; -} -export interface VuuUIMessageOutCloseTreeNode extends ViewportMessageOut { - key: string; - type: "closeTreeNode"; -} -export interface VuuUIMessageOutCreateLink extends ViewportMessageOut { - childColumnName: string; - parentColumnName: string; - parentClientVpId: string; - type: "createLink"; -} -export interface VuuUIMessageOutRemoveLink extends ViewportMessageOut { - type: "removeLink"; -} -export interface VuuUIMessageOutSetTitle extends ViewportMessageOut { - title: string; - type: "setTitle"; -} - -export interface VuuUIMessageOutDisable extends ViewportMessageOut { - type: "disable"; -} -export interface VuuUIMessageOutEnable extends ViewportMessageOut { - type: "enable"; -} -export interface VuuUIMessageOutOpenTreeNode extends ViewportMessageOut { - key: string; - type: "openTreeNode"; -} -export interface VuuUIMessageOutResume extends ViewportMessageOut { - type: "resume"; -} - -export interface VuuUIMessageOutSelect extends ViewportMessageOut { - selected: Selection; - type: "select"; -} -export interface VuuUIMessageOutSelectAll extends ViewportMessageOut { - type: "selectAll"; -} -export interface VuuUIMessageOutSelectNone extends ViewportMessageOut { - type: "selectNone"; -} - -export interface VuuUIMessageOutSort extends ViewportMessageOut { - sort: VuuSort; - type: "sort"; -} -export interface VuuUIMessageOutSuspend extends ViewportMessageOut { - type: "suspend"; -} - -export interface VuuUIMessageOutFilter extends ViewportMessageOut { - filter: DataSourceFilter; - type: "filter"; -} -export interface VuuUIMessageOutGroupby extends ViewportMessageOut { - groupBy: VuuGroupBy; - type: "groupBy"; -} - -export interface VuuUIMessageOutConfig extends ViewportMessageOut { - config: WithFullConfig; - type: "config"; -} - -export type VuuUIMessageOutViewport = - | VuuUIMessageOutAggregate - | VuuUIMessageOutCloseTreeNode - | VuuUIMessageOutColumns - | VuuUIMessageOutConfig - | VuuUIMessageOutCreateLink - | VuuUIMessageOutFilter - | VuuUIMessageOutDisable - | VuuUIMessageOutEnable - | VuuUIMessageOutGroupby - | VuuUIMessageOutOpenTreeNode - | VuuUIMessageOutRemoveLink - | VuuUIMessageOutResume - | VuuUIMessageOutSelect - | VuuUIMessageOutSelectAll - | VuuUIMessageOutSelectNone - | VuuUIMessageOutSetTitle - | VuuUIMessageOutSuspend - | VuuUIMessageOutSort - | VuuUIMessageOutViewRange; - -export const isViewporttMessage = ( - msg: object -): msg is VuuUIMessageOutViewport => "viewport" in msg; - -export interface TypeAheadRpcRequest { - method: TypeAheadMethod; - params: [VuuTable, ...string[]]; - type: "RPC_CALL"; -} - -export type VuuUIMessageOut = - | VuuUIMessageOutConnect - | VuuUIMessageOutSubscribe - | VuuUIMessageOutUnsubscribe - | VuuUIMessageOutViewport - | WithRequestId - | WithRequestId; - -export const isSessionTableActionMessage = ( - messageBody: ServerToClientBody -): messageBody is ServerToClientMenuSessionTableAction => - messageBody.type === "VIEW_PORT_MENU_RESP" && - messageBody.action !== null && - isSessionTable(messageBody.action.table); - -export const isSessionTable = (table?: unknown) => { - if ( - table !== null && - typeof table === "object" && - "table" in table && - "module" in table - ) { - return (table as VuuTable).table.startsWith("session"); - } - return false; -}; - -export const isVisualLinksAction = ( - action: GridAction -): action is DataSourceVisualLinksMessage => action.type === "vuu-links"; - -export const isVisualLinkCreatedAction = ( - action: GridAction -): action is DataSourceVisualLinkCreatedMessage => - action.type === "vuu-link-created"; - -export const isVisualLinkRemovedAction = ( - action: GridAction -): action is DataSourceVisualLinkRemovedMessage => - action.type === "vuu-link-removed"; - -export const isViewportMenusAction = ( - action: GridAction -): action is DataSourceMenusMessage => action.type === "vuu-menu"; - -export const isVuuFeatureAction = ( - action: GridAction -): action is VuuFeatureMessage => - isViewportMenusAction(action) || isVisualLinksAction(action); - -export const isVuuFeatureInvocation = ( - action: GridAction -): action is VuuFeatureInvocationMessage => - action.type === "vuu-link-created" || action.type === "vuu-link-removed"; diff --git a/vuu-ui/packages/vuu-datatable/package.json b/vuu-ui/packages/vuu-datatable/package.json index f8f51f33d..56914915a 100644 --- a/vuu-ui/packages/vuu-datatable/package.json +++ b/vuu-ui/packages/vuu-datatable/package.json @@ -20,7 +20,7 @@ "@finos/vuu-utils": "0.0.26" }, "peerDependencies": { - "classnames": "^2.2.6", + "clsx": "^2.0.0", "react": ">=17.0.2", "react-dom": ">=17.0.2" } diff --git a/vuu-ui/packages/vuu-datatable/src/filter-table/FilterTable.tsx b/vuu-ui/packages/vuu-datatable/src/filter-table/FilterTable.tsx index 5edd19733..7a4f5a3f5 100644 --- a/vuu-ui/packages/vuu-datatable/src/filter-table/FilterTable.tsx +++ b/vuu-ui/packages/vuu-datatable/src/filter-table/FilterTable.tsx @@ -1,7 +1,7 @@ import { FilterBar, FilterBarProps } from "@finos/vuu-filters"; import { Table, TableProps } from "@finos/vuu-table"; import { HTMLAttributes } from "react"; -import cx from "classnames"; +import cx from "clsx"; import "./FilterTable.css"; diff --git a/vuu-ui/packages/vuu-datatable/src/json-table/JsonTable.tsx b/vuu-ui/packages/vuu-datatable/src/json-table/JsonTable.tsx index 4a59bf2b4..49690c556 100644 --- a/vuu-ui/packages/vuu-datatable/src/json-table/JsonTable.tsx +++ b/vuu-ui/packages/vuu-datatable/src/json-table/JsonTable.tsx @@ -1,7 +1,7 @@ import { TableProps } from "@finos/vuu-table"; import { JsonData } from "@finos/vuu-utils"; import { Table } from "@finos/vuu-table"; -import { JsonDataSource } from "@finos/vuu-data"; +import { JsonDataSource } from "@finos/vuu-data-local"; import { useEffect, useMemo, useRef } from "react"; import { TableConfig } from "@finos/vuu-table-types"; diff --git a/vuu-ui/packages/vuu-filters/package.json b/vuu-ui/packages/vuu-filters/package.json index 9a7e02e49..e312c2cbb 100644 --- a/vuu-ui/packages/vuu-filters/package.json +++ b/vuu-ui/packages/vuu-filters/package.json @@ -22,8 +22,7 @@ "@finos/vuu-popups": "0.0.26", "@finos/vuu-ui-controls": "0.0.26", "@finos/vuu-utils": "0.0.26", - "@salt-ds/core": "1.8.0", - "@salt-ds/lab": "1.0.0-alpha.15", + "@salt-ds/core": "1.13.2", "uuid": "9.0.0" }, "peerDependencies": { diff --git a/vuu-ui/packages/vuu-filters/src/filter-bar/FilterBar.tsx b/vuu-ui/packages/vuu-filters/src/filter-bar/FilterBar.tsx index 02e7f71f6..d40e0fa78 100644 --- a/vuu-ui/packages/vuu-filters/src/filter-bar/FilterBar.tsx +++ b/vuu-ui/packages/vuu-filters/src/filter-bar/FilterBar.tsx @@ -1,10 +1,9 @@ -import { TableSchema } from "@finos/vuu-data"; -import { DataSourceFilter } from "@finos/vuu-data-types"; +import { DataSourceFilter, TableSchema } from "@finos/vuu-data-types"; import { Filter } from "@finos/vuu-filter-types"; import { ActiveItemChangeHandler, Toolbar } from "@finos/vuu-layout"; import { Prompt } from "@finos/vuu-popups"; import { Button } from "@salt-ds/core"; -import cx from "classnames"; +import cx from "clsx"; import { HTMLAttributes, ReactElement, useRef } from "react"; import { FilterBuilderMenu } from "../filter-builder-menu"; import { FilterClauseEditor, FilterClauseEditorProps } from "../filter-clause"; diff --git a/vuu-ui/packages/vuu-filters/src/filter-bar/useFilterBar.ts b/vuu-ui/packages/vuu-filters/src/filter-bar/useFilterBar.ts index e424935fc..551193bd9 100644 --- a/vuu-ui/packages/vuu-filters/src/filter-bar/useFilterBar.ts +++ b/vuu-ui/packages/vuu-filters/src/filter-bar/useFilterBar.ts @@ -9,12 +9,12 @@ import { NavigationOutOfBoundsHandler, } from "@finos/vuu-layout"; import { PromptProps } from "@finos/vuu-popups"; +import { EditableLabelProps } from "@finos/vuu-ui-controls"; import { dispatchMouseEvent, filterAsQuery, isMultiClauseFilter, } from "@finos/vuu-utils"; -import { EditableLabelProps } from "@salt-ds/lab"; import { FocusEventHandler, KeyboardEvent, diff --git a/vuu-ui/packages/vuu-filters/src/filter-bar/useFilters.ts b/vuu-ui/packages/vuu-filters/src/filter-bar/useFilters.ts index 1456b6b9c..4a85266d7 100644 --- a/vuu-ui/packages/vuu-filters/src/filter-bar/useFilters.ts +++ b/vuu-ui/packages/vuu-filters/src/filter-bar/useFilters.ts @@ -1,8 +1,8 @@ -import { useControlled } from "@finos/vuu-ui-controls"; +import { TableSchema } from "@finos/vuu-data-types"; import { Filter, NamedFilter } from "@finos/vuu-filter-types"; -import { useCallback } from "react"; -import { TableSchema } from "packages/vuu-data/src"; import { useLayoutManager } from "@finos/vuu-shell"; +import { useControlled } from "@finos/vuu-ui-controls"; +import { useCallback } from "react"; export interface FiltersHookProps { defaultFilters?: Filter[]; diff --git a/vuu-ui/packages/vuu-filters/src/filter-clause/ExpandoCombobox.tsx b/vuu-ui/packages/vuu-filters/src/filter-clause/ExpandoCombobox.tsx index 5c16d43c1..c8ea60e27 100644 --- a/vuu-ui/packages/vuu-filters/src/filter-clause/ExpandoCombobox.tsx +++ b/vuu-ui/packages/vuu-filters/src/filter-clause/ExpandoCombobox.tsx @@ -6,7 +6,7 @@ import { SelectionStrategy, SingleSelectionHandler, } from "@finos/vuu-ui-controls"; -import cx from "classnames"; +import cx from "clsx"; import { FormEvent, ForwardedRef, diff --git a/vuu-ui/packages/vuu-filters/src/filter-clause/FilterClauseEditor.tsx b/vuu-ui/packages/vuu-filters/src/filter-clause/FilterClauseEditor.tsx index bcb364069..219695598 100644 --- a/vuu-ui/packages/vuu-filters/src/filter-clause/FilterClauseEditor.tsx +++ b/vuu-ui/packages/vuu-filters/src/filter-clause/FilterClauseEditor.tsx @@ -1,9 +1,9 @@ -import { TableSchema } from "@finos/vuu-data"; +import { TableSchema } from "@finos/vuu-data-types"; import { SuggestionFetcher } from "@finos/vuu-data-react"; import { ColumnDescriptor } from "@finos/vuu-table-types"; import { FilterClause } from "@finos/vuu-filter-types"; import { CloseReason } from "@finos/vuu-ui-controls"; -import cx from "classnames"; +import cx from "clsx"; import { HTMLAttributes, useCallback } from "react"; import { ExpandoCombobox } from "./ExpandoCombobox"; import { NumericInput } from "./NumericInput"; diff --git a/vuu-ui/packages/vuu-filters/src/filter-clause/useFilterClauseEditor.ts b/vuu-ui/packages/vuu-filters/src/filter-clause/useFilterClauseEditor.ts index f9c6bfa05..867e9c7dd 100644 --- a/vuu-ui/packages/vuu-filters/src/filter-clause/useFilterClauseEditor.ts +++ b/vuu-ui/packages/vuu-filters/src/filter-clause/useFilterClauseEditor.ts @@ -1,12 +1,14 @@ -import { ColumnDescriptor } from "@finos/vuu-table-types"; +import { TableSchema } from "@finos/vuu-data-types"; import { FilterClause, FilterClauseOp } from "@finos/vuu-filter-types"; +import { ColumnDescriptor } from "@finos/vuu-table-types"; import { isMultiValueFilter, isSingleValueFilter, isValidFilterClauseOp, } from "@finos/vuu-utils"; -import { getColumnByName, TableSchema } from "@finos/vuu-data"; +import { getColumnByName } from "@finos/vuu-data-remote"; +import { SingleSelectionHandler } from "@finos/vuu-ui-controls"; import { KeyboardEvent, KeyboardEventHandler, @@ -16,7 +18,6 @@ import { useRef, useState, } from "react"; -import { SingleSelectionHandler } from "@finos/vuu-ui-controls/src"; const cursorAtTextStart = (input: HTMLInputElement) => input.selectionStart === 0; diff --git a/vuu-ui/packages/vuu-filters/src/filter-input/useCodeMirrorEditor.ts b/vuu-ui/packages/vuu-filters/src/filter-input/useCodeMirrorEditor.ts index 9ffb76104..cd7826b5a 100644 --- a/vuu-ui/packages/vuu-filters/src/filter-input/useCodeMirrorEditor.ts +++ b/vuu-ui/packages/vuu-filters/src/filter-input/useCodeMirrorEditor.ts @@ -12,7 +12,7 @@ import { } from "@finos/vuu-codemirror"; import { walkTree } from "@finos/vuu-filter-parser"; import { Filter } from "@finos/vuu-filter-types"; -import cx from "classnames"; +import cx from "clsx"; import { MutableRefObject, useEffect, useMemo, useRef } from "react"; import { filterLanguageSupport } from "./FilterLanguage"; import { vuuHighlighting } from "./highlighting"; diff --git a/vuu-ui/packages/vuu-filters/src/filter-pill-menu/FilterPillMenu.tsx b/vuu-ui/packages/vuu-filters/src/filter-pill-menu/FilterPillMenu.tsx index 76a44b32d..7b85f1c64 100644 --- a/vuu-ui/packages/vuu-filters/src/filter-pill-menu/FilterPillMenu.tsx +++ b/vuu-ui/packages/vuu-filters/src/filter-pill-menu/FilterPillMenu.tsx @@ -5,7 +5,7 @@ import { MenuBuilder, } from "@finos/vuu-data-types"; import { useMemo } from "react"; -import cx from "classnames"; +import cx from "clsx"; import "./FilterPillMenu.css"; import { diff --git a/vuu-ui/packages/vuu-filters/src/filter-pill/FilterPill.tsx b/vuu-ui/packages/vuu-filters/src/filter-pill/FilterPill.tsx index 356a19af6..656111ba2 100644 --- a/vuu-ui/packages/vuu-filters/src/filter-pill/FilterPill.tsx +++ b/vuu-ui/packages/vuu-filters/src/filter-pill/FilterPill.tsx @@ -1,10 +1,9 @@ import { MenuActionHandler } from "@finos/vuu-data-types"; import { Filter } from "@finos/vuu-filter-types"; -import { useId } from "@finos/vuu-layout"; -import { PopupCloseCallback, Tooltip, useTooltip } from "@finos/vuu-popups/src"; +import { PopupCloseCallback, Tooltip, useTooltip } from "@finos/vuu-popups"; import { EditableLabel, EditableLabelProps } from "@finos/vuu-ui-controls"; -import { filterAsQuery, isMultiClauseFilter } from "@finos/vuu-utils"; -import cx from "classnames"; +import { filterAsQuery, isMultiClauseFilter, useId } from "@finos/vuu-utils"; +import cx from "clsx"; import { HTMLAttributes, useCallback, useRef } from "react"; import { FilterPillMenu } from "../filter-pill-menu"; import { filterClauses } from "../filter-utils"; diff --git a/vuu-ui/packages/vuu-icons/index.css b/vuu-ui/packages/vuu-icons/index.css index df0ae24f9..b7376c4d1 100644 --- a/vuu-ui/packages/vuu-icons/index.css +++ b/vuu-ui/packages/vuu-icons/index.css @@ -84,7 +84,7 @@ span[data-icon] { background-color: var(--vuu-icon-color, var(--saltIcon-color, var(--salt-text-secondary-foreground))); left: var(--vuu-icon-left, auto); height: var(--vuu-icon-height, var(--vuu-icon-size, 12px)); - -webkit-mask: var(--vuu-icon-svg) center center/var(--vuu-icon-size) var(--vuu-icon-size); + /* -webkit-mask: var(--vuu-icon-svg) center center/var(--vuu-icon-size) var(--vuu-icon-size); */ mask: var(--vuu-icon-svg) center center/var(--vuu-icon-size) var(--vuu-icon-size); mask-repeat: no-repeat; -webkit-mask-repeat: no-repeat; diff --git a/vuu-ui/packages/vuu-layout/package.json b/vuu-ui/packages/vuu-layout/package.json index 764ef8bbe..929fd6860 100644 --- a/vuu-ui/packages/vuu-layout/package.json +++ b/vuu-ui/packages/vuu-layout/package.json @@ -11,7 +11,8 @@ }, "types": "src/index.ts", "dependencies": { - "@salt-ds/core": "1.8.0", + "@salt-ds/core": "1.13.2", + "@finos/vuu-data-types": "0.0.26", "@finos/vuu-filters": "0.0.26", "@finos/vuu-popups": "0.0.26", "@finos/vuu-table": "0.0.26", @@ -20,8 +21,9 @@ "@finos/vuu-utils": "0.0.26" }, "peerDependencies": { - "classnames": "^2.2.6", + "clsx": "^2.0.0", "react": ">=17.0.2", "react-dom": ">=17.0.2" - } + }, + "sideEffects": false } diff --git a/vuu-ui/packages/vuu-layout/src/DraggableLayout.tsx b/vuu-ui/packages/vuu-layout/src/DraggableLayout.tsx index db6b789bb..82c656a70 100644 --- a/vuu-ui/packages/vuu-layout/src/DraggableLayout.tsx +++ b/vuu-ui/packages/vuu-layout/src/DraggableLayout.tsx @@ -1,4 +1,4 @@ -import classnames from "classnames"; +import classnames from "clsx"; import { ForwardedRef, forwardRef, HTMLAttributes } from "react"; import { registerComponent } from "./registry/ComponentRegistry"; diff --git a/vuu-ui/packages/vuu-layout/src/dock-layout/DockLayout.tsx b/vuu-ui/packages/vuu-layout/src/dock-layout/DockLayout.tsx index 88a112f2d..61f60f00a 100644 --- a/vuu-ui/packages/vuu-layout/src/dock-layout/DockLayout.tsx +++ b/vuu-ui/packages/vuu-layout/src/dock-layout/DockLayout.tsx @@ -1,5 +1,5 @@ import { partition } from "@finos/vuu-utils"; -import cx from "classnames"; +import cx from "clsx"; import { HTMLAttributes, ReactElement } from "react"; import { registerComponent } from "../registry/ComponentRegistry"; import Drawer from "./Drawer"; diff --git a/vuu-ui/packages/vuu-layout/src/dock-layout/Drawer.tsx b/vuu-ui/packages/vuu-layout/src/dock-layout/Drawer.tsx index 673296b26..6b45bcf4c 100644 --- a/vuu-ui/packages/vuu-layout/src/dock-layout/Drawer.tsx +++ b/vuu-ui/packages/vuu-layout/src/dock-layout/Drawer.tsx @@ -1,5 +1,5 @@ import { Button, useControlled } from "@salt-ds/core"; -import cx from "classnames"; +import cx from "clsx"; import { CSSProperties, HTMLAttributes, useCallback } from "react"; import "./Drawer.css"; diff --git a/vuu-ui/packages/vuu-layout/src/drag-drop/DropMenu.tsx b/vuu-ui/packages/vuu-layout/src/drag-drop/DropMenu.tsx index f886a73a0..7c66b693f 100644 --- a/vuu-ui/packages/vuu-layout/src/drag-drop/DropMenu.tsx +++ b/vuu-ui/packages/vuu-layout/src/drag-drop/DropMenu.tsx @@ -1,4 +1,4 @@ -import cx from "classnames"; +import cx from "clsx"; import { HTMLAttributes } from "react"; import { DropTarget } from "./DropTarget"; diff --git a/vuu-ui/packages/vuu-layout/src/flexbox/Flexbox.tsx b/vuu-ui/packages/vuu-layout/src/flexbox/Flexbox.tsx index 09c2cec87..506de41fa 100644 --- a/vuu-ui/packages/vuu-layout/src/flexbox/Flexbox.tsx +++ b/vuu-ui/packages/vuu-layout/src/flexbox/Flexbox.tsx @@ -1,5 +1,5 @@ import { useForkRef } from "@salt-ds/core"; -import cx from "classnames"; +import cx from "clsx"; import { CSSProperties, ForwardedRef, forwardRef } from "react"; import { FlexboxProps } from "./flexboxTypes"; import { useSplitterResizing } from "./useSplitterResizing"; diff --git a/vuu-ui/packages/vuu-layout/src/flexbox/FluidGrid.tsx b/vuu-ui/packages/vuu-layout/src/flexbox/FluidGrid.tsx index b582ac163..da9cb9d74 100644 --- a/vuu-ui/packages/vuu-layout/src/flexbox/FluidGrid.tsx +++ b/vuu-ui/packages/vuu-layout/src/flexbox/FluidGrid.tsx @@ -1,5 +1,5 @@ import { useForkRef } from "@salt-ds/core"; -import cx from "classnames"; +import cx from "clsx"; import { ForwardedRef, forwardRef, useMemo } from "react"; import { useBreakpoints } from "../responsive"; import { asReactElements } from "../utils"; diff --git a/vuu-ui/packages/vuu-layout/src/flexbox/Splitter.tsx b/vuu-ui/packages/vuu-layout/src/flexbox/Splitter.tsx index 342b9f630..227d16779 100644 --- a/vuu-ui/packages/vuu-layout/src/flexbox/Splitter.tsx +++ b/vuu-ui/packages/vuu-layout/src/flexbox/Splitter.tsx @@ -1,4 +1,4 @@ -import cx from "classnames"; +import cx from "clsx"; import React, { HTMLAttributes, KeyboardEvent, diff --git a/vuu-ui/packages/vuu-layout/src/index.ts b/vuu-ui/packages/vuu-layout/src/index.ts index 039e77a90..e8fb4cef9 100644 --- a/vuu-ui/packages/vuu-layout/src/index.ts +++ b/vuu-ui/packages/vuu-layout/src/index.ts @@ -5,7 +5,6 @@ export * from "./DraggableLayout"; export * from "./flexbox"; export { Action } from "./layout-action"; export * from "./layout-header"; -export * from "./layout-persistence"; export * from "./layout-provider"; export * from "./layout-reducer"; export * from "./layout-view"; diff --git a/vuu-ui/packages/vuu-layout/src/layout-header/ActionButton.tsx b/vuu-ui/packages/vuu-layout/src/layout-header/ActionButton.tsx index bd1dc385d..9baf38292 100644 --- a/vuu-ui/packages/vuu-layout/src/layout-header/ActionButton.tsx +++ b/vuu-ui/packages/vuu-layout/src/layout-header/ActionButton.tsx @@ -1,22 +1,33 @@ -import classnames from 'classnames'; -import { HTMLAttributes, MouseEvent } from 'react'; +import classnames from "clsx"; +import { HTMLAttributes, MouseEvent } from "react"; -export interface ActionButtonProps extends Omit, 'onClick'> { - actionId: 'maximize' | 'minimize' | 'restore' | 'tearout'; +export interface ActionButtonProps + extends Omit, "onClick"> { + actionId: "maximize" | "minimize" | "restore" | "tearout"; iconName?: string; - onClick: (evt: MouseEvent, actionId: 'maximize' | 'minimize' | 'restore' | 'tearout') => void; + onClick: ( + evt: MouseEvent, + actionId: "maximize" | "minimize" | "restore" | "tearout" + ) => void; } -const ActionButton = ({ actionId, className, iconName, onClick, ...props }: ActionButtonProps) => { +const ActionButton = ({ + actionId, + className, + iconName, + onClick, + ...props +}: ActionButtonProps) => { const handleClick = (evt: MouseEvent) => { onClick(evt, actionId); }; return ( + title="Close View" + > ); }; diff --git a/vuu-ui/packages/vuu-layout/src/layout-header/Header.tsx b/vuu-ui/packages/vuu-layout/src/layout-header/Header.tsx index e128076cf..36f59da79 100644 --- a/vuu-ui/packages/vuu-layout/src/layout-header/Header.tsx +++ b/vuu-ui/packages/vuu-layout/src/layout-header/Header.tsx @@ -1,6 +1,6 @@ import { EditableLabel } from "@finos/vuu-ui-controls"; import { Button } from "@salt-ds/core"; -import { default as classnames, default as cx } from "classnames"; +import { default as classnames, default as cx } from "clsx"; import { cloneElement, HTMLAttributes, diff --git a/vuu-ui/packages/vuu-layout/src/layout-persistence/index.ts b/vuu-ui/packages/vuu-layout/src/layout-persistence/index.ts deleted file mode 100644 index 06c29a51c..000000000 --- a/vuu-ui/packages/vuu-layout/src/layout-persistence/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export * from "./defaultApplicationJson"; -export * from "./LayoutPersistenceManager"; -export * from "./LocalLayoutPersistenceManager"; -export * from "./RemoteLayoutPersistenceManager"; -export * from "./useLayoutContextMenuItems"; diff --git a/vuu-ui/packages/vuu-layout/src/layout-view/View.tsx b/vuu-ui/packages/vuu-layout/src/layout-view/View.tsx index aef7a57b0..0d9109992 100644 --- a/vuu-ui/packages/vuu-layout/src/layout-view/View.tsx +++ b/vuu-ui/packages/vuu-layout/src/layout-view/View.tsx @@ -1,5 +1,6 @@ +import { useId } from "@finos/vuu-utils"; import { useForkRef } from "@salt-ds/core"; -import cx from "classnames"; +import cx from "clsx"; import React, { ForwardedRef, forwardRef, @@ -11,7 +12,6 @@ import React, { } from "react"; import { Header as VuuHeader } from "../layout-header/Header"; import { registerComponent } from "../registry/ComponentRegistry"; -import { useId } from "../utils"; import { useView } from "./useView"; import { useViewResize } from "./useViewResize"; import { ViewContext, ViewContextAPI } from "./ViewContext"; diff --git a/vuu-ui/packages/vuu-layout/src/layout-view/useViewActionDispatcher.ts b/vuu-ui/packages/vuu-layout/src/layout-view/useViewActionDispatcher.ts index 6fc2fb2eb..1fd356a6f 100644 --- a/vuu-ui/packages/vuu-layout/src/layout-view/useViewActionDispatcher.ts +++ b/vuu-ui/packages/vuu-layout/src/layout-view/useViewActionDispatcher.ts @@ -1,4 +1,4 @@ -import { DataSource } from "@finos/vuu-data"; +import { DataSource } from "@finos/vuu-data-types"; import { ReactElement, RefObject, diff --git a/vuu-ui/packages/vuu-layout/src/measured-container/MeasuredContainer.tsx b/vuu-ui/packages/vuu-layout/src/measured-container/MeasuredContainer.tsx index a76471c5c..bf8f9571c 100644 --- a/vuu-ui/packages/vuu-layout/src/measured-container/MeasuredContainer.tsx +++ b/vuu-ui/packages/vuu-layout/src/measured-container/MeasuredContainer.tsx @@ -1,7 +1,7 @@ import { CSSProperties, forwardRef, ForwardedRef, HTMLAttributes } from "react"; import { MeasuredSize, useMeasuredContainer } from "./useMeasuredContainer"; import { useForkRef } from "@salt-ds/core"; -import cx from "classnames"; +import cx from "clsx"; import "./MeasuredContainer.css"; diff --git a/vuu-ui/packages/vuu-layout/src/overflow-container/OverflowContainer.tsx b/vuu-ui/packages/vuu-layout/src/overflow-container/OverflowContainer.tsx index da47264c6..451ffe79f 100644 --- a/vuu-ui/packages/vuu-layout/src/overflow-container/OverflowContainer.tsx +++ b/vuu-ui/packages/vuu-layout/src/overflow-container/OverflowContainer.tsx @@ -1,8 +1,7 @@ import { PopupMenu, PopupMenuProps } from "@finos/vuu-popups"; -import { orientationType } from "@finos/vuu-utils"; -import { useId } from "@finos/vuu-layout"; +import { orientationType, useId } from "@finos/vuu-utils"; -import cx from "classnames"; +import cx from "clsx"; import React, { CSSProperties, ForwardedRef, diff --git a/vuu-ui/packages/vuu-layout/src/overflow-container/useOverflowContainer.ts b/vuu-ui/packages/vuu-layout/src/overflow-container/useOverflowContainer.ts index 3b91b19f0..0966fe4e1 100644 --- a/vuu-ui/packages/vuu-layout/src/overflow-container/useOverflowContainer.ts +++ b/vuu-ui/packages/vuu-layout/src/overflow-container/useOverflowContainer.ts @@ -1,8 +1,11 @@ import { MenuActionHandler, MenuBuilder } from "@finos/vuu-data-types"; import { useDragDropNext as useDragDrop } from "@finos/vuu-ui-controls"; -import { isValidNumber, MEASURES } from "@finos/vuu-utils"; +import { + isValidNumber, + MEASURES, + useLayoutEffectSkipFirst, +} from "@finos/vuu-utils"; import { useCallback, useMemo, useRef, useState } from "react"; -import { useLayoutEffectSkipFirst } from "../utils"; import { applyOverflowClassToWrappedItems, removeOverflowIndicatorIfNoLongerNeeded, diff --git a/vuu-ui/packages/vuu-layout/src/palette/Palette.tsx b/vuu-ui/packages/vuu-layout/src/palette/Palette.tsx index 2fd0bfe93..bd23f0097 100644 --- a/vuu-ui/packages/vuu-layout/src/palette/Palette.tsx +++ b/vuu-ui/packages/vuu-layout/src/palette/Palette.tsx @@ -5,7 +5,7 @@ import { ListItemProps, ListProps, } from "@finos/vuu-ui-controls"; -import cx from "classnames"; +import cx from "clsx"; import { cloneElement, HTMLAttributes, diff --git a/vuu-ui/packages/vuu-layout/src/placeholder/LayoutStartPanel.tsx b/vuu-ui/packages/vuu-layout/src/placeholder/LayoutStartPanel.tsx index 3369d32e0..2a73ac743 100644 --- a/vuu-ui/packages/vuu-layout/src/placeholder/LayoutStartPanel.tsx +++ b/vuu-ui/packages/vuu-layout/src/placeholder/LayoutStartPanel.tsx @@ -1,6 +1,6 @@ import { Button } from "@salt-ds/core"; import { HTMLAttributes, useMemo, useState } from "react"; -import { QueryReponse, useViewContext } from "@finos/vuu-layout"; +import { QueryReponse, useViewContext } from "../layout-view"; import "./LayoutStartPanel.css"; diff --git a/vuu-ui/packages/vuu-layout/src/placeholder/Placeholder.tsx b/vuu-ui/packages/vuu-layout/src/placeholder/Placeholder.tsx index b1f424085..3bc656d3a 100644 --- a/vuu-ui/packages/vuu-layout/src/placeholder/Placeholder.tsx +++ b/vuu-ui/packages/vuu-layout/src/placeholder/Placeholder.tsx @@ -1,7 +1,7 @@ -import cx from "classnames"; +import cx from "clsx"; import { registerComponent } from "../registry/ComponentRegistry"; import { LayoutStartPanel } from "./LayoutStartPanel"; -import { View, ViewProps } from "@finos/vuu-layout"; +import { View, ViewProps } from "../layout-view"; import "./Placeholder.css"; diff --git a/vuu-ui/packages/vuu-layout/src/stack/Stack.tsx b/vuu-ui/packages/vuu-layout/src/stack/Stack.tsx index 5203675d6..a7eac8751 100644 --- a/vuu-ui/packages/vuu-layout/src/stack/Stack.tsx +++ b/vuu-ui/packages/vuu-layout/src/stack/Stack.tsx @@ -1,5 +1,6 @@ import { Tab, Tabstrip, TabstripProps } from "@finos/vuu-ui-controls"; -import cx from "classnames"; +import { useId } from "@finos/vuu-utils"; +import cx from "clsx"; import React, { ForwardedRef, forwardRef, @@ -9,7 +10,6 @@ import React, { useRef, } from "react"; import { getDefaultTabLabel } from "../layout-reducer"; -import { useId } from "../utils"; import { StackProps } from "./stackTypes"; import "./Stack.css"; diff --git a/vuu-ui/packages/vuu-layout/src/stack/StackLayout.tsx b/vuu-ui/packages/vuu-layout/src/stack/StackLayout.tsx index efa3e069d..cef23cf15 100644 --- a/vuu-ui/packages/vuu-layout/src/stack/StackLayout.tsx +++ b/vuu-ui/packages/vuu-layout/src/stack/StackLayout.tsx @@ -1,4 +1,4 @@ -import { useIdMemo as useId } from "@salt-ds/core"; +import { useId } from "@finos/vuu-utils"; import React, { useCallback, useRef } from "react"; import { useLayoutCreateNewChild, @@ -10,9 +10,9 @@ import { usePersistentState } from "../use-persistent-state"; import { Stack } from "./Stack"; import { StackProps, TabLabelFactory } from "./stackTypes"; import { getDefaultTabLabel } from "../layout-reducer"; +import { Placeholder } from "../placeholder"; import "./Stack.css"; -import { Placeholder } from "../placeholder"; const defaultCreateNewChild = () => ( { const isArray = Array.isArray(children); const count = isArray ? children.length : Children.count(children); @@ -27,21 +15,3 @@ export const asReactElements = (children: ReactNode): ReactElement[] => { return EMPTY_ARRAY; } }; - -export const useLayoutEffectSkipFirst = ( - func: EffectCallback, - deps: DependencyList -) => { - const goodToGo = useRef(false); - useLayoutEffect(() => { - if (goodToGo.current) { - func(); - } else { - goodToGo.current = true; - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, deps); -}; - -export const useId = (id?: string) => - useMemo(() => id ?? `vuu-${++vuuComponentIdCount}`, [id]); diff --git a/vuu-ui/packages/vuu-popups/package.json b/vuu-ui/packages/vuu-popups/package.json index 8e5056850..3fc887e8d 100644 --- a/vuu-ui/packages/vuu-popups/package.json +++ b/vuu-ui/packages/vuu-popups/package.json @@ -10,19 +10,16 @@ "type-defs": "node ../../scripts/build-type-defs.mjs" }, "dependencies": { - "@salt-ds/core": "1.8.0", - "@salt-ds/icons": "1.5.1", - "@salt-ds/lab": "1.0.0-alpha.15", - "@finos/vuu-data": "0.0.26", + "@salt-ds/core": "1.13.2", "@finos/vuu-data-types": "0.0.26", "@finos/vuu-layout": "0.0.26", - "@finos/vuu-shell": "0.0.26", "@finos/vuu-utils": "0.0.26", "@finos/vuu-ui-controls": "0.0.26" }, "peerDependencies": { - "classnames": "^2.2.6", + "clsx": "^2.0.0", "react": ">=17.0.2", "react-dom": ">=17.0.2" - } + }, + "sideEffects": false } diff --git a/vuu-ui/packages/vuu-popups/src/dialog-header/DialogHeader.tsx b/vuu-ui/packages/vuu-popups/src/dialog-header/DialogHeader.tsx index 55e18ec5d..b745d3a0c 100644 --- a/vuu-ui/packages/vuu-popups/src/dialog-header/DialogHeader.tsx +++ b/vuu-ui/packages/vuu-popups/src/dialog-header/DialogHeader.tsx @@ -1,6 +1,6 @@ import { Button, Text } from "@salt-ds/core"; import { HTMLAttributes } from "react"; -import cx from "classnames"; +import cx from "clsx"; import "./DialogHeader.css"; diff --git a/vuu-ui/packages/vuu-popups/src/dialog/Dialog.css b/vuu-ui/packages/vuu-popups/src/dialog/Dialog.css index e78d547bd..1d32f4bd5 100644 --- a/vuu-ui/packages/vuu-popups/src/dialog/Dialog.css +++ b/vuu-ui/packages/vuu-popups/src/dialog/Dialog.css @@ -3,8 +3,10 @@ border: var(--vuuDialog-border, solid 1px #ccc); border-radius: 5px; padding: var(--vuuDialog-padding, 16px); + position: relative; box-shadow: var(--salt-overlayable-shadow, none); height: var(--vuuDialog-height, fit-content); + overflow: visible; width: var(--vuuDialog-width, fit-content); } diff --git a/vuu-ui/packages/vuu-popups/src/dialog/Dialog.tsx b/vuu-ui/packages/vuu-popups/src/dialog/Dialog.tsx index 6338c682d..4c523fbbe 100644 --- a/vuu-ui/packages/vuu-popups/src/dialog/Dialog.tsx +++ b/vuu-ui/packages/vuu-popups/src/dialog/Dialog.tsx @@ -1,50 +1,95 @@ -import { Scrim } from "@salt-ds/lab"; -import cx from "classnames"; -import { HTMLAttributes, useCallback, useRef } from "react"; -import { Portal } from "../portal"; +import cx from "clsx"; +import { useThemeAttributes } from "@finos/vuu-utils"; +import { HTMLAttributes, useCallback, useLayoutEffect, useRef } from "react"; import { DialogHeader } from "../dialog-header"; import "./Dialog.css"; +import { PopupComponentProps, useAnchoredPosition } from "../popup"; const classBase = "vuuDialog"; -export interface DialogProps extends HTMLAttributes { +const AnchorBody = { current: document.body }; +const EMPTY_PROPS = {}; + +export interface DialogProps extends HTMLAttributes { + PopupProps?: Partial; isOpen?: boolean; onClose?: () => void; hideCloseButton?: boolean; } export const Dialog = ({ + PopupProps = EMPTY_PROPS, children, className, isOpen = false, onClose, + style, title, hideCloseButton = false, - ...props + ...htmlAttributes }: DialogProps) => { - const root = useRef(null); + const { + anchorElement = AnchorBody, + offsetLeft = 0, + offsetTop = 0, + placement = "auto", + } = PopupProps; + + const rootRef = useRef(null); + const portalRef = useRef(null); + const [themeClass, densityClass, dataMode] = useThemeAttributes(); + const { position } = useAnchoredPosition({ + anchorElement, + offsetLeft, + offsetTop, + placement, + }); const close = useCallback(() => { onClose?.(); }, [onClose]); - if (!isOpen) { - return null; - } + // if (!isOpen) { + // return null; + // } + + useLayoutEffect(() => { + if (rootRef.current) { + if (isOpen) { + rootRef.current.showModal(); + + const { left, top } = rootRef.current.getBoundingClientRect(); + if (portalRef.current) { + portalRef.current.style.cssText = `left:-${left}px;position:absolute;top:-${top}px;`; + } + } else { + rootRef.current.close(); + } + if (placement.endsWith("center")) { + const { width } = rootRef.current.getBoundingClientRect(); + rootRef.current.style.marginLeft = `-${width / 2}px`; + } + } + }, [isOpen, placement]); return ( - - -
- -
{children}
-
-
-
+ + +
{children}
+
+
); }; diff --git a/vuu-ui/packages/vuu-popups/src/menu/ContextMenu.tsx b/vuu-ui/packages/vuu-popups/src/menu/ContextMenu.tsx index 6d5d2cdd3..21d52e75b 100644 --- a/vuu-ui/packages/vuu-popups/src/menu/ContextMenu.tsx +++ b/vuu-ui/packages/vuu-popups/src/menu/ContextMenu.tsx @@ -1,15 +1,11 @@ +import { useId } from "@finos/vuu-utils"; import { useCallback, useRef } from "react"; +import { PopupCloseCallback, PopupComponent } from "../popup"; +import { Portal, PortalProps } from "../portal"; import { MenuList, MenuListProps } from "./MenuList"; import { useCascade } from "./use-cascade"; import { useItemsWithIdsNext } from "./use-items-with-ids-next"; -import { useId } from "@finos/vuu-layout"; -import { PopupCloseCallback } from "../popup"; import { ContextMenuOptions } from "./useContextMenu"; -import { - PopupComponent as Popup, - Portal, - PortalProps, -} from "@finos/vuu-popups"; export interface ContextMenuProps extends Omit { PortalProps?: Partial; @@ -97,7 +93,7 @@ export const ContextMenu = ({ const childMenuId = getChildMenuId(i); return ( - {menus[menuId]} - + ); })} diff --git a/vuu-ui/packages/vuu-popups/src/menu/MenuList.css b/vuu-ui/packages/vuu-popups/src/menu/MenuList.css index 16c33a0d5..6dcd5b5eb 100644 --- a/vuu-ui/packages/vuu-popups/src/menu/MenuList.css +++ b/vuu-ui/packages/vuu-popups/src/menu/MenuList.css @@ -65,8 +65,7 @@ .vuuMenuItem[aria-haspopup='true']:after { content: var(--menu-item-twisty-content); - -webkit-mask: var(--vuu-svg-chevron-right) center center/8px 8px no-repeat; - mask: var(---vuu-svg-chevron-right) center center/8px 8px no-repeat; + mask: var(--vuu-svg-chevron-right) center center/8px 8px no-repeat; background-color: var(--menu-item-twisty-color); height: 16px; left: var(--menu-item-twisty-left); diff --git a/vuu-ui/packages/vuu-popups/src/menu/MenuList.tsx b/vuu-ui/packages/vuu-popups/src/menu/MenuList.tsx index 08eb66c41..7b41e5d5c 100644 --- a/vuu-ui/packages/vuu-popups/src/menu/MenuList.tsx +++ b/vuu-ui/packages/vuu-popups/src/menu/MenuList.tsx @@ -1,3 +1,4 @@ +import cx from "clsx"; import React, { FC, HTMLAttributes, @@ -7,11 +8,10 @@ import React, { useMemo, useRef, } from "react"; -import cx from "classnames"; //TODO do we want this dependency ? -import { useId } from "@finos/vuu-layout"; -import { useKeyboardNavigation } from "./use-keyboard-navigation"; +import { useId } from "@finos/vuu-utils"; import { isMenuItemGroup } from "./use-items-with-ids-next"; +import { useKeyboardNavigation } from "./use-keyboard-navigation"; import "./MenuList.css"; diff --git a/vuu-ui/packages/vuu-popups/src/menu/useContextMenu.tsx b/vuu-ui/packages/vuu-popups/src/menu/useContextMenu.tsx index 54e1355a7..3ddb6ebdb 100644 --- a/vuu-ui/packages/vuu-popups/src/menu/useContextMenu.tsx +++ b/vuu-ui/packages/vuu-popups/src/menu/useContextMenu.tsx @@ -3,7 +3,10 @@ import { MenuActionHandler, MenuBuilder, } from "@finos/vuu-data-types"; -import { isGroupMenuItemDescriptor } from "@finos/vuu-utils"; +import { + isGroupMenuItemDescriptor, + useThemeAttributes, +} from "@finos/vuu-utils"; import { cloneElement, useCallback, useContext, useMemo } from "react"; import { MenuActionClosePopup, @@ -14,7 +17,6 @@ import { import { ContextMenu, ContextMenuProps } from "./ContextMenu"; import { MenuItem, MenuItemGroup } from "./MenuList"; import { ContextMenuContext } from "./context-menu-provider"; -import { useThemeAttributes } from "@finos/vuu-shell"; export type ContextMenuOptions = { [key: string]: unknown; diff --git a/vuu-ui/packages/vuu-popups/src/notifications/NotificationsProvider.tsx b/vuu-ui/packages/vuu-popups/src/notifications/NotificationsProvider.tsx index 9fd2c67e9..96fa49e33 100644 --- a/vuu-ui/packages/vuu-popups/src/notifications/NotificationsProvider.tsx +++ b/vuu-ui/packages/vuu-popups/src/notifications/NotificationsProvider.tsx @@ -1,5 +1,5 @@ import React, { useState, useContext, useCallback, useEffect } from "react"; -import classNames from "classnames"; +import classNames from "clsx"; import { getUniqueId } from "@finos/vuu-utils"; import "./notifications.css"; @@ -93,9 +93,7 @@ export const ToastNotification = (props: ToastNotificationProps) => { const [right, setRight] = useState(-toastWidth - toastContainerRightPadding); useEffect(() => { - setTimeout( - () => setRight(toastContainerRightPadding) - ); + setTimeout(() => setRight(toastContainerRightPadding)); if (animated) { setTimeout( diff --git a/vuu-ui/packages/vuu-popups/src/popup-menu/PopupMenu.tsx b/vuu-ui/packages/vuu-popups/src/popup-menu/PopupMenu.tsx index 110cc7513..be5671d0e 100644 --- a/vuu-ui/packages/vuu-popups/src/popup-menu/PopupMenu.tsx +++ b/vuu-ui/packages/vuu-popups/src/popup-menu/PopupMenu.tsx @@ -1,3 +1,7 @@ +import { MenuActionHandler, MenuBuilder } from "@finos/vuu-data-types"; +import { useId } from "@finos/vuu-utils"; +import { Button } from "@salt-ds/core"; +import cx from "clsx"; import { HTMLAttributes, MouseEvent, @@ -5,17 +9,12 @@ import { useRef, useState, } from "react"; +import { MenuOpenHandler, useContextMenu } from "../menu"; import { - MenuOpenHandler, PopupCloseCallback, PopupCloseReason, reasonIsClickAway, - useContextMenu, -} from "@finos/vuu-popups"; -import cx from "classnames"; -import { Button } from "@salt-ds/core"; -import { useId } from "@finos/vuu-layout"; -import { MenuActionHandler, MenuBuilder } from "@finos/vuu-data-types"; +} from "../popup/popup-service"; import "./PopupMenu.css"; diff --git a/vuu-ui/packages/vuu-popups/src/popup/Popup.tsx b/vuu-ui/packages/vuu-popups/src/popup/Popup.tsx index 30450c84e..bdc250dd8 100644 --- a/vuu-ui/packages/vuu-popups/src/popup/Popup.tsx +++ b/vuu-ui/packages/vuu-popups/src/popup/Popup.tsx @@ -1,4 +1,4 @@ -import cx from "classnames"; +import cx from "clsx"; import { HTMLAttributes, RefObject } from "react"; import { Position, useAnchoredPosition } from "./useAnchoredPosition"; @@ -6,6 +6,7 @@ import "./Popup.css"; export type PopupPlacement = | "absolute" + | "auto" | "below" | "below-center" | "below-right" diff --git a/vuu-ui/packages/vuu-popups/src/popup/popup-service.ts b/vuu-ui/packages/vuu-popups/src/popup/popup-service.ts index 34ede5088..c1eddb349 100644 --- a/vuu-ui/packages/vuu-popups/src/popup/popup-service.ts +++ b/vuu-ui/packages/vuu-popups/src/popup/popup-service.ts @@ -1,4 +1,4 @@ -import cx from "classnames"; +import cx from "clsx"; import React, { createElement, CSSProperties, diff --git a/vuu-ui/packages/vuu-popups/src/popup/useAnchoredPosition.ts b/vuu-ui/packages/vuu-popups/src/popup/useAnchoredPosition.ts index 09d367664..a1aa0b4cb 100644 --- a/vuu-ui/packages/vuu-popups/src/popup/useAnchoredPosition.ts +++ b/vuu-ui/packages/vuu-popups/src/popup/useAnchoredPosition.ts @@ -89,7 +89,7 @@ export const useAnchoredPosition = ({ useLayoutEffect(() => { if (placement === "absolute" && positionProp) { setPosition(positionProp); - } else if (anchorElement.current) { + } else if (anchorElement.current && placement !== "auto") { const dimensions = popupRef.current === null ? undefined diff --git a/vuu-ui/packages/vuu-popups/src/portal-deprecated/render-portal.tsx b/vuu-ui/packages/vuu-popups/src/portal-deprecated/render-portal.tsx index 03389d2f3..ebae78907 100644 --- a/vuu-ui/packages/vuu-popups/src/portal-deprecated/render-portal.tsx +++ b/vuu-ui/packages/vuu-popups/src/portal-deprecated/render-portal.tsx @@ -1,6 +1,6 @@ import * as ReactDOM from "react-dom"; import { ReactElement } from "react"; -import cx from "classnames"; +import cx from "clsx"; let containerId = 1; diff --git a/vuu-ui/packages/vuu-popups/src/portal/Portal.tsx b/vuu-ui/packages/vuu-popups/src/portal/Portal.tsx index f09bd0045..55d86557b 100644 --- a/vuu-ui/packages/vuu-popups/src/portal/Portal.tsx +++ b/vuu-ui/packages/vuu-popups/src/portal/Portal.tsx @@ -1,4 +1,4 @@ -import { ThemeAttributes, useThemeAttributes } from "@finos/vuu-shell"; +import { ThemeAttributes, useThemeAttributes } from "@finos/vuu-utils"; import { ReactNode, useLayoutEffect, useRef, useState } from "react"; import { createPortal } from "react-dom"; @@ -18,9 +18,11 @@ export interface PortalProps { */ container?: Element | (() => Element | null) | null; /** - * If this node does not exist on the document, it will be created for you. + * Id of element into which portal will be rendered. If this node does not exist on the document, + * it will be created for you. If more than one value is provided, the first element found will + * be used. */ - id?: string; + id?: string | string[]; /** * Callback invoked immediately after render (in layoutEffect). Can be * used to check position vis-a-vis viewport and adjust if out of bounds @@ -42,7 +44,21 @@ function getContainer(container: PortalProps["container"]) { return typeof container === "function" ? container() : container; } -const DEFAULT_ID = "vuu-portal-root"; +const DEFAULT_ID = ["vuu-dialog-portal-root", "vuu-portal-root"]; + +const getFirstAvailableElementById = (id: string | string[]) => { + if (Array.isArray(id)) { + for (const i of id) { + const element = document.getElementById(i); + if (element) { + return element; + } + } + } else { + return document.getElementById(id); + } + return null; +}; /** * Portals provide a first-class way to render children into a DOM node @@ -63,12 +79,17 @@ export const Portal = ({ useThemeAttributes(themeAttributes); useLayoutEffect(() => { - const root = document.getElementById(id); + const root = getFirstAvailableElementById(id); if (root) { portalRef.current = root; } else { portalRef.current = document.createElement("div"); - portalRef.current.id = id; + portalRef.current.id = + typeof id === "string" + ? id + : id.length > 0 + ? (id.at(-1) as string) + : "vuu-portal-root"; } const el = portalRef.current; if (!container.contains(el)) { diff --git a/vuu-ui/packages/vuu-popups/src/prompt/Prompt.tsx b/vuu-ui/packages/vuu-popups/src/prompt/Prompt.tsx index fd2406e81..8432e8675 100644 --- a/vuu-ui/packages/vuu-popups/src/prompt/Prompt.tsx +++ b/vuu-ui/packages/vuu-popups/src/prompt/Prompt.tsx @@ -1,6 +1,6 @@ -import { useThemeAttributes } from "@finos/vuu-shell"; +import { useThemeAttributes } from "@finos/vuu-utils"; import { Button } from "@salt-ds/core"; -import cx from "classnames"; +import cx from "clsx"; import { HTMLAttributes, useLayoutEffect, useRef } from "react"; import { PopupComponentProps, useAnchoredPosition } from "../popup"; diff --git a/vuu-ui/packages/vuu-popups/src/tooltip/Tooltip.tsx b/vuu-ui/packages/vuu-popups/src/tooltip/Tooltip.tsx index 18b3391ad..b0dbc97a3 100644 --- a/vuu-ui/packages/vuu-popups/src/tooltip/Tooltip.tsx +++ b/vuu-ui/packages/vuu-popups/src/tooltip/Tooltip.tsx @@ -1,7 +1,7 @@ import { CSSProperties, MouseEventHandler, ReactNode, RefObject } from "react"; import { Portal } from "../portal"; import { TooltipPlacement, useAnchoredPosition } from "./useAnchoredPosition"; -import cx from "classnames"; +import cx from "clsx"; import "./Tooltip.css"; diff --git a/vuu-ui/packages/vuu-popups/src/tooltip/useTooltip.ts b/vuu-ui/packages/vuu-popups/src/tooltip/useTooltip.ts index 5e4eb9617..604e817d0 100644 --- a/vuu-ui/packages/vuu-popups/src/tooltip/useTooltip.ts +++ b/vuu-ui/packages/vuu-popups/src/tooltip/useTooltip.ts @@ -1,7 +1,7 @@ +import { useId } from "@finos/vuu-utils"; import { MouseEvent, ReactNode, useCallback, useRef, useState } from "react"; import { TooltipProps } from "./Tooltip"; import { TooltipPlacement } from "./useAnchoredPosition"; -import { useId } from "@finos/vuu-layout"; export interface TooltipHookProps { id: string; diff --git a/vuu-ui/packages/vuu-shell/package.json b/vuu-ui/packages/vuu-shell/package.json index 2bfd27d39..5ee68a7c4 100644 --- a/vuu-ui/packages/vuu-shell/package.json +++ b/vuu-ui/packages/vuu-shell/package.json @@ -10,9 +10,7 @@ "type-defs": "node ../../scripts/build-type-defs.mjs" }, "dependencies": { - "@salt-ds/core": "1.8.0", - "@salt-ds/icons": "1.5.1", - "@salt-ds/lab": "1.0.0-alpha.15", + "@salt-ds/core": "1.13.2", "@finos/vuu-data": "0.0.26", "@finos/vuu-icons": "0.0.26", "@finos/vuu-filters": "0.0.26", @@ -20,10 +18,11 @@ "@finos/vuu-table": "0.0.26", "@finos/vuu-table-extras": "0.0.26", "@finos/vuu-ui-controls": "0.0.26", - "@finos/vuu-utils": "0.0.26" + "@finos/vuu-utils": "0.0.26", + "html-to-image": "^1.11.11" }, "peerDependencies": { - "classnames": "^2.2.6", + "clsx": "^2.0.0", "react": ">=17.0.2", "react-dom": ">=17.0.2" } diff --git a/vuu-ui/packages/vuu-shell/src/ShellContextProvider.tsx b/vuu-ui/packages/vuu-shell/src/ShellContextProvider.tsx index 6bdb0c67f..a14067b19 100644 --- a/vuu-ui/packages/vuu-shell/src/ShellContextProvider.tsx +++ b/vuu-ui/packages/vuu-shell/src/ShellContextProvider.tsx @@ -1,14 +1,10 @@ -import { ColumnDescriptor, ListOption } from "@finos/vuu-table-types"; +import { DefaultColumnConfiguration, ListOption } from "@finos/vuu-table-types"; import { RpcResponseHandler } from "@finos/vuu-data-react"; import { createContext, ReactElement, ReactNode, useContext } from "react"; import { VuuTable } from "@finos/vuu-protocol-types"; export type LookupTableProvider = (table: VuuTable) => ListOption[]; -export type DefaultColumnConfiguration = ( - tableName: T, - columnName: string -) => Partial | undefined; export interface ShellContextProps { getDefaultColumnConfig?: DefaultColumnConfiguration; getLookupValues?: LookupTableProvider; diff --git a/vuu-ui/packages/vuu-shell/src/app-header/AppHeader.tsx b/vuu-ui/packages/vuu-shell/src/app-header/AppHeader.tsx index 79b59c25a..c1cb8965f 100644 --- a/vuu-ui/packages/vuu-shell/src/app-header/AppHeader.tsx +++ b/vuu-ui/packages/vuu-shell/src/app-header/AppHeader.tsx @@ -2,13 +2,13 @@ import { HTMLAttributes, useCallback } from "react"; import { VuuUser } from "../shell"; // import { UserProfile } from "../user-profile"; // import { ThemeSwitch } from "../theme-switch"; -import { ThemeMode } from "../theme-provider"; -import cx from "classnames"; import { Toolbar } from "@finos/vuu-layout"; +import { ThemeMode } from "@finos/vuu-utils"; +import cx from "clsx"; import { logout } from "../login"; -import "./AppHeader.css"; import { Button } from "@salt-ds/core"; +import "./AppHeader.css"; const classBase = "vuuAppHeader"; export interface AppHeaderProps extends HTMLAttributes { diff --git a/vuu-ui/packages/vuu-shell/src/connection-status/ConnectionStatusIcon.tsx b/vuu-ui/packages/vuu-shell/src/connection-status/ConnectionStatusIcon.tsx index 2a3456db6..2cf5c3e3c 100644 --- a/vuu-ui/packages/vuu-shell/src/connection-status/ConnectionStatusIcon.tsx +++ b/vuu-ui/packages/vuu-shell/src/connection-status/ConnectionStatusIcon.tsx @@ -1,49 +1,58 @@ -import React, { useEffect, useState } from 'react'; -import cx from 'classnames'; -import './ConnectionStatusIcon.css'; +import React, { useEffect, useState } from "react"; +import cx from "clsx"; -type connectionStatus = 'connected' | 'reconnected' | 'connecting' | 'disconnected'; +import "./ConnectionStatusIcon.css"; + +type connectionStatus = + | "connected" + | "reconnected" + | "connecting" + | "disconnected"; interface ConnectionStatusProps { - connectionStatus: connectionStatus - className?: string; - props?: unknown; - element?: string; + connectionStatus: connectionStatus; + className?: string; + props?: unknown; + element?: string; } -export const ConnectionStatusIcon = ({ connectionStatus, className, element = 'span', ...props}: ConnectionStatusProps) => { - const [classBase, setClassBase] = useState('vuuConnectingStatus'); - useEffect(() => { - switch(connectionStatus) { - case 'connected': - case 'reconnected': - setClassBase('vuuActiveStatus'); - break; - case 'connecting': - setClassBase('vuuConnectingStatus'); - break; - case 'disconnected': - setClassBase('vuuDisconnectedStatus'); - break; - default: - break; - } - }, [connectionStatus]); +export const ConnectionStatusIcon = ({ + connectionStatus, + className, + element = "span", + ...props +}: ConnectionStatusProps) => { + const [classBase, setClassBase] = useState("vuuConnectingStatus"); + useEffect(() => { + switch (connectionStatus) { + case "connected": + case "reconnected": + setClassBase("vuuActiveStatus"); + break; + case "connecting": + setClassBase("vuuConnectingStatus"); + break; + case "disconnected": + setClassBase("vuuDisconnectedStatus"); + break; + default: + break; + } + }, [connectionStatus]); - const statusIcon = React.createElement ( - element, - { - ...props, - className: cx('vuuStatus vuuIcon', classBase, className) - }, - ) + const statusIcon = React.createElement(element, { + ...props, + className: cx("vuuStatus vuuIcon", classBase, className), + }); - return ( - <> -
- {statusIcon} -
Status: {connectionStatus.toUpperCase()}
-
- - ) -} \ No newline at end of file + return ( + <> +
+ {statusIcon} +
+ Status: {connectionStatus.toUpperCase()} +
+
+ + ); +}; diff --git a/vuu-ui/packages/vuu-shell/src/density-switch/DensitySwitch.tsx b/vuu-ui/packages/vuu-shell/src/density-switch/DensitySwitch.tsx deleted file mode 100644 index 03cd00263..000000000 --- a/vuu-ui/packages/vuu-shell/src/density-switch/DensitySwitch.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import { Dropdown } from "@salt-ds/lab"; -import { Density } from "@salt-ds/core"; -import { HTMLAttributes, useCallback } from "react"; -import cx from "classnames"; - -const classBase = "vuuDensitySwitch"; - -const densities: Density[] = ["high", "medium", "low", "touch"]; -const DEFAULT_DENSITY = "high"; - -export interface DensitySwitchProps - extends Omit, "onChange"> { - defaultDensity?: Density; - density?: Density; - onChange: (density: Density) => void; -} - -export const DensitySwitch = ({ - className: classNameProp, - defaultDensity = DEFAULT_DENSITY, - onChange, -}: DensitySwitchProps) => { - const handleSelectionChange = useCallback( - (_event, selectedItem) => { - onChange(selectedItem); - }, - [onChange] - ); - - const className = cx(classBase, classNameProp); - - return ( - - className={className} - source={densities} - defaultSelected={defaultDensity} - onSelectionChange={handleSelectionChange} - /> - ); -}; diff --git a/vuu-ui/packages/vuu-shell/src/density-switch/index.ts b/vuu-ui/packages/vuu-shell/src/density-switch/index.ts deleted file mode 100644 index 239aae884..000000000 --- a/vuu-ui/packages/vuu-shell/src/density-switch/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./DensitySwitch" \ No newline at end of file diff --git a/vuu-ui/packages/vuu-shell/src/index.ts b/vuu-ui/packages/vuu-shell/src/index.ts index 954fed7b5..2a67d7fee 100644 --- a/vuu-ui/packages/vuu-shell/src/index.ts +++ b/vuu-ui/packages/vuu-shell/src/index.ts @@ -1,6 +1,5 @@ export * from "./app-header"; export * from "./connection-status"; -export * from "./density-switch"; export * from "./feature"; export * from "./layout-management"; export * from "./left-nav"; @@ -10,6 +9,5 @@ export * from "./shell"; export * from "./shell-layouts"; export * from "./shellTypes"; export * from "./ShellContextProvider"; -export * from "./theme-provider"; export * from "./feature-list"; export * from "./theme-switch"; diff --git a/vuu-ui/packages/vuu-shell/src/layout-management/SaveLayoutPanel.tsx b/vuu-ui/packages/vuu-shell/src/layout-management/SaveLayoutPanel.tsx index 72678d4cf..f6be8c2d7 100644 --- a/vuu-ui/packages/vuu-shell/src/layout-management/SaveLayoutPanel.tsx +++ b/vuu-ui/packages/vuu-shell/src/layout-management/SaveLayoutPanel.tsx @@ -1,5 +1,5 @@ import { Checkbox, ComboBox, RadioButton } from "@finos/vuu-ui-controls"; -import { takeScreenshot } from "@finos/vuu-utils"; +import { takeScreenshot } from "./screenshot-utils"; import { Button, FormField, FormFieldLabel, Input, Text } from "@salt-ds/core"; import { ChangeEvent, useEffect, useMemo, useState } from "react"; import { LayoutMetadataDto } from "./layoutTypes"; @@ -32,7 +32,9 @@ export const SaveLayoutPanel = (props: SaveLayoutPanelProps) => { const [checkValues, setCheckValues] = useState([]); const [radioValue, setRadioValue] = useState(radioValues[0]); const [screenshot, setScreenshot] = useState(); - const [screenshotErrorMessage, setScreenshotErrorMessage] = useState(); + const [screenshotErrorMessage, setScreenshotErrorMessage] = useState< + string | undefined + >(); useEffect(() => { if (componentId) { diff --git a/vuu-ui/packages/vuu-utils/src/screenshot-utils.ts b/vuu-ui/packages/vuu-shell/src/layout-management/screenshot-utils.ts similarity index 92% rename from vuu-ui/packages/vuu-utils/src/screenshot-utils.ts rename to vuu-ui/packages/vuu-shell/src/layout-management/screenshot-utils.ts index bcfde9ae3..144e4ac3c 100644 --- a/vuu-ui/packages/vuu-utils/src/screenshot-utils.ts +++ b/vuu-ui/packages/vuu-shell/src/layout-management/screenshot-utils.ts @@ -8,11 +8,11 @@ import { toPng } from "html-to-image"; export const takeScreenshot = (node: HTMLElement): Promise => { return new Promise((resolve, reject) => { toPng(node, { - cacheBust: true, + cacheBust: true /*, filter: (child) => // remove content of table rows child.nodeType === Node.TEXT_NODE || - child.getAttribute("role") !== "row", + child.getAttribute("role") !== "row",*/, }) .then((screenshot) => { if (!screenshot) { diff --git a/vuu-ui/packages/vuu-shell/src/layout-management/useLayoutManager.tsx b/vuu-ui/packages/vuu-shell/src/layout-management/useLayoutManager.tsx index 178795ce8..1048f973a 100644 --- a/vuu-ui/packages/vuu-shell/src/layout-management/useLayoutManager.tsx +++ b/vuu-ui/packages/vuu-shell/src/layout-management/useLayoutManager.tsx @@ -8,25 +8,27 @@ import React, { import { ApplicationJSON, ApplicationSettings, - loadingApplicationJson, LayoutJSON, - LayoutPersistenceManager, - LocalLayoutPersistenceManager, - RemoteLayoutPersistenceManager, resolveJSONPath, - defaultApplicationJson, ApplicationSetting, } from "@finos/vuu-layout"; import { NotificationLevel, useNotifications } from "@finos/vuu-popups"; import { LayoutMetadata, LayoutMetadataDto } from "./layoutTypes"; +import { + defaultApplicationJson, + PersistenceManager, + loadingApplicationJson, + LocalPersistenceManager, + RemotePersistenceManager, +} from "../persistence-management"; -let _persistenceManager: LayoutPersistenceManager; +let _persistenceManager: PersistenceManager; const getPersistenceManager = () => { if (_persistenceManager === undefined) { _persistenceManager = process.env.LOCAL - ? new LocalLayoutPersistenceManager() - : new RemoteLayoutPersistenceManager(); + ? new LocalPersistenceManager() + : new RemotePersistenceManager(); } return _persistenceManager; }; diff --git a/vuu-ui/packages/vuu-shell/src/left-nav/LeftNav.tsx b/vuu-ui/packages/vuu-shell/src/left-nav/LeftNav.tsx index e2cf8b132..6f36ed978 100644 --- a/vuu-ui/packages/vuu-shell/src/left-nav/LeftNav.tsx +++ b/vuu-ui/packages/vuu-shell/src/left-nav/LeftNav.tsx @@ -2,12 +2,12 @@ import { VuuLogo } from "@finos/vuu-icons"; import { Stack, useLayoutProviderDispatch } from "@finos/vuu-layout"; import { LayoutResizeAction } from "@finos/vuu-layout/src/layout-reducer"; import { Tab, Tabstrip } from "@finos/vuu-ui-controls"; -import cx from "classnames"; -import { LayoutList } from "../layout-management"; +import { useThemeAttributes } from "@finos/vuu-utils"; +import cx from "clsx"; import { CSSProperties, HTMLAttributes, useCallback, useState } from "react"; import { FeatureProps } from "../feature"; import { FeatureList } from "../feature-list"; -import { useThemeAttributes } from "../theme-provider"; +import { LayoutList } from "../layout-management"; import "./LeftNav.css"; diff --git a/vuu-ui/packages/vuu-shell/src/login/LoginPanel.tsx b/vuu-ui/packages/vuu-shell/src/login/LoginPanel.tsx index b01ffacfa..b78a0800e 100644 --- a/vuu-ui/packages/vuu-shell/src/login/LoginPanel.tsx +++ b/vuu-ui/packages/vuu-shell/src/login/LoginPanel.tsx @@ -9,7 +9,7 @@ import { import { Button, FormField, FormFieldLabel } from "@salt-ds/core"; import { VuuInput } from "@finos/vuu-ui-controls"; import { VuuLogo } from "./VuuLogo"; -import cx from "classnames"; +import cx from "clsx"; import "./LoginPanel.css"; diff --git a/vuu-ui/packages/vuu-layout/src/layout-persistence/LocalLayoutPersistenceManager.ts b/vuu-ui/packages/vuu-shell/src/persistence-management/LocalPersistenceManager.ts similarity index 96% rename from vuu-ui/packages/vuu-layout/src/layout-persistence/LocalLayoutPersistenceManager.ts rename to vuu-ui/packages/vuu-shell/src/persistence-management/LocalPersistenceManager.ts index 929c70058..c897d4474 100644 --- a/vuu-ui/packages/vuu-layout/src/layout-persistence/LocalLayoutPersistenceManager.ts +++ b/vuu-ui/packages/vuu-shell/src/persistence-management/LocalPersistenceManager.ts @@ -1,23 +1,20 @@ +import { ApplicationJSON, LayoutJSON } from "@finos/vuu-layout"; +import { getLocalEntity, saveLocalEntity } from "@finos/vuu-filters"; +import { formatDate, getUniqueId } from "@finos/vuu-utils"; + +import { defaultApplicationJson } from "./defaultApplicationJson"; +import { PersistenceManager } from "./PersistenceManager"; import { Layout, LayoutMetadata, LayoutMetadataDto, WithId, -} from "@finos/vuu-shell"; -import { - ApplicationJSON, - LayoutJSON, - LayoutPersistenceManager, -} from "@finos/vuu-layout"; -import { getLocalEntity, saveLocalEntity } from "@finos/vuu-filters"; -import { formatDate, getUniqueId } from "@finos/vuu-utils"; - -import { defaultApplicationJson } from "./defaultApplicationJson"; +} from "../layout-management"; const metadataSaveLocation = "layouts/metadata"; const layoutsSaveLocation = "layouts/layouts"; -export class LocalLayoutPersistenceManager implements LayoutPersistenceManager { +export class LocalPersistenceManager implements PersistenceManager { #urlKey = "api/vui"; constructor(urlKey?: string) { if (urlKey) { diff --git a/vuu-ui/packages/vuu-layout/src/layout-persistence/LayoutPersistenceManager.ts b/vuu-ui/packages/vuu-shell/src/persistence-management/PersistenceManager.ts similarity index 94% rename from vuu-ui/packages/vuu-layout/src/layout-persistence/LayoutPersistenceManager.ts rename to vuu-ui/packages/vuu-shell/src/persistence-management/PersistenceManager.ts index 3ac7c097d..83c1d5921 100644 --- a/vuu-ui/packages/vuu-layout/src/layout-persistence/LayoutPersistenceManager.ts +++ b/vuu-ui/packages/vuu-shell/src/persistence-management/PersistenceManager.ts @@ -1,7 +1,7 @@ import { ApplicationJSON, LayoutJSON } from "@finos/vuu-layout"; -import { LayoutMetadata, LayoutMetadataDto } from "@finos/vuu-shell"; +import { LayoutMetadata, LayoutMetadataDto } from "../layout-management"; -export interface LayoutPersistenceManager { +export interface PersistenceManager { /** * Saves a new layout and its corresponding metadata * diff --git a/vuu-ui/packages/vuu-layout/src/layout-persistence/RemoteLayoutPersistenceManager.ts b/vuu-ui/packages/vuu-shell/src/persistence-management/RemotePersistenceManager.ts similarity index 94% rename from vuu-ui/packages/vuu-layout/src/layout-persistence/RemoteLayoutPersistenceManager.ts rename to vuu-ui/packages/vuu-shell/src/persistence-management/RemotePersistenceManager.ts index 18b6da4ee..a80e6baf8 100644 --- a/vuu-ui/packages/vuu-layout/src/layout-persistence/RemoteLayoutPersistenceManager.ts +++ b/vuu-ui/packages/vuu-shell/src/persistence-management/RemotePersistenceManager.ts @@ -1,6 +1,9 @@ -import { LayoutMetadata, LayoutMetadataDto } from "@finos/vuu-shell"; -import { LayoutPersistenceManager } from "./LayoutPersistenceManager"; -import { ApplicationJSON, LayoutJSON } from "../layout-reducer"; +import { PersistenceManager } from "./PersistenceManager"; +import { + ApplicationJSON, + LayoutJSON, +} from "@finos/vuu-layout/src/layout-reducer"; +import { LayoutMetadata, LayoutMetadataDto } from "../layout-management"; const baseURL = process.env.LAYOUT_BASE_URL; const metadataSaveLocation = "layouts/metadata"; @@ -11,9 +14,7 @@ export type CreateLayoutResponseDto = { metadata: LayoutMetadata }; export type GetLayoutResponseDto = { definition: LayoutJSON }; export type GetApplicationResponseDto = { definition: ApplicationJSON }; -export class RemoteLayoutPersistenceManager - implements LayoutPersistenceManager -{ +export class RemotePersistenceManager implements PersistenceManager { createLayout( metadata: LayoutMetadataDto, layout: LayoutJSON diff --git a/vuu-ui/packages/vuu-layout/src/layout-persistence/defaultApplicationJson.ts b/vuu-ui/packages/vuu-shell/src/persistence-management/defaultApplicationJson.ts similarity index 94% rename from vuu-ui/packages/vuu-layout/src/layout-persistence/defaultApplicationJson.ts rename to vuu-ui/packages/vuu-shell/src/persistence-management/defaultApplicationJson.ts index a8e805109..ba3b475a3 100644 --- a/vuu-ui/packages/vuu-layout/src/layout-persistence/defaultApplicationJson.ts +++ b/vuu-ui/packages/vuu-shell/src/persistence-management/defaultApplicationJson.ts @@ -1,4 +1,4 @@ -import { ApplicationJSON, LayoutJSON } from "../layout-reducer"; +import { ApplicationJSON, LayoutJSON } from "@finos/vuu-layout"; export const warningLayout: LayoutJSON = { type: "View", diff --git a/vuu-ui/packages/vuu-shell/src/persistence-management/index.ts b/vuu-ui/packages/vuu-shell/src/persistence-management/index.ts new file mode 100644 index 000000000..53d202da6 --- /dev/null +++ b/vuu-ui/packages/vuu-shell/src/persistence-management/index.ts @@ -0,0 +1,5 @@ +export * from "./defaultApplicationJson"; +export * from "./PersistenceManager"; +export * from "./LocalPersistenceManager"; +export * from "./RemotePersistenceManager"; +export * from "./useLayoutContextMenuItems"; diff --git a/vuu-ui/packages/vuu-layout/src/layout-persistence/useLayoutContextMenuItems.tsx b/vuu-ui/packages/vuu-shell/src/persistence-management/useLayoutContextMenuItems.tsx similarity index 98% rename from vuu-ui/packages/vuu-layout/src/layout-persistence/useLayoutContextMenuItems.tsx rename to vuu-ui/packages/vuu-shell/src/persistence-management/useLayoutContextMenuItems.tsx index b2cc99407..ec3349e5e 100644 --- a/vuu-ui/packages/vuu-layout/src/layout-persistence/useLayoutContextMenuItems.tsx +++ b/vuu-ui/packages/vuu-shell/src/persistence-management/useLayoutContextMenuItems.tsx @@ -1,8 +1,3 @@ -import { - LayoutMetadataDto, - SaveLayoutPanel, - useLayoutManager, -} from "@finos/vuu-shell"; import { ContextMenuItemDescriptor, MenuActionHandler, @@ -10,6 +5,11 @@ import { } from "@finos/vuu-data-types"; import { useCallback, useMemo } from "react"; import { MenuActionClosePopup, SetDialog } from "@finos/vuu-popups"; +import { + LayoutMetadataDto, + SaveLayoutPanel, + useLayoutManager, +} from "../layout-management"; export const useLayoutContextMenuItems = (setDialogState: SetDialog) => { const { saveLayout } = useLayoutManager(); diff --git a/vuu-ui/packages/vuu-shell/src/session-editing-form/SessionEditingForm.tsx b/vuu-ui/packages/vuu-shell/src/session-editing-form/SessionEditingForm.tsx index 79dde1378..73638b30e 100644 --- a/vuu-ui/packages/vuu-shell/src/session-editing-form/SessionEditingForm.tsx +++ b/vuu-ui/packages/vuu-shell/src/session-editing-form/SessionEditingForm.tsx @@ -1,3 +1,19 @@ +import { VuuDataSource } from "@finos/vuu-data-remote"; +import { DataSource, TableSchema } from "@finos/vuu-data-types"; +import { + VuuColumnDataType, + VuuDataRow, + VuuRowDataItemType, +} from "@finos/vuu-protocol-types"; +import { + buildColumnMap, + hasAction, + isErrorResponse, + isValidNumber, + shallowEquals, +} from "@finos/vuu-utils"; +import { Button, useIdMemo } from "@salt-ds/core"; +import cx from "clsx"; import { ChangeEvent, FocusEvent, @@ -8,22 +24,6 @@ import { useRef, useState, } from "react"; -import cx from "classnames"; -import { - VuuColumnDataType, - VuuDataRow, - VuuRowDataItemType, -} from "@finos/vuu-protocol-types"; -import { useIdMemo } from "@salt-ds/core"; -import { Button } from "@salt-ds/core"; -import { - DataSource, - hasAction, - isErrorResponse, - RemoteDataSource, - TableSchema, -} from "@finos/vuu-data"; -import { buildColumnMap, isValidNumber, shallowEquals } from "@finos/vuu-utils"; import "./SessionEditingForm.css"; @@ -135,7 +135,7 @@ const getDataSource = ( if (dataSource) { return dataSource; } else if (schema) { - return new RemoteDataSource({ + return new VuuDataSource({ bufferSize: 0, table: schema.table, columns: schema.columns.map((col) => col.name), diff --git a/vuu-ui/packages/vuu-shell/src/shell-layouts/context-panel/ContextPanel.tsx b/vuu-ui/packages/vuu-shell/src/shell-layouts/context-panel/ContextPanel.tsx index c341013b9..89ca7cff7 100644 --- a/vuu-ui/packages/vuu-shell/src/shell-layouts/context-panel/ContextPanel.tsx +++ b/vuu-ui/packages/vuu-shell/src/shell-layouts/context-panel/ContextPanel.tsx @@ -1,5 +1,5 @@ import { Button } from "@salt-ds/core"; -import cx from "classnames"; +import cx from "clsx"; import { useCallback, useMemo } from "react"; import { layoutFromJson, diff --git a/vuu-ui/packages/vuu-shell/src/shell-layouts/side-panel/SidePanel.tsx b/vuu-ui/packages/vuu-shell/src/shell-layouts/side-panel/SidePanel.tsx index 4bd61099c..4ffa9cd1d 100644 --- a/vuu-ui/packages/vuu-shell/src/shell-layouts/side-panel/SidePanel.tsx +++ b/vuu-ui/packages/vuu-shell/src/shell-layouts/side-panel/SidePanel.tsx @@ -1,5 +1,5 @@ import { CSSProperties, HTMLAttributes, useMemo } from "react"; -import cx from "classnames"; +import cx from "clsx"; import "./SidePanel.css"; // import { useLayoutManager } from "../../layout-management"; diff --git a/vuu-ui/packages/vuu-shell/src/shell.tsx b/vuu-ui/packages/vuu-shell/src/shell.tsx index d9d298dd8..ab48f8069 100644 --- a/vuu-ui/packages/vuu-shell/src/shell.tsx +++ b/vuu-ui/packages/vuu-shell/src/shell.tsx @@ -1,17 +1,20 @@ -import { connectToServer } from "@finos/vuu-data"; +import { connectToServer } from "@finos/vuu-data-remote"; import { DraggableLayout, LayoutProvider, LayoutProviderProps, - loadingApplicationJson, - useLayoutContextMenuItems, + StackLayout, } from "@finos/vuu-layout"; import { LayoutChangeHandler } from "@finos/vuu-layout/src/layout-reducer"; -import { logger } from "@finos/vuu-utils"; -import cx from "classnames"; +import { + logger, + ThemeMode, + ThemeProvider, + useThemeAttributes, +} from "@finos/vuu-utils"; +import cx from "clsx"; import { HTMLAttributes, - ReactElement, ReactNode, useCallback, useEffect, @@ -21,11 +24,19 @@ import { AppHeader } from "./app-header"; import { useLayoutManager } from "./layout-management"; import { SidePanelProps, useShellLayout } from "./shell-layouts"; import { SaveLocation } from "./shellTypes"; -import { ThemeMode, ThemeProvider, useThemeAttributes } from "./theme-provider"; -import { ShellContextProvider } from "."; import { ContextMenuProvider, useDialog } from "@finos/vuu-popups"; import "./shell.css"; +import { + loadingApplicationJson, + useLayoutContextMenuItems, +} from "./persistence-management"; + +if (typeof StackLayout !== "function") { + console.warn( + "StackLayout module not loaded, will be unsbale to deserialize from layout JSON" + ); +} export type VuuUser = { username: string; diff --git a/vuu-ui/packages/vuu-shell/src/theme-provider/index.ts b/vuu-ui/packages/vuu-shell/src/theme-provider/index.ts deleted file mode 100644 index 12243cf10..000000000 --- a/vuu-ui/packages/vuu-shell/src/theme-provider/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./ThemeProvider"; \ No newline at end of file diff --git a/vuu-ui/packages/vuu-shell/src/theme-switch/ThemeSwitch.tsx b/vuu-ui/packages/vuu-shell/src/theme-switch/ThemeSwitch.tsx index 763936b99..0d4ea5fc3 100644 --- a/vuu-ui/packages/vuu-shell/src/theme-switch/ThemeSwitch.tsx +++ b/vuu-ui/packages/vuu-shell/src/theme-switch/ThemeSwitch.tsx @@ -1,7 +1,7 @@ -import cx from "classnames"; +import cx from "clsx"; import { ToggleButton, ToggleButtonGroup, useControlled } from "@salt-ds/core"; import { HTMLAttributes, SyntheticEvent, useCallback } from "react"; -import { ThemeMode } from "../theme-provider"; +import { ThemeMode } from "@finos/vuu-utils"; import "./ThemeSwitch.css"; diff --git a/vuu-ui/packages/vuu-shell/src/user-profile/UserPanel.css b/vuu-ui/packages/vuu-shell/src/user-profile/UserPanel.css deleted file mode 100644 index 15c36f732..000000000 --- a/vuu-ui/packages/vuu-shell/src/user-profile/UserPanel.css +++ /dev/null @@ -1,26 +0,0 @@ -.vuuUserPanel { - background-color: white; - display: flex; - flex-direction: column; - max-height: 400px; - padding: 12px; -} - -vuuUserPanel-history { - flex: 1 1 auto; -} - -.vuuUserPanel-buttonBar { - --saltButton-width: 100%; - align-items: flex-end; - border-top: 1px solid var(--surface3); - display: flex; - flex: 0 0 32px; - justify-content: flex-start; -} - -.btn-logout { - --hwButton-icon-left: 12px; - --hwButton-padding: 0 6px 0 24px; - padding-left: 24px; -} diff --git a/vuu-ui/packages/vuu-shell/src/user-profile/UserPanel.tsx b/vuu-ui/packages/vuu-shell/src/user-profile/UserPanel.tsx deleted file mode 100644 index 4b2d8fa22..000000000 --- a/vuu-ui/packages/vuu-shell/src/user-profile/UserPanel.tsx +++ /dev/null @@ -1,103 +0,0 @@ -import { formatDate } from "@finos/vuu-utils"; -import { List, ListItem, ListItemProps } from "@salt-ds/lab"; -import { Button } from "@salt-ds/core"; -import { ExportIcon } from "@salt-ds/icons"; -import { - ForwardedRef, - forwardRef, - HTMLAttributes, - useCallback, - useEffect, - useState, -} from "react"; -import { getLayoutHistory, LayoutHistoryItem } from "../get-layout-history"; -import { logout } from "../login"; -import { VuuUser } from "../shell"; - -import "./UserPanel.css"; - -const byLastUpdate = ( - { lastUpdate: l1 }: LayoutHistoryItem, - { lastUpdate: l2 }: LayoutHistoryItem -) => { - return l2 === l1 ? 0 : l2 < l1 ? -1 : 1; -}; - -type HistoryEntry = { - id: string; - label: string; - lastUpdate: number; -}; - -const HistoryListItem = (props: ListItemProps) => { - return ; -}; - -export interface UserPanelProps extends HTMLAttributes { - loginUrl?: string; - onNavigate: (id: string) => void; - user: VuuUser; - layoutId: string; -} - -export const UserPanel = forwardRef(function UserPanel( - { loginUrl, onNavigate, user, layoutId = "latest" }: UserPanelProps, - forwardedRef: ForwardedRef -) { - const [history, setHistory] = useState([]); - - useEffect(() => { - async function getHistory() { - const history = await getLayoutHistory(user); - const sortedHistory = history - .filter((item) => item.id !== "latest") - .sort(byLastUpdate) - .map(({ id, lastUpdate }) => ({ - lastUpdate, - id, - label: `Saved at ${formatDate("hh:mm:ss")(new Date(lastUpdate))}`, - })); - console.log({ sortedHistory }); - setHistory(sortedHistory); - } - - getHistory(); - }, [user]); - - const handleHisorySelected = useCallback( - (evt, selected) => { - if (selected) { - onNavigate(selected.id); - } - }, - [onNavigate] - ); - - const handleLogout = useCallback(() => { - logout(loginUrl); - }, [loginUrl]); - - const selected = - history.length === 0 - ? null - : layoutId === "latest" - ? history[0] - : history.find((i) => i.id === layoutId); - - return ( -
- - ListItem={HistoryListItem} - className="vuuUserPanel-history" - onSelect={handleHisorySelected} - selected={selected} - source={history} - /> -
- -
-
- ); -}); diff --git a/vuu-ui/packages/vuu-shell/src/user-profile/UserProfile.css b/vuu-ui/packages/vuu-shell/src/user-profile/UserProfile.css deleted file mode 100644 index 1d2e0eb9a..000000000 --- a/vuu-ui/packages/vuu-shell/src/user-profile/UserProfile.css +++ /dev/null @@ -1,3 +0,0 @@ -.vuuUserProfile { - --svg-icon: var(--svg-user); -} diff --git a/vuu-ui/packages/vuu-shell/src/user-profile/UserProfile.tsx b/vuu-ui/packages/vuu-shell/src/user-profile/UserProfile.tsx deleted file mode 100644 index 32775e278..000000000 --- a/vuu-ui/packages/vuu-shell/src/user-profile/UserProfile.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import { Button } from "@salt-ds/core"; -import { DropdownBase } from "@salt-ds/lab"; -import { UserSolidIcon } from "@salt-ds/icons"; -import { UserPanel } from "./UserPanel"; - -import "./UserProfile.css"; -import { VuuUser } from "../shell"; - -export interface UserProfileProps { - layoutId: string; - loginUrl?: string; - onNavigate: (id: string) => void; - user: VuuUser; -} - -export const UserProfile = ({ - layoutId, - loginUrl, - onNavigate, - user, -}: UserProfileProps) => { - const handleNavigate = (id: string) => { - onNavigate(id); - }; - - return ( - - - - - ); -}; diff --git a/vuu-ui/packages/vuu-shell/src/user-profile/index.ts b/vuu-ui/packages/vuu-shell/src/user-profile/index.ts deleted file mode 100644 index 884472841..000000000 --- a/vuu-ui/packages/vuu-shell/src/user-profile/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './UserProfile'; diff --git a/vuu-ui/packages/vuu-layout/test/layout-persistence/LocalLayoutPersistenceManager.test.ts b/vuu-ui/packages/vuu-shell/test/layout-persistence/LocalLayoutPersistenceManager.test.ts similarity index 98% rename from vuu-ui/packages/vuu-layout/test/layout-persistence/LocalLayoutPersistenceManager.test.ts rename to vuu-ui/packages/vuu-shell/test/layout-persistence/LocalLayoutPersistenceManager.test.ts index 61fc9d912..ecdb41149 100644 --- a/vuu-ui/packages/vuu-layout/test/layout-persistence/LocalLayoutPersistenceManager.test.ts +++ b/vuu-ui/packages/vuu-shell/test/layout-persistence/LocalLayoutPersistenceManager.test.ts @@ -1,14 +1,14 @@ -import "../global-mocks"; +import "@finos/vuu-layout/test/global-mocks"; import { Layout, LayoutMetadata, LayoutMetadataDto } from "@finos/vuu-shell"; import { afterEach, describe, expect, it, vi } from "vitest"; -import { LocalLayoutPersistenceManager } from "../../src/layout-persistence"; -import { LayoutJSON } from "../../src/layout-reducer"; +import { LayoutJSON } from "@finos/vuu-layout"; import { getLocalEntity, saveLocalEntity, } from "../../../vuu-filters/src/local-config"; import { formatDate } from "@finos/vuu-utils"; import { expectPromiseRejectsWithError } from "@finos/vuu-utils/test/utils"; +import { LocalPersistenceManager } from "../../src/persistence-management/LocalPersistenceManager"; vi.mock("@finos/vuu-filters", async () => { return { @@ -27,7 +27,7 @@ vi.mock("@finos/vuu-filters", async () => { }; }); -const persistenceManager = new LocalLayoutPersistenceManager(); +const persistenceManager = new LocalPersistenceManager(); const existingId = "existing_id"; diff --git a/vuu-ui/packages/vuu-layout/test/layout-persistence/RemoteLayoutPersistenceManager.test.ts b/vuu-ui/packages/vuu-shell/test/layout-persistence/RemoteLayoutPersistenceManager.test.ts similarity index 97% rename from vuu-ui/packages/vuu-layout/test/layout-persistence/RemoteLayoutPersistenceManager.test.ts rename to vuu-ui/packages/vuu-shell/test/layout-persistence/RemoteLayoutPersistenceManager.test.ts index 1691aee09..2068f25ef 100644 --- a/vuu-ui/packages/vuu-layout/test/layout-persistence/RemoteLayoutPersistenceManager.test.ts +++ b/vuu-ui/packages/vuu-shell/test/layout-persistence/RemoteLayoutPersistenceManager.test.ts @@ -2,14 +2,14 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; import { GetLayoutResponseDto, CreateLayoutResponseDto, - RemoteLayoutPersistenceManager, -} from "../../src/layout-persistence/RemoteLayoutPersistenceManager"; + RemotePersistenceManager, +} from "../../src/persistence-management/RemotePersistenceManager"; import { LayoutMetadata, LayoutMetadataDto } from "@finos/vuu-shell"; -import { LayoutJSON } from "../../src/layout-reducer"; +import { LayoutJSON } from "@finos/vuu-layout"; import { v4 as uuidv4 } from "uuid"; import { expectPromiseRejectsWithError } from "@finos/vuu-utils/test/utils"; -const persistence = new RemoteLayoutPersistenceManager(); +const persistence = new RemotePersistenceManager(); const mockFetch = vi.fn(); global.fetch = mockFetch; diff --git a/vuu-ui/packages/vuu-utils/test/screenshot-utils.test.ts b/vuu-ui/packages/vuu-shell/test/layout-persistence/screenshot-utils.test.ts similarity index 97% rename from vuu-ui/packages/vuu-utils/test/screenshot-utils.test.ts rename to vuu-ui/packages/vuu-shell/test/layout-persistence/screenshot-utils.test.ts index c45b65a12..465c62825 100644 --- a/vuu-ui/packages/vuu-utils/test/screenshot-utils.test.ts +++ b/vuu-ui/packages/vuu-shell/test/layout-persistence/screenshot-utils.test.ts @@ -1,6 +1,6 @@ -import { takeScreenshot } from "../src/screenshot-utils"; +import { takeScreenshot } from "../../src/layout-management/screenshot-utils"; import { describe, expect, it, vi } from "vitest"; -import { expectPromiseRejectsWithError } from "./utils"; +import { expectPromiseRejectsWithError } from "@finos/vuu-utils/test/utils"; import htmlToImage from "html-to-image"; const node = document.createElement("div"); @@ -17,10 +17,8 @@ describe("takeScreenshot", () => { }); it("rejects with error message when toPng() promise is rejected", async () => { - htmlToImage.toPng = vi.fn().mockRejectedValue({}); - expectPromiseRejectsWithError( () => takeScreenshot(node), "Error taking screenshot" diff --git a/vuu-ui/packages/vuu-shell/test/layout-persistence/utils.ts b/vuu-ui/packages/vuu-shell/test/layout-persistence/utils.ts new file mode 100644 index 000000000..1dff87194 --- /dev/null +++ b/vuu-ui/packages/vuu-shell/test/layout-persistence/utils.ts @@ -0,0 +1,8 @@ +import { expect } from "vitest"; + +export const expectPromiseRejectsWithError = ( + f: () => Promise, + message: string +) => { + expect(f).rejects.toStrictEqual(new Error(message)); +}; diff --git a/vuu-ui/packages/vuu-table-extras/package.json b/vuu-ui/packages/vuu-table-extras/package.json index 663fc2f0d..2e84f15f0 100644 --- a/vuu-ui/packages/vuu-table-extras/package.json +++ b/vuu-ui/packages/vuu-table-extras/package.json @@ -15,19 +15,18 @@ }, "dependencies": { "@finos/vuu-codemirror": "0.0.26", - "@finos/vuu-data": "0.0.26", "@finos/vuu-data-react": "0.0.26", + "@finos/vuu-data-types": "0.0.26", "@finos/vuu-table-types": "0.0.26", "@finos/vuu-layout": "0.0.26", "@finos/vuu-popups": "0.0.26", "@finos/vuu-utils": "0.0.26", "@finos/vuu-ui-controls": "0.0.26", "@lezer/lr": "1.3.4", - "@salt-ds/core": "1.8.0", - "@salt-ds/lab": "1.0.0-alpha.15" + "@salt-ds/core": "1.13.2" }, "peerDependencies": { - "classnames": "^2.2.6", + "clsx": "^2.0.0", "react": ">=17.0.2", "react-dom": ">=17.0.2" }, diff --git a/vuu-ui/packages/vuu-table-extras/src/cell-renderers-next/background-cell/BackgroundCell.tsx b/vuu-ui/packages/vuu-table-extras/src/cell-renderers-next/background-cell/BackgroundCell.tsx index 0354e64e4..17eb34e45 100644 --- a/vuu-ui/packages/vuu-table-extras/src/cell-renderers-next/background-cell/BackgroundCell.tsx +++ b/vuu-ui/packages/vuu-table-extras/src/cell-renderers-next/background-cell/BackgroundCell.tsx @@ -8,7 +8,7 @@ import { UP1, UP2, } from "@finos/vuu-utils"; -import cx from "classnames"; +import cx from "clsx"; import { useDirection } from "./useDirection"; import "./BackgroundCell.css"; diff --git a/vuu-ui/packages/vuu-table/src/cell-renderers/dropdown-cell/DropdownCell.css b/vuu-ui/packages/vuu-table-extras/src/cell-renderers/dropdown-cell/DropdownCell.css similarity index 100% rename from vuu-ui/packages/vuu-table/src/cell-renderers/dropdown-cell/DropdownCell.css rename to vuu-ui/packages/vuu-table-extras/src/cell-renderers/dropdown-cell/DropdownCell.css diff --git a/vuu-ui/packages/vuu-table/src/cell-renderers/dropdown-cell/DropdownCell.tsx b/vuu-ui/packages/vuu-table-extras/src/cell-renderers/dropdown-cell/DropdownCell.tsx similarity index 94% rename from vuu-ui/packages/vuu-table/src/cell-renderers/dropdown-cell/DropdownCell.tsx rename to vuu-ui/packages/vuu-table-extras/src/cell-renderers/dropdown-cell/DropdownCell.tsx index 03eac99d7..246353a6e 100644 --- a/vuu-ui/packages/vuu-table/src/cell-renderers/dropdown-cell/DropdownCell.tsx +++ b/vuu-ui/packages/vuu-table-extras/src/cell-renderers/dropdown-cell/DropdownCell.tsx @@ -9,7 +9,7 @@ import { import { dispatchCustomEvent, registerComponent } from "@finos/vuu-utils"; import { VuuColumnDataType } from "@finos/vuu-protocol-types"; import { memo, useCallback, useState } from "react"; -import { dataAndColumnUnchanged } from "../cell-utils"; +import { dataAndColumnUnchanged } from "@finos/vuu-table/src/cell-renderers/cell-utils"; import "./DropdownCell.css"; diff --git a/vuu-ui/packages/vuu-table/src/cell-renderers/dropdown-cell/index.ts b/vuu-ui/packages/vuu-table-extras/src/cell-renderers/dropdown-cell/index.ts similarity index 100% rename from vuu-ui/packages/vuu-table/src/cell-renderers/dropdown-cell/index.ts rename to vuu-ui/packages/vuu-table-extras/src/cell-renderers/dropdown-cell/index.ts diff --git a/vuu-ui/packages/vuu-table-extras/src/cell-renderers/index.ts b/vuu-ui/packages/vuu-table-extras/src/cell-renderers/index.ts index f3fd0c349..c2ab78cbd 100644 --- a/vuu-ui/packages/vuu-table-extras/src/cell-renderers/index.ts +++ b/vuu-ui/packages/vuu-table-extras/src/cell-renderers/index.ts @@ -1 +1,3 @@ +export * from "./dropdown-cell"; +export * from "./lookup-cell"; export * from "./progress-cell"; diff --git a/vuu-ui/packages/vuu-table/src/cell-renderers/lookup-cell/LookupCell.tsx b/vuu-ui/packages/vuu-table-extras/src/cell-renderers/lookup-cell/LookupCell.tsx similarity index 87% rename from vuu-ui/packages/vuu-table/src/cell-renderers/lookup-cell/LookupCell.tsx rename to vuu-ui/packages/vuu-table-extras/src/cell-renderers/lookup-cell/LookupCell.tsx index 2b70be31d..254d2b4c9 100644 --- a/vuu-ui/packages/vuu-table/src/cell-renderers/lookup-cell/LookupCell.tsx +++ b/vuu-ui/packages/vuu-table-extras/src/cell-renderers/lookup-cell/LookupCell.tsx @@ -2,7 +2,7 @@ import { useLookupValues } from "@finos/vuu-data-react"; import { TableCellRendererProps } from "@finos/vuu-table-types"; import { registerComponent } from "@finos/vuu-utils"; import { memo } from "react"; -import { dataAndColumnUnchanged } from "../cell-utils"; +import { dataAndColumnUnchanged } from "@finos/vuu-table/src/cell-renderers/cell-utils"; // const classBase = "vuuTableLookupCell"; diff --git a/vuu-ui/packages/vuu-table/src/cell-renderers/lookup-cell/index.ts b/vuu-ui/packages/vuu-table-extras/src/cell-renderers/lookup-cell/index.ts similarity index 100% rename from vuu-ui/packages/vuu-table/src/cell-renderers/lookup-cell/index.ts rename to vuu-ui/packages/vuu-table-extras/src/cell-renderers/lookup-cell/index.ts diff --git a/vuu-ui/packages/vuu-table-extras/src/cell-renderers/progress-cell/ProgressCell.tsx b/vuu-ui/packages/vuu-table-extras/src/cell-renderers/progress-cell/ProgressCell.tsx index 3667f80d7..ec2958b50 100644 --- a/vuu-ui/packages/vuu-table-extras/src/cell-renderers/progress-cell/ProgressCell.tsx +++ b/vuu-ui/packages/vuu-table-extras/src/cell-renderers/progress-cell/ProgressCell.tsx @@ -5,7 +5,7 @@ import { isValidNumber, registerComponent, } from "@finos/vuu-utils"; -import cx from "classnames"; +import cx from "clsx"; import { CSSProperties } from "react"; import "./ProgressCell.css"; diff --git a/vuu-ui/packages/vuu-table-extras/src/column-expression-input/useColumnExpressionSuggestionProvider.ts b/vuu-ui/packages/vuu-table-extras/src/column-expression-input/useColumnExpressionSuggestionProvider.ts index 051da9733..9a7bd6ea0 100644 --- a/vuu-ui/packages/vuu-table-extras/src/column-expression-input/useColumnExpressionSuggestionProvider.ts +++ b/vuu-ui/packages/vuu-table-extras/src/column-expression-input/useColumnExpressionSuggestionProvider.ts @@ -13,11 +13,6 @@ import { } from "@finos/vuu-data-react"; import { ColumnDescriptor } from "@finos/vuu-table-types"; import { VuuTable } from "@finos/vuu-protocol-types"; -import { - ColumnExpressionOperator, - ColumnExpressionSuggestionType, - IExpressionSuggestionProvider, -} from "@finos/vuu-table-extras"; import { isNumericColumn, isTextColumn } from "@finos/vuu-utils"; import { useCallback, useRef } from "react"; import { @@ -25,6 +20,11 @@ import { columnFunctionDescriptors, } from "./column-function-descriptors"; import { functionDocInfo } from "./functionDocInfo"; +import { + ColumnExpressionOperator, + ColumnExpressionSuggestionType, + IExpressionSuggestionProvider, +} from "./useColumnExpressionEditor"; const NO_OPERATORS = [] as Completion[]; diff --git a/vuu-ui/packages/vuu-table-extras/src/column-expression-panel/ColumnExpressionPanel.tsx b/vuu-ui/packages/vuu-table-extras/src/column-expression-panel/ColumnExpressionPanel.tsx index 4cb2ec51f..d0be5e453 100644 --- a/vuu-ui/packages/vuu-table-extras/src/column-expression-panel/ColumnExpressionPanel.tsx +++ b/vuu-ui/packages/vuu-table-extras/src/column-expression-panel/ColumnExpressionPanel.tsx @@ -1,4 +1,4 @@ -import { ColumnDescriptor } from "@finos/vuu-table-types"; +import { ColumnDescriptor, ColumnSettingsProps } from "@finos/vuu-table-types"; import { Dropdown } from "@finos/vuu-ui-controls"; import { getCalculatedColumnExpression, @@ -12,7 +12,6 @@ import { ColumnExpressionSubmitHandler, useColumnExpressionSuggestionProvider, } from "../column-expression-input"; -import { ColumnSettingsProps } from "../column-settings"; import { useColumnExpression } from "./useColumnExpression"; const classBase = "vuuColumnExpressionPanel"; diff --git a/vuu-ui/packages/vuu-table-extras/src/column-formatting-settings/ColumnFormattingPanel.tsx b/vuu-ui/packages/vuu-table-extras/src/column-formatting-settings/ColumnFormattingPanel.tsx index 66487bb75..9a2964fd3 100644 --- a/vuu-ui/packages/vuu-table-extras/src/column-formatting-settings/ColumnFormattingPanel.tsx +++ b/vuu-ui/packages/vuu-table-extras/src/column-formatting-settings/ColumnFormattingPanel.tsx @@ -14,7 +14,7 @@ import { isTypeDescriptor, } from "@finos/vuu-utils"; import { FormField, FormFieldLabel } from "@salt-ds/core"; -import cx from "classnames"; +import cx from "clsx"; import { HTMLAttributes, useCallback, useMemo } from "react"; import { NumericFormattingSettings } from "./NumericFormattingSettings"; diff --git a/vuu-ui/packages/vuu-table-extras/src/column-formatting-settings/NumericFormattingSettings.tsx b/vuu-ui/packages/vuu-table-extras/src/column-formatting-settings/NumericFormattingSettings.tsx index 83ba314e6..8401e2372 100644 --- a/vuu-ui/packages/vuu-table-extras/src/column-formatting-settings/NumericFormattingSettings.tsx +++ b/vuu-ui/packages/vuu-table-extras/src/column-formatting-settings/NumericFormattingSettings.tsx @@ -1,5 +1,4 @@ -import { FormField, FormFieldLabel, Input } from "@salt-ds/core"; -import { Switch } from "@salt-ds/lab"; +import { FormField, FormFieldLabel, Input, Switch } from "@salt-ds/core"; import { ColumnDescriptor, ColumnTypeFormatting } from "@finos/vuu-table-types"; import { getTypeFormattingFromColumn } from "@finos/vuu-utils"; import { diff --git a/vuu-ui/packages/vuu-table-extras/src/column-list/ColumnList.tsx b/vuu-ui/packages/vuu-table-extras/src/column-list/ColumnList.tsx index 572ef49ff..93f7be278 100644 --- a/vuu-ui/packages/vuu-table-extras/src/column-list/ColumnList.tsx +++ b/vuu-ui/packages/vuu-table-extras/src/column-list/ColumnList.tsx @@ -1,13 +1,12 @@ +import { ColumnDescriptor } from "@finos/vuu-table-types"; import { List, ListItem, ListItemProps, ListProps, } from "@finos/vuu-ui-controls"; -import { Checkbox } from "@salt-ds/core"; -import { Switch } from "@salt-ds/lab"; -import cx from "classnames"; -import { ColumnDescriptor } from "@finos/vuu-table-types"; +import { Checkbox, Switch } from "@salt-ds/core"; +import cx from "clsx"; import { HTMLAttributes, MouseEventHandler, @@ -15,9 +14,9 @@ import { useCallback, } from "react"; import { ColumnItem } from "../table-settings"; +import { getColumnLabel } from "@finos/vuu-utils"; import "./ColumnList.css"; -import { getColumnLabel } from "@finos/vuu-utils"; const classBase = "vuuColumnList"; const classBaseListItem = "vuuColumnListItem"; diff --git a/vuu-ui/packages/vuu-table-extras/src/column-settings/ColumnNameLabel.tsx b/vuu-ui/packages/vuu-table-extras/src/column-settings/ColumnNameLabel.tsx index 088eab448..d37f9cee7 100644 --- a/vuu-ui/packages/vuu-table-extras/src/column-settings/ColumnNameLabel.tsx +++ b/vuu-ui/packages/vuu-table-extras/src/column-settings/ColumnNameLabel.tsx @@ -1,5 +1,5 @@ import { ColumnDescriptor } from "@finos/vuu-table-types"; -import cx from "classnames"; +import cx from "clsx"; import { getCalculatedColumnDetails, diff --git a/vuu-ui/packages/vuu-table-extras/src/column-settings/ColumnSettingsPanel.tsx b/vuu-ui/packages/vuu-table-extras/src/column-settings/ColumnSettingsPanel.tsx index c0cb8e6f3..22c852728 100644 --- a/vuu-ui/packages/vuu-table-extras/src/column-settings/ColumnSettingsPanel.tsx +++ b/vuu-ui/packages/vuu-table-extras/src/column-settings/ColumnSettingsPanel.tsx @@ -1,5 +1,4 @@ -import { ColumnDescriptor, TableConfig } from "@finos/vuu-table-types"; -import { VuuTable } from "@finos/vuu-protocol-types"; +import { ColumnDescriptor, ColumnSettingsProps } from "@finos/vuu-table-types"; import { VuuInput } from "@finos/vuu-ui-controls"; import { getCalculatedColumnName, @@ -13,8 +12,7 @@ import { ToggleButton, ToggleButtonGroup, } from "@salt-ds/core"; -import cx from "classnames"; -import { HTMLAttributes } from "react"; +import cx from "clsx"; import { ColumnExpressionPanel } from "../column-expression-panel"; import { ColumnFormattingPanel } from "../column-formatting-settings"; import { ColumnNameLabel } from "./ColumnNameLabel"; @@ -33,15 +31,6 @@ const getColumnLabel = (column: ColumnDescriptor) => { } }; -export interface ColumnSettingsProps extends HTMLAttributes { - column: ColumnDescriptor; - onConfigChange: (config: TableConfig) => void; - onCancelCreateColumn: () => void; - onCreateCalculatedColumn: (column: ColumnDescriptor) => void; - tableConfig: TableConfig; - vuuTable: VuuTable; -} - export const ColumnSettingsPanel = ({ column: columnProp, onCancelCreateColumn, diff --git a/vuu-ui/packages/vuu-table-extras/src/column-settings/useColumnSettings.ts b/vuu-ui/packages/vuu-table-extras/src/column-settings/useColumnSettings.ts index 0ac991b6c..e07acb670 100644 --- a/vuu-ui/packages/vuu-table-extras/src/column-settings/useColumnSettings.ts +++ b/vuu-ui/packages/vuu-table-extras/src/column-settings/useColumnSettings.ts @@ -2,6 +2,7 @@ import { ColumnDescriptor, TableConfig, ColumnTypeFormatting, + ColumnSettingsProps, } from "@finos/vuu-table-types"; import { @@ -22,7 +23,6 @@ import { useRef, useState, } from "react"; -import { ColumnSettingsProps } from "./ColumnSettingsPanel"; const integerCellRenderers: CellRendererDescriptor[] = [ { diff --git a/vuu-ui/packages/vuu-table-extras/src/datasource-stats/DatasourceStats.tsx b/vuu-ui/packages/vuu-table-extras/src/datasource-stats/DatasourceStats.tsx index 655db1446..8580ba340 100644 --- a/vuu-ui/packages/vuu-table-extras/src/datasource-stats/DatasourceStats.tsx +++ b/vuu-ui/packages/vuu-table-extras/src/datasource-stats/DatasourceStats.tsx @@ -1,9 +1,9 @@ -import { DataSource } from "@finos/vuu-data"; +import { DataSource } from "@finos/vuu-data-types"; +import { VuuRange } from "@finos/vuu-protocol-types"; +import cx from "clsx"; import { HTMLAttributes, useEffect, useState } from "react"; -import cx from "classnames"; import "./DatasourceStats.css"; -import { VuuRange } from "@finos/vuu-protocol-types"; interface DataSourceStatsProps extends HTMLAttributes { dataSource: DataSource; diff --git a/vuu-ui/packages/vuu-table-extras/src/index.ts b/vuu-ui/packages/vuu-table-extras/src/index.ts index a1fcb8c9f..852badc1f 100644 --- a/vuu-ui/packages/vuu-table-extras/src/index.ts +++ b/vuu-ui/packages/vuu-table-extras/src/index.ts @@ -8,4 +8,3 @@ export * from "./column-expression-panel"; export * from "./column-formatting-settings"; export * from "./datasource-stats"; export * from "./table-settings"; -export * from "./useTableAndColumnSettings"; diff --git a/vuu-ui/packages/vuu-table-extras/src/table-settings/TableSettingsPanel.tsx b/vuu-ui/packages/vuu-table-extras/src/table-settings/TableSettingsPanel.tsx index 2662cf925..7da4e5782 100644 --- a/vuu-ui/packages/vuu-table-extras/src/table-settings/TableSettingsPanel.tsx +++ b/vuu-ui/packages/vuu-table-extras/src/table-settings/TableSettingsPanel.tsx @@ -6,9 +6,7 @@ import { ToggleButton, ToggleButtonGroup, } from "@salt-ds/core"; -import { DataSourceConfig, SchemaColumn } from "@finos/vuu-data"; -import { TableConfig } from "@finos/vuu-table-types"; -import { HTMLAttributes } from "react"; +import { TableSettingsProps } from "@finos/vuu-table-types"; import { ColumnList } from "../column-list"; import { useTableSettings } from "./useTableSettings"; @@ -16,15 +14,6 @@ import "./TableSettingsPanel.css"; const classBase = "vuuTableSettingsPanel"; -export interface TableSettingsProps extends HTMLAttributes { - availableColumns: SchemaColumn[]; - onAddCalculatedColumn: () => void; - onConfigChange: (config: TableConfig) => void; - onDataSourceConfigChange: (dataSOurceConfig: DataSourceConfig) => void; - onNavigateToColumn?: (columnName: string) => void; - tableConfig: TableConfig; -} - /** The TableSettingsPanel assumes 'ownership' of the tableSettings. It updates the settings in state locally and notifies caller of @@ -37,7 +26,6 @@ export const TableSettingsPanel = ({ onDataSourceConfigChange, onNavigateToColumn, tableConfig: tableConfigProp, - ...htmlAttributes }: TableSettingsProps) => { const { columnItems, @@ -55,7 +43,7 @@ export const TableSettingsPanel = ({ }); return ( -
+
Column Labels void; - export type TableHeading = { label: string; width: number }; export type TableHeadings = TableHeading[][]; @@ -275,3 +271,48 @@ export type GridAction = | ScrollAction | GridActionResizeCol | GridActionSelection; + +/** + * Describes the props for a Column Configuration Editor, for which + * an implementation is provided in vuu-table-extras + */ +export interface ColumnSettingsProps { + column: ColumnDescriptor; + onConfigChange: (config: TableConfig) => void; + onCancelCreateColumn: () => void; + onCreateCalculatedColumn: (column: ColumnDescriptor) => void; + tableConfig: TableConfig; + vuuTable: VuuTable; +} + +/** + * Describes the props for a Table Configuration Editor, for which + * an implementation is provided in vuu-table-extras + */ +export interface TableSettingsProps { + availableColumns: SchemaColumn[]; + onAddCalculatedColumn: () => void; + onConfigChange: (config: TableConfig) => void; + onDataSourceConfigChange: (dataSOurceConfig: DataSourceConfig) => void; + onNavigateToColumn?: (columnName: string) => void; + tableConfig: TableConfig; +} + +export type DefaultColumnConfiguration = ( + tableName: T, + columnName: string +) => Partial | undefined; + +export type ResizePhase = "begin" | "resize" | "end"; + +export type TableColumnResizeHandler = ( + phase: ResizePhase, + columnName: string, + width?: number +) => void; + +export interface HeaderCellProps extends HTMLAttributes { + classBase?: string; + column: RuntimeColumnDescriptor; + onResize?: TableColumnResizeHandler; +} diff --git a/vuu-ui/packages/vuu-table/package.json b/vuu-ui/packages/vuu-table/package.json index 860db5516..f46fa8447 100644 --- a/vuu-ui/packages/vuu-table/package.json +++ b/vuu-ui/packages/vuu-table/package.json @@ -8,21 +8,20 @@ "build": "node ../../scripts/run-build.mjs", "type-defs": "node ../../scripts/build-type-defs.mjs" }, - "dependencies": { - "@salt-ds/core": "1.8.0", - "@salt-ds/icons": "1.5.1", - "@salt-ds/lab": "1.0.0-alpha.15", - "@finos/vuu-data": "0.0.26", - "@finos/vuu-data-react": "0.0.26", + "devDependencies": { "@finos/vuu-data-types": "0.0.26", + "@finos/vuu-table-types": "0.0.26", + "@finos/vuu-protocol-types": "0.0.26" + }, + "dependencies": { + "@salt-ds/core": "1.13.2", "@finos/vuu-layout": "0.0.26", "@finos/vuu-popups": "0.0.26", - "@finos/vuu-table-extras": "0.0.26", "@finos/vuu-ui-controls": "0.0.26", "@finos/vuu-utils": "0.0.26" }, "peerDependencies": { - "classnames": "^2.2.6", + "clsx": "^2.0.0", "react": ">=17.0.2", "react-dom": ">=17.0.2" } diff --git a/vuu-ui/packages/vuu-table/src/Row.tsx b/vuu-ui/packages/vuu-table/src/Row.tsx index 29a4f45ec..1309e484d 100644 --- a/vuu-ui/packages/vuu-table/src/Row.tsx +++ b/vuu-ui/packages/vuu-table/src/Row.tsx @@ -13,7 +13,7 @@ import { isNotHidden, RowSelected, } from "@finos/vuu-utils"; -import cx from "classnames"; +import cx from "clsx"; import { CSSProperties, memo, MouseEvent, useCallback } from "react"; import { TableCell, TableGroupCell } from "./table-cell"; @@ -92,7 +92,7 @@ export const Row = memo( return (
{showColumnHeaders ? ( @@ -304,6 +308,15 @@ export const Table = forwardRef(function TableNext( const [size, setSize] = useState(); + if (config === undefined) { + throw Error( + "vuu Table requires config prop. Minimum config is list of Column Descriptors" + ); + } + if (dataSource === undefined) { + throw Error("vuu Table requires dataSource prop"); + } + return ( void; export type ResizeHandler = (evt: MouseEvent, moveBy: number) => void; export interface CellResizeHookProps { diff --git a/vuu-ui/packages/vuu-table/src/context-menu/buildContextMenuDescriptors.ts b/vuu-ui/packages/vuu-table/src/context-menu/buildContextMenuDescriptors.ts index 72ffffcdf..38d9744dd 100644 --- a/vuu-ui/packages/vuu-table/src/context-menu/buildContextMenuDescriptors.ts +++ b/vuu-ui/packages/vuu-table/src/context-menu/buildContextMenuDescriptors.ts @@ -1,5 +1,8 @@ -import { DataSource } from "@finos/vuu-data"; -import { ContextMenuItemDescriptor, MenuBuilder } from "@finos/vuu-data-types"; +import { + ContextMenuItemDescriptor, + DataSource, + MenuBuilder, +} from "@finos/vuu-data-types"; import { RuntimeColumnDescriptor, PinLocation } from "@finos/vuu-table-types"; import { isNumericColumn } from "@finos/vuu-utils"; diff --git a/vuu-ui/packages/vuu-table/src/context-menu/useHandleTableContextMenu.ts b/vuu-ui/packages/vuu-table/src/context-menu/useHandleTableContextMenu.ts index 4f7ee9364..a250b68cc 100644 --- a/vuu-ui/packages/vuu-table/src/context-menu/useHandleTableContextMenu.ts +++ b/vuu-ui/packages/vuu-table/src/context-menu/useHandleTableContextMenu.ts @@ -1,10 +1,13 @@ /* eslint-disable no-sequences */ -import { DataSource } from "@finos/vuu-data"; import { RuntimeColumnDescriptor } from "@finos/vuu-table-types"; import { Filter } from "@finos/vuu-filter-types"; import { removeColumnFromFilter } from "@finos/vuu-utils"; import { VuuFilter } from "@finos/vuu-protocol-types"; -import { DataSourceFilter, MenuActionHandler } from "@finos/vuu-data-types"; +import { + DataSource, + DataSourceFilter, + MenuActionHandler, +} from "@finos/vuu-data-types"; import { PersistentColumnAction } from "../useTableModel"; import { addGroupColumn, diff --git a/vuu-ui/packages/vuu-table/src/header-cell/GroupHeaderCellNext.tsx b/vuu-ui/packages/vuu-table/src/header-cell/GroupHeaderCellNext.tsx index 333bbaaf0..b28b4e1de 100644 --- a/vuu-ui/packages/vuu-table/src/header-cell/GroupHeaderCellNext.tsx +++ b/vuu-ui/packages/vuu-table/src/header-cell/GroupHeaderCellNext.tsx @@ -1,15 +1,16 @@ +import { OverflowContainer } from "@finos/vuu-layout"; import { ColumnDescriptor, GroupColumnDescriptor, + HeaderCellProps, RuntimeColumnDescriptor, } from "@finos/vuu-table-types"; -import cx from "classnames"; +import { useLayoutEffectSkipFirst } from "@finos/vuu-utils"; +import cx from "clsx"; import { useCallback, useRef, useState } from "react"; +import { ColumnHeaderPill, GroupColumnPill } from "../column-header-pill"; import { ColumnResizer, useTableColumnResize } from "../column-resizing"; -import { HeaderCellProps } from "./HeaderCell"; import { useCell } from "../useCell"; -import { ColumnHeaderPill, GroupColumnPill } from "../column-header-pill"; -import { OverflowContainer, useLayoutEffectSkipFirst } from "@finos/vuu-layout"; import "./GroupHeaderCell.css"; diff --git a/vuu-ui/packages/vuu-table/src/header-cell/HeaderCell.tsx b/vuu-ui/packages/vuu-table/src/header-cell/HeaderCell.tsx index 828e439cd..45a570acf 100644 --- a/vuu-ui/packages/vuu-table/src/header-cell/HeaderCell.tsx +++ b/vuu-ui/packages/vuu-table/src/header-cell/HeaderCell.tsx @@ -1,25 +1,15 @@ -import { RuntimeColumnDescriptor } from "@finos/vuu-table-types"; -import { HTMLAttributes, MouseEventHandler, useCallback, useRef } from "react"; -import { useCell } from "../useCell"; -import { ColumnMenu } from "../column-menu"; +import { HeaderCellProps } from "@finos/vuu-table-types"; +import cx from "clsx"; +import { MouseEventHandler, useCallback, useRef } from "react"; import { SortIndicator } from "../column-header-pill"; -import cx from "classnames"; -import { - ColumnResizer, - TableColumnResizeHandler, - useTableColumnResize, -} from "../column-resizing"; +import { ColumnMenu } from "../column-menu"; +import { ColumnResizer, useTableColumnResize } from "../column-resizing"; +import { useCell } from "../useCell"; import "./HeaderCell.css"; const classBase = "vuuTableHeaderCell"; -export interface HeaderCellProps extends HTMLAttributes { - classBase?: string; - column: RuntimeColumnDescriptor; - onResize?: TableColumnResizeHandler; -} - export const HeaderCell = ({ className: classNameProp, column, diff --git a/vuu-ui/packages/vuu-table/src/table-cell/TableCell.css b/vuu-ui/packages/vuu-table/src/table-cell/TableCell.css index be1a1fa67..3c0852460 100644 --- a/vuu-ui/packages/vuu-table/src/table-cell/TableCell.css +++ b/vuu-ui/packages/vuu-table/src/table-cell/TableCell.css @@ -2,27 +2,27 @@ border-right-color: var(--cell-borderColor); border-right-style: solid; border-right-width: 1px; - display: inline-block; - height: 100%; - overflow:hidden; - padding: 0 11px 0 12px; - text-overflow: ellipsis; - vertical-align: top; - } + display: inline-block; + height: 100%; + overflow:hidden; + padding: var(--vuuTableCell-padding, 0 11px 0 12px); + text-overflow: ellipsis; + vertical-align: top; +} - .vuuTableCell-right { +.vuuTableCell-right { text-align: right; - } +} - .vuuTableCell-editable { +.vuuTableCell-editable { display: inline-flex; line-height: 18px; padding-bottom: 1px; padding-top: 1px; text-overflow: unset; - } +} - .vuuTableCell:focus { +.vuuTableCell:focus { outline: var(--vuuTableCell-outline, solid var(--vuu-color-purple-10) 2px); outline-offset: -2px; /** This is to achieve a white background to outline dashes */ diff --git a/vuu-ui/packages/vuu-table/src/table-cell/TableGroupCell.tsx b/vuu-ui/packages/vuu-table/src/table-cell/TableGroupCell.tsx index 1d72534ac..ecfd39455 100644 --- a/vuu-ui/packages/vuu-table/src/table-cell/TableGroupCell.tsx +++ b/vuu-ui/packages/vuu-table/src/table-cell/TableGroupCell.tsx @@ -2,7 +2,7 @@ import { GroupColumnDescriptor, TableCellProps } from "@finos/vuu-table-types"; import { getGroupValueAndOffset, metadataKeys } from "@finos/vuu-utils"; import { MouseEvent, useCallback } from "react"; import { useCell } from "../useCell"; -import cx from "classnames"; +import cx from "clsx"; import "./TableGroupCell.css"; diff --git a/vuu-ui/packages/vuu-table/src/table-dom-utils.ts b/vuu-ui/packages/vuu-table/src/table-dom-utils.ts index 798b4373a..da10cb990 100644 --- a/vuu-ui/packages/vuu-table/src/table-dom-utils.ts +++ b/vuu-ui/packages/vuu-table/src/table-dom-utils.ts @@ -40,7 +40,7 @@ export function getRowIndex(rowEl?: HTMLElement) { if (rowEl) { const idx: string | null = rowEl.ariaRowIndex; if (idx !== null) { - return parseInt(idx, 10); + return parseInt(idx, 10) - 1; } } return -1; diff --git a/vuu-ui/packages/vuu-table/src/table-header/TableHeader.tsx b/vuu-ui/packages/vuu-table/src/table-header/TableHeader.tsx index dc45e0de2..8ec2dfbe8 100644 --- a/vuu-ui/packages/vuu-table/src/table-header/TableHeader.tsx +++ b/vuu-ui/packages/vuu-table/src/table-header/TableHeader.tsx @@ -1,13 +1,13 @@ +import { VuuSortType } from "@finos/vuu-protocol-types"; import { ColumnDescriptor, RuntimeColumnDescriptor, + TableColumnResizeHandler, TableConfig, TableHeadings, } from "@finos/vuu-table-types"; import { isGroupColumn, isNotHidden } from "@finos/vuu-utils"; -import cx from "classnames"; -import { VuuSortType } from "packages/vuu-protocol-types"; -import { TableColumnResizeHandler } from "../column-resizing"; +import cx from "clsx"; import { GroupHeaderCellNext, HeaderCell } from "../header-cell"; import { useTableHeader } from "./useTableHeader"; diff --git a/vuu-ui/packages/vuu-table/src/useCell.ts b/vuu-ui/packages/vuu-table/src/useCell.ts index dfbad9cf4..b5c23be13 100644 --- a/vuu-ui/packages/vuu-table/src/useCell.ts +++ b/vuu-ui/packages/vuu-table/src/useCell.ts @@ -1,6 +1,6 @@ import { RuntimeColumnDescriptor } from "@finos/vuu-table-types"; import { getColumnStyle } from "@finos/vuu-utils"; -import cx from "classnames"; +import cx from "clsx"; import { useMemo } from "react"; export const useCell = ( diff --git a/vuu-ui/packages/vuu-table/src/useDataSource.ts b/vuu-ui/packages/vuu-table/src/useDataSource.ts index d02def46b..1272c2abf 100644 --- a/vuu-ui/packages/vuu-table/src/useDataSource.ts +++ b/vuu-ui/packages/vuu-table/src/useDataSource.ts @@ -1,13 +1,13 @@ import { DataSource, + DataSourceRow, DataSourceSubscribedMessage, - isVuuFeatureInvocation, SubscribeCallback, VuuFeatureInvocationMessage, -} from "@finos/vuu-data"; -import { DataSourceRow } from "@finos/vuu-data-types"; +} from "@finos/vuu-data-types"; import { VuuRange } from "@finos/vuu-protocol-types"; import { getFullRange, NULL_RANGE } from "@finos/vuu-utils"; +import { GridAction } from "packages/vuu-table-types"; import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { MovingWindow } from "./moving-window"; @@ -21,6 +21,11 @@ export interface DataSourceHookProps { renderBufferSize?: number; } +export const isVuuFeatureInvocation = ( + action: GridAction +): action is VuuFeatureInvocationMessage => + action.type === "vuu-link-created" || action.type === "vuu-link-removed"; + export const useDataSource = ({ dataSource, onFeatureInvocation, diff --git a/vuu-ui/packages/vuu-table/src/useSelection.ts b/vuu-ui/packages/vuu-table/src/useSelection.ts index cd202317b..be71e750a 100644 --- a/vuu-ui/packages/vuu-table/src/useSelection.ts +++ b/vuu-ui/packages/vuu-table/src/useSelection.ts @@ -1,9 +1,4 @@ -import { - RowClickHandler, - Selection, - SelectionChangeHandler, - TableSelectionModel, -} from "@finos/vuu-table-types"; +import { RowClickHandler, TableSelectionModel } from "@finos/vuu-table-types"; import { deselectItem, dispatchMouseEvent, @@ -11,7 +6,11 @@ import { metadataKeys, selectItem, } from "@finos/vuu-utils"; -import { DataSourceRow } from "packages/vuu-data-types"; +import { + DataSourceRow, + Selection, + SelectionChangeHandler, +} from "packages/vuu-data-types"; import { KeyboardEvent, KeyboardEventHandler, diff --git a/vuu-ui/packages/vuu-table/src/useTable.ts b/vuu-ui/packages/vuu-table/src/useTable.ts index 599ee316e..82eca5064 100644 --- a/vuu-ui/packages/vuu-table/src/useTable.ts +++ b/vuu-ui/packages/vuu-table/src/useTable.ts @@ -1,25 +1,20 @@ import { DataSourceConfig, + DataSourceRow, DataSourceSubscribedMessage, - JsonDataSource, -} from "@finos/vuu-data"; -import { DataSourceRow } from "@finos/vuu-data-types"; + SelectionChangeHandler, +} from "@finos/vuu-data-types"; import { ColumnDescriptor, DataCellEditHandler, RowClickHandler, RuntimeColumnDescriptor, - SelectionChangeHandler, + TableColumnResizeHandler, TableConfig, TableSelectionModel, } from "@finos/vuu-table-types"; -import { - MeasuredProps, - MeasuredSize, - useLayoutEffectSkipFirst, -} from "@finos/vuu-layout"; +import { MeasuredProps, MeasuredSize } from "@finos/vuu-layout"; import { VuuRange, VuuSortType } from "@finos/vuu-protocol-types"; -import { useTableAndColumnSettings } from "@finos/vuu-table-extras"; import { DragStartHandler, useDragDropNext as useDragDrop, @@ -32,6 +27,7 @@ import { isValidNumber, metadataKeys, updateColumn, + useLayoutEffectSkipFirst, } from "@finos/vuu-utils"; import { FocusEvent, @@ -42,7 +38,6 @@ import { useMemo, useState, } from "react"; -import { TableColumnResizeHandler } from "./column-resizing"; import { buildContextMenuDescriptors, useHandleTableContextMenu, @@ -66,6 +61,7 @@ import { import { useTableScroll } from "./useTableScroll"; import { useTableViewport } from "./useTableViewport"; import { useVirtualViewport } from "./useVirtualViewport"; +import { useTableAndColumnSettings } from "./useTableAndColumnSettings"; const stripInternalProperties = (tableConfig: TableConfig): TableConfig => { return tableConfig; @@ -249,6 +245,7 @@ export const useTable = ({ const { data, dataRef, getSelectedRows, range, setRange } = useDataSource({ dataSource, + // We need to factor this out of Table onFeatureInvocation, renderBufferSize, onSizeChange: onDataRowcountChange, @@ -436,11 +433,11 @@ export const useTable = ({ const key = row[KEY]; if (row[IS_EXPANDED]) { - (dataSource as JsonDataSource).closeTreeNode(key, true); + dataSource.closeTreeNode(key, true); if (isJson) { const idx = columns.indexOf(column); - const rows = (dataSource as JsonDataSource).getRowsAtDepth(idx + 1); - if (!rows.some((row) => row[IS_EXPANDED] || row[IS_LEAF])) { + const rows = dataSource.getRowsAtDepth?.(idx + 1); + if (rows && !rows.some((row) => row[IS_EXPANDED] || row[IS_LEAF])) { dispatchColumnAction({ type: "hideColumns", columns: columns.slice(idx + 2), @@ -450,10 +447,10 @@ export const useTable = ({ } else { dataSource.openTreeNode(key); if (isJson) { - const childRows = (dataSource as JsonDataSource).getChildRows(key); + const childRows = dataSource.getChildRows?.(key); const idx = columns.indexOf(column) + 1; const columnsToShow = [columns[idx]]; - if (childRows.some((row) => row[IS_LEAF])) { + if (childRows && childRows.some((row) => row[IS_LEAF])) { columnsToShow.push(columns[idx + 1]); } if (columnsToShow.some((col) => col.hidden)) { diff --git a/vuu-ui/packages/vuu-table-extras/src/useTableAndColumnSettings.ts b/vuu-ui/packages/vuu-table/src/useTableAndColumnSettings.ts similarity index 95% rename from vuu-ui/packages/vuu-table-extras/src/useTableAndColumnSettings.ts rename to vuu-ui/packages/vuu-table/src/useTableAndColumnSettings.ts index 17229d727..8c7ad6ba7 100644 --- a/vuu-ui/packages/vuu-table-extras/src/useTableAndColumnSettings.ts +++ b/vuu-ui/packages/vuu-table/src/useTableAndColumnSettings.ts @@ -1,13 +1,14 @@ -import { DataSourceConfig, SchemaColumn } from "@finos/vuu-data"; -import { ColumnDescriptor, TableConfig } from "@finos/vuu-table-types"; +import { DataSourceConfig, SchemaColumn } from "@finos/vuu-data-types"; import { useLayoutProviderDispatch } from "@finos/vuu-layout"; import { + ColumnDescriptor, ColumnSettingsProps, + TableConfig, TableSettingsProps, -} from "@finos/vuu-table-extras"; -import { ColumnActionColumnSettings } from "@finos/vuu-table"; +} from "@finos/vuu-table-types"; import { getCalculatedColumnType } from "@finos/vuu-utils"; import { useCallback, useRef, useState } from "react"; +import { ColumnActionColumnSettings } from "./useTableModel"; export interface TableAndColumnSettingsHookProps { availableColumns: SchemaColumn[]; diff --git a/vuu-ui/packages/vuu-table/src/useTableContextMenu.ts b/vuu-ui/packages/vuu-table/src/useTableContextMenu.ts index 6c715ffdd..24c6a0a38 100644 --- a/vuu-ui/packages/vuu-table/src/useTableContextMenu.ts +++ b/vuu-ui/packages/vuu-table/src/useTableContextMenu.ts @@ -1,5 +1,4 @@ -import { DataSource } from "@finos/vuu-data"; -import { DataSourceRow } from "@finos/vuu-data-types"; +import { DataSource, DataSourceRow } from "@finos/vuu-data-types"; import { RuntimeColumnDescriptor } from "@finos/vuu-table-types"; import { useContextMenu as usePopupContextMenu } from "@finos/vuu-popups"; import { buildColumnMap } from "@finos/vuu-utils"; diff --git a/vuu-ui/packages/vuu-table/src/useTableModel.ts b/vuu-ui/packages/vuu-table/src/useTableModel.ts index de734cf38..7c0bfc2dd 100644 --- a/vuu-ui/packages/vuu-table/src/useTableModel.ts +++ b/vuu-ui/packages/vuu-table/src/useTableModel.ts @@ -1,7 +1,8 @@ import { ColumnDescriptor, - RuntimeColumnDescriptor, PinLocation, + ResizePhase, + RuntimeColumnDescriptor, TableAttributes, TableConfig, TableHeadings, @@ -11,6 +12,7 @@ import { applyGroupByToColumns, applySortToColumns, getCellRenderer, + getColumnHeaderRenderer, getColumnLabel, getTableHeadings, getValueFormatter, @@ -26,8 +28,11 @@ import { subscribedOnly, } from "@finos/vuu-utils"; -import { DataSource, DataSourceConfig } from "@finos/vuu-data"; -import { TableSchema } from "@finos/vuu-data/src/message-utils"; +import { + DataSource, + DataSourceConfig, + TableSchema, +} from "@finos/vuu-data-types"; import { VuuColumnDataType, VuuTable } from "@finos/vuu-protocol-types"; import { buildValidationChecker } from "@finos/vuu-ui-controls"; import { Reducer, useReducer } from "react"; @@ -108,8 +113,6 @@ export interface ColumnActionPin { pin?: PinLocation; } -export type ResizePhase = "begin" | "resize" | "end"; - export interface ColumnActionResize { type: "resizeColumn"; column: RuntimeColumnDescriptor; @@ -297,12 +300,12 @@ const columnDescriptorToRuntimeColumDescriptor = ...rest } = column; - const runtimeColumnWithDefaults = { + const runtimeColumnWithDefaults: RuntimeColumnDescriptor = { ...rest, align, CellRenderer: getCellRenderer(column), - HeaderCellLabelRenderer: getCellRenderer(column, "col-label"), - HeaderCellContentRenderer: getCellRenderer(column, "col-content"), + HeaderCellLabelRenderer: getColumnHeaderRenderer(column), + HeaderCellContentRenderer: getColumnHeaderRenderer(column), clientSideEditValidationCheck: hasValidationRules(column.type) ? buildValidationChecker(column.type.renderer.rules) : undefined, diff --git a/vuu-ui/packages/vuu-table/src/useVirtualViewport.ts b/vuu-ui/packages/vuu-table/src/useVirtualViewport.ts index c57a40f75..556ddb6a6 100644 --- a/vuu-ui/packages/vuu-table/src/useVirtualViewport.ts +++ b/vuu-ui/packages/vuu-table/src/useVirtualViewport.ts @@ -2,7 +2,7 @@ import { RuntimeColumnDescriptor } from "@finos/vuu-table-types"; import { VuuRange } from "@finos/vuu-protocol-types"; import { RowAtPositionFunc } from "@finos/vuu-utils"; import { useCallback, useEffect, useRef } from "react"; -import { ViewportMeasurements } from "@finos/vuu-table"; +import { ViewportMeasurements } from "./useTableViewport"; export interface VirtualViewportHookProps { columns: RuntimeColumnDescriptor[]; diff --git a/vuu-ui/packages/vuu-theme/css/components/checkbox.css b/vuu-ui/packages/vuu-theme/css/components/checkbox.css index 68d813b98..58d5b7bfa 100644 --- a/vuu-ui/packages/vuu-theme/css/components/checkbox.css +++ b/vuu-ui/packages/vuu-theme/css/components/checkbox.css @@ -42,10 +42,8 @@ background-color: var(--vuu-icon-color); left: var(--vuu-icon-left, auto); height: var(--vuu-icon-height, var(--vuu-icon-size, 12px)); - -webkit-mask: var(--vuu-svg-tick) center center/var(--vuu-icon-size) var(--vuu-icon-size); - mask: var(--vuu-icon-svg) center center/var(--vuu-icon-size) var(--vuu-icon-size); + mask: var(--vuu-svg-tick) center center/var(--vuu-icon-size) var(--vuu-icon-size); mask-repeat: no-repeat; - -webkit-mask-repeat: no-repeat; position: absolute; top: var(--vuu-icon-top, auto); width: var(--vuu-icon-width, var(--vuu-icon-size, 12px)); diff --git a/vuu-ui/packages/vuu-theme/css/components/switch.css b/vuu-ui/packages/vuu-theme/css/components/switch.css index c40cde19a..bb961ada8 100644 --- a/vuu-ui/packages/vuu-theme/css/components/switch.css +++ b/vuu-ui/packages/vuu-theme/css/components/switch.css @@ -1,7 +1,6 @@ .saltSwitch { --switch-color: var(--vuu-color-gray-45); --vuu-icon-left: -1px; - } .saltSwitch-track { @@ -13,7 +12,7 @@ width: 26px; } -.saltSwitch:hover .saltSwitch-track { +.saltSwitch:not(.saltSwitch-disabled):hover .saltSwitch-track { --switch-color: var(--vuu-color-pink-10); } @@ -30,6 +29,10 @@ --switch-color: var(--vuu-color-purple-10); } +.saltSwitch-disabled { + --switch-color: var(--vuu-color-gray-30); +} + .saltSwitch-checked .saltSwitch-thumb, .saltSwitch-checked:hover .saltSwitch-thumb { background-color: white; @@ -42,10 +45,8 @@ content: ""; left: var(--vuu-icon-left, auto); height: var(--vuu-icon-height, var(--vuu-icon-size, 12px)); - -webkit-mask: var(--vuu-svg-tick) center center/var(--vuu-icon-size) var(--vuu-icon-size); - mask: var(--vuu-icon-svg) center center/var(--vuu-icon-size) var(--vuu-icon-size); + mask: var(--vuu-svg-tick) center center/var(--vuu-icon-size) var(--vuu-icon-size); mask-repeat: no-repeat; - -webkit-mask-repeat: no-repeat; position: absolute; top: var(--vuu-icon-top, auto); width: var(--vuu-icon-width, var(--vuu-icon-size, 12px)); diff --git a/vuu-ui/packages/vuu-theme/css/palette/neutral.css b/vuu-ui/packages/vuu-theme/css/palette/neutral.css index d5ed43163..db95dd59c 100644 --- a/vuu-ui/packages/vuu-theme/css/palette/neutral.css +++ b/vuu-ui/packages/vuu-theme/css/palette/neutral.css @@ -1,6 +1,6 @@ .vuu-theme[data-mode="light"] { --salt-palette-neutral-primary-background: var(--salt-color-white); - --salt-palette-neutral-primary-background-disabled: var(--salt-color-white-fade-background); + --salt-palette-neutral-primary-background-disabled: var(--vuu-color-gray-30); --salt-palette-neutral-primary-background-readonly: var(--salt-color-white-fade-background-readonly); --salt-palette-neutral-primary-foreground: var(--vuu-color-gray-80); --salt-palette-neutral-primary-foreground-disabled: var(--salt-color-gray-900-fade-foreground); diff --git a/vuu-ui/packages/vuu-ui-controls/package.json b/vuu-ui/packages/vuu-ui-controls/package.json index ab65e62ad..02ccb0c13 100644 --- a/vuu-ui/packages/vuu-ui-controls/package.json +++ b/vuu-ui/packages/vuu-ui-controls/package.json @@ -10,8 +10,7 @@ "type-defs": "node ../../scripts/build-type-defs.mjs" }, "dependencies": { - "@salt-ds/core": "1.8.0", - "@finos/vuu-data": "0.0.26", + "@salt-ds/core": "1.13.2", "@finos/vuu-data-types": "0.0.26", "@finos/vuu-table-types": "0.0.26", "@finos/vuu-layout": "0.0.26", @@ -20,8 +19,9 @@ "@finos/vuu-utils": "0.0.26" }, "peerDependencies": { - "classnames": "^2.2.6", + "clsx": "^2.0.0", "react": ">=17.0.2", "react-dom": ">=17.0.2" - } + }, + "sideEffects": false } diff --git a/vuu-ui/packages/vuu-ui-controls/src/combo-box/ComboBox.tsx b/vuu-ui/packages/vuu-ui-controls/src/combo-box/ComboBox.tsx index 84618f28b..dd328424d 100644 --- a/vuu-ui/packages/vuu-ui-controls/src/combo-box/ComboBox.tsx +++ b/vuu-ui/packages/vuu-ui-controls/src/combo-box/ComboBox.tsx @@ -1,4 +1,4 @@ -import { useId } from "@finos/vuu-layout"; +import { useId } from "@finos/vuu-utils"; import { Input, InputProps } from "@salt-ds/core"; import { ForwardedRef, @@ -16,8 +16,8 @@ import { } from "../common-hooks"; import { DropdownBase, DropdownBaseProps } from "../dropdown"; import { List, ListProps } from "../list"; -import { useCombobox } from "./useCombobox"; import { ChevronIcon } from "../list/ChevronIcon"; +import { useCombobox } from "./useCombobox"; //TODO why do we need onSelect from input ? export interface ComboBoxProps< diff --git a/vuu-ui/packages/vuu-ui-controls/src/combo-box/useCombobox.ts b/vuu-ui/packages/vuu-ui-controls/src/combo-box/useCombobox.ts index a5063293b..3c6c0670c 100644 --- a/vuu-ui/packages/vuu-ui-controls/src/combo-box/useCombobox.ts +++ b/vuu-ui/packages/vuu-ui-controls/src/combo-box/useCombobox.ts @@ -1,5 +1,5 @@ +import { useLayoutEffectSkipFirst } from "@finos/vuu-utils"; import { InputProps, useControlled } from "@salt-ds/core"; -import { useLayoutEffectSkipFirst } from "@finos/vuu-layout"; import { ChangeEvent, FocusEvent, diff --git a/vuu-ui/packages/vuu-ui-controls/src/cycle-state-button/CycleStateButton.tsx b/vuu-ui/packages/vuu-ui-controls/src/cycle-state-button/CycleStateButton.tsx index 9f9de984c..96adaff6d 100644 --- a/vuu-ui/packages/vuu-ui-controls/src/cycle-state-button/CycleStateButton.tsx +++ b/vuu-ui/packages/vuu-ui-controls/src/cycle-state-button/CycleStateButton.tsx @@ -1,5 +1,5 @@ import { Button, ButtonProps } from "@salt-ds/core"; -import cx from "classnames"; +import cx from "clsx"; import { CommitResponse } from "packages/vuu-table-types"; import { VuuColumnDataType, diff --git a/vuu-ui/packages/vuu-ui-controls/src/drag-drop/Draggable.tsx b/vuu-ui/packages/vuu-ui-controls/src/drag-drop/Draggable.tsx index 1e8d3be34..75a79cd1a 100644 --- a/vuu-ui/packages/vuu-ui-controls/src/drag-drop/Draggable.tsx +++ b/vuu-ui/packages/vuu-ui-controls/src/drag-drop/Draggable.tsx @@ -1,5 +1,5 @@ import { useForkRef } from "@salt-ds/core"; -import cx from "classnames"; +import cx from "clsx"; import { CSSProperties, forwardRef, diff --git a/vuu-ui/packages/vuu-ui-controls/src/dropdown/Dropdown.tsx b/vuu-ui/packages/vuu-ui-controls/src/dropdown/Dropdown.tsx index fa04c1bca..f6ff75c0c 100644 --- a/vuu-ui/packages/vuu-ui-controls/src/dropdown/Dropdown.tsx +++ b/vuu-ui/packages/vuu-ui-controls/src/dropdown/Dropdown.tsx @@ -8,7 +8,7 @@ import { useRef, } from "react"; -import { useId } from "@finos/vuu-layout"; +import { useId } from "@finos/vuu-utils"; import { CollectionProvider, itemToString as defaultItemToString, @@ -17,10 +17,10 @@ import { useCollectionItems, } from "../common-hooks"; import { List, ListProps } from "../list"; +import { forwardCallbackProps } from "../utils"; import { DropdownBase, MaybeChildProps } from "./DropdownBase"; import { DropdownButton } from "./DropdownButton"; import { DropdownBaseProps } from "./dropdownTypes"; -import { forwardCallbackProps } from "../utils"; import { useDropdown } from "./useDropdown"; export interface DropdownProps< diff --git a/vuu-ui/packages/vuu-ui-controls/src/dropdown/DropdownBase.tsx b/vuu-ui/packages/vuu-ui-controls/src/dropdown/DropdownBase.tsx index 3e932f2af..bb71b5655 100644 --- a/vuu-ui/packages/vuu-ui-controls/src/dropdown/DropdownBase.tsx +++ b/vuu-ui/packages/vuu-ui-controls/src/dropdown/DropdownBase.tsx @@ -1,11 +1,11 @@ -import cx from "classnames"; +import { PopupComponent as Popup, Portal } from "@finos/vuu-popups"; +import { useId } from "@finos/vuu-utils"; import { useForkRef } from "@salt-ds/core"; +import cx from "clsx"; import { Children, cloneElement, forwardRef, useRef } from "react"; import { forwardCallbackProps } from "../utils"; import { DropdownBaseProps } from "./dropdownTypes"; import { useDropdownBase } from "./useDropdownBase"; -import { useId } from "@finos/vuu-layout"; -import { PopupComponent as Popup, Portal } from "@finos/vuu-popups"; import "./Dropdown.css"; diff --git a/vuu-ui/packages/vuu-ui-controls/src/dropdown/DropdownButton.tsx b/vuu-ui/packages/vuu-ui-controls/src/dropdown/DropdownButton.tsx index 6ea5fc8b8..5c7b62434 100644 --- a/vuu-ui/packages/vuu-ui-controls/src/dropdown/DropdownButton.tsx +++ b/vuu-ui/packages/vuu-ui-controls/src/dropdown/DropdownButton.tsx @@ -1,5 +1,5 @@ import { Button, ButtonProps } from "@salt-ds/core"; -import cx from "classnames"; +import cx from "clsx"; import { AriaAttributes, ForwardedRef, forwardRef } from "react"; import "./DropdownButton.css"; diff --git a/vuu-ui/packages/vuu-ui-controls/src/editable-label/EditableLabel.tsx b/vuu-ui/packages/vuu-ui-controls/src/editable-label/EditableLabel.tsx index f7cace02f..67f55d2a3 100644 --- a/vuu-ui/packages/vuu-ui-controls/src/editable-label/EditableLabel.tsx +++ b/vuu-ui/packages/vuu-ui-controls/src/editable-label/EditableLabel.tsx @@ -1,4 +1,4 @@ -import cx from "classnames"; +import cx from "clsx"; import { ChangeEvent, KeyboardEvent, diff --git a/vuu-ui/packages/vuu-ui-controls/src/editable/useEditableText.ts b/vuu-ui/packages/vuu-ui-controls/src/editable/useEditableText.ts index 274905063..1e49c84bf 100644 --- a/vuu-ui/packages/vuu-ui-controls/src/editable/useEditableText.ts +++ b/vuu-ui/packages/vuu-ui-controls/src/editable/useEditableText.ts @@ -1,5 +1,5 @@ import { DataItemCommitHandler } from "@finos/vuu-table-types"; -import { useLayoutEffectSkipFirst } from "@finos/vuu-layout"; +import { useLayoutEffectSkipFirst } from "@finos/vuu-utils"; import { VuuRowDataItemType } from "@finos/vuu-protocol-types"; import { dispatchCustomEvent } from "@finos/vuu-utils"; import { diff --git a/vuu-ui/packages/vuu-ui-controls/src/expando-input/ExpandoInput.tsx b/vuu-ui/packages/vuu-ui-controls/src/expando-input/ExpandoInput.tsx index 54fa022bd..ee9abafdd 100644 --- a/vuu-ui/packages/vuu-ui-controls/src/expando-input/ExpandoInput.tsx +++ b/vuu-ui/packages/vuu-ui-controls/src/expando-input/ExpandoInput.tsx @@ -1,6 +1,6 @@ -import { VuuInput, VuuInputProps } from "@finos/vuu-ui-controls"; -import cx from "classnames"; +import cx from "clsx"; import { ForwardedRef, forwardRef } from "react"; +import { VuuInput, VuuInputProps } from "../vuu-input"; import "./ExpandoInput.css"; diff --git a/vuu-ui/packages/vuu-ui-controls/src/inputs/Checkbox.tsx b/vuu-ui/packages/vuu-ui-controls/src/inputs/Checkbox.tsx index 85eda99c2..889a5921f 100644 --- a/vuu-ui/packages/vuu-ui-controls/src/inputs/Checkbox.tsx +++ b/vuu-ui/packages/vuu-ui-controls/src/inputs/Checkbox.tsx @@ -1,16 +1,16 @@ -import { CheckboxIcon } from "@finos/vuu-ui-controls/src/list/CheckboxIcon"; +import { CheckboxIcon } from "../list/CheckboxIcon"; import "./Checkbox.css"; type CheckboxProps = { - onToggle: () => void, - className?: string, - checked: boolean, - label: string -} + onToggle: () => void; + className?: string; + checked: boolean; + label: string; +}; export const Checkbox = (props: CheckboxProps): JSX.Element => { - const {onToggle, checked, label} = props; + const { onToggle, checked, label } = props; return (
{ {label}
- ) -} + ); +}; diff --git a/vuu-ui/packages/vuu-ui-controls/src/instrument-picker/InstrumentPicker.tsx b/vuu-ui/packages/vuu-ui-controls/src/instrument-picker/InstrumentPicker.tsx index 5398cefe9..503cefc45 100644 --- a/vuu-ui/packages/vuu-ui-controls/src/instrument-picker/InstrumentPicker.tsx +++ b/vuu-ui/packages/vuu-ui-controls/src/instrument-picker/InstrumentPicker.tsx @@ -1,18 +1,20 @@ -import { TableSchema } from "@finos/vuu-data"; -import { DataSourceRow } from "@finos/vuu-data-types"; -import { useId } from "@finos/vuu-layout"; +import { DataSourceRow, TableSchema } from "@finos/vuu-data-types"; import { Table, TableProps, TableRowSelectHandler } from "@finos/vuu-table"; -import { ColumnMap } from "@finos/vuu-utils"; +import { ColumnMap, useId } from "@finos/vuu-utils"; import { Input } from "@salt-ds/core"; import { ForwardedRef, forwardRef, HTMLAttributes, useMemo } from "react"; import { DropdownBase, OpenChangeHandler } from "../dropdown"; -import "./SearchCell"; +import { SearchCell } from "./SearchCell"; import { useInstrumentPicker } from "./useInstrumentPicker"; import "./InstrumentPicker.css"; const classBase = "vuuInstrumentPicker"; +if (typeof SearchCell !== "function") { + console.warn("Instrument Picker: SearchCell module not loaded "); +} + export interface InstrumentPickerProps extends Omit, "onSelect"> { TableProps: Pick; diff --git a/vuu-ui/packages/vuu-ui-controls/src/instrument-picker/useDataSource.ts b/vuu-ui/packages/vuu-ui-controls/src/instrument-picker/useDataSource.ts index 4fe080729..9dafe4575 100644 --- a/vuu-ui/packages/vuu-ui-controls/src/instrument-picker/useDataSource.ts +++ b/vuu-ui/packages/vuu-ui-controls/src/instrument-picker/useDataSource.ts @@ -1,7 +1,10 @@ //TODO stansardise this -import { DataSource, SubscribeCallback } from "@finos/vuu-data"; -import { DataSourceRow } from "@finos/vuu-data-types"; +import { + DataSource, + DataSourceRow, + SubscribeCallback, +} from "@finos/vuu-data-types"; import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { MovingWindow } from "./moving-window"; export interface DataSourceHookProps { diff --git a/vuu-ui/packages/vuu-ui-controls/src/instrument-picker/useInstrumentPicker.ts b/vuu-ui/packages/vuu-ui-controls/src/instrument-picker/useInstrumentPicker.ts index 37f03a6ba..309bc2508 100644 --- a/vuu-ui/packages/vuu-ui-controls/src/instrument-picker/useInstrumentPicker.ts +++ b/vuu-ui/packages/vuu-ui-controls/src/instrument-picker/useInstrumentPicker.ts @@ -1,5 +1,4 @@ -import { DataSource } from "@finos/vuu-data"; -import { DataSourceRow } from "@finos/vuu-data-types"; +import { DataSource, DataSourceRow } from "@finos/vuu-data-types"; import { ColumnDescriptor } from "@finos/vuu-table-types"; import { TableRowSelectHandler, diff --git a/vuu-ui/packages/vuu-ui-controls/src/instrument-search/InstrumentSearch.tsx b/vuu-ui/packages/vuu-ui-controls/src/instrument-search/InstrumentSearch.tsx index f38449ad4..20a885b01 100644 --- a/vuu-ui/packages/vuu-ui-controls/src/instrument-search/InstrumentSearch.tsx +++ b/vuu-ui/packages/vuu-ui-controls/src/instrument-search/InstrumentSearch.tsx @@ -1,4 +1,4 @@ -import { DataSource } from "@finos/vuu-data"; +import { DataSource } from "@finos/vuu-data-types"; import { TableConfig } from "@finos/vuu-table-types"; import { registerComponent } from "@finos/vuu-layout"; @@ -8,16 +8,19 @@ import { useControlledTableNavigation, } from "@finos/vuu-table"; import { Input } from "@salt-ds/core"; -import cx from "classnames"; +import cx from "clsx"; import { HTMLAttributes, RefCallback, useCallback } from "react"; -import "./SearchCell"; +import { SearchCell } from "./SearchCell"; import "./InstrumentSearch.css"; -import { VuuTable } from "packages/vuu-protocol-types"; import { useInstrumentSearch } from "./useInstrumentSearch"; const classBase = "vuuInstrumentSearch"; +if (typeof SearchCell !== "function") { + console.warn("Instrument Search: SearchCell module not loaded "); +} + const defaultTableConfig: TableConfig = { columns: [ { name: "bbg", hidden: true }, @@ -38,10 +41,9 @@ const defaultTableConfig: TableConfig = { export interface InstrumentSearchProps extends HTMLAttributes { TableProps?: Partial; autoFocus?: boolean; - dataSource?: DataSource; + dataSource: DataSource; placeHolder?: string; searchColumns?: string[]; - table?: VuuTable; } const searchIcon = ; @@ -53,13 +55,11 @@ export const InstrumentSearch = ({ dataSource: dataSourceProp, placeHolder, searchColumns, - table, ...htmlAttributes }: InstrumentSearchProps) => { const { dataSource, onChange, searchState } = useInstrumentSearch({ dataSource: dataSourceProp, searchColumns, - table, }); const { highlightedIndexRef, onHighlight, onKeyDown, tableRef } = diff --git a/vuu-ui/packages/vuu-ui-controls/src/instrument-search/useDataSource.ts b/vuu-ui/packages/vuu-ui-controls/src/instrument-search/useDataSource.ts index 4fe080729..9dafe4575 100644 --- a/vuu-ui/packages/vuu-ui-controls/src/instrument-search/useDataSource.ts +++ b/vuu-ui/packages/vuu-ui-controls/src/instrument-search/useDataSource.ts @@ -1,7 +1,10 @@ //TODO stansardise this -import { DataSource, SubscribeCallback } from "@finos/vuu-data"; -import { DataSourceRow } from "@finos/vuu-data-types"; +import { + DataSource, + DataSourceRow, + SubscribeCallback, +} from "@finos/vuu-data-types"; import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { MovingWindow } from "./moving-window"; export interface DataSourceHookProps { diff --git a/vuu-ui/packages/vuu-ui-controls/src/instrument-search/useInstrumentSearch.ts b/vuu-ui/packages/vuu-ui-controls/src/instrument-search/useInstrumentSearch.ts index 3f90ca8e0..237ba5557 100644 --- a/vuu-ui/packages/vuu-ui-controls/src/instrument-search/useInstrumentSearch.ts +++ b/vuu-ui/packages/vuu-ui-controls/src/instrument-search/useInstrumentSearch.ts @@ -1,25 +1,15 @@ -import { DataSource, RemoteDataSource } from "@finos/vuu-data"; -import { getVuuTableSchema } from "@finos/vuu-data-react"; -import { useViewContext } from "@finos/vuu-layout"; import { FormEventHandler, useCallback, useMemo, useState } from "react"; import { InstrumentSearchProps } from "./InstrumentSearch"; export interface InstrumentSearchHookProps - extends Pick< - InstrumentSearchProps, - "dataSource" | "searchColumns" | "table" - > { + extends Pick { label?: string; } export const useInstrumentSearch = ({ - dataSource: dataSourceProp, + dataSource, searchColumns = ["description"], - table, }: InstrumentSearchHookProps) => { - const [dataSource, setDataSource] = useState(dataSourceProp); - const { loadSession, saveSession } = useViewContext(); - const [searchState, setSearchState] = useState<{ searchText: string; filter: string; @@ -31,32 +21,6 @@ export const useInstrumentSearch = ({ [searchColumns] ); - useMemo(() => { - if (dataSourceProp === undefined) { - if (table) { - const sessionKey = `instrument-search-${table.module}-${table.table}`; - const dataSource = loadSession?.(sessionKey) as DataSource; - if (dataSource) { - setDataSource(dataSource); - } else { - getVuuTableSchema(table).then((tableSchema) => { - const newDataSource = new RemoteDataSource({ - columns: tableSchema.columns.map((col) => col.name), - // sort: { sortDefs: [{ column: "description", sortType: "A" }] }, - table: tableSchema.table, - }); - setDataSource(newDataSource); - saveSession?.(newDataSource, sessionKey); - }); - } - } else { - throw Error( - `useInstrumentSearch, if dataSource ismnot provided as prop, Vuu table must be provided` - ); - } - } - }, [dataSourceProp, loadSession, saveSession, table]); - const handleChange = useCallback( (evt) => { const { value } = evt.target as HTMLInputElement; diff --git a/vuu-ui/packages/vuu-ui-controls/src/list/CheckboxIcon.tsx b/vuu-ui/packages/vuu-ui-controls/src/list/CheckboxIcon.tsx index 4521b67e6..ab0701a16 100644 --- a/vuu-ui/packages/vuu-ui-controls/src/list/CheckboxIcon.tsx +++ b/vuu-ui/packages/vuu-ui-controls/src/list/CheckboxIcon.tsx @@ -1,7 +1,7 @@ // TODO why do we need explicit React import - its not needed anywhere else // but we see a 'React is not defined' issue in showcase without it import React, { HTMLAttributes } from "react"; -import cx from "classnames"; +import cx from "clsx"; import "./CheckboxIcon.css"; diff --git a/vuu-ui/packages/vuu-ui-controls/src/list/ChevronIcon.tsx b/vuu-ui/packages/vuu-ui-controls/src/list/ChevronIcon.tsx index 25e060d61..851849b80 100644 --- a/vuu-ui/packages/vuu-ui-controls/src/list/ChevronIcon.tsx +++ b/vuu-ui/packages/vuu-ui-controls/src/list/ChevronIcon.tsx @@ -1,4 +1,4 @@ -import cx from "classnames"; +import cx from "clsx"; import { HTMLAttributes } from "react"; import "./ChevronIcon.css"; @@ -13,7 +13,5 @@ interface ChevronProps extends HTMLAttributes { export const ChevronIcon = (props: ChevronProps) => { const { direction, ...htmlAttributes } = props; - return ( - - ) + return ; }; diff --git a/vuu-ui/packages/vuu-ui-controls/src/list/List.tsx b/vuu-ui/packages/vuu-ui-controls/src/list/List.tsx index 18e56040e..ad2b5d9a2 100644 --- a/vuu-ui/packages/vuu-ui-controls/src/list/List.tsx +++ b/vuu-ui/packages/vuu-ui-controls/src/list/List.tsx @@ -1,6 +1,7 @@ -import { MeasuredContainer, MeasuredSize, useId } from "@finos/vuu-layout"; +import { MeasuredContainer, MeasuredSize } from "@finos/vuu-layout"; +import { useId } from "@finos/vuu-utils"; import { useForkRef } from "@salt-ds/core"; -import cx from "classnames"; +import cx from "clsx"; import { cloneElement, ForwardedRef, @@ -11,18 +12,18 @@ import { useRef, useState, } from "react"; -import { - isSelected, - LIST_FOCUS_VISIBLE, - useCollectionItems, - useImperativeScrollingAPI, -} from "./common-hooks"; import { CollectionIndexer, CollectionItem, itemToString as defaultItemToString, SelectionStrategy, } from "../common-hooks"; +import { + isSelected, + LIST_FOCUS_VISIBLE, + useCollectionItems, + useImperativeScrollingAPI, +} from "./common-hooks"; import { ListItem as DefaultListItem, ListItemProxy } from "./ListItem"; import { ListItemProps, ListProps } from "./listTypes"; diff --git a/vuu-ui/packages/vuu-ui-controls/src/list/ListItem.tsx b/vuu-ui/packages/vuu-ui-controls/src/list/ListItem.tsx index cafbbfbc2..745071a93 100644 --- a/vuu-ui/packages/vuu-ui-controls/src/list/ListItem.tsx +++ b/vuu-ui/packages/vuu-ui-controls/src/list/ListItem.tsx @@ -1,5 +1,5 @@ import { ForwardedRef, forwardRef, HTMLAttributes } from "react"; -import cx from "classnames"; +import cx from "clsx"; import { ListItemProps, ListItemType } from "./listTypes"; import { Highlighter } from "./Highlighter"; import { CheckboxIcon } from "./CheckboxIcon"; diff --git a/vuu-ui/packages/vuu-ui-controls/src/list/RadioIcon.tsx b/vuu-ui/packages/vuu-ui-controls/src/list/RadioIcon.tsx index db2423404..0b514a7ba 100644 --- a/vuu-ui/packages/vuu-ui-controls/src/list/RadioIcon.tsx +++ b/vuu-ui/packages/vuu-ui-controls/src/list/RadioIcon.tsx @@ -1,13 +1,10 @@ -import cx from "classnames"; +import cx from "clsx"; import "./RadioIcon.css"; const classBase = "vuuRadioIcon"; -export const RadioIcon = ({ - checked = false, - ...htmlAttributes -}) => ( +export const RadioIcon = ({ checked = false, ...htmlAttributes }) => ( =17.0.2", "react-dom": ">=17.0.2" - } + }, + "sideEffects": false } diff --git a/vuu-ui/packages/vuu-shell/src/theme-provider/ThemeProvider.tsx b/vuu-ui/packages/vuu-utils/src/ThemeProvider.tsx similarity index 97% rename from vuu-ui/packages/vuu-shell/src/theme-provider/ThemeProvider.tsx rename to vuu-ui/packages/vuu-utils/src/ThemeProvider.tsx index 660e95bc7..10a322d72 100644 --- a/vuu-ui/packages/vuu-shell/src/theme-provider/ThemeProvider.tsx +++ b/vuu-ui/packages/vuu-utils/src/ThemeProvider.tsx @@ -6,7 +6,7 @@ import React, { cloneElement, useContext, } from "react"; -import cx from "classnames"; +import cx from "clsx"; export const DEFAULT_DENSITY: Density = "medium"; export const DEFAULT_THEME = "salt-theme"; @@ -83,7 +83,7 @@ const createThemedChildren = ( } else { console.warn( `\nThemeProvider can only apply CSS classes for theming to a single nested child element of the ThemeProvider. - Wrap elements with a single container` + Wrap elements with a single container` ); return children; } diff --git a/vuu-ui/packages/vuu-utils/src/column-utils.ts b/vuu-ui/packages/vuu-utils/src/column-utils.ts index f61cddd1e..8cc478207 100644 --- a/vuu-ui/packages/vuu-utils/src/column-utils.ts +++ b/vuu-ui/packages/vuu-utils/src/column-utils.ts @@ -1,34 +1,38 @@ -import type { SchemaColumn, TableSchema } from "@finos/vuu-data"; -import type { DataSourceFilter, DataSourceRow } from "@finos/vuu-data-types"; +import type { + DataSourceFilter, + DataSourceRow, + SchemaColumn, + TableSchema, +} from "@finos/vuu-data-types"; +import type { Filter, MultiClauseFilter } from "@finos/vuu-filter-types"; +import type { + VuuAggregation, + VuuAggType, + VuuColumnDataType, + VuuDataRow, + VuuGroupBy, + VuuRowRecord, + VuuSort, +} from "@finos/vuu-protocol-types"; import type { ColumnAlignment, ColumnDescriptor, ColumnType, ColumnTypeDescriptor, + ColumnTypeFormatting, ColumnTypeRendering, ColumnTypeWithValidationRules, + DateTimeColumnTypeSimple, + DefaultColumnConfiguration, GroupColumnDescriptor, - RuntimeColumnDescriptor, + LookupRenderer, MappedValueTypeRenderer, PinLocation, + RuntimeColumnDescriptor, TableHeading, TableHeadings, - ColumnTypeFormatting, - LookupRenderer, ValueListRenderer, - DateTimeColumnTypeSimple, } from "@finos/vuu-table-types"; -import type { Filter, MultiClauseFilter } from "@finos/vuu-filter-types"; -import type { - VuuAggregation, - VuuAggType, - VuuColumnDataType, - VuuDataRow, - VuuGroupBy, - VuuRowRecord, - VuuSort, -} from "@finos/vuu-protocol-types"; -import { DefaultColumnConfiguration } from "@finos/vuu-shell"; import type { CSSProperties } from "react"; import { moveItem } from "./array-utils"; import { isFilterClause, isMultiClauseFilter } from "./filter-utils"; diff --git a/vuu-ui/packages/vuu-utils/src/component-registry.ts b/vuu-ui/packages/vuu-utils/src/component-registry.ts index cafc01cf7..502a9f120 100644 --- a/vuu-ui/packages/vuu-utils/src/component-registry.ts +++ b/vuu-ui/packages/vuu-utils/src/component-registry.ts @@ -4,6 +4,7 @@ import { ColumnDescriptorCustomRenderer, ColumnTypeRendering, EditValidationRule, + HeaderCellProps, TableCellRendererProps, } from "@finos/vuu-table-types"; import { @@ -11,7 +12,6 @@ import { VuuRowDataItemType, } from "@finos/vuu-protocol-types"; import { isTypeDescriptor, isColumnTypeRenderer } from "./column-utils"; -import { HeaderCellProps } from "@finos/vuu-table"; export interface CellConfigPanelProps extends HTMLAttributes { onConfigChange: () => void; @@ -33,6 +33,7 @@ export interface ConfigurationEditorProps { export type ConfigEditorComponent = FC; const cellRenderersMap = new Map>(); +const columnHeaderRenderersMap = new Map>(); const configEditorsMap = new Map>(); const cellConfigPanelsMap = new Map(); const editRuleValidatorsMap = new Map(); @@ -45,6 +46,8 @@ export type EditRuleValidator = ( export type ComponentType = | "cell-renderer" + | "column-header-content-renderer" + | "column-header-label-renderer" | "cell-config-panel" | "data-edit-validator"; @@ -83,6 +86,13 @@ const isCellRenderer = ( component: unknown ): component is FC => type === "cell-renderer"; +const isColumnHeaderRenderer = ( + type: ComponentType, + component: unknown +): component is FC => + type === "column-header-content-renderer" || + type === "column-header-label-renderer"; + const isCellConfigPanel = ( type: ComponentType, component: unknown @@ -107,6 +117,8 @@ export function registerComponent< ): void { if (isCellRenderer(type, component)) { cellRenderersMap.set(componentName, component); + } else if (isColumnHeaderRenderer(type, component)) { + columnHeaderRenderersMap.set(componentName, component); } else if (isCellConfigPanel(type, component)) { cellConfigPanelsMap.set(componentName, component); } else if (isEditRuleValidator(type, component)) { @@ -144,16 +156,12 @@ export const getRegisteredCellRenderers = ( export const getCellRendererOptions = (renderName: string) => optionsMap.get(renderName); -export function getCellRenderer( - column: ColumnDescriptor, - cellType: "cell" | "col-content" | "col-label" = "cell" -) { - if (cellType === "cell") { - return dataCellRenderer(column); - } else if (cellType === "col-label" && column.colHeaderLabelRenderer) { - return cellRenderersMap.get(column.colHeaderLabelRenderer); - } else if (cellType === "col-content" && column.colHeaderContentRenderer) { - return cellRenderersMap.get(column.colHeaderContentRenderer); +export function getCellRenderer(column: ColumnDescriptor) { + return dataCellRenderer(column); +} +export function getColumnHeaderRenderer(column: ColumnDescriptor) { + if (column.colHeaderContentRenderer) { + return columnHeaderRenderersMap.get(column.colHeaderContentRenderer); } } diff --git a/vuu-ui/packages/vuu-utils/src/datasource-action-utils.ts b/vuu-ui/packages/vuu-utils/src/datasource-action-utils.ts new file mode 100644 index 000000000..09ac3f2ef --- /dev/null +++ b/vuu-ui/packages/vuu-utils/src/datasource-action-utils.ts @@ -0,0 +1,31 @@ +import { + DataSourceMenusMessage, + DataSourceVisualLinkCreatedMessage, + DataSourceVisualLinkRemovedMessage, + DataSourceVisualLinksMessage, + VuuFeatureMessage, +} from "@finos/vuu-data-types"; +import { GridAction } from "@finos/vuu-table-types"; + +export const isVisualLinksAction = ( + action: GridAction +): action is DataSourceVisualLinksMessage => action.type === "vuu-links"; + +export const isVisualLinkCreatedAction = ( + action: GridAction +): action is DataSourceVisualLinkCreatedMessage => + action.type === "vuu-link-created"; + +export const isVisualLinkRemovedAction = ( + action: GridAction +): action is DataSourceVisualLinkRemovedMessage => + action.type === "vuu-link-removed"; + +export const isViewportMenusAction = ( + action: GridAction +): action is DataSourceMenusMessage => action.type === "vuu-menu"; + +export const isVuuFeatureAction = ( + action: GridAction +): action is VuuFeatureMessage => + isViewportMenusAction(action) || isVisualLinksAction(action); diff --git a/vuu-ui/packages/vuu-utils/src/datasource-utils.ts b/vuu-ui/packages/vuu-utils/src/datasource-utils.ts new file mode 100644 index 000000000..5cf1f9939 --- /dev/null +++ b/vuu-ui/packages/vuu-utils/src/datasource-utils.ts @@ -0,0 +1,257 @@ +import { + ConnectionQualityMetrics, + ConnectionStatusMessage, + DataSourceConfig, + MenuRpcResponse, + RpcResponse, + TypeaheadSuggestionProvider, + VuuUIMessageIn, + VuuUIMessageInRPC, + VuuUIMessageInRPCEditReject, + VuuUIMessageInRPCEditResponse, + VuuUIMessageInTableMeta, + VuuUIMessageOutViewport, + WithFilter, + WithFullConfig, + WithGroupBy, + WithSort, +} from "@finos/vuu-data-types"; +import { + LinkDescriptorWithLabel, + VuuFilter, + VuuSort, +} from "@finos/vuu-protocol-types"; + +export const NoFilter: VuuFilter = { filter: "" }; +export const NoSort: VuuSort = { sortDefs: [] }; + +export const vanillaConfig: WithFullConfig = { + aggregations: [], + columns: [], + filter: NoFilter, + groupBy: [], + sort: NoSort, +}; + +type DataConfigPredicate = ( + config: DataSourceConfig, + newConfig: DataSourceConfig +) => boolean; + +const equivalentAggregations: DataConfigPredicate = ( + { aggregations: agg1 }, + { aggregations: agg2 } +) => + (agg1 === undefined && agg2?.length === 0) || + (agg2 === undefined && agg1?.length === 0); + +const equivalentColumns: DataConfigPredicate = ( + { columns: cols1 }, + { columns: cols2 } +) => + (cols1 === undefined && cols2?.length === 0) || + (cols2 === undefined && cols1?.length === 0); + +const equivalentFilter: DataConfigPredicate = ( + { filter: f1 }, + { filter: f2 } +) => + (f1 === undefined && f2?.filter === "") || + (f2 === undefined && f1?.filter === ""); + +const equivalentGroupBy: DataConfigPredicate = ( + { groupBy: val1 }, + { groupBy: val2 } +) => + (val1 === undefined && val2?.length === 0) || + (val2 === undefined && val1?.length === 0); + +const equivalentSort: DataConfigPredicate = ({ sort: s1 }, { sort: s2 }) => + (s1 === undefined && s2?.sortDefs.length === 0) || + (s2 === undefined && s1?.sortDefs.length === 0); + +const exactlyTheSame = (a: unknown, b: unknown) => { + if (a === b) { + return true; + } else if (a === undefined && b === undefined) { + return true; + } else { + return false; + } +}; + +const aggregationsChanged: DataConfigPredicate = (config, newConfig) => { + const { aggregations: agg1 } = config; + const { aggregations: agg2 } = newConfig; + if (exactlyTheSame(agg1, agg2) || equivalentAggregations(config, newConfig)) { + return false; + } else if (agg1 === undefined || agg2 === undefined) { + return true; + } else if (agg1.length !== agg2.length) { + return true; + } + return agg1.some( + ({ column, aggType }, i) => + column !== agg2[i].column || aggType !== agg2[i].aggType + ); +}; + +export const columnsChanged: DataConfigPredicate = (config, newConfig) => { + const { columns: cols1 } = config; + const { columns: cols2 } = newConfig; + + if (exactlyTheSame(cols1, cols2) || equivalentColumns(config, newConfig)) { + return false; + } else if (cols1 === undefined || cols2 === undefined) { + return true; + } else if (cols1?.length !== cols2?.length) { + return true; + } + return cols1.some((column, i) => column !== cols2?.[i]); +}; + +export const filterChanged: DataConfigPredicate = (c1, c2) => { + if (equivalentFilter(c1, c2)) { + return false; + } else { + return c1.filter?.filter !== c2.filter?.filter; + } +}; + +export const groupByChanged: DataConfigPredicate = (config, newConfig) => { + const { groupBy: g1 } = config; + const { groupBy: g2 } = newConfig; + if (exactlyTheSame(g1, g2) || equivalentGroupBy(config, newConfig)) { + return false; + } else if (g1 === undefined || g2 === undefined) { + return true; + } else if (g1?.length !== g2?.length) { + return true; + } + return g1.some((column, i) => column !== g2?.[i]); +}; + +const sortChanged: DataConfigPredicate = (config, newConfig) => { + const { sort: s1 } = config; + const { sort: s2 } = newConfig; + if (exactlyTheSame(s1, s2) || equivalentSort(config, newConfig)) { + return false; + } else if (s1 === undefined || s2 === undefined) { + return true; + } else if (s1?.sortDefs.length !== s2?.sortDefs.length) { + return true; + } + return s1.sortDefs.some( + ({ column, sortType }, i) => + column !== s2.sortDefs[i].column || sortType !== s2.sortDefs[i].sortType + ); +}; + +const visualLinkChanged: DataConfigPredicate = () => { + // TODO + return false; +}; + +export const configChanged = ( + config: DataSourceConfig | undefined, + newConfig: DataSourceConfig | undefined +) => { + if (exactlyTheSame(config, newConfig)) { + return false; + } + + if (config === undefined || newConfig === undefined) { + return true; + } + + return ( + aggregationsChanged(config, newConfig) || + columnsChanged(config, newConfig) || + filterChanged(config, newConfig) || + groupByChanged(config, newConfig) || + sortChanged(config, newConfig) || + visualLinkChanged(config, newConfig) + ); +}; + +export const hasGroupBy = (config?: DataSourceConfig): config is WithGroupBy => + config !== undefined && + config.groupBy !== undefined && + config.groupBy.length > 0; + +export const hasFilter = (config?: DataSourceConfig): config is WithFilter => + config?.filter !== undefined && config.filter.filter.length > 0; + +export const hasSort = (config?: DataSourceConfig): config is WithSort => + config?.sort !== undefined && + Array.isArray(config.sort?.sortDefs) && + config.sort.sortDefs.length > 0; + +export const isTypeaheadSuggestionProvider = ( + source: unknown +): source is TypeaheadSuggestionProvider => + typeof (source as TypeaheadSuggestionProvider)["getTypeaheadSuggestions"] === + "function"; + +export const isTableSchema = ( + message: VuuUIMessageIn +): message is VuuUIMessageInTableMeta => message.type === "TABLE_META_RESP"; + +export const isConnectionStatusMessage = ( + msg: object | ConnectionStatusMessage +): msg is ConnectionStatusMessage => + (msg as ConnectionStatusMessage).type === "connection-status"; + +export const isConnectionQualityMetrics = ( + msg: object +): msg is ConnectionQualityMetrics => + (msg as ConnectionQualityMetrics).type === "connection-metrics"; + +export const messageHasResult = (msg: object): msg is VuuUIMessageInRPC => + typeof (msg as VuuUIMessageInRPC).result !== "undefined"; + +export const isErrorResponse = ( + response?: RpcResponse +): response is VuuUIMessageInRPCEditReject => + response !== undefined && "error" in response; + +export const hasAction = ( + response?: RpcResponse +): response is MenuRpcResponse | VuuUIMessageInRPCEditResponse => + response != undefined && "action" in response; + +export const isViewporttMessage = ( + msg: object +): msg is VuuUIMessageOutViewport => "viewport" in msg; + +export const withConfigDefaults = ( + config: DataSourceConfig +): WithFullConfig & { visualLink?: LinkDescriptorWithLabel } => { + if ( + config.aggregations && + config.columns && + config.filter && + config.groupBy && + config.sort + ) { + return config as WithFullConfig; + } else { + const { + aggregations = [], + columns = [], + filter = { filter: "" }, + groupBy = [], + sort = { sortDefs: [] }, + visualLink, + } = config; + + return { + aggregations, + columns, + filter, + groupBy, + sort, + visualLink, + }; + } +}; diff --git a/vuu-ui/packages/vuu-utils/src/date/formatter.ts b/vuu-ui/packages/vuu-utils/src/date/formatter.ts index 7228f1359..de6dbe7e9 100644 --- a/vuu-ui/packages/vuu-utils/src/date/formatter.ts +++ b/vuu-ui/packages/vuu-utils/src/date/formatter.ts @@ -67,7 +67,6 @@ export function formatDate(pattern: DateTimePattern): (d: Date) => string { return (d) => { const dateStr = dateTimeFormat.format(d); - console.log({ dateStr }); return postProcessor ? postProcessor(dateStr) : dateStr; }; } diff --git a/vuu-ui/packages/vuu-utils/src/event-emitter.ts b/vuu-ui/packages/vuu-utils/src/event-emitter.ts index 1cd4b6b3c..7b3a5176e 100644 --- a/vuu-ui/packages/vuu-utils/src/event-emitter.ts +++ b/vuu-ui/packages/vuu-utils/src/event-emitter.ts @@ -13,7 +13,17 @@ function isOnlyListener( return !Array.isArray(listeners); } -export class EventEmitter { +export interface IEventEmitter { + addListener(event: E, listener: Events[E]): void; + emit(event: E, ...args: Parameters): void; + on(event: E, listener: Events[E]): void; + removeListener(event: E, listener: Events[E]): void; + removeAllListeners(event?: E): void; +} + +export class EventEmitter + implements IEventEmitter +{ #events: Map = new Map(); addListener(event: E, listener: Events[E]) { diff --git a/vuu-ui/packages/vuu-utils/src/index.ts b/vuu-ui/packages/vuu-utils/src/index.ts index bd8193117..a41a84d61 100644 --- a/vuu-ui/packages/vuu-utils/src/index.ts +++ b/vuu-ui/packages/vuu-utils/src/index.ts @@ -6,6 +6,8 @@ export * from "./component-registry"; export * from "./DataWindow"; export * from "./common-types"; export * from "./data-utils"; +export * from "./datasource-action-utils"; +export * from "./datasource-utils"; export * from "./date"; export * from "./debug-utils"; export * from "./filter-utils"; @@ -30,5 +32,7 @@ export * from "./row-utils"; export * from "./selection-utils"; export * from "./sort-utils"; export * from "./text-utils"; +export * from "./ThemeProvider"; export * from "./url-utils"; -export * from "./screenshot-utils"; +export * from "./useId"; +export * from "./useLayoutEffectSkipFirst"; diff --git a/vuu-ui/packages/vuu-utils/src/row-utils.ts b/vuu-ui/packages/vuu-utils/src/row-utils.ts index e2762e073..74079eb97 100644 --- a/vuu-ui/packages/vuu-utils/src/row-utils.ts +++ b/vuu-ui/packages/vuu-utils/src/row-utils.ts @@ -1,6 +1,6 @@ import { DataSourceRow } from "@finos/vuu-data-types"; -import { metadataKeys } from "@finos/vuu-utils"; import { MutableRefObject } from "react"; +import { metadataKeys } from "./column-utils"; const { IDX } = metadataKeys; diff --git a/vuu-ui/packages/vuu-utils/src/selection-utils.ts b/vuu-ui/packages/vuu-utils/src/selection-utils.ts index 71c433546..7f0a70eb8 100644 --- a/vuu-ui/packages/vuu-utils/src/selection-utils.ts +++ b/vuu-ui/packages/vuu-utils/src/selection-utils.ts @@ -1,10 +1,10 @@ -import { DataSourceRow } from "@finos/vuu-data-types"; import { + DataSourceRow, RangeTuple, Selection, SelectionItem, - TableSelectionModel, -} from "@finos/vuu-table-types"; +} from "@finos/vuu-data-types"; +import { TableSelectionModel } from "@finos/vuu-table-types"; import { metadataKeys } from "./column-utils"; const NO_SELECTION: number[] = []; diff --git a/vuu-ui/packages/vuu-utils/src/useId.ts b/vuu-ui/packages/vuu-utils/src/useId.ts new file mode 100644 index 000000000..e930329aa --- /dev/null +++ b/vuu-ui/packages/vuu-utils/src/useId.ts @@ -0,0 +1,6 @@ +import { useMemo } from "react"; + +let vuuComponentIdCount = 0; + +export const useId = (id?: string) => + useMemo(() => id ?? `vuu-${++vuuComponentIdCount}`, [id]); diff --git a/vuu-ui/packages/vuu-utils/src/useLayoutEffectSkipFirst.ts b/vuu-ui/packages/vuu-utils/src/useLayoutEffectSkipFirst.ts new file mode 100644 index 000000000..eb7284f8b --- /dev/null +++ b/vuu-ui/packages/vuu-utils/src/useLayoutEffectSkipFirst.ts @@ -0,0 +1,16 @@ +import { DependencyList, EffectCallback, useLayoutEffect, useRef } from "react"; + +export const useLayoutEffectSkipFirst = ( + func: EffectCallback, + deps: DependencyList +) => { + const goodToGo = useRef(false); + useLayoutEffect(() => { + if (goodToGo.current) { + func(); + } else { + goodToGo.current = true; + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, deps); +}; diff --git a/vuu-ui/packages/vuu-utils/test/row-utils.test.ts b/vuu-ui/packages/vuu-utils/test/row-utils.test.ts index 848bae578..01c1a536c 100644 --- a/vuu-ui/packages/vuu-utils/test/row-utils.test.ts +++ b/vuu-ui/packages/vuu-utils/test/row-utils.test.ts @@ -1,4 +1,4 @@ -import { DataSourceRow } from "@finos/vuu-data"; +import { DataSourceRow } from "@finos/vuu-data-types"; import { describe, expect, it } from "vitest"; import { actualRowPositioning, virtualRowPositioning } from "../src/row-utils"; diff --git a/vuu-ui/sample-apps/app-vuu-example/demo.tsx b/vuu-ui/sample-apps/app-vuu-example/demo.tsx index f82aa7fc9..00bbff9cc 100644 --- a/vuu-ui/sample-apps/app-vuu-example/demo.tsx +++ b/vuu-ui/sample-apps/app-vuu-example/demo.tsx @@ -1,7 +1,7 @@ +import { LoginPanel } from "@finos/vuu-shell"; +import { ThemeProvider, uuid } from "@finos/vuu-utils"; import React from "react"; import ReactDOM from "react-dom"; -import { LoginPanel, ThemeProvider } from "@finos/vuu-shell"; -import { uuid } from "@finos/vuu-utils"; import "@finos/vuu-icons/index.css"; import "@finos/vuu-theme/index.css"; diff --git a/vuu-ui/sample-apps/app-vuu-example/login.tsx b/vuu-ui/sample-apps/app-vuu-example/login.tsx index 925da5457..e208f0a97 100644 --- a/vuu-ui/sample-apps/app-vuu-example/login.tsx +++ b/vuu-ui/sample-apps/app-vuu-example/login.tsx @@ -1,11 +1,11 @@ +import { authenticate } from "@finos/vuu-data-remote"; +import { LoginPanel } from "@finos/vuu-shell"; +import { ThemeProvider } from "@finos/vuu-utils"; import React from "react"; import ReactDOM from "react-dom"; -import { LoginPanel, ThemeProvider } from "@finos/vuu-shell"; -import { authenticate } from "@finos/vuu-data"; import "@finos/vuu-icons/index.css"; import "@finos/vuu-theme/index.css"; - import "./login.css"; async function login(username: string, password = "password") { diff --git a/vuu-ui/sample-apps/app-vuu-example/package.json b/vuu-ui/sample-apps/app-vuu-example/package.json index 0d95ab50b..a0781411f 100644 --- a/vuu-ui/sample-apps/app-vuu-example/package.json +++ b/vuu-ui/sample-apps/app-vuu-example/package.json @@ -17,7 +17,7 @@ "devDependencies": {}, "dependencies": { "@fontsource/open-sans": "^4.5.13", - "@salt-ds/core": "1.8.0", + "@salt-ds/core": "1.13.2", "@salt-ds/lab": "1.0.0-alpha.15", "@finos/vuu-data": "0.0.26", "@finos/vuu-table-types": "0.0.26", @@ -26,7 +26,7 @@ "@finos/vuu-popups": "0.0.26", "@finos/vuu-shell": "0.0.26", "@finos/vuu-utils": "0.0.26", - "classnames": "^2.3.1", + "clsx": "^2.0.0", "react": ">=17.0.2", "react-dom": ">=17.0.2" }, diff --git a/vuu-ui/sample-apps/app-vuu-example/src/session-editing/session-table-config.ts b/vuu-ui/sample-apps/app-vuu-example/src/session-editing/session-table-config.ts index 91dc3cb01..3d036a6e3 100644 --- a/vuu-ui/sample-apps/app-vuu-example/src/session-editing/session-table-config.ts +++ b/vuu-ui/sample-apps/app-vuu-example/src/session-editing/session-table-config.ts @@ -2,7 +2,7 @@ import { MenuRpcResponse, OpenDialogAction, TableSchema, -} from "@finos/vuu-data"; +} from "@finos/vuu-data-types"; import { FormConfig, FormFieldDescriptor } from "@finos/vuu-shell"; const static_config: { [key: string]: Partial } = { diff --git a/vuu-ui/sample-apps/app-vuu-example/src/useFeatures.ts b/vuu-ui/sample-apps/app-vuu-example/src/useFeatures.ts index 81fe3da34..9910d0662 100644 --- a/vuu-ui/sample-apps/app-vuu-example/src/useFeatures.ts +++ b/vuu-ui/sample-apps/app-vuu-example/src/useFeatures.ts @@ -1,4 +1,5 @@ import { useVuuTables } from "@finos/vuu-data-react"; +import { TableSchema } from "@finos/vuu-data-types"; import { FeatureProps, Features, @@ -6,7 +7,6 @@ import { isWildcardSchema, } from "@finos/vuu-shell"; import { wordify } from "@finos/vuu-utils"; -import { TableSchema } from "@finos/vuu-data"; import { useMemo } from "react"; export interface FeaturesHookProps { diff --git a/vuu-ui/sample-apps/app-vuu-example/src/useRpcResponseHandler.tsx b/vuu-ui/sample-apps/app-vuu-example/src/useRpcResponseHandler.tsx index 15b6292b0..11b147d7f 100644 --- a/vuu-ui/sample-apps/app-vuu-example/src/useRpcResponseHandler.tsx +++ b/vuu-ui/sample-apps/app-vuu-example/src/useRpcResponseHandler.tsx @@ -1,10 +1,11 @@ import { RpcResponseHandler, useVuuTables } from "@finos/vuu-data-react"; -import { hasAction, MenuRpcResponse, TableSchema } from "@finos/vuu-data"; +import { MenuRpcResponse, TableSchema } from "@finos/vuu-data-types"; +import { SetDialog } from "@finos/vuu-popups"; +import { VuuTable } from "@finos/vuu-protocol-types"; +import { Feature, SessionEditingForm } from "@finos/vuu-shell"; +import { hasAction } from "@finos/vuu-utils"; import { useCallback } from "react"; import { getFormConfig } from "./session-editing"; -import { Feature, SessionEditingForm } from "@finos/vuu-shell"; -import { VuuTable } from "@finos/vuu-protocol-types"; -import { SetDialog } from "@finos/vuu-popups"; const withTable = (action: unknown): action is { table: VuuTable } => action !== null && typeof action === "object" && "table" in action; diff --git a/vuu-ui/sample-apps/feature-basket-trading/package.json b/vuu-ui/sample-apps/feature-basket-trading/package.json index 1b9186a88..23f691808 100644 --- a/vuu-ui/sample-apps/feature-basket-trading/package.json +++ b/vuu-ui/sample-apps/feature-basket-trading/package.json @@ -14,26 +14,28 @@ "sideEffects": [ "**/*.css" ], - "devDependencies": {}, + "devDependencies": { + "@finos/vuu-data-types": "0.0.26", + "@finos/vuu-filter-types": "0.0.26", + "@finos/vuu-protocol-types": "0.0.26", + "@finos/vuu-table-types": "0.0.26" + }, "dependencies": { "@finos/vuu-data": "0.0.26", "@finos/vuu-data-react": "0.0.26", - "@finos/vuu-table-types": "0.0.26", "@finos/vuu-filters": "0.0.26", - "@finos/vuu-filter-types": "0.0.26", "@finos/vuu-layout": "0.0.26", "@finos/vuu-popups": "0.0.26", - "@finos/vuu-protocol-types": "0.0.26", "@finos/vuu-shell": "0.0.26", "@finos/vuu-table": "0.0.26", "@finos/vuu-table-extras": "0.0.26", "@finos/vuu-theme": "0.0.26", "@finos/vuu-utils": "0.0.26", - "@salt-ds/core": "1.8.0", + "@salt-ds/core": "1.13.2", "@salt-ds/lab": "1.0.0-alpha.15" }, "peerDependencies": { - "classnames": "^2.3.1", + "clsx": "^2.0.0", "react": ">=17.0.2", "react-dom": ">=17.0.2" }, diff --git a/vuu-ui/sample-apps/feature-basket-trading/src/VuuBasketTradingFeature.tsx b/vuu-ui/sample-apps/feature-basket-trading/src/VuuBasketTradingFeature.tsx index ae371c12a..64da74660 100644 --- a/vuu-ui/sample-apps/feature-basket-trading/src/VuuBasketTradingFeature.tsx +++ b/vuu-ui/sample-apps/feature-basket-trading/src/VuuBasketTradingFeature.tsx @@ -1,4 +1,4 @@ -import { TableSchema } from "@finos/vuu-data"; +import { TableSchema } from "@finos/vuu-data-types"; import { FlexboxLayout, Stack } from "@finos/vuu-layout"; import { BasketTableEdit } from "./basket-table-edit"; import { BasketTableLive } from "./basket-table-live"; diff --git a/vuu-ui/sample-apps/feature-basket-trading/src/basket-selector/BasketSelector.tsx b/vuu-ui/sample-apps/feature-basket-trading/src/basket-selector/BasketSelector.tsx index 7b23b2d50..8b1414b3b 100644 --- a/vuu-ui/sample-apps/feature-basket-trading/src/basket-selector/BasketSelector.tsx +++ b/vuu-ui/sample-apps/feature-basket-trading/src/basket-selector/BasketSelector.tsx @@ -1,13 +1,17 @@ -import { DropdownBase, PriceTicker } from "@finos/vuu-ui-controls"; +import { DataSource } from "@finos/vuu-data-types"; +import { + DropdownBase, + DropdownBaseProps, + InstrumentSearch, + PriceTicker, +} from "@finos/vuu-ui-controls"; +import { useId } from "@finos/vuu-utils"; import { Button } from "@salt-ds/core"; -import { DataSource } from "@finos/vuu-data"; -import { useId } from "@finos/vuu-layout"; -import { DropdownBaseProps, InstrumentSearch } from "@finos/vuu-ui-controls"; import { HTMLAttributes, useRef } from "react"; +import { Basket } from "../useBasketTrading"; import "./BasketSelector.css"; import { useBasketSelector } from "./useBasketSelector"; -import { Basket } from "../useBasketTrading"; const classBase = "vuuBasketSelector"; diff --git a/vuu-ui/sample-apps/feature-basket-trading/src/basket-selector/BasketSelectorRow.tsx b/vuu-ui/sample-apps/feature-basket-trading/src/basket-selector/BasketSelectorRow.tsx index 706d7ed0e..fa2cdf6cc 100644 --- a/vuu-ui/sample-apps/feature-basket-trading/src/basket-selector/BasketSelectorRow.tsx +++ b/vuu-ui/sample-apps/feature-basket-trading/src/basket-selector/BasketSelectorRow.tsx @@ -1,4 +1,4 @@ -import cx from "classnames"; +import cx from "clsx"; import { RowProps } from "@finos/vuu-table"; import { MouseEvent, useCallback } from "react"; diff --git a/vuu-ui/sample-apps/feature-basket-trading/src/basket-table-edit/BasketTableEdit.tsx b/vuu-ui/sample-apps/feature-basket-trading/src/basket-table-edit/BasketTableEdit.tsx index 0202d08bc..0f1348409 100644 --- a/vuu-ui/sample-apps/feature-basket-trading/src/basket-table-edit/BasketTableEdit.tsx +++ b/vuu-ui/sample-apps/feature-basket-trading/src/basket-table-edit/BasketTableEdit.tsx @@ -1,4 +1,4 @@ -import { TableSchema } from "@finos/vuu-data"; +import { TableSchema } from "@finos/vuu-data-types"; import { TableConfig } from "@finos/vuu-table-types"; import { Table, TableProps } from "@finos/vuu-table"; import { diff --git a/vuu-ui/sample-apps/feature-basket-trading/src/basket-table-live/BasketTableLive.tsx b/vuu-ui/sample-apps/feature-basket-trading/src/basket-table-live/BasketTableLive.tsx index e4f40c1c3..a81695a12 100644 --- a/vuu-ui/sample-apps/feature-basket-trading/src/basket-table-live/BasketTableLive.tsx +++ b/vuu-ui/sample-apps/feature-basket-trading/src/basket-table-live/BasketTableLive.tsx @@ -1,4 +1,4 @@ -import { TableSchema } from "@finos/vuu-data"; +import { TableSchema } from "@finos/vuu-data-types"; import { TableConfig } from "@finos/vuu-table-types"; import { Table, TableProps } from "@finos/vuu-table"; import { useMemo } from "react"; diff --git a/vuu-ui/sample-apps/feature-basket-trading/src/basket-toolbar/BasketMenu.tsx b/vuu-ui/sample-apps/feature-basket-trading/src/basket-toolbar/BasketMenu.tsx index a63ff956f..e229aa8c9 100644 --- a/vuu-ui/sample-apps/feature-basket-trading/src/basket-toolbar/BasketMenu.tsx +++ b/vuu-ui/sample-apps/feature-basket-trading/src/basket-toolbar/BasketMenu.tsx @@ -5,7 +5,7 @@ import { MenuBuilder, } from "@finos/vuu-data-types"; import { useMemo } from "react"; -import cx from "classnames"; +import cx from "clsx"; import "./BasketMenu.css"; diff --git a/vuu-ui/sample-apps/feature-basket-trading/src/basket-toolbar/BasketToolbar.tsx b/vuu-ui/sample-apps/feature-basket-trading/src/basket-toolbar/BasketToolbar.tsx index 2f0b4895b..d99ba5ddf 100644 --- a/vuu-ui/sample-apps/feature-basket-trading/src/basket-toolbar/BasketToolbar.tsx +++ b/vuu-ui/sample-apps/feature-basket-trading/src/basket-toolbar/BasketToolbar.tsx @@ -16,7 +16,7 @@ import { BasketSelector, BasketSelectorProps } from "../basket-selector"; import { Basket } from "../useBasketTrading"; import { BasketStatus } from "../VuuBasketTradingFeature"; import { BasketMenu } from "./BasketMenu"; -import cx from "classnames"; +import cx from "clsx"; import "./BasketToolbar.css"; diff --git a/vuu-ui/sample-apps/feature-basket-trading/src/cell-renderers/col-header-add-symbol/ColHeaderAddSymbol.tsx b/vuu-ui/sample-apps/feature-basket-trading/src/cell-renderers/col-header-add-symbol/ColHeaderAddSymbol.tsx index 98e122ddf..2369501c0 100644 --- a/vuu-ui/sample-apps/feature-basket-trading/src/cell-renderers/col-header-add-symbol/ColHeaderAddSymbol.tsx +++ b/vuu-ui/sample-apps/feature-basket-trading/src/cell-renderers/col-header-add-symbol/ColHeaderAddSymbol.tsx @@ -1,14 +1,31 @@ +import { + SetPropsAction, + useLayoutProviderDispatch, + useViewContext, +} from "@finos/vuu-layout"; import { registerComponent } from "@finos/vuu-utils"; import { Button } from "@salt-ds/core"; -import { SetPropsAction, useLayoutProviderDispatch } from "@finos/vuu-layout"; -import { MouseEventHandler, useCallback } from "react"; -import "./ColHeaderAddSymbol.css"; +import { DataSource } from "packages/vuu-data-types"; import { InstrumentSearchProps } from "packages/vuu-ui-controls/src"; +import { MouseEventHandler, useCallback, useMemo } from "react"; +import "./ColHeaderAddSymbol.css"; const classBase = "vuuColHeaderAddSymbol"; export const ColHeaderAddSymbol = () => { const dispatchLayoutAction = useLayoutProviderDispatch(); + const { loadSession } = useViewContext(); + + const dataSource = useMemo(() => { + const ds = loadSession?.("data-source-basket-constituent") as DataSource; + if (ds) { + return ds; + } else { + throw Error( + "ColHeaderAddSymbol expects Basket Constituent datasource to be available in session store" + ); + } + }, [loadSession]); const handleClick = useCallback( (e) => { @@ -25,14 +42,14 @@ export const ColHeaderAddSymbol = () => { allowDragDrop: "drag-copy", id: "basket-instruments", }, - table: { module: "BASKET", table: "basketConstituent" }, + dataSource, } as InstrumentSearchProps, }, title: "Add Ticker", }, } as SetPropsAction); }, - [dispatchLayoutAction] + [dataSource, dispatchLayoutAction] ); return ( @@ -45,6 +62,6 @@ export const ColHeaderAddSymbol = () => { registerComponent( "col-header-add-symbol", ColHeaderAddSymbol, - "cell-renderer", + "column-header-content-renderer", {} ); diff --git a/vuu-ui/sample-apps/feature-basket-trading/src/cell-renderers/progress-cell/ProgressCell.tsx b/vuu-ui/sample-apps/feature-basket-trading/src/cell-renderers/progress-cell/ProgressCell.tsx index 59752c338..89d73d899 100644 --- a/vuu-ui/sample-apps/feature-basket-trading/src/cell-renderers/progress-cell/ProgressCell.tsx +++ b/vuu-ui/sample-apps/feature-basket-trading/src/cell-renderers/progress-cell/ProgressCell.tsx @@ -5,7 +5,7 @@ import { isValidNumber, registerComponent, } from "@finos/vuu-utils"; -import cx from "classnames"; +import cx from "clsx"; import { CSSProperties } from "react"; import "./ProgressCell.css"; diff --git a/vuu-ui/sample-apps/feature-basket-trading/src/cell-renderers/status-cell/StatusCell.tsx b/vuu-ui/sample-apps/feature-basket-trading/src/cell-renderers/status-cell/StatusCell.tsx index e5c754296..ffabfa186 100644 --- a/vuu-ui/sample-apps/feature-basket-trading/src/cell-renderers/status-cell/StatusCell.tsx +++ b/vuu-ui/sample-apps/feature-basket-trading/src/cell-renderers/status-cell/StatusCell.tsx @@ -1,6 +1,6 @@ import { TableCellRendererProps } from "@finos/vuu-table-types"; import { registerComponent } from "@finos/vuu-utils"; -import cx from "classnames"; +import cx from "clsx"; import "./StatusCell.css"; diff --git a/vuu-ui/sample-apps/feature-basket-trading/src/new-basket-panel/NewBasketPanel.tsx b/vuu-ui/sample-apps/feature-basket-trading/src/new-basket-panel/NewBasketPanel.tsx index a205b28bd..1ed45b2da 100644 --- a/vuu-ui/sample-apps/feature-basket-trading/src/new-basket-panel/NewBasketPanel.tsx +++ b/vuu-ui/sample-apps/feature-basket-trading/src/new-basket-panel/NewBasketPanel.tsx @@ -1,4 +1,4 @@ -import { DataSource, TableSchema } from "@finos/vuu-data"; +import { DataSource, TableSchema } from "@finos/vuu-data-types"; import { DialogHeader, PopupComponent as Popup, @@ -10,7 +10,7 @@ import { VuuInput, } from "@finos/vuu-ui-controls"; import { Button, FormField, FormFieldLabel } from "@salt-ds/core"; -import cx from "classnames"; +import cx from "clsx"; import { DataSourceRow } from "@finos/vuu-data-types"; import { HTMLAttributes, RefCallback, useCallback, useMemo } from "react"; diff --git a/vuu-ui/sample-apps/feature-basket-trading/src/new-basket-panel/useNewBasketPanel.ts b/vuu-ui/sample-apps/feature-basket-trading/src/new-basket-panel/useNewBasketPanel.ts index 61178ca34..8ab08fe52 100644 --- a/vuu-ui/sample-apps/feature-basket-trading/src/new-basket-panel/useNewBasketPanel.ts +++ b/vuu-ui/sample-apps/feature-basket-trading/src/new-basket-panel/useNewBasketPanel.ts @@ -1,8 +1,3 @@ -import { - ClientToServerMenuRPC, - VuuMenu, - VuuMenuItem, -} from "@finos/vuu-protocol-types"; import { TableRowSelectHandler } from "@finos/vuu-table"; import { Commithandler, OpenChangeHandler } from "@finos/vuu-ui-controls"; import { buildColumnMap, metadataKeys } from "@finos/vuu-utils"; @@ -11,25 +6,6 @@ import { NewBasketPanelProps } from "./NewBasketPanel"; const { KEY } = metadataKeys; -type Menu = VuuMenu | VuuMenuItem; -const isMenu = (menu: Menu): menu is VuuMenu => "menus" in menu; -const flatten = (menus: Menu[], menuItems: VuuMenuItem[] = []) => { - menus.forEach((m) => - isMenu(m) ? flatten(m.menus, menuItems) : menuItems.push(m) - ); - return menuItems; -}; -const getRpcCommand = (menus: Menu[], selectRpcCommand?: string) => { - const selectionMenuItems = flatten(menus).filter( - (m) => m.context === "selected-rows" - ); - if (selectRpcCommand) { - return selectionMenuItems.find((m) => m.rpcName === selectRpcCommand); - } else if (selectionMenuItems.length === 1) { - return selectionMenuItems[0]; - } -}; - export type NewBasketHookProps = Pick< NewBasketPanelProps, "basketDataSource" | "basketSchema" | "onSaveBasket" @@ -44,32 +20,19 @@ export const useNewBasketPanel = ({ const [basketName, setBasketName] = useState(""); const [basketId, setBasketId] = useState(); const saveButtonRef = useRef(null); - const saveBasket = useCallback(() => { if (basketName && basketId) { onSaveBasket(basketName, basketId); - if (basketDataSource?.menu) { - const rpcCommand = getRpcCommand( - basketDataSource?.menu?.menus, - "CREATE_NEW_BASKET" - ); - if (rpcCommand) { - basketDataSource - .rpcCall?.({ - namedParams: {}, - params: [basketId, basketName], - rpcName: "createBasket", - type: "VIEW_PORT_RPC_CALL", - }) - .then((response) => { - console.log(`rpcResponse`, { response }); - }); - } - } else { - throw Error( - "useNewBasketPanel cannot create basket, datasource has no menu" - ); - } + basketDataSource + .rpcCall?.({ + namedParams: {}, + params: [basketId, basketName], + rpcName: "createBasket", + type: "VIEW_PORT_RPC_CALL", + }) + .then((response) => { + console.log(`rpcResponse`, { response }); + }); } }, [basketDataSource, basketId, basketName, onSaveBasket]); diff --git a/vuu-ui/sample-apps/feature-basket-trading/src/useBasketTrading.tsx b/vuu-ui/sample-apps/feature-basket-trading/src/useBasketTrading.tsx index e36dcccec..b85f72eba 100644 --- a/vuu-ui/sample-apps/feature-basket-trading/src/useBasketTrading.tsx +++ b/vuu-ui/sample-apps/feature-basket-trading/src/useBasketTrading.tsx @@ -1,20 +1,22 @@ import { useVuuMenuActions } from "@finos/vuu-data-react"; -import { DataSourceRow } from "@finos/vuu-data-types"; +import { + DataSourceRow, + SubscribeCallback, + ViewportRpcResponse, +} from "@finos/vuu-data-types"; import { useViewContext } from "@finos/vuu-layout"; -import { buildColumnMap, ColumnMap } from "@finos/vuu-utils"; import { ContextMenuConfiguration, NotificationLevel, useNotifications, } from "@finos/vuu-popups"; +import { buildColumnMap, ColumnMap } from "@finos/vuu-utils"; import { useCallback, useEffect, useMemo, useState } from "react"; import { BasketSelectorProps } from "./basket-selector"; import { BasketChangeHandler } from "./basket-toolbar"; import { NewBasketPanel } from "./new-basket-panel"; import { useBasketTradingDataSources } from "./useBasketTradingDatasources"; import { BasketTradingFeatureProps } from "./VuuBasketTradingFeature"; -import { VuuDataRow, VuuDataRowDto } from "packages/vuu-protocol-types"; -import { SubscribeCallback, ViewportRpcResponse } from "packages/vuu-data/src"; export class Basket { basketId: string; @@ -52,13 +54,6 @@ export type BasketTradingHookProps = Pick< | "basketTradingConstituentJoinSchema" >; -const toDataDto = (dataSourceRow: VuuDataRow, columnMap: ColumnMap) => { - Object.entries(columnMap).reduce((dto, [colName, index]) => { - dto[colName] = dataSourceRow[index]; - return dto; - }, {}); -}; - type BasketState = { basketInstanceId?: string; dialog?: JSX.Element; @@ -95,6 +90,7 @@ export const useBasketTrading = ({ } = useBasketTradingDataSources({ basketInstanceId, basketSchema, + basketConstituentSchema, basketTradingSchema, basketTradingConstituentJoinSchema, }); diff --git a/vuu-ui/sample-apps/feature-basket-trading/src/useBasketTradingDatasources.ts b/vuu-ui/sample-apps/feature-basket-trading/src/useBasketTradingDatasources.ts index b58a5c9f6..02a5ccf90 100644 --- a/vuu-ui/sample-apps/feature-basket-trading/src/useBasketTradingDatasources.ts +++ b/vuu-ui/sample-apps/feature-basket-trading/src/useBasketTradingDatasources.ts @@ -1,11 +1,11 @@ import { useViewContext } from "@finos/vuu-layout"; +import { VuuDataSource } from "@finos/vuu-data-remote"; import { DataSource, DataSourceConfig, - RemoteDataSource, TableSchema, ViewportRpcResponse, -} from "@finos/vuu-data"; +} from "@finos/vuu-data-types"; import { useCallback, useMemo } from "react"; import { BasketTradingFeatureProps } from "./VuuBasketTradingFeature"; import { NotificationLevel, useNotifications } from "@finos/vuu-popups"; @@ -14,16 +14,18 @@ export type basketDataSourceKey = | "data-source-basket" | "data-source-basket-trading-control" | "data-source-basket-trading-search" - | "data-source-basket-trading-constituent-join"; + | "data-source-basket-trading-constituent-join" + | "data-source-basket-constituent"; const NO_CONFIG = {}; export const useBasketTradingDataSources = ({ + basketConstituentSchema, basketSchema, basketInstanceId, basketTradingSchema, basketTradingConstituentJoinSchema, -}: Omit & { +}: BasketTradingFeatureProps & { basketInstanceId: string; }) => { const { notify } = useNotifications(); @@ -63,13 +65,14 @@ export const useBasketTradingDataSources = ({ 100, basketFilter, ], + ["data-source-basket-constituent", basketConstituentSchema, 100], ]; const dataSources: DataSource[] = []; for (const [key, schema, bufferSize, config] of dataSourceConfig) { - let dataSource = loadSession?.(key) as RemoteDataSource; + let dataSource = loadSession?.(key) as VuuDataSource; if (dataSource === undefined) { - dataSource = new RemoteDataSource({ + dataSource = new VuuDataSource({ ...config, bufferSize, viewport: `${id}-${key}`, @@ -83,10 +86,11 @@ export const useBasketTradingDataSources = ({ } return dataSources; }, [ + basketInstanceId, basketSchema, basketTradingSchema, - basketInstanceId, basketTradingConstituentJoinSchema, + basketConstituentSchema, loadSession, id, title, @@ -116,26 +120,32 @@ export const useBasketTradingDataSources = ({ [dataSourceBasketTradingControl, notify] ); - const handleTakeOffMarket = useCallback((basketInstanceId: string) => { - dataSourceBasketTradingControl - .rpcCall?.({ - namedParams: {}, - params: [basketInstanceId], - rpcName: "takeOffMarket", - type: "VIEW_PORT_RPC_CALL", - }) - .then((response) => { - if (response?.action.type === "VP_RCP_FAILURE") { - notify({ - type: NotificationLevel.Error, - header: "Failed to take off market", - body: "Please contact your support team", - }); - console.error(response.action.msg); - } - }); - }, []); + const handleTakeOffMarket = useCallback( + (basketInstanceId: string) => { + dataSourceBasketTradingControl + .rpcCall?.({ + namedParams: {}, + params: [basketInstanceId], + rpcName: "takeOffMarket", + type: "VIEW_PORT_RPC_CALL", + }) + .then((response) => { + if (response?.action.type === "VP_RCP_FAILURE") { + notify({ + type: NotificationLevel.Error, + header: "Failed to take off market", + body: "Please contact your support team", + }); + console.error(response.action.msg); + } + }); + }, + [dataSourceBasketTradingControl, notify] + ); + // Note: we do not need to return the BasketConstituent dataSource, we just stash it + // in session state from where it will be used by the AddInstrument button in Col + // Header return { dataSourceBasket, dataSourceBasketTradingControl, diff --git a/vuu-ui/sample-apps/feature-filter-table/package.json b/vuu-ui/sample-apps/feature-filter-table/package.json index fad2317e1..56e16a730 100644 --- a/vuu-ui/sample-apps/feature-filter-table/package.json +++ b/vuu-ui/sample-apps/feature-filter-table/package.json @@ -29,11 +29,11 @@ "@finos/vuu-table-extras": "0.0.26", "@finos/vuu-theme": "0.0.26", "@finos/vuu-utils": "0.0.26", - "@salt-ds/core": "1.8.0", + "@salt-ds/core": "1.13.2", "@salt-ds/lab": "1.0.0-alpha.15" }, "peerDependencies": { - "classnames": "^2.3.1", + "clsx": "^2.0.0", "react": ">=17.0.2", "react-dom": ">=17.0.2" }, diff --git a/vuu-ui/sample-apps/feature-filter-table/src/VuuFilterTableFeature.tsx b/vuu-ui/sample-apps/feature-filter-table/src/VuuFilterTableFeature.tsx index f3a600af2..d7364af1f 100644 --- a/vuu-ui/sample-apps/feature-filter-table/src/VuuFilterTableFeature.tsx +++ b/vuu-ui/sample-apps/feature-filter-table/src/VuuFilterTableFeature.tsx @@ -1,9 +1,9 @@ -import { TableSchema } from "@finos/vuu-data"; +import { TableSchema } from "@finos/vuu-data-types"; import { FilterTable } from "@finos/vuu-datatable"; import { FlexboxLayout } from "@finos/vuu-layout"; -import { DataSourceStats } from "@finos/vuu-table-extras"; -import cx from "classnames"; import { ContextMenuProvider } from "@finos/vuu-popups"; +import { DataSourceStats } from "@finos/vuu-table-extras"; +import cx from "clsx"; import { useFilterTable } from "./useFilterTable"; import "./VuuFilterTableFeature.css"; diff --git a/vuu-ui/sample-apps/feature-filter-table/src/useFilterTable.tsx b/vuu-ui/sample-apps/feature-filter-table/src/useFilterTable.tsx index 53940d3af..59bbc51b0 100644 --- a/vuu-ui/sample-apps/feature-filter-table/src/useFilterTable.tsx +++ b/vuu-ui/sample-apps/feature-filter-table/src/useFilterTable.tsx @@ -1,24 +1,29 @@ import { + MenuActionConfig, + SuggestionFetcher, + useVuuMenuActions, +} from "@finos/vuu-data-react"; +import { + DataSourceFilter, DataSourceVisualLinkCreatedMessage, - isTypeaheadSuggestionProvider, SchemaColumn, TypeaheadSuggestionProvider, VuuFeatureInvocationMessage, -} from "@finos/vuu-data"; -import { MenuActionConfig, useVuuMenuActions } from "@finos/vuu-data-react"; -import { DataSourceFilter } from "@finos/vuu-data-types"; -import { SuggestionFetcher } from "@finos/vuu-data-react"; -import { TableConfig } from "@finos/vuu-table-types"; +} from "@finos/vuu-data-types"; import { Filter } from "@finos/vuu-filter-types"; import { FilterBarProps } from "@finos/vuu-filters"; import { ActiveItemChangeHandler, useViewContext } from "@finos/vuu-layout"; import { useShellContext } from "@finos/vuu-shell"; -import { applyDefaultColumnConfig } from "@finos/vuu-utils"; +import { TableConfig } from "@finos/vuu-table-types"; +import { + applyDefaultColumnConfig, + isTypeaheadSuggestionProvider, +} from "@finos/vuu-utils"; import { Button } from "@salt-ds/core"; +import { TypeaheadParams } from "packages/vuu-protocol-types"; import { useCallback, useMemo, useRef, useState } from "react"; import { useSessionDataSource } from "./useSessionDataSource"; import { FilterTableFeatureProps } from "./VuuFilterTableFeature"; -import { TypeaheadParams } from "packages/vuu-protocol-types"; const NO_CONFIG: FilterTableConfig = {}; diff --git a/vuu-ui/sample-apps/feature-filter-table/src/useSessionDataSource.ts b/vuu-ui/sample-apps/feature-filter-table/src/useSessionDataSource.ts index 26a09cad9..232cc140b 100644 --- a/vuu-ui/sample-apps/feature-filter-table/src/useSessionDataSource.ts +++ b/vuu-ui/sample-apps/feature-filter-table/src/useSessionDataSource.ts @@ -1,10 +1,10 @@ +import { VuuDataSource } from "@finos/vuu-data-remote"; import { - configChanged, DataSource, DataSourceConfig, - RemoteDataSource, TableSchema, -} from "@finos/vuu-data"; +} from "@finos/vuu-data-types"; +import { configChanged } from "@finos/vuu-utils"; import { useViewContext } from "@finos/vuu-layout"; import { useCallback, useMemo } from "react"; @@ -15,8 +15,10 @@ type SessionDataSourceConfig = { const NO_CONFIG: SessionDataSourceConfig = {}; export const useSessionDataSource = ({ + dataSourceSessionKey = "data-source", tableSchema, }: { + dataSourceSessionKey?: string; tableSchema: TableSchema; }) => { const { id, load, save, loadSession, saveSession, title } = useViewContext(); @@ -38,10 +40,10 @@ export const useSessionDataSource = ({ ); const dataSource: DataSource = useMemo(() => { - let ds = loadSession?.("data-source") as RemoteDataSource; + let ds = loadSession?.(dataSourceSessionKey) as VuuDataSource; if (ds) { console.log( - "%cFilterTableFeature DATA SOURCE IN SESSION STATE", + "%useSessionDataSource DATA SOURCE IN SESSION STATE", "color:red;font-weight:bold;" ); @@ -65,7 +67,7 @@ export const useSessionDataSource = ({ dataSourceConfigFromState?.columns ?? tableSchema.columns.map((col) => col.name); - ds = new RemoteDataSource({ + ds = new VuuDataSource({ bufferSize: 0, // bufferSize: 200, viewport: id, diff --git a/vuu-ui/sample-apps/feature-instrument-tiles/package.json b/vuu-ui/sample-apps/feature-instrument-tiles/package.json index c310989c9..db92cc484 100644 --- a/vuu-ui/sample-apps/feature-instrument-tiles/package.json +++ b/vuu-ui/sample-apps/feature-instrument-tiles/package.json @@ -29,11 +29,11 @@ "@finos/vuu-table-extras": "0.0.26", "@finos/vuu-theme": "0.0.26", "@finos/vuu-utils": "0.0.26", - "@salt-ds/core": "1.8.0", + "@salt-ds/core": "1.13.2", "@salt-ds/lab": "1.0.0-alpha.15" }, "peerDependencies": { - "classnames": "^2.3.1", + "clsx": "^2.0.0", "react": ">=17.0.2", "react-dom": ">=17.0.2" }, diff --git a/vuu-ui/sample-apps/feature-instrument-tiles/src/VuuInstrumentTilesFeature.tsx b/vuu-ui/sample-apps/feature-instrument-tiles/src/VuuInstrumentTilesFeature.tsx index 4200e71fa..e552eb7fe 100644 --- a/vuu-ui/sample-apps/feature-instrument-tiles/src/VuuInstrumentTilesFeature.tsx +++ b/vuu-ui/sample-apps/feature-instrument-tiles/src/VuuInstrumentTilesFeature.tsx @@ -1,10 +1,10 @@ +import { VuuDataSource } from "@finos/vuu-data-remote"; import { DataSource, DataSourceConfig, - RemoteDataSource, + DataSourceFilter, TableSchema, -} from "@finos/vuu-data"; -import { DataSourceFilter } from "@finos/vuu-data-types"; +} from "@finos/vuu-data-types"; import { useViewContext } from "@finos/vuu-layout"; import { buildColumnMap, metadataKeys } from "@finos/vuu-utils"; import { useCallback, useEffect, useMemo } from "react"; @@ -56,13 +56,13 @@ const VuuInstrumentTilesFeature = ({ ); const dataSource: DataSource = useMemo(() => { - let ds = loadSession?.("data-source") as RemoteDataSource; + let ds = loadSession?.("data-source") as VuuDataSource; if (ds) { console.log({ ds }); return ds; } - ds = new RemoteDataSource({ + ds = new VuuDataSource({ bufferSize: 200, viewport: id, table: instrumentPricesSchema.table, diff --git a/vuu-ui/sample-apps/feature-instrument-tiles/src/useDataSource.ts b/vuu-ui/sample-apps/feature-instrument-tiles/src/useDataSource.ts index 4275b2a67..2d2d50aad 100644 --- a/vuu-ui/sample-apps/feature-instrument-tiles/src/useDataSource.ts +++ b/vuu-ui/sample-apps/feature-instrument-tiles/src/useDataSource.ts @@ -1,4 +1,4 @@ -import { DataSource, SubscribeCallback } from "@finos/vuu-data"; +import { DataSource, SubscribeCallback } from "@finos/vuu-data-types"; import { DataSourceRow } from "@finos/vuu-data-types"; import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { MovingWindow } from "./moving-window"; diff --git a/vuu-ui/sample-apps/feature-template/package.json b/vuu-ui/sample-apps/feature-template/package.json index 1c2775545..2dc04f0b8 100644 --- a/vuu-ui/sample-apps/feature-template/package.json +++ b/vuu-ui/sample-apps/feature-template/package.json @@ -29,11 +29,11 @@ "@finos/vuu-table-extras": "0.0.26", "@finos/vuu-theme": "0.0.26", "@finos/vuu-utils": "0.0.26", - "@salt-ds/core": "1.8.0", + "@salt-ds/core": "1.13.2", "@salt-ds/lab": "1.0.0-alpha.15" }, "peerDependencies": { - "classnames": "^2.3.1", + "clsx": "^2.0.0", "react": ">=17.0.2", "react-dom": ">=17.0.2" }, diff --git a/vuu-ui/sample-apps/feature-template/src/VuuTemplateFeature.tsx b/vuu-ui/sample-apps/feature-template/src/VuuTemplateFeature.tsx index 5cbc54377..6d1dfc368 100644 --- a/vuu-ui/sample-apps/feature-template/src/VuuTemplateFeature.tsx +++ b/vuu-ui/sample-apps/feature-template/src/VuuTemplateFeature.tsx @@ -1,9 +1,9 @@ +import { VuuDataSource } from "@finos/vuu-data-remote"; import { DataSource, DataSourceConfig, - RemoteDataSource, TableSchema, -} from "@finos/vuu-data"; +} from "@finos/vuu-data-types"; import { useViewContext } from "@finos/vuu-layout"; import { useCallback, useEffect, useMemo } from "react"; @@ -33,12 +33,12 @@ const VuuTemplateFeature = ({ tableSchema }: FilterTableFeatureProps) => { ); const dataSource: DataSource = useMemo(() => { - let ds = loadSession?.("data-source") as RemoteDataSource; + let ds = loadSession?.("data-source") as VuuDataSource; if (ds) { return ds; } - ds = new RemoteDataSource({ + ds = new VuuDataSource({ bufferSize: 200, viewport: id, table: tableSchema.table, diff --git a/vuu-ui/sample-apps/standalone-table/index.tsx b/vuu-ui/sample-apps/standalone-table/index.tsx new file mode 100644 index 000000000..449802cc1 --- /dev/null +++ b/vuu-ui/sample-apps/standalone-table/index.tsx @@ -0,0 +1,5 @@ +import React from "react"; +import ReactDOM from "react-dom"; +import { App } from "./src/App"; + +ReactDOM.render(, document.getElementById("root")); diff --git a/vuu-ui/sample-apps/standalone-table/package.json b/vuu-ui/sample-apps/standalone-table/package.json new file mode 100644 index 000000000..76ba47a41 --- /dev/null +++ b/vuu-ui/sample-apps/standalone-table/package.json @@ -0,0 +1,28 @@ +{ + "name": "standalone-table", + "version": "0.0.26", + "description": "", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "build": "node ./scripts/build.mjs", + "build:with-ag-grid": "node ./scripts/build.mjs --features feature-vuu-blotter,feature-ag-grid", + "start": "serve -p 5002 ../../deployed_apps/app-vuu-example" + }, + "keywords": [], + "author": "heswell", + "license": "Apache-2.0", + "sideEffects": [ + "**/*.css" + ], + "devDependencies": {}, + "dependencies": { + "@fontsource/open-sans": "^4.5.13", + "@finos/vuu-table": "0.0.26", + "clsx": "^2.0.0", + "react": ">=17.0.2", + "react-dom": ">=17.0.2" + }, + "engines": { + "node": ">=16.0.0" + } +} diff --git a/vuu-ui/sample-apps/standalone-table/public/index.html b/vuu-ui/sample-apps/standalone-table/public/index.html new file mode 100644 index 000000000..9951cfc38 --- /dev/null +++ b/vuu-ui/sample-apps/standalone-table/public/index.html @@ -0,0 +1,14 @@ + + + + + + + + VUU Table + + +
+ + + diff --git a/vuu-ui/sample-apps/standalone-table/scripts/.eslintrc.json b/vuu-ui/sample-apps/standalone-table/scripts/.eslintrc.json new file mode 100644 index 000000000..17388657e --- /dev/null +++ b/vuu-ui/sample-apps/standalone-table/scripts/.eslintrc.json @@ -0,0 +1,15 @@ +{ + "env": { + "node": true, + "es2021": true + }, + "extends": ["eslint:recommended", "plugin:react/recommended"], + "parserOptions": { + "ecmaFeatures": { + "jsx": true + }, + "ecmaVersion": "latest", + "sourceType": "module" + }, + "rules": {} +} diff --git a/vuu-ui/sample-apps/standalone-table/scripts/build.mjs b/vuu-ui/sample-apps/standalone-table/scripts/build.mjs new file mode 100644 index 000000000..c8513299d --- /dev/null +++ b/vuu-ui/sample-apps/standalone-table/scripts/build.mjs @@ -0,0 +1,107 @@ +import { + byFileName, + copyFolderSync, + formatBytes, + formatDuration, + getCommandLineArg, + padRight, + readPackageJson, + writeMetaFile, +} from "../../../scripts/utils.mjs"; +import { build } from "../../../scripts/esbuild.mjs"; +import fs from "fs"; +import path from "path"; + +const entryPoints = ["index.tsx"]; + +const outdir = "../../deployed_apps/standalone-table"; + +const watch = getCommandLineArg("--watch"); +const development = watch || getCommandLineArg("--dev"); + +const { name: projectName } = readPackageJson(); + +const esbuildConfig = { + entryPoints, + env: development ? "development" : "production", + name: "standalone-table", + outdir, + splitting: true, + target: "esnext", +}; + +async function main() { + function createDeployFolder() { + fs.rmSync(outdir, { recursive: true, force: true }); + fs.mkdirSync(outdir, { recursive: true }); + } + + console.log("[CLEAN]"); + createDeployFolder(); + + console.log("[BUILD]"); + const [ + { + result: { metafile }, + duration, + }, + ] = await Promise.all([build(esbuildConfig)]).catch((e) => { + console.error(e); + process.exit(1); + }); + + await writeMetaFile(metafile, outdir); + + console.log("[DEPLOY public assets]"); + const publicContent = fs.readdirSync(`./public`); + publicContent.forEach((file) => { + if (file !== ".DS_Store") { + if (typeof fs.cp === "function") { + // node v16.7 + + fs.cp( + path.resolve("public", file), + path.resolve(outdir, file), + { recursive: true }, + (err) => { + if (err) throw err; + } + ); + } else { + // delete once we no longer need to support node16 < .7 + copyFolderSync( + path.resolve("public", file), + path.resolve(outdir, file) + ); + } + } + }); + + const outputs = { + core: [], + common: [], + features: [], + }; + for (const [file, { bytes }] of Object.entries(metafile.outputs)) { + if (file.endsWith("js") || file.endsWith("css")) { + const fileName = file.replace(`${outdir}/`, ""); + if (fileName.startsWith(projectName)) { + outputs.core.push({ fileName, bytes }); + } else { + outputs.common.push({ fileName, bytes }); + } + } + } + + console.log("\ncore"); + outputs.core.sort(byFileName).forEach(({ fileName, bytes }) => { + console.log(`${padRight(fileName, 30)} ${formatBytes(bytes)}`); + }); + console.log("\ncommon"); + outputs.common.forEach(({ fileName, bytes }) => { + console.log(`${padRight(fileName, 30)} ${formatBytes(bytes)}`); + }); + + console.log(`\nbuild took ${formatDuration(duration)}`); +} + +main(); diff --git a/vuu-ui/sample-apps/standalone-table/src/App.css b/vuu-ui/sample-apps/standalone-table/src/App.css new file mode 100644 index 000000000..00137527b --- /dev/null +++ b/vuu-ui/sample-apps/standalone-table/src/App.css @@ -0,0 +1,8 @@ +body { + margin: 0; +} + +#root { + height: 100vh; + width: 100vw; +} \ No newline at end of file diff --git a/vuu-ui/sample-apps/standalone-table/src/App.tsx b/vuu-ui/sample-apps/standalone-table/src/App.tsx new file mode 100644 index 000000000..1fa399809 --- /dev/null +++ b/vuu-ui/sample-apps/standalone-table/src/App.tsx @@ -0,0 +1,37 @@ +import { Table } from "@finos/vuu-table"; +import { ArrayDataSource } from "@finos/vuu-data-local"; +import { getSchema, SimulTableName, vuuModule } from "@finos/vuu-data-test"; + +// import "@finos/vuu-icons/index.css"; +// import "@finos/vuu-theme/index.css"; + +import "./App.css"; +// import { ThemeProvider } from "packages/vuu-utils/src"; + +export const App = () => { + const columnDescriptors = [{ name: "Column 1" }, { name: "Column 2" }]; + // const dataSource = new ArrayDataSource({ + // columnDescriptors, + // data: [ + // ["test1", 1000], + // ["test2", 2000], + // ["test3", 3000], + // ["test4", 4000], + // ["test5", 5000], + // ["test6", 6000], + // ], + // }); + const schema = getSchema("instruments"); + const dataSource = + vuuModule("SIMUL").createDataSource("instruments"); + + const tableConfig = { + columns: schema.columns, + }; + + return ( + // + + // + ); +}; diff --git a/vuu-ui/sample-apps/standalone-table/src/table-custom.css b/vuu-ui/sample-apps/standalone-table/src/table-custom.css new file mode 100644 index 000000000..0f9053c52 --- /dev/null +++ b/vuu-ui/sample-apps/standalone-table/src/table-custom.css @@ -0,0 +1,3 @@ +.vuuTable { + +} \ No newline at end of file diff --git a/vuu-ui/sample-apps/standalone-table/tsconfig.json b/vuu-ui/sample-apps/standalone-table/tsconfig.json new file mode 100644 index 000000000..409f9488e --- /dev/null +++ b/vuu-ui/sample-apps/standalone-table/tsconfig.json @@ -0,0 +1,6 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "target": "esnext", + } +} diff --git a/vuu-ui/scripts/build-all.mjs b/vuu-ui/scripts/build-all.mjs index d13e2e983..059cf6c08 100644 --- a/vuu-ui/scripts/build-all.mjs +++ b/vuu-ui/scripts/build-all.mjs @@ -21,7 +21,7 @@ export const buildAll = async () => { "vuu-codemirror", "vuu-theme", ]; - const wave2 = ["vuu-data"]; + const wave2 = ["vuu-data-remote", "vuu-data-local"]; const wave3 = ["vuu-filters", "vuu-popups"]; const wave4 = [ "vuu-datatable", diff --git a/vuu-ui/scripts/esbuild.mjs b/vuu-ui/scripts/esbuild.mjs index 254020925..39ab88b92 100644 --- a/vuu-ui/scripts/esbuild.mjs +++ b/vuu-ui/scripts/esbuild.mjs @@ -18,7 +18,6 @@ export async function build(config) { target = ["es2020", "chrome79"], write = true, } = config; - return esbuild({ entryPoints, banner, diff --git a/vuu-ui/scripts/launch-table.mjs b/vuu-ui/scripts/launch-table.mjs new file mode 100644 index 000000000..2818a3f16 --- /dev/null +++ b/vuu-ui/scripts/launch-table.mjs @@ -0,0 +1,11 @@ +import { execWait } from "./utils.mjs"; + +export const launchApp = async () => { + const appName = "standalone-table"; + + execWait(`serve -p 3010 ./deployed_apps/${appName}`); + // await execWait("npm run --silent build"); + // await execWait(`npm run --silent build:${buildTarget}${url}`); +}; + +await launchApp(); diff --git a/vuu-ui/scripts/publish.mjs b/vuu-ui/scripts/publish.mjs index 61c7d1ce3..8357f2b90 100644 --- a/vuu-ui/scripts/publish.mjs +++ b/vuu-ui/scripts/publish.mjs @@ -4,7 +4,8 @@ const debug = getCommandLineArg("--debug"); const packages = [ "vuu-codemirror", - "vuu-data", + "vuu-data-local", + "vuu-data-remote", "vuu-data-ag-grid", "vuu-data-react", "vuu-data-test", diff --git a/vuu-ui/showcase/package.json b/vuu-ui/showcase/package.json index 24e81ce2d..47b49d21a 100644 --- a/vuu-ui/showcase/package.json +++ b/vuu-ui/showcase/package.json @@ -19,16 +19,13 @@ "@faker-js/faker": "^8.0.2", "@finos/vuu-data-test": "0.0.26", "@finos/vuu-data-ag-grid": "0.0.26", - "@finos/vuu-datagrid": "0.0.26", "@finos/vuu-filters": "0.0.26", "@finos/vuu-layout": "0.0.26", "@finos/vuu-theme": "0.0.26", "@finos/vuu-utils": "0.0.26", - "@salt-ds/core": "1.8.0", - "@salt-ds/icons": "1.5.1", - "@salt-ds/lab": "1.0.0-alpha.15", + "@salt-ds/core": "1.13.2", "@salt-ds/theme": "1.7.1", - "classnames": "^2.3.1", + "clsx": "^2.0.0", "react": ">=17.0.2", "react-dom": ">=17.0.2", "react-router-dom": "^6.2.1" diff --git a/vuu-ui/showcase/src/App.tsx b/vuu-ui/showcase/src/App.tsx index 890085558..950966163 100644 --- a/vuu-ui/showcase/src/App.tsx +++ b/vuu-ui/showcase/src/App.tsx @@ -1,17 +1,10 @@ import { Flexbox } from "@finos/vuu-layout"; -import { - Density, - DensitySwitch, - ThemeMode, - ThemeProvider, - ThemeSwitch, -} from "@finos/vuu-shell"; -import { Dropdown } from "@salt-ds/lab"; +import { Tree, TreeSourceNode } from "@finos/vuu-ui-controls"; +import { Density, ThemeMode, ThemeProvider } from "@finos/vuu-utils"; import { Button, Text } from "@salt-ds/core"; -import { IFrame } from "./components"; import { useCallback, useMemo, useState } from "react"; import { useLocation, useNavigate } from "react-router-dom"; -import { Tree, TreeSourceNode } from "@finos/vuu-ui-controls"; +import { IFrame } from "./components"; import "./App.css"; @@ -153,15 +146,6 @@ export const App = ({ stories }: AppProps) => { }} data-mode="light" > - - - -
diff --git a/vuu-ui/sample-apps/feature-basket-trading/src/basket-table-live/BasketTableLive.tsx b/vuu-ui/sample-apps/feature-basket-trading/src/basket-table-live/BasketTableLive.tsx index a81695a12..eeb1b3635 100644 --- a/vuu-ui/sample-apps/feature-basket-trading/src/basket-table-live/BasketTableLive.tsx +++ b/vuu-ui/sample-apps/feature-basket-trading/src/basket-table-live/BasketTableLive.tsx @@ -1,9 +1,5 @@ -import { TableSchema } from "@finos/vuu-data-types"; -import { TableConfig } from "@finos/vuu-table-types"; import { Table, TableProps } from "@finos/vuu-table"; -import { useMemo } from "react"; import { ProgressCell, SpreadCell, StatusCell } from "../cell-renderers"; -import columns from "./basketConstituentLiveColumns"; if ( typeof ProgressCell !== "function" || @@ -17,28 +13,12 @@ import "./BasketTableLive.css"; const classBase = "vuuBasketTableLive"; -export interface BasketTableLiveProps extends Omit { - tableSchema: TableSchema; -} - -export const BasketTableLive = ({ - tableSchema, - ...props -}: BasketTableLiveProps) => { - const tableConfig = useMemo( - () => ({ - columns, - rowSeparators: true, - }), - [] - ); - +export const BasketTableLive = ({ ...props }: TableProps) => { return (
); diff --git a/vuu-ui/sample-apps/feature-basket-trading/src/useBasketTrading.tsx b/vuu-ui/sample-apps/feature-basket-trading/src/useBasketTrading.tsx index fb4b269d0..c07dea64f 100644 --- a/vuu-ui/sample-apps/feature-basket-trading/src/useBasketTrading.tsx +++ b/vuu-ui/sample-apps/feature-basket-trading/src/useBasketTrading.tsx @@ -11,12 +11,15 @@ import { useNotifications, } from "@finos/vuu-popups"; import { buildColumnMap, ColumnMap } from "@finos/vuu-utils"; +import { TableConfig, TableConfigChangeHandler } from "@finos/vuu-table-types"; import { useCallback, useEffect, useMemo, useState } from "react"; import { BasketSelectorProps } from "./basket-selector"; import { BasketChangeHandler } from "./basket-toolbar"; import { NewBasketPanel } from "./new-basket-panel"; import { useBasketTradingDataSources } from "./useBasketTradingDatasources"; import { BasketTradingFeatureProps } from "./VuuBasketTradingFeature"; +import defaultEditColumns from "./basket-table-edit/basketConstituentEditColumns"; +import defaultLiveColumns from "./basket-table-live/basketConstituentLiveColumns"; export class Basket { basketId: string; @@ -70,6 +73,26 @@ export const useBasketTrading = ({ const { load, save } = useViewContext(); const { notify } = useNotifications(); + const editConfig = useMemo(() => { + const config = load?.("basket-edit-table-config") as TableConfig; + return ( + config ?? { + columns: defaultEditColumns, + rowSeparators: true, + } + ); + }, [load]); + + const liveConfig = useMemo(() => { + const config = load?.("basket-live-table-config") as TableConfig; + return ( + config ?? { + columns: defaultLiveColumns, + rowSeparators: true, + } + ); + }, [load]); + const basketConstituentMap = useMemo( () => buildColumnMap(basketConstituentSchema.columns), [basketConstituentSchema] @@ -144,12 +167,15 @@ export const useBasketTrading = ({ })); }, []); - const handleSaveNewBasket = useCallback((basketName, basketId) => { - setBasketState((state) => ({ - ...state, - dialog: undefined, - })); - }, []); + const handleSaveNewBasket = useCallback( + (/*basketName, basketId*/) => { + setBasketState((state) => ({ + ...state, + dialog: undefined, + })); + }, + [] + ); const handleSelectBasket = useCallback( (basketInstanceId: string) => { @@ -266,6 +292,27 @@ export const useBasketTrading = ({ [basketConstituentMap.ric, dataSourceBasketTradingConstituentJoin, notify] ); + // const handleTableConfigChange = useCallback( + // (config) => { + // save?.(config, "table-config"); + // }, + // [save] + // ); + + const handleConfigChangeEdit = useCallback( + (config) => { + save?.(config, "basket-edit-table-config"); + }, + [save] + ); + + const handleConfigChangeLive = useCallback( + (config) => { + save?.(config, "basket-live-table-config"); + }, + [save] + ); + useEffect(() => { dataSourceBasketTradingControl.resume?.(); return () => { @@ -280,8 +327,12 @@ export const useBasketTrading = ({ basketDesignContextMenuConfig, basketSelectorProps, dataSourceBasketTradingConstituentJoin, + editConfig, + liveConfig, onClickAddBasket: handleAddBasket, onCommitBasketChange: handleCommitBasketChange, + onConfigChangeEdit: handleConfigChangeEdit, + onConfigChangeLive: handleConfigChangeLive, onDropInstrument: handleDropInstrument, onSendToMarket, onTakeOffMarket, diff --git a/vuu-ui/sample-apps/feature-filter-table/src/useFilterTable.tsx b/vuu-ui/sample-apps/feature-filter-table/src/useFilterTable.tsx index 59bbc51b0..7ce8937d6 100644 --- a/vuu-ui/sample-apps/feature-filter-table/src/useFilterTable.tsx +++ b/vuu-ui/sample-apps/feature-filter-table/src/useFilterTable.tsx @@ -13,14 +13,14 @@ import { import { Filter } from "@finos/vuu-filter-types"; import { FilterBarProps } from "@finos/vuu-filters"; import { ActiveItemChangeHandler, useViewContext } from "@finos/vuu-layout"; +import { TypeaheadParams } from "@finos/vuu-protocol-types"; import { useShellContext } from "@finos/vuu-shell"; -import { TableConfig } from "@finos/vuu-table-types"; +import { TableConfig, TableConfigChangeHandler } from "@finos/vuu-table-types"; import { applyDefaultColumnConfig, isTypeaheadSuggestionProvider, } from "@finos/vuu-utils"; import { Button } from "@salt-ds/core"; -import { TypeaheadParams } from "packages/vuu-protocol-types"; import { useCallback, useMemo, useRef, useState } from "react"; import { useSessionDataSource } from "./useSessionDataSource"; import { FilterTableFeatureProps } from "./VuuFilterTableFeature"; @@ -108,8 +108,8 @@ export const useFilterTable = ({ tableSchema }: FilterTableFeatureProps) => { [save] ); - const handleTableConfigChange = useCallback( - (config: TableConfig) => { + const handleTableConfigChange = useCallback( + (config) => { save?.(config, "table-config"); }, [save] From 4e83c6c1aaae4a7096a623232ef20b1bbd38aeab Mon Sep 17 00:00:00 2001 From: heswell Date: Wed, 3 Jan 2024 16:41:01 +0000 Subject: [PATCH 25/38] tidy up relative path urls in import statements (#1098) --- .../vuu-data-remote/src/inlined-worker.js | 2463 +---------------- .../src/basket/reference-data/constituents.ts | 2 +- .../src/layout-reducer/layoutTypes.ts | 2 +- vuu-ui/packages/vuu-shell/src/shellTypes.ts | 4 +- .../BackgroundCellConfigurationEditor.tsx | 2 +- vuu-ui/packages/vuu-table/src/Table.tsx | 2 +- .../src/cell-renderers/cell-utils.ts | 2 +- .../packages/vuu-table/src/useDataSource.ts | 2 +- vuu-ui/packages/vuu-table/src/useSelection.ts | 2 +- .../cycle-state-button/CycleStateButton.tsx | 6 +- .../vuu-ui-controls/src/drag-drop/index.ts | 2 + .../basketConstituentEditColumns.ts | 2 +- .../basketConstituentLiveColumns.ts | 2 +- .../src/basket-toolbar/BasketToolbar.tsx | 8 +- .../ColHeaderAddSymbol.tsx | 5 +- .../sample-apps/standalone-table/src/App.tsx | 2 +- vuu-ui/scripts/build-all-type-defs.mjs | 16 +- .../DataTable/FilterTable.examples.tsx | 16 +- .../Filters/FilterBar/FilterBar.examples.tsx | 6 +- .../examples/ShowcaseControls/Tree.data.ts | 2 +- .../UiControls/InstrumentPicker.examples.tsx | 8 +- .../UiControls/InstrumentSearch.examples.tsx | 4 +- .../FilterTableFeature.examples.tsx | 2 +- vuu-ui/tsconfig.json | 2 +- 24 files changed, 56 insertions(+), 2508 deletions(-) diff --git a/vuu-ui/packages/vuu-data-remote/src/inlined-worker.js b/vuu-ui/packages/vuu-data-remote/src/inlined-worker.js index 7b138e587..5c8428f16 100644 --- a/vuu-ui/packages/vuu-data-remote/src/inlined-worker.js +++ b/vuu-ui/packages/vuu-data-remote/src/inlined-worker.js @@ -1,2465 +1,8 @@ export const workerSourceCode = ` -var __accessCheck = (obj, member, msg) => { - if (!member.has(obj)) - throw TypeError("Cannot " + msg); -}; -var __privateGet = (obj, member, getter) => { - __accessCheck(obj, member, "read from private field"); - return getter ? getter.call(obj) : member.get(obj); -}; -var __privateAdd = (obj, member, value) => { - if (member.has(obj)) - throw TypeError("Cannot add the same private member more than once"); - member instanceof WeakSet ? member.add(obj) : member.set(obj, value); -}; -var __privateSet = (obj, member, value, setter) => { - __accessCheck(obj, member, "write to private field"); - setter ? setter.call(obj, value) : member.set(obj, value); - return value; -}; - -// ../vuu-utils/src/array-utils.ts -function partition(array, test, pass = [], fail = []) { - for (let i = 0, len = array.length; i < len; i++) { - (test(array[i], i) ? pass : fail).push(array[i]); - } - return [pass, fail]; -} - -// ../vuu-utils/src/column-utils.ts -var metadataKeys = { - IDX: 0, - RENDER_IDX: 1, - IS_LEAF: 2, - IS_EXPANDED: 3, - DEPTH: 4, - COUNT: 5, - KEY: 6, - SELECTED: 7, - count: 8, - // TODO following only used in datamodel - PARENT_IDX: "parent_idx", - IDX_POINTER: "idx_pointer", - FILTER_COUNT: "filter_count", - NEXT_FILTER_IDX: "next_filter_idx" -}; -var { DEPTH, IS_LEAF } = metadataKeys; - -// ../vuu-utils/src/cookie-utils.ts -var getCookieValue = (name) => { - var _a, _b; - if (((_a = globalThis.document) == null ? void 0 : _a.cookie) !== void 0) { - return (_b = globalThis.document.cookie.split("; ").find((row) => row.startsWith(\`\${name}=\`))) == null ? void 0 : _b.split("=")[1]; - } -}; - -// ../vuu-utils/src/range-utils.ts -function getFullRange({ from, to }, bufferSize = 0, rowCount = Number.MAX_SAFE_INTEGER) { - if (bufferSize === 0) { - if (rowCount < from) { - return { from: 0, to: 0 }; - } else { - return { from, to: Math.min(to, rowCount) }; - } - } else if (from === 0) { - return { from, to: Math.min(to + bufferSize, rowCount) }; - } else { - const rangeSize = to - from; - const buff = Math.round(bufferSize / 2); - const shortfallBefore = from - buff < 0; - const shortFallAfter = rowCount - (to + buff) < 0; - if (shortfallBefore && shortFallAfter) { - return { from: 0, to: rowCount }; - } else if (shortfallBefore) { - return { from: 0, to: rangeSize + bufferSize }; - } else if (shortFallAfter) { - return { - from: Math.max(0, rowCount - (rangeSize + bufferSize)), - to: rowCount - }; - } else { - return { from: from - buff, to: to + buff }; - } - } -} -var withinRange = (value, { from, to }) => value >= from && value < to; -var WindowRange = class _WindowRange { - constructor(from, to) { - this.from = from; - this.to = to; - } - isWithin(index) { - return withinRange(index, this); - } - //find the overlap of this range and a new one - overlap(from, to) { - return from >= this.to || to < this.from ? [0, 0] : [Math.max(from, this.from), Math.min(to, this.to)]; - } - copy() { - return new _WindowRange(this.from, this.to); - } -}; - -// ../vuu-utils/src/datasource-utils.ts -var isConnectionStatusMessage = (msg) => msg.type === "connection-status"; -var isConnectionQualityMetrics = (msg) => msg.type === "connection-metrics"; -var isViewporttMessage = (msg) => "viewport" in msg; - -// ../vuu-utils/src/logging-utils.ts -var logLevels = ["error", "warn", "info", "debug"]; -var isValidLogLevel = (value) => typeof value === "string" && logLevels.includes(value); -var DEFAULT_LOG_LEVEL = "error"; -var NO_OP = () => void 0; -var DEFAULT_DEBUG_LEVEL = false ? "error" : "info"; -var { loggingLevel = DEFAULT_DEBUG_LEVEL } = getLoggingSettings(); -var logger = (category) => { - const debugEnabled5 = loggingLevel === "debug"; - const infoEnabled5 = debugEnabled5 || loggingLevel === "info"; - const warnEnabled = infoEnabled5 || loggingLevel === "warn"; - const errorEnabled = warnEnabled || loggingLevel === "error"; - const info5 = infoEnabled5 ? (message) => console.info(\`[\${category}] \${message}\`) : NO_OP; - const warn4 = warnEnabled ? (message) => console.warn(\`[\${category}] \${message}\`) : NO_OP; - const debug5 = debugEnabled5 ? (message) => console.debug(\`[\${category}] \${message}\`) : NO_OP; - const error4 = errorEnabled ? (message) => console.error(\`[\${category}] \${message}\`) : NO_OP; - if (false) { - return { - errorEnabled, - error: error4 - }; - } else { - return { - debugEnabled: debugEnabled5, - infoEnabled: infoEnabled5, - warnEnabled, - errorEnabled, - info: info5, - warn: warn4, - debug: debug5, - error: error4 - }; - } -}; -function getLoggingSettings() { - if (typeof loggingSettings !== "undefined") { - return loggingSettings; - } else { - return { - loggingLevel: getLoggingLevelFromCookie() - }; - } -} -function getLoggingLevelFromCookie() { - const value = getCookieValue("vuu-logging-level"); - if (isValidLogLevel(value)) { - return value; - } else { - return DEFAULT_LOG_LEVEL; - } -} - -// ../vuu-utils/src/debug-utils.ts -var { debug, debugEnabled } = logger("range-monitor"); -var RangeMonitor = class { - constructor(source) { - this.source = source; - this.range = { from: 0, to: 0 }; - this.timestamp = 0; - } - isSet() { - return this.timestamp !== 0; - } - set({ from, to }) { - const { timestamp } = this; - this.range.from = from; - this.range.to = to; - this.timestamp = performance.now(); - if (timestamp) { - debugEnabled && debug( - \`<\${this.source}> [\${from}-\${to}], \${(this.timestamp - timestamp).toFixed(0)} ms elapsed\` - ); - } else { - return 0; - } - } -}; - -// ../vuu-utils/src/keyset.ts -var KeySet = class { - constructor(range) { - this.keys = /* @__PURE__ */ new Map(); - this.free = []; - this.nextKeyValue = 0; - this.reset(range); - } - next() { - if (this.free.length > 0) { - return this.free.pop(); - } else { - return this.nextKeyValue++; - } - } - reset({ from, to }) { - this.keys.forEach((keyValue, rowIndex) => { - if (rowIndex < from || rowIndex >= to) { - this.free.push(keyValue); - this.keys.delete(rowIndex); - } - }); - const size = to - from; - if (this.keys.size + this.free.length > size) { - this.free.length = Math.max(0, size - this.keys.size); - } - for (let rowIndex = from; rowIndex < to; rowIndex++) { - if (!this.keys.has(rowIndex)) { - const nextKeyValue = this.next(); - this.keys.set(rowIndex, nextKeyValue); - } - } - if (this.nextKeyValue > this.keys.size) { - this.nextKeyValue = this.keys.size; - } - } - keyFor(rowIndex) { - const key = this.keys.get(rowIndex); - if (key === void 0) { - console.log(\`key not found +var ie=(r,e,t)=>{if(!e.has(r))throw TypeError("Cannot "+t)};var m=(r,e,t)=>(ie(r,e,"read from private field"),t?t.call(r):e.get(r)),ae=(r,e,t)=>{if(e.has(r))throw TypeError("Cannot add the same private member more than once");e instanceof WeakSet?e.add(r):e.set(r,t)},ue=(r,e,t,s)=>(ie(r,e,"write to private field"),s?s.call(r,t):e.set(r,t),t);function le(r,e,t=[],s=[]){for(let n=0,o=r.length;n{var e,t;if(((e=globalThis.document)==null?void 0:e.cookie)!==void 0)return(t=globalThis.document.cookie.split("; ").find(s=>s.startsWith(\`\${r}=\`)))==null?void 0:t.split("=")[1]};function G({from:r,to:e},t=0,s=Number.MAX_SAFE_INTEGER){if(t===0)return sr>=e&&r=this.to||tr.type==="connection-status",de=r=>r.type==="connection-metrics";var ge=r=>"viewport"in r;var Qe=["error","warn","info","debug"],Ye=r=>typeof r=="string"&&Qe.includes(r),Ze="error",P=()=>{},Xe="error",{loggingLevel:L=Xe}=et(),b=r=>{let e=L==="debug",t=e||L==="info",s=t||L==="warn",n=s||L==="error",o=t?p=>console.info(\`[\${r}] \${p}\`):P,i=s?p=>console.warn(\`[\${r}] \${p}\`):P,u=e?p=>console.debug(\`[\${r}] \${p}\`):P;return{errorEnabled:n,error:n?p=>console.error(\`[\${r}] \${p}\`):P}};function et(){return typeof loggingSettings<"u"?loggingSettings:{loggingLevel:tt()}}function tt(){let r=ce("vuu-logging-level");return Ye(r)?r:Ze}var{debug:st,debugEnabled:nt}=b("range-monitor"),k=class{constructor(e){this.source=e;this.range={from:0,to:0};this.timestamp=0}isSet(){return this.timestamp!==0}set({from:e,to:t}){let{timestamp:s}=this;if(this.range.from=e,this.range.to=t,this.timestamp=performance.now(),s)nt&&st(\`<\${this.source}> [\${e}-\${t}], \${(this.timestamp-s).toFixed(0)} ms elapsed\`);else return 0}};var O=class{constructor(e){this.keys=new Map,this.free=[],this.nextKeyValue=0,this.reset(e)}next(){return this.free.length>0?this.free.pop():this.nextKeyValue++}reset({from:e,to:t}){this.keys.forEach((n,o)=>{(o=t)&&(this.free.push(n),this.keys.delete(o))});let s=t-e;this.keys.size+this.free.length>s&&(this.free.length=Math.max(0,s-this.keys.size));for(let n=e;nthis.keys.size&&(this.nextKeyValue=this.keys.size)}keyFor(e){let t=this.keys.get(e);if(t===void 0)throw console.log(\`key not found keys: \${this.toDebugString()} free : \${this.free.join(",")} - \`); - throw Error(\`KeySet, no key found for rowIndex \${rowIndex}\`); - } - return key; - } - toDebugString() { - return Array.from(this.keys.entries()).map((k, v) => \`\${k}=>\${v}\`).join(","); - } -}; - -// ../vuu-utils/src/selection-utils.ts -var { SELECTED } = metadataKeys; -var RowSelected = { - False: 0, - True: 1, - First: 2, - Last: 4 -}; -var rangeIncludes = (range, index) => index >= range[0] && index <= range[1]; -var SINGLE_SELECTED_ROW = RowSelected.True + RowSelected.First + RowSelected.Last; -var FIRST_SELECTED_ROW_OF_BLOCK = RowSelected.True + RowSelected.First; -var LAST_SELECTED_ROW_OF_BLOCK = RowSelected.True + RowSelected.Last; -var getSelectionStatus = (selected, itemIndex) => { - for (const item of selected) { - if (typeof item === "number") { - if (item === itemIndex) { - return SINGLE_SELECTED_ROW; - } - } else if (rangeIncludes(item, itemIndex)) { - if (itemIndex === item[0]) { - return FIRST_SELECTED_ROW_OF_BLOCK; - } else if (itemIndex === item[1]) { - return LAST_SELECTED_ROW_OF_BLOCK; - } else { - return RowSelected.True; - } - } - } - return RowSelected.False; -}; -var expandSelection = (selected) => { - if (selected.every((selectedItem) => typeof selectedItem === "number")) { - return selected; - } - const expandedSelected = []; - for (const selectedItem of selected) { - if (typeof selectedItem === "number") { - expandedSelected.push(selectedItem); - } else { - for (let i = selectedItem[0]; i <= selectedItem[1]; i++) { - expandedSelected.push(i); - } - } - } - return expandedSelected; -}; - -// src/data-source.ts -var isSessionTableActionMessage = (messageBody) => messageBody.type === "VIEW_PORT_MENU_RESP" && messageBody.action !== null && isSessionTable(messageBody.action.table); -var isSessionTable = (table) => { - if (table !== null && typeof table === "object" && "table" in table && "module" in table) { - return table.table.startsWith("session"); - } - return false; -}; - -// src/message-utils.ts -var MENU_RPC_TYPES = [ - "VIEW_PORT_MENUS_SELECT_RPC", - "VIEW_PORT_MENU_TABLE_RPC", - "VIEW_PORT_MENU_ROW_RPC", - "VIEW_PORT_MENU_CELL_RPC", - "VP_EDIT_CELL_RPC", - "VP_EDIT_ROW_RPC", - "VP_EDIT_ADD_ROW_RPC", - "VP_EDIT_DELETE_CELL_RPC", - "VP_EDIT_DELETE_ROW_RPC", - "VP_EDIT_SUBMIT_FORM_RPC" -]; -var isVuuMenuRpcRequest = (message) => MENU_RPC_TYPES.includes(message["type"]); -var isVuuRpcRequest = (message) => message["type"] === "VIEW_PORT_RPC_CALL"; -var stripRequestId = ({ - requestId, - ...rest -}) => [requestId, rest]; -var getFirstAndLastRows = (rows) => { - let firstRow = rows.at(0); - if (firstRow.updateType === "SIZE") { - if (rows.length === 1) { - return rows; - } else { - firstRow = rows.at(1); - } - } - const lastRow = rows.at(-1); - return [firstRow, lastRow]; -}; -var groupRowsByViewport = (rows) => { - const result = {}; - for (const row of rows) { - const rowsForViewport = result[row.viewPortId] || (result[row.viewPortId] = []); - rowsForViewport.push(row); - } - return result; -}; -var createSchemaFromTableMetadata = ({ - columns, - dataTypes, - key, - table -}) => { - return { - table, - columns: columns.map((col, idx) => ({ - name: col, - serverDataType: dataTypes[idx] - })), - key - }; -}; - -// src/server-proxy/messages.ts -var CHANGE_VP_SUCCESS = "CHANGE_VP_SUCCESS"; -var CLOSE_TREE_NODE = "CLOSE_TREE_NODE"; -var CLOSE_TREE_SUCCESS = "CLOSE_TREE_SUCCESS"; -var CREATE_VP = "CREATE_VP"; -var DISABLE_VP = "DISABLE_VP"; -var DISABLE_VP_SUCCESS = "DISABLE_VP_SUCCESS"; -var ENABLE_VP = "ENABLE_VP"; -var ENABLE_VP_SUCCESS = "ENABLE_VP_SUCCESS"; -var GET_VP_VISUAL_LINKS = "GET_VP_VISUAL_LINKS"; -var GET_VIEW_PORT_MENUS = "GET_VIEW_PORT_MENUS"; -var HB = "HB"; -var HB_RESP = "HB_RESP"; -var LOGIN = "LOGIN"; -var OPEN_TREE_NODE = "OPEN_TREE_NODE"; -var OPEN_TREE_SUCCESS = "OPEN_TREE_SUCCESS"; -var REMOVE_VP = "REMOVE_VP"; -var SET_SELECTION_SUCCESS = "SET_SELECTION_SUCCESS"; - -// src/server-proxy/rpc-services.ts -var getRpcServiceModule = (service) => { - switch (service) { - case "TypeAheadRpcHandler": - return "TYPEAHEAD"; - default: - return "SIMUL"; - } -}; - -// src/server-proxy/array-backed-moving-window.ts -var EMPTY_ARRAY = []; -var log = logger("array-backed-moving-window"); -function dataIsUnchanged(newRow, existingRow) { - if (!existingRow) { - return false; - } - if (existingRow.data.length !== newRow.data.length) { - return false; - } - if (existingRow.sel !== newRow.sel) { - return false; - } - for (let i = 0; i < existingRow.data.length; i++) { - if (existingRow.data[i] !== newRow.data[i]) { - return false; - } - } - return true; -} -var _range; -var ArrayBackedMovingWindow = class { - // Note, the buffer is already accounted for in the range passed in here - constructor({ from: clientFrom, to: clientTo }, { from, to }, bufferSize) { - __privateAdd(this, _range, void 0); - this.setRowCount = (rowCount) => { - var _a; - (_a = log.info) == null ? void 0 : _a.call(log, \`setRowCount \${rowCount}\`); - if (rowCount < this.internalData.length) { - this.internalData.length = rowCount; - } - if (rowCount < this.rowCount) { - this.rowsWithinRange = 0; - const end = Math.min(rowCount, this.clientRange.to); - for (let i = this.clientRange.from; i < end; i++) { - const rowIndex = i - __privateGet(this, _range).from; - if (this.internalData[rowIndex] !== void 0) { - this.rowsWithinRange += 1; - } - } - } - this.rowCount = rowCount; - }; - this.bufferBreakout = (from, to) => { - const bufferPerimeter = this.bufferSize * 0.25; - if (__privateGet(this, _range).to - to < bufferPerimeter) { - return true; - } else if (__privateGet(this, _range).from > 0 && from - __privateGet(this, _range).from < bufferPerimeter) { - return true; - } else { - return false; - } - }; - this.bufferSize = bufferSize; - this.clientRange = new WindowRange(clientFrom, clientTo); - __privateSet(this, _range, new WindowRange(from, to)); - this.internalData = new Array(bufferSize); - this.rowsWithinRange = 0; - this.rowCount = 0; - } - get range() { - return __privateGet(this, _range); - } - // TODO we shpuld probably have a hasAllClientRowsWithinRange - get hasAllRowsWithinRange() { - return this.rowsWithinRange === this.clientRange.to - this.clientRange.from || // this.rowsWithinRange === this.range.to - this.range.from || - this.rowCount > 0 && this.clientRange.from + this.rowsWithinRange === this.rowCount; - } - // Check to see if set of rows is outside the current viewport range, indicating - // that veiwport is being scrolled quickly and server is not able to keep up. - outOfRange(firstIndex, lastIndex) { - const { from, to } = this.range; - if (lastIndex < from) { - return true; - } - if (firstIndex >= to) { - return true; - } - } - setAtIndex(row) { - const { rowIndex: index } = row; - const internalIndex = index - __privateGet(this, _range).from; - if (dataIsUnchanged(row, this.internalData[internalIndex])) { - return false; - } - const isWithinClientRange = this.isWithinClientRange(index); - if (isWithinClientRange || this.isWithinRange(index)) { - if (!this.internalData[internalIndex] && isWithinClientRange) { - this.rowsWithinRange += 1; - } - this.internalData[internalIndex] = row; - } - return isWithinClientRange; - } - getAtIndex(index) { - return __privateGet(this, _range).isWithin(index) && this.internalData[index - __privateGet(this, _range).from] != null ? this.internalData[index - __privateGet(this, _range).from] : void 0; - } - isWithinRange(index) { - return __privateGet(this, _range).isWithin(index); - } - isWithinClientRange(index) { - return this.clientRange.isWithin(index); - } - // Returns [false] or [serverDataRequired, clientRows, holdingRows] - setClientRange(from, to) { - var _a; - (_a = log.debug) == null ? void 0 : _a.call(log, \`setClientRange \${from} - \${to}\`); - const currentFrom = this.clientRange.from; - const currentTo = Math.min(this.clientRange.to, this.rowCount); - if (from === currentFrom && to === currentTo) { - return [ - false, - EMPTY_ARRAY - /*, EMPTY_ARRAY*/ - ]; - } - const originalRange = this.clientRange.copy(); - this.clientRange.from = from; - this.clientRange.to = to; - this.rowsWithinRange = 0; - for (let i = from; i < to; i++) { - const internalIndex = i - __privateGet(this, _range).from; - if (this.internalData[internalIndex]) { - this.rowsWithinRange += 1; - } - } - let clientRows = EMPTY_ARRAY; - const offset = __privateGet(this, _range).from; - if (this.hasAllRowsWithinRange) { - if (to > originalRange.to) { - const start = Math.max(from, originalRange.to); - clientRows = this.internalData.slice(start - offset, to - offset); - } else { - const end = Math.min(originalRange.from, to); - clientRows = this.internalData.slice(from - offset, end - offset); - } - } - const serverDataRequired = this.bufferBreakout(from, to); - return [serverDataRequired, clientRows]; - } - setRange(from, to) { - var _a, _b; - if (from !== __privateGet(this, _range).from || to !== __privateGet(this, _range).to) { - (_a = log.debug) == null ? void 0 : _a.call(log, \`setRange \${from} - \${to}\`); - const [overlapFrom, overlapTo] = __privateGet(this, _range).overlap(from, to); - const newData = new Array(to - from); - this.rowsWithinRange = 0; - for (let i = overlapFrom; i < overlapTo; i++) { - const data = this.getAtIndex(i); - if (data) { - const index = i - from; - newData[index] = data; - if (this.isWithinClientRange(i)) { - this.rowsWithinRange += 1; - } - } - } - this.internalData = newData; - __privateGet(this, _range).from = from; - __privateGet(this, _range).to = to; - } else { - (_b = log.debug) == null ? void 0 : _b.call(log, \`setRange \${from} - \${to} IGNORED because not changed\`); - } - } - //TODO temp - get data() { - return this.internalData; - } - getData() { - var _a; - const { from, to } = __privateGet(this, _range); - const { from: clientFrom, to: clientTo } = this.clientRange; - const startOffset = Math.max(0, clientFrom - from); - const endOffset = Math.min( - to - from, - to, - clientTo - from, - (_a = this.rowCount) != null ? _a : to - ); - return this.internalData.slice(startOffset, endOffset); - } - clear() { - var _a; - (_a = log.debug) == null ? void 0 : _a.call(log, "clear"); - this.internalData.length = 0; - this.rowsWithinRange = 0; - this.setRowCount(0); - } - // used only for debugging - getCurrentDataRange() { - const rows = this.internalData; - const len = rows.length; - let [firstRow] = this.internalData; - let lastRow = this.internalData[len - 1]; - if (firstRow && lastRow) { - return [firstRow.rowIndex, lastRow.rowIndex]; - } else { - for (let i = 0; i < len; i++) { - if (rows[i] !== void 0) { - firstRow = rows[i]; - break; - } - } - for (let i = len - 1; i >= 0; i--) { - if (rows[i] !== void 0) { - lastRow = rows[i]; - break; - } - } - if (firstRow && lastRow) { - return [firstRow.rowIndex, lastRow.rowIndex]; - } else { - return [-1, -1]; - } - } - } -}; -_range = new WeakMap(); - -// src/server-proxy/viewport.ts -var EMPTY_GROUPBY = []; -var { debug: debug2, debugEnabled: debugEnabled2, error, info, infoEnabled, warn } = logger("viewport"); -var isLeafUpdate = ({ rowKey, updateType }) => updateType === "U" && !rowKey.startsWith("\$root"); -var NO_DATA_UPDATE = [ - void 0, - void 0 -]; -var NO_UPDATE_STATUS = { - count: 0, - mode: void 0, - size: 0, - ts: 0 -}; -var Viewport = class { - constructor({ - aggregations, - bufferSize = 50, - columns, - filter, - groupBy = [], - table, - range, - sort, - title, - viewport, - visualLink - }, postMessageToClient) { - /** batchMode is irrelevant for Vuu Table, it was introduced to try and improve rendering performance of AgGrid */ - this.batchMode = true; - this.hasUpdates = false; - this.pendingUpdates = []; - this.pendingOperations = /* @__PURE__ */ new Map(); - this.pendingRangeRequests = []; - this.rowCountChanged = false; - this.selectedRows = []; - this.useBatchMode = true; - this.lastUpdateStatus = NO_UPDATE_STATUS; - this.updateThrottleTimer = void 0; - this.rangeMonitor = new RangeMonitor("ViewPort"); - this.disabled = false; - this.isTree = false; - // TODO roll disabled/suspended into status - this.status = ""; - this.suspended = false; - this.suspendTimer = null; - // Records SIZE only updates - this.setLastSizeOnlyUpdateSize = (size) => { - this.lastUpdateStatus.size = size; - }; - this.setLastUpdate = (mode) => { - const { ts: lastTS, mode: lastMode } = this.lastUpdateStatus; - let elapsedTime = 0; - if (lastMode === mode) { - const ts = Date.now(); - this.lastUpdateStatus.count += 1; - this.lastUpdateStatus.ts = ts; - elapsedTime = lastTS === 0 ? 0 : ts - lastTS; - } else { - this.lastUpdateStatus.count = 1; - this.lastUpdateStatus.ts = 0; - elapsedTime = 0; - } - this.lastUpdateStatus.mode = mode; - return elapsedTime; - }; - this.rangeRequestAlreadyPending = (range) => { - const { bufferSize } = this; - const bufferThreshold = bufferSize * 0.25; - let { from: stillPendingFrom } = range; - for (const { from, to } of this.pendingRangeRequests) { - if (stillPendingFrom >= from && stillPendingFrom < to) { - if (range.to + bufferThreshold <= to) { - return true; - } else { - stillPendingFrom = to; - } - } - } - return false; - }; - this.sendThrottledSizeMessage = () => { - this.updateThrottleTimer = void 0; - this.lastUpdateStatus.count = 3; - this.postMessageToClient({ - clientViewportId: this.clientViewportId, - mode: "size-only", - size: this.lastUpdateStatus.size, - type: "viewport-update" - }); - }; - // If we are receiving multiple SIZE updates but no data, table is loading rows - // outside of our viewport. We can safely throttle these requests. Doing so will - // alleviate pressure on UI DataTable. - this.shouldThrottleMessage = (mode) => { - const elapsedTime = this.setLastUpdate(mode); - return mode === "size-only" && elapsedTime > 0 && elapsedTime < 500 && this.lastUpdateStatus.count > 3; - }; - this.throttleMessage = (mode) => { - if (this.shouldThrottleMessage(mode)) { - info == null ? void 0 : info("throttling updates setTimeout to 2000"); - if (this.updateThrottleTimer === void 0) { - this.updateThrottleTimer = setTimeout( - this.sendThrottledSizeMessage, - 2e3 - ); - } - return true; - } else if (this.updateThrottleTimer !== void 0) { - clearTimeout(this.updateThrottleTimer); - this.updateThrottleTimer = void 0; - } - return false; - }; - this.getNewRowCount = () => { - if (this.rowCountChanged && this.dataWindow) { - this.rowCountChanged = false; - return this.dataWindow.rowCount; - } - }; - this.aggregations = aggregations; - this.bufferSize = bufferSize; - this.clientRange = range; - this.clientViewportId = viewport; - this.columns = columns; - this.filter = filter; - this.groupBy = groupBy; - this.keys = new KeySet(range); - this.pendingLinkedParent = visualLink; - this.table = table; - this.sort = sort; - this.title = title; - infoEnabled && (info == null ? void 0 : info( - \`constructor #\${viewport} \${table.table} bufferSize=\${bufferSize}\` - )); - this.dataWindow = new ArrayBackedMovingWindow( - this.clientRange, - range, - this.bufferSize - ); - this.postMessageToClient = postMessageToClient; - } - get hasUpdatesToProcess() { - if (this.suspended) { - return false; - } - return this.rowCountChanged || this.hasUpdates; - } - get size() { - var _a; - return (_a = this.dataWindow.rowCount) != null ? _a : 0; - } - subscribe() { - const { filter } = this.filter; - this.status = this.status === "subscribed" ? "resubscribing" : "subscribing"; - return { - type: CREATE_VP, - table: this.table, - range: getFullRange(this.clientRange, this.bufferSize), - aggregations: this.aggregations, - columns: this.columns, - sort: this.sort, - groupBy: this.groupBy, - filterSpec: { filter } - }; - } - handleSubscribed({ - viewPortId, - aggregations, - columns, - filterSpec: filter, - range, - sort, - groupBy - }, tableSchema) { - this.serverViewportId = viewPortId; - this.status = "subscribed"; - this.aggregations = aggregations; - this.columns = columns; - this.groupBy = groupBy; - this.isTree = groupBy && groupBy.length > 0; - this.dataWindow.setRange(range.from, range.to); - return { - aggregations, - type: "subscribed", - clientViewportId: this.clientViewportId, - columns, - filter, - groupBy, - range, - sort, - tableSchema - }; - } - awaitOperation(requestId, msg) { - this.pendingOperations.set(requestId, msg); - } - // Return a message if we need to communicate this to client UI - completeOperation(requestId, ...params) { - var _a; - const { clientViewportId, pendingOperations } = this; - const pendingOperation = pendingOperations.get(requestId); - if (!pendingOperation) { - error( - \`no matching operation found to complete for requestId \${requestId}\` - ); - return; - } - const { type } = pendingOperation; - info == null ? void 0 : info(\`completeOperation \${type}\`); - pendingOperations.delete(requestId); - if (type === "CHANGE_VP_RANGE") { - const [from, to] = params; - (_a = this.dataWindow) == null ? void 0 : _a.setRange(from, to); - for (let i = this.pendingRangeRequests.length - 1; i >= 0; i--) { - const pendingRangeRequest = this.pendingRangeRequests[i]; - if (pendingRangeRequest.requestId === requestId) { - pendingRangeRequest.acked = true; - break; - } else { - warn == null ? void 0 : warn("range requests sent faster than they are being ACKed"); - } - } - } else if (type === "config") { - const { aggregations, columns, filter, groupBy, sort } = pendingOperation.data; - this.aggregations = aggregations; - this.columns = columns; - this.filter = filter; - this.groupBy = groupBy; - this.sort = sort; - if (groupBy.length > 0) { - this.isTree = true; - } else if (this.isTree) { - this.isTree = false; - } - debug2 == null ? void 0 : debug2(\`config change confirmed, isTree : \${this.isTree}\`); - return { - clientViewportId, - type, - config: pendingOperation.data - }; - } else if (type === "groupBy") { - this.isTree = pendingOperation.data.length > 0; - this.groupBy = pendingOperation.data; - debug2 == null ? void 0 : debug2(\`groupBy change confirmed, isTree : \${this.isTree}\`); - return { - clientViewportId, - type, - groupBy: pendingOperation.data - }; - } else if (type === "columns") { - this.columns = pendingOperation.data; - return { - clientViewportId, - type, - columns: pendingOperation.data - }; - } else if (type === "filter") { - this.filter = pendingOperation.data; - return { - clientViewportId, - type, - filter: pendingOperation.data - }; - } else if (type === "aggregate") { - this.aggregations = pendingOperation.data; - return { - clientViewportId, - type: "aggregate", - aggregations: this.aggregations - }; - } else if (type === "sort") { - this.sort = pendingOperation.data; - return { - clientViewportId, - type, - sort: this.sort - }; - } else if (type === "selection") { - } else if (type === "disable") { - this.disabled = true; - return { - type: "disabled", - clientViewportId - }; - } else if (type === "enable") { - this.disabled = false; - return { - type: "enabled", - clientViewportId - }; - } else if (type === "CREATE_VISUAL_LINK") { - const [colName, parentViewportId, parentColName] = params; - this.linkedParent = { - colName, - parentViewportId, - parentColName - }; - this.pendingLinkedParent = void 0; - return { - type: "vuu-link-created", - clientViewportId, - colName, - parentViewportId, - parentColName - }; - } else if (type === "REMOVE_VISUAL_LINK") { - this.linkedParent = void 0; - return { - type: "vuu-link-removed", - clientViewportId - }; - } - } - // TODO when a range request arrives, consider the viewport to be scrolling - // until data arrives and we have the full range. - // When not scrolling, any server data is an update - // When scrolling, we are in batch mode - rangeRequest(requestId, range) { - if (debugEnabled2) { - this.rangeMonitor.set(range); - } - const type = "CHANGE_VP_RANGE"; - if (this.dataWindow) { - const [serverDataRequired, clientRows] = this.dataWindow.setClientRange( - range.from, - range.to - ); - let debounceRequest; - const maxRange = this.dataWindow.rowCount || void 0; - const serverRequest = serverDataRequired && !this.rangeRequestAlreadyPending(range) ? { - type, - viewPortId: this.serverViewportId, - ...getFullRange(range, this.bufferSize, maxRange) - } : null; - if (serverRequest) { - debugEnabled2 && (debug2 == null ? void 0 : debug2( - \`create CHANGE_VP_RANGE: [\${serverRequest.from} - \${serverRequest.to}]\` - )); - this.awaitOperation(requestId, { type }); - const pendingRequest = this.pendingRangeRequests.at(-1); - if (pendingRequest) { - if (pendingRequest.acked) { - console.warn("Range Request before previous request is filled"); - } else { - const { from, to } = pendingRequest; - if (this.dataWindow.outOfRange(from, to)) { - debounceRequest = { - clientViewportId: this.clientViewportId, - type: "debounce-begin" - }; - } else { - warn == null ? void 0 : warn("Range Request before previous request is acked"); - } - } - } - this.pendingRangeRequests.push({ ...serverRequest, requestId }); - if (this.useBatchMode) { - this.batchMode = true; - } - } else if (clientRows.length > 0) { - this.batchMode = false; - } - this.keys.reset(this.dataWindow.clientRange); - const toClient = this.isTree ? toClientRowTree : toClientRow; - if (clientRows.length) { - return [ - serverRequest, - clientRows.map((row) => { - return toClient(row, this.keys, this.selectedRows); - }) - ]; - } else if (debounceRequest) { - return [serverRequest, void 0, debounceRequest]; - } else { - return [serverRequest]; - } - } else { - return [null]; - } - } - setLinks(links) { - this.links = links; - return [ - { - type: "vuu-links", - links, - clientViewportId: this.clientViewportId - }, - this.pendingLinkedParent - ]; - } - setMenu(menu) { - return { - type: "vuu-menu", - menu, - clientViewportId: this.clientViewportId - }; - } - openTreeNode(requestId, message) { - if (this.useBatchMode) { - this.batchMode = true; - } - return { - type: OPEN_TREE_NODE, - vpId: this.serverViewportId, - treeKey: message.key - }; - } - closeTreeNode(requestId, message) { - if (this.useBatchMode) { - this.batchMode = true; - } - return { - type: CLOSE_TREE_NODE, - vpId: this.serverViewportId, - treeKey: message.key - }; - } - createLink(requestId, colName, parentVpId, parentColumnName) { - const message = { - type: "CREATE_VISUAL_LINK", - parentVpId, - childVpId: this.serverViewportId, - parentColumnName, - childColumnName: colName - }; - this.awaitOperation(requestId, message); - if (this.useBatchMode) { - this.batchMode = true; - } - return message; - } - removeLink(requestId) { - const message = { - type: "REMOVE_VISUAL_LINK", - childVpId: this.serverViewportId - }; - this.awaitOperation(requestId, message); - return message; - } - suspend() { - this.suspended = true; - info == null ? void 0 : info("suspend"); - } - resume() { - this.suspended = false; - if (debugEnabled2) { - debug2 == null ? void 0 : debug2(\`resume: \${this.currentData()}\`); - } - return [this.size, this.currentData()]; - } - currentData() { - const out = []; - if (this.dataWindow) { - const records = this.dataWindow.getData(); - const { keys } = this; - const toClient = this.isTree ? toClientRowTree : toClientRow; - for (const row of records) { - if (row) { - out.push(toClient(row, keys, this.selectedRows)); - } - } - } - return out; - } - enable(requestId) { - this.awaitOperation(requestId, { type: "enable" }); - info == null ? void 0 : info(\`enable: \${this.serverViewportId}\`); - return { - type: ENABLE_VP, - viewPortId: this.serverViewportId - }; - } - disable(requestId) { - this.awaitOperation(requestId, { type: "disable" }); - info == null ? void 0 : info(\`disable: \${this.serverViewportId}\`); - this.suspended = false; - return { - type: DISABLE_VP, - viewPortId: this.serverViewportId - }; - } - columnRequest(requestId, columns) { - this.awaitOperation(requestId, { - type: "columns", - data: columns - }); - debug2 == null ? void 0 : debug2(\`columnRequest: \${columns}\`); - return this.createRequest({ columns }); - } - filterRequest(requestId, dataSourceFilter) { - this.awaitOperation(requestId, { - type: "filter", - data: dataSourceFilter - }); - if (this.useBatchMode) { - this.batchMode = true; - } - const { filter } = dataSourceFilter; - info == null ? void 0 : info(\`filterRequest: \${filter}\`); - return this.createRequest({ filterSpec: { filter } }); - } - setConfig(requestId, config) { - this.awaitOperation(requestId, { type: "config", data: config }); - const { filter, ...remainingConfig } = config; - if (this.useBatchMode) { - this.batchMode = true; - } - debugEnabled2 ? debug2 == null ? void 0 : debug2(\`setConfig \${JSON.stringify(config)}\`) : info == null ? void 0 : info(\`setConfig\`); - return this.createRequest( - { - ...remainingConfig, - filterSpec: typeof (filter == null ? void 0 : filter.filter) === "string" ? { - filter: filter.filter - } : { - filter: "" - } - }, - true - ); - } - aggregateRequest(requestId, aggregations) { - this.awaitOperation(requestId, { type: "aggregate", data: aggregations }); - info == null ? void 0 : info(\`aggregateRequest: \${aggregations}\`); - return this.createRequest({ aggregations }); - } - sortRequest(requestId, sort) { - this.awaitOperation(requestId, { type: "sort", data: sort }); - info == null ? void 0 : info(\`sortRequest: \${JSON.stringify(sort.sortDefs)}\`); - return this.createRequest({ sort }); - } - groupByRequest(requestId, groupBy = EMPTY_GROUPBY) { - var _a; - this.awaitOperation(requestId, { type: "groupBy", data: groupBy }); - if (this.useBatchMode) { - this.batchMode = true; - } - if (!this.isTree) { - (_a = this.dataWindow) == null ? void 0 : _a.clear(); - } - return this.createRequest({ groupBy }); - } - selectRequest(requestId, selected) { - this.selectedRows = selected; - this.awaitOperation(requestId, { type: "selection", data: selected }); - info == null ? void 0 : info(\`selectRequest: \${selected}\`); - return { - type: "SET_SELECTION", - vpId: this.serverViewportId, - selection: expandSelection(selected) - }; - } - removePendingRangeRequest(firstIndex, lastIndex) { - for (let i = this.pendingRangeRequests.length - 1; i >= 0; i--) { - const { from, to } = this.pendingRangeRequests[i]; - let isLast = true; - if (firstIndex >= from && firstIndex < to || lastIndex > from && lastIndex < to) { - if (!isLast) { - console.warn( - "removePendingRangeRequest TABLE_ROWS are not for latest request" - ); - } - this.pendingRangeRequests.splice(i, 1); - break; - } else { - isLast = false; - } - } - } - updateRows(rows) { - var _a, _b, _c; - const [firstRow, lastRow] = getFirstAndLastRows(rows); - if (firstRow && lastRow) { - this.removePendingRangeRequest(firstRow.rowIndex, lastRow.rowIndex); - } - if (rows.length === 1) { - if (firstRow.vpSize === 0 && this.disabled) { - debug2 == null ? void 0 : debug2( - \`ignore a SIZE=0 message on disabled viewport (\${rows.length} rows)\` - ); - return; - } else if (firstRow.updateType === "SIZE") { - this.setLastSizeOnlyUpdateSize(firstRow.vpSize); - } - } - for (const row of rows) { - if (this.isTree && isLeafUpdate(row)) { - continue; - } else { - if (row.updateType === "SIZE" || ((_a = this.dataWindow) == null ? void 0 : _a.rowCount) !== row.vpSize) { - (_b = this.dataWindow) == null ? void 0 : _b.setRowCount(row.vpSize); - this.rowCountChanged = true; - } - if (row.updateType === "U") { - if ((_c = this.dataWindow) == null ? void 0 : _c.setAtIndex(row)) { - this.hasUpdates = true; - if (!this.batchMode) { - this.pendingUpdates.push(row); - } - } - } - } - } - } - // This is called only after new data has been received from server - data - // returned direcly from buffer does not use this. - getClientRows() { - let out = void 0; - let mode = "size-only"; - if (!this.hasUpdates && !this.rowCountChanged) { - return NO_DATA_UPDATE; - } - if (this.hasUpdates) { - const { keys, selectedRows } = this; - const toClient = this.isTree ? toClientRowTree : toClientRow; - if (this.updateThrottleTimer) { - self.clearTimeout(this.updateThrottleTimer); - this.updateThrottleTimer = void 0; - } - if (this.pendingUpdates.length > 0) { - out = []; - mode = "update"; - for (const row of this.pendingUpdates) { - out.push(toClient(row, keys, selectedRows)); - } - this.pendingUpdates.length = 0; - } else { - const records = this.dataWindow.getData(); - if (this.dataWindow.hasAllRowsWithinRange) { - out = []; - mode = "batch"; - for (const row of records) { - out.push(toClient(row, keys, selectedRows)); - } - this.batchMode = false; - } - } - this.hasUpdates = false; - } - if (this.throttleMessage(mode)) { - return NO_DATA_UPDATE; - } else { - return [out, mode]; - } - } - createRequest(params, overWrite = false) { - if (overWrite) { - return { - type: "CHANGE_VP", - viewPortId: this.serverViewportId, - ...params - }; - } else { - return { - type: "CHANGE_VP", - viewPortId: this.serverViewportId, - aggregations: this.aggregations, - columns: this.columns, - sort: this.sort, - groupBy: this.groupBy, - filterSpec: { - filter: this.filter.filter - }, - ...params - }; - } - } -}; -var toClientRow = ({ rowIndex, rowKey, sel: isSelected, data }, keys, selectedRows) => { - return [ - rowIndex, - keys.keyFor(rowIndex), - true, - false, - 0, - 0, - rowKey, - isSelected ? getSelectionStatus(selectedRows, rowIndex) : 0 - ].concat(data); -}; -var toClientRowTree = ({ rowIndex, rowKey, sel: isSelected, data }, keys, selectedRows) => { - const [depth, isExpanded, , isLeaf, , count, ...rest] = data; - return [ - rowIndex, - keys.keyFor(rowIndex), - isLeaf, - isExpanded, - depth, - count, - rowKey, - isSelected ? getSelectionStatus(selectedRows, rowIndex) : 0 - ].concat(rest); -}; - -// src/server-proxy/server-proxy.ts -var _requestId = 1; -var { debug: debug3, debugEnabled: debugEnabled3, error: error2, info: info2, infoEnabled: infoEnabled2, warn: warn2 } = logger("server-proxy"); -var nextRequestId = () => \`\${_requestId++}\`; -var DEFAULT_OPTIONS = {}; -var isActiveViewport = (viewPort) => viewPort.disabled !== true && viewPort.suspended !== true; -var NO_ACTION = { - type: "NO_ACTION" -}; -var addTitleToLinks = (links, serverViewportId, label) => links.map( - (link) => link.parentVpId === serverViewportId ? { ...link, label } : link -); -function addLabelsToLinks(links, viewports) { - return links.map((linkDescriptor) => { - const { parentVpId } = linkDescriptor; - const viewport = viewports.get(parentVpId); - if (viewport) { - return { - ...linkDescriptor, - parentClientVpId: viewport.clientViewportId, - label: viewport.title - }; - } else { - throw Error("addLabelsToLinks viewport not found"); - } - }); -} -var ServerProxy = class { - constructor(connection, callback) { - this.authToken = ""; - this.user = "user"; - this.pendingRequests = /* @__PURE__ */ new Map(); - this.queuedRequests = []; - this.cachedTableMetaRequests = /* @__PURE__ */ new Map(); - this.cachedTableSchemas = /* @__PURE__ */ new Map(); - this.connection = connection; - this.postMessageToClient = callback; - this.viewports = /* @__PURE__ */ new Map(); - this.mapClientToServerViewport = /* @__PURE__ */ new Map(); - } - async reconnect() { - await this.login(this.authToken); - const [activeViewports, inactiveViewports] = partition( - Array.from(this.viewports.values()), - isActiveViewport - ); - this.viewports.clear(); - this.mapClientToServerViewport.clear(); - const reconnectViewports = (viewports) => { - viewports.forEach((viewport) => { - const { clientViewportId } = viewport; - this.viewports.set(clientViewportId, viewport); - this.sendMessageToServer(viewport.subscribe(), clientViewportId); - }); - }; - reconnectViewports(activeViewports); - setTimeout(() => { - reconnectViewports(inactiveViewports); - }, 2e3); - } - async login(authToken, user = "user") { - if (authToken) { - this.authToken = authToken; - this.user = user; - return new Promise((resolve, reject) => { - this.sendMessageToServer( - { type: LOGIN, token: this.authToken, user }, - "" - ); - this.pendingLogin = { resolve, reject }; - }); - } else if (this.authToken === "") { - error2("login, cannot login until auth token has been obtained"); - } - } - subscribe(message) { - if (!this.mapClientToServerViewport.has(message.viewport)) { - const pendingTableSchema = this.getTableMeta(message.table); - const viewport = new Viewport(message, this.postMessageToClient); - this.viewports.set(message.viewport, viewport); - const pendingSubscription = this.awaitResponseToMessage( - viewport.subscribe(), - message.viewport - ); - const awaitPendingReponses = Promise.all([ - pendingSubscription, - pendingTableSchema - ]); - awaitPendingReponses.then(([subscribeResponse, tableSchema]) => { - const { viewPortId: serverViewportId } = subscribeResponse; - const { status: previousViewportStatus } = viewport; - if (message.viewport !== serverViewportId) { - this.viewports.delete(message.viewport); - this.viewports.set(serverViewportId, viewport); - } - this.mapClientToServerViewport.set(message.viewport, serverViewportId); - const clientResponse = viewport.handleSubscribed( - subscribeResponse, - tableSchema - ); - if (clientResponse) { - this.postMessageToClient(clientResponse); - if (debugEnabled3) { - debug3( - \`post DataSourceSubscribedMessage to client: \${JSON.stringify( - clientResponse - )}\` - ); - } - } - if (viewport.disabled) { - this.disableViewport(viewport); - } - if (this.queuedRequests.length > 0) { - this.processQueuedRequests(); - } - if (previousViewportStatus === "subscribing" && // A session table will never have Visual Links, nor Context Menus - !isSessionTable(viewport.table)) { - this.sendMessageToServer({ - type: GET_VP_VISUAL_LINKS, - vpId: serverViewportId - }); - this.sendMessageToServer({ - type: GET_VIEW_PORT_MENUS, - vpId: serverViewportId - }); - Array.from(this.viewports.entries()).filter( - ([id, { disabled }]) => id !== serverViewportId && !disabled - ).forEach(([vpId]) => { - this.sendMessageToServer({ - type: GET_VP_VISUAL_LINKS, - vpId - }); - }); - } - }); - } else { - error2(\`spurious subscribe call \${message.viewport}\`); - } - } - processQueuedRequests() { - const messageTypesProcessed = {}; - while (this.queuedRequests.length) { - const queuedRequest = this.queuedRequests.pop(); - if (queuedRequest) { - const { clientViewportId, message, requestId } = queuedRequest; - if (message.type === "CHANGE_VP_RANGE") { - if (messageTypesProcessed.CHANGE_VP_RANGE) { - continue; - } - messageTypesProcessed.CHANGE_VP_RANGE = true; - const serverViewportId = this.mapClientToServerViewport.get(clientViewportId); - if (serverViewportId) { - this.sendMessageToServer( - { - ...message, - viewPortId: serverViewportId - }, - requestId - ); - } - } - } - } - } - unsubscribe(clientViewportId) { - const serverViewportId = this.mapClientToServerViewport.get(clientViewportId); - if (serverViewportId) { - info2 == null ? void 0 : info2( - \`Unsubscribe Message (Client to Server): - \${serverViewportId}\` - ); - this.sendMessageToServer({ - type: REMOVE_VP, - viewPortId: serverViewportId - }); - } else { - error2( - \`failed to unsubscribe client viewport \${clientViewportId}, viewport not found\` - ); - } - } - getViewportForClient(clientViewportId, throws = true) { - const serverViewportId = this.mapClientToServerViewport.get(clientViewportId); - if (serverViewportId) { - const viewport = this.viewports.get(serverViewportId); - if (viewport) { - return viewport; - } else if (throws) { - throw Error( - \`Viewport not found for client viewport \${clientViewportId}\` - ); - } else { - return null; - } - } else if (this.viewports.has(clientViewportId)) { - return this.viewports.get(clientViewportId); - } else if (throws) { - throw Error( - \`Viewport server id not found for client viewport \${clientViewportId}\` - ); - } else { - return null; - } - } - /**********************************************************************/ - /* Handle messages from client */ - /**********************************************************************/ - setViewRange(viewport, message) { - const requestId = nextRequestId(); - const [serverRequest, rows, debounceRequest] = viewport.rangeRequest( - requestId, - message.range - ); - info2 == null ? void 0 : info2(\`setViewRange \${message.range.from} - \${message.range.to}\`); - if (serverRequest) { - if (true) { - info2 == null ? void 0 : info2( - \`CHANGE_VP_RANGE [\${message.range.from}-\${message.range.to}] => [\${serverRequest.from}-\${serverRequest.to}]\` - ); - } - const sentToServer = this.sendIfReady( - serverRequest, - requestId, - viewport.status === "subscribed" - ); - if (!sentToServer) { - this.queuedRequests.push({ - clientViewportId: message.viewport, - message: serverRequest, - requestId - }); - } - } - if (rows) { - info2 == null ? void 0 : info2(\`setViewRange \${rows.length} rows returned from cache\`); - this.postMessageToClient({ - mode: "batch", - type: "viewport-update", - clientViewportId: viewport.clientViewportId, - rows - }); - } else if (debounceRequest) { - this.postMessageToClient(debounceRequest); - } - } - setConfig(viewport, message) { - const requestId = nextRequestId(); - const request = viewport.setConfig(requestId, message.config); - this.sendIfReady(request, requestId, viewport.status === "subscribed"); - } - aggregate(viewport, message) { - const requestId = nextRequestId(); - const request = viewport.aggregateRequest(requestId, message.aggregations); - this.sendIfReady(request, requestId, viewport.status === "subscribed"); - } - sort(viewport, message) { - const requestId = nextRequestId(); - const request = viewport.sortRequest(requestId, message.sort); - this.sendIfReady(request, requestId, viewport.status === "subscribed"); - } - groupBy(viewport, message) { - const requestId = nextRequestId(); - const request = viewport.groupByRequest(requestId, message.groupBy); - this.sendIfReady(request, requestId, viewport.status === "subscribed"); - } - filter(viewport, message) { - const requestId = nextRequestId(); - const { filter } = message; - const request = viewport.filterRequest(requestId, filter); - this.sendIfReady(request, requestId, viewport.status === "subscribed"); - } - setColumns(viewport, message) { - const requestId = nextRequestId(); - const { columns } = message; - const request = viewport.columnRequest(requestId, columns); - this.sendIfReady(request, requestId, viewport.status === "subscribed"); - } - setTitle(viewport, message) { - if (viewport) { - viewport.title = message.title; - this.updateTitleOnVisualLinks(viewport); - } - } - select(viewport, message) { - const requestId = nextRequestId(); - const { selected } = message; - const request = viewport.selectRequest(requestId, selected); - this.sendIfReady(request, requestId, viewport.status === "subscribed"); - } - disableViewport(viewport) { - const requestId = nextRequestId(); - const request = viewport.disable(requestId); - this.sendIfReady(request, requestId, viewport.status === "subscribed"); - } - enableViewport(viewport) { - if (viewport.disabled) { - const requestId = nextRequestId(); - const request = viewport.enable(requestId); - this.sendIfReady(request, requestId, viewport.status === "subscribed"); - } - } - suspendViewport(viewport) { - viewport.suspend(); - viewport.suspendTimer = setTimeout(() => { - info2 == null ? void 0 : info2("suspendTimer expired, escalate suspend to disable"); - this.disableViewport(viewport); - }, 3e3); - } - resumeViewport(viewport) { - if (viewport.suspendTimer) { - debug3 == null ? void 0 : debug3("clear suspend timer"); - clearTimeout(viewport.suspendTimer); - viewport.suspendTimer = null; - } - const [size, rows] = viewport.resume(); - debug3 == null ? void 0 : debug3(\`resumeViewport size \${size}, \${rows.length} rows sent to client\`); - this.postMessageToClient({ - clientViewportId: viewport.clientViewportId, - mode: "batch", - rows, - size, - type: "viewport-update" - }); - } - openTreeNode(viewport, message) { - if (viewport.serverViewportId) { - const requestId = nextRequestId(); - this.sendIfReady( - viewport.openTreeNode(requestId, message), - requestId, - viewport.status === "subscribed" - ); - } - } - closeTreeNode(viewport, message) { - if (viewport.serverViewportId) { - const requestId = nextRequestId(); - this.sendIfReady( - viewport.closeTreeNode(requestId, message), - requestId, - viewport.status === "subscribed" - ); - } - } - createLink(viewport, message) { - const { parentClientVpId, parentColumnName, childColumnName } = message; - const requestId = nextRequestId(); - const parentVpId = this.mapClientToServerViewport.get(parentClientVpId); - if (parentVpId) { - const request = viewport.createLink( - requestId, - childColumnName, - parentVpId, - parentColumnName - ); - this.sendMessageToServer(request, requestId); - } else { - error2("ServerProxy unable to create link, viewport not found"); - } - } - removeLink(viewport) { - const requestId = nextRequestId(); - const request = viewport.removeLink(requestId); - this.sendMessageToServer(request, requestId); - } - updateTitleOnVisualLinks(viewport) { - var _a; - const { serverViewportId, title } = viewport; - for (const vp of this.viewports.values()) { - if (vp !== viewport && vp.links && serverViewportId && title) { - if ((_a = vp.links) == null ? void 0 : _a.some((link) => link.parentVpId === serverViewportId)) { - const [messageToClient] = vp.setLinks( - addTitleToLinks(vp.links, serverViewportId, title) - ); - this.postMessageToClient(messageToClient); - } - } - } - } - removeViewportFromVisualLinks(serverViewportId) { - var _a; - for (const vp of this.viewports.values()) { - if ((_a = vp.links) == null ? void 0 : _a.some(({ parentVpId }) => parentVpId === serverViewportId)) { - const [messageToClient] = vp.setLinks( - vp.links.filter(({ parentVpId }) => parentVpId !== serverViewportId) - ); - this.postMessageToClient(messageToClient); - } - } - } - menuRpcCall(message) { - const viewport = this.getViewportForClient(message.vpId, false); - if (viewport == null ? void 0 : viewport.serverViewportId) { - const [requestId, rpcRequest] = stripRequestId(message); - this.sendMessageToServer( - { - ...rpcRequest, - vpId: viewport.serverViewportId - }, - requestId - ); - } - } - viewportRpcCall(message) { - const viewport = this.getViewportForClient(message.vpId, false); - if (viewport == null ? void 0 : viewport.serverViewportId) { - const [requestId, rpcRequest] = stripRequestId(message); - this.sendMessageToServer( - { - ...rpcRequest, - vpId: viewport.serverViewportId, - namedParams: {} - }, - requestId - ); - } - } - rpcCall(message) { - const [requestId, rpcRequest] = stripRequestId(message); - const module = getRpcServiceModule(rpcRequest.service); - this.sendMessageToServer(rpcRequest, requestId, { module }); - } - handleMessageFromClient(message) { - var _a; - if (isViewporttMessage(message)) { - if (message.type === "disable") { - const viewport = this.getViewportForClient(message.viewport, false); - if (viewport !== null) { - return this.disableViewport(viewport); - } else { - return; - } - } else { - const viewport = this.getViewportForClient(message.viewport); - switch (message.type) { - case "setViewRange": - return this.setViewRange(viewport, message); - case "config": - return this.setConfig(viewport, message); - case "aggregate": - return this.aggregate(viewport, message); - case "sort": - return this.sort(viewport, message); - case "groupBy": - return this.groupBy(viewport, message); - case "filter": - return this.filter(viewport, message); - case "select": - return this.select(viewport, message); - case "suspend": - return this.suspendViewport(viewport); - case "resume": - return this.resumeViewport(viewport); - case "enable": - return this.enableViewport(viewport); - case "openTreeNode": - return this.openTreeNode(viewport, message); - case "closeTreeNode": - return this.closeTreeNode(viewport, message); - case "createLink": - return this.createLink(viewport, message); - case "removeLink": - return this.removeLink(viewport); - case "setColumns": - return this.setColumns(viewport, message); - case "setTitle": - return this.setTitle(viewport, message); - default: - } - } - } else if (isVuuRpcRequest(message)) { - return this.viewportRpcCall( - message - ); - } else if (isVuuMenuRpcRequest(message)) { - return this.menuRpcCall(message); - } else { - const { type, requestId } = message; - switch (type) { - case "GET_TABLE_LIST": { - (_a = this.tableList) != null ? _a : this.tableList = this.awaitResponseToMessage( - { type }, - requestId - ); - this.tableList.then((response) => { - this.postMessageToClient({ - type: "TABLE_LIST_RESP", - tables: response.tables, - requestId - }); - }); - return; - } - case "GET_TABLE_META": { - this.getTableMeta(message.table, requestId).then((tableSchema) => { - if (tableSchema) { - this.postMessageToClient({ - type: "TABLE_META_RESP", - tableSchema, - requestId - }); - } - }); - return; - } - case "RPC_CALL": - return this.rpcCall(message); - default: - } - } - error2( - \`Vuu ServerProxy Unexpected message from client \${JSON.stringify( - message - )}\` - ); - } - getTableMeta(table, requestId = nextRequestId()) { - if (isSessionTable(table)) { - return Promise.resolve(void 0); - } - const key = \`\${table.module}:\${table.table}\`; - let tableMetaRequest = this.cachedTableMetaRequests.get(key); - if (!tableMetaRequest) { - tableMetaRequest = this.awaitResponseToMessage( - { type: "GET_TABLE_META", table }, - requestId - ); - this.cachedTableMetaRequests.set(key, tableMetaRequest); - } - return tableMetaRequest == null ? void 0 : tableMetaRequest.then((response) => this.cacheTableMeta(response)); - } - awaitResponseToMessage(message, requestId = nextRequestId()) { - return new Promise((resolve, reject) => { - this.sendMessageToServer(message, requestId); - this.pendingRequests.set(requestId, { reject, resolve }); - }); - } - sendIfReady(message, requestId, isReady = true) { - if (isReady) { - this.sendMessageToServer(message, requestId); - } - return isReady; - } - sendMessageToServer(body, requestId = \`\${_requestId++}\`, options = DEFAULT_OPTIONS) { - const { module = "CORE" } = options; - if (this.authToken) { - this.connection.send({ - requestId, - sessionId: this.sessionId, - token: this.authToken, - user: this.user, - module, - body - }); - } - } - handleMessageFromServer(message) { - var _a, _b, _c; - const { body, requestId, sessionId } = message; - const pendingRequest = this.pendingRequests.get(requestId); - if (pendingRequest) { - const { resolve } = pendingRequest; - this.pendingRequests.delete(requestId); - resolve(body); - return; - } - const { viewports } = this; - switch (body.type) { - case HB: - this.sendMessageToServer( - { type: HB_RESP, ts: +/* @__PURE__ */ new Date() }, - "NA" - ); - break; - case "LOGIN_SUCCESS": - if (sessionId) { - this.sessionId = sessionId; - (_a = this.pendingLogin) == null ? void 0 : _a.resolve(sessionId); - this.pendingLogin = void 0; - } else { - throw Error("LOGIN_SUCCESS did not provide sessionId"); - } - break; - case "REMOVE_VP_SUCCESS": - { - const viewport = viewports.get(body.viewPortId); - if (viewport) { - this.mapClientToServerViewport.delete(viewport.clientViewportId); - viewports.delete(body.viewPortId); - this.removeViewportFromVisualLinks(body.viewPortId); - } - } - break; - case SET_SELECTION_SUCCESS: - { - const viewport = this.viewports.get(body.vpId); - if (viewport) { - viewport.completeOperation(requestId); - } - } - break; - case CHANGE_VP_SUCCESS: - case DISABLE_VP_SUCCESS: - if (viewports.has(body.viewPortId)) { - const viewport = this.viewports.get(body.viewPortId); - if (viewport) { - const response = viewport.completeOperation(requestId); - if (response !== void 0) { - this.postMessageToClient(response); - if (debugEnabled3) { - debug3(\`postMessageToClient \${JSON.stringify(response)}\`); - } - } - } - } - break; - case ENABLE_VP_SUCCESS: - { - const viewport = this.viewports.get(body.viewPortId); - if (viewport) { - const response = viewport.completeOperation(requestId); - if (response) { - this.postMessageToClient(response); - const [size, rows] = viewport.resume(); - this.postMessageToClient({ - clientViewportId: viewport.clientViewportId, - mode: "batch", - rows, - size, - type: "viewport-update" - }); - } - } - } - break; - case "TABLE_ROW": - { - const viewportRowMap = groupRowsByViewport(body.rows); - if (debugEnabled3) { - const [firstRow, secondRow] = body.rows; - if (body.rows.length === 0) { - debug3("handleMessageFromServer TABLE_ROW 0 rows"); - } else if ((firstRow == null ? void 0 : firstRow.rowIndex) === -1) { - if (body.rows.length === 1) { - if (firstRow.updateType === "SIZE") { - debug3( - \`handleMessageFromServer [\${firstRow.viewPortId}] TABLE_ROW SIZE ONLY \${firstRow.vpSize}\` - ); - } else { - debug3( - \`handleMessageFromServer [\${firstRow.viewPortId}] TABLE_ROW SIZE \${firstRow.vpSize} rowIdx \${firstRow.rowIndex}\` - ); - } - } else { - debug3( - \`handleMessageFromServer TABLE_ROW \${body.rows.length} rows, SIZE \${firstRow.vpSize}, [\${secondRow == null ? void 0 : secondRow.rowIndex}] - [\${(_b = body.rows[body.rows.length - 1]) == null ? void 0 : _b.rowIndex}]\` - ); - } - } else { - debug3( - \`handleMessageFromServer TABLE_ROW \${body.rows.length} rows [\${firstRow == null ? void 0 : firstRow.rowIndex}] - [\${(_c = body.rows[body.rows.length - 1]) == null ? void 0 : _c.rowIndex}]\` - ); - } - } - for (const [viewportId, rows] of Object.entries(viewportRowMap)) { - const viewport = viewports.get(viewportId); - if (viewport) { - viewport.updateRows(rows); - } else { - warn2 == null ? void 0 : warn2( - \`TABLE_ROW message received for non registered viewport \${viewportId}\` - ); - } - } - this.processUpdates(); - } - break; - case "CHANGE_VP_RANGE_SUCCESS": - { - const viewport = this.viewports.get(body.viewPortId); - if (viewport) { - const { from, to } = body; - if (true) { - info2 == null ? void 0 : info2(\`CHANGE_VP_RANGE_SUCCESS \${from} - \${to}\`); - } - viewport.completeOperation(requestId, from, to); - } - } - break; - case OPEN_TREE_SUCCESS: - case CLOSE_TREE_SUCCESS: - break; - case "CREATE_VISUAL_LINK_SUCCESS": - { - const viewport = this.viewports.get(body.childVpId); - const parentViewport = this.viewports.get(body.parentVpId); - if (viewport && parentViewport) { - const { childColumnName, parentColumnName } = body; - const response = viewport.completeOperation( - requestId, - childColumnName, - parentViewport.clientViewportId, - parentColumnName - ); - if (response) { - this.postMessageToClient(response); - } - } - } - break; - case "REMOVE_VISUAL_LINK_SUCCESS": - { - const viewport = this.viewports.get(body.childVpId); - if (viewport) { - const response = viewport.completeOperation( - requestId - ); - if (response) { - this.postMessageToClient(response); - } - } - } - break; - case "VP_VISUAL_LINKS_RESP": - { - const activeLinkDescriptors = this.getActiveLinks(body.links); - const viewport = this.viewports.get(body.vpId); - if (activeLinkDescriptors.length && viewport) { - const linkDescriptorsWithLabels = addLabelsToLinks( - activeLinkDescriptors, - this.viewports - ); - const [clientMessage, pendingLink] = viewport.setLinks( - linkDescriptorsWithLabels - ); - this.postMessageToClient(clientMessage); - if (pendingLink) { - const { link, parentClientVpId } = pendingLink; - const requestId2 = nextRequestId(); - const serverViewportId = this.mapClientToServerViewport.get(parentClientVpId); - if (serverViewportId) { - const message2 = viewport.createLink( - requestId2, - link.fromColumn, - serverViewportId, - link.toColumn - ); - this.sendMessageToServer(message2, requestId2); - } - } - } - } - break; - case "VIEW_PORT_MENUS_RESP": - if (body.menu.name) { - const viewport = this.viewports.get(body.vpId); - if (viewport) { - const clientMessage = viewport.setMenu(body.menu); - this.postMessageToClient(clientMessage); - } - } - break; - case "VP_EDIT_RPC_RESPONSE": - { - this.postMessageToClient({ - action: body.action, - requestId, - rpcName: body.rpcName, - type: "VP_EDIT_RPC_RESPONSE" - }); - } - break; - case "VP_EDIT_RPC_REJECT": - { - const viewport = this.viewports.get(body.vpId); - if (viewport) { - this.postMessageToClient({ - requestId, - type: "VP_EDIT_RPC_REJECT", - error: body.error - }); - } - } - break; - case "VIEW_PORT_MENU_REJ": { - console.log(\`send menu error back to client\`); - const { error: error4, rpcName, vpId } = body; - const viewport = this.viewports.get(vpId); - if (viewport) { - this.postMessageToClient({ - clientViewportId: viewport.clientViewportId, - error: error4, - rpcName, - type: "VIEW_PORT_MENU_REJ", - requestId - }); - } - break; - } - case "VIEW_PORT_MENU_RESP": - { - if (isSessionTableActionMessage(body)) { - const { action, rpcName } = body; - this.awaitResponseToMessage({ - type: "GET_TABLE_META", - table: action.table - }).then((response) => { - const tableSchema = createSchemaFromTableMetadata( - response - ); - this.postMessageToClient({ - rpcName, - type: "VIEW_PORT_MENU_RESP", - action: { - ...action, - tableSchema - }, - tableAlreadyOpen: this.isTableOpen(action.table), - requestId - }); - }); - } else { - const { action } = body; - this.postMessageToClient({ - type: "VIEW_PORT_MENU_RESP", - action: action || NO_ACTION, - tableAlreadyOpen: action !== null && this.isTableOpen(action.table), - requestId - }); - } - } - break; - case "RPC_RESP": - { - const { method, result } = body; - this.postMessageToClient({ - type: "RPC_RESP", - method, - result, - requestId - }); - } - break; - case "VIEW_PORT_RPC_REPONSE": - { - const { method, action } = body; - this.postMessageToClient({ - type: "VIEW_PORT_RPC_RESPONSE", - rpcName: method, - action, - requestId - }); - } - break; - case "ERROR": - error2(body.msg); - break; - default: - infoEnabled2 && info2(\`handleMessageFromServer \${body["type"]}.\`); - } - } - cacheTableMeta(messageBody) { - const { module, table } = messageBody.table; - const key = \`\${module}:\${table}\`; - let tableSchema = this.cachedTableSchemas.get(key); - if (!tableSchema) { - tableSchema = createSchemaFromTableMetadata(messageBody); - this.cachedTableSchemas.set(key, tableSchema); - } - return tableSchema; - } - isTableOpen(table) { - if (table) { - const tableName = table.table; - for (const viewport of this.viewports.values()) { - if (!viewport.suspended && viewport.table.table === tableName) { - return true; - } - } - } - } - // Eliminate links to suspended viewports - getActiveLinks(linkDescriptors) { - return linkDescriptors.filter((linkDescriptor) => { - const viewport = this.viewports.get(linkDescriptor.parentVpId); - return viewport && !viewport.suspended; - }); - } - processUpdates() { - this.viewports.forEach((viewport) => { - var _a; - if (viewport.hasUpdatesToProcess) { - const result = viewport.getClientRows(); - if (result !== NO_DATA_UPDATE) { - const [rows, mode] = result; - const size = viewport.getNewRowCount(); - if (size !== void 0 || rows && rows.length > 0) { - debugEnabled3 && debug3( - \`postMessageToClient #\${viewport.clientViewportId} viewport-update \${mode}, \${(_a = rows == null ? void 0 : rows.length) != null ? _a : "no"} rows, size \${size}\` - ); - if (mode) { - this.postMessageToClient({ - clientViewportId: viewport.clientViewportId, - mode, - rows, - size, - type: "viewport-update" - }); - } - } - } - } - }); - } -}; - -// src/websocket-connection.ts -var { debug: debug4, debugEnabled: debugEnabled4, error: error3, info: info3, infoEnabled: infoEnabled3, warn: warn3 } = logger( - "websocket-connection" -); -var WS = "ws"; -var isWebsocketUrl = (url) => url.startsWith(WS + "://") || url.startsWith(WS + "s://"); -var connectionAttemptStatus = {}; -var setWebsocket = Symbol("setWebsocket"); -var connectionCallback = Symbol("connectionCallback"); -async function connect(connectionString, protocol, callback, retryLimitDisconnect = 10, retryLimitStartup = 5) { - connectionAttemptStatus[connectionString] = { - status: "connecting", - connect: { - allowed: retryLimitStartup, - remaining: retryLimitStartup - }, - reconnect: { - allowed: retryLimitDisconnect, - remaining: retryLimitDisconnect - } - }; - return makeConnection(connectionString, protocol, callback); -} -async function reconnect(connection) { - throw Error("connection broken"); -} -async function makeConnection(url, protocol, callback, connection) { - const { - status: currentStatus, - connect: connectStatus, - reconnect: reconnectStatus - } = connectionAttemptStatus[url]; - const trackedStatus = currentStatus === "connecting" ? connectStatus : reconnectStatus; - try { - callback({ type: "connection-status", status: "connecting" }); - const reconnecting = typeof connection !== "undefined"; - const ws = await createWebsocket(url, protocol); - console.info( - "%c\u26A1 %cconnected", - "font-size: 24px;color: green;font-weight: bold;", - "color:green; font-size: 14px;" - ); - if (connection !== void 0) { - connection[setWebsocket](ws); - } - const websocketConnection = connection != null ? connection : new WebsocketConnection(ws, url, protocol, callback); - const status = reconnecting ? "reconnected" : "connection-open-awaiting-session"; - callback({ type: "connection-status", status }); - websocketConnection.status = status; - trackedStatus.remaining = trackedStatus.allowed; - return websocketConnection; - } catch (err) { - const retry = --trackedStatus.remaining > 0; - callback({ - type: "connection-status", - status: "disconnected", - reason: "failed to connect", - retry - }); - if (retry) { - return makeConnectionIn(url, protocol, callback, connection, 2e3); - } else { - throw Error("Failed to establish connection"); - } - } -} -var makeConnectionIn = (url, protocol, callback, connection, delay) => new Promise((resolve) => { - setTimeout(() => { - resolve(makeConnection(url, protocol, callback, connection)); - }, delay); -}); -var createWebsocket = (connectionString, protocol) => new Promise((resolve, reject) => { - const websocketUrl = isWebsocketUrl(connectionString) ? connectionString : \`wss://\${connectionString}\`; - if (infoEnabled3 && protocol !== void 0) { - info3(\`WebSocket Protocol \${protocol == null ? void 0 : protocol.toString()}\`); - } - const ws = new WebSocket(websocketUrl, protocol); - ws.onopen = () => resolve(ws); - ws.onerror = (evt) => reject(evt); -}); -var closeWarn = () => { - warn3 == null ? void 0 : warn3(\`Connection cannot be closed, socket not yet opened\`); -}; -var sendWarn = (msg) => { - warn3 == null ? void 0 : warn3(\`Message cannot be sent, socket closed \${msg.body.type}\`); -}; -var parseMessage = (message) => { - try { - return JSON.parse(message); - } catch (e) { - throw Error(\`Error parsing JSON response from server \${message}\`); - } -}; -var WebsocketConnection = class { - constructor(ws, url, protocol, callback) { - this.close = closeWarn; - this.requiresLogin = true; - this.send = sendWarn; - this.status = "ready"; - this.messagesCount = 0; - this.connectionMetricsInterval = null; - this.handleWebsocketMessage = (evt) => { - const vuuMessageFromServer = parseMessage(evt.data); - this.messagesCount += 1; - if (true) { - if (debugEnabled4 && vuuMessageFromServer.body.type !== "HB") { - debug4 == null ? void 0 : debug4(\`<<< \${vuuMessageFromServer.body.type}\`); - } - } - this[connectionCallback](vuuMessageFromServer); - }; - this.url = url; - this.protocol = protocol; - this[connectionCallback] = callback; - this[setWebsocket](ws); - } - reconnect() { - reconnect(this); - } - [(connectionCallback, setWebsocket)](ws) { - const callback = this[connectionCallback]; - ws.onmessage = (evt) => { - this.status = "connected"; - ws.onmessage = this.handleWebsocketMessage; - this.handleWebsocketMessage(evt); - }; - this.connectionMetricsInterval = setInterval(() => { - callback({ - type: "connection-metrics", - messagesLength: this.messagesCount - }); - this.messagesCount = 0; - }, 2e3); - ws.onerror = () => { - error3(\`\u26A1 connection error\`); - callback({ - type: "connection-status", - status: "disconnected", - reason: "error" - }); - if (this.connectionMetricsInterval) { - clearInterval(this.connectionMetricsInterval); - this.connectionMetricsInterval = null; - } - if (this.status === "connection-open-awaiting-session") { - error3( - \`Websocket connection lost before Vuu session established, check websocket configuration\` - ); - } else if (this.status !== "closed") { - reconnect(this); - this.send = queue; - } - }; - ws.onclose = () => { - info3 == null ? void 0 : info3(\`\u26A1 connection close\`); - callback({ - type: "connection-status", - status: "disconnected", - reason: "close" - }); - if (this.connectionMetricsInterval) { - clearInterval(this.connectionMetricsInterval); - this.connectionMetricsInterval = null; - } - if (this.status !== "closed") { - reconnect(this); - this.send = queue; - } - }; - const send = (msg) => { - if (true) { - if (debugEnabled4 && msg.body.type !== "HB_RESP") { - debug4 == null ? void 0 : debug4(\`>>> \${msg.body.type}\`); - } - } - ws.send(JSON.stringify(msg)); - }; - const queue = (msg) => { - info3 == null ? void 0 : info3(\`TODO queue message until websocket reconnected \${msg.body.type}\`); - }; - this.send = send; - this.close = () => { - this.status = "closed"; - ws.close(); - this.close = closeWarn; - this.send = sendWarn; - info3 == null ? void 0 : info3("close websocket"); - }; - } -}; - -// src/worker.ts -var server; -var { info: info4, infoEnabled: infoEnabled4 } = logger("worker"); -async function connectToServer(url, protocol, token, username, onConnectionStatusChange, retryLimitDisconnect, retryLimitStartup) { - const connection = await connect( - url, - protocol, - // if this was called during connect, we would get a ReferenceError, but it will - // never be called until subscriptions have been made, so this is safe. - //TODO do we need to listen in to the connection messages here so we can lock back in, in the event of a reconnenct ? - (msg) => { - if (isConnectionQualityMetrics(msg)) { - postMessage({ type: "connection-metrics", messages: msg }); - } else if (isConnectionStatusMessage(msg)) { - onConnectionStatusChange(msg); - if (msg.status === "reconnected") { - server.reconnect(); - } - } else { - server.handleMessageFromServer(msg); - } - }, - retryLimitDisconnect, - retryLimitStartup - ); - server = new ServerProxy(connection, (msg) => sendMessageToClient(msg)); - if (connection.requiresLogin) { - await server.login(token, username); - } -} -function sendMessageToClient(message) { - postMessage(message); -} -var handleMessageFromClient = async ({ - data: message -}) => { - switch (message.type) { - case "connect": - await connectToServer( - message.url, - message.protocol, - message.token, - message.username, - postMessage, - message.retryLimitDisconnect, - message.retryLimitStartup - ); - postMessage({ type: "connected" }); - break; - case "subscribe": - infoEnabled4 && info4(\`client subscribe: \${JSON.stringify(message)}\`); - server.subscribe(message); - break; - case "unsubscribe": - infoEnabled4 && info4(\`client unsubscribe: \${JSON.stringify(message)}\`); - server.unsubscribe(message.viewport); - break; - default: - infoEnabled4 && info4(\`client message: \${JSON.stringify(message)}\`); - server.handleMessageFromClient(message); - } -}; -self.addEventListener("message", handleMessageFromClient); -postMessage({ type: "ready" }); + \`),Error(\`KeySet, no key found for rowIndex \${e}\`);return t}toDebugString(){return Array.from(this.keys.entries()).map((e,t)=>\`\${e}=>\${t}\`).join(",")}};var{SELECTED:\$t}=\$,w={False:0,True:1,First:2,Last:4};var rt=(r,e)=>e>=r[0]&&e<=r[1],ot=w.True+w.First+w.Last,it=w.True+w.First,at=w.True+w.Last,z=(r,e)=>{for(let t of r)if(typeof t=="number"){if(t===e)return ot}else if(rt(t,e))return e===t[0]?it:e===t[1]?at:w.True;return w.False};var he=r=>{if(r.every(t=>typeof t=="number"))return r;let e=[];for(let t of r)if(typeof t=="number")e.push(t);else for(let s=t[0];s<=t[1];s++)e.push(s);return e};var fe=r=>r.type==="VIEW_PORT_MENU_RESP"&&r.action!==null&&x(r.action.table),x=r=>r!==null&&typeof r=="object"&&"table"in r&&"module"in r?r.table.startsWith("session"):!1;var ut=["VIEW_PORT_MENUS_SELECT_RPC","VIEW_PORT_MENU_TABLE_RPC","VIEW_PORT_MENU_ROW_RPC","VIEW_PORT_MENU_CELL_RPC","VP_EDIT_CELL_RPC","VP_EDIT_ROW_RPC","VP_EDIT_ADD_ROW_RPC","VP_EDIT_DELETE_CELL_RPC","VP_EDIT_DELETE_ROW_RPC","VP_EDIT_SUBMIT_FORM_RPC"],me=r=>ut.includes(r.type),Ce=r=>r.type==="VIEW_PORT_RPC_CALL",A=({requestId:r,...e})=>[r,e],Re=r=>{let e=r.at(0);if(e.updateType==="SIZE"){if(r.length===1)return r;e=r.at(1)}let t=r.at(-1);return[e,t]},Se=r=>{let e={};for(let t of r)(e[t.viewPortId]||(e[t.viewPortId]=[])).push(t);return e};var H=({columns:r,dataTypes:e,key:t,table:s})=>({table:s,columns:r.map((n,o)=>({name:n,serverDataType:e[o]})),key:t});var Te="CHANGE_VP_SUCCESS";var be="CLOSE_TREE_NODE",Ee="CLOSE_TREE_SUCCESS";var we="CREATE_VP",Ve="DISABLE_VP",ve="DISABLE_VP_SUCCESS";var ye="ENABLE_VP",Me="ENABLE_VP_SUCCESS";var K="GET_VP_VISUAL_LINKS",_e="GET_VIEW_PORT_MENUS";var Ie="HB",De="HB_RESP",Pe="LOGIN",Le="OPEN_TREE_NODE",ke="OPEN_TREE_SUCCESS";var Oe="REMOVE_VP";var xe="SET_SELECTION_SUCCESS";var Ne=r=>{switch(r){case"TypeAheadRpcHandler":return"TYPEAHEAD";default:return"SIMUL"}};var Ue=[],R=b("array-backed-moving-window");function lt(r,e){if(!e||e.data.length!==r.data.length||e.sel!==r.sel)return!1;for(let t=0;t{var t;if((t=R.info)==null||t.call(R,\`setRowCount \${e}\`),e{let s=this.bufferSize*.25;return m(this,h).to-t0&&e-m(this,h).from0&&this.clientRange.from+this.rowsWithinRange===this.rowCount}outOfRange(e,t){let{from:s,to:n}=this.range;if(t=n)return!0}setAtIndex(e){let{rowIndex:t}=e,s=t-m(this,h).from;if(lt(e,this.internalData[s]))return!1;let n=this.isWithinClientRange(t);return(n||this.isWithinRange(t))&&(!this.internalData[s]&&n&&(this.rowsWithinRange+=1),this.internalData[s]=e),n}getAtIndex(e){return m(this,h).isWithin(e)&&this.internalData[e-m(this,h).from]!=null?this.internalData[e-m(this,h).from]:void 0}isWithinRange(e){return m(this,h).isWithin(e)}isWithinClientRange(e){return this.clientRange.isWithin(e)}setClientRange(e,t){var p;(p=R.debug)==null||p.call(R,\`setClientRange \${e} - \${t}\`);let s=this.clientRange.from,n=Math.min(this.clientRange.to,this.rowCount);if(e===s&&t===n)return[!1,Ue];let o=this.clientRange.copy();this.clientRange.from=e,this.clientRange.to=t,this.rowsWithinRange=0;for(let a=e;ao.to){let a=Math.max(e,o.to);i=this.internalData.slice(a-u,t-u)}else{let a=Math.min(o.from,t);i=this.internalData.slice(e-u,a-u)}return[this.bufferBreakout(e,t),i]}setRange(e,t){var s,n;if(e!==m(this,h).from||t!==m(this,h).to){(s=R.debug)==null||s.call(R,\`setRange \${e} - \${t}\`);let[o,i]=m(this,h).overlap(e,t),u=new Array(t-e);this.rowsWithinRange=0;for(let c=o;c=0;o--)if(e[o]!==void 0){n=e[o];break}return s&&n?[s.rowIndex,n.rowIndex]:[-1,-1]}};h=new WeakMap;var ct=[],{debug:f,debugEnabled:U,error:pt,info:d,infoEnabled:dt,warn:y}=b("viewport"),gt=({rowKey:r,updateType:e})=>e==="U"&&!r.startsWith("\$root"),W=[void 0,void 0],ht={count:0,mode:void 0,size:0,ts:0},q=class{constructor({aggregations:e,bufferSize:t=50,columns:s,filter:n,groupBy:o=[],table:i,range:u,sort:c,title:p,viewport:a,visualLink:l},g){this.batchMode=!0;this.hasUpdates=!1;this.pendingUpdates=[];this.pendingOperations=new Map;this.pendingRangeRequests=[];this.rowCountChanged=!1;this.selectedRows=[];this.useBatchMode=!0;this.lastUpdateStatus=ht;this.updateThrottleTimer=void 0;this.rangeMonitor=new k("ViewPort");this.disabled=!1;this.isTree=!1;this.status="";this.suspended=!1;this.suspendTimer=null;this.setLastSizeOnlyUpdateSize=e=>{this.lastUpdateStatus.size=e};this.setLastUpdate=e=>{let{ts:t,mode:s}=this.lastUpdateStatus,n=0;if(s===e){let o=Date.now();this.lastUpdateStatus.count+=1,this.lastUpdateStatus.ts=o,n=t===0?0:o-t}else this.lastUpdateStatus.count=1,this.lastUpdateStatus.ts=0,n=0;return this.lastUpdateStatus.mode=e,n};this.rangeRequestAlreadyPending=e=>{let{bufferSize:t}=this,s=t*.25,{from:n}=e;for(let{from:o,to:i}of this.pendingRangeRequests)if(n>=o&&n{this.updateThrottleTimer=void 0,this.lastUpdateStatus.count=3,this.postMessageToClient({clientViewportId:this.clientViewportId,mode:"size-only",size:this.lastUpdateStatus.size,type:"viewport-update"})};this.shouldThrottleMessage=e=>{let t=this.setLastUpdate(e);return e==="size-only"&&t>0&&t<500&&this.lastUpdateStatus.count>3};this.throttleMessage=e=>this.shouldThrottleMessage(e)?(d==null||d("throttling updates setTimeout to 2000"),this.updateThrottleTimer===void 0&&(this.updateThrottleTimer=setTimeout(this.sendThrottledSizeMessage,2e3)),!0):(this.updateThrottleTimer!==void 0&&(clearTimeout(this.updateThrottleTimer),this.updateThrottleTimer=void 0),!1);this.getNewRowCount=()=>{if(this.rowCountChanged&&this.dataWindow)return this.rowCountChanged=!1,this.dataWindow.rowCount};this.aggregations=e,this.bufferSize=t,this.clientRange=u,this.clientViewportId=a,this.columns=s,this.filter=n,this.groupBy=o,this.keys=new O(u),this.pendingLinkedParent=l,this.table=i,this.sort=c,this.title=p,dt&&(d==null||d(\`constructor #\${a} \${i.table} bufferSize=\${t}\`)),this.dataWindow=new N(this.clientRange,u,this.bufferSize),this.postMessageToClient=g}get hasUpdatesToProcess(){return this.suspended?!1:this.rowCountChanged||this.hasUpdates}get size(){var e;return(e=this.dataWindow.rowCount)!=null?e:0}subscribe(){let{filter:e}=this.filter;return this.status=this.status==="subscribed"?"resubscribing":"subscribing",{type:we,table:this.table,range:G(this.clientRange,this.bufferSize),aggregations:this.aggregations,columns:this.columns,sort:this.sort,groupBy:this.groupBy,filterSpec:{filter:e}}}handleSubscribed({viewPortId:e,aggregations:t,columns:s,filterSpec:n,range:o,sort:i,groupBy:u},c){return this.serverViewportId=e,this.status="subscribed",this.aggregations=t,this.columns=s,this.groupBy=u,this.isTree=u&&u.length>0,this.dataWindow.setRange(o.from,o.to),{aggregations:t,type:"subscribed",clientViewportId:this.clientViewportId,columns:s,filter:n,groupBy:u,range:o,sort:i,tableSchema:c}}awaitOperation(e,t){this.pendingOperations.set(e,t)}completeOperation(e,...t){var u;let{clientViewportId:s,pendingOperations:n}=this,o=n.get(e);if(!o){pt(\`no matching operation found to complete for requestId \${e}\`);return}let{type:i}=o;if(d==null||d(\`completeOperation \${i}\`),n.delete(e),i==="CHANGE_VP_RANGE"){let[c,p]=t;(u=this.dataWindow)==null||u.setRange(c,p);for(let a=this.pendingRangeRequests.length-1;a>=0;a--){let l=this.pendingRangeRequests[a];if(l.requestId===e){l.acked=!0;break}else y==null||y("range requests sent faster than they are being ACKed")}}else if(i==="config"){let{aggregations:c,columns:p,filter:a,groupBy:l,sort:g}=o.data;return this.aggregations=c,this.columns=p,this.filter=a,this.groupBy=l,this.sort=g,l.length>0?this.isTree=!0:this.isTree&&(this.isTree=!1),f==null||f(\`config change confirmed, isTree : \${this.isTree}\`),{clientViewportId:s,type:i,config:o.data}}else{if(i==="groupBy")return this.isTree=o.data.length>0,this.groupBy=o.data,f==null||f(\`groupBy change confirmed, isTree : \${this.isTree}\`),{clientViewportId:s,type:i,groupBy:o.data};if(i==="columns")return this.columns=o.data,{clientViewportId:s,type:i,columns:o.data};if(i==="filter")return this.filter=o.data,{clientViewportId:s,type:i,filter:o.data};if(i==="aggregate")return this.aggregations=o.data,{clientViewportId:s,type:"aggregate",aggregations:this.aggregations};if(i==="sort")return this.sort=o.data,{clientViewportId:s,type:i,sort:this.sort};if(i!=="selection"){if(i==="disable")return this.disabled=!0,{type:"disabled",clientViewportId:s};if(i==="enable")return this.disabled=!1,{type:"enabled",clientViewportId:s};if(i==="CREATE_VISUAL_LINK"){let[c,p,a]=t;return this.linkedParent={colName:c,parentViewportId:p,parentColName:a},this.pendingLinkedParent=void 0,{type:"vuu-link-created",clientViewportId:s,colName:c,parentViewportId:p,parentColName:a}}else if(i==="REMOVE_VISUAL_LINK")return this.linkedParent=void 0,{type:"vuu-link-removed",clientViewportId:s}}}}rangeRequest(e,t){U&&this.rangeMonitor.set(t);let s="CHANGE_VP_RANGE";if(this.dataWindow){let[n,o]=this.dataWindow.setClientRange(t.from,t.to),i,u=this.dataWindow.rowCount||void 0,c=n&&!this.rangeRequestAlreadyPending(t)?{type:s,viewPortId:this.serverViewportId,...G(t,this.bufferSize,u)}:null;if(c){U&&(f==null||f(\`create CHANGE_VP_RANGE: [\${c.from} - \${c.to}]\`)),this.awaitOperation(e,{type:s});let a=this.pendingRangeRequests.at(-1);if(a)if(a.acked)console.warn("Range Request before previous request is filled");else{let{from:l,to:g}=a;this.dataWindow.outOfRange(l,g)?i={clientViewportId:this.clientViewportId,type:"debounce-begin"}:y==null||y("Range Request before previous request is acked")}this.pendingRangeRequests.push({...c,requestId:e}),this.useBatchMode&&(this.batchMode=!0)}else o.length>0&&(this.batchMode=!1);this.keys.reset(this.dataWindow.clientRange);let p=this.isTree?j:J;return o.length?[c,o.map(a=>p(a,this.keys,this.selectedRows))]:i?[c,void 0,i]:[c]}else return[null]}setLinks(e){return this.links=e,[{type:"vuu-links",links:e,clientViewportId:this.clientViewportId},this.pendingLinkedParent]}setMenu(e){return{type:"vuu-menu",menu:e,clientViewportId:this.clientViewportId}}openTreeNode(e,t){return this.useBatchMode&&(this.batchMode=!0),{type:Le,vpId:this.serverViewportId,treeKey:t.key}}closeTreeNode(e,t){return this.useBatchMode&&(this.batchMode=!0),{type:be,vpId:this.serverViewportId,treeKey:t.key}}createLink(e,t,s,n){let o={type:"CREATE_VISUAL_LINK",parentVpId:s,childVpId:this.serverViewportId,parentColumnName:n,childColumnName:t};return this.awaitOperation(e,o),this.useBatchMode&&(this.batchMode=!0),o}removeLink(e){let t={type:"REMOVE_VISUAL_LINK",childVpId:this.serverViewportId};return this.awaitOperation(e,t),t}suspend(){this.suspended=!0,d==null||d("suspend")}resume(){return this.suspended=!1,U&&(f==null||f(\`resume: \${this.currentData()}\`)),[this.size,this.currentData()]}currentData(){let e=[];if(this.dataWindow){let t=this.dataWindow.getData(),{keys:s}=this,n=this.isTree?j:J;for(let o of t)o&&e.push(n(o,s,this.selectedRows))}return e}enable(e){return this.awaitOperation(e,{type:"enable"}),d==null||d(\`enable: \${this.serverViewportId}\`),{type:ye,viewPortId:this.serverViewportId}}disable(e){return this.awaitOperation(e,{type:"disable"}),d==null||d(\`disable: \${this.serverViewportId}\`),this.suspended=!1,{type:Ve,viewPortId:this.serverViewportId}}columnRequest(e,t){return this.awaitOperation(e,{type:"columns",data:t}),f==null||f(\`columnRequest: \${t}\`),this.createRequest({columns:t})}filterRequest(e,t){this.awaitOperation(e,{type:"filter",data:t}),this.useBatchMode&&(this.batchMode=!0);let{filter:s}=t;return d==null||d(\`filterRequest: \${s}\`),this.createRequest({filterSpec:{filter:s}})}setConfig(e,t){this.awaitOperation(e,{type:"config",data:t});let{filter:s,...n}=t;return this.useBatchMode&&(this.batchMode=!0),U?f==null||f(\`setConfig \${JSON.stringify(t)}\`):d==null||d("setConfig"),this.createRequest({...n,filterSpec:typeof(s==null?void 0:s.filter)=="string"?{filter:s.filter}:{filter:""}},!0)}aggregateRequest(e,t){return this.awaitOperation(e,{type:"aggregate",data:t}),d==null||d(\`aggregateRequest: \${t}\`),this.createRequest({aggregations:t})}sortRequest(e,t){return this.awaitOperation(e,{type:"sort",data:t}),d==null||d(\`sortRequest: \${JSON.stringify(t.sortDefs)}\`),this.createRequest({sort:t})}groupByRequest(e,t=ct){var s;return this.awaitOperation(e,{type:"groupBy",data:t}),this.useBatchMode&&(this.batchMode=!0),this.isTree||(s=this.dataWindow)==null||s.clear(),this.createRequest({groupBy:t})}selectRequest(e,t){return this.selectedRows=t,this.awaitOperation(e,{type:"selection",data:t}),d==null||d(\`selectRequest: \${t}\`),{type:"SET_SELECTION",vpId:this.serverViewportId,selection:he(t)}}removePendingRangeRequest(e,t){for(let s=this.pendingRangeRequests.length-1;s>=0;s--){let{from:n,to:o}=this.pendingRangeRequests[s],i=!0;if(e>=n&&en&&t0){e=[],t="update";for(let i of this.pendingUpdates)e.push(o(i,s,n));this.pendingUpdates.length=0}else{let i=this.dataWindow.getData();if(this.dataWindow.hasAllRowsWithinRange){e=[],t="batch";for(let u of i)e.push(o(u,s,n));this.batchMode=!1}}this.hasUpdates=!1}return this.throttleMessage(t)?W:[e,t]}createRequest(e,t=!1){return t?{type:"CHANGE_VP",viewPortId:this.serverViewportId,...e}:{type:"CHANGE_VP",viewPortId:this.serverViewportId,aggregations:this.aggregations,columns:this.columns,sort:this.sort,groupBy:this.groupBy,filterSpec:{filter:this.filter.filter},...e}}},J=({rowIndex:r,rowKey:e,sel:t,data:s},n,o)=>[r,n.keyFor(r),!0,!1,0,0,e,t?z(o,r):0].concat(s),j=({rowIndex:r,rowKey:e,sel:t,data:s},n,o)=>{let[i,u,,c,,p,...a]=s;return[r,n.keyFor(r),c,u,i,p,e,t?z(o,r):0].concat(a)};var We=1;var{debug:V,debugEnabled:Q,error:M,info:T,infoEnabled:ft,warn:Y}=b("server-proxy"),C=()=>\`\${We++}\`,mt={},Ct=r=>r.disabled!==!0&&r.suspended!==!0,Rt={type:"NO_ACTION"},St=(r,e,t)=>r.map(s=>s.parentVpId===e?{...s,label:t}:s);function Tt(r,e){return r.map(t=>{let{parentVpId:s}=t,n=e.get(s);if(n)return{...t,parentClientVpId:n.clientViewportId,label:n.title};throw Error("addLabelsToLinks viewport not found")})}var F=class{constructor(e,t){this.authToken="";this.user="user";this.pendingRequests=new Map;this.queuedRequests=[];this.cachedTableMetaRequests=new Map;this.cachedTableSchemas=new Map;this.connection=e,this.postMessageToClient=t,this.viewports=new Map,this.mapClientToServerViewport=new Map}async reconnect(){await this.login(this.authToken);let[e,t]=le(Array.from(this.viewports.values()),Ct);this.viewports.clear(),this.mapClientToServerViewport.clear();let s=n=>{n.forEach(o=>{let{clientViewportId:i}=o;this.viewports.set(i,o),this.sendMessageToServer(o.subscribe(),i)})};s(e),setTimeout(()=>{s(t)},2e3)}async login(e,t="user"){if(e)return this.authToken=e,this.user=t,new Promise((s,n)=>{this.sendMessageToServer({type:Pe,token:this.authToken,user:t},""),this.pendingLogin={resolve:s,reject:n}});this.authToken===""&&M("login, cannot login until auth token has been obtained")}subscribe(e){if(this.mapClientToServerViewport.has(e.viewport))M(\`spurious subscribe call \${e.viewport}\`);else{let t=this.getTableMeta(e.table),s=new q(e,this.postMessageToClient);this.viewports.set(e.viewport,s);let n=this.awaitResponseToMessage(s.subscribe(),e.viewport);Promise.all([n,t]).then(([i,u])=>{let{viewPortId:c}=i,{status:p}=s;e.viewport!==c&&(this.viewports.delete(e.viewport),this.viewports.set(c,s)),this.mapClientToServerViewport.set(e.viewport,c);let a=s.handleSubscribed(i,u);a&&(this.postMessageToClient(a),Q&&V(\`post DataSourceSubscribedMessage to client: \${JSON.stringify(a)}\`)),s.disabled&&this.disableViewport(s),this.queuedRequests.length>0&&this.processQueuedRequests(),p==="subscribing"&&!x(s.table)&&(this.sendMessageToServer({type:K,vpId:c}),this.sendMessageToServer({type:_e,vpId:c}),Array.from(this.viewports.entries()).filter(([l,{disabled:g}])=>l!==c&&!g).forEach(([l])=>{this.sendMessageToServer({type:K,vpId:l})}))})}}processQueuedRequests(){let e={};for(;this.queuedRequests.length;){let t=this.queuedRequests.pop();if(t){let{clientViewportId:s,message:n,requestId:o}=t;if(n.type==="CHANGE_VP_RANGE"){if(e.CHANGE_VP_RANGE)continue;e.CHANGE_VP_RANGE=!0;let i=this.mapClientToServerViewport.get(s);i&&this.sendMessageToServer({...n,viewPortId:i},o)}}}}unsubscribe(e){let t=this.mapClientToServerViewport.get(e);t?(T==null||T(\`Unsubscribe Message (Client to Server): + \${t}\`),this.sendMessageToServer({type:Oe,viewPortId:t})):M(\`failed to unsubscribe client viewport \${e}, viewport not found\`)}getViewportForClient(e,t=!0){let s=this.mapClientToServerViewport.get(e);if(s){let n=this.viewports.get(s);if(n)return n;if(t)throw Error(\`Viewport not found for client viewport \${e}\`);return null}else{if(this.viewports.has(e))return this.viewports.get(e);if(t)throw Error(\`Viewport server id not found for client viewport \${e}\`);return null}}setViewRange(e,t){let s=C(),[n,o,i]=e.rangeRequest(s,t.range);T==null||T(\`setViewRange \${t.range.from} - \${t.range.to}\`),n&&(this.sendIfReady(n,s,e.status==="subscribed")||this.queuedRequests.push({clientViewportId:t.viewport,message:n,requestId:s})),o?(T==null||T(\`setViewRange \${o.length} rows returned from cache\`),this.postMessageToClient({mode:"batch",type:"viewport-update",clientViewportId:e.clientViewportId,rows:o})):i&&this.postMessageToClient(i)}setConfig(e,t){let s=C(),n=e.setConfig(s,t.config);this.sendIfReady(n,s,e.status==="subscribed")}aggregate(e,t){let s=C(),n=e.aggregateRequest(s,t.aggregations);this.sendIfReady(n,s,e.status==="subscribed")}sort(e,t){let s=C(),n=e.sortRequest(s,t.sort);this.sendIfReady(n,s,e.status==="subscribed")}groupBy(e,t){let s=C(),n=e.groupByRequest(s,t.groupBy);this.sendIfReady(n,s,e.status==="subscribed")}filter(e,t){let s=C(),{filter:n}=t,o=e.filterRequest(s,n);this.sendIfReady(o,s,e.status==="subscribed")}setColumns(e,t){let s=C(),{columns:n}=t,o=e.columnRequest(s,n);this.sendIfReady(o,s,e.status==="subscribed")}setTitle(e,t){e&&(e.title=t.title,this.updateTitleOnVisualLinks(e))}select(e,t){let s=C(),{selected:n}=t,o=e.selectRequest(s,n);this.sendIfReady(o,s,e.status==="subscribed")}disableViewport(e){let t=C(),s=e.disable(t);this.sendIfReady(s,t,e.status==="subscribed")}enableViewport(e){if(e.disabled){let t=C(),s=e.enable(t);this.sendIfReady(s,t,e.status==="subscribed")}}suspendViewport(e){e.suspend(),e.suspendTimer=setTimeout(()=>{T==null||T("suspendTimer expired, escalate suspend to disable"),this.disableViewport(e)},3e3)}resumeViewport(e){e.suspendTimer&&(V==null||V("clear suspend timer"),clearTimeout(e.suspendTimer),e.suspendTimer=null);let[t,s]=e.resume();V==null||V(\`resumeViewport size \${t}, \${s.length} rows sent to client\`),this.postMessageToClient({clientViewportId:e.clientViewportId,mode:"batch",rows:s,size:t,type:"viewport-update"})}openTreeNode(e,t){if(e.serverViewportId){let s=C();this.sendIfReady(e.openTreeNode(s,t),s,e.status==="subscribed")}}closeTreeNode(e,t){if(e.serverViewportId){let s=C();this.sendIfReady(e.closeTreeNode(s,t),s,e.status==="subscribed")}}createLink(e,t){let{parentClientVpId:s,parentColumnName:n,childColumnName:o}=t,i=C(),u=this.mapClientToServerViewport.get(s);if(u){let c=e.createLink(i,o,u,n);this.sendMessageToServer(c,i)}else M("ServerProxy unable to create link, viewport not found")}removeLink(e){let t=C(),s=e.removeLink(t);this.sendMessageToServer(s,t)}updateTitleOnVisualLinks(e){var n;let{serverViewportId:t,title:s}=e;for(let o of this.viewports.values())if(o!==e&&o.links&&t&&s&&(n=o.links)!=null&&n.some(i=>i.parentVpId===t)){let[i]=o.setLinks(St(o.links,t,s));this.postMessageToClient(i)}}removeViewportFromVisualLinks(e){var t;for(let s of this.viewports.values())if((t=s.links)!=null&&t.some(({parentVpId:n})=>n===e)){let[n]=s.setLinks(s.links.filter(({parentVpId:o})=>o!==e));this.postMessageToClient(n)}}menuRpcCall(e){let t=this.getViewportForClient(e.vpId,!1);if(t!=null&&t.serverViewportId){let[s,n]=A(e);this.sendMessageToServer({...n,vpId:t.serverViewportId},s)}}viewportRpcCall(e){let t=this.getViewportForClient(e.vpId,!1);if(t!=null&&t.serverViewportId){let[s,n]=A(e);this.sendMessageToServer({...n,vpId:t.serverViewportId,namedParams:{}},s)}}rpcCall(e){let[t,s]=A(e),n=Ne(s.service);this.sendMessageToServer(s,t,{module:n})}handleMessageFromClient(e){var t;if(ge(e))if(e.type==="disable"){let s=this.getViewportForClient(e.viewport,!1);return s!==null?this.disableViewport(s):void 0}else{let s=this.getViewportForClient(e.viewport);switch(e.type){case"setViewRange":return this.setViewRange(s,e);case"config":return this.setConfig(s,e);case"aggregate":return this.aggregate(s,e);case"sort":return this.sort(s,e);case"groupBy":return this.groupBy(s,e);case"filter":return this.filter(s,e);case"select":return this.select(s,e);case"suspend":return this.suspendViewport(s);case"resume":return this.resumeViewport(s);case"enable":return this.enableViewport(s);case"openTreeNode":return this.openTreeNode(s,e);case"closeTreeNode":return this.closeTreeNode(s,e);case"createLink":return this.createLink(s,e);case"removeLink":return this.removeLink(s);case"setColumns":return this.setColumns(s,e);case"setTitle":return this.setTitle(s,e);default:}}else{if(Ce(e))return this.viewportRpcCall(e);if(me(e))return this.menuRpcCall(e);{let{type:s,requestId:n}=e;switch(s){case"GET_TABLE_LIST":{(t=this.tableList)!=null||(this.tableList=this.awaitResponseToMessage({type:s},n)),this.tableList.then(o=>{this.postMessageToClient({type:"TABLE_LIST_RESP",tables:o.tables,requestId:n})});return}case"GET_TABLE_META":{this.getTableMeta(e.table,n).then(o=>{o&&this.postMessageToClient({type:"TABLE_META_RESP",tableSchema:o,requestId:n})});return}case"RPC_CALL":return this.rpcCall(e);default:}}}M(\`Vuu ServerProxy Unexpected message from client \${JSON.stringify(e)}\`)}getTableMeta(e,t=C()){if(x(e))return Promise.resolve(void 0);let s=\`\${e.module}:\${e.table}\`,n=this.cachedTableMetaRequests.get(s);return n||(n=this.awaitResponseToMessage({type:"GET_TABLE_META",table:e},t),this.cachedTableMetaRequests.set(s,n)),n==null?void 0:n.then(o=>this.cacheTableMeta(o))}awaitResponseToMessage(e,t=C()){return new Promise((s,n)=>{this.sendMessageToServer(e,t),this.pendingRequests.set(t,{reject:n,resolve:s})})}sendIfReady(e,t,s=!0){return s&&this.sendMessageToServer(e,t),s}sendMessageToServer(e,t=\`\${We++}\`,s=mt){let{module:n="CORE"}=s;this.authToken&&this.connection.send({requestId:t,sessionId:this.sessionId,token:this.authToken,user:this.user,module:n,body:e})}handleMessageFromServer(e){var u;let{body:t,requestId:s,sessionId:n}=e,o=this.pendingRequests.get(s);if(o){let{resolve:a}=o;this.pendingRequests.delete(s),a(t);return}let{viewports:i}=this;switch(t.type){case Ie:this.sendMessageToServer({type:De,ts:+new Date},"NA");break;case"LOGIN_SUCCESS":if(n)this.sessionId=n,(u=this.pendingLogin)==null||u.resolve(n),this.pendingLogin=void 0;else throw Error("LOGIN_SUCCESS did not provide sessionId");break;case"REMOVE_VP_SUCCESS":{let a=i.get(t.viewPortId);a&&(this.mapClientToServerViewport.delete(a.clientViewportId),i.delete(t.viewPortId),this.removeViewportFromVisualLinks(t.viewPortId))}break;case xe:{let a=this.viewports.get(t.vpId);a&&a.completeOperation(s)}break;case Te:case ve:if(i.has(t.viewPortId)){let a=this.viewports.get(t.viewPortId);if(a){let l=a.completeOperation(s);l!==void 0&&(this.postMessageToClient(l),Q&&V(\`postMessageToClient \${JSON.stringify(l)}\`))}}break;case Me:{let a=this.viewports.get(t.viewPortId);if(a){let l=a.completeOperation(s);if(l){this.postMessageToClient(l);let[g,S]=a.resume();this.postMessageToClient({clientViewportId:a.clientViewportId,mode:"batch",rows:S,size:g,type:"viewport-update"})}}}break;case"TABLE_ROW":{let a=Se(t.rows);for(let[l,g]of Object.entries(a)){let S=i.get(l);S?S.updateRows(g):Y==null||Y(\`TABLE_ROW message received for non registered viewport \${l}\`)}this.processUpdates()}break;case"CHANGE_VP_RANGE_SUCCESS":{let a=this.viewports.get(t.viewPortId);if(a){let{from:l,to:g}=t;a.completeOperation(s,l,g)}}break;case ke:case Ee:break;case"CREATE_VISUAL_LINK_SUCCESS":{let a=this.viewports.get(t.childVpId),l=this.viewports.get(t.parentVpId);if(a&&l){let{childColumnName:g,parentColumnName:S}=t,I=a.completeOperation(s,g,l.clientViewportId,S);I&&this.postMessageToClient(I)}}break;case"REMOVE_VISUAL_LINK_SUCCESS":{let a=this.viewports.get(t.childVpId);if(a){let l=a.completeOperation(s);l&&this.postMessageToClient(l)}}break;case"VP_VISUAL_LINKS_RESP":{let a=this.getActiveLinks(t.links),l=this.viewports.get(t.vpId);if(a.length&&l){let g=Tt(a,this.viewports),[S,I]=l.setLinks(g);if(this.postMessageToClient(S),I){let{link:ne,parentClientVpId:Ke}=I,re=C(),oe=this.mapClientToServerViewport.get(Ke);if(oe){let Je=l.createLink(re,ne.fromColumn,oe,ne.toColumn);this.sendMessageToServer(Je,re)}}}}break;case"VIEW_PORT_MENUS_RESP":if(t.menu.name){let a=this.viewports.get(t.vpId);if(a){let l=a.setMenu(t.menu);this.postMessageToClient(l)}}break;case"VP_EDIT_RPC_RESPONSE":this.postMessageToClient({action:t.action,requestId:s,rpcName:t.rpcName,type:"VP_EDIT_RPC_RESPONSE"});break;case"VP_EDIT_RPC_REJECT":this.viewports.get(t.vpId)&&this.postMessageToClient({requestId:s,type:"VP_EDIT_RPC_REJECT",error:t.error});break;case"VIEW_PORT_MENU_REJ":{console.log("send menu error back to client");let{error:a,rpcName:l,vpId:g}=t,S=this.viewports.get(g);S&&this.postMessageToClient({clientViewportId:S.clientViewportId,error:a,rpcName:l,type:"VIEW_PORT_MENU_REJ",requestId:s});break}case"VIEW_PORT_MENU_RESP":if(fe(t)){let{action:a,rpcName:l}=t;this.awaitResponseToMessage({type:"GET_TABLE_META",table:a.table}).then(g=>{let S=H(g);this.postMessageToClient({rpcName:l,type:"VIEW_PORT_MENU_RESP",action:{...a,tableSchema:S},tableAlreadyOpen:this.isTableOpen(a.table),requestId:s})})}else{let{action:a}=t;this.postMessageToClient({type:"VIEW_PORT_MENU_RESP",action:a||Rt,tableAlreadyOpen:a!==null&&this.isTableOpen(a.table),requestId:s})}break;case"RPC_RESP":{let{method:a,result:l}=t;this.postMessageToClient({type:"RPC_RESP",method:a,result:l,requestId:s})}break;case"VIEW_PORT_RPC_REPONSE":{let{method:a,action:l}=t;this.postMessageToClient({type:"VIEW_PORT_RPC_RESPONSE",rpcName:a,action:l,requestId:s})}break;case"ERROR":M(t.msg);break;default:ft&&T(\`handleMessageFromServer \${t.type}.\`)}}cacheTableMeta(e){let{module:t,table:s}=e.table,n=\`\${t}:\${s}\`,o=this.cachedTableSchemas.get(n);return o||(o=H(e),this.cachedTableSchemas.set(n,o)),o}isTableOpen(e){if(e){let t=e.table;for(let s of this.viewports.values())if(!s.suspended&&s.table.table===t)return!0}}getActiveLinks(e){return e.filter(t=>{let s=this.viewports.get(t.parentVpId);return s&&!s.suspended})}processUpdates(){this.viewports.forEach(e=>{var t;if(e.hasUpdatesToProcess){let s=e.getClientRows();if(s!==W){let[n,o]=s,i=e.getNewRowCount();(i!==void 0||n&&n.length>0)&&(Q&&V(\`postMessageToClient #\${e.clientViewportId} viewport-update \${o}, \${(t=n==null?void 0:n.length)!=null?t:"no"} rows, size \${i}\`),o&&this.postMessageToClient({clientViewportId:e.clientViewportId,mode:o,rows:n,size:i,type:"viewport-update"}))}}})}};var{debug:us,debugEnabled:ls,error:qe,info:E,infoEnabled:bt,warn:_}=b("websocket-connection"),Fe="ws",Et=r=>r.startsWith(Fe+"://")||r.startsWith(Fe+"s://"),Ge={},X=Symbol("setWebsocket"),B=Symbol("connectionCallback");async function ze(r,e,t,s=10,n=5){return Ge[r]={status:"connecting",connect:{allowed:n,remaining:n},reconnect:{allowed:s,remaining:s}},He(r,e,t)}async function Z(r){throw Error("connection broken")}async function He(r,e,t,s){let{status:n,connect:o,reconnect:i}=Ge[r],u=n==="connecting"?o:i;try{t({type:"connection-status",status:"connecting"});let c=typeof s<"u",p=await Vt(r,e);console.info("%c\u26A1 %cconnected","font-size: 24px;color: green;font-weight: bold;","color:green; font-size: 14px;"),s!==void 0&&s[X](p);let a=s!=null?s:new ee(p,r,e,t),l=c?"reconnected":"connection-open-awaiting-session";return t({type:"connection-status",status:l}),a.status=l,u.remaining=u.allowed,a}catch{let p=--u.remaining>0;if(t({type:"connection-status",status:"disconnected",reason:"failed to connect",retry:p}),p)return wt(r,e,t,s,2e3);throw Error("Failed to establish connection")}}var wt=(r,e,t,s,n)=>new Promise(o=>{setTimeout(()=>{o(He(r,e,t,s))},n)}),Vt=(r,e)=>new Promise((t,s)=>{let n=Et(r)?r:\`wss://\${r}\`;bt&&e!==void 0&&E(\`WebSocket Protocol \${e==null?void 0:e.toString()}\`);let o=new WebSocket(n,e);o.onopen=()=>t(o),o.onerror=i=>s(i)}),Be=()=>{_==null||_("Connection cannot be closed, socket not yet opened")},\$e=r=>{_==null||_(\`Message cannot be sent, socket closed \${r.body.type}\`)},vt=r=>{try{return JSON.parse(r)}catch{throw Error(\`Error parsing JSON response from server \${r}\`)}},ee=class{constructor(e,t,s,n){this.close=Be;this.requiresLogin=!0;this.send=\$e;this.status="ready";this.messagesCount=0;this.connectionMetricsInterval=null;this.handleWebsocketMessage=e=>{let t=vt(e.data);this.messagesCount+=1,this[B](t)};this.url=t,this.protocol=s,this[B]=n,this[X](e)}reconnect(){Z(this)}[(B,X)](e){let t=this[B];e.onmessage=o=>{this.status="connected",e.onmessage=this.handleWebsocketMessage,this.handleWebsocketMessage(o)},this.connectionMetricsInterval=setInterval(()=>{t({type:"connection-metrics",messagesLength:this.messagesCount}),this.messagesCount=0},2e3),e.onerror=()=>{qe("\u26A1 connection error"),t({type:"connection-status",status:"disconnected",reason:"error"}),this.connectionMetricsInterval&&(clearInterval(this.connectionMetricsInterval),this.connectionMetricsInterval=null),this.status==="connection-open-awaiting-session"?qe("Websocket connection lost before Vuu session established, check websocket configuration"):this.status!=="closed"&&(Z(this),this.send=n)},e.onclose=()=>{E==null||E("\u26A1 connection close"),t({type:"connection-status",status:"disconnected",reason:"close"}),this.connectionMetricsInterval&&(clearInterval(this.connectionMetricsInterval),this.connectionMetricsInterval=null),this.status!=="closed"&&(Z(this),this.send=n)};let s=o=>{e.send(JSON.stringify(o))},n=o=>{E==null||E(\`TODO queue message until websocket reconnected \${o.body.type}\`)};this.send=s,this.close=()=>{this.status="closed",e.close(),this.close=Be,this.send=\$e,E==null||E("close websocket")}}};var v,{info:te,infoEnabled:se}=b("worker");async function yt(r,e,t,s,n,o,i){let u=await ze(r,e,c=>{de(c)?postMessage({type:"connection-metrics",messages:c}):pe(c)?(n(c),c.status==="reconnected"&&v.reconnect()):v.handleMessageFromServer(c)},o,i);v=new F(u,c=>Mt(c)),u.requiresLogin&&await v.login(t,s)}function Mt(r){postMessage(r)}var _t=async({data:r})=>{switch(r.type){case"connect":await yt(r.url,r.protocol,r.token,r.username,postMessage,r.retryLimitDisconnect,r.retryLimitStartup),postMessage({type:"connected"});break;case"subscribe":se&&te(\`client subscribe: \${JSON.stringify(r)}\`),v.subscribe(r);break;case"unsubscribe":se&&te(\`client unsubscribe: \${JSON.stringify(r)}\`),v.unsubscribe(r.viewport);break;default:se&&te(\`client message: \${JSON.stringify(r)}\`),v.handleMessageFromClient(r)}};self.addEventListener("message",_t);postMessage({type:"ready"}); `; \ No newline at end of file diff --git a/vuu-ui/packages/vuu-data-test/src/basket/reference-data/constituents.ts b/vuu-ui/packages/vuu-data-test/src/basket/reference-data/constituents.ts index 82df44a61..6378d0135 100644 --- a/vuu-ui/packages/vuu-data-test/src/basket/reference-data/constituents.ts +++ b/vuu-ui/packages/vuu-data-test/src/basket/reference-data/constituents.ts @@ -2,7 +2,7 @@ import ftse from "./ftse100"; import nasdaq from "./nasdaq100"; import sp500 from "./sp500"; import hsi from "./hsi"; -import { VuuRowDataItemType } from "packages/vuu-protocol-types"; +import { VuuRowDataItemType } from "@finos/vuu-protocol-types"; const basketConstituentData = []; for (const row of ftse) { diff --git a/vuu-ui/packages/vuu-layout/src/layout-reducer/layoutTypes.ts b/vuu-ui/packages/vuu-layout/src/layout-reducer/layoutTypes.ts index de4883166..30519415d 100644 --- a/vuu-ui/packages/vuu-layout/src/layout-reducer/layoutTypes.ts +++ b/vuu-ui/packages/vuu-layout/src/layout-reducer/layoutTypes.ts @@ -1,5 +1,5 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import { NamedFilter } from "packages/vuu-filter-types"; +import { NamedFilter } from "@finos/vuu-filter-types"; import { CSSProperties, ReactElement } from "react"; import { DragDropRect, DragInstructions } from "../drag-drop"; import { DropTarget } from "../drag-drop/DropTarget"; diff --git a/vuu-ui/packages/vuu-shell/src/shellTypes.ts b/vuu-ui/packages/vuu-shell/src/shellTypes.ts index dab212f4a..ef5cc33f8 100644 --- a/vuu-ui/packages/vuu-shell/src/shellTypes.ts +++ b/vuu-ui/packages/vuu-shell/src/shellTypes.ts @@ -1,5 +1,5 @@ -import { VuuTable } from "@finos/vuu-protocol-types"; -import { ViewProps } from "packages/vuu-layout/src"; +import type { VuuTable } from "@finos/vuu-protocol-types"; +import type { ViewProps } from "@finos/vuu-layout"; declare global { const vuuConfig: Promise; diff --git a/vuu-ui/packages/vuu-table-extras/src/cell-renderers/background-cell/BackgroundCellConfigurationEditor.tsx b/vuu-ui/packages/vuu-table-extras/src/cell-renderers/background-cell/BackgroundCellConfigurationEditor.tsx index 611492243..35737802a 100644 --- a/vuu-ui/packages/vuu-table-extras/src/cell-renderers/background-cell/BackgroundCellConfigurationEditor.tsx +++ b/vuu-ui/packages/vuu-table-extras/src/cell-renderers/background-cell/BackgroundCellConfigurationEditor.tsx @@ -7,7 +7,7 @@ import { Dropdown, SingleSelectionHandler } from "@finos/vuu-ui-controls"; import "./BackgroundCellConfigurationEditor.css"; import { useCallback, useState } from "react"; -import { ColumnDescriptorCustomRenderer } from "packages/vuu-table-types"; +import type { ColumnDescriptorCustomRenderer } from "@finos/vuu-table-types"; const classBase = "vuuBackgroundCellConfiguration"; diff --git a/vuu-ui/packages/vuu-table/src/Table.tsx b/vuu-ui/packages/vuu-table/src/Table.tsx index 0cca3cde3..91d678083 100644 --- a/vuu-ui/packages/vuu-table/src/Table.tsx +++ b/vuu-ui/packages/vuu-table/src/Table.tsx @@ -35,7 +35,7 @@ import { useTable } from "./useTable"; import { TableHeader } from "./table-header/TableHeader"; import "./Table.css"; -import { DragDropState } from "packages/vuu-ui-controls/src/drag-drop/DragDropState"; +import type { DragDropState } from "@finos/vuu-ui-controls"; const classBase = "vuuTable"; diff --git a/vuu-ui/packages/vuu-table/src/cell-renderers/cell-utils.ts b/vuu-ui/packages/vuu-table/src/cell-renderers/cell-utils.ts index 26aac07de..ada447aa5 100644 --- a/vuu-ui/packages/vuu-table/src/cell-renderers/cell-utils.ts +++ b/vuu-ui/packages/vuu-table/src/cell-renderers/cell-utils.ts @@ -1,4 +1,4 @@ -import { TableCellRendererProps } from "packages/vuu-table-types"; +import { TableCellRendererProps } from "@finos/vuu-table-types"; /** * A memo compare function for cell renderers. Can be used to suppress * render where column and data are both unchanged. Avoids render diff --git a/vuu-ui/packages/vuu-table/src/useDataSource.ts b/vuu-ui/packages/vuu-table/src/useDataSource.ts index 1272c2abf..d220b00a9 100644 --- a/vuu-ui/packages/vuu-table/src/useDataSource.ts +++ b/vuu-ui/packages/vuu-table/src/useDataSource.ts @@ -7,7 +7,7 @@ import { } from "@finos/vuu-data-types"; import { VuuRange } from "@finos/vuu-protocol-types"; import { getFullRange, NULL_RANGE } from "@finos/vuu-utils"; -import { GridAction } from "packages/vuu-table-types"; +import { GridAction } from "@finos/vuu-table-types"; import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { MovingWindow } from "./moving-window"; diff --git a/vuu-ui/packages/vuu-table/src/useSelection.ts b/vuu-ui/packages/vuu-table/src/useSelection.ts index be71e750a..658d2e81e 100644 --- a/vuu-ui/packages/vuu-table/src/useSelection.ts +++ b/vuu-ui/packages/vuu-table/src/useSelection.ts @@ -10,7 +10,7 @@ import { DataSourceRow, Selection, SelectionChangeHandler, -} from "packages/vuu-data-types"; +} from "@finos/vuu-data-types"; import { KeyboardEvent, KeyboardEventHandler, diff --git a/vuu-ui/packages/vuu-ui-controls/src/cycle-state-button/CycleStateButton.tsx b/vuu-ui/packages/vuu-ui-controls/src/cycle-state-button/CycleStateButton.tsx index 96adaff6d..8dd90fd7a 100644 --- a/vuu-ui/packages/vuu-ui-controls/src/cycle-state-button/CycleStateButton.tsx +++ b/vuu-ui/packages/vuu-ui-controls/src/cycle-state-button/CycleStateButton.tsx @@ -1,10 +1,10 @@ import { Button, ButtonProps } from "@salt-ds/core"; import cx from "clsx"; -import { CommitResponse } from "packages/vuu-table-types"; -import { +import type { CommitResponse } from "@finos/vuu-table-types"; +import type { VuuColumnDataType, VuuRowDataItemType, -} from "packages/vuu-protocol-types"; +} from "@finos/vuu-protocol-types"; import { ForwardedRef, forwardRef, SyntheticEvent, useCallback } from "react"; const classBase = "vuuCycleStateButton"; diff --git a/vuu-ui/packages/vuu-ui-controls/src/drag-drop/index.ts b/vuu-ui/packages/vuu-ui-controls/src/drag-drop/index.ts index a39d84e65..2267fde99 100644 --- a/vuu-ui/packages/vuu-ui-controls/src/drag-drop/index.ts +++ b/vuu-ui/packages/vuu-ui-controls/src/drag-drop/index.ts @@ -1,4 +1,6 @@ export * from "./dragDropTypesNext"; export * from "./DragDropProvider"; +export * from "./DragDropState"; export * from "./useDragDropNext"; export * from "./drop-target-utils"; +export * from "./useGlobalDragDrop"; diff --git a/vuu-ui/sample-apps/feature-basket-trading/src/basket-table-edit/basketConstituentEditColumns.ts b/vuu-ui/sample-apps/feature-basket-trading/src/basket-table-edit/basketConstituentEditColumns.ts index 21f5319c3..6dbaa8f37 100644 --- a/vuu-ui/sample-apps/feature-basket-trading/src/basket-table-edit/basketConstituentEditColumns.ts +++ b/vuu-ui/sample-apps/feature-basket-trading/src/basket-table-edit/basketConstituentEditColumns.ts @@ -1,4 +1,4 @@ -import { ColumnDescriptor } from "packages/vuu-table-types"; +import type { ColumnDescriptor } from "@finos/vuu-table-types"; const editable = true; const hidden = true; diff --git a/vuu-ui/sample-apps/feature-basket-trading/src/basket-table-live/basketConstituentLiveColumns.ts b/vuu-ui/sample-apps/feature-basket-trading/src/basket-table-live/basketConstituentLiveColumns.ts index 8041aba72..76048e1a1 100644 --- a/vuu-ui/sample-apps/feature-basket-trading/src/basket-table-live/basketConstituentLiveColumns.ts +++ b/vuu-ui/sample-apps/feature-basket-trading/src/basket-table-live/basketConstituentLiveColumns.ts @@ -1,4 +1,4 @@ -import { ColumnDescriptor } from "packages/vuu-table-types"; +import type { ColumnDescriptor } from "@finos/vuu-table-types"; const hidden = true; const ticking = { diff --git a/vuu-ui/sample-apps/feature-basket-trading/src/basket-toolbar/BasketToolbar.tsx b/vuu-ui/sample-apps/feature-basket-trading/src/basket-toolbar/BasketToolbar.tsx index d99ba5ddf..0da37b7f1 100644 --- a/vuu-ui/sample-apps/feature-basket-trading/src/basket-toolbar/BasketToolbar.tsx +++ b/vuu-ui/sample-apps/feature-basket-trading/src/basket-toolbar/BasketToolbar.tsx @@ -6,15 +6,15 @@ import { useEditableText, } from "@finos/vuu-ui-controls"; import { Button, FormField, FormFieldLabel } from "@salt-ds/core"; -import { +import type { CommitResponse, DataItemCommitHandler, -} from "packages/vuu-table-types"; -import { VuuRowDataItemType } from "packages/vuu-protocol-types"; +} from "@finos/vuu-table-types"; +import type { VuuRowDataItemType } from "@finos/vuu-protocol-types"; import { HTMLAttributes, useCallback } from "react"; import { BasketSelector, BasketSelectorProps } from "../basket-selector"; import { Basket } from "../useBasketTrading"; -import { BasketStatus } from "../VuuBasketTradingFeature"; +import type { BasketStatus } from "../VuuBasketTradingFeature"; import { BasketMenu } from "./BasketMenu"; import cx from "clsx"; diff --git a/vuu-ui/sample-apps/feature-basket-trading/src/cell-renderers/col-header-add-symbol/ColHeaderAddSymbol.tsx b/vuu-ui/sample-apps/feature-basket-trading/src/cell-renderers/col-header-add-symbol/ColHeaderAddSymbol.tsx index 2369501c0..bc8b3fa20 100644 --- a/vuu-ui/sample-apps/feature-basket-trading/src/cell-renderers/col-header-add-symbol/ColHeaderAddSymbol.tsx +++ b/vuu-ui/sample-apps/feature-basket-trading/src/cell-renderers/col-header-add-symbol/ColHeaderAddSymbol.tsx @@ -5,9 +5,10 @@ import { } from "@finos/vuu-layout"; import { registerComponent } from "@finos/vuu-utils"; import { Button } from "@salt-ds/core"; -import { DataSource } from "packages/vuu-data-types"; -import { InstrumentSearchProps } from "packages/vuu-ui-controls/src"; +import type { DataSource } from "@finos/vuu-data-types"; +import type { InstrumentSearchProps } from "@finos/vuu-ui-controls/src"; import { MouseEventHandler, useCallback, useMemo } from "react"; + import "./ColHeaderAddSymbol.css"; const classBase = "vuuColHeaderAddSymbol"; diff --git a/vuu-ui/sample-apps/standalone-table/src/App.tsx b/vuu-ui/sample-apps/standalone-table/src/App.tsx index f762b7c0b..2677b9d54 100644 --- a/vuu-ui/sample-apps/standalone-table/src/App.tsx +++ b/vuu-ui/sample-apps/standalone-table/src/App.tsx @@ -5,7 +5,7 @@ import { getSchema, SimulTableName, vuuModule } from "@finos/vuu-data-test"; // import "@finos/vuu-theme/index.css"; import "./App.css"; -// import { ThemeProvider } from "packages/vuu-utils/src"; +// import { ThemeProvider } from "@finos/vuu-utils"; export const App = () => { const columnDescriptors = [{ name: "Column 1" }, { name: "Column 2" }]; diff --git a/vuu-ui/scripts/build-all-type-defs.mjs b/vuu-ui/scripts/build-all-type-defs.mjs index 4079e1323..2579e02a0 100644 --- a/vuu-ui/scripts/build-all-type-defs.mjs +++ b/vuu-ui/scripts/build-all-type-defs.mjs @@ -11,20 +11,22 @@ function buildPackage(packageName) { } const packages = [ - "vuu-utils", - "vuu-data", - "vuu-data-test", - "vuu-data-react", + "vuu-codemirror", "vuu-data-ag-grid", + "vuu-data-local", + "vuu-data-react", + "vuu-data-remote", + "vuu-data-test", + "vuu-datatable", "vuu-filter-parser", "vuu-filters", + "vuu-layout", "vuu-popups", - "vuu-datatable", + "vuu-shell", "vuu-table", "vuu-table-extras", - "vuu-layout", - "vuu-shell", "vuu-ui-controls", + "vuu-utils", ]; packages.forEach(buildPackage); diff --git a/vuu-ui/showcase/src/examples/DataTable/FilterTable.examples.tsx b/vuu-ui/showcase/src/examples/DataTable/FilterTable.examples.tsx index c3928a789..c28375e45 100644 --- a/vuu-ui/showcase/src/examples/DataTable/FilterTable.examples.tsx +++ b/vuu-ui/showcase/src/examples/DataTable/FilterTable.examples.tsx @@ -1,17 +1,17 @@ -import { FilterTable } from "@finos/vuu-datatable"; -import { TableConfig } from "@finos/vuu-table-types"; -import { Filter } from "@finos/vuu-filter-types"; -import { useCallback, useMemo, useState } from "react"; -import { useTestDataSource } from "../utils"; -import { DataSourceFilter } from "@finos/vuu-data-types"; import { getAllSchemas, getSchema, SimulTableName, vuuModule, } from "@finos/vuu-data-test"; -import { ActiveItemChangeHandler } from "packages/vuu-layout/src"; -import { TableProps } from "packages/vuu-table/src"; +import type { DataSourceFilter } from "@finos/vuu-data-types"; +import { FilterTable } from "@finos/vuu-datatable"; +import type { Filter } from "@finos/vuu-filter-types"; +import type { ActiveItemChangeHandler } from "@finos/vuu-layout"; +import type { TableProps } from "@finos/vuu-table"; +import type { TableConfig } from "@finos/vuu-table-types"; +import { useCallback, useMemo, useState } from "react"; +import { useTestDataSource } from "../utils"; let displaySequence = 1; const schemas = getAllSchemas(); diff --git a/vuu-ui/showcase/src/examples/Filters/FilterBar/FilterBar.examples.tsx b/vuu-ui/showcase/src/examples/Filters/FilterBar/FilterBar.examples.tsx index 96cf34278..55e32e03a 100644 --- a/vuu-ui/showcase/src/examples/Filters/FilterBar/FilterBar.examples.tsx +++ b/vuu-ui/showcase/src/examples/Filters/FilterBar/FilterBar.examples.tsx @@ -1,10 +1,10 @@ import { FilterBar, FilterBarProps } from "@finos/vuu-filters"; -import { Filter } from "@finos/vuu-filter-types"; +import type { Filter } from "@finos/vuu-filter-types"; import { useCallback, useEffect, useRef, useState } from "react"; -import { DataSourceFilter } from "@finos/vuu-data-types"; +import type { DataSourceFilter } from "@finos/vuu-data-types"; import { Input } from "@salt-ds/core"; import { getSchema, vuuModule } from "@finos/vuu-data-test"; -import { ActiveItemChangeHandler } from "packages/vuu-layout/src"; +import type { ActiveItemChangeHandler } from "@finos/vuu-layout"; let displaySequence = 1; diff --git a/vuu-ui/showcase/src/examples/ShowcaseControls/Tree.data.ts b/vuu-ui/showcase/src/examples/ShowcaseControls/Tree.data.ts index 54e49d951..034fb06ca 100644 --- a/vuu-ui/showcase/src/examples/ShowcaseControls/Tree.data.ts +++ b/vuu-ui/showcase/src/examples/ShowcaseControls/Tree.data.ts @@ -1,4 +1,4 @@ -import { TreeSourceNode } from "packages/vuu-ui-controls/src"; +import type { TreeSourceNode } from "@finos/vuu-ui-controls"; export const folderData: TreeSourceNode[] = [ // prettier-ignore diff --git a/vuu-ui/showcase/src/examples/UiControls/InstrumentPicker.examples.tsx b/vuu-ui/showcase/src/examples/UiControls/InstrumentPicker.examples.tsx index 97d53c0ce..a9b43dad1 100644 --- a/vuu-ui/showcase/src/examples/UiControls/InstrumentPicker.examples.tsx +++ b/vuu-ui/showcase/src/examples/UiControls/InstrumentPicker.examples.tsx @@ -1,16 +1,16 @@ -import { InstrumentPicker } from "@finos/vuu-ui-controls"; import { getAllSchemas, getSchema, SimulTableName, vuuModule, } from "@finos/vuu-data-test"; +import type { DataSourceRow } from "@finos/vuu-data-types"; +import type { TableProps, TableRowSelectHandler } from "@finos/vuu-table"; +import type { ColumnDescriptor } from "@finos/vuu-table-types"; +import { InstrumentPicker } from "@finos/vuu-ui-controls"; import { buildColumnMap, ColumnMap } from "@finos/vuu-utils"; import { useCallback, useMemo } from "react"; -import { TableProps, TableRowSelectHandler } from "@finos/vuu-table"; -import { ColumnDescriptor } from "@finos/vuu-table-types"; import { useTestDataSource } from "../utils"; -import { DataSourceRow } from "packages/vuu-data-types"; let displaySequence = 0; diff --git a/vuu-ui/showcase/src/examples/UiControls/InstrumentSearch.examples.tsx b/vuu-ui/showcase/src/examples/UiControls/InstrumentSearch.examples.tsx index 61be4489b..8cd9ed377 100644 --- a/vuu-ui/showcase/src/examples/UiControls/InstrumentSearch.examples.tsx +++ b/vuu-ui/showcase/src/examples/UiControls/InstrumentSearch.examples.tsx @@ -5,8 +5,8 @@ import { InstrumentSearch, useDragDropProvider, } from "@finos/vuu-ui-controls"; -import { DataSourceRow } from "packages/vuu-data-types"; -import { GlobalDropHandler } from "packages/vuu-ui-controls/src/drag-drop/useGlobalDragDrop"; +import type { DataSourceRow } from "@finos/vuu-data-types"; +import type { GlobalDropHandler } from "@finos/vuu-ui-controls"; import { HTMLAttributes, useCallback, diff --git a/vuu-ui/showcase/src/examples/VuuFeatures/FilterTableFeature.examples.tsx b/vuu-ui/showcase/src/examples/VuuFeatures/FilterTableFeature.examples.tsx index aa775c76d..322bdca64 100644 --- a/vuu-ui/showcase/src/examples/VuuFeatures/FilterTableFeature.examples.tsx +++ b/vuu-ui/showcase/src/examples/VuuFeatures/FilterTableFeature.examples.tsx @@ -10,7 +10,7 @@ import { useCallback, useState } from "react"; import { FilterTableFeature } from "../../features/FilterTable.feature"; import { VuuBlotterHeader } from "./VuuBlotterHeader"; import { JsonTable } from "@finos/vuu-datatable"; -import { JsonData } from "packages/vuu-utils/src"; +import type { JsonData } from "@finos/vuu-utils"; registerComponent("FilterTableFeature", FilterTableFeature, "view"); diff --git a/vuu-ui/tsconfig.json b/vuu-ui/tsconfig.json index 13fc0f95a..cbd1a38e0 100644 --- a/vuu-ui/tsconfig.json +++ b/vuu-ui/tsconfig.json @@ -34,10 +34,10 @@ "references": [ { "path": "packages/vuu-codemirror" }, { "path": "packages/vuu-data-local" }, + { "path": "packages/vuu-data-react" }, { "path": "packages/vuu-data-remote" }, { "path": "packages/vuu-data-types" }, { "path": "packages/vuu-data-ag-grid" }, - { "path": "packages/vuu-data-react" }, { "path": "packages/vuu-data-test" }, { "path": "packages/vuu-data-types" }, { "path": "packages/vuu-datatable" }, From 907c8cf3f79df900521841242fb5a4ea965ab44d Mon Sep 17 00:00:00 2001 From: heswell Date: Wed, 3 Jan 2024 17:41:11 +0000 Subject: [PATCH 26/38] add back -webkit prefix for css mask (#1100) --- vuu-ui/packages/vuu-icons/index.css | 2 +- vuu-ui/packages/vuu-popups/src/menu/MenuList.css | 1 + vuu-ui/packages/vuu-theme/css/components/checkbox.css | 2 ++ vuu-ui/packages/vuu-theme/css/components/switch.css | 2 ++ 4 files changed, 6 insertions(+), 1 deletion(-) diff --git a/vuu-ui/packages/vuu-icons/index.css b/vuu-ui/packages/vuu-icons/index.css index b7376c4d1..ddc71b731 100644 --- a/vuu-ui/packages/vuu-icons/index.css +++ b/vuu-ui/packages/vuu-icons/index.css @@ -84,8 +84,8 @@ span[data-icon] { background-color: var(--vuu-icon-color, var(--saltIcon-color, var(--salt-text-secondary-foreground))); left: var(--vuu-icon-left, auto); height: var(--vuu-icon-height, var(--vuu-icon-size, 12px)); - /* -webkit-mask: var(--vuu-icon-svg) center center/var(--vuu-icon-size) var(--vuu-icon-size); */ mask: var(--vuu-icon-svg) center center/var(--vuu-icon-size) var(--vuu-icon-size); + -webkit-mask: var(--vuu-icon-svg) center center/var(--vuu-icon-size) var(--vuu-icon-size); mask-repeat: no-repeat; -webkit-mask-repeat: no-repeat; position: absolute; diff --git a/vuu-ui/packages/vuu-popups/src/menu/MenuList.css b/vuu-ui/packages/vuu-popups/src/menu/MenuList.css index 6dcd5b5eb..35ede9d87 100644 --- a/vuu-ui/packages/vuu-popups/src/menu/MenuList.css +++ b/vuu-ui/packages/vuu-popups/src/menu/MenuList.css @@ -66,6 +66,7 @@ .vuuMenuItem[aria-haspopup='true']:after { content: var(--menu-item-twisty-content); mask: var(--vuu-svg-chevron-right) center center/8px 8px no-repeat; + -webkit-mask: var(--vuu-svg-chevron-right) center center/8px 8px no-repeat; background-color: var(--menu-item-twisty-color); height: 16px; left: var(--menu-item-twisty-left); diff --git a/vuu-ui/packages/vuu-theme/css/components/checkbox.css b/vuu-ui/packages/vuu-theme/css/components/checkbox.css index 58d5b7bfa..a1c3cf0a5 100644 --- a/vuu-ui/packages/vuu-theme/css/components/checkbox.css +++ b/vuu-ui/packages/vuu-theme/css/components/checkbox.css @@ -43,7 +43,9 @@ left: var(--vuu-icon-left, auto); height: var(--vuu-icon-height, var(--vuu-icon-size, 12px)); mask: var(--vuu-svg-tick) center center/var(--vuu-icon-size) var(--vuu-icon-size); + -webkit-mask: var(--vuu-svg-tick) center center/var(--vuu-icon-size) var(--vuu-icon-size); mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; position: absolute; top: var(--vuu-icon-top, auto); width: var(--vuu-icon-width, var(--vuu-icon-size, 12px)); diff --git a/vuu-ui/packages/vuu-theme/css/components/switch.css b/vuu-ui/packages/vuu-theme/css/components/switch.css index bb961ada8..e032d64e8 100644 --- a/vuu-ui/packages/vuu-theme/css/components/switch.css +++ b/vuu-ui/packages/vuu-theme/css/components/switch.css @@ -46,7 +46,9 @@ left: var(--vuu-icon-left, auto); height: var(--vuu-icon-height, var(--vuu-icon-size, 12px)); mask: var(--vuu-svg-tick) center center/var(--vuu-icon-size) var(--vuu-icon-size); + -webkit-mask: var(--vuu-svg-tick) center center/var(--vuu-icon-size) var(--vuu-icon-size); mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; position: absolute; top: var(--vuu-icon-top, auto); width: var(--vuu-icon-width, var(--vuu-icon-size, 12px)); From 2ddac4a415979fc808f9e28d6353258a20e71846 Mon Sep 17 00:00:00 2001 From: Na Lee Ha Date: Thu, 7 Dec 2023 16:19:28 +0000 Subject: [PATCH 27/38] #1061 introduce new view port action to include key of created row of a table in the response --- .../module/basket/service/BasketService.scala | 8 +++----- .../vuu/core/module/basket/BasketCreateTest.scala | 11 +++++++---- .../module/basket/BasketMutateOffMarketTest.scala | 15 +++++++++------ .../module/basket/BasketSendToMarketTest.scala | 6 ++++-- .../org/finos/vuu/viewport/ViewPortAction.scala | 4 +--- .../org/finos/vuu/viewport/ViewPortEdit.scala | 1 + 6 files changed, 25 insertions(+), 20 deletions(-) diff --git a/example/basket/src/main/scala/org/finos/vuu/core/module/basket/service/BasketService.scala b/example/basket/src/main/scala/org/finos/vuu/core/module/basket/service/BasketService.scala index 991aa248d..8d1a1fcec 100644 --- a/example/basket/src/main/scala/org/finos/vuu/core/module/basket/service/BasketService.scala +++ b/example/basket/src/main/scala/org/finos/vuu/core/module/basket/service/BasketService.scala @@ -4,7 +4,7 @@ import com.typesafe.scalalogging.StrictLogging import org.finos.toolbox.time.Clock import org.finos.vuu.core.module.basket.BasketConstants.Side import org.finos.vuu.core.module.basket.BasketModule -import org.finos.vuu.core.module.basket.BasketModule.{BasketConstituentTable} +import org.finos.vuu.core.module.basket.BasketModule.BasketConstituentTable import org.finos.vuu.core.table.{DataTable, RowData, RowWithData, TableContainer} import org.finos.vuu.net.rpc.RpcHandler import org.finos.vuu.net.{ClientSessionId, RequestContext} @@ -15,11 +15,9 @@ import java.util.concurrent.atomic.AtomicInteger object BasketTradeId { private val counter: AtomicInteger = new AtomicInteger(0) - var current:String = "NoneInitalised" //this is for testing but only works if tests that use this doesnt run in parallel def oneNew(user:String): String = { val counterValue = counter.incrementAndGet() - current = user + "-" + "".padTo(5 - counterValue.toString.length, "0").mkString + counterValue - current + user + "-" + "".padTo(5 - counterValue.toString.length, "0").mkString + counterValue } } @@ -103,7 +101,7 @@ class BasketService(val table: DataTable, val tableContainer: TableContainer, va logger.error("Cannot find the Basket Trading Constituent.") } - NoAction() + ViewPortCreateSuccess(basketTradeId) } override def menuItems(): ViewPortMenu = ViewPortMenu( diff --git a/example/basket/src/test/scala/org/finos/vuu/core/module/basket/BasketCreateTest.scala b/example/basket/src/test/scala/org/finos/vuu/core/module/basket/BasketCreateTest.scala index 9451fa78f..635db6e65 100644 --- a/example/basket/src/test/scala/org/finos/vuu/core/module/basket/BasketCreateTest.scala +++ b/example/basket/src/test/scala/org/finos/vuu/core/module/basket/BasketCreateTest.scala @@ -7,10 +7,10 @@ import org.finos.vuu.api.ViewPortDef import org.finos.vuu.core.module.TableDefContainer import org.finos.vuu.core.module.basket.service.{BasketServiceIF, BasketTradeId, BasketTradingServiceIF} import org.finos.vuu.core.module.price.PriceModule -import org.finos.vuu.core.table.TableTestHelper.combineQs import org.finos.vuu.order.oms.OmsApi import org.finos.vuu.test.VuuServerTestCase import org.finos.vuu.util.table.TableAsserts.assertVpEq +import org.finos.vuu.viewport.ViewPortCreateSuccess import org.scalatest.prop.Tables.Table class BasketCreateTest extends VuuServerTestCase { @@ -54,21 +54,24 @@ class BasketCreateTest extends VuuServerTestCase { val basketService = vuuServer.getViewPortRpcServiceProxy[BasketServiceIF](viewportBasket) - val action = basketService.createBasket(".FTSE", "TestBasket")(vuuServer.requestContext) + val vpAction = basketService.createBasket(".FTSE", "TestBasket")(vuuServer.requestContext) + + assert(vpAction.isInstanceOf[ViewPortCreateSuccess]) + val basketTradeInstanceId = vpAction.asInstanceOf[ViewPortCreateSuccess].key val viewportBasketTrading = vuuServer.createViewPort(BasketModule.NAME, BasketTradingTable) val basketTradingService = vuuServer.getViewPortRpcServiceProxy[BasketTradingServiceIF](viewportBasketTrading) //CJS: I don't like this forced cast, need to look at that a bit - basketTradingService.editCellAction().func(BasketTradeId.current, BT.Units, 100.asInstanceOf[Object], viewportBasketTrading, vuuServer.session) + basketTradingService.editCellAction().func(basketTradeInstanceId, BT.Units, 100.asInstanceOf[Object], viewportBasketTrading, vuuServer.session) vuuServer.runOnce() assertVpEq(combineQsForVp(viewportBasketTrading)) { Table( ("basketId", "instanceId", "basketName", "units", "status", "filledPct", "totalNotionalUsd", "totalNotional", "fxRateToUsd", "side"), - (".FTSE", BasketTradeId.current, "TestBasket", 100, "OFF-MARKET", null, null, null, null, "BUY") + (".FTSE", basketTradeInstanceId, "TestBasket", 100, "OFF-MARKET", null, null, null, null, "BUY") ) } } diff --git a/example/basket/src/test/scala/org/finos/vuu/core/module/basket/BasketMutateOffMarketTest.scala b/example/basket/src/test/scala/org/finos/vuu/core/module/basket/BasketMutateOffMarketTest.scala index c60cb88d1..666091a19 100644 --- a/example/basket/src/test/scala/org/finos/vuu/core/module/basket/BasketMutateOffMarketTest.scala +++ b/example/basket/src/test/scala/org/finos/vuu/core/module/basket/BasketMutateOffMarketTest.scala @@ -11,6 +11,7 @@ import org.finos.vuu.core.module.price.PriceModule import org.finos.vuu.order.oms.OmsApi import org.finos.vuu.test.{TestVuuServer, VuuServerTestCase} import org.finos.vuu.util.table.TableAsserts.assertVpEq +import org.finos.vuu.viewport.ViewPortCreateSuccess import org.scalatest.prop.Tables.Table class BasketMutateOffMarketTest extends VuuServerTestCase { @@ -68,8 +69,9 @@ class BasketMutateOffMarketTest extends VuuServerTestCase { Then("Get the Basket RPC Service and call create basket") val basketService = vuuServer.getViewPortRpcServiceProxy[BasketServiceIF](vpBasket) - basketService.createBasket(".FTSE", "MyCustomBasket")(vuuServer.requestContext) - val basketTradeInstanceId = BasketTradeId.current + val vpAction = basketService.createBasket(".FTSE", "MyCustomBasket")(vuuServer.requestContext) + assert(vpAction.isInstanceOf[ViewPortCreateSuccess]) + val basketTradeInstanceId = vpAction.asInstanceOf[ViewPortCreateSuccess].key val vpBasketTrading = vuuServer.createViewPort(BasketModule.NAME, BasketTradingTable) @@ -152,8 +154,7 @@ class BasketMutateOffMarketTest extends VuuServerTestCase { vuuServer.login("testUser", "testToken2") - GivenBasketTradeExist(vuuServer, ".FTSE", "MyCustomBasket") - val basketTradeInstanceId = BasketTradeId.current + val basketTradeInstanceId = GivenBasketTradeExist(vuuServer, ".FTSE", "MyCustomBasket") val vpBasketTrading = vuuServer.createViewPort(BasketModule.NAME, BasketTradingTable) val vpBasketTradingCons = vuuServer.createViewPort(BasketModule.NAME, BasketTradingConstituentTable) @@ -233,7 +234,7 @@ class BasketMutateOffMarketTest extends VuuServerTestCase { // } } - def GivenBasketTradeExist(vuuServer: TestVuuServer, basketId: String, basketTradeName: String): Unit = { + def GivenBasketTradeExist(vuuServer: TestVuuServer, basketId: String, basketTradeName: String): String = { val basketProvider = vuuServer.getProvider(BasketModule.NAME, BasketModule.BasketTable) basketProvider.tick(".FTSE", Map(B.Id -> ".FTSE", B.Name -> ".FTSE 100", B.NotionalValue -> 1000001, B.NotionalValueUsd -> 1500001)) @@ -244,6 +245,8 @@ class BasketMutateOffMarketTest extends VuuServerTestCase { val vpBasket = vuuServer.createViewPort(BasketModule.NAME, BasketModule.BasketTable) val basketService = vuuServer.getViewPortRpcServiceProxy[BasketServiceIF](vpBasket) - basketService.createBasket(basketId, basketTradeName)(vuuServer.requestContext) + val vpAction = basketService.createBasket(basketId, basketTradeName)(vuuServer.requestContext) + assert(vpAction.isInstanceOf[ViewPortCreateSuccess]) + vpAction.asInstanceOf[ViewPortCreateSuccess].key } } \ No newline at end of file diff --git a/example/basket/src/test/scala/org/finos/vuu/core/module/basket/BasketSendToMarketTest.scala b/example/basket/src/test/scala/org/finos/vuu/core/module/basket/BasketSendToMarketTest.scala index 7bc7511ea..15b40173c 100644 --- a/example/basket/src/test/scala/org/finos/vuu/core/module/basket/BasketSendToMarketTest.scala +++ b/example/basket/src/test/scala/org/finos/vuu/core/module/basket/BasketSendToMarketTest.scala @@ -11,6 +11,7 @@ import org.finos.vuu.core.module.price.PriceModule import org.finos.vuu.order.oms.OmsApi import org.finos.vuu.test.VuuServerTestCase import org.finos.vuu.util.table.TableAsserts.assertVpEq +import org.finos.vuu.viewport.ViewPortCreateSuccess import org.scalatest.prop.Tables.Table class BasketSendToMarketTest extends VuuServerTestCase { @@ -50,8 +51,9 @@ class BasketSendToMarketTest extends VuuServerTestCase { Then("Get the Basket RPC Service and call create basket") val basketService = vuuServer.getViewPortRpcServiceProxy[BasketServiceIF](vpBasket) - basketService.createBasket(".FTSE", "TestBasket")(vuuServer.requestContext) - val basketTradeInstanceId = BasketTradeId.current + val vpAction = basketService.createBasket(".FTSE", "TestBasket")(vuuServer.requestContext) + assert(vpAction.isInstanceOf[ViewPortCreateSuccess]) + val basketTradeInstanceId = vpAction.asInstanceOf[ViewPortCreateSuccess].key val vpBasketTrading = vuuServer.createViewPort(BasketModule.NAME, BasketTradingTable) val vpBasketTradingCons = vuuServer.createViewPort(BasketModule.NAME, BasketTradingConstituentTable) diff --git a/vuu/src/main/scala/org/finos/vuu/viewport/ViewPortAction.scala b/vuu/src/main/scala/org/finos/vuu/viewport/ViewPortAction.scala index 3575beab6..cbf47c3b9 100644 --- a/vuu/src/main/scala/org/finos/vuu/viewport/ViewPortAction.scala +++ b/vuu/src/main/scala/org/finos/vuu/viewport/ViewPortAction.scala @@ -9,13 +9,10 @@ import org.finos.vuu.net.rpc.VsJsonTypeResolver @JsonTypeIdResolver(classOf[VsJsonTypeResolver]) trait ViewPortAction {} - - case class NoAction() extends ViewPortAction case class OpenDialogViewPortAction(table: ViewPortTable, renderComponent: String = "grid") extends ViewPortAction - case class CloseDialogViewPortAction(vpId: String) extends ViewPortAction @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type") @@ -27,5 +24,6 @@ case class CloseDialogViewPortAction(vpId: String) extends ViewPortAction new Type(value = classOf[ViewPortEditFailure], name = "VP_EDIT_FAILURE"), new Type(value = classOf[ViewPortRpcSuccess], name = "VP_RPC_SUCCESS"), new Type(value = classOf[ViewPortRpcFailure], name = "VP_RPC_FAILURE"), + new Type(value = classOf[ViewPortCreateSuccess], name = "VP_CREATE_SUCCESS"), )) trait ViewPortActionMixin {} diff --git a/vuu/src/main/scala/org/finos/vuu/viewport/ViewPortEdit.scala b/vuu/src/main/scala/org/finos/vuu/viewport/ViewPortEdit.scala index 5969e3356..5be039be6 100644 --- a/vuu/src/main/scala/org/finos/vuu/viewport/ViewPortEdit.scala +++ b/vuu/src/main/scala/org/finos/vuu/viewport/ViewPortEdit.scala @@ -7,6 +7,7 @@ case class ViewPortEditSuccess() extends ViewPortEditAction {} case class ViewPortRpcSuccess() extends ViewPortAction {} case class ViewPortRpcFailure(msg: String) extends ViewPortAction {} case class ViewPortEditFailure(msg: String) extends ViewPortEditAction {} +case class ViewPortCreateSuccess(key:String) extends ViewPortAction case class ViewPortEditCellAction(filter: String, func: (String, String, Object, ViewPort, ClientSessionId) => ViewPortEditAction){ final val rpcName = "VP_EDIT_CELL" From 67585109cd38d6d598bb2d2c8b1931a80620af0a Mon Sep 17 00:00:00 2001 From: Na Lee Ha Date: Thu, 7 Dec 2023 16:31:26 +0000 Subject: [PATCH 28/38] #1061 returning basket constituent key when we add new constituents --- .../basket/service/BasketTradingConstituentJoinService.scala | 2 +- .../main/scala/org/finos/vuu/viewport/ViewPortAction.scala | 5 +++-- vuu/src/main/scala/org/finos/vuu/viewport/ViewPortEdit.scala | 3 --- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/example/basket/src/main/scala/org/finos/vuu/core/module/basket/service/BasketTradingConstituentJoinService.scala b/example/basket/src/main/scala/org/finos/vuu/core/module/basket/service/BasketTradingConstituentJoinService.scala index 41d113792..ca3f5d02f 100644 --- a/example/basket/src/main/scala/org/finos/vuu/core/module/basket/service/BasketTradingConstituentJoinService.scala +++ b/example/basket/src/main/scala/org/finos/vuu/core/module/basket/service/BasketTradingConstituentJoinService.scala @@ -79,7 +79,7 @@ class BasketTradingConstituentJoinService(val table: DataTable, val tableContain //todo should we guard against adding row for ric that already exist? updateJoinTable(Array(newRow)) match { - case Right(_) => ViewPortRpcSuccess() + case Right(_) => ViewPortCreateSuccess(newRow.key) case Left(errorReason) => ViewPortRpcFailure(errorReason.reason) } diff --git a/vuu/src/main/scala/org/finos/vuu/viewport/ViewPortAction.scala b/vuu/src/main/scala/org/finos/vuu/viewport/ViewPortAction.scala index cbf47c3b9..effbcfb09 100644 --- a/vuu/src/main/scala/org/finos/vuu/viewport/ViewPortAction.scala +++ b/vuu/src/main/scala/org/finos/vuu/viewport/ViewPortAction.scala @@ -10,10 +10,11 @@ import org.finos.vuu.net.rpc.VsJsonTypeResolver trait ViewPortAction {} case class NoAction() extends ViewPortAction - case class OpenDialogViewPortAction(table: ViewPortTable, renderComponent: String = "grid") extends ViewPortAction - case class CloseDialogViewPortAction(vpId: String) extends ViewPortAction +case class ViewPortRpcSuccess() extends ViewPortAction {} +case class ViewPortRpcFailure(msg: String) extends ViewPortAction {} +case class ViewPortCreateSuccess(key:String) extends ViewPortAction @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type") @JsonSubTypes(Array( diff --git a/vuu/src/main/scala/org/finos/vuu/viewport/ViewPortEdit.scala b/vuu/src/main/scala/org/finos/vuu/viewport/ViewPortEdit.scala index 5be039be6..2cbe9443d 100644 --- a/vuu/src/main/scala/org/finos/vuu/viewport/ViewPortEdit.scala +++ b/vuu/src/main/scala/org/finos/vuu/viewport/ViewPortEdit.scala @@ -4,10 +4,7 @@ import org.finos.vuu.net.ClientSessionId trait ViewPortEditAction extends ViewPortAction {} case class ViewPortEditSuccess() extends ViewPortEditAction {} -case class ViewPortRpcSuccess() extends ViewPortAction {} -case class ViewPortRpcFailure(msg: String) extends ViewPortAction {} case class ViewPortEditFailure(msg: String) extends ViewPortEditAction {} -case class ViewPortCreateSuccess(key:String) extends ViewPortAction case class ViewPortEditCellAction(filter: String, func: (String, String, Object, ViewPort, ClientSessionId) => ViewPortEditAction){ final val rpcName = "VP_EDIT_CELL" From 9106d107d615daffd8fc26ccd57d4a36102d4a02 Mon Sep 17 00:00:00 2001 From: Na Lee Ha Date: Thu, 7 Dec 2023 16:39:14 +0000 Subject: [PATCH 29/38] #1061 deleting create basket menu item as using rpc now --- .../module/basket/service/BasketService.scala | 27 ++----------------- 1 file changed, 2 insertions(+), 25 deletions(-) diff --git a/example/basket/src/main/scala/org/finos/vuu/core/module/basket/service/BasketService.scala b/example/basket/src/main/scala/org/finos/vuu/core/module/basket/service/BasketService.scala index 8d1a1fcec..7be804a60 100644 --- a/example/basket/src/main/scala/org/finos/vuu/core/module/basket/service/BasketService.scala +++ b/example/basket/src/main/scala/org/finos/vuu/core/module/basket/service/BasketService.scala @@ -7,7 +7,7 @@ import org.finos.vuu.core.module.basket.BasketModule import org.finos.vuu.core.module.basket.BasketModule.BasketConstituentTable import org.finos.vuu.core.table.{DataTable, RowData, RowWithData, TableContainer} import org.finos.vuu.net.rpc.RpcHandler -import org.finos.vuu.net.{ClientSessionId, RequestContext} +import org.finos.vuu.net.RequestContext import org.finos.vuu.order.oms.OmsApi import org.finos.vuu.viewport._ import java.util.concurrent.atomic.AtomicInteger @@ -59,26 +59,8 @@ class BasketService(val table: DataTable, val tableContainer: TableContainer, va RowWithData(basketTradeInstanceId, Map(BT.InstanceId -> basketTradeInstanceId, BT.Status -> "OFF-MARKET", BT.BasketId -> sourceBasketId, BT.BasketName -> basketTradeName, BT.Side -> Side.Buy, BT.Units -> 1)) } - def createBasketFromRpc(basketId: String, name: String)(ctx: RequestContext): ViewPortAction = { - createBasket(basketId, name)(ctx) - } - - def createBasket(selection: ViewPortSelection, session: ClientSessionId): ViewPortAction = { - - val basketId = selection.rowKeyIndex.map({ case (key, _) => key }).toList.head - - val instanceKey = BasketTradeId.oneNew(session.user) - - createBasketInternal(basketId, instanceKey, instanceKey, session) - } - - def createBasket(basketId: String, name: String)(ctx: RequestContext): ViewPortAction = { + def createBasket(sourceBasketId: String, basketTradeName: String)(ctx: RequestContext): ViewPortAction = { val basketTradeId = BasketTradeId.oneNew(ctx.session.user) - createBasketInternal(basketId, name, basketTradeId, ctx.session) - } - - private def createBasketInternal(sourceBasketId: String, basketTradeName: String, basketTradeId: String, sessionId: ClientSessionId) = { - val constituents = getConstituentsForSourceBasket(sourceBasketId) tableContainer.getTable(BasketModule.BasketTradingTable) match { @@ -103,9 +85,4 @@ class BasketService(val table: DataTable, val tableContainer: TableContainer, va ViewPortCreateSuccess(basketTradeId) } - - override def menuItems(): ViewPortMenu = ViewPortMenu( - new SelectionViewPortMenuItem("Create New", "", (sel, sess) => this.createBasket(sel, sess), "CREATE_NEW_BASKET"), - ) - } From 388c837f9f5189eba6ffc2c0e40fc519d4736bed Mon Sep 17 00:00:00 2001 From: Na Lee Ha Date: Fri, 15 Dec 2023 15:38:04 +0000 Subject: [PATCH 30/38] #1052 adding test for loading basket constituent csv file and handling when it errors & sourcing test resources for test --- .../module/basket/csv/CsvStaticLoader.scala | 82 ++++++++++++------- .../test/resources/constituents/ftse100.csv | 4 + .../resources/constituents/ftsewitherror.csv | 4 + .../finos/vuu/csv/CsvStaticLoaderTests.scala | 47 +++++++++++ 4 files changed, 109 insertions(+), 28 deletions(-) create mode 100644 example/basket/src/test/resources/constituents/ftse100.csv create mode 100644 example/basket/src/test/resources/constituents/ftsewitherror.csv create mode 100644 example/basket/src/test/scala/org/finos/vuu/csv/CsvStaticLoaderTests.scala diff --git a/example/basket/src/main/scala/org/finos/vuu/core/module/basket/csv/CsvStaticLoader.scala b/example/basket/src/main/scala/org/finos/vuu/core/module/basket/csv/CsvStaticLoader.scala index 13023bffa..9fef0d572 100644 --- a/example/basket/src/main/scala/org/finos/vuu/core/module/basket/csv/CsvStaticLoader.scala +++ b/example/basket/src/main/scala/org/finos/vuu/core/module/basket/csv/CsvStaticLoader.scala @@ -2,44 +2,70 @@ package org.finos.vuu.core.module.basket.csv import com.typesafe.scalalogging.StrictLogging +import java.io.File import scala.io.Source +import scala.util.control.NonFatal object CsvStaticLoader extends StrictLogging { - def loadConstituent(basketId: String): Array[Map[String, Any]] = { + def loadConstituent(basketId: String, resourcePath: Option[String] = None): Array[Map[String, Any]] = { + try { - val staticDirPath = getClass.getResource("/static").getPath - val dir = new java.io.File(staticDirPath) - val csvFiles = dir.listFiles.filter(_.isFile) - .filter(_.getName.endsWith(basketId.replace(".","").toLowerCase + ".csv")) - val csvFile = csvFiles(0) - logger.info("Loading basket static:" + basketId + "(" + csvFile + ")") + val constituentsFilesDirectory = + if(resourcePath.isDefined) resourcePath.get + else getClass.getResource("/static").getPath + + val dir = new File(constituentsFilesDirectory) + val csvFiles = dir.listFiles.filter(_.isFile) + .filter(_.getName.endsWith(basketId.replace(".", "").toLowerCase + ".csv")) + + if (csvFiles.isEmpty) { + logger.error(s"Failed to find constituents file for $basketId") + Array.empty + } + else { + val csvFile = csvFiles(0) + logger.info("Loading basket static:" + basketId + "(" + csvFile + ")") + val rows = readFileContent(csvFile) + logger.info(s"Found ${rows.length} constituents for basket $basketId") + + val header = rows(0) + val symbolInd = header.indexOf("Symbol") + val nameInd = header.indexOf("Name") + val lastTradeInd = header.indexOf("Last Trade") + val volumeInd = header.indexOf("Volume") + val weightInd = header.indexOf("Weighting") + val changeInd = header.indexOf("Change") + + val constituents = rows.tail.map(e => { + val weighting = if (getValueFromIndex(weightInd, e) == null) 0.0D else getValueFromIndex(weightInd, e).toDouble + Map[String, Any]( + "Symbol" -> getValueFromIndex(symbolInd, e), + "Last Trade" -> getValueFromIndex(lastTradeInd, e), + "Name" -> getValueFromIndex(nameInd, e), + "Weighting" -> weighting, + "Volume" -> getValueFromIndex(volumeInd, e), + "Change" -> getValueFromIndex(changeInd, e) + ) + }) + constituents + + } + } + catch { + case NonFatal(t) => logger.error(s"Failed to parse constituents for $basketId", t) + Array.empty + } + } + + + private def readFileContent(csvFile: File): Array[Array[String]] = { val bufferedSource = Source.fromFile(csvFile) val csv = for (line <- bufferedSource.getLines) yield line.split(",").map(_.trim) val array = csv.toArray bufferedSource.close - var data: Map[String, String] = Map() - val header = array(0) - val symbolInd = header.indexOf("Symbol") - val nameInd = header.indexOf("Name") - val lastTradeInd = header.indexOf("Last Trade") - val volumeInd = header.indexOf("Volume") - val weightInd = header.indexOf("Weighting") - val changeInd = header.indexOf("Change") - val list = array.tail.map(e => { - val weighting = if(getValueFromIndex(weightInd, e) == null) 0.0D else getValueFromIndex(weightInd, e).toDouble - Map[String, Any]( - "Symbol" -> getValueFromIndex(symbolInd, e), - "Last Trade" -> getValueFromIndex(lastTradeInd, e), - "Name" -> getValueFromIndex(nameInd, e), - "Weighting" -> weighting, - "Volume" -> getValueFromIndex(volumeInd, e), - "Change" -> getValueFromIndex(changeInd, e) - ) - }) - list + array } - def load: Array[String] = { val staticDirPath = getClass.getResource("/static").getPath val dir = new java.io.File(staticDirPath) diff --git a/example/basket/src/test/resources/constituents/ftse100.csv b/example/basket/src/test/resources/constituents/ftse100.csv new file mode 100644 index 000000000..57cee0058 --- /dev/null +++ b/example/basket/src/test/resources/constituents/ftse100.csv @@ -0,0 +1,4 @@ +Symbol,Name,Last Trade,Change,Volume, Weighting +AAL.L,Anglo American PLC,436.35,5.35,5799089,0.0278736825813547 +ABF.L,Associated British Foods PLC,435.60,7.40,86808,0.000417248060431947 +ADM.L,Admiral Group PLC,1,627.00,,86808,0.000417248060431947 \ No newline at end of file diff --git a/example/basket/src/test/resources/constituents/ftsewitherror.csv b/example/basket/src/test/resources/constituents/ftsewitherror.csv new file mode 100644 index 000000000..b11163374 --- /dev/null +++ b/example/basket/src/test/resources/constituents/ftsewitherror.csv @@ -0,0 +1,4 @@ +Symbol,Name,Last Trade,Change,Volume, Weighting +AAL.L,Anglo American PLC,436.35,5.35,5799089,0.0278736825813547 +ABF.L,Associated British Foods PLC,435.60,7.40,86808,NotANumber +ADM.L,Admiral Group PLC,1,627.00,,86808,0.000417248060431947 \ No newline at end of file diff --git a/example/basket/src/test/scala/org/finos/vuu/csv/CsvStaticLoaderTests.scala b/example/basket/src/test/scala/org/finos/vuu/csv/CsvStaticLoaderTests.scala new file mode 100644 index 000000000..03609aae7 --- /dev/null +++ b/example/basket/src/test/scala/org/finos/vuu/csv/CsvStaticLoaderTests.scala @@ -0,0 +1,47 @@ +package org.finos.vuu.csv + +import org.finos.vuu.core.module.basket.csv.CsvStaticLoader +import org.scalatest.featurespec.AnyFeatureSpec + +import scala.io.Source + +class CsvStaticLoaderTests extends AnyFeatureSpec{ + + Feature("CSV loading Test Case") { + + Scenario("Can successfully load and parse basket constituents") { + var path = getClass.getResource("/constituents") + //his.class.getResourceAsStream("/myfile") + var x = ClassLoader.getSystemResource("") +// var x = Source.fromURL(path) +// var B = Source.fromResource("/static") + val testResourcePath = this.getClass().getResource("/constituents").getPath + val constituents = CsvStaticLoader.loadConstituent(".FTSE100", Some(testResourcePath)) + + assert(constituents.length == 3) + val firstRow = constituents.head + assert(firstRow("Symbol") == "AAL.L") + assert(firstRow("Last Trade") == "436.35") + assert(firstRow("Name") == "Anglo American PLC") + assert(firstRow("Weighting") == 0.0278736825813547) + assert(firstRow("Volume") == "5799089") + assert(firstRow("Change") == "5.35") + } + + Scenario("When parsing basket constituents fails return empty") { + + val constituents = CsvStaticLoader.loadConstituent(".FTSEWithError") + + assert(constituents.length == 0) + } + + + Scenario("When no matching basket constituents file return empty") { + + val constituents = CsvStaticLoader.loadConstituent(".NoSuchFile") + + assert(constituents.length == 0) + } + + } +} From f64270238aee2d37760a2938aa485426be3cf37d Mon Sep 17 00:00:00 2001 From: Na Lee Ha Date: Fri, 15 Dec 2023 15:38:57 +0000 Subject: [PATCH 31/38] #1052 deleting redundant csv for constituents --- .../src/main/resources/static/ftse100.csv | 100 ---- .../basket/src/main/resources/static/hsi.csv | 81 --- .../src/main/resources/static/nasdaq100.csv | 102 ---- .../src/main/resources/static/sp500.csv | 504 ------------------ vuu/src/main/resources/static/ftse100.csv | 100 ---- vuu/src/main/resources/static/hsi.csv | 81 --- vuu/src/main/resources/static/nasdaq100.csv | 102 ---- vuu/src/main/resources/static/sp500.csv | 504 ------------------ 8 files changed, 1574 deletions(-) delete mode 100644 example/basket/src/main/resources/static/ftse100.csv delete mode 100644 example/basket/src/main/resources/static/hsi.csv delete mode 100644 example/basket/src/main/resources/static/nasdaq100.csv delete mode 100644 example/basket/src/main/resources/static/sp500.csv delete mode 100644 vuu/src/main/resources/static/ftse100.csv delete mode 100644 vuu/src/main/resources/static/hsi.csv delete mode 100644 vuu/src/main/resources/static/nasdaq100.csv delete mode 100644 vuu/src/main/resources/static/sp500.csv diff --git a/example/basket/src/main/resources/static/ftse100.csv b/example/basket/src/main/resources/static/ftse100.csv deleted file mode 100644 index aa0315f95..000000000 --- a/example/basket/src/main/resources/static/ftse100.csv +++ /dev/null @@ -1,100 +0,0 @@ -Symbol,Name,Last Trade,Change,Volume, Weighting -AAL.L,Anglo American PLC,436.35�13:13,�5.35�(1.24%),5799089,0.0278736825813547 -ABF.L,Associated British Foods PLC,"3,435.60�13:12",�7.40�(0.21%),86808,0.000417248060431947 -ADM.L,Admiral Group PLC,"1,627.00�13:13",,86808,0.000417248060431947 -ADN.L,Aberdeen Asset Management PLC,334.00�13:13,�2.50�(0.75%),806880,0.00387831899135251 -AHT.L,Ashtead Group PLC,"1,027.00�13:13",�6.00�(0.59%),331255,0.00159219779580666 -ANTO.L,Antofagasta PLC,484.10�13:13,�11.70�(2.48%),1753976,0.00843059492263598 -ARM.L,ARM Holdings PLC,"1,058.00�13:13",�3.00�(0.28%),475927,0.00228757277736148 -AV.L,Aviva PLC,493.97�13:13,�2.23�(0.45%),2226835,0.0107034211668507 -AZN.L,AstraZeneca PLC,"4,399.50�13:13",�2.50�(0.06%),815133,0.00391798755004232 -BA.L,BAE Systems PLC,478.10�13:13,�4.30�(0.91%),2039934,0.00980506986578636 -BAB.L,Babcock International Group PLC,988.00�13:13,�9.50�(0.97%),209614,0.00100752275066102 -BARC.L,Barclays PLC,226.30�13:13,�1.15�(0.51%),6575664,0.0316063387021032 -BATS.L,British American Tobacco PLC,"3,803.50�13:13",�8.50�(0.22%),465110,0.0022355801929258 -BDEV.L,Barratt Developments PLC,576.00�13:13,�0.50�(0.09%),1044365,0.00501980543997108 -BG.L,BG Group PLC,"1,013.50�13:13",�5.50�(0.55%),1507332,0.00724508516988073 -BKG.L,Berkeley Group Holdings (The) PLC,"3,126.00�13:13",�15.00�(0.48%),95071,0.000456964684744788 -BLND.L,British Land Co PLC,828.06�13:12,�10.44�(1.25%),1802548,0.00866405926683583 -BLT.L,BHP Billiton PLC,881.40�13:13,�4.30�(0.49%),4947287,0.0237794431982097 -BNZL.L,Bunzl PLC,"1,875.40�13:05",�4.60�(0.24%),104541,0.000502482829757812 -BP.L,BP PLC,381.50�13:13,�2.95�(0.78%),10493561,0.0504379547308349 -BRBY.L,Burberry Group PLC,"1,269.00�13:13",�7.00�(0.55%),295647,0.00142104572530785 -BT-A.L,BT Group PLC,489.20�13:13,�3.70�(0.75%),3914982,0.0188176048996174 -CCL.L,Carnival PLC,"3,426.00�13:12",�22.00�(0.64%),86257,0.000414599644602783 -CNA.L,Centrica PLC,212.80�13:13,�0.60�(0.28%),2144540,0.0103078651220939 -CPG.L,Compass Group PLC,"1,054.00�13:08",�5.00�(0.48%),1001167,0.00481217156158961 -CPI.L,Capita PLC,"1,235.00�13:11",�1.00�(0.08%),244591,0.0011756418803464 -CRH.L,CRH PLC,"1,783.20�13:12",�17.80�(0.99%),897325,0.00431304851888186 -DC.L,DIXONS CARPHONE,462.10�13:11,,756906,0.00363811584680332 -DGE.L,Diageo PLC,"1,881.50�13:13",�6.50�(0.34%),756906,0.00363811584680332 -DLG.L,Direct Line Insurance Group PLC,403.80�13:13,�0.40�(0.10%),1095340,0.00526481995338596 -EXPN.L,Experian PLC,"1,191.00�13:12",�2.00�(0.17%),467283,0.00224602485281105 -EZJ.L,easyJet PLC,"1,682.00�13:12",�28.00�(1.64%),1191230,0.00572572121265722 -FRES.L,Fresnillo PLC,678.50�13:12,�6.50�(0.97%),381871,0.00183548675335462 -GFS.L,G4S PLC,232.30�13:03,�2.00�(0.85%),1096551,0.00527064070033535 -GKN.L,GKN PLC,294.80�13:12,�2.50�(0.86%),792247,0.00380798456516713 -GLEN.L,Glencore PLC,90.48�13:13,�1.65�(1.86%),41631528,0.200104533116974 -GSK.L,GlaxoSmithKline PLC,"1,345.00�13:13",�0.50�(0.04%),1767356,0.00849490672625522 -HIK.L,Hikma Pharmaceuticals PLC,"2,010.00�13:04",�57.00�(2.92%),261511,0.00125696891451962 -HL.L,Hargreaves Lansdown PLC,"1,488.03�13:12",�9.97�(0.67%),372261,0.00178929568961912 -HMSO.L,Hammerson PLC,597.50�13:11,�3.50�(0.58%),478301,0.0022989835562697 -HSBA.L,HSBC Holdings PLC,519.70�13:13,�0.50�(0.10%),7415629,0.0356436828072631 -IAG.L,International Consolidated Airlines Group SA,575.40�13:12,�16.10�(2.72%),4311514,0.0207235606629018 -IHG.L,InterContinental Hotels Group PLC,"2,481.00�13:12",�19.00�(0.76%),219918,0.00105704956863507 -III.L,3i Group PLC,487.30�13:11,�4.50�(0.92%),189987,0.000913184352332553 -IMT.L,Imperial Tobacco Group PLC,"3,571.00�13:13",�29.00�(0.81%),926816,0.00445479884777089 -INTU.L,intu properties plc,319.90�13:09,�4.60�(1.42%),514821,0.0024745192115892 -ISAT.L,Inmarsat PLC,"1,054.44�13:13",�3.44�(0.33%),988089,0.00474931133978598 -ITRK.L,Intertek Group PLC,"2,643.00�13:14",�3.00�(0.11%),45868,0.000220467399731505 -ITV.L,ITV PLC,267.30�13:14,�2.60�(0.96%),3453208,0.0165980593985356 -JMAT.L,Johnson Matthey PLC,"2,445.00�13:14",�29.00�(1.20%),276397,0.00132851940096775 -KGF.L,Kingfisher PLC,346.20�13:14,�4.30�(1.23%),1021408,0.00490946118917235 -LAND.L,Land Securities Group PLC,"1,239.00�13:13",�7.00�(0.56%),384973,0.00185039670961971 -LGEN.L,Legal & General Group PLC,266.00�13:14,�1.60�(0.60%),1998399,0.00960542930051541 -LLOY.L,Lloyds Banking Group PLC,73.86�13:14,�0.02�(0.03%),18907878,0.0908818936317375 -LSE.L,London Stock Exchange Group PLC,"2,544.00�13:11",�6.00�(0.24%),129657,0.000623204448569543 -MGGT.L,Meggitt PLC,386.00�13:15,�3.20�(0.84%),611044,0.00293702105610748 -MKS.L,Marks & Spencer Group PLC,514.75�13:12,�3.25�(0.63%),920128,0.00442265255908587 -MNDI.L,Mondi PLC,"1,463.00�13:14",�7.00�(0.48%),383546,0.00184353774521278 -MRW.L,Morrison (Wm) Supermarkets PLC,155.20�13:14,,920128,0.00442265255908587 -NG.L,National Grid PLC,926.40�13:14,�1.10�(0.12%),1659592,0.00797693234619361 -NXT.L,Next PLC,"7,765.00�13:11",�95.00�(1.21%),114062,0.000548246109448308 -OML.L,Old Mutual PLC,198.50�13:14,�0.40�(0.20%),2040849,0.00980946787029396 -PRU.L,Prudential PLC,"1,499.50�13:15",�14.00�(0.93%),580870,0.00279198784516525 -PSON.L,Pearson PLC,794.00�13:09,�5.00�(0.63%),1177953,0.00566190448495522 -RB.L,Reckitt Benckiser Group PLC,"6,293.00�13:14",�34.00�(0.54%),281172,0.0013514707359664 -RBS.L,Royal Bank of Scotland Group PLC,313.40�13:14,�2.40�(0.77%),2100058,0.0100940596177149 -RDSA.L,Royal Dutch Shell PLC,"1,636.00�13:14",�18.00�(1.11%),2467461,0.0118600050276642 -RDSB.L,Royal Dutch Shell PLC,"1,652.00�13:15",�14.50�(0.89%),1457434,0.0070052473240666 -REL.L,Reed Elsevier PLC,"1,170.00�13:14",0.00�(0.00%),908802,0.00436821343443777 -RIO.L,Rio Tinto PLC,"2,235.00�13:15",�21.00�(0.95%),2190722,0.0105298417823887 -RMG.L,Royal Mail PLC,453.50�13:14,�1.20�(0.26%),995316,0.00478404836555252 -RR.L,Rolls-Royce Group PLC,546.63�13:14,�8.38�(1.51%),2792915,0.0134243199555489 -RRS.L,Randgold Resources Ltd,"3,929.00�13:14",0.00�(0.00%),135524,0.000651404549603483 -RSA.L,RSA Insurance Group PLC,437.10�13:14,�0.10�(0.02%),395477,0.00190088484005443 -SAB.L,SABMiller PLC,"4,011.00�13:15",�1.00�(0.02%),892451,0.00428962133421518 -SBRY.L,Sainsbury (J) PLC,255.80�13:14,�7.40�(2.98%),2395670,0.0115149371133421 -SDR.L,Schroders PLC,"2,930.00�13:09",�12.00�(0.41%),44674,0.000214728364341268 -SGE.L,Sage Group (The) PLC,545.50�13:13,�0.50�(0.09%),539717,0.00259418338669419 -SHP.L,Shire PLC,"4,685.00�13:14",�22.00�(0.47%),221318,0.0010637787558598 -SKY.L,SKY,"1,095.00�13:12",�4.00�(0.37%),925016,0.0044461470356248 -SL.L,Standard Life PLC,399.90�13:14,�3.20�(0.79%),861636,0.00414150711683647 -SMIN.L,Smiths Group PLC,992.50�13:14,�27.50�(2.70%),640309,0.00307768510191594 -SN.L,Smith & Nephew PLC,"1,110.00�13:14",�9.00�(0.82%),480018,0.00230723642374461 -SPD.L,Sports Direct International PLC,694.50�13:11,�1.50�(0.22%),157981,0.000759345519250522 -SSE.L,SSE PLC,"1,463.00�13:13",�2.00�(0.14%),562454,0.00270347019378617 -STAN.L,Standard Chartered PLC,583.00�13:14,�0.60�(0.10%),2018697,0.00970299290214945 -STJ.L,St James's Place PLC,964.00�13:14,�11.00�(1.13%),418480,0.00201145019271912 -SVT.L,Severn Trent PLC,"2,199.00�13:12",�1.00�(0.05%),95342,0.000458267263129005 -TPK.L,Travis Perkins PLC,"1,945.00�13:13",�4.00�(0.21%),92916,0.000446606542981001 -TSCO.L,Tesco PLC,171.54�13:14,�2.54�(1.50%),9831136,0.0472539676970174 -TUI.L,TUI AG,"1,115.00�13:10",�5.00�(0.45%),458970,0.00220606790038304 -TW.L,Taylor Wimpey PLC,183.90�13:15,�1.10�(0.59%),3180729,0.0152883721086725 -ULVR.L,Unilever PLC,"2,791.00�13:14",�29.00�(1.03%),824827,0.0039645823650113 -UU.L,United Utilities Group PLC,959.00�13:10,�2.50�(0.26%),436911,0.00210003994253274 -VOD.L,Vodafone Group PLC,224.25�13:15,�1.30�(0.58%),17572036,0.0844610858312637 -WOS.L,Wolseley PLC,"3,657.00�13:14",�4.00�(0.11%),179536,0.000862950969699912 -WPP.L,WPP PLC,"1,502.00�13:15",�12.00�(0.79%),857887,0.0041234873147611 -WTB.L,Whitbread PLC,"4,484.00�13:16",�60.00�(1.32%),141036,0.000677898321019722 -,,,,208048900, diff --git a/example/basket/src/main/resources/static/hsi.csv b/example/basket/src/main/resources/static/hsi.csv deleted file mode 100644 index fcd24d46c..000000000 --- a/example/basket/src/main/resources/static/hsi.csv +++ /dev/null @@ -1,81 +0,0 @@ -Name,Symbol,Last,Change,Change %,Volume,Turn.,P/E,P/B,Yield,Market Cap,Weighting -CKH HOLDINGS,00001.HK,41.9,1.15,+2.822%,5.15M,215.13M,4.38,0.31,6.98%,160.48B,0.0278736825813547 -CLP HOLDINGS,00002.HK,57.95,-0.1,-0.172%,3.32M,193.19M,156.62,1.39,5.35%,146.41B,0.000417248060431947 -HK & CHINA GAS,00003.HK,5.46,0.13,+2.439%,16.16M,88.00M,19.43,1.66,6.41%,101.88B,0.000417248060431947 -HSBC HOLDINGS,00005.HK,61.7,1.1,+1.815%,22.19M,1.37B,10.54,0.86,4.05%,1,0.00387831899135251 -POWER ASSETS,00006.HK,37.9,-0.25,-0.655%,4.23M,160.75M,14.3,0.93,7.44%,80.77B,0.00159219779580666 -HANG SENG BANK,00011.HK,97.45,2.95,+3.122%,2.54M,247.44M,19.69,1.01,4.21%,186.31B,0.00843059492263598 -HENDERSON LAND,00012.HK,20.65,0.85,+4.293%,5.07M,103.70M,10.81,0.31,8.72%,99.97B,0.00228757277736148 -SHK PPT,00016.HK,83.8,3.25,+4.035%,8.25M,685.41M,10.16,0.4,5.91%,242.83B,0.0107034211668507 -NEW WORLD DEV,00017.HK,15.24,0.8,+5.540%,12.95M,196.19M,30.48,0.18,13.52%,38.35B,0.00391798755004232 -GALAXY ENT,00027.HK,47.15,1.9,+4.199%,11.97M,560.21M,No Profit,3.22,0.00%,206.21B,0.00980506986578636 -MTR CORPORATION,00066.HK,31,0.8,+2.649%,4.68M,144.86M,19.5,1.07,4.23%,192.64B,0.00100752275066102 -HANG LUNG PPT,00101.HK,10.72,0.56,+5.512%,7.68M,81.99M,12.61,0.36,7.28%,48.23B,0.0316063387021032 -GEELY AUTO,00175.HK,9.24,0.17,+1.874%,18.77M,173.30M,16.06,1.15,2.27%,92.99B,0.0022355801929258 -ALI HEALTH,00241.HK,4.88,0.47,+10.658%,53.62M,257.82M,108.09,3.81,0.00%,66.04B,0.00501980543997108 -CITIC,00267.HK,7.2,0.2,+2.857%,11.54M,82.96M,2.78,0.28,9.04%,209.45B,0.00724508516988073 -WH GROUP,00288.HK,4.11,0.08,+1.985%,18.94M,77.65M,4.93,0.7,7.30%,52.73B,0.000456964684744788 -CHINA RES BEER,00291.HK,42.95,1.2,+2.874%,4.83M,207.98M,28.41,4.57,1.41%,139.34B,0.00866405926683583 -OOIL,00316.HK,104.5,-0.4,-0.381%,296.54K,30.98M,0.89,0.66,78.90%,69.01B,0.0237794431982097 -TINGYI,00322.HK,10.94,0.18,+1.673%,2.91M,31.81M,20.75,4.09,9.39%,61.64B,0.000502482829757812 -SINOPEC CORP,00386.HK,4.28,-0.01,-0.233%,92.43M,396.61M,6.94,0.58,9.36%,105.92B,0.0504379547308349 -HKEX,00388.HK,292.6,9,+3.173%,4.61M,1.34B,36.76,7.46,2.44%,370.97B,0.00142104572530785 -TECHTRONIC IND,00669.HK,76,1.35,+1.808%,5.47M,414.78M,16.54,3.43,2.43%,139.45B,0.0188176048996174 -CHINA OVERSEAS,00688.HK,16.24,0.52,+3.308%,13.15M,212.60M,6.76,0.44,4.93%,177.74B,0.000414599644602783 -TENCENT,00700.HK,306.2,8.8,+2.959%,11.25M,3.43B,13.74,3.6,0.78%,2,0.0103078651220939 -CHINA UNICOM,00762.HK,5.68,-0.05,-0.873%,9.23M,52.77M,9.16,0.45,5.44%,173.80B,0.00481217156158961 -LINK REIT,00823.HK,38.4,1.45,+3.924%,12.04M,460.96M,5.42,0.52,7.03%,98.38B,0.0011756418803464 -CHINA RES POWER,00836.HK,14.94,0.32,+2.189%,9.91M,147.81M,10.23,0.87,3.92%,71.87B,0.00431304851888186 -PETROCHINA,00857.HK,5.9,0,0.000%,64.23M,380.44M,6.38,0.7,8.08%,124.48B,0.00363811584680332 -XINYI GLASS,00868.HK,10.14,0.17,+1.705%,3.75M,38.02M,8.01,1.3,6.11%,42.22B,0.00363811584680332 -ZHONGSHENG HLDG,00881.HK,22.05,1.45,+7.039%,6.76M,147.71M,7.08,1.07,4.94%,52.72B,0.00526481995338596 -CNOOC,00883.HK,13.78,-0.02,-0.145%,26.37M,365.08M,4.03,0.97,19.09%,655.47B,0.00224602485281105 -CCB,00939.HK,4.42,0.06,+1.376%,233.61M,1.03B,3.06,0.35,9.93%,1,0.00572572121265722 -CHINA MOBILE,00941.HK,65.7,0.25,+0.382%,7.82M,516.10M,9.91,0.96,6.71%,1,0.00183548675335462 -LONGFOR GROUP,00960.HK,14.08,0.9,+6.829%,10.88M,150.68M,3.06,0.55,9.05%,92.81B,0.00527064070033535 -XINYI SOLAR,00968.HK,5.86,0.28,+5.018%,15.99M,92.88M,13.64,1.75,3.41%,52.17B,0.00380798456516713 -SMIC,00981.HK,20.05,0.25,+1.263%,13.10M,264.32M,11.17,1.06,0.00%,159.31B,0.200104533116974 -LENOVO GROUP,00992.HK,8.07,0.25,+3.197%,33.60M,270.50M,7.61,2.23,4.71%,97.87B,0.00849490672625522 -CKI HOLDINGS,01038.HK,37.05,-0.2,-0.537%,1.44M,53.73M,12.03,0.78,6.83%,93.35B,0.00125696891451962 -HENGAN INT'L,01044.HK,24.95,0.2,+0.808%,2.62M,64.97M,13.35,1.32,6.33%,28.99B,0.00178929568961912 -CHINA SHENHUA,01088.HK,25.4,0.35,+1.397%,7.98M,203.11M,6.14,1.13,11.33%,85.79B,0.0022989835562697 -CSPC PHARMA,01093.HK,5.74,0.05,+0.879%,29.29M,167.41M,9.96,2.01,3.66%,68.32B,0.0356436828072631 -SINOPHARM,01099.HK,22.7,0.2,+0.889%,2.07M,46.80M,7.37,0.92,4.08%,30.46B,0.0207235606629018 -CHINA RES LAND,01109.HK,31.2,1,+3.311%,9.88M,305.88M,7.02,0.81,5.07%,222.49B,0.00105704956863507 -CK ASSET,01113.HK,41.25,1.25,+3.125%,8.57M,352.44M,6.9,0.39,5.53%,146.47B,0.000913184352332553 -SINO BIOPHARM,01177.HK,2.83,0.02,+0.712%,26.30M,74.09M,18.37,1.59,4.24%,53.21B,0.00445479884777089 -CHINA RES MIXC,01209.HK,31.6,1.6,+5.333%,3.07M,96.42M,28.97,4.48,2.87%,72.13B,0.0024745192115892 -BYD COMPANY,01211.HK,242,7,+2.979%,3.90M,938.50M,37.57,5.63,0.53%,265.72B,0.00474931133978598 -AIA,01299.HK,63.85,0.95,+1.510%,38.75M,2.48B,408.88,2.53,2.41%,735.40B,0.000220467399731505 -CHINAHONGQIAO,01378.HK,7.67,0.28,+3.789%,13.05M,99.58M,7.27,0.76,6.65%,72.68B,0.0165980593985356 -ICBC,01398.HK,3.77,0.07,+1.892%,233.48M,881.67M,3.45,0.36,9.08%,327.21B,0.00132851940096775 -XIAOMI-W,01810.HK,12.34,0.62,+5.290%,78.53M,960.98M,109.39,1.9,0.00%,308.83B,0.00490946118917235 -BUD APAC,01876.HK,15.46,0.16,+1.046%,16.17M,250.45M,28.65,2.44,1.91%,204.74B,0.00185039670961971 -SANDS CHINA LTD,01928.HK,24,0.95,+4.121%,19.98M,475.93M,No Profit,N/A,0.00%,194.24B,0.00960542930051541 -CHOW TAI FOOK,01929.HK,11.8,0.28,+2.431%,4.88M,57.68M,21.93,3.64,10.34%,118.00B,0.0908818936317375 -WHARF REIC,01997.HK,30.25,1.4,+4.853%,4.23M,127.31M,No Profit,0.48,4.33%,91.85B,0.000623204448569543 -ANTA SPORTS,02020.HK,88.15,4.4,+5.254%,4.82M,422.51M,27.71,6.16,1.52%,249.70B,0.00293702105610748 -WUXI BIO,02269.HK,45.65,1.55,+3.515%,17.91M,811.49M,38.18,4.88,0.00%,194.01B,0.00442265255908587 -SHENZHOU INTL,02313.HK,75,4.6,+6.534%,5.52M,410.68M,21.87,3.25,2.55%,112.74B,0.00184353774521278 -PING AN,02318.HK,44.85,0.85,+1.932%,23.05M,1.03B,8.28,0.85,6.09%,334.02B,0.00442265255908587 -MENGNIU DAIRY,02319.HK,26.25,1.5,+6.061%,8.58M,223.15M,17.34,2.3,1.73%,103.42B,0.00797693234619361 -LI NING,02331.HK,32.95,1.5,+4.769%,22.54M,738.37M,18.8,3.16,1.58%,86.86B,0.000548246109448308 -SUNNY OPTICAL,02382.HK,54.7,1.05,+1.957%,5.62M,308.60M,22.01,2.44,0.91%,60.00B,0.00980946787029396 -BOC HONG KONG,02388.HK,21.45,0.3,+1.418%,6.53M,140.32M,8.38,0.75,6.33%,226.79B,0.00279198784516525 -CHINA LIFE,02628.HK,12.2,0.24,+2.007%,13.53M,165.07M,9.49,0.7,4.53%,90.78B,0.00566190448495522 -ENN ENERGY,02688.HK,65,1.15,+1.801%,3.06M,198.69M,11.08,1.67,4.48%,73.53B,0.0013514707359664 -ZIJIN MINING,02899.HK,11.98,0.16,+1.354%,16.20M,194.50M,13.97,3.14,1.88%,68.73B,0.0100940596177149 -MEITUAN-W,03690.HK,114.6,3.8,+3.430%,19.17M,2.19B,No Profit,4.89,0.00%,715.43B,0.0118600050276642 -HANSOH PHARMA,03692.HK,10.66,0.16,+1.524%,17.56M,187.72M,21.48,2.47,0.94%,63.25B,0.0070052473240666 -CM BANK,03968.HK,32.7,0.1,+0.307%,11.13M,363.99M,5.51,0.86,6.00%,150.12B,0.00436821343443777 -BANK OF CHINA,03988.HK,2.74,0.05,+1.859%,275.47M,754.54M,3.33,0.33,9.55%,229.13B,0.0105298417823887 -CG SERVICES,06098.HK,8.08,0.25,+3.193%,16.08M,128.87M,12.42,0.65,5.20%,27.01B,0.00478404836555252 -JD HEALTH,06618.HK,40.6,2.95,+7.835%,7.75M,312.36M,299.91,2.56,0.00%,129.12B,0.0134243199555489 -HAIER SMARTHOME,06690.HK,24.65,1.15,+4.894%,7.24M,178.37M,13.83,2.21,2.59%,70.46B,0.000651404549603483 -HAIDILAO,06862.HK,21,0.6,+2.941%,6.86M,143.79M,74.46,13.94,0.55%,117.05B,0.00190088484005443 -JD-SW,09618.HK,115.1,4,+3.600%,7.43M,852.28M,30.73,1.5,6.38%,360.24B,0.00428962133421518 -NONGFU SPRING,09633.HK,45,1.5,+3.448%,3.69M,165.62M,52.49,18.63,1.71%,226.56B,0.0115149371133421 -BIDU-SW,09888.HK,133.4,4.6,+3.571%,5.82M,772.73M,47.3,1.5,0.00%,377.37B,0.000214728364341268 -TRIP.COM-S,09961.HK,279.2,7,+2.572%,1.25M,349.59M,114.05,1.4,0.00%,176.65B,0.00259418338669419 -BABA-SW,09988.HK,85.6,2.6,+3.133%,34.61M,2.96B,21.65,1.62,0.00%,1,0.0010637787558598 -NTES-S,09999.HK,159.5,8.3,+5.489%,5.02M,797.10M,22.7,4.63,1.36%,546.99B,0.0044461470356248 diff --git a/example/basket/src/main/resources/static/nasdaq100.csv b/example/basket/src/main/resources/static/nasdaq100.csv deleted file mode 100644 index 6447cbb7a..000000000 --- a/example/basket/src/main/resources/static/nasdaq100.csv +++ /dev/null @@ -1,102 +0,0 @@ -#,Name,Symbol,Weighting,Last Trade,Chg,% Chg -1,Apple Inc,AAPL,11.007,174.94,0.15,(0.09%) -2,Microsoft Corp,MSFT,9.61,316.98,-0.03,(-0.01%) -3,Amazon.com Inc,AMZN,5.401,129.31,0.19,(0.14%) -4,NVIDIA Corp,NVDA,4.101,415.74,-0.36,(-0.09%) -5,Meta Platforms Inc,META,3.729,299.42,0.34,(0.11%) -6,Tesla Inc,TSLA,3.285,244.13,-0.75,(-0.31%) -7,Alphabet Inc,GOOGL,3.133,130.49,0.24,(0.18%) -8,Alphabet Inc,GOOG,3.085,131.49,0.24,(0.18%) -9,Broadcom Inc,AVGO,2.896,833.04,3.96,(0.48%) -10,Costco Wholesale Corp,COST,2.137,557.85,-0.74,(-0.13%) -11,PepsiCo Inc,PEP,2.096,174.84,-0.43,(-0.25%) -12,Adobe Inc,ADBE,2.033,511.42,-1.48,(-0.29%) -13,Cisco Systems Inc,CSCO,1.887,53.68,0.11,(0.20%) -14,Comcast Corp,CMCSA,1.633,45.30,-0.01,(-0.01%) -15,Netflix Inc,NFLX,1.478,379.89,0.08,(0.02%) -16,T-Mobile US Inc,TMUS,1.43,140.18,0.83,(0.60%) -17,Advanced Micro Devices Inc,AMD,1.348,96.09,-0.11,(-0.12%) -18,Texas Instruments Inc,TXN,1.264,161.00,0.69,(0.43%) -19,Intel Corp,INTC,1.26,34.19,0.01,(0.01%) -20,Amgen Inc,AMGN,1.251,271.18,3.48,(1.30%) -21,Intuit Inc,INTU,1.226,509.00,0.43,(0.08%) -22,Honeywell International Inc,HON,1.103,188.67,-1.12,(-0.59%) -23,QUALCOMM Inc,QCOM,1.046,107.53,-0.16,(-0.14%) -24,Applied Materials Inc,AMAT,0.982,136.32,0.15,(0.11%) -25,Booking Holdings Inc,BKNG,0.941,3,019.20,-43.30,(-1.42%) -26,Starbucks Corp,SBUX,0.926,93.80,0.12,(0.12%) -27,Intuitive Surgical Inc,ISRG,0.867,288.50,0.30,(0.10%) -28,Automatic Data Processing Inc,ADP,0.854,239.45,0.10,(0.04%) -29,Mondelez International Inc,MDLZ,0.835,71.25,0.82,(1.16%) -30,Gilead Sciences Inc,GILD,0.814,75.47,0.46,(0.61%) -31,Vertex Pharmaceuticals Inc,VRTX,0.794,353.67,4.14,(1.18%) -32,Regeneron Pharmaceuticals Inc,REGN,0.763,828.09,3.25,(0.39%) -33,Analog Devices Inc,ADI,0.752,176.82,1.34,(0.76%) -34,Lam Research Corp,LRCX,0.702,620.00,0.89,(0.14%) -35,Micron Technology Inc,MU,0.646,68.90,0.02,(0.03%) -36,Palo Alto Networks Inc,PANW,0.604,228.70,0.19,(0.08%) -37,Synopsys Inc,SNPS,0.587,447.12,0.27,(0.06%) -38,Charter Communications Inc,CHTR,0.581,441.88,-3.33,(-0.75%) -39,MercadoLibre Inc,MELI,0.562,1,275.50,-1.47,(-0.11%) -40,PayPal Holdings Inc,PYPL,0.559,57.90,0.02,(0.03%) -41,CSX Corp,CSX,0.54,31.23,0.03,(0.09%) -42,Cadence Design Systems Inc,CDNS,0.539,230.83,0.17,(0.07%) -43,KLA Corp,KLAC,0.53,456.11,4.29,(0.95%) -44,PDD Holdings Inc ADR,PDD,0.521,95.93,-0.01,(-0.01%) -45,Marriott International Inc/MD,MAR,0.505,193.90,-0.46,(-0.23%) -46,Monster Beverage Corp,MNST,0.498,54.48,-0.04,(-0.08%) -47,Airbnb Inc,ABNB,0.491,132.09,-0.11,(-0.08%) -48,O'Reilly Automotive Inc,ORLY,0.485,936.67,0.65,(0.07%) -49,Cintas Corp,CTAS,0.446,505.27,0.52,(0.10%) -50,ASML Holding NV,ASML,0.438,585.00,-2.10,(-0.36%) -51,NXP Semiconductors NV,NXPI,0.434,196.76,-0.04,(-0.02%) -52,Workday Inc,WDAY,0.414,235.55,4.73,(2.05%) -53,Lululemon Athletica Inc,LULU,0.405,386.36,-1.69,(-0.44%) -54,Keurig Dr Pepper Inc,KDP,0.404,33.25,0.13,(0.39%) -55,Fortinet Inc,FTNT,0.401,58.29,0.05,(0.09%) -56,Marvell Technology Inc,MRVL,0.388,52.38,0.08,(0.14%) -57,PACCAR Inc,PCAR,0.38,84.97,0.04,(0.04%) -58,Old Dominion Freight Line Inc,ODFL,0.38,401.01,0.35,(0.09%) -59,Autodesk Inc,ADSK,0.379,204.07,0.03,(0.01%) -60,Kraft Heinz Co/The,KHC,0.368,34.27,0.11,(0.31%) -61,Microchip Technology Inc,MCHP,0.36,77.00,-0.08,(-0.10%) -62,Copart Inc,CPRT,0.358,43.26,0.10,(0.22%) -63,American Electric Power Co Inc,AEP,0.357,79.23,0.06,(0.08%) -64,Paychex Inc,PAYX,0.355,113.01,0.06,(0.06%) -65,Exelon Corp,EXC,0.35,40.28,0.07,(0.16%) -66,ON Semiconductor Corp,ON,0.341,93.87,0.06,(0.06%) -67,AstraZeneca PLC ADR,AZN,0.339,67.35,-0.49,(-0.72%) -68,Seagen Inc,SGEN,0.336,212.18,-1.52,(-0.71%) -69,Ross Stores Inc,ROST,0.335,111.71,0.05,(0.04%) -70,Moderna Inc,MRNA,0.331,100.32,0.33,(0.33%) -71,Biogen Inc,BIIB,0.326,257.93,0.25,(0.10%) -72,Crowdstrike Holdings Inc,CRWD,0.319,162.85,0.28,(0.17%) -73,IDEXX Laboratories Inc,IDXX,0.316,439.41,3.72,(0.85%) -74,Baker Hughes Co,BKR,0.307,35.44,0.04,(0.10%) -75,Constellation Energy Corp,CEG,0.307,110.41,0.05,(0.04%) -76,Cognizant Technology Solutions Corp,CTSH,0.303,70.19,0.58,(0.83%) -77,Verisk Analytics Inc,VRSK,0.303,242.05,0.10,(0.04%) -78,Dexcom Inc,DXCM,0.3,88.30,0.80,(0.92%) -79,Trade Desk Inc/The,TTD,0.293,76.38,0.03,(0.03%) -80,Xcel Energy Inc,XEL,0.284,59.76,0.03,(0.04%) -81,Electronic Arts Inc,EA,0.279,118.38,-0.63,(-0.53%) -82,CoStar Group Inc,CSGP,0.277,78.18,0.12,(0.15%) -83,GLOBALFOUNDRIES Inc,GFS,0.273,57.21,0.38,(0.67%) -84,Fastenal Co,FAST,0.268,54.32,0.11,(0.20%) -85,Atlassian Corp,TEAM,0.253,196.01,0.55,(0.28%) -86,GE HealthCare Technologies Inc,GEHC,0.252,63.78,-0.56,(-0.86%) -87,Warner Bros Discovery Inc,WBD,0.244,11.09,-0.02,(-0.14%) -88,Diamondback Energy Inc,FANG,0.235,150.70,0.13,(0.09%) -89,Datadog Inc,DDOG,0.23,88.81,0.05,(0.06%) -90,ANSYS Inc,ANSS,0.227,300.60,-2.31,(-0.76%) -91,eBay Inc,EBAY,0.203,43.22,0.09,(0.20%) -92,Dollar Tree Inc,DLTR,0.201,104.77,0.27,(0.25%) -93,Align Technology Inc,ALGN,0.2,297.25,-1.31,(-0.44%) -94,Zscaler Inc,ZS,0.188,151.80,0.09,(0.06%) -95,Illumina Inc,ILMN,0.183,132.31,-0.13,(-0.10%) -96,Walgreens Boots Alliance Inc,WBA,0.161,21.18,0.06,(0.28%) -97,Zoom Video Communications Inc,ZM,0.151,68.57,-0.29,(-0.41%) -98,Enphase Energy Inc,ENPH,0.148,120.41,0.49,(0.41%) -99,Sirius XM Holdings Inc,SIRI,0.137,4.05,0.02,(0.50%) -100,JD.com Inc ADR,JD,0.117,30.43,0.02,(0.05%) -101,Lucid Group Inc,LCID,0.102,5.14,0.03,(0.49%) \ No newline at end of file diff --git a/example/basket/src/main/resources/static/sp500.csv b/example/basket/src/main/resources/static/sp500.csv deleted file mode 100644 index 19701b2cc..000000000 --- a/example/basket/src/main/resources/static/sp500.csv +++ /dev/null @@ -1,504 +0,0 @@ -#,Name,Symbol,Weighting,Price,Change,Change %, -1,Apple Inc,AAPL,6.992488,171.9,1.47,(0.86%), -2,Microsoft Corp,MSFT,6.487978,314.55,1.76,(0.56%), -3,Amazon.com Inc,AMZN,3.193379,126.25,0.27,(0.22%), -4,Nvidia Corp,NVDA,2.928461,433.11,8.43,(1.99%), -5,Alphabet Inc Cl A,GOOGL,2.162218,132.93,2.39,(1.83%), -6,Tesla Inc,TSLA,1.854311,246.56,6.06,(2.52%), -7,Alphabet Inc Cl C,GOOG,1.85251,133.81,2.35,(1.78%), -8,Meta Platforms Inc Class A,META,1.847731,305.93,8.19,(2.75%), -9,Berkshire Hathaway Inc Cl B,BRK.B,1.82184,358.67,0.89,(0.25%), -10,Exxon Mobil Corp,XOM,1.343563,118.97,-1.23,(-1.03%), -11,Unitedhealth Group Inc,UNH,1.302884,510.04,6.31,(1.25%), -12,Eli Lilly & Co,LLY,1.224046,546.65,-3.11,(-0.57%), -13,Jpmorgan Chase & Co,JPM,1.182918,148.23,2.45,(1.68%), -14,Johnson & Johnson W/d,JNJ,1.056344,156.83,-0.28,(-0.18%), -15,Visa Inc Class a Shares,V,1.029636,231.97,2.47,(1.08%), -16,Procter & Gamble Co,PG,0.969793,145.75,-1.59,(-1.08%), -17,Broadcom Inc,AVGO,0.941177,835.33,18.52,(2.27%), -18,Mastercard Inc A,MA,0.918779,400.65,5.17,(1.31%), -19,Chevron Corp,CVX,0.847353,170.55,-0.49,(-0.28%), -20,Home Depot Inc,HD,0.847289,304.35,2.53,(0.84%), -22,Abbvie Inc,ABBV,0.754672,152.14,-0.99,(-0.65%), -23,Merck & Co. Inc.,MRK,0.736434,104.2,0.26,(0.25%), -24,Costco Wholesale Corp,COST,0.697258,569.05,5.52,(0.98%), -25,Pepsico Inc,PEP,0.651768,168.92,-0.65,(-0.38%), -26,Walmart Inc,WMT,0.644449,161.87,0.15,(0.09%), -27,Adobe Inc,ADBE,0.639652,507.17,4.57,(0.91%), -28,Coca Cola Co,KO,0.60801,55.82,-0.13,(-0.23%), -29,Cisco Systems Inc,CSCO,0.605326,53.97,0.77,(1.44%), -30,Accenture Plc Cl A,ACN,0.55372,298.5,-15.9,(-5.05%), -31,Salesforce Inc,CRM,0.551342,204.46,1.73,(0.85%), -32,Thermo Fisher Scientific Inc,TMO,0.536951,503.47,5.18,(1.04%), -33,Mcdonald S Corp,MCD,0.536457,265.83,2.19,(0.83%), -34,Bank of America Corp,BAC,0.526405,27.51,0.24,(0.86%), -35,Comcast Corp Class A,CMCSA,0.512537,45.17,0.57,(1.27%), -36,Linde Plc,LIN,0.506835,375.48,3.47,(0.93%), -37,Pfizer Inc,PFE,0.506043,32.09,-0.02,(-0.05%), -38,Netflix Inc,NFLX,0.467192,377.77,0.18,(0.05%), -39,Abbott Laboratories,ABT,0.462893,97.52,1.99,(2.08%), -40,Oracle Corp,ORCL,0.459877,106.29,1.67,(1.60%), -41,Danaher Corp,DHR,0.454026,248.24,0.8,(0.32%), -42,Advanced Micro Devices,AMD,0.442473,103.74,5.67,(5.78%), -43,Wells Fargo & Co,WFC,0.417428,41.04,0.18,(0.43%), -44,Conocophillips,COP,0.411569,123.32,0.23,(0.18%), -45,Walt Disney Co,DIS,0.408438,80.35,0.45,(0.56%), -46,Intel Corp,INTC,0.404462,35.5,0.89,(2.56%), -47,Amgen Inc,AMGN,0.401904,270.91,1.93,(0.72%), -48,Texas Instruments Inc,TXN,0.400931,160.98,2.84,(1.80%), -49,Intuit Inc,INTU,0.397406,515.11,6.87,(1.35%), -50,Philip Morris International,PM,0.39143,92.66,2.34,(2.59%), -51,Caterpillar Inc,CAT,0.388444,276.34,3.63,(1.33%), -52,Verizon Communications Inc,VZ,0.380327,32.56,0.16,(0.48%), -53,Intl Business Machines Corp,IBM,0.364246,140.89,-2.28,(-1.59%), -54,Honeywell International Inc,HON,0.348317,188.68,0.8,(0.43%), -55,Union Pacific Corp,UNP,0.344419,203.88,1.48,(0.73%), -56,Qualcomm Inc,QCOM,0.340195,111.55,2.36,(2.16%), -57,Nextera Energy Inc,NEE,0.338809,57.64,-2.32,(-3.88%), -58,Lowe S Cos Inc,LOW,0.338613,209.52,2.56,(1.24%), -59,Bristol Myers Squibb Co,BMY,0.337683,58.3,0.41,(0.70%), -60,General Electric Co,GE,0.336989,112.43,1.54,(1.39%), -61,S&p Global Inc,SPGI,0.32985,369.21,6.15,(1.69%), -62,Applied Materials Inc,AMAT,0.316678,139.15,4.09,(3.03%), -63,Servicenow Inc,NOW,0.3112,552.84,6.46,(1.18%), -64,Boeing Co,BA,0.309673,193.12,-2.34,(-1.20%), -65,United Parcel Service Cl B,UPS,0.307795,154.29,1.88,(1.23%), -66,Booking Holdings Inc,BKNG,0.307126,3,86.26,3.6,(0.12%) -67,Nike Inc Cl B,NKE,0.305871,89.63,0.21,(0.24%), -68,At&t Inc,T,0.296603,14.94,0.07,(0.44%), -69,Goldman Sachs Group Inc,GS,0.296356,325.72,3.77,(1.17%), -70,Rtx Corp,RTX,0.296189,72.54,-0.34,(-0.46%), -71,Elevance Health Inc,ELV,0.292632,448.99,4.23,(0.95%), -72,Deere & Co,DE,0.291602,388.36,4,(1.04%), -73,Starbucks Corp,SBUX,0.291579,91.21,0.04,(0.04%), -74,Morgan Stanley,MS,0.29087,82.34,0.69,(0.84%), -75,Medtronic Plc,MDT,0.290688,78.77,0.55,(0.71%), -76,Prologis Inc,PLD,0.286912,112.3,1.05,(0.94%), -77,Intuitive Surgical Inc,ISRG,0.285764,296.31,4.88,(1.67%), -78,Tjx Companies Inc,TJX,0.282733,89.27,1.16,(1.32%), -79,Automatic Data Processing,ADP,0.279113,243.79,1.16,(0.48%), -80,Marsh & Mclennan Cos,MMC,0.266169,193.53,0.55,(0.29%), -81,Mondelez International Inc A,MDLZ,0.26425,69.44,-0.56,(-0.79%), -82,Gilead Sciences Inc,GILD,0.26285,75.96,0.41,(0.54%), -83,Lockheed Martin Corp,LMT,0.255775,410.4,1.68,(0.41%), -84,Blackrock Inc,BLK,0.252096,645.37,1.98,(0.31%), -85,Vertex Pharmaceuticals Inc,VRTX,0.251521,353.91,4.26,(1.22%), -86,Stryker Corp,SYK,0.250789,273.07,6.53,(2.45%), -87,Cvs Health Corp,CVS,0.250255,70.11,0.33,(0.47%), -88,Regeneron Pharmaceuticals,REGN,0.2481,835.67,3.11,(0.37%), -89,American Express Co,AXP,0.243515,150.42,0.52,(0.34%), -90,Chubb Ltd,CB,0.242706,212.92,1.29,(0.61%), -91,Analog Devices Inc,ADI,0.241943,177.01,4.2,(2.43%), -92,Schlumberger Ltd,SLB,0.241232,61.02,0.22,(0.36%), -93,Eaton Corp Plc,ETN,0.238556,216.42,2.06,(0.96%), -94,The Cigna Group,CI,0.238517,291.43,2.82,(0.98%), -95,Progressive Corp,PGR,0.229854,140.76,0.14,(0.10%), -96,Lam Research Corp,LRCX,0.228483,627.46,13.54,(2.20%), -97,Schwab (Charles) Corp,SCHW,0.225784,54.57,0.19,(0.35%), -98,Zoetis Inc,ZTS,0.224522,174.68,0,(-0.00%), -99,Citigroup Inc,C,0.217552,41.24,0.78,(1.92%), -100,Boston Scientific Corp,BSX,0.213003,53.3,1.2,(2.31%), -101,Blackstone Inc,BX,0.211158,108.88,2.33,(2.19%), -102,Eog Resources Inc,EOG,0.21104,130.56,0.75,(0.57%), -103,Becton Dickinson and Co,BDX,0.209627,262.6,3.8,(1.47%), -104,Micron Technology Inc,MU,0.208276,66.25,-1.96,(-2.87%), -105,American Tower Corp,AMT,0.207727,160.73,1.04,(0.65%), -106,Altria Group Inc,MO,0.207666,42.11,0.2,(0.47%), -107,T Mobile Us Inc,TMUS,0.20192,140.3,0.6,(0.43%), -108,Cme Group Inc,CME,0.201368,200.22,-0.14,(-0.07%), -109,Southern Co,SO,0.20116,65.04,-1.1,(-1.67%), -110,Palo Alto Networks Inc,PANW,0.198047,236.42,4.52,(1.95%), -111,Duke Energy Corp,DUK,0.193827,88.87,-1.23,(-1.36%), -112,Fiserv Inc,FI,0.192662,113.67,0.48,(0.42%), -113,Synopsys Inc,SNPS,0.189768,458.88,12.17,(2.72%), -114,Activision Blizzard Inc,ATVI,0.18717,93.71,-0.22,(-0.23%), -115,Aon Plc Class A,AON,0.186896,330.04,0.12,(0.04%), -116,Equinix Inc,EQIX,0.184757,715.84,8.74,(1.24%), -117,Illinois Tool Works,ITW,0.177501,233.17,0.77,(0.33%), -118,Air Products & Chemicals Inc,APD,0.17678,289.15,3.89,(1.36%), -119,Paypal Holdings Inc,PYPL,0.175802,58.3,0.96,(1.67%), -120,Cadence Design Sys Inc,CDNS,0.175052,235.09,4.44,(1.93%), -121,Northrop Grumman Corp,NOC,0.173654,441.3,4.06,(0.93%), -122,Intercontinental Exchange In,ICE,0.172998,109.93,1.66,(1.53%), -123,Humana Inc,HUM,0.170476,495.73,2.16,(0.44%), -124,Marathon Petroleum Corp,MPC,0.170186,155.28,2.85,(1.87%), -125,Kla Corp,KLAC,0.170079,459.61,14.05,(3.15%), -126,Fedex Corp,FDX,0.169747,266.99,4.28,(1.63%), -127,Csx Corp,CSX,0.169632,30.62,0.34,(1.14%), -128,Mckesson Corp,MCK,0.167376,445.58,1.2,(0.27%), -129,Sherwin Williams Co,SHW,0.165389,254.95,4.33,(1.73%), -130,Colgate Palmolive Co,CL,0.164,71.11,0.06,(0.08%), -131,Airbnb Inc Class A,ABNB,0.159553,137.66,3.63,(2.70%), -132,Waste Management Inc,WM,0.15893,154.17,-0.25,(-0.16%), -133,Emerson Electric Co,EMR,0.154857,97.31,0.45,(0.47%), -134,O Reilly Automotive Inc,ORLY,0.154194,918.15,3.98,(0.44%), -135,Pioneer Natural Resources Co,PXD,0.1524,234.43,0.34,(0.14%), -136,Phillips 66,PSX,0.150197,122.81,2.01,(1.66%), -137,Freeport Mcmoran Inc,FCX,0.146185,37.34,0.79,(2.17%), -138,3m Co W/d,MMM,0.144312,93.48,0.02,(0.02%), -139,Roper Technologies Inc,ROP,0.144165,486.61,-0.02,(-0.00%), -140,Valero Energy Corp,VLO,0.141937,147.59,3.64,(2.53%), -141,Nxp Semiconductors Nv,NXPI,0.141583,202.19,5.49,(2.79%), -142,Target Corp,TGT,0.141106,109.31,-0.44,(-0.40%), -143,Parker Hannifin Corp,PH,0.140358,396.29,5.18,(1.32%), -144,Us Bancorp,USB,0.139291,32.59,0.07,(0.20%), -145,General Dynamics Corp,GD,0.139193,223.44,2.44,(1.10%), -146,Chipotle Mexican Grill Inc,CMG,0.139055,1,828.59,22.51,(1.25%) -147,Hca Healthcare Inc,HCA,0.138966,251.59,4.33,(1.75%), -148,Arthur J Gallagher & Co,AJG,0.138231,231.77,1.44,(0.62%), -149,Moody S Corp,MCO,0.138162,319.07,4.56,(1.45%), -150,Amphenol Corp Cl A,APH,0.136941,84.4,2.04,(2.47%), -151,Ford Motor Co,F,0.1362,12.58,0.19,(1.49%), -152,Marriott International Cl A,MAR,0.135619,199.53,5.65,(2.92%), -153,Pnc Financial Services Group,PNC,0.135457,123.09,1.28,(1.05%), -154,Transdigm Group Inc,TDG,0.131273,860.46,8.64,(1.01%), -155,Carrier Global Corp,CARR,0.129065,56.83,1.75,(3.17%), -156,Autozone Inc,AZO,0.128857,2,556.17,15.27,(0.60%) -157,Trane Technologies Plc,TT,0.12759,207.07,7.01,(3.50%), -158,Motorola Solutions Inc,MSI,0.127284,275.18,2.2,(0.81%), -159,Arista Networks Inc,ANET,0.12715,184.23,2.63,(1.45%), -160,Norfolk Southern Corp,NSC,0.124378,197.3,1.08,(0.55%), -161,General Motors Co,GM,0.124282,33.25,0.9,(2.77%), -162,Paccar Inc,PCAR,0.123613,86.12,1.31,(1.54%), -163,Charter Communications Inc A,CHTR,0.123199,442.28,8.86,(2.04%), -164,Hess Corp,HES,0.121942,157.3,-0.74,(-0.47%), -165,Sempra,SRE,0.121909,68.15,-1.26,(-1.81%), -166,Occidental Petroleum Corp,OXY,0.121531,66.03,0.43,(0.66%), -167,American International Group,AIG,0.121272,61.73,0.72,(1.18%), -168,Autodesk Inc,ADSK,0.120711,208.03,5.75,(2.84%), -169,Edwards Lifesciences Corp,EW,0.119074,69.68,-0.43,(-0.62%), -170,Ecolab Inc,ECL,0.118911,169.5,1.63,(0.97%), -171,Public Storage,PSA,0.117206,266.58,1.6,(0.60%), -172,Microchip Technology Inc,MCHP,0.116275,78.91,2.41,(3.15%), -173,Aflac Inc,AFL,0.11627,77.65,0.62,(0.81%), -174,Cintas Corp,CTAS,0.116227,486.83,5.75,(1.19%), -175,Welltower Inc,WELL,0.116157,81.07,0.87,(1.08%), -176,Williams Cos Inc,WMB,0.115685,34.65,0.55,(1.61%), -177,Kimberly Clark Corp,KMB,0.114902,121.11,-0.55,(-0.45%), -178,Archer Daniels Midland Co,ADM,0.114307,76.74,0.38,(0.50%), -179,Msci Inc,MSCI,0.113047,518.97,7.03,(1.37%), -180,Constellation Brands Inc A,STZ,0.112869,251.62,1.03,(0.41%), -181,On Semiconductor,ON,0.111009,95.12,3.07,(3.33%), -182,Metlife Inc,MET,0.110772,63.06,0.26,(0.41%), -183,Monster Beverage Corp,MNST,0.110311,53.31,0.19,(0.35%), -184,Hilton Worldwide Holdings In,HLT,0.109054,153.24,3.88,(2.60%), -185,American Electric Power,AEP,0.108899,74.71,-1.15,(-1.51%), -186,Crown Castle Inc,CCI,0.108512,91.35,1.65,(1.83%), -187,Exelon Corp,EXC,0.107894,38.11,-0.69,(-1.78%), -188,Nucor Corp,NUE,0.107787,158.31,2.6,(1.67%), -189,Travelers Cos Inc,TRV,0.107342,167.42,-0.51,(-0.30%), -190,Dominion Energy Inc,D,0.106001,44.61,-0.86,(-1.88%), -191,Te Connectivity Ltd,TEL,0.105581,123.84,3.4,(2.82%), -192,Halliburton Co,HAL,0.105449,42.18,0.15,(0.37%), -193,Centene Corp,CNC,0.105443,69.87,0.13,(0.18%), -194,Fortinet Inc,FTNT,0.105315,59.07,0.93,(1.59%), -195,Oneok Inc,OKE,0.104854,64.86,0.35,(0.53%), -196,General Mills Inc,GIS,0.104655,63.79,-0.26,(-0.40%), -197,Copart Inc,CPRT,0.104453,43.66,0.61,(1.41%), -198,Paychex Inc,PAYX,0.104412,117.4,0.89,(0.76%), -199,Biogen Inc,BIIB,0.103916,258.95,1.43,(0.55%), -200,Truist Financial Corp,TFC,0.103679,28.15,0.18,(0.63%), -201,Ross Stores Inc,ROST,0.10361,111.18,2.26,(2.07%), -202,Johnson Controls Internation,JCI,0.103601,53.69,-0.85,(-1.55%), -203,Iqvia Holdings Inc,IQV,0.103397,200.11,-2.1,(-1.04%), -204,Capital One Financial Corp,COF,0.101688,96.63,1.14,(1.20%), -205,Baker Hughes Co,BKR,0.101425,36.62,0.37,(1.02%), -206,Idexx Laboratories Inc,IDXX,0.101263,439.37,2.51,(0.57%), -207,Corteva Inc,CTVA,0.100577,50.77,0.02,(0.05%), -208,Dow Inc,DOW,0.100258,50.87,-0.13,(-0.26%), -209,Old Dominion Freight Line,ODFL,0.100037,406.82,6.93,(1.73%), -210,Constellation Energy,CEG,0.099445,109.94,-0.81,(-0.73%), -211,Dexcom Inc,DXCM,0.099384,95.68,3.59,(3.90%), -212,Simon Property Group Inc,SPG,0.098977,108.45,0.26,(0.24%), -213,Digital Realty Trust Inc,DLR,0.098757,117.6,0.76,(0.65%), -214,Realty Income Corp,O,0.098278,49.83,0.17,(0.33%), -215,Kenvue Inc W/i,KVUE,0.097359,20.2,-0.02,(-0.12%), -216,Verisk Analytics Inc,VRSK,0.097203,241.97,2.34,(0.98%), -217,Cognizant Tech Solutions A,CTSH,0.096172,68.15,-0.05,(-0.07%), -218,P G & E Corp,PCG,0.095995,16.36,-0.09,(-0.52%), -219,Prudential Financial Inc,PRU,0.095804,94.93,0.41,(0.43%), -220,Ametek Inc,AME,0.09567,150.03,1.17,(0.79%), -221,Yum Brands Inc,YUM,0.095443,123.55,1.57,(1.29%), -222,Dupont De Nemours Inc,DD,0.094185,74.58,1.11,(1.51%), -223,Ameriprise Financial Inc,AMP,0.093691,332.11,5.16,(1.58%), -224,L3harris Technologies Inc,LHX,0.092512,173.16,-2.04,(-1.16%), -225,Fidelity National Info Serv,FIS,0.09207,56.06,0.52,(0.94%), -226,Sysco Corp,SYY,0.091968,65.99,0.78,(1.20%), -227,Moderna Inc,MRNA,0.091789,100.61,1.17,(1.18%), -228,Bank of New York Mellon Corp,BK,0.091699,42.76,0.59,(1.39%), -229,Agilent Technologies Inc,A,0.091382,111.91,1.41,(1.28%), -230,Otis Worldwide Corp,OTIS,0.091228,80.55,1.2,(1.51%), -231,Rockwell Automation Inc,ROK,0.091103,288.26,3.46,(1.21%), -232,Dr Horton Inc,DHI,0.090974,108.96,1.95,(1.82%), -233,Cummins Inc,CMI,0.090916,232.98,3.03,(1.32%), -234,Estee Lauder Companies Cl A,EL,0.090788,139.94,-0.1,(-0.07%), -235,Kinder Morgan Inc,KMI,0.090175,16.71,0.05,(0.27%), -236,Keurig Dr Pepper Inc,KDP,0.088358,31.51,-0.16,(-0.51%), -237,Fastenal Co,FAST,0.087952,55.72,0.66,(1.21%), -238,Xcel Energy Inc,XEL,0.087474,56.5,-0.71,(-1.25%), -239,Devon Energy Corp,DVN,0.087359,48.84,0,(0.01%), -240,Ww Grainger Inc,GWW,0.086956,704.07,3.96,(0.57%), -241,Costar Group Inc,CSGP,0.086756,77.1,0.75,(0.99%), -242,Cencora Inc,COR,0.086188,183.99,-1.17,(-0.63%), -243,United Rentals Inc,URI,0.085093,454.44,8.22,(1.84%), -244,Hershey Co,HSY,0.084755,201.01,-1.55,(-0.76%), -245,Arch Capital Group Ltd,ACGL,0.083799,81.62,0.54,(0.67%), -246,Ppg Industries Inc,PPG,0.083787,130.49,2.46,(1.92%), -247,Global Payments Inc,GPN,0.083671,116.72,1.47,(1.28%), -248,Consolidated Edison Inc,ED,0.083432,85.06,-1.57,(-1.81%), -249,Newmont Corp,NEM,0.082799,36.78,-0.5,(-1.34%), -250,Republic Services Inc,RSG,0.082765,145.01,0.28,(0.19%), -251,Allstate Corp,ALL,0.08254,112.77,-0.25,(-0.22%), -252,Electronic Arts Inc,EA,0.081213,119.76,1.79,(1.51%), -253,Vici Properties Inc,VICI,0.081127,29.28,0.4,(1.37%), -254,Kroger Co,KR,0.080998,44.96,0.48,(1.07%), -255,Public Service Enterprise Gp,PEG,0.080723,56.88,-1.02,(-1.75%), -256,Lennar Corp A,LEN,0.078759,113.41,1.71,(1.53%), -257,Diamondback Energy Inc,FANG,0.078498,158.01,0.78,(0.50%), -258,West Pharmaceutical Services,WST,0.077362,377.15,1.97,(0.52%), -259,Quanta Services Inc,PWR,0.077074,190.82,0.7,(0.37%), -260,Gartner Inc,IT,0.076911,347.78,-1.41,(-0.40%), -261,Aptiv Plc,APTV,0.0757,99.21,3.35,(3.50%), -262,Vulcan Materials Co,VMC,0.075604,207.6,4,(1.97%), -263,Kraft Heinz Co,KHC,0.075468,33.72,-0.31,(-0.90%), -264,Ge Healthcare Technology,GEHC,0.074734,69.81,1.53,(2.24%), -265,Cdw Corp/de,CDW,0.074375,202.53,3.84,(1.93%), -266,Fortive Corp,FTV,0.072323,74.75,1.16,(1.58%), -267,Ingersoll Rand Inc,IR,0.071683,64.52,1.25,(1.97%), -268,Ansys Inc,ANSS,0.071343,299.19,4.85,(1.65%), -269,Extra Space Storage Inc,EXR,0.071269,120.75,0.24,(0.20%), -270,Wec Energy Group Inc,WEC,0.071007,79.67,-0.91,(-1.12%), -271,Martin Marietta Materials,MLM,0.070759,418,8.05,(1.96%), -272,Edison International,EIX,0.068887,63.92,-1.38,(-2.11%), -273,American Water Works Co Inc,AWK,0.068233,123.27,-3.07,(-2.43%), -274,Warner Bros Discovery Inc,WBD,0.068207,10.89,-0.15,(-1.31%), -275,Lyondellbasell Indu Cl A,LYB,0.067294,94.86,-0.11,(-0.11%), -276,Mettler Toledo International,MTD,0.067028,1,112.26,14.48,(1.32%) -277,Avalonbay Communities Inc,AVB,0.066762,171.85,-0.6,(-0.35%), -278,Delta Air Lines Inc,DAL,0.065781,37.32,0.66,(1.79%), -279,T Rowe Price Group Inc,TROW,0.064996,104.73,1.19,(1.15%), -280,Keysight Technologies In,KEYS,0.064934,133.51,3.11,(2.38%), -281,Zimmer Biomet Holdings Inc,ZBH,0.064476,112.14,1.38,(1.24%), -282,Dollar General Corp,DG,0.064042,105.04,0.7,(0.67%), -283,Corning Inc,GLW,0.064037,30.35,0.29,(0.98%), -284,Ebay Inc,EBAY,0.063728,43.45,0.56,(1.31%), -285,Cbre Group Inc A,CBRE,0.063578,73.84,0.35,(0.48%), -286,Weyerhaeuser Co,WY,0.063312,30.4,-0.64,(-2.05%), -287,Church & Dwight Co Inc,CHD,0.062765,91.68,-0.29,(-0.31%), -288,Cardinal Health Inc,CAH,0.062583,88.18,0.14,(0.16%), -289,Hp Inc,HPQ,0.062013,25.73,0.09,(0.36%), -290,Equifax Inc,EFX,0.061821,185.4,4.68,(2.59%), -291,Tractor Supply Company,TSCO,0.061683,205.07,2.06,(1.02%), -292,Willis Towers Watson Plc,WTW,0.06168,211.96,0.35,(0.17%), -293,Hewlett Packard Enterprise,HPE,0.061499,17.7,0.63,(3.66%), -294,Fair Isaac Corp,FICO,0.061481,890.19,4.58,(0.52%), -295,Dollar Tree Inc,DLTR,0.061287,106.46,1.11,(1.05%), -296,Hartford Financial Svcs Grp,HIG,0.061236,72.24,0.53,(0.73%), -297,Resmed Inc,RMD,0.060853,149.81,1.16,(0.78%), -298,Take Two Interactive Softwre,TTWO,0.060753,139.63,1.85,(1.34%), -299,Royal Caribbean Cruises Ltd,RCL,0.060515,94.38,2.42,(2.64%), -300,Xylem Inc,XYL,0.060192,91.4,1.09,(1.20%), -301,Align Technology Inc,ALGN,0.060095,309.06,7.38,(2.45%), -302,Steris Plc,STE,0.060013,221.57,3.67,(1.69%), -303,Broadridge Financial Solutio,BR,0.059572,181.18,-0.04,(-0.02%), -304,Discover Financial Services,DFS,0.059507,86.35,1.09,(1.28%), -305,State Street Corp,STT,0.059411,67.81,1.03,(1.54%), -306,Sba Communications Corp,SBAC,0.059216,198.11,2.05,(1.05%), -307,Monolithic Power Systems Inc,MPWR,0.058699,457.69,16.51,(3.74%), -308,Illumina Inc,ILMN,0.058584,133.02,-0.28,(-0.21%), -309,Dte Energy Company,DTE,0.058057,98.82,-1.72,(-1.71%), -310,M & T Bank Corp,MTB,0.057846,126.63,2.09,(1.68%), -311,Coterra Energy Inc,CTRA,0.057589,27.48,0.34,(1.23%), -312,Eversource Energy,ES,0.057281,57.54,-1.23,(-2.09%), -313,Genuine Parts Co,GPC,0.055796,142.94,0.63,(0.45%), -314,Equity Residential,EQR,0.055712,58.67,0.23,(0.40%), -315,Entergy Corp,ETR,0.055241,92.23,-1.02,(-1.10%), -316,Dover Corp,DOV,0.055103,141.68,1.09,(0.77%), -317,Ameren Corporation,AEE,0.054981,74.6,-1.51,(-1.98%), -318,Ulta Beauty Inc,ULTA,0.054585,398.17,5.73,(1.46%), -319,Teledyne Technologies Inc,TDY,0.054228,414.36,0.92,(0.22%), -320,Nvr Inc,NVR,0.054188,6,27.42,86.42,(1.45%) -321,Targa Resources Corp,TRGP,0.05408,87.52,0.93,(1.08%), -322,Molina Healthcare Inc,MOH,0.053618,333.09,2.03,(0.61%), -323,Wabtec Corp,WAB,0.053425,108.18,1.35,(1.26%), -324,Fleetcor Technologies Inc,FLT,0.053345,260.14,1.28,(0.49%), -325,Albemarle Corp,ALB,0.053229,172.99,10.36,(6.37%), -326,Baxter International Inc,BAX,0.05272,37.54,0.21,(0.57%), -327,Raymond James Financial Inc,RJF,0.052247,101.39,1.84,(1.85%), -328,Mccormick & Co Non Vtg Shrs,MKC,0.051871,74.55,0.46,(0.63%), -329,Invitation Homes Inc,INVH,0.051153,31.73,0.03,(0.11%), -330,Firstenergy Corp,FE,0.050777,34.56,-0.69,(-1.94%), -331,Laboratory Crp of Amer Hldgs,LH,0.05072,204.23,-0.62,(-0.30%), -332,Howmet Aerospace Inc,HWM,0.050386,46.99,0.91,(1.97%), -333,Verisign Inc,VRSN,0.050215,202.93,2.46,(1.23%), -334,Ppl Corp,PPL,0.04902,23.56,-0.39,(-1.61%), -335,Iron Mountain Inc,IRM,0.047985,59.55,0.56,(0.94%), -336,Jacobs Solutions Inc,J,0.047882,136.45,0.27,(0.20%), -337,Intl Flavors & Fragrances,IFF,0.047868,67.84,0.64,(0.95%), -338,Centerpoint Energy Inc,CNP,0.047827,26.68,-0.48,(-1.75%), -339,Darden Restaurants Inc,DRI,0.047736,143.44,2.01,(1.42%), -340,Hologic Inc,HOLX,0.047358,69.99,0.75,(1.08%), -341,First Solar Inc,FSLR,0.047324,161.9,3.29,(2.07%), -342,Expeditors Intl Wash Inc,EXPD,0.046936,114.74,1.08,(0.95%), -343,Brown & Brown Inc,BRO,0.046675,71.15,0.19,(0.26%), -344,Factset Research Systems Inc,FDS,0.046601,443.66,8.47,(1.95%), -345,Fifth Third Bancorp,FITB,0.046598,25.05,0.19,(0.74%), -346,Ventas Inc,VTR,0.046351,42.18,0.77,(1.85%), -347,Marathon Oil Corp,MRO,0.046321,27.51,0.12,(0.45%), -348,Steel Dynamics Inc,STLD,0.046096,106.96,0.52,(0.48%), -349,Bunge Ltd,BG,0.046038,110.67,1.1,(1.00%), -350,Ptc Inc,PTC,0.045951,140.25,1.78,(1.28%), -351,Everest Group Ltd,EG,0.04587,381.3,-0.42,(-0.11%), -352,Cincinnati Financial Corp,CINF,0.045852,104.4,-0.3,(-0.29%), -353,Enphase Energy Inc,ENPH,0.045679,121.39,1.28,(1.07%), -354,Nasdaq Inc,NDAQ,0.04562,49.07,0.74,(1.52%), -355,Akamai Technologies Inc,AKAM,0.045578,107.75,0.79,(0.74%), -356,Cboe Global Markets Inc,CBOE,0.045525,155.28,0.51,(0.33%), -357,Cf Industries Holdings Inc,CF,0.04496,84.93,1.48,(1.78%), -358,Waters Corp,WAT,0.044936,274.46,2.12,(0.78%), -359,Pultegroup Inc,PHM,0.044848,74.85,1.65,(2.25%), -360,Tyler Technologies Inc,TYL,0.044831,387.74,2.43,(0.63%), -361,Principal Financial Group,PFG,0.044705,72.74,0.74,(1.02%), -362,Clorox Company,CLX,0.04465,128.98,-0.17,(-0.13%), -363,Southwest Airlines Co,LUV,0.044478,27.3,0.49,(1.81%), -364,Regions Financial Corp,RF,0.044397,17.16,0.22,(1.27%), -365,Garmin Ltd,GRMN,0.044336,104.65,1.42,(1.38%), -366,Atmos Energy Corp,ATO,0.044128,106.32,-0.14,(-0.13%), -367,Netapp Inc,NTAP,0.044116,76.49,1.54,(2.05%), -368,Textron Inc,TXT,0.043659,79.27,0.33,(0.41%), -369,Cooper Cos Inc,COO,0.04361,318.15,2.23,(0.71%), -370,Kellogg Co,K,0.043517,58.9,-0.22,(-0.38%), -371,Idex Corp,IEX,0.043484,210.72,3.28,(1.58%), -372,Cms Energy Corp,CMS,0.043476,52.78,-0.57,(-1.07%), -373,Skyworks Solutions Inc,SWKS,0.042974,98.55,2.25,(2.33%), -374,Alexandria Real Estate Equit,ARE,0.042466,99.48,0.59,(0.60%), -375,Hunt (Jb) Transprt Svcs Inc,JBHT,0.042319,186.54,0.95,(0.51%), -376,Las Vegas Sands Corp,LVS,0.042222,45.63,-0.53,(-1.15%), -377,Ball Corp,BALL,0.042202,48.27,0.04,(0.08%), -378,Walgreens Boots Alliance Inc,WBA,0.04215,20.97,-0.06,(-0.26%), -379,Teradyne Inc,TER,0.041494,100.04,3.56,(3.68%), -380,Mid America Apartment Comm,MAA,0.041385,128.55,0.48,(0.37%), -381,Epam Systems Inc,EPAM,0.041006,257.76,0.96,(0.37%), -382,Avery Dennison Corp,AVY,0.040961,183.42,1.39,(0.76%), -383,Omnicom Group,OMC,0.040483,74.6,1.21,(1.65%), -384,Huntington Bancshares Inc,HBAN,0.040444,10.25,0.13,(1.24%), -385,Eqt Corp,EQT,0.040251,40,0.39,(0.99%), -386,Tyson Foods Inc Cl A,TSN,0.040042,49.74,-0.37,(-0.74%), -387,Western Digital Corp,WDC,0.039814,45.5,0.94,(2.11%), -388,Northern Trust Corp,NTRS,0.039557,69.29,0.84,(1.23%), -389,Carnival Corp,CCL,0.039206,14.52,0.54,(3.88%), -390,Expedia Group Inc,EXPE,0.038585,102.75,2.5,(2.49%), -391,United Airlines Holdings Inc,UAL,0.038383,42.84,0.81,(1.94%), -392,Quest Diagnostics Inc,DGX,0.038331,123.71,0.31,(0.25%), -393,Axon Enterprise Inc,AXON,0.03828,195.69,1.04,(0.53%), -394,Packaging Corp of America,PKG,0.038236,152.79,0.9,(0.59%), -395,Revvity Inc,RVTY,0.0378,110.55,1.5,(1.38%), -396,Snap on Inc,SNA,0.037774,257.97,4,(1.58%), -397,Pool Corp,POOL,0.037475,353.56,9.86,(2.87%), -398,Essex Property Trust Inc,ESS,0.03733,210.81,0.07,(0.03%), -399,Domino S Pizza Inc,DPZ,0.037258,382.39,2.18,(0.57%), -400,Amcor Plc,AMCR,0.037101,9.09,0.06,(0.61%), -401,Best Buy Co Inc,BBY,0.037071,68.66,0.29,(0.43%), -402,Apa Corp,APA,0.03662,42.49,0.11,(0.27%), -403,Lamb Weston Holdings Inc,LW,0.036553,91.47,0.09,(0.10%), -404,Wr Berkley Corp,WRB,0.036551,65.21,0.86,(1.33%), -405,Conagra Brands Inc,CAG,0.036484,27.44,-0.1,(-0.35%), -406,Lkq Corp,LKQ,0.036449,49.51,0.72,(1.47%), -407,Jm Smucker Co,SJM,0.035767,124.48,-0.96,(-0.77%), -408,Stanley Black & Decker Inc,SWK,0.035567,83.87,0.97,(1.17%), -409,Synchrony Financial,SYF,0.035241,30.73,0.55,(1.84%), -410,Carmax Inc,KMX,0.035202,71.64,-8.05,(-10.10%), -411,Leidos Holdings Inc,LDOS,0.034943,92.2,0.21,(0.23%), -412,Seagate Technology Holdings,STX,0.034918,65.71,1.42,(2.20%), -413,Paycom Software Inc,PAYC,0.034914,259.42,2.34,(0.91%), -414,Celanese Corp,CE,0.034212,127.11,3.81,(3.09%), -415,Trimble Inc,TRMB,0.034136,52.22,3.01,(6.12%), -416,Alliant Energy Corp,LNT,0.03411,48.06,-0.49,(-1.02%), -417,Citizens Financial Group,CFG,0.033972,26.28,0.52,(2.00%), -418,International Paper Co,IP,0.033961,35.1,0.15,(0.41%), -419,Masco Corp,MAS,0.033414,54.58,1.37,(2.58%), -420,Nordson Corp,NDSN,0.033057,223.81,3.73,(1.69%), -421,Loews Corp,L,0.032942,64.16,0.36,(0.56%), -422,Evergy Inc,EVRG,0.032792,50.48,-0.58,(-1.13%), -423,Mosaic Co,MOS,0.03266,35.63,0.43,(1.22%), -424,Molson Coors Beverage Co B,TAP,0.032624,62.29,-0.12,(-0.19%), -425,Zebra Technologies Corp Cl A,ZBRA,0.03257,236.95,11.04,(4.89%), -426,Viatris Inc,VTRS,0.032115,9.8,0.21,(2.14%), -427,Live Nation Entertainment In,LYV,0.032035,83.73,2.71,(3.34%), -428,Host Hotels & Resorts Inc,HST,0.03173,16.38,0.34,(2.11%), -429,Insulet Corp,PODD,0.031493,166.19,4.49,(2.77%), -430,Match Group Inc,MTCH,0.031269,40.07,0.09,(0.23%), -431,Interpublic Group of Cos Inc,IPG,0.031184,29.12,0.39,(1.35%), -432,Hormel Foods Corp,HRL,0.030887,38.15,-0.19,(-0.48%), -433,Incyte Corp,INCY,0.03067,58.93,-0.18,(-0.30%), -434,Udr Inc,UDR,0.030252,35.67,0.28,(0.79%), -435,Jack Henry & Associates Inc,JKHY,0.030211,150.61,2.17,(1.46%), -436,Kimco Realty Corp,KIM,0.029862,17.73,0.24,(1.34%), -437,Aes Corp,AES,0.029775,15.29,-0.65,(-4.05%), -438,Bio Techne Corp,TECH,0.029742,67.67,0.1,(0.15%), -439,Pentair Plc,PNR,0.029592,65.59,0.87,(1.34%), -440,Rollins Inc,ROL,0.029276,37.64,0.2,(0.52%), -441,Mgm Resorts International,MGM,0.028601,36.76,0.27,(0.74%), -442,Ceridian Hcm Holding Inc,CDAY,0.028589,67.38,0.35,(0.52%), -443,Brown Forman Corp Class B,BF.B,0.028542,56.78,0.14,(0.25%), -444,Nisource Inc,NI,0.028365,24.84,-0.35,(-1.37%), -445,Gen Digital Inc,GEN,0.028124,17.83,-0.07,(-0.37%), -446,C.H. Robinson Worldwide Inc,CHRW,0.028048,86.31,0.02,(0.02%), -447,Camden Property Trust,CPT,0.027984,94.56,-0.32,(-0.34%), -448,Charles River Laboratories,CRL,0.027736,195.69,0.75,(0.38%), -449,Healthpeak Properties Inc,PEAK,0.027617,18.15,0.1,(0.58%), -450,Caesars Entertainment Inc,CZR,0.027217,47.52,1.54,(3.36%), -451,Regency Centers Corp,REG,0.027131,59.98,0.85,(1.43%), -452,Keycorp,KEY,0.0269,10.52,0.22,(2.09%), -453,Henry Schein Inc,HSIC,0.026715,73.88,0.62,(0.84%), -454,Globe Life Inc,GL,0.026574,110.04,0.61,(0.56%), -455,Borgwarner Inc,BWA,0.026416,40.72,0.92,(2.31%), -456,F5 Inc,FFIV,0.026087,160.33,2.74,(1.74%), -457,Qorvo Inc,QRVO,0.025849,96.39,1.83,(1.93%), -458,Teleflex Inc,TFX,0.025796,199.42,2.91,(1.48%), -459,Allegion Plc,ALLE,0.025545,104.97,1.68,(1.63%), -460,Westrock Co,WRK,0.025292,35.98,0.23,(0.64%), -461,Eastman Chemical Co,EMN,0.025003,76.99,2.35,(3.15%), -462,Wynn Resorts Ltd,WYNN,0.024938,92.21,0,(-0.00%), -463,Nrg Energy Inc,NRG,0.024681,38.55,-0.03,(-0.08%), -464,Juniper Networks Inc,JNPR,0.024655,27.92,0.42,(1.52%), -465,Pinnacle West Capital,PNW,0.02321,73.45,-0.71,(-0.95%), -466,Hasbro Inc,HAS,0.02308,65.23,0.24,(0.37%), -467,Catalent Inc,CTLT,0.023069,45.85,0.07,(0.15%), -468,American Airlines Group Inc,AAL,0.02296,13,0.39,(3.05%), -469,Fmc Corp,FMC,0.022942,66.03,0.02,(0.03%), -470,Campbell Soup Co,CPB,0.022776,41.15,-0.31,(-0.76%), -471,Smith (a.O.) Corp,AOS,0.022769,66.99,1.54,(2.35%), -472,Boston Properties Inc,BXP,0.02269,59.66,0.79,(1.34%), -473,Huntington Ingalls Industrie,HII,0.022502,204.41,1.22,(0.60%), -474,Fox Corp Class A,FOXA,0.021902,31.47,0.55,(1.76%), -475,Robert Half Inc,RHI,0.021872,73.78,0.64,(0.87%), -476,Assurant Inc,AIZ,0.021618,145.63,-0.13,(-0.09%), -477,Universal Health Services B,UHS,0.021551,127,2.8,(2.25%), -478,Etsy Inc,ETSY,0.021257,63.53,1.64,(2.65%), -479,Marketaxess Holdings Inc,MKTX,0.021132,205.89,4.11,(2.04%), -480,News Corp Class A,NWSA,0.0209,20,0.35,(1.76%), -481,Bio Rad Laboratories A,BIO,0.020548,356.1,3.63,(1.03%), -482,Bath & Body Works Inc,BBWI,0.020412,33.19,1.04,(3.23%), -483,Dentsply Sirona Inc,XRAY,0.020079,33.94,-0.17,(-0.51%), -484,Solaredge Technologies Inc,SEDG,0.020026,132.35,4.34,(3.39%), -485,Whirlpool Corp,WHR,0.019812,131.66,1.03,(0.79%), -486,Franklin Resources Inc,BEN,0.019128,24.55,0.28,(1.14%), -487,Generac Holdings Inc,GNRC,0.018958,110.73,1.84,(1.69%), -488,Norwegian Cruise Line Holdin,NCLH,0.018812,16.96,0.67,(4.08%), -489,Federal Realty Invs Trust,FRT,0.018475,91.45,1.05,(1.16%), -490,Tapestry Inc,TPR,0.01809,28.18,0.23,(0.84%), -491,Invesco Ltd,IVZ,0.017835,14.31,0.22,(1.53%), -492,Paramount Global Class B,PARA,0.017208,12.89,0.11,(0.89%), -493,Vf Corp,VFC,0.015631,16.59,-0.32,(-1.89%), -494,Comerica Inc,CMA,0.014638,41.07,1.12,(2.81%), -495,Davita Inc,DVA,0.014395,95.75,0.01,(0.01%), -496,Zions Bancorp Na,ZION,0.013918,33.96,0.79,(2.39%), -497,Ralph Lauren Corp,RL,0.013127,115.52,0.26,(0.22%), -498,Sealed Air Corp,SEE,0.012794,32.2,0.46,(1.46%), -499,Alaska Air Group Inc,ALK,0.012574,37.04,0.63,(1.73%), -500,Mohawk Industries Inc,MHK,0.011998,85.15,1.23,(1.46%), -501,Organon & Co,OGN,0.011665,16.93,0.34,(2.02%), -502,Dxc Technology Co,DXC,0.011658,20.64,0.29,(1.40%), -503,Fox Corp Class B,FOX,0.010545,29.16,0.53,(1.85%), -504,News Corp Class B,NWS,0.006575,20.75,0.36,(1.74%), diff --git a/vuu/src/main/resources/static/ftse100.csv b/vuu/src/main/resources/static/ftse100.csv deleted file mode 100644 index aa0315f95..000000000 --- a/vuu/src/main/resources/static/ftse100.csv +++ /dev/null @@ -1,100 +0,0 @@ -Symbol,Name,Last Trade,Change,Volume, Weighting -AAL.L,Anglo American PLC,436.35�13:13,�5.35�(1.24%),5799089,0.0278736825813547 -ABF.L,Associated British Foods PLC,"3,435.60�13:12",�7.40�(0.21%),86808,0.000417248060431947 -ADM.L,Admiral Group PLC,"1,627.00�13:13",,86808,0.000417248060431947 -ADN.L,Aberdeen Asset Management PLC,334.00�13:13,�2.50�(0.75%),806880,0.00387831899135251 -AHT.L,Ashtead Group PLC,"1,027.00�13:13",�6.00�(0.59%),331255,0.00159219779580666 -ANTO.L,Antofagasta PLC,484.10�13:13,�11.70�(2.48%),1753976,0.00843059492263598 -ARM.L,ARM Holdings PLC,"1,058.00�13:13",�3.00�(0.28%),475927,0.00228757277736148 -AV.L,Aviva PLC,493.97�13:13,�2.23�(0.45%),2226835,0.0107034211668507 -AZN.L,AstraZeneca PLC,"4,399.50�13:13",�2.50�(0.06%),815133,0.00391798755004232 -BA.L,BAE Systems PLC,478.10�13:13,�4.30�(0.91%),2039934,0.00980506986578636 -BAB.L,Babcock International Group PLC,988.00�13:13,�9.50�(0.97%),209614,0.00100752275066102 -BARC.L,Barclays PLC,226.30�13:13,�1.15�(0.51%),6575664,0.0316063387021032 -BATS.L,British American Tobacco PLC,"3,803.50�13:13",�8.50�(0.22%),465110,0.0022355801929258 -BDEV.L,Barratt Developments PLC,576.00�13:13,�0.50�(0.09%),1044365,0.00501980543997108 -BG.L,BG Group PLC,"1,013.50�13:13",�5.50�(0.55%),1507332,0.00724508516988073 -BKG.L,Berkeley Group Holdings (The) PLC,"3,126.00�13:13",�15.00�(0.48%),95071,0.000456964684744788 -BLND.L,British Land Co PLC,828.06�13:12,�10.44�(1.25%),1802548,0.00866405926683583 -BLT.L,BHP Billiton PLC,881.40�13:13,�4.30�(0.49%),4947287,0.0237794431982097 -BNZL.L,Bunzl PLC,"1,875.40�13:05",�4.60�(0.24%),104541,0.000502482829757812 -BP.L,BP PLC,381.50�13:13,�2.95�(0.78%),10493561,0.0504379547308349 -BRBY.L,Burberry Group PLC,"1,269.00�13:13",�7.00�(0.55%),295647,0.00142104572530785 -BT-A.L,BT Group PLC,489.20�13:13,�3.70�(0.75%),3914982,0.0188176048996174 -CCL.L,Carnival PLC,"3,426.00�13:12",�22.00�(0.64%),86257,0.000414599644602783 -CNA.L,Centrica PLC,212.80�13:13,�0.60�(0.28%),2144540,0.0103078651220939 -CPG.L,Compass Group PLC,"1,054.00�13:08",�5.00�(0.48%),1001167,0.00481217156158961 -CPI.L,Capita PLC,"1,235.00�13:11",�1.00�(0.08%),244591,0.0011756418803464 -CRH.L,CRH PLC,"1,783.20�13:12",�17.80�(0.99%),897325,0.00431304851888186 -DC.L,DIXONS CARPHONE,462.10�13:11,,756906,0.00363811584680332 -DGE.L,Diageo PLC,"1,881.50�13:13",�6.50�(0.34%),756906,0.00363811584680332 -DLG.L,Direct Line Insurance Group PLC,403.80�13:13,�0.40�(0.10%),1095340,0.00526481995338596 -EXPN.L,Experian PLC,"1,191.00�13:12",�2.00�(0.17%),467283,0.00224602485281105 -EZJ.L,easyJet PLC,"1,682.00�13:12",�28.00�(1.64%),1191230,0.00572572121265722 -FRES.L,Fresnillo PLC,678.50�13:12,�6.50�(0.97%),381871,0.00183548675335462 -GFS.L,G4S PLC,232.30�13:03,�2.00�(0.85%),1096551,0.00527064070033535 -GKN.L,GKN PLC,294.80�13:12,�2.50�(0.86%),792247,0.00380798456516713 -GLEN.L,Glencore PLC,90.48�13:13,�1.65�(1.86%),41631528,0.200104533116974 -GSK.L,GlaxoSmithKline PLC,"1,345.00�13:13",�0.50�(0.04%),1767356,0.00849490672625522 -HIK.L,Hikma Pharmaceuticals PLC,"2,010.00�13:04",�57.00�(2.92%),261511,0.00125696891451962 -HL.L,Hargreaves Lansdown PLC,"1,488.03�13:12",�9.97�(0.67%),372261,0.00178929568961912 -HMSO.L,Hammerson PLC,597.50�13:11,�3.50�(0.58%),478301,0.0022989835562697 -HSBA.L,HSBC Holdings PLC,519.70�13:13,�0.50�(0.10%),7415629,0.0356436828072631 -IAG.L,International Consolidated Airlines Group SA,575.40�13:12,�16.10�(2.72%),4311514,0.0207235606629018 -IHG.L,InterContinental Hotels Group PLC,"2,481.00�13:12",�19.00�(0.76%),219918,0.00105704956863507 -III.L,3i Group PLC,487.30�13:11,�4.50�(0.92%),189987,0.000913184352332553 -IMT.L,Imperial Tobacco Group PLC,"3,571.00�13:13",�29.00�(0.81%),926816,0.00445479884777089 -INTU.L,intu properties plc,319.90�13:09,�4.60�(1.42%),514821,0.0024745192115892 -ISAT.L,Inmarsat PLC,"1,054.44�13:13",�3.44�(0.33%),988089,0.00474931133978598 -ITRK.L,Intertek Group PLC,"2,643.00�13:14",�3.00�(0.11%),45868,0.000220467399731505 -ITV.L,ITV PLC,267.30�13:14,�2.60�(0.96%),3453208,0.0165980593985356 -JMAT.L,Johnson Matthey PLC,"2,445.00�13:14",�29.00�(1.20%),276397,0.00132851940096775 -KGF.L,Kingfisher PLC,346.20�13:14,�4.30�(1.23%),1021408,0.00490946118917235 -LAND.L,Land Securities Group PLC,"1,239.00�13:13",�7.00�(0.56%),384973,0.00185039670961971 -LGEN.L,Legal & General Group PLC,266.00�13:14,�1.60�(0.60%),1998399,0.00960542930051541 -LLOY.L,Lloyds Banking Group PLC,73.86�13:14,�0.02�(0.03%),18907878,0.0908818936317375 -LSE.L,London Stock Exchange Group PLC,"2,544.00�13:11",�6.00�(0.24%),129657,0.000623204448569543 -MGGT.L,Meggitt PLC,386.00�13:15,�3.20�(0.84%),611044,0.00293702105610748 -MKS.L,Marks & Spencer Group PLC,514.75�13:12,�3.25�(0.63%),920128,0.00442265255908587 -MNDI.L,Mondi PLC,"1,463.00�13:14",�7.00�(0.48%),383546,0.00184353774521278 -MRW.L,Morrison (Wm) Supermarkets PLC,155.20�13:14,,920128,0.00442265255908587 -NG.L,National Grid PLC,926.40�13:14,�1.10�(0.12%),1659592,0.00797693234619361 -NXT.L,Next PLC,"7,765.00�13:11",�95.00�(1.21%),114062,0.000548246109448308 -OML.L,Old Mutual PLC,198.50�13:14,�0.40�(0.20%),2040849,0.00980946787029396 -PRU.L,Prudential PLC,"1,499.50�13:15",�14.00�(0.93%),580870,0.00279198784516525 -PSON.L,Pearson PLC,794.00�13:09,�5.00�(0.63%),1177953,0.00566190448495522 -RB.L,Reckitt Benckiser Group PLC,"6,293.00�13:14",�34.00�(0.54%),281172,0.0013514707359664 -RBS.L,Royal Bank of Scotland Group PLC,313.40�13:14,�2.40�(0.77%),2100058,0.0100940596177149 -RDSA.L,Royal Dutch Shell PLC,"1,636.00�13:14",�18.00�(1.11%),2467461,0.0118600050276642 -RDSB.L,Royal Dutch Shell PLC,"1,652.00�13:15",�14.50�(0.89%),1457434,0.0070052473240666 -REL.L,Reed Elsevier PLC,"1,170.00�13:14",0.00�(0.00%),908802,0.00436821343443777 -RIO.L,Rio Tinto PLC,"2,235.00�13:15",�21.00�(0.95%),2190722,0.0105298417823887 -RMG.L,Royal Mail PLC,453.50�13:14,�1.20�(0.26%),995316,0.00478404836555252 -RR.L,Rolls-Royce Group PLC,546.63�13:14,�8.38�(1.51%),2792915,0.0134243199555489 -RRS.L,Randgold Resources Ltd,"3,929.00�13:14",0.00�(0.00%),135524,0.000651404549603483 -RSA.L,RSA Insurance Group PLC,437.10�13:14,�0.10�(0.02%),395477,0.00190088484005443 -SAB.L,SABMiller PLC,"4,011.00�13:15",�1.00�(0.02%),892451,0.00428962133421518 -SBRY.L,Sainsbury (J) PLC,255.80�13:14,�7.40�(2.98%),2395670,0.0115149371133421 -SDR.L,Schroders PLC,"2,930.00�13:09",�12.00�(0.41%),44674,0.000214728364341268 -SGE.L,Sage Group (The) PLC,545.50�13:13,�0.50�(0.09%),539717,0.00259418338669419 -SHP.L,Shire PLC,"4,685.00�13:14",�22.00�(0.47%),221318,0.0010637787558598 -SKY.L,SKY,"1,095.00�13:12",�4.00�(0.37%),925016,0.0044461470356248 -SL.L,Standard Life PLC,399.90�13:14,�3.20�(0.79%),861636,0.00414150711683647 -SMIN.L,Smiths Group PLC,992.50�13:14,�27.50�(2.70%),640309,0.00307768510191594 -SN.L,Smith & Nephew PLC,"1,110.00�13:14",�9.00�(0.82%),480018,0.00230723642374461 -SPD.L,Sports Direct International PLC,694.50�13:11,�1.50�(0.22%),157981,0.000759345519250522 -SSE.L,SSE PLC,"1,463.00�13:13",�2.00�(0.14%),562454,0.00270347019378617 -STAN.L,Standard Chartered PLC,583.00�13:14,�0.60�(0.10%),2018697,0.00970299290214945 -STJ.L,St James's Place PLC,964.00�13:14,�11.00�(1.13%),418480,0.00201145019271912 -SVT.L,Severn Trent PLC,"2,199.00�13:12",�1.00�(0.05%),95342,0.000458267263129005 -TPK.L,Travis Perkins PLC,"1,945.00�13:13",�4.00�(0.21%),92916,0.000446606542981001 -TSCO.L,Tesco PLC,171.54�13:14,�2.54�(1.50%),9831136,0.0472539676970174 -TUI.L,TUI AG,"1,115.00�13:10",�5.00�(0.45%),458970,0.00220606790038304 -TW.L,Taylor Wimpey PLC,183.90�13:15,�1.10�(0.59%),3180729,0.0152883721086725 -ULVR.L,Unilever PLC,"2,791.00�13:14",�29.00�(1.03%),824827,0.0039645823650113 -UU.L,United Utilities Group PLC,959.00�13:10,�2.50�(0.26%),436911,0.00210003994253274 -VOD.L,Vodafone Group PLC,224.25�13:15,�1.30�(0.58%),17572036,0.0844610858312637 -WOS.L,Wolseley PLC,"3,657.00�13:14",�4.00�(0.11%),179536,0.000862950969699912 -WPP.L,WPP PLC,"1,502.00�13:15",�12.00�(0.79%),857887,0.0041234873147611 -WTB.L,Whitbread PLC,"4,484.00�13:16",�60.00�(1.32%),141036,0.000677898321019722 -,,,,208048900, diff --git a/vuu/src/main/resources/static/hsi.csv b/vuu/src/main/resources/static/hsi.csv deleted file mode 100644 index fcd24d46c..000000000 --- a/vuu/src/main/resources/static/hsi.csv +++ /dev/null @@ -1,81 +0,0 @@ -Name,Symbol,Last,Change,Change %,Volume,Turn.,P/E,P/B,Yield,Market Cap,Weighting -CKH HOLDINGS,00001.HK,41.9,1.15,+2.822%,5.15M,215.13M,4.38,0.31,6.98%,160.48B,0.0278736825813547 -CLP HOLDINGS,00002.HK,57.95,-0.1,-0.172%,3.32M,193.19M,156.62,1.39,5.35%,146.41B,0.000417248060431947 -HK & CHINA GAS,00003.HK,5.46,0.13,+2.439%,16.16M,88.00M,19.43,1.66,6.41%,101.88B,0.000417248060431947 -HSBC HOLDINGS,00005.HK,61.7,1.1,+1.815%,22.19M,1.37B,10.54,0.86,4.05%,1,0.00387831899135251 -POWER ASSETS,00006.HK,37.9,-0.25,-0.655%,4.23M,160.75M,14.3,0.93,7.44%,80.77B,0.00159219779580666 -HANG SENG BANK,00011.HK,97.45,2.95,+3.122%,2.54M,247.44M,19.69,1.01,4.21%,186.31B,0.00843059492263598 -HENDERSON LAND,00012.HK,20.65,0.85,+4.293%,5.07M,103.70M,10.81,0.31,8.72%,99.97B,0.00228757277736148 -SHK PPT,00016.HK,83.8,3.25,+4.035%,8.25M,685.41M,10.16,0.4,5.91%,242.83B,0.0107034211668507 -NEW WORLD DEV,00017.HK,15.24,0.8,+5.540%,12.95M,196.19M,30.48,0.18,13.52%,38.35B,0.00391798755004232 -GALAXY ENT,00027.HK,47.15,1.9,+4.199%,11.97M,560.21M,No Profit,3.22,0.00%,206.21B,0.00980506986578636 -MTR CORPORATION,00066.HK,31,0.8,+2.649%,4.68M,144.86M,19.5,1.07,4.23%,192.64B,0.00100752275066102 -HANG LUNG PPT,00101.HK,10.72,0.56,+5.512%,7.68M,81.99M,12.61,0.36,7.28%,48.23B,0.0316063387021032 -GEELY AUTO,00175.HK,9.24,0.17,+1.874%,18.77M,173.30M,16.06,1.15,2.27%,92.99B,0.0022355801929258 -ALI HEALTH,00241.HK,4.88,0.47,+10.658%,53.62M,257.82M,108.09,3.81,0.00%,66.04B,0.00501980543997108 -CITIC,00267.HK,7.2,0.2,+2.857%,11.54M,82.96M,2.78,0.28,9.04%,209.45B,0.00724508516988073 -WH GROUP,00288.HK,4.11,0.08,+1.985%,18.94M,77.65M,4.93,0.7,7.30%,52.73B,0.000456964684744788 -CHINA RES BEER,00291.HK,42.95,1.2,+2.874%,4.83M,207.98M,28.41,4.57,1.41%,139.34B,0.00866405926683583 -OOIL,00316.HK,104.5,-0.4,-0.381%,296.54K,30.98M,0.89,0.66,78.90%,69.01B,0.0237794431982097 -TINGYI,00322.HK,10.94,0.18,+1.673%,2.91M,31.81M,20.75,4.09,9.39%,61.64B,0.000502482829757812 -SINOPEC CORP,00386.HK,4.28,-0.01,-0.233%,92.43M,396.61M,6.94,0.58,9.36%,105.92B,0.0504379547308349 -HKEX,00388.HK,292.6,9,+3.173%,4.61M,1.34B,36.76,7.46,2.44%,370.97B,0.00142104572530785 -TECHTRONIC IND,00669.HK,76,1.35,+1.808%,5.47M,414.78M,16.54,3.43,2.43%,139.45B,0.0188176048996174 -CHINA OVERSEAS,00688.HK,16.24,0.52,+3.308%,13.15M,212.60M,6.76,0.44,4.93%,177.74B,0.000414599644602783 -TENCENT,00700.HK,306.2,8.8,+2.959%,11.25M,3.43B,13.74,3.6,0.78%,2,0.0103078651220939 -CHINA UNICOM,00762.HK,5.68,-0.05,-0.873%,9.23M,52.77M,9.16,0.45,5.44%,173.80B,0.00481217156158961 -LINK REIT,00823.HK,38.4,1.45,+3.924%,12.04M,460.96M,5.42,0.52,7.03%,98.38B,0.0011756418803464 -CHINA RES POWER,00836.HK,14.94,0.32,+2.189%,9.91M,147.81M,10.23,0.87,3.92%,71.87B,0.00431304851888186 -PETROCHINA,00857.HK,5.9,0,0.000%,64.23M,380.44M,6.38,0.7,8.08%,124.48B,0.00363811584680332 -XINYI GLASS,00868.HK,10.14,0.17,+1.705%,3.75M,38.02M,8.01,1.3,6.11%,42.22B,0.00363811584680332 -ZHONGSHENG HLDG,00881.HK,22.05,1.45,+7.039%,6.76M,147.71M,7.08,1.07,4.94%,52.72B,0.00526481995338596 -CNOOC,00883.HK,13.78,-0.02,-0.145%,26.37M,365.08M,4.03,0.97,19.09%,655.47B,0.00224602485281105 -CCB,00939.HK,4.42,0.06,+1.376%,233.61M,1.03B,3.06,0.35,9.93%,1,0.00572572121265722 -CHINA MOBILE,00941.HK,65.7,0.25,+0.382%,7.82M,516.10M,9.91,0.96,6.71%,1,0.00183548675335462 -LONGFOR GROUP,00960.HK,14.08,0.9,+6.829%,10.88M,150.68M,3.06,0.55,9.05%,92.81B,0.00527064070033535 -XINYI SOLAR,00968.HK,5.86,0.28,+5.018%,15.99M,92.88M,13.64,1.75,3.41%,52.17B,0.00380798456516713 -SMIC,00981.HK,20.05,0.25,+1.263%,13.10M,264.32M,11.17,1.06,0.00%,159.31B,0.200104533116974 -LENOVO GROUP,00992.HK,8.07,0.25,+3.197%,33.60M,270.50M,7.61,2.23,4.71%,97.87B,0.00849490672625522 -CKI HOLDINGS,01038.HK,37.05,-0.2,-0.537%,1.44M,53.73M,12.03,0.78,6.83%,93.35B,0.00125696891451962 -HENGAN INT'L,01044.HK,24.95,0.2,+0.808%,2.62M,64.97M,13.35,1.32,6.33%,28.99B,0.00178929568961912 -CHINA SHENHUA,01088.HK,25.4,0.35,+1.397%,7.98M,203.11M,6.14,1.13,11.33%,85.79B,0.0022989835562697 -CSPC PHARMA,01093.HK,5.74,0.05,+0.879%,29.29M,167.41M,9.96,2.01,3.66%,68.32B,0.0356436828072631 -SINOPHARM,01099.HK,22.7,0.2,+0.889%,2.07M,46.80M,7.37,0.92,4.08%,30.46B,0.0207235606629018 -CHINA RES LAND,01109.HK,31.2,1,+3.311%,9.88M,305.88M,7.02,0.81,5.07%,222.49B,0.00105704956863507 -CK ASSET,01113.HK,41.25,1.25,+3.125%,8.57M,352.44M,6.9,0.39,5.53%,146.47B,0.000913184352332553 -SINO BIOPHARM,01177.HK,2.83,0.02,+0.712%,26.30M,74.09M,18.37,1.59,4.24%,53.21B,0.00445479884777089 -CHINA RES MIXC,01209.HK,31.6,1.6,+5.333%,3.07M,96.42M,28.97,4.48,2.87%,72.13B,0.0024745192115892 -BYD COMPANY,01211.HK,242,7,+2.979%,3.90M,938.50M,37.57,5.63,0.53%,265.72B,0.00474931133978598 -AIA,01299.HK,63.85,0.95,+1.510%,38.75M,2.48B,408.88,2.53,2.41%,735.40B,0.000220467399731505 -CHINAHONGQIAO,01378.HK,7.67,0.28,+3.789%,13.05M,99.58M,7.27,0.76,6.65%,72.68B,0.0165980593985356 -ICBC,01398.HK,3.77,0.07,+1.892%,233.48M,881.67M,3.45,0.36,9.08%,327.21B,0.00132851940096775 -XIAOMI-W,01810.HK,12.34,0.62,+5.290%,78.53M,960.98M,109.39,1.9,0.00%,308.83B,0.00490946118917235 -BUD APAC,01876.HK,15.46,0.16,+1.046%,16.17M,250.45M,28.65,2.44,1.91%,204.74B,0.00185039670961971 -SANDS CHINA LTD,01928.HK,24,0.95,+4.121%,19.98M,475.93M,No Profit,N/A,0.00%,194.24B,0.00960542930051541 -CHOW TAI FOOK,01929.HK,11.8,0.28,+2.431%,4.88M,57.68M,21.93,3.64,10.34%,118.00B,0.0908818936317375 -WHARF REIC,01997.HK,30.25,1.4,+4.853%,4.23M,127.31M,No Profit,0.48,4.33%,91.85B,0.000623204448569543 -ANTA SPORTS,02020.HK,88.15,4.4,+5.254%,4.82M,422.51M,27.71,6.16,1.52%,249.70B,0.00293702105610748 -WUXI BIO,02269.HK,45.65,1.55,+3.515%,17.91M,811.49M,38.18,4.88,0.00%,194.01B,0.00442265255908587 -SHENZHOU INTL,02313.HK,75,4.6,+6.534%,5.52M,410.68M,21.87,3.25,2.55%,112.74B,0.00184353774521278 -PING AN,02318.HK,44.85,0.85,+1.932%,23.05M,1.03B,8.28,0.85,6.09%,334.02B,0.00442265255908587 -MENGNIU DAIRY,02319.HK,26.25,1.5,+6.061%,8.58M,223.15M,17.34,2.3,1.73%,103.42B,0.00797693234619361 -LI NING,02331.HK,32.95,1.5,+4.769%,22.54M,738.37M,18.8,3.16,1.58%,86.86B,0.000548246109448308 -SUNNY OPTICAL,02382.HK,54.7,1.05,+1.957%,5.62M,308.60M,22.01,2.44,0.91%,60.00B,0.00980946787029396 -BOC HONG KONG,02388.HK,21.45,0.3,+1.418%,6.53M,140.32M,8.38,0.75,6.33%,226.79B,0.00279198784516525 -CHINA LIFE,02628.HK,12.2,0.24,+2.007%,13.53M,165.07M,9.49,0.7,4.53%,90.78B,0.00566190448495522 -ENN ENERGY,02688.HK,65,1.15,+1.801%,3.06M,198.69M,11.08,1.67,4.48%,73.53B,0.0013514707359664 -ZIJIN MINING,02899.HK,11.98,0.16,+1.354%,16.20M,194.50M,13.97,3.14,1.88%,68.73B,0.0100940596177149 -MEITUAN-W,03690.HK,114.6,3.8,+3.430%,19.17M,2.19B,No Profit,4.89,0.00%,715.43B,0.0118600050276642 -HANSOH PHARMA,03692.HK,10.66,0.16,+1.524%,17.56M,187.72M,21.48,2.47,0.94%,63.25B,0.0070052473240666 -CM BANK,03968.HK,32.7,0.1,+0.307%,11.13M,363.99M,5.51,0.86,6.00%,150.12B,0.00436821343443777 -BANK OF CHINA,03988.HK,2.74,0.05,+1.859%,275.47M,754.54M,3.33,0.33,9.55%,229.13B,0.0105298417823887 -CG SERVICES,06098.HK,8.08,0.25,+3.193%,16.08M,128.87M,12.42,0.65,5.20%,27.01B,0.00478404836555252 -JD HEALTH,06618.HK,40.6,2.95,+7.835%,7.75M,312.36M,299.91,2.56,0.00%,129.12B,0.0134243199555489 -HAIER SMARTHOME,06690.HK,24.65,1.15,+4.894%,7.24M,178.37M,13.83,2.21,2.59%,70.46B,0.000651404549603483 -HAIDILAO,06862.HK,21,0.6,+2.941%,6.86M,143.79M,74.46,13.94,0.55%,117.05B,0.00190088484005443 -JD-SW,09618.HK,115.1,4,+3.600%,7.43M,852.28M,30.73,1.5,6.38%,360.24B,0.00428962133421518 -NONGFU SPRING,09633.HK,45,1.5,+3.448%,3.69M,165.62M,52.49,18.63,1.71%,226.56B,0.0115149371133421 -BIDU-SW,09888.HK,133.4,4.6,+3.571%,5.82M,772.73M,47.3,1.5,0.00%,377.37B,0.000214728364341268 -TRIP.COM-S,09961.HK,279.2,7,+2.572%,1.25M,349.59M,114.05,1.4,0.00%,176.65B,0.00259418338669419 -BABA-SW,09988.HK,85.6,2.6,+3.133%,34.61M,2.96B,21.65,1.62,0.00%,1,0.0010637787558598 -NTES-S,09999.HK,159.5,8.3,+5.489%,5.02M,797.10M,22.7,4.63,1.36%,546.99B,0.0044461470356248 diff --git a/vuu/src/main/resources/static/nasdaq100.csv b/vuu/src/main/resources/static/nasdaq100.csv deleted file mode 100644 index 6447cbb7a..000000000 --- a/vuu/src/main/resources/static/nasdaq100.csv +++ /dev/null @@ -1,102 +0,0 @@ -#,Name,Symbol,Weighting,Last Trade,Chg,% Chg -1,Apple Inc,AAPL,11.007,174.94,0.15,(0.09%) -2,Microsoft Corp,MSFT,9.61,316.98,-0.03,(-0.01%) -3,Amazon.com Inc,AMZN,5.401,129.31,0.19,(0.14%) -4,NVIDIA Corp,NVDA,4.101,415.74,-0.36,(-0.09%) -5,Meta Platforms Inc,META,3.729,299.42,0.34,(0.11%) -6,Tesla Inc,TSLA,3.285,244.13,-0.75,(-0.31%) -7,Alphabet Inc,GOOGL,3.133,130.49,0.24,(0.18%) -8,Alphabet Inc,GOOG,3.085,131.49,0.24,(0.18%) -9,Broadcom Inc,AVGO,2.896,833.04,3.96,(0.48%) -10,Costco Wholesale Corp,COST,2.137,557.85,-0.74,(-0.13%) -11,PepsiCo Inc,PEP,2.096,174.84,-0.43,(-0.25%) -12,Adobe Inc,ADBE,2.033,511.42,-1.48,(-0.29%) -13,Cisco Systems Inc,CSCO,1.887,53.68,0.11,(0.20%) -14,Comcast Corp,CMCSA,1.633,45.30,-0.01,(-0.01%) -15,Netflix Inc,NFLX,1.478,379.89,0.08,(0.02%) -16,T-Mobile US Inc,TMUS,1.43,140.18,0.83,(0.60%) -17,Advanced Micro Devices Inc,AMD,1.348,96.09,-0.11,(-0.12%) -18,Texas Instruments Inc,TXN,1.264,161.00,0.69,(0.43%) -19,Intel Corp,INTC,1.26,34.19,0.01,(0.01%) -20,Amgen Inc,AMGN,1.251,271.18,3.48,(1.30%) -21,Intuit Inc,INTU,1.226,509.00,0.43,(0.08%) -22,Honeywell International Inc,HON,1.103,188.67,-1.12,(-0.59%) -23,QUALCOMM Inc,QCOM,1.046,107.53,-0.16,(-0.14%) -24,Applied Materials Inc,AMAT,0.982,136.32,0.15,(0.11%) -25,Booking Holdings Inc,BKNG,0.941,3,019.20,-43.30,(-1.42%) -26,Starbucks Corp,SBUX,0.926,93.80,0.12,(0.12%) -27,Intuitive Surgical Inc,ISRG,0.867,288.50,0.30,(0.10%) -28,Automatic Data Processing Inc,ADP,0.854,239.45,0.10,(0.04%) -29,Mondelez International Inc,MDLZ,0.835,71.25,0.82,(1.16%) -30,Gilead Sciences Inc,GILD,0.814,75.47,0.46,(0.61%) -31,Vertex Pharmaceuticals Inc,VRTX,0.794,353.67,4.14,(1.18%) -32,Regeneron Pharmaceuticals Inc,REGN,0.763,828.09,3.25,(0.39%) -33,Analog Devices Inc,ADI,0.752,176.82,1.34,(0.76%) -34,Lam Research Corp,LRCX,0.702,620.00,0.89,(0.14%) -35,Micron Technology Inc,MU,0.646,68.90,0.02,(0.03%) -36,Palo Alto Networks Inc,PANW,0.604,228.70,0.19,(0.08%) -37,Synopsys Inc,SNPS,0.587,447.12,0.27,(0.06%) -38,Charter Communications Inc,CHTR,0.581,441.88,-3.33,(-0.75%) -39,MercadoLibre Inc,MELI,0.562,1,275.50,-1.47,(-0.11%) -40,PayPal Holdings Inc,PYPL,0.559,57.90,0.02,(0.03%) -41,CSX Corp,CSX,0.54,31.23,0.03,(0.09%) -42,Cadence Design Systems Inc,CDNS,0.539,230.83,0.17,(0.07%) -43,KLA Corp,KLAC,0.53,456.11,4.29,(0.95%) -44,PDD Holdings Inc ADR,PDD,0.521,95.93,-0.01,(-0.01%) -45,Marriott International Inc/MD,MAR,0.505,193.90,-0.46,(-0.23%) -46,Monster Beverage Corp,MNST,0.498,54.48,-0.04,(-0.08%) -47,Airbnb Inc,ABNB,0.491,132.09,-0.11,(-0.08%) -48,O'Reilly Automotive Inc,ORLY,0.485,936.67,0.65,(0.07%) -49,Cintas Corp,CTAS,0.446,505.27,0.52,(0.10%) -50,ASML Holding NV,ASML,0.438,585.00,-2.10,(-0.36%) -51,NXP Semiconductors NV,NXPI,0.434,196.76,-0.04,(-0.02%) -52,Workday Inc,WDAY,0.414,235.55,4.73,(2.05%) -53,Lululemon Athletica Inc,LULU,0.405,386.36,-1.69,(-0.44%) -54,Keurig Dr Pepper Inc,KDP,0.404,33.25,0.13,(0.39%) -55,Fortinet Inc,FTNT,0.401,58.29,0.05,(0.09%) -56,Marvell Technology Inc,MRVL,0.388,52.38,0.08,(0.14%) -57,PACCAR Inc,PCAR,0.38,84.97,0.04,(0.04%) -58,Old Dominion Freight Line Inc,ODFL,0.38,401.01,0.35,(0.09%) -59,Autodesk Inc,ADSK,0.379,204.07,0.03,(0.01%) -60,Kraft Heinz Co/The,KHC,0.368,34.27,0.11,(0.31%) -61,Microchip Technology Inc,MCHP,0.36,77.00,-0.08,(-0.10%) -62,Copart Inc,CPRT,0.358,43.26,0.10,(0.22%) -63,American Electric Power Co Inc,AEP,0.357,79.23,0.06,(0.08%) -64,Paychex Inc,PAYX,0.355,113.01,0.06,(0.06%) -65,Exelon Corp,EXC,0.35,40.28,0.07,(0.16%) -66,ON Semiconductor Corp,ON,0.341,93.87,0.06,(0.06%) -67,AstraZeneca PLC ADR,AZN,0.339,67.35,-0.49,(-0.72%) -68,Seagen Inc,SGEN,0.336,212.18,-1.52,(-0.71%) -69,Ross Stores Inc,ROST,0.335,111.71,0.05,(0.04%) -70,Moderna Inc,MRNA,0.331,100.32,0.33,(0.33%) -71,Biogen Inc,BIIB,0.326,257.93,0.25,(0.10%) -72,Crowdstrike Holdings Inc,CRWD,0.319,162.85,0.28,(0.17%) -73,IDEXX Laboratories Inc,IDXX,0.316,439.41,3.72,(0.85%) -74,Baker Hughes Co,BKR,0.307,35.44,0.04,(0.10%) -75,Constellation Energy Corp,CEG,0.307,110.41,0.05,(0.04%) -76,Cognizant Technology Solutions Corp,CTSH,0.303,70.19,0.58,(0.83%) -77,Verisk Analytics Inc,VRSK,0.303,242.05,0.10,(0.04%) -78,Dexcom Inc,DXCM,0.3,88.30,0.80,(0.92%) -79,Trade Desk Inc/The,TTD,0.293,76.38,0.03,(0.03%) -80,Xcel Energy Inc,XEL,0.284,59.76,0.03,(0.04%) -81,Electronic Arts Inc,EA,0.279,118.38,-0.63,(-0.53%) -82,CoStar Group Inc,CSGP,0.277,78.18,0.12,(0.15%) -83,GLOBALFOUNDRIES Inc,GFS,0.273,57.21,0.38,(0.67%) -84,Fastenal Co,FAST,0.268,54.32,0.11,(0.20%) -85,Atlassian Corp,TEAM,0.253,196.01,0.55,(0.28%) -86,GE HealthCare Technologies Inc,GEHC,0.252,63.78,-0.56,(-0.86%) -87,Warner Bros Discovery Inc,WBD,0.244,11.09,-0.02,(-0.14%) -88,Diamondback Energy Inc,FANG,0.235,150.70,0.13,(0.09%) -89,Datadog Inc,DDOG,0.23,88.81,0.05,(0.06%) -90,ANSYS Inc,ANSS,0.227,300.60,-2.31,(-0.76%) -91,eBay Inc,EBAY,0.203,43.22,0.09,(0.20%) -92,Dollar Tree Inc,DLTR,0.201,104.77,0.27,(0.25%) -93,Align Technology Inc,ALGN,0.2,297.25,-1.31,(-0.44%) -94,Zscaler Inc,ZS,0.188,151.80,0.09,(0.06%) -95,Illumina Inc,ILMN,0.183,132.31,-0.13,(-0.10%) -96,Walgreens Boots Alliance Inc,WBA,0.161,21.18,0.06,(0.28%) -97,Zoom Video Communications Inc,ZM,0.151,68.57,-0.29,(-0.41%) -98,Enphase Energy Inc,ENPH,0.148,120.41,0.49,(0.41%) -99,Sirius XM Holdings Inc,SIRI,0.137,4.05,0.02,(0.50%) -100,JD.com Inc ADR,JD,0.117,30.43,0.02,(0.05%) -101,Lucid Group Inc,LCID,0.102,5.14,0.03,(0.49%) \ No newline at end of file diff --git a/vuu/src/main/resources/static/sp500.csv b/vuu/src/main/resources/static/sp500.csv deleted file mode 100644 index 19701b2cc..000000000 --- a/vuu/src/main/resources/static/sp500.csv +++ /dev/null @@ -1,504 +0,0 @@ -#,Name,Symbol,Weighting,Price,Change,Change %, -1,Apple Inc,AAPL,6.992488,171.9,1.47,(0.86%), -2,Microsoft Corp,MSFT,6.487978,314.55,1.76,(0.56%), -3,Amazon.com Inc,AMZN,3.193379,126.25,0.27,(0.22%), -4,Nvidia Corp,NVDA,2.928461,433.11,8.43,(1.99%), -5,Alphabet Inc Cl A,GOOGL,2.162218,132.93,2.39,(1.83%), -6,Tesla Inc,TSLA,1.854311,246.56,6.06,(2.52%), -7,Alphabet Inc Cl C,GOOG,1.85251,133.81,2.35,(1.78%), -8,Meta Platforms Inc Class A,META,1.847731,305.93,8.19,(2.75%), -9,Berkshire Hathaway Inc Cl B,BRK.B,1.82184,358.67,0.89,(0.25%), -10,Exxon Mobil Corp,XOM,1.343563,118.97,-1.23,(-1.03%), -11,Unitedhealth Group Inc,UNH,1.302884,510.04,6.31,(1.25%), -12,Eli Lilly & Co,LLY,1.224046,546.65,-3.11,(-0.57%), -13,Jpmorgan Chase & Co,JPM,1.182918,148.23,2.45,(1.68%), -14,Johnson & Johnson W/d,JNJ,1.056344,156.83,-0.28,(-0.18%), -15,Visa Inc Class a Shares,V,1.029636,231.97,2.47,(1.08%), -16,Procter & Gamble Co,PG,0.969793,145.75,-1.59,(-1.08%), -17,Broadcom Inc,AVGO,0.941177,835.33,18.52,(2.27%), -18,Mastercard Inc A,MA,0.918779,400.65,5.17,(1.31%), -19,Chevron Corp,CVX,0.847353,170.55,-0.49,(-0.28%), -20,Home Depot Inc,HD,0.847289,304.35,2.53,(0.84%), -22,Abbvie Inc,ABBV,0.754672,152.14,-0.99,(-0.65%), -23,Merck & Co. Inc.,MRK,0.736434,104.2,0.26,(0.25%), -24,Costco Wholesale Corp,COST,0.697258,569.05,5.52,(0.98%), -25,Pepsico Inc,PEP,0.651768,168.92,-0.65,(-0.38%), -26,Walmart Inc,WMT,0.644449,161.87,0.15,(0.09%), -27,Adobe Inc,ADBE,0.639652,507.17,4.57,(0.91%), -28,Coca Cola Co,KO,0.60801,55.82,-0.13,(-0.23%), -29,Cisco Systems Inc,CSCO,0.605326,53.97,0.77,(1.44%), -30,Accenture Plc Cl A,ACN,0.55372,298.5,-15.9,(-5.05%), -31,Salesforce Inc,CRM,0.551342,204.46,1.73,(0.85%), -32,Thermo Fisher Scientific Inc,TMO,0.536951,503.47,5.18,(1.04%), -33,Mcdonald S Corp,MCD,0.536457,265.83,2.19,(0.83%), -34,Bank of America Corp,BAC,0.526405,27.51,0.24,(0.86%), -35,Comcast Corp Class A,CMCSA,0.512537,45.17,0.57,(1.27%), -36,Linde Plc,LIN,0.506835,375.48,3.47,(0.93%), -37,Pfizer Inc,PFE,0.506043,32.09,-0.02,(-0.05%), -38,Netflix Inc,NFLX,0.467192,377.77,0.18,(0.05%), -39,Abbott Laboratories,ABT,0.462893,97.52,1.99,(2.08%), -40,Oracle Corp,ORCL,0.459877,106.29,1.67,(1.60%), -41,Danaher Corp,DHR,0.454026,248.24,0.8,(0.32%), -42,Advanced Micro Devices,AMD,0.442473,103.74,5.67,(5.78%), -43,Wells Fargo & Co,WFC,0.417428,41.04,0.18,(0.43%), -44,Conocophillips,COP,0.411569,123.32,0.23,(0.18%), -45,Walt Disney Co,DIS,0.408438,80.35,0.45,(0.56%), -46,Intel Corp,INTC,0.404462,35.5,0.89,(2.56%), -47,Amgen Inc,AMGN,0.401904,270.91,1.93,(0.72%), -48,Texas Instruments Inc,TXN,0.400931,160.98,2.84,(1.80%), -49,Intuit Inc,INTU,0.397406,515.11,6.87,(1.35%), -50,Philip Morris International,PM,0.39143,92.66,2.34,(2.59%), -51,Caterpillar Inc,CAT,0.388444,276.34,3.63,(1.33%), -52,Verizon Communications Inc,VZ,0.380327,32.56,0.16,(0.48%), -53,Intl Business Machines Corp,IBM,0.364246,140.89,-2.28,(-1.59%), -54,Honeywell International Inc,HON,0.348317,188.68,0.8,(0.43%), -55,Union Pacific Corp,UNP,0.344419,203.88,1.48,(0.73%), -56,Qualcomm Inc,QCOM,0.340195,111.55,2.36,(2.16%), -57,Nextera Energy Inc,NEE,0.338809,57.64,-2.32,(-3.88%), -58,Lowe S Cos Inc,LOW,0.338613,209.52,2.56,(1.24%), -59,Bristol Myers Squibb Co,BMY,0.337683,58.3,0.41,(0.70%), -60,General Electric Co,GE,0.336989,112.43,1.54,(1.39%), -61,S&p Global Inc,SPGI,0.32985,369.21,6.15,(1.69%), -62,Applied Materials Inc,AMAT,0.316678,139.15,4.09,(3.03%), -63,Servicenow Inc,NOW,0.3112,552.84,6.46,(1.18%), -64,Boeing Co,BA,0.309673,193.12,-2.34,(-1.20%), -65,United Parcel Service Cl B,UPS,0.307795,154.29,1.88,(1.23%), -66,Booking Holdings Inc,BKNG,0.307126,3,86.26,3.6,(0.12%) -67,Nike Inc Cl B,NKE,0.305871,89.63,0.21,(0.24%), -68,At&t Inc,T,0.296603,14.94,0.07,(0.44%), -69,Goldman Sachs Group Inc,GS,0.296356,325.72,3.77,(1.17%), -70,Rtx Corp,RTX,0.296189,72.54,-0.34,(-0.46%), -71,Elevance Health Inc,ELV,0.292632,448.99,4.23,(0.95%), -72,Deere & Co,DE,0.291602,388.36,4,(1.04%), -73,Starbucks Corp,SBUX,0.291579,91.21,0.04,(0.04%), -74,Morgan Stanley,MS,0.29087,82.34,0.69,(0.84%), -75,Medtronic Plc,MDT,0.290688,78.77,0.55,(0.71%), -76,Prologis Inc,PLD,0.286912,112.3,1.05,(0.94%), -77,Intuitive Surgical Inc,ISRG,0.285764,296.31,4.88,(1.67%), -78,Tjx Companies Inc,TJX,0.282733,89.27,1.16,(1.32%), -79,Automatic Data Processing,ADP,0.279113,243.79,1.16,(0.48%), -80,Marsh & Mclennan Cos,MMC,0.266169,193.53,0.55,(0.29%), -81,Mondelez International Inc A,MDLZ,0.26425,69.44,-0.56,(-0.79%), -82,Gilead Sciences Inc,GILD,0.26285,75.96,0.41,(0.54%), -83,Lockheed Martin Corp,LMT,0.255775,410.4,1.68,(0.41%), -84,Blackrock Inc,BLK,0.252096,645.37,1.98,(0.31%), -85,Vertex Pharmaceuticals Inc,VRTX,0.251521,353.91,4.26,(1.22%), -86,Stryker Corp,SYK,0.250789,273.07,6.53,(2.45%), -87,Cvs Health Corp,CVS,0.250255,70.11,0.33,(0.47%), -88,Regeneron Pharmaceuticals,REGN,0.2481,835.67,3.11,(0.37%), -89,American Express Co,AXP,0.243515,150.42,0.52,(0.34%), -90,Chubb Ltd,CB,0.242706,212.92,1.29,(0.61%), -91,Analog Devices Inc,ADI,0.241943,177.01,4.2,(2.43%), -92,Schlumberger Ltd,SLB,0.241232,61.02,0.22,(0.36%), -93,Eaton Corp Plc,ETN,0.238556,216.42,2.06,(0.96%), -94,The Cigna Group,CI,0.238517,291.43,2.82,(0.98%), -95,Progressive Corp,PGR,0.229854,140.76,0.14,(0.10%), -96,Lam Research Corp,LRCX,0.228483,627.46,13.54,(2.20%), -97,Schwab (Charles) Corp,SCHW,0.225784,54.57,0.19,(0.35%), -98,Zoetis Inc,ZTS,0.224522,174.68,0,(-0.00%), -99,Citigroup Inc,C,0.217552,41.24,0.78,(1.92%), -100,Boston Scientific Corp,BSX,0.213003,53.3,1.2,(2.31%), -101,Blackstone Inc,BX,0.211158,108.88,2.33,(2.19%), -102,Eog Resources Inc,EOG,0.21104,130.56,0.75,(0.57%), -103,Becton Dickinson and Co,BDX,0.209627,262.6,3.8,(1.47%), -104,Micron Technology Inc,MU,0.208276,66.25,-1.96,(-2.87%), -105,American Tower Corp,AMT,0.207727,160.73,1.04,(0.65%), -106,Altria Group Inc,MO,0.207666,42.11,0.2,(0.47%), -107,T Mobile Us Inc,TMUS,0.20192,140.3,0.6,(0.43%), -108,Cme Group Inc,CME,0.201368,200.22,-0.14,(-0.07%), -109,Southern Co,SO,0.20116,65.04,-1.1,(-1.67%), -110,Palo Alto Networks Inc,PANW,0.198047,236.42,4.52,(1.95%), -111,Duke Energy Corp,DUK,0.193827,88.87,-1.23,(-1.36%), -112,Fiserv Inc,FI,0.192662,113.67,0.48,(0.42%), -113,Synopsys Inc,SNPS,0.189768,458.88,12.17,(2.72%), -114,Activision Blizzard Inc,ATVI,0.18717,93.71,-0.22,(-0.23%), -115,Aon Plc Class A,AON,0.186896,330.04,0.12,(0.04%), -116,Equinix Inc,EQIX,0.184757,715.84,8.74,(1.24%), -117,Illinois Tool Works,ITW,0.177501,233.17,0.77,(0.33%), -118,Air Products & Chemicals Inc,APD,0.17678,289.15,3.89,(1.36%), -119,Paypal Holdings Inc,PYPL,0.175802,58.3,0.96,(1.67%), -120,Cadence Design Sys Inc,CDNS,0.175052,235.09,4.44,(1.93%), -121,Northrop Grumman Corp,NOC,0.173654,441.3,4.06,(0.93%), -122,Intercontinental Exchange In,ICE,0.172998,109.93,1.66,(1.53%), -123,Humana Inc,HUM,0.170476,495.73,2.16,(0.44%), -124,Marathon Petroleum Corp,MPC,0.170186,155.28,2.85,(1.87%), -125,Kla Corp,KLAC,0.170079,459.61,14.05,(3.15%), -126,Fedex Corp,FDX,0.169747,266.99,4.28,(1.63%), -127,Csx Corp,CSX,0.169632,30.62,0.34,(1.14%), -128,Mckesson Corp,MCK,0.167376,445.58,1.2,(0.27%), -129,Sherwin Williams Co,SHW,0.165389,254.95,4.33,(1.73%), -130,Colgate Palmolive Co,CL,0.164,71.11,0.06,(0.08%), -131,Airbnb Inc Class A,ABNB,0.159553,137.66,3.63,(2.70%), -132,Waste Management Inc,WM,0.15893,154.17,-0.25,(-0.16%), -133,Emerson Electric Co,EMR,0.154857,97.31,0.45,(0.47%), -134,O Reilly Automotive Inc,ORLY,0.154194,918.15,3.98,(0.44%), -135,Pioneer Natural Resources Co,PXD,0.1524,234.43,0.34,(0.14%), -136,Phillips 66,PSX,0.150197,122.81,2.01,(1.66%), -137,Freeport Mcmoran Inc,FCX,0.146185,37.34,0.79,(2.17%), -138,3m Co W/d,MMM,0.144312,93.48,0.02,(0.02%), -139,Roper Technologies Inc,ROP,0.144165,486.61,-0.02,(-0.00%), -140,Valero Energy Corp,VLO,0.141937,147.59,3.64,(2.53%), -141,Nxp Semiconductors Nv,NXPI,0.141583,202.19,5.49,(2.79%), -142,Target Corp,TGT,0.141106,109.31,-0.44,(-0.40%), -143,Parker Hannifin Corp,PH,0.140358,396.29,5.18,(1.32%), -144,Us Bancorp,USB,0.139291,32.59,0.07,(0.20%), -145,General Dynamics Corp,GD,0.139193,223.44,2.44,(1.10%), -146,Chipotle Mexican Grill Inc,CMG,0.139055,1,828.59,22.51,(1.25%) -147,Hca Healthcare Inc,HCA,0.138966,251.59,4.33,(1.75%), -148,Arthur J Gallagher & Co,AJG,0.138231,231.77,1.44,(0.62%), -149,Moody S Corp,MCO,0.138162,319.07,4.56,(1.45%), -150,Amphenol Corp Cl A,APH,0.136941,84.4,2.04,(2.47%), -151,Ford Motor Co,F,0.1362,12.58,0.19,(1.49%), -152,Marriott International Cl A,MAR,0.135619,199.53,5.65,(2.92%), -153,Pnc Financial Services Group,PNC,0.135457,123.09,1.28,(1.05%), -154,Transdigm Group Inc,TDG,0.131273,860.46,8.64,(1.01%), -155,Carrier Global Corp,CARR,0.129065,56.83,1.75,(3.17%), -156,Autozone Inc,AZO,0.128857,2,556.17,15.27,(0.60%) -157,Trane Technologies Plc,TT,0.12759,207.07,7.01,(3.50%), -158,Motorola Solutions Inc,MSI,0.127284,275.18,2.2,(0.81%), -159,Arista Networks Inc,ANET,0.12715,184.23,2.63,(1.45%), -160,Norfolk Southern Corp,NSC,0.124378,197.3,1.08,(0.55%), -161,General Motors Co,GM,0.124282,33.25,0.9,(2.77%), -162,Paccar Inc,PCAR,0.123613,86.12,1.31,(1.54%), -163,Charter Communications Inc A,CHTR,0.123199,442.28,8.86,(2.04%), -164,Hess Corp,HES,0.121942,157.3,-0.74,(-0.47%), -165,Sempra,SRE,0.121909,68.15,-1.26,(-1.81%), -166,Occidental Petroleum Corp,OXY,0.121531,66.03,0.43,(0.66%), -167,American International Group,AIG,0.121272,61.73,0.72,(1.18%), -168,Autodesk Inc,ADSK,0.120711,208.03,5.75,(2.84%), -169,Edwards Lifesciences Corp,EW,0.119074,69.68,-0.43,(-0.62%), -170,Ecolab Inc,ECL,0.118911,169.5,1.63,(0.97%), -171,Public Storage,PSA,0.117206,266.58,1.6,(0.60%), -172,Microchip Technology Inc,MCHP,0.116275,78.91,2.41,(3.15%), -173,Aflac Inc,AFL,0.11627,77.65,0.62,(0.81%), -174,Cintas Corp,CTAS,0.116227,486.83,5.75,(1.19%), -175,Welltower Inc,WELL,0.116157,81.07,0.87,(1.08%), -176,Williams Cos Inc,WMB,0.115685,34.65,0.55,(1.61%), -177,Kimberly Clark Corp,KMB,0.114902,121.11,-0.55,(-0.45%), -178,Archer Daniels Midland Co,ADM,0.114307,76.74,0.38,(0.50%), -179,Msci Inc,MSCI,0.113047,518.97,7.03,(1.37%), -180,Constellation Brands Inc A,STZ,0.112869,251.62,1.03,(0.41%), -181,On Semiconductor,ON,0.111009,95.12,3.07,(3.33%), -182,Metlife Inc,MET,0.110772,63.06,0.26,(0.41%), -183,Monster Beverage Corp,MNST,0.110311,53.31,0.19,(0.35%), -184,Hilton Worldwide Holdings In,HLT,0.109054,153.24,3.88,(2.60%), -185,American Electric Power,AEP,0.108899,74.71,-1.15,(-1.51%), -186,Crown Castle Inc,CCI,0.108512,91.35,1.65,(1.83%), -187,Exelon Corp,EXC,0.107894,38.11,-0.69,(-1.78%), -188,Nucor Corp,NUE,0.107787,158.31,2.6,(1.67%), -189,Travelers Cos Inc,TRV,0.107342,167.42,-0.51,(-0.30%), -190,Dominion Energy Inc,D,0.106001,44.61,-0.86,(-1.88%), -191,Te Connectivity Ltd,TEL,0.105581,123.84,3.4,(2.82%), -192,Halliburton Co,HAL,0.105449,42.18,0.15,(0.37%), -193,Centene Corp,CNC,0.105443,69.87,0.13,(0.18%), -194,Fortinet Inc,FTNT,0.105315,59.07,0.93,(1.59%), -195,Oneok Inc,OKE,0.104854,64.86,0.35,(0.53%), -196,General Mills Inc,GIS,0.104655,63.79,-0.26,(-0.40%), -197,Copart Inc,CPRT,0.104453,43.66,0.61,(1.41%), -198,Paychex Inc,PAYX,0.104412,117.4,0.89,(0.76%), -199,Biogen Inc,BIIB,0.103916,258.95,1.43,(0.55%), -200,Truist Financial Corp,TFC,0.103679,28.15,0.18,(0.63%), -201,Ross Stores Inc,ROST,0.10361,111.18,2.26,(2.07%), -202,Johnson Controls Internation,JCI,0.103601,53.69,-0.85,(-1.55%), -203,Iqvia Holdings Inc,IQV,0.103397,200.11,-2.1,(-1.04%), -204,Capital One Financial Corp,COF,0.101688,96.63,1.14,(1.20%), -205,Baker Hughes Co,BKR,0.101425,36.62,0.37,(1.02%), -206,Idexx Laboratories Inc,IDXX,0.101263,439.37,2.51,(0.57%), -207,Corteva Inc,CTVA,0.100577,50.77,0.02,(0.05%), -208,Dow Inc,DOW,0.100258,50.87,-0.13,(-0.26%), -209,Old Dominion Freight Line,ODFL,0.100037,406.82,6.93,(1.73%), -210,Constellation Energy,CEG,0.099445,109.94,-0.81,(-0.73%), -211,Dexcom Inc,DXCM,0.099384,95.68,3.59,(3.90%), -212,Simon Property Group Inc,SPG,0.098977,108.45,0.26,(0.24%), -213,Digital Realty Trust Inc,DLR,0.098757,117.6,0.76,(0.65%), -214,Realty Income Corp,O,0.098278,49.83,0.17,(0.33%), -215,Kenvue Inc W/i,KVUE,0.097359,20.2,-0.02,(-0.12%), -216,Verisk Analytics Inc,VRSK,0.097203,241.97,2.34,(0.98%), -217,Cognizant Tech Solutions A,CTSH,0.096172,68.15,-0.05,(-0.07%), -218,P G & E Corp,PCG,0.095995,16.36,-0.09,(-0.52%), -219,Prudential Financial Inc,PRU,0.095804,94.93,0.41,(0.43%), -220,Ametek Inc,AME,0.09567,150.03,1.17,(0.79%), -221,Yum Brands Inc,YUM,0.095443,123.55,1.57,(1.29%), -222,Dupont De Nemours Inc,DD,0.094185,74.58,1.11,(1.51%), -223,Ameriprise Financial Inc,AMP,0.093691,332.11,5.16,(1.58%), -224,L3harris Technologies Inc,LHX,0.092512,173.16,-2.04,(-1.16%), -225,Fidelity National Info Serv,FIS,0.09207,56.06,0.52,(0.94%), -226,Sysco Corp,SYY,0.091968,65.99,0.78,(1.20%), -227,Moderna Inc,MRNA,0.091789,100.61,1.17,(1.18%), -228,Bank of New York Mellon Corp,BK,0.091699,42.76,0.59,(1.39%), -229,Agilent Technologies Inc,A,0.091382,111.91,1.41,(1.28%), -230,Otis Worldwide Corp,OTIS,0.091228,80.55,1.2,(1.51%), -231,Rockwell Automation Inc,ROK,0.091103,288.26,3.46,(1.21%), -232,Dr Horton Inc,DHI,0.090974,108.96,1.95,(1.82%), -233,Cummins Inc,CMI,0.090916,232.98,3.03,(1.32%), -234,Estee Lauder Companies Cl A,EL,0.090788,139.94,-0.1,(-0.07%), -235,Kinder Morgan Inc,KMI,0.090175,16.71,0.05,(0.27%), -236,Keurig Dr Pepper Inc,KDP,0.088358,31.51,-0.16,(-0.51%), -237,Fastenal Co,FAST,0.087952,55.72,0.66,(1.21%), -238,Xcel Energy Inc,XEL,0.087474,56.5,-0.71,(-1.25%), -239,Devon Energy Corp,DVN,0.087359,48.84,0,(0.01%), -240,Ww Grainger Inc,GWW,0.086956,704.07,3.96,(0.57%), -241,Costar Group Inc,CSGP,0.086756,77.1,0.75,(0.99%), -242,Cencora Inc,COR,0.086188,183.99,-1.17,(-0.63%), -243,United Rentals Inc,URI,0.085093,454.44,8.22,(1.84%), -244,Hershey Co,HSY,0.084755,201.01,-1.55,(-0.76%), -245,Arch Capital Group Ltd,ACGL,0.083799,81.62,0.54,(0.67%), -246,Ppg Industries Inc,PPG,0.083787,130.49,2.46,(1.92%), -247,Global Payments Inc,GPN,0.083671,116.72,1.47,(1.28%), -248,Consolidated Edison Inc,ED,0.083432,85.06,-1.57,(-1.81%), -249,Newmont Corp,NEM,0.082799,36.78,-0.5,(-1.34%), -250,Republic Services Inc,RSG,0.082765,145.01,0.28,(0.19%), -251,Allstate Corp,ALL,0.08254,112.77,-0.25,(-0.22%), -252,Electronic Arts Inc,EA,0.081213,119.76,1.79,(1.51%), -253,Vici Properties Inc,VICI,0.081127,29.28,0.4,(1.37%), -254,Kroger Co,KR,0.080998,44.96,0.48,(1.07%), -255,Public Service Enterprise Gp,PEG,0.080723,56.88,-1.02,(-1.75%), -256,Lennar Corp A,LEN,0.078759,113.41,1.71,(1.53%), -257,Diamondback Energy Inc,FANG,0.078498,158.01,0.78,(0.50%), -258,West Pharmaceutical Services,WST,0.077362,377.15,1.97,(0.52%), -259,Quanta Services Inc,PWR,0.077074,190.82,0.7,(0.37%), -260,Gartner Inc,IT,0.076911,347.78,-1.41,(-0.40%), -261,Aptiv Plc,APTV,0.0757,99.21,3.35,(3.50%), -262,Vulcan Materials Co,VMC,0.075604,207.6,4,(1.97%), -263,Kraft Heinz Co,KHC,0.075468,33.72,-0.31,(-0.90%), -264,Ge Healthcare Technology,GEHC,0.074734,69.81,1.53,(2.24%), -265,Cdw Corp/de,CDW,0.074375,202.53,3.84,(1.93%), -266,Fortive Corp,FTV,0.072323,74.75,1.16,(1.58%), -267,Ingersoll Rand Inc,IR,0.071683,64.52,1.25,(1.97%), -268,Ansys Inc,ANSS,0.071343,299.19,4.85,(1.65%), -269,Extra Space Storage Inc,EXR,0.071269,120.75,0.24,(0.20%), -270,Wec Energy Group Inc,WEC,0.071007,79.67,-0.91,(-1.12%), -271,Martin Marietta Materials,MLM,0.070759,418,8.05,(1.96%), -272,Edison International,EIX,0.068887,63.92,-1.38,(-2.11%), -273,American Water Works Co Inc,AWK,0.068233,123.27,-3.07,(-2.43%), -274,Warner Bros Discovery Inc,WBD,0.068207,10.89,-0.15,(-1.31%), -275,Lyondellbasell Indu Cl A,LYB,0.067294,94.86,-0.11,(-0.11%), -276,Mettler Toledo International,MTD,0.067028,1,112.26,14.48,(1.32%) -277,Avalonbay Communities Inc,AVB,0.066762,171.85,-0.6,(-0.35%), -278,Delta Air Lines Inc,DAL,0.065781,37.32,0.66,(1.79%), -279,T Rowe Price Group Inc,TROW,0.064996,104.73,1.19,(1.15%), -280,Keysight Technologies In,KEYS,0.064934,133.51,3.11,(2.38%), -281,Zimmer Biomet Holdings Inc,ZBH,0.064476,112.14,1.38,(1.24%), -282,Dollar General Corp,DG,0.064042,105.04,0.7,(0.67%), -283,Corning Inc,GLW,0.064037,30.35,0.29,(0.98%), -284,Ebay Inc,EBAY,0.063728,43.45,0.56,(1.31%), -285,Cbre Group Inc A,CBRE,0.063578,73.84,0.35,(0.48%), -286,Weyerhaeuser Co,WY,0.063312,30.4,-0.64,(-2.05%), -287,Church & Dwight Co Inc,CHD,0.062765,91.68,-0.29,(-0.31%), -288,Cardinal Health Inc,CAH,0.062583,88.18,0.14,(0.16%), -289,Hp Inc,HPQ,0.062013,25.73,0.09,(0.36%), -290,Equifax Inc,EFX,0.061821,185.4,4.68,(2.59%), -291,Tractor Supply Company,TSCO,0.061683,205.07,2.06,(1.02%), -292,Willis Towers Watson Plc,WTW,0.06168,211.96,0.35,(0.17%), -293,Hewlett Packard Enterprise,HPE,0.061499,17.7,0.63,(3.66%), -294,Fair Isaac Corp,FICO,0.061481,890.19,4.58,(0.52%), -295,Dollar Tree Inc,DLTR,0.061287,106.46,1.11,(1.05%), -296,Hartford Financial Svcs Grp,HIG,0.061236,72.24,0.53,(0.73%), -297,Resmed Inc,RMD,0.060853,149.81,1.16,(0.78%), -298,Take Two Interactive Softwre,TTWO,0.060753,139.63,1.85,(1.34%), -299,Royal Caribbean Cruises Ltd,RCL,0.060515,94.38,2.42,(2.64%), -300,Xylem Inc,XYL,0.060192,91.4,1.09,(1.20%), -301,Align Technology Inc,ALGN,0.060095,309.06,7.38,(2.45%), -302,Steris Plc,STE,0.060013,221.57,3.67,(1.69%), -303,Broadridge Financial Solutio,BR,0.059572,181.18,-0.04,(-0.02%), -304,Discover Financial Services,DFS,0.059507,86.35,1.09,(1.28%), -305,State Street Corp,STT,0.059411,67.81,1.03,(1.54%), -306,Sba Communications Corp,SBAC,0.059216,198.11,2.05,(1.05%), -307,Monolithic Power Systems Inc,MPWR,0.058699,457.69,16.51,(3.74%), -308,Illumina Inc,ILMN,0.058584,133.02,-0.28,(-0.21%), -309,Dte Energy Company,DTE,0.058057,98.82,-1.72,(-1.71%), -310,M & T Bank Corp,MTB,0.057846,126.63,2.09,(1.68%), -311,Coterra Energy Inc,CTRA,0.057589,27.48,0.34,(1.23%), -312,Eversource Energy,ES,0.057281,57.54,-1.23,(-2.09%), -313,Genuine Parts Co,GPC,0.055796,142.94,0.63,(0.45%), -314,Equity Residential,EQR,0.055712,58.67,0.23,(0.40%), -315,Entergy Corp,ETR,0.055241,92.23,-1.02,(-1.10%), -316,Dover Corp,DOV,0.055103,141.68,1.09,(0.77%), -317,Ameren Corporation,AEE,0.054981,74.6,-1.51,(-1.98%), -318,Ulta Beauty Inc,ULTA,0.054585,398.17,5.73,(1.46%), -319,Teledyne Technologies Inc,TDY,0.054228,414.36,0.92,(0.22%), -320,Nvr Inc,NVR,0.054188,6,27.42,86.42,(1.45%) -321,Targa Resources Corp,TRGP,0.05408,87.52,0.93,(1.08%), -322,Molina Healthcare Inc,MOH,0.053618,333.09,2.03,(0.61%), -323,Wabtec Corp,WAB,0.053425,108.18,1.35,(1.26%), -324,Fleetcor Technologies Inc,FLT,0.053345,260.14,1.28,(0.49%), -325,Albemarle Corp,ALB,0.053229,172.99,10.36,(6.37%), -326,Baxter International Inc,BAX,0.05272,37.54,0.21,(0.57%), -327,Raymond James Financial Inc,RJF,0.052247,101.39,1.84,(1.85%), -328,Mccormick & Co Non Vtg Shrs,MKC,0.051871,74.55,0.46,(0.63%), -329,Invitation Homes Inc,INVH,0.051153,31.73,0.03,(0.11%), -330,Firstenergy Corp,FE,0.050777,34.56,-0.69,(-1.94%), -331,Laboratory Crp of Amer Hldgs,LH,0.05072,204.23,-0.62,(-0.30%), -332,Howmet Aerospace Inc,HWM,0.050386,46.99,0.91,(1.97%), -333,Verisign Inc,VRSN,0.050215,202.93,2.46,(1.23%), -334,Ppl Corp,PPL,0.04902,23.56,-0.39,(-1.61%), -335,Iron Mountain Inc,IRM,0.047985,59.55,0.56,(0.94%), -336,Jacobs Solutions Inc,J,0.047882,136.45,0.27,(0.20%), -337,Intl Flavors & Fragrances,IFF,0.047868,67.84,0.64,(0.95%), -338,Centerpoint Energy Inc,CNP,0.047827,26.68,-0.48,(-1.75%), -339,Darden Restaurants Inc,DRI,0.047736,143.44,2.01,(1.42%), -340,Hologic Inc,HOLX,0.047358,69.99,0.75,(1.08%), -341,First Solar Inc,FSLR,0.047324,161.9,3.29,(2.07%), -342,Expeditors Intl Wash Inc,EXPD,0.046936,114.74,1.08,(0.95%), -343,Brown & Brown Inc,BRO,0.046675,71.15,0.19,(0.26%), -344,Factset Research Systems Inc,FDS,0.046601,443.66,8.47,(1.95%), -345,Fifth Third Bancorp,FITB,0.046598,25.05,0.19,(0.74%), -346,Ventas Inc,VTR,0.046351,42.18,0.77,(1.85%), -347,Marathon Oil Corp,MRO,0.046321,27.51,0.12,(0.45%), -348,Steel Dynamics Inc,STLD,0.046096,106.96,0.52,(0.48%), -349,Bunge Ltd,BG,0.046038,110.67,1.1,(1.00%), -350,Ptc Inc,PTC,0.045951,140.25,1.78,(1.28%), -351,Everest Group Ltd,EG,0.04587,381.3,-0.42,(-0.11%), -352,Cincinnati Financial Corp,CINF,0.045852,104.4,-0.3,(-0.29%), -353,Enphase Energy Inc,ENPH,0.045679,121.39,1.28,(1.07%), -354,Nasdaq Inc,NDAQ,0.04562,49.07,0.74,(1.52%), -355,Akamai Technologies Inc,AKAM,0.045578,107.75,0.79,(0.74%), -356,Cboe Global Markets Inc,CBOE,0.045525,155.28,0.51,(0.33%), -357,Cf Industries Holdings Inc,CF,0.04496,84.93,1.48,(1.78%), -358,Waters Corp,WAT,0.044936,274.46,2.12,(0.78%), -359,Pultegroup Inc,PHM,0.044848,74.85,1.65,(2.25%), -360,Tyler Technologies Inc,TYL,0.044831,387.74,2.43,(0.63%), -361,Principal Financial Group,PFG,0.044705,72.74,0.74,(1.02%), -362,Clorox Company,CLX,0.04465,128.98,-0.17,(-0.13%), -363,Southwest Airlines Co,LUV,0.044478,27.3,0.49,(1.81%), -364,Regions Financial Corp,RF,0.044397,17.16,0.22,(1.27%), -365,Garmin Ltd,GRMN,0.044336,104.65,1.42,(1.38%), -366,Atmos Energy Corp,ATO,0.044128,106.32,-0.14,(-0.13%), -367,Netapp Inc,NTAP,0.044116,76.49,1.54,(2.05%), -368,Textron Inc,TXT,0.043659,79.27,0.33,(0.41%), -369,Cooper Cos Inc,COO,0.04361,318.15,2.23,(0.71%), -370,Kellogg Co,K,0.043517,58.9,-0.22,(-0.38%), -371,Idex Corp,IEX,0.043484,210.72,3.28,(1.58%), -372,Cms Energy Corp,CMS,0.043476,52.78,-0.57,(-1.07%), -373,Skyworks Solutions Inc,SWKS,0.042974,98.55,2.25,(2.33%), -374,Alexandria Real Estate Equit,ARE,0.042466,99.48,0.59,(0.60%), -375,Hunt (Jb) Transprt Svcs Inc,JBHT,0.042319,186.54,0.95,(0.51%), -376,Las Vegas Sands Corp,LVS,0.042222,45.63,-0.53,(-1.15%), -377,Ball Corp,BALL,0.042202,48.27,0.04,(0.08%), -378,Walgreens Boots Alliance Inc,WBA,0.04215,20.97,-0.06,(-0.26%), -379,Teradyne Inc,TER,0.041494,100.04,3.56,(3.68%), -380,Mid America Apartment Comm,MAA,0.041385,128.55,0.48,(0.37%), -381,Epam Systems Inc,EPAM,0.041006,257.76,0.96,(0.37%), -382,Avery Dennison Corp,AVY,0.040961,183.42,1.39,(0.76%), -383,Omnicom Group,OMC,0.040483,74.6,1.21,(1.65%), -384,Huntington Bancshares Inc,HBAN,0.040444,10.25,0.13,(1.24%), -385,Eqt Corp,EQT,0.040251,40,0.39,(0.99%), -386,Tyson Foods Inc Cl A,TSN,0.040042,49.74,-0.37,(-0.74%), -387,Western Digital Corp,WDC,0.039814,45.5,0.94,(2.11%), -388,Northern Trust Corp,NTRS,0.039557,69.29,0.84,(1.23%), -389,Carnival Corp,CCL,0.039206,14.52,0.54,(3.88%), -390,Expedia Group Inc,EXPE,0.038585,102.75,2.5,(2.49%), -391,United Airlines Holdings Inc,UAL,0.038383,42.84,0.81,(1.94%), -392,Quest Diagnostics Inc,DGX,0.038331,123.71,0.31,(0.25%), -393,Axon Enterprise Inc,AXON,0.03828,195.69,1.04,(0.53%), -394,Packaging Corp of America,PKG,0.038236,152.79,0.9,(0.59%), -395,Revvity Inc,RVTY,0.0378,110.55,1.5,(1.38%), -396,Snap on Inc,SNA,0.037774,257.97,4,(1.58%), -397,Pool Corp,POOL,0.037475,353.56,9.86,(2.87%), -398,Essex Property Trust Inc,ESS,0.03733,210.81,0.07,(0.03%), -399,Domino S Pizza Inc,DPZ,0.037258,382.39,2.18,(0.57%), -400,Amcor Plc,AMCR,0.037101,9.09,0.06,(0.61%), -401,Best Buy Co Inc,BBY,0.037071,68.66,0.29,(0.43%), -402,Apa Corp,APA,0.03662,42.49,0.11,(0.27%), -403,Lamb Weston Holdings Inc,LW,0.036553,91.47,0.09,(0.10%), -404,Wr Berkley Corp,WRB,0.036551,65.21,0.86,(1.33%), -405,Conagra Brands Inc,CAG,0.036484,27.44,-0.1,(-0.35%), -406,Lkq Corp,LKQ,0.036449,49.51,0.72,(1.47%), -407,Jm Smucker Co,SJM,0.035767,124.48,-0.96,(-0.77%), -408,Stanley Black & Decker Inc,SWK,0.035567,83.87,0.97,(1.17%), -409,Synchrony Financial,SYF,0.035241,30.73,0.55,(1.84%), -410,Carmax Inc,KMX,0.035202,71.64,-8.05,(-10.10%), -411,Leidos Holdings Inc,LDOS,0.034943,92.2,0.21,(0.23%), -412,Seagate Technology Holdings,STX,0.034918,65.71,1.42,(2.20%), -413,Paycom Software Inc,PAYC,0.034914,259.42,2.34,(0.91%), -414,Celanese Corp,CE,0.034212,127.11,3.81,(3.09%), -415,Trimble Inc,TRMB,0.034136,52.22,3.01,(6.12%), -416,Alliant Energy Corp,LNT,0.03411,48.06,-0.49,(-1.02%), -417,Citizens Financial Group,CFG,0.033972,26.28,0.52,(2.00%), -418,International Paper Co,IP,0.033961,35.1,0.15,(0.41%), -419,Masco Corp,MAS,0.033414,54.58,1.37,(2.58%), -420,Nordson Corp,NDSN,0.033057,223.81,3.73,(1.69%), -421,Loews Corp,L,0.032942,64.16,0.36,(0.56%), -422,Evergy Inc,EVRG,0.032792,50.48,-0.58,(-1.13%), -423,Mosaic Co,MOS,0.03266,35.63,0.43,(1.22%), -424,Molson Coors Beverage Co B,TAP,0.032624,62.29,-0.12,(-0.19%), -425,Zebra Technologies Corp Cl A,ZBRA,0.03257,236.95,11.04,(4.89%), -426,Viatris Inc,VTRS,0.032115,9.8,0.21,(2.14%), -427,Live Nation Entertainment In,LYV,0.032035,83.73,2.71,(3.34%), -428,Host Hotels & Resorts Inc,HST,0.03173,16.38,0.34,(2.11%), -429,Insulet Corp,PODD,0.031493,166.19,4.49,(2.77%), -430,Match Group Inc,MTCH,0.031269,40.07,0.09,(0.23%), -431,Interpublic Group of Cos Inc,IPG,0.031184,29.12,0.39,(1.35%), -432,Hormel Foods Corp,HRL,0.030887,38.15,-0.19,(-0.48%), -433,Incyte Corp,INCY,0.03067,58.93,-0.18,(-0.30%), -434,Udr Inc,UDR,0.030252,35.67,0.28,(0.79%), -435,Jack Henry & Associates Inc,JKHY,0.030211,150.61,2.17,(1.46%), -436,Kimco Realty Corp,KIM,0.029862,17.73,0.24,(1.34%), -437,Aes Corp,AES,0.029775,15.29,-0.65,(-4.05%), -438,Bio Techne Corp,TECH,0.029742,67.67,0.1,(0.15%), -439,Pentair Plc,PNR,0.029592,65.59,0.87,(1.34%), -440,Rollins Inc,ROL,0.029276,37.64,0.2,(0.52%), -441,Mgm Resorts International,MGM,0.028601,36.76,0.27,(0.74%), -442,Ceridian Hcm Holding Inc,CDAY,0.028589,67.38,0.35,(0.52%), -443,Brown Forman Corp Class B,BF.B,0.028542,56.78,0.14,(0.25%), -444,Nisource Inc,NI,0.028365,24.84,-0.35,(-1.37%), -445,Gen Digital Inc,GEN,0.028124,17.83,-0.07,(-0.37%), -446,C.H. Robinson Worldwide Inc,CHRW,0.028048,86.31,0.02,(0.02%), -447,Camden Property Trust,CPT,0.027984,94.56,-0.32,(-0.34%), -448,Charles River Laboratories,CRL,0.027736,195.69,0.75,(0.38%), -449,Healthpeak Properties Inc,PEAK,0.027617,18.15,0.1,(0.58%), -450,Caesars Entertainment Inc,CZR,0.027217,47.52,1.54,(3.36%), -451,Regency Centers Corp,REG,0.027131,59.98,0.85,(1.43%), -452,Keycorp,KEY,0.0269,10.52,0.22,(2.09%), -453,Henry Schein Inc,HSIC,0.026715,73.88,0.62,(0.84%), -454,Globe Life Inc,GL,0.026574,110.04,0.61,(0.56%), -455,Borgwarner Inc,BWA,0.026416,40.72,0.92,(2.31%), -456,F5 Inc,FFIV,0.026087,160.33,2.74,(1.74%), -457,Qorvo Inc,QRVO,0.025849,96.39,1.83,(1.93%), -458,Teleflex Inc,TFX,0.025796,199.42,2.91,(1.48%), -459,Allegion Plc,ALLE,0.025545,104.97,1.68,(1.63%), -460,Westrock Co,WRK,0.025292,35.98,0.23,(0.64%), -461,Eastman Chemical Co,EMN,0.025003,76.99,2.35,(3.15%), -462,Wynn Resorts Ltd,WYNN,0.024938,92.21,0,(-0.00%), -463,Nrg Energy Inc,NRG,0.024681,38.55,-0.03,(-0.08%), -464,Juniper Networks Inc,JNPR,0.024655,27.92,0.42,(1.52%), -465,Pinnacle West Capital,PNW,0.02321,73.45,-0.71,(-0.95%), -466,Hasbro Inc,HAS,0.02308,65.23,0.24,(0.37%), -467,Catalent Inc,CTLT,0.023069,45.85,0.07,(0.15%), -468,American Airlines Group Inc,AAL,0.02296,13,0.39,(3.05%), -469,Fmc Corp,FMC,0.022942,66.03,0.02,(0.03%), -470,Campbell Soup Co,CPB,0.022776,41.15,-0.31,(-0.76%), -471,Smith (a.O.) Corp,AOS,0.022769,66.99,1.54,(2.35%), -472,Boston Properties Inc,BXP,0.02269,59.66,0.79,(1.34%), -473,Huntington Ingalls Industrie,HII,0.022502,204.41,1.22,(0.60%), -474,Fox Corp Class A,FOXA,0.021902,31.47,0.55,(1.76%), -475,Robert Half Inc,RHI,0.021872,73.78,0.64,(0.87%), -476,Assurant Inc,AIZ,0.021618,145.63,-0.13,(-0.09%), -477,Universal Health Services B,UHS,0.021551,127,2.8,(2.25%), -478,Etsy Inc,ETSY,0.021257,63.53,1.64,(2.65%), -479,Marketaxess Holdings Inc,MKTX,0.021132,205.89,4.11,(2.04%), -480,News Corp Class A,NWSA,0.0209,20,0.35,(1.76%), -481,Bio Rad Laboratories A,BIO,0.020548,356.1,3.63,(1.03%), -482,Bath & Body Works Inc,BBWI,0.020412,33.19,1.04,(3.23%), -483,Dentsply Sirona Inc,XRAY,0.020079,33.94,-0.17,(-0.51%), -484,Solaredge Technologies Inc,SEDG,0.020026,132.35,4.34,(3.39%), -485,Whirlpool Corp,WHR,0.019812,131.66,1.03,(0.79%), -486,Franklin Resources Inc,BEN,0.019128,24.55,0.28,(1.14%), -487,Generac Holdings Inc,GNRC,0.018958,110.73,1.84,(1.69%), -488,Norwegian Cruise Line Holdin,NCLH,0.018812,16.96,0.67,(4.08%), -489,Federal Realty Invs Trust,FRT,0.018475,91.45,1.05,(1.16%), -490,Tapestry Inc,TPR,0.01809,28.18,0.23,(0.84%), -491,Invesco Ltd,IVZ,0.017835,14.31,0.22,(1.53%), -492,Paramount Global Class B,PARA,0.017208,12.89,0.11,(0.89%), -493,Vf Corp,VFC,0.015631,16.59,-0.32,(-1.89%), -494,Comerica Inc,CMA,0.014638,41.07,1.12,(2.81%), -495,Davita Inc,DVA,0.014395,95.75,0.01,(0.01%), -496,Zions Bancorp Na,ZION,0.013918,33.96,0.79,(2.39%), -497,Ralph Lauren Corp,RL,0.013127,115.52,0.26,(0.22%), -498,Sealed Air Corp,SEE,0.012794,32.2,0.46,(1.46%), -499,Alaska Air Group Inc,ALK,0.012574,37.04,0.63,(1.73%), -500,Mohawk Industries Inc,MHK,0.011998,85.15,1.23,(1.46%), -501,Organon & Co,OGN,0.011665,16.93,0.34,(2.02%), -502,Dxc Technology Co,DXC,0.011658,20.64,0.29,(1.40%), -503,Fox Corp Class B,FOX,0.010545,29.16,0.53,(1.85%), -504,News Corp Class B,NWS,0.006575,20.75,0.36,(1.74%), From 39c2e719e869b037f7de0b32851872a03235507f Mon Sep 17 00:00:00 2001 From: Na Lee Ha Date: Fri, 15 Dec 2023 16:57:28 +0000 Subject: [PATCH 32/38] #1052 test cleanup --- .../basket/BasketMutateOffMarketTest.scala | 87 +++++++++---------- .../finos/vuu/csv/CsvStaticLoaderTests.scala | 7 +- 2 files changed, 44 insertions(+), 50 deletions(-) diff --git a/example/basket/src/test/scala/org/finos/vuu/core/module/basket/BasketMutateOffMarketTest.scala b/example/basket/src/test/scala/org/finos/vuu/core/module/basket/BasketMutateOffMarketTest.scala index 666091a19..c54e31162 100644 --- a/example/basket/src/test/scala/org/finos/vuu/core/module/basket/BasketMutateOffMarketTest.scala +++ b/example/basket/src/test/scala/org/finos/vuu/core/module/basket/BasketMutateOffMarketTest.scala @@ -188,50 +188,49 @@ class BasketMutateOffMarketTest extends VuuServerTestCase { } //TODO join table cannot be tested currently as it doesnt get updated when underlying table gets updated -// Scenario("Adding new constituents by ric should add it to basket trading") { -// import BasketModule._ -// implicit val clock: Clock = new TestFriendlyClock(10001L) -// implicit val lifecycle: LifecycleContainer = new LifecycleContainer() -// implicit val tableDefContainer: TableDefContainer = new TableDefContainer(Map()) -// implicit val metricsProvider: MetricsProvider = new MetricsProviderImpl -// -// val omsApi = OmsApi() -// withVuuServer(PriceModule(), BasketModule(omsApi)) { -// vuuServer => -// -// vuuServer.login("testUser", "testToken2") -// -// GivenBasketTradeExist(vuuServer, ".FTSE", "MyCustomBasket") -// val basketTradeInstanceId = BasketTradeId.current -// -// val vpBasketTrading = vuuServer.createViewPort(BasketModule.NAME, BasketTradingTable) -// val vpBasketTradingCons = vuuServer.createViewPort(BasketModule.NAME, BasketTradingConstituentTable) -// val vpBasketTradingConsJoin = vuuServer.createViewPort(BasketModule.NAME, BasketTradingConstituentJoin) -// val basketTradingConstituentJoinService = vuuServer.getViewPortRpcServiceProxy[BasketTradingConstituentJoinServiceIF](vpBasketTradingConsJoin) -// -// vuuServer.runOnce() -// -// When("we edit the side of the parent basket to same side as current value") -// basketTradingConstituentJoinService.addConstituent("0001.HK")(vuuServer.requestContext) -// vuuServer.runOnce() -// -// Then("get all the updates that have occurred for all view ports from the outbound queue") -// val updates = combineQs(vpBasketTradingConsJoin) -// -// //todo should basketid be where the stock was sourced from? in this case .HSI? -// -// And("assert the basket trading constituent table has added row") -// assertVpEq(filterByVp(vpBasketTradingCons, updates)) { -// Table( -// ("quantity", "side", "instanceId", "instanceIdRic", "basketId", "ric", "description", "notionalUsd", "notionalLocal", "venue", "algo", "algoParams", "pctFilled", "weighting", "priceSpread", "limitPrice", "priceStrategyId", "filledQty", "orderStatus"), -// (10L, "BUY", basketTradeInstanceId, s"$basketTradeInstanceId.BP.L", ".FTSE", "BP.L", "Beyond Petroleum", null, null, null, -1, null, null, 0.1, null, null, 2, 0, "PENDING"), -// (10L, "SELL", basketTradeInstanceId, s"$basketTradeInstanceId.BT.L", ".FTSE", "BT.L", "British Telecom", null, null, null, -1, null, null, 0.1, null, null, 2, 0, "PENDING"), -// (10L, "BUY", basketTradeInstanceId, s"$basketTradeInstanceId.VOD.L", ".FTSE", "VOD.L", "Vodafone", null, null, null, -1, null, null, 0.1, null, null, 2, 0, "PENDING"), -// (10L, "BUY", basketTradeInstanceId, s"$basketTradeInstanceId.0001.HK", ".FTSE", "0001.HK", "", null, null, null, -1, null, null, 0.1, null, null, 2, 0, "PENDING") -// ) -// } -// } -// } + ignore("Adding new constituents by ric should add it to basket trading") { + import BasketModule._ + implicit val clock: Clock = new TestFriendlyClock(10001L) + implicit val lifecycle: LifecycleContainer = new LifecycleContainer() + implicit val tableDefContainer: TableDefContainer = new TableDefContainer(Map()) + implicit val metricsProvider: MetricsProvider = new MetricsProviderImpl + + val omsApi = OmsApi() + withVuuServer(PriceModule(), BasketModule(omsApi)) { + vuuServer => + + vuuServer.login("testUser", "testToken2") + + val basketTradeInstanceId = GivenBasketTradeExist(vuuServer, ".FTSE", "MyCustomBasket") + + val vpBasketTrading = vuuServer.createViewPort(BasketModule.NAME, BasketTradingTable) + val vpBasketTradingCons = vuuServer.createViewPort(BasketModule.NAME, BasketTradingConstituentTable) + val vpBasketTradingConsJoin = vuuServer.createViewPort(BasketModule.NAME, BasketTradingConstituentJoin) + val basketTradingConstituentJoinService = vuuServer.getViewPortRpcServiceProxy[BasketTradingConstituentJoinServiceIF](vpBasketTradingConsJoin) + + vuuServer.runOnce() + + When("we edit the side of the parent basket to same side as current value") + basketTradingConstituentJoinService.addConstituent("0001.HK")(vuuServer.requestContext) + vuuServer.runOnce() + + Then("get all the updates that have occurred for all view ports from the outbound queue") + val updates = combineQs(vpBasketTradingConsJoin) + + //todo should basketid be where the stock was sourced from? in this case .HSI? + + And("assert the basket trading constituent table has added row") + assertVpEq(filterByVp(vpBasketTradingCons, updates)) { + Table( + ("quantity", "side", "instanceId", "instanceIdRic", "basketId", "ric", "description", "notionalUsd", "notionalLocal", "venue", "algo", "algoParams", "pctFilled", "weighting", "priceSpread", "limitPrice", "priceStrategyId", "filledQty", "orderStatus"), + (10L, "BUY", basketTradeInstanceId, s"$basketTradeInstanceId.BP.L", ".FTSE", "BP.L", "Beyond Petroleum", null, null, null, -1, null, null, 0.1, null, null, 2, 0, "PENDING"), + (10L, "SELL", basketTradeInstanceId, s"$basketTradeInstanceId.BT.L", ".FTSE", "BT.L", "British Telecom", null, null, null, -1, null, null, 0.1, null, null, 2, 0, "PENDING"), + (10L, "BUY", basketTradeInstanceId, s"$basketTradeInstanceId.VOD.L", ".FTSE", "VOD.L", "Vodafone", null, null, null, -1, null, null, 0.1, null, null, 2, 0, "PENDING"), + (10L, "BUY", basketTradeInstanceId, s"$basketTradeInstanceId.0001.HK", ".FTSE", "0001.HK", "", null, null, null, -1, null, null, 0.1, null, null, 2, 0, "PENDING") + ) + } + } + } } def GivenBasketTradeExist(vuuServer: TestVuuServer, basketId: String, basketTradeName: String): String = { diff --git a/example/basket/src/test/scala/org/finos/vuu/csv/CsvStaticLoaderTests.scala b/example/basket/src/test/scala/org/finos/vuu/csv/CsvStaticLoaderTests.scala index 03609aae7..e2d6ed5d0 100644 --- a/example/basket/src/test/scala/org/finos/vuu/csv/CsvStaticLoaderTests.scala +++ b/example/basket/src/test/scala/org/finos/vuu/csv/CsvStaticLoaderTests.scala @@ -10,12 +10,7 @@ class CsvStaticLoaderTests extends AnyFeatureSpec{ Feature("CSV loading Test Case") { Scenario("Can successfully load and parse basket constituents") { - var path = getClass.getResource("/constituents") - //his.class.getResourceAsStream("/myfile") - var x = ClassLoader.getSystemResource("") -// var x = Source.fromURL(path) -// var B = Source.fromResource("/static") - val testResourcePath = this.getClass().getResource("/constituents").getPath + val testResourcePath = this.getClass.getResource("/constituents").getPath val constituents = CsvStaticLoader.loadConstituent(".FTSE100", Some(testResourcePath)) assert(constituents.length == 3) From cddecb2414bb707a646114cdca713459ab4de9a0 Mon Sep 17 00:00:00 2001 From: Na Lee Ha Date: Mon, 18 Dec 2023 13:40:49 +0000 Subject: [PATCH 33/38] #1052 refactored to separated generic file reader vs basket specific logic --- .../core/module/basket/csv/BasketLoader.scala | 56 +++++++++++++++++ .../core/module/basket/csv/CsvContent.scala | 17 +++++ .../core/module/basket/csv/FileLoader.scala | 31 +++++++++ .../org/finos/vuu/csv/BasketLoaderTests.scala | 63 +++++++++++++++++++ 4 files changed, 167 insertions(+) create mode 100644 example/basket/src/main/scala/org/finos/vuu/core/module/basket/csv/BasketLoader.scala create mode 100644 example/basket/src/main/scala/org/finos/vuu/core/module/basket/csv/CsvContent.scala create mode 100644 example/basket/src/main/scala/org/finos/vuu/core/module/basket/csv/FileLoader.scala create mode 100644 example/basket/src/test/scala/org/finos/vuu/csv/BasketLoaderTests.scala diff --git a/example/basket/src/main/scala/org/finos/vuu/core/module/basket/csv/BasketLoader.scala b/example/basket/src/main/scala/org/finos/vuu/core/module/basket/csv/BasketLoader.scala new file mode 100644 index 000000000..5b1984c76 --- /dev/null +++ b/example/basket/src/main/scala/org/finos/vuu/core/module/basket/csv/BasketLoader.scala @@ -0,0 +1,56 @@ +package org.finos.vuu.core.module.basket.csv + +import com.typesafe.scalalogging.StrictLogging + +import scala.util.control.NonFatal + +class BasketLoader(resourcePath: Option[String] = None) extends StrictLogging { + def loadBasketIds(): Array[String] = { + FileLoader.getFileNames(getPath(resourcePath), ".csv") + .map(fileName => "." + fileName.replace(".csv", "").toUpperCase) + } + + def loadConstituents(basketId: String): Array[Map[String, Any]] = { + try { + val csvFiles = FileLoader.getFiles(getPath(resourcePath), getBasketFileName(basketId)) + + if (csvFiles.isEmpty) { + logger.error(s"Failed to find constituents file for $basketId") + Array.empty + } + else { + val csvFile = csvFiles(0) + logger.info("Loading basket static:" + basketId + "(" + csvFile + ")") + val csvContent = FileLoader.readCsvContent(csvFile) + + logger.info(s"Found ${csvContent.dataRows.length} constituents for basket $basketId") + + csvContent.dataRows.map(row => toConstituent(csvContent, row)) + } + } + catch { + case NonFatal(t) => logger.error(s"Failed to parse constituents for $basketId", t) + Array.empty + } + } + + private def toConstituent(csvContent: CsvContent, row: Array[String]) = { + Map[String, Any]( + "Symbol" -> csvContent.getValue("Symbol", row), + "Last Trade" -> csvContent.getValue("Last Trade", row), + "Name" -> csvContent.getValue("Name", row), + "Weighting" -> csvContent.getValueAsDouble("Weighting", row, 0.0D), + "Volume" -> csvContent.getValue("Volume", row), + "Change" -> csvContent.getValue("Change", row) + ) + } + + private def getBasketFileName(basketId: String) = { + basketId.replace(".", "").toLowerCase + ".csv" + } + + private def getPath(resourcePath: Option[String] = None): String = { + if (resourcePath.isDefined) resourcePath.get + else getClass.getResource("/static").getPath + } +} diff --git a/example/basket/src/main/scala/org/finos/vuu/core/module/basket/csv/CsvContent.scala b/example/basket/src/main/scala/org/finos/vuu/core/module/basket/csv/CsvContent.scala new file mode 100644 index 000000000..f589b7776 --- /dev/null +++ b/example/basket/src/main/scala/org/finos/vuu/core/module/basket/csv/CsvContent.scala @@ -0,0 +1,17 @@ +package org.finos.vuu.core.module.basket.csv + +class CsvContent(data: Array[Array[String]]) { + + private val header = data(0) + val dataRows: Array[Array[String]] = data.tail + + def getValue(headerName: String, row: Array[String]) = { + val index = header.indexOf(headerName) + if (row.length > index && index > -1) row(index) else null + } + + def getValueAsDouble(headerName: String, row: Array[String], defaultValue: Double) = { + val x = getValue(headerName, row) + if (x == null) defaultValue else x.toDouble + } +} diff --git a/example/basket/src/main/scala/org/finos/vuu/core/module/basket/csv/FileLoader.scala b/example/basket/src/main/scala/org/finos/vuu/core/module/basket/csv/FileLoader.scala new file mode 100644 index 000000000..028ccd3f8 --- /dev/null +++ b/example/basket/src/main/scala/org/finos/vuu/core/module/basket/csv/FileLoader.scala @@ -0,0 +1,31 @@ +package org.finos.vuu.core.module.basket.csv + +import java.io.File +import scala.io.Source + +object FileLoader { + def getFileNames(folderPath: String, extensionFilter: String): Array[String] = { + getFiles(folderPath) + .filter(_.getName.endsWith(extensionFilter)) + .map(file => file.getName) + } + + def getFiles(folderPath: String, fileName: String): Array[File] = { + getFiles(folderPath) + .filter(_.getName.equals(fileName)) + } + + def readCsvContent(file: File): CsvContent = { + val bufferedSource = Source.fromFile(file) + val csv = for (line <- bufferedSource.getLines) yield line.split(",").map(_.trim) + val array = csv.toArray + bufferedSource.close + new CsvContent(array) + } + + private def getFiles(folderPath: String): Array[File] = { + val dir = new File(folderPath) + if (dir.listFiles == null) Array.empty + else dir.listFiles.filter(_.isFile) + } +} diff --git a/example/basket/src/test/scala/org/finos/vuu/csv/BasketLoaderTests.scala b/example/basket/src/test/scala/org/finos/vuu/csv/BasketLoaderTests.scala new file mode 100644 index 000000000..41a0dd780 --- /dev/null +++ b/example/basket/src/test/scala/org/finos/vuu/csv/BasketLoaderTests.scala @@ -0,0 +1,63 @@ +package org.finos.vuu.csv + +import org.finos.vuu.core.module.basket.csv.BasketLoader +import org.scalatest.featurespec.AnyFeatureSpec +class BasketLoaderTests extends AnyFeatureSpec { + + Feature("Basket ids loading Test Case") { + + Scenario("Can successfully get basket ids from files") { + val testResourcePath = this.getClass.getResource("/constituents").getPath + val basketLoader = new BasketLoader(Some(testResourcePath)) + val basketIds = basketLoader.loadBasketIds() + + assert(basketIds.length == 2) + assert(basketIds.contains(".FTSE100")) + assert(basketIds.contains(".FTSEWITHERROR")) + } + + Scenario("when no file found return empty") { + val testResourcePath = this.getClass.getResource("/constituents").getPath + "/doesNotExist" + val basketLoader = new BasketLoader(Some(testResourcePath)) + val basketIds = basketLoader.loadBasketIds() + + assert(basketIds.length == 0) + } + } + + Feature("Basket constituent loading Test Case") { + + val testResourcePath = this.getClass.getResource("/constituents").getPath + val basketLoader = new BasketLoader(Some(testResourcePath)) + + Scenario("Can successfully load and parse basket constituents") { + + val constituents = basketLoader.loadConstituents(".FTSE100") + + assert(constituents.length == 3) + val firstRow = constituents.head + assert(firstRow("Symbol") == "AAL.L") + assert(firstRow("Last Trade") == "436.35") + assert(firstRow("Name") == "Anglo American PLC") + assert(firstRow("Weighting") == 0.0278736825813547) + assert(firstRow("Volume") == "5799089") + assert(firstRow("Change") == "5.35") + } + + Scenario("When parsing basket constituents fails return empty") { + + val constituents = basketLoader.loadConstituents(".FTSEWithError") + + assert(constituents.length == 0) + } + + + Scenario("When no matching basket constituents file return empty") { + + val constituents = basketLoader.loadConstituents(".NoSuchFile") + + assert(constituents.length == 0) + } + + } +} \ No newline at end of file From 166d52a254e3760516df83e79e2db4e3341849cc Mon Sep 17 00:00:00 2001 From: Na Lee Ha Date: Mon, 18 Dec 2023 13:53:00 +0000 Subject: [PATCH 34/38] #1052 using the new basket provider and deleting old csv static loader --- .../module/basket/csv/CsvStaticLoader.scala | 117 ------------------ .../provider/BasketConstituentProvider.scala | 7 +- .../basket/provider/BasketProvider.scala | 7 +- .../finos/vuu/csv/CsvStaticLoaderTests.scala | 42 ------- 4 files changed, 7 insertions(+), 166 deletions(-) delete mode 100644 example/basket/src/main/scala/org/finos/vuu/core/module/basket/csv/CsvStaticLoader.scala delete mode 100644 example/basket/src/test/scala/org/finos/vuu/csv/CsvStaticLoaderTests.scala diff --git a/example/basket/src/main/scala/org/finos/vuu/core/module/basket/csv/CsvStaticLoader.scala b/example/basket/src/main/scala/org/finos/vuu/core/module/basket/csv/CsvStaticLoader.scala deleted file mode 100644 index 9fef0d572..000000000 --- a/example/basket/src/main/scala/org/finos/vuu/core/module/basket/csv/CsvStaticLoader.scala +++ /dev/null @@ -1,117 +0,0 @@ -package org.finos.vuu.core.module.basket.csv - -import com.typesafe.scalalogging.StrictLogging - -import java.io.File -import scala.io.Source -import scala.util.control.NonFatal - -object CsvStaticLoader extends StrictLogging { - def loadConstituent(basketId: String, resourcePath: Option[String] = None): Array[Map[String, Any]] = { - try { - - val constituentsFilesDirectory = - if(resourcePath.isDefined) resourcePath.get - else getClass.getResource("/static").getPath - - val dir = new File(constituentsFilesDirectory) - val csvFiles = dir.listFiles.filter(_.isFile) - .filter(_.getName.endsWith(basketId.replace(".", "").toLowerCase + ".csv")) - - if (csvFiles.isEmpty) { - logger.error(s"Failed to find constituents file for $basketId") - Array.empty - } - else { - val csvFile = csvFiles(0) - logger.info("Loading basket static:" + basketId + "(" + csvFile + ")") - val rows = readFileContent(csvFile) - logger.info(s"Found ${rows.length} constituents for basket $basketId") - - val header = rows(0) - val symbolInd = header.indexOf("Symbol") - val nameInd = header.indexOf("Name") - val lastTradeInd = header.indexOf("Last Trade") - val volumeInd = header.indexOf("Volume") - val weightInd = header.indexOf("Weighting") - val changeInd = header.indexOf("Change") - - val constituents = rows.tail.map(e => { - val weighting = if (getValueFromIndex(weightInd, e) == null) 0.0D else getValueFromIndex(weightInd, e).toDouble - Map[String, Any]( - "Symbol" -> getValueFromIndex(symbolInd, e), - "Last Trade" -> getValueFromIndex(lastTradeInd, e), - "Name" -> getValueFromIndex(nameInd, e), - "Weighting" -> weighting, - "Volume" -> getValueFromIndex(volumeInd, e), - "Change" -> getValueFromIndex(changeInd, e) - ) - }) - constituents - - } - } - catch { - case NonFatal(t) => logger.error(s"Failed to parse constituents for $basketId", t) - Array.empty - } - } - - - private def readFileContent(csvFile: File): Array[Array[String]] = { - val bufferedSource = Source.fromFile(csvFile) - val csv = for (line <- bufferedSource.getLines) yield line.split(",").map(_.trim) - val array = csv.toArray - bufferedSource.close - array - } - - def load: Array[String] = { - val staticDirPath = getClass.getResource("/static").getPath - val dir = new java.io.File(staticDirPath) - val csvFiles = dir.listFiles.filter(_.isFile) - .filter(_.getName.endsWith(".csv")) - val ids = csvFiles.map(e => "." + e.getName.replace(".csv", "").toUpperCase) - ids - } - - def loadStatic: Map[String, Array[Map[String, String]]] = { - var map: Map[String, Array[Map[String, String]]] = Map() - val staticDirPath = getClass.getResource("/static").getPath - val dir = new java.io.File(staticDirPath) - val csvFiles = dir.listFiles.filter(_.isFile) - .filter(_.getName.endsWith(".csv")) - - csvFiles.foreach(csvFile => { - println(csvFile) - - val bufferedSource = Source.fromFile(csvFile) - val csv = for (line <- bufferedSource.getLines) yield line.split(",").map(_.trim) - val array = csv.toArray - bufferedSource.close - var data: Map[String, String] = Map() - val header = array(0) - val symbolInd = header.indexOf("Symbol") - val nameInd = header.indexOf("Name") - val lastTradeInd = header.indexOf("Last Trade") - val volumeInd = header.indexOf("Volume") - val weightInd = header.indexOf("Weight") - val changeInd = header.indexOf("Change") - val list = array.tail.map(e => Map( - "Symbol" -> getValueFromIndex(symbolInd, e), - "Last Trade" -> getValueFromIndex(lastTradeInd, e), - "Name" -> getValueFromIndex(nameInd, e), - "Weight" -> getValueFromIndex(weightInd, e), - "Volume" -> getValueFromIndex(volumeInd, e), - "Change" -> getValueFromIndex(changeInd, e) - )) - val fileName = csvFile.getName.replace(".csv", "") - map += ("." + fileName.toUpperCase -> list) - }) - map - } - - private def getValueFromIndex(index: Int, e: Array[String]) = { - if (e.length > index && index > -1) e(index) else null - } -} diff --git a/example/basket/src/main/scala/org/finos/vuu/core/module/basket/provider/BasketConstituentProvider.scala b/example/basket/src/main/scala/org/finos/vuu/core/module/basket/provider/BasketConstituentProvider.scala index a87c400ed..eac0cfbab 100644 --- a/example/basket/src/main/scala/org/finos/vuu/core/module/basket/provider/BasketConstituentProvider.scala +++ b/example/basket/src/main/scala/org/finos/vuu/core/module/basket/provider/BasketConstituentProvider.scala @@ -4,25 +4,26 @@ import org.finos.toolbox.lifecycle.LifecycleContainer import org.finos.toolbox.thread.RunOnceLifeCycleRunner import org.finos.toolbox.time.Clock import org.finos.vuu.core.module.basket.BasketConstants -import org.finos.vuu.core.module.basket.csv.CsvStaticLoader +import org.finos.vuu.core.module.basket.csv.BasketLoader import org.finos.vuu.core.table.{DataTable, RowWithData} import org.finos.vuu.provider.DefaultProvider class BasketConstituentProvider(val table: DataTable)(implicit lifecycle: LifecycleContainer, clock: Clock) extends DefaultProvider { private val runner = new RunOnceLifeCycleRunner("BasketConstituentProvider", runOnce) + private val basketLoader = new BasketLoader() lifecycle(this).dependsOn(runner) import org.finos.vuu.core.module.basket.BasketModule.BasketConstituentColumnNames._ def runOnce(): Unit = { - val baskets = CsvStaticLoader.load + val baskets = basketLoader.loadBasketIds() baskets.foreach(basketId => updateBasketConstituents(basketId)) } def updateBasketConstituents(basketId: String): Unit = { - val list = CsvStaticLoader.loadConstituent(basketId) + val list = basketLoader.loadConstituents(basketId) list.foreach(row => { if (row.nonEmpty) { diff --git a/example/basket/src/main/scala/org/finos/vuu/core/module/basket/provider/BasketProvider.scala b/example/basket/src/main/scala/org/finos/vuu/core/module/basket/provider/BasketProvider.scala index 9f087222d..2708b45ac 100644 --- a/example/basket/src/main/scala/org/finos/vuu/core/module/basket/provider/BasketProvider.scala +++ b/example/basket/src/main/scala/org/finos/vuu/core/module/basket/provider/BasketProvider.scala @@ -4,17 +4,18 @@ import org.finos.toolbox.lifecycle.LifecycleContainer import org.finos.toolbox.thread.RunOnceLifeCycleRunner import org.finos.toolbox.time.Clock import org.finos.vuu.core.module.basket.BasketModule.BasketColumnNames._ -import org.finos.vuu.core.module.basket.csv.CsvStaticLoader +import org.finos.vuu.core.module.basket.csv.BasketLoader import org.finos.vuu.core.table.{DataTable, RowWithData} import org.finos.vuu.provider.DefaultProvider class BasketProvider(val table: DataTable)(implicit lifecycle: LifecycleContainer, clock: Clock) extends DefaultProvider { private val runner = new RunOnceLifeCycleRunner("BasketProvider", runOnce) + private val basketLoader = new BasketLoader() lifecycle(this).dependsOn(runner) def runOnce(): Unit = { - val data = CsvStaticLoader.load + val data = basketLoader.loadBasketIds() data.foreach(id => { table.processUpdate(id, RowWithData(id, Map( @@ -23,7 +24,5 @@ class BasketProvider(val table: DataTable)(implicit lifecycle: LifecycleContaine )), clock.now()) }) } - - override val lifecycleId: String = "org.finos.vuu.core.module.basket.provider.BasketProvider" } diff --git a/example/basket/src/test/scala/org/finos/vuu/csv/CsvStaticLoaderTests.scala b/example/basket/src/test/scala/org/finos/vuu/csv/CsvStaticLoaderTests.scala deleted file mode 100644 index e2d6ed5d0..000000000 --- a/example/basket/src/test/scala/org/finos/vuu/csv/CsvStaticLoaderTests.scala +++ /dev/null @@ -1,42 +0,0 @@ -package org.finos.vuu.csv - -import org.finos.vuu.core.module.basket.csv.CsvStaticLoader -import org.scalatest.featurespec.AnyFeatureSpec - -import scala.io.Source - -class CsvStaticLoaderTests extends AnyFeatureSpec{ - - Feature("CSV loading Test Case") { - - Scenario("Can successfully load and parse basket constituents") { - val testResourcePath = this.getClass.getResource("/constituents").getPath - val constituents = CsvStaticLoader.loadConstituent(".FTSE100", Some(testResourcePath)) - - assert(constituents.length == 3) - val firstRow = constituents.head - assert(firstRow("Symbol") == "AAL.L") - assert(firstRow("Last Trade") == "436.35") - assert(firstRow("Name") == "Anglo American PLC") - assert(firstRow("Weighting") == 0.0278736825813547) - assert(firstRow("Volume") == "5799089") - assert(firstRow("Change") == "5.35") - } - - Scenario("When parsing basket constituents fails return empty") { - - val constituents = CsvStaticLoader.loadConstituent(".FTSEWithError") - - assert(constituents.length == 0) - } - - - Scenario("When no matching basket constituents file return empty") { - - val constituents = CsvStaticLoader.loadConstituent(".NoSuchFile") - - assert(constituents.length == 0) - } - - } -} From 8f1d8730cfc3d2a9734f971d460fda73423644fb Mon Sep 17 00:00:00 2001 From: Na Lee Ha Date: Mon, 18 Dec 2023 16:32:25 +0000 Subject: [PATCH 35/38] #1052 handling when static resource is not found --- .../core/module/basket/csv/BasketLoader.scala | 19 +++++++++++++------ .../org/finos/vuu/csv/BasketLoaderTests.scala | 2 +- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/example/basket/src/main/scala/org/finos/vuu/core/module/basket/csv/BasketLoader.scala b/example/basket/src/main/scala/org/finos/vuu/core/module/basket/csv/BasketLoader.scala index 5b1984c76..0708e6e09 100644 --- a/example/basket/src/main/scala/org/finos/vuu/core/module/basket/csv/BasketLoader.scala +++ b/example/basket/src/main/scala/org/finos/vuu/core/module/basket/csv/BasketLoader.scala @@ -12,10 +12,11 @@ class BasketLoader(resourcePath: Option[String] = None) extends StrictLogging { def loadConstituents(basketId: String): Array[Map[String, Any]] = { try { - val csvFiles = FileLoader.getFiles(getPath(resourcePath), getBasketFileName(basketId)) + val filePath = getPath(resourcePath) + val csvFiles = FileLoader.getFiles(filePath, getBasketFileName(basketId)) if (csvFiles.isEmpty) { - logger.error(s"Failed to find constituents file for $basketId") + logger.error(s"Failed to find constituents file for $basketId in $filePath") Array.empty } else { @@ -25,16 +26,16 @@ class BasketLoader(resourcePath: Option[String] = None) extends StrictLogging { logger.info(s"Found ${csvContent.dataRows.length} constituents for basket $basketId") - csvContent.dataRows.map(row => toConstituent(csvContent, row)) + csvContent.dataRows.map(row => toConstituentMap(csvContent, row)) } } catch { - case NonFatal(t) => logger.error(s"Failed to parse constituents for $basketId", t) + case NonFatal(t) => logger.error(s"Failed to get and parse constituents for $basketId", t) Array.empty } } - private def toConstituent(csvContent: CsvContent, row: Array[String]) = { + private def toConstituentMap(csvContent: CsvContent, row: Array[String]) = { Map[String, Any]( "Symbol" -> csvContent.getValue("Symbol", row), "Last Trade" -> csvContent.getValue("Last Trade", row), @@ -51,6 +52,12 @@ class BasketLoader(resourcePath: Option[String] = None) extends StrictLogging { private def getPath(resourcePath: Option[String] = None): String = { if (resourcePath.isDefined) resourcePath.get - else getClass.getResource("/static").getPath + else { + val url = getStaticResourcePath + if (url == null) "" else url.getPath + } } + + private def getStaticResourcePath = + getClass.getResource("/static") } diff --git a/example/basket/src/test/scala/org/finos/vuu/csv/BasketLoaderTests.scala b/example/basket/src/test/scala/org/finos/vuu/csv/BasketLoaderTests.scala index 41a0dd780..2832e7c7b 100644 --- a/example/basket/src/test/scala/org/finos/vuu/csv/BasketLoaderTests.scala +++ b/example/basket/src/test/scala/org/finos/vuu/csv/BasketLoaderTests.scala @@ -16,7 +16,7 @@ class BasketLoaderTests extends AnyFeatureSpec { assert(basketIds.contains(".FTSEWITHERROR")) } - Scenario("when no file found return empty") { + Scenario("When no file found return empty") { val testResourcePath = this.getClass.getResource("/constituents").getPath + "/doesNotExist" val basketLoader = new BasketLoader(Some(testResourcePath)) val basketIds = basketLoader.loadBasketIds() From 45288585749940426bc9273b16d50d52dfe91064 Mon Sep 17 00:00:00 2001 From: Peter Ling Date: Fri, 8 Dec 2023 14:15:14 +0000 Subject: [PATCH 36/38] SLVUU-127: Include username in local storage layout key --- .../src/layout-management/SaveLayoutPanel.tsx | 4 +- .../layout-management/useLayoutManager.tsx | 2 +- .../LocalPersistenceManager.ts | 38 ++++++++++++------- .../RemotePersistenceManager.ts | 7 +++- .../src/examples/Apps/NewTheme.examples.tsx | 2 + 5 files changed, 36 insertions(+), 17 deletions(-) diff --git a/vuu-ui/packages/vuu-shell/src/layout-management/SaveLayoutPanel.tsx b/vuu-ui/packages/vuu-shell/src/layout-management/SaveLayoutPanel.tsx index f6be8c2d7..f8817823c 100644 --- a/vuu-ui/packages/vuu-shell/src/layout-management/SaveLayoutPanel.tsx +++ b/vuu-ui/packages/vuu-shell/src/layout-management/SaveLayoutPanel.tsx @@ -3,6 +3,7 @@ import { takeScreenshot } from "./screenshot-utils"; import { Button, FormField, FormFieldLabel, Input, Text } from "@salt-ds/core"; import { ChangeEvent, useEffect, useMemo, useState } from "react"; import { LayoutMetadataDto } from "./layoutTypes"; +import { getAuthDetailsFromCookies } from "../login"; import "./SaveLayoutPanel.css"; @@ -35,6 +36,7 @@ export const SaveLayoutPanel = (props: SaveLayoutPanelProps) => { const [screenshotErrorMessage, setScreenshotErrorMessage] = useState< string | undefined >(); + const [username] = getAuthDetailsFromCookies(); useEffect(() => { if (componentId) { @@ -53,7 +55,7 @@ export const SaveLayoutPanel = (props: SaveLayoutPanelProps) => { name: layoutName, group, screenshot: screenshot ?? "", - user: "User", + user: username, }); }; diff --git a/vuu-ui/packages/vuu-shell/src/layout-management/useLayoutManager.tsx b/vuu-ui/packages/vuu-shell/src/layout-management/useLayoutManager.tsx index 1048f973a..8b371efdb 100644 --- a/vuu-ui/packages/vuu-shell/src/layout-management/useLayoutManager.tsx +++ b/vuu-ui/packages/vuu-shell/src/layout-management/useLayoutManager.tsx @@ -239,7 +239,7 @@ export const LayoutManagementProvider = ( getPersistenceManager() .loadLayout(id) .then((layoutJson) => { - const { layout: currentLayout } = applicationJSONRef.current; + const { layout: currentLayout } = applicationJSONRef.current; setApplicationLayout({ ...currentLayout, children: (currentLayout.children || []).concat(layoutJson), diff --git a/vuu-ui/packages/vuu-shell/src/persistence-management/LocalPersistenceManager.ts b/vuu-ui/packages/vuu-shell/src/persistence-management/LocalPersistenceManager.ts index 9f7e2f387..b09d8aa66 100644 --- a/vuu-ui/packages/vuu-shell/src/persistence-management/LocalPersistenceManager.ts +++ b/vuu-ui/packages/vuu-shell/src/persistence-management/LocalPersistenceManager.ts @@ -1,5 +1,6 @@ import { ApplicationJSON, LayoutJSON } from "@finos/vuu-layout"; import { getLocalEntity, saveLocalEntity } from "@finos/vuu-filters"; +import { getAuthDetailsFromCookies } from "@finos/vuu-shell"; import { formatDate, getUniqueId } from "@finos/vuu-utils"; import { defaultApplicationJson } from "./defaultApplicationJson"; @@ -11,16 +12,21 @@ import { WithId, } from "../layout-management"; -const metadataSaveLocation = "layouts/metadata"; -const layoutsSaveLocation = "layouts/layouts"; +const baseMetadataSaveLocation = "layouts/metadata"; +const baseLayoutsSaveLocation = "layouts/layouts"; export class LocalPersistenceManager implements PersistenceManager { - #urlKey = "api/vui"; + username: string = getAuthDetailsFromCookies()[0]; + metadataSaveLocation = `${baseMetadataSaveLocation}/${this.username}`; + layoutsSaveLocation = `${baseLayoutsSaveLocation}/${this.username}`; + + #urlKey = `api/vui/${this.username}`; constructor(urlKey?: string) { if (urlKey) { this.#urlKey = urlKey; } } + createLayout( metadata: LayoutMetadataDto, layout: LayoutJSON @@ -103,7 +109,7 @@ export class LocalPersistenceManager implements PersistenceManager { loadMetadata(): Promise { return new Promise((resolve) => { - const metadata = getLocalEntity(metadataSaveLocation); + const metadata = getLocalEntity(this.metadataSaveLocation); resolve(metadata || []); }); } @@ -133,24 +139,27 @@ export class LocalPersistenceManager implements PersistenceManager { }); } - private loadLayouts(): Promise { + loadLayouts: () => Promise = () => { return new Promise((resolve) => { - const layouts = getLocalEntity(layoutsSaveLocation); + const layouts = getLocalEntity(this.layoutsSaveLocation); resolve(layouts || []); }); } - private saveLayoutsWithMetadata( + saveLayoutsWithMetadata: ( + layouts: Layout[], + metadata: LayoutMetadata[] + ) => void = ( layouts: Layout[], metadata: LayoutMetadata[] - ): void { - saveLocalEntity(layoutsSaveLocation, layouts); - saveLocalEntity(metadataSaveLocation, metadata); + ) => { + saveLocalEntity(this.layoutsSaveLocation, layouts); + saveLocalEntity(this.metadataSaveLocation, metadata); } // Ensures that there is exactly one Layout entry and exactly one Metadata // entry in local storage corresponding to the provided ID. - private async validateIds(id: string): Promise { + validateIds: (id: string) => Promise = async (id: string) => { return Promise.all([ this.validateId(id, "metadata").catch((error) => error.message), this.validateId(id, "layout").catch((error) => error.message), @@ -168,10 +177,13 @@ export class LocalPersistenceManager implements PersistenceManager { // Ensures that there is exactly one element (Layout or Metadata) in local // storage corresponding to the provided ID. - private validateId( + validateId: ( id: string, dataType: "metadata" | "layout" - ): Promise { + ) => Promise = ( + id: string, + dataType: "metadata" | "layout" + ) => { return new Promise((resolve, reject) => { const loadFunc = dataType === "metadata" ? this.loadMetadata : this.loadLayouts; diff --git a/vuu-ui/packages/vuu-shell/src/persistence-management/RemotePersistenceManager.ts b/vuu-ui/packages/vuu-shell/src/persistence-management/RemotePersistenceManager.ts index a80e6baf8..e7c908dd3 100644 --- a/vuu-ui/packages/vuu-shell/src/persistence-management/RemotePersistenceManager.ts +++ b/vuu-ui/packages/vuu-shell/src/persistence-management/RemotePersistenceManager.ts @@ -1,3 +1,4 @@ +import { getAuthDetailsFromCookies } from "@finos/vuu-shell"; import { PersistenceManager } from "./PersistenceManager"; import { ApplicationJSON, @@ -15,6 +16,8 @@ export type GetLayoutResponseDto = { definition: LayoutJSON }; export type GetApplicationResponseDto = { definition: ApplicationJSON }; export class RemotePersistenceManager implements PersistenceManager { + username: string = getAuthDetailsFromCookies()[0]; + createLayout( metadata: LayoutMetadataDto, layout: LayoutJSON @@ -139,7 +142,7 @@ export class RemotePersistenceManager implements PersistenceManager { method: "PUT", headers: { "Content-Type": "application/json", - username: "vuu-user", + username: this.username, }, body: JSON.stringify(applicationJSON), }) @@ -160,7 +163,7 @@ export class RemotePersistenceManager implements PersistenceManager { fetch(`${baseURL}/${applicationLayoutsSaveLocation}`, { method: "GET", headers: { - username: "vuu-user", + username: this.username, }, }) .then((response) => { diff --git a/vuu-ui/showcase/src/examples/Apps/NewTheme.examples.tsx b/vuu-ui/showcase/src/examples/Apps/NewTheme.examples.tsx index 1a3d92c22..dbac178c9 100644 --- a/vuu-ui/showcase/src/examples/Apps/NewTheme.examples.tsx +++ b/vuu-ui/showcase/src/examples/Apps/NewTheme.examples.tsx @@ -156,6 +156,8 @@ const ShellWithNewTheme = () => { }; export const ShellWithNewThemeAndLayoutManagement = () => { + document.cookie = `vuu-username=${user.username}`; + return ( From bd6d3260143d5502f9e5f2feaf0251ed394449e4 Mon Sep 17 00:00:00 2001 From: Peter Ling Date: Wed, 13 Dec 2023 14:55:56 +0000 Subject: [PATCH 37/38] SLVUU-127: Fix tests --- .../LocalPersistenceManager.ts | 2 +- .../LocalLayoutPersistenceManager.test.ts | 20 ++++++++++++++----- .../RemoteLayoutPersistenceManager.test.ts | 19 ++++++++++++++---- 3 files changed, 31 insertions(+), 10 deletions(-) diff --git a/vuu-ui/packages/vuu-shell/src/persistence-management/LocalPersistenceManager.ts b/vuu-ui/packages/vuu-shell/src/persistence-management/LocalPersistenceManager.ts index b09d8aa66..be9e8f5fa 100644 --- a/vuu-ui/packages/vuu-shell/src/persistence-management/LocalPersistenceManager.ts +++ b/vuu-ui/packages/vuu-shell/src/persistence-management/LocalPersistenceManager.ts @@ -186,7 +186,7 @@ export class LocalPersistenceManager implements PersistenceManager { ) => { return new Promise((resolve, reject) => { const loadFunc = - dataType === "metadata" ? this.loadMetadata : this.loadLayouts; + dataType === "metadata" ? () => this.loadMetadata() : () => this.loadLayouts(); loadFunc().then((array: WithId[]) => { const count = array.filter((element) => element.id === id).length; diff --git a/vuu-ui/packages/vuu-shell/test/layout-persistence/LocalLayoutPersistenceManager.test.ts b/vuu-ui/packages/vuu-shell/test/layout-persistence/LocalLayoutPersistenceManager.test.ts index f0f681832..01ad5d40a 100644 --- a/vuu-ui/packages/vuu-shell/test/layout-persistence/LocalLayoutPersistenceManager.test.ts +++ b/vuu-ui/packages/vuu-shell/test/layout-persistence/LocalLayoutPersistenceManager.test.ts @@ -27,6 +27,16 @@ vi.mock("@finos/vuu-filters", async () => { }; }); +const username = "vuu user"; + +vi.mock("@finos/vuu-shell", async () => { + return { + getAuthDetailsFromCookies: (): [string, string] => { + return [username, "token"]; + }, + }; +}); + const persistenceManager = new LocalPersistenceManager(); const existingId = "existing_id"; @@ -38,7 +48,7 @@ const existingMetadata: LayoutMetadata = { name: "Existing Layout", group: "Group 1", screenshot: "screenshot", - user: "vuu user", + user: username, created: newDate, }; @@ -51,14 +61,14 @@ const metadataToAdd: LayoutMetadataDto = { name: "New Layout", group: "Group 1", screenshot: "screenshot", - user: "vuu user", + user: username, }; const metadataToUpdate: Omit = { name: "New Layout", group: "Group 1", screenshot: "screenshot", - user: "vuu user", + user: username, created: newDate, }; @@ -66,8 +76,8 @@ const layoutToAdd: LayoutJSON = { type: "t", }; -const metadataSaveLocation = "layouts/metadata"; -const layoutsSaveLocation = "layouts/layouts"; +const metadataSaveLocation = `layouts/metadata/${username}`; +const layoutsSaveLocation = `layouts/layouts/${username}`; afterEach(() => { localStorage.clear(); diff --git a/vuu-ui/packages/vuu-shell/test/layout-persistence/RemoteLayoutPersistenceManager.test.ts b/vuu-ui/packages/vuu-shell/test/layout-persistence/RemoteLayoutPersistenceManager.test.ts index 2068f25ef..68ab36fb6 100644 --- a/vuu-ui/packages/vuu-shell/test/layout-persistence/RemoteLayoutPersistenceManager.test.ts +++ b/vuu-ui/packages/vuu-shell/test/layout-persistence/RemoteLayoutPersistenceManager.test.ts @@ -9,17 +9,28 @@ import { LayoutJSON } from "@finos/vuu-layout"; import { v4 as uuidv4 } from "uuid"; import { expectPromiseRejectsWithError } from "@finos/vuu-utils/test/utils"; -const persistence = new RemotePersistenceManager(); const mockFetch = vi.fn(); global.fetch = mockFetch; +const username = "vuu user"; + +vi.mock("@finos/vuu-shell", async () => { + return { + getAuthDetailsFromCookies: (): [string, string] => { + return [username, "token"]; + }, + }; +}); + +const persistence = new RemotePersistenceManager(); + const metadata: LayoutMetadata = { id: "0001", name: "layout 1", group: "group 1", screenshot: "screenshot", - user: "username", + user: username, created: "01.01.2000", }; @@ -27,7 +38,7 @@ const metadataToAdd: LayoutMetadataDto = { name: "layout 1", group: "group 1", screenshot: "screenshot", - user: "username", + user: username, }; const layout: LayoutJSON = { @@ -44,7 +55,7 @@ type FetchResponse = { statusText?: string; }; -describe("RemoteLayoutPersistenceManager", () => { +describe("RemotePersistenceManager", () => { beforeEach(() => { vi.clearAllMocks(); }); From e7e868fc8b207c354a38968edd599914cb78d877 Mon Sep 17 00:00:00 2001 From: Peter Ling Date: Thu, 14 Dec 2023 17:28:23 +0000 Subject: [PATCH 38/38] SLVUU-127: Refactor arrow function signatures --- .../LocalPersistenceManager.ts | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/vuu-ui/packages/vuu-shell/src/persistence-management/LocalPersistenceManager.ts b/vuu-ui/packages/vuu-shell/src/persistence-management/LocalPersistenceManager.ts index be9e8f5fa..56648dffe 100644 --- a/vuu-ui/packages/vuu-shell/src/persistence-management/LocalPersistenceManager.ts +++ b/vuu-ui/packages/vuu-shell/src/persistence-management/LocalPersistenceManager.ts @@ -139,27 +139,24 @@ export class LocalPersistenceManager implements PersistenceManager { }); } - loadLayouts: () => Promise = () => { + loadLayouts = (): Promise => { return new Promise((resolve) => { const layouts = getLocalEntity(this.layoutsSaveLocation); resolve(layouts || []); }); } - saveLayoutsWithMetadata: ( + saveLayoutsWithMetadata = ( layouts: Layout[], metadata: LayoutMetadata[] - ) => void = ( - layouts: Layout[], - metadata: LayoutMetadata[] - ) => { + ): void => { saveLocalEntity(this.layoutsSaveLocation, layouts); saveLocalEntity(this.metadataSaveLocation, metadata); } // Ensures that there is exactly one Layout entry and exactly one Metadata // entry in local storage corresponding to the provided ID. - validateIds: (id: string) => Promise = async (id: string) => { + validateIds = async (id: string): Promise => { return Promise.all([ this.validateId(id, "metadata").catch((error) => error.message), this.validateId(id, "layout").catch((error) => error.message), @@ -177,13 +174,10 @@ export class LocalPersistenceManager implements PersistenceManager { // Ensures that there is exactly one element (Layout or Metadata) in local // storage corresponding to the provided ID. - validateId: ( - id: string, - dataType: "metadata" | "layout" - ) => Promise = ( + validateId = ( id: string, dataType: "metadata" | "layout" - ) => { + ): Promise => { return new Promise((resolve, reject) => { const loadFunc = dataType === "metadata" ? () => this.loadMetadata() : () => this.loadLayouts();