diff --git a/.claude/settings.local.json b/.claude/settings.local.json new file mode 100644 index 0000000000..51882da855 --- /dev/null +++ b/.claude/settings.local.json @@ -0,0 +1,7 @@ +{ + "permissions": { + "allow": [ + "Bash(grep -l \"$l\" build/assets/*.js)" + ] + } +} diff --git a/.env.production b/.env.production index 3552083afc..97e12cb9b1 100644 --- a/.env.production +++ b/.env.production @@ -1,4 +1,5 @@ VITE_PUBLIC_URL=/mlrun +VITE_FEDERATION=false VITE_MLRUN_API_URL=${MLRUN_API_PROXY_URL} VITE_MLRUN_V3IO_ACCESS_KEY=${MLRUN_V3IO_ACCESS_KEY} VITE_IGUAZIO_API_URL= diff --git a/.gitignore b/.gitignore index e000bb3f1b..a62949c540 100755 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,8 @@ # production /build +.__mf__temp/ +*.tar # misc .DS_Store diff --git a/Dockerfile b/Dockerfile index 5d3cee3d8f..2380520dca 100644 --- a/Dockerfile +++ b/Dockerfile @@ -73,4 +73,4 @@ ENV MLRUN_API_PROXY_URL="${MLRUN_API_PROXY_URL:-http://localhost:8090}" \ MLRUN_NUCLIO_UI_URL="${MLRUN_NUCLIO_UI_URL:-http://localhost:8070}" \ MLRUN_V3IO_ACCESS_KEY="${MLRUN_V3IO_ACCESS_KEY:-\"\"}" -CMD echo resolver $(awk 'BEGIN{ORS=" "} $1=="nameserver" {if ($2 ~ /:/) print "["$2"]"; else print $2}' /etc/resolv.conf) ";" > /etc/nginx/resolvers.conf && /etc/nginx/run_nginx +CMD echo resolver $(awk 'BEGIN{ORS=" "} $1=="nameserver" {if ($2 ~ /:/) print "["$2"]"; else print $2}' /etc/resolv.conf) ";" > /etc/nginx/resolvers.conf && /etc/nginx/run_nginx \ No newline at end of file diff --git a/Dockerfile.mf b/Dockerfile.mf new file mode 100644 index 0000000000..3ef084252e --- /dev/null +++ b/Dockerfile.mf @@ -0,0 +1,67 @@ +# Copyright 2019 Iguazio +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# build stage — Module Federation remote +FROM quay.io/mlrun/node:20.19.2-slim AS build-stage + +WORKDIR /app + +COPY package*.json ./ +RUN npm install + +COPY . . + +RUN echo ">>> Building Module Federation remote" && \ + sed -i "/^VITE_FEDERATION=/d" .env.production && \ + echo "VITE_FEDERATION=true" >> .env.production && \ + sed -i "s|^VITE_PUBLIC_URL=/mlrun|VITE_PUBLIC_URL=|" .env.production && \ + echo ">>> Final .env.production:" && grep '^VITE_' .env.production + +RUN npm run build + +ARG COMMIT_HASH +ARG DATE +RUN echo "${COMMIT_HASH}" > ./build/COMMIT_HASH && \ + echo "${DATE}" > ./build/BUILD_DATE + +# production stage +FROM gcr.io/iguazio/nginx-unprivileged:1.21-alpine AS production-stage + +ARG UID=101 +ARG GID=101 + +USER root +RUN apk update --no-cache && apk upgrade --no-cache \ + && rm -f /etc/nginx/conf.d/default.conf + +USER $UID + +COPY --from=build-stage /app/build /usr/share/nginx/html +COPY --from=build-stage /app/.env.production /usr/share/nginx/html/ + +COPY nginx/nginx.conf.mf.tmpl /etc/nginx/conf.d/nginx.conf.tmpl +COPY nginx/run_nginx.mf /etc/nginx/run_nginx + +USER root +RUN INDEX=/usr/share/nginx/html/index.html && \ + [ -f "$INDEX" ] && sed -i 's| +When set to `true`, the image is built in **Module Federation** mode. + ### `docker run` environment variables The Docker container runs a Nginx server, which listens on exposed port number 8090, serves the web-app, and proxies to the backend API. @@ -36,6 +45,7 @@ You can pass the following environment variables to the `docker run` command to | `MLRUN_V3IO_ACCESS_KEY` | Sets the V3IO access key to use for accessing V3IO containers
Example: `a7097c94-6e8f-436d-9717-a84abe2861d1` | | `MLRUN_FUNCTION_CATALOG_URL` | Sets the base URL of the function-template catalog
Default: `https://raw.githubusercontent.com` | | `MLRUN_FUNCTION_CATALOG_PATH` | Sets the base URI of the function-template catalog
Default: `/mlrun/functions/master` | +| `MLRUN_IGZ_UI_ALLOWED_ORIGIN` | Allowed origin for Module Federation and CORS
Example: `https://igz-ui.pini.vmdev90ig4.lab.iguazeng.com` | Example: @@ -71,6 +81,11 @@ This command is run by the Dockerfile that is used by the command [`npm run dock Note: `npm install` should be run first. +### `npm run preview:federation` + +Builds and serves the **mlrun-ui** application in **Module Federation** mode at `http://localhost:5179/`.
+Use this command when developing locally with **igz-ui**, allowing **mlrun-ui** to be consumed as a remote module. + ## Development ### Environment variables diff --git a/config.json.tmpl b/config.json.tmpl index 4784356dd6..3bde3bc9d7 100644 --- a/config.json.tmpl +++ b/config.json.tmpl @@ -1,5 +1,6 @@ { "betaMode": "${MLRUN_BETA_MODE}", "nuclioMode": "${MLRUN_NUCLIO_MODE}", - "nuclioUiUrl": "${MLRUN_NUCLIO_UI_URL}" + "nuclioUiUrl": "${MLRUN_NUCLIO_UI_URL}", + "nuclioRemoteEntryUrl": "${MLRUN_NUCLIO_REMOTE_ENTRY_URL}" } diff --git a/config/getHttpsConfig.js b/config/getHttpsConfig.js deleted file mode 100644 index 053b5b76f5..0000000000 --- a/config/getHttpsConfig.js +++ /dev/null @@ -1,78 +0,0 @@ -/* -Copyright 2019 Iguazio Systems Ltd. - -Licensed under the Apache License, Version 2.0 (the "License") with -an addition restriction as set forth herein. You may not use this -file except in compliance with the License. You may obtain a copy of -the License at http://www.apache.org/licenses/LICENSE-2.0. - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing -permissions and limitations under the License. - -In addition, you may not use the software for any purposes that are -illegal under applicable law, and the grant of the foregoing license -under the Apache 2.0 license is conditioned upon your compliance with -such restriction. -*/ - -const fs = require('fs') -const path = require('path') -const crypto = require('node:crypto') -const chalk = require('react-dev-utils/chalk') -const paths = require('./paths') - -// Ensure the certificate and key provided are valid and if not -// throw an easy to debug error -function validateKeyAndCerts({ cert, key, keyFile, crtFile }) { - let encrypted - try { - // publicEncrypt will throw an error with an invalid cert - encrypted = crypto.publicEncrypt(cert, Buffer.from('test')) - } catch (err) { - throw new Error(`The certificate "${chalk.yellow(crtFile)}" is invalid.\n${err.message}`) - } - - try { - // privateDecrypt will throw an error with an invalid key - crypto.privateDecrypt(key, encrypted) - } catch (err) { - throw new Error(`The certificate key "${chalk.yellow(keyFile)}" is invalid.\n${err.message}`) - } -} - -// Read file and throw an error if it doesn't exist -function readEnvFile(file, type) { - if (!fs.existsSync(file)) { - throw new Error( - `You specified ${chalk.cyan(type)} in your env, but the file "${chalk.yellow( - file - )}" can't be found.` - ) - } - return fs.readFileSync(file) -} - -// Get the https config -// Return cert files if provided in env, otherwise just true or false -function getHttpsConfig() { - const { SSL_CRT_FILE, SSL_KEY_FILE, HTTPS } = process.env - const isHttps = HTTPS === 'true' - - if (isHttps && SSL_CRT_FILE && SSL_KEY_FILE) { - const crtFile = path.resolve(paths.appPath, SSL_CRT_FILE) - const keyFile = path.resolve(paths.appPath, SSL_KEY_FILE) - const config = { - cert: readEnvFile(crtFile, 'SSL_CRT_FILE'), - key: readEnvFile(keyFile, 'SSL_KEY_FILE') - } - - validateKeyAndCerts({ ...config, keyFile, crtFile }) - return config - } - return isHttps -} - -module.exports = getHttpsConfig diff --git a/config/loadDevProxyConfig.js b/config/loadDevProxyConfig.js new file mode 100644 index 0000000000..4208bc3239 --- /dev/null +++ b/config/loadDevProxyConfig.js @@ -0,0 +1,57 @@ +/* +Copyright 2019 Iguazio Systems Ltd. + +Licensed under the Apache License, Version 2.0 (the "License") with +an addition restriction as set forth herein. You may not use this +file except in compliance with the License. You may obtain a copy of +the License at http://www.apache.org/licenses/LICENSE-2.0. + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing +permissions and limitations under the License. + +In addition, you may not use the software for any purposes that are +illegal under applicable law, and the grant of the foregoing license +under the Apache 2.0 license is conditioned upon your compliance with +such restriction. +*/ +/** + * Dynamically loads the Mlrun proxy configuration for development. + * + * Returns an empty proxy in production. + * In development, it imports the shared `mlrunProxyConfig` function + * from the `iguazio.dashboard-react-controls` package and validates its export. + * + * Node cannot use the aliased import + * (`import { mlrunProxyConfig } from 'igz-controls/utils/proxyServerConfig.util'`) + * since Vite path aliases are resolved only at build time, + * not during Node's module execution. + */ +import path from 'path' +import { pathToFileURL } from 'url' + +export const loadMlrunProxyConfig = async mode => { + const modulePath = path.resolve( + 'node_modules/iguazio.dashboard-react-controls/dist/utils/proxyServerConfig.util.mjs' + ) + + try { + const moduleUrl = pathToFileURL(modulePath).href + + const { mlrunProxyConfig } = await import(moduleUrl) + + if (typeof mlrunProxyConfig !== 'function') { + throw new Error('Invalid export: expected mlrunProxyConfig to be a function.') + } + + return mlrunProxyConfig + } catch (error) { + if (process.env.PREVIEW_MODE === 'true' || mode === 'development') { + throw new Error(`Failed to load mlrunProxyConfig: ${error.message}`) + } + + return () => ({}) + } +} diff --git a/config/modules.js b/config/modules.js deleted file mode 100644 index 6aaf4be2b4..0000000000 --- a/config/modules.js +++ /dev/null @@ -1,153 +0,0 @@ -/* -Copyright 2019 Iguazio Systems Ltd. - -Licensed under the Apache License, Version 2.0 (the "License") with -an addition restriction as set forth herein. You may not use this -file except in compliance with the License. You may obtain a copy of -the License at http://www.apache.org/licenses/LICENSE-2.0. - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing -permissions and limitations under the License. - -In addition, you may not use the software for any purposes that are -illegal under applicable law, and the grant of the foregoing license -under the Apache 2.0 license is conditioned upon your compliance with -such restriction. -*/ -'use strict'; - -const fs = require('fs'); -const path = require('path'); -const paths = require('./paths'); -const chalk = require('react-dev-utils/chalk'); -const resolve = require('resolve'); - -/** - * Get additional module paths based on the baseUrl of a compilerOptions object. - * - * @param {Object} options - */ -function getAdditionalModulePaths(options = {}) { - const baseUrl = options.baseUrl; - - if (!baseUrl) { - return ''; - } - - const baseUrlResolved = path.resolve(paths.appPath, baseUrl); - - // We don't need to do anything if `baseUrl` is set to `node_modules`. This is - // the default behavior. - if (path.relative(paths.appNodeModules, baseUrlResolved) === '') { - return null; - } - - // Allow the user set the `baseUrl` to `appSrc`. - if (path.relative(paths.appSrc, baseUrlResolved) === '') { - return [paths.appSrc]; - } - - // If the path is equal to the root directory we ignore it here. - // We don't want to allow importing from the root directly as source files are - // not transpiled outside of `src`. We do allow importing them with the - // absolute path (e.g. `src/Components/Button.js`) but we set that up with - // an alias. - if (path.relative(paths.appPath, baseUrlResolved) === '') { - return null; - } - - // Otherwise, throw an error. - throw new Error( - chalk.red.bold( - "Your project's `baseUrl` can only be set to `src` or `node_modules`." + - ' Create React App does not support other values at this time.' - ) - ); -} - -/** - * Get webpack aliases based on the baseUrl of a compilerOptions object. - * - * @param {*} options - */ -function getWebpackAliases(options = {}) { - const baseUrl = options.baseUrl; - - if (!baseUrl) { - return {}; - } - - const baseUrlResolved = path.resolve(paths.appPath, baseUrl); - - if (path.relative(paths.appPath, baseUrlResolved) === '') { - return { - src: paths.appSrc, - }; - } -} - -/** - * Get jest aliases based on the baseUrl of a compilerOptions object. - * - * @param {*} options - */ -function getJestAliases(options = {}) { - const baseUrl = options.baseUrl; - - if (!baseUrl) { - return {}; - } - - const baseUrlResolved = path.resolve(paths.appPath, baseUrl); - - if (path.relative(paths.appPath, baseUrlResolved) === '') { - return { - '^src/(.*)$': '/src/$1', - }; - } -} - -function getModules() { - // Check if TypeScript is setup - const hasTsConfig = fs.existsSync(paths.appTsConfig); - const hasJsConfig = fs.existsSync(paths.appJsConfig); - - if (hasTsConfig && hasJsConfig) { - throw new Error( - 'You have both a tsconfig.json and a jsconfig.json. If you are using TypeScript please remove your jsconfig.json file.' - ); - } - - let config; - - // If there's a tsconfig.json we assume it's a - // TypeScript project and set up the config - // based on tsconfig.json - if (hasTsConfig) { - const ts = require(resolve.sync('typescript', { - basedir: paths.appNodeModules, - })); - config = ts.readConfigFile(paths.appTsConfig, ts.sys.readFile).config; - // Otherwise we'll check if there is jsconfig.json - // for non TS projects. - } else if (hasJsConfig) { - config = require(paths.appJsConfig); - } - - config = config || {}; - const options = config.compilerOptions || {}; - - const additionalModulePaths = getAdditionalModulePaths(options); - - return { - additionalModulePaths: additionalModulePaths, - webpackAliases: getWebpackAliases(options), - jestAliases: getJestAliases(options), - hasTsConfig, - }; -} - -module.exports = getModules(); diff --git a/config/paths.js b/config/paths.js index b17443273e..2d4fbe9c71 100644 --- a/config/paths.js +++ b/config/paths.js @@ -17,16 +17,16 @@ illegal under applicable law, and the grant of the foregoing license under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ -'use strict'; +'use strict' -const path = require('path'); -const fs = require('fs'); -const getPublicUrlOrPath = require('react-dev-utils/getPublicUrlOrPath'); +const path = require('path') +const fs = require('fs') +const getPublicUrlOrPath = require('react-dev-utils/getPublicUrlOrPath') // Make sure any symlinks in the project folder are resolved: // https://github.com/facebook/create-react-app/issues/637 -const appDirectory = fs.realpathSync(process.cwd()); -const resolveApp = relativePath => path.resolve(appDirectory, relativePath); +const appDirectory = fs.realpathSync(process.cwd()) +const resolveApp = relativePath => path.resolve(appDirectory, relativePath) // We use `PUBLIC_URL` environment variable or "homepage" field to infer // "public path" at which the app is served. @@ -38,9 +38,9 @@ const publicUrlOrPath = getPublicUrlOrPath( process.env.NODE_ENV === 'development', require(resolveApp('package.json')).homepage, process.env.PUBLIC_URL -); +) -const buildPath = process.env.BUILD_PATH || 'build'; +const buildPath = process.env.BUILD_PATH || 'build' const moduleFileExtensions = [ 'web.mjs', @@ -53,21 +53,21 @@ const moduleFileExtensions = [ 'tsx', 'json', 'web.jsx', - 'jsx', -]; + 'jsx' +] // Resolve file paths in the same order as webpack const resolveModule = (resolveFn, filePath) => { const extension = moduleFileExtensions.find(extension => fs.existsSync(resolveFn(`${filePath}.${extension}`)) - ); + ) if (extension) { - return resolveFn(`${filePath}.${extension}`); + return resolveFn(`${filePath}.${extension}`) } - return resolveFn(`${filePath}.js`); -}; + return resolveFn(`${filePath}.js`) +} // config after eject: we're in ./config/ module.exports = { @@ -83,14 +83,11 @@ module.exports = { appJsConfig: resolveApp('jsconfig.json'), yarnLockFile: resolveApp('yarn.lock'), testsSetup: resolveModule(resolveApp, 'src/setupTests'), - proxySetup: resolveApp('src/setupProxy.js'), appNodeModules: resolveApp('node_modules'), appWebpackCache: resolveApp('node_modules/.cache'), appTsBuildInfoFile: resolveApp('node_modules/.cache/tsconfig.tsbuildinfo'), swSrc: resolveModule(resolveApp, 'src/service-worker'), - publicUrlOrPath, -}; + publicUrlOrPath +} - - -module.exports.moduleFileExtensions = moduleFileExtensions; +module.exports.moduleFileExtensions = moduleFileExtensions diff --git a/eslint.config.mjs b/eslint.config.mjs index 465940434c..40c2693cd6 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -5,25 +5,29 @@ import react from 'eslint-plugin-react' import reactHooks from 'eslint-plugin-react-hooks' import eslintPluginImport from 'eslint-plugin-import' +import { viteGlobals } from './eslint.mlrun-globals.mjs' + export default [ - { ignores: ['dist'] }, + { ignores: ['dist', '.__mf__temp'] }, js.configs.recommended, eslintConfigPrettier, { - files: ['**/*.{js,jsx,ts,tsx}'], + files: ['**/*.{js,mjs,jsx,ts,tsx}'], languageOptions: { ecmaVersion: 2021, globals: { ...globals.browser, ...globals.jest, ...globals.node, + ...viteGlobals, ...globals.vitest }, parserOptions: { ecmaFeatures: { jsx: true } - } + }, + sourceType: 'module' }, plugins: { react: react, @@ -50,9 +54,13 @@ export default [ } }, { - files: ["**/*.test.jsx"], + files: ['**/*.test.js', '**/*.test.jsx'], rules: { - "import/named": "off" + 'import/named': 'off', + 'no-unused-vars': [ + process.env.NODE_ENV === 'production' ? 2 : 1, + { argsIgnorePattern: '^_', varsIgnorePattern: '^_' } + ] } } ] diff --git a/eslint.mlrun-globals.mjs b/eslint.mlrun-globals.mjs new file mode 100644 index 0000000000..ea00e909b4 --- /dev/null +++ b/eslint.mlrun-globals.mjs @@ -0,0 +1,9 @@ +export const viteGlobals = { + VITE_PUBLIC_URL: 'readonly', + VITE_MLRUN_API_URL: 'readonly', + VITE_NUCLIO_API_URL: 'readonly', + VITE_IGUAZIO_API_URL: 'readonly', + VITE_FUNCTION_CATALOG_URL: 'readonly', + VITE_MLRUN_V3IO_ACCESS_KEY: 'readonly', + VITE_FEDERATION: 'readonly' +} diff --git a/nginx/nginx.conf.mf.tmpl b/nginx/nginx.conf.mf.tmpl new file mode 100644 index 0000000000..7989d3eeba --- /dev/null +++ b/nginx/nginx.conf.mf.tmpl @@ -0,0 +1,30 @@ +server { + listen 8090; + server_name localhost; + + root /usr/share/nginx/html; + + # Basic Gzip as per standard defaults + gzip on; + + # CRITICAL: Allow the Global Host (IGZ) to fetch these assets + add_header Access-Control-Allow-Origin *; + add_header Access-Control-Allow-Methods 'GET, OPTIONS'; + add_header Access-Control-Allow-Headers 'Content-Type, Authorization'; + + location / { + # Show landing page when accessing the remote directly + index landing.html; + try_files $uri $uri/ /landing.html; + + # Ensure remote assets are always fresh + if ($request_filename ~* .*\.(?:js|json)$ ) { + add_header Cache-Control "no-cache, no-store, must-revalidate"; + } + } + + error_page 500 502 503 504 /50x.html; + location = /50x.html { + root /usr/share/nginx/html; + } +} diff --git a/nginx/run_nginx.mf b/nginx/run_nginx.mf new file mode 100644 index 0000000000..f6e1ae65af --- /dev/null +++ b/nginx/run_nginx.mf @@ -0,0 +1,7 @@ +#!/bin/sh + +# Simply copy the template as the final config +cp /etc/nginx/conf.d/nginx.conf.tmpl /etc/nginx/conf.d/nginx.conf + +# Start Nginx in foreground +exec nginx -g 'daemon off;' diff --git a/package-lock.json b/package-lock.json old mode 100755 new mode 100644 index 6280821a24..3a4a857403 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,8 @@ "hasInstallScript": true, "dependencies": { "@dagrejs/dagre": "^1.1.5", + "@module-federation/runtime": "0.23.0", + "@module-federation/vite": "1.11.0", "@monaco-editor/react": "^4.7.0", "@radix-ui/react-collapsible": "^1.1.12", "@radix-ui/react-dialog": "^1.1.15", @@ -29,6 +31,7 @@ "concurrently": "^6.4.2", "cronstrue": "^2.49.0", "dotenv": "^10.0.0", + "dotenv-cli": "^10.0.0", "dotenv-expand": "^5.1.0", "file-saver": "^2.0.5", "final-form": "^4.20.10", @@ -49,6 +52,7 @@ "qs": "^6.15.2", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-error-boundary": "^6.1.0", "react-final-form": "^6.5.9", "react-final-form-arrays": "^3.1.4", "react-modal-promise": "^1.0.2", @@ -195,9 +199,9 @@ } }, "node_modules/@asamuzakjp/css-color/node_modules/lru-cache": { - "version": "11.5.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.1.tgz", - "integrity": "sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==", + "version": "11.5.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.2.tgz", + "integrity": "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==", "dev": true, "license": "BlueOak-1.0.0", "engines": { @@ -219,9 +223,9 @@ } }, "node_modules/@asamuzakjp/dom-selector/node_modules/lru-cache": { - "version": "11.5.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.1.tgz", - "integrity": "sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==", + "version": "11.5.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.2.tgz", + "integrity": "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==", "dev": true, "license": "BlueOak-1.0.0", "engines": { @@ -5197,7 +5201,6 @@ "cpu": [ "ppc64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5214,7 +5217,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5231,7 +5233,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5248,7 +5249,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5265,7 +5265,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5282,7 +5281,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5299,7 +5297,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5316,7 +5313,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5333,7 +5329,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5350,7 +5345,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5367,7 +5361,6 @@ "cpu": [ "ia32" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5384,7 +5377,6 @@ "cpu": [ "loong64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5401,7 +5393,6 @@ "cpu": [ "mips64el" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5418,7 +5409,6 @@ "cpu": [ "ppc64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5435,7 +5425,6 @@ "cpu": [ "riscv64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5452,7 +5441,6 @@ "cpu": [ "s390x" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5469,7 +5457,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5486,7 +5473,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5503,7 +5489,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5520,7 +5505,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5537,7 +5521,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5554,7 +5537,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5571,7 +5553,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5588,7 +5569,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5605,7 +5585,6 @@ "cpu": [ "ia32" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5622,7 +5601,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5633,9 +5611,9 @@ } }, "node_modules/@eslint-community/eslint-utils": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", - "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.10.1.tgz", + "integrity": "sha512-cuadcxVFE8sDK6iWJbs8Sn0av2Nrh2QSGQhVlBW9AaAHqHwjWsZHT8LJ4hFGPh7ASBV2deFdM7H/DPjulmh8rg==", "dev": true, "license": "MIT", "dependencies": { @@ -5716,9 +5694,9 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "3.3.5", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.5.tgz", - "integrity": "sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==", + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.6.tgz", + "integrity": "sha512-l2Ul9PrHsPCKcEY/ac7VgFj9D80C7S68sOKc618SyHDPK36s1XcFebXY0iTzUVn4Yq+YbwvSnDmCz9yxjX+QrA==", "dev": true, "license": "MIT", "dependencies": { @@ -5728,7 +5706,7 @@ "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", - "js-yaml": "^4.1.1", + "js-yaml": "^4.3.0", "minimatch": "^3.1.5", "strip-json-comments": "^3.1.1" }, @@ -5753,9 +5731,9 @@ } }, "node_modules/@eslint/js": { - "version": "9.39.4", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.4.tgz", - "integrity": "sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==", + "version": "9.39.5", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.5.tgz", + "integrity": "sha512-QywQuszQh77pIXCsq998c8hbhSTI/azTty1Z6N53dmAudKHhy573j3yvRLsX2BSp8YpLtoCEG8E9DJe+8zUh4A==", "dev": true, "license": "MIT", "engines": { @@ -5808,31 +5786,31 @@ } }, "node_modules/@floating-ui/core": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.5.tgz", - "integrity": "sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.8.0.tgz", + "integrity": "sha512-0CIZ5itps/8x7BG8dEIhs53BvCUH2PCoogtakwRTut+Arm58sJooJ0AuZhLw2HJYIR5cMLNPBSS728sPho2khQ==", "license": "MIT", "dependencies": { - "@floating-ui/utils": "^0.2.11" + "@floating-ui/utils": "^0.2.12" } }, "node_modules/@floating-ui/dom": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.6.tgz", - "integrity": "sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.8.0.tgz", + "integrity": "sha512-yXSrzeHZBTZadLOlfyhCkJHNeLJnHRnRInwdZ40L7ZiaAtrBwoYlsDrX3v5zB1Utk7CLfzcOVnVVWoXEky7Ceg==", "license": "MIT", "dependencies": { - "@floating-ui/core": "^1.7.5", - "@floating-ui/utils": "^0.2.11" + "@floating-ui/core": "^1.8.0", + "@floating-ui/utils": "^0.2.12" } }, "node_modules/@floating-ui/react-dom": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.8.tgz", - "integrity": "sha512-cC52bHwM/n/CxS87FH0yWdngEZrjdtLW/qVruo68qg+prK7ZQ4YGdut2GyDVpoGeAYe/h899rVeOVm6Oi40k2A==", + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.9.tgz", + "integrity": "sha512-JDjEFGCpImxDCA7JJKviA0M9+RtmJdj0m/NVU5IMgBK+AmZouAQQ7/+2GLH0GXXY0YMw9oXPB8hKdbPYg5QLYg==", "license": "MIT", "dependencies": { - "@floating-ui/dom": "^1.7.6" + "@floating-ui/dom": "^1.8.0" }, "peerDependencies": { "react": ">=16.8.0", @@ -5840,9 +5818,9 @@ } }, "node_modules/@floating-ui/utils": { - "version": "0.2.11", - "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.11.tgz", - "integrity": "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==", + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.12.tgz", + "integrity": "sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww==", "license": "MIT" }, "node_modules/@humanfs/core": { @@ -6034,7 +6012,7 @@ "version": "0.3.13", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", @@ -6056,7 +6034,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=6.0.0" @@ -6066,7 +6044,7 @@ "version": "0.3.11", "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", - "dev": true, + "devOptional": true, "license": "MIT", "peer": true, "dependencies": { @@ -6078,14 +6056,13 @@ "version": "1.5.5", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "dev": true, "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.31", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -6116,6 +6093,302 @@ "react": ">=16" } }, + "node_modules/@module-federation/dts-plugin": { + "version": "0.21.6", + "resolved": "https://registry.npmjs.org/@module-federation/dts-plugin/-/dts-plugin-0.21.6.tgz", + "integrity": "sha512-YIsDk8/7QZIWn0I1TAYULniMsbyi2LgKTi9OInzVmZkwMC6644x/ratTWBOUDbdY1Co+feNkoYeot1qIWv2L7w==", + "license": "MIT", + "dependencies": { + "@module-federation/error-codes": "0.21.6", + "@module-federation/managers": "0.21.6", + "@module-federation/sdk": "0.21.6", + "@module-federation/third-party-dts-extractor": "0.21.6", + "adm-zip": "^0.5.10", + "ansi-colors": "^4.1.3", + "axios": "^1.12.0", + "chalk": "3.0.0", + "fs-extra": "9.1.0", + "isomorphic-ws": "5.0.0", + "koa": "3.0.3", + "lodash.clonedeepwith": "4.5.0", + "log4js": "6.9.1", + "node-schedule": "2.1.1", + "rambda": "^9.1.0", + "ws": "8.18.0" + }, + "peerDependencies": { + "typescript": "^4.9.0 || ^5.0.0", + "vue-tsc": ">=1.0.24" + }, + "peerDependenciesMeta": { + "vue-tsc": { + "optional": true + } + } + }, + "node_modules/@module-federation/dts-plugin/node_modules/@module-federation/error-codes": { + "version": "0.21.6", + "resolved": "https://registry.npmjs.org/@module-federation/error-codes/-/error-codes-0.21.6.tgz", + "integrity": "sha512-MLJUCQ05KnoVl8xd6xs9a5g2/8U+eWmVxg7xiBMeR0+7OjdWUbHwcwgVFatRIwSZvFgKHfWEiI7wsU1q1XbTRQ==", + "license": "MIT" + }, + "node_modules/@module-federation/dts-plugin/node_modules/@module-federation/sdk": { + "version": "0.21.6", + "resolved": "https://registry.npmjs.org/@module-federation/sdk/-/sdk-0.21.6.tgz", + "integrity": "sha512-x6hARETb8iqHVhEsQBysuWpznNZViUh84qV2yE7AD+g7uIzHKiYdoWqj10posbo5XKf/147qgWDzKZoKoEP2dw==", + "license": "MIT" + }, + "node_modules/@module-federation/dts-plugin/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==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@module-federation/dts-plugin/node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@module-federation/dts-plugin/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "license": "MIT", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@module-federation/dts-plugin/node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/@module-federation/dts-plugin/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==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@module-federation/error-codes": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@module-federation/error-codes/-/error-codes-0.23.0.tgz", + "integrity": "sha512-CzcKOPKh/qB1wPkVBC0iEK/Cg4jRAS1DnZsTx7b3JUCIXDcIaRq/XkTdo+EQ0cAsF5Os9lQ0f50O9DC/uFC8eA==", + "license": "MIT" + }, + "node_modules/@module-federation/managers": { + "version": "0.21.6", + "resolved": "https://registry.npmjs.org/@module-federation/managers/-/managers-0.21.6.tgz", + "integrity": "sha512-BeV6m2/7kF5MDVz9JJI5T8h8lMosnXkH2bOxxFewcra7ZjvDOgQu7WIio0mgk5l1zjNPvnEVKhnhrenEdcCiWg==", + "license": "MIT", + "dependencies": { + "@module-federation/sdk": "0.21.6", + "find-pkg": "2.0.0", + "fs-extra": "9.1.0" + } + }, + "node_modules/@module-federation/managers/node_modules/@module-federation/sdk": { + "version": "0.21.6", + "resolved": "https://registry.npmjs.org/@module-federation/sdk/-/sdk-0.21.6.tgz", + "integrity": "sha512-x6hARETb8iqHVhEsQBysuWpznNZViUh84qV2yE7AD+g7uIzHKiYdoWqj10posbo5XKf/147qgWDzKZoKoEP2dw==", + "license": "MIT" + }, + "node_modules/@module-federation/managers/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "license": "MIT", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@module-federation/managers/node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/@module-federation/runtime": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@module-federation/runtime/-/runtime-0.23.0.tgz", + "integrity": "sha512-ZHJcfM1O8RqYVrlIbhyeQ3S6gJW3mqHso3/QY7cKs1za+UvOgB8aTsDwq7Fv+aJZWSmtGzWa4zbSuxthyucw3g==", + "license": "MIT", + "dependencies": { + "@module-federation/error-codes": "0.23.0", + "@module-federation/runtime-core": "0.23.0", + "@module-federation/sdk": "0.23.0" + } + }, + "node_modules/@module-federation/runtime-core": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@module-federation/runtime-core/-/runtime-core-0.23.0.tgz", + "integrity": "sha512-+Orumtyg6Q2v19Gz15P3kDmRf4Q6KEpv8DggKWHdM8AX4xyVT8dMRJxdIxaVddbIYTd7aL7o2U3LLK6EjUe4UA==", + "license": "MIT", + "dependencies": { + "@module-federation/error-codes": "0.23.0", + "@module-federation/sdk": "0.23.0" + } + }, + "node_modules/@module-federation/sdk": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@module-federation/sdk/-/sdk-0.23.0.tgz", + "integrity": "sha512-1+DICHIF1z6yggtsZypmcn1gL35iitiSDXcsaqWynK4v5aw9MBRUS4zP3kG7eQDFTMmIo+rGbPN37AUsOq/RRQ==", + "license": "MIT" + }, + "node_modules/@module-federation/third-party-dts-extractor": { + "version": "0.21.6", + "resolved": "https://registry.npmjs.org/@module-federation/third-party-dts-extractor/-/third-party-dts-extractor-0.21.6.tgz", + "integrity": "sha512-Il6x4hLsvCgZNk1DFwuMBNeoxD1BsZ5AW2BI/nUgu0k5FiAvfcz1OFawRFEHtaM/kVrCsymMOW7pCao90DaX3A==", + "license": "MIT", + "dependencies": { + "find-pkg": "2.0.0", + "fs-extra": "9.1.0", + "resolve": "1.22.8" + } + }, + "node_modules/@module-federation/third-party-dts-extractor/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "license": "MIT", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@module-federation/third-party-dts-extractor/node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/@module-federation/third-party-dts-extractor/node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "license": "MIT", + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/@module-federation/vite": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@module-federation/vite/-/vite-1.11.0.tgz", + "integrity": "sha512-dawLMF1JUt/4IUwQh7dUF5TBcetGg3qPKBX+hCFL2aHFd8m3EI+HmGc4qIGVlGZMub6mpTIGo9EHfhV5cDIOmQ==", + "license": "MIT", + "dependencies": { + "@module-federation/dts-plugin": "^0.21.6", + "@module-federation/runtime": "^0.21.6", + "@module-federation/sdk": "^0.21.6", + "@rollup/pluginutils": "^5.1.0", + "defu": "^6.1.4", + "estree-walker": "^2", + "magic-string": "^0.30.11", + "pathe": "^1.1.2" + }, + "peerDependencies": { + "vite": "<=7.1.7" + } + }, + "node_modules/@module-federation/vite/node_modules/@module-federation/error-codes": { + "version": "0.21.6", + "resolved": "https://registry.npmjs.org/@module-federation/error-codes/-/error-codes-0.21.6.tgz", + "integrity": "sha512-MLJUCQ05KnoVl8xd6xs9a5g2/8U+eWmVxg7xiBMeR0+7OjdWUbHwcwgVFatRIwSZvFgKHfWEiI7wsU1q1XbTRQ==", + "license": "MIT" + }, + "node_modules/@module-federation/vite/node_modules/@module-federation/runtime": { + "version": "0.21.6", + "resolved": "https://registry.npmjs.org/@module-federation/runtime/-/runtime-0.21.6.tgz", + "integrity": "sha512-+caXwaQqwTNh+CQqyb4mZmXq7iEemRDrTZQGD+zyeH454JAYnJ3s/3oDFizdH6245pk+NiqDyOOkHzzFQorKhQ==", + "license": "MIT", + "dependencies": { + "@module-federation/error-codes": "0.21.6", + "@module-federation/runtime-core": "0.21.6", + "@module-federation/sdk": "0.21.6" + } + }, + "node_modules/@module-federation/vite/node_modules/@module-federation/runtime-core": { + "version": "0.21.6", + "resolved": "https://registry.npmjs.org/@module-federation/runtime-core/-/runtime-core-0.21.6.tgz", + "integrity": "sha512-5Hd1Y5qp5lU/aTiK66lidMlM/4ji2gr3EXAtJdreJzkY+bKcI5+21GRcliZ4RAkICmvdxQU5PHPL71XmNc7Lsw==", + "license": "MIT", + "dependencies": { + "@module-federation/error-codes": "0.21.6", + "@module-federation/sdk": "0.21.6" + } + }, + "node_modules/@module-federation/vite/node_modules/@module-federation/sdk": { + "version": "0.21.6", + "resolved": "https://registry.npmjs.org/@module-federation/sdk/-/sdk-0.21.6.tgz", + "integrity": "sha512-x6hARETb8iqHVhEsQBysuWpznNZViUh84qV2yE7AD+g7uIzHKiYdoWqj10posbo5XKf/147qgWDzKZoKoEP2dw==", + "license": "MIT" + }, "node_modules/@monaco-editor/loader": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/@monaco-editor/loader/-/loader-1.7.0.tgz", @@ -6188,10 +6461,9 @@ } }, "node_modules/@parcel/watcher": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.6.tgz", - "integrity": "sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==", - "dev": true, + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.6.0.tgz", + "integrity": "sha512-7FNeNl8NCE7aINx7WXiKQrPYZWC/hvrTsmk6zmxbI7LTXE7hVek/n8AfVgpe2y82zl3w0HvCHN0bVKMBoJcC0w==", "hasInstallScript": true, "license": "MIT", "optional": true, @@ -6199,7 +6471,7 @@ "detect-libc": "^2.0.3", "is-glob": "^4.0.3", "node-addon-api": "^7.0.0", - "picomatch": "^4.0.3" + "picomatch": "^4.0.4" }, "engines": { "node": ">= 10.0.0" @@ -6209,29 +6481,27 @@ "url": "https://opencollective.com/parcel" }, "optionalDependencies": { - "@parcel/watcher-android-arm64": "2.5.6", - "@parcel/watcher-darwin-arm64": "2.5.6", - "@parcel/watcher-darwin-x64": "2.5.6", - "@parcel/watcher-freebsd-x64": "2.5.6", - "@parcel/watcher-linux-arm-glibc": "2.5.6", - "@parcel/watcher-linux-arm-musl": "2.5.6", - "@parcel/watcher-linux-arm64-glibc": "2.5.6", - "@parcel/watcher-linux-arm64-musl": "2.5.6", - "@parcel/watcher-linux-x64-glibc": "2.5.6", - "@parcel/watcher-linux-x64-musl": "2.5.6", - "@parcel/watcher-win32-arm64": "2.5.6", - "@parcel/watcher-win32-ia32": "2.5.6", - "@parcel/watcher-win32-x64": "2.5.6" + "@parcel/watcher-android-arm64": "2.6.0", + "@parcel/watcher-darwin-arm64": "2.6.0", + "@parcel/watcher-darwin-x64": "2.6.0", + "@parcel/watcher-freebsd-x64": "2.6.0", + "@parcel/watcher-linux-arm-glibc": "2.6.0", + "@parcel/watcher-linux-arm-musl": "2.6.0", + "@parcel/watcher-linux-arm64-glibc": "2.6.0", + "@parcel/watcher-linux-arm64-musl": "2.6.0", + "@parcel/watcher-linux-x64-glibc": "2.6.0", + "@parcel/watcher-linux-x64-musl": "2.6.0", + "@parcel/watcher-win32-arm64": "2.6.0", + "@parcel/watcher-win32-x64": "2.6.0" } }, "node_modules/@parcel/watcher-android-arm64": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.6.tgz", - "integrity": "sha512-YQxSS34tPF/6ZG7r/Ih9xy+kP/WwediEUsqmtf0cuCV5TPPKw/PQHRhueUo6JdeFJaqV3pyjm0GdYjZotbRt/A==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.6.0.tgz", + "integrity": "sha512-trgpLSCKRC/huFjXX/Smh+0sWe4+YtKfktIToiMl59ghz7z+qkH6kMvNnUbLyRs9N11t8l4svSCs1+5B3rOAhA==", "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -6246,13 +6516,12 @@ } }, "node_modules/@parcel/watcher-darwin-arm64": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.6.tgz", - "integrity": "sha512-Z2ZdrnwyXvvvdtRHLmM4knydIdU9adO3D4n/0cVipF3rRiwP+3/sfzpAwA/qKFL6i1ModaabkU7IbpeMBgiVEA==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.6.0.tgz", + "integrity": "sha512-Y3QV0gl7Q1zbfueunkWIERICbEojQFCgpyG7YqOGNFLsckXyI1xu9mAIUpKY9QBYzBtSkN8dBPwd3yiAO9ovMw==", "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -6267,13 +6536,12 @@ } }, "node_modules/@parcel/watcher-darwin-x64": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.6.tgz", - "integrity": "sha512-HgvOf3W9dhithcwOWX9uDZyn1lW9R+7tPZ4sug+NGrGIo4Rk1hAXLEbcH1TQSqxts0NYXXlOWqVpvS1SFS4fRg==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.6.0.tgz", + "integrity": "sha512-Ohv6OpzhUfKYD7Beb8kDvG0jbIxORCYY1JRdZnaBtnjjkJxgD7ZVL0nw2sCYd0yTMKTvz3nnTnOF3cDifK+kvw==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -6288,13 +6556,12 @@ } }, "node_modules/@parcel/watcher-freebsd-x64": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.6.tgz", - "integrity": "sha512-vJVi8yd/qzJxEKHkeemh7w3YAn6RJCtYlE4HPMoVnCpIXEzSrxErBW5SJBgKLbXU3WdIpkjBTeUNtyBVn8TRng==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.6.0.tgz", + "integrity": "sha512-5HmXvDgs8VK+74jF9y9/2FE3/OnlcKmc56tjmSrEuZjpSZOGL+fvAu+HKJBdPs9uwoP2hE6TlSUpXZ/C5jUFmQ==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -6309,13 +6576,12 @@ } }, "node_modules/@parcel/watcher-linux-arm-glibc": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.6.tgz", - "integrity": "sha512-9JiYfB6h6BgV50CCfasfLf/uvOcJskMSwcdH1PHH9rvS1IrNy8zad6IUVPVUfmXr+u+Km9IxcfMLzgdOudz9EQ==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.6.0.tgz", + "integrity": "sha512-Ps/hui3A+vMbjdqlqAowK2ZL8+BO8dBjxeWXj6npTBs3jx4wWmbPpaLuqwrQrSqIVMCnpWo238bJ1U37GhQOYg==", "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -6330,13 +6596,12 @@ } }, "node_modules/@parcel/watcher-linux-arm-musl": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.6.tgz", - "integrity": "sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.6.0.tgz", + "integrity": "sha512-9c6AUHgHoG+IY88MRIHupztQiQnrbqHYQjkM2btA+Bf/wQnQMuiD0Wfk1EVv3TlNT3x41uU71rn6E4xh/+zvkw==", "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -6351,13 +6616,12 @@ } }, "node_modules/@parcel/watcher-linux-arm64-glibc": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.6.tgz", - "integrity": "sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.6.0.tgz", + "integrity": "sha512-yHRqS2owEXe6Hic9z6Mh1ECsCd+ODVOGvZDyciqRd21+v+o+DnXMOrw50DSpIG2sb8GPEaPPmfeCAWKPJdq46g==", "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -6372,13 +6636,12 @@ } }, "node_modules/@parcel/watcher-linux-arm64-musl": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.6.tgz", - "integrity": "sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.6.0.tgz", + "integrity": "sha512-WhB2e/V7rqdHHWZusBSPuy5Ei8S6lSz6FE5TKKQz5h3a0O+C+mhY7vxU9b/stqvMb8beLnPY82ZrFTLKs+SrKA==", "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -6393,13 +6656,12 @@ } }, "node_modules/@parcel/watcher-linux-x64-glibc": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.6.tgz", - "integrity": "sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.6.0.tgz", + "integrity": "sha512-ulGE6x6Oz6iAwg75T8YQSoguBWasniIbX+QWpaYPcCnDOpdWX3k+4xbEYPZVLxOuoJI+svJJPD3sEj8G7lrQ3A==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -6414,13 +6676,12 @@ } }, "node_modules/@parcel/watcher-linux-x64-musl": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.6.tgz", - "integrity": "sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.6.0.tgz", + "integrity": "sha512-tkBYKt7YQrjIJWYDnto2YgO8MRkjlMTSNoRHzsXinBqbLdeOM3L32wPZJvIZxqaLMfSlS/4sUjH/6STVP/XDLw==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -6435,34 +6696,12 @@ } }, "node_modules/@parcel/watcher-win32-arm64": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.6.tgz", - "integrity": "sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.6.0.tgz", + "integrity": "sha512-gIZAP23jaHjGWasY/TY6yL7NHFClf0Ga7FN+iINvk+KN94rhm94lYZhFsbYFNcA04/onvGD9kKmiJLJB2HbNwQ==", "cpu": [ "arm64" ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-win32-ia32": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.6.tgz", - "integrity": "sha512-k35yLp1ZMwwee3Ez/pxBi5cf4AoBKYXj00CZ80jUz5h8prpiaQsiRPKQMxoLstNuqe2vR4RNPEAEcjEFzhEz/g==", - "cpu": [ - "ia32" - ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -6477,13 +6716,12 @@ } }, "node_modules/@parcel/watcher-win32-x64": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.6.tgz", - "integrity": "sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.6.0.tgz", + "integrity": "sha512-cA+/pXV2YkfxlIcXOQ5fSWqAzzPyD78/x5qbK/I0vUkrlYHA8TIz+MXjAbGouguKVSI4bOmkTSJ1/poVSsgt+A==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -6497,28 +6735,14 @@ "url": "https://opencollective.com/parcel" } }, - "node_modules/@parcel/watcher/node_modules/picomatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", - "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "node_modules/@pkgr/core": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.3.6.tgz", + "integrity": "sha512-SEeaJLb3qBNF/OaXnaR1NmmBbFYk1zC0ZH/52fATcRPLFg/p791YrcyFFy44Bo9sLaGuSuLp5Q6axbb/O+v/RA==", "dev": true, "license": "MIT", - "optional": true, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/@pkgr/core": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.3.6.tgz", - "integrity": "sha512-SEeaJLb3qBNF/OaXnaR1NmmBbFYk1zC0ZH/52fATcRPLFg/p791YrcyFFy44Bo9sLaGuSuLp5Q6axbb/O+v/RA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^14.18.0 || >=16.0.0" + "node": "^14.18.0 || >=16.0.0" }, "funding": { "url": "https://opencollective.com/pkgr" @@ -6531,15 +6755,15 @@ "license": "MIT" }, "node_modules/@radix-ui/primitive": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.4.tgz", - "integrity": "sha512-7AdCK9PQyiljKoBDbN8OuctCbd/esdwZPQ8RtOE3SsyQtUpiPb+ND75q0jEhC1m1ecBI0MFNeLJvwIh9iKHRcQ==", + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.6.tgz", + "integrity": "sha512-w9hl+724uYEgCGR3bhuRepjBtrNB/6gkhCnAf58Ke+SLbHPPQqVZZB59z60roB+5H+nh3nWTcdJhQdFMEydWmw==", "license": "MIT" }, "node_modules/@radix-ui/react-arrow": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.11.tgz", - "integrity": "sha512-Kdil9BB1rIFC/khmf4hC35bn8701AJcizTU7G7cUbEbk5XqqbjDuHW60uUfKqO5WojjZcbAW51Q7P0hRmMLw8A==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.12.tgz", + "integrity": "sha512-ltXCE0glRomMZ9+u10d9o1Go+edqa1aLxufH59JRNNM3Yz1uvaeNWSaS1HeVh1X64agtdBG5JA1W1I6ySqWiwA==", "license": "MIT", "dependencies": { "@radix-ui/react-primitive": "2.1.7" @@ -6560,18 +6784,17 @@ } }, "node_modules/@radix-ui/react-checkbox": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/@radix-ui/react-checkbox/-/react-checkbox-1.3.7.tgz", - "integrity": "sha512-JroKHfQBfh+fDuzpPsBC+pESkhuq8ql4hljTguz8MWnS35cISr3d/Jhl9kYrB44FlDtxCArYdDvTx+BSsJ64rQ==", + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-checkbox/-/react-checkbox-1.3.8.tgz", + "integrity": "sha512-wfN60IGuxynWK7rP4Ks2p7u9G7gqirzkAiFptuzVbsR1ot2/K+PavNUAtxiKxyRfLOvSbVfvvm9m3rFqLEXz7A==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.5", + "@radix-ui/primitive": "1.1.6", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.2.0", - "@radix-ui/react-presence": "1.1.7", + "@radix-ui/react-presence": "1.1.8", "@radix-ui/react-primitive": "2.1.7", - "@radix-ui/react-use-controllable-state": "1.2.3", - "@radix-ui/react-use-previous": "1.1.2", + "@radix-ui/react-use-controllable-state": "1.2.4", "@radix-ui/react-use-size": "1.1.2" }, "peerDependencies": { @@ -6589,63 +6812,19 @@ } } }, - "node_modules/@radix-ui/react-checkbox/node_modules/@radix-ui/primitive": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.5.tgz", - "integrity": "sha512-d86WIWFYNtGA0H/d8exstrTRTp7eWJYlYJbtNofxr/3ljupZYn6EFDG/Qgu/0Kc8v7yMUxySagqJsL1+PdYjWg==", - "license": "MIT" - }, - "node_modules/@radix-ui/react-checkbox/node_modules/@radix-ui/react-context": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.2.0.tgz", - "integrity": "sha512-fOE+JtN9rygNZkCnHRBEP0TAvLldlhyOxMsbwFvTP4nAs+nBmfnna+o/Zski2wkmY1YMrFC0aSzsHoLY47iLrg==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-checkbox/node_modules/@radix-ui/react-presence": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.7.tgz", - "integrity": "sha512-zBZ4QM5XG3JRanDmqXYf3MD6th4AFXFmgU6KNMFzUaV6F3uw9I5/zjMUvFriSEn5ewo1nxuibvyxJdmLlDcslA==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-use-layout-effect": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, "node_modules/@radix-ui/react-collapsible": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.1.15.tgz", - "integrity": "sha512-8A1zibu5skAQ+UVbaeNH5hVMibiFCRJzgMuM14LTWGttnTZKQL9jwYnhAbHRuxrtCqPXa4JvvnVUq1pTNgyZYw==", + "version": "1.1.17", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.1.17.tgz", + "integrity": "sha512-DJgqGsNXa0df3ifz9PFNgvgj/bzIu5QTVWCt5nQWaUkM6y0EarUv4QG4s6mCoeQdOIyVOT/Q1osFuEGub2TDXQ==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.4", + "@radix-ui/primitive": "1.1.6", "@radix-ui/react-compose-refs": "1.1.3", - "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-context": "1.2.0", "@radix-ui/react-id": "1.1.2", - "@radix-ui/react-presence": "1.1.6", + "@radix-ui/react-presence": "1.1.8", "@radix-ui/react-primitive": "2.1.7", - "@radix-ui/react-use-controllable-state": "1.2.3", + "@radix-ui/react-use-controllable-state": "1.2.4", "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { @@ -6664,13 +6843,13 @@ } }, "node_modules/@radix-ui/react-collection": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.11.tgz", - "integrity": "sha512-djW9+zeg137KQdlPtmE8xnaD+K2rcXXMWFrSg0hsmYZ6HRbdTA7tDHFgpaW9+huWVEu0RCabL+985T4TA0BE7g==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.12.tgz", + "integrity": "sha512-nb67INpE0IahJKN7EYPp9m9YGwYeKlnzxT3MwXVkgCskaSJia97kG4T0ywpjNUSSnoJk/uvk12V8vbrEHEj+/Q==", "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.3", - "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-context": "1.2.0", "@radix-ui/react-primitive": "2.1.7", "@radix-ui/react-slot": "1.3.0" }, @@ -6705,9 +6884,9 @@ } }, "node_modules/@radix-ui/react-context": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.4.tgz", - "integrity": "sha512-QwH4PO5urrbO+FaGd5Aglg+YJgWTyyuZ3g/6mKvsqraLkglDdckw9JafgL5McL5VEJ6EPNduPaT3ZE9BttDAqg==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.2.0.tgz", + "integrity": "sha512-fOE+JtN9rygNZkCnHRBEP0TAvLldlhyOxMsbwFvTP4nAs+nBmfnna+o/Zski2wkmY1YMrFC0aSzsHoLY47iLrg==", "license": "MIT", "peerDependencies": { "@types/react": "*", @@ -6720,23 +6899,24 @@ } }, "node_modules/@radix-ui/react-dialog": { - "version": "1.1.18", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.18.tgz", - "integrity": "sha512-apa28mldjMgORmE6g/w3sCcA0Y9UAVeeDVoozN4i7kOw12mLl9RBchfzK3Nn6qxOWjrZhK1Lfy7f07kyzxtnBw==", + "version": "1.1.20", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.20.tgz", + "integrity": "sha512-cngVJcvK0yMvR7wICJpv+1uW3Qw4T7QM5sdbb+oE/lxOdTdvF00oaRpWUjVgmjyXe3J+xh7eZyXZlVF3g2g59g==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.4", + "@radix-ui/primitive": "1.1.6", "@radix-ui/react-compose-refs": "1.1.3", - "@radix-ui/react-context": "1.1.4", - "@radix-ui/react-dismissable-layer": "1.1.14", + "@radix-ui/react-context": "1.2.0", + "@radix-ui/react-dismissable-layer": "1.1.16", "@radix-ui/react-focus-guards": "1.1.4", - "@radix-ui/react-focus-scope": "1.1.11", + "@radix-ui/react-focus-scope": "1.1.13", "@radix-ui/react-id": "1.1.2", - "@radix-ui/react-portal": "1.1.13", - "@radix-ui/react-presence": "1.1.6", + "@radix-ui/react-portal": "1.1.14", + "@radix-ui/react-presence": "1.1.8", "@radix-ui/react-primitive": "2.1.7", "@radix-ui/react-slot": "1.3.0", - "@radix-ui/react-use-controllable-state": "1.2.3", + "@radix-ui/react-use-controllable-state": "1.2.4", + "@radix-ui/react-use-layout-effect": "1.1.2", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.7.2" }, @@ -6771,12 +6951,12 @@ } }, "node_modules/@radix-ui/react-dismissable-layer": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.14.tgz", - "integrity": "sha512-4lUhWTWAjbDIqFrAPWJ3WqBOpO5YchVZ88X3nh6H9Lu5AFi5nCUeTPj3D8FSDmabmFeRe9ME0BDA4MwKTha5GQ==", + "version": "1.1.16", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.16.tgz", + "integrity": "sha512-t45h68IjFx0ccBnPJqk0X6ecv69LkCFWd6DNCFQX56mUnVEXZbNOLCH/u9fHlAjFZ1RrFdl8/m4zev7B7NyhXQ==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.4", + "@radix-ui/primitive": "1.1.6", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-primitive": "2.1.7", "@radix-ui/react-use-callback-ref": "1.1.2", @@ -6798,18 +6978,18 @@ } }, "node_modules/@radix-ui/react-dropdown-menu": { - "version": "2.1.19", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.19.tgz", - "integrity": "sha512-HZccBkbK0LOi8nYKIp5jll/zIRW0cCOmG6WWyqsSpmXCU+ZlcBbTqIwlBvPCu886C5RVu6c/kHV7xSP8IgYNHw==", + "version": "2.1.21", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.21.tgz", + "integrity": "sha512-gavFM1iWLmWdxWNdGJHVeWeSQul5WE/0pxfvWWt1QnD71hyyujyMCDVacqBomaSOjdxwDzYB+Ng4+MxOvrFB1A==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.4", + "@radix-ui/primitive": "1.1.6", "@radix-ui/react-compose-refs": "1.1.3", - "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-context": "1.2.0", "@radix-ui/react-id": "1.1.2", - "@radix-ui/react-menu": "2.1.19", + "@radix-ui/react-menu": "2.1.21", "@radix-ui/react-primitive": "2.1.7", - "@radix-ui/react-use-controllable-state": "1.2.3" + "@radix-ui/react-use-controllable-state": "1.2.4" }, "peerDependencies": { "@types/react": "*", @@ -6842,9 +7022,9 @@ } }, "node_modules/@radix-ui/react-focus-scope": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.11.tgz", - "integrity": "sha512-Mn88Vg2whaRocGJNOH+DKFqYm6ySFPQaiwHNxZPyjn99B52KAEJWWY9NP83+nWdk2HM3rdov+STu9AG471Rt9w==", + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.13.tgz", + "integrity": "sha512-dE04aPEuP9rvKKT0d0KjSOtTEYNg6bmCYFsoSJpfC+y91Hic28ZfDCGgv6aJ+2Kw/LBXYipMZpyqVj/OD3Z8Gg==", "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.3", @@ -6885,25 +7065,25 @@ } }, "node_modules/@radix-ui/react-menu": { - "version": "2.1.19", - "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.19.tgz", - "integrity": "sha512-Mht9BVd1AIsNFVQr4KG3bIK7XQn5IXF0TL/2ObsrzOdc1loaly/+kBDL5roSCYn8j8XZkvpOD0WYLz2FQtH1Eg==", + "version": "2.1.21", + "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.21.tgz", + "integrity": "sha512-2BHtaJHvvoWTECyrja1mOjN6z2dWdpeHL6b8PxqZYgex8J8xakT2KAchpZIaMwNPauIRHH/VlPJYhSSKe8lz2g==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.4", - "@radix-ui/react-collection": "1.1.11", + "@radix-ui/primitive": "1.1.6", + "@radix-ui/react-collection": "1.1.12", "@radix-ui/react-compose-refs": "1.1.3", - "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-context": "1.2.0", "@radix-ui/react-direction": "1.1.2", - "@radix-ui/react-dismissable-layer": "1.1.14", + "@radix-ui/react-dismissable-layer": "1.1.16", "@radix-ui/react-focus-guards": "1.1.4", - "@radix-ui/react-focus-scope": "1.1.11", + "@radix-ui/react-focus-scope": "1.1.13", "@radix-ui/react-id": "1.1.2", - "@radix-ui/react-popper": "1.3.2", - "@radix-ui/react-portal": "1.1.13", - "@radix-ui/react-presence": "1.1.6", + "@radix-ui/react-popper": "1.3.4", + "@radix-ui/react-portal": "1.1.14", + "@radix-ui/react-presence": "1.1.8", "@radix-ui/react-primitive": "2.1.7", - "@radix-ui/react-roving-focus": "1.1.14", + "@radix-ui/react-roving-focus": "1.1.16", "@radix-ui/react-slot": "1.3.0", "@radix-ui/react-use-callback-ref": "1.1.2", "aria-hidden": "^1.2.4", @@ -6925,24 +7105,24 @@ } }, "node_modules/@radix-ui/react-popover": { - "version": "1.1.19", - "resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.19.tgz", - "integrity": "sha512-jkrTdQVxnIB8fpn0NyyxW9CTB5aCXZZelVz5z+Xmii6g5WxMqS3fInNslZ63puP39+Puu4jYohUK31y3dT87gQ==", + "version": "1.1.20", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.20.tgz", + "integrity": "sha512-/PYqbsyuDkNj+IxMcRx71qNt6GelnuNulMwdCV7AtFEhUyK6XkbwreEN6CCLydMeTiDozBV4uv5aF5d12dDH7w==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.5", + "@radix-ui/primitive": "1.1.6", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.2.0", - "@radix-ui/react-dismissable-layer": "1.1.15", + "@radix-ui/react-dismissable-layer": "1.1.16", "@radix-ui/react-focus-guards": "1.1.4", - "@radix-ui/react-focus-scope": "1.1.12", + "@radix-ui/react-focus-scope": "1.1.13", "@radix-ui/react-id": "1.1.2", - "@radix-ui/react-popper": "1.3.3", - "@radix-ui/react-portal": "1.1.13", - "@radix-ui/react-presence": "1.1.7", + "@radix-ui/react-popper": "1.3.4", + "@radix-ui/react-portal": "1.1.14", + "@radix-ui/react-presence": "1.1.8", "@radix-ui/react-primitive": "2.1.7", "@radix-ui/react-slot": "1.3.0", - "@radix-ui/react-use-controllable-state": "1.2.3", + "@radix-ui/react-use-controllable-state": "1.2.4", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.7.2" }, @@ -6961,144 +7141,16 @@ } } }, - "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/primitive": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.5.tgz", - "integrity": "sha512-d86WIWFYNtGA0H/d8exstrTRTp7eWJYlYJbtNofxr/3ljupZYn6EFDG/Qgu/0Kc8v7yMUxySagqJsL1+PdYjWg==", - "license": "MIT" - }, - "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-context": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.2.0.tgz", - "integrity": "sha512-fOE+JtN9rygNZkCnHRBEP0TAvLldlhyOxMsbwFvTP4nAs+nBmfnna+o/Zski2wkmY1YMrFC0aSzsHoLY47iLrg==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-dismissable-layer": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.15.tgz", - "integrity": "sha512-b0XaRlzn2QKuo10XyNgi2DAJDf5XC9d1nD3FJcuvCjbR7+4Ad28zmZsLsqx+hvDEzMnRuZaZxZm9gYObV6RmRA==", - "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.5", - "@radix-ui/react-compose-refs": "1.1.3", - "@radix-ui/react-primitive": "2.1.7", - "@radix-ui/react-use-callback-ref": "1.1.2", - "@radix-ui/react-use-effect-event": "0.0.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-focus-scope": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.12.tgz", - "integrity": "sha512-jjk/lqTeNL0azUx5ZYzVrl4NgaDIrdzTNE4mABV9yBFI7FQqN7pIgzV1bTleUezP2QiTGA1BFTqY8MegDgWX9A==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.3", - "@radix-ui/react-primitive": "2.1.7", - "@radix-ui/react-use-callback-ref": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-popper": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.3.3.tgz", - "integrity": "sha512-mS7dGpyjv6b+gsDjLF7e0ia1W4Im1B1hSCy2yuXlHuvnZxHKagfDaobt/KAKt27EpZMit2pss8eJBVyVjEWM+g==", - "license": "MIT", - "dependencies": { - "@floating-ui/react-dom": "^2.0.0", - "@radix-ui/react-arrow": "1.1.11", - "@radix-ui/react-compose-refs": "1.1.3", - "@radix-ui/react-context": "1.2.0", - "@radix-ui/react-primitive": "2.1.7", - "@radix-ui/react-use-callback-ref": "1.1.2", - "@radix-ui/react-use-layout-effect": "1.1.2", - "@radix-ui/react-use-rect": "1.1.2", - "@radix-ui/react-use-size": "1.1.2", - "@radix-ui/rect": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-presence": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.7.tgz", - "integrity": "sha512-zBZ4QM5XG3JRanDmqXYf3MD6th4AFXFmgU6KNMFzUaV6F3uw9I5/zjMUvFriSEn5ewo1nxuibvyxJdmLlDcslA==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-use-layout-effect": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, "node_modules/@radix-ui/react-popper": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.3.2.tgz", - "integrity": "sha512-3QXNeMkdshed1MR3LNoiCirBywRFPkD8ETJa/HlPuLwSajaQixf2ro+isoDNJlGABg9ug41XuZpINZJIle4XWg==", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.3.4.tgz", + "integrity": "sha512-PXnCa3XgTQk0FegMctxgqJXtFLZe4IFJdbUkB7jKSCKEpb6utEO4S9Vog/pkyCfEPdzM331gvE4xpztmBAfMng==", "license": "MIT", "dependencies": { "@floating-ui/react-dom": "^2.0.0", - "@radix-ui/react-arrow": "1.1.11", + "@radix-ui/react-arrow": "1.1.12", "@radix-ui/react-compose-refs": "1.1.3", - "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-context": "1.2.0", "@radix-ui/react-primitive": "2.1.7", "@radix-ui/react-use-callback-ref": "1.1.2", "@radix-ui/react-use-layout-effect": "1.1.2", @@ -7122,9 +7174,9 @@ } }, "node_modules/@radix-ui/react-portal": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.13.tgz", - "integrity": "sha512-z3oXfmaHLJTF1wktbjgD6cn9jiEbq3WSondB10LIuIt2m2Ym4iJlrW04/euMwENDdWDdE7z+OuY7Qyp1YpRSwA==", + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.14.tgz", + "integrity": "sha512-REwjAGPMa3J9oyDE4cuWkZbwnCbbyky66NurquQklXMSDn67cl6oGFx2gO7KZhPtFNbNw9xTWNrti3VIhgluYw==", "license": "MIT", "dependencies": { "@radix-ui/react-primitive": "2.1.7", @@ -7146,9 +7198,9 @@ } }, "node_modules/@radix-ui/react-presence": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.6.tgz", - "integrity": "sha512-zdTk4PlUO0E18HnZ3wYbW0KkJJxWCdiNYp6g6X1PtONFhxVkg01vliTJAmwIszU6mHiyBOoW9P0rAugl5/hULQ==", + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.8.tgz", + "integrity": "sha512-0hhyrQdXMaATgq4ammLG9+iPqsXxzZkgTSIxdrJHdfLnXO4Uo5L7BoO3/Xf0AEaettadGZWGGJMw6ujzQvIpGA==", "license": "MIT", "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.2" @@ -7192,20 +7244,22 @@ } }, "node_modules/@radix-ui/react-roving-focus": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.14.tgz", - "integrity": "sha512-8Qcnx9447tx/aCBgw6Jenfqg4Skq+vqab9mCBmuGNipIS5YXvL275wbKEu7+ICYHIlAPgCduUMJH1XOYewKF6Q==", + "version": "1.1.16", + "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.16.tgz", + "integrity": "sha512-w7lLsTSd3940vFYEshKkHw+NGf7H0QDJPHYsy8NRjDCVbO6ZdKW1X/xoJSYHZtttnrdZiYqbN2O/2uHGB0zasw==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.4", - "@radix-ui/react-collection": "1.1.11", + "@radix-ui/primitive": "1.1.6", + "@radix-ui/react-collection": "1.1.12", "@radix-ui/react-compose-refs": "1.1.3", - "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-context": "1.2.0", "@radix-ui/react-direction": "1.1.2", "@radix-ui/react-id": "1.1.2", "@radix-ui/react-primitive": "2.1.7", "@radix-ui/react-use-callback-ref": "1.1.2", - "@radix-ui/react-use-controllable-state": "1.2.3" + "@radix-ui/react-use-controllable-state": "1.2.4", + "@radix-ui/react-use-is-hydrated": "0.1.1", + "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", @@ -7223,17 +7277,17 @@ } }, "node_modules/@radix-ui/react-scroll-area": { - "version": "1.2.14", - "resolved": "https://registry.npmjs.org/@radix-ui/react-scroll-area/-/react-scroll-area-1.2.14.tgz", - "integrity": "sha512-bBODCWZK7JTbQLHs0uIP4f73wIWatakK4OS33UzkR1x897wu0PuO658a3f+6P2GEGyDzGYMuHRatMVoAk9WZTw==", + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-scroll-area/-/react-scroll-area-1.2.15.tgz", + "integrity": "sha512-JVBHNfTBbGd9hhq/xZZOgmVnBCXhLs8PJJ8vMzgwI0pLZNsKckW9pkoqHyxokUCt1hoxbwDNvF9DItEeZsG68g==", "license": "MIT", "dependencies": { "@radix-ui/number": "1.1.2", - "@radix-ui/primitive": "1.1.5", + "@radix-ui/primitive": "1.1.6", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.2.0", "@radix-ui/react-direction": "1.1.2", - "@radix-ui/react-presence": "1.1.7", + "@radix-ui/react-presence": "1.1.8", "@radix-ui/react-primitive": "2.1.7", "@radix-ui/react-use-callback-ref": "1.1.2", "@radix-ui/react-use-layout-effect": "1.1.2" @@ -7253,76 +7307,32 @@ } } }, - "node_modules/@radix-ui/react-scroll-area/node_modules/@radix-ui/primitive": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.5.tgz", - "integrity": "sha512-d86WIWFYNtGA0H/d8exstrTRTp7eWJYlYJbtNofxr/3ljupZYn6EFDG/Qgu/0Kc8v7yMUxySagqJsL1+PdYjWg==", - "license": "MIT" - }, - "node_modules/@radix-ui/react-scroll-area/node_modules/@radix-ui/react-context": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.2.0.tgz", - "integrity": "sha512-fOE+JtN9rygNZkCnHRBEP0TAvLldlhyOxMsbwFvTP4nAs+nBmfnna+o/Zski2wkmY1YMrFC0aSzsHoLY47iLrg==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-scroll-area/node_modules/@radix-ui/react-presence": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.7.tgz", - "integrity": "sha512-zBZ4QM5XG3JRanDmqXYf3MD6th4AFXFmgU6KNMFzUaV6F3uw9I5/zjMUvFriSEn5ewo1nxuibvyxJdmLlDcslA==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-use-layout-effect": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, "node_modules/@radix-ui/react-select": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.3.3.tgz", - "integrity": "sha512-L5RQTXz6Anxsf9CCv+pTgiAsUpyVj7rJxsGtmhFaEOJ++cVfXucv4qWfsIO0AIB4NAhi3yovWGVMKKS1Xf1Wrg==", + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.3.4.tgz", + "integrity": "sha512-E2JxqAvaTUEhWtBptWo02g8FnLYPymv9ahEvW/cZQPPV4ySeyo0M8n3sXccsLUAIfMbexnfXt91qF7UjTbTMMg==", "license": "MIT", "dependencies": { "@radix-ui/number": "1.1.2", - "@radix-ui/primitive": "1.1.5", + "@radix-ui/primitive": "1.1.6", "@radix-ui/react-collection": "1.1.12", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.2.0", "@radix-ui/react-direction": "1.1.2", - "@radix-ui/react-dismissable-layer": "1.1.15", + "@radix-ui/react-dismissable-layer": "1.1.16", "@radix-ui/react-focus-guards": "1.1.4", - "@radix-ui/react-focus-scope": "1.1.12", + "@radix-ui/react-focus-scope": "1.1.13", "@radix-ui/react-id": "1.1.2", - "@radix-ui/react-popper": "1.3.3", - "@radix-ui/react-portal": "1.1.13", - "@radix-ui/react-presence": "1.1.7", + "@radix-ui/react-popper": "1.3.4", + "@radix-ui/react-portal": "1.1.14", + "@radix-ui/react-presence": "1.1.8", "@radix-ui/react-primitive": "2.1.7", "@radix-ui/react-slot": "1.3.0", "@radix-ui/react-use-callback-ref": "1.1.2", - "@radix-ui/react-use-controllable-state": "1.2.3", + "@radix-ui/react-use-controllable-state": "1.2.4", "@radix-ui/react-use-layout-effect": "1.1.2", "@radix-ui/react-use-previous": "1.1.2", - "@radix-ui/react-visually-hidden": "1.2.7", + "@radix-ui/react-visually-hidden": "1.2.8", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.7.2" }, @@ -7335,291 +7345,19 @@ "peerDependenciesMeta": { "@types/react": { "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-select/node_modules/@radix-ui/primitive": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.5.tgz", - "integrity": "sha512-d86WIWFYNtGA0H/d8exstrTRTp7eWJYlYJbtNofxr/3ljupZYn6EFDG/Qgu/0Kc8v7yMUxySagqJsL1+PdYjWg==", - "license": "MIT" - }, - "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-collection": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.12.tgz", - "integrity": "sha512-nb67INpE0IahJKN7EYPp9m9YGwYeKlnzxT3MwXVkgCskaSJia97kG4T0ywpjNUSSnoJk/uvk12V8vbrEHEj+/Q==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.3", - "@radix-ui/react-context": "1.2.0", - "@radix-ui/react-primitive": "2.1.7", - "@radix-ui/react-slot": "1.3.0" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-context": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.2.0.tgz", - "integrity": "sha512-fOE+JtN9rygNZkCnHRBEP0TAvLldlhyOxMsbwFvTP4nAs+nBmfnna+o/Zski2wkmY1YMrFC0aSzsHoLY47iLrg==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-dismissable-layer": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.15.tgz", - "integrity": "sha512-b0XaRlzn2QKuo10XyNgi2DAJDf5XC9d1nD3FJcuvCjbR7+4Ad28zmZsLsqx+hvDEzMnRuZaZxZm9gYObV6RmRA==", - "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.5", - "@radix-ui/react-compose-refs": "1.1.3", - "@radix-ui/react-primitive": "2.1.7", - "@radix-ui/react-use-callback-ref": "1.1.2", - "@radix-ui/react-use-effect-event": "0.0.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-focus-scope": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.12.tgz", - "integrity": "sha512-jjk/lqTeNL0azUx5ZYzVrl4NgaDIrdzTNE4mABV9yBFI7FQqN7pIgzV1bTleUezP2QiTGA1BFTqY8MegDgWX9A==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.3", - "@radix-ui/react-primitive": "2.1.7", - "@radix-ui/react-use-callback-ref": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-popper": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.3.3.tgz", - "integrity": "sha512-mS7dGpyjv6b+gsDjLF7e0ia1W4Im1B1hSCy2yuXlHuvnZxHKagfDaobt/KAKt27EpZMit2pss8eJBVyVjEWM+g==", - "license": "MIT", - "dependencies": { - "@floating-ui/react-dom": "^2.0.0", - "@radix-ui/react-arrow": "1.1.11", - "@radix-ui/react-compose-refs": "1.1.3", - "@radix-ui/react-context": "1.2.0", - "@radix-ui/react-primitive": "2.1.7", - "@radix-ui/react-use-callback-ref": "1.1.2", - "@radix-ui/react-use-layout-effect": "1.1.2", - "@radix-ui/react-use-rect": "1.1.2", - "@radix-ui/react-use-size": "1.1.2", - "@radix-ui/rect": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-presence": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.7.tgz", - "integrity": "sha512-zBZ4QM5XG3JRanDmqXYf3MD6th4AFXFmgU6KNMFzUaV6F3uw9I5/zjMUvFriSEn5ewo1nxuibvyxJdmLlDcslA==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-use-layout-effect": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-separator": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.1.11.tgz", - "integrity": "sha512-jRhe86+8PF7VZ1u14eOWVOuh2BuAhALg/FT1VcMC4OHedMTRUazDnDlKTt+yxo5cRNKHMfmvZ4sSQtWDeMV4CQ==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-primitive": "2.1.7" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-slot": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.3.0.tgz", - "integrity": "sha512-MojKku4U/miO8Av4Dkb+ctMAQx7JmY96LmtDQlAarCRtd7rN52QCSzBF+XAvr5S6coSVj9HEPBgHAHKEJVk/WA==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.3" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-tabs": { - "version": "1.1.17", - "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.17.tgz", - "integrity": "sha512-nRyXnrAVCwjeXcHbvEbLS6ndbTeKHG1RqCP4A8Gw5L4cemDzPXdD8rAmr6wet0v57R69wGvuIIsFjHSVkZiMzQ==", - "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.5", - "@radix-ui/react-context": "1.2.0", - "@radix-ui/react-direction": "1.1.2", - "@radix-ui/react-id": "1.1.2", - "@radix-ui/react-presence": "1.1.7", - "@radix-ui/react-primitive": "2.1.7", - "@radix-ui/react-roving-focus": "1.1.15", - "@radix-ui/react-use-controllable-state": "1.2.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/primitive": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.5.tgz", - "integrity": "sha512-d86WIWFYNtGA0H/d8exstrTRTp7eWJYlYJbtNofxr/3ljupZYn6EFDG/Qgu/0Kc8v7yMUxySagqJsL1+PdYjWg==", - "license": "MIT" - }, - "node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-collection": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.12.tgz", - "integrity": "sha512-nb67INpE0IahJKN7EYPp9m9YGwYeKlnzxT3MwXVkgCskaSJia97kG4T0ywpjNUSSnoJk/uvk12V8vbrEHEj+/Q==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.3", - "@radix-ui/react-context": "1.2.0", - "@radix-ui/react-primitive": "2.1.7", - "@radix-ui/react-slot": "1.3.0" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-context": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.2.0.tgz", - "integrity": "sha512-fOE+JtN9rygNZkCnHRBEP0TAvLldlhyOxMsbwFvTP4nAs+nBmfnna+o/Zski2wkmY1YMrFC0aSzsHoLY47iLrg==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true + }, + "@types/react-dom": { + "optional": true } } }, - "node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-presence": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.7.tgz", - "integrity": "sha512-zBZ4QM5XG3JRanDmqXYf3MD6th4AFXFmgU6KNMFzUaV6F3uw9I5/zjMUvFriSEn5ewo1nxuibvyxJdmLlDcslA==", + "node_modules/@radix-ui/react-separator": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.1.12.tgz", + "integrity": "sha512-2hezgFBBR5jU3S9L9bIZ9Uag6LnvxuFBNsLCfTR8qx+NshuvFmpL4C72+5zMS3Z6UgHNSU1thOw2UaBBPEDpsQ==", "license": "MIT", "dependencies": { - "@radix-ui/react-use-layout-effect": "1.1.2" + "@radix-ui/react-primitive": "2.1.7" }, "peerDependencies": { "@types/react": "*", @@ -7636,23 +7374,38 @@ } } }, - "node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-roving-focus": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.15.tgz", - "integrity": "sha512-40svmmugfM3mUN7VUDGVE1tQGOhyi8enlGD0CNJEcMM36C1f71PKM21DFgNHUfem0XnA+d8H8oN3Z9ZpJjSslg==", + "node_modules/@radix-ui/react-slot": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.3.0.tgz", + "integrity": "sha512-MojKku4U/miO8Av4Dkb+ctMAQx7JmY96LmtDQlAarCRtd7rN52QCSzBF+XAvr5S6coSVj9HEPBgHAHKEJVk/WA==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.5", - "@radix-ui/react-collection": "1.1.12", - "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tabs": { + "version": "1.1.18", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.18.tgz", + "integrity": "sha512-1zq2XkQkK/KfbZn84edytYpOLquhNalra5LXc3NAMKhNRSGtyXqjMv6OyC9jlSuNKpqvQtsb57WKoICNk1v/sQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.6", "@radix-ui/react-context": "1.2.0", "@radix-ui/react-direction": "1.1.2", "@radix-ui/react-id": "1.1.2", + "@radix-ui/react-presence": "1.1.8", "@radix-ui/react-primitive": "2.1.7", - "@radix-ui/react-use-callback-ref": "1.1.2", - "@radix-ui/react-use-controllable-state": "1.2.3", - "@radix-ui/react-use-is-hydrated": "0.1.1", - "@radix-ui/react-use-layout-effect": "1.1.2" + "@radix-ui/react-roving-focus": "1.1.16", + "@radix-ui/react-use-controllable-state": "1.2.4" }, "peerDependencies": { "@types/react": "*", @@ -7670,23 +7423,24 @@ } }, "node_modules/@radix-ui/react-tooltip": { - "version": "1.2.11", - "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.2.11.tgz", - "integrity": "sha512-8XZ6Py3y3W2nEzAUGCN5cfVKaUi+CVApcz1d6lrNVVf2hvYEixMRkq8k9ggPKnQUpRRuOV5avt8uvxViH2jLwA==", + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.2.13.tgz", + "integrity": "sha512-56XPNYGMnGBcPyiBTaEXB7IGPybbsdNkFgSv90SCrHkXnu2Av1HhsyZMegzXlTu/QHA3V6/l22GZCv9iEoiqmQ==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.4", + "@radix-ui/primitive": "1.1.6", "@radix-ui/react-compose-refs": "1.1.3", - "@radix-ui/react-context": "1.1.4", - "@radix-ui/react-dismissable-layer": "1.1.14", + "@radix-ui/react-context": "1.2.0", + "@radix-ui/react-dismissable-layer": "1.1.16", "@radix-ui/react-id": "1.1.2", - "@radix-ui/react-popper": "1.3.2", - "@radix-ui/react-portal": "1.1.13", - "@radix-ui/react-presence": "1.1.6", + "@radix-ui/react-popper": "1.3.4", + "@radix-ui/react-portal": "1.1.14", + "@radix-ui/react-presence": "1.1.8", "@radix-ui/react-primitive": "2.1.7", "@radix-ui/react-slot": "1.3.0", - "@radix-ui/react-use-controllable-state": "1.2.3", - "@radix-ui/react-visually-hidden": "1.2.7" + "@radix-ui/react-use-controllable-state": "1.2.4", + "@radix-ui/react-use-layout-effect": "1.1.2", + "@radix-ui/react-visually-hidden": "1.2.8" }, "peerDependencies": { "@types/react": "*", @@ -7719,11 +7473,12 @@ } }, "node_modules/@radix-ui/react-use-controllable-state": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.3.tgz", - "integrity": "sha512-PLzC90MS+ReootmjC597dvopoelpZ8Q61HJkDXZSExitIq7PL55vHNnesAHwguHK0aPfBnpdNzQtv1uliaqQrA==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.4.tgz", + "integrity": "sha512-cx2DixxmSfjCcEoRvDvy1NLd6SWK94XFcEEOZUcharUlXbmahFQGKCfwdKZL2ub34iIwOPOEFVF80xb+yfLYiA==", "license": "MIT", "dependencies": { + "@radix-ui/primitive": "1.1.6", "@radix-ui/react-use-effect-event": "0.0.3", "@radix-ui/react-use-layout-effect": "1.1.2" }, @@ -7837,9 +7592,9 @@ } }, "node_modules/@radix-ui/react-visually-hidden": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.7.tgz", - "integrity": "sha512-1wNZBggTDK3GRuuQ6nP4k2yi7a6l7I5qbMPbZcRsrGsGVead/f/d5FhEzUvqFs0bcrDLx7n1zKQ3JvLR6whaaw==", + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.8.tgz", + "integrity": "sha512-FjsQEpkNBJJYiPSat6jh2LGKLPX2jAoDVS3AZSBNX3cOUoEGhw/f+z2FCY8Cf1NkoYIbytJ1f4mlWPQpR+MjVg==", "license": "MIT", "dependencies": { "@radix-ui/react-primitive": "2.1.7" @@ -8176,17 +7931,25 @@ "license": "MIT" }, "node_modules/@rollup/pluginutils": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.2.1.tgz", - "integrity": "sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==", - "dev": true, + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.4.0.tgz", + "integrity": "sha512-MfPp06CjRLfXQ3wY0R8vJDYBy/MvVcc9OulEfR0B8Iv9ko+GCNaRZ+EpJYFl27LhKsZK0o420sYCRHCjfCgeUg==", "license": "MIT", "dependencies": { - "estree-walker": "^2.0.1", - "picomatch": "^2.2.2" + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^4.0.2" }, "engines": { - "node": ">= 8.0.0" + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } } }, "node_modules/@rollup/rollup-android-arm-eabi": { @@ -8196,7 +7959,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -8210,7 +7972,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -8224,7 +7985,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -8238,7 +7998,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -8252,7 +8011,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -8266,7 +8024,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -8280,7 +8037,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -8294,7 +8050,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -8308,7 +8063,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -8322,7 +8076,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -8336,7 +8089,6 @@ "cpu": [ "loong64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -8350,7 +8102,6 @@ "cpu": [ "loong64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -8364,7 +8115,6 @@ "cpu": [ "ppc64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -8378,7 +8128,6 @@ "cpu": [ "ppc64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -8392,7 +8141,6 @@ "cpu": [ "riscv64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -8406,7 +8154,6 @@ "cpu": [ "riscv64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -8420,7 +8167,6 @@ "cpu": [ "s390x" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -8434,7 +8180,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -8448,7 +8193,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -8462,7 +8206,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -8476,7 +8219,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -8490,7 +8232,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -8504,7 +8245,6 @@ "cpu": [ "ia32" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -8518,7 +8258,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -8532,7 +8271,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -8547,9 +8285,9 @@ "license": "MIT" }, "node_modules/@sinclair/typebox": { - "version": "0.27.10", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.10.tgz", - "integrity": "sha512-MTBk/3jGLNB2tVxv6uLlFh1iu64iYOQ2PbdOSK3NW8JZsmlaOh2q6sdtKowBhfw8QFLmYNzTW4/oK4uATIi6ZA==", + "version": "0.27.12", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.12.tgz", + "integrity": "sha512-hhyNJ+nbR6ZR7pToHvllEFun9TL0sbL+tk/ON75lo+Xas054uez98qRbsuNt7MBCyZKK4+8Yli/OAGZhmfBZ/g==", "dev": true, "license": "MIT" }, @@ -9330,9 +9068,9 @@ } }, "node_modules/@swc/core": { - "version": "1.15.43", - "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.15.43.tgz", - "integrity": "sha512-1CuKjFkPxIgGdeHVuNbkxmBxkcbdc08u0aiI43pFq6yY1tTVKmXT9hFEooyyKs/sJ3xf1GPHyEwTtk9Xl8dvQw==", + "version": "1.15.46", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.15.46.tgz", + "integrity": "sha512-Ri3em2mBpq3h2zSPliCYl63otDGqek8PPEfv2nWgRQEbZ/VBCNyypVTVQ6cEbTCXBhy+WE2T3fQb08moIyuYaw==", "dev": true, "hasInstallScript": true, "license": "Apache-2.0", @@ -9348,18 +9086,18 @@ "url": "https://opencollective.com/swc" }, "optionalDependencies": { - "@swc/core-darwin-arm64": "1.15.43", - "@swc/core-darwin-x64": "1.15.43", - "@swc/core-linux-arm-gnueabihf": "1.15.43", - "@swc/core-linux-arm64-gnu": "1.15.43", - "@swc/core-linux-arm64-musl": "1.15.43", - "@swc/core-linux-ppc64-gnu": "1.15.43", - "@swc/core-linux-s390x-gnu": "1.15.43", - "@swc/core-linux-x64-gnu": "1.15.43", - "@swc/core-linux-x64-musl": "1.15.43", - "@swc/core-win32-arm64-msvc": "1.15.43", - "@swc/core-win32-ia32-msvc": "1.15.43", - "@swc/core-win32-x64-msvc": "1.15.43" + "@swc/core-darwin-arm64": "1.15.46", + "@swc/core-darwin-x64": "1.15.46", + "@swc/core-linux-arm-gnueabihf": "1.15.46", + "@swc/core-linux-arm64-gnu": "1.15.46", + "@swc/core-linux-arm64-musl": "1.15.46", + "@swc/core-linux-ppc64-gnu": "1.15.46", + "@swc/core-linux-s390x-gnu": "1.15.46", + "@swc/core-linux-x64-gnu": "1.15.46", + "@swc/core-linux-x64-musl": "1.15.46", + "@swc/core-win32-arm64-msvc": "1.15.46", + "@swc/core-win32-ia32-msvc": "1.15.46", + "@swc/core-win32-x64-msvc": "1.15.46" }, "peerDependencies": { "@swc/helpers": ">=0.5.17" @@ -9371,9 +9109,9 @@ } }, "node_modules/@swc/core-darwin-arm64": { - "version": "1.15.43", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.15.43.tgz", - "integrity": "sha512-v1aVuvXdo/BHxJzco9V2xpHrvwWmhfS8t6gziY5wJxd+Z2h8AeJRnAwPD8itCDaGXVBwJ/CaKfxEzTkG0Va0OA==", + "version": "1.15.46", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.15.46.tgz", + "integrity": "sha512-IsISIT22EfktVJrlvIpnAxG2u/A9aob9l99HMlx80x72WlFmFPk1V3UhkEzx86eJP8hw049KTFv/RISho2cq2Q==", "cpu": [ "arm64" ], @@ -9388,9 +9126,9 @@ } }, "node_modules/@swc/core-darwin-x64": { - "version": "1.15.43", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.15.43.tgz", - "integrity": "sha512-lp3d4Lamc8dt5huYdGLSR+9hLxmfr1jb0l+4XXG2zPqZwYWRN9R0U2qYoTrggiU2RWW0oV9VbWM3kBnqIc2kdQ==", + "version": "1.15.46", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.15.46.tgz", + "integrity": "sha512-4Tj4ppVIPCmUMpmGFiGtyEriwLyJ+yi/US4WfBrP/ok8COGddDZXLEzQETnKyK46mjvr1v0jevrS23zjoff7vA==", "cpu": [ "x64" ], @@ -9405,9 +9143,9 @@ } }, "node_modules/@swc/core-linux-arm-gnueabihf": { - "version": "1.15.43", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.15.43.tgz", - "integrity": "sha512-JWTQQELtsG5GgphDrr/XqqmM2pDN3cZqbMS0Mrg+iTiXL3F74sn/S2IyYE/5u4h2KLkTf9qQ7dXyxsbx7YzkeA==", + "version": "1.15.46", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.15.46.tgz", + "integrity": "sha512-i8tUGnNjyOgMmfmgFSg4aeJLQoFyfpIHK5FjpQAwpRyQIqEUB2w1e8zIDQzY1WhOxx8NoS1S5iUL813Un4Sf5A==", "cpu": [ "arm" ], @@ -9422,9 +9160,9 @@ } }, "node_modules/@swc/core-linux-arm64-gnu": { - "version": "1.15.43", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.15.43.tgz", - "integrity": "sha512-B4otJRdPWIsmiSBf0uG7Z/+vMWmkufjz5MmYxubwKuZazDW14Zd3symga1N62QR4RT+kEFeHEgsXfZGyn/w0hw==", + "version": "1.15.46", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.15.46.tgz", + "integrity": "sha512-c0OnhqzdhfOvv6qhNCcByepB+sNYOGZyhtr2Qa6ZCHvAWTYhSRw4j/u92Stue9PbZ/6q74b9nHzi76+kVzqQHQ==", "cpu": [ "arm64" ], @@ -9439,9 +9177,9 @@ } }, "node_modules/@swc/core-linux-arm64-musl": { - "version": "1.15.43", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.15.43.tgz", - "integrity": "sha512-6zB6OnpViBxYy4tgY3v2i6AZY9fwkcHZ032UOwtwUuW1d19sdT07qF0kZe6/3UR1tUaK6jjg2rmVcUIBCEYVjQ==", + "version": "1.15.46", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.15.46.tgz", + "integrity": "sha512-imyRpNEcUzFQFV2LE4jL68ErvmKEuZCbvZru77iQREunJ+bR4i658cupTgtG1mLYM3F1Tzy3Sb9xYb02KghWTg==", "cpu": [ "arm64" ], @@ -9456,9 +9194,9 @@ } }, "node_modules/@swc/core-linux-ppc64-gnu": { - "version": "1.15.43", - "resolved": "https://registry.npmjs.org/@swc/core-linux-ppc64-gnu/-/core-linux-ppc64-gnu-1.15.43.tgz", - "integrity": "sha512-coxE1ZWdB3uSDVNoEtYNrRi/1epvckZx9cTJ8ICUxTMTxGk+yvQ/Twacp3ruZSaMPGCriUjP86C37VhaT6nyRg==", + "version": "1.15.46", + "resolved": "https://registry.npmjs.org/@swc/core-linux-ppc64-gnu/-/core-linux-ppc64-gnu-1.15.46.tgz", + "integrity": "sha512-ctEfcl/HcUeomK33cbySiHZm98GEDIxTm1EkpBsYCiHxElYBzvTXVeuQT2YwbUXn9XCrjiw4ipyUNk33k26qRg==", "cpu": [ "ppc64" ], @@ -9473,9 +9211,9 @@ } }, "node_modules/@swc/core-linux-s390x-gnu": { - "version": "1.15.43", - "resolved": "https://registry.npmjs.org/@swc/core-linux-s390x-gnu/-/core-linux-s390x-gnu-1.15.43.tgz", - "integrity": "sha512-lXfLhs+LpBsD5inuYx+YDH5WsPPBQ95KPUiy8P5wq9ob9xKDZFqwNfU2QW6bGO8NqRO/H9JQomTSt5Yyh+FGfA==", + "version": "1.15.46", + "resolved": "https://registry.npmjs.org/@swc/core-linux-s390x-gnu/-/core-linux-s390x-gnu-1.15.46.tgz", + "integrity": "sha512-DxlMdnt84TtRVTv7WL/thWyz9+QU8QZNNoAP9rrk0P68LziuhfePp8MjQ44zIprpTHTsEwyziIuGUUN5iSC1bQ==", "cpu": [ "s390x" ], @@ -9490,9 +9228,9 @@ } }, "node_modules/@swc/core-linux-x64-gnu": { - "version": "1.15.43", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.15.43.tgz", - "integrity": "sha512-07XnKwTmKy8TGOZG3D9fRnLWGynxPjwQnZLVmBFbo6F+7vHYzBIOuwXEhemrChBWb6yDNZsVCcMWCPX6FDD2xg==", + "version": "1.15.46", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.15.46.tgz", + "integrity": "sha512-SKxI7J6t90XPl8hRUqtJi9NfGdunN/E/vZMc7Bc0figeRdOPDBT+Tm8g7cx9xM0T0mewh2l+8dewa3Am27/P+A==", "cpu": [ "x64" ], @@ -9507,9 +9245,9 @@ } }, "node_modules/@swc/core-linux-x64-musl": { - "version": "1.15.43", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.15.43.tgz", - "integrity": "sha512-TJc+bsSIaBh+hZvZ5GRtW/K1bw66TJ9vsUwvVIsZdiWxU5ObLwZvfcnZ3UpgVfMnFibRes9uriJrQNBHEEogRQ==", + "version": "1.15.46", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.15.46.tgz", + "integrity": "sha512-qj9T6B7bosI0VEsrWOVXZN1OXxS8Tp63ywyrLxNdOycnUtLdkgYcoBsN5y8ImnDDsnwrEWZOy1e+J4xSe7mA3Q==", "cpu": [ "x64" ], @@ -9524,9 +9262,9 @@ } }, "node_modules/@swc/core-win32-arm64-msvc": { - "version": "1.15.43", - "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.15.43.tgz", - "integrity": "sha512-jfd7s2/bUQYkOHLs+LWQNKZdmDa8+sufKLllhpWAhVQ2GDCwsHe3vR/j+OSiItZNtkzFuaawa3+SAKz9y5gYfw==", + "version": "1.15.46", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.15.46.tgz", + "integrity": "sha512-8p7l4c3LU+eA5g9Et1JPhNeMC1oQwXTGU+uah8DPIBX7YXzqswvaBtyKVmXefVGi/DJU1x3YJsc3mbAp9aWzSQ==", "cpu": [ "arm64" ], @@ -9541,9 +9279,9 @@ } }, "node_modules/@swc/core-win32-ia32-msvc": { - "version": "1.15.43", - "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.15.43.tgz", - "integrity": "sha512-rLAE8JvucqEW1ZGohxPQrQWPBQeJG4+ypKbWfdlU/qmKScvCkxf9/Jxnzki1dkUQCQ7P5Enp13RlvqOlvx/32g==", + "version": "1.15.46", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.15.46.tgz", + "integrity": "sha512-tUEnfr3Bn9u6FOjUb3PN9p+09qZC2j+wNDLKHzXXZn22rqGcUqR/ohCRSS+nG9B9+X+U+3FewNEHJkTmdIvMjQ==", "cpu": [ "ia32" ], @@ -9558,9 +9296,9 @@ } }, "node_modules/@swc/core-win32-x64-msvc": { - "version": "1.15.43", - "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.15.43.tgz", - "integrity": "sha512-h8MLDHZcfIukwQWj03rIJZx1I0E81AYj2X7J/nGErG4nz+QAv6G1Z+peotvinL3lqpbo32tLYSMFo32/ySzxKg==", + "version": "1.15.46", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.15.46.tgz", + "integrity": "sha512-Vux7UDzBJYQggSuPfcl2w9iu+IJpgpRCxHzgCaVkELnAXAE4XZMOTX9HNcaNiwfeIDqdu2rkr69RuDm6wY8neA==", "cpu": [ "x64" ], @@ -9621,12 +9359,12 @@ } }, "node_modules/@tanstack/react-virtual": { - "version": "3.14.5", - "resolved": "https://registry.npmjs.org/@tanstack/react-virtual/-/react-virtual-3.14.5.tgz", - "integrity": "sha512-4EKRXh7zBLkbKbFmG3AUVkircuHd+7OdT1pocJSepxtfBd3qnrJgJ5rtPkRYyo9fmyVb2+pI2xPy5oYvMLQy6A==", + "version": "3.14.8", + "resolved": "https://registry.npmjs.org/@tanstack/react-virtual/-/react-virtual-3.14.8.tgz", + "integrity": "sha512-O39GJQpAYEJcIu3uN1//YtmhjSEOyw75vg9CKCatBDPiD5hKtZQoJHfferyrB/LdOD3UWaoMLWtdEjarwIwdDw==", "license": "MIT", "dependencies": { - "@tanstack/virtual-core": "3.17.3" + "@tanstack/virtual-core": "3.17.6" }, "funding": { "type": "github", @@ -9651,9 +9389,9 @@ } }, "node_modules/@tanstack/virtual-core": { - "version": "3.17.3", - "resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.17.3.tgz", - "integrity": "sha512-8Np/TFELpI0ySuJoVmjvOrQYXH/8sTX0Biv9szhFhY39xOdAAY+smrMxjxOum/ux3eM8MUJQsEJ0/R0UpvC8dw==", + "version": "3.17.6", + "resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.17.6.tgz", + "integrity": "sha512-h0/Ebo18CkOrChlQIhNtQkM5ySUnh/GumQ/D1st3hG2HWUPEF+ILUc2k29UtivCi/9G7w7G3/f7Xyd5cCFbKBw==", "license": "MIT", "funding": { "type": "github", @@ -10029,9 +9767,9 @@ "license": "MIT" }, "node_modules/@types/d3-random": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-3.0.3.tgz", - "integrity": "sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-3.0.4.tgz", + "integrity": "sha512-UHYId5WTCx4L4YNel7NU00XUXXgvgpgZOvp10PuvsQENjMDXhh2RyFc0KBjO7B45ne4Ha1yVH7ii0vnzKkuzWA==", "license": "MIT" }, "node_modules/@types/d3-scale": { @@ -10123,7 +9861,6 @@ "version": "1.0.9", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", - "dev": true, "license": "MIT" }, "node_modules/@types/geojson": { @@ -10230,10 +9967,10 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "26.1.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-26.1.0.tgz", - "integrity": "sha512-O0A1G3xPGy4w7AgQdAQYUlQ+BKk2Oovw8eRpofyp5KdBZULnbe+WqaOVNrm705SHphCiG4XHsACrSmPu1f+Kgw==", - "dev": true, + "version": "26.1.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-26.1.1.tgz", + "integrity": "sha512-nxAkRSVkN1Y0JC1W8ky/fTfkGsMmcrRsbx+3XoZE+rMOX71kLYTV7fLXpqud1GpbpP5TuffXFqfX7fH2GgZREw==", + "devOptional": true, "license": "MIT", "dependencies": { "undici-types": "~8.3.0" @@ -10370,16 +10107,16 @@ } }, "node_modules/@vitest/expect": { - "version": "4.1.9", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.9.tgz", - "integrity": "sha512-vl/rYsUKcBr3SnQn166+XR5ZQcgMx3DQhFWdfli/cWpLnLUmbxZvyrJZotLFUryib+LtArYMSTJ5RbQ57ZqrlA==", + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.10.tgz", + "integrity": "sha512-YsCn+qAk1GWjQOWFEsEcL2gNQ0zmVmQu3T03qP6UyjhtmdtwtbuI+DASn/7iQB3HGTXkdBwGddzxPlmiql5vlA==", "dev": true, "license": "MIT", "dependencies": { "@standard-schema/spec": "^1.1.0", "@types/chai": "^5.2.2", - "@vitest/spy": "4.1.9", - "@vitest/utils": "4.1.9", + "@vitest/spy": "4.1.10", + "@vitest/utils": "4.1.10", "chai": "^6.2.2", "tinyrainbow": "^3.1.0" }, @@ -10398,13 +10135,13 @@ } }, "node_modules/@vitest/mocker": { - "version": "4.1.9", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.9.tgz", - "integrity": "sha512-EVkXzBjrPGM+cK8/ANWgBrkUCfJfb38/EfTSO8h7pWvKkyPkpWxvR7BkD2MyItMF62C97zAEoqdpUixwR/e+Rw==", + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.10.tgz", + "integrity": "sha512-v0xaezt+DKEmKfaxg133ldzADrwLGd7Ze1MfQQTYfvs8OqZIwbxyxaYURivwV7sWy5fqn3rH5uOrSp07bp44Ow==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/spy": "4.1.9", + "@vitest/spy": "4.1.10", "estree-walker": "^3.0.3", "magic-string": "^0.30.21" }, @@ -10435,9 +10172,9 @@ } }, "node_modules/@vitest/pretty-format": { - "version": "4.1.9", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.9.tgz", - "integrity": "sha512-s0iufns3iIFitdgm+YR7g1whCAaGtXz459VS9/PqyKDEEFgYIhsHOQmXgIgDuYCt7DeQmiZT0Qe2OA2p4ZPu5A==", + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.10.tgz", + "integrity": "sha512-W1HsjSH4MXQ9YfmmhLAoIYf1HRfekQCGngeIgcei6MP5QQGWUe0gkopdZQaVCFO+JDJMrAJGwa5pRpNpvy4P8Q==", "dev": true, "license": "MIT", "dependencies": { @@ -10448,28 +10185,35 @@ } }, "node_modules/@vitest/runner": { - "version": "4.1.9", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.9.tgz", - "integrity": "sha512-KXLMDtc7oe70+3mJfGrPUWPesswH+3sTxAMAMl8DG7I8IUQT4XW718dY5ID3vPUcmlu27CcKfY4P3h3I29SLJg==", + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.10.tgz", + "integrity": "sha512-IKI6kpIH+LmpROplyLwBBaCfMgOZOMsygVa6BARD6ahA04VRuJSa6OaVG7kRvSEMD870Vd91rSSw0eegtWyLGg==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/utils": "4.1.9", + "@vitest/utils": "4.1.10", "pathe": "^2.0.3" }, "funding": { "url": "https://opencollective.com/vitest" } }, + "node_modules/@vitest/runner/node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, "node_modules/@vitest/snapshot": { - "version": "4.1.9", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.9.tgz", - "integrity": "sha512-Jc7RKGNBo8Z28WYIm0Niej4xdSPByRf6mU58VpHQkd6Zh05rlnA+twjbK5HyeIGHxrzsc3mJgS43uM0CZKzaIA==", + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.10.tgz", + "integrity": "sha512-xRkfOT1qpTAi/Ti4Y1LtfRc3kEuqxGw59eN2jN9pRWMtS/XDevekhcFSqvQqjUNGksfjMJu3Y+oJ+4Ypn2OaJw==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.1.9", - "@vitest/utils": "4.1.9", + "@vitest/pretty-format": "4.1.10", + "@vitest/utils": "4.1.10", "magic-string": "^0.30.21", "pathe": "^2.0.3" }, @@ -10477,10 +10221,17 @@ "url": "https://opencollective.com/vitest" } }, + "node_modules/@vitest/snapshot/node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, "node_modules/@vitest/spy": { - "version": "4.1.9", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.9.tgz", - "integrity": "sha512-fHpsS6mIi+PiEW+vcRVOMkX1oSaPKne3VOclSFICPcGOmfKgXPU5iAah+wcNcj2xPrCCmfq99IDGf+EojhhvhA==", + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.10.tgz", + "integrity": "sha512-PLf/Ugvoq5wO/b4rwYCR1h2PSIdXz7wnkQFMiUpLdtM7l6pqVFcQIBEHyT1+l+cj7mNwAfZHzqXqDyjvOuwbDw==", "dev": true, "license": "MIT", "funding": { @@ -10488,13 +10239,13 @@ } }, "node_modules/@vitest/utils": { - "version": "4.1.9", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.9.tgz", - "integrity": "sha512-A51o8ymO5PpqlWNnBP9ZHPXDIpuMtTLlGSjN7la4US+LJzoUMyhwjA5QXlm39JexgwHKW4Xjs8Z2d3dLCXOeuA==", + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.10.tgz", + "integrity": "sha512-fy9am/HWxbaGt/Sawrp90vt6Y6jQwf1RX77cz3uwoJwJVMli/e1IEwRPnMNJ7vKfPTwo0diXifkpPvwH9v7nGA==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.1.9", + "@vitest/pretty-format": "4.1.10", "convert-source-map": "^2.0.0", "tinyrainbow": "^3.1.0" }, @@ -10725,9 +10476,9 @@ "peer": true }, "node_modules/@zip.js/zip.js": { - "version": "2.8.26", - "resolved": "https://registry.npmjs.org/@zip.js/zip.js/-/zip.js-2.8.26.tgz", - "integrity": "sha512-RQ4h9F6DOiHxpdocUDrOl6xBM+yOtz+LkUol47AVWcfebGBDpZ7w7Xvz9PS24JgXvLGiXXzSAfdCdVy1tPlaFA==", + "version": "2.8.33", + "resolved": "https://registry.npmjs.org/@zip.js/zip.js/-/zip.js-2.8.33.tgz", + "integrity": "sha512-Mc+s4DdDl9lmhFmkOmNDryC/b4rZm7y2/qBUQTCwPYGkQ8dkCeykILqEYBd+14ATuj93XWZJBrPe2x+cF9LcGA==", "dev": true, "license": "BSD-3-Clause", "engines": { @@ -10740,7 +10491,6 @@ "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "dev": true, "license": "MIT", "dependencies": { "mime-types": "~2.1.34", @@ -10796,6 +10546,15 @@ "node": ">=8.9" } }, + "node_modules/adm-zip": { + "version": "0.5.18", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.18.tgz", + "integrity": "sha512-ufJnssQGbxzLNS1Ho9bCtX4rQKCCvoVuDLHoJyc3F9dOGDB4BkWs2Ci0kv53lqocAEQ/Cbi+I2XCsNYGqVYqng==", + "license": "MIT", + "engines": { + "node": ">=12.0" + } + }, "node_modules/agent-base": { "version": "7.1.4", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", @@ -10878,6 +10637,15 @@ "ajv": "^6.9.1" } }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/ansi-regex": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", @@ -10922,6 +10690,19 @@ "node": ">= 8" } }, + "node_modules/anymatch/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/arg": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", @@ -11239,16 +11020,15 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", - "dev": true, "license": "ISC", "engines": { "node": ">= 4.0.0" } }, "node_modules/autoprefixer": { - "version": "10.5.2", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.5.2.tgz", - "integrity": "sha512-rD5t5DwOjJdmSORcTq64j8MawTC+tbQ+HHqjR4NDumamy/ambn1UJrlKL+KdwujWxMkFjPM3pPHOEA9tl4767Q==", + "version": "10.5.4", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.5.4.tgz", + "integrity": "sha512-MaU0U/za7N3r6brxD4YB/l4NSrFzLPlANv6wEuQVaIPlD3L4W9rFcQPbL/EilY9BHhHvhfcz3gInDLrEtWT4EA==", "dev": true, "funding": [ { @@ -11266,8 +11046,8 @@ ], "license": "MIT", "dependencies": { - "browserslist": "^4.28.4", - "caniuse-lite": "^1.0.30001799", + "browserslist": "^4.28.6", + "caniuse-lite": "^1.0.30001806", "fraction.js": "^5.3.4", "picocolors": "^1.1.1", "postcss-value-parser": "^4.2.0" @@ -11749,9 +11529,9 @@ } }, "node_modules/baseline-browser-mapping": { - "version": "2.10.40", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.40.tgz", - "integrity": "sha512-BSSLZ9/Cjjv7Gtj5B68ZzXcXUg8iOf3fme+FCuh8rC/Go+Kmh8cox7M3A8dolou16s64QjLPOSdngh7GxXvkSw==", + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.0.tgz", + "integrity": "sha512-oCu2wfipvX3AePSgmOuKkIywOu+8n9psz7hXYmk56ghpu3+7KzNIBopaOs4c9BrtdnTtW30unG9GTfHo7EwERQ==", "dev": true, "license": "Apache-2.0", "bin": { @@ -11865,9 +11645,9 @@ } }, "node_modules/body-parser": { - "version": "1.20.5", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.5.tgz", - "integrity": "sha512-3grm+/2tUOvu2cjJkvsIxrv/wVpfXQW4PsQHYm7yk4vfpu7Ekl6nEsYBoJUL6qDwZUx8wUhQ8tR2qz+ad9c9OA==", + "version": "1.20.6", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.6.tgz", + "integrity": "sha512-p5tAzS57i5MV9fZFDj9LeIiTZEufbSe2eDozP+ElheSUq1m74CRq1jI4mYNDdVs9vQztXFLuk/Gd6BWTdwRJ5g==", "dev": true, "license": "MIT", "dependencies": { @@ -11947,9 +11727,9 @@ "peer": true }, "node_modules/browserslist": { - "version": "4.28.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.4.tgz", - "integrity": "sha512-MTc8i/x9jBQd1iMw2CFGS+rwMa07eYjLR0CCTLDACl9xhxy+nIs3KeML/biicXtk9JrZ6dnnTatmc7ErPXIxqw==", + "version": "4.28.7", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.7.tgz", + "integrity": "sha512-JxV13hNrFxqjOc8alRbq9dK1MM79NEXYpma2B2J4wAtpWS5zIEIKqWPGCl7N4o7Uc7B7itylh7SuDujATRyyTw==", "dev": true, "funding": [ { @@ -11967,10 +11747,10 @@ ], "license": "MIT", "dependencies": { - "baseline-browser-mapping": "^2.10.38", - "caniuse-lite": "^1.0.30001799", - "electron-to-chromium": "^1.5.376", - "node-releases": "^2.0.48", + "baseline-browser-mapping": "^2.10.44", + "caniuse-lite": "^1.0.30001806", + "electron-to-chromium": "^1.5.393", + "node-releases": "^2.0.51", "update-browserslist-db": "^1.2.3" }, "bin": { @@ -12004,7 +11784,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/bytes": { @@ -12126,9 +11906,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001800", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001800.tgz", - "integrity": "sha512-MMHtuAz9Ys840zAY5F4k6fV5GaivZ9sPk+nz0mY+GYVzRBnYkN0mpqkSR92oWRQ19yQWo4HvBV/FnC16AJX8MA==", + "version": "1.0.30001806", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001806.tgz", + "integrity": "sha512-72Cuvd95zbSYPKq6Fhg8eDJRlzgWDf7/mtoZv6Qe/DYNCEBdNxoA3+rZAU2ZhGCpZlns3EssFavaZomckT5Uuw==", "dev": true, "funding": [ { @@ -12601,7 +12381,6 @@ "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "dev": true, "license": "MIT", "dependencies": { "safe-buffer": "5.2.1" @@ -12614,7 +12393,6 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -12644,6 +12422,19 @@ "dev": true, "license": "MIT" }, + "node_modules/cookies": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/cookies/-/cookies-0.9.1.tgz", + "integrity": "sha512-TG2hpqe4ELx54QER/S3HQ9SRVnQnGBtKUz5bLQWtYAQ+o6GpgMs6sYUvaiJjVxb+UXwhRhAEP3m7LbsIZ77Hmw==", + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "keygrip": "~1.1.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/core-js": { "version": "3.49.0", "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.49.0.tgz", @@ -12704,6 +12495,18 @@ "node": ">= 6" } }, + "node_modules/cron-parser": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/cron-parser/-/cron-parser-4.9.0.tgz", + "integrity": "sha512-p0SaNjrHOnQeR8/VnfGbmg9te2kfyYSQ7Sc/j/6DtPL3JQvKxmjO9TSjNFpujqV3vEYYBvNNvXSxzyksBWAx1Q==", + "license": "MIT", + "dependencies": { + "luxon": "^3.2.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/cronstrue": { "version": "2.59.0", "resolved": "https://registry.npmjs.org/cronstrue/-/cronstrue-2.59.0.tgz", @@ -12736,7 +12539,6 @@ "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", @@ -13112,9 +12914,9 @@ } }, "node_modules/cssstyle/node_modules/lru-cache": { - "version": "11.5.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.1.tgz", - "integrity": "sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==", + "version": "11.5.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.2.tgz", + "integrity": "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==", "dev": true, "license": "BlueOak-1.0.0", "engines": { @@ -13481,6 +13283,15 @@ "integrity": "sha512-hTIP/z+t+qKwBDcmmsnmjWTduxCg+5KfdqWQvb2X/8C9+knYY6epN/pfxdDuyVlSVeFz0sM5eEfwIUQ70U4ckg==", "license": "MIT" }, + "node_modules/date-format": { + "version": "4.0.14", + "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.14.tgz", + "integrity": "sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg==", + "license": "MIT", + "engines": { + "node": ">=4.0" + } + }, "node_modules/debug": { "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", @@ -13575,6 +13386,12 @@ "node": ">=6" } }, + "node_modules/deep-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz", + "integrity": "sha512-bHtC0iYvWhyaTzvV3CZgPeZQqCOBGyGsVV7v4eevpdkLHfiSrXUdBG+qAuSz4RI70sszvjQ1QSZ98An1yNwpSw==", + "license": "MIT" + }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -13638,6 +13455,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/defu": { + "version": "6.1.7", + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.7.tgz", + "integrity": "sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==", + "license": "MIT" + }, "node_modules/degenerator": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz", @@ -13662,11 +13485,16 @@ "node": ">=0.4.0" } }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "license": "MIT" + }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.8" @@ -13686,7 +13514,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.8", @@ -13697,7 +13524,6 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", - "dev": true, "license": "Apache-2.0", "optional": true, "engines": { @@ -13865,9 +13691,9 @@ } }, "node_modules/dompurify": { - "version": "3.4.11", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.11.tgz", - "integrity": "sha512-zhlUV12GsaRzMsf9q5M254YhA4+VuF0fG+QFqu6aYpoGlKtz+w8//jBcGVYBgQkR5GHjUomejY84AV+/uPbWdw==", + "version": "3.4.12", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.12.tgz", + "integrity": "sha512-zQvGet8Z2sWbQhCmfFz/T5QWH2oBmjnqK3qvOjaqaNLrLEF912WamU+ohnTp0TCep/MFVHpdJuCZEdFOdTnEFg==", "license": "(MPL-2.0 OR Apache-2.0)", "peer": true, "optionalDependencies": { @@ -13905,6 +13731,60 @@ "node": ">=10" } }, + "node_modules/dotenv-cli": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/dotenv-cli/-/dotenv-cli-10.0.0.tgz", + "integrity": "sha512-lnOnttzfrzkRx2echxJHQRB6vOAMSCzzZg79IxpC00tU42wZPuZkQxNNrrwVAxaQZIIh001l4PxVlCrBxngBzA==", + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.6", + "dotenv": "^17.1.0", + "dotenv-expand": "^11.0.0", + "minimist": "^1.2.6" + }, + "bin": { + "dotenv": "cli.js" + } + }, + "node_modules/dotenv-cli/node_modules/dotenv": { + "version": "17.4.2", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.4.2.tgz", + "integrity": "sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dotenv-cli/node_modules/dotenv-expand": { + "version": "11.0.7", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-11.0.7.tgz", + "integrity": "sha512-zIHwmZPRshsCdpMDyVsqGmgyP0yT8GAgXUnkdAoJisxvf33k7yO6OuoKmcTGuXPWSsm8Oh88nZicRLA9Y0rUeA==", + "license": "BSD-2-Clause", + "dependencies": { + "dotenv": "^16.4.5" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dotenv-cli/node_modules/dotenv-expand/node_modules/dotenv": { + "version": "16.6.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", + "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, "node_modules/dotenv-expand": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz", @@ -13946,13 +13826,12 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "dev": true, "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.384", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.384.tgz", - "integrity": "sha512-g6KAKY1vkYsADvSPWvdJsuYT0ixdcu6lUtD9P/wJKGBEDlZVXh2AX42j1mPqqaQPDluWjara9ziQ7xqAeXCt5A==", + "version": "1.5.395", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.395.tgz", + "integrity": "sha512-7zt9Aw+SrmxLWLN0zhaTWZQiCdryLVrYTq5R7iZakLvi2UQPYMMsROYV/2qVCzMeCiSXHwKOU+sZ4zOVVlrtKA==", "dev": true, "license": "ISC" }, @@ -13975,7 +13854,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.8" @@ -13992,9 +13870,9 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.24.1", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.24.1.tgz", - "integrity": "sha512-7DdUaTjmNwMcH2gLr1qycesKII3BK4RLy/mdAb7x10Lq7bR4aNKHt1BR1ZALSv0rPM/hF5wYF0PhGop/rJm8vw==", + "version": "5.24.3", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.24.3.tgz", + "integrity": "sha512-PwKooW9JUzh5chmYfHM3IQl5OkK2u2Nm011MgeZrss3JmFraUx/fqrf78kk8GUMYoibx/14MdwTl/1WKkG7TpQ==", "dev": true, "license": "MIT", "peer": true, @@ -14168,9 +14046,9 @@ } }, "node_modules/es-iterator-helpers": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.3.3.tgz", - "integrity": "sha512-0PuBxFi+4uPanB97iDxCLWuHeYud2FALrw5HFZGtAF38UpJDbDC8frwp2cnDyae692CQ0dou60UwWfhgsa4U/g==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.4.0.tgz", + "integrity": "sha512-c/A0P0oxkACDc+cKWw8evLXK83oBKgn0qPOqCYT4x9uolpCIJAcYvJC9QYKNDRPsTeGyCrQ326jrvgZWdCdK5Q==", "dev": true, "license": "MIT", "dependencies": { @@ -14267,7 +14145,6 @@ "version": "0.25.12", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", - "dev": true, "hasInstallScript": true, "license": "MIT", "bin": { @@ -14332,7 +14209,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "dev": true, "license": "MIT" }, "node_modules/escape-string-regexp": { @@ -14371,9 +14247,9 @@ } }, "node_modules/eslint": { - "version": "9.39.4", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.4.tgz", - "integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==", + "version": "9.39.5", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.5.tgz", + "integrity": "sha512-DgZS62aPLXKlnxILS/AYCoRvHaZeXceIzlXPkkGGzJWSow1aEk0lbTlxUSlyjC8jcaKxAdOnTDz+o1JFSBsyjw==", "dev": true, "license": "MIT", "dependencies": { @@ -14382,8 +14258,8 @@ "@eslint/config-array": "^0.21.2", "@eslint/config-helpers": "^0.4.2", "@eslint/core": "^0.17.0", - "@eslint/eslintrc": "^3.3.5", - "@eslint/js": "9.39.4", + "@eslint/eslintrc": "^3.3.6", + "@eslint/js": "9.39.5", "@eslint/plugin-kit": "^0.4.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", @@ -14490,9 +14366,9 @@ } }, "node_modules/eslint-module-utils": { - "version": "2.13.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.13.0.tgz", - "integrity": "sha512-bLohSkT6469rRs8czj0tLTD8vaeIS/whvPRJVjDr7IuoTT1k5DYDERlNycjDj/HkOlvQdYurmfZ/g3fG5bgeLQ==", + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.14.0.tgz", + "integrity": "sha512-W2WCRZ9Dqntd+2u8jJcVMV2PKulc6RdLgUUoh/yQr3uB6lo/ZOeGx11sv60/8S4QFFKNslAlWhr9u0Ef7ZW6Ig==", "dev": true, "license": "MIT", "dependencies": { @@ -14945,7 +14821,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", - "dev": true, "license": "MIT" }, "node_modules/esutils": { @@ -14999,6 +14874,18 @@ "node": ">=8" } }, + "node_modules/expand-tilde": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", + "integrity": "sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==", + "license": "MIT", + "dependencies": { + "homedir-polyfill": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/expect-type": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.4.0.tgz", @@ -15160,9 +15047,9 @@ "license": "MIT" }, "node_modules/fast-uri": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.3.tgz", - "integrity": "sha512-i70LwGWUduXqzicKXWshooq+sWL1K3WUU5rKZNG/0i3a1OSoX3HqhH5WbWwTmqWfor4urUakGPiRQcleRZTwOg==", + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.4.tgz", + "integrity": "sha512-8JnbkQ4juDyvYs4mgFGQqg4yCYtFDtUtmp2QIQq11ZZe5CFQ5wcqm1rqDgAh/QdMySuBnPzMUiJUNZG5N/AiQw==", "dev": true, "funding": [ { @@ -15216,6 +15103,23 @@ "pend": "~1.2.0" } }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, "node_modules/figures": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", @@ -15410,6 +15314,30 @@ "node": ">=6" } }, + "node_modules/find-file-up": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/find-file-up/-/find-file-up-2.0.1.tgz", + "integrity": "sha512-qVdaUhYO39zmh28/JLQM5CoYN9byEOKEH4qfa8K1eNV17W0UUMJ9WgbR/hHFH+t5rcl+6RTb5UC7ck/I+uRkpQ==", + "license": "MIT", + "dependencies": { + "resolve-dir": "^1.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/find-pkg/-/find-pkg-2.0.0.tgz", + "integrity": "sha512-WgZ+nKbELDa6N3i/9nrHeNznm+lY3z4YfhDDWgW+5P0pdmMj26bxaxU11ookgY3NyP9GC7HvZ9etp0jRFqGEeQ==", + "license": "MIT", + "dependencies": { + "find-file-up": "^2.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/find-up": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", @@ -15455,7 +15383,6 @@ "version": "3.4.2", "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", - "dev": true, "license": "ISC" }, "node_modules/follow-redirects": { @@ -15675,7 +15602,6 @@ "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -15725,7 +15651,6 @@ "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, @@ -15780,9 +15705,9 @@ } }, "node_modules/geckodriver": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/geckodriver/-/geckodriver-6.1.0.tgz", - "integrity": "sha512-ZRXLa4ZaYTTgUO4Eefw+RsQCleugU2QLb1ME7qTYxxuRj51yAhfnXaItXNs5/vUzfIaDHuZ+YnSF005hfp07nQ==", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/geckodriver/-/geckodriver-6.1.1.tgz", + "integrity": "sha512-/AcCyc9o9o6hUbudaSJM2iOtXbxSLqQPOb4GrPvEN40cjraUeaX/j5kH3mSgwiroyMn7qzx2wM61AQ2XY8j3sA==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -15792,7 +15717,7 @@ "decamelize": "^6.0.1", "http-proxy-agent": "^7.0.2", "https-proxy-agent": "^7.0.6", - "modern-tar": "^0.7.2" + "modern-tar": "^0.7.3" }, "bin": { "geckodriver": "bin/geckodriver.js" @@ -16313,7 +16238,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", - "dev": true, "license": "MIT", "dependencies": { "parse-passwd": "^1.0.0" @@ -16345,9 +16269,9 @@ } }, "node_modules/hosted-git-info/node_modules/lru-cache": { - "version": "11.5.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.1.tgz", - "integrity": "sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==", + "version": "11.5.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.2.tgz", + "integrity": "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==", "dev": true, "license": "BlueOak-1.0.0", "engines": { @@ -16417,11 +16341,57 @@ "node": ">= 6" } }, + "node_modules/http-assert": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/http-assert/-/http-assert-1.5.0.tgz", + "integrity": "sha512-uPpH7OKX4H25hBmU6G1jWNaqJGpTXxey+YOUizJUAgu0AjLUeC8D73hTrhvDS5D+GJN1DN1+hhc/eF/wpxtp0w==", + "license": "MIT", + "dependencies": { + "deep-equal": "~1.0.1", + "http-errors": "~1.8.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-assert/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/http-assert/node_modules/http-errors": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", + "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", + "license": "MIT", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/http-assert/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/http-errors": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", - "dev": true, "license": "MIT", "dependencies": { "depd": "~2.0.0", @@ -16738,7 +16708,6 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true, "license": "ISC" }, "node_modules/ini": { @@ -17065,7 +17034,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -17120,7 +17089,7 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" @@ -17458,6 +17427,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-wsl": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", @@ -17493,7 +17471,6 @@ "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/isobject": { @@ -17506,6 +17483,15 @@ "node": ">=0.10.0" } }, + "node_modules/isomorphic-ws": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-5.0.0.tgz", + "integrity": "sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw==", + "license": "MIT", + "peerDependencies": { + "ws": "*" + } + }, "node_modules/istanbul-lib-coverage": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", @@ -17615,6 +17601,19 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/jest-util/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/jest-worker": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", @@ -17635,7 +17634,7 @@ "version": "1.21.7", "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", - "dev": true, + "devOptional": true, "license": "MIT", "bin": { "jiti": "bin/jiti.js" @@ -17740,6 +17739,28 @@ "node": ">= 14" } }, + "node_modules/jsdom/node_modules/ws": { + "version": "8.21.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.1.tgz", + "integrity": "sha512-+0NTnW77fFN/DjQi6k/Sq/Yvk4Sgajw7urW8V+asjXnRgDs9gyGkdb7EzgfhA4goXsRIZKE28fzIXBHEzhuiWw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/jsesc": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", @@ -17845,6 +17866,18 @@ "setimmediate": "^1.0.5" } }, + "node_modules/keygrip": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/keygrip/-/keygrip-1.1.0.tgz", + "integrity": "sha512-iYSchDJ+liQ8iwbSI2QqsQOvqv58eJCEanyJPJi+Khyu8smkcKSFUCbPwzFcL7YVtZ6eONjqRX/38caJ7QjRAQ==", + "license": "MIT", + "dependencies": { + "tsscmp": "1.0.6" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -17901,6 +17934,106 @@ "seed-random": "~2.2.0" } }, + "node_modules/koa": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/koa/-/koa-3.0.3.tgz", + "integrity": "sha512-MeuwbCoN1daWS32/Ni5qkzmrOtQO2qrnfdxDHjrm6s4b59yG4nexAJ0pTEFyzjLp0pBVO80CZp0vW8Ze30Ebow==", + "license": "MIT", + "dependencies": { + "accepts": "^1.3.8", + "content-disposition": "~0.5.4", + "content-type": "^1.0.5", + "cookies": "~0.9.1", + "delegates": "^1.0.0", + "destroy": "^1.2.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "fresh": "~0.5.2", + "http-assert": "^1.5.0", + "http-errors": "^2.0.0", + "koa-compose": "^4.1.0", + "mime-types": "^3.0.1", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/koa-compose": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/koa-compose/-/koa-compose-4.1.0.tgz", + "integrity": "sha512-8ODW8TrDuMYvXRwra/Kh7/rJo9BtOfPc6qO8eAfC80CnCvSjSl0bkRM24X6/XBBEyj0v1nRUQ1LyOy3dbqOWXw==", + "license": "MIT" + }, + "node_modules/koa/node_modules/media-typer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/koa/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/koa/node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/koa/node_modules/type-is": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.1.0.tgz", + "integrity": "sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==", + "license": "MIT", + "dependencies": { + "content-type": "^2.0.0", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/koa/node_modules/type-is/node_modules/content-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.0.0.tgz", + "integrity": "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -17993,6 +18126,12 @@ "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", "license": "MIT" }, + "node_modules/lodash.clonedeepwith": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeepwith/-/lodash.clonedeepwith-4.5.0.tgz", + "integrity": "sha512-QRBRSxhbtsX1nc0baxSkkK5WlVTTm/s48DSukcGcWZwIyI8Zz+lB+kFiELJXtzfH4Aj6kMWQ1VWW4U5uUDgZMA==", + "license": "MIT" + }, "node_modules/lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", @@ -18052,6 +18191,22 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/log4js": { + "version": "6.9.1", + "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.9.1.tgz", + "integrity": "sha512-1somDdy9sChrr9/f4UlzhdaGfDR2c/SaD2a4T7qEkG4jTS57/B3qmnjLYePwQ8cqWnUHZI0iAKxMBpCZICiZ2g==", + "license": "Apache-2.0", + "dependencies": { + "date-format": "^4.0.14", + "debug": "^4.3.4", + "flatted": "^3.2.7", + "rfdc": "^1.3.0", + "streamroller": "^3.1.5" + }, + "engines": { + "node": ">=8.0" + } + }, "node_modules/loglevel": { "version": "1.9.2", "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.9.2.tgz", @@ -18073,6 +18228,12 @@ "dev": true, "license": "MIT" }, + "node_modules/long-timeout": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/long-timeout/-/long-timeout-0.1.1.tgz", + "integrity": "sha512-BFRuQUqc7x2NWxfJBCyUrN8iYUYznzL9JROmRz1gZ6KlOIgmoD+njPVbb+VNn2nGMKggMsK79iUNErillsrx7w==", + "license": "MIT" + }, "node_modules/longest-streak": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-2.0.4.tgz", @@ -18127,9 +18288,9 @@ } }, "node_modules/lucide-react": { - "version": "1.23.0", - "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-1.23.0.tgz", - "integrity": "sha512-38BpJcD0JhFosxHApP/BYsBetLpQFRoTRzEzstM/XCc3jsAG7wqaY1lgVwxiUe3xqYE+lNxo2PkCmYwXWrwwIw==", + "version": "1.25.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-1.25.0.tgz", + "integrity": "sha512-/mdJTRbiwcLOQ1NZZK1amZF9rIZyvO18D6r9TngE6TG1NmqHgFuT4eE7Xrkm9UsXMbBJD1NlfwHVltCDWHrOTw==", "license": "ISC", "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" @@ -18139,7 +18300,6 @@ "version": "3.7.2", "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.7.2.tgz", "integrity": "sha512-vtEhXh/gNjI9Yg1u4jX/0YVPMvxzHuGgCm6tC5kZyb08yjGWGnqAjGJvcXbqQR2P3MyMEFnRbpcdFS6PBcLqew==", - "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -18160,7 +18320,6 @@ "version": "0.30.21", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" @@ -18512,6 +18671,19 @@ "node": ">=8.6" } }, + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/mime": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", @@ -18576,7 +18748,6 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -18773,9 +18944,9 @@ } }, "node_modules/modern-tar": { - "version": "0.7.6", - "resolved": "https://registry.npmjs.org/modern-tar/-/modern-tar-0.7.6.tgz", - "integrity": "sha512-sweCIVXzx1aIGTCdzcMlSZt1h8k5Tmk08VNAuRk3IU28XamGiOH5ypi11g6De2CH7PhYqSSnGy2A/EFhbWnVKg==", + "version": "0.7.7", + "resolved": "https://registry.npmjs.org/modern-tar/-/modern-tar-0.7.7.tgz", + "integrity": "sha512-t9VmxaqrmANnEOBhpSDI6HD192Ge48k8vmWqQQL7hSFEqHEYwZbbsu49+aKLWZeRvFs3j1pMhXOqqF4kPlvjkQ==", "dev": true, "license": "MIT", "engines": { @@ -18792,13 +18963,13 @@ } }, "node_modules/monaco-editor": { - "version": "0.55.1", - "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.55.1.tgz", - "integrity": "sha512-jz4x+TJNFHwHtwuV9vA9rMujcZRb0CEilTEwG2rRSpe/A7Jdkuj8xPKttCgOh+v/lkHy7HsZ64oj+q3xoAFl9A==", + "version": "0.56.0", + "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.56.0.tgz", + "integrity": "sha512-sXboRm3BeBeLm938eaiyLMe0OxzfXIlZvbv4ir/jVgQy1zDhWjgmny0WoN45fuDKhCCQsYMbBJrv/A6jd8aCUg==", "license": "MIT", "peer": true, "dependencies": { - "dompurify": "3.2.7", + "dompurify": "3.4.8", "marked": "14.0.0" } }, @@ -18821,9 +18992,9 @@ } }, "node_modules/nanoid": { - "version": "3.3.15", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.15.tgz", - "integrity": "sha512-y7Wygv/7mEOvxTuEQDB8StXdMRBWf1kR/tlhAzBRUFkB2jfcLOAxO/SHmOO2zgz1pVgK29/kyupn059/bCHdjA==", + "version": "3.3.16", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.16.tgz", + "integrity": "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==", "funding": [ { "type": "github", @@ -18849,7 +19020,6 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -18904,7 +19074,6 @@ "version": "7.1.1", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", - "dev": true, "license": "MIT", "optional": true }, @@ -18983,15 +19152,29 @@ "license": "MIT" }, "node_modules/node-releases": { - "version": "2.0.50", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.50.tgz", - "integrity": "sha512-J6l92tKHX6w8Jy5nO1Vuc01NoIiRGi/d6qBKVxh+IQ8Cr3b6HbVNfKiF8ZpFKufTwpwxMmce2W3iQZ861ZRyTg==", + "version": "2.0.51", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.51.tgz", + "integrity": "sha512-wRNIrw4DmVLKQlbgOMdkMx27Wrpzes2hh5Jtbi2bjPd+4wJstWIqP5A+lscnqbm0xxmT5Bpg8Lec5ItEBwx6BQ==", "dev": true, "license": "MIT", "engines": { "node": ">=18" } }, + "node_modules/node-schedule": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/node-schedule/-/node-schedule-2.1.1.tgz", + "integrity": "sha512-OXdegQq03OmXEjt2hZP33W2YPs/E5BcFQks46+G2gAxs4gHOIVD1u7EqlYLYSKsaIpyKCK9Gbk0ta1/gjRSMRQ==", + "license": "MIT", + "dependencies": { + "cron-parser": "^4.2.0", + "long-timeout": "0.1.1", + "sorted-array-functions": "^1.3.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/nodemon": { "version": "3.1.14", "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.14.tgz", @@ -19260,9 +19443,9 @@ } }, "node_modules/obug": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.3.tgz", - "integrity": "sha512-9miFgM2OFba7hB+pRgvtV84pYTBaoTHohvmIgiRt6dRIzbwEOIaNaP+dIlGs2fNFoB0SeISs0Jz5WFVRid6Xyg==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.4.tgz", + "integrity": "sha512-4a+OsYv9UktOJKE+l1A4OufDgdRF9PifWj+tJnHURo/P+WOxpG4GzUFL9qCalmWauao6ogiG+QvnCovwPoyAWA==", "dev": true, "funding": [ "https://github.com/sponsors/sxzz", @@ -19277,7 +19460,6 @@ "version": "2.4.1", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "dev": true, "license": "MIT", "dependencies": { "ee-first": "1.1.1" @@ -19328,13 +19510,14 @@ } }, "node_modules/own-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", - "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.2.tgz", + "integrity": "sha512-19YVAg7T+WTrxggPukVq7DjTv6+PJ867TmhCvBsYwmbFCsZd344rq2Ld1p0wo8f8Qrrhgp82c6FJRqdXWtSEhg==", "dev": true, "license": "MIT", "dependencies": { - "get-intrinsic": "^1.2.6", + "call-bound": "^1.0.4", + "get-intrinsic": "^1.3.0", "object-keys": "^1.1.1", "safe-push-apply": "^1.0.0" }, @@ -19517,7 +19700,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", "integrity": "sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -19540,7 +19722,6 @@ "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.8" @@ -19570,7 +19751,6 @@ "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" @@ -19600,9 +19780,9 @@ } }, "node_modules/path-scurry/node_modules/lru-cache": { - "version": "11.5.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.1.tgz", - "integrity": "sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==", + "version": "11.5.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.2.tgz", + "integrity": "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==", "dev": true, "license": "BlueOak-1.0.0", "engines": { @@ -19627,10 +19807,9 @@ } }, "node_modules/pathe": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", - "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", - "dev": true, + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", + "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", "license": "MIT" }, "node_modules/pathval": { @@ -19664,13 +19843,12 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", - "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", - "dev": true, + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", + "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", "license": "MIT", "engines": { - "node": ">=8.6" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/jonschlinkert" @@ -19846,9 +20024,9 @@ } }, "node_modules/postcss": { - "version": "8.5.16", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.16.tgz", - "integrity": "sha512-vuwillviilfKZsg0VGj5R/YwwcHx4SLsIOI/7K6mQkWx+l5cUHTjj5g0AasTBcyXsbfTgrwsUNmVUb5xVwyPwg==", + "version": "8.5.22", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.22.tgz", + "integrity": "sha512-KBDEIpLrvpv16pp3K0Fw+UCoZfopFjjgeB+0tA/aaThfEE74kKDLrgg603YvOWJyg3+WYtyq3xYsQWsIyZlPqQ==", "funding": [ { "type": "opencollective", @@ -19865,7 +20043,7 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.12", + "nanoid": "^3.3.16", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -21564,9 +21742,9 @@ } }, "node_modules/prettier": { - "version": "3.9.4", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.9.4.tgz", - "integrity": "sha512-yWG/o/4oJfo036EKAfK6ACAoDOfHeRHx4tuxkfBZiauURiaSmYwlpOr5LQqKtIkRD2z1PLteme2WoxEnj4tHTg==", + "version": "3.9.6", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.9.6.tgz", + "integrity": "sha512-OpN0zzVdiaiAhxpuuj5efpIS4sY9j7bY6uR5mnj5yPzGkdkjNKSJeUThPb60Jw29QuAZgA4o+/iB49kFiaBX6g==", "dev": true, "license": "MIT", "bin": { @@ -21874,6 +22052,12 @@ "performance-now": "^2.1.0" } }, + "node_modules/rambda": { + "version": "9.4.2", + "resolved": "https://registry.npmjs.org/rambda/-/rambda-9.4.2.tgz", + "integrity": "sha512-++euMfxnl7OgaEKwXh9QqThOjMeta2HH001N1v4mYQzBjJBnmXBh2BCK6dZAbICFVXOFUVD3xFG0R3ZPU0mxXw==", + "license": "MIT" + }, "node_modules/randexp": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/randexp/-/randexp-0.5.3.tgz", @@ -22151,6 +22335,15 @@ "react": "^18.3.1" } }, + "node_modules/react-error-boundary": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/react-error-boundary/-/react-error-boundary-6.1.2.tgz", + "integrity": "sha512-3DpCr5HVdZ0caUjYE/kIHBEJN0mNP3ZCgf16c48uJ5TbWjorKVp+YG8W3XqlJ7vJAVNw6wNIImyPXmFydwmyng==", + "license": "MIT", + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0" + } + }, "node_modules/react-error-overlay": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.1.0.tgz", @@ -22288,9 +22481,9 @@ } }, "node_modules/react-resizable-panels": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/react-resizable-panels/-/react-resizable-panels-4.12.0.tgz", - "integrity": "sha512-t/Gp57qSCxGQ52ckhz+8lM7dnuymeU95TEzl2U203qEbGkSLHrtm7US2/ANzq/zOlja3CwPTAfCDuh1unv9mfw==", + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/react-resizable-panels/-/react-resizable-panels-4.12.2.tgz", + "integrity": "sha512-NwY5LCo4WrxVvDh0xoMML6EMLPONP/8ckKcIdpnojxexoatZdjLiRqLJQjQK5CPkd4SYiB/2M5BVrjZBQtOO7Q==", "license": "MIT", "peerDependencies": { "react": "^18.0.0 || ^19.0.0", @@ -22436,9 +22629,9 @@ } }, "node_modules/read-package-up/node_modules/type-fest": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-5.7.0.tgz", - "integrity": "sha512-1URUxUqfHFM1c+zfSPsa3gnkO7Aq21qyH75SIduNYz4SzY964rn1X2vCMQaHSHhktiw+0kPa2iyb6PUpXqB6Vg==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-5.8.0.tgz", + "integrity": "sha512-YGYEVz3Fm5iy/AybuA0oyNFq7H4CgQNfRp/qfe8nurE1kuCeNm3/vfm9X4Mtl+qLyaKJUh5xrFZwogr41SMjYA==", "dev": true, "license": "(MIT OR CC0-1.0)", "dependencies": { @@ -22587,9 +22780,9 @@ } }, "node_modules/read-pkg/node_modules/type-fest": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-5.7.0.tgz", - "integrity": "sha512-1URUxUqfHFM1c+zfSPsa3gnkO7Aq21qyH75SIduNYz4SzY964rn1X2vCMQaHSHhktiw+0kPa2iyb6PUpXqB6Vg==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-5.8.0.tgz", + "integrity": "sha512-YGYEVz3Fm5iy/AybuA0oyNFq7H4CgQNfRp/qfe8nurE1kuCeNm3/vfm9X4Mtl+qLyaKJUh5xrFZwogr41SMjYA==", "dev": true, "license": "(MIT OR CC0-1.0)", "dependencies": { @@ -22645,6 +22838,19 @@ "node": ">=8.10.0" } }, + "node_modules/readdirp/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/recast": { "version": "0.23.12", "resolved": "https://registry.npmjs.org/recast/-/recast-0.23.12.tgz", @@ -22965,19 +23171,80 @@ "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", "license": "MIT", "dependencies": { - "es-errors": "^1.3.0", - "is-core-module": "^2.16.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", + "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-dir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", + "integrity": "sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==", + "license": "MIT", + "dependencies": { + "expand-tilde": "^2.0.0", + "global-modules": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-dir/node_modules/global-modules": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "license": "MIT", + "dependencies": { + "global-prefix": "^1.0.1", + "is-windows": "^1.0.1", + "resolve-dir": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-dir/node_modules/global-prefix": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", + "integrity": "sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==", + "license": "MIT", + "dependencies": { + "expand-tilde": "^2.0.2", + "homedir-polyfill": "^1.0.1", + "ini": "^1.3.4", + "is-windows": "^1.0.1", + "which": "^1.2.14" }, "engines": { - "node": ">= 0.4" + "node": ">=0.10.0" + } + }, + "node_modules/resolve-dir/node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "license": "ISC" + }, + "node_modules/resolve-dir/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "bin": { + "which": "bin/which" } }, "node_modules/resolve-from": { @@ -23033,6 +23300,12 @@ "node": ">=0.10.0" } }, + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "license": "MIT" + }, "node_modules/rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -23076,7 +23349,6 @@ "version": "4.62.2", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.62.2.tgz", "integrity": "sha512-RFnrW4lhXA3s3eqHDZvN654g8OTjzRfqpIRJYczCGB6HzphckVAi/Qh4tbPUbRuDi7s1Llv8g/NspLkttY3gTA==", - "dev": true, "license": "MIT", "dependencies": { "@types/estree": "1.0.9" @@ -23183,7 +23455,6 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, "funding": [ { "type": "github", @@ -23283,10 +23554,10 @@ "license": "CC0-1.0" }, "node_modules/sass": { - "version": "1.101.0", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.101.0.tgz", - "integrity": "sha512-OL3GoQyoUdDt843DpVmDO6y2k1sc5IhUDSpu8XucEI+35neq5QivZ1iuegnpraEVTJXlQGK1gl27zKcTLEPbQw==", - "dev": true, + "version": "1.101.3", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.101.3.tgz", + "integrity": "sha512-Z1lLHhtAII+dyLNIQB6JQTZMy7sDxk3f5NzbINRc9ks1P0HCGvSuKev0wUhULFpLSaHBIMZrcTs9WDQUZerrgA==", + "devOptional": true, "license": "MIT", "dependencies": { "chokidar": "^5.0.0", @@ -23346,7 +23617,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "readdirp": "^5.0.0" @@ -23362,14 +23633,14 @@ "version": "5.1.9", "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.9.tgz", "integrity": "sha512-m8nVez3rwrgmWxtLMt1ZYXB2Lv7OKYn/disyxAlSDYAlKSlFoPPfIAmAM/M5xqL4m4C/wAPw7S2/CNaUii1Hxg==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/sass/node_modules/readdirp": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">= 20.19.0" @@ -23438,9 +23709,9 @@ "license": "MIT" }, "node_modules/selenium-webdriver": { - "version": "4.45.0", - "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-4.45.0.tgz", - "integrity": "sha512-Cb2nqvJiwXVOtRTCYHX9D1FJR5+Ls7aL3Nev0t6n4CpXsQ//YGiiUmSCbvTDDeLtbV85SZ46qmLab4SIYKXWRw==", + "version": "4.46.0", + "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-4.46.0.tgz", + "integrity": "sha512-UlTkgnx9y+bf3QxFsrgUyMqC2oy1Yf+qcOs7xIC/XfsUPv/ow7Sicx6SJ7AeOn2/Z+xF1M8SLqyn983wipI82w==", "dev": true, "funding": [ { @@ -23463,6 +23734,28 @@ "node": ">= 20.0.0" } }, + "node_modules/selenium-webdriver/node_modules/ws": { + "version": "8.21.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.1.tgz", + "integrity": "sha512-+0NTnW77fFN/DjQi6k/Sq/Yvk4Sgajw7urW8V+asjXnRgDs9gyGkdb7EzgfhA4goXsRIZKE28fzIXBHEzhuiWw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/semver": { "version": "7.8.5", "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", @@ -23606,7 +23899,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "dev": true, "license": "ISC" }, "node_modules/shallow-clone": { @@ -23626,7 +23918,6 @@ "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" @@ -23639,16 +23930,15 @@ "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/shell-quote": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.9.0.tgz", - "integrity": "sha512-Iov+JwFv/2HcTpcwNMKd8+IWNb8tboQJNQTkAY/LLVK7gGH9jy+LGkVqPxfekHl+yMmiqXszdGWXgkfml7hjqA==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.10.0.tgz", + "integrity": "sha512-w1aiOKwKuRgtwAReIIj89puqg+I7GvX4IbLrvmhXbzQsj1+Zwi4VO3+fa6ZF91TWSjIxoEkKnMeHcLEODK5ZXA==", "dev": true, "license": "MIT", "engines": { @@ -23870,6 +24160,12 @@ "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-rc" } }, + "node_modules/sorted-array-functions": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/sorted-array-functions/-/sorted-array-functions-1.3.0.tgz", + "integrity": "sha512-2sqgzeFlid6N4Z2fUQ1cvFmTOLRi/sEDzSQ0OKYchqgoPmQBVyM3959qYx3fpS6Esef80KjmpgPeEr028dP3OA==", + "license": "MIT" + }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -23926,7 +24222,7 @@ "version": "0.5.21", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "buffer-from": "^1.0.0", @@ -24023,16 +24319,15 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/std-env": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.1.0.tgz", - "integrity": "sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.2.0.tgz", + "integrity": "sha512-oCUKSupKTHX53EyjDtuZQ64pjLJ6yYCtpmEw0goYxtjG9KpbRe8KAsl2tBUGU9DyMcJ0RwJ8GqJAFzMXcXW1Rw==", "dev": true, "license": "MIT" }, @@ -24078,6 +24373,52 @@ } } }, + "node_modules/streamroller": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.1.5.tgz", + "integrity": "sha512-KFxaM7XT+irxvdqSP1LGLgNWbYN7ay5owZ3r/8t77p+EtSUAfUgtl7be3xtqtOmGUl9K9YPO2ca8133RlTjvKw==", + "license": "MIT", + "dependencies": { + "date-format": "^4.0.14", + "debug": "^4.3.4", + "fs-extra": "^8.1.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/streamroller/node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/streamroller/node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "license": "MIT", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/streamroller/node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, "node_modules/string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", @@ -24633,7 +24974,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/sugarss/-/sugarss-2.0.0.tgz", "integrity": "sha512-WfxjozUk0UVA4jm+U1d736AUpzSrNsQcIbyOkoE364GrtWmIrFdk5lksEupgWMD4VaT/0kVx1dobpiDumSgmJQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "postcss": "^7.0.2" @@ -24680,9 +25021,9 @@ "dev": true }, "node_modules/svgo": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.2.tgz", - "integrity": "sha512-TyzE4NVGLUFy+H/Uy4N6c3G0HEeprsVfge6Lmq+0FdQQ/zqoVYB62IsBZORsiL+o96s6ff/V6/3UQo/C0cgCAA==", + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.3.tgz", + "integrity": "sha512-5EZD0pafXX6PphdwOGCiVLDSaV1xyuQao2blHajHLsPxr07q4mmEjdtXEWgG07ae2mIz8Ex2CDXNCTiXhy3Khw==", "dev": true, "license": "MIT", "dependencies": { @@ -24951,10 +25292,10 @@ "license": "MIT" }, "node_modules/terser": { - "version": "5.48.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.48.0.tgz", - "integrity": "sha512-J/9An6vs9Us6wKRriSFXBWdRZapREHqFzdNUKk0pmu804EMR6dr6winwo7e5JDxN4xahxQsuysyYFwlwj4XN/Q==", - "dev": true, + "version": "5.49.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.49.0.tgz", + "integrity": "sha512-SNiDnXyHSrxVcIOtVbULzcTmniUiwcV7Nwdyj1twVubeTmbjoa8p69KKDpfkdoOavuM4/GRm1+ykI8qqnavHoA==", + "devOptional": true, "license": "BSD-2-Clause", "peer": true, "dependencies": { @@ -24974,7 +25315,7 @@ "version": "8.17.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.17.0.tgz", "integrity": "sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==", - "dev": true, + "devOptional": true, "license": "MIT", "peer": true, "bin": { @@ -24988,7 +25329,7 @@ "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true, + "devOptional": true, "license": "MIT", "peer": true }, @@ -25100,7 +25441,6 @@ "version": "0.2.17", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", - "dev": true, "license": "MIT", "dependencies": { "fdir": "^6.5.0", @@ -25113,37 +25453,6 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, - "node_modules/tinyglobby/node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/tinyglobby/node_modules/picomatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", - "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/tinyrainbow": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.0.tgz", @@ -25155,22 +25464,22 @@ } }, "node_modules/tldts": { - "version": "7.4.5", - "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.4.5.tgz", - "integrity": "sha512-RfEzKWcq5fHUOFq7J3rl3Oz6ylKGtcHqUznzj4EcXsxLSIjJcvpbXAQtWGeJQ0xKnimR5e0Cn+cn9TssfMzm+g==", + "version": "7.4.9", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.4.9.tgz", + "integrity": "sha512-3kZ8wQQ/k5DrChD4X4FVvr2D7E5uoRgAqkPyLpSCGUvqOvqu+JEdr3mwMUaVWb+vMHZaKhF5fp2PBigKsui7hA==", "dev": true, "license": "MIT", "dependencies": { - "tldts-core": "^7.4.5" + "tldts-core": "^7.4.9" }, "bin": { "tldts": "bin/cli.js" } }, "node_modules/tldts-core": { - "version": "7.4.5", - "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.4.5.tgz", - "integrity": "sha512-pGrwzZDvPwKe+7NNUqAunb6rqTfynr0VOUhCMdqbu5xlvNiszsAJygRzwvpVycdzejlbpY+SWJOn+s75Og7FEA==", + "version": "7.4.9", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.4.9.tgz", + "integrity": "sha512-DxKfPBI52p2msTEu7MPhdpdDTBhhVQg1a/8PjQckeyAvO13eMYElX545grIp6nnTGIMZlRvFZPvFhvI/WIz2Vg==", "dev": true, "license": "MIT" }, @@ -25208,7 +25517,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.6" @@ -25232,9 +25540,9 @@ } }, "node_modules/tough-cookie": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-6.0.1.tgz", - "integrity": "sha512-LktZQb3IeoUWB9lqR5EWTHgW/VTITCXg4D21M+lvybRVdylLrRMnqaIONLVb5mav8vM19m44HIcGq4qASeu2Qw==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-6.0.2.tgz", + "integrity": "sha512-exgYmnmL/sJpR3upZfXG5PoatXQii55xAiXGXzY+sROLZ/Y+SLcp9PgJNI9Vz37HpQ74WvDcLT8eqm+kV3FzrA==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -25349,6 +25657,15 @@ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD" }, + "node_modules/tsscmp": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.6.tgz", + "integrity": "sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==", + "license": "MIT", + "engines": { + "node": ">=0.6.x" + } + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -25488,10 +25805,9 @@ } }, "node_modules/typescript": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", - "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", - "dev": true, + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "license": "Apache-2.0", "peer": true, "bin": { @@ -25532,7 +25848,7 @@ "version": "8.3.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.3.0.tgz", "integrity": "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/unicode-canonical-property-names-ecmascript": { @@ -25943,7 +26259,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.8" @@ -25985,7 +26300,6 @@ "version": "6.4.3", "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.3.tgz", "integrity": "sha512-NTKlcQjlAK7MlQoyb6LgaqHc8sso/pVyUJYWMws3jg21uTJw/LddqIFPcPqP6PzpgbIcZyKI85sFE4HBrQDA8A==", - "dev": true, "license": "MIT", "dependencies": { "esbuild": "^0.25.0", @@ -26123,6 +26437,33 @@ "vite": ">=2" } }, + "node_modules/vite-plugin-eslint/node_modules/@rollup/pluginutils": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.2.1.tgz", + "integrity": "sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "estree-walker": "^2.0.1", + "picomatch": "^2.2.2" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/vite-plugin-eslint/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/vite-plugin-eslint/node_modules/rollup": { "version": "2.80.0", "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.80.0.tgz", @@ -26154,87 +26495,20 @@ "vite": ">=2.6.0" } }, - "node_modules/vite-plugin-svgr/node_modules/@rollup/pluginutils": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.4.0.tgz", - "integrity": "sha512-MfPp06CjRLfXQ3wY0R8vJDYBy/MvVcc9OulEfR0B8Iv9ko+GCNaRZ+EpJYFl27LhKsZK0o420sYCRHCjfCgeUg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0", - "estree-walker": "^2.0.2", - "picomatch": "^4.0.2" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, - "node_modules/vite-plugin-svgr/node_modules/picomatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", - "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/vite/node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/vite/node_modules/picomatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", - "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/vitest": { - "version": "4.1.9", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.9.tgz", - "integrity": "sha512-nE3/LEyc0z87uHYLZebqCUOaJr2hdtuPp7BQ4BosVFnfltxgAvMG08NyrSGlPpOUWvR27c5flSmYFTNr78L9GQ==", + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.10.tgz", + "integrity": "sha512-R9jUTe5S4Qb0HCd4TNqpC7oGcrMssMRGXLW80ubjWsW9VH5GF8y1Y0SFLY9AbqSk6nt0PnOx4H4WNJYZ13GUPw==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/expect": "4.1.9", - "@vitest/mocker": "4.1.9", - "@vitest/pretty-format": "4.1.9", - "@vitest/runner": "4.1.9", - "@vitest/snapshot": "4.1.9", - "@vitest/spy": "4.1.9", - "@vitest/utils": "4.1.9", + "@vitest/expect": "4.1.10", + "@vitest/mocker": "4.1.10", + "@vitest/pretty-format": "4.1.10", + "@vitest/runner": "4.1.10", + "@vitest/snapshot": "4.1.10", + "@vitest/spy": "4.1.10", + "@vitest/utils": "4.1.10", "es-module-lexer": "^2.0.0", "expect-type": "^1.3.0", "magic-string": "^0.30.21", @@ -26262,12 +26536,12 @@ "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", - "@vitest/browser-playwright": "4.1.9", - "@vitest/browser-preview": "4.1.9", - "@vitest/browser-webdriverio": "4.1.9", - "@vitest/coverage-istanbul": "4.1.9", - "@vitest/coverage-v8": "4.1.9", - "@vitest/ui": "4.1.9", + "@vitest/browser-playwright": "4.1.10", + "@vitest/browser-preview": "4.1.10", + "@vitest/browser-webdriverio": "4.1.10", + "@vitest/coverage-istanbul": "4.1.10", + "@vitest/coverage-v8": "4.1.10", + "@vitest/ui": "4.1.10", "happy-dom": "*", "jsdom": "*", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" @@ -26312,24 +26586,18 @@ } }, "node_modules/vitest/node_modules/es-module-lexer": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.0.tgz", - "integrity": "sha512-KLdwQm2NvGLDkQDCGvmiQrhkd0JbMzXthwQAUgWjQuQdBLFa3eiBP5arXZyA+f8x+x7OXgud6bq2rxjGtHV2tw==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.1.tgz", + "integrity": "sha512-shc1dbU90Yl/xq1QrC7QRtfcwURZuVRfPhZbDoldJ1cn1gzDvBaBWlv0eFolj5+0znnPJz5TXLxsN77X/12KTA==", "dev": true, "license": "MIT" }, - "node_modules/vitest/node_modules/picomatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", - "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "node_modules/vitest/node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } + "license": "MIT" }, "node_modules/w3c-xmlserializer": { "version": "5.0.0", @@ -26379,9 +26647,9 @@ } }, "node_modules/webpack": { - "version": "5.108.3", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.108.3.tgz", - "integrity": "sha512-hOpaCHmQVVY66IVTjofnH14IgSdmod2aquSGHGuYig/OIdWge01Hk2Wt988DZcwXumFUT4+FvJY5N+ikl8o/ww==", + "version": "5.108.4", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.108.4.tgz", + "integrity": "sha512-yur8LyJoeiWh47dErD+Ok7vlbmDsJ3UbbRPAoxbGJ54WpE2y5yVo5G/inUzujnYgw3tPmBRdn+G7PoxXaYC33w==", "dev": true, "license": "MIT", "peer": true, @@ -26426,9 +26694,9 @@ } }, "node_modules/webpack-sources": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.5.0.tgz", - "integrity": "sha512-HPuy+uuoTCaaoEoI1LQ3JN9+vrPBvEesnnX1jADHy728cHSMlq4wUc4afYqahq2B1mhQVZxCXOkNTnXltr+2vQ==", + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.5.1.tgz", + "integrity": "sha512-jyuiGJdtvY434z5bUZrjz67v76/ePNvFZTp9Mdz29IlH4+GPsgyGjiv0fKI+M7BdkU6ADjulUcKAd3tUK3WlEw==", "dev": true, "license": "MIT", "peer": true, @@ -26504,9 +26772,9 @@ } }, "node_modules/webpack/node_modules/es-module-lexer": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.0.tgz", - "integrity": "sha512-KLdwQm2NvGLDkQDCGvmiQrhkd0JbMzXthwQAUgWjQuQdBLFa3eiBP5arXZyA+f8x+x7OXgud6bq2rxjGtHV2tw==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.1.tgz", + "integrity": "sha512-shc1dbU90Yl/xq1QrC7QRtfcwURZuVRfPhZbDoldJ1cn1gzDvBaBWlv0eFolj5+0znnPJz5TXLxsN77X/12KTA==", "dev": true, "license": "MIT", "peer": true @@ -26601,7 +26869,6 @@ "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" @@ -26804,10 +27071,9 @@ } }, "node_modules/ws": { - "version": "8.21.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", - "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==", - "dev": true, + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", "license": "MIT", "engines": { "node": ">=10.0.0" @@ -26872,7 +27138,7 @@ "version": "2.9.0", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", - "dev": true, + "devOptional": true, "license": "ISC", "bin": { "yaml": "bin.mjs" diff --git a/package.json b/package.json index 78e27335d1..73fd27ec15 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,8 @@ "homepage": "/mlrun", "dependencies": { "@dagrejs/dagre": "^1.1.5", + "@module-federation/runtime": "0.23.0", + "@module-federation/vite": "1.11.0", "@monaco-editor/react": "^4.7.0", "@radix-ui/react-collapsible": "^1.1.12", "@radix-ui/react-dialog": "^1.1.15", @@ -24,6 +26,7 @@ "concurrently": "^6.4.2", "cronstrue": "^2.49.0", "dotenv": "^10.0.0", + "dotenv-cli": "^10.0.0", "dotenv-expand": "^5.1.0", "file-saver": "^2.0.5", "final-form": "^4.20.10", @@ -44,6 +47,7 @@ "qs": "^6.15.2", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-error-boundary": "^6.1.0", "react-final-form": "^6.5.9", "react-final-form-arrays": "^3.1.4", "react-modal-promise": "^1.0.2", @@ -81,6 +85,7 @@ "scripts": { "start": "vite", "build": "vite build", + "preview:federation": "cross-env PREVIEW_MODE=true dotenv -e .env.development.mf -- vite build && node scripts/previewLocalBuildMF.mjs", "lint": "eslint \"src/**/*.{js,jsx}\"", "lint:fix": "eslint \"src/**/*.{js,jsx}\" --fix", "format:check": "prettier --check \"src/**/*.{js,jsx}\"", @@ -88,7 +93,8 @@ "preview": "vite preview", "preinstall": "npx force-resolutions", "test:coverage": "npm run test -- --coverage --watchAll=false", - "docker": "docker build -t ${MLRUN_DOCKER_REGISTRY}${MLRUN_DOCKER_REPO:-mlrun}/mlrun-ui:${MLRUN_DOCKER_TAG:-latest} --build-arg COMMIT_HASH=\"`git rev-parse --short HEAD`\" --build-arg GIT_COMMIT_SHA=\"`git rev-parse HEAD`\" --build-arg DATE=\"`date -u`\" -f Dockerfile .", + "docker": "docker build -t ${MLRUN_DOCKER_REGISTRY}${MLRUN_DOCKER_REPO:-mlrun}/mlrun-ui:${MLRUN_DOCKER_TAG:-latest} --build-arg COMMIT_HASH=\"`git rev-parse --short HEAD`\" --build-arg DATE=\"`date -u`\" -f Dockerfile .", + "docker:mf": "docker buildx build --platform linux/amd64 -t ${MLRUN_DOCKER_REGISTRY}${MLRUN_DOCKER_REPO:-mlrun}/mlrun-ui:${MLRUN_DOCKER_TAG:-latest} --build-arg COMMIT_HASH=\"`git rev-parse --short HEAD`\" --build-arg GIT_COMMIT_SHA=\"`git rev-parse HEAD`\" --build-arg DATE=\"`date -u`\" -f Dockerfile.mf .", "generate-rn": "./generate-release-notes.js ${MLRUN_OLD_VERSION} ${MLRUN_VERSION} ${MLRUN_RELEASE_BRANCH} ${MLRUN_RELEASE_TYPE}", "storybook": "start-storybook -p 6006", "build-storybook": "build-storybook", diff --git a/public/config.json b/public/config.json index 8d111a5c0b..cc2b881b35 100644 --- a/public/config.json +++ b/public/config.json @@ -1,5 +1,6 @@ { "betaMode": "enabled", "nuclioMode": "enabled", - "nuclioUiUrl": "http://localhost:8070" + "nuclioUiUrl": "http://localhost:8070", + "nuclioRemoteEntryUrl": "http://localhost:5189" } diff --git a/public/landing.html b/public/landing.html new file mode 100644 index 0000000000..3872792cf4 --- /dev/null +++ b/public/landing.html @@ -0,0 +1,59 @@ + + + + + + MLRun UI + + + +
+

MLRun Remote UI

+

This is a remote module component.

+

Please access it via the main Iguazio Dashboard.

+
+ + diff --git a/scripts/build.js b/scripts/build.js deleted file mode 100644 index da28a0b14b..0000000000 --- a/scripts/build.js +++ /dev/null @@ -1,236 +0,0 @@ -/* -Copyright 2019 Iguazio Systems Ltd. - -Licensed under the Apache License, Version 2.0 (the "License") with -an addition restriction as set forth herein. You may not use this -file except in compliance with the License. You may obtain a copy of -the License at http://www.apache.org/licenses/LICENSE-2.0. - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing -permissions and limitations under the License. - -In addition, you may not use the software for any purposes that are -illegal under applicable law, and the grant of the foregoing license -under the Apache 2.0 license is conditioned upon your compliance with -such restriction. -*/ -'use strict'; - -// Do this as the first thing so that any code reading it knows the right env. -process.env.BABEL_ENV = 'production'; -process.env.NODE_ENV = 'production'; - -// Makes the script crash on unhandled rejections instead of silently -// ignoring them. In the future, promise rejections that are not handled will -// terminate the Node.js process with a non-zero exit code. -process.on('unhandledRejection', err => { - throw err; -}); - -// Ensure environment variables are read. -require('../config/env'); - -const path = require('path'); -const chalk = require('react-dev-utils/chalk'); -const fs = require('fs-extra'); -const bfj = require('bfj'); -const webpack = require('webpack'); -const configFactory = require('../config/webpack.config'); -const paths = require('../config/paths'); -const checkRequiredFiles = require('react-dev-utils/checkRequiredFiles'); -const formatWebpackMessages = require('react-dev-utils/formatWebpackMessages'); -const printHostingInstructions = require('react-dev-utils/printHostingInstructions'); -const FileSizeReporter = require('react-dev-utils/FileSizeReporter'); -const printBuildError = require('react-dev-utils/printBuildError'); - -const measureFileSizesBeforeBuild = - FileSizeReporter.measureFileSizesBeforeBuild; -const printFileSizesAfterBuild = FileSizeReporter.printFileSizesAfterBuild; -const useYarn = fs.existsSync(paths.yarnLockFile); - -// These sizes are pretty large. We'll warn for bundles exceeding them. -const WARN_AFTER_BUNDLE_GZIP_SIZE = 512 * 1024; -const WARN_AFTER_CHUNK_GZIP_SIZE = 1024 * 1024; - -const isInteractive = process.stdout.isTTY; - -// Warn and crash if required files are missing -if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) { - process.exit(1); -} - -const argv = process.argv.slice(2); -const writeStatsJson = argv.indexOf('--stats') !== -1; - -// Generate configuration -const config = configFactory('production'); - -// We require that you explicitly set browsers and do not fall back to -// browserslist defaults. -const { checkBrowsers } = require('react-dev-utils/browsersHelper'); -checkBrowsers(paths.appPath, isInteractive) - .then(() => { - // First, read the current file sizes in build directory. - // This lets us display how much they changed later. - return measureFileSizesBeforeBuild(paths.appBuild); - }) - .then(previousFileSizes => { - // Remove all content but keep the directory so that - // if you're in it, you don't end up in Trash - fs.emptyDirSync(paths.appBuild); - // Merge with the public folder - copyPublicFolder(); - // Start the webpack build - return build(previousFileSizes); - }) - .then( - ({ stats, previousFileSizes, warnings }) => { - if (warnings.length) { - console.log(chalk.yellow('Compiled with warnings.\n')); - console.log(warnings.join('\n\n')); - console.log( - '\nSearch for the ' + - chalk.underline(chalk.yellow('keywords')) + - ' to learn more about each warning.' - ); - console.log( - 'To ignore, add ' + - chalk.cyan('// eslint-disable-next-line') + - ' to the line before.\n' - ); - } else { - console.log(chalk.green('Compiled successfully.\n')); - } - - console.log('File sizes after gzip:\n'); - printFileSizesAfterBuild( - stats, - previousFileSizes, - paths.appBuild, - WARN_AFTER_BUNDLE_GZIP_SIZE, - WARN_AFTER_CHUNK_GZIP_SIZE - ); - console.log(); - - const appPackage = require(paths.appPackageJson); - const publicUrl = paths.publicUrlOrPath; - const publicPath = config.output.publicPath; - const buildFolder = path.relative(process.cwd(), paths.appBuild); - printHostingInstructions( - appPackage, - publicUrl, - publicPath, - buildFolder, - useYarn - ); - }, - err => { - const tscCompileOnError = process.env.TSC_COMPILE_ON_ERROR === 'true'; - if (tscCompileOnError) { - console.log( - chalk.yellow( - 'Compiled with the following type errors (you may want to check these before deploying your app):\n' - ) - ); - printBuildError(err); - } else { - console.log(chalk.red('Failed to compile.\n')); - printBuildError(err); - process.exit(1); - } - } - ) - .catch(err => { - if (err && err.message) { - console.log(err.message); - } - process.exit(1); - }); - -// Create the production build and print the deployment instructions. -function build(previousFileSizes) { - console.log('Creating an optimized production build...'); - - const compiler = webpack(config); - return new Promise((resolve, reject) => { - compiler.run((err, stats) => { - let messages; - if (err) { - if (!err.message) { - return reject(err); - } - - let errMessage = err.message; - - // Add additional information for postcss errors - if (Object.prototype.hasOwnProperty.call(err, 'postcssNode')) { - errMessage += - '\nCompileError: Begins at CSS selector ' + - err['postcssNode'].selector; - } - - messages = formatWebpackMessages({ - errors: [errMessage], - warnings: [], - }); - } else { - messages = formatWebpackMessages( - stats.toJson({ all: false, warnings: true, errors: true }) - ); - } - if (messages.errors.length) { - // Only keep the first error. Others are often indicative - // of the same problem, but confuse the reader with noise. - if (messages.errors.length > 1) { - messages.errors.length = 1; - } - return reject(new Error(messages.errors.join('\n\n'))); - } - if ( - process.env.CI && - (typeof process.env.CI !== 'string' || - process.env.CI.toLowerCase() !== 'false') && - messages.warnings.length - ) { - // Ignore sourcemap warnings in CI builds. See #8227 for more info. - const filteredWarnings = messages.warnings.filter( - w => !/Failed to parse source map/.test(w) - ); - if (filteredWarnings.length) { - console.log( - chalk.yellow( - '\nTreating warnings as errors because process.env.CI = true.\n' + - 'Most CI servers set it automatically.\n' - ) - ); - return reject(new Error(filteredWarnings.join('\n\n'))); - } - } - - const resolveArgs = { - stats, - previousFileSizes, - warnings: messages.warnings, - }; - - if (writeStatsJson) { - return bfj - .write(paths.appBuild + '/bundle-stats.json', stats.toJson()) - .then(() => resolve(resolveArgs)) - .catch(error => reject(new Error(error))); - } - - return resolve(resolveArgs); - }); - }); -} - -function copyPublicFolder() { - fs.copySync(paths.appPublic, paths.appBuild, { - dereference: true, - filter: file => file !== paths.appHtml, - }); -} diff --git a/scripts/previewLocalBuildMF.mjs b/scripts/previewLocalBuildMF.mjs new file mode 100644 index 0000000000..f1ac97f363 --- /dev/null +++ b/scripts/previewLocalBuildMF.mjs @@ -0,0 +1,9 @@ +import { spawn } from 'child_process' + +const preview = spawn( + 'dotenv', + ['-e', '.env.development.mf', '--', 'vite', 'preview', '--port', '5179'], + { stdio: 'inherit', shell: true } +) + +preview.on('exit', code => process.exit(code ?? 0)) diff --git a/scripts/start.js b/scripts/start.js deleted file mode 100644 index 75b8d3c4db..0000000000 --- a/scripts/start.js +++ /dev/null @@ -1,174 +0,0 @@ -/* -Copyright 2019 Iguazio Systems Ltd. - -Licensed under the Apache License, Version 2.0 (the "License") with -an addition restriction as set forth herein. You may not use this -file except in compliance with the License. You may obtain a copy of -the License at http://www.apache.org/licenses/LICENSE-2.0. - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing -permissions and limitations under the License. - -In addition, you may not use the software for any purposes that are -illegal under applicable law, and the grant of the foregoing license -under the Apache 2.0 license is conditioned upon your compliance with -such restriction. -*/ -'use strict'; - -// Do this as the first thing so that any code reading it knows the right env. -process.env.BABEL_ENV = 'development'; -process.env.NODE_ENV = 'development'; -process.env.PUBLIC_URL = '/'; - -// Makes the script crash on unhandled rejections instead of silently -// ignoring them. In the future, promise rejections that are not handled will -// terminate the Node.js process with a non-zero exit code. -process.on('unhandledRejection', err => { - throw err; -}); - -// Ensure environment variables are read. -require('../config/env'); - -const fs = require('fs'); -const chalk = require('react-dev-utils/chalk'); -const webpack = require('webpack'); -const WebpackDevServer = require('webpack-dev-server'); -const clearConsole = require('react-dev-utils/clearConsole'); -const checkRequiredFiles = require('react-dev-utils/checkRequiredFiles'); -const { - choosePort, - createCompiler, - prepareProxy, - prepareUrls, -} = require('react-dev-utils/WebpackDevServerUtils'); -const openBrowser = require('react-dev-utils/openBrowser'); -const semver = require('semver'); -const paths = require('../config/paths'); -const configFactory = require('../config/webpack.config'); -const createDevServerConfig = require('../config/webpackDevServer.config'); -const getClientEnvironment = require('../config/env'); -const react = require(require.resolve('react', { paths: [paths.appPath] })); - -const env = getClientEnvironment(paths.publicUrlOrPath.slice(0, -1)); -const useYarn = fs.existsSync(paths.yarnLockFile); -const isInteractive = process.stdout.isTTY; - -// Warn and crash if required files are missing -if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) { - process.exit(1); -} - -// Tools like Cloud9 rely on this. -const DEFAULT_PORT = parseInt(process.env.PORT, 10) || 3000; -const HOST = process.env.HOST || '0.0.0.0'; - -if (process.env.HOST) { - console.log( - chalk.cyan( - `Attempting to bind to HOST environment variable: ${chalk.yellow( - chalk.bold(process.env.HOST) - )}` - ) - ); - console.log( - `If this was unintentional, check that you haven't mistakenly set it in your shell.` - ); - console.log( - `Learn more here: ${chalk.yellow('https://cra.link/advanced-config')}` - ); - console.log(); -} - -// We require that you explicitly set browsers and do not fall back to -// browserslist defaults. -const { checkBrowsers } = require('react-dev-utils/browsersHelper'); -checkBrowsers(paths.appPath, isInteractive) - .then(() => { - // We attempt to use the default port but if it is busy, we offer the user to - // run on a different port. `choosePort()` Promise resolves to the next free port. - return choosePort(HOST, DEFAULT_PORT); - }) - .then(port => { - if (port == null) { - // We have not found a port. - return; - } - - const config = configFactory('development'); - const protocol = process.env.HTTPS === 'true' ? 'https' : 'http'; - const appName = require(paths.appPackageJson).name; - - const useTypeScript = fs.existsSync(paths.appTsConfig); - const urls = prepareUrls( - protocol, - HOST, - port, - paths.publicUrlOrPath.slice(0, -1) - ); - // Create a webpack compiler that is configured with custom messages. - const compiler = createCompiler({ - appName, - config, - urls, - useYarn, - useTypeScript, - webpack, - }); - // Load proxy config - const proxySetting = require(paths.appPackageJson).proxy; - const proxyConfig = prepareProxy( - proxySetting, - paths.appPublic, - paths.publicUrlOrPath - ); - // Serve webpack assets generated by the compiler over a web server. - const serverConfig = { - ...createDevServerConfig(proxyConfig, urls.lanUrlForConfig), - host: HOST, - port, - }; - const devServer = new WebpackDevServer(serverConfig, compiler); - // Launch WebpackDevServer. - devServer.startCallback(() => { - if (isInteractive) { - clearConsole(); - } - - if (env.raw.FAST_REFRESH && semver.lt(react.version, '16.10.0')) { - console.log( - chalk.yellow( - `Fast Refresh requires React 16.10 or higher. You are using React ${react.version}.` - ) - ); - } - - console.log(chalk.cyan('Starting the development server...\n')); - openBrowser(urls.localUrlForBrowser); - }); - - ['SIGINT', 'SIGTERM'].forEach(function (sig) { - process.on(sig, function () { - devServer.close(); - process.exit(); - }); - }); - - if (process.env.CI !== 'true') { - // Gracefully exit when stdin ends - process.stdin.on('end', function () { - devServer.close(); - process.exit(); - }); - } - }) - .catch(err => { - if (err && err.message) { - console.log(err.message); - } - process.exit(1); - }); diff --git a/src/App.jsx b/src/App.jsx index 494a38c9fa..c96d00ca87 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -65,85 +65,130 @@ import { JOBS_MONITORING_JOBS_TAB, JOBS_MONITORING_WORKFLOWS_TAB, JOBS_MONITORING_SCHEDULED_TAB, - INACTIVE_JOBS_TAB + INACTIVE_JOBS_TAB, + IS_MF_MODE } from './constants' import 'reactflow/dist/style.css' import 'igz-controls/index.css' import './tailwind.css' import './scss/main.scss' +import RemoteNuclioRouteWrapper from './components/RemoteNuclio/RemoteNuclioRouteWrapper' -const Page = lazyRetry(() => import('./layout/Page/Page')) -const Datasets = lazyRetry(() => import('./components/Datasets/Datasets')) -const FeatureStore = lazyRetry(() => import('./components/FeatureStore/FeatureStore')) -const Files = lazyRetry(() => import('./components/Files/Files')) -const FunctionsOld = lazyRetry(() => import('./components/FunctionsPageOld/FunctionsOld')) // todo [functionsWithPagination] delete FunctionsOld and other related logic in 1.9.0 -const Functions = lazyRetry(() => import('./components/FunctionsPage/Functions')) -const Jobs = lazyRetry(() => import('./components/Jobs/Jobs')) -const MonitorJobs = lazyRetry(() => import('./components/Jobs/MonitorJobs/MonitorJobs')) +const Page = lazyRetry(() => import('./layout/Page/Page'), 'Page') +const Datasets = lazyRetry(() => import('./components/Datasets/Datasets'), 'Datasets') +const FeatureStore = lazyRetry( + () => import('./components/FeatureStore/FeatureStore'), + 'FeatureStore' +) +const Files = lazyRetry(() => import('./components/Files/Files'), 'Files') +const FunctionsOld = lazyRetry( + () => import('./components/FunctionsPageOld/FunctionsOld'), + 'FunctionsOld' +) // todo [functionsWithPagination] delete FunctionsOld and other related logic in 1.9.0 +const Functions = lazyRetry(() => import('./components/FunctionsPage/Functions'), 'Functions') +const Jobs = lazyRetry(() => import('./components/Jobs/Jobs'), 'Jobs') +const MonitorJobs = lazyRetry( + () => import('./components/Jobs/MonitorJobs/MonitorJobs'), + 'MonitorJobs' +) const MonitorWorkflows = lazyRetry( - () => import('./components/Jobs/MonitorWorkflows/MonitorWorkflows') + () => import('./components/Jobs/MonitorWorkflows/MonitorWorkflows'), + 'MonitorWorkflows' +) +const ScheduledJobs = lazyRetry( + () => import('./components/Jobs/ScheduledJobs/ScheduledJobs'), + 'ScheduledJobs' ) -const ScheduledJobs = lazyRetry(() => import('./components/Jobs/ScheduledJobs/ScheduledJobs')) -const Models = lazyRetry(() => import('./components/ModelsPage/Models/Models')) +const Models = lazyRetry(() => import('./components/ModelsPage/Models/Models'), 'Models') const RealTimePipelines = lazyRetry( - () => import('./components/ModelsPage/RealTimePipelines/RealTimePipelines') + () => import('./components/ModelsPage/RealTimePipelines/RealTimePipelines'), + 'RealTimePipelines' ) const ModelEndpoints = lazyRetry( - () => import('./components/ModelsPage/ModelEndpoints/ModelEndpoints') + () => import('./components/ModelsPage/ModelEndpoints/ModelEndpoints'), + 'ModelEndpoints' +) +const ModelsPage = lazyRetry(() => import('./components/ModelsPage/ModelsPage'), 'ModelsPage') +const Projects = lazyRetry(() => import('./components/ProjectsPage/Projects'), 'Projects') +const ProjectMonitor = lazyRetry( + () => import('./components/Project/ProjectMonitor'), + 'ProjectMonitor' ) -const ModelsPage = lazyRetry(() => import('./components/ModelsPage/ModelsPage')) -const Projects = lazyRetry(() => import('./components/ProjectsPage/Projects')) -const ProjectMonitor = lazyRetry(() => import('./components/Project/ProjectMonitor')) const ConsumerGroupsWrapper = lazyRetry( - () => import('./components/ConsumerGroupsWrapper/ConsumerGroupsWrapper') + () => import('./components/ConsumerGroupsWrapper/ConsumerGroupsWrapper'), + 'ConsumerGroupsWrapper' +) +const ConsumerGroup = lazyRetry( + () => import('./components/ConsumerGroup/ConsumerGroup'), + 'ConsumerGroup' +) +const ConsumerGroups = lazyRetry( + () => import('./components/ConsumerGroups/ConsumerGroups'), + 'ConsumerGroups' ) -const ConsumerGroup = lazyRetry(() => import('./components/ConsumerGroup/ConsumerGroup')) -const ConsumerGroups = lazyRetry(() => import('./components/ConsumerGroups/ConsumerGroups')) const ProjectOverview = lazyRetry( - () => import('./components/Project/ProjectOverview/ProjectOverview') + () => import('./components/Project/ProjectOverview/ProjectOverview'), + 'ProjectOverview' +) +const ProjectSettings = lazyRetry( + () => import('./components/ProjectSettings/ProjectSettings'), + 'ProjectSettings' ) -const ProjectSettings = lazyRetry(() => import('./components/ProjectSettings/ProjectSettings')) const AddToFeatureVectorPage = lazyRetry( - () => import('./components/AddToFeatureVectorPage/AddToFeatureVectorPage') + () => import('./components/AddToFeatureVectorPage/AddToFeatureVectorPage'), + 'AddToFeatureVectorPage' +) +const FeatureSets = lazyRetry( + () => import('./components/FeatureStore/FeatureSets/FeatureSets'), + 'FeatureSets' ) -const FeatureSets = lazyRetry(() => import('./components/FeatureStore/FeatureSets/FeatureSets')) -const Features = lazyRetry(() => import('./components/FeatureStore/Features/Features')) +const Features = lazyRetry(() => import('./components/FeatureStore/Features/Features'), 'Features') const FeatureVectors = lazyRetry( - () => import('./components/FeatureStore/FeatureVectors/FeatureVectors') + () => import('./components/FeatureStore/FeatureVectors/FeatureVectors'), + 'FeatureVectors' ) const ProjectsJobsMonitoring = lazyRetry( - () => import('./components/ProjectsJobsMonitoring/ProjectsJobsMonitoring') + () => import('./components/ProjectsJobsMonitoring/ProjectsJobsMonitoring'), + 'ProjectsJobsMonitoring' ) -const ProjectsAlerts = lazyRetry(() => import('./components/Alerts/Alerts')) +const ProjectsAlerts = lazyRetry(() => import('./components/Alerts/Alerts'), 'ProjectsAlerts') const JobsMonitoring = lazyRetry( - () => import('./components/ProjectsJobsMonitoring/JobsMonitoring/JobsMonitoring') + () => import('./components/ProjectsJobsMonitoring/JobsMonitoring/JobsMonitoring'), + 'JobsMonitoring' ) const ScheduledMonitoring = lazyRetry( - () => import('./components/ProjectsJobsMonitoring/ScheduledMonitoring/ScheduledMonitoring') + () => import('./components/ProjectsJobsMonitoring/ScheduledMonitoring/ScheduledMonitoring'), + 'ScheduledMonitoring' ) const WorkflowsMonitoring = lazyRetry( - () => import('./components/ProjectsJobsMonitoring/WorkflowsMonitoring/WorkflowsMonitoring') + () => import('./components/ProjectsJobsMonitoring/WorkflowsMonitoring/WorkflowsMonitoring'), + 'WorkflowsMonitoring' ) -const Documents = lazyRetry(() => import('./components/Documents/Documents')) -const LLMPrompts = lazyRetry(() => import('./components/LLMPrompts/LLMPrompts')) +const Documents = lazyRetry(() => import('./components/Documents/Documents'), 'Documents') +const LLMPrompts = lazyRetry(() => import('./components/LLMPrompts/LLMPrompts'), 'LLMPrompts') const ApplicationMetrics = lazyRetry( - () => import('./components/ApplicationMetrics/ApplicationMetrics') + () => import('./components/ApplicationMetrics/ApplicationMetrics'), + 'ApplicationMetrics' ) const MonitoringApplicationsPage = lazyRetry( - () => import('./components/MonitoringApplicationsPage/MonitoringApplicationsPage') + () => import('./components/MonitoringApplicationsPage/MonitoringApplicationsPage'), + 'MonitoringApplicationsPage' ) const MonitoringApplications = lazyRetry( () => - import('./components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplications') + import('./components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplications'), + 'MonitoringApplications' ) const MonitoringApplication = lazyRetry( () => - import('./components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplication/MonitoringApplication') + import('./components/MonitoringApplicationsPage/MonitoringApplications/MonitoringApplication/MonitoringApplication'), + 'MonitoringApplication' ) const ApplicationsPage = lazyRetry( - () => import('./nextGenComponents/pages/ApplicationsPage/ApplicationsPage') + () => import('./nextGenComponents/pages/ApplicationsPage/ApplicationsPage'), + 'ApplicationsPage' ) const App = () => { const { isNuclioModeDisabled } = useNuclioMode() @@ -163,6 +208,14 @@ const App = () => { <> }> } /> + {IS_MF_MODE && ( + + } /> + } /> + } /> + } /> + + )} }> {[ `${JOBS_MONITORING_JOBS_TAB}/:jobName/:jobId/:tab`, @@ -189,7 +242,6 @@ const App = () => { } /> } /> - } /> } /> {[ diff --git a/src/api/jobs-api.js b/src/api/jobs-api.js index 34da1baddc..bd5686840b 100644 --- a/src/api/jobs-api.js +++ b/src/api/jobs-api.js @@ -19,7 +19,7 @@ such restriction. */ import { isNil } from 'lodash' -import { mainBaseUrl, mainHttpClient } from '../httpClient' +import { mainHttpClient } from '../httpClient' const jobsApi = { abortJob: (project, jobId, iter) => { @@ -76,10 +76,17 @@ const jobsApi = { params = `?attempt=${attempt}` } - return fetch(`${mainBaseUrl}/projects/${project}/logs/${id}${params}`, { - method: 'get', - signal - }) + // when we use adapter: 'fetch' in axios, we need to pass params as query string, because axios drops params in this case + const queryParams = new URLSearchParams(params).toString() + + return mainHttpClient.get( + `/projects/${project}/logs/${id}${queryParams ? '?' + queryParams : ''}`, + { + signal, + responseType: 'stream', + adapter: 'fetch' + } + ) }, getScheduledJobs: (project, newConfig) => { return mainHttpClient.get(`/projects/${project}/schedules`, newConfig) diff --git a/src/api/projects-iguazio-api.js b/src/api/projects-iguazio-api.js index edc7d3c702..2648eaf8fe 100644 --- a/src/api/projects-iguazio-api.js +++ b/src/api/projects-iguazio-api.js @@ -19,51 +19,51 @@ such restriction. */ import { iguazioHttpClient } from '../httpClient' -const projectsIguazioApi = { +const igz3Api = { editProject: (projectId, data) => iguazioHttpClient.put(`/projects/${projectId}`, data), getProjectJob: jobId => iguazioHttpClient.get(`/jobs/${jobId}`), - getProjects: config => { - return iguazioHttpClient.get('/projects', config) - }, - getProjectMembers: projectId => { - return iguazioHttpClient.get(`/projects/${projectId}`, { + getProjects: config => iguazioHttpClient.get('/projects', config), + getProjectMembers: projectId => + iguazioHttpClient.get(`/projects/${projectId}`, { params: { include: 'project_authorization_roles.principal_users,project_authorization_roles.principal_user_groups' } - }) - }, - getProjectMembersVisibility: project => { - return iguazioHttpClient.get(`/projects/__name__/${project}/authorization`, { - params: { - action: 'authorization/roles', - sub_resource: 'authorization/roles' - } - }) - }, - getProjectOwnerVisibility: project => { - return iguazioHttpClient.get(`/projects/__name__/${project}/authorization`, { - params: { - action: 'update', - sub_resource: 'authorization/owner' - } - }) - }, - getProjectWorkflowsUpdateAuthorization: project => { - return iguazioHttpClient.get(`/projects/__name__/${project}/authorization`, { - params: { - action: 'update', - sub_resource: 'workflow' - } - }) - }, - - updateProjectMembers: data => { - return iguazioHttpClient.post('/async_transactions', data) - }, + }), + getProjectMembersVisibility: project => + iguazioHttpClient.get(`/projects/__name__/${project}/authorization`, { + params: { action: 'authorization/roles', sub_resource: 'authorization/roles' } + }), + getProjectOwnerVisibility: project => + iguazioHttpClient.get(`/projects/__name__/${project}/authorization`, { + params: { action: 'update', sub_resource: 'authorization/owner' } + }), + getProjectWorkflowsUpdateAuthorization: project => + iguazioHttpClient.get(`/projects/__name__/${project}/authorization`, { + params: { action: 'update', sub_resource: 'workflow' } + }), + updateProjectMembers: data => iguazioHttpClient.post('/async_transactions', data), getScrubbedUsers: config => iguazioHttpClient.get('/scrubbed_users', config), getScrubbedUserGroups: config => iguazioHttpClient.get('/scrubbed_user_groups', config), getActiveUser: () => iguazioHttpClient.get('/self') } -export default projectsIguazioApi +const igz4Api = { + updateProjectOwner: (projectName, owner) => + iguazioHttpClient.put(`/v1/authorization/projects/${projectName}/owner`, { + owner, + project: projectName + }), + getProjectPolicies: projectName => + iguazioHttpClient.get(`/v1/authorization/projects/${projectName}/policies`), + setProjectMembership: (projectName, data) => + iguazioHttpClient.put(`/v1/authorization/projects/${projectName}/roles`, data), + searchUsersMetadata: searchTerm => + iguazioHttpClient.get('/v1/profile/search-users-metadata', { params: { searchTerm } }), + searchGroupsMetadata: searchTerm => + iguazioHttpClient.get('/v1/profile/search-groups-metadata', { params: { searchTerm } }), + getActiveUser: () => + iguazioHttpClient.get('/v1/authentication/self', { params: { format: 'full' } }) +} + +export default import.meta.env.VITE_FEDERATION === 'true' ? igz4Api : igz3Api diff --git a/src/common/Download/Download.jsx b/src/common/Download/Download.jsx index 2789e10b0c..145bd9d8e9 100644 --- a/src/common/Download/Download.jsx +++ b/src/common/Download/Download.jsx @@ -48,8 +48,8 @@ const Download = ({ () => disabled || !path || - (artifactLimits?.max_download_size && fileSize > artifactLimits.max_download_size), - [disabled, artifactLimits.max_download_size, fileSize, path] + (artifactLimits?.max_download_size && fileSize > artifactLimits?.max_download_size), + [disabled, artifactLimits?.max_download_size, fileSize, path] ) const downloadClassNames = classnames( 'download', diff --git a/src/common/HostLeaveGuard/HostLeaveGuard.jsx b/src/common/HostLeaveGuard/HostLeaveGuard.jsx new file mode 100644 index 0000000000..23ae0d40dd --- /dev/null +++ b/src/common/HostLeaveGuard/HostLeaveGuard.jsx @@ -0,0 +1,80 @@ +/* +Copyright 2019 Iguazio Systems Ltd. + +Licensed under the Apache License, Version 2.0 (the "License") with +an addition restriction as set forth herein. You may not use this +file except in compliance with the License. You may obtain a copy of +the License at http://www.apache.org/licenses/LICENSE-2.0. + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing +permissions and limitations under the License. + +In addition, you may not use the software for any purposes that are +illegal under applicable law, and the grant of the foregoing license +under the Apache 2.0 license is conditioned upon your compliance with +such restriction. +*/ +import { useEffect, useRef } from 'react' +import { useBlocker } from 'react-router-dom' + +/** + * Bridges host (mlrun-ui) navigation to a guard published by an embedded remote + * (nuclio) on `window.__igzLeaveGuard`. Because this host owns its own router, + * the remote's own `useBlocker` can't see navigations triggered from host chrome + * (navbar, breadcrumbs, programmatic `navigate()`, Back/Forward). This blocker + * runs inside the host router, so it catches all of them before they commit and + * delegates the confirmation prompt back to the remote (which stays mounted + * while the navigation is blocked). + * + * It is a no-op whenever no remote guard is registered. + */ +const HostLeaveGuard = () => { + const blocker = useBlocker(({ currentLocation, nextLocation }) => { + try { + return Boolean( + window.__igzLeaveGuard?.shouldBlock(currentLocation.pathname, nextLocation.pathname) + ) + } catch { + // Fail open: a broken/stale guard must never trap navigation. + return false + } + }) + + const blockerRef = useRef(blocker) + useEffect(() => { + blockerRef.current = blocker + }, [blocker]) + + useEffect(() => { + if (blocker.state !== 'blocked') return + + let active = true + const confirm = window.__igzLeaveGuard?.confirm + + Promise.resolve(confirm ? confirm() : true) + .then(confirmed => { + if (!active) return + + if (confirmed) { + blockerRef.current.proceed?.() + } else { + blockerRef.current.reset?.() + } + }) + .catch(() => { + // Fail open: never leave the user stuck if the prompt errors out. + if (active) blockerRef.current.proceed?.() + }) + + return () => { + active = false + } + }, [blocker.state]) + + return null +} + +export default HostLeaveGuard diff --git a/src/common/TokenExpiryBanner/TokenExpiryBanner.jsx b/src/common/TokenExpiryBanner/TokenExpiryBanner.jsx new file mode 100755 index 0000000000..2e7f6df605 --- /dev/null +++ b/src/common/TokenExpiryBanner/TokenExpiryBanner.jsx @@ -0,0 +1,64 @@ +/* +Copyright 2019 Iguazio Systems Ltd. + +Licensed under the Apache License, Version 2.0 (the "License") with +an addition restriction as set forth herein. You may not use this +file except in compliance with the License. You may obtain a copy of +the License at http://www.apache.org/licenses/LICENSE-2.0. + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing +permissions and limitations under the License. + +In addition, you may not use the software for any purposes that are +illegal under applicable law, and the grant of the foregoing license +under the Apache 2.0 license is conditioned upon your compliance with +such restriction. +*/ +import React from 'react' + +import useApiTokenExpiry from '../../hooks/useApiTokenExpiry' + +import WarningTriangle from './warningTriangle.svg?react' +import CloseIcon from './closeIcon.svg?react' + +import './tokenExpiryBanner.scss' + +const TokenExpiryBanner = () => { + const { hasExpiring, daysLeftLabel, dismiss } = useApiTokenExpiry() + + if (!hasExpiring) return null + + const handleLinkClick = e => { + e.preventDefault() + const url = `${window.location.pathname}?settings=tokens` + window.history.pushState(null, '', url) + window.dispatchEvent(new PopStateEvent('popstate', { state: null })) + } + + return ( +
+ + + + Your access token will expire in {daysLeftLabel}. Please renew it or create a new one under{' '} + + API Tokens + + . + + + +
+ ) +} + +export default TokenExpiryBanner diff --git a/src/common/TokenExpiryBanner/closeIcon.svg b/src/common/TokenExpiryBanner/closeIcon.svg new file mode 100644 index 0000000000..1dd857670f --- /dev/null +++ b/src/common/TokenExpiryBanner/closeIcon.svg @@ -0,0 +1,4 @@ + diff --git a/src/common/TokenExpiryBanner/tokenExpiryBanner.scss b/src/common/TokenExpiryBanner/tokenExpiryBanner.scss new file mode 100644 index 0000000000..df6a6a25fa --- /dev/null +++ b/src/common/TokenExpiryBanner/tokenExpiryBanner.scss @@ -0,0 +1,53 @@ +.token-expiry-banner { + display: flex; + align-items: center; + gap: 12px; + padding: 8px 20px; + border-bottom: 1px solid #F98B0A4D; + background-color: #ffeedf; + color: #4B4760; + + &__icon { + flex-shrink: 0; + width: 16px; + height: 16px; + } + + &__message { + flex: 1; + font-size: 13px; + line-height: 1.4; + } + + &__link { + color: #6279E7; + text-decoration: none; + + &:hover { + text-decoration: underline; + } + } + + &__close { + display: inline-flex; + align-items: center; + justify-content: center; + width: 40px; + height: 40px; + padding: 0; + margin: 0; + background: none; + border: none; + cursor: pointer; + color: #4B4760; + + &:hover { + opacity: 0.7; + } + + svg { + width: 16px; + height: 16px; + } + } +} diff --git a/src/common/TokenExpiryBanner/warningTriangle.svg b/src/common/TokenExpiryBanner/warningTriangle.svg new file mode 100644 index 0000000000..f68883fcf6 --- /dev/null +++ b/src/common/TokenExpiryBanner/warningTriangle.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/components/Datasets/datasets.util.jsx b/src/components/Datasets/datasets.util.jsx index be254d15cf..3003f9d074 100644 --- a/src/components/Datasets/datasets.util.jsx +++ b/src/components/Datasets/datasets.util.jsx @@ -176,7 +176,7 @@ export const generateActionsMenu = ( disabled: !isTargetPathValid || datasetMin.size > - (frontendSpec.artifact_limits.max_download_size ?? ARTIFACT_MAX_DOWNLOAD_SIZE), + (frontendSpec.artifact_limits?.max_download_size ?? ARTIFACT_MAX_DOWNLOAD_SIZE), icon: , onClick: datasetMin => { getFullDataset(datasetMin).then(dataset => { diff --git a/src/components/Details/details.util.js b/src/components/Details/details.util.js index f7469b815c..550930288f 100644 --- a/src/components/Details/details.util.js +++ b/src/components/Details/details.util.js @@ -40,7 +40,9 @@ import { FUNCTION_TYPE_LOCAL, MODEL_ENDPOINTS_TAB, MODELS_TAB, - TAG_LATEST + TAG_LATEST, + IS_MF_MODE, + NUCLIO_FUNCTIONS_PATH } from '../../constants' import { generateLinkPath, generateNuclioLink, parseUri } from '../../utils' import { getFunctionImage } from '../FunctionsPage/functions.util' @@ -332,8 +334,10 @@ export const generateRealTimePipelinesContent = selectedItem => { status: selectedItem.state.value, statusLabel: selectedItem.state.label, className: selectedItem.state.className, - link: generateNuclioLink(`/projects/${selectedItem.project}/functions/${nuclioFunctionName}`), - linkIsExternal: true + link: generateNuclioLink( + `/projects/${selectedItem.project}/${NUCLIO_FUNCTIONS_PATH}/${nuclioFunctionName}` + ), + linkIsExternal: !IS_MF_MODE }, childFunction: { value: selectedItem.childFunctions ?? selectedItem.function_refs ?? [], diff --git a/src/components/FeatureSetsPanel/FeatureSetsPanelView.jsx b/src/components/FeatureSetsPanel/FeatureSetsPanelView.jsx index ef542f1ca9..e260b7531b 100644 --- a/src/components/FeatureSetsPanel/FeatureSetsPanelView.jsx +++ b/src/components/FeatureSetsPanel/FeatureSetsPanelView.jsx @@ -119,6 +119,7 @@ const FeatureSetsPanelView = ({ dispatch(setNewFeatureSetCredentialsAccessKey(value))} setValidation={setValidation} diff --git a/src/components/JobWizard/JobWizard.jsx b/src/components/JobWizard/JobWizard.jsx index 842cff7efa..581d492d18 100644 --- a/src/components/JobWizard/JobWizard.jsx +++ b/src/components/JobWizard/JobWizard.jsx @@ -54,7 +54,8 @@ import { PARAMETERS_STEP, RESOURCES_STEP, RUN_DETAILS_STEP, - SCHEDULE_TAB + SCHEDULE_TAB, + IS_MF_MODE } from '../../constants' import { generateJobRequestData, @@ -359,14 +360,13 @@ const JobWizard = ({ mode, true ) - const credentials = jobRequestData.function?.metadata?.credentials - - delete jobRequestData.function.metadata + const credentials = IS_MF_MODE ? null : jobRequestData.function?.metadata?.credentials + if (!IS_MF_MODE) delete jobRequestData.function.metadata dispatch( editJob({ postData: { - credentials, + ...(credentials && { credentials }), scheduled_object: jobRequestData, cron_trigger: jobRequestData.schedule }, diff --git a/src/components/JobWizard/JobWizard.util.js b/src/components/JobWizard/JobWizard.util.js index e3e596b06e..10e30ff80c 100644 --- a/src/components/JobWizard/JobWizard.util.js +++ b/src/components/JobWizard/JobWizard.util.js @@ -42,6 +42,7 @@ import { EXISTING_IMAGE_SOURCE, FUNCTION_DEFAULT_HANDLER, HYPERPARAMETER_STRATEGY_STEP, + IS_MF_MODE, JOB_DEFAULT_OUTPUT_PATH, LIST_TUNING_STRATEGY, MAX_SELECTOR_CRITERIA, @@ -167,12 +168,12 @@ export const generateJobWizardData = ( }, [ADVANCED_STEP]: { inputPath: null, - outputPath: - currentProject?.spec?.artifact_path || - (frontendSpec.ce?.version && frontendSpec.default_artifact_path) || - JOB_DEFAULT_OUTPUT_PATH, - accessKey: true, - accessKeyInput: '', + outputPath: IS_MF_MODE + ? currentProject?.spec?.artifact_path || frontendSpec.default_artifact_path + : currentProject?.spec?.artifact_path || + (frontendSpec.ce?.version && frontendSpec.default_artifact_path) || + JOB_DEFAULT_OUTPUT_PATH, + ...(IS_MF_MODE ? { apiTokenInput: 'default' } : { accessKey: true, accessKeyInput: '' }), environmentVariablesTable: parseEnvironmentVariables(environmentVariables) // secretSourcesTable - currently not shown // secretSourcesTable: [] @@ -290,12 +291,16 @@ export const generateJobWizardDefaultData = ( [ADVANCED_STEP]: { inputPath: defaultData.task.spec.input_path, outputPath: defaultData.task.spec.output_path, - accessKey: - defaultData.function?.metadata?.credentials?.access_key === PANEL_DEFAULT_ACCESS_KEY, - accessKeyInput: - defaultData.function?.metadata?.credentials?.access_key === PANEL_DEFAULT_ACCESS_KEY - ? '' - : defaultData.function?.metadata?.credentials?.access_key, + ...(IS_MF_MODE + ? { apiTokenInput: defaultData.task.spec?.auth?.token_name ?? 'default' } + : { + accessKey: + defaultData.function?.metadata?.credentials?.access_key === PANEL_DEFAULT_ACCESS_KEY, + accessKeyInput: + defaultData.function?.metadata?.credentials?.access_key === PANEL_DEFAULT_ACCESS_KEY + ? '' + : defaultData.function?.metadata?.credentials?.access_key + }), environmentVariablesTable: parseEnvironmentVariables(defaultData.function?.spec?.env ?? []) // secretSourcesTable - currently not shown // secretSourcesTable: parseSecretSources(defaultData.task.spec.secret_sources) @@ -1025,6 +1030,10 @@ export const generateJobRequestData = ( labels: convertChipsData(labels) }, spec: { + ...(IS_MF_MODE && + formData[ADVANCED_STEP].apiTokenInput && { + auth: { token_name: formData[ADVANCED_STEP].apiTokenInput } + }), inputs: generateDataInputs(formData[DATA_INPUTS_STEP].dataInputsTable), parameters: generateParameters(formData[PARAMETERS_STEP].parametersTable), // secretSourcesTable - currently not shown @@ -1044,13 +1053,15 @@ export const generateJobRequestData = ( } }, function: { - metadata: { - credentials: { - access_key: formData[ADVANCED_STEP].accessKey - ? PANEL_DEFAULT_ACCESS_KEY - : formData[ADVANCED_STEP].accessKeyInput + ...(!IS_MF_MODE && { + metadata: { + credentials: { + access_key: formData[ADVANCED_STEP].accessKey + ? PANEL_DEFAULT_ACCESS_KEY + : formData[ADVANCED_STEP].accessKeyInput + } } - }, + }), spec: { image: formData[RUN_DETAILS_STEP].image?.imageSource === EXISTING_IMAGE_SOURCE diff --git a/src/components/JobWizard/JobWizardSteps/JobWizardAdvanced/JobWizardAdvanced.jsx b/src/components/JobWizard/JobWizardSteps/JobWizardAdvanced/JobWizardAdvanced.jsx index af40a04ab6..ea00869ac6 100644 --- a/src/components/JobWizard/JobWizardSteps/JobWizardAdvanced/JobWizardAdvanced.jsx +++ b/src/components/JobWizard/JobWizardSteps/JobWizardAdvanced/JobWizardAdvanced.jsx @@ -24,7 +24,7 @@ import { useSelector } from 'react-redux' import FormEnvironmentVariablesTable from '../../../../elements/FormEnvironmentVariablesTable/FormEnvironmentVariablesTable' import { FormCheckBox, FormInput, FormKeyValueTable, FormOnChange } from 'igz-controls/components' -import { ADVANCED_STEP } from '../../../../constants' +import { ADVANCED_STEP, API_TOKEN_TIP, IS_MF_MODE } from '../../../../constants' import { secretsKindOptions } from './JobWizardAdvanced.util' import './jobWizardAdvanced.scss' @@ -73,19 +73,35 @@ const JobWizardAdvanced = ({ formState, stepIsActive = false }) => { -
- {!frontendSpec.ce?.version && ( -
- -
- )} - {!formState.values?.[ADVANCED_STEP]?.accessKey && ( -
- -
- )} -
- {stepIsActive && ( + {!frontendSpec.ce?.version && ( +
+ {IS_MF_MODE ? ( +
+ +
+ ) : ( + <> +
+ +
+ {!formState.values?.[ADVANCED_STEP]?.accessKey && ( +
+ +
+ )} + + )} +
+ )} + {!IS_MF_MODE && formState.values?.[ADVANCED_STEP] !== undefined && stepIsActive && ( formState.form.change(`${ADVANCED_STEP}.accessKeyInput`, '')} name={`${ADVANCED_STEP}.accessKey`} diff --git a/src/components/JobWizard/JobWizardSteps/JobWizardAdvanced/jobWizardAdvanced.scss b/src/components/JobWizard/JobWizardSteps/JobWizardAdvanced/jobWizardAdvanced.scss index d4dbe92516..0a183a6a5f 100644 --- a/src/components/JobWizard/JobWizardSteps/JobWizardAdvanced/jobWizardAdvanced.scss +++ b/src/components/JobWizard/JobWizardSteps/JobWizardAdvanced/jobWizardAdvanced.scss @@ -2,4 +2,9 @@ .access-key-checkbox { margin: 30px 10px 0 10px; } + + .api-token-field { + display: flex; + align-items: center; + } } diff --git a/src/components/Jobs/jobs.util.js b/src/components/Jobs/jobs.util.js index deaeb4d74b..8dfc514bf5 100644 --- a/src/components/Jobs/jobs.util.js +++ b/src/components/Jobs/jobs.util.js @@ -41,6 +41,7 @@ import { COMPLETED_STATE, ABORTED_STATE, ABORTING_STATE, + IS_MF_MODE, PENDING_RETRY_STATE } from '../../constants' import { @@ -177,11 +178,13 @@ const generateEditableItem = (functionData, job) => { return { rerun_object: { function: { - metadata: { - credentials: { - access_key: functionData?.metadata?.credentials?.access_key ?? '' + ...(!IS_MF_MODE && { + metadata: { + credentials: { + access_key: functionData?.metadata?.credentials?.access_key ?? '' + } } - }, + }), spec: { env: functionData?.spec.env ?? [], resources: functionData?.spec.resources, @@ -200,6 +203,7 @@ const generateEditableItem = (functionData, job) => { project: job.project }, spec: { + ...(IS_MF_MODE && job.auth?.token_name && { auth: { token_name: job.auth.token_name } }), hyper_param_options: job.hyper_param_options, function: job.function, handler: job?.handler ?? '', diff --git a/src/components/LLMPrompts/llmPrompts.util.jsx b/src/components/LLMPrompts/llmPrompts.util.jsx index f10cdc8a23..c02e782cee 100644 --- a/src/components/LLMPrompts/llmPrompts.util.jsx +++ b/src/components/LLMPrompts/llmPrompts.util.jsx @@ -143,7 +143,7 @@ export const generateActionsMenu = ( disabled: !isTargetPathValid || llmPromptMin.size > - (frontendSpec.artifact_limits.max_download_size ?? ARTIFACT_MAX_DOWNLOAD_SIZE), + (frontendSpec.artifact_limits?.max_download_size ?? ARTIFACT_MAX_DOWNLOAD_SIZE), icon: , onClick: llmPromptMin => { getFullLLMPrompt(llmPromptMin).then(llmPrompt => { diff --git a/src/components/MonitoringApplicationsPage/MonitoringApplications/monitoringApplications.util.js b/src/components/MonitoringApplicationsPage/MonitoringApplications/monitoringApplications.util.js index 0030cddf53..0522b327e5 100644 --- a/src/components/MonitoringApplicationsPage/MonitoringApplications/monitoringApplications.util.js +++ b/src/components/MonitoringApplicationsPage/MonitoringApplications/monitoringApplications.util.js @@ -21,6 +21,7 @@ import classnames from 'classnames' import moment from 'moment' import { generateNuclioLink } from '../../../utils' +import { IS_MF_MODE, NUCLIO_FUNCTIONS_PATH } from '../../../constants' import { formatDatetime } from 'igz-controls/utils/datetime.util' export const generateOperatingFunctionsTable = (functions, projectName) => { @@ -52,7 +53,9 @@ export const generateOperatingFunctionsTable = (functions, projectName) => { return { name: { value: func.name, - href: generateNuclioLink(`/projects/${projectName}/functions/${nuclioFunctionName}`), + [IS_MF_MODE ? 'link' : 'href']: generateNuclioLink( + `/projects/${projectName}/${NUCLIO_FUNCTIONS_PATH}/${nuclioFunctionName}` + ), className: 'table-cell_big' }, status: { diff --git a/src/components/Project/ProjectOverview/ProjectOverview.util.jsx b/src/components/Project/ProjectOverview/ProjectOverview.util.jsx index 0c37be292f..c853ae54e1 100644 --- a/src/components/Project/ProjectOverview/ProjectOverview.util.jsx +++ b/src/components/Project/ProjectOverview/ProjectOverview.util.jsx @@ -23,7 +23,7 @@ import JobWizard from '../../JobWizard/JobWizard' import RegisterArtifactModal from '../../RegisterArtifactModal/RegisterArtifactModal' import RegisterModelModal from '../../../elements/RegisterModelModal/RegisterModelModal' -import { ARTIFACT_TYPE, DATASET_TYPE } from '../../../constants' +import { ARTIFACT_TYPE, DATASET_TYPE, IS_MF_MODE, NUCLIO_FUNCTIONS_PATH } from '../../../constants' import { PRIMARY_BUTTON, TERTIARY_BUTTON } from 'igz-controls/constants' import { generateNuclioLink } from '../../../utils' import { isSubmitDisabled } from 'igz-controls/utils/form.util' @@ -391,8 +391,10 @@ export const getInitialCards = (params, navigate, isDemoMode) => { icon: , label: 'Create real-time function', handleClick: () => ({ - path: generateNuclioLink(`${base_url}/create-function`), - externalLink: true + path: IS_MF_MODE + ? `/projects/${params.projectName}/${NUCLIO_FUNCTIONS_PATH}/create-function` + : generateNuclioLink(`/projects/${params.projectName}/create-function`), + externalLink: !IS_MF_MODE }), tooltip: 'These are typically used for serving, APIs, and stream processing. Specify the code, resources, and triggers.' @@ -445,8 +447,8 @@ export const getInitialCards = (params, navigate, isDemoMode) => { { id: 'nuclioFunctions', handleClick: () => ({ - path: generateNuclioLink(`${base_url}/functions`), - externalLink: true + path: generateNuclioLink(`${base_url}/${NUCLIO_FUNCTIONS_PATH}`), + externalLink: !IS_MF_MODE }), label: 'Nuclio functions' }, diff --git a/src/components/Project/project.utils.jsx b/src/components/Project/project.utils.jsx index 077f4282cb..9cc53082e8 100644 --- a/src/components/Project/project.utils.jsx +++ b/src/components/Project/project.utils.jsx @@ -21,7 +21,7 @@ import React from 'react' import JobWizard from '../JobWizard/JobWizard' -import { ARTIFACT_TYPE, DATASET_TYPE } from '../../constants' +import { ARTIFACT_TYPE, DATASET_TYPE, IS_MF_MODE, NUCLIO_FUNCTIONS_PATH } from '../../constants' import { PRIMARY_BUTTON, FORBIDDEN_ERROR_STATUS_CODE } from 'igz-controls/constants' import { showErrorNotification } from 'igz-controls/utils/notification.util' @@ -101,7 +101,11 @@ export const generateCreateNewOptions = ( id: 'createRealTimeFunction', icon: , handler: () => { - const url = generateNuclioLink(`/projects/${params.projectName}/create-function`) + if (IS_MF_MODE) { + return navigate(`/projects/${params.projectName}/${NUCLIO_FUNCTIONS_PATH}/create-function`) + } + + const url = generateNuclioLink(`/projects/${params.projectName}}/create-function`) if (window.top && window.top !== window.self) { window.top.location.assign(url) diff --git a/src/components/ProjectSettings/ProjectSettings.jsx b/src/components/ProjectSettings/ProjectSettings.jsx index 5d75f70f82..aa174016da 100644 --- a/src/components/ProjectSettings/ProjectSettings.jsx +++ b/src/components/ProjectSettings/ProjectSettings.jsx @@ -44,6 +44,7 @@ import projectsIguazioApi from '../../api/projects-iguazio-api' import { DANGER_BUTTON, TERTIARY_BUTTON } from 'igz-controls/constants' import { COMPLETED_STATE, + IS_MF_MODE, PROJECTS_SETTINGS_MEMBERS_TAB, PROJECTS_SETTINGS_SECRETS_TAB } from '../../constants' @@ -75,14 +76,36 @@ const ProjectSettings = () => { ) const userIsProjectOwner = useMemo(() => { + if (IS_MF_MODE) { + const activeUsername = membersState?.activeUser?.data?.attributes?.username + const ownerUsername = membersState?.projectInfo?.owner?.username + return Boolean(activeUsername && activeUsername === ownerUsername) + } return membersState?.activeUser?.data?.id === membersState?.projectInfo?.owner.id }, [membersState]) + const userIsSystemAdmin = useMemo( + () => + membersState?.activeUser?.data?.attributes?.user_policies_collection?.has('System Admin') ?? + false, + [membersState?.activeUser?.data?.attributes?.user_policies_collection] + ) + const projectMembersTabIsShown = useMemo( () => isProjectMembersTabShown(projectMembershipIsEnabled, userIsProjectOwner, membersState), [userIsProjectOwner, membersState, projectMembershipIsEnabled] ) + const fetchProjectPolicies = useCallback(() => { + return projectsIguazioApi + .getProjectPolicies(params.projectName) + .then(policiesResponse => generateMembers(policiesResponse, membersDispatch)) + .catch(error => { + showErrorNotification(dispatch, error, 'Failed to fetch project members') + throw error + }) + }, [dispatch, params.projectName]) + const fetchProjectIdAndOwner = useCallback(() => { return projectsIguazioApi .getProjects({ @@ -120,6 +143,7 @@ const ProjectSettings = () => { }, [dispatch] ) + const fetchProjectMembersVisibility = project => { projectsIguazioApi .getProjectMembersVisibility(project) @@ -130,23 +154,58 @@ const ProjectSettings = () => { setProjectMembersIsShown(false) }) } + const fetchActiveUser = () => { projectsIguazioApi.getActiveUser().then(response => { - const activeUser = response.data - activeUser.data.attributes.user_policies_collection = new Set([ - ...activeUser.data.attributes.assigned_policies, - ...(activeUser.included?.reduce?.( - (policies, group) => [...policies, ...group.attributes.assigned_policies], - [] - ) || []) - ]) - - membersDispatch({ - type: membersActions.SET_ACTIVE_USER, - payload: activeUser - }) + if (IS_MF_MODE) { + const activeUser = response.data + const relationships = activeUser.relationships || [] + + const userGroupNames = new Set( + relationships + .filter(rel => rel['@type']?.includes('usergroup')) + .map(rel => rel.spec?.name) + .filter(Boolean) + ) + + const userPoliciesCollection = new Set( + relationships + .filter(rel => rel['@type']?.includes('policy.Policy')) + .map(rel => rel.spec?.displayName) + .filter(Boolean) + ) + + membersDispatch({ + type: membersActions.SET_ACTIVE_USER, + payload: { + data: { + id: activeUser.metadata?.id, + attributes: { + username: activeUser.metadata?.username, + user_policies_collection: userPoliciesCollection, + user_group_names: userGroupNames + } + } + } + }) + } else { + const activeUser = response.data + activeUser.data.attributes.user_policies_collection = new Set([ + ...activeUser.data.attributes.assigned_policies, + ...(activeUser.included?.reduce?.( + (policies, group) => [...policies, ...group.attributes.assigned_policies], + [] + ) || []) + ]) + + membersDispatch({ + type: membersActions.SET_ACTIVE_USER, + payload: activeUser + }) + } }) } + const fetchProjectOwnerVisibility = project => { projectsIguazioApi .getProjectOwnerVisibility(project) @@ -160,39 +219,125 @@ const ProjectSettings = () => { const fetchProjectUsersData = useCallback(() => { if (projectMembershipIsEnabled) { - fetchProjectOwnerVisibility(params.projectName) - fetchProjectIdAndOwner() - .then(({ id: projectId, owner }) => { - fetchActiveUser() - fetchProjectMembersVisibility(params.projectName) + if (IS_MF_MODE) { + fetchActiveUser() - return fetchProjectMembers(projectId, owner) - }) - .catch(() => { - setProjectMembersIsShown(false) - }) - .finally(() => - membersDispatch({ - type: membersActions.GET_PROJECT_USERS_DATA_END + fetchProjectPolicies() + .catch(() => { + setProjectMembersIsShown(false) + setProjectOwnerIsShown(false) }) - ) + .finally(() => + membersDispatch({ + type: membersActions.GET_PROJECT_USERS_DATA_END + }) + ) + } else { + fetchProjectOwnerVisibility(params.projectName) + fetchProjectIdAndOwner() + .then(({ id: projectId, owner }) => { + fetchActiveUser() + fetchProjectMembersVisibility(params.projectName) + + return fetchProjectMembers(projectId, owner) + }) + .catch(() => { + setProjectMembersIsShown(false) + }) + .finally(() => + membersDispatch({ + type: membersActions.GET_PROJECT_USERS_DATA_END + }) + ) + } } - }, [fetchProjectIdAndOwner, fetchProjectMembers, params.projectName, projectMembershipIsEnabled]) - - const changeMembersCallback = (jobId, userIsValid) => { - const fetchJob = () => { - projectsIguazioApi - .getProjectJob(jobId) - .then(response => { - if (response.data.data.attributes.state !== COMPLETED_STATE) { - setTimeout(fetchJob, 1000) - } else { - if (userIsValid) { - fetchProjectMembers(membersState.projectInfo.id, membersState.projectInfo.owner).then( - () => { - membersDispatch({ - type: membersActions.GET_PROJECT_USERS_DATA_END + }, [ + fetchProjectIdAndOwner, + fetchProjectMembers, + fetchProjectPolicies, + params.projectName, + projectMembershipIsEnabled + ]) + + useEffect(() => { + if (!IS_MF_MODE) return + + const activeUsername = membersState?.activeUser?.data?.attributes?.username + const projectId = membersState?.projectInfo?.id + + if (activeUsername && projectId) { + setProjectOwnerIsShown(userIsProjectOwner || userIsSystemAdmin) + setProjectMembersIsShown(projectMembersTabIsShown) + } + }, [ + membersState?.activeUser?.data?.attributes?.username, + membersState?.projectInfo?.id, + userIsProjectOwner, + userIsSystemAdmin, + projectMembersTabIsShown + ]) + + const changeMembersCallback = IS_MF_MODE + ? userIsStillMember => { + membersDispatch({ + type: membersActions.GET_PROJECT_USERS_DATA_BEGIN + }) + + if (userIsStillMember) { + fetchProjectPolicies() + .then(() => { + membersDispatch({ + type: membersActions.GET_PROJECT_USERS_DATA_END + }) + dispatch( + setNotification({ + status: 200, + id: Math.random(), + message: 'Members updated successfully' + }) + ) + }) + .catch(() => { + membersDispatch({ + type: membersActions.GET_PROJECT_USERS_DATA_END + }) + }) + } else { + dispatch( + setNotification({ + status: 200, + id: Math.random(), + message: 'Members updated successfully' + }) + ) + navigate('/projects/') + } + } + : (jobId, userIsValid) => { + const fetchJob = () => { + projectsIguazioApi + .getProjectJob(jobId) + .then(response => { + if (response.data.data.attributes.state !== COMPLETED_STATE) { + setTimeout(fetchJob, 1000) + } else { + if (userIsValid) { + fetchProjectMembers( + membersState.projectInfo.id, + membersState.projectInfo.owner + ).then(() => { + membersDispatch({ + type: membersActions.GET_PROJECT_USERS_DATA_END + }) + dispatch( + setNotification({ + status: 200, + id: Math.random(), + message: 'Members updated successfully' + }) + ) }) + } else { dispatch( setNotification({ status: 200, @@ -200,42 +345,42 @@ const ProjectSettings = () => { message: 'Members updated successfully' }) ) + navigate('/projects/') } - ) - } else { - dispatch( - setNotification({ - status: 200, - id: Math.random(), - message: 'Members updated successfully' - }) - ) - navigate('/projects/') - } - } - }) - .catch(() => { - membersDispatch({ - type: membersActions.GET_PROJECT_USERS_DATA_END - }) - }) - } + } + }) + .catch(() => { + membersDispatch({ + type: membersActions.GET_PROJECT_USERS_DATA_END + }) + }) + } - membersDispatch({ - type: membersActions.GET_PROJECT_USERS_DATA_BEGIN - }) + membersDispatch({ + type: membersActions.GET_PROJECT_USERS_DATA_BEGIN + }) - fetchJob() - } + fetchJob() + } const changeOwnerCallback = () => { - const prevOwner = membersState.projectInfo.owner.id + if (IS_MF_MODE) { + const prevOwnerUsername = membersState.projectInfo.owner.username - return fetchProjectIdAndOwner().then(() => { - if (!membersState.users.some(member => member.id === prevOwner)) { - navigate('/projects/') - } - }) + return fetchProjectPolicies().then(() => { + if (!membersState.members.some(member => member.id === prevOwnerUsername)) { + navigate('/projects/') + } + }) + } else { + const prevOwner = membersState.projectInfo.owner.id + + return fetchProjectIdAndOwner().then(() => { + if (!membersState.users.some(member => member.id === prevOwner)) { + navigate('/projects/') + } + }) + } } const resetProjectData = useCallback(() => { diff --git a/src/components/ProjectSettings/projectSettings.util.jsx b/src/components/ProjectSettings/projectSettings.util.jsx index 81f7bd982d..2b076dbebc 100644 --- a/src/components/ProjectSettings/projectSettings.util.jsx +++ b/src/components/ProjectSettings/projectSettings.util.jsx @@ -23,6 +23,7 @@ import { forEach, groupBy } from 'lodash' import { membersActions } from '../../elements/MembersPopUp/membersReducer' import { + IS_MF_MODE, PROJECTS_SETTINGS_GENERAL_TAB, PROJECTS_SETTINGS_PAGE, PROJECTS_SETTINGS_MEMBERS_TAB, @@ -77,7 +78,69 @@ const addMember = (members, name, id, type, initialRole, role) => { }) } -export const generateMembers = (membersResponse, membersDispatch, owner) => { +const generateMembersMF = (policiesResponse, membersDispatch) => { + const members = [] + const memberSet = new Set() + const policies = policiesResponse.data.items || [] + + membersDispatch({ + type: membersActions.SET_PROJECT_AUTHORIZATION_ROLES, + payload: policies + }) + + const ownerPolicy = policies.find(policy => policy.spec.displayName === OWNER_ROLE) + const ownerMembers = ownerPolicy?.status?.assignedMembers || [] + const ownerMemberIds = new Set(ownerMembers.map(m => m.id)) + const ownerUsername = ownerMembers[0]?.id || '' + + membersDispatch({ + type: membersActions.SET_PROJECT_INFO, + payload: { + id: policies[0]?.spec?.projectName || '', + owner: { id: ownerUsername, username: ownerUsername, firstName: '', lastName: '' } + } + }) + + policies.forEach(policy => { + const roleName = policy.spec.displayName + const assignedMembers = policy.status?.assignedMembers || [] + + assignedMembers.forEach(assignedMember => { + if (memberSet.has(assignedMember.id)) return + + const memberType = assignedMember.kind === USER_ROLE ? USER_ROLE : USER_GROUP_ROLE + const isOwner = ownerMemberIds.has(assignedMember.id) + const effectiveRole = isOwner ? OWNER_ROLE : roleName + + addMember( + members, + assignedMember.id, + assignedMember.id, + memberType, + effectiveRole, + effectiveRole + ) + memberSet.add(assignedMember.id) + }) + }) + + membersDispatch({ + type: membersActions.SET_MEMBERS_ORIGINAL, + payload: members + }) + membersDispatch({ + type: membersActions.SET_MEMBERS, + payload: members + }) +} + +const isOwnerInMembersList = (ownerId, membersList) => { + return membersList.some(member => { + return member.id === ownerId + }) +} + +const generateMembersIGZ3 = (membersResponse, membersDispatch, owner) => { const members = [] const { project_authorization_role: projectAuthorizationRoles = [], @@ -86,6 +149,7 @@ export const generateMembers = (membersResponse, membersDispatch, owner) => { } = groupBy(membersResponse.data.included, includeItem => { return includeItem.type }) + membersDispatch({ type: membersActions.SET_PROJECT_AUTHORIZATION_ROLES, payload: projectAuthorizationRoles @@ -129,6 +193,7 @@ export const generateMembers = (membersResponse, membersDispatch, owner) => { }) } }) + membersDispatch({ type: membersActions.SET_MEMBERS_ORIGINAL, payload: members @@ -139,6 +204,8 @@ export const generateMembers = (membersResponse, membersDispatch, owner) => { }) } +export const generateMembers = IS_MF_MODE ? generateMembersMF : generateMembersIGZ3 + export const isProjectMembersTabShown = ( projectMembershipIsEnabled, userIsProjectOwner, @@ -150,21 +217,27 @@ export const isProjectMembersTabShown = ( const userIsProjectSecurityAdmin = activeUser.data?.attributes?.user_policies_collection?.has('Project Security Admin') ?? false - const userIsAdmin = members.some( - member => - member.role === ADMIN_ROLE && - (member.id === activeUser.data?.id || - (member.type === USER_GROUP_ROLE && - activeUser.data?.relationships?.user_groups?.data?.some?.( - group => group.id === member.id - ))) - ) - return userIsProjectOwner || userIsAdmin || userIsProjectSecurityAdmin -} + const userIsAdmin = IS_MF_MODE + ? (() => { + const activeUsername = activeUser.data?.attributes?.username + return members.some( + member => + member.role === ADMIN_ROLE && + (member.id === activeUsername || + (member.type === USER_GROUP_ROLE && + activeUser.data?.attributes?.user_group_names?.has(member.id))) + ) + })() + : members.some( + member => + member.role === ADMIN_ROLE && + (member.id === activeUser.data?.id || + (member.type === USER_GROUP_ROLE && + activeUser.data?.relationships?.user_groups?.data?.some?.( + group => group.id === member.id + ))) + ) -const isOwnerInMembersList = (ownerId, membersList) => { - return membersList.some(member => { - return member.id === ownerId - }) + return userIsProjectOwner || userIsAdmin || userIsProjectSecurityAdmin } diff --git a/src/components/ProjectsPage/projects.util.jsx b/src/components/ProjectsPage/projects.util.jsx index 70631352a9..eaa1853860 100644 --- a/src/components/ProjectsPage/projects.util.jsx +++ b/src/components/ProjectsPage/projects.util.jsx @@ -107,7 +107,7 @@ export const generateProjectActionsMenu = ( icon: , className: 'danger', hidden: - window.mlrunConfig.nuclioMode === 'enabled' && project.metadata.name === 'default', + window.mlrunConfig?.nuclioMode === 'enabled' && project?.metadata?.name === 'default', disabled: projectIsDeleting, onClick: deleteProject } diff --git a/src/components/RemoteNuclio/NuclioRemoteError.jsx b/src/components/RemoteNuclio/NuclioRemoteError.jsx new file mode 100644 index 0000000000..54d3f3ad8f --- /dev/null +++ b/src/components/RemoteNuclio/NuclioRemoteError.jsx @@ -0,0 +1,36 @@ +/* +Copyright 2019 Iguazio Systems Ltd. + +Licensed under the Apache License, Version 2.0 (the "License") with +an addition restriction as set forth herein. You may not use this +file except in compliance with the License. You may obtain a copy of +the License at http://www.apache.org/licenses/LICENSE-2.0. + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing +permissions and limitations under the License. + +In addition, you may not use the software for any purposes that are +illegal under applicable law, and the grant of the foregoing license +under the Apache 2.0 license is conditioned upon your compliance with +such restriction. +*/ +import React from 'react' + +const NuclioRemoteError = () => { + return ( +
+

Nuclio App Unavailable

+

+ The Nuclio remote app could not be loaded. + + Please check your network connection or make sure the remote is running. + +

+
+ ) +} + +export default NuclioRemoteError diff --git a/src/components/RemoteNuclio/RemoteNuclio.scss b/src/components/RemoteNuclio/RemoteNuclio.scss new file mode 100644 index 0000000000..93c94676d5 --- /dev/null +++ b/src/components/RemoteNuclio/RemoteNuclio.scss @@ -0,0 +1,58 @@ +.remote-nuclio-container { + width: 100%; + height: 100%; + + .nuclio-app-wrapper { + display: flex; + flex-direction: column; + width: 100%; + height: 100%; + min-height: 800px; + } + + .flex-center { + display: flex; + align-items: center; + justify-content: center; + height: 100%; + min-height: 400px; + } + + .remote-error-card { + display: flex; + flex-direction: column; + align-items: center; + max-width: 576px; + margin: 160px auto; + padding: 56px; + text-align: center; + color: #000000; + background-color: #f9fafb; + border-radius: 16px; + box-shadow: + 0 20px 25px -5px rgba(0, 0, 0, 0.1), + 0 10px 10px -5px rgba(0, 0, 0, 0.04); + transition: all 0.3s ease-in-out; + + .title { + margin-bottom: 20px; + font-weight: 600; + font-size: 24px; + line-height: 1.4; + } + + .description { + max-width: 440px; + color: #1f2937; + font-size: 16px; + line-height: 1.625; + + .subtext { + display: block; + margin-top: 4px; + font-size: 14px; + color: #4b5563; + } + } + } +} diff --git a/src/components/RemoteNuclio/RemoteNuclioRouteWrapper.jsx b/src/components/RemoteNuclio/RemoteNuclioRouteWrapper.jsx new file mode 100644 index 0000000000..f04a0e96cf --- /dev/null +++ b/src/components/RemoteNuclio/RemoteNuclioRouteWrapper.jsx @@ -0,0 +1,121 @@ +/* +Copyright 2019 Iguazio Systems Ltd. + +Licensed under the Apache License, Version 2.0 (the "License") with +an addition restriction as set forth herein. You may not use this +file except in compliance with the License. You may obtain a copy of +the License at http://www.apache.org/licenses/LICENSE-2.0. + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing +permissions and limitations under the License. + +In addition, you may not use the software for any purposes that are +illegal under applicable law, and the grant of the foregoing license +under the Apache 2.0 license is conditioned upon your compliance with +such restriction. +*/ +import React, { useEffect, useState, Suspense } from 'react' +import { ErrorBoundary } from 'react-error-boundary' +import { useParams } from 'react-router-dom' +import { ensureNuclioRemote, loadNuclioApp } from '../../utils/nuclio.remotes.utils' +import NuclioRemoteError from './NuclioRemoteError' +import { Loader } from 'igz-controls/components' + +import './RemoteNuclio.scss' +import Breadcrumbs from '../../common/Breadcrumbs/Breadcrumbs' + +const RemoteNuclioApp = React.lazy(() => loadNuclioApp()) + +const isNuclioPath = pathname => + /^\/projects\/[^/]+\/(real-time-functions|create-function|api-gateways)(\/|$)/.test(pathname) + +const RemoteNuclioRouteWrapper = () => { + const params = useParams() + const [ready, setReady] = useState(false) + const [error, setError] = useState(false) + + const nuclioItemName = params?.['*']?.split('/').filter(Boolean)[0] ?? '' + + useEffect(() => { + const origPushState = history.pushState + const origReplaceState = history.replaceState + + history.pushState = function (...args) { + origPushState.apply(this, args) + Promise.resolve().then(() => { + if (isNuclioPath(window.location.pathname)) { + window.dispatchEvent(new PopStateEvent('popstate')) + } + }) + } + + history.replaceState = function (...args) { + origReplaceState.apply(this, args) + Promise.resolve().then(() => { + if (isNuclioPath(window.location.pathname)) { + window.dispatchEvent(new PopStateEvent('popstate')) + } + }) + } + + return () => { + history.pushState = origPushState + history.replaceState = origReplaceState + } + }, []) + + useEffect(() => { + setReady(false) + setError(false) + + const init = async () => { + try { + await ensureNuclioRemote() + setReady(true) + } catch { + setError(true) + } + } + void init() + }, [params.projectName]) + + const renderContent = () => { + if (error) { + return + } + + if (!ready) { + return ( +
+ +
+ ) + } + + return ( + }> + + + + } + > +
+
+ +
+ +
+
+
+ ) + } + + return
{renderContent()}
+} + +export default RemoteNuclioRouteWrapper diff --git a/src/components/Workflow/workflow.util.js b/src/components/Workflow/workflow.util.js index c3285093b2..a6941afebc 100644 --- a/src/components/Workflow/workflow.util.js +++ b/src/components/Workflow/workflow.util.js @@ -31,7 +31,7 @@ import { JOBS_MONITORING_WORKFLOWS_TAB, WORKFLOW_TYPE_SKIPPED } from '../../constants' -import projectsIguazioApi from '../../api/projects-iguazio-api' +import { checkProjectWriteAccess } from '../../utils/projectAuth.util' import tasksApi from '../../api/tasks-api' import workflowsApi from '../../api/workflow-api' import { page } from '../Jobs/jobs.util' @@ -312,15 +312,10 @@ export const fetchMissingProjectsPermissions = async (projectNames, currentMap, await Promise.all( missingProjects.map(async projectName => { try { - await projectsIguazioApi.getProjectOwnerVisibility(projectName) - return [projectName, true] + const hasAccess = await checkProjectWriteAccess(projectName) + return [projectName, hasAccess] } catch { - try { - await projectsIguazioApi.getProjectWorkflowsUpdateAuthorization(projectName) - return [projectName, true] - } catch { - return [projectName, false] - } + return [projectName, false] } }) ) @@ -333,15 +328,12 @@ export const fetchMissingProjectsPermissions = async (projectNames, currentMap, export const fetchMissingProjectPermission = async (projectName, currentMap, dispatch) => { if (projectName in currentMap) return - const hasPermission = await projectsIguazioApi - .getProjectOwnerVisibility(projectName) - .then(() => true) - .catch(() => - projectsIguazioApi - .getProjectWorkflowsUpdateAuthorization(projectName) - .then(() => true) - .catch(() => false) - ) + let hasPermission = false + try { + hasPermission = await checkProjectWriteAccess(projectName) + } catch { + hasPermission = false + } dispatch(setAccessibleProjectsMap({ [projectName]: hasPermission })) } diff --git a/src/constants.js b/src/constants.js index 0d356ec540..2a01d86e92 100644 --- a/src/constants.js +++ b/src/constants.js @@ -19,6 +19,8 @@ such restriction. */ /*=========== GENERAL =============*/ +export const IS_MF_MODE = import.meta.env.VITE_FEDERATION === 'true' + export const SET_LOADING = 'SET_LOADING' export const AZURE_STORAGE_INPUT_PATH_SCHEME = 'az://' @@ -163,8 +165,8 @@ export const PROJECT_QUICK_ACTIONS_PAGE = 'quick-actions' export const ALL_VERSIONS_PATH = 'all-versions' export const NUCLIO_PAGE = 'nuclio' -export const REAL_TIME_FUNCTIONS_PAGE = 'real-time-functions' export const API_GATEWAYS_PAGE = 'api-gateways' +export const NUCLIO_FUNCTIONS_PATH = IS_MF_MODE ? 'real-time-functions' : 'functions' /*=========== CONSUMER_GROUPS =============*/ @@ -467,6 +469,8 @@ export const ENV_VARIABLE_TYPE_VALUE = 'value' export const ENV_VARIABLE_TYPE_SECRET = 'secret' export const PANEL_DEFAULT_ACCESS_KEY = '$generate' +export const API_TOKEN_TIP = + 'Get a valid API Token from your API tokens list (under Personal Settings)' /*=========== ML REACT FLOW =============*/ diff --git a/src/elements/ChangeOwnerPopUp/ChangeOwnerPopUp.jsx b/src/elements/ChangeOwnerPopUp/ChangeOwnerPopUp.jsx index 3b045f4fcb..27bce99e3e 100644 --- a/src/elements/ChangeOwnerPopUp/ChangeOwnerPopUp.jsx +++ b/src/elements/ChangeOwnerPopUp/ChangeOwnerPopUp.jsx @@ -39,7 +39,7 @@ import { setNotification } from 'igz-controls/reducers/notificationReducer' import { showErrorNotification } from 'igz-controls/utils/notification.util' import { useDetectOutsideClick } from 'igz-controls/hooks' -import { USER_ROLE } from '../../constants' +import { IS_MF_MODE, USER_ROLE } from '../../constants' import SearchIcon from 'igz-controls/images/search.svg?react' @@ -74,48 +74,104 @@ const ChangeOwnerPopUp = ({ changeOwnerCallback, projectId }) => { setShowSuggestionList(false) } - const applyChanges = () => { - if (newOwnerId) { - const projectData = { - data: { - type: 'project', - attributes: {}, - relationships: { - owner: { - data: { - id: newOwnerId, - type: USER_ROLE - } + const applyChangesMF = () => { + projectsIguazioApi + .updateProjectOwner(projectId, newOwnerId) + .then(changeOwnerCallback) + .then(() => { + dispatch( + setNotification({ + status: 200, + id: Math.random(), + message: 'Owner updated successfully' + }) + ) + }) + .catch(error => { + const customErrorMsg = + error.response?.status === FORBIDDEN_ERROR_STATUS_CODE + ? 'Missing edit permission for the project' + : getErrorMsg(error, 'Failed to edit project data') + + showErrorNotification(dispatch, error, '', customErrorMsg, () => applyChanges()) + }) + .finally(handleOnClose) + } + + const applyChangesIGZ3 = () => { + const projectData = { + data: { + type: 'project', + attributes: {}, + relationships: { + owner: { + data: { + id: newOwnerId, + type: USER_ROLE } } } } + } + + projectsIguazioApi + .editProject(projectId, projectData) + .then(changeOwnerCallback) + .then(() => { + dispatch( + setNotification({ + status: 200, + id: Math.random(), + message: 'Owner updated successfully' + }) + ) + }) + .catch(error => { + const customErrorMsg = + error.response?.status === FORBIDDEN_ERROR_STATUS_CODE + ? 'Missing edit permission for the project' + : getErrorMsg(error, 'Failed to edit project data') + + showErrorNotification(dispatch, error, '', customErrorMsg, () => applyChanges(newOwnerId)) + }) + .finally(handleOnClose) + } + + const applyChanges = () => { + if (newOwnerId) { + if (IS_MF_MODE) { + applyChangesMF() + } else { + applyChangesIGZ3() + } + } + } + + const generateSuggestionListMF = async (memberName, resolve) => { + let formattedUsers = [] + + try { + const response = await projectsIguazioApi.searchUsersMetadata(memberName) + const users = response.data.items || [] - projectsIguazioApi - .editProject(projectId, projectData) - .then(changeOwnerCallback) - .then(() => { - dispatch( - setNotification({ - status: 200, - id: Math.random(), - message: 'Owner updated successfully' - }) - ) - }) - .catch(error => { - const customErrorMsg = - error.response?.status === FORBIDDEN_ERROR_STATUS_CODE - ? 'Missing edit permission for the project' - : getErrorMsg(error, 'Failed to edit project data') - - showErrorNotification(dispatch, error, '', customErrorMsg, () => applyChanges(newOwnerId)) - }) - .finally(handleOnClose) + formattedUsers = users.map(user => { + return { + name: `${user.firstName} ${user.lastName}`, + username: user.username, + label: `${user.firstName} ${user.lastName} (${user.username})`, + id: user.username, + role: '' + } + }) + setUsersList(formattedUsers) + } catch (error) { + showErrorNotification(dispatch, error, 'Failed to fetch users') } + + resolve(formattedUsers) } - const generateSuggestionList = async (memberName, resolve) => { + const generateSuggestionListIGZ3 = async (memberName, resolve) => { const params = { 'filter[assigned_policies]': '[$contains_any]Developer,Project Admin', 'page[size]': 200 @@ -128,10 +184,7 @@ const ChangeOwnerPopUp = ({ changeOwnerCallback, projectId }) => { } try { - const response = await projectsIguazioApi.getScrubbedUsers({ - params - }) - + const response = await projectsIguazioApi.getScrubbedUsers({ params }) const { data: { data: users } } = response @@ -153,6 +206,8 @@ const ChangeOwnerPopUp = ({ changeOwnerCallback, projectId }) => { resolve(formattedUsers) } + const generateSuggestionList = IS_MF_MODE ? generateSuggestionListMF : generateSuggestionListIGZ3 + const onSearchChange = debounce(memberName => { const memberNameEscaped = deleteUnsafeHtml(memberName) setSearchValue(memberNameEscaped) diff --git a/src/elements/MembersPopUp/MembersPopUp.jsx b/src/elements/MembersPopUp/MembersPopUp.jsx index 6f757b0408..34c0707fb0 100644 --- a/src/elements/MembersPopUp/MembersPopUp.jsx +++ b/src/elements/MembersPopUp/MembersPopUp.jsx @@ -38,7 +38,7 @@ import { isIgzVersionCompatible } from '../../utils/isIgzVersionCompatible' import { membersActions } from './membersReducer' import { showErrorNotification } from 'igz-controls/utils/notification.util' -import { USER_GROUP_ROLE, USER_ROLE } from '../../constants' +import { IS_MF_MODE, OWNER_ROLE, USER_GROUP_ROLE, USER_ROLE } from '../../constants' import Add from 'igz-controls/images/add.svg?react' import Close from 'igz-controls/images/close.svg?react' @@ -96,7 +96,61 @@ const MembersPopUp = ({ changeMembersCallback, membersDispatch, membersState }) setMembersData(state => ({ ...state, members: membersCopy })) } - const applyMembersChanges = () => { + const applyMembersChangesMF = () => { + const projectName = membersData.projectInfo.id + const visibleMembers = membersData.members.filter( + member => member.modification !== DELETE_MODIFICATION && member.role !== OWNER_ROLE + ) + const groupedByRole = groupBy(visibleMembers, 'role') + + const membership = {} + + membersState.projectAuthorizationRoles + .filter(policy => policy.spec.displayName !== OWNER_ROLE) + .forEach(policy => { + const roleName = policy.spec.displayName.toLowerCase() + membership[roleName] = { + values: (groupedByRole[policy.spec.displayName] || []).map(member => member.id) + } + }) + + const body = { + membership, + override: true + } + + membersDispatch({ + type: membersActions.SET_MEMBERS, + payload: membersData.members + }) + + projectsIguazioApi + .setProjectMembership(projectName, body) + .then(() => { + const activeUsername = membersData.activeUser.data?.attributes?.username + const userIsStillMember = membersData.members?.some( + member => + member.modification !== DELETE_MODIFICATION && + (member.id === activeUsername || + (member.type === USER_GROUP_ROLE && + membersData.activeUser.data?.attributes?.user_group_names?.has(member.id))) + ) + + changeMembersCallback(userIsStillMember) + }) + .catch(error => { + const customErrorMsg = + error.response?.status === FORBIDDEN_ERROR_STATUS_CODE + ? 'Missing edit permission for the project' + : getErrorMsg(error, 'Failed to edit project data') + + showErrorNotification(dispatch, error, '', customErrorMsg, () => applyMembersChanges()) + }) + + handleOnClose() + } + + const applyMembersChangesIGZ3 = () => { const changesBody = { data: { attributes: { @@ -207,6 +261,8 @@ const MembersPopUp = ({ changeMembersCallback, membersDispatch, membersState }) handleOnClose() } + const applyMembersChanges = IS_MF_MODE ? applyMembersChangesMF : applyMembersChangesIGZ3 + const areChangesMade = () => { return membersData.members.some(member => member.modification !== '') } @@ -225,13 +281,66 @@ const MembersPopUp = ({ changeMembersCallback, membersDispatch, membersState }) handleOnClose() } - const generateUsersSuggestionList = debounce(searchQuery => { + const toSuggestionItem = (id, label, type) => { + const existingMember = membersData.members.find( + member => member.id === id && member.modification !== DELETE_MODIFICATION + ) + + return { + label, + id, + subLabel: existingMember?.role ?? '', + disabled: Boolean(existingMember), + icon: + type === USER_ROLE ? ( + + + + ) : ( + + + + ), + ui: { type } + } + } + + const generateUsersSuggestionListMF = debounce(searchQuery => { + const getUsersPromise = projectsIguazioApi.searchUsersMetadata(searchQuery) + const getUserGroupsPromise = projectsIguazioApi.searchGroupsMetadata(searchQuery) + + Promise.all([getUsersPromise, getUserGroupsPromise]) + .then(([usersResponse, groupsResponse]) => { + const users = usersResponse.data.items || [] + const groups = groupsResponse.data.items || [] + const suggestionList = [ + ...users.map(user => toSuggestionItem(user.username, user.username, USER_ROLE)), + ...groups.map(group => + toSuggestionItem( + group.groupId, + group.path.replace(/^\//, '') ?? group.groupId, + USER_GROUP_ROLE + ) + ) + ] + + setNewMembersSuggestionList(suggestionList) + }) + .catch(error => { + showErrorNotification(dispatch, error, 'Failed to fetch users') + }) + }, 400) + + const generateUsersSuggestionListIGZ3 = debounce(searchQuery => { const requiredIgzVersion = '3.5.3' let paramsScrubbedUsers = { 'filter[username]': `[$match-i]^.*${searchQuery}.*$`, 'page[size]': 200 } - let paramsUserGroups = { 'filter[name]': `[$match-i]^.*${searchQuery}.*$`, 'page[size]': 200 } + let paramsUserGroups = { + 'filter[name]': `[$match-i]^.*${searchQuery}.*$`, + 'page[size]': 200 + } if (isIgzVersionCompatible(requiredIgzVersion)) { paramsScrubbedUsers['filter[username]'] = `[$contains_istr]${searchQuery}` @@ -286,6 +395,10 @@ const MembersPopUp = ({ changeMembersCallback, membersDispatch, membersState }) }) }, 400) + const generateUsersSuggestionList = IS_MF_MODE + ? generateUsersSuggestionListMF + : generateUsersSuggestionListIGZ3 + return (
diff --git a/src/elements/MembersPopUp/membersReducer.js b/src/elements/MembersPopUp/membersReducer.js index 9a045856a9..865deb46d0 100644 --- a/src/elements/MembersPopUp/membersReducer.js +++ b/src/elements/MembersPopUp/membersReducer.js @@ -23,8 +23,7 @@ import { groupBy } from 'lodash' * - activeUser : logged in user data * - projectInfo : additional information about the project such as ID and Owner of the project * (data is received from iguazio API). - * - users : the list of user members (original list from response) - * - useGroups : the list of user-group members (original list from response) + * - projectAuthorizationRoles: the list of project policies from /authorization/projects/{project}/policies * - membersOriginal : the list of users and user-groups that is used to revert changes * - members : the list of users and user-groups that is displayed in the table of the `Member` dialog (includes owner) * - groupedOriginalMembers : grouped members list by their role, which is used to display the number of diff --git a/src/elements/PanelCredentialsAccessKey/PanelCredentialsAccessKey.jsx b/src/elements/PanelCredentialsAccessKey/PanelCredentialsAccessKey.jsx index e14799e5d4..3161a09fee 100644 --- a/src/elements/PanelCredentialsAccessKey/PanelCredentialsAccessKey.jsx +++ b/src/elements/PanelCredentialsAccessKey/PanelCredentialsAccessKey.jsx @@ -24,7 +24,7 @@ import PropTypes from 'prop-types' import CheckBox from '../../common/CheckBox/CheckBox' import Input from '../../common/Input/Input' -import { PANEL_DEFAULT_ACCESS_KEY } from '../../constants' +import { PANEL_DEFAULT_ACCESS_KEY, API_TOKEN_TIP } from '../../constants' import './panelCredentialsAccessKey.scss' @@ -32,6 +32,7 @@ const PanelCredentialsAccessKey = ({ className = '', credentialsAccessKey, frontendSpec, + isApiToken = false, isPanelEditMode = false, required = false, setCredentialsAccessKey, @@ -49,7 +50,7 @@ const PanelCredentialsAccessKey = ({ return (
- {!frontendSpec.ce?.version && ( + {!frontendSpec.ce?.version && !isApiToken && ( )} - {credentialsAccessKey !== PANEL_DEFAULT_ACCESS_KEY && ( + {(isApiToken || credentialsAccessKey !== PANEL_DEFAULT_ACCESS_KEY) && ( { if (credentialsAccessKey !== event.target.value) { @@ -87,6 +88,7 @@ const PanelCredentialsAccessKey = ({ isAccessKeyValid: value })) } + tip={isApiToken ? API_TOKEN_TIP : ''} value={inputValue} wrapperClassName="access-key__input" /> @@ -99,6 +101,7 @@ PanelCredentialsAccessKey.propTypes = { className: PropTypes.string, credentialsAccessKey: PropTypes.string.isRequired, frontendSpec: PropTypes.object.isRequired, + isApiToken: PropTypes.bool, isPanelEditMode: PropTypes.bool, required: PropTypes.bool, setCredentialsAccessKey: PropTypes.func.isRequired, diff --git a/src/elements/PanelCredentialsAccessKey/panelCredentialsAccessKey.scss b/src/elements/PanelCredentialsAccessKey/panelCredentialsAccessKey.scss index 64e53a8d03..5c60b92eef 100644 --- a/src/elements/PanelCredentialsAccessKey/panelCredentialsAccessKey.scss +++ b/src/elements/PanelCredentialsAccessKey/panelCredentialsAccessKey.scss @@ -4,7 +4,7 @@ height: 64px; padding: 22px 40px; - &__input { + &__input:not(:first-child) { margin-left: 20px; } } diff --git a/src/elements/ProjectFunctions/ProjectFunctions.jsx b/src/elements/ProjectFunctions/ProjectFunctions.jsx index ea8c54617a..48c0d872f7 100644 --- a/src/elements/ProjectFunctions/ProjectFunctions.jsx +++ b/src/elements/ProjectFunctions/ProjectFunctions.jsx @@ -32,7 +32,9 @@ import { FAILED_STATE, FUNCTION_READY_STATE, REQUEST_CANCELED, - RUNNING_STATE + RUNNING_STATE, + NUCLIO_FUNCTIONS_PATH, + IS_MF_MODE } from '../../constants' import { fetchApiGateways } from '../../reducers/nuclioReducer' import { generateNuclioLink } from '../../utils' @@ -82,7 +84,9 @@ const ProjectFunctions = ({ nuclioStreamsAreEnabled, project }) => { label: 'Running', className: RUNNING_STATE, status: RUNNING_STATE, - href: generateNuclioLink(`/projects/${params.projectName}/functions`), + [IS_MF_MODE ? 'link' : 'href']: generateNuclioLink( + `/projects/${params.projectName}/${NUCLIO_FUNCTIONS_PATH}` + ), loading: nuclioStore.loading }, failed: { @@ -91,14 +95,18 @@ const ProjectFunctions = ({ nuclioStreamsAreEnabled, project }) => { label: 'Failed', status: FAILED_STATE, className: functionsFailed > 0 ? FAILED_STATE : RUNNING_STATE, - href: generateNuclioLink(`/projects/${params.projectName}/functions`), + [IS_MF_MODE ? 'link' : 'href']: generateNuclioLink( + `/projects/${params.projectName}/${NUCLIO_FUNCTIONS_PATH}` + ), loading: nuclioStore.loading }, apiGateways: { value: nuclioStore.apiGateways, label: 'API gateways', className: RUNNING_STATE, - href: generateNuclioLink(`/projects/${params.projectName}/api-gateways`), + [IS_MF_MODE ? 'link' : 'href']: generateNuclioLink( + `/projects/${params.projectName}/api-gateways` + ), loading: nuclioStore.loading }, ...(nuclioStreamsAreEnabled && { @@ -149,8 +157,8 @@ const ProjectFunctions = ({ nuclioStreamsAreEnabled, project }) => { ? // if nuclio func is generated by MLRun then name only in this case starts with project name and we need to slice it func.metadata.name.slice(params.projectName.length + 1) : func.metadata.name, - href: generateNuclioLink( - `/projects/${params.projectName}/functions/${func.metadata.name}` + [IS_MF_MODE ? 'link' : 'href']: generateNuclioLink( + `/projects/${params.projectName}/${NUCLIO_FUNCTIONS_PATH}/${func.metadata.name}` ), className: 'table-cell_big' }, @@ -177,7 +185,11 @@ const ProjectFunctions = ({ nuclioStreamsAreEnabled, project }) => { loading: nuclioStore.loading }} footerLinkText="All real-time functions" - href={generateNuclioLink(`/projects/${params.projectName}/functions`)} + {...{ + [IS_MF_MODE ? 'link' : 'href']: generateNuclioLink( + `/projects/${params.projectName}/${NUCLIO_FUNCTIONS_PATH}` + ) + }} statistics={functions} subTitle="Recent real-time functions" table={functionsTable} diff --git a/src/hooks/nuclioMode.hook.js b/src/hooks/nuclioMode.hook.js index 88c5fea164..0ba4da3fab 100644 --- a/src/hooks/nuclioMode.hook.js +++ b/src/hooks/nuclioMode.hook.js @@ -33,11 +33,11 @@ import { useLayoutEffect, useState } from 'react' */ export const useNuclioMode = () => { - const [mode, setMode] = useState(window.mlrunConfig.nuclioMode) + const [mode, setMode] = useState(window?.mlrunConfig?.nuclioMode) useLayoutEffect(() => { - if (mode !== window.mlrunConfig.nuclioMode) { - setMode(window.mlrunConfig.nuclioMode) + if (mode !== window?.mlrunConfig?.nuclioMode) { + setMode(window?.mlrunConfig?.nuclioMode) } }, [mode]) diff --git a/src/hooks/useApiTokenExpiry.js b/src/hooks/useApiTokenExpiry.js new file mode 100644 index 0000000000..a2eee58f43 --- /dev/null +++ b/src/hooks/useApiTokenExpiry.js @@ -0,0 +1,91 @@ +/* +Copyright 2019 Iguazio Systems Ltd. + +Licensed under the Apache License, Version 2.0 (the "License") with +an addition restriction as set forth herein. You may not use this +file except in compliance with the License. You may obtain a copy of +the License at http://www.apache.org/licenses/LICENSE-2.0. + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing +permissions and limitations under the License. + +In addition, you may not use the software for any purposes that are +illegal under applicable law, and the grant of the foregoing license +under the Apache 2.0 license is conditioned upon your compliance with +such restriction. +*/ +import { useCallback, useMemo, useState, useEffect } from 'react' + +import { mainHttpClient } from '../httpClient' + +const TOKEN_EXPIRY_WARNING_DAYS = 7 +const DISMISSED_KEY = 'tokenExpiryBannerDismissed' + +// Module-level cache — survives component remounts and MF unmount/remount cycles +let tokenCache = null + +const isDismissed = () => sessionStorage.getItem(DISMISSED_KEY) === 'true' +const persistDismissed = () => sessionStorage.setItem(DISMISSED_KEY, 'true') + +const getDaysDifference = targetDate => { + const diffTime = new Date(targetDate).getTime() - Date.now() + return diffTime / (1000 * 60 * 60 * 24) +} + +const isTokenExpiringSoon = token => { + if (!token.expiration) return false + return getDaysDifference(token.expiration) <= TOKEN_EXPIRY_WARNING_DAYS +} + +const useApiTokenExpiry = () => { + const [tokens, setTokens] = useState(tokenCache) + const [dismissed, setDismissedState] = useState(isDismissed) + + useEffect(() => { + let cancelled = false + + mainHttpClient + .get('/user-secrets/tokens') + .then(({ data }) => { + if (!cancelled) { + const result = data.secret_tokens ?? [] + tokenCache = result + setTokens(result) + } + }) + .catch(() => { + // On error keep the cached value so the banner doesn't vanish + if (!cancelled && tokenCache === null) setTokens([]) + }) + + return () => { + cancelled = true + } + }, []) + + const hasExpiring = useMemo( + () => !dismissed && !!tokens?.some(isTokenExpiringSoon), + [tokens, dismissed] + ) + + const minDaysLeft = useMemo(() => { + if (!hasExpiring || !tokens) return 0 + const expiring = tokens.filter(isTokenExpiringSoon) + const min = Math.min(...expiring.map(t => getDaysDifference(t.expiration))) + return Math.max(0, Math.ceil(min)) + }, [tokens, hasExpiring]) + + const daysLeftLabel = minDaysLeft <= 1 ? '1 day' : `${minDaysLeft} days` + + const dismiss = useCallback(() => { + persistDismissed() + setDismissedState(true) + }, []) + + return { hasExpiring, daysLeftLabel, dismiss } +} + +export default useApiTokenExpiry diff --git a/src/httpClient.js b/src/httpClient.js index a61f075bf2..55ebad86c2 100755 --- a/src/httpClient.js +++ b/src/httpClient.js @@ -29,6 +29,13 @@ const headers = { 'Cache-Control': 'no-cache' } +/** + * Resolve auth bridge provided by igz-ui (host). + * - Primary: injected via Module Federation + * - Fallback: host global (timing safety) + */ +export const getHostAuth = () => window.__mlrunHostServices?.auth || window.__igzAuth || null + // serialize a param with an array value as a repeated param, for example: // { label: ['host', 'owner=admin'] } => 'label=host&label=owner%3Dadmin' const paramsSerializer = params => qs.stringify(params, { arrayFormat: 'repeat' }) @@ -62,10 +69,68 @@ export const nuclioHttpClient = axios.create({ }) export const iguazioHttpClient = axios.create({ - baseURL: import.meta.env.MODE === 'production' ? '/api' : '/iguazio/api', + baseURL: + import.meta.env.MODE === 'production' + ? import.meta.env.VITE_FEDERATION === 'true' + ? '/oris/api' + : '/api' + : import.meta.env.VITE_FEDERATION === 'true' + ? '/oris-mlrun/api' + : '/iguazio/api', headers }) +/** + * Module Federation auth: + * token injection and refresh are handled by the igz-ui host + */ + +const attachHostAuth = client => { + const auth = getHostAuth() + if (!auth) return + + client.interceptors.request.use(config => { + const token = auth.getAccessToken?.() + if (token) { + config.headers = config.headers ?? {} + config.headers.Authorization = `Bearer ${token}` + } + return config + }) + + client.interceptors.response.use( + res => res, + async err => { + const status = err?.response?.status + const req = err?.config + if (!req) throw err + + if (status === 401 && !req._retry) { + req._retry = true + + const token = await auth.refreshAccessToken?.() + if (!token) { + auth.redirectToLogin?.() + throw err + } + + req.headers = req.headers ?? {} + req.headers.Authorization = `Bearer ${token}` + + return client(req) + } + + throw err + } + ) +} + +attachHostAuth(mainHttpClient) +attachHostAuth(mainHttpClientV2) +attachHostAuth(functionTemplatesHttpClient) +attachHostAuth(nuclioHttpClient) +attachHostAuth(iguazioHttpClient) + const getAbortSignal = (controller, abortCallback, timeoutMs) => { let timeoutId = null const newController = new AbortController() diff --git a/src/index.jsx b/src/index.jsx index 9a141aaa0e..57839eb9e0 100644 --- a/src/index.jsx +++ b/src/index.jsx @@ -26,40 +26,23 @@ import ErrorBoundary from './components/ErrorBoundary/ErrorBoundary' import * as serviceWorker from './serviceWorker' import { Provider } from 'react-redux' import toolkitStore from './store/toolkitStore' -import { HTTP, HTTPS } from './constants' +import { loadRemoteConfig } from './loadRemoteConfig' if (!window.location.pathname.includes(import.meta.env.VITE_PUBLIC_URL)) { window.location.href = import.meta.env.VITE_PUBLIC_URL } -fetch(`${import.meta.env.VITE_PUBLIC_URL}/config.json`, { cache: 'no-store' }) - .then(response => response.json()) - .then(config => { - if (config.nuclioUiUrl) { - const mlrunProtocol = - config.nuclioUiUrl.startsWith(HTTP) || config.nuclioUiUrl.startsWith(HTTPS) - ? '' - : `${window.location.protocol}//` - - window.mlrunConfig = { - ...config, - nuclioUiUrl: `${mlrunProtocol}${config.nuclioUiUrl}` - } - } else { - window.mlrunConfig = config - } - }) - .then(() => { - const root = createRoot(document.getElementById('root')) - - root.render( - - - - - - ) - }) +loadRemoteConfig().then(() => { + const root = createRoot(document.getElementById('root')) + + root.render( + + + + + + ) +}) // If you want your app to work offline and load faster, you can change // unregister() to register() below. Note this comes with some pitfalls. diff --git a/src/layout/Navbar/navbar.util.jsx b/src/layout/Navbar/navbar.util.jsx index 0416c906c4..43140def1b 100644 --- a/src/layout/Navbar/navbar.util.jsx +++ b/src/layout/Navbar/navbar.util.jsx @@ -24,7 +24,9 @@ import { DOCUMENTS_PAGE, LLM_PROMPTS_PAGE, PROJECT_MONITOR, - PROJECT_QUICK_ACTIONS_PAGE + PROJECT_QUICK_ACTIONS_PAGE, + NUCLIO_FUNCTIONS_PATH, + IS_MF_MODE } from '../../constants' import { generateNuclioLink } from '../../utils' @@ -125,15 +127,15 @@ export const getLinks = projectName => { icon: , id: 'real-time-functions', label: 'Real-time functions', - link: generateNuclioLink(`${pathname}/functions`), - externalLink: true + link: generateNuclioLink(`${pathname}/${NUCLIO_FUNCTIONS_PATH}`), + externalLink: !IS_MF_MODE }, { icon: , id: 'api-gateways', label: 'API gateways', link: generateNuclioLink(`${pathname}/api-gateways`), - externalLink: true + externalLink: !IS_MF_MODE }, { icon: , diff --git a/src/layout/Page/Page.jsx b/src/layout/Page/Page.jsx index 3edc0d4fcb..2c73dcb9cd 100644 --- a/src/layout/Page/Page.jsx +++ b/src/layout/Page/Page.jsx @@ -26,6 +26,8 @@ import ModalContainer from 'react-modal-promise' import Sidebar from '../../nextGenComponents/shared/Sidebar' import { SidebarInset, SidebarProvider } from 'igz-controls/nextGenComponents' +import HostLeaveGuard from '../../common/HostLeaveGuard/HostLeaveGuard' +import TokenExpiryBanner from '../../common/TokenExpiryBanner/TokenExpiryBanner' import YamlModal from '../../common/YamlModal/YamlModal' import { Loader } from 'igz-controls/components' @@ -99,11 +101,13 @@ const Page = () => { return ( + {projectName && } <> }>
+
{isProjectsFetched ? : }
diff --git a/src/lazyWithRetry.js b/src/lazyWithRetry.js index f44786a6bb..4be065b970 100644 --- a/src/lazyWithRetry.js +++ b/src/lazyWithRetry.js @@ -19,26 +19,33 @@ such restriction. */ import { lazy } from 'react' // a function to retry loading a chunk to avoid chunk load error for out of date code -export const lazyRetry = componentImport => - lazy(() => { +export const lazyRetry = (componentImport, name) => { + if (!name) { + throw new Error('lazyRetry requires a name for the component being imported') + } + + return lazy(() => { return new Promise((resolve, reject) => { // check if the window has already been refreshed - const hasRefreshed = JSON.parse( - window.sessionStorage.getItem('retry-lazy-refreshed') || 'false' - ) + const componentStorageKey = `retry-lazy-refreshed-${name}` + const hasRefreshed = JSON.parse(window.sessionStorage.getItem(componentStorageKey) || 'false') // try to import the component componentImport() .then(component => { - window.sessionStorage.setItem('retry-lazy-refreshed', 'false') // success so reset the refresh + window.sessionStorage.setItem(componentStorageKey, 'false') // success so reset the refresh resolve(component) }) .catch(error => { + window.sessionStorage.setItem(componentStorageKey, 'true') if (!hasRefreshed) { // not been refreshed yet window.sessionStorage.setItem('retry-lazy-refreshed', 'true') // we are now going to refresh return window.location.reload() // refresh the page } - reject(error) // Default error behaviour as already tried refresh + // eslint-disable-next-line no-console + console.error(`Failed to load component ${name} after retrying`, error) + reject(error) // Default error behavior as already tried refresh }) }) }) +} diff --git a/src/loadRemoteConfig.js b/src/loadRemoteConfig.js new file mode 100644 index 0000000000..febebc05d6 --- /dev/null +++ b/src/loadRemoteConfig.js @@ -0,0 +1,60 @@ +/* +Copyright 2019 Iguazio Systems Ltd. + +Licensed under the Apache License, Version 2.0 (the "License") with +an addition restriction as set forth herein. You may not use this +file except in compliance with the License. You may obtain a copy of +the License at http://www.apache.org/licenses/LICENSE-2.0. + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing +permissions and limitations under the License. + +In addition, you may not use the software for any purposes that are +illegal under applicable law, and the grant of the foregoing license +under the Apache 2.0 license is conditioned upon your compliance with +such restriction. +*/ + +import { HTTP, HTTPS } from './constants' + +const withProtocol = url => { + if (!url || url.startsWith(HTTP) || url.startsWith(HTTPS)) return url + return `${window.location.protocol}//${url.replace(/^\/+/, '')}` +} + +export const loadRemoteConfig = async (url, services = {}) => { + /** + * Store host-provided services (auth bridge from igz-ui) + */ + if (services && Object.keys(services).length > 0) { + window.__mlrunHostServices = services + } + + // Priority 1: Use config injected by the Host (igz-ui) + if (window.mlrunConfig && Object.keys(window.mlrunConfig).length > 0) { + window.mlrunConfig.nuclioUiUrl = withProtocol(window.mlrunConfig.nuclioUiUrl) + window.mlrunConfig.nuclioRemoteEntryUrl = withProtocol(window.mlrunConfig.nuclioRemoteEntryUrl) + return + } + + // Priority 2: Standalone Fallback (Local Dev) + try { + const configPath = `${url ?? import.meta.env.VITE_PUBLIC_URL}/config.json` + const response = await fetch(configPath, { cache: 'no-store' }) + if (!response.ok) throw new Error(response.status) + + const config = await response.json() + const uiUrl = withProtocol(config.nuclioUiUrl) + + window.mlrunConfig = { + ...config, + nuclioUiUrl: uiUrl, + nuclioRemoteEntryUrl: withProtocol(config.nuclioRemoteEntryUrl || uiUrl) + } + } catch (err) { + throw new Error('[mlrun-ui] Config load failed. Falling back to Host injection.', err) + } +} diff --git a/src/main.jsx b/src/main.jsx new file mode 100644 index 0000000000..40ada1bd44 --- /dev/null +++ b/src/main.jsx @@ -0,0 +1,20 @@ +import App from './App' +import { Provider } from 'react-redux' +import store from './store/toolkitStore' +import ErrorBoundary from './components/ErrorBoundary/ErrorBoundary' +// Eagerly initialize react-text-mask in the entry chunk so its CJS/UMD module +// is resolved against React before any lazy chunks try to reference it. +// TODO: remove this import when custom react-text-mask will be included in our codebase (in progress) or when https://github.com/rollup/rollup/issues/6296 fixed (deps of vite) +import 'react-text-mask' + +const RemoteApp = () => { + return ( + + + + + + ) +} + +export default RemoteApp diff --git a/src/nextGenComponents/pages/ApplicationsPage/applicationsPage.util.test.js b/src/nextGenComponents/pages/ApplicationsPage/applicationsPage.util.test.js index 973a00ea14..8cabc4574e 100644 --- a/src/nextGenComponents/pages/ApplicationsPage/applicationsPage.util.test.js +++ b/src/nextGenComponents/pages/ApplicationsPage/applicationsPage.util.test.js @@ -17,7 +17,7 @@ illegal under applicable law, and the grant of the foregoing license under the Apache 2.0 license is conditioned upon your compliance with such restriction. */ -// eslint-disable-next-line import/named + import { vi, describe, it, expect, beforeEach, afterEach } from 'vitest' import { APPLICATION_STATUS, APPLICATION_STATUS_OPTIONS } from './applications.constants' diff --git a/src/nextGenComponents/shared/Sidebar/navbarList.util.jsx b/src/nextGenComponents/shared/Sidebar/navbarList.util.jsx index 24eb27a26a..1afc4f19cc 100644 --- a/src/nextGenComponents/shared/Sidebar/navbarList.util.jsx +++ b/src/nextGenComponents/shared/Sidebar/navbarList.util.jsx @@ -39,9 +39,10 @@ import { PROJECTS_PAGE_PATH, PROJECT_MONITOR, REAL_TIME_PIPELINES_TAB, - REAL_TIME_FUNCTIONS_PAGE, + NUCLIO_FUNCTIONS_PATH, SCHEDULE_TAB, - ALERTS_PAGE_PATH + ALERTS_PAGE_PATH, + IS_MF_MODE } from '../../../constants' import { generateNuclioLink } from '../../../utils' @@ -158,16 +159,16 @@ export const getLinks = projectName => { label: 'Nuclio', nestedLinks: [ { - id: REAL_TIME_FUNCTIONS_PAGE, + id: NUCLIO_FUNCTIONS_PATH, label: 'Real-time functions', - link: generateNuclioLink(`${pathname}/${FUNCTIONS_PAGE_PATH}`), - externalLink: true + link: generateNuclioLink(`${pathname}/${NUCLIO_FUNCTIONS_PATH}`), + externalLink: !IS_MF_MODE }, { id: API_GATEWAYS_PAGE, label: 'API gateways', link: generateNuclioLink(`${pathname}/${API_GATEWAYS_PAGE}`), - externalLink: true + externalLink: !IS_MF_MODE } ] }, diff --git a/src/reducers/featureStoreReducer.js b/src/reducers/featureStoreReducer.js index 53deac56ac..a493d4fdda 100644 --- a/src/reducers/featureStoreReducer.js +++ b/src/reducers/featureStoreReducer.js @@ -24,7 +24,6 @@ import { } from '../utils/getUniqueIdentifier' import featureStoreApi from '../api/featureStore-api' import { FORBIDDEN_ERROR_STATUS_CODE } from 'igz-controls/constants' -import { PANEL_DEFAULT_ACCESS_KEY } from '../constants' import { REDISNOSQL } from '../components/FeatureSetsPanel/FeatureSetsPanelTargetStore/featureSetsPanelTargetStore.util' import { createAsyncThunk, createSlice } from '@reduxjs/toolkit' import { hideLoading, showLoading } from './redux.util' @@ -67,7 +66,7 @@ const initialState = { loading: false, newFeatureSet: { credentials: { - access_key: PANEL_DEFAULT_ACCESS_KEY + access_key: 'default' // TODO should be conditional based on env for igz3 PANEL_DEFAULT_ACCESS_KEY }, metadata: { name: '', diff --git a/src/reducers/jobReducer.js b/src/reducers/jobReducer.js index 12df491dd7..7ffe9f70e3 100644 --- a/src/reducers/jobReducer.js +++ b/src/reducers/jobReducer.js @@ -27,7 +27,8 @@ import { LABELS_FILTER, NAME_FILTER, STATUS_FILTER, - TYPE_FILTER + TYPE_FILTER, + IS_MF_MODE } from '../constants' import { largeResponseCatchHandler } from '../utils/largeResponseCatchHandler' import functionsApi from '../api/functions-api' @@ -65,11 +66,13 @@ const initialState = { } }, function: { - metadata: { - credentials: { - access_key: '' + ...(!IS_MF_MODE && { + metadata: { + credentials: { + access_key: '' + } } - }, + }), spec: { env: [], node_selector: {}, diff --git a/src/setupProxy.js b/src/setupProxy.js deleted file mode 100644 index 80056e64d8..0000000000 --- a/src/setupProxy.js +++ /dev/null @@ -1,76 +0,0 @@ -/* -Copyright 2019 Iguazio Systems Ltd. - -Licensed under the Apache License, Version 2.0 (the "License") with -an addition restriction as set forth herein. You may not use this -file except in compliance with the License. You may obtain a copy of -the License at http://www.apache.org/licenses/LICENSE-2.0. - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. See the License for the specific language governing -permissions and limitations under the License. - -In addition, you may not use the software for any purposes that are -illegal under applicable law, and the grant of the foregoing license -under the Apache 2.0 license is conditioned upon your compliance with -such restriction. -*/ -const { createProxyMiddleware } = require('http-proxy-middleware') - -module.exports = function (app) { - app.use( - '/api', - createProxyMiddleware({ - target: import.meta.env.VITE_MLRUN_API_URL, - changeOrigin: true, - headers: { - Connection: 'keep-alive' - }, - onProxyReq: function (proxyReq) { - proxyReq.setHeader('x-v3io-session-key', import.meta.env.VITE_MLRUN_V3IO_ACCESS_KEY) - proxyReq.setHeader('x-remote-user', 'admin') - } - }) - ) - - if (import.meta.env.VITE_NUCLIO_API_URL) { - app.use( - '/nuclio', - createProxyMiddleware({ - target: import.meta.env.VITE_NUCLIO_API_URL, - pathRewrite: { - '^/nuclio': '' - }, - changeOrigin: true - }) - ) - } - - if (import.meta.env.VITE_IGUAZIO_API_URL) { - app.use( - '/iguazio', - createProxyMiddleware({ - target: import.meta.env.VITE_IGUAZIO_API_URL, - pathRewrite: { - '^/iguazio': '' - }, - changeOrigin: true - }) - ) - } - - if (import.meta.env.VITE_FUNCTION_CATALOG_URL) { - app.use( - '/function-catalog', - createProxyMiddleware({ - target: import.meta.env.VITE_FUNCTION_CATALOG_URL, - pathRewrite: { - '^/function-catalog': '' - }, - changeOrigin: true - }) - ) - } -} diff --git a/src/utils/createApplicationContent.jsx b/src/utils/createApplicationContent.jsx index d8422185dc..e9be466a5c 100644 --- a/src/utils/createApplicationContent.jsx +++ b/src/utils/createApplicationContent.jsx @@ -22,7 +22,7 @@ import { capitalize } from 'lodash' import { formatDatetime } from 'igz-controls/utils/datetime.util' import { generateNuclioLink } from './parseUri' import { saveAndTransformSearchParams } from 'igz-controls/utils/filter.util' -import { MONITORING_APP_PAGE } from '../constants' +import { IS_MF_MODE, MONITORING_APP_PAGE, NUCLIO_FUNCTIONS_PATH } from '../constants' export const createApplicationContent = (application, projectName) => { const identifierUnique = 'identifierUnique.' + application.name + application.application_class @@ -105,8 +105,10 @@ export const createApplicationContent = (application, projectName) => { value: application.name, className: 'table-cell-2', getLink: () => - generateNuclioLink(`/projects/${projectName}/functions/${nuclioFunctionName}`), - linkIsExternal: true, + generateNuclioLink( + `/projects/${projectName}/${NUCLIO_FUNCTIONS_PATH}/${nuclioFunctionName}` + ), + linkIsExternal: !IS_MF_MODE, showStatus: true } ] diff --git a/src/utils/createConsumerGroupsContent.js b/src/utils/createConsumerGroupsContent.js index db9ea22f54..14781c18c4 100644 --- a/src/utils/createConsumerGroupsContent.js +++ b/src/utils/createConsumerGroupsContent.js @@ -19,6 +19,7 @@ such restriction. */ import { generateNuclioLink } from './parseUri' import { getV3ioStreamIdentifier } from './getUniqueIdentifier' +import { IS_MF_MODE, NUCLIO_FUNCTIONS_PATH } from '../constants' const createConsumerGroupsContent = (content, params) => { return content.map(contentItem => { @@ -46,10 +47,10 @@ const createConsumerGroupsContent = (content, params) => { value: contentItem.functionName, getLink: () => { return generateNuclioLink( - `/projects/${params.projectName}/functions/${contentItem.functionName}` + `/projects/${params.projectName}/${NUCLIO_FUNCTIONS_PATH}/${contentItem.functionName}` ) }, - linkIsExternal: true, + linkIsExternal: !IS_MF_MODE, className: 'table-cell-1' } } diff --git a/src/utils/createRealTimePipelinesContent.js b/src/utils/createRealTimePipelinesContent.js index 5121112a3e..4375fde20e 100644 --- a/src/utils/createRealTimePipelinesContent.js +++ b/src/utils/createRealTimePipelinesContent.js @@ -19,7 +19,13 @@ such restriction. */ import { formatDatetime } from 'igz-controls/utils/datetime.util' -import { DETAILS_MODEL_ENDPOINTS_TAB, MODELS_PAGE, REAL_TIME_PIPELINES_TAB } from '../constants' +import { + DETAILS_MODEL_ENDPOINTS_TAB, + IS_MF_MODE, + MODELS_PAGE, + NUCLIO_FUNCTIONS_PATH, + REAL_TIME_PIPELINES_TAB +} from '../constants' import { typesOfJob } from './jobs.util' import { generateNuclioLink } from './parseUri' @@ -50,9 +56,11 @@ const createRealTimePipelinesContent = (pipelines, projectName) => className: 'table-cell-2', showStatus: true, showTag: true, - linkIsExternal: true, + linkIsExternal: !IS_MF_MODE, getLink: () => - generateNuclioLink(`/projects/${projectName}/functions/${nuclioFunctionName}`) + generateNuclioLink( + `/projects/${projectName}/${NUCLIO_FUNCTIONS_PATH}/${nuclioFunctionName}` + ) }, { id: `topology.${pipeline.ui.identifierUnique}`, diff --git a/src/utils/getArtifactPreview.jsx b/src/utils/getArtifactPreview.jsx index 5748253458..86b4abc58a 100644 --- a/src/utils/getArtifactPreview.jsx +++ b/src/utils/getArtifactPreview.jsx @@ -191,7 +191,7 @@ export const fetchArtifactPreviewFromPath = async ( { data: { content: `The artifact is too large to ${ - fileSize > artifactLimits.max_download_size + fileSize > artifactLimits?.max_download_size ? `download. Go to ${path} to retrieve the data, or use mlrun api/sdk project.get_artifact('${artifact.db_key || artifact.name}').to_dataitem().get()` : 'preview, use the download option instead' }` diff --git a/src/utils/getJobLogs.util.js b/src/utils/getJobLogs.util.js index c78b971249..7d41761d6c 100644 --- a/src/utils/getJobLogs.util.js +++ b/src/utils/getJobLogs.util.js @@ -34,7 +34,7 @@ export const getJobLogs = ( dispatch(fetchJobLogs({ id, project, attempt, signal })) .unwrap() .then(res => { - const reader = res.body?.getReader() + const reader = res.data?.getReader() if (reader) { const decoder = new TextDecoder() diff --git a/src/utils/nuclio.remotes.utils.js b/src/utils/nuclio.remotes.utils.js new file mode 100644 index 0000000000..90bf9f0365 --- /dev/null +++ b/src/utils/nuclio.remotes.utils.js @@ -0,0 +1,69 @@ +/* +Copyright 2019 Iguazio Systems Ltd. + +Licensed under the Apache License, Version 2.0 (the "License") with +an addition restriction as set forth herein. You may not use this +file except in compliance with the License. You may obtain a copy of +the License at http://www.apache.org/licenses/LICENSE-2.0. + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing +permissions and limitations under the License. + +In addition, you may not use the software for any purposes that are +illegal under applicable law, and the grant of the foregoing license +under the Apache 2.0 license is conditioned upon your compliance with +such restriction. +*/ +import { loadRemote, registerRemotes } from '@module-federation/runtime' + +let registerPromise = null + +const ensureNuclioRemote = async () => { + if (registerPromise) return registerPromise + + const config = window?.mlrunConfig + let remoteEntryUrl = config?.nuclioRemoteEntryUrl + + if (!remoteEntryUrl) { + throw new Error('[MF] Missing window.mlrunConfig.nuclioRemoteEntryUrl') + } + + if (window.location.hostname !== 'localhost') { + remoteEntryUrl = `${remoteEntryUrl.replace(/\/$/, '')}/nuclio-ui` + } else { + remoteEntryUrl = remoteEntryUrl.replace(/\/$/, '') + } + + registerPromise = (async () => { + try { + registerRemotes([ + { + name: 'nuclio', + entry: `${remoteEntryUrl.replace(/\/$/, '')}/remoteEntry.js`, + type: 'module', + shareScope: 'default' + } + ]) + } catch (err) { + registerPromise = null + throw err + } + })() + + return registerPromise +} + +const loadNuclioApp = async () => { + await ensureNuclioRemote() + const module = await loadRemote('nuclio/App') + + if (!module) throw new Error('[MF] Failed to load Nuclio application') + + const component = module.default?.default || module.default || module + return { default: component } +} + +export { ensureNuclioRemote, loadNuclioApp } diff --git a/src/utils/parseUri.js b/src/utils/parseUri.js index 26167d094d..b15de1ef1d 100644 --- a/src/utils/parseUri.js +++ b/src/utils/parseUri.js @@ -24,7 +24,8 @@ import { MONITOR_JOBS_TAB, FILES_PAGE, DATASETS_PAGE, - DOCUMENTS_PAGE + DOCUMENTS_PAGE, + IS_MF_MODE } from '../constants' /** @@ -117,10 +118,14 @@ const generateLinkPath = (uri = '') => { } const generateNuclioLink = pathname => { - const linkUrl = new URL(`${window.mlrunConfig.nuclioUiUrl}${pathname}`) + if (IS_MF_MODE) return pathname - if (window.location.origin !== window.mlrunConfig.nuclioUiUrl) { - linkUrl.searchParams.set?.('origin', window.location.origin) + const base = window.mlrunConfig?.nuclioUiUrl || window.location.origin + const cleanPath = pathname.startsWith('/') ? pathname : `/${pathname}` + const linkUrl = new URL(`${base}${cleanPath}`) + + if (window.location.origin !== base) { + linkUrl.searchParams.set('origin', window.location.origin) } return linkUrl.toString() diff --git a/src/utils/projectAuth.util.js b/src/utils/projectAuth.util.js new file mode 100644 index 0000000000..ec99b8b0b5 --- /dev/null +++ b/src/utils/projectAuth.util.js @@ -0,0 +1,53 @@ +/* +Copyright 2019 Iguazio Systems Ltd. + +Licensed under the Apache License, Version 2.0 (the "License") with +an addition restriction as set forth herein. You may not use this +file except in compliance with the License. You may obtain a copy of +the License at http://www.apache.org/licenses/LICENSE-2.0. + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing +permissions and limitations under the License. + +In addition, you may not use the software for any purposes that are +illegal under applicable law, and the grant of the foregoing license +under the Apache 2.0 license is conditioned upon your compliance with +such restriction. +*/ +import projectsIguazioApi from '../api/projects-iguazio-api' + +const WRITE_ROLES = ['Owner', 'Admin', 'Editor'] + +export const getActiveUsername = async () => { + const response = await projectsIguazioApi.getActiveUser() + return response.data.metadata?.username +} + +export const checkProjectWriteAccess = async (projectName, activeUsername = null) => { + if (import.meta.env.VITE_FEDERATION === 'true') { + if (!activeUsername) { + activeUsername = await getActiveUsername() + } + + const policiesResponse = await projectsIguazioApi.getProjectPolicies(projectName) + const policies = policiesResponse.data.items || [] + return policies.some( + policy => + WRITE_ROLES.includes(policy.spec.displayName) && + policy.status?.assignedMembers?.some(member => member.id === activeUsername) + ) + } else { + return projectsIguazioApi + .getProjectOwnerVisibility(projectName) + .then(() => true) + .catch(() => + projectsIguazioApi + .getProjectWorkflowsUpdateAuthorization(projectName) + .then(() => true) + .catch(() => false) + ) + } +} diff --git a/vite.config.mjs b/vite.config.mjs index b7bb90b568..f60034369d 100644 --- a/vite.config.mjs +++ b/vite.config.mjs @@ -1,50 +1,40 @@ import commonjs from 'vite-plugin-commonjs' import eslint from 'vite-plugin-eslint' +import { federation } from '@module-federation/vite' import path from 'node:path' import react from '@vitejs/plugin-react-swc' import svgr from 'vite-plugin-svgr' import { defineConfig, loadEnv } from 'vite' -export default defineConfig(({ mode }) => { +import { loadMlrunProxyConfig } from './config/loadDevProxyConfig.js' +import { dependencies } from './package.json' + +export default defineConfig(async ({ mode }) => { const env = loadEnv(mode, path.resolve(process.cwd()), '') + const mlrunProxyConfig = await loadMlrunProxyConfig(mode) + + const federationPlugin = + env.VITE_FEDERATION === 'true' + ? federation({ + filename: 'remoteEntry.js', + name: 'mlrun', + exposes: { + './loadRemoteConfig': './src/loadRemoteConfig.js', + './app': './src/main.jsx' + }, + shared: { + react: { requiredVersion: dependencies.react, singleton: true }, + 'react-dom': { requiredVersion: dependencies['react-dom'], singleton: true } + } + }) + : null return { - plugins: [commonjs(), react(), svgr(), eslint({ failOnError: false })], + plugins: [commonjs(), react(), federationPlugin, svgr(), eslint({ failOnError: false })], base: env.NODE_ENV === 'production' ? env.VITE_PUBLIC_URL : '/', server: { proxy: { - '/api': env.VITE_MLRUN_API_URL - ? { - target: env.VITE_MLRUN_API_URL, - changeOrigin: true, - headers: { - Connection: 'keep-alive', - 'x-v3io-session-key': env.VITE_MLRUN_V3IO_ACCESS_KEY, - 'x-remote-user': 'admin' - } - } - : undefined, - '/nuclio': env.VITE_NUCLIO_API_URL - ? { - target: env.VITE_NUCLIO_API_URL, - changeOrigin: true, - rewrite: path => path.replace(/^\/nuclio/, '') - } - : undefined, - '/iguazio': env.VITE_IGUAZIO_API_URL - ? { - target: env.VITE_IGUAZIO_API_URL, - changeOrigin: true, - rewrite: path => path.replace(/^\/iguazio/, '') - } - : undefined, - '/function-catalog': env.VITE_FUNCTION_CATALOG_URL - ? { - target: env.VITE_FUNCTION_CATALOG_URL, - changeOrigin: true, - rewrite: path => path.replace(/^\/function-catalog/, '') - } - : undefined + ...mlrunProxyConfig(env) }, fs: { strict: false @@ -84,6 +74,7 @@ export default defineConfig(({ mode }) => { force: true }, build: { + target: 'esnext', sourcemap: true, outDir: 'build', chunkSizeWarningLimit: 3000