diff --git a/.env b/.env index 3cf8b61..2303add 100644 --- a/.env +++ b/.env @@ -1 +1 @@ -DAEX_TESSERACT_SERVER=http://localhost:7777 +DAEX_TESSERACT_SERVER=https://datasaudi-pytesseract-dev.datawheel.us/tesseract/ diff --git a/app/index.tsx b/app/index.tsx index 408b8f0..e9e6a9c 100644 --- a/app/index.tsx +++ b/app/index.tsx @@ -60,11 +60,6 @@ function ColorPicker({primaryColor, setPrimaryColor, toggleColorScheme}) { return ( <> - - setOpened(v => !v)}> - - - ); } + +// setOpened(v => !v)}> +// +// diff --git a/package-lock.json b/package-lock.json index d32b564..2e3f536 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,17 +1,19 @@ { "name": "@datawheel/data-explorer", - "version": "0.1.0", + "version": "0.1.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@datawheel/data-explorer", - "version": "0.1.0", + "version": "0.1.1", "dependencies": { "@datawheel/olap-client": "^2.0.0", "@datawheel/use-translation": "^0.2.0", "@reduxjs/toolkit": "^1.9.3", "@tabler/icons-react": "^2.7.0", + "@tanstack/react-query": "^5.51.23", + "@tanstack/react-query-devtools": "^5.51.24", "@types/node": "^20.14.2", "d3plus-format": "^1.1.0", "esbuild-css-modules-plugin": "^3.1.0", @@ -19,6 +21,7 @@ "form-urlencoded": "^6.0.0", "hash-css-selector": "^1.0.0", "iso-639-1": "^2.1.0", + "lodash.debounce": "^4.0.8", "mantine-react-table": "^1.3.0", "match-sorter": "^6.3.4", "postcss-modules": "^6.0.0", @@ -47,6 +50,7 @@ "tsup": "^8.2.4", "typescript": "^5.2.2", "vite": "^5.0.0", + "vite-plugin-dts": "^3.9.1", "wrangler": "^3.59.0" }, "peerDependencies": { @@ -1236,6 +1240,125 @@ "react": ">=16.8.0" } }, + "node_modules/@microsoft/api-extractor": { + "version": "7.43.0", + "resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.43.0.tgz", + "integrity": "sha512-GFhTcJpB+MI6FhvXEI9b2K0snulNLWHqC/BbcJtyNYcKUiw7l3Lgis5ApsYncJ0leALX7/of4XfmXk+maT111w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@microsoft/api-extractor-model": "7.28.13", + "@microsoft/tsdoc": "0.14.2", + "@microsoft/tsdoc-config": "~0.16.1", + "@rushstack/node-core-library": "4.0.2", + "@rushstack/rig-package": "0.5.2", + "@rushstack/terminal": "0.10.0", + "@rushstack/ts-command-line": "4.19.1", + "lodash": "~4.17.15", + "minimatch": "~3.0.3", + "resolve": "~1.22.1", + "semver": "~7.5.4", + "source-map": "~0.6.1", + "typescript": "5.4.2" + }, + "bin": { + "api-extractor": "bin/api-extractor" + } + }, + "node_modules/@microsoft/api-extractor-model": { + "version": "7.28.13", + "resolved": "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.28.13.tgz", + "integrity": "sha512-39v/JyldX4MS9uzHcdfmjjfS6cYGAoXV+io8B5a338pkHiSt+gy2eXQ0Q7cGFJ7quSa1VqqlMdlPrB6sLR/cAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@microsoft/tsdoc": "0.14.2", + "@microsoft/tsdoc-config": "~0.16.1", + "@rushstack/node-core-library": "4.0.2" + } + }, + "node_modules/@microsoft/api-extractor/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@microsoft/api-extractor/node_modules/minimatch": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.8.tgz", + "integrity": "sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@microsoft/api-extractor/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@microsoft/api-extractor/node_modules/typescript": { + "version": "5.4.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.2.tgz", + "integrity": "sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/@microsoft/tsdoc": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.14.2.tgz", + "integrity": "sha512-9b8mPpKrfeGRuhFH5iO1iwCLeIIsV6+H1sRfxbkoGXIyQE2BTsPd9zqSqQJ+pv5sJ/hT5M1zvOFL02MnEezFug==", + "dev": true, + "license": "MIT" + }, + "node_modules/@microsoft/tsdoc-config": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/@microsoft/tsdoc-config/-/tsdoc-config-0.16.2.tgz", + "integrity": "sha512-OGiIzzoBLgWWR0UdRJX98oYO+XKGf7tiK4Zk6tQ/E4IJqGCe7dvkTvgDZV5cFJUzLGDOjeAXrnZoA6QkVySuxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@microsoft/tsdoc": "0.14.2", + "ajv": "~6.12.6", + "jju": "~1.4.0", + "resolve": "~1.19.0" + } + }, + "node_modules/@microsoft/tsdoc-config/node_modules/resolve": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz", + "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.1.0", + "path-parse": "^1.0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -1445,6 +1568,29 @@ } } }, + "node_modules/@rollup/pluginutils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.0.tgz", + "integrity": "sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.20.0", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.20.0.tgz", @@ -1653,6 +1799,98 @@ "win32" ] }, + "node_modules/@rushstack/node-core-library": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-4.0.2.tgz", + "integrity": "sha512-hyES82QVpkfQMeBMteQUnrhASL/KHPhd7iJ8euduwNJG4mu2GSOKybf0rOEjOm1Wz7CwJEUm9y0yD7jg2C1bfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "fs-extra": "~7.0.1", + "import-lazy": "~4.0.0", + "jju": "~1.4.0", + "resolve": "~1.22.1", + "semver": "~7.5.4", + "z-schema": "~5.0.2" + }, + "peerDependencies": { + "@types/node": "*" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@rushstack/rig-package": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@rushstack/rig-package/-/rig-package-0.5.2.tgz", + "integrity": "sha512-mUDecIJeH3yYGZs2a48k+pbhM6JYwWlgjs2Ca5f2n1G2/kgdgP9D/07oglEGf6mRyXEnazhEENeYTSNDRCwdqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve": "~1.22.1", + "strip-json-comments": "~3.1.1" + } + }, + "node_modules/@rushstack/terminal": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@rushstack/terminal/-/terminal-0.10.0.tgz", + "integrity": "sha512-UbELbXnUdc7EKwfH2sb8ChqNgapUOdqcCIdQP4NGxBpTZV2sQyeekuK3zmfQSa/MN+/7b4kBogl2wq0vpkpYGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rushstack/node-core-library": "4.0.2", + "supports-color": "~8.1.1" + }, + "peerDependencies": { + "@types/node": "*" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@rushstack/terminal/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@rushstack/terminal/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/@rushstack/ts-command-line": { + "version": "4.19.1", + "resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.19.1.tgz", + "integrity": "sha512-J7H768dgcpG60d7skZ5uSSwyCZs/S2HrWP1Ds8d1qYAyaaeJmpmmLr9BVw97RjFzmQPOYnoXcKA4GkqDCkduQg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rushstack/terminal": "0.10.0", + "@types/argparse": "1.0.38", + "argparse": "~1.0.9", + "string-argv": "~0.3.1" + } + }, "node_modules/@swc/core": { "version": "1.7.10", "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.7.10.tgz", @@ -1905,6 +2143,59 @@ "url": "https://github.com/sponsors/kentcdodds" } }, + "node_modules/@tanstack/query-core": { + "version": "5.51.24", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.51.24.tgz", + "integrity": "sha512-qtIR0FMHUDIWyIQw87q4C+so7XaN59MsGfWrc6rgi2VTHrVZF3Hd0St2dbpqRetHf6XW5yY5lzTrXpTilPlxUg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/query-devtools": { + "version": "5.51.16", + "resolved": "https://registry.npmjs.org/@tanstack/query-devtools/-/query-devtools-5.51.16.tgz", + "integrity": "sha512-ajwuq4WnkNCMj/Hy3KR8d3RtZ6PSKc1dD2vs2T408MdjgKzQ3klVoL6zDgVO7X+5jlb5zfgcO3thh4ojPhfIaw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/react-query": { + "version": "5.51.24", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.51.24.tgz", + "integrity": "sha512-sW1qRwoCDqOFku67xng4Y5z6NPK1DS347jR4RiX9wFHrmyqpbXgUjPIjT3fodezdJAaSJD/6CvWb0cl05J8zNQ==", + "license": "MIT", + "dependencies": { + "@tanstack/query-core": "5.51.24" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^18.0.0" + } + }, + "node_modules/@tanstack/react-query-devtools": { + "version": "5.51.24", + "resolved": "https://registry.npmjs.org/@tanstack/react-query-devtools/-/react-query-devtools-5.51.24.tgz", + "integrity": "sha512-tuEUUr8+ISdkM+tpYlBq2RsBIQ9RQvlZSGizyn4l3MR0hl3Pv8WBFbmOwzQZ1vtec1fa8DJ09SUgeQG1PnARog==", + "license": "MIT", + "dependencies": { + "@tanstack/query-devtools": "5.51.16" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "@tanstack/react-query": "^5.51.24", + "react": "^18 || ^19" + } + }, "node_modules/@tanstack/react-table": { "version": "8.10.6", "resolved": "https://registry.npmjs.org/@tanstack/react-table/-/react-table-8.10.6.tgz", @@ -1960,6 +2251,13 @@ "url": "https://github.com/sponsors/tannerlinsley" } }, + "node_modules/@types/argparse": { + "version": "1.0.38", + "resolved": "https://registry.npmjs.org/@types/argparse/-/argparse-1.0.38.tgz", + "integrity": "sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/estree": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", @@ -2047,6 +2345,121 @@ "vite": "^4 || ^5" } }, + "node_modules/@volar/language-core": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-1.11.1.tgz", + "integrity": "sha512-dOcNn3i9GgZAcJt43wuaEykSluAuOkQgzni1cuxLxTV0nJKanQztp7FxyswdRILaKH+P2XZMPRp2S4MV/pElCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/source-map": "1.11.1" + } + }, + "node_modules/@volar/source-map": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-1.11.1.tgz", + "integrity": "sha512-hJnOnwZ4+WT5iupLRnuzbULZ42L7BWWPMmruzwtLhJfpDVoZLjNBxHDi2sY2bgZXCKlpU5XcsMFoYrsQmPhfZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "muggle-string": "^0.3.1" + } + }, + "node_modules/@volar/typescript": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-1.11.1.tgz", + "integrity": "sha512-iU+t2mas/4lYierSnoFOeRFQUhAEMgsFuQxoxvwn5EdQopw43j+J27a4lt9LMInx1gLJBC6qL14WYGlgymaSMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/language-core": "1.11.1", + "path-browserify": "^1.0.1" + } + }, + "node_modules/@vue/compiler-core": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.4.38.tgz", + "integrity": "sha512-8IQOTCWnLFqfHzOGm9+P8OPSEDukgg3Huc92qSG49if/xI2SAwLHQO2qaPQbjCWPBcQoO1WYfXfTACUrWV3c5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.24.7", + "@vue/shared": "3.4.38", + "entities": "^4.5.0", + "estree-walker": "^2.0.2", + "source-map-js": "^1.2.0" + } + }, + "node_modules/@vue/compiler-dom": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.4.38.tgz", + "integrity": "sha512-Osc/c7ABsHXTsETLgykcOwIxFktHfGSUDkb05V61rocEfsFDcjDLH/IHJSNJP+/Sv9KeN2Lx1V6McZzlSb9EhQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/compiler-core": "3.4.38", + "@vue/shared": "3.4.38" + } + }, + "node_modules/@vue/language-core": { + "version": "1.8.27", + "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-1.8.27.tgz", + "integrity": "sha512-L8Kc27VdQserNaCUNiSFdDl9LWT24ly8Hpwf1ECy3aFb9m6bDhBGQYOujDm21N7EW3moKIOKEanQwe1q5BK+mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/language-core": "~1.11.1", + "@volar/source-map": "~1.11.1", + "@vue/compiler-dom": "^3.3.0", + "@vue/shared": "^3.3.0", + "computeds": "^0.0.1", + "minimatch": "^9.0.3", + "muggle-string": "^0.3.1", + "path-browserify": "^1.0.1", + "vue-template-compiler": "^2.7.14" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@vue/language-core/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@vue/language-core/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@vue/shared": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.38.tgz", + "integrity": "sha512-q0xCiLkuWWQLzVrecPb0RMsNWyxICOjPrcrwxTUEHb1fsnvni4dcuyG7RT/Ie7VPTvnjzIaWzRMUBsrqNj/hhw==", + "dev": true, + "license": "MIT" + }, "node_modules/acorn": { "version": "8.12.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", @@ -2071,6 +2484,23 @@ "node": ">=0.4.0" } }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, "node_modules/ansi-regex": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", @@ -2113,6 +2543,16 @@ "node": ">= 8" } }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, "node_modules/aria-hidden": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.4.tgz", @@ -2345,6 +2785,20 @@ "node": ">= 10" } }, + "node_modules/computeds": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/computeds/-/computeds-0.0.1.tgz", + "integrity": "sha512-7CEBgcMjVmitjYo5q8JTJVra6X5mQ20uTThdK+0kR7UEaDrAWEQcRiBtWJzga4eRpP6afNwwLsX2SET2JhVB1Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, "node_modules/consola": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/consola/-/consola-3.2.3.tgz", @@ -3137,6 +3591,13 @@ "integrity": "sha512-Rt2g+nTbLlDWZTwwrIXjy9MeiZmSDI375FvZs72ngxx8PDC6YXOeR3q5LAuPzjZQxhiWdRKac7RKV+YyQYfYIg==", "peer": true }, + "node_modules/de-indent": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", + "integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==", + "dev": true, + "license": "MIT" + }, "node_modules/debug": { "version": "4.3.6", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", @@ -3207,6 +3668,19 @@ "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", "dev": true }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -3279,6 +3753,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true, + "license": "MIT" + }, "node_modules/execa": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", @@ -3314,6 +3795,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, "node_modules/fast-glob": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", @@ -3330,6 +3818,13 @@ "node": ">=8.6.0" } }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, "node_modules/fastq": { "version": "1.17.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", @@ -3432,6 +3927,21 @@ "resolved": "https://registry.npmjs.org/form-urlencoded/-/form-urlencoded-6.1.5.tgz", "integrity": "sha512-9EMyy7kvglRcR027EtEPCZ2JYfi1xYFuGTsgVJ+yWmRlhc+dwSCwRIOSCH0cUYCAb0+REe6s8aPqXAG8lYVkZw==" }, + "node_modules/fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -3594,6 +4104,16 @@ "node": ">= 0.4" } }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "license": "MIT", + "bin": { + "he": "bin/he" + } + }, "node_modules/hoist-non-react-statics": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", @@ -3673,6 +4193,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/import-lazy": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz", + "integrity": "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/internmap": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", @@ -3809,6 +4339,13 @@ "@pkgjs/parseargs": "^0.11.0" } }, + "node_modules/jju": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/jju/-/jju-1.4.0.tgz", + "integrity": "sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==", + "dev": true, + "license": "MIT" + }, "node_modules/joycon": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz", @@ -3839,6 +4376,30 @@ "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "license": "MIT", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/kolorist": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/kolorist/-/kolorist-1.8.0.tgz", + "integrity": "sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==", + "dev": true, + "license": "MIT" + }, "node_modules/lightningcss": { "version": "1.26.0", "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.26.0.tgz", @@ -4106,6 +4667,12 @@ "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==" }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "license": "MIT" + }, "node_modules/lodash.sortby": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", @@ -4135,6 +4702,16 @@ "integrity": "sha512-OwQTGyq+57hmefrEv3Uhhyw4Z3l+aT/Q4nkdslVqy2n/7qIa4ML0wKnYcUUo54W1RRJYLdk2xKFsTaDGEVJLDw==", "dev": true }, + "node_modules/magic-string": { + "version": "0.30.11", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.11.tgz", + "integrity": "sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0" + } + }, "node_modules/mantine-react-table": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/mantine-react-table/-/mantine-react-table-1.3.4.tgz", @@ -4298,6 +4875,13 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, + "node_modules/muggle-string": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.3.1.tgz", + "integrity": "sha512-ckmWDJjphvd/FvZawgygcUeQCxzvohjFO5RxTjj4eq8kw359gFF3E1brjfI+viLMxss5JrHTDRHZvu2/tuy0Qg==", + "dev": true, + "license": "MIT" + }, "node_modules/mustache": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", @@ -4435,6 +5019,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "dev": true, + "license": "MIT" + }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -5074,6 +5665,35 @@ "node": ">=10" } }, + "node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -5133,6 +5753,13 @@ "deprecated": "Please use @jridgewell/sourcemap-codec instead", "dev": true }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true, + "license": "BSD-3-Clause" + }, "node_modules/stacktracey": { "version": "2.1.8", "resolved": "https://registry.npmjs.org/stacktracey/-/stacktracey-2.1.8.tgz", @@ -5153,6 +5780,16 @@ "npm": ">=6" } }, + "node_modules/string-argv": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", + "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6.19" + } + }, "node_modules/string-hash": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/string-hash/-/string-hash-1.1.3.tgz", @@ -5601,6 +6238,26 @@ "ufo": "^1.5.3" } }, + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, "node_modules/url-join": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz", @@ -5689,6 +6346,16 @@ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, + "node_modules/validator": { + "version": "13.12.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.12.0.tgz", + "integrity": "sha512-c1Q0mCiPlgdTVVVIJIrBuxNicYE+t/7oKeI9MWLj3fh/uq2Pxh/3eeWbVZ4OcGW1TUf53At0njHw5SMdA3tmMg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, "node_modules/vite": { "version": "5.4.0", "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.0.tgz", @@ -5748,6 +6415,34 @@ } } }, + "node_modules/vite-plugin-dts": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/vite-plugin-dts/-/vite-plugin-dts-3.9.1.tgz", + "integrity": "sha512-rVp2KM9Ue22NGWB8dNtWEr+KekN3rIgz1tWD050QnRGlriUCmaDwa7qA5zDEjbXg5lAXhYMSBJtx3q3hQIJZSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@microsoft/api-extractor": "7.43.0", + "@rollup/pluginutils": "^5.1.0", + "@vue/language-core": "^1.8.27", + "debug": "^4.3.4", + "kolorist": "^1.8.0", + "magic-string": "^0.30.8", + "vue-tsc": "^1.8.27" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "typescript": "*", + "vite": "*" + }, + "peerDependenciesMeta": { + "vite": { + "optional": true + } + } + }, "node_modules/vite/node_modules/@esbuild/aix-ppc64": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", @@ -6154,6 +6849,35 @@ "@esbuild/win32-x64": "0.21.5" } }, + "node_modules/vue-template-compiler": { + "version": "2.7.16", + "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.7.16.tgz", + "integrity": "sha512-AYbUWAJHLGGQM7+cNTELw+KsOG9nl2CnSv467WobS5Cv9uk3wFcnr1Etsz2sEIHEZvw1U+o9mRlEO6QbZvUPGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "de-indent": "^1.0.2", + "he": "^1.2.0" + } + }, + "node_modules/vue-tsc": { + "version": "1.8.27", + "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-1.8.27.tgz", + "integrity": "sha512-WesKCAZCRAbmmhuGl3+VrdWItEvfoFIPXOvUJkjULi+x+6G/Dy69yO3TBRJDr9eUlmsNAwVmxsNZxvHKzbkKdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/typescript": "~1.11.1", + "@vue/language-core": "1.8.27", + "semver": "^7.5.4" + }, + "bin": { + "vue-tsc": "bin/vue-tsc.js" + }, + "peerDependencies": { + "typescript": "*" + } + }, "node_modules/webidl-conversions": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", @@ -6814,6 +7538,13 @@ "integrity": "sha512-ibF0Or+FivM9lNrg+HGJfVX8WJqgo+kCLDc4vx6xMeTce7Aj+DLttKbxxRR/gNLSAelRc1omAPlJ77N/Jem07A==", "dev": true }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, "node_modules/yaml": { "version": "1.10.2", "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", @@ -6844,6 +7575,38 @@ "stacktracey": "^2.1.8" } }, + "node_modules/z-schema": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/z-schema/-/z-schema-5.0.5.tgz", + "integrity": "sha512-D7eujBWkLa3p2sIpJA0d1pr7es+a7m0vFAnZLlCEKq/Ij2k0MLi9Br2UPxoxdYystm5K1yeBGzub0FlYUEWj2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash.get": "^4.4.2", + "lodash.isequal": "^4.5.0", + "validator": "^13.7.0" + }, + "bin": { + "z-schema": "bin/z-schema" + }, + "engines": { + "node": ">=8.0.0" + }, + "optionalDependencies": { + "commander": "^9.4.1" + } + }, + "node_modules/z-schema/node_modules/commander": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": "^12.20.0 || >=14" + } + }, "node_modules/zod": { "version": "3.23.8", "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz", diff --git a/package.json b/package.json index 97380f8..5b270ef 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,8 @@ "@datawheel/use-translation": "^0.2.0", "@reduxjs/toolkit": "^1.9.3", "@tabler/icons-react": "^2.7.0", + "@tanstack/react-query": "^5.51.23", + "@tanstack/react-query-devtools": "^5.51.24", "@types/node": "^20.14.2", "d3plus-format": "^1.1.0", "esbuild-css-modules-plugin": "^3.1.0", @@ -29,6 +31,7 @@ "form-urlencoded": "^6.0.0", "hash-css-selector": "^1.0.0", "iso-639-1": "^2.1.0", + "lodash.debounce": "^4.0.8", "mantine-react-table": "^1.3.0", "match-sorter": "^6.3.4", "postcss-modules": "^6.0.0", @@ -68,6 +71,7 @@ "tsup": "^8.2.4", "typescript": "^5.2.2", "vite": "^5.0.0", + "vite-plugin-dts": "^3.9.1", "wrangler": "^3.59.0" } } \ No newline at end of file diff --git a/prettier.config.js b/prettier.config.cjs similarity index 92% rename from prettier.config.js rename to prettier.config.cjs index 196ad89..cc001e3 100644 --- a/prettier.config.js +++ b/prettier.config.cjs @@ -1,5 +1,4 @@ -process.env.RUNNING_PRETTIER = "false"; - +process.env.RUNNING_PRETTIER = "true"; module.exports = { arrowParens: "avoid", bracketSpacing: false, diff --git a/src/components/AreaCuts.jsx b/src/components/AreaCuts.jsx index 6162620..ff026ad 100644 --- a/src/components/AreaCuts.jsx +++ b/src/components/AreaCuts.jsx @@ -29,24 +29,20 @@ export const AreaCuts = () => { actions.updateCut(cutItem); }, []); - const cutTags = useMemo(() => items.map(item => - - ), [items]); + const cutTags = useMemo(() => items.map(item => ), [items]); - const toolbar = + const toolbar = ( <> - {items.length > 0 && + {items.length > 0 && ( - } - + + )} + - ; + + ); return ( { value="cuts" > - {items.length === 0 && } - title={t("params.error_no_cut_selected_title")} - >{t("params.error_no_cut_selected_detail")}} + {items.length === 0 && ( + } + title={t("params.error_no_cut_selected_title")} + > + {t("params.error_no_cut_selected_detail")} + + )} {cutTags} ); }; + +export {createHandler}; diff --git a/src/components/DrawerMenu.tsx b/src/components/DrawerMenu.tsx new file mode 100644 index 0000000..75e40d2 --- /dev/null +++ b/src/components/DrawerMenu.tsx @@ -0,0 +1,544 @@ +import React, {useMemo, useCallback, useState} from "react"; +import {useDisclosure} from "@mantine/hooks"; +import { + Drawer, + Button, + Group, + NumberInput, + MultiSelect, + ActionIcon, + Menu, + Switch, + Box, + Flex +} from "@mantine/core"; +import {useSelector} from "react-redux"; +import { + selectCutItems, + selectCutMap, + selectDrilldownItems, + selectDrilldownMap, + selectFilterItems, + selectFilterMap, + selectLocale, + selectMeasureMap +} from "../state/queries"; +import {useTranslation} from "../hooks/translation"; +import { + selectOlapMeasureMap, + selectOlapMeasureItems, + selectOlapDimensionItems +} from "../state/selectors"; +import {useActions} from "../hooks/settings"; +import {filterMap} from "../utils/array"; +import { + buildMeasure, + CutItem, + buildCut, + buildDrilldown, + buildFilter, + MeasureItem, + FilterItem +} from "../utils/structs"; +import {isActiveItem} from "../utils/validation"; +import { + IconFilter, + IconFilterOff, + IconMathGreater, + IconMathLower, + IconStack3, + IconSettings, + IconArrowsLeftRight +} from "@tabler/icons-react"; +import type {PlainLevel} from "@datawheel/olap-client"; +import {getCaption} from "../utils/string"; +import {abbreviateFullName} from "../utils/format"; +import {stringifyName} from "../utils/transform"; +import {Comparison} from "@datawheel/olap-client"; +import {getFiltersConditions} from "./TableView"; + +function AddColumnsDrawer() { + const [opened, {open, close}] = useDisclosure(true); + return ( + <> + + + + + + + + + ); +} + +export function DrawerMenu() { + return ( + + + + + ); +} + +function DrillDownOptions() { + const locale = useSelector(selectLocale); + const actions = useActions(); + const selectedDimensions = useSelector(selectDrilldownItems); + const dimensions = useSelector(selectOlapDimensionItems) || []; + + const createCutHandler = React.useCallback((level: PlainLevel) => { + const cutItem = buildCut({...level, key: level.fullName, members: []}); + cutItem.active = false; + actions.updateCut(cutItem); + }, []); + + const createHandler = useCallback( + (level: PlainLevel) => { + // find or create drilldown + const drilldownItem = + selectedDimensions.find(item => item.uniqueName === level.uniqueName) ?? + buildDrilldown({...level}); + createCutHandler(level); + actions.updateDrilldown(drilldownItem); + actions.willFetchMembers({...level, level: level.name}).then(members => { + const dimension = dimensions.find(dim => dim.name === level.dimension); + if (!dimension) return; + actions.updateDrilldown({ + ...drilldownItem, + dimType: dimension.dimensionType, + memberCount: members.length, + members + }); + }); + }, + [dimensions] + ); + + const activeItems = selectedDimensions.filter(i => i.active); + + const options = useMemo( + () => + dimensions.map(dimension => ( + + )), + [dimensions, activeItems, createCutHandler] + ); + + return options; +} + +function DimensionItem({dimension, locale, activeItems}) { + const isChildSubMenu = dimension.hierarchies.length !== 1; + + const options = dimension.hierarchies.map(hie => ( + + )); + + if (!isChildSubMenu) { + return options[0]; + } + + return options; +} + +function HierarchyItem({dimension, hierarchy, isSubMenu, locale, activeItems}) { + const {translate: t} = useTranslation(); + + const label = useMemo(() => { + const captions = [getCaption(dimension, locale), getCaption(hierarchy, locale)]; + if (isSubMenu) { + return captions[1]; + } + return t("params.dimmenu_hierarchy", { + abbr: abbreviateFullName(captions, t("params.dimmenu_abbrjoint")), + dimension: captions[0], + hierarchy: captions[1] + }); + }, [locale, dimension, hierarchy, isSubMenu]); + + const isChildSubMenu = hierarchy.levels.length !== 1; + + const options = hierarchy.levels.map(lvl => ( + + )); + + if (!isChildSubMenu) { + return options[0]; + } + + return options; +} + +function LevelItem({dimension, hierarchy, isSubMenu, level, locale, activeItems}) { + const [activeFilter, setActiveFilter] = useState(false); + const {translate: t} = useTranslation(); + const actions = useActions(); + const cutItems = useSelector(selectCutItems); + const dimensions = useSelector(selectOlapDimensionItems); + const drilldowns = useSelector(selectDrilldownMap); + + const label = useMemo(() => { + const captions = [ + getCaption(dimension, locale), + getCaption(hierarchy, locale), + getCaption(level, locale) + ]; + if (isSubMenu) { + return captions[2]; + } + return t("params.dimmenu_level", { + abbr: abbreviateFullName(captions, t("params.dimmenu_abbrjoint")), + dimension: captions[0], + hierarchy: captions[1], + level: captions[2] + }); + }, [locale, dimension, hierarchy, level, isSubMenu]); + + const createCutHandler = React.useCallback((level: PlainLevel) => { + const cutItem = buildCut({...level, members: [], key: level.fullName}); + cutItem.active = false; + actions.updateCut(cutItem); + }, []); + + function createDrilldown(level: PlainLevel, cuts: CutItem[]) { + const drilldown = buildDrilldown({...level, key: stringifyName(level), active: false}); + actions.updateDrilldown(drilldown); + const cut = cuts.find(cut => cut.uniqueName === drilldown.uniqueName); + if (!cut) { + createCutHandler({...level, key: stringifyName(level)}); + } + + actions.willFetchMembers({...level, level: level.name}).then(members => { + const dimension = dimensions.find(dim => dim.name === level.dimension); + if (!dimension) return; + actions.updateDrilldown({ + ...drilldown, + dimType: dimension.dimensionType, + memberCount: members.length, + members + }); + }); + + return drilldown; + } + + const currentDrilldown = drilldowns[stringifyName(level)] || createDrilldown(level, cutItems); + + const cut = cutItems.find(cut => { + return cut.uniqueName === currentDrilldown.uniqueName; + }); + + const updatecutHandler = React.useCallback((item: CutItem, members: string[]) => { + actions.updateCut({...item, members}); + }, []); + + const checked = activeItems.map(stringifyName).includes(stringifyName(level)); + return ( + <> + + { + if (cut) { + const active = checked ? false : cut.members.length ? true : false; + actions.updateCut({...cut, active}); + } + actions.updateDrilldown({...currentDrilldown, active: !currentDrilldown.active}); + }} + checked={checked} + label={label} + /> + + setActiveFilter(value => !value)}> + {activeFilter ? : } + + + {activeFilter && ( + + { + if (cut) { + if (currentDrilldown.active && !cut.active) { + updatecutHandler({...cut, active: true}, value); + } else { + updatecutHandler(cut, value); + } + } + }} + placeholder={`Filter by ${label}`} + value={cut?.members || []} + data={currentDrilldown.members.map(m => ({ + value: String(m.key), + label: m.caption ? `${m.caption} ${m.key}` : m.name + }))} + clearable + nothingFound="Nothing found" + /> + + )} + + ); +} + +export function getFilterfnText(type) { + switch (type) { + case "greaterThan": + return "Greater Than"; + case "lessThan": + return "Less Than"; + case "between": + return "Between"; + default: + return "Not Found"; + } +} + +export function getFilterFn(filter: FilterItem) { + if (filter.conditionOne && filter.conditionTwo) { + if (filter.conditionOne[0] === Comparison.GTE && filter.conditionTwo[0] === Comparison.LTE) { + return "between"; + } + } + if (filter.conditionOne[0] === Comparison.GTE || filter.conditionOne[0] === Comparison.GT) { + return "greaterThan"; + } + if (filter.conditionOne[0] === Comparison.LTE) { + return "lessThan"; + } +} + +export function getFilterValue(filter: FilterItem) { + const filterFn = getFilterFn(filter); + const isBetween = filterFn === "between"; + if (isBetween && filter.conditionTwo) { + return [filter.conditionOne[2], filter.conditionTwo[2]]; + } + return filter.conditionOne[2]; +} + +function isNotValid(value) { + return value === null || value === undefined || Number.isNaN(value); +} + +export function NumberInputComponent({text, filter}: {text: string; filter: FilterItem}) { + const actions = useActions(); + + function getFilterValue(filter: FilterItem) { + return isNotValid(filter.conditionOne[2]) || filter.conditionOne[2] === 0 + ? "" + : filter.conditionOne[2]; + } + + function onInputChange({filter, value}: {filter: FilterItem; value: number | ""}) { + const isEmpty = value === ""; + const conditions = + getFiltersConditions(getFilterFn(filter) || "greaterThan", [Number(value)]) || {}; + const active = isEmpty ? false : true; + actions.updateFilter(buildFilter({...filter, active, ...conditions})); + } + + return ( + onInputChange({filter, value})} + sx={{flex: "1 1 auto"}} + /> + ); +} + +export function MinMax({filter, ...rest}: {filter: FilterItem}) { + const actions = useActions(); + + function onInputChangeMinMax(props: {filter: FilterItem; min: number | ""; max: number | ""}) { + const {filter, min, max} = props; + const conditions = + getFiltersConditions(getFilterFn(filter) || "greaterThan", [Number(min), Number(max)]) || {}; + const active = Boolean(min) && Boolean(max); + + actions.updateFilter(buildFilter({...filter, active, ...conditions})); + } + + function getFilterValue(condition?: [`${Comparison}`, string, number]) { + if (condition) { + return isNotValid(condition[2]) || condition[2] === 0 ? "" : condition[2]; + } + return ""; + } + + const min = getFilterValue(filter.conditionOne); + const max = getFilterValue(filter.conditionTwo); + return ( + + onInputChangeMinMax({filter, min: value, max})} + {...rest} + /> + onInputChangeMinMax({filter, min, max: value})} + {...rest} + /> + + ); +} + +export function FilterFnsMenu({filter}: {filter: FilterItem}) { + const actions = useActions(); + + return ( + <> + + + + + + + + Filter Mode + } + onClick={() => { + const conditions = getFiltersConditions("greaterThan", [0]) || {}; + actions.updateFilter(buildFilter({...filter, ...conditions, active: false})); + }} + > + Greater Than + + } + onClick={() => { + const conditions = getFiltersConditions("lessThan", [0]) || {}; + actions.updateFilter(buildFilter({...filter, ...conditions, active: false})); + }} + > + Less Than + + } + onClick={() => { + const conditions = getFiltersConditions("between", [0, 0]) || {}; + actions.updateFilter(buildFilter({...filter, ...conditions, active: false})); + }} + > + Between + + + + + ); +} + +function MeasuresOptions() { + // param measures + const [activeFilter, setActiveFilter] = useState(false); + const {code: locale} = useSelector(selectLocale); + const itemMap = useSelector(selectMeasureMap); + const filtersMap = useSelector(selectFilterMap); + const filtersItems = useSelector(selectFilterItems); + // server + const measureMap = useSelector(selectOlapMeasureMap); + const measures = useSelector(selectOlapMeasureItems); + //actions + const actions = useActions(); + + function handlerCreateMeasure(data: MeasureItem) { + const measure = buildMeasure(data); + actions.updateMeasure(measure); + return measure; + } + function handlerCreateFilter(data: FilterItem) { + const filter = buildFilter(data); + actions.updateFilter(filter); + return filter; + } + + const filteredItems = useMemo(() => { + return filterMap(measures, (m: MeasureItem) => { + const measure = itemMap[m.name] || handlerCreateMeasure({...m, active: false}); + const foundFilter = filtersMap[m.name] || filtersItems.find(f => f.measure === measure.name); + + const filter = + foundFilter || + handlerCreateFilter({ + measure: measure.name, + active: false, + key: measure.name + } as FilterItem); + return {measure, filter}; + }); + }, [itemMap, measures, filtersMap, filtersItems, locale]); + + const activeItems = filteredItems.filter(f => isActiveItem(f.measure)); + + const options = filteredItems.map(({measure, filter}) => { + const filterFn = getFilterFn(filter); + const text = getFilterfnText(filterFn); + const isBetween = filterFn === "between"; + const checked = activeItems.map(active => active.measure.name).includes(measure.name); + return ( + + + { + actions.updateMeasure({...measure, active: !measure.active}); + actions.updateFilter({...filter, active: checked ? false : true}); + }} + checked={checked} + label={measure.name} + /> + + + setActiveFilter(value => !value)}> + {activeFilter ? : } + + + + {activeFilter && ( + + {isBetween ? ( + + ) : ( + + )} + + )} + + ); + }); + + return options; +} + +export default AddColumnsDrawer; diff --git a/src/components/ExplorerContent.tsx b/src/components/ExplorerContent.tsx index 922d245..dd83f78 100644 --- a/src/components/ExplorerContent.tsx +++ b/src/components/ExplorerContent.tsx @@ -1,13 +1,7 @@ import React, {useState, useEffect, useMemo} from "react"; import {ServerConfig} from "@datawheel/olap-client"; import {TranslationContextProps} from "@datawheel/use-translation"; -import { - CSSObject, - Center, - createStyles, - Header, - useMantineTheme -} from "@mantine/core"; +import {CSSObject, Center, createStyles, Header, useMantineTheme} from "@mantine/core"; import {useSelector} from "react-redux"; import {useSetup} from "../hooks/setup"; import {useTranslation} from "../hooks/translation"; @@ -18,7 +12,7 @@ import {ExplorerResults} from "./ExplorerResults"; import SideBar, {SideBarProvider, SideBarItem} from "./SideBar"; import ParamsExplorer from "./ParamsExplorer"; import {HomeSVG} from "./icons"; - +import {AppProviders} from "../context"; const useStyles = createStyles((theme, params: {height: CSSObject["height"]}) => ({ container: { height: "100%", @@ -30,17 +24,16 @@ const useStyles = createStyles((theme, params: {height: CSSObject["height"]}) => root: { display: "flex", flexFlow: "column nowrap", - height: "calc(100% - 50px)", + height: "calc(100% - 70px)", [theme.fn.largerThan("md")]: { flexDirection: "row" // height: params.height, // width: "100%" } }, - flexCol: { flex: "1 1 auto", - height: "calc(100vh - 50px)", + height: "calc(100vh - 70px)", [theme.fn.largerThan("md")]: { width: 0 } @@ -91,37 +84,17 @@ export function ExplorerContent(props: {
- - - - - - - - - {/* */} - + + + + + + + + + +
); - - // return ( - //
- - // - // {isSetupDone && serverState.online && props.withMultiQuery - // ? - // : null - // } - // {isSetupDone && serverState.online - // ? - // : null - // } - // - //
- // ); } diff --git a/src/components/ExplorerParams.tsx b/src/components/ExplorerParams.tsx index 5aa5cb5..ce6935e 100644 --- a/src/components/ExplorerParams.tsx +++ b/src/components/ExplorerParams.tsx @@ -10,7 +10,7 @@ import {ButtonExecuteQuery} from "./ButtonExecuteQuery"; import {CollapsiblePanel} from "./Layout/CollapsiblePanel"; import {PreviewModeSwitch} from "./PreviewModeSwitch"; import {SelectCube} from "./SelectCube"; -import {SelectLocale} from "./LocaleSelector"; +// import {SelectLocale} from "./LocaleSelector"; /** Defines which panel will be opened by default on the first load. */ export const ExplorerParams = (props: {defaultOpen: string}) => { @@ -18,7 +18,7 @@ export const ExplorerParams = (props: {defaultOpen: string}) => { return ( - + {/* */} ({ container: { @@ -46,9 +47,7 @@ export function ExplorerResults(props: { }) { const cube = useSelector(selectOlapCube); const serverStatus = useSelector(selectServerState); - const {isDirty, params, result} = useSelector(selectCurrentQueryItem); - - const {loading: isLoading} = useSelector(selectLoadingState); + const {params, result} = useSelector(selectCurrentQueryItem); const {online: isServerOnline, url: serverUrl} = serverStatus; const {data, error} = result; @@ -92,7 +91,8 @@ export function ExplorerResults(props: { // or the user changed parameters since last query // check is loading // use set loading when seraching members. - if (isServerOnline == null || !cube || isDirty || isLoading) { + + if (isServerOnline == null || !cube) { return ( } - title={t("results.error_emptyresult_title")} - description={t("results.error_emptyresult_detail")} - /> - ); - } + // if (data.length === 0) { + // return ( + // } + // title={t("results.error_emptyresult_title")} + // description={t("results.error_emptyresult_detail")} + // /> + // ); + // } return ( ({ alignItems: "center", - background: t.colorScheme === "dark" ? t.colors.dark[7]: t.colors.gray[1], + background: t.colorScheme === "dark" ? t.colors.dark[7] : t.colors.gray[1], justifyContent: "space-between" })} - w="100%"> + w="100%" + > {/* need to update this logic */} {(!queryItem.panel || queryItem.panel === "table") && ( - + + )} @@ -241,20 +243,22 @@ function SuccessResult(props: { - + + {/* */} - ); } diff --git a/src/components/LoadingOverlay.jsx b/src/components/LoadingOverlay.jsx index 8fcaada..03dd218 100644 --- a/src/components/LoadingOverlay.jsx +++ b/src/components/LoadingOverlay.jsx @@ -1,4 +1,11 @@ -import {Flex, Loader, LoadingOverlay as MantineLoadingOverlay, Space, Text, Title} from "@mantine/core"; +import { + Flex, + Loader, + LoadingOverlay as MantineLoadingOverlay, + Space, + Text, + Title +} from "@mantine/core"; import React from "react"; import {useSelector} from "react-redux"; import {useTranslation} from "../hooks/translation"; @@ -11,25 +18,21 @@ export const LoadingOverlay = () => { const {loading: isLoading, message} = useSelector(selectLoadingState); /* eslint-disable indent, operator-linebreak */ - const description = - !message ? undefined : - message.type === "HEAVY_QUERY" ? t("loading.message_heavyquery", message) : - /* else */ t("loading.message_default", message); + const description = !message + ? undefined + : message.type === "HEAVY_QUERY" + ? t("loading.message_heavyquery", message) + : /* else */ t("loading.message_default", message); /* eslint-enable indent, operator-linebreak */ - const customLoader = - + const customLoader = ( + {t("loading.title")} {description} - ; - + ); return ( { @@ -38,7 +37,7 @@ function MeasuresMenu(props: Props) { if (query && !query.test(getCaption(measure, locale))) { return null; } - return itemMap[measure.name] || buildMeasure({ active: false, ...measure }); + return itemMap[measure.name] || buildMeasure({active: false, ...measure}); }); }, [itemMap, measures, filter, locale]); @@ -49,8 +48,8 @@ function MeasuresMenu(props: Props) { disabled={activeItems.map(active => active.name).includes(item.name)} key={item.name} onClick={() => { - actions.updateMeasure({ ...item, active: !item.active }); - actions.willRequestQuery() + actions.updateMeasure({...item, active: !item.active}); + // actions.willRequestQuery(); }} > {item.name} diff --git a/src/components/OptionsMenu.tsx b/src/components/OptionsMenu.tsx index 66bc2ba..b4ab07c 100644 --- a/src/components/OptionsMenu.tsx +++ b/src/components/OptionsMenu.tsx @@ -3,15 +3,12 @@ import {Menu, ActionIcon, ActionIconProps, UnstyledButton, Group, Text} from "@m import {IconChevronRight, IconStack2} from "@tabler/icons-react"; import {DimensionMenu} from "./MenuDimension"; import MeasuresMenu from "./MeasuresMenu"; -import {IconArrowsLeftRight} from "@tabler/icons-react"; -import {useMantineTheme} from "@mantine/core"; -import {useMediaQuery} from "@mantine/hooks"; import {stringifyName} from "../utils/transform"; import {useSelector} from "react-redux"; import {selectDrilldownItems} from "../state/queries"; import {selectOlapDimensionItems} from "../state/selectors"; import {useActions} from "../hooks/settings"; -import {buildDrilldown} from "../utils/structs"; +import {buildDrilldown, buildCut} from "../utils/structs"; import type {LevelDescriptor} from "../utils/types"; import type {ComponentProps, ReactNode} from "react"; import type {PlainLevel} from "@datawheel/olap-client"; @@ -22,9 +19,18 @@ function OptionsMenu({children}: {children: ReactNode}) { const dimensions = useSelector(selectOlapDimensionItems); const {willRequestQuery} = useActions(); + const createCutHandler = React.useCallback((level: PlainLevel) => { + const cutItem = buildCut({...level, key: level.fullName}); + cutItem.active = false; + actions.updateCut(cutItem); + }, []); + const createHandler = useCallback( (level: PlainLevel) => { - const drilldownItem = buildDrilldown({...level, key: level.fullName}); + // find or create drilldown + const drilldownItem = + items.find(item => item.uniqueName === level.uniqueName) ?? buildDrilldown({...level}); + createCutHandler(level); actions.updateDrilldown(drilldownItem); actions .willFetchMembers({...level, level: level.name}) @@ -59,9 +65,11 @@ function OptionsMenu({children}: {children: ReactNode}) { Metrics - + + i.active)} onItemSelect={createHandler}> Dimensions + {/* }>Calculations */} diff --git a/src/components/SelectCubes.tsx b/src/components/SelectCubes.tsx index 9a8bd9e..3beeaff 100644 --- a/src/components/SelectCubes.tsx +++ b/src/components/SelectCubes.tsx @@ -1,15 +1,15 @@ import {type PlainCube} from "@datawheel/olap-client"; -import {Anchor, Stack, Text, TextProps, Box, Accordion, AccordionControlProps} from "@mantine/core"; +import {Stack, Text, TextProps, Box, Accordion, AccordionControlProps} from "@mantine/core"; import React, {PropsWithChildren, useCallback, useEffect, useMemo, useRef, useState} from "react"; import {useSelector} from "react-redux"; import {useActions} from "../hooks/settings"; import {useTranslation} from "../hooks/translation"; -import {selectLocale, selectMeasureMap, selectValidQueryStatus} from "../state/queries"; +import {selectLocale, selectMeasureMap} from "../state/queries"; import {selectOlapCube, selectOlapDimensionItems} from "../state/selectors"; import {selectOlapCubeItems} from "../state/server"; import {selectCubeName} from "../state/queries"; import {getAnnotation} from "../utils/string"; -import {buildDrilldown} from "../utils/structs"; +import {buildDrilldown, buildCut, MeasureItem} from "../utils/structs"; import type {Annotated} from "../utils/types"; import type {PlainLevel} from "@datawheel/olap-client"; import {useSideBar} from "./SideBar"; @@ -32,16 +32,22 @@ function SelectCubeInternal(props: {items: PlainCube[]; selectedItem: PlainCube const {items, selectedItem} = props; const {translate: t} = useTranslation(); const {code: locale} = useSelector(selectLocale); - const {willRequestQuery, updateMeasure, updateDrilldown, willFetchMembers} = useActions(); - const initRef = useRef(false); + const {updateMeasure, updateDrilldown, willFetchMembers, updateCut} = useActions(); const cube = useSelector(selectCubeName); const itemMap = useSelector(selectMeasureMap); const dimensions = useSelector(selectOlapDimensionItems); + const createCutHandler = React.useCallback((level: PlainLevel) => { + const cutItem = buildCut({...level}); + cutItem.active = false; + updateCut(cutItem); + }, []); + const addDrilldown = useCallback( (level: PlainLevel) => { - const drilldownItem = buildDrilldown({...level, key: level.fullName}); + const drilldownItem = buildDrilldown(level); + createCutHandler(level); updateDrilldown(drilldownItem); return willFetchMembers({...level, level: level.name}).then(members => { const dimension = dimensions.find(dim => dim.name === level.dimension); @@ -60,35 +66,12 @@ function SelectCubeInternal(props: {items: PlainCube[]; selectedItem: PlainCube useEffect(() => { const params = new URLSearchParams(location.search); const cubeParam = params.get("cube"); - - //autoload if not params if (selectedItem && cube && !cubeParam) { - initRef.current = true; - const measure = Object.keys(itemMap) - .map(k => itemMap[k]) - .shift(); - const dimension = [...dimensions].shift(); + const [measure] = Object.values(itemMap); + const [dimension] = dimensions; if (measure && dimension) { updateMeasure({...measure, active: true}); - addDrilldown(dimension.hierarchies[0].levels[0]).then(() => { - willRequestQuery(); - }); - } - } - if (selectedItem && cube && cubeParam) { - if (!initRef.current) { - initRef.current = true; - } else { - const measure = Object.keys(itemMap) - .map(k => itemMap[k]) - .shift(); - const dimension = [...dimensions].shift(); - if (measure && dimension) { - updateMeasure({...measure, active: true}); - addDrilldown(dimension.hierarchies[0].levels[0]).then(() => { - willRequestQuery(); - }); - } + addDrilldown(dimension.hierarchies[0].levels[0]); } } }, [selectedItem, cube]); @@ -189,6 +172,7 @@ function CubeTree({ const {graph, setGraph, map} = useSideBar(); useBuildGraph(items, locale, graph, setGraph); const actions = useActions(); + const onSelectCube = (table: string, subtopic: string) => { const cube = items.find( item => @@ -196,7 +180,7 @@ function CubeTree({ getAnnotation(item, "subtopic", locale) === subtopic ); if (cube) { - actions.willSetCube(cube.name); + return actions.willSetCube(cube.name); } }; @@ -250,7 +234,7 @@ function RootAccordions({items, graph, locale, selectedItem, onSelectCube}) { w={"100%"} styles={t => ({ control: { - background: t.colorScheme === "dark" ? t.colors.dark[7] :t.colors.gray[1], + background: t.colorScheme === "dark" ? t.colors.dark[7] : t.colors.gray[1], borderLeft: 8, borderLeftColor: "transparent", borderLeftStyle: "solid", @@ -258,7 +242,7 @@ function RootAccordions({items, graph, locale, selectedItem, onSelectCube}) { borderLeft: 8, borderLeftColor: t.colors[t.primaryColor][t.fn.primaryShade()], borderLeftStyle: "solid", - color: t.colors[t.primaryColor][t.fn.primaryShade()], + color: t.colors[t.primaryColor][t.fn.primaryShade()] } }, content: { @@ -306,8 +290,31 @@ function CubeButton({ locale: string; parent?: string; }) { - const {setExpanded} = useSideBar(); + const {updateMeasure, updateCut, updateDrilldown, willFetchMembers} = useActions(); const {classes} = useLinkStyles(); + + const createCutHandler = React.useCallback((level: PlainLevel) => { + const cutItem = buildCut({...level}); + cutItem.active = false; + updateCut(cutItem); + }, []); + + const addDrilldown = useCallback((level: PlainLevel, dimensions) => { + const drilldownItem = buildDrilldown(level); + createCutHandler(level); + updateDrilldown(drilldownItem); + return willFetchMembers({...level, level: level.name}).then(members => { + const dimension = dimensions.find(dim => dim.name === level.dimension); + if (!dimension) return; + return updateDrilldown({ + ...drilldownItem, + dimType: dimension.dimensionType, + memberCount: members.length, + members + }); + }); + }, []); + const table = item; const subtopic = parent ?? ""; return ( @@ -324,14 +331,23 @@ function CubeButton({ : classes.link } sx={t => ({ - background: isSelected(selectedItem, getCube(graph.items, table, subtopic, locale)) ?t.fn.primaryColor(): t.colorScheme === "dark" ? t.colors.dark[6]: t.colors.gray[3], - whiteSpace: "nowrap", - overflow: "hidden", - textOverflow: "ellipsis", + background: isSelected(selectedItem, getCube(graph.items, table, subtopic, locale)) + ? t.fn.primaryColor() + : t.colorScheme === "dark" + ? t.colors.dark[6] + : t.colors.gray[3], + overflow: "hidden" })} onClick={() => { - onSelectCube(item, subtopic); - setExpanded(false); + onSelectCube(item, subtopic).then(({cube, measures, dimensions}) => { + console.log(cube, measures, dimensions, "cubeData"); + const [measure]: MeasureItem[] = Object.values(measures); + const [dimension] = dimensions; + if (measure && dimension) { + updateMeasure({...measure, active: true}); + addDrilldown(dimension.hierarchies[0].levels[0], dimensions); + } + }); }} > {item} @@ -368,7 +384,7 @@ function SubtopicAccordion({ styles={t => ({ control: { fontSize: 14, - background: t.colorScheme === "dark" ? t.colors.dark[7]: t.colors.gray[2], + background: t.colorScheme === "dark" ? t.colors.dark[7] : t.colors.gray[2], borderLeft: 8, borderLeftColor: "transparent", borderLeftStyle: "solid", @@ -379,7 +395,7 @@ function SubtopicAccordion({ } }, content: { - padding: 0, + padding: 0 } })} > diff --git a/src/components/SideBar.tsx b/src/components/SideBar.tsx index 78ff031..95ccf77 100644 --- a/src/components/SideBar.tsx +++ b/src/components/SideBar.tsx @@ -1,5 +1,5 @@ import React, {PropsWithChildren, useState, useMemo, useEffect} from "react"; -import {Box, Flex, ActionIcon, Text, ScrollArea, Input, Group, Title} from "@mantine/core"; +import {Box, Flex, ActionIcon, Text, ScrollArea, Input, Group} from "@mantine/core"; import {createContext} from "../utils/create-context"; import {IconSearch} from "@tabler/icons-react"; import {DataSetSVG, IconChevronLeft, IconChevronRight} from "./icons"; @@ -8,9 +8,8 @@ import Graph from "../utils/graph"; import {useSelector} from "react-redux"; import {getKeys} from "./SelectCubes"; import {AnnotatedCube} from "./SelectCubes"; -import { LocaleSelector } from "./LocaleSelector"; +import {LocaleSelector} from "./LocaleSelector"; import {useTranslation} from "../hooks/translation"; -import {selectOlapCube} from "../state/selectors"; type SidebarProviderProps = { expanded: boolean; @@ -36,9 +35,7 @@ export function SideBarProvider(props: PropsWithChildren<{}>) { const [map, setMap] = useState>(); const [graph, setGraph] = useState(new Graph()); - const resetGraph = () => { - setGraph(new Graph()); - }; + const resetGraph = () => setGraph(new Graph()); return ( ) { const {expanded, setExpanded} = useSideBar(); - + const {translate: t} = useTranslation(); return ( ({ - height: "calc(100vh - 75px)", - backgroundColor: t.colorScheme === "dark" ? t.colors.dark[8]: t.colors.gray[2], + height: "calc(100vh - 70px)", + backgroundColor: t.colorScheme === "dark" ? t.colors.dark[8] : t.colors.gray[2], boxShadow: "0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)", - maxWidth: 300, - padding: 0, + maxWidth: 300 })} > @@ -83,7 +79,10 @@ function SideBar(props: PropsWithChildren) { setExpanded(!expanded)} variant="subtle" - sx={t => ({alignSelf: "center", color: t.colorScheme === "dark" ? t.white: t.colors.gray[7]})} + sx={t => ({ + alignSelf: "center", + color: t.colorScheme === "dark" ? t.white : t.colors.gray[7] + })} > @@ -93,11 +92,13 @@ function SideBar(props: PropsWithChildren) { sx={{ overflow: "hidden", whiteSpace: "nowrap", - transition: "width 0.2s cubic-bezier(0.4, 0, 0.2, 1), margin-left 0.2s cubic-bezier(0.4, 0, 0.2, 1)", - width: expanded ? 300 : 0, - }}> - ({color: t.colorScheme === "dark" ? t.white: t.black})} ml={"sm"}> - Select Dataset + transition: + "* 0.2s cubic-bezier(0.4, 0, 0.2, 1), margin-left 0.2s cubic-bezier(0.4, 0, 0.2, 1)", + width: expanded ? 300 : 0 + }} + > + ({color: t.colorScheme === "dark" ? t.white : t.black})} ml={"sm"}> + {t("sidebar.dataset")} @@ -106,21 +107,21 @@ function SideBar(props: PropsWithChildren) { - - ( - { - borderTopColor: theme.colorScheme === "dark" ? theme.colors.dark[6] :theme.colors.gray[3], + ({ + borderTopColor: + theme.colorScheme === "dark" ? theme.colors.dark[6] : theme.colors.gray[3], borderTopWidth: "1px", - borderTopStyle: expanded ? "solid": "none" - } - )}> - {props.children} + borderTopStyle: expanded ? "solid" : "none" + })} + > + {props.children} diff --git a/src/components/TableFooter.tsx b/src/components/TableFooter.tsx index 53330da..8286a4a 100644 --- a/src/components/TableFooter.tsx +++ b/src/components/TableFooter.tsx @@ -27,7 +27,7 @@ function TableFooter(props: Props) { return ( - + {t("results.count_rows", {n: result.data.length})} @@ -92,7 +92,11 @@ const DownloadQuery = () => { ); } - if (components.length === 0 || isDirty || result.data.length === 0) { + // if (components.length === 0 || isDirty || result.data.length === 0) { + // return null; + // } + + if (components.length === 0 || result.data.length === 0) { return null; } @@ -221,7 +225,7 @@ function MenuOpts({formats}: MenuOptsProps) { minWidth: 0 }} > - + {/*