Allow favorites to be sorted by type. Closes #314.

This commit is contained in:
Jack Kingsman
2026-07-08 14:57:29 -07:00
parent 2fcbefac3b
commit 84e6c34255
3 changed files with 158 additions and 24 deletions
+59 -1
View File
@@ -714,6 +714,60 @@ describe('Sidebar section summaries', () => {
expect(getFavoritesOrder()).toEqual(['Amy', 'Zed']);
});
it('cycles favorites through the four sort orders, grouping by type', () => {
// Mixed-type favorites: a channel (rank 0), two clients (rank 1), a repeater
// (rank 3). Names are chosen so plain-alpha and type-grouped orders differ.
const chan = makeChannel('cd'.repeat(16), 'Zulu');
const alpha = makeContact('11'.repeat(32), 'Alpha', 1, { favorite: true });
const bravo = makeContact('22'.repeat(32), 'Bravo', 1, { favorite: true });
const yankee = makeContact('33'.repeat(32), 'Yankee', 2, { favorite: true }); // repeater
const favChannel = { ...chan, favorite: true };
const props = {
contacts: [alpha, bravo, yankee],
channels: [favChannel],
activeConversation: null,
onSelectConversation: vi.fn(),
onNewMessage: vi.fn(),
lastMessageTimes: {
[getStateKey('contact', alpha.public_key)]: 100,
[getStateKey('contact', bravo.public_key)]: 300, // Bravo more recent than Alpha
},
unreadCounts: {},
mentions: {},
showCracker: false,
crackerRunning: false,
onToggleCracker: vi.fn(),
onMarkAllRead: vi.fn(),
};
const getFavoritesOrder = () =>
screen
.getAllByText(/^(Alpha|Bravo|Yankee|Zulu)$/)
.map((node) => node.textContent)
.filter((text): text is string => Boolean(text));
render(<Sidebar {...props} />);
// recent -> alpha: pure name order regardless of type.
fireEvent.click(screen.getByRole('button', { name: 'Sort Favorites alphabetically' }));
expect(getFavoritesOrder()).toEqual(['Alpha', 'Bravo', 'Yankee', 'Zulu']);
// alpha -> type-recent: group by type (channel, clients, repeater); within the
// client group, more-recent Bravo precedes Alpha.
fireEvent.click(screen.getByRole('button', { name: 'Sort Favorites by type, then recent' }));
expect(getFavoritesOrder()).toEqual(['Zulu', 'Bravo', 'Alpha', 'Yankee']);
// type-recent -> type-alpha: same grouping, clients now A-Z (Alpha before Bravo).
fireEvent.click(
screen.getByRole('button', { name: 'Sort Favorites by type, then alphabetically' })
);
expect(getFavoritesOrder()).toEqual(['Zulu', 'Alpha', 'Bravo', 'Yankee']);
// type-alpha -> recent: cycle wraps back to the recency sort.
expect(screen.getByRole('button', { name: 'Sort Favorites by recent' })).toBeInTheDocument();
});
it('seeds favorites sort from the legacy global sort order when section prefs are missing', () => {
localStorage.setItem('remoteterm-sortOrder', 'alpha');
@@ -746,6 +800,10 @@ describe('Sidebar section summaries', () => {
.filter((text): text is string => Boolean(text));
expect(favoriteRows).toEqual(['Amy', 'Zed']);
expect(screen.getByRole('button', { name: 'Sort Favorites by recent' })).toBeInTheDocument();
// Favorites now cycles recent -> alpha -> type-recent -> type-alpha, so the
// next order after the seeded 'alpha' is the type-grouped recency sort.
expect(
screen.getByRole('button', { name: 'Sort Favorites by type, then recent' })
).toBeInTheDocument();
});
});