From 67b69d05f7b4ca1a55bfdcf744b78535a38a5513 Mon Sep 17 00:00:00 2001 From: Anthony LC Date: Wed, 9 Apr 2025 15:32:25 +0200 Subject: [PATCH 01/26] =?UTF-8?q?=F0=9F=9A=A9(backend)=20add=20homepage=20?= =?UTF-8?q?feature=20flag?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a homepage feature flag that we will propagate to the frontend. It will be used to enable or disable the homepage at runtime. --- docs/env.md | 5 +++++ env.d/development/common.dist | 1 + src/backend/core/api/viewsets.py | 1 + src/backend/core/tests/test_api_config.py | 2 ++ src/backend/impress/settings.py | 5 +++++ src/frontend/apps/e2e/__tests__/app-impress/config.spec.ts | 1 + src/helm/env.d/dev/values.impress.yaml.gotmpl | 1 + 7 files changed, 16 insertions(+) diff --git a/docs/env.md b/docs/env.md index 767952fac..22bc601f6 100644 --- a/docs/env.md +++ b/docs/env.md @@ -47,6 +47,11 @@ These are the environmental variables you can set for the impress-backend contai | COLLABORATION_API_URL | collaboration api host | | | COLLABORATION_SERVER_SECRET | collaboration api secret | | | COLLABORATION_WS_URL | collaboration websocket url | | +| FRONTEND_CSS_URL | To add a external css file to the app | | +| FRONTEND_HOMEPAGE_FEATURE_ENABLED | frontend feature flag to display the homepage | false | +| FRONTEND_FOOTER_FEATURE_ENABLED | frontend feature flag to display the footer | false | +| FRONTEND_FOOTER_VIEW_CACHE_TIMEOUT | Cache duration of the json footer | 86400 | +| FRONTEND_URL_JSON_FOOTER | Url with a json to configure the footer | | | FRONTEND_THEME | frontend theme to use | | | POSTHOG_KEY | posthog key for analytics | | | CRISP_WEBSITE_ID | crisp website id for support | | diff --git a/env.d/development/common.dist b/env.d/development/common.dist index 451a40a7b..471f5aee2 100644 --- a/env.d/development/common.dist +++ b/env.d/development/common.dist @@ -64,5 +64,6 @@ COLLABORATION_WS_URL=ws://localhost:4444/collaboration/ws/ # Frontend FRONTEND_THEME=default +FRONTEND_HOMEPAGE_FEATURE_ENABLED=True FRONTEND_FOOTER_FEATURE_ENABLED=True FRONTEND_URL_JSON_FOOTER=http://frontend:3000/contents/footer-demo.json diff --git a/src/backend/core/api/viewsets.py b/src/backend/core/api/viewsets.py index 9f8a12557..685cfb836 100644 --- a/src/backend/core/api/viewsets.py +++ b/src/backend/core/api/viewsets.py @@ -1692,6 +1692,7 @@ def get(self, request): "CRISP_WEBSITE_ID", "ENVIRONMENT", "FRONTEND_CSS_URL", + "FRONTEND_HOMEPAGE_FEATURE_ENABLED", "FRONTEND_FOOTER_FEATURE_ENABLED", "FRONTEND_THEME", "MEDIA_BASE_URL", diff --git a/src/backend/core/tests/test_api_config.py b/src/backend/core/tests/test_api_config.py index e6adb1ae8..8ce579e24 100644 --- a/src/backend/core/tests/test_api_config.py +++ b/src/backend/core/tests/test_api_config.py @@ -19,6 +19,7 @@ COLLABORATION_WS_URL="http://testcollab/", CRISP_WEBSITE_ID="123", FRONTEND_CSS_URL="http://testcss/", + FRONTEND_HOMEPAGE_FEATURE_ENABLED=True, FRONTEND_FOOTER_FEATURE_ENABLED=True, FRONTEND_THEME="test-theme", MEDIA_BASE_URL="http://testserver/", @@ -41,6 +42,7 @@ def test_api_config(is_authenticated): "CRISP_WEBSITE_ID": "123", "ENVIRONMENT": "test", "FRONTEND_CSS_URL": "http://testcss/", + "FRONTEND_HOMEPAGE_FEATURE_ENABLED": True, "FRONTEND_FOOTER_FEATURE_ENABLED": True, "FRONTEND_THEME": "test-theme", "LANGUAGES": [ diff --git a/src/backend/impress/settings.py b/src/backend/impress/settings.py index 9d825095b..55e7909b8 100755 --- a/src/backend/impress/settings.py +++ b/src/backend/impress/settings.py @@ -410,6 +410,11 @@ class Base(Configuration): FRONTEND_THEME = values.Value( None, environ_name="FRONTEND_THEME", environ_prefix=None ) + FRONTEND_HOMEPAGE_FEATURE_ENABLED = values.BooleanValue( + default=False, + environ_name="FRONTEND_HOMEPAGE_FEATURE_ENABLED", + environ_prefix=None, + ) FRONTEND_URL_JSON_FOOTER = values.Value( None, environ_name="FRONTEND_URL_JSON_FOOTER", environ_prefix=None ) diff --git a/src/frontend/apps/e2e/__tests__/app-impress/config.spec.ts b/src/frontend/apps/e2e/__tests__/app-impress/config.spec.ts index c04156651..c2f3d3d18 100644 --- a/src/frontend/apps/e2e/__tests__/app-impress/config.spec.ts +++ b/src/frontend/apps/e2e/__tests__/app-impress/config.spec.ts @@ -10,6 +10,7 @@ const config = { COLLABORATION_WS_URL: 'ws://localhost:4444/collaboration/ws/', ENVIRONMENT: 'development', FRONTEND_CSS_URL: null, + FRONTEND_HOMEPAGE_FEATURE_ENABLED: true, FRONTEND_FOOTER_FEATURE_ENABLED: true, FRONTEND_THEME: 'default', MEDIA_BASE_URL: 'http://localhost:8083', diff --git a/src/helm/env.d/dev/values.impress.yaml.gotmpl b/src/helm/env.d/dev/values.impress.yaml.gotmpl index 25728d041..b3a5e4108 100644 --- a/src/helm/env.d/dev/values.impress.yaml.gotmpl +++ b/src/helm/env.d/dev/values.impress.yaml.gotmpl @@ -50,6 +50,7 @@ backend: DB_USER: dinum DB_PASSWORD: pass DB_PORT: 5432 + FRONTEND_HOMEPAGE_FEATURE_ENABLED: true FRONTEND_FOOTER_FEATURE_ENABLED: true FRONTEND_URL_JSON_FOOTER: https://impress.127.0.0.1.nip.io/contents/footer-demo.json POSTGRES_DB: impress From e9ab099ce04f682d0f6e8869b6734f74690c5f3e Mon Sep 17 00:00:00 2001 From: Anthony LC Date: Wed, 9 Apr 2025 16:00:29 +0200 Subject: [PATCH 02/26] =?UTF-8?q?=F0=9F=9A=A9(frontend)=20integrate=20home?= =?UTF-8?q?page=20feature=20flag?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the homepage feature flag is enabled, the homepage will be displayed. --- CHANGELOG.md | 5 +++ .../apps/e2e/__tests__/app-impress/common.ts | 21 ++++++++++++ .../e2e/__tests__/app-impress/config.spec.ts | 33 ++++--------------- .../e2e/__tests__/app-impress/home.spec.ts | 25 ++++++++++++++ .../impress/src/core/config/api/useConfig.tsx | 11 ++++--- .../src/features/auth/components/Auth.tsx | 10 ++++-- 6 files changed, 71 insertions(+), 34 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3738603cf..f4f1a6431 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,11 @@ and this project adheres to ## [Unreleased] +## Added + +- 🚩 add homepage feature flag #861 + + ## [3.1.0] - 2025-04-07 ## Added diff --git a/src/frontend/apps/e2e/__tests__/app-impress/common.ts b/src/frontend/apps/e2e/__tests__/app-impress/common.ts index a6b559939..11ae09024 100644 --- a/src/frontend/apps/e2e/__tests__/app-impress/common.ts +++ b/src/frontend/apps/e2e/__tests__/app-impress/common.ts @@ -1,5 +1,26 @@ import { Page, expect } from '@playwright/test'; +export const CONFIG = { + AI_FEATURE_ENABLED: true, + CRISP_WEBSITE_ID: null, + COLLABORATION_WS_URL: 'ws://localhost:4444/collaboration/ws/', + ENVIRONMENT: 'development', + FRONTEND_CSS_URL: null, + FRONTEND_HOMEPAGE_FEATURE_ENABLED: true, + FRONTEND_FOOTER_FEATURE_ENABLED: true, + FRONTEND_THEME: 'default', + MEDIA_BASE_URL: 'http://localhost:8083', + LANGUAGES: [ + ['en-us', 'English'], + ['fr-fr', 'Français'], + ['de-de', 'Deutsch'], + ['nl-nl', 'Nederlands'], + ], + LANGUAGE_CODE: 'en-us', + POSTHOG_KEY: {}, + SENTRY_DSN: null, +}; + export const keyCloakSignIn = async ( page: Page, browserName: string, diff --git a/src/frontend/apps/e2e/__tests__/app-impress/config.spec.ts b/src/frontend/apps/e2e/__tests__/app-impress/config.spec.ts index c2f3d3d18..90557aad2 100644 --- a/src/frontend/apps/e2e/__tests__/app-impress/config.spec.ts +++ b/src/frontend/apps/e2e/__tests__/app-impress/config.spec.ts @@ -2,28 +2,7 @@ import path from 'path'; import { expect, test } from '@playwright/test'; -import { createDoc } from './common'; - -const config = { - AI_FEATURE_ENABLED: true, - CRISP_WEBSITE_ID: null, - COLLABORATION_WS_URL: 'ws://localhost:4444/collaboration/ws/', - ENVIRONMENT: 'development', - FRONTEND_CSS_URL: null, - FRONTEND_HOMEPAGE_FEATURE_ENABLED: true, - FRONTEND_FOOTER_FEATURE_ENABLED: true, - FRONTEND_THEME: 'default', - MEDIA_BASE_URL: 'http://localhost:8083', - LANGUAGES: [ - ['en-us', 'English'], - ['fr-fr', 'Français'], - ['de-de', 'Deutsch'], - ['nl-nl', 'Nederlands'], - ], - LANGUAGE_CODE: 'en-us', - POSTHOG_KEY: {}, - SENTRY_DSN: null, -}; +import { CONFIG, createDoc } from './common'; test.describe('Config', () => { test('it checks the config api is called', async ({ page }) => { @@ -37,7 +16,7 @@ test.describe('Config', () => { const response = await responsePromise; expect(response.ok()).toBeTruthy(); - expect(await response.json()).toStrictEqual(config); + expect(await response.json()).toStrictEqual(CONFIG); }); test('it checks that sentry is trying to init from config endpoint', async ({ @@ -48,7 +27,7 @@ test.describe('Config', () => { if (request.method().includes('GET')) { await route.fulfill({ json: { - ...config, + ...CONFIG, SENTRY_DSN: 'https://sentry.io/123', }, }); @@ -121,7 +100,7 @@ test.describe('Config', () => { if (request.method().includes('GET')) { await route.fulfill({ json: { - ...config, + ...CONFIG, AI_FEATURE_ENABLED: false, }, }); @@ -152,7 +131,7 @@ test.describe('Config', () => { if (request.method().includes('GET')) { await route.fulfill({ json: { - ...config, + ...CONFIG, CRISP_WEBSITE_ID: '1234', }, }); @@ -174,7 +153,7 @@ test.describe('Config', () => { if (request.method().includes('GET')) { await route.fulfill({ json: { - ...config, + ...CONFIG, FRONTEND_CSS_URL: 'http://localhost:123465/css/style.css', }, }); diff --git a/src/frontend/apps/e2e/__tests__/app-impress/home.spec.ts b/src/frontend/apps/e2e/__tests__/app-impress/home.spec.ts index 829b45e7c..d25879291 100644 --- a/src/frontend/apps/e2e/__tests__/app-impress/home.spec.ts +++ b/src/frontend/apps/e2e/__tests__/app-impress/home.spec.ts @@ -1,5 +1,7 @@ import { expect, test } from '@playwright/test'; +import { CONFIG } from './common'; + test.beforeEach(async ({ page }) => { await page.goto('/docs/'); }); @@ -50,4 +52,27 @@ test.describe('Home page', () => { await expect(footer).toBeVisible(); }); + + test('it checks the homepage feature flag', async ({ page }) => { + await page.route('**/api/v1.0/config/', async (route) => { + const request = route.request(); + if (request.method().includes('GET')) { + await route.fulfill({ + json: { + ...CONFIG, + FRONTEND_HOMEPAGE_FEATURE_ENABLED: false, + }, + }); + } else { + await route.continue(); + } + }); + + await page.goto('/'); + + // Keyclock login page + await expect( + page.locator('.login-pf-page-header').getByText('impress'), + ).toBeVisible(); + }); }); diff --git a/src/frontend/apps/impress/src/core/config/api/useConfig.tsx b/src/frontend/apps/impress/src/core/config/api/useConfig.tsx index 65187ce0e..aa3648770 100644 --- a/src/frontend/apps/impress/src/core/config/api/useConfig.tsx +++ b/src/frontend/apps/impress/src/core/config/api/useConfig.tsx @@ -5,17 +5,18 @@ import { Theme } from '@/cunningham/'; import { PostHogConf } from '@/services'; interface ConfigResponse { - LANGUAGES: [string, string][]; - LANGUAGE_CODE: string; - ENVIRONMENT: string; + AI_FEATURE_ENABLED?: boolean; COLLABORATION_WS_URL?: string; CRISP_WEBSITE_ID?: string; - FRONTEND_THEME?: Theme; + ENVIRONMENT: string; FRONTEND_CSS_URL?: string; + FRONTEND_HOMEPAGE_FEATURE_ENABLED?: boolean; + FRONTEND_THEME?: Theme; + LANGUAGES: [string, string][]; + LANGUAGE_CODE: string; MEDIA_BASE_URL?: string; POSTHOG_KEY?: PostHogConf; SENTRY_DSN?: string; - AI_FEATURE_ENABLED?: boolean; } export const getConfig = async (): Promise => { diff --git a/src/frontend/apps/impress/src/features/auth/components/Auth.tsx b/src/frontend/apps/impress/src/features/auth/components/Auth.tsx index 7d47b9b15..87023c805 100644 --- a/src/frontend/apps/impress/src/features/auth/components/Auth.tsx +++ b/src/frontend/apps/impress/src/features/auth/components/Auth.tsx @@ -3,14 +3,16 @@ import { useRouter } from 'next/router'; import { PropsWithChildren } from 'react'; import { Box } from '@/components'; +import { useConfig } from '@/core'; import { useAuth } from '../hooks'; -import { getAuthUrl } from '../utils'; +import { getAuthUrl, gotoLogin } from '../utils'; export const Auth = ({ children }: PropsWithChildren) => { const { isLoading, pathAllowed, isFetchedAfterMount, authenticated } = useAuth(); const { replace, pathname } = useRouter(); + const { data: config } = useConfig(); if (isLoading && !isFetchedAfterMount) { return ( @@ -40,7 +42,11 @@ export const Auth = ({ children }: PropsWithChildren) => { * If the user is not authenticated and the path is not allowed, we redirect to the login page. */ if (!authenticated && !pathAllowed) { - void replace('/login'); + if (config?.FRONTEND_HOMEPAGE_FEATURE_ENABLED) { + void replace('/login'); + } else { + gotoLogin(); + } return ( From ecd06560c6dab354b0c42249ee7af31ebfd8ed95 Mon Sep 17 00:00:00 2001 From: Anthony LC Date: Thu, 10 Apr 2025 09:58:13 +0200 Subject: [PATCH 03/26] =?UTF-8?q?=F0=9F=9A=9A(frontend)=20Display=20homepa?= =?UTF-8?q?ge=20on=20/home=20url?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The homepage is now accessible at the /home URL. Before the homepage was accessible on the /login URL. We still keep the /login URL for backward compatibility. --- .../apps/impress/src/features/auth/components/Auth.tsx | 6 +++--- src/frontend/apps/impress/src/pages/home/index.tsx | 8 ++++++++ 2 files changed, 11 insertions(+), 3 deletions(-) create mode 100644 src/frontend/apps/impress/src/pages/home/index.tsx diff --git a/src/frontend/apps/impress/src/features/auth/components/Auth.tsx b/src/frontend/apps/impress/src/features/auth/components/Auth.tsx index 87023c805..2cf007e54 100644 --- a/src/frontend/apps/impress/src/features/auth/components/Auth.tsx +++ b/src/frontend/apps/impress/src/features/auth/components/Auth.tsx @@ -43,7 +43,7 @@ export const Auth = ({ children }: PropsWithChildren) => { */ if (!authenticated && !pathAllowed) { if (config?.FRONTEND_HOMEPAGE_FEATURE_ENABLED) { - void replace('/login'); + void replace('/home'); } else { gotoLogin(); } @@ -55,9 +55,9 @@ export const Auth = ({ children }: PropsWithChildren) => { } /** - * If the user is authenticated and the path is the login page, we redirect to the home page. + * If the user is authenticated and the path is the home page, we redirect to the index. */ - if (pathname === '/login' && authenticated) { + if (pathname === '/home' && authenticated) { void replace('/'); return ( diff --git a/src/frontend/apps/impress/src/pages/home/index.tsx b/src/frontend/apps/impress/src/pages/home/index.tsx new file mode 100644 index 000000000..dca212335 --- /dev/null +++ b/src/frontend/apps/impress/src/pages/home/index.tsx @@ -0,0 +1,8 @@ +import { HomeContent } from '@/features/home'; +import { NextPageWithLayout } from '@/types/next'; + +const Page: NextPageWithLayout = () => { + return ; +}; + +export default Page; From 419079ac69c2174e791b2bf2cc7a9b6a14ee8f87 Mon Sep 17 00:00:00 2001 From: Samuel Paccoud - DINUM Date: Thu, 17 Apr 2025 18:36:29 +0200 Subject: [PATCH 04/26] =?UTF-8?q?=F0=9F=9A=B8(backend)=20make=20document?= =?UTF-8?q?=20search=20on=20title=20accent-insensitive?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This should work in both cases: - search for "vélo" when the document title contains "velo" - search for "velo" when the document title contains "vélo" --- CHANGELOG.md | 1 + src/backend/core/api/filters.py | 37 +++++++++++++++++-- .../0021_activate_unaccent_extension.py | 10 +++++ .../test_api_documents_descendants_filters.py | 15 ++++++-- 4 files changed, 56 insertions(+), 7 deletions(-) create mode 100644 src/backend/core/migrations/0021_activate_unaccent_extension.py diff --git a/CHANGELOG.md b/CHANGELOG.md index f4f1a6431..40e36bf12 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to ## Added +- 🚸(backend) make document search on title accent-insensitive #874 - 🚩 add homepage feature flag #861 diff --git a/src/backend/core/api/filters.py b/src/backend/core/api/filters.py index 731deb155..5b0721fbb 100644 --- a/src/backend/core/api/filters.py +++ b/src/backend/core/api/filters.py @@ -1,5 +1,7 @@ """API filters for Impress' core application.""" +import unicodedata + from django.utils.translation import gettext_lazy as _ import django_filters @@ -7,13 +9,42 @@ from core import models +def remove_accents(value): + """Remove accents from a string (vélo -> velo).""" + return "".join( + c + for c in unicodedata.normalize("NFD", value) + if unicodedata.category(c) != "Mn" + ) + + +class AccentInsensitiveCharFilter(django_filters.CharFilter): + """ + A custom CharFilter that filters on the accent-insensitive value searched. + """ + + def filter(self, qs, value): + """ + Apply the filter to the queryset using the unaccented version of the field. + + Args: + qs: The queryset to filter. + value: The value to search for in the unaccented field. + Returns: + A filtered queryset. + """ + if value: + value = remove_accents(value) + return super().filter(qs, value) + + class DocumentFilter(django_filters.FilterSet): """ - Custom filter for filtering documents. + Custom filter for filtering documents on title (accent and case insensitive). """ - title = django_filters.CharFilter( - field_name="title", lookup_expr="icontains", label=_("Title") + title = AccentInsensitiveCharFilter( + field_name="title", lookup_expr="unaccent__icontains", label=_("Title") ) class Meta: diff --git a/src/backend/core/migrations/0021_activate_unaccent_extension.py b/src/backend/core/migrations/0021_activate_unaccent_extension.py new file mode 100644 index 000000000..b3bd5ec4c --- /dev/null +++ b/src/backend/core/migrations/0021_activate_unaccent_extension.py @@ -0,0 +1,10 @@ +from django.contrib.postgres.operations import UnaccentExtension +from django.db import migrations + + +class Migration(migrations.Migration): + dependencies = [ + ("core", "0020_remove_is_public_add_field_attachments_and_duplicated_from"), + ] + + operations = [UnaccentExtension()] diff --git a/src/backend/core/tests/documents/test_api_documents_descendants_filters.py b/src/backend/core/tests/documents/test_api_documents_descendants_filters.py index dec34895d..342ead705 100644 --- a/src/backend/core/tests/documents/test_api_documents_descendants_filters.py +++ b/src/backend/core/tests/documents/test_api_documents_descendants_filters.py @@ -7,6 +7,7 @@ from rest_framework.test import APIClient from core import factories +from core.api.filters import remove_accents fake = Faker() pytestmark = pytest.mark.django_db @@ -49,14 +50,16 @@ def test_api_documents_descendants_filter_unknown_field(): [ ("Project Alpha", 1), # Exact match ("project", 2), # Partial match (case-insensitive) - ("Guide", 1), # Word match within a title + ("Guide", 2), # Word match within a title ("Special", 0), # No match (nonexistent keyword) ("2024", 2), # Match by numeric keyword - ("", 5), # Empty string + ("", 6), # Empty string + ("velo", 1), # Accent-insensitive match (velo vs vélo) + ("bêta", 1), # Accent-insensitive match (bêta vs beta) ], ) def test_api_documents_descendants_filter_title(query, nb_results): - """Authenticated users should be able to search documents by their title.""" + """Authenticated users should be able to search documents by their unaccented title.""" user = factories.UserFactory() client = APIClient() client.force_login(user) @@ -70,6 +73,7 @@ def test_api_documents_descendants_filter_title(query, nb_results): "User Guide", "Financial Report 2024", "Annual Review 2024", + "Guide du vélo urbain", # <-- Title with accent for accent-insensitive test ] for title in titles: factories.DocumentFactory(title=title, parent=document) @@ -85,4 +89,7 @@ def test_api_documents_descendants_filter_title(query, nb_results): # Ensure all results contain the query in their title for result in results: - assert query.lower().strip() in result["title"].lower() + assert ( + remove_accents(query).lower().strip() + in remove_accents(result["title"]).lower() + ) From 101cef7d701d4129b4696c4a210c9896752e3ab2 Mon Sep 17 00:00:00 2001 From: Anthony LC Date: Tue, 22 Apr 2025 10:38:51 +0200 Subject: [PATCH 05/26] =?UTF-8?q?=E2=99=BB=EF=B8=8F(frontend)=20refacto=20?= =?UTF-8?q?useCunninghamTheme?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refacto useCunninghamTheme, we don't need a function to have access to the tokens anymore. --- .../apps/impress/src/components/Card.tsx | 2 +- .../impress/src/components/DropdownMenu.tsx | 16 +++-- .../quick-search/QuickSearchInput.tsx | 3 +- .../quick-search/QuickSearchItemContent.tsx | 3 +- .../separators/HorizontalSeparator.tsx | 2 +- .../separators/SeparatedSection.tsx | 8 +-- .../__tests__/useCunninghamTheme.spec.tsx | 2 +- .../src/cunningham/useCunninghamTheme.tsx | 68 +++++++++++-------- .../docs/doc-editor/components/DocEditor.tsx | 2 +- .../components/custom-blocks/DividerBlock.tsx | 4 +- .../components/custom-blocks/QuoteBlock.tsx | 2 +- .../doc-export/blocks-mapping/dividerDocx.tsx | 2 +- .../doc-export/blocks-mapping/dividerPDF.tsx | 2 +- .../docs/doc-header/components/DocHeader.tsx | 14 ++-- .../docs/doc-header/components/DocTitle.tsx | 2 +- .../docs/doc-header/components/DocToolBox.tsx | 9 +-- .../components/DocVersionHeader.tsx | 3 +- .../components/DocShareAddMemberList.tsx | 14 ++-- .../components/DocShareAddMemberListItem.tsx | 20 +++--- .../components/DocShareInvitationItem.tsx | 3 +- .../components/DocShareMemberItem.tsx | 3 +- .../doc-share/components/DocVisibility.tsx | 14 ++-- .../doc-share/components/SearchUserRow.tsx | 8 +-- .../doc-table-content/components/Heading.tsx | 2 +- .../components/TableContent.tsx | 3 +- .../doc-versioning/components/VersionItem.tsx | 7 +- .../docs-grid/components/DocsGridItem.tsx | 5 +- .../docs-grid/components/SimpleDocItem.tsx | 5 +- .../impress/src/features/footer/Footer.tsx | 2 +- .../src/features/header/components/Header.tsx | 17 ++--- .../features/header/components/LaGaufre.tsx | 2 +- .../src/features/header/components/Title.tsx | 5 +- .../features/home/components/HomeBanner.tsx | 5 +- .../features/home/components/HomeBottom.tsx | 7 +- .../features/home/components/HomeContent.tsx | 2 +- .../features/home/components/HomeHeader.tsx | 5 +- .../features/home/components/HomeSection.tsx | 15 ++-- .../components/LefPanelTargetFilters.tsx | 12 ++-- .../left-panel/components/LeftPanel.tsx | 14 ++-- .../components/LeftPanelDocContent.tsx | 3 +- .../components/LeftPanelFavoriteItem.tsx | 4 +- .../components/LeftPanelFavorites.tsx | 3 +- .../apps/impress/src/layouts/MainLayout.tsx | 5 +- .../impress/src/pages/accessibility/index.tsx | 2 +- .../impress/src/pages/legal-notice/index.tsx | 2 +- .../src/pages/personal-data-cookies/index.tsx | 2 +- 46 files changed, 159 insertions(+), 176 deletions(-) diff --git a/src/frontend/apps/impress/src/components/Card.tsx b/src/frontend/apps/impress/src/components/Card.tsx index 08aec9388..9e884bf47 100644 --- a/src/frontend/apps/impress/src/components/Card.tsx +++ b/src/frontend/apps/impress/src/components/Card.tsx @@ -18,7 +18,7 @@ export const Card = ({ $background="white" $radius="4px" $css={css` - border: 1px solid ${colorsTokens()['greyscale-200']}; + border: 1px solid ${colorsTokens['greyscale-200']}; ${$css} `} {...props} diff --git a/src/frontend/apps/impress/src/components/DropdownMenu.tsx b/src/frontend/apps/impress/src/components/DropdownMenu.tsx index 2664e928a..8758588ed 100644 --- a/src/frontend/apps/impress/src/components/DropdownMenu.tsx +++ b/src/frontend/apps/impress/src/components/DropdownMenu.tsx @@ -35,9 +35,7 @@ export const DropdownMenu = ({ label, topMessage, }: PropsWithChildren) => { - const theme = useCunninghamTheme(); - const spacings = theme.spacingsTokens(); - const colors = theme.colorsTokens(); + const { spacingsTokens, colorsTokens } = useCunninghamTheme(); const [isOpen, setIsOpen] = useState(false); const blockButtonRef = useRef(null); @@ -120,11 +118,11 @@ export const DropdownMenu = ({ key={option.label} $align="center" $justify="space-between" - $background={colors['greyscale-000']} - $color={colors['primary-600']} + $background={colorsTokens['greyscale-000']} + $color={colorsTokens['primary-600']} $padding={{ vertical: 'xs', horizontal: 'base' }} $width="100%" - $gap={spacings['base']} + $gap={spacingsTokens['base']} $css={css` border: none; ${index === 0 && @@ -148,7 +146,11 @@ export const DropdownMenu = ({ } `} > - + {option.icon && ( { const { t } = useTranslation(); const { spacingsTokens } = useCunninghamTheme(); - const spacing = spacingsTokens(); if (children) { return ( @@ -44,7 +43,7 @@ export const QuickSearchInput = ({ $direction="row" $align="center" className="quick-search-input" - $gap={spacing['2xs']} + $gap={spacingsTokens['2xs']} $padding={{ all: 'base' }} > {!loading && } diff --git a/src/frontend/apps/impress/src/components/quick-search/QuickSearchItemContent.tsx b/src/frontend/apps/impress/src/components/quick-search/QuickSearchItemContent.tsx index 94dc5efc8..09330bd5c 100644 --- a/src/frontend/apps/impress/src/components/quick-search/QuickSearchItemContent.tsx +++ b/src/frontend/apps/impress/src/components/quick-search/QuickSearchItemContent.tsx @@ -17,7 +17,6 @@ export const QuickSearchItemContent = ({ right, }: QuickSearchItemContentProps) => { const { spacingsTokens } = useCunninghamTheme(); - const spacings = spacingsTokens(); const { isDesktop } = useResponsiveStore(); @@ -32,7 +31,7 @@ export const QuickSearchItemContent = ({ {left} diff --git a/src/frontend/apps/impress/src/components/separators/HorizontalSeparator.tsx b/src/frontend/apps/impress/src/components/separators/HorizontalSeparator.tsx index 4b98621a9..f8ab9bd1a 100644 --- a/src/frontend/apps/impress/src/components/separators/HorizontalSeparator.tsx +++ b/src/frontend/apps/impress/src/components/separators/HorizontalSeparator.tsx @@ -26,7 +26,7 @@ export const HorizontalSeparator = ({ $background={ variant === SeparatorVariant.DARK ? '#e5e5e533' - : colorsTokens()['greyscale-100'] + : colorsTokens['greyscale-100'] } className="--docs--horizontal-separator" /> diff --git a/src/frontend/apps/impress/src/components/separators/SeparatedSection.tsx b/src/frontend/apps/impress/src/components/separators/SeparatedSection.tsx index 6a8f77900..0411f5b0e 100644 --- a/src/frontend/apps/impress/src/components/separators/SeparatedSection.tsx +++ b/src/frontend/apps/impress/src/components/separators/SeparatedSection.tsx @@ -13,17 +13,15 @@ export const SeparatedSection = ({ showSeparator = true, children, }: PropsWithChildren) => { - const theme = useCunninghamTheme(); - const colors = theme.colorsTokens(); - const spacings = theme.spacingsTokens(); + const { colorsTokens, spacingsTokens } = useCunninghamTheme(); return ( diff --git a/src/frontend/apps/impress/src/cunningham/__tests__/useCunninghamTheme.spec.tsx b/src/frontend/apps/impress/src/cunningham/__tests__/useCunninghamTheme.spec.tsx index c3c6bcfd6..425781d6c 100644 --- a/src/frontend/apps/impress/src/cunningham/__tests__/useCunninghamTheme.spec.tsx +++ b/src/frontend/apps/impress/src/cunningham/__tests__/useCunninghamTheme.spec.tsx @@ -4,7 +4,7 @@ describe('', () => { it('has the logo correctly set', () => { const { themeTokens, setTheme } = useCunninghamTheme.getState(); setTheme('default'); - const logo = themeTokens().logo; + const logo = themeTokens.logo; expect(logo?.src).toBe('/assets/logo-gouv.svg'); expect(logo?.widthHeader).toBe('110px'); expect(logo?.widthFooter).toBe('220px'); diff --git a/src/frontend/apps/impress/src/cunningham/useCunninghamTheme.tsx b/src/frontend/apps/impress/src/cunningham/useCunninghamTheme.tsx index 81cc478c2..7cc5e6628 100644 --- a/src/frontend/apps/impress/src/cunningham/useCunninghamTheme.tsx +++ b/src/frontend/apps/impress/src/cunningham/useCunninghamTheme.tsx @@ -3,39 +3,53 @@ import { create } from 'zustand'; import { tokens } from './cunningham-tokens'; -type Tokens = typeof tokens.themes.default; +type Tokens = typeof tokens.themes.default & + Partial<(typeof tokens.themes)[keyof typeof tokens.themes]>; type ColorsTokens = Tokens['theme']['colors']; type FontSizesTokens = Tokens['theme']['font']['sizes']; type SpacingsTokens = Tokens['theme']['spacings']; type ComponentTokens = Tokens['components']; export type Theme = keyof typeof tokens.themes; -interface AuthStore { - theme: string; +interface ThemeStore { + theme: Theme; setTheme: (theme: Theme) => void; - themeTokens: () => Partial; - colorsTokens: () => Partial; - fontSizesTokens: () => Partial; - spacingsTokens: () => Partial; - componentTokens: () => ComponentTokens; + themeTokens: Partial; + colorsTokens: Partial; + fontSizesTokens: Partial; + spacingsTokens: Partial; + componentTokens: ComponentTokens; } -export const useCunninghamTheme = create((set, get) => { - const currentTheme = () => - merge( - tokens.themes['default'], - tokens.themes[get().theme as keyof typeof tokens.themes], - ) as Tokens; - - return { - theme: 'default', - themeTokens: () => currentTheme().theme, - colorsTokens: () => currentTheme().theme.colors, - componentTokens: () => currentTheme().components, - spacingsTokens: () => currentTheme().theme.spacings, - fontSizesTokens: () => currentTheme().theme.font.sizes, - setTheme: (theme: Theme) => { - set({ theme }); - }, - }; -}); +const getMergedTokens = (theme: Theme) => { + return merge({}, tokens.themes['default'], tokens.themes[theme]); +}; + +const DEFAULT_THEME: Theme = 'default'; +const defaultTokens = getMergedTokens(DEFAULT_THEME); + +const initialState: ThemeStore = { + theme: DEFAULT_THEME, + setTheme: () => {}, + themeTokens: defaultTokens.theme, + colorsTokens: defaultTokens.theme.colors, + componentTokens: defaultTokens.components, + spacingsTokens: defaultTokens.theme.spacings, + fontSizesTokens: defaultTokens.theme.font.sizes, +}; + +export const useCunninghamTheme = create((set) => ({ + ...initialState, + setTheme: (theme: Theme) => { + const newTokens = getMergedTokens(theme); + + set({ + theme, + themeTokens: newTokens.theme, + colorsTokens: newTokens.theme.colors, + componentTokens: newTokens.components, + spacingsTokens: newTokens.theme.spacings, + fontSizesTokens: newTokens.theme.font.sizes, + }); + }, +})); diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/components/DocEditor.tsx b/src/frontend/apps/impress/src/features/docs/doc-editor/components/DocEditor.tsx index 41a2467dd..d7e23aa50 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-editor/components/DocEditor.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-editor/components/DocEditor.tsx @@ -67,7 +67,7 @@ export const DocEditor = ({ doc, versionId }: DocEditorProps) => { ); }, diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-blocks/QuoteBlock.tsx b/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-blocks/QuoteBlock.tsx index a034c466c..f52a5c702 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-blocks/QuoteBlock.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-blocks/QuoteBlock.tsx @@ -27,7 +27,7 @@ export const QuoteBlock = createReactBlockSpec( $margin="0 0 1rem 0" $padding="0.5rem 1rem" style={{ - borderLeft: `4px solid ${colorsTokens()['greyscale-300']}`, + borderLeft: `4px solid ${colorsTokens['greyscale-300']}`, fontStyle: 'italic', flexGrow: 1, }} diff --git a/src/frontend/apps/impress/src/features/docs/doc-export/blocks-mapping/dividerDocx.tsx b/src/frontend/apps/impress/src/features/docs/doc-export/blocks-mapping/dividerDocx.tsx index 49df88f12..406002e48 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-export/blocks-mapping/dividerDocx.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-export/blocks-mapping/dividerDocx.tsx @@ -14,7 +14,7 @@ export const blockMappingDividerDocx: DocsExporterDocx['mappings']['blockMapping }, border: { top: { - color: colorsTokens()['greyscale-300'], + color: colorsTokens['greyscale-300'], size: 1, style: 'single', space: 1, diff --git a/src/frontend/apps/impress/src/features/docs/doc-export/blocks-mapping/dividerPDF.tsx b/src/frontend/apps/impress/src/features/docs/doc-export/blocks-mapping/dividerPDF.tsx index 844185d15..ca5e7c185 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-export/blocks-mapping/dividerPDF.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-export/blocks-mapping/dividerPDF.tsx @@ -12,7 +12,7 @@ export const blockMappingDividerPDF: DocsExporterPDF['mappings']['blockMapping'] diff --git a/src/frontend/apps/impress/src/features/docs/doc-header/components/DocHeader.tsx b/src/frontend/apps/impress/src/features/docs/doc-header/components/DocHeader.tsx index 87656a790..8aebcd17a 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-header/components/DocHeader.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-header/components/DocHeader.tsx @@ -22,8 +22,6 @@ interface DocHeaderProps { export const DocHeader = ({ doc }: DocHeaderProps) => { const { colorsTokens, spacingsTokens } = useCunninghamTheme(); const { isDesktop } = useResponsiveStore(); - const spacings = spacingsTokens(); - const colors = colorsTokens(); const { t } = useTranslation(); const docIsPublic = doc.link_reach === LinkReach.PUBLIC; @@ -36,21 +34,21 @@ export const DocHeader = ({ doc }: DocHeaderProps) => { {(docIsPublic || docIsAuth) && ( { $align="center" $maxWidth="100%" > - + diff --git a/src/frontend/apps/impress/src/features/docs/doc-header/components/DocTitle.tsx b/src/frontend/apps/impress/src/features/docs/doc-header/components/DocTitle.tsx index faad51db8..b838ef440 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-header/components/DocTitle.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-header/components/DocTitle.tsx @@ -116,7 +116,7 @@ const DocTitleInput = ({ doc }: DocTitleProps) => { onBlurCapture={(event) => handleTitleSubmit(event.target.textContent || '') } - $color={colorsTokens()['greyscale-1000']} + $color={colorsTokens['greyscale-1000']} $minHeight="40px" $padding={{ right: 'big' }} $css={css` diff --git a/src/frontend/apps/impress/src/features/docs/doc-header/components/DocToolBox.tsx b/src/frontend/apps/impress/src/features/docs/doc-header/components/DocToolBox.tsx index f9b399de6..77a1fe50e 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-header/components/DocToolBox.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-header/components/DocToolBox.tsx @@ -47,9 +47,6 @@ export const DocToolBox = ({ doc }: DocToolBoxProps) => { const { spacingsTokens, colorsTokens } = useCunninghamTheme(); - const spacings = spacingsTokens(); - const colors = colorsTokens(); - const [isModalRemoveOpen, setIsModalRemoveOpen] = useState(false); const [isModalExportOpen, setIsModalExportOpen] = useState(false); const selectHistoryModal = useModal(); @@ -182,7 +179,7 @@ export const DocToolBox = ({ doc }: DocToolBoxProps) => { $direction="row" $align="center" $margin={{ left: 'auto' }} - $gap={spacings['2xs']} + $gap={spacingsTokens['2xs']} > {!isSmallMobile && ( <> @@ -245,12 +242,12 @@ export const DocToolBox = ({ doc }: DocToolBoxProps) => { $css={css` border-radius: 4px; &:hover { - background-color: ${colors['greyscale-100']}; + background-color: ${colorsTokens['greyscale-100']}; } ${isSmallMobile ? css` padding: 10px; - border: 1px solid ${colors['greyscale-300']}; + border: 1px solid ${colorsTokens['greyscale-300']}; ` : ''} `} diff --git a/src/frontend/apps/impress/src/features/docs/doc-header/components/DocVersionHeader.tsx b/src/frontend/apps/impress/src/features/docs/doc-header/components/DocVersionHeader.tsx index c5a2259cf..fd8e91999 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-header/components/DocVersionHeader.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-header/components/DocVersionHeader.tsx @@ -12,7 +12,6 @@ interface DocVersionHeaderProps { export const DocVersionHeader = ({ title }: DocVersionHeaderProps) => { const { spacingsTokens } = useCunninghamTheme(); - const spacings = spacingsTokens(); const { t } = useTranslation(); return ( @@ -20,7 +19,7 @@ export const DocVersionHeader = ({ title }: DocVersionHeaderProps) => { diff --git a/src/frontend/apps/impress/src/features/docs/doc-share/components/DocShareAddMemberList.tsx b/src/frontend/apps/impress/src/features/docs/doc-share/components/DocShareAddMemberList.tsx index 861fc0c76..fdded178d 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-share/components/DocShareAddMemberList.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-share/components/DocShareAddMemberList.tsx @@ -43,8 +43,6 @@ export const DocShareAddMemberList = ({ const { spacingsTokens, colorsTokens } = useCunninghamTheme(); const [invitationRole, setInvitationRole] = useState(Role.EDITOR); const canShare = doc.abilities.accesses_manage; - const spacing = spacingsTokens(); - const color = colorsTokens(); const { mutateAsync: createInvitation } = useCreateDocInvitation(); const { mutateAsync: createDocAccess } = useCreateDocAccess(); @@ -115,12 +113,12 @@ export const DocShareAddMemberList = ({ @@ -129,7 +127,7 @@ export const DocShareAddMemberList = ({ $align="center" $wrap="wrap" $flex={1} - $gap={spacing.xs} + $gap={spacingsTokens.xs} > {selectedUsers.map((user) => ( ))} - + { const { spacingsTokens, colorsTokens, fontSizesTokens } = useCunninghamTheme(); - const spacing = spacingsTokens(); - const color = colorsTokens(); - const fontSize = fontSizesTokens(); + return ( diff --git a/src/frontend/apps/impress/src/features/docs/doc-share/components/DocShareInvitationItem.tsx b/src/frontend/apps/impress/src/features/docs/doc-share/components/DocShareInvitationItem.tsx index 6a186e432..76a04fbd0 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-share/components/DocShareInvitationItem.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-share/components/DocShareInvitationItem.tsx @@ -24,7 +24,6 @@ type Props = { export const DocShareInvitationItem = ({ doc, invitation }: Props) => { const { t } = useTranslation(); const { spacingsTokens } = useCunninghamTheme(); - const spacing = spacingsTokens(); const fakeUser: User = { id: invitation.email, full_name: invitation.email, @@ -91,7 +90,7 @@ export const DocShareInvitationItem = ({ doc, invitation }: Props) => { alwaysShowRight={true} user={fakeUser} right={ - + { const { toast } = useToastProvider(); const { isDesktop } = useResponsiveStore(); const { spacingsTokens } = useCunninghamTheme(); - const spacing = spacingsTokens(); const isNotAllowed = isOtherOwner || !!isLastOwner || !doc.abilities.accesses_manage; @@ -78,7 +77,7 @@ export const DocShareMemberItem = ({ doc, access }: Props) => { alwaysShowRight={true} user={access.user} right={ - + { const { toast } = useToastProvider(); const { isDesktop } = useResponsiveStore(); const { spacingsTokens, colorsTokens } = useCunninghamTheme(); - const spacing = spacingsTokens(); - const colors = colorsTokens(); const canManage = doc.abilities.accesses_manage; const [linkReach, setLinkReach] = useState(doc.link_reach); const [docLinkRole, setDocLinkRole] = useState(doc.link_role); @@ -90,7 +88,7 @@ export const DocVisibility = ({ doc }: DocVisibilityProps) => { @@ -100,7 +98,7 @@ export const DocVisibility = ({ doc }: DocVisibilityProps) => { $direction="row" $align="center" $justify="space-between" - $gap={spacing['xs']} + $gap={spacingsTokens['xs']} $width="100%" $wrap="nowrap" > @@ -108,18 +106,18 @@ export const DocVisibility = ({ doc }: DocVisibilityProps) => { $direction="row" $align={isDesktop ? 'center' : undefined} $padding={{ horizontal: '2xs' }} - $gap={canManage ? spacing['3xs'] : spacing['base']} + $gap={canManage ? spacingsTokens['3xs'] : spacingsTokens['base']} > - + { )} {showLinkRoleOptions && ( - + {linkReach !== LinkReach.RESTRICTED && ( { const hasFullName = user.full_name != null && user.full_name !== ''; const { spacingsTokens, colorsTokens } = useCunninghamTheme(); - const spacings = spacingsTokens(); - const colors = colorsTokens(); return ( diff --git a/src/frontend/apps/impress/src/features/docs/doc-table-content/components/Heading.tsx b/src/frontend/apps/impress/src/features/docs/doc-table-content/components/Heading.tsx index 4865f8929..e069d92c3 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-table-content/components/Heading.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-table-content/components/Heading.tsx @@ -58,7 +58,7 @@ export const Heading = ({ }); }} $radius="4px" - $background={isActive ? `${colorsTokens()['greyscale-100']}` : 'none'} + $background={isActive ? `${colorsTokens['greyscale-100']}` : 'none'} $css="text-align: left;" className="--docs--table-content-heading" > diff --git a/src/frontend/apps/impress/src/features/docs/doc-table-content/components/TableContent.tsx b/src/frontend/apps/impress/src/features/docs/doc-table-content/components/TableContent.tsx index d4e793c03..1d4fe2bc8 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-table-content/components/TableContent.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-table-content/components/TableContent.tsx @@ -13,7 +13,6 @@ export const TableContent = () => { const { headings } = useHeadingStore(); const { editor } = useEditorStore(); const { spacingsTokens } = useCunninghamTheme(); - const spacing = spacingsTokens(); const [headingIdHighlight, setHeadingIdHighlight] = useState(); @@ -158,7 +157,7 @@ export const TableContent = () => { { const { colorsTokens, spacingsTokens } = useCunninghamTheme(); - const spacing = spacingsTokens(); const [isModalVersionOpen, setIsModalVersionOpen] = useState(false); @@ -33,13 +32,13 @@ export const VersionItem = ({ { const { isDesktop } = useResponsiveStore(); const { flexLeft, flexRight } = useResponsiveDocGrid(); const { spacingsTokens } = useCunninghamTheme(); - const spacings = spacingsTokens(); const shareModal = useModal(); const isPublic = doc.link_reach === LinkReach.PUBLIC; const isAuthenticated = doc.link_reach === LinkReach.AUTHENTICATED; @@ -63,7 +62,7 @@ export const DocsGridItem = ({ doc }: DocsGridItemProps) => { data-testid={`docs-grid-name-${doc.id}`} $direction="row" $align="center" - $gap={spacings.xs} + $gap={spacingsTokens.xs} $flex={flexLeft} $padding={{ right: isDesktop ? 'md' : '3xs' }} $maxWidth="100%" @@ -119,7 +118,7 @@ export const DocsGridItem = ({ doc }: DocsGridItemProps) => { )} - + {isDesktop && ( @@ -73,7 +72,7 @@ export const SimpleDocItem = ({ diff --git a/src/frontend/apps/impress/src/features/footer/Footer.tsx b/src/frontend/apps/impress/src/features/footer/Footer.tsx index 28fa35433..92f249e2e 100644 --- a/src/frontend/apps/impress/src/features/footer/Footer.tsx +++ b/src/frontend/apps/impress/src/features/footer/Footer.tsx @@ -18,7 +18,7 @@ const BlueStripe = styled.div` export const Footer = () => { const { t } = useTranslation(); const { themeTokens } = useCunninghamTheme(); - const logo = themeTokens().logo; + const logo = themeTokens.logo; return ( diff --git a/src/frontend/apps/impress/src/features/header/components/Header.tsx b/src/frontend/apps/impress/src/features/header/components/Header.tsx index b808f5ce6..73b15d7e1 100644 --- a/src/frontend/apps/impress/src/features/header/components/Header.tsx +++ b/src/frontend/apps/impress/src/features/header/components/Header.tsx @@ -16,12 +16,9 @@ import { Title } from './Title'; export const Header = () => { const { t } = useTranslation(); - const theme = useCunninghamTheme(); + const { spacingsTokens, colorsTokens } = useCunninghamTheme(); const { isDesktop } = useResponsiveStore(); - const spacings = theme.spacingsTokens(); - const colors = theme.colorsTokens(); - return ( { align-items: center; justify-content: space-between; height: ${HEADER_HEIGHT}px; - padding: 0 ${spacings['base']}; - background-color: ${colors['greyscale-000']}; - border-bottom: 1px solid ${colors['greyscale-200']}; + padding: 0 ${spacingsTokens['base']}; + background-color: ${colorsTokens['greyscale-000']}; + border-bottom: 1px solid ${colorsTokens['greyscale-200']}; `} className="--docs--header" > @@ -45,7 +42,7 @@ export const Header = () => { { {!isDesktop ? ( - + ) : ( - + diff --git a/src/frontend/apps/impress/src/features/header/components/LaGaufre.tsx b/src/frontend/apps/impress/src/features/header/components/LaGaufre.tsx index dce37284c..8f99198d5 100644 --- a/src/frontend/apps/impress/src/features/header/components/LaGaufre.tsx +++ b/src/frontend/apps/impress/src/features/header/components/LaGaufre.tsx @@ -15,7 +15,7 @@ const GaufreStyle = createGlobalStyle` export const LaGaufre = () => { const { componentTokens } = useCunninghamTheme(); - if (!componentTokens()['la-gauffre'].activated) { + if (!componentTokens['la-gauffre'].activated) { return null; } diff --git a/src/frontend/apps/impress/src/features/header/components/Title.tsx b/src/frontend/apps/impress/src/features/header/components/Title.tsx index b1117ed8d..be3b27068 100644 --- a/src/frontend/apps/impress/src/features/header/components/Title.tsx +++ b/src/frontend/apps/impress/src/features/header/components/Title.tsx @@ -6,14 +6,13 @@ import { useCunninghamTheme } from '@/cunningham'; export const Title = () => { const { t } = useTranslation(); - const theme = useCunninghamTheme(); - const spacings = theme.spacingsTokens(); + const { spacingsTokens } = useCunninghamTheme(); return ( DocLogo diff --git a/src/frontend/apps/impress/src/features/home/components/HomeHeader.tsx b/src/frontend/apps/impress/src/features/home/components/HomeHeader.tsx index 2fce7c680..2c285d148 100644 --- a/src/frontend/apps/impress/src/features/home/components/HomeHeader.tsx +++ b/src/frontend/apps/impress/src/features/home/components/HomeHeader.tsx @@ -18,8 +18,7 @@ export const getHeaderHeight = (isSmallMobile: boolean) => export const HomeHeader = () => { const { t } = useTranslation(); const { themeTokens, spacingsTokens } = useCunninghamTheme(); - const spacings = spacingsTokens(); - const logo = themeTokens().logo; + const logo = themeTokens.logo; const { isSmallMobile } = useResponsiveStore(); return ( @@ -57,7 +56,7 @@ export const HomeHeader = () => { )} { const { t } = useTranslation(); const { spacingsTokens } = useCunninghamTheme(); - const spacings = spacingsTokens(); const { isSmallMobile } = useResponsiveStore(); @@ -97,17 +96,17 @@ export const HomeSection = ({ > - + {availableSoon && ( @@ -200,14 +199,14 @@ const SectionTag = ({ availableSoon?: boolean; }) => { const { colorsTokens, spacingsTokens } = useCunninghamTheme(); - const spacings = spacingsTokens(); - const colors = colorsTokens(); return ( { const pathname = usePathname(); const { togglePanel } = useLeftPanelStore(); const { colorsTokens, spacingsTokens } = useCunninghamTheme(); - const spacing = spacingsTokens(); - const colors = colorsTokens(); const searchParams = useSearchParams(); const target = @@ -52,7 +50,7 @@ export const LeftPanelTargetFilters = () => { {defaultQueries.map((query) => { @@ -67,17 +65,17 @@ export const LeftPanelTargetFilters = () => { aria-selected={isActive} $align="center" $justify="flex-start" - $gap={spacing['xs']} - $radius={spacing['3xs']} + $gap={spacingsTokens['xs']} + $radius={spacingsTokens['3xs']} $padding={{ all: '2xs' }} $css={css` cursor: pointer; background-color: ${isActive - ? colors['greyscale-100'] + ? colorsTokens['greyscale-100'] : undefined}; font-weight: ${isActive ? 700 : undefined}; &:hover { - background-color: ${colors['greyscale-100']}; + background-color: ${colorsTokens['greyscale-100']}; } `} > diff --git a/src/frontend/apps/impress/src/features/left-panel/components/LeftPanel.tsx b/src/frontend/apps/impress/src/features/left-panel/components/LeftPanel.tsx index 9c6135091..f877e84e3 100644 --- a/src/frontend/apps/impress/src/features/left-panel/components/LeftPanel.tsx +++ b/src/frontend/apps/impress/src/features/left-panel/components/LeftPanel.tsx @@ -23,12 +23,10 @@ const MobileLeftPanelStyle = createGlobalStyle` export const LeftPanel = () => { const { isDesktop } = useResponsiveStore(); - const theme = useCunninghamTheme(); + const { colorsTokens, spacingsTokens } = useCunninghamTheme(); const { togglePanel, isPanelOpen } = useLeftPanelStore(); const pathname = usePathname(); - const colors = theme.colorsTokens(); - const spacings = theme.spacingsTokens(); useEffect(() => { togglePanel(false); @@ -44,7 +42,7 @@ export const LeftPanel = () => { width: 300px; min-width: 300px; overflow: hidden; - border-right: 1px solid ${colors['greyscale-200']}; + border-right: 1px solid ${colorsTokens['greyscale-200']}; `} className="--docs--left-panel-desktop" > @@ -81,13 +79,17 @@ export const LeftPanel = () => { width: 100%; justify-content: center; align-items: center; - gap: ${spacings['base']}; + gap: ${spacingsTokens['base']}; `} > - + diff --git a/src/frontend/apps/impress/src/features/left-panel/components/LeftPanelDocContent.tsx b/src/frontend/apps/impress/src/features/left-panel/components/LeftPanelDocContent.tsx index dc0b2acc4..505735780 100644 --- a/src/frontend/apps/impress/src/features/left-panel/components/LeftPanelDocContent.tsx +++ b/src/frontend/apps/impress/src/features/left-panel/components/LeftPanelDocContent.tsx @@ -8,7 +8,6 @@ import { SimpleDocItem } from '@/docs/docs-grid'; export const LeftPanelDocContent = () => { const { currentDoc } = useDocStore(); const { spacingsTokens } = useCunninghamTheme(); - const spacing = spacingsTokens(); if (!currentDoc) { return null; } @@ -24,7 +23,7 @@ export const LeftPanelDocContent = () => { { const shareModal = useModal(); const { spacingsTokens } = useCunninghamTheme(); const { isDesktop } = useResponsiveStore(); - const spacing = spacingsTokens(); + return ( { const { t } = useTranslation(); const { spacingsTokens } = useCunninghamTheme(); - const spacing = spacingsTokens(); const docs = useInfiniteDocs({ page: 1, @@ -29,7 +28,7 @@ export const LeftPanelFavorites = () => { diff --git a/src/frontend/apps/impress/src/layouts/MainLayout.tsx b/src/frontend/apps/impress/src/layouts/MainLayout.tsx index ca1854594..c5dde3bd0 100644 --- a/src/frontend/apps/impress/src/layouts/MainLayout.tsx +++ b/src/frontend/apps/impress/src/layouts/MainLayout.tsx @@ -19,7 +19,6 @@ export function MainLayout({ }: PropsWithChildren) { const { isDesktop } = useResponsiveStore(); const { colorsTokens } = useCunninghamTheme(); - const colors = colorsTokens(); const currentBackgroundColor = !isDesktop ? 'white' : backgroundColor; return ( @@ -43,8 +42,8 @@ export function MainLayout({ }} $background={ currentBackgroundColor === 'white' - ? colors['greyscale-000'] - : colors['greyscale-050'] + ? colorsTokens['greyscale-000'] + : colorsTokens['greyscale-050'] } $css={css` overflow-y: auto; diff --git a/src/frontend/apps/impress/src/pages/accessibility/index.tsx b/src/frontend/apps/impress/src/pages/accessibility/index.tsx index d89f2ee18..cec42d669 100644 --- a/src/frontend/apps/impress/src/pages/accessibility/index.tsx +++ b/src/frontend/apps/impress/src/pages/accessibility/index.tsx @@ -14,7 +14,7 @@ const Page: NextPageWithLayout = () => { diff --git a/src/frontend/apps/impress/src/pages/legal-notice/index.tsx b/src/frontend/apps/impress/src/pages/legal-notice/index.tsx index 0abbf9394..ed762ccf4 100644 --- a/src/frontend/apps/impress/src/pages/legal-notice/index.tsx +++ b/src/frontend/apps/impress/src/pages/legal-notice/index.tsx @@ -14,7 +14,7 @@ const Page: NextPageWithLayout = () => { diff --git a/src/frontend/apps/impress/src/pages/personal-data-cookies/index.tsx b/src/frontend/apps/impress/src/pages/personal-data-cookies/index.tsx index 1a064006b..6e4800c6d 100644 --- a/src/frontend/apps/impress/src/pages/personal-data-cookies/index.tsx +++ b/src/frontend/apps/impress/src/pages/personal-data-cookies/index.tsx @@ -14,7 +14,7 @@ const Page: NextPageWithLayout = () => { From 3bf33d202a8870d57dc631b6565a22d4af4df16b Mon Sep 17 00:00:00 2001 From: Anthony LC Date: Tue, 22 Apr 2025 11:23:55 +0200 Subject: [PATCH 06/26] =?UTF-8?q?=E2=9A=A1=EF=B8=8F(frontend)=20reduce=20u?= =?UTF-8?q?nblocking=20time=20for=20config?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We will serve the config from the cache if available in waiting for the config to be loaded. It will remove the loading time for the config except when the config is not available in the cache. --- CHANGELOG.md | 3 ++ .../impress/src/core/config/api/useConfig.tsx | 31 +++++++++++++++++-- .../language/hooks/useLanguageSynchronizer.ts | 2 +- 3 files changed, 32 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 40e36bf12..a78197160 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,9 @@ and this project adheres to - 🚸(backend) make document search on title accent-insensitive #874 - 🚩 add homepage feature flag #861 +## Changed + +⚡️(frontend) reduce unblocking time for config #867 ## [3.1.0] - 2025-04-07 diff --git a/src/frontend/apps/impress/src/core/config/api/useConfig.tsx b/src/frontend/apps/impress/src/core/config/api/useConfig.tsx index aa3648770..03c43feae 100644 --- a/src/frontend/apps/impress/src/core/config/api/useConfig.tsx +++ b/src/frontend/apps/impress/src/core/config/api/useConfig.tsx @@ -19,6 +19,21 @@ interface ConfigResponse { SENTRY_DSN?: string; } +const LOCAL_STORAGE_KEY = 'docs_config'; + +function getCachedTranslation() { + try { + const jsonString = localStorage.getItem(LOCAL_STORAGE_KEY); + return jsonString ? (JSON.parse(jsonString) as ConfigResponse) : undefined; + } catch { + return undefined; + } +} + +function setCachedTranslation(translations: ConfigResponse) { + localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(translations)); +} + export const getConfig = async (): Promise => { const response = await fetchAPI(`config/`); @@ -26,15 +41,25 @@ export const getConfig = async (): Promise => { throw new APIError('Failed to get the doc', await errorCauses(response)); } - return response.json() as Promise; + const config = response.json() as Promise; + setCachedTranslation(await config); + + return config; }; export const KEY_CONFIG = 'config'; export function useConfig() { - return useQuery({ + const cachedData = getCachedTranslation(); + const oneHour = 1000 * 60 * 60; + + const response = useQuery({ queryKey: [KEY_CONFIG], queryFn: () => getConfig(), - staleTime: Infinity, + initialData: cachedData, + staleTime: oneHour, + initialDataUpdatedAt: Date.now() - oneHour, // Force initial data to be considered stale }); + + return response; } diff --git a/src/frontend/apps/impress/src/features/language/hooks/useLanguageSynchronizer.ts b/src/frontend/apps/impress/src/features/language/hooks/useLanguageSynchronizer.ts index 536e2e72d..e6bb23b99 100644 --- a/src/frontend/apps/impress/src/features/language/hooks/useLanguageSynchronizer.ts +++ b/src/frontend/apps/impress/src/features/language/hooks/useLanguageSynchronizer.ts @@ -16,7 +16,7 @@ export const useLanguageSynchronizer = () => { const availableBackendLanguages = useMemo(() => { return conf?.LANGUAGES.map(([locale]) => locale); - }, [conf]); + }, [conf?.LANGUAGES]); const synchronizeLanguage = useCallback( async (direction?: 'toBackend' | 'toFrontend') => { From 4307b4f4336aba463186fd14e51e72a6452336ab Mon Sep 17 00:00:00 2001 From: Anthony LC Date: Wed, 12 Feb 2025 10:13:41 +0100 Subject: [PATCH 07/26] =?UTF-8?q?=F0=9F=90=9B(backend)=20race=20condition?= =?UTF-8?q?=20create=20doc?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When 2 docs are created almost at the same time, the second one will fail because the first one. We get a unicity error on the path key already used ("impress_document_path_key"). To fix this issue, we will lock the table the time to create the document, the next query will wait for the lock to be released. --- CHANGELOG.md | 4 ++ src/backend/core/api/viewsets.py | 26 ++++++++++++- .../test_api_documents_children_create.py | 39 +++++++++++++++++++ .../documents/test_api_documents_create.py | 31 +++++++++++++++ .../test_api_documents_create_for_owner.py | 31 +++++++++++++++ 5 files changed, 129 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a78197160..7ac31a5ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -145,6 +145,10 @@ and this project adheres to - 🐛(email) invitation emails in receivers language +## Fixed + +- 🐛(backend) race condition create doc #633 + ## [2.2.0] - 2025-02-10 ## Added diff --git a/src/backend/core/api/viewsets.py b/src/backend/core/api/viewsets.py index 685cfb836..544fdb2a9 100644 --- a/src/backend/core/api/viewsets.py +++ b/src/backend/core/api/viewsets.py @@ -11,8 +11,8 @@ from django.contrib.postgres.search import TrigramSimilarity from django.core.exceptions import ValidationError from django.core.files.storage import default_storage +from django.db import connection, transaction from django.db import models as db -from django.db import transaction from django.db.models.expressions import RawSQL from django.db.models.functions import Left, Length from django.http import Http404, StreamingHttpResponse @@ -607,6 +607,14 @@ def retrieve(self, request, *args, **kwargs): @transaction.atomic def perform_create(self, serializer): """Set the current user as creator and owner of the newly created object.""" + + # locks the table to ensure safe concurrent access + with connection.cursor() as cursor: + cursor.execute( + f'LOCK TABLE "{models.Document._meta.db_table}" ' # noqa: SLF001 + "IN SHARE ROW EXCLUSIVE MODE;" + ) + obj = models.Document.add_root( creator=self.request.user, **serializer.validated_data, @@ -666,10 +674,19 @@ def trashbin(self, request, *args, **kwargs): permission_classes=[], url_path="create-for-owner", ) + @transaction.atomic def create_for_owner(self, request): """ Create a document on behalf of a specified owner (pre-existing user or invited). """ + + # locks the table to ensure safe concurrent access + with connection.cursor() as cursor: + cursor.execute( + f'LOCK TABLE "{models.Document._meta.db_table}" ' # noqa: SLF001 + "IN SHARE ROW EXCLUSIVE MODE;" + ) + # Deserialize and validate the data serializer = serializers.ServerCreateDocumentSerializer(data=request.data) if not serializer.is_valid(): @@ -775,7 +792,12 @@ def children(self, request, *args, **kwargs): serializer.is_valid(raise_exception=True) with transaction.atomic(): - child_document = document.add_child( + # "select_for_update" locks the table to ensure safe concurrent access + locked_parent = models.Document.objects.select_for_update().get( + pk=document.pk + ) + + child_document = locked_parent.add_child( creator=request.user, **serializer.validated_data, ) diff --git a/src/backend/core/tests/documents/test_api_documents_children_create.py b/src/backend/core/tests/documents/test_api_documents_children_create.py index 3a3c3ff9e..5aea1b605 100644 --- a/src/backend/core/tests/documents/test_api_documents_children_create.py +++ b/src/backend/core/tests/documents/test_api_documents_children_create.py @@ -2,6 +2,7 @@ Tests for Documents API endpoint in impress's core app: children create """ +from concurrent.futures import ThreadPoolExecutor from uuid import uuid4 import pytest @@ -249,3 +250,41 @@ def test_api_documents_children_create_force_id_existing(): assert response.json() == { "id": ["A document with this ID already exists. You cannot override it."] } + + +@pytest.mark.django_db(transaction=True) +def test_api_documents_create_document_children_race_condition(): + """ + It should be possible to create several documents at the same time + without causing any race conditions or data integrity issues. + """ + + user = factories.UserFactory() + + client = APIClient() + client.force_login(user) + + document = factories.DocumentFactory() + + factories.UserDocumentAccessFactory(user=user, document=document, role="owner") + + def create_document(): + return client.post( + f"/api/v1.0/documents/{document.id}/children/", + { + "title": "my child", + }, + ) + + with ThreadPoolExecutor(max_workers=2) as executor: + future1 = executor.submit(create_document) + future2 = executor.submit(create_document) + + response1 = future1.result() + response2 = future2.result() + + assert response1.status_code == 201 + assert response2.status_code == 201 + + document.refresh_from_db() + assert document.numchild == 2 diff --git a/src/backend/core/tests/documents/test_api_documents_create.py b/src/backend/core/tests/documents/test_api_documents_create.py index 151724e0f..2b6c404d1 100644 --- a/src/backend/core/tests/documents/test_api_documents_create.py +++ b/src/backend/core/tests/documents/test_api_documents_create.py @@ -2,6 +2,7 @@ Tests for Documents API endpoint in impress's core app: create """ +from concurrent.futures import ThreadPoolExecutor from uuid import uuid4 import pytest @@ -51,6 +52,36 @@ def test_api_documents_create_authenticated_success(): assert document.accesses.filter(role="owner", user=user).exists() +@pytest.mark.django_db(transaction=True) +def test_api_documents_create_document_race_condition(): + """ + It should be possible to create several documents at the same time + without causing any race conditions or data integrity issues. + """ + + def create_document(title): + user = factories.UserFactory() + client = APIClient() + client.force_login(user) + return client.post( + "/api/v1.0/documents/", + { + "title": title, + }, + format="json", + ) + + with ThreadPoolExecutor(max_workers=2) as executor: + future1 = executor.submit(create_document, "my document 1") + future2 = executor.submit(create_document, "my document 2") + + response1 = future1.result() + response2 = future2.result() + + assert response1.status_code == 201 + assert response2.status_code == 201 + + def test_api_documents_create_authenticated_title_null(): """It should be possible to create several documents with a null title.""" user = factories.UserFactory() diff --git a/src/backend/core/tests/documents/test_api_documents_create_for_owner.py b/src/backend/core/tests/documents/test_api_documents_create_for_owner.py index 084aaec10..c2e878d16 100644 --- a/src/backend/core/tests/documents/test_api_documents_create_for_owner.py +++ b/src/backend/core/tests/documents/test_api_documents_create_for_owner.py @@ -4,6 +4,7 @@ # pylint: disable=W0621 +from concurrent.futures import ThreadPoolExecutor from unittest.mock import patch from django.core import mail @@ -425,6 +426,36 @@ def test_api_documents_create_for_owner_new_user_no_sub_no_fallback_allow_duplic assert document.creator == user +@pytest.mark.django_db(transaction=True) +def test_api_documents_create_document_race_condition(): + """ + It should be possible to create several documents at the same time + without causing any race conditions or data integrity issues. + """ + + def create_document(title): + user = factories.UserFactory() + client = APIClient() + client.force_login(user) + return client.post( + "/api/v1.0/documents/", + { + "title": title, + }, + format="json", + ) + + with ThreadPoolExecutor(max_workers=2) as executor: + future1 = executor.submit(create_document, "my document 1") + future2 = executor.submit(create_document, "my document 2") + + response1 = future1.result() + response2 = future2.result() + + assert response1.status_code == 201 + assert response2.status_code == 201 + + @patch.object(ServerCreateDocumentSerializer, "_send_email_notification") @override_settings(SERVER_TO_SERVER_API_TOKENS=["DummyToken"], LANGUAGE_CODE="de-de") def test_api_documents_create_for_owner_with_default_language( From cdafe6fd33ddf31ae0a8bfcc1538da19fb00fec7 Mon Sep 17 00:00:00 2001 From: virgile-dev Date: Tue, 22 Apr 2025 15:57:45 +0200 Subject: [PATCH 08/26] =?UTF-8?q?=F0=9F=93=9D(readme)=20update=20xl=20pack?= =?UTF-8?q?ages=20info=20(#885)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Info message so people fulfill their licencing obligations Signed-off-by: virgile-deville --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index e09298284..473013117 100644 --- a/README.md +++ b/README.md @@ -24,8 +24,6 @@ Welcome to Docs! The open source document editor where your notes can become kno ## Why use Docs ❓ -⚠️ **Note that Docs provides docs/pdf exporters by loading [two BlockNote packages](https://github.com/suitenumerique/docs/blob/main/src/frontend/apps/impress/package.json#L22C7-L23C53), which we use under the AGPL-3.0 licence. Until we comply with the terms of this license, we recommend that you don't run Docs as a commercial product, unless you are willing to sponsor [BlockNote](https://github.com/TypeCellOS/BlockNote).** - Docs is a collaborative text editor designed to address common challenges in knowledge building and sharing. ### Write @@ -39,11 +37,13 @@ Docs is a collaborative text editor designed to address common challenges in kno * 🤝 Collaborate with your team in real time * 🔒 Granular access control to ensure your information is secure and only shared with the right people * 📑 Professional document exports in multiple formats (.odt, .doc, .pdf) with customizable templates -* 📚 Built-in wiki functionality to turn your team's collaborative work into organized knowledge `ETA 02/2025` +* 📚 Built-in wiki functionality to turn your team's collaborative work into organized knowledge `ETA 05/2025` ### Self-host * 🚀 Easy to install, scalable and secure alternative to Notion, Outline or Confluence +⚠️ For the PDF and Docx export Docs relies on XL packages from BlockNote licenced in AGPL-3.0. Please make sure you fulfill your obligations regarding BlockNote licensing (see https://github.com/TypeCellOS/BlockNote/blob/main/packages/xl-pdf-exporter/LICENSE and https://www.blocknotejs.org/about#partner-with-us). + ## Getting started 🔧 ### Test it @@ -118,6 +118,7 @@ $ make run-backend ``` **Adding content** + You can create a basic demo site by running: ```shellscript From 5268699d508e2b77ed0c43c70ba0f67d00b6dd1a Mon Sep 17 00:00:00 2001 From: Anthony LC Date: Wed, 23 Apr 2025 11:43:50 +0200 Subject: [PATCH 09/26] =?UTF-8?q?=E2=AC=86=EF=B8=8F(dependencies)=20update?= =?UTF-8?q?=20js=20dependencies?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/frontend/apps/e2e/.eslintrc.js | 6 +- .../apps/e2e/__tests__/app-impress/common.ts | 1 + .../e2e/__tests__/app-impress/config.spec.ts | 7 +- src/frontend/apps/e2e/package.json | 4 +- src/frontend/apps/impress/package.json | 40 +- src/frontend/package.json | 18 +- .../eslint-config-impress/package.json | 11 +- src/frontend/packages/i18n/package.json | 2 +- src/frontend/servers/y-provider/.eslintrc.cjs | 3 + src/frontend/servers/y-provider/package.json | 22 +- src/frontend/yarn.lock | 3203 +++++++++++++---- 11 files changed, 2521 insertions(+), 796 deletions(-) diff --git a/src/frontend/apps/e2e/.eslintrc.js b/src/frontend/apps/e2e/.eslintrc.js index 57ee5e7a8..46f10c31d 100644 --- a/src/frontend/apps/e2e/.eslintrc.js +++ b/src/frontend/apps/e2e/.eslintrc.js @@ -1,9 +1,9 @@ module.exports = { root: true, - extends: ["impress/playwright"], + extends: ['impress/playwright'], parserOptions: { tsconfigRootDir: __dirname, - project: ["./tsconfig.json"], + project: ['./tsconfig.json'], }, - ignorePatterns: ["node_modules"], + ignorePatterns: ['node_modules'], }; diff --git a/src/frontend/apps/e2e/__tests__/app-impress/common.ts b/src/frontend/apps/e2e/__tests__/app-impress/common.ts index 11ae09024..874be8cd7 100644 --- a/src/frontend/apps/e2e/__tests__/app-impress/common.ts +++ b/src/frontend/apps/e2e/__tests__/app-impress/common.ts @@ -78,6 +78,7 @@ export const createDoc = async ( }); const input = page.getByLabel('doc title input'); + await expect(input).toBeVisible(); await expect(input).toHaveText(''); await input.click(); diff --git a/src/frontend/apps/e2e/__tests__/app-impress/config.spec.ts b/src/frontend/apps/e2e/__tests__/app-impress/config.spec.ts index 90557aad2..6a47bed42 100644 --- a/src/frontend/apps/e2e/__tests__/app-impress/config.spec.ts +++ b/src/frontend/apps/e2e/__tests__/app-impress/config.spec.ts @@ -79,11 +79,14 @@ test.describe('Config', () => { test('it checks that collaboration server is configured from config endpoint', async ({ page, - browserName, }) => { await page.goto('/'); - void createDoc(page, 'doc-collaboration', browserName, 1); + void page + .getByRole('button', { + name: 'New doc', + }) + .click(); const webSocket = await page.waitForEvent('websocket', (webSocket) => { return webSocket.url().includes('ws://localhost:4444/collaboration/ws/'); diff --git a/src/frontend/apps/e2e/package.json b/src/frontend/apps/e2e/package.json index 4e43b620d..ba3372690 100644 --- a/src/frontend/apps/e2e/package.json +++ b/src/frontend/apps/e2e/package.json @@ -12,9 +12,9 @@ "test:ui::chromium": "yarn test:ui --project=chromium" }, "devDependencies": { - "@playwright/test": "1.50.1", + "@playwright/test": "1.52.0", "@types/node": "*", - "@types/pdf-parse": "1.1.4", + "@types/pdf-parse": "1.1.5", "eslint-config-impress": "*", "typescript": "*" }, diff --git a/src/frontend/apps/impress/package.json b/src/frontend/apps/impress/package.json index 6fac8b44b..45fbe9e68 100644 --- a/src/frontend/apps/impress/package.json +++ b/src/frontend/apps/impress/package.json @@ -22,32 +22,32 @@ "@blocknote/xl-docx-exporter": "0.23.2-hotfix.0", "@blocknote/xl-pdf-exporter": "0.23.2-hotfix.0", "@fontsource/material-icons": "5.2.5", - "@gouvfr-lasuite/integration": "1.0.2", - "@gouvfr-lasuite/ui-kit": "0.1.3", + "@gouvfr-lasuite/integration": "1.0.3", + "@gouvfr-lasuite/ui-kit": "0.4.0", "@hocuspocus/provider": "2.15.2", "@openfun/cunningham-react": "3.0.0", "@react-pdf/renderer": "4.1.6", - "@sentry/nextjs": "9.3.0", - "@tanstack/react-query": "5.67.1", + "@sentry/nextjs": "9.13.0", + "@tanstack/react-query": "5.74.4", "canvg": "4.0.3", "clsx": "2.1.1", - "cmdk": "1.0.4", + "cmdk": "1.1.1", "crisp-sdk-web": "1.0.25", "docx": "9.1.1", - "i18next": "24.2.2", - "i18next-browser-languagedetector": "8.0.4", + "i18next": "25.0.1", + "i18next-browser-languagedetector": "8.0.5", "idb": "8.0.2", "lodash": "4.17.21", - "luxon": "3.5.0", - "next": "15.2.4", - "posthog-js": "1.227.0", + "luxon": "3.6.1", + "next": "15.3.1", + "posthog-js": "1.236.5", "react": "*", - "react-aria-components": "1.6.0", + "react-aria-components": "1.8.0", "react-dom": "*", "react-i18next": "15.4.1", - "react-intersection-observer": "9.15.1", + "react-intersection-observer": "9.16.0", "react-select": "5.10.1", - "styled-components": "6.1.15", + "styled-components": "6.1.17", "use-debounce": "10.0.4", "y-protocols": "1.0.6", "yjs": "*", @@ -55,30 +55,30 @@ }, "devDependencies": { "@svgr/webpack": "8.1.0", - "@tanstack/react-query-devtools": "5.67.1", + "@tanstack/react-query-devtools": "5.74.4", "@testing-library/dom": "10.4.0", "@testing-library/jest-dom": "6.6.3", - "@testing-library/react": "16.2.0", + "@testing-library/react": "16.3.0", "@testing-library/user-event": "14.6.1", "@types/jest": "29.5.14", "@types/lodash": "4.17.16", - "@types/luxon": "3.4.2", + "@types/luxon": "3.6.2", "@types/node": "*", "@types/react": "*", "@types/react-dom": "*", "cross-env": "7.0.3", - "dotenv": "16.4.7", + "dotenv": "16.5.0", "eslint-config-impress": "*", "fetch-mock": "9.11.0", "jest": "29.7.0", "jest-environment-jsdom": "29.7.0", "node-fetch": "2.7.0", "prettier": "3.5.3", - "stylelint": "16.15.0", - "stylelint-config-standard": "37.0.0", + "stylelint": "16.18.0", + "stylelint-config-standard": "38.0.0", "stylelint-prettier": "5.0.3", "typescript": "*", - "webpack": "5.98.0", + "webpack": "5.99.6", "workbox-webpack-plugin": "7.1.0" } } diff --git a/src/frontend/package.json b/src/frontend/package.json index 8621c7b9f..9731a4426 100644 --- a/src/frontend/package.json +++ b/src/frontend/package.json @@ -28,15 +28,15 @@ "server:test": "yarn COLLABORATION_SERVER run test" }, "resolutions": { - "@types/node": "22.13.9", - "@types/react": "19.0.0", - "@types/react-dom": "19.0.0", - "@typescript-eslint/eslint-plugin": "8.26.0", - "@typescript-eslint/parser": "8.26.0", + "@types/node": "22.14.1", + "@types/react": "19.1.2", + "@types/react-dom": "19.1.2", + "@typescript-eslint/eslint-plugin": "8.31.0", + "@typescript-eslint/parser": "8.31.0", "eslint": "8.57.0", - "react": "19.0.0", - "react-dom": "19.0.0", - "typescript": "5.8.2", - "yjs": "13.6.23" + "react": "19.1.0", + "react-dom": "19.1.0", + "typescript": "5.8.3", + "yjs": "13.6.26" } } diff --git a/src/frontend/packages/eslint-config-impress/package.json b/src/frontend/packages/eslint-config-impress/package.json index ac95f7159..45237bd04 100644 --- a/src/frontend/packages/eslint-config-impress/package.json +++ b/src/frontend/packages/eslint-config-impress/package.json @@ -6,19 +6,18 @@ "lint": "eslint --ext .js ." }, "dependencies": { - "@next/eslint-plugin-next": "15.2.1", - "@tanstack/eslint-plugin-query": "5.66.1", + "@next/eslint-plugin-next": "15.3.1", + "@tanstack/eslint-plugin-query": "5.73.3", "@typescript-eslint/eslint-plugin": "*", "@typescript-eslint/parser": "*", "eslint": "*", - "eslint-config-next": "15.2.1", - "eslint-config-prettier": "10.0.2", + "eslint-config-next": "15.3.1", + "eslint-config-prettier": "10.1.2", "eslint-plugin-import": "2.31.0", "eslint-plugin-jest": "28.11.0", "eslint-plugin-jsx-a11y": "6.10.2", "eslint-plugin-playwright": "2.2.0", - "eslint-plugin-prettier": "5.2.3", - "eslint-plugin-react": "7.37.4", + "eslint-plugin-prettier": "5.2.6", "eslint-plugin-testing-library": "7.1.1", "prettier": "3.5.3" } diff --git a/src/frontend/packages/i18n/package.json b/src/frontend/packages/i18n/package.json index 917acff8c..d272556d8 100644 --- a/src/frontend/packages/i18n/package.json +++ b/src/frontend/packages/i18n/package.json @@ -18,7 +18,7 @@ "eslint-plugin-import": "2.31.0", "i18next-parser": "9.3.0", "jest": "29.7.0", - "ts-jest": "29.2.6", + "ts-jest": "29.3.2", "typescript": "*", "yargs": "17.7.2" } diff --git a/src/frontend/servers/y-provider/.eslintrc.cjs b/src/frontend/servers/y-provider/.eslintrc.cjs index 33a3b049f..313916138 100644 --- a/src/frontend/servers/y-provider/.eslintrc.cjs +++ b/src/frontend/servers/y-provider/.eslintrc.cjs @@ -10,5 +10,8 @@ module.exports = { rootDir: __dirname, }, }, + rules: { + '@next/next/no-html-link-for-pages': 'off', + }, ignorePatterns: ['node_modules', '.eslintrc.js'], }; diff --git a/src/frontend/servers/y-provider/package.json b/src/frontend/servers/y-provider/package.json index e5acea45d..1218afa5f 100644 --- a/src/frontend/servers/y-provider/package.json +++ b/src/frontend/servers/y-provider/package.json @@ -16,13 +16,13 @@ "node": ">=18" }, "dependencies": { - "@blocknote/server-util": "0.23.2", + "@blocknote/server-util": "0.23.2-hotfix.0", "@hocuspocus/server": "2.15.2", - "@sentry/node": "9.3.0", - "@sentry/profiling-node": "9.3.0", - "axios": "1.8.2", + "@sentry/node": "9.13.0", + "@sentry/profiling-node": "9.13.0", + "axios": "1.8.4", "cors": "2.8.5", - "express": "4.21.2", + "express": "5.1.0", "express-ws": "5.0.2", "uuid": "11.1.0", "y-protocols": "1.0.6", @@ -31,20 +31,20 @@ "devDependencies": { "@hocuspocus/provider": "2.15.2", "@types/cors": "2.8.17", - "@types/express": "5.0.0", + "@types/express": "5.0.1", "@types/express-ws": "3.0.5", "@types/jest": "29.5.14", "@types/node": "*", - "@types/supertest": "6.0.2", - "@types/ws": "8.5.14", + "@types/supertest": "6.0.3", + "@types/ws": "8.18.1", "cross-env": "7.0.3", "eslint-config-impress": "*", "jest": "29.7.0", "nodemon": "3.1.9", - "supertest": "7.0.0", - "ts-jest": "29.2.6", + "supertest": "7.1.0", + "ts-jest": "29.3.2", "ts-node": "10.9.2", - "tsc-alias": "1.8.11", + "tsc-alias": "1.8.15", "typescript": "*", "ws": "8.18.1" } diff --git a/src/frontend/yarn.lock b/src/frontend/yarn.lock index 6d129b3f8..ffa7a6134 100644 --- a/src/frontend/yarn.lock +++ b/src/frontend/yarn.lock @@ -969,6 +969,13 @@ dependencies: regenerator-runtime "^0.14.0" +"@babel/runtime@^7.26.10": + version "7.27.0" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.27.0.tgz#fbee7cf97c709518ecc1f590984481d5460d4762" + integrity sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw== + dependencies: + regenerator-runtime "^0.14.0" + "@babel/runtime@^7.9.2": version "7.26.10" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.26.10.tgz#a07b4d8fa27af131a633d7b3524db803eb4764c2" @@ -1060,55 +1067,6 @@ y-protocols "^1.0.6" yjs "^13.6.15" -"@blocknote/core@^0.23.2", "@blocknote/core@^0.23.6": - version "0.23.6" - resolved "https://registry.yarnpkg.com/@blocknote/core/-/core-0.23.6.tgz#3cffea4549b77a6d6a9406ad9bb3e56e8c76d3ab" - integrity sha512-X5bxzFCgAG42lT2NhKJQdEQp0DEWaY4DJdGo76d2o3xef+bNGCLRe4i2XkGty2B9B3uYElgHqz6GYGeF0Hfn5g== - dependencies: - "@emoji-mart/data" "^1.2.1" - "@tiptap/core" "^2.7.1" - "@tiptap/extension-bold" "^2.7.1" - "@tiptap/extension-code" "^2.7.1" - "@tiptap/extension-collaboration" "^2.7.1" - "@tiptap/extension-collaboration-cursor" "^2.7.1" - "@tiptap/extension-gapcursor" "^2.7.1" - "@tiptap/extension-hard-break" "^2.7.1" - "@tiptap/extension-history" "^2.7.1" - "@tiptap/extension-horizontal-rule" "^2.7.1" - "@tiptap/extension-italic" "^2.7.1" - "@tiptap/extension-link" "^2.7.1" - "@tiptap/extension-paragraph" "^2.7.1" - "@tiptap/extension-strike" "^2.7.1" - "@tiptap/extension-table-cell" "^2.7.1" - "@tiptap/extension-table-header" "^2.7.1" - "@tiptap/extension-table-row" "^2.7.1" - "@tiptap/extension-text" "^2.7.1" - "@tiptap/extension-underline" "^2.7.1" - "@tiptap/pm" "^2.7.1" - emoji-mart "^5.6.0" - hast-util-from-dom "^4.2.0" - prosemirror-dropcursor "^1.8.1" - prosemirror-highlight "^0.9.0" - prosemirror-model "^1.23.0" - prosemirror-state "^1.4.3" - prosemirror-tables "^1.6.1" - prosemirror-transform "^1.10.2" - prosemirror-view "^1.38.0" - rehype-format "^5.0.0" - rehype-parse "^8.0.4" - rehype-remark "^9.1.2" - rehype-stringify "^9.0.3" - remark-gfm "^3.0.1" - remark-parse "^10.0.1" - remark-rehype "^10.1.0" - remark-stringify "^10.0.2" - shiki "^1.22.0" - unified "^10.1.2" - uuid "^8.3.2" - y-prosemirror "1.2.13" - y-protocols "^1.0.6" - yjs "^13.6.15" - "@blocknote/mantine@0.23.2-hotfix.0": version "0.23.2-hotfix.0" resolved "https://registry.yarnpkg.com/@blocknote/mantine/-/mantine-0.23.2-hotfix.0.tgz#695a6b44b92fab91ee0dcaa93c4224bc573374f4" @@ -1133,29 +1091,17 @@ lodash.merge "^4.6.2" react-icons "^5.2.1" -"@blocknote/react@^0.23.2": - version "0.23.6" - resolved "https://registry.yarnpkg.com/@blocknote/react/-/react-0.23.6.tgz#359272d4a7116822254c32710ec889f6ae503a72" - integrity sha512-HHlutNtgDNuSLYPyDjbyAGSimSY+CTG3Uvga5J8E4aky2XvxDQhrp1w2iPdOX5IAcLbpuqTOpDbdRj5pfTvveA== - dependencies: - "@blocknote/core" "^0.23.6" - "@floating-ui/react" "^0.26.4" - "@tiptap/core" "^2.7.1" - "@tiptap/react" "^2.7.1" - lodash.merge "^4.6.2" - react-icons "^5.2.1" - -"@blocknote/server-util@0.23.2": - version "0.23.2" - resolved "https://registry.yarnpkg.com/@blocknote/server-util/-/server-util-0.23.2.tgz#aa2123b71027b8db1f98e7e3073c87361902fd19" - integrity sha512-5QFwqtS1+Lkhtj/tdF4lH7WmfpV1WgeCo2qI6rVp/5wZkW74ph9/9cY4pzD92e1ztGv9gzfEVYAEK2/e+qbfOw== +"@blocknote/server-util@0.23.2-hotfix.0": + version "0.23.2-hotfix.0" + resolved "https://registry.yarnpkg.com/@blocknote/server-util/-/server-util-0.23.2-hotfix.0.tgz#de81adda978cda5cb799766121511d93b71d7984" + integrity sha512-Ymya3lxiGkPupcwDWq5/QEuAfHl0KdaPChbN0u7ejmdX6pSGP6m7wnDa2mVbrEW937hVhovijTS/hKR3HVMocQ== dependencies: - "@blocknote/core" "^0.23.2" - "@blocknote/react" "^0.23.2" + "@blocknote/core" "^0.23.2-hotfix.0" + "@blocknote/react" "^0.23.2-hotfix.0" "@tiptap/core" "^2.7.1" "@tiptap/pm" "^2.7.1" jsdom "^25.0.1" - y-prosemirror "1.2.13" + y-prosemirror "1.2.17" y-protocols "^1.0.6" yjs "^13.6.15" @@ -1276,6 +1222,13 @@ dependencies: tslib "^2.4.0" +"@emnapi/runtime@^1.4.0": + version "1.4.3" + resolved "https://registry.yarnpkg.com/@emnapi/runtime/-/runtime-1.4.3.tgz#c0564665c80dc81c448adac23f9dfbed6c838f7d" + integrity sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ== + dependencies: + tslib "^2.4.0" + "@emoji-mart/data@^1.2.1": version "1.2.1" resolved "https://registry.yarnpkg.com/@emoji-mart/data/-/data-1.2.1.tgz#0ad70c662e3bc603e23e7d98413bd1e64c4fcb6c" @@ -1640,14 +1593,20 @@ resolved "https://registry.yarnpkg.com/@gouvfr-lasuite/integration/-/integration-1.0.2.tgz#ed0000f4b738c5a19bb60f5b80a9a2f5d9414234" integrity sha512-npOotZQSyu6SffHiPP+jQVOkJ3qW2KE2cANhEK92sNLX9uZqQaCqljO5GhzsBmh0lB76fiXnrr9i8SIpnDUSZg== -"@gouvfr-lasuite/ui-kit@0.1.3": - version "0.1.3" - resolved "https://registry.yarnpkg.com/@gouvfr-lasuite/ui-kit/-/ui-kit-0.1.3.tgz#1be7f1bdf12e7428e630d6ce11fbc77c4c9b9b21" - integrity sha512-ba3ZrAIhX84cofa2IwiWhgE0wzz85+ySbOTvB1lP9jeWYvWn/N5HsnxphA9bEMIrx1Yi91upzmYLvjHRoDq1Ww== +"@gouvfr-lasuite/integration@1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@gouvfr-lasuite/integration/-/integration-1.0.3.tgz#7aca824ba61d343a7905dc90c8a8bbdbce8f9a09" + integrity sha512-OgP28CqlPi35wQPul1Dr52SngACXAk8buLGqHYXDp23fbTOJThqarrZE/pgJHoc9Ndwiu7ngwBSO4rZ7OPyMpA== + +"@gouvfr-lasuite/ui-kit@0.4.0": + version "0.4.0" + resolved "https://registry.yarnpkg.com/@gouvfr-lasuite/ui-kit/-/ui-kit-0.4.0.tgz#513489a3944e66358f5ddc029ba98b4bd4db05de" + integrity sha512-no7q6v8XClB87BCb17NkiU5BJOvoJl1SAQ9MsBmBYpqyakzlMSFdEogiwCSoy0Dfjw4GQL7C6uIyJn2xK725PA== dependencies: "@dnd-kit/core" "6.3.1" "@dnd-kit/modifiers" "9.0.0" "@dnd-kit/sortable" "10.0.0" + "@gouvfr-lasuite/integration" "1.0.2" "@openfun/cunningham-react" "3.0.0" "@types/node" "22.10.7" clsx "2.1.1" @@ -1721,6 +1680,13 @@ optionalDependencies: "@img/sharp-libvips-darwin-arm64" "1.0.4" +"@img/sharp-darwin-arm64@0.34.1": + version "0.34.1" + resolved "https://registry.yarnpkg.com/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.1.tgz#e79a4756bea9a06a7aadb4391ee53cb154a4968c" + integrity sha512-pn44xgBtgpEbZsu+lWf2KNb6OAf70X68k+yk69Ic2Xz11zHR/w24/U49XT7AeRwJ0Px+mhALhU5LPci1Aymk7A== + optionalDependencies: + "@img/sharp-libvips-darwin-arm64" "1.1.0" + "@img/sharp-darwin-x64@0.33.5": version "0.33.5" resolved "https://registry.yarnpkg.com/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.5.tgz#e03d3451cd9e664faa72948cc70a403ea4063d61" @@ -1728,46 +1694,98 @@ optionalDependencies: "@img/sharp-libvips-darwin-x64" "1.0.4" +"@img/sharp-darwin-x64@0.34.1": + version "0.34.1" + resolved "https://registry.yarnpkg.com/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.1.tgz#f1f1d386719f6933796415d84937502b7199a744" + integrity sha512-VfuYgG2r8BpYiOUN+BfYeFo69nP/MIwAtSJ7/Zpxc5QF3KS22z8Pvg3FkrSFJBPNQ7mmcUcYQFBmEQp7eu1F8Q== + optionalDependencies: + "@img/sharp-libvips-darwin-x64" "1.1.0" + "@img/sharp-libvips-darwin-arm64@1.0.4": version "1.0.4" resolved "https://registry.yarnpkg.com/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.4.tgz#447c5026700c01a993c7804eb8af5f6e9868c07f" integrity sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg== +"@img/sharp-libvips-darwin-arm64@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.1.0.tgz#843f7c09c7245dc0d3cfec2b3c83bb08799a704f" + integrity sha512-HZ/JUmPwrJSoM4DIQPv/BfNh9yrOA8tlBbqbLz4JZ5uew2+o22Ik+tHQJcih7QJuSa0zo5coHTfD5J8inqj9DA== + "@img/sharp-libvips-darwin-x64@1.0.4": version "1.0.4" resolved "https://registry.yarnpkg.com/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.4.tgz#e0456f8f7c623f9dbfbdc77383caa72281d86062" integrity sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ== +"@img/sharp-libvips-darwin-x64@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.1.0.tgz#1239c24426c06a8e833815562f78047a3bfbaaf8" + integrity sha512-Xzc2ToEmHN+hfvsl9wja0RlnXEgpKNmftriQp6XzY/RaSfwD9th+MSh0WQKzUreLKKINb3afirxW7A0fz2YWuQ== + "@img/sharp-libvips-linux-arm64@1.0.4": version "1.0.4" resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.4.tgz#979b1c66c9a91f7ff2893556ef267f90ebe51704" integrity sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA== +"@img/sharp-libvips-linux-arm64@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.1.0.tgz#20d276cefd903ee483f0441ba35961679c286315" + integrity sha512-IVfGJa7gjChDET1dK9SekxFFdflarnUB8PwW8aGwEoF3oAsSDuNUTYS+SKDOyOJxQyDC1aPFMuRYLoDInyV9Ew== + "@img/sharp-libvips-linux-arm@1.0.5": version "1.0.5" resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.5.tgz#99f922d4e15216ec205dcb6891b721bfd2884197" integrity sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g== +"@img/sharp-libvips-linux-arm@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.1.0.tgz#067c0b566eae8063738cf1b1db8f8a8573b5465c" + integrity sha512-s8BAd0lwUIvYCJyRdFqvsj+BJIpDBSxs6ivrOPm/R7piTs5UIwY5OjXrP2bqXC9/moGsyRa37eYWYCOGVXxVrA== + +"@img/sharp-libvips-linux-ppc64@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.1.0.tgz#682334595f2ca00e0a07a675ba170af165162802" + integrity sha512-tiXxFZFbhnkWE2LA8oQj7KYR+bWBkiV2nilRldT7bqoEZ4HiDOcePr9wVDAZPi/Id5fT1oY9iGnDq20cwUz8lQ== + "@img/sharp-libvips-linux-s390x@1.0.4": version "1.0.4" resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.4.tgz#f8a5eb1f374a082f72b3f45e2fb25b8118a8a5ce" integrity sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA== +"@img/sharp-libvips-linux-s390x@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.1.0.tgz#82fcd68444b3666384235279c145c2b28d8ee302" + integrity sha512-xukSwvhguw7COyzvmjydRb3x/09+21HykyapcZchiCUkTThEQEOMtBj9UhkaBRLuBrgLFzQ2wbxdeCCJW/jgJA== + "@img/sharp-libvips-linux-x64@1.0.4": version "1.0.4" resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.4.tgz#d4c4619cdd157774906e15770ee119931c7ef5e0" integrity sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw== +"@img/sharp-libvips-linux-x64@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.1.0.tgz#65b2b908bf47156b0724fde9095676c83a18cf5a" + integrity sha512-yRj2+reB8iMg9W5sULM3S74jVS7zqSzHG3Ol/twnAAkAhnGQnpjj6e4ayUz7V+FpKypwgs82xbRdYtchTTUB+Q== + "@img/sharp-libvips-linuxmusl-arm64@1.0.4": version "1.0.4" resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.4.tgz#166778da0f48dd2bded1fa3033cee6b588f0d5d5" integrity sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA== +"@img/sharp-libvips-linuxmusl-arm64@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.1.0.tgz#72accf924e80b081c8db83b900b444a67c203f01" + integrity sha512-jYZdG+whg0MDK+q2COKbYidaqW/WTz0cc1E+tMAusiDygrM4ypmSCjOJPmFTvHHJ8j/6cAGyeDWZOsK06tP33w== + "@img/sharp-libvips-linuxmusl-x64@1.0.4": version "1.0.4" resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.4.tgz#93794e4d7720b077fcad3e02982f2f1c246751ff" integrity sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw== +"@img/sharp-libvips-linuxmusl-x64@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.1.0.tgz#1fa052737e203f46bf44192acd01f9faf11522d7" + integrity sha512-wK7SBdwrAiycjXdkPnGCPLjYb9lD4l6Ze2gSdAGVZrEL05AOUJESWU2lhlC+Ffn5/G+VKuSm6zzbQSzFX/P65A== + "@img/sharp-linux-arm64@0.33.5": version "0.33.5" resolved "https://registry.yarnpkg.com/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.5.tgz#edb0697e7a8279c9fc829a60fc35644c4839bb22" @@ -1775,6 +1793,13 @@ optionalDependencies: "@img/sharp-libvips-linux-arm64" "1.0.4" +"@img/sharp-linux-arm64@0.34.1": + version "0.34.1" + resolved "https://registry.yarnpkg.com/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.1.tgz#c36ef964499b8cfc2d2ed88fe68f27ce41522c80" + integrity sha512-kX2c+vbvaXC6vly1RDf/IWNXxrlxLNpBVWkdpRq5Ka7OOKj6nr66etKy2IENf6FtOgklkg9ZdGpEu9kwdlcwOQ== + optionalDependencies: + "@img/sharp-libvips-linux-arm64" "1.1.0" + "@img/sharp-linux-arm@0.33.5": version "0.33.5" resolved "https://registry.yarnpkg.com/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.5.tgz#422c1a352e7b5832842577dc51602bcd5b6f5eff" @@ -1782,6 +1807,13 @@ optionalDependencies: "@img/sharp-libvips-linux-arm" "1.0.5" +"@img/sharp-linux-arm@0.34.1": + version "0.34.1" + resolved "https://registry.yarnpkg.com/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.1.tgz#c96e38ff028d645912bb0aa132a7178b96997866" + integrity sha512-anKiszvACti2sGy9CirTlNyk7BjjZPiML1jt2ZkTdcvpLU1YH6CXwRAZCA2UmRXnhiIftXQ7+Oh62Ji25W72jA== + optionalDependencies: + "@img/sharp-libvips-linux-arm" "1.1.0" + "@img/sharp-linux-s390x@0.33.5": version "0.33.5" resolved "https://registry.yarnpkg.com/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.5.tgz#f5c077926b48e97e4a04d004dfaf175972059667" @@ -1789,6 +1821,13 @@ optionalDependencies: "@img/sharp-libvips-linux-s390x" "1.0.4" +"@img/sharp-linux-s390x@0.34.1": + version "0.34.1" + resolved "https://registry.yarnpkg.com/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.1.tgz#8ac58d9a49dcb08215e76c8d450717979b7815c3" + integrity sha512-7s0KX2tI9mZI2buRipKIw2X1ufdTeaRgwmRabt5bi9chYfhur+/C1OXg3TKg/eag1W+6CCWLVmSauV1owmRPxA== + optionalDependencies: + "@img/sharp-libvips-linux-s390x" "1.1.0" + "@img/sharp-linux-x64@0.33.5": version "0.33.5" resolved "https://registry.yarnpkg.com/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.5.tgz#d806e0afd71ae6775cc87f0da8f2d03a7c2209cb" @@ -1796,6 +1835,13 @@ optionalDependencies: "@img/sharp-libvips-linux-x64" "1.0.4" +"@img/sharp-linux-x64@0.34.1": + version "0.34.1" + resolved "https://registry.yarnpkg.com/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.1.tgz#3d8652efac635f0dba39d5e3b8b49515a2b2dee1" + integrity sha512-wExv7SH9nmoBW3Wr2gvQopX1k8q2g5V5Iag8Zk6AVENsjwd+3adjwxtp3Dcu2QhOXr8W9NusBU6XcQUohBZ5MA== + optionalDependencies: + "@img/sharp-libvips-linux-x64" "1.1.0" + "@img/sharp-linuxmusl-arm64@0.33.5": version "0.33.5" resolved "https://registry.yarnpkg.com/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.5.tgz#252975b915894fb315af5deea174651e208d3d6b" @@ -1803,6 +1849,13 @@ optionalDependencies: "@img/sharp-libvips-linuxmusl-arm64" "1.0.4" +"@img/sharp-linuxmusl-arm64@0.34.1": + version "0.34.1" + resolved "https://registry.yarnpkg.com/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.1.tgz#b267e6a3e06f9e4d345cde471e5480c5c39e6969" + integrity sha512-DfvyxzHxw4WGdPiTF0SOHnm11Xv4aQexvqhRDAoD00MzHekAj9a/jADXeXYCDFH/DzYruwHbXU7uz+H+nWmSOQ== + optionalDependencies: + "@img/sharp-libvips-linuxmusl-arm64" "1.1.0" + "@img/sharp-linuxmusl-x64@0.33.5": version "0.33.5" resolved "https://registry.yarnpkg.com/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.5.tgz#3f4609ac5d8ef8ec7dadee80b560961a60fd4f48" @@ -1810,6 +1863,13 @@ optionalDependencies: "@img/sharp-libvips-linuxmusl-x64" "1.0.4" +"@img/sharp-linuxmusl-x64@0.34.1": + version "0.34.1" + resolved "https://registry.yarnpkg.com/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.1.tgz#a8dee4b6227f348c4bbacaa6ac3dc584a1a80391" + integrity sha512-pax/kTR407vNb9qaSIiWVnQplPcGU8LRIJpDT5o8PdAx5aAA7AS3X9PS8Isw1/WfqgQorPotjrZL3Pqh6C5EBg== + optionalDependencies: + "@img/sharp-libvips-linuxmusl-x64" "1.1.0" + "@img/sharp-wasm32@0.33.5": version "0.33.5" resolved "https://registry.yarnpkg.com/@img/sharp-wasm32/-/sharp-wasm32-0.33.5.tgz#6f44f3283069d935bb5ca5813153572f3e6f61a1" @@ -1817,16 +1877,33 @@ dependencies: "@emnapi/runtime" "^1.2.0" +"@img/sharp-wasm32@0.34.1": + version "0.34.1" + resolved "https://registry.yarnpkg.com/@img/sharp-wasm32/-/sharp-wasm32-0.34.1.tgz#f7dfd66b6c231269042d3d8750c90f28b9ddcba1" + integrity sha512-YDybQnYrLQfEpzGOQe7OKcyLUCML4YOXl428gOOzBgN6Gw0rv8dpsJ7PqTHxBnXnwXr8S1mYFSLSa727tpz0xg== + dependencies: + "@emnapi/runtime" "^1.4.0" + "@img/sharp-win32-ia32@0.33.5": version "0.33.5" resolved "https://registry.yarnpkg.com/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.5.tgz#1a0c839a40c5351e9885628c85f2e5dfd02b52a9" integrity sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ== +"@img/sharp-win32-ia32@0.34.1": + version "0.34.1" + resolved "https://registry.yarnpkg.com/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.1.tgz#4bc293705df76a5f0a02df66ca3dc12e88f61332" + integrity sha512-WKf/NAZITnonBf3U1LfdjoMgNO5JYRSlhovhRhMxXVdvWYveM4kM3L8m35onYIdh75cOMCo1BexgVQcCDzyoWw== + "@img/sharp-win32-x64@0.33.5": version "0.33.5" resolved "https://registry.yarnpkg.com/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.5.tgz#56f00962ff0c4e0eb93d34a047d29fa995e3e342" integrity sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg== +"@img/sharp-win32-x64@0.34.1": + version "0.34.1" + resolved "https://registry.yarnpkg.com/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.1.tgz#8a7922fec949f037c204c79f6b83238d2482384b" + integrity sha512-hw1iIAHpNE8q3uMIRCgGOeDoz9KtFNarFLQclLxr/LK1VBkj8nby18RjFvr6aP7USRYAjTZW6yisnBWMX571Tw== + "@internationalized/date@3.6.0": version "3.6.0" resolved "https://registry.yarnpkg.com/@internationalized/date/-/date-3.6.0.tgz#b30d43030bfed1855f20c9503606926d75bfdf64" @@ -1841,6 +1918,13 @@ dependencies: "@swc/helpers" "^0.5.0" +"@internationalized/date@^3.8.0": + version "3.8.0" + resolved "https://registry.yarnpkg.com/@internationalized/date/-/date-3.8.0.tgz#24fb301029224351381aa87cba853ca1093af094" + integrity sha512-J51AJ0fEL68hE4CwGPa6E0PO6JDaVLd8aln48xFCSy7CZkZc96dGEGmLs2OEEbBxcsVZtfrqkXJwI2/MSG8yKw== + dependencies: + "@swc/helpers" "^0.5.0" + "@internationalized/message@^3.1.6": version "3.1.6" resolved "https://registry.yarnpkg.com/@internationalized/message/-/message-3.1.6.tgz#e5a832788a17214bfb3e5bbf5f0e23ed2f568ad7" @@ -1849,6 +1933,14 @@ "@swc/helpers" "^0.5.0" intl-messageformat "^10.1.0" +"@internationalized/message@^3.1.7": + version "3.1.7" + resolved "https://registry.yarnpkg.com/@internationalized/message/-/message-3.1.7.tgz#bf5d3332a685d946949bfb7447aa212bbe44ad5d" + integrity sha512-gLQlhEW4iO7DEFPf/U7IrIdA3UyLGS0opeqouaFwlMObLUzwexRjbygONHDVbC9G9oFLXsLyGKYkJwqXw/QADg== + dependencies: + "@swc/helpers" "^0.5.0" + intl-messageformat "^10.1.0" + "@internationalized/number@^3.6.0": version "3.6.0" resolved "https://registry.yarnpkg.com/@internationalized/number/-/number-3.6.0.tgz#dc6ba20c41b25eb605f1d5cac7d8668e9022c224" @@ -1856,6 +1948,13 @@ dependencies: "@swc/helpers" "^0.5.0" +"@internationalized/number@^3.6.1": + version "3.6.1" + resolved "https://registry.yarnpkg.com/@internationalized/number/-/number-3.6.1.tgz#7c13cc55eb546aa3d42b8d5e7ac7db69a082fec7" + integrity sha512-UVsb4bCwbL944E0SX50CHFtWEeZ2uB5VozZ5yDXJdq6iPZsZO5p+bjVMZh2GxHf4Bs/7xtDCcPwEa2NU9DaG/g== + dependencies: + "@swc/helpers" "^0.5.0" + "@internationalized/string@^3.2.5": version "3.2.5" resolved "https://registry.yarnpkg.com/@internationalized/string/-/string-3.2.5.tgz#2f387b256e79596a2e62ddd5e15c619fe241189c" @@ -1863,6 +1962,13 @@ dependencies: "@swc/helpers" "^0.5.0" +"@internationalized/string@^3.2.6": + version "3.2.6" + resolved "https://registry.yarnpkg.com/@internationalized/string/-/string-3.2.6.tgz#dc46f771aeb63a3f1823e060270c4cce8ad44d37" + integrity sha512-LR2lnM4urJta5/wYJVV7m8qk5DrMZmLRTuFhbQO5b9/sKLHgty6unQy1Li4+Su2DWydmB4aZdS5uxBRXIq2aAw== + dependencies: + "@swc/helpers" "^0.5.0" + "@istanbuljs/load-nyc-config@^1.0.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" @@ -2153,57 +2259,57 @@ resolved "https://registry.yarnpkg.com/@mantine/utils/-/utils-6.0.22.tgz#7eace697084e2bc5a831eb0fd7cbbc04cc1b0354" integrity sha512-RSKlNZvxhMCkOFZ6slbYvZYbWjHUM+PxDQnupIOxIdsTZQQjx/BFfrfJ7kQFOP+g7MtpOds8weAetEs5obwMOQ== -"@next/env@15.2.4": - version "15.2.4" - resolved "https://registry.yarnpkg.com/@next/env/-/env-15.2.4.tgz#060f8d8ddb02be5c825eab4ccd9ab619001efffb" - integrity sha512-+SFtMgoiYP3WoSswuNmxJOCwi06TdWE733D+WPjpXIe4LXGULwEaofiiAy6kbS0+XjM5xF5n3lKuBwN2SnqD9g== +"@next/env@15.3.1": + version "15.3.1" + resolved "https://registry.yarnpkg.com/@next/env/-/env-15.3.1.tgz#fca98dcb90d92d555972cdbf03adf9aa982e2115" + integrity sha512-cwK27QdzrMblHSn9DZRV+DQscHXRuJv6MydlJRpFSqJWZrTYMLzKDeyueJNN9MGd8NNiUKzDQADAf+dMLXX7YQ== -"@next/eslint-plugin-next@15.2.1": - version "15.2.1" - resolved "https://registry.yarnpkg.com/@next/eslint-plugin-next/-/eslint-plugin-next-15.2.1.tgz#06b63dde98345d86b060d77d0cac29dd0d6b61fd" - integrity sha512-6ppeToFd02z38SllzWxayLxjjNfzvc7Wm07gQOKSLjyASvKcXjNStZrLXMHuaWkhjqxe+cnhb2uzfWXm1VEj/Q== +"@next/eslint-plugin-next@15.3.1": + version "15.3.1" + resolved "https://registry.yarnpkg.com/@next/eslint-plugin-next/-/eslint-plugin-next-15.3.1.tgz#8f57c6ccb80ae31e40935f70da57be5f03f225d5" + integrity sha512-oEs4dsfM6iyER3jTzMm4kDSbrQJq8wZw5fmT6fg2V3SMo+kgG+cShzLfEV20senZzv8VF+puNLheiGPlBGsv2A== dependencies: fast-glob "3.3.1" -"@next/swc-darwin-arm64@15.2.4": - version "15.2.4" - resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.2.4.tgz#3a54f67aa2e0096a9147bd24dff1492e151819ae" - integrity sha512-1AnMfs655ipJEDC/FHkSr0r3lXBgpqKo4K1kiwfUf3iE68rDFXZ1TtHdMvf7D0hMItgDZ7Vuq3JgNMbt/+3bYw== - -"@next/swc-darwin-x64@15.2.4": - version "15.2.4" - resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-15.2.4.tgz#9b540f24afde1b7878623fdba9695344d26b7d67" - integrity sha512-3qK2zb5EwCwxnO2HeO+TRqCubeI/NgCe+kL5dTJlPldV/uwCnUgC7VbEzgmxbfrkbjehL4H9BPztWOEtsoMwew== - -"@next/swc-linux-arm64-gnu@15.2.4": - version "15.2.4" - resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.2.4.tgz#417a234c9f4dc5495094a8979859ac528c0f1f58" - integrity sha512-HFN6GKUcrTWvem8AZN7tT95zPb0GUGv9v0d0iyuTb303vbXkkbHDp/DxufB04jNVD+IN9yHy7y/6Mqq0h0YVaQ== - -"@next/swc-linux-arm64-musl@15.2.4": - version "15.2.4" - resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.2.4.tgz#9bca76375508a175956f2d51f8547d0d6f9ffa64" - integrity sha512-Oioa0SORWLwi35/kVB8aCk5Uq+5/ZIumMK1kJV+jSdazFm2NzPDztsefzdmzzpx5oGCJ6FkUC7vkaUseNTStNA== - -"@next/swc-linux-x64-gnu@15.2.4": - version "15.2.4" - resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.2.4.tgz#c3d5041d53a5b228bf521ed49649e0f2a7aff947" - integrity sha512-yb5WTRaHdkgOqFOZiu6rHV1fAEK0flVpaIN2HB6kxHVSy/dIajWbThS7qON3W9/SNOH2JWkVCyulgGYekMePuw== - -"@next/swc-linux-x64-musl@15.2.4": - version "15.2.4" - resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.2.4.tgz#b2a51a108b1c412c69a504556cde0517631768c7" - integrity sha512-Dcdv/ix6srhkM25fgXiyOieFUkz+fOYkHlydWCtB0xMST6X9XYI3yPDKBZt1xuhOytONsIFJFB08xXYsxUwJLw== - -"@next/swc-win32-arm64-msvc@15.2.4": - version "15.2.4" - resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.2.4.tgz#7d687b42512abd36f44c2c787d58a1590f174b69" - integrity sha512-dW0i7eukvDxtIhCYkMrZNQfNicPDExt2jPb9AZPpL7cfyUo7QSNl1DjsHjmmKp6qNAqUESyT8YFl/Aw91cNJJg== - -"@next/swc-win32-x64-msvc@15.2.4": - version "15.2.4" - resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.2.4.tgz#779a0ea272fa4f509387f3b320e2d70803943a95" - integrity sha512-SbnWkJmkS7Xl3kre8SdMF6F/XDh1DTFEhp0jRTj/uB8iPKoU2bb2NDfcu+iifv1+mxQEd1g2vvSxcZbXSKyWiQ== +"@next/swc-darwin-arm64@15.3.1": + version "15.3.1" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.3.1.tgz#8f9589aed9f6816687440aa36a86376b3a16af58" + integrity sha512-hjDw4f4/nla+6wysBL07z52Gs55Gttp5Bsk5/8AncQLJoisvTBP0pRIBK/B16/KqQyH+uN4Ww8KkcAqJODYH3w== + +"@next/swc-darwin-x64@15.3.1": + version "15.3.1" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-15.3.1.tgz#2df013226d848394ed7307188c141f0e6da4ab3e" + integrity sha512-q+aw+cJ2ooVYdCEqZVk+T4Ni10jF6Fo5DfpEV51OupMaV5XL6pf3GCzrk6kSSZBsMKZtVC1Zm/xaNBFpA6bJ2g== + +"@next/swc-linux-arm64-gnu@15.3.1": + version "15.3.1" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.3.1.tgz#d1c4e24b2b27c36a7ebc21ae0573e9e98f794143" + integrity sha512-wBQ+jGUI3N0QZyWmmvRHjXjTWFy8o+zPFLSOyAyGFI94oJi+kK/LIZFJXeykvgXUk1NLDAEFDZw/NVINhdk9FQ== + +"@next/swc-linux-arm64-musl@15.3.1": + version "15.3.1" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.3.1.tgz#bce27533f9f046800f850a9c20832e8c15b10955" + integrity sha512-IIxXEXRti/AulO9lWRHiCpUUR8AR/ZYLPALgiIg/9ENzMzLn3l0NSxVdva7R/VDcuSEBo0eGVCe3evSIHNz0Hg== + +"@next/swc-linux-x64-gnu@15.3.1": + version "15.3.1" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.3.1.tgz#f90558d93bc25e01b0b271725e291863286753c4" + integrity sha512-bfI4AMhySJbyXQIKH5rmLJ5/BP7bPwuxauTvVEiJ/ADoddaA9fgyNNCcsbu9SlqfHDoZmfI6g2EjzLwbsVTr5A== + +"@next/swc-linux-x64-musl@15.3.1": + version "15.3.1" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.3.1.tgz#639f143bd0f3fd6e1bde4b383dc6cd8a8ff12628" + integrity sha512-FeAbR7FYMWR+Z+M5iSGytVryKHiAsc0x3Nc3J+FD5NVbD5Mqz7fTSy8CYliXinn7T26nDMbpExRUI/4ekTvoiA== + +"@next/swc-win32-arm64-msvc@15.3.1": + version "15.3.1" + resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.3.1.tgz#52ee1e63b192fec8f0230caf839cfc308d0d44d1" + integrity sha512-yP7FueWjphQEPpJQ2oKmshk/ppOt+0/bB8JC8svPUZNy0Pi3KbPx2Llkzv1p8CoQa+D2wknINlJpHf3vtChVBw== + +"@next/swc-win32-x64-msvc@15.3.1": + version "15.3.1" + resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.3.1.tgz#df5ceb9c3b97bf0d61cb6e84f79bbf9e91a89d29" + integrity sha512-3PMvF2zRJAifcRNni9uMk/gulWfWS+qVI/pagd+4yLF5bcXPZPPH2xlYRYOsUjmCJOXSTAC2PjRzbhsRzR2fDQ== "@nodelib/fs.scandir@2.1.5": version "2.1.5" @@ -2562,27 +2668,27 @@ dependencies: "@opentelemetry/core" "^1.1.0" -"@pkgr/core@^0.1.0": - version "0.1.1" - resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.1.1.tgz#1ec17e2edbec25c8306d424ecfbf13c7de1aaa31" - integrity sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA== +"@pkgr/core@^0.2.3": + version "0.2.4" + resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.2.4.tgz#d897170a2b0ba51f78a099edccd968f7b103387c" + integrity sha512-ROFF39F6ZrnzSUEmQQZUar0Jt4xVoP9WnDRdWwF4NNcXs3xBTLgBUDoOwW141y1jP+S8nahIbdxbFC7IShw9Iw== -"@playwright/test@1.50.1": - version "1.50.1" - resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.50.1.tgz#027d00ca77ec79688764eb765cfe9a688807bf0b" - integrity sha512-Jii3aBg+CEDpgnuDxEp/h7BimHcUTDlpEtce89xEumlJ5ef2hqepZ+PWp1DDpYC/VO9fmWVI1IlEaoI5fK9FXQ== +"@playwright/test@1.52.0": + version "1.52.0" + resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.52.0.tgz#267ec595b43a8f4fa5e444ea503689629e91a5b8" + integrity sha512-uh6W7sb55hl7D6vsAeA+V2p5JnlAqzhqFyF0VcJkKZXkgnFcVG9PziERRHQfPLfNGx1C292a4JqbWzhR8L4R1g== dependencies: - playwright "1.50.1" + playwright "1.52.0" "@popperjs/core@^2.9.0": version "2.11.8" resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.8.tgz#6b79032e760a0899cd4204710beede972a3a185f" integrity sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A== -"@prisma/instrumentation@6.4.1": - version "6.4.1" - resolved "https://registry.yarnpkg.com/@prisma/instrumentation/-/instrumentation-6.4.1.tgz#3a0fb65bfb3e3a6712c41f9334599fa281c451d5" - integrity sha512-1SeN0IvMp5zm3RLJnEr+Zn67WDqUIPP1lF/PkLbi/X64vsnFyItcXNRBrYr0/sI2qLcH9iNzJUhyd3emdGizaQ== +"@prisma/instrumentation@6.5.0": + version "6.5.0" + resolved "https://registry.yarnpkg.com/@prisma/instrumentation/-/instrumentation-6.5.0.tgz#ce6c160365dfccbe0f4e7c57a4afc4f946fee562" + integrity sha512-morJDtFRoAp5d/KENEm+K6Y3PQcn5bCvpJ5a9y3V3DNMrNy/ZSn2zulPGj+ld+Xj2UYVoaMJ8DpBX/o6iF6OiA== dependencies: "@opentelemetry/instrumentation" "^0.52.0 || ^0.53.0 || ^0.54.0 || ^0.55.0 || ^0.56.0 || ^0.57.0" @@ -2591,16 +2697,31 @@ resolved "https://registry.yarnpkg.com/@radix-ui/primitive/-/primitive-1.1.1.tgz#fc169732d755c7fbad33ba8d0cd7fd10c90dc8e3" integrity sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA== +"@radix-ui/primitive@1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@radix-ui/primitive/-/primitive-1.1.2.tgz#83f415c4425f21e3d27914c12b3272a32e3dae65" + integrity sha512-XnbHrrprsNqZKQhStrSwgRUQzoCI1glLzdw79xiZPoofhGICeZRSQ3dIxAKH1gb3OHfNf4d6f+vAv3kil2eggA== + "@radix-ui/react-compose-refs@1.1.1": version "1.1.1" resolved "https://registry.yarnpkg.com/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz#6f766faa975f8738269ebb8a23bad4f5a8d2faec" integrity sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw== +"@radix-ui/react-compose-refs@1.1.2", "@radix-ui/react-compose-refs@^1.1.1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz#a2c4c47af6337048ee78ff6dc0d090b390d2bb30" + integrity sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg== + "@radix-ui/react-context@1.1.1": version "1.1.1" resolved "https://registry.yarnpkg.com/@radix-ui/react-context/-/react-context-1.1.1.tgz#82074aa83a472353bb22e86f11bcbd1c61c4c71a" integrity sha512-UASk9zi+crv9WteK/NU4PLvOoL3OuE6BWVKNF6hPRBtYBDXQ2u5iu3O59zUlJiTVvkyuycnqrztsHVJwcK9K+Q== +"@radix-ui/react-context@1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@radix-ui/react-context/-/react-context-1.1.2.tgz#61628ef269a433382c364f6f1e3788a6dc213a36" + integrity sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA== + "@radix-ui/react-dialog@^1.1.2": version "1.1.5" resolved "https://registry.yarnpkg.com/@radix-ui/react-dialog/-/react-dialog-1.1.5.tgz#1bb2880e6b0ef9d9d0d9f440e1414c94bbacb55b" @@ -2621,6 +2742,26 @@ aria-hidden "^1.2.4" react-remove-scroll "^2.6.2" +"@radix-ui/react-dialog@^1.1.6": + version "1.1.11" + resolved "https://registry.yarnpkg.com/@radix-ui/react-dialog/-/react-dialog-1.1.11.tgz#1144609cbc9f8b36bcc288beb880f6b72cbd85ee" + integrity sha512-yI7S1ipkP5/+99qhSI6nthfo/tR6bL6Zgxi/+1UO6qPa6UeM6nlafWcQ65vB4rU2XjgjMfMhI3k9Y5MztA62VQ== + dependencies: + "@radix-ui/primitive" "1.1.2" + "@radix-ui/react-compose-refs" "1.1.2" + "@radix-ui/react-context" "1.1.2" + "@radix-ui/react-dismissable-layer" "1.1.7" + "@radix-ui/react-focus-guards" "1.1.2" + "@radix-ui/react-focus-scope" "1.1.4" + "@radix-ui/react-id" "1.1.1" + "@radix-ui/react-portal" "1.1.6" + "@radix-ui/react-presence" "1.1.4" + "@radix-ui/react-primitive" "2.1.0" + "@radix-ui/react-slot" "1.2.0" + "@radix-ui/react-use-controllable-state" "1.2.2" + aria-hidden "^1.2.4" + react-remove-scroll "^2.6.3" + "@radix-ui/react-dismissable-layer@1.1.4": version "1.1.4" resolved "https://registry.yarnpkg.com/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.4.tgz#6e31ad92e7d9e77548001fd8c04f8561300c02a9" @@ -2632,11 +2773,27 @@ "@radix-ui/react-use-callback-ref" "1.1.0" "@radix-ui/react-use-escape-keydown" "1.1.0" +"@radix-ui/react-dismissable-layer@1.1.7": + version "1.1.7" + resolved "https://registry.yarnpkg.com/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.7.tgz#80b5c23a0d29cfe56850399210c603376c27091f" + integrity sha512-j5+WBUdhccJsmH5/H0K6RncjDtoALSEr6jbkaZu+bjw6hOPOhHycr6vEUujl+HBK8kjUfWcoCJXxP6e4lUlMZw== + dependencies: + "@radix-ui/primitive" "1.1.2" + "@radix-ui/react-compose-refs" "1.1.2" + "@radix-ui/react-primitive" "2.1.0" + "@radix-ui/react-use-callback-ref" "1.1.1" + "@radix-ui/react-use-escape-keydown" "1.1.1" + "@radix-ui/react-focus-guards@1.1.1": version "1.1.1" resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.1.tgz#8635edd346304f8b42cae86b05912b61aef27afe" integrity sha512-pSIwfrT1a6sIoDASCSpFwOasEwKTZWDw/iBdtnqKO7v6FeOzYJ7U53cPzYFVR3geGGXgVHaH+CdngrrAzqUGxg== +"@radix-ui/react-focus-guards@1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.2.tgz#4ec9a7e50925f7fb661394460045b46212a33bed" + integrity sha512-fyjAACV62oPV925xFCrH8DR5xWhg9KYtJT4s3u54jxp+L/hbpTY2kIeEFFbFe+a/HCE94zGQMZLIpVTPVZDhaA== + "@radix-ui/react-focus-scope@1.1.1": version "1.1.1" resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.1.tgz#5c602115d1db1c4fcfa0fae4c3b09bb8919853cb" @@ -2646,6 +2803,15 @@ "@radix-ui/react-primitive" "2.0.1" "@radix-ui/react-use-callback-ref" "1.1.0" +"@radix-ui/react-focus-scope@1.1.4": + version "1.1.4" + resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.4.tgz#dbe9ed31b36ff9aadadf4b59aa733a4e91799d15" + integrity sha512-r2annK27lIW5w9Ho5NyQgqs0MmgZSTIKXWpVCJaLC1q2kZrZkcqnmHkCHMEmv8XLvsLlurKMPT+kbKkRkm/xVA== + dependencies: + "@radix-ui/react-compose-refs" "1.1.2" + "@radix-ui/react-primitive" "2.1.0" + "@radix-ui/react-use-callback-ref" "1.1.1" + "@radix-ui/react-id@1.1.0", "@radix-ui/react-id@^1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@radix-ui/react-id/-/react-id-1.1.0.tgz#de47339656594ad722eb87f94a6b25f9cffae0ed" @@ -2653,6 +2819,13 @@ dependencies: "@radix-ui/react-use-layout-effect" "1.1.0" +"@radix-ui/react-id@1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-id/-/react-id-1.1.1.tgz#1404002e79a03fe062b7e3864aa01e24bd1471f7" + integrity sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg== + dependencies: + "@radix-ui/react-use-layout-effect" "1.1.1" + "@radix-ui/react-portal@1.1.3": version "1.1.3" resolved "https://registry.yarnpkg.com/@radix-ui/react-portal/-/react-portal-1.1.3.tgz#b0ea5141103a1671b715481b13440763d2ac4440" @@ -2661,6 +2834,14 @@ "@radix-ui/react-primitive" "2.0.1" "@radix-ui/react-use-layout-effect" "1.1.0" +"@radix-ui/react-portal@1.1.6": + version "1.1.6" + resolved "https://registry.yarnpkg.com/@radix-ui/react-portal/-/react-portal-1.1.6.tgz#4202e1bb34afdac612e4e982eca8efd36cbc611f" + integrity sha512-XmsIl2z1n/TsYFLIdYam2rmFwf9OC/Sh2avkbmVMDuBZIe7hSpM0cYnWPAo7nHOVx8zTuwDZGByfcqLdnzp3Vw== + dependencies: + "@radix-ui/react-primitive" "2.1.0" + "@radix-ui/react-use-layout-effect" "1.1.1" + "@radix-ui/react-presence@1.1.2": version "1.1.2" resolved "https://registry.yarnpkg.com/@radix-ui/react-presence/-/react-presence-1.1.2.tgz#bb764ed8a9118b7ec4512da5ece306ded8703cdc" @@ -2669,6 +2850,14 @@ "@radix-ui/react-compose-refs" "1.1.1" "@radix-ui/react-use-layout-effect" "1.1.0" +"@radix-ui/react-presence@1.1.4": + version "1.1.4" + resolved "https://registry.yarnpkg.com/@radix-ui/react-presence/-/react-presence-1.1.4.tgz#253ac0ad4946c5b4a9c66878335f5cf07c967ced" + integrity sha512-ueDqRbdc4/bkaQT3GIpLQssRlFgWaL/U2z/S31qRwwLWoxHLgry3SIfCwhxeQNbirEUXFa+lq3RL3oBYXtcmIA== + dependencies: + "@radix-ui/react-compose-refs" "1.1.2" + "@radix-ui/react-use-layout-effect" "1.1.1" + "@radix-ui/react-primitive@2.0.1", "@radix-ui/react-primitive@^2.0.0": version "2.0.1" resolved "https://registry.yarnpkg.com/@radix-ui/react-primitive/-/react-primitive-2.0.1.tgz#6d9efc550f7520135366f333d1e820cf225fad9e" @@ -2676,6 +2865,13 @@ dependencies: "@radix-ui/react-slot" "1.1.1" +"@radix-ui/react-primitive@2.1.0", "@radix-ui/react-primitive@^2.0.2": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@radix-ui/react-primitive/-/react-primitive-2.1.0.tgz#9233e17a22d0010195086f8b5eb1808ebbca8437" + integrity sha512-/J/FhLdK0zVcILOwt5g+dH4KnkonCtkVJsa2G6JmvbbtZfBEI1gMsO3QMjseL4F/SwfAMt1Vc/0XKYKq+xJ1sw== + dependencies: + "@radix-ui/react-slot" "1.2.0" + "@radix-ui/react-slot@1.1.1": version "1.1.1" resolved "https://registry.yarnpkg.com/@radix-ui/react-slot/-/react-slot-1.1.1.tgz#ab9a0ffae4027db7dc2af503c223c978706affc3" @@ -2683,11 +2879,23 @@ dependencies: "@radix-ui/react-compose-refs" "1.1.1" +"@radix-ui/react-slot@1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@radix-ui/react-slot/-/react-slot-1.2.0.tgz#57727fc186ddb40724ccfbe294e1a351d92462ba" + integrity sha512-ujc+V6r0HNDviYqIK3rW4ffgYiZ8g5DEHrGJVk4x7kTlLXRDILnKX9vAUYeIsLOoDpDJ0ujpqMkjH4w2ofuo6w== + dependencies: + "@radix-ui/react-compose-refs" "1.1.2" + "@radix-ui/react-use-callback-ref@1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.0.tgz#bce938ca413675bc937944b0d01ef6f4a6dc5bf1" integrity sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw== +"@radix-ui/react-use-callback-ref@1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz#62a4dba8b3255fdc5cc7787faeac1c6e4cc58d40" + integrity sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg== + "@radix-ui/react-use-controllable-state@1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.1.0.tgz#1321446857bb786917df54c0d4d084877aab04b0" @@ -2695,6 +2903,21 @@ dependencies: "@radix-ui/react-use-callback-ref" "1.1.0" +"@radix-ui/react-use-controllable-state@1.2.2": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz#905793405de57d61a439f4afebbb17d0645f3190" + integrity sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg== + dependencies: + "@radix-ui/react-use-effect-event" "0.0.2" + "@radix-ui/react-use-layout-effect" "1.1.1" + +"@radix-ui/react-use-effect-event@0.0.2": + version "0.0.2" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz#090cf30d00a4c7632a15548512e9152217593907" + integrity sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA== + dependencies: + "@radix-ui/react-use-layout-effect" "1.1.1" + "@radix-ui/react-use-escape-keydown@1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.0.tgz#31a5b87c3b726504b74e05dac1edce7437b98754" @@ -2702,11 +2925,23 @@ dependencies: "@radix-ui/react-use-callback-ref" "1.1.0" +"@radix-ui/react-use-escape-keydown@1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.1.tgz#b3fed9bbea366a118f40427ac40500aa1423cc29" + integrity sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g== + dependencies: + "@radix-ui/react-use-callback-ref" "1.1.1" + "@radix-ui/react-use-layout-effect@1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.0.tgz#3c2c8ce04827b26a39e442ff4888d9212268bd27" integrity sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w== +"@radix-ui/react-use-layout-effect@1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz#0c4230a9eed49d4589c967e2d9c0d9d60a23971e" + integrity sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ== + "@react-aria/autocomplete@3.0.0-alpha.37": version "3.0.0-alpha.37" resolved "https://registry.yarnpkg.com/@react-aria/autocomplete/-/autocomplete-3.0.0-alpha.37.tgz#f8ba3df6c91dcf3d449b416d72c184812533eff3" @@ -2726,6 +2961,26 @@ "@react-types/shared" "^3.27.0" "@swc/helpers" "^0.5.0" +"@react-aria/autocomplete@3.0.0-beta.2": + version "3.0.0-beta.2" + resolved "https://registry.yarnpkg.com/@react-aria/autocomplete/-/autocomplete-3.0.0-beta.2.tgz#61fc21cde05206e9a90f32378f25d13f5424366c" + integrity sha512-oxsFCIGj5yooQkZzdqjvsdfr9fOlmAq4v6njIOAyQFsta3H0yQiv+YU3XnrnCBxVX+Mz/mZtZgfhAA9JBDukHg== + dependencies: + "@react-aria/combobox" "^3.12.2" + "@react-aria/focus" "^3.20.2" + "@react-aria/i18n" "^3.12.8" + "@react-aria/interactions" "^3.25.0" + "@react-aria/listbox" "^3.14.3" + "@react-aria/searchfield" "^3.8.3" + "@react-aria/textfield" "^3.17.2" + "@react-aria/utils" "^3.28.2" + "@react-stately/autocomplete" "3.0.0-beta.1" + "@react-stately/combobox" "^3.10.4" + "@react-types/autocomplete" "3.0.0-alpha.30" + "@react-types/button" "^3.12.0" + "@react-types/shared" "^3.29.0" + "@swc/helpers" "^0.5.0" + "@react-aria/breadcrumbs@^3.5.19", "@react-aria/breadcrumbs@^3.5.21": version "3.5.21" resolved "https://registry.yarnpkg.com/@react-aria/breadcrumbs/-/breadcrumbs-3.5.21.tgz#7e8fdef1dd6805e3bcfdc3b39f15b5640aaf6c9e" @@ -2750,6 +3005,18 @@ "@react-types/shared" "^3.27.0" "@swc/helpers" "^0.5.0" +"@react-aria/breadcrumbs@^3.5.23": + version "3.5.23" + resolved "https://registry.yarnpkg.com/@react-aria/breadcrumbs/-/breadcrumbs-3.5.23.tgz#d5f15a567656ccbba11680cb3849f42e74618c32" + integrity sha512-4uLxuAgPfXds8sBc/Cg0ml7LKWzK+YTwHL7xclhQUkPO32rzlHDl+BJ5cyWhvZgGUf8JJXbXhD5VlJJzbbl8Xg== + dependencies: + "@react-aria/i18n" "^3.12.8" + "@react-aria/link" "^3.8.0" + "@react-aria/utils" "^3.28.2" + "@react-types/breadcrumbs" "^3.7.12" + "@react-types/shared" "^3.29.0" + "@swc/helpers" "^0.5.0" + "@react-aria/button@^3.11.0", "@react-aria/button@^3.12.0": version "3.12.0" resolved "https://registry.yarnpkg.com/@react-aria/button/-/button-3.12.0.tgz#40c7af1141aa83a51e0177dd605d2a5dda0ebc84" @@ -2777,6 +3044,19 @@ "@react-types/shared" "^3.27.0" "@swc/helpers" "^0.5.0" +"@react-aria/button@^3.13.0": + version "3.13.0" + resolved "https://registry.yarnpkg.com/@react-aria/button/-/button-3.13.0.tgz#9751a34bc69e02c935d4b373fb456560ec0d3ef1" + integrity sha512-BEcTQb7Q8ZrAtn0scPDv/ErZoGC1FI0sLk0UTPGskuh/RV9ZZGFbuSWTqOwV8w5CS6VMvPjH6vaE8hS7sb5DIw== + dependencies: + "@react-aria/interactions" "^3.25.0" + "@react-aria/toolbar" "3.0.0-beta.15" + "@react-aria/utils" "^3.28.2" + "@react-stately/toggle" "^3.8.3" + "@react-types/button" "^3.12.0" + "@react-types/shared" "^3.29.0" + "@swc/helpers" "^0.5.0" + "@react-aria/calendar@3.6.0": version "3.6.0" resolved "https://registry.yarnpkg.com/@react-aria/calendar/-/calendar-3.6.0.tgz#d5e7cf4beb8724648a7042dbc5bb519de4351906" @@ -2825,6 +3105,22 @@ "@react-types/shared" "^3.27.0" "@swc/helpers" "^0.5.0" +"@react-aria/calendar@^3.8.0": + version "3.8.0" + resolved "https://registry.yarnpkg.com/@react-aria/calendar/-/calendar-3.8.0.tgz#8f210d2ecfd89a8020f5568fdf2014a8e6c62a46" + integrity sha512-9vms/fWjJPZkJcMxciwWWOjGy/Q0nqI6FV0pYbMZbqepkzglEaVd98kl506r/4hLhWKwLdTfqCgbntRecj8jBg== + dependencies: + "@internationalized/date" "^3.8.0" + "@react-aria/i18n" "^3.12.8" + "@react-aria/interactions" "^3.25.0" + "@react-aria/live-announcer" "^3.4.2" + "@react-aria/utils" "^3.28.2" + "@react-stately/calendar" "^3.8.0" + "@react-types/button" "^3.12.0" + "@react-types/calendar" "^3.7.0" + "@react-types/shared" "^3.29.0" + "@swc/helpers" "^0.5.0" + "@react-aria/checkbox@^3.15.0", "@react-aria/checkbox@^3.15.2": version "3.15.2" resolved "https://registry.yarnpkg.com/@react-aria/checkbox/-/checkbox-3.15.2.tgz#d23447c91294445cc1400ca311363d37e1b58012" @@ -2859,6 +3155,23 @@ "@react-types/shared" "^3.27.0" "@swc/helpers" "^0.5.0" +"@react-aria/checkbox@^3.15.4": + version "3.15.4" + resolved "https://registry.yarnpkg.com/@react-aria/checkbox/-/checkbox-3.15.4.tgz#3e85c948923960eebcc3a6d668a5d056f1bf0d7e" + integrity sha512-ZkDJFs2EfMBXVIpBSo4ouB+NXyr2LRgZNp2x8/v+7n3aTmMU8j2PzT+Ra2geTQbC0glMP7UrSg4qZblqrxEBcQ== + dependencies: + "@react-aria/form" "^3.0.15" + "@react-aria/interactions" "^3.25.0" + "@react-aria/label" "^3.7.17" + "@react-aria/toggle" "^3.11.2" + "@react-aria/utils" "^3.28.2" + "@react-stately/checkbox" "^3.6.13" + "@react-stately/form" "^3.1.3" + "@react-stately/toggle" "^3.8.3" + "@react-types/checkbox" "^3.9.3" + "@react-types/shared" "^3.29.0" + "@swc/helpers" "^0.5.0" + "@react-aria/collections@3.0.0-alpha.6": version "3.0.0-alpha.6" resolved "https://registry.yarnpkg.com/@react-aria/collections/-/collections-3.0.0-alpha.6.tgz#2fab7192ba4ac1452ad01b2c5456195a16f353e1" @@ -2881,6 +3194,18 @@ "@swc/helpers" "^0.5.0" use-sync-external-store "^1.2.0" +"@react-aria/collections@3.0.0-rc.0": + version "3.0.0-rc.0" + resolved "https://registry.yarnpkg.com/@react-aria/collections/-/collections-3.0.0-rc.0.tgz#d0a906f4a4582a91b6ad866a58fbe2ef1713b15e" + integrity sha512-WcRcE3wKtbprOJlBaMbdYS5Suu2KIGq1gVT2fLXVbmDY0CjGemqp2m5aDblQOO8pxvsAqHV8pyznkhANTnK1CQ== + dependencies: + "@react-aria/interactions" "^3.25.0" + "@react-aria/ssr" "^3.9.8" + "@react-aria/utils" "^3.28.2" + "@react-types/shared" "^3.29.0" + "@swc/helpers" "^0.5.0" + use-sync-external-store "^1.4.0" + "@react-aria/color@^3.0.2", "@react-aria/color@^3.0.4": version "3.0.4" resolved "https://registry.yarnpkg.com/@react-aria/color/-/color-3.0.4.tgz#ed0097ecd18c253b61d3e2ec5f87c2662a726cde" @@ -2919,6 +3244,25 @@ "@react-types/shared" "^3.27.0" "@swc/helpers" "^0.5.0" +"@react-aria/color@^3.0.6": + version "3.0.6" + resolved "https://registry.yarnpkg.com/@react-aria/color/-/color-3.0.6.tgz#6444d992afe0149bb5cce28d75b747a01cc59fef" + integrity sha512-ik4Db9hrN1yIT0CQMB888ktBmrwA/kNhkfiDACtoUHv8Ev+YEpmagnmih9vMyW2vcnozYJpnn/aCMl59J5uMew== + dependencies: + "@react-aria/i18n" "^3.12.8" + "@react-aria/interactions" "^3.25.0" + "@react-aria/numberfield" "^3.11.13" + "@react-aria/slider" "^3.7.18" + "@react-aria/spinbutton" "^3.6.14" + "@react-aria/textfield" "^3.17.2" + "@react-aria/utils" "^3.28.2" + "@react-aria/visually-hidden" "^3.8.22" + "@react-stately/color" "^3.8.4" + "@react-stately/form" "^3.1.3" + "@react-types/color" "^3.0.4" + "@react-types/shared" "^3.29.0" + "@swc/helpers" "^0.5.0" + "@react-aria/combobox@^3.11.0", "@react-aria/combobox@^3.12.0": version "3.12.0" resolved "https://registry.yarnpkg.com/@react-aria/combobox/-/combobox-3.12.0.tgz#0d5c84326a799fa4cb7daa73e65981b1d33f8185" @@ -2962,6 +3306,28 @@ "@react-types/shared" "^3.27.0" "@swc/helpers" "^0.5.0" +"@react-aria/combobox@^3.12.2": + version "3.12.2" + resolved "https://registry.yarnpkg.com/@react-aria/combobox/-/combobox-3.12.2.tgz#6e2b0cfc6863d8ead79a5dd7736104187a6929f7" + integrity sha512-EgddiF8VnAjB4EynJERPn4IoDMUabI8GiKOQZ6Ar3MlRWxQnUfxPpZwXs8qWR3dPCzYUt2PhBinhBMjyR1yRIw== + dependencies: + "@react-aria/focus" "^3.20.2" + "@react-aria/i18n" "^3.12.8" + "@react-aria/listbox" "^3.14.3" + "@react-aria/live-announcer" "^3.4.2" + "@react-aria/menu" "^3.18.2" + "@react-aria/overlays" "^3.27.0" + "@react-aria/selection" "^3.24.0" + "@react-aria/textfield" "^3.17.2" + "@react-aria/utils" "^3.28.2" + "@react-stately/collections" "^3.12.3" + "@react-stately/combobox" "^3.10.4" + "@react-stately/form" "^3.1.3" + "@react-types/button" "^3.12.0" + "@react-types/combobox" "^3.13.4" + "@react-types/shared" "^3.29.0" + "@swc/helpers" "^0.5.0" + "@react-aria/datepicker@3.12.0": version "3.12.0" resolved "https://registry.yarnpkg.com/@react-aria/datepicker/-/datepicker-3.12.0.tgz#a82ff3ebd3ead20a00096d082c1e6be47bbd5886" @@ -3034,6 +3400,30 @@ "@react-types/shared" "^3.27.0" "@swc/helpers" "^0.5.0" +"@react-aria/datepicker@^3.14.2": + version "3.14.2" + resolved "https://registry.yarnpkg.com/@react-aria/datepicker/-/datepicker-3.14.2.tgz#db1efa94edc86b57950cf32cbfd252b206653fab" + integrity sha512-O7fdzcqIJ7i/+8SGYvx4tloTZgK4Ws8OChdbFcd2rZoRPqxM50M6J+Ota8hTet2wIhojUXnM3x2na3EvoucBXA== + dependencies: + "@internationalized/date" "^3.8.0" + "@internationalized/number" "^3.6.1" + "@internationalized/string" "^3.2.6" + "@react-aria/focus" "^3.20.2" + "@react-aria/form" "^3.0.15" + "@react-aria/i18n" "^3.12.8" + "@react-aria/interactions" "^3.25.0" + "@react-aria/label" "^3.7.17" + "@react-aria/spinbutton" "^3.6.14" + "@react-aria/utils" "^3.28.2" + "@react-stately/datepicker" "^3.14.0" + "@react-stately/form" "^3.1.3" + "@react-types/button" "^3.12.0" + "@react-types/calendar" "^3.7.0" + "@react-types/datepicker" "^3.12.0" + "@react-types/dialog" "^3.5.17" + "@react-types/shared" "^3.29.0" + "@swc/helpers" "^0.5.0" + "@react-aria/dialog@^3.5.20", "@react-aria/dialog@^3.5.22": version "3.5.22" resolved "https://registry.yarnpkg.com/@react-aria/dialog/-/dialog-3.5.22.tgz#91017dfcc204465cb332fac41a5bfcb07893b269" @@ -3058,6 +3448,18 @@ "@react-types/shared" "^3.27.0" "@swc/helpers" "^0.5.0" +"@react-aria/dialog@^3.5.24": + version "3.5.24" + resolved "https://registry.yarnpkg.com/@react-aria/dialog/-/dialog-3.5.24.tgz#1ad9ecd505f8c3e0c7700a84e8c213a0416c5278" + integrity sha512-tw0WH89gVpHMI5KUQhuzRE+IYCc9clRfDvCppuXNueKDrZmrQKbeoU6d0b5WYRsBur2+d7ErtvpLzHVqE1HzfA== + dependencies: + "@react-aria/interactions" "^3.25.0" + "@react-aria/overlays" "^3.27.0" + "@react-aria/utils" "^3.28.2" + "@react-types/dialog" "^3.5.17" + "@react-types/shared" "^3.29.0" + "@swc/helpers" "^0.5.0" + "@react-aria/disclosure@^3.0.0", "@react-aria/disclosure@^3.0.2": version "3.0.2" resolved "https://registry.yarnpkg.com/@react-aria/disclosure/-/disclosure-3.0.2.tgz#84eacfe35181057c690689132acf4d1b7fdbdcad" @@ -3080,6 +3482,17 @@ "@react-types/button" "^3.10.2" "@swc/helpers" "^0.5.0" +"@react-aria/disclosure@^3.0.4": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@react-aria/disclosure/-/disclosure-3.0.4.tgz#cff7e457b7014038785bcdb23c4ee10a5813674a" + integrity sha512-HXGVLA06BH0b/gN8dCTzWATwMikz8D+ahRxZiI0HDZxLADWGsSPqRXKN0GNAiBKbvPtvAbrwslE3pktk/SlU/w== + dependencies: + "@react-aria/ssr" "^3.9.8" + "@react-aria/utils" "^3.28.2" + "@react-stately/disclosure" "^3.0.3" + "@react-types/button" "^3.12.0" + "@swc/helpers" "^0.5.0" + "@react-aria/dnd@^3.8.0", "@react-aria/dnd@^3.9.0": version "3.9.0" resolved "https://registry.yarnpkg.com/@react-aria/dnd/-/dnd-3.9.0.tgz#08761cb010948391c58fdfd4b13e089270261a12" @@ -3112,6 +3525,22 @@ "@react-types/shared" "^3.27.0" "@swc/helpers" "^0.5.0" +"@react-aria/dnd@^3.9.2": + version "3.9.2" + resolved "https://registry.yarnpkg.com/@react-aria/dnd/-/dnd-3.9.2.tgz#1b45989d3e61e5aecc0703931d8715a158aec91b" + integrity sha512-pPYygmJTjSPV2K/r48TvF75WuddG8d8nlIxAXSW22++WKqZ0z+eun6gDUXoKeB2rgY7sVfLqpRdnPV52AnBX+Q== + dependencies: + "@internationalized/string" "^3.2.6" + "@react-aria/i18n" "^3.12.8" + "@react-aria/interactions" "^3.25.0" + "@react-aria/live-announcer" "^3.4.2" + "@react-aria/overlays" "^3.27.0" + "@react-aria/utils" "^3.28.2" + "@react-stately/dnd" "^3.5.3" + "@react-types/button" "^3.12.0" + "@react-types/shared" "^3.29.0" + "@swc/helpers" "^0.5.0" + "@react-aria/focus@^3.19.0", "@react-aria/focus@^3.20.0": version "3.20.0" resolved "https://registry.yarnpkg.com/@react-aria/focus/-/focus-3.20.0.tgz#eb46f9f285c17a5357d09c3ded65aaa6a23e1f6d" @@ -3134,6 +3563,17 @@ "@swc/helpers" "^0.5.0" clsx "^2.0.0" +"@react-aria/focus@^3.20.2": + version "3.20.2" + resolved "https://registry.yarnpkg.com/@react-aria/focus/-/focus-3.20.2.tgz#f20cd830d2536b905169a547228c5d5471a874bc" + integrity sha512-Q3rouk/rzoF/3TuH6FzoAIKrl+kzZi9LHmr8S5EqLAOyP9TXIKG34x2j42dZsAhrw7TbF9gA8tBKwnCNH4ZV+Q== + dependencies: + "@react-aria/interactions" "^3.25.0" + "@react-aria/utils" "^3.28.2" + "@react-types/shared" "^3.29.0" + "@swc/helpers" "^0.5.0" + clsx "^2.0.0" + "@react-aria/form@^3.0.11", "@react-aria/form@^3.0.13": version "3.0.13" resolved "https://registry.yarnpkg.com/@react-aria/form/-/form-3.0.13.tgz#c39cc905fdbc923107b11c12917433aac52ab435" @@ -3156,6 +3596,17 @@ "@react-types/shared" "^3.27.0" "@swc/helpers" "^0.5.0" +"@react-aria/form@^3.0.15": + version "3.0.15" + resolved "https://registry.yarnpkg.com/@react-aria/form/-/form-3.0.15.tgz#eaa46c5bc36314a60da116b11bd334e2cf3fb7ca" + integrity sha512-kk8AnLz+EOgnn3sTaXYmtw+YzVDc1of/+xAkuOupQi6zQFnNRjc99JlDbKHoUZ39urMl+8lsp/1b9VPPhNrBNw== + dependencies: + "@react-aria/interactions" "^3.25.0" + "@react-aria/utils" "^3.28.2" + "@react-stately/form" "^3.1.3" + "@react-types/shared" "^3.29.0" + "@swc/helpers" "^0.5.0" + "@react-aria/grid@^3.11.1": version "3.11.1" resolved "https://registry.yarnpkg.com/@react-aria/grid/-/grid-3.11.1.tgz#51aa217620e811af7df7fef5315df42525bd3b0b" @@ -3194,6 +3645,25 @@ "@react-types/shared" "^3.28.0" "@swc/helpers" "^0.5.0" +"@react-aria/grid@^3.13.0": + version "3.13.0" + resolved "https://registry.yarnpkg.com/@react-aria/grid/-/grid-3.13.0.tgz#d61877ca662c5082cd8d688ab674641db3bfb185" + integrity sha512-RcuJYA4fyJ83MH3SunU+P5BGkx3LJdQ6kxwqwWGIuI9eUKc7uVbqvN9WN3fI+L0QfxqBFmh7ffRxIdQn7puuzw== + dependencies: + "@react-aria/focus" "^3.20.2" + "@react-aria/i18n" "^3.12.8" + "@react-aria/interactions" "^3.25.0" + "@react-aria/live-announcer" "^3.4.2" + "@react-aria/selection" "^3.24.0" + "@react-aria/utils" "^3.28.2" + "@react-stately/collections" "^3.12.3" + "@react-stately/grid" "^3.11.1" + "@react-stately/selection" "^3.20.1" + "@react-types/checkbox" "^3.9.3" + "@react-types/grid" "^3.3.1" + "@react-types/shared" "^3.29.0" + "@swc/helpers" "^0.5.0" + "@react-aria/gridlist@^3.10.0", "@react-aria/gridlist@^3.11.0": version "3.11.0" resolved "https://registry.yarnpkg.com/@react-aria/gridlist/-/gridlist-3.11.0.tgz#2e2043ba23d9f5a8baab52e3552faabcd15b8fa2" @@ -3228,6 +3698,23 @@ "@react-types/shared" "^3.27.0" "@swc/helpers" "^0.5.0" +"@react-aria/gridlist@^3.12.0": + version "3.12.0" + resolved "https://registry.yarnpkg.com/@react-aria/gridlist/-/gridlist-3.12.0.tgz#9ba69d0cf0b5f24ad8a6be28740921f7cd78cbd5" + integrity sha512-KSpnSBYQ7ozGQNaRR2NGq7Fl2zIv5w9KNyO9V/IE2mxUNfX6fwqUPoANFcy9ySosksE7pPnFtuYIB+TQtUjYqQ== + dependencies: + "@react-aria/focus" "^3.20.2" + "@react-aria/grid" "^3.13.0" + "@react-aria/i18n" "^3.12.8" + "@react-aria/interactions" "^3.25.0" + "@react-aria/selection" "^3.24.0" + "@react-aria/utils" "^3.28.2" + "@react-stately/collections" "^3.12.3" + "@react-stately/list" "^3.12.1" + "@react-stately/tree" "^3.8.9" + "@react-types/shared" "^3.29.0" + "@swc/helpers" "^0.5.0" + "@react-aria/i18n@3.12.4": version "3.12.4" resolved "https://registry.yarnpkg.com/@react-aria/i18n/-/i18n-3.12.4.tgz#4520ce48a1b6ebe4aa470d72eba300e65de01814" @@ -3270,6 +3757,20 @@ "@react-types/shared" "^3.27.0" "@swc/helpers" "^0.5.0" +"@react-aria/i18n@^3.12.8": + version "3.12.8" + resolved "https://registry.yarnpkg.com/@react-aria/i18n/-/i18n-3.12.8.tgz#43d534f04d3bfdef674ba94527cf7532875d8fc8" + integrity sha512-V/Nau9WuwTwxfFffQL4URyKyY2HhRlu9zmzkF2Hw/j5KmEQemD+9jfaLueG2CJu85lYL06JrZXUdnhZgKnqMkA== + dependencies: + "@internationalized/date" "^3.8.0" + "@internationalized/message" "^3.1.7" + "@internationalized/number" "^3.6.1" + "@internationalized/string" "^3.2.6" + "@react-aria/ssr" "^3.9.8" + "@react-aria/utils" "^3.28.2" + "@react-types/shared" "^3.29.0" + "@swc/helpers" "^0.5.0" + "@react-aria/interactions@^3.22.5", "@react-aria/interactions@^3.24.0": version "3.24.0" resolved "https://registry.yarnpkg.com/@react-aria/interactions/-/interactions-3.24.0.tgz#5502ff5049578a6ae8cdbc3d96d64fb6ceeef362" @@ -3291,6 +3792,17 @@ "@react-types/shared" "^3.27.0" "@swc/helpers" "^0.5.0" +"@react-aria/interactions@^3.25.0": + version "3.25.0" + resolved "https://registry.yarnpkg.com/@react-aria/interactions/-/interactions-3.25.0.tgz#a57dcec4b8c429756770fbe969263588bb879110" + integrity sha512-GgIsDLlO8rDU/nFn6DfsbP9rfnzhm8QFjZkB9K9+r+MTSCn7bMntiWQgMM+5O6BiA8d7C7x4zuN4bZtc0RBdXQ== + dependencies: + "@react-aria/ssr" "^3.9.8" + "@react-aria/utils" "^3.28.2" + "@react-stately/flags" "^3.1.1" + "@react-types/shared" "^3.29.0" + "@swc/helpers" "^0.5.0" + "@react-aria/label@^3.7.13", "@react-aria/label@^3.7.15": version "3.7.15" resolved "https://registry.yarnpkg.com/@react-aria/label/-/label-3.7.15.tgz#0a343f83730b6dab01b784f6cfa3b124b598d28b" @@ -3309,6 +3821,15 @@ "@react-types/shared" "^3.27.0" "@swc/helpers" "^0.5.0" +"@react-aria/label@^3.7.17": + version "3.7.17" + resolved "https://registry.yarnpkg.com/@react-aria/label/-/label-3.7.17.tgz#288ee245c4caf6bc4dad495f7f994633e0adc122" + integrity sha512-Fz7IC2LQT2Y/sAoV+gFEXoULtkznzmK2MmeTv5shTNjeTxzB1BhQbD4wyCypi7eGsnD/9Zy+8viULCsIUbvjWw== + dependencies: + "@react-aria/utils" "^3.28.2" + "@react-types/shared" "^3.29.0" + "@swc/helpers" "^0.5.0" + "@react-aria/landmark@^3.0.0": version "3.0.0" resolved "https://registry.yarnpkg.com/@react-aria/landmark/-/landmark-3.0.0.tgz#79ffc21d94a2910bec2a26379db65caa1316ac54" @@ -3319,6 +3840,16 @@ "@swc/helpers" "^0.5.0" use-sync-external-store "^1.4.0" +"@react-aria/landmark@^3.0.2": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@react-aria/landmark/-/landmark-3.0.2.tgz#bc79d6f31be313e7741b5fc9451aa0119fd432db" + integrity sha512-KVXa9s3fSgo/PiUjdbnPh3a1yS4t2bMZeVBPPzYAgQ4wcU2WjuLkhviw+5GWSWRfT+jpIMV7R/cmyvr0UHvRfg== + dependencies: + "@react-aria/utils" "^3.28.2" + "@react-types/shared" "^3.29.0" + "@swc/helpers" "^0.5.0" + use-sync-external-store "^1.4.0" + "@react-aria/link@^3.7.7", "@react-aria/link@^3.7.9": version "3.7.9" resolved "https://registry.yarnpkg.com/@react-aria/link/-/link-3.7.9.tgz#cf48a85cd420fd41d8db710f0500f3dd807662e8" @@ -3342,6 +3873,17 @@ "@react-types/shared" "^3.27.0" "@swc/helpers" "^0.5.0" +"@react-aria/link@^3.8.0": + version "3.8.0" + resolved "https://registry.yarnpkg.com/@react-aria/link/-/link-3.8.0.tgz#7067ec4de77c2cae6c820fb84c9aee5eca7059df" + integrity sha512-gpDD6t3FqtFR9QjSIKNpmSR3tS4JG2anVKx2wixuRDHO6Ddexxv4SBzsE1+230p+FlFGjftFa2lEgQ7RNjZrmA== + dependencies: + "@react-aria/interactions" "^3.25.0" + "@react-aria/utils" "^3.28.2" + "@react-types/link" "^3.6.0" + "@react-types/shared" "^3.29.0" + "@swc/helpers" "^0.5.0" + "@react-aria/listbox@^3.13.6", "@react-aria/listbox@^3.14.1": version "3.14.1" resolved "https://registry.yarnpkg.com/@react-aria/listbox/-/listbox-3.14.1.tgz#25256d0fb246e49c7f75a44be4d5d453e18a45ae" @@ -3372,6 +3914,21 @@ "@react-types/shared" "^3.27.0" "@swc/helpers" "^0.5.0" +"@react-aria/listbox@^3.14.3": + version "3.14.3" + resolved "https://registry.yarnpkg.com/@react-aria/listbox/-/listbox-3.14.3.tgz#d8a223b8830fd8cbc762a0fb237da0bfc0a502a2" + integrity sha512-wzelam1KENUvKjsTq8gfrOW2/iab8SyIaSXfFvGmWW82XlDTlW+oQeA39tvOZktMVGspr+xp8FySY09rtz6UXw== + dependencies: + "@react-aria/interactions" "^3.25.0" + "@react-aria/label" "^3.7.17" + "@react-aria/selection" "^3.24.0" + "@react-aria/utils" "^3.28.2" + "@react-stately/collections" "^3.12.3" + "@react-stately/list" "^3.12.1" + "@react-types/listbox" "^3.6.0" + "@react-types/shared" "^3.29.0" + "@swc/helpers" "^0.5.0" + "@react-aria/live-announcer@^3.4.1": version "3.4.1" resolved "https://registry.yarnpkg.com/@react-aria/live-announcer/-/live-announcer-3.4.1.tgz#efedf706b23f6e1b526a3a35c14c202ac3e68487" @@ -3379,6 +3936,13 @@ dependencies: "@swc/helpers" "^0.5.0" +"@react-aria/live-announcer@^3.4.2": + version "3.4.2" + resolved "https://registry.yarnpkg.com/@react-aria/live-announcer/-/live-announcer-3.4.2.tgz#3788b749272a0f2c09196b1a99c8cbdb6172565e" + integrity sha512-6+yNF9ZrZ4YJ60Oxy2gKI4/xy6WUv1iePDCFJkgpNVuOEYi8W8czff8ctXu/RPB25OJx5v2sCw9VirRogTo2zA== + dependencies: + "@swc/helpers" "^0.5.0" + "@react-aria/menu@^3.16.0", "@react-aria/menu@^3.18.0": version "3.18.0" resolved "https://registry.yarnpkg.com/@react-aria/menu/-/menu-3.18.0.tgz#88c55e9a08d6b023f9ec6fa61f7299ac4be0fc73" @@ -3419,6 +3983,26 @@ "@react-types/shared" "^3.27.0" "@swc/helpers" "^0.5.0" +"@react-aria/menu@^3.18.2": + version "3.18.2" + resolved "https://registry.yarnpkg.com/@react-aria/menu/-/menu-3.18.2.tgz#3e0b0db37c1ea3cc2c27b4bb30f8e38cd586a4ad" + integrity sha512-90k+Ke1bhFWhR2zuRI6OwKWQrCpOD99n+9jhG96JZJZlNo5lB+5kS+ufG1LRv5GBnCug0ciLQmPMAfguVsCjEQ== + dependencies: + "@react-aria/focus" "^3.20.2" + "@react-aria/i18n" "^3.12.8" + "@react-aria/interactions" "^3.25.0" + "@react-aria/overlays" "^3.27.0" + "@react-aria/selection" "^3.24.0" + "@react-aria/utils" "^3.28.2" + "@react-stately/collections" "^3.12.3" + "@react-stately/menu" "^3.9.3" + "@react-stately/selection" "^3.20.1" + "@react-stately/tree" "^3.8.9" + "@react-types/button" "^3.12.0" + "@react-types/menu" "^3.10.0" + "@react-types/shared" "^3.29.0" + "@swc/helpers" "^0.5.0" + "@react-aria/meter@^3.4.18", "@react-aria/meter@^3.4.20": version "3.4.20" resolved "https://registry.yarnpkg.com/@react-aria/meter/-/meter-3.4.20.tgz#08cfefd59c0b2746f911a6e2062c4c79af28d8a8" @@ -3439,6 +4023,16 @@ "@react-types/shared" "^3.27.0" "@swc/helpers" "^0.5.0" +"@react-aria/meter@^3.4.22": + version "3.4.22" + resolved "https://registry.yarnpkg.com/@react-aria/meter/-/meter-3.4.22.tgz#25b53b6ee2b8b6aa6336122306cfac8a17ba3d58" + integrity sha512-A/30vrtJO0xqctS/ngE1Lp/w3Aq3MPcpdRHU5E06EUYotzRzHFE9sNmezWslkZ3NfYwA/mxLvgmrsOJSR0Hx6A== + dependencies: + "@react-aria/progress" "^3.4.22" + "@react-types/meter" "^3.4.8" + "@react-types/shared" "^3.29.0" + "@swc/helpers" "^0.5.0" + "@react-aria/numberfield@^3.11.10": version "3.11.10" resolved "https://registry.yarnpkg.com/@react-aria/numberfield/-/numberfield-3.11.10.tgz#ce6b0325c296799ff976a396e733c2ef7c89f784" @@ -3473,6 +4067,23 @@ "@react-types/shared" "^3.28.0" "@swc/helpers" "^0.5.0" +"@react-aria/numberfield@^3.11.13": + version "3.11.13" + resolved "https://registry.yarnpkg.com/@react-aria/numberfield/-/numberfield-3.11.13.tgz#5b48764609f0cb7fa35c41879b48740cf4ebd1bf" + integrity sha512-F73BVdIRV8VvKl0omhGaf0E7mdJ7pdPjDP3wYNf410t55BXPxmndItUKpGfxSbl8k6ZYLvQyOqkD6oWSfZXpZw== + dependencies: + "@react-aria/i18n" "^3.12.8" + "@react-aria/interactions" "^3.25.0" + "@react-aria/spinbutton" "^3.6.14" + "@react-aria/textfield" "^3.17.2" + "@react-aria/utils" "^3.28.2" + "@react-stately/form" "^3.1.3" + "@react-stately/numberfield" "^3.9.11" + "@react-types/button" "^3.12.0" + "@react-types/numberfield" "^3.8.10" + "@react-types/shared" "^3.29.0" + "@swc/helpers" "^0.5.0" + "@react-aria/overlays@^3.24.0", "@react-aria/overlays@^3.26.0": version "3.26.0" resolved "https://registry.yarnpkg.com/@react-aria/overlays/-/overlays-3.26.0.tgz#febaefb56a3d240776a65ae0f31cd63da87ad311" @@ -3507,6 +4118,23 @@ "@react-types/shared" "^3.27.0" "@swc/helpers" "^0.5.0" +"@react-aria/overlays@^3.27.0": + version "3.27.0" + resolved "https://registry.yarnpkg.com/@react-aria/overlays/-/overlays-3.27.0.tgz#08788d80ff5fce428ca2d9856d08602f0c1eeb2a" + integrity sha512-2vZVgL7FrloN5Rh8sAhadGADJbuWg69DdSJB3fd2/h5VvcEhnIfNPu9Ma5XmdkApDoTboIEsKZ4QLYwRl98w6w== + dependencies: + "@react-aria/focus" "^3.20.2" + "@react-aria/i18n" "^3.12.8" + "@react-aria/interactions" "^3.25.0" + "@react-aria/ssr" "^3.9.8" + "@react-aria/utils" "^3.28.2" + "@react-aria/visually-hidden" "^3.8.22" + "@react-stately/overlays" "^3.6.15" + "@react-types/button" "^3.12.0" + "@react-types/overlays" "^3.8.14" + "@react-types/shared" "^3.29.0" + "@swc/helpers" "^0.5.0" + "@react-aria/progress@^3.4.18", "@react-aria/progress@^3.4.20": version "3.4.20" resolved "https://registry.yarnpkg.com/@react-aria/progress/-/progress-3.4.20.tgz#02876e8f0627bc58e802881ddf8712c54ea8638f" @@ -3531,6 +4159,18 @@ "@react-types/shared" "^3.27.0" "@swc/helpers" "^0.5.0" +"@react-aria/progress@^3.4.22": + version "3.4.22" + resolved "https://registry.yarnpkg.com/@react-aria/progress/-/progress-3.4.22.tgz#e65c7c1bbac1be85205e96d5b243e295b16614d4" + integrity sha512-wK2hath4C9HKgmjCH+iSrAs86sUKqqsYKbEKk9/Rj9rzXqHyaEK9EG0YZDnSjd8kX+N9hYcs5MfJl6AZMH4juQ== + dependencies: + "@react-aria/i18n" "^3.12.8" + "@react-aria/label" "^3.7.17" + "@react-aria/utils" "^3.28.2" + "@react-types/progress" "^3.5.11" + "@react-types/shared" "^3.29.0" + "@swc/helpers" "^0.5.0" + "@react-aria/radio@^3.10.10", "@react-aria/radio@^3.11.0": version "3.11.0" resolved "https://registry.yarnpkg.com/@react-aria/radio/-/radio-3.11.0.tgz#f72ce66b9cdffc9a93c48c658f77f9ef6c6c6f3a" @@ -3563,6 +4203,22 @@ "@react-types/shared" "^3.27.0" "@swc/helpers" "^0.5.0" +"@react-aria/radio@^3.11.2": + version "3.11.2" + resolved "https://registry.yarnpkg.com/@react-aria/radio/-/radio-3.11.2.tgz#5bffae601e3c7b25ca8e201491b4db125e005ba9" + integrity sha512-6AFJHXMewJBgHNhqkN1qjgwwx6kmagwYD+3Z+hNK1UHTsKe1Uud5/IF7gPFCqlZeKxA+Lvn9gWiqJrQbtD2+wg== + dependencies: + "@react-aria/focus" "^3.20.2" + "@react-aria/form" "^3.0.15" + "@react-aria/i18n" "^3.12.8" + "@react-aria/interactions" "^3.25.0" + "@react-aria/label" "^3.7.17" + "@react-aria/utils" "^3.28.2" + "@react-stately/radio" "^3.10.12" + "@react-types/radio" "^3.8.8" + "@react-types/shared" "^3.29.0" + "@swc/helpers" "^0.5.0" + "@react-aria/searchfield@^3.7.11", "@react-aria/searchfield@^3.8.1": version "3.8.1" resolved "https://registry.yarnpkg.com/@react-aria/searchfield/-/searchfield-3.8.1.tgz#6915f90249376fe698456394fcf2ce2c2cabb648" @@ -3591,6 +4247,20 @@ "@react-types/shared" "^3.27.0" "@swc/helpers" "^0.5.0" +"@react-aria/searchfield@^3.8.3": + version "3.8.3" + resolved "https://registry.yarnpkg.com/@react-aria/searchfield/-/searchfield-3.8.3.tgz#d34dd617d0d6d6fc059e384979e30d1509e164c1" + integrity sha512-t1DW3nUkPHyZhFhUbT+TdhvI8yZYvUPCuwl0FyraMRCQ4+ww5Ieu4n8JB9IGYmIUB/GWEbZlDHplu4s3efmliA== + dependencies: + "@react-aria/i18n" "^3.12.8" + "@react-aria/textfield" "^3.17.2" + "@react-aria/utils" "^3.28.2" + "@react-stately/searchfield" "^3.5.11" + "@react-types/button" "^3.12.0" + "@react-types/searchfield" "^3.6.1" + "@react-types/shared" "^3.29.0" + "@swc/helpers" "^0.5.0" + "@react-aria/select@^3.15.0", "@react-aria/select@^3.15.2": version "3.15.2" resolved "https://registry.yarnpkg.com/@react-aria/select/-/select-3.15.2.tgz#87ba17618f9ac91db0d1ad1be2c74a18d22a53e5" @@ -3631,6 +4301,26 @@ "@react-types/shared" "^3.27.0" "@swc/helpers" "^0.5.0" +"@react-aria/select@^3.15.4": + version "3.15.4" + resolved "https://registry.yarnpkg.com/@react-aria/select/-/select-3.15.4.tgz#6621441d23624add367b40cd1dfdd4a2a24ce3d8" + integrity sha512-CipqXgdOfWsiHw/chfqd8t9IQpvehP+3uKLJx3ic4Uyj+FT/SxVmmjX0gyvVbZd00ltFCMJYO2xYKQUlbW2AtQ== + dependencies: + "@react-aria/form" "^3.0.15" + "@react-aria/i18n" "^3.12.8" + "@react-aria/interactions" "^3.25.0" + "@react-aria/label" "^3.7.17" + "@react-aria/listbox" "^3.14.3" + "@react-aria/menu" "^3.18.2" + "@react-aria/selection" "^3.24.0" + "@react-aria/utils" "^3.28.2" + "@react-aria/visually-hidden" "^3.8.22" + "@react-stately/select" "^3.6.12" + "@react-types/button" "^3.12.0" + "@react-types/select" "^3.9.11" + "@react-types/shared" "^3.29.0" + "@swc/helpers" "^0.5.0" + "@react-aria/selection@^3.21.0", "@react-aria/selection@^3.23.0": version "3.23.0" resolved "https://registry.yarnpkg.com/@react-aria/selection/-/selection-3.23.0.tgz#1634de20acd65de7b67dbf9a3d1006dd5ce01993" @@ -3657,6 +4347,19 @@ "@react-types/shared" "^3.27.0" "@swc/helpers" "^0.5.0" +"@react-aria/selection@^3.24.0": + version "3.24.0" + resolved "https://registry.yarnpkg.com/@react-aria/selection/-/selection-3.24.0.tgz#b8d93e514bccba0e8c2545564d7eb50023560c88" + integrity sha512-RfGXVc04zz41NVIW89/a3quURZ4LT/GJLkiajQK2VjhisidPdrAWkcfjjWJj0n+tm5gPWbi9Rs5R/Rc8mrvq8Q== + dependencies: + "@react-aria/focus" "^3.20.2" + "@react-aria/i18n" "^3.12.8" + "@react-aria/interactions" "^3.25.0" + "@react-aria/utils" "^3.28.2" + "@react-stately/selection" "^3.20.1" + "@react-types/shared" "^3.29.0" + "@swc/helpers" "^0.5.0" + "@react-aria/separator@^3.4.4", "@react-aria/separator@^3.4.6": version "3.4.6" resolved "https://registry.yarnpkg.com/@react-aria/separator/-/separator-3.4.6.tgz#0d73453ecd0db6c88c9bddf7fc1500571f094bbc" @@ -3675,6 +4378,15 @@ "@react-types/shared" "^3.27.0" "@swc/helpers" "^0.5.0" +"@react-aria/separator@^3.4.8": + version "3.4.8" + resolved "https://registry.yarnpkg.com/@react-aria/separator/-/separator-3.4.8.tgz#385922853411cfae61ad85fd8538932d06f832a5" + integrity sha512-ncuOSTBF/qbNumnW/IRz+xyr+Ud85eCF0Expw4XWhKjAZfzJd86MxPY5ZsxE7pYLOcRWdOSIH1/obwwwSz8ALQ== + dependencies: + "@react-aria/utils" "^3.28.2" + "@react-types/shared" "^3.29.0" + "@swc/helpers" "^0.5.0" + "@react-aria/slider@^3.7.14", "@react-aria/slider@^3.7.16": version "3.7.16" resolved "https://registry.yarnpkg.com/@react-aria/slider/-/slider-3.7.16.tgz#ae9543d6a5bc027bcf05ea48b4910f2bb9ac0d62" @@ -3704,6 +4416,20 @@ "@react-types/slider" "^3.7.8" "@swc/helpers" "^0.5.0" +"@react-aria/slider@^3.7.18": + version "3.7.18" + resolved "https://registry.yarnpkg.com/@react-aria/slider/-/slider-3.7.18.tgz#9aba6bd82b12299b6409672db465fc346b4418f4" + integrity sha512-GBVv5Rpvj/6JH2LnF1zVAhBmxGiuq7R8Ekqyr5kBrCc2ToF3PrTjfGc/mlh0eEtbj+NvAcnlgTx1/qosYt1sGw== + dependencies: + "@react-aria/i18n" "^3.12.8" + "@react-aria/interactions" "^3.25.0" + "@react-aria/label" "^3.7.17" + "@react-aria/utils" "^3.28.2" + "@react-stately/slider" "^3.6.3" + "@react-types/shared" "^3.29.0" + "@react-types/slider" "^3.7.10" + "@swc/helpers" "^0.5.0" + "@react-aria/spinbutton@^3.6.10", "@react-aria/spinbutton@^3.6.12": version "3.6.12" resolved "https://registry.yarnpkg.com/@react-aria/spinbutton/-/spinbutton-3.6.12.tgz#b26e0aecc5fd559a1b3df3041b063cfec245fddc" @@ -3728,6 +4454,18 @@ "@react-types/shared" "^3.27.0" "@swc/helpers" "^0.5.0" +"@react-aria/spinbutton@^3.6.14": + version "3.6.14" + resolved "https://registry.yarnpkg.com/@react-aria/spinbutton/-/spinbutton-3.6.14.tgz#ba0de579975ea1ba4744874bd29274c9f367c70d" + integrity sha512-oSKe9p0Q/7W39eXRnLxlwJG5dQo4ffosRT3u2AtOcFkk2Zzj+tSQFzHQ4202nrWdzRnQ2KLTgUUNnUvXf0BJcg== + dependencies: + "@react-aria/i18n" "^3.12.8" + "@react-aria/live-announcer" "^3.4.2" + "@react-aria/utils" "^3.28.2" + "@react-types/button" "^3.12.0" + "@react-types/shared" "^3.29.0" + "@swc/helpers" "^0.5.0" + "@react-aria/ssr@^3.9.7": version "3.9.7" resolved "https://registry.yarnpkg.com/@react-aria/ssr/-/ssr-3.9.7.tgz#d89d129f7bbc5148657e6c952ac31c9353183770" @@ -3735,6 +4473,13 @@ dependencies: "@swc/helpers" "^0.5.0" +"@react-aria/ssr@^3.9.8": + version "3.9.8" + resolved "https://registry.yarnpkg.com/@react-aria/ssr/-/ssr-3.9.8.tgz#9c06f1860abac629517898c1b5424be5d03bc112" + integrity sha512-lQDE/c9uTfBSDOjaZUJS8xP2jCKVk4zjQeIlCH90xaLhHDgbpCdns3xvFpJJujfj3nI4Ll9K7A+ONUBDCASOuw== + dependencies: + "@swc/helpers" "^0.5.0" + "@react-aria/switch@^3.6.10", "@react-aria/switch@^3.7.0": version "3.7.0" resolved "https://registry.yarnpkg.com/@react-aria/switch/-/switch-3.7.0.tgz#18de5921bcc55c4b1edcfedc91b64b7c8ee5cd3a" @@ -3757,6 +4502,17 @@ "@react-types/switch" "^3.5.8" "@swc/helpers" "^0.5.0" +"@react-aria/switch@^3.7.2": + version "3.7.2" + resolved "https://registry.yarnpkg.com/@react-aria/switch/-/switch-3.7.2.tgz#5c27500b29d161aed996de75acbd0ca42bce00e8" + integrity sha512-vaREbp1gFjv+jEMXoXpNK7JYFO/jhwnSYAwEINNWnwf54IGeHvTPaB2NwolYSFvP4HAj8TKYbGFUSz7RKLhLgw== + dependencies: + "@react-aria/toggle" "^3.11.2" + "@react-stately/toggle" "^3.8.3" + "@react-types/shared" "^3.29.0" + "@react-types/switch" "^3.5.10" + "@swc/helpers" "^0.5.0" + "@react-aria/table@^3.16.0", "@react-aria/table@^3.17.0": version "3.17.0" resolved "https://registry.yarnpkg.com/@react-aria/table/-/table-3.17.0.tgz#2ad67e363cd499b112be55d215d914d73f8c9569" @@ -3799,6 +4555,27 @@ "@react-types/table" "^3.10.4" "@swc/helpers" "^0.5.0" +"@react-aria/table@^3.17.2": + version "3.17.2" + resolved "https://registry.yarnpkg.com/@react-aria/table/-/table-3.17.2.tgz#447dc14c2ebf9841a532182bacbdbd7cd2c983f8" + integrity sha512-wsF3JqiAKcol1sfeNqTxyzH6+nxu0sAfyuh+XQfp1tvSGx15NifYeNKovNX4EPpUVkAI7jL5Le+eYeYYGELfnw== + dependencies: + "@react-aria/focus" "^3.20.2" + "@react-aria/grid" "^3.13.0" + "@react-aria/i18n" "^3.12.8" + "@react-aria/interactions" "^3.25.0" + "@react-aria/live-announcer" "^3.4.2" + "@react-aria/utils" "^3.28.2" + "@react-aria/visually-hidden" "^3.8.22" + "@react-stately/collections" "^3.12.3" + "@react-stately/flags" "^3.1.1" + "@react-stately/table" "^3.14.1" + "@react-types/checkbox" "^3.9.3" + "@react-types/grid" "^3.3.1" + "@react-types/shared" "^3.29.0" + "@react-types/table" "^3.12.0" + "@swc/helpers" "^0.5.0" + "@react-aria/tabs@^3.10.0", "@react-aria/tabs@^3.9.8": version "3.10.0" resolved "https://registry.yarnpkg.com/@react-aria/tabs/-/tabs-3.10.0.tgz#be09af509d1a83a4e3fcd866ea12ca874b86507b" @@ -3813,6 +4590,20 @@ "@react-types/tabs" "^3.3.13" "@swc/helpers" "^0.5.0" +"@react-aria/tabs@^3.10.2": + version "3.10.2" + resolved "https://registry.yarnpkg.com/@react-aria/tabs/-/tabs-3.10.2.tgz#ea81b9c68963f8016343daec77832be1be6a0129" + integrity sha512-rpEgh//Gnew3le49tQVFOQ6ZyacJdaNUDXHt0ocguXb+2UrKtH54M8oIAE7E8KaB1puQlFXRs+Rjlr1rOlmjEQ== + dependencies: + "@react-aria/focus" "^3.20.2" + "@react-aria/i18n" "^3.12.8" + "@react-aria/selection" "^3.24.0" + "@react-aria/utils" "^3.28.2" + "@react-stately/tabs" "^3.8.1" + "@react-types/shared" "^3.29.0" + "@react-types/tabs" "^3.3.14" + "@swc/helpers" "^0.5.0" + "@react-aria/tabs@^3.9.9": version "3.9.9" resolved "https://registry.yarnpkg.com/@react-aria/tabs/-/tabs-3.9.9.tgz#71d35657062bbfd9d2d31ecedeaf24980e6207c7" @@ -3859,6 +4650,22 @@ "@react-types/shared" "^3.27.0" "@swc/helpers" "^0.5.0" +"@react-aria/tag@^3.5.2": + version "3.5.2" + resolved "https://registry.yarnpkg.com/@react-aria/tag/-/tag-3.5.2.tgz#12ec45e7e147658ceb885b047d1ec1a2861fd5a8" + integrity sha512-xZ5Df0x+xcDg6UTDvnjP4pu+XrmYVaYcqzF7RGoCD1KyRCHU5Czg9p+888NB0K+vnJHfNsQh6rmMhDUydXu9eg== + dependencies: + "@react-aria/gridlist" "^3.12.0" + "@react-aria/i18n" "^3.12.8" + "@react-aria/interactions" "^3.25.0" + "@react-aria/label" "^3.7.17" + "@react-aria/selection" "^3.24.0" + "@react-aria/utils" "^3.28.2" + "@react-stately/list" "^3.12.1" + "@react-types/button" "^3.12.0" + "@react-types/shared" "^3.29.0" + "@swc/helpers" "^0.5.0" + "@react-aria/textfield@^3.15.0", "@react-aria/textfield@^3.17.0": version "3.17.0" resolved "https://registry.yarnpkg.com/@react-aria/textfield/-/textfield-3.17.0.tgz#a0fac5887ec9bec0a00a2c9401efd885dbe611f8" @@ -3889,6 +4696,21 @@ "@react-types/textfield" "^3.11.0" "@swc/helpers" "^0.5.0" +"@react-aria/textfield@^3.17.2": + version "3.17.2" + resolved "https://registry.yarnpkg.com/@react-aria/textfield/-/textfield-3.17.2.tgz#cf8c00e2aecaf461263a73eb476a0b518b1f74b8" + integrity sha512-4KINB0HueYUHUgvi/ThTP27hu4Mv5ujG55pH3dmSRD4Olu/MRy1m/Psq72o8LTf4bTOM9ZP1rKccUg6xfaMidA== + dependencies: + "@react-aria/form" "^3.0.15" + "@react-aria/interactions" "^3.25.0" + "@react-aria/label" "^3.7.17" + "@react-aria/utils" "^3.28.2" + "@react-stately/form" "^3.1.3" + "@react-stately/utils" "^3.10.6" + "@react-types/shared" "^3.29.0" + "@react-types/textfield" "^3.12.1" + "@swc/helpers" "^0.5.0" + "@react-aria/toast@^3.0.0": version "3.0.0" resolved "https://registry.yarnpkg.com/@react-aria/toast/-/toast-3.0.0.tgz#41b32263104e60f8f75922cf84f72498c931e622" @@ -3903,6 +4725,20 @@ "@react-types/shared" "^3.28.0" "@swc/helpers" "^0.5.0" +"@react-aria/toast@^3.0.2": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@react-aria/toast/-/toast-3.0.2.tgz#c92dae0c7044ae791027d85d76559619dd38f7aa" + integrity sha512-iaiHDE1CKYM3BbNEp3A2Ed8YAlpXUGyY6vesKISdHEZ2lJ7r+1hbcFoTNdG8HfbB8Lz5vw8Wd2o+ZmQ2tnDY9Q== + dependencies: + "@react-aria/i18n" "^3.12.8" + "@react-aria/interactions" "^3.25.0" + "@react-aria/landmark" "^3.0.2" + "@react-aria/utils" "^3.28.2" + "@react-stately/toast" "^3.1.0" + "@react-types/button" "^3.12.0" + "@react-types/shared" "^3.29.0" + "@swc/helpers" "^0.5.0" + "@react-aria/toggle@^3.10.11": version "3.10.11" resolved "https://registry.yarnpkg.com/@react-aria/toggle/-/toggle-3.10.11.tgz#7873648bc83041570d149c234c531639f5346168" @@ -3928,6 +4764,18 @@ "@react-types/shared" "^3.28.0" "@swc/helpers" "^0.5.0" +"@react-aria/toggle@^3.11.2": + version "3.11.2" + resolved "https://registry.yarnpkg.com/@react-aria/toggle/-/toggle-3.11.2.tgz#ebfe73d07f13fc46421abc8d7f7d56a707f81b2f" + integrity sha512-JOg8yYYCjLDnEpuggPo9GyXFaT/B238d3R8i/xQ6KLelpi3fXdJuZlFD6n9NQp3DJbE8Wj+wM5/VFFAi3cISpw== + dependencies: + "@react-aria/interactions" "^3.25.0" + "@react-aria/utils" "^3.28.2" + "@react-stately/toggle" "^3.8.3" + "@react-types/checkbox" "^3.9.3" + "@react-types/shared" "^3.29.0" + "@swc/helpers" "^0.5.0" + "@react-aria/toolbar@3.0.0-beta.11": version "3.0.0-beta.11" resolved "https://registry.yarnpkg.com/@react-aria/toolbar/-/toolbar-3.0.0-beta.11.tgz#019c9ff2a47ad207504a95afeb0f863cf71a114b" @@ -3961,6 +4809,17 @@ "@react-types/shared" "^3.28.0" "@swc/helpers" "^0.5.0" +"@react-aria/toolbar@3.0.0-beta.15": + version "3.0.0-beta.15" + resolved "https://registry.yarnpkg.com/@react-aria/toolbar/-/toolbar-3.0.0-beta.15.tgz#2b85e9a1f3e9185447e7164736cab7a859ed5f25" + integrity sha512-PNGpNIKIsCW8rxI9XXSADlLrSpikILJKKECyTRw9KwvXDRc44pezvdjGHCNinQcKsQoy5BtkK5cTSAyVqzzTXQ== + dependencies: + "@react-aria/focus" "^3.20.2" + "@react-aria/i18n" "^3.12.8" + "@react-aria/utils" "^3.28.2" + "@react-types/shared" "^3.29.0" + "@swc/helpers" "^0.5.0" + "@react-aria/tooltip@^3.7.10", "@react-aria/tooltip@^3.8.0": version "3.8.0" resolved "https://registry.yarnpkg.com/@react-aria/tooltip/-/tooltip-3.8.0.tgz#fa4b639a28d6ac567fb2150476ed867abdc9dc4a" @@ -3986,6 +4845,18 @@ "@react-types/tooltip" "^3.4.14" "@swc/helpers" "^0.5.0" +"@react-aria/tooltip@^3.8.2": + version "3.8.2" + resolved "https://registry.yarnpkg.com/@react-aria/tooltip/-/tooltip-3.8.2.tgz#b19be87d6472719b9c55ed4be57948f952e9e4de" + integrity sha512-ctVTgh1LXvmr1ve3ehAWfvlJR7nHYZeqhl/g1qnA+983LQtc1IF9MraCs92g0m7KpBwCihuA+aYwTPsUHfKfXg== + dependencies: + "@react-aria/interactions" "^3.25.0" + "@react-aria/utils" "^3.28.2" + "@react-stately/tooltip" "^3.5.3" + "@react-types/shared" "^3.29.0" + "@react-types/tooltip" "^3.4.16" + "@swc/helpers" "^0.5.0" + "@react-aria/tree@3.0.0-beta.2": version "3.0.0-beta.2" resolved "https://registry.yarnpkg.com/@react-aria/tree/-/tree-3.0.0-beta.2.tgz#f4edf593e0a5acbc19f2a17d2d78fb0633a105e5" @@ -4028,6 +4899,20 @@ "@react-types/shared" "^3.28.0" "@swc/helpers" "^0.5.0" +"@react-aria/tree@^3.0.2": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@react-aria/tree/-/tree-3.0.2.tgz#a4a98d9077325f4a4c9567d6762ffb086786603c" + integrity sha512-gr06Y1760+kdlDeUcGNR+PCuJMtlrdtNMGG1Z0fSygy8y7/zVdTOLQp0c1Q3pjL2nr7Unjz/H1xSgERParHsbg== + dependencies: + "@react-aria/gridlist" "^3.12.0" + "@react-aria/i18n" "^3.12.8" + "@react-aria/selection" "^3.24.0" + "@react-aria/utils" "^3.28.2" + "@react-stately/tree" "^3.8.9" + "@react-types/button" "^3.12.0" + "@react-types/shared" "^3.29.0" + "@swc/helpers" "^0.5.0" + "@react-aria/utils@^3.26.0", "@react-aria/utils@^3.28.0": version "3.28.0" resolved "https://registry.yarnpkg.com/@react-aria/utils/-/utils-3.28.0.tgz#8b524815bb368c16efa1aba04a5d92b7014624ee" @@ -4051,6 +4936,18 @@ "@swc/helpers" "^0.5.0" clsx "^2.0.0" +"@react-aria/utils@^3.28.2": + version "3.28.2" + resolved "https://registry.yarnpkg.com/@react-aria/utils/-/utils-3.28.2.tgz#f698bc54b2cb506c2f81d1ce92543ae39aae3968" + integrity sha512-J8CcLbvnQgiBn54eeEvQQbIOfBF3A1QizxMw9P4cl9MkeR03ug7RnjTIdJY/n2p7t59kLeAB3tqiczhcj+Oi5w== + dependencies: + "@react-aria/ssr" "^3.9.8" + "@react-stately/flags" "^3.1.1" + "@react-stately/utils" "^3.10.6" + "@react-types/shared" "^3.29.0" + "@swc/helpers" "^0.5.0" + clsx "^2.0.0" + "@react-aria/virtualizer@^4.1.0": version "4.1.2" resolved "https://registry.yarnpkg.com/@react-aria/virtualizer/-/virtualizer-4.1.2.tgz#65971240d502a86a1491fe22ea00020d076f126a" @@ -4075,6 +4972,18 @@ "@react-types/shared" "^3.27.0" "@swc/helpers" "^0.5.0" +"@react-aria/virtualizer@^4.1.4": + version "4.1.4" + resolved "https://registry.yarnpkg.com/@react-aria/virtualizer/-/virtualizer-4.1.4.tgz#3860a941b88686246f153a2824b52040d97e563d" + integrity sha512-SBKD2K+kBc3aLMVEqnBXjpqLhUSyvoi1ubSgUS5KMIqgyn44OWn5zKTsj9SIPZot6buSlgV2700TIWDhEJzWlw== + dependencies: + "@react-aria/i18n" "^3.12.8" + "@react-aria/interactions" "^3.25.0" + "@react-aria/utils" "^3.28.2" + "@react-stately/virtualizer" "^4.3.2" + "@react-types/shared" "^3.29.0" + "@swc/helpers" "^0.5.0" + "@react-aria/visually-hidden@^3.8.18", "@react-aria/visually-hidden@^3.8.20": version "3.8.20" resolved "https://registry.yarnpkg.com/@react-aria/visually-hidden/-/visually-hidden-3.8.20.tgz#67554c778642a22cadec1af4c8115d12ba5a6e07" @@ -4095,6 +5004,16 @@ "@react-types/shared" "^3.27.0" "@swc/helpers" "^0.5.0" +"@react-aria/visually-hidden@^3.8.22": + version "3.8.22" + resolved "https://registry.yarnpkg.com/@react-aria/visually-hidden/-/visually-hidden-3.8.22.tgz#949771f98717db7d1e9d3362341d155fb1e9668d" + integrity sha512-EO3R8YTKZ7HkLl9k1Y2uBKYBgpJagth4/4W7mfpJZE24A3fQnCP8zx1sweXiAm0mirR4J6tNaK7Ia8ssP5TpOw== + dependencies: + "@react-aria/interactions" "^3.25.0" + "@react-aria/utils" "^3.28.2" + "@react-types/shared" "^3.29.0" + "@swc/helpers" "^0.5.0" + "@react-dnd/asap@^4.0.0": version "4.0.1" resolved "https://registry.yarnpkg.com/@react-dnd/asap/-/asap-4.0.1.tgz#5291850a6b58ce6f2da25352a64f1b0674871aab" @@ -4257,6 +5176,14 @@ "@react-stately/utils" "^3.10.4" "@swc/helpers" "^0.5.0" +"@react-stately/autocomplete@3.0.0-beta.1": + version "3.0.0-beta.1" + resolved "https://registry.yarnpkg.com/@react-stately/autocomplete/-/autocomplete-3.0.0-beta.1.tgz#2e6ab2ea9702523bf6e9a8fb95ec4b79cb1993bc" + integrity sha512-ohs6QOtJouQ+Y1+zRKiCzv57QogSTRuOA1QfrnIS1YPwKO1EDQXSqFkq2htK5+bN9GCm94yo6r4iX++SZKmLXA== + dependencies: + "@react-stately/utils" "^3.10.6" + "@swc/helpers" "^0.5.0" + "@react-stately/calendar@3.6.0": version "3.6.0" resolved "https://registry.yarnpkg.com/@react-stately/calendar/-/calendar-3.6.0.tgz#c770890160c33826206a015eb7da32fe8ece81d5" @@ -4290,6 +5217,17 @@ "@react-types/shared" "^3.27.0" "@swc/helpers" "^0.5.0" +"@react-stately/calendar@^3.8.0": + version "3.8.0" + resolved "https://registry.yarnpkg.com/@react-stately/calendar/-/calendar-3.8.0.tgz#c8b051ef97d940eb4c1b4ac140a48b71868b628f" + integrity sha512-YAuJiR9EtVThX91gU2ay/6YgPe0LvZWEssu4BS0Atnwk5cAo32gvF5FMta9ztH1LIULdZFaypU/C1mvnayMf+Q== + dependencies: + "@internationalized/date" "^3.8.0" + "@react-stately/utils" "^3.10.6" + "@react-types/calendar" "^3.7.0" + "@react-types/shared" "^3.29.0" + "@swc/helpers" "^0.5.0" + "@react-stately/checkbox@^3.6.10", "@react-stately/checkbox@^3.6.12": version "3.6.12" resolved "https://registry.yarnpkg.com/@react-stately/checkbox/-/checkbox-3.6.12.tgz#bc1745ed078c2fabb42551f7dc17b0601c04112f" @@ -4312,6 +5250,17 @@ "@react-types/shared" "^3.27.0" "@swc/helpers" "^0.5.0" +"@react-stately/checkbox@^3.6.13": + version "3.6.13" + resolved "https://registry.yarnpkg.com/@react-stately/checkbox/-/checkbox-3.6.13.tgz#7229a286b7f0af3154ca537a46cebd89c59c1460" + integrity sha512-b8+bkOhobzuJ5bAA16JpYg1tM973eNXD3U4h/8+dckLndKHRjIwPvrL25tzKN7NcQp2LKVCauFesgI+Z+/2FJg== + dependencies: + "@react-stately/form" "^3.1.3" + "@react-stately/utils" "^3.10.6" + "@react-types/checkbox" "^3.9.3" + "@react-types/shared" "^3.29.0" + "@swc/helpers" "^0.5.0" + "@react-stately/collections@^3.12.0", "@react-stately/collections@^3.12.2": version "3.12.2" resolved "https://registry.yarnpkg.com/@react-stately/collections/-/collections-3.12.2.tgz#95cce481bd6ff69aa4694a8b47015360dc4de84e" @@ -4328,6 +5277,14 @@ "@react-types/shared" "^3.27.0" "@swc/helpers" "^0.5.0" +"@react-stately/collections@^3.12.3": + version "3.12.3" + resolved "https://registry.yarnpkg.com/@react-stately/collections/-/collections-3.12.3.tgz#2bdaea476068dcc44c8b62f1cac28f20f52df097" + integrity sha512-QfSBME2QWDjUw/RmmUjrYl/j1iCYcYCIDsgZda1OeRtt63R11k0aqmmwrDRwCsA+Sv+D5QgkOp4KK+CokTzoVQ== + dependencies: + "@react-types/shared" "^3.29.0" + "@swc/helpers" "^0.5.0" + "@react-stately/color@^3.8.1", "@react-stately/color@^3.8.3": version "3.8.3" resolved "https://registry.yarnpkg.com/@react-stately/color/-/color-3.8.3.tgz#cf9c15fc2641319d8b820f7d8aded001fee0ce15" @@ -4358,6 +5315,21 @@ "@react-types/shared" "^3.27.0" "@swc/helpers" "^0.5.0" +"@react-stately/color@^3.8.4": + version "3.8.4" + resolved "https://registry.yarnpkg.com/@react-stately/color/-/color-3.8.4.tgz#8d5436eb2322221d9e20087662ca66dc7632fbf4" + integrity sha512-LXmfnJPWnL5q1/Z8Pn2d+9efrClLWCiK6c3IGXN8ZWcdR/cMJ/w9SY9f7evyXvmeUmdU1FTGgoSVqGfup3tSyA== + dependencies: + "@internationalized/number" "^3.6.1" + "@internationalized/string" "^3.2.6" + "@react-stately/form" "^3.1.3" + "@react-stately/numberfield" "^3.9.11" + "@react-stately/slider" "^3.6.3" + "@react-stately/utils" "^3.10.6" + "@react-types/color" "^3.0.4" + "@react-types/shared" "^3.29.0" + "@swc/helpers" "^0.5.0" + "@react-stately/combobox@^3.10.1", "@react-stately/combobox@^3.10.3": version "3.10.3" resolved "https://registry.yarnpkg.com/@react-stately/combobox/-/combobox-3.10.3.tgz#9e6cad7697a8e64e80aa084460f4f15a27f2a85d" @@ -4388,6 +5360,21 @@ "@react-types/shared" "^3.27.0" "@swc/helpers" "^0.5.0" +"@react-stately/combobox@^3.10.4": + version "3.10.4" + resolved "https://registry.yarnpkg.com/@react-stately/combobox/-/combobox-3.10.4.tgz#15d36405b9711ba0536b0de012413b11d45c143f" + integrity sha512-sgujLhukIGKskLDrOL4SAbO7WOgLsD7gSdjRQZ0f/e8bWMmUOWEp22T+X1hMMcuVRkRdXlEF1kH2/E6BVanXYw== + dependencies: + "@react-stately/collections" "^3.12.3" + "@react-stately/form" "^3.1.3" + "@react-stately/list" "^3.12.1" + "@react-stately/overlays" "^3.6.15" + "@react-stately/select" "^3.6.12" + "@react-stately/utils" "^3.10.6" + "@react-types/combobox" "^3.13.4" + "@react-types/shared" "^3.29.0" + "@swc/helpers" "^0.5.0" + "@react-stately/data@^3.12.0", "@react-stately/data@^3.12.2": version "3.12.2" resolved "https://registry.yarnpkg.com/@react-stately/data/-/data-3.12.2.tgz#c155b87e1030c56b742520a9a3d38d2f002bfc84" @@ -4404,6 +5391,14 @@ "@react-types/shared" "^3.27.0" "@swc/helpers" "^0.5.0" +"@react-stately/data@^3.12.3": + version "3.12.3" + resolved "https://registry.yarnpkg.com/@react-stately/data/-/data-3.12.3.tgz#0f26b5658b49f1f3d1d478f36167e3a80abf62e3" + integrity sha512-JYPNV1gd9OZm8xPay0exx5okFNgiwESNvdBHsfDC+f8BifRyFLdrvoaUGF0enKIeSQMB1oReFAxTAXtDZd27rA== + dependencies: + "@react-types/shared" "^3.29.0" + "@swc/helpers" "^0.5.0" + "@react-stately/datepicker@3.11.0": version "3.11.0" resolved "https://registry.yarnpkg.com/@react-stately/datepicker/-/datepicker-3.11.0.tgz#5f4daff449f756dc40b4201ae337dd4a3f29facc" @@ -4446,6 +5441,20 @@ "@react-types/shared" "^3.27.0" "@swc/helpers" "^0.5.0" +"@react-stately/datepicker@^3.14.0": + version "3.14.0" + resolved "https://registry.yarnpkg.com/@react-stately/datepicker/-/datepicker-3.14.0.tgz#5f7e282d56e038ac0ef1b620fb9c1ff86253af57" + integrity sha512-JSkQfKW0+WpPQyOOeRPBLwXkVfpTUwgZJDnHBCud5kEuQiFFyeAIbL57RNXc4AX2pzY3piQa6OHnjDGTfqClxQ== + dependencies: + "@internationalized/date" "^3.8.0" + "@internationalized/string" "^3.2.6" + "@react-stately/form" "^3.1.3" + "@react-stately/overlays" "^3.6.15" + "@react-stately/utils" "^3.10.6" + "@react-types/datepicker" "^3.12.0" + "@react-types/shared" "^3.29.0" + "@swc/helpers" "^0.5.0" + "@react-stately/disclosure@^3.0.0", "@react-stately/disclosure@^3.0.2": version "3.0.2" resolved "https://registry.yarnpkg.com/@react-stately/disclosure/-/disclosure-3.0.2.tgz#5add41dd7d013327137e6920eff7968e871fb349" @@ -4464,6 +5473,15 @@ "@react-types/shared" "^3.27.0" "@swc/helpers" "^0.5.0" +"@react-stately/disclosure@^3.0.3": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@react-stately/disclosure/-/disclosure-3.0.3.tgz#abf55875ef2e4118e516219d5652918f6fbd9eac" + integrity sha512-4kB+WDXVcrxCmJ+X6c23wa5Ax5dPSpm6Ef8DktLrLcUfJyfr+SWs5/IfkrYG0sOl3/u5OwyWe1pq3hDpzyDlLA== + dependencies: + "@react-stately/utils" "^3.10.6" + "@react-types/shared" "^3.29.0" + "@swc/helpers" "^0.5.0" + "@react-stately/dnd@^3.5.0", "@react-stately/dnd@^3.5.2": version "3.5.2" resolved "https://registry.yarnpkg.com/@react-stately/dnd/-/dnd-3.5.2.tgz#457ecae7c4633548a49f8f3823cb5649785c31e7" @@ -4482,6 +5500,15 @@ "@react-types/shared" "^3.27.0" "@swc/helpers" "^0.5.0" +"@react-stately/dnd@^3.5.3": + version "3.5.3" + resolved "https://registry.yarnpkg.com/@react-stately/dnd/-/dnd-3.5.3.tgz#4a97c8041bac9411270692e43fe08eb2b311b79f" + integrity sha512-e4IodPF7fv9hR6jqSjiyrrFQ/6NbHNM5Ft1MJzCu6tJHvT+sl6qxIP5A+XR3wkjMpi4QW2WhVUmoFNbS/6ZAug== + dependencies: + "@react-stately/selection" "^3.20.1" + "@react-types/shared" "^3.29.0" + "@swc/helpers" "^0.5.0" + "@react-stately/flags@^3.0.5": version "3.0.5" resolved "https://registry.yarnpkg.com/@react-stately/flags/-/flags-3.0.5.tgz#b35bcbd3b80c4f821e23e9c649566a4af11e97bf" @@ -4496,6 +5523,13 @@ dependencies: "@swc/helpers" "^0.5.0" +"@react-stately/flags@^3.1.1": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@react-stately/flags/-/flags-3.1.1.tgz#c47d540c4196798f4cc0ee83f844099b4d57b876" + integrity sha512-XPR5gi5LfrPdhxZzdIlJDz/B5cBf63l4q6/AzNqVWFKgd0QqY5LvWJftXkklaIUpKSJkIKQb8dphuZXDtkWNqg== + dependencies: + "@swc/helpers" "^0.5.0" + "@react-stately/form@^3.1.0", "@react-stately/form@^3.1.2": version "3.1.2" resolved "https://registry.yarnpkg.com/@react-stately/form/-/form-3.1.2.tgz#eb1ca5f782a8cf1f36834e5455ee15b35c945348" @@ -4512,6 +5546,14 @@ "@react-types/shared" "^3.27.0" "@swc/helpers" "^0.5.0" +"@react-stately/form@^3.1.3": + version "3.1.3" + resolved "https://registry.yarnpkg.com/@react-stately/form/-/form-3.1.3.tgz#79d7bdef5a86540511294db9f74fb151a82456a9" + integrity sha512-Jisgm0facSS3sAzHfSgshoCo3LxfO0wmQj98MOBCGXyVL+MSwx2ilb38eXIyBCzHJzJnPRTLaK/E4T49aph47A== + dependencies: + "@react-types/shared" "^3.29.0" + "@swc/helpers" "^0.5.0" + "@react-stately/grid@^3.10.1": version "3.10.1" resolved "https://registry.yarnpkg.com/@react-stately/grid/-/grid-3.10.1.tgz#2d13d30950a5ae83e15f266ccad710b4dad4a6c5" @@ -4534,6 +5576,17 @@ "@react-types/shared" "^3.28.0" "@swc/helpers" "^0.5.0" +"@react-stately/grid@^3.11.1": + version "3.11.1" + resolved "https://registry.yarnpkg.com/@react-stately/grid/-/grid-3.11.1.tgz#ff704976ff552cb99f25c2a7286c531018494bee" + integrity sha512-xMk2YsaIKkF8dInRLUFpUXBIqnYt88hehhq2nb65RFgsFFhngE/OkaFudSUzaYPc1KvHpW+oHqvseC+G1iDG2w== + dependencies: + "@react-stately/collections" "^3.12.3" + "@react-stately/selection" "^3.20.1" + "@react-types/grid" "^3.3.1" + "@react-types/shared" "^3.29.0" + "@swc/helpers" "^0.5.0" + "@react-stately/layout@^4.1.0": version "4.2.0" resolved "https://registry.yarnpkg.com/@react-stately/layout/-/layout-4.2.0.tgz#04442c189e66755c0225de31c240f85fcd46f0bd" @@ -4560,6 +5613,19 @@ "@react-types/table" "^3.10.4" "@swc/helpers" "^0.5.0" +"@react-stately/layout@^4.2.2": + version "4.2.2" + resolved "https://registry.yarnpkg.com/@react-stately/layout/-/layout-4.2.2.tgz#1e9cef07ee4ac662d7bb4bf1c5a847b532514273" + integrity sha512-cKojNZteaVPtJrEePoNmKOgua4LYhholsthaEpD7ldKcOacl9VsvBbaowv945HEDKj6A919YoXOLdgy5qzoPtw== + dependencies: + "@react-stately/collections" "^3.12.3" + "@react-stately/table" "^3.14.1" + "@react-stately/virtualizer" "^4.3.2" + "@react-types/grid" "^3.3.1" + "@react-types/shared" "^3.29.0" + "@react-types/table" "^3.12.0" + "@swc/helpers" "^0.5.0" + "@react-stately/list@^3.11.1", "@react-stately/list@^3.12.0": version "3.12.0" resolved "https://registry.yarnpkg.com/@react-stately/list/-/list-3.12.0.tgz#e7476a6ccba9509804bef6557a566355eb6b4daf" @@ -4582,6 +5648,17 @@ "@react-types/shared" "^3.27.0" "@swc/helpers" "^0.5.0" +"@react-stately/list@^3.12.1": + version "3.12.1" + resolved "https://registry.yarnpkg.com/@react-stately/list/-/list-3.12.1.tgz#b439faa41a1fca08367c24b0925e3060d5037ecd" + integrity sha512-N+YCInNZ2OpY0WUNvJWUTyFHtzE5yBtZ9DI4EHJDvm61+jmZ2s3HszOfa7j+7VOKq78VW3m5laqsQNWvMrLFrQ== + dependencies: + "@react-stately/collections" "^3.12.3" + "@react-stately/selection" "^3.20.1" + "@react-stately/utils" "^3.10.6" + "@react-types/shared" "^3.29.0" + "@swc/helpers" "^0.5.0" + "@react-stately/menu@^3.9.0", "@react-stately/menu@^3.9.2": version "3.9.2" resolved "https://registry.yarnpkg.com/@react-stately/menu/-/menu-3.9.2.tgz#59dcb8958b519a64630625b06579ff5cae60bb97" @@ -4602,6 +5679,16 @@ "@react-types/shared" "^3.27.0" "@swc/helpers" "^0.5.0" +"@react-stately/menu@^3.9.3": + version "3.9.3" + resolved "https://registry.yarnpkg.com/@react-stately/menu/-/menu-3.9.3.tgz#b768dd9d4b7e047893aab5365dd5c3f335767ad9" + integrity sha512-9x1sTX3Xq2Q3mJUHV+YN9MR36qNzgn8eBSLa40eaFDaOOtoJ+V10m7OriUfpjey7WzLBpq00Sfda54/PbQHZ0g== + dependencies: + "@react-stately/overlays" "^3.6.15" + "@react-types/menu" "^3.10.0" + "@react-types/shared" "^3.29.0" + "@swc/helpers" "^0.5.0" + "@react-stately/numberfield@^3.9.10", "@react-stately/numberfield@^3.9.8": version "3.9.10" resolved "https://registry.yarnpkg.com/@react-stately/numberfield/-/numberfield-3.9.10.tgz#9b1aa5d80e031d1aa7a74c24a55194635c9e5d9e" @@ -4613,6 +5700,17 @@ "@react-types/numberfield" "^3.8.9" "@swc/helpers" "^0.5.0" +"@react-stately/numberfield@^3.9.11": + version "3.9.11" + resolved "https://registry.yarnpkg.com/@react-stately/numberfield/-/numberfield-3.9.11.tgz#2805ac70bf7d95f6c5b2d9c468ee86c8ea0a4b2d" + integrity sha512-gAFSZIHnZsgIWVPgGRUUpfW6zM7TCV5oS1SCY90ay5nrS7JCXurQbMrWJLOWHTdM5iSeYMgoyt68OK5KD0KHMw== + dependencies: + "@internationalized/number" "^3.6.1" + "@react-stately/form" "^3.1.3" + "@react-stately/utils" "^3.10.6" + "@react-types/numberfield" "^3.8.10" + "@swc/helpers" "^0.5.0" + "@react-stately/numberfield@^3.9.9": version "3.9.9" resolved "https://registry.yarnpkg.com/@react-stately/numberfield/-/numberfield-3.9.9.tgz#a7d2d756aee8dd2df0eb1b0c1ab657148de4a439" @@ -4642,6 +5740,15 @@ "@react-types/overlays" "^3.8.12" "@swc/helpers" "^0.5.0" +"@react-stately/overlays@^3.6.15": + version "3.6.15" + resolved "https://registry.yarnpkg.com/@react-stately/overlays/-/overlays-3.6.15.tgz#5eae748a58e182200b8f84893ab693b21e7231e6" + integrity sha512-LBaGpXuI+SSd5HSGzyGJA0Gy09V2tl2G/r0lllTYqwt0RDZR6p7IrhdGVXZm6vI0oWEnih7yLC32krkVQrffgQ== + dependencies: + "@react-stately/utils" "^3.10.6" + "@react-types/overlays" "^3.8.14" + "@swc/helpers" "^0.5.0" + "@react-stately/radio@^3.10.10": version "3.10.10" resolved "https://registry.yarnpkg.com/@react-stately/radio/-/radio-3.10.10.tgz#1507265e66ce2d200f0d2127f1659ba0d7f53fba" @@ -4664,6 +5771,17 @@ "@react-types/shared" "^3.28.0" "@swc/helpers" "^0.5.0" +"@react-stately/radio@^3.10.12": + version "3.10.12" + resolved "https://registry.yarnpkg.com/@react-stately/radio/-/radio-3.10.12.tgz#79eb7d9263eed9b162b525dce35199d8414e2f95" + integrity sha512-hFH45CXVa7uyXeTYQy7LGR0SnmGnNRx7XnEXS25w4Ch6BpH8m8SAbhKXqysgcmsE3xrhRas7P9zWw7wI24G28Q== + dependencies: + "@react-stately/form" "^3.1.3" + "@react-stately/utils" "^3.10.6" + "@react-types/radio" "^3.8.8" + "@react-types/shared" "^3.29.0" + "@swc/helpers" "^0.5.0" + "@react-stately/searchfield@^3.5.10", "@react-stately/searchfield@^3.5.8": version "3.5.10" resolved "https://registry.yarnpkg.com/@react-stately/searchfield/-/searchfield-3.5.10.tgz#f9e71c9bbe239142ca6bf66e0d6bb4cba5e768bb" @@ -4673,6 +5791,15 @@ "@react-types/searchfield" "^3.6.0" "@swc/helpers" "^0.5.0" +"@react-stately/searchfield@^3.5.11": + version "3.5.11" + resolved "https://registry.yarnpkg.com/@react-stately/searchfield/-/searchfield-3.5.11.tgz#44f1e24ed5e4199d3f88802ae36813b717f44496" + integrity sha512-vOgK3kgkYcyjTLsBABVzoQL9w6qBamnWAQICcw5OkA6octnF7NZ5DqdjkwnMY95KOGchiTlD5tNNHrz0ekeGiw== + dependencies: + "@react-stately/utils" "^3.10.6" + "@react-types/searchfield" "^3.6.1" + "@swc/helpers" "^0.5.0" + "@react-stately/searchfield@^3.5.9": version "3.5.9" resolved "https://registry.yarnpkg.com/@react-stately/searchfield/-/searchfield-3.5.9.tgz#0e552c1928b9affb6dfd6de280c2d9aca8486b73" @@ -4706,6 +5833,18 @@ "@react-types/shared" "^3.28.0" "@swc/helpers" "^0.5.0" +"@react-stately/select@^3.6.12": + version "3.6.12" + resolved "https://registry.yarnpkg.com/@react-stately/select/-/select-3.6.12.tgz#24bd59113f4bb999b943655793e985fdf3d44b52" + integrity sha512-5o/NAaENO/Gxs1yui5BHLItxLnDPSQJ5HDKycuD0/gGC17BboAGEY/F9masiQ5qwRPe3JEc0QfvMRq3yZVNXog== + dependencies: + "@react-stately/form" "^3.1.3" + "@react-stately/list" "^3.12.1" + "@react-stately/overlays" "^3.6.15" + "@react-types/select" "^3.9.11" + "@react-types/shared" "^3.29.0" + "@swc/helpers" "^0.5.0" + "@react-stately/selection@^3.18.0", "@react-stately/selection@^3.20.0": version "3.20.0" resolved "https://registry.yarnpkg.com/@react-stately/selection/-/selection-3.20.0.tgz#991a67be2d80fb0c0c0ffba7542b1a0df5a31165" @@ -4726,6 +5865,16 @@ "@react-types/shared" "^3.27.0" "@swc/helpers" "^0.5.0" +"@react-stately/selection@^3.20.1": + version "3.20.1" + resolved "https://registry.yarnpkg.com/@react-stately/selection/-/selection-3.20.1.tgz#a2a849dd443bc4cf898e0239ab1f25d83532143b" + integrity sha512-K9MP6Rfg2yvFoY2Cr+ykA7bP4EBXlGaq5Dqfa1krvcXlEgMbQka5muLHdNXqjzGgcwPmS1dx1NECD15q63NtOw== + dependencies: + "@react-stately/collections" "^3.12.3" + "@react-stately/utils" "^3.10.6" + "@react-types/shared" "^3.29.0" + "@swc/helpers" "^0.5.0" + "@react-stately/slider@^3.6.0", "@react-stately/slider@^3.6.2": version "3.6.2" resolved "https://registry.yarnpkg.com/@react-stately/slider/-/slider-3.6.2.tgz#9c203dd1a7b12799cd3c14ea4375451409656746" @@ -4746,6 +5895,16 @@ "@react-types/slider" "^3.7.8" "@swc/helpers" "^0.5.0" +"@react-stately/slider@^3.6.3": + version "3.6.3" + resolved "https://registry.yarnpkg.com/@react-stately/slider/-/slider-3.6.3.tgz#88a460be021fc6cc240a16b74943267d294520ae" + integrity sha512-755X1jhpRD1bqf/5Ax1xuSpZbnG/0EEHGOowH28FLYKy5+1l4QVDGPFYxLB9KzXPdRAr9EF0j2kRhH2d8MCksQ== + dependencies: + "@react-stately/utils" "^3.10.6" + "@react-types/shared" "^3.29.0" + "@react-types/slider" "^3.7.10" + "@swc/helpers" "^0.5.0" + "@react-stately/table@^3.13.0", "@react-stately/table@^3.14.0": version "3.14.0" resolved "https://registry.yarnpkg.com/@react-stately/table/-/table-3.14.0.tgz#b91edbb1dcd16177162584d1299a36e1310d7124" @@ -4776,6 +5935,21 @@ "@react-types/table" "^3.10.4" "@swc/helpers" "^0.5.0" +"@react-stately/table@^3.14.1": + version "3.14.1" + resolved "https://registry.yarnpkg.com/@react-stately/table/-/table-3.14.1.tgz#fb86ca78ee5263220d2c562ff07849b3f081e493" + integrity sha512-7P5h4YBAv3B/7BGq/kln+xSKgJCSq4xjt4HmJA7ZkGnEksUPUokBNQdWwZsy3lX/mwunaaKR9x/YNIu7yXB02g== + dependencies: + "@react-stately/collections" "^3.12.3" + "@react-stately/flags" "^3.1.1" + "@react-stately/grid" "^3.11.1" + "@react-stately/selection" "^3.20.1" + "@react-stately/utils" "^3.10.6" + "@react-types/grid" "^3.3.1" + "@react-types/shared" "^3.29.0" + "@react-types/table" "^3.12.0" + "@swc/helpers" "^0.5.0" + "@react-stately/tabs@^3.7.0", "@react-stately/tabs@^3.8.0": version "3.8.0" resolved "https://registry.yarnpkg.com/@react-stately/tabs/-/tabs-3.8.0.tgz#9936aee9196cb5b55f9683ffe961da2e8adb104f" @@ -4796,6 +5970,16 @@ "@react-types/tabs" "^3.3.12" "@swc/helpers" "^0.5.0" +"@react-stately/tabs@^3.8.1": + version "3.8.1" + resolved "https://registry.yarnpkg.com/@react-stately/tabs/-/tabs-3.8.1.tgz#bf1f27fb59cf618f7ef01d1861e7c573ec552b5b" + integrity sha512-1TBbt2BXbemstb/gEYw/NVt3esi5WvgWQW5Z7G8nDzLkpnMHOZXueoUkMxsdm0vhE8p0M9fsJQCMXKvCG3JzJg== + dependencies: + "@react-stately/list" "^3.12.1" + "@react-types/shared" "^3.29.0" + "@react-types/tabs" "^3.3.14" + "@swc/helpers" "^0.5.0" + "@react-stately/toast@^3.0.0": version "3.0.0" resolved "https://registry.yarnpkg.com/@react-stately/toast/-/toast-3.0.0.tgz#a2aff2b4939b75d8622c8ce670d8e005a5832971" @@ -4804,6 +5988,14 @@ "@swc/helpers" "^0.5.0" use-sync-external-store "^1.4.0" +"@react-stately/toast@^3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@react-stately/toast/-/toast-3.1.0.tgz#77a3a02a151fcd7103d103738bd3886229aaf576" + integrity sha512-9W2+evz+EARrjkR1QPLlOL5lcNpVo6PjMAIygRSaCPJ6ftQAZ6B+7xTFGPFabWh83gwXQDUgoSwC3/vosvxZaQ== + dependencies: + "@swc/helpers" "^0.5.0" + use-sync-external-store "^1.4.0" + "@react-stately/toggle@^3.8.0", "@react-stately/toggle@^3.8.2": version "3.8.2" resolved "https://registry.yarnpkg.com/@react-stately/toggle/-/toggle-3.8.2.tgz#7d86ae3c662e750ed9e38ee0eb98a9bb78ee02d9" @@ -4824,6 +6016,16 @@ "@react-types/shared" "^3.27.0" "@swc/helpers" "^0.5.0" +"@react-stately/toggle@^3.8.3": + version "3.8.3" + resolved "https://registry.yarnpkg.com/@react-stately/toggle/-/toggle-3.8.3.tgz#181aaa4e4ecca970cc04d4189699c90f6f39006f" + integrity sha512-4T2V3P1RK4zEFz4vJjUXUXyB0g4Slm6stE6Ry20fzDWjltuW42cD2lmrd7ccTO/CXFmHLECcXQLD4GEbOj0epA== + dependencies: + "@react-stately/utils" "^3.10.6" + "@react-types/checkbox" "^3.9.3" + "@react-types/shared" "^3.29.0" + "@swc/helpers" "^0.5.0" + "@react-stately/tooltip@^3.5.0", "@react-stately/tooltip@^3.5.2": version "3.5.2" resolved "https://registry.yarnpkg.com/@react-stately/tooltip/-/tooltip-3.5.2.tgz#50722b8253bf3628e0e6d8f59dea738382920be7" @@ -4842,6 +6044,15 @@ "@react-types/tooltip" "^3.4.14" "@swc/helpers" "^0.5.0" +"@react-stately/tooltip@^3.5.3": + version "3.5.3" + resolved "https://registry.yarnpkg.com/@react-stately/tooltip/-/tooltip-3.5.3.tgz#2960dd592ab1ae4cfdc02c9dda56968e17f93fc6" + integrity sha512-btfy/gQ3Eccudx//4HkyQ+CRr3vxbLs74HYHthaoJ9GZbRj/3XDzfUM2X16zRoqTZVrIz/AkUj7AfGfsitU5nQ== + dependencies: + "@react-stately/overlays" "^3.6.15" + "@react-types/tooltip" "^3.4.16" + "@swc/helpers" "^0.5.0" + "@react-stately/tree@^3.8.6", "@react-stately/tree@^3.8.8": version "3.8.8" resolved "https://registry.yarnpkg.com/@react-stately/tree/-/tree-3.8.8.tgz#48bdb3579b91788afc04b97127b18acbed2eb367" @@ -4864,6 +6075,17 @@ "@react-types/shared" "^3.27.0" "@swc/helpers" "^0.5.0" +"@react-stately/tree@^3.8.9": + version "3.8.9" + resolved "https://registry.yarnpkg.com/@react-stately/tree/-/tree-3.8.9.tgz#03ace9eca113c42f797a149ee032e080887731c4" + integrity sha512-j/LLI9UvbqcfOdl2v9m3gET3etUxoQzv3XdryNAbSkg0jTx8/13Fgi/Xp98bUcNLfynfeGW5P/fieU71sMkGog== + dependencies: + "@react-stately/collections" "^3.12.3" + "@react-stately/selection" "^3.20.1" + "@react-stately/utils" "^3.10.6" + "@react-types/shared" "^3.29.0" + "@swc/helpers" "^0.5.0" + "@react-stately/utils@^3.10.4", "@react-stately/utils@^3.10.5": version "3.10.5" resolved "https://registry.yarnpkg.com/@react-stately/utils/-/utils-3.10.5.tgz#47bb91cd5afd1bafe39353614e5e281b818ebccc" @@ -4871,6 +6093,13 @@ dependencies: "@swc/helpers" "^0.5.0" +"@react-stately/utils@^3.10.6": + version "3.10.6" + resolved "https://registry.yarnpkg.com/@react-stately/utils/-/utils-3.10.6.tgz#2ae25c2773e53a4ebdaf39264aa27145b758dc1b" + integrity sha512-O76ip4InfTTzAJrg8OaZxKU4vvjMDOpfA/PGNOytiXwBbkct2ZeZwaimJ8Bt9W1bj5VsZ81/o/tW4BacbdDOMA== + dependencies: + "@swc/helpers" "^0.5.0" + "@react-stately/virtualizer@^4.2.0", "@react-stately/virtualizer@^4.3.0": version "4.3.0" resolved "https://registry.yarnpkg.com/@react-stately/virtualizer/-/virtualizer-4.3.0.tgz#492154a9992d8bb7d4fdf7d30f201bf244986951" @@ -4889,6 +6118,15 @@ "@react-types/shared" "^3.27.0" "@swc/helpers" "^0.5.0" +"@react-stately/virtualizer@^4.3.2": + version "4.3.2" + resolved "https://registry.yarnpkg.com/@react-stately/virtualizer/-/virtualizer-4.3.2.tgz#3de29fe3df37d5f806e68934906562b236c3d2cc" + integrity sha512-KxR0s6IBqUD2TfDM3mAOtiTZLb1zOwcuCeUOvCKNqzEdFhh7nEJPrG33mgJn64S4kM11c0AsPwBlxISqdvCXJg== + dependencies: + "@react-aria/utils" "^3.28.2" + "@react-types/shared" "^3.29.0" + "@swc/helpers" "^0.5.0" + "@react-types/autocomplete@3.0.0-alpha.28": version "3.0.0-alpha.28" resolved "https://registry.yarnpkg.com/@react-types/autocomplete/-/autocomplete-3.0.0-alpha.28.tgz#0dc91682abcde43ec3c80a254eddfc0c002539c4" @@ -4898,6 +6136,15 @@ "@react-types/searchfield" "^3.5.11" "@react-types/shared" "^3.27.0" +"@react-types/autocomplete@3.0.0-alpha.30": + version "3.0.0-alpha.30" + resolved "https://registry.yarnpkg.com/@react-types/autocomplete/-/autocomplete-3.0.0-alpha.30.tgz#c4672644f762d112557c54e78fddf1f8f9ae4146" + integrity sha512-9neGygI+stJqiEFHzoc1jMySj6lOc4MUmBmu0uGn2zdOG2zxaAZSjh1pd9AJkHNyZ4j/n5rVXMo+v3RNkUntNw== + dependencies: + "@react-types/combobox" "^3.13.4" + "@react-types/searchfield" "^3.6.1" + "@react-types/shared" "^3.29.0" + "@react-types/breadcrumbs@^3.7.10": version "3.7.10" resolved "https://registry.yarnpkg.com/@react-types/breadcrumbs/-/breadcrumbs-3.7.10.tgz#4d5b84460890107e6438b8d00025557cc7163237" @@ -4914,6 +6161,14 @@ "@react-types/link" "^3.5.11" "@react-types/shared" "^3.28.0" +"@react-types/breadcrumbs@^3.7.12": + version "3.7.12" + resolved "https://registry.yarnpkg.com/@react-types/breadcrumbs/-/breadcrumbs-3.7.12.tgz#042c5e1b1d20b0ef6346365d7a5965bd6f7f7437" + integrity sha512-+LvGEADlv11mLQjxEAZriptSYJJTP+2OIFEKx0z9mmpp+8jTlEHFhAnRVaE6I9QCxcDB5F6q/olfizSwOPOMIg== + dependencies: + "@react-types/link" "^3.6.0" + "@react-types/shared" "^3.29.0" + "@react-types/button@^3.10.1", "@react-types/button@^3.11.0": version "3.11.0" resolved "https://registry.yarnpkg.com/@react-types/button/-/button-3.11.0.tgz#ca57d3bbf03935a07fe7e8356192152d9d77a00c" @@ -4928,6 +6183,13 @@ dependencies: "@react-types/shared" "^3.27.0" +"@react-types/button@^3.12.0": + version "3.12.0" + resolved "https://registry.yarnpkg.com/@react-types/button/-/button-3.12.0.tgz#3e6957be95360124a1cad91cb5414099e3c78f83" + integrity sha512-YrASNa+RqGQpzJcxNAahzNuTYVID1OE6HCorrEOXIyGS3EGogHsQmFs9OyThXnGHq6q4rLlA806/jWbP9uZdxA== + dependencies: + "@react-types/shared" "^3.29.0" + "@react-types/calendar@^3.5.0", "@react-types/calendar@^3.6.1": version "3.6.1" resolved "https://registry.yarnpkg.com/@react-types/calendar/-/calendar-3.6.1.tgz#25e0ff634787d70f70abf72a030c1e33c668a820" @@ -4944,6 +6206,14 @@ "@internationalized/date" "^3.7.0" "@react-types/shared" "^3.27.0" +"@react-types/calendar@^3.7.0": + version "3.7.0" + resolved "https://registry.yarnpkg.com/@react-types/calendar/-/calendar-3.7.0.tgz#3e152d01e376256ccf54eb1b28c7520c8521fb22" + integrity sha512-RiEfX2ZTcvfRktQc5obOJtNTgW+UwjNOUW5yf9CLCNOSM07e0w5jtC1ewsOZZbcctMrMCljjL8niGWiBv1wQ1Q== + dependencies: + "@internationalized/date" "^3.8.0" + "@react-types/shared" "^3.29.0" + "@react-types/checkbox@^3.9.1": version "3.9.1" resolved "https://registry.yarnpkg.com/@react-types/checkbox/-/checkbox-3.9.1.tgz#6ba0153f3f498af211112eab6e31d243170d5004" @@ -4958,6 +6228,13 @@ dependencies: "@react-types/shared" "^3.28.0" +"@react-types/checkbox@^3.9.3": + version "3.9.3" + resolved "https://registry.yarnpkg.com/@react-types/checkbox/-/checkbox-3.9.3.tgz#f74ed23f1d14c5003240ae08f8ef66610ec66eb5" + integrity sha512-h6wmK7CraKHKE6L13Ut+CtnjRktbMRhkCSorv7eg82M6p4PDhZ7mfDSh13IlGR4sryT8Ka+aOjOU+EvMrKiduA== + dependencies: + "@react-types/shared" "^3.29.0" + "@react-types/color@^3.0.1", "@react-types/color@^3.0.3": version "3.0.3" resolved "https://registry.yarnpkg.com/@react-types/color/-/color-3.0.3.tgz#0a1cde0eb9fb266fca722a5edfe068e5c19f11e8" @@ -4974,6 +6251,14 @@ "@react-types/shared" "^3.27.0" "@react-types/slider" "^3.7.8" +"@react-types/color@^3.0.4": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@react-types/color/-/color-3.0.4.tgz#00d3ff6dbba261a83a15646e6d90a2a0b60148da" + integrity sha512-D6Uea8kYGaoZRHgemJ0b0+iXbrvABP8RzsctL8Yp5QVyGgYJDMO8/7eZ3tdtGs/V8Iv+yCzG4yBexPA95i6tEg== + dependencies: + "@react-types/shared" "^3.29.0" + "@react-types/slider" "^3.7.10" + "@react-types/combobox@^3.13.2": version "3.13.2" resolved "https://registry.yarnpkg.com/@react-types/combobox/-/combobox-3.13.2.tgz#b6ee140166691e59bebe57f082dc6127f9bb7210" @@ -4988,6 +6273,13 @@ dependencies: "@react-types/shared" "^3.28.0" +"@react-types/combobox@^3.13.4": + version "3.13.4" + resolved "https://registry.yarnpkg.com/@react-types/combobox/-/combobox-3.13.4.tgz#cc6b5fc5d5fa0d1018d878ac2b19485696e2b59b" + integrity sha512-4mX7eZ/Bv3YWzEzLEZAF/TfKM+I+SCsvnm/cHqOJq3jEE8aVU1ql4Q1+3+SvciX3pfFIfeKlu9S3oYKRT5WIgg== + dependencies: + "@react-types/shared" "^3.29.0" + "@react-types/datepicker@^3.10.0": version "3.10.0" resolved "https://registry.yarnpkg.com/@react-types/datepicker/-/datepicker-3.10.0.tgz#4557c2d22a52fb7340ca27e6eba4d23556684e84" @@ -5008,6 +6300,16 @@ "@react-types/overlays" "^3.8.13" "@react-types/shared" "^3.28.0" +"@react-types/datepicker@^3.12.0": + version "3.12.0" + resolved "https://registry.yarnpkg.com/@react-types/datepicker/-/datepicker-3.12.0.tgz#ae2a8e689e7a78fa967450154a2b7896796c1285" + integrity sha512-dw/xflOdQPQ3uEABaBrZRTvjsMRu5/VZjRx9ygc64sX2N7HKIt+foMPXKJ+1jhtki2p4gigNVjcnJndJHoj9SA== + dependencies: + "@internationalized/date" "^3.8.0" + "@react-types/calendar" "^3.7.0" + "@react-types/overlays" "^3.8.14" + "@react-types/shared" "^3.29.0" + "@react-types/dialog@^3.5.14", "@react-types/dialog@^3.5.16": version "3.5.16" resolved "https://registry.yarnpkg.com/@react-types/dialog/-/dialog-3.5.16.tgz#109e95f3750b5d2fd1ba10bc4d28bd71b79ba9f4" @@ -5024,6 +6326,21 @@ "@react-types/overlays" "^3.8.12" "@react-types/shared" "^3.27.0" +"@react-types/dialog@^3.5.17": + version "3.5.17" + resolved "https://registry.yarnpkg.com/@react-types/dialog/-/dialog-3.5.17.tgz#35897ebe2ddde1b814f968caa50ffcf97864324d" + integrity sha512-rKe2WrT272xuCH13euegBGjJAORYXJpHsX2hlu/f02TmMG4nSLss9vKBnY2N7k7nci65k5wDTW6lcsvQ4Co5zQ== + dependencies: + "@react-types/overlays" "^3.8.14" + "@react-types/shared" "^3.29.0" + +"@react-types/form@^3.7.11": + version "3.7.11" + resolved "https://registry.yarnpkg.com/@react-types/form/-/form-3.7.11.tgz#ea40bd3a49494f46a8a11898a0543e048448b9c7" + integrity sha512-umqy2Kvg3ooJi+Wqun95tKbKN51gtNt9s7OFLdwCtfWa6GvHFOixSjqAvZbo+m5qC3X/1kMIz3Dg698l0/+oLQ== + dependencies: + "@react-types/shared" "^3.29.0" + "@react-types/form@^3.7.8": version "3.7.10" resolved "https://registry.yarnpkg.com/@react-types/form/-/form-3.7.10.tgz#3ec956b48a9fce3e5825713dc69c28f8917008c9" @@ -5052,6 +6369,13 @@ dependencies: "@react-types/shared" "^3.27.0" +"@react-types/grid@^3.3.1": + version "3.3.1" + resolved "https://registry.yarnpkg.com/@react-types/grid/-/grid-3.3.1.tgz#8f41f5fb6d1c213b34bc80bc8416b1a837378f56" + integrity sha512-bPDckheJiHSIzSeSkLqrO6rXRLWvciFJr9rpCjq/+wBj6HsLh2iMpkB/SqmRHTGpPlJvlu0b7AlxK1FYE0QSKA== + dependencies: + "@react-types/shared" "^3.29.0" + "@react-types/link@^3.5.10": version "3.5.10" resolved "https://registry.yarnpkg.com/@react-types/link/-/link-3.5.10.tgz#17fa4a543fdeb1c3bdc268664073c597b759a266" @@ -5066,6 +6390,13 @@ dependencies: "@react-types/shared" "^3.28.0" +"@react-types/link@^3.6.0": + version "3.6.0" + resolved "https://registry.yarnpkg.com/@react-types/link/-/link-3.6.0.tgz#5bac8cb4fafb0b0f273f617f8522d02448c59609" + integrity sha512-BQ5Tktb+fUxvtqksAJZuP8Z/bpmnQ/Y/zgwxfU0OKmIWkKMUsXY+e0GBVxwFxeh39D77stpVxRsTl7NQrjgtSw== + dependencies: + "@react-types/shared" "^3.29.0" + "@react-types/listbox@^3.5.4": version "3.5.4" resolved "https://registry.yarnpkg.com/@react-types/listbox/-/listbox-3.5.4.tgz#71de93319e508a38a073e5cc9ffcaa01d7fb02e7" @@ -5080,6 +6411,21 @@ dependencies: "@react-types/shared" "^3.28.0" +"@react-types/listbox@^3.6.0": + version "3.6.0" + resolved "https://registry.yarnpkg.com/@react-types/listbox/-/listbox-3.6.0.tgz#3016f170a67e9ac0190405a61f438406309dc5ff" + integrity sha512-+1ugDKTxson/WNOQZO4BfrnQ6cGDt+72mEytXMsSsd4aEC+x3RyUv6NKwdOl4n602cOreo0MHtap1X2BOACVoQ== + dependencies: + "@react-types/shared" "^3.29.0" + +"@react-types/menu@^3.10.0": + version "3.10.0" + resolved "https://registry.yarnpkg.com/@react-types/menu/-/menu-3.10.0.tgz#85b807ee348801ac59036b9aa6c7bae4d9a1cd36" + integrity sha512-DKMqEmUmarVCK0jblNkSlzSH53AAsxWCX9RaKZeP9EnRs2/l1oZRuiQVHlOQRgYwEigAXa2TrwcX4nnxZ+U36Q== + dependencies: + "@react-types/overlays" "^3.8.14" + "@react-types/shared" "^3.29.0" + "@react-types/menu@^3.9.14": version "3.9.14" resolved "https://registry.yarnpkg.com/@react-types/menu/-/menu-3.9.14.tgz#524d173ad2d79bf9deeffd7de2af8a9839f9a212" @@ -5110,6 +6456,20 @@ dependencies: "@react-types/progress" "^3.5.10" +"@react-types/meter@^3.4.8": + version "3.4.8" + resolved "https://registry.yarnpkg.com/@react-types/meter/-/meter-3.4.8.tgz#d7a9c56971226f1e1ccea264a164a634c0a4c8b7" + integrity sha512-uXmHdUDbAo7L3EkytrUrU6DLOFUt63s9QSTcDp+vwyWoshY4/4Dm4JARdmhJU2ZP1nb2Sy45ASeMvSBw3ia2oA== + dependencies: + "@react-types/progress" "^3.5.11" + +"@react-types/numberfield@^3.8.10": + version "3.8.10" + resolved "https://registry.yarnpkg.com/@react-types/numberfield/-/numberfield-3.8.10.tgz#56b42ebce833bb54feb24dadffdfb37e6089bc70" + integrity sha512-mdb4lMC4skO8Eqd0GeU4lJgDTEvqIhtINB5WCzLVZFrFVuxgWDoU5otsu0lbWhCnUA7XWQxupGI//TC1LLppjQ== + dependencies: + "@react-types/shared" "^3.29.0" + "@react-types/numberfield@^3.8.8": version "3.8.8" resolved "https://registry.yarnpkg.com/@react-types/numberfield/-/numberfield-3.8.8.tgz#7134dc8e40ebeb493be7badc28648a11b6186f16" @@ -5138,6 +6498,13 @@ dependencies: "@react-types/shared" "^3.28.0" +"@react-types/overlays@^3.8.14": + version "3.8.14" + resolved "https://registry.yarnpkg.com/@react-types/overlays/-/overlays-3.8.14.tgz#75b5e27579bde3db4b231f6dbe230a5494531896" + integrity sha512-XJS67KHYhdMvPNHXNGdmc85gE+29QT5TwC58V4kxxHVtQh9fYzEEPzIV8K84XWSz04rRGe3fjDgRNbcqBektWQ== + dependencies: + "@react-types/shared" "^3.29.0" + "@react-types/progress@^3.5.10": version "3.5.10" resolved "https://registry.yarnpkg.com/@react-types/progress/-/progress-3.5.10.tgz#673e4c830238fa40a9f737d472dff4ba3c1bb980" @@ -5145,6 +6512,13 @@ dependencies: "@react-types/shared" "^3.28.0" +"@react-types/progress@^3.5.11": + version "3.5.11" + resolved "https://registry.yarnpkg.com/@react-types/progress/-/progress-3.5.11.tgz#76af0ef249e1c54536429321f62abafe8d1ea9da" + integrity sha512-CysuMld/lycOckrnlvrlsVoJysDPeBnUYBChwtqwiv4ZNRXos+wgAL1ows6dl7Nr57/FH5B4v5gf9AHEo7jUvw== + dependencies: + "@react-types/shared" "^3.29.0" + "@react-types/progress@^3.5.9": version "3.5.9" resolved "https://registry.yarnpkg.com/@react-types/progress/-/progress-3.5.9.tgz#aab7a20f361d970e5e847fedbe4306557cde0bad" @@ -5166,6 +6540,13 @@ dependencies: "@react-types/shared" "^3.28.0" +"@react-types/radio@^3.8.8": + version "3.8.8" + resolved "https://registry.yarnpkg.com/@react-types/radio/-/radio-3.8.8.tgz#dbb3940408c38ed073ad441f05be4318e5013398" + integrity sha512-QfAIp+0CnRSnoRTJVXUEPi+9AvFvRzWLIKEnE9OmgXjuvJCU3QNiwd8NWjNeE+94QBEVvAZQcqGU+44q5poxNg== + dependencies: + "@react-types/shared" "^3.29.0" + "@react-types/searchfield@^3.5.11": version "3.5.11" resolved "https://registry.yarnpkg.com/@react-types/searchfield/-/searchfield-3.5.11.tgz#b15872853ef0908c1b0d81fcb40df50e60600f58" @@ -5182,6 +6563,14 @@ "@react-types/shared" "^3.28.0" "@react-types/textfield" "^3.12.0" +"@react-types/searchfield@^3.6.1": + version "3.6.1" + resolved "https://registry.yarnpkg.com/@react-types/searchfield/-/searchfield-3.6.1.tgz#ef0ebb9b94606647c5b5d6a374f28e9cf3e637a6" + integrity sha512-XR4tYktxHxGJufpO0MTAPknIbmN5eZqXCZwTdBS4tecihf9iGDsXmrBOs+M7LEnil67GaZcFrMhKxOMVpLwZAg== + dependencies: + "@react-types/shared" "^3.29.0" + "@react-types/textfield" "^3.12.1" + "@react-types/select@^3.9.10": version "3.9.10" resolved "https://registry.yarnpkg.com/@react-types/select/-/select-3.9.10.tgz#d7ca15b384c859e094b077271d0f0fde2f6e4e86" @@ -5189,6 +6578,13 @@ dependencies: "@react-types/shared" "^3.28.0" +"@react-types/select@^3.9.11": + version "3.9.11" + resolved "https://registry.yarnpkg.com/@react-types/select/-/select-3.9.11.tgz#6dbfcc82366d25edc2f9718e74088729dffb17ef" + integrity sha512-uEpQCgDlrq/5fW05FgNEsqsqpvZVKfHQO9Mp7OTqGtm4UBNAbcQ6hOV7MJwQCS25Lu2luzOYdgqDUN8eAATJVQ== + dependencies: + "@react-types/shared" "^3.29.0" + "@react-types/select@^3.9.9": version "3.9.9" resolved "https://registry.yarnpkg.com/@react-types/select/-/select-3.9.9.tgz#adb771b5152be664e0e3011dad60cc4a3258c66d" @@ -5206,6 +6602,18 @@ resolved "https://registry.yarnpkg.com/@react-types/shared/-/shared-3.27.0.tgz#167c163139efc98c2194aba090076c03b658c07d" integrity sha512-gvznmLhi6JPEf0bsq7SwRYTHAKKq/wcmKqFez9sRdbED+SPMUmK5omfZ6w3EwUFQHbYUa4zPBYedQ7Knv70RMw== +"@react-types/shared@^3.29.0": + version "3.29.0" + resolved "https://registry.yarnpkg.com/@react-types/shared/-/shared-3.29.0.tgz#f29bdad3bff1336aaa754d7abc420da2f014d931" + integrity sha512-IDQYu/AHgZimObzCFdNl1LpZvQW/xcfLt3v20sorl5qRucDVj4S9os98sVTZ4IRIBjmS+MkjqpR5E70xan7ooA== + +"@react-types/slider@^3.7.10": + version "3.7.10" + resolved "https://registry.yarnpkg.com/@react-types/slider/-/slider-3.7.10.tgz#fa3797a9a91670b8e3a6f763521058d4ac725db5" + integrity sha512-Yb8wbpu2gS7AwvJUuz0IdZBRi6eIBZq32BSss4UHX0StA8dtR1/K4JeTsArxwiA3P0BA6t0gbR6wzxCvVA9fRw== + dependencies: + "@react-types/shared" "^3.29.0" + "@react-types/slider@^3.7.8": version "3.7.8" resolved "https://registry.yarnpkg.com/@react-types/slider/-/slider-3.7.8.tgz#a844b81a67171931352d3b5fb40ae87290b99097" @@ -5220,6 +6628,13 @@ dependencies: "@react-types/shared" "^3.28.0" +"@react-types/switch@^3.5.10": + version "3.5.10" + resolved "https://registry.yarnpkg.com/@react-types/switch/-/switch-3.5.10.tgz#b099548d5671dfade4c715e8b492aa4a82e76e0e" + integrity sha512-YyNhx4CvuJ0Rvv7yMuQaqQuOIeg+NwLV00NHHJ+K0xEANSLcICLOLPNMOqRIqLSQDz5vDI705UKk8gVcxqPX5g== + dependencies: + "@react-types/shared" "^3.29.0" + "@react-types/switch@^3.5.8": version "3.5.8" resolved "https://registry.yarnpkg.com/@react-types/switch/-/switch-3.5.8.tgz#fd2d2c7fab236d3daaca57cfe34b3ec37cb0fef5" @@ -5250,6 +6665,14 @@ "@react-types/grid" "^3.2.11" "@react-types/shared" "^3.27.0" +"@react-types/table@^3.12.0": + version "3.12.0" + resolved "https://registry.yarnpkg.com/@react-types/table/-/table-3.12.0.tgz#0163725f5672849ebbde5ae278989605a163b643" + integrity sha512-dmTzjCYwHf2HBOeTa/CEL177Aox0f0mkeLF5nQw/2z6SBolfmYoAwVTPxTaYFVu4MkEJxQTz9AuAsJvCbRJbhg== + dependencies: + "@react-types/grid" "^3.3.1" + "@react-types/shared" "^3.29.0" + "@react-types/tabs@^3.3.12": version "3.3.12" resolved "https://registry.yarnpkg.com/@react-types/tabs/-/tabs-3.3.12.tgz#7cd69dae549136ede13f35878e65ccff7bb4522f" @@ -5264,6 +6687,13 @@ dependencies: "@react-types/shared" "^3.28.0" +"@react-types/tabs@^3.3.14": + version "3.3.14" + resolved "https://registry.yarnpkg.com/@react-types/tabs/-/tabs-3.3.14.tgz#e9d29fc780902c3b9ae4495a5a2f899585ef8ed7" + integrity sha512-/uKsA7L2dctKU0JEaBWerlX+3BoXpKUFr3kHpRUoH66DSGvAo34vZ7kv/BHMZifJenIbF04GhDBsGp1zjrQKBg== + dependencies: + "@react-types/shared" "^3.29.0" + "@react-types/textfield@^3.11.0": version "3.11.0" resolved "https://registry.yarnpkg.com/@react-types/textfield/-/textfield-3.11.0.tgz#09d1fb2dbc24795b22008d27490b1620e6d68c01" @@ -5278,6 +6708,13 @@ dependencies: "@react-types/shared" "^3.28.0" +"@react-types/textfield@^3.12.1": + version "3.12.1" + resolved "https://registry.yarnpkg.com/@react-types/textfield/-/textfield-3.12.1.tgz#272f7f97e72dd4ec1debd5202e2f1c4296b65a18" + integrity sha512-6YTAMCKjEGuXg0A4bZA77j5QJ1a6yFviMUWsCIL6Dxq5K3TklzVsbAduSbHomPPuvkNTBSW4+TUJrVSnoTjMNA== + dependencies: + "@react-types/shared" "^3.29.0" + "@react-types/tooltip@^3.4.14": version "3.4.14" resolved "https://registry.yarnpkg.com/@react-types/tooltip/-/tooltip-3.4.14.tgz#7acc4247f9bcb30e50fc4c18e8b3fda17e52d85c" @@ -5294,6 +6731,14 @@ "@react-types/overlays" "^3.8.13" "@react-types/shared" "^3.28.0" +"@react-types/tooltip@^3.4.16": + version "3.4.16" + resolved "https://registry.yarnpkg.com/@react-types/tooltip/-/tooltip-3.4.16.tgz#25533d36dab850522b01b7dcfc3abe72a63d3a26" + integrity sha512-XEyKeqR3YxqJcR0cpigLGEBeRTEzrB0cu++IaADdqXJ8dBzS6s8y9EgR5UvKZmX1CQOBvMfXyYkj7nmJ039fOw== + dependencies: + "@react-types/overlays" "^3.8.14" + "@react-types/shared" "^3.29.0" + "@remirror/core-constants@3.0.0": version "3.0.0" resolved "https://registry.yarnpkg.com/@remirror/core-constants/-/core-constants-3.0.0.tgz#96fdb89d25c62e7b6a5d08caf0ce5114370e3b8f" @@ -5366,6 +6811,101 @@ estree-walker "^2.0.2" picomatch "^4.0.2" +"@rollup/rollup-android-arm-eabi@4.35.0": + version "4.35.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.35.0.tgz#e1d7700735f7e8de561ef7d1fa0362082a180c43" + integrity sha512-uYQ2WfPaqz5QtVgMxfN6NpLD+no0MYHDBywl7itPYd3K5TjjSghNKmX8ic9S8NU8w81NVhJv/XojcHptRly7qQ== + +"@rollup/rollup-android-arm64@4.35.0": + version "4.35.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.35.0.tgz#fa6cdfb1fc9e2c8e227a7f35d524d8f7f90cf4db" + integrity sha512-FtKddj9XZudurLhdJnBl9fl6BwCJ3ky8riCXjEw3/UIbjmIY58ppWwPEvU3fNu+W7FUsAsB1CdH+7EQE6CXAPA== + +"@rollup/rollup-darwin-arm64@4.35.0": + version "4.35.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.35.0.tgz#6da5a1ddc4f11d4a7ae85ab443824cb6bf614e30" + integrity sha512-Uk+GjOJR6CY844/q6r5DR/6lkPFOw0hjfOIzVx22THJXMxktXG6CbejseJFznU8vHcEBLpiXKY3/6xc+cBm65Q== + +"@rollup/rollup-darwin-x64@4.35.0": + version "4.35.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.35.0.tgz#25b74ce2d8d3f9ea8e119b01384d44a1c0a0d3ae" + integrity sha512-3IrHjfAS6Vkp+5bISNQnPogRAW5GAV1n+bNCrDwXmfMHbPl5EhTmWtfmwlJxFRUCBZ+tZ/OxDyU08aF6NI/N5Q== + +"@rollup/rollup-freebsd-arm64@4.35.0": + version "4.35.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.35.0.tgz#be3d39e3441df5d6e187c83d158c60656c82e203" + integrity sha512-sxjoD/6F9cDLSELuLNnY0fOrM9WA0KrM0vWm57XhrIMf5FGiN8D0l7fn+bpUeBSU7dCgPV2oX4zHAsAXyHFGcQ== + +"@rollup/rollup-freebsd-x64@4.35.0": + version "4.35.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.35.0.tgz#cd932d3ec679711efd65ca25821fb318e25b7ce4" + integrity sha512-2mpHCeRuD1u/2kruUiHSsnjWtHjqVbzhBkNVQ1aVD63CcexKVcQGwJ2g5VphOd84GvxfSvnnlEyBtQCE5hxVVw== + +"@rollup/rollup-linux-arm-gnueabihf@4.35.0": + version "4.35.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.35.0.tgz#d300b74c6f805474225632f185daaeae760ac2bb" + integrity sha512-mrA0v3QMy6ZSvEuLs0dMxcO2LnaCONs1Z73GUDBHWbY8tFFocM6yl7YyMu7rz4zS81NDSqhrUuolyZXGi8TEqg== + +"@rollup/rollup-linux-arm-musleabihf@4.35.0": + version "4.35.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.35.0.tgz#2caac622380f314c41934ed1e68ceaf6cc380cc3" + integrity sha512-DnYhhzcvTAKNexIql8pFajr0PiDGrIsBYPRvCKlA5ixSS3uwo/CWNZxB09jhIapEIg945KOzcYEAGGSmTSpk7A== + +"@rollup/rollup-linux-arm64-gnu@4.35.0": + version "4.35.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.35.0.tgz#1ec841650b038cc15c194c26326483fd7ebff3e3" + integrity sha512-uagpnH2M2g2b5iLsCTZ35CL1FgyuzzJQ8L9VtlJ+FckBXroTwNOaD0z0/UF+k5K3aNQjbm8LIVpxykUOQt1m/A== + +"@rollup/rollup-linux-arm64-musl@4.35.0": + version "4.35.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.35.0.tgz#2fc70a446d986e27f6101ea74e81746987f69150" + integrity sha512-XQxVOCd6VJeHQA/7YcqyV0/88N6ysSVzRjJ9I9UA/xXpEsjvAgDTgH3wQYz5bmr7SPtVK2TsP2fQ2N9L4ukoUg== + +"@rollup/rollup-linux-loongarch64-gnu@4.35.0": + version "4.35.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.35.0.tgz#561bd045cd9ce9e08c95f42e7a8688af8c93d764" + integrity sha512-5pMT5PzfgwcXEwOaSrqVsz/LvjDZt+vQ8RT/70yhPU06PTuq8WaHhfT1LW+cdD7mW6i/J5/XIkX/1tCAkh1W6g== + +"@rollup/rollup-linux-powerpc64le-gnu@4.35.0": + version "4.35.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.35.0.tgz#45d849a0b33813f33fe5eba9f99e0ff15ab5caad" + integrity sha512-c+zkcvbhbXF98f4CtEIP1EBA/lCic5xB0lToneZYvMeKu5Kamq3O8gqrxiYYLzlZH6E3Aq+TSW86E4ay8iD8EA== + +"@rollup/rollup-linux-riscv64-gnu@4.35.0": + version "4.35.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.35.0.tgz#78dde3e6fcf5b5733a97d0a67482d768aa1e83a5" + integrity sha512-s91fuAHdOwH/Tad2tzTtPX7UZyytHIRR6V4+2IGlV0Cej5rkG0R61SX4l4y9sh0JBibMiploZx3oHKPnQBKe4g== + +"@rollup/rollup-linux-s390x-gnu@4.35.0": + version "4.35.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.35.0.tgz#2e34835020f9e03dfb411473a5c2a0e8a9c5037b" + integrity sha512-hQRkPQPLYJZYGP+Hj4fR9dDBMIM7zrzJDWFEMPdTnTy95Ljnv0/4w/ixFw3pTBMEuuEuoqtBINYND4M7ujcuQw== + +"@rollup/rollup-linux-x64-gnu@4.35.0": + version "4.35.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.35.0.tgz#4f9774beddc6f4274df57ac99862eb23040de461" + integrity sha512-Pim1T8rXOri+0HmV4CdKSGrqcBWX0d1HoPnQ0uw0bdp1aP5SdQVNBy8LjYncvnLgu3fnnCt17xjWGd4cqh8/hA== + +"@rollup/rollup-linux-x64-musl@4.35.0": + version "4.35.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.35.0.tgz#dfcff2c1aed518b3d23ccffb49afb349d74fb608" + integrity sha512-QysqXzYiDvQWfUiTm8XmJNO2zm9yC9P/2Gkrwg2dH9cxotQzunBHYr6jk4SujCTqnfGxduOmQcI7c2ryuW8XVg== + +"@rollup/rollup-win32-arm64-msvc@4.35.0": + version "4.35.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.35.0.tgz#b0b37e2d77041e3aa772f519291309abf4c03a84" + integrity sha512-OUOlGqPkVJCdJETKOCEf1mw848ZyJ5w50/rZ/3IBQVdLfR5jk/6Sr5m3iO2tdPgwo0x7VcncYuOvMhBWZq8ayg== + +"@rollup/rollup-win32-ia32-msvc@4.35.0": + version "4.35.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.35.0.tgz#5b5a40e44a743ddc0e06b8e1b3982f856dc9ce0a" + integrity sha512-2/lsgejMrtwQe44glq7AFFHLfJBPafpsTa6JvP2NGef/ifOa4KBoglVf7AKN7EV9o32evBPRqfg96fEHzWo5kw== + +"@rollup/rollup-win32-x64-msvc@4.35.0": + version "4.35.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.35.0.tgz#05f25dbc9981bee1ae6e713daab10397044a46ca" + integrity sha512-PIQeY5XDkrOysbQblSW7v3l1MDZzkTEzAfTPkj5VAu3FW8fS4ynyLg2sINp0fp3SjZ8xkRYpLqoKcYqAkhU1dw== + "@rtsao/scc@^1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@rtsao/scc/-/scc-1.1.0.tgz#927dd2fae9bc3361403ac2c7a00c32ddce9ad7e8" @@ -5376,19 +6916,19 @@ resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.10.5.tgz#3a1c12c959010a55c17d46b395ed3047b545c246" integrity sha512-kkKUDVlII2DQiKy7UstOR1ErJP8kUKAQ4oa+SQtM0K+lPdmmjj0YnnxBgtTVYH7mUKtbsxeFC9y0AmK7Yb78/A== -"@sentry-internal/browser-utils@9.3.0": - version "9.3.0" - resolved "https://registry.yarnpkg.com/@sentry-internal/browser-utils/-/browser-utils-9.3.0.tgz#345fa61da239186fa0ad6c7194d4a1f7df7646c7" - integrity sha512-G3z4HCUyb5nJe03EPUhWjnaHqMDt4mOTFJDNha3DGoB51lMYojpQI1Qo1u6bY4qkWVSO1c+HqOU0RVsXoAchtQ== +"@sentry-internal/browser-utils@9.13.0": + version "9.13.0" + resolved "https://registry.yarnpkg.com/@sentry-internal/browser-utils/-/browser-utils-9.13.0.tgz#886e6c1dcf706624d98166c389aadcbf9681bd71" + integrity sha512-uZcbwcGI49oPC/YDEConJ+3xi2mu0TsVsDiMQKb6JoSc33KH37wq2IwXJb9nakzKJXxyMNemb44r8irAswjItw== dependencies: - "@sentry/core" "9.3.0" + "@sentry/core" "9.13.0" -"@sentry-internal/feedback@9.3.0": - version "9.3.0" - resolved "https://registry.yarnpkg.com/@sentry-internal/feedback/-/feedback-9.3.0.tgz#d60bcedd01907478b286512ce54f59682b2910e0" - integrity sha512-LQmIbQaATlN5QEwCD2Xt+7VKfwfR5W3dbn0jdF1x4hQFE/srdnOj60xMz/mj3tP5BxV552xJniGsyZ8lXHDb2A== +"@sentry-internal/feedback@9.13.0": + version "9.13.0" + resolved "https://registry.yarnpkg.com/@sentry-internal/feedback/-/feedback-9.13.0.tgz#235bea4cd8c7dd4151725467a64b1c0f05b9788a" + integrity sha512-fOhMnhEbOR5QVPtn5Gc5+UKQHjvAN/LmtYE6Qya3w2FDh3ZlnIXNFJWqwOneuICV3kCWjN4lLckwmzzwychr7A== dependencies: - "@sentry/core" "9.3.0" + "@sentry/core" "9.13.0" "@sentry-internal/node-cpu-profiler@^2.0.0": version "2.1.0" @@ -5398,91 +6938,91 @@ detect-libc "^2.0.3" node-abi "^3.73.0" -"@sentry-internal/replay-canvas@9.3.0": - version "9.3.0" - resolved "https://registry.yarnpkg.com/@sentry-internal/replay-canvas/-/replay-canvas-9.3.0.tgz#b9432ab65152304b5f86f99efdeffcd92091f733" - integrity sha512-MhDMJeRGa55a0D541+OzTFMWwbabthhDGbAL90/NpappfyeBbAiktmCNl0BFTZuRbCGrC2m1LLCqHegCVKW4fQ== +"@sentry-internal/replay-canvas@9.13.0": + version "9.13.0" + resolved "https://registry.yarnpkg.com/@sentry-internal/replay-canvas/-/replay-canvas-9.13.0.tgz#1821377b9587b61f080c8a21617ebdeef26b2580" + integrity sha512-5muW2BmEfWP1fpVWDNcIsph/WgqOqpHaXC1QMr4hk8/BWgt1/S2KPy85YiGVtM5lJJr0VhASKK8rBXG+9zm9IQ== dependencies: - "@sentry-internal/replay" "9.3.0" - "@sentry/core" "9.3.0" + "@sentry-internal/replay" "9.13.0" + "@sentry/core" "9.13.0" -"@sentry-internal/replay@9.3.0": - version "9.3.0" - resolved "https://registry.yarnpkg.com/@sentry-internal/replay/-/replay-9.3.0.tgz#c846cf77cd8deefda84316f1a938bbeae5861564" - integrity sha512-ZkH+Gahn89JygpuiFn26ZgAqJXHtnr+HjfQ2ONOFoWQHNH6X5wk75UTma55aYk1d8VcBPFoU6WjFhZoQ55SV1g== +"@sentry-internal/replay@9.13.0": + version "9.13.0" + resolved "https://registry.yarnpkg.com/@sentry-internal/replay/-/replay-9.13.0.tgz#0266a5ff990f371f25154e85950d6a6e6da77c93" + integrity sha512-l+Atwab/bqI1N8+PSG1WWTCVmiOl7swL85Z9ntwS39QBnd66CTyzt/+j/n/UbAs8GienJK6FIfX1dvG1WmvUhA== dependencies: - "@sentry-internal/browser-utils" "9.3.0" - "@sentry/core" "9.3.0" + "@sentry-internal/browser-utils" "9.13.0" + "@sentry/core" "9.13.0" -"@sentry/babel-plugin-component-annotate@3.1.2": - version "3.1.2" - resolved "https://registry.yarnpkg.com/@sentry/babel-plugin-component-annotate/-/babel-plugin-component-annotate-3.1.2.tgz#5497ca5adbe775955e96c566511a0bed3ab0a3ce" - integrity sha512-5h2WXRJ6swKA0TwxHHryC8M2QyOfS9QhTAL6ElPfkEYe9HhJieXmxsDpyspbqAa26ccnCUcmwE5vL34jAjt4sQ== +"@sentry/babel-plugin-component-annotate@3.3.1": + version "3.3.1" + resolved "https://registry.yarnpkg.com/@sentry/babel-plugin-component-annotate/-/babel-plugin-component-annotate-3.3.1.tgz#baecd89396cbb4659565a4e8efe7f0a71b19262a" + integrity sha512-5GOxGT7lZN+I8A7Vp0rWY+726FDKEw8HnFiebe51rQrMbfGfCu2Aw9uSM0nT9OG6xhV6WvGccIcCszTPs4fUZQ== -"@sentry/browser@9.3.0": - version "9.3.0" - resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-9.3.0.tgz#270e93c0f1bc10abb6651255bcaa30ba21c4928a" - integrity sha512-yPwWWQo/hpN63p0NGmk/Dd1Fx5CQRWNMfuV7dtfPBtg3vRjDecA9OLyK29AqK5h3Fl8FuJOyOqB87CvtXUqh5g== +"@sentry/browser@9.13.0": + version "9.13.0" + resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-9.13.0.tgz#76cf662656c7c7ddfd36081b6e8ba05c385fe823" + integrity sha512-KiC8s9/6HvdlfCRqA420YbiBiXMBif7GYESJ8VQqOKUmlPczn8V2CRrEZjMqxhlHdIGiR0PS6jb2VSgeJBchJQ== dependencies: - "@sentry-internal/browser-utils" "9.3.0" - "@sentry-internal/feedback" "9.3.0" - "@sentry-internal/replay" "9.3.0" - "@sentry-internal/replay-canvas" "9.3.0" - "@sentry/core" "9.3.0" + "@sentry-internal/browser-utils" "9.13.0" + "@sentry-internal/feedback" "9.13.0" + "@sentry-internal/replay" "9.13.0" + "@sentry-internal/replay-canvas" "9.13.0" + "@sentry/core" "9.13.0" -"@sentry/bundler-plugin-core@3.1.2": - version "3.1.2" - resolved "https://registry.yarnpkg.com/@sentry/bundler-plugin-core/-/bundler-plugin-core-3.1.2.tgz#29e4e686c5893b41a0d98a1bef6f0315a610bd59" - integrity sha512-lqOCvmOPzKiQenIMhmm5/mwCntwFy0dPZbVD28Dnr3MXpT1rIBg1HXjfnqQWFlMRbL9haSsWiY/TQyR/6b30YA== +"@sentry/bundler-plugin-core@3.3.1": + version "3.3.1" + resolved "https://registry.yarnpkg.com/@sentry/bundler-plugin-core/-/bundler-plugin-core-3.3.1.tgz#67c5017dc8a70f629c14e88420c6ede4e51c2047" + integrity sha512-Dd6xaWb293j9otEJ1yJqG2Ra6zB49OPzMNdIkdP8wdY+S9UFQE5PyKTyredmPY7hqCc005OrUQZolIIo9Zl13A== dependencies: "@babel/core" "^7.18.5" - "@sentry/babel-plugin-component-annotate" "3.1.2" - "@sentry/cli" "2.41.1" + "@sentry/babel-plugin-component-annotate" "3.3.1" + "@sentry/cli" "2.42.2" dotenv "^16.3.1" find-up "^5.0.0" glob "^9.3.2" magic-string "0.30.8" unplugin "1.0.1" -"@sentry/cli-darwin@2.41.1": - version "2.41.1" - resolved "https://registry.yarnpkg.com/@sentry/cli-darwin/-/cli-darwin-2.41.1.tgz#ca7e12bf1ad59bc2df35868ae98abc8869108efa" - integrity sha512-7pS3pu/SuhE6jOn3wptstAg6B5nUP878O6s+2svT7b5fKNfYUi/6NPK6dAveh2Ca0rwVq40TO4YFJabWMgTpdQ== - -"@sentry/cli-linux-arm64@2.41.1": - version "2.41.1" - resolved "https://registry.yarnpkg.com/@sentry/cli-linux-arm64/-/cli-linux-arm64-2.41.1.tgz#948e8af8290418b1562db3531db08e69e39d74bb" - integrity sha512-EzYCEnnENBnS5kpNW+2dBcrPZn1MVfywh2joGVQZTpmgDL5YFJ59VOd+K0XuEwqgFI8BSNI14KXZ75s4DD1/Vw== - -"@sentry/cli-linux-arm@2.41.1": - version "2.41.1" - resolved "https://registry.yarnpkg.com/@sentry/cli-linux-arm/-/cli-linux-arm-2.41.1.tgz#1e5fa971ae8dfb3ea5564c8503b4e635ae6aed8a" - integrity sha512-wNUvquD6qjOCczvuBGf9OiD29nuQ6yf8zzfyPJa5Bdx1QXuteKsKb6HBrMwuIR3liyuu0duzHd+H/+p1n541Hg== - -"@sentry/cli-linux-i686@2.41.1": - version "2.41.1" - resolved "https://registry.yarnpkg.com/@sentry/cli-linux-i686/-/cli-linux-i686-2.41.1.tgz#3f01aff314f2ad8fd761f3e6e807a5ec09ae4eb4" - integrity sha512-urpQCWrdYnSAsZY3udttuMV88wTJzKZL10xsrp7sjD/Hd+O6qSLVLkxebIlxts70jMLLFHYrQ2bkRg5kKuX6Fg== - -"@sentry/cli-linux-x64@2.41.1": - version "2.41.1" - resolved "https://registry.yarnpkg.com/@sentry/cli-linux-x64/-/cli-linux-x64-2.41.1.tgz#30dbf966a4b4c1721ffccd901dfcb6f967db073d" - integrity sha512-ZqpYwHXAaK4MMEFlyaLYr6mJTmpy9qP6n30jGhLTW7kHKS3s6GPLCSlNmIfeClrInEt0963fM633ZRnXa04VPw== - -"@sentry/cli-win32-i686@2.41.1": - version "2.41.1" - resolved "https://registry.yarnpkg.com/@sentry/cli-win32-i686/-/cli-win32-i686-2.41.1.tgz#f88eeb5d2d4ee46c38d8616ae1eb484108ea71c2" - integrity sha512-AuRimCeVsx99DIOr9cwdYBHk39tlmAuPDdy2r16iNzY0InXs4xOys4gGzM7N4vlFQvFkzuc778Su0HkfasgprA== - -"@sentry/cli-win32-x64@2.41.1": - version "2.41.1" - resolved "https://registry.yarnpkg.com/@sentry/cli-win32-x64/-/cli-win32-x64-2.41.1.tgz#eefd95a2aa184adb464334e265b55a9142070f6f" - integrity sha512-6JcPvXGye61+wPp0xdzfc2YLE/Dcud8JdaK8VxLM3b/8+Em7E+UyliDu3uF8+YGUqizY5JYTd3fs17DC8DZhLw== - -"@sentry/cli@2.41.1": - version "2.41.1" - resolved "https://registry.yarnpkg.com/@sentry/cli/-/cli-2.41.1.tgz#a9467ca3ff4acfcdedec1565c9ff726b93758d29" - integrity sha512-0GVmDiTV7R1492wkVY4bGcfC0fSmRmQjuxaaPI8CIV9B2VP9pBVCUizi1mevXaaE4I3fM60LI+XYrKFEneuVog== +"@sentry/cli-darwin@2.42.2": + version "2.42.2" + resolved "https://registry.yarnpkg.com/@sentry/cli-darwin/-/cli-darwin-2.42.2.tgz#a32a4f226e717122b37d9969e8d4d0e14779f720" + integrity sha512-GtJSuxER7Vrp1IpxdUyRZzcckzMnb4N5KTW7sbTwUiwqARRo+wxS+gczYrS8tdgtmXs5XYhzhs+t4d52ITHMIg== + +"@sentry/cli-linux-arm64@2.42.2": + version "2.42.2" + resolved "https://registry.yarnpkg.com/@sentry/cli-linux-arm64/-/cli-linux-arm64-2.42.2.tgz#1c06c83ff21f51ec23acf5be3b1f8c7553bf86b1" + integrity sha512-BOxzI7sgEU5Dhq3o4SblFXdE9zScpz6EXc5Zwr1UDZvzgXZGosUtKVc7d1LmkrHP8Q2o18HcDWtF3WvJRb5Zpw== + +"@sentry/cli-linux-arm@2.42.2": + version "2.42.2" + resolved "https://registry.yarnpkg.com/@sentry/cli-linux-arm/-/cli-linux-arm-2.42.2.tgz#00cadc359ae3c051efb3e63873c033c61dbd1ca1" + integrity sha512-7udCw+YL9lwq+9eL3WLspvnuG+k5Icg92YE7zsteTzWLwgPVzaxeZD2f8hwhsu+wmL+jNqbpCRmktPteh3i2mg== + +"@sentry/cli-linux-i686@2.42.2": + version "2.42.2" + resolved "https://registry.yarnpkg.com/@sentry/cli-linux-i686/-/cli-linux-i686-2.42.2.tgz#3b817b715dd806c20dfbffd539725ad8089c310a" + integrity sha512-Sw/dQp5ZPvKnq3/y7wIJyxTUJYPGoTX/YeMbDs8BzDlu9to2LWV3K3r7hE7W1Lpbaw4tSquUHiQjP5QHCOS7aQ== + +"@sentry/cli-linux-x64@2.42.2": + version "2.42.2" + resolved "https://registry.yarnpkg.com/@sentry/cli-linux-x64/-/cli-linux-x64-2.42.2.tgz#ddf906bc3071cc79ce6e633eddcb76bb9068e688" + integrity sha512-mU4zUspAal6TIwlNLBV5oq6yYqiENnCWSxtSQVzWs0Jyq97wtqGNG9U+QrnwjJZ+ta/hvye9fvL2X25D/RxHQw== + +"@sentry/cli-win32-i686@2.42.2": + version "2.42.2" + resolved "https://registry.yarnpkg.com/@sentry/cli-win32-i686/-/cli-win32-i686-2.42.2.tgz#9036085c7c6ce455ad45fda411c55ff39c06eb95" + integrity sha512-iHvFHPGqgJMNqXJoQpqttfsv2GI3cGodeTq4aoVLU/BT3+hXzbV0x1VpvvEhncJkDgDicJpFLM8sEPHb3b8abw== + +"@sentry/cli-win32-x64@2.42.2": + version "2.42.2" + resolved "https://registry.yarnpkg.com/@sentry/cli-win32-x64/-/cli-win32-x64-2.42.2.tgz#7d6464b63f32c9f97fff428f246b1f039b402233" + integrity sha512-vPPGHjYoaGmfrU7xhfFxG7qlTBacroz5NdT+0FmDn6692D8IvpNXl1K+eV3Kag44ipJBBeR8g1HRJyx/F/9ACw== + +"@sentry/cli@2.42.2": + version "2.42.2" + resolved "https://registry.yarnpkg.com/@sentry/cli/-/cli-2.42.2.tgz#8173df4d057d600a9ef0cf1e9b42b0c6607b46e4" + integrity sha512-spb7S/RUumCGyiSTg8DlrCX4bivCNmU/A1hcfkwuciTFGu8l5CDc2I6jJWWZw8/0enDGxuj5XujgXvU5tr4bxg== dependencies: https-proxy-agent "^5.0.0" node-fetch "^2.6.7" @@ -5490,43 +7030,43 @@ proxy-from-env "^1.1.0" which "^2.0.2" optionalDependencies: - "@sentry/cli-darwin" "2.41.1" - "@sentry/cli-linux-arm" "2.41.1" - "@sentry/cli-linux-arm64" "2.41.1" - "@sentry/cli-linux-i686" "2.41.1" - "@sentry/cli-linux-x64" "2.41.1" - "@sentry/cli-win32-i686" "2.41.1" - "@sentry/cli-win32-x64" "2.41.1" - -"@sentry/core@9.3.0": - version "9.3.0" - resolved "https://registry.yarnpkg.com/@sentry/core/-/core-9.3.0.tgz#d5a1ab7deecd95f86316e658129d3874557cbfd9" - integrity sha512-SxQ4z7wTkfguvYb2ctNEMU9kVAbhl9ymfjhLnrvtygTwL5soLqAKdco/lX/4P9K9Osgb2Dl6urQWRl+AhzKVbQ== - -"@sentry/nextjs@9.3.0": - version "9.3.0" - resolved "https://registry.yarnpkg.com/@sentry/nextjs/-/nextjs-9.3.0.tgz#2b589188e5a6e1a1af36f50e51612b4a66c43ed1" - integrity sha512-t4kSVX6B+ECmZxyiUjawzdZ9CQlaJA30Hctlxps76QMussmFyKhlmrT9L4+wGRllytCE3cUpryRYdy8SyIpSvg== + "@sentry/cli-darwin" "2.42.2" + "@sentry/cli-linux-arm" "2.42.2" + "@sentry/cli-linux-arm64" "2.42.2" + "@sentry/cli-linux-i686" "2.42.2" + "@sentry/cli-linux-x64" "2.42.2" + "@sentry/cli-win32-i686" "2.42.2" + "@sentry/cli-win32-x64" "2.42.2" + +"@sentry/core@9.13.0": + version "9.13.0" + resolved "https://registry.yarnpkg.com/@sentry/core/-/core-9.13.0.tgz#3269cab4ba34fa0928f04936ddb82182069cb568" + integrity sha512-Zn1Qec5XNkNRE/M5QjL6YJLghETg6P188G/v2OzdHdHIRf0Y58/SnJilu3louF+ogos6kaSqqdMgzqKgZ8tCdg== + +"@sentry/nextjs@9.13.0": + version "9.13.0" + resolved "https://registry.yarnpkg.com/@sentry/nextjs/-/nextjs-9.13.0.tgz#f6ad50c6c59324dd438f16df5d4fc6f5999859a0" + integrity sha512-7ShYoSewbF3nEeN4JzGlAaWOcQFe3iXOsIb84NXPGoWUv5r378ChRIWeN93CVXOvmG6RIMv0L/yRXKU3qjzkHQ== dependencies: "@opentelemetry/api" "^1.9.0" "@opentelemetry/semantic-conventions" "^1.30.0" "@rollup/plugin-commonjs" "28.0.1" - "@sentry-internal/browser-utils" "9.3.0" - "@sentry/core" "9.3.0" - "@sentry/node" "9.3.0" - "@sentry/opentelemetry" "9.3.0" - "@sentry/react" "9.3.0" - "@sentry/vercel-edge" "9.3.0" - "@sentry/webpack-plugin" "3.1.2" + "@sentry-internal/browser-utils" "9.13.0" + "@sentry/core" "9.13.0" + "@sentry/node" "9.13.0" + "@sentry/opentelemetry" "9.13.0" + "@sentry/react" "9.13.0" + "@sentry/vercel-edge" "9.13.0" + "@sentry/webpack-plugin" "3.3.1" chalk "3.0.0" resolve "1.22.8" - rollup "3.29.5" + rollup "4.35.0" stacktrace-parser "^0.1.10" -"@sentry/node@9.3.0": - version "9.3.0" - resolved "https://registry.yarnpkg.com/@sentry/node/-/node-9.3.0.tgz#fe262a72c6dff0166673ee92247bfdcd0f8598be" - integrity sha512-XzphoVImlKh+wjeKYSaZlH4aQVuw8I63RH6juCktMBKnjTfR9aZkHWeiFc4YghHU2jPXjKTKvGFRkU45xIGr1g== +"@sentry/node@9.13.0": + version "9.13.0" + resolved "https://registry.yarnpkg.com/@sentry/node/-/node-9.13.0.tgz#5b345c3400e88415617ba52a03b269c3a621a928" + integrity sha512-75UVkrED5b0BaazNQKCmF8NqeqjErxildPojDyC037JN+cVFMPr/kFFGGm7E+eCvA/j2pAPUzqifHp/PjykPcw== dependencies: "@opentelemetry/api" "^1.9.0" "@opentelemetry/context-async-hooks" "^1.30.1" @@ -5558,50 +7098,50 @@ "@opentelemetry/resources" "^1.30.1" "@opentelemetry/sdk-trace-base" "^1.30.1" "@opentelemetry/semantic-conventions" "^1.30.0" - "@prisma/instrumentation" "6.4.1" - "@sentry/core" "9.3.0" - "@sentry/opentelemetry" "9.3.0" + "@prisma/instrumentation" "6.5.0" + "@sentry/core" "9.13.0" + "@sentry/opentelemetry" "9.13.0" import-in-the-middle "^1.13.0" -"@sentry/opentelemetry@9.3.0": - version "9.3.0" - resolved "https://registry.yarnpkg.com/@sentry/opentelemetry/-/opentelemetry-9.3.0.tgz#cfc87ab74b76215db9d1c99c227b7f31f289618f" - integrity sha512-kvHj0n0Gk5H482dU6UH+UrccMBPqbjYadwNdb61kMNy5H/xkFcCDKZ8wm3TawlnuiPxzzf4orofiR6Pn/IW6uA== +"@sentry/opentelemetry@9.13.0": + version "9.13.0" + resolved "https://registry.yarnpkg.com/@sentry/opentelemetry/-/opentelemetry-9.13.0.tgz#5c04e9b391cf4085aa05b5e7a08b5c6220ac5dd4" + integrity sha512-TLSP0n+sXKVcVkAM2ttVmXcAT2K3e9D5gdPfr6aCnW+KIGJuD7wzla/TIcTWFaVwUejbvXAB6IFpZ/qA8HFwyA== dependencies: - "@sentry/core" "9.3.0" + "@sentry/core" "9.13.0" -"@sentry/profiling-node@9.3.0": - version "9.3.0" - resolved "https://registry.yarnpkg.com/@sentry/profiling-node/-/profiling-node-9.3.0.tgz#c7c8854a07c4e9abd2bd261856780e4177b0bc36" - integrity sha512-pwuJFP/yFXskJgrDGqaBEnrskQwEA75SurJ47ezp2pda2lR7cyQb7Lr7y8AaJx/jnv0tFIoWxgPqj6DVT+1rVw== +"@sentry/profiling-node@9.13.0": + version "9.13.0" + resolved "https://registry.yarnpkg.com/@sentry/profiling-node/-/profiling-node-9.13.0.tgz#54cb684ebbbaac9523c9a4fc180a800a35504684" + integrity sha512-bg5ypu6csGTdMjI5u6EW5RbIloAXHm5GvvqYYnGOt8V2p2jHPmShtxY6JXcOJ7CflNuZDknh6z58/m0T8HJ3zw== dependencies: "@sentry-internal/node-cpu-profiler" "^2.0.0" - "@sentry/core" "9.3.0" - "@sentry/node" "9.3.0" + "@sentry/core" "9.13.0" + "@sentry/node" "9.13.0" -"@sentry/react@9.3.0": - version "9.3.0" - resolved "https://registry.yarnpkg.com/@sentry/react/-/react-9.3.0.tgz#7f456c7b076f4cb75bc0617edb3c5599ded16e77" - integrity sha512-/ruDHBHLDXmZoEHNCSjdekZr9+0pbOC5+BY1oABGoDXRISGyoenOBtAsX8TsaC9oJYhr16yKDFlYxzzQRhxDyg== +"@sentry/react@9.13.0": + version "9.13.0" + resolved "https://registry.yarnpkg.com/@sentry/react/-/react-9.13.0.tgz#8dc7b7d05b3e33984dc70162b584dc42c0413495" + integrity sha512-CpJ23YoFmb3sY3NZ3g/6GEqwXhfEZMz+X1nZvu7RC0aB9Psdtk5sZmoqhWwveeEwVFBNq66QxSeSBvwODLergA== dependencies: - "@sentry/browser" "9.3.0" - "@sentry/core" "9.3.0" + "@sentry/browser" "9.13.0" + "@sentry/core" "9.13.0" hoist-non-react-statics "^3.3.2" -"@sentry/vercel-edge@9.3.0": - version "9.3.0" - resolved "https://registry.yarnpkg.com/@sentry/vercel-edge/-/vercel-edge-9.3.0.tgz#8a4328e97b01538f04c298a25ed2b84bdc24d45c" - integrity sha512-zqtd5L2sn4yGdxvMDEHUI6+7blkO305w2ATPz06jwChS6oCKoSHZfrLPZygChKhk9bzM1D6IWg/3uyGdntfj/A== +"@sentry/vercel-edge@9.13.0": + version "9.13.0" + resolved "https://registry.yarnpkg.com/@sentry/vercel-edge/-/vercel-edge-9.13.0.tgz#7bdc1709292142fb0a708ae8db3e963db7567d31" + integrity sha512-lYqnmJp7YcvVTCN0/YG8DSkVSE5Zl6qqgkQz5UG6Ya7Ou+4uisJYGWoJhRynmMT6V/Btp1iqkiIjV3k3dwq5gg== dependencies: "@opentelemetry/api" "^1.9.0" - "@sentry/core" "9.3.0" + "@sentry/core" "9.13.0" -"@sentry/webpack-plugin@3.1.2": - version "3.1.2" - resolved "https://registry.yarnpkg.com/@sentry/webpack-plugin/-/webpack-plugin-3.1.2.tgz#e7cf2b10b6d2fb2d6106e692469d02b6ab684bba" - integrity sha512-BTG1m+5c3PcuzjUphB7vQESo91VdT8FT+Ngzbf58OOTtiMDEJ35FtJX1ww36QE7G6vlSpdT/NyZKsY6t+mgJfg== +"@sentry/webpack-plugin@3.3.1": + version "3.3.1" + resolved "https://registry.yarnpkg.com/@sentry/webpack-plugin/-/webpack-plugin-3.3.1.tgz#b257e1cb5f939b68f5050e9c4ea040d7366a55de" + integrity sha512-AFRnGNUnlIvq3M+ADdfWb+DIXWKK6yYEkVPAyOppkjO+cL/19gjXMdvAwv+CMFts28YCFKF8Kr3pamUiCmwodA== dependencies: - "@sentry/bundler-plugin-core" "3.1.2" + "@sentry/bundler-plugin-core" "3.3.1" unplugin "1.0.1" uuid "^9.0.0" @@ -5808,36 +7348,36 @@ dependencies: tslib "^2.8.0" -"@tanstack/eslint-plugin-query@5.66.1": - version "5.66.1" - resolved "https://registry.yarnpkg.com/@tanstack/eslint-plugin-query/-/eslint-plugin-query-5.66.1.tgz#9951e4d3633ca6248196742cad437b4d7c760cd7" - integrity sha512-pYMVTGgJ7yPk9Rm6UWEmbY6TX0EmMmxJqYkthgeDCwEznToy2m+W928nUODFirtZBZlhBsqHy33LO0kyTlgf0w== +"@tanstack/eslint-plugin-query@5.73.3": + version "5.73.3" + resolved "https://registry.yarnpkg.com/@tanstack/eslint-plugin-query/-/eslint-plugin-query-5.73.3.tgz#55e3083fe4caa889de9a858e24cbdaa7cade741b" + integrity sha512-GmUtnOkRzDuNOq96g3eW5ADKC1nWfrM9RI0kRyQVr87rOl6y+PUgkuVaPxh3R2C0EVODxCS07b9aaWphidl/OA== dependencies: "@typescript-eslint/utils" "^8.18.1" -"@tanstack/query-core@5.67.1": - version "5.67.1" - resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-5.67.1.tgz#419e8a94acd773d63cf4746d3df842c3329f56c2" - integrity sha512-AkFmuukVejyqVIjEQoFhLb3q+xHl7JG8G9cANWTMe3s8iKzD9j1VBSYXgCjy6vm6xM8cUCR9zP2yqWxY9pTWOA== +"@tanstack/query-core@5.74.4": + version "5.74.4" + resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-5.74.4.tgz#08c4f88f336738d822d9242c5e7d2be50f5c25b3" + integrity sha512-YuG0A0+3i9b2Gfo9fkmNnkUWh5+5cFhWBN0pJAHkHilTx6A0nv8kepkk4T4GRt4e5ahbtFj2eTtkiPcVU1xO4A== -"@tanstack/query-devtools@5.65.0": - version "5.65.0" - resolved "https://registry.yarnpkg.com/@tanstack/query-devtools/-/query-devtools-5.65.0.tgz#37da5e911543b4f6d98b9a04369eab0de6044ba1" - integrity sha512-g5y7zc07U9D3esMdqUfTEVu9kMHoIaVBsD0+M3LPdAdD710RpTcLiNvJY1JkYXqkq9+NV+CQoemVNpQPBXVsJg== +"@tanstack/query-devtools@5.73.3": + version "5.73.3" + resolved "https://registry.yarnpkg.com/@tanstack/query-devtools/-/query-devtools-5.73.3.tgz#8fc9872ed4408964b2c560d811caee491cfbdc3c" + integrity sha512-hBQyYwsOuO7QOprK75NzfrWs/EQYjgFA0yykmcvsV62q0t6Ua97CU3sYgjHx0ZvxkXSOMkY24VRJ5uv9f5Ik4w== -"@tanstack/react-query-devtools@5.67.1": - version "5.67.1" - resolved "https://registry.yarnpkg.com/@tanstack/react-query-devtools/-/react-query-devtools-5.67.1.tgz#1346bc5286a7da6c347278c202da58108e910130" - integrity sha512-a/2I8ORNalh+ek6Nyb9mEiq2u7vydjVMvaQz5ZieGq7r7DxgIFcPiMs4Ay0qkQvHfptESgXR5nImGTHmmt19yQ== +"@tanstack/react-query-devtools@5.74.4": + version "5.74.4" + resolved "https://registry.yarnpkg.com/@tanstack/react-query-devtools/-/react-query-devtools-5.74.4.tgz#743985734fa4b448914013134e9e6d1a62299f66" + integrity sha512-PGCAcytQMmeagoeGG45ccBhrC1x0/5OlNjsM1FAb9OfsQZIhPzjwjhGcwmMu6TbT4RIHgvjxLwC5NHgkUwJQzw== dependencies: - "@tanstack/query-devtools" "5.65.0" + "@tanstack/query-devtools" "5.73.3" -"@tanstack/react-query@5.67.1": - version "5.67.1" - resolved "https://registry.yarnpkg.com/@tanstack/react-query/-/react-query-5.67.1.tgz#040b2e2fe60681f8c1f69f2378f0d43d9533af51" - integrity sha512-fH5u4JLwB6A+wLFdi8wWBWAYoJV5deYif2OveJ26ktAWjU499uvVFS1wPWnyEyq5LvZX1MZInvv9QRaIZANRaQ== +"@tanstack/react-query@5.74.4": + version "5.74.4" + resolved "https://registry.yarnpkg.com/@tanstack/react-query/-/react-query-5.74.4.tgz#d73ee1899c08a227519cbf53b9a0e0b1e67cd3fe" + integrity sha512-mAbxw60d4ffQ4qmRYfkO1xzRBPUEf/72Dgo3qqea0J66nIKuDTLEqQt0ku++SDFlMGMnB6uKDnEG1xD/TDse4Q== dependencies: - "@tanstack/query-core" "5.67.1" + "@tanstack/query-core" "5.74.4" "@tanstack/react-table@8.20.6": version "8.20.6" @@ -5878,10 +7418,10 @@ lodash "^4.17.21" redent "^3.0.0" -"@testing-library/react@16.2.0": - version "16.2.0" - resolved "https://registry.yarnpkg.com/@testing-library/react/-/react-16.2.0.tgz#c96126ee01a49cdb47175721911b4a9432afc601" - integrity sha512-2cSskAvA1QNtKc8Y9VJQRv0tm3hLVgxRGDB+KYhIaPQJ1I+RHbhIXcM+zClKXzMes/wshsMVzf4B9vS4IZpqDQ== +"@testing-library/react@16.3.0": + version "16.3.0" + resolved "https://registry.yarnpkg.com/@testing-library/react/-/react-16.3.0.tgz#3a85bb9bdebf180cd76dba16454e242564d598a6" + integrity sha512-kFSyxiEDwv1WLl2fgsq6pPBbw5aWKrsY2/noi1Id0TK0UParSF62oFQFGHXIyaG4pp2tEub/Zlel+fjjZILDsw== dependencies: "@babel/runtime" "^7.12.5" @@ -6149,7 +7689,7 @@ "@types/estree" "*" "@types/json-schema" "*" -"@types/estree@*", "@types/estree@^1.0.0", "@types/estree@^1.0.6": +"@types/estree@*", "@types/estree@1.0.6", "@types/estree@^1.0.0", "@types/estree@^1.0.6": version "1.0.6" resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.6.tgz#628effeeae2064a1b4e79f78e81d87b7e5fc7b50" integrity sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw== @@ -6178,7 +7718,7 @@ "@types/express-serve-static-core" "*" "@types/ws" "*" -"@types/express@*", "@types/express@5.0.0": +"@types/express@*": version "5.0.0" resolved "https://registry.yarnpkg.com/@types/express/-/express-5.0.0.tgz#13a7d1f75295e90d19ed6e74cab3678488eaa96c" integrity sha512-DvZriSMehGHL1ZNLzi6MidnsDhUZM/x2pRdDIKdwbUNqqwHxMlRdkxtn6/EPKyqKpHqTl/4nRZsRNLpZxZRpPQ== @@ -6188,6 +7728,15 @@ "@types/qs" "*" "@types/serve-static" "*" +"@types/express@5.0.1": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@types/express/-/express-5.0.1.tgz#138d741c6e5db8cc273bec5285cd6e9d0779fc9f" + integrity sha512-UZUw8vjpWFXuDnjFTh7/5c2TWDlQqeXHi6hcN7F2XSVT5P+WmUnnbFS3KA6Jnc6IsEqI2qCVu2bK0R0J4A8ZQQ== + dependencies: + "@types/body-parser" "*" + "@types/express-serve-static-core" "^5.0.0" + "@types/serve-static" "*" + "@types/extend@^3.0.0": version "3.0.4" resolved "https://registry.yarnpkg.com/@types/extend/-/extend-3.0.4.tgz#5f9aa502299e1b9beb9ade57ea9e36898de0ff52" @@ -6275,10 +7824,10 @@ resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.17.16.tgz#94ae78fab4a38d73086e962d0b65c30d816bfb0a" integrity sha512-HX7Em5NYQAXKW+1T+FiuG27NGwzJfCX3s1GjOa7ujxZa52kjJLOr4FUxT+giF6Tgxv1e+/czV/iTtBw27WTU9g== -"@types/luxon@3.4.2": - version "3.4.2" - resolved "https://registry.yarnpkg.com/@types/luxon/-/luxon-3.4.2.tgz#e4fc7214a420173cea47739c33cdf10874694db7" - integrity sha512-TifLZlFudklWlMBfhubvgqTXRzLDI5pCbGa4P8a3wPyUQSW+1xQ5eDsreP9DWHX3tjq1ke96uYG/nwundroWcA== +"@types/luxon@3.6.2": + version "3.6.2" + resolved "https://registry.yarnpkg.com/@types/luxon/-/luxon-3.6.2.tgz#be6536931801f437eafcb9c0f6d6781f72308041" + integrity sha512-R/BdP7OxEMc44l2Ex5lSXHoIXTB2JLNa3y2QISIbr58U/YcsffyQrYW//hZSdrfxrjRZj3GcUoxMPGdO8gSYuw== "@types/markdown-it@^14.0.0": version "14.1.2" @@ -6334,12 +7883,12 @@ dependencies: "@types/node" "*" -"@types/node@*", "@types/node@22.10.7", "@types/node@22.13.9", "@types/node@^22.7.5": - version "22.13.9" - resolved "https://registry.yarnpkg.com/@types/node/-/node-22.13.9.tgz#5d9a8f7a975a5bd3ef267352deb96fb13ec02eca" - integrity sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw== +"@types/node@*", "@types/node@22.10.7", "@types/node@22.14.1", "@types/node@^22.7.5": + version "22.14.1" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.14.1.tgz#53b54585cec81c21eee3697521e31312d6ca1e6f" + integrity sha512-u0HuPQwe/dHrItgHHpmw3N2fYCR6x4ivMNbPHRkBVP4CvN+kiRrKHWk3i8tXiO/joPwXLMYvF9TTF0eqgHIuOw== dependencies: - undici-types "~6.20.0" + undici-types "~6.21.0" "@types/parse-json@^4.0.0": version "4.0.2" @@ -6351,10 +7900,12 @@ resolved "https://registry.yarnpkg.com/@types/parse5/-/parse5-6.0.3.tgz#705bb349e789efa06f43f128cef51240753424cb" integrity sha512-SuT16Q1K51EAVPz1K29DJ/sXjhSQ0zjvsypYJ6tlwVsRV9jwW5Adq2ch8Dq8kDBCkYnELS7N7VNCSB5nC56t/g== -"@types/pdf-parse@1.1.4": - version "1.1.4" - resolved "https://registry.yarnpkg.com/@types/pdf-parse/-/pdf-parse-1.1.4.tgz#21a539efd2f16009d08aeed3350133948b5d7ed1" - integrity sha512-+gbBHbNCVGGYw1S9lAIIvrHW47UYOhMIFUsJcMkMrzy1Jf0vulBN3XQIjPgnoOXveMuHnF3b57fXROnY/Or7eg== +"@types/pdf-parse@1.1.5": + version "1.1.5" + resolved "https://registry.yarnpkg.com/@types/pdf-parse/-/pdf-parse-1.1.5.tgz#a0959022604457169177622b512ed03b975f10e2" + integrity sha512-kBfrSXsloMnUJOKi25s3+hRmkycHfLK6A09eRGqF/N8BkQoPUmaCr+q8Cli5FnfohEz/rsv82zAiPz/LXtOGhA== + dependencies: + "@types/node" "*" "@types/pg-pool@2.0.6": version "2.0.6" @@ -6396,12 +7947,10 @@ resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.7.tgz#50ae4353eaaddc04044279812f52c8c65857dbcb" integrity sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ== -"@types/react-dom@*", "@types/react-dom@19.0.0": - version "19.0.0" - resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-19.0.0.tgz#e7f5d618a080486eaf9952246dbf59eaa2c64130" - integrity sha512-1KfiQKsH1o00p9m5ag12axHQSb3FOU9H20UTrujVSkNhuCrRHiQWFqgEnTNK5ZNfnzZv8UWrnXVqCmCF9fgY3w== - dependencies: - "@types/react" "*" +"@types/react-dom@*", "@types/react-dom@19.1.2": + version "19.1.2" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-19.1.2.tgz#bd1fe3b8c28a3a2e942f85314dcfb71f531a242f" + integrity sha512-XGJkWF41Qq305SKWEILa1O8vzhb3aOo3ogBlSmiqNko/WmRb6QIaweuZCXjKygVDXpzXb5wyxKTSOsmkuqj+Qw== "@types/react-modal@3.16.3": version "3.16.3" @@ -6415,10 +7964,10 @@ resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.12.tgz#b5d76568485b02a307238270bfe96cb51ee2a044" integrity sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w== -"@types/react@*", "@types/react@19.0.0": - version "19.0.0" - resolved "https://registry.yarnpkg.com/@types/react/-/react-19.0.0.tgz#fbbb53ce223f4e2b750ad5dd09580b2c43522bbf" - integrity sha512-MY3oPudxvMYyesqs/kW1Bh8y9VqSmf+tzqw3ae8a9DZW68pUe3zAdHeI1jc6iAysuRdACnVknHP8AhwD4/dxtg== +"@types/react@*", "@types/react@19.1.2": + version "19.1.2" + resolved "https://registry.yarnpkg.com/@types/react/-/react-19.1.2.tgz#11df86f66f188f212c90ecb537327ec68bfd593f" + integrity sha512-oxLPMytKchWGbnQM9O7D67uPa9paTNxO7jVoNMXgkkErULBPhPARCfkKL9ytcIJJRGjbsVwW4ugJzyFFvm/Tiw== dependencies: csstype "^3.0.2" @@ -6469,10 +8018,10 @@ "@types/node" "*" form-data "^4.0.0" -"@types/supertest@6.0.2": - version "6.0.2" - resolved "https://registry.yarnpkg.com/@types/supertest/-/supertest-6.0.2.tgz#2af1c466456aaf82c7c6106c6b5cbd73a5e86588" - integrity sha512-137ypx2lk/wTQbW6An6safu9hXmajAifU/s7szAHLN/FeIm5w7yR0Wkl9fdJMRSHwOn4HLAI0DaB2TOORuhPDg== +"@types/supertest@6.0.3": + version "6.0.3" + resolved "https://registry.yarnpkg.com/@types/supertest/-/supertest-6.0.3.tgz#d736f0e994b195b63e1c93e80271a2faf927388c" + integrity sha512-8WzXq62EXFhJ7QsH3Ocb/iKQ/Ty9ZVWnVzoTKc9tyyFRRF3a74Tk2+TLFgaFFw364Ere+npzHKEJ6ga2LzIL7w== dependencies: "@types/methods" "^1.1.4" "@types/superagent" "^8.1.0" @@ -6514,13 +8063,20 @@ resolved "https://registry.yarnpkg.com/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz#60be8d21baab8c305132eb9cb912ed497852aadc" integrity sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg== -"@types/ws@*", "@types/ws@8.5.14": +"@types/ws@*": version "8.5.14" resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.14.tgz#93d44b268c9127d96026cf44353725dd9b6c3c21" integrity sha512-bd/YFLW+URhBzMXurx7lWByOu+xzU9+kb3RboOteXYDfW+tr+JZa99OyNmPINEGB/ahzKrEuc8rcv4gnpJmxTw== dependencies: "@types/node" "*" +"@types/ws@8.18.1": + version "8.18.1" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.18.1.tgz#48464e4bf2ddfd17db13d845467f6070ffea4aa9" + integrity sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg== + dependencies: + "@types/node" "*" + "@types/yargs-parser@*": version "21.0.3" resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.3.tgz#815e30b786d2e8f0dcd85fd5bcf5e1a04d008f15" @@ -6533,30 +8089,30 @@ dependencies: "@types/yargs-parser" "*" -"@typescript-eslint/eslint-plugin@*", "@typescript-eslint/eslint-plugin@8.26.0", "@typescript-eslint/eslint-plugin@^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0": - version "8.26.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.26.0.tgz#7e880faf91f89471c30c141951e15f0eb3a0599e" - integrity sha512-cLr1J6pe56zjKYajK6SSSre6nl1Gj6xDp1TY0trpgPzjVbgDwd09v2Ws37LABxzkicmUjhEeg/fAUjPJJB1v5Q== +"@typescript-eslint/eslint-plugin@*", "@typescript-eslint/eslint-plugin@8.31.0", "@typescript-eslint/eslint-plugin@^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0": + version "8.31.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.31.0.tgz#ef3ece95406a80026f82a19a2984c1e375981711" + integrity sha512-evaQJZ/J/S4wisevDvC1KFZkPzRetH8kYZbkgcTRyql3mcKsf+ZFDV1BVWUGTCAW5pQHoqn5gK5b8kn7ou9aFQ== dependencies: "@eslint-community/regexpp" "^4.10.0" - "@typescript-eslint/scope-manager" "8.26.0" - "@typescript-eslint/type-utils" "8.26.0" - "@typescript-eslint/utils" "8.26.0" - "@typescript-eslint/visitor-keys" "8.26.0" + "@typescript-eslint/scope-manager" "8.31.0" + "@typescript-eslint/type-utils" "8.31.0" + "@typescript-eslint/utils" "8.31.0" + "@typescript-eslint/visitor-keys" "8.31.0" graphemer "^1.4.0" ignore "^5.3.1" natural-compare "^1.4.0" ts-api-utils "^2.0.1" -"@typescript-eslint/parser@*", "@typescript-eslint/parser@8.26.0", "@typescript-eslint/parser@^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0": - version "8.26.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.26.0.tgz#9b4d2198e89f64fb81e83167eedd89a827d843a9" - integrity sha512-mNtXP9LTVBy14ZF3o7JG69gRPBK/2QWtQd0j0oH26HcY/foyJJau6pNUez7QrM5UHnSvwlQcJXKsk0I99B9pOA== +"@typescript-eslint/parser@*", "@typescript-eslint/parser@8.31.0", "@typescript-eslint/parser@^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0": + version "8.31.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.31.0.tgz#5ec28823d06dd20ed5f67b61224823f12ccde095" + integrity sha512-67kYYShjBR0jNI5vsf/c3WG4u+zDnCTHTPqVMQguffaWWFs7artgwKmfwdifl+r6XyM5LYLas/dInj2T0SgJyw== dependencies: - "@typescript-eslint/scope-manager" "8.26.0" - "@typescript-eslint/types" "8.26.0" - "@typescript-eslint/typescript-estree" "8.26.0" - "@typescript-eslint/visitor-keys" "8.26.0" + "@typescript-eslint/scope-manager" "8.31.0" + "@typescript-eslint/types" "8.31.0" + "@typescript-eslint/typescript-estree" "8.31.0" + "@typescript-eslint/visitor-keys" "8.31.0" debug "^4.3.4" "@typescript-eslint/scope-manager@8.22.0", "@typescript-eslint/scope-manager@^8.15.0": @@ -6567,21 +8123,21 @@ "@typescript-eslint/types" "8.22.0" "@typescript-eslint/visitor-keys" "8.22.0" -"@typescript-eslint/scope-manager@8.26.0": - version "8.26.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.26.0.tgz#b06623fad54a3a77fadab5f652ef75ed3780b545" - integrity sha512-E0ntLvsfPqnPwng8b8y4OGuzh/iIOm2z8U3S9zic2TeMLW61u5IH2Q1wu0oSTkfrSzwbDJIB/Lm8O3//8BWMPA== +"@typescript-eslint/scope-manager@8.31.0": + version "8.31.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.31.0.tgz#48c7f7d729ea038e36cae0ff511e48c2412fb11c" + integrity sha512-knO8UyF78Nt8O/B64i7TlGXod69ko7z6vJD9uhSlm0qkAbGeRUSudcm0+K/4CrRjrpiHfBCjMWlc08Vav1xwcw== dependencies: - "@typescript-eslint/types" "8.26.0" - "@typescript-eslint/visitor-keys" "8.26.0" + "@typescript-eslint/types" "8.31.0" + "@typescript-eslint/visitor-keys" "8.31.0" -"@typescript-eslint/type-utils@8.26.0": - version "8.26.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.26.0.tgz#9ee8cc98184b5f66326578de9c097edc89da6f68" - integrity sha512-ruk0RNChLKz3zKGn2LwXuVoeBcUMh+jaqzN461uMMdxy5H9epZqIBtYj7UiPXRuOpaALXGbmRuZQhmwHhaS04Q== +"@typescript-eslint/type-utils@8.31.0": + version "8.31.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.31.0.tgz#01536a993fae23e2def885b006aaa991cbfbe9e7" + integrity sha512-DJ1N1GdjI7IS7uRlzJuEDCgDQix3ZVYVtgeWEyhyn4iaoitpMBX6Ndd488mXSx0xah/cONAkEaYyylDyAeHMHg== dependencies: - "@typescript-eslint/typescript-estree" "8.26.0" - "@typescript-eslint/utils" "8.26.0" + "@typescript-eslint/typescript-estree" "8.31.0" + "@typescript-eslint/utils" "8.31.0" debug "^4.3.4" ts-api-utils "^2.0.1" @@ -6590,10 +8146,10 @@ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.22.0.tgz#d9dec7116479ad03aeb6c8ac9c5223c4c79cf360" integrity sha512-0S4M4baNzp612zwpD4YOieP3VowOARgK2EkN/GBn95hpyF8E2fbMT55sRHWBq+Huaqk3b3XK+rxxlM8sPgGM6A== -"@typescript-eslint/types@8.26.0": - version "8.26.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.26.0.tgz#c4e93a8faf3a38a8d8adb007dc7834f1c89ee7bf" - integrity sha512-89B1eP3tnpr9A8L6PZlSjBvnJhWXtYfZhECqlBl1D9Lme9mHO6iWlsprBtVenQvY1HMhax1mWOjhtL3fh/u+pA== +"@typescript-eslint/types@8.31.0": + version "8.31.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.31.0.tgz#c48e20ec47a43b72747714f49ea9f7b38a4fa6c1" + integrity sha512-Ch8oSjVyYyJxPQk8pMiP2FFGYatqXQfQIaMp+TpuuLlDachRWpUAeEu1u9B/v/8LToehUIWyiKcA/w5hUFRKuQ== "@typescript-eslint/typescript-estree@8.22.0": version "8.22.0" @@ -6609,13 +8165,13 @@ semver "^7.6.0" ts-api-utils "^2.0.0" -"@typescript-eslint/typescript-estree@8.26.0": - version "8.26.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.26.0.tgz#128972172005a7376e34ed2ecba4e29363b0cad1" - integrity sha512-tiJ1Hvy/V/oMVRTbEOIeemA2XoylimlDQ03CgPPNaHYZbpsc78Hmngnt+WXZfJX1pjQ711V7g0H7cSJThGYfPQ== +"@typescript-eslint/typescript-estree@8.31.0": + version "8.31.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.31.0.tgz#9c7f84eff6ad23d63cf086c6e93af571cd561270" + integrity sha512-xLmgn4Yl46xi6aDSZ9KkyfhhtnYI15/CvHbpOy/eR5NWhK/BK8wc709KKwhAR0m4ZKRP7h07bm4BWUYOCuRpQQ== dependencies: - "@typescript-eslint/types" "8.26.0" - "@typescript-eslint/visitor-keys" "8.26.0" + "@typescript-eslint/types" "8.31.0" + "@typescript-eslint/visitor-keys" "8.31.0" debug "^4.3.4" fast-glob "^3.3.2" is-glob "^4.0.3" @@ -6623,15 +8179,15 @@ semver "^7.6.0" ts-api-utils "^2.0.1" -"@typescript-eslint/utils@8.26.0": - version "8.26.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.26.0.tgz#845d20ed8378a5594e6445f54e53b972aee7b3e6" - integrity sha512-2L2tU3FVwhvU14LndnQCA2frYC8JnPDVKyQtWFPf8IYFMt/ykEN1bPolNhNbCVgOmdzTlWdusCTKA/9nKrf8Ig== +"@typescript-eslint/utils@8.31.0": + version "8.31.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.31.0.tgz#6fb52471a29fdd16fc253d568c5ad4b048f78ba4" + integrity sha512-qi6uPLt9cjTFxAb1zGNgTob4x9ur7xC6mHQJ8GwEzGMGE9tYniublmJaowOJ9V2jUzxrltTPfdG2nKlWsq0+Ww== dependencies: "@eslint-community/eslint-utils" "^4.4.0" - "@typescript-eslint/scope-manager" "8.26.0" - "@typescript-eslint/types" "8.26.0" - "@typescript-eslint/typescript-estree" "8.26.0" + "@typescript-eslint/scope-manager" "8.31.0" + "@typescript-eslint/types" "8.31.0" + "@typescript-eslint/typescript-estree" "8.31.0" "@typescript-eslint/utils@^6.0.0 || ^7.0.0 || ^8.0.0", "@typescript-eslint/utils@^8.15.0", "@typescript-eslint/utils@^8.18.1": version "8.22.0" @@ -6651,12 +8207,12 @@ "@typescript-eslint/types" "8.22.0" eslint-visitor-keys "^4.2.0" -"@typescript-eslint/visitor-keys@8.26.0": - version "8.26.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.26.0.tgz#a4876216756c69130ea958df3b77222c2ad95290" - integrity sha512-2z8JQJWAzPdDd51dRQ/oqIJxe99/hoLIqmf8RMCAJQtYDc535W/Jt2+RTP4bP0aKeBG1F65yjIZuczOXCmbWwg== +"@typescript-eslint/visitor-keys@8.31.0": + version "8.31.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.31.0.tgz#9a1a97ed16c60d4d1e7399b41c11a6d94ebc1ce5" + integrity sha512-QcGHmlRHWOl93o64ZUMNewCdwKGU6WItOU52H0djgNmn1EOrhVudrDzXz4OycCRSCPwFCDrE2iIt5vmuUdHxuQ== dependencies: - "@typescript-eslint/types" "8.26.0" + "@typescript-eslint/types" "8.31.0" eslint-visitor-keys "^4.2.0" "@ungap/structured-clone@^1.0.0", "@ungap/structured-clone@^1.2.0": @@ -6805,13 +8361,13 @@ abs-svg-path@^0.1.1: resolved "https://registry.yarnpkg.com/abs-svg-path/-/abs-svg-path-0.1.1.tgz#df601c8e8d2ba10d4a76d625e236a9a39c2723bf" integrity sha512-d8XPSGjfyzlXC3Xx891DJRyZfqk5JU0BJrDQcsWomFIV1/BIzPW5HDH5iDdWpqWaav0YVIEzT1RHTwWr0FFshA== -accepts@~1.3.8: - version "1.3.8" - resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" - integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== +accepts@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-2.0.0.tgz#bbcf4ba5075467f3f2131eab3cffc73c2f5d7895" + integrity sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng== dependencies: - mime-types "~2.1.34" - negotiator "0.6.3" + mime-types "^3.0.0" + negotiator "^1.0.0" acorn-globals@^7.0.0: version "7.0.1" @@ -6965,11 +8521,6 @@ array-buffer-byte-length@^1.0.1, array-buffer-byte-length@^1.0.2: call-bound "^1.0.3" is-array-buffer "^3.0.5" -array-flatten@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" - integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== - array-includes@^3.1.6, array-includes@^3.1.8: version "3.1.8" resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.8.tgz#5e370cbe172fdd5dd6530c1d4aadda25281ba97d" @@ -7107,10 +8658,10 @@ axe-core@^4.10.0: resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.10.2.tgz#85228e3e1d8b8532a27659b332e39b7fa0e022df" integrity sha512-RE3mdQ7P3FRSe7eqCWoeQ/Z9QXrtniSjp1wUjt5nRC3WIpz5rSCve6o3fsZ2aCpJtrZjSZgjwXAoTO5k4tEI0w== -axios@1.8.2: - version "1.8.2" - resolved "https://registry.yarnpkg.com/axios/-/axios-1.8.2.tgz#fabe06e241dfe83071d4edfbcaa7b1c3a40f7979" - integrity sha512-ls4GYBm5aig9vWx8AWDSGLpnpDQRtWAfrjU+EuytuODrFBkqesN2RkOQCBzrA1RQNHw1SmRMSDDDSwzNAYQ6Rg== +axios@1.8.4: + version "1.8.4" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.8.4.tgz#78990bb4bc63d2cae072952d374835950a82f447" + integrity sha512-eBSYY4Y68NNlHbHBMdeDmKNtDgXWhQsJcGqzO3iLUM0GraQFSS9cVgPX5I9b3lbdFKyYoAEGAZF1DwhTaljNAw== dependencies: follow-redirects "^1.15.6" form-data "^4.0.0" @@ -7273,23 +8824,20 @@ bluebird@^3.4.1: resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== -body-parser@1.20.3: - version "1.20.3" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.3.tgz#1953431221c6fb5cd63c4b36d53fab0928e548c6" - integrity sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g== +body-parser@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-2.2.0.tgz#f7a9656de305249a715b549b7b8fd1ab9dfddcfa" + integrity sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg== dependencies: - bytes "3.1.2" - content-type "~1.0.5" - debug "2.6.9" - depd "2.0.0" - destroy "1.2.0" - http-errors "2.0.0" - iconv-lite "0.4.24" - on-finished "2.4.1" - qs "6.13.0" - raw-body "2.5.2" - type-is "~1.6.18" - unpipe "1.0.0" + bytes "^3.1.2" + content-type "^1.0.5" + debug "^4.4.0" + http-errors "^2.0.0" + iconv-lite "^0.6.3" + on-finished "^2.4.1" + qs "^6.14.0" + raw-body "^3.0.0" + type-is "^2.0.0" boolbase@^1.0.0: version "1.0.0" @@ -7408,7 +8956,7 @@ busboy@1.6.0: dependencies: streamsearch "^1.1.0" -bytes@3.1.2: +bytes@3.1.2, bytes@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== @@ -7632,6 +9180,16 @@ cmdk@1.0.4: "@radix-ui/react-primitive" "^2.0.0" use-sync-external-store "^1.2.2" +cmdk@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/cmdk/-/cmdk-1.1.1.tgz#b8524272699ccaa37aaf07f36850b376bf3d58e5" + integrity sha512-Vsv7kFaXm+ptHDMZ7izaRsP70GgrW9NBNGswt9OZaVBLlE0SNpDq8eu/VGXyF9r7M0azK3Wy7OlYXsuyYLFzHg== + dependencies: + "@radix-ui/react-compose-refs" "^1.1.1" + "@radix-ui/react-dialog" "^1.1.6" + "@radix-ui/react-id" "^1.1.0" + "@radix-ui/react-primitive" "^2.0.2" + co@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" @@ -7742,14 +9300,14 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== -content-disposition@0.5.4: - version "0.5.4" - resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" - integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== +content-disposition@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-1.0.0.tgz#844426cb398f934caefcbb172200126bc7ceace2" + integrity sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg== dependencies: safe-buffer "5.2.1" -content-type@~1.0.4, content-type@~1.0.5: +content-type@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== @@ -7771,15 +9329,15 @@ convert-stream@1.0.2: dependencies: bluebird "^3.4.1" -cookie-signature@1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" - integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== +cookie-signature@^1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.2.2.tgz#57c7fc3cc293acab9fec54d73e15690ebe4a1793" + integrity sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg== -cookie@0.7.1: - version "0.7.1" - resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.7.1.tgz#2f73c42142d5d5cf71310a74fc4ae61670e5dbc9" - integrity sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w== +cookie@^0.7.1: + version "0.7.2" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.7.2.tgz#556369c472a2ba910f2979891b526b3436237ed7" + integrity sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w== cookiejar@^2.1.4: version "2.1.4" @@ -8051,20 +9609,20 @@ data-view-byte-offset@^1.0.1: es-errors "^1.3.0" is-data-view "^1.0.1" -debug@2.6.9, debug@^2.2.0: - version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" - integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== - dependencies: - ms "2.0.0" - -debug@4, debug@^4, debug@^4.0.0, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.3.5, debug@^4.3.7: +debug@4, debug@^4, debug@^4.0.0, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.3.5, debug@^4.3.7, debug@^4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a" integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA== dependencies: ms "^2.1.3" +debug@^2.2.0: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + debug@^3.1.0, debug@^3.2.7: version "3.2.7" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" @@ -8122,7 +9680,7 @@ delayed-stream@~1.0.0: resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== -depd@2.0.0: +depd@2.0.0, depd@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== @@ -8132,11 +9690,6 @@ dequal@^2.0.0, dequal@^2.0.3: resolved "https://registry.yarnpkg.com/dequal/-/dequal-2.0.3.tgz#2644214f1997d39ed0ee0ece72335490a7ac67be" integrity sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA== -destroy@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" - integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== - detect-libc@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.3.tgz#f0cd503b40f9939b894697d19ad50895e30cf700" @@ -8292,7 +9845,12 @@ dot-case@^3.0.4: no-case "^3.0.4" tslib "^2.0.3" -dotenv@16.4.7, dotenv@^16.3.1: +dotenv@16.5.0: + version "16.5.0" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.5.0.tgz#092b49f25f808f020050051d1ff258e404c78692" + integrity sha512-m/C+AwOAr9/W1UOIZUo232ejMNnJAJtYQjUbHoNTBNTJSvqzzDh7vnrei3o3r3m9blf6ZoDkvcw0VmozNRFJxg== + +dotenv@^16.3.1: version "16.4.7" resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.4.7.tgz#0e20c5b82950140aa99be360a8a5f52335f53c26" integrity sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ== @@ -8364,12 +9922,7 @@ emoji-regex@^9.2.2: resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== -encodeurl@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" - integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== - -encodeurl@~2.0.0: +encodeurl@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-2.0.0.tgz#7b8ea898077d7e409d3ac45474ea38eaf0857a58" integrity sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg== @@ -8580,7 +10133,7 @@ escalade@^3.1.1, escalade@^3.2.0: resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== -escape-html@~1.0.3: +escape-html@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== @@ -8611,12 +10164,12 @@ escodegen@^2.0.0: optionalDependencies: source-map "~0.6.1" -eslint-config-next@15.2.1: - version "15.2.1" - resolved "https://registry.yarnpkg.com/eslint-config-next/-/eslint-config-next-15.2.1.tgz#f49f71eb5de2e8a794cf79cb54b02f1e209d4d7f" - integrity sha512-mhsprz7l0no8X+PdDnVHF4dZKu9YBJp2Rf6ztWbXBLJ4h6gxmW//owbbGJMBVUU+PibGJDAqZhW4pt8SC8HSow== +eslint-config-next@15.3.1: + version "15.3.1" + resolved "https://registry.yarnpkg.com/eslint-config-next/-/eslint-config-next-15.3.1.tgz#2ba06a63adfead7c003f224b47c4b778392ce1c4" + integrity sha512-GnmyVd9TE/Ihe3RrvcafFhXErErtr2jS0JDeCSp3vWvy86AXwHsRBt0E3MqP/m8ACS1ivcsi5uaqjbhsG18qKw== dependencies: - "@next/eslint-plugin-next" "15.2.1" + "@next/eslint-plugin-next" "15.3.1" "@rushstack/eslint-patch" "^1.10.3" "@typescript-eslint/eslint-plugin" "^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0" "@typescript-eslint/parser" "^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0" @@ -8627,10 +10180,10 @@ eslint-config-next@15.2.1: eslint-plugin-react "^7.37.0" eslint-plugin-react-hooks "^5.0.0" -eslint-config-prettier@10.0.2: - version "10.0.2" - resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-10.0.2.tgz#47444de8aa104ce82c2f91ad2a5e96b62c01e20d" - integrity sha512-1105/17ZIMjmCOJOPNfVdbXafLCLj3hPmkmB7dLgt7XsQ/zkxSuDerE/xgO3RxoHysR1N1whmquY0lSn2O0VLg== +eslint-config-prettier@10.1.2: + version "10.1.2" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-10.1.2.tgz#31a4b393c40c4180202c27e829af43323bf85276" + integrity sha512-Epgp/EofAUeEpIdZkW60MHKvPyru1ruQJxPL+WIycnaPApuseK0Zpkrh/FwL9oIpQvIhJwV7ptOy0DWUjTlCiA== eslint-import-resolver-node@^0.3.6, eslint-import-resolver-node@^0.3.9: version "0.3.9" @@ -8722,20 +10275,20 @@ eslint-plugin-playwright@2.2.0: dependencies: globals "^13.23.0" -eslint-plugin-prettier@5.2.3: - version "5.2.3" - resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.3.tgz#c4af01691a6fa9905207f0fbba0d7bea0902cce5" - integrity sha512-qJ+y0FfCp/mQYQ/vWQ3s7eUlFEL4PyKfAJxsnYTJ4YT73nsJBWqmEpFryxV9OeUiqmsTsYJ5Y+KDNaeP31wrRw== +eslint-plugin-prettier@5.2.6: + version "5.2.6" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.6.tgz#be39e3bb23bb3eeb7e7df0927cdb46e4d7945096" + integrity sha512-mUcf7QG2Tjk7H055Jk0lGBjbgDnfrvqjhXh9t2xLMSCjZVcw9Rb1V6sVNXO0th3jgeO7zllWPTNRil3JW94TnQ== dependencies: prettier-linter-helpers "^1.0.0" - synckit "^0.9.1" + synckit "^0.11.0" eslint-plugin-react-hooks@^5.0.0: version "5.1.0" resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.1.0.tgz#3d34e37d5770866c34b87d5b499f5f0b53bf0854" integrity sha512-mpJRtPgHN2tNAvZ35AMfqeB3Xqeo273QxrHJsbBEPWODRM4r0yB6jfoROqKEYrOn27UtRPpcpHc2UqyBSuUNTw== -eslint-plugin-react@7.37.4, eslint-plugin-react@^7.37.0: +eslint-plugin-react@^7.37.0: version "7.37.4" resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.37.4.tgz#1b6c80b6175b6ae4b26055ae4d55d04c414c7181" integrity sha512-BGP0jRmfYyvOyvMoRX/uoUeW+GqNj9y16bPQzqAHf3AYII/tDs+jMN0dBVkl88/OZwNGwrVFxE7riHsXVfy/LQ== @@ -8890,7 +10443,7 @@ esutils@^2.0.2: resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== -etag@~1.8.1: +etag@^1.8.1: version "1.8.1" resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== @@ -8943,42 +10496,38 @@ express-ws@5.0.2: dependencies: ws "^7.4.6" -express@4.21.2: - version "4.21.2" - resolved "https://registry.yarnpkg.com/express/-/express-4.21.2.tgz#cf250e48362174ead6cea4a566abef0162c1ec32" - integrity sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA== - dependencies: - accepts "~1.3.8" - array-flatten "1.1.1" - body-parser "1.20.3" - content-disposition "0.5.4" - content-type "~1.0.4" - cookie "0.7.1" - cookie-signature "1.0.6" - debug "2.6.9" - depd "2.0.0" - encodeurl "~2.0.0" - escape-html "~1.0.3" - etag "~1.8.1" - finalhandler "1.3.1" - fresh "0.5.2" - http-errors "2.0.0" - merge-descriptors "1.0.3" - methods "~1.1.2" - on-finished "2.4.1" - parseurl "~1.3.3" - path-to-regexp "0.1.12" - proxy-addr "~2.0.7" - qs "6.13.0" - range-parser "~1.2.1" - safe-buffer "5.2.1" - send "0.19.0" - serve-static "1.16.2" - setprototypeof "1.2.0" - statuses "2.0.1" - type-is "~1.6.18" - utils-merge "1.0.1" - vary "~1.1.2" +express@5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/express/-/express-5.1.0.tgz#d31beaf715a0016f0d53f47d3b4d7acf28c75cc9" + integrity sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA== + dependencies: + accepts "^2.0.0" + body-parser "^2.2.0" + content-disposition "^1.0.0" + content-type "^1.0.5" + cookie "^0.7.1" + cookie-signature "^1.2.1" + debug "^4.4.0" + encodeurl "^2.0.0" + escape-html "^1.0.3" + etag "^1.8.1" + finalhandler "^2.1.0" + fresh "^2.0.0" + http-errors "^2.0.0" + merge-descriptors "^2.0.0" + mime-types "^3.0.0" + on-finished "^2.4.1" + once "^1.4.0" + parseurl "^1.3.3" + proxy-addr "^2.0.7" + qs "^6.14.0" + range-parser "^1.2.1" + router "^2.2.0" + send "^1.1.0" + serve-static "^2.2.0" + statuses "^2.0.1" + type-is "^2.0.1" + vary "^1.1.2" extend@^3.0.0: version "3.0.2" @@ -9099,12 +10648,12 @@ figlet@1.8.0: resolved "https://registry.yarnpkg.com/figlet/-/figlet-1.8.0.tgz#1b93c4f65f4c1a3b1135221987eee8cf8b9c0ac7" integrity sha512-chzvGjd+Sp7KUvPHZv6EXV5Ir3Q7kYNpCr4aHrRW79qFtTefmQZNny+W1pW9kf5zeE6dikku2W50W/wAH2xWgw== -file-entry-cache@^10.0.6: - version "10.0.7" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-10.0.7.tgz#e0ac34d4b8c44bea8a0a27ceb4dae982f2d32749" - integrity sha512-txsf5fu3anp2ff3+gOJJzRImtrtm/oa9tYLN0iTuINZ++EyVR/nRrg2fKYwvG/pXDofcrvvb0scEbX3NyW/COw== +file-entry-cache@^10.0.7: + version "10.0.8" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-10.0.8.tgz#2b7a32c40615c4a6b59c385fb059a2762faf9624" + integrity sha512-FGXHpfmI4XyzbLd3HQ8cbUcsFGohJpZtmQRHr8z8FxxtCe2PcpgIlVLwIgunqjvRmXypBETvwhV4ptJizA+Y1Q== dependencies: - flat-cache "^6.1.7" + flat-cache "^6.1.8" file-entry-cache@^6.0.1: version "6.0.1" @@ -9127,18 +10676,17 @@ fill-range@^7.1.1: dependencies: to-regex-range "^5.0.1" -finalhandler@1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.3.1.tgz#0c575f1d1d324ddd1da35ad7ece3df7d19088019" - integrity sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ== - dependencies: - debug "2.6.9" - encodeurl "~2.0.0" - escape-html "~1.0.3" - on-finished "2.4.1" - parseurl "~1.3.3" - statuses "2.0.1" - unpipe "~1.0.0" +finalhandler@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-2.1.0.tgz#72306373aa89d05a8242ed569ed86a1bff7c561f" + integrity sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q== + dependencies: + debug "^4.4.0" + encodeurl "^2.0.0" + escape-html "^1.0.3" + on-finished "^2.4.1" + parseurl "^1.3.3" + statuses "^2.0.1" find-root@^1.1.0: version "1.1.0" @@ -9170,14 +10718,14 @@ flat-cache@^3.0.4: keyv "^4.5.3" rimraf "^3.0.2" -flat-cache@^6.1.7: - version "6.1.7" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-6.1.7.tgz#c04b08316739ad7ef997e1b9ea363443fc2fcb38" - integrity sha512-qwZ4xf1v1m7Rc9XiORly31YaChvKt6oNVHuqqZcoED/7O+ToyNVGobKsIAopY9ODcWpEDKEBAbrSOCBHtNQvew== +flat-cache@^6.1.8: + version "6.1.8" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-6.1.8.tgz#968fb89b19df488fe60f346857ffc54b8dd0ba14" + integrity sha512-R6MaD3nrJAtO7C3QOuS79ficm2pEAy++TgEUD8ii1LVlbcgZ9DtASLkt9B+RZSFCzm7QHDMlXPsqqB6W2Pfr1Q== dependencies: cacheable "^1.8.9" flatted "^3.3.3" - hookified "^1.7.1" + hookified "^1.8.1" flatted@^3.2.9: version "3.3.2" @@ -9244,10 +10792,10 @@ forwarded@0.2.0: resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== -fresh@0.5.2: - version "0.5.2" - resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" - integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== +fresh@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-2.0.0.tgz#8dd7df6a1b3a1b3a5cf186c05a5dd267622635a4" + integrity sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A== fs-extra@^11.2.0: version "11.3.0" @@ -9407,7 +10955,7 @@ get-symbol-description@^1.1.0: es-errors "^1.3.0" get-intrinsic "^1.2.6" -get-tsconfig@^4.7.5: +get-tsconfig@^4.10.0, get-tsconfig@^4.7.5: version "4.10.0" resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.10.0.tgz#403a682b373a823612475a4c2928c7326fc0f6bb" integrity sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A== @@ -9881,6 +11429,11 @@ hookified@^1.7.1: resolved "https://registry.yarnpkg.com/hookified/-/hookified-1.7.1.tgz#b08228173e06e9e8767bae1dffb216b8c6171b41" integrity sha512-OXcdHsXeOiD7OJ5zvWj8Oy/6RCdLwntAX+wUrfemNcMGn6sux4xbEHi2QXwqePYhjQ/yvxxq2MvCRirdlHscBw== +hookified@^1.8.1: + version "1.8.2" + resolved "https://registry.yarnpkg.com/hookified/-/hookified-1.8.2.tgz#b365a89dfce3da43e790673a6a97d3b896ae5fa7" + integrity sha512-5nZbBNP44sFCDjSoB//0N7m508APCgbQ4mGGo1KJGBYyCKNHfry1Pvd0JVHZIxjdnqn8nFRBAN/eFB6Rk/4w5w== + hsl-to-hex@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/hsl-to-hex/-/hsl-to-hex-1.0.0.tgz#c58c826dc6d2f1e0a5ff1da5a7ecbf03faac1352" @@ -9949,7 +11502,7 @@ htmlparser2@^9.1.0: domutils "^3.1.0" entities "^4.5.0" -http-errors@2.0.0: +http-errors@2.0.0, http-errors@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== @@ -10003,10 +11556,10 @@ hyphen@^1.6.4: resolved "https://registry.yarnpkg.com/hyphen/-/hyphen-1.10.6.tgz#0e779d280e696102b97d7e42f5ca5de2cc97e274" integrity sha512-fXHXcGFTXOvZTSkPJuGOQf5Lv5T/R2itiiCVPg9LxAje5D00O0pP83yJShFq5V89Ly//Gt6acj7z8pbBr34stw== -i18next-browser-languagedetector@8.0.4: - version "8.0.4" - resolved "https://registry.yarnpkg.com/i18next-browser-languagedetector/-/i18next-browser-languagedetector-8.0.4.tgz#9b16f6440b6aad3521f2ab1a2ffbb7d917397df2" - integrity sha512-f3frU3pIxD50/Tz20zx9TD9HobKYg47fmAETb117GKGPrhwcSSPJDoCposXlVycVebQ9GQohC3Efbpq7/nnJ5w== +i18next-browser-languagedetector@8.0.5: + version "8.0.5" + resolved "https://registry.yarnpkg.com/i18next-browser-languagedetector/-/i18next-browser-languagedetector-8.0.5.tgz#6cfdc72820457ce95e69a2788a4f837d1d8f4e9d" + integrity sha512-OstebRKqKiQw8xEvQF5aRyUujsCatanj7Q9eo5iiH2gJpoXGZ7483ol3sVBwfqbobTQPNH1J+NAyJ1aCQoEC+w== dependencies: "@babel/runtime" "^7.23.2" @@ -10033,20 +11586,20 @@ i18next-parser@9.3.0: vinyl "^3.0.0" vinyl-fs "^4.0.0" -i18next@24.2.2, "i18next@^23.5.1 || ^24.2.0": +i18next@25.0.1: + version "25.0.1" + resolved "https://registry.yarnpkg.com/i18next/-/i18next-25.0.1.tgz#8870939202299a29fe2c99ea913f8e72db535e31" + integrity sha512-8S8PyZbrymJZn3DaN70/34JYWNhsqrU6yA4MuzcygJBv+41dgNMocEA8h+kV1P7MCc1ll03lOTOIXE7mpNCicw== + dependencies: + "@babel/runtime" "^7.26.10" + +"i18next@^23.5.1 || ^24.2.0": version "24.2.2" resolved "https://registry.yarnpkg.com/i18next/-/i18next-24.2.2.tgz#3ba3d213302068d569142737f03f30929de696de" integrity sha512-NE6i86lBCKRYZa5TaUDkU5S4HFgLIEJRLr3Whf2psgaxBleQ2LC1YW1Vc+SCgkAW7VEzndT6al6+CzegSUHcTQ== dependencies: "@babel/runtime" "^7.23.2" -iconv-lite@0.4.24: - version "0.4.24" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" - integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== - dependencies: - safer-buffer ">= 2.1.2 < 3" - iconv-lite@0.6.3, iconv-lite@^0.6.3: version "0.6.3" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" @@ -10362,6 +11915,11 @@ is-potential-custom-element-name@^1.0.1: resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5" integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ== +is-promise@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-4.0.0.tgz#42ff9f84206c1991d26debf520dd5c01042dd2f3" + integrity sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ== + is-reference@1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/is-reference/-/is-reference-1.2.1.tgz#8b2dac0b371f4bc994fdeaba9eb542d03002d0b7" @@ -11300,10 +12858,10 @@ lru-cache@^5.1.1: dependencies: yallist "^3.0.2" -luxon@3.5.0: - version "3.5.0" - resolved "https://registry.yarnpkg.com/luxon/-/luxon-3.5.0.tgz#6b6f65c5cd1d61d1fd19dbf07ee87a50bf4b8e20" - integrity sha512-rh+Zjr6DNfUYR3bPwJEnuwDdqMbxZW7LOQfUN4B54+Cl+0o5zaU9RJ6bcidfDtC1cWCZXQ+nvX8bf6bAji37QQ== +luxon@3.6.1: + version "3.6.1" + resolved "https://registry.yarnpkg.com/luxon/-/luxon-3.6.1.tgz#d283ffc4c0076cb0db7885ec6da1c49ba97e47b0" + integrity sha512-tJLxrKJhO2ukZ5z0gyjY1zPh3Rh88Ej9P7jNrZiHMUXHae1yvI2imgOZtL1TO8TW6biMMKfTtAOoEJANgtWBMQ== lz-string@^1.5.0: version "1.5.0" @@ -11563,10 +13121,10 @@ media-engine@^1.0.3: resolved "https://registry.yarnpkg.com/media-engine/-/media-engine-1.0.3.tgz#be3188f6cd243ea2a40804a35de5a5b032f58dad" integrity sha512-aa5tG6sDoK+k70B9iEX1NeyfT8ObCKhNDs6lJVpwF6r8vhUfuKMslIcirq6HIUYuuUYLefcEQOn9bSBOvawtwg== -media-typer@0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" - integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== +media-typer@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-1.1.0.tgz#6ab74b8f2d3320f2064b2a87a38e7931ff3a5561" + integrity sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw== "memoize-one@>=3.1.1 <6": version "5.2.1" @@ -11583,10 +13141,10 @@ meow@^13.2.0: resolved "https://registry.yarnpkg.com/meow/-/meow-13.2.0.tgz#6b7d63f913f984063b3cc261b6e8800c4cd3474f" integrity sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA== -merge-descriptors@1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.3.tgz#d80319a65f3c7935351e5cfdac8f9318504dbed5" - integrity sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ== +merge-descriptors@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-2.0.0.tgz#ea922f660635a2249ee565e0449f951e6b603808" + integrity sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g== merge-stream@^2.0.0: version "2.0.0" @@ -11598,7 +13156,7 @@ merge2@^1.3.0, merge2@^1.4.1: resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== -methods@^1.1.2, methods@~1.1.2: +methods@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== @@ -11921,17 +13479,24 @@ mime-db@1.52.0: resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== -mime-types@^2.1.12, mime-types@^2.1.27, mime-types@~2.1.24, mime-types@~2.1.34: +mime-db@^1.54.0: + version "1.54.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.54.0.tgz#cddb3ee4f9c64530dff640236661d42cb6a314f5" + integrity sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ== + +mime-types@^2.1.12, mime-types@^2.1.27: version "2.1.35" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== dependencies: mime-db "1.52.0" -mime@1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" - integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== +mime-types@^3.0.0, mime-types@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-3.0.1.tgz#b1d94d6997a9b32fd69ebaed0db73de8acb519ce" + integrity sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA== + dependencies: + mime-db "^1.54.0" mime@2.6.0: version "2.6.0" @@ -12016,7 +13581,7 @@ ms@2.0.0: resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== -ms@2.1.3, ms@^2.1.1, ms@^2.1.3: +ms@^2.1.1, ms@^2.1.3: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== @@ -12041,22 +13606,22 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== -negotiator@0.6.3: - version "0.6.3" - resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" - integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== +negotiator@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-1.0.0.tgz#b6c91bb47172d69f93cfd7c357bbb529019b5f6a" + integrity sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg== neo-async@^2.6.2: version "2.6.2" resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== -next@15.2.4: - version "15.2.4" - resolved "https://registry.yarnpkg.com/next/-/next-15.2.4.tgz#e05225e9511df98e3b2edc713e17f4c970bff961" - integrity sha512-VwL+LAaPSxEkd3lU2xWbgEOtrM8oedmyhBqaVNmgKB+GvZlCy9rgaEc+y2on0wv+l0oSFqLtYD6dcC1eAedUaQ== +next@15.3.1: + version "15.3.1" + resolved "https://registry.yarnpkg.com/next/-/next-15.3.1.tgz#69cf2c124e504db64e14fc75eb29bd64c0c787a7" + integrity sha512-8+dDV0xNLOgHlyBxP1GwHGVaNXsmp+2NhZEYrXr24GWLHtt27YrBPbPuHvzlhi7kZNYjeJNR93IF5zfFu5UL0g== dependencies: - "@next/env" "15.2.4" + "@next/env" "15.3.1" "@swc/counter" "0.1.3" "@swc/helpers" "0.5.15" busboy "1.6.0" @@ -12064,15 +13629,15 @@ next@15.2.4: postcss "8.4.31" styled-jsx "5.1.6" optionalDependencies: - "@next/swc-darwin-arm64" "15.2.4" - "@next/swc-darwin-x64" "15.2.4" - "@next/swc-linux-arm64-gnu" "15.2.4" - "@next/swc-linux-arm64-musl" "15.2.4" - "@next/swc-linux-x64-gnu" "15.2.4" - "@next/swc-linux-x64-musl" "15.2.4" - "@next/swc-win32-arm64-msvc" "15.2.4" - "@next/swc-win32-x64-msvc" "15.2.4" - sharp "^0.33.5" + "@next/swc-darwin-arm64" "15.3.1" + "@next/swc-darwin-x64" "15.3.1" + "@next/swc-linux-arm64-gnu" "15.3.1" + "@next/swc-linux-arm64-musl" "15.3.1" + "@next/swc-linux-x64-gnu" "15.3.1" + "@next/swc-linux-x64-musl" "15.3.1" + "@next/swc-win32-arm64-msvc" "15.3.1" + "@next/swc-win32-x64-msvc" "15.3.1" + sharp "^0.34.1" no-case@^3.0.4: version "3.0.4" @@ -12235,7 +13800,7 @@ obuf@~1.1.2: resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e" integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg== -on-finished@2.4.1: +on-finished@^2.4.1: version "2.4.1" resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== @@ -12383,7 +13948,7 @@ parse5@^7.0.0, parse5@^7.1.1, parse5@^7.1.2: dependencies: entities "^4.5.0" -parseurl@~1.3.3: +parseurl@^1.3.3: version "1.3.3" resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== @@ -12421,16 +13986,16 @@ path-scurry@^1.6.1: lru-cache "^10.2.0" minipass "^5.0.0 || ^6.0.2 || ^7.0.0" -path-to-regexp@0.1.12: - version "0.1.12" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.12.tgz#d5e1a12e478a976d432ef3c58d534b9923164bb7" - integrity sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ== - path-to-regexp@^2.2.1: version "2.4.0" resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-2.4.0.tgz#35ce7f333d5616f1c1e1bfe266c3aba2e5b2e704" integrity sha512-G6zHoVqC6GGTQkZwF4lkuEyMbVOjoBKAEybQUypI1WTkqinCOrq2x6U2+phkJ1XsEMTy4LjtwPI7HW+NVrRR2w== +path-to-regexp@^8.0.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-8.2.0.tgz#73990cc29e57a3ff2a0d914095156df5db79e8b4" + integrity sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ== + path-type@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" @@ -12515,17 +14080,17 @@ pkg-dir@^4.2.0: dependencies: find-up "^4.0.0" -playwright-core@1.50.1: - version "1.50.1" - resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.50.1.tgz#6a0484f1f1c939168f40f0ab3828c4a1592c4504" - integrity sha512-ra9fsNWayuYumt+NiM069M6OkcRb1FZSK8bgi66AtpFoWkg2+y0bJSNmkFrWhMbEBbVKC/EruAHH3g0zmtwGmQ== +playwright-core@1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.52.0.tgz#238f1f0c3edd4ebba0434ce3f4401900319a3dca" + integrity sha512-l2osTgLXSMeuLZOML9qYODUQoPPnUsKsb5/P6LJ2e6uPKXUdPK5WYhN4z03G+YNbWmGDY4YENauNu4ZKczreHg== -playwright@1.50.1: - version "1.50.1" - resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.50.1.tgz#2f93216511d65404f676395bfb97b41aa052b180" - integrity sha512-G8rwsOQJ63XG6BbKj2w5rHeavFjy5zynBA9zsJMMtBoe/Uf757oG12NXz6e6OirF7RCrTVAKFXbLmn1RbL7Qaw== +playwright@1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.52.0.tgz#26cb9a63346651e1c54c8805acfd85683173d4bd" + integrity sha512-JAwMNMBlxJ2oD1kce4KPtMkDeKGHQstdpFPcPH3maElAXon/QZeTvtsfXmTMRyO9TslfoYOXkSsvao2nE1ilTw== dependencies: - playwright-core "1.50.1" + playwright-core "1.52.0" optionalDependencies: fsevents "2.3.2" @@ -12640,15 +14205,15 @@ postgres-range@^1.1.1: resolved "https://registry.yarnpkg.com/postgres-range/-/postgres-range-1.1.4.tgz#a59c5f9520909bcec5e63e8cf913a92e4c952863" integrity sha512-i/hbxIE9803Alj/6ytL7UHQxRvZkI9O4Sy+J3HGc4F4oo/2eQAjTSNJ0bfxyse3bH0nuVesCk+3IRLaMtG3H6w== -posthog-js@1.227.0: - version "1.227.0" - resolved "https://registry.yarnpkg.com/posthog-js/-/posthog-js-1.227.0.tgz#0c1f489e7a9472ccb8d0ac6e01b6102c8b06f9a6" - integrity sha512-xdXpBI+6SJDG3vUSxW3KH8o4B5CrHz0Y95anSaHjIzkEeRd9NbTTDku/Hy9lLt1+8tkiwvsh6fYi7jS1UBHL/g== +posthog-js@1.236.5: + version "1.236.5" + resolved "https://registry.yarnpkg.com/posthog-js/-/posthog-js-1.236.5.tgz#6cb34fd4c9e4e6df58e9b2f6878270a9a226af49" + integrity sha512-2FrWVZwcLyeZAtdDckJaCfsk9m6DMdr/nVPVSqzF7yvm9pDsdbkvB3A16iqRj5L3EcqV2xWOcv8xWmKgdnNnqA== dependencies: core-js "^3.38.1" fflate "^0.4.8" preact "^10.19.3" - web-vitals "^4.2.0" + web-vitals "^4.2.4" preact@^10.19.3: version "10.25.4" @@ -12891,16 +14456,7 @@ prosemirror-view@^1.0.0, prosemirror-view@^1.1.0, prosemirror-view@^1.27.0, pros prosemirror-state "^1.0.0" prosemirror-transform "^1.1.0" -prosemirror-view@^1.38.0: - version "1.38.1" - resolved "https://registry.yarnpkg.com/prosemirror-view/-/prosemirror-view-1.38.1.tgz#566d30cc8b00a68d6b4c60f5d8a6ab97c82990b3" - integrity sha512-4FH/uM1A4PNyrxXbD+RAbAsf0d/mM0D/wAKSVVWK7o0A9Q/oOXJBrw786mBf2Vnrs/Edly6dH6Z2gsb7zWwaUw== - dependencies: - prosemirror-model "^1.20.0" - prosemirror-state "^1.0.0" - prosemirror-transform "^1.1.0" - -proxy-addr@~2.0.7: +proxy-addr@^2.0.7: version "2.0.7" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== @@ -12940,14 +14496,7 @@ pure-rand@^6.0.0: resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-6.1.0.tgz#d173cf23258231976ccbdb05247c9787957604f2" integrity sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA== -qs@6.13.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.13.0.tgz#6ca3bd58439f7e245655798997787b0d88a51906" - integrity sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg== - dependencies: - side-channel "^1.0.6" - -qs@^6.11.0: +qs@^6.11.0, qs@^6.14.0: version "6.14.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.14.0.tgz#c63fa40680d2c5c941412a0e899c89af60c0a930" integrity sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w== @@ -13004,19 +14553,19 @@ randombytes@^2.1.0: dependencies: safe-buffer "^5.1.0" -range-parser@~1.2.1: +range-parser@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== -raw-body@2.5.2: - version "2.5.2" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a" - integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA== +raw-body@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-3.0.0.tgz#25b3476f07a51600619dae3fe82ddc28a36e5e0f" + integrity sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g== dependencies: bytes "3.1.2" http-errors "2.0.0" - iconv-lite "0.4.24" + iconv-lite "0.6.3" unpipe "1.0.0" react-arborist@3.4.3: @@ -13108,6 +14657,40 @@ react-aria-components@1.6.0: react-stately "^3.35.0" use-sync-external-store "^1.2.0" +react-aria-components@1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/react-aria-components/-/react-aria-components-1.8.0.tgz#db8744ceae1d117d06f73b3de29b716a8b4ef7c3" + integrity sha512-qNJ/Z4opj1/NKFf1ch/V8rNYar5MXu4J8YVAt2pFgnBRLjVlIlfnENN8Oa5OFiYFCzMPRFdq5mI8RuYIEnvZfg== + dependencies: + "@internationalized/date" "^3.8.0" + "@internationalized/string" "^3.2.6" + "@react-aria/autocomplete" "3.0.0-beta.2" + "@react-aria/collections" "3.0.0-rc.0" + "@react-aria/dnd" "^3.9.2" + "@react-aria/focus" "^3.20.2" + "@react-aria/interactions" "^3.25.0" + "@react-aria/live-announcer" "^3.4.2" + "@react-aria/overlays" "^3.27.0" + "@react-aria/ssr" "^3.9.8" + "@react-aria/toolbar" "3.0.0-beta.15" + "@react-aria/utils" "^3.28.2" + "@react-aria/virtualizer" "^4.1.4" + "@react-stately/autocomplete" "3.0.0-beta.1" + "@react-stately/layout" "^4.2.2" + "@react-stately/selection" "^3.20.1" + "@react-stately/table" "^3.14.1" + "@react-stately/utils" "^3.10.6" + "@react-stately/virtualizer" "^4.3.2" + "@react-types/form" "^3.7.11" + "@react-types/grid" "^3.3.1" + "@react-types/shared" "^3.29.0" + "@react-types/table" "^3.12.0" + "@swc/helpers" "^0.5.0" + client-only "^0.0.1" + react-aria "^3.39.0" + react-stately "^3.37.0" + use-sync-external-store "^1.4.0" + react-aria@3.36.0: version "3.36.0" resolved "https://registry.yarnpkg.com/react-aria/-/react-aria-3.36.0.tgz#95a8e3340ab400bfec4d159e47da8861469e5bcd" @@ -13246,6 +14829,54 @@ react-aria@^3.37.0: "@react-aria/visually-hidden" "^3.8.19" "@react-types/shared" "^3.27.0" +react-aria@^3.39.0: + version "3.39.0" + resolved "https://registry.yarnpkg.com/react-aria/-/react-aria-3.39.0.tgz#68e01a25365f403cfbc870b7ec29093d8722f0ba" + integrity sha512-zXCjR01WnfW4uW0f294uWrvdfwEMHgDFSwMwMBwRafAvmsQea87X5VTAfDmQOAbPa+iQFcngIyH0Pn5CfXNrjw== + dependencies: + "@internationalized/string" "^3.2.6" + "@react-aria/breadcrumbs" "^3.5.23" + "@react-aria/button" "^3.13.0" + "@react-aria/calendar" "^3.8.0" + "@react-aria/checkbox" "^3.15.4" + "@react-aria/color" "^3.0.6" + "@react-aria/combobox" "^3.12.2" + "@react-aria/datepicker" "^3.14.2" + "@react-aria/dialog" "^3.5.24" + "@react-aria/disclosure" "^3.0.4" + "@react-aria/dnd" "^3.9.2" + "@react-aria/focus" "^3.20.2" + "@react-aria/gridlist" "^3.12.0" + "@react-aria/i18n" "^3.12.8" + "@react-aria/interactions" "^3.25.0" + "@react-aria/label" "^3.7.17" + "@react-aria/landmark" "^3.0.2" + "@react-aria/link" "^3.8.0" + "@react-aria/listbox" "^3.14.3" + "@react-aria/menu" "^3.18.2" + "@react-aria/meter" "^3.4.22" + "@react-aria/numberfield" "^3.11.13" + "@react-aria/overlays" "^3.27.0" + "@react-aria/progress" "^3.4.22" + "@react-aria/radio" "^3.11.2" + "@react-aria/searchfield" "^3.8.3" + "@react-aria/select" "^3.15.4" + "@react-aria/selection" "^3.24.0" + "@react-aria/separator" "^3.4.8" + "@react-aria/slider" "^3.7.18" + "@react-aria/ssr" "^3.9.8" + "@react-aria/switch" "^3.7.2" + "@react-aria/table" "^3.17.2" + "@react-aria/tabs" "^3.10.2" + "@react-aria/tag" "^3.5.2" + "@react-aria/textfield" "^3.17.2" + "@react-aria/toast" "^3.0.2" + "@react-aria/tooltip" "^3.8.2" + "@react-aria/tree" "^3.0.2" + "@react-aria/utils" "^3.28.2" + "@react-aria/visually-hidden" "^3.8.22" + "@react-types/shared" "^3.29.0" + react-dnd-html5-backend@^14.0.3: version "14.1.0" resolved "https://registry.yarnpkg.com/react-dnd-html5-backend/-/react-dnd-html5-backend-14.1.0.tgz#b35a3a0c16dd3a2bfb5eb7ec62cf0c2cace8b62f" @@ -13264,12 +14895,12 @@ react-dnd@^14.0.3: fast-deep-equal "^3.1.3" hoist-non-react-statics "^3.3.2" -react-dom@*, react-dom@19.0.0: - version "19.0.0" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-19.0.0.tgz#43446f1f01c65a4cd7f7588083e686a6726cfb57" - integrity sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ== +react-dom@*, react-dom@19.0.0, react-dom@19.1.0: + version "19.1.0" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-19.1.0.tgz#133558deca37fa1d682708df8904b25186793623" + integrity sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g== dependencies: - scheduler "^0.25.0" + scheduler "^0.26.0" react-i18next@15.4.1: version "15.4.1" @@ -13284,10 +14915,10 @@ react-icons@^5.2.1: resolved "https://registry.yarnpkg.com/react-icons/-/react-icons-5.4.0.tgz#443000f6e5123ee1b21ea8c0a716f6e7797f7416" integrity sha512-7eltJxgVt7X64oHh6wSWNwwbKTCtMfK35hcjvJS0yxEAhPM8oUKdS3+kqaW1vicIltw+kR2unHaa12S9pPALoQ== -react-intersection-observer@9.15.1: - version "9.15.1" - resolved "https://registry.yarnpkg.com/react-intersection-observer/-/react-intersection-observer-9.15.1.tgz#5866b6fdfef24be9f288b74b35b773f63d90c3eb" - integrity sha512-vGrqYEVWXfH+AGu241uzfUpNK4HAdhCkSAyFdkMb9VWWXs6mxzBLpWCxEy9YcnDNY2g9eO6z7qUtTBdA9hc8pA== +react-intersection-observer@9.16.0: + version "9.16.0" + resolved "https://registry.yarnpkg.com/react-intersection-observer/-/react-intersection-observer-9.16.0.tgz#7376d54edc47293300961010844d53b273ee0fb9" + integrity sha512-w9nJSEp+DrW9KmQmeWHQyfaP6b03v+TdXynaoA964Wxt7mdR3An11z4NNCQgL4gKSK7y1ver2Fq+JKH6CWEzUA== react-is@18.2.0: version "18.2.0" @@ -13337,7 +14968,7 @@ react-remove-scroll-bar@^2.3.7: react-style-singleton "^2.2.2" tslib "^2.0.0" -react-remove-scroll@^2.6.2: +react-remove-scroll@^2.6.2, react-remove-scroll@^2.6.3: version "2.6.3" resolved "https://registry.yarnpkg.com/react-remove-scroll/-/react-remove-scroll-2.6.3.tgz#df02cde56d5f2731e058531f8ffd7f9adec91ac2" integrity sha512-pnAi91oOk8g8ABQKGF5/M9qxmmOPxaAnopyTHYfqYEwJhyFrbbBtHuSgtKEoH0jpcxx5o3hXqH1mNd9/Oi+8iQ== @@ -13462,6 +15093,38 @@ react-stately@^3.34.0: "@react-stately/tree" "^3.8.8" "@react-types/shared" "^3.28.0" +react-stately@^3.37.0: + version "3.37.0" + resolved "https://registry.yarnpkg.com/react-stately/-/react-stately-3.37.0.tgz#9bd09ecd1c7b11461ec60e17a7c670c17a64962e" + integrity sha512-fm2LRM3XN5lJD48+WQKWvESx54kAIHw0JztCRHMsFmTDgYWX/VASuXKON7LECv227stSEadrxGa8LhPkcelljw== + dependencies: + "@react-stately/calendar" "^3.8.0" + "@react-stately/checkbox" "^3.6.13" + "@react-stately/collections" "^3.12.3" + "@react-stately/color" "^3.8.4" + "@react-stately/combobox" "^3.10.4" + "@react-stately/data" "^3.12.3" + "@react-stately/datepicker" "^3.14.0" + "@react-stately/disclosure" "^3.0.3" + "@react-stately/dnd" "^3.5.3" + "@react-stately/form" "^3.1.3" + "@react-stately/list" "^3.12.1" + "@react-stately/menu" "^3.9.3" + "@react-stately/numberfield" "^3.9.11" + "@react-stately/overlays" "^3.6.15" + "@react-stately/radio" "^3.10.12" + "@react-stately/searchfield" "^3.5.11" + "@react-stately/select" "^3.6.12" + "@react-stately/selection" "^3.20.1" + "@react-stately/slider" "^3.6.3" + "@react-stately/table" "^3.14.1" + "@react-stately/tabs" "^3.8.1" + "@react-stately/toast" "^3.1.0" + "@react-stately/toggle" "^3.8.3" + "@react-stately/tooltip" "^3.5.3" + "@react-stately/tree" "^3.8.9" + "@react-types/shared" "^3.29.0" + react-style-singleton@^2.2.2, react-style-singleton@^2.2.3: version "2.2.3" resolved "https://registry.yarnpkg.com/react-style-singleton/-/react-style-singleton-2.2.3.tgz#4265608be69a4d70cfe3047f2c6c88b2c3ace388" @@ -13497,10 +15160,10 @@ react-window@^1.8.11: "@babel/runtime" "^7.0.0" memoize-one ">=3.1.1 <6" -react@*, react@19.0.0: - version "19.0.0" - resolved "https://registry.yarnpkg.com/react/-/react-19.0.0.tgz#6e1969251b9f108870aa4bff37a0ce9ddfaaabdd" - integrity sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ== +react@*, react@19.0.0, react@19.1.0: + version "19.1.0" + resolved "https://registry.yarnpkg.com/react/-/react-19.1.0.tgz#926864b6c48da7627f004795d6cce50e90793b75" + integrity sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg== readable-stream@^3.4.0: version "3.6.2" @@ -13856,11 +15519,32 @@ rimraf@^3.0.2: dependencies: glob "^7.1.3" -rollup@3.29.5: - version "3.29.5" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-3.29.5.tgz#8a2e477a758b520fb78daf04bca4c522c1da8a54" - integrity sha512-GVsDdsbJzzy4S/v3dqWPJ7EfvZJfCHiDqe80IyrF59LYuP+e6U1LJoUqeuqRbwAWoMNoXivMNeNAOf5E22VA1w== +rollup@4.35.0: + version "4.35.0" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.35.0.tgz#76c95dba17a579df4c00c3955aed32aa5d4dc66d" + integrity sha512-kg6oI4g+vc41vePJyO6dHt/yl0Rz3Thv0kJeVQ3D1kS3E5XSuKbPc29G4IpT/Kv1KQwgHVcN+HtyS+HYLNSvQg== + dependencies: + "@types/estree" "1.0.6" optionalDependencies: + "@rollup/rollup-android-arm-eabi" "4.35.0" + "@rollup/rollup-android-arm64" "4.35.0" + "@rollup/rollup-darwin-arm64" "4.35.0" + "@rollup/rollup-darwin-x64" "4.35.0" + "@rollup/rollup-freebsd-arm64" "4.35.0" + "@rollup/rollup-freebsd-x64" "4.35.0" + "@rollup/rollup-linux-arm-gnueabihf" "4.35.0" + "@rollup/rollup-linux-arm-musleabihf" "4.35.0" + "@rollup/rollup-linux-arm64-gnu" "4.35.0" + "@rollup/rollup-linux-arm64-musl" "4.35.0" + "@rollup/rollup-linux-loongarch64-gnu" "4.35.0" + "@rollup/rollup-linux-powerpc64le-gnu" "4.35.0" + "@rollup/rollup-linux-riscv64-gnu" "4.35.0" + "@rollup/rollup-linux-s390x-gnu" "4.35.0" + "@rollup/rollup-linux-x64-gnu" "4.35.0" + "@rollup/rollup-linux-x64-musl" "4.35.0" + "@rollup/rollup-win32-arm64-msvc" "4.35.0" + "@rollup/rollup-win32-ia32-msvc" "4.35.0" + "@rollup/rollup-win32-x64-msvc" "4.35.0" fsevents "~2.3.2" rollup@^2.43.1: @@ -13875,6 +15559,17 @@ rope-sequence@^1.3.0: resolved "https://registry.yarnpkg.com/rope-sequence/-/rope-sequence-1.3.4.tgz#df85711aaecd32f1e756f76e43a415171235d425" integrity sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ== +router@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/router/-/router-2.2.0.tgz#019be620b711c87641167cc79b99090f00b146ef" + integrity sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ== + dependencies: + debug "^4.4.0" + depd "^2.0.0" + is-promise "^4.0.0" + parseurl "^1.3.3" + path-to-regexp "^8.0.0" + rrweb-cssom@^0.7.1: version "0.7.1" resolved "https://registry.yarnpkg.com/rrweb-cssom/-/rrweb-cssom-0.7.1.tgz#c73451a484b86dd7cfb1e0b2898df4b703183e4b" @@ -13947,7 +15642,7 @@ safe-regex-test@^1.0.3, safe-regex-test@^1.1.0: es-errors "^1.3.0" is-regex "^1.2.1" -"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0": +"safer-buffer@>= 2.1.2 < 3.0.0": version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== @@ -13969,10 +15664,10 @@ scheduler@0.25.0-rc-603e6108-20241029: resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.25.0-rc-603e6108-20241029.tgz#684dd96647e104d23e0d29a37f18937daf82df19" integrity sha512-pFwF6H1XrSdYYNLfOcGlM28/j8CGLu8IvdrxqhjWULe2bPcKiKW4CV+OWqR/9fT52mywx65l7ysNkjLKBda7eA== -scheduler@^0.25.0: - version "0.25.0" - resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.25.0.tgz#336cd9768e8cceebf52d3c80e3dcf5de23e7e015" - integrity sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA== +scheduler@^0.26.0: + version "0.26.0" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.26.0.tgz#4ce8a8c2a2095f13ea11bf9a445be50c555d6337" + integrity sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA== schema-utils@^4.3.0: version "4.3.0" @@ -13999,24 +15694,22 @@ semver@^7.6.0, semver@^7.7.1: resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.1.tgz#abd5098d82b18c6c81f6074ff2647fd3e7220c9f" integrity sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA== -send@0.19.0: - version "0.19.0" - resolved "https://registry.yarnpkg.com/send/-/send-0.19.0.tgz#bbc5a388c8ea6c048967049dbeac0e4a3f09d7f8" - integrity sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw== +send@^1.1.0, send@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/send/-/send-1.2.0.tgz#32a7554fb777b831dfa828370f773a3808d37212" + integrity sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw== dependencies: - debug "2.6.9" - depd "2.0.0" - destroy "1.2.0" - encodeurl "~1.0.2" - escape-html "~1.0.3" - etag "~1.8.1" - fresh "0.5.2" - http-errors "2.0.0" - mime "1.6.0" - ms "2.1.3" - on-finished "2.4.1" - range-parser "~1.2.1" - statuses "2.0.1" + debug "^4.3.5" + encodeurl "^2.0.0" + escape-html "^1.0.3" + etag "^1.8.1" + fresh "^2.0.0" + http-errors "^2.0.0" + mime-types "^3.0.1" + ms "^2.1.3" + on-finished "^2.4.1" + range-parser "^1.2.1" + statuses "^2.0.1" serialize-javascript@^6.0.1, serialize-javascript@^6.0.2: version "6.0.2" @@ -14025,15 +15718,15 @@ serialize-javascript@^6.0.1, serialize-javascript@^6.0.2: dependencies: randombytes "^2.1.0" -serve-static@1.16.2: - version "1.16.2" - resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.16.2.tgz#b6a5343da47f6bdd2673848bf45754941e803296" - integrity sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw== +serve-static@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-2.2.0.tgz#9c02564ee259bdd2251b82d659a2e7e1938d66f9" + integrity sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ== dependencies: - encodeurl "~2.0.0" - escape-html "~1.0.3" - parseurl "~1.3.3" - send "0.19.0" + encodeurl "^2.0.0" + escape-html "^1.0.3" + parseurl "^1.3.3" + send "^1.2.0" set-function-length@^1.2.2: version "1.2.2" @@ -14110,6 +15803,36 @@ sharp@^0.33.5: "@img/sharp-win32-ia32" "0.33.5" "@img/sharp-win32-x64" "0.33.5" +sharp@^0.34.1: + version "0.34.1" + resolved "https://registry.yarnpkg.com/sharp/-/sharp-0.34.1.tgz#e5922894b0cc7ddf159eeabc6d5668e4e8b11d61" + integrity sha512-1j0w61+eVxu7DawFJtnfYcvSv6qPFvfTaqzTQ2BLknVhHTwGS8sc63ZBF4rzkWMBVKybo4S5OBtDdZahh2A1xg== + dependencies: + color "^4.2.3" + detect-libc "^2.0.3" + semver "^7.7.1" + optionalDependencies: + "@img/sharp-darwin-arm64" "0.34.1" + "@img/sharp-darwin-x64" "0.34.1" + "@img/sharp-libvips-darwin-arm64" "1.1.0" + "@img/sharp-libvips-darwin-x64" "1.1.0" + "@img/sharp-libvips-linux-arm" "1.1.0" + "@img/sharp-libvips-linux-arm64" "1.1.0" + "@img/sharp-libvips-linux-ppc64" "1.1.0" + "@img/sharp-libvips-linux-s390x" "1.1.0" + "@img/sharp-libvips-linux-x64" "1.1.0" + "@img/sharp-libvips-linuxmusl-arm64" "1.1.0" + "@img/sharp-libvips-linuxmusl-x64" "1.1.0" + "@img/sharp-linux-arm" "0.34.1" + "@img/sharp-linux-arm64" "0.34.1" + "@img/sharp-linux-s390x" "0.34.1" + "@img/sharp-linux-x64" "0.34.1" + "@img/sharp-linuxmusl-arm64" "0.34.1" + "@img/sharp-linuxmusl-x64" "0.34.1" + "@img/sharp-wasm32" "0.34.1" + "@img/sharp-win32-ia32" "0.34.1" + "@img/sharp-win32-x64" "0.34.1" + shebang-command@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" @@ -14170,7 +15893,7 @@ side-channel-weakmap@^1.0.2: object-inspect "^1.13.3" side-channel-map "^1.0.1" -side-channel@^1.0.6, side-channel@^1.1.0: +side-channel@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.1.0.tgz#c3fcff9c4da932784873335ec9765fa94ff66bc9" integrity sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw== @@ -14331,7 +16054,7 @@ stacktrace-parser@^0.1.10: dependencies: type-fest "^0.7.1" -statuses@2.0.1: +statuses@2.0.1, statuses@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== @@ -14513,10 +16236,10 @@ strip-json-comments@^3.1.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== -styled-components@6.1.15: - version "6.1.15" - resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-6.1.15.tgz#7651904d5424d08c1046056eb39024cc23c72ab7" - integrity sha512-PpOTEztW87Ua2xbmLa7yssjNyUF9vE7wdldRfn1I2E6RTkqknkBYpj771OxM/xrvRGinLy2oysa7GOd7NcZZIA== +styled-components@6.1.17: + version "6.1.17" + resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-6.1.17.tgz#59032edd7efa59e114ddbc41165f0984d0fa4fb7" + integrity sha512-97D7DwWanI7nN24v0D4SvbfjLE9656umNSJZkBkDIWL37aZqG/wRQ+Y9pWtXyBIM/NSfcBzHLErEsqHmJNSVUg== dependencies: "@emotion/is-prop-valid" "1.2.2" "@emotion/unitless" "0.8.1" @@ -14535,17 +16258,17 @@ styled-jsx@5.1.6: dependencies: client-only "0.0.1" -stylelint-config-recommended@^15.0.0: - version "15.0.0" - resolved "https://registry.yarnpkg.com/stylelint-config-recommended/-/stylelint-config-recommended-15.0.0.tgz#93d48db401215708b724f078533864e52085a07b" - integrity sha512-9LejMFsat7L+NXttdHdTq94byn25TD+82bzGRiV1Pgasl99pWnwipXS5DguTpp3nP1XjvLXVnEJIuYBfsRjRkA== +stylelint-config-recommended@^16.0.0: + version "16.0.0" + resolved "https://registry.yarnpkg.com/stylelint-config-recommended/-/stylelint-config-recommended-16.0.0.tgz#0221f19902816fe7d53d9a01eb0be4cc7b4fe80a" + integrity sha512-4RSmPjQegF34wNcK1e1O3Uz91HN8P1aFdFzio90wNK9mjgAI19u5vsU868cVZboKzCaa5XbpvtTzAAGQAxpcXA== -stylelint-config-standard@37.0.0: - version "37.0.0" - resolved "https://registry.yarnpkg.com/stylelint-config-standard/-/stylelint-config-standard-37.0.0.tgz#55e75c7215d5398b096d2f75af6a16693c18532d" - integrity sha512-+6eBlbSTrOn/il2RlV0zYGQwRTkr+WtzuVSs1reaWGObxnxLpbcspCUYajVQHonVfxVw2U+h42azGhrBvcg8OA== +stylelint-config-standard@38.0.0: + version "38.0.0" + resolved "https://registry.yarnpkg.com/stylelint-config-standard/-/stylelint-config-standard-38.0.0.tgz#9d673ec1f35d7569476ee4b0582e7dd5faebf036" + integrity sha512-uj3JIX+dpFseqd/DJx8Gy3PcRAJhlEZ2IrlFOc4LUxBX/PNMEQ198x7LCOE2Q5oT9Vw8nyc4CIL78xSqPr6iag== dependencies: - stylelint-config-recommended "^15.0.0" + stylelint-config-recommended "^16.0.0" stylelint-prettier@5.0.3: version "5.0.3" @@ -14554,10 +16277,10 @@ stylelint-prettier@5.0.3: dependencies: prettier-linter-helpers "^1.0.0" -stylelint@16.15.0: - version "16.15.0" - resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-16.15.0.tgz#a561cd50ad468cc4898f5c57cc1f223287fdea59" - integrity sha512-OK6Rs7EPdcdmjqiDycadZY4fw3f5/TC1X6/tGjnF3OosbwCeNs7nG+79MCAtjEg7ckwqTJTsku08e0Rmaz5nUw== +stylelint@16.18.0: + version "16.18.0" + resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-16.18.0.tgz#8e992c3a7af1b2ebf7ea5ccf26c2415adbea64b4" + integrity sha512-OXb68qzesv7J70BSbFwfK3yTVLEVXiQ/ro6wUE4UrSbKCMjLLA02S8Qq3LC01DxKyVjk7z8xh35aB4JzO3/sNA== dependencies: "@csstools/css-parser-algorithms" "^3.0.4" "@csstools/css-tokenizer" "^3.0.3" @@ -14572,7 +16295,7 @@ stylelint@16.15.0: debug "^4.3.7" fast-glob "^3.3.3" fastest-levenshtein "^1.0.16" - file-entry-cache "^10.0.6" + file-entry-cache "^10.0.7" global-modules "^2.0.0" globby "^11.1.0" globjoin "^0.1.4" @@ -14623,10 +16346,10 @@ superagent@^9.0.1: mime "2.6.0" qs "^6.11.0" -supertest@7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/supertest/-/supertest-7.0.0.tgz#cac53b3d6872a0b317980b2b0cfa820f09cd7634" - integrity sha512-qlsr7fIC0lSddmA3tzojvzubYxvlGtzumcdHgPwbFWMISQwL22MhM2Y3LNt+6w9Yyx7559VW5ab70dgphm8qQA== +supertest@7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/supertest/-/supertest-7.1.0.tgz#09b273174a8820e57ccdb03d9ca0d96c08c96b52" + integrity sha512-5QeSO8hSrKghtcWEoPiO036fxH0Ii2wVQfFZSP0oqQhmjk8bOLhDFXr4JrvaFmPuEWUoq4znY3uSi8UzLKxGqw== dependencies: methods "^1.1.2" superagent "^9.0.1" @@ -14708,13 +16431,13 @@ symlink-or-copy@^1.1.8, symlink-or-copy@^1.2.0, symlink-or-copy@^1.3.1: resolved "https://registry.yarnpkg.com/symlink-or-copy/-/symlink-or-copy-1.3.1.tgz#9506dd64d8e98fa21dcbf4018d1eab23e77f71fe" integrity sha512-0K91MEXFpBUaywiwSSkmKjnGcasG/rVBXFLJz5DrgGabpYD6N+3yZrfD6uUIfpuTu65DZLHi7N8CizHc07BPZA== -synckit@^0.9.1: - version "0.9.2" - resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.9.2.tgz#a3a935eca7922d48b9e7d6c61822ee6c3ae4ec62" - integrity sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw== +synckit@^0.11.0: + version "0.11.4" + resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.11.4.tgz#48972326b59723fc15b8d159803cf8302b545d59" + integrity sha512-Q/XQKRaJiLiFIBNN+mndW7S/RHxvwzuZS6ZwmRzUBqJBv/5QIKCEwkBC8GBf8EQJKYnaFs0wOZbKTXBPj8L9oQ== dependencies: - "@pkgr/core" "^0.1.0" - tslib "^2.6.2" + "@pkgr/core" "^0.2.3" + tslib "^2.8.1" tabbable@^6.0.0: version "6.2.0" @@ -14930,10 +16653,10 @@ ts-api-utils@^2.0.1: resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-2.0.1.tgz#660729385b625b939aaa58054f45c058f33f10cd" integrity sha512-dnlgjFSVetynI8nzgJ+qF62efpglpWRk8isUEWZGWlJYySCTD6aKvbUDu+zbPeDakk3bg5H4XpitHukgfL1m9w== -ts-jest@29.2.6: - version "29.2.6" - resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-29.2.6.tgz#df53edf8b72fb89de032cfa310abf37582851d9a" - integrity sha512-yTNZVZqc8lSixm+QGVFcPe6+yj7+TWZwIesuOWvfcn4B9bz5x4NDzVCQQjOs7Hfouu36aEqfEbo9Qpo+gq8dDg== +ts-jest@29.3.2: + version "29.3.2" + resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-29.3.2.tgz#0576cdf0a507f811fe73dcd16d135ce89f8156cb" + integrity sha512-bJJkrWc6PjFVz5g2DGCNUo8z7oFEYaz1xP1NpeDU7KNLMWPpEyV8Chbpkn8xjzgRDpQhnGMyvyldoL7h8JXyug== dependencies: bs-logger "^0.2.6" ejs "^3.1.10" @@ -14943,6 +16666,7 @@ ts-jest@29.2.6: lodash.memoize "^4.1.2" make-error "^1.3.6" semver "^7.7.1" + type-fest "^4.39.1" yargs-parser "^21.1.1" ts-node@10.9.2: @@ -14964,13 +16688,14 @@ ts-node@10.9.2: v8-compile-cache-lib "^3.0.1" yn "3.1.1" -tsc-alias@1.8.11: - version "1.8.11" - resolved "https://registry.yarnpkg.com/tsc-alias/-/tsc-alias-1.8.11.tgz#acd3f7680a69ff82bed2df2ef26072e445c15470" - integrity sha512-2DuEQ58A9Rj2NE2c1+/qaGKlshni9MCK95MJzRGhQG0CYLw0bE/ACgbhhTSf/p1svLelwqafOd8stQate2bYbg== +tsc-alias@1.8.15: + version "1.8.15" + resolved "https://registry.yarnpkg.com/tsc-alias/-/tsc-alias-1.8.15.tgz#7a07a77a4157872f834841a2a1647fad9464884d" + integrity sha512-yKLVx8ddUurRwhVcS6JFF2ZjksOX2ZWDRIdgt+PQhJBDegIdAdilptiHsuAbx9UFxa16GFrxeKQ2kTcGvR6fkQ== dependencies: chokidar "^3.5.3" commander "^9.0.0" + get-tsconfig "^4.10.0" globby "^11.0.4" mylas "^2.1.9" normalize-path "^3.0.0" @@ -14986,7 +16711,7 @@ tsconfig-paths@^3.15.0: minimist "^1.2.6" strip-bom "^3.0.0" -tslib@2, tslib@^2.0.0, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.4.0, tslib@^2.6.2, tslib@^2.8.0: +tslib@2, tslib@^2.0.0, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.4.0, tslib@^2.6.2, tslib@^2.8.0, tslib@^2.8.1: version "2.8.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== @@ -15033,13 +16758,19 @@ type-fest@^4.27.0: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-4.33.0.tgz#2da0c135b9afa76cf8b18ecfd4f260ecd414a432" integrity sha512-s6zVrxuyKbbAsSAD5ZPTB77q4YIdRctkTbJ2/Dqlinwz+8ooH2gd+YA7VA6Pa93KML9GockVvoxjZ2vHP+mu8g== -type-is@~1.6.18: - version "1.6.18" - resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" - integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== +type-fest@^4.39.1: + version "4.40.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-4.40.0.tgz#62bc09caccb99a75e1ad6b9b4653e8805e5e1eee" + integrity sha512-ABHZ2/tS2JkvH1PEjxFDTUWC8dB5OsIGZP4IFLhR293GqT5Y5qB1WwL2kMPYhQW9DVgVD8Hd7I8gjwPIf5GFkw== + +type-is@^2.0.0, type-is@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-2.0.1.tgz#64f6cf03f92fce4015c2b224793f6bdd4b068c97" + integrity sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw== dependencies: - media-typer "0.3.0" - mime-types "~2.1.24" + content-type "^1.0.5" + media-typer "^1.1.0" + mime-types "^3.0.0" typed-array-buffer@^1.0.3: version "1.0.3" @@ -15086,10 +16817,10 @@ typed-array-length@^1.0.7: possible-typed-array-names "^1.0.0" reflect.getprototypeof "^1.0.6" -typescript@*, typescript@5.8.2, typescript@^5.0.4: - version "5.8.2" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.8.2.tgz#8170b3702f74b79db2e5a96207c15e65807999e4" - integrity sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ== +typescript@*, typescript@5.8.3, typescript@^5.0.4: + version "5.8.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.8.3.tgz#92f8a3e5e3cf497356f4178c34cd65a7f5e8440e" + integrity sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ== uc.micro@^2.0.0, uc.micro@^2.1.0: version "2.1.0" @@ -15119,10 +16850,10 @@ underscore.string@~3.3.4: sprintf-js "^1.1.1" util-deprecate "^1.0.2" -undici-types@~6.20.0: - version "6.20.0" - resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.20.0.tgz#8171bf22c1f588d1554d55bf204bc624af388433" - integrity sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg== +undici-types@~6.21.0: + version "6.21.0" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.21.0.tgz#691d00af3909be93a7faa13be61b3a5b50ef12cb" + integrity sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ== undici@^6.19.5: version "6.21.1" @@ -15292,7 +17023,7 @@ universalify@^2.0.0: resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.1.tgz#168efc2180964e6386d061e094df61afe239b18d" integrity sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw== -unpipe@1.0.0, unpipe@~1.0.0: +unpipe@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== @@ -15382,11 +17113,6 @@ util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== -utils-merge@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" - integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== - uuid@11.1.0: version "11.1.0" resolved "https://registry.yarnpkg.com/uuid/-/uuid-11.1.0.tgz#9549028be1753bb934fc96e2bca09bb4105ae912" @@ -15436,7 +17162,7 @@ value-or-function@^4.0.0: resolved "https://registry.yarnpkg.com/value-or-function/-/value-or-function-4.0.0.tgz#70836b6a876a010dc3a2b884e7902e9db064378d" integrity sha512-aeVK81SIuT6aMJfNo9Vte8Dw0/FZINGBV8BfCraGtqVxIeLAEhJyoWs8SmvRVmXfGss2PmmOwZCuBPbZR+IYWg== -vary@^1, vary@~1.1.2: +vary@^1, vary@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== @@ -15604,7 +17330,7 @@ web-namespaces@^2.0.0: resolved "https://registry.yarnpkg.com/web-namespaces/-/web-namespaces-2.0.1.tgz#1010ff7c650eccb2592cebeeaf9a1b253fd40692" integrity sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ== -web-vitals@^4.2.0: +web-vitals@^4.2.4: version "4.2.4" resolved "https://registry.yarnpkg.com/web-vitals/-/web-vitals-4.2.4.tgz#1d20bc8590a37769bd0902b289550936069184b7" integrity sha512-r4DIlprAGwJ7YM11VZp4R884m0Vmgr6EAKe3P+kO0PPj3Unqyvv59rczf6UiGcb9Z8QxZVcqKNwv/g0WNdWwsw== @@ -15642,10 +17368,10 @@ webpack-virtual-modules@^0.5.0: resolved "https://registry.yarnpkg.com/webpack-virtual-modules/-/webpack-virtual-modules-0.5.0.tgz#362f14738a56dae107937ab98ea7062e8bdd3b6c" integrity sha512-kyDivFZ7ZM0BVOUteVbDFhlRt7Ah/CSPwJdi8hBpkK7QLumUqdLtVfm/PX/hkcnrvr0i77fO5+TjZ94Pe+C9iw== -webpack@5.98.0: - version "5.98.0" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.98.0.tgz#44ae19a8f2ba97537978246072fb89d10d1fbd17" - integrity sha512-UFynvx+gM44Gv9qFgj0acCQK2VE1CtdfwFdimkapco3hlPCJ/zeq73n2yVKimVbtm+TnApIugGhLJnkU6gjYXA== +webpack@5.99.6: + version "5.99.6" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.99.6.tgz#0d6ba7ce1d3609c977f193d2634d54e5cf36379d" + integrity sha512-TJOLrJ6oeccsGWPl7ujCYuc0pIq2cNsuD6GZDma8i5o5Npvcco/z+NKvZSFsP0/x6SShVb0+X2JK/JHUjKY9dQ== dependencies: "@types/eslint-scope" "^3.7.7" "@types/estree" "^1.0.6" @@ -16054,13 +17780,6 @@ xtend@^4.0.0, xtend@~4.0.1: resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== -y-prosemirror@1.2.13: - version "1.2.13" - resolved "https://registry.yarnpkg.com/y-prosemirror/-/y-prosemirror-1.2.13.tgz#1355c82474e66e4fb9644ed0104cf0af5a9766b1" - integrity sha512-eW5/rJcYhqlrqyPLTaGIaPSt7YS6f2wwbV5wXlUkY8rERY0tSJPoumsPD7UWwtXk9C5TdTsvwaIrdOoD1QLbYA== - dependencies: - lib0 "^0.2.42" - y-prosemirror@1.2.17: version "1.2.17" resolved "https://registry.yarnpkg.com/y-prosemirror/-/y-prosemirror-1.2.17.tgz#6c50cd87fd21f7cdb6617cee281d43a034215a56" @@ -16108,10 +17827,10 @@ yargs@17.7.2, yargs@^17.3.1: y18n "^5.0.5" yargs-parser "^21.1.1" -yjs@*, yjs@13.6.23, yjs@^13.6.15: - version "13.6.23" - resolved "https://registry.yarnpkg.com/yjs/-/yjs-13.6.23.tgz#62358dfa52e92dc870b8a0bedcf0d4cbd4c5ffa8" - integrity sha512-ExtnT5WIOVpkL56bhLeisG/N5c4fmzKn4k0ROVfJa5TY2QHbH7F0Wu2T5ZhR7ErsFWQEFafyrnSI8TPKVF9Few== +yjs@*, yjs@13.6.26, yjs@^13.6.15: + version "13.6.26" + resolved "https://registry.yarnpkg.com/yjs/-/yjs-13.6.26.tgz#ab0928484f20249bcbe01a73e911b57d918f1bae" + integrity sha512-wiARO3wixu7mtoRP5f7LqpUtsURP9SmNgXUt3RlnZg4qDuF7dUjthwIvwxIDmK55dPw4Wl4QdW5A3ag0atwu7g== dependencies: lib0 "^0.2.99" From b90c5375eecf88fc3a5c9615a54e0af1559ba01b Mon Sep 17 00:00:00 2001 From: Nathan Panchout Date: Mon, 17 Mar 2025 14:46:59 +0100 Subject: [PATCH 10/26] =?UTF-8?q?=F0=9F=90=9B(back)=20keep=20info=20if=20d?= =?UTF-8?q?ocument=20has=20deleted=20children?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With the soft delete feature, relying on the is_leaf method from the treebeard is not accurate anymore. To determine if a node is a leaf, it checks if the number of numchild is equal to 0. But a node can have soft deleted children, then numchild is equal to 0, but it is not a leaf because if we want to add a child we have to look for the last child to compute a correct path. Otherwise we will have an error saying that the path already exists. --- ...0021_remove_document_is_public_and_more.py | 17 +++++++ src/backend/core/models.py | 11 ++++- .../core/tests/test_models_documents.py | 44 +++++++++++++++++++ 3 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 src/backend/core/migrations/0021_remove_document_is_public_and_more.py diff --git a/src/backend/core/migrations/0021_remove_document_is_public_and_more.py b/src/backend/core/migrations/0021_remove_document_is_public_and_more.py new file mode 100644 index 000000000..97eaa4681 --- /dev/null +++ b/src/backend/core/migrations/0021_remove_document_is_public_and_more.py @@ -0,0 +1,17 @@ +# Generated by Django 5.1.7 on 2025-03-14 14:03 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("core", "0020_remove_is_public_add_field_attachments_and_duplicated_from"), + ] + + operations = [ + migrations.AddField( + model_name="document", + name="has_deleted_children", + field=models.BooleanField(default=False), + ), + ] diff --git a/src/backend/core/models.py b/src/backend/core/models.py index 2c5239ead..fd2211c61 100644 --- a/src/backend/core/models.py +++ b/src/backend/core/models.py @@ -464,6 +464,7 @@ def get_queryset(self): return self._queryset_class(self.model).order_by("path") +# pylint: disable=too-many-public-methods class Document(MP_Node, BaseModel): """Pad document carrying the content.""" @@ -486,6 +487,7 @@ class Document(MP_Node, BaseModel): ) deleted_at = models.DateTimeField(null=True, blank=True) ancestors_deleted_at = models.DateTimeField(null=True, blank=True) + has_deleted_children = models.BooleanField(default=False) duplicated_from = models.ForeignKey( "self", on_delete=models.SET_NULL, @@ -561,6 +563,12 @@ def save(self, *args, **kwargs): content_file = ContentFile(bytes_content) default_storage.save(file_key, content_file) + def is_leaf(self): + """ + :returns: True if the node is has no children + """ + return not self.has_deleted_children and self.numchild == 0 + @property def key_base(self): """Key base of the location where the document is stored in object storage.""" @@ -945,7 +953,8 @@ def soft_delete(self): if self.depth > 1: self._meta.model.objects.filter(pk=self.get_parent().pk).update( - numchild=models.F("numchild") - 1 + numchild=models.F("numchild") - 1, + has_deleted_children=True, ) # Mark all descendants as soft deleted diff --git a/src/backend/core/tests/test_models_documents.py b/src/backend/core/tests/test_models_documents.py index 3f2b8d6e0..96ac76e73 100644 --- a/src/backend/core/tests/test_models_documents.py +++ b/src/backend/core/tests/test_models_documents.py @@ -1307,6 +1307,50 @@ def test_models_documents_get_select_options(ancestors_links, select_options): assert models.LinkReachChoices.get_select_options(ancestors_links) == select_options +def test_models_documents_children_create_after_sibling_deletion(): + """ + It should be possible to create a new child after all children have been deleted. + """ + + root = factories.DocumentFactory() + assert root.numchild == 0 + assert root.has_deleted_children is False + assert root.is_leaf() is True + child1 = factories.DocumentFactory(parent=root) + child2 = factories.DocumentFactory(parent=root) + + root.refresh_from_db() + assert root.numchild == 2 + assert root.has_deleted_children is False + assert root.is_leaf() is False + + child1.soft_delete() + child2.soft_delete() + root.refresh_from_db() + assert root.numchild == 0 + assert root.has_deleted_children is True + assert root.is_leaf() is False + + factories.DocumentFactory(parent=root) + root.refresh_from_db() + assert root.numchild == 1 + assert root.has_deleted_children is True + assert root.is_leaf() is False + + +def test_models_documents_has_deleted_children(): + """ + A document should have its has_deleted_children attribute set to True if one of its children + has been solf deleted no matter if numchild is 0 or not. + """ + root = factories.DocumentFactory() + child = factories.DocumentFactory(parent=root) + assert root.has_deleted_children is False + child.soft_delete() + root.refresh_from_db() + assert root.has_deleted_children is True + + def test_models_documents_compute_ancestors_links_no_highest_readable(): """Test the compute_ancestors_links method.""" document = factories.DocumentFactory(link_reach="public") From 9eadaf3d1edb5df73163811ca707fa22a97933ff Mon Sep 17 00:00:00 2001 From: Nathan Panchout Date: Mon, 17 Mar 2025 14:48:42 +0100 Subject: [PATCH 11/26] =?UTF-8?q?=E2=9E=95(frontend)=20updated=20dependenc?= =?UTF-8?q?ies=20and=20added=20new=20packages?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added several new dependencies to the `package.json` file, including `@dnd-kit/core`, `@dnd-kit/modifiers`, `@fontsource/material-icons`, and `@gouvfr-lasuite/ui-kit`. --- src/frontend/apps/impress/package.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/frontend/apps/impress/package.json b/src/frontend/apps/impress/package.json index 45fbe9e68..f83bb47be 100644 --- a/src/frontend/apps/impress/package.json +++ b/src/frontend/apps/impress/package.json @@ -21,6 +21,8 @@ "@blocknote/react": "0.23.2-hotfix.0", "@blocknote/xl-docx-exporter": "0.23.2-hotfix.0", "@blocknote/xl-pdf-exporter": "0.23.2-hotfix.0", + "@dnd-kit/core": "6.3.1", + "@dnd-kit/modifiers": "9.0.0", "@fontsource/material-icons": "5.2.5", "@gouvfr-lasuite/integration": "1.0.3", "@gouvfr-lasuite/ui-kit": "0.4.0", From 4ec3f4290396a8b05b468fc3a466863249f3b925 Mon Sep 17 00:00:00 2001 From: Nathan Panchout Date: Mon, 17 Mar 2025 15:12:12 +0100 Subject: [PATCH 12/26] =?UTF-8?q?=E2=9C=A8(frontend)=20Added=20drag-and-dr?= =?UTF-8?q?op=20functionality=20for=20document=20management?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added a new feature for moving documents within the user interface via drag-and-drop. This includes the creation of Draggable and Droppable components, as well as tests to verify document creation and movement behavior. Changes have also been made to document types to include user roles and child management capabilities. --- .../apps/e2e/__tests__/app-impress/common.ts | 17 + .../__tests__/app-impress/doc-editor.spec.ts | 2 - .../app-impress/doc-grid-dnd.spec.ts | 311 ++++++++++++++++++ .../__tests__/app-impress/doc-grid.spec.ts | 2 + .../__tests__/app-impress/doc-header.spec.ts | 4 +- .../features/docs/doc-management/types.tsx | 8 +- .../features/docs/doc-tree/api/useMove.tsx | 36 ++ .../components/DocGridContentList.tsx | 173 ++++++++++ .../docs/docs-grid/components/DocsGrid.tsx | 11 +- .../docs-grid/components/DocsGridItem.tsx | 55 ++-- .../docs/docs-grid/components/Draggable.tsx | 26 ++ .../docs/docs-grid/components/Droppable.tsx | 53 +++ .../docs-grid/components/SimpleDocItem.tsx | 1 + .../docs/docs-grid/hooks/useDragAndDrop.tsx | 70 ++++ .../src/features/service-worker/ApiPlugin.ts | 2 + 15 files changed, 739 insertions(+), 32 deletions(-) create mode 100644 src/frontend/apps/e2e/__tests__/app-impress/doc-grid-dnd.spec.ts create mode 100644 src/frontend/apps/impress/src/features/docs/doc-tree/api/useMove.tsx create mode 100644 src/frontend/apps/impress/src/features/docs/docs-grid/components/DocGridContentList.tsx create mode 100644 src/frontend/apps/impress/src/features/docs/docs-grid/components/Draggable.tsx create mode 100644 src/frontend/apps/impress/src/features/docs/docs-grid/components/Droppable.tsx create mode 100644 src/frontend/apps/impress/src/features/docs/docs-grid/hooks/useDragAndDrop.tsx diff --git a/src/frontend/apps/e2e/__tests__/app-impress/common.ts b/src/frontend/apps/e2e/__tests__/app-impress/common.ts index 874be8cd7..32c377662 100644 --- a/src/frontend/apps/e2e/__tests__/app-impress/common.ts +++ b/src/frontend/apps/e2e/__tests__/app-impress/common.ts @@ -213,6 +213,7 @@ export const mockedDocument = async (page: Page, json: object) => { }, link_reach: 'restricted', created_at: '2021-09-01T09:00:00Z', + user_roles: ['owner'], ...json, }, }); @@ -222,6 +223,22 @@ export const mockedDocument = async (page: Page, json: object) => { }); }; +export const mockedListDocs = async (page: Page, data: object[] = []) => { + await page.route('**/documents/**/', async (route) => { + const request = route.request(); + if (request.method().includes('GET') && request.url().includes('page=')) { + await route.fulfill({ + json: { + count: data.length, + next: null, + previous: null, + results: data, + }, + }); + } + }); +}; + export const mockedInvitations = async (page: Page, json?: object) => { await page.route('**/invitations/**/', async (route) => { const request = route.request(); diff --git a/src/frontend/apps/e2e/__tests__/app-impress/doc-editor.spec.ts b/src/frontend/apps/e2e/__tests__/app-impress/doc-editor.spec.ts index 09f0cde2e..cc272a143 100644 --- a/src/frontend/apps/e2e/__tests__/app-impress/doc-editor.spec.ts +++ b/src/frontend/apps/e2e/__tests__/app-impress/doc-editor.spec.ts @@ -364,8 +364,6 @@ test.describe('Doc Editor', () => { retrieve: true, }, link_reach: 'public', - link_role: 'editor', - created_at: '2021-09-01T09:00:00Z', title: '', }); diff --git a/src/frontend/apps/e2e/__tests__/app-impress/doc-grid-dnd.spec.ts b/src/frontend/apps/e2e/__tests__/app-impress/doc-grid-dnd.spec.ts new file mode 100644 index 000000000..924d3db5f --- /dev/null +++ b/src/frontend/apps/e2e/__tests__/app-impress/doc-grid-dnd.spec.ts @@ -0,0 +1,311 @@ +import { expect, test } from '@playwright/test'; + +import { createDoc, mockedListDocs } from './common'; + +test.describe('Doc grid dnd', () => { + test('it creates a doc', async ({ page, browserName }) => { + await page.goto('/'); + const header = page.locator('header').first(); + await createDoc(page, 'Draggable doc', browserName, 1); + await header.locator('h2').getByText('Docs').click(); + await createDoc(page, 'Droppable doc', browserName, 1); + await header.locator('h2').getByText('Docs').click(); + + const response = await page.waitForResponse( + (response) => + response.url().endsWith('documents/?page=1') && + response.status() === 200, + ); + const responseJson = await response.json(); + + const items = responseJson.results; + + const docsGrid = page.getByTestId('docs-grid'); + await expect(docsGrid).toBeVisible(); + await expect(page.getByTestId('grid-loader')).toBeHidden(); + const draggableElement = page.getByTestId(`draggable-doc-${items[1].id}`); + const dropZone = page.getByTestId(`droppable-doc-${items[0].id}`); + await expect(draggableElement).toBeVisible(); + await expect(dropZone).toBeVisible(); + + // Obtenir les positions des éléments + const draggableBoundingBox = await draggableElement.boundingBox(); + const dropZoneBoundingBox = await dropZone.boundingBox(); + + expect(draggableBoundingBox).toBeDefined(); + expect(dropZoneBoundingBox).toBeDefined(); + + // eslint-disable-next-line playwright/no-conditional-in-test + if (!draggableBoundingBox || !dropZoneBoundingBox) { + throw new Error('Impossible de déterminer la position des éléments'); + } + + await page.mouse.move( + draggableBoundingBox.x + draggableBoundingBox.width / 2, + draggableBoundingBox.y + draggableBoundingBox.height / 2, + ); + await page.mouse.down(); + + // Déplacer vers la zone cible + await page.mouse.move( + dropZoneBoundingBox.x + dropZoneBoundingBox.width / 2, + dropZoneBoundingBox.y + dropZoneBoundingBox.height / 2, + { steps: 10 }, // Rendre le mouvement plus fluide + ); + + const dragOverlay = page.getByTestId('drag-doc-overlay'); + + await expect(dragOverlay).toBeVisible(); + await expect(dragOverlay).toHaveText(items[1].title as string); + await page.mouse.up(); + + await expect(dragOverlay).toBeHidden(); + }); + + test('it checks cant drop when we have not the minimum role', async ({ + page, + }) => { + await mockedListDocs(page, data); + await page.goto('/'); + const docsGrid = page.getByTestId('docs-grid'); + await expect(docsGrid).toBeVisible(); + await expect(page.getByTestId('grid-loader')).toBeHidden(); + + const canDropAndDrag = page.getByTestId('droppable-doc-can-drop-and-drag'); + + const noDropAndNoDrag = page.getByTestId( + 'droppable-doc-no-drop-and-no-drag', + ); + + await expect(canDropAndDrag).toBeVisible(); + + await expect(noDropAndNoDrag).toBeVisible(); + + const canDropAndDragBoundigBox = await canDropAndDrag.boundingBox(); + + const noDropAndNoDragBoundigBox = await noDropAndNoDrag.boundingBox(); + + // eslint-disable-next-line playwright/no-conditional-in-test + if (!canDropAndDragBoundigBox || !noDropAndNoDragBoundigBox) { + throw new Error('Impossible de déterminer la position des éléments'); + } + + await page.mouse.move( + canDropAndDragBoundigBox.x + canDropAndDragBoundigBox.width / 2, + canDropAndDragBoundigBox.y + canDropAndDragBoundigBox.height / 2, + ); + + await page.mouse.down(); + + await page.mouse.move( + noDropAndNoDragBoundigBox.x + noDropAndNoDragBoundigBox.width / 2, + noDropAndNoDragBoundigBox.y + noDropAndNoDragBoundigBox.height / 2, + { steps: 10 }, + ); + + const dragOverlay = page.getByTestId('drag-doc-overlay'); + + await expect(dragOverlay).toBeVisible(); + await expect(dragOverlay).toHaveText( + 'You must be at least the editor of the target document', + ); + + await page.mouse.up(); + }); + + test('it checks cant drag when we have not the minimum role', async ({ + page, + }) => { + await mockedListDocs(page, data); + await page.goto('/'); + const docsGrid = page.getByTestId('docs-grid'); + await expect(docsGrid).toBeVisible(); + await expect(page.getByTestId('grid-loader')).toBeHidden(); + + const canDropAndDrag = page.getByTestId('droppable-doc-can-drop-and-drag'); + + const noDropAndNoDrag = page.getByTestId( + 'droppable-doc-no-drop-and-no-drag', + ); + + await expect(canDropAndDrag).toBeVisible(); + + await expect(noDropAndNoDrag).toBeVisible(); + + const canDropAndDragBoundigBox = await canDropAndDrag.boundingBox(); + + const noDropAndNoDragBoundigBox = await noDropAndNoDrag.boundingBox(); + + // eslint-disable-next-line playwright/no-conditional-in-test + if (!canDropAndDragBoundigBox || !noDropAndNoDragBoundigBox) { + throw new Error('Impossible de déterminer la position des éléments'); + } + + await page.mouse.move( + noDropAndNoDragBoundigBox.x + noDropAndNoDragBoundigBox.width / 2, + noDropAndNoDragBoundigBox.y + noDropAndNoDragBoundigBox.height / 2, + ); + + await page.mouse.down(); + + await page.mouse.move( + canDropAndDragBoundigBox.x + canDropAndDragBoundigBox.width / 2, + canDropAndDragBoundigBox.y + canDropAndDragBoundigBox.height / 2, + { steps: 10 }, + ); + + const dragOverlay = page.getByTestId('drag-doc-overlay'); + + await expect(dragOverlay).toBeVisible(); + await expect(dragOverlay).toHaveText( + 'You must be the owner to move the document', + ); + + await page.mouse.up(); + }); +}); + +const data = [ + { + id: 'can-drop-and-drag', + abilities: { + accesses_manage: true, + accesses_view: true, + ai_transform: true, + ai_translate: true, + attachment_upload: true, + children_list: true, + children_create: true, + collaboration_auth: true, + descendants: true, + destroy: true, + favorite: true, + link_configuration: true, + invite_owner: true, + move: true, + partial_update: true, + restore: true, + retrieve: true, + media_auth: true, + link_select_options: { + restricted: ['reader', 'editor'], + authenticated: ['reader', 'editor'], + public: ['reader', 'editor'], + }, + tree: true, + update: true, + versions_destroy: true, + versions_list: true, + versions_retrieve: true, + }, + created_at: '2025-03-14T14:45:22.527221Z', + creator: 'bc6895e0-8f6d-4b00-827d-c143aa6b2ecb', + depth: 1, + excerpt: null, + is_favorite: false, + link_role: 'reader', + link_reach: 'restricted', + nb_accesses_ancestors: 1, + nb_accesses_direct: 1, + numchild: 5, + path: '000000o', + title: 'Can drop and drag', + updated_at: '2025-03-14T14:45:27.699542Z', + user_roles: ['owner'], + }, + { + id: 'can-only-drop', + title: 'Can only drop', + abilities: { + accesses_manage: true, + accesses_view: true, + ai_transform: true, + ai_translate: true, + attachment_upload: true, + children_list: true, + children_create: true, + collaboration_auth: true, + descendants: true, + destroy: true, + favorite: true, + link_configuration: true, + invite_owner: true, + move: true, + partial_update: true, + restore: true, + retrieve: true, + media_auth: true, + link_select_options: { + restricted: ['reader', 'editor'], + authenticated: ['reader', 'editor'], + public: ['reader', 'editor'], + }, + tree: true, + update: true, + versions_destroy: true, + versions_list: true, + versions_retrieve: true, + }, + created_at: '2025-03-14T14:45:22.527221Z', + creator: 'bc6895e0-8f6d-4b00-827d-c143aa6b2ecb', + depth: 1, + excerpt: null, + is_favorite: false, + link_role: 'reader', + link_reach: 'restricted', + nb_accesses_ancestors: 1, + nb_accesses_direct: 1, + numchild: 5, + path: '000000o', + + updated_at: '2025-03-14T14:45:27.699542Z', + user_roles: ['editor'], + }, + { + id: 'no-drop-and-no-drag', + abilities: { + accesses_manage: false, + accesses_view: true, + ai_transform: false, + ai_translate: false, + attachment_upload: false, + children_list: true, + children_create: false, + collaboration_auth: true, + descendants: true, + destroy: false, + favorite: true, + link_configuration: false, + invite_owner: false, + move: false, + partial_update: false, + restore: false, + retrieve: true, + media_auth: true, + link_select_options: { + restricted: ['reader', 'editor'], + authenticated: ['reader', 'editor'], + public: ['reader', 'editor'], + }, + tree: true, + update: false, + versions_destroy: false, + versions_list: true, + versions_retrieve: true, + }, + created_at: '2025-03-14T14:44:16.032773Z', + creator: '9264f420-f018-4bd6-96ae-4788f41af56d', + depth: 1, + excerpt: null, + is_favorite: false, + link_role: 'reader', + link_reach: 'restricted', + nb_accesses_ancestors: 14, + nb_accesses_direct: 14, + numchild: 0, + path: '000000l', + title: 'No drop and no drag', + updated_at: '2025-03-14T14:44:16.032774Z', + user_roles: ['reader'], + }, +]; diff --git a/src/frontend/apps/e2e/__tests__/app-impress/doc-grid.spec.ts b/src/frontend/apps/e2e/__tests__/app-impress/doc-grid.spec.ts index 758c8712c..71083ef52 100644 --- a/src/frontend/apps/e2e/__tests__/app-impress/doc-grid.spec.ts +++ b/src/frontend/apps/e2e/__tests__/app-impress/doc-grid.spec.ts @@ -59,6 +59,7 @@ test.describe('Documents Grid mobile', () => { link_reach: 'public', created_at: '2024-10-07T13:02:41.085298Z', updated_at: '2024-10-07T13:30:21.829690Z', + user_roles: ['owner'], }, ], }, @@ -168,6 +169,7 @@ test.describe('Document grid item options', () => { }, link_reach: 'restricted', created_at: '2021-09-01T09:00:00Z', + user_roles: ['editor'], }, ], }, diff --git a/src/frontend/apps/e2e/__tests__/app-impress/doc-header.spec.ts b/src/frontend/apps/e2e/__tests__/app-impress/doc-header.spec.ts index be1bfcad1..ba33ddb0f 100644 --- a/src/frontend/apps/e2e/__tests__/app-impress/doc-header.spec.ts +++ b/src/frontend/apps/e2e/__tests__/app-impress/doc-header.spec.ts @@ -96,7 +96,9 @@ test.describe('Doc Header', () => { ).toBeVisible(); await expect( - page.getByText(`Are you sure you want to delete this document ?`), + page.getByText( + `Are you sure you want to delete the document "${randomDoc}"?`, + ), ).toBeVisible(); await page diff --git a/src/frontend/apps/impress/src/features/docs/doc-management/types.tsx b/src/frontend/apps/impress/src/features/docs/doc-management/types.tsx index e57dc6e14..2cc117b73 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-management/types.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-management/types.tsx @@ -42,10 +42,14 @@ export interface Doc { is_favorite: boolean; link_reach: LinkReach; link_role: LinkRole; - nb_accesses_ancestors: number; - nb_accesses_direct: number; + user_roles: Role[]; created_at: string; updated_at: string; + nb_accesses_direct: number; + nb_accesses_ancestors: number; + children?: Doc[]; + childrenCount?: number; + numchild: number; abilities: { accesses_manage: boolean; accesses_view: boolean; diff --git a/src/frontend/apps/impress/src/features/docs/doc-tree/api/useMove.tsx b/src/frontend/apps/impress/src/features/docs/doc-tree/api/useMove.tsx new file mode 100644 index 000000000..1ba87df43 --- /dev/null +++ b/src/frontend/apps/impress/src/features/docs/doc-tree/api/useMove.tsx @@ -0,0 +1,36 @@ +import { TreeViewMoveModeEnum } from '@gouvfr-lasuite/ui-kit'; +import { useMutation } from '@tanstack/react-query'; + +import { APIError, errorCauses, fetchAPI } from '@/api'; + +export type MoveDocParam = { + sourceDocumentId: string; + targetDocumentId: string; + position: TreeViewMoveModeEnum; +}; + +export const moveDoc = async ({ + sourceDocumentId, + targetDocumentId, + position, +}: MoveDocParam): Promise => { + const response = await fetchAPI(`documents/${sourceDocumentId}/move/`, { + method: 'POST', + body: JSON.stringify({ + target_document_id: targetDocumentId, + position, + }), + }); + + if (!response.ok) { + throw new APIError('Failed to move the doc', await errorCauses(response)); + } + + return response.json() as Promise; +}; + +export function useMoveDoc() { + return useMutation({ + mutationFn: moveDoc, + }); +} diff --git a/src/frontend/apps/impress/src/features/docs/docs-grid/components/DocGridContentList.tsx b/src/frontend/apps/impress/src/features/docs/docs-grid/components/DocGridContentList.tsx new file mode 100644 index 000000000..6d03cac77 --- /dev/null +++ b/src/frontend/apps/impress/src/features/docs/docs-grid/components/DocGridContentList.tsx @@ -0,0 +1,173 @@ +import { DndContext, DragOverlay, Modifier } from '@dnd-kit/core'; +import { getEventCoordinates } from '@dnd-kit/utilities'; +import { TreeViewMoveModeEnum } from '@gouvfr-lasuite/ui-kit'; +import { useQueryClient } from '@tanstack/react-query'; +import { useMemo } from 'react'; +import { useTranslation } from 'react-i18next'; + +import { Box, Text } from '@/components'; +import { Doc, KEY_LIST_DOC, Role } from '@/docs/doc-management'; +import { useMoveDoc } from '@/docs/doc-tree/api/useMove'; + +import { useDragAndDrop } from '../hooks/useDragAndDrop'; + +import { DocsGridItem } from './DocsGridItem'; +import { Draggable } from './Draggable'; +import { Droppable } from './Droppable'; + +const snapToTopLeft: Modifier = ({ + activatorEvent, + draggingNodeRect, + transform, +}) => { + if (draggingNodeRect && activatorEvent) { + const activatorCoordinates = getEventCoordinates(activatorEvent); + + if (!activatorCoordinates) { + return transform; + } + + const offsetX = activatorCoordinates.x - draggingNodeRect.left; + const offsetY = activatorCoordinates.y - draggingNodeRect.top; + + return { + ...transform, + x: transform.x + offsetX - 3, + y: transform.y + offsetY - 3, + }; + } + + return transform; +}; + +type DocGridContentListProps = { + docs: Doc[]; +}; + +export const DocGridContentList = ({ docs }: DocGridContentListProps) => { + const { mutate: handleMove, isError } = useMoveDoc(); + const queryClient = useQueryClient(); + const onDrag = (sourceDocumentId: string, targetDocumentId: string) => + handleMove( + { + sourceDocumentId, + targetDocumentId, + position: TreeViewMoveModeEnum.FIRST_CHILD, + }, + { + onSuccess: () => { + void queryClient.invalidateQueries({ + queryKey: [KEY_LIST_DOC], + }); + }, + }, + ); + + const { + selectedDoc, + canDrag, + canDrop, + sensors, + handleDragStart, + handleDragEnd, + updateCanDrop, + } = useDragAndDrop(onDrag); + + const { t } = useTranslation(); + + const overlayText = useMemo(() => { + if (!canDrag) { + return t('You must be the owner to move the document'); + } + if (!canDrop) { + return t('You must be at least the editor of the target document'); + } + + return selectedDoc?.title || t('Unnamed document'); + }, [canDrag, canDrop, selectedDoc, t]); + + const overlayBgColor = useMemo(() => { + if (!canDrag) { + return 'var(--c--theme--colors--danger-600)'; + } + if (canDrop !== undefined && !canDrop) { + return 'var(--c--theme--colors--danger-600)'; + } + if (isError) { + return 'var(--c--theme--colors--danger-600)'; + } + + return '#5858D3'; + }, [canDrag, canDrop, isError]); + + if (docs.length === 0) { + return null; + } + + return ( + + {docs.map((doc) => ( + + ))} + + + + {overlayText} + + + + + ); +}; + +interface DocGridItemProps { + doc: Doc; + dragMode: boolean; + canDrag: boolean; + updateCanDrop: (canDrop: boolean, isOver: boolean) => void; +} + +export const DraggableDocGridItem = ({ + doc, + dragMode, + canDrag, + updateCanDrop, +}: DocGridItemProps) => { + const canDropItem = doc.user_roles.some( + (role) => + role === Role.ADMIN || role === Role.OWNER || role === Role.EDITOR, + ); + + return ( + updateCanDrop(canDropItem, isOver)} + id={doc.id} + data={doc} + > + + + + + ); +}; diff --git a/src/frontend/apps/impress/src/features/docs/docs-grid/components/DocsGrid.tsx b/src/frontend/apps/impress/src/features/docs/docs-grid/components/DocsGrid.tsx index 534252102..fc0dba2ff 100644 --- a/src/frontend/apps/impress/src/features/docs/docs-grid/components/DocsGrid.tsx +++ b/src/frontend/apps/impress/src/features/docs/docs-grid/components/DocsGrid.tsx @@ -9,7 +9,7 @@ import { useResponsiveStore } from '@/stores'; import { useResponsiveDocGrid } from '../hooks/useResponsiveDocGrid'; -import { DocsGridItem } from './DocsGridItem'; +import { DocGridContentList } from './DocGridContentList'; import { DocsGridLoader } from './DocsGridLoader'; type DocsGridProps = { @@ -37,6 +37,9 @@ export const DocsGrid = ({ is_creator_me: target === DocDefaultFilter.MY_DOCS, }), }); + + const docs = data?.pages.flatMap((page) => page.results) ?? []; + const loading = isFetching || isLoading; const hasDocs = data?.pages.some((page) => page.results.length > 0); const loadMore = (inView: boolean) => { @@ -115,11 +118,7 @@ export const DocsGrid = ({ )} - {data?.pages.map((currentPage) => { - return currentPage.results.map((doc) => ( - - )); - })} + {hasNextPage && !loading && ( { +export const DocsGridItem = ({ doc, dragMode = false }: DocsGridItemProps) => { const { t } = useTranslation(); const { isDesktop } = useResponsiveStore(); const { flexLeft, flexRight } = useResponsiveDocGrid(); @@ -45,7 +46,9 @@ export const DocsGridItem = ({ doc }: DocsGridItemProps) => { cursor: pointer; border-radius: 4px; &:hover { - background-color: var(--c--theme--colors--greyscale-100); + background-color: ${dragMode + ? 'none' + : 'var(--c--theme--colors--greyscale-100)'}; } `} className="--docs--doc-grid-item" @@ -79,25 +82,35 @@ export const DocsGridItem = ({ doc }: DocsGridItemProps) => { : undefined } > - - {isPublic - ? t('Accessible to anyone') - : t('Accessible to authenticated users')} - - } - placement="top" - > -
- -
- + {dragMode && ( + + )} + {!dragMode && ( + + {isPublic + ? t('Accessible to anyone') + : t('Accessible to authenticated users')} +
+ } + placement="top" + > +
+ +
+ + )}
)}
diff --git a/src/frontend/apps/impress/src/features/docs/docs-grid/components/Draggable.tsx b/src/frontend/apps/impress/src/features/docs/docs-grid/components/Draggable.tsx new file mode 100644 index 000000000..bafacf0b4 --- /dev/null +++ b/src/frontend/apps/impress/src/features/docs/docs-grid/components/Draggable.tsx @@ -0,0 +1,26 @@ +import { Data, useDraggable } from '@dnd-kit/core'; + +type DraggableProps = { + id: string; + data?: Data; + children: React.ReactNode; +}; + +export const Draggable = (props: DraggableProps) => { + const { attributes, listeners, setNodeRef } = useDraggable({ + id: props.id, + data: props.data, + }); + + return ( +
+ {props.children} +
+ ); +}; diff --git a/src/frontend/apps/impress/src/features/docs/docs-grid/components/Droppable.tsx b/src/frontend/apps/impress/src/features/docs/docs-grid/components/Droppable.tsx new file mode 100644 index 000000000..851bf6f6e --- /dev/null +++ b/src/frontend/apps/impress/src/features/docs/docs-grid/components/Droppable.tsx @@ -0,0 +1,53 @@ +import { Data, useDroppable } from '@dnd-kit/core'; +import { PropsWithChildren, useEffect } from 'react'; +import { css } from 'styled-components'; + +import { Box } from '@/components'; +import { Doc } from '@/docs/doc-management'; + +type DroppableProps = { + id: string; + onOver?: (isOver: boolean, data?: Data) => void; + data?: Data; + enabledDrop?: boolean; + canDrop?: boolean; +}; + +export const Droppable = ({ + onOver, + canDrop, + data, + children, + id, +}: PropsWithChildren) => { + const { isOver, setNodeRef } = useDroppable({ + id, + data, + }); + + const enableHover = canDrop && isOver; + + useEffect(() => { + onOver?.(isOver, data); + }, [isOver, data, onOver]); + + return ( + + {children} + + ); +}; diff --git a/src/frontend/apps/impress/src/features/docs/docs-grid/components/SimpleDocItem.tsx b/src/frontend/apps/impress/src/features/docs/docs-grid/components/SimpleDocItem.tsx index 1a02d87a6..87c9387c9 100644 --- a/src/frontend/apps/impress/src/features/docs/docs-grid/components/SimpleDocItem.tsx +++ b/src/frontend/apps/impress/src/features/docs/docs-grid/components/SimpleDocItem.tsx @@ -41,6 +41,7 @@ export const SimpleDocItem = ({ $direction="row" $gap={spacingsTokens.sm} $overflow="auto" + $width="100%" className="--docs--simple-doc-item" > void, +) { + const [selectedDoc, setSelectedDoc] = useState(); + const [canDrop, setCanDrop] = useState(); + + const canDrag = selectedDoc?.user_roles.some((role) => role === Role.OWNER); + + const mouseSensor = useSensor(MouseSensor, { activationConstraint }); + const touchSensor = useSensor(TouchSensor, { activationConstraint }); + const keyboardSensor = useSensor(KeyboardSensor, {}); + const sensors = useSensors(mouseSensor, touchSensor, keyboardSensor); + + const handleDragStart = (e: DragStartEvent) => { + document.body.style.cursor = 'grabbing'; + if (e.active.data.current) { + setSelectedDoc(e.active.data.current as Doc); + } + }; + + const handleDragEnd = (e: DragEndEvent) => { + setSelectedDoc(undefined); + setCanDrop(undefined); + document.body.style.cursor = 'default'; + if (!canDrag || !canDrop) { + return; + } + + const { active, over } = e; + + if (!over?.id || active.id === over?.id) { + return; + } + + onDrag(active.id as string, over.id as string); + }; + + const updateCanDrop = (docCanDrop: boolean, isOver: boolean) => { + if (isOver) { + setCanDrop(docCanDrop); + } + }; + + return { + selectedDoc, + canDrag, + canDrop, + sensors, + handleDragStart, + handleDragEnd, + updateCanDrop, + }; +} diff --git a/src/frontend/apps/impress/src/features/service-worker/ApiPlugin.ts b/src/frontend/apps/impress/src/features/service-worker/ApiPlugin.ts index 63127f971..492bc3eee 100644 --- a/src/frontend/apps/impress/src/features/service-worker/ApiPlugin.ts +++ b/src/frontend/apps/impress/src/features/service-worker/ApiPlugin.ts @@ -175,6 +175,7 @@ export class ApiPlugin implements WorkboxPlugin { is_favorite: false, nb_accesses_direct: 1, nb_accesses_ancestors: 1, + numchild: 0, updated_at: new Date().toISOString(), abilities: { accesses_manage: true, @@ -201,6 +202,7 @@ export class ApiPlugin implements WorkboxPlugin { }, link_reach: LinkReach.RESTRICTED, link_role: LinkRole.READER, + user_roles: [], }; await DocsDB.cacheResponse( From b9da03b4fee758bab03ebbe01221a5187a3474a4 Mon Sep 17 00:00:00 2001 From: Nathan Panchout Date: Mon, 17 Mar 2025 15:13:02 +0100 Subject: [PATCH 13/26] =?UTF-8?q?=E2=9C=A8(frontend)=20added=20subpage=20m?= =?UTF-8?q?anagement=20and=20document=20tree=20features?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New components were created to manage subpages in the document tree, including the ability to add, reorder, and view subpages. Tests were added to verify the functionality of these features. Additionally, API changes were made to manage the creation and retrieval of document children. --- CHANGELOG.md | 1 + .../apps/e2e/__tests__/app-impress/common.ts | 9 +- .../__tests__/app-impress/doc-create.spec.ts | 4 +- .../__tests__/app-impress/doc-editor.spec.ts | 1 + .../__tests__/app-impress/doc-export.spec.ts | 2 +- .../__tests__/app-impress/doc-routing.spec.ts | 2 +- .../__tests__/app-impress/doc-search.spec.ts | 83 +++++- .../__tests__/app-impress/doc-tree.spec.ts | 279 ++++++++++++++++++ .../app-impress/doc-visibility.spec.ts | 4 +- .../impress/src/components/DropdownMenu.tsx | 9 +- .../src/components/filter/FilterDropdown.tsx | 63 ++++ .../quick-search/QuickSearchInput.tsx | 3 + .../docs/doc-header/components/DocTitle.tsx | 21 +- .../docs/doc-header/components/DocToolBox.tsx | 47 +-- .../docs/doc-management/api/useDoc.tsx | 3 +- .../docs/doc-management/api/useDocs.tsx | 1 - .../components/ModalRemoveDoc.tsx | 19 +- .../components/DocSearchContent.tsx | 68 +++++ .../components/DocSearchFilters.tsx | 67 +++++ .../doc-search/components/DocSearchModal.tsx | 98 +++--- .../components/DocSearchSubPageContent.tsx | 73 +++++ .../docs/doc-search/components/index.ts | 1 + .../components/DocShareAddMemberList.tsx | 40 ++- .../components/DocShareInvitationItem.tsx | 15 +- .../components/DocShareMemberItem.tsx | 15 +- .../src/features/docs/doc-tree/api/index.ts | 1 + .../docs/doc-tree/api/useCreateChildren.tsx | 44 +++ .../docs/doc-tree/api/useDocChildren.tsx | 58 ++++ .../features/docs/doc-tree/api/useDocTree.tsx | 44 +++ .../docs/doc-tree/assets/doc-extract-bold.svg | 10 + .../docs/doc-tree/assets/sub-page-logo.svg | 3 + .../doc-tree/components/DocSubPageItem.tsx | 169 +++++++++++ .../docs/doc-tree/components/DocTree.tsx | 233 +++++++++++++++ .../components/DocTreeItemActions.tsx | 171 +++++++++++ .../src/features/docs/doc-tree/hooks/index.ts | 1 + .../docs/doc-tree/hooks/useTreeUtils.tsx | 13 + .../src/features/docs/doc-tree/index.ts | 3 + .../src/features/docs/doc-tree/utils.ts | 29 ++ .../components/LeftPanelDocContent.tsx | 30 +- .../left-panel/components/LeftPanelHeader.tsx | 39 ++- .../components/LeftPanelHeaderButton.tsx | 73 +++++ .../impress/src/pages/docs/[id]/index.tsx | 26 +- src/frontend/apps/impress/src/tests/utils.tsx | 9 +- 43 files changed, 1734 insertions(+), 150 deletions(-) create mode 100644 src/frontend/apps/e2e/__tests__/app-impress/doc-tree.spec.ts create mode 100644 src/frontend/apps/impress/src/components/filter/FilterDropdown.tsx create mode 100644 src/frontend/apps/impress/src/features/docs/doc-search/components/DocSearchContent.tsx create mode 100644 src/frontend/apps/impress/src/features/docs/doc-search/components/DocSearchFilters.tsx create mode 100644 src/frontend/apps/impress/src/features/docs/doc-search/components/DocSearchSubPageContent.tsx create mode 100644 src/frontend/apps/impress/src/features/docs/doc-tree/api/index.ts create mode 100644 src/frontend/apps/impress/src/features/docs/doc-tree/api/useCreateChildren.tsx create mode 100644 src/frontend/apps/impress/src/features/docs/doc-tree/api/useDocChildren.tsx create mode 100644 src/frontend/apps/impress/src/features/docs/doc-tree/api/useDocTree.tsx create mode 100644 src/frontend/apps/impress/src/features/docs/doc-tree/assets/doc-extract-bold.svg create mode 100644 src/frontend/apps/impress/src/features/docs/doc-tree/assets/sub-page-logo.svg create mode 100644 src/frontend/apps/impress/src/features/docs/doc-tree/components/DocSubPageItem.tsx create mode 100644 src/frontend/apps/impress/src/features/docs/doc-tree/components/DocTree.tsx create mode 100644 src/frontend/apps/impress/src/features/docs/doc-tree/components/DocTreeItemActions.tsx create mode 100644 src/frontend/apps/impress/src/features/docs/doc-tree/hooks/index.ts create mode 100644 src/frontend/apps/impress/src/features/docs/doc-tree/hooks/useTreeUtils.tsx create mode 100644 src/frontend/apps/impress/src/features/docs/doc-tree/index.ts create mode 100644 src/frontend/apps/impress/src/features/docs/doc-tree/utils.ts create mode 100644 src/frontend/apps/impress/src/features/left-panel/components/LeftPanelHeaderButton.tsx diff --git a/CHANGELOG.md b/CHANGELOG.md index 7ac31a5ab..02ca0c834 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to - 🚸(backend) make document search on title accent-insensitive #874 - 🚩 add homepage feature flag #861 +- ✨(frontend) multi-pages #701 ## Changed diff --git a/src/frontend/apps/e2e/__tests__/app-impress/common.ts b/src/frontend/apps/e2e/__tests__/app-impress/common.ts index 32c377662..fa5785b6f 100644 --- a/src/frontend/apps/e2e/__tests__/app-impress/common.ts +++ b/src/frontend/apps/e2e/__tests__/app-impress/common.ts @@ -59,16 +59,19 @@ export const createDoc = async ( docName: string, browserName: string, length: number = 1, + isChild: boolean = false, ) => { const randomDocs = randomName(docName, browserName, length); for (let i = 0; i < randomDocs.length; i++) { - const header = page.locator('header').first(); - await header.locator('h2').getByText('Docs').click(); + if (!isChild) { + const header = page.locator('header').first(); + await header.locator('h2').getByText('Docs').click(); + } await page .getByRole('button', { - name: 'New doc', + name: isChild ? 'New page' : 'New doc', }) .click(); diff --git a/src/frontend/apps/e2e/__tests__/app-impress/doc-create.spec.ts b/src/frontend/apps/e2e/__tests__/app-impress/doc-create.spec.ts index 52aedce08..cf1b90370 100644 --- a/src/frontend/apps/e2e/__tests__/app-impress/doc-create.spec.ts +++ b/src/frontend/apps/e2e/__tests__/app-impress/doc-create.spec.ts @@ -14,10 +14,10 @@ test.beforeEach(async ({ page }) => { test.describe('Doc Create', () => { test('it creates a doc', async ({ page, browserName }) => { - const [docTitle] = await createDoc(page, 'My new doc', browserName, 1); + const [docTitle] = await createDoc(page, 'my-new-doc', browserName, 1); await page.waitForFunction( - () => document.title.match(/My new doc - Docs/), + () => document.title.match(/my-new-doc - Docs/), { timeout: 5000 }, ); diff --git a/src/frontend/apps/e2e/__tests__/app-impress/doc-editor.spec.ts b/src/frontend/apps/e2e/__tests__/app-impress/doc-editor.spec.ts index cc272a143..643ce9900 100644 --- a/src/frontend/apps/e2e/__tests__/app-impress/doc-editor.spec.ts +++ b/src/frontend/apps/e2e/__tests__/app-impress/doc-editor.spec.ts @@ -171,6 +171,7 @@ test.describe('Doc Editor', () => { await expect(editor.getByText('Hello World Doc 2')).toBeHidden(); await expect(editor.getByText('Hello World Doc 1')).toBeVisible(); + await page.goto('/'); await page .getByRole('button', { name: 'New doc', diff --git a/src/frontend/apps/e2e/__tests__/app-impress/doc-export.spec.ts b/src/frontend/apps/e2e/__tests__/app-impress/doc-export.spec.ts index 9d452b347..60160303f 100644 --- a/src/frontend/apps/e2e/__tests__/app-impress/doc-export.spec.ts +++ b/src/frontend/apps/e2e/__tests__/app-impress/doc-export.spec.ts @@ -298,7 +298,7 @@ test.describe('Doc Export', () => { }) .click(); - await page + void page .getByRole('button', { name: 'Download', }) diff --git a/src/frontend/apps/e2e/__tests__/app-impress/doc-routing.spec.ts b/src/frontend/apps/e2e/__tests__/app-impress/doc-routing.spec.ts index 95019784c..197c2bea8 100644 --- a/src/frontend/apps/e2e/__tests__/app-impress/doc-routing.spec.ts +++ b/src/frontend/apps/e2e/__tests__/app-impress/doc-routing.spec.ts @@ -58,7 +58,7 @@ test.describe('Doc Routing', () => { }); test('checks 401 on docs/[id] page', async ({ page, browserName }) => { - const [docTitle] = await createDoc(page, 'My new doc', browserName, 1); + const [docTitle] = await createDoc(page, '401-doc', browserName, 1); await verifyDocName(page, docTitle); const responsePromise = page.route( diff --git a/src/frontend/apps/e2e/__tests__/app-impress/doc-search.spec.ts b/src/frontend/apps/e2e/__tests__/app-impress/doc-search.spec.ts index 27088c931..73534b273 100644 --- a/src/frontend/apps/e2e/__tests__/app-impress/doc-search.spec.ts +++ b/src/frontend/apps/e2e/__tests__/app-impress/doc-search.spec.ts @@ -1,6 +1,6 @@ import { expect, test } from '@playwright/test'; -import { createDoc, verifyDocName } from './common'; +import { createDoc, randomName, verifyDocName } from './common'; test.beforeEach(async ({ page }) => { await page.goto('/'); @@ -94,4 +94,85 @@ test.describe('Document search', () => { page.getByLabel('Search modal').getByText('search'), ).toBeHidden(); }); + + test("it checks we don't see filters in search modal", async ({ page }) => { + const searchButton = page + .getByTestId('left-panel-desktop') + .getByRole('button', { name: 'search' }); + + await expect(searchButton).toBeVisible(); + await page.getByRole('button', { name: 'search', exact: true }).click(); + await expect( + page.getByRole('combobox', { name: 'Quick search input' }), + ).toBeVisible(); + await expect(page.getByTestId('doc-search-filters')).toBeHidden(); + }); +}); + +test.describe('Sub page search', () => { + test('it check the precense of filters in search modal', async ({ + page, + browserName, + }) => { + await page.goto('/'); + const [doc1Title] = await createDoc( + page, + 'My sub page search', + browserName, + 1, + ); + await verifyDocName(page, doc1Title); + const searchButton = page + .getByTestId('left-panel-desktop') + .getByRole('button', { name: 'search' }); + await searchButton.click(); + const filters = page.getByTestId('doc-search-filters'); + await expect(filters).toBeVisible(); + await filters.click(); + await filters.getByRole('button', { name: 'Current doc' }).click(); + await expect( + page.getByRole('menuitem', { name: 'All docs' }), + ).toBeVisible(); + await expect( + page.getByRole('menuitem', { name: 'Current doc' }), + ).toBeVisible(); + await page.getByRole('menuitem', { name: 'Current doc' }).click(); + + await expect(page.getByRole('button', { name: 'Reset' })).toBeVisible(); + }); + + test('it searches sub pages', async ({ page, browserName }) => { + await page.goto('/'); + + const [doc1Title] = await createDoc( + page, + 'My sub page search', + browserName, + 1, + ); + await verifyDocName(page, doc1Title); + await page.getByRole('button', { name: 'New page' }).click(); + await verifyDocName(page, ''); + await page.getByRole('textbox', { name: 'doc title input' }).click(); + await page + .getByRole('textbox', { name: 'doc title input' }) + .press('ControlOrMeta+a'); + const [randomDocName] = randomName('doc-sub-page', browserName, 1); + await page + .getByRole('textbox', { name: 'doc title input' }) + .fill(randomDocName); + const searchButton = page + .getByTestId('left-panel-desktop') + .getByRole('button', { name: 'search' }); + + await searchButton.click(); + await expect( + page.getByRole('button', { name: 'Current doc' }), + ).toBeVisible(); + await page.getByRole('combobox', { name: 'Quick search input' }).click(); + await page + .getByRole('combobox', { name: 'Quick search input' }) + .fill('sub'); + await expect(page.getByLabel(randomDocName)).toBeVisible(); + }); }); diff --git a/src/frontend/apps/e2e/__tests__/app-impress/doc-tree.spec.ts b/src/frontend/apps/e2e/__tests__/app-impress/doc-tree.spec.ts new file mode 100644 index 000000000..bf4b31349 --- /dev/null +++ b/src/frontend/apps/e2e/__tests__/app-impress/doc-tree.spec.ts @@ -0,0 +1,279 @@ +/* eslint-disable playwright/no-conditional-in-test */ +import { expect, test } from '@playwright/test'; + +import { + createDoc, + expectLoginPage, + keyCloakSignIn, + randomName, + verifyDocName, +} from './common'; + +test.describe('Doc Tree', () => { + test('create new sub pages', async ({ page, browserName }) => { + await page.goto('/'); + const [titleParent] = await createDoc( + page, + 'doc-tree-content', + browserName, + 1, + ); + await verifyDocName(page, titleParent); + const addButton = page.getByRole('button', { name: 'New page' }); + const docTree = page.getByTestId('doc-tree'); + + await expect(addButton).toBeVisible(); + + // Wait for and intercept the POST request to create a new page + const responsePromise = page.waitForResponse( + (response) => + response.url().includes('/documents/') && + response.url().includes('/children/') && + response.request().method() === 'POST', + ); + + await addButton.click(); + const response = await responsePromise; + expect(response.ok()).toBeTruthy(); + const subPageJson = await response.json(); + + await expect(docTree).toBeVisible(); + const subPageItem = docTree + .getByTestId(`doc-sub-page-item-${subPageJson.id}`) + .first(); + + await expect(subPageItem).toBeVisible(); + await subPageItem.click(); + await verifyDocName(page, ''); + const input = page.getByRole('textbox', { name: 'doc title input' }); + await input.click(); + const [randomDocName] = randomName('doc-tree-test', browserName, 1); + await input.fill(randomDocName); + await input.press('Enter'); + await expect(subPageItem.getByText(randomDocName)).toBeVisible(); + await page.reload(); + await expect(subPageItem.getByText(randomDocName)).toBeVisible(); + }); + + test('check the reorder of sub pages', async ({ page, browserName }) => { + await page.goto('/'); + await createDoc(page, 'doc-tree-content', browserName, 1); + const addButton = page.getByRole('button', { name: 'New page' }); + await expect(addButton).toBeVisible(); + + const docTree = page.getByTestId('doc-tree'); + + // Create first sub page + const firstResponsePromise = page.waitForResponse( + (response) => + response.url().includes('/documents/') && + response.url().includes('/children/') && + response.request().method() === 'POST', + ); + + await addButton.click(); + const firstResponse = await firstResponsePromise; + expect(firstResponse.ok()).toBeTruthy(); + + const secondResponsePromise = page.waitForResponse( + (response) => + response.url().includes('/documents/') && + response.url().includes('/children/') && + response.request().method() === 'POST', + ); + + // Create second sub page + await addButton.click(); + const secondResponse = await secondResponsePromise; + expect(secondResponse.ok()).toBeTruthy(); + + const secondSubPageJson = await secondResponse.json(); + const firstSubPageJson = await firstResponse.json(); + + const firstSubPageItem = docTree + .getByTestId(`doc-sub-page-item-${firstSubPageJson.id}`) + .first(); + + const secondSubPageItem = docTree + .getByTestId(`doc-sub-page-item-${secondSubPageJson.id}`) + .first(); + + // check that the sub pages are visible in the tree + await expect(firstSubPageItem).toBeVisible(); + await expect(secondSubPageItem).toBeVisible(); + + // get the bounding boxes of the sub pages + const firstSubPageBoundingBox = await firstSubPageItem.boundingBox(); + const secondSubPageBoundingBox = await secondSubPageItem.boundingBox(); + + expect(firstSubPageBoundingBox).toBeDefined(); + expect(secondSubPageBoundingBox).toBeDefined(); + + if (!firstSubPageBoundingBox || !secondSubPageBoundingBox) { + throw new Error('Impossible de déterminer la position des éléments'); + } + + // move the first sub page to the second position + await page.mouse.move( + firstSubPageBoundingBox.x + firstSubPageBoundingBox.width / 2, + firstSubPageBoundingBox.y + firstSubPageBoundingBox.height / 2, + ); + + await page.mouse.down(); + + await page.mouse.move( + secondSubPageBoundingBox.x + secondSubPageBoundingBox.width / 2, + secondSubPageBoundingBox.y + secondSubPageBoundingBox.height + 4, + { steps: 10 }, + ); + + await page.mouse.up(); + + // check that the sub pages are visible in the tree + await expect(firstSubPageItem).toBeVisible(); + await expect(secondSubPageItem).toBeVisible(); + + // reload the page + await page.reload(); + + // check that the sub pages are visible in the tree + await expect(firstSubPageItem).toBeVisible(); + await expect(secondSubPageItem).toBeVisible(); + + // Check the position of the sub pages + const allSubPageItems = await docTree + .getByTestId(/^doc-sub-page-item/) + .all(); + + expect(allSubPageItems.length).toBe(2); + + // Check that the first element has the ID of the second sub page after the drag and drop + await expect(allSubPageItems[0]).toHaveAttribute( + 'data-testid', + `doc-sub-page-item-${secondSubPageJson.id}`, + ); + + // Check that the second element has the ID of the first sub page after the drag and drop + await expect(allSubPageItems[1]).toHaveAttribute( + 'data-testid', + `doc-sub-page-item-${firstSubPageJson.id}`, + ); + }); +}); + +test.describe('Doc Tree: Inheritance', () => { + test.use({ storageState: { cookies: [], origins: [] } }); + + test('A child inherit from the parent', async ({ page, browserName }) => { + await page.goto('/'); + await keyCloakSignIn(page, browserName); + + const [docParent] = await createDoc( + page, + 'doc-tree-inheritance-parent', + browserName, + 1, + ); + await verifyDocName(page, docParent); + + await page.getByRole('button', { name: 'Share' }).click(); + const selectVisibility = page.getByLabel('Visibility', { exact: true }); + await selectVisibility.click(); + + await page + .getByRole('menuitem', { + name: 'Public', + }) + .click(); + + await expect( + page.getByText('The document visibility has been updated.'), + ).toBeVisible(); + + await page.getByRole('button', { name: 'close' }).click(); + + const [docChild] = await createDoc( + page, + 'doc-tree-inheritance-child', + browserName, + 1, + true, + ); + await verifyDocName(page, docChild); + + const urlDoc = page.url(); + + await page + .getByRole('button', { + name: 'Logout', + }) + .click(); + + await expectLoginPage(page); + + await page.goto(urlDoc); + + await expect(page.locator('h2').getByText(docChild)).toBeVisible(); + + const docTree = page.getByTestId('doc-tree'); + await expect(docTree.getByText(docParent)).toBeVisible(); + }); + + test('Do not show private parent from children', async ({ + page, + browserName, + }) => { + await page.goto('/'); + await keyCloakSignIn(page, browserName); + + const [docParent] = await createDoc( + page, + 'doc-tree-inheritance-private-parent', + browserName, + 1, + ); + await verifyDocName(page, docParent); + + const [docChild] = await createDoc( + page, + 'doc-tree-inheritance-private-child', + browserName, + 1, + true, + ); + await verifyDocName(page, docChild); + + await page.getByRole('button', { name: 'Share' }).click(); + const selectVisibility = page.getByLabel('Visibility', { exact: true }); + await selectVisibility.click(); + + await page + .getByRole('menuitem', { + name: 'Public', + }) + .click(); + + await expect( + page.getByText('The document visibility has been updated.'), + ).toBeVisible(); + + await page.getByRole('button', { name: 'close' }).click(); + + const urlDoc = page.url(); + + await page + .getByRole('button', { + name: 'Logout', + }) + .click(); + + await expectLoginPage(page); + + await page.goto(urlDoc); + + await expect(page.locator('h2').getByText(docChild)).toBeVisible(); + + const docTree = page.getByTestId('doc-tree'); + await expect(docTree.getByText(docParent)).toBeHidden(); + }); +}); diff --git a/src/frontend/apps/e2e/__tests__/app-impress/doc-visibility.spec.ts b/src/frontend/apps/e2e/__tests__/app-impress/doc-visibility.spec.ts index a28200b08..d27138cad 100644 --- a/src/frontend/apps/e2e/__tests__/app-impress/doc-visibility.spec.ts +++ b/src/frontend/apps/e2e/__tests__/app-impress/doc-visibility.spec.ts @@ -241,7 +241,7 @@ test.describe('Doc Visibility: Public', () => { ).toBeVisible(); await expect(page.getByRole('button', { name: 'search' })).toBeVisible(); - await expect(page.getByRole('button', { name: 'New doc' })).toBeVisible(); + await expect(page.getByRole('button', { name: 'New page' })).toBeVisible(); const urlDoc = page.url(); @@ -257,7 +257,7 @@ test.describe('Doc Visibility: Public', () => { await expect(page.locator('h2').getByText(docTitle)).toBeVisible(); await expect(page.getByRole('button', { name: 'search' })).toBeHidden(); - await expect(page.getByRole('button', { name: 'New doc' })).toBeHidden(); + await expect(page.getByRole('button', { name: 'New page' })).toBeHidden(); await expect(page.getByRole('button', { name: 'Share' })).toBeVisible(); const card = page.getByLabel('It is the card information'); await expect(card).toBeVisible(); diff --git a/src/frontend/apps/impress/src/components/DropdownMenu.tsx b/src/frontend/apps/impress/src/components/DropdownMenu.tsx index 8758588ed..5fc3d64be 100644 --- a/src/frontend/apps/impress/src/components/DropdownMenu.tsx +++ b/src/frontend/apps/impress/src/components/DropdownMenu.tsx @@ -8,6 +8,7 @@ export type DropdownMenuOption = { icon?: string; label: string; testId?: string; + value?: string; callback?: () => void | Promise; danger?: boolean; isSelected?: boolean; @@ -23,6 +24,8 @@ export type DropdownMenuProps = { buttonCss?: BoxProps['$css']; disabled?: boolean; topMessage?: string; + selectedValues?: string[]; + afterOpenChange?: (isOpen: boolean) => void; }; export const DropdownMenu = ({ @@ -34,6 +37,8 @@ export const DropdownMenu = ({ buttonCss, label, topMessage, + afterOpenChange, + selectedValues, }: PropsWithChildren) => { const { spacingsTokens, colorsTokens } = useCunninghamTheme(); const [isOpen, setIsOpen] = useState(false); @@ -41,6 +46,7 @@ export const DropdownMenu = ({ const onOpenChange = (isOpen: boolean) => { setIsOpen(isOpen); + afterOpenChange?.(isOpen); }; if (disabled) { @@ -163,7 +169,8 @@ export const DropdownMenu = ({ {option.label}
- {option.isSelected && ( + {(option.isSelected || + selectedValues?.includes(option.value ?? '')) && ( )} diff --git a/src/frontend/apps/impress/src/components/filter/FilterDropdown.tsx b/src/frontend/apps/impress/src/components/filter/FilterDropdown.tsx new file mode 100644 index 000000000..313209bf4 --- /dev/null +++ b/src/frontend/apps/impress/src/components/filter/FilterDropdown.tsx @@ -0,0 +1,63 @@ +import { css } from 'styled-components'; + +import { Box } from '../Box'; +import { DropdownMenu, DropdownMenuOption } from '../DropdownMenu'; +import { Icon } from '../Icon'; +import { Text } from '../Text'; + +export type FilterDropdownProps = { + options: DropdownMenuOption[]; + selectedValue?: string; +}; + +export const FilterDropdown = ({ + options, + selectedValue, +}: FilterDropdownProps) => { + const selectedOption = options.find( + (option) => option.value === selectedValue, + ); + + if (options.length === 0) { + return null; + } + + return ( + + + + {selectedOption?.label ?? options[0].label} + + + + + ); +}; diff --git a/src/frontend/apps/impress/src/components/quick-search/QuickSearchInput.tsx b/src/frontend/apps/impress/src/components/quick-search/QuickSearchInput.tsx index 9ab52f53b..e78f6a564 100644 --- a/src/frontend/apps/impress/src/components/quick-search/QuickSearchInput.tsx +++ b/src/frontend/apps/impress/src/components/quick-search/QuickSearchInput.tsx @@ -56,6 +56,9 @@ export const QuickSearchInput = ({ /* eslint-disable-next-line jsx-a11y/no-autofocus */ autoFocus={true} aria-label={t('Quick search input')} + onClick={(e) => { + e.stopPropagation(); + }} value={inputValue} role="combobox" placeholder={placeholder ?? t('Search')} diff --git a/src/frontend/apps/impress/src/features/docs/doc-header/components/DocTitle.tsx b/src/frontend/apps/impress/src/features/docs/doc-header/components/DocTitle.tsx index b838ef440..5175cfe7e 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-header/components/DocTitle.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-header/components/DocTitle.tsx @@ -1,10 +1,7 @@ /* eslint-disable jsx-a11y/click-events-have-key-events */ /* eslint-disable jsx-a11y/no-noninteractive-element-interactions */ -import { - Tooltip, - VariantType, - useToastProvider, -} from '@openfun/cunningham-react'; +import { Tooltip } from '@openfun/cunningham-react'; +import { useQueryClient } from '@tanstack/react-query'; import React, { useCallback, useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { css } from 'styled-components'; @@ -15,6 +12,7 @@ import { Doc, KEY_DOC, KEY_LIST_DOC, + KEY_SUB_PAGE, useTrans, useUpdateDoc, } from '@/docs/doc-management'; @@ -54,21 +52,24 @@ export const DocTitleText = ({ title }: DocTitleTextProps) => { const DocTitleInput = ({ doc }: DocTitleProps) => { const { isDesktop } = useResponsiveStore(); + const queryClient = useQueryClient(); const { t } = useTranslation(); const { colorsTokens } = useCunninghamTheme(); const [titleDisplay, setTitleDisplay] = useState(doc.title); - const { toast } = useToastProvider(); + const { untitledDocument } = useTrans(); const { broadcast } = useBroadcastStore(); const { mutate: updateDoc } = useUpdateDoc({ listInvalideQueries: [KEY_DOC, KEY_LIST_DOC], - onSuccess(data) { - toast(t('Document title updated successfully'), VariantType.SUCCESS); - + onSuccess(updatedDoc) { // Broadcast to every user connected to the document - broadcast(`${KEY_DOC}-${data.id}`); + broadcast(`${KEY_DOC}-${updatedDoc.id}`); + queryClient.setQueryData( + [KEY_SUB_PAGE, { id: updatedDoc.id }], + updatedDoc, + ); }, }); diff --git a/src/frontend/apps/impress/src/features/docs/doc-header/components/DocToolBox.tsx b/src/frontend/apps/impress/src/features/docs/doc-header/components/DocToolBox.tsx index 77a1fe50e..a079c280c 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-header/components/DocToolBox.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-header/components/DocToolBox.tsx @@ -29,6 +29,7 @@ import { useDeleteFavoriteDoc, } from '@/docs/doc-management'; import { DocShareModal } from '@/docs/doc-share'; +import { useTreeUtils } from '@/docs/doc-tree/'; import { KEY_LIST_DOC_VERSIONS, ModalSelectVersion, @@ -44,6 +45,7 @@ export const DocToolBox = ({ doc }: DocToolBoxProps) => { const { t } = useTranslation(); const hasAccesses = doc.nb_accesses_direct > 1 && doc.abilities.accesses_view; const queryClient = useQueryClient(); + const { isCurrentParent } = useTreeUtils(doc); const { spacingsTokens, colorsTokens } = useCunninghamTheme(); @@ -65,27 +67,26 @@ export const DocToolBox = ({ doc }: DocToolBoxProps) => { }); const options: DropdownMenuOption[] = [ - ...(isSmallMobile - ? [ - { - label: t('Share'), - icon: 'group', - callback: modalShare.open, - }, - { - label: t('Export'), - icon: 'download', - callback: () => { - setIsModalExportOpen(true); - }, - }, - { - label: t('Copy link'), - icon: 'add_link', - callback: copyDocLink, - }, - ] - : []), + { + label: t('Share'), + icon: 'group', + callback: modalShare.open, + show: isSmallMobile, + }, + { + label: t('Export'), + icon: 'download', + callback: () => { + setIsModalExportOpen(true); + }, + show: isSmallMobile, + }, + { + label: t('Copy link'), + icon: 'add_link', + callback: copyDocLink, + show: isSmallMobile, + }, { label: doc.is_favorite ? t('Unpin') : t('Pin'), icon: 'push_pin', @@ -97,6 +98,7 @@ export const DocToolBox = ({ doc }: DocToolBoxProps) => { } }, testId: `docs-actions-${doc.is_favorite ? 'unpin' : 'pin'}-${doc.id}`, + show: isCurrentParent, }, { label: t('Version history'), @@ -190,6 +192,9 @@ export const DocToolBox = ({ doc }: DocToolBoxProps) => { modalShare.open(); }} size={isSmallMobile ? 'small' : 'medium'} + style={{ + color: colors['primary-800'], + }} > {t('Share')} diff --git a/src/frontend/apps/impress/src/features/docs/doc-management/api/useDoc.tsx b/src/frontend/apps/impress/src/features/docs/doc-management/api/useDoc.tsx index ebbb1d543..5365ad4d9 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-management/api/useDoc.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-management/api/useDoc.tsx @@ -19,6 +19,7 @@ export const getDoc = async ({ id }: DocParams): Promise => { }; export const KEY_DOC = 'doc'; +export const KEY_SUB_PAGE = 'sub-page'; export const KEY_DOC_VISIBILITY = 'doc-visibility'; export function useDoc( @@ -26,7 +27,7 @@ export function useDoc( queryConfig?: UseQueryOptions, ) { return useQuery({ - queryKey: [KEY_DOC, param], + queryKey: queryConfig?.queryKey ?? [KEY_DOC, param], queryFn: () => getDoc(param), ...queryConfig, }); diff --git a/src/frontend/apps/impress/src/features/docs/doc-management/api/useDocs.tsx b/src/frontend/apps/impress/src/features/docs/doc-management/api/useDocs.tsx index c9881ad70..5f5636d57 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-management/api/useDocs.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-management/api/useDocs.tsx @@ -53,7 +53,6 @@ export const getDocs = async (params: DocsParams): Promise => { if (params.is_favorite !== undefined) { searchParams.set('is_favorite', params.is_favorite.toString()); } - const response = await fetchAPI(`documents/?${searchParams.toString()}`); if (!response.ok) { diff --git a/src/frontend/apps/impress/src/features/docs/doc-management/components/ModalRemoveDoc.tsx b/src/frontend/apps/impress/src/features/docs/doc-management/components/ModalRemoveDoc.tsx index c3ff4b5b7..f83b1aff8 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-management/components/ModalRemoveDoc.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-management/components/ModalRemoveDoc.tsx @@ -12,21 +12,27 @@ import { useRouter } from 'next/router'; import { Box, Text, TextErrors } from '@/components'; import { useRemoveDoc } from '../api/useRemoveDoc'; +import { useTrans } from '../hooks'; import { Doc } from '../types'; interface ModalRemoveDocProps { onClose: () => void; doc: Doc; + afterDelete?: (doc: Doc) => void; } -export const ModalRemoveDoc = ({ onClose, doc }: ModalRemoveDocProps) => { +export const ModalRemoveDoc = ({ + onClose, + doc, + afterDelete, +}: ModalRemoveDocProps) => { const { toast } = useToastProvider(); const { push } = useRouter(); const pathname = usePathname(); + const { untitledDocument } = useTrans(); const { mutate: removeDoc, - isError, error, } = useRemoveDoc({ @@ -34,6 +40,11 @@ export const ModalRemoveDoc = ({ onClose, doc }: ModalRemoveDocProps) => { toast(t('The document has been deleted.'), VariantType.SUCCESS, { duration: 4000, }); + if (afterDelete) { + afterDelete(doc); + return; + } + if (pathname === '/') { onClose(); } else { @@ -90,7 +101,9 @@ export const ModalRemoveDoc = ({ onClose, doc }: ModalRemoveDocProps) => { > {!isError && ( - {t('Are you sure you want to delete this document ?')} + {t('Are you sure you want to delete the document "{{title}}"?', { + title: doc.title ?? untitledDocument, + })} )} diff --git a/src/frontend/apps/impress/src/features/docs/doc-search/components/DocSearchContent.tsx b/src/frontend/apps/impress/src/features/docs/doc-search/components/DocSearchContent.tsx new file mode 100644 index 000000000..fc14d8bc6 --- /dev/null +++ b/src/frontend/apps/impress/src/features/docs/doc-search/components/DocSearchContent.tsx @@ -0,0 +1,68 @@ +import { t } from 'i18next'; +import { useEffect, useMemo } from 'react'; +import { InView } from 'react-intersection-observer'; + +import { QuickSearchData, QuickSearchGroup } from '@/components/quick-search'; + +import { Doc, useInfiniteDocs } from '../../doc-management'; + +import { DocSearchFiltersValues } from './DocSearchFilters'; +import { DocSearchItem } from './DocSearchItem'; + +type DocSearchContentProps = { + search: string; + filters: DocSearchFiltersValues; + onSelect: (doc: Doc) => void; + onLoadingChange?: (loading: boolean) => void; +}; + +export const DocSearchContent = ({ + search, + filters, + onSelect, + onLoadingChange, +}: DocSearchContentProps) => { + const { + data, + isFetching, + isRefetching, + isLoading, + fetchNextPage, + hasNextPage, + } = useInfiniteDocs({ + page: 1, + title: search, + ...filters, + }); + + const loading = isFetching || isRefetching || isLoading; + + const docsData: QuickSearchData = useMemo(() => { + const docs = data?.pages.flatMap((page) => page.results) || []; + + return { + groupName: docs.length > 0 ? t('Select a document') : '', + elements: search ? docs : [], + emptyString: t('No document found'), + endActions: hasNextPage + ? [ + { + content: void fetchNextPage()} />, + }, + ] + : [], + }; + }, [search, data?.pages, fetchNextPage, hasNextPage]); + + useEffect(() => { + onLoadingChange?.(loading); + }, [loading, onLoadingChange]); + + return ( + } + /> + ); +}; diff --git a/src/frontend/apps/impress/src/features/docs/doc-search/components/DocSearchFilters.tsx b/src/frontend/apps/impress/src/features/docs/doc-search/components/DocSearchFilters.tsx new file mode 100644 index 000000000..96edcf71d --- /dev/null +++ b/src/frontend/apps/impress/src/features/docs/doc-search/components/DocSearchFilters.tsx @@ -0,0 +1,67 @@ +import { Button } from '@openfun/cunningham-react'; +import { useTranslation } from 'react-i18next'; + +import { Box } from '@/components'; +import { FilterDropdown } from '@/components/filter/FilterDropdown'; + +export enum DocSearchTarget { + ALL = 'all', + CURRENT = 'current', +} + +export type DocSearchFiltersValues = { + target?: DocSearchTarget; +}; + +export type DocSearchFiltersProps = { + values?: DocSearchFiltersValues; + onValuesChange?: (values: DocSearchFiltersValues) => void; + onReset?: () => void; +}; + +export const DocSearchFilters = ({ + values, + onValuesChange, + onReset, +}: DocSearchFiltersProps) => { + const { t } = useTranslation(); + const hasFilters = Object.keys(values ?? {}).length > 0; + const handleTargetChange = (target: DocSearchTarget) => { + onValuesChange?.({ ...values, target }); + }; + + return ( + + + handleTargetChange(DocSearchTarget.ALL), + }, + { + label: t('Current doc'), + value: DocSearchTarget.CURRENT, + callback: () => handleTargetChange(DocSearchTarget.CURRENT), + }, + ]} + /> + + {hasFilters && ( + + )} + + ); +}; diff --git a/src/frontend/apps/impress/src/features/docs/doc-search/components/DocSearchModal.tsx b/src/frontend/apps/impress/src/features/docs/doc-search/components/DocSearchModal.tsx index 48fbbf48c..caede5f1a 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-search/components/DocSearchModal.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-search/components/DocSearchModal.tsx @@ -1,65 +1,61 @@ import { Modal, ModalSize } from '@openfun/cunningham-react'; import Image from 'next/image'; -import { useRouter } from 'next/navigation'; -import { useMemo, useState } from 'react'; +import { useRouter } from 'next/router'; +import { useState } from 'react'; import { useTranslation } from 'react-i18next'; -import { InView } from 'react-intersection-observer'; import { useDebouncedCallback } from 'use-debounce'; import { Box } from '@/components'; -import { - QuickSearch, - QuickSearchData, - QuickSearchGroup, -} from '@/components/quick-search'; -import { Doc, useInfiniteDocs } from '@/docs/doc-management'; +import { QuickSearch } from '@/components/quick-search'; import { useResponsiveStore } from '@/stores'; +import { Doc } from '../../doc-management'; import EmptySearchIcon from '../assets/illustration-docs-empty.png'; -import { DocSearchItem } from './DocSearchItem'; +import { DocSearchContent } from './DocSearchContent'; +import { + DocSearchFilters, + DocSearchFiltersValues, + DocSearchTarget, +} from './DocSearchFilters'; +import { DocSearchSubPageContent } from './DocSearchSubPageContent'; type DocSearchModalProps = { onClose: () => void; isOpen: boolean; + showFilters?: boolean; + defaultFilters?: DocSearchFiltersValues; }; -export const DocSearchModal = ({ ...modalProps }: DocSearchModalProps) => { +export const DocSearchModal = ({ + showFilters = false, + defaultFilters, + ...modalProps +}: DocSearchModalProps) => { const { t } = useTranslation(); + const [loading, setLoading] = useState(false); + const router = useRouter(); + const isDocPage = router.pathname === '/docs/[id]'; + const [search, setSearch] = useState(''); + const [filters, setFilters] = useState( + defaultFilters ?? {}, + ); + + const target = filters.target ?? DocSearchTarget.ALL; const { isDesktop } = useResponsiveStore(); - const { - data, - isFetching, - isRefetching, - isLoading, - fetchNextPage, - hasNextPage, - } = useInfiniteDocs({ - page: 1, - title: search, - }); - const loading = isFetching || isRefetching || isLoading; + const handleInputSearch = useDebouncedCallback(setSearch, 300); const handleSelect = (doc: Doc) => { - router.push(`/docs/${doc.id}`); + void router.push(`/docs/${doc.id}`); modalProps.onClose?.(); }; - const docsData: QuickSearchData = useMemo(() => { - const docs = data?.pages.flatMap((page) => page.results) || []; - - return { - groupName: docs.length > 0 ? t('Select a document') : '', - elements: search ? docs : [], - emptyString: t('No document found'), - endActions: hasNextPage - ? [{ content: void fetchNextPage()} /> }] - : [], - }; - }, [data, hasNextPage, fetchNextPage, t, search]); + const handleResetFilters = () => { + setFilters({}); + }; return ( { onFilter={handleInputSearch} > + {showFilters && ( + + )} {search.length === 0 && ( { )} {search && ( - } - /> + <> + {target === DocSearchTarget.ALL && ( + + )} + {isDocPage && target === DocSearchTarget.CURRENT && ( + + )} + )} diff --git a/src/frontend/apps/impress/src/features/docs/doc-search/components/DocSearchSubPageContent.tsx b/src/frontend/apps/impress/src/features/docs/doc-search/components/DocSearchSubPageContent.tsx new file mode 100644 index 000000000..e4fa2c7e7 --- /dev/null +++ b/src/frontend/apps/impress/src/features/docs/doc-search/components/DocSearchSubPageContent.tsx @@ -0,0 +1,73 @@ +import { useTreeContext } from '@gouvfr-lasuite/ui-kit'; +import { t } from 'i18next'; +import { useEffect, useMemo } from 'react'; +import { InView } from 'react-intersection-observer'; + +import { QuickSearchData, QuickSearchGroup } from '@/components/quick-search'; + +import { Doc } from '../../doc-management'; +import { useInfiniteSubDocs } from '../../doc-management/api/useSubDocs'; + +import { DocSearchFiltersValues } from './DocSearchFilters'; +import { DocSearchItem } from './DocSearchItem'; + +type DocSearchSubPageContentProps = { + search: string; + filters: DocSearchFiltersValues; + onSelect: (doc: Doc) => void; + onLoadingChange?: (loading: boolean) => void; +}; + +export const DocSearchSubPageContent = ({ + search, + filters, + onSelect, + onLoadingChange, +}: DocSearchSubPageContentProps) => { + const treeContext = useTreeContext(); + + const { + data: subDocsData, + isFetching, + isRefetching, + isLoading, + fetchNextPage: subDocsFetchNextPage, + hasNextPage: subDocsHasNextPage, + } = useInfiniteSubDocs({ + page: 1, + title: search, + ...filters, + parent_id: treeContext?.root?.id ?? '', + }); + + const loading = isFetching || isRefetching || isLoading; + + const docsData: QuickSearchData = useMemo(() => { + const subDocs = subDocsData?.pages.flatMap((page) => page.results) || []; + + return { + groupName: subDocs.length > 0 ? t('Select a page') : '', + elements: search ? subDocs : [], + emptyString: t('No document found'), + endActions: subDocsHasNextPage + ? [ + { + content: void subDocsFetchNextPage()} />, + }, + ] + : [], + }; + }, [search, subDocsData, subDocsFetchNextPage, subDocsHasNextPage]); + + useEffect(() => { + onLoadingChange?.(loading); + }, [loading, onLoadingChange]); + + return ( + } + /> + ); +}; diff --git a/src/frontend/apps/impress/src/features/docs/doc-search/components/index.ts b/src/frontend/apps/impress/src/features/docs/doc-search/components/index.ts index a5cb98858..1a0889239 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-search/components/index.ts +++ b/src/frontend/apps/impress/src/features/docs/doc-search/components/index.ts @@ -1 +1,2 @@ export * from './DocSearchModal'; +export * from './DocSearchFilters'; diff --git a/src/frontend/apps/impress/src/features/docs/doc-share/components/DocShareAddMemberList.tsx b/src/frontend/apps/impress/src/features/docs/doc-share/components/DocShareAddMemberList.tsx index fdded178d..67c907f0a 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-share/components/DocShareAddMemberList.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-share/components/DocShareAddMemberList.tsx @@ -3,6 +3,7 @@ import { VariantType, useToastProvider, } from '@openfun/cunningham-react'; +import { useQueryClient } from '@tanstack/react-query'; import { useState } from 'react'; import { useTranslation } from 'react-i18next'; import { css } from 'styled-components'; @@ -11,7 +12,7 @@ import { APIError } from '@/api'; import { Box } from '@/components'; import { useCunninghamTheme } from '@/cunningham'; import { User } from '@/features/auth'; -import { Doc, Role } from '@/features/docs'; +import { Doc, KEY_SUB_PAGE, Role } from '@/features/docs'; import { useCreateDocAccess, useCreateDocInvitation } from '../api'; import { OptionType } from '../types'; @@ -39,11 +40,12 @@ export const DocShareAddMemberList = ({ }: Props) => { const { t } = useTranslation(); const { toast } = useToastProvider(); + const [isLoading, setIsLoading] = useState(false); const { spacingsTokens, colorsTokens } = useCunninghamTheme(); const [invitationRole, setInvitationRole] = useState(Role.EDITOR); const canShare = doc.abilities.accesses_manage; - + const queryClient = useQueryClient(); const { mutateAsync: createInvitation } = useCreateDocInvitation(); const { mutateAsync: createDocAccess } = useCreateDocAccess(); @@ -89,14 +91,32 @@ export const DocShareAddMemberList = ({ }; return isInvitationMode - ? createInvitation({ - ...payload, - email: user.email, - }) - : createDocAccess({ - ...payload, - memberId: user.id, - }); + ? createInvitation( + { + ...payload, + email: user.email, + }, + { + onSuccess: () => { + void queryClient.invalidateQueries({ + queryKey: [KEY_SUB_PAGE, { id: doc.id }], + }); + }, + }, + ) + : createDocAccess( + { + ...payload, + memberId: user.id, + }, + { + onSuccess: () => { + void queryClient.invalidateQueries({ + queryKey: [KEY_SUB_PAGE, { id: doc.id }], + }); + }, + }, + ); }); const settledPromises = await Promise.allSettled(promises); diff --git a/src/frontend/apps/impress/src/features/docs/doc-share/components/DocShareInvitationItem.tsx b/src/frontend/apps/impress/src/features/docs/doc-share/components/DocShareInvitationItem.tsx index 76a04fbd0..de91ccf24 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-share/components/DocShareInvitationItem.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-share/components/DocShareInvitationItem.tsx @@ -1,4 +1,5 @@ import { VariantType, useToastProvider } from '@openfun/cunningham-react'; +import { useQueryClient } from '@tanstack/react-query'; import { useTranslation } from 'react-i18next'; import { @@ -8,7 +9,7 @@ import { IconOptions, } from '@/components'; import { useCunninghamTheme } from '@/cunningham'; -import { Doc, Role } from '@/docs/doc-management'; +import { Doc, KEY_SUB_PAGE, Role } from '@/docs/doc-management'; import { User } from '@/features/auth'; import { useDeleteDocInvitation, useUpdateDocInvitation } from '../api'; @@ -23,7 +24,9 @@ type Props = { }; export const DocShareInvitationItem = ({ doc, invitation }: Props) => { const { t } = useTranslation(); + const queryClient = useQueryClient(); const { spacingsTokens } = useCunninghamTheme(); + const fakeUser: User = { id: invitation.email, full_name: invitation.email, @@ -36,6 +39,11 @@ export const DocShareInvitationItem = ({ doc, invitation }: Props) => { const canUpdate = doc.abilities.accesses_manage; const { mutate: updateDocInvitation } = useUpdateDocInvitation({ + onSuccess: () => { + void queryClient.invalidateQueries({ + queryKey: [KEY_SUB_PAGE, { id: doc.id }], + }); + }, onError: (error) => { toast( error?.data?.role?.[0] ?? t('Error during update invitation'), @@ -48,6 +56,11 @@ export const DocShareInvitationItem = ({ doc, invitation }: Props) => { }); const { mutate: removeDocInvitation } = useDeleteDocInvitation({ + onSuccess: () => { + void queryClient.invalidateQueries({ + queryKey: [KEY_SUB_PAGE, { id: doc.id }], + }); + }, onError: (error) => { toast( error?.data?.role?.[0] ?? t('Error during delete invitation'), diff --git a/src/frontend/apps/impress/src/features/docs/doc-share/components/DocShareMemberItem.tsx b/src/frontend/apps/impress/src/features/docs/doc-share/components/DocShareMemberItem.tsx index f07d08dc1..7829752c8 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-share/components/DocShareMemberItem.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-share/components/DocShareMemberItem.tsx @@ -1,4 +1,5 @@ import { VariantType, useToastProvider } from '@openfun/cunningham-react'; +import { useQueryClient } from '@tanstack/react-query'; import { useTranslation } from 'react-i18next'; import { @@ -8,7 +9,7 @@ import { IconOptions, } from '@/components'; import { useCunninghamTheme } from '@/cunningham'; -import { Access, Doc, Role } from '@/docs/doc-management/'; +import { Access, Doc, KEY_SUB_PAGE, Role } from '@/docs/doc-management/'; import { useResponsiveStore } from '@/stores'; import { useDeleteDocAccess, useUpdateDocAccess } from '../api'; @@ -23,14 +24,21 @@ type Props = { }; export const DocShareMemberItem = ({ doc, access }: Props) => { const { t } = useTranslation(); + const queryClient = useQueryClient(); const { isLastOwner, isOtherOwner } = useWhoAmI(access); const { toast } = useToastProvider(); + const { isDesktop } = useResponsiveStore(); const { spacingsTokens } = useCunninghamTheme(); const isNotAllowed = isOtherOwner || !!isLastOwner || !doc.abilities.accesses_manage; const { mutate: updateDocAccess } = useUpdateDocAccess({ + onSuccess: () => { + void queryClient.invalidateQueries({ + queryKey: [KEY_SUB_PAGE, { id: doc.id }], + }); + }, onError: () => { toast(t('Error during invitation update'), VariantType.ERROR, { duration: 4000, @@ -39,6 +47,11 @@ export const DocShareMemberItem = ({ doc, access }: Props) => { }); const { mutate: removeDocAccess } = useDeleteDocAccess({ + onSuccess: () => { + void queryClient.invalidateQueries({ + queryKey: [KEY_SUB_PAGE, { id: doc.id }], + }); + }, onError: () => { toast(t('Error while deleting invitation'), VariantType.ERROR, { duration: 4000, diff --git a/src/frontend/apps/impress/src/features/docs/doc-tree/api/index.ts b/src/frontend/apps/impress/src/features/docs/doc-tree/api/index.ts new file mode 100644 index 000000000..98d4836ff --- /dev/null +++ b/src/frontend/apps/impress/src/features/docs/doc-tree/api/index.ts @@ -0,0 +1 @@ +export * from './useDocChildren'; diff --git a/src/frontend/apps/impress/src/features/docs/doc-tree/api/useCreateChildren.tsx b/src/frontend/apps/impress/src/features/docs/doc-tree/api/useCreateChildren.tsx new file mode 100644 index 000000000..b9f774a81 --- /dev/null +++ b/src/frontend/apps/impress/src/features/docs/doc-tree/api/useCreateChildren.tsx @@ -0,0 +1,44 @@ +import { useMutation, useQueryClient } from '@tanstack/react-query'; + +import { APIError, errorCauses, fetchAPI } from '@/api'; + +import { Doc, KEY_LIST_DOC } from '../../doc-management'; + +export type CreateDocParam = Pick & { + parentId: string; +}; + +export const createDocChildren = async ({ + title, + parentId, +}: CreateDocParam): Promise => { + const response = await fetchAPI(`documents/${parentId}/children/`, { + method: 'POST', + body: JSON.stringify({ + title, + }), + }); + + if (!response.ok) { + throw new APIError('Failed to create the doc', await errorCauses(response)); + } + + return response.json() as Promise; +}; + +interface CreateDocProps { + onSuccess: (data: Doc) => void; +} + +export function useCreateChildrenDoc({ onSuccess }: CreateDocProps) { + const queryClient = useQueryClient(); + return useMutation({ + mutationFn: createDocChildren, + onSuccess: (data) => { + void queryClient.resetQueries({ + queryKey: [KEY_LIST_DOC], + }); + onSuccess(data); + }, + }); +} diff --git a/src/frontend/apps/impress/src/features/docs/doc-tree/api/useDocChildren.tsx b/src/frontend/apps/impress/src/features/docs/doc-tree/api/useDocChildren.tsx new file mode 100644 index 000000000..406c32a77 --- /dev/null +++ b/src/frontend/apps/impress/src/features/docs/doc-tree/api/useDocChildren.tsx @@ -0,0 +1,58 @@ +import { UseQueryOptions, useQuery } from '@tanstack/react-query'; + +import { APIError, errorCauses, fetchAPI, useAPIInfiniteQuery } from '@/api'; + +import { DocsResponse } from '../../doc-management'; + +export type DocsChildrenParams = { + docId: string; + page?: number; + page_size?: number; +}; + +export const getDocChildren = async ( + params: DocsChildrenParams, +): Promise => { + const { docId, page, page_size } = params; + const searchParams = new URLSearchParams(); + + if (page) { + searchParams.set('page', page.toString()); + } + if (page_size) { + searchParams.set('page_size', page_size.toString()); + } + + const response = await fetchAPI( + `documents/${docId}/children/?${searchParams.toString()}`, + ); + + if (!response.ok) { + throw new APIError( + 'Failed to get the doc children', + await errorCauses(response), + ); + } + + return response.json() as Promise; +}; + +export const KEY_LIST_DOC_CHILDREN = 'doc-children'; + +export function useDocChildren( + params: DocsChildrenParams, + queryConfig?: Omit< + UseQueryOptions, + 'queryKey' | 'queryFn' + >, +) { + return useQuery({ + queryKey: [KEY_LIST_DOC_CHILDREN, params], + queryFn: () => getDocChildren(params), + ...queryConfig, + }); +} + +export const useInfiniteDocChildren = (params: DocsChildrenParams) => { + return useAPIInfiniteQuery(KEY_LIST_DOC_CHILDREN, getDocChildren, params); +}; diff --git a/src/frontend/apps/impress/src/features/docs/doc-tree/api/useDocTree.tsx b/src/frontend/apps/impress/src/features/docs/doc-tree/api/useDocTree.tsx new file mode 100644 index 000000000..bebb1d828 --- /dev/null +++ b/src/frontend/apps/impress/src/features/docs/doc-tree/api/useDocTree.tsx @@ -0,0 +1,44 @@ +import { UseQueryOptions, useQuery } from '@tanstack/react-query'; + +import { APIError, errorCauses, fetchAPI } from '@/api'; + +import { Doc } from '../../doc-management'; + +export type DocsTreeParams = { + docId: string; +}; + +export const getDocTree = async ({ docId }: DocsTreeParams): Promise => { + const searchParams = new URLSearchParams(); + + const response = await fetchAPI( + `documents/${docId}/tree/?${searchParams.toString()}`, + ); + + if (!response.ok) { + throw new APIError( + 'Failed to get the doc tree', + await errorCauses(response), + ); + } + + return response.json() as Promise; +}; + +export const KEY_LIST_DOC_CHILDREN = 'doc-tree'; + +export function useDocTree( + params: DocsTreeParams, + queryConfig?: Omit< + UseQueryOptions, + 'queryKey' | 'queryFn' + >, +) { + return useQuery({ + queryKey: [KEY_LIST_DOC_CHILDREN, params], + queryFn: () => getDocTree(params), + staleTime: 0, + refetchOnWindowFocus: false, + ...queryConfig, + }); +} diff --git a/src/frontend/apps/impress/src/features/docs/doc-tree/assets/doc-extract-bold.svg b/src/frontend/apps/impress/src/features/docs/doc-tree/assets/doc-extract-bold.svg new file mode 100644 index 000000000..47d4fa1a9 --- /dev/null +++ b/src/frontend/apps/impress/src/features/docs/doc-tree/assets/doc-extract-bold.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/frontend/apps/impress/src/features/docs/doc-tree/assets/sub-page-logo.svg b/src/frontend/apps/impress/src/features/docs/doc-tree/assets/sub-page-logo.svg new file mode 100644 index 000000000..790684c6e --- /dev/null +++ b/src/frontend/apps/impress/src/features/docs/doc-tree/assets/sub-page-logo.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/frontend/apps/impress/src/features/docs/doc-tree/components/DocSubPageItem.tsx b/src/frontend/apps/impress/src/features/docs/doc-tree/components/DocSubPageItem.tsx new file mode 100644 index 000000000..789686bae --- /dev/null +++ b/src/frontend/apps/impress/src/features/docs/doc-tree/components/DocSubPageItem.tsx @@ -0,0 +1,169 @@ +import { + TreeViewItem, + TreeViewNodeProps, + useTreeContext, +} from '@gouvfr-lasuite/ui-kit'; +import { useRouter } from 'next/navigation'; +import { useEffect, useRef, useState } from 'react'; +import { css } from 'styled-components'; + +import { Box, Icon, Text } from '@/components'; +import { useCunninghamTheme } from '@/cunningham'; +import { + Doc, + KEY_SUB_PAGE, + useDoc, + useTrans, +} from '@/features/docs/doc-management'; +import { useLeftPanelStore } from '@/features/left-panel'; + +import Logo from './../assets/sub-page-logo.svg'; +import { DocTreeItemActions } from './DocTreeItemActions'; + +const ItemTextCss = css` + overflow: hidden; + text-overflow: ellipsis; + white-space: initial; + display: -webkit-box; + line-clamp: 1; + -webkit-line-clamp: 1; + -webkit-box-orient: vertical; +`; + +type Props = TreeViewNodeProps; +export const DocSubPageItem = (props: Props) => { + const doc = props.node.data.value as Doc; + const treeContext = useTreeContext(); + const { untitledDocument } = useTrans(); + const { node } = props; + const { spacingsTokens } = useCunninghamTheme(); + const [isHover, setIsHover] = useState(false); + + const spacing = spacingsTokens(); + const router = useRouter(); + const { togglePanel } = useLeftPanelStore(); + + const isInitialLoad = useRef(false); + const { data: docQuery } = useDoc( + { id: doc.id }, + { + initialData: doc, + queryKey: [KEY_SUB_PAGE, { id: doc.id }], + refetchOnMount: false, + refetchOnWindowFocus: false, + }, + ); + + useEffect(() => { + if (docQuery && isInitialLoad.current === true) { + treeContext?.treeData.updateNode(docQuery.id, docQuery); + } + + if (docQuery) { + isInitialLoad.current = true; + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [docQuery]); + + const afterCreate = (createdDoc: Doc) => { + const actualChildren = node.data.children ?? []; + + if (actualChildren.length === 0) { + treeContext?.treeData + .handleLoadChildren(node?.data.value.id) + .then((allChildren) => { + node.open(); + + router.push(`/docs/${doc.id}`); + treeContext?.treeData.setChildren(node.data.value.id, allChildren); + togglePanel(); + }) + .catch(console.error); + } else { + const newDoc = { + ...createdDoc, + children: [], + childrenCount: 0, + parentId: node.id, + }; + treeContext?.treeData.addChild(node.data.value.id, newDoc); + node.open(); + router.push(`/docs/${createdDoc.id}`); + togglePanel(); + } + }; + + return ( + setIsHover(true)} + onMouseLeave={() => setIsHover(false)} + $css={css` + &:not(:has(.isSelected)):has(.light-doc-item-actions) { + background-color: var(--c--theme--colors--greyscale-100); + } + `} + > + { + treeContext?.treeData.setSelectedNode(props.node.data.value as Doc); + router.push(`/docs/${props.node.data.value.id}`); + }} + > + + + + + + + + {doc.title || untitledDocument} + + {doc.nb_accesses_direct > 1 && ( + + )} + + + {isHover && ( + + + + )} + + + + ); +}; diff --git a/src/frontend/apps/impress/src/features/docs/doc-tree/components/DocTree.tsx b/src/frontend/apps/impress/src/features/docs/doc-tree/components/DocTree.tsx new file mode 100644 index 000000000..32bea3e54 --- /dev/null +++ b/src/frontend/apps/impress/src/features/docs/doc-tree/components/DocTree.tsx @@ -0,0 +1,233 @@ +import { + OpenMap, + TreeView, + TreeViewMoveResult, + useTreeContext, +} from '@gouvfr-lasuite/ui-kit'; +import { useRouter } from 'next/navigation'; +import { useEffect, useRef, useState } from 'react'; +import { css } from 'styled-components'; + +import { Box, StyledLink } from '@/components'; +import { useCunninghamTheme } from '@/cunningham'; + +import { Doc, KEY_SUB_PAGE, useDoc, useDocStore } from '../../doc-management'; +import { SimpleDocItem } from '../../docs-grid'; +import { useDocTree } from '../api/useDocTree'; +import { useMoveDoc } from '../api/useMove'; +import { canDrag, canDrop, serializeDocToSubPage } from '../utils'; + +import { DocSubPageItem } from './DocSubPageItem'; +import { DocTreeItemActions } from './DocTreeItemActions'; + +type DocTreeProps = { + initialTargetId: string; +}; +export const DocTree = ({ initialTargetId }: DocTreeProps) => { + const { spacingsTokens } = useCunninghamTheme(); + const spacing = spacingsTokens(); + const treeContext = useTreeContext(); + const { currentDoc } = useDocStore(); + const router = useRouter(); + + const previousDocId = useRef(initialTargetId); + + const { data: rootNode } = useDoc( + { id: treeContext?.root?.id ?? '' }, + { + enabled: !!treeContext?.root?.id, + initialData: treeContext?.root ?? undefined, + queryKey: [KEY_SUB_PAGE, { id: treeContext?.root?.id ?? '' }], + refetchOnMount: false, + refetchOnWindowFocus: false, + }, + ); + + const [initialOpenState, setInitialOpenState] = useState( + undefined, + ); + + const { mutate: moveDoc } = useMoveDoc(); + + const { data } = useDocTree({ + docId: initialTargetId, + }); + + const handleMove = (result: TreeViewMoveResult) => { + moveDoc({ + sourceDocumentId: result.sourceId, + targetDocumentId: result.targetModeId, + position: result.mode, + }); + treeContext?.treeData.handleMove(result); + }; + + useEffect(() => { + if (!data) { + return; + } + + const { children: rootChildren, ...root } = data; + const children = rootChildren ?? []; + treeContext?.setRoot(root); + const initialOpenState: OpenMap = {}; + initialOpenState[root.id] = true; + const serialize = (children: Doc[]) => { + children.forEach((child) => { + child.childrenCount = child.numchild ?? 0; + if (child?.children?.length && child?.children?.length > 0) { + initialOpenState[child.id] = true; + } + serialize(child.children ?? []); + }); + }; + serialize(children); + + treeContext?.treeData.resetTree(children); + setInitialOpenState(initialOpenState); + if (initialTargetId === root.id) { + treeContext?.treeData.setSelectedNode(root); + } else { + treeContext?.treeData.selectNodeById(initialTargetId); + } + + // Because treeData change in the treeContext, we have a infinite loop + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [data, initialTargetId]); + + useEffect(() => { + if ( + !currentDoc || + (previousDocId.current && previousDocId.current === currentDoc.id) + ) { + return; + } + + const item = treeContext?.treeData.getNode(currentDoc?.id ?? ''); + if (!item && currentDoc.id !== rootNode?.id) { + treeContext?.treeData.resetTree([]); + treeContext?.setRoot(currentDoc); + treeContext?.setInitialTargetId(currentDoc.id); + } else if (item) { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { children, ...rest } = currentDoc; + treeContext?.treeData.updateNode( + currentDoc.id, + serializeDocToSubPage(rest), + ); + } + if (currentDoc?.id && currentDoc?.id !== previousDocId.current) { + previousDocId.current = currentDoc?.id; + } + + treeContext?.treeData.setSelectedNode(currentDoc); + + // we don't need to run this effect on every change of treeContext.data bacause it cause an infinite loop + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [currentDoc, rootNode?.id]); + + const rootIsSelected = + treeContext?.treeData.selectedNode?.id === treeContext?.root?.id; + + if (!initialTargetId || !treeContext) { + return null; + } + + return ( + + + + {treeContext.root !== null && rootNode && ( + { + e.stopPropagation(); + e.preventDefault(); + treeContext.treeData.setSelectedNode( + treeContext.root ?? undefined, + ); + router.push(`/docs/${treeContext?.root?.id}`); + }} + > + + +
+ { + const newDoc = { + ...createdDoc, + children: [], + childrenCount: 0, + parentId: treeContext.root?.id ?? undefined, + }; + treeContext?.treeData.addChild(null, newDoc); + }} + /> +
+
+
+ )} +
+
+ + {initialOpenState && treeContext.treeData.nodes.length > 0 && ( + { + if (!rootNode) { + return false; + } + const parentDoc = parentNode?.data.value as Doc; + if (!parentDoc) { + return canDrop(rootNode); + } + return canDrop(parentDoc); + }} + canDrag={(node) => { + const doc = node.value as Doc; + return canDrag(doc); + }} + rootNodeId={treeContext.root?.id ?? ''} + renderNode={DocSubPageItem} + /> + )} +
+ ); +}; diff --git a/src/frontend/apps/impress/src/features/docs/doc-tree/components/DocTreeItemActions.tsx b/src/frontend/apps/impress/src/features/docs/doc-tree/components/DocTreeItemActions.tsx new file mode 100644 index 000000000..785513649 --- /dev/null +++ b/src/frontend/apps/impress/src/features/docs/doc-tree/components/DocTreeItemActions.tsx @@ -0,0 +1,171 @@ +import { + DropdownMenu, + DropdownMenuOption, + useTreeContext, +} from '@gouvfr-lasuite/ui-kit'; +import { useModal } from '@openfun/cunningham-react'; +import { useRouter } from 'next/navigation'; +import { Fragment, useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { css } from 'styled-components'; + +import { Box, BoxButton, Icon } from '@/components'; +import { useLeftPanelStore } from '@/features/left-panel'; + +import { Doc, ModalRemoveDoc, useCopyDocLink } from '../../doc-management'; +import { useCreateChildrenDoc } from '../api/useCreateChildren'; +import { useDetachDoc } from '../api/useDetach'; +import MoveDocIcon from '../assets/doc-extract-bold.svg'; +import { useTreeUtils } from '../hooks'; +import { isOwnerOrAdmin } from '../utils'; + +type DocTreeItemActionsProps = { + doc: Doc; + parentId?: string | null; + onCreateSuccess?: (newDoc: Doc) => void; +}; + +export const DocTreeItemActions = ({ + doc, + parentId, + onCreateSuccess, +}: DocTreeItemActionsProps) => { + const [isOpen, setIsOpen] = useState(false); + const router = useRouter(); + const { t } = useTranslation(); + const deleteModal = useModal(); + const { togglePanel } = useLeftPanelStore(); + const copyLink = useCopyDocLink(doc.id); + const canUpdate = isOwnerOrAdmin(doc); + const { isChild } = useTreeUtils(doc); + const { mutate: detachDoc } = useDetachDoc(); + const treeContext = useTreeContext(); + + const handleDetachDoc = () => { + if (!treeContext?.root) { + return; + } + + detachDoc( + { documentId: doc.id, rootId: treeContext.root.id }, + { + onSuccess: () => { + treeContext.treeData.deleteNode(doc.id); + if (treeContext.root) { + treeContext.treeData.setSelectedNode(treeContext.root); + router.push(`/docs/${treeContext.root.id}`); + } + }, + }, + ); + }; + + const options: DropdownMenuOption[] = [ + { + label: t('Copy link'), + icon: , + callback: copyLink, + }, + ...(isChild + ? [ + { + label: t('Convert to doc'), + isDisabled: !canUpdate, + icon: ( + + + + ), + callback: handleDetachDoc, + }, + ] + : []), + { + label: t('Delete'), + isDisabled: !canUpdate, + icon: , + callback: deleteModal.open, + }, + ]; + + const { mutate: createChildrenDoc } = useCreateChildrenDoc({ + onSuccess: (doc) => { + onCreateSuccess?.(doc); + togglePanel(); + router.push(`/docs/${doc.id}`); + treeContext?.treeData.setSelectedNode(doc); + }, + }); + + const afterDelete = () => { + if (parentId) { + treeContext?.treeData.deleteNode(doc.id); + router.push(`/docs/${parentId}`); + } else if (doc.id === treeContext?.root?.id && !parentId) { + router.push(`/docs/`); + } else if (treeContext && treeContext.root) { + treeContext?.treeData.deleteNode(doc.id); + router.push(`/docs/${treeContext.root.id}`); + } + }; + + return ( + + + + { + e.stopPropagation(); + e.preventDefault(); + setIsOpen(!isOpen); + }} + iconName="more_horiz" + variant="filled" + $theme="primary" + $variation="600" + /> + + {canUpdate && ( + { + e.stopPropagation(); + e.preventDefault(); + + createChildrenDoc({ + parentId: doc.id, + }); + }} + color="primary" + > + + + )} + + {deleteModal.isOpen && ( + + )} + + ); +}; diff --git a/src/frontend/apps/impress/src/features/docs/doc-tree/hooks/index.ts b/src/frontend/apps/impress/src/features/docs/doc-tree/hooks/index.ts new file mode 100644 index 000000000..3fb57a348 --- /dev/null +++ b/src/frontend/apps/impress/src/features/docs/doc-tree/hooks/index.ts @@ -0,0 +1 @@ +export * from './useTreeUtils'; diff --git a/src/frontend/apps/impress/src/features/docs/doc-tree/hooks/useTreeUtils.tsx b/src/frontend/apps/impress/src/features/docs/doc-tree/hooks/useTreeUtils.tsx new file mode 100644 index 000000000..086f5b6b3 --- /dev/null +++ b/src/frontend/apps/impress/src/features/docs/doc-tree/hooks/useTreeUtils.tsx @@ -0,0 +1,13 @@ +import { useTreeContext } from '@gouvfr-lasuite/ui-kit'; + +import { Doc } from '@/docs/doc-management'; + +export const useTreeUtils = (doc: Doc) => { + const treeContext = useTreeContext(); + + return { + isParent: doc.nb_accesses_ancestors <= 1, // it is a parent + isChild: doc.nb_accesses_ancestors > 1, // it is a child + isCurrentParent: treeContext?.root?.id === doc.id, // it can be a child but not for the current user + } as const; +}; diff --git a/src/frontend/apps/impress/src/features/docs/doc-tree/index.ts b/src/frontend/apps/impress/src/features/docs/doc-tree/index.ts new file mode 100644 index 000000000..608f00da5 --- /dev/null +++ b/src/frontend/apps/impress/src/features/docs/doc-tree/index.ts @@ -0,0 +1,3 @@ +export * from './api'; +export * from './hooks'; +export * from './utils'; diff --git a/src/frontend/apps/impress/src/features/docs/doc-tree/utils.ts b/src/frontend/apps/impress/src/features/docs/doc-tree/utils.ts new file mode 100644 index 000000000..f632c2cad --- /dev/null +++ b/src/frontend/apps/impress/src/features/docs/doc-tree/utils.ts @@ -0,0 +1,29 @@ +import { TreeViewDataType } from '@gouvfr-lasuite/ui-kit'; + +import { Doc, Role } from '../doc-management'; + +export const serializeDocToSubPage = (doc: Doc): Doc => { + return { ...doc, childrenCount: doc.numchild }; +}; + +export const subPageToTree = (children: Doc[]): TreeViewDataType[] => { + children.forEach((child) => { + child.childrenCount = child.numchild ?? 0; + subPageToTree(child.children ?? []); + }); + return children; +}; + +export const isOwnerOrAdmin = (doc: Doc): boolean => { + return doc.user_roles.some( + (role) => role === Role.OWNER || role === Role.ADMIN, + ); +}; + +export const canDrag = (doc: Doc): boolean => { + return isOwnerOrAdmin(doc); +}; + +export const canDrop = (doc: Doc): boolean => { + return isOwnerOrAdmin(doc); +}; diff --git a/src/frontend/apps/impress/src/features/left-panel/components/LeftPanelDocContent.tsx b/src/frontend/apps/impress/src/features/left-panel/components/LeftPanelDocContent.tsx index 505735780..31b00f074 100644 --- a/src/frontend/apps/impress/src/features/left-panel/components/LeftPanelDocContent.tsx +++ b/src/frontend/apps/impress/src/features/left-panel/components/LeftPanelDocContent.tsx @@ -1,14 +1,14 @@ -import { css } from 'styled-components'; +import { useTreeContext } from '@gouvfr-lasuite/ui-kit'; -import { Box, SeparatedSection } from '@/components'; -import { useCunninghamTheme } from '@/cunningham'; -import { useDocStore } from '@/docs/doc-management'; -import { SimpleDocItem } from '@/docs/docs-grid'; +import { Box } from '@/components'; +import { Doc, useDocStore } from '@/docs/doc-management'; +import { DocTree } from '@/features/docs/doc-tree/components/DocTree'; export const LeftPanelDocContent = () => { const { currentDoc } = useDocStore(); - const { spacingsTokens } = useCunninghamTheme(); - if (!currentDoc) { + const tree = useTreeContext(); + + if (!currentDoc || !tree) { return null; } @@ -19,19 +19,9 @@ export const LeftPanelDocContent = () => { $css="width: 100%; overflow-y: auto; overflow-x: hidden;" className="--docs--left-panel-doc-content" > - - - - - - - + {tree.initialTargetId && ( + + )}
); }; diff --git a/src/frontend/apps/impress/src/features/left-panel/components/LeftPanelHeader.tsx b/src/frontend/apps/impress/src/features/left-panel/components/LeftPanelHeader.tsx index 7177bc2c7..5733b0dff 100644 --- a/src/frontend/apps/impress/src/features/left-panel/components/LeftPanelHeader.tsx +++ b/src/frontend/apps/impress/src/features/left-panel/components/LeftPanelHeader.tsx @@ -1,19 +1,21 @@ import { Button } from '@openfun/cunningham-react'; -import { t } from 'i18next'; -import { useRouter } from 'next/navigation'; +import { useRouter } from 'next/router'; import { PropsWithChildren, useCallback, useState } from 'react'; import { Box, Icon, SeparatedSection } from '@/components'; -import { useCreateDoc } from '@/docs/doc-management'; -import { DocSearchModal } from '@/docs/doc-search'; +import { DocSearchModal, DocSearchTarget } from '@/docs/doc-search/'; import { useAuth } from '@/features/auth'; import { useCmdK } from '@/hook/useCmdK'; import { useLeftPanelStore } from '../stores'; +import { LeftPanelHeaderButton } from './LeftPanelHeaderButton'; + export const LeftPanelHeader = ({ children }: PropsWithChildren) => { const router = useRouter(); const { authenticated } = useAuth(); + const isDoc = router.pathname === '/docs/[id]'; + const [isSearchModalOpen, setIsSearchModalOpen] = useState(false); const openSearchModal = useCallback(() => { @@ -33,22 +35,11 @@ export const LeftPanelHeader = ({ children }: PropsWithChildren) => { useCmdK(openSearchModal); const { togglePanel } = useLeftPanelStore(); - const { mutate: createDoc, isPending: isCreatingDoc } = useCreateDoc({ - onSuccess: (doc) => { - router.push(`/docs/${doc.id}`); - togglePanel(); - }, - }); - const goToHome = () => { - router.push('/'); + void router.push('/'); togglePanel(); }; - const createNewDoc = () => { - createDoc(); - }; - return ( <> @@ -80,17 +71,21 @@ export const LeftPanelHeader = ({ children }: PropsWithChildren) => { /> )} - {authenticated && ( - - )} + + {authenticated && }
{children}
{isSearchModalOpen && ( - + )} ); diff --git a/src/frontend/apps/impress/src/features/left-panel/components/LeftPanelHeaderButton.tsx b/src/frontend/apps/impress/src/features/left-panel/components/LeftPanelHeaderButton.tsx new file mode 100644 index 000000000..7589f9554 --- /dev/null +++ b/src/frontend/apps/impress/src/features/left-panel/components/LeftPanelHeaderButton.tsx @@ -0,0 +1,73 @@ +import { useTreeContext } from '@gouvfr-lasuite/ui-kit'; +import { Button } from '@openfun/cunningham-react'; +import { useRouter } from 'next/router'; +import { useTranslation } from 'react-i18next'; + +import { Doc, useCreateDoc, useDocStore } from '@/features/docs'; +import { useCreateChildrenDoc } from '@/features/docs/doc-tree/api/useCreateChildren'; +import { isOwnerOrAdmin } from '@/features/docs/doc-tree/utils'; + +import { useLeftPanelStore } from '../stores'; + +export const LeftPanelHeaderButton = () => { + const router = useRouter(); + const isDoc = router.pathname === '/docs/[id]'; + + if (isDoc) { + return ; + } + + return ; +}; + +export const LeftPanelHeaderHomeButton = () => { + const router = useRouter(); + const { t } = useTranslation(); + const { togglePanel } = useLeftPanelStore(); + const { mutate: createDoc } = useCreateDoc({ + onSuccess: (doc) => { + void router.push(`/docs/${doc.id}`); + togglePanel(); + }, + }); + return ( + + ); +}; + +export const LeftPanelHeaderDocButton = () => { + const router = useRouter(); + const { currentDoc } = useDocStore(); + const { t } = useTranslation(); + const { togglePanel } = useLeftPanelStore(); + const treeContext = useTreeContext(); + const tree = treeContext?.treeData; + const { mutate: createChildrenDoc } = useCreateChildrenDoc({ + onSuccess: (doc) => { + tree?.addRootNode(doc); + tree?.selectNodeById(doc.id); + void router.push(`/docs/${doc.id}`); + togglePanel(); + }, + }); + + const onCreateDoc = () => { + if (treeContext && treeContext.root) { + createChildrenDoc({ + parentId: treeContext.root.id, + }); + } + }; + + return ( + + ); +}; diff --git a/src/frontend/apps/impress/src/pages/docs/[id]/index.tsx b/src/frontend/apps/impress/src/pages/docs/[id]/index.tsx index 74f2d0391..168dc29a9 100644 --- a/src/frontend/apps/impress/src/pages/docs/[id]/index.tsx +++ b/src/frontend/apps/impress/src/pages/docs/[id]/index.tsx @@ -1,3 +1,4 @@ +import { TreeProvider } from '@gouvfr-lasuite/ui-kit'; import { Loader } from '@openfun/cunningham-react'; import { useQueryClient } from '@tanstack/react-query'; import Head from 'next/head'; @@ -7,14 +8,15 @@ import { useTranslation } from 'react-i18next'; import { Box, Icon, TextErrors } from '@/components'; import { DocEditor } from '@/docs/doc-editor'; +import { KEY_AUTH, setAuthUrl } from '@/features/auth'; import { Doc, KEY_DOC, useCollaboration, useDoc, useDocStore, -} from '@/docs/doc-management/'; -import { KEY_AUTH, setAuthUrl } from '@/features/auth'; +} from '@/features/docs/doc-management/'; +import { getDocChildren, subPageToTree } from '@/features/docs/doc-tree/'; import { MainLayout } from '@/layouts'; import { useBroadcastStore } from '@/stores'; import { NextPageWithLayout } from '@/types/next'; @@ -34,9 +36,17 @@ export function DocLayout() { - - - + { + const doc = await getDocChildren({ docId }); + return subPageToTree(doc.results); + }} + > + + + + ); } @@ -84,6 +94,12 @@ const DocPage = ({ id }: DocProps) => { setCurrentDoc(docQuery); }, [docQuery, setCurrentDoc, isFetching]); + useEffect(() => { + return () => { + setCurrentDoc(undefined); + }; + }, [setCurrentDoc]); + /** * We add a broadcast task to reset the query cache * when the document visibility changes. diff --git a/src/frontend/apps/impress/src/tests/utils.tsx b/src/frontend/apps/impress/src/tests/utils.tsx index b0d7c7ded..523fa01d5 100644 --- a/src/frontend/apps/impress/src/tests/utils.tsx +++ b/src/frontend/apps/impress/src/tests/utils.tsx @@ -1,3 +1,4 @@ +import { TreeProvider } from '@gouvfr-lasuite/ui-kit'; import { CunninghamProvider } from '@openfun/cunningham-react'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { PropsWithChildren } from 'react'; @@ -14,8 +15,10 @@ export const AppWrapper = ({ children }: PropsWithChildren) => { }); return ( - - {children} - + + + {children} + + ); }; From 585d39d054af1b260d9899d5dac823b2604c8aea Mon Sep 17 00:00:00 2001 From: Nathan Panchout Date: Thu, 27 Mar 2025 16:08:39 +0100 Subject: [PATCH 14/26] =?UTF-8?q?=E2=9C=A8(frontend)=20added=20new=20featu?= =?UTF-8?q?res=20for=20document=20management?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Created new files for managing subdocuments and detaching documents. - Refactored API request configuration to use an improved configuration type. - Removed unnecessary logs from the ModalConfirmDownloadUnsafe component. --- .../__tests__/app-impress/doc-tree.spec.ts | 40 ++++++++++++ src/frontend/apps/impress/src/api/helpers.tsx | 7 ++- .../ModalConfirmDownloadUnsafe.tsx | 1 - .../features/docs/doc-management/api/index.ts | 3 +- .../docs/doc-management/api/useDocs.tsx | 30 +++------ .../docs/doc-management/api/useSubDocs.tsx | 62 +++++++++++++++++++ .../features/docs/doc-management/types.tsx | 20 ++++-- .../features/docs/doc-tree/api/useDetach.tsx | 51 +++++++++++++++ .../components/DocTreeItemActions.tsx | 4 +- .../docs/doc-tree/hooks/useTreeUtils.tsx | 2 +- .../src/features/service-worker/ApiPlugin.ts | 1 + .../apps/impress/src/pages/globals.css | 8 --- 12 files changed, 190 insertions(+), 39 deletions(-) create mode 100644 src/frontend/apps/impress/src/features/docs/doc-management/api/useSubDocs.tsx create mode 100644 src/frontend/apps/impress/src/features/docs/doc-tree/api/useDetach.tsx diff --git a/src/frontend/apps/e2e/__tests__/app-impress/doc-tree.spec.ts b/src/frontend/apps/e2e/__tests__/app-impress/doc-tree.spec.ts index bf4b31349..07a927aa4 100644 --- a/src/frontend/apps/e2e/__tests__/app-impress/doc-tree.spec.ts +++ b/src/frontend/apps/e2e/__tests__/app-impress/doc-tree.spec.ts @@ -159,6 +159,46 @@ test.describe('Doc Tree', () => { `doc-sub-page-item-${firstSubPageJson.id}`, ); }); + + test('it detachs a document', async ({ page, browserName }) => { + await page.goto('/'); + const [docParent] = await createDoc( + page, + 'doc-tree-detach', + browserName, + 1, + ); + await verifyDocName(page, docParent); + + const [docChild] = await createDoc( + page, + 'doc-tree-detach-child', + browserName, + 1, + true, + ); + await verifyDocName(page, docChild); + + const docTree = page.getByTestId('doc-tree'); + const child = docTree + .getByRole('treeitem') + .locator('.--docs-sub-page-item') + .filter({ + hasText: docChild, + }); + await child.hover(); + const menu = child.getByText(`more_horiz`); + await menu.click(); + await page.getByText('Convert to doc').click(); + + await expect( + page.getByRole('textbox', { name: 'doc title input' }), + ).not.toHaveText(docChild); + + const header = page.locator('header').first(); + await header.locator('h2').getByText('Docs').click(); + await expect(page.getByText(docChild)).toBeVisible(); + }); }); test.describe('Doc Tree: Inheritance', () => { diff --git a/src/frontend/apps/impress/src/api/helpers.tsx b/src/frontend/apps/impress/src/api/helpers.tsx index 9f304d2e3..7b54753ce 100644 --- a/src/frontend/apps/impress/src/api/helpers.tsx +++ b/src/frontend/apps/impress/src/api/helpers.tsx @@ -21,6 +21,11 @@ export type DefinedInitialDataInfiniteOptionsAPI< TPageParam >; +export type InfiniteQueryConfig = Omit< + DefinedInitialDataInfiniteOptionsAPI, + 'queryKey' | 'initialData' | 'getNextPageParam' | 'initialPageParam' +>; + /** * @param param Used for infinite scroll pagination * @param queryConfig @@ -30,7 +35,7 @@ export const useAPIInfiniteQuery = ['next'] }>( key: string, api: (props: T & { page: number }) => Promise, param: T, - queryConfig?: DefinedInitialDataInfiniteOptionsAPI, + queryConfig?: InfiniteQueryConfig, ) => { return useInfiniteQuery, QueryKey, number>({ initialPageParam: 1, diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteToolBar/ModalConfirmDownloadUnsafe.tsx b/src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteToolBar/ModalConfirmDownloadUnsafe.tsx index e38c8639c..3929175cb 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteToolBar/ModalConfirmDownloadUnsafe.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteToolBar/ModalConfirmDownloadUnsafe.tsx @@ -32,7 +32,6 @@ export const ModalConfirmDownloadUnsafe = ({ aria-label={t('Download')} color="danger" onClick={() => { - console.log('onClick'); if (onConfirm) { void onConfirm(); } diff --git a/src/frontend/apps/impress/src/features/docs/doc-management/api/index.ts b/src/frontend/apps/impress/src/features/docs/doc-management/api/index.ts index 11123c6bb..df4123600 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-management/api/index.ts +++ b/src/frontend/apps/impress/src/features/docs/doc-management/api/index.ts @@ -1,8 +1,9 @@ export * from './useCreateDoc'; +export * from './useCreateFavoriteDoc'; export * from './useDeleteFavoriteDoc'; export * from './useDoc'; export * from './useDocOptions'; export * from './useDocs'; -export * from './useCreateFavoriteDoc'; +export * from './useSubDocs'; export * from './useUpdateDoc'; export * from './useUpdateDocLink'; diff --git a/src/frontend/apps/impress/src/features/docs/doc-management/api/useDocs.tsx b/src/frontend/apps/impress/src/features/docs/doc-management/api/useDocs.tsx index 5f5636d57..88f385df5 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-management/api/useDocs.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-management/api/useDocs.tsx @@ -8,22 +8,7 @@ import { useAPIInfiniteQuery, } from '@/api'; -import { Doc } from '../types'; - -export const isDocsOrdering = (data: string): data is DocsOrdering => { - return !!docsOrdering.find((validKey) => validKey === data); -}; - -const docsOrdering = [ - 'created_at', - '-created_at', - 'updated_at', - '-updated_at', - 'title', - '-title', -] as const; - -export type DocsOrdering = (typeof docsOrdering)[number]; +import { Doc, DocsOrdering } from '../types'; export type DocsParams = { page: number; @@ -33,26 +18,31 @@ export type DocsParams = { is_favorite?: boolean; }; -export type DocsResponse = APIList; -export const getDocs = async (params: DocsParams): Promise => { +export const constructParams = (params: DocsParams): URLSearchParams => { const searchParams = new URLSearchParams(); + if (params.page) { searchParams.set('page', params.page.toString()); } - if (params.ordering) { searchParams.set('ordering', params.ordering); } if (params.is_creator_me !== undefined) { searchParams.set('is_creator_me', params.is_creator_me.toString()); } - if (params.title && params.title.length > 0) { searchParams.set('title', params.title); } if (params.is_favorite !== undefined) { searchParams.set('is_favorite', params.is_favorite.toString()); } + + return searchParams; +}; + +export type DocsResponse = APIList; +export const getDocs = async (params: DocsParams): Promise => { + const searchParams = constructParams(params); const response = await fetchAPI(`documents/?${searchParams.toString()}`); if (!response.ok) { diff --git a/src/frontend/apps/impress/src/features/docs/doc-management/api/useSubDocs.tsx b/src/frontend/apps/impress/src/features/docs/doc-management/api/useSubDocs.tsx new file mode 100644 index 000000000..e76c8bc4e --- /dev/null +++ b/src/frontend/apps/impress/src/features/docs/doc-management/api/useSubDocs.tsx @@ -0,0 +1,62 @@ +import { UseQueryOptions, useQuery } from '@tanstack/react-query'; + +import { + APIError, + InfiniteQueryConfig, + errorCauses, + fetchAPI, + useAPIInfiniteQuery, +} from '@/api'; + +import { DocsOrdering } from '../types'; + +import { DocsResponse, constructParams } from './useDocs'; + +export type SubDocsParams = { + page: number; + ordering?: DocsOrdering; + is_creator_me?: boolean; + title?: string; + is_favorite?: boolean; + parent_id: string; +}; + +export const getSubDocs = async ( + params: SubDocsParams, +): Promise => { + const searchParams = constructParams(params); + searchParams.set('parent_id', params.parent_id); + + const response: Response = await fetchAPI( + `documents/${params.parent_id}/descendants/?${searchParams.toString()}`, + ); + + if (!response.ok) { + throw new APIError( + 'Failed to get the sub docs', + await errorCauses(response), + ); + } + + return response.json() as Promise; +}; + +export const KEY_LIST_SUB_DOC = 'sub-docs'; + +export function useSubDocs( + params: SubDocsParams, + queryConfig?: UseQueryOptions, +) { + return useQuery({ + queryKey: [KEY_LIST_SUB_DOC, params], + queryFn: () => getSubDocs(params), + ...queryConfig, + }); +} + +export const useInfiniteSubDocs = ( + params: SubDocsParams, + queryConfig?: InfiniteQueryConfig, +) => { + return useAPIInfiniteQuery(KEY_LIST_SUB_DOC, getSubDocs, params, queryConfig); +}; diff --git a/src/frontend/apps/impress/src/features/docs/doc-management/types.tsx b/src/frontend/apps/impress/src/features/docs/doc-management/types.tsx index 2cc117b73..c09b9de17 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-management/types.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-management/types.tsx @@ -37,19 +37,20 @@ export type Base64 = string; export interface Doc { id: string; title?: string; + children?: Doc[]; + childrenCount?: number; content: Base64; + created_at: string; creator: string; + depth: number; is_favorite: boolean; link_reach: LinkReach; link_role: LinkRole; - user_roles: Role[]; - created_at: string; - updated_at: string; nb_accesses_direct: number; nb_accesses_ancestors: number; - children?: Doc[]; - childrenCount?: number; numchild: number; + updated_at: string; + user_roles: Role[]; abilities: { accesses_manage: boolean; accesses_view: boolean; @@ -80,3 +81,12 @@ export enum DocDefaultFilter { MY_DOCS = 'my_docs', SHARED_WITH_ME = 'shared_with_me', } + +export type DocsOrdering = + | 'title' + | 'created_at' + | '-created_at' + | 'updated_at' + | '-updated_at' + | '-title' + | undefined; diff --git a/src/frontend/apps/impress/src/features/docs/doc-tree/api/useDetach.tsx b/src/frontend/apps/impress/src/features/docs/doc-tree/api/useDetach.tsx new file mode 100644 index 000000000..8e261c492 --- /dev/null +++ b/src/frontend/apps/impress/src/features/docs/doc-tree/api/useDetach.tsx @@ -0,0 +1,51 @@ +import { useMutation, useQueryClient } from '@tanstack/react-query'; + +import { APIError, errorCauses, fetchAPI } from '@/api'; + +import { KEY_DOC, KEY_LIST_DOC } from '../../doc-management'; + +export type DetachDocParam = { + documentId: string; + rootId: string; +}; + +enum POSITION_MOVE { + FIRST_CHILD = 'first-child', + LAST_CHILD = 'last-child', + FIRST_SIBLING = 'first-sibling', + LAST_SIBLING = 'last-sibling', + LEFT = 'left', + RIGHT = 'right', +} + +export const detachDoc = async ({ + documentId, + rootId, +}: DetachDocParam): Promise => { + const response = await fetchAPI(`documents/${documentId}/move/`, { + method: 'POST', + body: JSON.stringify({ + target_document_id: rootId, + position: POSITION_MOVE.LAST_SIBLING, + }), + }); + + if (!response.ok) { + throw new APIError('Failed to move the doc', await errorCauses(response)); + } + + return response.json() as Promise; +}; + +export function useDetachDoc() { + const queryClient = useQueryClient(); + return useMutation({ + mutationFn: detachDoc, + onSuccess: (_data, variables) => { + void queryClient.invalidateQueries({ queryKey: [KEY_LIST_DOC] }); + void queryClient.invalidateQueries({ + queryKey: [KEY_DOC, { id: variables.documentId }], + }); + }, + }); +} diff --git a/src/frontend/apps/impress/src/features/docs/doc-tree/components/DocTreeItemActions.tsx b/src/frontend/apps/impress/src/features/docs/doc-tree/components/DocTreeItemActions.tsx index 785513649..ef8d5f19a 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-tree/components/DocTreeItemActions.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-tree/components/DocTreeItemActions.tsx @@ -37,7 +37,7 @@ export const DocTreeItemActions = ({ const { togglePanel } = useLeftPanelStore(); const copyLink = useCopyDocLink(doc.id); const canUpdate = isOwnerOrAdmin(doc); - const { isChild } = useTreeUtils(doc); + const { isCurrentParent } = useTreeUtils(doc); const { mutate: detachDoc } = useDetachDoc(); const treeContext = useTreeContext(); @@ -66,7 +66,7 @@ export const DocTreeItemActions = ({ icon: , callback: copyLink, }, - ...(isChild + ...(!isCurrentParent ? [ { label: t('Convert to doc'), diff --git a/src/frontend/apps/impress/src/features/docs/doc-tree/hooks/useTreeUtils.tsx b/src/frontend/apps/impress/src/features/docs/doc-tree/hooks/useTreeUtils.tsx index 086f5b6b3..55ebff958 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-tree/hooks/useTreeUtils.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-tree/hooks/useTreeUtils.tsx @@ -8,6 +8,6 @@ export const useTreeUtils = (doc: Doc) => { return { isParent: doc.nb_accesses_ancestors <= 1, // it is a parent isChild: doc.nb_accesses_ancestors > 1, // it is a child - isCurrentParent: treeContext?.root?.id === doc.id, // it can be a child but not for the current user + isCurrentParent: treeContext?.root?.id === doc.id || doc.depth === 1, // it can be a child but not for the current user } as const; }; diff --git a/src/frontend/apps/impress/src/features/service-worker/ApiPlugin.ts b/src/frontend/apps/impress/src/features/service-worker/ApiPlugin.ts index 492bc3eee..9b38b3cba 100644 --- a/src/frontend/apps/impress/src/features/service-worker/ApiPlugin.ts +++ b/src/frontend/apps/impress/src/features/service-worker/ApiPlugin.ts @@ -172,6 +172,7 @@ export class ApiPlugin implements WorkboxPlugin { content: '', created_at: new Date().toISOString(), creator: 'dummy-id', + depth: 1, is_favorite: false, nb_accesses_direct: 1, nb_accesses_ancestors: 1, diff --git a/src/frontend/apps/impress/src/pages/globals.css b/src/frontend/apps/impress/src/pages/globals.css index c6bb8ac7a..b646185f4 100644 --- a/src/frontend/apps/impress/src/pages/globals.css +++ b/src/frontend/apps/impress/src/pages/globals.css @@ -68,11 +68,3 @@ main ::-webkit-scrollbar-thumb:hover, /* Support for IE. */ font-feature-settings: 'liga'; } - -[data-nextjs-dialog-overlay] { - display: none !important; -} - -nextjs-portal { - display: none; -} From ae4a43362742052586465b4d11b977020c72aa31 Mon Sep 17 00:00:00 2001 From: Anthony LC Date: Mon, 31 Mar 2025 16:12:17 +0200 Subject: [PATCH 15/26] =?UTF-8?q?=F0=9F=94=A5(frontend)=20silent=20next.js?= =?UTF-8?q?=20error?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The error modal since next.js 15 are quite intrusive. We decided to hide them. --- src/frontend/apps/impress/src/pages/globals.css | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/frontend/apps/impress/src/pages/globals.css b/src/frontend/apps/impress/src/pages/globals.css index b646185f4..c6bb8ac7a 100644 --- a/src/frontend/apps/impress/src/pages/globals.css +++ b/src/frontend/apps/impress/src/pages/globals.css @@ -68,3 +68,11 @@ main ::-webkit-scrollbar-thumb:hover, /* Support for IE. */ font-feature-settings: 'liga'; } + +[data-nextjs-dialog-overlay] { + display: none !important; +} + +nextjs-portal { + display: none; +} From 09978ff0559b5fcaa22d8e96004f8fa31de2e145 Mon Sep 17 00:00:00 2001 From: Anthony LC Date: Wed, 2 Apr 2025 15:25:31 +0200 Subject: [PATCH 16/26] =?UTF-8?q?=E2=9C=8F=EF=B8=8F(frontend)=20child=20do?= =?UTF-8?q?cument=20with=20different=20wording?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We want to have a different wording when the child document has no title, so we can distinguish between the two cases. --- .../docs/doc-editor/components/DocEditor.tsx | 9 +-------- .../docs/doc-export/components/ModalExport.tsx | 3 +-- .../docs/doc-header/components/DocTitle.tsx | 16 +++++++--------- .../doc-header/components/DocVersionHeader.tsx | 8 ++------ .../doc-management/components/ModalRemoveDoc.tsx | 2 +- .../docs/doc-management/hooks/useTrans.tsx | 7 ++++--- .../docs/doc-tree/components/DocSubPageItem.tsx | 2 +- .../docs/docs-grid/components/SimpleDocItem.tsx | 2 +- 8 files changed, 18 insertions(+), 31 deletions(-) diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/components/DocEditor.tsx b/src/frontend/apps/impress/src/features/docs/doc-editor/components/DocEditor.tsx index d7e23aa50..5cf1db3b9 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-editor/components/DocEditor.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-editor/components/DocEditor.tsx @@ -25,11 +25,8 @@ interface DocEditorProps { export const DocEditor = ({ doc, versionId }: DocEditorProps) => { const { isDesktop } = useResponsiveStore(); - const isVersion = !!versionId && typeof versionId === 'string'; - const { colorsTokens } = useCunninghamTheme(); - const { provider } = useProviderStore(); if (!provider) { @@ -59,11 +56,7 @@ export const DocEditor = ({ doc, versionId }: DocEditorProps) => { $padding={{ horizontal: isDesktop ? '54px' : 'base' }} className="--docs--doc-editor-header" > - {isVersion ? ( - - ) : ( - - )} + {isVersion ? : }
{ const [format, setFormat] = useState( DocDownloadFormat.PDF, ); - const { untitledDocument } = useTrans(); - + const { untitledDocument } = useTrans(doc); const templateOptions = useMemo(() => { const templateOptions = (templates?.pages || []) .map((page) => diff --git a/src/frontend/apps/impress/src/features/docs/doc-header/components/DocTitle.tsx b/src/frontend/apps/impress/src/features/docs/doc-header/components/DocTitle.tsx index 5175cfe7e..b9440e6e9 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-header/components/DocTitle.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-header/components/DocTitle.tsx @@ -13,6 +13,7 @@ import { KEY_DOC, KEY_LIST_DOC, KEY_SUB_PAGE, + useDocStore, useTrans, useUpdateDoc, } from '@/docs/doc-management'; @@ -24,19 +25,16 @@ interface DocTitleProps { export const DocTitle = ({ doc }: DocTitleProps) => { if (!doc.abilities.partial_update) { - return ; + return ; } return ; }; -interface DocTitleTextProps { - title?: string; -} - -export const DocTitleText = ({ title }: DocTitleTextProps) => { +export const DocTitleText = () => { const { isMobile } = useResponsiveStore(); - const { untitledDocument } = useTrans(); + const { currentDoc } = useDocStore(); + const { untitledDocument } = useTrans(currentDoc); return ( { $size={isMobile ? 'h4' : 'h2'} $variation="1000" > - {title || untitledDocument} + {currentDoc?.title || untitledDocument} ); }; @@ -57,7 +55,7 @@ const DocTitleInput = ({ doc }: DocTitleProps) => { const { colorsTokens } = useCunninghamTheme(); const [titleDisplay, setTitleDisplay] = useState(doc.title); - const { untitledDocument } = useTrans(); + const { untitledDocument } = useTrans(doc); const { broadcast } = useBroadcastStore(); diff --git a/src/frontend/apps/impress/src/features/docs/doc-header/components/DocVersionHeader.tsx b/src/frontend/apps/impress/src/features/docs/doc-header/components/DocVersionHeader.tsx index fd8e91999..511b803c9 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-header/components/DocVersionHeader.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-header/components/DocVersionHeader.tsx @@ -5,11 +5,7 @@ import { useCunninghamTheme } from '@/cunningham'; import { DocTitleText } from './DocTitle'; -interface DocVersionHeaderProps { - title?: string; -} - -export const DocVersionHeader = ({ title }: DocVersionHeaderProps) => { +export const DocVersionHeader = () => { const { spacingsTokens } = useCunninghamTheme(); const { t } = useTranslation(); @@ -23,7 +19,7 @@ export const DocVersionHeader = ({ title }: DocVersionHeaderProps) => { aria-label={t('It is the document title')} className="--docs--doc-version-header" > - + diff --git a/src/frontend/apps/impress/src/features/docs/doc-management/components/ModalRemoveDoc.tsx b/src/frontend/apps/impress/src/features/docs/doc-management/components/ModalRemoveDoc.tsx index f83b1aff8..f852e694e 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-management/components/ModalRemoveDoc.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-management/components/ModalRemoveDoc.tsx @@ -29,7 +29,7 @@ export const ModalRemoveDoc = ({ const { toast } = useToastProvider(); const { push } = useRouter(); const pathname = usePathname(); - const { untitledDocument } = useTrans(); + const { untitledDocument } = useTrans(doc); const { mutate: removeDoc, diff --git a/src/frontend/apps/impress/src/features/docs/doc-management/hooks/useTrans.tsx b/src/frontend/apps/impress/src/features/docs/doc-management/hooks/useTrans.tsx index eb9a70163..086877025 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-management/hooks/useTrans.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-management/hooks/useTrans.tsx @@ -1,9 +1,10 @@ import { useTranslation } from 'react-i18next'; -import { Role } from '../types'; +import { Doc, Role } from '../types'; -export const useTrans = () => { +export const useTrans = (doc?: Doc) => { const { t } = useTranslation(); + const isChild = doc && doc.nb_accesses_ancestors > 1; const translatedRoles = { [Role.READER]: t('Reader'), @@ -38,7 +39,7 @@ export const useTrans = () => { transRole: (role: Role) => { return translatedRoles[role]; }, - untitledDocument: t('Untitled document'), + untitledDocument: isChild ? t('Untitled page') : t('Untitled document'), translatedRoles, getNotAllowedMessage, }; diff --git a/src/frontend/apps/impress/src/features/docs/doc-tree/components/DocSubPageItem.tsx b/src/frontend/apps/impress/src/features/docs/doc-tree/components/DocSubPageItem.tsx index 789686bae..8cb305fc3 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-tree/components/DocSubPageItem.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-tree/components/DocSubPageItem.tsx @@ -34,7 +34,7 @@ type Props = TreeViewNodeProps; export const DocSubPageItem = (props: Props) => { const doc = props.node.data.value as Doc; const treeContext = useTreeContext(); - const { untitledDocument } = useTrans(); + const { untitledDocument } = useTrans(doc); const { node } = props; const { spacingsTokens } = useCunninghamTheme(); const [isHover, setIsHover] = useState(false); diff --git a/src/frontend/apps/impress/src/features/docs/docs-grid/components/SimpleDocItem.tsx b/src/frontend/apps/impress/src/features/docs/docs-grid/components/SimpleDocItem.tsx index 87c9387c9..3cc8108bc 100644 --- a/src/frontend/apps/impress/src/features/docs/docs-grid/components/SimpleDocItem.tsx +++ b/src/frontend/apps/impress/src/features/docs/docs-grid/components/SimpleDocItem.tsx @@ -34,7 +34,7 @@ export const SimpleDocItem = ({ const { t } = useTranslation(); const { spacingsTokens } = useCunninghamTheme(); const { isDesktop } = useResponsiveStore(); - const { untitledDocument } = useTrans(); + const { untitledDocument } = useTrans(doc); return ( Date: Wed, 2 Apr 2025 10:26:45 +0200 Subject: [PATCH 17/26] test-feature --- .github/workflows/docker-hub.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/docker-hub.yml b/.github/workflows/docker-hub.yml index 84b23c7e0..da903bed5 100644 --- a/.github/workflows/docker-hub.yml +++ b/.github/workflows/docker-hub.yml @@ -6,6 +6,7 @@ on: push: branches: - 'main' + - 'feature/doc-dnd' tags: - 'v*' pull_request: From bfa06af2cb9fec26dfbcf563664792f5a4eadc56 Mon Sep 17 00:00:00 2001 From: Anthony LC Date: Thu, 10 Apr 2025 16:29:34 +0200 Subject: [PATCH 18/26] save --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 03897a5a1..9b8250caa 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -22,7 +22,7 @@ services: - "1081:1080" minio: - user: ${DOCKER_USER:-1000} + # user: ${DOCKER_USER:-1000} image: minio/minio environment: - MINIO_ROOT_USER=impress From 2ee842c3cf77c88811849d81e251c2008be58362 Mon Sep 17 00:00:00 2001 From: Anthony LC Date: Wed, 23 Apr 2025 14:28:05 +0200 Subject: [PATCH 19/26] =?UTF-8?q?fixup!=20=F0=9F=90=9B(back)=20keep=20info?= =?UTF-8?q?=20if=20document=20has=20deleted=20children?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...c_and_more.py => 0022_remove_document_is_public_and_more.py} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename src/backend/core/migrations/{0021_remove_document_is_public_and_more.py => 0022_remove_document_is_public_and_more.py} (80%) diff --git a/src/backend/core/migrations/0021_remove_document_is_public_and_more.py b/src/backend/core/migrations/0022_remove_document_is_public_and_more.py similarity index 80% rename from src/backend/core/migrations/0021_remove_document_is_public_and_more.py rename to src/backend/core/migrations/0022_remove_document_is_public_and_more.py index 97eaa4681..cfce2c5ed 100644 --- a/src/backend/core/migrations/0021_remove_document_is_public_and_more.py +++ b/src/backend/core/migrations/0022_remove_document_is_public_and_more.py @@ -5,7 +5,7 @@ class Migration(migrations.Migration): dependencies = [ - ("core", "0020_remove_is_public_add_field_attachments_and_duplicated_from"), + ("core", "0021_activate_unaccent_extension"), ] operations = [ From eaf5e22ca5edd5a51eff1fc207acfe855f22031a Mon Sep 17 00:00:00 2001 From: Anthony LC Date: Wed, 23 Apr 2025 14:32:26 +0200 Subject: [PATCH 20/26] =?UTF-8?q?fixup!=20=E2=9C=A8(frontend)=20added=20su?= =?UTF-8?q?bpage=20management=20and=20document=20tree=20features?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/features/docs/doc-header/components/DocToolBox.tsx | 2 +- .../src/features/docs/doc-tree/components/DocSubPageItem.tsx | 3 +-- .../impress/src/features/docs/doc-tree/components/DocTree.tsx | 3 +-- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/frontend/apps/impress/src/features/docs/doc-header/components/DocToolBox.tsx b/src/frontend/apps/impress/src/features/docs/doc-header/components/DocToolBox.tsx index a079c280c..e967cfbfc 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-header/components/DocToolBox.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-header/components/DocToolBox.tsx @@ -193,7 +193,7 @@ export const DocToolBox = ({ doc }: DocToolBoxProps) => { }} size={isSmallMobile ? 'small' : 'medium'} style={{ - color: colors['primary-800'], + color: colorsTokens['primary-800'], }} > {t('Share')} diff --git a/src/frontend/apps/impress/src/features/docs/doc-tree/components/DocSubPageItem.tsx b/src/frontend/apps/impress/src/features/docs/doc-tree/components/DocSubPageItem.tsx index 8cb305fc3..292c2f4f7 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-tree/components/DocSubPageItem.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-tree/components/DocSubPageItem.tsx @@ -39,7 +39,6 @@ export const DocSubPageItem = (props: Props) => { const { spacingsTokens } = useCunninghamTheme(); const [isHover, setIsHover] = useState(false); - const spacing = spacingsTokens(); const router = useRouter(); const { togglePanel } = useLeftPanelStore(); @@ -115,7 +114,7 @@ export const DocSubPageItem = (props: Props) => { data-testid={`doc-sub-page-item-${props.node.data.value.id}`} $width="100%" $direction="row" - $gap={spacing['xs']} + $gap={spacingsTokens['xs']} role="button" tabIndex={0} $align="center" diff --git a/src/frontend/apps/impress/src/features/docs/doc-tree/components/DocTree.tsx b/src/frontend/apps/impress/src/features/docs/doc-tree/components/DocTree.tsx index 32bea3e54..b26212518 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-tree/components/DocTree.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-tree/components/DocTree.tsx @@ -25,7 +25,6 @@ type DocTreeProps = { }; export const DocTree = ({ initialTargetId }: DocTreeProps) => { const { spacingsTokens } = useCunninghamTheme(); - const spacing = spacingsTokens(); const treeContext = useTreeContext(); const { currentDoc } = useDocStore(); const router = useRouter(); @@ -138,7 +137,7 @@ export const DocTree = ({ initialTargetId }: DocTreeProps) => { Date: Wed, 23 Apr 2025 17:18:57 +0200 Subject: [PATCH 21/26] =?UTF-8?q?=F0=9F=9A=9A(frontend)=20reduce=20feature?= =?UTF-8?q?s=20coupling?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move some components and assets to `doc-management` to reduce coupling between features: - SimpleDocItem from `doc-grid` to `doc-management` - useCreateChildDoc from `doc-tree` to `doc-management` - isOwnerOrAdmin from `doc-tree` to `doc-management` --- .../features/docs/doc-management/api/index.ts | 1 + .../api/useCreateChildDoc.tsx} | 22 ++++++------- .../assets/pinned-document.svg | 0 .../assets/simple-document.svg | 0 .../components/SimpleDocItem.tsx | 0 .../docs/doc-management/components/index.ts | 1 + .../src/features/docs/doc-management/utils.ts | 6 ++++ .../doc-search/components/DocSearchItem.tsx | 3 +- .../docs/doc-tree/components/DocTree.tsx | 9 ++++-- .../components/DocTreeItemActions.tsx | 14 ++++++--- .../src/features/docs/doc-tree/utils.ts | 8 +---- .../docs-grid/components/DocsGridItem.tsx | 5 +-- .../docs/docs-grid/components/index.ts | 1 - .../components/LeftPanelFavoriteItem.tsx | 4 +-- .../components/LeftPanelHeaderButton.tsx | 31 +++++++++++-------- 15 files changed, 60 insertions(+), 45 deletions(-) rename src/frontend/apps/impress/src/features/docs/{doc-tree/api/useCreateChildren.tsx => doc-management/api/useCreateChildDoc.tsx} (57%) rename src/frontend/apps/impress/src/features/docs/{docs-grid => doc-management}/assets/pinned-document.svg (100%) rename src/frontend/apps/impress/src/features/docs/{docs-grid => doc-management}/assets/simple-document.svg (100%) rename src/frontend/apps/impress/src/features/docs/{docs-grid => doc-management}/components/SimpleDocItem.tsx (100%) diff --git a/src/frontend/apps/impress/src/features/docs/doc-management/api/index.ts b/src/frontend/apps/impress/src/features/docs/doc-management/api/index.ts index df4123600..d19a0013f 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-management/api/index.ts +++ b/src/frontend/apps/impress/src/features/docs/doc-management/api/index.ts @@ -1,3 +1,4 @@ +export * from './useCreateChildDoc'; export * from './useCreateDoc'; export * from './useCreateFavoriteDoc'; export * from './useDeleteFavoriteDoc'; diff --git a/src/frontend/apps/impress/src/features/docs/doc-tree/api/useCreateChildren.tsx b/src/frontend/apps/impress/src/features/docs/doc-management/api/useCreateChildDoc.tsx similarity index 57% rename from src/frontend/apps/impress/src/features/docs/doc-tree/api/useCreateChildren.tsx rename to src/frontend/apps/impress/src/features/docs/doc-management/api/useCreateChildDoc.tsx index b9f774a81..dd2037830 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-tree/api/useCreateChildren.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-management/api/useCreateChildDoc.tsx @@ -2,16 +2,16 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; import { APIError, errorCauses, fetchAPI } from '@/api'; -import { Doc, KEY_LIST_DOC } from '../../doc-management'; +import { Doc, KEY_LIST_DOC } from '..'; -export type CreateDocParam = Pick & { +export type CreateChildDocParam = Pick & { parentId: string; }; -export const createDocChildren = async ({ +export const createChildDoc = async ({ title, parentId, -}: CreateDocParam): Promise => { +}: CreateChildDocParam): Promise => { const response = await fetchAPI(`documents/${parentId}/children/`, { method: 'POST', body: JSON.stringify({ @@ -26,19 +26,19 @@ export const createDocChildren = async ({ return response.json() as Promise; }; -interface CreateDocProps { - onSuccess: (data: Doc) => void; +interface UseCreateChildDocProps { + onSuccess: (doc: Doc) => void; } -export function useCreateChildrenDoc({ onSuccess }: CreateDocProps) { +export function useCreateChildDoc({ onSuccess }: UseCreateChildDocProps) { const queryClient = useQueryClient(); - return useMutation({ - mutationFn: createDocChildren, - onSuccess: (data) => { + return useMutation({ + mutationFn: createChildDoc, + onSuccess: (doc) => { void queryClient.resetQueries({ queryKey: [KEY_LIST_DOC], }); - onSuccess(data); + onSuccess(doc); }, }); } diff --git a/src/frontend/apps/impress/src/features/docs/docs-grid/assets/pinned-document.svg b/src/frontend/apps/impress/src/features/docs/doc-management/assets/pinned-document.svg similarity index 100% rename from src/frontend/apps/impress/src/features/docs/docs-grid/assets/pinned-document.svg rename to src/frontend/apps/impress/src/features/docs/doc-management/assets/pinned-document.svg diff --git a/src/frontend/apps/impress/src/features/docs/docs-grid/assets/simple-document.svg b/src/frontend/apps/impress/src/features/docs/doc-management/assets/simple-document.svg similarity index 100% rename from src/frontend/apps/impress/src/features/docs/docs-grid/assets/simple-document.svg rename to src/frontend/apps/impress/src/features/docs/doc-management/assets/simple-document.svg diff --git a/src/frontend/apps/impress/src/features/docs/docs-grid/components/SimpleDocItem.tsx b/src/frontend/apps/impress/src/features/docs/doc-management/components/SimpleDocItem.tsx similarity index 100% rename from src/frontend/apps/impress/src/features/docs/docs-grid/components/SimpleDocItem.tsx rename to src/frontend/apps/impress/src/features/docs/doc-management/components/SimpleDocItem.tsx diff --git a/src/frontend/apps/impress/src/features/docs/doc-management/components/index.ts b/src/frontend/apps/impress/src/features/docs/doc-management/components/index.ts index 639460cd1..50da09e9f 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-management/components/index.ts +++ b/src/frontend/apps/impress/src/features/docs/doc-management/components/index.ts @@ -1 +1,2 @@ export * from './ModalRemoveDoc'; +export * from './SimpleDocItem'; diff --git a/src/frontend/apps/impress/src/features/docs/doc-management/utils.ts b/src/frontend/apps/impress/src/features/docs/doc-management/utils.ts index 2c229128e..7fe304fc2 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-management/utils.ts +++ b/src/frontend/apps/impress/src/features/docs/doc-management/utils.ts @@ -22,3 +22,9 @@ export const base64ToYDoc = (base64: string) => { export const base64ToBlocknoteXmlFragment = (base64: string) => { return base64ToYDoc(base64).getXmlFragment('document-store'); }; + +export const isOwnerOrAdmin = (doc: Doc): boolean => { + return doc.user_roles.some( + (role) => role === Role.OWNER || role === Role.ADMIN, + ); +}; diff --git a/src/frontend/apps/impress/src/features/docs/doc-search/components/DocSearchItem.tsx b/src/frontend/apps/impress/src/features/docs/doc-search/components/DocSearchItem.tsx index 7d7414076..59b9b47b5 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-search/components/DocSearchItem.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-search/components/DocSearchItem.tsx @@ -1,7 +1,6 @@ import { Box, Icon } from '@/components'; import { QuickSearchItemContent } from '@/components/quick-search/'; -import { Doc } from '@/docs/doc-management'; -import { SimpleDocItem } from '@/docs/docs-grid/'; +import { Doc, SimpleDocItem } from '@/docs/doc-management'; import { useResponsiveStore } from '@/stores'; type DocSearchItemProps = { diff --git a/src/frontend/apps/impress/src/features/docs/doc-tree/components/DocTree.tsx b/src/frontend/apps/impress/src/features/docs/doc-tree/components/DocTree.tsx index b26212518..8118d54af 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-tree/components/DocTree.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-tree/components/DocTree.tsx @@ -10,9 +10,14 @@ import { css } from 'styled-components'; import { Box, StyledLink } from '@/components'; import { useCunninghamTheme } from '@/cunningham'; +import { + Doc, + KEY_SUB_PAGE, + SimpleDocItem, + useDoc, + useDocStore, +} from '@/docs/doc-management'; -import { Doc, KEY_SUB_PAGE, useDoc, useDocStore } from '../../doc-management'; -import { SimpleDocItem } from '../../docs-grid'; import { useDocTree } from '../api/useDocTree'; import { useMoveDoc } from '../api/useMove'; import { canDrag, canDrop, serializeDocToSubPage } from '../utils'; diff --git a/src/frontend/apps/impress/src/features/docs/doc-tree/components/DocTreeItemActions.tsx b/src/frontend/apps/impress/src/features/docs/doc-tree/components/DocTreeItemActions.tsx index ef8d5f19a..d8c1e3840 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-tree/components/DocTreeItemActions.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-tree/components/DocTreeItemActions.tsx @@ -10,14 +10,18 @@ import { useTranslation } from 'react-i18next'; import { css } from 'styled-components'; import { Box, BoxButton, Icon } from '@/components'; +import { + Doc, + ModalRemoveDoc, + isOwnerOrAdmin, + useCopyDocLink, + useCreateChildDoc, +} from '@/docs/doc-management'; import { useLeftPanelStore } from '@/features/left-panel'; -import { Doc, ModalRemoveDoc, useCopyDocLink } from '../../doc-management'; -import { useCreateChildrenDoc } from '../api/useCreateChildren'; import { useDetachDoc } from '../api/useDetach'; import MoveDocIcon from '../assets/doc-extract-bold.svg'; import { useTreeUtils } from '../hooks'; -import { isOwnerOrAdmin } from '../utils'; type DocTreeItemActionsProps = { doc: Doc; @@ -92,7 +96,7 @@ export const DocTreeItemActions = ({ }, ]; - const { mutate: createChildrenDoc } = useCreateChildrenDoc({ + const { mutate: createChildDoc } = useCreateChildDoc({ onSuccess: (doc) => { onCreateSuccess?.(doc); togglePanel(); @@ -144,7 +148,7 @@ export const DocTreeItemActions = ({ e.stopPropagation(); e.preventDefault(); - createChildrenDoc({ + createChildDoc({ parentId: doc.id, }); }} diff --git a/src/frontend/apps/impress/src/features/docs/doc-tree/utils.ts b/src/frontend/apps/impress/src/features/docs/doc-tree/utils.ts index f632c2cad..98efb6f2f 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-tree/utils.ts +++ b/src/frontend/apps/impress/src/features/docs/doc-tree/utils.ts @@ -1,6 +1,6 @@ import { TreeViewDataType } from '@gouvfr-lasuite/ui-kit'; -import { Doc, Role } from '../doc-management'; +import { Doc, isOwnerOrAdmin } from '../doc-management'; export const serializeDocToSubPage = (doc: Doc): Doc => { return { ...doc, childrenCount: doc.numchild }; @@ -14,12 +14,6 @@ export const subPageToTree = (children: Doc[]): TreeViewDataType[] => { return children; }; -export const isOwnerOrAdmin = (doc: Doc): boolean => { - return doc.user_roles.some( - (role) => role === Role.OWNER || role === Role.ADMIN, - ); -}; - export const canDrag = (doc: Doc): boolean => { return isOwnerOrAdmin(doc); }; diff --git a/src/frontend/apps/impress/src/features/docs/docs-grid/components/DocsGridItem.tsx b/src/frontend/apps/impress/src/features/docs/docs-grid/components/DocsGridItem.tsx index ada5e2c29..ea4e557c7 100644 --- a/src/frontend/apps/impress/src/features/docs/docs-grid/components/DocsGridItem.tsx +++ b/src/frontend/apps/impress/src/features/docs/docs-grid/components/DocsGridItem.tsx @@ -5,7 +5,7 @@ import { css } from 'styled-components'; import { Box, Icon, StyledLink, Text } from '@/components'; import { useCunninghamTheme } from '@/cunningham'; -import { Doc, LinkReach } from '@/docs/doc-management'; +import { Doc, LinkReach, SimpleDocItem } from '@/docs/doc-management'; import { DocShareModal } from '@/docs/doc-share'; import { useResponsiveStore } from '@/stores'; @@ -13,11 +13,12 @@ import { useResponsiveDocGrid } from '../hooks/useResponsiveDocGrid'; import { DocsGridActions } from './DocsGridActions'; import { DocsGridItemSharedButton } from './DocsGridItemSharedButton'; -import { SimpleDocItem } from './SimpleDocItem'; + type DocsGridItemProps = { doc: Doc; dragMode?: boolean; }; + export const DocsGridItem = ({ doc, dragMode = false }: DocsGridItemProps) => { const { t } = useTranslation(); const { isDesktop } = useResponsiveStore(); diff --git a/src/frontend/apps/impress/src/features/docs/docs-grid/components/index.ts b/src/frontend/apps/impress/src/features/docs/docs-grid/components/index.ts index a017747f9..540d636cc 100644 --- a/src/frontend/apps/impress/src/features/docs/docs-grid/components/index.ts +++ b/src/frontend/apps/impress/src/features/docs/docs-grid/components/index.ts @@ -1,4 +1,3 @@ export * from './DocsGrid'; export * from './DocsGridActions'; -export * from './SimpleDocItem'; export * from './DocsGridLoader'; diff --git a/src/frontend/apps/impress/src/features/left-panel/components/LeftPanelFavoriteItem.tsx b/src/frontend/apps/impress/src/features/left-panel/components/LeftPanelFavoriteItem.tsx index 32c74d6e7..dc424eb92 100644 --- a/src/frontend/apps/impress/src/features/left-panel/components/LeftPanelFavoriteItem.tsx +++ b/src/frontend/apps/impress/src/features/left-panel/components/LeftPanelFavoriteItem.tsx @@ -3,9 +3,9 @@ import { css } from 'styled-components'; import { Box, StyledLink } from '@/components'; import { useCunninghamTheme } from '@/cunningham'; -import { Doc } from '@/docs/doc-management'; +import { Doc, SimpleDocItem } from '@/docs/doc-management'; import { DocShareModal } from '@/docs/doc-share'; -import { DocsGridActions, SimpleDocItem } from '@/docs/docs-grid'; +import { DocsGridActions } from '@/docs/docs-grid'; import { useResponsiveStore } from '@/stores'; type LeftPanelFavoriteItemProps = { diff --git a/src/frontend/apps/impress/src/features/left-panel/components/LeftPanelHeaderButton.tsx b/src/frontend/apps/impress/src/features/left-panel/components/LeftPanelHeaderButton.tsx index 7589f9554..784ffcdbe 100644 --- a/src/frontend/apps/impress/src/features/left-panel/components/LeftPanelHeaderButton.tsx +++ b/src/frontend/apps/impress/src/features/left-panel/components/LeftPanelHeaderButton.tsx @@ -3,9 +3,13 @@ import { Button } from '@openfun/cunningham-react'; import { useRouter } from 'next/router'; import { useTranslation } from 'react-i18next'; -import { Doc, useCreateDoc, useDocStore } from '@/features/docs'; -import { useCreateChildrenDoc } from '@/features/docs/doc-tree/api/useCreateChildren'; -import { isOwnerOrAdmin } from '@/features/docs/doc-tree/utils'; +import { + Doc, + isOwnerOrAdmin, + useCreateChildDoc, + useCreateDoc, + useDocStore, +} from '@/docs/doc-management'; import { useLeftPanelStore } from '../stores'; @@ -44,7 +48,7 @@ export const LeftPanelHeaderDocButton = () => { const { togglePanel } = useLeftPanelStore(); const treeContext = useTreeContext(); const tree = treeContext?.treeData; - const { mutate: createChildrenDoc } = useCreateChildrenDoc({ + const { mutate: createChildDoc } = useCreateChildDoc({ onSuccess: (doc) => { tree?.addRootNode(doc); tree?.selectNodeById(doc.id); @@ -54,19 +58,20 @@ export const LeftPanelHeaderDocButton = () => { }); const onCreateDoc = () => { - if (treeContext && treeContext.root) { - createChildrenDoc({ - parentId: treeContext.root.id, - }); + if (!treeContext?.root) { + return; } + + createChildDoc({ + parentId: treeContext.root.id, + }); }; + const disabled = + (currentDoc && !isOwnerOrAdmin(currentDoc)) || !treeContext?.root; + return ( - ); From 177a07cec4d65d18fde116948aed04994f0d73f7 Mon Sep 17 00:00:00 2001 From: Anthony LC Date: Wed, 23 Apr 2025 17:40:27 +0200 Subject: [PATCH 22/26] =?UTF-8?q?=E2=9C=A8(frontend)=20create=20page=20fro?= =?UTF-8?q?m=20slash=20menu?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We are now able to create a new page from the slash menu. --- .../__tests__/app-impress/doc-create.spec.ts | 18 ++++++ .../docs/doc-editor/assets/doc-plus.svg | 30 ++++++++++ .../components/BlockNoteSuggestionMenu.tsx | 27 +++++++-- .../InterlinkingSearchInlineContent.tsx | 57 +++++++++++++++++++ .../Interlinking/index.ts | 1 + .../components/custom-inline-content/index.ts | 1 + 6 files changed, 130 insertions(+), 4 deletions(-) create mode 100644 src/frontend/apps/impress/src/features/docs/doc-editor/assets/doc-plus.svg create mode 100644 src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/InterlinkingSearchInlineContent.tsx create mode 100644 src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/index.ts create mode 100644 src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/index.ts diff --git a/src/frontend/apps/e2e/__tests__/app-impress/doc-create.spec.ts b/src/frontend/apps/e2e/__tests__/app-impress/doc-create.spec.ts index cf1b90370..97507778e 100644 --- a/src/frontend/apps/e2e/__tests__/app-impress/doc-create.spec.ts +++ b/src/frontend/apps/e2e/__tests__/app-impress/doc-create.spec.ts @@ -29,6 +29,24 @@ test.describe('Doc Create', () => { await expect(page.getByTestId('grid-loader')).toBeHidden(); await expect(docsGrid.getByText(docTitle)).toBeVisible(); }); + + test('it creates a sub doc from slash menu editor', async ({ + page, + browserName, + }) => { + const [title] = await createDoc(page, 'my-new-slash-doc', browserName, 1); + + await verifyDocName(page, title); + + await page.locator('.bn-block-outer').last().fill('/'); + await page.getByText('Add a new page').click(); + + const input = page.getByRole('textbox', { name: 'doc title input' }); + await expect(input).toHaveText(''); + await expect( + page.locator('.c__tree-view--row-content').getByText('Untitled page'), + ).toBeVisible(); + }); }); test.describe('Doc Create: Not loggued', () => { diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/assets/doc-plus.svg b/src/frontend/apps/impress/src/features/docs/doc-editor/assets/doc-plus.svg new file mode 100644 index 000000000..219f8f170 --- /dev/null +++ b/src/frontend/apps/impress/src/features/docs/doc-editor/assets/doc-plus.svg @@ -0,0 +1,30 @@ + + + + + + + diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteSuggestionMenu.tsx b/src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteSuggestionMenu.tsx index d15e1b5ed..a3fcbc161 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteSuggestionMenu.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteSuggestionMenu.tsx @@ -9,24 +9,43 @@ import { import React, { useMemo } from 'react'; import { useTranslation } from 'react-i18next'; -import { DocsBlockSchema } from '../types'; +import { + DocsBlockSchema, + DocsInlineContentSchema, + DocsStyleSchema, +} from '../types'; import { getDividerReactSlashMenuItems, getQuoteReactSlashMenuItems, } from './custom-blocks'; +import { useGetInterlinkingMenuItems } from './custom-inline-content'; export const BlockNoteSuggestionMenu = () => { - const editor = useBlockNoteEditor(); + const editor = useBlockNoteEditor< + DocsBlockSchema, + DocsInlineContentSchema, + DocsStyleSchema + >(); const { t } = useTranslation(); const basicBlocksName = useDictionary().slash_menu.page_break.group; + const getInterlinkingMenuItems = useGetInterlinkingMenuItems(); const getSlashMenuItems = useMemo(() => { + // We insert it after the "Code Block" item to have the interlinking block displayed after the basic blocks + const defaultMenu = getDefaultReactSlashMenuItems(editor); + const index = defaultMenu.findIndex((item) => item.title === 'Code Block'); + const newSlashMenuItems = [ + ...defaultMenu.slice(0, index + 1), + ...getInterlinkingMenuItems(t), + ...defaultMenu.slice(index + 1), + ]; + return async (query: string) => Promise.resolve( filterSuggestionItems( combineByGroup( - getDefaultReactSlashMenuItems(editor), + newSlashMenuItems, getPageBreakReactSlashMenuItems(editor), getQuoteReactSlashMenuItems(editor, t, basicBlocksName), getDividerReactSlashMenuItems(editor, t, basicBlocksName), @@ -34,7 +53,7 @@ export const BlockNoteSuggestionMenu = () => { query, ), ); - }, [basicBlocksName, editor, t]); + }, [basicBlocksName, editor, getInterlinkingMenuItems, t]); return ( , + group: string, + createPage: () => void, +) => [ + { + title: t('New page'), + onItemClick: createPage, + aliases: ['new page'], + group, + icon: , + subtext: t('Add a new page'), + }, +]; + +export const useGetInterlinkingMenuItems = () => { + const treeContext = useTreeContext(); + const router = useRouter(); + const { currentDoc } = useDocStore(); + + const { mutate: createChildDoc } = useCreateChildDoc({ + onSuccess: (createdDoc) => { + const newDoc = { + ...createdDoc, + children: [], + childrenCount: 0, + parentId: currentDoc?.id ?? undefined, + }; + treeContext?.treeData.addChild(currentDoc?.id || null, newDoc); + + router.push(`/docs/${newDoc.id}`); + treeContext?.treeData.setSelectedNode(createdDoc); + }, + }); + + return useCallback( + (t: TFunction<'translation', undefined>) => + getInterlinkingMenuItems( + t, + t('Links'), + () => + currentDoc?.id && + createChildDoc({ + parentId: currentDoc.id, + }), + ), + [createChildDoc, currentDoc?.id], + ); +}; diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/index.ts b/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/index.ts new file mode 100644 index 000000000..b1a3b4487 --- /dev/null +++ b/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/index.ts @@ -0,0 +1 @@ +export * from './InterlinkingSearchInlineContent'; diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/index.ts b/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/index.ts new file mode 100644 index 000000000..fa505a9e9 --- /dev/null +++ b/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/index.ts @@ -0,0 +1 @@ +export * from './Interlinking'; From 17a4573566eb5983d345c0faec414b4efbab21a4 Mon Sep 17 00:00:00 2001 From: Anthony LC Date: Wed, 23 Apr 2025 18:41:11 +0200 Subject: [PATCH 23/26] =?UTF-8?q?=E2=9C=A8(frontend)=20interlinking=20cust?= =?UTF-8?q?om=20inline=20content?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We want to be able to interlink documents in the editor. We created a custom inline content that allows users to interlink documents. --- .../__tests__/app-impress/doc-editor.spec.ts | 49 ++++ .../apps/impress/src/components/Box.tsx | 7 +- .../impress/src/components/DropdownMenu.tsx | 4 +- .../apps/impress/src/components/index.ts | 1 + .../docs/doc-editor/assets/doc-link.svg | 14 ++ .../docs/doc-editor/assets/doc-selected.svg | 6 + .../doc-editor/components/BlockNoteEditor.tsx | 10 + .../components/BlockNoteSuggestionMenu.tsx | 2 +- .../InterlinkingLinkInlineContent.tsx | 60 +++++ .../InterlinkingSearchInlineContent.tsx | 49 +++- .../Interlinking/SearchPage.tsx | 219 ++++++++++++++++++ .../Interlinking/index.ts | 1 + .../doc-search/components/DocSearchModal.tsx | 2 + .../components/DocSearchSubPageContent.tsx | 7 +- .../docs/doc-search/components/index.ts | 1 + 15 files changed, 422 insertions(+), 10 deletions(-) create mode 100644 src/frontend/apps/impress/src/features/docs/doc-editor/assets/doc-link.svg create mode 100644 src/frontend/apps/impress/src/features/docs/doc-editor/assets/doc-selected.svg create mode 100644 src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/InterlinkingLinkInlineContent.tsx create mode 100644 src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/SearchPage.tsx diff --git a/src/frontend/apps/e2e/__tests__/app-impress/doc-editor.spec.ts b/src/frontend/apps/e2e/__tests__/app-impress/doc-editor.spec.ts index 643ce9900..00b73eaff 100644 --- a/src/frontend/apps/e2e/__tests__/app-impress/doc-editor.spec.ts +++ b/src/frontend/apps/e2e/__tests__/app-impress/doc-editor.spec.ts @@ -451,4 +451,53 @@ test.describe('Doc Editor', () => { const svgBuffer = await cs.toBuffer(await download.createReadStream()); expect(svgBuffer.toString()).toContain('Hello svg'); }); + + test('it checks interlink feature', async ({ page, browserName }) => { + const [randomDoc] = await createDoc(page, 'doc-interlink', browserName, 1); + + await verifyDocName(page, randomDoc); + + const [docChild1] = await createDoc( + page, + 'doc-interlink-child-1', + browserName, + 1, + true, + ); + + await verifyDocName(page, docChild1); + + const [docChild2] = await createDoc( + page, + 'doc-interlink-child-2', + browserName, + 1, + true, + ); + + await verifyDocName(page, docChild2); + + await page.locator('.bn-block-outer').last().fill('/'); + await page.getByText('Link to a page').first().click(); + + await page + .locator( + "span[data-inline-content-type='interlinkingSearchInline'] input", + ) + .fill('interlink-child-1'); + + await page + .locator('.quick-search-container') + .getByText('interlink-child-1') + .click(); + + const interlink = page.getByRole('link', { + name: 'child-1', + }); + + await expect(interlink).toBeVisible(); + await interlink.click(); + + await verifyDocName(page, docChild1); + }); }); diff --git a/src/frontend/apps/impress/src/components/Box.tsx b/src/frontend/apps/impress/src/components/Box.tsx index 84e320571..fbbabad8e 100644 --- a/src/frontend/apps/impress/src/components/Box.tsx +++ b/src/frontend/apps/impress/src/components/Box.tsx @@ -44,13 +44,12 @@ export interface BoxProps { export type BoxType = ComponentPropsWithRef; export const Box = styled('div')` - display: flex; - flex-direction: column; ${({ $align }) => $align && `align-items: ${$align};`} ${({ $background }) => $background && `background: ${$background};`} ${({ $color }) => $color && `color: ${$color};`} - ${({ $direction }) => $direction && `flex-direction: ${$direction};`} - ${({ $display }) => $display && `display: ${$display};`} + ${({ $direction }) => `flex-direction: ${$direction || 'column'};`} + ${({ $display, as }) => + `display: ${$display || as?.match('span|input') ? 'inline-flex' : 'flex'};`} ${({ $flex }) => $flex && `flex: ${$flex};`} ${({ $gap }) => $gap && `gap: ${$gap};`} ${({ $height }) => $height && `height: ${$height};`} diff --git a/src/frontend/apps/impress/src/components/DropdownMenu.tsx b/src/frontend/apps/impress/src/components/DropdownMenu.tsx index 5fc3d64be..bb0ede411 100644 --- a/src/frontend/apps/impress/src/components/DropdownMenu.tsx +++ b/src/frontend/apps/impress/src/components/DropdownMenu.tsx @@ -23,6 +23,7 @@ export type DropdownMenuProps = { arrowCss?: BoxProps['$css']; buttonCss?: BoxProps['$css']; disabled?: boolean; + opened?: boolean; topMessage?: string; selectedValues?: string[]; afterOpenChange?: (isOpen: boolean) => void; @@ -36,12 +37,13 @@ export const DropdownMenu = ({ arrowCss, buttonCss, label, + opened, topMessage, afterOpenChange, selectedValues, }: PropsWithChildren) => { const { spacingsTokens, colorsTokens } = useCunninghamTheme(); - const [isOpen, setIsOpen] = useState(false); + const [isOpen, setIsOpen] = useState(opened ?? false); const blockButtonRef = useRef(null); const onOpenChange = (isOpen: boolean) => { diff --git a/src/frontend/apps/impress/src/components/index.ts b/src/frontend/apps/impress/src/components/index.ts index 205b72246..b11539ea2 100644 --- a/src/frontend/apps/impress/src/components/index.ts +++ b/src/frontend/apps/impress/src/components/index.ts @@ -3,6 +3,7 @@ export * from './BoxButton'; export * from './Card'; export * from './DropButton'; export * from './DropdownMenu'; +export * from './quick-search'; export * from './Icon'; export * from './InfiniteScroll'; export * from './Link'; diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/assets/doc-link.svg b/src/frontend/apps/impress/src/features/docs/doc-editor/assets/doc-link.svg new file mode 100644 index 000000000..bcb7b8815 --- /dev/null +++ b/src/frontend/apps/impress/src/features/docs/doc-editor/assets/doc-link.svg @@ -0,0 +1,14 @@ + + + diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/assets/doc-selected.svg b/src/frontend/apps/impress/src/features/docs/doc-editor/assets/doc-selected.svg new file mode 100644 index 000000000..f36a74afb --- /dev/null +++ b/src/frontend/apps/impress/src/features/docs/doc-editor/assets/doc-selected.svg @@ -0,0 +1,6 @@ + + + diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteEditor.tsx b/src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteEditor.tsx index e39bbf6fe..7c0a70c55 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteEditor.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteEditor.tsx @@ -2,6 +2,7 @@ import { BlockNoteSchema, Dictionary, defaultBlockSpecs, + defaultInlineContentSpecs, locales, withPageBreak, } from '@blocknote/core'; @@ -28,6 +29,10 @@ import { randomColor } from '../utils'; import { BlockNoteSuggestionMenu } from './BlockNoteSuggestionMenu'; import { BlockNoteToolbar } from './BlockNoteToolBar/BlockNoteToolbar'; import { DividerBlock, QuoteBlock } from './custom-blocks'; +import { + InterlinkingLinkInlineContent, + InterlinkingSearchInlineContent, +} from './custom-inline-content'; export const blockNoteSchema = withPageBreak( BlockNoteSchema.create({ @@ -36,6 +41,11 @@ export const blockNoteSchema = withPageBreak( divider: DividerBlock, quote: QuoteBlock, }, + inlineContentSpecs: { + ...defaultInlineContentSpecs, + interlinkingSearchInline: InterlinkingSearchInlineContent, + interlinkingLinkInline: InterlinkingLinkInlineContent, + }, }), ); diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteSuggestionMenu.tsx b/src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteSuggestionMenu.tsx index a3fcbc161..67e7a960b 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteSuggestionMenu.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteSuggestionMenu.tsx @@ -37,7 +37,7 @@ export const BlockNoteSuggestionMenu = () => { const index = defaultMenu.findIndex((item) => item.title === 'Code Block'); const newSlashMenuItems = [ ...defaultMenu.slice(0, index + 1), - ...getInterlinkingMenuItems(t), + ...getInterlinkingMenuItems(editor, t), ...defaultMenu.slice(index + 1), ]; diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/InterlinkingLinkInlineContent.tsx b/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/InterlinkingLinkInlineContent.tsx new file mode 100644 index 000000000..939ee219b --- /dev/null +++ b/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/InterlinkingLinkInlineContent.tsx @@ -0,0 +1,60 @@ +/* eslint-disable react-hooks/rules-of-hooks */ +import { createReactInlineContentSpec } from '@blocknote/react'; +import { css } from 'styled-components'; + +import { StyledLink, Text } from '@/components'; +import { useCunninghamTheme } from '@/cunningham'; +import SelectedPageIcon from '@/docs/doc-editor/assets/doc-selected.svg'; + +export const InterlinkingLinkInlineContent = createReactInlineContentSpec( + { + type: 'interlinkingLinkInline', + propSchema: { + url: { + default: '', + }, + title: { + default: '', + }, + }, + content: 'none', + }, + { + render: (props) => { + return ; + }, + }, +); + +interface LinkSelectedProps { + url: string; + title: string; +} +const LinkSelected = ({ url, title }: LinkSelectedProps) => { + const { colorsTokens } = useCunninghamTheme(); + + return ( + + + + {title} + + + ); +}; diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/InterlinkingSearchInlineContent.tsx b/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/InterlinkingSearchInlineContent.tsx index e8c0ca3b5..972dd63a4 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/InterlinkingSearchInlineContent.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/InterlinkingSearchInlineContent.tsx @@ -1,16 +1,62 @@ +/* eslint-disable react-hooks/rules-of-hooks */ +import { createReactInlineContentSpec } from '@blocknote/react'; import { useTreeContext } from '@gouvfr-lasuite/ui-kit'; import { TFunction } from 'i18next'; import { useRouter } from 'next/navigation'; import { useCallback } from 'react'; +import { DocsBlockNoteEditor } from '@/docs/doc-editor'; +import LinkPageIcon from '@/docs/doc-editor/assets/doc-link.svg'; import AddPageIcon from '@/docs/doc-editor/assets/doc-plus.svg'; import { Doc, useCreateChildDoc, useDocStore } from '@/docs/doc-management'; +import { SearchPage } from './SearchPage'; + +export const InterlinkingSearchInlineContent = createReactInlineContentSpec( + { + type: 'interlinkingSearchInline', + propSchema: { + disabled: { + default: false, + values: [true, false], + }, + }, + content: 'styled', + }, + { + render: (props) => { + if (props.inlineContent.props.disabled) { + return null; + } + + return ; + }, + }, +); + export const getInterlinkingMenuItems = ( + editor: DocsBlockNoteEditor, t: TFunction<'translation', undefined>, group: string, createPage: () => void, ) => [ + { + title: t('Link to a page'), + onItemClick: () => { + editor.insertInlineContent([ + { + type: 'interlinkingSearchInline', + props: { + disabled: false, + }, + }, + ]); + }, + aliases: ['interlinking', 'link', 'anchor', 'a'], + group, + icon: , + subtext: t('Link to a page'), + }, { title: t('New page'), onItemClick: createPage, @@ -42,8 +88,9 @@ export const useGetInterlinkingMenuItems = () => { }); return useCallback( - (t: TFunction<'translation', undefined>) => + (editor: DocsBlockNoteEditor, t: TFunction<'translation', undefined>) => getInterlinkingMenuItems( + editor, t, t('Links'), () => diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/SearchPage.tsx b/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/SearchPage.tsx new file mode 100644 index 000000000..280ca01b2 --- /dev/null +++ b/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/SearchPage.tsx @@ -0,0 +1,219 @@ +/* eslint-disable react-hooks/rules-of-hooks */ +import { + PartialCustomInlineContentFromConfig, + StyleSchema, +} from '@blocknote/core'; +import { useBlockNoteEditor } from '@blocknote/react'; +import { useEffect, useRef, useState } from 'react'; +import { css } from 'styled-components'; + +import { + Box, + Card, + Icon, + QuickSearch, + QuickSearchItemContent, + Text, +} from '@/components'; +import { useCunninghamTheme } from '@/cunningham'; +import { + DocsBlockSchema, + DocsInlineContentSchema, + DocsStyleSchema, +} from '@/docs/doc-editor'; +import FoundPageIcon from '@/docs/doc-editor/assets/doc-found.svg'; +import { DocSearchSubPageContent, DocSearchTarget } from '@/docs/doc-search'; + +const inputStyle = css` + background-color: var(--c--theme--colors--greyscale-100); + border: none; + outline: none; + color: var(--c--theme--colors--greyscale-700); + font-size: 16px; + width: 100%; + font-family: 'Inter'; +`; + +type SearchPageProps = { + updateInlineContent: ( + update: PartialCustomInlineContentFromConfig< + { + type: string; + propSchema: { + disabled: { + default: boolean; + }; + }; + content: 'styled'; + }, + StyleSchema + >, + ) => void; + contentRef: (node: HTMLElement | null) => void; +}; + +export const SearchPage = ({ + contentRef, + updateInlineContent, +}: SearchPageProps) => { + const { colorsTokens } = useCunninghamTheme(); + const editor = useBlockNoteEditor< + DocsBlockSchema, + DocsInlineContentSchema, + DocsStyleSchema + >(); + const inputRef = useRef(null); + const [search, setSearch] = useState(''); + + /** + * createReactInlineContentSpec add automatically the focus after + * the inline content, so we need to set the focus on the input + * after the component is mounted. + */ + useEffect(() => { + setTimeout(() => { + if (inputRef.current) { + inputRef.current.focus(); + } + }, 100); + }, [inputRef]); + + return ( + + + {' '} + / + { + const value = (e.target as HTMLInputElement).value; + setSearch(value); + }} + onKeyDown={(e) => { + if (e.key === 'Backspace' && search.length === 0) { + e.preventDefault(); + + updateInlineContent({ + type: 'interlinkingSearchInline', + props: { + disabled: true, + }, + }); + + contentRef(null); + editor.focus(); + editor.insertInlineContent(['']); + } + }} + /> + + + + div { + margin-top: 0; + & [cmdk-group-heading] { + padding: 0.4rem; + margin: 0; + } + + & [cmdk-group-items] .ml-b { + margin-left: 0rem; + padding: 0.5rem; + font-size: 14px; + display: block; + } + + & [cmdk-item] { + border-radius: 0; + } + + & .--docs--doc-search-item > div { + gap: 0.8rem; + } + } + `} + $margin={{ left: '-0.7rem', top: '0.5rem' }} + > + { + updateInlineContent({ + type: 'interlinkingSearchInline', + props: { + disabled: true, + }, + }); + + editor.insertInlineContent([ + { + type: 'interlinkingLinkInline', + props: { + url: `/docs/${doc.id}`, + title: doc.title || '', + }, + }, + ' ', + ]); + }} + renderElement={(doc) => ( + + + + {doc.title} + + + } + right={ + + } + /> + )} + /> + + + + + ); +}; diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/index.ts b/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/index.ts index b1a3b4487..3fabd144a 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/index.ts +++ b/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/index.ts @@ -1 +1,2 @@ +export * from './InterlinkingLinkInlineContent'; export * from './InterlinkingSearchInlineContent'; diff --git a/src/frontend/apps/impress/src/features/docs/doc-search/components/DocSearchModal.tsx b/src/frontend/apps/impress/src/features/docs/doc-search/components/DocSearchModal.tsx index caede5f1a..6214031a6 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-search/components/DocSearchModal.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-search/components/DocSearchModal.tsx @@ -18,6 +18,7 @@ import { DocSearchFiltersValues, DocSearchTarget, } from './DocSearchFilters'; +import { DocSearchItem } from './DocSearchItem'; import { DocSearchSubPageContent } from './DocSearchSubPageContent'; type DocSearchModalProps = { @@ -112,6 +113,7 @@ export const DocSearchModal = ({ filters={filters} onSelect={handleSelect} onLoadingChange={setLoading} + renderElement={(doc) => } /> )} diff --git a/src/frontend/apps/impress/src/features/docs/doc-search/components/DocSearchSubPageContent.tsx b/src/frontend/apps/impress/src/features/docs/doc-search/components/DocSearchSubPageContent.tsx index e4fa2c7e7..585d8dff9 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-search/components/DocSearchSubPageContent.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-search/components/DocSearchSubPageContent.tsx @@ -1,6 +1,6 @@ import { useTreeContext } from '@gouvfr-lasuite/ui-kit'; import { t } from 'i18next'; -import { useEffect, useMemo } from 'react'; +import React, { useEffect, useMemo } from 'react'; import { InView } from 'react-intersection-observer'; import { QuickSearchData, QuickSearchGroup } from '@/components/quick-search'; @@ -9,13 +9,13 @@ import { Doc } from '../../doc-management'; import { useInfiniteSubDocs } from '../../doc-management/api/useSubDocs'; import { DocSearchFiltersValues } from './DocSearchFilters'; -import { DocSearchItem } from './DocSearchItem'; type DocSearchSubPageContentProps = { search: string; filters: DocSearchFiltersValues; onSelect: (doc: Doc) => void; onLoadingChange?: (loading: boolean) => void; + renderElement: (doc: Doc) => React.ReactNode; }; export const DocSearchSubPageContent = ({ @@ -23,6 +23,7 @@ export const DocSearchSubPageContent = ({ filters, onSelect, onLoadingChange, + renderElement, }: DocSearchSubPageContentProps) => { const treeContext = useTreeContext(); @@ -67,7 +68,7 @@ export const DocSearchSubPageContent = ({ } + renderElement={renderElement} /> ); }; diff --git a/src/frontend/apps/impress/src/features/docs/doc-search/components/index.ts b/src/frontend/apps/impress/src/features/docs/doc-search/components/index.ts index 1a0889239..d5d0e0c44 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-search/components/index.ts +++ b/src/frontend/apps/impress/src/features/docs/doc-search/components/index.ts @@ -1,2 +1,3 @@ export * from './DocSearchModal'; export * from './DocSearchFilters'; +export * from './DocSearchSubPageContent'; From 57e5a198fdb9e270f417e85ba9e097edfc595318 Mon Sep 17 00:00:00 2001 From: Anthony LC Date: Fri, 25 Apr 2025 12:28:40 +0200 Subject: [PATCH 24/26] =?UTF-8?q?=E2=9C=A8(frontend)=20create=20page=20fro?= =?UTF-8?q?m=20dropdown=20search?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We are now able to create a new page from the dropdown search. --- .../__tests__/app-impress/doc-create.spec.ts | 22 +++++++++ .../apps/impress/src/components/BoxButton.tsx | 2 +- .../docs/doc-editor/assets/doc-found.svg | 3 ++ .../InterlinkingSearchInlineContent.tsx | 45 ++++--------------- .../Interlinking/SearchPage.tsx | 34 ++++++++++++++ .../docs/doc-management/hooks/index.ts | 1 + .../hooks/useCreateChildDocTree.tsx | 35 +++++++++++++++ 7 files changed, 104 insertions(+), 38 deletions(-) create mode 100644 src/frontend/apps/impress/src/features/docs/doc-editor/assets/doc-found.svg create mode 100644 src/frontend/apps/impress/src/features/docs/doc-management/hooks/useCreateChildDocTree.tsx diff --git a/src/frontend/apps/e2e/__tests__/app-impress/doc-create.spec.ts b/src/frontend/apps/e2e/__tests__/app-impress/doc-create.spec.ts index 97507778e..7946c1c66 100644 --- a/src/frontend/apps/e2e/__tests__/app-impress/doc-create.spec.ts +++ b/src/frontend/apps/e2e/__tests__/app-impress/doc-create.spec.ts @@ -47,6 +47,28 @@ test.describe('Doc Create', () => { page.locator('.c__tree-view--row-content').getByText('Untitled page'), ).toBeVisible(); }); + + test('it creates a sub doc from interlinking dropdown', async ({ + page, + browserName, + }) => { + const [title] = await createDoc(page, 'my-new-slash-doc', browserName, 1); + + await verifyDocName(page, title); + + await page.locator('.bn-block-outer').last().fill('/'); + await page.getByText('Link to a page').first().click(); + await page + .locator('.quick-search-container') + .getByText('Add a new page') + .click(); + + const input = page.getByRole('textbox', { name: 'doc title input' }); + await expect(input).toHaveText(''); + await expect( + page.locator('.c__tree-view--row-content').getByText('Untitled page'), + ).toBeVisible(); + }); }); test.describe('Doc Create: Not loggued', () => { diff --git a/src/frontend/apps/impress/src/components/BoxButton.tsx b/src/frontend/apps/impress/src/components/BoxButton.tsx index 3b8d77511..15d1b3403 100644 --- a/src/frontend/apps/impress/src/components/BoxButton.tsx +++ b/src/frontend/apps/impress/src/components/BoxButton.tsx @@ -31,11 +31,11 @@ const BoxButton = forwardRef( $background="none" $margin="none" $padding="none" + $hasTransition $css={css` cursor: ${props.disabled ? 'not-allowed' : 'pointer'}; border: none; outline: none; - transition: all 0.2s ease-in-out; font-family: inherit; color: ${props.disabled diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/assets/doc-found.svg b/src/frontend/apps/impress/src/features/docs/doc-editor/assets/doc-found.svg new file mode 100644 index 000000000..87d445d67 --- /dev/null +++ b/src/frontend/apps/impress/src/features/docs/doc-editor/assets/doc-found.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/InterlinkingSearchInlineContent.tsx b/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/InterlinkingSearchInlineContent.tsx index 972dd63a4..ba0ed6db4 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/InterlinkingSearchInlineContent.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/InterlinkingSearchInlineContent.tsx @@ -1,14 +1,11 @@ /* eslint-disable react-hooks/rules-of-hooks */ import { createReactInlineContentSpec } from '@blocknote/react'; -import { useTreeContext } from '@gouvfr-lasuite/ui-kit'; import { TFunction } from 'i18next'; -import { useRouter } from 'next/navigation'; -import { useCallback } from 'react'; import { DocsBlockNoteEditor } from '@/docs/doc-editor'; import LinkPageIcon from '@/docs/doc-editor/assets/doc-link.svg'; import AddPageIcon from '@/docs/doc-editor/assets/doc-plus.svg'; -import { Doc, useCreateChildDoc, useDocStore } from '@/docs/doc-management'; +import { useCreateChildDocTree, useDocStore } from '@/docs/doc-management'; import { SearchPage } from './SearchPage'; @@ -29,12 +26,12 @@ export const InterlinkingSearchInlineContent = createReactInlineContentSpec( return null; } - return ; + return ; }, }, ); -export const getInterlinkingMenuItems = ( +export const getInterlinkinghMenuItems = ( editor: DocsBlockNoteEditor, t: TFunction<'translation', undefined>, group: string, @@ -68,37 +65,11 @@ export const getInterlinkingMenuItems = ( ]; export const useGetInterlinkingMenuItems = () => { - const treeContext = useTreeContext(); - const router = useRouter(); const { currentDoc } = useDocStore(); + const createChildDoc = useCreateChildDocTree(currentDoc?.id); - const { mutate: createChildDoc } = useCreateChildDoc({ - onSuccess: (createdDoc) => { - const newDoc = { - ...createdDoc, - children: [], - childrenCount: 0, - parentId: currentDoc?.id ?? undefined, - }; - treeContext?.treeData.addChild(currentDoc?.id || null, newDoc); - - router.push(`/docs/${newDoc.id}`); - treeContext?.treeData.setSelectedNode(createdDoc); - }, - }); - - return useCallback( - (editor: DocsBlockNoteEditor, t: TFunction<'translation', undefined>) => - getInterlinkingMenuItems( - editor, - t, - t('Links'), - () => - currentDoc?.id && - createChildDoc({ - parentId: currentDoc.id, - }), - ), - [createChildDoc, currentDoc?.id], - ); + return ( + editor: DocsBlockNoteEditor, + t: TFunction<'translation', undefined>, + ) => getInterlinkinghMenuItems(editor, t, t('Links'), createChildDoc); }; diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/SearchPage.tsx b/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/SearchPage.tsx index 280ca01b2..be5b6710f 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/SearchPage.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/SearchPage.tsx @@ -5,10 +5,12 @@ import { } from '@blocknote/core'; import { useBlockNoteEditor } from '@blocknote/react'; import { useEffect, useRef, useState } from 'react'; +import { useTranslation } from 'react-i18next'; import { css } from 'styled-components'; import { Box, + BoxButton, Card, Icon, QuickSearch, @@ -22,6 +24,8 @@ import { DocsStyleSchema, } from '@/docs/doc-editor'; import FoundPageIcon from '@/docs/doc-editor/assets/doc-found.svg'; +import AddPageIcon from '@/docs/doc-editor/assets/doc-plus.svg'; +import { useCreateChildDocTree, useDocStore } from '@/docs/doc-management'; import { DocSearchSubPageContent, DocSearchTarget } from '@/docs/doc-search'; const inputStyle = css` @@ -62,6 +66,9 @@ export const SearchPage = ({ DocsInlineContentSchema, DocsStyleSchema >(); + const { t } = useTranslation(); + const { currentDoc } = useDocStore(); + const createChildDoc = useCreateChildDocTree(currentDoc?.id); const inputRef = useRef(null); const [search, setSearch] = useState(''); @@ -211,6 +218,33 @@ export const SearchPage = ({ /> )} /> + + + + + {t('Add a new page')} + + + diff --git a/src/frontend/apps/impress/src/features/docs/doc-management/hooks/index.ts b/src/frontend/apps/impress/src/features/docs/doc-management/hooks/index.ts index a1937ba07..2d39b8848 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-management/hooks/index.ts +++ b/src/frontend/apps/impress/src/features/docs/doc-management/hooks/index.ts @@ -1,3 +1,4 @@ export * from './useCollaboration'; +export * from './useCreateChildDocTree'; export * from './useTrans'; export * from './useCopyDocLink'; diff --git a/src/frontend/apps/impress/src/features/docs/doc-management/hooks/useCreateChildDocTree.tsx b/src/frontend/apps/impress/src/features/docs/doc-management/hooks/useCreateChildDocTree.tsx new file mode 100644 index 000000000..b11a3d345 --- /dev/null +++ b/src/frontend/apps/impress/src/features/docs/doc-management/hooks/useCreateChildDocTree.tsx @@ -0,0 +1,35 @@ +import { useTreeContext } from '@gouvfr-lasuite/ui-kit'; +import { useRouter } from 'next/navigation'; + +import { useCreateChildDoc } from '../api'; +import { Doc } from '../types'; + +export const useCreateChildDocTree = (parentId?: string) => { + const treeContext = useTreeContext(); + const router = useRouter(); + + const { mutate: createChildDoc } = useCreateChildDoc({ + onSuccess: (createdDoc) => { + const newDoc = { + ...createdDoc, + children: [], + childrenCount: 0, + parentId: parentId ?? undefined, + }; + treeContext?.treeData.addChild(parentId || null, newDoc); + + router.push(`/docs/${newDoc.id}`); + treeContext?.treeData.setSelectedNode(createdDoc); + }, + }); + + return () => { + if (!parentId) { + return null; + } + + createChildDoc({ + parentId, + }); + }; +}; From e6ad7d350c8c30e7145f887caca5a46d91d973b4 Mon Sep 17 00:00:00 2001 From: Anthony LC Date: Sun, 27 Apr 2025 22:21:20 +0200 Subject: [PATCH 25/26] =?UTF-8?q?=E2=9C=A8(frontend)=20create=20editor=20s?= =?UTF-8?q?hortcuts=20hook?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We created the editor shortcuts hook to handle the shortcuts for the editor. We implemented the following shortcuts: - "@" to open the interlinking inline content --- .../__tests__/app-impress/doc-editor.spec.ts | 16 ++++++++ .../doc-editor/components/BlockNoteEditor.tsx | 5 +-- .../InterlinkingSearchInlineContent.tsx | 13 ++++++- .../Interlinking/SearchPage.tsx | 9 ++++- .../hook/__tests__/useSaveDoc.test.tsx | 2 +- .../features/docs/doc-editor/hook/index.ts | 2 + .../docs/doc-editor/hook/useSaveDoc.tsx | 4 +- .../docs/doc-editor/hook/useShortcuts.tsx | 39 +++++++++++++++++++ 8 files changed, 81 insertions(+), 9 deletions(-) create mode 100644 src/frontend/apps/impress/src/features/docs/doc-editor/hook/useShortcuts.tsx diff --git a/src/frontend/apps/e2e/__tests__/app-impress/doc-editor.spec.ts b/src/frontend/apps/e2e/__tests__/app-impress/doc-editor.spec.ts index 00b73eaff..1989c281c 100644 --- a/src/frontend/apps/e2e/__tests__/app-impress/doc-editor.spec.ts +++ b/src/frontend/apps/e2e/__tests__/app-impress/doc-editor.spec.ts @@ -500,4 +500,20 @@ test.describe('Doc Editor', () => { await verifyDocName(page, docChild1); }); + + test('it checks interlink shortcut @', async ({ page, browserName }) => { + const [randomDoc] = await createDoc(page, 'doc-interlink', browserName, 1); + + await verifyDocName(page, randomDoc); + + const editor = page.locator('.bn-block-outer').last(); + await editor.click(); + await page.keyboard.press('@'); + + await expect( + page.locator( + "span[data-inline-content-type='interlinkingSearchInline'] input", + ), + ).toBeVisible(); + }); }); diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteEditor.tsx b/src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteEditor.tsx index 7c0a70c55..a55805b16 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteEditor.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteEditor.tsx @@ -19,9 +19,7 @@ import { Box, TextErrors } from '@/components'; import { Doc } from '@/docs/doc-management'; import { useAuth } from '@/features/auth'; -import { useUploadFile } from '../hook'; -import { useHeadings } from '../hook/useHeadings'; -import useSaveDoc from '../hook/useSaveDoc'; +import { useHeadings, useSaveDoc, useShortcuts, useUploadFile } from '../hook'; import { useEditorStore } from '../stores'; import { cssEditor } from '../styles'; import { randomColor } from '../utils'; @@ -129,6 +127,7 @@ export const BlockNoteEditor = ({ doc, provider }: BlockNoteEditorProps) => { [collabName, lang, provider, uploadFile], ); useHeadings(editor); + useShortcuts(editor); useEffect(() => { setEditor(editor); diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/InterlinkingSearchInlineContent.tsx b/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/InterlinkingSearchInlineContent.tsx index ba0ed6db4..c1d241c6f 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/InterlinkingSearchInlineContent.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/InterlinkingSearchInlineContent.tsx @@ -13,6 +13,10 @@ export const InterlinkingSearchInlineContent = createReactInlineContentSpec( { type: 'interlinkingSearchInline', propSchema: { + trigger: { + default: '/', + values: ['/', '@'], + }, disabled: { default: false, values: [true, false], @@ -26,7 +30,13 @@ export const InterlinkingSearchInlineContent = createReactInlineContentSpec( return null; } - return ; + return ( + + ); }, }, ); @@ -45,6 +55,7 @@ export const getInterlinkinghMenuItems = ( type: 'interlinkingSearchInline', props: { disabled: false, + trigger: '/', }, }, ]); diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/SearchPage.tsx b/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/SearchPage.tsx index be5b6710f..1b7b9842c 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/SearchPage.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/SearchPage.tsx @@ -39,6 +39,7 @@ const inputStyle = css` `; type SearchPageProps = { + trigger: string; updateInlineContent: ( update: PartialCustomInlineContentFromConfig< { @@ -47,6 +48,9 @@ type SearchPageProps = { disabled: { default: boolean; }; + trigger: { + default: string; + }; }; content: 'styled'; }, @@ -58,6 +62,7 @@ type SearchPageProps = { export const SearchPage = ({ contentRef, + trigger, updateInlineContent, }: SearchPageProps) => { const { colorsTokens } = useCunninghamTheme(); @@ -99,7 +104,7 @@ export const SearchPage = ({ tabIndex={-1} // Ensure the span is focusable > {' '} - / + {trigger} ({ useRouter: jest.fn(), diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/hook/index.ts b/src/frontend/apps/impress/src/features/docs/doc-editor/hook/index.ts index 7cef48671..95a0804b2 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-editor/hook/index.ts +++ b/src/frontend/apps/impress/src/features/docs/doc-editor/hook/index.ts @@ -1,2 +1,4 @@ +export * from './useHeadings'; export * from './useSaveDoc'; +export * from './useShortcuts'; export * from './useUploadFile'; diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/hook/useSaveDoc.tsx b/src/frontend/apps/impress/src/features/docs/doc-editor/hook/useSaveDoc.tsx index 26e518914..3bd4048a5 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-editor/hook/useSaveDoc.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-editor/hook/useSaveDoc.tsx @@ -10,7 +10,7 @@ import { toBase64 } from '../utils'; const SAVE_INTERVAL = 60000; -const useSaveDoc = (docId: string, yDoc: Y.Doc, canSave: boolean) => { +export const useSaveDoc = (docId: string, yDoc: Y.Doc, canSave: boolean) => { const { mutate: updateDoc } = useUpdateDoc({ listInvalideQueries: [KEY_LIST_DOC_VERSIONS], onSuccess: () => { @@ -92,5 +92,3 @@ const useSaveDoc = (docId: string, yDoc: Y.Doc, canSave: boolean) => { }; }, [router.events, saveDoc]); }; - -export default useSaveDoc; diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/hook/useShortcuts.tsx b/src/frontend/apps/impress/src/features/docs/doc-editor/hook/useShortcuts.tsx new file mode 100644 index 000000000..f2f3722fa --- /dev/null +++ b/src/frontend/apps/impress/src/features/docs/doc-editor/hook/useShortcuts.tsx @@ -0,0 +1,39 @@ +import { useEffect } from 'react'; + +import { DocsBlockNoteEditor } from '../types'; + +export const useShortcuts = (editor: DocsBlockNoteEditor) => { + useEffect(() => { + const handleKeyDown = (event: KeyboardEvent) => { + if (event.key === '@' && editor?.isFocused()) { + const selection = window.getSelection(); + const previousChar = + selection?.anchorNode?.textContent?.charAt( + selection.anchorOffset - 1, + ) || ''; + + if (![' ', ''].includes(previousChar)) { + return; + } + + event.preventDefault(); + editor.insertInlineContent([ + { + type: 'interlinkingSearchInline', + props: { + disabled: false, + trigger: '@', + }, + }, + ]); + } + }; + + // Attach the event listener to the document instead of the window + document.addEventListener('keydown', handleKeyDown); + + return () => { + document.removeEventListener('keydown', handleKeyDown); + }; + }, [editor]); +}; From 87cf9dcb5e54887e202a883c9935828c31bcd935 Mon Sep 17 00:00:00 2001 From: Anthony LC Date: Tue, 29 Apr 2025 11:52:18 +0200 Subject: [PATCH 26/26] =?UTF-8?q?=E2=9C=A8(frontend)=20interlinking=20expo?= =?UTF-8?q?rt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Create interlinking link mapping for docx and pdf export. --- .../__tests__/app-impress/doc-export.spec.ts | 68 ++++++++++++++++++ .../docs/doc-export/assets/doc-selected.png | Bin 0 -> 338 bytes .../blocks-mapping/paragraphPDF.tsx | 2 +- .../doc-export/blocks-mapping/quoteDocx.tsx | 16 +++-- .../inline-content-mapping/index.ts | 2 + .../interlinkingLinkDocx.tsx | 49 +++++++++++++ .../interlinkingLinkPDF.tsx | 22 ++++++ .../features/docs/doc-export/mappingDocx.tsx | 7 ++ .../features/docs/doc-export/mappingPDF.tsx | 6 ++ 9 files changed, 166 insertions(+), 6 deletions(-) create mode 100644 src/frontend/apps/impress/src/features/docs/doc-export/assets/doc-selected.png create mode 100644 src/frontend/apps/impress/src/features/docs/doc-export/inline-content-mapping/index.ts create mode 100644 src/frontend/apps/impress/src/features/docs/doc-export/inline-content-mapping/interlinkingLinkDocx.tsx create mode 100644 src/frontend/apps/impress/src/features/docs/doc-export/inline-content-mapping/interlinkingLinkPDF.tsx diff --git a/src/frontend/apps/e2e/__tests__/app-impress/doc-export.spec.ts b/src/frontend/apps/e2e/__tests__/app-impress/doc-export.spec.ts index 60160303f..7208a6f87 100644 --- a/src/frontend/apps/e2e/__tests__/app-impress/doc-export.spec.ts +++ b/src/frontend/apps/e2e/__tests__/app-impress/doc-export.spec.ts @@ -311,4 +311,72 @@ test.describe('Doc Export', () => { const pdfData = await pdf(pdfBuffer); expect(pdfData.text).toContain('Hello World'); }); + + test('it exports the doc with interlinking', async ({ + page, + browserName, + }) => { + const [randomDoc] = await createDoc( + page, + 'export-interlinking', + browserName, + 1, + ); + + await verifyDocName(page, randomDoc); + + const [docChild] = await createDoc( + page, + 'export-interlink-child', + browserName, + 1, + true, + ); + + await verifyDocName(page, docChild); + + await page.locator('.bn-block-outer').last().fill('/'); + await page.getByText('Link to a page').first().click(); + + await page + .locator( + "span[data-inline-content-type='interlinkingSearchInline'] input", + ) + .fill('interlink-child'); + + await page + .locator('.quick-search-container') + .getByText('interlink-child') + .click(); + + const interlink = page.getByRole('link', { + name: 'interlink-child', + }); + + await expect(interlink).toBeVisible(); + + const downloadPromise = page.waitForEvent('download', (download) => { + return download.suggestedFilename().includes(`${docChild}.pdf`); + }); + + await page + .getByRole('button', { + name: 'download', + }) + .click(); + + void page + .getByRole('button', { + name: 'Download', + }) + .click(); + + const download = await downloadPromise; + expect(download.suggestedFilename()).toBe(`${docChild}.pdf`); + + const pdfBuffer = await cs.toBuffer(await download.createReadStream()); + const pdfData = await pdf(pdfBuffer); + + expect(pdfData.text).toContain('interlink-child'); // This is the pdf text + }); }); diff --git a/src/frontend/apps/impress/src/features/docs/doc-export/assets/doc-selected.png b/src/frontend/apps/impress/src/features/docs/doc-export/assets/doc-selected.png new file mode 100644 index 0000000000000000000000000000000000000000..d4375fb49e3b95f524e65ae2b82cde3e984b14f3 GIT binary patch literal 338 zcmeAS@N?(olHy`uVBq!ia0vp^JU}eK!3HFi66di4Db50q$YKTtZeb8+WSBKa0w~B> z9OUlAup(vvTn;DLzZGSyCB=0t#kFT)tG(DA { - if (content.type === 'text' && !content.text) { + if (content.type === 'text' && 'text' in content && !content.text) { content.text = ' '; } }); diff --git a/src/frontend/apps/impress/src/features/docs/doc-export/blocks-mapping/quoteDocx.tsx b/src/frontend/apps/impress/src/features/docs/doc-export/blocks-mapping/quoteDocx.tsx index bcdaa68c8..1691386f7 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-export/blocks-mapping/quoteDocx.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-export/blocks-mapping/quoteDocx.tsx @@ -8,11 +8,17 @@ export const blockMappingQuoteDocx: DocsExporterDocx['mappings']['blockMapping'] if (Array.isArray(block.content)) { block.content.forEach((content) => { if (content.type === 'text') { - content.styles = { - ...content.styles, - italic: true, - textColor: 'gray', - }; + if ( + 'styles' in content && + typeof content.styles === 'object' && + content.styles !== null + ) { + content.styles = { + ...content.styles, + italic: true, + textColor: 'gray', + }; + } } }); } diff --git a/src/frontend/apps/impress/src/features/docs/doc-export/inline-content-mapping/index.ts b/src/frontend/apps/impress/src/features/docs/doc-export/inline-content-mapping/index.ts new file mode 100644 index 000000000..83c7581d6 --- /dev/null +++ b/src/frontend/apps/impress/src/features/docs/doc-export/inline-content-mapping/index.ts @@ -0,0 +1,2 @@ +export * from './interlinkingLinkPDF'; +export * from './interlinkingLinkDocX'; diff --git a/src/frontend/apps/impress/src/features/docs/doc-export/inline-content-mapping/interlinkingLinkDocx.tsx b/src/frontend/apps/impress/src/features/docs/doc-export/inline-content-mapping/interlinkingLinkDocx.tsx new file mode 100644 index 000000000..549196512 --- /dev/null +++ b/src/frontend/apps/impress/src/features/docs/doc-export/inline-content-mapping/interlinkingLinkDocx.tsx @@ -0,0 +1,49 @@ +/* eslint-disable jsx-a11y/alt-text */ + +import { ExternalHyperlink, ImageRun, Paragraph, TextRun } from 'docx'; + +import DocSelectedIcon from '../assets/doc-selected.png'; +import { DocsExporterDocx } from '../types'; + +export const inlineContentMappingInterlinkingLinkDocx: DocsExporterDocx['mappings']['inlineContentMapping']['interlinkingLinkInline'] = + (inline) => { + const fetchImageData = async () => { + const response = await fetch(DocSelectedIcon.src); + return response.arrayBuffer(); + }; + //const file = new FileReader(); + //file.readAsArrayBuffer(DocSelectedIcon.src); + function dataURItoBlob(dataURI: string) { + const byteString = atob(dataURI.split(',')[1]); + const ab = new ArrayBuffer(byteString.length); + const ia = new Uint8Array(ab); + for (let i = 0; i < byteString.length; i++) { + ia[i] = byteString.charCodeAt(i); + } + const bb = new Blob([ab]); + return bb; + } + + const imageDataPromise = fetchImageData(); + + return new Paragraph({ + children: [ + new ExternalHyperlink({ + children: [ + new ImageRun({ + data: dataURItoBlob(DocSelectedIcon.src).arrayBuffer(), + transformation: { + width: 12, + height: 12, + }, + }), + new TextRun({ + text: inline.props.title, + style: 'Hyperlink', + }), + ], + link: window.location.origin + inline.props.url, + }), + ], + }); + }; diff --git a/src/frontend/apps/impress/src/features/docs/doc-export/inline-content-mapping/interlinkingLinkPDF.tsx b/src/frontend/apps/impress/src/features/docs/doc-export/inline-content-mapping/interlinkingLinkPDF.tsx new file mode 100644 index 000000000..2baeae33c --- /dev/null +++ b/src/frontend/apps/impress/src/features/docs/doc-export/inline-content-mapping/interlinkingLinkPDF.tsx @@ -0,0 +1,22 @@ +/* eslint-disable jsx-a11y/alt-text */ +import { Image, Link } from '@react-pdf/renderer'; + +import DocSelectedIcon from '../assets/doc-selected.png'; +import { DocsExporterPDF } from '../types'; + +export const inlineContentMappingInterlinkingLinkPDF: DocsExporterPDF['mappings']['inlineContentMapping']['interlinkingLinkInline'] = + (inline) => { + return ( + + {' '} + + {inline.props.title}{' '} + + ); + }; diff --git a/src/frontend/apps/impress/src/features/docs/doc-export/mappingDocx.tsx b/src/frontend/apps/impress/src/features/docs/doc-export/mappingDocx.tsx index 449446924..260ae83ce 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-export/mappingDocx.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-export/mappingDocx.tsx @@ -1,10 +1,12 @@ import { docxDefaultSchemaMappings } from '@blocknote/xl-docx-exporter'; +import { Paragraph } from 'docx'; import { blockMappingDividerDocx, blockMappingImageDocx, blockMappingQuoteDocx, } from './blocks-mapping'; +import { inlineContentMappingInterlinkingLinkDocx } from './inline-content-mapping'; import { DocsExporterDocx } from './types'; export const docxDocsSchemaMappings: DocsExporterDocx['mappings'] = { @@ -15,4 +17,9 @@ export const docxDocsSchemaMappings: DocsExporterDocx['mappings'] = { quote: blockMappingQuoteDocx, image: blockMappingImageDocx, }, + inlineContentMapping: { + ...docxDefaultSchemaMappings.inlineContentMapping, + interlinkingSearchInline: () => new Paragraph(''), + interlinkingLinkInline: inlineContentMappingInterlinkingLinkDocx, + }, }; diff --git a/src/frontend/apps/impress/src/features/docs/doc-export/mappingPDF.tsx b/src/frontend/apps/impress/src/features/docs/doc-export/mappingPDF.tsx index 380e2f1af..1b25ae174 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-export/mappingPDF.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-export/mappingPDF.tsx @@ -8,6 +8,7 @@ import { blockMappingQuotePDF, blockMappingTablePDF, } from './blocks-mapping'; +import { inlineContentMappingInterlinkingLinkPDF } from './inline-content-mapping'; import { DocsExporterPDF } from './types'; export const pdfDocsSchemaMappings: DocsExporterPDF['mappings'] = { @@ -21,4 +22,9 @@ export const pdfDocsSchemaMappings: DocsExporterPDF['mappings'] = { quote: blockMappingQuotePDF, table: blockMappingTablePDF, }, + inlineContentMapping: { + ...pdfDefaultSchemaMappings.inlineContentMapping, + interlinkingSearchInline: () => <>, + interlinkingLinkInline: inlineContentMappingInterlinkingLinkPDF, + }, };