5 Commits

Author SHA1 Message Date
8a4570a044 Fix Drone configuration
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
2025-12-04 17:23:06 +01:00
e51fc6b4bb Fix ESLint issues
Some checks failed
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is failing
2025-12-04 16:32:06 +01:00
0f68d59798 Fix spaces support in UI
Some checks failed
continuous-integration/drone/push Build is failing
2025-12-04 15:35:16 +01:00
5ad23005be Fix time alignment
All checks were successful
continuous-integration/drone/push Build is passing
2025-12-04 15:03:38 +01:00
4e096a1d49 Can get spaces hierarchy
All checks were successful
continuous-integration/drone/push Build is passing
2025-12-04 09:18:32 +01:00
12 changed files with 382 additions and 50 deletions

View File

@@ -89,7 +89,7 @@ steps:
path: /tmp/release
environment:
PLUGIN_API_KEY:
from_secret: API_KEY
from_secret: GITEA_API_KEY # needs permission write:repository
settings:
base_url: https://gitea.communiquons.org
files: /tmp/release/*

View File

@@ -481,6 +481,16 @@ dependencies = [
"tokio",
]
[[package]]
name = "async-rx"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a30de4e5329a0947e389f738a6ca0d0b938fea5cb7baaeae7d72e243614468a2"
dependencies = [
"futures-core",
"pin-project-lite",
]
[[package]]
name = "async-stream"
version = "0.3.6"
@@ -514,6 +524,15 @@ dependencies = [
"syn",
]
[[package]]
name = "async_cell"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "447ab28afbb345f5408b120702a44e5529ebf90b1796ec76e9528df8e288e6c2"
dependencies = [
"loom",
]
[[package]]
name = "atomic-waker"
version = "1.1.2"
@@ -829,7 +848,7 @@ dependencies = [
"num-traits",
"serde",
"wasm-bindgen",
"windows-link",
"windows-link 0.2.1",
]
[[package]]
@@ -1431,6 +1450,15 @@ dependencies = [
"zeroize",
]
[[package]]
name = "emojis"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f52f3d011046a013bdefbc63a5523b06ad0c0f1e227941baf98475496229d634"
dependencies = [
"phf 0.12.1",
]
[[package]]
name = "encoding_rs"
version = "0.8.35"
@@ -1526,6 +1554,20 @@ dependencies = [
"tracing",
]
[[package]]
name = "eyeball-im-util"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bda2d08a8fa99050bdb84d077193a371e9abd29696921971aa26ae076adb6023"
dependencies = [
"arrayvec",
"eyeball-im",
"futures-core",
"imbl",
"pin-project-lite",
"smallvec",
]
[[package]]
name = "fallible-iterator"
version = "0.3.0"
@@ -1748,6 +1790,29 @@ dependencies = [
"slab",
]
[[package]]
name = "fuzzy-matcher"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "54614a3312934d066701a80f20f15fa3b56d67ac7722b39eea5b4c9dd1d66c94"
dependencies = [
"thread_local",
]
[[package]]
name = "generator"
version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "605183a538e3e2a9c1038635cc5c2d194e2ee8fd0d1b66b8349fad7dbacce5a2"
dependencies = [
"cc",
"cfg-if",
"libc",
"log",
"rustversion",
"windows",
]
[[package]]
name = "generic-array"
version = "0.14.7"
@@ -2182,7 +2247,7 @@ dependencies = [
"js-sys",
"log",
"wasm-bindgen",
"windows-core",
"windows-core 0.62.2",
]
[[package]]
@@ -2694,6 +2759,19 @@ version = "0.4.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
[[package]]
name = "loom"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "419e0dc8046cb947daa77eb95ae174acfbddb7673b4151f56d1eed8e93fbfaca"
dependencies = [
"cfg-if",
"generator",
"scoped-tls",
"tracing",
"tracing-subscriber",
]
[[package]]
name = "lru"
version = "0.12.5"
@@ -2785,7 +2863,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7a7213d12e1864c0f002f52c2923d4556935a43dec5e71355c2760e0f6e7a18"
dependencies = [
"log",
"phf",
"phf 0.11.3",
"phf_codegen",
"string_cache",
"string_cache_codegen",
@@ -2803,6 +2881,15 @@ dependencies = [
"syn",
]
[[package]]
name = "matchers"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9"
dependencies = [
"regex-automata",
]
[[package]]
name = "matrix-pickle"
version = "0.2.2"
@@ -3064,6 +3151,46 @@ dependencies = [
"zeroize",
]
[[package]]
name = "matrix-sdk-ui"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f11354688a758f1b20b9d057553d76c288670d538aae824ac3eb63df07a8b380"
dependencies = [
"as_variant",
"async-rx",
"async-stream",
"async_cell",
"bitflags",
"chrono",
"emojis",
"eyeball",
"eyeball-im",
"eyeball-im-util",
"futures-core",
"futures-util",
"fuzzy-matcher",
"growable-bloom-filter",
"imbl",
"indexmap",
"itertools 0.14.0",
"matrix-sdk",
"matrix-sdk-base",
"matrix-sdk-common",
"mime",
"once_cell",
"pin-project-lite",
"ruma",
"serde",
"serde_json",
"thiserror 2.0.17",
"tokio",
"tokio-stream",
"tracing",
"unicode-normalization",
"unicode-segmentation",
]
[[package]]
name = "matrixgw_backend"
version = "0.1.0"
@@ -3089,6 +3216,7 @@ dependencies = [
"log",
"mailchecker",
"matrix-sdk",
"matrix-sdk-ui",
"mime_guess",
"ractor",
"rand 0.9.2",
@@ -3443,7 +3571,7 @@ dependencies = [
"libc",
"redox_syscall",
"smallvec",
"windows-link",
"windows-link 0.2.1",
]
[[package]]
@@ -3483,7 +3611,16 @@ version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078"
dependencies = [
"phf_shared",
"phf_shared 0.11.3",
]
[[package]]
name = "phf"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "913273894cec178f401a31ec4b656318d95473527be05c0752cc41cdc32be8b7"
dependencies = [
"phf_shared 0.12.1",
]
[[package]]
@@ -3493,7 +3630,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a"
dependencies = [
"phf_generator",
"phf_shared",
"phf_shared 0.11.3",
]
[[package]]
@@ -3502,7 +3639,7 @@ version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d"
dependencies = [
"phf_shared",
"phf_shared 0.11.3",
"rand 0.8.5",
]
@@ -3515,6 +3652,15 @@ dependencies = [
"siphasher",
]
[[package]]
name = "phf_shared"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06005508882fb681fd97892ecff4b7fd0fee13ef1aa569f8695dae7ab9099981"
dependencies = [
"siphasher",
]
[[package]]
name = "pin-project-lite"
version = "0.2.16"
@@ -4119,6 +4265,7 @@ dependencies = [
"percent-encoding",
"regex",
"ruma-common",
"ruma-html",
"ruma-identifiers-validation",
"ruma-macros",
"serde",
@@ -4355,6 +4502,12 @@ dependencies = [
"windows-sys 0.61.2",
]
[[package]]
name = "scoped-tls"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294"
[[package]]
name = "scopeguard"
version = "1.2.0"
@@ -4652,7 +4805,7 @@ checksum = "bf776ba3fa74f83bf4b63c3dcbbf82173db2632ed8452cb2d891d33f459de70f"
dependencies = [
"new_debug_unreachable",
"parking_lot",
"phf_shared",
"phf_shared 0.11.3",
"precomputed-hash",
"serde",
]
@@ -4664,7 +4817,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c711928715f1fe0fe509c53b43e993a9a557babc2d0a3567d0a3006f1ac931a0"
dependencies = [
"phf_generator",
"phf_shared",
"phf_shared 0.11.3",
"proc-macro2",
"quote",
]
@@ -5300,10 +5453,14 @@ version = "0.3.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e"
dependencies = [
"matchers",
"nu-ansi-term",
"once_cell",
"regex-automata",
"sharded-slab",
"smallvec",
"thread_local",
"tracing",
"tracing-core",
"tracing-log",
]
@@ -5667,6 +5824,41 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows"
version = "0.61.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893"
dependencies = [
"windows-collections",
"windows-core 0.61.2",
"windows-future",
"windows-link 0.1.3",
"windows-numerics",
]
[[package]]
name = "windows-collections"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8"
dependencies = [
"windows-core 0.61.2",
]
[[package]]
name = "windows-core"
version = "0.61.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3"
dependencies = [
"windows-implement",
"windows-interface",
"windows-link 0.1.3",
"windows-result 0.3.4",
"windows-strings 0.4.2",
]
[[package]]
name = "windows-core"
version = "0.62.2"
@@ -5675,9 +5867,20 @@ checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb"
dependencies = [
"windows-implement",
"windows-interface",
"windows-link",
"windows-result",
"windows-strings",
"windows-link 0.2.1",
"windows-result 0.4.1",
"windows-strings 0.5.1",
]
[[package]]
name = "windows-future"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e"
dependencies = [
"windows-core 0.61.2",
"windows-link 0.1.3",
"windows-threading",
]
[[package]]
@@ -5702,21 +5905,46 @@ dependencies = [
"syn",
]
[[package]]
name = "windows-link"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a"
[[package]]
name = "windows-link"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
[[package]]
name = "windows-numerics"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1"
dependencies = [
"windows-core 0.61.2",
"windows-link 0.1.3",
]
[[package]]
name = "windows-registry"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720"
dependencies = [
"windows-link",
"windows-result",
"windows-strings",
"windows-link 0.2.1",
"windows-result 0.4.1",
"windows-strings 0.5.1",
]
[[package]]
name = "windows-result"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6"
dependencies = [
"windows-link 0.1.3",
]
[[package]]
@@ -5725,7 +5953,16 @@ version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5"
dependencies = [
"windows-link",
"windows-link 0.2.1",
]
[[package]]
name = "windows-strings"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57"
dependencies = [
"windows-link 0.1.3",
]
[[package]]
@@ -5734,7 +5971,7 @@ version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091"
dependencies = [
"windows-link",
"windows-link 0.2.1",
]
[[package]]
@@ -5770,7 +6007,7 @@ version = "0.61.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
dependencies = [
"windows-link",
"windows-link 0.2.1",
]
[[package]]
@@ -5795,7 +6032,7 @@ version = "0.53.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3"
dependencies = [
"windows-link",
"windows-link 0.2.1",
"windows_aarch64_gnullvm 0.53.1",
"windows_aarch64_msvc 0.53.1",
"windows_i686_gnu 0.53.1",
@@ -5806,6 +6043,15 @@ dependencies = [
"windows_x86_64_msvc 0.53.1",
]
[[package]]
name = "windows-threading"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6"
dependencies = [
"windows-link 0.1.3",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.6"

View File

@@ -28,6 +28,7 @@ rand = "0.9.2"
hex = "0.4.3"
mailchecker = "6.0.19"
matrix-sdk = { version = "0.14.0" }
matrix-sdk-ui = "0.14.0"
url = "2.5.7"
ractor = "0.15.9"
serde_json = "1.0.145"

View File

@@ -0,0 +1,32 @@
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());
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))
}

View File

@@ -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;

View File

@@ -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",

View File

@@ -71,7 +71,6 @@
"integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/code-frame": "^7.27.1",
"@babel/generator": "^7.28.5",
@@ -421,7 +420,6 @@
"resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.14.0.tgz",
"integrity": "sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==",
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/runtime": "^7.18.3",
"@emotion/babel-plugin": "^11.13.5",
@@ -465,7 +463,6 @@
"resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.14.1.tgz",
"integrity": "sha512-qEEJt42DuToa3gurlH4Qqc1kVpNq8wO8cJtDzU46TjlzWjDlsVyevtYCRijVq3SrHsROS+gVQ8Fnea108GnKzw==",
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/runtime": "^7.18.3",
"@emotion/babel-plugin": "^11.13.5",
@@ -816,7 +813,6 @@
"resolved": "https://registry.npmjs.org/@mui/material/-/material-7.3.6.tgz",
"integrity": "sha512-R4DaYF3dgCQCUAkr4wW1w26GHXcf5rCmBRHVBuuvJvaGLmZdD8EjatP80Nz5JCw0KxORAzwftnHzXVnjR8HnFw==",
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/runtime": "^7.28.4",
"@mui/core-downloads-tracker": "^7.3.6",
@@ -927,7 +923,6 @@
"resolved": "https://registry.npmjs.org/@mui/system/-/system-7.3.6.tgz",
"integrity": "sha512-8fehAazkHNP1imMrdD2m2hbA9sl7Ur6jfuNweh5o4l9YPty4iaZzRXqYvBCWQNwFaSHmMEj2KPbyXGp7Bt73Rg==",
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/runtime": "^7.28.4",
"@mui/private-theming": "^7.3.6",
@@ -1505,7 +1500,6 @@
"integrity": "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"undici-types": "~7.16.0"
}
@@ -1527,7 +1521,6 @@
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.7.tgz",
"integrity": "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==",
"license": "MIT",
"peer": true,
"dependencies": {
"csstype": "^3.2.2"
}
@@ -1597,7 +1590,6 @@
"integrity": "sha512-PC0PDZfJg8sP7cmKe6L3QIL8GZwU5aRvUFedqSIpw3B+QjRSUZeeITC2M5XKeMXEzL6wccN196iy3JLwKNvDVA==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@typescript-eslint/scope-manager": "8.48.1",
"@typescript-eslint/types": "8.48.1",
@@ -1849,7 +1841,6 @@
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
"dev": true,
"license": "MIT",
"peer": true,
"bin": {
"acorn": "bin/acorn"
},
@@ -1970,7 +1961,6 @@
}
],
"license": "MIT",
"peer": true,
"dependencies": {
"baseline-browser-mapping": "^2.8.19",
"caniuse-lite": "^1.0.30001751",
@@ -2155,8 +2145,7 @@
"version": "1.11.19",
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.19.tgz",
"integrity": "sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==",
"license": "MIT",
"peer": true
"license": "MIT"
},
"node_modules/debug": {
"version": "4.4.3",
@@ -2261,7 +2250,6 @@
"integrity": "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.8.0",
"@eslint-community/regexpp": "^4.12.1",
@@ -3369,7 +3357,6 @@
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"dev": true,
"license": "MIT",
"peer": true,
"engines": {
"node": ">=12"
},
@@ -3457,7 +3444,6 @@
"resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz",
"integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">=0.10.0"
}
@@ -3467,7 +3453,6 @@
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz",
"integrity": "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"scheduler": "^0.27.0"
},
@@ -3795,7 +3780,6 @@
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
"dev": true,
"license": "Apache-2.0",
"peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@@ -3892,7 +3876,6 @@
"integrity": "sha512-v2ekZjuVLfumjp1Cr7LSQM1n2oOo3+gMruhOgT0Q4/cQ2J3nkTDLTAWLQQ86UHMbFYyVIN1wGh8BEZbvjkyctg==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@oxc-project/runtime": "0.101.0",
"fdir": "^6.5.0",
@@ -4015,7 +3998,6 @@
"integrity": "sha512-AvvthqfqrAhNH9dnfmrfKzX5upOdjUVJYFqNSlkmGf64gRaTzlPwz99IHYnVs28qYAybvAlBV+H7pn0saFY4Ig==",
"dev": true,
"license": "MIT",
"peer": true,
"funding": {
"url": "https://github.com/sponsors/colinhacks"
}

View 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;
}
}

View File

@@ -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,

View File

@@ -322,8 +322,15 @@ function RoomMessage(p: {
"&:hover *": { visibility: "visible" },
}}
>
<Typography variant="caption">
&nbsp; {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 */}

View File

@@ -31,8 +31,10 @@ export function RoomSelector(p: {
() =>
p.rooms
.filter((r) => !unread || r.number_unread_messages > 0)
.filter((r) =>
r.name?.toLocaleLowerCase()?.includes(filter.toLocaleLowerCase())
.filter(
(r) =>
filter === "" ||
r.name?.toLocaleLowerCase()?.includes(filter.toLocaleLowerCase())
),
[p.rooms, unread, filter]
);

View File

@@ -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