mirror of
https://github.com/vector-im/element-web.git
synced 2026-05-16 09:56:15 +02:00
fix(prototype): fix test suite and setting keys for variant-a space-scoped sections
- Rename setting keys to element.io.prototype.RoomList.* prefix - Guard against legacy flat-array format in OrderedCustomSections - Shallow-copy settings cache before mutation - Update all tests to match new API: spaceId param on createSection(), Record<SpaceKey, string[]> for OrderedCustomSections, and full setting key names
This commit is contained in:
parent
a64e5f0d8f
commit
4bc83cf3e1
3
.gitignore
vendored
3
.gitignore
vendored
@ -42,3 +42,6 @@ storybook-static
|
||||
# vitepress
|
||||
/docs/.vitepress/dist
|
||||
/docs/.vitepress/cache
|
||||
|
||||
# Local Netlify folder
|
||||
.netlify
|
||||
|
||||
@ -368,8 +368,8 @@ export interface Settings {
|
||||
"inviteRules": IBaseSetting<ComputedInviteConfig>;
|
||||
"blockInvites": IBaseSetting<boolean>;
|
||||
"Developer.elementCallUrl": IBaseSetting<string>;
|
||||
"RoomList.CustomSectionData": IBaseSetting<CustomSectionsData>;
|
||||
"RoomList.OrderedCustomSections": IBaseSetting<OrderedCustomSections>;
|
||||
"element.io.prototype.RoomList.CustomSectionData": IBaseSetting<CustomSectionsData>;
|
||||
"element.io.prototype.RoomList.OrderedCustomSections": IBaseSetting<OrderedCustomSections>;
|
||||
}
|
||||
|
||||
export type SettingKey = keyof Settings;
|
||||
@ -1379,7 +1379,7 @@ export const SETTINGS: Settings = {
|
||||
* Managed by the {@link RoomListStoreV3}
|
||||
* Store the custom section data for the room list
|
||||
*/
|
||||
"RoomList.CustomSectionData": {
|
||||
"element.io.prototype.RoomList.CustomSectionData": {
|
||||
supportedLevels: LEVELS_ACCOUNT_SETTINGS,
|
||||
default: {},
|
||||
},
|
||||
@ -1387,7 +1387,7 @@ export const SETTINGS: Settings = {
|
||||
* Managed by the {@link RoomListStoreV3}
|
||||
* Store the ordering of the custom sections for the room list, keyed by space/metaspace ID.
|
||||
*/
|
||||
"RoomList.OrderedCustomSections": {
|
||||
"element.io.prototype.RoomList.OrderedCustomSections": {
|
||||
supportedLevels: LEVELS_ACCOUNT_SETTINGS,
|
||||
default: {},
|
||||
},
|
||||
|
||||
@ -133,7 +133,7 @@ export class RoomListStoreV3Class extends AsyncStoreWithClient<EmptyObject> {
|
||||
this.onActiveSpaceChanged();
|
||||
});
|
||||
SpaceStore.instance.on(UPDATE_HOME_BEHAVIOUR, () => this.onActiveSpaceChanged());
|
||||
SettingsStore.watchSetting("RoomList.OrderedCustomSections", null, () => this.onOrderedCustomSectionsChange());
|
||||
SettingsStore.watchSetting("element.io.prototype.RoomList.OrderedCustomSections", null, () => this.onOrderedCustomSectionsChange());
|
||||
this.loadCustomSections();
|
||||
}
|
||||
|
||||
@ -532,7 +532,10 @@ export class RoomListStoreV3Class extends AsyncStoreWithClient<EmptyObject> {
|
||||
*/
|
||||
private loadCustomSections(): void {
|
||||
const activeSpace = SpaceStore.instance.activeSpace;
|
||||
const orderedCustomSections: Record<string, string[]> = SettingsStore.getValue("RoomList.OrderedCustomSections") || {};
|
||||
const storedSections = SettingsStore.getValue("element.io.prototype.RoomList.OrderedCustomSections");
|
||||
// Guard against legacy flat-array format stored by the base branch
|
||||
const orderedCustomSections: Record<string, string[]> =
|
||||
storedSections && !Array.isArray(storedSections) ? storedSections : {};
|
||||
const spaceSections = orderedCustomSections[activeSpace] ?? [];
|
||||
this.sortedTags = [DefaultTagID.Favourite, ...spaceSections, CHATS_TAG, DefaultTagID.LowPriority];
|
||||
}
|
||||
|
||||
@ -65,17 +65,18 @@ export async function createSection(spaceId: SpaceKey): Promise<string | undefin
|
||||
const tag = `${CUSTOM_SECTION_TAG_PREFIX}${window.crypto.randomUUID()}`;
|
||||
const newSection: CustomSection = { tag, name: sectionName, spaceId };
|
||||
|
||||
// Save the new section data
|
||||
const sectionData = SettingsStore.getValue("RoomList.CustomSectionData") || {};
|
||||
// Save the new section data — shallow-copy to avoid mutating the settings cache reference
|
||||
const sectionData = { ...(SettingsStore.getValue("element.io.prototype.RoomList.CustomSectionData") || {}) };
|
||||
sectionData[tag] = newSection;
|
||||
await SettingsStore.setValue("RoomList.CustomSectionData", null, SettingLevel.ACCOUNT, sectionData);
|
||||
await SettingsStore.setValue("element.io.prototype.RoomList.CustomSectionData", null, SettingLevel.ACCOUNT, sectionData);
|
||||
|
||||
// Add the new section to the ordered list of sections for this space
|
||||
const orderedSections: OrderedCustomSections = SettingsStore.getValue("RoomList.OrderedCustomSections") || {};
|
||||
const spaceSections = orderedSections[spaceId] ?? [];
|
||||
spaceSections.push(tag);
|
||||
orderedSections[spaceId] = spaceSections;
|
||||
await SettingsStore.setValue("RoomList.OrderedCustomSections", null, SettingLevel.ACCOUNT, orderedSections);
|
||||
// Shallow-copy and guard against legacy flat-array format from the base branch
|
||||
const storedSections = SettingsStore.getValue("element.io.prototype.RoomList.OrderedCustomSections");
|
||||
const orderedSections: OrderedCustomSections =
|
||||
storedSections && !Array.isArray(storedSections) ? { ...storedSections } : {};
|
||||
orderedSections[spaceId] = [...(orderedSections[spaceId] ?? []), tag];
|
||||
await SettingsStore.setValue("element.io.prototype.RoomList.OrderedCustomSections", null, SettingLevel.ACCOUNT, orderedSections);
|
||||
return tag;
|
||||
}
|
||||
|
||||
@ -84,7 +85,7 @@ export async function createSection(spaceId: SpaceKey): Promise<string | undefin
|
||||
* @param tag - The tag of the section to edit.
|
||||
*/
|
||||
export async function editSection(tag: string): Promise<void> {
|
||||
const sectionData = SettingsStore.getValue("RoomList.CustomSectionData") || {};
|
||||
const sectionData = SettingsStore.getValue("element.io.prototype.RoomList.CustomSectionData") || {};
|
||||
const section = sectionData[tag];
|
||||
if (!section) {
|
||||
logger.info("Unknown section tag, cannot edit section", tag);
|
||||
@ -99,7 +100,7 @@ export async function editSection(tag: string): Promise<void> {
|
||||
|
||||
// Save the new name
|
||||
sectionData[tag].name = newName;
|
||||
await SettingsStore.setValue("RoomList.CustomSectionData", null, SettingLevel.ACCOUNT, sectionData);
|
||||
await SettingsStore.setValue("element.io.prototype.RoomList.CustomSectionData", null, SettingLevel.ACCOUNT, sectionData);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -108,7 +109,7 @@ export async function editSection(tag: string): Promise<void> {
|
||||
* @param isEmpty - Whether the section is empty (has no rooms). If the section is not empty, the confirmation dialog will show a warning message.
|
||||
*/
|
||||
export async function deleteSection(tag: string, isEmpty: boolean): Promise<void> {
|
||||
const sectionData = SettingsStore.getValue("RoomList.CustomSectionData");
|
||||
const sectionData = SettingsStore.getValue("element.io.prototype.RoomList.CustomSectionData");
|
||||
if (!sectionData[tag]) {
|
||||
logger.info("Unknown section tag, cannot delete section", tag);
|
||||
return;
|
||||
@ -120,13 +121,16 @@ export async function deleteSection(tag: string, isEmpty: boolean): Promise<void
|
||||
|
||||
// Remove the section from the ordered list of sections for its space
|
||||
const spaceId = sectionData[tag].spaceId;
|
||||
const orderedSections: OrderedCustomSections = SettingsStore.getValue("RoomList.OrderedCustomSections") || {};
|
||||
const storedSections = SettingsStore.getValue("element.io.prototype.RoomList.OrderedCustomSections");
|
||||
const orderedSections: OrderedCustomSections =
|
||||
storedSections && !Array.isArray(storedSections) ? { ...storedSections } : {};
|
||||
if (orderedSections[spaceId]) {
|
||||
orderedSections[spaceId] = orderedSections[spaceId].filter((sectionTag) => sectionTag !== tag);
|
||||
}
|
||||
await SettingsStore.setValue("RoomList.OrderedCustomSections", null, SettingLevel.ACCOUNT, orderedSections);
|
||||
await SettingsStore.setValue("element.io.prototype.RoomList.OrderedCustomSections", null, SettingLevel.ACCOUNT, orderedSections);
|
||||
|
||||
// Remove the section data
|
||||
delete sectionData[tag];
|
||||
await SettingsStore.setValue("RoomList.CustomSectionData", null, SettingLevel.ACCOUNT, sectionData);
|
||||
// Remove the section data — shallow-copy to avoid mutating the settings cache reference
|
||||
const updatedSectionData = { ...sectionData };
|
||||
delete updatedSectionData[tag];
|
||||
await SettingsStore.setValue("element.io.prototype.RoomList.CustomSectionData", null, SettingLevel.ACCOUNT, updatedSectionData);
|
||||
}
|
||||
|
||||
@ -14,13 +14,17 @@ import RoomListActions from "../../actions/RoomListActions";
|
||||
import dis from "../../dispatcher/dispatcher";
|
||||
import { getTagsForRoom } from "./getTagsForRoom";
|
||||
import { isCustomSectionTag } from "../../stores/room-list-v3/section";
|
||||
import RoomListStoreV3 from "../../stores/room-list-v3/RoomListStoreV3";
|
||||
|
||||
/**
|
||||
* Toggle tag for a given room.
|
||||
* A room can only be in one section: either a custom section, Favourite, or LowPriority.
|
||||
* Applying any of these will atomically replace the current section tag.
|
||||
*
|
||||
* - For custom section tags: replaces the active space's current custom section tag (if any),
|
||||
* leaving tags from other spaces intact. A room can be in one custom section per space.
|
||||
* - For Favourite/LowPriority: simple toggle of that specific tag, independent of custom sections.
|
||||
*
|
||||
* @param room The room to tag
|
||||
* @param tagId The tag to invert
|
||||
* @param tagId The tag to toggle
|
||||
*/
|
||||
export function tagRoom(room: Room, tagId: TagID): void {
|
||||
if (tagId !== DefaultTagID.Favourite && tagId !== DefaultTagID.LowPriority && !isCustomSectionTag(tagId)) {
|
||||
@ -28,14 +32,25 @@ export function tagRoom(room: Room, tagId: TagID): void {
|
||||
return;
|
||||
}
|
||||
|
||||
// Find the section tag currently applied (Fav, LowPriority, or custom) — at most one exists
|
||||
const currentSectionTag =
|
||||
getTagsForRoom(room).find(
|
||||
(t) => t === DefaultTagID.Favourite || t === DefaultTagID.LowPriority || isCustomSectionTag(t),
|
||||
) ?? null;
|
||||
let removeTag: TagID | null;
|
||||
let addTag: TagID | null;
|
||||
|
||||
if (isCustomSectionTag(tagId)) {
|
||||
// For custom sections: only replace within the active space's custom sections.
|
||||
// Tags from other spaces are left intact.
|
||||
const activeSpaceCustomSectionTags = new Set(
|
||||
RoomListStoreV3.instance.orderedSectionTags.filter((t) => isCustomSectionTag(t)),
|
||||
);
|
||||
const currentSectionTag = getTagsForRoom(room).find((t) => activeSpaceCustomSectionTags.has(t)) ?? null;
|
||||
const isApplied = currentSectionTag === tagId;
|
||||
removeTag = currentSectionTag;
|
||||
addTag = isApplied ? null : tagId;
|
||||
} else {
|
||||
// For Favourite/LowPriority: simple toggle — independent of custom sections.
|
||||
const isApplied = getTagsForRoom(room).includes(tagId);
|
||||
removeTag = isApplied ? tagId : null;
|
||||
addTag = isApplied ? null : tagId;
|
||||
}
|
||||
|
||||
const isApplied = currentSectionTag === tagId;
|
||||
const removeTag = currentSectionTag;
|
||||
const addTag = isApplied ? null : tagId;
|
||||
dis.dispatch(RoomListActions.tagRoom(room.client, room, removeTag, addTag));
|
||||
}
|
||||
|
||||
@ -38,7 +38,7 @@ 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, { CHATS_TAG, LISTS_UPDATE_EVENT } from "../../stores/room-list-v3/RoomListStoreV3";
|
||||
import { _t } from "../../languageHandler";
|
||||
|
||||
interface RoomItemProps {
|
||||
@ -98,13 +98,18 @@ export class RoomListItemViewModel
|
||||
this.disposables.trackListener(props.room, RoomEvent.Name, this.onRoomChanged);
|
||||
this.disposables.trackListener(props.room, RoomEvent.Tags, this.onRoomChanged);
|
||||
|
||||
const orderSectionsRef = SettingsStore.watchSetting("RoomList.OrderedCustomSections", null, () =>
|
||||
const orderSectionsRef = SettingsStore.watchSetting("element.io.prototype.RoomList.OrderedCustomSections", null, () =>
|
||||
this.onOrderedCustomSectionsChange(),
|
||||
);
|
||||
this.disposables.track(() => {
|
||||
SettingsStore.unwatchSetting(orderSectionsRef);
|
||||
});
|
||||
|
||||
// Rebuild sections when the active space changes (variant-a: sections are scoped per space).
|
||||
// Listen to LISTS_UPDATE_EVENT (not UPDATE_SELECTED_SPACE directly) to guarantee that
|
||||
// RoomListStoreV3 has already called loadCustomSections() and updated orderedSectionTags.
|
||||
this.disposables.trackListener(RoomListStoreV3.instance, LISTS_UPDATE_EVENT, this.onOrderedCustomSectionsChange);
|
||||
|
||||
// Load message preview asynchronously (sync data is already complete)
|
||||
void this.loadAndSetMessagePreview();
|
||||
}
|
||||
@ -423,7 +428,7 @@ export class RoomListItemViewModel
|
||||
* Order follows the canonical section order from RoomListStoreV3.
|
||||
*/
|
||||
private static buildSections(roomTags: Room["tags"]): Section[] {
|
||||
const customSectionData = SettingsStore.getValue("RoomList.CustomSectionData") || {};
|
||||
const customSectionData = SettingsStore.getValue("element.io.prototype.RoomList.CustomSectionData") || {};
|
||||
|
||||
return (
|
||||
RoomListStoreV3.instance.orderedSectionTags
|
||||
|
||||
@ -54,7 +54,7 @@ export class RoomListSectionHeaderViewModel
|
||||
isUnread: false,
|
||||
displaySectionMenu: !isDefaultSection,
|
||||
});
|
||||
const sectionWatherRef = SettingsStore.watchSetting("RoomList.CustomSectionData", null, () =>
|
||||
const sectionWatherRef = SettingsStore.watchSetting("element.io.prototype.RoomList.CustomSectionData", null, () =>
|
||||
this.onCustomSectionDataChange(),
|
||||
);
|
||||
this.disposables.track(() => SettingsStore.unwatchSetting(sectionWatherRef));
|
||||
@ -140,7 +140,7 @@ export class RoomListSectionHeaderViewModel
|
||||
* Handle changes to custom section data.
|
||||
*/
|
||||
private onCustomSectionDataChange(): void {
|
||||
const customSectionData = SettingsStore.getValue("RoomList.CustomSectionData") || {};
|
||||
const customSectionData = SettingsStore.getValue("element.io.prototype.RoomList.CustomSectionData") || {};
|
||||
const sectionData = customSectionData[this.props.tag];
|
||||
if (sectionData) {
|
||||
this.snapshot.merge({ title: sectionData.name });
|
||||
|
||||
@ -284,7 +284,7 @@ export class RoomListViewModel
|
||||
public getSectionHeaderViewModel(tag: string): RoomListSectionHeaderViewModel {
|
||||
if (this.roomSectionHeaderViewModels.has(tag)) return this.roomSectionHeaderViewModels.get(tag)!;
|
||||
|
||||
const customSections = SettingsStore.getValue("RoomList.CustomSectionData");
|
||||
const customSections = SettingsStore.getValue("element.io.prototype.RoomList.CustomSectionData");
|
||||
const title = TAG_TO_TITLE_MAP[tag] || customSections[tag]?.name || tag;
|
||||
const viewModel = new RoomListSectionHeaderViewModel({
|
||||
tag,
|
||||
@ -637,7 +637,7 @@ function computeSections(
|
||||
roomsResult: RoomsResult,
|
||||
isSectionExpanded: (tag: string) => boolean,
|
||||
): { sections: Section[]; isFlatList: boolean } {
|
||||
const customSections = SettingsStore.getValue("RoomList.CustomSectionData");
|
||||
const customSections = SettingsStore.getValue("element.io.prototype.RoomList.CustomSectionData");
|
||||
|
||||
const sections = roomsResult.sections
|
||||
// Only include sections that have rooms or are custom sections (which may be empty but should still be shown)
|
||||
|
||||
@ -832,7 +832,7 @@ describe("RoomListStoreV3", () => {
|
||||
function enableSections(): void {
|
||||
jest.spyOn(SettingsStore, "getValue").mockImplementation((setting: string) => {
|
||||
if (setting === "feature_room_list_sections") return true;
|
||||
if (setting === "RoomList.OrderedCustomSections") return [];
|
||||
if (setting === "element.io.prototype.RoomList.OrderedCustomSections") return {};
|
||||
return false;
|
||||
});
|
||||
}
|
||||
@ -1084,7 +1084,8 @@ describe("RoomListStoreV3", () => {
|
||||
|
||||
let settingsWatcher: (settingName: string) => void = () => {};
|
||||
jest.spyOn(SettingsStore, "watchSetting").mockImplementation((settingName, _roomId, callback) => {
|
||||
if (settingName === "RoomList.OrderedCustomSections") settingsWatcher = callback as () => void;
|
||||
if (settingName === "element.io.prototype.RoomList.OrderedCustomSections")
|
||||
settingsWatcher = callback as () => void;
|
||||
return "watcher-id";
|
||||
});
|
||||
|
||||
@ -1092,7 +1093,7 @@ describe("RoomListStoreV3", () => {
|
||||
|
||||
jest.spyOn(SettingsStore, "getValue").mockImplementation((setting: string) => {
|
||||
if (setting === "feature_room_list_sections") return true;
|
||||
if (setting === "RoomList.OrderedCustomSections") return [];
|
||||
if (setting === "element.io.prototype.RoomList.OrderedCustomSections") return {};
|
||||
return false;
|
||||
});
|
||||
|
||||
@ -1106,12 +1107,13 @@ describe("RoomListStoreV3", () => {
|
||||
rooms[0].tags = { [customTag]: { order: 0 } };
|
||||
jest.spyOn(SettingsStore, "getValue").mockImplementation((setting: string) => {
|
||||
if (setting === "feature_room_list_sections") return true;
|
||||
if (setting === "RoomList.OrderedCustomSections") return [customTag];
|
||||
if (setting === "element.io.prototype.RoomList.OrderedCustomSections")
|
||||
return { [MetaSpace.Home]: [customTag] };
|
||||
return false;
|
||||
});
|
||||
|
||||
// Trigger the settings watcher
|
||||
settingsWatcher("RoomList.OrderedCustomSections");
|
||||
settingsWatcher("element.io.prototype.RoomList.OrderedCustomSections");
|
||||
|
||||
// Now there should be 4 sections (Favourite, custom, Chats, LowPriority)
|
||||
expect(store.getSortedRoomsInActiveSpace().sections).toHaveLength(4);
|
||||
|
||||
@ -10,6 +10,7 @@ import SettingsStore from "../../../../src/settings/SettingsStore";
|
||||
import { createSection, editSection, deleteSection } from "../../../../src/stores/room-list-v3/section";
|
||||
import { CreateSectionDialog } from "../../../../src/components/views/dialogs/CreateSectionDialog";
|
||||
import { RemoveSectionDialog } from "../../../../src/components/views/dialogs/RemoveSectionDialog";
|
||||
import { MetaSpace } from "../../../../src/stores/spaces";
|
||||
|
||||
describe("section", () => {
|
||||
afterEach(() => {
|
||||
@ -23,8 +24,8 @@ describe("section", () => {
|
||||
});
|
||||
|
||||
it.each([
|
||||
[false, "", undefined],
|
||||
[true, "", undefined],
|
||||
[false, "", undefined] as const,
|
||||
[true, "", undefined] as const,
|
||||
[true, "My Section", expect.stringMatching(/^element\.io\.section\./)],
|
||||
])("returns %s when shouldCreate=%s and name='%s'", async (shouldCreate, name, expected) => {
|
||||
jest.spyOn(Modal, "createDialog").mockReturnValue({
|
||||
@ -32,7 +33,7 @@ describe("section", () => {
|
||||
close: jest.fn(),
|
||||
} as any);
|
||||
|
||||
const result = await createSection();
|
||||
const result = await createSection(MetaSpace.Home);
|
||||
expect(result).toEqual(expected);
|
||||
});
|
||||
|
||||
@ -42,7 +43,7 @@ describe("section", () => {
|
||||
close: jest.fn(),
|
||||
} as any);
|
||||
|
||||
const result = await createSection();
|
||||
const result = await createSection(MetaSpace.Home);
|
||||
expect(result).toMatch(/^element\.io\.section\./);
|
||||
});
|
||||
|
||||
@ -52,14 +53,14 @@ describe("section", () => {
|
||||
close: jest.fn(),
|
||||
} as any);
|
||||
|
||||
await createSection();
|
||||
await createSection(MetaSpace.Home);
|
||||
expect(createDialogSpy).toHaveBeenCalledWith(CreateSectionDialog);
|
||||
});
|
||||
|
||||
it("saves section data and ordered sections at ACCOUNT level when confirmed", async () => {
|
||||
const existingTag = "element.io.section.existing";
|
||||
jest.spyOn(SettingsStore, "getValue").mockImplementation((setting) => {
|
||||
if (setting === "RoomList.OrderedCustomSections") return [existingTag];
|
||||
if (setting === "element.io.prototype.RoomList.OrderedCustomSections") return { [MetaSpace.Home]: [existingTag] };
|
||||
return null;
|
||||
});
|
||||
jest.spyOn(Modal, "createDialog").mockReturnValue({
|
||||
@ -68,23 +69,29 @@ describe("section", () => {
|
||||
} as any);
|
||||
const setValueSpy = jest.spyOn(SettingsStore, "setValue").mockResolvedValue(undefined);
|
||||
|
||||
await createSection();
|
||||
await createSection(MetaSpace.Home);
|
||||
|
||||
const customDataCall = setValueSpy.mock.calls.find(([name]) => name === "RoomList.CustomSectionData");
|
||||
const savedSection = Object.values(customDataCall![3] as Record<string, { tag: string; name: string }>)[0];
|
||||
const customDataCall = setValueSpy.mock.calls.find(
|
||||
([name]) => name === "element.io.prototype.RoomList.CustomSectionData",
|
||||
);
|
||||
const savedSection = Object.values(
|
||||
customDataCall![3] as Record<string, { tag: string; name: string; spaceId: string }>,
|
||||
)[0];
|
||||
expect(savedSection.name).toBe("My Section");
|
||||
expect(savedSection.tag).toMatch(/^element\.io\.section\./);
|
||||
|
||||
const orderedCall = setValueSpy.mock.calls.find(([name]) => name === "RoomList.OrderedCustomSections");
|
||||
const savedOrder = orderedCall![3] as string[];
|
||||
expect(savedOrder[0]).toBe(existingTag);
|
||||
expect(savedOrder[1]).toMatch(/^element\.io\.section\./);
|
||||
const orderedCall = setValueSpy.mock.calls.find(
|
||||
([name]) => name === "element.io.prototype.RoomList.OrderedCustomSections",
|
||||
);
|
||||
const savedOrder = orderedCall![3] as Record<string, string[]>;
|
||||
expect(savedOrder[MetaSpace.Home][0]).toBe(existingTag);
|
||||
expect(savedOrder[MetaSpace.Home][1]).toMatch(/^element\.io\.section\./);
|
||||
});
|
||||
});
|
||||
|
||||
describe("editSection", () => {
|
||||
const tag = "element.io.section.abc";
|
||||
const existingSectionData = { [tag]: { tag, name: "Old Name" } };
|
||||
const existingSectionData = { [tag]: { tag, name: "Old Name", spaceId: MetaSpace.Home } };
|
||||
|
||||
beforeEach(() => {
|
||||
jest.spyOn(SettingsStore, "getValue").mockReturnValue(existingSectionData);
|
||||
@ -134,10 +141,10 @@ describe("section", () => {
|
||||
await editSection(tag);
|
||||
|
||||
expect(setValueSpy).toHaveBeenCalledWith(
|
||||
"RoomList.CustomSectionData",
|
||||
"element.io.prototype.RoomList.CustomSectionData",
|
||||
null,
|
||||
expect.anything(),
|
||||
expect.objectContaining({ [tag]: { tag, name: "New Name" } }),
|
||||
expect.objectContaining({ [tag]: { tag, name: "New Name", spaceId: MetaSpace.Home } }),
|
||||
);
|
||||
});
|
||||
});
|
||||
@ -147,11 +154,15 @@ describe("section", () => {
|
||||
const otherTag = "element.io.section.other";
|
||||
|
||||
beforeEach(() => {
|
||||
jest.spyOn(SettingsStore, "getValue").mockImplementation((setting) => {
|
||||
if (setting === "RoomList.CustomSectionData") return { [tag]: { tag, name: "My Section" } };
|
||||
if (setting === "RoomList.OrderedCustomSections") return [otherTag, tag];
|
||||
return null;
|
||||
});
|
||||
jest.spyOn(SettingsStore, "getValue").mockImplementation(
|
||||
(setting): ReturnType<(typeof SettingsStore)["getValue"]> => {
|
||||
if (setting === "element.io.prototype.RoomList.CustomSectionData")
|
||||
return { [tag]: { tag, name: "My Section", spaceId: MetaSpace.Home } };
|
||||
if (setting === "element.io.prototype.RoomList.OrderedCustomSections")
|
||||
return { [MetaSpace.Home]: [otherTag, tag] };
|
||||
return null;
|
||||
},
|
||||
);
|
||||
jest.spyOn(SettingsStore, "setValue").mockResolvedValue(undefined);
|
||||
});
|
||||
|
||||
@ -196,10 +207,14 @@ describe("section", () => {
|
||||
|
||||
await deleteSection(tag, false);
|
||||
|
||||
const orderedCall = setValueSpy.mock.calls.find(([name]) => name === "RoomList.OrderedCustomSections");
|
||||
expect(orderedCall![3]).toEqual([otherTag]);
|
||||
const orderedCall = setValueSpy.mock.calls.find(
|
||||
([name]) => name === "element.io.prototype.RoomList.OrderedCustomSections",
|
||||
);
|
||||
expect(orderedCall![3]).toEqual({ [MetaSpace.Home]: [otherTag] });
|
||||
|
||||
const customDataCall = setValueSpy.mock.calls.find(([name]) => name === "RoomList.CustomSectionData");
|
||||
const customDataCall = setValueSpy.mock.calls.find(
|
||||
([name]) => name === "element.io.prototype.RoomList.CustomSectionData",
|
||||
);
|
||||
expect(customDataCall![3]).not.toHaveProperty(tag);
|
||||
});
|
||||
});
|
||||
|
||||
@ -78,7 +78,7 @@ describe("RoomListItemViewModel", () => {
|
||||
|
||||
jest.spyOn(SettingsStore, "getValue").mockImplementation((setting) => {
|
||||
if (setting === "RoomList.showMessagePreview") return false;
|
||||
if (setting === "RoomList.OrderedCustomSections") return [];
|
||||
if (setting === "element.io.prototype.RoomList.OrderedCustomSections") return {};
|
||||
return false;
|
||||
});
|
||||
jest.spyOn(SettingsStore, "watchSetting").mockImplementation(() => "watcher-id");
|
||||
@ -653,8 +653,8 @@ describe("RoomListItemViewModel", () => {
|
||||
it("should use custom section name from CustomSectionData", () => {
|
||||
jest.spyOn(SettingsStore, "getValue").mockImplementation((setting) => {
|
||||
if (setting === "feature_room_list_sections") return true;
|
||||
if (setting === "RoomList.CustomSectionData")
|
||||
return { [customTag]: { name: "My Custom Section", tag: customTag } };
|
||||
if (setting === "element.io.prototype.RoomList.CustomSectionData")
|
||||
return { [customTag]: { name: "My Custom Section", tag: customTag, spaceId: "!space:server" } };
|
||||
return false;
|
||||
});
|
||||
viewModel = new RoomListItemViewModel({ room, client: matrixClient });
|
||||
@ -666,7 +666,7 @@ describe("RoomListItemViewModel", () => {
|
||||
it("should update sections when OrderedCustomSections setting changes", () => {
|
||||
let watchCallback: CallbackFn<"RoomList.OrderedCustomSections"> = () => {};
|
||||
jest.spyOn(SettingsStore, "watchSetting").mockImplementation((setting, _room, callback) => {
|
||||
if (setting === "RoomList.OrderedCustomSections") watchCallback = callback;
|
||||
if (setting === "element.io.prototype.RoomList.OrderedCustomSections") watchCallback = callback;
|
||||
return "watcher-id";
|
||||
});
|
||||
jest.spyOn(SettingsStore, "getValue").mockImplementation((setting) => {
|
||||
@ -683,7 +683,7 @@ describe("RoomListItemViewModel", () => {
|
||||
CHATS_TAG,
|
||||
DefaultTagID.LowPriority,
|
||||
]);
|
||||
watchCallback("RoomList.OrderedCustomSections", null, null as any, null, null);
|
||||
watchCallback("element.io.prototype.RoomList.OrderedCustomSections", null, null as any, null, null);
|
||||
|
||||
expect(viewModel.getSnapshot().sections.map((s) => s.tag)).toEqual([]);
|
||||
});
|
||||
|
||||
@ -26,7 +26,7 @@ describe("RoomListSectionHeaderViewModel", () => {
|
||||
jest.spyOn(SettingsStore, "watchSetting").mockReturnValue("watcher-id");
|
||||
jest.spyOn(SettingsStore, "unwatchSetting").mockReturnValue(undefined);
|
||||
jest.spyOn(SettingsStore, "getValue").mockImplementation((setting) => {
|
||||
if (setting === "RoomList.OrderedCustomSections") return [];
|
||||
if (setting === "element.io.prototype.RoomList.OrderedCustomSections") return {};
|
||||
return null;
|
||||
});
|
||||
});
|
||||
@ -118,7 +118,7 @@ describe("RoomListSectionHeaderViewModel", () => {
|
||||
|
||||
beforeEach(() => {
|
||||
jest.spyOn(SettingsStore, "watchSetting").mockImplementation((settingName, _roomId, callback) => {
|
||||
if (settingName === "RoomList.CustomSectionData") watchCallback = callback as () => void;
|
||||
if (settingName === "element.io.prototype.RoomList.CustomSectionData") watchCallback = callback as () => void;
|
||||
return "watcher-id";
|
||||
});
|
||||
});
|
||||
@ -133,7 +133,7 @@ describe("RoomListSectionHeaderViewModel", () => {
|
||||
});
|
||||
expect(vm.getSnapshot().title).toBe("Old Title");
|
||||
|
||||
jest.spyOn(SettingsStore, "getValue").mockReturnValue({ [tag]: { tag, name: "New Title" } });
|
||||
jest.spyOn(SettingsStore, "getValue").mockReturnValue({ [tag]: { tag, name: "New Title", spaceId: "!space:server" } });
|
||||
watchCallback();
|
||||
|
||||
expect(vm.getSnapshot().title).toBe("New Title");
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user