• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

DigitalTolk / ex / 24964032432

26 Apr 2026 06:35PM UTC coverage: 90.069% (-0.3%) from 90.372%
24964032432

Pull #13

github

web-flow
Merge 391ad3cab into c7a0902b0
Pull Request #13: Docker fixes

1506 of 1799 branches covered (83.71%)

Branch coverage included in aggregate %.

955 of 1086 new or added lines in 34 files covered. (87.94%)

7935 of 8683 relevant lines covered (91.39%)

18.33 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.12
/frontend/src/lib/sidebar-groups.ts
1
import type { UserChannel, UserConversation, SidebarCategory } from '@/types';
2

3
// SidebarItem is the discriminated union the sidebar renders. A user's
4
// favorites and category sections can hold a mix of channels and DMs,
5
// so a single list type lets the renderer treat them uniformly.
6
export type SidebarItem =
7
  | { kind: 'channel'; channel: UserChannel }
8
  | { kind: 'conversation'; conversation: UserConversation };
9

10
export interface SidebarSection {
11
  key: string;
12
  title: string;
13
  items: SidebarItem[];
14
  category?: SidebarCategory;
15
}
16

17
const FAVORITES_KEY = '__favorites__';
12✔
18
const CHANNELS_DEFAULT_KEY = '__channels__';
12✔
19
const DMS_DEFAULT_KEY = '__dms__';
12✔
20

21
export const SidebarSectionKeys = {
12✔
22
  Favorites: FAVORITES_KEY,
23
  Channels: CHANNELS_DEFAULT_KEY,
24
  DirectMessages: DMS_DEFAULT_KEY,
25
} as const;
26

27
// groupSidebarItems lays out the sidebar top-to-bottom:
28
//   - Favorites: every favorited channel + DM mixed.
29
//   - User-defined categories (in position order): channels and DMs
30
//     assigned to that category, mixed.
31
//   - "Channels": uncategorised, unfavorited channels.
32
//   - "Direct Messages": uncategorised, unfavorited DMs/groups.
33
//
34
// A favorited item appears ONLY in Favorites — never duplicated under
35
// its category. Stale categoryIDs (deleted category) fall through to
36
// the appropriate default section, which the delete flow relies on.
37
export function groupSidebarItems(
38
  channels: UserChannel[],
39
  conversations: UserConversation[],
40
  categories: SidebarCategory[],
41
): SidebarSection[] {
42
  const sections: SidebarSection[] = [];
95✔
43

44
  const favItems: SidebarItem[] = [
95✔
45
    ...channels.filter((c) => c.favorite).map((c): SidebarItem => ({ kind: 'channel', channel: c })),
178✔
46
    ...conversations.filter((c) => c.favorite).map((c): SidebarItem => ({ kind: 'conversation', conversation: c })),
61✔
47
  ];
48
  sections.push({ key: FAVORITES_KEY, title: 'Favorites', items: favItems });
95✔
49

50
  const sortedCats = [...categories].sort((a, b) => {
95✔
51
    if (a.position !== b.position) return a.position - b.position;
22!
NEW
52
    return a.id.localeCompare(b.id);
×
53
  });
54
  const knownCategoryIDs = new Set(categories.map((c) => c.id));
95✔
55
  for (const cat of sortedCats) {
95✔
56
    const items: SidebarItem[] = [
48✔
57
      ...channels
58
        .filter((c) => !c.favorite && c.categoryID === cat.id)
178✔
59
        .map((c): SidebarItem => ({ kind: 'channel', channel: c })),
45✔
60
      ...conversations
61
        .filter((c) => !c.favorite && c.categoryID === cat.id)
4✔
62
        .map((c): SidebarItem => ({ kind: 'conversation', conversation: c })),
1✔
63
    ];
64
    sections.push({ key: cat.id, title: cat.name, category: cat, items });
48✔
65
  }
66

67
  // Default Channels: unfavorited and either uncategorised or pointing at
68
  // a deleted category.
69
  const channelsDefault = channels
95✔
70
    .filter((c) => !c.favorite && (!c.categoryID || !knownCategoryIDs.has(c.categoryID)))
178✔
71
    .map((c): SidebarItem => ({ kind: 'channel', channel: c }));
110✔
72
  sections.push({ key: CHANNELS_DEFAULT_KEY, title: 'Channels', items: channelsDefault });
95✔
73

74
  const dmsDefault = conversations
95✔
75
    .filter((c) => !c.favorite && (!c.categoryID || !knownCategoryIDs.has(c.categoryID)))
61✔
76
    .map((c): SidebarItem => ({ kind: 'conversation', conversation: c }));
58✔
77
  sections.push({ key: DMS_DEFAULT_KEY, title: 'Direct Messages', items: dmsDefault });
95✔
78

79
  return sections;
95✔
80
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc