This commit is contained in:
@@ -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()
|
||||||
|
|||||||
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -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]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user