From 46648db093e86185fc9e14c593a3c78b39c2ec8a Mon Sep 17 00:00:00 2001 From: Pierre HUBERT Date: Mon, 29 Apr 2024 22:14:16 +0200 Subject: [PATCH] Managed to load server configuration from WebUI --- remote_backend/Cargo.lock | 16 + remote_backend/Cargo.toml | 1 + remote_backend/src/app_config.rs | 2 +- remote_backend/src/controllers/mod.rs | 1 + .../src/controllers/server_controller.rs | 17 + remote_backend/src/main.rs | 18 +- remote_frontend/.env | 1 + remote_frontend/package-lock.json | 1797 ++++++++++++++++- remote_frontend/package.json | 1 + remote_frontend/src/App.tsx | 15 +- remote_frontend/src/api/ApiClient.ts | 174 ++ remote_frontend/src/api/ServerApi.ts | 30 + remote_frontend/src/index.css | 11 +- remote_frontend/src/main.tsx | 11 +- remote_frontend/src/widgets/AsyncWidget.tsx | 77 + 15 files changed, 2159 insertions(+), 13 deletions(-) create mode 100644 remote_backend/src/controllers/server_controller.rs create mode 100644 remote_frontend/.env create mode 100644 remote_frontend/src/api/ApiClient.ts create mode 100644 remote_frontend/src/api/ServerApi.ts create mode 100644 remote_frontend/src/widgets/AsyncWidget.tsx diff --git a/remote_backend/Cargo.lock b/remote_backend/Cargo.lock index 01fcf6b..379cb9d 100644 --- a/remote_backend/Cargo.lock +++ b/remote_backend/Cargo.lock @@ -19,6 +19,21 @@ dependencies = [ "tracing", ] +[[package]] +name = "actix-cors" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9e772b3bcafe335042b5db010ab7c09013dad6eac4915c91d8d50902769f331" +dependencies = [ + "actix-utils", + "actix-web", + "derive_more", + "futures-util", + "log", + "once_cell", + "smallvec", +] + [[package]] name = "actix-http" version = "3.6.0" @@ -1691,6 +1706,7 @@ checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" name = "remote_backend" version = "0.1.0" dependencies = [ + "actix-cors", "actix-identity", "actix-remote-ip", "actix-session", diff --git a/remote_backend/Cargo.toml b/remote_backend/Cargo.toml index 6c19633..017eb44 100644 --- a/remote_backend/Cargo.toml +++ b/remote_backend/Cargo.toml @@ -16,6 +16,7 @@ actix-web = "4.5.1" actix-remote-ip = "0.1.0" actix-session = { version = "0.9.0", features = ["cookie-session"] } actix-identity = "0.7.1" +actix-cors = "0.7.0" lazy_static = "1.4.0" anyhow = "1.0.82" reqwest = { version = "0.12.4", features = ["json"] } diff --git a/remote_backend/src/app_config.rs b/remote_backend/src/app_config.rs index c3d565e..115ec6a 100644 --- a/remote_backend/src/app_config.rs +++ b/remote_backend/src/app_config.rs @@ -10,7 +10,7 @@ pub struct AppConfig { pub listen_address: String, /// Website main origin - #[clap(short, long, env, default_value = "http://localhost:3000")] + #[clap(short, long, env, default_value = "http://localhost:5173")] pub website_origin: String, /// Proxy IP, might end with a star "*" diff --git a/remote_backend/src/controllers/mod.rs b/remote_backend/src/controllers/mod.rs index 7a1fb5e..128ba83 100644 --- a/remote_backend/src/controllers/mod.rs +++ b/remote_backend/src/controllers/mod.rs @@ -6,6 +6,7 @@ use std::fmt::{Display, Formatter}; use std::io::ErrorKind; pub mod auth_controller; +pub mod server_controller; /// Custom error to ease controller writing #[derive(Debug)] diff --git a/remote_backend/src/controllers/server_controller.rs b/remote_backend/src/controllers/server_controller.rs new file mode 100644 index 0000000..ffb2006 --- /dev/null +++ b/remote_backend/src/controllers/server_controller.rs @@ -0,0 +1,17 @@ +use crate::app_config::AppConfig; +use crate::controllers::HttpResult; +use crate::extractors::auth_extractor::AuthExtractor; +use actix_web::HttpResponse; + +#[derive(serde::Serialize)] +struct ServerConfig { + authenticated: bool, + disable_auth: bool, +} + +pub async fn config(auth: AuthExtractor) -> HttpResult { + Ok(HttpResponse::Ok().json(ServerConfig { + authenticated: auth.is_authenticated(), + disable_auth: AppConfig::get().unsecure_disable_login, + })) +} diff --git a/remote_backend/src/main.rs b/remote_backend/src/main.rs index 2f489fc..92453cd 100644 --- a/remote_backend/src/main.rs +++ b/remote_backend/src/main.rs @@ -1,3 +1,4 @@ +use actix_cors::Cors; use actix_identity::config::LogoutBehaviour; use actix_identity::IdentityMiddleware; use actix_remote_ip::RemoteIPConfig; @@ -9,9 +10,9 @@ use actix_web::web::Data; use actix_web::{web, App, HttpServer}; use light_openid::basic_state_manager::BasicStateManager; use remote_backend::app_config::AppConfig; -use remote_backend::controllers::auth_controller; +use remote_backend::constants; +use remote_backend::controllers::{auth_controller, server_controller}; use remote_backend::middlewares::auth_middleware::AuthChecker; -use remote_backend::{constants, virtweb_client}; use std::time::Duration; #[actix_web::main] @@ -40,15 +41,28 @@ async fn main() -> std::io::Result<()> { .login_deadline(Some(Duration::from_secs(constants::MAX_SESSION_DURATION))) .build(); + let cors = Cors::default() + .allowed_origin(&AppConfig::get().website_origin) + .allowed_methods(vec!["GET", "POST", "PUT", "PATCH", "DELETE"]) + .allowed_header("X-Auth-Token") + .allow_any_header() + .supports_credentials() + .max_age(3600); + App::new() .wrap(Logger::default()) .wrap(AuthChecker) .wrap(identity_middleware) .wrap(session_mw) + .wrap(cors) .app_data(state_manager.clone()) .app_data(Data::new(RemoteIPConfig { proxy: AppConfig::get().proxy_ip.clone(), })) + .route( + "/api/server/config", + web::get().to(server_controller::config), + ) .route( "/api/auth/start_oidc", web::get().to(auth_controller::start_oidc), diff --git a/remote_frontend/.env b/remote_frontend/.env new file mode 100644 index 0000000..264f577 --- /dev/null +++ b/remote_frontend/.env @@ -0,0 +1 @@ +VITE_APP_BACKEND=http://localhost:8002/api diff --git a/remote_frontend/package-lock.json b/remote_frontend/package-lock.json index e503763..5ec1cd8 100644 --- a/remote_frontend/package-lock.json +++ b/remote_frontend/package-lock.json @@ -8,6 +8,7 @@ "name": "remote_frontend", "version": "0.0.0", "dependencies": { + "@fluentui/react-components": "^9.49.0", "react": "^18.2.0", "react-dom": "^18.2.0" }, @@ -334,6 +335,17 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/runtime": { + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.5.tgz", + "integrity": "sha512-Nms86NXrsaeU9vbBJKni6gXiEXZ4CVpYVzEjDH9Sb8vmZ3UljyA1GSOJl/6LGPO8EHLuSF9H+IxNXHPX8QHJ4g==", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/template": { "version": "7.24.0", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.0.tgz", @@ -383,6 +395,11 @@ "node": ">=6.9.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/@esbuild/aix-ppc64": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz", @@ -844,6 +861,1662 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@floating-ui/core": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.1.tgz", + "integrity": "sha512-42UH54oPZHPdRHdw6BgoBD6cg/eVTmVrFcgeRDM3jbO7uxSoipVcmcIGFcA5jmOHO5apcyvBhkSKES3fQJnu7A==", + "dependencies": { + "@floating-ui/utils": "^0.2.0" + } + }, + "node_modules/@floating-ui/devtools": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@floating-ui/devtools/-/devtools-0.2.1.tgz", + "integrity": "sha512-8PHJLbD6VhBh+LJ1uty/Bz30qs02NXCE5u8WpOhSewlYXUWl03GNXknr9AS2yaAWJEQaY27x7eByJs44gODBcw==", + "peerDependencies": { + "@floating-ui/dom": ">=1.5.4" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.4.tgz", + "integrity": "sha512-0G8R+zOvQsAG1pg2Q99P21jiqxqGBW1iRe/iXHsBRBxnpXKFI8QwbB4x5KmYLggNO5m34IQgOIu9SCRfR/WWiQ==", + "dependencies": { + "@floating-ui/core": "^1.0.0", + "@floating-ui/utils": "^0.2.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.2.tgz", + "integrity": "sha512-J4yDIIthosAsRZ5CPYP/jQvUAQtlZTTD/4suA08/FEnlxqW3sKS9iAhgsa9VYLZ6vDHn/ixJgIqRQPotoBjxIw==" + }, + "node_modules/@fluentui/keyboard-keys": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/@fluentui/keyboard-keys/-/keyboard-keys-9.0.7.tgz", + "integrity": "sha512-vaQ+lOveQTdoXJYqDQXWb30udSfTVcIuKk1rV0X0eGAgcHeSDeP1HxMy+OgHOQZH3OiBH4ZYeWxb+tmfiDiygQ==", + "dependencies": { + "@swc/helpers": "^0.5.1" + } + }, + "node_modules/@fluentui/priority-overflow": { + "version": "9.1.11", + "resolved": "https://registry.npmjs.org/@fluentui/priority-overflow/-/priority-overflow-9.1.11.tgz", + "integrity": "sha512-sdrpavvKX2kepQ1d6IaI3ObLq5SAQBPRHPGx2+wiMWL7cEx9vGGM0fmeicl3soqqmM5uwCmWnZk9QZv9XOY98w==", + "dependencies": { + "@swc/helpers": "^0.5.1" + } + }, + "node_modules/@fluentui/react-accordion": { + "version": "9.3.50", + "resolved": "https://registry.npmjs.org/@fluentui/react-accordion/-/react-accordion-9.3.50.tgz", + "integrity": "sha512-I/dL89nrNC9BzjzTsXRApaQMpmegdSZ4ofh4vpbTJ/ZohHPBKTjpPzgPFuSRsUPY3ZUX0P5q4Xb5MpObLY+t0g==", + "dependencies": { + "@fluentui/react-aria": "^9.10.5", + "@fluentui/react-context-selector": "^9.1.58", + "@fluentui/react-icons": "^2.0.235", + "@fluentui/react-jsx-runtime": "^9.0.36", + "@fluentui/react-shared-contexts": "^9.17.0", + "@fluentui/react-tabster": "^9.20.1", + "@fluentui/react-theme": "^9.1.19", + "@fluentui/react-utilities": "^9.18.7", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-accordion/node_modules/@fluentui/react-context-selector": { + "version": "9.1.58", + "resolved": "https://registry.npmjs.org/@fluentui/react-context-selector/-/react-context-selector-9.1.58.tgz", + "integrity": "sha512-XFL+X09+AABkC1D/4P20e+AbU+hG3+AiivA2+ZW+6Lqpg2RmYe5a9AhZdMCD0Desyq2BoKurYNyNOmI3OPJF8w==", + "dependencies": { + "@fluentui/react-utilities": "^9.18.7", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0", + "scheduler": ">=0.19.0 <=0.23.0" + } + }, + "node_modules/@fluentui/react-accordion/node_modules/scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/@fluentui/react-alert": { + "version": "9.0.0-beta.117", + "resolved": "https://registry.npmjs.org/@fluentui/react-alert/-/react-alert-9.0.0-beta.117.tgz", + "integrity": "sha512-vZYEyILCKN8XpUB+bk4a7OoDI23vtD5IR4g2Fm6OHqEGxauQPEUTCFK6Ogxt85mQLce0pWEK75p5dVkWOvCzWw==", + "dependencies": { + "@fluentui/react-avatar": "^9.6.22", + "@fluentui/react-button": "^9.3.76", + "@fluentui/react-icons": "^2.0.235", + "@fluentui/react-jsx-runtime": "^9.0.36", + "@fluentui/react-tabster": "^9.20.1", + "@fluentui/react-theme": "^9.1.19", + "@fluentui/react-utilities": "^9.18.7", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-aria": { + "version": "9.10.5", + "resolved": "https://registry.npmjs.org/@fluentui/react-aria/-/react-aria-9.10.5.tgz", + "integrity": "sha512-mltw1Kelz31UxeZXlQpmX5eW4UUQBRQm4OLTlM4YDiDNe1N3Qd63cUIDGhgn0MvCvwVpIryOO89jj+RJGXkpkA==", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.7", + "@fluentui/react-jsx-runtime": "^9.0.36", + "@fluentui/react-shared-contexts": "^9.17.0", + "@fluentui/react-tabster": "^9.20.1", + "@fluentui/react-utilities": "^9.18.7", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-avatar": { + "version": "9.6.22", + "resolved": "https://registry.npmjs.org/@fluentui/react-avatar/-/react-avatar-9.6.22.tgz", + "integrity": "sha512-AYK2Ak4DhbUTDIHvde1DQ9NLSx/iOq2GduDOI6tIwUxVMmqrjF+ec+DxJLjtdrBK6RCnYtvb5F4fMezySBZrPQ==", + "dependencies": { + "@fluentui/react-badge": "^9.2.32", + "@fluentui/react-context-selector": "^9.1.58", + "@fluentui/react-icons": "^2.0.235", + "@fluentui/react-jsx-runtime": "^9.0.36", + "@fluentui/react-popover": "^9.9.5", + "@fluentui/react-shared-contexts": "^9.17.0", + "@fluentui/react-tabster": "^9.20.1", + "@fluentui/react-theme": "^9.1.19", + "@fluentui/react-tooltip": "^9.4.24", + "@fluentui/react-utilities": "^9.18.7", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-avatar/node_modules/@fluentui/react-context-selector": { + "version": "9.1.58", + "resolved": "https://registry.npmjs.org/@fluentui/react-context-selector/-/react-context-selector-9.1.58.tgz", + "integrity": "sha512-XFL+X09+AABkC1D/4P20e+AbU+hG3+AiivA2+ZW+6Lqpg2RmYe5a9AhZdMCD0Desyq2BoKurYNyNOmI3OPJF8w==", + "dependencies": { + "@fluentui/react-utilities": "^9.18.7", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0", + "scheduler": ">=0.19.0 <=0.23.0" + } + }, + "node_modules/@fluentui/react-avatar/node_modules/scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/@fluentui/react-badge": { + "version": "9.2.32", + "resolved": "https://registry.npmjs.org/@fluentui/react-badge/-/react-badge-9.2.32.tgz", + "integrity": "sha512-fqO8Mlg129h3yuYwodVk4bj02fe9ryiA+37MKMzajQSGrOJH1xnTzD+R8ngf8s1iEq5TUsy7dQXLyzGSxllhVw==", + "dependencies": { + "@fluentui/react-icons": "^2.0.235", + "@fluentui/react-jsx-runtime": "^9.0.36", + "@fluentui/react-shared-contexts": "^9.17.0", + "@fluentui/react-theme": "^9.1.19", + "@fluentui/react-utilities": "^9.18.7", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-breadcrumb": { + "version": "9.0.22", + "resolved": "https://registry.npmjs.org/@fluentui/react-breadcrumb/-/react-breadcrumb-9.0.22.tgz", + "integrity": "sha512-EGHbOwaInu7CJmCdd5V0jI88iC9/xQiCQYEwn8EaZpciSpv6AD1QMiwwdr9OHLq3Y4NgEZTDki8JD+fWbhlk8Q==", + "dependencies": { + "@fluentui/react-aria": "^9.10.5", + "@fluentui/react-button": "^9.3.76", + "@fluentui/react-icons": "^2.0.235", + "@fluentui/react-jsx-runtime": "^9.0.36", + "@fluentui/react-link": "^9.2.18", + "@fluentui/react-shared-contexts": "^9.17.0", + "@fluentui/react-tabster": "^9.20.1", + "@fluentui/react-theme": "^9.1.19", + "@fluentui/react-utilities": "^9.18.7", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-button": { + "version": "9.3.76", + "resolved": "https://registry.npmjs.org/@fluentui/react-button/-/react-button-9.3.76.tgz", + "integrity": "sha512-3ZsEjbRcNY3oEAjxCOuXg6JNtA6/jryMs/IKoP0b7yh8UyJsChRy9hhlRD8ms+f7OBfqLoUyz4WUfwV9eeQV8g==", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.7", + "@fluentui/react-aria": "^9.10.5", + "@fluentui/react-icons": "^2.0.235", + "@fluentui/react-jsx-runtime": "^9.0.36", + "@fluentui/react-shared-contexts": "^9.17.0", + "@fluentui/react-tabster": "^9.20.1", + "@fluentui/react-theme": "^9.1.19", + "@fluentui/react-utilities": "^9.18.7", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-card": { + "version": "9.0.75", + "resolved": "https://registry.npmjs.org/@fluentui/react-card/-/react-card-9.0.75.tgz", + "integrity": "sha512-AWtgjvKm0hRbnelIMfXZrPJ8kke2bGLKQhVTLcRybTjLh7aXHp/PPVtY5ktZODUp96VuAZkZl1yL3IxJLjldog==", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.7", + "@fluentui/react-jsx-runtime": "^9.0.36", + "@fluentui/react-tabster": "^9.20.1", + "@fluentui/react-theme": "^9.1.19", + "@fluentui/react-utilities": "^9.18.7", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-checkbox": { + "version": "9.2.21", + "resolved": "https://registry.npmjs.org/@fluentui/react-checkbox/-/react-checkbox-9.2.21.tgz", + "integrity": "sha512-oma+pLiLvtWonUiXUsJLXeIJ4fUIbd6TgvK6v5SFU+97loaQGsx+0TtayUBj1dCVVvoW/tjJebNtud92Ozz/qQ==", + "dependencies": { + "@fluentui/react-field": "^9.1.62", + "@fluentui/react-icons": "^2.0.235", + "@fluentui/react-jsx-runtime": "^9.0.36", + "@fluentui/react-label": "^9.1.68", + "@fluentui/react-shared-contexts": "^9.17.0", + "@fluentui/react-tabster": "^9.20.1", + "@fluentui/react-theme": "^9.1.19", + "@fluentui/react-utilities": "^9.18.7", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-combobox": { + "version": "9.10.1", + "resolved": "https://registry.npmjs.org/@fluentui/react-combobox/-/react-combobox-9.10.1.tgz", + "integrity": "sha512-RoXXtB7bKlT7JbuNP5mQxZMANbq2opT+vslNVhoOy5Gu8EJe1gxdNwKfug+NY/SC2N1SFBH1xdgsBzhPsGi38g==", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.7", + "@fluentui/react-aria": "^9.10.5", + "@fluentui/react-context-selector": "^9.1.58", + "@fluentui/react-field": "^9.1.62", + "@fluentui/react-icons": "^2.0.235", + "@fluentui/react-jsx-runtime": "^9.0.36", + "@fluentui/react-portal": "^9.4.21", + "@fluentui/react-positioning": "^9.14.4", + "@fluentui/react-shared-contexts": "^9.17.0", + "@fluentui/react-tabster": "^9.20.1", + "@fluentui/react-theme": "^9.1.19", + "@fluentui/react-utilities": "^9.18.7", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-combobox/node_modules/@fluentui/react-context-selector": { + "version": "9.1.58", + "resolved": "https://registry.npmjs.org/@fluentui/react-context-selector/-/react-context-selector-9.1.58.tgz", + "integrity": "sha512-XFL+X09+AABkC1D/4P20e+AbU+hG3+AiivA2+ZW+6Lqpg2RmYe5a9AhZdMCD0Desyq2BoKurYNyNOmI3OPJF8w==", + "dependencies": { + "@fluentui/react-utilities": "^9.18.7", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0", + "scheduler": ">=0.19.0 <=0.23.0" + } + }, + "node_modules/@fluentui/react-combobox/node_modules/scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/@fluentui/react-components": { + "version": "9.49.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-components/-/react-components-9.49.0.tgz", + "integrity": "sha512-7IRiUhdMlGcyAVHxnNTdj2l2WbEaXkHeETMkkLDxf3x7d8qwWkRcrRYm/Ds36aI37kBOYKwKjYNqaybDxq4WBw==", + "dependencies": { + "@fluentui/react-accordion": "^9.3.50", + "@fluentui/react-alert": "9.0.0-beta.117", + "@fluentui/react-aria": "^9.10.5", + "@fluentui/react-avatar": "^9.6.22", + "@fluentui/react-badge": "^9.2.32", + "@fluentui/react-breadcrumb": "^9.0.22", + "@fluentui/react-button": "^9.3.76", + "@fluentui/react-card": "^9.0.75", + "@fluentui/react-checkbox": "^9.2.21", + "@fluentui/react-combobox": "^9.10.1", + "@fluentui/react-dialog": "^9.10.1", + "@fluentui/react-divider": "^9.2.67", + "@fluentui/react-drawer": "^9.1.12", + "@fluentui/react-field": "^9.1.62", + "@fluentui/react-image": "^9.1.64", + "@fluentui/react-infobutton": "9.0.0-beta.101", + "@fluentui/react-infolabel": "^9.0.29", + "@fluentui/react-input": "^9.4.72", + "@fluentui/react-label": "^9.1.68", + "@fluentui/react-link": "^9.2.18", + "@fluentui/react-menu": "^9.14.0", + "@fluentui/react-message-bar": "^9.0.27", + "@fluentui/react-overflow": "^9.1.17", + "@fluentui/react-persona": "^9.2.81", + "@fluentui/react-popover": "^9.9.5", + "@fluentui/react-portal": "^9.4.21", + "@fluentui/react-positioning": "^9.14.4", + "@fluentui/react-progress": "^9.1.72", + "@fluentui/react-provider": "^9.14.0", + "@fluentui/react-radio": "^9.2.16", + "@fluentui/react-rating": "^9.0.4", + "@fluentui/react-search": "^9.0.1", + "@fluentui/react-select": "^9.1.72", + "@fluentui/react-shared-contexts": "^9.17.0", + "@fluentui/react-skeleton": "^9.1.0", + "@fluentui/react-slider": "^9.1.78", + "@fluentui/react-spinbutton": "^9.2.72", + "@fluentui/react-spinner": "^9.4.5", + "@fluentui/react-switch": "^9.1.78", + "@fluentui/react-table": "^9.15.0", + "@fluentui/react-tabs": "^9.4.17", + "@fluentui/react-tabster": "^9.20.1", + "@fluentui/react-tags": "^9.3.1", + "@fluentui/react-teaching-popover": "^9.1.0", + "@fluentui/react-text": "^9.4.16", + "@fluentui/react-textarea": "^9.3.72", + "@fluentui/react-theme": "^9.1.19", + "@fluentui/react-toast": "^9.3.38", + "@fluentui/react-toolbar": "^9.1.79", + "@fluentui/react-tooltip": "^9.4.24", + "@fluentui/react-tree": "^9.4.39", + "@fluentui/react-utilities": "^9.18.7", + "@fluentui/react-virtualizer": "9.0.0-alpha.75", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-dialog": { + "version": "9.10.1", + "resolved": "https://registry.npmjs.org/@fluentui/react-dialog/-/react-dialog-9.10.1.tgz", + "integrity": "sha512-xtNk5cuSFAqxAvFG8wbsyCDMjduRX7kpmOMym0jRveEiAnXirWApJlXtIbqGhQq1E13bHhcUrgk+rThYNj++0A==", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.7", + "@fluentui/react-aria": "^9.10.5", + "@fluentui/react-context-selector": "^9.1.58", + "@fluentui/react-icons": "^2.0.235", + "@fluentui/react-jsx-runtime": "^9.0.36", + "@fluentui/react-portal": "^9.4.21", + "@fluentui/react-shared-contexts": "^9.17.0", + "@fluentui/react-tabster": "^9.20.1", + "@fluentui/react-theme": "^9.1.19", + "@fluentui/react-utilities": "^9.18.7", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1", + "react-transition-group": "^4.4.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-dialog/node_modules/@fluentui/react-context-selector": { + "version": "9.1.58", + "resolved": "https://registry.npmjs.org/@fluentui/react-context-selector/-/react-context-selector-9.1.58.tgz", + "integrity": "sha512-XFL+X09+AABkC1D/4P20e+AbU+hG3+AiivA2+ZW+6Lqpg2RmYe5a9AhZdMCD0Desyq2BoKurYNyNOmI3OPJF8w==", + "dependencies": { + "@fluentui/react-utilities": "^9.18.7", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0", + "scheduler": ">=0.19.0 <=0.23.0" + } + }, + "node_modules/@fluentui/react-dialog/node_modules/scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/@fluentui/react-divider": { + "version": "9.2.67", + "resolved": "https://registry.npmjs.org/@fluentui/react-divider/-/react-divider-9.2.67.tgz", + "integrity": "sha512-+25KhiweeFQUW4PrqnkBhVgTktMSF+965Xlezjpp7848MYEb2SfyvJC2akeZ4bcZUwCyqth9RTv/4hKBdYXmOw==", + "dependencies": { + "@fluentui/react-jsx-runtime": "^9.0.36", + "@fluentui/react-shared-contexts": "^9.17.0", + "@fluentui/react-theme": "^9.1.19", + "@fluentui/react-utilities": "^9.18.7", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-drawer": { + "version": "9.1.12", + "resolved": "https://registry.npmjs.org/@fluentui/react-drawer/-/react-drawer-9.1.12.tgz", + "integrity": "sha512-YFIrKhcdi6seNjgNIC1P8VeajNFLlbYe1WRPJi0J/6fcQEQRBOfMpLgwUdqw4rXV/54U4+F5DI6q5t67i5jLGg==", + "dependencies": { + "@fluentui/react-dialog": "^9.10.1", + "@fluentui/react-jsx-runtime": "^9.0.36", + "@fluentui/react-motion-preview": "^0.5.19", + "@fluentui/react-shared-contexts": "^9.17.0", + "@fluentui/react-tabster": "^9.20.1", + "@fluentui/react-theme": "^9.1.19", + "@fluentui/react-utilities": "^9.18.7", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-field": { + "version": "9.1.62", + "resolved": "https://registry.npmjs.org/@fluentui/react-field/-/react-field-9.1.62.tgz", + "integrity": "sha512-p1x4NYdGO9CMOAQ9yqos0liSEb84i5tpTFXPgdSCyYrAcsFbBnblabgyg0hUtdtuuuZVKcHGE3M+vk8xaa0n+A==", + "dependencies": { + "@fluentui/react-context-selector": "^9.1.58", + "@fluentui/react-icons": "^2.0.235", + "@fluentui/react-jsx-runtime": "^9.0.36", + "@fluentui/react-label": "^9.1.68", + "@fluentui/react-theme": "^9.1.19", + "@fluentui/react-utilities": "^9.18.7", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-field/node_modules/@fluentui/react-context-selector": { + "version": "9.1.58", + "resolved": "https://registry.npmjs.org/@fluentui/react-context-selector/-/react-context-selector-9.1.58.tgz", + "integrity": "sha512-XFL+X09+AABkC1D/4P20e+AbU+hG3+AiivA2+ZW+6Lqpg2RmYe5a9AhZdMCD0Desyq2BoKurYNyNOmI3OPJF8w==", + "dependencies": { + "@fluentui/react-utilities": "^9.18.7", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0", + "scheduler": ">=0.19.0 <=0.23.0" + } + }, + "node_modules/@fluentui/react-field/node_modules/scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/@fluentui/react-icons": { + "version": "2.0.237", + "resolved": "https://registry.npmjs.org/@fluentui/react-icons/-/react-icons-2.0.237.tgz", + "integrity": "sha512-J+6XDB/Y3G3nfNWvKKI6xhUXDN6/xvhksnV+zfXiGb6tqtK7QiihAzvRRgPnKuS3BH/H1TM7k3KC19V0AJrTDg==", + "dependencies": { + "@griffel/react": "^1.0.0", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "react": ">=16.8.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-image": { + "version": "9.1.64", + "resolved": "https://registry.npmjs.org/@fluentui/react-image/-/react-image-9.1.64.tgz", + "integrity": "sha512-GIf3ld0McmndF6vc9I0WS/90d9ON11J9QB9tnI7TxYEFpzgpJ7UIMjVsqqICM/xIj+RtBqYu/1VgiXccIcuZsw==", + "dependencies": { + "@fluentui/react-jsx-runtime": "^9.0.36", + "@fluentui/react-shared-contexts": "^9.17.0", + "@fluentui/react-theme": "^9.1.19", + "@fluentui/react-utilities": "^9.18.7", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-infobutton": { + "version": "9.0.0-beta.101", + "resolved": "https://registry.npmjs.org/@fluentui/react-infobutton/-/react-infobutton-9.0.0-beta.101.tgz", + "integrity": "sha512-gX8Y8/cCc8LgfXtB4aJE+SRo3H3FA+DtWoGvmdaMLIWEoUbxv8sLSEl537MPGhlmTeu+ogXmA+c0RaFMJhvDsw==", + "dependencies": { + "@fluentui/react-icons": "^2.0.235", + "@fluentui/react-jsx-runtime": "^9.0.36", + "@fluentui/react-label": "^9.1.68", + "@fluentui/react-popover": "^9.9.5", + "@fluentui/react-tabster": "^9.20.1", + "@fluentui/react-theme": "^9.1.19", + "@fluentui/react-utilities": "^9.18.7", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-infolabel": { + "version": "9.0.29", + "resolved": "https://registry.npmjs.org/@fluentui/react-infolabel/-/react-infolabel-9.0.29.tgz", + "integrity": "sha512-FloTgj6lsK+wH2YaOonwfmc2TexTbpnGfw+fQ140rKTYEJlsgbb41PzviY3YUbokaG1S/S2rxy+JBlnUU8zzTQ==", + "dependencies": { + "@fluentui/react-icons": "^2.0.235", + "@fluentui/react-jsx-runtime": "^9.0.36", + "@fluentui/react-label": "^9.1.68", + "@fluentui/react-popover": "^9.9.5", + "@fluentui/react-tabster": "^9.20.1", + "@fluentui/react-theme": "^9.1.19", + "@fluentui/react-utilities": "^9.18.7", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.8.0 <19.0.0", + "@types/react-dom": ">=16.8.0 <19.0.0", + "react": ">=16.8.0 <19.0.0", + "react-dom": ">=16.8.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-input": { + "version": "9.4.72", + "resolved": "https://registry.npmjs.org/@fluentui/react-input/-/react-input-9.4.72.tgz", + "integrity": "sha512-MhxgCJd0dma8qx3AOlfgowRTyGabEW8a9vczM9uaex6dO0vtf2CIsP7MfR3DC4b8MeHT1+XEEmfCTNFJb9q3BA==", + "dependencies": { + "@fluentui/react-field": "^9.1.62", + "@fluentui/react-jsx-runtime": "^9.0.36", + "@fluentui/react-shared-contexts": "^9.17.0", + "@fluentui/react-theme": "^9.1.19", + "@fluentui/react-utilities": "^9.18.7", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-jsx-runtime": { + "version": "9.0.36", + "resolved": "https://registry.npmjs.org/@fluentui/react-jsx-runtime/-/react-jsx-runtime-9.0.36.tgz", + "integrity": "sha512-qCaZJ2UagJ6aEahSp83n6OPFAKkxFGB2NEJZ+Cg+PDNZHScA80ds6NfO/FkQ3rz0Vmx0R+qN8MH/zgb6Il05Kg==", + "dependencies": { + "@fluentui/react-utilities": "^9.18.7", + "@swc/helpers": "^0.5.1", + "react-is": "^17.0.2" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "react": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-label": { + "version": "9.1.68", + "resolved": "https://registry.npmjs.org/@fluentui/react-label/-/react-label-9.1.68.tgz", + "integrity": "sha512-j9aQw47kQKX9ECI2EehXvXUwQC2qrOokn1TJsabo54ipgt6yxxjQJPODluqQNWeBxRT0ctuYBTiZvJNvJkw+1A==", + "dependencies": { + "@fluentui/react-jsx-runtime": "^9.0.36", + "@fluentui/react-shared-contexts": "^9.17.0", + "@fluentui/react-theme": "^9.1.19", + "@fluentui/react-utilities": "^9.18.7", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-link": { + "version": "9.2.18", + "resolved": "https://registry.npmjs.org/@fluentui/react-link/-/react-link-9.2.18.tgz", + "integrity": "sha512-dQc9ryjAI6TEyH+pFp71Qzz3jLg4WyiB5oNHNAN6HDRQKSdJKwMzn2HexGmuIV5e/WVH9E9kTfQe5g7a0WMwqw==", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.7", + "@fluentui/react-jsx-runtime": "^9.0.36", + "@fluentui/react-shared-contexts": "^9.17.0", + "@fluentui/react-tabster": "^9.20.1", + "@fluentui/react-theme": "^9.1.19", + "@fluentui/react-utilities": "^9.18.7", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-menu": { + "version": "9.14.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-menu/-/react-menu-9.14.0.tgz", + "integrity": "sha512-rI7NI18Q8FS6p0hs56DRjfo337egGpfpj1AgU6qPKd8TnzX87+LGVAQ0/AuIiDTW9XIIhJmlPaNe9tw2NsoZ4w==", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.7", + "@fluentui/react-aria": "^9.10.5", + "@fluentui/react-context-selector": "^9.1.58", + "@fluentui/react-icons": "^2.0.235", + "@fluentui/react-jsx-runtime": "^9.0.36", + "@fluentui/react-portal": "^9.4.21", + "@fluentui/react-positioning": "^9.14.4", + "@fluentui/react-shared-contexts": "^9.17.0", + "@fluentui/react-tabster": "^9.20.1", + "@fluentui/react-theme": "^9.1.19", + "@fluentui/react-utilities": "^9.18.7", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-menu/node_modules/@fluentui/react-context-selector": { + "version": "9.1.58", + "resolved": "https://registry.npmjs.org/@fluentui/react-context-selector/-/react-context-selector-9.1.58.tgz", + "integrity": "sha512-XFL+X09+AABkC1D/4P20e+AbU+hG3+AiivA2+ZW+6Lqpg2RmYe5a9AhZdMCD0Desyq2BoKurYNyNOmI3OPJF8w==", + "dependencies": { + "@fluentui/react-utilities": "^9.18.7", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0", + "scheduler": ">=0.19.0 <=0.23.0" + } + }, + "node_modules/@fluentui/react-menu/node_modules/scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/@fluentui/react-message-bar": { + "version": "9.0.27", + "resolved": "https://registry.npmjs.org/@fluentui/react-message-bar/-/react-message-bar-9.0.27.tgz", + "integrity": "sha512-U42QwnMziF9MHKeY4j4YUg9P0SnNGLlvIbtSlLGry4yIh6qa4I3aSuY0skPemkbr4TAsKTwiUMDFkd0SbyztFA==", + "dependencies": { + "@fluentui/react-button": "^9.3.76", + "@fluentui/react-icons": "^2.0.235", + "@fluentui/react-jsx-runtime": "^9.0.36", + "@fluentui/react-shared-contexts": "^9.17.0", + "@fluentui/react-theme": "^9.1.19", + "@fluentui/react-utilities": "^9.18.7", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1", + "react-transition-group": "^4.4.1" + }, + "peerDependencies": { + "@types/react": ">=16.8.0 <19.0.0", + "@types/react-dom": ">=16.8.0 <19.0.0", + "react": ">=16.8.0 <19.0.0", + "react-dom": ">=16.8.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-motion-preview": { + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/@fluentui/react-motion-preview/-/react-motion-preview-0.5.19.tgz", + "integrity": "sha512-Gb77BuKbwVlpPZXm+nMAKp6jpjeAT7p6qFkW7YKan8CgDArxUFOLbo2CmpzysJKvd6z6ni21eEFd7gdD7N9p7Q==", + "dependencies": { + "@fluentui/react-jsx-runtime": "^9.0.36", + "@fluentui/react-shared-contexts": "^9.17.0", + "@fluentui/react-theme": "^9.1.19", + "@fluentui/react-utilities": "^9.18.7", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-overflow": { + "version": "9.1.17", + "resolved": "https://registry.npmjs.org/@fluentui/react-overflow/-/react-overflow-9.1.17.tgz", + "integrity": "sha512-21QUisRSs4/aOSxDvSBSm6Tj7ow0WEECbLEI9Vvb7AuaIGGUWujTOuFIWehK9/ME9Ml/Uv23pHtTcBesc0JzOw==", + "dependencies": { + "@fluentui/priority-overflow": "^9.1.11", + "@fluentui/react-context-selector": "^9.1.58", + "@fluentui/react-theme": "^9.1.19", + "@fluentui/react-utilities": "^9.18.7", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-overflow/node_modules/@fluentui/react-context-selector": { + "version": "9.1.58", + "resolved": "https://registry.npmjs.org/@fluentui/react-context-selector/-/react-context-selector-9.1.58.tgz", + "integrity": "sha512-XFL+X09+AABkC1D/4P20e+AbU+hG3+AiivA2+ZW+6Lqpg2RmYe5a9AhZdMCD0Desyq2BoKurYNyNOmI3OPJF8w==", + "dependencies": { + "@fluentui/react-utilities": "^9.18.7", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0", + "scheduler": ">=0.19.0 <=0.23.0" + } + }, + "node_modules/@fluentui/react-overflow/node_modules/scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/@fluentui/react-persona": { + "version": "9.2.81", + "resolved": "https://registry.npmjs.org/@fluentui/react-persona/-/react-persona-9.2.81.tgz", + "integrity": "sha512-LQnteXDG5C8Jlwgk4TQsHTNvHV9r1uqWRLEmKqDrrKFf2ApA3lHyHy1EEc8a5BwOv0ef1dpalqgnAuArXZrEiw==", + "dependencies": { + "@fluentui/react-avatar": "^9.6.22", + "@fluentui/react-badge": "^9.2.32", + "@fluentui/react-jsx-runtime": "^9.0.36", + "@fluentui/react-shared-contexts": "^9.17.0", + "@fluentui/react-theme": "^9.1.19", + "@fluentui/react-utilities": "^9.18.7", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-popover": { + "version": "9.9.5", + "resolved": "https://registry.npmjs.org/@fluentui/react-popover/-/react-popover-9.9.5.tgz", + "integrity": "sha512-yhKaMAKlj+wnV2LzoBqUXlLe5l0EiHg8m2I4n9efXHIVGzyaZEkVc26rwSaxoTbUnFSS8NG1EG5EYqQGh3wiwA==", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.7", + "@fluentui/react-aria": "^9.10.5", + "@fluentui/react-context-selector": "^9.1.58", + "@fluentui/react-jsx-runtime": "^9.0.36", + "@fluentui/react-portal": "^9.4.21", + "@fluentui/react-positioning": "^9.14.4", + "@fluentui/react-shared-contexts": "^9.17.0", + "@fluentui/react-tabster": "^9.20.1", + "@fluentui/react-theme": "^9.1.19", + "@fluentui/react-utilities": "^9.18.7", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-popover/node_modules/@fluentui/react-context-selector": { + "version": "9.1.58", + "resolved": "https://registry.npmjs.org/@fluentui/react-context-selector/-/react-context-selector-9.1.58.tgz", + "integrity": "sha512-XFL+X09+AABkC1D/4P20e+AbU+hG3+AiivA2+ZW+6Lqpg2RmYe5a9AhZdMCD0Desyq2BoKurYNyNOmI3OPJF8w==", + "dependencies": { + "@fluentui/react-utilities": "^9.18.7", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0", + "scheduler": ">=0.19.0 <=0.23.0" + } + }, + "node_modules/@fluentui/react-popover/node_modules/scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/@fluentui/react-portal": { + "version": "9.4.21", + "resolved": "https://registry.npmjs.org/@fluentui/react-portal/-/react-portal-9.4.21.tgz", + "integrity": "sha512-FsDOmvvpC7OAFiwSAiSvvu/WoUUC4oMTQnY/zyotqnzKEyGS/6nMJ5Mr0gyzxtPDCzl6wIPAch5rVksseCm8vg==", + "dependencies": { + "@fluentui/react-shared-contexts": "^9.17.0", + "@fluentui/react-tabster": "^9.20.1", + "@fluentui/react-utilities": "^9.18.7", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1", + "use-disposable": "^1.0.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-positioning": { + "version": "9.14.4", + "resolved": "https://registry.npmjs.org/@fluentui/react-positioning/-/react-positioning-9.14.4.tgz", + "integrity": "sha512-mQz0C0iwRWy3g14laBcbbEEeoTb21dXn/ve8DNEJbVQ4P70MM43vCQeXWbHIDNw6HON+bIG3TyfNyFKQIpLwNA==", + "dependencies": { + "@floating-ui/devtools": "0.2.1", + "@floating-ui/dom": "^1.2.0", + "@fluentui/react-shared-contexts": "^9.17.0", + "@fluentui/react-theme": "^9.1.19", + "@fluentui/react-utilities": "^9.18.7", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-progress": { + "version": "9.1.72", + "resolved": "https://registry.npmjs.org/@fluentui/react-progress/-/react-progress-9.1.72.tgz", + "integrity": "sha512-+pXMRybkZx5qjz3Cfnuj0ntzT6gvLlqukSPHGaneFHOMbivWz9TjVj/FCGIwy6OrY3nAQcgk92zN5sapgM0Nsw==", + "dependencies": { + "@fluentui/react-field": "^9.1.62", + "@fluentui/react-jsx-runtime": "^9.0.36", + "@fluentui/react-shared-contexts": "^9.17.0", + "@fluentui/react-theme": "^9.1.19", + "@fluentui/react-utilities": "^9.18.7", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-provider": { + "version": "9.14.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-provider/-/react-provider-9.14.0.tgz", + "integrity": "sha512-uau0iv04ncFJLkRqKF1tFS8mUqumMBLc+n9CvUE8MK6/QXqHwcWPMUr09dCOsVAB6zpjiQO+4yHBZlja6RKKxA==", + "dependencies": { + "@fluentui/react-icons": "^2.0.235", + "@fluentui/react-jsx-runtime": "^9.0.36", + "@fluentui/react-shared-contexts": "^9.17.0", + "@fluentui/react-tabster": "^9.20.1", + "@fluentui/react-theme": "^9.1.19", + "@fluentui/react-utilities": "^9.18.7", + "@griffel/core": "^1.14.1", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-radio": { + "version": "9.2.16", + "resolved": "https://registry.npmjs.org/@fluentui/react-radio/-/react-radio-9.2.16.tgz", + "integrity": "sha512-H5NzFFYYkQ2osE7Rh96DjWRgI24POZoaBnjJrUvds5B/3Jod4905c2VsP6MSvkr+cslVRnO55OCeBX7MlqP17g==", + "dependencies": { + "@fluentui/react-field": "^9.1.62", + "@fluentui/react-jsx-runtime": "^9.0.36", + "@fluentui/react-label": "^9.1.68", + "@fluentui/react-shared-contexts": "^9.17.0", + "@fluentui/react-tabster": "^9.20.1", + "@fluentui/react-theme": "^9.1.19", + "@fluentui/react-utilities": "^9.18.7", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-rating": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/@fluentui/react-rating/-/react-rating-9.0.4.tgz", + "integrity": "sha512-AieJyOO6Ldflfr8IxbUYkBpEDKOm+zPJJhtzUVQrb/kqJOsCDknPoO4UkL3VbfjN8QGCQ353Aq1ZX2svL5ar3Q==", + "dependencies": { + "@fluentui/react-icons": "^2.0.235", + "@fluentui/react-jsx-runtime": "^9.0.36", + "@fluentui/react-tabster": "^9.20.1", + "@fluentui/react-theme": "^9.1.19", + "@fluentui/react-utilities": "^9.18.7", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.8.0 <19.0.0", + "@types/react-dom": ">=16.8.0 <19.0.0", + "react": ">=16.8.0 <19.0.0", + "react-dom": ">=16.8.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-search": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@fluentui/react-search/-/react-search-9.0.1.tgz", + "integrity": "sha512-Hz/44MwKCaSjoGSxzwE9pu/cj0XtjeNNl2ky3aRYgvmfHTIMGc2c72vhxp98EYrVolyV7ijCdm3AnwWW7aA6Kw==", + "dependencies": { + "@fluentui/react-icons": "^2.0.235", + "@fluentui/react-input": "^9.4.72", + "@fluentui/react-jsx-runtime": "^9.0.36", + "@fluentui/react-theme": "^9.1.19", + "@fluentui/react-utilities": "^9.18.7", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-select": { + "version": "9.1.72", + "resolved": "https://registry.npmjs.org/@fluentui/react-select/-/react-select-9.1.72.tgz", + "integrity": "sha512-xtdiK++/aT49xT/JRSNhOSwgfMR/OcifShXrLCx1WNG78yXMCFOv7J2/i+01MsPZHZDo7EYWgxKmAYZ0+e4TIw==", + "dependencies": { + "@fluentui/react-field": "^9.1.62", + "@fluentui/react-icons": "^2.0.235", + "@fluentui/react-jsx-runtime": "^9.0.36", + "@fluentui/react-shared-contexts": "^9.17.0", + "@fluentui/react-theme": "^9.1.19", + "@fluentui/react-utilities": "^9.18.7", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-shared-contexts": { + "version": "9.17.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-shared-contexts/-/react-shared-contexts-9.17.0.tgz", + "integrity": "sha512-SvfFmzzy0QfhaCrGcUJFJcscc6NGyuoYxT0Q8wgu5ol3vZ+idvVgGIJbhwQFVT08Ph5yR6FsWS22/nLjTqE58A==", + "dependencies": { + "@fluentui/react-theme": "^9.1.19", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "react": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-skeleton": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-skeleton/-/react-skeleton-9.1.0.tgz", + "integrity": "sha512-eV+UbqZ3Xq8aShusyDnGrex9NG+7wcmvnKiTY8aOAf4Kl5XJwNr8WE5nHcHO3pyIsX6bQQcvSWsyxMw5rJy/Ag==", + "dependencies": { + "@fluentui/react-field": "^9.1.62", + "@fluentui/react-jsx-runtime": "^9.0.36", + "@fluentui/react-shared-contexts": "^9.17.0", + "@fluentui/react-theme": "^9.1.19", + "@fluentui/react-utilities": "^9.18.7", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-slider": { + "version": "9.1.78", + "resolved": "https://registry.npmjs.org/@fluentui/react-slider/-/react-slider-9.1.78.tgz", + "integrity": "sha512-0+SC1TG6smvlK21MU6DCO6dEGtnFNa/Zt2VqNxP2h56iusdPzDwqj2UQre5S6tfigR1fCAMEMeOkerOpXKWW/g==", + "dependencies": { + "@fluentui/react-field": "^9.1.62", + "@fluentui/react-jsx-runtime": "^9.0.36", + "@fluentui/react-shared-contexts": "^9.17.0", + "@fluentui/react-tabster": "^9.20.1", + "@fluentui/react-theme": "^9.1.19", + "@fluentui/react-utilities": "^9.18.7", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-spinbutton": { + "version": "9.2.72", + "resolved": "https://registry.npmjs.org/@fluentui/react-spinbutton/-/react-spinbutton-9.2.72.tgz", + "integrity": "sha512-79/IfTrRWmsq4C09q6nZsCGBsHSbfLCsTe8WI13sB0zWBlCDQVXOwsi7XuS8DbO3jmT8eUggJbaYEn4h/8iHHQ==", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.7", + "@fluentui/react-field": "^9.1.62", + "@fluentui/react-icons": "^2.0.235", + "@fluentui/react-jsx-runtime": "^9.0.36", + "@fluentui/react-shared-contexts": "^9.17.0", + "@fluentui/react-theme": "^9.1.19", + "@fluentui/react-utilities": "^9.18.7", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-spinner": { + "version": "9.4.5", + "resolved": "https://registry.npmjs.org/@fluentui/react-spinner/-/react-spinner-9.4.5.tgz", + "integrity": "sha512-Kg5NUB2UrViDiBEKNdV7UVN4mPxeZF5seUm7qZP4hBSKf90oj2xcJ+BKggQg++MelDLMFeLnTE1pJO/Lv/ovbA==", + "dependencies": { + "@fluentui/react-jsx-runtime": "^9.0.36", + "@fluentui/react-label": "^9.1.68", + "@fluentui/react-shared-contexts": "^9.17.0", + "@fluentui/react-theme": "^9.1.19", + "@fluentui/react-utilities": "^9.18.7", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-switch": { + "version": "9.1.78", + "resolved": "https://registry.npmjs.org/@fluentui/react-switch/-/react-switch-9.1.78.tgz", + "integrity": "sha512-pyqKSXE5vglqkGS9UXIQe/l2Q78t/PFPuiCbfEr1c8TYhzdQWXJq2WkK5WbrZAwLRL9AEbhCmoD1Lig9PXvGHQ==", + "dependencies": { + "@fluentui/react-field": "^9.1.62", + "@fluentui/react-icons": "^2.0.235", + "@fluentui/react-jsx-runtime": "^9.0.36", + "@fluentui/react-label": "^9.1.68", + "@fluentui/react-shared-contexts": "^9.17.0", + "@fluentui/react-tabster": "^9.20.1", + "@fluentui/react-theme": "^9.1.19", + "@fluentui/react-utilities": "^9.18.7", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-table": { + "version": "9.15.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-table/-/react-table-9.15.0.tgz", + "integrity": "sha512-uvdmF7JdlYZ5jXi8Y7M4KB2TmNNm9+oTevwiF3BmnQVLCoHq0lX1Mlv12gLRuztAuHiTOsNcPETZTbUjlf1GZg==", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.7", + "@fluentui/react-aria": "^9.10.5", + "@fluentui/react-avatar": "^9.6.22", + "@fluentui/react-checkbox": "^9.2.21", + "@fluentui/react-context-selector": "^9.1.58", + "@fluentui/react-icons": "^2.0.235", + "@fluentui/react-jsx-runtime": "^9.0.36", + "@fluentui/react-radio": "^9.2.16", + "@fluentui/react-shared-contexts": "^9.17.0", + "@fluentui/react-tabster": "^9.20.1", + "@fluentui/react-theme": "^9.1.19", + "@fluentui/react-utilities": "^9.18.7", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-table/node_modules/@fluentui/react-context-selector": { + "version": "9.1.58", + "resolved": "https://registry.npmjs.org/@fluentui/react-context-selector/-/react-context-selector-9.1.58.tgz", + "integrity": "sha512-XFL+X09+AABkC1D/4P20e+AbU+hG3+AiivA2+ZW+6Lqpg2RmYe5a9AhZdMCD0Desyq2BoKurYNyNOmI3OPJF8w==", + "dependencies": { + "@fluentui/react-utilities": "^9.18.7", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0", + "scheduler": ">=0.19.0 <=0.23.0" + } + }, + "node_modules/@fluentui/react-table/node_modules/scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/@fluentui/react-tabs": { + "version": "9.4.17", + "resolved": "https://registry.npmjs.org/@fluentui/react-tabs/-/react-tabs-9.4.17.tgz", + "integrity": "sha512-ZdzS46h2FW8dZOLCZPkrnvYEE6dD4HRYN6M4/RGqiN8dT8jWxj0FBZSNpp6gGTCftADr6k675GqKWoGmnr2ctA==", + "dependencies": { + "@fluentui/react-context-selector": "^9.1.58", + "@fluentui/react-jsx-runtime": "^9.0.36", + "@fluentui/react-shared-contexts": "^9.17.0", + "@fluentui/react-tabster": "^9.20.1", + "@fluentui/react-theme": "^9.1.19", + "@fluentui/react-utilities": "^9.18.7", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-tabs/node_modules/@fluentui/react-context-selector": { + "version": "9.1.58", + "resolved": "https://registry.npmjs.org/@fluentui/react-context-selector/-/react-context-selector-9.1.58.tgz", + "integrity": "sha512-XFL+X09+AABkC1D/4P20e+AbU+hG3+AiivA2+ZW+6Lqpg2RmYe5a9AhZdMCD0Desyq2BoKurYNyNOmI3OPJF8w==", + "dependencies": { + "@fluentui/react-utilities": "^9.18.7", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0", + "scheduler": ">=0.19.0 <=0.23.0" + } + }, + "node_modules/@fluentui/react-tabs/node_modules/scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/@fluentui/react-tabster": { + "version": "9.20.1", + "resolved": "https://registry.npmjs.org/@fluentui/react-tabster/-/react-tabster-9.20.1.tgz", + "integrity": "sha512-dDm18fThjQfDYL5dH2WdcECdbYNe0T8sn6j2RGP3V6cxqCwXpAI+zfquIAjqkgoR9bn/XDDSkUKTyxrFMrVMVA==", + "dependencies": { + "@fluentui/react-shared-contexts": "^9.17.0", + "@fluentui/react-theme": "^9.1.19", + "@fluentui/react-utilities": "^9.18.7", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1", + "keyborg": "^2.5.0", + "tabster": "^7.1.0" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-tags": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/@fluentui/react-tags/-/react-tags-9.3.1.tgz", + "integrity": "sha512-tzfMFmM3q4Rl65M7qDSIHSNM6PLMcctLfjpt0qBj//OriomJ1cG0N1tmEXRVWlq3BMeGI+xIXCXktrl/2xbpCA==", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.7", + "@fluentui/react-aria": "^9.10.5", + "@fluentui/react-avatar": "^9.6.22", + "@fluentui/react-icons": "^2.0.235", + "@fluentui/react-jsx-runtime": "^9.0.36", + "@fluentui/react-shared-contexts": "^9.17.0", + "@fluentui/react-tabster": "^9.20.1", + "@fluentui/react-theme": "^9.1.19", + "@fluentui/react-utilities": "^9.18.7", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-teaching-popover": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-teaching-popover/-/react-teaching-popover-9.1.0.tgz", + "integrity": "sha512-KBeCqzoPc8jiGTQmvEABJuxcJHyM2sp/hSNLpdl68zniqXCJCvqY3o02Av1xWRjmyFKn7Lt5q6MTs5ZkaEYcYQ==", + "dependencies": { + "@fluentui/react-aria": "^9.10.5", + "@fluentui/react-button": "^9.3.76", + "@fluentui/react-context-selector": "^9.1.58", + "@fluentui/react-icons": "^2.0.235", + "@fluentui/react-jsx-runtime": "^9.0.36", + "@fluentui/react-popover": "^9.9.5", + "@fluentui/react-shared-contexts": "^9.17.0", + "@fluentui/react-tabster": "^9.20.1", + "@fluentui/react-theme": "^9.1.19", + "@fluentui/react-utilities": "^9.18.7", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1", + "use-sync-external-store": "^1.2.0" + }, + "peerDependencies": { + "@types/react": ">=16.8.0 <19.0.0", + "@types/react-dom": ">=16.8.0 <19.0.0", + "react": ">=16.8.0 <19.0.0", + "react-dom": ">=16.8.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-teaching-popover/node_modules/@fluentui/react-context-selector": { + "version": "9.1.58", + "resolved": "https://registry.npmjs.org/@fluentui/react-context-selector/-/react-context-selector-9.1.58.tgz", + "integrity": "sha512-XFL+X09+AABkC1D/4P20e+AbU+hG3+AiivA2+ZW+6Lqpg2RmYe5a9AhZdMCD0Desyq2BoKurYNyNOmI3OPJF8w==", + "dependencies": { + "@fluentui/react-utilities": "^9.18.7", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0", + "scheduler": ">=0.19.0 <=0.23.0" + } + }, + "node_modules/@fluentui/react-teaching-popover/node_modules/scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/@fluentui/react-text": { + "version": "9.4.16", + "resolved": "https://registry.npmjs.org/@fluentui/react-text/-/react-text-9.4.16.tgz", + "integrity": "sha512-rgdLtbY6rHdFrxNWqflh88aEqqONWBgoMA6xEOQix357E3A5J7S8NJSlKAsd00zQO5gFRiKO+gr5iiRFVKDqeA==", + "dependencies": { + "@fluentui/react-jsx-runtime": "^9.0.36", + "@fluentui/react-shared-contexts": "^9.17.0", + "@fluentui/react-theme": "^9.1.19", + "@fluentui/react-utilities": "^9.18.7", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-textarea": { + "version": "9.3.72", + "resolved": "https://registry.npmjs.org/@fluentui/react-textarea/-/react-textarea-9.3.72.tgz", + "integrity": "sha512-lLYtumX6CxHPbsTP2W+PX6ehWGlZXAKpcgqrhCU4YGxNAdD7FbBO30SIQMAgQ6ygWMAZRztGGRQYkihFz8SeiQ==", + "dependencies": { + "@fluentui/react-field": "^9.1.62", + "@fluentui/react-jsx-runtime": "^9.0.36", + "@fluentui/react-shared-contexts": "^9.17.0", + "@fluentui/react-theme": "^9.1.19", + "@fluentui/react-utilities": "^9.18.7", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-theme": { + "version": "9.1.19", + "resolved": "https://registry.npmjs.org/@fluentui/react-theme/-/react-theme-9.1.19.tgz", + "integrity": "sha512-mrVhKbr4o9UKERPxgghIRDU59S7gRizrgz3/wwyMt7elkr8Sw+OpwKIeEw9x6P0RTcFDC00nggaMJhBGs7Xo4A==", + "dependencies": { + "@fluentui/tokens": "1.0.0-alpha.16", + "@swc/helpers": "^0.5.1" + } + }, + "node_modules/@fluentui/react-toast": { + "version": "9.3.38", + "resolved": "https://registry.npmjs.org/@fluentui/react-toast/-/react-toast-9.3.38.tgz", + "integrity": "sha512-oGLdXgObrDCpWzGoM+AKEz1QmwvIix9xCyA2Tf5j9n4kuXAzN9QQZCrS0qVt+I43SboUdsvW8VT+06oSdNPNUA==", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.7", + "@fluentui/react-aria": "^9.10.5", + "@fluentui/react-icons": "^2.0.235", + "@fluentui/react-jsx-runtime": "^9.0.36", + "@fluentui/react-portal": "^9.4.21", + "@fluentui/react-shared-contexts": "^9.17.0", + "@fluentui/react-tabster": "^9.20.1", + "@fluentui/react-theme": "^9.1.19", + "@fluentui/react-utilities": "^9.18.7", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1", + "react-transition-group": "^4.4.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-toolbar": { + "version": "9.1.79", + "resolved": "https://registry.npmjs.org/@fluentui/react-toolbar/-/react-toolbar-9.1.79.tgz", + "integrity": "sha512-9PnMPBh9Yz519qJad18fxe8mQxeLipkB2X9E7xfqMk0zJM1Yni2PmyjuFfJZlgMipkdD26/G1P+gqt45O+b4oQ==", + "dependencies": { + "@fluentui/react-button": "^9.3.76", + "@fluentui/react-context-selector": "^9.1.58", + "@fluentui/react-divider": "^9.2.67", + "@fluentui/react-jsx-runtime": "^9.0.36", + "@fluentui/react-radio": "^9.2.16", + "@fluentui/react-shared-contexts": "^9.17.0", + "@fluentui/react-tabster": "^9.20.1", + "@fluentui/react-theme": "^9.1.19", + "@fluentui/react-utilities": "^9.18.7", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-toolbar/node_modules/@fluentui/react-context-selector": { + "version": "9.1.58", + "resolved": "https://registry.npmjs.org/@fluentui/react-context-selector/-/react-context-selector-9.1.58.tgz", + "integrity": "sha512-XFL+X09+AABkC1D/4P20e+AbU+hG3+AiivA2+ZW+6Lqpg2RmYe5a9AhZdMCD0Desyq2BoKurYNyNOmI3OPJF8w==", + "dependencies": { + "@fluentui/react-utilities": "^9.18.7", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0", + "scheduler": ">=0.19.0 <=0.23.0" + } + }, + "node_modules/@fluentui/react-toolbar/node_modules/scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/@fluentui/react-tooltip": { + "version": "9.4.24", + "resolved": "https://registry.npmjs.org/@fluentui/react-tooltip/-/react-tooltip-9.4.24.tgz", + "integrity": "sha512-TJNP3KBZID+yLc4BlJ0A4lrB7SlelI9RPgpFs7En5AR35eqKsRriGLiiIj3cAeKh7BvvH+dNCDjg6zo82rbytQ==", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.7", + "@fluentui/react-jsx-runtime": "^9.0.36", + "@fluentui/react-portal": "^9.4.21", + "@fluentui/react-positioning": "^9.14.4", + "@fluentui/react-shared-contexts": "^9.17.0", + "@fluentui/react-tabster": "^9.20.1", + "@fluentui/react-theme": "^9.1.19", + "@fluentui/react-utilities": "^9.18.7", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-tree": { + "version": "9.4.39", + "resolved": "https://registry.npmjs.org/@fluentui/react-tree/-/react-tree-9.4.39.tgz", + "integrity": "sha512-3Zab9biXU+ds2Vx59NGuDksYtGNLuVrAxWQxTmXDbGQ0Y8ogPTA82t52Nf2vRbygzw8PV4dBfwbgau6uQgFNNQ==", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.7", + "@fluentui/react-aria": "^9.10.5", + "@fluentui/react-avatar": "^9.6.22", + "@fluentui/react-button": "^9.3.76", + "@fluentui/react-checkbox": "^9.2.21", + "@fluentui/react-context-selector": "^9.1.58", + "@fluentui/react-icons": "^2.0.235", + "@fluentui/react-jsx-runtime": "^9.0.36", + "@fluentui/react-radio": "^9.2.16", + "@fluentui/react-shared-contexts": "^9.17.0", + "@fluentui/react-tabster": "^9.20.1", + "@fluentui/react-theme": "^9.1.19", + "@fluentui/react-utilities": "^9.18.7", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-tree/node_modules/@fluentui/react-context-selector": { + "version": "9.1.58", + "resolved": "https://registry.npmjs.org/@fluentui/react-context-selector/-/react-context-selector-9.1.58.tgz", + "integrity": "sha512-XFL+X09+AABkC1D/4P20e+AbU+hG3+AiivA2+ZW+6Lqpg2RmYe5a9AhZdMCD0Desyq2BoKurYNyNOmI3OPJF8w==", + "dependencies": { + "@fluentui/react-utilities": "^9.18.7", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0", + "scheduler": ">=0.19.0 <=0.23.0" + } + }, + "node_modules/@fluentui/react-tree/node_modules/scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/@fluentui/react-utilities": { + "version": "9.18.7", + "resolved": "https://registry.npmjs.org/@fluentui/react-utilities/-/react-utilities-9.18.7.tgz", + "integrity": "sha512-voVd4xrx+9VxCPYt51JlzLuJYsjCf3LYjoytAyruu7kEOkPF31Fnjkmp81yrXnAbM+J+tL8HajG5bUHjt8H59w==", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.7", + "@fluentui/react-shared-contexts": "^9.17.0", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "react": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-virtualizer": { + "version": "9.0.0-alpha.75", + "resolved": "https://registry.npmjs.org/@fluentui/react-virtualizer/-/react-virtualizer-9.0.0-alpha.75.tgz", + "integrity": "sha512-1ISbGEr4XVDcrSCQfnStc+yH3lD2bZuK2zg6cEouqZNBo6GdNFtvRU5Zi84CfOFeGMzO6NItHfBHLoJYqSYCSw==", + "dependencies": { + "@fluentui/react-jsx-runtime": "^9.0.36", + "@fluentui/react-shared-contexts": "^9.17.0", + "@fluentui/react-utilities": "^9.18.7", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/tokens": { + "version": "1.0.0-alpha.16", + "resolved": "https://registry.npmjs.org/@fluentui/tokens/-/tokens-1.0.0-alpha.16.tgz", + "integrity": "sha512-Gr9G8LIlUhZYX5j6CfDQrofQqsWAz/q54KabWn1tWV/1083WwyoTZXiG1k6b37NnK7Feye7D7Nz+4MNqoKpXGw==", + "dependencies": { + "@swc/helpers": "^0.5.1" + } + }, + "node_modules/@griffel/core": { + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/@griffel/core/-/core-1.15.3.tgz", + "integrity": "sha512-5ksBpOjFJ75HijGehQ06Ri9cQjhd/rqQ0N/jJzXDDXQFYdOOzib/QL7BXNwhkLtTyHvN391cD4/BqcTdynfLUg==", + "dependencies": { + "@emotion/hash": "^0.9.0", + "@griffel/style-types": "^1.0.4", + "csstype": "^3.1.3", + "rtl-css-js": "^1.16.1", + "stylis": "^4.2.0", + "tslib": "^2.1.0" + } + }, + "node_modules/@griffel/react": { + "version": "1.5.21", + "resolved": "https://registry.npmjs.org/@griffel/react/-/react-1.5.21.tgz", + "integrity": "sha512-7wuY9uFSt/0E7kLAKX//ue8NILx0IGoOtIx6WVuavEUFJXPCrvFn4uCDgnJC0211LZtJ+XH7zZGPNUtSb7nijw==", + "dependencies": { + "@griffel/core": "^1.15.3", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "react": ">=16.8.0 <19.0.0" + } + }, + "node_modules/@griffel/style-types": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@griffel/style-types/-/style-types-1.0.4.tgz", + "integrity": "sha512-geZomjQTIHXoQZFFB811PUMXYAr8LuBNOMPcR2YJAl1pslbHYYiZKCa2FgZCw00hnQFP4uB4JIJ2CiPJqKZYmw==", + "dependencies": { + "csstype": "^3.1.3" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.14", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", @@ -1190,6 +2863,14 @@ "win32" ] }, + "node_modules/@swc/helpers": { + "version": "0.5.11", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.11.tgz", + "integrity": "sha512-YNlnKRWF2sVojTpIyzwou9XoTNbzbzONwRhOoniEioF1AtaitTvVZblaQRrAzChWQ1bLYyYSWzM18y4WwgzJ+A==", + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", @@ -1246,14 +2927,12 @@ "node_modules/@types/prop-types": { "version": "15.7.12", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", - "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==", - "dev": true + "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==" }, "node_modules/@types/react": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.1.tgz", "integrity": "sha512-V0kuGBX3+prX+DQ/7r2qsv1NsdfnCLnTgnRJ1pYnxykBhGMz+qj+box5lq7XsO5mtZsBqpjwwTu/7wszPfMBcw==", - "dev": true, "dependencies": { "@types/prop-types": "*", "csstype": "^3.0.2" @@ -1263,7 +2942,6 @@ "version": "18.3.0", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.0.tgz", "integrity": "sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==", - "dev": true, "dependencies": { "@types/react": "*" } @@ -1708,8 +3386,7 @@ "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "dev": true + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" }, "node_modules/debug": { "version": "4.3.4", @@ -1758,6 +3435,15 @@ "node": ">=6.0.0" } }, + "node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, "node_modules/electron-to-chromium": { "version": "1.4.751", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.751.tgz", @@ -2498,6 +4184,11 @@ "node": ">=6" } }, + "node_modules/keyborg": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/keyborg/-/keyborg-2.5.0.tgz", + "integrity": "sha512-nb4Ji1suqWqj6VXb61Jrs4ab/UWgtGph4wDch2NIZDfLBUObmLcZE0aiDjZY49ghtu03fvwxDNvS9ZB0XMz6/g==" + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -2634,6 +4325,14 @@ "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", "dev": true }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -2793,6 +4492,21 @@ "node": ">= 0.8.0" } }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -2845,6 +4559,11 @@ "react": "^18.3.1" } }, + "node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" + }, "node_modules/react-refresh": { "version": "0.14.2", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz", @@ -2854,6 +4573,26 @@ "node": ">=0.10.0" } }, + "node_modules/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" + }, "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -2923,6 +4662,14 @@ "fsevents": "~2.3.2" } }, + "node_modules/rtl-css-js": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/rtl-css-js/-/rtl-css-js-1.16.1.tgz", + "integrity": "sha512-lRQgou1mu19e+Ya0LsTvKrVJ5TYUbqCVPAiImX3UfLTenarvPUl1QFdvu5Z3PYmHT9RCcwIfbjRQBntExyj3Zg==", + "dependencies": { + "@babel/runtime": "^7.1.2" + } + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -3050,6 +4797,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/stylis": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.2.tgz", + "integrity": "sha512-bhtUjWd/z6ltJiQwg0dUfxEJ+W+jdqQd8TbWLWyeIJHlnsqmGLRFFd8e5mA0AZi/zx90smXRlN66YMTcaSFifg==" + }, "node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -3062,6 +4814,15 @@ "node": ">=4" } }, + "node_modules/tabster": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/tabster/-/tabster-7.1.1.tgz", + "integrity": "sha512-3VsXUb0XxVcFq9NmzTieAJAlruMiaj/dvXIHm7RgjsUrMGkEcq9KbBdai05NAGp2D2d/CxHc6j1mbuUzGofWBA==", + "dependencies": { + "keyborg": "2.5.0", + "tslib": "^2.3.1" + } + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -3101,6 +4862,11 @@ "typescript": ">=4.2.0" } }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -3177,6 +4943,25 @@ "punycode": "^2.1.0" } }, + "node_modules/use-disposable": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/use-disposable/-/use-disposable-1.0.2.tgz", + "integrity": "sha512-UMaXVlV77dWOu4GqAFNjRzHzowYKUKbJBQfCexvahrYeIz4OkUYUjna4Tjjdf92NH8Nm8J7wEfFRgTIwYjO5jg==", + "peerDependencies": { + "@types/react": ">=16.8.0 <19.0.0", + "@types/react-dom": ">=16.8.0 <19.0.0", + "react": ">=16.8.0 <19.0.0", + "react-dom": ">=16.8.0 <19.0.0" + } + }, + "node_modules/use-sync-external-store": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz", + "integrity": "sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/vite": { "version": "5.2.10", "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.10.tgz", diff --git a/remote_frontend/package.json b/remote_frontend/package.json index 10bea5c..5031631 100644 --- a/remote_frontend/package.json +++ b/remote_frontend/package.json @@ -10,6 +10,7 @@ "preview": "vite preview" }, "dependencies": { + "@fluentui/react-components": "^9.49.0", "react": "^18.2.0", "react-dom": "^18.2.0" }, diff --git a/remote_frontend/src/App.tsx b/remote_frontend/src/App.tsx index 6749a00..938173d 100644 --- a/remote_frontend/src/App.tsx +++ b/remote_frontend/src/App.tsx @@ -1 +1,14 @@ -export function App(): React.ReactElement {} +import { ServerApi } from "./api/ServerApi"; +import { AsyncWidget } from "./widgets/AsyncWidget"; + +export function App() { + return ( + <>todo} + /> + ); +} diff --git a/remote_frontend/src/api/ApiClient.ts b/remote_frontend/src/api/ApiClient.ts new file mode 100644 index 0000000..06fe546 --- /dev/null +++ b/remote_frontend/src/api/ApiClient.ts @@ -0,0 +1,174 @@ +interface RequestParams { + uri: string; + method: "GET" | "POST" | "DELETE" | "PATCH" | "PUT"; + allowFail?: boolean; + jsonData?: any; + formData?: FormData; + upProgress?: (progress: number) => void; + downProgress?: (e: { progress: number; total: number }) => void; +} + +interface APIResponse { + data: any; + status: number; +} + +export class ApiError extends Error { + constructor(message: string, public code: number, public data: any) { + super(`HTTP status: ${code}\nMessage: ${message}\nData=${data}`); + } +} + +export class APIClient { + /** + * Get backend URL + */ + static backendURL(): string { + const URL = import.meta.env.VITE_APP_BACKEND ?? ""; + if (URL.length === 0) throw new Error("Backend URL undefined!"); + return URL; + } + + /** + * Check out whether the backend is accessed through + * HTTPS or not + */ + static IsBackendSecure(): boolean { + return this.backendURL().startsWith("https"); + } + + /** + * Perform a request on the backend + */ + static async exec(args: RequestParams): Promise { + let body: string | undefined | FormData = undefined; + let headers: any = {}; + + // JSON request + if (args.jsonData) { + headers["Content-Type"] = "application/json"; + body = JSON.stringify(args.jsonData); + } + + // Form data request + else if (args.formData) { + body = args.formData; + } + + const url = this.backendURL() + args.uri; + + let data; + let status: number; + + // Make the request with XMLHttpRequest + if (args.upProgress) { + const res: XMLHttpRequest = await new Promise((resolve, reject) => { + const xhr = new XMLHttpRequest(); + xhr.upload.addEventListener("progress", (e) => + args.upProgress!(e.loaded / e.total) + ); + xhr.addEventListener("load", () => resolve(xhr)); + xhr.addEventListener("error", () => + reject(new Error("File upload failed")) + ); + xhr.addEventListener("abort", () => + reject(new Error("File upload aborted")) + ); + xhr.addEventListener("timeout", () => + reject(new Error("File upload timeout")) + ); + xhr.open(args.method, url, true); + xhr.withCredentials = true; + for (const key in headers) { + if (headers.hasOwnProperty(key)) + xhr.setRequestHeader(key, headers[key]); + } + xhr.send(body); + }); + + status = res.status; + if (res.responseType === "json") data = JSON.parse(res.responseText); + else data = res.response; + } + + // Make the request with fetch + else { + const res = await fetch(url, { + method: args.method, + body: body, + headers: headers, + credentials: "include", + }); + + // Process response + // JSON response + if (res.headers.get("content-type") === "application/json") + data = await res.json(); + // Text / XML response + else if ( + ["application/xml", "text/plain"].includes( + res.headers.get("content-type") ?? "" + ) + ) + data = await res.text(); + // Binary file, tracking download progress + else if (res.body !== null && args.downProgress) { + // Track download progress + const contentEncoding = res.headers.get("content-encoding"); + const contentLength = contentEncoding + ? null + : res.headers.get("content-length"); + + const total = parseInt(contentLength ?? "0", 10); + let loaded = 0; + + const resInt = new Response( + new ReadableStream({ + start(controller) { + const reader = res.body!.getReader(); + + const read = async () => { + try { + const ret = await reader.read(); + if (ret.done) { + controller.close(); + return; + } + loaded += ret.value.byteLength; + args.downProgress!({ progress: loaded, total }); + controller.enqueue(ret.value); + read(); + } catch (e) { + console.error(e); + controller.error(e); + } + }; + + read(); + }, + }) + ); + + data = await resInt.blob(); + } + + // Do not track progress (binary file) + else data = await res.blob(); + + status = res.status; + } + + // Handle expired tokens + if (status === 412) { + window.location.href = "/"; + } + + if (!args.allowFail && (status < 200 || status > 299)) + throw new ApiError("Request failed!", status, data); + + return { + data: data, + status: status, + }; + } +} diff --git a/remote_frontend/src/api/ServerApi.ts b/remote_frontend/src/api/ServerApi.ts new file mode 100644 index 0000000..2980a15 --- /dev/null +++ b/remote_frontend/src/api/ServerApi.ts @@ -0,0 +1,30 @@ +import { APIClient } from "./ApiClient"; + +export interface ServerConfig { + authenticated: boolean; + disable_auth: boolean; +} + +let config: ServerConfig | null = null; + +export class ServerApi { + /** + * Get server configuration + */ + static async LoadConfig(): Promise { + config = ( + await APIClient.exec({ + uri: "/server/config", + method: "GET", + }) + ).data; + } + + /** + * Get cached configuration + */ + static get Config(): ServerConfig { + if (config === null) throw new Error("Missing configuration!"); + return config; + } +} diff --git a/remote_frontend/src/index.css b/remote_frontend/src/index.css index a727a88..33c5860 100644 --- a/remote_frontend/src/index.css +++ b/remote_frontend/src/index.css @@ -1,7 +1,14 @@ body { margin: 0; - display: flex; - place-items: center; min-width: 320px; min-height: 100vh; + display: flex; + flex-direction: column; +} + +#root { + width: 100%; + height: 100%; + flex: 1; + display: flex; } diff --git a/remote_frontend/src/main.tsx b/remote_frontend/src/main.tsx index 2a5a795..8dc1b59 100644 --- a/remote_frontend/src/main.tsx +++ b/remote_frontend/src/main.tsx @@ -2,9 +2,18 @@ import React from "react"; import ReactDOM from "react-dom/client"; import "./index.css"; import { App } from "./App"; +import { + FluentProvider, + teamsHighContrastTheme, +} from "@fluentui/react-components"; ReactDOM.createRoot(document.getElementById("root")!).render( - + + + ); diff --git a/remote_frontend/src/widgets/AsyncWidget.tsx b/remote_frontend/src/widgets/AsyncWidget.tsx new file mode 100644 index 0000000..ecf4474 --- /dev/null +++ b/remote_frontend/src/widgets/AsyncWidget.tsx @@ -0,0 +1,77 @@ +import { Button, Spinner } from "@fluentui/react-components"; +import React, { useEffect, useRef, useState } from "react"; + +enum State { + Loading, + Ready, + Error, +} + +export function AsyncWidget(p: { + loadKey: any; + load: () => Promise; + errMsg: string; + build: () => React.ReactElement; + ready?: boolean; + buildLoading?: () => React.ReactElement; + buildError?: (e: string) => React.ReactElement; + errAdditionalElement?: () => React.ReactElement; + loadingMessage?: string; +}): React.ReactElement { + const [state, setState] = useState(State.Loading); + + const counter = useRef(null); + + const load = async () => { + try { + setState(State.Loading); + await p.load(); + setState(State.Ready); + } catch (e) { + console.error(e); + setState(State.Error); + } + }; + + useEffect(() => { + if (counter.current === p.loadKey) return; + counter.current = p.loadKey; + + load(); + }); + + if (state === State.Error) + return ( + p.buildError?.(p.errMsg) ?? ( +
+
{p.errMsg}
+ + + + {p.errAdditionalElement && p.errAdditionalElement()} +
+ ) + ); + + if (state === State.Loading || p.ready === false) + return ( + p.buildLoading?.() ?? ( + + ) + ); + + return p.build(); +}