diff --git a/.github/workflows/api-and-component.yml b/.github/workflows/api-and-component.yml index 326b4082b..1cdc70274 100644 --- a/.github/workflows/api-and-component.yml +++ b/.github/workflows/api-and-component.yml @@ -1,4 +1,4 @@ -name: API and Component Tests +name: API, Component and Hook Tests on: push: branches: @@ -8,7 +8,7 @@ on: - master jobs: test: - name: Test API and Components + name: Test API, Components and Hooks strategy: matrix: node-version: [18.16.1, 20.4.0] @@ -25,4 +25,6 @@ jobs: run: npm run test:component - name: Run API Tests run: npm run test:api + - name: Run Hook Tests + run: npm run test:hook diff --git a/.storybook/main.js b/.storybook/main.js index a9544cbef..eac729ee6 100644 --- a/.storybook/main.js +++ b/.storybook/main.js @@ -8,6 +8,7 @@ module.exports = { "@storybook/addon-links", "@storybook/addon-essentials", "@storybook/addon-interactions", + "storybook-dark-mode" ], framework: { diff --git a/.storybook/preview.js b/.storybook/preview.js index a4b5173a3..1a47fade1 100644 --- a/.storybook/preview.js +++ b/.storybook/preview.js @@ -6,5 +6,8 @@ export const parameters = { date: /Date$/, }, }, + darkMode: { + stylePreview: true + } } import '../src/component-library/outputtailwind.css' diff --git a/components.json b/components.json new file mode 100644 index 000000000..9f58b0311 --- /dev/null +++ b/components.json @@ -0,0 +1,17 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "default", + "rsc": true, + "tsx": true, + "tailwind": { + "config": "tailwind.config.js", + "css": "src/component-library/tailwind.css", + "baseColor": "slate", + "cssVariables": false, + "prefix": "" + }, + "aliases": { + "components": "@/component-library", + "utils": "@/component-library/utils" + } +} \ No newline at end of file diff --git a/jest.config.js b/jest.config.js index b86e2e3ef..c0222aff7 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,7 +1,8 @@ module.exports = { - projects: [ + projects: [ '/test/api/jest.api.config.js', '/test/component/jest.component.config.js', + '/test/hook/jest.hook.config.js', '/test/gateway/jest.gateway.config.js', '/test/sdk/jest.sdk.config.js', ], diff --git a/package-lock.json b/package-lock.json index cd977b481..8d5c4333d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,17 +21,22 @@ "@types/react-datepicker": "^4.10.0", "@types/react-dom": "18.0.10", "@types/react-modal": "^3.16.0", + "ag-grid-community": "^32.1.0", + "ag-grid-react": "^32.1.0", "bulma": "^0.9.4", "bulma-checkradio": "^2.1.3", "bulma-steps": "^2.2.1", "bulma-switch": "^2.0.4", "can-ndjson-stream": "^1.0.2", "chart.js": "^4.3.0", + "class-variance-authority": "^0.7.0", + "clsx": "^2.1.1", "comlink": "^4.4.1", "date-format": "^4.0.14", "flowbite-datepicker": "^1.2.2", "inversify": "^6.0.1", "iron-session": "^6.3.1", + "lucide-react": "^0.428.0", "ndjson": "^2.0.0", "next": "^13.5.6", "react": "18.2.0", @@ -42,7 +47,7 @@ "react-modal": "^3.16.1", "reflect-metadata": "^0.1.13", "swr": "^2.0.3", - "tailwind-merge": "^1.11.0", + "tailwind-merge": "^1.14.0", "tailwindcss": "^3.2.7", "typescript": "4.9.5", "util": "^0.12.5" @@ -61,6 +66,7 @@ "@storybook/testing-library": "^0.2.2", "@testing-library/jest-dom": "^5.16.5", "@testing-library/react": "^13.4.0", + "@testing-library/react-hooks": "^8.0.1", "@testing-library/user-event": "^14.4.3", "@types/react-highlight": "^0.12.5", "babel-loader": "^8.3.0", @@ -80,9 +86,11 @@ "sass": "^1.58.1", "sass-loader": "^13.2.0", "storybook": "^7.6.4", + "storybook-dark-mode": "^4.0.2", "style-loader": "^3.3.1", - "tailwindcss-animate": "^1.0.5", - "ts-node": "^10.9.1" + "tailwindcss-animate": "^1.0.7", + "ts-node": "^10.9.1", + "web-streams-polyfill": "^4.0.0" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -5725,6 +5733,19 @@ "integrity": "sha512-FcOqPAXACP0I3oJ/ws6/rrPT9WGhu915Cg8D02a9YxLo0DE9zI+a9A5gRGvmQ09fiWPukqI8ZAEoQEdWUKMQdQ==", "dev": true }, + "node_modules/@storybook/icons": { + "version": "1.2.10", + "resolved": "https://registry.npmjs.org/@storybook/icons/-/icons-1.2.10.tgz", + "integrity": "sha512-310apKdDcjbbX2VSLWPwhEwAgjxTzVagrwucVZIdGPErwiAppX8KvBuWZgPo+rQLVrtH8S+pw1dbUwjcE6d7og==", + "dev": true, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/@storybook/manager": { "version": "7.6.4", "resolved": "https://registry.npmjs.org/@storybook/manager/-/manager-7.6.4.tgz", @@ -6612,6 +6633,36 @@ "react-dom": "^18.0.0" } }, + "node_modules/@testing-library/react-hooks": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@testing-library/react-hooks/-/react-hooks-8.0.1.tgz", + "integrity": "sha512-Aqhl2IVmLt8IovEVarNDFuJDVWVvhnr9/GCU6UUnrYXwgDFF9h2L2o2P9KBni1AST5sT6riAyoukFLyjQUgD/g==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.12.5", + "react-error-boundary": "^3.1.0" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "@types/react": "^16.9.0 || ^17.0.0", + "react": "^16.9.0 || ^17.0.0", + "react-dom": "^16.9.0 || ^17.0.0", + "react-test-renderer": "^16.9.0 || ^17.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "react-test-renderer": { + "optional": true + } + } + }, "node_modules/@testing-library/user-event": { "version": "14.4.3", "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.4.3.tgz", @@ -7432,6 +7483,15 @@ "web-streams-polyfill": "^3.1.1" } }, + "node_modules/@web-std/stream/node_modules/web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, "node_modules/@webassemblyjs/ast": { "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz", @@ -7781,6 +7841,32 @@ "node": ">=8.9" } }, + "node_modules/ag-charts-types": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/ag-charts-types/-/ag-charts-types-10.1.0.tgz", + "integrity": "sha512-pk9ft8hbgTXJ/thI/SEUR1BoauNplYExpcHh7tMOqVikoDsta1O15TB1ZL4XWnl4TPIzROBmONKsz7d8a2HBuQ==" + }, + "node_modules/ag-grid-community": { + "version": "32.1.0", + "resolved": "https://registry.npmjs.org/ag-grid-community/-/ag-grid-community-32.1.0.tgz", + "integrity": "sha512-RVvkjRH61nuCXwIqTKQPqNbKR+8cGBKw7S1qmmMXsy0pCBAJaQn4kL3v31hKHxDtV4bPscBXLFKGnKzHuss0GQ==", + "dependencies": { + "ag-charts-types": "10.1.0" + } + }, + "node_modules/ag-grid-react": { + "version": "32.1.0", + "resolved": "https://registry.npmjs.org/ag-grid-react/-/ag-grid-react-32.1.0.tgz", + "integrity": "sha512-GDbtvU3aicSajWXWxvQio5ZaPqJDx2jzgRBKQf1RF1IVzL+XATDmLFNuMND0+wJ/VW/xUjBFjiq9W1fjXg/DCA==", + "dependencies": { + "ag-grid-community": "32.1.0", + "prop-types": "^15.8.1" + }, + "peerDependencies": { + "react": "^16.3.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.3.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/agent-base": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", @@ -9023,6 +9109,25 @@ "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", "dev": true }, + "node_modules/class-variance-authority": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.0.tgz", + "integrity": "sha512-jFI8IQw4hczaL4ALINxqLEXQbWcNjoSkloa4IaufXCJr6QawJyw7tuRysRsrE8w2p/4gGaxKIt/hX3qz/IbD1A==", + "dependencies": { + "clsx": "2.0.0" + }, + "funding": { + "url": "https://joebell.co.uk" + } + }, + "node_modules/class-variance-authority/node_modules/clsx": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz", + "integrity": "sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==", + "engines": { + "node": ">=6" + } + }, "node_modules/classnames": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz", @@ -9143,6 +9248,14 @@ "node": ">=0.10.0" } }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "engines": { + "node": ">=6" + } + }, "node_modules/co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", @@ -14717,6 +14830,14 @@ "node": ">=10" } }, + "node_modules/lucide-react": { + "version": "0.428.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.428.0.tgz", + "integrity": "sha512-rGrzslfEcgqwh+TLBC5qJ8wvVIXhLvAIXVFKNHndYyb1utSxxn9rXOC+1CNJLi6yNOooyPqIs6+3YCp6uSiEvg==", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc" + } + }, "node_modules/lz-string": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", @@ -16953,6 +17074,22 @@ "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", "dev": true }, + "node_modules/react-error-boundary": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/react-error-boundary/-/react-error-boundary-3.1.4.tgz", + "integrity": "sha512-uM9uPzZJTF6wRQORmSrvOIgt4lJ9MC1sNgEOj2XGsDTRE4kmpWxg7ENK9EWNKJRMAOY9z0MuF4yIfl6gp4sotA==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.12.5" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + }, + "peerDependencies": { + "react": ">=16.13.1" + } + }, "node_modules/react-fast-compare": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.1.tgz", @@ -18239,6 +18376,74 @@ "url": "https://opencollective.com/storybook" } }, + "node_modules/storybook-dark-mode": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/storybook-dark-mode/-/storybook-dark-mode-4.0.2.tgz", + "integrity": "sha512-zjcwwQ01R5t1VsakA6alc2JDIRVtavryW8J3E3eKLDIlAMcvsgtpxlelWkZs2cuNspk6Z10XzhQVrUWtYc3F0w==", + "dev": true, + "dependencies": { + "@storybook/components": "^8.0.0", + "@storybook/core-events": "^8.0.0", + "@storybook/global": "^5.0.0", + "@storybook/icons": "^1.2.5", + "@storybook/manager-api": "^8.0.0", + "@storybook/theming": "^8.0.0", + "fast-deep-equal": "^3.1.3", + "memoizerific": "^1.11.3" + } + }, + "node_modules/storybook-dark-mode/node_modules/@storybook/components": { + "version": "8.2.9", + "resolved": "https://registry.npmjs.org/@storybook/components/-/components-8.2.9.tgz", + "integrity": "sha512-OkkcZ/f/6o3GdFEEK9ZHKIGHWUHmavZUYs5xaSgU64bOrA2aqEFtfeWWitZYTv3Euhk8MVLWfyEMDfez0AlvDg==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.9" + } + }, + "node_modules/storybook-dark-mode/node_modules/@storybook/core-events": { + "version": "8.2.9", + "resolved": "https://registry.npmjs.org/@storybook/core-events/-/core-events-8.2.9.tgz", + "integrity": "sha512-8VS6k2ySAYdG2VBWxb66Vko7Pqd429TIdkrw1/u2N0IPsvPsdbs3WaOTyxOMB1e39YUCpD/IZUOPdxX2lC3g4w==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.9" + } + }, + "node_modules/storybook-dark-mode/node_modules/@storybook/manager-api": { + "version": "8.2.9", + "resolved": "https://registry.npmjs.org/@storybook/manager-api/-/manager-api-8.2.9.tgz", + "integrity": "sha512-mkYvUlfqDw+0WbxIynh5TcrotmoXlumEsOA4+45zuNea8XpEgj5cNBUCnmfEO6yQ85swqkS8YYbMpg1cZyu/Vw==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.9" + } + }, + "node_modules/storybook-dark-mode/node_modules/@storybook/theming": { + "version": "8.2.9", + "resolved": "https://registry.npmjs.org/@storybook/theming/-/theming-8.2.9.tgz", + "integrity": "sha512-OL0NFvowPX85N5zIYdgeKKaFm7V4Vgtci093vL3cDZT13LGH6GuEzJKkUFGuUGNPFlJc+EgTj0o6PYKrOLyQ6w==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.9" + } + }, "node_modules/stream-browserify": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", @@ -18586,9 +18791,9 @@ } }, "node_modules/tailwind-merge": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-1.11.0.tgz", - "integrity": "sha512-oG3/328Y7LrfPMfkgMNxoqEk1ZQdXBxdphf9FFrreo8q0EtVIHt3bQf2IyFhQuVt8puB57lCRBNbazGhYAyz9w==", + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-1.14.0.tgz", + "integrity": "sha512-3mFKyCo/MBcgyOTlrY8T7odzZFx+w+qKSMAmdFzRvqBfLlSigU6TZnlFHK0lkMwj9Bj8OYU+9yW9lmGuS0QEnQ==", "funding": { "type": "github", "url": "https://github.com/sponsors/dcastil" @@ -18635,9 +18840,9 @@ } }, "node_modules/tailwindcss-animate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tailwindcss-animate/-/tailwindcss-animate-1.0.5.tgz", - "integrity": "sha512-UU3qrOJ4lFQABY+MVADmBm+0KW3xZyhMdRvejwtXqYOL7YjHYxmuREFAZdmVG5LPe5E9CAst846SLC4j5I3dcw==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/tailwindcss-animate/-/tailwindcss-animate-1.0.7.tgz", + "integrity": "sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==", "dev": true, "peerDependencies": { "tailwindcss": ">=3.0.0 || insiders" @@ -19732,9 +19937,9 @@ } }, "node_modules/web-streams-polyfill": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", - "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0.tgz", + "integrity": "sha512-0zJXHRAYEjM2tUfZ2DiSOHAa2aw1tisnnhU3ufD57R8iefL+DcdJyRBRyJpG+NUimDgbTI/lH+gAE1PAvV3Cgw==", "dev": true, "engines": { "node": ">= 8" @@ -24110,6 +24315,12 @@ "integrity": "sha512-FcOqPAXACP0I3oJ/ws6/rrPT9WGhu915Cg8D02a9YxLo0DE9zI+a9A5gRGvmQ09fiWPukqI8ZAEoQEdWUKMQdQ==", "dev": true }, + "@storybook/icons": { + "version": "1.2.10", + "resolved": "https://registry.npmjs.org/@storybook/icons/-/icons-1.2.10.tgz", + "integrity": "sha512-310apKdDcjbbX2VSLWPwhEwAgjxTzVagrwucVZIdGPErwiAppX8KvBuWZgPo+rQLVrtH8S+pw1dbUwjcE6d7og==", + "dev": true + }, "@storybook/manager": { "version": "7.6.4", "resolved": "https://registry.npmjs.org/@storybook/manager/-/manager-7.6.4.tgz", @@ -24652,6 +24863,16 @@ "@types/react-dom": "^18.0.0" } }, + "@testing-library/react-hooks": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@testing-library/react-hooks/-/react-hooks-8.0.1.tgz", + "integrity": "sha512-Aqhl2IVmLt8IovEVarNDFuJDVWVvhnr9/GCU6UUnrYXwgDFF9h2L2o2P9KBni1AST5sT6riAyoukFLyjQUgD/g==", + "dev": true, + "requires": { + "@babel/runtime": "^7.12.5", + "react-error-boundary": "^3.1.0" + } + }, "@testing-library/user-event": { "version": "14.4.3", "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.4.3.tgz", @@ -25358,6 +25579,14 @@ "dev": true, "requires": { "web-streams-polyfill": "^3.1.1" + }, + "dependencies": { + "web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", + "dev": true + } } }, "@webassemblyjs/ast": { @@ -25667,6 +25896,28 @@ "regex-parser": "^2.2.11" } }, + "ag-charts-types": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/ag-charts-types/-/ag-charts-types-10.1.0.tgz", + "integrity": "sha512-pk9ft8hbgTXJ/thI/SEUR1BoauNplYExpcHh7tMOqVikoDsta1O15TB1ZL4XWnl4TPIzROBmONKsz7d8a2HBuQ==" + }, + "ag-grid-community": { + "version": "32.1.0", + "resolved": "https://registry.npmjs.org/ag-grid-community/-/ag-grid-community-32.1.0.tgz", + "integrity": "sha512-RVvkjRH61nuCXwIqTKQPqNbKR+8cGBKw7S1qmmMXsy0pCBAJaQn4kL3v31hKHxDtV4bPscBXLFKGnKzHuss0GQ==", + "requires": { + "ag-charts-types": "10.1.0" + } + }, + "ag-grid-react": { + "version": "32.1.0", + "resolved": "https://registry.npmjs.org/ag-grid-react/-/ag-grid-react-32.1.0.tgz", + "integrity": "sha512-GDbtvU3aicSajWXWxvQio5ZaPqJDx2jzgRBKQf1RF1IVzL+XATDmLFNuMND0+wJ/VW/xUjBFjiq9W1fjXg/DCA==", + "requires": { + "ag-grid-community": "32.1.0", + "prop-types": "^15.8.1" + } + }, "agent-base": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", @@ -26603,6 +26854,21 @@ "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", "dev": true }, + "class-variance-authority": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.0.tgz", + "integrity": "sha512-jFI8IQw4hczaL4ALINxqLEXQbWcNjoSkloa4IaufXCJr6QawJyw7tuRysRsrE8w2p/4gGaxKIt/hX3qz/IbD1A==", + "requires": { + "clsx": "2.0.0" + }, + "dependencies": { + "clsx": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz", + "integrity": "sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==" + } + } + }, "classnames": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz", @@ -26693,6 +26959,11 @@ } } }, + "clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==" + }, "co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", @@ -30953,6 +31224,11 @@ "yallist": "^4.0.0" } }, + "lucide-react": { + "version": "0.428.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.428.0.tgz", + "integrity": "sha512-rGrzslfEcgqwh+TLBC5qJ8wvVIXhLvAIXVFKNHndYyb1utSxxn9rXOC+1CNJLi6yNOooyPqIs6+3YCp6uSiEvg==" + }, "lz-string": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", @@ -32626,6 +32902,15 @@ } } }, + "react-error-boundary": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/react-error-boundary/-/react-error-boundary-3.1.4.tgz", + "integrity": "sha512-uM9uPzZJTF6wRQORmSrvOIgt4lJ9MC1sNgEOj2XGsDTRE4kmpWxg7ENK9EWNKJRMAOY9z0MuF4yIfl6gp4sotA==", + "dev": true, + "requires": { + "@babel/runtime": "^7.12.5" + } + }, "react-fast-compare": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.1.tgz", @@ -33566,6 +33851,48 @@ "@storybook/cli": "7.6.4" } }, + "storybook-dark-mode": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/storybook-dark-mode/-/storybook-dark-mode-4.0.2.tgz", + "integrity": "sha512-zjcwwQ01R5t1VsakA6alc2JDIRVtavryW8J3E3eKLDIlAMcvsgtpxlelWkZs2cuNspk6Z10XzhQVrUWtYc3F0w==", + "dev": true, + "requires": { + "@storybook/components": "^8.0.0", + "@storybook/core-events": "^8.0.0", + "@storybook/global": "^5.0.0", + "@storybook/icons": "^1.2.5", + "@storybook/manager-api": "^8.0.0", + "@storybook/theming": "^8.0.0", + "fast-deep-equal": "^3.1.3", + "memoizerific": "^1.11.3" + }, + "dependencies": { + "@storybook/components": { + "version": "8.2.9", + "resolved": "https://registry.npmjs.org/@storybook/components/-/components-8.2.9.tgz", + "integrity": "sha512-OkkcZ/f/6o3GdFEEK9ZHKIGHWUHmavZUYs5xaSgU64bOrA2aqEFtfeWWitZYTv3Euhk8MVLWfyEMDfez0AlvDg==", + "dev": true + }, + "@storybook/core-events": { + "version": "8.2.9", + "resolved": "https://registry.npmjs.org/@storybook/core-events/-/core-events-8.2.9.tgz", + "integrity": "sha512-8VS6k2ySAYdG2VBWxb66Vko7Pqd429TIdkrw1/u2N0IPsvPsdbs3WaOTyxOMB1e39YUCpD/IZUOPdxX2lC3g4w==", + "dev": true + }, + "@storybook/manager-api": { + "version": "8.2.9", + "resolved": "https://registry.npmjs.org/@storybook/manager-api/-/manager-api-8.2.9.tgz", + "integrity": "sha512-mkYvUlfqDw+0WbxIynh5TcrotmoXlumEsOA4+45zuNea8XpEgj5cNBUCnmfEO6yQ85swqkS8YYbMpg1cZyu/Vw==", + "dev": true + }, + "@storybook/theming": { + "version": "8.2.9", + "resolved": "https://registry.npmjs.org/@storybook/theming/-/theming-8.2.9.tgz", + "integrity": "sha512-OL0NFvowPX85N5zIYdgeKKaFm7V4Vgtci093vL3cDZT13LGH6GuEzJKkUFGuUGNPFlJc+EgTj0o6PYKrOLyQ6w==", + "dev": true + } + } + }, "stream-browserify": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", @@ -33821,9 +34148,9 @@ } }, "tailwind-merge": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-1.11.0.tgz", - "integrity": "sha512-oG3/328Y7LrfPMfkgMNxoqEk1ZQdXBxdphf9FFrreo8q0EtVIHt3bQf2IyFhQuVt8puB57lCRBNbazGhYAyz9w==" + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-1.14.0.tgz", + "integrity": "sha512-3mFKyCo/MBcgyOTlrY8T7odzZFx+w+qKSMAmdFzRvqBfLlSigU6TZnlFHK0lkMwj9Bj8OYU+9yW9lmGuS0QEnQ==" }, "tailwindcss": { "version": "3.2.7", @@ -33863,9 +34190,9 @@ } }, "tailwindcss-animate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tailwindcss-animate/-/tailwindcss-animate-1.0.5.tgz", - "integrity": "sha512-UU3qrOJ4lFQABY+MVADmBm+0KW3xZyhMdRvejwtXqYOL7YjHYxmuREFAZdmVG5LPe5E9CAst846SLC4j5I3dcw==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/tailwindcss-animate/-/tailwindcss-animate-1.0.7.tgz", + "integrity": "sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==", "dev": true }, "tapable": { @@ -34685,9 +35012,9 @@ } }, "web-streams-polyfill": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", - "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0.tgz", + "integrity": "sha512-0zJXHRAYEjM2tUfZ2DiSOHAa2aw1tisnnhU3ufD57R8iefL+DcdJyRBRyJpG+NUimDgbTI/lH+gAE1PAvV3Cgw==", "dev": true }, "webcrypto-core": { diff --git a/package.json b/package.json index 874adf14e..39038a2b2 100644 --- a/package.json +++ b/package.json @@ -9,11 +9,12 @@ "build": "next build", "start": "next start", "lint": "next lint", - "test": "jest --testPathPattern test/component test/api test/gateway test/sdk --projects test/api/jest.api.config.js test/component/jest.component.config.js test/gateway/jest.gateway.config.js test/sdk/jest.sdk.config.js", + "test": "jest --testPathPattern test/component test/api test/gateway test/sdk --projects test/api/jest.api.config.js test/component/jest.component.config.js test/gateway/jest.gateway.config.js test/sdk/jest.sdk.config.js test/hook/jest.hook.config.js", "test:api": "jest --testPathPattern=test/api --projects test/api/jest.api.config.js", "test:component": "jest --testPathPattern=test/component --projects test/component/jest.component.config.js", "test:gateway": "jest --testPathPattern=test/gateway --projects test/gateway/jest.gateway.config.js", "test:sdk": "jest --testPathPattern=test/sdk --projects test/sdk/jest.sdk.config.js", + "test:hook": "jest --testPathPattern=test/hook --projects test/hook/jest.hook.config.js", "storybook": "storybook dev -p 6006", "build-storybook": "storybook build", "build-tailwind": "tailwindcss -i src/component-library/tailwind.css -o src/component-library/outputtailwind.css" @@ -32,17 +33,22 @@ "@types/react-datepicker": "^4.10.0", "@types/react-dom": "18.0.10", "@types/react-modal": "^3.16.0", + "ag-grid-community": "^32.1.0", + "ag-grid-react": "^32.1.0", "bulma": "^0.9.4", "bulma-checkradio": "^2.1.3", "bulma-steps": "^2.2.1", "bulma-switch": "^2.0.4", "can-ndjson-stream": "^1.0.2", "chart.js": "^4.3.0", + "class-variance-authority": "^0.7.0", + "clsx": "^2.1.1", "comlink": "^4.4.1", "date-format": "^4.0.14", "flowbite-datepicker": "^1.2.2", "inversify": "^6.0.1", "iron-session": "^6.3.1", + "lucide-react": "^0.428.0", "ndjson": "^2.0.0", "next": "^13.5.6", "react": "18.2.0", @@ -53,7 +59,7 @@ "react-modal": "^3.16.1", "reflect-metadata": "^0.1.13", "swr": "^2.0.3", - "tailwind-merge": "^1.11.0", + "tailwind-merge": "^1.14.0", "tailwindcss": "^3.2.7", "typescript": "4.9.5", "util": "^0.12.5" @@ -72,6 +78,7 @@ "@storybook/testing-library": "^0.2.2", "@testing-library/jest-dom": "^5.16.5", "@testing-library/react": "^13.4.0", + "@testing-library/react-hooks": "^8.0.1", "@testing-library/user-event": "^14.4.3", "@types/react-highlight": "^0.12.5", "babel-loader": "^8.3.0", @@ -91,8 +98,10 @@ "sass": "^1.58.1", "sass-loader": "^13.2.0", "storybook": "^7.6.4", + "storybook-dark-mode": "^4.0.2", "style-loader": "^3.3.1", - "tailwindcss-animate": "^1.0.5", - "ts-node": "^10.9.1" + "tailwindcss-animate": "^1.0.7", + "ts-node": "^10.9.1", + "web-streams-polyfill": "^4.0.0" } } diff --git a/public/streamWorker.js b/public/streamWorker.js new file mode 100644 index 000000000..9a6091cc6 --- /dev/null +++ b/public/streamWorker.js @@ -0,0 +1,107 @@ +self.onmessage = async function (event) { + const {url, fetchOptions, updateDelay = 50, maxUpdateLength = 100} = event.data; + const buffer = []; + + const postData = () => { + if (buffer.length > maxUpdateLength) { + // Remove the first {maxUpdateLength} elements from the buffer + const newBuffer = buffer.splice(0, maxUpdateLength); + self.postMessage({type: 'data', data: newBuffer}); + } else { + self.postMessage({type: 'data', data: buffer}); + buffer.length = 0; + } + }; + + const updateWhileFetching = () => { + if (buffer.length === 0) return; + postData(); + }; + + const updateAfterFetching = () => { + if (buffer.length === 0) { + self.postMessage({type: 'finish'}); + } + postData(); + if (buffer.length === 0) { + self.postMessage({type: 'finish'}); + } + } + + const whileFetchingInterval = setInterval(updateWhileFetching, updateDelay); + + try { + const response = await fetch(url, fetchOptions); + if (!response.ok) { + self.postMessage({type: 'error', error: await getResponseError(response)}); + return; + } + + const reader = response.body.getReader(); + const decoder = new TextDecoder(); + let partialData = ''; + + while (true) { + const {done, value} = await reader.read(); + if (done) break; + + const chunk = decoder.decode(value, {stream: true}); + partialData += chunk; + + const lines = partialData.split('\n'); + partialData = lines.pop() || ''; + + for (const line of lines) { + try { + const parsedObject = JSON.parse(line); + buffer.push(parsedObject); + } catch (e) { + self.postMessage({type: 'error', error: {type: 'parsing_error', message: e.message}}); + clearInterval(whileFetchingInterval); + return; + } + } + } + + if (partialData) { + try { + const parsedObject = JSON.parse(partialData); + buffer.push(parsedObject); + } catch (e) { + self.postMessage({type: 'error', error: {type: 'parsing_error', message: e.message}}); + clearInterval(whileFetchingInterval); + return; + } + } + + clearInterval(whileFetchingInterval); + postData(); + if (buffer.length === 0) { + self.postMessage({type: 'finish'}); + } else { + setInterval(updateAfterFetching, updateDelay); + } + } catch (e) { + self.postMessage({type: 'error', error: {type: 'network_error', message: e.message}}); + } finally { + clearInterval(whileFetchingInterval); + } +}; + +async function getResponseError(response) { + let message = response.statusText; + + try { + const jsonResponse = await response.json(); + message = jsonResponse.message ?? message; + } catch (e) { + } + + const error = {type: 'invalid_response', message: message}; + if (response.status === 404) { + error.type = 'not_found'; + } else if (response.status === 400) { + error.type = 'bad_request'; + } + return error; +} diff --git a/src/app/(rucio)/did/list/page.tsx b/src/app/(rucio)/did/list/page.tsx index d4a96b907..a289b75fb 100644 --- a/src/app/(rucio)/did/list/page.tsx +++ b/src/app/(rucio)/did/list/page.tsx @@ -1,48 +1,17 @@ 'use client'; -import { ListDID as ListDIDStory } from "@/component-library/Pages/DID/ListDID"; -import { DIDType } from "@/lib/core/entity/rucio"; -import { DIDMetaViewModel, DIDViewModel } from "@/lib/infrastructure/data/view-model/did"; -import useComDOM from "@/lib/infrastructure/hooks/useComDOM"; -import { useEffect, useState } from "react"; +import { ListDID } from "@/component-library/Pages/DID/ListDID"; +import { DIDViewModel } from "@/lib/infrastructure/data/view-model/did"; import { didMetaQueryBase } from "../queries"; +import useChunkedStream from "@/lib/infrastructure/hooks/useChunkedStream"; export default function Page() { - const [didMetaQueryResponse, setDIDMetaQueryResponse] = useState({status: "pending"} as DIDMetaViewModel) + const streamingHook = useChunkedStream(); - const didMetaQuery = async (scope: string, name: string) => { - setDIDMetaQueryResponse(await didMetaQueryBase(scope, name)) - } - const didQuery = async (query: string, type: DIDType) => { - const request: any = { - url: new URL(`${process.env.NEXT_PUBLIC_WEBUI_HOST}/api/feature/list-dids`), - method: 'GET', - headers: new Headers({ - 'Content-Type': 'application/json', - } as HeadersInit), - params: { - "query": query, - "type": type - }, - - } - await DIDSearchComDOM.setRequest(request) - } - - const DIDSearchComDOM = useComDOM( - 'list-did-query', - [], - false, - Infinity, - 200, - true - ) return ( - ) } diff --git a/src/app/(rucio)/did/page/[scope]/[name]/page.tsx b/src/app/(rucio)/did/page/[scope]/[name]/page.tsx index 28176fc89..b5185b6ca 100644 --- a/src/app/(rucio)/did/page/[scope]/[name]/page.tsx +++ b/src/app/(rucio)/did/page/[scope]/[name]/page.tsx @@ -4,7 +4,7 @@ import useComDOM from "@/lib/infrastructure/hooks/useComDOM"; import { useEffect, useState } from "react"; import { fixtureDIDDatasetReplicasViewModel, fixtureDIDKeyValuePairsDataViewModel, fixtureDIDMetaViewModel, fixtureDIDRulesViewModel, mockUseComDOM } from 'test/fixtures/table-fixtures'; import { HTTPRequest } from "@/lib/sdk/http"; -import { DIDDatasetReplicasViewModel, DIDKeyValuePairsDataViewModel, DIDMetaViewModel, DIDRulesViewModel, DIDViewModel, FilereplicaStateDViewModel, FilereplicaStateViewModel } from '@/lib/infrastructure/data/view-model/did'; +import { DIDDatasetReplicasViewModel, DIDKeyValuePairsDataViewModel, DIDMetaViewModel, DIDRulesViewModel, DIDViewModel, FilereplicaStateDViewModel, FileReplicaStateViewModel } from '@/lib/infrastructure/data/view-model/did'; import { didKeyValuePairsDataQuery, didMetaQueryBase } from '@/app/(rucio)/did/queries'; import { Loading } from '@/component-library/Pages/Helpers/Loading'; @@ -25,7 +25,7 @@ export default function Page({ params }: { params: { scope: string, name: string const didContentsComDOM = useComDOM( 'page-did-contents-query', [], false, Infinity, 200, true ) - const didFileReplicasComDOM = useComDOM( + const didFileReplicasComDOM = useComDOM( 'page-did-filereplicas-query', [], false, Infinity, 200, true ) const didFileReplicasDOnChange = (scope: string, name: string) => { diff --git a/src/app/(rucio)/rse/list/page.tsx b/src/app/(rucio)/rse/list/page.tsx index 3b09a3ab0..f21a219b8 100644 --- a/src/app/(rucio)/rse/list/page.tsx +++ b/src/app/(rucio)/rse/list/page.tsx @@ -1,38 +1,11 @@ 'use client'; -import { ListRSE as ListRSEStory } from "@/component-library/Pages/RSE/ListRSE"; -import { RSEViewModel } from "@/lib/infrastructure/data/view-model/rse"; -import useComDOM from "@/lib/infrastructure/hooks/useComDOM"; -import { HTTPRequest } from "@/lib/sdk/http"; -import { mockUseComDOM, fixtureRSEViewModel } from "test/fixtures/table-fixtures"; -export default function Page() { - - const setRSEQuery = async (rseExpression: string) => { - await RSESearchComDOM.setRequest({ - url: new URL(`${process.env.NEXT_PUBLIC_WEBUI_HOST}/api/feature/list-rses`), - method: 'GET', - headers: new Headers({ - 'Content-Type': 'application/json', - } as HeadersInit), - params: { - "rseExpression": rseExpression - }, - } as HTTPRequest) - } - const RSESearchComDOM = useComDOM( - 'list-rse-query', - [], - false, - Infinity, - 200, - true - ) +import {ListRSE} from "@/component-library/Pages/RSE/ListRSE"; +import {RSEViewModel} from "@/lib/infrastructure/data/view-model/list-rse"; +import useChunkedStream from "@/lib/infrastructure/hooks/useChunkedStream"; - return ( - - ) +export default function Page() { + const streamingHook = useChunkedStream(); + return ; } \ No newline at end of file diff --git a/src/component-library/Pages/DID/ListDID.stories.tsx b/src/component-library/Pages/DID/ListDID.stories.tsx index 9f08d6250..4362d5a28 100644 --- a/src/component-library/Pages/DID/ListDID.stories.tsx +++ b/src/component-library/Pages/DID/ListDID.stories.tsx @@ -1,17 +1,27 @@ -import { StoryFn, Meta } from '@storybook/react'; -import { ListDID as LD } from './ListDID'; -import { fixtureDIDMetaViewModel, fixtureDIDViewModel, mockUseComDOM } from 'test/fixtures/table-fixtures'; +import {StoryFn, Meta} from '@storybook/react'; +import {ListDID as LD} from './ListDID'; +import { + fixtureDIDMetaViewModel, + fixtureDIDViewModel, + mockUseChunkedStream, +} from 'test/fixtures/table-fixtures'; +import {DIDMetaViewModel} from "@/lib/infrastructure/data/view-model/did"; export default { title: 'Components/Pages/DID', component: LD, } as Meta; -const Template: StoryFn = (args) => ; +const Template: StoryFn = (args) => { + return
+ +
; +} export const ListDID = Template.bind({}); ListDID.args = { - comdom: mockUseComDOM(Array.from({length: 100}, () => fixtureDIDViewModel())), - didMetaQuery: (scope: string, name: string) => { }, - didMetaQueryResponse: fixtureDIDMetaViewModel() + streamingHook: mockUseChunkedStream(Array.from({length: 100}, () => fixtureDIDViewModel())), + queryMeta: async (): Promise => { + return Promise.resolve(fixtureDIDMetaViewModel()); + }, } diff --git a/src/component-library/Pages/DID/ListDID.tsx b/src/component-library/Pages/DID/ListDID.tsx index e89c38da0..9a86214a9 100644 --- a/src/component-library/Pages/DID/ListDID.tsx +++ b/src/component-library/Pages/DID/ListDID.tsx @@ -1,56 +1,101 @@ -import { DIDViewModel, DIDMetaViewModel } from "@/lib/infrastructure/data/view-model/did" -import { useEffect, useState } from "react" -import { twMerge } from "tailwind-merge" -import { TextInput } from "../../Input/TextInput" -import { Button } from "../../Button/Button" -import { DIDMetaView } from "./DIDMetaView" -import { ListDIDTable } from "./ListDIDTable" -import { UseComDOM } from "@/lib/infrastructure/hooks/useComDOM" -import { Heading } from "../Helpers/Heading" -import { Body } from "../Helpers/Body" -import { DIDType } from "@/lib/core/entity/rucio" -import { Checkbox } from "../../Button/Checkbox" +import {DIDMetaViewModel, DIDViewModel} from "@/lib/infrastructure/data/view-model/did" +import {useEffect, useRef, useState} from "react" +import {twMerge} from "tailwind-merge" +import {TextInput} from "../../Input/TextInput" +import {Button} from "../../Button/Button" +import {DIDMetaView} from "./DIDMetaView" +import {ListDIDTable} from "./ListDIDTable" +import {Heading} from "../Helpers/Heading" +import {Body} from "../Helpers/Body" +import {DIDType} from "@/lib/core/entity/rucio" +import {Checkbox} from "../../Button/Checkbox" import Link from "next/link" import {useSearchParams} from "next/navigation"; - -var format = require("date-format") +import {StreamingStatus, UseChunkedStream} from "@/lib/infrastructure/hooks/useChunkedStream"; +import {AgGridReact} from "ag-grid-react"; +import {SelectionChangedEvent} from "ag-grid-community"; export interface ListDIDPageProps { - comdom: UseComDOM, - didQuery: (query: string, type: DIDType) => void, - didMetaQuery: (scope: string, name: string) => void, - didMetaQueryResponse: DIDMetaViewModel, + streamingHook: UseChunkedStream, + queryMeta: (scope: string, name: string) => Promise, } - - export const ListDID = ( props: ListDIDPageProps ) => { const searchParams = useSearchParams() - const pattern = searchParams?.get('pattern') + const firstPattern = searchParams?.get('pattern') + + const tableRef = useRef(null); - const meta = props.didMetaQueryResponse - const [didSearchQuery, setDidSearchQuery] = useState(pattern ?? "") - const [didTypeAllowed, setDidTypeAllowed] = useState(DIDType.DATASET) // [container, dataset, file] + // TODO: null instead of pending + const [meta, setMeta] = useState({status: "pending"} as DIDMetaViewModel) + const [pattern, setPattern] = useState(firstPattern ?? null); + const [type, setType] = useState(DIDType.DATASET); + + const [selected, setSelected] = useState(null); + + const getMeta = async () => { + // TODO: handle multiple ongoing requests for metadata + const newMeta = await props.queryMeta(selected!.scope, selected!.name); + setMeta(newMeta); + } - // selection - const [selectedDID, setSelectedDID] = useState(null) // scope:name taken from table - const [selection, setSelection] = useState([]) // list of objects from table useEffect(() => { - if (selection.length === 1) { - setSelectedDID(selection[0].scope + ":" + selection[0].name) - props.didMetaQuery(selection[0].scope, selection[0].name) + if (selected !== null) { + getMeta(); } - else { - setSelectedDID(null) + }, [selected]) + + const onData = (data: DIDViewModel[]) => { + tableRef.current?.api.applyTransactionAsync({add: data}); + } + + const startStreaming = () => { + if (tableRef.current?.api) { + const api = tableRef.current!.api; + api.setGridOption('rowData', []); } - }, [selection]) + + const url = '/api/feature/list-dids?' + new URLSearchParams({ + 'query': pattern!, + 'type': type + }); + props.streamingHook.start({url, onData}); + }; + + useEffect(() => { + if (pattern === null) return; + + startStreaming(); + }, []); + + const onSearch = (event: any) => { + event.preventDefault(); + // TODO: display a warning message + if (pattern === null || pattern === '') return; + // TODO: possibly check for semicolon on the client side as well + + if (props.streamingHook.status !== StreamingStatus.RUNNING) { + startStreaming(); + } else { + // TODO: display an error message + } + } + + const onSelectionChanged = (event: SelectionChangedEvent) => { + const selectedRows = event.api.getSelectedRows(); + if (selectedRows.length === 1) { + setSelected(selectedRows[0] as DIDViewModel); + } else { + setSelected(null); + } + }; return (
{ setDidSearchQuery(event.target.value) }} - onEnterkey={async (e: any) => { - e.preventDefault() - await props.didQuery(e.target.value, didTypeAllowed) - setDidSearchQuery(e.target.value) - props.comdom.start() + onChange={(event) => { + setPattern(event.target.value); }} + onEnterkey={onSearch} id="did-search-pattern" - defaultValue={didSearchQuery} + defaultValue={firstPattern ?? ''} />
+
-
- + {setDidTypeAllowed(e.target.id as DIDType)}} + onChange={(e: any) => { + setType(e.target.id as DIDType) + }} id={DIDType.CONTAINER} /> {setDidTypeAllowed(e.target.id as DIDType)}} - checked={didTypeAllowed === DIDType.DATASET} // default to dataset + onChange={(e: any) => { + setType(e.target.id as DIDType) + }} + checked={type === DIDType.DATASET} // default to dataset id={DIDType.DATASET} /> {setDidTypeAllowed(e.target.id as DIDType)}} + onChange={(e: any) => { + setType(e.target.id as DIDType) + }} id={DIDType.FILE} /> @@ -140,21 +196,21 @@ export const ListDID = (
{ - // pass data from child (table) into the component state - setSelection(data) - }} + streamingHook={props.streamingHook} + tableRef={tableRef} + onSelectionChanged={onSelectionChanged} />
- +
@@ -176,7 +232,7 @@ export const ListDID = (
diff --git a/src/component-library/Pages/DID/ListDIDTable.stories.tsx b/src/component-library/Pages/DID/ListDIDTable.stories.tsx deleted file mode 100644 index 5c75ebe63..000000000 --- a/src/component-library/Pages/DID/ListDIDTable.stories.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import { StoryFn, Meta } from "@storybook/react"; -import { ListDIDTable as L } from "./ListDIDTable"; -import { fixtureDIDViewModel, mockUseComDOM } from "test/fixtures/table-fixtures"; -import { DID } from "@/lib/core/entity/rucio"; - -export default { - title: 'Components/Pages/DID', - component: L, -} as Meta; - -const Template: StoryFn = (args) => ; - -export const ListDIDTable = Template.bind({}); -ListDIDTable.args = { - comdom: mockUseComDOM(Array.from({length: 100}, () => fixtureDIDViewModel())), - selectionFunc: (data: DID[]) => {console.info("ListDIDTable", data)} -}; diff --git a/src/component-library/Pages/DID/ListDIDTable.tsx b/src/component-library/Pages/DID/ListDIDTable.tsx index 9fccf9247..4a09b10c7 100644 --- a/src/component-library/Pages/DID/ListDIDTable.tsx +++ b/src/component-library/Pages/DID/ListDIDTable.tsx @@ -1,50 +1,29 @@ -import { twMerge } from "tailwind-merge"; -import { DIDViewModel } from "@/lib/infrastructure/data/view-model/did"; -import { createColumnHelper } from "@tanstack/react-table"; -import { TableFilterString } from "../../StreamedTables/TableFilterString"; -import { P } from "../../Text/Content/P"; -import { StreamedTable } from "../../StreamedTables/StreamedTable"; -import { useCallback } from "react"; -import { UseComDOM } from "@/lib/infrastructure/hooks/useComDOM"; +import React, {RefObject, useState} from "react"; +import {AgGridReact} from "ag-grid-react"; +import {UseChunkedStream} from "@/lib/infrastructure/hooks/useChunkedStream"; +import {StreamedTable} from "@/component-library/Table/StreamedTable"; +import {DefaultTextFilterParams} from "@/component-library/Table/FilterParameters/DefaultTextFilterParams"; +import {DIDViewModel} from "@/lib/infrastructure/data/view-model/did"; +import {SelectionChangedEvent, ValueGetterParams} from "ag-grid-community"; -export const ListDIDTable = ( - props: { - comdom: UseComDOM, - selectionFunc: (data: DIDViewModel[]) => void - } -) => { - const tableData = props.comdom - const columnHelper = createColumnHelper() - const tablecolumns = [ - columnHelper.accessor(row => `${row.scope}:${row.name}`, { - id: "did", - header: info => { - return ( - - ) +type ListDIDTableProps = { + tableRef: RefObject + streamingHook: UseChunkedStream + onSelectionChanged: (event: SelectionChangedEvent) => void, +} + +export const ListDIDTable = (props: ListDIDTableProps) => { + const [columnDefs] = useState([ + { + headerName: 'Name', + valueGetter: (params: ValueGetterParams) => { + return params.data?.scope + ':' + params.data?.name; }, - cell: info =>

{info.getValue()}

- }) - ] - const handleChange = useCallback((data: any[]) => { - props.selectionFunc(data) - }, [props]) + minWidth: 250, + filter: true, + filterParams: DefaultTextFilterParams, + }, + ]); - return ( - - ); -}; + return +} \ No newline at end of file diff --git a/src/component-library/Pages/DID/PageDID.tsx b/src/component-library/Pages/DID/PageDID.tsx index 5d638cad4..cebf2f9a4 100644 --- a/src/component-library/Pages/DID/PageDID.tsx +++ b/src/component-library/Pages/DID/PageDID.tsx @@ -19,7 +19,7 @@ import { PageDIDRules } from "./PageDIDRules"; import { PageDIDByType } from "./PageDIDByType"; import { PageDIDDatasetReplicas } from "./PageDIDDatasetReplicas"; import { UseComDOM } from "@/lib/infrastructure/hooks/useComDOM"; -import { DIDDatasetReplicasViewModel, DIDKeyValuePairsDataViewModel, DIDMetaViewModel, DIDRulesViewModel, DIDViewModel, FilereplicaStateDViewModel, FilereplicaStateViewModel } from "@/lib/infrastructure/data/view-model/did"; +import { DIDDatasetReplicasViewModel, DIDKeyValuePairsDataViewModel, DIDMetaViewModel, DIDRulesViewModel, DIDViewModel, FilereplicaStateDViewModel, FileReplicaStateViewModel } from "@/lib/infrastructure/data/view-model/did"; import { HTTPRequest } from "@/lib/sdk/http"; export interface PageDIDPageProps { @@ -30,7 +30,7 @@ export interface PageDIDPageProps { // Metadata [BOTH] didKeyValuePairsData: DIDKeyValuePairsDataViewModel // File Replica States [FILE] - didFileReplicasComDOM: UseComDOM + didFileReplicasComDOM: UseComDOM // File Replica States [DATASET] simply uses Contents ComDOM // But we supply an onchange function that is called when the contents comdom is selected didFileReplicasDOnChange: (scope: string, name: string) => void // This function changes the file replicas comdom's request to the selected file diff --git a/src/component-library/Pages/DID/PageDIDFileReplicas.tsx b/src/component-library/Pages/DID/PageDIDFileReplicas.tsx index f5d49e331..dbd72b2ea 100644 --- a/src/component-library/Pages/DID/PageDIDFileReplicas.tsx +++ b/src/component-library/Pages/DID/PageDIDFileReplicas.tsx @@ -13,17 +13,17 @@ import { StreamedTable } from "../../StreamedTables/StreamedTable"; import { TableFilterString } from "../../StreamedTables/TableFilterString"; import { UseComDOM } from "@/lib/infrastructure/hooks/useComDOM"; import { TableInternalLink } from "../../StreamedTables/TableInternalLink"; -import { FilereplicaStateViewModel } from "@/lib/infrastructure/data/view-model/did"; +import { FileReplicaStateViewModel } from "@/lib/infrastructure/data/view-model/did"; import { TableStyling } from "@/component-library/StreamedTables/types"; export const PageDIDFilereplicas = ( props: { - comdom: UseComDOM, + comdom: UseComDOM, tablestyling?: TableStyling, } ) => { - const columnHelper = createColumnHelper() + const columnHelper = createColumnHelper() const tablecolumns: any[] = [ columnHelper.accessor("rse", { id: "rse", @@ -70,7 +70,7 @@ export const PageDIDFilereplicas = ( }) ] return ( - + tablecomdom={props.comdom} tablecolumns={tablecolumns} tablestyling={props.tablestyling ?? {}} diff --git a/src/component-library/Pages/DID/PageDIDFileReplicasD.tsx b/src/component-library/Pages/DID/PageDIDFileReplicasD.tsx index 40b9293f3..adb68cd10 100644 --- a/src/component-library/Pages/DID/PageDIDFileReplicasD.tsx +++ b/src/component-library/Pages/DID/PageDIDFileReplicasD.tsx @@ -10,7 +10,7 @@ import { twMerge } from "tailwind-merge" import { StreamedTable } from "../../StreamedTables/StreamedTable"; import { TableFilterString } from "../../StreamedTables/TableFilterString"; import { UseComDOM } from "@/lib/infrastructure/hooks/useComDOM"; -import { DIDViewModel, FilereplicaStateViewModel } from "@/lib/infrastructure/data/view-model/did"; +import { DIDViewModel, FileReplicaStateViewModel } from "@/lib/infrastructure/data/view-model/did"; import { TableInternalLink } from "@/component-library/StreamedTables/TableInternalLink"; @@ -18,7 +18,7 @@ import { TableInternalLink } from "@/component-library/StreamedTables/TableInter export const PageDIDFilereplicasD = ( props: { datasetComDOM: UseComDOM, // the files in the dataset - replicaComDOM: UseComDOM, // replicas of the selected file + replicaComDOM: UseComDOM, // replicas of the selected file onChangeFileSelection: (scope: string, name: string) => void, } ) => { diff --git a/src/component-library/Pages/RSE/ListRSE.stories.tsx b/src/component-library/Pages/RSE/ListRSE.stories.tsx index cefbb499f..901774d58 100644 --- a/src/component-library/Pages/RSE/ListRSE.stories.tsx +++ b/src/component-library/Pages/RSE/ListRSE.stories.tsx @@ -1,5 +1,5 @@ import { StoryFn, Meta } from "@storybook/react"; -import { mockUseComDOM, fixtureRSEViewModel } from "test/fixtures/table-fixtures"; +import {fixtureRSEViewModel, mockUseChunkedStream} from "test/fixtures/table-fixtures"; import { ListRSE as L } from "./ListRSE"; export default { @@ -7,10 +7,9 @@ export default { component: L, } as Meta; -const Template: StoryFn = (args) => ; +const Template: StoryFn = (args) =>
; export const ListRSE = Template.bind({}); ListRSE.args = { - comdom: mockUseComDOM(Array.from({ length: 100 }, () => fixtureRSEViewModel())), - setRSEQuery: (rseExpression: string) => { }, + streamingHook: mockUseChunkedStream(Array.from({ length: 100 }, () => fixtureRSEViewModel())), }; diff --git a/src/component-library/Pages/RSE/ListRSE.tsx b/src/component-library/Pages/RSE/ListRSE.tsx index 080c93378..cf597d1d6 100644 --- a/src/component-library/Pages/RSE/ListRSE.tsx +++ b/src/component-library/Pages/RSE/ListRSE.tsx @@ -1,136 +1,64 @@ -import { twMerge } from "tailwind-merge"; -import { UseComDOM } from "@/lib/infrastructure/hooks/useComDOM"; -import { RSEType } from "@/lib/core/entity/rucio"; -import { StreamedTable } from "../../StreamedTables/StreamedTable"; -import { createColumnHelper } from "@tanstack/react-table"; -import { TableFilterString } from "../../StreamedTables/TableFilterString"; -import { TableFilterDiscrete } from "../../StreamedTables/TableFilterDiscrete"; -import { BoolTag } from "../../Tags/BoolTag"; -import { HiDotsHorizontal } from "react-icons/hi"; -import { RSETypeTag } from "../../Tags/RSETypeTag"; -import { TableFilterBoolean } from "../../StreamedTables/TableFilterBoolean"; -import { TableInternalLink } from "../../StreamedTables/TableInternalLink"; -import useReponsiveHook from "../../Helpers/ResponsiveHook"; -import { Body } from "../Helpers/Body"; -import { Heading } from "../Helpers/Heading"; -import { RSEViewModel } from "@/lib/infrastructure/data/view-model/rse"; -import { TextInput } from "@/component-library/Input/TextInput"; -import { useState } from "react"; -import { Button } from "@/component-library/Button/Button"; +import {twMerge} from "tailwind-merge"; +import {Heading} from "../Helpers/Heading"; +import {RSEViewModel} from "@/lib/infrastructure/data/view-model/rse"; +import {TextInput} from "@/component-library/Input/TextInput"; +import {useEffect, useRef, useState} from "react"; +import {Button} from "@/component-library/Button/Button"; import {useSearchParams} from "next/navigation"; +import {StreamingStatus, UseChunkedStream} from "@/lib/infrastructure/hooks/useChunkedStream"; +import {AgGridReact} from "ag-grid-react"; +import {ListRSETable} from "@/component-library/Pages/RSE/ListRSETable"; -const defaultRSEQuery = "*"; +type ListRSEProps = { + streamingHook: UseChunkedStream +} -export const ListRSE = ( - props: { - comdom: UseComDOM - setRSEQuery: (rseExpression: string) => void - } -) => { +const defaultExpression = "*"; +export const ListRSE = (props: ListRSEProps) => { const searchParams = useSearchParams() - const expression = searchParams?.get('expression') + const firstExpression = searchParams?.get('expression') + const [expression, setExpression] = useState(firstExpression ?? defaultExpression); + + const tableRef = useRef(null); - const [rseSearchQuery, setRSESearchQuery] = useState(expression ?? defaultRSEQuery) - const setInputAsQuery = (searchPattern: string) => { - setRSESearchQuery(searchPattern !== '' ? searchPattern : defaultRSEQuery) + const onData = (data: RSEViewModel[]) => { + console.log(data); + tableRef.current?.api.applyTransactionAsync({add: data}); } - const columnHelper = createColumnHelper() - const tablecolumns = [ - columnHelper.accessor("name", { - id: "name", - header: info => { - return ( - - ) - }, - cell: info => { - return ( - - {info.getValue()} - - ) - } - }), - columnHelper.accessor("rse_type", { - id: "rse_type", - header: info => { - return ( - - name="RSE Type" - keys={Object.values(RSEType)} - renderFunc={key => key === undefined ? : } - column={info.column} - stack - /> - ) - }, - cell: info => , - meta: { - style: "w-8 md:w-32" - } - }), - columnHelper.accessor("volatile", { - id: "volatile", - cell: info => , - header: info => { - return ( - - ) - }, - meta: { - style: "w-36" - } - }), - columnHelper.accessor("deterministic", { - id: "deterministic", - cell: info => , - header: info => { - return ( - - ) - }, - meta: { - style: "w-36" - } - }), - columnHelper.accessor("staging_area", { - id: "staging_area", - cell: info => , - header: info => { - return ( - - ) - }, - meta: { - style: "w-36" - } - }) - ] + const startStreaming = () => { + if (tableRef.current?.api) { + const api = tableRef.current!.api; + api.setGridOption('rowData', []); + } + + const url = `/api/feature/list-rses?rseExpression=${expression ?? defaultExpression}`; + props.streamingHook.start({url, onData}); + }; + + const onGridReady = () => { + if (expression === null) return; - const responsive = useReponsiveHook() + startStreaming(); + } + + const updateExpression = (value: string) => { + setExpression(value !== '' ? value : defaultExpression); + } + + const onSearch = (event: any) => { + event.preventDefault(); + if (props.streamingHook.status !== StreamingStatus.RUNNING) { + startStreaming(); + } else { + // TODO: display an error message (toast?) if there's streaming already + } + } return (
{ setInputAsQuery(event.target.value) }} - onEnterkey={(e) => { - e.preventDefault() - setInputAsQuery(e.target.value) - props.setRSEQuery(rseSearchQuery) - props.comdom.start() + onEnterkey={onSearch} + onChange={(e) => { + updateExpression(e.target.value); }} id="rse-search-pattern" - defaultValue={expression ?? ''} - placeholder={defaultRSEQuery} - /> -
); }; diff --git a/src/component-library/Pages/RSE/ListRSETable.tsx b/src/component-library/Pages/RSE/ListRSETable.tsx new file mode 100644 index 000000000..6dceba86c --- /dev/null +++ b/src/component-library/Pages/RSE/ListRSETable.tsx @@ -0,0 +1,102 @@ +import React, {RefObject, useState} from "react"; +import {AgGridReact} from "ag-grid-react"; +import {UseChunkedStream} from "@/lib/infrastructure/hooks/useChunkedStream"; +import {RSEViewModel} from "@/lib/infrastructure/data/view-model/rse"; +import {StreamedTable} from "@/component-library/Table/StreamedTable"; +import {ClickableCell} from "@/component-library/Table/Cells/ClickableCell"; +import {BadgeCell, badgeCellWrapperStyle} from "@/component-library/Table/Cells/BadgeCell"; +import {CheckboxCell, checkboxCellWrapperStyle} from "@/component-library/Table/Cells/CheckboxCell"; +import {DefaultTextFilterParams} from "@/component-library/Table/FilterParameters/DefaultTextFilterParams"; +import {DefaultBooleanFilterParams} from "@/component-library/Table/FilterParameters/DefaultBooleanFilterParams"; +import {buildDiscreteFilterParams} from "@/component-library/Table/FilterParameters/buildDiscreteFilterParams"; +import {GridReadyEvent} from "ag-grid-community"; + +type ListRSETableProps = { + tableRef: RefObject + streamingHook: UseChunkedStream + onGridReady: (event: GridReadyEvent) => void +} + +const ClickableName = (props: { value: string }) => { + return + {props.value} + +}; + +const typeColorClasses: Record = { + 'DISK': 'bg-base-info-500', + 'TAPE': 'bg-extra-rose-500', + 'UNKNOWN': 'bg-base-warning-400', +} + +const TypeBadge = (props: { value: string }) => { + return +} + +export const ListRSETable = (props: ListRSETableProps) => { + const [columnDefs] = useState([ + { + headerName: 'Name', + field: 'name', + flex: 4, + minWidth: 250, + cellRenderer: ClickableName, + filter: true, + filterParams: DefaultTextFilterParams, + }, + { + headerName: 'Type', + field: 'rse_type', + flex: 1, + minWidth: 125, + maxWidth: 200, + cellStyle: badgeCellWrapperStyle, + cellRenderer: TypeBadge, + filter: true, + sortable: false, + filterParams: buildDiscreteFilterParams([ + 'DISK', + 'TAPE', + 'UNKNOWN' + ]) + }, + { + headerName: 'Volatile', + field: 'volatile', + flex: 1, + maxWidth: 175, + minWidth: 125, + cellStyle: checkboxCellWrapperStyle, + cellRenderer: CheckboxCell, + sortable: false, + filter: true, + filterParams: DefaultBooleanFilterParams + }, + { + headerName: 'Deterministic', + field: 'deterministic', + flex: 1, + maxWidth: 200, + minWidth: 175, + cellStyle: checkboxCellWrapperStyle, + cellRenderer: CheckboxCell, + sortable: false, + filter: true, + filterParams: DefaultBooleanFilterParams, + }, + { + headerName: 'Staging', + field: 'staging_area', + flex: 1, + maxWidth: 175, + minWidth: 125, + cellStyle: checkboxCellWrapperStyle, + cellRenderer: CheckboxCell, + sortable: false, + filter: true, + filterParams: DefaultBooleanFilterParams + }, + ]); + + return +} \ No newline at end of file diff --git a/src/component-library/Pages/Rule/ListRule.tsx b/src/component-library/Pages/Rule/ListRule.tsx index b0411a706..d94698f0e 100644 --- a/src/component-library/Pages/Rule/ListRule.tsx +++ b/src/component-library/Pages/Rule/ListRule.tsx @@ -1,26 +1,26 @@ -import { twMerge } from "tailwind-merge"; -import { UseComDOM } from "@/lib/infrastructure/hooks/useComDOM"; -import { Rule, RuleState } from "@/lib/core/entity/rucio"; -import { StreamedTable } from "../../StreamedTables/StreamedTable"; -import { Button } from "../../Button/Button"; -import { createColumnHelper } from "@tanstack/react-table"; -import { TableFilterString } from "../../StreamedTables/TableFilterString"; -import { TableInternalLink } from "../../StreamedTables/TableInternalLink"; -import { P } from "../../Text/Content/P"; -import { DateTag } from "../../Tags/DateTag"; -import { TableSortUpDown } from "../../StreamedTables/TableSortUpDown"; -import { RuleStateTag } from "../../Tags/RuleStateTag"; -import { TableFilterDiscrete } from "../../StreamedTables/TableFilterDiscrete"; -import { HiDotsHorizontal } from "react-icons/hi"; -import { TextInput } from "../../Input/TextInput"; -import { Contenttd, Generaltable, Titleth } from "../../Helpers/Metatable"; -import { Dropdown } from "../../Input/Dropdown"; -import { DateInput } from "../../Input/DateInput"; -import { useState } from "react"; -import { Heading } from "../Helpers/Heading"; -import { Body } from "../Helpers/Body"; -import { RuleViewModel } from "@/lib/infrastructure/data/view-model/rule"; -import { HTTPRequest } from "@/lib/sdk/http"; +import {twMerge} from "tailwind-merge"; +import {UseComDOM} from "@/lib/infrastructure/hooks/useComDOM"; +import {Rule, RuleState} from "@/lib/core/entity/rucio"; +import {StreamedTable} from "../../StreamedTables/StreamedTable"; +import {Button} from "../../Button/Button"; +import {createColumnHelper} from "@tanstack/react-table"; +import {TableFilterString} from "../../StreamedTables/TableFilterString"; +import {TableInternalLink} from "../../StreamedTables/TableInternalLink"; +import {P} from "../../Text/Content/P"; +import {DateTag} from "../../Tags/DateTag"; +import {TableSortUpDown} from "../../StreamedTables/TableSortUpDown"; +import {RuleStateTag} from "../../Tags/RuleStateTag"; +import {TableFilterDiscrete} from "../../StreamedTables/TableFilterDiscrete"; +import {HiDotsHorizontal} from "react-icons/hi"; +import {TextInput} from "../../Input/TextInput"; +import {Contenttd, Generaltable, Titleth} from "../../Helpers/Metatable"; +import {Dropdown} from "../../Input/Dropdown"; +import {DateInput} from "../../Input/DateInput"; +import {useState} from "react"; +import {Heading} from "../Helpers/Heading"; +import {Body} from "../Helpers/Body"; +import {RuleViewModel} from "@/lib/infrastructure/data/view-model/rule"; +import {HTTPRequest} from "@/lib/sdk/http"; type ListRuleUserDefineQuery = Partial<{ account: string @@ -89,7 +89,8 @@ export const ListRule = ( }), columnHelper.accessor("created_at", { id: "created_at", - cell: info => , + cell: info => , header: info => { return ( , + cell: info => , header: info => { return ( column={info.column} name="State" keys={Object.values(RuleState)} - renderFunc={key => key === undefined ? : } + renderFunc={key => key === undefined ? + : + } stack /> ) @@ -148,7 +151,7 @@ export const ListRule = ( column={info.column} name="Locks OK Count" className="ml-1 dark:text-text-0 text-text-1000" - element={} + element={} stack /> ) @@ -166,7 +169,7 @@ export const ListRule = ( column={info.column} name="Locks Replicating Count" className="ml-1" - element={} + element={} stack /> ) @@ -184,7 +187,7 @@ export const ListRule = ( column={info.column} name="Locks Stuck Count" className="ml-1" - element={} + element={} stack /> ) @@ -246,7 +249,10 @@ export const ListRule = ( Account setUserdefinequery({ ...userdefinequery, account: e.target.value })} + onChange={e => setUserdefinequery({ + ...userdefinequery, + account: e.target.value + })} /> @@ -254,7 +260,10 @@ export const ListRule = ( RSE Expression setUserdefinequery({ ...userdefinequery, rse_expression: e.target.value })} + onChange={e => setUserdefinequery({ + ...userdefinequery, + rse_expression: e.target.value + })} /> @@ -262,7 +271,10 @@ export const ListRule = ( Activity setUserdefinequery({ ...userdefinequery, activity: e.target.value })} + onChange={e => setUserdefinequery({ + ...userdefinequery, + activity: e.target.value + })} /> @@ -272,9 +284,11 @@ export const ListRule = ( keys={Object.values(RuleState)} renderFunc={key => key ? - : UNDEFINED + : UNDEFINED } - handleChange={key => { setUserdefinequery({ ...userdefinequery, state: key }) }} + handleChange={key => { + setUserdefinequery({...userdefinequery, state: key}) + }} /> @@ -290,16 +304,22 @@ export const ListRule = ( )} >
- + { setUserdefinequery({ ...userdefinequery, from_date: date }) }} + onchange={date => { + setUserdefinequery({...userdefinequery, from_date: date}) + }} id="from-date" />
- + { setUserdefinequery({ ...userdefinequery, to_date: date }) }} + onchange={date => { + setUserdefinequery({...userdefinequery, to_date: date}) + }} id="to-date" />
@@ -311,7 +331,11 @@ export const ListRule = ( + + + Page 0 of 0 + + + +
+
+}; \ No newline at end of file diff --git a/src/component-library/Table/RegularTable.tsx b/src/component-library/Table/RegularTable.tsx new file mode 100644 index 000000000..2e8e25ea1 --- /dev/null +++ b/src/component-library/Table/RegularTable.tsx @@ -0,0 +1,150 @@ +import React, {RefObject, useEffect, useRef, useState} from "react"; +import {twMerge} from "tailwind-merge"; +import {Skeleton} from "@/component-library/ui/skeleton"; +import {AgGridReact} from "ag-grid-react"; +import {ColDef, ColGroupDef} from "ag-grid-community/dist/types/core/entities/colDef"; +import {NoDataYetOverlay} from "@/component-library/Table/Overlays/NoDataYetOverlay"; +import {GridReadyEvent, SelectionChangedEvent} from "ag-grid-community"; +import {SimplePaginationPanel} from "@/component-library/Table/PaginationPanels/SimplePaginationPanel"; +import useDarkMode from "@/lib/infrastructure/hooks/useDarkMode"; +import '@/component-library/ag-grid-theme-rucio-dark.css'; +import '@/component-library/ag-grid-theme-rucio-light.css'; + +export interface RegularTableProps { + tableRef: RefObject, + columnDefs: (ColDef | ColGroupDef)[], + noRowsOverlayComponent?: any, + rowSelection?: 'single' | 'multiple', + onSelectionChanged?: (event: SelectionChangedEvent) => void, + onGridReady?: (event: GridReadyEvent) => void, +} + +export const RegularTable = (props: RegularTableProps) => { + // Refs for controlling the pagination panel + const currentPageRef = useRef(null); + const totalPagesRef = useRef(null); + const previousPageRef = useRef(null); + const nextPageRef = useRef(null); + const firstPageRef = useRef(null); + const lastPageRef = useRef(null); + const containerRef = useRef(null); + + const onNextPage = () => { + const gridApi = props.tableRef.current!.api; + if (gridApi) { + gridApi.paginationGoToNextPage(); + } + } + + const onPreviousPage = () => { + const gridApi = props.tableRef.current!.api; + if (gridApi) { + gridApi.paginationGoToPreviousPage(); + } + } + + const onFirstPage = () => { + const gridApi = props.tableRef.current!.api; + if (gridApi) { + gridApi.paginationGoToFirstPage(); + } + }; + + const onLastPage = () => { + const gridApi = props.tableRef.current!.api; + if (gridApi) { + gridApi.paginationGoToLastPage(); + } + }; + + const onPaginationChanged = () => { + const gridApi = props.tableRef.current!.api; + // Make sure the table is loaded before updating the pagination component to avoid flickering + if (isTableLoaded && gridApi) { + const totalPages = gridApi.paginationGetTotalPages(); + totalPagesRef.current!.textContent = totalPages.toString(); + // Ensure visibility of the pagination panel only after some data is loaded + containerRef.current!.style.visibility = totalPages === 0 ? 'hidden' : 'visible'; + + // Pages are zero based, hence the +1 + const currentPage = gridApi.paginationGetCurrentPage() + 1; + currentPageRef.current!.textContent = currentPage.toString(); + + previousPageRef.current!.disabled = currentPage === 1; + firstPageRef.current!.disabled = currentPage === 1; + previousPageRef.current!.onclick = onPreviousPage; + firstPageRef.current!.onclick = onFirstPage; + + nextPageRef.current!.disabled = currentPage === totalPages; + lastPageRef.current!.disabled = currentPage === totalPages; + nextPageRef.current!.onclick = onNextPage; + lastPageRef.current!.onclick = onLastPage; + } + }; + + // Whether the table component is ready to be displayed + const [isTableLoaded, setIsTableLoaded] = useState(false); + + const onGridReady = (event: GridReadyEvent) => { + setIsTableLoaded(true); + event.api.sizeColumnsToFit(); // Ensures columns stretch to fit grid width + + if (props.onGridReady) { + props.onGridReady(event); + } + } + + // Resize the columns to fit the grid on changing the window dimensions + useEffect(() => { + const handleResize = () => { + if (props.tableRef.current?.api) { + props.tableRef.current!.api.sizeColumnsToFit(); + } + }; + + window.addEventListener('resize', handleResize); + + return () => { + window.removeEventListener('resize', handleResize); + }; + }, [props.tableRef]); + + const isDarkMode = useDarkMode(); + + /* loadingOverlayComponent is shown when the loading hasn't begun yet, + whereas noRowsOverlayComponent is shown when the loading has started without data transactions */ + return <> +
+ {!isTableLoaded && } + +
+ + +} \ No newline at end of file diff --git a/src/component-library/Table/StreamedTable.tsx b/src/component-library/Table/StreamedTable.tsx new file mode 100644 index 000000000..fb25aefb5 --- /dev/null +++ b/src/component-library/Table/StreamedTable.tsx @@ -0,0 +1,28 @@ +import React, {useEffect} from "react"; +import {RegularTable, RegularTableProps} from "@/component-library/Table/RegularTable"; +import {UseChunkedStream} from "@/lib/infrastructure/hooks/useChunkedStream"; +import {NoLoadedRowsOverlay} from "@/component-library/Table/Overlays/NoLoadedRowsOverlay"; + +export interface StreamedTableProps extends RegularTableProps { + streamingHook: UseChunkedStream +} + +export const StreamedTable = (props: StreamedTableProps) => { + // Ensure the overlay updates when streaming faces an error + useEffect(() => { + if (props.tableRef.current?.api) { + props.tableRef.current!.api.showNoRowsOverlay(); + } + }, [props.streamingHook.error]); + + const { noRowsOverlayComponent, ...otherProps } = props; + + const getDefaultNoRowsElement = (gridProps: any) => { + return + } + + return +} \ No newline at end of file diff --git a/src/component-library/ag-grid-theme-rucio-dark.css b/src/component-library/ag-grid-theme-rucio-dark.css new file mode 100644 index 000000000..04325f579 --- /dev/null +++ b/src/component-library/ag-grid-theme-rucio-dark.css @@ -0,0 +1,17 @@ +/* + * This file is a theme downloaded from the AG Grid Theme Builder for AG Grid 32.1.0. + * + * See installation docs at https://www.ag-grid.com/javascript-data-grid/applying-theme-builder-styling-grid/ + */ + +@import url('https://fonts.googleapis.com/css2?family=IBM%20Plex%20Sans:wght@400;500&display=swap'); +@import url('ag-grid-theme-rucio.css'); + +.ag-grid-theme-rucio-dark { + --ag-background-color: var(--ag-inherited-background-color, #1E293B); + --ag-foreground-color: var(--ag-inherited-foreground-color, #F1F5F9); + --ag-text-color: var(--ag-inherited-text-color, var(--ag-foreground-color)); + --ag-header-background-color: var(--ag-inherited-header-background-color, #334155); + --ag-header-text-color: var(--ag-inherited-header-text-color, --ag-foreground-color); + --ag-color-scheme: var(--ag-inherited-color-scheme, dark); +} \ No newline at end of file diff --git a/src/component-library/ag-grid-theme-rucio-light.css b/src/component-library/ag-grid-theme-rucio-light.css new file mode 100644 index 000000000..207150487 --- /dev/null +++ b/src/component-library/ag-grid-theme-rucio-light.css @@ -0,0 +1,17 @@ +/* + * This file is a theme downloaded from the AG Grid Theme Builder for AG Grid 32.1.0. + * + * See installation docs at https://www.ag-grid.com/javascript-data-grid/applying-theme-builder-styling-grid/ + */ + +@import url('https://fonts.googleapis.com/css2?family=IBM%20Plex%20Sans:wght@400;500&display=swap'); +@import url('ag-grid-theme-rucio.css'); + +.ag-grid-theme-rucio-light { + --ag-background-color: var(--ag-inherited-background-color, #ffffff); + --ag-foreground-color: var(--ag-inherited-foreground-color, #0f172a); + --ag-text-color: var(--ag-inherited-text-color, var(--ag-foreground-color)); + --ag-header-background-color: var(--ag-inherited-header-background-color, #e2e8f0); + --ag-header-text-color: var(--ag-inherited-header-text-color, #334155); + --ag-color-scheme: var(--ag-inherited-color-scheme, light); +} \ No newline at end of file diff --git a/src/component-library/ag-grid-theme-rucio.css b/src/component-library/ag-grid-theme-rucio.css new file mode 100644 index 000000000..5c32ca0bd --- /dev/null +++ b/src/component-library/ag-grid-theme-rucio.css @@ -0,0 +1,408 @@ +/* + * This file is a theme downloaded from the AG Grid Theme Builder for AG Grid 32.1.0. + * + * See installation docs at https://www.ag-grid.com/javascript-data-grid/applying-theme-builder-styling-grid/ + */ + +@import url('https://fonts.googleapis.com/css2?family=IBM%20Plex%20Sans:wght@400;500&display=swap'); + +.ag-root-wrapper { + border-bottom-left-radius: 0!important; + border-bottom-right-radius: 0!important; + border-bottom: none!important; +} + +:where(.ag-root-wrapper, .ag-measurement-container, .ag-apply-theme-variables, .ag-popup) { + --ag-background-color: var(--ag-inherited-background-color, #1E293B); + --ag-foreground-color: var(--ag-inherited-foreground-color, #F1F5F9); + --ag-text-color: var(--ag-inherited-text-color, var(--ag-foreground-color)); + --ag-accent-color: var(--ag-inherited-accent-color, #8B5CF6); + --ag-invalid-color: var(--ag-inherited-invalid-color, #e02525); + --ag-border-color: var(--ag-inherited-border-color, color-mix(in srgb, transparent, var(--ag-foreground-color) 15%)); + --ag-wrapper-border: var(--ag-inherited-wrapper-border, solid 1px var(--ag-border-color)); + --ag-row-border: var(--ag-inherited-row-border, solid 1px var(--ag-border-color)); + --ag-color-scheme: var(--ag-inherited-color-scheme, dark); + --ag-header-row-border: var(--ag-inherited-header-row-border, var(--ag-row-border)); + --ag-footer-row-border: var(--ag-inherited-footer-row-border, var(--ag-row-border)); + --ag-column-border: var(--ag-inherited-column-border, solid 1px transparent); + --ag-header-column-border: var(--ag-inherited-header-column-border, none); + --ag-header-column-border-height: var(--ag-inherited-header-column-border-height, 100%); + --ag-pinned-column-border: var(--ag-inherited-pinned-column-border, solid 1px var(--ag-border-color)); + --ag-pinned-row-border: var(--ag-inherited-pinned-row-border, solid 1px var(--ag-border-color)); + --ag-side-panel-border: var(--ag-inherited-side-panel-border, solid 1px var(--ag-border-color)); + --ag-font-family: var(--ag-inherited-font-family, 'monospace'); + --ag-chrome-background-color: var(--ag-inherited-chrome-background-color, color-mix(in srgb, var(--ag-background-color), var(--ag-foreground-color) 7%)); + --ag-header-background-color: var(--ag-inherited-header-background-color, #334155); + --ag-header-font-family: var(--ag-inherited-header-font-family, var(--ag-font-family)); + --ag-header-font-weight: var(--ag-inherited-header-font-weight, 500); + --ag-header-font-size: var(--ag-inherited-header-font-size, 15px); + --ag-header-text-color: var(--ag-inherited-header-text-color, #FFFFFF); + --ag-header-cell-hover-background-color: var(--ag-inherited-header-cell-hover-background-color, transparent); + --ag-header-cell-hover-background-transition-duration: var(--ag-inherited-header-cell-hover-background-transition-duration, 0.2s); + --ag-cell-text-color: var(--ag-inherited-cell-text-color, var(--ag-text-color)); + --ag-subtle-text-color: var(--ag-inherited-subtle-text-color, color-mix(in srgb, transparent, var(--ag-text-color) 40%)); + --ag-range-selection-border-style: var(--ag-inherited-range-selection-border-style, solid); + --ag-range-selection-border-color: var(--ag-inherited-range-selection-border-color, var(--ag-accent-color)); + --ag-range-selection-background-color: var(--ag-inherited-range-selection-background-color, color-mix(in srgb, transparent, var(--ag-accent-color) 50%)); + --ag-range-selection-chart-background-color: var(--ag-inherited-range-selection-chart-background-color, #0058FF1A); + --ag-range-selection-chart-category-background-color: var(--ag-inherited-range-selection-chart-category-background-color, #00FF841A); + --ag-range-selection-highlight-color: var(--ag-inherited-range-selection-highlight-color, color-mix(in srgb, transparent, var(--ag-accent-color) 50%)); + --ag-row-hover-color: var(--ag-inherited-row-hover-color, color-mix(in srgb, transparent, var(--ag-accent-color) 12%)); + --ag-column-hover-color: var(--ag-inherited-column-hover-color, color-mix(in srgb, transparent, var(--ag-accent-color) 5%)); + --ag-selected-row-background-color: var(--ag-inherited-selected-row-background-color, color-mix(in srgb, transparent, var(--ag-accent-color) 40%)); + --ag-modal-overlay-background-color: var(--ag-inherited-modal-overlay-background-color, color-mix(in srgb, transparent, var(--ag-background-color) 66%)); + --ag-odd-row-background-color: var(--ag-inherited-odd-row-background-color, var(--ag-background-color)); + --ag-border-radius: var(--ag-inherited-border-radius, 4px); + --ag-wrapper-border-radius: var(--ag-inherited-wrapper-border-radius, 8px); + --ag-cell-horizontal-padding: var(--ag-inherited-cell-horizontal-padding, calc(var(--ag-grid-size) * 2 * var(--ag-cell-horizontal-padding-scale))); + --ag-cell-widget-spacing: var(--ag-inherited-cell-widget-spacing, calc(var(--ag-grid-size) * 1.5)); + --ag-cell-horizontal-padding-scale: var(--ag-inherited-cell-horizontal-padding-scale, 1); + --ag-row-group-indent-size: var(--ag-inherited-row-group-indent-size, calc(var(--ag-cell-widget-spacing) + var(--ag-icon-size))); + --ag-value-change-delta-up-color: var(--ag-inherited-value-change-delta-up-color, #43a047); + --ag-value-change-delta-down-color: var(--ag-inherited-value-change-delta-down-color, #e53935); + --ag-value-change-value-highlight-background-color: var(--ag-inherited-value-change-value-highlight-background-color, #16a08580); + --ag-grid-size: var(--ag-inherited-grid-size, 8px); + --ag-font-size: var(--ag-inherited-font-size, 16px); + --ag-row-height: var(--ag-inherited-row-height, calc(max(var(--ag-icon-size), var(--ag-font-size)) + var(--ag-grid-size) * 3.5 * var(--ag-row-vertical-padding-scale))); + --ag-row-vertical-padding-scale: var(--ag-inherited-row-vertical-padding-scale, 1); + --ag-header-height: var(--ag-inherited-header-height, calc(max(var(--ag-icon-size), var(--ag-font-size)) + var(--ag-grid-size) * 4.25 * var(--ag-header-vertical-padding-scale))); + --ag-header-vertical-padding-scale: var(--ag-inherited-header-vertical-padding-scale, 1); + --ag-popup-shadow: var(--ag-inherited-popup-shadow, 0 0 16px 0 #00000026); + --ag-dropdown-shadow: var(--ag-inherited-dropdown-shadow, 0 1px 4px 1px #babfc766); + --ag-drag-ghost-background-color: var(--ag-inherited-drag-ghost-background-color, var(--ag-background-color)); + --ag-drag-ghost-border: var(--ag-inherited-drag-ghost-border, solid 1px var(--ag-border-color)); + --ag-drag-ghost-shadow: var(--ag-inherited-drag-ghost-shadow, var(--ag-popup-shadow)); + --ag-focus-shadow: var(--ag-inherited-focus-shadow, 0 0 0 3px color-mix(in srgb, transparent, var(--ag-accent-color) 50%)); + --ag-side-bar-panel-width: var(--ag-inherited-side-bar-panel-width, 250px); + --ag-side-button-selected-border: var(--ag-inherited-side-button-selected-border, solid 1px var(--ag-border-color)); + --ag-side-button-selected-background-color: var(--ag-inherited-side-button-selected-background-color, var(--ag-background-color)); + --ag-side-bar-background-color: var(--ag-inherited-side-bar-background-color, var(--ag-chrome-background-color)); + --ag-header-column-resize-handle-display: var(--ag-inherited-header-column-resize-handle-display, block); + --ag-header-column-resize-handle-height: var(--ag-inherited-header-column-resize-handle-height, 30%); + --ag-header-column-resize-handle-width: var(--ag-inherited-header-column-resize-handle-width, 2px); + --ag-header-column-resize-handle-color: var(--ag-inherited-header-column-resize-handle-color, var(--ag-border-color)); + --ag-widget-container-horizontal-padding: var(--ag-inherited-widget-container-horizontal-padding, calc(var(--ag-grid-size) * 1.5)); + --ag-widget-container-vertical-padding: var(--ag-inherited-widget-container-vertical-padding, calc(var(--ag-grid-size) * 1.5)); + --ag-widget-horizontal-spacing: var(--ag-inherited-widget-horizontal-spacing, calc(var(--ag-grid-size) * 1.5)); + --ag-widget-vertical-spacing: var(--ag-inherited-widget-vertical-spacing, var(--ag-grid-size)); + --ag-list-item-height: var(--ag-inherited-list-item-height, calc(var(--ag-icon-size) + var(--ag-widget-vertical-spacing))); + --ag-icon-size: var(--ag-inherited-icon-size, 16px); + --ag-toggle-button-width: var(--ag-inherited-toggle-button-width, 28px); + --ag-toggle-button-height: var(--ag-inherited-toggle-button-height, 18px); + --ag-toggle-button-border-width: var(--ag-inherited-toggle-button-border-width, 2px); + --ag-toggle-button-on-border-color: var(--ag-inherited-toggle-button-on-border-color, var(--ag-accent-color)); + --ag-toggle-button-on-background-color: var(--ag-inherited-toggle-button-on-background-color, var(--ag-accent-color)); + --ag-toggle-button-off-border-color: var(--ag-inherited-toggle-button-off-border-color, color-mix(in srgb, var(--ag-background-color), var(--ag-foreground-color) 30%)); + --ag-toggle-button-off-background-color: var(--ag-inherited-toggle-button-off-background-color, color-mix(in srgb, var(--ag-background-color), var(--ag-foreground-color) 30%)); + --ag-toggle-button-switch-border-color: var(--ag-inherited-toggle-button-switch-border-color, var(--ag-toggle-button-off-border-color)); + --ag-toggle-button-switch-background-color: var(--ag-inherited-toggle-button-switch-background-color, var(--ag-background-color)); + --ag-checkbox-border-width: var(--ag-inherited-checkbox-border-width, 1px); + --ag-checkbox-border-radius: var(--ag-inherited-checkbox-border-radius, var(--ag-border-radius)); + --ag-checkbox-unchecked-background-color: var(--ag-inherited-checkbox-unchecked-background-color, var(--ag-background-color)); + --ag-checkbox-unchecked-border-color: var(--ag-inherited-checkbox-unchecked-border-color, color-mix(in srgb, var(--ag-background-color), var(--ag-foreground-color) 30%)); + --ag-checkbox-checked-background-color: var(--ag-inherited-checkbox-checked-background-color, var(--ag-accent-color)); + --ag-checkbox-checked-border-color: var(--ag-inherited-checkbox-checked-border-color, var(--ag-accent-color)); + --ag-checkbox-checked-shape-image: var(--ag-inherited-checkbox-checked-shape-image, url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2210%22%20height%3D%227%22%20fill%3D%22none%22%3E%3Cpath%20stroke%3D%22%23000%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke-width%3D%221.75%22%20d%3D%22M1%203.5%203.5%206l5-5%22%2F%3E%3C%2Fsvg%3E')); + --ag-checkbox-checked-shape-color: var(--ag-inherited-checkbox-checked-shape-color, var(--ag-background-color)); + --ag-checkbox-indeterminate-background-color: var(--ag-inherited-checkbox-indeterminate-background-color, color-mix(in srgb, var(--ag-background-color), var(--ag-foreground-color) 30%)); + --ag-checkbox-indeterminate-border-color: var(--ag-inherited-checkbox-indeterminate-border-color, color-mix(in srgb, var(--ag-background-color), var(--ag-foreground-color) 30%)); + --ag-checkbox-indeterminate-shape-image: var(--ag-inherited-checkbox-indeterminate-shape-image, url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2210%22%20height%3D%222%22%20fill%3D%22none%22%3E%3Crect%20width%3D%2210%22%20height%3D%222%22%20fill%3D%22%23000%22%20rx%3D%221%22%2F%3E%3C%2Fsvg%3E')); + --ag-checkbox-indeterminate-shape-color: var(--ag-inherited-checkbox-indeterminate-shape-color, var(--ag-background-color)); + --ag-radio-checked-shape-image: var(--ag-inherited-radio-checked-shape-image, url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%226%22%20height%3D%226%22%20fill%3D%22none%22%3E%3Ccircle%20cx%3D%223%22%20cy%3D%223%22%20r%3D%223%22%20fill%3D%22%23000%22%2F%3E%3C%2Fsvg%3E')); + --ag-menu-border: var(--ag-inherited-menu-border, solid 1px color-mix(in srgb, transparent, var(--ag-foreground-color) 20%)); + --ag-menu-background-color: var(--ag-inherited-menu-background-color, color-mix(in srgb, var(--ag-background-color), var(--ag-foreground-color) 3%)); + --ag-menu-text-color: var(--ag-inherited-menu-text-color, color-mix(in srgb, var(--ag-background-color), var(--ag-foreground-color) 95%)); + --ag-menu-shadow: var(--ag-inherited-menu-shadow, var(--ag-popup-shadow)); + --ag-menu-separator-color: var(--ag-inherited-menu-separator-color, var(--ag-border-color)); + --ag-set-filter-indent-size: var(--ag-inherited-set-filter-indent-size, var(--ag-icon-size)); + --ag-chart-menu-panel-width: var(--ag-inherited-chart-menu-panel-width, 260px); + --ag-chart-menu-label-color: var(--ag-inherited-chart-menu-label-color, color-mix(in srgb, transparent, var(--ag-foreground-color) 80%)); + --ag-icon-button-hover-color: var(--ag-inherited-icon-button-hover-color, color-mix(in srgb, transparent, var(--ag-foreground-color) 10%)); + --ag-dialog-shadow: var(--ag-inherited-dialog-shadow, var(--ag-popup-shadow)); + --ag-dialog-border: var(--ag-inherited-dialog-border, solid 1px color-mix(in srgb, transparent, var(--ag-foreground-color) 20%)); + --ag-panel-background-color: var(--ag-inherited-panel-background-color, var(--ag-background-color)); + --ag-panel-title-bar-background-color: var(--ag-inherited-panel-title-bar-background-color, var(--ag-header-background-color)); + --ag-panel-title-bar-border: var(--ag-inherited-panel-title-bar-border, solid 1px var(--ag-border-color)); + --ag-column-select-indent-size: var(--ag-inherited-column-select-indent-size, var(--ag-icon-size)); + --ag-tool-panel-separator-border: var(--ag-inherited-tool-panel-separator-border, solid 1px var(--ag-border-color)); + --ag-tooltip-background-color: var(--ag-inherited-tooltip-background-color, var(--ag-chrome-background-color)); + --ag-tooltip-text-color: var(--ag-inherited-tooltip-text-color, var(--ag-text-color)); + --ag-tooltip-border: var(--ag-inherited-tooltip-border, solid 1px var(--ag-border-color)); + --ag-column-drop-cell-background-color: var(--ag-inherited-column-drop-cell-background-color, color-mix(in srgb, transparent, var(--ag-foreground-color) 7%)); + --ag-column-drop-cell-border: var(--ag-inherited-column-drop-cell-border, solid 1px color-mix(in srgb, transparent, var(--ag-foreground-color) 13%)); + --ag-select-cell-background-color: var(--ag-inherited-select-cell-background-color, color-mix(in srgb, transparent, var(--ag-foreground-color) 7%)); + --ag-select-cell-border: var(--ag-inherited-select-cell-border, solid 1px color-mix(in srgb, transparent, var(--ag-foreground-color) 13%)); + --ag-advanced-filter-builder-button-bar-border: var(--ag-inherited-advanced-filter-builder-button-bar-border, solid 1px var(--ag-border-color)); + --ag-advanced-filter-builder-indent-size: var(--ag-inherited-advanced-filter-builder-indent-size, calc(var(--ag-grid-size) * 2 + var(--ag-icon-size))); + --ag-advanced-filter-builder-join-pill-color: var(--ag-inherited-advanced-filter-builder-join-pill-color, #f08e8d); + --ag-advanced-filter-builder-column-pill-color: var(--ag-inherited-advanced-filter-builder-column-pill-color, #a6e194); + --ag-advanced-filter-builder-option-pill-color: var(--ag-inherited-advanced-filter-builder-option-pill-color, #f3c08b); + --ag-advanced-filter-builder-value-pill-color: var(--ag-inherited-advanced-filter-builder-value-pill-color, #85c0e4); + --ag-filter-tool-panel-group-indent: var(--ag-inherited-filter-tool-panel-group-indent, var(--ag-grid-size)); + --ag-icon-button-hover-background-color: var(--ag-inherited-icon-button-hover-background-color, color-mix(in srgb, transparent, var(--ag-foreground-color) 10%)); + --ag-row-loading-skeleton-effect-color: var(--ag-inherited-row-loading-skeleton-effect-color, rgba(66, 66, 66, 0.2)); + --ag-tab-bar-background-color: var(--ag-inherited-tab-bar-background-color, color-mix(in srgb, transparent, var(--ag-foreground-color) 5%)); + --ag-tab-bar-horizontal-padding: var(--ag-inherited-tab-bar-horizontal-padding, 0); + --ag-tab-bar-top-padding: var(--ag-inherited-tab-bar-top-padding, 0); + --ag-tab-background-color: var(--ag-inherited-tab-background-color, transparent); + --ag-tab-text-color: var(--ag-inherited-tab-text-color, color-mix(in srgb, transparent, var(--ag-text-color) 70%)); + --ag-tab-horizontal-padding: var(--ag-inherited-tab-horizontal-padding, calc(var(--ag-grid-size))); + --ag-tab-top-padding: var(--ag-inherited-tab-top-padding, calc(var(--ag-grid-size))); + --ag-tab-bottom-padding: var(--ag-inherited-tab-bottom-padding, calc(var(--ag-grid-size))); + --ag-tab-spacing: var(--ag-inherited-tab-spacing, 0); + --ag-tab-hover-background-color: var(--ag-inherited-tab-hover-background-color, var(--ag-tab-background-color)); + --ag-tab-hover-text-color: var(--ag-inherited-tab-hover-text-color, var(--ag-text-color)); + --ag-tab-selected-background-color: var(--ag-inherited-tab-selected-background-color, var(--ag-background-color)); + --ag-tab-selected-text-color: var(--ag-inherited-tab-selected-text-color, var(--ag-text-color)); + --ag-tab-selected-border-width: var(--ag-inherited-tab-selected-border-width, 1px); + --ag-tab-selected-border-color: var(--ag-inherited-tab-selected-border-color, var(--ag-border-color)); + --ag-tab-selected-underline-color: var(--ag-inherited-tab-selected-underline-color, transparent); + --ag-tab-selected-underline-width: var(--ag-inherited-tab-selected-underline-width, 0); + --ag-tab-selected-underline-transition-duration: var(--ag-inherited-tab-selected-underline-transition-duration, 0); + --ag-tab-bar-border: var(--ag-inherited-tab-bar-border, solid 1px var(--ag-border-color)); + --ag-input-background-color: var(--ag-inherited-input-background-color, var(--ag-background-color)); + --ag-input-border: var(--ag-inherited-input-border, solid 1px var(--ag-border-color)); + --ag-input-border-radius: var(--ag-inherited-input-border-radius, var(--ag-border-radius)); + --ag-input-text-color: var(--ag-inherited-input-text-color, var(--ag-text-color)); + --ag-input-padding-start: var(--ag-inherited-input-padding-start, var(--ag-grid-size)); + --ag-input-height: var(--ag-inherited-input-height, calc(max(var(--ag-icon-size), var(--ag-font-size)) + var(--ag-grid-size) * 2)); + --ag-input-focus-background-color: var(--ag-inherited-input-focus-background-color, var(--ag-input-background-color)); + --ag-input-focus-border: var(--ag-inherited-input-focus-border, solid 1px var(--ag-accent-color)); + --ag-input-focus-shadow: var(--ag-inherited-input-focus-shadow, var(--ag-focus-shadow)); + --ag-input-focus-text-color: var(--ag-inherited-input-focus-text-color, var(--ag-input-text-color)); + --ag-input-disabled-background-color: var(--ag-inherited-input-disabled-background-color, color-mix(in srgb, var(--ag-background-color), var(--ag-foreground-color) 6%)); + --ag-input-disabled-border: var(--ag-inherited-input-disabled-border, var(--ag-input-border)); + --ag-input-disabled-text-color: var(--ag-inherited-input-disabled-text-color, color-mix(in srgb, transparent, var(--ag-text-color) 50%)); + --ag-input-invalid-background-color: var(--ag-inherited-input-invalid-background-color, var(--ag-input-background-color)); + --ag-input-invalid-border: var(--ag-inherited-input-invalid-border, solid 1px var(--ag-invalid-color)); + --ag-input-invalid-text-color: var(--ag-inherited-input-invalid-text-color, var(--ag-input-text-color)); +} +:has(> :where(.ag-root-wrapper, .ag-measurement-container, .ag-apply-theme-variables, .ag-popup)):not(:where(.ag-root-wrapper, .ag-measurement-container, .ag-apply-theme-variables, .ag-popup)) { + --ag-inherited-background-color: var(--ag-background-color); + --ag-inherited-foreground-color: var(--ag-foreground-color); + --ag-inherited-text-color: var(--ag-text-color); + --ag-inherited-accent-color: var(--ag-accent-color); + --ag-inherited-invalid-color: var(--ag-invalid-color); + --ag-inherited-border-color: var(--ag-border-color); + --ag-inherited-wrapper-border: var(--ag-wrapper-border); + --ag-inherited-row-border: var(--ag-row-border); + --ag-inherited-color-scheme: var(--ag-color-scheme); + --ag-inherited-header-row-border: var(--ag-header-row-border); + --ag-inherited-footer-row-border: var(--ag-footer-row-border); + --ag-inherited-column-border: var(--ag-column-border); + --ag-inherited-header-column-border: var(--ag-header-column-border); + --ag-inherited-header-column-border-height: var(--ag-header-column-border-height); + --ag-inherited-pinned-column-border: var(--ag-pinned-column-border); + --ag-inherited-pinned-row-border: var(--ag-pinned-row-border); + --ag-inherited-side-panel-border: var(--ag-side-panel-border); + --ag-inherited-font-family: var(--ag-font-family); + --ag-inherited-chrome-background-color: var(--ag-chrome-background-color); + --ag-inherited-header-background-color: var(--ag-header-background-color); + --ag-inherited-header-font-family: var(--ag-header-font-family); + --ag-inherited-header-font-weight: var(--ag-header-font-weight); + --ag-inherited-header-font-size: var(--ag-header-font-size); + --ag-inherited-header-text-color: var(--ag-header-text-color); + --ag-inherited-header-cell-hover-background-color: var(--ag-header-cell-hover-background-color); + --ag-inherited-header-cell-hover-background-transition-duration: var(--ag-header-cell-hover-background-transition-duration); + --ag-inherited-cell-text-color: var(--ag-cell-text-color); + --ag-inherited-subtle-text-color: var(--ag-subtle-text-color); + --ag-inherited-range-selection-border-style: var(--ag-range-selection-border-style); + --ag-inherited-range-selection-border-color: var(--ag-range-selection-border-color); + --ag-inherited-range-selection-background-color: var(--ag-range-selection-background-color); + --ag-inherited-range-selection-chart-background-color: var(--ag-range-selection-chart-background-color); + --ag-inherited-range-selection-chart-category-background-color: var(--ag-range-selection-chart-category-background-color); + --ag-inherited-range-selection-highlight-color: var(--ag-range-selection-highlight-color); + --ag-inherited-row-hover-color: var(--ag-row-hover-color); + --ag-inherited-column-hover-color: var(--ag-column-hover-color); + --ag-inherited-selected-row-background-color: var(--ag-selected-row-background-color); + --ag-inherited-modal-overlay-background-color: var(--ag-modal-overlay-background-color); + --ag-inherited-odd-row-background-color: var(--ag-odd-row-background-color); + --ag-inherited-border-radius: var(--ag-border-radius); + --ag-inherited-wrapper-border-radius: var(--ag-wrapper-border-radius); + --ag-inherited-cell-horizontal-padding: var(--ag-cell-horizontal-padding); + --ag-inherited-cell-widget-spacing: var(--ag-cell-widget-spacing); + --ag-inherited-cell-horizontal-padding-scale: var(--ag-cell-horizontal-padding-scale); + --ag-inherited-row-group-indent-size: var(--ag-row-group-indent-size); + --ag-inherited-value-change-delta-up-color: var(--ag-value-change-delta-up-color); + --ag-inherited-value-change-delta-down-color: var(--ag-value-change-delta-down-color); + --ag-inherited-value-change-value-highlight-background-color: var(--ag-value-change-value-highlight-background-color); + --ag-inherited-grid-size: var(--ag-grid-size); + --ag-inherited-font-size: var(--ag-font-size); + --ag-inherited-row-height: var(--ag-row-height); + --ag-inherited-row-vertical-padding-scale: var(--ag-row-vertical-padding-scale); + --ag-inherited-header-height: var(--ag-header-height); + --ag-inherited-header-vertical-padding-scale: var(--ag-header-vertical-padding-scale); + --ag-inherited-popup-shadow: var(--ag-popup-shadow); + --ag-inherited-dropdown-shadow: var(--ag-dropdown-shadow); + --ag-inherited-drag-ghost-background-color: var(--ag-drag-ghost-background-color); + --ag-inherited-drag-ghost-border: var(--ag-drag-ghost-border); + --ag-inherited-drag-ghost-shadow: var(--ag-drag-ghost-shadow); + --ag-inherited-focus-shadow: var(--ag-focus-shadow); + --ag-inherited-side-bar-panel-width: var(--ag-side-bar-panel-width); + --ag-inherited-side-button-selected-border: var(--ag-side-button-selected-border); + --ag-inherited-side-button-selected-background-color: var(--ag-side-button-selected-background-color); + --ag-inherited-side-bar-background-color: var(--ag-side-bar-background-color); + --ag-inherited-header-column-resize-handle-display: var(--ag-header-column-resize-handle-display); + --ag-inherited-header-column-resize-handle-height: var(--ag-header-column-resize-handle-height); + --ag-inherited-header-column-resize-handle-width: var(--ag-header-column-resize-handle-width); + --ag-inherited-header-column-resize-handle-color: var(--ag-header-column-resize-handle-color); + --ag-inherited-widget-container-horizontal-padding: var(--ag-widget-container-horizontal-padding); + --ag-inherited-widget-container-vertical-padding: var(--ag-widget-container-vertical-padding); + --ag-inherited-widget-horizontal-spacing: var(--ag-widget-horizontal-spacing); + --ag-inherited-widget-vertical-spacing: var(--ag-widget-vertical-spacing); + --ag-inherited-list-item-height: var(--ag-list-item-height); + --ag-inherited-icon-size: var(--ag-icon-size); + --ag-inherited-toggle-button-width: var(--ag-toggle-button-width); + --ag-inherited-toggle-button-height: var(--ag-toggle-button-height); + --ag-inherited-toggle-button-border-width: var(--ag-toggle-button-border-width); + --ag-inherited-toggle-button-on-border-color: var(--ag-toggle-button-on-border-color); + --ag-inherited-toggle-button-on-background-color: var(--ag-toggle-button-on-background-color); + --ag-inherited-toggle-button-off-border-color: var(--ag-toggle-button-off-border-color); + --ag-inherited-toggle-button-off-background-color: var(--ag-toggle-button-off-background-color); + --ag-inherited-toggle-button-switch-border-color: var(--ag-toggle-button-switch-border-color); + --ag-inherited-toggle-button-switch-background-color: var(--ag-toggle-button-switch-background-color); + --ag-inherited-checkbox-border-width: var(--ag-checkbox-border-width); + --ag-inherited-checkbox-border-radius: var(--ag-checkbox-border-radius); + --ag-inherited-checkbox-unchecked-background-color: var(--ag-checkbox-unchecked-background-color); + --ag-inherited-checkbox-unchecked-border-color: var(--ag-checkbox-unchecked-border-color); + --ag-inherited-checkbox-checked-background-color: var(--ag-checkbox-checked-background-color); + --ag-inherited-checkbox-checked-border-color: var(--ag-checkbox-checked-border-color); + --ag-inherited-checkbox-checked-shape-image: var(--ag-checkbox-checked-shape-image); + --ag-inherited-checkbox-checked-shape-color: var(--ag-checkbox-checked-shape-color); + --ag-inherited-checkbox-indeterminate-background-color: var(--ag-checkbox-indeterminate-background-color); + --ag-inherited-checkbox-indeterminate-border-color: var(--ag-checkbox-indeterminate-border-color); + --ag-inherited-checkbox-indeterminate-shape-image: var(--ag-checkbox-indeterminate-shape-image); + --ag-inherited-checkbox-indeterminate-shape-color: var(--ag-checkbox-indeterminate-shape-color); + --ag-inherited-radio-checked-shape-image: var(--ag-radio-checked-shape-image); + --ag-inherited-menu-border: var(--ag-menu-border); + --ag-inherited-menu-background-color: var(--ag-menu-background-color); + --ag-inherited-menu-text-color: var(--ag-menu-text-color); + --ag-inherited-menu-shadow: var(--ag-menu-shadow); + --ag-inherited-menu-separator-color: var(--ag-menu-separator-color); + --ag-inherited-set-filter-indent-size: var(--ag-set-filter-indent-size); + --ag-inherited-chart-menu-panel-width: var(--ag-chart-menu-panel-width); + --ag-inherited-chart-menu-label-color: var(--ag-chart-menu-label-color); + --ag-inherited-icon-button-hover-color: var(--ag-icon-button-hover-color); + --ag-inherited-dialog-shadow: var(--ag-dialog-shadow); + --ag-inherited-dialog-border: var(--ag-dialog-border); + --ag-inherited-panel-background-color: var(--ag-panel-background-color); + --ag-inherited-panel-title-bar-background-color: var(--ag-panel-title-bar-background-color); + --ag-inherited-panel-title-bar-border: var(--ag-panel-title-bar-border); + --ag-inherited-column-select-indent-size: var(--ag-column-select-indent-size); + --ag-inherited-tool-panel-separator-border: var(--ag-tool-panel-separator-border); + --ag-inherited-tooltip-background-color: var(--ag-tooltip-background-color); + --ag-inherited-tooltip-text-color: var(--ag-tooltip-text-color); + --ag-inherited-tooltip-border: var(--ag-tooltip-border); + --ag-inherited-column-drop-cell-background-color: var(--ag-column-drop-cell-background-color); + --ag-inherited-column-drop-cell-border: var(--ag-column-drop-cell-border); + --ag-inherited-select-cell-background-color: var(--ag-select-cell-background-color); + --ag-inherited-select-cell-border: var(--ag-select-cell-border); + --ag-inherited-advanced-filter-builder-button-bar-border: var(--ag-advanced-filter-builder-button-bar-border); + --ag-inherited-advanced-filter-builder-indent-size: var(--ag-advanced-filter-builder-indent-size); + --ag-inherited-advanced-filter-builder-join-pill-color: var(--ag-advanced-filter-builder-join-pill-color); + --ag-inherited-advanced-filter-builder-column-pill-color: var(--ag-advanced-filter-builder-column-pill-color); + --ag-inherited-advanced-filter-builder-option-pill-color: var(--ag-advanced-filter-builder-option-pill-color); + --ag-inherited-advanced-filter-builder-value-pill-color: var(--ag-advanced-filter-builder-value-pill-color); + --ag-inherited-filter-tool-panel-group-indent: var(--ag-filter-tool-panel-group-indent); + --ag-inherited-icon-button-hover-background-color: var(--ag-icon-button-hover-background-color); + --ag-inherited-row-loading-skeleton-effect-color: var(--ag-row-loading-skeleton-effect-color); + --ag-inherited-tab-bar-background-color: var(--ag-tab-bar-background-color); + --ag-inherited-tab-bar-horizontal-padding: var(--ag-tab-bar-horizontal-padding); + --ag-inherited-tab-bar-top-padding: var(--ag-tab-bar-top-padding); + --ag-inherited-tab-background-color: var(--ag-tab-background-color); + --ag-inherited-tab-text-color: var(--ag-tab-text-color); + --ag-inherited-tab-horizontal-padding: var(--ag-tab-horizontal-padding); + --ag-inherited-tab-top-padding: var(--ag-tab-top-padding); + --ag-inherited-tab-bottom-padding: var(--ag-tab-bottom-padding); + --ag-inherited-tab-spacing: var(--ag-tab-spacing); + --ag-inherited-tab-hover-background-color: var(--ag-tab-hover-background-color); + --ag-inherited-tab-hover-text-color: var(--ag-tab-hover-text-color); + --ag-inherited-tab-selected-background-color: var(--ag-tab-selected-background-color); + --ag-inherited-tab-selected-text-color: var(--ag-tab-selected-text-color); + --ag-inherited-tab-selected-border-width: var(--ag-tab-selected-border-width); + --ag-inherited-tab-selected-border-color: var(--ag-tab-selected-border-color); + --ag-inherited-tab-selected-underline-color: var(--ag-tab-selected-underline-color); + --ag-inherited-tab-selected-underline-width: var(--ag-tab-selected-underline-width); + --ag-inherited-tab-selected-underline-transition-duration: var(--ag-tab-selected-underline-transition-duration); + --ag-inherited-tab-bar-border: var(--ag-tab-bar-border); + --ag-inherited-input-background-color: var(--ag-input-background-color); + --ag-inherited-input-border: var(--ag-input-border); + --ag-inherited-input-border-radius: var(--ag-input-border-radius); + --ag-inherited-input-text-color: var(--ag-input-text-color); + --ag-inherited-input-padding-start: var(--ag-input-padding-start); + --ag-inherited-input-height: var(--ag-input-height); + --ag-inherited-input-focus-background-color: var(--ag-input-focus-background-color); + --ag-inherited-input-focus-border: var(--ag-input-focus-border); + --ag-inherited-input-focus-shadow: var(--ag-input-focus-shadow); + --ag-inherited-input-focus-text-color: var(--ag-input-focus-text-color); + --ag-inherited-input-disabled-background-color: var(--ag-input-disabled-background-color); + --ag-inherited-input-disabled-border: var(--ag-input-disabled-border); + --ag-inherited-input-disabled-text-color: var(--ag-input-disabled-text-color); + --ag-inherited-input-invalid-background-color: var(--ag-input-invalid-background-color); + --ag-inherited-input-invalid-border: var(--ag-input-invalid-border); + --ag-inherited-input-invalid-text-color: var(--ag-input-invalid-text-color); +} + + +/* Part core/part */:where([class^=ag-]),:where([class^=ag-]):after,:where([class^=ag-]):before,:where([class^=ag-]):focus,:where([class^=ag-]):focus-within{box-sizing:border-box;outline:none}:where([class^=ag-]):where(button),:where([class^=ag-]):where(input),:where([class^=ag-]):where(textarea){background:none;border:none;color:inherit;cursor:pointer;font-family:inherit;font-size:inherit;line-height:inherit;margin:0;padding:0}:where([class^=ag-]):where(button){font-weight:inherit}:where([class^=ag-])::-ms-clear{display:none}ag-grid,ag-grid-angular,ag-grid-aurelia,ag-grid-ng2,ag-grid-polymer{display:block}.ag-aria-description-container{border:0;z-index:9999;clip:rect(1px,1px,1px,1px);height:1px;overflow:hidden;padding:0;position:absolute;white-space:nowrap;width:1px}.ag-hidden{display:none!important}.ag-invisible{visibility:hidden!important}.ag-unselectable{-webkit-user-select:none;-moz-user-select:none;user-select:none}.ag-selectable{-webkit-user-select:text;-moz-user-select:text;user-select:text}.ag-tabs-header{display:flex}.ag-tab{cursor:pointer;position:relative}.ag-tab-guard{display:block;height:0;position:absolute;width:0}.ag-virtual-list-viewport .ag-tab-guard{position:sticky}.ag-tab-guard-top{top:1px}.ag-tab-guard-bottom{bottom:1px}.ag-shake-left-to-right{animation-direction:alternate;animation-duration:.2s;animation-iteration-count:infinite;animation-name:ag-shake-left-to-right}@keyframes ag-shake-left-to-right{0%{padding-left:6px;padding-right:2px}to{padding-left:2px;padding-right:6px}}.ag-watermark{bottom:20px;color:#9b9b9b;opacity:.7;position:absolute;right:25px;transition:opacity 1s ease-out 3s}.ag-watermark:before{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMDkiIGhlaWdodD0iMzYiIGZpbGw9Im5vbmUiPjxwYXRoIGZpbGw9IiM5QjlCOUIiIGQ9Ik0xOTIuOTkzIDIzLjY1OHYtNy45NDZoLTEzLjU0MWwtNy45NDcgNy45NDZ6TTIwOC4yNSAzLjk1aC0xNi45NzRsLTguMDEgNy45NDdoMjQuOTg0ek0xNjMuNjIyIDMxLjYwNWw0LjA2OS00LjA2OWgxMy43MzJ2Ny45NDdoLTE3LjgwMXoiLz48cGF0aCBmaWxsPSIjOUI5QjlCIiBkPSJNMTY2LjYxIDE5Ljc4aDguNzczbDguMDEtNy45NDZIMTY2LjYxek0xNTcuMDExIDMxLjYwNWg2LjYxMWw3Ljg4My03Ljk0N2gtMTQuNDk0ek0xOTEuMjc2IDMuOTVsLTQuMDY4IDQuMDdIMTYxLjI3Vi4wNzJoMzAuMDA2ek0yMC44NCAzMC4yMDZIOC4zNzhsLTIuMTYyIDUuMzRILjc1TDEyLjI1NyA4LjU5Mmg0Ljc2OEwyOC41MyAzNS41NDZoLTUuNTN6bS0xLjcxNy00LjI2TDE0LjYwOSAxNC45NWwtNC41MTQgMTAuOTk4ek0xMDQuNDM3IDE4LjUwOWMxLjU4OS0yLjM1MiA1LjU5NC0yLjYwNyA3LjI0Ny0yLjYwN3Y0LjU3OGMtMi4wMzQgMC00LjA2OS4wNjMtNS4yNzcuOTUzLTEuMjA3Ljg5LTEuODQzIDIuMDk4LTEuODQzIDMuNTZ2MTAuNTUzaC00Ljk1OVYxNS45MDJoNC43Njh6TTExOS4zNzYgMTUuOTAyaC00Ljk1OHYxOS42NDRoNC45NTh6TTExOS4zNzYgNy4xM2gtNC45NTh2NS44NDhoNC45NTh6TTE0My45NzkgNy4xM3YyOC40MTZoLTQuNzY4bC0uMTI3LTIuOTg4YTguMyA4LjMgMCAwIDEtMi42NyAyLjQ4Yy0xLjA4MS41NzItMi40MTYuODktMy45NDIuODktMS4zMzUgMC0yLjYwNi0uMjU1LTMuNjg3LS43LTEuMTQ0LS41MDgtMi4xNjItMS4xNDQtMi45ODgtMi4wMzRhOS42IDkuNiAwIDAgMS0xLjk3MS0zLjE3OWMtLjUwOC0xLjIwNy0uNjk5LTIuNjA2LS42OTktNC4xMzJzLjI1NC0yLjkyNC42OTktNC4xOTZjLjUwOS0xLjI3MSAxLjE0NS0yLjM1MiAxLjk3MS0zLjI0MnMxLjg0NC0xLjU4OSAyLjk4OC0yLjA5OCAyLjM1Mi0uNzYzIDMuNjg3LS43NjNjMS41MjYgMCAyLjc5Ny4yNTUgMy44NzguODI3czEuOTcxIDEuMzM1IDIuNjcgMi40MTZWNy4xOTNoNC45NTl6bS0xMC40MjYgMjQuNTM4YzEuNjUzIDAgMi45MjQtLjU3MiAzLjk0MS0xLjY1M3MxLjUyNi0yLjU0MyAxLjUyNi00LjMyMy0uNTA5LTMuMTc4LTEuNTI2LTQuMzIyYy0xLjAxNy0xLjA4MS0yLjI4OC0xLjY1My0zLjk0MS0xLjY1My0xLjU5IDAtMi45MjUuNTcyLTMuODc4IDEuNjUzLTEuMDE3IDEuMDgtMS41MjYgMi41NDMtMS41MjYgNC4zMjIgMCAxLjc4LjUwOSAzLjE4IDEuNTI2IDQuMjYgMS4wMTcgMS4xNDQgMi4yODggMS43MTYgMy44NzggMS43MTZNNTcuMjAyIDIwLjM1M0g0NC45MzN2NC4yNTloNi45OTNjLS4xOSAyLjE2MS0xLjAxNyAzLjgxNC0yLjQxNiA1LjE1LTEuMzk4IDEuMjctMy4xNzggMS45MDYtNS40NjcgMS45MDYtMS4yNzEgMC0yLjQ4LS4yNTQtMy40OTYtLjY5OWE3IDcgMCAwIDEtMi43MzQtMS45N2MtLjc2My0uODI3LTEuMzM1LTEuODQ0LTEuNzgtMy4wNTJzLS42MzYtMi40OC0uNjM2LTMuOTQyLjE5LTIuNzMzLjYzNi0zLjk0MWMuMzgxLTEuMjA4IDEuMDE3LTIuMTYyIDEuNzgtMy4wNTIuNzYzLS44MjYgMS42NTMtMS40NjIgMi43MzMtMS45N2E5LjEgOS4xIDAgMCAxIDMuNTYtLjdxNC4wMDUgMCA2LjEwMyAxLjkwN2wzLjMwNi0zLjMwNWMtMi40OC0xLjkwNy01LjY1OC0yLjkyNS05LjQwOS0yLjkyNS0yLjA5NyAwLTQuMDA0LjMxOC01LjcyMSAxLjAxOC0xLjcxNi42OTktMy4xNzkgMS41ODktNC4zODYgMi43OTdBMTIuMSAxMi4xIDAgMCAwIDMxLjIgMTYuMjJjLS42MzUgMS43MTctLjk1MyAzLjYyNC0uOTUzIDUuNjU4cy4zMTggMy45NDIgMS4wMTcgNS42NThjLjcgMS43MTcgMS41OSAzLjE3OSAyLjc5NyA0LjM4N2ExMi4xIDEyLjEgMCAwIDAgNC4zODcgMi43OTdjMS43MTYuNyAzLjYyMyAxLjAxNyA1LjY1NyAxLjAxNyAyLjAzNSAwIDMuODc4LS4zMTggNS41MzEtMS4wMTcgMS42NTMtLjcgMy4wNTItMS41OSA0LjE5Ni0yLjc5N3ExLjcxNi0xLjgxMiAyLjY3LTQuMzg3Yy42MzYtMS43MTYuOTU0LTMuNjIzLjk1NC01LjY1OHYtLjgyNmMtLjE5MS0uMTI3LS4yNTUtLjQ0NS0uMjU1LS43TTk1Ljk4MiAyMC4zNTNoLTEyLjI3djQuMjU5aDYuOTkzYy0uMTkgMi4xNjEtMS4wMTcgMy44MTQtMi40MTYgNS4xNS0xLjM5OCAxLjI3LTMuMTc4IDEuOTA2LTUuNDY3IDEuOTA2LTEuMjcxIDAtMi40OC0uMjU0LTMuNDk2LS42OTlhNyA3IDAgMCAxLTIuNzM0LTEuOTdjLS43NjMtLjgyNy0xLjMzNS0xLjg0NC0xLjc4LTMuMDUycy0uNjM2LTIuNDgtLjYzNi0zLjk0Mi4xOS0yLjczMy42MzYtMy45NDFjLjM4MS0xLjIwOCAxLjAxNy0yLjE2MiAxLjc4LTMuMDUyLjc2My0uODI2IDEuNjUzLTEuNDYyIDIuNzM0LTEuOTdhOS4xIDkuMSAwIDAgMSAzLjU2LS43cTQuMDA1IDAgNi4xMDMgMS45MDdsMy4zMDUtMy4zMDVjLTIuNDc5LTEuOTA3LTUuNjU4LTIuOTI1LTkuNDA4LTIuOTI1LTIuMDk4IDAtNC4wMDUuMzE4LTUuNzIyIDEuMDE4LTEuNzE2LjY5OS0zLjE3OCAxLjU4OS00LjM4NiAyLjc5N2ExMi4xIDEyLjEgMCAwIDAtMi43OTcgNC4zODZjLS42MzYgMS43MTctLjk1NCAzLjYyNC0uOTU0IDUuNjU4cy4zMTggMy45NDIgMS4wMTcgNS42NThjLjcgMS43MTcgMS41OSAzLjE3OSAyLjc5NyA0LjM4N2ExMi4xIDEyLjEgMCAwIDAgNC4zODcgMi43OTdjMS43MTYuNyAzLjYyMyAxLjAxNyA1LjY1OCAxLjAxNyAyLjAzNCAwIDMuODc4LS4zMTggNS41My0xLjAxNyAxLjY1My0uNyAzLjA1Mi0xLjU5IDQuMTk2LTIuNzk3cTEuNzE4LTEuODEyIDIuNjctNC4zODdjLjYzNi0xLjcxNi45NTQtMy42MjMuOTU0LTUuNjU4di0uODI2Yy0uMTktLjEyNy0uMjU1LS40NDUtLjI1NS0uNyIvPjwvc3ZnPg==);background-repeat:no-repeat;background-size:170px 40px;content:"";display:block;height:40px;width:170px}.ag-watermark-text{font-family:Impact,sans-serif;font-size:19px;font-weight:700;opacity:.5}.ag-ltr .ag-watermark-text{padding-left:.7rem}.ag-rtl .ag-watermark-text{padding-right:.7rem}.ag-root-wrapper-body{display:flex;flex-direction:row}.ag-root-wrapper-body.ag-layout-normal{flex:1 1 auto;height:0;min-height:0}.ag-root{display:flex;flex-direction:column;position:relative}.ag-root.ag-layout-auto-height,.ag-root.ag-layout-normal{flex:1 1 auto;overflow:hidden;width:0}.ag-root.ag-layout-normal{height:100%}.ag-body-horizontal-scroll-viewport,.ag-body-vertical-scroll-viewport,.ag-body-viewport,.ag-center-cols-viewport,.ag-floating-bottom-viewport,.ag-floating-top-viewport,.ag-header-viewport,.ag-sticky-bottom-viewport,.ag-sticky-top-viewport,.ag-virtual-list-viewport{flex:1 1 auto;height:100%;min-width:0;overflow:hidden;position:relative}.ag-body-viewport,.ag-center-cols-viewport,.ag-floating-bottom-viewport,.ag-floating-top-viewport,.ag-header-viewport,.ag-sticky-bottom-viewport,.ag-sticky-top-viewport{overflow-x:auto;-ms-overflow-style:none!important;scrollbar-width:none!important}.ag-body-viewport::-webkit-scrollbar,.ag-center-cols-viewport::-webkit-scrollbar,.ag-floating-bottom-viewport::-webkit-scrollbar,.ag-floating-top-viewport::-webkit-scrollbar,.ag-header-viewport::-webkit-scrollbar,.ag-sticky-bottom-viewport::-webkit-scrollbar,.ag-sticky-top-viewport::-webkit-scrollbar{display:none!important}.ag-body-viewport{display:flex;overflow-x:hidden}.ag-body-viewport.ag-layout-normal{overflow-y:auto;-webkit-overflow-scrolling:touch}.ag-sticky-bottom-container,.ag-sticky-top-container{min-height:1px}.ag-center-cols-viewport{min-height:100%;width:100%}.ag-body-horizontal-scroll-viewport{overflow-x:scroll}.ag-body-vertical-scroll-viewport{overflow-y:scroll}.ag-virtual-list-viewport{overflow:auto;width:100%}.ag-body-container,.ag-body-horizontal-scroll-container,.ag-body-vertical-scroll-container,.ag-center-cols-container,.ag-floating-bottom-container,.ag-floating-bottom-full-width-container,.ag-floating-top-container,.ag-full-width-container,.ag-header-container,.ag-pinned-left-cols-container,.ag-pinned-right-cols-container,.ag-sticky-bottom-container,.ag-sticky-top-container,.ag-virtual-list-container{position:relative}.ag-floating-bottom-container,.ag-floating-top-container,.ag-header-container,.ag-sticky-bottom-container,.ag-sticky-top-container{height:100%;white-space:nowrap}.ag-center-cols-container,.ag-pinned-right-cols-container{display:block}.ag-body-horizontal-scroll-container{height:100%}.ag-body-vertical-scroll-container{width:100%}.ag-floating-bottom-full-width-container,.ag-floating-top-full-width-container,.ag-full-width-container,.ag-sticky-bottom-full-width-container,.ag-sticky-top-full-width-container{pointer-events:none;position:absolute;top:0}.ag-ltr .ag-floating-bottom-full-width-container,.ag-ltr .ag-floating-top-full-width-container,.ag-ltr .ag-full-width-container,.ag-ltr .ag-sticky-bottom-full-width-container,.ag-ltr .ag-sticky-top-full-width-container{left:0}.ag-rtl .ag-floating-bottom-full-width-container,.ag-rtl .ag-floating-top-full-width-container,.ag-rtl .ag-full-width-container,.ag-rtl .ag-sticky-bottom-full-width-container,.ag-rtl .ag-sticky-top-full-width-container{right:0}.ag-full-width-container{width:100%}.ag-floating-bottom-full-width-container,.ag-floating-top-full-width-container{display:inline-block;height:100%;overflow:hidden;width:100%}.ag-virtual-list-container{overflow:hidden}.ag-body{display:flex;flex:1 1 auto;flex-direction:row!important;min-height:0;position:relative}.ag-body-horizontal-scroll,.ag-body-vertical-scroll{display:flex;min-height:0;min-width:0;position:relative}.ag-body-horizontal-scroll.ag-scrollbar-invisible,.ag-body-vertical-scroll.ag-scrollbar-invisible{bottom:0;position:absolute}.ag-body-horizontal-scroll.ag-scrollbar-invisible.ag-apple-scrollbar,.ag-body-vertical-scroll.ag-scrollbar-invisible.ag-apple-scrollbar{opacity:0;transition:opacity .4s;visibility:hidden}.ag-body-horizontal-scroll.ag-scrollbar-invisible.ag-apple-scrollbar.ag-scrollbar-active,.ag-body-horizontal-scroll.ag-scrollbar-invisible.ag-apple-scrollbar.ag-scrollbar-scrolling,.ag-body-vertical-scroll.ag-scrollbar-invisible.ag-apple-scrollbar.ag-scrollbar-active,.ag-body-vertical-scroll.ag-scrollbar-invisible.ag-apple-scrollbar.ag-scrollbar-scrolling{opacity:1;visibility:visible}.ag-body-horizontal-scroll{width:100%}.ag-body-horizontal-scroll.ag-scrollbar-invisible{left:0;right:0}.ag-body-vertical-scroll{height:100%}.ag-body-vertical-scroll.ag-scrollbar-invisible{top:0;z-index:10}.ag-ltr .ag-body-vertical-scroll.ag-scrollbar-invisible{right:0}.ag-rtl .ag-body-vertical-scroll.ag-scrollbar-invisible{left:0}.ag-force-vertical-scroll{overflow-y:scroll!important}.ag-horizontal-left-spacer,.ag-horizontal-right-spacer{height:100%;min-width:0;overflow-x:scroll}.ag-horizontal-left-spacer.ag-scroller-corner,.ag-horizontal-right-spacer.ag-scroller-corner{overflow-x:hidden}.ag-ltr .ag-column-moving .ag-cell{transition:left .2s}.ag-rtl .ag-column-moving .ag-cell{transition:right .2s}.ag-ltr .ag-column-moving .ag-header-cell{transition:left .2s}.ag-rtl .ag-column-moving .ag-header-cell{transition:right .2s}.ag-ltr .ag-column-moving .ag-header-group-cell{transition:left .2s,width .2s}.ag-rtl .ag-column-moving .ag-header-group-cell{transition:right .2s,width .2s}.ag-row-animation .ag-row{transition:transform .4s,top .4s,opacity .2s}.ag-row-animation .ag-row.ag-after-created{transition:transform .4s,top .4s,height .4s,opacity .2s}.ag-row-no-animation .ag-row{transition:none}.ag-row-loading{align-items:center;display:flex}.ag-row-position-absolute{position:absolute}.ag-row-position-relative{position:relative}.ag-full-width-row{overflow:hidden;pointer-events:all}.ag-row-inline-editing{z-index:1}.ag-row-dragging{z-index:2}.ag-stub-cell{align-items:center;display:flex}.ag-cell{display:inline-block;height:100%;position:absolute;white-space:nowrap}.ag-cell-value{flex:1 1 auto}.ag-cell-value,.ag-group-value{overflow:hidden;text-overflow:ellipsis}.ag-cell-wrap-text{white-space:normal;word-break:break-word}.ag-sparkline-wrapper{height:100%;left:0;position:absolute;top:0;width:100%}.ag-full-width-row .ag-cell-wrapper.ag-row-group{align-items:center;height:100%}.ag-cell .ag-icon{display:inline-block;vertical-align:middle}.ag-popup-child{top:0;z-index:5}.ag-popup-editor{position:absolute;-webkit-user-select:none;-moz-user-select:none;user-select:none}.ag-large-text-input{display:block}.ag-floating-top{border-bottom:var(--ag-pinned-row-border);display:flex;overflow:hidden;position:relative;white-space:nowrap;width:100%}.ag-pinned-left-floating-top,.ag-pinned-right-floating-top{display:inline-block;min-width:0;overflow:hidden;position:relative}.ag-floating-bottom{border-top:var(--ag-pinned-row-border);display:flex;overflow:hidden;position:relative;white-space:nowrap;width:100%}.ag-pinned-left-floating-bottom,.ag-pinned-right-floating-bottom{display:inline-block;min-width:0;overflow:hidden;position:relative}.ag-sticky-bottom,.ag-sticky-top{background-color:var(--ag-background-color);display:flex;height:0;overflow:hidden;position:absolute;width:100%}.ag-pinned-left-sticky-top,.ag-pinned-right-sticky-top{height:100%;overflow:hidden;position:relative}.ag-sticky-bottom-full-width-container,.ag-sticky-top-full-width-container{height:100%;overflow:hidden;width:100%}.ag-value-slide-out{opacity:1}.ag-ltr .ag-value-slide-out{margin-right:5px;transition:opacity 3s,margin-right 3s}.ag-rtl .ag-value-slide-out{margin-left:5px;transition:opacity 3s,margin-left 3s}:is(.ag-ltr,.ag-rtl) .ag-value-slide-out{transition-timing-function:linear}.ag-value-slide-out-end{opacity:0}.ag-ltr .ag-value-slide-out-end{margin-right:10px}.ag-rtl .ag-value-slide-out-end{margin-left:10px}.ag-opacity-zero{opacity:0!important}.ag-tool-panel-wrapper{cursor:default;display:flex;overflow-x:hidden;overflow-y:auto;-webkit-user-select:none;-moz-user-select:none;user-select:none}.ag-select-agg-func-item{align-items:center;display:flex;flex-direction:row;flex-wrap:nowrap;height:100%;position:relative}.ag-select-agg-func-item>*{flex:none}.ag-select-agg-func-item{flex:1 1 auto;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ag-tool-panel-horizontal-resize{cursor:ew-resize;height:100%;position:absolute;top:0;width:5px;z-index:1}.ag-details-row{width:100%}.ag-details-row-fixed-height{height:100%}.ag-details-grid{width:100%}.ag-details-grid-fixed-height{height:100%}.ag-cell-label-container{align-items:center;display:flex;flex-direction:row-reverse;height:100%;justify-content:space-between;width:100%}.ag-right-aligned-header .ag-cell-label-container{flex-direction:row}.ag-right-aligned-header .ag-header-cell-text{text-align:end}.ag-column-group-icons{display:block}.ag-column-group-icons>*{cursor:pointer}.ag-pill-select{display:flex;flex-direction:column}.ag-pill-select .ag-column-drop-list{padding:0}.ag-pill-select .ag-select{padding-top:var(--ag-grid-size)}.ag-pill-select .ag-picker-field-wrapper{background-color:transparent;border:0}.ag-pill-select .ag-picker-field-display{cursor:pointer}.ag-ltr{direction:ltr}.ag-ltr .ag-body,.ag-ltr .ag-body-horizontal-scroll,.ag-ltr .ag-body-viewport,.ag-ltr .ag-floating-bottom,.ag-ltr .ag-floating-top,.ag-ltr .ag-header,.ag-ltr .ag-sticky-bottom,.ag-ltr .ag-sticky-top{flex-direction:row}.ag-rtl{direction:rtl}.ag-rtl .ag-body,.ag-rtl .ag-body-horizontal-scroll,.ag-rtl .ag-body-viewport,.ag-rtl .ag-floating-bottom,.ag-rtl .ag-floating-top,.ag-rtl .ag-header,.ag-rtl .ag-sticky-bottom,.ag-rtl .ag-sticky-top{flex-direction:row-reverse}.ag-rtl .ag-icon-contracted,.ag-rtl .ag-icon-expanded,.ag-rtl .ag-icon-tree-closed{display:block;transform:rotate(180deg)}.ag-measurement-container{overflow:hidden;visibility:hidden;width:0}.ag-measurement-container div{position:absolute}.ag-group{position:relative;width:100%}.ag-group-title-bar{align-items:center;display:flex;padding:var(--ag-grid-size)}.ag-group-title{display:inline;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ag-group-title-bar .ag-group-title{cursor:default}.ag-group-toolbar{align-items:center;display:flex;padding:var(--ag-grid-size)}.ag-group-container{display:flex}.ag-disabled .ag-group-container{pointer-events:none}.ag-disabled-group-container,.ag-disabled-group-title-bar{opacity:.5}.ag-group-container-horizontal{flex-direction:row;flex-wrap:wrap}.ag-group-container-vertical{flex-direction:column}.ag-group-title-bar-icon{cursor:pointer;flex:none}.ag-ltr .ag-group-title-bar-icon{margin-right:var(--ag-grid-size)}.ag-rtl .ag-group-title-bar-icon{margin-left:var(--ag-grid-size)}.ag-group-item-alignment-stretch .ag-group-item{align-items:stretch}.ag-group-item-alignment-start .ag-group-item{align-items:flex-start}.ag-group-item-alignment-end .ag-group-item{align-items:flex-end}.ag-popup-child:not(.ag-tooltip-custom){box-shadow:var(--ag-popup-shadow)}.ag-rtl{text-align:right}.ag-ltr .ag-pivot-leaf-group{margin-left:min(var(--ag-row-group-indent-size),calc(var(--ag-row-group-indent-size)*var(--ag-indentation-level)))}.ag-rtl .ag-pivot-leaf-group{margin-right:min(var(--ag-row-group-indent-size),calc(var(--ag-row-group-indent-size)*var(--ag-indentation-level)))}.ag-ltr .ag-row-group-leaf-indent{margin-left:calc(var(--ag-cell-widget-spacing) + var(--ag-icon-size))}.ag-rtl .ag-row-group-leaf-indent{margin-right:calc(var(--ag-cell-widget-spacing) + var(--ag-icon-size))}.ag-value-change-delta{padding:0 2px}.ag-value-change-delta-up{color:var(--ag-value-change-delta-up-color)}.ag-value-change-delta-down{color:var(--ag-value-change-delta-down-color)}.ag-value-change-value{background-color:transparent;border-radius:1px;padding-left:1px;padding-right:1px;transition:background-color 1s}.ag-value-change-value-highlight{background-color:var(--ag-value-change-value-highlight-background-color);transition:background-color .1s}.ag-cell-data-changed{background-color:var(--ag-value-change-value-highlight-background-color)!important}.ag-cell-data-changed-animation{background-color:transparent}.ag-cell-highlight{background-color:var(--ag-range-selection-highlight-color)!important}.ag-row{background-color:var(--ag-background-color);border-bottom:var(--ag-row-border);color:var(--ag-cell-text-color);height:var(--ag-row-height);white-space:nowrap;width:100%;--ag-internal-content-line-height:min(calc(var(--ag-row-height) - 1px),var(--ag-line-height,1000px))}.ag-sticky-bottom{border-top:var(--ag-row-border);box-sizing:content-box!important;display:none}.ag-group-contracted,.ag-group-expanded{cursor:pointer}.ag-cell,.ag-full-width-row .ag-cell-wrapper.ag-row-group{border:1px solid transparent;line-height:var(--ag-internal-content-line-height)}.ag-ltr .ag-cell{border-right:var(--ag-column-border)}.ag-rtl .ag-cell{border-left:var(--ag-column-border)}.ag-cell-wrapper{align-items:center;display:flex}.ag-ltr .ag-cell-wrapper{padding-left:calc(var(--ag-indentation-level)*var(--ag-row-group-indent-size))}.ag-rtl .ag-cell-wrapper{padding-right:calc(var(--ag-indentation-level)*var(--ag-row-group-indent-size))}.ag-cell-wrapper.ag-row-group{align-items:flex-start}.ag-cell-wrapper>:not(.ag-cell-value):not(.ag-group-value){align-items:center;display:flex;height:var(--ag-internal-content-line-height)}.ag-ltr .ag-row>.ag-cell-wrapper.ag-row-group{padding-left:calc(var(--ag-cell-horizontal-padding) + var(--ag-row-group-indent-size)*var(--ag-indentation-level))}.ag-rtl .ag-row>.ag-cell-wrapper.ag-row-group{padding-right:calc(var(--ag-cell-horizontal-padding) + var(--ag-row-group-indent-size)*var(--ag-indentation-level))}.ag-ltr .ag-group-contracted,.ag-ltr .ag-group-expanded,.ag-ltr .ag-row-drag,.ag-ltr .ag-selection-checkbox{margin-right:var(--ag-cell-widget-spacing)}.ag-rtl .ag-group-contracted,.ag-rtl .ag-group-expanded,.ag-rtl .ag-row-drag,.ag-rtl .ag-selection-checkbox{margin-left:var(--ag-cell-widget-spacing)}.ag-ltr .ag-group-child-count{margin-left:3px}.ag-rtl .ag-group-child-count{margin-right:3px}.ag-row-highlight-above:after,.ag-row-highlight-below:after{background-color:var(--ag-range-selection-border-color);content:"";height:1px;position:absolute;width:calc(100% - 1px)}.ag-ltr .ag-row-highlight-above:after,.ag-ltr .ag-row-highlight-below:after{left:1px}.ag-rtl .ag-row-highlight-above:after,.ag-rtl .ag-row-highlight-below:after{right:1px}.ag-row-highlight-above:after{top:-1px}.ag-row-highlight-above.ag-row-first:after{top:0}.ag-row-highlight-below:after{bottom:0}.ag-row-odd{background-color:var(--ag-odd-row-background-color)}.ag-row-selected:before{background-color:var(--ag-selected-row-background-color);content:"";display:block;inset:0;pointer-events:none;position:absolute}.ag-row-hover.ag-full-width-row.ag-row-group:before,.ag-row-hover:not(.ag-full-width-row):before{background-color:var(--ag-row-hover-color);content:"";display:block;inset:0;pointer-events:none;position:absolute}.ag-row-hover.ag-row-selected:before{background-color:var(--ag-row-hover-color);background-image:linear-gradient(var(--ag-selected-row-background-color),var(--ag-selected-row-background-color))}.ag-row-hover.ag-full-width-row.ag-row-group>*{position:relative}.ag-column-hover{background-color:var(--ag-column-hover-color)}.ag-ltr .ag-right-aligned-cell{text-align:right}.ag-rtl .ag-right-aligned-cell{text-align:left}.ag-right-aligned-cell .ag-cell-value,.ag-right-aligned-cell .ag-group-value{margin-left:auto}.ag-cell,.ag-full-width-row .ag-cell-wrapper.ag-row-group{-webkit-font-smoothing:subpixel-antialiased}.ag-ltr .ag-cell,.ag-ltr .ag-full-width-row .ag-cell-wrapper.ag-row-group{padding-left:calc(var(--ag-cell-horizontal-padding) - 1px + var(--ag-row-group-indent-size)*var(--ag-indentation-level));padding-right:calc(var(--ag-cell-horizontal-padding) - 1px)}.ag-rtl .ag-cell,.ag-rtl .ag-full-width-row .ag-cell-wrapper.ag-row-group{padding-left:calc(var(--ag-cell-horizontal-padding) - 1px);padding-right:calc(var(--ag-cell-horizontal-padding) - 1px + var(--ag-row-group-indent-size)*var(--ag-indentation-level))}.ag-row>.ag-cell-wrapper{padding-left:calc(var(--ag-cell-horizontal-padding) - 1px);padding-right:calc(var(--ag-cell-horizontal-padding) - 1px)}.ag-row-dragging{cursor:move;opacity:.5}.ag-details-row{background-color:var(--ag-background-color);padding:calc(var(--ag-grid-size)*3.5)}.ag-layout-auto-height .ag-center-cols-container,.ag-layout-auto-height .ag-center-cols-viewport,.ag-layout-print .ag-center-cols-container,.ag-layout-print .ag-center-cols-viewport{min-height:150px}.ag-overlay-loading-wrapper{background-color:var(--ag-modal-overlay-background-color)}.ag-skeleton-container{align-content:center;height:100%;width:100%}.ag-skeleton-effect{animation:ag-skeleton-loading 1.5s ease-in-out .5s infinite;background-color:var(--ag-row-loading-skeleton-effect-color);border-radius:.25rem;height:1em;width:100%}.ag-ltr .ag-right-aligned-cell .ag-skeleton-effect{margin-left:auto}.ag-rtl .ag-right-aligned-cell .ag-skeleton-effect{margin-right:auto}@keyframes ag-skeleton-loading{0%{opacity:1}50%{opacity:.4}to{opacity:1}}.ag-loading{align-items:center;display:flex;height:100%}.ag-ltr .ag-loading{padding-left:var(--ag-cell-horizontal-padding)}.ag-rtl .ag-loading{padding-right:var(--ag-cell-horizontal-padding)}.ag-ltr .ag-loading-icon{padding-right:var(--ag-cell-widget-spacing)}.ag-rtl .ag-loading-icon{padding-left:var(--ag-cell-widget-spacing)}.ag-icon-loading{animation-duration:1s;animation-iteration-count:infinite;animation-name:spin;animation-timing-function:linear}@keyframes spin{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.ag-details-row{padding:calc(var(--ag-grid-size)*3.75)}.ag-body-viewport:not(.ag-has-focus) .ag-cell-range-single-cell:not(.ag-cell-inline-editing),.ag-cell-range-selected:not(.ag-cell-focus){background-color:var(--ag-range-selection-background-color)}.ag-cell-range-chart:is(.ag-cell-range-selected:not(.ag-cell-focus),.ag-body-viewport:not(.ag-has-focus) .ag-cell-range-single-cell:not(.ag-cell-inline-editing)){background-color:var(--ag-range-selection-chart-background-color)!important}.ag-cell-range-chart.ag-cell-range-chart-category:is(.ag-cell-range-selected:not(.ag-cell-focus),.ag-body-viewport:not(.ag-has-focus) .ag-cell-range-single-cell:not(.ag-cell-inline-editing)){background-color:var(--ag-range-selection-chart-category-background-color)!important}.ag-cell-range-selected-1:not(.ag-cell-focus),.ag-root:not(.ag-context-menu-open) .ag-body-viewport:not(.ag-has-focus) .ag-cell-range-selected-1:not(.ag-cell-inline-editing){background-color:var(--ag-range-selection-background-color)}.ag-cell-range-selected-2:not(.ag-cell-focus){background-image:linear-gradient(var(--ag-range-selection-background-color),var(--ag-range-selection-background-color))}.ag-cell-range-selected-3:not(.ag-cell-focus){background-image:linear-gradient(var(--ag-range-selection-background-color),var(--ag-range-selection-background-color)),linear-gradient(var(--ag-range-selection-background-color),var(--ag-range-selection-background-color))}.ag-cell-range-selected-4:not(.ag-cell-focus){background-image:linear-gradient(var(--ag-range-selection-background-color),var(--ag-range-selection-background-color)),linear-gradient(var(--ag-range-selection-background-color),var(--ag-range-selection-background-color)),linear-gradient(var(--ag-range-selection-background-color),var(--ag-range-selection-background-color))}.ag-cell.ag-cell-range-selected.ag-cell-range-top:not(.ag-cell-range-single-cell){border-top-color:var(--ag-range-selection-border-color);border-top-style:var(--ag-range-selection-border-style)}.ag-cell.ag-cell-range-selected.ag-cell-range-right:not(.ag-cell-range-single-cell){border-right-color:var(--ag-range-selection-border-color);border-right-style:var(--ag-range-selection-border-style)}.ag-cell.ag-cell-range-selected.ag-cell-range-bottom:not(.ag-cell-range-single-cell){border-bottom-color:var(--ag-range-selection-border-color);border-bottom-style:var(--ag-range-selection-border-style)}.ag-cell.ag-cell-range-selected.ag-cell-range-left:not(.ag-cell-range-single-cell){border-left-color:var(--ag-range-selection-border-color);border-left-style:var(--ag-range-selection-border-style)}.ag-ltr .ag-cell-focus:not(.ag-cell-range-selected):focus-within,.ag-ltr .ag-cell-range-single-cell,.ag-ltr .ag-cell-range-single-cell.ag-cell-range-handle,.ag-ltr .ag-context-menu-open .ag-cell-focus:not(.ag-cell-range-selected),.ag-ltr .ag-full-width-row.ag-row-focus:focus .ag-cell-wrapper.ag-row-group,.ag-rtl .ag-cell-focus:not(.ag-cell-range-selected):focus-within,.ag-rtl .ag-cell-range-single-cell,.ag-rtl .ag-cell-range-single-cell.ag-cell-range-handle,.ag-rtl .ag-context-menu-open .ag-cell-focus:not(.ag-cell-range-selected),.ag-rtl .ag-full-width-row.ag-row-focus:focus .ag-cell-wrapper.ag-row-group{border:1px solid;border-color:var(--ag-range-selection-border-color);border-style:var(--ag-range-selection-border-style);outline:initial}.ag-cell.ag-selection-fill-top,.ag-cell.ag-selection-fill-top.ag-cell-range-selected{border-top:1px dashed;border-top-color:var(--ag-range-selection-border-color)}.ag-ltr .ag-cell.ag-selection-fill-right,.ag-ltr .ag-cell.ag-selection-fill-right.ag-cell-range-selected{border-right:1px dashed var(--ag-range-selection-border-color)!important}.ag-rtl .ag-cell.ag-selection-fill-right,.ag-rtl .ag-cell.ag-selection-fill-right.ag-cell-range-selected{border-left:1px dashed var(--ag-range-selection-border-color)!important}.ag-cell.ag-selection-fill-bottom,.ag-cell.ag-selection-fill-bottom.ag-cell-range-selected{border-bottom:1px dashed;border-bottom-color:var(--ag-range-selection-border-color)}.ag-ltr .ag-cell.ag-selection-fill-left,.ag-ltr .ag-cell.ag-selection-fill-left.ag-cell-range-selected{border-left:1px dashed var(--ag-range-selection-border-color)!important}.ag-rtl .ag-cell.ag-selection-fill-left,.ag-rtl .ag-cell.ag-selection-fill-left.ag-cell-range-selected{border-right:1px dashed var(--ag-range-selection-border-color)!important}.ag-fill-handle,.ag-range-handle{background-color:var(--ag-range-selection-border-color);bottom:-1px;height:6px;position:absolute;width:6px}.ag-ltr .ag-fill-handle,.ag-ltr .ag-range-handle{right:-1px}.ag-rtl .ag-fill-handle,.ag-rtl .ag-range-handle{left:-1px}.ag-fill-handle{cursor:cell}.ag-ltr .ag-range-handle{cursor:nwse-resize}.ag-rtl .ag-range-handle{cursor:nesw-resize}.ag-input-wrapper,.ag-picker-field-wrapper{align-items:center;display:flex;flex:1 1 auto;line-height:normal;position:relative}.ag-input-field{align-items:center;display:flex;flex-direction:row}.ag-input-field-input{flex:1 1 auto}.ag-floating-filter-input .ag-input-field-input[type=date]{width:1px}.ag-input-field-input{min-width:0;width:100%}.ag-column-select-header-filter-wrapper .ag-input-wrapper:before,.ag-filter-filter .ag-input-wrapper:before,.ag-filter-toolpanel-search .ag-input-wrapper:before,.ag-mini-filter .ag-input-wrapper:before{background-color:currentColor;content:"";display:block;height:12px;-webkit-mask-image:url("data:image/svg+xml;charset=utf-8;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMiIgaGVpZ2h0PSIxMiIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjMDAwIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIHN0cm9rZS13aWR0aD0iMS41Ij48cGF0aCBkPSJNNS4zIDlhMy43IDMuNyAwIDEgMCAwLTcuNSAzLjcgMy43IDAgMCAwIDAgNy41Wk0xMC41IDEwLjUgOC4zIDguMiIvPjwvc3ZnPg==");mask-image:url("data:image/svg+xml;charset=utf-8;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMiIgaGVpZ2h0PSIxMiIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjMDAwIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIHN0cm9rZS13aWR0aD0iMS41Ij48cGF0aCBkPSJNNS4zIDlhMy43IDMuNyAwIDEgMCAwLTcuNSAzLjcgMy43IDAgMCAwIDAgNy41Wk0xMC41IDEwLjUgOC4zIDguMiIvPjwvc3ZnPg==");-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;opacity:50%;position:absolute;width:12px}.ag-ltr .ag-column-select-header-filter-wrapper .ag-input-wrapper:before,.ag-ltr .ag-filter-filter .ag-input-wrapper:before,.ag-ltr .ag-filter-toolpanel-search .ag-input-wrapper:before,.ag-ltr .ag-mini-filter .ag-input-wrapper:before{margin-left:var(--ag-grid-size)}.ag-rtl .ag-column-select-header-filter-wrapper .ag-input-wrapper:before,.ag-rtl .ag-filter-filter .ag-input-wrapper:before,.ag-rtl .ag-filter-toolpanel-search .ag-input-wrapper:before,.ag-rtl .ag-mini-filter .ag-input-wrapper:before{margin-right:var(--ag-grid-size)}.ag-ltr .ag-column-select-header-filter-wrapper input.ag-number-field-input,.ag-ltr .ag-column-select-header-filter-wrapper input.ag-text-field-input,.ag-ltr .ag-filter-filter input.ag-number-field-input,.ag-ltr .ag-filter-filter input.ag-text-field-input,.ag-ltr .ag-filter-toolpanel-search input.ag-number-field-input,.ag-ltr .ag-filter-toolpanel-search input.ag-text-field-input,.ag-ltr .ag-mini-filter input.ag-number-field-input,.ag-ltr .ag-mini-filter input.ag-text-field-input{padding-left:calc(var(--ag-grid-size)*1.5 + 12px)}.ag-rtl .ag-column-select-header-filter-wrapper input.ag-number-field-input,.ag-rtl .ag-column-select-header-filter-wrapper input.ag-text-field-input,.ag-rtl .ag-filter-filter input.ag-number-field-input,.ag-rtl .ag-filter-filter input.ag-text-field-input,.ag-rtl .ag-filter-toolpanel-search input.ag-number-field-input,.ag-rtl .ag-filter-toolpanel-search input.ag-text-field-input,.ag-rtl .ag-mini-filter input.ag-number-field-input,.ag-rtl .ag-mini-filter input.ag-text-field-input{padding-right:calc(var(--ag-grid-size)*1.5 + 12px)}.ag-advanced-filter-header{align-items:center;background-color:var(--ag-header-background-color);border-bottom:var(--ag-header-row-border);display:flex;padding-left:var(--ag-cell-horizontal-padding);padding-right:var(--ag-cell-horizontal-padding);position:relative}.ag-advanced-filter{align-items:center;display:flex;width:100%}.ag-advanced-filter-apply-button,.ag-advanced-filter-builder-button{line-height:normal;white-space:nowrap}.ag-ltr .ag-advanced-filter-apply-button,.ag-ltr .ag-advanced-filter-builder-button{margin-left:calc(var(--ag-grid-size)*2)}.ag-rtl .ag-advanced-filter-apply-button,.ag-rtl .ag-advanced-filter-builder-button{margin-right:calc(var(--ag-grid-size)*2)}.ag-advanced-filter-builder-button{align-items:center;background-color:unset;border:0;display:flex;font-size:var(--ag-font-size);font-weight:600;padding:var(--ag-grid-size)}.ag-advanced-filter-builder-button:hover:not(:disabled){background-color:var(--ag-row-hover-color)}.ag-advanced-filter-builder-button:not(:disabled){cursor:pointer}.ag-ltr .ag-advanced-filter-builder-button-label{margin-left:var(--ag-grid-size)}.ag-rtl .ag-advanced-filter-builder-button-label{margin-right:var(--ag-grid-size)}.ag-advanced-filter-builder{background-color:var(--ag-chrome-background-color);display:flex;flex-direction:column;-webkit-user-select:none;-moz-user-select:none;user-select:none;width:100%}.ag-advanced-filter-builder-list{flex:1;overflow:auto}.ag-advanced-filter-builder-button-panel{border-top:var(--ag-advanced-filter-builder-button-bar-border);display:flex;justify-content:flex-end;padding:var(--ag-widget-container-vertical-padding) var(--ag-widget-container-horizontal-padding)}.ag-ltr .ag-advanced-filter-builder .ag-advanced-filter-builder-button-panel .ag-advanced-filter-builder-apply-button,.ag-ltr .ag-advanced-filter-builder .ag-advanced-filter-builder-button-panel .ag-advanced-filter-builder-cancel-button{margin-left:calc(var(--ag-grid-size)*2)}.ag-rtl .ag-advanced-filter-builder .ag-advanced-filter-builder-button-panel .ag-advanced-filter-builder-apply-button,.ag-rtl .ag-advanced-filter-builder .ag-advanced-filter-builder-button-panel .ag-advanced-filter-builder-cancel-button{margin-right:calc(var(--ag-grid-size)*2)}.ag-advanced-filter-builder-item-wrapper{align-items:center;display:flex;flex:1 1 auto;justify-content:space-between;overflow:hidden}.ag-ltr .ag-advanced-filter-builder-item-wrapper{padding-left:calc(var(--ag-icon-size)/2);padding-right:var(--ag-icon-size)}.ag-rtl .ag-advanced-filter-builder-item-wrapper{padding-left:var(--ag-icon-size);padding-right:calc(var(--ag-icon-size)/2)}.ag-virtual-list-viewport .ag-advanced-filter-builder-item-wrapper .ag-tab-guard{position:absolute}.ag-advanced-filter-builder-item-tree-lines>*{width:var(--ag-advanced-filter-builder-indent-size)}.ag-advanced-filter-builder-item-tree-lines .ag-advanced-filter-builder-item-tree-line-root{width:var(--ag-icon-size)}.ag-advanced-filter-builder-item-tree-lines .ag-advanced-filter-builder-item-tree-line-root:before{height:50%;top:50%}.ag-advanced-filter-builder-item-tree-line-horizontal,.ag-advanced-filter-builder-item-tree-line-vertical,.ag-advanced-filter-builder-item-tree-line-vertical-bottom,.ag-advanced-filter-builder-item-tree-line-vertical-top{align-items:center;display:flex;height:100%;position:relative}.ag-advanced-filter-builder-item-tree-line-horizontal:after,.ag-advanced-filter-builder-item-tree-line-horizontal:before,.ag-advanced-filter-builder-item-tree-line-vertical-bottom:after,.ag-advanced-filter-builder-item-tree-line-vertical-bottom:before,.ag-advanced-filter-builder-item-tree-line-vertical-top:after,.ag-advanced-filter-builder-item-tree-line-vertical-top:before,.ag-advanced-filter-builder-item-tree-line-vertical:after,.ag-advanced-filter-builder-item-tree-line-vertical:before{content:"";height:100%;position:absolute}.ag-advanced-filter-builder-item-tree-line-horizontal:after{border-bottom:1px solid var(--ag-border-color);height:50%;top:0;width:calc(var(--ag-advanced-filter-builder-indent-size) - var(--ag-icon-size))}.ag-ltr .ag-advanced-filter-builder-item-tree-line-horizontal:after{left:calc(var(--ag-icon-size)/2)}.ag-rtl .ag-advanced-filter-builder-item-tree-line-horizontal:after{right:calc(var(--ag-icon-size)/2)}.ag-advanced-filter-builder-item-tree-line-vertical:before{top:0;width:calc(var(--ag-advanced-filter-builder-indent-size) - var(--ag-icon-size)/2)}.ag-ltr .ag-advanced-filter-builder-item-tree-line-vertical:before{border-left:1px solid var(--ag-border-color);left:calc(var(--ag-icon-size)/2)}.ag-rtl .ag-advanced-filter-builder-item-tree-line-vertical:before{border-right:1px solid var(--ag-border-color);right:calc(var(--ag-icon-size)/2)}.ag-advanced-filter-builder-item-tree-line-vertical-top:before{height:50%;top:0;width:calc(var(--ag-advanced-filter-builder-indent-size) - var(--ag-icon-size)/2)}.ag-ltr .ag-advanced-filter-builder-item-tree-line-vertical-top:before{border-left:1px solid var(--ag-border-color);left:calc(var(--ag-icon-size)/2)}.ag-rtl .ag-advanced-filter-builder-item-tree-line-vertical-top:before{border-right:1px solid var(--ag-border-color);right:calc(var(--ag-icon-size)/2)}.ag-advanced-filter-builder-item-tree-line-vertical-bottom:before{height:calc(50% - var(--ag-icon-size)*1.5/2);top:calc(50% + var(--ag-icon-size)*1.5/2);width:calc(var(--ag-icon-size)/2)}.ag-ltr .ag-advanced-filter-builder-item-tree-line-vertical-bottom:before{border-left:1px solid var(--ag-border-color);left:calc(var(--ag-icon-size)/2)}.ag-rtl .ag-advanced-filter-builder-item-tree-line-vertical-bottom:before{border-right:1px solid var(--ag-border-color);right:calc(var(--ag-icon-size)/2)}.ag-advanced-filter-builder-item-condition{padding-bottom:var(--ag-grid-size);padding-top:var(--ag-grid-size)}.ag-advanced-filter-builder-item,.ag-advanced-filter-builder-item-buttons,.ag-advanced-filter-builder-item-condition,.ag-advanced-filter-builder-item-tree-lines,.ag-advanced-filter-builder-pill,.ag-advanced-filter-builder-pill-wrapper{align-items:center;display:flex;height:100%}.ag-advanced-filter-builder-pill-wrapper{margin:0 var(--ag-grid-size)}.ag-advanced-filter-builder-pill{border-radius:var(--ag-border-radius);min-height:calc(100% - var(--ag-grid-size)*3);min-width:calc(var(--ag-grid-size)*2);padding:var(--ag-grid-size) calc(var(--ag-grid-size)*2);position:relative}.ag-ltr .ag-advanced-filter-builder-pill .ag-picker-field-display{margin-right:var(--ag-grid-size)}.ag-rtl .ag-advanced-filter-builder-pill .ag-picker-field-display{margin-left:var(--ag-grid-size)}.ag-advanced-filter-builder-pill .ag-advanced-filter-builder-value-number{font-family:monospace;font-weight:700}.ag-advanced-filter-builder-pill .ag-advanced-filter-builder-value-empty{color:var(--ag-subtle-text-color)}.ag-advanced-filter-builder-item-button:focus-visible,.ag-advanced-filter-builder-pill:focus-visible{shadow:var(--ag-focus-shadow)}.ag-advanced-filter-builder-pill-display{font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ag-advanced-filter-builder-join-pill{background-color:var(--ag-advanced-filter-builder-join-pill-color);cursor:pointer}.ag-advanced-filter-builder-column-pill{background-color:var(--ag-advanced-filter-builder-column-pill-color);cursor:pointer}.ag-advanced-filter-builder-option-pill{background-color:var(--ag-advanced-filter-builder-option-pill-color);cursor:pointer}.ag-advanced-filter-builder-value-pill{background-color:var(--ag-advanced-filter-builder-value-pill-color);cursor:text;max-width:140px}.ag-advanced-filter-builder-value-pill .ag-advanced-filter-builder-pill-display{display:block}.ag-advanced-filter-builder-item-buttons>*{margin:0 calc(var(--ag-grid-size)*.5)}.ag-advanced-filter-builder-item-button{color:var(--ag-subtle-text-color);cursor:pointer;position:relative}.ag-advanced-filter-builder-item-button-disabled{cursor:default;opacity:.5}.ag-advanced-filter-builder-virtual-list-container{top:var(--ag-grid-size)}.ag-advanced-filter-builder-virtual-list-item{cursor:default;display:flex;height:var(--ag-list-item-height)}.ag-advanced-filter-builder-virtual-list-item:hover{background-color:var(--ag-row-hover-color)}.ag-advanced-filter-builder-virtual-list-item:hover .ag-advanced-filter-builder-item-button{opacity:100%}.ag-advanced-filter-builder-validation .ag-advanced-filter-builder-invalid,.ag-advanced-filter-builder-virtual-list-item-highlight .ag-advanced-filter-builder-item-button:focus-visible{opacity:100%}.ag-advanced-filter-builder-invalid{color:var(--ag-invalid-color);cursor:default;margin:0 var(--ag-grid-size)}.ag-cell-inline-editing{border-radius:var(--ag-border-radius);padding:0;z-index:1}.ag-cell-inline-editing .ag-cell-edit-wrapper,.ag-cell-inline-editing .ag-cell-editor,.ag-cell-inline-editing .ag-cell-editor .ag-wrapper,.ag-cell-inline-editing .ag-cell-editor input,.ag-cell-inline-editing .ag-cell-wrapper{height:100%;line-height:normal;width:100%}.ag-autocomplete-list-popup,.ag-popup-editor .ag-large-text{background-color:var(--ag-background-color);border-radius:var(--ag-border-radius);box-shadow:var(--ag-dropdown-shadow);padding:0}.ag-large-text-input{height:auto;padding:var(--ag-cell-horizontal-padding)}.ag-rtl .ag-large-text-input textarea{resize:none}.ag-checkbox-edit{padding-left:var(--ag-cell-horizontal-padding);padding-right:var(--ag-cell-horizontal-padding)}.ag-chart{height:100%;width:100%}.ag-chart,.ag-chart-components-wrapper{display:flex;overflow:hidden;position:relative}.ag-chart-components-wrapper{flex:1 1 auto}.ag-chart-canvas-wrapper{flex:1 1 auto;overflow:hidden;position:relative}.ag-chart-menu{display:flex;flex-direction:column;position:absolute;top:16px}.ag-ltr .ag-chart-menu{right:20px}.ag-rtl .ag-chart-menu{left:20px}.ag-chart-docked-container{min-width:var(--ag-chart-menu-panel-width);position:relative}.ag-chart-menu-hidden~.ag-chart-docked-container{display:none}.ag-chart-tabbed-menu{display:flex;flex-direction:column;height:100%;overflow:hidden;width:100%}.ag-chart-tabbed-menu-header{cursor:default;flex:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.ag-chart-tabbed-menu-body{align-items:stretch;display:flex;flex:1 1 auto;overflow:hidden}.ag-chart-tab{overflow:hidden;overflow-y:auto;width:100%}.ag-chart-settings{overflow-x:hidden}.ag-chart-settings-wrapper{display:flex;flex-direction:column;height:100%;overflow:hidden;position:relative;width:100%}.ag-chart-settings-nav-bar{align-items:center;display:flex;height:30px;padding:0 10px;-webkit-user-select:none;-moz-user-select:none;user-select:none;width:100%}.ag-chart-settings-card-selector{align-items:center;display:flex;flex:1 1 auto;height:100%;justify-content:space-around;padding:0 10px}.ag-chart-settings-card-item{background-color:var(--ag-foreground-color);border-radius:4px;cursor:pointer;height:10px;height:8px;position:relative;width:10px;width:8px}.ag-chart-settings-card-item.ag-not-selected{opacity:.2}.ag-chart-settings-card-item:before{background-color:transparent;content:" ";display:block;height:20px;left:50%;margin-left:-10px;margin-top:-10px;position:absolute;top:50%;width:20px}.ag-chart-settings-card-item.ag-selected{background-color:var(--ag-accent-color)}.ag-chart-settings-next,.ag-chart-settings-prev{flex:none;position:relative}.ag-chart-settings-next:focus-within,.ag-chart-settings-prev:focus-within{border-radius:1px;box-shadow:var(--ag-focus-shadow)}.ag-chart-settings-next-button,.ag-chart-settings-prev-button{cursor:pointer;height:100%;left:0;opacity:0;position:absolute;top:0;width:100%}.ag-chart-settings-mini-charts-container{flex:1 1 auto;overflow-x:hidden;overflow-y:auto;position:relative}.ag-chart-settings-mini-wrapper{display:flex;flex-direction:column;left:0;min-height:100%;overflow:hidden;position:absolute;top:0;width:100%}.ag-chart-settings-mini-wrapper.ag-animating{transition:left .3s;transition-timing-function:ease-in-out}.ag-chart-mini-thumbnail{cursor:pointer}.ag-chart-mini-thumbnail-canvas{display:block}.ag-chart-advanced-settings-wrapper,.ag-chart-data-wrapper,.ag-chart-format-wrapper{display:flex;flex-direction:column;padding-bottom:16px;position:relative;-webkit-user-select:none;-moz-user-select:none;user-select:none}.ag-chart-advanced-settings-wrapper,.ag-chart-data-wrapper{height:100%;overflow-y:auto}.ag-chart-advanced-settings{background-color:var(--ag-chrome-background-color)}.ag-chart-advanced-settings,.ag-chart-advanced-settings-wrapper{width:100%}.ag-chart-advanced-settings-wrapper{padding-bottom:0}.ag-chart-advanced-settings-section,.ag-chart-data-section,.ag-chart-format-section{display:flex;margin:0}.ag-chart-advanced-settings-section{border-bottom:1px solid var(--ag-border-color)}.ag-chart-empty-text{align-items:center;background-color:var(--ag-background-color);display:flex;height:100%;justify-content:center;top:0;width:100%}.ag-chart .ag-chart-menu{display:none}.ag-chart-menu-hidden:hover .ag-chart-menu{display:block}.ag-chart .ag-chart-menu-wrapper .ag-chart-menu{display:flex;flex-direction:row;gap:20px;top:8px;width:auto}.ag-ltr .ag-chart .ag-chart-menu-wrapper .ag-chart-menu{justify-content:right;right:calc(var(--ag-cell-horizontal-padding) + var(--ag-grid-size) - 4px)}.ag-rtl .ag-chart .ag-chart-menu-wrapper .ag-chart-menu{justify-content:left;left:calc(var(--ag-cell-horizontal-padding) + var(--ag-grid-size) - 4px)}.ag-charts-font-size-color{align-self:stretch;display:flex;justify-content:space-between}.ag-charts-data-group-item{position:relative}.ag-charts-data-group-item:not(:last-child){margin-bottom:var(--ag-grid-size)}.ag-chart-menu{background:var(--ag-background-color)}.ag-chart-menu,.ag-chart-menu-icon{border-radius:var(--ag-border-radius)}.ag-chart-menu-icon{cursor:pointer;margin:2px 0;opacity:.5;opacity:.8}.ag-chart-menu-icon:hover{opacity:1}.ag-chart-menu-toolbar-button{background-color:unset;border:0;border-radius:1px;padding:0 2px}.ag-chart-mini-thumbnail{border:1px solid var(--ag-border-color);border-radius:5px}.ag-chart-mini-thumbnail.ag-selected{border-color:var(--ag-accent-color);border-width:2px}.ag-chart-mini-thumbnail:focus-visible{border-color:var(--ag-accent-color);box-shadow:var(--ag-focus-shadow)}.ag-chart-data-column-drag-handle{margin-left:var(--ag-grid-size)}.ag-charts-data-group-title-bar,.ag-charts-format-top-level-group-title-bar,.ag-charts-settings-group-title-bar{position:relative}.ag-charts-advanced-settings-top-level-group-title-bar{background-color:unset;position:relative}.ag-charts-advanced-settings-top-level-group-title-bar:focus-visible,.ag-charts-data-group-title-bar:focus-visible,.ag-charts-format-top-level-group-title-bar:focus-visible,.ag-charts-settings-group-title-bar:focus-visible{box-shadow:inset var(--ag-focus-shadow)}.ag-charts-data-group-container{padding:calc(var(--ag-widget-container-vertical-padding)*.5) var(--ag-widget-container-horizontal-padding)}.ag-charts-data-group-container .ag-charts-data-group-item:not(.ag-charts-format-sub-level-group):not(.ag-pill-select):not(.ag-select){height:var(--ag-list-item-height)}.ag-charts-data-group-container .ag-charts-data-group-item.ag-picker-field{margin-top:var(--ag-grid-size)}.ag-charts-advanced-settings-top-level-group-container,.ag-charts-format-top-level-group-container{margin-left:calc(var(--ag-grid-size)*2);padding:var(--ag-grid-size)}.ag-charts-advanced-settings-top-level-group-item,.ag-charts-format-top-level-group-item{margin:var(--ag-grid-size) 0}.ag-charts-format-sub-level-group-container{display:flex;flex-direction:column;gap:var(--ag-widget-vertical-spacing);padding:var(--ag-widget-container-vertical-padding) var(--ag-widget-container-horizontal-padding)}.ag-charts-settings-group-container{display:grid;grid-template-columns:60px 1fr 60px 1fr 60px;padding:var(--ag-grid-size);row-gap:8px}.ag-charts-settings-group-container .ag-chart-mini-thumbnail:nth-child(3n+1){grid-column:1}.ag-charts-settings-group-container .ag-chart-mini-thumbnail:nth-child(3n+2){grid-column:3}.ag-charts-settings-group-container .ag-chart-mini-thumbnail:nth-child(3n+3){grid-column:5}.ag-chart-data-section,.ag-chart-format-section{display:flex;margin:0}.ag-chart-menu-panel{background-color:var(--ag-chrome-background-color)}.ag-ltr .ag-chart-menu-panel{border-left:1px solid var(--ag-border-color)}.ag-rtl .ag-chart-menu-panel{border-right:1px solid var(--ag-border-color)}.ag-chart-tabbed-menu-body{position:relative}.ag-chart-tabbed-menu-body:after{background:linear-gradient(var(--ag-background-color),transparent);content:"";display:block;height:16px;left:0;position:absolute;right:0;top:0}.ag-charts-data-group-title-bar,.ag-charts-format-top-level-group-title-bar,.ag-charts-settings-group-container,.ag-charts-settings-group-title-bar{border-top:none;font-weight:500;padding:0 calc(var(--ag-grid-size)*1.5)}.ag-chart-settings-nav-bar{border-top:1px solid var(--ag-border-color)}.ag-charts-format-sub-level-group-title-bar{background:none;font-weight:500}.ag-chart-data-section .ag-label:not(.ag-group-title-bar),.ag-chart-format-section .ag-label:not(.ag-group-title-bar){color:var(--ag-chart-menu-label-color)}.ag-chart-data-section .ag-label-align-top .ag-label,.ag-chart-format-section .ag-label-align-top .ag-label{margin-bottom:var(--ag-widget-vertical-spacing);margin-top:calc(var(--ag-widget-vertical-spacing)*.5)}.ag-chart-data-section .ag-slider.ag-label-align-top .ag-label,.ag-chart-format-section .ag-slider.ag-label-align-top .ag-label{margin-bottom:0}.ag-chart-data-section label,.ag-chart-format-section label{display:inline-block}.ag-chart-data-wrapper,.ag-chart-format-wrapper,.ag-charts-data-group-container,.ag-charts-data-group-title-bar,.ag-charts-format-sub-level-group,.ag-charts-format-sub-level-group-container,.ag-charts-format-sub-level-group-container>*,.ag-charts-format-sub-level-group-item:last-child,.ag-charts-format-sub-level-group-title-bar,.ag-charts-format-top-level-group,.ag-charts-format-top-level-group .ag-charts-format-top-level-group-container,.ag-charts-format-top-level-group-item,.ag-charts-format-top-level-group-title-bar,.ag-charts-settings-group-container,.ag-charts-settings-group-title-bar{margin:0;padding:0}.ag-charts-data-group,.ag-charts-format-top-level-group{border-top:1px solid var(--ag-border-color)}.ag-charts-data-group-title-bar,.ag-charts-format-top-level-group-title-bar,.ag-charts-settings-group-title-bar{padding:var(--ag-widget-container-vertical-padding) var(--ag-widget-container-horizontal-padding)}.ag-charts-data-group .ag-charts-data-group-container,.ag-charts-format-top-level-group .ag-charts-format-top-level-group-container,.ag-charts-settings-group .ag-charts-settings-group-container{padding:0 var(--ag-widget-container-horizontal-padding)}.ag-charts-format-sub-level-group-title-bar{padding:var(--ag-widget-vertical-spacing) 0}.ag-charts-format-sub-level-group-container{padding-bottom:var(--ag-widget-container-vertical-padding);padding-top:var(--ag-widget-vertical-spacing)}.ag-charts-format-sub-level-group-container>*,.ag-charts-format-sub-level-no-header-group-container>*,.ag-charts-format-top-level-group-container>*{margin-bottom:var(--ag-widget-vertical-spacing)}.ag-chart-advanced-settings-section,.ag-chart-settings-mini-wrapper,.ag-charts-data-group-item{padding-bottom:var(--ag-widget-container-vertical-padding)}.ag-chart-advanced-settings-section{padding-top:var(--ag-widget-container-vertical-padding)}.ag-charts-advanced-settings-top-level-group .ag-charts-advanced-settings-top-level-group-container,.ag-charts-advanced-settings-top-level-group .ag-charts-advanced-settings-top-level-group-title-bar{padding:0 var(--ag-widget-container-horizontal-padding)}.ag-charts-advanced-settings-top-level-group-container{margin:0}.ag-charts-advanced-settings-top-level-group-item{margin-bottom:0;margin-top:calc(var(--ag-widget-vertical-spacing)*2)}.ag-chart-menu{--ag-icon-size:20px;background-color:color-mix(in srgb,transparent,var(--ag-background-color) 30%);padding:4px 2px}.ag-chart-settings-card-item.ag-not-selected:hover{opacity:.35}.ag-column-drop{align-items:center;display:inline-flex;overflow:auto;position:relative;width:100%}.ag-column-drop-cell,.ag-column-drop-list{align-items:center;display:flex}.ag-column-drop-cell{gap:var(--ag-grid-size);position:relative}.ag-column-drop-cell-text{flex:1 1 auto;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ag-column-drop-vertical{align-items:stretch;display:flex;flex-direction:column;overflow:hidden}.ag-column-drop-vertical-title-bar{align-items:center;display:flex;flex:none}.ag-column-drop-vertical-list{align-items:stretch;flex-direction:column;flex-grow:1;overflow-x:auto;position:relative}.ag-column-drop-vertical-list>*{flex:none}.ag-column-drop-empty .ag-column-drop-vertical-list{overflow:hidden}.ag-column-drop-vertical-empty-message{display:block}.ag-column-drop.ag-column-drop-horizontal{overflow:hidden;white-space:nowrap}.ag-column-drop-cell-button{cursor:pointer}.ag-column-drop-wrapper{display:flex}.ag-column-drop-horizontal-half-width{display:inline-block;width:50%!important}.ag-column-drop-cell{background:var(--ag-column-drop-cell-background-color);border:var(--ag-column-drop-cell-border);border-radius:500px;padding:calc(var(--ag-grid-size)*.5)}.ag-ltr .ag-column-drop-cell{padding-left:calc(var(--ag-grid-size)*.75)}.ag-rtl .ag-column-drop-cell{padding-right:calc(var(--ag-grid-size)*.75)}.ag-column-drop-cell:focus-visible{box-shadow:var(--ag-focus-shadow)}.ag-column-drop-cell-button{min-width:calc(var(--ag-grid-size)*4)}.ag-column-drop-cell-ghost{opacity:.5}.ag-column-drop-horizontal{gap:var(--ag-cell-widget-spacing);height:var(--ag-header-height)}.ag-ltr .ag-column-drop-horizontal{padding-left:var(--ag-cell-horizontal-padding)}.ag-rtl .ag-column-drop-horizontal{padding-right:var(--ag-cell-horizontal-padding)}.ag-column-drop-horizontal-list{gap:var(--ag-cell-widget-spacing)}.ag-column-drop-vertical-list{padding-bottom:var(--ag-grid-size);padding-left:var(--ag-grid-size);padding-right:var(--ag-grid-size)}.ag-column-drop-vertical-cell{margin-top:var(--ag-grid-size)}.ag-ltr .ag-column-drop-vertical-icon{margin-right:var(--ag-widget-horizontal-spacing)}.ag-rtl .ag-column-drop-vertical-icon{margin-left:var(--ag-widget-horizontal-spacing)}.ag-column-drop-vertical-empty-message{bottom:0;left:0;margin-top:var(--ag-grid-size);overflow:hidden;position:absolute;right:0;top:0}.ag-select-agg-func-popup{background:var(--ag-background-color);border:1px solid var(--ag-border-color);border-radius:var(--ag-border-radius);box-shadow:var(--ag-dropdown-shadow);height:calc(var(--ag-grid-size)*5*3.5);padding:0;position:absolute}.ag-select-agg-func-virtual-list-item{cursor:default}.ag-ltr .ag-select-agg-func-virtual-list-item{padding-left:calc(var(--ag-grid-size)*2)}.ag-rtl .ag-select-agg-func-virtual-list-item{padding-right:calc(var(--ag-grid-size)*2)}.ag-select-agg-func-virtual-list-item:hover{background-color:var(--ag-selected-row-background-color)}.ag-select-agg-func-virtual-list-item:focus-visible{shadow:var(--ag-focus-shadow)}.ag-sort-indicator-container{display:contents}.ag-ltr .ag-sort-indicator-icon{padding-left:var(--ag-grid-size)}.ag-rtl .ag-sort-indicator-icon{padding-right:var(--ag-grid-size)}.ag-column-drop-horizontal{background-color:var(--ag-header-background-color);border-bottom:var(--ag-header-row-border)}.ag-ltr .ag-column-drop-horizontal-half-width:not(:last-child){border-right:var(--ag-column-border)}.ag-rtl .ag-column-drop-horizontal-half-width:not(:last-child){border-left:var(--ag-column-border)}.ag-column-drop-cell-button{min-width:0;opacity:.75}.ag-column-drop-cell-button:hover{opacity:1}.ag-column-drop-vertical{min-height:75px}.ag-column-drop-vertical-title-bar{padding:var(--ag-widget-container-vertical-padding) calc(var(--ag-grid-size)*2) 0}.ag-column-drop-vertical-empty-message{align-items:center;border:1px dashed;border-color:var(--ag-border-color);display:flex;justify-content:center;margin:calc(var(--ag-grid-size)*1.5) calc(var(--ag-grid-size)*2);padding:calc(var(--ag-grid-size)*2)}.ag-column-select{display:flex;flex:3 1 0px;flex-direction:column;overflow:hidden;position:relative}.ag-column-select-header{flex:none;height:var(--ag-header-height);padding-left:var(--ag-widget-container-horizontal-padding);padding-right:var(--ag-widget-container-horizontal-padding)}.ag-column-select-column,.ag-column-select-column-group,.ag-column-select-header{align-items:center;display:flex;gap:var(--ag-widget-horizontal-spacing);position:relative}.ag-column-select-column,.ag-column-select-column-group{height:100%}.ag-column-select-virtual-list-item:focus-visible{box-shadow:inset var(--ag-focus-shadow)}.ag-column-select-header-icon{border-radius:var(--ag-border-radius);cursor:pointer;height:var(--ag-icon-size);position:relative;width:var(--ag-icon-size)}.ag-column-select-header-icon:focus-visible{box-shadow:var(--ag-focus-shadow)}.ag-column-select-header-filter-wrapper{flex:1 1 auto}.ag-column-select-header-filter{width:100%}.ag-column-select-list{flex:1 1 0px;overflow:hidden}.ag-ltr .ag-column-select-column,.ag-ltr .ag-column-select-column-group{padding-left:calc(var(--ag-indentation-level)*var(--ag-column-select-indent-size))}.ag-rtl .ag-column-select-column,.ag-rtl .ag-column-select-column-group{padding-right:calc(var(--ag-indentation-level)*var(--ag-column-select-indent-size))}.ag-ltr .ag-column-select-add-group-indent{margin-left:calc(var(--ag-icon-size) + var(--ag-grid-size)*1.5)}.ag-rtl .ag-column-select-add-group-indent{margin-right:calc(var(--ag-icon-size) + var(--ag-grid-size)*1.5)}.ag-column-select-column-group:not(:last-child),.ag-column-select-column:not(:last-child){margin-bottom:var(--ag-widget-vertical-spacing)}.ag-column-select-column-group-readonly,.ag-column-select-column-readonly{opacity:.5;pointer-events:none}.ag-column-select-virtual-list-viewport{padding:calc(var(--ag-widget-container-vertical-padding)*.5) 0}.ag-column-select-virtual-list-item{padding:0 var(--ag-widget-container-horizontal-padding)}.ag-column-select-column-label{flex:1 1 auto;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ag-column-select-checkbox{display:flex}.ag-set-filter{--ag-indentation-level:0}.ag-set-filter-item{align-items:center;display:flex;height:100%}.ag-set-filter-item-checkbox{display:flex;height:100%;width:100%}.ag-set-filter-group-icons{display:block}.ag-set-filter-group-icons>*{cursor:pointer}.ag-filter-body-wrapper{display:flex;flex-direction:column}.ag-filter-filter{flex:1 1 0px}.ag-filter-condition{display:flex;justify-content:center}.ag-floating-filter-body{display:flex;flex:1 1 auto;height:100%;position:relative}.ag-floating-filter-full-body{align-items:center;display:flex;flex:1 1 auto;height:100%;overflow:hidden;width:100%}.ag-floating-filter-full-body>div{flex:1 1 auto}.ag-floating-filter-input{align-items:center;display:flex;width:100%}.ag-floating-filter-input>*{flex:1 1 auto}.ag-floating-filter-button{display:flex;flex:none}.ag-set-floating-filter-input input[disabled]{pointer-events:none}.ag-floating-filter-button-button{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:transparent;border:none;height:var(--ag-icon-size);width:var(--ag-icon-size)}.ag-filter-loading{height:100%;padding:var(--ag-widget-container-vertical-padding) var(--ag-widget-container-horizontal-padding);position:absolute;width:100%;z-index:1}.ag-column-panel{display:flex;flex:1 1 auto;flex-direction:column;overflow:hidden}.ag-pivot-mode-panel{display:flex;height:var(--ag-header-height)}.ag-pivot-mode-select{align-items:center;display:flex}.ag-ltr .ag-pivot-mode-select{margin-left:var(--ag-widget-container-horizontal-padding)}.ag-rtl .ag-pivot-mode-select{margin-right:var(--ag-widget-container-horizontal-padding)}.ag-column-panel-column-select{border-bottom:var(--ag-tool-panel-separator-border);border-top:var(--ag-tool-panel-separator-border)}:where(.ag-column-panel) .ag-column-drop-vertical{flex:1 1 0px;min-height:50px}:where(.ag-column-panel) .ag-column-drop-vertical:where(:not(.ag-last-column-drop)){border-bottom:var(--ag-tool-panel-separator-border)}.ag-dnd-ghost{align-items:center;background-color:var(--ag-drag-ghost-background-color);border:var(--ag-drag-ghost-border);border-radius:var(--ag-border-radius);box-shadow:var(--ag-drag-ghost-shadow);color:var(--ag-text-color);cursor:move;font-weight:500;gap:var(--ag-cell-widget-spacing);height:var(--ag-header-height)!important;max-width:200px;padding-left:var(--ag-cell-horizontal-padding);padding-right:var(--ag-cell-horizontal-padding);position:absolute;text-overflow:ellipsis;transform:translateY(calc(var(--ag-grid-size)*2));z-index:9999}.ag-dnd-ghost,.ag-header{display:flex;overflow:hidden;white-space:nowrap}.ag-header{background-color:var(--ag-header-background-color);border-bottom:var(--ag-header-row-border);color:var(--ag-header-text-color);font-family:var(--ag-header-font-family);font-size:var(--ag-header-font-size);font-weight:var(--ag-header-font-weight);width:100%}.ag-header-row{height:var(--ag-header-height);position:absolute}.ag-header-row:not(:first-child) .ag-header-cell:not(.ag-header-span-height.ag-header-span-total),.ag-header-row:not(:first-child) .ag-header-group-cell.ag-header-group-cell-with-group{border-top:var(--ag-header-row-border)}.ag-header-row:not(.ag-header-row-column-group){overflow:hidden}.ag-header.ag-header-allow-overflow .ag-header-row{overflow:visible}.ag-header-cell,.ag-header-group-cell{align-items:center;display:inline-flex;gap:var(--ag-cell-widget-spacing);height:100%;padding:0 var(--ag-cell-horizontal-padding);position:absolute}:is(.ag-header-cell:not(.ag-floating-filter),.ag-header-group-cell):before{background-color:transparent;content:"";inset:0;position:absolute;transition:background-color var(--ag-header-cell-hover-background-transition-duration)}.ag-header-cell-moving:is(.ag-header-cell:not(.ag-floating-filter),.ag-header-group-cell):before,:is(.ag-header-cell:not(.ag-floating-filter),.ag-header-group-cell):hover:before{background-color:var(--ag-header-cell-hover-background-color)}:where(.ag-header-cell:not(.ag-floating-filter) *,.ag-header-group-cell *){position:relative;z-index:1}.ag-header-cell-filter-button,.ag-header-cell.ag-header-active .ag-header-cell-menu-button{opacity:1}.ag-header-cell-menu-button:not(.ag-header-menu-always-show){opacity:0;transition:opacity .2s}.ag-header-cell-label,.ag-header-group-cell-label{align-items:center;align-self:stretch;display:flex;flex:1 1 auto;gap:var(--ag-grid-size)}.ag-header-cell-label{overflow:hidden;text-overflow:ellipsis}.ag-header-group-cell-label.ag-sticky-label{flex:none;max-width:100%;position:sticky}.ag-ltr .ag-header-group-cell-label.ag-sticky-label{left:var(--ag-cell-horizontal-padding)}.ag-rtl .ag-header-group-cell-label.ag-sticky-label{right:var(--ag-cell-horizontal-padding)}.ag-header-group-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ag-header-cell-text{overflow:hidden;text-overflow:ellipsis;word-break:break-word}.ag-header-cell:not(.ag-header-cell-auto-height) .ag-header-cell-comp-wrapper{align-items:center;display:flex;height:100%}.ag-header-cell-comp-wrapper{width:100%}.ag-header-cell-wrap-text .ag-header-cell-comp-wrapper{white-space:normal}.ag-right-aligned-header .ag-header-cell-label{flex-direction:row-reverse}.ag-floating-filter-button-button,.ag-header-cell-filter-button,.ag-header-cell-menu-button,.ag-header-cell-sortable .ag-header-cell-label,.ag-header-expand-icon,.ag-panel-title-bar-button,.ag-side-button-button{cursor:pointer}.ag-advanced-filter-header-cell:focus-visible,.ag-header-cell:focus-visible,.ag-header-group-cell:focus-visible{box-shadow:inset var(--ag-focus-shadow)}.ag-header-cell:after,.ag-header-group-cell:not(.ag-header-span-height.ag-header-group-cell-no-group):after{content:"";height:var(--ag-header-column-border-height);position:absolute;top:calc(50% - var(--ag-header-column-border-height)*.5);z-index:1}.ag-ltr .ag-header-cell:after,.ag-ltr .ag-header-group-cell:not(.ag-header-span-height.ag-header-group-cell-no-group):after{border-right:var(--ag-header-column-border);right:0}.ag-rtl .ag-header-cell:after,.ag-rtl .ag-header-group-cell:not(.ag-header-span-height.ag-header-group-cell-no-group):after{border-left:var(--ag-header-column-border);left:0}.ag-header-cell-resize{align-items:center;cursor:ew-resize;display:flex;height:100%;position:absolute;top:0;width:8px;z-index:2}.ag-ltr .ag-header-cell-resize{right:-4px}.ag-rtl .ag-header-cell-resize{left:-4px}.ag-header-cell-resize:after{background-color:var(--ag-header-column-resize-handle-color);content:"";display:var(--ag-header-column-resize-handle-display);height:var(--ag-header-column-resize-handle-height);position:absolute;top:calc(50% - var(--ag-header-column-resize-handle-height)*.5);width:var(--ag-header-column-resize-handle-width);z-index:1}.ag-ltr .ag-header-cell-resize:after{left:calc(50% - var(--ag-header-column-resize-handle-width))}.ag-rtl .ag-header-cell-resize:after{right:calc(50% - var(--ag-header-column-resize-handle-width))}.ag-header-cell.ag-header-span-height .ag-header-cell-resize:after{height:calc(100% - var(--ag-grid-size)*4);top:calc(var(--ag-grid-size)*2)}.ag-header-group-cell-no-group.ag-header-span-height .ag-header-cell-resize{display:none}.ag-menu{background-color:var(--ag-menu-background-color);border:var(--ag-menu-border);border-radius:var(--ag-border-radius);box-shadow:var(--ag-menu-shadow);color:var(--ag-menu-text-color);max-height:100%;min-width:180px;overflow-y:auto;position:absolute;-webkit-user-select:none;-moz-user-select:none;user-select:none}.ag-menu-list{cursor:default;display:table;padding:var(--ag-grid-size) 0;width:100%}.ag-menu-option,.ag-menu-separator{display:table-row}.ag-menu-option-part,.ag-menu-separator-part{display:table-cell;vertical-align:middle}.ag-menu-option-text{white-space:nowrap}.ag-menu-option-custom{display:contents}.ag-compact-menu-option{display:flex;flex-wrap:nowrap;width:100%}.ag-compact-menu-option-text{flex:1 1 auto;white-space:nowrap}.ag-menu-separator{height:calc(var(--ag-grid-size)*2 + 1px)}.ag-menu-separator-part:after{border-top:1px solid var(--ag-menu-separator-color);content:"";display:block}.ag-compact-menu-option-active,.ag-menu-option-active{background-color:var(--ag-row-hover-color)}.ag-compact-menu-option-part,.ag-menu-option-part{line-height:var(--ag-icon-size);padding:calc(var(--ag-grid-size) + 2px) 0}.ag-compact-menu-option-disabled,.ag-menu-option-disabled{cursor:not-allowed;opacity:.5}.ag-compact-menu-option-icon,.ag-menu-option-icon{width:var(--ag-icon-size)}.ag-ltr .ag-compact-menu-option-icon,.ag-ltr .ag-menu-option-icon{padding-left:calc(var(--ag-grid-size)*2)}.ag-rtl .ag-compact-menu-option-icon,.ag-rtl .ag-menu-option-icon{padding-right:calc(var(--ag-grid-size)*2)}.ag-compact-menu-option-text,.ag-menu-option-text{padding-left:calc(var(--ag-grid-size)*2);padding-right:calc(var(--ag-grid-size)*2)}.ag-ltr .ag-compact-menu-option-shortcut,.ag-ltr .ag-menu-option-shortcut{padding-right:var(--ag-grid-size)}.ag-rtl .ag-compact-menu-option-shortcut,.ag-rtl .ag-menu-option-shortcut{padding-left:var(--ag-grid-size)}.ag-ltr .ag-compact-menu-option-popup-pointer,.ag-ltr .ag-menu-option-popup-pointer{padding-right:var(--ag-grid-size)}.ag-rtl .ag-compact-menu-option-popup-pointer,.ag-rtl .ag-menu-option-popup-pointer{padding-left:var(--ag-grid-size)}.ag-menu-column-select-wrapper{height:265px;overflow:auto}.ag-menu-column-select-wrapper .ag-column-select{height:100%}.ag-menu.ag-tabs{min-width:290px}.ag-filter-separator{border-top:1px solid var(--menu-separator-color)}.ag-filter-select .ag-picker-field-wrapper{width:0}.ag-filter-condition-operator{height:17px}.ag-ltr .ag-filter-condition-operator-or{margin-left:calc(var(--ag-grid-size)*2)}.ag-rtl .ag-filter-condition-operator-or{margin-right:calc(var(--ag-grid-size)*2)}.ag-set-filter-select-all{padding-top:var(--ag-widget-container-vertical-padding)}.ag-filter-no-matches,.ag-set-filter-list{height:calc(var(--ag-list-item-height)*6)}.ag-filter-no-matches{padding:var(--ag-widget-container-vertical-padding) var(--ag-widget-container-horizontal-padding)}.ag-set-filter-tree-list{height:calc(var(--ag-list-item-height)*10)}.ag-set-filter-filter{margin-left:var(--ag-widget-container-horizontal-padding);margin-right:var(--ag-widget-container-horizontal-padding);margin-top:var(--ag-widget-container-vertical-padding)}.ag-filter-to{margin-top:var(--ag-widget-vertical-spacing)}.ag-mini-filter{margin:var(--ag-widget-container-vertical-padding) var(--ag-widget-container-horizontal-padding)}.ag-ltr .ag-set-filter-item{padding-left:calc(var(--ag-widget-container-horizontal-padding) + var(--ag-indentation-level)*var(--ag-set-filter-indent-size))}.ag-rtl .ag-set-filter-item{padding-right:calc(var(--ag-widget-container-horizontal-padding) + var(--ag-indentation-level)*var(--ag-set-filter-indent-size))}.ag-ltr .ag-set-filter-add-group-indent{margin-left:calc(var(--ag-icon-size) + var(--ag-widget-container-horizontal-padding))}.ag-rtl .ag-set-filter-add-group-indent{margin-right:calc(var(--ag-icon-size) + var(--ag-widget-container-horizontal-padding))}.ag-ltr .ag-set-filter-group-icons{margin-right:var(--ag-widget-container-horizontal-padding)}.ag-rtl .ag-set-filter-group-icons{margin-left:var(--ag-widget-container-horizontal-padding)}.ag-filter-menu .ag-set-filter-list{min-width:200px}.ag-filter-virtual-list-item:focus-visible{box-shadow:inset var(--ag-focus-shadow)}.ag-filter-apply-panel{display:flex;justify-content:flex-end;overflow:hidden;padding:var(--ag-widget-vertical-spacing) var(--ag-widget-container-horizontal-padding) var(--ag-widget-container-vertical-padding)}.ag-filter-apply-panel-button{line-height:1.5}.ag-ltr .ag-filter-apply-panel-button{margin-left:calc(var(--ag-grid-size)*2)}.ag-rtl .ag-filter-apply-panel-button{margin-right:calc(var(--ag-grid-size)*2)}.ag-simple-filter-body-wrapper{display:flex;flex-direction:column;min-height:calc(var(--ag-list-item-height) + var(--ag-widget-container-vertical-padding) + var(--ag-widget-vertical-spacing));overflow-y:auto;padding:var(--ag-widget-container-vertical-padding) var(--ag-widget-container-horizontal-padding);padding-bottom:calc(var(--ag-widget-container-vertical-padding) - var(--ag-widget-vertical-spacing))}.ag-simple-filter-body-wrapper>*{margin-bottom:var(--ag-widget-vertical-spacing)}.ag-simple-filter-body-wrapper .ag-resizer-wrapper{margin:0}.ag-multi-filter-menu-item{margin:var(--ag-grid-size) 0}.ag-multi-filter-group-title-bar{background-color:transparent;color:var(--ag-header-text-color);font-weight:500;padding:calc(var(--ag-grid-size)*1.5) var(--ag-grid-size)}.ag-multi-filter-group-title-bar:focus-visible{box-shadow:var(--ag-focus-shadow)}.ag-group-filter-field-select-wrapper{display:flex;flex-direction:column;gap:var(--ag-widget-vertical-spacing);padding:var(--ag-widget-container-vertical-padding) var(--ag-widget-container-horizontal-padding)}.ag-menu-option .ag-icon{opacity:65%}.ag-menu-option{cursor:pointer;font-weight:500}.ag-ltr .ag-menu-option-popup-pointer .ag-icon{text-align:right}.ag-rtl .ag-menu-option-popup-pointer .ag-icon{text-align:left}.ag-panel{background-color:var(--ag-panel-background-color);display:flex;flex-direction:column;overflow:hidden;position:relative}.ag-dialog{border:var(--ag-dialog-border);border-radius:var(--ag-border-radius);box-shadow:var(--ag-dialog-shadow);position:absolute}.ag-panel-title-bar{align-items:center;background-color:var(--ag-panel-title-bar-background-color);border-bottom:var(--ag-panel-title-bar-border);color:var(--ag-header-text-color);cursor:default;display:flex;flex:none;height:var(--ag-header-height);padding:var(--ag-grid-size) var(--ag-cell-horizontal-padding)}.ag-ltr .ag-panel-title-bar-button{margin-left:calc(var(--ag-grid-size)*2);margin-right:var(--ag-grid-size)}.ag-rtl .ag-panel-title-bar-button{margin-left:var(--ag-grid-size);margin-right:calc(var(--ag-grid-size)*2)}.ag-panel-title-bar-title{color:var(--ag-header-text-color);flex:1 1 auto;font-weight:500}.ag-panel-title-bar-buttons{display:flex}.ag-panel-title-bar-button{cursor:pointer}.ag-panel-content-wrapper{display:flex;flex:1 1 auto;overflow:hidden;position:relative}.ag-resizer{pointer-events:none;position:absolute;-webkit-user-select:none;-moz-user-select:none;user-select:none;z-index:1}.ag-resizer.ag-resizer-topLeft{height:5px;left:0;top:0;width:5px}.ag-ltr .ag-resizer.ag-resizer-topLeft{cursor:nwse-resize}.ag-rtl .ag-resizer.ag-resizer-topLeft{cursor:nesw-resize}.ag-resizer.ag-resizer-top{cursor:ns-resize;height:5px;left:5px;right:5px;top:0}.ag-resizer.ag-resizer-topRight{height:5px;right:0;top:0;width:5px}.ag-ltr .ag-resizer.ag-resizer-topRight{cursor:nesw-resize}.ag-rtl .ag-resizer.ag-resizer-topRight{cursor:nwse-resize}.ag-resizer.ag-resizer-right{bottom:5px;cursor:ew-resize;right:0;top:5px;width:5px}.ag-resizer.ag-resizer-bottomRight{bottom:0;height:5px;right:0;width:5px}.ag-ltr .ag-resizer.ag-resizer-bottomRight{cursor:nwse-resize}.ag-rtl .ag-resizer.ag-resizer-bottomRight{cursor:nesw-resize}.ag-resizer.ag-resizer-bottom{bottom:0;cursor:ns-resize;height:5px;left:5px;right:5px}.ag-resizer.ag-resizer-bottomLeft{bottom:0;height:5px;left:0;width:5px}.ag-ltr .ag-resizer.ag-resizer-bottomLeft{cursor:nesw-resize}.ag-rtl .ag-resizer.ag-resizer-bottomLeft{cursor:nwse-resize}.ag-resizer.ag-resizer-left{bottom:5px;cursor:ew-resize;left:0;top:5px;width:5px}.ag-dragging-fill-handle .ag-dialog,.ag-dragging-range-handle .ag-dialog{opacity:.7;pointer-events:none}.ag-pinned-left-header,.ag-pinned-right-header{display:inline-block;overflow:hidden;position:relative}.ag-body-horizontal-scroll:not(.ag-scrollbar-invisible) .ag-horizontal-left-spacer:not(.ag-scroller-corner){border-right:var(--ag-pinned-column-border)}.ag-body-horizontal-scroll:not(.ag-scrollbar-invisible) .ag-horizontal-right-spacer:not(.ag-scroller-corner),.ag-pinned-right-header{border-left:var(--ag-pinned-column-border)}.ag-pinned-left-header{border-right:var(--ag-pinned-column-border)}.ag-cell.ag-cell-first-right-pinned:not(.ag-cell-range-left):not(.ag-cell-range-single-cell){border-left:var(--ag-pinned-column-border)}.ag-cell.ag-cell-last-left-pinned:not(.ag-cell-range-right):not(.ag-cell-range-single-cell){border-right:var(--ag-pinned-column-border)}.ag-pinned-left-header .ag-header-cell-resize:after{left:calc(50% - var(--ag-header-column-resize-handle-width))}.ag-pinned-right-header .ag-header-cell-resize:after{left:50%}.ag-pinned-left-header,.ag-pinned-right-header{height:100%}.ag-pinned-left-header .ag-header-cell-resize{right:-4px}.ag-pinned-right-header .ag-header-cell-resize{left:-4px}.ag-layout-print.ag-body{display:block;height:unset}.ag-layout-print.ag-root-wrapper{display:inline-block}.ag-layout-print .ag-body-horizontal-scroll,.ag-layout-print .ag-body-vertical-scroll{display:none}.ag-layout-print.ag-force-vertical-scroll{overflow-y:visible!important}@media print{.ag-root-wrapper.ag-layout-print{display:table}.ag-root-wrapper.ag-layout-print .ag-body-horizontal-scroll-viewport,.ag-root-wrapper.ag-layout-print .ag-body-viewport,.ag-root-wrapper.ag-layout-print .ag-center-cols-container,.ag-root-wrapper.ag-layout-print .ag-center-cols-viewport,.ag-root-wrapper.ag-layout-print .ag-root,.ag-root-wrapper.ag-layout-print .ag-root-wrapper-body,.ag-root-wrapper.ag-layout-print .ag-virtual-list-viewport{display:block!important;height:auto!important;overflow:hidden!important}.ag-root-wrapper.ag-layout-print .ag-cell,.ag-root-wrapper.ag-layout-print .ag-row{-moz-column-break-inside:avoid;break-inside:avoid}}.ag-select{align-items:center;display:flex;flex-direction:row}.ag-select .ag-picker-field-wrapper{cursor:default}.ag-ltr .ag-select .ag-picker-field-wrapper{padding-left:calc(var(--ag-cell-horizontal-padding)/2);padding-right:var(--ag-grid-size)}.ag-rtl .ag-select .ag-picker-field-wrapper{padding-left:var(--ag-grid-size);padding-right:calc(var(--ag-cell-horizontal-padding)/2)}.ag-select.ag-disabled .ag-picker-field-wrapper:focus{box-shadow:none}.ag-select:not(.ag-cell-editor,.ag-label-align-top){min-height:var(--ag-list-item-height)}.ag-select .ag-picker-field-display{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ag-select .ag-picker-field-icon{align-items:center;display:flex}.ag-select.ag-disabled{opacity:.5}.ag-rich-select{cursor:default;height:100%}.ag-rich-select-value{align-items:center;background-color:var(--ag-input-background-color);display:flex;height:100%;padding:var(--ag-grid-size)}.ag-rich-select-value .ag-picker-field-display{overflow:hidden;text-overflow:ellipsis}.ag-rich-select-value .ag-picker-field-display.ag-display-as-placeholder{opacity:.5}.ag-rich-select-list{background-color:var(--ag-input-background-color);border:var(--ag-input-border);border-radius:var(--ag-input-border-radius);box-shadow:var(--ag-dropdown-shadow);height:auto;position:relative;width:100%}.ag-rich-select-list .ag-loading-text{padding:var(--ag-widget-container-vertical-padding) var(--ag-widget-container-horizontal-padding)}.ag-rich-select-row{align-items:center;display:flex;flex:1 1 auto;height:100%;overflow:hidden;padding:0 var(--ag-grid-size);white-space:nowrap}.ag-rich-select-row-selected{background-color:var(--ag-selected-row-background-color)}.ag-rich-select-row-highlighted,.ag-rich-select-row:hover{background-image:linear-gradient(var(--ag-row-hover-color),var(--ag-row-hover-color))}.ag-rich-select-row-text-highlight{font-weight:700}.ag-rich-select-field-input{flex:1 1 auto}.ag-ltr .ag-rich-select-field-input{left:var(--ag-grid-size)}.ag-rtl .ag-rich-select-field-input{right:var(--ag-grid-size)}.ag-rich-select-field-input .ag-input-field-input{border:none!important;box-shadow:none!important;padding:0!important;text-overflow:ellipsis}.ag-rich-select-field-input .ag-input-field-input::-moz-placeholder{opacity:.8}.ag-rich-select-field-input .ag-input-field-input::placeholder{opacity:.8}.ag-popup-editor .ag-rich-select-value{height:var(--ag-row-height);min-width:200px}.ag-rich-select-virtual-list-item{cursor:default;height:var(--ag-list-item-height)}.ag-pill-container{display:flex;flex-wrap:nowrap;gap:.25rem}.ag-pill{align-items:center;background:var(--ag-select-cell-background-color);border:var(--ag-select-cell-border);border-radius:var(--ag-border-radius);display:flex;padding:0 .25rem;white-space:nowrap}.ag-pill:focus-visible{box-shadow:var(--ag-focus-shadow)}.ag-pill .ag-pill-button{border:none;padding:0}.ag-ltr .ag-pill .ag-pill-button{margin-left:var(--ag-grid-size)}.ag-rtl .ag-pill .ag-pill-button{margin-right:var(--ag-grid-size)}.ag-pill .ag-pill-button:hover{color:var(--ag-accent-color);cursor:pointer}.ag-popup,.ag-root-wrapper{cursor:default;line-height:normal;white-space:normal;-webkit-font-smoothing:antialiased;background-color:var(--ag-background-color);color:var(--ag-text-color);color-scheme:var(--ag-color-scheme);font-family:var(--ag-font-family);font-size:var(--ag-font-size);--ag-indentation-level:0}.ag-root-wrapper{border:var(--ag-wrapper-border);border-radius:var(--ag-wrapper-border-radius);display:flex;flex-direction:column;overflow:hidden;position:relative}.ag-root-wrapper.ag-layout-normal{height:100%}.ag-ltr .ag-side-bar-left .ag-tool-panel-horizontal-resize{right:-3px}.ag-ltr .ag-side-bar-right .ag-tool-panel-horizontal-resize,.ag-rtl .ag-side-bar-left .ag-tool-panel-horizontal-resize{left:-3px}.ag-rtl .ag-side-bar-right .ag-tool-panel-horizontal-resize{right:-3px}.ag-tool-panel-wrapper{width:var(--ag-side-bar-panel-width)}.ag-side-bar{background-color:var(--ag-side-bar-background-color);display:flex;flex-direction:row-reverse;position:relative}.ag-side-bar-left{flex-direction:row;order:-1}.ag-side-buttons{position:relative;width:calc(var(--ag-icon-size) + var(--ag-grid-size)*2)}.ag-side-button.ag-selected{background-color:var(--ag-side-button-selected-background-color);border-bottom:var(--ag-side-button-selected-border)}.ag-side-button.ag-selected:not(:first-of-type){border-top:var(--ag-side-button-selected-border)}.ag-side-button-button{align-items:center;display:flex;flex-direction:column;gap:var(--ag-grid-size);padding:calc(var(--ag-grid-size)*3) 0;position:relative;white-space:nowrap;width:100%}.ag-side-button-button:focus{box-shadow:none}.ag-side-button-button:focus-visible{box-shadow:inset var(--ag-focus-shadow)}.ag-side-button-label{writing-mode:vertical-lr}@media (max-resolution:1.5x){.ag-side-button-label{font-family:"Segoe UI",var(--ag-font-family)}.ag-ltr .ag-side-button-label{transform:rotate(.05deg)}.ag-rtl .ag-side-button-label{transform:rotate(-.05deg)}}.ag-ltr .ag-side-bar-left,.ag-rtl .ag-side-bar-right{border-right:var(--ag-side-panel-border)}.ag-ltr .ag-side-bar-left .ag-tool-panel-wrapper,.ag-ltr .ag-side-bar-right,.ag-rtl .ag-side-bar-left,.ag-rtl .ag-side-bar-right .ag-tool-panel-wrapper{border-left:var(--ag-side-panel-border)}.ag-ltr .ag-side-bar-right .ag-tool-panel-wrapper,.ag-rtl .ag-side-bar-left .ag-tool-panel-wrapper{border-right:var(--ag-side-panel-border)}.ag-ltr .ag-chart-menu-panel{border-left:var(--ag-side-panel-border)}.ag-rtl .ag-chart-menu-panel{border-right:var(--ag-side-panel-border)}.ag-button{border-radius:0}.ag-standard-button{-moz-appearance:none;appearance:none;-webkit-appearance:none;background-color:var(--ag-background-color);border:var(--ag-input-border);border-radius:var(--ag-border-radius);cursor:pointer;font-family:inherit;padding:var(--ag-grid-size) calc(var(--ag-grid-size)*2)}.ag-standard-button:hover{background-color:var(--ag-row-hover-color)}.ag-standard-button:active{border-color:var(--ag-accent-color)}.ag-standard-button:disabled{background-color:var(--ag-input-disabled-background-color);border:var(--ag-input-disabled-border);color:var(--ag-input-disabled-text-color)}:where(input[class^=ag-][type=button],button[class^=ag-]):focus-visible{box-shadow:var(--ag-focus-shadow)}.ag-checkbox-input-wrapper,.ag-radio-button-input-wrapper{background-color:var(--ag-checkbox-unchecked-background-color);border:solid var(--ag-checkbox-border-width) var(--ag-checkbox-unchecked-border-color);flex:none;height:var(--ag-icon-size);position:relative;width:var(--ag-icon-size)}.ag-checkbox-input-wrapper input,.ag-radio-button-input-wrapper input{-webkit-appearance:none;-moz-appearance:none;appearance:none;height:100%;opacity:0;width:100%}.ag-checkbox-input-wrapper:after,.ag-radio-button-input-wrapper:after{content:"";display:block;inset:0;-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;pointer-events:none;position:absolute}.ag-checkbox-input-wrapper.ag-checked,.ag-radio-button-input-wrapper.ag-checked{background-color:var(--ag-checkbox-checked-background-color);border-color:var(--ag-checkbox-checked-border-color)}.ag-checkbox-input-wrapper.ag-checked:after,.ag-radio-button-input-wrapper.ag-checked:after{background-color:var(--ag-checkbox-checked-shape-color)}.ag-checkbox-input-wrapper:active,.ag-checkbox-input-wrapper:focus-within,.ag-radio-button-input-wrapper:active,.ag-radio-button-input-wrapper:focus-within{box-shadow:var(--ag-focus-shadow)}.ag-checkbox-input-wrapper.ag-disabled,.ag-radio-button-input-wrapper.ag-disabled{filter:grayscale();opacity:.5}.ag-checkbox-input-wrapper{border-radius:var(--ag-checkbox-border-radius)}.ag-checkbox-input-wrapper.ag-checked:after{-webkit-mask-image:var(--ag-checkbox-checked-shape-image);mask-image:var(--ag-checkbox-checked-shape-image)}.ag-checkbox-input-wrapper.ag-indeterminate{background-color:var(--ag-checkbox-indeterminate-background-color);border-color:var(--ag-checkbox-indeterminate-border-color)}.ag-checkbox-input-wrapper.ag-indeterminate:after{background-color:var(--ag-checkbox-indeterminate-shape-color);-webkit-mask-image:var(--ag-checkbox-indeterminate-shape-image);mask-image:var(--ag-checkbox-indeterminate-shape-image)}.ag-radio-button-input-wrapper{border-radius:100%}.ag-radio-button-input-wrapper.ag-checked:after{-webkit-mask-image:var(--ag-radio-checked-shape-image);mask-image:var(--ag-radio-checked-shape-image)}.ag-drag-handle{color:varXXX(--ag-icon-font-color);cursor:grab}.ag-list-item,.ag-virtual-list-item{height:var(--ag-list-item-height)}.ag-virtual-list-item{position:absolute;width:100%}.ag-select-list{background-color:var(--ag-background-color);border:var(--ag-input-border);border-radius:var(--ag-border-radius);box-shadow:var(--ag-dropdown-shadow);overflow-x:hidden;overflow-y:auto}.ag-list-item{align-items:center;display:flex;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ag-list-item.ag-active-item{background-color:var(--ag-row-hover-color)}.ag-select-list-item{cursor:default;-webkit-user-select:none;-moz-user-select:none;user-select:none}.ag-ltr .ag-select-list-item{padding-left:calc(var(--ag-cell-horizontal-padding)/2)}.ag-rtl .ag-select-list-item{padding-right:calc(var(--ag-cell-horizontal-padding)/2)}.ag-select-list-item span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ag-list-item-hovered:after{background-color:var(--ag-range-selection-border-color);content:"";height:1px;left:0;position:absolute;right:0}.ag-item-highlight-top:after{top:0}.ag-item-highlight-bottom:after{bottom:0}.ag-range-field{align-items:center;display:flex}.ag-range-field .ag-input-wrapper{height:100%}input[class^=ag-][type=range]{-webkit-appearance:none;background:none;height:100%;overflow:visible;padding:0;width:100%}input[class^=ag-][type=range]::-webkit-slider-runnable-track{background-color:var(--ag-border-color);border-radius:1.5px;height:3px;margin:0;padding:0;width:100%}input[class^=ag-][type=range]::-moz-range-track{background-color:var(--ag-border-color);border-radius:1.5px;height:3px;margin:0;padding:0;width:100%}input[class^=ag-][type=range]::-webkit-slider-thumb{-webkit-appearance:none;background-color:var(--ag-background-color);border:1px solid var(--ag-border-color);border-radius:100%;height:var(--ag-icon-size);margin:0;padding:0;transform:translateY(calc(var(--ag-icon-size)*-.5 + 1.5px));width:var(--ag-icon-size)}input[class^=ag-][type=range]::-moz-ag-range-thumb{-webkit-appearance:none;background-color:var(--ag-background-color);border:1px solid var(--ag-border-color);border-radius:100%;height:var(--ag-icon-size);margin:0;padding:0;transform:translateY(calc(var(--ag-icon-size)*-.5 + 1.5px));width:var(--ag-icon-size)}input[class^=ag-][type=range]:focus::-webkit-slider-thumb{border-color:var(--ag-accent-color);box-shadow:var(--ag-focus-shadow)}input[class^=ag-][type=range]:focus::-moz-ag-range-thumb{border-color:var(--ag-accent-color);box-shadow:var(--ag-focus-shadow)}input[class^=ag-][type=range]:active::-webkit-slider-runnable-track{background-color:var(--ag-accent-color)}input[class^=ag-][type=range]:active::-moz-ag-range-track{background-color:var(--ag-accent-color)}input[class^=ag-][type=range]:disabled{opacity:.5}.ag-toggle-button{flex:none;min-width:unset;width:unset}.ag-toggle-button-input-wrapper{background-color:var(--ag-toggle-button-off-background-color);border:solid var(--ag-toggle-button-border-width) var(--ag-toggle-button-off-border-color);border-radius:calc(var(--ag-toggle-button-height)*.5);flex:none;height:var(--ag-toggle-button-height);max-width:var(--ag-toggle-button-width);min-width:var(--ag-toggle-button-width);position:relative}.ag-toggle-button-input-wrapper input{-webkit-appearance:none;-moz-appearance:none;appearance:none;height:100%;opacity:0;width:100%}.ag-toggle-button-input-wrapper:before{background-color:var(--ag-toggle-button-switch-background-color);border:var(--ag-toggle-button-border-width) solid var(--ag-toggle-button-switch-border-color);border-radius:100%;content:"";display:block;height:var(--ag-toggle-button-height);pointer-events:none;position:absolute;top:calc(0px - var(--ag-toggle-button-border-width));width:var(--ag-toggle-button-height)}.ag-ltr .ag-toggle-button-input-wrapper:before{left:calc(0px - var(--ag-toggle-button-border-width));transition:left .1s}.ag-rtl .ag-toggle-button-input-wrapper:before{right:calc(0px - var(--ag-toggle-button-border-width));transition:right .1s}.ag-toggle-button-input-wrapper.ag-checked{background-color:var(--ag-toggle-button-on-background-color)}.ag-toggle-button-input-wrapper.ag-checked,.ag-toggle-button-input-wrapper.ag-checked:before{border-color:var(--ag-toggle-button-on-border-color)}.ag-ltr .ag-toggle-button-input-wrapper.ag-checked:before{left:calc(100% - var(--ag-toggle-button-height) + var(--ag-toggle-button-border-width))}.ag-rtl .ag-toggle-button-input-wrapper.ag-checked:before{right:calc(100% - var(--ag-toggle-button-height) + var(--ag-toggle-button-border-width))}.ag-toggle-button-input-wrapper:focus-within{box-shadow:var(--ag-focus-shadow)}.ag-toggle-button-input-wrapper.ag-disabled{opacity:.5}.ag-autocomplete{align-items:center;display:flex;width:100%}.ag-autocomplete>*{flex:1 1 auto}.ag-autocomplete-list-popup{position:absolute;-webkit-user-select:none;-moz-user-select:none;user-select:none}.ag-autocomplete-list{height:calc(var(--ag-row-height)*6.5);min-width:200px;position:relative;width:100%}.ag-autocomplete-virtual-list-item{cursor:default;display:flex;height:var(--ag-list-item-height)}.ag-autocomplete-virtual-list-item:focus-visible:after{content:none}.ag-autocomplete-virtual-list-item:hover{background-color:var(--ag-row-hover-color)}.ag-autocomplete-row{align-items:center;display:flex;flex:1 1 auto;overflow:hidden}.ag-autocomplete-row-label{margin:0 var(--ag-widget-container-horizontal-padding);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ag-autocomplete-row-selected{background-color:var(--ag-selected-row-background-color)}.ag-tooltip{background-color:var(--ag-tooltip-background-color);border:var(--ag-tooltip-border);border-radius:var(--ag-border-radius);color:var(--ag-tooltip-text-color);padding:var(--ag-widget-container-vertical-padding) var(--ag-widget-container-horizontal-padding);white-space:normal}.ag-tooltip,.ag-tooltip-custom{position:absolute;z-index:99999}.ag-tooltip-custom:not(.ag-tooltip-interactive),.ag-tooltip:not(.ag-tooltip-interactive){pointer-events:none}.ag-tooltip-custom.ag-tooltip-animate,.ag-tooltip.ag-tooltip-animate{transition:opacity 1s}.ag-tooltip-custom.ag-tooltip-animate.ag-tooltip-hiding,.ag-tooltip.ag-tooltip-animate.ag-tooltip-hiding{opacity:0}.ag-angle-select{align-items:center;display:flex}.ag-angle-select-wrapper{display:flex}.ag-angle-select-parent-circle{display:block;position:relative}.ag-angle-select-child-circle{position:absolute}.ag-slider-wrapper{display:flex}.ag-picker-field-display,.ag-slider-wrapper .ag-input-field{flex:1 1 auto}.ag-picker-field{align-items:center;display:flex}.ag-picker-field-icon{border:0;cursor:pointer;display:flex;margin:0;padding:0}.ag-color-panel{display:flex;flex-direction:column;text-align:center;width:100%}.ag-spectrum-color{cursor:default;flex:1 1 auto;overflow:visible;position:relative}.ag-spectrum-fill{inset:0;position:absolute}.ag-spectrum-val{cursor:pointer}.ag-spectrum-dragger{cursor:pointer;pointer-events:none;position:absolute}.ag-spectrum-alpha,.ag-spectrum-hue{cursor:default}.ag-spectrum-hue-background{background:linear-gradient(270deg,red 3%,#ff0 17%,#0f0 33%,#0ff 50%,#00f 67%,#f0f 83%,red);height:100%;width:100%}.ag-spectrum-alpha-background{background:linear-gradient(to right,var(--ag-internal-spectrum-alpha-color-from),var(--ag-internal-spectrum-alpha-color-to)),url('data:image/svg+xml;utf8,') 0 0 /4px 4px;height:100%;width:100%}.ag-spectrum-tool{cursor:pointer;position:relative}.ag-spectrum-slider{pointer-events:none;position:absolute}.ag-spectrum-alpha .ag-spectrum-slider{background:linear-gradient(to bottom,var(--ag-internal-spectrum-alpha-color),var(--ag-internal-spectrum-alpha-color)) var(--ag-background-color)}.ag-recent-colors{display:flex;gap:6px;margin-top:10px}.ag-recent-color{cursor:pointer}.ag-angle-select[disabled]{opacity:.5;pointer-events:none}.ag-ltr .ag-angle-select-field,.ag-ltr .ag-slider-field{margin-right:calc(var(--ag-grid-size)*2)}.ag-rtl .ag-angle-select-field,.ag-rtl .ag-slider-field{margin-left:calc(var(--ag-grid-size)*2)}.ag-angle-select-parent-circle{background-color:var(--ag-background-color);border:1px solid;border-color:var(--ag-border-color);border-radius:12px;height:24px;width:24px}.ag-angle-select-child-circle{background-color:var(--ag-foreground-color);border-radius:3px;height:6px;left:12px;margin-left:-3px;margin-top:-4px;top:4px;width:6px}.ag-picker-field-wrapper{background-color:var(--ag-background-color);border:var(--ag-input-border);border-radius:5px;min-height:max(var(--ag-list-item-height),calc(var(--ag-grid-size)*4));overflow:hidden}.ag-picker-field-wrapper:disabled{opacity:.5}.ag-picker-field-wrapper.ag-picker-has-focus,.ag-picker-field-wrapper:focus-within{border:var(--ag-input-focus-border);box-shadow:var(--ag-focus-shadow)}.ag-picker-field-button{background-color:var(--ag-background-color)}.ag-dialog.ag-color-dialog{border-radius:5px}.ag-color-picker .ag-picker-field-wrapper{padding-left:var(--ag-grid-size);padding-right:var(--ag-grid-size)}.ag-color-picker .ag-picker-field-display{align-items:center;display:flex;flex-direction:row;min-height:var(--ag-list-item-height)}.ag-ltr .ag-color-picker-color,.ag-ltr .ag-color-picker-value{margin-right:var(--ag-grid-size)}.ag-rtl .ag-color-picker-color,.ag-rtl .ag-color-picker-value{margin-left:var(--ag-grid-size)}.ag-color-panel{padding:var(--ag-grid-size)}.ag-spectrum-tools{padding-bottom:0;padding-left:0;padding-right:0}.ag-spectrum-tool{height:12px}.ag-spectrum-alpha-background,.ag-spectrum-hue-background{border-radius:12px}.ag-spectrum-slider{border:3px solid #f8f8f8;border-radius:18px;height:18px;margin-top:-15px;width:18px}.ag-recent-colors{margin-bottom:2px;margin-left:var(--ag-grid-size);margin-right:var(--ag-grid-size)}.ag-color-input-color,.ag-color-picker-color,.ag-recent-color{border-radius:4px}.ag-recent-color{border:1px solid var(--ag-border-color)}.ag-spectrum-sat{background-image:linear-gradient(90deg,#fff,hsla(20,42%,65%,0))}.ag-spectrum-val{background-image:linear-gradient(0deg,#000,hsla(20,42%,65%,0))}.ag-spectrum-dragger{background:#000;border:3px solid #fff;border-radius:18px;box-shadow:0 0 2px 0 rgba(0,0,0,.24);height:18px;width:18px}.ag-spectrum-alpha-background,.ag-spectrum-hue-background{border-radius:2px}.ag-spectrum-tool{border-radius:2px;height:11px;margin-bottom:10px}.ag-spectrum-slider{border:2px solid #fff;border-radius:13px;box-shadow:0 1px 4px 0 rgba(0,0,0,.37);height:13px;margin-top:-12px;width:13px}.ag-recent-color:focus-visible:not(:disabled):not([readonly]),.ag-spectrum-color:focus-visible:not(:disabled):not([readonly]),.ag-spectrum-slider:focus-visible:not(:disabled):not([readonly]){box-shadow:var(--ag-focus-shadow)}.ag-ltr .ag-color-input input.ag-input-field-input[class^=ag-][type=text]{padding-left:calc(var(--ag-icon-size) + var(--ag-grid-size)*2)}.ag-rtl .ag-color-input input.ag-input-field-input[class^=ag-][type=text]{padding-right:calc(var(--ag-icon-size) + var(--ag-grid-size)*2)}.ag-color-input .ag-color-input-color{position:absolute}.ag-ltr .ag-color-input .ag-color-input-color{margin-left:var(--ag-grid-size)}.ag-rtl .ag-color-input .ag-color-input-color{margin-right:var(--ag-grid-size)}.ag-color-input-color,.ag-color-picker-color{border:1px solid var(--ag-border-color);border-radius:2px;height:var(--ag-icon-size);width:var(--ag-icon-size)}.ag-pill-select .ag-picker-field-display{color:var(--ag-chart-menu-label-color);font-weight:500}.ag-pill-select .ag-picker-field-icon .ag-icon{color:var(--ag-chart-menu-label-color)}.ag-filter-toolpanel{flex:1 1 0px;min-width:0}.ag-filter-toolpanel-header{position:relative}.ag-filter-toolpanel-header,.ag-filter-toolpanel-header>*,.ag-filter-toolpanel-search,.ag-filter-toolpanel-search>*{align-items:center;display:flex}.ag-filter-toolpanel-header{height:calc(var(--ag-grid-size)*6)}.ag-filter-toolpanel-header:focus-visible{border-radius:var(--ag-border-radius);box-shadow:inset var(--ag-focus-shadow)}.ag-filter-toolpanel-header,.ag-filter-toolpanel-search{padding:0 var(--ag-grid-size)}.ag-filter-toolpanel-group:not(.ag-has-filter)>.ag-group-title-bar .ag-filter-toolpanel-group-instance-header-icon{display:none}.ag-filter-toolpanel-group-level-0-header{height:calc(var(--ag-grid-size)*8)}.ag-filter-toolpanel-group-item{margin-bottom:calc(var(--ag-grid-size)*.5);margin-top:calc(var(--ag-grid-size)*.5)}.ag-filter-toolpanel-search{margin-bottom:var(--ag-grid-size);margin-top:var(--ag-widget-container-vertical-padding)}.ag-filter-toolpanel-search-input{flex-grow:1;height:calc(var(--ag-grid-size)*4)}.ag-ltr .ag-filter-toolpanel-group-title-bar-icon{margin-right:var(--ag-grid-size)}.ag-rtl .ag-filter-toolpanel-group-title-bar-icon{margin-left:var(--ag-grid-size)}.ag-filter-toolpanel-expand{cursor:pointer}.ag-ltr .ag-filter-toolpanel-expand{margin-right:var(--ag-grid-size)}.ag-rtl .ag-filter-toolpanel-expand{margin-left:var(--ag-grid-size)}.ag-ltr .ag-filter-toolpanel-group-title-bar,.ag-ltr .ag-filter-toolpanel-instance-header{padding-left:calc(var(--ag-grid-size) + var(--ag-filter-tool-panel-group-indent)*var(--ag-indentation-level))}.ag-rtl .ag-filter-toolpanel-group-title-bar,.ag-rtl .ag-filter-toolpanel-instance-header{padding-right:calc(var(--ag-grid-size) + var(--ag-filter-tool-panel-group-indent)*var(--ag-indentation-level))}.ag-ltr .ag-filter-toolpanel-instance-body{margin-left:var(--ag-filter-tool-panel-group-indent)}.ag-rtl .ag-filter-toolpanel-instance-body{margin-right:var(--ag-filter-tool-panel-group-indent)}.ag-ltr .ag-filter-toolpanel-group-instance-header-icon,.ag-ltr .ag-filter-toolpanel-instance-header-icon{margin-left:var(--ag-grid-size)}.ag-rtl .ag-filter-toolpanel-group-instance-header-icon,.ag-rtl .ag-filter-toolpanel-instance-header-icon{margin-right:var(--ag-grid-size)}.ag-filter-toolpanel-instance-filter{background-color:var(--ag-chrome-background-color)}.ag-filter-toolpanel-group-level-0{border-top:none}.ag-filter-toolpanel-header{height:auto;padding-bottom:var(--ag-grid-size);padding-top:var(--ag-grid-size)}.ag-filter-toolpanel-group-item{margin:0}.ag-filter-toolpanel-header,.ag-filter-toolpanel-search{color:var(--ag-header-text-color);font-weight:500}.ag-paging-panel{align-items:center;border-top:var(--ag-footer-row-border);display:flex;gap:calc(var(--ag-grid-size)*4);height:max(var(--ag-row-height),22px);justify-content:center;padding:0 var(--ag-cell-horizontal-padding)}.ag-paging-page-size .ag-wrapper{min-width:50px}.ag-paging-page-summary-panel{align-items:center;display:flex;gap:var(--ag-cell-widget-spacing)}.ag-disabled .ag-paging-page-summary-panel{pointer-events:none}.ag-paging-button{cursor:pointer;position:relative}.ag-paging-button:focus-visible{box-shadow:var(--ag-focus-shadow)}.ag-paging-button.ag-disabled{cursor:default;opacity:.5}.ag-paging-number,.ag-paging-row-summary-panel-number{font-weight:500}.ag-status-bar{border-top:var(--ag-footer-row-border);display:flex;justify-content:space-between;line-height:1.5;overflow:hidden;padding-left:calc(var(--ag-grid-size)*4);padding-right:calc(var(--ag-grid-size)*4)}.ag-status-panel{display:inline-flex}.ag-status-name-value{white-space:nowrap}.ag-status-bar-center,.ag-status-bar-left,.ag-status-bar-right{display:inline-flex}.ag-status-bar-center{text-align:center}.ag-status-name-value{margin-left:var(--ag-grid-size);margin-right:var(--ag-grid-size);padding-bottom:var(--ag-widget-container-vertical-padding);padding-top:var(--ag-widget-container-vertical-padding)}.ag-status-name-value-value{font-weight:500}.ag-overlay{inset:0;pointer-events:none;position:absolute;z-index:2}.ag-overlay-panel,.ag-overlay-wrapper{display:flex;height:100%;width:100%}.ag-overlay-wrapper{align-items:center;flex:none;justify-content:center;text-align:center}.ag-overlay-loading-wrapper{pointer-events:all}.ag-overlay-loading-center{background:var(--ag-background-color);border:1px solid var(--ag-border-color);border-radius:var(--ag-border-radius);box-shadow:var(--ag-popup-shadow);padding:var(--ag-grid-size)}.ag-icon{display:block;height:var(--ag-icon-size);position:relative;-webkit-user-select:none;-moz-user-select:none;user-select:none;width:var(--ag-icon-size)}.ag-column-select-column-group-readonly .ag-icon,.ag-disabled .ag-icon,[disabled] .ag-icon{opacity:.5}.ag-icon-grip{opacity:.7}.ag-column-select-column-readonly .ag-icon-grip,.ag-column-select-column-readonly.ag-icon-grip{opacity:.35}:is(.ag-header-cell-menu-button,.ag-header-cell-filter-button,.ag-panel-title-bar-button,.ag-header-expand-icon,.ag-column-group-icons,.ag-set-filter-group-icons,.ag-group-expanded .ag-icon,.ag-group-contracted .ag-icon,.ag-chart-settings-prev,.ag-chart-settings-next,.ag-group-title-bar-icon,.ag-column-select-header-icon,.ag-floating-filter-button-button,.ag-filter-toolpanel-expand,.ag-panel-title-bar-button-icon,.ag-chart-menu-icon):hover{background-color:var(--ag-icon-button-hover-color);border-radius:1px;box-shadow:0 0 0 4px var(--ag-icon-button-hover-color)}.ag-filter-active{--ag-icon-button-hover-color:color-mix(in srgb,transparent,var(--ag-accent-color) 28%);background-color:color-mix(in srgb,transparent,var(--ag-accent-color) 14%);border-radius:1px;box-shadow:0 0 0 4px color-mix(in srgb,transparent,var(--ag-accent-color) 14%);position:relative}.ag-filter-active:after{background-color:var(--ag-accent-color);border-radius:50%;content:"";height:6px;position:absolute;top:-1px;width:6px}.ag-ltr .ag-filter-active:after{right:-1px}.ag-rtl .ag-filter-active:after{left:-1px}.ag-filter-active .ag-icon-filter{clip-path:path("M8,0C8,4.415 11.585,8 16,8L16,16L0,16L0,0L8,0Z")}.ag-label-align-right .ag-label{order:1}.ag-label-align-right>*{flex:none}.ag-label-align-top{align-items:flex-start;flex-direction:column}.ag-label-align-top>*{align-self:stretch}.ag-label-ellipsis{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ag-label{white-space:nowrap}.ag-ltr .ag-label{margin-right:var(--ag-grid-size)}.ag-rtl .ag-label{margin-left:var(--ag-grid-size)}.ag-label-align-top .ag-label{margin-bottom:calc(var(--ag-grid-size)*.5)}.ag-ltr .ag-label-align-right .ag-label{margin-left:var(--ag-grid-size)}.ag-rtl .ag-label-align-right .ag-label{margin-right:var(--ag-grid-size)} + + +/* Part iconSet/quartzRegular */.ag-icon::before {content:'';display:block;width:var(--ag-icon-size);height:var(--ag-icon-size);background-color:currentColor;mask-size: contain;}.ag-icon-aggregation::before { mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-aggregation%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22M18%207V4H6l6%208-6%208h12v-3%22%2F%3E%3C%2Fsvg%3E'); } +.ag-icon-arrows::before { mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-arrows%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpolyline%20points%3D%225%209%202%2012%205%2015%22%2F%3E%3Cpolyline%20points%3D%229%205%2012%202%2015%205%22%2F%3E%3Cpolyline%20points%3D%2215%2019%2012%2022%209%2019%22%2F%3E%3Cpolyline%20points%3D%2219%209%2022%2012%2019%2015%22%2F%3E%3Cline%20x1%3D%222%22%20x2%3D%2222%22%20y1%3D%2212%22%20y2%3D%2212%22%2F%3E%3Cline%20x1%3D%2212%22%20x2%3D%2212%22%20y1%3D%222%22%20y2%3D%2222%22%2F%3E%3C%2Fsvg%3E'); } +.ag-icon-asc::before { mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-asc%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22m5%2012%207-7%207%207%22%2F%3E%3Cpath%20d%3D%22M12%2019V5%22%2F%3E%3C%2Fsvg%3E'); } +.ag-icon-cancel::before { mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-cancel%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Ccircle%20cx%3D%2212%22%20cy%3D%2212%22%20r%3D%2210%22%2F%3E%3Cpath%20d%3D%22m15%209-6%206%22%2F%3E%3Cpath%20d%3D%22m9%209%206%206%22%2F%3E%3C%2Fsvg%3E'); } +.ag-icon-chart::before { mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-chart%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cline%20x1%3D%2218%22%20x2%3D%2218%22%20y1%3D%2220%22%20y2%3D%2210%22%2F%3E%3Cline%20x1%3D%2212%22%20x2%3D%2212%22%20y1%3D%2220%22%20y2%3D%224%22%2F%3E%3Cline%20x1%3D%226%22%20x2%3D%226%22%20y1%3D%2220%22%20y2%3D%2214%22%2F%3E%3C%2Fsvg%3E'); } +.ag-icon-color-picker::before { mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-color-picker%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22m19%2011-8-8-8.6%208.6a2%202%200%200%200%200%202.8l5.2%205.2c.8.8%202%20.8%202.8%200L19%2011Z%22%2F%3E%3Cpath%20d%3D%22m5%202%205%205%22%2F%3E%3Cpath%20d%3D%22M2%2013h15%22%2F%3E%3Cpath%20d%3D%22M22%2020a2%202%200%201%201-4%200c0-1.6%201.7-2.4%202-4%20.3%201.6%202%202.4%202%204Z%22%2F%3E%3C%2Fsvg%3E'); } +.ag-icon-columns::before { mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-columns%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22M9%203H5a2%202%200%200%200-2%202v4m6-6h10a2%202%200%200%201%202%202v4M9%203v18m0%200h10a2%202%200%200%200%202-2V9M9%2021H5a2%202%200%200%201-2-2V9m0%200h18%22%2F%3E%3C%2Fsvg%3E'); } +.ag-icon-contracted::before { mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-contracted%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22m9%2018%206-6-6-6%22%2F%3E%3C%2Fsvg%3E'); } +.ag-icon-copy::before { mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-copy%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Crect%20width%3D%2214%22%20height%3D%2214%22%20x%3D%228%22%20y%3D%228%22%20rx%3D%222%22%20ry%3D%222%22%2F%3E%3Cpath%20d%3D%22M4%2016c-1.1%200-2-.9-2-2V4c0-1.1.9-2%202-2h10c1.1%200%202%20.9%202%202%22%2F%3E%3C%2Fsvg%3E'); } +.ag-icon-cross::before { mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-cross%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22M18%206%206%2018%22%2F%3E%3Cpath%20d%3D%22m6%206%2012%2012%22%2F%3E%3C%2Fsvg%3E'); } +.ag-icon-csv::before { mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-csv%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22M14.5%202H6a2%202%200%200%200-2%202v16a2%202%200%200%200%202%202h12a2%202%200%200%200%202-2V7.5L14.5%202z%22%2F%3E%3Cpolyline%20points%3D%2214%202%2014%208%2020%208%22%2F%3E%3Cpath%20d%3D%22M8%2013h2%22%2F%3E%3Cpath%20d%3D%22M8%2017h2%22%2F%3E%3Cpath%20d%3D%22M14%2013h2%22%2F%3E%3Cpath%20d%3D%22M14%2017h2%22%2F%3E%3C%2Fsvg%3E'); } +.ag-icon-cut::before { mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-cut%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Ccircle%20cx%3D%226%22%20cy%3D%226%22%20r%3D%223%22%2F%3E%3Cpath%20d%3D%22M8.12%208.12%2012%2012%22%2F%3E%3Cpath%20d%3D%22M20%204%208.12%2015.88%22%2F%3E%3Ccircle%20cx%3D%226%22%20cy%3D%2218%22%20r%3D%223%22%2F%3E%3Cpath%20d%3D%22M14.8%2014.8%2020%2020%22%2F%3E%3C%2Fsvg%3E'); } +.ag-icon-desc::before { mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-desc%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22M12%205v14%22%2F%3E%3Cpath%20d%3D%22m19%2012-7%207-7-7%22%2F%3E%3C%2Fsvg%3E'); } +.ag-icon-down::before { mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-down%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22M12%205v14%22%2F%3E%3Cpath%20d%3D%22m19%2012-7%207-7-7%22%2F%3E%3C%2Fsvg%3E'); } +.ag-icon-excel::before { mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-excel%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22M14.5%202H6a2%202%200%200%200-2%202v16a2%202%200%200%200%202%202h12a2%202%200%200%200%202-2V7.5L14.5%202z%22%2F%3E%3Cpolyline%20points%3D%2214%202%2014%208%2020%208%22%2F%3E%3Cpath%20d%3D%22M8%2013h2%22%2F%3E%3Cpath%20d%3D%22M8%2017h2%22%2F%3E%3Cpath%20d%3D%22M14%2013h2%22%2F%3E%3Cpath%20d%3D%22M14%2017h2%22%2F%3E%3C%2Fsvg%3E'); } +.ag-icon-expanded::before { mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-expanded%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22m15%2018-6-6%206-6%22%2F%3E%3C%2Fsvg%3E'); } +.ag-icon-eye-slash::before { mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-eye-slash%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22M9.88%209.88a3%203%200%201%200%204.24%204.24%22%2F%3E%3Cpath%20d%3D%22M10.73%205.08A10.43%2010.43%200%200%201%2012%205c7%200%2010%207%2010%207a13.16%2013.16%200%200%201-1.67%202.68%22%2F%3E%3Cpath%20d%3D%22M6.61%206.61A13.526%2013.526%200%200%200%202%2012s3%207%2010%207a9.74%209.74%200%200%200%205.39-1.61%22%2F%3E%3Cline%20x1%3D%222%22%20x2%3D%2222%22%20y1%3D%222%22%20y2%3D%2222%22%2F%3E%3C%2Fsvg%3E'); } +.ag-icon-eye::before { mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-eye%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22M2%2012s3-7%2010-7%2010%207%2010%207-3%207-10%207-10-7-10-7Z%22%2F%3E%3Ccircle%20cx%3D%2212%22%20cy%3D%2212%22%20r%3D%223%22%2F%3E%3C%2Fsvg%3E'); } +.ag-icon-filter::before { mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-filter%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22M3%206h18%22%2F%3E%3Cpath%20d%3D%22M7%2012h10%22%2F%3E%3Cpath%20d%3D%22M10%2018h4%22%2F%3E%3C%2Fsvg%3E'); } +.ag-icon-first::before { mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-first%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22m17%2018-6-6%206-6%22%2F%3E%3Cpath%20d%3D%22M7%206v12%22%2F%3E%3C%2Fsvg%3E'); } +.ag-icon-group::before { mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-group%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22M16%2012H3%22%2F%3E%3Cpath%20d%3D%22M16%2018H3%22%2F%3E%3Cpath%20d%3D%22M10%206H3%22%2F%3E%3Cpath%20d%3D%22M21%2018V8a2%202%200%200%200-2-2h-5%22%2F%3E%3Cpath%20d%3D%22m16%208-2-2%202-2%22%2F%3E%3C%2Fsvg%3E'); } +.ag-icon-last::before { mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-last%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22m7%2018%206-6-6-6%22%2F%3E%3Cpath%20d%3D%22M17%206v12%22%2F%3E%3C%2Fsvg%3E'); } +.ag-icon-left::before { mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-left%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22m12%2019-7-7%207-7%22%2F%3E%3Cpath%20d%3D%22M19%2012H5%22%2F%3E%3C%2Fsvg%3E'); } +.ag-icon-linked::before { mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-linked%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22M9%2017H7A5%205%200%200%201%207%207h2%22%2F%3E%3Cpath%20d%3D%22M15%207h2a5%205%200%201%201%200%2010h-2%22%2F%3E%3Cline%20x1%3D%228%22%20x2%3D%2216%22%20y1%3D%2212%22%20y2%3D%2212%22%2F%3E%3C%2Fsvg%3E'); } +.ag-icon-loading::before { mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-loading%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cline%20x1%3D%2212%22%20x2%3D%2212%22%20y1%3D%222%22%20y2%3D%226%22%2F%3E%3Cline%20x1%3D%2212%22%20x2%3D%2212%22%20y1%3D%2218%22%20y2%3D%2222%22%2F%3E%3Cline%20x1%3D%224.93%22%20x2%3D%227.76%22%20y1%3D%224.93%22%20y2%3D%227.76%22%2F%3E%3Cline%20x1%3D%2216.24%22%20x2%3D%2219.07%22%20y1%3D%2216.24%22%20y2%3D%2219.07%22%2F%3E%3Cline%20x1%3D%222%22%20x2%3D%226%22%20y1%3D%2212%22%20y2%3D%2212%22%2F%3E%3Cline%20x1%3D%2218%22%20x2%3D%2222%22%20y1%3D%2212%22%20y2%3D%2212%22%2F%3E%3Cline%20x1%3D%224.93%22%20x2%3D%227.76%22%20y1%3D%2219.07%22%20y2%3D%2216.24%22%2F%3E%3Cline%20x1%3D%2216.24%22%20x2%3D%2219.07%22%20y1%3D%227.76%22%20y2%3D%224.93%22%2F%3E%3C%2Fsvg%3E'); } +.ag-icon-maximize::before { mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-maximize%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpolyline%20points%3D%2215%203%2021%203%2021%209%22%2F%3E%3Cpolyline%20points%3D%229%2021%203%2021%203%2015%22%2F%3E%3Cline%20x1%3D%2221%22%20x2%3D%2214%22%20y1%3D%223%22%20y2%3D%2210%22%2F%3E%3Cline%20x1%3D%223%22%20x2%3D%2210%22%20y1%3D%2221%22%20y2%3D%2214%22%2F%3E%3C%2Fsvg%3E'); } +.ag-icon-menu::before { mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-menu%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cline%20x1%3D%224%22%20x2%3D%2220%22%20y1%3D%2212%22%20y2%3D%2212%22%2F%3E%3Cline%20x1%3D%224%22%20x2%3D%2220%22%20y1%3D%226%22%20y2%3D%226%22%2F%3E%3Cline%20x1%3D%224%22%20x2%3D%2220%22%20y1%3D%2218%22%20y2%3D%2218%22%2F%3E%3C%2Fsvg%3E'); } +.ag-icon-menu-alt::before { mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-menu-alt%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Ccircle%20cx%3D%2212%22%20cy%3D%225%22%20r%3D%220.75%22%20fill%3D%22%23D9D9D9%22%2F%3E%3Ccircle%20cx%3D%2212%22%20cy%3D%2212%22%20r%3D%220.75%22%20fill%3D%22%23D9D9D9%22%2F%3E%3Ccircle%20cx%3D%2212%22%20cy%3D%2219%22%20r%3D%220.75%22%20fill%3D%22%23D9D9D9%22%2F%3E%3C%2Fsvg%3E'); } +.ag-icon-minimize::before { mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-minimize%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpolyline%20points%3D%224%2014%2010%2014%2010%2020%22%2F%3E%3Cpolyline%20points%3D%2220%2010%2014%2010%2014%204%22%2F%3E%3Cline%20x1%3D%2214%22%20x2%3D%2221%22%20y1%3D%2210%22%20y2%3D%223%22%2F%3E%3Cline%20x1%3D%223%22%20x2%3D%2210%22%20y1%3D%2221%22%20y2%3D%2214%22%2F%3E%3C%2Fsvg%3E'); } +.ag-icon-minus::before { mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-minus%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Ccircle%20cx%3D%2212%22%20cy%3D%2212%22%20r%3D%2210%22%2F%3E%3Cpath%20d%3D%22M8%2012h8%22%2F%3E%3C%2Fsvg%3E'); } +.ag-icon-next::before { mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-next%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22m9%2018%206-6-6-6%22%2F%3E%3C%2Fsvg%3E'); } +.ag-icon-none::before { mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-none%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22m7%2015%205%205%205-5%22%2F%3E%3Cpath%20d%3D%22m7%209%205-5%205%205%22%2F%3E%3C%2Fsvg%3E'); } +.ag-icon-not-allowed::before { mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-not-allowed%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Ccircle%20cx%3D%2212%22%20cy%3D%2212%22%20r%3D%2210%22%2F%3E%3Cpath%20d%3D%22m4.9%204.9%2014.2%2014.2%22%2F%3E%3C%2Fsvg%3E'); } +.ag-icon-paste::before { mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-paste%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22M15%202H9a1%201%200%200%200-1%201v2c0%20.6.4%201%201%201h6c.6%200%201-.4%201-1V3c0-.6-.4-1-1-1Z%22%2F%3E%3Cpath%20d%3D%22M8%204H6a2%202%200%200%200-2%202v14a2%202%200%200%200%202%202h12a2%202%200%200%200%202-2M16%204h2a2%202%200%200%201%202%202v2M11%2014h10%22%2F%3E%3Cpath%20d%3D%22m17%2010%204%204-4%204%22%2F%3E%3C%2Fsvg%3E'); } +.ag-icon-pin::before { mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-pin%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cline%20x1%3D%2212%22%20x2%3D%2212%22%20y1%3D%2217%22%20y2%3D%2222%22%2F%3E%3Cpath%20d%3D%22M5%2017h14v-1.76a2%202%200%200%200-1.11-1.79l-1.78-.9A2%202%200%200%201%2015%2010.76V6h1a2%202%200%200%200%200-4H8a2%202%200%200%200%200%204h1v4.76a2%202%200%200%201-1.11%201.79l-1.78.9A2%202%200%200%200%205%2015.24Z%22%2F%3E%3C%2Fsvg%3E'); } +.ag-icon-pivot::before { mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-pivot%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22M15%203v18%22%2F%3E%3Crect%20width%3D%2218%22%20height%3D%2218%22%20x%3D%223%22%20y%3D%223%22%20rx%3D%222%22%2F%3E%3Cpath%20d%3D%22M21%209H3%22%2F%3E%3Cpath%20d%3D%22M21%2015H3%22%2F%3E%3C%2Fsvg%3E'); } +.ag-icon-plus::before { mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-plus%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Ccircle%20cx%3D%2212%22%20cy%3D%2212%22%20r%3D%2210%22%2F%3E%3Cpath%20d%3D%22M8%2012h8%22%2F%3E%3Cpath%20d%3D%22M12%208v8%22%2F%3E%3C%2Fsvg%3E'); } +.ag-icon-previous::before { mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-previous%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22m15%2018-6-6%206-6%22%2F%3E%3C%2Fsvg%3E'); } +.ag-icon-right::before { mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-right%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22M5%2012h14%22%2F%3E%3Cpath%20d%3D%22m12%205%207%207-7%207%22%2F%3E%3C%2Fsvg%3E'); } +.ag-icon-save::before { mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-save%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22M12%2017V3%22%2F%3E%3Cpath%20d%3D%22m6%2011%206%206%206-6%22%2F%3E%3Cpath%20d%3D%22M19%2021H5%22%2F%3E%3C%2Fsvg%3E'); } +.ag-icon-small-down::before { mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-small-down%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22m6%209%206%206%206-6%22%2F%3E%3C%2Fsvg%3E'); } +.ag-icon-small-left::before { mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-small-left%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22m15%2018-6-6%206-6%22%2F%3E%3C%2Fsvg%3E'); } +.ag-icon-small-right::before { mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-small-right%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22m9%2018%206-6-6-6%22%2F%3E%3C%2Fsvg%3E'); } +.ag-icon-small-up::before { mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-small-up%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22m18%2015-6-6-6%206%22%2F%3E%3C%2Fsvg%3E'); } +.ag-icon-tick::before { mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-tick%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22M20%206%209%2017l-5-5%22%2F%3E%3C%2Fsvg%3E'); } +.ag-icon-tree-closed::before { mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-tree-closed%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22m9%2018%206-6-6-6%22%2F%3E%3C%2Fsvg%3E'); } +.ag-icon-tree-indeterminate::before { mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-tree-indeterminate%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22M5%2012h14%22%2F%3E%3C%2Fsvg%3E'); } +.ag-icon-tree-open::before { mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-tree-open%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22m6%209%206%206%206-6%22%2F%3E%3C%2Fsvg%3E'); } +.ag-icon-unlinked::before { mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-unlinked%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22M9%2017H7A5%205%200%200%201%207%207%22%2F%3E%3Cpath%20d%3D%22M15%207h2a5%205%200%200%201%204%208%22%2F%3E%3Cline%20x1%3D%228%22%20x2%3D%2212%22%20y1%3D%2212%22%20y2%3D%2212%22%2F%3E%3Cline%20x1%3D%222%22%20x2%3D%2222%22%20y1%3D%222%22%20y2%3D%2222%22%2F%3E%3C%2Fsvg%3E'); } +.ag-icon-up::before { mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-up%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22m5%2012%207-7%207%207%22%2F%3E%3Cpath%20d%3D%22M12%2019V5%22%2F%3E%3C%2Fsvg%3E'); } +.ag-icon-grip::before { mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-grip%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Ccircle%20cx%3D%225%22%20cy%3D%228%22%20r%3D%220.5%22%2F%3E%3Ccircle%20cx%3D%2212%22%20cy%3D%228%22%20r%3D%220.5%22%2F%3E%3Ccircle%20cx%3D%2219%22%20cy%3D%228%22%20r%3D%220.5%22%2F%3E%3Ccircle%20cx%3D%225%22%20cy%3D%2216%22%20r%3D%220.5%22%2F%3E%3Ccircle%20cx%3D%2212%22%20cy%3D%2216%22%20r%3D%220.5%22%2F%3E%3Ccircle%20cx%3D%2219%22%20cy%3D%2216%22%20r%3D%220.5%22%2F%3E%3Cg%20stroke%3D%22none%22%20fill%3D%22currentColor%22%3E%3Ccircle%20cx%3D%225%22%20cy%3D%228%22%20r%3D%221%22%2F%3E%3Ccircle%20cx%3D%2212%22%20cy%3D%228%22%20r%3D%221%22%2F%3E%3Ccircle%20cx%3D%2219%22%20cy%3D%228%22%20r%3D%221%22%2F%3E%3Ccircle%20cx%3D%225%22%20cy%3D%2216%22%20r%3D%221%22%2F%3E%3Ccircle%20cx%3D%2212%22%20cy%3D%2216%22%20r%3D%221%22%2F%3E%3Ccircle%20cx%3D%2219%22%20cy%3D%2216%22%20r%3D%221%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E'); } +.ag-icon-settings::before { mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20class%3D%22ag-icon%20ag-icon-settings%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke%3D%22black%22%20stroke-width%3D%221.5%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E*%20%7B%20vector-effect%3A%20non-scaling-stroke%3B%20%7D%3C%2Fstyle%3E%3Cpath%20d%3D%22M20%207h-9%22%2F%3E%3Cpath%20d%3D%22M14%2017H5%22%2F%3E%3Ccircle%20cx%3D%2217%22%20cy%3D%2217%22%20r%3D%223%22%2F%3E%3Ccircle%20cx%3D%227%22%20cy%3D%227%22%20r%3D%223%22%2F%3E%3C%2Fsvg%3E'); } + + + +/* Part tabStyle/quartz */.ag-tabs-header{background-color:var(--ag-tab-bar-background-color);border-bottom:var(--ag-tab-bar-border);gap:var(--ag-tab-spacing);padding:var(--ag-tab-bar-top-padding) var(--ag-tab-bar-horizontal-padding) 0}.ag-tabs-header-wrapper{display:flex}.ag-tabs-header-wrapper .ag-tabs-header{flex:1}.ag-tabs-close-button-wrapper{border:0;padding:var(--ag-grid-size)}.ag-ltr .ag-tabs-close-button-wrapper{border-right:1px solid var(--ag-border-color)}.ag-rtl .ag-tabs-close-button-wrapper{border-left:1px solid var(--ag-border-color)}.ag-tabs-close-button{background-color:unset;border:0;cursor:pointer;padding:0}.ag-tab{align-items:center;background-color:var(--ag-tab-background-color);border-left:var(--ag-tab-selected-border-width) solid transparent;border-right:var(--ag-tab-selected-border-width) solid transparent;color:var(--ag-tab-text-color);display:flex;flex:1;justify-content:center;padding:var(--ag-tab-top-padding) var(--ag-tab-horizontal-padding) var(--ag-tab-bottom-padding);position:relative}.ag-tab:hover{background-color:var(--ag-tab-hover-background-color);color:var(--ag-tab-hover-text-color)}.ag-tab.ag-tab-selected{background-color:var(--ag-tab-selected-background-color);color:var(--ag-tab-selected-text-color)}.ag-ltr .ag-tab.ag-tab-selected:not(:first-of-type){border-left-color:var(--ag-tab-selected-border-color)}.ag-ltr .ag-tab.ag-tab-selected:not(:last-of-type),.ag-rtl .ag-tab.ag-tab-selected:not(:first-of-type){border-right-color:var(--ag-tab-selected-border-color)}.ag-rtl .ag-tab.ag-tab-selected:not(:last-of-type){border-left-color:var(--ag-tab-selected-border-color)}.ag-tab:after{background-color:var(--ag-tab-selected-underline-color);bottom:0;content:"";display:block;height:var(--ag-tab-selected-underline-width);left:0;opacity:0;position:absolute;right:0;transition:opacity var(--ag-tab-selected-underline-transition-duration)}.ag-tab.ag-tab-selected:after{opacity:1}.ag-tab:focus-visible{box-shadow:inset var(--ag-focus-shadow)} + + +/* Part inputStyle/bordered */:where(input[class^=ag-][type=number]:not(.ag-number-field-input-stepper)){-moz-appearance:textfield}:where(input[class^=ag-][type=number]:not(.ag-number-field-input-stepper))::-webkit-inner-spin-button,:where(input[class^=ag-][type=number]:not(.ag-number-field-input-stepper))::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}:where(input[class^=ag-]:not([type]),input[class^=ag-][type=text],input[class^=ag-][type=number],input[class^=ag-][type=tel],input[class^=ag-][type=date],input[class^=ag-][type=datetime-local],textarea[class^=ag-]){background-color:var(--ag-input-background-color);border:var(--ag-input-border);border-radius:var(--ag-input-border-radius);color:var(--ag-input-text-color);min-height:var(--ag-input-height)}.ag-ltr :where(input[class^=ag-]:not([type]),input[class^=ag-][type=text],input[class^=ag-][type=number],input[class^=ag-][type=tel],input[class^=ag-][type=date],input[class^=ag-][type=datetime-local],textarea[class^=ag-]){padding-left:var(--ag-input-padding-start)}.ag-rtl :where(input[class^=ag-]:not([type]),input[class^=ag-][type=text],input[class^=ag-][type=number],input[class^=ag-][type=tel],input[class^=ag-][type=date],input[class^=ag-][type=datetime-local],textarea[class^=ag-]){padding-right:var(--ag-input-padding-start)}:where(input[class^=ag-]:not([type]),input[class^=ag-][type=text],input[class^=ag-][type=number],input[class^=ag-][type=tel],input[class^=ag-][type=date],input[class^=ag-][type=datetime-local],textarea[class^=ag-]):where(:disabled){background-color:var(--ag-input-disabled-background-color);border:var(--ag-input-disabled-border);color:var(--ag-input-disabled-text-color)}:where(input[class^=ag-]:not([type]),input[class^=ag-][type=text],input[class^=ag-][type=number],input[class^=ag-][type=tel],input[class^=ag-][type=date],input[class^=ag-][type=datetime-local],textarea[class^=ag-]):where(:focus){background-color:var(--ag-input-focus-background-color);border:var(--ag-input-focus-border);box-shadow:var(--ag-input-focus-shadow);color:var(--ag-input-focus-text-color)}:where(input[class^=ag-]:not([type]),input[class^=ag-][type=text],input[class^=ag-][type=number],input[class^=ag-][type=tel],input[class^=ag-][type=date],input[class^=ag-][type=datetime-local],textarea[class^=ag-]):where(:invalid){background-color:var(--ag-input-invalid-background-color);border:var(--ag-input-invalid-border);color:var(--ag-input-invalid-text-color)}:where(input[class^=ag-]:not([type]),input[class^=ag-][type=text],input[class^=ag-][type=number],input[class^=ag-][type=tel],input[class^=ag-][type=date],input[class^=ag-][type=datetime-local],textarea[class^=ag-]):where(.invalid){background-color:var(--ag-input-invalid-background-color);border:var(--ag-input-invalid-border);color:var(--ag-input-invalid-text-color)} diff --git a/src/component-library/outputtailwind.css b/src/component-library/outputtailwind.css index 43226587f..ad09a3544 100644 --- a/src/component-library/outputtailwind.css +++ b/src/component-library/outputtailwind.css @@ -639,6 +639,10 @@ html { z-index: 10; } +.\!m-0 { + margin: 0px !important; +} + .m-0 { margin: 0px; } @@ -833,6 +837,10 @@ html { height: 2rem; } +.h-\[800px\] { + height: 800px; +} + .h-auto { height: auto; } @@ -1010,6 +1018,16 @@ html { animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite; } +@keyframes spin { + to { + transform: rotate(360deg); + } +} + +.animate-spin { + animation: spin 1s linear infinite; +} + .cursor-not-allowed { cursor: not-allowed; } @@ -1074,6 +1092,10 @@ html { flex-wrap: wrap; } +.content-center { + align-content: center; +} + .items-start { align-items: flex-start; } @@ -1253,6 +1275,10 @@ html { border-top-width: 1px; } +.border-solid { + border-style: solid; +} + .border-base-error-500 { --tw-border-opacity: 1; border-color: rgb(239 68 68 / var(--tw-border-opacity)); @@ -1348,6 +1374,24 @@ html { border-color: rgb(51 65 85 / var(--tw-border-opacity)); } +.border-neutral-800 { + --tw-border-opacity: 1; + border-color: rgb(30 41 59 / var(--tw-border-opacity)); +} + +.border-neutral-900 { + --tw-border-opacity: 1; + border-color: rgb(15 23 42 / var(--tw-border-opacity)); +} + +.border-opacity-10 { + --tw-border-opacity: 0.1; +} + +.border-opacity-20 { + --tw-border-opacity: 0.2; +} + .bg-base-error-100 { --tw-bg-opacity: 1; background-color: rgb(254 226 226 / var(--tw-bg-opacity)); @@ -1388,6 +1432,11 @@ html { background-color: rgb(125 211 252 / var(--tw-bg-opacity)); } +.bg-base-info-500 { + --tw-bg-opacity: 1; + background-color: rgb(14 165 233 / var(--tw-bg-opacity)); +} + .bg-base-success-100 { --tw-bg-opacity: 1; background-color: rgb(220 252 231 / var(--tw-bg-opacity)); @@ -1428,6 +1477,11 @@ html { background-color: rgb(252 211 77 / var(--tw-bg-opacity)); } +.bg-base-warning-400 { + --tw-bg-opacity: 1; + background-color: rgb(251 191 36 / var(--tw-bg-opacity)); +} + .bg-base-warning-500 { --tw-bg-opacity: 1; background-color: rgb(245 158 11 / var(--tw-bg-opacity)); @@ -1503,6 +1557,11 @@ html { background-color: rgb(254 205 211 / var(--tw-bg-opacity)); } +.bg-extra-rose-500 { + --tw-bg-opacity: 1; + background-color: rgb(244 63 94 / var(--tw-bg-opacity)); +} + .bg-extra-yellow-100 { --tw-bg-opacity: 1; background-color: rgb(254 252 232 / var(--tw-bg-opacity)); @@ -1651,6 +1710,10 @@ html { --tw-bg-opacity: 0.5; } +.bg-opacity-80 { + --tw-bg-opacity: 0.8; +} + .p-0 { padding: 0px; } @@ -1991,6 +2054,31 @@ html { color: rgb(17 24 39 / var(--tw-text-opacity)); } +.text-neutral-100 { + --tw-text-opacity: 1; + color: rgb(241 245 249 / var(--tw-text-opacity)); +} + +.text-neutral-600 { + --tw-text-opacity: 1; + color: rgb(71 85 105 / var(--tw-text-opacity)); +} + +.text-neutral-700 { + --tw-text-opacity: 1; + color: rgb(51 65 85 / var(--tw-text-opacity)); +} + +.text-neutral-800 { + --tw-text-opacity: 1; + color: rgb(30 41 59 / var(--tw-text-opacity)); +} + +.text-neutral-900 { + --tw-text-opacity: 1; + color: rgb(15 23 42 / var(--tw-text-opacity)); +} + .text-red-500 { --tw-text-opacity: 1; color: rgb(239 68 68 / var(--tw-text-opacity)); @@ -2419,6 +2507,11 @@ html { --tw-ring-opacity: 0.5; } +.disabled\:text-neutral-400:disabled { + --tw-text-opacity: 1; + color: rgb(148 163 184 / var(--tw-text-opacity)); +} + .group:focus-within .group-focus-within\:block { display: block; } @@ -2427,499 +2520,519 @@ html { display: block; } -@media (prefers-color-scheme: dark) { - .dark\:rounded-md { - border-radius: 0.375rem; - } +.dark .dark\:rounded-md { + border-radius: 0.375rem; +} - .dark\:rounded-b-sm { - border-bottom-right-radius: 0.125rem; - border-bottom-left-radius: 0.125rem; - } +.dark .dark\:rounded-b-sm { + border-bottom-right-radius: 0.125rem; + border-bottom-left-radius: 0.125rem; +} - .dark\:border { - border-width: 1px; - } +.dark .dark\:border { + border-width: 1px; +} - .dark\:border-0 { - border-width: 0px; - } +.dark .dark\:border-0 { + border-width: 0px; +} - .dark\:border-2 { - border-width: 2px; - } +.dark .dark\:border-2 { + border-width: 2px; +} - .dark\:border-base-error-200 { - --tw-border-opacity: 1; - border-color: rgb(254 202 202 / var(--tw-border-opacity)); - } +.dark .dark\:border-base-error-200 { + --tw-border-opacity: 1; + border-color: rgb(254 202 202 / var(--tw-border-opacity)); +} - .dark\:border-base-info-200 { - --tw-border-opacity: 1; - border-color: rgb(186 230 253 / var(--tw-border-opacity)); - } +.dark .dark\:border-base-info-200 { + --tw-border-opacity: 1; + border-color: rgb(186 230 253 / var(--tw-border-opacity)); +} - .dark\:border-base-success-200 { - --tw-border-opacity: 1; - border-color: rgb(187 247 208 / var(--tw-border-opacity)); - } +.dark .dark\:border-base-success-200 { + --tw-border-opacity: 1; + border-color: rgb(187 247 208 / var(--tw-border-opacity)); +} - .dark\:border-base-warning-200 { - --tw-border-opacity: 1; - border-color: rgb(253 230 138 / var(--tw-border-opacity)); - } +.dark .dark\:border-base-warning-200 { + --tw-border-opacity: 1; + border-color: rgb(253 230 138 / var(--tw-border-opacity)); +} - .dark\:border-brand-200 { - --tw-border-opacity: 1; - border-color: rgb(221 214 254 / var(--tw-border-opacity)); - } +.dark .dark\:border-brand-200 { + --tw-border-opacity: 1; + border-color: rgb(221 214 254 / var(--tw-border-opacity)); +} - .dark\:border-brand-700 { - --tw-border-opacity: 1; - border-color: rgb(109 40 217 / var(--tw-border-opacity)); - } +.dark .dark\:border-brand-700 { + --tw-border-opacity: 1; + border-color: rgb(109 40 217 / var(--tw-border-opacity)); +} - .dark\:border-extra-indigo-200 { - --tw-border-opacity: 1; - border-color: rgb(199 210 254 / var(--tw-border-opacity)); - } +.dark .dark\:border-extra-indigo-200 { + --tw-border-opacity: 1; + border-color: rgb(199 210 254 / var(--tw-border-opacity)); +} - .dark\:border-extra-rose-200 { - --tw-border-opacity: 1; - border-color: rgb(254 205 211 / var(--tw-border-opacity)); - } +.dark .dark\:border-extra-rose-200 { + --tw-border-opacity: 1; + border-color: rgb(254 205 211 / var(--tw-border-opacity)); +} - .dark\:border-gray-700 { - --tw-border-opacity: 1; - border-color: rgb(55 65 81 / var(--tw-border-opacity)); - } +.dark .dark\:border-gray-700 { + --tw-border-opacity: 1; + border-color: rgb(55 65 81 / var(--tw-border-opacity)); +} - .dark\:border-neutral-0 { - --tw-border-opacity: 1; - border-color: rgb(255 255 255 / var(--tw-border-opacity)); - } +.dark .dark\:border-neutral-0 { + --tw-border-opacity: 1; + border-color: rgb(255 255 255 / var(--tw-border-opacity)); +} - .dark\:border-neutral-100 { - --tw-border-opacity: 1; - border-color: rgb(241 245 249 / var(--tw-border-opacity)); - } +.dark .dark\:border-neutral-100 { + --tw-border-opacity: 1; + border-color: rgb(241 245 249 / var(--tw-border-opacity)); +} - .dark\:border-neutral-200 { - --tw-border-opacity: 1; - border-color: rgb(226 232 240 / var(--tw-border-opacity)); - } +.dark .dark\:border-neutral-200 { + --tw-border-opacity: 1; + border-color: rgb(226 232 240 / var(--tw-border-opacity)); +} - .dark\:border-neutral-400 { - --tw-border-opacity: 1; - border-color: rgb(148 163 184 / var(--tw-border-opacity)); - } +.dark .dark\:border-neutral-400 { + --tw-border-opacity: 1; + border-color: rgb(148 163 184 / var(--tw-border-opacity)); +} - .dark\:bg-base-error-600 { - --tw-bg-opacity: 1; - background-color: rgb(220 38 38 / var(--tw-bg-opacity)); - } +.dark .dark\:border-opacity-10 { + --tw-border-opacity: 0.1; +} - .dark\:bg-base-error-700 { - --tw-bg-opacity: 1; - background-color: rgb(185 28 28 / var(--tw-bg-opacity)); - } +.dark .dark\:border-opacity-20 { + --tw-border-opacity: 0.2; +} - .dark\:bg-base-error-900 { - --tw-bg-opacity: 1; - background-color: rgb(127 29 29 / var(--tw-bg-opacity)); - } +.dark .dark\:bg-base-error-600 { + --tw-bg-opacity: 1; + background-color: rgb(220 38 38 / var(--tw-bg-opacity)); +} - .dark\:bg-base-info-600 { - --tw-bg-opacity: 1; - background-color: rgb(2 132 199 / var(--tw-bg-opacity)); - } +.dark .dark\:bg-base-error-700 { + --tw-bg-opacity: 1; + background-color: rgb(185 28 28 / var(--tw-bg-opacity)); +} - .dark\:bg-base-info-700 { - --tw-bg-opacity: 1; - background-color: rgb(3 105 161 / var(--tw-bg-opacity)); - } +.dark .dark\:bg-base-error-900 { + --tw-bg-opacity: 1; + background-color: rgb(127 29 29 / var(--tw-bg-opacity)); +} - .dark\:bg-base-success-600 { - --tw-bg-opacity: 1; - background-color: rgb(22 163 74 / var(--tw-bg-opacity)); - } +.dark .dark\:bg-base-info-600 { + --tw-bg-opacity: 1; + background-color: rgb(2 132 199 / var(--tw-bg-opacity)); +} - .dark\:bg-base-success-700 { - --tw-bg-opacity: 1; - background-color: rgb(21 128 61 / var(--tw-bg-opacity)); - } +.dark .dark\:bg-base-info-700 { + --tw-bg-opacity: 1; + background-color: rgb(3 105 161 / var(--tw-bg-opacity)); +} - .dark\:bg-base-success-900 { - --tw-bg-opacity: 1; - background-color: rgb(20 83 45 / var(--tw-bg-opacity)); - } +.dark .dark\:bg-base-success-600 { + --tw-bg-opacity: 1; + background-color: rgb(22 163 74 / var(--tw-bg-opacity)); +} - .dark\:bg-base-warning-600 { - --tw-bg-opacity: 1; - background-color: rgb(217 119 6 / var(--tw-bg-opacity)); - } +.dark .dark\:bg-base-success-700 { + --tw-bg-opacity: 1; + background-color: rgb(21 128 61 / var(--tw-bg-opacity)); +} - .dark\:bg-base-warning-700 { - --tw-bg-opacity: 1; - background-color: rgb(180 83 9 / var(--tw-bg-opacity)); - } +.dark .dark\:bg-base-success-900 { + --tw-bg-opacity: 1; + background-color: rgb(20 83 45 / var(--tw-bg-opacity)); +} - .dark\:bg-blue-600 { - --tw-bg-opacity: 1; - background-color: rgb(37 99 235 / var(--tw-bg-opacity)); - } +.dark .dark\:bg-base-warning-600 { + --tw-bg-opacity: 1; + background-color: rgb(217 119 6 / var(--tw-bg-opacity)); +} - .dark\:bg-blue-900 { - --tw-bg-opacity: 1; - background-color: rgb(30 58 138 / var(--tw-bg-opacity)); - } +.dark .dark\:bg-base-warning-700 { + --tw-bg-opacity: 1; + background-color: rgb(180 83 9 / var(--tw-bg-opacity)); +} - .dark\:bg-brand-500 { - --tw-bg-opacity: 1; - background-color: rgb(139 92 246 / var(--tw-bg-opacity)); - } +.dark .dark\:bg-blue-600 { + --tw-bg-opacity: 1; + background-color: rgb(37 99 235 / var(--tw-bg-opacity)); +} - .dark\:bg-brand-600 { - --tw-bg-opacity: 1; - background-color: rgb(124 58 237 / var(--tw-bg-opacity)); - } +.dark .dark\:bg-blue-900 { + --tw-bg-opacity: 1; + background-color: rgb(30 58 138 / var(--tw-bg-opacity)); +} - .dark\:bg-brand-700 { - --tw-bg-opacity: 1; - background-color: rgb(109 40 217 / var(--tw-bg-opacity)); - } +.dark .dark\:bg-brand-500 { + --tw-bg-opacity: 1; + background-color: rgb(139 92 246 / var(--tw-bg-opacity)); +} - .dark\:bg-extra-emerald-900 { - --tw-bg-opacity: 1; - background-color: rgb(6 78 59 / var(--tw-bg-opacity)); - } +.dark .dark\:bg-brand-600 { + --tw-bg-opacity: 1; + background-color: rgb(124 58 237 / var(--tw-bg-opacity)); +} - .dark\:bg-extra-indigo-700 { - --tw-bg-opacity: 1; - background-color: rgb(67 56 202 / var(--tw-bg-opacity)); - } +.dark .dark\:bg-brand-700 { + --tw-bg-opacity: 1; + background-color: rgb(109 40 217 / var(--tw-bg-opacity)); +} - .dark\:bg-extra-rose-700 { - --tw-bg-opacity: 1; - background-color: rgb(190 18 60 / var(--tw-bg-opacity)); - } +.dark .dark\:bg-extra-emerald-900 { + --tw-bg-opacity: 1; + background-color: rgb(6 78 59 / var(--tw-bg-opacity)); +} - .dark\:bg-extra-rose-900 { - --tw-bg-opacity: 1; - background-color: rgb(136 19 55 / var(--tw-bg-opacity)); - } +.dark .dark\:bg-extra-indigo-700 { + --tw-bg-opacity: 1; + background-color: rgb(67 56 202 / var(--tw-bg-opacity)); +} - .dark\:bg-extra-yellow-900 { - --tw-bg-opacity: 1; - background-color: rgb(113 63 18 / var(--tw-bg-opacity)); - } +.dark .dark\:bg-extra-rose-700 { + --tw-bg-opacity: 1; + background-color: rgb(190 18 60 / var(--tw-bg-opacity)); +} - .dark\:bg-gray-300 { - --tw-bg-opacity: 1; - background-color: rgb(209 213 219 / var(--tw-bg-opacity)); - } +.dark .dark\:bg-extra-rose-900 { + --tw-bg-opacity: 1; + background-color: rgb(136 19 55 / var(--tw-bg-opacity)); +} - .dark\:bg-gray-600 { - --tw-bg-opacity: 1; - background-color: rgb(75 85 99 / var(--tw-bg-opacity)); - } +.dark .dark\:bg-extra-yellow-900 { + --tw-bg-opacity: 1; + background-color: rgb(113 63 18 / var(--tw-bg-opacity)); +} - .dark\:bg-gray-700 { - --tw-bg-opacity: 1; - background-color: rgb(55 65 81 / var(--tw-bg-opacity)); - } +.dark .dark\:bg-gray-300 { + --tw-bg-opacity: 1; + background-color: rgb(209 213 219 / var(--tw-bg-opacity)); +} - .dark\:bg-gray-800 { - --tw-bg-opacity: 1; - background-color: rgb(31 41 55 / var(--tw-bg-opacity)); - } +.dark .dark\:bg-gray-600 { + --tw-bg-opacity: 1; + background-color: rgb(75 85 99 / var(--tw-bg-opacity)); +} - .dark\:bg-green-600 { - --tw-bg-opacity: 1; - background-color: rgb(22 163 74 / var(--tw-bg-opacity)); - } +.dark .dark\:bg-gray-700 { + --tw-bg-opacity: 1; + background-color: rgb(55 65 81 / var(--tw-bg-opacity)); +} - .dark\:bg-inherit { - background-color: inherit; - } +.dark .dark\:bg-gray-800 { + --tw-bg-opacity: 1; + background-color: rgb(31 41 55 / var(--tw-bg-opacity)); +} - .dark\:bg-neutral-500 { - --tw-bg-opacity: 1; - background-color: rgb(100 116 139 / var(--tw-bg-opacity)); - } +.dark .dark\:bg-green-600 { + --tw-bg-opacity: 1; + background-color: rgb(22 163 74 / var(--tw-bg-opacity)); +} - .dark\:bg-neutral-600 { - --tw-bg-opacity: 1; - background-color: rgb(71 85 105 / var(--tw-bg-opacity)); - } +.dark .dark\:bg-inherit { + background-color: inherit; +} - .dark\:bg-neutral-700 { - --tw-bg-opacity: 1; - background-color: rgb(51 65 85 / var(--tw-bg-opacity)); - } +.dark .dark\:bg-neutral-500 { + --tw-bg-opacity: 1; + background-color: rgb(100 116 139 / var(--tw-bg-opacity)); +} - .dark\:bg-neutral-800 { - --tw-bg-opacity: 1; - background-color: rgb(30 41 59 / var(--tw-bg-opacity)); - } +.dark .dark\:bg-neutral-600 { + --tw-bg-opacity: 1; + background-color: rgb(71 85 105 / var(--tw-bg-opacity)); +} - .dark\:bg-neutral-900 { - --tw-bg-opacity: 1; - background-color: rgb(15 23 42 / var(--tw-bg-opacity)); - } +.dark .dark\:bg-neutral-700 { + --tw-bg-opacity: 1; + background-color: rgb(51 65 85 / var(--tw-bg-opacity)); +} - .dark\:bg-purple-600 { - --tw-bg-opacity: 1; - background-color: rgb(147 51 234 / var(--tw-bg-opacity)); - } +.dark .dark\:bg-neutral-800 { + --tw-bg-opacity: 1; + background-color: rgb(30 41 59 / var(--tw-bg-opacity)); +} - .dark\:bg-red-600 { - --tw-bg-opacity: 1; - background-color: rgb(220 38 38 / var(--tw-bg-opacity)); - } +.dark .dark\:bg-neutral-900 { + --tw-bg-opacity: 1; + background-color: rgb(15 23 42 / var(--tw-bg-opacity)); +} - .dark\:bg-clip-content { - background-clip: content-box; - } +.dark .dark\:bg-purple-600 { + --tw-bg-opacity: 1; + background-color: rgb(147 51 234 / var(--tw-bg-opacity)); +} - .dark\:font-bold { - font-weight: 700; - } +.dark .dark\:bg-red-600 { + --tw-bg-opacity: 1; + background-color: rgb(220 38 38 / var(--tw-bg-opacity)); +} - .dark\:text-base-error-300 { - --tw-text-opacity: 1; - color: rgb(252 165 165 / var(--tw-text-opacity)); - } +.dark .dark\:bg-opacity-60 { + --tw-bg-opacity: 0.6; +} - .dark\:text-base-error-500 { - --tw-text-opacity: 1; - color: rgb(239 68 68 / var(--tw-text-opacity)); - } +.dark .dark\:bg-clip-content { + background-clip: content-box; +} - .dark\:text-base-success-200 { - --tw-text-opacity: 1; - color: rgb(187 247 208 / var(--tw-text-opacity)); - } +.dark .dark\:font-bold { + font-weight: 700; +} - .dark\:text-base-success-300 { - --tw-text-opacity: 1; - color: rgb(134 239 172 / var(--tw-text-opacity)); - } +.dark .dark\:text-base-error-300 { + --tw-text-opacity: 1; + color: rgb(252 165 165 / var(--tw-text-opacity)); +} - .dark\:text-blue-300 { - --tw-text-opacity: 1; - color: rgb(147 197 253 / var(--tw-text-opacity)); - } +.dark .dark\:text-base-error-500 { + --tw-text-opacity: 1; + color: rgb(239 68 68 / var(--tw-text-opacity)); +} - .dark\:text-brand-100 { - --tw-text-opacity: 1; - color: rgb(237 233 254 / var(--tw-text-opacity)); - } +.dark .dark\:text-base-success-200 { + --tw-text-opacity: 1; + color: rgb(187 247 208 / var(--tw-text-opacity)); +} - .dark\:text-brand-200 { - --tw-text-opacity: 1; - color: rgb(221 214 254 / var(--tw-text-opacity)); - } +.dark .dark\:text-base-success-300 { + --tw-text-opacity: 1; + color: rgb(134 239 172 / var(--tw-text-opacity)); +} - .dark\:text-brand-400 { - --tw-text-opacity: 1; - color: rgb(167 139 250 / var(--tw-text-opacity)); - } +.dark .dark\:text-blue-300 { + --tw-text-opacity: 1; + color: rgb(147 197 253 / var(--tw-text-opacity)); +} - .dark\:text-extra-emerald-300 { - --tw-text-opacity: 1; - color: rgb(110 231 183 / var(--tw-text-opacity)); - } +.dark .dark\:text-brand-100 { + --tw-text-opacity: 1; + color: rgb(237 233 254 / var(--tw-text-opacity)); +} - .dark\:text-extra-rose-300 { - --tw-text-opacity: 1; - color: rgb(253 164 175 / var(--tw-text-opacity)); - } +.dark .dark\:text-brand-200 { + --tw-text-opacity: 1; + color: rgb(221 214 254 / var(--tw-text-opacity)); +} - .dark\:text-extra-yellow-300 { - --tw-text-opacity: 1; - color: rgb(253 224 71 / var(--tw-text-opacity)); - } +.dark .dark\:text-brand-400 { + --tw-text-opacity: 1; + color: rgb(167 139 250 / var(--tw-text-opacity)); +} - .dark\:text-gray-300 { - --tw-text-opacity: 1; - color: rgb(209 213 219 / var(--tw-text-opacity)); - } +.dark .dark\:text-extra-emerald-300 { + --tw-text-opacity: 1; + color: rgb(110 231 183 / var(--tw-text-opacity)); +} - .dark\:text-gray-400 { - --tw-text-opacity: 1; - color: rgb(156 163 175 / var(--tw-text-opacity)); - } +.dark .dark\:text-extra-rose-300 { + --tw-text-opacity: 1; + color: rgb(253 164 175 / var(--tw-text-opacity)); +} - .dark\:text-red-400 { - --tw-text-opacity: 1; - color: rgb(248 113 113 / var(--tw-text-opacity)); - } +.dark .dark\:text-extra-yellow-300 { + --tw-text-opacity: 1; + color: rgb(253 224 71 / var(--tw-text-opacity)); +} - .dark\:text-text-0 { - --tw-text-opacity: 1; - color: rgb(255 255 255 / var(--tw-text-opacity)); - } +.dark .dark\:text-gray-300 { + --tw-text-opacity: 1; + color: rgb(209 213 219 / var(--tw-text-opacity)); +} - .dark\:text-text-100 { - --tw-text-opacity: 1; - color: rgb(241 245 249 / var(--tw-text-opacity)); - } +.dark .dark\:text-gray-400 { + --tw-text-opacity: 1; + color: rgb(156 163 175 / var(--tw-text-opacity)); +} - .dark\:text-text-200 { - --tw-text-opacity: 1; - color: rgb(226 232 240 / var(--tw-text-opacity)); - } +.dark .dark\:text-neutral-100 { + --tw-text-opacity: 1; + color: rgb(241 245 249 / var(--tw-text-opacity)); +} - .dark\:text-text-300 { - --tw-text-opacity: 1; - color: rgb(203 213 225 / var(--tw-text-opacity)); - } +.dark .dark\:text-red-400 { + --tw-text-opacity: 1; + color: rgb(248 113 113 / var(--tw-text-opacity)); +} - .dark\:text-text-400 { - --tw-text-opacity: 1; - color: rgb(148 163 184 / var(--tw-text-opacity)); - } +.dark .dark\:text-text-0 { + --tw-text-opacity: 1; + color: rgb(255 255 255 / var(--tw-text-opacity)); +} - .dark\:text-white { - --tw-text-opacity: 1; - color: rgb(255 255 255 / var(--tw-text-opacity)); - } +.dark .dark\:text-text-100 { + --tw-text-opacity: 1; + color: rgb(241 245 249 / var(--tw-text-opacity)); +} - .dark\:ring-gray-900 { - --tw-ring-opacity: 1; - --tw-ring-color: rgb(17 24 39 / var(--tw-ring-opacity)); - } +.dark .dark\:text-text-200 { + --tw-text-opacity: 1; + color: rgb(226 232 240 / var(--tw-text-opacity)); +} - .dark\:after\:bg-neutral-600::after { - content: var(--tw-content); - --tw-bg-opacity: 1; - background-color: rgb(71 85 105 / var(--tw-bg-opacity)); - } +.dark .dark\:text-text-300 { + --tw-text-opacity: 1; + color: rgb(203 213 225 / var(--tw-text-opacity)); +} - .dark\:odd\:bg-neutral-800:nth-child(odd) { - --tw-bg-opacity: 1; - background-color: rgb(30 41 59 / var(--tw-bg-opacity)); - } +.dark .dark\:text-text-400 { + --tw-text-opacity: 1; + color: rgb(148 163 184 / var(--tw-text-opacity)); +} - .odd\:dark\:bg-brand-500:nth-child(odd) { - --tw-bg-opacity: 1; - background-color: rgb(139 92 246 / var(--tw-bg-opacity)); - } +.dark .dark\:text-white { + --tw-text-opacity: 1; + color: rgb(255 255 255 / var(--tw-text-opacity)); +} - .odd\:dark\:bg-neutral-800:nth-child(odd) { - --tw-bg-opacity: 1; - background-color: rgb(30 41 59 / var(--tw-bg-opacity)); - } +.dark .dark\:ring-gray-900 { + --tw-ring-opacity: 1; + --tw-ring-color: rgb(17 24 39 / var(--tw-ring-opacity)); +} - .dark\:hover\:bg-base-success-600:hover { - --tw-bg-opacity: 1; - background-color: rgb(22 163 74 / var(--tw-bg-opacity)); - } +.dark .dark\:after\:bg-neutral-600::after { + content: var(--tw-content); + --tw-bg-opacity: 1; + background-color: rgb(71 85 105 / var(--tw-bg-opacity)); +} - .dark\:hover\:bg-base-warning-600:hover { - --tw-bg-opacity: 1; - background-color: rgb(217 119 6 / var(--tw-bg-opacity)); - } +.dark .dark\:odd\:bg-neutral-800:nth-child(odd) { + --tw-bg-opacity: 1; + background-color: rgb(30 41 59 / var(--tw-bg-opacity)); +} - .dark\:hover\:bg-blue-700:hover { - --tw-bg-opacity: 1; - background-color: rgb(29 78 216 / var(--tw-bg-opacity)); - } +.dark .odd\:dark\:bg-brand-500:nth-child(odd) { + --tw-bg-opacity: 1; + background-color: rgb(139 92 246 / var(--tw-bg-opacity)); +} - .dark\:hover\:bg-brand-600:hover { - --tw-bg-opacity: 1; - background-color: rgb(124 58 237 / var(--tw-bg-opacity)); - } +.dark .odd\:dark\:bg-neutral-800:nth-child(odd) { + --tw-bg-opacity: 1; + background-color: rgb(30 41 59 / var(--tw-bg-opacity)); +} - .dark\:hover\:bg-gray-600:hover { - --tw-bg-opacity: 1; - background-color: rgb(75 85 99 / var(--tw-bg-opacity)); - } +.dark .dark\:hover\:bg-base-success-600:hover { + --tw-bg-opacity: 1; + background-color: rgb(22 163 74 / var(--tw-bg-opacity)); +} - .dark\:hover\:bg-gray-700:hover { - --tw-bg-opacity: 1; - background-color: rgb(55 65 81 / var(--tw-bg-opacity)); - } +.dark .dark\:hover\:bg-base-warning-600:hover { + --tw-bg-opacity: 1; + background-color: rgb(217 119 6 / var(--tw-bg-opacity)); +} - .dark\:hover\:bg-green-700:hover { - --tw-bg-opacity: 1; - background-color: rgb(21 128 61 / var(--tw-bg-opacity)); - } +.dark .dark\:hover\:bg-blue-700:hover { + --tw-bg-opacity: 1; + background-color: rgb(29 78 216 / var(--tw-bg-opacity)); +} - .dark\:hover\:bg-neutral-600:hover { - --tw-bg-opacity: 1; - background-color: rgb(71 85 105 / var(--tw-bg-opacity)); - } +.dark .dark\:hover\:bg-brand-600:hover { + --tw-bg-opacity: 1; + background-color: rgb(124 58 237 / var(--tw-bg-opacity)); +} - .dark\:hover\:bg-neutral-900:hover { - --tw-bg-opacity: 1; - background-color: rgb(15 23 42 / var(--tw-bg-opacity)); - } +.dark .dark\:hover\:bg-gray-600:hover { + --tw-bg-opacity: 1; + background-color: rgb(75 85 99 / var(--tw-bg-opacity)); +} - .dark\:hover\:bg-purple-700:hover { - --tw-bg-opacity: 1; - background-color: rgb(126 34 206 / var(--tw-bg-opacity)); - } +.dark .dark\:hover\:bg-gray-700:hover { + --tw-bg-opacity: 1; + background-color: rgb(55 65 81 / var(--tw-bg-opacity)); +} - .dark\:hover\:bg-red-700:hover { - --tw-bg-opacity: 1; - background-color: rgb(185 28 28 / var(--tw-bg-opacity)); - } +.dark .dark\:hover\:bg-green-700:hover { + --tw-bg-opacity: 1; + background-color: rgb(21 128 61 / var(--tw-bg-opacity)); +} - .dark\:hover\:bg-transparent:hover { - background-color: transparent; - } +.dark .dark\:hover\:bg-neutral-600:hover { + --tw-bg-opacity: 1; + background-color: rgb(71 85 105 / var(--tw-bg-opacity)); +} - .hover\:dark\:bg-neutral-500:hover { - --tw-bg-opacity: 1; - background-color: rgb(100 116 139 / var(--tw-bg-opacity)); - } +.dark .dark\:hover\:bg-neutral-900:hover { + --tw-bg-opacity: 1; + background-color: rgb(15 23 42 / var(--tw-bg-opacity)); +} - .hover\:dark\:bg-neutral-600:hover { - --tw-bg-opacity: 1; - background-color: rgb(71 85 105 / var(--tw-bg-opacity)); - } +.dark .dark\:hover\:bg-purple-700:hover { + --tw-bg-opacity: 1; + background-color: rgb(126 34 206 / var(--tw-bg-opacity)); +} - .hover\:dark\:bg-neutral-900:hover { - --tw-bg-opacity: 1; - background-color: rgb(15 23 42 / var(--tw-bg-opacity)); - } +.dark .dark\:hover\:bg-red-700:hover { + --tw-bg-opacity: 1; + background-color: rgb(185 28 28 / var(--tw-bg-opacity)); +} - .dark\:hover\:text-brand-300:hover { - --tw-text-opacity: 1; - color: rgb(196 181 253 / var(--tw-text-opacity)); - } +.dark .dark\:hover\:bg-transparent:hover { + background-color: transparent; +} - .dark\:hover\:text-brand-400:hover { - --tw-text-opacity: 1; - color: rgb(167 139 250 / var(--tw-text-opacity)); - } +.dark .hover\:dark\:bg-neutral-500:hover { + --tw-bg-opacity: 1; + background-color: rgb(100 116 139 / var(--tw-bg-opacity)); +} - .dark\:focus\:ring-blue-800:focus { - --tw-ring-opacity: 1; - --tw-ring-color: rgb(30 64 175 / var(--tw-ring-opacity)); - } +.dark .hover\:dark\:bg-neutral-600:hover { + --tw-bg-opacity: 1; + background-color: rgb(71 85 105 / var(--tw-bg-opacity)); +} - .dark\:focus\:ring-green-800:focus { - --tw-ring-opacity: 1; - --tw-ring-color: rgb(22 101 52 / var(--tw-ring-opacity)); - } +.dark .hover\:dark\:bg-neutral-900:hover { + --tw-bg-opacity: 1; + background-color: rgb(15 23 42 / var(--tw-bg-opacity)); +} - .dark\:focus\:ring-purple-900:focus { - --tw-ring-opacity: 1; - --tw-ring-color: rgb(88 28 135 / var(--tw-ring-opacity)); - } +.dark .dark\:hover\:text-brand-300:hover { + --tw-text-opacity: 1; + color: rgb(196 181 253 / var(--tw-text-opacity)); +} - .dark\:focus\:ring-red-900:focus { - --tw-ring-opacity: 1; - --tw-ring-color: rgb(127 29 29 / var(--tw-ring-opacity)); - } +.dark .dark\:hover\:text-brand-400:hover { + --tw-text-opacity: 1; + color: rgb(167 139 250 / var(--tw-text-opacity)); +} - .dark\:focus\:ring-yellow-900:focus { - --tw-ring-opacity: 1; - --tw-ring-color: rgb(113 63 18 / var(--tw-ring-opacity)); - } +.dark .dark\:focus\:ring-blue-800:focus { + --tw-ring-opacity: 1; + --tw-ring-color: rgb(30 64 175 / var(--tw-ring-opacity)); +} + +.dark .dark\:focus\:ring-green-800:focus { + --tw-ring-opacity: 1; + --tw-ring-color: rgb(22 101 52 / var(--tw-ring-opacity)); +} + +.dark .dark\:focus\:ring-purple-900:focus { + --tw-ring-opacity: 1; + --tw-ring-color: rgb(88 28 135 / var(--tw-ring-opacity)); +} + +.dark .dark\:focus\:ring-red-900:focus { + --tw-ring-opacity: 1; + --tw-ring-color: rgb(127 29 29 / var(--tw-ring-opacity)); +} + +.dark .dark\:focus\:ring-yellow-900:focus { + --tw-ring-opacity: 1; + --tw-ring-color: rgb(113 63 18 / var(--tw-ring-opacity)); +} + +.dark .disabled\:dark\:text-neutral-500:disabled { + --tw-text-opacity: 1; + color: rgb(100 116 139 / var(--tw-text-opacity)); } @media (min-width: 640px) { @@ -3277,4 +3390,4 @@ html { .\32xl\:w-44 { width: 11rem; } -} \ No newline at end of file +} diff --git a/src/component-library/tailwind.css b/src/component-library/tailwind.css index e3365957b..1b1e89882 100644 --- a/src/component-library/tailwind.css +++ b/src/component-library/tailwind.css @@ -7,4 +7,4 @@ font-size: 16px; /* font-family: monospace; */ } -} \ No newline at end of file +} diff --git a/src/component-library/ui/loading-spinner.tsx b/src/component-library/ui/loading-spinner.tsx new file mode 100644 index 000000000..c50b51ccb --- /dev/null +++ b/src/component-library/ui/loading-spinner.tsx @@ -0,0 +1,23 @@ +import {cn} from "@/component-library/utils"; +import React from "react"; + +export const LoadingSpinner = (props: { size?: number, className?: string }) => { + const size = props.size ?? 24; + return ( + + + + ); +}; \ No newline at end of file diff --git a/src/component-library/ui/skeleton.tsx b/src/component-library/ui/skeleton.tsx new file mode 100644 index 000000000..5abf6ac54 --- /dev/null +++ b/src/component-library/ui/skeleton.tsx @@ -0,0 +1,15 @@ +import { cn } from "@/component-library/utils" + +function Skeleton({ + className, + ...props +}: React.HTMLAttributes) { + return ( +
+ ) +} + +export { Skeleton } diff --git a/src/component-library/utils.ts b/src/component-library/utils.ts index c6d495528..4c3ced2eb 100644 --- a/src/component-library/utils.ts +++ b/src/component-library/utils.ts @@ -1,3 +1,10 @@ +import { type ClassValue, clsx } from "clsx" +import { twMerge } from "tailwind-merge" + +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)) +} + // Function to emulate pausing between interactions export function sleep(ms: number) { return new Promise((resolve) => setTimeout(resolve, ms)); diff --git a/src/lib/core/port/primary/list-file-replicas-ports.ts b/src/lib/core/port/primary/list-file-replicas-ports.ts index 4a356f664..e3ad89f04 100644 --- a/src/lib/core/port/primary/list-file-replicas-ports.ts +++ b/src/lib/core/port/primary/list-file-replicas-ports.ts @@ -1,6 +1,6 @@ import { BaseAuthenticatedInputPort, BaseStreamingOutputPort } from "@/lib/sdk/primary-ports"; import { ListFileReplicasResponse, ListFileReplicasRequest, ListFileReplicasError } from "@/lib/core/usecase-models/list-file-replicas-usecase-models"; -import { FilereplicaStateViewModel } from "@/lib/infrastructure/data/view-model/did"; +import { FileReplicaStateViewModel } from "@/lib/infrastructure/data/view-model/did"; /** * @interface ListFileReplicasInputPort that abstracts the usecase. @@ -11,4 +11,4 @@ export interface ListFileReplicasInputPort extends BaseAuthenticatedInputPort
  • {} +export interface ListFileReplicasOutputPort extends BaseStreamingOutputPort {} diff --git a/src/lib/core/use-case/list-file-replicas-usecase.ts b/src/lib/core/use-case/list-file-replicas-usecase.ts index 127d0ce58..06794565d 100644 --- a/src/lib/core/use-case/list-file-replicas-usecase.ts +++ b/src/lib/core/use-case/list-file-replicas-usecase.ts @@ -4,14 +4,14 @@ import { AuthenticatedRequestModel } from "@/lib/sdk/usecase-models"; import { ListFileReplicasError, ListFileReplicasRequest, ListFileReplicasResponse } from "@/lib/core/usecase-models/list-file-replicas-usecase-models"; import { ListFileReplicasInputPort, type ListFileReplicasOutputPort } from "@/lib/core/port/primary/list-file-replicas-ports"; -import { FilereplicaStateViewModel } from "@/lib/infrastructure/data/view-model/did"; +import { FileReplicaStateViewModel } from "@/lib/infrastructure/data/view-model/did"; import { ListReplicasDTO } from "@/lib/core/dto/replica-dto"; import { FileReplicaStateDTO} from "@/lib/core/dto/replica-dto"; import type ReplicaGatewayOutputPort from "@/lib/core/port/secondary/replica-gateway-output-port"; @injectable() -export default class ListFileReplicasUseCase extends BaseSingleEndpointStreamingUseCase, ListFileReplicasResponse, ListFileReplicasError, ListReplicasDTO, FileReplicaStateDTO, FilereplicaStateViewModel> implements ListFileReplicasInputPort { +export default class ListFileReplicasUseCase extends BaseSingleEndpointStreamingUseCase, ListFileReplicasResponse, ListFileReplicasError, ListReplicasDTO, FileReplicaStateDTO, FileReplicaStateViewModel> implements ListFileReplicasInputPort { constructor( protected readonly presenter: ListFileReplicasOutputPort, diff --git a/src/lib/infrastructure/data/view-model/did.ts b/src/lib/infrastructure/data/view-model/did.ts index e543dd9d8..71123c312 100644 --- a/src/lib/infrastructure/data/view-model/did.ts +++ b/src/lib/infrastructure/data/view-model/did.ts @@ -11,7 +11,7 @@ export interface DIDMetaViewModel extends DIDMeta, BaseViewModel {} export interface DIDKeyValuePairsDataViewModel extends DIDKeyValuePairsData, BaseViewModel {} export interface DIDRulesViewModel extends DIDRules, BaseViewModel {} export interface DIDDatasetReplicasViewModel extends DIDDatasetReplicas, BaseViewModel {} -export interface FilereplicaStateViewModel extends FileReplicaState, BaseViewModel {} +export interface FileReplicaStateViewModel extends FileReplicaState, BaseViewModel {} export interface FilereplicaStateDViewModel extends FileReplicaStateD, BaseViewModel {} export function generateEmptyDIDRulesViewModel(): DIDRulesViewModel { @@ -34,7 +34,7 @@ export function generateEmptyDIDViewModel(): DIDViewModel { } } -export function generateEmptyFilereplicaStateViewModel(): FilereplicaStateViewModel { +export function generateEmptyFilereplicaStateViewModel(): FileReplicaStateViewModel { return { status: "error", rse: "", diff --git a/src/lib/infrastructure/data/view-model/page-did.d.ts b/src/lib/infrastructure/data/view-model/page-did.d.ts deleted file mode 100644 index 1be6a6987..000000000 --- a/src/lib/infrastructure/data/view-model/page-did.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { DateISO, ReplicaState, RSEBlockState } from "@/lib/core/entity/rucio" -import { RuleState } from "@/lib/core/entity/rucio" -import { ObjectFlags } from "typescript" - - - diff --git a/src/lib/infrastructure/hooks/useChunkedStream.ts b/src/lib/infrastructure/hooks/useChunkedStream.ts new file mode 100644 index 000000000..ffa05b363 --- /dev/null +++ b/src/lib/infrastructure/hooks/useChunkedStream.ts @@ -0,0 +1,113 @@ +import {useCallback, useState, useRef, useEffect} from "react"; + +export enum StreamingErrorType { + BAD_METHOD_CALL = 'bad_method_call', + NETWORK_ERROR = 'network_error', + BAD_REQUEST = 'bad_request', + NOT_FOUND = 'not_found', + INVALID_RESPONSE = 'invalid_response', + PARSING_ERROR = 'parsing_error', +} + +export interface StreamingError { + type: StreamingErrorType, + message: string +} + + +export enum StreamingStatus { + STOPPED = 'stopped', + RUNNING = 'running', +} + +type StreamingCallback = (data: TData[]) => void; + +/** + * @param url - A path to the streamed resource + * @param fetchOptions - A set of options to configure the request + * @param onData - A callback that accepts each resulting object. Throws an error if the object is invalid + */ +export type StreamingSettings = { + url: string, + fetchOptions?: RequestInit, + onData: StreamingCallback, + updateDelay?: number, + maxUpdateLength?: number +} + +export interface UseChunkedStream { + status: StreamingStatus, + error: StreamingError | undefined, + start: (options: StreamingSettings) => void, + stop: () => void, +} + +/** + * @description A React hook that fetches and parses NDJSON from a streamable endpoint + * @template TData - The expected type of received objects + * @returns status - An indication if there is ongoing streaming + * @returns start - A function which begins the fetching if there was none prior to the call + * @returns stop - A function which interrupts the fetching while deleting its state + * @returns error - A string with explanation of the error + */ +export default function useChunkedStream(): UseChunkedStream { + const [status, setStatus] = useState(StreamingStatus.STOPPED); + const [error, setError] = useState(undefined); + // These refs are required for the correct state handling during fetching + const workerRef = useRef(null); + + useEffect(() => { + // Cleanup function to terminate the worker + return () => { + if (workerRef.current) { + workerRef.current.terminate(); + workerRef.current = null; + } + }; + }, []); + + const start = useCallback((settings: StreamingSettings) => { + if (workerRef.current) { + setError({type: StreamingErrorType.BAD_METHOD_CALL, message: 'Another request is currently running.'}); + return; + } + + setStatus(StreamingStatus.RUNNING); + setError(undefined); + + const worker = new Worker('/streamWorker.js'); + workerRef.current = worker; + + worker.onmessage = (event) => { + const {type, data, error} = event.data; + + if (type === 'data') { + settings.onData(data); + } else if (type === 'error') { + setError(error); + stop(); + } else if (type === 'finish') { + stop(); + } + }; + + worker.postMessage({ + url: settings.url, + fetchOptions: settings.fetchOptions, + updateDelay: settings.updateDelay, + maxUpdateLength: settings.maxUpdateLength + }); + }, []); + + const stop = useCallback(() => { + if (workerRef.current) { + workerRef.current.terminate(); + workerRef.current = null; + setStatus(StreamingStatus.STOPPED); + } else { + setError({type: StreamingErrorType.BAD_METHOD_CALL, message: 'There is no active fetching.'}); + } + }, []); + + return {stop, start, status, error}; +} \ No newline at end of file diff --git a/src/lib/infrastructure/hooks/useDarkMode.ts b/src/lib/infrastructure/hooks/useDarkMode.ts new file mode 100644 index 000000000..68e5df32c --- /dev/null +++ b/src/lib/infrastructure/hooks/useDarkMode.ts @@ -0,0 +1,34 @@ +import { useEffect, useState } from 'react'; + +/** + * A hook that observes the color mode of the page. + * It is intended for use inside components that cannot be styled with Tailwind. + */ +const useDarkMode = () => { + const [isDarkMode, setIsDarkMode] = useState( + document.body.classList.contains('dark') + ); + + useEffect(() => { + const className = 'dark'; + const element = document.body; + + const toggleDarkMode = () => { + setIsDarkMode(element.classList.contains(className)); + }; + + const observer = new MutationObserver(toggleDarkMode); + observer.observe(element, { + attributes: true, + attributeFilter: ['class'], + }); + + toggleDarkMode(); + + return () => observer.disconnect(); + }, []); + + return isDarkMode; +}; + +export default useDarkMode; diff --git a/src/lib/infrastructure/hooks/useThrottleArray.ts b/src/lib/infrastructure/hooks/useThrottleArray.ts new file mode 100644 index 000000000..a6016b083 --- /dev/null +++ b/src/lib/infrastructure/hooks/useThrottleArray.ts @@ -0,0 +1,51 @@ +import {useCallback, useEffect, useRef, useState} from "react"; + +type ThrottleArrayOptions = { + interval: number; + maxUpdateLength: number; +}; + +/** + * A React hook that accepts data and flushes no more than {options.maxUpdateLength} elements each {options.interval} ms. + * @param options + * @returns data - a desired state of the array + * @returns pushData - a function to enqueue an element for the state update + */ +export function useThrottleArray(options: ThrottleArrayOptions): [T[], (item: T) => void] { + const [data, setData] = useState([]); + const bufferRef = useRef([]); + const intervalRef = useRef(null); + + // Don't update the state with incoming data; push it to the buffer instead + const pushData = useCallback((item: T) => { + bufferRef.current.push(item); + }, []); + + const flushBuffer = useCallback(() => { + if (bufferRef.current.length === 0) return; + + if (bufferRef.current.length > options.maxUpdateLength) { + // Remove the first {options.maxUpdateLength} elements from the buffer + const newBuffer: T[] = bufferRef.current.splice(0, options.maxUpdateLength) + setData(prevData => [...prevData, ...newBuffer]); + } else { + setData(prevData => [...prevData, ...bufferRef.current]); + bufferRef.current = []; + } + }, []); + + useEffect(() => { + intervalRef.current = setInterval(() => { + flushBuffer(); + }, options.interval); + + // Cleanup interval on component unmount + return () => { + if (intervalRef.current) { + clearInterval(intervalRef.current); + } + }; + }, [options.interval, flushBuffer]); + + return [data, pushData]; +} \ No newline at end of file diff --git a/src/lib/infrastructure/ioc/features/list-file-replicas-feature.ts b/src/lib/infrastructure/ioc/features/list-file-replicas-feature.ts index ce137bd5c..aa145b2b7 100644 --- a/src/lib/infrastructure/ioc/features/list-file-replicas-feature.ts +++ b/src/lib/infrastructure/ioc/features/list-file-replicas-feature.ts @@ -6,7 +6,7 @@ import { } from "@/lib/core/usecase-models/list-file-replicas-usecase-models" import { ListFileReplicasControllerParameters } from "@/lib/infrastructure/controller/list-file-replicas-controller" import ListFileReplicasController from "@/lib/infrastructure/controller/list-file-replicas-controller" -import { FilereplicaStateViewModel } from "@/lib/infrastructure/data/view-model/did" +import { FileReplicaStateViewModel } from "@/lib/infrastructure/data/view-model/did" import { BaseStreamableFeature, IOCSymbols, @@ -28,7 +28,7 @@ export default class ListFileReplicasFeature extends BaseStreamableFeature< ListFileReplicasRequest, ListFileReplicasResponse, ListFileReplicasError, - FilereplicaStateViewModel + FileReplicaStateViewModel > { constructor(appContainer: Container) { const replicaGateway = appContainer.get(GATEWAYS.REPLICA) diff --git a/src/lib/infrastructure/presenter/list-file-replicas-presenter.ts b/src/lib/infrastructure/presenter/list-file-replicas-presenter.ts index 53426ee45..9bd696d59 100644 --- a/src/lib/infrastructure/presenter/list-file-replicas-presenter.ts +++ b/src/lib/infrastructure/presenter/list-file-replicas-presenter.ts @@ -3,11 +3,11 @@ import { ListFileReplicasResponse, } from '@/lib/core/usecase-models/list-file-replicas-usecase-models' import { NextApiResponse } from 'next' -import { FilereplicaStateViewModel, generateEmptyFilereplicaStateViewModel } from '@/lib/infrastructure/data/view-model/did' +import { FileReplicaStateViewModel, generateEmptyFilereplicaStateViewModel } from '@/lib/infrastructure/data/view-model/did' import { BaseStreamingPresenter } from '@/lib/sdk/presenter' import { ListFileReplicasOutputPort } from '@/lib/core/port/primary/list-file-replicas-ports' -export default class ListFileReplicasPresenter extends BaseStreamingPresenter implements ListFileReplicasOutputPort { +export default class ListFileReplicasPresenter extends BaseStreamingPresenter implements ListFileReplicasOutputPort { response: NextApiResponse constructor(response: NextApiResponse) { @@ -15,15 +15,15 @@ export default class ListFileReplicasPresenter extends BaseStreamingPresenter
  • { - it("Checks empty render of the story", async () => { - await act(async () => render( - fixtureDIDViewModel()))} - didQuery={jest.fn(x => console.log(x))} - didMetaQuery={jest.fn(x => console.log(x))} - didMetaQueryResponse={{} as DIDMetaViewModel} - /> - )) - // check if DID Search Pattern Input exists - const searchPatternInput = screen.getByLabelText("DID Search Pattern") - expect(searchPatternInput).toHaveValue("") - // check if query is set to Containers and Datasets - const datasetButton= screen.getByLabelText("Dataset") - expect(datasetButton).toBeChecked() - const filesButton = screen.getByLabelText("File") - expect(filesButton).not.toBeChecked() - // Check that `No DID selected` is shown instead of the DIDMetaView, etc - const noDIDSelectedDiv = screen.getByText("No DID selected").closest("div") - expect(noDIDSelectedDiv).toHaveClass("block") - const goDIDViewLink = screen.getByText("Go To DID Page") - expect(goDIDViewLink?.parentElement).toHaveClass("hidden") - // Check that the DID Table Search is empty - const didFilterInputs = screen.getAllByPlaceholderText("Filter DID") - didFilterInputs.map((didFilterInput) => { expect(didFilterInput).toHaveValue("") }) - // Check that we are on page 1 of 0 (I know, technically this is a bug) - const paginationNav = screen.getByRole("navigation", { name: "Table Pagination" }) - expect(paginationNav).toBeInTheDocument() - const totalPageCountSpan = screen.getByRole("generic", { name: "Total Page Count" }) - expect(totalPageCountSpan).toHaveTextContent("0") - const currentPageInput = screen.getByRole("spinbutton", { name: "Current Page Number" }) // refers to the input element (with restricted values) - expect(currentPageInput).toHaveValue(1) - // check pagination buttons - const firstPageButton = screen.getByRole("button", { name: "First Page" }) - expect(firstPageButton).toBeDisabled() - const previousPageButton = screen.getByRole("button", { name: "Previous Page" }) - expect(previousPageButton).toBeDisabled() - const nextPageButton = screen.getByRole("button", { name: "Next Page" }) - expect(nextPageButton).toBeDisabled() - const lastPageButton = screen.getByRole("button", { name: "Last Page" }) - expect(lastPageButton).toBeDisabled() - }) - it("Checks render with data and user input", async () => { - /* - PROBLEM: - we make use of `aria-label` to identify the table rows, but the - `aria-label` is only for *interactive* elements so we can't use it - on the table rows, which are not interactive - SOLUTION: - remove `aria-label` from the table rows, grab table rows differently. - */ - const mockDIDMeta = fixtureDIDMetaViewModel() - await act(async () => render( - fixtureDIDViewModel()))} - didQuery={jest.fn(x => console.log(x))} - didMetaQuery={jest.fn(x => console.log(x))} - didMetaQueryResponse={mockDIDMeta} - /> - )) - const tableRows = screen.getAllByRole("row", {selected: false}) - // check that metaview is still invisible - const noDIDSelectedDiv = screen.getByText("No DID selected").closest("div") - expect(noDIDSelectedDiv).toHaveClass("block") - // click the first row - fireEvent.click(tableRows[0]) - expect(noDIDSelectedDiv).not.toHaveClass("block") - const metaDataDiv = screen.getByRole("generic", { name: "DID Metadata Quick Summary" }) - expect(metaDataDiv).toHaveClass("flex") - const goDIDViewButton = screen.getByRole("link", { name: "Go To DID Page" }) - expect(goDIDViewButton).not.toHaveClass("hidden") - const didCreationRow = screen.getByRole("row", { name: "Date of DID Creation" }) - expect(didCreationRow).toHaveTextContent(format("yyyy-MM-dd", new Date(mockDIDMeta.created_at))) - const didObsoleteRow = screen.getByRole("row", { name: "DID Obsolete" }) - expect(didObsoleteRow).toHaveTextContent(mockDIDMeta.obsolete ? "True" : "False") - }) -}) \ No newline at end of file diff --git a/test/fixtures/table-fixtures.ts b/test/fixtures/table-fixtures.ts index 2a0d83075..a77e803fe 100644 --- a/test/fixtures/table-fixtures.ts +++ b/test/fixtures/table-fixtures.ts @@ -1,21 +1,43 @@ -import { faker } from '@faker-js/faker' +import {faker} from '@faker-js/faker' import { - LockState, DIDType, RuleNotification, RuleState, - RSEBlockState, SubscriptionState, DIDAvailability, + DIDKeyValuePair, + DIDType, + LockState, ReplicaState, - RSEType, - RSEProtocol, RSEAttribute, + RSEBlockState, + RSEProtocol, + RSEType, + RuleNotification, + RuleState, + SubscriptionState, } from '@/lib/core/entity/rucio' -import { RSEAccountUsageLimitViewModel, RSEAttributeViewModel, RSEProtocolViewModel, RSEViewModel } from '@/lib/infrastructure/data/view-model/rse'; -import { UseComDOM } from '@/lib/infrastructure/hooks/useComDOM'; -import { SubscriptionRuleStatesViewModel, SubscriptionViewModel } from '@/lib/infrastructure/data/view-model/subscriptions'; -import { BaseViewModel } from '@/lib/sdk/view-models'; -import { DIDDatasetReplicasViewModel, DIDKeyValuePairsDataViewModel, DIDLongViewModel, DIDMetaViewModel, DIDRulesViewModel, DIDViewModel, FilereplicaStateDViewModel, FilereplicaStateViewModel } from '@/lib/infrastructure/data/view-model/did'; -import { RuleMetaViewModel, RulePageLockEntryViewModel, RuleViewModel } from '@/lib/infrastructure/data/view-model/rule'; -import { DIDKeyValuePair } from '@/lib/core/entity/rucio'; -import { ListDIDsViewModel } from '@/lib/infrastructure/data/view-model/list-did'; +import { + RSEAccountUsageLimitViewModel, + RSEAttributeViewModel, + RSEProtocolViewModel, + RSEViewModel +} from '@/lib/infrastructure/data/view-model/rse'; +import {UseComDOM} from '@/lib/infrastructure/hooks/useComDOM'; +import { + SubscriptionRuleStatesViewModel, + SubscriptionViewModel +} from '@/lib/infrastructure/data/view-model/subscriptions'; +import {BaseViewModel} from '@/lib/sdk/view-models'; +import { + DIDDatasetReplicasViewModel, + DIDKeyValuePairsDataViewModel, + DIDLongViewModel, + DIDMetaViewModel, + DIDRulesViewModel, + DIDViewModel, + FilereplicaStateDViewModel, + FileReplicaStateViewModel +} from '@/lib/infrastructure/data/view-model/did'; +import {RuleMetaViewModel, RulePageLockEntryViewModel, RuleViewModel} from '@/lib/infrastructure/data/view-model/rule'; +import {ListDIDsViewModel} from '@/lib/infrastructure/data/view-model/list-did'; +import useChunkedStream, {StreamingSettings, StreamingStatus} from "@/lib/infrastructure/hooks/useChunkedStream"; export function mockUseComDOM(data: T[]): UseComDOM { return { @@ -33,6 +55,17 @@ export function mockUseComDOM(data: T[]): UseComDOM } as UseComDOM } +export function mockUseChunkedStream(data: T[]): ReturnType> { + return { + start: (settings: StreamingSettings) => { + settings.onData(data); + }, + stop: () => {}, + status: StreamingStatus.STOPPED, + error: undefined + }; +} + export function mockBaseVM(fail?: "none" | "some" | "all"): BaseViewModel { const setting = fail ?? "none" return { @@ -148,7 +181,7 @@ export function fixtureRuleMetaViewModel(): RuleMetaViewModel { export function fixtureRSEAccountUsageLimitViewModel(): RSEAccountUsageLimitViewModel { const bytes_limit = faker.number.int({ min: 0, max: 1e12 }) const used_bytes = faker.number.int({ min: 0, max: 1e12 }) - const has_quota = bytes_limit > used_bytes + const has_quota = bytes_limit > used_bytes return { ...mockBaseVM(), rse_id: faker.string.uuid(), @@ -319,7 +352,7 @@ export function fixtureDIDRulesViewModel(): DIDRulesViewModel { } } -export function fixtureFilereplicaStateViewModel(): FilereplicaStateViewModel { +export function fixtureFilereplicaStateViewModel(): FileReplicaStateViewModel { return { ...mockBaseVM(), rse: createRSEName(), diff --git a/test/hook/jest.hook.config.js b/test/hook/jest.hook.config.js new file mode 100644 index 000000000..44018a0db --- /dev/null +++ b/test/hook/jest.hook.config.js @@ -0,0 +1,30 @@ +const nextJest = require('next/jest') + +const createJestConfig = nextJest({ + // Provide the path to your Next.js app to load next.config.js and .env files in your test environment + dir: './', +}) + +// Add any custom config to be passed to Jest +/** @type {import('jest').Config} */ +const customJestConfig = { + displayName: 'hook', + rootDir: '../../', + // Add more setup options before each test is run + setupFilesAfterEnv: ['/test/hook/jest.hook.setup.ts'], + // if using TypeScript with a baseUrl set to the root directory then you need the below for alias' to work + moduleDirectories: ['node_modules', '/'], + + // If you're using [Module Path Aliases](https://nextjs.org/docs/advanced-features/module-path-aliases), + // you will have to add the moduleNameMapper in order for jest to resolve your absolute paths. + // The paths have to be matching with the paths option within the compilerOptions in the tsconfig.json + // For example: + moduleNameMapper: { + '@/(.*)$': '/src/$1', + }, + testEnvironment: 'jest-environment-jsdom', + +} + +// createJestConfig is exported this way to ensure that next/jest can load the Next.js config which is async +module.exports = createJestConfig(customJestConfig) diff --git a/test/hook/jest.hook.setup.ts b/test/hook/jest.hook.setup.ts new file mode 100644 index 000000000..73c927952 --- /dev/null +++ b/test/hook/jest.hook.setup.ts @@ -0,0 +1,18 @@ +import '@testing-library/jest-dom/extend-expect' +import "reflect-metadata" +import fetchMock from 'jest-fetch-mock' +import "@inrupt/jest-jsdom-polyfills" +fetchMock.enableMocks() + +import { loadEnvConfig } from '@next/env' + +const noop = () => {}; +Object.defineProperty(window, 'scrollTo', { value: noop, writable: true }); + +const setupTests = async () => { + const projectDir = process.cwd() + loadEnvConfig(projectDir) + +} + +export default setupTests \ No newline at end of file diff --git a/test/hook/useThrottleArray.test.ts b/test/hook/useThrottleArray.test.ts new file mode 100644 index 000000000..cf5021f65 --- /dev/null +++ b/test/hook/useThrottleArray.test.ts @@ -0,0 +1,91 @@ +import {act, cleanup, renderHook} from "@testing-library/react-hooks"; +import {useThrottleArray} from "@/lib/infrastructure/hooks/useThrottleArray"; + +describe('useThrottleArray', () => { + afterEach(() => { + cleanup(); + }); + + it('Should delay updating the state', async () => { + const {result, waitForNextUpdate} = renderHook(() => useThrottleArray({ + interval: 50, + maxUpdateLength: 10 + })); + + act(() => { + const pushData = result.current[1]; + pushData('test1'); + pushData('test2'); + pushData('test3'); + }); + + await new Promise(resolve => setTimeout(resolve, 25)); + + const data1 = result.current[0]; + expect(data1).toEqual([]); + + await waitForNextUpdate(); + + const data2 = result.current[0]; + expect(data2).toEqual(['test1', 'test2', 'test3']); + }); + + it('Should only update the state by maxUpdateLength', async () => { + const {result, waitForNextUpdate} = renderHook(() => useThrottleArray({ + interval: 50, + maxUpdateLength: 2 + })); + + act(() => { + const pushData = result.current[1]; + pushData('test1'); + pushData('test2'); + pushData('test3'); + pushData('test4'); + pushData('test5'); + }); + + await waitForNextUpdate(); + + const data1 = result.current[0]; + expect(data1).toEqual(['test1', 'test2']); + + await waitForNextUpdate(); + + const data2 = result.current[0]; + expect(data2).toEqual(['test1', 'test2', 'test3', 'test4']); + + await waitForNextUpdate(); + + const data3 = result.current[0]; + expect(data3).toEqual(['test1', 'test2', 'test3', 'test4', 'test5']); + }); + + it('Does not keep updating the state on unmount', async () => { + const {result, waitForNextUpdate, unmount} = renderHook(() => useThrottleArray({ + interval: 50, + maxUpdateLength: 2 + })); + + act(() => { + const pushData = result.current[1]; + pushData('test1'); + pushData('test2'); + pushData('test3'); + pushData('test4'); + pushData('test5'); + }); + + await waitForNextUpdate(); + + const data1 = result.current[0]; + expect(data1).toEqual(['test1', 'test2']); + + unmount(); + + await new Promise(resolve => setTimeout(resolve, 300)); + + const data2 = result.current[0]; + expect(data2).toEqual(['test1', 'test2']); + }); +}); \ No newline at end of file