Fix spaces support in UI
Some checks failed
continuous-integration/drone/push Build is failing

This commit is contained in:
2025-12-04 15:35:16 +01:00
parent 5ad23005be
commit 0f68d59798
4 changed files with 62 additions and 6 deletions

View File

@@ -7,11 +7,11 @@ use std::collections::HashMap;
/// Get space hierarchy /// Get space hierarchy
pub async fn hierarchy(client: MatrixClientExtractor) -> HttpResult { pub async fn hierarchy(client: MatrixClientExtractor) -> HttpResult {
let spaces = client.client.client.joined_space_rooms();
let space_service = SpaceService::new(client.client.client); let space_service = SpaceService::new(client.client.client);
let spaces = space_service.joined_spaces().await;
let mut hierarchy = HashMap::new(); let mut hierarchy = HashMap::new();
for space in spaces { for space in spaces {
let rooms = space_service.space_room_list(space.room_id.to_owned()); let rooms = space_service.space_room_list(space.room_id().to_owned());
while !matches!( while !matches!(
rooms.pagination_state(), rooms.pagination_state(),
SpaceRoomListPaginationState::Idle { end_reached: true } SpaceRoomListPaginationState::Idle { end_reached: true }
@@ -20,7 +20,7 @@ pub async fn hierarchy(client: MatrixClientExtractor) -> HttpResult {
} }
hierarchy.insert( hierarchy.insert(
space.room_id.to_owned(), space.room_id().to_owned(),
rooms rooms
.rooms() .rooms()
.into_iter() .into_iter()

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, type UsersMap,
} from "../../api/matrix/MatrixApiProfile"; } from "../../api/matrix/MatrixApiProfile";
import { MatrixApiRoom, type Room } from "../../api/matrix/MatrixApiRoom"; import { MatrixApiRoom, type Room } from "../../api/matrix/MatrixApiRoom";
import {
MatrixApiSpace,
type SpaceHierarchy,
} from "../../api/matrix/MatrixApiSpace";
import { MatrixSyncApi } from "../../api/MatrixSyncApi"; import { MatrixSyncApi } from "../../api/MatrixSyncApi";
import type { WsMessage } from "../../api/WsApi"; import type { WsMessage } from "../../api/WsApi";
import { RoomEventsManager } from "../../utils/RoomEventsManager"; import { RoomEventsManager } from "../../utils/RoomEventsManager";
@@ -19,13 +23,19 @@ import { SpaceSelector } from "./SpaceSelector";
export function MainMessageWidget(): React.ReactElement { export function MainMessageWidget(): React.ReactElement {
const [rooms, setRooms] = React.useState<Room[] | undefined>(); const [rooms, setRooms] = React.useState<Room[] | undefined>();
const [hierarchy, setHierarchy] = React.useState<
SpaceHierarchy | undefined
>();
const [users, setUsers] = React.useState<UsersMap | undefined>(); const [users, setUsers] = React.useState<UsersMap | undefined>();
const loadRoomsList = async () => { const loadRoomsList = async () => {
await MatrixSyncApi.Start(); await MatrixSyncApi.Start();
const rooms = await MatrixApiRoom.ListJoined(); const rooms = await MatrixApiRoom.ListJoined();
const hierarchy = await MatrixApiSpace.Hierarchy();
setRooms(rooms); setRooms(rooms);
setHierarchy(hierarchy);
// Get the list of users in rooms // Get the list of users in rooms
const users = rooms.reduce((prev, r) => { const users = rooms.reduce((prev, r) => {
@@ -40,11 +50,12 @@ export function MainMessageWidget(): React.ReactElement {
<AsyncWidget <AsyncWidget
loadKey={1} loadKey={1}
load={loadRoomsList} load={loadRoomsList}
ready={!!rooms && !!users} ready={!!rooms && !!users && !!hierarchy}
errMsg="Failed to initialize messaging component!" errMsg="Failed to initialize messaging component!"
build={() => ( build={() => (
<MainMessageWidgetInner <MainMessageWidgetInner
rooms={rooms!} rooms={rooms!}
hierarchy={hierarchy!}
users={users!} users={users!}
onRoomsListUpdate={(cb) => setRooms((r) => cb(r!))} onRoomsListUpdate={(cb) => setRooms((r) => cb(r!))}
/> />
@@ -55,6 +66,7 @@ export function MainMessageWidget(): React.ReactElement {
function MainMessageWidgetInner(p: { function MainMessageWidgetInner(p: {
rooms: Room[]; rooms: Room[];
hierarchy: SpaceHierarchy;
users: UsersMap; users: UsersMap;
onRoomsListUpdate: (cb: (a: Room[]) => Room[]) => void; onRoomsListUpdate: (cb: (a: Room[]) => Room[]) => void;
}): React.ReactElement { }): React.ReactElement {
@@ -65,7 +77,9 @@ function MainMessageWidgetInner(p: {
const spaceRooms = React.useMemo(() => { const spaceRooms = React.useMemo(() => {
return p.rooms 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( .sort(
(a, b) => (b.latest_event?.time ?? 0) - (a.latest_event?.time ?? 0) (a, b) => (b.latest_event?.time ?? 0) - (a.latest_event?.time ?? 0)
); );

View File

@@ -3,16 +3,18 @@ import { Button } from "@mui/material";
import React from "react"; import React from "react";
import type { UsersMap } from "../../api/matrix/MatrixApiProfile"; import type { UsersMap } from "../../api/matrix/MatrixApiProfile";
import type { Room } from "../../api/matrix/MatrixApiRoom"; import type { Room } from "../../api/matrix/MatrixApiRoom";
import type { SpaceHierarchy } from "../../api/matrix/MatrixApiSpace";
import { RoomIcon } from "./RoomIcon"; import { RoomIcon } from "./RoomIcon";
export function SpaceSelector(p: { export function SpaceSelector(p: {
rooms: Room[]; rooms: Room[];
hierarchy: SpaceHierarchy;
users: UsersMap; users: UsersMap;
selectedSpace?: string; selectedSpace?: string;
onChange: (space?: string) => void; onChange: (space?: string) => void;
}): React.ReactElement { }): React.ReactElement {
const spaces = React.useMemo( const spaces = React.useMemo(
() => p.rooms.filter((r) => r.is_space), () => p.rooms.filter((r) => r.is_space && p.hierarchy.has(r.id)),
[p.rooms] [p.rooms]
); );