Compare commits
6 Commits
29939d598f
...
renovate/e
| Author | SHA1 | Date | |
|---|---|---|---|
| 874410770c | |||
| e88961a43a | |||
| f6169d690f | |||
| 5221260e26 | |||
| c562152019 | |||
| 2ea20e6de4 |
94
matrixgw_backend/Cargo.lock
generated
94
matrixgw_backend/Cargo.lock
generated
@@ -95,6 +95,44 @@ dependencies = [
|
|||||||
"syn 2.0.116",
|
"syn 2.0.116",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "actix-multipart"
|
||||||
|
version = "0.7.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d5118a26dee7e34e894f7e85aa0ee5080ae4c18bf03c0e30d49a80e418f00a53"
|
||||||
|
dependencies = [
|
||||||
|
"actix-multipart-derive",
|
||||||
|
"actix-utils",
|
||||||
|
"actix-web",
|
||||||
|
"derive_more 0.99.20",
|
||||||
|
"futures-core",
|
||||||
|
"futures-util",
|
||||||
|
"httparse",
|
||||||
|
"local-waker",
|
||||||
|
"log",
|
||||||
|
"memchr",
|
||||||
|
"mime",
|
||||||
|
"rand 0.8.5",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"serde_plain",
|
||||||
|
"tempfile",
|
||||||
|
"tokio",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "actix-multipart-derive"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e11eb847f49a700678ea2fa73daeb3208061afa2b9d1a8527c03390f4c4a1c6b"
|
||||||
|
dependencies = [
|
||||||
|
"darling",
|
||||||
|
"parse-size",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.116",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "actix-remote-ip"
|
name = "actix-remote-ip"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@@ -243,16 +281,18 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "actix-ws"
|
name = "actix-ws"
|
||||||
version = "0.3.1"
|
version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "12d4f2fbee3ef7a22fa6cb0e416b962237a167ed0419f22d4e451da2d7f082f8"
|
checksum = "decf53c3cdd63dd6f289980b430238f9a2f6d19f8bce8e418272e08d3da43f0f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"actix-codec",
|
"actix-codec",
|
||||||
"actix-http",
|
"actix-http",
|
||||||
"actix-web",
|
"actix-web",
|
||||||
"bytestring",
|
"bytestring",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
|
"futures-sink",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
"tokio-util",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -402,9 +442,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyhow"
|
name = "anyhow"
|
||||||
version = "1.0.101"
|
version = "1.0.102"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5f0e0fee31ef5ed1ba1316088939cea399010ed7731dba877ed44aeb407a75ea"
|
checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anymap2"
|
name = "anymap2"
|
||||||
@@ -872,9 +912,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "4.5.59"
|
version = "4.5.60"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c5caf74d17c3aec5495110c34cc3f78644bfa89af6c8993ed4de2790e49b6499"
|
checksum = "2797f34da339ce31042b27d23607e051786132987f595b02ba4f6a6dffb7030a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap_builder",
|
"clap_builder",
|
||||||
"clap_derive",
|
"clap_derive",
|
||||||
@@ -882,9 +922,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_builder"
|
name = "clap_builder"
|
||||||
version = "4.5.59"
|
version = "4.5.60"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "370daa45065b80218950227371916a1633217ae42b2715b2287b606dcd618e24"
|
checksum = "24a241312cea5059b13574bb9b3861cabf758b879c15190b37b6d6fd63ab6876"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstream",
|
"anstream",
|
||||||
"anstyle",
|
"anstyle",
|
||||||
@@ -994,6 +1034,12 @@ version = "0.4.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b"
|
checksum = "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "convert_case"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "convert_case"
|
name = "convert_case"
|
||||||
version = "0.10.0"
|
version = "0.10.0"
|
||||||
@@ -1301,6 +1347,19 @@ dependencies = [
|
|||||||
"syn 1.0.109",
|
"syn 1.0.109",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "derive_more"
|
||||||
|
version = "0.99.20"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6edb4b64a43d977b8e99788fe3a04d483834fba1215a7e02caa415b626497f7f"
|
||||||
|
dependencies = [
|
||||||
|
"convert_case 0.4.0",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"rustc_version",
|
||||||
|
"syn 2.0.116",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "derive_more"
|
name = "derive_more"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
@@ -1336,7 +1395,7 @@ version = "2.1.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb"
|
checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"convert_case",
|
"convert_case 0.10.0",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"rustc_version",
|
"rustc_version",
|
||||||
@@ -3213,6 +3272,7 @@ name = "matrixgw_backend"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"actix-cors",
|
"actix-cors",
|
||||||
|
"actix-multipart",
|
||||||
"actix-remote-ip",
|
"actix-remote-ip",
|
||||||
"actix-session",
|
"actix-session",
|
||||||
"actix-web",
|
"actix-web",
|
||||||
@@ -3535,6 +3595,12 @@ dependencies = [
|
|||||||
"windows-link",
|
"windows-link",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "parse-size"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "487f2ccd1e17ce8c1bfab3a65c89525af41cfad4c8659021a1e9a2aacd73b89b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pbkdf2"
|
name = "pbkdf2"
|
||||||
version = "0.12.2"
|
version = "0.12.2"
|
||||||
@@ -4577,6 +4643,15 @@ dependencies = [
|
|||||||
"serde_core",
|
"serde_core",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_plain"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9ce1fc6db65a611022b23a0dec6975d63fb80a302cb3388835ff02c097258d50"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_spanned"
|
name = "serde_spanned"
|
||||||
version = "1.0.4"
|
version = "1.0.4"
|
||||||
@@ -5071,6 +5146,7 @@ dependencies = [
|
|||||||
"bytes",
|
"bytes",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-sink",
|
"futures-sink",
|
||||||
|
"futures-util",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -6,14 +6,15 @@ edition = "2024"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
env_logger = "0.11.9"
|
env_logger = "0.11.9"
|
||||||
log = "0.4.29"
|
log = "0.4.29"
|
||||||
clap = { version = "4.5.59", features = ["derive", "env"] }
|
clap = { version = "4.5.60", features = ["derive", "env"] }
|
||||||
anyhow = "1.0.101"
|
anyhow = "1.0.102"
|
||||||
serde = { version = "1.0.228", features = ["derive"] }
|
serde = { version = "1.0.228", features = ["derive"] }
|
||||||
tokio = { version = "1.49.0", features = ["full"] }
|
tokio = { version = "1.49.0", features = ["full"] }
|
||||||
actix-web = "4.13.0"
|
actix-web = "4.13.0"
|
||||||
actix-session = { version = "0.11.0", features = ["redis-session"] }
|
actix-session = { version = "0.11.0", features = ["redis-session"] }
|
||||||
actix-remote-ip = "0.1.0"
|
actix-remote-ip = "0.1.0"
|
||||||
actix-cors = "0.7.1"
|
actix-cors = "0.7.1"
|
||||||
|
actix-multipart = "0.7.2"
|
||||||
light-openid = "1.1.0"
|
light-openid = "1.1.0"
|
||||||
bytes = "1.11.1"
|
bytes = "1.11.1"
|
||||||
sha2 = "0.11.0-rc.5"
|
sha2 = "0.11.0-rc.5"
|
||||||
@@ -32,7 +33,7 @@ url = "2.5.8"
|
|||||||
ractor = "0.15.10"
|
ractor = "0.15.10"
|
||||||
serde_json = "1.0.149"
|
serde_json = "1.0.149"
|
||||||
lazy-regex = "3.6.0"
|
lazy-regex = "3.6.0"
|
||||||
actix-ws = "0.3.1"
|
actix-ws = "0.4.0"
|
||||||
infer = "0.19.0"
|
infer = "0.19.0"
|
||||||
rust-embed = "8.11.0"
|
rust-embed = "8.11.0"
|
||||||
mime_guess = "2.0.5"
|
mime_guess = "2.0.5"
|
||||||
@@ -2,11 +2,14 @@ use crate::controllers::HttpResult;
|
|||||||
use crate::controllers::matrix::matrix_media_controller;
|
use crate::controllers::matrix::matrix_media_controller;
|
||||||
use crate::controllers::matrix::matrix_media_controller::MediaQuery;
|
use crate::controllers::matrix::matrix_media_controller::MediaQuery;
|
||||||
use crate::controllers::matrix::matrix_room_controller::RoomIdInPath;
|
use crate::controllers::matrix::matrix_room_controller::RoomIdInPath;
|
||||||
|
use crate::controllers::server_controller::ServerConstraints;
|
||||||
use crate::extractors::matrix_client_extractor::MatrixClientExtractor;
|
use crate::extractors::matrix_client_extractor::MatrixClientExtractor;
|
||||||
|
use actix_multipart::form::MultipartForm;
|
||||||
use actix_web::dev::Payload;
|
use actix_web::dev::Payload;
|
||||||
use actix_web::{FromRequest, HttpRequest, HttpResponse, web};
|
use actix_web::{FromRequest, HttpRequest, HttpResponse, web};
|
||||||
use futures_util::{StreamExt, stream};
|
use futures_util::{StreamExt, stream};
|
||||||
use matrix_sdk::Room;
|
use matrix_sdk::Room;
|
||||||
|
use matrix_sdk::attachment::AttachmentConfig;
|
||||||
use matrix_sdk::deserialized_responses::{TimelineEvent, TimelineEventKind};
|
use matrix_sdk::deserialized_responses::{TimelineEvent, TimelineEventKind};
|
||||||
use matrix_sdk::media::MediaEventContent;
|
use matrix_sdk::media::MediaEventContent;
|
||||||
use matrix_sdk::room::MessagesOptions;
|
use matrix_sdk::room::MessagesOptions;
|
||||||
@@ -23,6 +26,7 @@ use matrix_sdk::ruma::events::{AnyMessageLikeEvent, AnyTimelineEvent};
|
|||||||
use matrix_sdk::ruma::{MilliSecondsSinceUnixEpoch, OwnedEventId, OwnedUserId, RoomId, UInt};
|
use matrix_sdk::ruma::{MilliSecondsSinceUnixEpoch, OwnedEventId, OwnedUserId, RoomId, UInt};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::value::RawValue;
|
use serde_json::value::RawValue;
|
||||||
|
use std::io::Read;
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
pub struct APIEvent {
|
pub struct APIEvent {
|
||||||
@@ -136,6 +140,55 @@ pub async fn send_text_message(
|
|||||||
Ok(HttpResponse::Accepted().finish())
|
Ok(HttpResponse::Accepted().finish())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, actix_multipart::form::MultipartForm)]
|
||||||
|
pub struct SendFileForm {
|
||||||
|
#[multipart]
|
||||||
|
file: actix_multipart::form::tempfile::TempFile,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn send_file(
|
||||||
|
client: MatrixClientExtractor,
|
||||||
|
path: web::Path<RoomIdInPath>,
|
||||||
|
req: HttpRequest,
|
||||||
|
) -> HttpResult {
|
||||||
|
let Some(payload) = client.auth.payload else {
|
||||||
|
return Ok(HttpResponse::BadRequest().body("No payload included in request!"));
|
||||||
|
};
|
||||||
|
|
||||||
|
// Reconstruct multipart form from authenticated request
|
||||||
|
let mut form = MultipartForm::<SendFileForm>::from_request(
|
||||||
|
&req,
|
||||||
|
&mut Payload::from(bytes::Bytes::from(payload)),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
// Read attachment to end
|
||||||
|
let mut buff = Vec::with_capacity(form.file.size);
|
||||||
|
form.file.file.read_to_end(&mut buff)?;
|
||||||
|
|
||||||
|
if form.file.size > ServerConstraints::default().max_upload_file_size {
|
||||||
|
return Ok(HttpResponse::NotFound().json("Uploaded file is too large!"));
|
||||||
|
}
|
||||||
|
|
||||||
|
let Some(room) = client.client.client.get_room(&path.room_id) else {
|
||||||
|
return Ok(HttpResponse::NotFound().json("Room not found!"));
|
||||||
|
};
|
||||||
|
|
||||||
|
let Some(file_name) = form.file.file_name.as_deref() else {
|
||||||
|
return Ok(HttpResponse::BadRequest().json("File name must be specified!"));
|
||||||
|
};
|
||||||
|
|
||||||
|
let Some(mime_type) = form.file.content_type.as_ref() else {
|
||||||
|
return Ok(HttpResponse::BadRequest().json("File content type must be specified!"));
|
||||||
|
};
|
||||||
|
|
||||||
|
// Do send the file
|
||||||
|
room.send_attachment(file_name, mime_type, buff, AttachmentConfig::new())
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(HttpResponse::Accepted().finish())
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(serde::Deserialize)]
|
#[derive(serde::Deserialize)]
|
||||||
pub struct EventIdInPath {
|
pub struct EventIdInPath {
|
||||||
pub(crate) event_id: OwnedEventId,
|
pub(crate) event_id: OwnedEventId,
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ pub struct ServerConstraints {
|
|||||||
pub token_name: LenConstraints,
|
pub token_name: LenConstraints,
|
||||||
pub token_ip_net: LenConstraints,
|
pub token_ip_net: LenConstraints,
|
||||||
pub token_max_inactivity: LenConstraints,
|
pub token_max_inactivity: LenConstraints,
|
||||||
|
pub max_upload_file_size: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for ServerConstraints {
|
impl Default for ServerConstraints {
|
||||||
@@ -47,6 +48,7 @@ impl Default for ServerConstraints {
|
|||||||
token_name: LenConstraints::new(5, 255),
|
token_name: LenConstraints::new(5, 255),
|
||||||
token_ip_net: LenConstraints::max_only(44),
|
token_ip_net: LenConstraints::max_only(44),
|
||||||
token_max_inactivity: LenConstraints::new(3600, 3600 * 24 * 365),
|
token_max_inactivity: LenConstraints::new(3600, 3600 * 24 * 365),
|
||||||
|
max_upload_file_size: 20_000_000,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ use matrixgw_backend::controllers::matrix::{
|
|||||||
matrix_event_controller, matrix_media_controller, matrix_profile_controller,
|
matrix_event_controller, matrix_media_controller, matrix_profile_controller,
|
||||||
matrix_room_controller, matrix_space_controller,
|
matrix_room_controller, matrix_space_controller,
|
||||||
};
|
};
|
||||||
|
use matrixgw_backend::controllers::server_controller::ServerConstraints;
|
||||||
use matrixgw_backend::controllers::{
|
use matrixgw_backend::controllers::{
|
||||||
auth_controller, matrix_link_controller, matrix_sync_thread_controller, server_controller,
|
auth_controller, matrix_link_controller, matrix_sync_thread_controller, server_controller,
|
||||||
static_controller, tokens_controller, ws_controller,
|
static_controller, tokens_controller, ws_controller,
|
||||||
@@ -75,6 +76,9 @@ async fn main() -> std::io::Result<()> {
|
|||||||
.wrap(Logger::default())
|
.wrap(Logger::default())
|
||||||
.wrap(session_mw)
|
.wrap(session_mw)
|
||||||
.wrap(cors)
|
.wrap(cors)
|
||||||
|
.app_data(web::PayloadConfig::new(
|
||||||
|
ServerConstraints::default().max_upload_file_size,
|
||||||
|
))
|
||||||
.app_data(web::Data::new(manager_actor_clone.clone()))
|
.app_data(web::Data::new(manager_actor_clone.clone()))
|
||||||
.app_data(web::Data::new(RemoteIPConfig {
|
.app_data(web::Data::new(RemoteIPConfig {
|
||||||
proxy: AppConfig::get().proxy_ip.clone(),
|
proxy: AppConfig::get().proxy_ip.clone(),
|
||||||
@@ -182,6 +186,10 @@ async fn main() -> std::io::Result<()> {
|
|||||||
"/api/matrix/room/{room_id}/send_text_message",
|
"/api/matrix/room/{room_id}/send_text_message",
|
||||||
web::post().to(matrix_event_controller::send_text_message),
|
web::post().to(matrix_event_controller::send_text_message),
|
||||||
)
|
)
|
||||||
|
.route(
|
||||||
|
"/api/matrix/room/{room_id}/send_file",
|
||||||
|
web::post().to(matrix_event_controller::send_file),
|
||||||
|
)
|
||||||
.route(
|
.route(
|
||||||
"/api/matrix/room/{room_id}/event/{event_id}/set_text_content",
|
"/api/matrix/room/{room_id}/event/{event_id}/set_text_content",
|
||||||
web::post().to(matrix_event_controller::set_text_content),
|
web::post().to(matrix_event_controller::set_text_content),
|
||||||
|
|||||||
250
matrixgw_frontend/package-lock.json
generated
250
matrixgw_frontend/package-lock.json
generated
@@ -15,9 +15,10 @@
|
|||||||
"@mui/material": "^7.3.8",
|
"@mui/material": "^7.3.8",
|
||||||
"@mui/x-data-grid": "^8.27.3",
|
"@mui/x-data-grid": "^8.27.3",
|
||||||
"@mui/x-date-pickers": "^8.27.2",
|
"@mui/x-date-pickers": "^8.27.2",
|
||||||
"date-and-time": "^4.2.0",
|
"date-and-time": "^4.3.0",
|
||||||
"dayjs": "^1.11.19",
|
"dayjs": "^1.11.19",
|
||||||
"emoji-picker-react": "^4.17.4",
|
"emoji-picker-react": "^4.18.0",
|
||||||
|
"filesize": "^11.0.13",
|
||||||
"is-cidr": "^6.0.3",
|
"is-cidr": "^6.0.3",
|
||||||
"qrcode.react": "^4.2.0",
|
"qrcode.react": "^4.2.0",
|
||||||
"react": "^19.2.4",
|
"react": "^19.2.4",
|
||||||
@@ -28,16 +29,16 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^9.39.3",
|
"@eslint/js": "^9.39.3",
|
||||||
"@types/node": "^25.1.0",
|
"@types/node": "^25.3.3",
|
||||||
"@types/react": "^19.2.14",
|
"@types/react": "^19.2.14",
|
||||||
"@types/react-dom": "^19.2.3",
|
"@types/react-dom": "^19.2.3",
|
||||||
"@vitejs/plugin-react": "^5.1.4",
|
"@vitejs/plugin-react": "^5.1.4",
|
||||||
"eslint": "^9.39.3",
|
"eslint": "^9.39.3",
|
||||||
"eslint-plugin-react-hooks": "^7.0.1",
|
"eslint-plugin-react-hooks": "^7.0.1",
|
||||||
"eslint-plugin-react-refresh": "^0.4.26",
|
"eslint-plugin-react-refresh": "^0.5.2",
|
||||||
"globals": "^16.5.0",
|
"globals": "^17.4.0",
|
||||||
"typescript": "~5.9.3",
|
"typescript": "~5.9.3",
|
||||||
"typescript-eslint": "^8.54.0",
|
"typescript-eslint": "^8.56.1",
|
||||||
"vite": "npm:rolldown-vite@7.3.1"
|
"vite": "npm:rolldown-vite@7.3.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -1495,13 +1496,13 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@types/node": {
|
"node_modules/@types/node": {
|
||||||
"version": "25.1.0",
|
"version": "25.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-25.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-25.3.3.tgz",
|
||||||
"integrity": "sha512-t7frlewr6+cbx+9Ohpl0NOTKXZNV9xHRmNOvql47BFJKcEG1CxtxlPEEe+gR9uhVWM4DwhnvTF110mIL4yP9RA==",
|
"integrity": "sha512-DpzbrH7wIcBaJibpKo9nnSQL0MTRdnWttGyE5haGwK86xgMOkFLp7vEyfQPGLOJh5wNYiJ3V9PmUMDhV9u8kkQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"undici-types": "~7.16.0"
|
"undici-types": "~7.18.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/parse-json": {
|
"node_modules/@types/parse-json": {
|
||||||
@@ -1545,17 +1546,17 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||||
"version": "8.54.0",
|
"version": "8.56.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.54.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.56.1.tgz",
|
||||||
"integrity": "sha512-hAAP5io/7csFStuOmR782YmTthKBJ9ND3WVL60hcOjvtGFb+HJxH4O5huAcmcZ9v9G8P+JETiZ/G1B8MALnWZQ==",
|
"integrity": "sha512-Jz9ZztpB37dNC+HU2HI28Bs9QXpzCz+y/twHOwhyrIRdbuVDxSytJNDl6z/aAKlaRIwC7y8wJdkBv7FxYGgi0A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/regexpp": "^4.12.2",
|
"@eslint-community/regexpp": "^4.12.2",
|
||||||
"@typescript-eslint/scope-manager": "8.54.0",
|
"@typescript-eslint/scope-manager": "8.56.1",
|
||||||
"@typescript-eslint/type-utils": "8.54.0",
|
"@typescript-eslint/type-utils": "8.56.1",
|
||||||
"@typescript-eslint/utils": "8.54.0",
|
"@typescript-eslint/utils": "8.56.1",
|
||||||
"@typescript-eslint/visitor-keys": "8.54.0",
|
"@typescript-eslint/visitor-keys": "8.56.1",
|
||||||
"ignore": "^7.0.5",
|
"ignore": "^7.0.5",
|
||||||
"natural-compare": "^1.4.0",
|
"natural-compare": "^1.4.0",
|
||||||
"ts-api-utils": "^2.4.0"
|
"ts-api-utils": "^2.4.0"
|
||||||
@@ -1568,8 +1569,8 @@
|
|||||||
"url": "https://opencollective.com/typescript-eslint"
|
"url": "https://opencollective.com/typescript-eslint"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@typescript-eslint/parser": "^8.54.0",
|
"@typescript-eslint/parser": "^8.56.1",
|
||||||
"eslint": "^8.57.0 || ^9.0.0",
|
"eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
|
||||||
"typescript": ">=4.8.4 <6.0.0"
|
"typescript": ">=4.8.4 <6.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -1584,16 +1585,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/parser": {
|
"node_modules/@typescript-eslint/parser": {
|
||||||
"version": "8.54.0",
|
"version": "8.56.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.54.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.56.1.tgz",
|
||||||
"integrity": "sha512-BtE0k6cjwjLZoZixN0t5AKP0kSzlGu7FctRXYuPAm//aaiZhmfq1JwdYpYr1brzEspYyFeF+8XF5j2VK6oalrA==",
|
"integrity": "sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/scope-manager": "8.54.0",
|
"@typescript-eslint/scope-manager": "8.56.1",
|
||||||
"@typescript-eslint/types": "8.54.0",
|
"@typescript-eslint/types": "8.56.1",
|
||||||
"@typescript-eslint/typescript-estree": "8.54.0",
|
"@typescript-eslint/typescript-estree": "8.56.1",
|
||||||
"@typescript-eslint/visitor-keys": "8.54.0",
|
"@typescript-eslint/visitor-keys": "8.56.1",
|
||||||
"debug": "^4.4.3"
|
"debug": "^4.4.3"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -1604,19 +1605,19 @@
|
|||||||
"url": "https://opencollective.com/typescript-eslint"
|
"url": "https://opencollective.com/typescript-eslint"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"eslint": "^8.57.0 || ^9.0.0",
|
"eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
|
||||||
"typescript": ">=4.8.4 <6.0.0"
|
"typescript": ">=4.8.4 <6.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/project-service": {
|
"node_modules/@typescript-eslint/project-service": {
|
||||||
"version": "8.54.0",
|
"version": "8.56.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.54.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.56.1.tgz",
|
||||||
"integrity": "sha512-YPf+rvJ1s7MyiWM4uTRhE4DvBXrEV+d8oC3P9Y2eT7S+HBS0clybdMIPnhiATi9vZOYDc7OQ1L/i6ga6NFYK/g==",
|
"integrity": "sha512-TAdqQTzHNNvlVFfR+hu2PDJrURiwKsUvxFn1M0h95BB8ah5jejas08jUWG4dBA68jDMI988IvtfdAI53JzEHOQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/tsconfig-utils": "^8.54.0",
|
"@typescript-eslint/tsconfig-utils": "^8.56.1",
|
||||||
"@typescript-eslint/types": "^8.54.0",
|
"@typescript-eslint/types": "^8.56.1",
|
||||||
"debug": "^4.4.3"
|
"debug": "^4.4.3"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -1631,14 +1632,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/scope-manager": {
|
"node_modules/@typescript-eslint/scope-manager": {
|
||||||
"version": "8.54.0",
|
"version": "8.56.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.54.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.56.1.tgz",
|
||||||
"integrity": "sha512-27rYVQku26j/PbHYcVfRPonmOlVI6gihHtXFbTdB5sb6qA0wdAQAbyXFVarQ5t4HRojIz64IV90YtsjQSSGlQg==",
|
"integrity": "sha512-YAi4VDKcIZp0O4tz/haYKhmIDZFEUPOreKbfdAN3SzUDMcPhJ8QI99xQXqX+HoUVq8cs85eRKnD+rne2UAnj2w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "8.54.0",
|
"@typescript-eslint/types": "8.56.1",
|
||||||
"@typescript-eslint/visitor-keys": "8.54.0"
|
"@typescript-eslint/visitor-keys": "8.56.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
@@ -1649,9 +1650,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/tsconfig-utils": {
|
"node_modules/@typescript-eslint/tsconfig-utils": {
|
||||||
"version": "8.54.0",
|
"version": "8.56.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.54.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.56.1.tgz",
|
||||||
"integrity": "sha512-dRgOyT2hPk/JwxNMZDsIXDgyl9axdJI3ogZ2XWhBPsnZUv+hPesa5iuhdYt2gzwA9t8RE5ytOJ6xB0moV0Ujvw==",
|
"integrity": "sha512-qOtCYzKEeyr3aR9f28mPJqBty7+DBqsdd63eO0yyDwc6vgThj2UjWfJIcsFeSucYydqcuudMOprZ+x1SpF3ZuQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -1666,15 +1667,15 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/type-utils": {
|
"node_modules/@typescript-eslint/type-utils": {
|
||||||
"version": "8.54.0",
|
"version": "8.56.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.54.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.56.1.tgz",
|
||||||
"integrity": "sha512-hiLguxJWHjjwL6xMBwD903ciAwd7DmK30Y9Axs/etOkftC3ZNN9K44IuRD/EB08amu+Zw6W37x9RecLkOo3pMA==",
|
"integrity": "sha512-yB/7dxi7MgTtGhZdaHCemf7PuwrHMenHjmzgUW1aJpO+bBU43OycnM3Wn+DdvDO/8zzA9HlhaJ0AUGuvri4oGg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "8.54.0",
|
"@typescript-eslint/types": "8.56.1",
|
||||||
"@typescript-eslint/typescript-estree": "8.54.0",
|
"@typescript-eslint/typescript-estree": "8.56.1",
|
||||||
"@typescript-eslint/utils": "8.54.0",
|
"@typescript-eslint/utils": "8.56.1",
|
||||||
"debug": "^4.4.3",
|
"debug": "^4.4.3",
|
||||||
"ts-api-utils": "^2.4.0"
|
"ts-api-utils": "^2.4.0"
|
||||||
},
|
},
|
||||||
@@ -1686,14 +1687,14 @@
|
|||||||
"url": "https://opencollective.com/typescript-eslint"
|
"url": "https://opencollective.com/typescript-eslint"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"eslint": "^8.57.0 || ^9.0.0",
|
"eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
|
||||||
"typescript": ">=4.8.4 <6.0.0"
|
"typescript": ">=4.8.4 <6.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/types": {
|
"node_modules/@typescript-eslint/types": {
|
||||||
"version": "8.54.0",
|
"version": "8.56.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.54.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.56.1.tgz",
|
||||||
"integrity": "sha512-PDUI9R1BVjqu7AUDsRBbKMtwmjWcn4J3le+5LpcFgWULN3LvHC5rkc9gCVxbrsrGmO1jfPybN5s6h4Jy+OnkAA==",
|
"integrity": "sha512-dbMkdIUkIkchgGDIv7KLUpa0Mda4IYjo4IAMJUZ+3xNoUXxMsk9YtKpTHSChRS85o+H9ftm51gsK1dZReY9CVw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -1705,18 +1706,18 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/typescript-estree": {
|
"node_modules/@typescript-eslint/typescript-estree": {
|
||||||
"version": "8.54.0",
|
"version": "8.56.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.54.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.56.1.tgz",
|
||||||
"integrity": "sha512-BUwcskRaPvTk6fzVWgDPdUndLjB87KYDrN5EYGetnktoeAvPtO4ONHlAZDnj5VFnUANg0Sjm7j4usBlnoVMHwA==",
|
"integrity": "sha512-qzUL1qgalIvKWAf9C1HpvBjif+Vm6rcT5wZd4VoMb9+Km3iS3Cv9DY6dMRMDtPnwRAFyAi7YXJpTIEXLvdfPxg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/project-service": "8.54.0",
|
"@typescript-eslint/project-service": "8.56.1",
|
||||||
"@typescript-eslint/tsconfig-utils": "8.54.0",
|
"@typescript-eslint/tsconfig-utils": "8.56.1",
|
||||||
"@typescript-eslint/types": "8.54.0",
|
"@typescript-eslint/types": "8.56.1",
|
||||||
"@typescript-eslint/visitor-keys": "8.54.0",
|
"@typescript-eslint/visitor-keys": "8.56.1",
|
||||||
"debug": "^4.4.3",
|
"debug": "^4.4.3",
|
||||||
"minimatch": "^9.0.5",
|
"minimatch": "^10.2.2",
|
||||||
"semver": "^7.7.3",
|
"semver": "^7.7.3",
|
||||||
"tinyglobby": "^0.2.15",
|
"tinyglobby": "^0.2.15",
|
||||||
"ts-api-utils": "^2.4.0"
|
"ts-api-utils": "^2.4.0"
|
||||||
@@ -1732,36 +1733,49 @@
|
|||||||
"typescript": ">=4.8.4 <6.0.0"
|
"typescript": ">=4.8.4 <6.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@typescript-eslint/typescript-estree/node_modules/balanced-match": {
|
||||||
|
"version": "4.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz",
|
||||||
|
"integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": "18 || 20 || >=22"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
|
"node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
|
||||||
"version": "2.0.2",
|
"version": "5.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz",
|
||||||
"integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
|
"integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"balanced-match": "^1.0.0"
|
"balanced-match": "^4.0.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "18 || 20 || >=22"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": {
|
"node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": {
|
||||||
"version": "9.0.5",
|
"version": "10.2.4",
|
||||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz",
|
||||||
"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
|
"integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "ISC",
|
"license": "BlueOak-1.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"brace-expansion": "^2.0.1"
|
"brace-expansion": "^5.0.2"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=16 || 14 >=14.17"
|
"node": "18 || 20 || >=22"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/sponsors/isaacs"
|
"url": "https://github.com/sponsors/isaacs"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/typescript-estree/node_modules/semver": {
|
"node_modules/@typescript-eslint/typescript-estree/node_modules/semver": {
|
||||||
"version": "7.7.3",
|
"version": "7.7.4",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
|
||||||
"integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
|
"integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"bin": {
|
"bin": {
|
||||||
@@ -1772,16 +1786,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/utils": {
|
"node_modules/@typescript-eslint/utils": {
|
||||||
"version": "8.54.0",
|
"version": "8.56.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.54.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.56.1.tgz",
|
||||||
"integrity": "sha512-9Cnda8GS57AQakvRyG0PTejJNlA2xhvyNtEVIMlDWOOeEyBkYWhGPnfrIAnqxLMTSTo6q8g12XVjjev5l1NvMA==",
|
"integrity": "sha512-HPAVNIME3tABJ61siYlHzSWCGtOoeP2RTIaHXFMPqjrQKCGB9OgUVdiNgH7TJS2JNIQ5qQ4RsAUDuGaGme/KOA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/eslint-utils": "^4.9.1",
|
"@eslint-community/eslint-utils": "^4.9.1",
|
||||||
"@typescript-eslint/scope-manager": "8.54.0",
|
"@typescript-eslint/scope-manager": "8.56.1",
|
||||||
"@typescript-eslint/types": "8.54.0",
|
"@typescript-eslint/types": "8.56.1",
|
||||||
"@typescript-eslint/typescript-estree": "8.54.0"
|
"@typescript-eslint/typescript-estree": "8.56.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
@@ -1791,19 +1805,19 @@
|
|||||||
"url": "https://opencollective.com/typescript-eslint"
|
"url": "https://opencollective.com/typescript-eslint"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"eslint": "^8.57.0 || ^9.0.0",
|
"eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
|
||||||
"typescript": ">=4.8.4 <6.0.0"
|
"typescript": ">=4.8.4 <6.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/visitor-keys": {
|
"node_modules/@typescript-eslint/visitor-keys": {
|
||||||
"version": "8.54.0",
|
"version": "8.56.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.54.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.56.1.tgz",
|
||||||
"integrity": "sha512-VFlhGSl4opC0bprJiItPQ1RfUhGDIBokcPwaFH4yiBCaNPeld/9VeXbiPO1cLyorQi1G1vL+ecBk1x8o1axORA==",
|
"integrity": "sha512-KiROIzYdEV85YygXw6BI/Dx4fnBlFQu6Mq4QE4MOH9fFnhohw6wX/OAvDY2/C+ut0I3RSPKenvZJIVYqJNkhEw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "8.54.0",
|
"@typescript-eslint/types": "8.56.1",
|
||||||
"eslint-visitor-keys": "^4.2.1"
|
"eslint-visitor-keys": "^5.0.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
@@ -1813,6 +1827,19 @@
|
|||||||
"url": "https://opencollective.com/typescript-eslint"
|
"url": "https://opencollective.com/typescript-eslint"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": {
|
||||||
|
"version": "5.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz",
|
||||||
|
"integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"engines": {
|
||||||
|
"node": "^20.19.0 || ^22.13.0 || >=24"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/eslint"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@vitejs/plugin-react": {
|
"node_modules/@vitejs/plugin-react": {
|
||||||
"version": "5.1.4",
|
"version": "5.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.1.4.tgz",
|
||||||
@@ -2139,9 +2166,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/date-and-time": {
|
"node_modules/date-and-time": {
|
||||||
"version": "4.2.0",
|
"version": "4.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/date-and-time/-/date-and-time-4.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/date-and-time/-/date-and-time-4.3.0.tgz",
|
||||||
"integrity": "sha512-bqLrJqsjXMW3yQlR7QrQZqZNVDwo+GkvcAeRzZScAdUAgQPP+baV+j6HFbVp3cpCgVez3Mx2zIPqwk9FMfkVIw==",
|
"integrity": "sha512-dVj2DNzRQtgIrDOcX1DVuMEv0S8wF/zZ6F9OfD1P+zwmtk3hN28nIff8dBGl320DjVNGssfFrdbUad7lDYLZLQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
@@ -2205,9 +2232,9 @@
|
|||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
"node_modules/emoji-picker-react": {
|
"node_modules/emoji-picker-react": {
|
||||||
"version": "4.17.4",
|
"version": "4.18.0",
|
||||||
"resolved": "https://registry.npmjs.org/emoji-picker-react/-/emoji-picker-react-4.17.4.tgz",
|
"resolved": "https://registry.npmjs.org/emoji-picker-react/-/emoji-picker-react-4.18.0.tgz",
|
||||||
"integrity": "sha512-ZO85fhiyjCQxOSGkmBarbGVe+t7SRUME0XuE7AwThtzEay+xnYH8FSuCspiip2mFJT5DPO2lPnELqEvzwjBcYA==",
|
"integrity": "sha512-vLTrLfApXAIciguGE57pXPWs9lPLBspbEpPMiUq03TIli2dHZBiB+aZ0R9/Wat0xmTfcd4AuEzQgSYxEZ8C88Q==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"flairup": "1.0.0"
|
"flairup": "1.0.0"
|
||||||
@@ -2331,13 +2358,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/eslint-plugin-react-refresh": {
|
"node_modules/eslint-plugin-react-refresh": {
|
||||||
"version": "0.4.26",
|
"version": "0.5.2",
|
||||||
"resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.26.tgz",
|
"resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.5.2.tgz",
|
||||||
"integrity": "sha512-1RETEylht2O6FM/MvgnyvT+8K21wLqDNg4qD51Zj3guhjt433XbnnkVttHMyaVyAFD03QSV4LPS5iE3VQmO7XQ==",
|
"integrity": "sha512-hmgTH57GfzoTFjVN0yBwTggnsVUF2tcqi7RJZHqi9lIezSs4eFyAMktA68YD4r5kNw1mxyY4dmkyoFDb3FIqrA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"eslint": ">=8.40"
|
"eslint": "^9 || ^10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/eslint-scope": {
|
"node_modules/eslint-scope": {
|
||||||
@@ -2486,6 +2513,15 @@
|
|||||||
"node": ">=16.0.0"
|
"node": ">=16.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/filesize": {
|
||||||
|
"version": "11.0.13",
|
||||||
|
"resolved": "https://registry.npmjs.org/filesize/-/filesize-11.0.13.tgz",
|
||||||
|
"integrity": "sha512-mYJ/qXKvREuO0uH8LTQJ6v7GsUvVOguqxg2VTwQUkyTPXXRRWPdjuUPVqdBrJQhvci48OHlNGRnux+Slr2Rnvw==",
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10.8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/find-root": {
|
"node_modules/find-root": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz",
|
||||||
@@ -2584,9 +2620,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/globals": {
|
"node_modules/globals": {
|
||||||
"version": "16.5.0",
|
"version": "17.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/globals/-/globals-16.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/globals/-/globals-17.4.0.tgz",
|
||||||
"integrity": "sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==",
|
"integrity": "sha512-hjrNztw/VajQwOLsMNT1cbJiH2muO3OROCHnbehc8eY5JyD2gqz4AcMHPqgaOR59DjgUjYAYLeH699g/eWi2jw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -3781,16 +3817,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/typescript-eslint": {
|
"node_modules/typescript-eslint": {
|
||||||
"version": "8.54.0",
|
"version": "8.56.1",
|
||||||
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.54.0.tgz",
|
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.56.1.tgz",
|
||||||
"integrity": "sha512-CKsJ+g53QpsNPqbzUsfKVgd3Lny4yKZ1pP4qN3jdMOg/sisIDLGyDMezycquXLE5JsEU0wp3dGNdzig0/fmSVQ==",
|
"integrity": "sha512-U4lM6pjmBX7J5wk4szltF7I1cGBHXZopnAXCMXb3+fZ3B/0Z3hq3wS/CCUB2NZBNAExK92mCU2tEohWuwVMsDQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/eslint-plugin": "8.54.0",
|
"@typescript-eslint/eslint-plugin": "8.56.1",
|
||||||
"@typescript-eslint/parser": "8.54.0",
|
"@typescript-eslint/parser": "8.56.1",
|
||||||
"@typescript-eslint/typescript-estree": "8.54.0",
|
"@typescript-eslint/typescript-estree": "8.56.1",
|
||||||
"@typescript-eslint/utils": "8.54.0"
|
"@typescript-eslint/utils": "8.56.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
@@ -3800,14 +3836,14 @@
|
|||||||
"url": "https://opencollective.com/typescript-eslint"
|
"url": "https://opencollective.com/typescript-eslint"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"eslint": "^8.57.0 || ^9.0.0",
|
"eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
|
||||||
"typescript": ">=4.8.4 <6.0.0"
|
"typescript": ">=4.8.4 <6.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/undici-types": {
|
"node_modules/undici-types": {
|
||||||
"version": "7.16.0",
|
"version": "7.18.2",
|
||||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz",
|
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz",
|
||||||
"integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==",
|
"integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -17,9 +17,10 @@
|
|||||||
"@mui/material": "^7.3.8",
|
"@mui/material": "^7.3.8",
|
||||||
"@mui/x-data-grid": "^8.27.3",
|
"@mui/x-data-grid": "^8.27.3",
|
||||||
"@mui/x-date-pickers": "^8.27.2",
|
"@mui/x-date-pickers": "^8.27.2",
|
||||||
"date-and-time": "^4.2.0",
|
"date-and-time": "^4.3.0",
|
||||||
"dayjs": "^1.11.19",
|
"dayjs": "^1.11.19",
|
||||||
"emoji-picker-react": "^4.17.4",
|
"emoji-picker-react": "^4.18.0",
|
||||||
|
"filesize": "^11.0.13",
|
||||||
"is-cidr": "^6.0.3",
|
"is-cidr": "^6.0.3",
|
||||||
"qrcode.react": "^4.2.0",
|
"qrcode.react": "^4.2.0",
|
||||||
"react": "^19.2.4",
|
"react": "^19.2.4",
|
||||||
@@ -30,16 +31,16 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^9.39.3",
|
"@eslint/js": "^9.39.3",
|
||||||
"@types/node": "^25.1.0",
|
"@types/node": "^25.3.3",
|
||||||
"@types/react": "^19.2.14",
|
"@types/react": "^19.2.14",
|
||||||
"@types/react-dom": "^19.2.3",
|
"@types/react-dom": "^19.2.3",
|
||||||
"@vitejs/plugin-react": "^5.1.4",
|
"@vitejs/plugin-react": "^5.1.4",
|
||||||
"eslint": "^9.39.3",
|
"eslint": "^9.39.3",
|
||||||
"eslint-plugin-react-hooks": "^7.0.1",
|
"eslint-plugin-react-hooks": "^7.0.1",
|
||||||
"eslint-plugin-react-refresh": "^0.4.26",
|
"eslint-plugin-react-refresh": "^0.5.2",
|
||||||
"globals": "^16.5.0",
|
"globals": "^17.4.0",
|
||||||
"typescript": "~5.9.3",
|
"typescript": "~5.9.3",
|
||||||
"typescript-eslint": "^8.54.0",
|
"typescript-eslint": "^8.56.1",
|
||||||
"vite": "npm:rolldown-vite@7.3.1"
|
"vite": "npm:rolldown-vite@7.3.1"
|
||||||
},
|
},
|
||||||
"overrides": {
|
"overrides": {
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ export interface ServerConstraints {
|
|||||||
token_name: LenConstraint;
|
token_name: LenConstraint;
|
||||||
token_ip_net: LenConstraint;
|
token_ip_net: LenConstraint;
|
||||||
token_max_inactivity: LenConstraint;
|
token_max_inactivity: LenConstraint;
|
||||||
|
max_upload_file_size: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LenConstraint {
|
export interface LenConstraint {
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ export class MatrixApiEvent {
|
|||||||
*/
|
*/
|
||||||
static async GetRoomEvents(
|
static async GetRoomEvents(
|
||||||
room: Room,
|
room: Room,
|
||||||
from?: string
|
from?: string,
|
||||||
): Promise<MatrixEventsList> {
|
): Promise<MatrixEventsList> {
|
||||||
return (
|
return (
|
||||||
await APIClient.exec({
|
await APIClient.exec({
|
||||||
@@ -86,7 +86,7 @@ export class MatrixApiEvent {
|
|||||||
static GetEventFileURL(
|
static GetEventFileURL(
|
||||||
room: Room,
|
room: Room,
|
||||||
event_id: string,
|
event_id: string,
|
||||||
thumbnail: boolean
|
thumbnail: boolean,
|
||||||
): string {
|
): string {
|
||||||
return `${APIClient.ActualBackendURL()}/matrix/room/${
|
return `${APIClient.ActualBackendURL()}/matrix/room/${
|
||||||
room.id
|
room.id
|
||||||
@@ -104,13 +104,26 @@ export class MatrixApiEvent {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send file message
|
||||||
|
*/
|
||||||
|
static async SendFileMessage(room: Room, file: Blob): Promise<void> {
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.set("file", file);
|
||||||
|
await APIClient.exec({
|
||||||
|
method: "POST",
|
||||||
|
uri: `/matrix/room/${room.id}/send_file`,
|
||||||
|
formData,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Edit text message content
|
* Edit text message content
|
||||||
*/
|
*/
|
||||||
static async SetTextMessageContent(
|
static async SetTextMessageContent(
|
||||||
room: Room,
|
room: Room,
|
||||||
event_id: string,
|
event_id: string,
|
||||||
content: string
|
content: string,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
await APIClient.exec({
|
await APIClient.exec({
|
||||||
method: "POST",
|
method: "POST",
|
||||||
@@ -125,7 +138,7 @@ export class MatrixApiEvent {
|
|||||||
static async ReactToEvent(
|
static async ReactToEvent(
|
||||||
room: Room,
|
room: Room,
|
||||||
event_id: string,
|
event_id: string,
|
||||||
key: string
|
key: string,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
await APIClient.exec({
|
await APIClient.exec({
|
||||||
method: "POST",
|
method: "POST",
|
||||||
|
|||||||
33
matrixgw_frontend/src/utils/FilesUtils.ts
Normal file
33
matrixgw_frontend/src/utils/FilesUtils.ts
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import { filesize } from "filesize";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Select a file to upload
|
||||||
|
*/
|
||||||
|
export async function selectFileToUpload(p: {
|
||||||
|
allowedTypes?: string[];
|
||||||
|
maxSize?: number;
|
||||||
|
}): Promise<Blob | null> {
|
||||||
|
// Create file element
|
||||||
|
const fileEl = document.createElement("input");
|
||||||
|
fileEl.type = "file";
|
||||||
|
if (p.allowedTypes && p.allowedTypes.length > 0)
|
||||||
|
fileEl.accept = p.allowedTypes.join(",");
|
||||||
|
fileEl.click();
|
||||||
|
|
||||||
|
// Wait for a file to be chosen
|
||||||
|
await new Promise((res) =>
|
||||||
|
fileEl.addEventListener("change", () => res(null)),
|
||||||
|
);
|
||||||
|
|
||||||
|
if ((fileEl.files?.length ?? 0) === 0) return null;
|
||||||
|
const file = fileEl.files![0];
|
||||||
|
|
||||||
|
// Check file size
|
||||||
|
if (p.maxSize && file.size > p.maxSize) {
|
||||||
|
throw new Error(
|
||||||
|
`The file is too big ! (max accepted file size : ${filesize(p.maxSize)})`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return file;
|
||||||
|
}
|
||||||
@@ -1,18 +1,23 @@
|
|||||||
|
import AttachFileIcon from "@mui/icons-material/AttachFile";
|
||||||
import SendIcon from "@mui/icons-material/Send";
|
import SendIcon from "@mui/icons-material/Send";
|
||||||
import { IconButton, TextField } from "@mui/material";
|
import { IconButton, TextField, Tooltip } from "@mui/material";
|
||||||
import React, { type FormEvent } from "react";
|
import React, { type SyntheticEvent } from "react";
|
||||||
import { MatrixApiEvent } from "../../api/matrix/MatrixApiEvent";
|
import { MatrixApiEvent } from "../../api/matrix/MatrixApiEvent";
|
||||||
import type { Room } from "../../api/matrix/MatrixApiRoom";
|
import type { Room } from "../../api/matrix/MatrixApiRoom";
|
||||||
import { useAlert } from "../../hooks/contexts_provider/AlertDialogProvider";
|
import { useAlert } from "../../hooks/contexts_provider/AlertDialogProvider";
|
||||||
import { useLoadingMessage } from "../../hooks/contexts_provider/LoadingMessageProvider";
|
import { useLoadingMessage } from "../../hooks/contexts_provider/LoadingMessageProvider";
|
||||||
|
import { selectFileToUpload } from "../../utils/FilesUtils";
|
||||||
|
import { ServerApi } from "../../api/ServerApi";
|
||||||
|
import { useSnackbar } from "../../hooks/contexts_provider/SnackbarProvider";
|
||||||
|
|
||||||
export function SendMessageForm(p: { room: Room }): React.ReactElement {
|
export function SendMessageForm(p: { room: Room }): React.ReactElement {
|
||||||
const loadingMessage = useLoadingMessage();
|
const loadingMessage = useLoadingMessage();
|
||||||
const alert = useAlert();
|
const alert = useAlert();
|
||||||
|
const snackbar = useSnackbar();
|
||||||
|
|
||||||
const [text, setText] = React.useState("");
|
const [text, setText] = React.useState("");
|
||||||
|
|
||||||
const handleTextSubmit = async (e: FormEvent) => {
|
const handleTextSubmit = async (e: SyntheticEvent) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
if (text === "") return;
|
if (text === "") return;
|
||||||
@@ -31,6 +36,26 @@ export function SendMessageForm(p: { room: Room }): React.ReactElement {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleFileSubmit = async () => {
|
||||||
|
try {
|
||||||
|
const file = await selectFileToUpload({
|
||||||
|
maxSize: ServerApi.Config.constraints.max_upload_file_size,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!file) return;
|
||||||
|
|
||||||
|
loadingMessage.show("Uploading file...");
|
||||||
|
await MatrixApiEvent.SendFileMessage(p.room, file);
|
||||||
|
|
||||||
|
snackbar("The file was successfully uploaded!");
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
alert(`Failed to upload file! ${e}`);
|
||||||
|
} finally {
|
||||||
|
loadingMessage.hide();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form onSubmit={handleTextSubmit}>
|
<form onSubmit={handleTextSubmit}>
|
||||||
<div
|
<div
|
||||||
@@ -50,6 +75,13 @@ export function SendMessageForm(p: { room: Room }): React.ReactElement {
|
|||||||
value={text}
|
value={text}
|
||||||
onChange={(e) => setText(e.target.value)}
|
onChange={(e) => setText(e.target.value)}
|
||||||
/>
|
/>
|
||||||
|
<span style={{ width: "10px" }}></span>
|
||||||
|
<Tooltip title="Send a file">
|
||||||
|
<IconButton size="small" onClick={handleFileSubmit}>
|
||||||
|
<AttachFileIcon />
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
<span style={{ width: "10px" }}></span>
|
||||||
<IconButton
|
<IconButton
|
||||||
size="small"
|
size="small"
|
||||||
style={{ visibility: text === "" ? "hidden" : "visible" }}
|
style={{ visibility: text === "" ? "hidden" : "visible" }}
|
||||||
|
|||||||
Reference in New Issue
Block a user