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

apowers313 / aiforge / 21002763057

14 Jan 2026 05:00PM UTC coverage: 82.93% (-1.8%) from 84.765%
21002763057

push

github

apowers313
chore: delint

993 of 1165 branches covered (85.24%)

Branch coverage included in aggregate %.

5206 of 6310 relevant lines covered (82.5%)

15.95 hits per line

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

92.68
/src/client/stores/uiStore.ts
1
import { createWithEqualityFn } from 'zustand/traditional';
1✔
2
import { shallow } from 'zustand/shallow';
1✔
3
import { DEFAULT_TERMINAL_THEME_ID } from '@shared/terminalThemes';
1✔
4

5
interface WorkspaceStateUpdate {
6
  sidebarCollapsed?: boolean;
7
  expandedProjectIds?: string[];
8
  activeShellId?: string | null;
9
  terminalFontSize?: number;
10
  terminalTheme?: string;
11
}
12

13
interface UIState {
14
  // Sidebar state
15
  sidebarCollapsed: boolean;
16
  expandedProjectIds: string[];
17

18
  // Modal state
19
  addProjectModalOpen: boolean;
20

21
  // Selection state (UI-only, no server sync needed)
22
  selectedProjectId: string | null;
23
  activeShellId: string | null;
24

25
  // Terminal settings
26
  terminalFontSize: number;
27
  terminalTheme: string;
28

29
  // Shell activity tracking (for AI shell activity indicator)
30
  // Maps shellId -> timestamp of last activity (input or output)
31
  shellActivityTimestamps: Record<string, number>;
32

33
  // Actions
34
  toggleSidebar: () => void;
35
  setSidebarCollapsed: (collapsed: boolean) => void;
36
  openAddProjectModal: () => void;
37
  closeAddProjectModal: () => void;
38
  toggleProjectExpanded: (projectId: string) => void;
39
  setProjectExpanded: (projectId: string, expanded: boolean) => void;
40
  setSelectedProject: (id: string | null) => void;
41
  setActiveShell: (id: string | null) => void;
42
  setTerminalFontSize: (size: number) => void;
43
  setTerminalTheme: (themeId: string) => void;
44
  setWorkspaceState: (state: WorkspaceStateUpdate) => void;
45
  recordShellActivity: (shellId: string) => void;
46
  getShellActivityTimestamp: (shellId: string) => number | undefined;
47
  reset: () => void;
48
}
49

50
const DEFAULT_TERMINAL_FONT_SIZE = 14;
1✔
51

52
const initialState = {
1✔
53
  sidebarCollapsed: false,
1✔
54
  addProjectModalOpen: false,
1✔
55
  expandedProjectIds: [] as string[],
1✔
56
  selectedProjectId: null as string | null,
1✔
57
  activeShellId: null as string | null,
1✔
58
  terminalFontSize: DEFAULT_TERMINAL_FONT_SIZE,
1✔
59
  terminalTheme: DEFAULT_TERMINAL_THEME_ID,
1✔
60
  shellActivityTimestamps: {} as Record<string, number>,
1✔
61
};
1✔
62

63
export const useUIStore = createWithEqualityFn<UIState>()((set) => ({
1✔
64
  ...initialState,
12✔
65

66
  toggleSidebar: (): void => {
12✔
67
    set((state) => ({ sidebarCollapsed: !state.sidebarCollapsed }));
6✔
68
  },
6✔
69

70
  setSidebarCollapsed: (collapsed: boolean): void => {
12✔
71
    set({ sidebarCollapsed: collapsed });
2✔
72
  },
2✔
73

74
  openAddProjectModal: (): void => {
12✔
75
    set({ addProjectModalOpen: true });
7✔
76
  },
7✔
77

78
  closeAddProjectModal: (): void => {
12✔
79
    set({ addProjectModalOpen: false });
3✔
80
  },
3✔
81

82
  toggleProjectExpanded: (projectId: string): void => {
12✔
83
    set((state) => {
9✔
84
      const index = state.expandedProjectIds.indexOf(projectId);
9✔
85
      if (index >= 0) {
9✔
86
        return {
1✔
87
          expandedProjectIds: state.expandedProjectIds.filter((id) => id !== projectId),
1✔
88
        };
1✔
89
      }
1✔
90
      return {
8✔
91
        expandedProjectIds: [...state.expandedProjectIds, projectId],
8✔
92
      };
8✔
93
    });
9✔
94
  },
9✔
95

96
  setProjectExpanded: (projectId: string, expanded: boolean): void => {
12✔
97
    set((state) => {
5✔
98
      const isCurrentlyExpanded = state.expandedProjectIds.includes(projectId);
5✔
99
      if (expanded && !isCurrentlyExpanded) {
5✔
100
        return {
2✔
101
          expandedProjectIds: [...state.expandedProjectIds, projectId],
2✔
102
        };
2✔
103
      }
2✔
104
      if (!expanded && isCurrentlyExpanded) {
5✔
105
        return {
1✔
106
          expandedProjectIds: state.expandedProjectIds.filter((id) => id !== projectId),
1✔
107
        };
1✔
108
      }
1✔
109
      return {};
2✔
110
    });
5✔
111
  },
5✔
112

113
  setSelectedProject: (id: string | null): void => {
12✔
114
    set({ selectedProjectId: id });
2✔
115
  },
2✔
116

117
  setActiveShell: (id: string | null): void => {
12✔
118
    set({ activeShellId: id });
11✔
119
  },
11✔
120

121
  setTerminalFontSize: (size: number): void => {
12✔
122
    set({ terminalFontSize: size });
×
123
  },
×
124

125
  setTerminalTheme: (themeId: string): void => {
12✔
126
    set({ terminalTheme: themeId });
×
127
  },
×
128

129
  setWorkspaceState: (state: WorkspaceStateUpdate): void => {
12✔
130
    set((current) => ({
2✔
131
      sidebarCollapsed: state.sidebarCollapsed ?? current.sidebarCollapsed,
2!
132
      expandedProjectIds: state.expandedProjectIds ?? current.expandedProjectIds,
2!
133
      activeShellId: state.activeShellId !== undefined ? state.activeShellId : current.activeShellId,
2!
134
      terminalFontSize: state.terminalFontSize ?? current.terminalFontSize,
2✔
135
      terminalTheme: state.terminalTheme ?? current.terminalTheme,
2✔
136
    }));
2✔
137
  },
2✔
138

139
  recordShellActivity: (shellId: string): void => {
12✔
140
    set((state) => ({
5✔
141
      shellActivityTimestamps: {
5✔
142
        ...state.shellActivityTimestamps,
5✔
143
        [shellId]: Date.now(),
5✔
144
      },
5✔
145
    }));
5✔
146
  },
5✔
147

148
  getShellActivityTimestamp: (shellId: string): number | undefined => {
12✔
149
    // This is a selector, not an action - but zustand allows it
150
    return useUIStore.getState().shellActivityTimestamps[shellId];
×
151
  },
×
152

153
  reset: (): void => {
12✔
154
    set(initialState);
101✔
155
  },
101✔
156
}), shallow);
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc