From e8bf3abde8beb3ab2e6ef1c7e0255969a30f3d8f Mon Sep 17 00:00:00 2001 From: Peter Kosztolanyi Date: Thu, 25 Sep 2025 18:30:32 +0200 Subject: [PATCH] Switch to Material UI; replaced custom CSS/HTML with MUI components (no functional changes) --- .github/workflows/release.yml | 7 +- README.md | 173 +- precise/.eslintignore | 1 - precise/eslint.config.js | 77 + precise/index.html | 2 +- precise/package-lock.json | 3310 +++++++++++------ precise/package.json | 76 +- precise/src/App.tsx | 12 - precise/src/QueryApp.tsx | 114 - precise/src/QueryCell.tsx | 323 +- precise/src/QueryEditor.tsx | 1057 +----- precise/src/QueryEditorPane.tsx | 951 +++++ precise/src/ResultSet.tsx | 550 +-- precise/src/SubstitutionEditor.tsx | 63 +- precise/src/assets/close.png | Bin 46334 -> 0 bytes precise/src/assets/pin_down.png | Bin 36813 -> 0 bytes precise/src/assets/pin_up.png | Bin 62626 -> 0 bytes .../controls/catalog_viewer/CatalogViewer.tsx | 302 +- .../catalog_viewer/CatalogViewerColumn.tsx | 144 +- .../catalog_viewer/CatalogViewerSchema.tsx | 101 +- .../catalog_viewer/CatalogViewerTable.tsx | 123 +- .../controls/catalog_viewer/ViewerState.ts | 2 +- .../controls/catalog_viewer/catalogviewer.css | 204 - precise/src/controls/tabs/EnterpriseTabs.tsx | 87 +- precise/src/controls/tabs/TabItem.tsx | 135 - .../src/controls/tabs/TabsEllipsesMenu.tsx | 76 +- precise/src/controls/tabs/tabs.css | 193 - precise/src/index.ts | 1 + precise/src/main.tsx | 60 +- precise/src/sql/SchemaProvider.ts | 10 +- precise/src/style/components.css | 201 - precise/src/style/control.css | 231 -- precise/src/style/layout.css | 144 - precise/src/style/normalize.css | 94 - precise/src/style/query-editor.css | 162 - precise/src/style/results.css | 231 -- precise/src/style/theme.css | 66 - precise/src/theme.tsx | 45 + precise/src/utils/ClearButton.tsx | 33 +- precise/src/utils/CopyLink.tsx | 39 +- precise/src/utils/ErrorBoxProvider.tsx | 41 - precise/src/utils/ProgressBar.tsx | 33 - precise/src/utils/ResizableContainer.tsx | 83 - precise/src/utils/errorbox.css | 40 - precise/vite.config.ts | 31 +- 45 files changed, 4632 insertions(+), 4996 deletions(-) delete mode 100644 precise/.eslintignore create mode 100644 precise/eslint.config.js delete mode 100644 precise/src/App.tsx delete mode 100644 precise/src/QueryApp.tsx create mode 100644 precise/src/QueryEditorPane.tsx delete mode 100644 precise/src/assets/close.png delete mode 100644 precise/src/assets/pin_down.png delete mode 100644 precise/src/assets/pin_up.png delete mode 100644 precise/src/controls/catalog_viewer/catalogviewer.css delete mode 100644 precise/src/controls/tabs/TabItem.tsx delete mode 100644 precise/src/controls/tabs/tabs.css create mode 100644 precise/src/index.ts delete mode 100644 precise/src/style/components.css delete mode 100644 precise/src/style/control.css delete mode 100644 precise/src/style/layout.css delete mode 100644 precise/src/style/normalize.css delete mode 100644 precise/src/style/query-editor.css delete mode 100644 precise/src/style/results.css delete mode 100644 precise/src/style/theme.css create mode 100644 precise/src/theme.tsx delete mode 100644 precise/src/utils/ErrorBoxProvider.tsx delete mode 100644 precise/src/utils/ProgressBar.tsx delete mode 100644 precise/src/utils/ResizableContainer.tsx delete mode 100644 precise/src/utils/errorbox.css diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 11a125a..c816d4c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -2,8 +2,7 @@ name: Publish Package to npmjs on: release: - types: [created] - pull_request: + types: [published] jobs: publish: @@ -27,11 +26,7 @@ jobs: - name: Build package run: npm run build - # This step is a placeholder for publishing to npm. - # The project structure and Node configuration will need to be adjusted - # before this can be enabled and work as intended. - name: Publish to npm - if: github.event_name == 'release' run: npm publish env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/README.md b/README.md index 9f3fc3f..09789e5 100644 --- a/README.md +++ b/README.md @@ -1,106 +1,54 @@ # Trino Query UI -This Trino Query UI is a new UI component that can be integrated into Trino and run directly from the Trino installation at the `/query/` path. For testing, it can also be run separately and can proxy to a Trino running locally or elsewhere. +A reusable React component for executing queries against Trino. It can be embedded into any react application and configured to proxy requests to a local or remote Trino cluster. + +> [!WARNING] +> This package is under heavy development and is not yet recommended for production workloads. Treat the current release as an early-stage demo; production-ready builds and documentation will follow soon. ![Trino Query UI Demo](demos.gif "Trino Query UI Demo") Implementation details: -* React Typescript project with Vite -* Using Node.js v20+ -* Monaco editor + ANTLR parser using Trino language - -## Building and Shipping in Trino - -The Query UI builds just like the existing UI in Trino. -1. First you build the TypeScript into Javascript and CSS -2. Then copy the distributable path into Trino. -3. Then modify Trino to respond to the query ui path. +* React TypeScript project with Vite +* Uses Node.js v20+ +* Monaco editor + ANTLR parser using the Trino language -### Building for Integration +## Installation ``` -cd precise -npm run build +npm install trino-query-ui ``` -### Copying into Trino - -mkdir -p $TRINO_HOME/core/trino-main/src/main/resources/query_ui_webapp/ -cp -r dist/* $TRINO_HOME/core/trino-main/src/main/resources/query_ui_webapp/ - -### Modifying Trino to Respond to /query/ - -Modify `$TRINO_HOME/core/trino-main/src/main/java/io/trino/server/ui/WebUiStaticResource.java`: - -Add `/query/` path. Note any path can be used: - -```java - @GET - @Path("/query") - public Response getQuery(@BeanParam ExternalUriInfo externalUriInfo) - { - return Response.seeOther(externalUriInfo.absolutePath("/query/")).build(); - } - - // asset files are always visible - @ResourceSecurity(PUBLIC) - @GET - @Path("/query/assets/{path: .*}") - public Response getQueryAssetsFile(@PathParam("path") String path) - throws IOException - { - return getQueryFile("assets/" + path); - } - - @ResourceSecurity(PUBLIC) - @GET - @Path("/query/{path: .*}") - public Response getQueryFile(@PathParam("path") String path) - throws IOException - { - if (path.isEmpty()) { - path = "index.html"; - } - - String fullPath = "/query_ui_webapp/" + path; - if (!isCanonical(fullPath)) { - return Response.status(NOT_FOUND).build(); - } - - URL resource = getClass().getResource(fullPath); - if (resource == null) { - return Response.status(NOT_FOUND).build(); - } - - return Response.ok(resource.openStream()).build(); - } - - private static boolean isCanonical(String fullPath) - { - try { - return new URI(fullPath).normalize().getPath().equals(fullPath); - } - catch (URISyntaxException e) { - return false; - } - } +## Quick Start + +```tsx +import { QueryEditor } from 'trino-query-ui' +import 'trino-query-ui/dist/index.css' + +function MyTrinoApp() { + return +} + +export default MyTrinoApp ``` + ## Development -### Setup the Coding Environment +### Build and Run -Tested on Ubuntu and Windows. +1. Install Node.js (v20 or newer) from +2. Install the dependencies and run the dev server: +``` +cd precise +npm install +npm run dev +``` -1. Install node.js at least v20 -2. Create an NPM enviroment using Vite: `npm create vite@latest`, pick *React*, then *Typescript* -3. In the precise folder, install monaco `npm install @monaco-editor/react` -4. Install Typescript Runtime for ANTLR4 `npm install antlr4ng` and the cli `npm install --save-dev antlr4ng-cli` - because seems abandoned? +The local URL will be displayed, and you can open it in your browser. -### Setup Proxying to Local Trino Instance +### Set Up Proxying to a Local Trino Instance -To run outside of Trino, update the contents of the `vite.config.ts` with the following so that queries can be properly proxied over to Trino's query endpoint running on `http://localhost:8080` or any other proxy path required. +Update `vite.config.ts` with the following so that queries can be properly proxied to Trino's query endpoint running on `http://localhost:8080` (or any other path you require). ```tsx import { defineConfig } from 'vite' @@ -119,26 +67,15 @@ export default defineConfig({ }, }, }, + ... }); ``` -### Build and Run - -To run, start: - -```shell - cd precise - npm install - npm run dev -``` - -The local URL will be be displayed which you can open in your browser. - ### Building the Parser -To build parser: `npm run antlr4ng`, as configured in **package.json** +Run `npm run antlr4ng` to build the parser, as configured in **package.json**. -### Linting and code formatting +### Linting and Code Formatting To check code quality and formatting: @@ -146,37 +83,37 @@ To check code quality and formatting: npm run check ``` -This command runs both eslint and prettier, as defined in **package.json** +This command runs both ESLint and Prettier, as defined in **package.json**. ## Philosophy -This UI's purpose is to provide an environment where once the cluster is stood up, executing queries and exploring data sets can be done right away. The idended use cases are: +This UI's purpose is to provide an environment where, once the cluster is up, you can immediately execute queries and explore data sets. The intended use cases are: * Initial proof-of-concept queries. * Exploration of data sets. * Performance analysis. -* Adhoc query execution. +* Ad hoc query execution. * Quickly enabling a data engineering team to start work before other integrations are in place. * Early demos. -The approach taken: -1. Direct integration into Trino UI - - No need for additional authentication hop (although it could be added in the future) - - Auth as the user executing the query if using Oauth2 +The approach: +1. Direct integration into the Trino UI + - No need for an additional authentication hop (although it could be added in the future) + - Authenticates as the user executing the query when using OAuth2 - Trino does the heavy lifting -2. Don't need to think, just write a query - - Autocomplete must be aware of not just Trino language but tables and columns - - Syntax highlighting, validation - - Comprehensive catalog explorer -3. No black box query execution - - Show progress and details of execution: people ask "why is my query slow" but mostly this is because they are only shown a spinner for 10 minutes. - - Link to Trino query UI to drill into query performance - - Show stages and split counts like Trino console client -4. Easy to navigate +2. Remove friction so you can simply write a query + - Autocomplete understands the Trino language, tables, and columns + - Provides syntax highlighting and validation + - Offers a comprehensive catalog explorer +3. Avoid black-box query execution + - Show progress and execution details. People ask "why is my query slow?" mostly because they only see a spinner for minutes. + - Link to the Trino Query UI to drill into query performance + - Show stages and split counts like the Trino console client +4. Keep the experience easy to navigate ### Gaps and Future Direction -* The ability to save queries and use source control requires either back end capabilities in the Trino service or can utilize Trino to write queries as tables. +* Saving queries and using source control require either backend capabilities in the Trino service or leveraging Trino to write queries as tables. * No autocomplete for the Trino function list. -* Basic graphing capabilities - looking at a table is not enough even for inspecting data sets. -* No LLM copilot integration yet, this is done badly in many query UIs and if done well could make query crafting very fast, and solve other issues like translation from other query languages. -* Parameters and string replace: this is partly implemented in `SubstitutionEditor` and should support both SQL parameters and string replacement. \ No newline at end of file +* Basic graphing capabilities are still missing—looking at a table alone is not enough even for inspecting data sets. +* No LLM copilot integration yet. Many query UIs implement this poorly, but, done well, it could make query crafting fast and help translate from other query languages. +* Parameters and string replacement are only partly implemented in `SubstitutionEditor` and should support both SQL parameters and string replacement. diff --git a/precise/.eslintignore b/precise/.eslintignore deleted file mode 100644 index 4150114..0000000 --- a/precise/.eslintignore +++ /dev/null @@ -1 +0,0 @@ -src/generated/** diff --git a/precise/eslint.config.js b/precise/eslint.config.js new file mode 100644 index 0000000..7355361 --- /dev/null +++ b/precise/eslint.config.js @@ -0,0 +1,77 @@ +import js from '@eslint/js' +import globals from 'globals'; +import tsParser from '@typescript-eslint/parser' +import tsPlugin from '@typescript-eslint/eslint-plugin' +import reactHooksPlugin from 'eslint-plugin-react-hooks'; +import reactRefreshPlugin from 'eslint-plugin-react-refresh'; + +export default [ + js.configs.recommended, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parser: tsParser, + ecmaVersion: 'latest', + sourceType: 'module', + globals: { + ...globals.browser, + process: 'readonly', + React: 'readonly', + }, + }, + plugins: { + '@typescript-eslint': tsPlugin, + }, + rules: { + ...tsPlugin.configs.recommended.rules, + '@typescript-eslint/no-unused-expressions': [ + 'error', + { + allowShortCircuit: true, + allowTernary: true, + }, + ], + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/no-unused-vars': 'off', + }, + }, + { + files: ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'], + plugins: { + 'react-hooks': reactHooksPlugin, + }, + rules: { + ...reactHooksPlugin.configs.recommended.rules, + }, + }, + { + files: ['**/*.{js,jsx,ts,tsx}'], // Match all JS/TS files + plugins: { + 'react-refresh': reactRefreshPlugin, + }, + rules: { + 'react-refresh/only-export-components': [ + 'warn', + { allowConstantExport: true }, + ], + // Fix and enable separately + // 'eol-last': ['warn', 'always'], + // 'no-multiple-empty-lines': ['warn', { max: 1, maxEOF: 0 }], + }, + }, + { + files: ['src/utils/ProgressBar.tsx'], + rules: { + '@typescript-eslint/no-empty-object-type': 'off', + }, + }, + { + files: ['src/generated/**/*.ts'], + linterOptions: { + reportUnusedDisableDirectives: false, + }, + }, + { + ignores: ['dist', 'src/generated/**', '.eslintrc.cjs'], + }, +]; diff --git a/precise/index.html b/precise/index.html index 8963d85..9f6fd79 100644 --- a/precise/index.html +++ b/precise/index.html @@ -4,7 +4,7 @@ - Trino Query Editor + Trino Query Editor - Example app
diff --git a/precise/package-lock.json b/precise/package-lock.json index e567576..fea73f1 100644 --- a/precise/package-lock.json +++ b/precise/package-lock.json @@ -1,83 +1,66 @@ { - "name": "precise", - "version": "0.0.0", + "name": "trino-query-ui", + "version": "0.0.1", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "precise", - "version": "0.0.0", - "dependencies": { - "@monaco-editor/react": "^4.6.0", - "antlr4-c3": "^3.4.1", - "antlr4ng": "^3.0.4", - "lucide-react": "^0.460.0", - "precise": "file:", - "prettier": "^3.5.3", - "react": "^18.2.0", + "name": "trino-query-ui", + "version": "0.0.1", + "license": "Apache-2.0", + "dependencies": { + "@emotion/react": "^11.14.0", + "@emotion/styled": "^11.14.1", + "@monaco-editor/react": "^4.7.0", + "@mui/icons-material": "^7.3.2", + "@mui/material": "^7.3.2", + "@mui/x-data-grid": "^8.14.0", + "@mui/x-tree-view": "^8.13.1", + "antlr4-c3": "^3.4.4", + "antlr4ng": "^3.0.16", + "lucide-react": "^0.544.0", + "prettier": "^3.6.2", "react-dnd": "^16.0.1", "react-dnd-html5-backend": "^16.0.1", - "react-dom": "^18.2.0", - "sql-formatter": "^15.5.2", + "sql-formatter": "^15.6.9", "uuidv4": "^6.2.13" }, "devDependencies": { - "@types/http-proxy-middleware": "^1.0.0", - "@types/react": "^18.2.66", - "@types/react-dom": "^18.2.22", - "@typescript-eslint/eslint-plugin": "^7.2.0", - "@typescript-eslint/parser": "^7.2.0", - "@vitejs/plugin-react": "^4.2.1", + "@types/react": "^19.1.13", + "@types/react-dom": "^19.1.9", + "@typescript-eslint/eslint-plugin": "^8.44.1", + "@typescript-eslint/parser": "^8.44.1", + "@vitejs/plugin-react": "^5.0.3", "antlr4ng-cli": "^2.0.0", - "eslint": "^8.57.0", - "eslint-plugin-react-hooks": "^4.6.0", - "eslint-plugin-react-refresh": "^0.4.6", - "typescript": "^5.2.2", - "vite": "^6.2.4" - } - }, - "node_modules/@aashutoshrathi/word-wrap": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", - "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@ampproject/remapping": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", - "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" + "eslint": "^9.36.0", + "eslint-plugin-react-hooks": "^5.2.0", + "eslint-plugin-react-refresh": "^0.4.21", + "typescript": "^5.9.2", + "vite": "^7.1.7" }, - "engines": { - "node": ">=6.0.0" + "peerDependencies": { + "react": "^19.1.1", + "react-dom": "^19.1.1" } }, "node_modules/@babel/code-frame": { - "version": "7.26.2", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", - "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", - "dev": true, + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.25.9", + "@babel/helper-validator-identifier": "^7.27.1", "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" + "picocolors": "^1.1.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/compat-data": { - "version": "7.26.8", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.8.tgz", - "integrity": "sha512-oH5UPLMWR3L2wEFLnFJ1TZXqHufiTKAiLfqw5zkhS4dKXLJ10yVztfil/twG8EDTA4F/tvVNw9nOl4ZMslB8rQ==", + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.4.tgz", + "integrity": "sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw==", "dev": true, "license": "MIT", "engines": { @@ -85,22 +68,22 @@ } }, "node_modules/@babel/core": { - "version": "7.26.10", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.10.tgz", - "integrity": "sha512-vMqyb7XCDMPvJFFOaT9kxtiRh42GwlZEg1/uIgtZshS5a/8OaduUfCi7kynKgc3Tw/6Uo2D+db9qBttghhmxwQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.26.2", - "@babel/generator": "^7.26.10", - "@babel/helper-compilation-targets": "^7.26.5", - "@babel/helper-module-transforms": "^7.26.0", - "@babel/helpers": "^7.26.10", - "@babel/parser": "^7.26.10", - "@babel/template": "^7.26.9", - "@babel/traverse": "^7.26.10", - "@babel/types": "^7.26.10", + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.4.tgz", + "integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.3", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-module-transforms": "^7.28.3", + "@babel/helpers": "^7.28.4", + "@babel/parser": "^7.28.4", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.4", + "@babel/types": "^7.28.4", + "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -126,16 +109,15 @@ } }, "node_modules/@babel/generator": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.27.0.tgz", - "integrity": "sha512-VybsKvpiN1gU1sdMZIp7FcqphVVKEwcuj02x73uvcHE0PTihx1nlBcowYWhDwjpoAXRv43+gDzyggGnn1XZhVw==", - "dev": true, + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz", + "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.27.0", - "@babel/types": "^7.27.0", - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25", + "@babel/parser": "^7.28.3", + "@babel/types": "^7.28.2", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" }, "engines": { @@ -143,14 +125,14 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.0.tgz", - "integrity": "sha512-LVk7fbXml0H2xH34dFzKQ7TDZ2G4/rVTOrq9V+icbbadjbVxxeFeDsNHv2SrZeWoA+6ZiTyWYWtScEIW07EAcA==", + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", + "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.26.8", - "@babel/helper-validator-option": "^7.25.9", + "@babel/compat-data": "^7.27.2", + "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" @@ -169,30 +151,38 @@ "semver": "bin/semver.js" } }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-module-imports": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", - "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", - "dev": true, + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", "license": "MIT", "dependencies": { - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.25.9" + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", - "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", + "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9", - "@babel/traverse": "^7.25.9" + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.28.3" }, "engines": { "node": ">=6.9.0" @@ -202,9 +192,9 @@ } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.26.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.26.5.tgz", - "integrity": "sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", + "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", "dev": true, "license": "MIT", "engines": { @@ -212,29 +202,27 @@ } }, "node_modules/@babel/helper-string-parser": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", - "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", - "dev": true, + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", - "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", - "dev": true, + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz", - "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", "dev": true, "license": "MIT", "engines": { @@ -242,27 +230,26 @@ } }, "node_modules/@babel/helpers": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.0.tgz", - "integrity": "sha512-U5eyP/CTFPuNE3qk+WZMxFkp/4zUzdceQlfzf7DdGdhp+Fezd7HD+i8Y24ZuTMKX3wQBld449jijbGq6OdGNQg==", + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", + "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", "dev": true, "license": "MIT", "dependencies": { - "@babel/template": "^7.27.0", - "@babel/types": "^7.27.0" + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.4" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.0.tgz", - "integrity": "sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg==", - "dev": true, + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.4.tgz", + "integrity": "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==", "license": "MIT", "dependencies": { - "@babel/types": "^7.27.0" + "@babel/types": "^7.28.4" }, "bin": { "parser": "bin/babel-parser.js" @@ -272,13 +259,13 @@ } }, "node_modules/@babel/plugin-transform-react-jsx-self": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.25.9.tgz", - "integrity": "sha512-y8quW6p0WHkEhmErnfe58r7x0A70uKphQm8Sp8cV7tjNQwK56sNVK0M73LK3WuYmsuyrftut4xAkjjgU0twaMg==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz", + "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -288,13 +275,13 @@ } }, "node_modules/@babel/plugin-transform-react-jsx-source": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.25.9.tgz", - "integrity": "sha512-+iqjT8xmXhhYv4/uiYd8FNQsraMFZIfxVSqxxVSZP0WbbSAWvBXAul0m/zu+7Vv4O/3WtApy9pmaTMiumEZgfg==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz", + "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -304,69 +291,237 @@ } }, "node_modules/@babel/runtime": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.0.tgz", - "integrity": "sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw==", + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz", + "integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==", "license": "MIT", - "dependencies": { - "regenerator-runtime": "^0.14.0" - }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/template": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.0.tgz", - "integrity": "sha512-2ncevenBqXI6qRMukPlXwHKHchC7RyMuu4xv5JBXRfOGVcTy1mXCD12qrp7Jsoxll1EV3+9sE4GugBVRjT2jFA==", - "dev": true, + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.26.2", - "@babel/parser": "^7.27.0", - "@babel/types": "^7.27.0" + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.2", + "@babel/types": "^7.27.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.27.0.tgz", - "integrity": "sha512-19lYZFzYVQkkHkl4Cy4WrAVcqBkgvV2YM2TU3xG6DIwO7O3ecbDPfW3yM3bjAGcqcQHi+CCtjMR3dIEHxsd6bA==", - "dev": true, + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.4.tgz", + "integrity": "sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==", "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.26.2", - "@babel/generator": "^7.27.0", - "@babel/parser": "^7.27.0", - "@babel/template": "^7.27.0", - "@babel/types": "^7.27.0", - "debug": "^4.3.1", - "globals": "^11.1.0" + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.3", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.4", + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.4", + "debug": "^4.3.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/types": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.0.tgz", - "integrity": "sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg==", - "dev": true, + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.4.tgz", + "integrity": "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==", "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9" + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1" }, "engines": { "node": ">=6.9.0" } }, + "node_modules/@base-ui-components/utils": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@base-ui-components/utils/-/utils-0.1.1.tgz", + "integrity": "sha512-HWXZA8upEKgrdL1rQqxWu1H+2tB2cXzY2jCxvgnpUv3eoWN2jldhXxMZnXIjZF7jahGxSWXfSIM/qskiTWFFxA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.28.3", + "@floating-ui/utils": "^0.2.10", + "reselect": "^5.1.1", + "use-sync-external-store": "^1.5.0" + }, + "peerDependencies": { + "@types/react": "^17 || ^18 || ^19", + "react": "^17 || ^18 || ^19", + "react-dom": "^17 || ^18 || ^19" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/babel-plugin": { + "version": "11.13.5", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.13.5.tgz", + "integrity": "sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.16.7", + "@babel/runtime": "^7.18.3", + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/serialize": "^1.3.3", + "babel-plugin-macros": "^3.1.0", + "convert-source-map": "^1.5.0", + "escape-string-regexp": "^4.0.0", + "find-root": "^1.1.0", + "source-map": "^0.5.7", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/babel-plugin/node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "license": "MIT" + }, + "node_modules/@emotion/cache": { + "version": "11.14.0", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.14.0.tgz", + "integrity": "sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==", + "license": "MIT", + "dependencies": { + "@emotion/memoize": "^0.9.0", + "@emotion/sheet": "^1.4.0", + "@emotion/utils": "^1.4.2", + "@emotion/weak-memoize": "^0.4.0", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/hash": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz", + "integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==", + "license": "MIT" + }, + "node_modules/@emotion/is-prop-valid": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.4.0.tgz", + "integrity": "sha512-QgD4fyscGcbbKwJmqNvUMSE02OsHUa+lAWKdEUIJKgqe5IwRSKd7+KhibEWdaKwgjLj0DRSHA9biAIqGBk05lw==", + "license": "MIT", + "dependencies": { + "@emotion/memoize": "^0.9.0" + } + }, + "node_modules/@emotion/memoize": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz", + "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==", + "license": "MIT" + }, + "node_modules/@emotion/react": { + "version": "11.14.0", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.14.0.tgz", + "integrity": "sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.13.5", + "@emotion/cache": "^11.14.0", + "@emotion/serialize": "^1.3.3", + "@emotion/use-insertion-effect-with-fallbacks": "^1.2.0", + "@emotion/utils": "^1.4.2", + "@emotion/weak-memoize": "^0.4.0", + "hoist-non-react-statics": "^3.3.1" + }, + "peerDependencies": { + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/serialize": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.3.tgz", + "integrity": "sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==", + "license": "MIT", + "dependencies": { + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/unitless": "^0.10.0", + "@emotion/utils": "^1.4.2", + "csstype": "^3.0.2" + } + }, + "node_modules/@emotion/sheet": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz", + "integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==", + "license": "MIT" + }, + "node_modules/@emotion/styled": { + "version": "11.14.1", + "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.14.1.tgz", + "integrity": "sha512-qEEJt42DuToa3gurlH4Qqc1kVpNq8wO8cJtDzU46TjlzWjDlsVyevtYCRijVq3SrHsROS+gVQ8Fnea108GnKzw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.13.5", + "@emotion/is-prop-valid": "^1.3.0", + "@emotion/serialize": "^1.3.3", + "@emotion/use-insertion-effect-with-fallbacks": "^1.2.0", + "@emotion/utils": "^1.4.2" + }, + "peerDependencies": { + "@emotion/react": "^11.0.0-rc.0", + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/unitless": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.10.0.tgz", + "integrity": "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==", + "license": "MIT" + }, + "node_modules/@emotion/use-insertion-effect-with-fallbacks": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.2.0.tgz", + "integrity": "sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==", + "license": "MIT", + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@emotion/utils": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.2.tgz", + "integrity": "sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==", + "license": "MIT" + }, + "node_modules/@emotion/weak-memoize": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz", + "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==", + "license": "MIT" + }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.2.tgz", - "integrity": "sha512-wCIboOL2yXZym2cgm6mlA742s9QeJ8DjGVaL39dLN4rRwrOgOyYSnOaFPhKZGLb2ngj4EyfAFjsNJwPXZvseag==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.10.tgz", + "integrity": "sha512-0NFWnA+7l41irNuaSVlLfgNT12caWJVLzp5eAVhZ0z1qpxbockccEt3s+149rE64VUI3Ml2zt8Nv5JVc4QXTsw==", "cpu": [ "ppc64" ], @@ -381,9 +536,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.2.tgz", - "integrity": "sha512-NQhH7jFstVY5x8CKbcfa166GoV0EFkaPkCKBQkdPJFvo5u+nGXLEH/ooniLb3QI8Fk58YAx7nsPLozUWfCBOJA==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.10.tgz", + "integrity": "sha512-dQAxF1dW1C3zpeCDc5KqIYuZ1tgAdRXNoZP7vkBIRtKZPYe2xVr/d3SkirklCHudW1B45tGiUlz2pUWDfbDD4w==", "cpu": [ "arm" ], @@ -398,9 +553,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.2.tgz", - "integrity": "sha512-5ZAX5xOmTligeBaeNEPnPaeEuah53Id2tX4c2CVP3JaROTH+j4fnfHCkr1PjXMd78hMst+TlkfKcW/DlTq0i4w==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.10.tgz", + "integrity": "sha512-LSQa7eDahypv/VO6WKohZGPSJDq5OVOo3UoFR1E4t4Gj1W7zEQMUhI+lo81H+DtB+kP+tDgBp+M4oNCwp6kffg==", "cpu": [ "arm64" ], @@ -415,9 +570,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.2.tgz", - "integrity": "sha512-Ffcx+nnma8Sge4jzddPHCZVRvIfQ0kMsUsCMcJRHkGJ1cDmhe4SsrYIjLUKn1xpHZybmOqCWwB0zQvsjdEHtkg==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.10.tgz", + "integrity": "sha512-MiC9CWdPrfhibcXwr39p9ha1x0lZJ9KaVfvzA0Wxwz9ETX4v5CHfF09bx935nHlhi+MxhA63dKRRQLiVgSUtEg==", "cpu": [ "x64" ], @@ -432,9 +587,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.2.tgz", - "integrity": "sha512-MpM6LUVTXAzOvN4KbjzU/q5smzryuoNjlriAIx+06RpecwCkL9JpenNzpKd2YMzLJFOdPqBpuub6eVRP5IgiSA==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.10.tgz", + "integrity": "sha512-JC74bdXcQEpW9KkV326WpZZjLguSZ3DfS8wrrvPMHgQOIEIG/sPXEN/V8IssoJhbefLRcRqw6RQH2NnpdprtMA==", "cpu": [ "arm64" ], @@ -449,9 +604,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.2.tgz", - "integrity": "sha512-5eRPrTX7wFyuWe8FqEFPG2cU0+butQQVNcT4sVipqjLYQjjh8a8+vUTfgBKM88ObB85ahsnTwF7PSIt6PG+QkA==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.10.tgz", + "integrity": "sha512-tguWg1olF6DGqzws97pKZ8G2L7Ig1vjDmGTwcTuYHbuU6TTjJe5FXbgs5C1BBzHbJ2bo1m3WkQDbWO2PvamRcg==", "cpu": [ "x64" ], @@ -466,9 +621,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.2.tgz", - "integrity": "sha512-mLwm4vXKiQ2UTSX4+ImyiPdiHjiZhIaE9QvC7sw0tZ6HoNMjYAqQpGyui5VRIi5sGd+uWq940gdCbY3VLvsO1w==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.10.tgz", + "integrity": "sha512-3ZioSQSg1HT2N05YxeJWYR+Libe3bREVSdWhEEgExWaDtyFbbXWb49QgPvFH8u03vUPX10JhJPcz7s9t9+boWg==", "cpu": [ "arm64" ], @@ -483,9 +638,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.2.tgz", - "integrity": "sha512-6qyyn6TjayJSwGpm8J9QYYGQcRgc90nmfdUb0O7pp1s4lTY+9D0H9O02v5JqGApUyiHOtkz6+1hZNvNtEhbwRQ==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.10.tgz", + "integrity": "sha512-LLgJfHJk014Aa4anGDbh8bmI5Lk+QidDmGzuC2D+vP7mv/GeSN+H39zOf7pN5N8p059FcOfs2bVlrRr4SK9WxA==", "cpu": [ "x64" ], @@ -500,9 +655,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.2.tgz", - "integrity": "sha512-UHBRgJcmjJv5oeQF8EpTRZs/1knq6loLxTsjc3nxO9eXAPDLcWW55flrMVc97qFPbmZP31ta1AZVUKQzKTzb0g==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.10.tgz", + "integrity": "sha512-oR31GtBTFYCqEBALI9r6WxoU/ZofZl962pouZRTEYECvNF/dtXKku8YXcJkhgK/beU+zedXfIzHijSRapJY3vg==", "cpu": [ "arm" ], @@ -517,9 +672,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.2.tgz", - "integrity": "sha512-gq/sjLsOyMT19I8obBISvhoYiZIAaGF8JpeXu1u8yPv8BE5HlWYobmlsfijFIZ9hIVGYkbdFhEqC0NvM4kNO0g==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.10.tgz", + "integrity": "sha512-5luJWN6YKBsawd5f9i4+c+geYiVEw20FVW5x0v1kEMWNq8UctFjDiMATBxLvmmHA4bf7F6hTRaJgtghFr9iziQ==", "cpu": [ "arm64" ], @@ -534,9 +689,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.2.tgz", - "integrity": "sha512-bBYCv9obgW2cBP+2ZWfjYTU+f5cxRoGGQ5SeDbYdFCAZpYWrfjjfYwvUpP8MlKbP0nwZ5gyOU/0aUzZ5HWPuvQ==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.10.tgz", + "integrity": "sha512-NrSCx2Kim3EnnWgS4Txn0QGt0Xipoumb6z6sUtl5bOEZIVKhzfyp/Lyw4C1DIYvzeW/5mWYPBFJU3a/8Yr75DQ==", "cpu": [ "ia32" ], @@ -551,9 +706,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.2.tgz", - "integrity": "sha512-SHNGiKtvnU2dBlM5D8CXRFdd+6etgZ9dXfaPCeJtz+37PIUlixvlIhI23L5khKXs3DIzAn9V8v+qb1TRKrgT5w==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.10.tgz", + "integrity": "sha512-xoSphrd4AZda8+rUDDfD9J6FUMjrkTz8itpTITM4/xgerAZZcFW7Dv+sun7333IfKxGG8gAq+3NbfEMJfiY+Eg==", "cpu": [ "loong64" ], @@ -568,9 +723,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.2.tgz", - "integrity": "sha512-hDDRlzE6rPeoj+5fsADqdUZl1OzqDYow4TB4Y/3PlKBD0ph1e6uPHzIQcv2Z65u2K0kpeByIyAjCmjn1hJgG0Q==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.10.tgz", + "integrity": "sha512-ab6eiuCwoMmYDyTnyptoKkVS3k8fy/1Uvq7Dj5czXI6DF2GqD2ToInBI0SHOp5/X1BdZ26RKc5+qjQNGRBelRA==", "cpu": [ "mips64el" ], @@ -585,9 +740,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.2.tgz", - "integrity": "sha512-tsHu2RRSWzipmUi9UBDEzc0nLc4HtpZEI5Ba+Omms5456x5WaNuiG3u7xh5AO6sipnJ9r4cRWQB2tUjPyIkc6g==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.10.tgz", + "integrity": "sha512-NLinzzOgZQsGpsTkEbdJTCanwA5/wozN9dSgEl12haXJBzMTpssebuXR42bthOF3z7zXFWH1AmvWunUCkBE4EA==", "cpu": [ "ppc64" ], @@ -602,9 +757,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.2.tgz", - "integrity": "sha512-k4LtpgV7NJQOml/10uPU0s4SAXGnowi5qBSjaLWMojNCUICNu7TshqHLAEbkBdAszL5TabfvQ48kK84hyFzjnw==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.10.tgz", + "integrity": "sha512-FE557XdZDrtX8NMIeA8LBJX3dC2M8VGXwfrQWU7LB5SLOajfJIxmSdyL/gU1m64Zs9CBKvm4UAuBp5aJ8OgnrA==", "cpu": [ "riscv64" ], @@ -619,9 +774,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.2.tgz", - "integrity": "sha512-GRa4IshOdvKY7M/rDpRR3gkiTNp34M0eLTaC1a08gNrh4u488aPhuZOCpkF6+2wl3zAN7L7XIpOFBhnaE3/Q8Q==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.10.tgz", + "integrity": "sha512-3BBSbgzuB9ajLoVZk0mGu+EHlBwkusRmeNYdqmznmMc9zGASFjSsxgkNsqmXugpPk00gJ0JNKh/97nxmjctdew==", "cpu": [ "s390x" ], @@ -636,9 +791,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.2.tgz", - "integrity": "sha512-QInHERlqpTTZ4FRB0fROQWXcYRD64lAoiegezDunLpalZMjcUcld3YzZmVJ2H/Cp0wJRZ8Xtjtj0cEHhYc/uUg==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.10.tgz", + "integrity": "sha512-QSX81KhFoZGwenVyPoberggdW1nrQZSvfVDAIUXr3WqLRZGZqWk/P4T8p2SP+de2Sr5HPcvjhcJzEiulKgnxtA==", "cpu": [ "x64" ], @@ -653,9 +808,9 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.2.tgz", - "integrity": "sha512-talAIBoY5M8vHc6EeI2WW9d/CkiO9MQJ0IOWX8hrLhxGbro/vBXJvaQXefW2cP0z0nQVTdQ/eNyGFV1GSKrxfw==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.10.tgz", + "integrity": "sha512-AKQM3gfYfSW8XRk8DdMCzaLUFB15dTrZfnX8WXQoOUpUBQ+NaAFCP1kPS/ykbbGYz7rxn0WS48/81l9hFl3u4A==", "cpu": [ "arm64" ], @@ -670,9 +825,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.2.tgz", - "integrity": "sha512-voZT9Z+tpOxrvfKFyfDYPc4DO4rk06qamv1a/fkuzHpiVBMOhpjK+vBmWM8J1eiB3OLSMFYNaOaBNLXGChf5tg==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.10.tgz", + "integrity": "sha512-7RTytDPGU6fek/hWuN9qQpeGPBZFfB4zZgcz2VK2Z5VpdUxEI8JKYsg3JfO0n/Z1E/6l05n0unDCNc4HnhQGig==", "cpu": [ "x64" ], @@ -687,9 +842,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.2.tgz", - "integrity": "sha512-dcXYOC6NXOqcykeDlwId9kB6OkPUxOEqU+rkrYVqJbK2hagWOMrsTGsMr8+rW02M+d5Op5NNlgMmjzecaRf7Tg==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.10.tgz", + "integrity": "sha512-5Se0VM9Wtq797YFn+dLimf2Zx6McttsH2olUBsDml+lm0GOCRVebRWUvDtkY4BWYv/3NgzS8b/UM3jQNh5hYyw==", "cpu": [ "arm64" ], @@ -704,9 +859,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.2.tgz", - "integrity": "sha512-t/TkWwahkH0Tsgoq1Ju7QfgGhArkGLkF1uYz8nQS/PPFlXbP5YgRpqQR3ARRiC2iXoLTWFxc6DJMSK10dVXluw==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.10.tgz", + "integrity": "sha512-XkA4frq1TLj4bEMB+2HnI0+4RnjbuGZfet2gs/LNs5Hc7D89ZQBHQ0gL2ND6Lzu1+QVkjp3x1gIcPKzRNP8bXw==", "cpu": [ "x64" ], @@ -720,10 +875,27 @@ "node": ">=18" } }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.10.tgz", + "integrity": "sha512-AVTSBhTX8Y/Fz6OmIVBip9tJzZEUcY8WLh7I59+upa5/GPhh2/aM6bvOMQySspnCCHvFi79kMtdJS1w0DXAeag==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@esbuild/sunos-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.2.tgz", - "integrity": "sha512-cfZH1co2+imVdWCjd+D1gf9NjkchVhhdpgb1q5y6Hcv9TP6Zi9ZG/beI3ig8TvwT9lH9dlxLq5MQBBgwuj4xvA==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.10.tgz", + "integrity": "sha512-fswk3XT0Uf2pGJmOpDB7yknqhVkJQkAQOcW/ccVOtfx05LkbWOaRAtn5SaqXypeKQra1QaEa841PgrSL9ubSPQ==", "cpu": [ "x64" ], @@ -738,9 +910,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.2.tgz", - "integrity": "sha512-7Loyjh+D/Nx/sOTzV8vfbB3GJuHdOQyrOryFdZvPHLf42Tk9ivBU5Aedi7iyX+x6rbn2Mh68T4qq1SDqJBQO5Q==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.10.tgz", + "integrity": "sha512-ah+9b59KDTSfpaCg6VdJoOQvKjI33nTaQr4UluQwW7aEwZQsbMCfTmfEO4VyewOxx4RaDT/xCy9ra2GPWmO7Kw==", "cpu": [ "arm64" ], @@ -755,9 +927,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.2.tgz", - "integrity": "sha512-WRJgsz9un0nqZJ4MfhabxaD9Ft8KioqU3JMinOTvobbX6MOSUigSBlogP8QB3uxpJDsFS6yN+3FDBdqE5lg9kg==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.10.tgz", + "integrity": "sha512-QHPDbKkrGO8/cz9LKVnJU22HOi4pxZnZhhA2HYHez5Pz4JeffhDjf85E57Oyco163GnzNCVkZK0b/n4Y0UHcSw==", "cpu": [ "ia32" ], @@ -772,9 +944,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.2.tgz", - "integrity": "sha512-kM3HKb16VIXZyIeVrM1ygYmZBKybX8N4p754bw390wGO3Tf2j4L2/WYL+4suWujpgf6GBYs3jv7TyUivdd05JA==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.10.tgz", + "integrity": "sha512-9KpxSVFCu0iK1owoez6aC/s/EdUQLDN3adTxGCqxMVhrPDj6bt5dbrHDXUuq+Bs2vATFBBrQS5vdQ/Ed2P+nbw==", "cpu": [ "x64" ], @@ -789,39 +961,107 @@ } }, "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz", + "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==", "dev": true, + "license": "MIT", "dependencies": { - "eslint-visitor-keys": "^3.3.0" + "eslint-visitor-keys": "^3.4.3" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, + "funding": { + "url": "https://opencollective.com/eslint" + }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "node_modules/@eslint-community/regexpp": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", - "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", "dev": true, + "license": "MIT", "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, + "node_modules/@eslint/config-array": { + "version": "0.21.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.0.tgz", + "integrity": "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.6", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-array/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.3.1.tgz", + "integrity": "sha512-xR93k9WhrDYpXHORXpxVL5oHj3Era7wo6k/Wd8/IsQNnZUTzkGS29lyn3nAT05v6ltUuTFVCCYDEGfy2Or/sPA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.2.tgz", + "integrity": "sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", + "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", "dev": true, + "license": "MIT", "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", + "espree": "^10.0.1", + "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", @@ -829,35 +1069,31 @@ "strip-json-comments": "^3.1.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" } }, "node_modules/@eslint/eslintrc/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==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, - "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "node_modules/@eslint/eslintrc/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, + "license": "MIT", "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">= 4" } }, "node_modules/@eslint/eslintrc/node_modules/minimatch": { @@ -865,6 +1101,7 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -873,48 +1110,70 @@ } }, "node_modules/@eslint/js": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", - "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", + "version": "9.36.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.36.0.tgz", + "integrity": "sha512-uhCbYtYynH30iZErszX78U+nR3pJU3RHGQ57NXy5QupD4SBVwDeU8TNBy+MjMngc1UyIW9noKqsRqfjQTBU2dw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", + "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", "dev": true, + "license": "Apache-2.0", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.11.14", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", - "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "node_modules/@eslint/plugin-kit": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.5.tgz", + "integrity": "sha512-Z5kJ+wU3oA7MMIqVR9tyZRtjYPr4OC004Q4Rw7pgOKUOKkJfZ3O24nz3WYfGRpMDNmcOi3TwQOmgm7B7Tpii0w==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "@humanwhocodes/object-schema": "^2.0.2", - "debug": "^4.3.1", - "minimatch": "^3.0.5" + "@eslint/core": "^0.15.2", + "levn": "^0.4.1" }, "engines": { - "node": ">=10.10.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@humanwhocodes/config-array/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==", + "node_modules/@floating-ui/utils": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz", + "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==", + "license": "MIT" + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" } }, - "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/@humanfs/node": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", + "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "brace-expansion": "^1.1.7" + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.4.0" }, "engines": { - "node": "*" + "node": ">=18.18.0" } }, "node_modules/@humanwhocodes/module-importer": { @@ -922,6 +1181,7 @@ "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=12.22" }, @@ -930,59 +1190,60 @@ "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", - "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", - "dev": true + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", - "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" } }, "node_modules/@jridgewell/resolve-uri": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", - "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", - "dev": true, + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "dev": true, + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -990,34 +1251,444 @@ } }, "node_modules/@monaco-editor/loader": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@monaco-editor/loader/-/loader-1.4.0.tgz", - "integrity": "sha512-00ioBig0x642hytVspPl7DbQyaSWRaolYie/UFNjoTdvoKPzo6xrXLhTk9ixgIKcLH5b5vDOjVNiGyY+uDCUlg==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@monaco-editor/loader/-/loader-1.5.0.tgz", + "integrity": "sha512-hKoGSM+7aAc7eRTRjpqAZucPmoNOC4UUbknb/VNoTkEIkCPhqV8LfbsgM1webRM7S/z21eHEx9Fkwx8Z/C/+Xw==", + "license": "MIT", "dependencies": { "state-local": "^1.0.6" - }, - "peerDependencies": { - "monaco-editor": ">= 0.21.0 < 1" } }, "node_modules/@monaco-editor/react": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/@monaco-editor/react/-/react-4.6.0.tgz", - "integrity": "sha512-RFkU9/i7cN2bsq/iTkurMWOEErmYcY6JiQI3Jn+WeR/FGISH8JbHERjpS9oRuSOPvDMJI0Z8nJeKkbOs9sBYQw==", + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@monaco-editor/react/-/react-4.7.0.tgz", + "integrity": "sha512-cyzXQCtO47ydzxpQtCGSQGOC8Gk3ZUeBXFAxD+CWXYFo5OqZyZUonFl0DwUlTyAfRHntBfw2p3w4s9R6oe1eCA==", + "license": "MIT", "dependencies": { - "@monaco-editor/loader": "^1.4.0" + "@monaco-editor/loader": "^1.5.0" }, "peerDependencies": { "monaco-editor": ">= 0.25.0 < 1", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, + "node_modules/@mui/core-downloads-tracker": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-7.3.2.tgz", + "integrity": "sha512-AOyfHjyDKVPGJJFtxOlept3EYEdLoar/RvssBTWVAvDJGIE676dLi2oT/Kx+FoVXFoA/JdV7DEMq/BVWV3KHRw==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + } + }, + "node_modules/@mui/icons-material": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-7.3.2.tgz", + "integrity": "sha512-TZWazBjWXBjR6iGcNkbKklnwodcwj0SrChCNHc9BhD9rBgET22J1eFhHsEmvSvru9+opDy3umqAimQjokhfJlQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.28.3" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@mui/material": "^7.3.2", + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/material": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-7.3.2.tgz", + "integrity": "sha512-qXvbnawQhqUVfH1LMgMaiytP+ZpGoYhnGl7yYq2x57GYzcFL/iPzSZ3L30tlbwEjSVKNYcbiKO8tANR1tadjUg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.28.3", + "@mui/core-downloads-tracker": "^7.3.2", + "@mui/system": "^7.3.2", + "@mui/types": "^7.4.6", + "@mui/utils": "^7.3.2", + "@popperjs/core": "^2.11.8", + "@types/react-transition-group": "^4.4.12", + "clsx": "^2.1.1", + "csstype": "^3.1.3", + "prop-types": "^15.8.1", + "react-is": "^19.1.1", + "react-transition-group": "^4.4.5" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@mui/material-pigment-css": "^7.3.2", + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@mui/material-pigment-css": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/material/node_modules/react-is": { + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.1.1.tgz", + "integrity": "sha512-tr41fA15Vn8p4X9ntI+yCyeGSf1TlYaY5vlTZfQmeLBrFo3psOPX6HhTDnFNL9uj3EhP0KAQ80cugCl4b4BERA==", + "license": "MIT" + }, + "node_modules/@mui/private-theming": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-7.3.2.tgz", + "integrity": "sha512-ha7mFoOyZGJr75xeiO9lugS3joRROjc8tG1u4P50dH0KR7bwhHznVMcYg7MouochUy0OxooJm/OOSpJ7gKcMvg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.28.3", + "@mui/utils": "^7.3.2", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/styled-engine": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-7.3.2.tgz", + "integrity": "sha512-PkJzW+mTaek4e0nPYZ6qLnW5RGa0KN+eRTf5FA2nc7cFZTeM+qebmGibaTLrgQBy3UpcpemaqfzToBNkzuxqew==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.28.3", + "@emotion/cache": "^11.14.0", + "@emotion/serialize": "^1.3.3", + "@emotion/sheet": "^1.4.0", + "csstype": "^3.1.3", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.4.1", + "@emotion/styled": "^11.3.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + } + } + }, + "node_modules/@mui/system": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-7.3.2.tgz", + "integrity": "sha512-9d8JEvZW+H6cVkaZ+FK56R53vkJe3HsTpcjMUtH8v1xK6Y1TjzHdZ7Jck02mGXJsE6MQGWVs3ogRHTQmS9Q/rA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.28.3", + "@mui/private-theming": "^7.3.2", + "@mui/styled-engine": "^7.3.2", + "@mui/types": "^7.4.6", + "@mui/utils": "^7.3.2", + "clsx": "^2.1.1", + "csstype": "^3.1.3", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/types": { + "version": "7.4.7", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.4.7.tgz", + "integrity": "sha512-8vVje9rdEr1rY8oIkYgP+Su5Kwl6ik7O3jQ0wl78JGSmiZhRHV+vkjooGdKD8pbtZbutXFVTWQYshu2b3sG9zw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.28.4" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/utils": { + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-7.3.3.tgz", + "integrity": "sha512-kwNAUh7bLZ7mRz9JZ+6qfRnnxbE4Zuc+RzXnhSpRSxjTlSTj7b4JxRLXpG+MVtPVtqks5k/XC8No1Vs3x4Z2gg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.28.4", + "@mui/types": "^7.4.7", + "@types/prop-types": "^15.7.15", + "clsx": "^2.1.1", + "prop-types": "^15.8.1", + "react-is": "^19.1.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/utils/node_modules/react-is": { + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.1.1.tgz", + "integrity": "sha512-tr41fA15Vn8p4X9ntI+yCyeGSf1TlYaY5vlTZfQmeLBrFo3psOPX6HhTDnFNL9uj3EhP0KAQ80cugCl4b4BERA==", + "license": "MIT" + }, + "node_modules/@mui/x-data-grid": { + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/@mui/x-data-grid/-/x-data-grid-8.14.0.tgz", + "integrity": "sha512-bzUpD83Wx4mawkgquDQUUbLLnpF+JP7Pe7YQx1ixS6W/AlUwXAVagPTOijwchHvlx0Ky11dJvOQAfrnWu6an/Q==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.28.4", + "@mui/utils": "^7.3.3", + "@mui/x-internals": "8.14.0", + "@mui/x-virtualizer": "0.2.3", + "clsx": "^2.1.1", + "prop-types": "^15.8.1", + "use-sync-external-store": "^1.6.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.9.0", + "@emotion/styled": "^11.8.1", + "@mui/material": "^5.15.14 || ^6.0.0 || ^7.0.0", + "@mui/system": "^5.15.14 || ^6.0.0 || ^7.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + } + } + }, + "node_modules/@mui/x-data-grid/node_modules/@mui/x-internals": { + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/@mui/x-internals/-/x-internals-8.14.0.tgz", + "integrity": "sha512-esYyl61nuuFXiN631TWuPh2tqdoyTdBI/4UXgwH3rytF8jiWvy6prPBPRHEH1nvW3fgw9FoBI48FlOO+yEI8xg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.28.4", + "@mui/utils": "^7.3.3", + "reselect": "^5.1.1", + "use-sync-external-store": "^1.6.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/@mui/x-internals": { + "version": "8.13.1", + "resolved": "https://registry.npmjs.org/@mui/x-internals/-/x-internals-8.13.1.tgz", + "integrity": "sha512-OKQyCJ9uxtMpjBZCOEQGOR5MhgL1f9HjI4qZHuaLxxtDATK5rcBbVjBF67hI8FzXeF1wrcZP2wsjc4AgGpAo9g==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.28.4", + "@mui/utils": "^7.3.2", + "reselect": "^5.1.1", + "use-sync-external-store": "^1.5.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/@mui/x-tree-view": { + "version": "8.13.1", + "resolved": "https://registry.npmjs.org/@mui/x-tree-view/-/x-tree-view-8.13.1.tgz", + "integrity": "sha512-i5GrIMbNZRGEIYpJDC+d8TStANmvQpwIGYbsGTczrM+6x3KCkASahURgSraZVBfAAxJ2sm55rbrG+6jtkbq5HQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.28.4", + "@base-ui-components/utils": "0.1.1", + "@mui/utils": "^7.3.2", + "@mui/x-internals": "8.13.1", + "@types/react-transition-group": "^4.4.12", + "clsx": "^2.1.1", + "prop-types": "^15.8.1", + "react-transition-group": "^4.4.5" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.9.0", + "@emotion/styled": "^11.8.1", + "@mui/material": "^5.15.14 || ^6.0.0 || ^7.0.0", + "@mui/system": "^5.15.14 || ^6.0.0 || ^7.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + } + } + }, + "node_modules/@mui/x-virtualizer": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@mui/x-virtualizer/-/x-virtualizer-0.2.3.tgz", + "integrity": "sha512-CZ+VxFmeJaTduAOlSyo5cVek0PV5Y8gm4coyaHEpCvms207J9AoMUKqWIcdwsVGlTH1Y71j35xT/MwHKutZiNw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.28.4", + "@mui/utils": "^7.3.3", + "@mui/x-internals": "8.14.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/@mui/x-virtualizer/node_modules/@mui/x-internals": { + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/@mui/x-internals/-/x-internals-8.14.0.tgz", + "integrity": "sha512-esYyl61nuuFXiN631TWuPh2tqdoyTdBI/4UXgwH3rytF8jiWvy6prPBPRHEH1nvW3fgw9FoBI48FlOO+yEI8xg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.28.4", + "@mui/utils": "^7.3.3", + "reselect": "^5.1.1", + "use-sync-external-store": "^1.6.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" @@ -1031,6 +1702,7 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true, + "license": "MIT", "engines": { "node": ">= 8" } @@ -1040,6 +1712,7 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" @@ -1048,6 +1721,16 @@ "node": ">= 8" } }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, "node_modules/@react-dnd/asap": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/@react-dnd/asap/-/asap-5.0.2.tgz", @@ -1066,10 +1749,17 @@ "integrity": "sha512-/RVXdLvJxLg4QKvMoM5WlwNR9ViO9z8B/qPcc+C0Sa/teJY7QG7kJ441DwzOjMYEY7GmU4dj5EcGHIkKZiQZCA==", "license": "MIT" }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.35", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.35.tgz", + "integrity": "sha512-slYrCpoxJUqzFDDNlvrOYRazQUNRvWPjXA17dAOISY3rDMxX6k8K4cj2H+hEYMHF81HO3uNd5rHVigAWRM5dSg==", + "dev": true, + "license": "MIT" + }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.38.0.tgz", - "integrity": "sha512-ldomqc4/jDZu/xpYU+aRxo3V4mGCV9HeTgUBANI3oIQMOL+SsxB+S2lxMpkFp5UamSS3XuTMQVbsS24R4J4Qjg==", + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.52.2.tgz", + "integrity": "sha512-o3pcKzJgSGt4d74lSZ+OCnHwkKBeAbFDmbEm5gg70eA8VkyCuC/zV9TwBnmw6VjDlRdF4Pshfb+WE9E6XY1PoQ==", "cpu": [ "arm" ], @@ -1081,9 +1771,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.38.0.tgz", - "integrity": "sha512-VUsgcy4GhhT7rokwzYQP+aV9XnSLkkhlEJ0St8pbasuWO/vwphhZQxYEKUP3ayeCYLhk6gEtacRpYP/cj3GjyQ==", + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.52.2.tgz", + "integrity": "sha512-cqFSWO5tX2vhC9hJTK8WAiPIm4Q8q/cU8j2HQA0L3E1uXvBYbOZMhE2oFL8n2pKB5sOCHY6bBuHaRwG7TkfJyw==", "cpu": [ "arm64" ], @@ -1095,9 +1785,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.38.0.tgz", - "integrity": "sha512-buA17AYXlW9Rn091sWMq1xGUvWQFOH4N1rqUxGJtEQzhChxWjldGCCup7r/wUnaI6Au8sKXpoh0xg58a7cgcpg==", + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.52.2.tgz", + "integrity": "sha512-vngduywkkv8Fkh3wIZf5nFPXzWsNsVu1kvtLETWxTFf/5opZmflgVSeLgdHR56RQh71xhPhWoOkEBvbehwTlVA==", "cpu": [ "arm64" ], @@ -1109,9 +1799,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.38.0.tgz", - "integrity": "sha512-Mgcmc78AjunP1SKXl624vVBOF2bzwNWFPMP4fpOu05vS0amnLcX8gHIge7q/lDAHy3T2HeR0TqrriZDQS2Woeg==", + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.52.2.tgz", + "integrity": "sha512-h11KikYrUCYTrDj6h939hhMNlqU2fo/X4NB0OZcys3fya49o1hmFaczAiJWVAFgrM1NCP6RrO7lQKeVYSKBPSQ==", "cpu": [ "x64" ], @@ -1123,9 +1813,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.38.0.tgz", - "integrity": "sha512-zzJACgjLbQTsscxWqvrEQAEh28hqhebpRz5q/uUd1T7VTwUNZ4VIXQt5hE7ncs0GrF+s7d3S4on4TiXUY8KoQA==", + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.52.2.tgz", + "integrity": "sha512-/eg4CI61ZUkLXxMHyVlmlGrSQZ34xqWlZNW43IAU4RmdzWEx0mQJ2mN/Cx4IHLVZFL6UBGAh+/GXhgvGb+nVxw==", "cpu": [ "arm64" ], @@ -1137,9 +1827,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.38.0.tgz", - "integrity": "sha512-hCY/KAeYMCyDpEE4pTETam0XZS4/5GXzlLgpi5f0IaPExw9kuB+PDTOTLuPtM10TlRG0U9OSmXJ+Wq9J39LvAg==", + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.52.2.tgz", + "integrity": "sha512-QOWgFH5X9+p+S1NAfOqc0z8qEpJIoUHf7OWjNUGOeW18Mx22lAUOiA9b6r2/vpzLdfxi/f+VWsYjUOMCcYh0Ng==", "cpu": [ "x64" ], @@ -1151,9 +1841,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.38.0.tgz", - "integrity": "sha512-mimPH43mHl4JdOTD7bUMFhBdrg6f9HzMTOEnzRmXbOZqjijCw8LA5z8uL6LCjxSa67H2xiLFvvO67PT05PRKGg==", + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.52.2.tgz", + "integrity": "sha512-kDWSPafToDd8LcBYd1t5jw7bD5Ojcu12S3uT372e5HKPzQt532vW+rGFFOaiR0opxePyUkHrwz8iWYEyH1IIQA==", "cpu": [ "arm" ], @@ -1165,9 +1855,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.38.0.tgz", - "integrity": "sha512-tPiJtiOoNuIH8XGG8sWoMMkAMm98PUwlriOFCCbZGc9WCax+GLeVRhmaxjJtz6WxrPKACgrwoZ5ia/uapq3ZVg==", + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.52.2.tgz", + "integrity": "sha512-gKm7Mk9wCv6/rkzwCiUC4KnevYhlf8ztBrDRT9g/u//1fZLapSRc+eDZj2Eu2wpJ+0RzUKgtNijnVIB4ZxyL+w==", "cpu": [ "arm" ], @@ -1179,9 +1869,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.38.0.tgz", - "integrity": "sha512-wZco59rIVuB0tjQS0CSHTTUcEde+pXQWugZVxWaQFdQQ1VYub/sTrNdY76D1MKdN2NB48JDuGABP6o6fqos8mA==", + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.52.2.tgz", + "integrity": "sha512-66lA8vnj5mB/rtDNwPgrrKUOtCLVQypkyDa2gMfOefXK6rcZAxKLO9Fy3GkW8VkPnENv9hBkNOFfGLf6rNKGUg==", "cpu": [ "arm64" ], @@ -1193,9 +1883,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.38.0.tgz", - "integrity": "sha512-fQgqwKmW0REM4LomQ+87PP8w8xvU9LZfeLBKybeli+0yHT7VKILINzFEuggvnV9M3x1Ed4gUBmGUzCo/ikmFbQ==", + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.52.2.tgz", + "integrity": "sha512-s+OPucLNdJHvuZHuIz2WwncJ+SfWHFEmlC5nKMUgAelUeBUnlB4wt7rXWiyG4Zn07uY2Dd+SGyVa9oyLkVGOjA==", "cpu": [ "arm64" ], @@ -1206,10 +1896,10 @@ "linux" ] }, - "node_modules/@rollup/rollup-linux-loongarch64-gnu": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.38.0.tgz", - "integrity": "sha512-hz5oqQLXTB3SbXpfkKHKXLdIp02/w3M+ajp8p4yWOWwQRtHWiEOCKtc9U+YXahrwdk+3qHdFMDWR5k+4dIlddg==", + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.52.2.tgz", + "integrity": "sha512-8wTRM3+gVMDLLDdaT6tKmOE3lJyRy9NpJUS/ZRWmLCmOPIJhVyXwjBo+XbrrwtV33Em1/eCTd5TuGJm4+DmYjw==", "cpu": [ "loong64" ], @@ -1220,10 +1910,10 @@ "linux" ] }, - "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.38.0.tgz", - "integrity": "sha512-NXqygK/dTSibQ+0pzxsL3r4Xl8oPqVoWbZV9niqOnIHV/J92fe65pOir0xjkUZDRSPyFRvu+4YOpJF9BZHQImw==", + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.52.2.tgz", + "integrity": "sha512-6yqEfgJ1anIeuP2P/zhtfBlDpXUb80t8DpbYwXQ3bQd95JMvUaqiX+fKqYqUwZXqdJDd8xdilNtsHM2N0cFm6A==", "cpu": [ "ppc64" ], @@ -1235,9 +1925,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.38.0.tgz", - "integrity": "sha512-GEAIabR1uFyvf/jW/5jfu8gjM06/4kZ1W+j1nWTSSB3w6moZEBm7iBtzwQ3a1Pxos2F7Gz+58aVEnZHU295QTg==", + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.52.2.tgz", + "integrity": "sha512-sshYUiYVSEI2B6dp4jMncwxbrUqRdNApF2c3bhtLAU0qA8Lrri0p0NauOsTWh3yCCCDyBOjESHMExonp7Nzc0w==", "cpu": [ "riscv64" ], @@ -1249,9 +1939,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.38.0.tgz", - "integrity": "sha512-9EYTX+Gus2EGPbfs+fh7l95wVADtSQyYw4DfSBcYdUEAmP2lqSZY0Y17yX/3m5VKGGJ4UmIH5LHLkMJft3bYoA==", + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.52.2.tgz", + "integrity": "sha512-duBLgd+3pqC4MMwBrKkFxaZerUxZcYApQVC5SdbF5/e/589GwVvlRUnyqMFbM8iUSb1BaoX/3fRL7hB9m2Pj8Q==", "cpu": [ "riscv64" ], @@ -1263,9 +1953,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.38.0.tgz", - "integrity": "sha512-Mpp6+Z5VhB9VDk7RwZXoG2qMdERm3Jw07RNlXHE0bOnEeX+l7Fy4bg+NxfyN15ruuY3/7Vrbpm75J9QHFqj5+Q==", + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.52.2.tgz", + "integrity": "sha512-tzhYJJidDUVGMgVyE+PmxENPHlvvqm1KILjjZhB8/xHYqAGeizh3GBGf9u6WdJpZrz1aCpIIHG0LgJgH9rVjHQ==", "cpu": [ "s390x" ], @@ -1277,9 +1967,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.38.0.tgz", - "integrity": "sha512-vPvNgFlZRAgO7rwncMeE0+8c4Hmc+qixnp00/Uv3ht2x7KYrJ6ERVd3/R0nUtlE6/hu7/HiiNHJ/rP6knRFt1w==", + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.52.2.tgz", + "integrity": "sha512-opH8GSUuVcCSSyHHcl5hELrmnk4waZoVpgn/4FDao9iyE4WpQhyWJ5ryl5M3ocp4qkRuHfyXnGqg8M9oKCEKRA==", "cpu": [ "x64" ], @@ -1291,9 +1981,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.38.0.tgz", - "integrity": "sha512-q5Zv+goWvQUGCaL7fU8NuTw8aydIL/C9abAVGCzRReuj5h30TPx4LumBtAidrVOtXnlB+RZkBtExMsfqkMfb8g==", + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.52.2.tgz", + "integrity": "sha512-LSeBHnGli1pPKVJ79ZVJgeZWWZXkEe/5o8kcn23M8eMKCUANejchJbF/JqzM4RRjOJfNRhKJk8FuqL1GKjF5oQ==", "cpu": [ "x64" ], @@ -1304,10 +1994,24 @@ "linux" ] }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.52.2.tgz", + "integrity": "sha512-uPj7MQ6/s+/GOpolavm6BPo+6CbhbKYyZHUDvZ/SmJM7pfDBgdGisFX3bY/CBDMg2ZO4utfhlApkSfZ92yXw7Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.38.0.tgz", - "integrity": "sha512-u/Jbm1BU89Vftqyqbmxdq14nBaQjQX1HhmsdBWqSdGClNaKwhjsg5TpW+5Ibs1mb8Es9wJiMdl86BcmtUVXNZg==", + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.52.2.tgz", + "integrity": "sha512-Z9MUCrSgIaUeeHAiNkm3cQyst2UhzjPraR3gYYfOjAuZI7tcFRTOD+4cHLPoS/3qinchth+V56vtqz1Tv+6KPA==", "cpu": [ "arm64" ], @@ -1319,9 +2023,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.38.0.tgz", - "integrity": "sha512-mqu4PzTrlpNHHbu5qleGvXJoGgHpChBlrBx/mEhTPpnAL1ZAYFlvHD7rLK839LLKQzqEQMFJfGrrOHItN4ZQqA==", + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.52.2.tgz", + "integrity": "sha512-+GnYBmpjldD3XQd+HMejo+0gJGwYIOfFeoBQv32xF/RUIvccUz20/V6Otdv+57NE70D5pa8W/jVGDoGq0oON4A==", "cpu": [ "ia32" ], @@ -1332,10 +2036,24 @@ "win32" ] }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.52.2.tgz", + "integrity": "sha512-ApXFKluSB6kDQkAqZOKXBjiaqdF1BlKi+/eqnYe9Ee7U2K3pUDKsIyr8EYm/QDHTJIM+4X+lI0gJc3TTRhd+dA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.38.0.tgz", - "integrity": "sha512-jjqy3uWlecfB98Psxb5cD6Fny9Fupv9LrDSPTQZUROqjvZmcCqNu4UMl7qqhlUUGpwiAkotj6GYu4SZdcr/nLw==", + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.52.2.tgz", + "integrity": "sha512-ARz+Bs8kY6FtitYM96PqPEVvPXqEZmPZsSkXvyX19YzDqkCaIlhCieLLMI5hxO9SRZ2XtCtm8wxhy0iJ2jxNfw==", "cpu": [ "x64" ], @@ -1351,6 +2069,7 @@ "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", @@ -1360,10 +2079,11 @@ } }, "node_modules/@types/babel__generator": { - "version": "7.6.8", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", - "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/types": "^7.0.0" } @@ -1373,92 +2093,82 @@ "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", "dev": true, + "license": "MIT", "dependencies": { "@babel/parser": "^7.1.0", "@babel/types": "^7.0.0" } }, "node_modules/@types/babel__traverse": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.5.tgz", - "integrity": "sha512-WXCyOcRtH37HAUkpXhUduaxdm82b4GSlyTqajXviN4EfiuPgNYR109xMCKvpl6zPIpua0DGlMEDCq+g8EdoheQ==", + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.20.7" + "@babel/types": "^7.28.2" } }, "node_modules/@types/estree": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", - "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", "dev": true, "license": "MIT" }, - "node_modules/@types/http-proxy": { - "version": "1.17.15", - "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.15.tgz", - "integrity": "sha512-25g5atgiVNTIv0LBDTg1H74Hvayx0ajtJPLLcYE3whFv75J0pWNtOBzaXJQgDTmrX1bx5U9YC2w/n65BN1HwRQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/http-proxy-middleware": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@types/http-proxy-middleware/-/http-proxy-middleware-1.0.0.tgz", - "integrity": "sha512-/s8lFX6rT43hSPqjjD8KNuu0SkPKY7uIdR6u9DCxVqCRhAvfKxGbVOixJsAT2mdpSnCyrGFAGoB39KFh6tmRxw==", - "deprecated": "This is a stub types definition. http-proxy-middleware provides its own type definitions, so you do not need this installed.", - "dev": true, - "dependencies": { - "http-proxy-middleware": "*" - } - }, "node_modules/@types/json-schema": { "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true + "dev": true, + "license": "MIT" }, - "node_modules/@types/node": { - "version": "20.12.12", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.12.tgz", - "integrity": "sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw==", - "devOptional": true, - "dependencies": { - "undici-types": "~5.26.4" - } + "node_modules/@types/parse-json": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", + "license": "MIT" }, "node_modules/@types/prop-types": { - "version": "15.7.12", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", - "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==", - "devOptional": true + "version": "15.7.15", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", + "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", + "license": "MIT" }, "node_modules/@types/react": { - "version": "18.2.74", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.74.tgz", - "integrity": "sha512-9AEqNZZyBx8OdZpxzQlaFEVCSFUM2YXJH46yPOiOpm078k6ZLOCcuAzGum/zK8YBwY+dbahVNbHrbgrAwIRlqw==", - "devOptional": true, + "version": "19.1.13", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.13.tgz", + "integrity": "sha512-hHkbU/eoO3EG5/MZkuFSKmYqPbSVk5byPFa3e7y/8TybHiLMACgI8seVYlicwk7H5K/rI2px9xrQp/C+AUDTiQ==", + "license": "MIT", "dependencies": { - "@types/prop-types": "*", "csstype": "^3.0.2" } }, "node_modules/@types/react-dom": { - "version": "18.2.24", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.24.tgz", - "integrity": "sha512-cN6upcKd8zkGy4HU9F1+/s98Hrp6D4MOcippK4PoE8OZRngohHZpbJn1GsaDLz87MqvHNoT13nHvNqM9ocRHZg==", + "version": "19.1.9", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.9.tgz", + "integrity": "sha512-qXRuZaOsAdXKFyOhRBg6Lqqc0yay13vN7KrIg4L7N4aaHN68ma9OK3NE1BoDFgFOTfM7zg+3/8+2n8rLUH3OKQ==", "dev": true, - "dependencies": { + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.0.0" + } + }, + "node_modules/@types/react-transition-group": { + "version": "4.4.12", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.12.tgz", + "integrity": "sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==", + "license": "MIT", + "peerDependencies": { "@types/react": "*" } }, - "node_modules/@types/semver": { - "version": "7.5.8", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", - "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", - "dev": true + "node_modules/@types/trusted-types": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-1.0.6.tgz", + "integrity": "sha512-230RC8sFeHoT6sSUlRO6a8cAnclO06eeiq1QDfiv2FGCLWFvvERWgwIQD4FWqD9A69BN7Lzee4OXwoMVnnsWDw==", + "license": "MIT", + "peer": true }, "node_modules/@types/uuid": { "version": "8.3.4", @@ -1467,119 +2177,150 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.5.0.tgz", - "integrity": "sha512-HpqNTH8Du34nLxbKgVMGljZMG0rJd2O9ecvr2QLYp+7512ty1j42KnsFwspPXg1Vh8an9YImf6CokUBltisZFQ==", + "version": "8.44.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.44.1.tgz", + "integrity": "sha512-molgphGqOBT7t4YKCSkbasmu1tb1MgrZ2szGzHbclF7PNmOkSTQVHy+2jXOSnxvR3+Xe1yySHFZoqMpz3TfQsw==", "dev": true, + "license": "MIT", "dependencies": { - "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "7.5.0", - "@typescript-eslint/type-utils": "7.5.0", - "@typescript-eslint/utils": "7.5.0", - "@typescript-eslint/visitor-keys": "7.5.0", - "debug": "^4.3.4", + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.44.1", + "@typescript-eslint/type-utils": "8.44.1", + "@typescript-eslint/utils": "8.44.1", + "@typescript-eslint/visitor-keys": "8.44.1", "graphemer": "^1.4.0", - "ignore": "^5.2.4", + "ignore": "^7.0.0", "natural-compare": "^1.4.0", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" + "ts-api-utils": "^2.1.0" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^7.0.0", - "eslint": "^8.56.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "@typescript-eslint/parser": "^8.44.1", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/parser": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.5.0.tgz", - "integrity": "sha512-cj+XGhNujfD2/wzR1tabNsidnYRaFfEkcULdcIyVBYcXjBvBKOes+mpMBP7hMpOyk+gBcfXsrg4NBGAStQyxjQ==", + "version": "8.44.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.44.1.tgz", + "integrity": "sha512-EHrrEsyhOhxYt8MTg4zTF+DJMuNBzWwgvvOYNj/zm1vnaD/IC5zCXFehZv94Piqa2cRFfXrTFxIvO95L7Qc/cw==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "7.5.0", - "@typescript-eslint/types": "7.5.0", - "@typescript-eslint/typescript-estree": "7.5.0", - "@typescript-eslint/visitor-keys": "7.5.0", + "@typescript-eslint/scope-manager": "8.44.1", + "@typescript-eslint/types": "8.44.1", + "@typescript-eslint/typescript-estree": "8.44.1", + "@typescript-eslint/visitor-keys": "8.44.1", "debug": "^4.3.4" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.56.0" + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.44.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.44.1.tgz", + "integrity": "sha512-ycSa60eGg8GWAkVsKV4E6Nz33h+HjTXbsDT4FILyL8Obk5/mx4tbvCNsLf9zret3ipSumAOG89UcCs/KRaKYrA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.44.1", + "@typescript-eslint/types": "^8.44.1", + "debug": "^4.3.4" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.5.0.tgz", - "integrity": "sha512-Z1r7uJY0MDeUlql9XJ6kRVgk/sP11sr3HKXn268HZyqL7i4cEfrdFuSSY/0tUqT37l5zT0tJOsuDP16kio85iA==", + "version": "8.44.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.44.1.tgz", + "integrity": "sha512-NdhWHgmynpSvyhchGLXh+w12OMT308Gm25JoRIyTZqEbApiBiQHD/8xgb6LqCWCFcxFtWwaVdFsLPQI3jvhywg==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "7.5.0", - "@typescript-eslint/visitor-keys": "7.5.0" + "@typescript-eslint/types": "8.44.1", + "@typescript-eslint/visitor-keys": "8.44.1" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.44.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.44.1.tgz", + "integrity": "sha512-B5OyACouEjuIvof3o86lRMvyDsFwZm+4fBOqFHccIctYgBjqR3qT39FBYGN87khcgf0ExpdCBeGKpKRhSFTjKQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, "node_modules/@typescript-eslint/type-utils": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.5.0.tgz", - "integrity": "sha512-A021Rj33+G8mx2Dqh0nMO9GyjjIBK3MqgVgZ2qlKf6CJy51wY/lkkFqq3TqqnH34XyAHUkq27IjlUkWlQRpLHw==", + "version": "8.44.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.44.1.tgz", + "integrity": "sha512-KdEerZqHWXsRNKjF9NYswNISnFzXfXNDfPxoTh7tqohU/PRIbwTmsjGK6V9/RTYWau7NZvfo52lgVk+sJh0K3g==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "7.5.0", - "@typescript-eslint/utils": "7.5.0", + "@typescript-eslint/types": "8.44.1", + "@typescript-eslint/typescript-estree": "8.44.1", + "@typescript-eslint/utils": "8.44.1", "debug": "^4.3.4", - "ts-api-utils": "^1.0.1" + "ts-api-utils": "^2.1.0" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.56.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/types": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.5.0.tgz", - "integrity": "sha512-tv5B4IHeAdhR7uS4+bf8Ov3k793VEVHd45viRRkehIUZxm0WF82VPiLgHzA/Xl4TGPg1ZD49vfxBKFPecD5/mg==", + "version": "8.44.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.44.1.tgz", + "integrity": "sha512-Lk7uj7y9uQUOEguiDIDLYLJOrYHQa7oBiURYVFqIpGxclAFQ78f6VUOM8lI2XEuNOKNB7XuvM2+2cMXAoq4ALQ==", "dev": true, + "license": "MIT", "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", @@ -1587,106 +2328,116 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.5.0.tgz", - "integrity": "sha512-YklQQfe0Rv2PZEueLTUffiQGKQneiIEKKnfIqPIOxgM9lKSZFCjT5Ad4VqRKj/U4+kQE3fa8YQpskViL7WjdPQ==", + "version": "8.44.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.44.1.tgz", + "integrity": "sha512-qnQJ+mVa7szevdEyvfItbO5Vo+GfZ4/GZWWDRRLjrxYPkhM+6zYB2vRYwCsoJLzqFCdZT4mEqyJoyzkunsZ96A==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "7.5.0", - "@typescript-eslint/visitor-keys": "7.5.0", + "@typescript-eslint/project-service": "8.44.1", + "@typescript-eslint/tsconfig-utils": "8.44.1", + "@typescript-eslint/types": "8.44.1", + "@typescript-eslint/visitor-keys": "8.44.1", "debug": "^4.3.4", - "globby": "^11.1.0", + "fast-glob": "^3.3.2", "is-glob": "^4.0.3", - "minimatch": "9.0.3", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^2.1.0" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/utils": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.5.0.tgz", - "integrity": "sha512-3vZl9u0R+/FLQcpy2EHyRGNqAS/ofJ3Ji8aebilfJe+fobK8+LbIFmrHciLVDxjDoONmufDcnVSF38KwMEOjzw==", + "version": "8.44.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.44.1.tgz", + "integrity": "sha512-DpX5Fp6edTlocMCwA+mHY8Mra+pPjRZ0TfHkXI8QFelIKcbADQz1LUPNtzOFUriBB2UYqw4Pi9+xV4w9ZczHFg==", "dev": true, + "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@types/json-schema": "^7.0.12", - "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "7.5.0", - "@typescript-eslint/types": "7.5.0", - "@typescript-eslint/typescript-estree": "7.5.0", - "semver": "^7.5.4" + "@eslint-community/eslint-utils": "^4.7.0", + "@typescript-eslint/scope-manager": "8.44.1", + "@typescript-eslint/types": "8.44.1", + "@typescript-eslint/typescript-estree": "8.44.1" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.56.0" + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.5.0.tgz", - "integrity": "sha512-mcuHM/QircmA6O7fy6nn2w/3ditQkj+SgtOc8DW3uQ10Yfj42amm2i+6F2K4YAOPNNTmE6iM1ynM6lrSwdendA==", + "version": "8.44.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.44.1.tgz", + "integrity": "sha512-576+u0QD+Jp3tZzvfRfxon0EA2lzcDt3lhUbsC6Lgzy9x2VR4E+JUiNyGHi5T8vk0TV+fpJ5GLG1JsJuWCaKhw==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "7.5.0", - "eslint-visitor-keys": "^3.4.1" + "@typescript-eslint/types": "8.44.1", + "eslint-visitor-keys": "^4.2.1" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@ungap/structured-clone": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", - "dev": true + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } }, "node_modules/@vitejs/plugin-react": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.3.4.tgz", - "integrity": "sha512-SCCPBJtYLdE8PX/7ZQAs1QAZ8Jqwih+0VBLum1EGqmCCQal+MIUqLCzj3ZUy8ufbC0cAM4LRlSTm7IQJwWT4ug==", + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.0.3.tgz", + "integrity": "sha512-PFVHhosKkofGH0Yzrw1BipSedTH68BFF8ZWy1kfUpCtJcouXXY0+racG8sExw7hw0HoX36813ga5o3LTWZ4FUg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/core": "^7.26.0", - "@babel/plugin-transform-react-jsx-self": "^7.25.9", - "@babel/plugin-transform-react-jsx-source": "^7.25.9", + "@babel/core": "^7.28.4", + "@babel/plugin-transform-react-jsx-self": "^7.27.1", + "@babel/plugin-transform-react-jsx-source": "^7.27.1", + "@rolldown/pluginutils": "1.0.0-beta.35", "@types/babel__core": "^7.20.5", - "react-refresh": "^0.14.2" + "react-refresh": "^0.17.0" }, "engines": { - "node": "^14.18.0 || >=16.0.0" + "node": "^20.19.0 || >=22.12.0" }, "peerDependencies": { - "vite": "^4.2.0 || ^5.0.0 || ^6.0.0" + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, "node_modules/acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, + "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -1699,6 +2450,7 @@ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, + "license": "MIT", "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } @@ -1708,6 +2460,7 @@ "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", @@ -1719,35 +2472,44 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "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, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, "node_modules/antlr4-c3": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/antlr4-c3/-/antlr4-c3-3.4.1.tgz", - "integrity": "sha512-YLO/ncwUp8w2GNK/lnsYXtMkd8izHCWjxtk7EaTGIZq07THfvI5aHDuhls/RctX3EYDlM9zeTKdqn54eLYNglQ==", + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/antlr4-c3/-/antlr4-c3-3.4.4.tgz", + "integrity": "sha512-ixp1i17ypbRzZnffdarIfCVEXJwPydtDt61SHMGkc+UCD7rrbfvHESTMTgx8jFhUgKAgcHyt9060kQ8nU3vlxA==", + "license": "MIT", "dependencies": { - "antlr4ng": "^3.0.1" + "antlr4ng": "3.0.16" } }, "node_modules/antlr4ng": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/antlr4ng/-/antlr4ng-3.0.4.tgz", - "integrity": "sha512-u1Ww6wVv9hq70E9AaYe5qW3ba8hvnjJdO3ZsKnb3iJWFV/medLEEhbyWwXCvvD2ef0ptdaiIUgmaazS/WE6uyQ==", - "peerDependencies": { - "antlr4ng-cli": "^2.0.0" - } + "version": "3.0.16", + "resolved": "https://registry.npmjs.org/antlr4ng/-/antlr4ng-3.0.16.tgz", + "integrity": "sha512-DQuJkC7kX3xunfF4K2KsWTSvoxxslv+FQp/WHQZTJSsH2Ec3QfFmrxC3Nky2ok9yglXn6nHM4zUaVDxcN5f6kA==", + "license": "BSD-3-Clause" }, "node_modules/antlr4ng-cli": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/antlr4ng-cli/-/antlr4ng-cli-2.0.0.tgz", "integrity": "sha512-oAt5OSSYhRQn1PgahtpAP4Vp3BApCoCqlzX7Q8ZUWWls4hX59ryYuu0t7Hwrnfk796OxP/vgIJaqxdltd/oEvQ==", + "deprecated": "This package is deprecated and will no longer be updated. Please use the new antlr-ng package instead: https://github.com/mike-lischke/antlr-ng", + "dev": true, + "license": "BSD-3-Clause", "bin": { "antlr4ng": "index.js" } @@ -1755,28 +2517,47 @@ "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "license": "Python-2.0" }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, + "node_modules/babel-plugin-macros": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", + "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.5", + "cosmiconfig": "^7.0.0", + "resolve": "^1.19.0" + }, "engines": { - "node": ">=8" + "node": ">=10", + "npm": ">=6" } }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.8.7", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.7.tgz", + "integrity": "sha512-bxxN2M3a4d1CRoQC//IqsR5XrLh0IJ8TCv2x6Y9N0nckNz/rTjZB3//GGscZziZOxmjP55rzxg/ze7usFI9FqQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.js" + } }, "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==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } @@ -1795,9 +2576,9 @@ } }, "node_modules/browserslist": { - "version": "4.24.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz", - "integrity": "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==", + "version": "4.26.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.26.2.tgz", + "integrity": "sha512-ECFzp6uFOSB+dcZ5BK/IBaGWssbSYBHvuMeMt3MMFyhI0Z8SqGgEkBLARgpRH3hutIgPVsALcMwbDrJqPxQ65A==", "dev": true, "funding": [ { @@ -1815,10 +2596,11 @@ ], "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001688", - "electron-to-chromium": "^1.5.73", - "node-releases": "^2.0.19", - "update-browserslist-db": "^1.1.1" + "baseline-browser-mapping": "^2.8.3", + "caniuse-lite": "^1.0.30001741", + "electron-to-chromium": "^1.5.218", + "node-releases": "^2.0.21", + "update-browserslist-db": "^1.1.3" }, "bin": { "browserslist": "cli.js" @@ -1831,15 +2613,15 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/caniuse-lite": { - "version": "1.0.30001707", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001707.tgz", - "integrity": "sha512-3qtRjw/HQSMlDWf+X79N206fepf4SOOU6SQLMaq/0KkZLmSjPxAkBOQQ+FxbHKfHmYLZFfdWsO3KA90ceHPSnw==", + "version": "1.0.30001745", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001745.tgz", + "integrity": "sha512-ywt6i8FzvdgrrrGbr1jZVObnVv6adj+0if2/omv9cmR2oiZs30zL4DIyaptKcbOrBdOIc74QTMoJvSE2QHh5UQ==", "dev": true, "funding": [ { @@ -1857,6 +2639,52 @@ ], "license": "CC-BY-4.0" }, + "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, + "license": "MIT", + "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/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "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, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "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, + "license": "MIT" + }, "node_modules/commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", @@ -1867,7 +2695,8 @@ "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/convert-source-map": { "version": "2.0.0", @@ -1876,6 +2705,31 @@ "dev": true, "license": "MIT" }, + "node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "license": "MIT", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cosmiconfig/node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -1895,13 +2749,12 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "devOptional": true + "license": "MIT" }, "node_modules/debug": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", - "dev": true, + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -1915,24 +2768,13 @@ } } }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, "node_modules/discontinuous-range": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/discontinuous-range/-/discontinuous-range-1.0.0.tgz", @@ -1950,29 +2792,36 @@ "redux": "^4.2.0" } }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, + "node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "license": "MIT", "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" } }, "node_modules/electron-to-chromium": { - "version": "1.5.129", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.129.tgz", - "integrity": "sha512-JlXUemX4s0+9f8mLqib/bHH8gOHf5elKS6KeWG3sk3xozb/JTq/RLXIv8OKUWiK4Ah00Wm88EFj5PYkFr4RUPA==", + "version": "1.5.223", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.223.tgz", + "integrity": "sha512-qKm55ic6nbEmagFlTFczML33rF90aU+WtrJ9MdTCThrcvDNdUHN4p6QfVN78U06ZmguqXIyMPyYhw2TrbDUwPQ==", "dev": true, "license": "ISC" }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, "node_modules/esbuild": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.2.tgz", - "integrity": "sha512-16854zccKPnC+toMywC+uKNeYSv+/eXkevRAfwRD/G9Cleq66m8XFIrigkbvauLLlCfDL45Q2cWegSg53gGBnQ==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.10.tgz", + "integrity": "sha512-9RiGKvCwaqxO2owP61uQ4BgNborAQskMR6QusfWzQqv7AZOg5oGehdY2pRJMTKuwxd1IDBP4rSbI5lHzU7SMsQ==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -1983,31 +2832,32 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.2", - "@esbuild/android-arm": "0.25.2", - "@esbuild/android-arm64": "0.25.2", - "@esbuild/android-x64": "0.25.2", - "@esbuild/darwin-arm64": "0.25.2", - "@esbuild/darwin-x64": "0.25.2", - "@esbuild/freebsd-arm64": "0.25.2", - "@esbuild/freebsd-x64": "0.25.2", - "@esbuild/linux-arm": "0.25.2", - "@esbuild/linux-arm64": "0.25.2", - "@esbuild/linux-ia32": "0.25.2", - "@esbuild/linux-loong64": "0.25.2", - "@esbuild/linux-mips64el": "0.25.2", - "@esbuild/linux-ppc64": "0.25.2", - "@esbuild/linux-riscv64": "0.25.2", - "@esbuild/linux-s390x": "0.25.2", - "@esbuild/linux-x64": "0.25.2", - "@esbuild/netbsd-arm64": "0.25.2", - "@esbuild/netbsd-x64": "0.25.2", - "@esbuild/openbsd-arm64": "0.25.2", - "@esbuild/openbsd-x64": "0.25.2", - "@esbuild/sunos-x64": "0.25.2", - "@esbuild/win32-arm64": "0.25.2", - "@esbuild/win32-ia32": "0.25.2", - "@esbuild/win32-x64": "0.25.2" + "@esbuild/aix-ppc64": "0.25.10", + "@esbuild/android-arm": "0.25.10", + "@esbuild/android-arm64": "0.25.10", + "@esbuild/android-x64": "0.25.10", + "@esbuild/darwin-arm64": "0.25.10", + "@esbuild/darwin-x64": "0.25.10", + "@esbuild/freebsd-arm64": "0.25.10", + "@esbuild/freebsd-x64": "0.25.10", + "@esbuild/linux-arm": "0.25.10", + "@esbuild/linux-arm64": "0.25.10", + "@esbuild/linux-ia32": "0.25.10", + "@esbuild/linux-loong64": "0.25.10", + "@esbuild/linux-mips64el": "0.25.10", + "@esbuild/linux-ppc64": "0.25.10", + "@esbuild/linux-riscv64": "0.25.10", + "@esbuild/linux-s390x": "0.25.10", + "@esbuild/linux-x64": "0.25.10", + "@esbuild/netbsd-arm64": "0.25.10", + "@esbuild/netbsd-x64": "0.25.10", + "@esbuild/openbsd-arm64": "0.25.10", + "@esbuild/openbsd-x64": "0.25.10", + "@esbuild/openharmony-arm64": "0.25.10", + "@esbuild/sunos-x64": "0.25.10", + "@esbuild/win32-arm64": "0.25.10", + "@esbuild/win32-ia32": "0.25.10", + "@esbuild/win32-x64": "0.25.10" } }, "node_modules/escalade": { @@ -2020,93 +2870,114 @@ "node": ">=6" } }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/eslint": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", - "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", + "version": "9.36.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.36.0.tgz", + "integrity": "sha512-hB4FIzXovouYzwzECDcUkJ4OcfOEkXTv2zRY6B9bkwjx/cprAq0uvm1nl7zvQ0/TsUk0zQiN4uPfJpB9m+rPMQ==", "dev": true, + "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.0", - "@humanwhocodes/config-array": "^0.11.14", + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.0", + "@eslint/config-helpers": "^0.3.1", + "@eslint/core": "^0.15.2", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.36.0", + "@eslint/plugin-kit": "^0.3.5", + "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", + "cross-spawn": "^7.0.6", "debug": "^4.3.2", - "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", + "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" + "optionator": "^0.9.3" }, "bin": { "eslint": "bin/eslint.js" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } } }, "node_modules/eslint-plugin-react-hooks": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz", - "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.2.0.tgz", + "integrity": "sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, "peerDependencies": { - "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" } }, "node_modules/eslint-plugin-react-refresh": { - "version": "0.4.6", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.6.tgz", - "integrity": "sha512-NjGXdm7zgcKRkKMua34qVO9doI7VOxZ6ancSvBELJSSoX97jyndXcSoa8XBh69JoB31dNz3EEzlMcizZl7LaMA==", + "version": "0.4.21", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.21.tgz", + "integrity": "sha512-MWDWTtNC4voTcWDxXbdmBNe8b/TxfxRFUL6hXgKWJjN9c1AagYEmpiFWBWzDw+5H3SulWUe1pJKTnoSdmk88UA==", "dev": true, + "license": "MIT", "peerDependencies": { - "eslint": ">=7" + "eslint": ">=8.40" } }, "node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -2117,6 +2988,7 @@ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, + "license": "Apache-2.0", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, @@ -2124,99 +2996,38 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/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/eslint/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==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, - "node_modules/eslint/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/eslint/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/eslint/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/eslint/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, + "license": "Apache-2.0", "engines": { - "node": ">=8" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/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==", + "node_modules/eslint/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">= 4" } }, "node_modules/eslint/node_modules/minimatch": { @@ -2224,6 +3035,7 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -2231,40 +3043,43 @@ "node": "*" } }, - "node_modules/eslint/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==", + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "has-flag": "^4.0.0" + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" }, "engines": { - "node": ">=8" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", "dev": true, - "dependencies": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - }, + "license": "Apache-2.0", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" } }, "node_modules/esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "estraverse": "^5.1.0" }, @@ -2277,6 +3092,7 @@ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "estraverse": "^5.2.0" }, @@ -2289,6 +3105,7 @@ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } @@ -2298,32 +3115,29 @@ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=0.10.0" } }, - "node_modules/eventemitter3": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", - "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", - "dev": true - }, "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==" + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "license": "MIT" }, "node_modules/fast-glob": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", - "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", - "micromatch": "^4.0.4" + "micromatch": "^4.0.8" }, "engines": { "node": ">=8.6.0" @@ -2334,6 +3148,7 @@ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, + "license": "ISC", "dependencies": { "is-glob": "^4.0.1" }, @@ -2345,33 +3160,37 @@ "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 + "dev": true, + "license": "MIT" }, "node_modules/fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fastq": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", - "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", "dev": true, + "license": "ISC", "dependencies": { "reusify": "^1.0.4" } }, "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "dev": true, + "license": "MIT", "dependencies": { - "flat-cache": "^3.0.4" + "flat-cache": "^4.0.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=16.0.0" } }, "node_modules/fill-range": { @@ -2387,11 +3206,18 @@ "node": ">=8" } }, + "node_modules/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", + "license": "MIT" + }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, + "license": "MIT", "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" @@ -2404,50 +3230,25 @@ } }, "node_modules/flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dev": true, + "license": "MIT", "dependencies": { "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" + "keyv": "^4.5.4" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=16" } }, "node_modules/flatted": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", - "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", - "dev": true - }, - "node_modules/follow-redirects": { - "version": "1.15.6", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", - "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true + "license": "ISC" }, "node_modules/fsevents": { "version": "2.3.3", @@ -2464,6 +3265,15 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -2474,31 +3284,12 @@ "node": ">=6.9.0" } }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, + "license": "ISC", "dependencies": { "is-glob": "^4.0.3" }, @@ -2506,53 +3297,14 @@ "node": ">=10.13.0" } }, - "node_modules/glob/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, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/glob/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", "dev": true, "license": "MIT", "engines": { - "node": ">=4" - } - }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -2562,63 +3314,55 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true - }, - "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", - "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", - "license": "BSD-3-Clause", - "dependencies": { - "react-is": "^16.7.0" - } + "dev": true, + "license": "MIT" }, - "node_modules/http-proxy": { - "version": "1.18.1", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", - "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "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, - "dependencies": { - "eventemitter3": "^4.0.0", - "follow-redirects": "^1.0.0", - "requires-port": "^1.0.0" - }, + "license": "MIT", "engines": { - "node": ">=8.0.0" + "node": ">=8" } }, - "node_modules/http-proxy-middleware": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-3.0.3.tgz", - "integrity": "sha512-usY0HG5nyDUwtqpiZdETNbmKtw3QQ1jwYFZ9wi5iHzX2BcILwQKtYDJPo7XHTsu5Z0B2Hj3W9NNnbd+AjFWjqg==", - "dev": true, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "license": "MIT", "dependencies": { - "@types/http-proxy": "^1.17.15", - "debug": "^4.3.6", - "http-proxy": "^1.18.1", - "is-glob": "^4.0.3", - "is-plain-object": "^5.0.0", - "micromatch": "^4.0.8" + "function-bind": "^1.1.2" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">= 0.4" + } + }, + "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", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "license": "BSD-3-Clause", + "dependencies": { + "react-is": "^16.7.0" } }, "node_modules/ignore": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", - "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 4" } }, "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "license": "MIT", "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -2635,31 +3379,38 @@ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8.19" } }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "license": "MIT" + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "license": "MIT", "dependencies": { - "once": "^1.3.0", - "wrappy": "1" + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -2669,6 +3420,7 @@ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, + "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" }, @@ -2686,41 +3438,25 @@ "node": ">=0.12.0" } }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-plain-object": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", - "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" }, "node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, + "license": "MIT", "dependencies": { "argparse": "^2.0.1" }, @@ -2732,7 +3468,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", - "dev": true, "license": "MIT", "bin": { "jsesc": "bin/jsesc" @@ -2745,19 +3480,28 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "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==", + "license": "MIT" }, "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 + "dev": true, + "license": "MIT" }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json5": { "version": "2.2.3", @@ -2777,6 +3521,7 @@ "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dev": true, + "license": "MIT", "dependencies": { "json-buffer": "3.0.1" } @@ -2786,6 +3531,7 @@ "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, + "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" @@ -2794,11 +3540,18 @@ "node": ">= 0.8.0" } }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "license": "MIT" + }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, + "license": "MIT", "dependencies": { "p-locate": "^5.0.0" }, @@ -2813,12 +3566,14 @@ "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, @@ -2837,12 +3592,12 @@ } }, "node_modules/lucide-react": { - "version": "0.460.0", - "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.460.0.tgz", - "integrity": "sha512-BVtq/DykVeIvRTJvRAgCsOwaGL8Un3Bxh8MbDxMhEWlZay3T4IpEKDEpwt5KZ0KJMHzgm6jrltxlT5eXOWXDHg==", + "version": "0.544.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.544.0.tgz", + "integrity": "sha512-t5tS44bqd825zAW45UQxpG2CvcC4urOwn2TrwSH8u+MjeE+1NnWl6QqeQ/6NdjMqdOygyiT9p3Ev0p1NJykxjw==", "license": "ISC", "peerDependencies": { - "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc" + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "node_modules/merge2": { @@ -2850,6 +3605,7 @@ "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 8" } @@ -2869,10 +3625,11 @@ } }, "node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "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" }, @@ -2884,10 +3641,14 @@ } }, "node_modules/monaco-editor": { - "version": "0.47.0", - "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.47.0.tgz", - "integrity": "sha512-VabVvHvQ9QmMwXu4du008ZDuyLnHs9j7ThVFsiJoXSOQk18+LF89N4ADzPbFenm0W4V2bGHnFBztIRQTgBfxzw==", - "peer": true + "version": "0.53.0", + "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.53.0.tgz", + "integrity": "sha512-0WNThgC6CMWNXXBxTbaYYcunj08iB5rnx4/G56UOPeL9UVIUGGHA1GR0EWIh9Ebabj7NpCRawQ5b0hfN1jQmYQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@types/trusted-types": "^1.0.6" + } }, "node_modules/moo": { "version": "0.5.2", @@ -2899,7 +3660,6 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, "license": "MIT" }, "node_modules/nanoid": { @@ -2925,7 +3685,8 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/nearley": { "version": "2.20.1", @@ -2950,33 +3711,34 @@ } }, "node_modules/node-releases": { - "version": "2.0.19", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", - "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", + "version": "2.0.21", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.21.tgz", + "integrity": "sha512-5b0pgg78U3hwXkCM8Z9b2FJdPZlr9Psr9V2gQPESdGHqbntyFJKFW4r5TeWGFzafGY3hzs1JC62VEQMbl1JFkw==", "dev": true, "license": "MIT" }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "dependencies": { - "wrappy": "1" + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, "node_modules/optionator": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", - "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, + "license": "MIT", "dependencies": { - "@aashutoshrathi/word-wrap": "^1.2.3", "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", - "type-check": "^0.4.0" + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" }, "engines": { "node": ">= 0.8.0" @@ -2987,6 +3749,7 @@ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, + "license": "MIT", "dependencies": { "yocto-queue": "^0.1.0" }, @@ -3002,6 +3765,7 @@ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, + "license": "MIT", "dependencies": { "p-limit": "^3.0.2" }, @@ -3016,7 +3780,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, + "license": "MIT", "dependencies": { "callsites": "^3.0.0" }, @@ -3024,38 +3788,55 @@ "node": ">=6" } }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "license": "MIT" + }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -3064,7 +3845,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true, "license": "ISC" }, "node_modules/picomatch": { @@ -3072,6 +3852,7 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, + "license": "MIT", "engines": { "node": ">=8.6" }, @@ -3080,9 +3861,9 @@ } }, "node_modules/postcss": { - "version": "8.5.3", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz", - "integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==", + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", "dev": true, "funding": [ { @@ -3100,7 +3881,7 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.8", + "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -3108,23 +3889,20 @@ "node": "^10 || ^12 || >=14" } }, - "node_modules/precise": { - "resolved": "", - "link": true - }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8.0" } }, "node_modules/prettier": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz", - "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", + "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", "license": "MIT", "bin": { "prettier": "bin/prettier.cjs" @@ -3136,11 +3914,23 @@ "url": "https://github.com/prettier/prettier?sponsor=1" } }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -3163,7 +3953,8 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/railroad-diagrams": { "version": "1.0.0", @@ -3185,12 +3976,11 @@ } }, "node_modules/react": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", - "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", - "dependencies": { - "loose-envify": "^1.1.0" - }, + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/react/-/react-19.1.1.tgz", + "integrity": "sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ==", + "license": "MIT", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -3235,15 +4025,16 @@ } }, "node_modules/react-dom": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", - "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.1.tgz", + "integrity": "sha512-Dlq/5LAZgF0Gaz6yiqZCf6VCcZs1ghAJyrsu84Q/GT0gV+mCxbfmKNoGRKBYMJ8IEdGPqu49YWXD02GCknEDkw==", + "license": "MIT", + "peer": true, "dependencies": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.0" + "scheduler": "^0.26.0" }, "peerDependencies": { - "react": "^18.2.0" + "react": "^19.1.1" } }, "node_modules/react-is": { @@ -3253,15 +4044,31 @@ "license": "MIT" }, "node_modules/react-refresh": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz", - "integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==", + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", + "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" } }, + "node_modules/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "license": "BSD-3-Clause", + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, "node_modules/redux": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", @@ -3271,23 +4078,37 @@ "@babel/runtime": "^7.9.2" } }, - "node_modules/regenerator-runtime": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", - "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", + "node_modules/reselect": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz", + "integrity": "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==", "license": "MIT" }, - "node_modules/requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", - "dev": true + "node_modules/resolve": { + "version": "1.22.10", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", + "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, + "license": "MIT", "engines": { "node": ">=4" } @@ -3302,38 +4123,24 @@ } }, "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", "dev": true, + "license": "MIT", "engines": { "iojs": ">=1.0.0", "node": ">=0.10.0" } }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/rollup": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.38.0.tgz", - "integrity": "sha512-5SsIRtJy9bf1ErAOiFMFzl64Ex9X5V7bnJ+WlFMb+zmP459OSWCEG7b0ERZ+PEU7xPt4OG3RHbrp1LJlXxYTrw==", + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.52.2.tgz", + "integrity": "sha512-I25/2QgoROE1vYV+NQ1En9T9UFB9Cmfm2CJ83zZOlaDpvz29wGQSZXWKw7MiNXau7wYgB/T9fVIdIuEQ+KbiiA==", "dev": true, "license": "MIT", "dependencies": { - "@types/estree": "1.0.7" + "@types/estree": "1.0.8" }, "bin": { "rollup": "dist/bin/rollup" @@ -3343,26 +4150,28 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.38.0", - "@rollup/rollup-android-arm64": "4.38.0", - "@rollup/rollup-darwin-arm64": "4.38.0", - "@rollup/rollup-darwin-x64": "4.38.0", - "@rollup/rollup-freebsd-arm64": "4.38.0", - "@rollup/rollup-freebsd-x64": "4.38.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.38.0", - "@rollup/rollup-linux-arm-musleabihf": "4.38.0", - "@rollup/rollup-linux-arm64-gnu": "4.38.0", - "@rollup/rollup-linux-arm64-musl": "4.38.0", - "@rollup/rollup-linux-loongarch64-gnu": "4.38.0", - "@rollup/rollup-linux-powerpc64le-gnu": "4.38.0", - "@rollup/rollup-linux-riscv64-gnu": "4.38.0", - "@rollup/rollup-linux-riscv64-musl": "4.38.0", - "@rollup/rollup-linux-s390x-gnu": "4.38.0", - "@rollup/rollup-linux-x64-gnu": "4.38.0", - "@rollup/rollup-linux-x64-musl": "4.38.0", - "@rollup/rollup-win32-arm64-msvc": "4.38.0", - "@rollup/rollup-win32-ia32-msvc": "4.38.0", - "@rollup/rollup-win32-x64-msvc": "4.38.0", + "@rollup/rollup-android-arm-eabi": "4.52.2", + "@rollup/rollup-android-arm64": "4.52.2", + "@rollup/rollup-darwin-arm64": "4.52.2", + "@rollup/rollup-darwin-x64": "4.52.2", + "@rollup/rollup-freebsd-arm64": "4.52.2", + "@rollup/rollup-freebsd-x64": "4.52.2", + "@rollup/rollup-linux-arm-gnueabihf": "4.52.2", + "@rollup/rollup-linux-arm-musleabihf": "4.52.2", + "@rollup/rollup-linux-arm64-gnu": "4.52.2", + "@rollup/rollup-linux-arm64-musl": "4.52.2", + "@rollup/rollup-linux-loong64-gnu": "4.52.2", + "@rollup/rollup-linux-ppc64-gnu": "4.52.2", + "@rollup/rollup-linux-riscv64-gnu": "4.52.2", + "@rollup/rollup-linux-riscv64-musl": "4.52.2", + "@rollup/rollup-linux-s390x-gnu": "4.52.2", + "@rollup/rollup-linux-x64-gnu": "4.52.2", + "@rollup/rollup-linux-x64-musl": "4.52.2", + "@rollup/rollup-openharmony-arm64": "4.52.2", + "@rollup/rollup-win32-arm64-msvc": "4.52.2", + "@rollup/rollup-win32-ia32-msvc": "4.52.2", + "@rollup/rollup-win32-x64-gnu": "4.52.2", + "@rollup/rollup-win32-x64-msvc": "4.52.2", "fsevents": "~2.3.2" } }, @@ -3385,26 +4194,24 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "dependencies": { "queue-microtask": "^1.2.2" } }, "node_modules/scheduler": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", - "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", - "dependencies": { - "loose-envify": "^1.1.0" - } + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz", + "integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==", + "license": "MIT", + "peer": true }, "node_modules/semver": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", - "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, + "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -3412,29 +4219,12 @@ "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, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/semver/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 - }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, + "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" }, @@ -3447,17 +4237,18 @@ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, + "node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "license": "BSD-3-Clause", "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, "node_modules/source-map-js": { @@ -3471,9 +4262,9 @@ } }, "node_modules/sql-formatter": { - "version": "15.5.2", - "resolved": "https://registry.npmjs.org/sql-formatter/-/sql-formatter-15.5.2.tgz", - "integrity": "sha512-+9xZgiv1DP/c7GxkkBUHRZOf4j35gquVdwEm0rg16qKRYeFkv1+/vEeO13fsUbbz06KUotIyASJ+hyau8LM8Kg==", + "version": "15.6.9", + "resolved": "https://registry.npmjs.org/sql-formatter/-/sql-formatter-15.6.9.tgz", + "integrity": "sha512-r9VKnkRfKW7jbhTgytwbM+JqmFclQYN9L58Z3UTktuy9V1f1Y+rGK3t70Truh2wIOJzvZkzobAQ2PwGjjXsr6Q==", "license": "MIT", "dependencies": { "argparse": "^2.0.1", @@ -3486,37 +4277,100 @@ "node_modules/state-local": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/state-local/-/state-local-1.0.7.tgz", - "integrity": "sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==" + "integrity": "sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==", + "license": "MIT" + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "node_modules/stylis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==", + "license": "MIT" + }, + "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, + "license": "MIT", "dependencies": { - "ansi-regex": "^5.0.1" + "has-flag": "^4.0.0" }, "engines": { "node": ">=8" } }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, "engines": { - "node": ">=8" + "node": ">=12.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } } }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } }, "node_modules/to-regex-range": { "version": "5.0.1", @@ -3532,15 +4386,16 @@ } }, "node_modules/ts-api-utils": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", - "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", + "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", "dev": true, + "license": "MIT", "engines": { - "node": ">=16" + "node": ">=18.12" }, "peerDependencies": { - "typescript": ">=4.2.0" + "typescript": ">=4.8.4" } }, "node_modules/type-check": { @@ -3548,6 +4403,7 @@ "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, + "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1" }, @@ -3555,23 +4411,12 @@ "node": ">= 0.8.0" } }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/typescript": { - "version": "5.4.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.4.tgz", - "integrity": "sha512-dGE2Vv8cpVvw28v8HCPqyb08EzbBURxDpuhJvTrusShUfGnhHBafDsLdS1EhhxyL6BJQE+2cT3dDPAv+MQ6oLw==", + "version": "5.9.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz", + "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==", "dev": true, + "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -3580,12 +4425,6 @@ "node": ">=14.17" } }, - "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "devOptional": true - }, "node_modules/update-browserslist-db": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", @@ -3622,10 +4461,20 @@ "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/use-sync-external-store": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", + "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/uuid": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", @@ -3639,6 +4488,7 @@ "version": "6.2.13", "resolved": "https://registry.npmjs.org/uuidv4/-/uuidv4-6.2.13.tgz", "integrity": "sha512-AXyzMjazYB3ovL3q051VLH06Ixj//Knx7QnUSi1T//Ie3io6CpsPu9nVMOx5MoLWh6xV0B9J0hIaxungxXUbPQ==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", "license": "MIT", "dependencies": { "@types/uuid": "8.3.4", @@ -3646,21 +4496,24 @@ } }, "node_modules/vite": { - "version": "6.2.4", - "resolved": "https://registry.npmjs.org/vite/-/vite-6.2.4.tgz", - "integrity": "sha512-veHMSew8CcRzhL5o8ONjy8gkfmFJAd5Ac16oxBUjlwgX3Gq2Wqr+qNC3TjPIpy7TPV/KporLga5GT9HqdrCizw==", + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.7.tgz", + "integrity": "sha512-VbA8ScMvAISJNJVbRDTJdCwqQoAareR/wutevKanhR2/1EkoXVZVkkORaYm/tNVCjP/UDTKtcw3bAkwOUdedmA==", "dev": true, "license": "MIT", "dependencies": { "esbuild": "^0.25.0", - "postcss": "^8.5.3", - "rollup": "^4.30.1" + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" }, "bin": { "vite": "bin/vite.js" }, "engines": { - "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + "node": "^20.19.0 || >=22.12.0" }, "funding": { "url": "https://github.com/vitejs/vite?sponsor=1" @@ -3669,14 +4522,14 @@ "fsevents": "~2.3.3" }, "peerDependencies": { - "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", - "less": "*", + "less": "^4.0.0", "lightningcss": "^1.21.0", - "sass": "*", - "sass-embedded": "*", - "stylus": "*", - "sugarss": "*", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" @@ -3717,11 +4570,43 @@ } } }, + "node_modules/vite/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, + "license": "ISC", "dependencies": { "isexe": "^2.0.0" }, @@ -3732,11 +4617,15 @@ "node": ">= 8" } }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } }, "node_modules/yallist": { "version": "3.1.1", @@ -3750,6 +4639,7 @@ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, diff --git a/precise/package.json b/precise/package.json index 7b7045a..82bf689 100644 --- a/precise/package.json +++ b/precise/package.json @@ -1,8 +1,30 @@ { - "name": "precise", - "homepage": ".", - "private": true, - "version": "0.0.0", + "name": "trino-query-ui", + "description": "Trino Query Editor react component", + "version": "0.0.1", + "author": { + "name": "Trino contributors", + "email": "general@trino.io", + "url": "https://github.com/trinodb/trino-query-ui/graphs/contributors" + }, + "keywords": [ + "trino", + "trinodb", + "react" + ], + "repository": { + "type": "git", + "url": "https://github.com/trinodb/trino-query-ui.git" + }, + "homepage": "https://trinodb.github.io/trino-query-ui", + "bugs": { + "url": "https://github.com/trinodb/trino-query-ui/issues" + }, + "main": "dist/index.js", + "license": "Apache-2.0", + "files": [ + "dist" + ], "type": "module", "scripts": { "dev": "vite", @@ -18,31 +40,37 @@ "antlr4ng": "antlr4ng -visitor -listener -Dlanguage=TypeScript -o src/generated/lexer/SqlBase.g4 trino/SqlBase.g4" }, "dependencies": { - "@monaco-editor/react": "^4.6.0", - "antlr4-c3": "^3.4.1", - "antlr4ng": "^3.0.4", - "lucide-react": "^0.460.0", - "precise": "file:", - "prettier": "^3.5.3", - "react": "^18.2.0", + "@emotion/react": "^11.14.0", + "@emotion/styled": "^11.14.1", + "@monaco-editor/react": "^4.7.0", + "@mui/icons-material": "^7.3.2", + "@mui/material": "^7.3.2", + "@mui/x-data-grid": "^8.14.0", + "@mui/x-tree-view": "^8.13.1", + "antlr4-c3": "^3.4.4", + "antlr4ng": "^3.0.16", + "lucide-react": "^0.544.0", + "prettier": "^3.6.2", "react-dnd": "^16.0.1", "react-dnd-html5-backend": "^16.0.1", - "react-dom": "^18.2.0", - "sql-formatter": "^15.5.2", + "sql-formatter": "^15.6.9", "uuidv4": "^6.2.13" }, "devDependencies": { - "@types/http-proxy-middleware": "^1.0.0", - "@types/react": "^18.2.66", - "@types/react-dom": "^18.2.22", - "@typescript-eslint/eslint-plugin": "^7.2.0", - "@typescript-eslint/parser": "^7.2.0", - "@vitejs/plugin-react": "^4.2.1", + "@types/react": "^19.1.13", + "@types/react-dom": "^19.1.9", + "@typescript-eslint/eslint-plugin": "^8.44.1", + "@typescript-eslint/parser": "^8.44.1", + "@vitejs/plugin-react": "^5.0.3", "antlr4ng-cli": "^2.0.0", - "eslint": "^8.57.0", - "eslint-plugin-react-hooks": "^4.6.0", - "eslint-plugin-react-refresh": "^0.4.6", - "typescript": "^5.2.2", - "vite": "^6.2.4" + "eslint": "^9.36.0", + "eslint-plugin-react-hooks": "^5.2.0", + "eslint-plugin-react-refresh": "^0.4.21", + "typescript": "^5.9.2", + "vite": "^7.1.7" + }, + "peerDependencies": { + "react": "^19.1.1", + "react-dom": "^19.1.1" } } diff --git a/precise/src/App.tsx b/precise/src/App.tsx deleted file mode 100644 index 29fecdf..0000000 --- a/precise/src/App.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import QueryApp from './QueryApp' - -// for now this is a defacto Tab, but we will treat this tab more as a page in the future -function App() { - return ( -
- -
- ) -} - -export default App diff --git a/precise/src/QueryApp.tsx b/precise/src/QueryApp.tsx deleted file mode 100644 index 5a58314..0000000 --- a/precise/src/QueryApp.tsx +++ /dev/null @@ -1,114 +0,0 @@ -import React from 'react' -import QueryCell from './QueryCell' -import Queries from './schema/Queries' -import CatalogViewer from './controls/catalog_viewer/CatalogViewer' -import './style/layout.css' -import './style/components.css' - -interface QueryAppProps {} - -interface QueryAppState { - queries: Queries -} - -class QueryApp extends React.Component { - constructor(props: QueryAppProps) { - super(props) - - this.state = { - queries: new Queries(), - } - } - - setQueryContent = (query: string, catalog?: string, schema?: string) => { - const currentQuery = this.state.queries.getCurrentQuery() - const updates: any = {} - - if (query) { - updates.query = query - } - - if (catalog) { - updates.catalog = catalog - } - - if (schema) { - updates.schema = schema - } - - this.state.queries.updateQuery(currentQuery.id, updates) - } - - appendQueryContent = (query: string, catalog?: string, schema?: string) => { - const currentQuery = this.state.queries.getCurrentQuery() - const updates: any = {} - - if (query) { - // Append to existing query, adding newlines as needed - const existingQuery = currentQuery.query || '' - const separator = existingQuery.trim() === '' ? '' : '\n\n' - updates.query = existingQuery + separator + query - } - - if (catalog) { - updates.catalog = catalog - } - - if (schema) { - updates.schema = schema - } - - this.state.queries.updateQuery(currentQuery.id, updates) - } - - render() { - return ( -
-
-
-
-
-
- -
-
- - - -
-
-
- -
-
-
-
- ) - } -} - -export default QueryApp diff --git a/precise/src/QueryCell.tsx b/precise/src/QueryCell.tsx index ee0506f..e1fb7e8 100644 --- a/precise/src/QueryCell.tsx +++ b/precise/src/QueryCell.tsx @@ -1,12 +1,19 @@ -import React from 'react' -import QueryEditor from './QueryEditor' +import React, { ReactNode } from 'react' +import { Box, Divider, IconButton, Stack, TextField, Toolbar, Typography } from '@mui/material' +import type { TextFieldProps } from '@mui/material/TextField' +import type { TypographyProps } from '@mui/material/Typography' +import MenuIcon from '@mui/icons-material/Menu' +import PlayCircleOutlinedIcon from '@mui/icons-material/PlayCircleOutlined' +import StopCircleOutlinedIcon from '@mui/icons-material/StopCircleOutlined' +import UnfoldLessIcon from '@mui/icons-material/UnfoldLess' +import UnfoldMoreIcon from '@mui/icons-material/UnfoldMore' +import QueryEditorPane from './QueryEditorPane' import ResultSet from './ResultSet' import Queries from './schema/Queries' import QueryInfo from './schema/QueryInfo' import AsyncTrinoClient from './AsyncTrinoClient' -import { Play, StopCircle, Link, Plus, FileEdit, MinusSquare, PlusSquare } from 'lucide-react' -import './style/components.css' -import './style/query-editor.css' + +const TOOLBAR_HEIGHT = 64 interface QueryCellState { results: any[] @@ -15,15 +22,22 @@ interface QueryCellState { errorMessage: string currentQuery: QueryInfo runningQuery: QueryInfo | undefined + editingTitle: boolean + editingCatalog: boolean + editingSchema: boolean + editorCollapsed: boolean } interface QueryCellProps { queries: Queries + drawerOpen: boolean + height: number + onDrawerToggle: () => void + theme?: string } class QueryCell extends React.Component { private queryRunner: AsyncTrinoClient - private isQueryCollapsed: boolean = false constructor(props: QueryCellProps) { super(props) @@ -34,6 +48,10 @@ class QueryCell extends React.Component { errorMessage: '', currentQuery: this.props.queries.getCurrentQuery(), runningQuery: undefined, + editingTitle: false, + editingCatalog: false, + editingSchema: false, + editorCollapsed: false, } this.queryRunner = new AsyncTrinoClient() this.setupQueryRunner() @@ -50,13 +68,19 @@ class QueryCell extends React.Component { shouldComponentUpdate(nextProps: QueryCellProps, nextState: QueryCellState) { // Only update if the ResultSet-related props have changed return ( + this.props.drawerOpen !== nextProps.drawerOpen || + this.props.height !== nextProps.height || this.state.results !== nextState.results || this.state.columns !== nextState.columns || this.state.response !== nextState.response || this.state.errorMessage !== nextState.errorMessage || this.state.runningQuery !== nextState.runningQuery || this.state.currentQuery !== nextState.currentQuery || - this.state.currentQuery.title !== nextState.currentQuery.title + this.state.currentQuery.title !== nextState.currentQuery.title || + this.state.editingTitle !== nextState.editingTitle || + this.state.editingCatalog !== nextState.editingCatalog || + this.state.editingSchema !== nextState.editingSchema || + this.state.editorCollapsed !== nextState.editorCollapsed ) } @@ -109,6 +133,14 @@ class QueryCell extends React.Component { this.props.queries.updateQuery(this.state.currentQuery.id, { title: title }) } + handleCatalogChange = (catalog: string) => { + this.props.queries.updateQuery(this.state.currentQuery.id, { catalog: catalog }) + } + + handleSchemaChange = (schema: string) => { + this.props.queries.updateQuery(this.state.currentQuery.id, { schema: schema }) + } + ClearResults() { this.setState({ results: [], columns: [], errorMessage: '' }) } @@ -132,11 +164,63 @@ class QueryCell extends React.Component { } toggleQueryCollapse = () => { - const queryEditor = document.getElementById('query-editor') - if (queryEditor) { - this.isQueryCollapsed = !this.isQueryCollapsed - queryEditor.style.display = this.isQueryCollapsed ? 'none' : 'block' + this.setState({ editorCollapsed: !this.state.editorCollapsed }) + } + + private renderEditableTextField( + key: 'editingTitle' | 'editingCatalog' | 'editingSchema', + value: string | undefined, + options: { + typographyProps?: TypographyProps + textFieldProps?: TextFieldProps + displayContent?: ReactNode + } = {} + ) { + const { typographyProps = {}, textFieldProps = {}, displayContent } = options + const isEditing = this.state[key] + + if (isEditing) { + const { onChange, onKeyDown, onBlur, autoFocus, ...restTextFieldProps } = textFieldProps + + return ( + { + onChange?.(event) + }} + onKeyDown={(event) => { + onKeyDown?.(event) + if (!event.defaultPrevented && (event.key === 'Enter' || event.key === 'Escape')) { + this.setState({ [key]: false } as Pick) + } + }} + onBlur={(event) => { + onBlur?.(event) + this.setState({ [key]: false } as Pick) + }} + autoFocus={autoFocus ?? true} + /> + ) } + + const { onClick, ...restTypographyProps } = typographyProps + + return ( + { + onClick?.(event) + if (!event.defaultPrevented) { + this.setState({ [key]: true } as Pick) + } + }} + > + {displayContent ?? value} + + ) } render() { @@ -146,123 +230,122 @@ class QueryCell extends React.Component { response.stats !== undefined && (response.stats.state === 'RUNNING' || response.stats.state === 'QUEUED') + const availablePanelHeight = Math.max(this.props.height - TOOLBAR_HEIGHT, 0) + const resultSetHeight = this.state.editorCollapsed ? availablePanelHeight : availablePanelHeight / 2 + return ( - <> -
-
- - this.handleTitleChange(e.target.value)} - value={currentQuery.title} - /> - - this.props.queries.updateQuery(this.state.currentQuery.id, { catalog: e.target.value }) - } - value={currentQuery.catalog ?? ''} - /> - - this.props.queries.updateQuery(this.state.currentQuery.id, { schema: e.target.value }) - } - value={currentQuery.schema ?? ''} - /> - -
- -
- -
- -
-
-
- + + + + + this.Execute()} + > + {!isQueryRunning ? : } + + {this.renderEditableTextField('editingTitle', currentQuery.title, { + typographyProps: { + variant: 'h6', + sx: { ml: 2 }, + }, + textFieldProps: { + sx: { maxWidth: 200 }, + onChange: (event) => this.handleTitleChange(event.target.value), + }, + })} + + + + + Catalog: + + {this.renderEditableTextField('editingCatalog', currentQuery.catalog ?? '', { + typographyProps: { + sx: { ml: 2, maxWidth: 200, fontFamily: 'monospace' }, + noWrap: true, + }, + textFieldProps: { + sx: { + maxWidth: 200, + '& .MuiInputBase-input': { fontFamily: 'monospace' }, + }, + onChange: (event) => this.handleCatalogChange(event.target.value), + }, + displayContent: + currentQuery.catalog && currentQuery.catalog.length > 0 ? ( + currentQuery.catalog + ) : ( + + <no-catalog> + + ), + })} + + + + + Schema: + + {this.renderEditableTextField('editingSchema', currentQuery.schema ?? '', { + typographyProps: { + sx: { ml: 2, maxWidth: 200, fontFamily: 'monospace' }, + noWrap: true, + }, + textFieldProps: { + sx: { + maxWidth: 200, + '& .MuiInputBase-input': { fontFamily: 'monospace' }, + }, + onChange: (event) => this.handleSchemaChange(event.target.value), + }, + displayContent: + currentQuery.schema && currentQuery.schema.length > 0 ? ( + currentQuery.schema + ) : ( + + <no-schema> + + ), + })} + + + + {this.state.editorCollapsed ? : } + + + + + {}} onExecute={() => this.Execute()} queries={this.props.queries} catalog={currentQuery.catalog} schema={currentQuery.schema} + theme={this.props.theme} + maxHeight={availablePanelHeight} /> -
-
- this.ClearResults()} - /> -
- + {this.props.theme != 'dark' && } + + this.ClearResults()} + /> + ) } } diff --git a/precise/src/QueryEditor.tsx b/precise/src/QueryEditor.tsx index e392fa6..2bad7a7 100644 --- a/precise/src/QueryEditor.tsx +++ b/precise/src/QueryEditor.tsx @@ -1,927 +1,208 @@ -import React from 'react' -import Editor from '@monaco-editor/react' -import * as monaco from 'monaco-editor/esm/vs/editor/editor.api' +import React, { useRef, useState } from 'react' +import { styled } from '@mui/material/styles' +import { Box, Drawer, useMediaQuery } from '@mui/material' +import CssBaseline from '@mui/material/CssBaseline' +import MuiAppBar, { AppBarProps as MuiAppBarProps } from '@mui/material/AppBar' +import { ThemeProvider } from '@mui/material/styles' +import QueryCell from './QueryCell' +import { darkTheme, lightTheme } from './theme' import Queries from './schema/Queries' import QueryInfo from './schema/QueryInfo' -import EnterpriseTabs from './controls/tabs/EnterpriseTabs' -import * as editor_api from 'monaco-editor/esm/vs/editor/editor.api' -import * as c3 from 'antlr4-c3' -import { CharStream, CommonTokenStream, TerminalNode, ParseTree, ParserRuleContext } from 'antlr4ng' -import { TableNameContext } from './generated/lexer/SqlBase.g4/SqlBaseParser' -import { SqlBaseLexer } from './generated/lexer/SqlBase.g4/SqlBaseLexer' -import { SqlBaseParser } from './generated/lexer/SqlBase.g4/SqlBaseParser' -import SqlBaseErrorListener from './sql/SqlBaseErrorListener' -import SqlBaseListenerImpl from './sql/SqlBaseListenerImpl' -import StatementDescriptor from './sql/StatementDescriptor' -import SchemaProvider from './sql/SchemaProvider' -import TableReference from './schema/TableReference' -import Table from './schema/Table' -import Column from './schema/Column' -import NamedQuery from './sql/NamedQuery' -import { tokenMap } from './sql/TokenMap' -import SubstitutionEditor from './SubstitutionEditor' -import './style/query-editor.css' -import { format } from 'sql-formatter' -import { Code, Maximize2, Minimize2 } from 'lucide-react' +import CatalogViewer from './controls/catalog_viewer/CatalogViewer' -const TRINO_SQL_LANGUAGE = 'trinosql' - -interface QueryEditorProps { - queries: Queries - onQueryChange: (query: string) => void - onSelectChange: (selectedText: string) => void - onExecute: () => void - catalog?: string - schema?: string -} - -interface QueryEditorState { - currentQuery: QueryInfo | null - substitutions: Record - isMaximized: boolean - height: string - width: string -} - -// create a private class that extends CompletionItem -// this class will be used to create the completion items -// for the monaco editor -class CompletionItemImpl implements editor_api.languages.CompletionItem { - label: string - kind: editor_api.languages.CompletionItemKind - tags?: readonly editor_api.languages.CompletionItemTag[] | undefined - detail?: string | undefined - sortText?: string | undefined - filterText?: string | undefined - preselect?: boolean | undefined - insertText: string - insertTextRules?: editor_api.languages.CompletionItemInsertTextRule | undefined - range: editor_api.IRange | editor_api.languages.CompletionItemRanges - commitCharacters?: string[] | undefined - additionalTextEdits?: editor_api.editor.ISingleEditOperation[] | undefined - command?: editor_api.languages.Command | undefined - - constructor( - label: string, - kind: editor_api.languages.CompletionItemKind, - insertText: string, - insertTextRules: editor_api.languages.CompletionItemInsertTextRule, - range: editor_api.IRange | editor_api.languages.CompletionItemRanges - ) { - this.label = label - this.kind = kind - this.insertText = insertText - this.insertTextRules = insertTextRules - this.preselect = false - // single line - this.range = range - } +interface IQueryEditor { + height: number + theme?: 'dark' | 'light' + enableCatalogSearchColumns?: boolean } -class CustomTokenizerState implements monaco.languages.IState { - clone(): monaco.languages.IState { - return new CustomTokenizerState() - } +const DRAWER_WIDTH = 260 + +const Main = styled('main', { shouldForwardProp: (prop) => prop !== 'open' })<{ + open?: boolean +}>(({ theme }) => ({ + flexGrow: 1, + padding: theme.spacing(3), + transition: theme.transitions.create('margin', { + easing: theme.transitions.easing.sharp, + duration: theme.transitions.duration.leavingScreen, + }), + marginLeft: 0, + variants: [ + { + props: ({ open }) => open, + style: { + transition: theme.transitions.create('margin', { + easing: theme.transitions.easing.easeOut, + duration: theme.transitions.duration.enteringScreen, + }), + marginLeft: `${DRAWER_WIDTH}px`, + }, + }, + ], +})) - equals(other: monaco.languages.IState): boolean { - return other instanceof CustomTokenizerState - } +interface AppBarProps extends MuiAppBarProps { + open?: boolean } -class QueryEditor extends React.Component { - private editorRef: monaco.editor.IStandaloneCodeEditor | null = null - private isRunningParse: boolean = false - private updateCounter: number = 0 - private parseCancelToken: { cancel: boolean } = { cancel: false } - private lastCompletionItemsPosition: monaco.Position | undefined = undefined - private completionItems: monaco.languages.CompletionItem[] = [] - - openModel: any = null - decorations: any = null - state: QueryEditorState - - constructor(props: QueryEditorProps) { - super(props) - this.state = { - currentQuery: props.queries.getCurrentQuery(), - substitutions: {}, - isMaximized: false, - height: '40vh', - width: '100%', - } - } - - setEditorRef = (editor: monaco.editor.IStandaloneCodeEditor) => { - this.editorRef = editor - } - - componentDidMount() { - this.props.queries.addChangeListener(this.handleQueriesChange) - } - - componentWillUnmount() { - this.props.queries.removeChangeListener(this.handleQueriesChange) - } - - handleQueriesChange = () => { - this.setState({ - currentQuery: this.props.queries.getCurrentQuery(), - }) - } - - handleTabChange = (queryId: string) => { - this.props.queries.setCurrentQuery(queryId) - if (this.editorRef) { - const model = monaco.editor.getModel(monaco.Uri.parse(`file:///${queryId}`)) - if (model) { - this.editorRef.setModel(model) - } - } - } - - handleTabSelectAndPromote = (queryId: string) => { - this.props.queries.moveQueryToFront(queryId) - this.props.queries.setCurrentQuery(queryId) - } - - handleTabCreate = () => { - const newQuery = this.props.queries.addQuery(false, 'New Query') - monaco.editor.createModel('', TRINO_SQL_LANGUAGE, monaco.Uri.parse(`file:///${newQuery.id}`)) - this.props.queries.setCurrentQuery(newQuery.id) - return newQuery.id - } - - handleTabClose = (id: string) => { - this.props.queries.deleteQuery(id) - const model = monaco.editor.getModel(monaco.Uri.parse(`file:///${id}`)) - if (model) { - model.dispose() - } - } - - handleTabRename = (id: string, newTitle: string) => { - this.props.queries.updateQuery(id, { title: newTitle }) - } - - handleEditorChange = (newQuery: string | undefined) => { - if (newQuery !== undefined && this.state.currentQuery) { - this.props.queries.updateQuery(this.state.currentQuery.id, { query: newQuery }) - this.props.onQueryChange(newQuery) +const AppBar = styled(MuiAppBar, { + shouldForwardProp: (prop) => prop !== 'open', +})(({ theme }) => ({ + position: 'absolute', + boxShadow: 'none', + borderBottom: `1px solid ${theme.palette.divider}`, + transition: theme.transitions.create(['margin', 'width'], { + easing: theme.transitions.easing.sharp, + duration: theme.transitions.duration.leavingScreen, + }), + variants: [ + { + props: ({ open }) => open, + style: { + width: `calc(100% - ${DRAWER_WIDTH}px)`, + marginLeft: `${DRAWER_WIDTH}px`, + transition: theme.transitions.create(['margin', 'width'], { + easing: theme.transitions.easing.easeOut, + duration: theme.transitions.duration.enteringScreen, + }), + }, + }, + ], +})) + +export const QueryEditor = ({ height, theme, enableCatalogSearchColumns }: IQueryEditor) => { + const [queries, setQueries] = useState(() => new Queries()) + const [drawerOpen, setDrawerOpen] = useState(true) + const [queryRunning, setQueryRunning] = useState(false) + const [currentQuery, setCurrentQuery] = useState(queries.getCurrentQuery()) + const prefersDarkMode = useMediaQuery('(prefers-color-scheme: dark)') + const containerRef = useRef(null) + + const muiThemeToUse = () => { + if (theme === 'dark') { + return darkTheme + } else if (theme === 'light') { + return lightTheme + } else if (prefersDarkMode) { + return darkTheme + } else { + return lightTheme } } - handleSubstitutionChange = (newSubstitutions: Record) => { - this.setState({ substitutions: newSubstitutions }) - } - - toggleMaximize = () => { - this.setState((prevState) => ({ - isMaximized: !prevState.isMaximized, - // 2.5 em for the tab bar, 3em for the substitution editor, 3em for the brand bar - height: !prevState.isMaximized ? 'calc(100vh - 2.5em - 3em - 3.5em)' : '40vh', - width: '100%', - })) - } - - // method to get contents of react editor - getContent() { - return this.openModel.getValue() - } + const applyQueryUpdates = (updates: Partial) => { + const activeQuery = queries.getCurrentQuery() - async parseAndDecoratePromiseAsync(monaco: any, editor: any, waitForUserToStopTyping: number): Promise { - if (this.isRunningParse) { - //console.error("cancelled parsing:" + this.isRunningParse); - return false + if (!activeQuery) { + return } - this.isRunningParse = true - this.parseCancelToken.cancel = false - - try { - let lastUpdateCounter = 0 - - // Wait for the user to stop typing before parsing - do { - await new Promise((resolve, reject) => { - setTimeout(() => { - this.parseCancelToken.cancel ? reject(new Error('Parsing cancelled')) : resolve() - }, waitForUserToStopTyping) - }) - lastUpdateCounter = this.updateCounter - } while (lastUpdateCounter !== this.updateCounter) - - if (this.parseCancelToken.cancel) { - //console.error("cancelled parsing"); - return false - } - - // Call sync method - return this.parseAndDecoratePromise(monaco, editor, lastUpdateCounter) - } catch (error) { - //console.error(error); - return false - } finally { - this.isRunningParse = false - //console.error("end parsing:" + this.isRunningParse); - } + queries.updateQuery(activeQuery.id, updates) + setCurrentQuery((prev) => ({ ...prev, ...updates })) } - // Takes the editor and parses the text, then decorates the editor with errors, autocomplete, and special syntax highlighting - parseAndDecoratePromise(monaco: any, editor: any, lastUpdateCounter: number): boolean { - const newValue: string = editor.getValue() - const lines: string[] = newValue.split('\n') - const caretPosition: editor_api.Position = editor.getPosition() - - // Gather information about the cursor position - let currentWord = '' - const currentLine: string = lines[caretPosition.lineNumber - 1] - // note: column is 1 indexed, so current position is - 1, previous character is - 2 - const isCursorSurroundedBySpaces = - currentLine[caretPosition.column - 2] == ' ' && - (currentLine[caretPosition.column - 1] == ' ' || caretPosition.column == currentLine.length + 1) - let startWordColumn = caretPosition.column - let endWord = caretPosition.column - 1 - // get characters before the current word - // The cursor position after typing a word is at the end of the word, like this: `word|` - // So: - start -1 to get the last character of the word to the left - // - then -1 because the column is 1 indexed - for (let i = caretPosition.column - 1; i >= 1; i--) { - if (currentLine[i - 1] == ' ' || currentLine[i - 1] == ',') { - break - } - currentWord = currentLine[i - 1] + currentWord - startWordColumn = i - } - - // get characters after the current word - for (let i = caretPosition.column; i < currentLine.length; i++) { - if (currentLine[i - 1] == ' ' || currentLine[i - 1] == ',') { - break - } - currentWord += currentLine[i - 1] - endWord = i - } - - // In parseAndDecoratePromise, after calculating currentWord: - console.log('Current word being parsed:', currentWord) - console.log('Cursor position:', caretPosition.lineNumber, caretPosition.column) - console.log('Word bounds:', startWordColumn, 'to', endWord) - - const inputStream = CharStream.fromString(newValue) - const lexer = new SqlBaseLexer(inputStream) - const tokenStream = new CommonTokenStream(lexer) - const parser = new SqlBaseParser(tokenStream) - - // Pass the current catalog and schema to the listener - const listener = new SqlBaseListenerImpl(this.props.catalog, this.props.schema) - - parser.addParseListener(listener) - // Remove default error listeners for SQL and add our custom one - parser.removeErrorListeners() - const errors: SqlBaseErrorListener = new SqlBaseErrorListener() - parser.addErrorListener(errors) - // Build a parsed structure for a single statement - const tree = parser.singleStatement() - - let currentTreePosition: any = undefined - let currentTreeIndex: number = 0 - - let statements = listener.statements - let namedQueries = listener.namedQueries - currentTreePosition = this.parseTreeFromPosition(tree, caretPosition.column, caretPosition.lineNumber) - if (statements.length == 0 && currentTreePosition == undefined) { - // reconstruct input inserting an underscore at the cursor position - const phantomKeyword: string = 'i' - const newLine = - currentLine.substring(0, caretPosition.column - 1) + - phantomKeyword + - currentLine.substring(caretPosition.column - 1) - const newText = - lines.slice(0, caretPosition.lineNumber - 1).join('\n') + - newLine + - (lines.length > caretPosition.lineNumber ? '\n' + lines.slice(caretPosition.lineNumber).join('\n') : '') - - const inputStreamWithChar = CharStream.fromString(newText) - const lexerWithChar = new SqlBaseLexer(inputStreamWithChar) - const tokenStreamWithChar = new CommonTokenStream(lexerWithChar) - const parserWithChar = new SqlBaseParser(tokenStreamWithChar) - const listenerWithChar = new SqlBaseListenerImpl(this.props.catalog, this.props.schema) - parserWithChar.addParseListener(listenerWithChar) - const treeWithChar = parserWithChar.singleStatement() - currentTreePosition = this.parseTreeFromPosition( - treeWithChar, - caretPosition.column - 1, - caretPosition.lineNumber, - '' - ) - statements = listenerWithChar.statements - namedQueries = listenerWithChar.namedQueries - //console.log("created phantom"); - } else { - // symbol covering caret position - currentTreePosition = this.parseTreeFromPosition(tree, caretPosition.column, caretPosition.lineNumber) - } - - if (currentTreePosition != undefined && currentTreePosition.symbol != undefined) { - currentTreeIndex = currentTreePosition.symbol.tokenIndex - //console.log("found symbol at " + currentTreePosition.symbol.tokenIndex); - } else { - currentTreeIndex = currentTreePosition.ruleIndex - } - - const markers = errors.getMarkers() - monaco.editor.setModelMarkers(editor.getModel(), 'owner', markers) + const setQueryContent = (query: string, catalog?: string, schema?: string) => { + const updates: Partial = {} - // Add decorations for table names - editor.removeDecorationsCollection - if (this.decorations) { - this.decorations.clear() + if (query) { + updates.query = query } - this.decorations = editor.createDecorationsCollection(listener.getDecorations()) - // Autocomplete handling happend after the parse - // Verify no typing - if (this.updateCounter != lastUpdateCounter) { - return false + if (catalog) { + updates.catalog = catalog } - const core = new c3.CodeCompletionCore(parser) - core.showDebugOutput = false // logging debug info from parser - - // create a set of rules that should be used for code completion - const ruleSet = new Set([SqlBaseParser.RULE_selectItem]) - core.preferredRules = ruleSet - - const candidates = core.collectCandidates(currentTreeIndex) - - this.generateLexerAutocompleteCandidates( - lines, - parser, - startWordColumn, - endWord, - caretPosition, - monaco, - editor, - core, - candidates, - currentTreePosition, - statements, - namedQueries - ) - - this.isRunningParse = false - return true - } - - checkForParentOfContext(currentTreePosition: any, parentType: any): boolean { - let current: any = currentTreePosition - while (current) { - if (current instanceof parentType) { - return true - } - current = current.parent + if (schema) { + updates.schema = schema } - return false - } - - createCompletionItem( - match: string, - replace: string, - caretPosition: editor_api.Position, - startWordColumn: number, - endWordColumn: number - ) { - return { - label: match, - kind: editor_api.languages.CompletionItemKind.Keyword, - insertText: replace, - insertTextRules: editor_api.languages.CompletionItemInsertTextRule.None, - // Use Monaco's preferred format for ranges - range: { - startLineNumber: caretPosition.lineNumber, - startColumn: startWordColumn, - endLineNumber: caretPosition.lineNumber, - endColumn: Math.max(startWordColumn, caretPosition.column), // Use at least the cursor position - }, - } + applyQueryUpdates(updates) } - generateLexerAutocompleteCandidates( - lines: string[], - parser: SqlBaseParser, - startWordColumn: number, - endWord: number, - caretPosition: editor_api.Position, - monaco: any, - editor: any, - core: any, - candidates: any, - currentTreePosition: any, - statements: StatementDescriptor[], - namedQueries: Map - ) { - // At the beginning: - // console.log("Generating autocomplete candidates"); - // console.log("Word bounds passed:", startWordColumn, "to", endWord); - const endWordLineOffset: number = endWord + 1 - - const keywords: string[] = [] - const completionItems: CompletionItemImpl[] = [] - for (const candidate of candidates.tokens) { - //var tokenType = parser.getTokenType(candidate[0]); - let displayName = parser.vocabulary.getSymbolicName(candidate[0]) - - if (candidate[1].length > 0) { - for (const candidateId of candidate[1]) { - displayName += ' ' + parser.vocabulary.getSymbolicName(candidateId) - } - } - - if (displayName) { - completionItems.push( - this.createCompletionItem( - displayName.toLowerCase(), - displayName.toLowerCase() + ' ', - caretPosition, - startWordColumn, - startWordColumn + displayName.length - ) - ) - if (displayName.toLowerCase() == 'select') { - completionItems.push( - this.createCompletionItem( - 'select * from', - 'select * from ', - caretPosition, - startWordColumn, - endWordLineOffset - ) - ) - } - if (displayName.toLowerCase() == 'limit') { - completionItems.push( - this.createCompletionItem( - 'limit 5', - 'limit 5', - caretPosition, - startWordColumn, - endWordLineOffset - ) - ) - } - if (displayName.toLowerCase() == 'with') { - completionItems.push( - this.createCompletionItem( - 'with query as (select * from )', - 'with query as (select * from )', - caretPosition, - startWordColumn, - endWordLineOffset - ) - ) - } - } - } - - //console.log("Keyword completion items:", completionItems.length); - - // check if parent is the parser's TableNameContext - if (this.checkForParentOfContext(currentTreePosition, TableNameContext)) { - // loop through all tables in the catalog - const tableNames: string[] = SchemaProvider.getTableNameList(undefined, undefined) - for (const tableName of tableNames) { - completionItems.push( - new CompletionItemImpl( - tableName, - editor_api.languages.CompletionItemKind.Reference, - tableName, - monaco.languages.CompletionItemInsertTextRule.None, - { - startLineNumber: caretPosition.lineNumber, - startColumn: startWordColumn, - endLineNumber: caretPosition.lineNumber, - endColumn: endWordLineOffset, - } - ) - ) - } + const appendQueryContent = (query: string, catalog?: string, schema?: string) => { + const activeQuery = queries.getCurrentQuery() + const updates: Partial = {} - // add named queries - for (const [key, value] of namedQueries) { - completionItems.push( - new CompletionItemImpl( - key, - editor_api.languages.CompletionItemKind.Reference, - key, - monaco.languages.CompletionItemInsertTextRule.None, - { - startLineNumber: caretPosition.lineNumber, - startColumn: startWordColumn, - endLineNumber: caretPosition.lineNumber, - endColumn: endWordLineOffset, - } - ) - ) - } + if (query !== undefined) { + const existingQuery = activeQuery.query || '' + const separator = existingQuery.trim() === '' || query.trim() === '' ? '' : '\n\n' + updates.query = existingQuery + separator + query } - //console.log("After table names, completion items:", completionItems.length); - for (const statement of statements) { - console.log(statement) - // log location of caret vs statement position - console.log('caret: ' + caretPosition.column + ' ' + caretPosition.lineNumber) - console.log('statement start: ' + statement.start.column + ' ' + statement.start.line) - console.log('statement end: ' + statement.end.column + ' ' + statement.end.line) - - // if inside ColumnReferenceContext, we can use the table name to get the columns - if ( - (caretPosition.column >= statement.start.column && statement.start.line == caretPosition.lineNumber) || - (caretPosition.column <= statement.end.column && statement.end.line == caretPosition.lineNumber) || - (caretPosition.lineNumber > statement.start.line && caretPosition.lineNumber < statement.end.line) - ) { - console.log('Found statement') - - const tableName: string = statement.tableName - let tableReference: TableReference | undefined - if (TableReference.isFullyQualified(tableName)) { - tableReference = TableReference.fromFullyQualified(tableName) - } else if (this.props.catalog && this.props.schema) { - // Use current catalog and schema from props - tableReference = new TableReference(this.props.catalog, this.props.schema, tableName) - } - - if (tableReference) { - SchemaProvider.getTableWithCache(tableReference, (table: Table) => { - for (const column of table.getColumns()) { - completionItems.push( - new CompletionItemImpl( - column.getName(), - editor_api.languages.CompletionItemKind.Field, - column.getName(), - monaco.languages.CompletionItemInsertTextRule.None, - { - insert: { - startLineNumber: caretPosition.lineNumber, - startColumn: startWordColumn, - endLineNumber: caretPosition.lineNumber, - endColumn: endWordLineOffset, - }, - replace: { - startLineNumber: caretPosition.lineNumber, - startColumn: startWordColumn, - endLineNumber: caretPosition.lineNumber, - endColumn: endWordLineOffset, - }, - } - ) - ) - } - - const singleListOfColumnsJoinedByCommas: string = - '\n ' + - table - .getColumns() - .map((column: Column) => column.getName()) - .join('\n ,') - - completionItems.push( - new CompletionItemImpl( - singleListOfColumnsJoinedByCommas, - editor_api.languages.CompletionItemKind.Field, - singleListOfColumnsJoinedByCommas + ' ', - monaco.languages.CompletionItemInsertTextRule.None, - { - insert: { - startLineNumber: caretPosition.lineNumber, - startColumn: startWordColumn, - endLineNumber: caretPosition.lineNumber, - endColumn: endWordLineOffset, - }, - replace: { - startLineNumber: caretPosition.lineNumber, - startColumn: startWordColumn, - endLineNumber: caretPosition.lineNumber, - endColumn: endWordLineOffset, - }, - } - ) - ) - }) - } - } - } - - const selectNames: string[] = [] - for (const candidate of candidates.rules) { - switch (candidate[0]) { - case SqlBaseParser.RULE_selectItem: { - // unused - } - } - } - - // Finally combine all found lists into one for the UI. - // We do that in separate steps so that you can apply some ordering to each of your sub lists. - // Then you also can order symbols groups as a whole depending their importance. - // let candidates: string[] = []; - // candidates.push(...keywords); - // candidates.push(...functionNames); - - if (completionItems.length > 0) { - this.completionItems = completionItems - this.lastCompletionItemsPosition = caretPosition - } - - // At the very end of the method: - console.log('Final completion items:', completionItems.length) - } - - cancelParsing() { - //console.error("CANCEL"); - this.parseCancelToken.cancel = true - this.isRunningParse = false - } - - editorDidMount = (editor: monaco.editor.IStandaloneCodeEditor, monaco: typeof import('monaco-editor')) => { - this.setEditorRef(editor) - - editor.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.Enter, () => { - this.props.onExecute() - }) - - editor.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.Enter, () => { - // execute the query on ctrl+enter - this.props.onExecute() - }) - - editor.addAction({ - id: 'format-sql', - label: 'Format SQL', - keybindings: [monaco.KeyMod.Alt | monaco.KeyMod.Shift | monaco.KeyCode.KeyF], - contextMenuGroupId: 'modification', - contextMenuOrder: 1.5, - run: () => { - this.formatSql() - }, - }) - - // Check if the provider is already registered - if (!monaco.languages.getLanguages().some((lang: any) => lang.id === TRINO_SQL_LANGUAGE)) { - monaco.languages.register({ id: TRINO_SQL_LANGUAGE }) - - monaco.languages.setTokensProvider(TRINO_SQL_LANGUAGE, { - getInitialState: () => new CustomTokenizerState(), - tokenize: (line: any, state: any) => { - const inputStream = CharStream.fromString(line) - const lexer = new SqlBaseLexer(inputStream) - const tokenStream = new CommonTokenStream(lexer) - lexer.reset() - - const tokens = [] - let token = lexer.nextToken() - while (token.type !== SqlBaseLexer.EOF) { - tokens.push({ - startIndex: token.start, - scopes: tokenMap[token.type as keyof typeof tokenMap] || 'identifier', - }) - token = lexer.nextToken() - } - - return { tokens, endState: state } - }, - }) - - monaco.languages.registerCompletionItemProvider(TRINO_SQL_LANGUAGE, { - provideCompletionItems: async (model: any, position: any) => { - this.cancelParsing() // Cancel any ongoing parsing - const parseResult = await this.parseAndDecoratePromiseAsync(monaco, editor, 0) - if ( - this.lastCompletionItemsPosition && - this.lastCompletionItemsPosition.lineNumber == position.lineNumber && - this.lastCompletionItemsPosition.column == position.column - ) { - return { suggestions: this.completionItems } - } else { - return { suggestions: [] } // either parsing failed or the position is not the same as the last parse - } - }, - }) + if (catalog !== undefined) { + updates.catalog = catalog } - editor.onDidChangeModelContent(async (e: any) => { - this.updateCounter++ - this.handleEditorChange(editor.getValue()) - await this.parseAndDecoratePromiseAsync(monaco, editor, 200).then((result) => { - //console.log("done parsing"); - }) - }) - - editor.onDidChangeCursorSelection(() => { - const selection = editor.getSelection() - if (selection == null) { - return - } - if (selection.startLineNumber != selection.endLineNumber || selection.startColumn != selection.endColumn) { - const model = editor.getModel() - if (model) { - const selectedText = model.getValueInRange(selection) - this.props.onSelectChange(selectedText) - } - } else { - this.props.onSelectChange(editor.getValue()) - } - }) - - // init the parser once to get the initial state - this.parseAndDecoratePromiseAsync(monaco, editor, 0).then((result) => { - //console.log("done parsing"); - }) - } - - parseTreeFromPosition( - root: ParseTree, - cursorColumnOffsetZero: number, - row: number, - phantomKeyword: string = '' - ): any | undefined { - // Does the root node actually contain the position? If not, we don't need to look further. - if (root instanceof TerminalNode) { - const terminal = root as TerminalNode - const token = terminal.symbol - if (token.line != row) return undefined - //let tokenStop = token.column + (token.stop - token.start + 1); - if (cursorColumnOffsetZero >= token.column && token.text !== phantomKeyword && token.text !== '') { - // all we care about is whether it's the last token after this one starts - return terminal - } - return undefined - } else { - const context = root as ParserRuleContext - if (!context.start || !context.stop) { - // Invalid tree? - return undefined - } - - let result = undefined - if (context.children) { - let lastresult = undefined - for (const child of context.children) { - result = this.parseTreeFromPosition(child, cursorColumnOffsetZero, row, phantomKeyword) - if (result == undefined && lastresult != undefined) { - return lastresult - } - lastresult = result - } - if (result != undefined) { - return result - } - } - - if ( - context.children && - context.children.length > 1 && - context.children[0].getText() !== phantomKeyword && - context.children[0].getText() !== '' - ) { - return context.children[0] - } else { - return undefined - } + if (schema !== undefined) { + updates.schema = schema } - } - - // Format the entire SQL query - formatSql = () => { - if (this.editorRef) { - const currentValue = this.editorRef.getValue() - - try { - const config = { - indent: ' ', - uppercase: true, - linesBetweenQueries: 2, - } - const formattedSql = format(currentValue, config) - - // Replace the entire editor content with the formatted SQL - this.editorRef.setValue(formattedSql) - // Trigger a save to update the query in state - this.handleEditorChange(formattedSql) - } catch (error) { - console.error('Error formatting SQL:', error) - } - } + applyQueryUpdates(updates) } - // Format only the selected text - formatSelection = () => { - if (this.editorRef) { - const selection = this.editorRef.getSelection() - if (!selection || selection.isEmpty()) { - // No selection, format the entire query - this.formatSql() - return - } - - const model = this.editorRef.getModel() - if (model) { - const selectedText = model.getValueInRange(selection) - try { - // Format just the selected text - const config = { - indent: ' ', - uppercase: true, - linesBetweenQueries: 2, - } - const formattedSql = format(selectedText, config) + return ( + + + + - // Replace just the selected part - this.editorRef.executeEdits('format-selection', [ - { - range: selection, - text: formattedSql, - forceMoveMarkers: true, + { - this.setState({ height: newHeight }) - } - - render() { - const options = { - selectOnLineNumbers: true, - } - - const { currentQuery, isMaximized, height, width } = this.state - - return ( - <> - - -
-
-
- - -
- -
-
- - ) - } + }} + variant="persistent" + anchor="left" + open={drawerOpen} + ModalProps={{ + container: containerRef.current, + disablePortal: true, + }} + slotProps={{ + paper: { + sx: { + position: 'absolute', + display: 'flex', + flexDirection: 'column', + overflow: 'hidden', + }, + }, + }} + > + setDrawerOpen(false)} + enableSearchColumns={enableCatalogSearchColumns} + /> +
+ +
+ setDrawerOpen(true)} + theme={theme} + /> +
+
+
+ ) } export default QueryEditor diff --git a/precise/src/QueryEditorPane.tsx b/precise/src/QueryEditorPane.tsx new file mode 100644 index 0000000..31d9452 --- /dev/null +++ b/precise/src/QueryEditorPane.tsx @@ -0,0 +1,951 @@ +import React from 'react' +import { Box, Stack, Tooltip, IconButton } from '@mui/material' +import CodeIcon from '@mui/icons-material/Code' +import Maximize from '@mui/icons-material/Maximize' +import Minimize from '@mui/icons-material/Minimize' +import Editor from '@monaco-editor/react' +import * as monaco from 'monaco-editor/esm/vs/editor/editor.api' +import Queries from './schema/Queries' +import QueryInfo from './schema/QueryInfo' +import EnterpriseTabs from './controls/tabs/EnterpriseTabs' +import * as editor_api from 'monaco-editor/esm/vs/editor/editor.api' +import * as c3 from 'antlr4-c3' +import { CharStream, CommonTokenStream, TerminalNode, ParseTree, ParserRuleContext } from 'antlr4ng' +import { TableNameContext } from './generated/lexer/SqlBase.g4/SqlBaseParser' +import { SqlBaseLexer } from './generated/lexer/SqlBase.g4/SqlBaseLexer' +import { SqlBaseParser } from './generated/lexer/SqlBase.g4/SqlBaseParser' +import SqlBaseErrorListener from './sql/SqlBaseErrorListener' +import SqlBaseListenerImpl from './sql/SqlBaseListenerImpl' +import StatementDescriptor from './sql/StatementDescriptor' +import SchemaProvider from './sql/SchemaProvider' +import TableReference from './schema/TableReference' +import Table from './schema/Table' +import Column from './schema/Column' +import NamedQuery from './sql/NamedQuery' +import { tokenMap } from './sql/TokenMap' +import SubstitutionEditor from './SubstitutionEditor' +import { format } from 'sql-formatter' + +const TRINO_SQL_LANGUAGE = 'trinosql' +const TABS_HEIGHT = 64 + +interface QueryEditorPaneProps { + queries: Queries + maxHeight: number + onQueryChange: (query: string) => void + onSelectChange: (selectedText: string) => void + onExecute: () => void + catalog?: string + schema?: string + theme?: string +} + +interface QueryEditorPaneState { + currentQuery: QueryInfo | null + substitutions: Record + isMaximized: boolean + height: number + width: string +} + +// create a private class that extends CompletionItem +// this class will be used to create the completion items +// for the monaco editor +class CompletionItemImpl implements editor_api.languages.CompletionItem { + label: string + kind: editor_api.languages.CompletionItemKind + tags?: readonly editor_api.languages.CompletionItemTag[] | undefined + detail?: string | undefined + sortText?: string | undefined + filterText?: string | undefined + preselect?: boolean | undefined + insertText: string + insertTextRules?: editor_api.languages.CompletionItemInsertTextRule | undefined + range: editor_api.IRange | editor_api.languages.CompletionItemRanges + commitCharacters?: string[] | undefined + additionalTextEdits?: editor_api.editor.ISingleEditOperation[] | undefined + command?: editor_api.languages.Command | undefined + + constructor( + label: string, + kind: editor_api.languages.CompletionItemKind, + insertText: string, + insertTextRules: editor_api.languages.CompletionItemInsertTextRule, + range: editor_api.IRange | editor_api.languages.CompletionItemRanges + ) { + this.label = label + this.kind = kind + this.insertText = insertText + this.insertTextRules = insertTextRules + this.preselect = false + // single line + this.range = range + } +} + +class CustomTokenizerState implements monaco.languages.IState { + clone(): monaco.languages.IState { + return new CustomTokenizerState() + } + + equals(other: monaco.languages.IState): boolean { + return other instanceof CustomTokenizerState + } +} + +class QueryEditorPane extends React.Component { + private editorRef: monaco.editor.IStandaloneCodeEditor | null = null + private isRunningParse: boolean = false + private updateCounter: number = 0 + private parseCancelToken: { cancel: boolean } = { cancel: false } + private lastCompletionItemsPosition: monaco.Position | undefined = undefined + private completionItems: monaco.languages.CompletionItem[] = [] + + openModel: any = null + decorations: any = null + state: QueryEditorPaneState + + constructor(props: QueryEditorPaneProps) { + super(props) + this.state = { + currentQuery: props.queries.getCurrentQuery(), + substitutions: {}, + isMaximized: false, + height: this.props.maxHeight / 2, + width: '100%', + } + } + + setEditorRef = (editor: monaco.editor.IStandaloneCodeEditor) => { + this.editorRef = editor + } + + componentDidMount() { + this.props.queries.addChangeListener(this.handleQueriesChange) + } + + componentDidUpdate(prevProps: QueryEditorPaneProps) { + if (prevProps.maxHeight !== this.props.maxHeight) { + this.handleHeightChange(this.props.maxHeight) + } + } + + componentWillUnmount() { + this.props.queries.removeChangeListener(this.handleQueriesChange) + } + + handleQueriesChange = () => { + this.setState({ + currentQuery: this.props.queries.getCurrentQuery(), + }) + } + + handleTabChange = (queryId: string) => { + this.props.queries.setCurrentQuery(queryId) + if (this.editorRef) { + const model = monaco.editor.getModel(monaco.Uri.parse(`file:///${queryId}`)) + if (model) { + this.editorRef.setModel(model) + } + } + } + + handleTabSelectAndPromote = (queryId: string) => { + this.props.queries.moveQueryToFront(queryId) + this.props.queries.setCurrentQuery(queryId) + } + + handleTabCreate = () => { + const newQuery = this.props.queries.addQuery(false, 'New Query') + monaco.editor.createModel('', TRINO_SQL_LANGUAGE, monaco.Uri.parse(`file:///${newQuery.id}`)) + this.props.queries.setCurrentQuery(newQuery.id) + return newQuery.id + } + + handleTabClose = (id: string) => { + this.props.queries.deleteQuery(id) + const model = monaco.editor.getModel(monaco.Uri.parse(`file:///${id}`)) + if (model) { + model.dispose() + } + } + + handleTabRename = (id: string, newTitle: string) => { + this.props.queries.updateQuery(id, { title: newTitle }) + } + + handleEditorChange = (newQuery: string | undefined) => { + if (newQuery !== undefined && this.state.currentQuery) { + this.props.queries.updateQuery(this.state.currentQuery.id, { query: newQuery }) + this.props.onQueryChange(newQuery) + } + } + + handleSubstitutionChange = (newSubstitutions: Record) => { + this.setState({ substitutions: newSubstitutions }) + } + + toggleMaximize = () => { + this.setState((prevState) => ({ + isMaximized: !prevState.isMaximized, + height: !prevState.isMaximized ? this.props.maxHeight : this.props.maxHeight / 2, + width: '100%', + })) + } + + // method to get contents of react editor + getContent() { + return this.openModel.getValue() + } + + async parseAndDecoratePromiseAsync(monaco: any, editor: any, waitForUserToStopTyping: number): Promise { + if (this.isRunningParse) { + //console.error("cancelled parsing:" + this.isRunningParse); + return false + } + + this.isRunningParse = true + this.parseCancelToken.cancel = false + + try { + let lastUpdateCounter = 0 + + // Wait for the user to stop typing before parsing + do { + await new Promise((resolve, reject) => { + setTimeout(() => { + this.parseCancelToken.cancel ? reject(new Error('Parsing cancelled')) : resolve() + }, waitForUserToStopTyping) + }) + lastUpdateCounter = this.updateCounter + } while (lastUpdateCounter !== this.updateCounter) + + if (this.parseCancelToken.cancel) { + //console.error("cancelled parsing"); + return false + } + + // Call sync method + return this.parseAndDecoratePromise(monaco, editor, lastUpdateCounter) + } catch (error) { + //console.error(error); + return false + } finally { + this.isRunningParse = false + //console.error("end parsing:" + this.isRunningParse); + } + } + + // Takes the editor and parses the text, then decorates the editor with errors, autocomplete, and special syntax highlighting + parseAndDecoratePromise(monaco: any, editor: any, lastUpdateCounter: number): boolean { + const newValue: string = editor.getValue() + const lines: string[] = newValue.split('\n') + const caretPosition: editor_api.Position = editor.getPosition() + + // Gather information about the cursor position + let currentWord = '' + const currentLine: string = lines[caretPosition.lineNumber - 1] + // note: column is 1 indexed, so current position is - 1, previous character is - 2 + const isCursorSurroundedBySpaces = + currentLine[caretPosition.column - 2] == ' ' && + (currentLine[caretPosition.column - 1] == ' ' || caretPosition.column == currentLine.length + 1) + let startWordColumn = caretPosition.column + let endWord = caretPosition.column - 1 + // get characters before the current word + // The cursor position after typing a word is at the end of the word, like this: `word|` + // So: - start -1 to get the last character of the word to the left + // - then -1 because the column is 1 indexed + for (let i = caretPosition.column - 1; i >= 1; i--) { + if (currentLine[i - 1] == ' ' || currentLine[i - 1] == ',') { + break + } + currentWord = currentLine[i - 1] + currentWord + startWordColumn = i + } + + // get characters after the current word + for (let i = caretPosition.column; i < currentLine.length; i++) { + if (currentLine[i - 1] == ' ' || currentLine[i - 1] == ',') { + break + } + currentWord += currentLine[i - 1] + endWord = i + } + + // In parseAndDecoratePromise, after calculating currentWord: + console.log('Current word being parsed:', currentWord) + console.log('Cursor position:', caretPosition.lineNumber, caretPosition.column) + console.log('Word bounds:', startWordColumn, 'to', endWord) + + const inputStream = CharStream.fromString(newValue) + const lexer = new SqlBaseLexer(inputStream) + const tokenStream = new CommonTokenStream(lexer) + const parser = new SqlBaseParser(tokenStream) + + // Pass the current catalog and schema to the listener + const listener = new SqlBaseListenerImpl(this.props.catalog, this.props.schema) + + parser.addParseListener(listener) + // Remove default error listeners for SQL and add our custom one + parser.removeErrorListeners() + const errors: SqlBaseErrorListener = new SqlBaseErrorListener() + parser.addErrorListener(errors) + // Build a parsed structure for a single statement + const tree = parser.singleStatement() + + let currentTreePosition: any = undefined + let currentTreeIndex: number = 0 + + let statements = listener.statements + let namedQueries = listener.namedQueries + currentTreePosition = this.parseTreeFromPosition(tree, caretPosition.column, caretPosition.lineNumber) + if (statements.length == 0 && currentTreePosition == undefined) { + // reconstruct input inserting an underscore at the cursor position + const phantomKeyword: string = 'i' + const newLine = + currentLine.substring(0, caretPosition.column - 1) + + phantomKeyword + + currentLine.substring(caretPosition.column - 1) + const newText = + lines.slice(0, caretPosition.lineNumber - 1).join('\n') + + newLine + + (lines.length > caretPosition.lineNumber ? '\n' + lines.slice(caretPosition.lineNumber).join('\n') : '') + + const inputStreamWithChar = CharStream.fromString(newText) + const lexerWithChar = new SqlBaseLexer(inputStreamWithChar) + const tokenStreamWithChar = new CommonTokenStream(lexerWithChar) + const parserWithChar = new SqlBaseParser(tokenStreamWithChar) + const listenerWithChar = new SqlBaseListenerImpl(this.props.catalog, this.props.schema) + parserWithChar.addParseListener(listenerWithChar) + const treeWithChar = parserWithChar.singleStatement() + currentTreePosition = this.parseTreeFromPosition( + treeWithChar, + caretPosition.column - 1, + caretPosition.lineNumber, + '' + ) + statements = listenerWithChar.statements + namedQueries = listenerWithChar.namedQueries + //console.log("created phantom"); + } else { + // symbol covering caret position + currentTreePosition = this.parseTreeFromPosition(tree, caretPosition.column, caretPosition.lineNumber) + } + + if (currentTreePosition != undefined && currentTreePosition.symbol != undefined) { + currentTreeIndex = currentTreePosition.symbol.tokenIndex + //console.log("found symbol at " + currentTreePosition.symbol.tokenIndex); + } else { + currentTreeIndex = currentTreePosition.ruleIndex + } + + const markers = errors.getMarkers() + monaco.editor.setModelMarkers(editor.getModel(), 'owner', markers) + + // Add decorations for table names + if (this.decorations) { + this.decorations.clear() + } + this.decorations = editor.createDecorationsCollection(listener.getDecorations()) + + // Autocomplete handling happend after the parse + // Verify no typing + if (this.updateCounter != lastUpdateCounter) { + return false + } + + const core = new c3.CodeCompletionCore(parser) + core.showDebugOutput = false // logging debug info from parser + + // create a set of rules that should be used for code completion + const ruleSet = new Set([SqlBaseParser.RULE_selectItem]) + core.preferredRules = ruleSet + + const candidates = core.collectCandidates(currentTreeIndex) + + this.generateLexerAutocompleteCandidates( + lines, + parser, + startWordColumn, + endWord, + caretPosition, + monaco, + editor, + core, + candidates, + currentTreePosition, + statements, + namedQueries + ) + + this.isRunningParse = false + return true + } + + checkForParentOfContext(currentTreePosition: any, parentType: any): boolean { + let current: any = currentTreePosition + while (current) { + if (current instanceof parentType) { + return true + } + current = current.parent + } + + return false + } + + createCompletionItem( + match: string, + replace: string, + caretPosition: editor_api.Position, + startWordColumn: number, + endWordColumn: number + ) { + return { + label: match, + kind: editor_api.languages.CompletionItemKind.Keyword, + insertText: replace, + insertTextRules: editor_api.languages.CompletionItemInsertTextRule.None, + // Use Monaco's preferred format for ranges + range: { + startLineNumber: caretPosition.lineNumber, + startColumn: startWordColumn, + endLineNumber: caretPosition.lineNumber, + endColumn: Math.max(startWordColumn, caretPosition.column), // Use at least the cursor position + }, + } + } + + generateLexerAutocompleteCandidates( + lines: string[], + parser: SqlBaseParser, + startWordColumn: number, + endWord: number, + caretPosition: editor_api.Position, + monaco: any, + editor: any, + core: any, + candidates: any, + currentTreePosition: any, + statements: StatementDescriptor[], + namedQueries: Map + ) { + // At the beginning: + // console.log("Generating autocomplete candidates"); + // console.log("Word bounds passed:", startWordColumn, "to", endWord); + const endWordLineOffset: number = endWord + 1 + + const keywords: string[] = [] + const completionItems: CompletionItemImpl[] = [] + for (const candidate of candidates.tokens) { + //var tokenType = parser.getTokenType(candidate[0]); + let displayName = parser.vocabulary.getSymbolicName(candidate[0]) + + if (candidate[1].length > 0) { + for (const candidateId of candidate[1]) { + displayName += ' ' + parser.vocabulary.getSymbolicName(candidateId) + } + } + + if (displayName) { + completionItems.push( + this.createCompletionItem( + displayName.toLowerCase(), + displayName.toLowerCase() + ' ', + caretPosition, + startWordColumn, + startWordColumn + displayName.length + ) + ) + if (displayName.toLowerCase() == 'select') { + completionItems.push( + this.createCompletionItem( + 'select * from', + 'select * from ', + caretPosition, + startWordColumn, + endWordLineOffset + ) + ) + } + if (displayName.toLowerCase() == 'limit') { + completionItems.push( + this.createCompletionItem( + 'limit 5', + 'limit 5', + caretPosition, + startWordColumn, + endWordLineOffset + ) + ) + } + if (displayName.toLowerCase() == 'with') { + completionItems.push( + this.createCompletionItem( + 'with query as (select * from )', + 'with query as (select * from )', + caretPosition, + startWordColumn, + endWordLineOffset + ) + ) + } + } + } + + //console.log("Keyword completion items:", completionItems.length); + + // check if parent is the parser's TableNameContext + if (this.checkForParentOfContext(currentTreePosition, TableNameContext)) { + // loop through all tables in the catalog + const tableNames: string[] = SchemaProvider.getTableNameList(undefined, undefined) + for (const tableName of tableNames) { + completionItems.push( + new CompletionItemImpl( + tableName, + editor_api.languages.CompletionItemKind.Reference, + tableName, + monaco.languages.CompletionItemInsertTextRule.None, + { + startLineNumber: caretPosition.lineNumber, + startColumn: startWordColumn, + endLineNumber: caretPosition.lineNumber, + endColumn: endWordLineOffset, + } + ) + ) + } + + // add named queries + for (const [key, value] of namedQueries) { + completionItems.push( + new CompletionItemImpl( + key, + editor_api.languages.CompletionItemKind.Reference, + key, + monaco.languages.CompletionItemInsertTextRule.None, + { + startLineNumber: caretPosition.lineNumber, + startColumn: startWordColumn, + endLineNumber: caretPosition.lineNumber, + endColumn: endWordLineOffset, + } + ) + ) + } + } + + //console.log("After table names, completion items:", completionItems.length); + for (const statement of statements) { + console.log(statement) + // log location of caret vs statement position + console.log('caret: ' + caretPosition.column + ' ' + caretPosition.lineNumber) + console.log('statement start: ' + statement.start.column + ' ' + statement.start.line) + console.log('statement end: ' + statement.end.column + ' ' + statement.end.line) + + // if inside ColumnReferenceContext, we can use the table name to get the columns + if ( + (caretPosition.column >= statement.start.column && statement.start.line == caretPosition.lineNumber) || + (caretPosition.column <= statement.end.column && statement.end.line == caretPosition.lineNumber) || + (caretPosition.lineNumber > statement.start.line && caretPosition.lineNumber < statement.end.line) + ) { + console.log('Found statement') + + const tableName: string = statement.tableName + let tableReference: TableReference | undefined + if (TableReference.isFullyQualified(tableName)) { + tableReference = TableReference.fromFullyQualified(tableName) + } else if (this.props.catalog && this.props.schema) { + // Use current catalog and schema from props + tableReference = new TableReference(this.props.catalog, this.props.schema, tableName) + } + + if (tableReference) { + SchemaProvider.getTableWithCache(tableReference, (table: Table) => { + for (const column of table.getColumns()) { + completionItems.push( + new CompletionItemImpl( + column.getName(), + editor_api.languages.CompletionItemKind.Field, + column.getName(), + monaco.languages.CompletionItemInsertTextRule.None, + { + insert: { + startLineNumber: caretPosition.lineNumber, + startColumn: startWordColumn, + endLineNumber: caretPosition.lineNumber, + endColumn: endWordLineOffset, + }, + replace: { + startLineNumber: caretPosition.lineNumber, + startColumn: startWordColumn, + endLineNumber: caretPosition.lineNumber, + endColumn: endWordLineOffset, + }, + } + ) + ) + } + + const singleListOfColumnsJoinedByCommas: string = + '\n ' + + table + .getColumns() + .map((column: Column) => column.getName()) + .join('\n ,') + + completionItems.push( + new CompletionItemImpl( + singleListOfColumnsJoinedByCommas, + editor_api.languages.CompletionItemKind.Field, + singleListOfColumnsJoinedByCommas + ' ', + monaco.languages.CompletionItemInsertTextRule.None, + { + insert: { + startLineNumber: caretPosition.lineNumber, + startColumn: startWordColumn, + endLineNumber: caretPosition.lineNumber, + endColumn: endWordLineOffset, + }, + replace: { + startLineNumber: caretPosition.lineNumber, + startColumn: startWordColumn, + endLineNumber: caretPosition.lineNumber, + endColumn: endWordLineOffset, + }, + } + ) + ) + }) + } + } + } + + const selectNames: string[] = [] + for (const candidate of candidates.rules) { + switch (candidate[0]) { + case SqlBaseParser.RULE_selectItem: { + // unused + } + } + } + + // Finally combine all found lists into one for the UI. + // We do that in separate steps so that you can apply some ordering to each of your sub lists. + // Then you also can order symbols groups as a whole depending their importance. + // let candidates: string[] = []; + // candidates.push(...keywords); + // candidates.push(...functionNames); + + if (completionItems.length > 0) { + this.completionItems = completionItems + this.lastCompletionItemsPosition = caretPosition + } + + // At the very end of the method: + console.log('Final completion items:', completionItems.length) + } + + cancelParsing() { + //console.error("CANCEL"); + this.parseCancelToken.cancel = true + this.isRunningParse = false + } + + editorDidMount = (editor: monaco.editor.IStandaloneCodeEditor, monaco: typeof import('monaco-editor')) => { + this.setEditorRef(editor) + + editor.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.Enter, () => { + this.props.onExecute() + }) + + editor.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.Enter, () => { + // execute the query on ctrl+enter + this.props.onExecute() + }) + + editor.addAction({ + id: 'format-sql', + label: 'Format SQL', + keybindings: [monaco.KeyMod.Alt | monaco.KeyMod.Shift | monaco.KeyCode.KeyF], + contextMenuGroupId: 'modification', + contextMenuOrder: 1.5, + run: () => { + this.formatSql() + }, + }) + + // Check if the provider is already registered + if (!monaco.languages.getLanguages().some((lang: any) => lang.id === TRINO_SQL_LANGUAGE)) { + monaco.languages.register({ id: TRINO_SQL_LANGUAGE }) + + monaco.languages.setTokensProvider(TRINO_SQL_LANGUAGE, { + getInitialState: () => new CustomTokenizerState(), + tokenize: (line: any, state: any) => { + const inputStream = CharStream.fromString(line) + const lexer = new SqlBaseLexer(inputStream) + const tokenStream = new CommonTokenStream(lexer) + lexer.reset() + + const tokens = [] + let token = lexer.nextToken() + while (token.type !== SqlBaseLexer.EOF) { + tokens.push({ + startIndex: token.start, + scopes: tokenMap[token.type as keyof typeof tokenMap] || 'identifier', + }) + token = lexer.nextToken() + } + + return { tokens, endState: state } + }, + }) + + monaco.languages.registerCompletionItemProvider(TRINO_SQL_LANGUAGE, { + provideCompletionItems: async (model: any, position: any) => { + this.cancelParsing() // Cancel any ongoing parsing + const parseResult = await this.parseAndDecoratePromiseAsync(monaco, editor, 0) + if ( + this.lastCompletionItemsPosition && + this.lastCompletionItemsPosition.lineNumber == position.lineNumber && + this.lastCompletionItemsPosition.column == position.column + ) { + return { suggestions: this.completionItems } + } else { + return { suggestions: [] } // either parsing failed or the position is not the same as the last parse + } + }, + }) + } + + editor.onDidChangeModelContent(async (e: any) => { + this.updateCounter++ + this.handleEditorChange(editor.getValue()) + await this.parseAndDecoratePromiseAsync(monaco, editor, 200).then((result) => { + //console.log("done parsing"); + }) + }) + + editor.onDidChangeCursorSelection(() => { + const selection = editor.getSelection() + if (selection == null) { + return + } + if (selection.startLineNumber != selection.endLineNumber || selection.startColumn != selection.endColumn) { + const model = editor.getModel() + if (model) { + const selectedText = model.getValueInRange(selection) + this.props.onSelectChange(selectedText) + } + } else { + this.props.onSelectChange(editor.getValue()) + } + }) + + // init the parser once to get the initial state + this.parseAndDecoratePromiseAsync(monaco, editor, 0).then((result) => { + //console.log("done parsing"); + }) + } + + parseTreeFromPosition( + root: ParseTree, + cursorColumnOffsetZero: number, + row: number, + phantomKeyword: string = '' + ): any | undefined { + // Does the root node actually contain the position? If not, we don't need to look further. + if (root instanceof TerminalNode) { + const terminal = root as TerminalNode + const token = terminal.symbol + if (token.line != row) return undefined + //let tokenStop = token.column + (token.stop - token.start + 1); + if (cursorColumnOffsetZero >= token.column && token.text !== phantomKeyword && token.text !== '') { + // all we care about is whether it's the last token after this one starts + return terminal + } + return undefined + } else { + const context = root as ParserRuleContext + if (!context.start || !context.stop) { + // Invalid tree? + return undefined + } + + let result = undefined + if (context.children) { + let lastresult = undefined + for (const child of context.children) { + result = this.parseTreeFromPosition(child, cursorColumnOffsetZero, row, phantomKeyword) + if (result == undefined && lastresult != undefined) { + return lastresult + } + lastresult = result + } + if (result != undefined) { + return result + } + } + + if ( + context.children && + context.children.length > 1 && + context.children[0].getText() !== phantomKeyword && + context.children[0].getText() !== '' + ) { + return context.children[0] + } else { + return undefined + } + } + } + + // Format the entire SQL query + formatSql = () => { + if (this.editorRef) { + const currentValue = this.editorRef.getValue() + + try { + const config = { + indent: ' ', + uppercase: true, + linesBetweenQueries: 2, + } + const formattedSql = format(currentValue, config) + + // Replace the entire editor content with the formatted SQL + this.editorRef.setValue(formattedSql) + + // Trigger a save to update the query in state + this.handleEditorChange(formattedSql) + } catch (error) { + console.error('Error formatting SQL:', error) + } + } + } + + // Format only the selected text + formatSelection = () => { + if (this.editorRef) { + const selection = this.editorRef.getSelection() + if (!selection || selection.isEmpty()) { + // No selection, format the entire query + this.formatSql() + return + } + + const model = this.editorRef.getModel() + if (model) { + const selectedText = model.getValueInRange(selection) + try { + // Format just the selected text + const config = { + indent: ' ', + uppercase: true, + linesBetweenQueries: 2, + } + const formattedSql = format(selectedText, config) + + // Replace just the selected part + this.editorRef.executeEdits('format-selection', [ + { + range: selection, + text: formattedSql, + forceMoveMarkers: true, + }, + ]) + } catch (error) { + console.error('Error formatting selection:', error) + } + } + } + } + + handleHeightChange = (maxHeight: number) => { + this.setState({ height: this.state.isMaximized ? maxHeight : maxHeight / 2 }) + } + + render() { + const options = { + selectOnLineNumbers: true, + } + + const { currentQuery, isMaximized, height, width } = this.state + + return ( + <> + + + + ({ + position: 'absolute', + alignItems: 'center', + background: theme.palette.background.default, + border: 1, + borderColor: theme.palette.divider, + boxShadow: 1, + px: 0.5, + top: 0, + right: 15, + zIndex: 1000, + })} + > + + + + + + + + {isMaximized ? ( + + ) : ( + + )} + + + + + + + + + ) + } +} + +export default QueryEditorPane diff --git a/precise/src/ResultSet.tsx b/precise/src/ResultSet.tsx index 46da4ac..fbc4c6a 100644 --- a/precise/src/ResultSet.tsx +++ b/precise/src/ResultSet.tsx @@ -1,17 +1,33 @@ import React from 'react' -import QueryInfo from './schema/QueryInfo' +import { + Alert, + Box, + CircularProgress, + LinearProgress, + Link, + Paper, + Stack, + Table, + TableBody, + TableCell, + TableContainer, + TableFooter, + TableHead, + TableRow, + Typography, +} from '@mui/material' +import { DataGrid, GridColDef } from '@mui/x-data-grid' +import Chip, { ChipProps } from '@mui/material/Chip' import ReactDOMServer from 'react-dom/server' -import ErrorBox from './utils/ErrorBoxProvider' -import ProgressBar from './utils/ProgressBar' import CopyLink from './utils/CopyLink' import ClearButton from './utils/ClearButton' -import './style/results.css' interface ResultSetProps { - queryInfo: QueryInfo | undefined + queryId: string | undefined results: any[] columns: any[] response: any + height: number errorMessage: string onClearResults: (queryId: string | undefined) => void } @@ -21,6 +37,38 @@ class ResultSet extends React.Component { statsHistory: any[] = [] lastQueryId: string | undefined = undefined + static readonly STATE_COLOR_MAP: Record = { + QUEUED: 'default', + RUNNING: 'info', + PLANNING: 'info', + FINISHED: 'success', + BLOCKED: 'secondary', + USER_ERROR: 'error', + CANCELED: 'warning', + INSUFFICIENT_RESOURCES: 'error', + EXTERNAL_ERROR: 'error', + UNKNOWN_ERROR: 'error', + } + + getQueryStateColor(queryState: string): ChipProps['color'] { + switch (queryState) { + case 'QUEUED': + return ResultSet.STATE_COLOR_MAP.QUEUED + case 'PLANNING': + return ResultSet.STATE_COLOR_MAP.PLANNING + case 'STARTING': + case 'FINISHING': + case 'RUNNING': + return ResultSet.STATE_COLOR_MAP.RUNNING + case 'FAILED': + return ResultSet.STATE_COLOR_MAP.UNKNOWN_ERROR + case 'FINISHED': + return ResultSet.STATE_COLOR_MAP.FINISHED + default: + return ResultSet.STATE_COLOR_MAP.QUEUED + } + } + renderHeader(columns: any) { return ( @@ -60,11 +108,27 @@ class ResultSet extends React.Component { ) } - renderTable = (results: any[], response: any, columns: any) => { + renderTable = (results: any[], columns: any) => { + const muiColumns: GridColDef[] = columns.map((column: any) => ({ field: column.name, minWidth: 150 })) + const muiRows = results + .flat() + .map((row: any[], i: number) => + Object.fromEntries([ + ['mui-row-id', `row-${i + 1}`], + ...columns.map((c: any, j: number) => [c.name, row[j]]), + ]) + ) + return ( -
30 ? 'scrollable' : 'result-table-container'}> - {this.renderInnerTable(results, response, columns)} -
+ String(row['mui-row-id'])} + density="compact" + /> ) } @@ -214,14 +278,14 @@ class ResultSet extends React.Component { } render() { - const { queryInfo, results, columns, response, errorMessage } = this.props + const { queryId, results, columns, response, height, errorMessage } = this.props // if the query ID has changed, reset the last processed rows and elapsed time - if (queryInfo == null || this.lastQueryId !== queryInfo.id) { + if (this.lastQueryId !== queryId) { this.reset() } - this.lastQueryId = queryInfo?.id + this.lastQueryId = queryId // new implementation, look over 10 second window in stats history let processedRowsSinceLast = 0 @@ -271,239 +335,289 @@ class ResultSet extends React.Component { // Ensure the 'result-set' class is applied to the container return ( -
- { - // only return if there are columns - columns && columns.length ? ( -
- {response.stats && this.isFinishedFailedOrCancelled(response.stats.state) && ( - this.props.onClearResults(queryInfo?.id)} /> - )} - this.copy()} /> - {/* if row count > 30 place in scrollable div */} - {this.renderTable(results, response, columns)} -
- ) : null - } + {response && response.id ? ( -
- {this.getRowCount()} rows:{' '} - - {response.id} - -
+ + {errorMessage ? ( + + {errorMessage} + + ) : null} + + + {this.getRowCount()} rows: + + + {response.id} + + {columns && columns.length ? ( + response.stats && this.isFinishedFailedOrCancelled(response.stats.state) ? ( + <> + this.props.onClearResults(queryId)} /> + this.copy()} /> + + ) : null + ) : null} + + ) : null} - {errorMessage ? : null} {/* if the status is not finished, show spinner */} {response && response.stats && response.stats.state !== 'FINISHED' && response.stats.state !== 'FAILED' && response.stats.state !== 'CANCELLED' ? ( -
-
-
-
-
- {response && response.stats && response.stats.runningPercentage - ? Math.floor(response.stats.runningPercentage) - : 0} - % -
-
- {response.stats.state} -
+ <> + + + + {response && response.stats && response.stats.progressPercentage + ? Math.floor(response.stats.progressPercentage) + : 0} + % + + + + Workers: {response.stats.nodes}, Running splits: {response.stats.runningSplits}, Total splits: {response.stats.totalSplits}, Run time:{' '} {Math.floor(response.stats.elapsedTimeMillis / 1000)}s -
-
-
-
-
- -
- {this.formatMillisAsHHMMSS(response.stats.elapsedTimeMillis)} -
-
-
- {/* if response.stats.subStages */} - {response.stats.rootStage && response.stats.rootStage.subStages ? ( -
- - - - {' '} - {/* groupings for subcategories of metrics */} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {/* look at all the substages in subStages */} - {stages.map((subStageInfo: any) => { - return ( - + + + + + + {this.formatMillisAsHHMMSS(response.stats.elapsedTimeMillis)} + + + + {response.stats.rootStage && response.stats.rootStage.subStages ? ( + +
- Rows - - Bytes - - Splits -
StageNodesProcessedRateCurrent RateProcessedRateCurrent RateInput ProcessedQueuedRunningDone
0 (root){response.stats.rootStage.nodes} - {this.rowCountToCorrectScale(response.stats.rootStage.processedRows)} - - {this.rowCountToCorrectScale( - response.stats.rootStage.processedRows / - (response.stats.rootStage.wallTimeMillis / 1000) - )} - - {this.bytesToCorrectScale(response.stats.rootStage.processedBytes)} - - {this.bytesToCorrectScale( - response.stats.rootStage.processedBytes / - (response.stats.wallTimeMillis / 1000) - )} - - {this.bytesToCorrectScale(response.stats.rootStage.physicalInputBytes)} - - {response.stats.rootStage.queuedSplits} - - {response.stats.rootStage.runningSplits} - - {response.stats.rootStage.completedSplits} -
*': { + borderRight: (theme) => `1px solid ${theme.palette.divider}`, + }, + '& .MuiTableRow-root > *:last-of-type': { + borderRight: 'none', + }, + }} + size="small" + stickyHeader + > + + + + Query run metrics + + + Rows + + + Bytes + + + Splits + + + + Stage + Nodes + Processed + Rate + Current Rate + Processed + Rate + Current Rate + Input Processed + Queued + Running + Done + + + + + 0 (root) + {response.stats.rootStage.nodes} + + {this.rowCountToCorrectScale( + response.stats.rootStage.processedRows + )} + + + {this.rowCountToCorrectScale( + response.stats.rootStage.processedRows / + (response.stats.rootStage.wallTimeMillis / 1000) + )} + + + + {this.bytesToCorrectScale(response.stats.rootStage.processedBytes)} + + + {this.bytesToCorrectScale( + response.stats.rootStage.processedBytes / + (response.stats.wallTimeMillis / 1000) + )} + + + + {this.bytesToCorrectScale( + response.stats.rootStage.physicalInputBytes + )} + + + {response.stats.rootStage.queuedSplits} + + + {response.stats.rootStage.runningSplits} + + + {response.stats.rootStage.completedSplits} + + + + {/* Sub-stages */} + {stages.map((subStageInfo: any) => ( + - - - - - - - - - - - - - - ) - })} - - - - - - - - - - - - - - - -
- {subStageInfo.stage.stageId} - {subStageInfo.stage.nodes} + {subStageInfo.stage.stageId} + {subStageInfo.stage.nodes} + {this.rowCountToCorrectScale(subStageInfo.stage.processedRows)} - + + {this.rowCountToCorrectScale( subStageInfo.stage.processedRows / (subStageInfo.stage.wallTimeMillis / 1000) )} - + + + {this.bytesToCorrectScale(response.stats.processedBytes)} - + + {this.bytesToCorrectScale( subStageInfo.stage.processedBytes / (subStageInfo.stage.wallTimeMillis / 1000) )} - + + + {this.bytesToCorrectScale(response.stats.physicalInputBytes)} - + + {subStageInfo.stage.queuedSplits} - + + {subStageInfo.stage.runningSplits} - + + {subStageInfo.stage.completedSplits} -
Total{response.stats.nodes} - {this.rowCountToCorrectScale(response.stats.processedRows)} - - {this.rowCountToCorrectScale( - response.stats.processedRows / - (response.stats.elapsedTimeMillis / 1000) - )} - - {this.rowCountToCorrectScale(processedRowsSinceLast)} - - {this.bytesToCorrectScale(response.stats.processedBytes)} - - {this.bytesToCorrectScale( - response.stats.processedBytes / - (response.stats.elapsedTimeMillis / 1000) - )} - - {this.bytesToCorrectScale(response.stats.physicalInputBytes)} - {response.stats.queuedSplits}{response.stats.runningSplits}{response.stats.completedSplits}
-
- ) : null} -
+ + + ))} + + + theme.typography.fontWeightBold, + color: 'text.primary', + }, + }} + > + {/* Totals */} + + Total + {response.stats.nodes} + + {this.rowCountToCorrectScale(response.stats.processedRows)} + + + {this.rowCountToCorrectScale( + response.stats.processedRows / + (response.stats.elapsedTimeMillis / 1000) + )} + + + {this.rowCountToCorrectScale(processedRowsSinceLast)} + + + {this.bytesToCorrectScale(response.stats.processedBytes)} + + + {this.bytesToCorrectScale( + response.stats.processedBytes / + (response.stats.elapsedTimeMillis / 1000) + )} + + + + {this.bytesToCorrectScale(response.stats.physicalInputBytes)} + + {response.stats.queuedSplits} + {response.stats.runningSplits} + {response.stats.completedSplits} + + + + + ) : null} +
+ + ) : columns && columns.length ? ( + + {this.renderTable(results, columns)} + ) : null} -
+ ) } } diff --git a/precise/src/SubstitutionEditor.tsx b/precise/src/SubstitutionEditor.tsx index da81681..c5e1467 100644 --- a/precise/src/SubstitutionEditor.tsx +++ b/precise/src/SubstitutionEditor.tsx @@ -1,4 +1,6 @@ import React, { useState, useEffect } from 'react' +import { Box, Stack, Typography, TextField, InputAdornment, IconButton } from '@mui/material' +import ClearIcon from '@mui/icons-material/Clear' interface SubstitutionField { name: string @@ -60,21 +62,52 @@ const SubstitutionEditor: React.FC = ({ query, onSubsti } return ( -
-

Query Parameters

- {fields.map((field) => ( -
- - handleInputChange(field.name, e.target.value)} - placeholder={field.defaultValue} - /> -
- ))} -
+ + Query Parameters + + {fields.map((field) => { + const isNumber = field.type !== 'varchar' + const val = values[field.name] ?? '' + + return ( + handleInputChange(field.name, e.target.value)} + placeholder={field.defaultValue !== undefined ? String(field.defaultValue) : ''} + slotProps={{ + input: { + // helpful for numeric types + inputProps: isNumber ? { step: field.type === 'double' ? 'any' : 1 } : undefined, + // optional clear button (keeps width stable when empty) + endAdornment: ( + + handleInputChange(field.name, '')} + sx={{ + visibility: val ? 'visible' : 'hidden', + '& .MuiSvgIcon-root': { fontSize: 16 }, + }} + > + + + + ), + }, + }} + /> + ) + })} + + ) } diff --git a/precise/src/assets/close.png b/precise/src/assets/close.png deleted file mode 100644 index cbd90bea7f7a655f062499f7cfa3966fdb924383..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 46334 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 diff --git a/precise/src/assets/pin_down.png b/precise/src/assets/pin_down.png deleted file mode 100644 index 1039779c17a1f167f51a94325d4a2165ff399bb4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 36813 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 IM6N<$g8e-P@c;k- diff --git a/precise/src/assets/pin_up.png b/precise/src/assets/pin_up.png deleted file mode 100644 index 1d3ce9b066659a0b73cd96374aabcfff2ad49d21..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 62626 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

  • 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 void onAppendQuery?: (query: string, catalog?: string, schema?: string) => void + onDrawerToggle?: () => void + enableSearchColumns?: boolean } -const CatalogViewer: React.FC = ({ initialFilterText = '', onGenerateQuery, onAppendQuery }) => { +const CatalogViewer: React.FC = ({ + initialFilterText = '', + onGenerateQuery, + onAppendQuery, + onDrawerToggle, + enableSearchColumns, +}) => { // Basic state const [catalogs, setCatalogs] = useState>(new Map()) const [errorMessage, setErrorMessage] = useState() @@ -27,7 +51,7 @@ const CatalogViewer: React.FC = ({ initialFilterText = '', o // View state const [matches, setMatches] = useState>(new Set()) const [expandedNodes, setExpandedNodes] = useState>(new Set()) - const viewerState = useRef() + const viewerState = useRef(null) const [isLoadingColumns, setIsLoadingColumns] = useState(false) @@ -70,8 +94,8 @@ const CatalogViewer: React.FC = ({ initialFilterText = '', o try { await SchemaProvider.populateCatalogsAndRefreshTableList( - () => { - setCatalogs(SchemaProvider.catalogs) + (nextCatalogs) => { + setCatalogs(nextCatalogs) setIsLoading(false) }, (error: string) => { @@ -153,91 +177,184 @@ const CatalogViewer: React.FC = ({ initialFilterText = '', o } return ( -
    -
    -
    - + `calc(${theme.mixins.toolbar.minHeight}px + ${theme.spacing(1)})`, + px: 0, + py: 0, + }} + > + + setFilterText(e.target.value)} - className="filter-input" + fullWidth /> - {filterText && ( -
    setFilterText('')} - role="button" - aria-label="Clear search" - > - Clear -
    - )} -
    - - - -
    - - {isLoading &&
    Loading catalogs...
    } - - {errorMessage && } - -
    - {Array.from(catalogs.values()) - .sort((a, b) => a.getName().localeCompare(b.getName())) - .map((catalog: Catalog) => { - const catalogName = catalog.getName() - const catalogPath = buildPath.catalog(catalogName) - - if (filterText && !isVisible(catalogPath)) { - return null - } - - return ( -
    -
    handleToggle(catalogPath)}> -
    - {catalogName} - {catalog.getType()} catalog -
    - + + + + + + + {enableSearchColumns && ( + + setSearchColumns(e.target.checked)} + /> + } + label={ + + - {isExpanded(catalogPath) ? 'â–Ľ' : 'â–¶'} - -
    handleGenerateCatalogQuery(e, catalogName)} - title="Set this catalog as default catalog" - > - -
    -
    - - {isExpanded(catalogPath) && ( -
    + Search columns + + {isLoadingColumns && } + + } + /> + + )} + + + + {errorMessage && ( + + Catalog Viewer + {errorMessage} + + )} + + { + handleToggle(itemId) + }} + > + {Array.from(catalogs.values()) + .sort((a, b) => a.getName().localeCompare(b.getName())) + .map((catalog: Catalog) => { + const catalogName = catalog.getName() + const catalogPath = buildPath.catalog(catalogName) + + if (filterText && !isVisible(catalogPath)) { + return null + } + + return ( + + {catalogName} + {catalog.getType() === 'system' && ( + + )} + + handleGenerateCatalogQuery(e, catalogName)} + disabled={isLoading} + > + + + + } + slotProps={{ + label: { + style: { + overflow: 'visible', + }, + }, + }} + > + {catalog.getError() && ( - + + Catalog Viewer + {catalog.getError()} + )} {Array.from(catalog.getSchemas().values()) .sort((a, b) => a.getName().localeCompare(b.getName())) .map((schema) => { - const schemaPath = buildPath.schema(catalogName, schema.getName()) + const schemaName = schema.getName() + const schemaPath = buildPath.schema(catalogName, schemaName) return ( = ({ initialFilterText = '', o catalogName={catalogName} schema={schema} filterText={filterText} - isExpanded={isExpanded(schemaPath)} isVisible={isVisible} + isLoading={isLoading} hasMatchingChildren={hasMatchingChildren} - onToggle={handleToggle} onGenerateQuery={handleGenerateQuery} /> ) })} -
    - )} -
    - ) - })} -
    -
    + + + ) + })} + + + ) } diff --git a/precise/src/controls/catalog_viewer/CatalogViewerColumn.tsx b/precise/src/controls/catalog_viewer/CatalogViewerColumn.tsx index 201510b..0b8fcad 100644 --- a/precise/src/controls/catalog_viewer/CatalogViewerColumn.tsx +++ b/precise/src/controls/catalog_viewer/CatalogViewerColumn.tsx @@ -1,123 +1,63 @@ -import React, { useState, useEffect } from 'react' +import React from 'react' +import { Box, Stack, Typography } from '@mui/material' +import { TreeItem } from '@mui/x-tree-view' import Column from '../../schema/Column' import TableReference from './../../schema/TableReference' -import CopyLink from './../../utils/CopyLink' import { buildPath } from './ViewerState' -import './catalogviewer.css' interface CatalogViewerColumnProps { tableRef: TableReference column: Column - isExpanded: boolean isVisible: (path: string) => boolean - onToggle: (path: string) => Promise } -const CatalogViewerColumn: React.FC = ({ - tableRef, - column, - isExpanded, - isVisible, - onToggle, -}) => { - const [sampleValues, setSampleValues] = useState([]) - const [isLoadingSamples, setIsLoadingSamples] = useState(false) - const [showSamples, setShowSamples] = useState(false) - +const CatalogViewerColumn: React.FC = ({ tableRef, column, isVisible }) => { const columnPath = buildPath.column(tableRef.catalogName, tableRef.schemaName, tableRef.tableName, column.getName()) - // Load sample values when samples are shown - useEffect(() => { - if (showSamples && sampleValues.length === 0 && !isLoadingSamples) { - setIsLoadingSamples(true) - column.getSampleValues(tableRef, (newSampleValues: string[]) => { - setSampleValues(newSampleValues) - setIsLoadingSamples(false) - }) - } - }, [showSamples, column, tableRef, sampleValues.length, isLoadingSamples]) - - const handleRefresh = (e: React.MouseEvent) => { - e.stopPropagation() - setIsLoadingSamples(true) - column.getSampleValues(tableRef, (newSampleValues: string[]) => { - setSampleValues(newSampleValues) - setIsLoadingSamples(false) - }) - } - - const handleToggle = async () => { - // Toggle samples if already expanded - if (isExpanded) { - setShowSamples(!showSamples) - } else { - // Just expand the column initially - await onToggle(columnPath) - setShowSamples(true) - } - } - - const renderSampleValue = (value: string, index: number) => { - if (value === null) { - return ( -
    - NULL -
    - ) - } - - const displayValue = value.length > 50 ? value.substring(0, 50) + '...' : value - - return ( -
    - {displayValue} - navigator.clipboard.writeText(value)} /> -
    - ) - } - // Check visibility using the passed down helper if (!isVisible(columnPath)) { return null } return ( -
    -
    - {showSamples && ( -
    -
    -
    - )} -
    - {column.getName()} - {column.getType()} - {showSamples ? 'â–Ľ' : 'â–¶'} -
    - {column.getExtraOrComment() && ( -
    - {column.getExtraOrComment()} -
    - )} -
    - - {showSamples && ( -
    -
    - Sample values: -
    -
    - {isLoadingSamples ? ( -
    Loading samples...
    - ) : sampleValues.length === 0 ? ( -
    No sample values available
    - ) : ( - sampleValues.map((value, index) => renderSampleValue(value, index)) - )} -
    -
    - )} -
    + + + + + {column.getName()} + + + {column.getType()} + + + + + } + slotProps={{ + label: { + style: { + overflow: 'visible', + }, + }, + }} + /> ) } diff --git a/precise/src/controls/catalog_viewer/CatalogViewerSchema.tsx b/precise/src/controls/catalog_viewer/CatalogViewerSchema.tsx index 90857b4..d348217 100644 --- a/precise/src/controls/catalog_viewer/CatalogViewerSchema.tsx +++ b/precise/src/controls/catalog_viewer/CatalogViewerSchema.tsx @@ -1,20 +1,21 @@ import React from 'react' +import { Box, IconButton, Typography } from '@mui/material' +import { TreeItem } from '@mui/x-tree-view' +import AccountTreeOutlinedIcon from '@mui/icons-material/AccountTreeOutlined' +import ChevronRightIcon from '@mui/icons-material/ChevronRight' import Schema from '../../schema/Schema' import Table from '../../schema/Table' import CatalogViewerTable from './CatalogViewerTable' import TableReference from '../../schema/TableReference' import { buildPath } from './ViewerState' -import './catalogviewer.css' -import { ChevronRight } from 'lucide-react' interface SchemaProps { catalogName: string schema: Schema filterText: string - isExpanded: boolean isVisible: (path: string) => boolean + isLoading: boolean hasMatchingChildren: (path: string) => boolean - onToggle: (path: string) => Promise onGenerateQuery?: ( queryType: string, tableRef: TableReference | null, @@ -27,10 +28,9 @@ const CatalogViewerSchema: React.FC = ({ catalogName, schema, filterText, - isExpanded, isVisible, + isLoading, hasMatchingChildren, - onToggle, onGenerateQuery, }) => { const schemaPath = buildPath.schema(catalogName, schema.getName()) @@ -48,51 +48,60 @@ const CatalogViewerSchema: React.FC = ({ } return ( -
    -
    onToggle(schemaPath)}> - {schema.getName()} - schema - - {isExpanded ? 'â–Ľ' : 'â–¶'} - + {schema.getName()} - {onGenerateQuery && ( -
    - -
    - )} -
    - - {isExpanded && ( -
    - {Array.from(schema.getTables().values()) - .sort((a: Table, b: Table) => a.getName().localeCompare(b.getName())) - .map((table: Table) => { - const tablePath = buildPath.table(catalogName, schema.getName(), table.getName()) + + + + } + slotProps={{ + label: { + style: { + overflow: 'visible', + }, + }, + }} + > + {Array.from(schema.getTables().values()) + .sort((a: Table, b: Table) => a.getName().localeCompare(b.getName())) + .map((table: Table) => { + const tablePath = buildPath.table(catalogName, schema.getName(), table.getName()) - // Table visibility is handled within the component - return ( - - ) - })} -
    - )} -
    + return ( + + ) + })} +
    ) } diff --git a/precise/src/controls/catalog_viewer/CatalogViewerTable.tsx b/precise/src/controls/catalog_viewer/CatalogViewerTable.tsx index 9283651..1b077a6 100644 --- a/precise/src/controls/catalog_viewer/CatalogViewerTable.tsx +++ b/precise/src/controls/catalog_viewer/CatalogViewerTable.tsx @@ -1,19 +1,22 @@ import React, { useState, useEffect } from 'react' +import { Alert, Box, IconButton, Typography } from '@mui/material' +import { TreeItem } from '@mui/x-tree-view' +import HourglassEmptyOutlinedIcon from '@mui/icons-material/HourglassEmptyOutlined' +import SearchOutlinedIcon from '@mui/icons-material/SearchOutlined' +import TableRowsOutlined from '@mui/icons-material/TableRowsOutlined' import Table from '../../schema/Table' import SchemaProvider from '../../sql/SchemaProvider' import TableReference from '../../schema/TableReference' import CatalogViewerColumn from './CatalogViewerColumn' import { buildPath } from './ViewerState' -import './catalogviewer.css' -import { ChevronRight } from 'lucide-react' interface CatalogViewerTableProps { tableRef: TableReference filterText: string isExpanded: boolean isVisible: (path: string) => boolean + isLoading: boolean hasMatchingChildren: (path: string) => boolean - onToggle: (path: string) => Promise onGenerateQuery?: (queryType: string, tableRef: TableReference) => void } @@ -22,7 +25,7 @@ const CatalogViewerTable: React.FC = ({ filterText, isExpanded, isVisible, - onToggle, + isLoading, onGenerateQuery, }) => { const [table, setTable] = useState(() => new Table(tableRef.tableName)) @@ -63,60 +66,70 @@ const CatalogViewerTable: React.FC = ({ } return ( -
    -
    -
    onToggle(tablePath)}> - {table.getName()} - table - {isExpanded ? 'â–Ľ' : 'â–¶'} + + {table.getName()} - {onGenerateQuery && ( -
    - -
    - )} -
    -
    + + + + + } + slotProps={{ + label: { + style: { + overflow: 'visible', + }, + }, + }} + > + + {table.getError() ? ( + {table.getError()} + ) : table.getColumns().length === 0 && table.isLoading() ? null : ( + table.getColumns().length > 0 && + table.getColumns().map((column) => { + const columnPath = buildPath.column( + tableRef.catalogName, + tableRef.schemaName, + tableRef.tableName, + column.getName() + ) - {isExpanded && ( -
    - {table.getError() ? ( -
    {table.getError()}
    - ) : table.getColumns().length === 0 && isExpanded && table.isLoading() ? ( -
    Loading columns...
    - ) : ( - table.getColumns().length > 0 && - table.getColumns().map((column) => { - const columnPath = buildPath.column( - tableRef.catalogName, - tableRef.schemaName, - tableRef.tableName, - column.getName() - ) + if (!isVisible(columnPath)) { + return null + } - if (!isVisible(columnPath)) { - return null - } - - return ( - - ) - }) - )} -
    - )} -
    + return ( + + ) + }) + )} + + ) } diff --git a/precise/src/controls/catalog_viewer/ViewerState.ts b/precise/src/controls/catalog_viewer/ViewerState.ts index c02737b..9325a06 100644 --- a/precise/src/controls/catalog_viewer/ViewerState.ts +++ b/precise/src/controls/catalog_viewer/ViewerState.ts @@ -19,7 +19,7 @@ export const buildPath = { } export class ViewerStateManager { - private userExpanded = new Set() + public userExpanded = new Set() private matches = new Set() private onStateUpdate: StateUpdateCallback private isSearching = false diff --git a/precise/src/controls/catalog_viewer/catalogviewer.css b/precise/src/controls/catalog_viewer/catalogviewer.css deleted file mode 100644 index 8610726..0000000 --- a/precise/src/controls/catalog_viewer/catalogviewer.css +++ /dev/null @@ -1,204 +0,0 @@ -.filter-input { - width: 95%; - padding: 0.5em; - margin: 0.5em; - border: 1px solid #2b2b2b; - border-radius: 3px; - background-color: #181818; - color: #9d9d9d; - font-size: small; -} - -/* A plain text with no obvious element of it being a button */ -.reload-button { - border: 0; - background-color: transparent; - color: #bbb; - right: 20px; - position: absolute; - padding: 0; - margin: 0; - font-size: 2em; -} - -/* catalog explorer */ -.viewer_catalog { - font-weight: bold; - color: #fff; - cursor: pointer; -} - -.catalog-content { - padding-left: 0.5em; -} - -.viewer_catalog:hover { - color: #fff; - background-color: #689CC5; -} - -.viewer_catalog_body { - margin-left: 10px; - padding-left: 10px; - border-left: #444 1px solid; -} - -.viewer_schema { - font-weight: regular; - color: #bbb; - cursor: pointer; -} - -.viewer_schema:hover { - color: #fff; - background-color: #416480; -} - -.viewer-schema-body { - margin-left: 10px; - padding-left: 10px; - border-left: #444 1px solid; -} - -.viewer_table { - font-weight: regular; - color: #999; - cursor: pointer; - position: relative; - padding-right: 30px; -} - -.viewer_samplevalue { - color: #999; -} - -.viewer_table_body { - margin-left: 10px; - padding-left: 10px; - border-left: #888 1px solid; - padding-right: 10px; -} - -.viewer_samplevalues_body { - margin-left: 10px; - padding-left: 10px; - border-left: #444 1px solid; -} - -.viewer_table:hover { - color: #fff; - background-color: #334e64; -} - -/* monospaced text */ -.viewer_column { - font-family: monospace; - cursor: pointer; -} - -.viewer_column:hover { - color: #fff; - background-color: #334e64; - cursor: pointer; -} - -.loading-message { - color: #999; - font-size: x-small; -} - -.table-name { - padding-right: 0.25em; -} - -.schema-name { - padding-right: 0.25em; -} - -.catalog-viewer { - position: relative; -} - -.catalog-viewer-header { - padding-bottom: 0.5em; -} - -.catalog-name { - padding-right: 0.25em; -} - -.column-name { - padding-right: 0.25em; -} - -.expand-indicator { - color: #444; - font-size: x-small; - padding-left: 0.25em; -} - -/* Add to catalogviewer.css */ -.search-container { - position: relative; - display: flex; - flex: 1; - align-items: center; -} - -/* input inside the search container needs to have text cursor */ -.search-container > .filter-input { - cursor: text !important; -} - -.clear-search { - position: absolute; - right: 8px; - top: 50%; - transform: translateY(-50%); - cursor: pointer; - opacity: 0.6; - transition: opacity 0.2s; - padding: 4px; - display: flex; - align-items: center; - justify-content: center; -} - -.clear-search:hover { - opacity: 1; -} - -.filter-input { - padding-right: 28px; /* Make room for the clear button */ -} - -.expand-indicator-has-matches { - color: #689CC5; /* Light blue to match the hover color */ -} - -/* Add to catalogviewer.css */ -.generate-query-button { - margin-left: auto; - color: #666; - cursor: pointer; - padding: 2px 8px; - transition: color 0.2s; - display: flex; - align-items: center; -} - -.generate-query-button:hover { - color: #fff; -} - -/* Make viewer rows display as flex to accommodate the button on the right */ -.viewer_catalog, .viewer_schema, .viewer_table { - display: flex; - align-items: center; - width: 100%; -} - -/* Add spacing between the expand indicator and text */ -.catalog-name, .schema-name, .table-name { - margin-right: 0.5em; -} \ No newline at end of file diff --git a/precise/src/controls/tabs/EnterpriseTabs.tsx b/precise/src/controls/tabs/EnterpriseTabs.tsx index 823cf49..c12275b 100644 --- a/precise/src/controls/tabs/EnterpriseTabs.tsx +++ b/precise/src/controls/tabs/EnterpriseTabs.tsx @@ -1,8 +1,7 @@ import React, { Component } from 'react' -import { DndProvider } from 'react-dnd' -import { HTML5Backend } from 'react-dnd-html5-backend' -import './tabs.css' -import TabItem from './TabItem' +import { Box, Divider, IconButton, Tab as MuiTab, Tabs as MuiTabs } from '@mui/material' +import AddIcon from '@mui/icons-material/Add' +import CloseIcon from '@mui/icons-material/Close' import TabsEllipsesMenu from './TabsEllipsesMenu' import Tabs from './Tabs' import TabInfo from './TabInfo' @@ -131,29 +130,69 @@ class EnterpriseTabs extends Component const { newTabLabel = '+' } = this.props return ( - -
    -
    - {tabs.map((tab, index) => ( - + + this.handleTabClick(id)} + sx={{ flexGrow: 1 }} + > + {tabs.map((tab) => ( + this.handleTabClick(tab.id)} - handleTabClose={() => this.handleTabClose(tab.id)} - handleTabRename={(id, newTitle) => this.handleTabRename(tab.id, newTitle)} - handleTabPin={() => this.handleTabPin(tab.id)} + value={tab.id} + label={tab.title} + sx={{ minHeight: 36, py: 0 }} + icon={ + { + e.stopPropagation() + this.handleTabClose(tab.id) + }} + > + + + } + iconPosition="end" /> ))} -
    - {newTabLabel} -
    -
    - -
    -
    + { + e.stopPropagation() + this.handleNewTab() + }} + > + + + } + aria-label="Add tab" + sx={{ minWidth: 0, px: 1 }} + disableRipple + /> + + + + + + + + ) } } diff --git a/precise/src/controls/tabs/TabItem.tsx b/precise/src/controls/tabs/TabItem.tsx deleted file mode 100644 index c591cb2..0000000 --- a/precise/src/controls/tabs/TabItem.tsx +++ /dev/null @@ -1,135 +0,0 @@ -import React, { useState, useRef, useEffect } from 'react' -import { useDrag, useDrop } from 'react-dnd' -import TabInfo from './TabInfo' -import PinUpIcon from '../../assets/pin_up.png' -import PinDownIcon from '../../assets/pin_down.png' -import CloseIcon from '../../assets/close.png' - -const ItemType = { - TAB: 'tab', -} - -interface TabItemProps { - tab: T - isActive: boolean - index: number - moveTab: (fromIndex: number, toIndex: number) => void - handleTabClick: (tabId: string) => void - handleTabClose: (tabId: string) => void - handleTabRename: (tabId: string, newTitle: string) => void - handleTabPin: (tabId: string) => void -} - -function TabItem({ - tab, - isActive, - index, - moveTab, - handleTabClick, - handleTabClose, - handleTabRename, - handleTabPin, -}: TabItemProps) { - const [isEditing, setIsEditing] = useState(false) - const [editedTitle, setEditedTitle] = useState(tab.title) - const inputRef = useRef(null) - - const [{ isDragging }, drag, preview] = useDrag({ - type: ItemType.TAB, - item: () => ({ index }), - collect: (monitor) => ({ - isDragging: monitor.isDragging(), - }), - canDrag: () => !isEditing, // Disable dragging when editing - }) - - const [, drop] = useDrop({ - accept: ItemType.TAB, - hover: (draggedItem: { index: number }) => { - if (draggedItem.index !== index) { - moveTab(draggedItem.index, index) - draggedItem.index = index - } - }, - }) - - useEffect(() => { - if (isEditing && inputRef.current) { - inputRef.current.focus() - inputRef.current.select() // Select all text when editing starts - } - }, [isEditing]) - - const handleDoubleClick = (e: React.MouseEvent) => { - e.stopPropagation() - setIsEditing(true) - } - - const handleInputChange = (event: React.ChangeEvent) => { - setEditedTitle(event.target.value) - } - - const handleInputBlur = () => { - setIsEditing(false) - if (editedTitle.trim() !== tab.title && editedTitle.trim() !== '') { - handleTabRename(tab.id, editedTitle.trim()) - } else { - setEditedTitle(tab.title) // Reset to original title if empty or unchanged - } - } - - const handleInputKeyPress = (event: React.KeyboardEvent) => { - if (event.key === 'Enter') { - handleInputBlur() - } - } - - return ( -
    preview(drop(node))} - className={`tab-item ${isActive ? 'tab-item-selected' : ''} ${isDragging ? 'dragging' : ''} ${tab.isPinned ? 'pinned' : ''}`} - onClick={() => handleTabClick(tab.id)} - > -
    - {isEditing ? ( - e.stopPropagation()} - style={{ cursor: 'text' }} - /> - ) : ( -
    - {tab.title} -
    - )} -
    -
    -
    { - e.stopPropagation() - handleTabPin(tab.id) - }} - > - Pin -
    -
    { - e.stopPropagation() - handleTabClose(tab.id) - }} - > - Close -
    -
    -
    - ) -} - -export default TabItem diff --git a/precise/src/controls/tabs/TabsEllipsesMenu.tsx b/precise/src/controls/tabs/TabsEllipsesMenu.tsx index 2e729bb..b92d794 100644 --- a/precise/src/controls/tabs/TabsEllipsesMenu.tsx +++ b/precise/src/controls/tabs/TabsEllipsesMenu.tsx @@ -1,4 +1,7 @@ import React, { useState, useRef, useEffect } from 'react' +import { Box, IconButton, Popover, TextField, List, ListItemButton, ListItemText } from '@mui/material' +import ExpandMoreIcon from '@mui/icons-material/ExpandMore' +import PushPinIcon from '@mui/icons-material/PushPin' import TabInfo from './TabInfo' interface TabsEllipsesMenuProps { @@ -12,62 +15,61 @@ function TabsEllipsesMenu({ onTabSelect, filterPlaceholder = 'Filter tabs...', }: TabsEllipsesMenuProps) { - const [isOpen, setIsOpen] = useState(false) + const [anchorEl, setAnchorEl] = useState(null) const [filter, setFilter] = useState('') - const menuRef = useRef(null) + const isOpen = Boolean(anchorEl) const filteredTabs = tabs.filter((tab) => tab.title.toLowerCase().includes(filter.toLowerCase())) - useEffect(() => { - function handleClickOutside(event: MouseEvent) { - if (menuRef.current && !menuRef.current.contains(event.target as Node)) { - setIsOpen(false) - } - } - - document.addEventListener('mousedown', handleClickOutside) - return () => { - document.removeEventListener('mousedown', handleClickOutside) - } - }, [menuRef]) - - const handleEllipsesClick = (event: React.MouseEvent) => { + const handleEllipsesClick = (event: React.MouseEvent) => { event.stopPropagation() - setIsOpen(true) + setAnchorEl(event.currentTarget) } + const handleClosePopover = () => setAnchorEl(null) + return ( -
    - - {isOpen && ( -
    - + + + + + e.stopPropagation()}> + setFilter(e.target.value)} - autoFocus + sx={{ mb: 1 }} /> -
    + {filteredTabs.map((tab) => ( -
    { onTabSelect(tab.id) - setIsOpen(false) + handleClosePopover() }} + sx={{ gap: 1 }} > - {tab.title} - {tab.isPinned && 📌} -
    + + {tab.isPinned && } + ))} -
    -
    - )} -
    + + + + ) } diff --git a/precise/src/controls/tabs/tabs.css b/precise/src/controls/tabs/tabs.css deleted file mode 100644 index 5fada60..0000000 --- a/precise/src/controls/tabs/tabs.css +++ /dev/null @@ -1,193 +0,0 @@ -.tabs-container { - position: relative; - display: flex; - align-items: center; - overflow-x: auto; - white-space: nowrap; - margin-top: 0px; /* Tabs overlap the control bar, better fix might be to prevent the animation from doing this */ -} - -.tabs { - display: flex; - flex-direction: row; - flex-grow: 1; - overflow-x: auto; - /* disable scrollbars */ - scrollbar-width: none; - height: 2.5em; -} - -.controltab { - display: inline-flex; - align-items: center; - padding: 10px; - padding-left: 20px; - padding-right: 20px; - background-color: #000000; - border-left: 1px solid #2b2b2b; - border-top: 1px solid #2b2b2b; - border-radius: 3px; - font-size: xx-large; - cursor: pointer; - flex-shrink: 0; - box-sizing: border-box; - color: #ffffff; - font-size: small; -} - -.controltab:hover, .tabs-ellipses-menu:hover { - background-color: #2b2b2b; -} - -.tab-item, -.tab-item-selected { - display: flex; - align-items: center; - justify-content: space-between; - padding: 10px; - border-left: 1px solid #2b2b2b; - border-top: 1px solid #2b2b2b; - border-top-left-radius: 5px; - border-top-right-radius: 5px; - cursor: pointer; - box-sizing: border-box; - font-size: small; - max-width: 200px; - animation: tabPopup 0.3s ease-out; -} - -@keyframes tabPopup { - from { - transform: translateY(10px); - opacity: 0; - } - to { - transform: translateY(0); - opacity: 1; - } -} - -.tab-item { - background-color: #101010; - color: #9d9d9d; -} - -.tab-item-selected { - background-color: #1F1F1F; - color: #dddddd; -} - -.tab-item:hover, -.tab-item-selected:hover { - background-color: #2b2b2b; -} - -.tab-content { - flex-grow: 1; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - margin-right: 5px; -} - -.tab-buttons { - display: flex; - align-items: center; -} - -.tab-button { - background: none; - border: none; - cursor: pointer; - display: flex; - align-items: center; - justify-content: center; - padding: 2px; - color: inherit; - font-size: 14px; - width: 14px; - height: 14px; - margin-left: 0px; -} - -.tab-button:hover { - background-color: rgba(255, 255, 255, 0.1); - border-radius: 3px; -} - -.close-button:hover { - color: #ff4444; -} - -.tab-list-button-and-menu { - position: absolute; - right: 0px; - top: 0px; - z-index: 1000; -} - -.ellipses-button { - display: flex; - align-items: center; - justify-content: center; - width: 30px; - height: 30px; - padding: 0; - margin-right: 20px; - background-color: #000000; - border: none; - border-left: 1px solid #2b2b2b; - border-top: 1px solid #2b2b2b; - border-radius: 3px; - cursor: pointer; - color: #ffffff; - font-size: 18px; - outline: none; -} - -.ellipses-button:hover { - background-color: #2b2b2b; -} - -.tabs-ellipses-menu-content { - position: fixed; - right: 10px; - top: 130px; - background-color: #101010; - min-width: 300px; - box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2); - z-index: 1001; - max-height: calc(100vh - 50px); - overflow-y: auto; - overflow-x: hidden; - border: 1px solid #2b2b2b; - border-radius: 3px; -} - -.tabs-ellipses-menu-content input { - width: calc(100% - 20px); - margin: 10px; - padding: 5px; - background-color: #181818; - border: 1px solid #2b2b2b; - color: #9d9d9d; - font-size: small; -} - -.tabs-ellipses-menu-content .tab-list { - max-height: 250px; - overflow-y: auto; -} - -.tabs-ellipses-menu-content .tab-item { - display: block; - padding: 10px; - text-decoration: none; - cursor: pointer; - border: none; - border-radius: 0; -} - -.tabs-ellipses-menu-content .tab-item:hover { - background-color: #2b2b2b; -} \ No newline at end of file diff --git a/precise/src/index.ts b/precise/src/index.ts new file mode 100644 index 0000000..7a787a1 --- /dev/null +++ b/precise/src/index.ts @@ -0,0 +1 @@ +export { default as QueryEditor } from './QueryEditor' diff --git a/precise/src/main.tsx b/precise/src/main.tsx index b5c4551..8214d84 100644 --- a/precise/src/main.tsx +++ b/precise/src/main.tsx @@ -1,12 +1,50 @@ -import React from 'react' +import React, { useLayoutEffect, useRef, useState } from 'react' import ReactDOM from 'react-dom/client' -import App from './App.tsx' -import './style/theme.css' -import './style/normalize.css' -import './style/layout.css' -import './style/components.css' -import './style/query-editor.css' -import './style/results.css' -import './style/control.css' - -ReactDOM.createRoot(document.getElementById('root')!).render() +import QueryEditor from './QueryEditor' + +function useObservedHeight(ref: React.RefObject | React.RefObject) { + const [height, setHeight] = useState(0) + + useLayoutEffect(() => { + const el = ref.current + if (!el) return + + // Initial measure + setHeight(el.getBoundingClientRect().height) + + const ro = new ResizeObserver(([entry]) => { + setHeight(entry.contentRect.height) + }) + ro.observe(el) + + return () => ro.disconnect() + }, [ref]) + + return height +} + +export default function App() { + const slotRef = useRef(null) + const slotHeight = useObservedHeight(slotRef) + + return ( +
    +

    Trino Query Editor - Example app

    +
    + +
    +
    + ) +} + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + +) diff --git a/precise/src/sql/SchemaProvider.ts b/precise/src/sql/SchemaProvider.ts index 9e2c41b..627a4ed 100644 --- a/precise/src/sql/SchemaProvider.ts +++ b/precise/src/sql/SchemaProvider.ts @@ -63,7 +63,10 @@ class SchemaProvider { return null } - static populateCatalogsAndRefreshTableList(callback: any = null, errorCallback: any = null) { + static populateCatalogsAndRefreshTableList( + callback: ((nextCatalogs: Map) => void) | null = null, + errorCallback: ((error: string) => void) | null = null + ) { // refresh catalogs new TrinoQueryRunner() .SetAllResultsCallback((results: any[], isError: boolean) => { @@ -73,7 +76,6 @@ class SchemaProvider { this.catalogs.set(catalog.getName(), catalog) } this.lastSchemaFetchError = undefined - callback() // refresh tables and schemas for this catalog new TrinoQueryRunner() @@ -97,7 +99,7 @@ class SchemaProvider { if (!isError) { catalog.clearErrorMessage() } - callback() + callback?.(new Map(this.catalogs)) }) .SetErrorMessageCallback((error: string) => { catalog.setErrorMessage(error.toString()) @@ -111,7 +113,7 @@ class SchemaProvider { }) .SetErrorMessageCallback((error: string) => { this.lastSchemaFetchError = error.toString() - errorCallback(error.toString()) + errorCallback?.(error.toString()) }) .StartQuery('select catalog_name, connector_name from system.metadata.catalogs') } diff --git a/precise/src/style/components.css b/precise/src/style/components.css deleted file mode 100644 index 57a1d65..0000000 --- a/precise/src/style/components.css +++ /dev/null @@ -1,201 +0,0 @@ -/** - * components.css - * Styles for reusable UI components and utility classes - */ - -.collapse-button { - background-color: var(--dark-gray); - color: var(--highlight-blue); - border-color: var(--light-gray); - font-size: large; - border-radius: 0px 10px 10px 0px; - padding: 0.5em; - cursor: pointer; - text-align: center; - vertical-align: middle; - position: fixed; - left: 0; - bottom: 0; - z-index: 1000; -} - -.button-align-right { - padding-left: 1vw; - bottom: 0; -} - -.small-rounded-dark-grey-button { - background-color: var(--very-dark-gray); - color: var(--muted-text-color); - font-size: large; - border-radius: 10px; - padding: 0em; - cursor: pointer; - width: 1.5em; - height: 1.5em; - border: 1px solid var(--dark-gray); - text-align: center; - vertical-align: middle; - position: absolute; - left: 50%; - line-height: 1.0em; -} - -/* Progress Indicators */ -.spinner { - display: inline-block; - width: 30px; - height: 30px; - border: 3px solid rgba(255, 255, 255, 0.3); - border-radius: 50%; - border-top-color: var(--white); - animation: spin 1s linear infinite; -} - -.progress-percent { - font-weight: bold; - font-size: 1.5em; -} - -.progress-bar { - width: 100%; - border: 1px solid var(--medium-gray); - background-color: var(--dark-accent); - display: grid; - grid-template-columns: 1fr; -} - -.progress-bar-fill { - transition: width 1100ms; - transition-timing-function: linear; - grid-column-start: 0; - left: 0px; - top: 0px; - line-height: 30px; - text-align: center; - bottom: 0px; - width: 0%; - background: var(--brand-gradient); - z-index: 1; - white-space: nowrap; -} - -.progress-bar-running-state { - width: 100%; - transition: opacity 500ms; - transition-timing-function: linear; - grid-column-start: 0; - left: 0px; - top: 0px; - line-height: 30px; - text-align: center; - bottom: 0px; - background: var(--brand-gradient); - z-index: 1; - white-space: nowrap; -} - -.progress-bar-timer { - padding-left: 1em; - font-size: large; -} - -/* Add Query Button */ -.add-query-button { - display: grid; - grid-template-columns: auto; - align-items: center; - width: 100%; - height: 1em; -} - -.add-query-button hr { - border: 0; - height: 1px; - width: 100%; - background: #333; - background-image: linear-gradient(to right, #111, #222, #111); -} - -/* Error Handling */ -.result-cell-null { - color: var(--muted-text-color); - font-style: italic; -} - -/* Links and Text */ -.link-to-query { - font-size: small; - text-align: right; - margin-right: 1em; -} - -.status-text { - color: var(--muted-text-color); - font-size: small; -} - -.read-the-docs { - color: var(--muted-text-color); -} - -.helper-text { - color: #666; - font-size: x-small; -} - -.offset-page-for-copy { - font-size: .875em; - margin-right: .125em; - position: relative; - top: -.25em; - left: -.125em; -} - -.offset-page-for-copy-inner { - position: absolute; - top: .25em; - left: .25em; -} - -/* Utility Classes - Only include the ones actually used in the project */ -.flex { - display: flex; -} - -.items-center { - align-items: center; -} - -.justify-center { - justify-content: center; -} - - button:focus, - button:focus-visible { - outline: 4px auto -webkit-focus-ring-color; - } - - /* Progress bar color consistency */ - .progress-bar { - width: 100%; - border: 1px solid #777; - background-color: #222; - display: grid; - grid-template-columns: 1fr; - } - - .progress-bar-fill { - transition: width 1100ms; - transition-timing-function: linear; - grid-column-start: 0; - left: 0px; - top: 0px; - line-height: 30px; - text-align: center; - bottom: 0px; - width: 0%; - background: var(--brand-gradient); - z-index: 1; - white-space: nowrap; - } \ No newline at end of file diff --git a/precise/src/style/control.css b/precise/src/style/control.css deleted file mode 100644 index 5fc42ca..0000000 --- a/precise/src/style/control.css +++ /dev/null @@ -1,231 +0,0 @@ -/** - * control.css - * Styles for control elements and interactions - */ - -/* Basic Interactive Elements */ -.clickable { - cursor: pointer; -} - -.selectable { - user-select: text; -} - -.non-selectable { - user-select: none; -} - -input:focus { - outline: none; - border-color: var(--highlight-blue); -} - -/* Tab Controls */ -.tab-container { - display: flex; - border-bottom: 1px solid var(--dark-gray); - background-color: var(--subtle-darker-accent-color); -} - -.tab { - padding: 8px 16px; - cursor: pointer; - border-right: 1px solid var(--dark-gray); - user-select: none; -} - -.tab.active { - background-color: var(--lighter-accent-color); - border-bottom: 2px solid var(--highlight-blue); -} - -.tab:hover:not(.active) { - background-color: var(--subtle-lighter-accent-color); -} - -/* Editor Controls */ -.editor-toolbar { - display: flex; - align-items: center; - padding: 4px; - background-color: var(--subtle-darker-accent-color); - border-bottom: 1px solid var(--dark-gray); -} - -.toolbar-button { - background: none; - border: none; - color: var(--muted-text-color); - padding: 4px 8px; - cursor: pointer; - border-radius: 4px; -} - -.toolbar-button:hover { - background-color: var(--subtle-lighter-accent-color); - color: var(--white); -} - -.toolbar-button.active { - background-color: var(--lighter-accent-color); - color: var(--white); -} - -/* Resizable Elements */ -.resizable { - position: relative; -} - -.resize-handle { - position: absolute; - width: 10px; - height: 100%; - right: 0; - top: 0; - cursor: col-resize; - z-index: 10; -} - -.resize-handle-horizontal { - width: 100%; - height: 10px; - left: 0; - bottom: 0; - cursor: row-resize; -} - -/* Context Menus and Dropdowns */ -.context-menu { - position: absolute; - background-color: var(--lighter-accent-color); - border: 1px solid var(--dark-gray); - border-radius: 4px; - z-index: 1000; - box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3); -} - -.menu-item { - padding: 6px 12px; - cursor: pointer; -} - -.menu-item:hover { - background-color: var(--subtle-lighter-accent-color); -} - -.menu-divider { - height: 1px; - background-color: var(--dark-gray); - margin: 4px 0; -} - -/* parent type of small control buttons */ -.small-rounded-button { - background-color: #111; - color: #7d7d7d; - border-color: #689CC5; - font-size: large; - border-radius: 10px; - padding: 0.5em; - cursor: pointer; - height: auto; - text-align: center; - vertical-align: middle; - margin-right: 2px; -} - -.small-rounded-button:hover { - background-color: #333; - /* animate */ - transition: background-color 0.25s; -} - -/* input box with no border and transparent background, no outline when selected */ -.query-title { - padding-left: 1em; - color: #61dafb; - font-weight: 300; - font-size: 1.5em; - border: none; - background-color: transparent; - outline: none; -} - -.card-header { - padding-top: 0.2em; - padding-left: 0.2em; - background-color: #1E1E1E; - right: 0px; - height: 3em; -} - -/* grid containing execute query and title text */ -.card-header-grid { - display: grid; - grid-template-columns: 4em auto 10em 10em 3.75em 5px 3.75em 5px 3.75em 5px 3.75em; - padding-right: 20px; /* to account for scrollbar */ -} - -.query-run-button { - background-color: #111; - color: #689CC5; - border-color: #689CC5; - font-size: large; - border-radius: 10px; - padding: 0.5em; - cursor: pointer; - width: 4em; - height: auto; - text-align: center; - vertical-align: middle; -} - -.query-run-button:hover { - background-color: var(--dark-accent); - color: var(--white); -} - -.query-control-button { - background-color: #111; - color: #689CC5; - border-color: #3f5f79; - font-size: large; - border-radius: 10px; - padding: 0.5em; - cursor: pointer; - width: 100%; - height: 100%; - text-align: center; - vertical-align: middle; - box-sizing: border-box; -} - -.query-control-button:hover { - background-color: var(--dark-accent); - color: var(--white); -} - - -.catalog-setting { - /* align text right */ - text-align: right; -} - -/* Catalog and schema settings */ -.catalog-setting, -.schema-setting { - padding-left: 1em; - color: #777; - font-weight: 300; - font-size: 1em; - border: none; - background-color: transparent; - outline: none; - } - -/* hover over the catalog setting and schema setting to change the color to white */ -.catalog-setting:hover, .schema-setting:hover { - color: #fff; - transition: background-color 0.25s, color 0.25s; -} diff --git a/precise/src/style/layout.css b/precise/src/style/layout.css deleted file mode 100644 index ede5c71..0000000 --- a/precise/src/style/layout.css +++ /dev/null @@ -1,144 +0,0 @@ -/** - * layout.css - * Layout structures and positioning styles - */ - -/* Page Layout */ -.page { - width: 100%; - } - - /* Grid Layout for page with collapsible sidebar */ - .pagegrid { - display: grid; - grid-template-columns: 0vw 100vw; - transition: grid-template-columns 0.1s; - max-width: 100%; - width: 100%; - box-sizing: border-box; - } - - /* For expanded layout */ - .catalog-expanded { - /* Will be applied via JavaScript */ - } - - /* For collapsed layout */ - .catalog-collapsed { - /* Will be applied via JavaScript */ - } - - /* Catalog Sidebar */ - .catalog-container { - width: auto; - height: calc(100vh); - } - - .catalog-wrapper { - overflow-y: auto; - overflow-x: hidden; - width: auto; - background-color: var(--dark-gray); - height: calc(100vh - 3em); - scrollbar-color: var(--medium-gray) var(--dark-gray); - } - - /* Branding and Header */ - .branding-header { - background: var(--brand-gradient); - height: 3em; - width: 100%; - position: fixed; - } - - .branding-padder { - height: 3em; - } - - /* Card Layout */ - .card { - margin: 0px; - } - - /* Editor and Results Layout */ - .query-editor { - margin: 0px; - padding: 0px; - } - - .editorspace { - /* Space for the Monaco editor */ - } - - .resultSetPort { - padding-top: 0em; - } - - /* Spacers and Common Layout Elements */ - .spacer { - margin-bottom: 1em; - } - - /* Status Layouts */ - .status { - display: grid; - grid-template-columns: 60px 60px auto; - align-items: left; - } - - .progress-bar-grid { - display: grid; - grid-template-columns: 90fr 10fr; - align-items: center; - } - - /* Query Status Table Layout */ - .query-status-table { - border-spacing: 0px; - } - - .query-status-table th { - padding: 4px 8px 4px 8px; - color: var(--muted-text-color); - font-size: small; - padding-right: 1em; - text-align: left; - } - - /* Image size modifiers */ - .full-height-image { - height: 100%; - width: auto; - object-fit: contain; - } - - .half-height-image { - height: 50%; - width: auto; - object-fit: contain; - } - - /* Fixes for scrollable areas */ - .scrollable { - overflow-y: auto; - overflow-x: auto; - height: 40vh; - width: 100%; - margin: 0; - padding: 0; - } - - /* Catalog container height */ - .catalog-container { - width: auto; - height: calc(100vh); - } - - .catalog-wrapper { - overflow-y: auto; - overflow-x: hidden; - width: auto; - background-color: var(--dark-gray); - height: calc(100vh - 3em); - scrollbar-color: var(--medium-gray) var(--dark-gray); - } \ No newline at end of file diff --git a/precise/src/style/normalize.css b/precise/src/style/normalize.css deleted file mode 100644 index a0ac59d..0000000 --- a/precise/src/style/normalize.css +++ /dev/null @@ -1,94 +0,0 @@ -/** - * normalize.css - * Base styles and resets for consistent rendering - */ - -/* Reset margins and paddings */ -html, body { - margin: 0; - padding: 0; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; - color: var(--text-color); - background-color: var(--bg-color); - } - - body { - overflow-y: auto; - } - - #root { - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; - color: #fff; - background-color: #121212; - margin: 0; - padding: 0; - max-width: 100%; - overflow-x: hidden; - } - - /* Basic elements styling */ - a { - font-weight: 500; - color: var(--link-color); - text-decoration: inherit; - } - - a:hover { - color: var(--link-hover-color); - } - - button { - border-radius: 8px; - border: 1px solid transparent; - padding: 0.6em 1.2em; - font-size: 1em; - font-weight: 500; - font-family: inherit; - background-color: #1a1a1a; - cursor: pointer; - transition: border-color 0.25s; - } - - button:hover { - border-color: var(--border-color); - } - - button:focus, - button:focus-visible { - outline: 4px auto -webkit-focus-ring-color; - } - - /* Tables */ - table { - border-collapse: collapse; - border-spacing: 0; - width: 100%; - box-sizing: border-box; - color: var(--text-color); - } - - /* Basic animations */ - @keyframes spin { - to { - transform: rotate(360deg); - } - } - - @keyframes logo-spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } - } - - .animate-spin { - animation: spin 1s linear infinite; - } - - @media (prefers-reduced-motion: no-preference) { - a:nth-of-type(2) .logo { - animation: logo-spin infinite 20s linear; - } - } \ No newline at end of file diff --git a/precise/src/style/query-editor.css b/precise/src/style/query-editor.css deleted file mode 100644 index ef51423..0000000 --- a/precise/src/style/query-editor.css +++ /dev/null @@ -1,162 +0,0 @@ -/** - * query-editor.css - * Styles specific to the query editor component - */ - - /* Query title input */ - .query-title { - background-color: transparent; - color: var(--highlight-blue); - border: 0px; - padding: 0px 12px; - font-size: 2em; - width: 100%; - } - - /* Query Editor Area */ - .editorspace { - /* Container for Monaco editor */ - } - - /* SQL Syntax Highlighting */ - .qualifiedName { - color: var(--white) !important; - background-color: var(--success-color); - cursor: pointer !important; - font-weight: bold; - } - - .relationReference { - color: var(--white) !important; - background-color: rgba(0, 0, 255, 0.5); - cursor: pointer !important; - font-weight: bold; - } - - .columnType { - color: var(--muted-text-color); - } - - .columnExtraOrComment { - font-style: italic; - } - - /* Query Stage Indicators */ - .status-stage-default { - border-left: 4px solid var(--lighter-accent-color); - border-top: 1px solid var(--lighter-accent-color); - } - - .status-stage-rows { - border-left: 4px solid var(--rows-color); - border-top: 1px solid var(--rows-color-partial-transparent); - } - - .status-stage-bytes { - border-left: 4px solid var(--bytes-color); - border-top: 1px solid var(--bytes-color-partial-transparent); - } - - .status-stage-splits { - border-left: 4px solid var(--splits-color); - border-top: 1px solid var(--splits-color-partial-transparent); - } - - /* Stage Headers */ - .status-stage-category-header-splits { - border-left: 4px solid var(--splits-color); - text-align: center; - } - - .status-stage-category-header-bytes { - border-left: 4px solid var(--bytes-color); - text-align: center; - } - - .status-stage-category-header-rows { - border-left: 4px solid var(--rows-color); - text-align: center; - } - - /* Stage Row Styles */ - .stage-running td { - padding: 4px 8px 4px 8px; - text-align: left; - } - - .stage-not-running td { - padding: 4px 8px 4px 8px; - color: var(--muted-text-color); - text-align: left; - } - - .substitution-field { - /* Field container styling */ - margin-bottom: 10px; - } - - .substitution-field label { - /* Label styling */ - margin-right: 8px; - } - - .substitution-field input { - /* Input styling */ - padding: 4px 8px; - border-radius: 4px; - border: 1px solid var(--lighter-accent-color); - background-color: var(--subtle-lighter-accent-color); - color: var(--text-color); - } - - /* Add this to your query-editor.css file */ - -.editor-toolbar { - position: absolute; - top: 5px; - right: 25px; - z-index: 1000; - display: flex; - gap: 8px; -} - -.editor-button { - background: none; - border: none; - cursor: pointer; - color: rgba(255, 255, 255, 0.7); - display: flex; - align-items: center; - justify-content: center; - padding: 4px; - border-radius: 4px; - transition: all 0.2s ease; -} - -.editor-button:hover { - background-color: rgba(255, 255, 255, 0.1); - color: white; -} - -.editor-button:active { - background-color: rgba(255, 255, 255, 0.2); -} - -.editor-button[disabled] { - opacity: 0.5; - cursor: not-allowed; -} - -.editor-button[data-tooltip]:hover::after { - content: attr(data-tooltip); - position: absolute; - bottom: -30px; - left: 50%; - transform: translateX(-50%); - background-color: rgba(0, 0, 0, 0.8); - color: white; - padding: 4px 8px; - border-radius: 4px; - font-size: 12px; - white-space: nowrap; -} \ No newline at end of file diff --git a/precise/src/style/results.css b/precise/src/style/results.css deleted file mode 100644 index 8c69fbd..0000000 --- a/precise/src/style/results.css +++ /dev/null @@ -1,231 +0,0 @@ -/** - * results.css - * Styles for the query results display - */ - -/* Results Container */ -.result-set { - width: 100%; - overflow-x: auto; - box-sizing: border-box; - padding: 0; - margin: 0; - position: relative; /* For positioning clear and copy buttons */ - } - - .result-table-container { - width: 100%; - overflow-x: auto; - margin: 0; - padding: 0; - } - - /* Results Table */ - .result-table { - table-layout: fixed; - width: 100%; - min-width: 100%; - border-collapse: collapse; - } - - .result-set table { - border-collapse: collapse; - border-spacing: 0; - width: 100%; - box-sizing: border-box; - } - - .result-set tr, - .result-set td, - .result-set th { - box-sizing: border-box; - } - - /* Table Rows & Cells */ - .result-set tr:nth-child(even) td { - background-color: var(--subtle-lighter-accent-color); - } - - .result-set tr:nth-child(odd) td { - background-color: var(--lighter-accent-color); - } - - .result-set td { - padding: 10px; - border: 1px solid var(--lighter-accent-color); - text-align: left; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - } - - .result-set th { - padding: 10px; - text-align: left; - background-color: var(--subtle-darker-accent-color); - color: darkgray; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - } - - /* Null Values */ - .result-cell-null { - color: var(--muted-text-color); - font-style: italic; - } - - /* Clear Results Button */ - .clear-result-table { - position: absolute; - right: 0; - max-width: calc(100% - 20px); - color: var(--muted-text-color); - font-size: small; - cursor: pointer; - margin-right: 1em; - } - - /* Stats Display */ - .stats { - margin: 0em; - } - - /* Collapsed Display */ - .displaydefaultcollapsed { - display: none; - } - - /* Reload Link */ - .reload-link-div { - text-align: right; - float: right; - padding-right: 0.5em; - cursor: pointer; - font-size: small; - color: var(--error-color-subtle); - } - - .reload-link-div:hover { - color: var(--white); - } - - /* Results table structure improvements */ -.result-set tr, .result-set td, .result-set th { - box-sizing: border-box; - } - - .result-set table { - border-collapse: collapse; - border-spacing: 0; - width: 100%; - box-sizing: border-box; - } - - /* Adding missing hover style */ - .reload-link-div:hover { - color: var(--white); - } - - /* Fix table container sizing */ - .result-table-container { - width: 100%; - overflow-x: auto; - margin: 0; - padding: 0; - } - - /* Fix copy link formatting */ - .offset-page-for-copy { - font-size: .875em; - margin-right: .125em; - position: relative; - top: -.25em; - left: -.125em; - } - - .offset-page-for-copy-inner { - position: absolute; - top: .25em; - left: .25em; - } - - /* Helper text formatting */ - .helper-text { - color: #666; - font-size: x-small; - } - - /* Shared styles for action buttons (copy and clear) */ -.result-action-button { - position: absolute; - background-color: rgba(40, 40, 40, 0.6); - color: rgba(200, 200, 200, 0.8); - padding: 8px 12px; - border-radius: 4px; - font-size: small; - cursor: pointer; - display: flex; - align-items: center; - justify-content: center; - transition: all 0.2s ease-in-out; - backdrop-filter: blur(2px); - z-index: 10; - box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); - right: 10px; /* Positioned on the right */ - width: auto; /* Allow content to determine width */ - white-space: nowrap; /* Keep text on one line */ - } - - - .result-action-button:hover { - transform: scale(1.15); - background-color: rgba(60, 60, 60, 0.8); - color: white; - box-shadow: 0 3px 8px rgba(0, 0, 0, 0.3); - } - - .copy-link { - position: absolute; - top: 2px; - right: 10px; - max-width: calc(100% - 20px); - } - - .copy-link.copied { - animation: action-pulse 0.3s ease-in-out; - background-color: rgba(40, 100, 40, 0.8); - } - - /* Clear button specific styles */ - .clear-result-table { - top: 2px; - margin-right: 80px; - } - - .clear-result-table.confirmed { - animation: action-pulse 0.3s ease-in-out; - background-color: rgba(120, 40, 40, 0.8); - } - - /* Shared animation for feedback */ - @keyframes action-pulse { - 0% { transform: scale(1.15); } - 50% { transform: scale(1.3); } - 100% { transform: scale(1.15); } - } - - /* Icon styling */ - .action-icon { - margin-right: 6px; - } - - /* Text label styling */ - .action-text { - user-select: none; - } - - /* Make sure the result container has proper positioning context */ - .result-set { - position: relative; - } \ No newline at end of file diff --git a/precise/src/style/theme.css b/precise/src/style/theme.css deleted file mode 100644 index a2eb627..0000000 --- a/precise/src/style/theme.css +++ /dev/null @@ -1,66 +0,0 @@ -/** - * theme.css - * Contains all theme variables and color definitions - */ - - :root { - /* Base typography */ - font-weight: 400; - font-synthesis: none; - text-rendering: optimizeLegibility; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - - /* Color scheme */ - color-scheme: light dark; - color: rgba(255, 255, 255, 0.87); - background-color: #242424; - - /* Brand Colors */ - --bytes-color: #1C364D; - --bytes-color-partial-transparent: rgba(28, 54, 77, 0.5); - --rows-color: #0C61A6; - --rows-color-partial-transparent: rgba(12, 97, 166, 0.5); - --splits-color: #564682; - --splits-color-partial-transparent: rgba(86, 70, 130, 0.5); - - /* UI Colors */ - --link-color: #5bc0de; - --link-hover-color: #747bff; - --border-color: #646cff; - --subtle-lighter-accent-color: #1e1e1e; - --lighter-accent-color: #2c2c2c; - --subtle-darker-accent-color: #131313; - - /* Text Colors */ - --muted-text-color: #888; - --white: #fff; - - /* Gradient */ - --brand-gradient: linear-gradient(45deg, #564682, #1C2F44, #1C364D, #0C61A6); - - /* Structural Colors */ - --dark-gray: #333; - --medium-gray: #555; - --light-gray: #666; - --very-dark-gray: #111; - --dark-accent: #222; - --highlight-blue: #689CC5; - - /* Success/Error States */ - --success-color: rgba(1, 123, 15, 0.5); - --error-color-subtle: #999; -} - -@media (prefers-color-scheme: light) { - :root { - color: #213547; - background-color: #ffffff; - } - a:hover { - color: #747bff; - } - button { - background-color: #f9f9f9; - } -} \ No newline at end of file diff --git a/precise/src/theme.tsx b/precise/src/theme.tsx new file mode 100644 index 0000000..ebdf6b0 --- /dev/null +++ b/precise/src/theme.tsx @@ -0,0 +1,45 @@ +import { createTheme } from '@mui/material/styles' +import darkScrollbar from '@mui/material/darkScrollbar' + +export const lightTheme = createTheme({ + palette: { + mode: 'light', + primary: { + main: '#0b1367', + }, + secondary: { + main: '#f50057', + }, + }, + components: { + MuiLink: { + styleOverrides: { + root: { + color: '#f50057', + textDecoration: 'none', + }, + }, + }, + }, +}) + +export const darkTheme = createTheme({ + palette: { + mode: 'dark', + }, + components: { + MuiLink: { + styleOverrides: { + root: { + color: '#dd33fa', + textDecoration: 'none', + }, + }, + }, + MuiCssBaseline: { + styleOverrides: { + body: darkScrollbar(), + }, + }, + }, +}) diff --git a/precise/src/utils/ClearButton.tsx b/precise/src/utils/ClearButton.tsx index 89031ca..6809022 100644 --- a/precise/src/utils/ClearButton.tsx +++ b/precise/src/utils/ClearButton.tsx @@ -1,5 +1,7 @@ import React, { useState } from 'react' -import { Trash2, AlertTriangle } from 'lucide-react' +import { Button, Tooltip } from '@mui/material' +import DeleteOutlineIcon from '@mui/icons-material/DeleteOutline' +import WarningAmberIcon from '@mui/icons-material/WarningAmber' interface ClearButtonProps { onClear: () => void @@ -19,23 +21,18 @@ const ClearButton: React.FC = ({ onClear }) => { } return ( -
    - {confirming ? ( - <> - - Confirm - - ) : ( - <> - - Clear - - )} -
    + + + ) } diff --git a/precise/src/utils/CopyLink.tsx b/precise/src/utils/CopyLink.tsx index 790032a..06d8fe0 100644 --- a/precise/src/utils/CopyLink.tsx +++ b/precise/src/utils/CopyLink.tsx @@ -1,5 +1,7 @@ import React, { useState } from 'react' -import { Copy, CheckCircle } from 'lucide-react' +import { Button, Tooltip } from '@mui/material' +import CopyAllOutlinedIcon from '@mui/icons-material/CopyAllOutlined' +import DoneOutlinedIcon from '@mui/icons-material/DoneOutlined' interface CopyLinkProps { copy: () => void @@ -15,23 +17,24 @@ const CopyLink: React.FC = ({ copy }) => { } return ( -
    - {copied ? ( - <> - - Copied! - - ) : ( - <> - - Copy - - )} -
    + + + ) } diff --git a/precise/src/utils/ErrorBoxProvider.tsx b/precise/src/utils/ErrorBoxProvider.tsx deleted file mode 100644 index 5d7bdca..0000000 --- a/precise/src/utils/ErrorBoxProvider.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import React, { useState } from 'react' -import CloseIcon from '../assets/close.png' -import './errorbox.css' - -interface ErrorBoxProviderProps { - errorMessage: string - errorContext: string -} - -const ErrorBox: React.FC = ({ errorMessage, errorContext }) => { - const [isVisible, setIsVisible] = useState(true) - const [errorTimestamp] = useState(new Date().toISOString()) // Capture timestamp when error occurs - - if (!errorMessage || !isVisible) { - return null - } - - return ( -
    -
    - Error: {errorContext} -
    setIsVisible(false)} - role="button" - aria-label="Close error message" - > - Close -
    -
    -
    -
    - {errorMessage} -
    {errorTimestamp}
    -
    -
    -
    - ) -} - -export default ErrorBox diff --git a/precise/src/utils/ProgressBar.tsx b/precise/src/utils/ProgressBar.tsx deleted file mode 100644 index 9a7cada..0000000 --- a/precise/src/utils/ProgressBar.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import * as React from 'react' - -// ProgressBar properties -interface ProgressBarProps { - progress: number - state: string -} - -// ProgressBar state -interface ProgressBarState {} - -export default class ProgressBar extends React.Component { - constructor(props: ProgressBarProps) { - super(props) - this.state = { - progress: 0, - } - } - - render() { - return ( -
    - {this.props.progress === 0 && Number.isFinite(this.props.progress) ? ( -
    {this.props.state}
    - ) : ( -
    - {Math.round(this.props.progress) + '%'} -
    - )} -
    - ) - } -} diff --git a/precise/src/utils/ResizableContainer.tsx b/precise/src/utils/ResizableContainer.tsx deleted file mode 100644 index 4268c8a..0000000 --- a/precise/src/utils/ResizableContainer.tsx +++ /dev/null @@ -1,83 +0,0 @@ -import React, { useState, useRef, useEffect } from 'react' - -interface ResizableContainerProps { - children: React.ReactNode - initialHeight: string - minHeight?: string - maxHeight?: string - onHeightChange: (newHeight: string) => void -} - -const ResizableContainer: React.FC = ({ - children, - initialHeight, - minHeight = '100px', - maxHeight = '80vh', - onHeightChange, -}) => { - const [height, setHeight] = useState(initialHeight) - const containerRef = useRef(null) - const resizeHandleRef = useRef(null) - - useEffect(() => { - const container = containerRef.current - const resizeHandle = resizeHandleRef.current - let isResizing = false - let startY: number - let startHeight: number - - const onMouseDown = (e: MouseEvent) => { - isResizing = true - startY = e.clientY - startHeight = container!.getBoundingClientRect().height - document.addEventListener('mousemove', onMouseMove) - document.addEventListener('mouseup', onMouseUp) - } - - const onMouseMove = (e: MouseEvent) => { - if (!isResizing) return - const diff = e.clientY - startY - const newHeight = startHeight + diff - const minHeightPx = parseInt(minHeight) - const maxHeightPx = parseInt(maxHeight) - const clampedHeight = Math.max(minHeightPx, Math.min(maxHeightPx, newHeight)) - const newHeightString = `${clampedHeight}px` - setHeight(newHeightString) - onHeightChange(newHeightString) - } - - const onMouseUp = () => { - isResizing = false - document.removeEventListener('mousemove', onMouseMove) - document.removeEventListener('mouseup', onMouseUp) - } - - resizeHandle?.addEventListener('mousedown', onMouseDown) - - return () => { - resizeHandle?.removeEventListener('mousedown', onMouseDown) - document.removeEventListener('mousemove', onMouseMove) - document.removeEventListener('mouseup', onMouseUp) - } - }, [minHeight, maxHeight, onHeightChange]) - - return ( -
    - {children} -
    -
    - ) -} - -export default ResizableContainer diff --git a/precise/src/utils/errorbox.css b/precise/src/utils/errorbox.css deleted file mode 100644 index 9f89172..0000000 --- a/precise/src/utils/errorbox.css +++ /dev/null @@ -1,40 +0,0 @@ -.error-box { - background-color: #2b2b2b; - border: 1px solid #ff6b6b; - border-radius: 4px; - margin: 10px; - padding: 10px; -} - -.error-box-header { - color: #ff6b6b; - display: flex; - justify-content: space-between; - align-items: center; - font-weight: bold; - margin-bottom: 8px; -} - -.error-box-close { - cursor: pointer; - opacity: 0.8; - transition: opacity 0.2s; -} - -.error-box-close:hover { - opacity: 1; -} - -.error-box-body { - color: #ff9999; -} - -.error-box-message { - margin-bottom: 8px; -} - -.error-box-context { - color: #999; - font-size: 0.9em; - margin-top: 8px; -} \ No newline at end of file diff --git a/precise/vite.config.ts b/precise/vite.config.ts index d12a4f7..2675219 100644 --- a/precise/vite.config.ts +++ b/precise/vite.config.ts @@ -4,7 +4,6 @@ import react from '@vitejs/plugin-react' // Used for local debugging against Trino also running on localhost at port 8080: // https://vitejs.dev/config/ export default defineConfig({ - base: '/query/', plugins: [react()], server: { proxy: { @@ -15,6 +14,34 @@ export default defineConfig({ }, }, }, + build: { + lib: { + entry: "src/index.ts", + name: "QueryEditor", + fileName: "index" + }, + rollupOptions: { + // Don’t bundle peer dependencies like React + external: [ + "react", + "react-dom", + "react-dom/client", + "react-dom/server", + "react/jsx-runtime", + "react/jsx-dev-runtime" + ], + output: { + globals: { + react: "React", + "react-dom": "ReactDOM", + "react-dom/client": "ReactDOMClient", + "react-dom/server": "ReactDOMServer", + "react/jsx-runtime": "jsxRuntime", + "react/jsx-dev-runtime": "jsxDevRuntime" + } + } + } + }, }); // Used for integration into Trino @@ -22,4 +49,4 @@ export default defineConfig({ // export default defineConfig({ // base: '/query/', // This tells your app it's served from the /query/ path // plugins: [react()] -// }); \ No newline at end of file +// });