Room list: add new settings to enable/disable the sections (#34151)
* Add new settings to enable/disable the sections * Add `RoomList.showSections` settings to preference user settings * Hide sections ui in room list header - Hide the collapse/expand button and the *new section* entry in the menu. - Display the *start chat* button instead of the compose menu when the only action available is to create a DM * Hide sections ui in context menu of room item * Listen to show section settings in room list item vm * Listen to show sections setting in room list header vm * Put all the rooms inside the chat section when sections are disabled When the chat section is the only section, the room list is in "flat list mode". Putting all the rooms inside the chat section. The section filters (aka custom section, favourites etc) are not passed to the skip list. * Update preferences settings screenshot * Add e2e test for RoomList.showSections toggle * Hide "Chat moved" toast when a room is tagged when RoomList.showSections is disabled
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
import { rejectToast } from "@element-hq/element-web-playwright-common";
|
||||
|
||||
import { expect, test } from "../../../element-web-test";
|
||||
import { SettingLevel } from "../../../../src/settings/SettingLevel";
|
||||
import { assertRoomInSection, dragRoomToSection, getPrimaryFilters, getRoomList, getSectionHeader } from "./utils";
|
||||
|
||||
test.describe("Room list sections", () => {
|
||||
@@ -89,6 +90,45 @@ test.describe("Room list sections", () => {
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Show sections setting", () => {
|
||||
test.beforeEach(async ({ app }) => {
|
||||
// A favourite room and a regular room so that, when sections are enabled, we get
|
||||
// two meaningful sections (Favourites + Chats).
|
||||
const favouriteId = await app.client.createRoom({ name: "favourite room" });
|
||||
await app.client.evaluate(async (client, roomId) => {
|
||||
await client.setRoomTag(roomId, "m.favourite");
|
||||
}, favouriteId);
|
||||
await app.client.createRoom({ name: "regular room" });
|
||||
});
|
||||
|
||||
test("toggling RoomList.showSections switches between a sectioned and a flat list", async ({ page, app }) => {
|
||||
const roomList = getRoomList(page);
|
||||
|
||||
// Sections are enabled by default: section headers are visible and rooms render as treegrid rows.
|
||||
await expect(getSectionHeader(page, "Favourites")).toBeVisible();
|
||||
await expect(getSectionHeader(page, "Chats")).toBeVisible();
|
||||
await expect(roomList.getByRole("row", { name: "Open room favourite room" })).toBeVisible();
|
||||
|
||||
// Disable sections
|
||||
await app.settings.setValue("RoomList.showSections", null, SettingLevel.ACCOUNT, false);
|
||||
|
||||
// The list becomes flat: no section headers, rooms render as listbox options.
|
||||
await expect(getSectionHeader(page, "Favourites")).not.toBeVisible();
|
||||
await expect(getSectionHeader(page, "Chats")).not.toBeVisible();
|
||||
await expect(page.getByRole("listbox", { name: "Room list", exact: true })).toBeVisible();
|
||||
await expect(roomList.getByRole("option", { name: "Open room favourite room" })).toBeVisible();
|
||||
await expect(roomList.getByRole("option", { name: "Open room regular room" })).toBeVisible();
|
||||
|
||||
// Re-enable sections
|
||||
await app.settings.setValue("RoomList.showSections", null, SettingLevel.ACCOUNT, true);
|
||||
|
||||
// The sections reappear.
|
||||
await expect(getSectionHeader(page, "Favourites")).toBeVisible();
|
||||
await expect(getSectionHeader(page, "Chats")).toBeVisible();
|
||||
await expect(roomList.getByRole("row", { name: "Open room favourite room" })).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Section collapse and expand", () => {
|
||||
[
|
||||
{ section: "Favourites", roomName: "favourite room", tag: "m.favourite" },
|
||||
|
||||
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 268 KiB After Width: | Height: | Size: 271 KiB |
@@ -272,6 +272,7 @@ export default class PreferencesUserSettingsTab extends React.Component<EmptyObj
|
||||
|
||||
<SettingsSubsection heading={_t("settings|preferences|room_list_heading")} formWrap>
|
||||
<SettingsFlag name="RoomList.showMessagePreview" level={SettingLevel.DEVICE} />
|
||||
<SettingsFlag name="RoomList.showSections" level={SettingLevel.ACCOUNT} />
|
||||
</SettingsSubsection>
|
||||
|
||||
<SettingsSubsection heading={_t("common|spaces")} formWrap>
|
||||
|
||||
@@ -2958,6 +2958,7 @@
|
||||
"show_nsfw_content": "Show NSFW content",
|
||||
"show_read_receipts": "Show read receipts sent by other users",
|
||||
"show_redaction_placeholder": "Show a placeholder for removed messages",
|
||||
"show_sections": "Show sections",
|
||||
"show_stickers_button": "Show stickers button",
|
||||
"show_typing_notifications": "Show typing notifications",
|
||||
"showbold": "Show all activity in the room list (dots or number of unread messages)",
|
||||
|
||||
@@ -366,6 +366,7 @@ export interface Settings {
|
||||
"Developer.elementCallUrl": IBaseSetting<string>;
|
||||
"RoomList.CustomSectionData": IBaseSetting<CustomSectionsData>;
|
||||
"RoomList.OrderedCustomSections": IBaseSetting<ReorderableSection[]>;
|
||||
"RoomList.showSections": IBaseSetting<boolean>;
|
||||
}
|
||||
|
||||
export type SettingKey = keyof Settings;
|
||||
@@ -1225,6 +1226,11 @@ export const SETTINGS: Settings = {
|
||||
default: false,
|
||||
displayName: _td("settings|show_message_previews"),
|
||||
},
|
||||
"RoomList.showSections": {
|
||||
supportedLevels: LEVELS_ACCOUNT_SETTINGS,
|
||||
default: true,
|
||||
displayName: _td("settings|show_sections"),
|
||||
},
|
||||
"RightPanel.phasesGlobal": {
|
||||
supportedLevels: [SettingLevel.DEVICE],
|
||||
default: null,
|
||||
|
||||
@@ -137,6 +137,8 @@ export class RoomListStoreV3Class extends AsyncStoreWithClient<EmptyObject> {
|
||||
SpaceStore.instance.on(UPDATE_HOME_BEHAVIOUR, () => this.onActiveSpaceChanged());
|
||||
SettingsStore.watchSetting("RoomList.OrderedCustomSections", null, () => this.onOrderedCustomSectionsChange());
|
||||
this.loadCustomSections();
|
||||
|
||||
SettingsStore.watchSetting("RoomList.showSections", null, () => this.scheduleEmit());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -172,8 +174,11 @@ export class RoomListStoreV3Class extends AsyncStoreWithClient<EmptyObject> {
|
||||
*/
|
||||
public getSortedRoomsInActiveSpace(filterKeys?: FilterKey[]): RoomsResult {
|
||||
const spaceId = SpaceStore.instance.activeSpace;
|
||||
const areSectionsEnabled = SettingsStore.getValue("RoomList.showSections");
|
||||
|
||||
const sections = this.getSections(filterKeys);
|
||||
const sections = areSectionsEnabled
|
||||
? this.getSections(filterKeys)
|
||||
: [{ tag: CHATS_TAG, rooms: Array.from(this.roomSkipList?.getRoomsInActiveSpace(filterKeys) ?? []) }];
|
||||
|
||||
return {
|
||||
spaceId: spaceId,
|
||||
|
||||
@@ -70,6 +70,13 @@ export class RoomListHeaderViewModel
|
||||
);
|
||||
this.disposables.track(() => SettingsStore.unwatchSetting(settingsFeatureVideoRef));
|
||||
|
||||
const settingsShowSectionsRef = SettingsStore.watchSetting(
|
||||
"RoomList.showSections",
|
||||
null,
|
||||
this.onShowSectionsChange,
|
||||
);
|
||||
this.disposables.track(() => SettingsStore.unwatchSetting(settingsShowSectionsRef));
|
||||
|
||||
// Listen for space changes
|
||||
this.disposables.trackListener(props.spaceStore, UPDATE_SELECTED_SPACE, this.onSpaceChange);
|
||||
this.disposables.trackListener(props.spaceStore, UPDATE_HOME_BEHAVIOUR, this.onHomeBehaviourChange);
|
||||
@@ -133,6 +140,15 @@ export class RoomListHeaderViewModel
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles show sections setting change events.
|
||||
*/
|
||||
private readonly onShowSectionsChange = (): void => {
|
||||
this.snapshot.merge({
|
||||
areSectionsEnabled: SettingsStore.getValue("RoomList.showSections"),
|
||||
});
|
||||
};
|
||||
|
||||
public createChatRoom = (e: Event): void => {
|
||||
defaultDispatcher.fire(Action.CreateChat);
|
||||
PosthogTrackers.trackInteraction("WebRoomListHeaderPlusMenuCreateChatItem", e);
|
||||
@@ -310,6 +326,7 @@ function computeHeaderSpaceState(
|
||||
): Omit<RoomListHeaderViewSnapshot, "activeSortOption" | "isMessagePreviewEnabled"> {
|
||||
const displaySectionReleaseAnnouncement =
|
||||
ReleaseAnnouncementStore.instance.getReleaseAnnouncement() === "room_list_section";
|
||||
const areSectionsEnabled = SettingsStore.getValue("RoomList.showSections");
|
||||
|
||||
const activeSpace = spaceStore.activeSpaceRoom;
|
||||
const title = getHeaderTitle(spaceStore);
|
||||
@@ -330,5 +347,6 @@ function computeHeaderSpaceState(
|
||||
canInviteInSpace,
|
||||
canAccessSpaceSettings,
|
||||
displaySectionReleaseAnnouncement,
|
||||
areSectionsEnabled,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -110,6 +110,14 @@ export class RoomListItemViewModel
|
||||
SettingsStore.unwatchSetting(settingsWatchRef);
|
||||
});
|
||||
|
||||
// Subscribe to settings changes for section toggle
|
||||
const settingsShowSectionsRef = SettingsStore.watchSetting(
|
||||
"RoomList.showSections",
|
||||
null,
|
||||
this.onShowSectionsChange,
|
||||
);
|
||||
this.disposables.track(() => SettingsStore.unwatchSetting(settingsShowSectionsRef));
|
||||
|
||||
// Subscribe to call state changes
|
||||
this.disposables.trackListener(CallStore.instance, CallStoreEvent.Call, this.onCallStateChanged);
|
||||
// If there is an active call for this room, listen to participant changes
|
||||
@@ -153,6 +161,11 @@ export class RoomListItemViewModel
|
||||
void this.loadAndSetMessagePreview();
|
||||
};
|
||||
|
||||
private readonly onShowSectionsChange = (): void => {
|
||||
const areSectionsEnabled = SettingsStore.getValue("RoomList.showSections");
|
||||
this.snapshot.merge({ areSectionsEnabled });
|
||||
};
|
||||
|
||||
/**
|
||||
* Handler for call participant changes. Only updates the item if the call moves between having participants and not having participants, to avoid unnecessary updates.
|
||||
* @param participants The current call participants
|
||||
@@ -321,6 +334,7 @@ export class RoomListItemViewModel
|
||||
|
||||
// Build sections list for the "Move to section" submenu
|
||||
const sections: Section[] = RoomListItemViewModel.buildSections(roomTags, availableSections);
|
||||
const areSectionsEnabled = SettingsStore.getValue("RoomList.showSections");
|
||||
|
||||
return {
|
||||
id: room.roomId,
|
||||
@@ -350,6 +364,7 @@ export class RoomListItemViewModel
|
||||
canMarkAsUnread,
|
||||
roomNotifState,
|
||||
sections,
|
||||
areSectionsEnabled,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@ import { RoomListSectionHeaderViewModel } from "./RoomListSectionHeaderViewModel
|
||||
import { getCustomSectionData, isCustomSectionTag, CHATS_TAG } from "../../stores/room-list-v3/section";
|
||||
import { tagRoom } from "../../utils/room/tagRoom";
|
||||
import { getSectionTagForRoom } from "../../utils/room/getSectionTagForRoom";
|
||||
import SettingsStore from "../../settings/SettingsStore";
|
||||
|
||||
/**
|
||||
* Tracks the position of the active room within a specific section.
|
||||
@@ -799,6 +800,10 @@ export class RoomListViewModel
|
||||
};
|
||||
|
||||
public onRoomTagged = (): void => {
|
||||
const areSectionsEnabled = SettingsStore.getValue("RoomList.showSections");
|
||||
// Only show the "chat moved" toast if sections are enabled
|
||||
if (!areSectionsEnabled) return;
|
||||
|
||||
this.showToast("chat_moved");
|
||||
};
|
||||
|
||||
|
||||
+185
-152
@@ -117,6 +117,39 @@ exports[`PreferencesUserSettingsTab should render 1`] = `
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="_inline-field_1o4d9_33"
|
||||
>
|
||||
<div
|
||||
class="_inline-field-control_1o4d9_45"
|
||||
>
|
||||
<div
|
||||
class="_container_udcm8_10"
|
||||
>
|
||||
<input
|
||||
checked=""
|
||||
class="_input_udcm8_24"
|
||||
disabled=""
|
||||
id="mx_SettingsFlag_QgU2PomxwKpa"
|
||||
role="switch"
|
||||
type="checkbox"
|
||||
/>
|
||||
<div
|
||||
class="_ui_udcm8_34"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="_inline-field-body_1o4d9_39"
|
||||
>
|
||||
<label
|
||||
class="_label_1o4d9_60"
|
||||
for="mx_SettingsFlag_QgU2PomxwKpa"
|
||||
>
|
||||
Show sections
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
@@ -150,7 +183,7 @@ exports[`PreferencesUserSettingsTab should render 1`] = `
|
||||
<input
|
||||
class="_input_udcm8_24"
|
||||
disabled=""
|
||||
id="mx_SettingsFlag_QgU2PomxwKpa"
|
||||
id="mx_SettingsFlag_6hpi3YEetmBG"
|
||||
role="switch"
|
||||
type="checkbox"
|
||||
/>
|
||||
@@ -164,7 +197,7 @@ exports[`PreferencesUserSettingsTab should render 1`] = `
|
||||
>
|
||||
<label
|
||||
class="_label_1o4d9_60"
|
||||
for="mx_SettingsFlag_QgU2PomxwKpa"
|
||||
for="mx_SettingsFlag_6hpi3YEetmBG"
|
||||
>
|
||||
Show all rooms in Home
|
||||
</label>
|
||||
@@ -228,7 +261,7 @@ exports[`PreferencesUserSettingsTab should render 1`] = `
|
||||
<input
|
||||
class="_input_udcm8_24"
|
||||
disabled=""
|
||||
id="mx_SettingsFlag_6hpi3YEetmBG"
|
||||
id="mx_SettingsFlag_4yVCeEefiPqp"
|
||||
role="switch"
|
||||
type="checkbox"
|
||||
/>
|
||||
@@ -242,7 +275,7 @@ exports[`PreferencesUserSettingsTab should render 1`] = `
|
||||
>
|
||||
<label
|
||||
class="_label_1o4d9_60"
|
||||
for="mx_SettingsFlag_6hpi3YEetmBG"
|
||||
for="mx_SettingsFlag_4yVCeEefiPqp"
|
||||
>
|
||||
Use Ctrl + F to search timeline
|
||||
</label>
|
||||
@@ -307,38 +340,6 @@ exports[`PreferencesUserSettingsTab should render 1`] = `
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="_inline-field_1o4d9_33"
|
||||
>
|
||||
<div
|
||||
class="_inline-field-control_1o4d9_45"
|
||||
>
|
||||
<div
|
||||
class="_container_udcm8_10"
|
||||
>
|
||||
<input
|
||||
class="_input_udcm8_24"
|
||||
disabled=""
|
||||
id="mx_SettingsFlag_4yVCeEefiPqp"
|
||||
role="switch"
|
||||
type="checkbox"
|
||||
/>
|
||||
<div
|
||||
class="_ui_udcm8_34"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="_inline-field-body_1o4d9_39"
|
||||
>
|
||||
<label
|
||||
class="_label_1o4d9_60"
|
||||
for="mx_SettingsFlag_4yVCeEefiPqp"
|
||||
>
|
||||
Show timestamps in 12 hour format (e.g. 2:30pm)
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="_inline-field_1o4d9_33"
|
||||
>
|
||||
@@ -367,7 +368,7 @@ exports[`PreferencesUserSettingsTab should render 1`] = `
|
||||
class="_label_1o4d9_60"
|
||||
for="mx_SettingsFlag_MRMwbPDmfGtm"
|
||||
>
|
||||
Always show message timestamps
|
||||
Show timestamps in 12 hour format (e.g. 2:30pm)
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
@@ -398,6 +399,38 @@ exports[`PreferencesUserSettingsTab should render 1`] = `
|
||||
<label
|
||||
class="_label_1o4d9_60"
|
||||
for="mx_SettingsFlag_GQvdMWe954DV"
|
||||
>
|
||||
Always show message timestamps
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="_inline-field_1o4d9_33"
|
||||
>
|
||||
<div
|
||||
class="_inline-field-control_1o4d9_45"
|
||||
>
|
||||
<div
|
||||
class="_container_udcm8_10"
|
||||
>
|
||||
<input
|
||||
class="_input_udcm8_24"
|
||||
disabled=""
|
||||
id="mx_SettingsFlag_IAu5CsiHRD7n"
|
||||
role="switch"
|
||||
type="checkbox"
|
||||
/>
|
||||
<div
|
||||
class="_ui_udcm8_34"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="_inline-field-body_1o4d9_39"
|
||||
>
|
||||
<label
|
||||
class="_label_1o4d9_60"
|
||||
for="mx_SettingsFlag_IAu5CsiHRD7n"
|
||||
>
|
||||
Publish timezone on public profile
|
||||
</label>
|
||||
@@ -452,7 +485,7 @@ exports[`PreferencesUserSettingsTab should render 1`] = `
|
||||
checked=""
|
||||
class="_input_udcm8_24"
|
||||
disabled=""
|
||||
id="mx_SettingsFlag_IAu5CsiHRD7n"
|
||||
id="mx_SettingsFlag_yrA2ohjWVJIP"
|
||||
role="switch"
|
||||
type="checkbox"
|
||||
/>
|
||||
@@ -466,7 +499,7 @@ exports[`PreferencesUserSettingsTab should render 1`] = `
|
||||
>
|
||||
<label
|
||||
class="_label_1o4d9_60"
|
||||
for="mx_SettingsFlag_IAu5CsiHRD7n"
|
||||
for="mx_SettingsFlag_yrA2ohjWVJIP"
|
||||
>
|
||||
Send read receipts
|
||||
</label>
|
||||
@@ -491,7 +524,7 @@ exports[`PreferencesUserSettingsTab should render 1`] = `
|
||||
checked=""
|
||||
class="_input_udcm8_24"
|
||||
disabled=""
|
||||
id="mx_SettingsFlag_yrA2ohjWVJIP"
|
||||
id="mx_SettingsFlag_auy1OmnTidX4"
|
||||
role="switch"
|
||||
type="checkbox"
|
||||
/>
|
||||
@@ -505,7 +538,7 @@ exports[`PreferencesUserSettingsTab should render 1`] = `
|
||||
>
|
||||
<label
|
||||
class="_label_1o4d9_60"
|
||||
for="mx_SettingsFlag_yrA2ohjWVJIP"
|
||||
for="mx_SettingsFlag_auy1OmnTidX4"
|
||||
>
|
||||
Send typing notifications
|
||||
</label>
|
||||
@@ -542,39 +575,6 @@ exports[`PreferencesUserSettingsTab should render 1`] = `
|
||||
class="_container_udcm8_10"
|
||||
>
|
||||
<input
|
||||
class="_input_udcm8_24"
|
||||
disabled=""
|
||||
id="mx_SettingsFlag_auy1OmnTidX4"
|
||||
role="switch"
|
||||
type="checkbox"
|
||||
/>
|
||||
<div
|
||||
class="_ui_udcm8_34"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="_inline-field-body_1o4d9_39"
|
||||
>
|
||||
<label
|
||||
class="_label_1o4d9_60"
|
||||
for="mx_SettingsFlag_auy1OmnTidX4"
|
||||
>
|
||||
Automatically replace plain text Emoji
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="_inline-field_1o4d9_33"
|
||||
>
|
||||
<div
|
||||
class="_inline-field-control_1o4d9_45"
|
||||
>
|
||||
<div
|
||||
class="_container_udcm8_10"
|
||||
>
|
||||
<input
|
||||
checked=""
|
||||
class="_input_udcm8_24"
|
||||
disabled=""
|
||||
id="mx_SettingsFlag_ePDS0OpWwAHG"
|
||||
@@ -593,20 +593,8 @@ exports[`PreferencesUserSettingsTab should render 1`] = `
|
||||
class="_label_1o4d9_60"
|
||||
for="mx_SettingsFlag_ePDS0OpWwAHG"
|
||||
>
|
||||
Enable Markdown
|
||||
Automatically replace plain text Emoji
|
||||
</label>
|
||||
<span
|
||||
class="_message_1o4d9_86 _help-message_1o4d9_92"
|
||||
id="radix-react-use-id-4"
|
||||
>
|
||||
<span>
|
||||
Start messages with
|
||||
<code>
|
||||
/plain
|
||||
</code>
|
||||
to send without markdown.
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
@@ -638,8 +626,20 @@ exports[`PreferencesUserSettingsTab should render 1`] = `
|
||||
class="_label_1o4d9_60"
|
||||
for="mx_SettingsFlag_75JNTNkNU64r"
|
||||
>
|
||||
Enable Emoji suggestions while typing
|
||||
Enable Markdown
|
||||
</label>
|
||||
<span
|
||||
class="_message_1o4d9_86 _help-message_1o4d9_92"
|
||||
id="radix-react-use-id-4"
|
||||
>
|
||||
<span>
|
||||
Start messages with
|
||||
<code>
|
||||
/plain
|
||||
</code>
|
||||
to send without markdown.
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
@@ -652,6 +652,7 @@ exports[`PreferencesUserSettingsTab should render 1`] = `
|
||||
class="_container_udcm8_10"
|
||||
>
|
||||
<input
|
||||
checked=""
|
||||
class="_input_udcm8_24"
|
||||
disabled=""
|
||||
id="mx_SettingsFlag_aTLcRsQRlYy7"
|
||||
@@ -670,7 +671,7 @@ exports[`PreferencesUserSettingsTab should render 1`] = `
|
||||
class="_label_1o4d9_60"
|
||||
for="mx_SettingsFlag_aTLcRsQRlYy7"
|
||||
>
|
||||
Use Ctrl + Enter to send a message
|
||||
Enable Emoji suggestions while typing
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
@@ -702,7 +703,7 @@ exports[`PreferencesUserSettingsTab should render 1`] = `
|
||||
class="_label_1o4d9_60"
|
||||
for="mx_SettingsFlag_5nfv5bOEPN1s"
|
||||
>
|
||||
Surround selected text when typing special characters
|
||||
Use Ctrl + Enter to send a message
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
@@ -716,7 +717,6 @@ exports[`PreferencesUserSettingsTab should render 1`] = `
|
||||
class="_container_udcm8_10"
|
||||
>
|
||||
<input
|
||||
checked=""
|
||||
class="_input_udcm8_24"
|
||||
disabled=""
|
||||
id="mx_SettingsFlag_u1JYVtOyR5kb"
|
||||
@@ -735,7 +735,7 @@ exports[`PreferencesUserSettingsTab should render 1`] = `
|
||||
class="_label_1o4d9_60"
|
||||
for="mx_SettingsFlag_u1JYVtOyR5kb"
|
||||
>
|
||||
Show stickers button
|
||||
Surround selected text when typing special characters
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
@@ -767,6 +767,39 @@ exports[`PreferencesUserSettingsTab should render 1`] = `
|
||||
<label
|
||||
class="_label_1o4d9_60"
|
||||
for="mx_SettingsFlag_u3pEwuLn9Enn"
|
||||
>
|
||||
Show stickers button
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="_inline-field_1o4d9_33"
|
||||
>
|
||||
<div
|
||||
class="_inline-field-control_1o4d9_45"
|
||||
>
|
||||
<div
|
||||
class="_container_udcm8_10"
|
||||
>
|
||||
<input
|
||||
checked=""
|
||||
class="_input_udcm8_24"
|
||||
disabled=""
|
||||
id="mx_SettingsFlag_YuxfFEpOsztW"
|
||||
role="switch"
|
||||
type="checkbox"
|
||||
/>
|
||||
<div
|
||||
class="_ui_udcm8_34"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="_inline-field-body_1o4d9_39"
|
||||
>
|
||||
<label
|
||||
class="_label_1o4d9_60"
|
||||
for="mx_SettingsFlag_YuxfFEpOsztW"
|
||||
>
|
||||
Insert a trailing colon after user mentions at the start of a message
|
||||
</label>
|
||||
@@ -805,7 +838,7 @@ exports[`PreferencesUserSettingsTab should render 1`] = `
|
||||
<input
|
||||
class="_input_udcm8_24"
|
||||
disabled=""
|
||||
id="mx_SettingsFlag_YuxfFEpOsztW"
|
||||
id="mx_SettingsFlag_hQkBerF1ejc4"
|
||||
role="switch"
|
||||
type="checkbox"
|
||||
/>
|
||||
@@ -819,7 +852,7 @@ exports[`PreferencesUserSettingsTab should render 1`] = `
|
||||
>
|
||||
<label
|
||||
class="_label_1o4d9_60"
|
||||
for="mx_SettingsFlag_YuxfFEpOsztW"
|
||||
for="mx_SettingsFlag_hQkBerF1ejc4"
|
||||
>
|
||||
Enable automatic language detection for syntax highlighting
|
||||
</label>
|
||||
@@ -837,7 +870,7 @@ exports[`PreferencesUserSettingsTab should render 1`] = `
|
||||
<input
|
||||
class="_input_udcm8_24"
|
||||
disabled=""
|
||||
id="mx_SettingsFlag_hQkBerF1ejc4"
|
||||
id="mx_SettingsFlag_GFes1UFzOK2n"
|
||||
role="switch"
|
||||
type="checkbox"
|
||||
/>
|
||||
@@ -851,7 +884,7 @@ exports[`PreferencesUserSettingsTab should render 1`] = `
|
||||
>
|
||||
<label
|
||||
class="_label_1o4d9_60"
|
||||
for="mx_SettingsFlag_hQkBerF1ejc4"
|
||||
for="mx_SettingsFlag_GFes1UFzOK2n"
|
||||
>
|
||||
Expand code blocks by default
|
||||
</label>
|
||||
@@ -870,7 +903,7 @@ exports[`PreferencesUserSettingsTab should render 1`] = `
|
||||
checked=""
|
||||
class="_input_udcm8_24"
|
||||
disabled=""
|
||||
id="mx_SettingsFlag_GFes1UFzOK2n"
|
||||
id="mx_SettingsFlag_vfGFMldL2r2v"
|
||||
role="switch"
|
||||
type="checkbox"
|
||||
/>
|
||||
@@ -884,7 +917,7 @@ exports[`PreferencesUserSettingsTab should render 1`] = `
|
||||
>
|
||||
<label
|
||||
class="_label_1o4d9_60"
|
||||
for="mx_SettingsFlag_GFes1UFzOK2n"
|
||||
for="mx_SettingsFlag_vfGFMldL2r2v"
|
||||
>
|
||||
Show line numbers in code blocks
|
||||
</label>
|
||||
@@ -932,7 +965,7 @@ exports[`PreferencesUserSettingsTab should render 1`] = `
|
||||
<input
|
||||
checked=""
|
||||
class="_input_udcm8_24"
|
||||
id="mx_SettingsFlag_vfGFMldL2r2v"
|
||||
id="mx_SettingsFlag_bsSwicmKUiOB"
|
||||
role="switch"
|
||||
type="checkbox"
|
||||
/>
|
||||
@@ -946,7 +979,7 @@ exports[`PreferencesUserSettingsTab should render 1`] = `
|
||||
>
|
||||
<label
|
||||
class="_label_1o4d9_60"
|
||||
for="mx_SettingsFlag_vfGFMldL2r2v"
|
||||
for="mx_SettingsFlag_bsSwicmKUiOB"
|
||||
>
|
||||
Enable previews
|
||||
</label>
|
||||
@@ -963,7 +996,7 @@ exports[`PreferencesUserSettingsTab should render 1`] = `
|
||||
>
|
||||
<input
|
||||
class="_input_udcm8_24"
|
||||
id="mx_SettingsFlag_bsSwicmKUiOB"
|
||||
id="mx_SettingsFlag_dvqsxEaZtl3A"
|
||||
role="switch"
|
||||
type="checkbox"
|
||||
/>
|
||||
@@ -977,7 +1010,7 @@ exports[`PreferencesUserSettingsTab should render 1`] = `
|
||||
>
|
||||
<label
|
||||
class="_label_1o4d9_60"
|
||||
for="mx_SettingsFlag_bsSwicmKUiOB"
|
||||
for="mx_SettingsFlag_dvqsxEaZtl3A"
|
||||
>
|
||||
Enable previews in encrypted rooms
|
||||
</label>
|
||||
@@ -1016,7 +1049,7 @@ exports[`PreferencesUserSettingsTab should render 1`] = `
|
||||
<input
|
||||
class="_input_udcm8_24"
|
||||
disabled=""
|
||||
id="mx_SettingsFlag_dvqsxEaZtl3A"
|
||||
id="mx_SettingsFlag_NIiWzqsApP1c"
|
||||
role="switch"
|
||||
type="checkbox"
|
||||
/>
|
||||
@@ -1030,7 +1063,7 @@ exports[`PreferencesUserSettingsTab should render 1`] = `
|
||||
>
|
||||
<label
|
||||
class="_label_1o4d9_60"
|
||||
for="mx_SettingsFlag_dvqsxEaZtl3A"
|
||||
for="mx_SettingsFlag_NIiWzqsApP1c"
|
||||
>
|
||||
Autoplay GIFs
|
||||
</label>
|
||||
@@ -1048,7 +1081,7 @@ exports[`PreferencesUserSettingsTab should render 1`] = `
|
||||
<input
|
||||
class="_input_udcm8_24"
|
||||
disabled=""
|
||||
id="mx_SettingsFlag_NIiWzqsApP1c"
|
||||
id="mx_SettingsFlag_q1SIAPqLMVXh"
|
||||
role="switch"
|
||||
type="checkbox"
|
||||
/>
|
||||
@@ -1062,7 +1095,7 @@ exports[`PreferencesUserSettingsTab should render 1`] = `
|
||||
>
|
||||
<label
|
||||
class="_label_1o4d9_60"
|
||||
for="mx_SettingsFlag_NIiWzqsApP1c"
|
||||
for="mx_SettingsFlag_q1SIAPqLMVXh"
|
||||
>
|
||||
Autoplay videos
|
||||
</label>
|
||||
@@ -1089,39 +1122,6 @@ exports[`PreferencesUserSettingsTab should render 1`] = `
|
||||
<div
|
||||
class="mx_SettingsSubsection_content"
|
||||
>
|
||||
<div
|
||||
class="_inline-field_1o4d9_33"
|
||||
>
|
||||
<div
|
||||
class="_inline-field-control_1o4d9_45"
|
||||
>
|
||||
<div
|
||||
class="_container_udcm8_10"
|
||||
>
|
||||
<input
|
||||
checked=""
|
||||
class="_input_udcm8_24"
|
||||
disabled=""
|
||||
id="mx_SettingsFlag_q1SIAPqLMVXh"
|
||||
role="switch"
|
||||
type="checkbox"
|
||||
/>
|
||||
<div
|
||||
class="_ui_udcm8_34"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="_inline-field-body_1o4d9_39"
|
||||
>
|
||||
<label
|
||||
class="_label_1o4d9_60"
|
||||
for="mx_SettingsFlag_q1SIAPqLMVXh"
|
||||
>
|
||||
Show typing notifications
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="_inline-field_1o4d9_33"
|
||||
>
|
||||
@@ -1151,7 +1151,7 @@ exports[`PreferencesUserSettingsTab should render 1`] = `
|
||||
class="_label_1o4d9_60"
|
||||
for="mx_SettingsFlag_dXFDGgBsKXay"
|
||||
>
|
||||
Show a placeholder for removed messages
|
||||
Show typing notifications
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1184,7 +1184,7 @@ exports[`PreferencesUserSettingsTab should render 1`] = `
|
||||
class="_label_1o4d9_60"
|
||||
for="mx_SettingsFlag_7Az0xw4Bs4Tt"
|
||||
>
|
||||
Show read receipts sent by other users
|
||||
Show a placeholder for removed messages
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1217,7 +1217,7 @@ exports[`PreferencesUserSettingsTab should render 1`] = `
|
||||
class="_label_1o4d9_60"
|
||||
for="mx_SettingsFlag_8jmzPIlPoBCv"
|
||||
>
|
||||
Show join/leave messages (invites/removes/bans unaffected)
|
||||
Show read receipts sent by other users
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1250,7 +1250,7 @@ exports[`PreferencesUserSettingsTab should render 1`] = `
|
||||
class="_label_1o4d9_60"
|
||||
for="mx_SettingsFlag_enFRaTjdsFou"
|
||||
>
|
||||
Show display name changes
|
||||
Show join/leave messages (invites/removes/bans unaffected)
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1283,7 +1283,7 @@ exports[`PreferencesUserSettingsTab should render 1`] = `
|
||||
class="_label_1o4d9_60"
|
||||
for="mx_SettingsFlag_bfwnd5rz4XNX"
|
||||
>
|
||||
Show chat effects (animations when receiving e.g. confetti)
|
||||
Show display name changes
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1316,7 +1316,7 @@ exports[`PreferencesUserSettingsTab should render 1`] = `
|
||||
class="_label_1o4d9_60"
|
||||
for="mx_SettingsFlag_gs5uWEzYzZrS"
|
||||
>
|
||||
Show profile picture changes
|
||||
Show chat effects (animations when receiving e.g. confetti)
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1349,7 +1349,7 @@ exports[`PreferencesUserSettingsTab should render 1`] = `
|
||||
class="_label_1o4d9_60"
|
||||
for="mx_SettingsFlag_qWg7OgID1yRR"
|
||||
>
|
||||
Show avatars in user, room and event mentions
|
||||
Show profile picture changes
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1382,7 +1382,7 @@ exports[`PreferencesUserSettingsTab should render 1`] = `
|
||||
class="_label_1o4d9_60"
|
||||
for="mx_SettingsFlag_pOPewl7rtMbV"
|
||||
>
|
||||
Enable big emoji in chat
|
||||
Show avatars in user, room and event mentions
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1415,7 +1415,7 @@ exports[`PreferencesUserSettingsTab should render 1`] = `
|
||||
class="_label_1o4d9_60"
|
||||
for="mx_SettingsFlag_cmt3PZSyNp3v"
|
||||
>
|
||||
Jump to the bottom of the timeline when you send a message
|
||||
Enable big emoji in chat
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1447,6 +1447,39 @@ exports[`PreferencesUserSettingsTab should render 1`] = `
|
||||
<label
|
||||
class="_label_1o4d9_60"
|
||||
for="mx_SettingsFlag_dJJz3lHUv9XX"
|
||||
>
|
||||
Jump to the bottom of the timeline when you send a message
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="_inline-field_1o4d9_33"
|
||||
>
|
||||
<div
|
||||
class="_inline-field-control_1o4d9_45"
|
||||
>
|
||||
<div
|
||||
class="_container_udcm8_10"
|
||||
>
|
||||
<input
|
||||
checked=""
|
||||
class="_input_udcm8_24"
|
||||
disabled=""
|
||||
id="mx_SettingsFlag_SBSSOZDRlzlA"
|
||||
role="switch"
|
||||
type="checkbox"
|
||||
/>
|
||||
<div
|
||||
class="_ui_udcm8_34"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="_inline-field-body_1o4d9_39"
|
||||
>
|
||||
<label
|
||||
class="_label_1o4d9_60"
|
||||
for="mx_SettingsFlag_SBSSOZDRlzlA"
|
||||
>
|
||||
Show current profile picture and name for users in message history
|
||||
</label>
|
||||
@@ -1696,7 +1729,7 @@ exports[`PreferencesUserSettingsTab should render 1`] = `
|
||||
<input
|
||||
class="_input_udcm8_24"
|
||||
disabled=""
|
||||
id="mx_SettingsFlag_SBSSOZDRlzlA"
|
||||
id="mx_SettingsFlag_FLEpLCb0jpp6"
|
||||
role="switch"
|
||||
type="checkbox"
|
||||
/>
|
||||
@@ -1710,7 +1743,7 @@ exports[`PreferencesUserSettingsTab should render 1`] = `
|
||||
>
|
||||
<label
|
||||
class="_label_1o4d9_60"
|
||||
for="mx_SettingsFlag_SBSSOZDRlzlA"
|
||||
for="mx_SettingsFlag_FLEpLCb0jpp6"
|
||||
>
|
||||
Show NSFW content
|
||||
</label>
|
||||
@@ -1750,7 +1783,7 @@ exports[`PreferencesUserSettingsTab should render 1`] = `
|
||||
checked=""
|
||||
class="_input_udcm8_24"
|
||||
disabled=""
|
||||
id="mx_SettingsFlag_FLEpLCb0jpp6"
|
||||
id="mx_SettingsFlag_NQFWldEwbV3q"
|
||||
role="switch"
|
||||
type="checkbox"
|
||||
/>
|
||||
@@ -1764,7 +1797,7 @@ exports[`PreferencesUserSettingsTab should render 1`] = `
|
||||
>
|
||||
<label
|
||||
class="_label_1o4d9_60"
|
||||
for="mx_SettingsFlag_FLEpLCb0jpp6"
|
||||
for="mx_SettingsFlag_NQFWldEwbV3q"
|
||||
>
|
||||
Prompt before sending invites to potentially invalid matrix IDs
|
||||
</label>
|
||||
|
||||
@@ -929,6 +929,7 @@ describe("RoomListStoreV3", () => {
|
||||
describe("Sections", () => {
|
||||
function enableSections(): void {
|
||||
jest.spyOn(SettingsStore, "getValue").mockImplementation((setting: string) => {
|
||||
if (setting === "RoomList.showSections") return true;
|
||||
if (setting === "RoomList.OrderedCustomSections") return [];
|
||||
if (setting === "RoomList.CustomSectionData") return {};
|
||||
return false;
|
||||
@@ -961,6 +962,55 @@ describe("RoomListStoreV3", () => {
|
||||
expect(result.sections[2].tag).toBe(DefaultTagID.LowPriority);
|
||||
});
|
||||
|
||||
describe("RoomList.showSections disabled", () => {
|
||||
function disableSections(): void {
|
||||
jest.spyOn(SettingsStore, "getValue").mockImplementation((setting: string) => {
|
||||
if (setting === "RoomList.showSections") return false;
|
||||
if (setting === "RoomList.OrderedCustomSections") return [];
|
||||
if (setting === "RoomList.CustomSectionData") return {};
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
it("returns a single Chats section containing the rooms", async () => {
|
||||
disableSections();
|
||||
const { rooms } = getClientAndRooms();
|
||||
|
||||
rooms[3].tags[DefaultTagID.Favourite] = {};
|
||||
rooms[7].tags[DefaultTagID.LowPriority] = {};
|
||||
|
||||
const store = new RoomListStoreV3Class(dispatcher);
|
||||
await store.start();
|
||||
|
||||
const { sections } = store.getSortedRoomsInActiveSpace();
|
||||
expect(sections).toHaveLength(1);
|
||||
expect(sections[0].tag).toBe(CHATS_TAG);
|
||||
expect(sections[0].rooms).toContain(rooms[3]);
|
||||
expect(sections[0].rooms).toContain(rooms[7]);
|
||||
});
|
||||
});
|
||||
|
||||
it("emits LISTS_UPDATE_EVENT when RoomList.showSections setting changes", async () => {
|
||||
enableSections();
|
||||
getClientAndRooms();
|
||||
|
||||
let settingsWatcher: () => void = () => {};
|
||||
jest.spyOn(SettingsStore, "watchSetting").mockImplementation((settingName, _roomId, callback) => {
|
||||
if (settingName === "RoomList.showSections") settingsWatcher = callback as () => void;
|
||||
return "watcher-id";
|
||||
});
|
||||
|
||||
const store = new RoomListStoreV3Class(dispatcher);
|
||||
await store.start();
|
||||
|
||||
const listsUpdateListener = jest.fn();
|
||||
store.on(LISTS_UPDATE_EVENT, listsUpdateListener);
|
||||
|
||||
settingsWatcher();
|
||||
|
||||
expect(listsUpdateListener).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it.each([
|
||||
{ tag: DefaultTagID.Favourite, label: "Favourite" },
|
||||
{ tag: DefaultTagID.LowPriority, label: "LowPriority" },
|
||||
@@ -1209,6 +1259,7 @@ describe("RoomListStoreV3", () => {
|
||||
const customTag = "element.io.section.custom";
|
||||
|
||||
jest.spyOn(SettingsStore, "getValue").mockImplementation((setting: string) => {
|
||||
if (setting === "RoomList.showSections") return true;
|
||||
if (setting === "RoomList.OrderedCustomSections") return [];
|
||||
if (setting === "RoomList.CustomSectionData") return {};
|
||||
return false;
|
||||
@@ -1223,6 +1274,7 @@ describe("RoomListStoreV3", () => {
|
||||
// Mark a room with the custom tag and update the settings
|
||||
rooms[0].tags = { [customTag]: { order: 0 } };
|
||||
jest.spyOn(SettingsStore, "getValue").mockImplementation((setting: string) => {
|
||||
if (setting === "RoomList.showSections") return true;
|
||||
if (setting === "RoomList.OrderedCustomSections") return [customTag];
|
||||
if (setting === "RoomList.CustomSectionData")
|
||||
return { [customTag]: { tag: customTag, name: "Custom" } };
|
||||
|
||||
@@ -156,6 +156,36 @@ describe("RoomListHeaderViewModel", () => {
|
||||
expect(vm.getSnapshot().isMessagePreviewEnabled).toBe(true);
|
||||
});
|
||||
|
||||
it("should set areSectionsEnabled to true when RoomList.showSections is enabled", () => {
|
||||
jest.spyOn(SettingsStore, "getValue").mockImplementation((settingName: string) => {
|
||||
if (settingName === "RoomList.showSections") return true;
|
||||
return false;
|
||||
});
|
||||
|
||||
vm = new RoomListHeaderViewModel({ matrixClient, spaceStore: SpaceStore.instance });
|
||||
expect(vm.getSnapshot().areSectionsEnabled).toBe(true);
|
||||
});
|
||||
|
||||
it("should update areSectionsEnabled when RoomList.showSections setting changes", () => {
|
||||
let watchCallback: () => void = () => {};
|
||||
jest.spyOn(SettingsStore, "watchSetting").mockImplementation((settingName, _roomId, callback) => {
|
||||
if (settingName === "RoomList.showSections") watchCallback = callback as () => void;
|
||||
return "watcher-id";
|
||||
});
|
||||
|
||||
vm = new RoomListHeaderViewModel({ matrixClient, spaceStore: SpaceStore.instance });
|
||||
expect(vm.getSnapshot().areSectionsEnabled).toBe(false);
|
||||
|
||||
// Enable sections
|
||||
jest.spyOn(SettingsStore, "getValue").mockImplementation((settingName: string) => {
|
||||
if (settingName === "RoomList.showSections") return true;
|
||||
return false;
|
||||
});
|
||||
watchCallback();
|
||||
|
||||
expect(vm.getSnapshot().areSectionsEnabled).toBe(true);
|
||||
});
|
||||
|
||||
it("should set displaySectionReleaseAnnouncement to true when sections feature is enabled and announcement is active", () => {
|
||||
jest.spyOn(ReleaseAnnouncementStore.instance, "getReleaseAnnouncement").mockReturnValue(
|
||||
"room_list_section",
|
||||
|
||||
@@ -664,6 +664,36 @@ describe("RoomListItemViewModel", () => {
|
||||
|
||||
expect(viewModel.getSnapshot().sections.map((s) => s.tag)).toEqual([]);
|
||||
});
|
||||
|
||||
it("should set areSectionsEnabled to true when RoomList.showSections is enabled", () => {
|
||||
jest.spyOn(SettingsStore, "getValue").mockImplementation((setting) => {
|
||||
if (setting === "RoomList.showSections") return true;
|
||||
return false;
|
||||
});
|
||||
|
||||
viewModel = new RoomListItemViewModel({ room, client: matrixClient });
|
||||
expect(viewModel.getSnapshot().areSectionsEnabled).toBe(true);
|
||||
});
|
||||
|
||||
it("should update areSectionsEnabled when RoomList.showSections setting changes", () => {
|
||||
let watchCallback: CallbackFn<"RoomList.showSections"> = () => {};
|
||||
jest.spyOn(SettingsStore, "watchSetting").mockImplementation((setting, _room, callback) => {
|
||||
if (setting === "RoomList.showSections") watchCallback = callback;
|
||||
return "watcher-id";
|
||||
});
|
||||
|
||||
viewModel = new RoomListItemViewModel({ room, client: matrixClient });
|
||||
expect(viewModel.getSnapshot().areSectionsEnabled).toBe(false);
|
||||
|
||||
// Enable sections
|
||||
jest.spyOn(SettingsStore, "getValue").mockImplementation((setting) => {
|
||||
if (setting === "RoomList.showSections") return true;
|
||||
return false;
|
||||
});
|
||||
watchCallback("RoomList.showSections", null, null as any, null, null);
|
||||
|
||||
expect(viewModel.getSnapshot().areSectionsEnabled).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Cleanup", () => {
|
||||
|
||||
BIN
Binary file not shown.
|
After Width: | Height: | Size: 19 KiB |
BIN
Binary file not shown.
|
After Width: | Height: | Size: 18 KiB |
BIN
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
+14
@@ -142,3 +142,17 @@ export const DisplaySectionReleaseAnnouncement: Story = {
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const SectionsDisabled: Story = {
|
||||
args: {
|
||||
areSectionsEnabled: false,
|
||||
},
|
||||
};
|
||||
|
||||
export const NoComposeMenu: Story = {
|
||||
args: {
|
||||
canCreateRoom: false,
|
||||
canCreateVideoRoom: false,
|
||||
areSectionsEnabled: false,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
import React, { type JSX } from "react";
|
||||
import { IconButton, H1 } from "@vector-im/compound-web";
|
||||
import { CollapseAllIcon, ExpandAllIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
|
||||
import { CollapseAllIcon, ExpandAllIcon, ChatIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
|
||||
|
||||
import { type ViewModel, useViewModel } from "../../core/viewmodel";
|
||||
import { Flex } from "../../core/utils/Flex";
|
||||
@@ -59,6 +59,10 @@ export interface RoomListHeaderViewSnapshot {
|
||||
* Whether message previews are enabled in the room list.
|
||||
*/
|
||||
isMessagePreviewEnabled: boolean;
|
||||
/**
|
||||
* Whether sections are enabled in the room list.
|
||||
*/
|
||||
areSectionsEnabled: boolean;
|
||||
/**
|
||||
* If "collapse", an icon to collapse all sections is shown.
|
||||
* If "expand", an icon to expand all sections is shown.
|
||||
@@ -145,7 +149,9 @@ interface RoomListHeaderViewProps {
|
||||
*/
|
||||
export function RoomListHeaderView({ vm }: Readonly<RoomListHeaderViewProps>): JSX.Element {
|
||||
const { translate: _t } = useI18n();
|
||||
const { title, displaySpaceMenu, collapseSections } = useViewModel(vm);
|
||||
const { title, displaySpaceMenu, collapseSections, areSectionsEnabled, canCreateRoom, canCreateVideoRoom } =
|
||||
useViewModel(vm);
|
||||
const canOnlyStartChat = !areSectionsEnabled && !canCreateRoom && !canCreateVideoRoom;
|
||||
|
||||
return (
|
||||
<Flex
|
||||
@@ -164,7 +170,7 @@ export function RoomListHeaderView({ vm }: Readonly<RoomListHeaderViewProps>): J
|
||||
</Flex>
|
||||
<Flex align="center" gap="var(--cpd-space-2x)">
|
||||
<OptionMenuView vm={vm} />
|
||||
{collapseSections && (
|
||||
{areSectionsEnabled && collapseSections && (
|
||||
<IconButton
|
||||
size="28px"
|
||||
style={{ padding: "4px" }}
|
||||
@@ -182,7 +188,18 @@ export function RoomListHeaderView({ vm }: Readonly<RoomListHeaderViewProps>): J
|
||||
)}
|
||||
</IconButton>
|
||||
)}
|
||||
<ComposeMenuView vm={vm} />
|
||||
{canOnlyStartChat ? (
|
||||
<IconButton
|
||||
size="28px"
|
||||
style={{ padding: "4px" }}
|
||||
onClick={(e) => vm.createChatRoom(e.nativeEvent)}
|
||||
tooltip={_t("action|start_chat")}
|
||||
>
|
||||
<ChatIcon color="var(--cpd-color-icon-secondary)" aria-hidden />
|
||||
</IconButton>
|
||||
) : (
|
||||
<ComposeMenuView vm={vm} />
|
||||
)}
|
||||
</Flex>
|
||||
</Flex>
|
||||
</Flex>
|
||||
|
||||
@@ -17,4 +17,5 @@ export const defaultSnapshot: RoomListHeaderViewSnapshot = {
|
||||
activeSortOption: "recent",
|
||||
isMessagePreviewEnabled: true,
|
||||
displaySectionReleaseAnnouncement: false,
|
||||
areSectionsEnabled: true,
|
||||
};
|
||||
|
||||
+5
-2
@@ -36,7 +36,8 @@ interface ComposeMenuViewProps {
|
||||
export function ComposeMenuView({ vm }: ComposeMenuViewProps): JSX.Element {
|
||||
const { translate: _t } = useI18n();
|
||||
const [open, setOpen] = useState(false);
|
||||
const { canCreateRoom, canCreateVideoRoom, displaySectionReleaseAnnouncement } = useViewModel(vm);
|
||||
const { canCreateRoom, canCreateVideoRoom, displaySectionReleaseAnnouncement, areSectionsEnabled } =
|
||||
useViewModel(vm);
|
||||
|
||||
// 28px button with a 20px icon
|
||||
const button = (
|
||||
@@ -80,7 +81,9 @@ export function ComposeMenuView({ vm }: ComposeMenuViewProps): JSX.Element {
|
||||
hideChevron
|
||||
/>
|
||||
)}
|
||||
<MenuItem Icon={SectionIcon} label={_t("action|new_section")} onSelect={vm.createSection} hideChevron />
|
||||
{areSectionsEnabled && (
|
||||
<MenuItem Icon={SectionIcon} label={_t("action|new_section")} onSelect={vm.createSection} hideChevron />
|
||||
)}
|
||||
</Menu>
|
||||
);
|
||||
}
|
||||
|
||||
+38
-34
@@ -131,41 +131,45 @@ export function MoreOptionContent({ vm }: MoreOptionContentProps): JSX.Element {
|
||||
hideChevron={true}
|
||||
/>
|
||||
)}
|
||||
<SubMenu
|
||||
trigger={
|
||||
<MenuItem
|
||||
Icon={ArrowRightIcon}
|
||||
label={_t("room_list|more_options|move_to_section")}
|
||||
onSelect={null}
|
||||
/>
|
||||
}
|
||||
>
|
||||
{snapshot.sections.map((section) => (
|
||||
<MenuItem
|
||||
key={section.tag}
|
||||
label={section.name}
|
||||
labelProps={{ className: styles.sectionLabel }}
|
||||
onSelect={() => vm.onToggleSection(section.tag)}
|
||||
onClick={(evt) => evt.stopPropagation()}
|
||||
hideChevron={true}
|
||||
aria-checked={section.isSelected}
|
||||
{snapshot.areSectionsEnabled && (
|
||||
<>
|
||||
<SubMenu
|
||||
trigger={
|
||||
<MenuItem
|
||||
Icon={ArrowRightIcon}
|
||||
label={_t("room_list|more_options|move_to_section")}
|
||||
onSelect={null}
|
||||
/>
|
||||
}
|
||||
>
|
||||
{section.isSelected && (
|
||||
<CheckIcon color="var(--cpd-color-icon-tertiary)" width="24px" height="24px" />
|
||||
)}
|
||||
</MenuItem>
|
||||
))}
|
||||
{hasSections && <Separator />}
|
||||
<MenuItem label={_t("action|new_section")} onSelect={vm.onCreateSection} hideChevron={true} />
|
||||
</SubMenu>
|
||||
{isInSection && (
|
||||
<MenuItem
|
||||
Icon={MinusIcon}
|
||||
label={_t("room_list|more_options|remove_from_section")}
|
||||
onSelect={vm.onRemoveFromSection}
|
||||
onClick={(evt) => evt.stopPropagation()}
|
||||
hideChevron={true}
|
||||
/>
|
||||
{snapshot.sections.map((section) => (
|
||||
<MenuItem
|
||||
key={section.tag}
|
||||
label={section.name}
|
||||
labelProps={{ className: styles.sectionLabel }}
|
||||
onSelect={() => vm.onToggleSection(section.tag)}
|
||||
onClick={(evt) => evt.stopPropagation()}
|
||||
hideChevron={true}
|
||||
aria-checked={section.isSelected}
|
||||
>
|
||||
{section.isSelected && (
|
||||
<CheckIcon color="var(--cpd-color-icon-tertiary)" width="24px" height="24px" />
|
||||
)}
|
||||
</MenuItem>
|
||||
))}
|
||||
{hasSections && <Separator />}
|
||||
<MenuItem label={_t("action|new_section")} onSelect={vm.onCreateSection} hideChevron={true} />
|
||||
</SubMenu>
|
||||
{isInSection && (
|
||||
<MenuItem
|
||||
Icon={MinusIcon}
|
||||
label={_t("room_list|more_options|remove_from_section")}
|
||||
onSelect={vm.onRemoveFromSection}
|
||||
onClick={(evt) => evt.stopPropagation()}
|
||||
hideChevron={true}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
<Separator />
|
||||
<MenuItem
|
||||
|
||||
+6
@@ -308,3 +308,9 @@ export const LastItem: Story = {
|
||||
isSelected: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const SectionDisabled: Story = {
|
||||
args: {
|
||||
areSectionsEnabled: false,
|
||||
},
|
||||
};
|
||||
|
||||
+2
@@ -94,6 +94,8 @@ export interface RoomListItemViewSnapshot {
|
||||
roomNotifState: RoomNotifState;
|
||||
/** Available sections the room can be assigned to */
|
||||
sections: Section[];
|
||||
/** Whether sections are enabled in the room list */
|
||||
areSectionsEnabled: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+1
@@ -53,4 +53,5 @@ export const defaultSnapshot: RoomListItemViewSnapshot = {
|
||||
isSelected: false,
|
||||
},
|
||||
],
|
||||
areSectionsEnabled: true,
|
||||
};
|
||||
|
||||
@@ -106,6 +106,7 @@ export const createMockRoomSnapshot = (id: string, name: string, index: number):
|
||||
canMarkAsUnread: true,
|
||||
roomNotifState: RoomNotifState.AllMessages,
|
||||
sections: [],
|
||||
areSectionsEnabled: true,
|
||||
});
|
||||
|
||||
export function createMockRoomItemViewModel(roomId: string, name: string, index: number): RoomListItemViewModel {
|
||||
|
||||
Reference in New Issue
Block a user