Room list: drag and drop rooms into sections (#33366)
* chore: add dnd kit deps * chore: patch dnd kit to fix ts error * feat(sc): add drag-and-drop to room list item and wrapper * feat(sc): make the room list header a droppable element * feat(sc): add dnd to room list view * feat(tags): can tag room as CHAT * feat(vm): implement `changeRoomSection` * feat(sc): disable dragging in flat list * fix: disable keyboard navigation when dragging element * test(sc): update snapshots * test(sc): add dnd test * test(e2e): add e2e tests for room drag and drop * test(vm): add tests for changeRoomSection * fix: remove focus visible when dropping with the mouse * test(playwright): update existing screenshots * chore(sc): move numbers out of main build The Ew RecorderWorklet imports shared component bundle. However if the bundle uses some deps using document/window which, the worklet will not work. The solution is to put the used functions into a separate bundle. * doc(sc): add subpath import into README * doc: typo barrel/bundle * test: improve test expect * refactor: add utils to section tag * fix: incorrect check in tagRoom * fix: add doc about dndkit tunning
This commit is contained in:
@@ -38,8 +38,9 @@ import { Action } from "../../dispatcher/actions";
|
||||
import type { ViewRoomPayload } from "../../dispatcher/payloads/ViewRoomPayload";
|
||||
import PosthogTrackers from "../../PosthogTrackers";
|
||||
import { type Call, CallEvent } from "../../models/Call";
|
||||
import RoomListStoreV3, { CHATS_TAG } from "../../stores/room-list-v3/RoomListStoreV3";
|
||||
import RoomListStoreV3 from "../../stores/room-list-v3/RoomListStoreV3";
|
||||
import { _t } from "../../languageHandler";
|
||||
import { isDefaultSectionTag } from "../../stores/room-list-v3/section";
|
||||
|
||||
interface RoomItemProps {
|
||||
room: Room;
|
||||
@@ -429,9 +430,7 @@ export class RoomListItemViewModel
|
||||
RoomListStoreV3.instance.orderedSectionTags
|
||||
// Exclude the Chats because the user toggle the other sections to move rooms in and out of the Chats section.
|
||||
// Also exclude the default sections because they are available as toggles in the main context menu, and we don't want them to be duplicated in the "Move to section" submenu.
|
||||
.filter(
|
||||
(tag) => tag !== CHATS_TAG && tag !== DefaultTagID.Favourite && tag !== DefaultTagID.LowPriority,
|
||||
)
|
||||
.filter((tag) => !isDefaultSectionTag(tag))
|
||||
.map((tag) => ({
|
||||
tag,
|
||||
name: RoomListItemViewModel.getSectionName(tag, customSectionData),
|
||||
|
||||
@@ -16,8 +16,8 @@ import { RoomNotificationStateStore } from "../../stores/notifications/RoomNotif
|
||||
import { NotificationStateEvents } from "../../stores/notifications/NotificationState";
|
||||
import { type RoomNotificationState } from "../../stores/notifications/RoomNotificationState";
|
||||
import SettingsStore from "../../settings/SettingsStore";
|
||||
import { DefaultTagID } from "../../stores/room-list-v3/skip-list/tag";
|
||||
import RoomListStoreV3, { CHATS_TAG } from "../../stores/room-list-v3/RoomListStoreV3";
|
||||
import RoomListStoreV3 from "../../stores/room-list-v3/RoomListStoreV3";
|
||||
import { isDefaultSectionTag } from "../../stores/room-list-v3/section";
|
||||
|
||||
interface RoomListSectionHeaderViewModelProps {
|
||||
tag: string;
|
||||
@@ -45,8 +45,7 @@ export class RoomListSectionHeaderViewModel
|
||||
private readonly expandedBySpace = new Map<string, boolean>();
|
||||
|
||||
public constructor(props: RoomListSectionHeaderViewModelProps) {
|
||||
const isDefaultSection =
|
||||
props.tag === DefaultTagID.Favourite || props.tag === DefaultTagID.LowPriority || props.tag === CHATS_TAG;
|
||||
const isDefaultSection = isDefaultSectionTag(props.tag);
|
||||
super(props, {
|
||||
id: props.tag,
|
||||
title: props.title,
|
||||
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
_t,
|
||||
type ToastType,
|
||||
} from "@element-hq/web-shared-components";
|
||||
import { type MatrixClient, type Room } from "matrix-js-sdk/src/matrix";
|
||||
import { type Room, type MatrixClient } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import { Action } from "../../dispatcher/actions";
|
||||
import dispatcher from "../../dispatcher/dispatcher";
|
||||
@@ -24,7 +24,6 @@ import { type ViewRoomPayload } from "../../dispatcher/payloads/ViewRoomPayload"
|
||||
import { type RoomListSectionsCollapseStateChangedPayload } from "../../dispatcher/payloads/RoomListSectionsCollapseStateChangedPayload";
|
||||
import SpaceStore from "../../stores/spaces/SpaceStore";
|
||||
import RoomListStoreV3, {
|
||||
CHATS_TAG,
|
||||
RoomListStoreV3Event,
|
||||
type RoomsResult,
|
||||
type Section,
|
||||
@@ -38,6 +37,9 @@ import { keepIfSame } from "../../utils/keepIfSame";
|
||||
import { DefaultTagID } from "../../stores/room-list-v3/skip-list/tag";
|
||||
import { RoomListSectionHeaderViewModel } from "./RoomListSectionHeaderViewModel";
|
||||
import SettingsStore from "../../settings/SettingsStore";
|
||||
import { tagRoom } from "../../utils/room/tagRoom";
|
||||
import { getSectionTagForRoom } from "../../utils/room/getSectionTagForRoom";
|
||||
import { CHATS_TAG } from "../../stores/room-list-v3/section";
|
||||
|
||||
/**
|
||||
* Tracks the position of the active room within a specific section.
|
||||
@@ -667,6 +669,17 @@ export class RoomListViewModel
|
||||
this.closeToast();
|
||||
}, 15 * 1000);
|
||||
}
|
||||
|
||||
public changeRoomSection = (roomId: string, tag: string): void => {
|
||||
const room = this.props.client.getRoom(roomId);
|
||||
if (!room) return;
|
||||
|
||||
const currentTag = getSectionTagForRoom(room);
|
||||
// Room is already in the section
|
||||
if (currentTag === tag) return;
|
||||
|
||||
tagRoom(room, tag);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user