(visibleRooms, {
keys: ["name"],
funcs: [r => [r.getCanonicalAlias(), ...r.getAltAliases()].filter(Boolean)],
shouldMatchWordsOnly: false,
});
rooms = matcher.match(lcQuery);
}
const joinRule = space.getJoinRule();
return sortRooms(rooms).reduce((arr, room) => {
if (room.isSpaceRoom()) {
if (room !== space && !existingSubspacesSet.has(room)) {
arr[0].push(room);
}
} else if (!existingRoomsSet.has(room)) {
if (!DMRoomMap.shared().getUserIdForRoomId(room.roomId)) {
arr[1].push(room);
} else if (joinRule !== "public") {
// Only show DMs for non-public spaces as they make very little sense in spaces other than "Just Me" ones.
arr[2].push(room);
}
}
return arr;
}, [[], [], []]);
}, [visibleRooms, space, lcQuery, existingRoomsSet, existingSubspacesSet]);
const addRooms = async () => {
setError(null);
setProgress(0);
let error;
for (const room of selectedToAdd) {
const via = calculateRoomVia(room);
try {
await SpaceStore.instance.addRoomToSpace(space, room.roomId, via).catch(async e => {
if (e.errcode === "M_LIMIT_EXCEEDED") {
await sleep(e.data.retry_after_ms);
return SpaceStore.instance.addRoomToSpace(space, room.roomId, via); // retry
}
throw e;
});
setProgress(i => i + 1);
} catch (e) {
console.error("Failed to add rooms to space", e);
setError(error = e);
break;
}
}
if (!error) {
onFinished(true);
}
};
const busy = progress !== null;
let footer;
if (error) {
footer = <>
{ _t("Not all selected were added") }
{ _t("Try again") }
{ _t("Retry") }
>;
} else if (busy) {
footer =
{ _t("Adding rooms... (%(progress)s out of %(count)s)", {
count: selectedToAdd.size,
progress,
}) }
;
} else {
let button = emptySelectionButton;
if (!button || selectedToAdd.size > 0) {
button =
{ _t("Add") }
;
}
footer = <>
{ footerPrompt }
{ button }
>;
}
const onChange = !busy && !error ? (checked: boolean, room: Room) => {
if (checked) {
selectedToAdd.add(room);
} else {
selectedToAdd.delete(room);
}
setSelectedToAdd(new Set(selectedToAdd));
} : null;
const [truncateAt, setTruncateAt] = useState(20);
function overflowTile(overflowCount: number, totalCount: number): JSX.Element {
const text = _t("and %(count)s others...", { count: overflowCount });
return (
}
name={text}
presenceState="online"
suppressOnHover={true}
onClick={() => setTruncateAt(totalCount)}
/>
);
}
let noResults = true;
if ((roomsRenderer && rooms.length > 0) ||
(dmsRenderer && dms.length > 0) ||
(!roomsRenderer && !dmsRenderer && spacesRenderer && spaces.length > 0) // only count spaces when alone
) {
noResults = false;
}
return
{ rooms.length > 0 && roomsRenderer ? (
roomsRenderer(rooms, selectedToAdd, onChange, truncateAt, overflowTile)
) : undefined }
{ spaces.length > 0 && spacesRenderer ? (
spacesRenderer(spaces, selectedToAdd, onChange)
) : null }
{ dms.length > 0 && dmsRenderer ? (
dmsRenderer(dms, selectedToAdd, onChange)
) : null }
{ noResults ?
{ _t("No results") }
: undefined }
{ footer }
;
};
export const defaultRoomsRenderer: IAddExistingToSpaceProps["roomsRenderer"] = (
rooms, selectedToAdd, onChange, truncateAt, overflowTile,
) => (
{ _t("Rooms") }
rooms.slice(start, end).map(room =>
{
onChange(checked, room);
} : null}
/>,
)}
getChildCount={() => rooms.length}
/>
);
export const defaultSpacesRenderer: IAddExistingToSpaceProps["spacesRenderer"] = (spaces, selectedToAdd, onChange) => (
{ spaces.map(space => {
return {
onChange(checked, space);
} : null}
/>;
}) }
);
export const defaultDmsRenderer: IAddExistingToSpaceProps["dmsRenderer"] = (dms, selectedToAdd, onChange) => (
{ _t("Direct Messages") }
{ dms.map(room => {
return {
onChange(checked, room);
} : null}
/>;
}) }
);
interface ISubspaceSelectorProps {
title: string;
space: Room;
value: Room;
onChange(space: Room): void;
}
export const SubspaceSelector = ({ title, space, value, onChange }: ISubspaceSelectorProps) => {
const options = useMemo(() => {
return [space, ...SpaceStore.instance.getChildSpaces(space.roomId).filter(space => {
return space.currentState.maySendStateEvent(EventType.SpaceChild, space.client.credentials.userId);
})];
}, [space]);
let body;
if (options.length > 1) {
body = (
{
onChange(options.find(space => space.roomId === key) || space);
}}
value={value.roomId}
label={_t("Space selection")}
>
{ options.map((space) => {
const classes = classNames({
mx_SubspaceSelector_dropdownOptionActive: space === value,
});
return
{ space.name || getDisplayAliasForRoom(space) || space.roomId }
;
}) }
);
} else {
body = (
{ space.name || getDisplayAliasForRoom(space) || space.roomId }
);
}
return ;
};
const AddExistingToSpaceDialog: React.FC = ({ space, onCreateRoomClick, onAddSubspaceClick, onFinished }) => {
const [selectedSpace, setSelectedSpace] = useState(space);
return
)}
className="mx_AddExistingToSpaceDialog"
contentId="mx_AddExistingToSpace"
onFinished={onFinished}
fixedWidth={false}
>
{ _t("Want to add a new room instead?") }
{
onCreateRoomClick();
onFinished();
}}
>
{ _t("Create a new room") }
>}
filterPlaceholder={_t("Search for rooms")}
roomsRenderer={defaultRoomsRenderer}
spacesRenderer={() => (
{ _t("Spaces") }
{
onAddSubspaceClick();
onFinished();
}}
>
{ _t("Adding spaces has moved.") }
)}
dmsRenderer={defaultDmsRenderer}
/>
;
};
export default AddExistingToSpaceDialog;