From e041f47dfeaca2dc1a5d1b05605e12e302fc5068 Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Thu, 15 Feb 2024 17:19:05 +0100 Subject: [PATCH] Replace Jotai with @tanstack/router (#2359) * Start replacing jotai with @tanstack/router * Remove jotai completely * Move the common layout & reimplement the ?action parameter This also makes sure everything is properly loaded in the route loader, and we use fragment where it makes sense * Change the default error component * GraphQL API: make the sessions fetchable through node(id: ID!) --- crates/graphql/src/query/mod.rs | 70 +- crates/handlers/src/oauth2/discovery.rs | 2 +- frontend/locales/en.json | 14 +- frontend/package-lock.json | 909 +++-------- frontend/package.json | 10 +- frontend/schema.graphql | 8 + frontend/src/atoms.ts | 0 frontend/src/components/BrowserSession.tsx | 1 - .../src/components/BrowserSessionList.tsx | 56 +- .../src/components/CompatSession.test.tsx | 10 +- frontend/src/components/CompatSession.tsx | 3 +- frontend/src/components/ErrorBoundary.tsx | 23 +- .../src/components/GenericError.module.css | 49 + frontend/src/components/GenericError.tsx | 46 + frontend/src/components/GraphQLError.tsx | 24 - .../src/components/Layout/Layout.test.tsx | 43 - frontend/src/components/Layout/Layout.tsx | 33 +- .../Layout/__snapshots__/Layout.test.tsx.snap | 3 +- .../Link}/Link.module.css | 0 .../UserProfile.tsx => Link/Link.tsx} | 33 +- .../components/{UserProfile => Link}/index.ts | 2 +- .../__snapshots__/LoadingScreen.test.tsx.snap | 1 + .../LoadingSpinner/LoadingSpinner.tsx | 8 +- .../src/components/NavBar/NavBar.stories.tsx | 31 +- .../src/components/NavItem/NavItem.module.css | 4 +- .../components/NavItem/NavItem.stories.tsx | 59 - .../src/components/NavItem/NavItem.test.tsx | 54 - frontend/src/components/NavItem/NavItem.tsx | 36 +- frontend/src/components/NavItem/index.ts | 2 +- .../src/components/OAuth2Session.test.tsx | 14 +- frontend/src/components/OAuth2Session.tsx | 5 - .../src/components/Session/Session.test.tsx | 43 +- frontend/src/components/Session/Session.tsx | 8 +- .../__snapshots__/Session.test.tsx.snap | 91 +- .../SessionDetail/BrowserSessionDetail.tsx | 4 +- .../CompatSessionDetail.test.tsx | 14 +- .../SessionDetail/CompatSessionDetail.tsx | 8 +- .../OAuth2SessionDetail.test.tsx | 10 +- .../SessionDetail/OAuth2SessionDetail.tsx | 18 +- .../SessionDetail/SessionDetail.tsx | 6 +- .../SessionDetail/SessionHeader.module.css | 46 +- .../SessionDetail/SessionHeader.stories.tsx | 16 +- .../SessionDetail/SessionHeader.tsx | 34 +- .../CompatSessionDetail.test.tsx.snap | 246 +-- .../OAuth2SessionDetail.test.tsx.snap | 246 +-- .../__snapshots__/SessionHeader.test.tsx.snap | 39 +- .../UnverifiedEmailAlert.test.tsx | 30 +- .../UnverifiedEmailAlert.tsx | 4 +- .../UnverifiedEmailAlert.test.tsx.snap | 7 +- .../components/UserEmail/UserEmail.module.css | 1 + .../src/components/UserEmail/UserEmail.tsx | 12 +- frontend/src/components/UserGreeting.tsx | 72 +- .../components/UserProfile/UserEmailList.tsx | 45 +- .../src/components/UserProfile/UserName.tsx | 54 +- .../BrowserSessionsOverview.stories.tsx | 20 +- .../BrowserSessionsOverview.test.tsx | 10 +- .../BrowserSessionsOverview.tsx | 4 +- .../UserSessionsOverview.tsx | 6 +- .../BrowserSessionsOverview.test.tsx.snap | 35 +- .../components/VerifyEmail/VerifyEmail.tsx | 21 +- .../__snapshots__/CompatSession.test.tsx.snap | 92 +- .../__snapshots__/OAuth2Session.test.tsx.snap | 97 +- frontend/src/gql/gql.ts | 86 +- frontend/src/gql/graphql.ts | 1395 ++++++++++------- frontend/src/gql/schema.ts | 40 + frontend/src/main.tsx | 52 +- frontend/src/pages/BrowserSession.tsx | 50 - frontend/src/pages/BrowserSessionList.tsx | 21 - frontend/src/pages/SessionDetail.tsx | 24 - frontend/src/routeTree.gen.ts | 118 ++ frontend/src/routes/__root.tsx | 100 ++ frontend/src/routes/_account.index.tsx | 74 + frontend/src/routes/_account.sessions.$id.tsx | 82 + .../_account.sessions.browsers.tsx} | 25 +- .../_account.sessions.index.tsx} | 35 +- frontend/src/routes/_account.tsx | 67 + .../clients.$id.tsx} | 36 +- frontend/src/routes/devices.$id.tsx | 80 + .../emails.$id.verify.tsx} | 40 +- frontend/src/routing/Link.tsx | 43 - frontend/src/routing/Router.tsx | 94 -- frontend/src/routing/actions.test.ts | 155 -- frontend/src/routing/actions.ts | 82 - frontend/src/routing/atoms.ts | 89 -- frontend/src/routing/index.ts | 21 - frontend/src/routing/routes.test.ts | 67 - frontend/src/routing/routes.ts | 136 -- frontend/src/routing/useNavigationLink.ts | 56 - frontend/src/test-utils/WithLocation.tsx | 58 - frontend/src/test-utils/router.tsx | 34 + frontend/src/utils/useCurrentUserId.tsx | 37 - frontend/vite.config.ts | 32 +- 92 files changed, 2415 insertions(+), 3706 deletions(-) delete mode 100644 frontend/src/atoms.ts create mode 100644 frontend/src/components/GenericError.module.css create mode 100644 frontend/src/components/GenericError.tsx delete mode 100644 frontend/src/components/GraphQLError.tsx delete mode 100644 frontend/src/components/Layout/Layout.test.tsx rename frontend/src/{routing => components/Link}/Link.module.css (100%) rename frontend/src/components/{UserProfile/UserProfile.tsx => Link/Link.tsx} (50%) rename frontend/src/components/{UserProfile => Link}/index.ts (93%) delete mode 100644 frontend/src/components/NavItem/NavItem.stories.tsx delete mode 100644 frontend/src/components/NavItem/NavItem.test.tsx delete mode 100644 frontend/src/pages/BrowserSession.tsx delete mode 100644 frontend/src/pages/BrowserSessionList.tsx delete mode 100644 frontend/src/pages/SessionDetail.tsx create mode 100644 frontend/src/routeTree.gen.ts create mode 100644 frontend/src/routes/__root.tsx create mode 100644 frontend/src/routes/_account.index.tsx create mode 100644 frontend/src/routes/_account.sessions.$id.tsx rename frontend/src/{pages/Profile.tsx => routes/_account.sessions.browsers.tsx} (51%) rename frontend/src/{pages/SessionsOverview.tsx => routes/_account.sessions.index.tsx} (59%) create mode 100644 frontend/src/routes/_account.tsx rename frontend/src/{pages/OAuth2Client.tsx => routes/clients.$id.tsx} (56%) create mode 100644 frontend/src/routes/devices.$id.tsx rename frontend/src/{pages/VerifyEmail.tsx => routes/emails.$id.verify.tsx} (58%) delete mode 100644 frontend/src/routing/Link.tsx delete mode 100644 frontend/src/routing/Router.tsx delete mode 100644 frontend/src/routing/actions.test.ts delete mode 100644 frontend/src/routing/actions.ts delete mode 100644 frontend/src/routing/atoms.ts delete mode 100644 frontend/src/routing/index.ts delete mode 100644 frontend/src/routing/routes.test.ts delete mode 100644 frontend/src/routing/routes.ts delete mode 100644 frontend/src/routing/useNavigationLink.ts delete mode 100644 frontend/src/test-utils/WithLocation.tsx create mode 100644 frontend/src/test-utils/router.tsx delete mode 100644 frontend/src/utils/useCurrentUserId.tsx diff --git a/crates/graphql/src/query/mod.rs b/crates/graphql/src/query/mod.rs index 024f1360..2e1e5133 100644 --- a/crates/graphql/src/query/mod.rs +++ b/crates/graphql/src/query/mod.rs @@ -16,7 +16,10 @@ use async_graphql::{Context, MergedObject, Object, ID}; use mas_storage::user::UserRepository; use crate::{ - model::{Anonymous, BrowserSession, Node, NodeType, OAuth2Client, User, UserEmail}, + model::{ + Anonymous, BrowserSession, CompatSession, Node, NodeType, OAuth2Client, OAuth2Session, + User, UserEmail, + }, state::ContextExt, UserId, }; @@ -149,6 +152,56 @@ impl BaseQuery { Ok(Some(BrowserSession(browser_session))) } + /// Fetch a compatible session by its ID. + async fn compat_session( + &self, + ctx: &Context<'_>, + id: ID, + ) -> Result, async_graphql::Error> { + let state = ctx.state(); + let id = NodeType::CompatSession.extract_ulid(&id)?; + let requester = ctx.requester(); + + let mut repo = state.repository().await?; + let compat_session = repo.compat_session().lookup(id).await?; + repo.cancel().await?; + + let Some(compat_session) = compat_session else { + return Ok(None); + }; + + if !requester.is_owner_or_admin(&compat_session) { + return Ok(None); + } + + Ok(Some(CompatSession::new(compat_session))) + } + + /// Fetch an OAuth 2.0 session by its ID. + async fn oauth2_session( + &self, + ctx: &Context<'_>, + id: ID, + ) -> Result, async_graphql::Error> { + let state = ctx.state(); + let id = NodeType::OAuth2Session.extract_ulid(&id)?; + let requester = ctx.requester(); + + let mut repo = state.repository().await?; + let oauth2_session = repo.oauth2_session().lookup(id).await?; + repo.cancel().await?; + + let Some(oauth2_session) = oauth2_session else { + return Ok(None); + }; + + if !requester.is_owner_or_admin(&oauth2_session) { + return Ok(None); + } + + Ok(Some(OAuth2Session(oauth2_session))) + } + /// Fetch a user email by its ID. async fn user_email( &self, @@ -185,10 +238,7 @@ impl BaseQuery { let ret = match node_type { // TODO - NodeType::Authentication - | NodeType::CompatSession - | NodeType::CompatSsoLogin - | NodeType::OAuth2Session => None, + NodeType::Authentication | NodeType::CompatSsoLogin => None, NodeType::UpstreamOAuth2Provider => UpstreamOAuthQuery .upstream_oauth2_provider(ctx, id) @@ -210,6 +260,16 @@ impl BaseQuery { .await? .map(|e| Node::UserEmail(Box::new(e))), + NodeType::CompatSession => self + .compat_session(ctx, id) + .await? + .map(|s| Node::CompatSession(Box::new(s))), + + NodeType::OAuth2Session => self + .oauth2_session(ctx, id) + .await? + .map(|s| Node::OAuth2Session(Box::new(s))), + NodeType::BrowserSession => self .browser_session(ctx, id) .await? diff --git a/crates/handlers/src/oauth2/discovery.rs b/crates/handlers/src/oauth2/discovery.rs index 9a883209..56b51af5 100644 --- a/crates/handlers/src/oauth2/discovery.rs +++ b/crates/handlers/src/oauth2/discovery.rs @@ -177,7 +177,7 @@ pub(crate) async fn get( graphql_endpoint: url_builder.graphql_endpoint(), account_management_uri: url_builder.account_management_uri(), // This needs to be kept in sync with what is supported in the frontend, - // see frontend/src/routing/actions.ts + // see frontend/src/routes/__root.tsx account_management_actions_supported: vec![ "org.matrix.profile".to_owned(), "org.matrix.sessions_list".to_owned(), diff --git a/frontend/locales/en.json b/frontend/locales/en.json index a1a75715..03ce5a8a 100644 --- a/frontend/locales/en.json +++ b/frontend/locales/en.json @@ -66,7 +66,12 @@ "confirmation_modal_title": "Are you sure you want to end this session?", "text": "End session" }, - "error_boundary_title": "Something went wrong", + "error": { + "hideDetails": "Hide details", + "showDetails": "Show details", + "subtitle": "An unexpected error occurred. Please try again.", + "title": "Something went wrong" + }, "last_active": { "active_date": "Active {{relativeDate}}", "active_now": "Active now", @@ -132,7 +137,6 @@ "title": "Cannot find session: {{deviceId}}" } }, - "unknown_route": "Unknown route {{route}}", "unverified_email_alert": { "button": "Review and verify", "text:one": "You have {{count}} unverified email address.", @@ -154,9 +158,6 @@ "heading": "Emails", "no_primary_email_alert": "No primary email address" }, - "user_greeting": { - "error": "Failed to load user" - }, "user_name": { "display_name_field_label": "Display Name" }, @@ -177,8 +178,7 @@ "description": "Check the code sent to your email and update the fields below to continue.", "title": "You entered the wrong code" }, - "resend_code": "Resend code", - "unknown_email": "Unknown email" + "resend_code": "Resend code" } } } diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 4bd99c45..c0586fef 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -8,10 +8,10 @@ "name": "mas-frontend", "version": "0.0.0", "dependencies": { - "@emotion/react": "^11.11.3", "@fontsource/inconsolata": "^5.0.16", "@fontsource/inter": "^5.0.16", "@radix-ui/react-alert-dialog": "^1.0.5", + "@tanstack/react-router": "^1.16.2", "@types/ua-parser-js": "^0.7.39", "@urql/core": "^4.2.3", "@urql/devtools": "^2.0.3", @@ -27,15 +27,12 @@ "i18next": "^23.8.2", "i18next-browser-languagedetector": "^7.2.0", "i18next-http-backend": "^2.4.3", - "jotai": "^2.6.4", - "jotai-devtools": "^0.7.1", - "jotai-location": "^0.5.2", - "jotai-urql": "^0.7.1", "react": "^18.2.0", "react-dom": "^18.2.0", "react-i18next": "^14.0.5", "ua-parser-js": "^1.0.37", - "urql": "^4.0.6" + "urql": "^4.0.6", + "zod": "^3.22.4" }, "devDependencies": { "@graphql-codegen/cli": "^5.0.2", @@ -45,6 +42,8 @@ "@storybook/addon-essentials": "^7.6.13", "@storybook/react": "^7.6.13", "@storybook/react-vite": "^7.6.13", + "@tanstack/router-devtools": "^1.16.2", + "@tanstack/router-vite-plugin": "^1.16.3", "@testing-library/react": "^14.2.1", "@types/node": "^20.11.17", "@types/react": "^18.2.55", @@ -343,6 +342,7 @@ "version": "7.23.5", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", + "dev": true, "dependencies": { "@babel/highlight": "^7.23.4", "chalk": "^2.4.2" @@ -586,6 +586,7 @@ "version": "7.22.15", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", + "dev": true, "dependencies": { "@babel/types": "^7.22.15" }, @@ -707,6 +708,7 @@ "version": "7.23.4", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", + "dev": true, "engines": { "node": ">=6.9.0" } @@ -715,6 +717,7 @@ "version": "7.22.20", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "dev": true, "engines": { "node": ">=6.9.0" } @@ -760,6 +763,7 @@ "version": "7.23.4", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", + "dev": true, "dependencies": { "@babel/helper-validator-identifier": "^7.22.20", "chalk": "^2.4.2", @@ -2537,6 +2541,7 @@ "version": "7.23.9", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.9.tgz", "integrity": "sha512-dQjSq/7HaSjRM43FFGnv5keM2HsxpmyV1PfaSVm0nzzjwwTmjOe6J4bC8e3+pTEIgHaHj+1ZlLThRJ2auc/w1Q==", + "dev": true, "dependencies": { "@babel/helper-string-parser": "^7.23.4", "@babel/helper-validator-identifier": "^7.22.20", @@ -2599,114 +2604,15 @@ "node": ">=10.0.0" } }, - "node_modules/@emotion/babel-plugin": { - "version": "11.11.0", - "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.11.0.tgz", - "integrity": "sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ==", - "dependencies": { - "@babel/helper-module-imports": "^7.16.7", - "@babel/runtime": "^7.18.3", - "@emotion/hash": "^0.9.1", - "@emotion/memoize": "^0.8.1", - "@emotion/serialize": "^1.1.2", - "babel-plugin-macros": "^3.1.0", - "convert-source-map": "^1.5.0", - "escape-string-regexp": "^4.0.0", - "find-root": "^1.1.0", - "source-map": "^0.5.7", - "stylis": "4.2.0" - } - }, - "node_modules/@emotion/babel-plugin/node_modules/convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" - }, - "node_modules/@emotion/cache": { - "version": "11.11.0", - "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.11.0.tgz", - "integrity": "sha512-P34z9ssTCBi3e9EI1ZsWpNHcfY1r09ZO0rZbRO2ob3ZQMnFI35jB536qoXbkdesr5EUhYi22anuEJuyxifaqAQ==", - "dependencies": { - "@emotion/memoize": "^0.8.1", - "@emotion/sheet": "^1.2.2", - "@emotion/utils": "^1.2.1", - "@emotion/weak-memoize": "^0.3.1", - "stylis": "4.2.0" - } - }, - "node_modules/@emotion/hash": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.1.tgz", - "integrity": "sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ==" - }, - "node_modules/@emotion/memoize": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz", - "integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==" - }, - "node_modules/@emotion/react": { - "version": "11.11.3", - "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.11.3.tgz", - "integrity": "sha512-Cnn0kuq4DoONOMcnoVsTOR8E+AdnKFf//6kUWc4LCdnxj31pZWn7rIULd6Y7/Js1PiPHzn7SKCM9vB/jBni8eA==", - "dependencies": { - "@babel/runtime": "^7.18.3", - "@emotion/babel-plugin": "^11.11.0", - "@emotion/cache": "^11.11.0", - "@emotion/serialize": "^1.1.3", - "@emotion/use-insertion-effect-with-fallbacks": "^1.0.1", - "@emotion/utils": "^1.2.1", - "@emotion/weak-memoize": "^0.3.1", - "hoist-non-react-statics": "^3.3.1" - }, - "peerDependencies": { - "react": ">=16.8.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@emotion/serialize": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.1.3.tgz", - "integrity": "sha512-iD4D6QVZFDhcbH0RAG1uVu1CwVLMWUkCvAqqlewO/rxf8+87yIBAlt4+AxMiiKPLs5hFc0owNk/sLLAOROw3cA==", - "dependencies": { - "@emotion/hash": "^0.9.1", - "@emotion/memoize": "^0.8.1", - "@emotion/unitless": "^0.8.1", - "@emotion/utils": "^1.2.1", - "csstype": "^3.0.2" - } - }, - "node_modules/@emotion/sheet": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.2.tgz", - "integrity": "sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA==" - }, - "node_modules/@emotion/unitless": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.1.tgz", - "integrity": "sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==" - }, "node_modules/@emotion/use-insertion-effect-with-fallbacks": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.1.tgz", "integrity": "sha512-jT/qyKZ9rzLErtrjGgdkMBn2OP8wl0G3sQlBb3YPryvKHsjvINUhVaPFfP+fpBcOkmrVOVEEHQFJ7nbj2TH2gw==", + "dev": true, "peerDependencies": { "react": ">=16.8.0" } }, - "node_modules/@emotion/utils": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.1.tgz", - "integrity": "sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg==" - }, - "node_modules/@emotion/weak-memoize": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz", - "integrity": "sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww==" - }, "node_modules/@esbuild/aix-ppc64": { "version": "0.19.12", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz", @@ -3215,20 +3121,6 @@ "@floating-ui/utils": "^0.2.1" } }, - "node_modules/@floating-ui/react": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.19.2.tgz", - "integrity": "sha512-JyNk4A0Ezirq8FlXECvRtQOX/iBe5Ize0W/pLkrZjfHW9GUV7Xnq6zm6fyZuQzaHHqEnVizmvlA96e1/CkZv+w==", - "dependencies": { - "@floating-ui/react-dom": "^1.3.0", - "aria-hidden": "^1.1.3", - "tabbable": "^6.0.1" - }, - "peerDependencies": { - "react": ">=16.8.0", - "react-dom": ">=16.8.0" - } - }, "node_modules/@floating-ui/react-dom": { "version": "2.0.8", "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.0.8.tgz", @@ -3241,18 +3133,6 @@ "react-dom": ">=16.8.0" } }, - "node_modules/@floating-ui/react/node_modules/@floating-ui/react-dom": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-1.3.0.tgz", - "integrity": "sha512-htwHm67Ji5E/pROEAr7f8IKFShuiCKHwUC/UY4vC3I5jiSvGFAYnSYiZO5MlGmads+QqvUkR9ANHEguGrDv72g==", - "dependencies": { - "@floating-ui/dom": "^1.2.1" - }, - "peerDependencies": { - "react": ">=16.8.0", - "react-dom": ">=16.8.0" - } - }, "node_modules/@floating-ui/utils": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.1.tgz", @@ -5384,74 +5264,6 @@ "integrity": "sha512-gbkePEBupNydxCelHCESvFSFM8XPh1Zs/OAVRW/rKpEqPAl5PbOM90Si8mv9bvnR53uPD2s/FiRxdvSejpRJew==", "dev": true }, - "node_modules/@mantine/core": { - "version": "6.0.21", - "resolved": "https://registry.npmjs.org/@mantine/core/-/core-6.0.21.tgz", - "integrity": "sha512-Kx4RrRfv0I+cOCIcsq/UA2aWcYLyXgW3aluAuW870OdXnbII6qg7RW28D+r9D76SHPxWFKwIKwmcucAG08Divg==", - "dependencies": { - "@floating-ui/react": "^0.19.1", - "@mantine/styles": "6.0.21", - "@mantine/utils": "6.0.21", - "@radix-ui/react-scroll-area": "1.0.2", - "react-remove-scroll": "^2.5.5", - "react-textarea-autosize": "8.3.4" - }, - "peerDependencies": { - "@mantine/hooks": "6.0.21", - "react": ">=16.8.0", - "react-dom": ">=16.8.0" - } - }, - "node_modules/@mantine/hooks": { - "version": "6.0.21", - "resolved": "https://registry.npmjs.org/@mantine/hooks/-/hooks-6.0.21.tgz", - "integrity": "sha512-sYwt5wai25W6VnqHbS5eamey30/HD5dNXaZuaVEAJ2i2bBv8C0cCiczygMDpAFiSYdXoSMRr/SZ2CrrPTzeNew==", - "peerDependencies": { - "react": ">=16.8.0" - } - }, - "node_modules/@mantine/prism": { - "version": "6.0.21", - "resolved": "https://registry.npmjs.org/@mantine/prism/-/prism-6.0.21.tgz", - "integrity": "sha512-M9hDUAuuxiINI7f07V0qlX532UXlOTpBqNcG1WWm80t6C0fHjzkTvFj77QpnGS73+MI88mV8ru458y10bQjTBA==", - "dependencies": { - "@mantine/utils": "6.0.21", - "prism-react-renderer": "^1.2.1" - }, - "peerDependencies": { - "@mantine/core": "6.0.21", - "@mantine/hooks": "6.0.21", - "react": ">=16.8.0", - "react-dom": ">=16.8.0" - } - }, - "node_modules/@mantine/styles": { - "version": "6.0.21", - "resolved": "https://registry.npmjs.org/@mantine/styles/-/styles-6.0.21.tgz", - "integrity": "sha512-PVtL7XHUiD/B5/kZ/QvZOZZQQOj12QcRs3Q6nPoqaoPcOX5+S7bMZLMH0iLtcGq5OODYk0uxlvuJkOZGoPj8Mg==", - "dependencies": { - "clsx": "1.1.1", - "csstype": "3.0.9" - }, - "peerDependencies": { - "@emotion/react": ">=11.9.0", - "react": ">=16.8.0", - "react-dom": ">=16.8.0" - } - }, - "node_modules/@mantine/styles/node_modules/csstype": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.9.tgz", - "integrity": "sha512-rpw6JPxK6Rfg1zLOYCSwle2GFOOsnjmDYDaBwEcwoOg4qlsIVCN789VkBZDJAGi4T07gI4YSutR43t9Zz4Lzuw==" - }, - "node_modules/@mantine/utils": { - "version": "6.0.21", - "resolved": "https://registry.npmjs.org/@mantine/utils/-/utils-6.0.21.tgz", - "integrity": "sha512-33RVDRop5jiWFao3HKd3Yp7A9mEq4HAJxJPTuYm1NkdqX6aTKOQK7wT8v8itVodBp+sb4cJK6ZVdD1UurK/txQ==", - "peerDependencies": { - "react": ">=16.8.0" - } - }, "node_modules/@mdx-js/react": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-2.3.0.tgz", @@ -6167,137 +5979,6 @@ } } }, - "node_modules/@radix-ui/react-scroll-area": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-scroll-area/-/react-scroll-area-1.0.2.tgz", - "integrity": "sha512-k8VseTxI26kcKJaX0HPwkvlNBPTs56JRdYzcZ/vzrNUkDlvXBy8sMc7WvCpYzZkHgb+hd72VW9MqkqecGtuNgg==", - "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/number": "1.0.0", - "@radix-ui/primitive": "1.0.0", - "@radix-ui/react-compose-refs": "1.0.0", - "@radix-ui/react-context": "1.0.0", - "@radix-ui/react-direction": "1.0.0", - "@radix-ui/react-presence": "1.0.0", - "@radix-ui/react-primitive": "1.0.1", - "@radix-ui/react-use-callback-ref": "1.0.0", - "@radix-ui/react-use-layout-effect": "1.0.0" - }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0" - } - }, - "node_modules/@radix-ui/react-scroll-area/node_modules/@radix-ui/number": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.0.0.tgz", - "integrity": "sha512-Ofwh/1HX69ZfJRiRBMTy7rgjAzHmwe4kW9C9Y99HTRUcYLUuVT0KESFj15rPjRgKJs20GPq8Bm5aEDJ8DuA3vA==", - "dependencies": { - "@babel/runtime": "^7.13.10" - } - }, - "node_modules/@radix-ui/react-scroll-area/node_modules/@radix-ui/primitive": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.0.0.tgz", - "integrity": "sha512-3e7rn8FDMin4CgeL7Z/49smCA3rFYY3Ha2rUQ7HRWFadS5iCRw08ZgVT1LaNTCNqgvrUiyczLflrVrF0SRQtNA==", - "dependencies": { - "@babel/runtime": "^7.13.10" - } - }, - "node_modules/@radix-ui/react-scroll-area/node_modules/@radix-ui/react-compose-refs": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.0.0.tgz", - "integrity": "sha512-0KaSv6sx787/hK3eF53iOkiSLwAGlFMx5lotrqD2pTjB18KbybKoEIgkNZTKC60YECDQTKGTRcDBILwZVqVKvA==", - "dependencies": { - "@babel/runtime": "^7.13.10" - }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0" - } - }, - "node_modules/@radix-ui/react-scroll-area/node_modules/@radix-ui/react-context": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.0.0.tgz", - "integrity": "sha512-1pVM9RfOQ+n/N5PJK33kRSKsr1glNxomxONs5c49MliinBY6Yw2Q995qfBUUo0/Mbg05B/sGA0gkgPI7kmSHBg==", - "dependencies": { - "@babel/runtime": "^7.13.10" - }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0" - } - }, - "node_modules/@radix-ui/react-scroll-area/node_modules/@radix-ui/react-direction": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.0.0.tgz", - "integrity": "sha512-2HV05lGUgYcA6xgLQ4BKPDmtL+QbIZYH5fCOTAOOcJ5O0QbWS3i9lKaurLzliYUDhORI2Qr3pyjhJh44lKA3rQ==", - "dependencies": { - "@babel/runtime": "^7.13.10" - }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0" - } - }, - "node_modules/@radix-ui/react-scroll-area/node_modules/@radix-ui/react-presence": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.0.0.tgz", - "integrity": "sha512-A+6XEvN01NfVWiKu38ybawfHsBjWum42MRPnEuqPsBZ4eV7e/7K321B5VgYMPv3Xx5An6o1/l9ZuDBgmcmWK3w==", - "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/react-compose-refs": "1.0.0", - "@radix-ui/react-use-layout-effect": "1.0.0" - }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0" - } - }, - "node_modules/@radix-ui/react-scroll-area/node_modules/@radix-ui/react-primitive": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-1.0.1.tgz", - "integrity": "sha512-fHbmislWVkZaIdeF6GZxF0A/NH/3BjrGIYj+Ae6eTmTCr7EB0RQAAVEiqsXK6p3/JcRqVSBQoceZroj30Jj3XA==", - "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/react-slot": "1.0.1" - }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0" - } - }, - "node_modules/@radix-ui/react-scroll-area/node_modules/@radix-ui/react-slot": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.0.1.tgz", - "integrity": "sha512-avutXAFL1ehGvAXtPquu0YK5oz6ctS474iM3vNGQIkswrVhdrS52e3uoMQBzZhNRAIE0jBnUyXWNmSjGHhCFcw==", - "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/react-compose-refs": "1.0.0" - }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0" - } - }, - "node_modules/@radix-ui/react-scroll-area/node_modules/@radix-ui/react-use-callback-ref": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.0.0.tgz", - "integrity": "sha512-GZtyzoHz95Rhs6S63D2t/eqvdFCm7I+yHMLVQheKM7nBD8mbZIt+ct1jz4536MDnaOGKIxynJ8eHTkVGVVkoTg==", - "dependencies": { - "@babel/runtime": "^7.13.10" - }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0" - } - }, - "node_modules/@radix-ui/react-scroll-area/node_modules/@radix-ui/react-use-layout-effect": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.0.0.tgz", - "integrity": "sha512-6Tpkq+R6LOlmQb1R5NNETLG0B4YP0wc+klfXafpUCj6JGyaUc8il7/kUZ7m59rGbXGczE9Bs+iz2qloqsZBduQ==", - "dependencies": { - "@babel/runtime": "^7.13.10" - }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0" - } - }, "node_modules/@radix-ui/react-select": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-1.2.2.tgz", @@ -6768,23 +6449,6 @@ "@babel/runtime": "^7.13.10" } }, - "node_modules/@redux-devtools/extension": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/@redux-devtools/extension/-/extension-3.3.0.tgz", - "integrity": "sha512-X34S/rC8S/M1BIrkYD1mJ5f8vlH0BDqxXrs96cvxSBo4FhMdbhU+GUGsmNYov1xjSyLMHgo8NYrUG8bNX7525g==", - "dependencies": { - "@babel/runtime": "^7.23.2", - "immutable": "^4.3.4" - }, - "peerDependencies": { - "redux": "^3.1.0 || ^4.0.0 || ^5.0.0" - } - }, - "node_modules/@redux-devtools/extension/node_modules/immutable": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.5.tgz", - "integrity": "sha512-8eabxkth9gZatlwl5TBuJnCsoTADlL6ftEr7A4qgdaTsPyreilDSnUk57SO+jfKcNtxPa22U5KK6DSeAYhpBJw==" - }, "node_modules/@repeaterjs/repeater": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/@repeaterjs/repeater/-/repeater-3.0.5.tgz", @@ -8461,6 +8125,136 @@ "@svgr/core": "*" } }, + "node_modules/@tanstack/history": { + "version": "1.15.13", + "resolved": "https://registry.npmjs.org/@tanstack/history/-/history-1.15.13.tgz", + "integrity": "sha512-ToaeMtK5S4YaxCywAlYexc7KPFN0esjyTZ4vXzJhXEWAkro9iHgh7m/4ozPJb7oTo65WkHWX0W9GjcZbInSD8w==", + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/react-router": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/@tanstack/react-router/-/react-router-1.16.2.tgz", + "integrity": "sha512-GgAxcs3JQjpC/nQd81S9MQ2wC9aPEw+fBt0n1VwYl/vW571OpU4HfRawu/OT4piHcV9/VS5oAUoZlwtApI0hLw==", + "dependencies": { + "@tanstack/history": "1.15.13", + "@tanstack/react-store": "^0.2.1", + "tiny-invariant": "^1.3.1", + "tiny-warning": "^1.0.3" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": ">=16", + "react-dom": ">=16" + } + }, + "node_modules/@tanstack/react-store": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@tanstack/react-store/-/react-store-0.2.1.tgz", + "integrity": "sha512-tEbMCQjbeVw9KOP/202LfqZMSNAVi6zYkkp1kBom8nFuMx/965Hzes3+6G6b/comCwVxoJU8Gg9IrcF8yRPthw==", + "dependencies": { + "@tanstack/store": "0.1.3", + "use-sync-external-store": "^1.2.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": ">=16", + "react-dom": ">=16" + } + }, + "node_modules/@tanstack/router-devtools": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/@tanstack/router-devtools/-/router-devtools-1.16.2.tgz", + "integrity": "sha512-ntGIeLjzEaWyo0Tb8x3tAC9YZXyywYDuODn3IZCYBx+ju4lIyQEIWjZpBNGEaHv3D9QfNTeZN0uposXylZN2kw==", + "dev": true, + "dependencies": { + "@tanstack/react-router": "1.16.2", + "date-fns": "^2.29.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": ">=16", + "react-dom": ">=16" + } + }, + "node_modules/@tanstack/router-devtools/node_modules/date-fns": { + "version": "2.30.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", + "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.21.0" + }, + "engines": { + "node": ">=0.11" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/date-fns" + } + }, + "node_modules/@tanstack/router-generator": { + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/@tanstack/router-generator/-/router-generator-1.16.3.tgz", + "integrity": "sha512-S3cO7bUtWnbMKVuC6nVcx4TpE1n98aCXQ3xhPtiZr5dgtIxIQFN+O62H0M1UJi1kkDPQ37dJoXzupXLxW1aexw==", + "dev": true, + "dependencies": { + "prettier": "^3.1.1", + "zod": "^3.22.4" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/router-vite-plugin": { + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/@tanstack/router-vite-plugin/-/router-vite-plugin-1.16.3.tgz", + "integrity": "sha512-ECIzQP1QS3hxFKmg8UUw3u8fkPqWWb3XrEUm8NIQZ1bMfirYV8vVNpl2beeB5+N1mqEwBXzxXuXEse0utO4rPg==", + "dev": true, + "dependencies": { + "@tanstack/router-generator": "1.16.3" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/store": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@tanstack/store/-/store-0.1.3.tgz", + "integrity": "sha512-GnolmC8Fr4mvsHE1fGQmR3Nm0eBO3KnZjDU0a+P3TeQNM/dDscFGxtA7p31NplQNW3KwBw4t1RVFmz0VeKLxcw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, "node_modules/@testing-library/dom": { "version": "9.3.4", "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-9.3.4.tgz", @@ -8605,11 +8399,6 @@ "@babel/types": "^7.20.7" } }, - "node_modules/@types/base16": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/base16/-/base16-1.0.5.tgz", - "integrity": "sha512-OzOWrTluG9cwqidEzC/Q6FAmIPcnZfm8BFRlIx0+UIUqnuAmi5OS88O0RpT3Yz6qdmqObvUhasrbNsCofE4W9A==" - }, "node_modules/@types/body-parser": { "version": "1.19.5", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", @@ -8780,7 +8569,8 @@ "node_modules/@types/lodash": { "version": "4.14.202", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.202.tgz", - "integrity": "sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ==" + "integrity": "sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ==", + "dev": true }, "node_modules/@types/mdx": { "version": "2.0.11", @@ -8834,7 +8624,8 @@ "node_modules/@types/parse-json": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", - "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==" + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", + "dev": true }, "node_modules/@types/pretty-hrtime": { "version": "1.0.3", @@ -8845,7 +8636,8 @@ "node_modules/@types/prop-types": { "version": "15.7.11", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.11.tgz", - "integrity": "sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==" + "integrity": "sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==", + "devOptional": true }, "node_modules/@types/q": { "version": "1.5.8", @@ -8868,6 +8660,7 @@ "version": "18.2.55", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.55.tgz", "integrity": "sha512-Y2Tz5P4yz23brwm2d7jNon39qoAtMMmalOQv6+fEFt1mT+FcM3D841wDpoUvFXhaYenuROCy3FZYqdTjM7qVyA==", + "devOptional": true, "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -8901,7 +8694,8 @@ "node_modules/@types/scheduler": { "version": "0.16.8", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.8.tgz", - "integrity": "sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==" + "integrity": "sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==", + "devOptional": true }, "node_modules/@types/semver": { "version": "7.5.6", @@ -10458,6 +10252,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", + "dev": true, "dependencies": { "@babel/runtime": "^7.12.5", "cosmiconfig": "^7.0.0", @@ -10472,6 +10267,7 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "dev": true, "dependencies": { "@types/parse-json": "^4.0.0", "import-fresh": "^3.2.1", @@ -10487,6 +10283,7 @@ "version": "1.10.2", "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true, "engines": { "node": ">= 6" } @@ -10617,11 +10414,6 @@ "dev": true, "optional": true }, - "node_modules/base16": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/base16/-/base16-1.0.0.tgz", - "integrity": "sha512-pNdYkNPiJUnEhnfXV56+sQy8+AaPcG3POZAUnwr4EeqCUZFz4u2PePbo3e5Gj4ziYPCWGUZT9RHisvJKnwFuBQ==" - }, "node_modules/base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", @@ -11047,6 +10839,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, "engines": { "node": ">=6" } @@ -11501,14 +11294,6 @@ "integrity": "sha512-au6ydSpg6nsrigcZ4m8Bc9hxjeW+GJ8xh5G3BJCMt4WXe1H10UNaVOamqQTmrx1kjVuxAHIQSNU6hY4Nsn9/ag==", "dev": true }, - "node_modules/clsx": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.1.1.tgz", - "integrity": "sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA==", - "engines": { - "node": ">=6" - } - }, "node_modules/coa": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz", @@ -11522,19 +11307,11 @@ "node": ">= 4.0" } }, - "node_modules/color": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", - "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", - "dependencies": { - "color-convert": "^1.9.3", - "color-string": "^1.6.0" - } - }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, "dependencies": { "color-name": "~1.1.4" }, @@ -11545,29 +11322,8 @@ "node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/color-string": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", - "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", - "dependencies": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" - } - }, - "node_modules/color/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true }, "node_modules/colorette": { "version": "2.0.20", @@ -11967,7 +11723,8 @@ "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "devOptional": true }, "node_modules/damerau-levenshtein": { "version": "1.0.8", @@ -12291,11 +12048,6 @@ "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", "dev": true }, - "node_modules/diff-match-patch": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/diff-match-patch/-/diff-match-patch-1.0.5.tgz", - "integrity": "sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw==" - }, "node_modules/diff-sequences": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", @@ -12593,6 +12345,7 @@ "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, "dependencies": { "is-arrayish": "^0.2.1" } @@ -12827,6 +12580,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, "engines": { "node": ">=10" }, @@ -14817,11 +14571,6 @@ "node": ">=8" } }, - "node_modules/find-root": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", - "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==" - }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -15112,6 +14861,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -15725,6 +15475,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "dev": true, "dependencies": { "function-bind": "^1.1.2" }, @@ -15799,14 +15550,6 @@ "@babel/runtime": "^7.7.6" } }, - "node_modules/hoist-non-react-statics": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", - "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", - "dependencies": { - "react-is": "^16.7.0" - } - }, "node_modules/hosted-git-info": { "version": "2.8.9", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", @@ -16444,6 +16187,7 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -16459,6 +16203,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, "engines": { "node": ">=4" } @@ -16681,7 +16426,8 @@ "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true }, "node_modules/is-async-function": { "version": "2.0.0", @@ -16770,6 +16516,7 @@ "version": "2.13.1", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dev": true, "dependencies": { "hasown": "^2.0.0" }, @@ -17511,11 +17258,6 @@ "node": ">=8" } }, - "node_modules/javascript-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/javascript-stringify/-/javascript-stringify-2.1.0.tgz", - "integrity": "sha512-JVAfqNPTvNq3sB/VHQJAFxN/sPgKnsKrCwyRt15zwNCdrMMJDdcEOdubuy+DuJYYdm0ox1J4uzEuYKkN+9yhVg==" - }, "node_modules/jest-haste-map": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", @@ -17691,66 +17433,6 @@ "url": "https://github.com/sponsors/panva" } }, - "node_modules/jotai": { - "version": "2.6.4", - "resolved": "https://registry.npmjs.org/jotai/-/jotai-2.6.4.tgz", - "integrity": "sha512-RniwQPX4893YlNR1muOtyUGHYaTD1fhEN4qnOuZJSrDHj6xdEMrqlRSN/hCm2fshwk78ruecB/P2l+NCVWe6TQ==", - "engines": { - "node": ">=12.20.0" - }, - "peerDependencies": { - "@types/react": ">=17.0.0", - "react": ">=17.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "react": { - "optional": true - } - } - }, - "node_modules/jotai-devtools": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/jotai-devtools/-/jotai-devtools-0.7.1.tgz", - "integrity": "sha512-Uqz5LOXSNkVBYG7HEauYtguTJyndX5kMVtFSYsqcNrCr2H53okxMwZnRg5n7WOy9uHyi1+a5xa1omjpIH6lGbA==", - "dependencies": { - "@mantine/core": "^6.0.21", - "@mantine/hooks": "^6.0.21", - "@mantine/prism": "^6.0.21", - "@redux-devtools/extension": "^3.2.6", - "javascript-stringify": "^2.1.0", - "jsondiffpatch": "^0.5.0", - "react-error-boundary": "^4.0.11", - "react-json-tree": "^0.18.0", - "react-resizable-panels": "^0.0.54" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "@emotion/react": ">=11.0.0", - "react": ">=17.0.0" - } - }, - "node_modules/jotai-location": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/jotai-location/-/jotai-location-0.5.2.tgz", - "integrity": "sha512-4S9hDh1wYp4SG4Laq3+Xd0GdW7jwnWlbEuL8U22kv3wUZW892n6gXlNhwU0LaoXnWoGG0gtjSLBuFm5iodFKLg==", - "peerDependencies": { - "jotai": ">=1.11.0" - } - }, - "node_modules/jotai-urql": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/jotai-urql/-/jotai-urql-0.7.1.tgz", - "integrity": "sha512-b1CJcCY/i/0C9viEniuUD1rSqV17SxOUrxCmPPDzDavGPV3bZQYtu2QKS4gj6Y95YOhTbv92hzWUwEUyNQt8IQ==", - "peerDependencies": { - "@urql/core": "*", - "jotai": ">=1.11.0" - } - }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -17891,7 +17573,8 @@ "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true }, "node_modules/json-schema-traverse": { "version": "0.4.1", @@ -17954,66 +17637,6 @@ "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==", "dev": true }, - "node_modules/jsondiffpatch": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsondiffpatch/-/jsondiffpatch-0.5.0.tgz", - "integrity": "sha512-Quz3MvAwHxVYNXsOByL7xI5EB2WYOeFswqaHIA3qOK3isRWTxiplBEocmmru6XmxDB2L7jDNYtYA4FyimoAFEw==", - "dependencies": { - "chalk": "^3.0.0", - "diff-match-patch": "^1.0.0" - }, - "bin": { - "jsondiffpatch": "bin/jsondiffpatch" - }, - "engines": { - "node": ">=8.17.0" - } - }, - "node_modules/jsondiffpatch/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jsondiffpatch/node_modules/chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jsondiffpatch/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/jsondiffpatch/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/jsonfile": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", @@ -18152,7 +17775,8 @@ "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true }, "node_modules/listr2": { "version": "4.0.5", @@ -18265,11 +17889,6 @@ "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", "dev": true }, - "node_modules/lodash.curry": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.curry/-/lodash.curry-4.1.1.tgz", - "integrity": "sha512-/u14pXGviLaweY5JI0IUzgzF2J6Ne8INyzAZjImcryjgkZ+ebruBxy2/JaOOkTqScddcYtakjhSaeemV8lR0tA==" - }, "node_modules/lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", @@ -19643,6 +19262,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, "dependencies": { "callsites": "^3.0.0" }, @@ -19668,6 +19288,7 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, "dependencies": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", @@ -19770,7 +19391,8 @@ "node_modules/path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true }, "node_modules/path-posix": { "version": "1.0.0", @@ -19834,6 +19456,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, "engines": { "node": ">=8" } @@ -20268,14 +19891,6 @@ "node": ">= 0.8" } }, - "node_modules/prism-react-renderer": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/prism-react-renderer/-/prism-react-renderer-1.3.5.tgz", - "integrity": "sha512-IJ+MSwBWKG+SM3b2SUfdrhC+gu01QkV2KmRQgREThBfSQRoufqRfxfHUxpG1WcaFjP+kojcFyO9Qqtpgt3qLCg==", - "peerDependencies": { - "react": ">=0.14.9" - } - }, "node_modules/process": { "version": "0.11.10", "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", @@ -20610,20 +20225,6 @@ "node": ">=0.10.0" } }, - "node_modules/react-base16-styling": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/react-base16-styling/-/react-base16-styling-0.9.1.tgz", - "integrity": "sha512-1s0CY1zRBOQ5M3T61wetEpvQmsYSNtWEcdYzyZNxKa8t7oDvaOn9d21xrGezGAHFWLM7SHcktPuPTrvoqxSfKw==", - "dependencies": { - "@babel/runtime": "^7.16.7", - "@types/base16": "^1.0.2", - "@types/lodash": "^4.14.178", - "base16": "^1.0.0", - "color": "^3.2.1", - "csstype": "^3.0.10", - "lodash.curry": "^4.1.1" - } - }, "node_modules/react-colorful": { "version": "5.6.1", "resolved": "https://registry.npmjs.org/react-colorful/-/react-colorful-5.6.1.tgz", @@ -20718,17 +20319,6 @@ "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", "dev": true }, - "node_modules/react-error-boundary": { - "version": "4.0.12", - "resolved": "https://registry.npmjs.org/react-error-boundary/-/react-error-boundary-4.0.12.tgz", - "integrity": "sha512-kJdxdEYlb7CPC1A0SeUY38cHpjuu6UkvzKiAmqmOFL21VRfMhOcWxTCBgLVCO0VEMh9JhFNcVaXlV4/BTpiwOA==", - "dependencies": { - "@babel/runtime": "^7.12.5" - }, - "peerDependencies": { - "react": ">=16.13.1" - } - }, "node_modules/react-i18next": { "version": "14.0.5", "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-14.0.5.tgz", @@ -20753,21 +20343,8 @@ "node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - }, - "node_modules/react-json-tree": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/react-json-tree/-/react-json-tree-0.18.0.tgz", - "integrity": "sha512-Qe6HKSXrr++n9Y31nkRJ3XvQMATISpqigH1vEKhLwB56+nk5thTP0ITThpjxY6ZG/ubpVq/aEHIcyLP/OPHxeA==", - "dependencies": { - "@babel/runtime": "^7.20.6", - "@types/lodash": "^4.14.191", - "react-base16-styling": "^0.9.1" - }, - "peerDependencies": { - "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" - } + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true }, "node_modules/react-refresh": { "version": "0.14.0", @@ -20823,15 +20400,6 @@ } } }, - "node_modules/react-resizable-panels": { - "version": "0.0.54", - "resolved": "https://registry.npmjs.org/react-resizable-panels/-/react-resizable-panels-0.0.54.tgz", - "integrity": "sha512-f8hHdQrqvXoiZGdRNuoOi/C2cdYT2nEpaOb1KIWVWorSTPZmnE+ZQiamGeu+AMx3iZ/tqBtlAkBOpKXzTnDCoA==", - "peerDependencies": { - "react": "^16.14.0 || ^17.0.0 || ^18.0.0", - "react-dom": "^16.14.0 || ^17.0.0 || ^18.0.0" - } - }, "node_modules/react-shallow-renderer": { "version": "16.15.0", "resolved": "https://registry.npmjs.org/react-shallow-renderer/-/react-shallow-renderer-16.15.0.tgz", @@ -20887,22 +20455,6 @@ "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", "dev": true }, - "node_modules/react-textarea-autosize": { - "version": "8.3.4", - "resolved": "https://registry.npmjs.org/react-textarea-autosize/-/react-textarea-autosize-8.3.4.tgz", - "integrity": "sha512-CdtmP8Dc19xL8/R6sWvtknD/eCXkQr30dtvC4VmGInhRsfF8X/ihXCq6+9l9qbxmKRiq407/7z5fxE7cVWQNgQ==", - "dependencies": { - "@babel/runtime": "^7.10.2", - "use-composed-ref": "^1.3.0", - "use-latest": "^1.2.1" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" - } - }, "node_modules/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -21065,12 +20617,6 @@ "node": ">=0.10.0" } }, - "node_modules/redux": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", - "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==", - "peer": true - }, "node_modules/reflect.getprototypeof": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.5.tgz", @@ -21304,6 +20850,7 @@ "version": "1.22.8", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", @@ -21763,19 +21310,6 @@ "integrity": "sha512-6+eerH9fEnNmi/hyM1DXcRK3pWdoMQtlkQ+ns0ntzunjKqp5i3sKCc80ym8Fib3iaYhdJUOPdhlJWj1tvge2Ww==", "dev": true }, - "node_modules/simple-swizzle": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", - "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", - "dependencies": { - "is-arrayish": "^0.3.1" - } - }, - "node_modules/simple-swizzle/node_modules/is-arrayish": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", - "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" - }, "node_modules/sisteransi": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", @@ -21845,14 +21379,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/source-map-js": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", @@ -22307,11 +21833,6 @@ "node": ">=0.4.0" } }, - "node_modules/stylis": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", - "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==" - }, "node_modules/sucrase": { "version": "3.35.0", "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", @@ -22380,6 +21901,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, "engines": { "node": ">= 0.4" }, @@ -22579,11 +22101,6 @@ "url": "https://opencollective.com/unts" } }, - "node_modules/tabbable": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz", - "integrity": "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==" - }, "node_modules/tailwindcss": { "version": "3.4.1", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.1.tgz", @@ -22908,8 +22425,12 @@ "node_modules/tiny-invariant": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.1.tgz", - "integrity": "sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw==", - "dev": true + "integrity": "sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw==" + }, + "node_modules/tiny-warning": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", + "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" }, "node_modules/tinybench": { "version": "2.6.0", @@ -22966,6 +22487,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true, "engines": { "node": ">=4" } @@ -23582,43 +23104,6 @@ } } }, - "node_modules/use-composed-ref": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/use-composed-ref/-/use-composed-ref-1.3.0.tgz", - "integrity": "sha512-GLMG0Jc/jiKov/3Ulid1wbv3r54K9HlMW29IWcDFPEqFkSO2nS0MuefWgMJpeHQ9YJeXDL3ZUF+P3jdXlZX/cQ==", - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" - } - }, - "node_modules/use-isomorphic-layout-effect": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz", - "integrity": "sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==", - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/use-latest": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/use-latest/-/use-latest-1.2.1.tgz", - "integrity": "sha512-xA+AVm/Wlg3e2P/JiItTziwS7FK92LWrDB0p+hgXloIMuVCeJJ8v6f0eeHyPZaJrM+usM1FkFfbNCrJGs8A/zw==", - "dependencies": { - "use-isomorphic-layout-effect": "^1.1.1" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, "node_modules/use-resize-observer": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/use-resize-observer/-/use-resize-observer-9.1.0.tgz", @@ -23653,6 +23138,14 @@ } } }, + "node_modules/use-sync-external-store": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", + "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/util": { "version": "0.12.5", "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", @@ -25179,6 +24672,14 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zod": { + "version": "3.22.4", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.22.4.tgz", + "integrity": "sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } } } } diff --git a/frontend/package.json b/frontend/package.json index 975e6ba0..6ee2a32e 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -16,10 +16,10 @@ "i18n": "i18next" }, "dependencies": { - "@emotion/react": "^11.11.3", "@fontsource/inconsolata": "^5.0.16", "@fontsource/inter": "^5.0.16", "@radix-ui/react-alert-dialog": "^1.0.5", + "@tanstack/react-router": "^1.16.2", "@types/ua-parser-js": "^0.7.39", "@urql/core": "^4.2.3", "@urql/devtools": "^2.0.3", @@ -35,14 +35,12 @@ "i18next": "^23.8.2", "i18next-browser-languagedetector": "^7.2.0", "i18next-http-backend": "^2.4.3", - "jotai": "^2.6.4", - "jotai-devtools": "^0.7.1", - "jotai-location": "^0.5.2", "react": "^18.2.0", "react-dom": "^18.2.0", "react-i18next": "^14.0.5", "ua-parser-js": "^1.0.37", - "urql": "^4.0.6" + "urql": "^4.0.6", + "zod": "^3.22.4" }, "devDependencies": { "@graphql-codegen/cli": "^5.0.2", @@ -52,6 +50,8 @@ "@storybook/addon-essentials": "^7.6.13", "@storybook/react": "^7.6.13", "@storybook/react-vite": "^7.6.13", + "@tanstack/router-devtools": "^1.16.2", + "@tanstack/router-vite-plugin": "^1.16.3", "@testing-library/react": "^14.2.1", "@types/node": "^20.11.17", "@types/react": "^18.2.55", diff --git a/frontend/schema.graphql b/frontend/schema.graphql index 39c9ab63..e8a30b21 100644 --- a/frontend/schema.graphql +++ b/frontend/schema.graphql @@ -894,6 +894,14 @@ type Query { """ browserSession(id: ID!): BrowserSession """ + Fetch a compatible session by its ID. + """ + compatSession(id: ID!): CompatSession + """ + Fetch an OAuth 2.0 session by its ID. + """ + oauth2Session(id: ID!): Oauth2Session + """ Fetch a user email by its ID. """ userEmail(id: ID!): UserEmail diff --git a/frontend/src/atoms.ts b/frontend/src/atoms.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/frontend/src/components/BrowserSession.tsx b/frontend/src/components/BrowserSession.tsx index 8d0e3884..75a5b792 100644 --- a/frontend/src/components/BrowserSession.tsx +++ b/frontend/src/components/BrowserSession.tsx @@ -99,7 +99,6 @@ const BrowserSession: React.FC = ({ session }) => { deviceType={deviceInformation?.deviceType} lastActiveIp={data.lastActiveIp || undefined} lastActiveAt={lastActiveAt} - link={{ type: "browser-session", id: data.id }} > {!data.finishedAt && } diff --git a/frontend/src/components/BrowserSessionList.tsx b/frontend/src/components/BrowserSessionList.tsx index fb688e34..1f398da4 100644 --- a/frontend/src/components/BrowserSessionList.tsx +++ b/frontend/src/components/BrowserSessionList.tsx @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +import { notFound } from "@tanstack/react-router"; import { useState, useTransition } from "react"; import { useQuery } from "urql"; @@ -26,44 +27,46 @@ import SessionListHeader from "./SessionList/SessionListHeader"; const QUERY = graphql(/* GraphQL */ ` query BrowserSessionList( - $userId: ID! $state: SessionState $first: Int $after: String $last: Int $before: String ) { - user(id: $userId) { - id - browserSessions( - first: $first - after: $after - last: $last - before: $before - state: $state - ) { - totalCount + viewer { + __typename + ... on User { + id + browserSessions( + first: $first + after: $after + last: $last + before: $before + state: $state + ) { + totalCount - edges { - cursor - node { - id - ...BrowserSession_session + edges { + cursor + node { + id + ...BrowserSession_session + } } - } - pageInfo { - hasNextPage - hasPreviousPage - startCursor - endCursor + pageInfo { + hasNextPage + hasPreviousPage + startCursor + endCursor + } } } } } `); -const BrowserSessionList: React.FC<{ userId: string }> = ({ userId }) => { +const BrowserSessionList: React.FC = () => { const [pagination, setPagination] = usePagination(); const [pending, startTransition] = useTransition(); const [filter, setFilter] = useState( @@ -71,11 +74,12 @@ const BrowserSessionList: React.FC<{ userId: string }> = ({ userId }) => { ); const [result] = useQuery({ query: QUERY, - variables: { userId, state: filter, ...pagination }, + variables: { state: filter, ...pagination }, }); if (result.error) throw result.error; - const browserSessions = result.data?.user?.browserSessions; - if (!browserSessions) throw new Error(); // Suspense mode is enabled + const user = result.data?.viewer; + if (user?.__typename !== "User") throw notFound(); + const browserSessions = user.browserSessions; const [prevPage, nextPage] = usePages(pagination, browserSessions.pageInfo); diff --git a/frontend/src/components/CompatSession.test.tsx b/frontend/src/components/CompatSession.test.tsx index ce8721f2..e65c38db 100644 --- a/frontend/src/components/CompatSession.test.tsx +++ b/frontend/src/components/CompatSession.test.tsx @@ -20,8 +20,8 @@ import { describe, expect, it, beforeAll } from "vitest"; import { never } from "wonka"; import { makeFragmentData } from "../gql"; -import { WithLocation } from "../test-utils/WithLocation"; import { mockLocale } from "../test-utils/mockLocale"; +import { DummyRouter } from "../test-utils/router"; import CompatSession, { FRAGMENT } from "./CompatSession"; @@ -49,9 +49,9 @@ describe("", () => { const session = makeFragmentData(baseSession, FRAGMENT); const component = create( - + - + , ); expect(component.toJSON()).toMatchSnapshot(); @@ -67,9 +67,9 @@ describe("", () => { ); const component = create( - + - + , ); expect(component.toJSON()).toMatchSnapshot(); diff --git a/frontend/src/components/CompatSession.tsx b/frontend/src/components/CompatSession.tsx index 47e1b4fe..cdb4bf52 100644 --- a/frontend/src/components/CompatSession.tsx +++ b/frontend/src/components/CompatSession.tsx @@ -48,7 +48,7 @@ export const END_SESSION_MUTATION = graphql(/* GraphQL */ ` `); export const simplifyUrl = (url: string): string => { - let parsed; + let parsed: URL; try { parsed = new URL(url); } catch (e) { @@ -97,7 +97,6 @@ const CompatSession: React.FC<{ clientName={clientName} lastActiveIp={data.lastActiveIp || undefined} lastActiveAt={lastActiveAt} - link={{ type: "session", id: data.deviceId }} > {!data.finishedAt && } diff --git a/frontend/src/components/ErrorBoundary.tsx b/frontend/src/components/ErrorBoundary.tsx index 73ab2807..f92793cd 100644 --- a/frontend/src/components/ErrorBoundary.tsx +++ b/frontend/src/components/ErrorBoundary.tsx @@ -12,12 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { CombinedError } from "@urql/core"; -import { Alert } from "@vector-im/compound-web"; import { ErrorInfo, ReactNode, PureComponent } from "react"; -import { Translation } from "react-i18next"; -import GraphQLError from "./GraphQLError"; +import GenericError from "./GenericError"; +import Layout from "./Layout"; interface Props { children: ReactNode; @@ -27,9 +25,6 @@ interface IState { error?: Error; } -const isGqlError = (error: Error): error is CombinedError => - error.name === "CombinedError"; - /** * This error boundary component can be used to wrap large content areas and * catch exceptions during rendering in the component tree below them. @@ -57,18 +52,10 @@ export default class ErrorBoundary extends PureComponent { public render(): ReactNode { if (this.state.error) { - if (isGqlError(this.state.error)) { - return ; - } - return ( - - {(t): ReactNode => ( - - {this.state.error!.message} - - )} - + + + ); } diff --git a/frontend/src/components/GenericError.module.css b/frontend/src/components/GenericError.module.css new file mode 100644 index 00000000..f17e258b --- /dev/null +++ b/frontend/src/components/GenericError.module.css @@ -0,0 +1,49 @@ +/* Copyright 2024 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +.error { + display: flex; + flex-direction: column; + gap: var(--cpd-space-4x); +} + +.message { + display: flex; + flex-direction: column; + gap: var(--cpd-space-2x); + text-align: center; + + &>p { + color: var(--cpd-color-text-secondary); + } +} + +.icon { + align-self: center; + height: var(--cpd-space-16x); + width: var(--cpd-space-16x); + padding: var(--cpd-space-3x); + border-radius: var(--cpd-space-2x); + background-color: var(--cpd-color-bg-critical-subtle); + color: var(--cpd-color-icon-critical-primary); +} + +.details { + font: var(--cpd-font-body-sm-regular); + background: var(--cpd-color-bg-critical-subtle); + border: 1px solid var(--cpd-color-border-critical-subtle); + padding: var(--cpd-space-4x); + text-align: initial; +} diff --git a/frontend/src/components/GenericError.tsx b/frontend/src/components/GenericError.tsx new file mode 100644 index 00000000..4b00ca42 --- /dev/null +++ b/frontend/src/components/GenericError.tsx @@ -0,0 +1,46 @@ +// Copyright 2024 The Matrix.org Foundation C.I.C. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import IconError from "@vector-im/compound-design-tokens/icons/error.svg?react"; +import { Button, H2, Text } from "@vector-im/compound-web"; +import { useState } from "react"; +import { useTranslation } from "react-i18next"; + +import styles from "./GenericError.module.css"; + +const GenericError: React.FC<{ error: unknown }> = ({ error }) => { + const { t } = useTranslation(); + const [open, setOpen] = useState(false); + return ( +
+ +
+

{t("frontend.error.title")}

+ {t("frontend.error.subtitle")} +
+ + {open && ( +
+          {String(error)}
+        
+ )} +
+ ); +}; + +export default GenericError; diff --git a/frontend/src/components/GraphQLError.tsx b/frontend/src/components/GraphQLError.tsx deleted file mode 100644 index b2889625..00000000 --- a/frontend/src/components/GraphQLError.tsx +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2023 The Matrix.org Foundation C.I.C. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import { CombinedError } from "@urql/core"; -import { Alert } from "@vector-im/compound-web"; - -const GraphQLError: React.FC<{ error: CombinedError }> = ({ error }) => ( - - {error.toString()} - -); - -export default GraphQLError; diff --git a/frontend/src/components/Layout/Layout.test.tsx b/frontend/src/components/Layout/Layout.test.tsx deleted file mode 100644 index d1c03aef..00000000 --- a/frontend/src/components/Layout/Layout.test.tsx +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2023 The Matrix.org Foundation C.I.C. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// @vitest-environment happy-dom - -import { render } from "@testing-library/react"; -import { Provider } from "urql"; -import { describe, expect, it } from "vitest"; -import { never } from "wonka"; - -import { WithLocation } from "../../test-utils/WithLocation"; - -import Layout from "./Layout"; - -describe("", () => { - it("renders app navigation correctly", async () => { - const mockClient = { - executeQuery: (): typeof never => never, - }; - - const component = render( - - - - - , - ); - - expect(await component.findByText("Profile")).toMatchSnapshot(); - expect(await component.findByText("Sessions")).toMatchSnapshot(); - }); -}); diff --git a/frontend/src/components/Layout/Layout.tsx b/frontend/src/components/Layout/Layout.tsx index 9ddbb2f4..87917f6e 100644 --- a/frontend/src/components/Layout/Layout.tsx +++ b/frontend/src/components/Layout/Layout.tsx @@ -12,45 +12,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { useAtomValue } from "jotai"; -import { useTranslation } from "react-i18next"; - -import { appConfigAtom, routeAtom } from "../../routing"; +import appConfig from "../../config"; import Footer from "../Footer"; -import NavBar from "../NavBar"; -import NavItem from "../NavItem"; -import UserGreeting from "../UserGreeting"; import styles from "./Layout.module.css"; const Layout: React.FC<{ - userId: string; children?: React.ReactNode; -}> = ({ userId, children }) => { - const route = useAtomValue(routeAtom); - const appConfig = useAtomValue(appConfigAtom); - const { t } = useTranslation(); - - // Hide the nav bar & user greeting on the verify-email page - const shouldHideNavBar = route.type === "verify-email"; - +}> = ({ children }) => { return (
- {shouldHideNavBar ? null : ( - <> - - - - - {t("frontend.nav.profile")} - - - {t("frontend.nav.sessions")} - - - - )} - {children}