Media row: a joined file-zone room (by type or fileZoneRooms) is the row; alias or carried id only finds an unjoined one
Some checks failed
Build pull request / Build pull request (pull_request) Has been cancelled

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Void 2026-11-11 17:12:57 +00:00
commit d226ca45fb
4 changed files with 63 additions and 4 deletions

View file

@ -195,7 +195,7 @@ function MindMedia({ media }: { media: MediaRowState }) {
}
function GroupSection({ tierId, group }: { tierId: string; group: EstateGroup }) {
const media = useMindMedia(group.mind);
const media = useMindMedia(group.mind, group.rooms);
const hasMedia = MINDS.includes(group.mind);
// The media room is the Media row; it is not listed a second time among the Mind's rooms.
const rooms =

View file

@ -4,6 +4,9 @@ import { useAtomValue } from 'jotai';
import { Avatar, Box, Icon, Icons, Text } from 'folds';
import { NavGutter, NavItem, NavItemContent, NavLink } from '../../components/nav';
import { NAV_ROOM_ICON_REST_OPACITY, NavLabel } from '../../components/nav/styles.css';
import { EstateRoom } from './buildEstate';
import { isFileZone } from '../albums/isFileZone';
import { useClientConfig } from '../../hooks/useClientConfig';
import { MINDS } from '../../components/message/pose/poses';
import { useMatrixClient } from '../../hooks/useMatrixClient';
import { allRoomsAtom } from '../../state/room-list/roomList';
@ -15,6 +18,7 @@ import {
lookupMediaRoom,
mediaRoomIdFromStewardships,
mediaRow,
typedMediaRoom,
} from './mediaRoom';
const mediaIcon = (
@ -58,12 +62,31 @@ export function MediaLink({ to }: { to: string }) {
}
/** The Mind's media room as the navigator sees it right now. */
export const useMindMedia = (mind: string): MediaRowState => {
export const useMindMedia = (mind: string, rooms: readonly EstateRoom[]): MediaRowState => {
const mx = useMatrixClient();
const { rootId } = useEstateRootId();
const joined = useAtomValue(allRoomsAtom);
const invited = useAtomValue(allInvitesAtom);
const config = useClientConfig();
const server = mx.getDomain() ?? '';
// A joined room whose type says it is a file zone is the Media row; the alias or carried id only finds a
// room the client cannot type yet (not joined).
const typed = typedMediaRoom(rooms, (roomId) => {
const room = mx.getRoom(roomId);
return (
!!room &&
isFileZone(
{
roomId,
aliases: [room.getCanonicalAlias(), ...room.getAltAliases()].filter(
(a): a is string => !!a
),
createType: room.currentState.getStateEvents('m.room.create', '')?.getContent().type,
},
config
)
);
});
const carried = mediaRoomIdFromStewardships(
rootId
? mx.getRoom(rootId)?.currentState.getStateEvents(STEWARDSHIPS_KEY, '')?.getContent()
@ -74,10 +97,11 @@ export const useMindMedia = (mind: string): MediaRowState => {
queryKey: ['mind-media', mind, server, carried],
queryFn: () => lookupMediaRoom(mx, mind, server, carried),
staleTime: 60_000,
enabled: MINDS.includes(mind),
enabled: MINDS.includes(mind) && !typed,
});
const membership = new Map<string, 'join' | 'invite'>();
invited.forEach((id) => membership.set(id, 'invite'));
joined.forEach((id) => membership.set(id, 'join'));
if (typed) return { kind: 'room', room: { ...typed, name: 'Media' } };
return mediaRow(lookup.data, membership);
};

View file

@ -1,5 +1,11 @@
import { describe, expect, it } from 'vitest';
import { lookupMediaRoom, mediaAlias, mediaRoomIdFromStewardships, mediaRow } from './mediaRoom';
import {
lookupMediaRoom,
mediaAlias,
mediaRoomIdFromStewardships,
mediaRow,
typedMediaRoom,
} from './mediaRoom';
const notFound = Object.assign(new Error('Room alias not found'), {
httpStatus: 404,
@ -90,4 +96,23 @@ describe('the Media row of a Mind', () => {
expect(mediaRow(undefined, new Map())).toEqual({ kind: 'checking' });
expect(mediaRow({ found: false, reason: 'unset' }, new Map())).toEqual({ kind: 'unset' });
});
it('takes the joined room whose type says file zone, whatever its alias, before any alias lookup', () => {
const room = (roomId: string, state: 'joined' | 'joinable') => ({
roomId,
name: roomId,
state,
via: [],
parentId: null,
direct: false,
});
const rooms = [
room('!chat', 'joined'),
room('!old-files-slug', 'joined'),
room('!unjoined', 'joinable'),
];
const zones = new Set(['!old-files-slug', '!unjoined']);
expect(typedMediaRoom(rooms, (id) => zones.has(id))?.roomId).toBe('!old-files-slug');
expect(typedMediaRoom(rooms, () => false)).toBeUndefined();
});
});

View file

@ -19,6 +19,16 @@ export const mediaRoomIdFromStewardships = (content: unknown, mind: string): str
return typeof id === 'string' && id.startsWith('!') ? id : undefined;
};
/**
* The Mind's media room among the rooms the client already knows: the first one whose room type (or the
* fileZoneRooms config) says it is a file zone. The type is the authority; the alias is only how an unknown
* room is found, below.
*/
export const typedMediaRoom = (
rooms: readonly EstateRoom[],
isZone: (roomId: string) => boolean
): EstateRoom | undefined => rooms.find((r) => r.state === 'joined' && isZone(r.roomId));
type MediaClient = {
getRoomIdForAlias(alias: string): Promise<{ room_id: string; servers?: string[] }>;
};