diff --git a/.docker/templates/default.conf.template b/.docker/templates/default.conf.template index 991a5294..61c4e648 100644 --- a/.docker/templates/default.conf.template +++ b/.docker/templates/default.conf.template @@ -37,17 +37,6 @@ server { internal; } - location /vite { - proxy_set_header X-Forwarded-For $remote_addr; - proxy_set_header Host $http_host; - proxy_pass http://node:3000; - proxy_http_version 1.1; - - # Enable WebSocket support for HMR - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "upgrade"; - } - location ~ \.php$ { return 404; } diff --git a/.env b/.env index e25463ff..ab0e35b3 100644 --- a/.env +++ b/.env @@ -115,7 +115,7 @@ TRACK_SCREEN_INFO_UPDATE_INTERVAL_SECONDS=300 ADMIN_REJSEPLANEN_APIKEY= ADMIN_SHOW_SCREEN_STATUS=false ADMIN_TOUCH_BUTTON_REGIONS=false -ADMIN_LOGIN_METHODS="[]" +ADMIN_LOGIN_METHODS='[{"type":"username-password","enabled":true,"provider":"username-password","label":""}]' ADMIN_ENHANCED_PREVIEW=false ###< Admin configuration ### diff --git a/.github/workflows/apispec.yaml b/.github/workflows/apispec.yaml new file mode 100644 index 00000000..81de9fed --- /dev/null +++ b/.github/workflows/apispec.yaml @@ -0,0 +1,50 @@ +on: pull_request + +name: Api Spec + +jobs: + apispec: + runs-on: ubuntu-latest + name: API Specification validation + strategy: + fail-fast: false + matrix: + php: ["8.3"] + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 2 + + - name: Setup PHP, with composer and extensions + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php}} + extensions: apcu, ctype, iconv, imagick, json, redis, soap, xmlreader, zip + coverage: none + + - name: Get composer cache directory + id: composer-cache + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - name: Cache composer dependencies + uses: actions/cache@v4 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ matrix.php }}-composer- + + - name: Install Dependencies + run: composer install -q --no-ansi --no-interaction --no-scripts --no-suggest --no-progress --prefer-dist + + - name: Export specifications (yaml) + run: bin/console api:openapi:export --yaml --output=public/api-spec-v2.yaml --no-interaction + + - name: Check for changes in specifications (yaml) + run: git diff --diff-filter=ACMRT --exit-code public/api-spec-v2.yaml + + - name: Export specifications (json) + run: bin/console api:openapi:export --output=public/api-spec-v2.json --no-interaction + + - name: Check for changes in specifications (json) + run: git diff --diff-filter=ACMRT --exit-code public/api-spec-v2.json diff --git a/.github/workflows/composer.yaml b/.github/workflows/composer.yaml index 1bdcc571..b93b0d81 100644 --- a/.github/workflows/composer.yaml +++ b/.github/workflows/composer.yaml @@ -26,7 +26,7 @@ name: Composer env: - COMPOSE_USER: root + COMPOSE_USER: runner on: pull_request: @@ -65,5 +65,4 @@ jobs: - uses: actions/checkout@v4 - run: | docker network create frontend - docker compose run --rm phpfpm composer install - docker compose run --rm phpfpm composer audit + docker compose run --rm phpfpm composer audit --locked diff --git a/.github/workflows/composer_install.yaml b/.github/workflows/composer_install.yaml new file mode 100644 index 00000000..569a71b3 --- /dev/null +++ b/.github/workflows/composer_install.yaml @@ -0,0 +1,40 @@ +on: pull_request + +name: Composer install + +jobs: + test-composer-install: + runs-on: ubuntu-latest + env: + COMPOSER_ALLOW_SUPERUSER: 1 + strategy: + fail-fast: false + matrix: + php: ["8.3"] + name: Composer install in prod mode (PHP ${{ matrix.php}}) + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup PHP, with composer and extensions + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php}} + extensions: apcu, ctype, iconv, imagick, json, redis, soap, xmlreader, zip + coverage: none + + - name: Get composer cache directory + id: composer-cache + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - name: Cache composer dependencies + uses: actions/cache@v4 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ matrix.php }}-composer- + + - name: "[prod] Composer install with exported .env variables" + run: | + set -a && source .env && set +a + APP_ENV=prod composer install --no-dev -o diff --git a/.github/workflows/doctrine.yaml b/.github/workflows/doctrine.yaml new file mode 100644 index 00000000..411acc50 --- /dev/null +++ b/.github/workflows/doctrine.yaml @@ -0,0 +1,57 @@ +on: pull_request + +name: Doctrine + +jobs: + validate-doctrine-shema: + runs-on: ubuntu-latest + env: + DATABASE_URL: mysql://db:db@127.0.0.1:3306/db?serverVersion=mariadb-10.5.13 + strategy: + fail-fast: false + matrix: + php: ["8.3"] + name: Validate Schema (PHP ${{ matrix.php}}) + services: + mariadb: + image: mariadb:10.5.13 + env: + MYSQL_USER: db + MYSQL_PASSWORD: db + MYSQL_DATABASE: db + MYSQL_ROOT_PASSWORD: db + ports: + - 3306:3306 + options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3 + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup PHP, with composer and extensions + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php}} + extensions: apcu, ctype, iconv, imagick, json, redis, soap, xmlreader, zip + coverage: none + + - name: Get composer cache directory + id: composer-cache + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - name: Cache composer dependencies + uses: actions/cache@v4 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ matrix.php }}-composer- + + - name: "Composer install with exported .env variables" + run: | + set -a && source .env && set +a + APP_ENV=prod composer install --no-dev -o + + - name: Run Doctrine Migrations + run: APP_ENV=prod php bin/console doctrine:migrations:migrate --no-interaction + + - name: Validate Doctrine schema + run: APP_ENV=prod php bin/console doctrine:schema:validate diff --git a/.github/workflows/php.yaml b/.github/workflows/php.yaml index 60fb70eb..ee967977 100644 --- a/.github/workflows/php.yaml +++ b/.github/workflows/php.yaml @@ -34,7 +34,7 @@ name: Symfony PHP env: - COMPOSE_USER: root + COMPOSE_USER: runner on: pull_request: diff --git a/.github/workflows/phpunit.yaml b/.github/workflows/phpunit.yaml new file mode 100644 index 00000000..2a2e5488 --- /dev/null +++ b/.github/workflows/phpunit.yaml @@ -0,0 +1,59 @@ +on: pull_request + +name: Test + +jobs: + phpunit: + runs-on: ubuntu-latest + services: + mariadb: + image: mariadb:lts + ports: + - 3306 + env: + MYSQL_USER: db + MYSQL_PASSWORD: db + MYSQL_DATABASE: db_test + MYSQL_ROOT_PASSWORD: password + # https://mariadb.org/mariadb-server-docker-official-images-healthcheck-without-mysqladmin/ + options: >- + --health-cmd="healthcheck.sh --connect --innodb_initialized" + --health-interval=5s + --health-timeout=2s + --health-retries=3 + strategy: + fail-fast: false + matrix: + php: ["8.3"] + name: PHP Unit tests (PHP ${{ matrix.php }}) + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup PHP, with composer and extensions + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php}} + extensions: apcu, ctype, iconv, imagick, json, redis, soap, xmlreader, zip + coverage: none + + - name: Get composer cache directory + id: composer-cache + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - name: Cache composer dependencies + uses: actions/cache@v4 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ matrix.php }}-composer- + + - name: Install Dependencies + run: composer install -q --no-ansi --no-interaction --no-scripts --no-suggest --no-progress --prefer-dist + + - name: PHP Unit - Test setup + env: + PORT: ${{ job.services.mariadb.ports[3306] }} + run: | + DATABASE_URL="mysql://db:db@127.0.0.1:$PORT/db_test" composer run test-setup + DATABASE_URL="mysql://db:db@127.0.0.1:$PORT/db_test" composer run test diff --git a/.github/workflows/playwright.yaml b/.github/workflows/playwright.yaml new file mode 100644 index 00000000..02550e4e --- /dev/null +++ b/.github/workflows/playwright.yaml @@ -0,0 +1,42 @@ +on: pull_request + +name: Test + +env: + COMPOSE_USER: runner + +jobs: + frontend-build-and-test: + name: Playwright + runs-on: ubuntu-latest + strategy: + fail-fast: true + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup network + run: docker network create frontend + + - name: Composer install + run: | + docker compose run --rm phpfpm composer install + + - name: Build assets + run: | + docker compose run --rm node npm install + docker compose run --rm node npm run build + + - name: Run playwright + env: + CI: "true" + run: | + docker compose run --rm playwright npx playwright install --with-deps + docker compose run --rm playwright npx playwright test + + - uses: actions/upload-artifact@v4 + if: always() + with: + name: playwright-report + path: playwright-report/ + retention-days: 30 diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml deleted file mode 100644 index 87882f18..00000000 --- a/.github/workflows/pr.yaml +++ /dev/null @@ -1,265 +0,0 @@ -on: pull_request -name: Pull Request Review -jobs: - test-composer-install: - runs-on: ubuntu-latest - env: - COMPOSER_ALLOW_SUPERUSER: 1 - strategy: - fail-fast: false - matrix: - php: ["8.3"] - name: Validate composer (PHP ${{ matrix.php}}) - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Setup PHP, with composer and extensions - uses: shivammathur/setup-php@v2 - with: - php-version: ${{ matrix.php}} - extensions: apcu, ctype, iconv, imagick, json, redis, soap, xmlreader, zip - coverage: none - - - name: Get composer cache directory - id: composer-cache - run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT - - - name: Cache composer dependencies - uses: actions/cache@v4 - with: - path: ${{ steps.composer-cache.outputs.dir }} - key: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.lock') }} - restore-keys: ${{ matrix.php }}-composer- - - - name: "[prod] Composer install with exported .env variables" - run: | - set -a && source .env && set +a - APP_ENV=prod composer install --no-dev -o - - validate-doctrine-shema: - runs-on: ubuntu-latest - env: - DATABASE_URL: mysql://db:db@127.0.0.1:3306/db?serverVersion=mariadb-10.5.13 - strategy: - fail-fast: false - matrix: - php: ["8.3"] - name: Validate Doctrine Schema (PHP ${{ matrix.php}}) - services: - mariadb: - image: mariadb:10.5.13 - env: - MYSQL_USER: db - MYSQL_PASSWORD: db - MYSQL_DATABASE: db - MYSQL_ROOT_PASSWORD: db - ports: - - 3306:3306 - options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3 - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Setup PHP, with composer and extensions - uses: shivammathur/setup-php@v2 - with: - php-version: ${{ matrix.php}} - extensions: apcu, ctype, iconv, imagick, json, redis, soap, xmlreader, zip - coverage: none - - - name: Get composer cache directory - id: composer-cache - run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT - - - name: Cache composer dependencies - uses: actions/cache@v4 - with: - path: ${{ steps.composer-cache.outputs.dir }} - key: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.lock') }} - restore-keys: ${{ matrix.php }}-composer- - - - name: "Composer install with exported .env variables" - run: | - set -a && source .env && set +a - APP_ENV=prod composer install --no-dev -o - - - name: Run Doctrine Migrations - run: APP_ENV=prod php bin/console doctrine:migrations:migrate --no-interaction - - - name: Validate Doctrine schema - run: APP_ENV=prod php bin/console doctrine:schema:validate - - psalm: - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - php: ["8.3"] - name: Psalm (PHP ${{ matrix.php }}) - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Setup PHP, with composer and extensions - uses: shivammathur/setup-php@v2 - with: - php-version: ${{ matrix.php}} - extensions: apcu, ctype, iconv, imagick, json, redis, soap, xmlreader, zip - coverage: none - - - name: Get composer cache directory - id: composer-cache - run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT - - - name: Cache composer dependencies - uses: actions/cache@v4 - with: - path: ${{ steps.composer-cache.outputs.dir }} - key: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.lock') }} - restore-keys: ${{ matrix.php }}-composer- - - - name: Install Dependencies - run: composer install -q --no-ansi --no-interaction --no-scripts --no-suggest --no-progress --prefer-dist - - - name: Psalm - run: phpdbg -qrr ./vendor/bin/psalm - - rector: - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - php: ["8.3"] - name: Rector (PHP ${{ matrix.php }}) - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Setup PHP, with composer and extensions - uses: shivammathur/setup-php@v2 - with: - php-version: ${{ matrix.php}} - extensions: apcu, ctype, iconv, imagick, json, redis, soap, xmlreader, zip - coverage: none - - - name: Get composer cache directory - id: composer-cache - run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT - - - name: Cache composer dependencies - uses: actions/cache@v4 - with: - path: ${{ steps.composer-cache.outputs.dir }} - key: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.lock') }} - restore-keys: ${{ matrix.php }}-composer- - - - name: Install Dependencies - run: composer install -q --no-ansi --no-interaction --no-scripts --no-suggest --no-progress --prefer-dist - - - name: Rector - run: phpdbg -qrr ./vendor/bin/rector --dry-run - - phpunit: - runs-on: ubuntu-latest - services: - mariadb: - image: mariadb:lts - ports: - - 3306 - env: - MYSQL_USER: db - MYSQL_PASSWORD: db - MYSQL_DATABASE: db_test - MYSQL_ROOT_PASSWORD: password - # https://mariadb.org/mariadb-server-docker-official-images-healthcheck-without-mysqladmin/ - options: >- - --health-cmd="healthcheck.sh --connect --innodb_initialized" - --health-interval=5s - --health-timeout=2s - --health-retries=3 - strategy: - fail-fast: false - matrix: - php: ["8.3"] - name: PHP Unit tests (PHP ${{ matrix.php }}) - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Setup PHP, with composer and extensions - uses: shivammathur/setup-php@v2 - with: - php-version: ${{ matrix.php}} - extensions: apcu, ctype, iconv, imagick, json, redis, soap, xmlreader, zip - coverage: none - - - name: Get composer cache directory - id: composer-cache - run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT - - - name: Cache composer dependencies - uses: actions/cache@v4 - with: - path: ${{ steps.composer-cache.outputs.dir }} - key: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.lock') }} - restore-keys: ${{ matrix.php }}-composer- - - - name: Install Dependencies - run: composer install -q --no-ansi --no-interaction --no-scripts --no-suggest --no-progress --prefer-dist - - - name: PHP Unit - Test setup - env: - PORT: ${{ job.services.mariadb.ports[3306] }} - run: DATABASE_URL="mysql://db:db@127.0.0.1:$PORT/db_test" composer run test-setup - - - name: PHP Unit - Test - env: - PORT: ${{ job.services.mariadb.ports[3306] }} - run: DATABASE_URL="mysql://db:db@127.0.0.1:$PORT/db_test" composer run test - - apispec: - runs-on: ubuntu-latest - name: API Specification validation - strategy: - fail-fast: false - matrix: - php: ["8.3"] - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - fetch-depth: 2 - - - name: Setup PHP, with composer and extensions - uses: shivammathur/setup-php@v2 - with: - php-version: ${{ matrix.php}} - extensions: apcu, ctype, iconv, imagick, json, redis, soap, xmlreader, zip - coverage: none - - - name: Get composer cache directory - id: composer-cache - run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT - - - name: Cache composer dependencies - uses: actions/cache@v4 - with: - path: ${{ steps.composer-cache.outputs.dir }} - key: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.lock') }} - restore-keys: ${{ matrix.php }}-composer- - - - name: Install Dependencies - run: composer install -q --no-ansi --no-interaction --no-scripts --no-suggest --no-progress --prefer-dist - - - name: Export specifications (yaml) - run: bin/console api:openapi:export --yaml --output=public/api-spec-v2.yaml --no-interaction - - - name: Check for changes in specifications (yaml) - run: git diff --diff-filter=ACMRT --exit-code public/api-spec-v2.yaml - - - name: Export specifications (json) - run: bin/console api:openapi:export --output=public/api-spec-v2.json --no-interaction - - - name: Check for changes in specifications (json) - run: git diff --diff-filter=ACMRT --exit-code public/api-spec-v2.json diff --git a/.github/workflows/psalm.yaml b/.github/workflows/psalm.yaml new file mode 100644 index 00000000..6cbb222c --- /dev/null +++ b/.github/workflows/psalm.yaml @@ -0,0 +1,39 @@ +on: pull_request + +name: Psalm + +jobs: + psalm: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + php: ["8.3"] + name: Psalm (PHP ${{ matrix.php }}) + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup PHP, with composer and extensions + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php}} + extensions: apcu, ctype, iconv, imagick, json, redis, soap, xmlreader, zip + coverage: none + + - name: Get composer cache directory + id: composer-cache + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - name: Cache composer dependencies + uses: actions/cache@v4 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ matrix.php }}-composer- + + - name: Install Dependencies + run: composer install -q --no-ansi --no-interaction --no-scripts --no-suggest --no-progress --prefer-dist + + - name: Psalm + run: phpdbg -qrr ./vendor/bin/psalm diff --git a/.github/workflows/rector.yaml b/.github/workflows/rector.yaml new file mode 100644 index 00000000..aa482e70 --- /dev/null +++ b/.github/workflows/rector.yaml @@ -0,0 +1,39 @@ +on: pull_request + +name: Rector + +jobs: + rector: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + php: ["8.3"] + name: Rector (PHP ${{ matrix.php }}) + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup PHP, with composer and extensions + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php}} + extensions: apcu, ctype, iconv, imagick, json, redis, soap, xmlreader, zip + coverage: none + + - name: Get composer cache directory + id: composer-cache + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - name: Cache composer dependencies + uses: actions/cache@v4 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ matrix.php }}-composer- + + - name: Install Dependencies + run: composer install -q --no-ansi --no-interaction --no-scripts --no-suggest --no-progress --prefer-dist + + - name: Rector + run: phpdbg -qrr ./vendor/bin/rector --dry-run diff --git a/.github/workflows/twig.yaml b/.github/workflows/twig.yaml index 9b0e3431..9dc424b4 100644 --- a/.github/workflows/twig.yaml +++ b/.github/workflows/twig.yaml @@ -24,7 +24,7 @@ name: Twig env: - COMPOSE_USER: root + COMPOSE_USER: runner on: pull_request: diff --git a/CHANGELOG.md b/CHANGELOG.md index 91ad6d86..3e9902fb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ All notable changes to this project will be documented in this file. * Added ADRs 008 and 009. * Cleaned up Github Actions workflows. * Updated PHP dependencies. +* Added Playwright github action. ### NB! Prior to 3.x the project was split into separate repositories diff --git a/assets/admin/admin-config-loader.js b/assets/admin/admin-config-loader.js new file mode 100644 index 00000000..0624ff13 --- /dev/null +++ b/assets/admin/admin-config-loader.js @@ -0,0 +1,57 @@ +let configData = null; +let activePromise = null; + +const AdminConfigLoader = { + async loadConfig() { + if (activePromise) { + return activePromise; + } + + activePromise = new Promise((resolve) => { + if (configData !== null) { + resolve(configData); + } else { + fetch("/config/admin") + .then((response) => response.json()) + .then((data) => { + configData = data; + resolve(configData); + }) + .catch(() => { + if (configData !== null) { + resolve(configData); + } else { + // eslint-disable-next-line no-console + console.error("Could not load config. Will use default config."); + + // Default config. + resolve({ + rejseplanenApiKey: null, + touchButtonRegions: false, + showScreenStatus: false, + enhancedPreview: false, + loginMethods: [ + { + type: "username-password", + enabled: true, + provider: "username-password", + label: null, + icon: null, + }, + ], + }); + } + }) + .finally(() => { + activePromise = null; + }); + } + }); + + return activePromise; + }, +}; + +Object.freeze(AdminConfigLoader); + +export default AdminConfigLoader; diff --git a/assets/admin/app.jsx b/assets/admin/app.jsx index 315bf4a4..5b839224 100644 --- a/assets/admin/app.jsx +++ b/assets/admin/app.jsx @@ -39,7 +39,7 @@ import UsersList from "./components/users/users-list"; import ActivationCodeList from "./components/activation-code/activation-code-list"; import ActivationCodeCreate from "./components/activation-code/activation-code-create"; import ActivationCodeActivate from "./components/activation-code/activation-code-activate"; -import ConfigLoader from "../shared/config-loader.js"; +import AdminConfigLoader from "./admin-config-loader.js"; import "react-toastify/dist/ReactToastify.css"; import "./app.scss"; import FeedSourcesList from "./components/feed-sources/feed-sources-list"; @@ -90,7 +90,9 @@ function App() { }; useEffect(() => { - setConfig(ConfigLoader.getConfig()); + AdminConfigLoader.loadConfig().then((loadedConfig) => { + setConfig(loadedConfig); + }) }, []); const handleReauthenticate = () => { diff --git a/assets/admin/components/screen/screen-list.jsx b/assets/admin/components/screen/screen-list.jsx index 9308be6c..eaaace95 100644 --- a/assets/admin/components/screen/screen-list.jsx +++ b/assets/admin/components/screen/screen-list.jsx @@ -18,7 +18,7 @@ import { displayError, } from "../util/list/toast-component/display-toast"; import "./screen-list.scss"; -import ConfigLoader from "../../../shared/config-loader.js"; +import AdminConfigLoader from "../../admin-config-loader.js"; /** * The screen list component. @@ -68,8 +68,9 @@ function ScreenList() { }); useEffect(() => { - const config = ConfigLoader.getConfig(); - setShowScreenStatus(config.showScreenStatus); + AdminConfigLoader.loadConfig().then((loadedConfig) => { + setShowScreenStatus(loadedConfig.showScreenStatus); + }); }, []); useEffect(() => { diff --git a/assets/admin/components/screen/screen-status.jsx b/assets/admin/components/screen/screen-status.jsx index 6399e0b3..1c10835b 100644 --- a/assets/admin/components/screen/screen-status.jsx +++ b/assets/admin/components/screen/screen-status.jsx @@ -18,7 +18,7 @@ import idFromUrl from "../util/helpers/id-from-url"; import { api } from "../../redux/api/api.generated.ts"; import { displayError } from "../util/list/toast-component/display-toast"; import FormInput from "../util/forms/form-input"; -import ConfigLoader from "../../../shared/config-loader.js"; +import AdminConfigLoader from "../../admin-config-loader.js"; /** * Displays screen status. @@ -102,8 +102,9 @@ function ScreenStatus({ screen, handleInput = () => {}, mode = "default" }) { }, [status]); useEffect(() => { - const config = ConfigLoader.getConfig(); - setShowScreenStatus(config.showScreenStatus); + AdminConfigLoader.loadConfig().then((loadedConfig) => { + setShowScreenStatus(loadedConfig.showScreenStatus); + }); }, []); if (mode === "minimal") { diff --git a/assets/admin/components/user/login.jsx b/assets/admin/components/user/login.jsx index 6c7c6383..bcfb922e 100644 --- a/assets/admin/components/user/login.jsx +++ b/assets/admin/components/user/login.jsx @@ -9,7 +9,7 @@ import {MultiSelect} from "react-multi-select-component"; import UserContext from "../../context/user-context"; import FormInput from "../util/forms/form-input"; import {api} from "../../redux/api/api.generated.ts"; -import ConfigLoader from "../../../shared/config-loader.js"; +import AdminConfigLoader from "../../admin-config-loader.js"; import {displayError} from "../util/list/toast-component/display-toast"; import localStorageKeys from "../util/local-storage-keys"; import LoginSidebar from "../navigation/login-sidebar/login-sidebar"; @@ -193,7 +193,6 @@ function Login() { }; useEffect(() => { - const config = ConfigLoader.getConfig(); const loginMethodDefaults = [ { type: "oidc", @@ -217,9 +216,11 @@ function Login() { }, ]; - setLoginMethods( - config.loginMethods ?? loginMethodDefaults - ); + AdminConfigLoader.loadConfig().then((loadedConfig) => { + setLoginMethods( + loadedConfig.loginMethods ?? loginMethodDefaults + ); + }); }, []); useEffect(() => { diff --git a/assets/client/app.jsx b/assets/client/app.jsx index 81e91e52..477055dd 100644 --- a/assets/client/app.jsx +++ b/assets/client/app.jsx @@ -2,7 +2,7 @@ import React, { useEffect, useRef, useState } from "react"; import PropTypes from "prop-types"; import Screen from "./components/screen.jsx"; import ContentService from "./service/content-service"; -import ConfigLoader from "../shared/config-loader"; +import ClientConfigLoader from "./client-config-loader.js"; import logger from "./logger/logger"; import "./app.scss"; import fallback from "./assets/fallback.png"; @@ -97,12 +97,12 @@ function App({ preview, previewId }) { clearTimeout(checkLoginTimeoutRef.current); } - const config = ConfigLoader.getConfig(); - - checkLoginTimeoutRef.current = setTimeout( - checkLogin, - config.loginCheckTimeout ?? defaults.loginCheckTimeoutDefault - ); + ClientConfigLoader.loadConfig().then((config) => { + checkLoginTimeoutRef.current = setTimeout( + checkLogin, + config.loginCheckTimeout ?? defaults.loginCheckTimeoutDefault + ); + }); }; /* eslint-enable no-use-before-define */ @@ -220,8 +220,9 @@ function App({ preview, previewId }) { tokenService.checkToken(); - const config = ConfigLoader.getConfig(); - setDebug(config.debug ?? false); + ClientConfigLoader.loadConfig().then((config) => { + setDebug(config.debug ?? false); + }); releaseService.checkForNewRelease().finally(() => { releaseService.setPreviousBootInUrl(); diff --git a/assets/client/client-config-loader.js b/assets/client/client-config-loader.js new file mode 100644 index 00000000..b02c0e18 --- /dev/null +++ b/assets/client/client-config-loader.js @@ -0,0 +1,83 @@ +// Only fetch new config if more than 15 minutes have passed. +import appStorage from "./util/app-storage"; + +const configFetchIntervalDefault = 15 * 60 * 1000; + +// Defaults. +let configData = null; + +// Last time the config was fetched. +let latestFetchTimestamp = 0; + +let activePromise = null; + +const ClientConfigLoader = { + async loadConfig() { + if (activePromise) { + return activePromise; + } + + activePromise = new Promise((resolve) => { + const nowTimestamp = new Date().getTime(); + + if ( + latestFetchTimestamp + + (configData?.configFetchInterval ?? configFetchIntervalDefault) >= + nowTimestamp + ) { + resolve(configData); + } else { + fetch(`/config/client`) + .then((response) => response.json()) + .then((data) => { + latestFetchTimestamp = nowTimestamp; + configData = data; + + // Make api endpoint available through localstorage. + appStorage.setApiUrl(configData.apiEndpoint); + + resolve(configData); + }) + .catch(() => { + if (configData !== null) { + resolve(configData); + } else { + // eslint-disable-next-line no-console + console.error("Could not load config. Will use default config."); + + // Default config. + resolve({ + apiEndpoint: "/api", + dataStrategy: { + type: "pull", + config: { + interval: 30000, + }, + }, + loginCheckTimeout: 20000, + configFetchInterval: 900000, + refreshTokenTimeout: 15000, + releaseTimestampIntervalTimeout: 600000, + colorScheme: { + type: "library", + lat: 56.0, + lng: 10.0, + }, + schedulingInterval: 60000, + debug: false, + }); + } + }) + .finally(() => { + activePromise = null; + }); + } + }); + + return activePromise; + }, +}; + +Object.freeze(ClientConfigLoader); + +export default ClientConfigLoader; diff --git a/assets/client/components/screen.jsx b/assets/client/components/screen.jsx index d04bfce2..73d9d378 100644 --- a/assets/client/components/screen.jsx +++ b/assets/client/components/screen.jsx @@ -6,7 +6,7 @@ import Region from "./region.jsx"; import "./screen.scss"; import logger from "../logger/logger"; import TouchRegion from "./touch-region.jsx"; -import ConfigLoader from "../../shared/config-loader"; +import ClientConfigLoader from "../client-config-loader.js"; /** * Screen component. @@ -32,41 +32,41 @@ function Screen({ screen }) { }; const refreshColorScheme = () => { - const config = ConfigLoader.getConfig(); - logger.info("Refreshing color scheme."); - const now = new Date(); - let colorScheme = ""; + ClientConfigLoader.loadConfig().then((config) => { + const now = new Date(); + let colorScheme; - if (config.colorScheme?.type === "library") { - // Default to somewhere in Denmark. - const times = SunCalc.getTimes( - now, - config.colorScheme?.lat ?? 56.0, - config.colorScheme?.lng ?? 10.0 - ); + if (config.colorScheme?.type === "library") { + // Default to somewhere in Denmark. + const times = SunCalc.getTimes( + now, + config.colorScheme?.lat ?? 56.0, + config.colorScheme?.lng ?? 10.0 + ); - if (now > times.sunrise && now < times.sunset) { - logger.info("Light color scheme activated."); - colorScheme = "color-scheme-light"; + if (now > times.sunrise && now < times.sunset) { + logger.info("Light color scheme activated."); + colorScheme = "color-scheme-light"; + } else { + logger.info("Dark color scheme activated."); + colorScheme = "color-scheme-dark"; + } } else { - logger.info("Dark color scheme activated."); - colorScheme = "color-scheme-dark"; + // Browser based. + colorScheme = window?.matchMedia("(prefers-color-scheme: dark)").matches + ? "color-scheme-dark" + : "color-scheme-light"; } - } else { - // Browser based. - colorScheme = window?.matchMedia("(prefers-color-scheme: dark)").matches - ? "color-scheme-dark" - : "color-scheme-light"; - } - // Set class name on html root. - document.documentElement.classList.remove( - "color-scheme-light", - "color-scheme-dark" - ); - document.documentElement.classList.add(colorScheme); + // Set class name on html root. + document.documentElement.classList.remove( + "color-scheme-light", + "color-scheme-dark" + ); + document.documentElement.classList.add(colorScheme); + }); }; useEffect(() => { diff --git a/assets/client/service/content-service.js b/assets/client/service/content-service.js index 34713c0d..c1ae1665 100644 --- a/assets/client/service/content-service.js +++ b/assets/client/service/content-service.js @@ -8,7 +8,7 @@ import { import logger from "../logger/logger"; import DataSync from "../data-sync/data-sync"; import ScheduleService from "./schedule-service"; -import ConfigLoader from "../../shared/config-loader"; +import ClientConfigLoader from "../client-config-loader.js"; /** * ContentService. @@ -48,18 +48,19 @@ class ContentService { startSyncing(screenPath) { logger.info("Starting data synchronization"); - const config = ConfigLoader.getConfig(); - const dataStrategyConfig = { - interval: config.pullStrategyInterval, - endpoint: "", - }; + ClientConfigLoader.loadConfig().then((config) => { + const dataStrategyConfig = { + interval: config.pullStrategyInterval, + endpoint: "", + }; - if (screenPath) { - dataStrategyConfig.entryPoint = screenPath; - } + if (screenPath) { + dataStrategyConfig.entryPoint = screenPath; + } - this.dataSync = new DataSync(dataStrategyConfig); - this.dataSync.start(); + this.dataSync = new DataSync(dataStrategyConfig); + this.dataSync.start(); + }); } /** diff --git a/assets/client/service/release-service.js b/assets/client/service/release-service.js index 1e7389e6..731a7d14 100644 --- a/assets/client/service/release-service.js +++ b/assets/client/service/release-service.js @@ -1,5 +1,5 @@ import ReleaseLoader from "../util/release-loader"; -import ConfigLoader from "../../shared/config-loader"; +import ClientConfigLoader from "../client-config-loader.js"; import defaults from "../util/defaults"; import idFromPath from "../util/id-from-path"; import appStorage from "../util/app-storage"; @@ -70,13 +70,13 @@ class ReleaseService { }; startReleaseCheck = () => { - const config = ConfigLoader.getConfig(); - - this.releaseCheckInterval = setInterval( - this.checkForNewRelease, - config.releaseTimestampIntervalTimeout ?? - defaults.releaseTimestampIntervalTimeoutDefault, - ); + ClientConfigLoader.loadConfig().then((config) => { + this.releaseCheckInterval = setInterval( + this.checkForNewRelease, + config.releaseTimestampIntervalTimeout ?? + defaults.releaseTimestampIntervalTimeoutDefault, + ); + }); }; stopReleaseCheck = () => { diff --git a/assets/client/service/schedule-service.js b/assets/client/service/schedule-service.js index dbb95bfd..fddbcff2 100644 --- a/assets/client/service/schedule-service.js +++ b/assets/client/service/schedule-service.js @@ -4,7 +4,7 @@ import Md5 from "crypto-js/md5"; import Base64 from "crypto-js/enc-base64"; import isPublished from "../util/isPublished"; import logger from "../logger/logger"; -import ConfigLoader from "../../shared/config-loader"; +import ClientConfigLoader from "../client-config-loader.js"; import ScheduleUtils from "../util/schedule"; /** @@ -94,20 +94,21 @@ class ScheduleService { const { intervals } = this; if (!Object.prototype.hasOwnProperty.call(intervals, regionId)) { - const config = ConfigLoader.getConfig(); - const schedulingInterval = config?.schedulingInterval ?? 60000; - - // Extra check because of async. - if (!Object.prototype.hasOwnProperty.call(intervals, regionId)) { - logger.info( - `registering scheduling interval for region: ${regionId}, with an update rate of ${schedulingInterval}`, - ); - - this.intervals[regionId] = setInterval( - () => this.checkScheduling(regionId), - schedulingInterval, - ); - } + ClientConfigLoader.loadConfig().then((config) => { + const schedulingInterval = config?.schedulingInterval ?? 60000; + + // Extra check because of async. + if (!Object.prototype.hasOwnProperty.call(intervals, regionId)) { + logger.info( + `registering scheduling interval for region: ${regionId}, with an update rate of ${schedulingInterval}`, + ); + + this.intervals[regionId] = setInterval( + () => this.checkScheduling(regionId), + schedulingInterval, + ); + } + }); } if (newContent) { diff --git a/assets/client/service/tenant-service.js b/assets/client/service/tenant-service.js index ba7e8af3..66512e76 100644 --- a/assets/client/service/tenant-service.js +++ b/assets/client/service/tenant-service.js @@ -1,4 +1,3 @@ -import ConfigLoader from "../../shared/config-loader"; import appStorage from "../util/app-storage"; class TenantService { diff --git a/assets/client/service/token-service.js b/assets/client/service/token-service.js index 011708e8..5d80706f 100644 --- a/assets/client/service/token-service.js +++ b/assets/client/service/token-service.js @@ -1,6 +1,6 @@ import logger from "../logger/logger"; import appStorage from "../util/app-storage"; -import ConfigLoader from "../../shared/config-loader"; +import ClientConfigLoader from "../client-config-loader.js"; import defaults from "../util/defaults"; import statusService from "./status-service"; import constants from "../util/constants"; @@ -219,13 +219,13 @@ class TokenService { }; startRefreshing = () => { - const config = ConfigLoader.getConfig(); - - // Start refresh token interval. - this.refreshInterval = setInterval( - this.ensureFreshToken, - config.refreshTokenTimeout ?? defaults.refreshTokenTimeoutDefault, - ); + ClientConfigLoader.loadConfig().then((config) => { + // Start refresh token interval. + this.refreshInterval = setInterval( + this.ensureFreshToken, + config.refreshTokenTimeout ?? defaults.refreshTokenTimeoutDefault, + ); + }); }; stopRefreshing = () => { diff --git a/assets/client/util/release-loader.js b/assets/client/util/release-loader.js index 1b3f6bd1..e6ec48bb 100644 --- a/assets/client/util/release-loader.js +++ b/assets/client/util/release-loader.js @@ -8,7 +8,7 @@ export default class ReleaseLoader { .then((response) => response.json()) .catch((err) => { /* eslint-disable-next-line no-console */ - console.error("Could not find release.json. Returning defaults.", err); + console.warn("Could not find release.json. Returning defaults.", err); return { releaseTimestamp: null, diff --git a/assets/shared/config-loader.js b/assets/shared/config-loader.js deleted file mode 100644 index e1aac43a..00000000 --- a/assets/shared/config-loader.js +++ /dev/null @@ -1,9 +0,0 @@ -const ConfigLoader = { - getConfig() { - return DISPLAY_CONFIG; - }, -}; - -Object.freeze(ConfigLoader); - -export default ConfigLoader; diff --git a/assets/tests/admin/admin-app.spec.js b/assets/tests/admin/admin-app.spec.js deleted file mode 100644 index 32bceda7..00000000 --- a/assets/tests/admin/admin-app.spec.js +++ /dev/null @@ -1,59 +0,0 @@ -import { test, expect } from "@playwright/test"; - -test("Basic app runs", async ({ page }) => { - await page.goto( - "/admin/slide/list?published=all&page=1&order=asc&sort=title", - ); - - await page.route("**/slides*", async (route) => { - const json = { - "hydra:member": [ - { - "@id": "/v2/slides/0086TQQC671WHA1S150MMF1Q3T", - title: "Title on slide", - description: "description", - created: "1978-12-11T09:47:36.000Z", - modified: "2021-12-09T12:01:33.000Z", - modifiedBy: "", - createdBy: "", - templateInfo: { - "@id": "/v2/templates/00MWCNKC4P0X5C0AT70E741E2V", - }, - theme: "", - onPlaylists: ["/v2/playlists/00S7ZQK8Y90R351YES1DJN0RKR"], - duration: 70592, - published: { - from: null, - to: "1989-08-28T18:14:52.000Z", - }, - }, - ], - }; - await route.fulfill({ json }); - }); - await page.route("**/token", async (route) => { - const json = { - token: "1", - refresh_token: "2", - tenants: [ - { - tenantKey: "ABC", - title: "ABC Tenant", - description: "Description", - roles: ["ROLE_ADMIN"], - }, - ], - user: { - fullname: "John Doe", - email: "johndoe@example.com", - }, - }; - await route.fulfill({ json }); - }); - - await expect(page).toHaveTitle(/OS2Display Admin/); - await page.getByLabel("Email").fill("johndoe@example.com"); - await page.getByLabel("Kodeord").fill("password"); - await page.locator("#login").click(); - await expect(page.getByText("Title on slide")).toBeVisible(); -}); diff --git a/assets/tests/admin/admin-campaign.spec.js b/assets/tests/admin/admin-campaign.spec.js index f607a6ba..fcc15ee2 100644 --- a/assets/tests/admin/admin-campaign.spec.js +++ b/assets/tests/admin/admin-campaign.spec.js @@ -1,317 +1,40 @@ import { test, expect } from "@playwright/test"; +import { + fulfillDataRoute, + fulfillEmptyRoutes, + beforeEachTest, + loginTest, +} from "./test-helper.js"; +import { slidesJson1 } from "./data-fixtures.js"; test.describe("Campaign pages work", () => { test.beforeEach(async ({ page }) => { - await page.goto("/admin/campaign/create"); - await page.route("**/slides*", async (route) => { - const json = { - "@id": "/v2/slides", - "hydra:member": [], - "hydra:totalItems": 100, - "hydra:view": { - "@id": "/v2/slides?itemsPerPage=0\u0026title=", - "@type": "hydra:PartialCollectionView", - }, - }; - await route.fulfill({ json }); - }); + await beforeEachTest(page); + }); + + test.beforeEach(async ({ page }) => { + await loginTest(page); - await page.route("**/token", async (route) => { - const json = { - token: "1", - refresh_token: "2", - tenants: [ - { - tenantKey: "ABC", - title: "ABC Tenant", - description: "Description", - roles: ["ROLE_ADMIN"], - }, - ], - user: { - fullname: "John Doe", - email: "johndoe@example.com", - }, - }; - await route.fulfill({ json }); - }); + await fulfillEmptyRoutes(page, [ + "**/playlists*", + "**/screens*", + "**/screen-groups*", + ]); - await expect(page).toHaveTitle(/OS2Display Admin/); - await page.getByLabel("Email").fill("johndoe@example.com"); - await page.getByLabel("Kodeord").fill("password"); - await page.locator("#login").click(); + await page.locator(".sidebar-nav .nav-link").getByText("Kampagner").click(); + await expect(page.locator("h1").getByText("Kampagner")).toBeVisible(); + await page.getByText("Opret ny kampagne").click(); }); - test("It loads create campaign page", async ({ page }) => { - await expect(page.locator("#save_playlist")).toBeVisible(); + test("It cancels create campaign", async ({ page }) => { + await expect(page.locator("#cancel_playlist")).toBeVisible(); + await page.locator("#cancel_playlist").click(); + await expect(page.locator("#cancel_playlist")).not.toBeVisible(); }); test("It removes slide", async ({ page }) => { // Intercept slides in dropdown - await page.route("**/slides*", async (route) => { - const json = { - "@id": "/v2/slides", - "hydra:member": [ - { - "@type": "Slide", - "@id": "/v2/slides/00015Y0ZVC18N407JD07SM0YCF", - title: "Odio quidem ab dolores dolores.", - description: - "Accusamus odio atque numquam sunt asperiores ab. Consequatur similique amet velit sit qui doloremque dicta. Ducimus repellat facere odit quia deserunt id quos.", - created: "1970-01-15T17:36:43.000Z", - modified: "2021-12-09T12:01:33.000Z", - modifiedBy: "", - createdBy: "", - templateInfo: { - "@id": "/v2/templates/000YR9PMQC0GMC1TP90V9N07WX", - options: [], - }, - theme: "/v2/themes/01FPFH3WX93S4575W6Q9T8K0Y8", - onPlaylists: [], - duration: 107879, - published: { - from: null, - to: null, - }, - media: [ - "/v2/media/00042YZWK214MP01NA1GF517Q2", - "/v2/media/00TET3FF6K1Q011N5S12621E4H", - "/v2/media/01DCA32QJY1BH600BV2H140JDK", - ], - content: [], - }, - { - "@type": "Slide", - "@id": "/v2/slides/000E7VDT9E0GEJ0W5X040T1CB1", - title: "Sed ex quo minus doloremque possimus.", - description: - "Ipsum quo ipsam rerum ullam labore fugit ut. Repellendus a iusto dolore veritatis. Aut vero assumenda voluptates tempore doloremque expedita pariatur. Sint ducimus qui ducimus asperiores cum.", - created: "1970-06-27T00:53:51.000Z", - modified: "2021-12-09T12:01:33.000Z", - modifiedBy: "", - createdBy: "", - templateInfo: { - "@id": "/v2/templates/01FGC8EXSE1KCC1PTR0NHB0H3R", - options: [], - }, - theme: "", - onPlaylists: [], - duration: 80335, - published: { - from: "2021-03-19T22:20:54.000Z", - to: "2021-12-28T06:13:08.000Z", - }, - media: [ - "/v2/media/009H64MSPN1HEH0DTV2DEV085B", - "/v2/media/00SC0JP6PV2QYS06R70SS31K68", - ], - content: [], - }, - { - "@type": "Slide", - "@id": "/v2/slides/001M5VMMV81A6Q1KN10QY90HKE", - title: "Maxime numquam ducimus quos non.", - description: - "Aut ex id earum unde aut itaque vero id. Sunt praesentium harum vel autem.", - created: "1971-10-11T12:15:35.000Z", - modified: "2021-12-09T12:01:33.000Z", - modifiedBy: "", - createdBy: "", - templateInfo: { - "@id": "/v2/templates/000BGWFMBS15N807E60HP91JCX", - options: [], - }, - theme: "", - onPlaylists: [], - duration: 21254, - published: { - from: null, - to: null, - }, - media: ["/v2/media/00YMKGY3FM106Q0SRV077G0KEX"], - content: [], - }, - { - "@type": "Slide", - "@id": "/v2/slides/001M9W40CC0DQE02DR0PS41J7X", - title: "Est doloremque culpa et facere.", - description: - "Eos voluptatem sint fugiat magni omnis aut ut. Odit quod non rerum dolor. Quis deleniti occaecati perspiciatis et esse dolorum. Impedit sunt dolor dolores.", - created: "1971-10-13T01:40:56.000Z", - modified: "2021-12-09T12:01:33.000Z", - modifiedBy: "", - createdBy: "", - templateInfo: { - "@id": "/v2/templates/000BGWFMBS15N807E60HP91JCX", - options: [], - }, - theme: "", - onPlaylists: [], - duration: 60870, - published: { - from: "2021-02-26T20:12:10.000Z", - to: "2021-06-08T05:44:41.000Z", - }, - media: ["/v2/media/00BBYAKF190NMJ0FH118V91VV7"], - content: [], - }, - { - "@type": "Slide", - "@id": "/v2/slides/001W87XHKC0CX10P4215RV2K9B", - title: "Occaecati temporibus dolore maxime tenetur.", - description: - "Qui rem inventore non labore quam nihil in. Sunt rerum consequatur possimus cupiditate iure quo sit ratione. Et quis mollitia et.", - created: "1972-01-19T20:34:13.000Z", - modified: "2021-12-09T12:01:33.000Z", - modifiedBy: "", - createdBy: "", - templateInfo: { - "@id": "/v2/templates/002BAP34VD1EHG0E4J0D2Y00JW", - options: [], - }, - theme: "", - onPlaylists: [], - duration: 75535, - published: { - from: null, - to: "1996-02-16T00:54:17.000Z", - }, - media: ["/v2/media/0027FWF7Y014RG0KW9053S1AX6"], - content: [], - }, - { - "@type": "Slide", - "@id": "/v2/slides/0021MQ8MWP0MXK1NXB1J5918PM", - title: "Excepturi sed qui.", - description: - "Expedita numquam sunt autem nostrum. Sed eos molestiae earum natus. Rerum consectetur et eius illo qui sunt sapiente. Est dolore veritatis cupiditate occaecati.", - created: "1972-03-26T20:11:47.000Z", - modified: "2021-12-09T12:01:33.000Z", - modifiedBy: "", - createdBy: "", - templateInfo: { - "@id": "/v2/templates/017BG9P0E0103F0TFS17FM016M", - options: [], - }, - theme: "", - onPlaylists: [], - duration: 92829, - published: { - from: "2021-12-29T03:25:23.000Z", - to: null, - }, - media: ["/v2/media/001AX5W2S909NW0K5A0NVE0NS6"], - content: [], - }, - { - "@type": "Slide", - "@id": "/v2/slides/002T3E98DP1KK410PC0F2P037P", - title: "Voluptate aliquid maxime.", - description: - "Veniam labore odit omnis sint. Perferendis amet soluta quo quaerat nihil ex eius error.", - created: "1973-01-24T19:40:11.000Z", - modified: "2021-12-09T12:01:33.000Z", - modifiedBy: "", - createdBy: "", - templateInfo: { - "@id": "/v2/templates/002BAP34VD1EHG0E4J0D2Y00JW", - options: [], - }, - theme: "/v2/themes/01FPFH3WX93S4575W6Q9T8K0YN", - onPlaylists: [], - duration: 41589, - published: { - from: null, - to: "1989-10-31T03:15:44.000Z", - }, - media: [ - "/v2/media/00CX9N9EJE10WT1PVM10G51N13", - "/v2/media/016HWRGVWJ170F1AF2099T13JW", - "/v2/media/01DCA32QJY1BH600BV2H140JDK", - ], - content: [], - }, - { - "@type": "Slide", - "@id": "/v2/slides/00367HAGPF0XZA1SDN1ECH1NZX", - title: "Non ut nobis reprehenderit pariatur.", - description: - "Iste asperiores reprehenderit et mollitia et. Molestias iusto repudiandae a qui accusantium nam vel nesciunt.", - created: "1973-06-24T12:58:37.000Z", - modified: "2021-12-09T12:01:33.000Z", - modifiedBy: "", - createdBy: "", - templateInfo: { - "@id": "/v2/templates/000YR9PMQC0GMC1TP90V9N07WX", - options: [], - }, - theme: "", - onPlaylists: [], - duration: 106091, - published: { - from: "2022-01-11T14:56:13.000Z", - to: "2022-02-05T09:10:20.000Z", - }, - media: ["/v2/media/00F1M5J6BY1GS517RP1T1B1306"], - content: [], - }, - { - "@type": "Slide", - "@id": "/v2/slides/0039BTMNG61RJ606WT1QYN1X2K", - title: "Iusto aut et dicta neque.", - description: - "Nihil esse quisquam aut aliquid velit vitae. Dignissimos sit eos voluptatem corporis qui. Maxime qui eaque magni dolor et. Dolorem est velit qui ratione iure provident architecto.", - created: "1973-08-02T11:45:30.000Z", - modified: "2021-12-09T12:01:33.000Z", - modifiedBy: "", - createdBy: "", - templateInfo: { - "@id": "/v2/templates/016MHSNKCH1PQW1VY615JC19Y3", - options: [], - }, - theme: "/v2/themes/01FPFH3WX93S4575W6Q9T8K0YB", - onPlaylists: [], - duration: 79809, - published: { - from: "2021-08-10T06:26:30.000Z", - to: "2021-08-12T15:26:21.000Z", - }, - media: ["/v2/media/011ZBTXPF8123R1BA31CQR18HA"], - content: [], - }, - { - "@type": "Slide", - "@id": "/v2/slides/00446YF1RP0KZH0WQK1QJM1S4T", - title: "Inventore non nisi odit voluptatem et.", - description: - "Et in eum fugit culpa mollitia sunt. Et cupiditate molestias quia sapiente sint maxime qui. Beatae ad quod sed provident quas expedita exercitationem enim. Pariatur illo nam consequatur.", - created: "1974-07-02T03:19:57.000Z", - modified: "2021-12-09T12:01:33.000Z", - modifiedBy: "", - createdBy: "", - templateInfo: { - "@id": "/v2/templates/017BG9P0E0103F0TFS17FM016M", - options: [], - }, - theme: "/v2/themes/01FPFH3WXAX8JMJTQHBV2BYEDM", - onPlaylists: [], - duration: 37983, - published: { - from: "2022-01-24T16:30:24.000Z", - to: "2022-02-05T09:19:31.000Z", - }, - media: [ - "/v2/media/0010X8D6JJ03G50T1J1FCW1XH6", - "/v2/media/00F1M5J6BY1GS517RP1T1B1306", - "/v2/media/00KXYB7Z291JXC1SY30G161HQD", - ], - content: [], - }, - ], - "hydra:totalItems": 60, - }; - await route.fulfill({ json }); - }); + await fulfillDataRoute(page, "**/slides*", slidesJson1); // Pick slide await page @@ -339,19 +62,9 @@ test.describe("Campaign pages work", () => { ).toHaveCount(6); // Remove slide - await page - .locator("#slides-section") - .locator("tbody") - .locator(".remove-from-list") - .click(); - await expect( - page.locator("#slides-section").locator("tbody"), - ).not.toBeVisible(); - }); + await page.locator(".remove-from-list").click(); - test("It cancels create campaign", async ({ page }) => { - await expect(page.locator("#cancel_playlist")).toBeVisible(); - await page.locator("#cancel_playlist").click(); - await expect(page.locator("#cancel_playlist")).not.toBeVisible(); + // See that slides section is removed. + await expect(page.getByText("Afspilningsrækkefølge")).not.toBeVisible(); }); }); diff --git a/assets/tests/admin/admin-content-string.spec.js b/assets/tests/admin/admin-content-string.spec.js index eaee3469..15c122db 100644 --- a/assets/tests/admin/admin-content-string.spec.js +++ b/assets/tests/admin/admin-content-string.spec.js @@ -16,6 +16,7 @@ test.describe("Content string", () => { ), ).toBe("test, hest or test"); }); + test("It creates a string: 'test'", async ({ page }) => { expect(contentString([{ name: "test" }], "or")).toBe("test"); }); diff --git a/assets/tests/admin/admin-feed-sources.spec.js b/assets/tests/admin/admin-feed-sources.spec.js index d8539cc2..263cb1d3 100644 --- a/assets/tests/admin/admin-feed-sources.spec.js +++ b/assets/tests/admin/admin-feed-sources.spec.js @@ -1,238 +1,46 @@ import { test, expect } from "@playwright/test"; +import { + errorJson, + feedSourcesJson, + feedSourcesJson2, + feedSourceSingleJson, +} from "./data-fixtures.js"; +import { + fulfillDataRoute, + fulfillEmptyRoutes, + beforeEachTest, + loginTest, +} from "./test-helper.js"; -const feedSourcesJson = { - "@context": "/contexts/FeedSource", - "@id": "/v2/feed-sources", - "@type": "hydra:Collection", - "hydra:totalItems": 5, - "hydra:member": [ - { - "@id": "/v2/feed-sources/01JBBP48CS9CV80XRWRP8CAETJ", - "@type": "FeedSource", - title: "test 2", - description: "test 2", - outputType: "", - feedType: "test 2", - secrets: [], - feeds: [], - admin: [], - supportedFeedOutputType: "test 2", - modifiedBy: "admin@example.com", - createdBy: "admin@example.com", - id: "01JBBP48CS9CV80XRWRP8CAETJ", - created: "2024-10-29T09:26:25.000Z", - modified: "2024-10-29T09:26:25.000Z", - }, - { - "@id": "/v2/feed-sources/01JB9MSQEH75HC3GG75XCVP2WH", - "@type": "FeedSource", - title: "Ny datakilde test 3", - description: "Ny datakilde test 3", - outputType: "", - feedType: "App\\Feed\\RssFeedType", - secrets: [], - feeds: [ - "/v2/feeds/01JB9R7EPN9NPW117C22NY31KH", - "/v2/feeds/01JBBQMF72W2V36TWF6VXFA5Z7", - ], - admin: [ - { - key: "rss-url", - input: "input", - name: "url", - type: "url", - label: "Kilde", - helpText: "Her kan du skrive rss kilden", - formGroupClasses: "col-md-6", - }, - { - key: "rss-number-of-entries", - input: "input", - name: "numberOfEntries", - type: "number", - label: "Antal indgange", - helpText: - "Her kan du skrive, hvor mange indgange, der maksimalt skal vises.", - formGroupClasses: "col-md-6 mb-3", - }, - { - key: "rss-entry-duration", - input: "input", - name: "entryDuration", - type: "number", - label: "Varighed pr. indgang (i sekunder)", - helpText: "Her skal du skrive varigheden pr. indgang.", - formGroupClasses: "col-md-6 mb-3", - }, - ], - supportedFeedOutputType: "rss", - modifiedBy: "admin@example.com", - createdBy: "admin@example.com", - id: "01JB9MSQEH75HC3GG75XCVP2WH", - created: "2024-10-28T14:24:43.000Z", - modified: "2024-10-28T15:23:28.000Z", - }, - { - "@id": "/v2/feed-sources/01JB1DH8G4CXKGX5JRTYDHDPSP", - "@type": "FeedSource", - title: "Calendar datakilde test", - description: "test", - outputType: "", - feedType: "App\\Feed\\CalendarApiFeedType", - secrets: [], - feeds: [], - admin: [], - supportedFeedOutputType: "calendar", - modifiedBy: "", - createdBy: "", - id: "01JB1DH8G4CXKGX5JRTYDHDPSP", - created: "2024-10-25T10:43:50.000Z", - modified: "2024-10-25T10:43:50.000Z", - }, - { - "@id": "/v2/feed-sources/01J711Y2Q01VBJ1Y7A1HZQ0ZN6", - "@type": "FeedSource", - title: "feed_source_abc_notified", - description: - "Ut magnam veritatis velit ut doloribus id. Consequatur ut ipsum exercitationem aliquam laudantium voluptate voluptates perspiciatis. Id occaecati ea rerum facilis molestias et.", - outputType: "", - feedType: "App\\Feed\\RssFeedType", - secrets: [], - feeds: ["/v2/feeds/01GJD7S1KR10811MTA176C001R"], - admin: [ - { - key: "rss-url", - input: "input", - name: "url", - type: "url", - label: "Kilde", - helpText: "Her kan du skrive rss kilden", - formGroupClasses: "col-md-6", - }, - { - key: "rss-number-of-entries", - input: "input", - name: "numberOfEntries", - type: "number", - label: "Antal indgange", - helpText: - "Her kan du skrive, hvor mange indgange, der maksimalt skal vises.", - formGroupClasses: "col-md-6 mb-3", - }, - { - key: "rss-entry-duration", - input: "input", - name: "entryDuration", - type: "number", - label: "Varighed pr. indgang (i sekunder)", - helpText: "Her skal du skrive varigheden pr. indgang.", - formGroupClasses: "col-md-6 mb-3", - }, - ], - supportedFeedOutputType: "instagram", - modifiedBy: "", - createdBy: "", - id: "01J711Y2Q01VBJ1Y7A1HZQ0ZN6", - created: "2024-09-05T12:18:20.000Z", - modified: "2024-09-17T09:33:12.000Z", - }, - { - "@id": "/v2/feed-sources/01J1H8GVVR1CVJ1SQK0JXN1X4Q", - "@type": "FeedSource", - title: "feed_source_abc_1", - description: - "Totam eos molestias omnis aliquam quia qui voluptas. Non eum nihil ut sunt dolor.", - outputType: "", - feedType: "App\\Feed\\RssFeedType", - secrets: [], - feeds: ["/v2/feeds/01HD49075G0FNY1FNX12VE17K1"], - admin: [ - { - key: "rss-url", - input: "input", - name: "url", - type: "url", - label: "Kilde", - helpText: "Her kan du skrive rss kilden", - formGroupClasses: "col-md-6", - }, - { - key: "rss-number-of-entries", - input: "input", - name: "numberOfEntries", - type: "number", - label: "Antal indgange", - helpText: - "Her kan du skrive, hvor mange indgange, der maksimalt skal vises.", - formGroupClasses: "col-md-6 mb-3", - }, - { - key: "rss-entry-duration", - input: "input", - name: "entryDuration", - type: "number", - label: "Varighed pr. indgang (i sekunder)", - helpText: "Her skal du skrive varigheden pr. indgang.", - formGroupClasses: "col-md-6 mb-3", - }, - ], - supportedFeedOutputType: "rss", - modifiedBy: "", - createdBy: "", - id: "01J1H8GVVR1CVJ1SQK0JXN1X4Q", - created: "2024-06-29T05:47:07.000Z", - modified: "2024-10-21T18:01:25.000Z", - }, - ], -}; +test.describe("feed sources", () => { + test.beforeEach(async ({ page }) => { + await beforeEachTest(page); + }); -test.describe("fest", () => { test.beforeEach(async ({ page }) => { - await page.goto("/admin/feed-sources/list"); - await page.route("**/feed-sources*", async (route) => { - await route.fulfill({ json: feedSourcesJson }); - }); - await page.route("**/token", async (route) => { - const json = { - token: "1", - refresh_token: "2", - tenants: [ - { - tenantKey: "ABC", - title: "ABC Tenant", - description: "Description", - roles: ["ROLE_ADMIN"], - }, - ], - user: { - fullname: "John Doe", - email: "johndoe@example.com", - }, - }; - await route.fulfill({ json }); - }); - await expect(page).toHaveTitle(/OS2Display Admin/); - await page.getByLabel("Email").fill("admin@example.com"); - await page.getByLabel("Kodeord").fill("password"); - await page.locator("#login").click(); + await loginTest(page); + + await fulfillDataRoute(page, "**/feed-sources*", feedSourcesJson); + + await page + .locator(".sidebar-nav .nav-link") + .getByText("Datakilder") + .click(); + + await fulfillEmptyRoutes(page, ["**/slides*"]); + + await expect(page.locator("h1").getByText("Datakilder")).toBeVisible(); }); test("It loads create datakilde page", async ({ page }) => { - page.getByText("Opret ny datakilde").click(); + await page.getByText("Opret ny datakilde").click(); await expect(page.locator("#save")).toBeVisible(); }); test("It display error toast on save error", async ({ page }) => { - await page.route("**/feed-sources", async (route) => { - const json = { - "@context": "/contexts/Error", - "@type": "hydra:Error", - "hydra:title": "An error occurred", - "hydra:description": "An error occurred", - }; - await route.fulfill({ status: 500, json }); - }); - page.getByText("Opret ny datakilde").click(); + await fulfillDataRoute(page, "**/feed-sources*", errorJson, 500); + + await page.getByText("Opret ny datakilde").click(); // Displays error toast and stays on page await expect( @@ -251,44 +59,14 @@ test.describe("fest", () => { ).toBeVisible(); await expect(page).toHaveURL(/feed-sources\/create/); }); + test("Cancel create datakilde", async ({ page }) => { - page.getByText("Opret ny datakilde").click(); + await page.getByText("Opret ny datakilde").click(); + await expect(page.locator("#cancel")).toBeVisible(); await page.locator("#cancel").click(); await expect(page.locator("#cancel")).not.toBeVisible(); }); -}); - -test.describe("datakilde list work", () => { - test.beforeEach(async ({ page }) => { - await page.goto("/admin/feed-sources/list"); - await page.route("**/token", async (route) => { - const json = { - token: "1", - refresh_token: "2", - tenants: [ - { - tenantKey: "ABC", - title: "ABC Tenant", - description: "Description", - roles: ["ROLE_ADMIN"], - }, - ], - user: { - fullname: "John Doe", - email: "johndoe@example.com", - }, - }; - await route.fulfill({ json }); - }); - await page.route("**/feed-sources*", async (route) => { - await route.fulfill({ json: feedSourcesJson }); - }); - await expect(page).toHaveTitle(/OS2Display Admin/); - await page.getByLabel("Email").fill("johndoe@example.com"); - await page.getByLabel("Kodeord").fill("password"); - await page.locator("#login").click(); - }); test("It loads datakilde list", async ({ page }) => { await expect(page.locator("table").locator("tbody")).not.toBeEmpty(); @@ -298,133 +76,12 @@ test.describe("datakilde list work", () => { test("It goes to edit", async ({ page }) => { await expect(page.locator("#feed-sourceTitle")).not.toBeVisible(); - await page.route("**/feed-sources*", async (route) => { - const json = { - "@context": "/contexts/FeedSource", - "@id": "/v2/feed-sources", - "@type": "hydra:Collection", - "hydra:totalItems": 2, - "hydra:member": [ - { - "@id": "/v2/feed-sources/01J711Y2Q01VBJ1Y7A1HZQ0ZN6", - "@type": "FeedSource", - title: "feed_source_abc_notified", - description: - "Ut magnam veritatis velit ut doloribus id. Consequatur ut ipsum exercitationem aliquam laudantium voluptate voluptates perspiciatis. Id occaecati ea rerum facilis molestias et.", - outputType: "", - feedType: "App\\Feed\\RssFeedType", - secrets: [], - feeds: ["/v2/feeds/01GJD7S1KR10811MTA176C001R"], - admin: [ - { - key: "rss-url", - input: "input", - name: "url", - type: "url", - label: "Kilde", - helpText: "Her kan du skrive rss kilden", - formGroupClasses: "col-md-6", - }, - { - key: "rss-number-of-entries", - input: "input", - name: "numberOfEntries", - type: "number", - label: "Antal indgange", - helpText: - "Her kan du skrive, hvor mange indgange, der maksimalt skal vises.", - formGroupClasses: "col-md-6 mb-3", - }, - { - key: "rss-entry-duration", - input: "input", - name: "entryDuration", - type: "number", - label: "Varighed pr. indgang (i sekunder)", - helpText: "Her skal du skrive varigheden pr. indgang.", - formGroupClasses: "col-md-6 mb-3", - }, - ], - supportedFeedOutputType: "instagram", - modifiedBy: "", - createdBy: "", - id: "01J711Y2Q01VBJ1Y7A1HZQ0ZN6", - created: "2024-09-05T12:18:20.000Z", - modified: "2024-09-17T09:33:12.000Z", - }, - { - "@id": "/v2/feed-sources/01J1H8GVVR1CVJ1SQK0JXN1X4Q", - "@type": "FeedSource", - title: "feed_source_abc_1", - description: - "Totam eos molestias omnis aliquam quia qui voluptas. Non eum nihil ut sunt dolor.", - outputType: "", - feedType: "App\\Feed\\RssFeedType", - secrets: [], - feeds: ["/v2/feeds/01HD49075G0FNY1FNX12VE17K1"], - admin: [ - { - key: "rss-url", - input: "input", - name: "url", - type: "url", - label: "Kilde", - helpText: "Her kan du skrive rss kilden", - formGroupClasses: "col-md-6", - }, - { - key: "rss-number-of-entries", - input: "input", - name: "numberOfEntries", - type: "number", - label: "Antal indgange", - helpText: - "Her kan du skrive, hvor mange indgange, der maksimalt skal vises.", - formGroupClasses: "col-md-6 mb-3", - }, - { - key: "rss-entry-duration", - input: "input", - name: "entryDuration", - type: "number", - label: "Varighed pr. indgang (i sekunder)", - helpText: "Her skal du skrive varigheden pr. indgang.", - formGroupClasses: "col-md-6 mb-3", - }, - ], - supportedFeedOutputType: "rss", - modifiedBy: "", - createdBy: "", - id: "01J1H8GVVR1CVJ1SQK0JXN1X4Q", - created: "2024-06-29T05:47:07.000Z", - modified: "2024-10-21T18:01:25.000Z", - }, - ], - }; - await route.fulfill({ json }); - }); - - await page.route("**/feed-sources/*", async (route) => { - const json = { - "@id": "/v2/feed-sources/01J711Y2Q01VBJ1Y7A1HZQ0ZN6", - "@type": "FeedSource", - title: "feed_source_abc_notified", - description: - "Ut magnam veritatis velit ut doloribus id. Consequatur ut ipsum exercitationem aliquam laudantium voluptate voluptates perspiciatis. Id occaecati ea rerum facilis molestias et.", - outputType: "", - feedType: "App\\Feed\\RssFeedType", - secrets: [], - feeds: ["/v2/feeds/01GJD7S1KR10811MTA176C001R"], - supportedFeedOutputType: "instagram", - modifiedBy: "", - createdBy: "", - id: "01J711Y2Q01VBJ1Y7A1HZQ0ZN6", - created: "2024-09-05T12:18:20.000Z", - modified: "2024-09-17T09:33:12.000Z", - }; - - await route.fulfill({ json }); - }); + await fulfillDataRoute(page, "**/feed-sources*", feedSourcesJson2); + await fulfillDataRoute( + page, + "**/feed-sources/01JBBP48CS9CV80XRWRP8CAETJ", + feedSourceSingleJson, + ); await page.locator("tbody").locator("tr td a").first().click(); await expect(page.locator("#feed-sourceTitle")).toBeVisible(); diff --git a/assets/tests/admin/admin-login.spec.js b/assets/tests/admin/admin-login.spec.js index 7a398b12..3f141b4e 100644 --- a/assets/tests/admin/admin-login.spec.js +++ b/assets/tests/admin/admin-login.spec.js @@ -1,94 +1,62 @@ import { test, expect } from "@playwright/test"; +import { + accessConfigJson, + adminConfigJson, + emptyJson, + tokenAdminJson, + tokenEditorJson, + tokenTenantsJson, +} from "./data-fixtures.js"; +import { + fulfillDataRoute, + fulfillEmptyRoutes, + beforeEachTest, +} from "./test-helper.js"; test.describe("Login works", () => { - test("Login one tenant works", async ({ page }) => { - await page.route("**/token", async (route) => { - const json = { - token: "1", - refresh_token: "2", - tenants: [ - { - tenantKey: "ABC", - title: "ABC Tenant", - description: "Description", - roles: ["ROLE_ADMIN"], - }, - ], - user: { - fullname: "John Doe", - email: "johndoe@example.com", - }, - }; - await route.fulfill({ json }); + test.beforeEach(async ({ page }) => { + await page.route("**/access-config.json", async (route) => { + await route.fulfill({ json: accessConfigJson }); + }); + + await page.route("**/config/admin", async (route) => { + await route.fulfill({ json: adminConfigJson }); }); + }); + test("Login one tenant works", async ({ page }) => { await page.goto("/admin/playlist/list"); + + await fulfillEmptyRoutes(page, ["**/playlists*"]); + + await fulfillDataRoute(page, "**/token", tokenAdminJson); + await page.locator("#login").click(); await expect(page.locator(".name")).toHaveText("John Doe"); }); test("Login three tenant works", async ({ page }) => { - await page.route("**/token", async (route) => { - const json = { - token: "1", - refresh_token: "2", - tenants: [ - { - tenantKey: "ABC", - title: "ABC Tenant", - description: "Nulla quam ipsam voluptatem cupiditate.", - roles: ["ROLE_ADMIN"], - }, - { - tenantKey: "DEF", - title: "DEF Tenant", - description: "Inventore sed libero et.", - roles: ["ROLE_ADMIN"], - }, - { - tenantKey: "XYZ", - title: "XYC Tenant", - description: "Itaque quibusdam tempora velit porro ut velit.", - roles: ["ROLE_ADMIN"], - }, - ], - user: { - fullname: "John Doe", - email: "johndoe@example.com", - }, - }; - await route.fulfill({ json }); - }); - await page.goto("/admin/group/list"); + await page.goto("/admin/playlist/list"); + + await fulfillEmptyRoutes(page, ["**/playlists*"]); + + await fulfillDataRoute(page, "**/token", tokenTenantsJson); + await page.locator("#login").click(); + // Expect dropdown with tenants await expect(page.locator(".dropdown-container")).toBeVisible(); }); test("Login with tenant that has role editor", async ({ page }) => { await page.goto("/admin/playlist/list"); - await page.route("**/token", async (route) => { - const json = { - token: "1", - refresh_token: "2", - tenants: [ - { - tenantKey: "ABC", - title: "ABC Tenant", - description: "Description", - roles: ["ROLE_EDITOR"], - }, - ], - user: { - fullname: "John Doe", - email: "johndoe@example.com", - }, - }; - await route.fulfill({ json }); - }); - await page.goto("/admin/group/list"); + await fulfillEmptyRoutes(page, ["**/playlists*"]); + + await fulfillDataRoute(page, "**/token", tokenEditorJson); + await page.locator("#login").click(); + await expect(page.locator(".name")).toHaveText("John Doe"); await expect(page.locator(".sidebar-nav").locator(".nav-item")).toHaveCount( 4, @@ -98,28 +66,12 @@ test.describe("Login works", () => { test("Role editor should not be able to visit restricted route", async ({ page, }) => { - await page.goto("/admin/playlist/list"); - await page.route("**/token", async (route) => { - const json = { - token: "1", - refresh_token: "2", - tenants: [ - { - tenantKey: "ABC", - title: "ABC Tenant", - description: "Description", - roles: ["ROLE_EDITOR"], - }, - ], - user: { - fullname: "John Doe", - email: "johndoe@example.com", - }, - }; - await route.fulfill({ json }); - }); await page.goto("/admin/shared/list"); + + await fulfillDataRoute(page, "**/token", tokenEditorJson); + await page.locator("#login").click(); + await expect(page.locator("main").locator("div")).toHaveText( "Du har ikke adgang til denne side", ); diff --git a/assets/tests/admin/admin-media.spec.js b/assets/tests/admin/admin-media.spec.js index 06c932d6..4fec028b 100644 --- a/assets/tests/admin/admin-media.spec.js +++ b/assets/tests/admin/admin-media.spec.js @@ -1,89 +1,18 @@ import { test, expect } from "@playwright/test"; +import { fulfillDataRoute, beforeEachTest, loginTest } from "./test-helper.js"; +import { mediaListJson } from "./data-fixtures.js"; test.describe("media list tests", () => { test.beforeEach(async ({ page }) => { - await page.goto("/admin/media/list"); - await page.route("**/media*", async (route) => { - const json = { - "@context": "/contexts/Media", - "@id": "/v2/media", - "@type": "hydra:Collection", - "hydra:member": [ - { - "@type": "Media", - "@id": "/v2/media/001AG48FJC1NVA1EW20TSN13BP", - title: "Laudantium aut exercitationem rerum itaque unde.", - description: - "Quia ut iusto dolores reiciendis animi. Magnam aut ut officiis quae. Nostrum magni et dolore dignissimos in totam qui et.", - license: "Attribution-NonCommercial-NoDerivs License", - created: "1971-06-13T05:21:39+01:00", - modified: "2021-12-09T12:01:34+01:00", - modifiedBy: "", - createdBy: "", - media: [], - assets: { - type: "image/jpeg", - uri: "http://api-display-admin-client.local.itkdev.dk/media/test_3.jpg", - dimensions: { - height: 3456, - width: 5184, - }, - sha: "5a08dbb7fd3a074ed8659694c09cdb94fdb16cb1", - size: 8945324, - }, - }, - { - "@type": "Media", - "@id": "/v2/media/001AX5W2S909NW0K5A0NVE0NS6", - title: "Ut eos illum quod.", - description: - "Et id est illum veniam eos quam placeat. Maxime ab aut aut fugit. Occaecati ut ea et occaecati repellendus amet. Quia consequuntur quod vel deserunt maiores.", - license: "Attribution-NoDerivs License", - created: "1971-06-18T06:59:58+01:00", - modified: "2021-12-09T12:01:34+01:00", - modifiedBy: "", - createdBy: "", - media: [], - assets: { - type: "image/jpeg", - uri: "http://api-display-admin-client.local.itkdev.dk/media/test_2.jpg", - dimensions: { - height: 2592, - width: 3888, - }, - sha: "0654506b260c33544d39e5613716ef112ab38c7c", - size: 4855058, - }, - }, - ], - "hydra:totalItems": 100, - }; - await route.fulfill({ json }); - }); - await page.route("**/token", async (route) => { - const json = { - token: "1", - refresh_token: "2", - tenants: [ - { - tenantKey: "ABC", - title: "ABC Tenant", - description: "Description", - roles: ["ROLE_ADMIN"], - }, - ], - user: { - fullname: "John Doe", - email: "johndoe@example.com", - }, - }; - await route.fulfill({ json }); - }); + await beforeEachTest(page); + }); + + test.beforeEach(async ({ page }) => { + await loginTest(page); + + await fulfillDataRoute(page, "**/media*", mediaListJson); - await expect(page).toHaveTitle(/OS2Display Admin/); - await page.getByLabel("Email").fill("johndoe@example.com"); - await page.getByLabel("Kodeord").fill("password"); - await page.locator("#login").click(); + await page.locator(".sidebar-nav .nav-link").getByText("Medier").click(); }); test("It loads media list", async ({ page }) => { diff --git a/assets/tests/admin/admin-playlist.spec.js b/assets/tests/admin/admin-playlist.spec.js index 21807e4c..d1fc39b5 100644 --- a/assets/tests/admin/admin-playlist.spec.js +++ b/assets/tests/admin/admin-playlist.spec.js @@ -1,41 +1,30 @@ import { test, expect } from "@playwright/test"; +import { + beforeEachTest, + fulfillDataRoute, + fulfillEmptyRoutes, + loginTest, +} from "./test-helper.js"; +import { + emptyJson, + errorJson, + playlistListJson, + onSaveJson, + playlistSingleJson, +} from "./data-fixtures.js"; test.describe("Playlist create tests", () => { test.beforeEach(async ({ page }) => { - await page.goto("/admin/playlist/create"); - await page.route("**/token", async (route) => { - const json = { - token: "1", - refresh_token: "2", - tenants: [ - { - tenantKey: "ABC", - title: "ABC Tenant", - description: "Description", - roles: ["ROLE_ADMIN"], - }, - ], - user: { - fullname: "John Doe", - email: "johndoe@example.com", - }, - }; - await route.fulfill({ json }); - }); - await page.route("**/slides*", async (route) => { - const json = { - "@context": "/contexts/Slide", - "@id": "/v2/slides", - "@type": "hydra:Collection", - "hydra:member": [], - "hydra:totalItems": 100, - }; - await route.fulfill({ json }); - }); - await expect(page).toHaveTitle(/OS2Display Admin/); - await page.getByLabel("Email").fill("johndoe@example.com"); - await page.getByLabel("Kodeord").fill("password"); - await page.locator("#login").click(); + await beforeEachTest(page); + }); + + test.beforeEach(async ({ page }) => { + await loginTest(page); + + await fulfillEmptyRoutes(page, ["**/tenants*"]); + + await page.getByLabel("Tilføj ny spilleliste").first().click(); + await expect(page.getByText("Opret ny spilleliste:")).toBeVisible(); }); test("It loads create playlist page", async ({ page }) => { @@ -43,17 +32,7 @@ test.describe("Playlist create tests", () => { }); test("It redirects on save", async ({ page }) => { - await page.route("**/playlists", async (route) => { - const json = { - title: "A laudantium aspernatur qui.", - description: "Description", - created: "1991-09-10T22:36:56+02:00", - modified: "2021-12-09T12:01:33+01:00", - modifiedBy: "", - createdBy: "", - }; - await route.fulfill({ json }); - }); + await fulfillDataRoute(page, "**/playlists", onSaveJson); // Displays success toast and redirects await expect( @@ -71,15 +50,7 @@ test.describe("Playlist create tests", () => { }); test("It display error toast on save error", async ({ page }) => { - await page.route("**/playlists", async (route) => { - const json = { - "@context": "/contexts/Error", - "@type": "hydra:Error", - "hydra:title": "An error occurred", - "hydra:description": "An error occurred", - }; - await route.fulfill({ status: 500, json }); - }); + await fulfillDataRoute(page, "**/playlists", errorJson, 500); // Displays error toast and stays on page await expect( @@ -108,95 +79,20 @@ test.describe("Playlist create tests", () => { test.describe("Playlist list tests", () => { test.beforeEach(async ({ page }) => { - await page.goto("/admin/playlist/list"); - await page.route("**/playlists*", async (route) => { - const json = { - "@context": "/contexts/Playlist", - "@id": "/v2/playlists", - "@type": "hydra:Collection", - "hydra:member": [ - { - "@type": "Playlist", - "@id": "/v2/playlists/004ZP1XQ1G1MVZ1T0100YN0MPC", - title: "Et consequatur voluptatibus dolore ut ut.", - description: - "Atque maiores nam in occaecati labore labore inventore quo. Enim nemo totam hic. Ut suscipit id sint sed quia.", - schedules: [], - created: "1975-06-08T13:12:49.000Z", - modified: "2022-01-30T15:42:42.000Z", - modifiedBy: "", - createdBy: "", - slides: "/v2/playlists/004ZP1XQ1G1MVZ1T0100YN0MPC/slides", - campaignScreens: ["/v2/screens/00TH1ZRMZC141K1DMB1H7J03CS"], - campaignScreenGroups: [], - isCampaign: true, - published: { - from: "2022-03-23T21:30:21.000Z", - to: "2022-03-25T12:39:29.000Z", - }, - }, - { - "@type": "Playlist", - "@id": "/v2/playlists/007TM6JDGF1ECH07J10ZHY0S7P", - title: "Voluptas molestias nemo et.", - description: - "Aperiam quam sunt quia qui. Iusto ut deserunt veritatis nobis dolorem. Aliquid quo vel quia.", - schedules: [], - created: "1978-07-12T17:43:59.000Z", - modified: "2022-01-30T15:42:42.000Z", - modifiedBy: "", - createdBy: "", - slides: "/v2/playlists/007TM6JDGF1ECH07J10ZHY0S7P/slides", - campaignScreens: [], - campaignScreenGroups: [ - "/v2/screen-groups/00EQWMS5WA1WJE0WD81VF91DFH", - "/v2/screen-groups/0135RY0QPR1DVF0ZT70YHS1NX3", - "/v2/screen-groups/0135RY0QPR1DVF0ZT70YHS1NX3", - ], - isCampaign: false, - published: { - from: "2021-03-21T02:10:37.000Z", - to: "2021-11-08T12:13:31.000Z", - }, - }, - ], - "hydra:totalItems": 10, - }; - await route.fulfill({ json }); - }); - await page.route("**/token", async (route) => { - const json = { - token: "1", - refresh_token: "2", - tenants: [ - { - tenantKey: "ABC", - title: "ABC Tenant", - description: "Description", - roles: ["ROLE_ADMIN"], - }, - ], - user: { - fullname: "John Doe", - email: "johndoe@example.com", - }, - }; - await route.fulfill({ json }); - }); - await page.route("**/slides*", async (route) => { - const json = { - "@context": "/contexts/Slide", - "@id": "/v2/slides", - "@type": "hydra:Collection", - "hydra:member": [], - "hydra:totalItems": 100, - }; - await route.fulfill({ json }); - }); - await expect(page).toHaveTitle(/OS2Display Admin/); - await page.getByLabel("Email").fill("johndoe@example.com"); - await page.getByLabel("Kodeord").fill("password"); - await page.locator("#login").click(); + await beforeEachTest(page); + }); + + test.beforeEach(async ({ page }) => { + await loginTest(page); + + await fulfillDataRoute(page, "**/playlists*", playlistListJson); + + await fulfillEmptyRoutes(page, ["**/tenants*"]); + + await page.getByRole("link", { name: "Spillelister", exact: true }).click(); + await expect( + page.getByRole("heading", { name: "Spillelister", exact: true }), + ).toBeVisible(); }); test("It loads playlist list", async ({ page }) => { @@ -207,29 +103,7 @@ test.describe("Playlist list tests", () => { }); test("It goes to edit", async ({ page }) => { - await page.route("**/playlists/*", async (route) => { - const json = { - "@id": "/v2/playlists/004ZP1XQ1G1MVZ1T0100YN0MPC", - title: "Et consequatur voluptatibus dolore ut ut.", - description: - "Atque maiores nam in occaecati labore labore inventore quo. Enim nemo totam hic. Ut suscipit id sint sed quia.", - schedules: [], - created: "1975-06-08T13:12:49.000Z", - modified: "2022-01-30T15:42:42.000Z", - modifiedBy: "", - createdBy: "", - slides: "/v2/playlists/004ZP1XQ1G1MVZ1T0100YN0MPC/slides", - campaignScreens: ["/v2/screens/00TH1ZRMZC141K1DMB1H7J03CS"], - campaignScreenGroups: [], - isCampaign: true, - published: { - from: "2022-03-23T21:30:21.000Z", - to: "2022-03-25T12:39:29.000Z", - }, - }; - - await route.fulfill({ json }); - }); + await fulfillDataRoute(page, "**/playlists/*", playlistSingleJson); await expect(page.locator("#playlistTitle")).not.toBeVisible(); await page.locator("tbody").locator("tr td a").nth(0).click(); diff --git a/assets/tests/admin/admin-screen-groups.spec.js b/assets/tests/admin/admin-screen-groups.spec.js index d4c2d07e..cf3b466a 100644 --- a/assets/tests/admin/admin-screen-groups.spec.js +++ b/assets/tests/admin/admin-screen-groups.spec.js @@ -1,32 +1,39 @@ import { test, expect } from "@playwright/test"; +import { + beforeEachTest, + fulfillDataRoute, + fulfillEmptyRoutes, + loginTest, +} from "./test-helper.js"; +import { + playlistListJson, + onSaveJson, + errorJson, + screenGroupsListJson, + screenGroupsSingleJson, +} from "./data-fixtures.js"; +import { json } from "react-router-dom"; test.describe("Create group page works", () => { test.beforeEach(async ({ page }) => { - await page.goto("/admin/group/create"); - await page.route("**/token", async (route) => { - const json = { - token: "1", - refresh_token: "2", - tenants: [ - { - tenantKey: "ABC", - title: "ABC Tenant", - description: "Description", - roles: ["ROLE_ADMIN"], - }, - ], - user: { - fullname: "John Doe", - email: "johndoe@example.com", - }, - }; - await route.fulfill({ json }); - }); + await beforeEachTest(page); + }); + + test.beforeEach(async ({ page }) => { + await loginTest(page); + + await fulfillEmptyRoutes(page, ["**/screen-groups*"]); - await expect(page).toHaveTitle(/OS2Display Admin/); - await page.getByLabel("Email").fill("johndoe@example.com"); - await page.getByLabel("Kodeord").fill("password"); - await page.locator("#login").click(); + await page.getByRole("link", { name: "Grupper", exact: true }).click(); + await expect( + page.getByRole("heading", { name: "Grupper", exact: true }), + ).toBeVisible(); + await page + .getByRole("button", { name: "Opret ny gruppe", exact: true }) + .click(); + await expect( + page.getByRole("heading", { name: "Opret ny gruppe", exact: true }), + ).toBeVisible(); }); test("It loads create group page", async ({ page }) => { @@ -34,17 +41,7 @@ test.describe("Create group page works", () => { }); test("It redirects on save", async ({ page }) => { - await page.route("**/screen-groups", async (route) => { - const json = { - title: "A laudantium aspernatur qui.", - description: "Description", - created: "1991-09-10T22:36:56+02:00", - modified: "2021-12-09T12:01:33+01:00", - modifiedBy: "", - createdBy: "", - }; - await route.fulfill({ json }); - }); + await fulfillDataRoute(page, "**/screen-groups", onSaveJson); // Displays success toast and redirects await expect( @@ -68,15 +65,8 @@ test.describe("Create group page works", () => { }); test("It display error toast on save error", async ({ page }) => { - await page.route("**/screen-groups", async (route) => { - const json = { - "@context": "/contexts/Error", - "@type": "hydra:Error", - "hydra:title": "An error occurred", - "hydra:description": "An error occurred", - }; - await route.fulfill({ status: 500, json }); - }); + await fulfillDataRoute(page, "**/screen-groups", errorJson, 500); + // Displays error toast and stays on page await expect( page.locator(".Toastify").locator(".Toastify__toast--error"), @@ -91,152 +81,19 @@ test.describe("Create group page works", () => { test.describe("Groups list works", () => { test.beforeEach(async ({ page }) => { - await page.goto("/admin/group/list"); - await page.route("**/token", async (route) => { - const json = { - token: "1", - refresh_token: "2", - tenants: [ - { - tenantKey: "ABC", - title: "ABC Tenant", - description: "Description", - roles: ["ROLE_ADMIN"], - }, - ], - user: { - fullname: "John Doe", - email: "johndoe@example.com", - }, - }; - await route.fulfill({ json }); - }); + await beforeEachTest(page); + }); - await page.route("**/screen-groups*", async (route) => { - const json = { - "@id": "/v2/screen-groups", - "hydra:member": [ - { - "@type": "ScreenGroup", - "@id": "/v2/screen-groups/000RAH746Q1AD8011Z1JNV06N3", - title: "Cupiditate et quidem autem iusto.", - description: - "Eos quibusdam consectetur nisi consequatur voluptas. Unde maxime sunt quidem magnam. Sed ipsa voluptas qui occaecati ea nobis.", - created: "1970-10-30T08:30:07+01:00", - modified: "2021-12-09T12:01:33+01:00", - modifiedBy: "", - createdBy: "", - }, - { - "@type": "ScreenGroup", - "@id": "/v2/screen-groups/0012G98YZS0VTK0Z2T02AD1DC3", - title: "Dignissimos nihil non sit laudantium.", - description: - "Maxime dicta magnam est voluptas voluptas. Est omnis expedita harum reprehenderit debitis laboriosam ab omnis. Sed temporibus iste voluptatibus ut qui est non voluptatem.", - created: "1971-03-05T20:43:43+01:00", - modified: "2021-12-09T12:01:33+01:00", - modifiedBy: "", - createdBy: "", - }, - { - "@type": "ScreenGroup", - "@id": "/v2/screen-groups/001EZQXKKR0P7X0A3119Z016SB", - title: "Aut nam accusantium id aut.", - description: - "Et est nisi autem nihil. Blanditiis facere repellat et. Est et architecto modi laboriosam corporis et.", - created: "1971-08-07T23:56:38+01:00", - modified: "2021-12-09T12:01:33+01:00", - modifiedBy: "", - createdBy: "", - }, - { - "@type": "ScreenGroup", - "@id": "/v2/screen-groups/003J350X2D060H00TE1DW50640", - title: "Velit rem commodi necessitatibus eos.", - description: - "Non sequi sed fugit. Nihil cumque nesciunt hic recusandae rem suscipit sunt. Nostrum voluptatem ut consequatur non illum.", - created: "1973-11-18T23:15:03+01:00", - modified: "2021-12-09T12:01:33+01:00", - modifiedBy: "", - createdBy: "", - }, - { - "@type": "ScreenGroup", - "@id": "/v2/screen-groups/003Z784JQS1PNS1RX1003N0NCD", - title: "Quod esse voluptas ut.", - description: - "Deleniti velit est quasi commodi alias est minima. Harum iusto odio aperiam consequatur qui est. Vel ut id aperiam nobis fugiat et modi. Est dolores rerum id sed excepturi et.", - created: "1974-05-01T02:50:31+01:00", - modified: "2021-12-09T12:01:33+01:00", - modifiedBy: "", - createdBy: "", - }, - { - "@type": "ScreenGroup", - "@id": "/v2/screen-groups/009YS5ZYPH1B9T0JE01S290T5Y", - title: "Tenetur voluptatem quo rerum exercitationem.", - description: - "Suscipit provident odit in eius sed voluptatibus. Neque aut corporis aspernatur quo qui. Inventore nam est sed sed maiores odio.", - created: "1980-11-05T17:57:30+01:00", - modified: "2021-12-09T12:01:33+01:00", - modifiedBy: "", - createdBy: "", - }, - { - "@type": "ScreenGroup", - "@id": "/v2/screen-groups/00C1V2MX2S02N30EXM163A0E6X", - title: "Distinctio quisquam et totam molestias.", - description: - "Ad ipsam architecto eum repellat excepturi. Quos deleniti itaque ut reprehenderit aut rerum autem. Nihil et mollitia voluptatibus quis voluptatem. Ex eaque sint nostrum impedit.", - created: "1983-02-17T02:51:45+01:00", - modified: "2021-12-09T12:01:33+01:00", - modifiedBy: "", - createdBy: "", - }, - { - "@type": "ScreenGroup", - "@id": "/v2/screen-groups/00DDTCJCDX0H101N480E180K4B", - title: "Cumque facere nulla reiciendis.", - description: - "Veritatis doloremque delectus voluptas numquam dolores nobis. Dignissimos quo facere eum iure.", - created: "1984-08-16T16:14:03+02:00", - modified: "2021-12-09T12:01:33+01:00", - modifiedBy: "", - createdBy: "", - }, - { - "@type": "ScreenGroup", - "@id": "/v2/screen-groups/00GEPM6JRX0V2P0YST0JHA03CC", - title: "Ea aspernatur odit rerum.", - description: - "Adipisci tenetur placeat perspiciatis assumenda. Voluptas officiis magnam reprehenderit possimus non. Tempore delectus numquam veritatis harum natus.", - created: "1987-12-03T16:33:04+01:00", - modified: "2021-12-09T12:01:33+01:00", - modifiedBy: "", - createdBy: "", - }, - { - "@type": "ScreenGroup", - "@id": "/v2/screen-groups/00KXGYAJ4A1D5P0EA11SKF0BG8", - title: "A laudantium aspernatur qui.", - description: - "Non fugiat nobis occaecati. Sed ut velit beatae amet ea esse. Quo dolorem commodi magni at. Illum voluptatem neque nobis et ut. Ad rerum tempore vel commodi suscipit corrupti.", - created: "1991-09-10T22:36:56+02:00", - modified: "2021-12-09T12:01:33+01:00", - modifiedBy: "", - createdBy: "", - }, - ], - "hydra:totalItems": 20, - }; + test.beforeEach(async ({ page }) => { + await loginTest(page); - await route.fulfill({ json }); - }); + await fulfillEmptyRoutes(page, ["**/screens*"]); + await fulfillDataRoute(page, "**/screen-groups*", screenGroupsListJson); - await expect(page).toHaveTitle(/OS2Display Admin/); - await page.getByLabel("Email").fill("johndoe@example.com"); - await page.getByLabel("Kodeord").fill("password"); - await page.locator("#login").click(); + await page.getByRole("link", { name: "Grupper", exact: true }).click(); + await expect( + page.getByRole("heading", { name: "Grupper", exact: true }), + ).toBeVisible(); }); test("It loads groups list", async ({ page }) => { @@ -245,19 +102,11 @@ test.describe("Groups list works", () => { }); test("It goes to edit (groups list)", async ({ page }) => { - await page.route("**/screen-groups/*", async (route) => { - const json = { - "@id": "/v2/screen-groups/00GEPM6JRX0V2P0YST0JHA03CC", - title: "Ea aspernatur odit rerum.", - description: - "Adipisci tenetur placeat perspiciatis assumenda. Voluptas officiis magnam reprehenderit possimus non. Tempore delectus numquam veritatis harum natus.", - created: "1987-12-03T16:33:04+01:00", - modified: "2021-12-09T12:01:33+01:00", - modifiedBy: "", - createdBy: "", - }; - await route.fulfill({ json }); - }); + await fulfillDataRoute( + page, + "**/screen-groups/000RAH746Q1AD8011Z1JNV06N3", + screenGroupsSingleJson, + ); await expect(page.locator("#groupTitle")).not.toBeVisible(); await page.locator("tbody").locator("tr td a").nth(0).click(); @@ -278,11 +127,11 @@ test.describe("Groups list works", () => { test("It removes all selected", async ({ page }) => { await page.locator("tbody").locator("tr td input").nth(0).click(); - expect( + await expect( page.locator("tbody").locator("tr").nth(0).getByRole("checkbox"), ).toBeChecked(); await page.locator("#clear-rows-button").click(); - expect( + await expect( page.locator("tbody").locator("tr").nth(0).getByRole("checkbox"), ).not.toBeChecked(); }); diff --git a/assets/tests/admin/admin-screens.spec.js b/assets/tests/admin/admin-screens.spec.js index d61292b7..1a859f23 100644 --- a/assets/tests/admin/admin-screens.spec.js +++ b/assets/tests/admin/admin-screens.spec.js @@ -1,159 +1,53 @@ import { test, expect } from "@playwright/test"; - -test.describe("Screen list tests", () => { +import { + adminConfigJson, + screenGroupsListJson, + screensListJson, +} from "./data-fixtures.js"; +import { + beforeEachTest, + fulfillDataRoute, + fulfillEmptyRoutes, + loginTest, +} from "./test-helper.js"; + +test.describe("Screen", () => { test.beforeEach(async ({ page }) => { - await page.goto("/admin/screen/list"); - await page.route("**/token", async (route) => { - const json = { - token: "1", - refresh_token: "2", - tenants: [ - { - tenantKey: "ABC", - title: "ABC Tenant", - description: "Description", - roles: ["ROLE_ADMIN"], - }, - ], - user: { - fullname: "John Doe", - email: "johndoe@example.com", - }, - }; - await route.fulfill({ json }); - }); - await page.route("**/screens*", async (route) => { - const json = { - "@id": "/v2/screens", - "hydra:member": [ - { - "@type": "Screen", - "@id": "/v2/screens/00APXK73HQ11PM0X3P12EG14DZ", - title: "Ab eos dolorum minima inventore.", - description: - "Non inventore ab vitae. Voluptatem assumenda aliquam sunt nulla sint corrupti et. Nihil consectetur facere cum modi aliquid. Non aut voluptas voluptas laudantium.", - size: "42", - created: "1981-09-01T17:22:18+02:00", - modified: "2021-12-09T12:01:33+01:00", - modifiedBy: "", - createdBy: "", - layout: "/v2/layouts/009S1H8VER00GK086N0M1J16K9", - location: - "Natus aut est eveniet deleniti nihil voluptatum. Accusamus similique adipisci at qui molestiae quia nihil eligendi. Delectus repellendus ut asperiores ut debitis.", - regions: [], - inScreenGroups: "/v2/screens/00APXK73HQ11PM0X3P12EG14DZ/groups", - dimensions: { - width: 1920, - height: 1200, - }, - }, - { - "@type": "Screen", - "@id": "/v2/screens/00AYESM1AR002E0YKH0JQ70185", - title: "Accusantium aperiam mollitia consectetur.", - description: - "Asperiores id aut temporibus expedita quia rem. Sunt possimus voluptas voluptas exercitationem. Totam odio necessitatibus aut velit. Nisi est voluptates suscipit rerum perspiciatis.", - size: "55", - created: "1981-12-04T09:31:11+01:00", - modified: "2021-12-09T12:01:33+01:00", - modifiedBy: "", - createdBy: "", - layout: "/v2/layouts/009S1H8VER00GK086N0M1J16K9", - location: - "Occaecati beatae iure molestias sapiente nihil. Tempore quo quibusdam odit quia.", - regions: [], - inScreenGroups: "/v2/screens/00AYESM1AR002E0YKH0JQ70185/groups", - dimensions: { - width: 1920, - height: 1200, - }, - }, - ], - }; - - await route.fulfill({ json }); - }); - await expect(page).toHaveTitle(/OS2Display Admin/); - await page.getByLabel("Email").fill("johndoe@example.com"); - await page.getByLabel("Kodeord").fill("password"); - await page.locator("#login").click(); + await beforeEachTest(page); }); - test("It loads screens list", async ({ page }) => { - await page.getByText("Skærme"); - await expect(page.locator("table").locator("tbody")).not.toBeEmpty(); - await expect(page.locator("tbody").locator("tr td")).toHaveCount(14); - }); + test.beforeEach(async ({ page }) => { + await loginTest(page); - test("It goes to screen edit", async ({ page }) => { - await page.route("**/screens/*", async (route) => { - const json = { - "@id": "/v2/screens/00APXK73HQ11PM0X3P12EG14DZ", - title: "Ab eos dolorum minima inventore.", - description: - "Non inventore ab vitae. Voluptatem assumenda aliquam sunt nulla sint corrupti et. Nihil consectetur facere cum modi aliquid. Non aut voluptas voluptas laudantium.", - size: "42", - created: "1981-09-01T17:22:18+02:00", - modified: "2021-12-09T12:01:33+01:00", - modifiedBy: "", - createdBy: "", - layout: "/v2/layouts/009S1H8VER00GK086N0M1J16K9", - location: - "Natus aut est eveniet deleniti nihil voluptatum. Accusamus similique adipisci at qui molestiae quia nihil eligendi. Delectus repellendus ut asperiores ut debitis.", - regions: [], - inScreenGroups: "/v2/screens/00APXK73HQ11PM0X3P12EG14DZ/groups", - dimensions: { - width: 1920, - height: 1200, - }, - }; + await fulfillDataRoute(page, "**/screens*", screensListJson); - await route.fulfill({ json }); - }); - await expect(page.locator("#screenTitle")).not.toBeVisible(); - await page.locator("tbody").locator("#edit_button").nth(0).click(); - await expect(page.locator("#screenTitle")).toBeVisible(); - }); + await fulfillEmptyRoutes(page, [ + "**/campaigns*", + "**/screen-groups*", + "**/layouts*", + ]); - test("The correct amount of column headers loaded", async ({ page }) => { - await expect(page.locator("thead").locator("th")).toHaveCount(7); + await page.getByRole("link", { name: "Skærme", exact: true }).click(); + await expect( + page.getByRole("heading", { name: "Skærme", exact: true }), + ).toBeVisible(); }); -}); -test.describe("Screen create tests", () => { - test.beforeEach(async ({ page }) => { - await page.goto("/admin/screen/create"); - await page.route("**/token", async (route) => { - const json = { - token: "1", - refresh_token: "2", - tenants: [ - { - tenantKey: "ABC", - title: "ABC Tenant", - description: "Description", - roles: ["ROLE_ADMIN"], - }, - ], - user: { - fullname: "John Doe", - email: "johndoe@example.com", - }, - }; - await route.fulfill({ json }); - }); - - await expect(page).toHaveTitle(/OS2Display Admin/); - await page.getByLabel("Email").fill("johndoe@example.com"); - await page.getByLabel("Kodeord").fill("password"); - await page.locator("#login").click(); + test("Loads list", async ({ page }) => { + await expect(page.locator("table").locator("tbody")).not.toBeEmpty(); + await expect(page.locator("tbody").locator("tr td")).toHaveCount(16); + await expect(page.locator("thead").locator("th")).toHaveCount(8); }); test("It loads create screen page", async ({ page }) => { + await page.getByLabel("Tilføj ny skærm").first().click(); + await expect(page.getByText("Opret ny skærm")).toBeVisible(); await expect(page.locator("#save_screen")).toBeVisible(); }); test("It cancels create screen", async ({ page }) => { + await page.getByLabel("Tilføj ny skærm").first().click(); + await expect(page.getByText("Opret ny skærm")).toBeVisible(); await expect(page.locator("#cancel_screen")).toBeVisible(); await page.locator("#cancel_screen").click(); await expect(page.locator("#cancel_screen")).not.toBeVisible(); diff --git a/assets/tests/admin/admin-shared-list.spec.js b/assets/tests/admin/admin-shared-list.spec.js index b85f18db..7244ae2a 100644 --- a/assets/tests/admin/admin-shared-list.spec.js +++ b/assets/tests/admin/admin-shared-list.spec.js @@ -1,87 +1,28 @@ import { test, expect } from "@playwright/test"; +import { + beforeEachTest, + fulfillDataRoute, + fulfillEmptyRoutes, + loginTest, +} from "./test-helper.js"; +import { playlistListJson, screensListJson } from "./data-fixtures.js"; test.describe("Shared list tests", () => { test.beforeEach(async ({ page }) => { - await page.goto("/admin/shared/list"); - await page.route("**/token", async (route) => { - const json = { - token: "1", - refresh_token: "2", - tenants: [ - { - tenantKey: "ABC", - title: "ABC Tenant", - description: "Description", - roles: ["ROLE_ADMIN"], - }, - ], - user: { - fullname: "John Doe", - email: "johndoe@example.com", - }, - }; - await route.fulfill({ json }); - }); - await page.route("**/playlists*", async (route) => { - const json = { - "@context": "/contexts/Playlist", - "@id": "/v2/playlists", - "@type": "hydra:Collection", - "hydra:member": [ - { - "@type": "Playlist", - "@id": "/v2/playlists/004ZP1XQ1G1MVZ1T0100YN0MPC", - title: "Et consequatur voluptatibus dolore ut ut.", - description: - "Atque maiores nam in occaecati labore labore inventore quo. Enim nemo totam hic. Ut suscipit id sint sed quia.", - schedules: [], - created: "1975-06-08T13:12:49.000Z", - modified: "2022-01-30T15:42:42.000Z", - modifiedBy: "", - createdBy: "", - slides: "/v2/playlists/004ZP1XQ1G1MVZ1T0100YN0MPC/slides", - campaignScreens: ["/v2/screens/00TH1ZRMZC141K1DMB1H7J03CS"], - campaignScreenGroups: [], - isCampaign: true, - published: { - from: "2022-03-23T21:30:21.000Z", - to: "2022-03-25T12:39:29.000Z", - }, - }, - { - "@type": "Playlist", - "@id": "/v2/playlists/007TM6JDGF1ECH07J10ZHY0S7P", - title: "Voluptas molestias nemo et.", - description: - "Aperiam quam sunt quia qui. Iusto ut deserunt veritatis nobis dolorem. Aliquid quo vel quia.", - schedules: [], - created: "1978-07-12T17:43:59.000Z", - modified: "2022-01-30T15:42:42.000Z", - modifiedBy: "", - createdBy: "", - slides: "/v2/playlists/007TM6JDGF1ECH07J10ZHY0S7P/slides", - campaignScreens: [], - campaignScreenGroups: [ - "/v2/screen-groups/00EQWMS5WA1WJE0WD81VF91DFH", - "/v2/screen-groups/0135RY0QPR1DVF0ZT70YHS1NX3", - "/v2/screen-groups/0135RY0QPR1DVF0ZT70YHS1NX3", - ], - isCampaign: false, - published: { - from: "2021-03-21T02:10:37.000Z", - to: "2021-11-08T12:13:31.000Z", - }, - }, - ], - "hydra:totalItems": 2, - }; + await beforeEachTest(page); + }); + + test.beforeEach(async ({ page }) => { + await loginTest(page); - await route.fulfill({ json }); - }); - await expect(page).toHaveTitle(/OS2Display Admin/); - await page.getByLabel("Email").fill("johndoe@example.com"); - await page.getByLabel("Kodeord").fill("password"); - await page.locator("#login").click(); + await fulfillDataRoute(page, "**/playlists*", playlistListJson); + + await page + .getByRole("link", { name: "Delte spillelister", exact: true }) + .click(); + await expect( + page.getByRole("heading", { name: "Delte spillelister", exact: true }), + ).toBeVisible(); }); test("It loads shared playlist list", async ({ page }) => { diff --git a/assets/tests/admin/admin-slides.spec.js b/assets/tests/admin/admin-slides.spec.js index 529f6757..a93d3112 100644 --- a/assets/tests/admin/admin-slides.spec.js +++ b/assets/tests/admin/admin-slides.spec.js @@ -1,124 +1,30 @@ import { test, expect } from "@playwright/test"; +import { + beforeEachTest, + fulfillDataRoute, + fulfillEmptyRoutes, + loginTest, +} from "./test-helper.js"; +import { + emptyJson, + errorJson, + slidesListJson, + templatesListJson, +} from "./data-fixtures.js"; -test.describe("Create slide page works", () => { +test.describe("Slide create", () => { test.beforeEach(async ({ page }) => { - await page.goto("/admin/slide/create"); - await page.route("**/token", async (route) => { - const json = { - token: "1", - refresh_token: "2", - tenants: [ - { - tenantKey: "ABC", - title: "ABC Tenant", - description: "Description", - roles: ["ROLE_ADMIN"], - }, - ], - user: { - fullname: "John Doe", - email: "johndoe@example.com", - }, - }; - await route.fulfill({ json }); - }); - await page.route("**/templates?itemsPerPage*", async (route) => { - const json = { - "@id": "/v2/templates", - "hydra:member": [ - { - "@type": "Template", - "@id": "/v2/templates/00XZXR5XDH0D1M16K10NYQ0A55", - title: "Est totam provident sunt.", - description: - "Tempora qui minus officia quis consequuntur voluptates. Quasi minima eveniet repudiandae laborum dolor quasi totam qui. Iusto enim inventore molestias amet aut.", - created: "2002-08-30T14:14:07+02:00", - modified: "2021-12-09T12:01:33+01:00", - modifiedBy: "", - createdBy: "", - resources: { - admin: - "http://www.harber.com/atque-inventore-consequatur-mollitia-ducimus-veritatis-doloribus-ad", - schema: "http://www.kulas.net/quia-unde-quos-error-modi-saepe", - component: "http://keebler.com/", - assets: { - type: "css", - url: "https://www.borer.biz/voluptas-blanditiis-et-quo-aut-culpa-reiciendis-dolorum", - }, - options: { - fade: true, - }, - content: { - text: "Accusantium exercitationem animi qui provident ipsa distinctio.", - }, - }, - }, - { - "@type": "Template", - "@id": "/v2/templates/016MHSNKCH1PQW1VY615JC19Y3", - title: "Ut exercitationem est quia ad quas.", - description: - "Laborum quod ut ducimus suscipit quia nostrum. Saepe ex voluptas aut. Sit numquam vel est sunt. Cupiditate excepturi non saepe in voluptatem vel rem quaerat. Magni aut eaque vel deleniti.", - created: "2012-01-28T09:17:22+01:00", - modified: "2021-12-09T12:01:33+01:00", - modifiedBy: "", - createdBy: "", - resources: { - admin: - "https://vandervort.com/sapiente-quo-est-rerum-nihil-sint-placeat-ipsa-id.html", - schema: - "http://www.gulgowski.com/debitis-voluptatem-earum-sed-totam-aut-impedit-facere", - component: - "https://lehner.com/officia-ducimus-ea-beatae-eum-amet-provident-sint.html", - assets: { - type: "css", - url: "http://www.emmerich.net/aliquam-excepturi-id-et-ab-voluptate.html", - }, - options: { - fade: true, - }, - content: { - text: "Ut qui assumenda ex vel quod dolorem perspiciatis eos quis.", - }, - }, - }, - { - "@type": "Template", - "@id": "/v2/templates/017X81AEJV2GJE0NC51KKK0EK8", - title: "Delectus magnam repudiandae molestiae et a.", - description: - "Consequuntur est ut commodi sed. Fugiat repellat harum assumenda sed illo voluptatem nobis fugit. At vero consequatur ut dignissimos. Et inventore ipsam ullam ullam dolor debitis quo saepe.", - created: "2013-06-17T03:02:15+02:00", - modified: "2021-12-09T12:01:33+01:00", - modifiedBy: "", - createdBy: "", - resources: { - admin: "http://www.ratke.com/libero-provident-nihil-minus-alias", - schema: "http://murazik.biz/", - component: - "http://kuhlman.biz/inventore-iure-tempora-perspiciatis-repudiandae-numquam-veniam-sequi-dolorem.html", - assets: { - type: "css", - url: "http://dibbert.biz/eius-et-non-autem", - }, - options: { - fade: true, - }, - content: { - text: "Praesentium at porro aut corporis quis in quia asperiores sed sit.", - }, - }, - }, - ], - "hydra:totalItems": 12, - }; + await beforeEachTest(page); + }); + + test.beforeEach(async ({ page }) => { + await loginTest(page); - await route.fulfill({ json }); - }); - await expect(page).toHaveTitle(/OS2Display Admin/); - await page.getByLabel("Email").fill("johndoe@example.com"); - await page.getByLabel("Kodeord").fill("password"); - await page.locator("#login").click(); + await fulfillDataRoute(page, "**/templates*", templatesListJson); + await fulfillEmptyRoutes(page, ["**/playlists*", "**/themes*"]); + + await page.getByLabel("Tilføj nyt slide").first().click(); + await expect(page.getByText("Opret nyt slide:")).toBeVisible(); }); test("It loads create slide page", async ({ page }) => { @@ -126,15 +32,7 @@ test.describe("Create slide page works", () => { }); test("It display error toast on save error", async ({ page }) => { - await page.route("**/slides", async (route) => { - const json = { - "@context": "/contexts/Error", - "@type": "hydra:Error", - "hydra:title": "An error occurred", - "hydra:description": "An error occurred", - }; - await route.fulfill({ status: 500, json }); - }); + await fulfillDataRoute(page, "**/slides", errorJson, 500); // Displays error toast and stays on page await expect( @@ -157,333 +55,23 @@ test.describe("Create slide page works", () => { }); }); -test.describe("Slides list works", () => { +test.describe("Slides list", () => { test.beforeEach(async ({ page }) => { - await page.goto("/admin/slide/list"); - await page.route("**/slides*", async (route) => { - const json = { - "@id": "/v2/slides", - "hydra:member": [ - { - "@id": "/v2/slides/0086TQQC671WHA1S150MMF1Q3T", - title: "Adipisci vero quia.", - description: - "Dolores porro ex sed consectetur dolorem aspernatur. Recusandae voluptatem non a aut. Tenetur optio aut fugit reprehenderit. Non dolorum temporibus possimus iure aut quas.", - created: "1978-12-11T09:47:36.000Z", - modified: "2021-12-09T12:01:33.000Z", - modifiedBy: "", - createdBy: "", - templateInfo: { - "@id": "/v2/templates/00MWCNKC4P0X5C0AT70E741E2V", - options: [], - }, - theme: "", - onPlaylists: ["/v2/playlists/00S7ZQK8Y90R351YES1DJN0RKR"], - duration: 70592, - published: { - from: null, - to: "1989-08-28T18:14:52.000Z", - }, - media: ["/v2/media/00W2E6VC0V22QK1WYH0CMP151C"], - }, - { - "@id": "/v2/slides/00BEFT32281WT51SNJ0JXA11AV", - title: "Alias et id consequatur.", - description: - "Beatae reiciendis provident eos est totam repudiandae molestiae. Qui itaque officiis quibusdam. A nisi minus dolorum excepturi. Atque molestiae non velit ipsum consequatur nisi.", - created: "1982-06-21T15:09:47.000Z", - modified: "2021-12-09T12:01:33.000Z", - modifiedBy: "", - createdBy: "", - templateInfo: { - "@id": "/v2/templates/00PXXK8ND01SRF18YH1WN004VA", - options: [], - }, - theme: "/v2/themes/01FPFH3WX93S4575W6Q9T8K0YB", - onPlaylists: [], - duration: 40787, - published: { - from: "2021-03-12T18:12:47.000Z", - to: "2021-05-20T08:42:21.000Z", - }, - media: [ - "/v2/media/0010X8D6JJ03G50T1J1FCW1XH6", - "/v2/media/0043AB9VWE08071MNB08Q20JSG", - "/v2/media/009RGQK5AD19K21CZE11HC1DPX", - "/v2/media/00HM3QQ61107C41D7M0W2B1CEK", - "/v2/media/01BTDHQH3Z06N40M9V0TJ41YA8", - ], - }, - { - "@id": "/v2/slides/00BCX948J60YCR1TC009A31MPQ", - title: "Amet impedit eum quia quo.", - description: - "Quis nostrum voluptatum quam aut sint enim. Ut sed occaecati deserunt accusantium. Cupiditate et voluptatum ex quidem. Nobis rerum consequatur fugiat occaecati voluptas et.", - created: "1982-06-02T00:11:19.000Z", - modified: "2021-12-09T12:01:33.000Z", - modifiedBy: "", - createdBy: "", - templateInfo: { - "@id": "/v2/templates/000YR9PMQC0GMC1TP90V9N07WX", - options: [], - }, - theme: "", - onPlaylists: [], - duration: 4902, - published: { - from: null, - to: null, - }, - media: [ - "/v2/media/00007SBZ470CJ60C7J06H508R8", - "/v2/media/004MDCEC451GPJ1DW80D1Z026F", - ], - }, - { - "@id": "/v2/slides/000AGMKXFZ0QWX0V5013R80S3S", - title: "Aperiam maxime autem.", - description: - "Ea laboriosam rerum voluptatem. Quos odit veniam cum. Quia non expedita non facere id eum nesciunt. Fugit dolorum ipsa aspernatur.", - created: "1970-05-11T17:45:13.000Z", - modified: "2021-12-09T12:01:33.000Z", - modifiedBy: "", - createdBy: "", - templateInfo: { - "@id": "/v2/templates/018A0WH44D0X1N176Z16CC0HJP", - options: [], - }, - theme: "", - onPlaylists: [], - duration: 85133, - published: { - from: "2021-08-13T23:56:36.000Z", - to: null, - }, - media: [ - "/v2/media/00CGESC8E10CZA11EV2AYR1KWC", - "/v2/media/00HM3QQ61107C41D7M0W2B1CEK", - "/v2/media/01DCA32QJY1BH600BV2H140JDK", - ], - }, - { - "@id": "/v2/slides/014FR06WMH05WP17B71Q6Z1K7R", - title: "Architecto dolores facilis et.", - description: - "Aspernatur doloremque et perferendis dolorum hic. Ab vel praesentium non pariatur. Omnis ut magni voluptas et. Ducimus harum sed beatae labore.", - created: "2009-09-25T07:04:00.000Z", - modified: "2021-12-09T12:01:33.000Z", - modifiedBy: "", - createdBy: "", - templateInfo: { - "@id": "/v2/templates/00HH42EEHC05QT14VQ041R1KEY", - options: [], - }, - theme: "", - onPlaylists: ["/v2/playlists/00S7ZQK8Y90R351YES1DJN0RKR"], - duration: 11240, - published: { - from: "2020-12-24T06:17:03.000Z", - to: null, - }, - media: ["/v2/media/000NDA6BBM1A071RNN0SP40XNJ"], - }, - { - "@id": "/v2/slides/00J96KHGSC1HPH0VHW1FSX0CVD", - title: "Assumenda quaerat sint nihil perspiciatis.", - description: - "Eaque quaerat voluptas vitae rerum numquam dolore explicabo. Quas error voluptates quo est vel. Odit cum illum qui aut iure ipsum officiis.", - created: "1989-11-29T16:39:50.000Z", - modified: "2021-12-09T12:01:33.000Z", - modifiedBy: "", - createdBy: "", - templateInfo: { - "@id": "/v2/templates/001R8FR6VC10G51B200TK60QP3", - options: [], - }, - theme: "/v2/themes/01FPFH3WX93S4575W6Q9T8K0YN", - onPlaylists: [], - duration: 81995, - published: { - from: "2021-11-26T14:53:28.000Z", - to: null, - }, - media: [ - "/v2/media/009H64MSPN1HEH0DTV2DEV085B", - "/v2/media/00H1A2WZ1A06BK0W781ETS1EXZ", - "/v2/media/01BBCV60M903YC07RP09VN1JBZ", - ], - }, - { - "@id": "/v2/slides/00FTMVQRPS18QD0MBY0RQ30FP0", - title: "Atque nulla explicabo beatae.", - description: - "Repudiandae sapiente voluptatibus dolores voluptatem. Recusandae quia iste voluptates tempora fuga aliquam aut hic.", - created: "1987-03-29T10:52:22.000Z", - modified: "2021-12-09T12:01:33.000Z", - modifiedBy: "", - createdBy: "", - templateInfo: { - "@id": "/v2/templates/01F8MJT0AV24D602FN131008YY", - options: [], - }, - theme: "/v2/themes/01FPFH3WX93S4575W6Q9T8K0Y9", - onPlaylists: [], - duration: 32646, - published: { - from: "2021-09-04T10:08:04.000Z", - to: "2021-10-27T01:46:23.000Z", - }, - media: [ - "/v2/media/000NDA6BBM1A071RNN0SP40XNJ", - "/v2/media/003M4E1AQG052J0HPM1X670P4F", - "/v2/media/009RF9AGF80QP60ECM0CY01A1Y", - "/v2/media/00QWNXTD5X0VSF1EWQ1H7H0YS2", - ], - }, - { - "@id": "/v2/slides/008J6BKZMA0YHM04S813NF0DZV", - title: "Atque quis aut qui veritatis.", - description: - "Dolore expedita labore praesentium beatae. Labore maiores est voluptates cupiditate praesentium. Maiores est dolorem iusto.", - created: "1979-05-01T14:59:35.000Z", - modified: "2021-12-09T12:01:33.000Z", - modifiedBy: "", - createdBy: "", - templateInfo: { - "@id": "/v2/templates/011763DN4P0FRS1T6B09180KCW", - options: [], - }, - theme: "", - onPlaylists: ["/v2/playlists/01EDTHWKBM0TR3035E0Z631B8E"], - duration: 86942, - published: { - from: "2020-12-26T12:37:10.000Z", - to: null, - }, - media: [ - "/v2/media/00JBVT18N31VBA0S3805CN03MC", - "/v2/media/016SXZGDJR0T321KYJ19B91N1Z", - "/v2/media/01795VPQZX0GNM00T11JJ71BS8", - ], - }, - { - "@id": "/v2/slides/0118GD1EXJ1CSM1BHW0P7K1KQG", - title: "Aut odio illum et.", - description: - "Voluptatibus dicta dolor suscipit eos. Voluptate atque quia quo blanditiis sint est odio. Voluptatum expedita ipsa ut et placeat laborum. Modi molestias quibusdam sunt ratione nulla sit.", - created: "2006-03-22T07:17:31.000Z", - modified: "2021-12-09T12:01:33.000Z", - modifiedBy: "", - createdBy: "", - templateInfo: { - "@id": "/v2/templates/000AT4BWMM1GJZ17WE1M9M0RFB", - options: [], - }, - theme: "/v2/themes/01FPFH3WX93S4575W6Q9T8K0YB", - onPlaylists: [], - duration: 104864, - published: { - from: "2021-03-27T10:02:38.000Z", - to: null, - }, - media: [ - "/v2/media/002B3H5Z2K10M211AK1ERC02PM", - "/v2/media/00XA10EH8H0YYY1H4B1CC40SSA", - ], - }, - { - "@id": "/v2/slides/0151GSJGTE1JSE032C14JR0CQ2", - title: "Aut qui placeat consequatur aut.", - description: - "Officiis sit adipisci exercitationem ut vero nihil iste voluptas. Temporibus aut saepe rerum sint. Soluta perferendis aliquid voluptatem eos.", - created: "2010-05-04T04:35:53.000Z", - modified: "2021-12-09T12:01:33.000Z", - modifiedBy: "", - createdBy: "", - templateInfo: { - "@id": "/v2/templates/01F8MJT0AV24D602FN131008YY", - options: [], - }, - theme: "", - onPlaylists: [], - duration: 28141, - published: { - from: "2020-12-14T13:20:43.000Z", - to: "2021-02-11T10:45:45.000Z", - }, - media: [ - "/v2/media/00KXYB7Z291JXC1SY30G161HQD", - "/v2/media/01ENQN7X2F0ANK1BNA0J3513JX", - ], - }, - ], - "hydra:totalItems": 100, - }; - await route.fulfill({ json }); - }); - await page.route("**/token", async (route) => { - const json = { - token: "1", - refresh_token: "2", - tenants: [ - { - tenantKey: "ABC", - title: "ABC Tenant", - description: "Description", - roles: ["ROLE_ADMIN"], - }, - ], - user: { - fullname: "John Doe", - email: "johndoe@example.com", - }, - }; - await route.fulfill({ json }); - }); - - await expect(page).toHaveTitle(/OS2Display Admin/); - await page.getByLabel("Email").fill("johndoe@example.com"); - await page.getByLabel("Kodeord").fill("password"); - await page.locator("#login").click(); + await beforeEachTest(page); }); - test("It loads slides list", async ({ page }) => { - await expect(page.locator("table").locator("tbody")).not.toBeEmpty(); - await expect(page.locator("tbody").locator("tr td").first()).toBeVisible(); - }); + test.beforeEach(async ({ page }) => { + await loginTest(page); - test("It goes to edit (slides list)", async ({ page }) => { - await page.route("**/slides/*", async (route) => { - const json = { - "@id": "/v2/slides/000622HP9N1G5P1CMD035H159G", - title: "Aut consequatur excepturi ut totam aspernatur.", - description: - "Et aut harum aut est. Et hic et totam. Possimus veritatis nemo sit repellat dolorem. Distinctio id voluptates laborum voluptas voluptas repellat.", - created: "1970-03-17T08:57:16.000Z", - modified: "2022-01-30T15:42:42.000Z", - modifiedBy: "", - createdBy: "", - templateInfo: { - "@id": "/v2/templates/00EPSCBVJS0TB0118C1JPM1VPM", - options: [], - }, - theme: "/v2/themes/01FTNTE789TEPTT7MC3TYM91JJ", - onPlaylists: [], - duration: 9834, - published: { - from: "2021-06-02T16:19:12.000Z", - to: "2021-06-14T01:24:17.000Z", - }, - media: ["/v2/media/014BH0252D18481TYB050J1WD9"], - content: [], - feed: null, - }; - await route.fulfill({ json }); - }); + await fulfillDataRoute(page, "**/templates*", templatesListJson); + await fulfillDataRoute(page, "**/templates/*", emptyJson); + await fulfillDataRoute(page, "**/slides*", slidesListJson); + await fulfillEmptyRoutes(page, ["**/playlists*", "**/themes*"]); - await expect(page.locator("#slidesTitle")).not.toBeVisible(); - await page.locator("tbody").locator("#edit_button").nth(0).click(); - await expect(page.locator("#slidesTitle")).toBeVisible(); + await page.getByLabel("Tilføj nyt slide").first().click(); + await expect(page.getByText("Opret nyt slide:")).toBeVisible(); + await page.getByRole("link", { name: "Slides" }).first().click(); + await expect(page.getByRole("heading", { name: "Slides" })).toBeVisible(); }); test("The correct amount of column headers loaded", async ({ page }) => { @@ -492,11 +80,11 @@ test.describe("Slides list works", () => { test("It removes all selected", async ({ page }) => { await page.locator("tbody").locator("tr td input").nth(0).click(); - expect( + await expect( page.locator("tbody").locator("tr").nth(0).getByRole("checkbox"), ).toBeChecked(); await page.locator("#clear-rows-button").click(); - expect( + await expect( page.locator("tbody").locator("tr").nth(0).getByRole("checkbox"), ).not.toBeChecked(); }); diff --git a/assets/tests/admin/admin-theme.spec.js b/assets/tests/admin/admin-theme.spec.js index ab3dd1d6..8c9da305 100644 --- a/assets/tests/admin/admin-theme.spec.js +++ b/assets/tests/admin/admin-theme.spec.js @@ -1,325 +1,43 @@ import { test, expect } from "@playwright/test"; +import { + beforeEachTest, + fulfillDataRoute, + fulfillEmptyRoutes, + loginTest, +} from "./test-helper.js"; +import { + errorJson, + feedSourcesJson2, + screensListJson, + themesJson, + themesSingleJson, +} from "./data-fixtures.js"; -const themesJson = { - "@context": "/contexts/Theme", - "@id": "/v2/themes", - "@type": "hydra:Collection", - "hydra:member": [ - { - "@type": "Theme", - "@id": "/v2/themes/01FTNTE788816N6YCW9NVM2JQB", - title: "Consequatur quisquam recusandae asperiores accusamus.", - description: - "Occaecati debitis et saepe eum sint dolorem. Enim ipsum inventore sed libero et velit qui suscipit. Deserunt laudantium quibusdam enim nostrum soluta qui ipsam non.", - onSlides: [], - created: "2022-01-30T15:42:42+01:00", - modified: "2022-01-30T15:42:42+01:00", - modifiedBy: "", - createdBy: "", - css: "", - }, - { - "@type": "Theme", - "@id": "/v2/themes/01FTNTE788816N6YCW9NVM2JQC", - title: "Sit vitae voluptas sint non.", - description: - "Optio quos qui illo error. Laborum vero a officia id corporis. Saepe provident esse hic eligendi. Culpa ut ab voluptas sed a.", - onSlides: [ - { - "@type": "Slide", - "@id": "/v2/slides/007ZR8C9811R741WAP1KHK0T09", - title: "Mollitia iure culpa exercitationem.", - description: - "Facilis nihil minus vel eum. Ut corrupti dicta quo modi temporibus est.", - created: "1978-09-14T10:51:02+01:00", - modified: "2022-01-30T15:42:42+01:00", - modifiedBy: "", - createdBy: "", - templateInfo: { - "@id": "/v2/templates/017BG9P0E0103F0TFS17FM016M", - options: [], - }, - theme: "/v2/themes/01FTNTE788816N6YCW9NVM2JQC", - onPlaylists: [], - duration: 92789, - published: { - from: "2021-08-04T05:24:19+02:00", - to: "2021-11-14T19:59:53+01:00", - }, - media: ["/v2/media/00MTYFFTN30XNZ0F350YM31TN5"], - content: [], - feed: null, - }, - { - "@type": "Slide", - "@id": "/v2/slides/00GYC65JP01DEG1F6H0R5Q0JBA", - title: "Voluptatem recusandae hic.", - description: - "Nulla occaecati praesentium quia magni ipsum dolor. Et aliquid natus molestiae ut quis. Ad voluptatum qui consequatur deleniti labore est. Voluptas hic veritatis quidem molestias qui.", - created: "1988-06-15T11:26:36+02:00", - modified: "2022-01-30T15:42:42+01:00", - modifiedBy: "", - createdBy: "", - templateInfo: { - "@id": "/v2/templates/002BAP34VD1EHG0E4J0D2Y00JW", - options: [], - }, - theme: "/v2/themes/01FTNTE788816N6YCW9NVM2JQC", - onPlaylists: [], - duration: 78938, - published: { - from: "2021-10-09T12:14:12+02:00", - to: "2021-12-24T16:18:08+01:00", - }, - media: [ - "/v2/media/00YB5658GH0TAE1A1N0XBB0YR7", - "/v2/media/01CVTNA9Y917EX09MY0FNX0GKA", - "/v2/media/01E4S5SPXR19MP1KGY16TD1XG2", - ], - content: [], - feed: null, - }, - { - "@type": "Slide", - "@id": "/v2/slides/00V28394SD1WBY1BPE1STN13MD", - title: "Reprehenderit neque nam mollitia quia.", - description: - "Omnis aliquam ea architecto dignissimos. Harum provident asperiores neque consequatur sit sed. Quasi ipsa illum et qui deleniti quo.", - created: "1999-06-23T10:05:00+02:00", - modified: "2022-01-30T15:42:42+01:00", - modifiedBy: "", - createdBy: "", - templateInfo: { - "@id": "/v2/templates/01FGC8EXSE1KCC1PTR0NHB0H3R", - options: [], - }, - theme: "/v2/themes/01FTNTE788816N6YCW9NVM2JQC", - onPlaylists: [], - duration: 69299, - published: { - from: "2021-06-09T03:25:34+02:00", - to: "2021-11-05T02:30:21+01:00", - }, - media: ["/v2/media/0041NS3DFY1EMS0XGQ025B0425"], - content: [], - feed: null, - }, - ], - created: "2022-01-30T15:42:42+01:00", - modified: "2022-01-30T15:42:42+01:00", - modifiedBy: "", - createdBy: "", - css: "", - }, - { - "@type": "Theme", - "@id": "/v2/themes/01FTNTE788816N6YCW9NVM2JQD", - title: "Enim ex eveniet facere.", - description: - "Delectus aut nam et eum. Fugit repellendus illo veritatis. Ex esse veritatis voluptate vel possimus. Aut incidunt sunt cumque asperiores incidunt iure sequi.", - onSlides: [ - { - "@type": "Slide", - "@id": "/v2/slides/003VYYZPPN1MQ61MEM1TE10G2J", - title: "Quos ducimus culpa consequuntur nulla aliquid.", - description: - "At quia quia voluptatibus eius. Delectus quia consequuntur aut nihil. Impedit sit aut dolorum aut dolore. Dolore beatae ipsa voluptas.", - created: "1974-03-21T14:49:33+01:00", - modified: "2022-01-30T15:42:42+01:00", - modifiedBy: "", - createdBy: "", - templateInfo: { - "@id": "/v2/templates/01FGC8EXSE1KCC1PTR0NHB0H3R", - options: [], - }, - theme: "/v2/themes/01FTNTE788816N6YCW9NVM2JQD", - onPlaylists: ["/v2/playlists/00XVQEW1EV0N3K0JZQ0TYS0T1G"], - duration: 77194, - published: { - from: "2021-07-02T08:33:02+02:00", - to: "2022-03-12T20:52:07+01:00", - }, - media: [ - "/v2/media/00GEQ02WW10SZ21F9G1MAZ0KR8", - "/v2/media/00MTYFFTN30XNZ0F350YM31TN5", - "/v2/media/00SSYSBFHR16PM09MQ0B0K0202", - "/v2/media/00X6A9GBZM0EHF05AA0B350D8E", - ], - content: [], - feed: null, - }, - { - "@type": "Slide", - "@id": "/v2/slides/00EBKSK8ZZ0Y301VFR0WGQ05F4", - title: "Maiores repudiandae quibusdam et rerum.", - description: - "At totam ut animi nisi ut ut qui. Aspernatur omnis quod temporibus non quo numquam. Dignissimos non eius numquam neque. Numquam modi tempora minus ad aut aut sit.", - created: "1985-08-21T22:37:57+02:00", - modified: "2022-01-30T15:42:42+01:00", - modifiedBy: "", - createdBy: "", - templateInfo: { - "@id": "/v2/templates/0044JYNRTJ1KD0128318R80B3Q", - options: [], - }, - theme: "/v2/themes/01FTNTE788816N6YCW9NVM2JQD", - onPlaylists: [], - duration: 66516, - published: { - from: "2021-08-30T14:57:29+02:00", - to: "2021-10-24T12:24:48+02:00", - }, - media: ["/v2/media/00031XCV6Z1W860V5R0SXB0D6R"], - content: [], - feed: null, - }, - { - "@type": "Slide", - "@id": "/v2/slides/00VRS9JQ7C1BZZ1NBA1XE50E19", - title: "Doloremque cum aliquam quis sint.", - description: - "Est quos beatae voluptatem optio et sit. Culpa fugiat quam et quisquam error a. Aut molestias quaerat quia aut non ipsum autem. Sunt aspernatur eos dolores quas alias. Culpa aut maiores consectetur.", - created: "2000-03-29T12:07:31+02:00", - modified: "2022-01-30T15:42:42+01:00", - modifiedBy: "", - createdBy: "", - templateInfo: { - "@id": "/v2/templates/01FGC8EXSE1KCC1PTR0NHB0H3R", - options: [], - }, - theme: "/v2/themes/01FTNTE788816N6YCW9NVM2JQD", - onPlaylists: [], - duration: 28295, - published: { - from: "2022-03-18T13:47:21+01:00", - to: "2022-03-19T12:34:17+01:00", - }, - media: [ - "/v2/media/003NVKRN4E183T0C431JF7036P", - "/v2/media/00C07KS3R00PEV24RF09870SH9", - "/v2/media/0170X462SF1P3205JP1R6K0553", - ], - content: [], - feed: null, - }, - { - "@type": "Slide", - "@id": "/v2/slides/00X2XD9Y011VB31K2T10JW0NR1", - title: "Eveniet repellendus et autem repellat.", - description: - "Rerum praesentium quo sequi. Accusamus fugiat voluptatem est quam. Esse voluptatem quia fugiat nisi delectus omnis.", - created: "2001-09-04T01:28:51+02:00", - modified: "2022-01-30T15:42:42+01:00", - modifiedBy: "", - createdBy: "", - templateInfo: { - "@id": "/v2/templates/017BG9P0E0103F0TFS17FM016M", - options: [], - }, - theme: "/v2/themes/01FTNTE788816N6YCW9NVM2JQD", - onPlaylists: ["/v2/playlists/007TM6JDGF1ECH07J10ZHY0S7P"], - duration: 99209, - published: { - from: "2021-11-11T07:58:12+01:00", - to: "2021-11-13T19:36:00+01:00", - }, - media: [ - "/v2/media/00J8PGYF1N12T60T200QN50KKJ", - "/v2/media/014S7FGP500Z8P18ZW12631TCP", - "/v2/media/019PTTMBQB0Z2D05VQ0HVC1M5M", - ], - content: [], - feed: null, - }, - { - "@type": "Slide", - "@id": "/v2/slides/011KV2WHQS0NDK1Q1Q01GY0XPS", - title: "Harum ducimus reiciendis.", - description: - "Est aut quis omnis. Cumque id officiis molestias accusamus est molestias. Nulla qui aut quo sunt et.", - created: "2006-08-10T03:26:54+02:00", - modified: "2022-01-30T15:42:42+01:00", - modifiedBy: "", - createdBy: "", - templateInfo: { - "@id": "/v2/templates/01FGC8EXSE1KCC1PTR0NHB0H3R", - options: [], - }, - theme: "/v2/themes/01FTNTE788816N6YCW9NVM2JQD", - onPlaylists: [], - duration: 7509, - published: { - from: "2021-07-22T07:48:05+02:00", - to: "2021-09-03T23:11:43+02:00", - }, - media: [ - "/v2/media/008ARWMTYJ0SX810490JQQ0DAK", - "/v2/media/00E98GAQXH1Y2C1G131MVH0YWZ", - "/v2/media/00MTYFFTN30XNZ0F350YM31TN5", - "/v2/media/0142VZYZ7H0XHE1XJB1M730VGS", - "/v2/media/015H8MEPVH13BE15A11MHJ0KAM", - ], - content: [], - feed: null, - }, - ], - created: "2022-01-30T15:42:42+01:00", - modified: "2022-01-30T15:42:42+01:00", - modifiedBy: "", - createdBy: "", - css: "", - }, - ], - "hydra:totalItems": 20, -}; +test.describe("Theme", () => { + test.beforeEach(async ({ page }) => { + await beforeEachTest(page); + }); -test.describe("Theme pages work", () => { test.beforeEach(async ({ page }) => { - await page.goto("/admin/themes/list"); - await page.route("**/themes*", async (route) => { - await route.fulfill({ json: themesJson }); - }); - await page.route("**/token", async (route) => { - const json = { - token: "1", - refresh_token: "2", - tenants: [ - { - tenantKey: "ABC", - title: "ABC Tenant", - description: "Description", - roles: ["ROLE_ADMIN"], - }, - ], - user: { - fullname: "John Doe", - email: "johndoe@example.com", - }, - }; - await route.fulfill({ json }); - }); - await expect(page).toHaveTitle(/OS2Display Admin/); - await page.getByLabel("Email").fill("johndoe@example.com"); - await page.getByLabel("Kodeord").fill("password"); - await page.locator("#login").click(); + await loginTest(page); + + await fulfillDataRoute(page, "**/themes*", themesJson); + // await fulfillEmptyRoutes(page, ["**/campaigns*", "**/screen-groups*", "**/layouts*"]); + + await page.getByRole("link", { name: "Temaer", exact: true }).click(); + await expect( + page.getByRole("heading", { name: "Temaer", exact: true }), + ).toBeVisible(); }); test("It loads create theme page", async ({ page }) => { - page.getByText("Opret nyt tema").click(); + await page.getByText("Opret nyt tema").click(); await expect(page.locator("#save_theme")).toBeVisible(); }); test("It display error toast on save error", async ({ page }) => { - await page.route("**/themes", async (route) => { - const json = { - "@context": "/contexts/Error", - "@type": "hydra:Error", - "hydra:title": "An error occurred", - "hydra:description": "An error occurred", - }; - await route.fulfill({ status: 500, json }); - }); - page.getByText("Opret nyt tema").click(); + await fulfillDataRoute(page, "**/themes", errorJson, 500); + await page.getByText("Opret nyt tema").click(); // Displays error toast and stays on page await expect( @@ -340,43 +58,11 @@ test.describe("Theme pages work", () => { }); test("It cancels create theme", async ({ page }) => { - page.getByText("Opret nyt tema").click(); + await page.getByText("Opret nyt tema").click(); await expect(page.locator("#cancel_theme")).toBeVisible(); await page.locator("#cancel_theme").click(); await expect(page.locator("#cancel_theme")).not.toBeVisible(); }); -}); - -test.describe("Themes list work", () => { - test.beforeEach(async ({ page }) => { - await page.goto("/admin/themes/list"); - await page.route("**/token", async (route) => { - const json = { - token: "1", - refresh_token: "2", - tenants: [ - { - tenantKey: "ABC", - title: "ABC Tenant", - description: "Description", - roles: ["ROLE_ADMIN"], - }, - ], - user: { - fullname: "John Doe", - email: "johndoe@example.com", - }, - }; - await route.fulfill({ json }); - }); - await page.route("**/themes*", async (route) => { - await route.fulfill({ json: themesJson }); - }); - await expect(page).toHaveTitle(/OS2Display Admin/); - await page.getByLabel("Email").fill("johndoe@example.com"); - await page.getByLabel("Kodeord").fill("password"); - await page.locator("#login").click(); - }); test("It loads themes list", async ({ page }) => { await expect(page.locator("table").locator("tbody")).not.toBeEmpty(); @@ -386,61 +72,7 @@ test.describe("Themes list work", () => { test("It goes to edit", async ({ page }) => { await expect(page.locator("#themeTitle")).not.toBeVisible(); - await page.route("**/themes*", async (route) => { - const json = { - "@context": "/contexts/Theme", - "@id": "/v2/themes", - "@type": "hydra:Collection", - "hydra:member": [ - { - "@type": "Theme", - "@id": "/v2/themes/01FTNTE788816N6YCW9NVM2JQB", - title: "Consequatur quisquam recusandae asperiores accusamus.", - description: - "Occaecati debitis et saepe eum sint dolorem. Enim ipsum inventore sed libero et velit qui suscipit. Deserunt laudantium quibusdam enim nostrum soluta qui ipsam non.", - onSlides: [], - created: "2022-01-30T15:42:42+01:00", - modified: "2022-01-30T15:42:42+01:00", - modifiedBy: "", - createdBy: "", - css: "", - }, - { - "@type": "Theme", - "@id": "/v2/themes/01FTNTE788816N6YCW9NVM2JQC", - title: "Sit vitae voluptas sint non.", - description: - "Optio quos qui illo error. Laborum vero a officia id corporis. Saepe provident esse hic eligendi. Culpa ut ab voluptas sed a.", - onSlides: [], - created: "2022-01-30T15:42:42+01:00", - modified: "2022-01-30T15:42:42+01:00", - modifiedBy: "", - createdBy: "", - css: "", - }, - ], - "hydra:totalItems": 2, - }; - await route.fulfill({ json }); - }); - - await page.route("**/themes/*", async (route) => { - const json = { - "@type": "Theme", - "@id": "/v2/themes/01FTNTE788816N6YCW9NVM2JQN", - title: "Hic minus et omnis porro.", - description: - "Odit quia nisi accusantium natus. Ut explicabo corporis eligendi ut. Sapiente ut qui quidem explicabo optio amet velit aut. Iure sed alias asperiores perspiciatis deserunt omnis inventore mollitia.", - onSlides: [], - created: "2022-01-30T15:42:42+01:00", - modified: "2022-01-30T15:42:42+01:00", - modifiedBy: "", - createdBy: "", - css: "", - }; - - await route.fulfill({ json }); - }); + await fulfillDataRoute(page, "**/themes/*", themesSingleJson); await page.locator("tbody").locator("tr td a").first().click(); await expect(page.locator("#themeTitle")).toBeVisible(); diff --git a/assets/tests/admin/admin-top-bar.spec.js b/assets/tests/admin/admin-top-bar.spec.js index ef754dd6..72fcdba4 100644 --- a/assets/tests/admin/admin-top-bar.spec.js +++ b/assets/tests/admin/admin-top-bar.spec.js @@ -1,38 +1,18 @@ import { test, expect } from "@playwright/test"; +import { + beforeEachTest, + fulfillEmptyRoutes, + loginTest, +} from "./test-helper.js"; +import { emptyJson } from "./data-fixtures.js"; test.describe("Nav items loads", () => { test.beforeEach(async ({ page }) => { - await page.goto("/admin/screen/create"); - await page.route("**/token", async (route) => { - const json = { - token: "1", - refresh_token: "2", - tenants: [ - { - tenantKey: "ABC", - title: "ABC Tenant", - description: "Description", - roles: ["ROLE_ADMIN"], - }, - ], - user: { - fullname: "John Doe", - email: "johndoe@example.com", - }, - }; - await route.fulfill({ json }); - }); - await page.route("**/layouts*", async (route) => { - const json = { - "@id": "/v2/layouts", - "hydra:member": [], - }; - await route.fulfill({ json }); - }); - await expect(page).toHaveTitle(/OS2Display Admin/); - await page.getByLabel("Email").fill("johndoe@example.com"); - await page.getByLabel("Kodeord").fill("password"); - await page.locator("#login").click(); + await beforeEachTest(page); + }); + + test.beforeEach(async ({ page }) => { + await loginTest(page); }); test("It loads", async ({ page }) => { @@ -40,51 +20,88 @@ test.describe("Nav items loads", () => { }); test("It navigates to slides list", async ({ page }) => { + await page.route("**/media*", async (route) => { + await route.fulfill({ json: emptyJson }); + }); + + // Go to media page first, since Slide is the starting page, to allow for link click. + await page.getByRole("link", { name: "Medier" }).click(); + await page.getByRole("link", { name: "Slides" }).click(); await expect(page.locator("h1")).toHaveText("Slides"); }); test("It navigates to media list", async ({ page }) => { + await page.route("**/media*", async (route) => { + await route.fulfill({ json: emptyJson }); + }); + await page.getByRole("link", { name: "Medier" }).click(); await expect(page.locator("h1")).toHaveText("Medier"); }); test("It navigates to screens list", async ({ page }) => { + await page.route("**/screens*", async (route) => { + await route.fulfill({ json: emptyJson }); + }); await page.getByRole("link", { name: "Skærme" }).click(); await expect(page.locator("h1")).toHaveText("Skærme"); }); test("It navigates to groups list", async ({ page }) => { + await page.route("**/screen-groups*", async (route) => { + await route.fulfill({ json: emptyJson }); + }); + await page.getByRole("link", { name: "Grupper" }).click(); await expect(page.locator("h1")).toHaveText("Grupper"); }); test("It navigates to playlists list", async ({ page }) => { + await page.route("**/playlists*", async (route) => { + await route.fulfill({ json: emptyJson }); + }); + await page.getByRole("link", { name: "Spillelister", exact: true }).click(); await expect(page.locator("h1")).toHaveText("Spillelister"); }); test("It navigates to themes list", async ({ page }) => { + await page.route("**/themes*", async (route) => { + await route.fulfill({ json: emptyJson }); + }); + await page.getByRole("link", { name: "Temaer" }).click(); await expect(page.locator("h1")).toHaveText("Temaer"); }); - test.skip("It navigates to create slide", async ({ page }) => { - await page.goto("/admin/screen/create"); - await page.getByRole("button", { name: "Tilføj" }).click(); - await page.getByRole("link", { name: "Nyt slide", exact: true }).click(); - await expect(page.locator("h1")).toHaveText("Opret nyt slide"); + test("It navigates to create slide", async ({ page }) => { + await page.route("**/playlists*", async (route) => { + await route.fulfill({ json: emptyJson }); + }); + await page.route("**/themes*", async (route) => { + await route.fulfill({ json: emptyJson }); + }); + await page.route("**/templates*", async (route) => { + await route.fulfill({ json: emptyJson }); + }); + + await page.getByLabel("Tilføj nyt slide").first().click(); + await expect(page.locator("h1")).toHaveText("Opret nyt slide:"); }); - test.skip("It navigates to create playlist", async ({ page }) => { - await page.getByRole("button", { name: "Tilføj" }).click(); - await page.getByRole("link", { name: "Ny spilleliste" }).click(); - await expect(page.locator("h1")).toHaveText("Opret nyt spilleliste"); + test("It navigates to create playlist", async ({ page }) => { + await page.route("**/tenants*", async (route) => { + await route.fulfill({ json: emptyJson }); + }); + await page.getByLabel("Tilføj ny spilleliste").first().click(); + await expect(page.locator("h1")).toHaveText("Opret ny spilleliste:"); }); - test.skip("It navigates to create screen", async ({ page }) => { - await page.getByRole("button", { name: "Tilføj" }).click(); - await page.getByRole("link", { name: "Ny skærm" }).click(); + test("It navigates to create screen", async ({ page }) => { + await fulfillEmptyRoutes(page, ["**/screen-groups*", "**/layouts*"]); + + await page.getByLabel("Tilføj ny skærm").first().click(); await expect(page.locator("h1")).toHaveText("Opret ny skærm"); }); diff --git a/assets/tests/admin/data-fixtures.js b/assets/tests/admin/data-fixtures.js new file mode 100644 index 00000000..503c7284 --- /dev/null +++ b/assets/tests/admin/data-fixtures.js @@ -0,0 +1,1670 @@ +const tokenAdminJson = { + token: "1", + refresh_token: "2", + tenants: [ + { + tenantKey: "ABC", + title: "ABC Tenant", + description: "Description", + roles: ["ROLE_ADMIN"], + }, + ], + user: { + fullname: "John Doe", + email: "johndoe@example.com", + }, +}; + +const tokenTenantsJson = { + token: "1", + refresh_token: "2", + tenants: [ + { + tenantKey: "ABC", + title: "ABC Tenant", + description: "Nulla quam ipsam voluptatem cupiditate.", + roles: ["ROLE_ADMIN"], + }, + { + tenantKey: "DEF", + title: "DEF Tenant", + description: "Inventore sed libero et.", + roles: ["ROLE_ADMIN"], + }, + { + tenantKey: "XYZ", + title: "XYC Tenant", + description: "Itaque quibusdam tempora velit porro ut velit.", + roles: ["ROLE_ADMIN"], + }, + ], + user: { + fullname: "John Doe", + email: "johndoe@example.com", + }, +}; + +const tokenEditorJson = { + token: "1", + refresh_token: "2", + tenants: [ + { + tenantKey: "ABC", + title: "ABC Tenant", + description: "Description", + roles: ["ROLE_EDITOR"], + }, + ], + user: { + fullname: "John Doe", + email: "johndoe@example.com", + }, +}; + +const feedSourcesJson = { + "@context": "/contexts/FeedSource", + "@id": "/v2/feed-sources", + "@type": "hydra:Collection", + "hydra:totalItems": 5, + "hydra:member": [ + { + "@id": "/v2/feed-sources/01JBBP48CS9CV80XRWRP8CAETJ", + "@type": "FeedSource", + title: "test 2", + description: "test 2", + outputType: "", + feedType: "test 2", + secrets: [], + feeds: [], + admin: [], + supportedFeedOutputType: "test 2", + modifiedBy: "admin@example.com", + createdBy: "admin@example.com", + id: "01JBBP48CS9CV80XRWRP8CAETJ", + created: "2024-10-29T09:26:25.000Z", + modified: "2024-10-29T09:26:25.000Z", + }, + { + "@id": "/v2/feed-sources/01JB9MSQEH75HC3GG75XCVP2WH", + "@type": "FeedSource", + title: "Ny datakilde test 3", + description: "Ny datakilde test 3", + outputType: "", + feedType: "App\\Feed\\RssFeedType", + secrets: [], + feeds: [ + "/v2/feeds/01JB9R7EPN9NPW117C22NY31KH", + "/v2/feeds/01JBBQMF72W2V36TWF6VXFA5Z7", + ], + admin: [ + { + key: "rss-url", + input: "input", + name: "url", + type: "url", + label: "Kilde", + helpText: "Her kan du skrive rss kilden", + formGroupClasses: "col-md-6", + }, + { + key: "rss-number-of-entries", + input: "input", + name: "numberOfEntries", + type: "number", + label: "Antal indgange", + helpText: + "Her kan du skrive, hvor mange indgange, der maksimalt skal vises.", + formGroupClasses: "col-md-6 mb-3", + }, + { + key: "rss-entry-duration", + input: "input", + name: "entryDuration", + type: "number", + label: "Varighed pr. indgang (i sekunder)", + helpText: "Her skal du skrive varigheden pr. indgang.", + formGroupClasses: "col-md-6 mb-3", + }, + ], + supportedFeedOutputType: "rss", + modifiedBy: "admin@example.com", + createdBy: "admin@example.com", + id: "01JB9MSQEH75HC3GG75XCVP2WH", + created: "2024-10-28T14:24:43.000Z", + modified: "2024-10-28T15:23:28.000Z", + }, + { + "@id": "/v2/feed-sources/01JB1DH8G4CXKGX5JRTYDHDPSP", + "@type": "FeedSource", + title: "Calendar datakilde test", + description: "test", + outputType: "", + feedType: "App\\Feed\\CalendarApiFeedType", + secrets: [], + feeds: [], + admin: [], + supportedFeedOutputType: "calendar", + modifiedBy: "", + createdBy: "", + id: "01JB1DH8G4CXKGX5JRTYDHDPSP", + created: "2024-10-25T10:43:50.000Z", + modified: "2024-10-25T10:43:50.000Z", + }, + { + "@id": "/v2/feed-sources/01J711Y2Q01VBJ1Y7A1HZQ0ZN6", + "@type": "FeedSource", + title: "feed_source_abc_notified", + description: + "Ut magnam veritatis velit ut doloribus id. Consequatur ut ipsum exercitationem aliquam laudantium voluptate voluptates perspiciatis. Id occaecati ea rerum facilis molestias et.", + outputType: "", + feedType: "App\\Feed\\RssFeedType", + secrets: [], + feeds: ["/v2/feeds/01GJD7S1KR10811MTA176C001R"], + admin: [ + { + key: "rss-url", + input: "input", + name: "url", + type: "url", + label: "Kilde", + helpText: "Her kan du skrive rss kilden", + formGroupClasses: "col-md-6", + }, + { + key: "rss-number-of-entries", + input: "input", + name: "numberOfEntries", + type: "number", + label: "Antal indgange", + helpText: + "Her kan du skrive, hvor mange indgange, der maksimalt skal vises.", + formGroupClasses: "col-md-6 mb-3", + }, + { + key: "rss-entry-duration", + input: "input", + name: "entryDuration", + type: "number", + label: "Varighed pr. indgang (i sekunder)", + helpText: "Her skal du skrive varigheden pr. indgang.", + formGroupClasses: "col-md-6 mb-3", + }, + ], + supportedFeedOutputType: "instagram", + modifiedBy: "", + createdBy: "", + id: "01J711Y2Q01VBJ1Y7A1HZQ0ZN6", + created: "2024-09-05T12:18:20.000Z", + modified: "2024-09-17T09:33:12.000Z", + }, + { + "@id": "/v2/feed-sources/01J1H8GVVR1CVJ1SQK0JXN1X4Q", + "@type": "FeedSource", + title: "feed_source_abc_1", + description: + "Totam eos molestias omnis aliquam quia qui voluptas. Non eum nihil ut sunt dolor.", + outputType: "", + feedType: "App\\Feed\\RssFeedType", + secrets: [], + feeds: ["/v2/feeds/01HD49075G0FNY1FNX12VE17K1"], + admin: [ + { + key: "rss-url", + input: "input", + name: "url", + type: "url", + label: "Kilde", + helpText: "Her kan du skrive rss kilden", + formGroupClasses: "col-md-6", + }, + { + key: "rss-number-of-entries", + input: "input", + name: "numberOfEntries", + type: "number", + label: "Antal indgange", + helpText: + "Her kan du skrive, hvor mange indgange, der maksimalt skal vises.", + formGroupClasses: "col-md-6 mb-3", + }, + { + key: "rss-entry-duration", + input: "input", + name: "entryDuration", + type: "number", + label: "Varighed pr. indgang (i sekunder)", + helpText: "Her skal du skrive varigheden pr. indgang.", + formGroupClasses: "col-md-6 mb-3", + }, + ], + supportedFeedOutputType: "rss", + modifiedBy: "", + createdBy: "", + id: "01J1H8GVVR1CVJ1SQK0JXN1X4Q", + created: "2024-06-29T05:47:07.000Z", + modified: "2024-10-21T18:01:25.000Z", + }, + ], +}; + +const feedSourcesJson2 = { + "@context": "/contexts/FeedSource", + "@id": "/v2/feed-sources", + "@type": "hydra:Collection", + "hydra:totalItems": 2, + "hydra:member": [ + { + "@id": "/v2/feed-sources/01J711Y2Q01VBJ1Y7A1HZQ0ZN6", + "@type": "FeedSource", + title: "feed_source_abc_notified", + description: + "Ut magnam veritatis velit ut doloribus id. Consequatur ut ipsum exercitationem aliquam laudantium voluptate voluptates perspiciatis. Id occaecati ea rerum facilis molestias et.", + outputType: "", + feedType: "App\\Feed\\RssFeedType", + secrets: [], + feeds: ["/v2/feeds/01GJD7S1KR10811MTA176C001R"], + admin: [ + { + key: "rss-url", + input: "input", + name: "url", + type: "url", + label: "Kilde", + helpText: "Her kan du skrive rss kilden", + formGroupClasses: "col-md-6", + }, + { + key: "rss-number-of-entries", + input: "input", + name: "numberOfEntries", + type: "number", + label: "Antal indgange", + helpText: + "Her kan du skrive, hvor mange indgange, der maksimalt skal vises.", + formGroupClasses: "col-md-6 mb-3", + }, + { + key: "rss-entry-duration", + input: "input", + name: "entryDuration", + type: "number", + label: "Varighed pr. indgang (i sekunder)", + helpText: "Her skal du skrive varigheden pr. indgang.", + formGroupClasses: "col-md-6 mb-3", + }, + ], + supportedFeedOutputType: "instagram", + modifiedBy: "", + createdBy: "", + id: "01J711Y2Q01VBJ1Y7A1HZQ0ZN6", + created: "2024-09-05T12:18:20.000Z", + modified: "2024-09-17T09:33:12.000Z", + }, + { + "@id": "/v2/feed-sources/01J1H8GVVR1CVJ1SQK0JXN1X4Q", + "@type": "FeedSource", + title: "feed_source_abc_1", + description: + "Totam eos molestias omnis aliquam quia qui voluptas. Non eum nihil ut sunt dolor.", + outputType: "", + feedType: "App\\Feed\\RssFeedType", + secrets: [], + feeds: ["/v2/feeds/01HD49075G0FNY1FNX12VE17K1"], + admin: [ + { + key: "rss-url", + input: "input", + name: "url", + type: "url", + label: "Kilde", + helpText: "Her kan du skrive rss kilden", + formGroupClasses: "col-md-6", + }, + { + key: "rss-number-of-entries", + input: "input", + name: "numberOfEntries", + type: "number", + label: "Antal indgange", + helpText: + "Her kan du skrive, hvor mange indgange, der maksimalt skal vises.", + formGroupClasses: "col-md-6 mb-3", + }, + { + key: "rss-entry-duration", + input: "input", + name: "entryDuration", + type: "number", + label: "Varighed pr. indgang (i sekunder)", + helpText: "Her skal du skrive varigheden pr. indgang.", + formGroupClasses: "col-md-6 mb-3", + }, + ], + supportedFeedOutputType: "rss", + modifiedBy: "", + createdBy: "", + id: "01J1H8GVVR1CVJ1SQK0JXN1X4Q", + created: "2024-06-29T05:47:07.000Z", + modified: "2024-10-21T18:01:25.000Z", + }, + ], +}; + +const feedSourceSingleJson = { + "@id": "/v2/feed-sources/01JBBP48CS9CV80XRWRP8CAETJ", + "@type": "FeedSource", + title: "feed_source_abc_notified", + description: + "Ut magnam veritatis velit ut doloribus id. Consequatur ut ipsum exercitationem aliquam laudantium voluptate voluptates perspiciatis. Id occaecati ea rerum facilis molestias et.", + outputType: "", + feedType: "App\\Feed\\RssFeedType", + secrets: [], + feeds: ["/v2/feeds/01GJD7S1KR10811MTA176C001R"], + supportedFeedOutputType: "instagram", + modifiedBy: "", + createdBy: "", + id: "01J711Y2Q01VBJ1Y7A1HZQ0ZN6", + created: "2024-09-05T12:18:20.000Z", + modified: "2024-09-17T09:33:12.000Z", +}; + +const errorJson = { + "@context": "/contexts/Error", + "@type": "hydra:Error", + "hydra:title": "An error occurred", + "hydra:description": "An error occurred", +}; + +const emptyJson = { + "@id": "/v2/slides", + "hydra:member": [], + "hydra:totalItems": 0, + "hydra:view": { + "@id": "/v2/slides?itemsPerPage=0\u0026title=", + "@type": "hydra:PartialCollectionView", + }, +}; + +const adminConfigJson = { + rejseplanenApiKey: null, + touchButtonRegions: false, + showScreenStatus: true, + loginMethods: [ + { + type: "username-password", + enabled: true, + provider: "username-password", + label: "", + }, + ], + enhancedPreview: true, +}; + +const clientConfigJson = { + loginCheckTimeout: 1000 * 60 * 60, + refreshTokenTimeout: 1000 * 60 * 60, + releaseTimestampIntervalTimeout: 1000 * 60 * 60, + pullStrategyInterval: 1000 * 60 * 60, + schedulingInterval: 1000 * 60 * 60, + debug: false, + logging: false, +}; + +const accessConfigJson = { + campaign: { + roles: ["ROLE_ADMIN"], + }, + screen: { + roles: ["ROLE_ADMIN"], + }, + settings: { + roles: ["ROLE_ADMIN"], + }, + groups: { + roles: ["ROLE_ADMIN"], + }, + shared: { + roles: ["ROLE_ADMIN"], + }, + users: { + roles: ["ROLE_ADMIN", "ROLE_EXTERNAL_USER_ADMIN"], + }, +}; + +const slidesJson1 = { + "@id": "/v2/slides", + "hydra:member": [ + { + "@type": "Slide", + "@id": "/v2/slides/00015Y0ZVC18N407JD07SM0YCF", + title: "Odio quidem ab dolores dolores.", + description: + "Accusamus odio atque numquam sunt asperiores ab. Consequatur similique amet velit sit qui doloremque dicta. Ducimus repellat facere odit quia deserunt id quos.", + created: "1970-01-15T17:36:43.000Z", + modified: "2021-12-09T12:01:33.000Z", + modifiedBy: "", + createdBy: "", + templateInfo: { + "@id": "/v2/templates/000YR9PMQC0GMC1TP90V9N07WX", + options: [], + }, + theme: "/v2/themes/01FPFH3WX93S4575W6Q9T8K0Y8", + onPlaylists: [], + duration: 107879, + published: { + from: null, + to: null, + }, + media: [ + "/v2/media/00042YZWK214MP01NA1GF517Q2", + "/v2/media/00TET3FF6K1Q011N5S12621E4H", + "/v2/media/01DCA32QJY1BH600BV2H140JDK", + ], + content: [], + }, + { + "@type": "Slide", + "@id": "/v2/slides/000E7VDT9E0GEJ0W5X040T1CB1", + title: "Sed ex quo minus doloremque possimus.", + description: + "Ipsum quo ipsam rerum ullam labore fugit ut. Repellendus a iusto dolore veritatis. Aut vero assumenda voluptates tempore doloremque expedita pariatur. Sint ducimus qui ducimus asperiores cum.", + created: "1970-06-27T00:53:51.000Z", + modified: "2021-12-09T12:01:33.000Z", + modifiedBy: "", + createdBy: "", + templateInfo: { + "@id": "/v2/templates/01FGC8EXSE1KCC1PTR0NHB0H3R", + options: [], + }, + theme: "", + onPlaylists: [], + duration: 80335, + published: { + from: "2021-03-19T22:20:54.000Z", + to: "2021-12-28T06:13:08.000Z", + }, + media: [ + "/v2/media/009H64MSPN1HEH0DTV2DEV085B", + "/v2/media/00SC0JP6PV2QYS06R70SS31K68", + ], + content: [], + }, + { + "@type": "Slide", + "@id": "/v2/slides/001M5VMMV81A6Q1KN10QY90HKE", + title: "Maxime numquam ducimus quos non.", + description: + "Aut ex id earum unde aut itaque vero id. Sunt praesentium harum vel autem.", + created: "1971-10-11T12:15:35.000Z", + modified: "2021-12-09T12:01:33.000Z", + modifiedBy: "", + createdBy: "", + templateInfo: { + "@id": "/v2/templates/000BGWFMBS15N807E60HP91JCX", + options: [], + }, + theme: "", + onPlaylists: [], + duration: 21254, + published: { + from: null, + to: null, + }, + media: ["/v2/media/00YMKGY3FM106Q0SRV077G0KEX"], + content: [], + }, + { + "@type": "Slide", + "@id": "/v2/slides/001M9W40CC0DQE02DR0PS41J7X", + title: "Est doloremque culpa et facere.", + description: + "Eos voluptatem sint fugiat magni omnis aut ut. Odit quod non rerum dolor. Quis deleniti occaecati perspiciatis et esse dolorum. Impedit sunt dolor dolores.", + created: "1971-10-13T01:40:56.000Z", + modified: "2021-12-09T12:01:33.000Z", + modifiedBy: "", + createdBy: "", + templateInfo: { + "@id": "/v2/templates/000BGWFMBS15N807E60HP91JCX", + options: [], + }, + theme: "", + onPlaylists: [], + duration: 60870, + published: { + from: "2021-02-26T20:12:10.000Z", + to: "2021-06-08T05:44:41.000Z", + }, + media: ["/v2/media/00BBYAKF190NMJ0FH118V91VV7"], + content: [], + }, + { + "@type": "Slide", + "@id": "/v2/slides/001W87XHKC0CX10P4215RV2K9B", + title: "Occaecati temporibus dolore maxime tenetur.", + description: + "Qui rem inventore non labore quam nihil in. Sunt rerum consequatur possimus cupiditate iure quo sit ratione. Et quis mollitia et.", + created: "1972-01-19T20:34:13.000Z", + modified: "2021-12-09T12:01:33.000Z", + modifiedBy: "", + createdBy: "", + templateInfo: { + "@id": "/v2/templates/002BAP34VD1EHG0E4J0D2Y00JW", + options: [], + }, + theme: "", + onPlaylists: [], + duration: 75535, + published: { + from: null, + to: "1996-02-16T00:54:17.000Z", + }, + media: ["/v2/media/0027FWF7Y014RG0KW9053S1AX6"], + content: [], + }, + { + "@type": "Slide", + "@id": "/v2/slides/0021MQ8MWP0MXK1NXB1J5918PM", + title: "Excepturi sed qui.", + description: + "Expedita numquam sunt autem nostrum. Sed eos molestiae earum natus. Rerum consectetur et eius illo qui sunt sapiente. Est dolore veritatis cupiditate occaecati.", + created: "1972-03-26T20:11:47.000Z", + modified: "2021-12-09T12:01:33.000Z", + modifiedBy: "", + createdBy: "", + templateInfo: { + "@id": "/v2/templates/017BG9P0E0103F0TFS17FM016M", + options: [], + }, + theme: "", + onPlaylists: [], + duration: 92829, + published: { + from: "2021-12-29T03:25:23.000Z", + to: null, + }, + media: ["/v2/media/001AX5W2S909NW0K5A0NVE0NS6"], + content: [], + }, + { + "@type": "Slide", + "@id": "/v2/slides/002T3E98DP1KK410PC0F2P037P", + title: "Voluptate aliquid maxime.", + description: + "Veniam labore odit omnis sint. Perferendis amet soluta quo quaerat nihil ex eius error.", + created: "1973-01-24T19:40:11.000Z", + modified: "2021-12-09T12:01:33.000Z", + modifiedBy: "", + createdBy: "", + templateInfo: { + "@id": "/v2/templates/002BAP34VD1EHG0E4J0D2Y00JW", + options: [], + }, + theme: "/v2/themes/01FPFH3WX93S4575W6Q9T8K0YN", + onPlaylists: [], + duration: 41589, + published: { + from: null, + to: "1989-10-31T03:15:44.000Z", + }, + media: [ + "/v2/media/00CX9N9EJE10WT1PVM10G51N13", + "/v2/media/016HWRGVWJ170F1AF2099T13JW", + "/v2/media/01DCA32QJY1BH600BV2H140JDK", + ], + content: [], + }, + { + "@type": "Slide", + "@id": "/v2/slides/00367HAGPF0XZA1SDN1ECH1NZX", + title: "Non ut nobis reprehenderit pariatur.", + description: + "Iste asperiores reprehenderit et mollitia et. Molestias iusto repudiandae a qui accusantium nam vel nesciunt.", + created: "1973-06-24T12:58:37.000Z", + modified: "2021-12-09T12:01:33.000Z", + modifiedBy: "", + createdBy: "", + templateInfo: { + "@id": "/v2/templates/000YR9PMQC0GMC1TP90V9N07WX", + options: [], + }, + theme: "", + onPlaylists: [], + duration: 106091, + published: { + from: "2022-01-11T14:56:13.000Z", + to: "2022-02-05T09:10:20.000Z", + }, + media: ["/v2/media/00F1M5J6BY1GS517RP1T1B1306"], + content: [], + }, + { + "@type": "Slide", + "@id": "/v2/slides/0039BTMNG61RJ606WT1QYN1X2K", + title: "Iusto aut et dicta neque.", + description: + "Nihil esse quisquam aut aliquid velit vitae. Dignissimos sit eos voluptatem corporis qui. Maxime qui eaque magni dolor et. Dolorem est velit qui ratione iure provident architecto.", + created: "1973-08-02T11:45:30.000Z", + modified: "2021-12-09T12:01:33.000Z", + modifiedBy: "", + createdBy: "", + templateInfo: { + "@id": "/v2/templates/016MHSNKCH1PQW1VY615JC19Y3", + options: [], + }, + theme: "/v2/themes/01FPFH3WX93S4575W6Q9T8K0YB", + onPlaylists: [], + duration: 79809, + published: { + from: "2021-08-10T06:26:30.000Z", + to: "2021-08-12T15:26:21.000Z", + }, + media: ["/v2/media/011ZBTXPF8123R1BA31CQR18HA"], + content: [], + }, + { + "@type": "Slide", + "@id": "/v2/slides/00446YF1RP0KZH0WQK1QJM1S4T", + title: "Inventore non nisi odit voluptatem et.", + description: + "Et in eum fugit culpa mollitia sunt. Et cupiditate molestias quia sapiente sint maxime qui. Beatae ad quod sed provident quas expedita exercitationem enim. Pariatur illo nam consequatur.", + created: "1974-07-02T03:19:57.000Z", + modified: "2021-12-09T12:01:33.000Z", + modifiedBy: "", + createdBy: "", + templateInfo: { + "@id": "/v2/templates/017BG9P0E0103F0TFS17FM016M", + options: [], + }, + theme: "/v2/themes/01FPFH3WXAX8JMJTQHBV2BYEDM", + onPlaylists: [], + duration: 37983, + published: { + from: "2022-01-24T16:30:24.000Z", + to: "2022-02-05T09:19:31.000Z", + }, + media: [ + "/v2/media/0010X8D6JJ03G50T1J1FCW1XH6", + "/v2/media/00F1M5J6BY1GS517RP1T1B1306", + "/v2/media/00KXYB7Z291JXC1SY30G161HQD", + ], + content: [], + }, + ], + "hydra:totalItems": 60, +}; + +const mediaListJson = { + "@context": "/contexts/Media", + "@id": "/v2/media", + "@type": "hydra:Collection", + "hydra:member": [ + { + "@type": "Media", + "@id": "/v2/media/001AG48FJC1NVA1EW20TSN13BP", + title: "Laudantium aut exercitationem rerum itaque unde.", + description: + "Quia ut iusto dolores reiciendis animi. Magnam aut ut officiis quae. Nostrum magni et dolore dignissimos in totam qui et.", + license: "Attribution-NonCommercial-NoDerivs License", + created: "1971-06-13T05:21:39+01:00", + modified: "2021-12-09T12:01:34+01:00", + modifiedBy: "", + createdBy: "", + media: [], + assets: { + type: "image/jpeg", + uri: "https://display.local.itkdev.dk/fixtures/template/images/mountain1.jpeg", + dimensions: { + height: 3456, + width: 5184, + }, + sha: "5a08dbb7fd3a074ed8659694c09cdb94fdb16cb1", + size: 8945324, + }, + }, + { + "@type": "Media", + "@id": "/v2/media/001AX5W2S909NW0K5A0NVE0NS6", + title: "Ut eos illum quod.", + description: + "Et id est illum veniam eos quam placeat. Maxime ab aut aut fugit. Occaecati ut ea et occaecati repellendus amet. Quia consequuntur quod vel deserunt maiores.", + license: "Attribution-NoDerivs License", + created: "1971-06-18T06:59:58+01:00", + modified: "2021-12-09T12:01:34+01:00", + modifiedBy: "", + createdBy: "", + media: [], + assets: { + type: "image/jpeg", + uri: "https://display.local.itkdev.dk/fixtures/template/images/mountain2.jpeg", + dimensions: { + height: 2592, + width: 3888, + }, + sha: "0654506b260c33544d39e5613716ef112ab38c7c", + size: 4855058, + }, + }, + ], + "hydra:totalItems": 100, +}; + +const onSaveJson = { + title: "A laudantium aspernatur qui.", + description: "Description", + created: "1991-09-10T22:36:56+02:00", + modified: "2021-12-09T12:01:33+01:00", + modifiedBy: "", + createdBy: "", +}; + +const playlistListJson = { + "@context": "/contexts/Playlist", + "@id": "/v2/playlists", + "@type": "hydra:Collection", + "hydra:member": [ + { + "@type": "Playlist", + "@id": "/v2/playlists/004ZP1XQ1G1MVZ1T0100YN0MPC", + title: "Et consequatur voluptatibus dolore ut ut.", + description: + "Atque maiores nam in occaecati labore labore inventore quo. Enim nemo totam hic. Ut suscipit id sint sed quia.", + schedules: [], + created: "1975-06-08T13:12:49.000Z", + modified: "2022-01-30T15:42:42.000Z", + modifiedBy: "", + createdBy: "", + slides: "/v2/playlists/004ZP1XQ1G1MVZ1T0100YN0MPC/slides", + campaignScreens: ["/v2/screens/00TH1ZRMZC141K1DMB1H7J03CS"], + campaignScreenGroups: [], + isCampaign: true, + published: { + from: "2022-03-23T21:30:21.000Z", + to: "2022-03-25T12:39:29.000Z", + }, + }, + { + "@type": "Playlist", + "@id": "/v2/playlists/007TM6JDGF1ECH07J10ZHY0S7P", + title: "Voluptas molestias nemo et.", + description: + "Aperiam quam sunt quia qui. Iusto ut deserunt veritatis nobis dolorem. Aliquid quo vel quia.", + schedules: [], + created: "1978-07-12T17:43:59.000Z", + modified: "2022-01-30T15:42:42.000Z", + modifiedBy: "", + createdBy: "", + slides: "/v2/playlists/007TM6JDGF1ECH07J10ZHY0S7P/slides", + campaignScreens: [], + campaignScreenGroups: [ + "/v2/screen-groups/00EQWMS5WA1WJE0WD81VF91DFH", + "/v2/screen-groups/0135RY0QPR1DVF0ZT70YHS1NX3", + "/v2/screen-groups/0135RY0QPR1DVF0ZT70YHS1NX3", + ], + isCampaign: false, + published: { + from: "2021-03-21T02:10:37.000Z", + to: "2021-11-08T12:13:31.000Z", + }, + }, + ], + "hydra:totalItems": 10, +}; + +const playlistSingleJson = { + "@id": "/v2/playlists/004ZP1XQ1G1MVZ1T0100YN0MPC", + title: "Et consequatur voluptatibus dolore ut ut.", + description: + "Atque maiores nam in occaecati labore labore inventore quo. Enim nemo totam hic. Ut suscipit id sint sed quia.", + schedules: [], + created: "1975-06-08T13:12:49.000Z", + modified: "2022-01-30T15:42:42.000Z", + modifiedBy: "", + createdBy: "", + slides: "/v2/playlists/004ZP1XQ1G1MVZ1T0100YN0MPC/slides", + campaignScreens: ["/v2/screens/00TH1ZRMZC141K1DMB1H7J03CS"], + campaignScreenGroups: [], + isCampaign: true, + published: { + from: "2022-03-23T21:30:21.000Z", + to: "2022-03-25T12:39:29.000Z", + }, +}; + +const screenGroupsListJson = { + "@id": "/v2/screen-groups", + "hydra:member": [ + { + "@type": "ScreenGroup", + "@id": "/v2/screen-groups/000RAH746Q1AD8011Z1JNV06N3", + title: "Cupiditate et quidem autem iusto.", + description: + "Eos quibusdam consectetur nisi consequatur voluptas. Unde maxime sunt quidem magnam. Sed ipsa voluptas qui occaecati ea nobis.", + created: "1970-10-30T08:30:07+01:00", + modified: "2021-12-09T12:01:33+01:00", + modifiedBy: "", + createdBy: "", + }, + { + "@type": "ScreenGroup", + "@id": "/v2/screen-groups/0012G98YZS0VTK0Z2T02AD1DC3", + title: "Dignissimos nihil non sit laudantium.", + description: + "Maxime dicta magnam est voluptas voluptas. Est omnis expedita harum reprehenderit debitis laboriosam ab omnis. Sed temporibus iste voluptatibus ut qui est non voluptatem.", + created: "1971-03-05T20:43:43+01:00", + modified: "2021-12-09T12:01:33+01:00", + modifiedBy: "", + createdBy: "", + }, + { + "@type": "ScreenGroup", + "@id": "/v2/screen-groups/001EZQXKKR0P7X0A3119Z016SB", + title: "Aut nam accusantium id aut.", + description: + "Et est nisi autem nihil. Blanditiis facere repellat et. Est et architecto modi laboriosam corporis et.", + created: "1971-08-07T23:56:38+01:00", + modified: "2021-12-09T12:01:33+01:00", + modifiedBy: "", + createdBy: "", + }, + { + "@type": "ScreenGroup", + "@id": "/v2/screen-groups/003J350X2D060H00TE1DW50640", + title: "Velit rem commodi necessitatibus eos.", + description: + "Non sequi sed fugit. Nihil cumque nesciunt hic recusandae rem suscipit sunt. Nostrum voluptatem ut consequatur non illum.", + created: "1973-11-18T23:15:03+01:00", + modified: "2021-12-09T12:01:33+01:00", + modifiedBy: "", + createdBy: "", + }, + { + "@type": "ScreenGroup", + "@id": "/v2/screen-groups/003Z784JQS1PNS1RX1003N0NCD", + title: "Quod esse voluptas ut.", + description: + "Deleniti velit est quasi commodi alias est minima. Harum iusto odio aperiam consequatur qui est. Vel ut id aperiam nobis fugiat et modi. Est dolores rerum id sed excepturi et.", + created: "1974-05-01T02:50:31+01:00", + modified: "2021-12-09T12:01:33+01:00", + modifiedBy: "", + createdBy: "", + }, + { + "@type": "ScreenGroup", + "@id": "/v2/screen-groups/009YS5ZYPH1B9T0JE01S290T5Y", + title: "Tenetur voluptatem quo rerum exercitationem.", + description: + "Suscipit provident odit in eius sed voluptatibus. Neque aut corporis aspernatur quo qui. Inventore nam est sed sed maiores odio.", + created: "1980-11-05T17:57:30+01:00", + modified: "2021-12-09T12:01:33+01:00", + modifiedBy: "", + createdBy: "", + }, + { + "@type": "ScreenGroup", + "@id": "/v2/screen-groups/00C1V2MX2S02N30EXM163A0E6X", + title: "Distinctio quisquam et totam molestias.", + description: + "Ad ipsam architecto eum repellat excepturi. Quos deleniti itaque ut reprehenderit aut rerum autem. Nihil et mollitia voluptatibus quis voluptatem. Ex eaque sint nostrum impedit.", + created: "1983-02-17T02:51:45+01:00", + modified: "2021-12-09T12:01:33+01:00", + modifiedBy: "", + createdBy: "", + }, + { + "@type": "ScreenGroup", + "@id": "/v2/screen-groups/00DDTCJCDX0H101N480E180K4B", + title: "Cumque facere nulla reiciendis.", + description: + "Veritatis doloremque delectus voluptas numquam dolores nobis. Dignissimos quo facere eum iure.", + created: "1984-08-16T16:14:03+02:00", + modified: "2021-12-09T12:01:33+01:00", + modifiedBy: "", + createdBy: "", + }, + { + "@type": "ScreenGroup", + "@id": "/v2/screen-groups/00GEPM6JRX0V2P0YST0JHA03CC", + title: "Ea aspernatur odit rerum.", + description: + "Adipisci tenetur placeat perspiciatis assumenda. Voluptas officiis magnam reprehenderit possimus non. Tempore delectus numquam veritatis harum natus.", + created: "1987-12-03T16:33:04+01:00", + modified: "2021-12-09T12:01:33+01:00", + modifiedBy: "", + createdBy: "", + }, + { + "@type": "ScreenGroup", + "@id": "/v2/screen-groups/00KXGYAJ4A1D5P0EA11SKF0BG8", + title: "A laudantium aspernatur qui.", + description: + "Non fugiat nobis occaecati. Sed ut velit beatae amet ea esse. Quo dolorem commodi magni at. Illum voluptatem neque nobis et ut. Ad rerum tempore vel commodi suscipit corrupti.", + created: "1991-09-10T22:36:56+02:00", + modified: "2021-12-09T12:01:33+01:00", + modifiedBy: "", + createdBy: "", + }, + ], + "hydra:totalItems": 20, +}; + +const screenGroupsSingleJson = { + "@id": "/v2/screen-groups/00GEPM6JRX0V2P0YST0JHA03CC", + title: "Ea aspernatur odit rerum.", + description: + "Adipisci tenetur placeat perspiciatis assumenda. Voluptas officiis magnam reprehenderit possimus non. Tempore delectus numquam veritatis harum natus.", + created: "1987-12-03T16:33:04+01:00", + modified: "2021-12-09T12:01:33+01:00", + modifiedBy: "", + createdBy: "", +}; + +const screensListJson = { + "@id": "/v2/screens", + "hydra:totalItems": 2, + "hydra:member": [ + { + "@type": "Screen", + "@id": "/v2/screens/00APXK73HQ11PM0X3P12EG14DZ", + title: "Ab eos dolorum minima inventore.", + description: + "Non inventore ab vitae. Voluptatem assumenda aliquam sunt nulla sint corrupti et. Nihil consectetur facere cum modi aliquid. Non aut voluptas voluptas laudantium.", + size: "42", + created: "1981-09-01T17:22:18+02:00", + modified: "2021-12-09T12:01:33+01:00", + modifiedBy: "", + createdBy: "", + layout: "/v2/layouts/009S1H8VER00GK086N0M1J16K9", + location: + "Natus aut est eveniet deleniti nihil voluptatum. Accusamus similique adipisci at qui molestiae quia nihil eligendi. Delectus repellendus ut asperiores ut debitis.", + regions: [], + inScreenGroups: "/v2/screens/00APXK73HQ11PM0X3P12EG14DZ/groups", + dimensions: { + width: 1920, + height: 1200, + }, + }, + { + "@type": "Screen", + "@id": "/v2/screens/00AYESM1AR002E0YKH0JQ70185", + title: "Accusantium aperiam mollitia consectetur.", + description: + "Asperiores id aut temporibus expedita quia rem. Sunt possimus voluptas voluptas exercitationem. Totam odio necessitatibus aut velit. Nisi est voluptates suscipit rerum perspiciatis.", + size: "55", + created: "1981-12-04T09:31:11+01:00", + modified: "2021-12-09T12:01:33+01:00", + modifiedBy: "", + createdBy: "", + layout: "/v2/layouts/009S1H8VER00GK086N0M1J16K9", + location: + "Occaecati beatae iure molestias sapiente nihil. Tempore quo quibusdam odit quia.", + regions: [], + inScreenGroups: "/v2/screens/00AYESM1AR002E0YKH0JQ70185/groups", + dimensions: { + width: 1920, + height: 1200, + }, + }, + ], +}; + +const templatesListJson = { + "@id": "/v2/templates", + "hydra:member": [ + { + "@type": "Template", + "@id": "/v2/templates/00XZXR5XDH0D1M16K10NYQ0A55", + title: "Est totam provident sunt.", + description: + "Tempora qui minus officia quis consequuntur voluptates. Quasi minima eveniet repudiandae laborum dolor quasi totam qui. Iusto enim inventore molestias amet aut.", + created: "2002-08-30T14:14:07+02:00", + modified: "2021-12-09T12:01:33+01:00", + modifiedBy: "", + createdBy: "", + resources: { + admin: + "http://www.harber.com/atque-inventore-consequatur-mollitia-ducimus-veritatis-doloribus-ad", + schema: "http://www.kulas.net/quia-unde-quos-error-modi-saepe", + component: "http://keebler.com/", + assets: { + type: "css", + url: "https://www.borer.biz/voluptas-blanditiis-et-quo-aut-culpa-reiciendis-dolorum", + }, + options: { + fade: true, + }, + content: { + text: "Accusantium exercitationem animi qui provident ipsa distinctio.", + }, + }, + }, + { + "@type": "Template", + "@id": "/v2/templates/016MHSNKCH1PQW1VY615JC19Y3", + title: "Ut exercitationem est quia ad quas.", + description: + "Laborum quod ut ducimus suscipit quia nostrum. Saepe ex voluptas aut. Sit numquam vel est sunt. Cupiditate excepturi non saepe in voluptatem vel rem quaerat. Magni aut eaque vel deleniti.", + created: "2012-01-28T09:17:22+01:00", + modified: "2021-12-09T12:01:33+01:00", + modifiedBy: "", + createdBy: "", + resources: { + admin: + "https://vandervort.com/sapiente-quo-est-rerum-nihil-sint-placeat-ipsa-id.html", + schema: + "http://www.gulgowski.com/debitis-voluptatem-earum-sed-totam-aut-impedit-facere", + component: + "https://lehner.com/officia-ducimus-ea-beatae-eum-amet-provident-sint.html", + assets: { + type: "css", + url: "http://www.emmerich.net/aliquam-excepturi-id-et-ab-voluptate.html", + }, + options: { + fade: true, + }, + content: { + text: "Ut qui assumenda ex vel quod dolorem perspiciatis eos quis.", + }, + }, + }, + { + "@type": "Template", + "@id": "/v2/templates/017X81AEJV2GJE0NC51KKK0EK8", + title: "Delectus magnam repudiandae molestiae et a.", + description: + "Consequuntur est ut commodi sed. Fugiat repellat harum assumenda sed illo voluptatem nobis fugit. At vero consequatur ut dignissimos. Et inventore ipsam ullam ullam dolor debitis quo saepe.", + created: "2013-06-17T03:02:15+02:00", + modified: "2021-12-09T12:01:33+01:00", + modifiedBy: "", + createdBy: "", + resources: { + admin: "http://www.ratke.com/libero-provident-nihil-minus-alias", + schema: "http://murazik.biz/", + component: + "http://kuhlman.biz/inventore-iure-tempora-perspiciatis-repudiandae-numquam-veniam-sequi-dolorem.html", + assets: { + type: "css", + url: "http://dibbert.biz/eius-et-non-autem", + }, + options: { + fade: true, + }, + content: { + text: "Praesentium at porro aut corporis quis in quia asperiores sed sit.", + }, + }, + }, + ], + "hydra:totalItems": 12, +}; + +const slidesListJson = { + "@id": "/v2/slides", + "hydra:member": [ + { + "@id": "/v2/slides/0086TQQC671WHA1S150MMF1Q3T", + title: "Adipisci vero quia.", + description: + "Dolores porro ex sed consectetur dolorem aspernatur. Recusandae voluptatem non a aut. Tenetur optio aut fugit reprehenderit. Non dolorum temporibus possimus iure aut quas.", + created: "1978-12-11T09:47:36.000Z", + modified: "2021-12-09T12:01:33.000Z", + modifiedBy: "", + createdBy: "", + templateInfo: { + "@id": "/v2/templates/00MWCNKC4P0X5C0AT70E741E2V", + options: [], + }, + theme: "", + onPlaylists: ["/v2/playlists/00S7ZQK8Y90R351YES1DJN0RKR"], + duration: 70592, + published: { + from: null, + to: "1989-08-28T18:14:52.000Z", + }, + media: ["/v2/media/00W2E6VC0V22QK1WYH0CMP151C"], + }, + { + "@id": "/v2/slides/00BEFT32281WT51SNJ0JXA11AV", + title: "Alias et id consequatur.", + description: + "Beatae reiciendis provident eos est totam repudiandae molestiae. Qui itaque officiis quibusdam. A nisi minus dolorum excepturi. Atque molestiae non velit ipsum consequatur nisi.", + created: "1982-06-21T15:09:47.000Z", + modified: "2021-12-09T12:01:33.000Z", + modifiedBy: "", + createdBy: "", + templateInfo: { + "@id": "/v2/templates/00PXXK8ND01SRF18YH1WN004VA", + options: [], + }, + theme: "/v2/themes/01FPFH3WX93S4575W6Q9T8K0YB", + onPlaylists: [], + duration: 40787, + published: { + from: "2021-03-12T18:12:47.000Z", + to: "2021-05-20T08:42:21.000Z", + }, + media: [ + "/v2/media/0010X8D6JJ03G50T1J1FCW1XH6", + "/v2/media/0043AB9VWE08071MNB08Q20JSG", + "/v2/media/009RGQK5AD19K21CZE11HC1DPX", + "/v2/media/00HM3QQ61107C41D7M0W2B1CEK", + "/v2/media/01BTDHQH3Z06N40M9V0TJ41YA8", + ], + }, + { + "@id": "/v2/slides/00BCX948J60YCR1TC009A31MPQ", + title: "Amet impedit eum quia quo.", + description: + "Quis nostrum voluptatum quam aut sint enim. Ut sed occaecati deserunt accusantium. Cupiditate et voluptatum ex quidem. Nobis rerum consequatur fugiat occaecati voluptas et.", + created: "1982-06-02T00:11:19.000Z", + modified: "2021-12-09T12:01:33.000Z", + modifiedBy: "", + createdBy: "", + templateInfo: { + "@id": "/v2/templates/000YR9PMQC0GMC1TP90V9N07WX", + options: [], + }, + theme: "", + onPlaylists: [], + duration: 4902, + published: { + from: null, + to: null, + }, + media: [ + "/v2/media/00007SBZ470CJ60C7J06H508R8", + "/v2/media/004MDCEC451GPJ1DW80D1Z026F", + ], + }, + { + "@id": "/v2/slides/000AGMKXFZ0QWX0V5013R80S3S", + title: "Aperiam maxime autem.", + description: + "Ea laboriosam rerum voluptatem. Quos odit veniam cum. Quia non expedita non facere id eum nesciunt. Fugit dolorum ipsa aspernatur.", + created: "1970-05-11T17:45:13.000Z", + modified: "2021-12-09T12:01:33.000Z", + modifiedBy: "", + createdBy: "", + templateInfo: { + "@id": "/v2/templates/018A0WH44D0X1N176Z16CC0HJP", + options: [], + }, + theme: "", + onPlaylists: [], + duration: 85133, + published: { + from: "2021-08-13T23:56:36.000Z", + to: null, + }, + media: [ + "/v2/media/00CGESC8E10CZA11EV2AYR1KWC", + "/v2/media/00HM3QQ61107C41D7M0W2B1CEK", + "/v2/media/01DCA32QJY1BH600BV2H140JDK", + ], + }, + { + "@id": "/v2/slides/014FR06WMH05WP17B71Q6Z1K7R", + title: "Architecto dolores facilis et.", + description: + "Aspernatur doloremque et perferendis dolorum hic. Ab vel praesentium non pariatur. Omnis ut magni voluptas et. Ducimus harum sed beatae labore.", + created: "2009-09-25T07:04:00.000Z", + modified: "2021-12-09T12:01:33.000Z", + modifiedBy: "", + createdBy: "", + templateInfo: { + "@id": "/v2/templates/00HH42EEHC05QT14VQ041R1KEY", + options: [], + }, + theme: "", + onPlaylists: ["/v2/playlists/00S7ZQK8Y90R351YES1DJN0RKR"], + duration: 11240, + published: { + from: "2020-12-24T06:17:03.000Z", + to: null, + }, + media: ["/v2/media/000NDA6BBM1A071RNN0SP40XNJ"], + }, + { + "@id": "/v2/slides/00J96KHGSC1HPH0VHW1FSX0CVD", + title: "Assumenda quaerat sint nihil perspiciatis.", + description: + "Eaque quaerat voluptas vitae rerum numquam dolore explicabo. Quas error voluptates quo est vel. Odit cum illum qui aut iure ipsum officiis.", + created: "1989-11-29T16:39:50.000Z", + modified: "2021-12-09T12:01:33.000Z", + modifiedBy: "", + createdBy: "", + templateInfo: { + "@id": "/v2/templates/001R8FR6VC10G51B200TK60QP3", + options: [], + }, + theme: "/v2/themes/01FPFH3WX93S4575W6Q9T8K0YN", + onPlaylists: [], + duration: 81995, + published: { + from: "2021-11-26T14:53:28.000Z", + to: null, + }, + media: [ + "/v2/media/009H64MSPN1HEH0DTV2DEV085B", + "/v2/media/00H1A2WZ1A06BK0W781ETS1EXZ", + "/v2/media/01BBCV60M903YC07RP09VN1JBZ", + ], + }, + { + "@id": "/v2/slides/00FTMVQRPS18QD0MBY0RQ30FP0", + title: "Atque nulla explicabo beatae.", + description: + "Repudiandae sapiente voluptatibus dolores voluptatem. Recusandae quia iste voluptates tempora fuga aliquam aut hic.", + created: "1987-03-29T10:52:22.000Z", + modified: "2021-12-09T12:01:33.000Z", + modifiedBy: "", + createdBy: "", + templateInfo: { + "@id": "/v2/templates/01F8MJT0AV24D602FN131008YY", + options: [], + }, + theme: "/v2/themes/01FPFH3WX93S4575W6Q9T8K0Y9", + onPlaylists: [], + duration: 32646, + published: { + from: "2021-09-04T10:08:04.000Z", + to: "2021-10-27T01:46:23.000Z", + }, + media: [ + "/v2/media/000NDA6BBM1A071RNN0SP40XNJ", + "/v2/media/003M4E1AQG052J0HPM1X670P4F", + "/v2/media/009RF9AGF80QP60ECM0CY01A1Y", + "/v2/media/00QWNXTD5X0VSF1EWQ1H7H0YS2", + ], + }, + { + "@id": "/v2/slides/008J6BKZMA0YHM04S813NF0DZV", + title: "Atque quis aut qui veritatis.", + description: + "Dolore expedita labore praesentium beatae. Labore maiores est voluptates cupiditate praesentium. Maiores est dolorem iusto.", + created: "1979-05-01T14:59:35.000Z", + modified: "2021-12-09T12:01:33.000Z", + modifiedBy: "", + createdBy: "", + templateInfo: { + "@id": "/v2/templates/011763DN4P0FRS1T6B09180KCW", + options: [], + }, + theme: "", + onPlaylists: ["/v2/playlists/01EDTHWKBM0TR3035E0Z631B8E"], + duration: 86942, + published: { + from: "2020-12-26T12:37:10.000Z", + to: null, + }, + media: [ + "/v2/media/00JBVT18N31VBA0S3805CN03MC", + "/v2/media/016SXZGDJR0T321KYJ19B91N1Z", + "/v2/media/01795VPQZX0GNM00T11JJ71BS8", + ], + }, + { + "@id": "/v2/slides/0118GD1EXJ1CSM1BHW0P7K1KQG", + title: "Aut odio illum et.", + description: + "Voluptatibus dicta dolor suscipit eos. Voluptate atque quia quo blanditiis sint est odio. Voluptatum expedita ipsa ut et placeat laborum. Modi molestias quibusdam sunt ratione nulla sit.", + created: "2006-03-22T07:17:31.000Z", + modified: "2021-12-09T12:01:33.000Z", + modifiedBy: "", + createdBy: "", + templateInfo: { + "@id": "/v2/templates/000AT4BWMM1GJZ17WE1M9M0RFB", + options: [], + }, + theme: "/v2/themes/01FPFH3WX93S4575W6Q9T8K0YB", + onPlaylists: [], + duration: 104864, + published: { + from: "2021-03-27T10:02:38.000Z", + to: null, + }, + media: [ + "/v2/media/002B3H5Z2K10M211AK1ERC02PM", + "/v2/media/00XA10EH8H0YYY1H4B1CC40SSA", + ], + }, + { + "@id": "/v2/slides/0151GSJGTE1JSE032C14JR0CQ2", + title: "Aut qui placeat consequatur aut.", + description: + "Officiis sit adipisci exercitationem ut vero nihil iste voluptas. Temporibus aut saepe rerum sint. Soluta perferendis aliquid voluptatem eos.", + created: "2010-05-04T04:35:53.000Z", + modified: "2021-12-09T12:01:33.000Z", + modifiedBy: "", + createdBy: "", + templateInfo: { + "@id": "/v2/templates/01F8MJT0AV24D602FN131008YY", + options: [], + }, + theme: "", + onPlaylists: [], + duration: 28141, + published: { + from: "2020-12-14T13:20:43.000Z", + to: "2021-02-11T10:45:45.000Z", + }, + media: [ + "/v2/media/00KXYB7Z291JXC1SY30G161HQD", + "/v2/media/01ENQN7X2F0ANK1BNA0J3513JX", + ], + }, + ], + "hydra:totalItems": 100, +}; + +const themesJson = { + "@context": "/contexts/Theme", + "@id": "/v2/themes", + "@type": "hydra:Collection", + "hydra:member": [ + { + "@type": "Theme", + "@id": "/v2/themes/01FTNTE788816N6YCW9NVM2JQB", + title: "Consequatur quisquam recusandae asperiores accusamus.", + description: + "Occaecati debitis et saepe eum sint dolorem. Enim ipsum inventore sed libero et velit qui suscipit. Deserunt laudantium quibusdam enim nostrum soluta qui ipsam non.", + onSlides: [], + created: "2022-01-30T15:42:42+01:00", + modified: "2022-01-30T15:42:42+01:00", + modifiedBy: "", + createdBy: "", + css: "", + }, + { + "@type": "Theme", + "@id": "/v2/themes/01FTNTE788816N6YCW9NVM2JQC", + title: "Sit vitae voluptas sint non.", + description: + "Optio quos qui illo error. Laborum vero a officia id corporis. Saepe provident esse hic eligendi. Culpa ut ab voluptas sed a.", + onSlides: [ + { + "@type": "Slide", + "@id": "/v2/slides/007ZR8C9811R741WAP1KHK0T09", + title: "Mollitia iure culpa exercitationem.", + description: + "Facilis nihil minus vel eum. Ut corrupti dicta quo modi temporibus est.", + created: "1978-09-14T10:51:02+01:00", + modified: "2022-01-30T15:42:42+01:00", + modifiedBy: "", + createdBy: "", + templateInfo: { + "@id": "/v2/templates/017BG9P0E0103F0TFS17FM016M", + options: [], + }, + theme: "/v2/themes/01FTNTE788816N6YCW9NVM2JQC", + onPlaylists: [], + duration: 92789, + published: { + from: "2021-08-04T05:24:19+02:00", + to: "2021-11-14T19:59:53+01:00", + }, + media: ["/v2/media/00MTYFFTN30XNZ0F350YM31TN5"], + content: [], + feed: null, + }, + { + "@type": "Slide", + "@id": "/v2/slides/00GYC65JP01DEG1F6H0R5Q0JBA", + title: "Voluptatem recusandae hic.", + description: + "Nulla occaecati praesentium quia magni ipsum dolor. Et aliquid natus molestiae ut quis. Ad voluptatum qui consequatur deleniti labore est. Voluptas hic veritatis quidem molestias qui.", + created: "1988-06-15T11:26:36+02:00", + modified: "2022-01-30T15:42:42+01:00", + modifiedBy: "", + createdBy: "", + templateInfo: { + "@id": "/v2/templates/002BAP34VD1EHG0E4J0D2Y00JW", + options: [], + }, + theme: "/v2/themes/01FTNTE788816N6YCW9NVM2JQC", + onPlaylists: [], + duration: 78938, + published: { + from: "2021-10-09T12:14:12+02:00", + to: "2021-12-24T16:18:08+01:00", + }, + media: [ + "/v2/media/00YB5658GH0TAE1A1N0XBB0YR7", + "/v2/media/01CVTNA9Y917EX09MY0FNX0GKA", + "/v2/media/01E4S5SPXR19MP1KGY16TD1XG2", + ], + content: [], + feed: null, + }, + { + "@type": "Slide", + "@id": "/v2/slides/00V28394SD1WBY1BPE1STN13MD", + title: "Reprehenderit neque nam mollitia quia.", + description: + "Omnis aliquam ea architecto dignissimos. Harum provident asperiores neque consequatur sit sed. Quasi ipsa illum et qui deleniti quo.", + created: "1999-06-23T10:05:00+02:00", + modified: "2022-01-30T15:42:42+01:00", + modifiedBy: "", + createdBy: "", + templateInfo: { + "@id": "/v2/templates/01FGC8EXSE1KCC1PTR0NHB0H3R", + options: [], + }, + theme: "/v2/themes/01FTNTE788816N6YCW9NVM2JQC", + onPlaylists: [], + duration: 69299, + published: { + from: "2021-06-09T03:25:34+02:00", + to: "2021-11-05T02:30:21+01:00", + }, + media: ["/v2/media/0041NS3DFY1EMS0XGQ025B0425"], + content: [], + feed: null, + }, + ], + created: "2022-01-30T15:42:42+01:00", + modified: "2022-01-30T15:42:42+01:00", + modifiedBy: "", + createdBy: "", + css: "", + }, + { + "@type": "Theme", + "@id": "/v2/themes/01FTNTE788816N6YCW9NVM2JQD", + title: "Enim ex eveniet facere.", + description: + "Delectus aut nam et eum. Fugit repellendus illo veritatis. Ex esse veritatis voluptate vel possimus. Aut incidunt sunt cumque asperiores incidunt iure sequi.", + onSlides: [ + { + "@type": "Slide", + "@id": "/v2/slides/003VYYZPPN1MQ61MEM1TE10G2J", + title: "Quos ducimus culpa consequuntur nulla aliquid.", + description: + "At quia quia voluptatibus eius. Delectus quia consequuntur aut nihil. Impedit sit aut dolorum aut dolore. Dolore beatae ipsa voluptas.", + created: "1974-03-21T14:49:33+01:00", + modified: "2022-01-30T15:42:42+01:00", + modifiedBy: "", + createdBy: "", + templateInfo: { + "@id": "/v2/templates/01FGC8EXSE1KCC1PTR0NHB0H3R", + options: [], + }, + theme: "/v2/themes/01FTNTE788816N6YCW9NVM2JQD", + onPlaylists: ["/v2/playlists/00XVQEW1EV0N3K0JZQ0TYS0T1G"], + duration: 77194, + published: { + from: "2021-07-02T08:33:02+02:00", + to: "2022-03-12T20:52:07+01:00", + }, + media: [ + "/v2/media/00GEQ02WW10SZ21F9G1MAZ0KR8", + "/v2/media/00MTYFFTN30XNZ0F350YM31TN5", + "/v2/media/00SSYSBFHR16PM09MQ0B0K0202", + "/v2/media/00X6A9GBZM0EHF05AA0B350D8E", + ], + content: [], + feed: null, + }, + { + "@type": "Slide", + "@id": "/v2/slides/00EBKSK8ZZ0Y301VFR0WGQ05F4", + title: "Maiores repudiandae quibusdam et rerum.", + description: + "At totam ut animi nisi ut ut qui. Aspernatur omnis quod temporibus non quo numquam. Dignissimos non eius numquam neque. Numquam modi tempora minus ad aut aut sit.", + created: "1985-08-21T22:37:57+02:00", + modified: "2022-01-30T15:42:42+01:00", + modifiedBy: "", + createdBy: "", + templateInfo: { + "@id": "/v2/templates/0044JYNRTJ1KD0128318R80B3Q", + options: [], + }, + theme: "/v2/themes/01FTNTE788816N6YCW9NVM2JQD", + onPlaylists: [], + duration: 66516, + published: { + from: "2021-08-30T14:57:29+02:00", + to: "2021-10-24T12:24:48+02:00", + }, + media: ["/v2/media/00031XCV6Z1W860V5R0SXB0D6R"], + content: [], + feed: null, + }, + { + "@type": "Slide", + "@id": "/v2/slides/00VRS9JQ7C1BZZ1NBA1XE50E19", + title: "Doloremque cum aliquam quis sint.", + description: + "Est quos beatae voluptatem optio et sit. Culpa fugiat quam et quisquam error a. Aut molestias quaerat quia aut non ipsum autem. Sunt aspernatur eos dolores quas alias. Culpa aut maiores consectetur.", + created: "2000-03-29T12:07:31+02:00", + modified: "2022-01-30T15:42:42+01:00", + modifiedBy: "", + createdBy: "", + templateInfo: { + "@id": "/v2/templates/01FGC8EXSE1KCC1PTR0NHB0H3R", + options: [], + }, + theme: "/v2/themes/01FTNTE788816N6YCW9NVM2JQD", + onPlaylists: [], + duration: 28295, + published: { + from: "2022-03-18T13:47:21+01:00", + to: "2022-03-19T12:34:17+01:00", + }, + media: [ + "/v2/media/003NVKRN4E183T0C431JF7036P", + "/v2/media/00C07KS3R00PEV24RF09870SH9", + "/v2/media/0170X462SF1P3205JP1R6K0553", + ], + content: [], + feed: null, + }, + { + "@type": "Slide", + "@id": "/v2/slides/00X2XD9Y011VB31K2T10JW0NR1", + title: "Eveniet repellendus et autem repellat.", + description: + "Rerum praesentium quo sequi. Accusamus fugiat voluptatem est quam. Esse voluptatem quia fugiat nisi delectus omnis.", + created: "2001-09-04T01:28:51+02:00", + modified: "2022-01-30T15:42:42+01:00", + modifiedBy: "", + createdBy: "", + templateInfo: { + "@id": "/v2/templates/017BG9P0E0103F0TFS17FM016M", + options: [], + }, + theme: "/v2/themes/01FTNTE788816N6YCW9NVM2JQD", + onPlaylists: ["/v2/playlists/007TM6JDGF1ECH07J10ZHY0S7P"], + duration: 99209, + published: { + from: "2021-11-11T07:58:12+01:00", + to: "2021-11-13T19:36:00+01:00", + }, + media: [ + "/v2/media/00J8PGYF1N12T60T200QN50KKJ", + "/v2/media/014S7FGP500Z8P18ZW12631TCP", + "/v2/media/019PTTMBQB0Z2D05VQ0HVC1M5M", + ], + content: [], + feed: null, + }, + { + "@type": "Slide", + "@id": "/v2/slides/011KV2WHQS0NDK1Q1Q01GY0XPS", + title: "Harum ducimus reiciendis.", + description: + "Est aut quis omnis. Cumque id officiis molestias accusamus est molestias. Nulla qui aut quo sunt et.", + created: "2006-08-10T03:26:54+02:00", + modified: "2022-01-30T15:42:42+01:00", + modifiedBy: "", + createdBy: "", + templateInfo: { + "@id": "/v2/templates/01FGC8EXSE1KCC1PTR0NHB0H3R", + options: [], + }, + theme: "/v2/themes/01FTNTE788816N6YCW9NVM2JQD", + onPlaylists: [], + duration: 7509, + published: { + from: "2021-07-22T07:48:05+02:00", + to: "2021-09-03T23:11:43+02:00", + }, + media: [ + "/v2/media/008ARWMTYJ0SX810490JQQ0DAK", + "/v2/media/00E98GAQXH1Y2C1G131MVH0YWZ", + "/v2/media/00MTYFFTN30XNZ0F350YM31TN5", + "/v2/media/0142VZYZ7H0XHE1XJB1M730VGS", + "/v2/media/015H8MEPVH13BE15A11MHJ0KAM", + ], + content: [], + feed: null, + }, + ], + created: "2022-01-30T15:42:42+01:00", + modified: "2022-01-30T15:42:42+01:00", + modifiedBy: "", + createdBy: "", + css: "", + }, + ], + "hydra:totalItems": 20, +}; + +const themesSingleJson = { + "@type": "Theme", + "@id": "/v2/themes/01FTNTE788816N6YCW9NVM2JQN", + title: "Hic minus et omnis porro.", + description: + "Odit quia nisi accusantium natus. Ut explicabo corporis eligendi ut. Sapiente ut qui quidem explicabo optio amet velit aut. Iure sed alias asperiores perspiciatis deserunt omnis inventore mollitia.", + onSlides: [], + created: "2022-01-30T15:42:42+01:00", + modified: "2022-01-30T15:42:42+01:00", + modifiedBy: "", + createdBy: "", + css: "", +}; + +export { + tokenAdminJson, + tokenTenantsJson, + tokenEditorJson, + feedSourcesJson, + feedSourcesJson2, + feedSourceSingleJson, + errorJson, + emptyJson, + slidesJson1, + accessConfigJson, + clientConfigJson, + adminConfigJson, + mediaListJson, + onSaveJson, + playlistListJson, + playlistSingleJson, + screenGroupsListJson, + screenGroupsSingleJson, + screensListJson, + templatesListJson, + slidesListJson, + themesJson, + themesSingleJson, +}; diff --git a/assets/tests/admin/test-helper.js b/assets/tests/admin/test-helper.js new file mode 100644 index 00000000..d29f9e41 --- /dev/null +++ b/assets/tests/admin/test-helper.js @@ -0,0 +1,65 @@ +import { + accessConfigJson, + adminConfigJson, + emptyJson, + feedSourcesJson, + tokenAdminJson, +} from "./data-fixtures.js"; +import { expect } from "@playwright/test"; + +const beforeEachTest = async (page) => { + // Abort all routes that are not registered. + await page.route("*", async (route) => { + await route.abort(); + }); + + // Handle calls to cccess-config. + await page.route("**/access-config.json*", async (route) => { + await route.fulfill({ json: accessConfigJson }); + }); + + // Handle all calls to config. + await page.route("**/config/admin", async (route) => { + await route.fulfill({ json: adminConfigJson }); + }); +}; + +const fulfillEmptyRoutes = async (page, routePatterns) => { + for (const routePattern of routePatterns) { + await page.route(routePattern, async (route) => { + await route.fulfill({ json: emptyJson }); + }); + } +}; + +const fulfillDataRoute = async (page, routePattern, data, status) => { + const result = { json: data }; + + if (status) { + result["status"] = status; + } + + await page.route(routePattern, async (route) => { + await route.fulfill(result); + }); +}; + +const loginTest = async (page) => { + await page.goto("/admin/slides/list"); + + await page.route("**/token", async (route) => { + await route.fulfill({ json: tokenAdminJson }); + }); + + await page.route("**/slides*", async (route) => { + await route.fulfill({ json: emptyJson }); + }); + + await expect(page).toHaveTitle(/OS2Display Admin/); + await page.getByLabel("Email").fill("admin@example.com"); + await page.getByLabel("Kodeord").fill("password"); + await page.locator("#login").click(); + await expect(page.locator("h1").getByText("Slides")).toBeVisible(); +}; + +export { loginTest, beforeEachTest, fulfillEmptyRoutes, fulfillDataRoute }; diff --git a/assets/tests/template/template-calendar.spec.js b/assets/tests/template/template-calendar.spec.js index 09ba1dfa..c24eb9ad 100644 --- a/assets/tests/template/template-calendar.spec.js +++ b/assets/tests/template/template-calendar.spec.js @@ -32,7 +32,7 @@ test("Calendar 1", async ({ page }) => { await expect(page.locator(".header-title")).toHaveText( "Møder i dag på Bautavej", ); - await expect(page.locator(".header-date")).toHaveText(new RegExp("06:00")); + await expect(page.locator(".header-date")).toHaveText(new RegExp("06:")); await expect(page.locator(".content-item")).toHaveCount(3); await expect(page.getByText("Hvad")).toBeVisible(); await expect(page.getByText("Hvornår")).toBeVisible(); diff --git a/config/routes.yaml b/config/routes.yaml index 505235fa..82b9feaa 100644 --- a/config/routes.yaml +++ b/config/routes.yaml @@ -34,7 +34,17 @@ client: # https://symfony.com/doc/current/routing.html#slash-characters-in-route-parameters subroutes: '.*' methods: ['GET'] - controller: App\Controller\Client\ClientController' + controller: App\Controller\Client\ClientController + +admin_config: + path: /config/admin + methods: ['GET'] + controller: App\Controller\Admin\AdminConfigController + +client_config: + path: /config/client + methods: ['GET'] + controller: App\Controller\Client\ClientConfigController when@dev: templates: diff --git a/config/services.yaml b/config/services.yaml index 429b8939..1e6406c7 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -53,7 +53,7 @@ services: Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface: '@Lexik\Bundle\JWTAuthenticationBundle\Security\Http\Authentication\AuthenticationFailureHandler' Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface: '@Lexik\Bundle\JWTAuthenticationBundle\Security\Http\Authentication\AuthenticationSuccessHandler' - App\Controller\Admin\AdminController: + App\Controller\Admin\AdminConfigController: arguments: $rejseplanenApiKey: '%env(ADMIN_REJSEPLANEN_APIKEY)%' $touchButtonRegions: '%env(bool:ADMIN_TOUCH_BUTTON_REGIONS)%' @@ -61,7 +61,7 @@ services: $loginMethods: '%env(json:ADMIN_LOGIN_METHODS)%' $enhancedPreview: '%env(bool:ADMIN_ENHANCED_PREVIEW)%' - App\Controller\Client\ClientController: + App\Controller\Client\ClientConfigController: arguments: $loginCheckTimeout: '%env(int:CLIENT_LOGIN_CHECK_TIMEOUT)%' $refreshTokenTimeout: '%env(int:CLIENT_REFRESH_TOKEN_TIMEOUT)%' diff --git a/docker-compose.override.yml b/docker-compose.override.yml index a831755c..efb2d29e 100644 --- a/docker-compose.override.yml +++ b/docker-compose.override.yml @@ -1,8 +1,4 @@ services: - phpfpm: - environment: - - PHP_MEMORY_LIMIT=512M - nginx: labels: # HTTPS config - uncomment to enable redirect from :80 to :443 @@ -21,16 +17,26 @@ services: command: npm run dev networks: - app + - frontend + ports: + - "5173" working_dir: /app environment: - NODE_ENV=development volumes: - .:/app:delegated + labels: + - "traefik.enable=true" + - "traefik.docker.network=frontend" + - "traefik.http.routers.${COMPOSE_PROJECT_NAME}node.rule=Host(`node-${COMPOSE_DOMAIN}`)" + # HTTPS config - uncomment to enable redirect from :80 to :443 + - "traefik.http.routers.${COMPOSE_PROJECT_NAME}node.middlewares=redirect-to-https" + - "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https" playwright: # https://playwright.dev/docs/docker # This Playwright version should match the one in `package.json`. - image: mcr.microsoft.com/playwright:v1.52.0 + image: mcr.microsoft.com/playwright:v1.53.2 networks: - app depends_on: diff --git a/docs/test.md b/docs/test.md new file mode 100644 index 00000000..d0ed9808 --- /dev/null +++ b/docs/test.md @@ -0,0 +1,57 @@ +# Test + +## Playwright + +To test the React apps we use playwright. + +### Updating Playwright + +It is important that the versions of the playwright container and the library imported in package.json align. + +See the `docker-compose.override.yml` playwright entry and the version imported in package.json. + +### Dev mode + +This project includes a test script that handles building assets, running +Playwright tests, and stops and starts the node container. This script tests the +*built* files. + +```bash +./scripts/test {TEST-PATH} +``` + +TEST-PATH is optional, and is the specific test file or directory to run like +`admin`/`client`/`template` or a specific file, e.g. `admin-app.spec.js`. If +TEST-PATH is omitted, all tests will run. + +To run tests locally, there are a few options. + +To run from the developer machine: + +```shell +BASE_URL="https://display.local.itkdev.dk" npx playwright test template +``` + +In interactive mode: + +```shell +BASE_URL="https://display.local.itkdev.dk" npx playwright test template --ui +``` + +### Prod mode + +Another option is to run the tests on the built javascript assets through the playwright container. +This is the option that runs in Github Actions. + +```shell +# Stop the node container, to avoid Vite build dev assets. +docker compose stop node + +# Build the assets +docker compose run --rm node npm run build + +# Run the test +docker compose run --rm playwright npx playwright test + +# To return to vite dev mode, restart the node container. +``` diff --git a/package-lock.json b/package-lock.json index 74f6a777..c6b41214 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,6 +15,7 @@ "@hello-pangea/dnd": "^16.0.0", "@popperjs/core": "^2.11.8", "@u-wave/react-vimeo": "^0.9.11", + "@vitejs/plugin-react-oxc": "^0.3.0", "bootstrap": "^5.3.7", "crypto-js": "^4.0.0", "dayjs": "^1.10.5", @@ -57,10 +58,10 @@ "ulid": "^2.3.0" }, "devDependencies": { - "@playwright/test": "^1.52.0", + "@playwright/test": "1.53.2", "@reduxjs/toolkit": "^1.6.1", "@vitejs/plugin-react": "^4.6.0", - "@vitejs/plugin-react-swc": "^3.10.2", + "esbuild": "^0.25.8", "sass": "^1.88.9", "typescript": "^4.4.2", "vite": "npm:rolldown-vite@^7.0.3", @@ -118,30 +119,30 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.27.2.tgz", - "integrity": "sha512-TUtMJYRPyUb/9aU8f3K0mjmjf6M9N5Woshn2CS6nqJSeJtTtQcpLUXjGt9vbF8ZGff0El99sWkLgzwW3VXnxZQ==", + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.0.tgz", + "integrity": "sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.27.7", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.27.7.tgz", - "integrity": "sha512-BU2f9tlKQ5CAthiMIgpzAh4eDTLWo1mqi9jqE2OxMG0E/OM199VJt2q8BztTxpnSW0i1ymdwLXRJnYzvDM5r2w==", + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.0.tgz", + "integrity": "sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ==", "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.27.5", + "@babel/generator": "^7.28.0", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.27.3", "@babel/helpers": "^7.27.6", - "@babel/parser": "^7.27.7", + "@babel/parser": "^7.28.0", "@babel/template": "^7.27.2", - "@babel/traverse": "^7.27.7", - "@babel/types": "^7.27.7", + "@babel/traverse": "^7.28.0", + "@babel/types": "^7.28.0", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -157,15 +158,15 @@ } }, "node_modules/@babel/generator": { - "version": "7.27.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.27.5.tgz", - "integrity": "sha512-ZGhA37l0e/g2s1Cnzdix0O3aLYm66eF8aufiVteOgnwxgnRP8GoyMj7VWsgWnQbVKXyge7hqrFh2K2TQM6t1Hw==", + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.0.tgz", + "integrity": "sha512-lJjzvrbEeWrhB4P3QBsH7tey117PjLZnDbLiQEKjQ/fNJTjuq4HSqgFA+UNSwZT8D7dxxbnuSBMsa1lrWzKlQg==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.27.5", - "@babel/types": "^7.27.3", - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25", + "@babel/parser": "^7.28.0", + "@babel/types": "^7.28.0", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" }, "engines": { @@ -173,12 +174,12 @@ } }, "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.1.tgz", - "integrity": "sha512-WnuuDILl9oOBbKnb4L+DyODx7iC47XfzmNCpTttFsSp6hTG7XZxu60+4IO+2/hPfcGOoKbFiwoI/+zwARbNQow==", + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", + "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==", "license": "MIT", "dependencies": { - "@babel/types": "^7.27.1" + "@babel/types": "^7.27.3" }, "engines": { "node": ">=6.9.0" @@ -200,6 +201,15 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-module-imports": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", @@ -267,25 +277,25 @@ } }, "node_modules/@babel/helpers": { - "version": "7.27.6", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.6.tgz", - "integrity": "sha512-muE8Tt8M22638HU31A3CgfSUciwz1fhATfoVai05aPXGor//CdWDCbnlY1yvBPo07njuVOCNGCSp/GTt12lIug==", + "version": "7.28.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.2.tgz", + "integrity": "sha512-/V9771t+EgXz62aCcyofnQhGM8DQACbRhvzKFsXKC9QM+5MadF8ZmIm0crDMaz3+o0h0zXfJnd4EhbYbxsrcFw==", "license": "MIT", "dependencies": { "@babel/template": "^7.27.2", - "@babel/types": "^7.27.6" + "@babel/types": "^7.28.2" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.27.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.7.tgz", - "integrity": "sha512-qnzXzDXdr/po3bOTbTIQZ7+TxNKxpkN5IifVLXS+r7qwynkZfPyjZfE7hCXbo7IoO9TNcSyibgONsf2HauUd3Q==", + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.0.tgz", + "integrity": "sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==", "license": "MIT", "dependencies": { - "@babel/types": "^7.27.7" + "@babel/types": "^7.28.0" }, "bin": { "parser": "bin/babel-parser.js" @@ -342,9 +352,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.1.tgz", - "integrity": "sha512-1x3D2xEk2fRo3PAhwQwu5UubzgiVWSXTBfWpVd2Mx2AzRqJuDJCsgaDVZ7HB5iGzDW1Hl1sWN2mFyKjmR9uAog==", + "version": "7.28.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.2.tgz", + "integrity": "sha512-KHp2IflsnGywDjBWDkR9iEqiWSpc8GIi0lgTT3mOElT0PP1tG26P4tmFI2YvAdzgq9RGyoHZQEIEdZy6Ec5xCA==", "license": "MIT", "engines": { "node": ">=6.9.0" @@ -365,27 +375,27 @@ } }, "node_modules/@babel/traverse": { - "version": "7.27.7", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.27.7.tgz", - "integrity": "sha512-X6ZlfR/O/s5EQ/SnUSLzr+6kGnkg8HXGMzpgsMsrJVcfDtH1vIp6ctCN4eZ1LS5c0+te5Cb6Y514fASjMRJ1nw==", + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.0.tgz", + "integrity": "sha512-mGe7UK5wWyh0bKRfupsUchrQGqvDbZDbKJw+kcRGSmdHVYrv+ltd0pnpDTVpiTqnaBru9iEvA8pz8W46v0Amwg==", "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.27.5", - "@babel/parser": "^7.27.7", + "@babel/generator": "^7.28.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.0", "@babel/template": "^7.27.2", - "@babel/types": "^7.27.7", - "debug": "^4.3.1", - "globals": "^11.1.0" + "@babel/types": "^7.28.0", + "debug": "^4.3.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/types": { - "version": "7.27.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.7.tgz", - "integrity": "sha512-8OLQgDScAOHXnAz2cV+RfzzNMipuLVBz2biuAJFMV9bfkNf393je3VM8CLkjQodW5+iWsSJdSgSWT6rsZoXHPw==", + "version": "7.28.2", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.2.tgz", + "integrity": "sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==", "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.27.1", @@ -396,22 +406,20 @@ } }, "node_modules/@emnapi/core": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.4.3.tgz", - "integrity": "sha512-4m62DuCE07lw01soJwPiBGC0nAww0Q+RY70VZ+n49yDIO13yyinhbWCeNnaob0lakDtWQzSdtNWzJeOJt2ma+g==", - "dev": true, + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.4.5.tgz", + "integrity": "sha512-XsLw1dEOpkSX/WucdqUhPWP7hDxSvZiY+fsUC14h+FtQ2Ifni4znbBt8punRX+Uj2JG/uDb8nEHVKvrVlvdZ5Q==", "license": "MIT", "optional": true, "dependencies": { - "@emnapi/wasi-threads": "1.0.2", + "@emnapi/wasi-threads": "1.0.4", "tslib": "^2.4.0" } }, "node_modules/@emnapi/runtime": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.4.3.tgz", - "integrity": "sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ==", - "dev": true, + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.4.5.tgz", + "integrity": "sha512-++LApOtY0pEEz1zrd9vy1/zXVaVJJ/EbAF3u0fXIzPJEDtnITsBGbbK0EkM72amhl/R5b+5xx0Y/QhcVOpuulg==", "license": "MIT", "optional": true, "dependencies": { @@ -419,10 +427,9 @@ } }, "node_modules/@emnapi/wasi-threads": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.0.2.tgz", - "integrity": "sha512-5n3nTJblwRi8LlXkJ9eBzu+kZR8Yxcc7ubakyQTFzPMtIhFpUBRbsnc2Dv88IZDIbCDlBiWrknhB4Lsz7mg6BA==", - "dev": true, + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.0.4.tgz", + "integrity": "sha512-PJR+bOmMOPH8AtcTGAyYNiuJ3/Fcoj2XN/gBEWzDIKh254XO+mM9XoXHk5GNEhodxeMznbg7BlRojVbKN+gC6g==", "license": "MIT", "optional": true, "dependencies": { @@ -565,478 +572,444 @@ "license": "MIT" }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.4.tgz", - "integrity": "sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q==", + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.8.tgz", + "integrity": "sha512-urAvrUedIqEiFR3FYSLTWQgLu5tb+m0qZw0NBEasUeo6wuqatkMDaRT+1uABiGXEu5vqgPd7FGE1BhsAIy9QVA==", "cpu": [ "ppc64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "aix" ], - "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/android-arm": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.4.tgz", - "integrity": "sha512-QNdQEps7DfFwE3hXiU4BZeOV68HHzYwGd0Nthhd3uCkkEKK7/R6MTgM0P7H7FAs5pU/DIWsviMmEGxEoxIZ+ZQ==", + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.8.tgz", + "integrity": "sha512-RONsAvGCz5oWyePVnLdZY/HHwA++nxYWIX1atInlaW6SEkwq6XkP3+cb825EUcRs5Vss/lGh/2YxAb5xqc07Uw==", "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "android" ], - "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/android-arm64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.4.tgz", - "integrity": "sha512-bBy69pgfhMGtCnwpC/x5QhfxAz/cBgQ9enbtwjf6V9lnPI/hMyT9iWpR1arm0l3kttTr4L0KSLpKmLp/ilKS9A==", + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.8.tgz", + "integrity": "sha512-OD3p7LYzWpLhZEyATcTSJ67qB5D+20vbtr6vHlHWSQYhKtzUYrETuWThmzFpZtFsBIxRvhO07+UgVA9m0i/O1w==", "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "android" ], - "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/android-x64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.4.tgz", - "integrity": "sha512-TVhdVtQIFuVpIIR282btcGC2oGQoSfZfmBdTip2anCaVYcqWlZXGcdcKIUklfX2wj0JklNYgz39OBqh2cqXvcQ==", + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.8.tgz", + "integrity": "sha512-yJAVPklM5+4+9dTeKwHOaA+LQkmrKFX96BM0A/2zQrbS6ENCmxc4OVoBs5dPkCCak2roAD+jKCdnmOqKszPkjA==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "android" ], - "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.4.tgz", - "integrity": "sha512-Y1giCfM4nlHDWEfSckMzeWNdQS31BQGs9/rouw6Ub91tkK79aIMTH3q9xHvzH8d0wDru5Ci0kWB8b3up/nl16g==", + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.8.tgz", + "integrity": "sha512-Jw0mxgIaYX6R8ODrdkLLPwBqHTtYHJSmzzd+QeytSugzQ0Vg4c5rDky5VgkoowbZQahCbsv1rT1KW72MPIkevw==", "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "darwin" ], - "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.4.tgz", - "integrity": "sha512-CJsry8ZGM5VFVeyUYB3cdKpd/H69PYez4eJh1W/t38vzutdjEjtP7hB6eLKBoOdxcAlCtEYHzQ/PJ/oU9I4u0A==", + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.8.tgz", + "integrity": "sha512-Vh2gLxxHnuoQ+GjPNvDSDRpoBCUzY4Pu0kBqMBDlK4fuWbKgGtmDIeEC081xi26PPjn+1tct+Bh8FjyLlw1Zlg==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "darwin" ], - "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.4.tgz", - "integrity": "sha512-yYq+39NlTRzU2XmoPW4l5Ifpl9fqSk0nAJYM/V/WUGPEFfek1epLHJIkTQM6bBs1swApjO5nWgvr843g6TjxuQ==", + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.8.tgz", + "integrity": "sha512-YPJ7hDQ9DnNe5vxOm6jaie9QsTwcKedPvizTVlqWG9GBSq+BuyWEDazlGaDTC5NGU4QJd666V0yqCBL2oWKPfA==", "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "freebsd" ], - "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.4.tgz", - "integrity": "sha512-0FgvOJ6UUMflsHSPLzdfDnnBBVoCDtBTVyn/MrWloUNvq/5SFmh13l3dvgRPkDihRxb77Y17MbqbCAa2strMQQ==", + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.8.tgz", + "integrity": "sha512-MmaEXxQRdXNFsRN/KcIimLnSJrk2r5H8v+WVafRWz5xdSVmWLoITZQXcgehI2ZE6gioE6HirAEToM/RvFBeuhw==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "freebsd" ], - "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/linux-arm": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.4.tgz", - "integrity": "sha512-kro4c0P85GMfFYqW4TWOpvmF8rFShbWGnrLqlzp4X1TNWjRY3JMYUfDCtOxPKOIY8B0WC8HN51hGP4I4hz4AaQ==", + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.8.tgz", + "integrity": "sha512-FuzEP9BixzZohl1kLf76KEVOsxtIBFwCaLupVuk4eFVnOZfU+Wsn+x5Ryam7nILV2pkq2TqQM9EZPsOBuMC+kg==", "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.4.tgz", - "integrity": "sha512-+89UsQTfXdmjIvZS6nUnOOLoXnkUTB9hR5QAeLrQdzOSWZvNSAXAtcRDHWtqAUtAmv7ZM1WPOOeSxDzzzMogiQ==", + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.8.tgz", + "integrity": "sha512-WIgg00ARWv/uYLU7lsuDK00d/hHSfES5BzdWAdAig1ioV5kaFNrtK8EqGcUBJhYqotlUByUKz5Qo6u8tt7iD/w==", "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.4.tgz", - "integrity": "sha512-yTEjoapy8UP3rv8dB0ip3AfMpRbyhSN3+hY8mo/i4QXFeDxmiYbEKp3ZRjBKcOP862Ua4b1PDfwlvbuwY7hIGQ==", + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.8.tgz", + "integrity": "sha512-A1D9YzRX1i+1AJZuFFUMP1E9fMaYY+GnSQil9Tlw05utlE86EKTUA7RjwHDkEitmLYiFsRd9HwKBPEftNdBfjg==", "cpu": [ "ia32" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.4.tgz", - "integrity": "sha512-NeqqYkrcGzFwi6CGRGNMOjWGGSYOpqwCjS9fvaUlX5s3zwOtn1qwg1s2iE2svBe4Q/YOG1q6875lcAoQK/F4VA==", + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.8.tgz", + "integrity": "sha512-O7k1J/dwHkY1RMVvglFHl1HzutGEFFZ3kNiDMSOyUrB7WcoHGf96Sh+64nTRT26l3GMbCW01Ekh/ThKM5iI7hQ==", "cpu": [ "loong64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.4.tgz", - "integrity": "sha512-IcvTlF9dtLrfL/M8WgNI/qJYBENP3ekgsHbYUIzEzq5XJzzVEV/fXY9WFPfEEXmu3ck2qJP8LG/p3Q8f7Zc2Xg==", + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.8.tgz", + "integrity": "sha512-uv+dqfRazte3BzfMp8PAQXmdGHQt2oC/y2ovwpTteqrMx2lwaksiFZ/bdkXJC19ttTvNXBuWH53zy/aTj1FgGw==", "cpu": [ "mips64el" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.4.tgz", - "integrity": "sha512-HOy0aLTJTVtoTeGZh4HSXaO6M95qu4k5lJcH4gxv56iaycfz1S8GO/5Jh6X4Y1YiI0h7cRyLi+HixMR+88swag==", + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.8.tgz", + "integrity": "sha512-GyG0KcMi1GBavP5JgAkkstMGyMholMDybAf8wF5A70CALlDM2p/f7YFE7H92eDeH/VBtFJA5MT4nRPDGg4JuzQ==", "cpu": [ "ppc64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.4.tgz", - "integrity": "sha512-i8JUDAufpz9jOzo4yIShCTcXzS07vEgWzyX3NH2G7LEFVgrLEhjwL3ajFE4fZI3I4ZgiM7JH3GQ7ReObROvSUA==", + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.8.tgz", + "integrity": "sha512-rAqDYFv3yzMrq7GIcen3XP7TUEG/4LK86LUPMIz6RT8A6pRIDn0sDcvjudVZBiiTcZCY9y2SgYX2lgK3AF+1eg==", "cpu": [ "riscv64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.4.tgz", - "integrity": "sha512-jFnu+6UbLlzIjPQpWCNh5QtrcNfMLjgIavnwPQAfoGx4q17ocOU9MsQ2QVvFxwQoWpZT8DvTLooTvmOQXkO51g==", + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.8.tgz", + "integrity": "sha512-Xutvh6VjlbcHpsIIbwY8GVRbwoviWT19tFhgdA7DlenLGC/mbc3lBoVb7jxj9Z+eyGqvcnSyIltYUrkKzWqSvg==", "cpu": [ "s390x" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/linux-x64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.4.tgz", - "integrity": "sha512-6e0cvXwzOnVWJHq+mskP8DNSrKBr1bULBvnFLpc1KY+d+irZSgZ02TGse5FsafKS5jg2e4pbvK6TPXaF/A6+CA==", + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.8.tgz", + "integrity": "sha512-ASFQhgY4ElXh3nDcOMTkQero4b1lgubskNlhIfJrsH5OKZXDpUAKBlNS0Kx81jwOBp+HCeZqmoJuihTv57/jvQ==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.4.tgz", - "integrity": "sha512-vUnkBYxZW4hL/ie91hSqaSNjulOnYXE1VSLusnvHg2u3jewJBz3YzB9+oCw8DABeVqZGg94t9tyZFoHma8gWZQ==", + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.8.tgz", + "integrity": "sha512-d1KfruIeohqAi6SA+gENMuObDbEjn22olAR7egqnkCD9DGBG0wsEARotkLgXDu6c4ncgWTZJtN5vcgxzWRMzcw==", "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "netbsd" ], - "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.4.tgz", - "integrity": "sha512-XAg8pIQn5CzhOB8odIcAm42QsOfa98SBeKUdo4xa8OvX8LbMZqEtgeWE9P/Wxt7MlG2QqvjGths+nq48TrUiKw==", + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.8.tgz", + "integrity": "sha512-nVDCkrvx2ua+XQNyfrujIG38+YGyuy2Ru9kKVNyh5jAys6n+l44tTtToqHjino2My8VAY6Lw9H7RI73XFi66Cg==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "netbsd" ], - "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.4.tgz", - "integrity": "sha512-Ct2WcFEANlFDtp1nVAXSNBPDxyU+j7+tId//iHXU2f/lN5AmO4zLyhDcpR5Cz1r08mVxzt3Jpyt4PmXQ1O6+7A==", + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.8.tgz", + "integrity": "sha512-j8HgrDuSJFAujkivSMSfPQSAa5Fxbvk4rgNAS5i3K+r8s1X0p1uOO2Hl2xNsGFppOeHOLAVgYwDVlmxhq5h+SQ==", "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "openbsd" ], - "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.4.tgz", - "integrity": "sha512-xAGGhyOQ9Otm1Xu8NT1ifGLnA6M3sJxZ6ixylb+vIUVzvvd6GOALpwQrYrtlPouMqd/vSbgehz6HaVk4+7Afhw==", + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.8.tgz", + "integrity": "sha512-1h8MUAwa0VhNCDp6Af0HToI2TJFAn1uqT9Al6DJVzdIBAd21m/G0Yfc77KDM3uF3T/YaOgQq3qTJHPbTOInaIQ==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "openbsd" ], - "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.8.tgz", + "integrity": "sha512-r2nVa5SIK9tSWd0kJd9HCffnDHKchTGikb//9c7HX+r+wHYCpQrSgxhlY6KWV1nFo1l4KFbsMlHk+L6fekLsUg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], "engines": { "node": ">=18" } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.4.tgz", - "integrity": "sha512-Mw+tzy4pp6wZEK0+Lwr76pWLjrtjmJyUB23tHKqEDP74R3q95luY/bXqXZeYl4NYlvwOqoRKlInQialgCKy67Q==", + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.8.tgz", + "integrity": "sha512-zUlaP2S12YhQ2UzUfcCuMDHQFJyKABkAjvO5YSndMiIkMimPmxA+BYSBikWgsRpvyxuRnow4nS5NPnf9fpv41w==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "sunos" ], - "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.4.tgz", - "integrity": "sha512-AVUP428VQTSddguz9dO9ngb+E5aScyg7nOeJDrF1HPYu555gmza3bDGMPhmVXL8svDSoqPCsCPjb265yG/kLKQ==", + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.8.tgz", + "integrity": "sha512-YEGFFWESlPva8hGL+zvj2z/SaK+pH0SwOM0Nc/d+rVnW7GSTFlLBGzZkuSU9kFIGIo8q9X3ucpZhu8PDN5A2sQ==", "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "win32" ], - "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.4.tgz", - "integrity": "sha512-i1sW+1i+oWvQzSgfRcxxG2k4I9n3O9NRqy8U+uugaT2Dy7kLO9Y7wI72haOahxceMX8hZAzgGou1FhndRldxRg==", + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.8.tgz", + "integrity": "sha512-hiGgGC6KZ5LZz58OL/+qVVoZiuZlUYlYHNAmczOm7bs2oE1XriPFi5ZHHrS8ACpV5EjySrnoCKmcbQMN+ojnHg==", "cpu": [ "ia32" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "win32" ], - "peer": true, "engines": { "node": ">=18" } }, "node_modules/@esbuild/win32-x64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.4.tgz", - "integrity": "sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ==", + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.8.tgz", + "integrity": "sha512-cn3Yr7+OaaZq1c+2pe+8yxC8E144SReCQjN6/2ynubzYjvyqZjTXfQJpAcQpsdJq3My7XADANiYGHoFC69pLQw==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "win32" ], - "peer": true, "engines": { "node": ">=18" } }, "node_modules/@floating-ui/core": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.0.tgz", - "integrity": "sha512-FRdBLykrPPA6P76GGGqlex/e7fbe0F1ykgxHYNXQsH/iTEtjMj/f9bpY5oQqbjt5VgZvgz/uKXbGuROijh3VLA==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.3.tgz", + "integrity": "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==", "license": "MIT", "dependencies": { - "@floating-ui/utils": "^0.2.9" + "@floating-ui/utils": "^0.2.10" } }, "node_modules/@floating-ui/dom": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.0.tgz", - "integrity": "sha512-lGTor4VlXcesUMh1cupTUTDoCxMb0V6bm3CnxHzQcw8Eaf1jQbgQX4i02fYgT0vJ82tb5MZ4CZk1LRGkktJCzg==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.3.tgz", + "integrity": "sha512-uZA413QEpNuhtb3/iIKoYMSK07keHPYeXF02Zhd6e213j+d1NamLix/mCLxBUDW/Gx52sPH2m+chlUsyaBs/Ag==", "license": "MIT", "dependencies": { - "@floating-ui/core": "^1.7.0", - "@floating-ui/utils": "^0.2.9" + "@floating-ui/core": "^1.7.3", + "@floating-ui/utils": "^0.2.10" } }, "node_modules/@floating-ui/utils": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.9.tgz", - "integrity": "sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==", + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz", + "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==", "license": "MIT" }, "node_modules/@foliojs-fork/fontkit": { @@ -1215,16 +1188,16 @@ } }, "node_modules/@fortawesome/react-fontawesome": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.2.tgz", - "integrity": "sha512-EnkrprPNqI6SXJl//m29hpaNzOp1bruISWaOiRtkMi/xSvHJlzc2j2JAYS7egxt/EbjSNV/k6Xy0AQI6vB2+1g==", + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.3.tgz", + "integrity": "sha512-HlJco8RDY8NrzFVjy23b/7mNS4g9NegcrBG3n7jinwpc2x/AmSVk53IhWniLYM4szYLxRAFTAGwGn0EIlclDeQ==", "license": "MIT", "dependencies": { "prop-types": "^15.8.1" }, "peerDependencies": { - "@fortawesome/fontawesome-svg-core": "~1 || ~6", - "react": ">=16.3" + "@fortawesome/fontawesome-svg-core": "~1 || ~6 || ~7", + "react": "^16.3 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "node_modules/@hello-pangea/dnd": { @@ -1292,17 +1265,13 @@ } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", - "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", + "version": "0.3.12", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.12.tgz", + "integrity": "sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==", "license": "MIT", "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" } }, "node_modules/@jridgewell/resolve-uri": { @@ -1314,25 +1283,16 @@ "node": ">=6.0.0" } }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", - "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.4.tgz", + "integrity": "sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==", "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "version": "0.3.29", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.29.tgz", + "integrity": "sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==", "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -1340,16 +1300,15 @@ } }, "node_modules/@napi-rs/wasm-runtime": { - "version": "0.2.11", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.11.tgz", - "integrity": "sha512-9DPkXtvHydrcOsopiYpUgPHpmj0HWZKMUnL2dZqpvC42lsratuBG06V5ipyno0fUek5VlFsNQ+AcFATSrJXgMA==", - "dev": true, + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.0.1.tgz", + "integrity": "sha512-KVlQ/jgywZpixGCKMNwxStmmbYEMyokZpCf2YuIChhfJA2uqfAKNEM8INz7zzTo55iEXfBhIIs3VqYyqzDLj8g==", "license": "MIT", "optional": true, "dependencies": { - "@emnapi/core": "^1.4.3", - "@emnapi/runtime": "^1.4.3", - "@tybys/wasm-util": "^0.9.0" + "@emnapi/core": "^1.4.5", + "@emnapi/runtime": "^1.4.5", + "@tybys/wasm-util": "^0.10.0" } }, "node_modules/@nodelib/fs.scandir": { @@ -1391,20 +1350,18 @@ } }, "node_modules/@oxc-project/runtime": { - "version": "0.75.0", - "resolved": "https://registry.npmjs.org/@oxc-project/runtime/-/runtime-0.75.0.tgz", - "integrity": "sha512-gzRmVI/vorsPmbDXt7GD4Uh2lD3rCOku/1xWPB4Yx48k0EP4TZmzQudWapjN4+7Vv+rgXr0RqCHQadeaMvdBuw==", - "dev": true, + "version": "0.78.0", + "resolved": "https://registry.npmjs.org/@oxc-project/runtime/-/runtime-0.78.0.tgz", + "integrity": "sha512-jOU7sDFMyq5ShGJC21UobalVzqcdtWGfySVp8ELvKoVLzMpLHb4kv1bs9VKxaP8XC7Z9hlAXwEKVhCTN+j21aQ==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@oxc-project/types": { - "version": "0.75.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.75.0.tgz", - "integrity": "sha512-QMW+06WOXs7+F301Y3X0VpmWhwuQVc/X/RP2zF9OIwvSMmsif3xURS2wxbakFIABYsytgBcHpUcFepVS0Qnd3A==", - "dev": true, + "version": "0.78.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.78.0.tgz", + "integrity": "sha512-8FvExh0WRWN1FoSTjah1xa9RlavZcJQ8/yxRbZ7ElmSa2Ij5f5Em7MvRbSthE6FbwC6Wh8iAw0Gpna7QdoqLGg==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/Boshen" @@ -1414,7 +1371,6 @@ "version": "2.5.1", "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz", "integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==", - "dev": true, "hasInstallScript": true, "license": "MIT", "optional": true, @@ -1454,7 +1410,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1475,7 +1430,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1496,7 +1450,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1517,7 +1470,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1538,7 +1490,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1559,7 +1510,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1580,7 +1530,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1601,7 +1550,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1622,7 +1570,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1643,7 +1590,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1664,7 +1610,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1685,7 +1630,6 @@ "cpu": [ "ia32" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1706,7 +1650,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1721,13 +1664,13 @@ } }, "node_modules/@playwright/test": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.52.0.tgz", - "integrity": "sha512-uh6W7sb55hl7D6vsAeA+V2p5JnlAqzhqFyF0VcJkKZXkgnFcVG9PziERRHQfPLfNGx1C292a4JqbWzhR8L4R1g==", + "version": "1.53.2", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.53.2.tgz", + "integrity": "sha512-tEB2U5z74ebBeyfGNZ3Jfg29AnW+5HlWhvHtb/Mqco9pFdZU1ZLNdVb2UtB5CvmiilNr2ZfVH/qMmAROG/XTzw==", "dev": true, "license": "Apache-2.0", "dependencies": { - "playwright": "1.52.0" + "playwright": "1.53.2" }, "bin": { "playwright": "cli.js" @@ -1808,14 +1751,26 @@ "react": ">=16.8.0" } }, + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-beta.30.tgz", + "integrity": "sha512-4j7QBitb/WMT1fzdJo7BsFvVNaFR5WCQPdf/RPDHEsgQIYwBaHaL47KTZxncGFQDD1UAKN3XScJ0k7LAsZfsvg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.0.0-beta.21", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-beta.21.tgz", - "integrity": "sha512-FFkhqqq4kz7UCa4mGkexdsPK5++31zBTnhUTYhDUX+hdCwcYOlh2r2WsjHY+fQCMbIJ2UqOdAIocVGirs6/f7w==", + "version": "1.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-beta.30.tgz", + "integrity": "sha512-4vWFTe1o5LXeitI2lW8qMGRxxwrH/LhKd2HDLa/QPhdxohvdnfKyDZWN96XUhDyje2bHFCFyhMs3ak2lg2mJFA==", "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1823,13 +1778,12 @@ ] }, "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.0.0-beta.21", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-beta.21.tgz", - "integrity": "sha512-To/Ma+/5rxSoCVO/EInVCpQBB5YA4PDme0yYsbC5b76d+1OzuENaY4iq8vmCcEDZVnTU+xnfwfiMR9X+gB8W/w==", + "version": "1.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-beta.30.tgz", + "integrity": "sha512-MxrfodqImbsDFFFU/8LxyFPZjt7s4ht8g2Zb76EmIQ+xlmit46L9IzvWiuMpEaSJ5WbnjO7fCDWwakMGyJJ+Dw==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1837,13 +1791,12 @@ ] }, "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.0.0-beta.21", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-beta.21.tgz", - "integrity": "sha512-Z1lct0slFVDp08xzmRX6dPI7/uh6JG8dAswVdM4h5jjeXksC2AQpzBj4YgeX6t0OI428PC7FKP1k6T8HZS7Frg==", + "version": "1.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-beta.30.tgz", + "integrity": "sha512-c/TQXcATKoO8qE1bCjCOkymZTu7yVUAxBSNLp42Q97XHCb0Cu9v6MjZpB6c7Hq9NQ9NzW44uglak9D/r77JeDw==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1851,13 +1804,12 @@ ] }, "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.0.0-beta.21", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-beta.21.tgz", - "integrity": "sha512-XKfjZLMODXpgHW1gZUkP/3giahuZD+35ft92nJX6qzEAjcwsZRNsAW2mlWPH68Kp97TBw09+zkNuL8vP66L9uw==", + "version": "1.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-beta.30.tgz", + "integrity": "sha512-Vxci4xylM11zVqvrmezAaRjGBDyOlMRtlt7TDgxaBmSYLuiokXbZpD8aoSuOyjUAeN0/tmWItkxNGQza8UWGNQ==", "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1865,13 +1817,12 @@ ] }, "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.0.0-beta.21", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-beta.21.tgz", - "integrity": "sha512-Q+5C4gUakWccecCmsr3ts6ypQzGPHUp+ooUQhQAf7L6bTv6037gsRYGDdkxla77S5+VfLXBwNXKZFsndDOuZoQ==", + "version": "1.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-beta.30.tgz", + "integrity": "sha512-iEBEdSs25Ol0lXyVNs763f7YPAIP0t1EAjoXME81oJ94DesJslaLTj71Rn1shoMDVA+dfkYA286w5uYnOs9ZNA==", "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1879,27 +1830,38 @@ ] }, "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.0.0-beta.21", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-beta.21.tgz", - "integrity": "sha512-xf30hS7YvyZlkqR3NZAWm+so0m9Rrp24TRq1F4UmNWpDL5Cwbmgak/Cn4IYUEY6PE960+ZejuAhbCDPt5Bxaeg==", + "version": "1.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-beta.30.tgz", + "integrity": "sha512-Ny684Sn1X8c+gGLuDlxkOuwiEE3C7eEOqp1/YVBzQB4HO7U/b4n7alvHvShboOEY5DP1fFUjq6Z+sBLYlCIZbQ==", "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ] }, + "node_modules/@rolldown/binding-linux-arm64-ohos": { + "version": "1.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-ohos/-/binding-linux-arm64-ohos-1.0.0-beta.30.tgz", + "integrity": "sha512-6moyULHDPKwt5RDEV72EqYw5n+s46AerTwtEBau5wCsZd1wuHS1L9z6wqhKISXAFTK9sneN0TEjvYKo+sgbbiA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.0.0-beta.21", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-beta.21.tgz", - "integrity": "sha512-/X3MvmRcIQSxmHF/TxO2SI0snHjGlY2uO3BKwgPA100hSmvVDuz6cFB80tcGNCUVSJAtRHt/FniNTmbMHfdHLQ==", + "version": "1.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-beta.30.tgz", + "integrity": "sha512-p0yoPdoGg5Ow2YZKKB5Ypbn58i7u4XFk3PvMkriFnEcgtVk40c5u7miaX7jH0JdzahyXVBJ/KT5yEpJrzQn8yg==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1907,13 +1869,12 @@ ] }, "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.0.0-beta.21", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-beta.21.tgz", - "integrity": "sha512-z5rjicKLgYiffiHOQgM3kROyEUILRZx3GeLtRnrf9yjgMDdpguRl3ggB67ej5ytgRXn5K5F13lsIv5R0i9KRFQ==", + "version": "1.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-beta.30.tgz", + "integrity": "sha512-sM/KhCrsT0YdHX10mFSr0cvbfk1+btG6ftepAfqhbcDfhi0s65J4dTOxGmklJnJL9i1LXZ8WA3N4wmnqsfoK8Q==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1921,30 +1882,28 @@ ] }, "node_modules/@rolldown/binding-wasm32-wasi": { - "version": "1.0.0-beta.21", - "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-beta.21.tgz", - "integrity": "sha512-v5eFQYJcD4a2FBb/KDzS+bhVW2tf5aolJCbAiqlVnJwD3dbYMQtwJRwej2kISDerGplx6yQIHp5R5Y7GRoEGhw==", + "version": "1.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-beta.30.tgz", + "integrity": "sha512-i3kD5OWs8PQP0V+JW3TFyCLuyjuNzrB45em0g84Jc+gvnDsGVlzVjMNPo7txE/yT8CfE90HC/lDs3ry9FvaUyw==", "cpu": [ "wasm32" ], - "dev": true, "license": "MIT", "optional": true, "dependencies": { - "@napi-rs/wasm-runtime": "^0.2.10" + "@napi-rs/wasm-runtime": "^1.0.1" }, "engines": { - "node": ">=14.21.3" + "node": ">=14.0.0" } }, "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.0.0-beta.21", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-beta.21.tgz", - "integrity": "sha512-1QZIJXSlbIlHJT6xY1YCuyF54sSOoOlsUaX3pWlJvuZs4fbgl894gN4wZATYd0V7KT62qfRdB40wg0yfrTkfFQ==", + "version": "1.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-beta.30.tgz", + "integrity": "sha512-q7mrYln30V35VrCqnBVQQvNPQm8Om9HC59I3kMYiOWogvJobzSPyO+HA1MP363+Qgwe39I2I1nqBKPOtWZ33AQ==", "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1952,13 +1911,12 @@ ] }, "node_modules/@rolldown/binding-win32-ia32-msvc": { - "version": "1.0.0-beta.21", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-1.0.0-beta.21.tgz", - "integrity": "sha512-JXTN7gKNmQoFtqYrCK0If4HuZagvBQ7ThY6fl2rAMbUXpq3mtVd+Z2k0TzzeWB7Nxwo6FusLYYlbmPYS5QCl1w==", + "version": "1.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-1.0.0-beta.30.tgz", + "integrity": "sha512-nUqGBt39XTpbBEREEnyKofdP3uz+SN/x2884BH+N3B2NjSUrP6NXwzltM35C0wKK42hX/nthRrwSgj715m99Jw==", "cpu": [ "ia32" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1966,13 +1924,12 @@ ] }, "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.0.0-beta.21", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-beta.21.tgz", - "integrity": "sha512-wp7kF6IpuVVqQVzkaDxrxJqBByMSEJ8uAa9LTW1fK2x8TulNRjlxPRpjeDNji2uiEGa+QbdQDfRm/WS8ROnutg==", + "version": "1.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-beta.30.tgz", + "integrity": "sha512-lbnvUwAXIVWSXAeZrCa4b1KvV/DW0rBnMHuX0T7I6ey1IsXZ90J37dEgt3j48Ex1Cw1E+5H7VDNP2gyOX8iu3w==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1980,16 +1937,15 @@ ] }, "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-beta.19", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.19.tgz", - "integrity": "sha512-3FL3mnMbPu0muGOCaKAhhFEYmqv9eTfPSJRJmANrCwtgK8VuxpsZDGK+m0LYAGoyO8+0j5uRe4PeyPDK1yA/hA==", - "dev": true, + "version": "1.0.0-beta.27", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", + "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==", "license": "MIT" }, "node_modules/@rollup/pluginutils": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.4.tgz", - "integrity": "sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.2.0.tgz", + "integrity": "sha512-qWJ2ZTbmumwiLFomfzTyt5Kng4hwPi9rwCYN4SHb6eaRU1KNO4ccxINHr/VhH4GgPlt1XfSTLX2LBTme8ne4Zw==", "dev": true, "license": "MIT", "dependencies": { @@ -2009,17 +1965,10 @@ } } }, - "node_modules/@rollup/pluginutils/node_modules/estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", - "dev": true, - "license": "MIT" - }, "node_modules/@rollup/pluginutils/node_modules/picomatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", - "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", "engines": { @@ -2029,378 +1978,78 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.41.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.41.1.tgz", - "integrity": "sha512-NELNvyEWZ6R9QMkiytB4/L4zSEaBC03KIXEghptLGLZWJ6VPrL63ooZQCOnlx36aQPGhzuOMwDerC1Eb2VmrLw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "peer": true - }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.41.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.41.1.tgz", - "integrity": "sha512-DXdQe1BJ6TK47ukAoZLehRHhfKnKg9BjnQYUu9gzhI8Mwa1d2fzxA1aw2JixHVl403bwp1+/o/NhhHtxWJBgEA==", - "cpu": [ - "arm64" - ], + "node_modules/@svgr/babel-plugin-add-jsx-attribute": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-8.0.0.tgz", + "integrity": "sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "peer": true + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.41.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.41.1.tgz", - "integrity": "sha512-5afxvwszzdulsU2w8JKWwY8/sJOLPzf0e1bFuvcW5h9zsEg+RQAojdW0ux2zyYAz7R8HvvzKCjLNJhVq965U7w==", - "cpu": [ - "arm64" - ], + "node_modules/@svgr/babel-plugin-remove-jsx-attribute": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-8.0.0.tgz", + "integrity": "sha512-BcCkm/STipKvbCl6b7QFrMh/vx00vIP63k2eM66MfHJzPr6O2U0jYEViXkHJWqXqQYjdeA9cuCl5KWmlwjDvbA==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "peer": true + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.41.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.41.1.tgz", - "integrity": "sha512-egpJACny8QOdHNNMZKf8xY0Is6gIMz+tuqXlusxquWu3F833DcMwmGM7WlvCO9sB3OsPjdC4U0wHw5FabzCGZg==", - "cpu": [ - "x64" - ], + "node_modules/@svgr/babel-plugin-remove-jsx-empty-expression": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-8.0.0.tgz", + "integrity": "sha512-5BcGCBfBxB5+XSDSWnhTThfI9jcO5f0Ai2V24gZpG+wXF14BzwxxdDb4g6trdOux0rhibGs385BeFMSmxtS3uA==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "peer": true + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } }, - "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.41.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.41.1.tgz", - "integrity": "sha512-DBVMZH5vbjgRk3r0OzgjS38z+atlupJ7xfKIDJdZZL6sM6wjfDNo64aowcLPKIx7LMQi8vybB56uh1Ftck/Atg==", - "cpu": [ - "arm64" - ], + "node_modules/@svgr/babel-plugin-replace-jsx-attribute-value": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-8.0.0.tgz", + "integrity": "sha512-KVQ+PtIjb1BuYT3ht8M5KbzWBhdAjjUPdlMtpuw/VjT8coTrItWX6Qafl9+ji831JaJcu6PJNKCV0bp01lBNzQ==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "peer": true + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } }, - "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.41.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.41.1.tgz", - "integrity": "sha512-3FkydeohozEskBxNWEIbPfOE0aqQgB6ttTkJ159uWOFn42VLyfAiyD9UK5mhu+ItWzft60DycIN1Xdgiy8o/SA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "peer": true - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.41.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.41.1.tgz", - "integrity": "sha512-wC53ZNDgt0pqx5xCAgNunkTzFE8GTgdZ9EwYGVcg+jEjJdZGtq9xPjDnFgfFozQI/Xm1mh+D9YlYtl+ueswNEg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true - }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.41.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.41.1.tgz", - "integrity": "sha512-jwKCca1gbZkZLhLRtsrka5N8sFAaxrGz/7wRJ8Wwvq3jug7toO21vWlViihG85ei7uJTpzbXZRcORotE+xyrLA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true - }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.41.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.41.1.tgz", - "integrity": "sha512-g0UBcNknsmmNQ8V2d/zD2P7WWfJKU0F1nu0k5pW4rvdb+BIqMm8ToluW/eeRmxCared5dD76lS04uL4UaNgpNA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true - }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.41.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.41.1.tgz", - "integrity": "sha512-XZpeGB5TKEZWzIrj7sXr+BEaSgo/ma/kCgrZgL0oo5qdB1JlTzIYQKel/RmhT6vMAvOdM2teYlAaOGJpJ9lahg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true - }, - "node_modules/@rollup/rollup-linux-loongarch64-gnu": { - "version": "4.41.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.41.1.tgz", - "integrity": "sha512-bkCfDJ4qzWfFRCNt5RVV4DOw6KEgFTUZi2r2RuYhGWC8WhCA8lCAJhDeAmrM/fdiAH54m0mA0Vk2FGRPyzI+tw==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true - }, - "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.41.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.41.1.tgz", - "integrity": "sha512-3mr3Xm+gvMX+/8EKogIZSIEF0WUu0HL9di+YWlJpO8CQBnoLAEL/roTCxuLncEdgcfJcvA4UMOf+2dnjl4Ut1A==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true - }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.41.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.41.1.tgz", - "integrity": "sha512-3rwCIh6MQ1LGrvKJitQjZFuQnT2wxfU+ivhNBzmxXTXPllewOF7JR1s2vMX/tWtUYFgphygxjqMl76q4aMotGw==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true - }, - "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.41.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.41.1.tgz", - "integrity": "sha512-LdIUOb3gvfmpkgFZuccNa2uYiqtgZAz3PTzjuM5bH3nvuy9ty6RGc/Q0+HDFrHrizJGVpjnTZ1yS5TNNjFlklw==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true - }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.41.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.41.1.tgz", - "integrity": "sha512-oIE6M8WC9ma6xYqjvPhzZYk6NbobIURvP/lEbh7FWplcMO6gn7MM2yHKA1eC/GvYwzNKK/1LYgqzdkZ8YFxR8g==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true - }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.41.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.41.1.tgz", - "integrity": "sha512-cWBOvayNvA+SyeQMp79BHPK8ws6sHSsYnK5zDcsC3Hsxr1dgTABKjMnMslPq1DvZIp6uO7kIWhiGwaTdR4Og9A==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true - }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.41.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.41.1.tgz", - "integrity": "sha512-y5CbN44M+pUCdGDlZFzGGBSKCA4A/J2ZH4edTYSSxFg7ce1Xt3GtydbVKWLlzL+INfFIZAEg1ZV6hh9+QQf9YQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true - }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.41.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.41.1.tgz", - "integrity": "sha512-lZkCxIrjlJlMt1dLO/FbpZbzt6J/A8p4DnqzSa4PWqPEUUUnzXLeki/iyPLfV0BmHItlYgHUqJe+3KiyydmiNQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "peer": true - }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.41.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.41.1.tgz", - "integrity": "sha512-+psFT9+pIh2iuGsxFYYa/LhS5MFKmuivRsx9iPJWNSGbh2XVEjk90fmpUEjCnILPEPJnikAU6SFDiEUyOv90Pg==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "peer": true - }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.41.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.41.1.tgz", - "integrity": "sha512-Wq2zpapRYLfi4aKxf2Xff0tN+7slj2d4R87WEzqw7ZLsVvO5zwYCIuEGSZYiK41+GlwUo1HiR+GdkLEJnCKTCw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "peer": true - }, - "node_modules/@svgr/babel-plugin-add-jsx-attribute": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-8.0.0.tgz", - "integrity": "sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@svgr/babel-plugin-remove-jsx-attribute": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-8.0.0.tgz", - "integrity": "sha512-BcCkm/STipKvbCl6b7QFrMh/vx00vIP63k2eM66MfHJzPr6O2U0jYEViXkHJWqXqQYjdeA9cuCl5KWmlwjDvbA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@svgr/babel-plugin-remove-jsx-empty-expression": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-8.0.0.tgz", - "integrity": "sha512-5BcGCBfBxB5+XSDSWnhTThfI9jcO5f0Ai2V24gZpG+wXF14BzwxxdDb4g6trdOux0rhibGs385BeFMSmxtS3uA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@svgr/babel-plugin-replace-jsx-attribute-value": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-8.0.0.tgz", - "integrity": "sha512-KVQ+PtIjb1BuYT3ht8M5KbzWBhdAjjUPdlMtpuw/VjT8coTrItWX6Qafl9+ji831JaJcu6PJNKCV0bp01lBNzQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@svgr/babel-plugin-svg-dynamic-title": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-8.0.0.tgz", - "integrity": "sha512-omNiKqwjNmOQJ2v6ge4SErBbkooV2aAWwaPFs2vUY7p7GhVkzRkJ00kILXQvRhA6miHnNpXv7MRnnSjdRjK8og==", + "node_modules/@svgr/babel-plugin-svg-dynamic-title": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-8.0.0.tgz", + "integrity": "sha512-omNiKqwjNmOQJ2v6ge4SErBbkooV2aAWwaPFs2vUY7p7GhVkzRkJ00kILXQvRhA6miHnNpXv7MRnnSjdRjK8og==", "dev": true, "license": "MIT", "engines": { @@ -2513,13 +2162,6 @@ "url": "https://github.com/sponsors/gregberge" } }, - "node_modules/@svgr/core/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true, - "license": "Python-2.0" - }, "node_modules/@svgr/core/node_modules/cosmiconfig": { "version": "8.3.6", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", @@ -2547,19 +2189,6 @@ } } }, - "node_modules/@svgr/core/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, "node_modules/@svgr/hast-util-to-babel-ast": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-8.0.0.tgz", @@ -2614,237 +2243,10 @@ "@svgr/core": "*" } }, - "node_modules/@swc/core": { - "version": "1.12.7", - "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.12.7.tgz", - "integrity": "sha512-bcpllEihyUSnqp0UtXTvXc19CT4wp3tGWLENhWnjr4B5iEOkzqMu+xHGz1FI5IBatjfqOQb29tgIfv6IL05QaA==", - "dev": true, - "hasInstallScript": true, - "license": "Apache-2.0", - "dependencies": { - "@swc/counter": "^0.1.3", - "@swc/types": "^0.1.23" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/swc" - }, - "optionalDependencies": { - "@swc/core-darwin-arm64": "1.12.7", - "@swc/core-darwin-x64": "1.12.7", - "@swc/core-linux-arm-gnueabihf": "1.12.7", - "@swc/core-linux-arm64-gnu": "1.12.7", - "@swc/core-linux-arm64-musl": "1.12.7", - "@swc/core-linux-x64-gnu": "1.12.7", - "@swc/core-linux-x64-musl": "1.12.7", - "@swc/core-win32-arm64-msvc": "1.12.7", - "@swc/core-win32-ia32-msvc": "1.12.7", - "@swc/core-win32-x64-msvc": "1.12.7" - }, - "peerDependencies": { - "@swc/helpers": ">=0.5.17" - }, - "peerDependenciesMeta": { - "@swc/helpers": { - "optional": true - } - } - }, - "node_modules/@swc/core-darwin-arm64": { - "version": "1.12.7", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.12.7.tgz", - "integrity": "sha512-w6BBT0hBRS56yS+LbReVym0h+iB7/PpCddqrn1ha94ra4rZ4R/A91A/rkv+LnQlPqU/+fhqdlXtCJU9mrhCBtA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "Apache-2.0 AND MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-darwin-x64": { - "version": "1.12.7", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.12.7.tgz", - "integrity": "sha512-jN6LhFfGOpm4DY2mXPgwH4aa9GLOwublwMVFFZ/bGnHYYCRitLZs9+JWBbyWs7MyGcA246Ew+EREx36KVEAxjA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0 AND MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-linux-arm-gnueabihf": { - "version": "1.12.7", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.12.7.tgz", - "integrity": "sha512-rHn8XXi7G2StEtZRAeJ6c7nhJPDnqsHXmeNrAaYwk8Tvpa6ZYG2nT9E1OQNXj1/dfbSFTjdiA8M8ZvGYBlpBoA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-linux-arm64-gnu": { - "version": "1.12.7", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.12.7.tgz", - "integrity": "sha512-N15hKizSSh+hkZ2x3TDVrxq0TDcbvDbkQJi2ZrLb9fK+NdFUV/x+XF16ZDPlbxtrGXl1CT7VD439SNaMN9F7qw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "Apache-2.0 AND MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-linux-arm64-musl": { - "version": "1.12.7", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.12.7.tgz", - "integrity": "sha512-jxyINtBezpxd3eIUDiDXv7UQ87YWlPsM9KumOwJk09FkFSO4oYxV2RT+Wu+Nt5tVWue4N0MdXT/p7SQsDEk4YA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "Apache-2.0 AND MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-linux-x64-gnu": { - "version": "1.12.7", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.12.7.tgz", - "integrity": "sha512-PR4tPVwU1BQBfFDk2XfzXxsEIjF3x/bOV1BzZpYvrlkU0TKUDbR4t2wzvsYwD/coW7/yoQmlL70/qnuPtTp1Zw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0 AND MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-linux-x64-musl": { - "version": "1.12.7", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.12.7.tgz", - "integrity": "sha512-zy7JWfQtQItgMfUjSbbcS3DZqQUn2d9VuV0LSGpJxtTXwgzhRpF1S2Sj7cU9hGpbM27Y8RJ4DeFb3qbAufjbrw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0 AND MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-win32-arm64-msvc": { - "version": "1.12.7", - "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.12.7.tgz", - "integrity": "sha512-52PeF0tyX04ZFD8nibNhy/GjMFOZWTEWPmIB3wpD1vIJ1po+smtBnEdRRll5WIXITKoiND8AeHlBNBPqcsdcwA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "Apache-2.0 AND MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-win32-ia32-msvc": { - "version": "1.12.7", - "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.12.7.tgz", - "integrity": "sha512-WzQwkNMuhB1qQShT9uUgz/mX2j7NIEPExEtzvGsBT7TlZ9j1kGZ8NJcZH/fwOFcSJL4W7DnkL7nAhx6DBlSPaA==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "Apache-2.0 AND MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-win32-x64-msvc": { - "version": "1.12.7", - "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.12.7.tgz", - "integrity": "sha512-R52ivBi2lgjl+Bd3XCPum0YfgbZq/W1AUExITysddP9ErsNSwnreYyNB3exEijiazWGcqHEas2ChiuMOP7NYrA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0 AND MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/counter": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", - "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/@swc/types": { - "version": "0.1.23", - "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.23.tgz", - "integrity": "sha512-u1iIVZV9Q0jxY+yM2vw/hZGDNudsN85bBpTqzAQ9rzkxW9D+e3aEM4Han+ow518gSewkXgjmEK0BD79ZcNVgPw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@swc/counter": "^0.1.3" - } - }, "node_modules/@tybys/wasm-util": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.9.0.tgz", - "integrity": "sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==", - "dev": true, + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.0.tgz", + "integrity": "sha512-VyyPYFlOMNylG45GoAe0xDoLwWuowvf92F9kySqzYh8vmYm7D2u4iUJKa1tOUpS70Ku13ASrOkS4ScXFsTaCNQ==", "license": "MIT", "optional": true, "dependencies": { @@ -2887,30 +2289,32 @@ } }, "node_modules/@types/babel__traverse": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.7.tgz", - "integrity": "sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng==", + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.20.7" + "@babel/types": "^7.28.2" } }, "node_modules/@types/estree": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", - "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", "dev": true, "license": "MIT" }, "node_modules/@types/hoist-non-react-statics": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.6.tgz", - "integrity": "sha512-lPByRJUer/iN/xa4qpyL0qmL11DqNW81iU/IG1S3uvRUq4oKagz8VCxZjiWkumgt66YT3vOdDgZ0o32sGKtCEw==", + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.7.tgz", + "integrity": "sha512-PQTyIulDkIDro8P+IHbKCsw7U2xxBYflVzW/FgWdCAePD9xGSidgA76/GeJ6lBKoblyhf9pBY763gbrN+1dI8g==", "license": "MIT", "dependencies": { - "@types/react": "*", "hoist-non-react-statics": "^3.3.0" + }, + "peerDependencies": { + "@types/react": "*" } }, "node_modules/@types/invariant": { @@ -2919,18 +2323,6 @@ "integrity": "sha512-IwpIMieE55oGWiXkQPSBY1nw1nFs6bsKXTFskNY8sdS17K24vyEBRQZEwlRS7ZmXCWnJcQtbxWzly+cODWGs2A==", "license": "MIT" }, - "node_modules/@types/node": { - "version": "20.19.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.2.tgz", - "integrity": "sha512-9pLGGwdzOUBDYi0GNjM97FIA+f92fqSke6joWeBjWXllfNxZBs7qeMF7tvtOIsbY45xkWkxrdwUfUf3MnQa9gA==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "undici-types": "~6.21.0" - } - }, "node_modules/@types/parse-json": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", @@ -2938,9 +2330,9 @@ "license": "MIT" }, "node_modules/@types/prop-types": { - "version": "15.7.14", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.14.tgz", - "integrity": "sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==", + "version": "15.7.15", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", + "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", "license": "MIT" }, "node_modules/@types/quill": { @@ -2953,9 +2345,9 @@ } }, "node_modules/@types/react": { - "version": "18.3.22", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.22.tgz", - "integrity": "sha512-vUhG0YmQZ7kL/tmKLrD3g5zXbXXreZXB3pmROW8bg3CnLnpjkRVwUlLne7Ufa2r9yJ8+/6B73RzhAek5TBKh2Q==", + "version": "18.3.23", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.23.tgz", + "integrity": "sha512-/LDXMQh55EzZQ0uVAZmKKhfENivEvWz6E+EYzh+/MCjMhNsotd+ZHhBGIjFDTi6+fz0OhQQQLbTgdQIxxCsC0w==", "license": "MIT", "dependencies": { "@types/prop-types": "*", @@ -3024,9 +2416,9 @@ } }, "node_modules/@vimeo/player": { - "version": "2.27.1", - "resolved": "https://registry.npmjs.org/@vimeo/player/-/player-2.27.1.tgz", - "integrity": "sha512-G3lk+BI0qPvJYxh+OguN5uE5aKfJBcGOQODl++NlXNLP9OMe21jZql0iI6AFGGd1KBLXZXuNmpvBKb4PG+fiVw==", + "version": "2.29.3", + "resolved": "https://registry.npmjs.org/@vimeo/player/-/player-2.29.3.tgz", + "integrity": "sha512-pS2LsZbcbuQmV9BatpxdjcsFsjuas1jslCzY48o1qsXJ/sQuPiWIuk5B/dSaLbY3AcnS4M1IPphPgA7PRSMdxA==", "license": "MIT", "dependencies": { "native-promise-only": "0.8.1", @@ -3034,16 +2426,16 @@ } }, "node_modules/@vitejs/plugin-react": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.6.0.tgz", - "integrity": "sha512-5Kgff+m8e2PB+9j51eGHEpn5kUzRKH2Ry0qGoe8ItJg7pqnkPrYPkDQZGgGmTa0EGarHrkjLvOdU3b1fzI8otQ==", + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", + "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/core": "^7.27.4", + "@babel/core": "^7.28.0", "@babel/plugin-transform-react-jsx-self": "^7.27.1", "@babel/plugin-transform-react-jsx-source": "^7.27.1", - "@rolldown/pluginutils": "1.0.0-beta.19", + "@rolldown/pluginutils": "1.0.0-beta.27", "@types/babel__core": "^7.20.5", "react-refresh": "^0.17.0" }, @@ -3051,30 +2443,24 @@ "node": "^14.18.0 || >=16.0.0" }, "peerDependencies": { - "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0" + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, - "node_modules/@vitejs/plugin-react-swc": { - "version": "3.10.2", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react-swc/-/plugin-react-swc-3.10.2.tgz", - "integrity": "sha512-xD3Rdvrt5LgANug7WekBn1KhcvLn1H3jNBfJRL3reeOIua/WnZOEV5qi5qIBq5T8R0jUDmRtxuvk4bPhzGHDWw==", - "dev": true, + "node_modules/@vitejs/plugin-react-oxc": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react-oxc/-/plugin-react-oxc-0.3.0.tgz", + "integrity": "sha512-OaqaDIc74NNuqH1xKGbGoErpKP8L1XlxBQsfWvIUfpQaDCe5El9Ac5mPrvn/Dg0pv3xKB/PNm4Wirxr6hnKu/A==", "license": "MIT", "dependencies": { - "@rolldown/pluginutils": "1.0.0-beta.11", - "@swc/core": "^1.11.31" + "@rolldown/pluginutils": "1.0.0-beta.27" + }, + "engines": { + "node": ">=20.0.0" }, "peerDependencies": { - "vite": "^4 || ^5 || ^6 || ^7.0.0-beta.0" + "vite": "^6.3.0 || ^7.0.0" } }, - "node_modules/@vitejs/plugin-react-swc/node_modules/@rolldown/pluginutils": { - "version": "1.0.0-beta.11", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.11.tgz", - "integrity": "sha512-L/gAA/hyCSuzTF1ftlzUSI/IKr2POHsv1Dd78GfqkR83KMNuswWD61JxGV2L7nRwBBBSDr6R1gCkdTmoN7W4ag==", - "dev": true, - "license": "MIT" - }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -3103,12 +2489,18 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/ansis/-/ansis-4.1.0.tgz", "integrity": "sha512-BGcItUBWSMRgOCe+SVZJ+S7yTRG0eGt9cXAHev72yuGcY23hnLA7Bky5L/xLyPINoSN95geovfBkqoTlNZYa7w==", - "dev": true, "license": "ISC", "engines": { "node": ">=14" } }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, "node_modules/atomic-sleep": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", @@ -3187,7 +2579,7 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "fill-range": "^7.1.1" @@ -3206,9 +2598,9 @@ } }, "node_modules/browserslist": { - "version": "4.24.5", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.5.tgz", - "integrity": "sha512-FDToo4Wo82hIdgc1CQ+NQD0hEhmpPjrZ3hiUgwgOG6IuTdlpr8jdjyG24P6cNP1yJpTLzS5OcGgSw0xmDU1/Tw==", + "version": "4.25.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.1.tgz", + "integrity": "sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw==", "funding": [ { "type": "opencollective", @@ -3225,8 +2617,8 @@ ], "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001716", - "electron-to-chromium": "^1.5.149", + "caniuse-lite": "^1.0.30001726", + "electron-to-chromium": "^1.5.173", "node-releases": "^2.0.19", "update-browserslist-db": "^1.1.3" }, @@ -3316,9 +2708,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001718", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001718.tgz", - "integrity": "sha512-AflseV1ahcSunK53NfEs9gFWgOEmzr0f+kaMFA4xiLZlr9Hzt7HxcSpIFcnNCUkz6R6dWKa54rUz3HUmI3nVcw==", + "version": "1.0.30001731", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001731.tgz", + "integrity": "sha512-lDdp2/wrOmTRWuoB5DpfNkC0rJDU8DqRa6nYL6HK6sytw70QMopt/NIc/9SM7ylItlBWfACXk0tEn37UWM/+mg==", "funding": [ { "type": "opencollective", @@ -3339,7 +2731,7 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "readdirp": "^4.0.1" @@ -3368,40 +2760,6 @@ "wrap-ansi": "^6.2.0" } }, - "node_modules/cliui/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "license": "MIT" - }, - "node_modules/cliui/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cliui/node_modules/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/clone": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", @@ -3454,9 +2812,9 @@ "license": "MIT" }, "node_modules/core-js": { - "version": "3.42.0", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.42.0.tgz", - "integrity": "sha512-Sz4PP4ZA+Rq4II21qkNqOEDTDrCvcANId3xpIgB34NDkWc3UduWj2dqEtN9yZIq8Dk3HyPI33x9sqqU5C8sr0g==", + "version": "3.45.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.45.0.tgz", + "integrity": "sha512-c2KZL9lP4DjkN3hk/an4pWn5b5ZefhRJnAc42n6LJ19kSnbeRbdQZE5dSeE2LBol1OwJD3X1BQvFTAsa8ReeDA==", "hasInstallScript": true, "license": "MIT", "funding": { @@ -3782,7 +3140,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", - "dev": true, "license": "Apache-2.0", "optional": true, "bin": { @@ -3913,11 +3270,17 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.157", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.157.tgz", - "integrity": "sha512-/0ybgsQd1muo8QlnuTpKwtl0oX5YMlUGbm8xyqgDU00motRkKFFbUJySAQBWcY79rVqNLWIWa87BGVGClwAB2w==", + "version": "1.5.198", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.198.tgz", + "integrity": "sha512-G5COfnp3w+ydVu80yprgWSfmfQaYRh9DOxfhAxstLyetKaLyl55QrNjx8C38Pc/C+RaDmb1M0Lk8wPEMQ+bGgQ==", "license": "ISC" }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, "node_modules/entities": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz", @@ -3970,14 +3333,12 @@ } }, "node_modules/esbuild": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.4.tgz", - "integrity": "sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q==", - "dev": true, + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.8.tgz", + "integrity": "sha512-vVC0USHGtMi8+R4Kz8rt6JhEWLxsv9Rnu/lGYbPR8u47B+DCBksq9JarW0zOO7bs37hyOK1l2/oqtbciutL5+Q==", + "devOptional": true, "hasInstallScript": true, "license": "MIT", - "optional": true, - "peer": true, "bin": { "esbuild": "bin/esbuild" }, @@ -3985,31 +3346,32 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.4", - "@esbuild/android-arm": "0.25.4", - "@esbuild/android-arm64": "0.25.4", - "@esbuild/android-x64": "0.25.4", - "@esbuild/darwin-arm64": "0.25.4", - "@esbuild/darwin-x64": "0.25.4", - "@esbuild/freebsd-arm64": "0.25.4", - "@esbuild/freebsd-x64": "0.25.4", - "@esbuild/linux-arm": "0.25.4", - "@esbuild/linux-arm64": "0.25.4", - "@esbuild/linux-ia32": "0.25.4", - "@esbuild/linux-loong64": "0.25.4", - "@esbuild/linux-mips64el": "0.25.4", - "@esbuild/linux-ppc64": "0.25.4", - "@esbuild/linux-riscv64": "0.25.4", - "@esbuild/linux-s390x": "0.25.4", - "@esbuild/linux-x64": "0.25.4", - "@esbuild/netbsd-arm64": "0.25.4", - "@esbuild/netbsd-x64": "0.25.4", - "@esbuild/openbsd-arm64": "0.25.4", - "@esbuild/openbsd-x64": "0.25.4", - "@esbuild/sunos-x64": "0.25.4", - "@esbuild/win32-arm64": "0.25.4", - "@esbuild/win32-ia32": "0.25.4", - "@esbuild/win32-x64": "0.25.4" + "@esbuild/aix-ppc64": "0.25.8", + "@esbuild/android-arm": "0.25.8", + "@esbuild/android-arm64": "0.25.8", + "@esbuild/android-x64": "0.25.8", + "@esbuild/darwin-arm64": "0.25.8", + "@esbuild/darwin-x64": "0.25.8", + "@esbuild/freebsd-arm64": "0.25.8", + "@esbuild/freebsd-x64": "0.25.8", + "@esbuild/linux-arm": "0.25.8", + "@esbuild/linux-arm64": "0.25.8", + "@esbuild/linux-ia32": "0.25.8", + "@esbuild/linux-loong64": "0.25.8", + "@esbuild/linux-mips64el": "0.25.8", + "@esbuild/linux-ppc64": "0.25.8", + "@esbuild/linux-riscv64": "0.25.8", + "@esbuild/linux-s390x": "0.25.8", + "@esbuild/linux-x64": "0.25.8", + "@esbuild/netbsd-arm64": "0.25.8", + "@esbuild/netbsd-x64": "0.25.8", + "@esbuild/openbsd-arm64": "0.25.8", + "@esbuild/openbsd-x64": "0.25.8", + "@esbuild/openharmony-arm64": "0.25.8", + "@esbuild/sunos-x64": "0.25.8", + "@esbuild/win32-arm64": "0.25.8", + "@esbuild/win32-ia32": "0.25.8", + "@esbuild/win32-x64": "0.25.8" } }, "node_modules/escalade": { @@ -4033,6 +3395,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true, + "license": "MIT" + }, "node_modules/eventemitter3": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-2.0.3.tgz", @@ -4045,6 +3414,12 @@ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", "license": "MIT" }, + "node_modules/fast-diff": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.1.2.tgz", + "integrity": "sha512-KaJUt+M9t1qaIteSvjc6P3RbMdXsNhK61GRftR6SNxqmhthcd9MGIi4T+o0jD8LUSpSnSKXE20nLtJ3fOHxQig==", + "license": "Apache-2.0" + }, "node_modules/fast-glob": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", @@ -4097,7 +3472,7 @@ "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" @@ -4135,9 +3510,9 @@ } }, "node_modules/focus-trap": { - "version": "7.6.4", - "resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-7.6.4.tgz", - "integrity": "sha512-xx560wGBk7seZ6y933idtjJQc1l+ck+pI3sKvhKozdBV1dRZoKhkW5xoCaFv9tQiX5RH1xfSxjuNu6g+lmN/gw==", + "version": "7.6.5", + "resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-7.6.5.tgz", + "integrity": "sha512-7Ke1jyybbbPZyZXFxEftUtxFGLMpE2n6A+z//m4CRDlj0hW+o3iYSmh8nFlYMurOiJVDmJRilUQtJr08KfIxlg==", "license": "MIT", "dependencies": { "tabbable": "^6.2.0" @@ -4259,15 +3634,6 @@ "node": ">= 6" } }, - "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, "node_modules/gopd": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", @@ -4280,6 +3646,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/has-property-descriptors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", @@ -4460,10 +3835,10 @@ } }, "node_modules/immutable": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.2.tgz", - "integrity": "sha512-qHKXW1q6liAk1Oys6umoaZbDRqjcjgSrbnrifHsfsttza7zcvRAsL7mMV6xWcyhwQy7Xj5v4hhbr6b+iDYwlmQ==", - "dev": true, + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.3.tgz", + "integrity": "sha512-+chQdDfvscSF1SJqv2gn4SRO2ZyS3xL3r7IW/wWEEzrzLisnOlKiQu5ytC/BVNcS15C39WT2Hg/bjKjDMcu+zg==", + "devOptional": true, "license": "MIT" }, "node_modules/import-fresh": { @@ -4575,7 +3950,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" @@ -4594,7 +3969,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" @@ -4607,7 +3982,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=0.12.0" @@ -4649,6 +4024,19 @@ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "license": "MIT" }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, "node_modules/jsesc": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", @@ -4689,7 +4077,6 @@ "version": "1.30.1", "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.1.tgz", "integrity": "sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==", - "dev": true, "license": "MPL-2.0", "dependencies": { "detect-libc": "^2.0.3" @@ -4721,7 +4108,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -4742,7 +4128,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -4763,7 +4148,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -4784,7 +4168,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -4805,7 +4188,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -4826,7 +4208,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -4847,7 +4228,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -4868,7 +4248,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -4889,7 +4268,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -4910,7 +4288,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -4928,7 +4305,6 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz", "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==", - "dev": true, "license": "Apache-2.0", "engines": { "node": ">=8" @@ -5049,7 +4425,7 @@ "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "braces": "^3.0.3", @@ -5079,7 +4455,6 @@ "version": "3.3.11", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", - "dev": true, "funding": [ { "type": "github", @@ -5115,7 +4490,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 }, @@ -5356,13 +4730,13 @@ "license": "MIT" }, "node_modules/playwright": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.52.0.tgz", - "integrity": "sha512-JAwMNMBlxJ2oD1kce4KPtMkDeKGHQstdpFPcPH3maElAXon/QZeTvtsfXmTMRyO9TslfoYOXkSsvao2nE1ilTw==", + "version": "1.53.2", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.53.2.tgz", + "integrity": "sha512-6K/qQxVFuVQhRQhFsVZ9fGeatxirtrpPgxzBYWyZLEXJzqYwuL4fuNmfOfD5et1tJE4GScKyPNeLhZeRwuTU3A==", "dev": true, "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.52.0" + "playwright-core": "1.53.2" }, "bin": { "playwright": "cli.js" @@ -5375,9 +4749,9 @@ } }, "node_modules/playwright-core": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.52.0.tgz", - "integrity": "sha512-l2osTgLXSMeuLZOML9qYODUQoPPnUsKsb5/P6LJ2e6uPKXUdPK5WYhN4z03G+YNbWmGDY4YENauNu4ZKczreHg==", + "version": "1.53.2", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.53.2.tgz", + "integrity": "sha512-ox/OytMy+2w1jcYEYlOo1Hhp8hZkLCximMTUTMBXjGUA1KoFfiSZ+DU+3a739jsPY0yoKH2TFy9S2fsJas8yAw==", "dev": true, "license": "Apache-2.0", "bin": { @@ -5414,7 +4788,6 @@ "version": "8.5.6", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", - "dev": true, "funding": [ { "type": "opencollective", @@ -5587,12 +4960,6 @@ "node": ">=0.10" } }, - "node_modules/quill-delta/node_modules/fast-diff": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.1.2.tgz", - "integrity": "sha512-KaJUt+M9t1qaIteSvjc6P3RbMdXsNhK61GRftR6SNxqmhthcd9MGIi4T+o0jD8LUSpSnSKXE20nLtJ3fOHxQig==", - "license": "Apache-2.0" - }, "node_modules/quill/node_modules/clone": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", @@ -5764,9 +5131,9 @@ } }, "node_modules/react-is": { - "version": "19.1.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.1.0.tgz", - "integrity": "sha512-Oe56aUPnkHyyDxxkvqtd7KkdQP5uIUfHxd5XTb3wE9d/kRnZLmKbDB0GWk919tdQ+mxxPtG6EAs6RMT6i1qtHg==", + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.1.1.tgz", + "integrity": "sha512-tr41fA15Vn8p4X9ntI+yCyeGSf1TlYaY5vlTZfQmeLBrFo3psOPX6HhTDnFNL9uj3EhP0KAQ80cugCl4b4BERA==", "license": "MIT", "peer": true }, @@ -5939,9 +5306,9 @@ "license": "MIT" }, "node_modules/react-select": { - "version": "5.10.1", - "resolved": "https://registry.npmjs.org/react-select/-/react-select-5.10.1.tgz", - "integrity": "sha512-roPEZUL4aRZDx6DcsD+ZNreVl+fM8VsKn0Wtex1v4IazH60ILp5xhdlp464IsEAlJdXeD+BhDAFsBVMfvLQueA==", + "version": "5.10.2", + "resolved": "https://registry.npmjs.org/react-select/-/react-select-5.10.2.tgz", + "integrity": "sha512-Z33nHdEFWq9tfnfVXaiM12rbJmk+QjFEztWLtmXqQhz6Al4UZZ9xc0wiatmGtUOCCnHN0WizL3tCMYRENX4rVQ==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.12.0", @@ -5986,9 +5353,9 @@ } }, "node_modules/react-tooltip": { - "version": "5.28.1", - "resolved": "https://registry.npmjs.org/react-tooltip/-/react-tooltip-5.28.1.tgz", - "integrity": "sha512-ZA4oHwoIIK09TS7PvSLFcRlje1wGZaxw6xHvfrzn6T82UcMEfEmHVCad16Gnr4NDNDh93HyN037VK4HDi5odfQ==", + "version": "5.29.1", + "resolved": "https://registry.npmjs.org/react-tooltip/-/react-tooltip-5.29.1.tgz", + "integrity": "sha512-rmJmEb/p99xWhwmVT7F7riLG08wwKykjHiMGbDPloNJk3tdI73oHsVOwzZ4SRjqMdd5/xwb/4nmz0RcoMfY7Bw==", "license": "MIT", "dependencies": { "@floating-ui/dom": "^1.6.1", @@ -6019,7 +5386,7 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">= 14.18.0" @@ -6161,84 +5528,42 @@ } }, "node_modules/rolldown": { - "version": "1.0.0-beta.21", - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-beta.21.tgz", - "integrity": "sha512-pjU+yNElXbreaNNz2EDOPrf5Yj6aoT8cTfd4pViBSdO7Nr0MOqHV0vDR9w3V8venZmjzF4LAfs03Cbl46YsdVw==", - "dev": true, + "version": "1.0.0-beta.30", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-beta.30.tgz", + "integrity": "sha512-H/LmDTUPlm65hWOTjXvd1k0qrGinNi8LrG3JsHVm6Oit7STg0upBmgoG5PZUHbAnGTHr0MLoLyzjmH261lIqSg==", "license": "MIT", "dependencies": { - "@oxc-project/runtime": "=0.75.0", - "@oxc-project/types": "=0.75.0", - "@rolldown/pluginutils": "1.0.0-beta.21", + "@oxc-project/runtime": "=0.78.0", + "@oxc-project/types": "=0.78.0", + "@rolldown/pluginutils": "1.0.0-beta.30", "ansis": "^4.0.0" }, "bin": { "rolldown": "bin/cli.mjs" }, "optionalDependencies": { - "@rolldown/binding-darwin-arm64": "1.0.0-beta.21", - "@rolldown/binding-darwin-x64": "1.0.0-beta.21", - "@rolldown/binding-freebsd-x64": "1.0.0-beta.21", - "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-beta.21", - "@rolldown/binding-linux-arm64-gnu": "1.0.0-beta.21", - "@rolldown/binding-linux-arm64-musl": "1.0.0-beta.21", - "@rolldown/binding-linux-x64-gnu": "1.0.0-beta.21", - "@rolldown/binding-linux-x64-musl": "1.0.0-beta.21", - "@rolldown/binding-wasm32-wasi": "1.0.0-beta.21", - "@rolldown/binding-win32-arm64-msvc": "1.0.0-beta.21", - "@rolldown/binding-win32-ia32-msvc": "1.0.0-beta.21", - "@rolldown/binding-win32-x64-msvc": "1.0.0-beta.21" + "@rolldown/binding-android-arm64": "1.0.0-beta.30", + "@rolldown/binding-darwin-arm64": "1.0.0-beta.30", + "@rolldown/binding-darwin-x64": "1.0.0-beta.30", + "@rolldown/binding-freebsd-x64": "1.0.0-beta.30", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-beta.30", + "@rolldown/binding-linux-arm64-gnu": "1.0.0-beta.30", + "@rolldown/binding-linux-arm64-musl": "1.0.0-beta.30", + "@rolldown/binding-linux-arm64-ohos": "1.0.0-beta.30", + "@rolldown/binding-linux-x64-gnu": "1.0.0-beta.30", + "@rolldown/binding-linux-x64-musl": "1.0.0-beta.30", + "@rolldown/binding-wasm32-wasi": "1.0.0-beta.30", + "@rolldown/binding-win32-arm64-msvc": "1.0.0-beta.30", + "@rolldown/binding-win32-ia32-msvc": "1.0.0-beta.30", + "@rolldown/binding-win32-x64-msvc": "1.0.0-beta.30" } }, "node_modules/rolldown/node_modules/@rolldown/pluginutils": { - "version": "1.0.0-beta.21", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.21.tgz", - "integrity": "sha512-OTjWr7XYqRZaSzi6dTe0fP25EEsYEQ2H04xIedXG3D0Hrs+Bpe3V5L48R6y+R5ohTygp1ijC09mbrd7vlslpzA==", - "dev": true, + "version": "1.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.30.tgz", + "integrity": "sha512-whXaSoNUFiyDAjkUF8OBpOm77Szdbk5lGNqFe6CbVbJFrhCCPinCbRA3NjawwlNHla1No7xvXXh+CpSxnPfUEw==", "license": "MIT" }, - "node_modules/rollup": { - "version": "4.41.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.41.1.tgz", - "integrity": "sha512-cPmwD3FnFv8rKMBc1MxWCwVQFxwf1JEmSX3iQXrRVVG15zerAIXRjMFVWnd5Q5QvgKF7Aj+5ykXFhUl+QGnyOw==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "@types/estree": "1.0.7" - }, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.41.1", - "@rollup/rollup-android-arm64": "4.41.1", - "@rollup/rollup-darwin-arm64": "4.41.1", - "@rollup/rollup-darwin-x64": "4.41.1", - "@rollup/rollup-freebsd-arm64": "4.41.1", - "@rollup/rollup-freebsd-x64": "4.41.1", - "@rollup/rollup-linux-arm-gnueabihf": "4.41.1", - "@rollup/rollup-linux-arm-musleabihf": "4.41.1", - "@rollup/rollup-linux-arm64-gnu": "4.41.1", - "@rollup/rollup-linux-arm64-musl": "4.41.1", - "@rollup/rollup-linux-loongarch64-gnu": "4.41.1", - "@rollup/rollup-linux-powerpc64le-gnu": "4.41.1", - "@rollup/rollup-linux-riscv64-gnu": "4.41.1", - "@rollup/rollup-linux-riscv64-musl": "4.41.1", - "@rollup/rollup-linux-s390x-gnu": "4.41.1", - "@rollup/rollup-linux-x64-gnu": "4.41.1", - "@rollup/rollup-linux-x64-musl": "4.41.1", - "@rollup/rollup-win32-arm64-msvc": "4.41.1", - "@rollup/rollup-win32-ia32-msvc": "4.41.1", - "@rollup/rollup-win32-x64-msvc": "4.41.1", - "fsevents": "~2.3.2" - } - }, "node_modules/rrule": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/rrule/-/rrule-2.8.1.tgz", @@ -6288,10 +5613,10 @@ "license": "MIT" }, "node_modules/sass": { - "version": "1.89.0", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.89.0.tgz", - "integrity": "sha512-ld+kQU8YTdGNjOLfRWBzewJpU5cwEv/h5yyqlSeJcj6Yh8U4TDA9UA5FPicqDz/xgRPWRSYIQNiFks21TbA9KQ==", - "dev": true, + "version": "1.90.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.90.0.tgz", + "integrity": "sha512-9GUyuksjw70uNpb1MTYWsH9MQHOHY6kwfnkafC24+7aOMZn9+rVMBxRbLvw756mrBFbIsFg6Xw9IkR2Fnn3k+Q==", + "devOptional": true, "license": "MIT", "dependencies": { "chokidar": "^4.0.0", @@ -6424,7 +5749,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -6466,6 +5790,20 @@ "node": ">=4" } }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -6532,16 +5870,18 @@ "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==", "license": "MIT" }, - "node_modules/styled-components/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "license": "MIT", - "engines": { - "node": ">=4" - } + "node_modules/stylis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==", + "license": "MIT" + }, + "node_modules/suncalc": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/suncalc/-/suncalc-1.9.0.tgz", + "integrity": "sha512-vMJ8Byp1uIPoj+wb9c1AdK4jpkSKVAywgHX0lqY7zt6+EWRRC3Z+0Ucfjy/0yxTVO1hwwchZe4uoFNqrIC24+A==" }, - "node_modules/styled-components/node_modules/supports-color": { + "node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", @@ -6553,17 +5893,6 @@ "node": ">=4" } }, - "node_modules/stylis": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", - "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==", - "license": "MIT" - }, - "node_modules/suncalc": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/suncalc/-/suncalc-1.9.0.tgz", - "integrity": "sha512-vMJ8Byp1uIPoj+wb9c1AdK4jpkSKVAywgHX0lqY7zt6+EWRRC3Z+0Ucfjy/0yxTVO1hwwchZe4uoFNqrIC24+A==" - }, "node_modules/supports-preserve-symlinks-flag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", @@ -6620,7 +5949,6 @@ "version": "0.2.14", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", "integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==", - "dev": true, "license": "MIT", "dependencies": { "fdir": "^6.4.4", @@ -6637,7 +5965,6 @@ "version": "6.4.6", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz", "integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==", - "dev": true, "license": "MIT", "peerDependencies": { "picomatch": "^3 || ^4" @@ -6649,10 +5976,9 @@ } }, "node_modules/tinyglobby/node_modules/picomatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", - "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", - "dev": true, + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "license": "MIT", "engines": { "node": ">=12" @@ -6671,7 +5997,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "is-number": "^7.0.0" @@ -6734,15 +6060,6 @@ "react": ">=15.0.0" } }, - "node_modules/undici-types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", - "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true - }, "node_modules/unicode-properties": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/unicode-properties/-/unicode-properties-1.4.1.tgz", @@ -6833,18 +6150,16 @@ }, "node_modules/vite": { "name": "rolldown-vite", - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/rolldown-vite/-/rolldown-vite-7.0.3.tgz", - "integrity": "sha512-Bg5i1Du+reIljLk5sB/+iOXkhW541NcbS1Ntqd+0EpzdXnl+uxiZDEOUGmVFT8Z94FTpEld2BvoXN80+o2LKAA==", - "dev": true, + "version": "7.0.12", + "resolved": "https://registry.npmjs.org/rolldown-vite/-/rolldown-vite-7.0.12.tgz", + "integrity": "sha512-Gr40FRnE98FwPJcMwcJgBwP6U7Qxw/VEtDsFdFjvGUTdgI/tTmF7z7dbVo/ajItM54G+Zo9w5BIrUmat6MbuWQ==", "license": "MIT", "dependencies": { - "@oxc-project/runtime": "0.75.0", "fdir": "^6.4.6", "lightningcss": "^1.30.1", - "picomatch": "^4.0.2", + "picomatch": "^4.0.3", "postcss": "^8.5.6", - "rolldown": "1.0.0-beta.21", + "rolldown": "1.0.0-beta.30", "tinyglobby": "^0.2.14" }, "bin": { @@ -6943,7 +6258,6 @@ "version": "6.4.6", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz", "integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==", - "dev": true, "license": "MIT", "peerDependencies": { "picomatch": "^3 || ^4" @@ -6958,7 +6272,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, @@ -6970,10 +6283,9 @@ } }, "node_modules/vite/node_modules/picomatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", - "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", - "dev": true, + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "license": "MIT", "engines": { "node": ">=12" @@ -7015,10 +6327,24 @@ "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", "license": "ISC" }, + "node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/xmldoc": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/xmldoc/-/xmldoc-2.0.1.tgz", - "integrity": "sha512-sOOqgsjl3PU6iBw+fBUGAkTCE+JFK+sBaOL3pnZgzqk2/yvOD7RlFmZtDRJAEBzdpOYxSXyOQH4mjubdfs3MSg==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/xmldoc/-/xmldoc-2.0.2.tgz", + "integrity": "sha512-UiRwoSStEXS3R+YE8OqYv3jebza8cBBAI2y8g3B15XFkn3SbEOyyLnmPHjLBPZANrPJKEzxxB7A3XwcLikQVlQ==", "license": "MIT", "dependencies": { "sax": "^1.2.4" @@ -7040,10 +6366,9 @@ "license": "ISC" }, "node_modules/yaml": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.0.tgz", - "integrity": "sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==", - "dev": true, + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.1.tgz", + "integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==", "license": "ISC", "optional": true, "peer": true, @@ -7097,26 +6422,6 @@ "engines": { "node": ">=6" } - }, - "node_modules/yargs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "license": "MIT" - }, - "node_modules/yargs/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } } } } diff --git a/package.json b/package.json index 4102d20f..39bcd49f 100644 --- a/package.json +++ b/package.json @@ -8,10 +8,10 @@ "build": "vite build" }, "devDependencies": { - "@playwright/test": "^1.52.0", - "@vitejs/plugin-react": "^4.6.0", - "@vitejs/plugin-react-swc": "^3.10.2", + "@playwright/test": "1.53.2", "@reduxjs/toolkit": "^1.6.1", + "@vitejs/plugin-react": "^4.6.0", + "esbuild": "^0.25.8", "sass": "^1.88.9", "typescript": "^4.4.2", "vite": "npm:rolldown-vite@^7.0.3", @@ -26,6 +26,7 @@ "@hello-pangea/dnd": "^16.0.0", "@popperjs/core": "^2.11.8", "@u-wave/react-vimeo": "^0.9.11", + "@vitejs/plugin-react-oxc": "^0.3.0", "bootstrap": "^5.3.7", "crypto-js": "^4.0.0", "dayjs": "^1.10.5", diff --git a/playwright.config.ts b/playwright.config.ts index dde1c703..0a2463bb 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -6,6 +6,8 @@ import { defineConfig, devices } from '@playwright/test'; */ // require('dotenv').config(); +const BASE_URL = process.env.BASE_URL ?? 'http://nginx:8080'; + /** * See https://playwright.dev/docs/test-configuration. */ @@ -26,9 +28,7 @@ export default defineConfig({ use: { /* Base URL to use in actions like `await page.goto('/')`. */ // Docker baseurl - baseURL: 'http://nginx:8080/', - // for testing locally - // baseURL: 'https://display.local.itkdev.dk/', + baseURL: BASE_URL, /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ trace: 'on-first-retry', diff --git a/scripts/test b/scripts/test new file mode 100755 index 00000000..ed98d4a3 --- /dev/null +++ b/scripts/test @@ -0,0 +1,24 @@ +#!/usr/bin/env bash + +# -o errexit: Exit immediately if a command exits with a non-zero status. +# -o errtrace: Ensures that the ERR trap is also triggered when the error occurs inside a function or a subshell. (https://stackoverflow.com/questions/25378845/what-does-set-o-errtrace-do-in-a-shell-script) +# -o noclobber: Prevents accidentally overwriting files with output redirection. +# -o nounset: This command will cause the shell to exit if a variable is accessed before it is set. +# -o pipefail: Ensures that a pipeline return the exit status of the command that first fails. +set -o errexit -o errtrace -o noclobber -o nounset -o pipefail + +TEST_PATH="${1:-}" + +# Stop node container to avoid build conflicts. +docker compose stop node +# Build assets. +docker compose run --rm node npm run build + +# Run tests (with or without a test path) +if [[ -n "$TEST_PATH" ]]; then + docker compose run --rm playwright npx playwright test "$TEST_PATH" +else + docker compose run --rm playwright npx playwright test +fi +# Restart node container. +docker compose start node diff --git a/scripts/test.sh b/scripts/test.sh deleted file mode 100755 index aa6cdc02..00000000 --- a/scripts/test.sh +++ /dev/null @@ -1,8 +0,0 @@ -# Stop node container to avoid build conflicts. -docker compose stop node -# Build assets. -docker compose run --rm node npm run build -# Run tests. -docker compose run --rm playwright npx playwright test ${TEMPLATE_FILTER} -# Restart node container. -docker compose start node diff --git a/src/Controller/Admin/AdminConfigController.php b/src/Controller/Admin/AdminConfigController.php new file mode 100644 index 00000000..6d61d2af --- /dev/null +++ b/src/Controller/Admin/AdminConfigController.php @@ -0,0 +1,33 @@ + $this->rejseplanenApiKey, + 'touchButtonRegions' => $this->touchButtonRegions, + 'showScreenStatus' => $this->showScreenStatus, + 'loginMethods' => $this->loginMethods, + 'enhancedPreview' => $this->enhancedPreview, + ]); + } +} diff --git a/src/Controller/Admin/AdminController.php b/src/Controller/Admin/AdminController.php index 757ddb76..98493248 100644 --- a/src/Controller/Admin/AdminController.php +++ b/src/Controller/Admin/AdminController.php @@ -13,11 +13,6 @@ class AdminController extends AbstractController { public function __construct( - private readonly string $rejseplanenApiKey, - private readonly bool $touchButtonRegions, - private readonly bool $showScreenStatus, - private readonly array $loginMethods, - private readonly bool $enhancedPreview, private readonly ?Profiler $profiler = null, ) {} @@ -25,14 +20,6 @@ public function __invoke(): Response { $this->profiler?->disable(); - return $this->render('admin/admin.html.twig', [ - 'config' => json_encode([ - 'rejseplanenApiKey' => $this->rejseplanenApiKey, - 'touchButtonRegions' => $this->touchButtonRegions, - 'showScreenStatus' => $this->showScreenStatus, - 'loginMethods' => $this->loginMethods, - 'enhancedPreview' => $this->enhancedPreview, - ]), - ]); + return $this->render('admin/admin.html.twig'); } } diff --git a/src/Controller/Client/ClientConfigController.php b/src/Controller/Client/ClientConfigController.php new file mode 100644 index 00000000..aa0ffb88 --- /dev/null +++ b/src/Controller/Client/ClientConfigController.php @@ -0,0 +1,39 @@ + $this->loginCheckTimeout, + 'refreshTokenTimeout' => $this->refreshTokenTimeout, + 'releaseTimestampIntervalTimeout' => $this->releaseTimestampIntervalTimeout, + 'pullStrategyInterval' => $this->pullStrategyInterval, + 'schedulingInterval' => $this->schedulingInterval, + 'colorScheme' => $this->colorScheme, + 'debug' => $this->debug, + 'logging' => $this->logging, + ]); + } +} diff --git a/src/Controller/Client/ClientController.php b/src/Controller/Client/ClientController.php index f10d4df6..b834187a 100644 --- a/src/Controller/Client/ClientController.php +++ b/src/Controller/Client/ClientController.php @@ -13,14 +13,6 @@ class ClientController extends AbstractController { public function __construct( - private readonly int $loginCheckTimeout, - private readonly int $refreshTokenTimeout, - private readonly int $releaseTimestampIntervalTimeout, - private readonly int $schedulingInterval, - private readonly int $pullStrategyInterval, - private readonly array $colorScheme, - private readonly bool $debug, - private readonly array $logging, private readonly ?Profiler $profiler = null, ) {} @@ -28,17 +20,6 @@ public function __invoke(): Response { $this->profiler?->disable(); - return $this->render('client/client.html.twig', [ - 'config' => json_encode([ - 'loginCheckTimeout' => $this->loginCheckTimeout, - 'refreshTokenTimeout' => $this->refreshTokenTimeout, - 'releaseTimestampIntervalTimeout' => $this->releaseTimestampIntervalTimeout, - 'pullStrategyInterval' => $this->pullStrategyInterval, - 'schedulingInterval' => $this->schedulingInterval, - 'colorScheme' => $this->colorScheme, - 'debug' => $this->debug, - 'logging' => $this->logging, - ]), - ]); + return $this->render('client/client.html.twig'); } } diff --git a/templates/admin/admin.html.twig b/templates/admin/admin.html.twig index 680f9ab5..05d7f34f 100644 --- a/templates/admin/admin.html.twig +++ b/templates/admin/admin.html.twig @@ -11,10 +11,6 @@ {% block javascripts %} {{ vite_entry_script_tags('admin', {dependency: 'react'}) }} {% endblock %} - - diff --git a/templates/client/client.html.twig b/templates/client/client.html.twig index 204f105d..cf2bfd3f 100644 --- a/templates/client/client.html.twig +++ b/templates/client/client.html.twig @@ -11,10 +11,6 @@ {% block javascripts %} {{ vite_entry_script_tags('client', {dependency: 'react'}) }} {% endblock %} - - diff --git a/vite.config.js b/vite.config.js index 1a956033..71e96119 100644 --- a/vite.config.js +++ b/vite.config.js @@ -1,27 +1,29 @@ -import {defineConfig} from "vite"; +import { defineConfig } from "vite"; import symfonyPlugin from "vite-plugin-symfony"; -import react from "@vitejs/plugin-react-swc"; +import react from "@vitejs/plugin-react-oxc"; import svgr from "vite-plugin-svgr"; -export default defineConfig(({command}) => { +export default defineConfig(({ command }) => { return { - base: command === 'serve' ? '/vite' : '/build', + base: "/build", css: { preprocessorOptions: { scss: { quietDeps: true - }, + } } }, + experimental: { + enableNativePlugin: true + }, plugins: [ react(), symfonyPlugin(), svgr({ // svgr options: https://react-svgr.com/docs/options/ - svgrOptions: {exportType: "default", ref: true, svgo: false, titleProp: true}, - include: "**/*.svg", - }), - + svgrOptions: { exportType: "default", ref: true, svgo: false, titleProp: true }, + include: "**/*.svg" + }) ], build: { outDir: "./public/build", @@ -34,18 +36,17 @@ export default defineConfig(({command}) => { admin: "./assets/admin/index.jsx", client: "./assets/client/index.jsx", template: "./assets/shared/template/index.jsx" - }, - }, + } + } }, server: { - strictPort: true, - port: 3000, host: "0.0.0.0", hmr: { - host: "display.local.itkdev.dk", + host: "node-display.local.itkdev.dk", protocol: "wss", - clientPort: 443, - } - }, - } + clientPort: 443 + }, + cors: true + } + }; });