Compare commits
107 Commits
f087b27b53
...
renovate/n
| Author | SHA1 | Date | |
|---|---|---|---|
| 166b860c1a | |||
| 96b02dd73a | |||
| 5dd4aa6c0e | |||
| 8f4480e555 | |||
| 06e1f60314 | |||
| a7432a4014 | |||
| be5e7eb328 | |||
| c1e703c4b4 | |||
| 071aad8147 | |||
| f4b3c0aa16 | |||
| daca7410d7 | |||
| 23074ac354 | |||
| 36bd8d0672 | |||
| 6162555702 | |||
| 951d0db0b7 | |||
| ef90aba489 | |||
| 6b39fd11bd | |||
| bf6561fa87 | |||
| e5feecc703 | |||
| 153ad14a51 | |||
| e5494e51a3 | |||
| f04ab4591b | |||
| ca2cdb2f79 | |||
| 795a12c8d0 | |||
| 79e78006fa | |||
| 18c0fbef3c | |||
| 0ac6fc4ac3 | |||
| 2aaced17d8 | |||
| 9da2a9e9b3 | |||
| 9595ff2e71 | |||
| 5bd62d7683 | |||
| 7e747b50f3 | |||
| a9a5d60edd | |||
| 89dbc252e8 | |||
| 3a6b2c6cf2 | |||
| 98c813b220 | |||
| ceb7859169 | |||
| 96e597ca59 | |||
| d9630fbc4c | |||
| 4d7db2de2a | |||
| 4c0be88570 | |||
| 2f933a247f | |||
| f6a7132d43 | |||
| 1089b5a6a6 | |||
| 28a1b5f4f0 | |||
| acf91c3f0e | |||
| fadb9e6d46 | |||
| 17bad4fcfd | |||
| b3dfc35103 | |||
| 602f663217 | |||
| 5ebfbf6aec | |||
| aad0a74ad5 | |||
| 382e24e17b | |||
| 1876c7b43d | |||
| 73af601a16 | |||
| 6247463c70 | |||
| 9425ed9a12 | |||
| 430ad85c37 | |||
| 29e50bd70c | |||
| 0e83e804d8 | |||
| bd674bfb67 | |||
| fec81ac92e | |||
| d3e25eed9e | |||
| ba5f5f2557 | |||
| 7e548ad5d1 | |||
| 7b63bb0d05 | |||
| 788018451a | |||
| 7b3a2d6a3f | |||
| 0d462f848d | |||
| 9c6c338919 | |||
| 8a4570a044 | |||
| e51fc6b4bb | |||
| 0f68d59798 | |||
| 5ad23005be | |||
| 4e096a1d49 | |||
| ac2a361b77 | |||
| 24f8d67020 | |||
| 5bcee2ea9d | |||
| 48d9444dde | |||
| bcdfe87107 | |||
| 5088699c15 | |||
| 854b474970 | |||
| 336aea463b | |||
| fe9c692e12 | |||
| b47ec37a76 | |||
| 996534c62b | |||
| 3ba6543cb4 | |||
| 8b299bcf8f | |||
| 1fa98cf6e3 | |||
| e80d54d0e7 | |||
| b91b61f4f0 | |||
| f0e8c799ff | |||
| b4e7cb8718 | |||
| 7a590e882b | |||
| 9a643ced94 | |||
| 5f2a6478a7 | |||
| 1db929a31b | |||
| 0b2c4071e8 | |||
| 61ecfc5af1 | |||
| 661793f58d | |||
| d253e73099 | |||
| f0d3d311e9 | |||
| 592203aa4a | |||
| aeb35029c3 | |||
| 1dc56d5ec1 | |||
| 51b1ab380c | |||
| b5abddaacb |
183
.drone.yml
183
.drone.yml
@@ -4,102 +4,101 @@ type: docker
|
||||
name: default
|
||||
|
||||
steps:
|
||||
# Frontend
|
||||
- name: web_build
|
||||
image: node:23
|
||||
volumes:
|
||||
- name: web_app
|
||||
path: /tmp/web_build
|
||||
commands:
|
||||
- node -v
|
||||
- npm -v
|
||||
- cd matrixgw_frontend
|
||||
- npm install
|
||||
- npm run lint
|
||||
- npm run build
|
||||
- mv dist /tmp/web_build
|
||||
# Frontend
|
||||
- name: web_build
|
||||
image: node:23
|
||||
volumes:
|
||||
- name: web_app
|
||||
path: /tmp/web_build
|
||||
commands:
|
||||
- node -v
|
||||
- npm -v
|
||||
- cd matrixgw_frontend
|
||||
- npm install
|
||||
- npm run lint
|
||||
- npm run build
|
||||
- mv dist /tmp/web_build
|
||||
|
||||
# Backend
|
||||
- name: backend_fetch_deps
|
||||
image: rust
|
||||
volumes:
|
||||
- name: rust_registry
|
||||
path: /usr/local/cargo/registry
|
||||
commands:
|
||||
- cd matrixgw_backend
|
||||
- cargo fetch
|
||||
# Backend
|
||||
- name: backend_fetch_deps
|
||||
image: rust
|
||||
volumes:
|
||||
- name: rust_registry
|
||||
path: /usr/local/cargo/registry
|
||||
commands:
|
||||
- cd matrixgw_backend
|
||||
- cargo fetch
|
||||
|
||||
- name: backend_code_quality
|
||||
image: rust
|
||||
volumes:
|
||||
- name: rust_registry
|
||||
path: /usr/local/cargo/registry
|
||||
depends_on:
|
||||
- backend_fetch_deps
|
||||
commands:
|
||||
- cd matrixgw_backend
|
||||
- rustup component add clippy
|
||||
- cargo clippy -- -D warnings
|
||||
- cargo clippy --example api_curl -- -D warnings
|
||||
- name: backend_code_quality
|
||||
image: rust
|
||||
volumes:
|
||||
- name: rust_registry
|
||||
path: /usr/local/cargo/registry
|
||||
depends_on:
|
||||
- backend_fetch_deps
|
||||
commands:
|
||||
- cd matrixgw_backend
|
||||
- rustup component add clippy
|
||||
- cargo clippy -- -D warnings
|
||||
- cargo clippy --example api_curl -- -D warnings
|
||||
|
||||
- name: backend_test
|
||||
image: rust
|
||||
volumes:
|
||||
- name: rust_registry
|
||||
path: /usr/local/cargo/registry
|
||||
depends_on:
|
||||
- backend_code_quality
|
||||
commands:
|
||||
- cd matrixgw_backend
|
||||
- cargo test
|
||||
- name: backend_test
|
||||
image: rust
|
||||
volumes:
|
||||
- name: rust_registry
|
||||
path: /usr/local/cargo/registry
|
||||
depends_on:
|
||||
- backend_code_quality
|
||||
commands:
|
||||
- cd matrixgw_backend
|
||||
- cargo test
|
||||
|
||||
- name: backend_build
|
||||
image: rust
|
||||
when:
|
||||
event:
|
||||
- tag
|
||||
volumes:
|
||||
- name: rust_registry
|
||||
path: /usr/local/cargo/registry
|
||||
- name: web_app
|
||||
path: /tmp/web_build
|
||||
- name: release
|
||||
path: /tmp/release
|
||||
depends_on:
|
||||
- backend_test
|
||||
- web_build
|
||||
commands:
|
||||
- cd matrixgw_backend
|
||||
- mv /tmp/web_build/dist static
|
||||
- cargo build --release
|
||||
- cargo build --release --example api_curl
|
||||
- ls -lah target/release/matrixgw_backend target/release/examples/api_curl
|
||||
- cp target/release/matrixgw_backend target/release/examples/api_curl /tmp/release
|
||||
|
||||
- name: backend_build
|
||||
image: rust
|
||||
when:
|
||||
event:
|
||||
- tag
|
||||
volumes:
|
||||
- name: rust_registry
|
||||
path: /usr/local/cargo/registry
|
||||
- name: web_app
|
||||
path: /tmp/web_build
|
||||
- name: release
|
||||
path: /tmp/release
|
||||
depends_on:
|
||||
- backend_test
|
||||
- web_build
|
||||
commands:
|
||||
- cd matrixgw_backend
|
||||
- mv /tmp/web_build/dist static
|
||||
- cargo build --release
|
||||
- cargo build --release --example api_curl
|
||||
- ls -lah target/release/matrixgw_backend target/release/examples/api_curl
|
||||
- cp target/release/matrixgw_backend target/release/examples/api_curl /tmp/release
|
||||
|
||||
# Release
|
||||
- name: gitea_release
|
||||
image: plugins/gitea-release
|
||||
depends_on:
|
||||
- backend_build
|
||||
when:
|
||||
event:
|
||||
- tag
|
||||
volumes:
|
||||
- name: release
|
||||
path: /tmp/release
|
||||
environment:
|
||||
PLUGIN_API_KEY:
|
||||
from_secret: API_KEY
|
||||
settings:
|
||||
base_url: https://gitea.communiquons.org
|
||||
files: /tmp/release/*
|
||||
checksum: sha512
|
||||
# Release
|
||||
- name: gitea_release
|
||||
image: plugins/gitea-release
|
||||
depends_on:
|
||||
- backend_build
|
||||
when:
|
||||
event:
|
||||
- tag
|
||||
volumes:
|
||||
- name: release
|
||||
path: /tmp/release
|
||||
environment:
|
||||
PLUGIN_API_KEY:
|
||||
from_secret: GITEA_API_KEY # needs permission write:repository
|
||||
settings:
|
||||
base_url: https://gitea.communiquons.org
|
||||
files: /tmp/release/*
|
||||
checksum: sha512
|
||||
|
||||
volumes:
|
||||
- name: rust_registry
|
||||
temp: {}
|
||||
- name: web_app
|
||||
temp: {}
|
||||
- name: release
|
||||
temp: {}
|
||||
- name: rust_registry
|
||||
temp: {}
|
||||
- name: web_app
|
||||
temp: {}
|
||||
- name: release
|
||||
temp: {}
|
||||
|
||||
1283
matrixgw_backend/Cargo.lock
generated
1283
matrixgw_backend/Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -6,7 +6,7 @@ edition = "2024"
|
||||
[dependencies]
|
||||
env_logger = "0.11.8"
|
||||
log = "0.4.29"
|
||||
clap = { version = "4.5.53", features = ["derive", "env"] }
|
||||
clap = { version = "4.5.54", features = ["derive", "env"] }
|
||||
lazy_static = "1.5.0"
|
||||
anyhow = "1.0.100"
|
||||
serde = { version = "1.0.228", features = ["derive"] }
|
||||
@@ -27,12 +27,13 @@ ipnet = { version = "2.11.0", features = ["serde"] }
|
||||
rand = "0.9.2"
|
||||
hex = "0.4.3"
|
||||
mailchecker = "6.0.19"
|
||||
matrix-sdk = { version = "0.14.0" }
|
||||
url = "2.5.7"
|
||||
ractor = "0.15.9"
|
||||
serde_json = "1.0.145"
|
||||
matrix-sdk = { version = "0.16.0", features = ["e2e-encryption"] }
|
||||
matrix-sdk-ui = "0.16.0"
|
||||
url = "2.5.8"
|
||||
ractor = "0.15.10"
|
||||
serde_json = "1.0.149"
|
||||
lazy-regex = "3.4.2"
|
||||
actix-ws = "0.3.0"
|
||||
actix-ws = "0.3.1"
|
||||
infer = "0.19.0"
|
||||
rust-embed = "8.9.0"
|
||||
mime_guess = "2.0.5"
|
||||
@@ -4,11 +4,9 @@ use crate::utils::crypt_utils::sha512;
|
||||
use actix_web::dev::Payload;
|
||||
use actix_web::http::header;
|
||||
use actix_web::{FromRequest, HttpRequest, HttpResponse, web};
|
||||
use matrix_sdk::crypto::{AttachmentDecryptor, MediaEncryptionInfo};
|
||||
use matrix_sdk::media::{MediaFormat, MediaRequestParameters, MediaThumbnailSettings};
|
||||
use matrix_sdk::ruma::events::room::MediaSource;
|
||||
use matrix_sdk::ruma::{OwnedMxcUri, UInt};
|
||||
use std::io::{Cursor, Read};
|
||||
|
||||
#[derive(serde::Deserialize)]
|
||||
pub struct MediaMXCInPath {
|
||||
@@ -54,21 +52,6 @@ pub async fn serve_media(req: HttpRequest, source: MediaSource, thumbnail: bool)
|
||||
)
|
||||
.await?;
|
||||
|
||||
// Decrypt file if needed
|
||||
let media = if let MediaSource::Encrypted(file) = source {
|
||||
let mut cursor = Cursor::new(media);
|
||||
let mut decryptor =
|
||||
AttachmentDecryptor::new(&mut cursor, MediaEncryptionInfo::from(*file))?;
|
||||
|
||||
let mut decrypted_data = Vec::new();
|
||||
|
||||
decryptor.read_to_end(&mut decrypted_data)?;
|
||||
|
||||
decrypted_data
|
||||
} else {
|
||||
media
|
||||
};
|
||||
|
||||
let digest = sha512(&media);
|
||||
|
||||
let mime_type = infer::get(&media).map(|x| x.mime_type());
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
use crate::controllers::HttpResult;
|
||||
use crate::extractors::matrix_client_extractor::MatrixClientExtractor;
|
||||
use actix_web::HttpResponse;
|
||||
use matrix_sdk_ui::spaces::SpaceService;
|
||||
use matrix_sdk_ui::spaces::room_list::SpaceRoomListPaginationState;
|
||||
use std::collections::HashMap;
|
||||
|
||||
/// Get space hierarchy
|
||||
pub async fn hierarchy(client: MatrixClientExtractor) -> HttpResult {
|
||||
let spaces = client.client.client.joined_space_rooms();
|
||||
let space_service = SpaceService::new(client.client.client);
|
||||
let mut hierarchy = HashMap::new();
|
||||
for space in spaces {
|
||||
let rooms = space_service
|
||||
.space_room_list(space.room_id().to_owned())
|
||||
.await;
|
||||
while !matches!(
|
||||
rooms.pagination_state(),
|
||||
SpaceRoomListPaginationState::Idle { end_reached: true }
|
||||
) {
|
||||
rooms.paginate().await?;
|
||||
}
|
||||
|
||||
hierarchy.insert(
|
||||
space.room_id().to_owned(),
|
||||
rooms
|
||||
.rooms()
|
||||
.into_iter()
|
||||
.map(|room| room.room_id)
|
||||
.collect::<Vec<_>>(),
|
||||
);
|
||||
}
|
||||
Ok(HttpResponse::Ok().json(hierarchy))
|
||||
}
|
||||
@@ -2,3 +2,4 @@ pub mod matrix_event_controller;
|
||||
pub mod matrix_media_controller;
|
||||
pub mod matrix_profile_controller;
|
||||
pub mod matrix_room_controller;
|
||||
pub mod matrix_space_controller;
|
||||
|
||||
@@ -11,7 +11,7 @@ use matrixgw_backend::broadcast_messages::BroadcastMessage;
|
||||
use matrixgw_backend::constants;
|
||||
use matrixgw_backend::controllers::matrix::{
|
||||
matrix_event_controller, matrix_media_controller, matrix_profile_controller,
|
||||
matrix_room_controller,
|
||||
matrix_room_controller, matrix_space_controller,
|
||||
};
|
||||
use matrixgw_backend::controllers::{
|
||||
auth_controller, matrix_link_controller, matrix_sync_thread_controller, server_controller,
|
||||
@@ -138,6 +138,11 @@ async fn main() -> std::io::Result<()> {
|
||||
web::get().to(matrix_sync_thread_controller::status),
|
||||
)
|
||||
.service(web::resource("/api/ws").route(web::get().to(ws_controller::ws)))
|
||||
// Matrix spaces controller
|
||||
.route(
|
||||
"/api/matrix/space/hierarchy",
|
||||
web::get().to(matrix_space_controller::hierarchy),
|
||||
)
|
||||
// Matrix room controller
|
||||
.route(
|
||||
"/api/matrix/room/joined",
|
||||
|
||||
444
matrixgw_frontend/package-lock.json
generated
444
matrixgw_frontend/package-lock.json
generated
@@ -11,36 +11,34 @@
|
||||
"@emotion/react": "^11.14.0",
|
||||
"@emotion/styled": "^11.14.1",
|
||||
"@fontsource/roboto": "^5.2.9",
|
||||
"@mdi/js": "^7.4.47",
|
||||
"@mdi/react": "^1.6.1",
|
||||
"@mui/icons-material": "^7.3.6",
|
||||
"@mui/material": "^7.3.6",
|
||||
"@mui/x-data-grid": "^8.20.0",
|
||||
"@mui/x-date-pickers": "^8.19.0",
|
||||
"date-and-time": "^4.1.1",
|
||||
"@mui/icons-material": "^7.3.7",
|
||||
"@mui/material": "^7.3.7",
|
||||
"@mui/x-data-grid": "^8.24.0",
|
||||
"@mui/x-date-pickers": "^8.23.0",
|
||||
"date-and-time": "^4.1.2",
|
||||
"dayjs": "^1.11.19",
|
||||
"emoji-picker-react": "^4.16.1",
|
||||
"is-cidr": "^6.0.1",
|
||||
"qrcode.react": "^4.2.0",
|
||||
"react": "^19.1.1",
|
||||
"react-dom": "^19.1.1",
|
||||
"react": "^19.2.3",
|
||||
"react-dom": "^19.2.3",
|
||||
"react-favicon": "^2.0.7",
|
||||
"react-json-view-lite": "^2.5.0",
|
||||
"react-router": "^7.10.0"
|
||||
"react-router": "^7.12.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.39.1",
|
||||
"@types/node": "^24.10.1",
|
||||
"@types/react": "^19.2.7",
|
||||
"@eslint/js": "^9.39.2",
|
||||
"@types/node": "^24.10.9",
|
||||
"@types/react": "^19.2.8",
|
||||
"@types/react-dom": "^19.2.3",
|
||||
"@vitejs/plugin-react": "^5.1.1",
|
||||
"eslint": "^9.39.1",
|
||||
"@vitejs/plugin-react": "^5.1.2",
|
||||
"eslint": "^9.39.2",
|
||||
"eslint-plugin-react-hooks": "^7.0.1",
|
||||
"eslint-plugin-react-refresh": "^0.4.22",
|
||||
"eslint-plugin-react-refresh": "^0.4.26",
|
||||
"globals": "^16.5.0",
|
||||
"typescript": "~5.9.3",
|
||||
"typescript-eslint": "^8.48.1",
|
||||
"vite": "npm:rolldown-vite@7.2.10"
|
||||
"typescript-eslint": "^8.51.0",
|
||||
"vite": "npm:rolldown-vite@7.3.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/code-frame": {
|
||||
@@ -634,9 +632,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/js": {
|
||||
"version": "9.39.1",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.1.tgz",
|
||||
"integrity": "sha512-S26Stp4zCy88tH94QbBv3XCuzRQiZ9yXofEILmglYTh/Ug/a9/umqvgFtYBAo3Lp0nsI/5/qH1CCrbdK3AP1Tw==",
|
||||
"version": "9.39.2",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.2.tgz",
|
||||
"integrity": "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -777,25 +775,10 @@
|
||||
"@jridgewell/sourcemap-codec": "^1.4.14"
|
||||
}
|
||||
},
|
||||
"node_modules/@mdi/js": {
|
||||
"version": "7.4.47",
|
||||
"resolved": "https://registry.npmjs.org/@mdi/js/-/js-7.4.47.tgz",
|
||||
"integrity": "sha512-KPnNOtm5i2pMabqZxpUz7iQf+mfrYZyKCZ8QNz85czgEt7cuHcGorWfdzUMWYA0SD+a6Hn4FmJ+YhzzzjkTZrQ==",
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/@mdi/react": {
|
||||
"version": "1.6.1",
|
||||
"resolved": "https://registry.npmjs.org/@mdi/react/-/react-1.6.1.tgz",
|
||||
"integrity": "sha512-4qZeDcluDFGFTWkHs86VOlHkm6gnKaMql13/gpIcUQ8kzxHgpj31NuCkD8abECVfbULJ3shc7Yt4HJ6Wu6SN4w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prop-types": "^15.7.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@mui/core-downloads-tracker": {
|
||||
"version": "7.3.6",
|
||||
"resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-7.3.6.tgz",
|
||||
"integrity": "sha512-QaYtTHlr8kDFN5mE1wbvVARRKH7Fdw1ZuOjBJcFdVpfNfRYKF3QLT4rt+WaB6CKJvpqxRsmEo0kpYinhH5GeHg==",
|
||||
"version": "7.3.7",
|
||||
"resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-7.3.7.tgz",
|
||||
"integrity": "sha512-8jWwS6FweMkpyRkrJooamUGe1CQfO1yJ+lM43IyUJbrhHW/ObES+6ry4vfGi8EKaldHL3t3BG1bcLcERuJPcjg==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
@@ -803,9 +786,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@mui/icons-material": {
|
||||
"version": "7.3.6",
|
||||
"resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-7.3.6.tgz",
|
||||
"integrity": "sha512-0FfkXEj22ysIq5pa41A2NbcAhJSvmcZQ/vcTIbjDsd6hlslG82k5BEBqqS0ZJprxwIL3B45qpJ+bPHwJPlF7uQ==",
|
||||
"version": "7.3.7",
|
||||
"resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-7.3.7.tgz",
|
||||
"integrity": "sha512-3Q+ulAqG+A1+R4ebgoIs7AccaJhIGy+Xi/9OnvX376jQ6wcy+rz4geDGrxQxCGzdjOQr4Z3NgyFSZCz4T999lA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.28.4"
|
||||
@@ -818,7 +801,7 @@
|
||||
"url": "https://opencollective.com/mui-org"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@mui/material": "^7.3.6",
|
||||
"@mui/material": "^7.3.7",
|
||||
"@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||
"react": "^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||
},
|
||||
@@ -829,23 +812,23 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@mui/material": {
|
||||
"version": "7.3.6",
|
||||
"resolved": "https://registry.npmjs.org/@mui/material/-/material-7.3.6.tgz",
|
||||
"integrity": "sha512-R4DaYF3dgCQCUAkr4wW1w26GHXcf5rCmBRHVBuuvJvaGLmZdD8EjatP80Nz5JCw0KxORAzwftnHzXVnjR8HnFw==",
|
||||
"version": "7.3.7",
|
||||
"resolved": "https://registry.npmjs.org/@mui/material/-/material-7.3.7.tgz",
|
||||
"integrity": "sha512-6bdIxqzeOtBAj2wAsfhWCYyMKPLkRO9u/2o5yexcL0C3APqyy91iGSWgT3H7hg+zR2XgE61+WAu12wXPON8b6A==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.28.4",
|
||||
"@mui/core-downloads-tracker": "^7.3.6",
|
||||
"@mui/system": "^7.3.6",
|
||||
"@mui/types": "^7.4.9",
|
||||
"@mui/utils": "^7.3.6",
|
||||
"@mui/core-downloads-tracker": "^7.3.7",
|
||||
"@mui/system": "^7.3.7",
|
||||
"@mui/types": "^7.4.10",
|
||||
"@mui/utils": "^7.3.7",
|
||||
"@popperjs/core": "^2.11.8",
|
||||
"@types/react-transition-group": "^4.4.12",
|
||||
"clsx": "^2.1.1",
|
||||
"csstype": "^3.1.3",
|
||||
"csstype": "^3.2.3",
|
||||
"prop-types": "^15.8.1",
|
||||
"react-is": "^19.2.0",
|
||||
"react-is": "^19.2.3",
|
||||
"react-transition-group": "^4.4.5"
|
||||
},
|
||||
"engines": {
|
||||
@@ -858,7 +841,7 @@
|
||||
"peerDependencies": {
|
||||
"@emotion/react": "^11.5.0",
|
||||
"@emotion/styled": "^11.3.0",
|
||||
"@mui/material-pigment-css": "^7.3.6",
|
||||
"@mui/material-pigment-css": "^7.3.7",
|
||||
"@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||
"react": "^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||
"react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||
@@ -879,13 +862,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@mui/private-theming": {
|
||||
"version": "7.3.6",
|
||||
"resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-7.3.6.tgz",
|
||||
"integrity": "sha512-Ws9wZpqM+FlnbZXaY/7yvyvWQo1+02Tbx50mVdNmzWEi51C51y56KAbaDCYyulOOBL6BJxuaqG8rNNuj7ivVyw==",
|
||||
"version": "7.3.7",
|
||||
"resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-7.3.7.tgz",
|
||||
"integrity": "sha512-w7r1+CYhG0syCAQUWAuV5zSaU2/67WA9JXUderdb7DzCIJdp/5RmJv6L85wRjgKCMsxFF0Kfn0kPgPbPgw/jdw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.28.4",
|
||||
"@mui/utils": "^7.3.6",
|
||||
"@mui/utils": "^7.3.7",
|
||||
"prop-types": "^15.8.1"
|
||||
},
|
||||
"engines": {
|
||||
@@ -906,16 +889,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@mui/styled-engine": {
|
||||
"version": "7.3.6",
|
||||
"resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-7.3.6.tgz",
|
||||
"integrity": "sha512-+wiYbtvj+zyUkmDB+ysH6zRjuQIJ+CM56w0fEXV+VDNdvOuSywG+/8kpjddvvlfMLsaWdQe5oTuYGBcodmqGzQ==",
|
||||
"version": "7.3.7",
|
||||
"resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-7.3.7.tgz",
|
||||
"integrity": "sha512-y/QkNXv6cF6dZ5APztd/dFWfQ6LHKPx3skyYO38YhQD4+Cxd6sFAL3Z38WMSSC8LQz145Mpp3CcLrSCLKPwYAg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.28.4",
|
||||
"@emotion/cache": "^11.14.0",
|
||||
"@emotion/serialize": "^1.3.3",
|
||||
"@emotion/sheet": "^1.4.0",
|
||||
"csstype": "^3.1.3",
|
||||
"csstype": "^3.2.3",
|
||||
"prop-types": "^15.8.1"
|
||||
},
|
||||
"engines": {
|
||||
@@ -940,19 +923,19 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@mui/system": {
|
||||
"version": "7.3.6",
|
||||
"resolved": "https://registry.npmjs.org/@mui/system/-/system-7.3.6.tgz",
|
||||
"integrity": "sha512-8fehAazkHNP1imMrdD2m2hbA9sl7Ur6jfuNweh5o4l9YPty4iaZzRXqYvBCWQNwFaSHmMEj2KPbyXGp7Bt73Rg==",
|
||||
"version": "7.3.7",
|
||||
"resolved": "https://registry.npmjs.org/@mui/system/-/system-7.3.7.tgz",
|
||||
"integrity": "sha512-DovL3k+FBRKnhmatzUMyO5bKkhMLlQ9L7Qw5qHrre3m8zCZmE+31NDVBFfqrbrA7sq681qaEIHdkWD5nmiAjyQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.28.4",
|
||||
"@mui/private-theming": "^7.3.6",
|
||||
"@mui/styled-engine": "^7.3.6",
|
||||
"@mui/types": "^7.4.9",
|
||||
"@mui/utils": "^7.3.6",
|
||||
"@mui/private-theming": "^7.3.7",
|
||||
"@mui/styled-engine": "^7.3.7",
|
||||
"@mui/types": "^7.4.10",
|
||||
"@mui/utils": "^7.3.7",
|
||||
"clsx": "^2.1.1",
|
||||
"csstype": "^3.1.3",
|
||||
"csstype": "^3.2.3",
|
||||
"prop-types": "^15.8.1"
|
||||
},
|
||||
"engines": {
|
||||
@@ -981,9 +964,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@mui/types": {
|
||||
"version": "7.4.9",
|
||||
"resolved": "https://registry.npmjs.org/@mui/types/-/types-7.4.9.tgz",
|
||||
"integrity": "sha512-dNO8Z9T2cujkSIaCnWwprfeKmTWh97cnjkgmpFJ2sbfXLx8SMZijCYHOtP/y5nnUb/Rm2omxbDMmtUoSaUtKaw==",
|
||||
"version": "7.4.10",
|
||||
"resolved": "https://registry.npmjs.org/@mui/types/-/types-7.4.10.tgz",
|
||||
"integrity": "sha512-0+4mSjknSu218GW3isRqoxKRTOrTLd/vHi/7UC4+wZcUrOAqD9kRk7UQRL1mcrzqRoe7s3UT6rsRpbLkW5mHpQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.28.4"
|
||||
@@ -998,17 +981,17 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@mui/utils": {
|
||||
"version": "7.3.6",
|
||||
"resolved": "https://registry.npmjs.org/@mui/utils/-/utils-7.3.6.tgz",
|
||||
"integrity": "sha512-jn+Ba02O6PiFs7nKva8R2aJJ9kJC+3kQ2R0BbKNY3KQQ36Qng98GnPRFTlbwYTdMD6hLEBKaMLUktyg/rTfd2w==",
|
||||
"version": "7.3.7",
|
||||
"resolved": "https://registry.npmjs.org/@mui/utils/-/utils-7.3.7.tgz",
|
||||
"integrity": "sha512-+YjnjMRnyeTkWnspzoxRdiSOgkrcpTikhNPoxOZW0APXx+urHtUoXJ9lbtCZRCA5a4dg5gSbd19alL1DvRs5fg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.28.4",
|
||||
"@mui/types": "^7.4.9",
|
||||
"@mui/types": "^7.4.10",
|
||||
"@types/prop-types": "^15.7.15",
|
||||
"clsx": "^2.1.1",
|
||||
"prop-types": "^15.8.1",
|
||||
"react-is": "^19.2.0"
|
||||
"react-is": "^19.2.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
@@ -1028,15 +1011,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@mui/x-data-grid": {
|
||||
"version": "8.20.0",
|
||||
"resolved": "https://registry.npmjs.org/@mui/x-data-grid/-/x-data-grid-8.20.0.tgz",
|
||||
"integrity": "sha512-PXZOZjxEcD3XL26EQN+wBS8/f5dY2JhprHk0Cm8hjoapvuFYChDPl1hA3QrbU0rpWNIOKotsLrnNBpXNgzQzKQ==",
|
||||
"version": "8.24.0",
|
||||
"resolved": "https://registry.npmjs.org/@mui/x-data-grid/-/x-data-grid-8.24.0.tgz",
|
||||
"integrity": "sha512-OCTrskRlxwJZ+vYWbgQnQPXWNMA/nY/RIkoESjbCG38N9fJicVCdyjszjcQn9V1NQH4fwkMlIN+DVU6zzbqJxQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.28.4",
|
||||
"@mui/utils": "^7.3.5",
|
||||
"@mui/x-internals": "8.19.0",
|
||||
"@mui/x-virtualizer": "0.2.10",
|
||||
"@mui/x-internals": "8.24.0",
|
||||
"@mui/x-virtualizer": "0.3.1",
|
||||
"clsx": "^2.1.1",
|
||||
"prop-types": "^15.8.1",
|
||||
"use-sync-external-store": "^1.6.0"
|
||||
@@ -1065,15 +1048,37 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@mui/x-date-pickers": {
|
||||
"version": "8.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@mui/x-date-pickers/-/x-date-pickers-8.19.0.tgz",
|
||||
"integrity": "sha512-TQ4FsGUsiGJVs+Ie4q7nHXUmFqZADXL/1hVtZpOKsdr3WQXwpX7C5YmeakZGFR2NZnuv4snFj+WTee3kgyFbyQ==",
|
||||
"node_modules/@mui/x-data-grid/node_modules/@mui/x-internals": {
|
||||
"version": "8.24.0",
|
||||
"resolved": "https://registry.npmjs.org/@mui/x-internals/-/x-internals-8.24.0.tgz",
|
||||
"integrity": "sha512-tHPk8eUcuwvhNsAc4zcia8y+issjC+bLGssrQQSdLLeLIf9ewFbcwAURNTSnNhreyj/4RJOemVrSxKXpjkdVvQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.28.4",
|
||||
"@mui/utils": "^7.3.5",
|
||||
"@mui/x-internals": "8.19.0",
|
||||
"reselect": "^5.1.1",
|
||||
"use-sync-external-store": "^1.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/mui-org"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@mui/x-date-pickers": {
|
||||
"version": "8.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@mui/x-date-pickers/-/x-date-pickers-8.23.0.tgz",
|
||||
"integrity": "sha512-uKtam5wqMEuErmRxZLPEX/7CZZFTMfrl05V9cWNjBkpGTcdDBIs1Kba8z2pfQU93e9lSLrRlxbCMJzCu6iF0Rg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.28.4",
|
||||
"@mui/utils": "^7.3.5",
|
||||
"@mui/x-internals": "8.23.0",
|
||||
"@types/react-transition-group": "^4.4.12",
|
||||
"clsx": "^2.1.1",
|
||||
"prop-types": "^15.8.1",
|
||||
@@ -1132,9 +1137,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@mui/x-internals": {
|
||||
"version": "8.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@mui/x-internals/-/x-internals-8.19.0.tgz",
|
||||
"integrity": "sha512-mMmiyJAN5fW27srXJjhXhXJa+w2xGO45rwcjws6OQc9rdXGdJqRXhBwJd+OT7J1xwSdFIIUhjZRTz1KAfCSGBg==",
|
||||
"version": "8.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@mui/x-internals/-/x-internals-8.23.0.tgz",
|
||||
"integrity": "sha512-FN7wdqwTxqq1tJBYVz8TA/HMcViuaHS0Jphr4pEjT/8Iuf94Yt3P82WbsTbXyYrgOQDQl07UqE7qWcJetRcHcg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.28.4",
|
||||
@@ -1154,14 +1159,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@mui/x-virtualizer": {
|
||||
"version": "0.2.10",
|
||||
"resolved": "https://registry.npmjs.org/@mui/x-virtualizer/-/x-virtualizer-0.2.10.tgz",
|
||||
"integrity": "sha512-PGZeWFQzyw3IuxuoDT8NewwSseO6PxR86iC7WGMfmUwJ3s1Z2XL83PXlAxLeqJ4Oi9Y4+4wQ7m6bLAKg7VQ3kg==",
|
||||
"version": "0.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@mui/x-virtualizer/-/x-virtualizer-0.3.1.tgz",
|
||||
"integrity": "sha512-MhQ7U/zmSofBxeCRMiolhZWJ80RUJMFFMRqeehJu5GqscnudiVcplZb0eNsAkz9IjnJTyrjyLS0PY+kn78enOw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.28.4",
|
||||
"@mui/utils": "^7.3.5",
|
||||
"@mui/x-internals": "8.19.0"
|
||||
"@mui/x-internals": "8.24.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
@@ -1175,6 +1180,28 @@
|
||||
"react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@mui/x-virtualizer/node_modules/@mui/x-internals": {
|
||||
"version": "8.24.0",
|
||||
"resolved": "https://registry.npmjs.org/@mui/x-internals/-/x-internals-8.24.0.tgz",
|
||||
"integrity": "sha512-tHPk8eUcuwvhNsAc4zcia8y+issjC+bLGssrQQSdLLeLIf9ewFbcwAURNTSnNhreyj/4RJOemVrSxKXpjkdVvQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.28.4",
|
||||
"@mui/utils": "^7.3.5",
|
||||
"reselect": "^5.1.1",
|
||||
"use-sync-external-store": "^1.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/mui-org"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@napi-rs/wasm-runtime": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.0.tgz",
|
||||
@@ -1440,9 +1467,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/pluginutils": {
|
||||
"version": "1.0.0-beta.47",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.47.tgz",
|
||||
"integrity": "sha512-8QagwMH3kNCuzD8EWL8R2YPW5e4OrHNSAHRFDdmFqEwEaD/KcNKjVoumo+gP2vW5eKB2UPbM6vTYiGZX0ixLnw==",
|
||||
"version": "1.0.0-beta.53",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.53.tgz",
|
||||
"integrity": "sha512-vENRlFU4YbrwVqNDZ7fLvy+JR1CRkyr01jhSiDpE1u6py3OMzQfztQU2jxykW3ALNxO4kSlqIDeYyD0Y9RcQeQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
@@ -1517,9 +1544,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "24.10.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.1.tgz",
|
||||
"integrity": "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==",
|
||||
"version": "24.10.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.9.tgz",
|
||||
"integrity": "sha512-ne4A0IpG3+2ETuREInjPNhUGis1SFjv1d5asp8MzEAGtOZeTeHVDOYqOgqfhvseqg/iXty2hjBf1zAOb7RNiNw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
@@ -1540,9 +1567,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/react": {
|
||||
"version": "19.2.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.7.tgz",
|
||||
"integrity": "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==",
|
||||
"version": "19.2.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.8.tgz",
|
||||
"integrity": "sha512-3MbSL37jEchWZz2p2mjntRZtPt837ij10ApxKfgmXCTuHWagYg7iA5bqPw6C8BMPfwidlvfPI/fxOc42HLhcyg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
@@ -1569,21 +1596,20 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||
"version": "8.48.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.48.1.tgz",
|
||||
"integrity": "sha512-X63hI1bxl5ohelzr0LY5coufyl0LJNthld+abwxpCoo6Gq+hSqhKwci7MUWkXo67mzgUK6YFByhmaHmUcuBJmA==",
|
||||
"version": "8.51.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.51.0.tgz",
|
||||
"integrity": "sha512-XtssGWJvypyM2ytBnSnKtHYOGT+4ZwTnBVl36TA4nRO2f4PRNGz5/1OszHzcZCvcBMh+qb7I06uoCmLTRdR9og==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eslint-community/regexpp": "^4.10.0",
|
||||
"@typescript-eslint/scope-manager": "8.48.1",
|
||||
"@typescript-eslint/type-utils": "8.48.1",
|
||||
"@typescript-eslint/utils": "8.48.1",
|
||||
"@typescript-eslint/visitor-keys": "8.48.1",
|
||||
"graphemer": "^1.4.0",
|
||||
"@typescript-eslint/scope-manager": "8.51.0",
|
||||
"@typescript-eslint/type-utils": "8.51.0",
|
||||
"@typescript-eslint/utils": "8.51.0",
|
||||
"@typescript-eslint/visitor-keys": "8.51.0",
|
||||
"ignore": "^7.0.0",
|
||||
"natural-compare": "^1.4.0",
|
||||
"ts-api-utils": "^2.1.0"
|
||||
"ts-api-utils": "^2.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
@@ -1593,7 +1619,7 @@
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@typescript-eslint/parser": "^8.48.1",
|
||||
"@typescript-eslint/parser": "^8.51.0",
|
||||
"eslint": "^8.57.0 || ^9.0.0",
|
||||
"typescript": ">=4.8.4 <6.0.0"
|
||||
}
|
||||
@@ -1609,17 +1635,17 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/parser": {
|
||||
"version": "8.48.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.48.1.tgz",
|
||||
"integrity": "sha512-PC0PDZfJg8sP7cmKe6L3QIL8GZwU5aRvUFedqSIpw3B+QjRSUZeeITC2M5XKeMXEzL6wccN196iy3JLwKNvDVA==",
|
||||
"version": "8.51.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.51.0.tgz",
|
||||
"integrity": "sha512-3xP4XzzDNQOIqBMWogftkwxhg5oMKApqY0BAflmLZiFYHqyhSOxv/cd/zPQLTcCXr4AkaKb25joocY0BD1WC6A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "8.48.1",
|
||||
"@typescript-eslint/types": "8.48.1",
|
||||
"@typescript-eslint/typescript-estree": "8.48.1",
|
||||
"@typescript-eslint/visitor-keys": "8.48.1",
|
||||
"@typescript-eslint/scope-manager": "8.51.0",
|
||||
"@typescript-eslint/types": "8.51.0",
|
||||
"@typescript-eslint/typescript-estree": "8.51.0",
|
||||
"@typescript-eslint/visitor-keys": "8.51.0",
|
||||
"debug": "^4.3.4"
|
||||
},
|
||||
"engines": {
|
||||
@@ -1635,14 +1661,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/project-service": {
|
||||
"version": "8.48.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.48.1.tgz",
|
||||
"integrity": "sha512-HQWSicah4s9z2/HifRPQ6b6R7G+SBx64JlFQpgSSHWPKdvCZX57XCbszg/bapbRsOEv42q5tayTYcEFpACcX1w==",
|
||||
"version": "8.51.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.51.0.tgz",
|
||||
"integrity": "sha512-Luv/GafO07Z7HpiI7qeEW5NW8HUtZI/fo/kE0YbtQEFpJRUuR0ajcWfCE5bnMvL7QQFrmT/odMe8QZww8X2nfQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/tsconfig-utils": "^8.48.1",
|
||||
"@typescript-eslint/types": "^8.48.1",
|
||||
"@typescript-eslint/tsconfig-utils": "^8.51.0",
|
||||
"@typescript-eslint/types": "^8.51.0",
|
||||
"debug": "^4.3.4"
|
||||
},
|
||||
"engines": {
|
||||
@@ -1657,14 +1683,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/scope-manager": {
|
||||
"version": "8.48.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.48.1.tgz",
|
||||
"integrity": "sha512-rj4vWQsytQbLxC5Bf4XwZ0/CKd362DkWMUkviT7DCS057SK64D5lH74sSGzhI6PDD2HCEq02xAP9cX68dYyg1w==",
|
||||
"version": "8.51.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.51.0.tgz",
|
||||
"integrity": "sha512-JhhJDVwsSx4hiOEQPeajGhCWgBMBwVkxC/Pet53EpBVs7zHHtayKefw1jtPaNRXpI9RA2uocdmpdfE7T+NrizA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.48.1",
|
||||
"@typescript-eslint/visitor-keys": "8.48.1"
|
||||
"@typescript-eslint/types": "8.51.0",
|
||||
"@typescript-eslint/visitor-keys": "8.51.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
@@ -1675,9 +1701,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/tsconfig-utils": {
|
||||
"version": "8.48.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.48.1.tgz",
|
||||
"integrity": "sha512-k0Jhs4CpEffIBm6wPaCXBAD7jxBtrHjrSgtfCjUvPp9AZ78lXKdTR8fxyZO5y4vWNlOvYXRtngSZNSn+H53Jkw==",
|
||||
"version": "8.51.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.51.0.tgz",
|
||||
"integrity": "sha512-Qi5bSy/vuHeWyir2C8u/uqGMIlIDu8fuiYWv48ZGlZ/k+PRPHtaAu7erpc7p5bzw2WNNSniuxoMSO4Ar6V9OXw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -1692,17 +1718,17 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/type-utils": {
|
||||
"version": "8.48.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.48.1.tgz",
|
||||
"integrity": "sha512-1jEop81a3LrJQLTf/1VfPQdhIY4PlGDBc/i67EVWObrtvcziysbLN3oReexHOM6N3jyXgCrkBsZpqwH0hiDOQg==",
|
||||
"version": "8.51.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.51.0.tgz",
|
||||
"integrity": "sha512-0XVtYzxnobc9K0VU7wRWg1yiUrw4oQzexCG2V2IDxxCxhqBMSMbjB+6o91A+Uc0GWtgjCa3Y8bi7hwI0Tu4n5Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.48.1",
|
||||
"@typescript-eslint/typescript-estree": "8.48.1",
|
||||
"@typescript-eslint/utils": "8.48.1",
|
||||
"@typescript-eslint/types": "8.51.0",
|
||||
"@typescript-eslint/typescript-estree": "8.51.0",
|
||||
"@typescript-eslint/utils": "8.51.0",
|
||||
"debug": "^4.3.4",
|
||||
"ts-api-utils": "^2.1.0"
|
||||
"ts-api-utils": "^2.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
@@ -1717,9 +1743,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/types": {
|
||||
"version": "8.48.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.48.1.tgz",
|
||||
"integrity": "sha512-+fZ3LZNeiELGmimrujsDCT4CRIbq5oXdHe7chLiW8qzqyPMnn1puNstCrMNVAqwcl2FdIxkuJ4tOs/RFDBVc/Q==",
|
||||
"version": "8.51.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.51.0.tgz",
|
||||
"integrity": "sha512-TizAvWYFM6sSscmEakjY3sPqGwxZRSywSsPEiuZF6d5GmGD9Gvlsv0f6N8FvAAA0CD06l3rIcWNbsN1e5F/9Ag==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -1731,21 +1757,21 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree": {
|
||||
"version": "8.48.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.48.1.tgz",
|
||||
"integrity": "sha512-/9wQ4PqaefTK6POVTjJaYS0bynCgzh6ClJHGSBj06XEHjkfylzB+A3qvyaXnErEZSaxhIo4YdyBgq6j4RysxDg==",
|
||||
"version": "8.51.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.51.0.tgz",
|
||||
"integrity": "sha512-1qNjGqFRmlq0VW5iVlcyHBbCjPB7y6SxpBkrbhNWMy/65ZoncXCEPJxkRZL8McrseNH6lFhaxCIaX+vBuFnRng==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/project-service": "8.48.1",
|
||||
"@typescript-eslint/tsconfig-utils": "8.48.1",
|
||||
"@typescript-eslint/types": "8.48.1",
|
||||
"@typescript-eslint/visitor-keys": "8.48.1",
|
||||
"@typescript-eslint/project-service": "8.51.0",
|
||||
"@typescript-eslint/tsconfig-utils": "8.51.0",
|
||||
"@typescript-eslint/types": "8.51.0",
|
||||
"@typescript-eslint/visitor-keys": "8.51.0",
|
||||
"debug": "^4.3.4",
|
||||
"minimatch": "^9.0.4",
|
||||
"semver": "^7.6.0",
|
||||
"tinyglobby": "^0.2.15",
|
||||
"ts-api-utils": "^2.1.0"
|
||||
"ts-api-utils": "^2.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
@@ -1798,16 +1824,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/utils": {
|
||||
"version": "8.48.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.48.1.tgz",
|
||||
"integrity": "sha512-fAnhLrDjiVfey5wwFRwrweyRlCmdz5ZxXz2G/4cLn0YDLjTapmN4gcCsTBR1N2rWnZSDeWpYtgLDsJt+FpmcwA==",
|
||||
"version": "8.51.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.51.0.tgz",
|
||||
"integrity": "sha512-11rZYxSe0zabiKaCP2QAwRf/dnmgFgvTmeDTtZvUvXG3UuAdg/GU02NExmmIXzz3vLGgMdtrIosI84jITQOxUA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.7.0",
|
||||
"@typescript-eslint/scope-manager": "8.48.1",
|
||||
"@typescript-eslint/types": "8.48.1",
|
||||
"@typescript-eslint/typescript-estree": "8.48.1"
|
||||
"@typescript-eslint/scope-manager": "8.51.0",
|
||||
"@typescript-eslint/types": "8.51.0",
|
||||
"@typescript-eslint/typescript-estree": "8.51.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
@@ -1822,13 +1848,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/visitor-keys": {
|
||||
"version": "8.48.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.48.1.tgz",
|
||||
"integrity": "sha512-BmxxndzEWhE4TIEEMBs8lP3MBWN3jFPs/p6gPm/wkv02o41hI6cq9AuSmGAaTTHPtA1FTi2jBre4A9rm5ZmX+Q==",
|
||||
"version": "8.51.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.51.0.tgz",
|
||||
"integrity": "sha512-mM/JRQOzhVN1ykejrvwnBRV3+7yTKK8tVANVN3o1O0t0v7o+jqdVu9crPy5Y9dov15TJk/FTIgoUGHrTOVL3Zg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.48.1",
|
||||
"@typescript-eslint/types": "8.51.0",
|
||||
"eslint-visitor-keys": "^4.2.1"
|
||||
},
|
||||
"engines": {
|
||||
@@ -1840,16 +1866,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vitejs/plugin-react": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.1.1.tgz",
|
||||
"integrity": "sha512-WQfkSw0QbQ5aJ2CHYw23ZGkqnRwqKHD/KYsMeTkZzPT4Jcf0DcBxBtwMJxnu6E7oxw5+JC6ZAiePgh28uJ1HBA==",
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.1.2.tgz",
|
||||
"integrity": "sha512-EcA07pHJouywpzsoTUqNh5NwGayl2PPVEJKUSinGGSxFGYn+shYbqMGBg6FXDqgXum9Ou/ecb+411ssw8HImJQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.28.5",
|
||||
"@babel/plugin-transform-react-jsx-self": "^7.27.1",
|
||||
"@babel/plugin-transform-react-jsx-source": "^7.27.1",
|
||||
"@rolldown/pluginutils": "1.0.0-beta.47",
|
||||
"@rolldown/pluginutils": "1.0.0-beta.53",
|
||||
"@types/babel__core": "^7.20.5",
|
||||
"react-refresh": "^0.18.0"
|
||||
},
|
||||
@@ -2160,9 +2186,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/date-and-time": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/date-and-time/-/date-and-time-4.1.1.tgz",
|
||||
"integrity": "sha512-IqEzQvjaRO6KL6wxHaBsVZhzym+Kuk3VWmgydIjzbJD0Zwwa1YpvSZ/2rYR5qmAx1aDM8dMAxpQ9Wm4xQoUv3g==",
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/date-and-time/-/date-and-time-4.1.2.tgz",
|
||||
"integrity": "sha512-ChrHKo2M1kAQFRZRsM+UYugnaj3d0X1+4vEUFy5u+sWVXY7TN14s+n8Xq4w20j98WTD304SwjaB5m5VQq/Mi2w==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
@@ -2273,9 +2299,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint": {
|
||||
"version": "9.39.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.1.tgz",
|
||||
"integrity": "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==",
|
||||
"version": "9.39.2",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.2.tgz",
|
||||
"integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
@@ -2286,7 +2312,7 @@
|
||||
"@eslint/config-helpers": "^0.4.2",
|
||||
"@eslint/core": "^0.17.0",
|
||||
"@eslint/eslintrc": "^3.3.1",
|
||||
"@eslint/js": "9.39.1",
|
||||
"@eslint/js": "9.39.2",
|
||||
"@eslint/plugin-kit": "^0.4.1",
|
||||
"@humanfs/node": "^0.16.6",
|
||||
"@humanwhocodes/module-importer": "^1.0.1",
|
||||
@@ -2354,9 +2380,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-react-refresh": {
|
||||
"version": "0.4.24",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.24.tgz",
|
||||
"integrity": "sha512-nLHIW7TEq3aLrEYWpVaJ1dRgFR+wLDPN8e8FpYAql/bMV2oBEfC37K0gLEGgv9fy66juNShSMV8OkTqzltcG/w==",
|
||||
"version": "0.4.26",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.26.tgz",
|
||||
"integrity": "sha512-1RETEylht2O6FM/MvgnyvT+8K21wLqDNg4qD51Zj3guhjt433XbnnkVttHMyaVyAFD03QSV4LPS5iE3VQmO7XQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
@@ -2619,13 +2645,6 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/graphemer": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz",
|
||||
"integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/has-flag": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
||||
@@ -3470,9 +3489,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/react": {
|
||||
"version": "19.2.0",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz",
|
||||
"integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==",
|
||||
"version": "19.2.3",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz",
|
||||
"integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
@@ -3480,16 +3499,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/react-dom": {
|
||||
"version": "19.2.0",
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz",
|
||||
"integrity": "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==",
|
||||
"version": "19.2.3",
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.3.tgz",
|
||||
"integrity": "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"scheduler": "^0.27.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^19.2.0"
|
||||
"react": "^19.2.3"
|
||||
}
|
||||
},
|
||||
"node_modules/react-favicon": {
|
||||
@@ -3508,9 +3527,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/react-is": {
|
||||
"version": "19.2.0",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.0.tgz",
|
||||
"integrity": "sha512-x3Ax3kNSMIIkyVYhWPyO09bu0uttcAIoecO/um/rKGQ4EltYWVYtyiGkS/3xMynrbVQdS69Jhlv8FXUEZehlzA==",
|
||||
"version": "19.2.3",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.3.tgz",
|
||||
"integrity": "sha512-qJNJfu81ByyabuG7hPFEbXqNcWSU3+eVus+KJs+0ncpGfMyYdvSmxiJxbWR65lYi1I+/0HBcliO029gc4F+PnA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/react-json-view-lite": {
|
||||
@@ -3536,9 +3555,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/react-router": {
|
||||
"version": "7.10.0",
|
||||
"resolved": "https://registry.npmjs.org/react-router/-/react-router-7.10.0.tgz",
|
||||
"integrity": "sha512-FVyCOH4IZ0eDDRycODfUqoN8ZSR2LbTvtx6RPsBgzvJ8xAXlMZNCrOFpu+jb8QbtZnpAd/cEki2pwE848pNGxw==",
|
||||
"version": "7.12.0",
|
||||
"resolved": "https://registry.npmjs.org/react-router/-/react-router-7.12.0.tgz",
|
||||
"integrity": "sha512-kTPDYPFzDVGIIGNLS5VJykK0HfHLY5MF3b+xj0/tTyNYL1gF1qs7u67Z9jEhQk2sQ98SUaHxlG31g1JtF7IfVw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cookie": "^1.0.1",
|
||||
@@ -3640,13 +3659,6 @@
|
||||
"@rolldown/binding-win32-x64-msvc": "1.0.0-beta.53"
|
||||
}
|
||||
},
|
||||
"node_modules/rolldown/node_modules/@rolldown/pluginutils": {
|
||||
"version": "1.0.0-beta.53",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.53.tgz",
|
||||
"integrity": "sha512-vENRlFU4YbrwVqNDZ7fLvy+JR1CRkyr01jhSiDpE1u6py3OMzQfztQU2jxykW3ALNxO4kSlqIDeYyD0Y9RcQeQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/scheduler": {
|
||||
"version": "0.27.0",
|
||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz",
|
||||
@@ -3773,9 +3785,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/ts-api-utils": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz",
|
||||
"integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==",
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.3.0.tgz",
|
||||
"integrity": "sha512-6eg3Y9SF7SsAvGzRHQvvc1skDAhwI4YQ32ui1scxD1Ccr0G5qIIbUBT3pFTKX8kmWIQClHobtUdNuaBgwdfdWg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -3822,16 +3834,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/typescript-eslint": {
|
||||
"version": "8.48.1",
|
||||
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.48.1.tgz",
|
||||
"integrity": "sha512-FbOKN1fqNoXp1hIl5KYpObVrp0mCn+CLgn479nmu2IsRMrx2vyv74MmsBLVlhg8qVwNFGbXSp8fh1zp8pEoC2A==",
|
||||
"version": "8.51.0",
|
||||
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.51.0.tgz",
|
||||
"integrity": "sha512-jh8ZuM5oEh2PSdyQG9YAEM1TCGuWenLSuSUhf/irbVUNW9O5FhbFVONviN2TgMTBnUmyHv7E56rYnfLZK6TkiA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/eslint-plugin": "8.48.1",
|
||||
"@typescript-eslint/parser": "8.48.1",
|
||||
"@typescript-eslint/typescript-estree": "8.48.1",
|
||||
"@typescript-eslint/utils": "8.48.1"
|
||||
"@typescript-eslint/eslint-plugin": "8.51.0",
|
||||
"@typescript-eslint/parser": "8.51.0",
|
||||
"@typescript-eslint/typescript-estree": "8.51.0",
|
||||
"@typescript-eslint/utils": "8.51.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
@@ -3904,9 +3916,9 @@
|
||||
},
|
||||
"node_modules/vite": {
|
||||
"name": "rolldown-vite",
|
||||
"version": "7.2.10",
|
||||
"resolved": "https://registry.npmjs.org/rolldown-vite/-/rolldown-vite-7.2.10.tgz",
|
||||
"integrity": "sha512-v2ekZjuVLfumjp1Cr7LSQM1n2oOo3+gMruhOgT0Q4/cQ2J3nkTDLTAWLQQ86UHMbFYyVIN1wGh8BEZbvjkyctg==",
|
||||
"version": "7.3.1",
|
||||
"resolved": "https://registry.npmjs.org/rolldown-vite/-/rolldown-vite-7.3.1.tgz",
|
||||
"integrity": "sha512-LYzdNAjRHhF2yA4JUQm/QyARyi216N2rpJ0lJZb8E9FU2y5v6Vk+xq/U4XBOxMefpWixT5H3TslmAHm1rqIq2w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
@@ -3933,7 +3945,7 @@
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/node": "^20.19.0 || >=22.12.0",
|
||||
"esbuild": "^0.25.0",
|
||||
"esbuild": "^0.27.0",
|
||||
"jiti": ">=1.21.0",
|
||||
"less": "^4.0.0",
|
||||
"sass": "^1.70.0",
|
||||
|
||||
@@ -13,38 +13,36 @@
|
||||
"@emotion/react": "^11.14.0",
|
||||
"@emotion/styled": "^11.14.1",
|
||||
"@fontsource/roboto": "^5.2.9",
|
||||
"@mdi/js": "^7.4.47",
|
||||
"@mdi/react": "^1.6.1",
|
||||
"@mui/icons-material": "^7.3.6",
|
||||
"@mui/material": "^7.3.6",
|
||||
"@mui/x-data-grid": "^8.20.0",
|
||||
"@mui/x-date-pickers": "^8.19.0",
|
||||
"date-and-time": "^4.1.1",
|
||||
"@mui/icons-material": "^7.3.7",
|
||||
"@mui/material": "^7.3.7",
|
||||
"@mui/x-data-grid": "^8.24.0",
|
||||
"@mui/x-date-pickers": "^8.23.0",
|
||||
"date-and-time": "^4.1.2",
|
||||
"dayjs": "^1.11.19",
|
||||
"emoji-picker-react": "^4.16.1",
|
||||
"is-cidr": "^6.0.1",
|
||||
"qrcode.react": "^4.2.0",
|
||||
"react": "^19.1.1",
|
||||
"react-dom": "^19.1.1",
|
||||
"react": "^19.2.3",
|
||||
"react-dom": "^19.2.3",
|
||||
"react-favicon": "^2.0.7",
|
||||
"react-json-view-lite": "^2.5.0",
|
||||
"react-router": "^7.10.0"
|
||||
"react-router": "^7.12.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.39.1",
|
||||
"@types/node": "^24.10.1",
|
||||
"@types/react": "^19.2.7",
|
||||
"@eslint/js": "^9.39.2",
|
||||
"@types/node": "^24.10.9",
|
||||
"@types/react": "^19.2.8",
|
||||
"@types/react-dom": "^19.2.3",
|
||||
"@vitejs/plugin-react": "^5.1.1",
|
||||
"eslint": "^9.39.1",
|
||||
"@vitejs/plugin-react": "^5.1.2",
|
||||
"eslint": "^9.39.2",
|
||||
"eslint-plugin-react-hooks": "^7.0.1",
|
||||
"eslint-plugin-react-refresh": "^0.4.22",
|
||||
"eslint-plugin-react-refresh": "^0.4.26",
|
||||
"globals": "^16.5.0",
|
||||
"typescript": "~5.9.3",
|
||||
"typescript-eslint": "^8.48.1",
|
||||
"vite": "npm:rolldown-vite@7.2.10"
|
||||
"typescript-eslint": "^8.51.0",
|
||||
"vite": "npm:rolldown-vite@7.3.1"
|
||||
},
|
||||
"overrides": {
|
||||
"vite": "npm:rolldown-vite@7.2.10"
|
||||
"vite": "npm:rolldown-vite@7.3.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,9 @@ export interface RoomMessageEvent extends BaseRoomEvent {
|
||||
"m.relates_to"?: {
|
||||
rel_type?: "m.replace" | string;
|
||||
event_id?: string;
|
||||
"m.in_reply_to"?:{
|
||||
event_id?:string
|
||||
}
|
||||
};
|
||||
"m.new_content"?: {
|
||||
msgtype?: MessageType;
|
||||
|
||||
@@ -15,8 +15,11 @@ export interface MatrixRoomMessage {
|
||||
body: string;
|
||||
msgtype: MessageType;
|
||||
"m.relates_to"?: {
|
||||
event_id: string;
|
||||
rel_type: "m.replace" | string;
|
||||
event_id?: string;
|
||||
rel_type?: "m.replace" | string;
|
||||
"m.in_reply_to"?: {
|
||||
event_id?: string;
|
||||
};
|
||||
};
|
||||
url?: string;
|
||||
file?: {
|
||||
@@ -71,8 +74,8 @@ export class MatrixApiEvent {
|
||||
await APIClient.exec({
|
||||
method: "GET",
|
||||
uri:
|
||||
`/matrix/room/${encodeURIComponent(room.id)}/events` +
|
||||
(from ? `?from=${from}` : ""),
|
||||
`/matrix/room/${encodeURIComponent(room.id)}/events?limit=200` +
|
||||
(from ? `&from=${from}` : ""),
|
||||
})
|
||||
).data as MatrixEventsList;
|
||||
}
|
||||
|
||||
40
matrixgw_frontend/src/api/matrix/MatrixApiSpace.ts
Normal file
40
matrixgw_frontend/src/api/matrix/MatrixApiSpace.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import { APIClient } from "../ApiClient";
|
||||
|
||||
export type SpaceHierarchy = Map<string, string[]>;
|
||||
|
||||
export class MatrixApiSpace {
|
||||
/**
|
||||
* Request Matrix space hierarchy
|
||||
*/
|
||||
static async Hierarchy(): Promise<SpaceHierarchy> {
|
||||
const hierarchy = new Map(
|
||||
Object.entries(
|
||||
(
|
||||
await APIClient.exec({
|
||||
method: "GET",
|
||||
uri: "/matrix/space/hierarchy",
|
||||
})
|
||||
).data as { [s: string]: string[] }
|
||||
)
|
||||
) as SpaceHierarchy;
|
||||
|
||||
// Simplify hierarchy
|
||||
while (true) {
|
||||
let changed = false;
|
||||
for (const [roomid, children] of hierarchy) {
|
||||
for (const child of children) {
|
||||
if (!hierarchy.has(child)) continue;
|
||||
hierarchy.set(roomid, [
|
||||
...hierarchy.get(roomid)!,
|
||||
...hierarchy.get(child)!,
|
||||
]);
|
||||
hierarchy.delete(child);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
if (!changed) break;
|
||||
}
|
||||
|
||||
return hierarchy;
|
||||
}
|
||||
}
|
||||
18
matrixgw_frontend/src/icons/AppIcon.tsx
Normal file
18
matrixgw_frontend/src/icons/AppIcon.tsx
Normal file
@@ -0,0 +1,18 @@
|
||||
import { Icon } from "@mui/material";
|
||||
import { useActualColorMode } from "../widgets/dashboard/ThemeSwitcher";
|
||||
|
||||
export function AppIcon(p: { src: string; size?: string }): React.ReactElement {
|
||||
const { mode } = useActualColorMode();
|
||||
return (
|
||||
<Icon style={{ display: "inline-flex", width: p.size, height: p.size }}>
|
||||
<img
|
||||
style={{
|
||||
height: "100%",
|
||||
flex: 1,
|
||||
backgroundColor: mode === "dark" ? "white" : "black",
|
||||
mask: `url("${p.src}")`,
|
||||
}}
|
||||
/>
|
||||
</Icon>
|
||||
);
|
||||
}
|
||||
1
matrixgw_frontend/src/icons/message-text-fast.svg
Normal file
1
matrixgw_frontend/src/icons/message-text-fast.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9 5C7.9 5 7 5.9 7 7V21L11 17H20C21.1 17 22 16.1 22 15V7C22 5.9 21.1 5 20 5H9M3 7C2.4 7 2 7.4 2 8S2.4 9 3 9H5V7H3M11 8H19V10H11V8M2 11C1.4 11 1 11.4 1 12S1.4 13 2 13H5V11H2M11 12H16V14H11V12M1 15C.4 15 0 15.4 0 16C0 16.6 .4 17 1 17H5V15H1Z" /></svg>
|
||||
|
After Width: | Height: | Size: 318 B |
1
matrixgw_frontend/src/icons/openid.svg
Normal file
1
matrixgw_frontend/src/icons/openid.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M14,2L11,3.5V19.94C7,19.5 4,17.46 4,15C4,12.75 6.5,10.85 10,10.22V8.19C4.86,8.88 1,11.66 1,15C1,18.56 5.36,21.5 11,21.94C11.03,21.94 11.06,21.94 11.09,21.94L14,20.5V2M15,8.19V10.22C16.15,10.43 17.18,10.77 18.06,11.22L16.5,12L23,13.5L22.5,9L20.5,10C19,9.12 17.12,8.47 15,8.19Z" /></svg>
|
||||
|
After Width: | Height: | Size: 354 B |
@@ -41,7 +41,8 @@ export function MatrixAuthCallback(): React.ReactElement {
|
||||
};
|
||||
|
||||
load();
|
||||
}, [code, info, navigate, snackbar, state]);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [code, state]);
|
||||
|
||||
if (error)
|
||||
return (
|
||||
|
||||
@@ -23,13 +23,21 @@ export function WSDebugRoute(): React.ReactElement {
|
||||
|
||||
return (
|
||||
<MatrixGWRouteContainer label={"WebSocket Debug"}>
|
||||
<div>
|
||||
State:{" "}
|
||||
<span style={{ color: state == WSState.Connected ? "green" : "red" }}>
|
||||
{/* Status bar */}
|
||||
<div style={{ display: "flex", alignItems: "center" }}>
|
||||
<span style={{ marginRight: "0.5em" }}>State: </span>
|
||||
<span
|
||||
style={{
|
||||
marginRight: "0.5em",
|
||||
color: state == WSState.Connected ? "green" : "red",
|
||||
}}
|
||||
>
|
||||
{state}
|
||||
</span>
|
||||
<MatrixWS onStateChange={setState} onMessage={handleMessage} />
|
||||
</div>
|
||||
|
||||
{/* WS messages list */}
|
||||
{messages.map((msg, id) => (
|
||||
<div style={{ margin: "10px", backgroundColor: "black" }}>
|
||||
<JsonView
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { Alert, Box, Button, CircularProgress } from "@mui/material";
|
||||
import Icon from "@mdi/react";
|
||||
import { mdiOpenid } from "@mdi/js";
|
||||
import { ServerApi } from "../../api/ServerApi";
|
||||
import React from "react";
|
||||
import { AuthApi } from "../../api/AuthApi";
|
||||
import { ServerApi } from "../../api/ServerApi";
|
||||
import { AppIcon } from "../../icons/AppIcon";
|
||||
import openid from "../../icons/openid.svg";
|
||||
|
||||
export function LoginRoute(): React.ReactElement {
|
||||
const [loading, setLoading] = React.useState(false);
|
||||
@@ -40,7 +40,7 @@ export function LoginRoute(): React.ReactElement {
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
onClick={authWithOpenID}
|
||||
startIcon={<Icon path={mdiOpenid} size={1} />}
|
||||
startIcon={<AppIcon src={openid} />}
|
||||
>
|
||||
Sign in with {ServerApi.Config.oidc_provider_name}
|
||||
</Button>
|
||||
|
||||
@@ -21,6 +21,7 @@ export interface Message {
|
||||
time_sent: number;
|
||||
time_sent_dayjs: dayjs.Dayjs;
|
||||
modified: boolean;
|
||||
inReplyTo?: string;
|
||||
reactions: Map<string, MessageReaction[]>;
|
||||
content: string;
|
||||
type: MessageType;
|
||||
@@ -37,7 +38,7 @@ export class RoomEventsManager {
|
||||
receiptsEventsMap: Map<string, Receipt[]>;
|
||||
|
||||
get canLoadOlder(): boolean {
|
||||
return !!this.endToken;
|
||||
return !!this.endToken && this.events.length > 0;
|
||||
}
|
||||
|
||||
constructor(
|
||||
@@ -92,13 +93,7 @@ export class RoomEventsManager {
|
||||
content: {
|
||||
body: m.data["m.new_content"]?.body ?? m.data.body,
|
||||
msgtype: m.data.msgtype,
|
||||
"m.relates_to":
|
||||
m.data["m.relates_to"] && m.data["m.relates_to"].event_id
|
||||
? {
|
||||
event_id: m.data["m.relates_to"].event_id!,
|
||||
rel_type: m.data["m.relates_to"].rel_type ?? "",
|
||||
}
|
||||
: undefined,
|
||||
"m.relates_to": m.data["m.relates_to"],
|
||||
url: m.data.url,
|
||||
file: m.data.file,
|
||||
},
|
||||
@@ -174,7 +169,7 @@ export class RoomEventsManager {
|
||||
// Message
|
||||
if (data.type === "m.room.message") {
|
||||
// Check if this message replaces another one
|
||||
if (data.content["m.relates_to"]) {
|
||||
if (data.content["m.relates_to"]?.rel_type === "replace") {
|
||||
const message = this.messages.find(
|
||||
(m) => m.event_id === data.content["m.relates_to"]?.event_id
|
||||
);
|
||||
@@ -206,6 +201,7 @@ export class RoomEventsManager {
|
||||
event_id: evt.id,
|
||||
account: evt.sender,
|
||||
modified: false,
|
||||
inReplyTo: data.content["m.relates_to"]?.["m.in_reply_to"]?.event_id,
|
||||
reactions: new Map(),
|
||||
time_sent: evt.time,
|
||||
time_sent_dayjs: dayjs.unix(evt.time / 1000),
|
||||
|
||||
@@ -16,9 +16,16 @@ function emojiUnicode(emoji: string): string {
|
||||
return s.includes("f") ? s : `${s}-fe0f`;
|
||||
}
|
||||
|
||||
export function EmojiIcon(p: { emojiKey: string }): React.ReactElement {
|
||||
export function EmojiIcon(p: {
|
||||
emojiKey: string;
|
||||
size?: number;
|
||||
}): React.ReactElement {
|
||||
const unified = emojiUnicode(p.emojiKey);
|
||||
return (
|
||||
<Emoji unified={unified ?? ""} emojiStyle={EmojiStyle.NATIVE} size={18} />
|
||||
<Emoji
|
||||
unified={unified ?? ""}
|
||||
emojiStyle={EmojiStyle.NATIVE}
|
||||
size={p.size ?? 18}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { mdiMessageTextFast } from "@mdi/js";
|
||||
import Icon from "@mdi/react";
|
||||
import { Typography } from "@mui/material";
|
||||
import MuiCard from "@mui/material/Card";
|
||||
import Stack from "@mui/material/Stack";
|
||||
import { styled } from "@mui/material/styles";
|
||||
import { Outlet } from "react-router";
|
||||
import { AppIcon } from "../../icons/AppIcon";
|
||||
import mdiMessageTextFast from "../../icons/message-text-fast.svg";
|
||||
|
||||
const Card = styled(MuiCard)(({ theme }) => ({
|
||||
display: "flex",
|
||||
@@ -57,12 +57,7 @@ export function BaseLoginPage(): React.ReactElement {
|
||||
variant="h4"
|
||||
sx={{ width: "100%", fontSize: "clamp(2rem, 10vw, 2.15rem)" }}
|
||||
>
|
||||
<Icon
|
||||
path={mdiMessageTextFast}
|
||||
size={"1em"}
|
||||
style={{ display: "inline-table" }}
|
||||
/>{" "}
|
||||
MatrixGW
|
||||
<AppIcon src={mdiMessageTextFast} size={"2em"} /> MatrixGW
|
||||
</Typography>
|
||||
<Outlet />
|
||||
</Card>
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import { mdiMessageTextFast } from "@mdi/js";
|
||||
import Icon from "@mdi/react";
|
||||
import LogoutIcon from "@mui/icons-material/Logout";
|
||||
import MenuIcon from "@mui/icons-material/Menu";
|
||||
import MenuOpenIcon from "@mui/icons-material/MenuOpen";
|
||||
@@ -13,6 +11,8 @@ import Toolbar from "@mui/material/Toolbar";
|
||||
import Tooltip from "@mui/material/Tooltip";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import * as React from "react";
|
||||
import { AppIcon } from "../../icons/AppIcon";
|
||||
import mdiMessageTextFast from "../../icons/message-text-fast.svg";
|
||||
import { RouterLink } from "../RouterLink";
|
||||
import { useUserInfo } from "./BaseAuthenticatedPage";
|
||||
import ThemeSwitcher from "./ThemeSwitcher";
|
||||
@@ -101,7 +101,7 @@ export default function DashboardHeader({
|
||||
<RouterLink to="/">
|
||||
<Stack direction="row" alignItems="center">
|
||||
<LogoContainer>
|
||||
<Icon path={mdiMessageTextFast} size="2em" />
|
||||
<AppIcon src={mdiMessageTextFast} size="2em" />
|
||||
</LogoContainer>
|
||||
<Typography
|
||||
variant="h6"
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { mdiBug, mdiForum, mdiKeyVariant, mdiLinkLock } from "@mdi/js";
|
||||
import Icon from "@mdi/react";
|
||||
import BugReportIcon from "@mui/icons-material/BugReport";
|
||||
import ForumIcon from "@mui/icons-material/Forum";
|
||||
import KeyIcon from "@mui/icons-material/Key";
|
||||
import LinkIcon from "@mui/icons-material/Link";
|
||||
import Box from "@mui/material/Box";
|
||||
import Drawer from "@mui/material/Drawer";
|
||||
import List from "@mui/material/List";
|
||||
@@ -98,27 +100,27 @@ export default function DashboardSidebar({
|
||||
<DashboardSidebarPageItem
|
||||
disabled={!user.info.matrix_account_connected}
|
||||
title="Messages"
|
||||
icon={<Icon path={mdiForum} size={"1.5em"} />}
|
||||
icon={<ForumIcon style={{ height: "1em", width: "1em" }} />}
|
||||
href="/"
|
||||
mini={viewport === "desktop"}
|
||||
/>
|
||||
<DashboardSidebarDividerItem />
|
||||
<DashboardSidebarPageItem
|
||||
title="Matrix link"
|
||||
icon={<Icon path={mdiLinkLock} size={"1.5em"} />}
|
||||
icon={<LinkIcon style={{ height: "1em", width: "1em" }} />}
|
||||
href="/matrix_link"
|
||||
mini={viewport === "desktop"}
|
||||
/>
|
||||
<DashboardSidebarPageItem
|
||||
title="API tokens"
|
||||
icon={<Icon path={mdiKeyVariant} size={"1.5em"} />}
|
||||
icon={<KeyIcon style={{ height: "1em", width: "1em" }} />}
|
||||
href="/tokens"
|
||||
mini={viewport === "desktop"}
|
||||
/>
|
||||
<DashboardSidebarPageItem
|
||||
disabled={!user.info.matrix_account_connected}
|
||||
title="WS Debug"
|
||||
icon={<Icon path={mdiBug} size={"1.5em"} />}
|
||||
icon={<BugReportIcon style={{ height: "1em", width: "1em" }} />}
|
||||
href="/wsdebug"
|
||||
mini={viewport === "desktop"}
|
||||
/>
|
||||
|
||||
@@ -7,9 +7,10 @@ import DarkModeIcon from "@mui/icons-material/DarkMode";
|
||||
import LightModeIcon from "@mui/icons-material/LightMode";
|
||||
import type {} from "@mui/material/themeCssVarsAugmentation";
|
||||
|
||||
export default function ThemeSwitcher() {
|
||||
const theme = useTheme();
|
||||
|
||||
export function useActualColorMode(): {
|
||||
mode: "light" | "dark";
|
||||
setMode: (mode: "light" | "dark") => void;
|
||||
} {
|
||||
const prefersDarkMode = useMediaQuery("(prefers-color-scheme: dark)");
|
||||
const preferredMode = prefersDarkMode ? "dark" : "light";
|
||||
|
||||
@@ -17,21 +18,27 @@ export default function ThemeSwitcher() {
|
||||
|
||||
const paletteMode = !mode || mode === "system" ? preferredMode : mode;
|
||||
|
||||
return { mode: paletteMode, setMode };
|
||||
}
|
||||
|
||||
export default function ThemeSwitcher() {
|
||||
const theme = useTheme();
|
||||
|
||||
const { mode, setMode } = useActualColorMode();
|
||||
|
||||
const toggleMode = React.useCallback(() => {
|
||||
setMode(paletteMode === "dark" ? "light" : "dark");
|
||||
}, [setMode, paletteMode]);
|
||||
setMode(mode === "dark" ? "light" : "dark");
|
||||
}, [mode, setMode]);
|
||||
|
||||
return (
|
||||
<Tooltip
|
||||
title={`${paletteMode === "dark" ? "Light" : "Dark"} mode`}
|
||||
title={`${mode === "dark" ? "Light" : "Dark"} mode`}
|
||||
enterDelay={1000}
|
||||
>
|
||||
<div>
|
||||
<IconButton
|
||||
size="small"
|
||||
aria-label={`Switch to ${
|
||||
paletteMode === "dark" ? "light" : "dark"
|
||||
} mode`}
|
||||
aria-label={`Switch to ${mode === "dark" ? "light" : "dark"} mode`}
|
||||
onClick={toggleMode}
|
||||
>
|
||||
<LightModeIcon
|
||||
|
||||
@@ -6,6 +6,10 @@ import {
|
||||
type UsersMap,
|
||||
} from "../../api/matrix/MatrixApiProfile";
|
||||
import { MatrixApiRoom, type Room } from "../../api/matrix/MatrixApiRoom";
|
||||
import {
|
||||
MatrixApiSpace,
|
||||
type SpaceHierarchy,
|
||||
} from "../../api/matrix/MatrixApiSpace";
|
||||
import { MatrixSyncApi } from "../../api/MatrixSyncApi";
|
||||
import type { WsMessage } from "../../api/WsApi";
|
||||
import { RoomEventsManager } from "../../utils/RoomEventsManager";
|
||||
@@ -19,13 +23,19 @@ import { SpaceSelector } from "./SpaceSelector";
|
||||
|
||||
export function MainMessageWidget(): React.ReactElement {
|
||||
const [rooms, setRooms] = React.useState<Room[] | undefined>();
|
||||
const [hierarchy, setHierarchy] = React.useState<
|
||||
SpaceHierarchy | undefined
|
||||
>();
|
||||
const [users, setUsers] = React.useState<UsersMap | undefined>();
|
||||
|
||||
const loadRoomsList = async () => {
|
||||
await MatrixSyncApi.Start();
|
||||
|
||||
const rooms = await MatrixApiRoom.ListJoined();
|
||||
const hierarchy = await MatrixApiSpace.Hierarchy();
|
||||
|
||||
setRooms(rooms);
|
||||
setHierarchy(hierarchy);
|
||||
|
||||
// Get the list of users in rooms
|
||||
const users = rooms.reduce((prev, r) => {
|
||||
@@ -40,11 +50,12 @@ export function MainMessageWidget(): React.ReactElement {
|
||||
<AsyncWidget
|
||||
loadKey={1}
|
||||
load={loadRoomsList}
|
||||
ready={!!rooms && !!users}
|
||||
ready={!!rooms && !!users && !!hierarchy}
|
||||
errMsg="Failed to initialize messaging component!"
|
||||
build={() => (
|
||||
<MainMessageWidgetInner
|
||||
rooms={rooms!}
|
||||
hierarchy={hierarchy!}
|
||||
users={users!}
|
||||
onRoomsListUpdate={(cb) => setRooms((r) => cb(r!))}
|
||||
/>
|
||||
@@ -55,6 +66,7 @@ export function MainMessageWidget(): React.ReactElement {
|
||||
|
||||
function MainMessageWidgetInner(p: {
|
||||
rooms: Room[];
|
||||
hierarchy: SpaceHierarchy;
|
||||
users: UsersMap;
|
||||
onRoomsListUpdate: (cb: (a: Room[]) => Room[]) => void;
|
||||
}): React.ReactElement {
|
||||
@@ -65,11 +77,13 @@ function MainMessageWidgetInner(p: {
|
||||
|
||||
const spaceRooms = React.useMemo(() => {
|
||||
return p.rooms
|
||||
.filter((r) => !r.is_space && (!space || r.parents.includes(space)))
|
||||
.filter(
|
||||
(r) => !r.is_space && (!space || p.hierarchy.get(space)?.includes(r.id))
|
||||
)
|
||||
.sort(
|
||||
(a, b) => (b.latest_event?.time ?? 0) - (a.latest_event?.time ?? 0)
|
||||
);
|
||||
}, [space, p.rooms]);
|
||||
}, [space, p.rooms, p.hierarchy]);
|
||||
|
||||
const unreadRooms = React.useMemo(
|
||||
() =>
|
||||
@@ -111,7 +125,7 @@ function MainMessageWidgetInner(p: {
|
||||
p.onRoomsListUpdate((r) => {
|
||||
const n = [...r];
|
||||
const idx = r.findIndex((el) => el.id === m.room_id);
|
||||
if (idx && n[idx].notifications === "AllMessages")
|
||||
if (idx && n[idx]?.notifications === "AllMessages")
|
||||
n[idx] = {
|
||||
...n[idx],
|
||||
number_unread_messages: n[idx].number_unread_messages + 1,
|
||||
|
||||
@@ -55,16 +55,8 @@ export function RoomMessagesList(p: {
|
||||
messagesEndRef.current?.scrollIntoView({ behavior: "instant" });
|
||||
}, [lastEventId, messagesEndRef]);
|
||||
|
||||
// Watch scroll to detect when user reach the top to load older messages
|
||||
const handleScroll = async () => {
|
||||
if (!listContainerRef.current || loadingOlder || !p.manager.canLoadOlder)
|
||||
return;
|
||||
|
||||
const { scrollTop } = listContainerRef.current;
|
||||
|
||||
if (scrollTop !== 0) {
|
||||
return;
|
||||
}
|
||||
const loadOlderMessages = async () => {
|
||||
if (loadingOlder || !p.manager.canLoadOlder) return;
|
||||
|
||||
setLoadingOlder(true);
|
||||
|
||||
@@ -82,6 +74,19 @@ export function RoomMessagesList(p: {
|
||||
}
|
||||
};
|
||||
|
||||
// Watch scroll to detect when user reach the top to load older messages
|
||||
const handleScroll = async () => {
|
||||
if (!listContainerRef.current) return;
|
||||
|
||||
const { scrollTop } = listContainerRef.current;
|
||||
|
||||
if (scrollTop !== 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
loadOlderMessages();
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
onScroll={handleScroll}
|
||||
@@ -94,22 +99,8 @@ export function RoomMessagesList(p: {
|
||||
paddingLeft: "20px",
|
||||
}}
|
||||
>
|
||||
{/* Empty conversation notice */}
|
||||
{p.manager.messages.length === 0 && (
|
||||
<div
|
||||
style={{
|
||||
height: "100%",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
No message in this conversation yet!
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/** Begining of conversation */}
|
||||
{!p.manager.canLoadOlder && (
|
||||
{!p.manager.canLoadOlder && p.manager.messages.length > 0 && (
|
||||
<Typography
|
||||
component={"div"}
|
||||
variant="caption"
|
||||
@@ -119,6 +110,22 @@ export function RoomMessagesList(p: {
|
||||
</Typography>
|
||||
)}
|
||||
|
||||
{/** Load older messages button */}
|
||||
{p.manager.canLoadOlder && !loadingOlder && (
|
||||
<div
|
||||
style={{
|
||||
display: "inline-flex",
|
||||
justifyContent: "center",
|
||||
width: "100%",
|
||||
padding: "20px",
|
||||
}}
|
||||
>
|
||||
<Button onClick={loadOlderMessages} variant="outlined">
|
||||
Load older messages
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/** Loading older messages spinner */}
|
||||
{loadingOlder && (
|
||||
<div
|
||||
@@ -133,6 +140,21 @@ export function RoomMessagesList(p: {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Empty conversation notice */}
|
||||
{p.manager.messages.length === 0 && (
|
||||
<div
|
||||
style={{
|
||||
height: "100%",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
No message in this conversation yet!
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/** Messages themselves */}
|
||||
{p.manager.messages.map((m, idx) => (
|
||||
<RoomMessage
|
||||
key={m.event_id}
|
||||
@@ -149,6 +171,11 @@ export function RoomMessagesList(p: {
|
||||
p.manager.messages[idx - 1].time_sent_dayjs.startOf("day").unix()
|
||||
}
|
||||
receipts={p.manager.receiptsEventsMap.get(m.event_id)}
|
||||
repliedMessage={
|
||||
(m.inReplyTo &&
|
||||
p.manager.messages.find((s) => s.event_id === m.inReplyTo)) ||
|
||||
undefined
|
||||
}
|
||||
/>
|
||||
))}
|
||||
|
||||
@@ -164,6 +191,7 @@ function RoomMessage(p: {
|
||||
previousFromSamePerson: boolean;
|
||||
firstMessageOfDay: boolean;
|
||||
receipts?: Receipt[];
|
||||
repliedMessage?: Message;
|
||||
}): React.ReactElement {
|
||||
const theme = useTheme();
|
||||
const user = useUserInfo();
|
||||
@@ -180,6 +208,8 @@ function RoomMessage(p: {
|
||||
const closeImageFullScreen = () => setShowImageFullScreen(false);
|
||||
|
||||
const sender = p.users.get(p.message.account);
|
||||
const repliedMsgSender =
|
||||
p.repliedMessage && p.users.get(p.repliedMessage.account);
|
||||
|
||||
const handleDeleteMessage = async () => {
|
||||
if (!(await confirm(`Do you really want to delete this message?`))) return;
|
||||
@@ -292,12 +322,37 @@ function RoomMessage(p: {
|
||||
"&:hover *": { visibility: "visible" },
|
||||
}}
|
||||
>
|
||||
<Typography variant="caption">
|
||||
{p.message.time_sent_dayjs.format("HH:mm")}
|
||||
<Typography
|
||||
variant="caption"
|
||||
style={{
|
||||
paddingLeft: "2px",
|
||||
display: "inline-flex",
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
{p.message.time_sent_dayjs.format("HH:mm")}
|
||||
</Typography>
|
||||
|
||||
{/** Message itself */}
|
||||
<div style={{ marginLeft: "15px", whiteSpace: "pre-wrap", flex: 1 }}>
|
||||
{/** In case of reply */}
|
||||
{p.repliedMessage && repliedMsgSender && (
|
||||
<div
|
||||
style={{
|
||||
display: "inline-flex",
|
||||
alignItems: "center",
|
||||
borderLeft: "1px red solid",
|
||||
paddingLeft: "10px",
|
||||
overflow: "hidden",
|
||||
}}
|
||||
>
|
||||
<AccountIcon user={repliedMsgSender} size={16} />
|
||||
<div style={{ marginLeft: "10px" }}>
|
||||
{p.repliedMessage?.content}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Image */}
|
||||
{p.message.type === "m.image" && (
|
||||
<img
|
||||
@@ -465,11 +520,9 @@ function RoomMessage(p: {
|
||||
}}
|
||||
>
|
||||
<div style={{ margin: "0px 3px" }}>
|
||||
<EmojiIcon emojiKey={r} />
|
||||
</div>
|
||||
<div style={{ height: "2em", marginLeft: "2px" }}>
|
||||
{reactions.length}
|
||||
<EmojiIcon emojiKey={r} size={16} />
|
||||
</div>
|
||||
<div style={{ marginLeft: "2px" }}>{reactions.length}</div>
|
||||
</span>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import SearchIcon from "@mui/icons-material/Search";
|
||||
import {
|
||||
Chip,
|
||||
List,
|
||||
@@ -5,6 +6,7 @@ import {
|
||||
ListItemButton,
|
||||
ListItemIcon,
|
||||
ListItemText,
|
||||
TextField,
|
||||
} from "@mui/material";
|
||||
import React from "react";
|
||||
import type { UsersMap } from "../../api/matrix/MatrixApiProfile";
|
||||
@@ -22,11 +24,19 @@ export function RoomSelector(p: {
|
||||
}): React.ReactElement {
|
||||
const user = useUserInfo();
|
||||
|
||||
const [filter, setFilter] = React.useState("");
|
||||
const [unread, setUnread] = React.useState(false);
|
||||
|
||||
const shownRooms = React.useMemo(
|
||||
() => p.rooms.filter((r) => !unread || r.number_unread_messages > 0),
|
||||
[p.rooms, unread]
|
||||
() =>
|
||||
p.rooms
|
||||
.filter((r) => !unread || r.number_unread_messages > 0)
|
||||
.filter(
|
||||
(r) =>
|
||||
filter === "" ||
|
||||
r.name?.toLocaleLowerCase()?.includes(filter.toLocaleLowerCase())
|
||||
),
|
||||
[p.rooms, unread, filter]
|
||||
);
|
||||
|
||||
if (p.rooms.length === 0)
|
||||
@@ -45,6 +55,19 @@ export function RoomSelector(p: {
|
||||
|
||||
return (
|
||||
<div style={{ display: "flex", flexDirection: "column" }}>
|
||||
{/** Filter bar */}
|
||||
<TextField
|
||||
placeholder="Filter rooms"
|
||||
slotProps={{
|
||||
input: {
|
||||
startAdornment: <SearchIcon style={{ marginRight: "10px" }} />,
|
||||
},
|
||||
}}
|
||||
style={{ margin: "5px" }}
|
||||
value={filter}
|
||||
onChange={(e) => setFilter(e.target.value)}
|
||||
/>
|
||||
|
||||
{/** Chip bar */}
|
||||
<div style={{ padding: "5px 10px", marginTop: "5px" }}>
|
||||
<span onClick={() => setUnread(!unread)} style={{ cursor: "pointer" }}>
|
||||
|
||||
@@ -3,17 +3,19 @@ import { Button } from "@mui/material";
|
||||
import React from "react";
|
||||
import type { UsersMap } from "../../api/matrix/MatrixApiProfile";
|
||||
import type { Room } from "../../api/matrix/MatrixApiRoom";
|
||||
import type { SpaceHierarchy } from "../../api/matrix/MatrixApiSpace";
|
||||
import { RoomIcon } from "./RoomIcon";
|
||||
|
||||
export function SpaceSelector(p: {
|
||||
rooms: Room[];
|
||||
hierarchy: SpaceHierarchy;
|
||||
users: UsersMap;
|
||||
selectedSpace?: string;
|
||||
onChange: (space?: string) => void;
|
||||
}): React.ReactElement {
|
||||
const spaces = React.useMemo(
|
||||
() => p.rooms.filter((r) => r.is_space),
|
||||
[p.rooms]
|
||||
() => p.rooms.filter((r) => r.is_space && p.hierarchy.has(r.id)),
|
||||
[p.rooms, p.hierarchy]
|
||||
);
|
||||
|
||||
// Do not display space bar if your is not member of any space
|
||||
|
||||
Reference in New Issue
Block a user