mirror of
https://github.com/vector-im/element-web.git
synced 2026-05-04 11:51:36 +02:00
Unread Sorting - Add option for sorting in OptionsMenuView (#31754)
* Add new sort option * Support new sorting algorithm in vm * Add option item for unread sorter * Add tests
This commit is contained in:
parent
b9cdc0390a
commit
d6d647f56d
@ -51,7 +51,8 @@
|
||||
"sort": "Sort",
|
||||
"sort_type": {
|
||||
"activity": "Activity",
|
||||
"atoz": "A-Z"
|
||||
"atoz": "A-Z",
|
||||
"unread_first": "Unread first"
|
||||
},
|
||||
"space_menu": {
|
||||
"home": "Space home",
|
||||
|
||||
@ -19,7 +19,7 @@ import styles from "./RoomListHeaderView.module.css";
|
||||
/**
|
||||
* The available sorting options for the room list.
|
||||
*/
|
||||
export type SortOption = "recent" | "alphabetical";
|
||||
export type SortOption = "recent" | "alphabetical" | "unread-first";
|
||||
|
||||
export interface RoomListHeaderViewSnapshot {
|
||||
/**
|
||||
|
||||
@ -36,6 +36,7 @@ describe("<OptionMenuView />", () => {
|
||||
|
||||
expect(screen.getByRole("menuitemradio", { name: "A-Z" })).toBeChecked();
|
||||
expect(screen.getByRole("menuitemradio", { name: "Activity" })).not.toBeChecked();
|
||||
expect(screen.getByRole("menuitemradio", { name: "Unread first" })).not.toBeChecked();
|
||||
});
|
||||
|
||||
it("should show Activity selected if activeSortOption is recent", async () => {
|
||||
@ -49,9 +50,25 @@ describe("<OptionMenuView />", () => {
|
||||
await user.click(button);
|
||||
|
||||
expect(screen.getByRole("menuitemradio", { name: "A-Z" })).not.toBeChecked();
|
||||
expect(screen.getByRole("menuitemradio", { name: "Unread first" })).not.toBeChecked();
|
||||
expect(screen.getByRole("menuitemradio", { name: "Activity" })).toBeChecked();
|
||||
});
|
||||
|
||||
it("should show `Unread First` selected if activeSortOption is unread-first", async () => {
|
||||
const user = userEvent.setup();
|
||||
|
||||
const vm = new MockedViewModel({ ...defaultSnapshot, activeSortOption: "unread-first" });
|
||||
render(<OptionMenuView vm={vm} />);
|
||||
|
||||
// Open the menu
|
||||
const button = screen.getByRole("button", { name: "Room Options" });
|
||||
await user.click(button);
|
||||
|
||||
expect(screen.getByRole("menuitemradio", { name: "A-Z" })).not.toBeChecked();
|
||||
expect(screen.getByRole("menuitemradio", { name: "Activity" })).not.toBeChecked();
|
||||
expect(screen.getByRole("menuitemradio", { name: "Unread first" })).toBeChecked();
|
||||
});
|
||||
|
||||
it("should sort A to Z", async () => {
|
||||
const user = userEvent.setup();
|
||||
|
||||
@ -78,6 +95,19 @@ describe("<OptionMenuView />", () => {
|
||||
expect(vm.sort).toHaveBeenCalledWith("recent");
|
||||
});
|
||||
|
||||
it("should sort by unread first", async () => {
|
||||
const user = userEvent.setup();
|
||||
|
||||
const vm = new MockedViewModel({ ...defaultSnapshot, activeSortOption: "recent" });
|
||||
render(<OptionMenuView vm={vm} />);
|
||||
|
||||
await user.click(screen.getByRole("button", { name: "Room Options" }));
|
||||
|
||||
await user.click(screen.getByRole("menuitemradio", { name: "Unread first" }));
|
||||
|
||||
expect(vm.sort).toHaveBeenCalledWith("unread-first");
|
||||
});
|
||||
|
||||
it("should toggle message preview", async () => {
|
||||
const user = userEvent.setup();
|
||||
|
||||
|
||||
@ -60,6 +60,11 @@ export function OptionMenuView({ vm }: OptionMenuViewProps): JSX.Element {
|
||||
checked={activeSortOption === "recent"}
|
||||
onSelect={() => vm.sort("recent")}
|
||||
/>
|
||||
<RadioMenuItem
|
||||
label={_t("room_list|sort_type|unread_first")}
|
||||
checked={activeSortOption === "unread-first"}
|
||||
onSelect={() => vm.sort("unread-first")}
|
||||
/>
|
||||
<RadioMenuItem
|
||||
label={_t("room_list|sort_type|atoz")}
|
||||
checked={activeSortOption === "alphabetical"}
|
||||
|
||||
@ -170,7 +170,18 @@ export class RoomListHeaderViewModel
|
||||
};
|
||||
|
||||
public sort = (option: SortOption): void => {
|
||||
const sortingAlgorithm = option === "recent" ? SortingAlgorithm.Recency : SortingAlgorithm.Alphabetic;
|
||||
let sortingAlgorithm: SortingAlgorithm;
|
||||
switch (option) {
|
||||
case "alphabetical":
|
||||
sortingAlgorithm = SortingAlgorithm.Alphabetic;
|
||||
break;
|
||||
case "recent":
|
||||
sortingAlgorithm = SortingAlgorithm.Recency;
|
||||
break;
|
||||
case "unread-first":
|
||||
sortingAlgorithm = SortingAlgorithm.Unread;
|
||||
break;
|
||||
}
|
||||
RoomListStoreV3.instance.resort(sortingAlgorithm);
|
||||
this.snapshot.merge({ activeSortOption: option });
|
||||
};
|
||||
@ -192,8 +203,20 @@ export class RoomListHeaderViewModel
|
||||
*/
|
||||
function getInitialSnapshot(spaceStore: SpaceStoreClass, matrixClient: MatrixClient): RoomListHeaderViewSnapshot {
|
||||
const sortingAlgorithm = SettingsStore.getValue("RoomList.preferredSorting");
|
||||
const activeSortOption =
|
||||
sortingAlgorithm === SortingAlgorithm.Recency ? ("recent" as const) : ("alphabetical" as const);
|
||||
|
||||
let activeSortOption: SortOption;
|
||||
switch (sortingAlgorithm) {
|
||||
case SortingAlgorithm.Alphabetic:
|
||||
activeSortOption = "alphabetical";
|
||||
break;
|
||||
case SortingAlgorithm.Recency:
|
||||
activeSortOption = "recent";
|
||||
break;
|
||||
case SortingAlgorithm.Unread:
|
||||
activeSortOption = "unread-first";
|
||||
break;
|
||||
}
|
||||
|
||||
const isMessagePreviewEnabled = SettingsStore.getValue("RoomList.showMessagePreview");
|
||||
|
||||
return {
|
||||
|
||||
@ -271,6 +271,7 @@ describe("RoomListHeaderViewModel", () => {
|
||||
it.each([
|
||||
["recent" as const, SortingAlgorithm.Recency],
|
||||
["alphabetical" as const, SortingAlgorithm.Alphabetic],
|
||||
["unread-first" as const, SortingAlgorithm.Unread],
|
||||
])("should resort when sort is called with '%s'", (option, expectedAlgorithm) => {
|
||||
const resortSpy = jest.spyOn(RoomListStoreV3.instance, "resort").mockImplementation(jest.fn());
|
||||
vm = new RoomListHeaderViewModel({ matrixClient, spaceStore: SpaceStore.instance });
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user