From 81978e22d5b04ee332ccb3aa368364d0d25e4d4b Mon Sep 17 00:00:00 2001 From: dekzter Date: Mon, 10 Mar 2025 20:54:06 -0400 Subject: [PATCH] first run at mantine --- docker/docker-compose.dev.yml | 3 +- docker/entrypoint.sh | 1 - docker/uwsgi.dev.ini | 2 +- vite/.gitignore | 24 + vite/README.md | 12 + vite/eslint.config.js | 33 + vite/index.html | 13 + vite/package-lock.json | 4665 +++++++++++++++++ vite/package.json | 52 + vite/prettier.config.js | 10 + vite/public/vite.svg | 1 + vite/src/App.css | 38 + vite/src/App.jsx | 169 + vite/src/WebSocket.jsx | 85 + vite/src/api.js | 783 +++ vite/src/assets/react.svg | 1 + vite/src/components/Alert.jsx | 26 + vite/src/components/FloatingVideo.jsx | 98 + vite/src/components/Sidebar-new.jsx | 186 + vite/src/components/Sidebar.jsx | 189 + vite/src/components/forms/Channel.jsx | 491 ++ vite/src/components/forms/ChannelGroup.jsx | 71 + vite/src/components/forms/EPG.jsx | 143 + vite/src/components/forms/LoginForm.jsx | 93 + vite/src/components/forms/M3U.jsx | 192 + vite/src/components/forms/M3UProfile.jsx | 158 + vite/src/components/forms/M3UProfiles.jsx | 107 + vite/src/components/forms/Stream.jsx | 103 + vite/src/components/forms/StreamProfile.jsx | 111 + vite/src/components/forms/SuperuserForm.jsx | 128 + vite/src/components/forms/UserAgent.jsx | 119 + vite/src/components/tables/ChannelsTable.jsx | 1005 ++++ vite/src/components/tables/EPGsTable.jsx | 168 + vite/src/components/tables/M3UsTable.jsx | 242 + .../components/tables/StreamProfilesTable.jsx | 202 + vite/src/components/tables/StreamsTable.jsx | 608 +++ .../src/components/tables/UserAgentsTable.jsx | 219 + vite/src/helpers/index.jsx | 3 + vite/src/helpers/table.jsx | 61 + vite/src/images/dispatcharr.svg | 23 + vite/src/images/ghost.svg | 66 + vite/src/images/logo.png | Bin 0 -> 44564 bytes vite/src/index.css | 31 + vite/src/logo.svg | 1 + vite/src/main.jsx | 9 + vite/src/mantineTheme.jsx | 58 + vite/src/pages/Channels.jsx | 43 + vite/src/pages/Dashboard.jsx | 27 + vite/src/pages/EPG.jsx | 27 + vite/src/pages/Guide.jsx | 532 ++ vite/src/pages/Home.jsx | 14 + vite/src/pages/Login.jsx | 8 + vite/src/pages/M3U.jsx | 34 + vite/src/pages/Settings.jsx | 146 + vite/src/pages/StreamProfiles.jsx | 8 + vite/src/store/alerts.jsx | 24 + vite/src/store/auth.jsx | 129 + vite/src/store/channels.jsx | 89 + vite/src/store/epgs.jsx | 31 + vite/src/store/playlists.jsx | 65 + vite/src/store/settings.jsx | 34 + vite/src/store/streamProfiles.jsx | 40 + vite/src/store/streams.jsx | 41 + vite/src/store/useVideoStore.jsx | 24 + vite/src/store/userAgents.jsx | 40 + vite/src/theme.jsx | 92 + vite/src/utils.js | 53 + vite/vite.config.js | 26 + 68 files changed, 12327 insertions(+), 3 deletions(-) create mode 100644 vite/.gitignore create mode 100644 vite/README.md create mode 100644 vite/eslint.config.js create mode 100644 vite/index.html create mode 100644 vite/package-lock.json create mode 100644 vite/package.json create mode 100644 vite/prettier.config.js create mode 100644 vite/public/vite.svg create mode 100644 vite/src/App.css create mode 100644 vite/src/App.jsx create mode 100644 vite/src/WebSocket.jsx create mode 100644 vite/src/api.js create mode 100644 vite/src/assets/react.svg create mode 100644 vite/src/components/Alert.jsx create mode 100644 vite/src/components/FloatingVideo.jsx create mode 100644 vite/src/components/Sidebar-new.jsx create mode 100644 vite/src/components/Sidebar.jsx create mode 100644 vite/src/components/forms/Channel.jsx create mode 100644 vite/src/components/forms/ChannelGroup.jsx create mode 100644 vite/src/components/forms/EPG.jsx create mode 100644 vite/src/components/forms/LoginForm.jsx create mode 100644 vite/src/components/forms/M3U.jsx create mode 100644 vite/src/components/forms/M3UProfile.jsx create mode 100644 vite/src/components/forms/M3UProfiles.jsx create mode 100644 vite/src/components/forms/Stream.jsx create mode 100644 vite/src/components/forms/StreamProfile.jsx create mode 100644 vite/src/components/forms/SuperuserForm.jsx create mode 100644 vite/src/components/forms/UserAgent.jsx create mode 100644 vite/src/components/tables/ChannelsTable.jsx create mode 100644 vite/src/components/tables/EPGsTable.jsx create mode 100644 vite/src/components/tables/M3UsTable.jsx create mode 100644 vite/src/components/tables/StreamProfilesTable.jsx create mode 100644 vite/src/components/tables/StreamsTable.jsx create mode 100644 vite/src/components/tables/UserAgentsTable.jsx create mode 100644 vite/src/helpers/index.jsx create mode 100644 vite/src/helpers/table.jsx create mode 100644 vite/src/images/dispatcharr.svg create mode 100644 vite/src/images/ghost.svg create mode 100644 vite/src/images/logo.png create mode 100644 vite/src/index.css create mode 100644 vite/src/logo.svg create mode 100644 vite/src/main.jsx create mode 100644 vite/src/mantineTheme.jsx create mode 100644 vite/src/pages/Channels.jsx create mode 100644 vite/src/pages/Dashboard.jsx create mode 100644 vite/src/pages/EPG.jsx create mode 100644 vite/src/pages/Guide.jsx create mode 100644 vite/src/pages/Home.jsx create mode 100644 vite/src/pages/Login.jsx create mode 100644 vite/src/pages/M3U.jsx create mode 100644 vite/src/pages/Settings.jsx create mode 100644 vite/src/pages/StreamProfiles.jsx create mode 100644 vite/src/store/alerts.jsx create mode 100644 vite/src/store/auth.jsx create mode 100644 vite/src/store/channels.jsx create mode 100644 vite/src/store/epgs.jsx create mode 100644 vite/src/store/playlists.jsx create mode 100644 vite/src/store/settings.jsx create mode 100644 vite/src/store/streamProfiles.jsx create mode 100644 vite/src/store/streams.jsx create mode 100644 vite/src/store/useVideoStore.jsx create mode 100644 vite/src/store/userAgents.jsx create mode 100644 vite/src/theme.jsx create mode 100644 vite/src/utils.js create mode 100644 vite/vite.config.js diff --git a/docker/docker-compose.dev.yml b/docker/docker-compose.dev.yml index e1cb976d..35c5087b 100644 --- a/docker/docker-compose.dev.yml +++ b/docker/docker-compose.dev.yml @@ -6,8 +6,9 @@ services: image: dispatcharr/dispatcharr container_name: dispatcharr_dev ports: - - "5656:5656" + - 5656:5656 - 9191:9191 + - 8001:8001 volumes: - ../:/app environment: diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh index 305f061f..fe81a6ac 100755 --- a/docker/entrypoint.sh +++ b/docker/entrypoint.sh @@ -46,7 +46,6 @@ if [[ ! -f /etc/profile.d/dispatcharr.sh ]]; then echo "export POSTGRES_HOST=$POSTGRES_HOST" >> /etc/profile.d/dispatcharr.sh echo "export POSTGRES_PORT=$POSTGRES_PORT" >> /etc/profile.d/dispatcharr.sh echo "export DISPATCHARR_ENV=$DISPATCHARR_ENV" >> /etc/profile.d/dispatcharr.sh - echo "export REACT_APP_ENV_MODE=$DISPATCHARR_ENV" >> /etc/profile.d/dispatcharr.sh fi chmod +x /etc/profile.d/dispatcharr.sh diff --git a/docker/uwsgi.dev.ini b/docker/uwsgi.dev.ini index 9bd0ab3f..e8761385 100644 --- a/docker/uwsgi.dev.ini +++ b/docker/uwsgi.dev.ini @@ -5,7 +5,7 @@ attach-daemon = celery -A dispatcharr worker -l info attach-daemon = redis-server attach-daemon = daphne -b 0.0.0.0 -p 8001 dispatcharr.asgi:application -attach-daemon = cd /app/frontend && npm run start +attach-daemon = cd /app/vite && npm run dev # Core settings chdir = /app diff --git a/vite/.gitignore b/vite/.gitignore new file mode 100644 index 00000000..a547bf36 --- /dev/null +++ b/vite/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/vite/README.md b/vite/README.md new file mode 100644 index 00000000..fd3b758d --- /dev/null +++ b/vite/README.md @@ -0,0 +1,12 @@ +# React + Vite + +This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. + +Currently, two official plugins are available: + +- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh +- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh + +## Expanding the ESLint configuration + +If you are developing a production application, we recommend using TypeScript and enable type-aware lint rules. Check out the [TS template](https://github.com/vitejs/vite/tree/main/packages/create-vite/template-react-ts) to integrate TypeScript and [`typescript-eslint`](https://typescript-eslint.io) in your project. diff --git a/vite/eslint.config.js b/vite/eslint.config.js new file mode 100644 index 00000000..ec2b712d --- /dev/null +++ b/vite/eslint.config.js @@ -0,0 +1,33 @@ +import js from '@eslint/js' +import globals from 'globals' +import reactHooks from 'eslint-plugin-react-hooks' +import reactRefresh from 'eslint-plugin-react-refresh' + +export default [ + { ignores: ['dist'] }, + { + files: ['**/*.{js,jsx}'], + languageOptions: { + ecmaVersion: 2020, + globals: globals.browser, + parserOptions: { + ecmaVersion: 'latest', + ecmaFeatures: { jsx: true }, + sourceType: 'module', + }, + }, + plugins: { + 'react-hooks': reactHooks, + 'react-refresh': reactRefresh, + }, + rules: { + ...js.configs.recommended.rules, + ...reactHooks.configs.recommended.rules, + 'no-unused-vars': ['error', { varsIgnorePattern: '^[A-Z_]' }], + 'react-refresh/only-export-components': [ + 'warn', + { allowConstantExport: true }, + ], + }, + }, +] diff --git a/vite/index.html b/vite/index.html new file mode 100644 index 00000000..18475376 --- /dev/null +++ b/vite/index.html @@ -0,0 +1,13 @@ + + + + + + + Dispatcharr + + +
+ + + diff --git a/vite/package-lock.json b/vite/package-lock.json new file mode 100644 index 00000000..0bb89a2e --- /dev/null +++ b/vite/package-lock.json @@ -0,0 +1,4665 @@ +{ + "name": "vite", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "vite", + "version": "0.0.0", + "dependencies": { + "@emotion/react": "^11.14.0", + "@emotion/styled": "^11.14.0", + "@mantine/core": "^7.17.1", + "@mantine/dates": "^7.17.1", + "@mantine/hooks": "^7.17.1", + "@mui/icons-material": "^6.4.7", + "@mui/material": "^6.4.7", + "@mui/x-date-pickers": "^7.27.3", + "@tabler/icons-react": "^3.31.0", + "axios": "^1.8.2", + "clsx": "^2.1.1", + "dayjs": "^1.11.13", + "formik": "^2.4.6", + "hls.js": "^1.5.20", + "lucide-react": "^0.479.0", + "mantine-react-table": "^2.0.0-beta.9", + "material-react-table": "^3.2.1", + "mpegts.js": "^1.8.0", + "prettier": "^3.5.3", + "react": "^19.0.0", + "react-dom": "^19.0.0", + "react-draggable": "^4.4.6", + "react-pro-sidebar": "^1.1.0", + "react-router-dom": "^7.3.0", + "video.js": "^8.21.0", + "yup": "^1.6.1", + "zustand": "^5.0.3" + }, + "devDependencies": { + "@eslint/js": "^9.21.0", + "@types/react": "^19.0.10", + "@types/react-dom": "^19.0.4", + "@vitejs/plugin-react-swc": "^3.8.0", + "eslint": "^9.21.0", + "eslint-plugin-react-hooks": "^5.1.0", + "eslint-plugin-react-refresh": "^0.4.19", + "globals": "^15.15.0", + "vite": "^6.2.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", + "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.25.9", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/generator": { + "version": "7.26.9", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.9.tgz", + "integrity": "sha512-kEWdzjOAUMW4hAyrzJ0ZaTOu9OmpyDIQicIh0zg0EEcEkYXZb2TjtBhnHi2ViX7PKwZqF4xwqfAm299/QMP3lg==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.26.9", + "@babel/types": "^7.26.9", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", + "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", + "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", + "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.26.9", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.9.tgz", + "integrity": "sha512-81NWa1njQblgZbQHxWHpxxCzNsa3ZwvFqpUg7P+NNUU6f3UU2jBEg4OlF/J6rl8+PQGh1q6/zWScd001YwcA5A==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.26.9" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.26.9", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.9.tgz", + "integrity": "sha512-aA63XwOkcl4xxQa3HjPMqOP6LiK0ZDv3mUPYEFXkpHbaFjtGggE1A61FjFzJnB+p7/oy2gA8E+rcBNl/zC1tMg==", + "license": "MIT", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.26.9", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.26.9.tgz", + "integrity": "sha512-qyRplbeIpNZhmzOysF/wFMuP9sctmh2cFzRAZOn1YapxBsE1i9bJIY586R/WBLfLcmcBlM8ROBiQURnnNy+zfA==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.26.2", + "@babel/parser": "^7.26.9", + "@babel/types": "^7.26.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.26.9", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.9.tgz", + "integrity": "sha512-ZYW7L+pL8ahU5fXmNbPF+iZFHCv5scFak7MZ9bwaRPLUhHh7QQEMjZUg0HevihoqCM5iSYHN61EyCoZvqC+bxg==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.26.2", + "@babel/generator": "^7.26.9", + "@babel/parser": "^7.26.9", + "@babel/template": "^7.26.9", + "@babel/types": "^7.26.9", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/types": { + "version": "7.26.9", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.9.tgz", + "integrity": "sha512-Y3IR1cRnOxOCDvMmNiym7XpXQ93iGDDPHx+Zj+NM+rg0fBaShfQLkg+hKPaZCEvg5N/LeCo4+Rj/i3FuJsIQaw==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@emotion/babel-plugin": { + "version": "11.13.5", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.13.5.tgz", + "integrity": "sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.16.7", + "@babel/runtime": "^7.18.3", + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/serialize": "^1.3.3", + "babel-plugin-macros": "^3.1.0", + "convert-source-map": "^1.5.0", + "escape-string-regexp": "^4.0.0", + "find-root": "^1.1.0", + "source-map": "^0.5.7", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/cache": { + "version": "11.14.0", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.14.0.tgz", + "integrity": "sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==", + "license": "MIT", + "dependencies": { + "@emotion/memoize": "^0.9.0", + "@emotion/sheet": "^1.4.0", + "@emotion/utils": "^1.4.2", + "@emotion/weak-memoize": "^0.4.0", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/hash": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz", + "integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==", + "license": "MIT" + }, + "node_modules/@emotion/is-prop-valid": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.3.1.tgz", + "integrity": "sha512-/ACwoqx7XQi9knQs/G0qKvv5teDMhD7bXYns9N/wM8ah8iNb8jZ2uNO0YOgiq2o2poIvVtJS2YALasQuMSQ7Kw==", + "license": "MIT", + "dependencies": { + "@emotion/memoize": "^0.9.0" + } + }, + "node_modules/@emotion/memoize": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz", + "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==", + "license": "MIT" + }, + "node_modules/@emotion/react": { + "version": "11.14.0", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.14.0.tgz", + "integrity": "sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.13.5", + "@emotion/cache": "^11.14.0", + "@emotion/serialize": "^1.3.3", + "@emotion/use-insertion-effect-with-fallbacks": "^1.2.0", + "@emotion/utils": "^1.4.2", + "@emotion/weak-memoize": "^0.4.0", + "hoist-non-react-statics": "^3.3.1" + }, + "peerDependencies": { + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/serialize": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.3.tgz", + "integrity": "sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==", + "license": "MIT", + "dependencies": { + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/unitless": "^0.10.0", + "@emotion/utils": "^1.4.2", + "csstype": "^3.0.2" + } + }, + "node_modules/@emotion/sheet": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz", + "integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==", + "license": "MIT" + }, + "node_modules/@emotion/styled": { + "version": "11.14.0", + "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.14.0.tgz", + "integrity": "sha512-XxfOnXFffatap2IyCeJyNov3kiDQWoR08gPUQxvbL7fxKryGBKUZUkG6Hz48DZwVrJSVh9sJboyV1Ds4OW6SgA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.13.5", + "@emotion/is-prop-valid": "^1.3.0", + "@emotion/serialize": "^1.3.3", + "@emotion/use-insertion-effect-with-fallbacks": "^1.2.0", + "@emotion/utils": "^1.4.2" + }, + "peerDependencies": { + "@emotion/react": "^11.0.0-rc.0", + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/unitless": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.10.0.tgz", + "integrity": "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==", + "license": "MIT" + }, + "node_modules/@emotion/use-insertion-effect-with-fallbacks": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.2.0.tgz", + "integrity": "sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==", + "license": "MIT", + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@emotion/utils": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.2.tgz", + "integrity": "sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==", + "license": "MIT" + }, + "node_modules/@emotion/weak-memoize": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz", + "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==", + "license": "MIT" + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.1.tgz", + "integrity": "sha512-kfYGy8IdzTGy+z0vFGvExZtxkFlA4zAxgKEahG9KE1ScBjpQnFsNOX8KTU5ojNru5ed5CVoJYXFtoxaq5nFbjQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.1.tgz", + "integrity": "sha512-dp+MshLYux6j/JjdqVLnMglQlFu+MuVeNrmT5nk6q07wNhCdSnB7QZj+7G8VMUGh1q+vj2Bq8kRsuyA00I/k+Q==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.1.tgz", + "integrity": "sha512-50tM0zCJW5kGqgG7fQ7IHvQOcAn9TKiVRuQ/lN0xR+T2lzEFvAi1ZcS8DiksFcEpf1t/GYOeOfCAgDHFpkiSmA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.1.tgz", + "integrity": "sha512-GCj6WfUtNldqUzYkN/ITtlhwQqGWu9S45vUXs7EIYf+7rCiiqH9bCloatO9VhxsL0Pji+PF4Lz2XXCES+Q8hDw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.1.tgz", + "integrity": "sha512-5hEZKPf+nQjYoSr/elb62U19/l1mZDdqidGfmFutVUjjUZrOazAtwK+Kr+3y0C/oeJfLlxo9fXb1w7L+P7E4FQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.1.tgz", + "integrity": "sha512-hxVnwL2Dqs3fM1IWq8Iezh0cX7ZGdVhbTfnOy5uURtao5OIVCEyj9xIzemDi7sRvKsuSdtCAhMKarxqtlyVyfA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.1.tgz", + "integrity": "sha512-1MrCZs0fZa2g8E+FUo2ipw6jw5qqQiH+tERoS5fAfKnRx6NXH31tXBKI3VpmLijLH6yriMZsxJtaXUyFt/8Y4A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.1.tgz", + "integrity": "sha512-0IZWLiTyz7nm0xuIs0q1Y3QWJC52R8aSXxe40VUxm6BB1RNmkODtW6LHvWRrGiICulcX7ZvyH6h5fqdLu4gkww==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.1.tgz", + "integrity": "sha512-NdKOhS4u7JhDKw9G3cY6sWqFcnLITn6SqivVArbzIaf3cemShqfLGHYMx8Xlm/lBit3/5d7kXvriTUGa5YViuQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.1.tgz", + "integrity": "sha512-jaN3dHi0/DDPelk0nLcXRm1q7DNJpjXy7yWaWvbfkPvI+7XNSc/lDOnCLN7gzsyzgu6qSAmgSvP9oXAhP973uQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.1.tgz", + "integrity": "sha512-OJykPaF4v8JidKNGz8c/q1lBO44sQNUQtq1KktJXdBLn1hPod5rE/Hko5ugKKZd+D2+o1a9MFGUEIUwO2YfgkQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.1.tgz", + "integrity": "sha512-nGfornQj4dzcq5Vp835oM/o21UMlXzn79KobKlcs3Wz9smwiifknLy4xDCLUU0BWp7b/houtdrgUz7nOGnfIYg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.1.tgz", + "integrity": "sha512-1osBbPEFYwIE5IVB/0g2X6i1qInZa1aIoj1TdL4AaAb55xIIgbg8Doq6a5BzYWgr+tEcDzYH67XVnTmUzL+nXg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.1.tgz", + "integrity": "sha512-/6VBJOwUf3TdTvJZ82qF3tbLuWsscd7/1w+D9LH0W/SqUgM5/JJD0lrJ1fVIfZsqB6RFmLCe0Xz3fmZc3WtyVg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.1.tgz", + "integrity": "sha512-nSut/Mx5gnilhcq2yIMLMe3Wl4FK5wx/o0QuuCLMtmJn+WeWYoEGDN1ipcN72g1WHsnIbxGXd4i/MF0gTcuAjQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.1.tgz", + "integrity": "sha512-cEECeLlJNfT8kZHqLarDBQso9a27o2Zd2AQ8USAEoGtejOrCYHNtKP8XQhMDJMtthdF4GBmjR2au3x1udADQQQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.1.tgz", + "integrity": "sha512-xbfUhu/gnvSEg+EGovRc+kjBAkrvtk38RlerAzQxvMzlB4fXpCFCeUAYzJvrnhFtdeyVCDANSjJvOvGYoeKzFA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.1.tgz", + "integrity": "sha512-O96poM2XGhLtpTh+s4+nP7YCCAfb4tJNRVZHfIE7dgmax+yMP2WgMd2OecBuaATHKTHsLWHQeuaxMRnCsH8+5g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.1.tgz", + "integrity": "sha512-X53z6uXip6KFXBQ+Krbx25XHV/NCbzryM6ehOAeAil7X7oa4XIq+394PWGnwaSQ2WRA0KI6PUO6hTO5zeF5ijA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.1.tgz", + "integrity": "sha512-Na9T3szbXezdzM/Kfs3GcRQNjHzM6GzFBeU1/6IV/npKP5ORtp9zbQjvkDJ47s6BCgaAZnnnu/cY1x342+MvZg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.1.tgz", + "integrity": "sha512-T3H78X2h1tszfRSf+txbt5aOp/e7TAz3ptVKu9Oyir3IAOFPGV6O9c2naym5TOriy1l0nNf6a4X5UXRZSGX/dw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.1.tgz", + "integrity": "sha512-2H3RUvcmULO7dIE5EWJH8eubZAI4xw54H1ilJnRNZdeo8dTADEZ21w6J22XBkXqGJbe0+wnNJtw3UXRoLJnFEg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.1.tgz", + "integrity": "sha512-GE7XvrdOzrb+yVKB9KsRMq+7a2U/K5Cf/8grVFRAGJmfADr/e/ODQ134RK2/eeHqYV5eQRFxb1hY7Nr15fv1NQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.1.tgz", + "integrity": "sha512-uOxSJCIcavSiT6UnBhBzE8wy3n0hOkJsBOzy7HDAuTDE++1DJMRRVCPGisULScHL+a/ZwdXPpXD3IyFKjA7K8A==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.1.tgz", + "integrity": "sha512-Y1EQdcfwMSeQN/ujR5VayLOJ1BHaK+ssyk0AEzPjC+t1lITgsnccPqFjb6V+LsTp/9Iov4ysfjxLaGJ9RPtkVg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz", + "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.2.tgz", + "integrity": "sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.6", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.1.0.tgz", + "integrity": "sha512-kLrdPDJE1ckPo94kmPPf9Hfd0DU0Jw6oKYrhe+pwSC0iTUInmTa+w6fw8sGgcfkFJGNdWOUeOaDM4quW4a7OkA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.12.0.tgz", + "integrity": "sha512-cmrR6pytBuSMTaBweKoGMwu3EiHiEC+DoyupPmlZ0HxBJBtIxwe+j/E4XPIKNx+Q74c8lXKPwYawBf5glsTkHg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.0.tgz", + "integrity": "sha512-yaVPAiNAalnCZedKLdR21GOGILMLKPyqSLWaAjQFvYA2i/ciDi8ArYVr69Anohb6cH2Ukhqti4aFnYyPm8wdwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "9.22.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.22.0.tgz", + "integrity": "sha512-vLFajx9o8d1/oL2ZkpMYbkLv8nDB6yaIwFNt7nI4+I80U/z03SxmfOMsLbvWr3p7C+Wnoh//aOu2pQW8cS0HCQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", + "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.7.tgz", + "integrity": "sha512-JubJ5B2pJ4k4yGxaNLdbjrnk9d/iDz6/q8wOilpIowd6PJPgaxCuHBnBszq7Ce2TyMrywm5r4PnKm6V3iiZF+g==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.12.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@floating-ui/core": { + "version": "1.6.9", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.9.tgz", + "integrity": "sha512-uMXCuQ3BItDUbAMhIXw7UPXRfAlOAvZzdK9BWpE60MCn+Svt3aLn9jsPTi/WNGlRUu2uI0v5S7JiIUsbsvh3fw==", + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.9" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.6.13", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.13.tgz", + "integrity": "sha512-umqzocjDgNRGTuO7Q8CU32dkHkECqI8ZdMZ5Swb6QAM0t5rnlrN3lGo1hdpscRd3WS8T6DKYK4ephgIH9iRh3w==", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.6.0", + "@floating-ui/utils": "^0.2.9" + } + }, + "node_modules/@floating-ui/react": { + "version": "0.26.28", + "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.26.28.tgz", + "integrity": "sha512-yORQuuAtVpiRjpMhdc0wJj06b9JFjrYF4qp96j++v2NBpbi6SEGF7donUJ3TMieerQ6qVkAv1tgr7L4r5roTqw==", + "license": "MIT", + "dependencies": { + "@floating-ui/react-dom": "^2.1.2", + "@floating-ui/utils": "^0.2.8", + "tabbable": "^6.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.2.tgz", + "integrity": "sha512-06okr5cgPzMNBy+Ycse2A6udMi4bqwW/zgBF/rwjcNqWkyr82Mcg8b0vjX8OJpZFy/FKjJmw6wV7t44kK6kW7A==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.9.tgz", + "integrity": "sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==", + "license": "MIT" + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.6", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", + "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.3.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.2.tgz", + "integrity": "sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", + "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", + "license": "MIT", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@mantine/core": { + "version": "7.17.1", + "resolved": "https://registry.npmjs.org/@mantine/core/-/core-7.17.1.tgz", + "integrity": "sha512-V8O3Ftq4la4I4wNDkTfH4Slkt/pCEU32pTE/DkO46zua0VFxfOAJeLjaol0s11//T+bXx82DtjMsd9APWPuFhA==", + "license": "MIT", + "dependencies": { + "@floating-ui/react": "^0.26.28", + "clsx": "^2.1.1", + "react-number-format": "^5.4.3", + "react-remove-scroll": "^2.6.2", + "react-textarea-autosize": "8.5.6", + "type-fest": "^4.27.0" + }, + "peerDependencies": { + "@mantine/hooks": "7.17.1", + "react": "^18.x || ^19.x", + "react-dom": "^18.x || ^19.x" + } + }, + "node_modules/@mantine/core/node_modules/type-fest": { + "version": "4.37.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.37.0.tgz", + "integrity": "sha512-S/5/0kFftkq27FPNye0XM1e2NsnoD/3FS+pBmbjmmtLT6I+i344KoOf7pvXreaFsDamWeaJX55nczA1m5PsBDg==", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@mantine/dates": { + "version": "7.17.1", + "resolved": "https://registry.npmjs.org/@mantine/dates/-/dates-7.17.1.tgz", + "integrity": "sha512-L9MlIDb528RpznUeeW71xS4q3lYGolElz/f7xGRXEu9gHLaNJufbxroTw2N8RC6p/+RN1ZrSXEsjlr2euiofAw==", + "license": "MIT", + "dependencies": { + "clsx": "^2.1.1" + }, + "peerDependencies": { + "@mantine/core": "7.17.1", + "@mantine/hooks": "7.17.1", + "dayjs": ">=1.0.0", + "react": "^18.x || ^19.x", + "react-dom": "^18.x || ^19.x" + } + }, + "node_modules/@mantine/hooks": { + "version": "7.17.1", + "resolved": "https://registry.npmjs.org/@mantine/hooks/-/hooks-7.17.1.tgz", + "integrity": "sha512-mkHLrXMPd5xdI5WD7UOLwNEpdh/i6A7HaRDTXvjDE2/S0N8VmAE+BlvdyvWRMi7ODp2zVqJdP8cF1tgUn+Z0fA==", + "license": "MIT", + "peerDependencies": { + "react": "^18.x || ^19.x" + } + }, + "node_modules/@mui/core-downloads-tracker": { + "version": "6.4.7", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-6.4.7.tgz", + "integrity": "sha512-XjJrKFNt9zAKvcnoIIBquXyFyhfrHYuttqMsoDS7lM7VwufYG4fAPw4kINjBFg++fqXM2BNAuWR9J7XVIuKIKg==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + } + }, + "node_modules/@mui/icons-material": { + "version": "6.4.7", + "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-6.4.7.tgz", + "integrity": "sha512-Rk8cs9ufQoLBw582Rdqq7fnSXXZTqhYRbpe1Y5SAz9lJKZP3CIdrj0PfG8HJLGw1hrsHFN/rkkm70IDzhJsG1g==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.26.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@mui/material": "^6.4.7", + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/material": { + "version": "6.4.7", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-6.4.7.tgz", + "integrity": "sha512-K65StXUeGAtFJ4ikvHKtmDCO5Ab7g0FZUu2J5VpoKD+O6Y3CjLYzRi+TMlI3kaL4CL158+FccMoOd/eaddmeRQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.26.0", + "@mui/core-downloads-tracker": "^6.4.7", + "@mui/system": "^6.4.7", + "@mui/types": "^7.2.21", + "@mui/utils": "^6.4.6", + "@popperjs/core": "^2.11.8", + "@types/react-transition-group": "^4.4.12", + "clsx": "^2.1.1", + "csstype": "^3.1.3", + "prop-types": "^15.8.1", + "react-is": "^19.0.0", + "react-transition-group": "^4.4.5" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@mui/material-pigment-css": "^6.4.7", + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@mui/material-pigment-css": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/private-theming": { + "version": "6.4.6", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-6.4.6.tgz", + "integrity": "sha512-T5FxdPzCELuOrhpA2g4Pi6241HAxRwZudzAuL9vBvniuB5YU82HCmrARw32AuCiyTfWzbrYGGpZ4zyeqqp9RvQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.26.0", + "@mui/utils": "^6.4.6", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/styled-engine": { + "version": "6.4.6", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-6.4.6.tgz", + "integrity": "sha512-vSWYc9ZLX46be5gP+FCzWVn5rvDr4cXC5JBZwSIkYk9xbC7GeV+0kCvB8Q6XLFQJy+a62bbqtmdwS4Ghi9NBlQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.26.0", + "@emotion/cache": "^11.13.5", + "@emotion/serialize": "^1.3.3", + "@emotion/sheet": "^1.4.0", + "csstype": "^3.1.3", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.4.1", + "@emotion/styled": "^11.3.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + } + } + }, + "node_modules/@mui/system": { + "version": "6.4.7", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-6.4.7.tgz", + "integrity": "sha512-7wwc4++Ak6tGIooEVA9AY7FhH2p9fvBMORT4vNLMAysH3Yus/9B9RYMbrn3ANgsOyvT3Z7nE+SP8/+3FimQmcg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.26.0", + "@mui/private-theming": "^6.4.6", + "@mui/styled-engine": "^6.4.6", + "@mui/types": "^7.2.21", + "@mui/utils": "^6.4.6", + "clsx": "^2.1.1", + "csstype": "^3.1.3", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/types": { + "version": "7.2.21", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.21.tgz", + "integrity": "sha512-6HstngiUxNqLU+/DPqlUJDIPbzUBxIVHb1MmXP0eTWDIROiCR2viugXpEif0PPe2mLqqakPzzRClWAnK+8UJww==", + "license": "MIT", + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/utils": { + "version": "6.4.6", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-6.4.6.tgz", + "integrity": "sha512-43nZeE1pJF2anGafNydUcYFPtHwAqiBiauRtaMvurdrZI3YrUjHkAu43RBsxef7OFtJMXGiHFvq43kb7lig0sA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.26.0", + "@mui/types": "^7.2.21", + "@types/prop-types": "^15.7.14", + "clsx": "^2.1.1", + "prop-types": "^15.8.1", + "react-is": "^19.0.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/x-date-pickers": { + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@mui/x-date-pickers/-/x-date-pickers-7.27.3.tgz", + "integrity": "sha512-igfKTPC4ZVCmS5j/NXcXBtj/hHseQHzRpCpIB1PMnJGhMdRYXnz8qZz5XhlNBKlzJVXkGu6Uil+obZpCLNj1xg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.25.7", + "@mui/utils": "^5.16.6 || ^6.0.0", + "@mui/x-internals": "7.26.0", + "@types/react-transition-group": "^4.4.11", + "clsx": "^2.1.1", + "prop-types": "^15.8.1", + "react-transition-group": "^4.4.5" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.9.0", + "@emotion/styled": "^11.8.1", + "@mui/material": "^5.15.14 || ^6.0.0", + "@mui/system": "^5.15.14 || ^6.0.0", + "date-fns": "^2.25.0 || ^3.2.0 || ^4.0.0", + "date-fns-jalali": "^2.13.0-0 || ^3.2.0-0 || ^4.0.0-0", + "dayjs": "^1.10.7", + "luxon": "^3.0.2", + "moment": "^2.29.4", + "moment-hijri": "^2.1.2 || ^3.0.0", + "moment-jalaali": "^0.7.4 || ^0.8.0 || ^0.9.0 || ^0.10.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "date-fns": { + "optional": true + }, + "date-fns-jalali": { + "optional": true + }, + "dayjs": { + "optional": true + }, + "luxon": { + "optional": true + }, + "moment": { + "optional": true + }, + "moment-hijri": { + "optional": true + }, + "moment-jalaali": { + "optional": true + } + } + }, + "node_modules/@mui/x-internals": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@mui/x-internals/-/x-internals-7.26.0.tgz", + "integrity": "sha512-VxTCYQcZ02d3190pdvys2TDg9pgbvewAVakEopiOgReKAUhLdRlgGJHcOA/eAuGLyK1YIo26A6Ow6ZKlSRLwMg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.25.7", + "@mui/utils": "^5.16.6 || ^6.0.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.35.0.tgz", + "integrity": "sha512-uYQ2WfPaqz5QtVgMxfN6NpLD+no0MYHDBywl7itPYd3K5TjjSghNKmX8ic9S8NU8w81NVhJv/XojcHptRly7qQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.35.0.tgz", + "integrity": "sha512-FtKddj9XZudurLhdJnBl9fl6BwCJ3ky8riCXjEw3/UIbjmIY58ppWwPEvU3fNu+W7FUsAsB1CdH+7EQE6CXAPA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.35.0.tgz", + "integrity": "sha512-Uk+GjOJR6CY844/q6r5DR/6lkPFOw0hjfOIzVx22THJXMxktXG6CbejseJFznU8vHcEBLpiXKY3/6xc+cBm65Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.35.0.tgz", + "integrity": "sha512-3IrHjfAS6Vkp+5bISNQnPogRAW5GAV1n+bNCrDwXmfMHbPl5EhTmWtfmwlJxFRUCBZ+tZ/OxDyU08aF6NI/N5Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.35.0.tgz", + "integrity": "sha512-sxjoD/6F9cDLSELuLNnY0fOrM9WA0KrM0vWm57XhrIMf5FGiN8D0l7fn+bpUeBSU7dCgPV2oX4zHAsAXyHFGcQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.35.0.tgz", + "integrity": "sha512-2mpHCeRuD1u/2kruUiHSsnjWtHjqVbzhBkNVQ1aVD63CcexKVcQGwJ2g5VphOd84GvxfSvnnlEyBtQCE5hxVVw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.35.0.tgz", + "integrity": "sha512-mrA0v3QMy6ZSvEuLs0dMxcO2LnaCONs1Z73GUDBHWbY8tFFocM6yl7YyMu7rz4zS81NDSqhrUuolyZXGi8TEqg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.35.0.tgz", + "integrity": "sha512-DnYhhzcvTAKNexIql8pFajr0PiDGrIsBYPRvCKlA5ixSS3uwo/CWNZxB09jhIapEIg945KOzcYEAGGSmTSpk7A==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.35.0.tgz", + "integrity": "sha512-uagpnH2M2g2b5iLsCTZ35CL1FgyuzzJQ8L9VtlJ+FckBXroTwNOaD0z0/UF+k5K3aNQjbm8LIVpxykUOQt1m/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.35.0.tgz", + "integrity": "sha512-XQxVOCd6VJeHQA/7YcqyV0/88N6ysSVzRjJ9I9UA/xXpEsjvAgDTgH3wQYz5bmr7SPtVK2TsP2fQ2N9L4ukoUg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.35.0.tgz", + "integrity": "sha512-5pMT5PzfgwcXEwOaSrqVsz/LvjDZt+vQ8RT/70yhPU06PTuq8WaHhfT1LW+cdD7mW6i/J5/XIkX/1tCAkh1W6g==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.35.0.tgz", + "integrity": "sha512-c+zkcvbhbXF98f4CtEIP1EBA/lCic5xB0lToneZYvMeKu5Kamq3O8gqrxiYYLzlZH6E3Aq+TSW86E4ay8iD8EA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.35.0.tgz", + "integrity": "sha512-s91fuAHdOwH/Tad2tzTtPX7UZyytHIRR6V4+2IGlV0Cej5rkG0R61SX4l4y9sh0JBibMiploZx3oHKPnQBKe4g==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.35.0.tgz", + "integrity": "sha512-hQRkPQPLYJZYGP+Hj4fR9dDBMIM7zrzJDWFEMPdTnTy95Ljnv0/4w/ixFw3pTBMEuuEuoqtBINYND4M7ujcuQw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.35.0.tgz", + "integrity": "sha512-Pim1T8rXOri+0HmV4CdKSGrqcBWX0d1HoPnQ0uw0bdp1aP5SdQVNBy8LjYncvnLgu3fnnCt17xjWGd4cqh8/hA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.35.0.tgz", + "integrity": "sha512-QysqXzYiDvQWfUiTm8XmJNO2zm9yC9P/2Gkrwg2dH9cxotQzunBHYr6jk4SujCTqnfGxduOmQcI7c2ryuW8XVg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.35.0.tgz", + "integrity": "sha512-OUOlGqPkVJCdJETKOCEf1mw848ZyJ5w50/rZ/3IBQVdLfR5jk/6Sr5m3iO2tdPgwo0x7VcncYuOvMhBWZq8ayg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.35.0.tgz", + "integrity": "sha512-2/lsgejMrtwQe44glq7AFFHLfJBPafpsTa6JvP2NGef/ifOa4KBoglVf7AKN7EV9o32evBPRqfg96fEHzWo5kw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.35.0.tgz", + "integrity": "sha512-PIQeY5XDkrOysbQblSW7v3l1MDZzkTEzAfTPkj5VAu3FW8fS4ynyLg2sINp0fp3SjZ8xkRYpLqoKcYqAkhU1dw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@swc/core": { + "version": "1.11.8", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.11.8.tgz", + "integrity": "sha512-UAL+EULxrc0J73flwYHfu29mO8CONpDJiQv1QPDXsyCvDUcEhqAqUROVTgC+wtJCFFqMQdyr4stAA5/s0KSOmA==", + "dev": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@swc/counter": "^0.1.3", + "@swc/types": "^0.1.19" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/swc" + }, + "optionalDependencies": { + "@swc/core-darwin-arm64": "1.11.8", + "@swc/core-darwin-x64": "1.11.8", + "@swc/core-linux-arm-gnueabihf": "1.11.8", + "@swc/core-linux-arm64-gnu": "1.11.8", + "@swc/core-linux-arm64-musl": "1.11.8", + "@swc/core-linux-x64-gnu": "1.11.8", + "@swc/core-linux-x64-musl": "1.11.8", + "@swc/core-win32-arm64-msvc": "1.11.8", + "@swc/core-win32-ia32-msvc": "1.11.8", + "@swc/core-win32-x64-msvc": "1.11.8" + }, + "peerDependencies": { + "@swc/helpers": "*" + }, + "peerDependenciesMeta": { + "@swc/helpers": { + "optional": true + } + } + }, + "node_modules/@swc/core-darwin-arm64": { + "version": "1.11.8", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.11.8.tgz", + "integrity": "sha512-rrSsunyJWpHN+5V1zumndwSSifmIeFQBK9i2RMQQp15PgbgUNxHK5qoET1n20pcUrmZeT6jmJaEWlQchkV//Og==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-darwin-x64": { + "version": "1.11.8", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.11.8.tgz", + "integrity": "sha512-44goLqQuuo0HgWnG8qC+ZFw/qnjCVVeqffhzFr9WAXXotogVaxM8ze6egE58VWrfEc8me8yCcxOYL9RbtjhS/Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm-gnueabihf": { + "version": "1.11.8", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.11.8.tgz", + "integrity": "sha512-Mzo8umKlhTWwF1v8SLuTM1z2A+P43UVhf4R8RZDhzIRBuB2NkeyE+c0gexIOJBuGSIATryuAF4O4luDu727D1w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-gnu": { + "version": "1.11.8", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.11.8.tgz", + "integrity": "sha512-EyhO6U+QdoGYC1MeHOR0pyaaSaKYyNuT4FQNZ1eZIbnuueXpuICC7iNmLIOfr3LE5bVWcZ7NKGVPlM2StJEcgA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-musl": { + "version": "1.11.8", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.11.8.tgz", + "integrity": "sha512-QU6wOkZnS6/QuBN1MHD6G2BgFxB0AclvTVGbqYkRA7MsVkcC29PffESqzTXnypzB252/XkhQjoB2JIt9rPYf6A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-gnu": { + "version": "1.11.8", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.11.8.tgz", + "integrity": "sha512-r72onUEIU1iJi9EUws3R28pztQ/eM3EshNpsPRBfuLwKy+qn3et55vXOyDhIjGCUph5Eg2Yn8H3h6MTxDdLd+w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-musl": { + "version": "1.11.8", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.11.8.tgz", + "integrity": "sha512-294k8cLpO103++f4ZUEDr3vnBeUfPitW6G0a3qeVZuoXFhFgaW7ANZIWknUc14WiLOMfMecphJAEiy9C8OeYSw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-arm64-msvc": { + "version": "1.11.8", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.11.8.tgz", + "integrity": "sha512-EbjOzQ+B85rumHyeesBYxZ+hq3ZQn+YAAT1ZNE9xW1/8SuLoBmHy/K9YniRGVDq/2NRmp5kI5+5h5TX0asIS9A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-ia32-msvc": { + "version": "1.11.8", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.11.8.tgz", + "integrity": "sha512-Z+FF5kgLHfQWIZ1KPdeInToXLzbY0sMAashjd/igKeP1Lz0qKXVAK+rpn6ASJi85Fn8wTftCGCyQUkRVn0bTDg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-x64-msvc": { + "version": "1.11.8", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.11.8.tgz", + "integrity": "sha512-j6B6N0hChCeAISS6xp/hh6zR5CSCr037BAjCxNLsT8TGe5D+gYZ57heswUWXRH8eMKiRDGiLCYpPB2pkTqxCSw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/counter": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", + "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/@swc/types": { + "version": "0.1.19", + "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.19.tgz", + "integrity": "sha512-WkAZaAfj44kh/UFdAQcrMP1I0nwRqpt27u+08LMBYMqmQfwwMofYoMh/48NGkMMRfC4ynpfwRbJuu8ErfNloeA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@swc/counter": "^0.1.3" + } + }, + "node_modules/@tabler/icons": { + "version": "3.31.0", + "resolved": "https://registry.npmjs.org/@tabler/icons/-/icons-3.31.0.tgz", + "integrity": "sha512-dblAdeKY3+GA1U+Q9eziZ0ooVlZMHsE8dqP0RkwvRtEsAULoKOYaCUOcJ4oW1DjWegdxk++UAt2SlQVnmeHv+g==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/codecalm" + } + }, + "node_modules/@tabler/icons-react": { + "version": "3.31.0", + "resolved": "https://registry.npmjs.org/@tabler/icons-react/-/icons-react-3.31.0.tgz", + "integrity": "sha512-2rrCM5y/VnaVKnORpDdAua9SEGuJKVqPtWxeQ/vUVsgaUx30LDgBZph7/lterXxDY1IKR6NO//HDhWiifXTi3w==", + "license": "MIT", + "dependencies": { + "@tabler/icons": "3.31.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/codecalm" + }, + "peerDependencies": { + "react": ">= 16" + } + }, + "node_modules/@tanstack/match-sorter-utils": { + "version": "8.19.4", + "resolved": "https://registry.npmjs.org/@tanstack/match-sorter-utils/-/match-sorter-utils-8.19.4.tgz", + "integrity": "sha512-Wo1iKt2b9OT7d+YGhvEPD3DXvPv2etTusIMhMUoG7fbhmxcXCtIjJDEygy91Y2JFlwGyjqiBPRozme7UD8hoqg==", + "license": "MIT", + "dependencies": { + "remove-accents": "0.5.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/react-table": { + "version": "8.20.6", + "resolved": "https://registry.npmjs.org/@tanstack/react-table/-/react-table-8.20.6.tgz", + "integrity": "sha512-w0jluT718MrOKthRcr2xsjqzx+oEM7B7s/XXyfs19ll++hlId3fjTm+B2zrR3ijpANpkzBAr15j1XGVOMxpggQ==", + "license": "MIT", + "dependencies": { + "@tanstack/table-core": "8.20.5" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, + "node_modules/@tanstack/react-virtual": { + "version": "3.11.2", + "resolved": "https://registry.npmjs.org/@tanstack/react-virtual/-/react-virtual-3.11.2.tgz", + "integrity": "sha512-OuFzMXPF4+xZgx8UzJha0AieuMihhhaWG0tCqpp6tDzlFwOmNBPYMuLOtMJ1Tr4pXLHmgjcWhG6RlknY2oNTdQ==", + "license": "MIT", + "dependencies": { + "@tanstack/virtual-core": "3.11.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/@tanstack/table-core": { + "version": "8.20.5", + "resolved": "https://registry.npmjs.org/@tanstack/table-core/-/table-core-8.20.5.tgz", + "integrity": "sha512-P9dF7XbibHph2PFRz8gfBKEXEY/HJPOhym8CHmjF8y3q5mWpKx9xtZapXQUWCgkqvsK0R46Azuz+VaxD4Xl+Tg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/virtual-core": { + "version": "3.11.2", + "resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.11.2.tgz", + "integrity": "sha512-vTtpNt7mKCiZ1pwU9hfKPhpdVO2sVzFQsxoVBGtOSHxlrRRzYr8iQ2TlwbAcRYCcEiZ9ECAM8kBzH0v2+VzfKw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@types/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==", + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/hoist-non-react-statics": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.6.tgz", + "integrity": "sha512-lPByRJUer/iN/xa4qpyL0qmL11DqNW81iU/IG1S3uvRUq4oKagz8VCxZjiWkumgt66YT3vOdDgZ0o32sGKtCEw==", + "license": "MIT", + "dependencies": { + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/parse-json": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", + "license": "MIT" + }, + "node_modules/@types/prop-types": { + "version": "15.7.14", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.14.tgz", + "integrity": "sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==", + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "19.0.10", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.0.10.tgz", + "integrity": "sha512-JuRQ9KXLEjaUNjTWpzuR231Z2WpIwczOkBEIvbHNCzQefFIT0L8IqE6NV6ULLyC1SI/i234JnDoMkfg+RjQj2g==", + "license": "MIT", + "dependencies": { + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.0.4", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.0.4.tgz", + "integrity": "sha512-4fSQ8vWFkg+TGhePfUzVmat3eC14TXYSsiiDSLI0dVLsrm9gZFABjPy/Qu6TKgl1tq1Bu1yDsuQgY3A3DOjCcg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.0.0" + } + }, + "node_modules/@types/react-transition-group": { + "version": "4.4.12", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.12.tgz", + "integrity": "sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*" + } + }, + "node_modules/@videojs/http-streaming": { + "version": "3.17.0", + "resolved": "https://registry.npmjs.org/@videojs/http-streaming/-/http-streaming-3.17.0.tgz", + "integrity": "sha512-Ch1P3tvvIEezeZXyK11UfWgp4cWKX4vIhZ30baN/lRinqdbakZ5hiAI3pGjRy3d+q/Epyc8Csz5xMdKNNGYpcw==", + "license": "Apache-2.0", + "dependencies": { + "@babel/runtime": "^7.12.5", + "@videojs/vhs-utils": "^4.1.1", + "aes-decrypter": "^4.0.2", + "global": "^4.4.0", + "m3u8-parser": "^7.2.0", + "mpd-parser": "^1.3.1", + "mux.js": "7.1.0", + "video.js": "^7 || ^8" + }, + "engines": { + "node": ">=8", + "npm": ">=5" + }, + "peerDependencies": { + "video.js": "^8.19.0" + } + }, + "node_modules/@videojs/vhs-utils": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@videojs/vhs-utils/-/vhs-utils-4.1.1.tgz", + "integrity": "sha512-5iLX6sR2ownbv4Mtejw6Ax+naosGvoT9kY+gcuHzANyUZZ+4NpeNdKMUhb6ag0acYej1Y7cmr/F2+4PrggMiVA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.5", + "global": "^4.4.0" + }, + "engines": { + "node": ">=8", + "npm": ">=5" + } + }, + "node_modules/@videojs/xhr": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/@videojs/xhr/-/xhr-2.7.0.tgz", + "integrity": "sha512-giab+EVRanChIupZK7gXjHy90y3nncA2phIOyG3Ne5fvpiMJzvqYwiTOnEVW2S4CoYcuKJkomat7bMXA/UoUZQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.5.5", + "global": "~4.4.0", + "is-function": "^1.0.1" + } + }, + "node_modules/@vitejs/plugin-react-swc": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react-swc/-/plugin-react-swc-3.8.0.tgz", + "integrity": "sha512-T4sHPvS+DIqDP51ifPqa9XIRAz/kIvIi8oXcnOZZgHmMotgmmdxe/DD5tMFlt5nuIRzT0/QuiwmKlH0503Aapw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@swc/core": "^1.10.15" + }, + "peerDependencies": { + "vite": "^4 || ^5 || ^6" + } + }, + "node_modules/@xmldom/xmldom": { + "version": "0.8.10", + "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.10.tgz", + "integrity": "sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/acorn": { + "version": "8.14.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", + "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/aes-decrypter": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/aes-decrypter/-/aes-decrypter-4.0.2.tgz", + "integrity": "sha512-lc+/9s6iJvuaRe5qDlMTpCFjnwpkeOXp8qP3oiZ5jsj1MRg+SBVUmmICrhxHvc8OELSmc+fEyyxAuppY6hrWzw==", + "license": "Apache-2.0", + "dependencies": { + "@babel/runtime": "^7.12.5", + "@videojs/vhs-utils": "^4.1.1", + "global": "^4.4.0", + "pkcs7": "^1.0.4" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/axios": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.8.2.tgz", + "integrity": "sha512-ls4GYBm5aig9vWx8AWDSGLpnpDQRtWAfrjU+EuytuODrFBkqesN2RkOQCBzrA1RQNHw1SmRMSDDDSwzNAYQ6Rg==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/babel-plugin-macros": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", + "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.5", + "cosmiconfig": "^7.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/classnames": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", + "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==", + "license": "MIT" + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "license": "MIT" + }, + "node_modules/cookie": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz", + "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "license": "MIT", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cosmiconfig/node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "license": "MIT" + }, + "node_modules/dayjs": { + "version": "1.11.13", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz", + "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==", + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/deepmerge": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-2.2.1.tgz", + "integrity": "sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/detect-node-es": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", + "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==", + "license": "MIT" + }, + "node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, + "node_modules/dom-walk": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz", + "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==" + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", + "license": "MIT" + }, + "node_modules/esbuild": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.1.tgz", + "integrity": "sha512-BGO5LtrGC7vxnqucAe/rmvKdJllfGaYWdyABvyMoXQlfYMb2bbRuReWR5tEGE//4LcNJj9XrkovTqNYRFZHAMQ==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.1", + "@esbuild/android-arm": "0.25.1", + "@esbuild/android-arm64": "0.25.1", + "@esbuild/android-x64": "0.25.1", + "@esbuild/darwin-arm64": "0.25.1", + "@esbuild/darwin-x64": "0.25.1", + "@esbuild/freebsd-arm64": "0.25.1", + "@esbuild/freebsd-x64": "0.25.1", + "@esbuild/linux-arm": "0.25.1", + "@esbuild/linux-arm64": "0.25.1", + "@esbuild/linux-ia32": "0.25.1", + "@esbuild/linux-loong64": "0.25.1", + "@esbuild/linux-mips64el": "0.25.1", + "@esbuild/linux-ppc64": "0.25.1", + "@esbuild/linux-riscv64": "0.25.1", + "@esbuild/linux-s390x": "0.25.1", + "@esbuild/linux-x64": "0.25.1", + "@esbuild/netbsd-arm64": "0.25.1", + "@esbuild/netbsd-x64": "0.25.1", + "@esbuild/openbsd-arm64": "0.25.1", + "@esbuild/openbsd-x64": "0.25.1", + "@esbuild/sunos-x64": "0.25.1", + "@esbuild/win32-arm64": "0.25.1", + "@esbuild/win32-ia32": "0.25.1", + "@esbuild/win32-x64": "0.25.1" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.22.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.22.0.tgz", + "integrity": "sha512-9V/QURhsRN40xuHXWjV64yvrzMjcz7ZyNoF2jJFmy9j/SLk0u1OLSZgXi28MrXjymnjEGSR80WCdab3RGMDveQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.19.2", + "@eslint/config-helpers": "^0.1.0", + "@eslint/core": "^0.12.0", + "@eslint/eslintrc": "^3.3.0", + "@eslint/js": "9.22.0", + "@eslint/plugin-kit": "^0.2.7", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.3.0", + "eslint-visitor-keys": "^4.2.0", + "espree": "^10.3.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.2.0.tgz", + "integrity": "sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-react-refresh": { + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.19.tgz", + "integrity": "sha512-eyy8pcr/YxSYjBoqIFSrlbn9i/xvxUFa8CjzAYo9cFjgGXqq1hyjihcpZvxRLalpaWmueWR81xn7vuKmAFijDQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "eslint": ">=8.40" + } + }, + "node_modules/eslint-scope": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.3.0.tgz", + "integrity": "sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", + "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.14.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", + "license": "MIT" + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" + }, + "node_modules/follow-redirects": { + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz", + "integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/formik": { + "version": "2.4.6", + "resolved": "https://registry.npmjs.org/formik/-/formik-2.4.6.tgz", + "integrity": "sha512-A+2EI7U7aG296q2TLGvNapDNTZp1khVt5Vk0Q/fyfSROss0V/V6+txt2aJnwEos44IxTCW/LYAi/zgWzlevj+g==", + "funding": [ + { + "type": "individual", + "url": "https://opencollective.com/formik" + } + ], + "license": "Apache-2.0", + "dependencies": { + "@types/hoist-non-react-statics": "^3.3.1", + "deepmerge": "^2.1.1", + "hoist-non-react-statics": "^3.3.0", + "lodash": "^4.17.21", + "lodash-es": "^4.17.21", + "react-fast-compare": "^2.0.1", + "tiny-warning": "^1.0.2", + "tslib": "^2.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-nonce": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", + "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/global": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz", + "integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==", + "license": "MIT", + "dependencies": { + "min-document": "^2.19.0", + "process": "^0.11.10" + } + }, + "node_modules/globals": { + "version": "15.15.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.15.0.tgz", + "integrity": "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/highlight-words": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/highlight-words/-/highlight-words-2.0.0.tgz", + "integrity": "sha512-If5n+IhSBRXTScE7wl16VPmd+44Vy7kof24EdqhjsZsDuHikpv1OCagVcJFpB4fS4UPUniedlWqrjIO8vWOsIQ==", + "license": "MIT", + "engines": { + "node": ">= 20", + "npm": ">= 9" + } + }, + "node_modules/hls.js": { + "version": "1.5.20", + "resolved": "https://registry.npmjs.org/hls.js/-/hls.js-1.5.20.tgz", + "integrity": "sha512-uu0VXUK52JhihhnN/MVVo1lvqNNuhoxkonqgO3IpjvQiGpJBdIXMGkofjQb/j9zvV7a1SW8U9g1FslWx/1HOiQ==", + "license": "Apache-2.0" + }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "license": "BSD-3-Clause", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/hoist-non-react-statics/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "license": "MIT" + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-function": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.2.tgz", + "integrity": "sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ==", + "license": "MIT" + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "license": "MIT" + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "license": "MIT" + }, + "node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lucide-react": { + "version": "0.479.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.479.0.tgz", + "integrity": "sha512-aBhNnveRhorBOK7uA4gDjgaf+YlHMdMhQ/3cupk6exM10hWlEU+2QtWYOfhXhjAsmdb6LeKR+NZnow4UxRRiTQ==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/m3u8-parser": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/m3u8-parser/-/m3u8-parser-7.2.0.tgz", + "integrity": "sha512-CRatFqpjVtMiMaKXxNvuI3I++vUumIXVVT/JpCpdU/FynV/ceVw1qpPyyBNindL+JlPMSesx+WX1QJaZEJSaMQ==", + "license": "Apache-2.0", + "dependencies": { + "@babel/runtime": "^7.12.5", + "@videojs/vhs-utils": "^4.1.1", + "global": "^4.4.0" + } + }, + "node_modules/mantine-react-table": { + "version": "2.0.0-beta.9", + "resolved": "https://registry.npmjs.org/mantine-react-table/-/mantine-react-table-2.0.0-beta.9.tgz", + "integrity": "sha512-ZdfcwebWaPERoDvAuk43VYcBCzamohARVclnbuepT0PHZ0wRcDPMBR+zgaocL+pFy8EXUGwvWTOKNh25ITpjNQ==", + "license": "MIT", + "dependencies": { + "@tanstack/match-sorter-utils": "8.19.4", + "@tanstack/react-table": "8.20.5", + "@tanstack/react-virtual": "3.11.2" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kevinvandy" + }, + "peerDependencies": { + "@mantine/core": "^7.9", + "@mantine/dates": "^7.9", + "@mantine/hooks": "^7.9", + "@tabler/icons-react": ">=2.23.0", + "clsx": ">=2", + "dayjs": ">=1.11", + "react": ">=18.0", + "react-dom": ">=18.0" + } + }, + "node_modules/mantine-react-table/node_modules/@tanstack/react-table": { + "version": "8.20.5", + "resolved": "https://registry.npmjs.org/@tanstack/react-table/-/react-table-8.20.5.tgz", + "integrity": "sha512-WEHopKw3znbUZ61s9i0+i9g8drmDo6asTWbrQh8Us63DAk/M0FkmIqERew6P71HI75ksZ2Pxyuf4vvKh9rAkiA==", + "license": "MIT", + "dependencies": { + "@tanstack/table-core": "8.20.5" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, + "node_modules/material-react-table": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/material-react-table/-/material-react-table-3.2.1.tgz", + "integrity": "sha512-sQtTf7bETpkPN2Hm5BVtz89wrfXCVQguz6XlwMChSnfKFO5QCKAJJC5aSIKnUc3S0AvTz/k/ILi00FnnY1Gixw==", + "license": "MIT", + "dependencies": { + "@tanstack/match-sorter-utils": "8.19.4", + "@tanstack/react-table": "8.20.6", + "@tanstack/react-virtual": "3.11.2", + "highlight-words": "2.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kevinvandy" + }, + "peerDependencies": { + "@emotion/react": ">=11.13", + "@emotion/styled": ">=11.13", + "@mui/icons-material": ">=6", + "@mui/material": ">=6", + "@mui/x-date-pickers": ">=7.15", + "react": ">=18.0", + "react-dom": ">=18.0" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/min-document": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz", + "integrity": "sha512-9Wy1B3m3f66bPPmU5hdA4DR4PB2OfDU/+GS3yAB7IQozE3tqXaVv2zOjgla7MEGSRv95+ILmOuvhLkOK6wJtCQ==", + "dependencies": { + "dom-walk": "^0.1.0" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/mpd-parser": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/mpd-parser/-/mpd-parser-1.3.1.tgz", + "integrity": "sha512-1FuyEWI5k2HcmhS1HkKnUAQV7yFPfXPht2DnRRGtoiiAAW+ESTbtEXIDpRkwdU+XyrQuwrIym7UkoPKsZ0SyFw==", + "license": "Apache-2.0", + "dependencies": { + "@babel/runtime": "^7.12.5", + "@videojs/vhs-utils": "^4.0.0", + "@xmldom/xmldom": "^0.8.3", + "global": "^4.4.0" + }, + "bin": { + "mpd-to-m3u8-json": "bin/parse.js" + } + }, + "node_modules/mpegts.js": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/mpegts.js/-/mpegts.js-1.8.0.tgz", + "integrity": "sha512-ZtujqtmTjWgcDDkoOnLvrOKUTO/MKgLHM432zGDI8oPaJ0S+ebPxg1nEpDpLw6I7KmV/GZgUIrfbWi3qqEircg==", + "license": "Apache-2.0", + "dependencies": { + "es6-promise": "^4.2.5", + "webworkify-webpack": "github:xqq/webworkify-webpack" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/mux.js": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/mux.js/-/mux.js-7.1.0.tgz", + "integrity": "sha512-NTxawK/BBELJrYsZThEulyUMDVlLizKdxyAsMuzoCD1eFj97BVaA8D/CvKsKu6FOLYkFojN5CbM9h++ZTZtknA==", + "license": "Apache-2.0", + "dependencies": { + "@babel/runtime": "^7.11.2", + "global": "^4.4.0" + }, + "bin": { + "muxjs-transmux": "bin/transmux.js" + }, + "engines": { + "node": ">=8", + "npm": ">=5" + } + }, + "node_modules/nanoid": { + "version": "3.3.9", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.9.tgz", + "integrity": "sha512-SppoicMGpZvbF1l3z4x7No3OlIjP7QJvC9XR7AhZr1kL133KHnKPztkKDc+Ir4aJ/1VhTySrtKhrsycmrMQfvg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "license": "MIT" + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/pkcs7": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/pkcs7/-/pkcs7-1.0.4.tgz", + "integrity": "sha512-afRERtHn54AlwaF2/+LFszyAANTCggGilmcmILUzEjvs3XgFZT+xE6+QWQcAGmu4xajy+Xtj7acLOPdx5/eXWQ==", + "license": "Apache-2.0", + "dependencies": { + "@babel/runtime": "^7.5.5" + }, + "bin": { + "pkcs7": "bin/cli.js" + } + }, + "node_modules/postcss": { + "version": "8.5.3", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz", + "integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.8", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz", + "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==", + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, + "node_modules/property-expr": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.6.tgz", + "integrity": "sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA==", + "license": "MIT" + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/react": { + "version": "19.0.0", + "resolved": "https://registry.npmjs.org/react/-/react-19.0.0.tgz", + "integrity": "sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.0.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.0.0.tgz", + "integrity": "sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.25.0" + }, + "peerDependencies": { + "react": "^19.0.0" + } + }, + "node_modules/react-draggable": { + "version": "4.4.6", + "resolved": "https://registry.npmjs.org/react-draggable/-/react-draggable-4.4.6.tgz", + "integrity": "sha512-LtY5Xw1zTPqHkVmtM3X8MUOxNDOUhv/khTgBgrUvwaS064bwVvxT+q5El0uUFNx5IEPKXuRejr7UqLwBIg5pdw==", + "license": "MIT", + "dependencies": { + "clsx": "^1.1.1", + "prop-types": "^15.8.1" + }, + "peerDependencies": { + "react": ">= 16.3.0", + "react-dom": ">= 16.3.0" + } + }, + "node_modules/react-draggable/node_modules/clsx": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", + "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/react-fast-compare": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-2.0.4.tgz", + "integrity": "sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw==", + "license": "MIT" + }, + "node_modules/react-is": { + "version": "19.0.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.0.0.tgz", + "integrity": "sha512-H91OHcwjZsbq3ClIDHMzBShc1rotbfACdWENsmEf0IFvZ3FgGPtdHMcsv45bQ1hAbgdfiA8SnxTKfDS+x/8m2g==", + "license": "MIT" + }, + "node_modules/react-number-format": { + "version": "5.4.3", + "resolved": "https://registry.npmjs.org/react-number-format/-/react-number-format-5.4.3.tgz", + "integrity": "sha512-VCY5hFg/soBighAoGcdE+GagkJq0230qN6jcS5sp8wQX1qy1fYN/RX7/BXkrs0oyzzwqR8/+eSUrqXbGeywdUQ==", + "license": "MIT", + "peerDependencies": { + "react": "^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/react-pro-sidebar": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/react-pro-sidebar/-/react-pro-sidebar-1.1.0.tgz", + "integrity": "sha512-rdRJ4PeMsqWq9n69AmF6et6qCbhCF1KEBgjAH8vIiLxE1k5fMxtRYo0k4asxW8qpIH6sqahiMxrxVVoObv8orQ==", + "license": "MIT", + "dependencies": { + "@emotion/react": "^11.10.5", + "@emotion/styled": "^11.10.5", + "@popperjs/core": "^2.11.6", + "classnames": "^2.3.2" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/react-remove-scroll": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.6.3.tgz", + "integrity": "sha512-pnAi91oOk8g8ABQKGF5/M9qxmmOPxaAnopyTHYfqYEwJhyFrbbBtHuSgtKEoH0jpcxx5o3hXqH1mNd9/Oi+8iQ==", + "license": "MIT", + "dependencies": { + "react-remove-scroll-bar": "^2.3.7", + "react-style-singleton": "^2.2.3", + "tslib": "^2.1.0", + "use-callback-ref": "^1.3.3", + "use-sidecar": "^1.1.3" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-remove-scroll-bar": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz", + "integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==", + "license": "MIT", + "dependencies": { + "react-style-singleton": "^2.2.2", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-router": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.3.0.tgz", + "integrity": "sha512-466f2W7HIWaNXTKM5nHTqNxLrHTyXybm7R0eBlVSt0k/u55tTCDO194OIx/NrYD4TS5SXKTNekXfT37kMKUjgw==", + "license": "MIT", + "dependencies": { + "@types/cookie": "^0.6.0", + "cookie": "^1.0.1", + "set-cookie-parser": "^2.6.0", + "turbo-stream": "2.4.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, + "node_modules/react-router-dom": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.3.0.tgz", + "integrity": "sha512-z7Q5FTiHGgQfEurX/FBinkOXhWREJIAB2RiU24lvcBa82PxUpwqvs/PAXb9lJyPjTs2jrl6UkLvCZVGJPeNuuQ==", + "license": "MIT", + "dependencies": { + "react-router": "7.3.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/react-style-singleton": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz", + "integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==", + "license": "MIT", + "dependencies": { + "get-nonce": "^1.0.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-textarea-autosize": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/react-textarea-autosize/-/react-textarea-autosize-8.5.6.tgz", + "integrity": "sha512-aT3ioKXMa8f6zHYGebhbdMD2L00tKeRX1zuVuDx9YQK/JLLRSaSxq3ugECEmUB9z2kvk6bFSIoRHLkkUv0RJiw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.20.13", + "use-composed-ref": "^1.3.0", + "use-latest": "^1.2.1" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "license": "BSD-3-Clause", + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", + "license": "MIT" + }, + "node_modules/remove-accents": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/remove-accents/-/remove-accents-0.5.0.tgz", + "integrity": "sha512-8g3/Otx1eJaVD12e31UbJj1YzdtVvzH85HV7t+9MJYk/u3XmkOUJ5Ys9wQrf9PCPK8+xn4ymzqYCiZl6QWKn+A==", + "license": "MIT" + }, + "node_modules/resolve": { + "version": "1.22.10", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", + "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/rollup": { + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.35.0.tgz", + "integrity": "sha512-kg6oI4g+vc41vePJyO6dHt/yl0Rz3Thv0kJeVQ3D1kS3E5XSuKbPc29G4IpT/Kv1KQwgHVcN+HtyS+HYLNSvQg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.6" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.35.0", + "@rollup/rollup-android-arm64": "4.35.0", + "@rollup/rollup-darwin-arm64": "4.35.0", + "@rollup/rollup-darwin-x64": "4.35.0", + "@rollup/rollup-freebsd-arm64": "4.35.0", + "@rollup/rollup-freebsd-x64": "4.35.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.35.0", + "@rollup/rollup-linux-arm-musleabihf": "4.35.0", + "@rollup/rollup-linux-arm64-gnu": "4.35.0", + "@rollup/rollup-linux-arm64-musl": "4.35.0", + "@rollup/rollup-linux-loongarch64-gnu": "4.35.0", + "@rollup/rollup-linux-powerpc64le-gnu": "4.35.0", + "@rollup/rollup-linux-riscv64-gnu": "4.35.0", + "@rollup/rollup-linux-s390x-gnu": "4.35.0", + "@rollup/rollup-linux-x64-gnu": "4.35.0", + "@rollup/rollup-linux-x64-musl": "4.35.0", + "@rollup/rollup-win32-arm64-msvc": "4.35.0", + "@rollup/rollup-win32-ia32-msvc": "4.35.0", + "@rollup/rollup-win32-x64-msvc": "4.35.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/scheduler": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.25.0.tgz", + "integrity": "sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==", + "license": "MIT" + }, + "node_modules/set-cookie-parser": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz", + "integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==", + "license": "MIT" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/stylis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==", + "license": "MIT" + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tabbable": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz", + "integrity": "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==", + "license": "MIT" + }, + "node_modules/tiny-case": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-case/-/tiny-case-1.0.3.tgz", + "integrity": "sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q==", + "license": "MIT" + }, + "node_modules/tiny-warning": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", + "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==", + "license": "MIT" + }, + "node_modules/toposort": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz", + "integrity": "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==", + "license": "MIT" + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/turbo-stream": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/turbo-stream/-/turbo-stream-2.4.0.tgz", + "integrity": "sha512-FHncC10WpBd2eOmGwpmQsWLDoK4cqsA/UT/GqNoaKOQnT8uzhtCbg3EoUDMvqpOSAI0S26mr0rkjzbOO6S3v1g==", + "license": "ISC" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/use-callback-ref": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz", + "integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-composed-ref": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/use-composed-ref/-/use-composed-ref-1.4.0.tgz", + "integrity": "sha512-djviaxuOOh7wkj0paeO1Q/4wMZ8Zrnag5H6yBvzN7AKKe8beOaED9SF5/ByLqsku8NP4zQqsvM2u3ew/tJK8/w==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-isomorphic-layout-effect": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.2.0.tgz", + "integrity": "sha512-q6ayo8DWoPZT0VdG4u3D3uxcgONP3Mevx2i2b0434cwWBoL+aelL1DzkXI6w3PhTZzUeR2kaVlZn70iCiseP6w==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-latest": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/use-latest/-/use-latest-1.3.0.tgz", + "integrity": "sha512-mhg3xdm9NaM8q+gLT8KryJPnRFOz1/5XPBhmDEVZK1webPzDjrPk7f/mbpeLqTgB9msytYWANxgALOCJKnLvcQ==", + "license": "MIT", + "dependencies": { + "use-isomorphic-layout-effect": "^1.1.1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-sidecar": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz", + "integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==", + "license": "MIT", + "dependencies": { + "detect-node-es": "^1.1.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/video.js": { + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/video.js/-/video.js-8.21.0.tgz", + "integrity": "sha512-zcwerRb257QAuWfi8NH9yEX7vrGKFthjfcONmOQ4lxFRpDAbAi+u5LAjCjMWqhJda6zEmxkgdDpOMW3Y21QpXA==", + "license": "Apache-2.0", + "dependencies": { + "@babel/runtime": "^7.12.5", + "@videojs/http-streaming": "^3.16.2", + "@videojs/vhs-utils": "^4.1.1", + "@videojs/xhr": "2.7.0", + "aes-decrypter": "^4.0.2", + "global": "4.4.0", + "m3u8-parser": "^7.2.0", + "mpd-parser": "^1.3.1", + "mux.js": "^7.0.1", + "videojs-contrib-quality-levels": "4.1.0", + "videojs-font": "4.2.0", + "videojs-vtt.js": "0.15.5" + } + }, + "node_modules/videojs-contrib-quality-levels": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/videojs-contrib-quality-levels/-/videojs-contrib-quality-levels-4.1.0.tgz", + "integrity": "sha512-TfrXJJg1Bv4t6TOCMEVMwF/CoS8iENYsWNKip8zfhB5kTcegiFYezEA0eHAJPU64ZC8NQbxQgOwAsYU8VXbOWA==", + "license": "Apache-2.0", + "dependencies": { + "global": "^4.4.0" + }, + "engines": { + "node": ">=16", + "npm": ">=8" + }, + "peerDependencies": { + "video.js": "^8" + } + }, + "node_modules/videojs-font": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/videojs-font/-/videojs-font-4.2.0.tgz", + "integrity": "sha512-YPq+wiKoGy2/M7ccjmlvwi58z2xsykkkfNMyIg4xb7EZQQNwB71hcSsB3o75CqQV7/y5lXkXhI/rsGAS7jfEmQ==", + "license": "Apache-2.0" + }, + "node_modules/videojs-vtt.js": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/videojs-vtt.js/-/videojs-vtt.js-0.15.5.tgz", + "integrity": "sha512-yZbBxvA7QMYn15Lr/ZfhhLPrNpI/RmCSCqgIff57GC2gIrV5YfyzLfLyZMj0NnZSAz8syB4N0nHXpZg9MyrMOQ==", + "license": "Apache-2.0", + "dependencies": { + "global": "^4.3.1" + } + }, + "node_modules/vite": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.2.1.tgz", + "integrity": "sha512-n2GnqDb6XPhlt9B8olZPrgMD/es/Nd1RdChF6CBD/fHW6pUyUTt2sQW2fPRX5GiD9XEa6+8A6A4f2vT6pSsE7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "postcss": "^8.5.3", + "rollup": "^4.30.1" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "jiti": ">=1.21.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/webworkify-webpack": { + "version": "2.1.5", + "resolved": "git+ssh://git@github.com/xqq/webworkify-webpack.git#24d1e719b4a6cac37a518b2bb10fe124527ef4ef", + "license": "MIT" + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/yaml": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.0.tgz", + "integrity": "sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==", + "dev": true, + "license": "ISC", + "optional": true, + "peer": true, + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yup": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/yup/-/yup-1.6.1.tgz", + "integrity": "sha512-JED8pB50qbA4FOkDol0bYF/p60qSEDQqBD0/qeIrUCG1KbPBIQ776fCUNb9ldbPcSTxA69g/47XTo4TqWiuXOA==", + "license": "MIT", + "dependencies": { + "property-expr": "^2.0.5", + "tiny-case": "^1.0.3", + "toposort": "^2.0.2", + "type-fest": "^2.19.0" + } + }, + "node_modules/zustand": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.3.tgz", + "integrity": "sha512-14fwWQtU3pH4dE0dOpdMiWjddcH+QzKIgk1cl8epwSE7yag43k/AD/m4L6+K7DytAOr9gGBe3/EXj9g7cdostg==", + "license": "MIT", + "engines": { + "node": ">=12.20.0" + }, + "peerDependencies": { + "@types/react": ">=18.0.0", + "immer": ">=9.0.6", + "react": ">=18.0.0", + "use-sync-external-store": ">=1.2.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { + "optional": true + }, + "use-sync-external-store": { + "optional": true + } + } + } + } +} diff --git a/vite/package.json b/vite/package.json new file mode 100644 index 00000000..2e734af8 --- /dev/null +++ b/vite/package.json @@ -0,0 +1,52 @@ +{ + "name": "vite", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite --host", + "build": "vite build", + "lint": "eslint .", + "preview": "vite preview" + }, + "dependencies": { + "@emotion/react": "^11.14.0", + "@emotion/styled": "^11.14.0", + "@mantine/core": "^7.17.1", + "@mantine/dates": "^7.17.1", + "@mantine/hooks": "^7.17.1", + "@mui/icons-material": "^6.4.7", + "@mui/material": "^6.4.7", + "@mui/x-date-pickers": "^7.27.3", + "@tabler/icons-react": "^3.31.0", + "axios": "^1.8.2", + "clsx": "^2.1.1", + "dayjs": "^1.11.13", + "formik": "^2.4.6", + "hls.js": "^1.5.20", + "lucide-react": "^0.479.0", + "mantine-react-table": "^2.0.0-beta.9", + "material-react-table": "^3.2.1", + "mpegts.js": "^1.8.0", + "prettier": "^3.5.3", + "react": "^19.0.0", + "react-dom": "^19.0.0", + "react-draggable": "^4.4.6", + "react-pro-sidebar": "^1.1.0", + "react-router-dom": "^7.3.0", + "video.js": "^8.21.0", + "yup": "^1.6.1", + "zustand": "^5.0.3" + }, + "devDependencies": { + "@eslint/js": "^9.21.0", + "@types/react": "^19.0.10", + "@types/react-dom": "^19.0.4", + "@vitejs/plugin-react-swc": "^3.8.0", + "eslint": "^9.21.0", + "eslint-plugin-react-hooks": "^5.1.0", + "eslint-plugin-react-refresh": "^0.4.19", + "globals": "^15.15.0", + "vite": "^6.2.0" + } +} diff --git a/vite/prettier.config.js b/vite/prettier.config.js new file mode 100644 index 00000000..d2b86878 --- /dev/null +++ b/vite/prettier.config.js @@ -0,0 +1,10 @@ +// prettier.config.js or .prettierrc.js +export default { + semi: true, // Add semicolons at the end of statements + singleQuote: true, // Use single quotes instead of double + tabWidth: 2, // Set the indentation width + trailingComma: "es5", // Add trailing commas where valid in ES5 + printWidth: 80, // Wrap lines at 80 characters + bracketSpacing: true, // Add spaces inside object braces + arrowParens: "always", // Always include parentheses around arrow function parameters +}; diff --git a/vite/public/vite.svg b/vite/public/vite.svg new file mode 100644 index 00000000..e7b8dfb1 --- /dev/null +++ b/vite/public/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/vite/src/App.css b/vite/src/App.css new file mode 100644 index 00000000..74b5e053 --- /dev/null +++ b/vite/src/App.css @@ -0,0 +1,38 @@ +.App { + text-align: center; +} + +.App-logo { + height: 40vmin; + pointer-events: none; +} + +@media (prefers-reduced-motion: no-preference) { + .App-logo { + animation: App-logo-spin infinite 20s linear; + } +} + +.App-header { + background-color: #282c34; + min-height: 100vh; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + font-size: calc(10px + 2vmin); + color: white; +} + +.App-link { + color: #61dafb; +} + +@keyframes App-logo-spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} diff --git a/vite/src/App.jsx b/vite/src/App.jsx new file mode 100644 index 00000000..198d1f06 --- /dev/null +++ b/vite/src/App.jsx @@ -0,0 +1,169 @@ +// frontend/src/App.js +import React, { useEffect, useState } from 'react'; +import { + BrowserRouter as Router, + Route, + Routes, + Navigate, +} from 'react-router-dom'; +// import Sidebar from './components/Sidebar'; +import Sidebar from './components/Sidebar-new'; +import Login from './pages/Login'; +import Channels from './pages/Channels'; +import M3U from './pages/M3U'; +import { ThemeProvider } from '@mui/material/styles'; +import { Box, CssBaseline, GlobalStyles } from '@mui/material'; +import theme from './theme'; +import EPG from './pages/EPG'; +import Guide from './pages/Guide'; +import Settings from './pages/Settings'; +import StreamProfiles from './pages/StreamProfiles'; +import useAuthStore from './store/auth'; +import Alert from './components/Alert'; +import FloatingVideo from './components/FloatingVideo'; +import SuperuserForm from './components/forms/SuperuserForm'; +import { WebsocketProvider } from './WebSocket'; +import { AppShell, MantineProvider } from '@mantine/core'; +import '@mantine/core/styles.css'; // Ensure Mantine global styles load +import 'mantine-react-table/styles.css'; +import mantineTheme from './mantineTheme'; + +const drawerWidth = 240; +const miniDrawerWidth = 60; +const defaultRoute = '/channels'; + +const App = () => { + const [open, setOpen] = useState(true); + const [needsSuperuser, setNeedsSuperuser] = useState(false); + const { + isAuthenticated, + setIsAuthenticated, + logout, + initData, + initializeAuth, + } = useAuthStore(); + + const toggleDrawer = () => { + setOpen(!open); + }; + + // Check if a superuser exists on first load. + useEffect(() => { + async function checkSuperuser() { + try { + const response = await fetch('/api/accounts/initialize-superuser/'); + const res = await response.json(); + if (!res.data.superuser_exists) { + setNeedsSuperuser(true); + } + } catch (error) { + console.error('Error checking superuser status:', error); + } + } + checkSuperuser(); + }, []); + + // Authentication check + useEffect(() => { + const checkAuth = async () => { + const loggedIn = await initializeAuth(); + if (loggedIn) { + await initData(); + setIsAuthenticated(true); + } else { + await logout(); + } + }; + checkAuth(); + }, [initializeAuth, initData, setIsAuthenticated, logout]); + + // If no superuser exists, show the initialization form + if (needsSuperuser) { + return setNeedsSuperuser(false)} />; + } + + return ( + + + + + + + + + + + + {isAuthenticated ? ( + <> + } /> + } /> + } /> + } + /> + } /> + } /> + + ) : ( + } /> + )} + + } + /> + + + + + + + + + + + + ); +}; + +export default App; diff --git a/vite/src/WebSocket.jsx b/vite/src/WebSocket.jsx new file mode 100644 index 00000000..a5ae12e7 --- /dev/null +++ b/vite/src/WebSocket.jsx @@ -0,0 +1,85 @@ +import React, { + useState, + useEffect, + useRef, + createContext, + useContext, +} from 'react'; +import useStreamsStore from './store/streams'; +import useAlertStore from './store/alerts'; + +export const WebsocketContext = createContext(false, null, () => {}); + +export const WebsocketProvider = ({ children }) => { + const [isReady, setIsReady] = useState(false); + const [val, setVal] = useState(null); + + const { showAlert } = useAlertStore(); + const { fetchStreams } = useStreamsStore(); + + const ws = useRef(null); + + useEffect(() => { + let wsUrl = `${window.location.host}/ws/`; + if (import.meta.env.DEV) { + wsUrl = `${window.location.hostname}:8001/ws/`; + } + + if (window.location.protocol.match(/https/)) { + wsUrl = `wss://${wsUrl}`; + } else { + wsUrl = `ws://${wsUrl}`; + } + + const socket = new WebSocket(wsUrl); + + socket.onopen = () => { + console.log('websocket connected'); + setIsReady(true); + }; + + // Reconnection logic + socket.onclose = () => { + setIsReady(false); + setTimeout(() => { + const reconnectWs = new WebSocket(wsUrl); + reconnectWs.onopen = () => setIsReady(true); + }, 3000); // Attempt to reconnect every 3 seconds + }; + + socket.onmessage = async (event) => { + event = JSON.parse(event.data); + switch (event.type) { + case 'm3u_refresh': + if (event.message?.success) { + fetchStreams(); + showAlert(event.message.message, 'success'); + } + break; + + default: + console.error(`Unknown websocket event type: ${event.type}`); + break; + } + }; + + ws.current = socket; + + return () => { + socket.close(); + }; + }, []); + + const ret = [isReady, val, ws.current?.send.bind(ws.current)]; + + return ( + + {children} + + ); +}; + +export const useWebSocket = () => { + const socket = useContext(WebsocketContext); + return socket; +}; diff --git a/vite/src/api.js b/vite/src/api.js new file mode 100644 index 00000000..1d436a02 --- /dev/null +++ b/vite/src/api.js @@ -0,0 +1,783 @@ +// src/api.js (updated) +import useAuthStore from './store/auth'; +import useChannelsStore from './store/channels'; +import useUserAgentsStore from './store/userAgents'; +import usePlaylistsStore from './store/playlists'; +import useEPGsStore from './store/epgs'; +import useStreamsStore from './store/streams'; +import useStreamProfilesStore from './store/streamProfiles'; +import useSettingsStore from './store/settings'; + +// If needed, you can set a base host or keep it empty if relative requests +const host = import.meta.env.DEV + ? `http://${window.location.hostname}:5656` + : ''; + +export default class API { + /** + * A static method so we can do: await API.getAuthToken() + */ + static async getAuthToken() { + return await useAuthStore.getState().getToken(); + } + + static async login(username, password) { + const response = await fetch(`${host}/api/accounts/token/`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ username, password }), + }); + + return await response.json(); + } + + static async refreshToken(refresh) { + const response = await fetch(`${host}/api/accounts/token/refresh/`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ refresh }), + }); + + const retval = await response.json(); + return retval; + } + + static async logout() { + const response = await fetch(`${host}/api/accounts/auth/logout/`, { + method: 'POST', + }); + + return response.data.data; + } + + static async getChannels() { + const response = await fetch(`${host}/api/channels/channels/`, { + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${await API.getAuthToken()}`, + }, + }); + + const retval = await response.json(); + return retval; + } + + static async getChannelGroups() { + const response = await fetch(`${host}/api/channels/groups/`, { + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${await API.getAuthToken()}`, + }, + }); + + const retval = await response.json(); + return retval; + } + + static async addChannelGroup(values) { + const response = await fetch(`${host}/api/channels/groups/`, { + method: 'POST', + headers: { + Authorization: `Bearer ${await API.getAuthToken()}`, + 'Content-Type': 'application/json', + }, + body: JSON.stringify(values), + }); + + const retval = await response.json(); + if (retval.id) { + useChannelsStore.getState().addChannelGroup(retval); + } + + return retval; + } + + static async updateChannelGroup(values) { + const { id, ...payload } = values; + const response = await fetch(`${host}/api/channels/groups/${id}/`, { + method: 'PUT', + headers: { + Authorization: `Bearer ${await API.getAuthToken()}`, + 'Content-Type': 'application/json', + }, + body: JSON.stringify(payload), + }); + + const retval = await response.json(); + if (retval.id) { + useChannelsStore.getState().updateChannelGroup(retval); + } + + return retval; + } + + static async addChannel(channel) { + let body = null; + if (channel.logo_file) { + // Must send FormData for file upload + body = new FormData(); + for (const prop in channel) { + body.append(prop, channel[prop]); + } + } else { + body = { ...channel }; + delete body.logo_file; + body = JSON.stringify(body); + } + + const response = await fetch(`${host}/api/channels/channels/`, { + method: 'POST', + headers: { + Authorization: `Bearer ${await API.getAuthToken()}`, + ...(channel.logo_file + ? {} + : { + 'Content-Type': 'application/json', + }), + }, + body: body, + }); + + const retval = await response.json(); + if (retval.id) { + useChannelsStore.getState().addChannel(retval); + } + + return retval; + } + + static async deleteChannel(id) { + const response = await fetch(`${host}/api/channels/channels/${id}/`, { + method: 'DELETE', + headers: { + Authorization: `Bearer ${await API.getAuthToken()}`, + 'Content-Type': 'application/json', + }, + }); + + useChannelsStore.getState().removeChannels([id]); + } + + // @TODO: the bulk delete endpoint is currently broken + static async deleteChannels(channel_ids) { + const response = await fetch(`${host}/api/channels/channels/bulk-delete/`, { + method: 'DELETE', + headers: { + Authorization: `Bearer ${await API.getAuthToken()}`, + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ channel_ids }), + }); + + useChannelsStore.getState().removeChannels(channel_ids); + } + + static async updateChannel(values) { + const { id, ...payload } = values; + const response = await fetch(`${host}/api/channels/channels/${id}/`, { + method: 'PUT', + headers: { + Authorization: `Bearer ${await API.getAuthToken()}`, + 'Content-Type': 'application/json', + }, + body: JSON.stringify(payload), + }); + + const retval = await response.json(); + if (retval.id) { + useChannelsStore.getState().updateChannel(retval); + } + + return retval; + } + + static async assignChannelNumbers(channelIds) { + // Make the request + const response = await fetch(`${host}/api/channels/channels/assign/`, { + method: 'POST', + headers: { + Authorization: `Bearer ${await API.getAuthToken()}`, + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ channel_order: channelIds }), + }); + + if (!response.ok) { + const text = await response.text(); + throw new Error(`Assign channels failed: ${response.status} => ${text}`); + } + + const retval = await response.json(); + + // Optionally refresh the channel list in Zustand + await useChannelsStore.getState().fetchChannels(); + + return retval; + } + + static async createChannelFromStream(values) { + const response = await fetch(`${host}/api/channels/channels/from-stream/`, { + method: 'POST', + headers: { + Authorization: `Bearer ${await API.getAuthToken()}`, + 'Content-Type': 'application/json', + }, + body: JSON.stringify(values), + }); + + const retval = await response.json(); + if (retval.id) { + useChannelsStore.getState().addChannel(retval); + } + + return retval; + } + + static async createChannelsFromStreams(values) { + const response = await fetch( + `${host}/api/channels/channels/from-stream/bulk/`, + { + method: 'POST', + headers: { + Authorization: `Bearer ${await API.getAuthToken()}`, + 'Content-Type': 'application/json', + }, + body: JSON.stringify(values), + } + ); + + const retval = await response.json(); + if (retval.created.length > 0) { + useChannelsStore.getState().addChannels(retval.created); + } + + return retval; + } + + static async getStreams() { + const response = await fetch(`${host}/api/channels/streams/`, { + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${await API.getAuthToken()}`, + }, + }); + + const retval = await response.json(); + return retval; + } + + static async queryStreams(params) { + const response = await fetch( + `${host}/api/channels/streams/?${params.toString()}`, + { + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${await API.getAuthToken()}`, + }, + } + ); + + const retval = await response.json(); + return retval; + } + + static async getAllStreamIds(params) { + const response = await fetch( + `${host}/api/channels/streams/ids/?${params.toString()}`, + { + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${await API.getAuthToken()}`, + }, + } + ); + + const retval = await response.json(); + return retval; + } + + static async getStreamGroups() { + const response = await fetch(`${host}/api/channels/streams/groups/`, { + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${await API.getAuthToken()}`, + }, + }); + + const retval = await response.json(); + return retval; + } + + static async addStream(values) { + const response = await fetch(`${host}/api/channels/streams/`, { + method: 'POST', + headers: { + Authorization: `Bearer ${await API.getAuthToken()}`, + 'Content-Type': 'application/json', + }, + body: JSON.stringify(values), + }); + + const retval = await response.json(); + if (retval.id) { + useStreamsStore.getState().addStream(retval); + } + + return retval; + } + + static async updateStream(values) { + const { id, ...payload } = values; + const response = await fetch(`${host}/api/channels/streams/${id}/`, { + method: 'PUT', + headers: { + Authorization: `Bearer ${await API.getAuthToken()}`, + 'Content-Type': 'application/json', + }, + body: JSON.stringify(payload), + }); + + const retval = await response.json(); + if (retval.id) { + useStreamsStore.getState().updateStream(retval); + } + + return retval; + } + + static async deleteStream(id) { + const response = await fetch(`${host}/api/channels/streams/${id}/`, { + method: 'DELETE', + headers: { + Authorization: `Bearer ${await API.getAuthToken()}`, + 'Content-Type': 'application/json', + }, + }); + + useStreamsStore.getState().removeStreams([id]); + } + + static async deleteStreams(ids) { + const response = await fetch(`${host}/api/channels/streams/bulk-delete/`, { + method: 'DELETE', + headers: { + Authorization: `Bearer ${await API.getAuthToken()}`, + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ stream_ids: ids }), + }); + + useStreamsStore.getState().removeStreams(ids); + } + + static async getUserAgents() { + const response = await fetch(`${host}/api/core/useragents/`, { + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${await API.getAuthToken()}`, + }, + }); + + const retval = await response.json(); + return retval; + } + + static async addUserAgent(values) { + const response = await fetch(`${host}/api/core/useragents/`, { + method: 'POST', + headers: { + Authorization: `Bearer ${await API.getAuthToken()}`, + 'Content-Type': 'application/json', + }, + body: JSON.stringify(values), + }); + + const retval = await response.json(); + if (retval.id) { + useUserAgentsStore.getState().addUserAgent(retval); + } + + return retval; + } + + static async updateUserAgent(values) { + const { id, ...payload } = values; + const response = await fetch(`${host}/api/core/useragents/${id}/`, { + method: 'PUT', + headers: { + Authorization: `Bearer ${await API.getAuthToken()}`, + 'Content-Type': 'application/json', + }, + body: JSON.stringify(payload), + }); + + const retval = await response.json(); + if (retval.id) { + useUserAgentsStore.getState().updateUserAgent(retval); + } + + return retval; + } + + static async deleteUserAgent(id) { + const response = await fetch(`${host}/api/core/useragents/${id}/`, { + method: 'DELETE', + headers: { + Authorization: `Bearer ${await API.getAuthToken()}`, + 'Content-Type': 'application/json', + }, + }); + + useUserAgentsStore.getState().removeUserAgents([id]); + } + + static async getPlaylist(id) { + const response = await fetch(`${host}/api/m3u/accounts/${id}/`, { + headers: { + Authorization: `Bearer ${await API.getAuthToken()}`, + 'Content-Type': 'application/json', + }, + }); + + const retval = await response.json(); + return retval; + } + + static async getPlaylists() { + const response = await fetch(`${host}/api/m3u/accounts/`, { + headers: { + Authorization: `Bearer ${await API.getAuthToken()}`, + 'Content-Type': 'application/json', + }, + }); + + const retval = await response.json(); + return retval; + } + + static async addPlaylist(values) { + const response = await fetch(`${host}/api/m3u/accounts/`, { + method: 'POST', + headers: { + Authorization: `Bearer ${await API.getAuthToken()}`, + 'Content-Type': 'application/json', + }, + body: JSON.stringify(values), + }); + + const retval = await response.json(); + if (retval.id) { + usePlaylistsStore.getState().addPlaylist(retval); + } + + return retval; + } + + static async refreshPlaylist(id) { + const response = await fetch(`${host}/api/m3u/refresh/${id}/`, { + method: 'POST', + headers: { + Authorization: `Bearer ${await API.getAuthToken()}`, + 'Content-Type': 'application/json', + }, + }); + + const retval = await response.json(); + return retval; + } + + static async refreshAllPlaylist() { + const response = await fetch(`${host}/api/m3u/refresh/`, { + method: 'POST', + headers: { + Authorization: `Bearer ${await API.getAuthToken()}`, + 'Content-Type': 'application/json', + }, + }); + + const retval = await response.json(); + return retval; + } + + static async deletePlaylist(id) { + const response = await fetch(`${host}/api/m3u/accounts/${id}/`, { + method: 'DELETE', + headers: { + Authorization: `Bearer ${await API.getAuthToken()}`, + 'Content-Type': 'application/json', + }, + }); + + usePlaylistsStore.getState().removePlaylists([id]); + } + + static async updatePlaylist(values) { + const { id, ...payload } = values; + const response = await fetch(`${host}/api/m3u/accounts/${id}/`, { + method: 'PUT', + headers: { + Authorization: `Bearer ${await API.getAuthToken()}`, + 'Content-Type': 'application/json', + }, + body: JSON.stringify(payload), + }); + + const retval = await response.json(); + if (retval.id) { + usePlaylistsStore.getState().updatePlaylist(retval); + } + + return retval; + } + + static async getEPGs() { + const response = await fetch(`${host}/api/epg/sources/`, { + headers: { + Authorization: `Bearer ${await API.getAuthToken()}`, + 'Content-Type': 'application/json', + }, + }); + + const retval = await response.json(); + return retval; + } + + // Notice there's a duplicated "refreshPlaylist" method above; + // you might want to rename or remove one if it's not needed. + + static async addEPG(values) { + let body = null; + if (values.epg_file) { + body = new FormData(); + for (const prop in values) { + body.append(prop, values[prop]); + } + } else { + body = { ...values }; + delete body.epg_file; + body = JSON.stringify(body); + } + + const response = await fetch(`${host}/api/epg/sources/`, { + method: 'POST', + headers: { + Authorization: `Bearer ${await API.getAuthToken()}`, + ...(values.epg_file + ? {} + : { + 'Content-Type': 'application/json', + }), + }, + body, + }); + + const retval = await response.json(); + if (retval.id) { + useEPGsStore.getState().addEPG(retval); + } + + return retval; + } + + static async deleteEPG(id) { + const response = await fetch(`${host}/api/epg/sources/${id}/`, { + method: 'DELETE', + headers: { + Authorization: `Bearer ${await API.getAuthToken()}`, + 'Content-Type': 'application/json', + }, + }); + + useEPGsStore.getState().removeEPGs([id]); + } + + static async refreshEPG(id) { + const response = await fetch(`${host}/api/epg/import/`, { + method: 'POST', + headers: { + Authorization: `Bearer ${await API.getAuthToken()}`, + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ id }), + }); + + const retval = await response.json(); + return retval; + } + + static async getStreamProfiles() { + const response = await fetch(`${host}/api/core/streamprofiles/`, { + headers: { + Authorization: `Bearer ${await API.getAuthToken()}`, + 'Content-Type': 'application/json', + }, + }); + + const retval = await response.json(); + return retval; + } + + static async addStreamProfile(values) { + const response = await fetch(`${host}/api/core/streamprofiles/`, { + method: 'POST', + headers: { + Authorization: `Bearer ${await API.getAuthToken()}`, + 'Content-Type': 'application/json', + }, + body: JSON.stringify(values), + }); + + const retval = await response.json(); + if (retval.id) { + useStreamProfilesStore.getState().addStreamProfile(retval); + } + return retval; + } + + static async updateStreamProfile(values) { + const { id, ...payload } = values; + const response = await fetch(`${host}/api/core/streamprofiles/${id}/`, { + method: 'PUT', + headers: { + Authorization: `Bearer ${await API.getAuthToken()}`, + 'Content-Type': 'application/json', + }, + body: JSON.stringify(payload), + }); + + const retval = await response.json(); + if (retval.id) { + useStreamProfilesStore.getState().updateStreamProfile(retval); + } + + return retval; + } + + static async deleteStreamProfile(id) { + const response = await fetch(`${host}/api/core/streamprofiles/${id}/`, { + method: 'DELETE', + headers: { + Authorization: `Bearer ${await API.getAuthToken()}`, + 'Content-Type': 'application/json', + }, + }); + + useStreamProfilesStore.getState().removeStreamProfiles([id]); + } + + static async getGrid() { + const response = await fetch(`${host}/api/epg/grid/`, { + headers: { + Authorization: `Bearer ${await API.getAuthToken()}`, + 'Content-Type': 'application/json', + }, + }); + + const retval = await response.json(); + return retval.data; + } + + static async addM3UProfile(accountId, values) { + const response = await fetch( + `${host}/api/m3u/accounts/${accountId}/profiles/`, + { + method: 'POST', + headers: { + Authorization: `Bearer ${await API.getAuthToken()}`, + 'Content-Type': 'application/json', + }, + body: JSON.stringify(values), + } + ); + + const retval = await response.json(); + if (retval.id) { + // Refresh the playlist + const playlist = await API.getPlaylist(accountId); + usePlaylistsStore + .getState() + .updateProfiles(playlist.id, playlist.profiles); + } + + return retval; + } + + static async deleteM3UProfile(accountId, id) { + const response = await fetch( + `${host}/api/m3u/accounts/${accountId}/profiles/${id}/`, + { + method: 'DELETE', + headers: { + Authorization: `Bearer ${await API.getAuthToken()}`, + 'Content-Type': 'application/json', + }, + } + ); + + const playlist = await API.getPlaylist(accountId); + usePlaylistsStore.getState().updatePlaylist(playlist); + } + + static async updateM3UProfile(accountId, values) { + const { id, ...payload } = values; + const response = await fetch( + `${host}/api/m3u/accounts/${accountId}/profiles/${id}/`, + { + method: 'PUT', + headers: { + Authorization: `Bearer ${await API.getAuthToken()}`, + 'Content-Type': 'application/json', + }, + body: JSON.stringify(payload), + } + ); + + const playlist = await API.getPlaylist(accountId); + usePlaylistsStore.getState().updateProfiles(playlist.id, playlist.profiles); + } + + static async getSettings() { + const response = await fetch(`${host}/api/core/settings/`, { + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${await API.getAuthToken()}`, + }, + }); + + const retval = await response.json(); + return retval; + } + + static async getEnvironmentSettings() { + const response = await fetch(`${host}/api/core/settings/env/`, { + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${await API.getAuthToken()}`, + }, + }); + + const retval = await response.json(); + return retval; + } + + static async updateSetting(values) { + const { id, ...payload } = values; + const response = await fetch(`${host}/api/core/settings/${id}/`, { + method: 'PUT', + headers: { + Authorization: `Bearer ${await API.getAuthToken()}`, + 'Content-Type': 'application/json', + }, + body: JSON.stringify(payload), + }); + + const retval = await response.json(); + if (retval.id) { + useSettingsStore.getState().updateSetting(retval); + } + + return retval; + } +} diff --git a/vite/src/assets/react.svg b/vite/src/assets/react.svg new file mode 100644 index 00000000..6c87de9b --- /dev/null +++ b/vite/src/assets/react.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/vite/src/components/Alert.jsx b/vite/src/components/Alert.jsx new file mode 100644 index 00000000..fa843400 --- /dev/null +++ b/vite/src/components/Alert.jsx @@ -0,0 +1,26 @@ +import React, { useState } from 'react'; +import { Snackbar, Alert, Button } from '@mui/material'; +import useAlertStore from '../store/alerts'; + +const AlertPopup = () => { + const { open, message, severity, hideAlert } = useAlertStore(); + + const handleClose = () => { + hideAlert(); + }; + + return ( + + + {message} + + + ); +}; + +export default AlertPopup; diff --git a/vite/src/components/FloatingVideo.jsx b/vite/src/components/FloatingVideo.jsx new file mode 100644 index 00000000..cc162c11 --- /dev/null +++ b/vite/src/components/FloatingVideo.jsx @@ -0,0 +1,98 @@ +// frontend/src/components/FloatingVideo.js +import React, { useEffect, useRef } from 'react'; +import Draggable from 'react-draggable'; +import useVideoStore from '../store/useVideoStore'; +import mpegts from 'mpegts.js'; + +export default function FloatingVideo() { + const { isVisible, streamUrl, hideVideo } = useVideoStore(); + const videoRef = useRef(null); + const playerRef = useRef(null); + + useEffect(() => { + if (!isVisible || !streamUrl) { + return; + } + + // If the browser supports MSE for live playback, initialize mpegts.js + if (mpegts.getFeatureList().mseLivePlayback) { + const player = mpegts.createPlayer({ + type: 'mpegts', + url: streamUrl, + isLive: true, + // You can include other custom MPEGTS.js config fields here, e.g.: + // cors: true, + // withCredentials: false, + }); + + player.attachMediaElement(videoRef.current); + player.load(); + player.play(); + + // Store player instance so we can clean up later + playerRef.current = player; + } + + // Cleanup when component unmounts or streamUrl changes + return () => { + if (playerRef.current) { + playerRef.current.destroy(); + playerRef.current = null; + } + }; + }, [isVisible, streamUrl]); + + // If the floating video is hidden or no URL is selected, do not render + if (!isVisible || !streamUrl) { + return null; + } + + return ( + +
+ {/* Simple header row with a close button */} +
+ +
+ + {/* The
+
+ ); +} diff --git a/vite/src/components/Sidebar-new.jsx b/vite/src/components/Sidebar-new.jsx new file mode 100644 index 00000000..6aede6eb --- /dev/null +++ b/vite/src/components/Sidebar-new.jsx @@ -0,0 +1,186 @@ +import { Link, useLocation } from 'react-router-dom'; +import { + ListOrdered, + Play, + Database, + SlidersHorizontal, + LayoutGrid, + Settings as LucideSettings, +} from 'lucide-react'; +import { + Avatar, + AppShell, + Group, + Stack, + Box, + Text, + UnstyledButton, +} from '@mantine/core'; +import { useState } from 'react'; +import headerLogo from '../images/dispatcharr.svg'; +import logo from '../images/logo.png'; + +// Navigation Items +const navItems = [ + { + label: 'Channels', + icon: , + path: '/channels', + // badge: '(323)', + }, + { label: 'M3U', icon: , path: '/m3u' }, + { label: 'EPG', icon: , path: '/epg' }, + { + label: 'Stream Profiles', + icon: , + path: '/stream-profiles', + }, + { label: 'TV Guide', icon: , path: '/guide' }, + { label: 'Settings', icon: , path: '/settings' }, +]; + +const Sidebar = ({ collapsed, toggleDrawer, drawerWidth, miniDrawerWidth }) => { + const location = useLocation(); + + return ( + + {/* Brand - Click to Toggle */} + + {/* */} + + {!collapsed && ( + + Dispatcharr + + )} + + + {/* Navigation Links */} + + {navItems.map((item) => { + const isActive = location.pathname === item.path; + + return ( + + {item.icon} + {!collapsed && ( + + {item.label} + + )} + {!collapsed && item.badge && ( + + {item.badge} + + )} + + ); + })} + + + {/* Profile Section */} + + + {!collapsed && ( + + + John Doe + + + ••• + + + )} + + + ); +}; + +export default Sidebar; diff --git a/vite/src/components/Sidebar.jsx b/vite/src/components/Sidebar.jsx new file mode 100644 index 00000000..9b4502fa --- /dev/null +++ b/vite/src/components/Sidebar.jsx @@ -0,0 +1,189 @@ +import React from 'react'; +import { Link, useLocation } from 'react-router-dom'; +import { + Drawer, + Toolbar, + Box, + Typography, + Avatar, + List, + ListItemButton, + ListItemIcon, + ListItemText, +} from '@mui/material'; +import { useTheme } from '@mui/material/styles'; +import { + ListOrdered, + Play, + Database, + SlidersHorizontal, + LayoutGrid, + Settings as LucideSettings, +} from 'lucide-react'; +import logo from '../images/logo.png'; +import { AppShell } from '@mantine/core'; + +const navItems = [ + { label: 'Channels', icon: , path: '/channels' }, + { label: 'M3U', icon: , path: '/m3u' }, + { label: 'EPG', icon: , path: '/epg' }, + { + label: 'Stream Profiles', + icon: , + path: '/stream-profiles', + }, + { label: 'TV Guide', icon: , path: '/guide' }, + { label: 'Settings', icon: , path: '/settings' }, +]; + +const Sidebar = ({ open, drawerWidth, miniDrawerWidth, toggleDrawer }) => { + const location = useLocation(); + const theme = useTheme(); + + return ( + + + + {open ? ( + + Dispatcharr Logo + + Dispatcharr + + + ) : ( + Dispatcharr Logo + )} + + + + {navItems.map((item) => { + const isActive = location.pathname.startsWith(item.path); + return ( + + + + {item.icon} + + {open && ( + + )} + + + ); + })} + + + + + + {open && ( + + John Doe + + )} + + + + ); +}; + +export default Sidebar; diff --git a/vite/src/components/forms/Channel.jsx b/vite/src/components/forms/Channel.jsx new file mode 100644 index 00000000..2b5d84e2 --- /dev/null +++ b/vite/src/components/forms/Channel.jsx @@ -0,0 +1,491 @@ +import React, { useState, useEffect, useMemo } from 'react'; +import { + Box, + Typography, + Stack, + TextField, + Button, + Select, + MenuItem, + Grid2, + InputLabel, + FormControl, + CircularProgress, + IconButton, + Dialog, + DialogTitle, + DialogContent, + DialogActions, + FormHelperText, +} from '@mui/material'; +import { useFormik } from 'formik'; +import * as Yup from 'yup'; +import useChannelsStore from '../../store/channels'; +import API from '../../api'; +import useStreamProfilesStore from '../../store/streamProfiles'; +import { Add as AddIcon, Remove as RemoveIcon } from '@mui/icons-material'; +import useStreamsStore from '../../store/streams'; +import { + MaterialReactTable, + useMaterialReactTable, +} from 'material-react-table'; +import ChannelGroupForm from './ChannelGroup'; +import usePlaylistsStore from '../../store/playlists'; +import logo from '../../images/logo.png'; + +const Channel = ({ channel = null, isOpen, onClose }) => { + const channelGroups = useChannelsStore((state) => state.channelGroups); + const streams = useStreamsStore((state) => state.streams); + const { profiles: streamProfiles } = useStreamProfilesStore(); + const { playlists } = usePlaylistsStore(); + + const [logoFile, setLogoFile] = useState(null); + const [logoPreview, setLogoPreview] = useState(logo); + const [channelStreams, setChannelStreams] = useState([]); + const [channelGroupModelOpen, setChannelGroupModalOpen] = useState(false); + + const addStream = (stream) => { + const streamSet = new Set(channelStreams); + streamSet.add(stream); + setChannelStreams(Array.from(streamSet)); + }; + + const removeStream = (stream) => { + const streamSet = new Set(channelStreams); + streamSet.delete(stream); + setChannelStreams(Array.from(streamSet)); + }; + + const handleLogoChange = (e) => { + const file = e.target.files[0]; + if (file) { + setLogoFile(file); + setLogoPreview(URL.createObjectURL(file)); + } + }; + + const formik = useFormik({ + initialValues: { + channel_name: '', + channel_number: '', + channel_group_id: '', + stream_profile_id: '0', + tvg_id: '', + tvg_name: '', + }, + validationSchema: Yup.object({ + channel_name: Yup.string().required('Name is required'), + channel_number: Yup.string().required('Invalid channel number').min(0), + channel_group_id: Yup.string().required('Channel group is required'), + }), + onSubmit: async (values, { setSubmitting, resetForm }) => { + if (values.stream_profile_id == '0') { + values.stream_profile_id = null; + } + + console.log(values); + if (channel?.id) { + await API.updateChannel({ + id: channel.id, + ...values, + logo_file: logoFile, + streams: channelStreams.map((stream) => stream.id), + }); + } else { + await API.addChannel({ + ...values, + logo_file: logoFile, + streams: channelStreams.map((stream) => stream.id), + }); + } + + resetForm(); + setLogoFile(null); + setLogoPreview(logo); + setSubmitting(false); + onClose(); + }, + }); + + useEffect(() => { + if (channel) { + formik.setValues({ + channel_name: channel.channel_name, + channel_number: channel.channel_number, + channel_group_id: channel.channel_group?.id, + stream_profile_id: channel.stream_profile_id || '0', + tvg_id: channel.tvg_id, + tvg_name: channel.tvg_name, + }); + + console.log(channel); + const filteredStreams = streams + .filter((stream) => channel.stream_ids.includes(stream.id)) + .sort( + (a, b) => + channel.stream_ids.indexOf(a.id) - channel.stream_ids.indexOf(b.id) + ); + setChannelStreams(filteredStreams); + } else { + formik.resetForm(); + } + }, [channel]); + + const activeStreamsTable = useMaterialReactTable({ + data: channelStreams, + columns: useMemo( + () => [ + { + header: 'Name', + accessorKey: 'name', + }, + { + header: 'M3U', + accessorKey: 'group_name', + }, + ], + [] + ), + enableSorting: false, + enableBottomToolbar: false, + enableTopToolbar: false, + columnFilterDisplayMode: 'popover', + enablePagination: false, + enableRowVirtualization: true, + enableRowOrdering: true, + rowVirtualizerOptions: { overscan: 5 }, //optionally customize the row virtualizer + initialState: { + density: 'compact', + }, + enableRowActions: true, + positionActionsColumn: 'last', + renderRowActions: ({ row }) => ( + <> + removeStream(row.original)} + > + {/* Small icon size */} + + + ), + muiTableContainerProps: { + sx: { + height: '200px', + }, + }, + muiRowDragHandleProps: ({ table }) => ({ + onDragEnd: () => { + const { draggingRow, hoveredRow } = table.getState(); + + if (hoveredRow && draggingRow) { + channelStreams.splice( + hoveredRow.index, + 0, + channelStreams.splice(draggingRow.index, 1)[0] + ); + + setChannelStreams([...channelStreams]); + } + }, + }), + }); + + const availableStreamsTable = useMaterialReactTable({ + data: streams, + columns: useMemo( + () => [ + { + header: 'Name', + accessorKey: 'name', + }, + { + header: 'M3U', + accessorFn: (row) => + playlists.find((playlist) => playlist.id === row.m3u_account)?.name, + }, + ], + [] + ), + enableBottomToolbar: false, + enableTopToolbar: false, + columnFilterDisplayMode: 'popover', + enablePagination: false, + enableRowVirtualization: true, + rowVirtualizerOptions: { overscan: 5 }, //optionally customize the row virtualizer + initialState: { + density: 'compact', + }, + enableRowActions: true, + renderRowActions: ({ row }) => ( + <> + addStream(row.original)} + > + {/* Small icon size */} + + + ), + positionActionsColumn: 'last', + muiTableContainerProps: { + sx: { + height: '200px', + }, + }, + }); + + if (!isOpen) { + return <>; + } + + return ( + <> + + + Channel + + +
+ + + + + + + + + + Channel Group + + + + {formik.touched.channel_group_id && + formik.errors.channel_group_id} + + + + + setChannelGroupModalOpen(true)} + title="Create new group" + size="small" + variant="filled" + > + + + + + + + + Stream Profile + + + + + + + + + + + + + + + + {/* File upload input */} + + Logo + {/* Display selected image */} + + Selected + + handleLogoChange(event)} + style={{ display: 'none' }} + /> + + + + + + + + + Active Streams + + + + + Available Streams + + + + + + + {/* Submit button */} + + +
+
+ setChannelGroupModalOpen(false)} + /> + + ); +}; + +export default Channel; diff --git a/vite/src/components/forms/ChannelGroup.jsx b/vite/src/components/forms/ChannelGroup.jsx new file mode 100644 index 00000000..407695df --- /dev/null +++ b/vite/src/components/forms/ChannelGroup.jsx @@ -0,0 +1,71 @@ +// Modal.js +import React, { useEffect } from 'react'; +import { useFormik } from 'formik'; +import * as Yup from 'yup'; +import API from '../../api'; +import { Flex, TextInput, Button } from '@mantine/core'; + +const ChannelGroup = ({ channelGroup = null, isOpen, onClose }) => { + const formik = useFormik({ + initialValues: { + name: '', + }, + validationSchema: Yup.object({ + name: Yup.string().required('Name is required'), + }), + onSubmit: async (values, { setSubmitting, resetForm }) => { + if (channelGroup?.id) { + await API.updateChannelGroup({ id: channelGroup.id, ...values }); + } else { + await API.addChannelGroup(values); + } + + resetForm(); + setSubmitting(false); + onClose(); + }, + }); + + useEffect(() => { + if (channelGroup) { + formik.setValues({ + name: channelGroup.name, + }); + } else { + formik.resetForm(); + } + }, [channelGroup]); + + if (!isOpen) { + return <>; + } + + return ( + +
+ + + + + + +
+ ); +}; + +export default ChannelGroup; diff --git a/vite/src/components/forms/EPG.jsx b/vite/src/components/forms/EPG.jsx new file mode 100644 index 00000000..93b0ca5f --- /dev/null +++ b/vite/src/components/forms/EPG.jsx @@ -0,0 +1,143 @@ +// Modal.js +import React, { useState, useEffect } from 'react'; +import { useFormik } from 'formik'; +import * as Yup from 'yup'; +import API from '../../api'; +import useEPGsStore from '../../store/epgs'; +import { + LoadingOverlay, + TextInput, + Button, + Checkbox, + Modal, + Flex, + NativeSelect, + FileInput, + Space, +} from '@mantine/core'; + +const EPG = ({ epg = null, isOpen, onClose }) => { + const epgs = useEPGsStore((state) => state.epgs); + const [file, setFile] = useState(null); + + const handleFileChange = (e) => { + const file = e.target.files[0]; + if (file) { + setFile(file); + } + }; + + const formik = useFormik({ + initialValues: { + name: '', + source_type: 'xmltv', + url: '', + api_key: '', + is_active: true, + }, + validationSchema: Yup.object({ + name: Yup.string().required('Name is required'), + source_type: Yup.string().required('Source type is required'), + }), + onSubmit: async (values, { setSubmitting, resetForm }) => { + if (epg?.id) { + await API.updateEPG({ id: epg.id, ...values, epg_file: file }); + } else { + await API.addEPG({ + ...values, + epg_file: file, + }); + } + + resetForm(); + setFile(null); + setSubmitting(false); + onClose(); + }, + }); + + useEffect(() => { + if (epg) { + formik.setValues({ + name: epg.name, + source_type: epg.source_type, + url: epg.url, + api_key: epg.api_key, + is_active: epg.is_active, + }); + } else { + formik.resetForm(); + } + }, [epg]); + + if (!isOpen) { + return <>; + } + + return ( + +
+ + + + + + + + + + + + +
+ ); +}; + +export default EPG; diff --git a/vite/src/components/forms/LoginForm.jsx b/vite/src/components/forms/LoginForm.jsx new file mode 100644 index 00000000..8eb8c183 --- /dev/null +++ b/vite/src/components/forms/LoginForm.jsx @@ -0,0 +1,93 @@ +import React, { useState, useEffect } from 'react'; +import { useNavigate } from 'react-router-dom'; +import useAuthStore from '../../store/auth'; +import { + Paper, + Title, + TextInput, + Button, + Checkbox, + Modal, + Box, + Center, + Stack, +} from '@mantine/core'; + +const LoginForm = () => { + const { login, isAuthenticated, initData } = useAuthStore(); // Get login function from AuthContext + const navigate = useNavigate(); // Hook to navigate to other routes + const [formData, setFormData] = useState({ username: '', password: '' }); + + useEffect(() => { + if (isAuthenticated) { + navigate('/channels'); + } + }, [isAuthenticated, navigate]); + + const handleInputChange = (e) => { + setFormData({ + ...formData, + [e.target.name]: e.target.value, + }); + }; + + const handleSubmit = async (e) => { + e.preventDefault(); + await login(formData); + initData(); + navigate('/channels'); // Or any other route you'd like + }; + + // // Handle form submission + // const handleSubmit = async (e) => { + // e.preventDefault(); + // setLoading(true); + // setError(''); // Reset error on each new submission + + // await login(username, password) + // navigate('/channels'); // Or any other route you'd like + // }; + + return ( +
+ + + Login + +
+ + + + + + + +
+
+
+ ); +}; + +export default LoginForm; diff --git a/vite/src/components/forms/M3U.jsx b/vite/src/components/forms/M3U.jsx new file mode 100644 index 00000000..1567bf2a --- /dev/null +++ b/vite/src/components/forms/M3U.jsx @@ -0,0 +1,192 @@ +// Modal.js +import React, { useState, useEffect } from 'react'; +import { useFormik } from 'formik'; +import * as Yup from 'yup'; +import API from '../../api'; +import useUserAgentsStore from '../../store/userAgents'; +import M3UProfiles from './M3UProfiles'; +import { + LoadingOverlay, + TextInput, + Button, + Checkbox, + Modal, + Flex, + NativeSelect, + FileInput, + Select, + Space, +} from '@mantine/core'; + +const M3U = ({ playlist = null, isOpen, onClose }) => { + const userAgents = useUserAgentsStore((state) => state.userAgents); + const [file, setFile] = useState(null); + const [profileModalOpen, setProfileModalOpen] = useState(false); + + const handleFileChange = (file) => { + console.log(file); + if (file) { + setFile(file); + } + }; + + const formik = useFormik({ + initialValues: { + name: '', + server_url: '', + user_agent: '', + is_active: true, + max_streams: 0, + }, + validationSchema: Yup.object({ + name: Yup.string().required('Name is required'), + user_agent: Yup.string().required('User-Agent is required'), + max_streams: Yup.string().required('Max streams is required'), + }), + onSubmit: async (values, { setSubmitting, resetForm }) => { + if (playlist?.id) { + await API.updatePlaylist({ + id: playlist.id, + ...values, + uploaded_file: file, + }); + } else { + await API.addPlaylist({ + ...values, + uploaded_file: file, + }); + } + + resetForm(); + setFile(null); + setSubmitting(false); + onClose(); + }, + }); + + useEffect(() => { + if (playlist) { + formik.setValues({ + name: playlist.name, + server_url: playlist.server_url, + max_streams: playlist.max_streams, + user_agent: playlist.user_agent, + is_active: playlist.is_active, + }); + } else { + formik.resetForm(); + } + }, [playlist]); + + if (!isOpen) { + return <>; + } + + console.log(formik.values); + + return ( + +
+ + +
+ + + + + + + + + ({ + label: ua.user_agent_name, + value: `${ua.id}`, + }))} + /> + + + + + formik.setFieldValue('is_active', e.target.checked) + } + /> + + + + + + + {playlist && ( + setProfileModalOpen(false)} + /> + )} + +
+
+ ); +}; + +export default M3U; diff --git a/vite/src/components/forms/M3UProfile.jsx b/vite/src/components/forms/M3UProfile.jsx new file mode 100644 index 00000000..d01bbd5e --- /dev/null +++ b/vite/src/components/forms/M3UProfile.jsx @@ -0,0 +1,158 @@ +import React, { useState, useEffect } from 'react'; +import { useFormik } from 'formik'; +import * as Yup from 'yup'; +import API from '../../api'; +import { + Flex, + Modal, + TextInput, + Button, + Title, + Text, + Paper, +} from '@mantine/core'; + +const RegexFormAndView = ({ profile = null, m3u, isOpen, onClose }) => { + const [searchPattern, setSearchPattern] = useState(''); + const [replacePattern, setReplacePattern] = useState(''); + + let regex; + try { + regex = new RegExp(searchPattern, 'g'); + } catch (e) { + regex = null; + } + + const highlightedUrl = regex + ? m3u.server_url.replace(regex, (match) => `${match}`) + : m3u.server_url; + + const resultUrl = + regex && replacePattern + ? m3u.server_url.replace(regex, replacePattern) + : m3u.server_url; + + const onSearchPatternUpdate = (e) => { + formik.handleChange(e); + setSearchPattern(e.target.value); + }; + + const onReplacePatternUpdate = (e) => { + formik.handleChange(e); + setReplacePattern(e.target.value); + }; + + const formik = useFormik({ + initialValues: { + name: '', + max_streams: 0, + search_pattern: '', + replace_pattern: '', + }, + validationSchema: Yup.object({ + name: Yup.string().required('Name is required'), + search_pattern: Yup.string().required('Search pattern is required'), + replace_pattern: Yup.string().required('Replace pattern is required'), + }), + onSubmit: async (values, { setSubmitting, resetForm }) => { + console.log('submiting'); + if (profile?.id) { + await API.updateM3UProfile(m3u.id, { + id: profile.id, + ...values, + }); + } else { + await API.addM3UProfile(m3u.id, values); + } + + resetForm(); + setSubmitting(false); + onClose(); + }, + }); + + useEffect(() => { + if (profile) { + setSearchPattern(profile.search_pattern); + setReplacePattern(profile.replace_pattern); + formik.setValues({ + name: profile.name, + max_streams: profile.max_streams, + search_pattern: profile.search_pattern, + replace_pattern: profile.replace_pattern, + }); + } else { + formik.resetForm(); + } + }, [profile]); + + return ( + +
+ + + + + + + + + + + + Search + + + + + Replace + {resultUrl} + +
+ ); +}; + +export default RegexFormAndView; diff --git a/vite/src/components/forms/M3UProfiles.jsx b/vite/src/components/forms/M3UProfiles.jsx new file mode 100644 index 00000000..7579db4f --- /dev/null +++ b/vite/src/components/forms/M3UProfiles.jsx @@ -0,0 +1,107 @@ +import React, { useState, useMemo } from 'react'; +import API from '../../api'; +import M3UProfile from './M3UProfile'; +import { Delete as DeleteIcon, Edit as EditIcon } from '@mui/icons-material'; +import usePlaylistsStore from '../../store/playlists'; +import { + Card, + Checkbox, + Flex, + Modal, + Button, + Box, + ActionIcon, + Text, +} from '@mantine/core'; + +const M3UProfiles = ({ playlist = null, isOpen, onClose }) => { + const profiles = usePlaylistsStore((state) => state.profiles[playlist.id]); + const [profileEditorOpen, setProfileEditorOpen] = useState(false); + const [profile, setProfile] = useState(null); + + const editProfile = (profile = null) => { + if (profile) { + setProfile(profile); + } + + setProfileEditorOpen(true); + }; + + const deleteProfile = async (id) => { + await API.deleteM3UProfile(playlist.id, id); + }; + + const toggleActive = async (values) => { + await API.updateM3UProfile(playlist.id, { + ...values, + is_active: !values.is_active, + }); + }; + + const closeEditor = () => { + setProfile(null); + setProfileEditorOpen(false); + }; + + if (!isOpen || !profiles) { + return <>; + } + + return ( + <> + + {profiles + .filter((playlist) => playlist.is_default == false) + .map((item) => ( + + + Max Streams: {item.max_streams} + toggleActive(item)} + color="primary" + /> + editProfile(item)} color="yellow.5"> + + + deleteProfile(item.id)} + color="error" + > + + + + + ))} + + + + + + + + + ); +}; + +export default M3UProfiles; diff --git a/vite/src/components/forms/Stream.jsx b/vite/src/components/forms/Stream.jsx new file mode 100644 index 00000000..456797ec --- /dev/null +++ b/vite/src/components/forms/Stream.jsx @@ -0,0 +1,103 @@ +// Modal.js +import React, { useEffect } from 'react'; +import { useFormik } from 'formik'; +import * as Yup from 'yup'; +import API from '../../api'; +import useStreamProfilesStore from '../../store/streamProfiles'; +import { TextInput, Select, Button } from '@mantine/core'; + +const Stream = ({ stream = null, isOpen, onClose }) => { + const streamProfiles = useStreamProfilesStore((state) => state.profiles); + + const formik = useFormik({ + initialValues: { + name: '', + url: '', + stream_profile_id: '', + }, + validationSchema: Yup.object({ + name: Yup.string().required('Name is required'), + url: Yup.string().required('URL is required').min(0), + // stream_profile_id: Yup.string().required('Stream profile is required'), + }), + onSubmit: async (values, { setSubmitting, resetForm }) => { + if (stream?.id) { + await API.updateStream({ id: stream.id, ...values }); + } else { + await API.addStream(values); + } + + resetForm(); + setSubmitting(false); + onClose(); + }, + }); + + useEffect(() => { + if (stream) { + formik.setValues({ + name: stream.name, + url: stream.url, + stream_profile_id: stream.stream_profile_id, + }); + } else { + formik.resetForm(); + } + }, [stream]); + + if (!isOpen) { + return <>; + } + + return ( + +
+ + + + + ({ + label: ua.user_agent_name, + value: `${ua.id}`, + }))} + /> + + + +
+ ); +}; + +export default StreamProfile; diff --git a/vite/src/components/forms/SuperuserForm.jsx b/vite/src/components/forms/SuperuserForm.jsx new file mode 100644 index 00000000..32eb5e14 --- /dev/null +++ b/vite/src/components/forms/SuperuserForm.jsx @@ -0,0 +1,128 @@ +// frontend/src/components/forms/SuperuserForm.js +import React, { useState } from 'react'; +import axios from 'axios'; +import { + Box, + Paper, + Typography, + Grid2, + TextField, + Button, +} from '@mui/material'; + +function SuperuserForm({ onSuccess }) { + const [formData, setFormData] = useState({ + username: '', + password: '', + email: '', + }); + const [error, setError] = useState(''); + + const handleChange = (e) => { + setFormData((prev) => ({ + ...prev, + [e.target.name]: e.target.value, + })); + }; + + const handleSubmit = async (e) => { + e.preventDefault(); + try { + const res = await axios.post('/api/accounts/initialize-superuser/', { + username: formData.username, + password: formData.password, + email: formData.email, + }); + if (res.data.superuser_exists) { + onSuccess(); + } + } catch (err) { + let msg = 'Failed to create superuser.'; + if (err.response && err.response.data && err.response.data.error) { + msg += ` ${err.response.data.error}`; + } + setError(msg); + } + }; + + return ( + + + + Create your Super User Account + + {error && ( + + {error} + + )} +
+ + + + + + + + + + + + + + +
+
+
+ ); +} + +export default SuperuserForm; diff --git a/vite/src/components/forms/UserAgent.jsx b/vite/src/components/forms/UserAgent.jsx new file mode 100644 index 00000000..a5644b75 --- /dev/null +++ b/vite/src/components/forms/UserAgent.jsx @@ -0,0 +1,119 @@ +// Modal.js +import React, { useEffect } from 'react'; +import { useFormik } from 'formik'; +import * as Yup from 'yup'; +import API from '../../api'; +import { + LoadingOverlay, + TextInput, + Button, + Checkbox, + Modal, + Flex, + NativeSelect, + FileInput, + Space, +} from '@mantine/core'; + +const UserAgent = ({ userAgent = null, isOpen, onClose }) => { + const formik = useFormik({ + initialValues: { + user_agent_name: '', + user_agent: '', + description: '', + is_active: true, + }, + validationSchema: Yup.object({ + user_agent_name: Yup.string().required('Name is required'), + user_agent: Yup.string().required('User-Agent is required'), + }), + onSubmit: async (values, { setSubmitting, resetForm }) => { + if (userAgent?.id) { + await API.updateUserAgent({ id: userAgent.id, ...values }); + } else { + await API.addUserAgent(values); + } + + resetForm(); + setSubmitting(false); + onClose(); + }, + }); + + useEffect(() => { + if (userAgent) { + formik.setValues({ + user_agent_name: userAgent.user_agent_name, + user_agent: userAgent.user_agent, + description: userAgent.description, + is_active: userAgent.is_active, + }); + } else { + formik.resetForm(); + } + }, [userAgent]); + + if (!isOpen) { + return <>; + } + + return ( + +
+ + + + + + + + + + + + + + +
+ ); +}; + +export default UserAgent; diff --git a/vite/src/components/tables/ChannelsTable.jsx b/vite/src/components/tables/ChannelsTable.jsx new file mode 100644 index 00000000..9a89c36c --- /dev/null +++ b/vite/src/components/tables/ChannelsTable.jsx @@ -0,0 +1,1005 @@ +import { useEffect, useMemo, useRef, useState, useCallback } from 'react'; +import { MantineReactTable, useMantineReactTable } from 'mantine-react-table'; +import useChannelsStore from '../../store/channels'; +import useAlertStore from '../../store/alerts'; +import { + Add as AddIcon, + LiveTv as LiveTvIcon, + ContentCopy, + IndeterminateCheckBox, + CompareArrows, + Code, + AddBox, +} from '@mui/icons-material'; +import API from '../../api'; +import ChannelForm from '../forms/Channel'; +import { TableHelper } from '../../helpers'; +import utils from '../../utils'; +import logo from '../../images/logo.png'; +import useVideoStore from '../../store/useVideoStore'; +import useSettingsStore from '../../store/settings'; +import usePlaylistsStore from '../../store/playlists'; +import { + Tv2, + ScreenShare, + Scroll, + SquareMinus, + Pencil, + ArrowUp, + ArrowDown, + ArrowUpDown, + TvMinimalPlay, +} from 'lucide-react'; +import ghostImage from '../../images/ghost.svg'; +import { + Box, + TextInput, + Popover, + ActionIcon, + Select, + Button, + Paper, + Flex, + Center, + Text, + Tooltip, + Grid, + Group, + useMantineTheme, + UnstyledButton, +} from '@mantine/core'; +import { + IconArrowDown, + IconArrowUp, + IconDeviceDesktopSearch, + IconSelector, + IconSortAscendingNumbers, + IconSquarePlus, +} from '@tabler/icons-react'; // Import custom icons + +const ChannelStreams = ({ channel, isExpanded }) => { + const channelStreams = useChannelsStore( + (state) => state.channels[channel.id]?.streams + ); + const { playlists } = usePlaylistsStore(); + + const removeStream = async (stream) => { + const newStreamList = channelStreams.filter((s) => s.id !== stream.id); + await API.updateChannel({ + ...channel, + stream_ids: newStreamList.map((s) => s.id), + }); + }; + + const channelStreamsTable = useMantineReactTable({ + ...TableHelper.defaultProperties, + data: channelStreams, + columns: useMemo( + () => [ + { + header: 'Name', + accessorKey: 'name', + }, + { + header: 'M3U', + accessorFn: (row) => + playlists.find((playlist) => playlist.id === row.m3u_account)?.name, + }, + ], + [playlists] + ), + enableKeyboardShortcuts: false, + enableColumnFilters: false, + enableBottomToolbar: false, + enableTopToolbar: false, + columnFilterDisplayMode: 'popover', + enablePagination: false, + enableRowVirtualization: true, + enableColumnHeaders: false, + rowVirtualizerOptions: { overscan: 5 }, //optionally customize the row virtualizer + initialState: { + density: 'compact', + }, + enableRowActions: true, + enableRowOrdering: true, + mantineRowDragHandleProps: ({ table }) => ({ + onDragEnd: async () => { + const { draggingRow, hoveredRow } = table.getState(); + + if (hoveredRow && draggingRow) { + channelStreams.splice( + hoveredRow.index, + 0, + channelStreams.splice(draggingRow.index, 1)[0] + ); + + const { streams: _, ...channelUpdate } = channel; + + API.updateChannel({ + ...channelUpdate, + stream_ids: channelStreams.map((stream) => stream.id), + }); + } + }, + }), + renderRowActions: ({ row }) => ( + + removeStream(row.original)} + > + + + + ), + }); + + if (!isExpanded) { + return <>; + } + + return ( + + + + ); +}; + +// /* ----------------------------------------------------------- +// 2) Custom-styled "chip" buttons for HDHR, M3U, EPG +// ------------------------------------------------------------ */ +// const HDHRButton = styled(Button)(() => ({ +// border: '1px solid #a3d977', +// color: '#a3d977', +// backgroundColor: 'transparent', +// textTransform: 'none', +// fontSize: '0.85rem', +// display: 'flex', +// alignItems: 'center', +// gap: '4px', +// padding: '2px 8px', +// minWidth: 'auto', +// '&:hover': { +// borderColor: '#c2e583', +// color: '#c2e583', +// backgroundColor: 'rgba(163,217,119,0.1)', +// }, +// })); + +// const M3UButton = styled(Button)(() => ({ +// border: '1px solid #5f6dc6', +// color: '#5f6dc6', +// backgroundColor: 'transparent', +// textTransform: 'none', +// fontSize: '0.85rem', +// display: 'flex', +// alignItems: 'center', +// gap: '4px', +// padding: '2px 8px', +// minWidth: 'auto', +// '&:hover': { +// borderColor: '#7f8de6', +// color: '#7f8de6', +// backgroundColor: 'rgba(95,109,198,0.1)', +// }, +// })); + +// const EPGButton = styled(Button)(() => ({ +// border: '1px solid #707070', +// color: '#a0a0a0', +// backgroundColor: 'transparent', +// textTransform: 'none', +// fontSize: '0.85rem', +// display: 'flex', +// alignItems: 'center', +// gap: '4px', +// padding: '2px 8px', +// minWidth: 'auto', +// '&:hover': { +// borderColor: '#a0a0a0', +// color: '#c0c0c0', +// backgroundColor: 'rgba(112,112,112,0.1)', +// }, +// })); + +const ChannelsTable = ({}) => { + const [channel, setChannel] = useState(null); + const [channelModalOpen, setChannelModalOpen] = useState(false); + const [rowSelection, setRowSelection] = useState([]); + const [channelGroupOptions, setChannelGroupOptions] = useState([]); + + const [anchorEl, setAnchorEl] = useState(null); + const [textToCopy, setTextToCopy] = useState(''); + + const [filterValues, setFilterValues] = useState({}); + + // const theme = useTheme(); + const theme = useMantineTheme(); + + const { showVideo } = useVideoStore(); + const { + channels, + isLoading: channelsLoading, + fetchChannels, + setChannelsPageSelection, + } = useChannelsStore(); + const { showAlert } = useAlertStore(); + + useEffect(() => { + setChannelGroupOptions([ + ...new Set( + Object.values(channels).map((channel) => channel.channel_group?.name) + ), + ]); + }, [channels]); + + const handleFilterChange = (columnId, value) => { + console.log(columnId); + console.log(value); + setFilterValues((prev) => ({ + ...prev, + [columnId]: value ? value.toLowerCase() : '', + })); + }; + + const outputUrlRef = useRef(null); + + const { + environment: { env_mode }, + } = useSettingsStore(); + + // Configure columns + const columns = useMemo( + () => [ + { + header: '#', + size: 50, + accessorKey: 'channel_number', + }, + { + header: 'Name', + accessorKey: 'channel_name', + muiTableHeadCellProps: { + sx: { textAlign: 'center' }, + }, + Header: ({ column }) => ( + handleFilterChange(column.id, e.target.value)} + size="xs" + /> + ), + meta: { + filterVariant: null, + }, + }, + { + header: 'Group', + accessorFn: (row) => row.channel_group?.name || '', + Header: ({ column }) => ( + { + setActiveFilterValue(e.target.value); + column.setFilterValue(e.target.value); + }} + displayEmpty + fullWidth + > + All + Active + Inactive + + + ), + filterFn: (row, _columnId, activeFilterValue) => { + if (!activeFilterValue) return true; // Show all if no filter + return String(row.getValue('is_active')) === activeFilterValue; + }, + }, + ], + [] + ); + + //optionally access the underlying virtualizer instance + const rowVirtualizerInstanceRef = useRef(null); + + const [isLoading, setIsLoading] = useState(true); + const [sorting, setSorting] = useState([]); + + const editPlaylist = async (playlist = null) => { + if (playlist) { + setPlaylist(playlist); + } + setPlaylistModalOpen(true); + }; + + const refreshPlaylist = async (id) => { + await API.refreshPlaylist(id); + }; + + const deletePlaylist = async (id) => { + await API.deletePlaylist(id); + }; + + const closeModal = () => { + setPlaylistModalOpen(false); + setPlaylist(null); + }; + + const deletePlaylists = async (ids) => { + const selected = table + .getRowModel() + .rows.filter((row) => row.getIsSelected()); + // await API.deleteStreams(selected.map(stream => stream.original.id)) + }; + + useEffect(() => { + if (typeof window !== 'undefined') { + setIsLoading(false); + } + }, []); + + useEffect(() => { + //scroll to the top of the table when the sorting changes + try { + rowVirtualizerInstanceRef.current?.scrollToIndex?.(0); + } catch (error) { + console.error(error); + } + }, [sorting]); + + const table = useMaterialReactTable({ + ...TableHelper.defaultProperties, + columns, + data: playlists, + enablePagination: false, + enableRowVirtualization: true, + // enableRowSelection: true, + onRowSelectionChange: setRowSelection, + onSortingChange: setSorting, + state: { + isLoading, + sorting, + rowSelection, + }, + rowVirtualizerInstanceRef, //optional + rowVirtualizerOptions: { overscan: 5 }, //optionally customize the row virtualizer + initialState: { + density: 'compact', + }, + enableRowActions: true, + renderRowActions: ({ row }) => ( + <> + { + editPlaylist(row.original); + }} + sx={{ pt: 0, pb: 0 }} + > + {/* Small icon size */} + + deletePlaylist(row.original.id)} + sx={{ pt: 0, pb: 0 }} + > + {/* Small icon size */} + + refreshPlaylist(row.original.id)} + sx={{ pt: 0, pb: 0 }} + > + {/* Small icon size */} + + + ), + muiTableContainerProps: { + sx: { + height: 'calc(43vh - 0px)', + pr: 1, + pl: 1, + }, + }, + renderTopToolbarCustomActions: ({ table }) => ( + + M3U Accounts + + editPlaylist()} + > + {/* Small icon size */} + + + + ), + }); + + return ( + + + + + ); +}; + +export default Example; diff --git a/vite/src/components/tables/StreamProfilesTable.jsx b/vite/src/components/tables/StreamProfilesTable.jsx new file mode 100644 index 00000000..b2ac3390 --- /dev/null +++ b/vite/src/components/tables/StreamProfilesTable.jsx @@ -0,0 +1,202 @@ +import { useEffect, useMemo, useRef, useState } from 'react'; +import { MantineReactTable, useMantineReactTable } from 'mantine-react-table'; +import API from '../../api'; +import { + Delete as DeleteIcon, + Edit as EditIcon, + Add as AddIcon, + Check as CheckIcon, + Close as CloseIcon, +} from '@mui/icons-material'; +import StreamProfileForm from '../forms/StreamProfile'; +import useStreamProfilesStore from '../../store/streamProfiles'; +import { TableHelper } from '../../helpers'; +import useSettingsStore from '../../store/settings'; +import useAlertStore from '../../store/alerts'; +import { Box, ActionIcon, Tooltip, Text } from '@mantine/core'; + +const StreamProfiles = () => { + const [profile, setProfile] = useState(null); + const [profileModalOpen, setProfileModalOpen] = useState(false); + const [rowSelection, setRowSelection] = useState([]); + const [activeFilterValue, setActiveFilterValue] = useState('all'); + + const streamProfiles = useStreamProfilesStore((state) => state.profiles); + const { settings } = useSettingsStore(); + const { showAlert } = useAlertStore(); + + const columns = useMemo( + //column definitions... + () => [ + { + header: 'Name', + accessorKey: 'profile_name', + }, + { + header: 'Command', + accessorKey: 'command', + }, + { + header: 'Parameters', + accessorKey: 'parameters', + }, + { + header: 'Active', + accessorKey: 'is_active', + size: 100, + sortingFn: 'basic', + muiTableBodyCellProps: { + align: 'left', + }, + Cell: ({ cell }) => ( + + {cell.getValue() ? ( + + ) : ( + + )} + + ), + Filter: ({ column }) => ( + + e.stopPropagation()} + onChange={handleGroupChange} + data={groupOptions} + /> + ), + Cell: ({ cell }) => ( +
+ {cell.getValue()} +
+ ), + }, + { + header: 'M3U', + size: 75, + accessorFn: (row) => + playlists.find((playlist) => playlist.id === row.m3u_account)?.name, + Header: ({ column }) => ( + { + setActiveFilterValue(e.target.value); + column.setFilterValue(e.target.value); + }} + displayEmpty + data={[ + { + value: 'all', + label: 'All', + }, + { + value: 'active', + label: 'Active', + }, + { + value: 'inactive', + label: 'Inactive', + }, + ]} + /> + ), + filterFn: (row, _columnId, activeFilterValue) => { + if (activeFilterValue == 'all') return true; // Show all if no filter + return String(row.getValue('is_active')) === activeFilterValue; + }, + }, + ], + [] + ); + + //optionally access the underlying virtualizer instance + const rowVirtualizerInstanceRef = useRef(null); + + const [isLoading, setIsLoading] = useState(true); + const [sorting, setSorting] = useState([]); + + const editUserAgent = async (userAgent = null) => { + setUserAgent(userAgent); + setUserAgentModalOpen(true); + }; + + const deleteUserAgent = async (ids) => { + if (Array.isArray(ids)) { + if (ids.includes(settings['default-user-agent'].value)) { + showAlert('Cannot delete default user-agent', 'error'); + return; + } + + await API.deleteUserAgents(ids); + } else { + if (ids == settings['default-user-agent'].value) { + showAlert('Cannot delete default user-agent', 'error'); + return; + } + + await API.deleteUserAgent(ids); + } + }; + + const closeUserAgentForm = () => { + setUserAgent(null); + setUserAgentModalOpen(false); + }; + + useEffect(() => { + if (typeof window !== 'undefined') { + setIsLoading(false); + } + }, []); + + useEffect(() => { + //scroll to the top of the table when the sorting changes + try { + rowVirtualizerInstanceRef.current?.scrollToIndex?.(0); + } catch (error) { + console.error(error); + } + }, [sorting]); + + const table = useMantineReactTable({ + ...TableHelper.defaultProperties, + columns, + data: userAgents, + enablePagination: false, + enableRowVirtualization: true, + enableRowSelection: true, + onRowSelectionChange: setRowSelection, + onSortingChange: setSorting, + state: { + isLoading, + sorting, + rowSelection, + }, + rowVirtualizerInstanceRef, //optional + rowVirtualizerOptions: { overscan: 5 }, //optionally customize the row virtualizer + initialState: { + density: 'compact', + }, + enableRowActions: true, + renderRowActions: ({ row }) => ( + <> + { + editUserAgent(row.original); + }} + > + {/* Small icon size */} + + deleteUserAgent(row.original.id)} + > + {/* Small icon size */} + + + ), + muiTableContainerProps: { + sx: { + height: 'calc(42vh + 5px)', + }, + }, + renderTopToolbarCustomActions: ({ table }) => ( + + User-Agents + + editUserAgent()} + > + {/* Small icon size */} + + + + ), + }); + + return ( + <> + + + + ); +}; + +export default UserAgentsTable; diff --git a/vite/src/helpers/index.jsx b/vite/src/helpers/index.jsx new file mode 100644 index 00000000..7ec0abb7 --- /dev/null +++ b/vite/src/helpers/index.jsx @@ -0,0 +1,3 @@ +import table from "./table"; + +export const TableHelper = table; diff --git a/vite/src/helpers/table.jsx b/vite/src/helpers/table.jsx new file mode 100644 index 00000000..f8ebe8ab --- /dev/null +++ b/vite/src/helpers/table.jsx @@ -0,0 +1,61 @@ +// frontend/src/helpers/table.js + +export default { + defaultProperties: { + enableBottomToolbar: false, + enableDensityToggle: false, + enableFullScreenToggle: false, + positionToolbarAlertBanner: 'none', + // columnFilterDisplayMode: 'popover', + enableRowNumbers: false, + positionActionsColumn: 'last', + enableColumnActions: false, + enableColumnFilters: false, + enableGlobalFilter: false, + initialState: { + density: 'compact', + }, + mantineSelectAllCheckboxProps: { + size: 'xs', + }, + mantineSelectCheckboxProps: { + size: 'xs', + }, + mantineTableBodyCellProps: { + style: { + // py: 0, + paddingLeft: 10, + paddingRight: 10, + borderColor: '#444', + color: '#E0E0E0', + fontSize: '0.85rem', + }, + }, + mantineTableHeadCellProps: { + style: { + paddingLeft: 10, + paddingRight: 10, + color: '#CFCFCF', + backgroundColor: '#383A3F', + borderColor: '#444', + // fontWeight: 600, + // fontSize: '0.8rem', + }, + }, + mantineTableBodyProps: { + style: { + // Subtle row striping + '& tr:nth-of-type(odd)': { + backgroundColor: '#2F3034', + }, + '& tr:nth-of-type(even)': { + backgroundColor: '#333539', + }, + // Row hover effect + '& tr:hover td': { + backgroundColor: '#3B3D41', + }, + }, + }, + }, +}; diff --git a/vite/src/images/dispatcharr.svg b/vite/src/images/dispatcharr.svg new file mode 100644 index 00000000..3ddd8e2b --- /dev/null +++ b/vite/src/images/dispatcharr.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vite/src/images/ghost.svg b/vite/src/images/ghost.svg new file mode 100644 index 00000000..2206100d --- /dev/null +++ b/vite/src/images/ghost.svg @@ -0,0 +1,66 @@ + + + + + + + + + + + diff --git a/vite/src/images/logo.png b/vite/src/images/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..99c3c19f3d6ba0647c2883654126d5ea8b529020 GIT binary patch literal 44564 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 \ No newline at end of file diff --git a/vite/src/main.jsx b/vite/src/main.jsx new file mode 100644 index 00000000..2a7b83c0 --- /dev/null +++ b/vite/src/main.jsx @@ -0,0 +1,9 @@ +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import App from './App'; + +ReactDOM.createRoot(document.getElementById('root')).render( + + + +); diff --git a/vite/src/mantineTheme.jsx b/vite/src/mantineTheme.jsx new file mode 100644 index 00000000..e89455d8 --- /dev/null +++ b/vite/src/mantineTheme.jsx @@ -0,0 +1,58 @@ +import { createTheme, MantineProvider, rem } from '@mantine/core'; + +const theme = createTheme({ + palette: { + mode: 'dark', + background: { + default: '#18181b', // Global background color (Tailwind zinc-900) + paper: '#27272a', // Paper background (Tailwind zinc-800) + }, + primary: { + main: '#4A90E2', + contrastText: '#FFFFFF', + }, + secondary: { + main: '#F5A623', + contrastText: '#FFFFFF', + }, + text: { + primary: '#FFFFFF', + secondary: '#d4d4d8', // Updated secondary text color (Tailwind zinc-300) + }, + // Custom colors for components (chip buttons, borders, etc.) + custom: { + // For chip buttons: + greenMain: '#90C43E', + greenHoverBg: 'rgba(144,196,62,0.1)', + + indigoMain: '#4F39F6', + indigoHoverBg: 'rgba(79,57,246,0.1)', + + greyBorder: '#707070', + greyHoverBg: 'rgba(112,112,112,0.1)', + greyText: '#a0a0a0', + + // Common border colors: + borderDefault: '#3f3f46', // Tailwind zinc-700 + borderHover: '#5f5f66', // Approximate Tailwind zinc-600 + + // For the "Add" button: + successBorder: '#00a63e', + successBg: '#0d542b', + successBgHover: '#0a4020', + successIcon: '#05DF72', + }, + }, + + custom: { + sidebar: { + activeBackground: 'rgba(21, 69, 62, 0.67)', + activeBorder: '#14917e', + hoverBackground: '#27272a', + hoverBorder: '#3f3f46', + fontFamily: 'Inter, sans-serif', + }, + }, +}); + +export default theme; diff --git a/vite/src/pages/Channels.jsx b/vite/src/pages/Channels.jsx new file mode 100644 index 00000000..4899c4fb --- /dev/null +++ b/vite/src/pages/Channels.jsx @@ -0,0 +1,43 @@ +import React, { useState } from 'react'; +import ChannelsTable from '../components/tables/ChannelsTable'; +import StreamsTable from '../components/tables/StreamsTable'; +import { Box, Grid } from '@mantine/core'; + +const ChannelsPage = () => { + return ( + + + + + + + + + + + + + ); +}; + +export default ChannelsPage; diff --git a/vite/src/pages/Dashboard.jsx b/vite/src/pages/Dashboard.jsx new file mode 100644 index 00000000..af2104e1 --- /dev/null +++ b/vite/src/pages/Dashboard.jsx @@ -0,0 +1,27 @@ +// src/components/Dashboard.js +import React, { useState } from "react"; + +const Dashboard = () => { + const [newStream, setNewStream] = useState(""); + + return ( +
+

Dashboard Page

+ setNewStream(e.target.value)} + placeholder="Enter Stream" + /> + +

Streams:

+
    + {state.streams.map((stream, index) => ( +
  • {stream}
  • + ))} +
+
+ ); +}; + +export default Dashboard; diff --git a/vite/src/pages/EPG.jsx b/vite/src/pages/EPG.jsx new file mode 100644 index 00000000..f8b9a7f4 --- /dev/null +++ b/vite/src/pages/EPG.jsx @@ -0,0 +1,27 @@ +import React from 'react'; +import { Box } from '@mantine/core'; +import UserAgentsTable from '../components/tables/UserAgentsTable'; +import EPGsTable from '../components/tables/EPGsTable'; + +const EPGPage = () => { + return ( + + + + + + + + + + ); +}; + +export default EPGPage; diff --git a/vite/src/pages/Guide.jsx b/vite/src/pages/Guide.jsx new file mode 100644 index 00000000..d60ec8ba --- /dev/null +++ b/vite/src/pages/Guide.jsx @@ -0,0 +1,532 @@ +// frontend/src/pages/Guide.js +import React, { useMemo, useState, useEffect, useRef } from 'react'; +import { + Box, + Typography, + Paper, + Stack, + Dialog, + DialogTitle, + DialogContent, + DialogActions, + Button, + Slide, + CircularProgress, + Backdrop, +} from '@mui/material'; +import dayjs from 'dayjs'; +import API from '../api'; +import useChannelsStore from '../store/channels'; +import logo from '../images/logo.png'; +import useVideoStore from '../store/useVideoStore'; // NEW import +import useAlertStore from '../store/alerts'; +import useSettingsStore from '../store/settings'; + +/** Layout constants */ +const CHANNEL_WIDTH = 120; // Width of the channel/logo column +const PROGRAM_HEIGHT = 90; // Height of each channel row +const HOUR_WIDTH = 300; // The width for a 1-hour block +const MINUTE_INCREMENT = 15; // For positioning programs every 15 min +const MINUTE_BLOCK_WIDTH = HOUR_WIDTH / (60 / MINUTE_INCREMENT); + +// Modal size constants +const MODAL_WIDTH = 600; +const MODAL_HEIGHT = 400; + +// Slide transition for Dialog +const Transition = React.forwardRef(function Transition(props, ref) { + return ; +}); + +export default function TVChannelGuide({ startDate, endDate }) { + const { channels } = useChannelsStore(); + + const [programs, setPrograms] = useState([]); + const [guideChannels, setGuideChannels] = useState([]); + const [now, setNow] = useState(dayjs()); + const [selectedProgram, setSelectedProgram] = useState(null); + const [loading, setLoading] = useState(true); + const { showAlert } = useAlertStore(); + const { + environment: { env_mode }, + } = useSettingsStore(); + + const guideRef = useRef(null); + + // Load program data once + useEffect(() => { + if (!channels || channels.length === 0) { + console.warn('No channels provided or empty channels array'); + showAlert('No channels available', 'error'); + setLoading(false); + return; + } + + const fetchPrograms = async () => { + console.log('Fetching program grid...'); + const fetched = await API.getGrid(); // GETs your EPG grid + console.log(`Received ${fetched.length} programs`); + + // Unique tvg_ids from returned programs + const programIds = [...new Set(fetched.map((p) => p.tvg_id))]; + + // Filter your Redux/Zustand channels by matching tvg_id + const filteredChannels = channels.filter((ch) => + programIds.includes(ch.tvg_id) + ); + console.log( + `found ${filteredChannels.length} channels with matching tvg_ids` + ); + + setGuideChannels(filteredChannels); + setPrograms(fetched); + setLoading(false); + }; + + fetchPrograms(); + }, [channels]); + + // Use start/end from props or default to "today at midnight" +24h + const defaultStart = dayjs(startDate || dayjs().startOf('day')); + const defaultEnd = endDate ? dayjs(endDate) : defaultStart.add(24, 'hour'); + + // Expand timeline if needed based on actual earliest/ latest program + const earliestProgramStart = useMemo(() => { + if (!programs.length) return defaultStart; + return programs.reduce((acc, p) => { + const s = dayjs(p.start_time); + return s.isBefore(acc) ? s : acc; + }, defaultStart); + }, [programs, defaultStart]); + + const latestProgramEnd = useMemo(() => { + if (!programs.length) return defaultEnd; + return programs.reduce((acc, p) => { + const e = dayjs(p.end_time); + return e.isAfter(acc) ? e : acc; + }, defaultEnd); + }, [programs, defaultEnd]); + + const start = earliestProgramStart.isBefore(defaultStart) + ? earliestProgramStart + : defaultStart; + const end = latestProgramEnd.isAfter(defaultEnd) + ? latestProgramEnd + : defaultEnd; + + // Time increments in 15-min steps (for placing programs) + const programTimeline = useMemo(() => { + const times = []; + let current = start; + while (current.isBefore(end)) { + times.push(current); + current = current.add(MINUTE_INCREMENT, 'minute'); + } + return times; + }, [start, end]); + + // Hourly marks + const hourTimeline = useMemo(() => { + const hours = []; + let current = start; + while (current.isBefore(end)) { + hours.push(current); + current = current.add(1, 'hour'); + } + return hours; + }, [start, end]); + + // Scroll to "now" on load + useEffect(() => { + if (guideRef.current) { + const nowOffset = dayjs().diff(start, 'minute'); + const scrollPosition = + (nowOffset / MINUTE_INCREMENT) * MINUTE_BLOCK_WIDTH - + MINUTE_BLOCK_WIDTH; + guideRef.current.scrollLeft = Math.max(scrollPosition, 0); + } + }, [programs, start]); + + // Update “now” every 60s + useEffect(() => { + const interval = setInterval(() => { + setNow(dayjs()); + }, 60000); + return () => clearInterval(interval); + }, []); + + // Pixel offset for the “now” vertical line + const nowPosition = useMemo(() => { + if (now.isBefore(start) || now.isAfter(end)) return -1; + const minutesSinceStart = now.diff(start, 'minute'); + return (minutesSinceStart / MINUTE_INCREMENT) * MINUTE_BLOCK_WIDTH; + }, [now, start, end]); + + // Helper: find channel by tvg_id + function findChannelByTvgId(tvgId) { + return guideChannels.find((ch) => ch.tvg_id === tvgId); + } + + // The “Watch Now” click => show floating video + const { showVideo } = useVideoStore(); // or useVideoStore() + function handleWatchStream(program) { + const matched = findChannelByTvgId(program.tvg_id); + if (!matched) { + console.warn(`No channel found for tvg_id=${program.tvg_id}`); + return; + } + // Build a playable stream URL for that channel + let vidUrl = `/output/stream/${matched.channel_number}/`; + if (env_mode == 'dev') { + vidUrl = `${window.location.protocol}//${window.location.hostname}:5656${vidUrl}`; + } + + showVideo(vidUrl); + + // Optionally close the modal + setSelectedProgram(null); + } + + // On program click, open the details modal + function handleProgramClick(program, event) { + // Optionally scroll that element into view or do something else + event.currentTarget.scrollIntoView({ + behavior: 'smooth', + inline: 'center', + }); + setSelectedProgram(program); + } + + // Close the modal + function handleCloseModal() { + setSelectedProgram(null); + } + + // Renders each program block + function renderProgram(program, channelStart) { + const programKey = `${program.tvg_id}-${program.start_time}`; + const programStart = dayjs(program.start_time); + const programEnd = dayjs(program.end_time); + const startOffsetMinutes = programStart.diff(channelStart, 'minute'); + const durationMinutes = programEnd.diff(programStart, 'minute'); + const leftPx = (startOffsetMinutes / MINUTE_INCREMENT) * MINUTE_BLOCK_WIDTH; + const widthPx = (durationMinutes / MINUTE_INCREMENT) * MINUTE_BLOCK_WIDTH; + + // Highlight if currently live + const isLive = now.isAfter(programStart) && now.isBefore(programEnd); + + return ( + handleProgramClick(program, e)} + > + + + {program.title} + + + {programStart.format('h:mma')} - {programEnd.format('h:mma')} + + + + ); + } + + if (loading) { + return ( + theme.zIndex.drawer + 1, + position: 'fixed', // Ensure it covers the entire page + top: 0, + left: 0, + right: 0, + bottom: 0, + }} + open={loading} + > + + + ); + } + + return ( + + {/* Sticky top bar */} + + + TV Guide + + + {now.format('dddd, MMMM D, YYYY • h:mm A')} + + + + {/* Main layout */} + + {/* Channel Logos Column */} + + + {guideChannels.map((channel) => ( + + + {channel.channel_name} + + + ))} + + + {/* Timeline & Program Blocks */} + + {/* Sticky timeline header */} + + + {hourTimeline.map((time, hourIndex) => ( + + + {time.format('h:mma')} + + + {[0, 1, 2, 3].map((i) => ( + + ))} + + + ))} + + + + {/* Now line */} + + {nowPosition >= 0 && ( + + )} + + {/* Channel rows */} + {guideChannels.map((channel) => { + const channelPrograms = programs.filter( + (p) => p.tvg_id === channel.tvg_id + ); + return ( + + + {channelPrograms.map((prog) => renderProgram(prog, start))} + + + ); + })} + + + + + {/* Modal for program details */} + + {selectedProgram && ( + <> + + {selectedProgram.title} + + + + {dayjs(selectedProgram.start_time).format('h:mma')} -{' '} + {dayjs(selectedProgram.end_time).format('h:mma')} + + + {selectedProgram.description || 'No description available.'} + + + + {/* Only show the Watch button if currently live */} + {now.isAfter(dayjs(selectedProgram.start_time)) && + now.isBefore(dayjs(selectedProgram.end_time)) && ( + + )} + + + + )} + + + ); +} diff --git a/vite/src/pages/Home.jsx b/vite/src/pages/Home.jsx new file mode 100644 index 00000000..ac971332 --- /dev/null +++ b/vite/src/pages/Home.jsx @@ -0,0 +1,14 @@ +// src/components/Home.js +import React, { useState } from "react"; + +const Home = () => { + const [newChannel, setNewChannel] = useState(""); + + return ( +
+

Home Page

+
+ ); +}; + +export default Home; diff --git a/vite/src/pages/Login.jsx b/vite/src/pages/Login.jsx new file mode 100644 index 00000000..7ce24331 --- /dev/null +++ b/vite/src/pages/Login.jsx @@ -0,0 +1,8 @@ +import React from 'react'; +import LoginForm from '../components/forms/LoginForm'; + +const Login = () => { + return ; +}; + +export default Login; diff --git a/vite/src/pages/M3U.jsx b/vite/src/pages/M3U.jsx new file mode 100644 index 00000000..71cc729e --- /dev/null +++ b/vite/src/pages/M3U.jsx @@ -0,0 +1,34 @@ +import React, { useState } from 'react'; +import useUserAgentsStore from '../store/userAgents'; +import M3UsTable from '../components/tables/M3UsTable'; +import UserAgentsTable from '../components/tables/UserAgentsTable'; +import { Box } from '@mantine/core'; + +const M3UPage = () => { + const isLoading = useUserAgentsStore((state) => state.isLoading); + const error = useUserAgentsStore((state) => state.error); + + if (isLoading) return
Loading...
; + if (error) return
Error: {error}
; + + return ( + + + + + + + + + + ); +}; + +export default M3UPage; diff --git a/vite/src/pages/Settings.jsx b/vite/src/pages/Settings.jsx new file mode 100644 index 00000000..32655186 --- /dev/null +++ b/vite/src/pages/Settings.jsx @@ -0,0 +1,146 @@ +import React, { useEffect } from 'react'; +import { useFormik } from 'formik'; +import * as Yup from 'yup'; + +import API from '../api'; +import useSettingsStore from '../store/settings'; +import useUserAgentsStore from '../store/userAgents'; +import useStreamProfilesStore from '../store/streamProfiles'; +import { Button, Center, Flex, Paper, Select, Title } from '@mantine/core'; + +const SettingsPage = () => { + const { settings } = useSettingsStore(); + const { userAgents } = useUserAgentsStore(); + const { profiles: streamProfiles } = useStreamProfilesStore(); + + // Add your region choices here: + const regionChoices = [ + { value: 'us', label: 'US' }, + { value: 'uk', label: 'UK' }, + { value: 'nl', label: 'NL' }, + { value: 'de', label: 'DE' }, + // Add more if needed + ]; + + const formik = useFormik({ + initialValues: { + 'default-user-agent': '', + 'default-stream-profile': '', + 'preferred-region': '', + }, + validationSchema: Yup.object({ + 'default-user-agent': Yup.string().required('User-Agent is required'), + 'default-stream-profile': Yup.string().required( + 'Stream Profile is required' + ), + // The region is optional or required as you prefer + // 'preferred-region': Yup.string().required('Region is required'), + }), + onSubmit: async (values, { setSubmitting, resetForm }) => { + const changedSettings = {}; + for (const settingKey in values) { + // If the user changed the setting’s value from what’s in the DB: + if (String(values[settingKey]) !== String(settings[settingKey].value)) { + changedSettings[settingKey] = values[settingKey]; + } + } + + // Update each changed setting in the backend + for (const updatedKey in changedSettings) { + await API.updateSetting({ + ...settings[updatedKey], + value: changedSettings[updatedKey], + }); + } + + setSubmitting(false); + // Don’t necessarily resetForm, in case the user wants to see new values + }, + }); + + // Initialize form values once settings / userAgents / profiles are loaded + useEffect(() => { + formik.setValues( + Object.values(settings).reduce((acc, setting) => { + // If the setting’s value is numeric, parse it + // Otherwise, just store as string + const possibleNumber = parseInt(setting.value, 10); + acc[setting.key] = isNaN(possibleNumber) + ? setting.value + : possibleNumber; + return acc; + }, {}) + ); + // eslint-disable-next-line + }, [settings, userAgents, streamProfiles]); + + return ( +
+ + + Settings + +
+ ({ + value: `${option.id}`, + label: option.profile_name, + }))} + /> + {/*