Revert most changes to Space.tsx

This commit is contained in:
Gimle Larpes 2025-06-27 12:38:13 +02:00 committed by GitHub
parent eaf70fb79a
commit efc77ceb44
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -26,7 +26,6 @@ import { useVirtualizer } from '@tanstack/react-virtual';
import { JoinRule, Room } from 'matrix-js-sdk';
import { RoomJoinRulesEventContent } from 'matrix-js-sdk/lib/types';
import FocusTrap from 'focus-trap-react';
import { logger } from 'matrix-js-sdk/lib/logger';
import { useMatrixClient } from '../../../hooks/useMatrixClient';
import { mDirectAtom } from '../../../state/mDirectList';
import {
@ -46,8 +45,7 @@ import {
import { useSpace } from '../../../hooks/useSpace';
import { VirtualTile } from '../../../components/virtualizer';
import { RoomNavCategoryButton, RoomNavItem } from '../../../features/room-nav';
// Using the original name for clarity when generating space category IDs
import { makeNavCategoryId as makeSpaceNavCategoryId } from '../../../state/closedNavCategories';
import { makeNavCategoryId } from '../../../state/closedNavCategories';
import { roomToUnreadAtom } from '../../../state/room/roomToUnread';
import { useCategoryHandler } from '../../../hooks/useCategoryHandler';
import { useNavToActivePathMapper } from '../../../hooks/useNavToActivePathMapper';
@ -79,118 +77,6 @@ import {
import { useOpenSpaceSettings } from '../../../state/hooks/spaceSettings';
import { useRoomNavigate } from '../../../hooks/useRoomNavigate';
import { CallNavStatus } from '../../../features/room-nav/RoomCallNavStatus';
import { getStateEvents } from '../../../utils/room';
import { RoomNavUser } from '../../../features/room-nav/RoomNavUser';
import { useStateEvents } from '../../../hooks/useStateEvents';
/**
* Processes the raw hierarchy from useSpaceJoinedHierarchy into a flat list
* suitable for the virtualizer, including collapsible headers for text/voice rooms.
* Removes the top-level "Rooms" category header.
*
* @param hierarchy - The raw hierarchy data (array of { roomId: string }).
* @param mx - The Matrix client instance.
* @param spaceRoomId - The ID of the root space being viewed.
* @param closedCategories - The Set of currently closed category IDs.
* @returns An array of processed items for rendering.
*/
const processHierarchyForVirtualizer = (
hierarchy: { roomId: string }[],
mx: ReturnType<typeof useMatrixClient>,
spaceRoomId: string,
closedCategories: Set<string>
): Array<{ type: string; key: string; [key: string]: any }> => {
const processed: Array<{ type: string; key: string; [key: string]: any }> = [];
let currentCategoryRooms = { text: [], voice: [], users: [] };
let currentParentId: string = spaceRoomId;
const addCollectedRoomsToProcessed = (parentId: string) => {
const textCategoryId = `${parentId}_text_rooms`;
const voiceCategoryId = `${parentId}_call_rooms`;
const isTextClosed = closedCategories.has(textCategoryId);
const isCallClosed = closedCategories.has(voiceCategoryId);
if (currentCategoryRooms.text.length > 0) {
processed.push({
type: 'room_header',
title: 'Text Rooms',
categoryId: textCategoryId,
key: `${parentId}-text-header`,
});
if (!isTextClosed) {
currentCategoryRooms.text.forEach((room) =>
processed.push({ type: 'room', room, key: room.roomId })
);
}
}
if (currentCategoryRooms.voice.length > 0) {
processed.push({
type: 'room_header',
title: 'Call Rooms',
categoryId: voiceCategoryId,
key: `${parentId}-voice-header`,
});
if (!isCallClosed) {
currentCategoryRooms.voice.forEach((room) => {
processed.push({ type: 'room', room, key: room.roomId });
currentCategoryRooms.users.forEach((entry) => {
if (entry.room.roomId === room.roomId) {
processed.push(entry);
}
});
});
}
}
currentCategoryRooms = { text: [], voice: [], users: [] };
};
hierarchy.forEach((item) => {
const room = mx.getRoom(item.roomId);
if (!room) {
logger.warn(`processHierarchyForVirtualizer: Room not found for ID ${item.roomId}`);
}
if (room.isSpaceRoom()) {
addCollectedRoomsToProcessed(currentParentId);
currentParentId = room.roomId;
if (room.roomId !== spaceRoomId) {
const spaceCategoryId = makeSpaceNavCategoryId(spaceRoomId, room.roomId);
processed.push({
type: 'category',
room,
categoryId: spaceCategoryId,
key: room.roomId,
});
}
} else if (room.isCallRoom()) {
currentCategoryRooms.voice.push(room);
getStateEvents(room, 'org.matrix.msc3401.call.member').forEach(({ event }) => {
if (Object.entries(event?.content).length !== 0) {
if (event.origin_server_ts + event.content.expires > Date.now()) {
currentCategoryRooms.users.push({
type: 'user',
sender: event.sender,
key: event.event_id,
room,
});
}
}
});
} else if (!room.isCallRoom()) {
currentCategoryRooms.text.push(room);
} else {
logger.warn(`processHierarchyForVirtualizer: Room ${room.roomId} is neither text nor voice.`);
currentCategoryRooms.text.push(room);
}
});
addCollectedRoomsToProcessed(currentParentId);
return processed;
};
type SpaceMenuProps = {
room: Room;
@ -203,7 +89,7 @@ const SpaceMenu = forwardRef<HTMLDivElement, SpaceMenuProps>(({ room, requestClo
const roomToParents = useAtomValue(roomToParentsAtom);
const powerLevels = usePowerLevels(room);
const { getPowerLevel, canDoAction } = usePowerLevelsAPI(powerLevels);
const canInvite = canDoAction('invite', mx.getUserId() ?? '');
const canInvite = canDoAction('invite', getPowerLevel(mx.getUserId() ?? ''));
const openSpaceSettings = useOpenSpaceSettings();
const { navigateRoom } = useRoomNavigate();
@ -354,6 +240,7 @@ function SpaceHeader() {
return cords;
});
};
return (
<>
<PageNavHeader>
@ -430,8 +317,7 @@ export function Space() {
getRoom,
useCallback(
(parentId, roomId) => {
const parentSpaceCategoryId = makeSpaceNavCategoryId(space.roomId, parentId);
if (!closedCategories.has(parentSpaceCategoryId)) {
if (!closedCategories.has(makeNavCategoryId(space.roomId, parentId))) {
return false;
}
const showRoomAnyway = roomToUnread.has(roomId) || roomId === selectedRoomId;
@ -439,31 +325,14 @@ export function Space() {
},
[space.roomId, closedCategories, roomToUnread, selectedRoomId]
),
useCallback(
(subCategoryId) => closedCategories.has(makeSpaceNavCategoryId(space.roomId, subCategoryId)),
(sId) => closedCategories.has(makeNavCategoryId(space.roomId, sId)),
[closedCategories, space.roomId]
)
);
const callRooms = useMemo(
() =>
hierarchy
.map((item) => mx.getRoom(item.roomId))
.filter((room): room is Room => !!room && room.isCallRoom()),
[hierarchy, mx]
);
const updateTrigger = useStateEvents(callRooms, StateEvent.GroupCallMemberPrefix);
const processedHierarchy = useMemo(
() => processHierarchyForVirtualizer(hierarchy, mx, space.roomId, closedCategories),
// eslint-disable-next-line react-hooks/exhaustive-deps
[hierarchy, mx, space.roomId, closedCategories, updateTrigger]
);
const virtualizer = useVirtualizer({
count: processedHierarchy.length,
count: hierarchy.length,
getScrollElement: () => scrollRef.current,
estimateSize: () => 32,
overscan: 10,
@ -477,12 +346,9 @@ export function Space() {
getSpaceRoomPath(spaceIdOrAlias, getCanonicalAliasOrRoomId(mx, roomId));
return (
<PageNav style={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
<PageNav>
<SpaceHeader />
<PageNavContent
scrollRef={scrollRef}
style={{ flexGrow: 1, overflowY: 'auto', overflowX: 'hidden' }}
>
<PageNavContent scrollRef={scrollRef}>
<Box direction="Column" gap="300">
<NavCategory>
<NavItem variant="Background" radii="400" aria-selected={lobbySelected}>
@ -518,91 +384,56 @@ export function Space() {
</NavLink>
</NavItem>
</NavCategory>
</Box>
<NavCategory
style={{
height: `${virtualizer.getTotalSize()}px`,
width: '100%',
position: 'relative',
}}
>
{virtualizer.getVirtualItems().map((vItem) => {
const item = processedHierarchy[vItem.index];
if (!item) return null;
const renderContent = () => {
switch (item.type) {
case 'category': {
const { room, categoryId } = item;
const { name } = room;
const paddingTop = config?.space?.S400 ?? '1rem';
return (
<div style={{ paddingTop }}>
<NavCategory
style={{
height: virtualizer.getTotalSize(),
position: 'relative',
}}
>
{virtualizer.getVirtualItems().map((vItem) => {
const { roomId } = hierarchy[vItem.index] ?? {};
const room = mx.getRoom(roomId);
if (!room) return null;
if (room.isSpaceRoom()) {
const categoryId = makeNavCategoryId(space.roomId, roomId);
return (
<VirtualTile
virtualItem={vItem}
key={vItem.index}
ref={virtualizer.measureElement}
>
<div style={{ paddingTop: vItem.index === 0 ? undefined : config.space.S400 }}>
<NavCategoryHeader>
<RoomNavCategoryButton
data-category-id={categoryId}
onClick={handleCategoryClick}
closed={closedCategories.has(categoryId)}
>
{name}
{roomId === space.roomId ? 'Rooms' : room?.name}
</RoomNavCategoryButton>
</NavCategoryHeader>
</div>
);
}
case 'room_header': {
const { title, categoryId } = item;
return (
<Box>
<NavCategoryHeader variant="Subtle">
<RoomNavCategoryButton
data-category-id={categoryId}
onClick={handleCategoryClick}
closed={closedCategories.has(categoryId)}
>
{title}
</RoomNavCategoryButton>
</NavCategoryHeader>
</Box>
);
}
case 'room': {
const { room } = item;
return (
<Box>
<RoomNavItem
room={room}
selected={selectedRoomId === room.roomId}
showAvatar={mDirects.has(room.roomId)}
direct={mDirects.has(room.roomId)}
linkPath={getToLink(room.roomId)}
notificationMode={getRoomNotificationMode(
notificationPreferences,
room.roomId
)}
/>
</Box>
);
}
case 'user': {
const { sender, room } = item;
return (
<Box style={{ paddingLeft: config.space.S200 }}>
<RoomNavUser room={room} space={space} sender={sender} />
</Box>
);
}
default:
return null;
</VirtualTile>
);
}
};
return (
<VirtualTile virtualItem={vItem} key={item.key} ref={virtualizer.measureElement}>
{renderContent()}
</VirtualTile>
);
})}
</NavCategory>
return (
<VirtualTile virtualItem={vItem} key={vItem.index} ref={virtualizer.measureElement}>
<RoomNavItem
room={room}
selected={selectedRoomId === roomId}
showAvatar={mDirects.has(roomId)}
direct={mDirects.has(roomId)}
linkPath={getToLink(roomId)}
notificationMode={getRoomNotificationMode(notificationPreferences, room.roomId)}
/>
</VirtualTile>
);
})}
</NavCategory>
</Box>
</PageNavContent>
<CallNavStatus />
</PageNav>