@@ -146,6 +146,188 @@ func TestProjectHandlerSnapshot(t *testing.T) {
146146 }
147147}
148148
149+ func TestProjectTabStatusFiltersRows (t * testing.T ) {
150+ m := newTestModelWithStore (t )
151+ types , _ := m .store .ProjectTypes ()
152+
153+ for _ , p := range []data.Project {
154+ {
155+ Title : "Kitchen Plan" ,
156+ ProjectTypeID : types [0 ].ID ,
157+ Status : data .ProjectStatusPlanned ,
158+ },
159+ {
160+ Title : "Fence Done" ,
161+ ProjectTypeID : types [0 ].ID ,
162+ Status : data .ProjectStatusCompleted ,
163+ },
164+ {
165+ Title : "Basement Work" ,
166+ ProjectTypeID : types [0 ].ID ,
167+ Status : data .ProjectStatusInProgress ,
168+ },
169+ {
170+ Title : "Old Patio Idea" ,
171+ ProjectTypeID : types [0 ].ID ,
172+ Status : data .ProjectStatusAbandoned ,
173+ },
174+ } {
175+ if err := m .store .CreateProject (p ); err != nil {
176+ t .Fatalf ("CreateProject(%q): %v" , p .Title , err )
177+ }
178+ }
179+
180+ m .active = tabIndex (tabProjects )
181+ if err := m .reloadActiveTab (); err != nil {
182+ t .Fatalf ("reloadActiveTab: %v" , err )
183+ }
184+ tab := m .activeTab ()
185+ if tab == nil {
186+ t .Fatal ("expected active projects tab" )
187+ }
188+ if len (tab .Rows ) != 4 {
189+ t .Fatalf ("expected 4 rows before filtering, got %d" , len (tab .Rows ))
190+ }
191+
192+ tab .HideCompleted = true
193+ if err := m .reloadActiveTab (); err != nil {
194+ t .Fatalf ("reloadActiveTab with HideCompleted: %v" , err )
195+ }
196+ if len (tab .Rows ) != 3 {
197+ t .Fatalf ("expected 3 rows with completed hidden, got %d" , len (tab .Rows ))
198+ }
199+ for i , cells := range tab .CellRows {
200+ if len (cells ) > 3 && cells [3 ].Value == data .ProjectStatusCompleted {
201+ t .Fatalf ("row %d still has completed status after filtering" , i )
202+ }
203+ }
204+
205+ tab .HideCompleted = false
206+ tab .HideAbandoned = true
207+ if err := m .reloadActiveTab (); err != nil {
208+ t .Fatalf ("reloadActiveTab with HideAbandoned: %v" , err )
209+ }
210+ if len (tab .Rows ) != 3 {
211+ t .Fatalf ("expected 3 rows with abandoned hidden, got %d" , len (tab .Rows ))
212+ }
213+ for i , cells := range tab .CellRows {
214+ if len (cells ) > 3 && cells [3 ].Value == data .ProjectStatusAbandoned {
215+ t .Fatalf ("row %d still has abandoned status after filtering" , i )
216+ }
217+ }
218+
219+ tab .HideAbandoned = false
220+ tab .HideCompleted = true
221+ tab .HideAbandoned = true
222+ if err := m .reloadActiveTab (); err != nil {
223+ t .Fatalf ("reloadActiveTab with settled filters: %v" , err )
224+ }
225+ if len (tab .Rows ) != 2 {
226+ t .Fatalf ("expected 2 rows with settled hidden, got %d" , len (tab .Rows ))
227+ }
228+ for i , cells := range tab .CellRows {
229+ if len (cells ) <= 3 {
230+ continue
231+ }
232+ status := cells [3 ].Value
233+ if status == data .ProjectStatusCompleted || status == data .ProjectStatusAbandoned {
234+ t .Fatalf ("row %d still has settled status %q after filtering" , i , status )
235+ }
236+ }
237+
238+ tab .HideCompleted = false
239+ tab .HideAbandoned = false
240+ if err := m .reloadActiveTab (); err != nil {
241+ t .Fatalf ("reloadActiveTab after clearing filters: %v" , err )
242+ }
243+ if len (tab .Rows ) != 4 {
244+ t .Fatalf ("expected 4 rows after showing all projects, got %d" , len (tab .Rows ))
245+ }
246+ }
247+
248+ func TestProjectStatusFilterToggleKeysReloadRows (t * testing.T ) {
249+ m := newTestModelWithStore (t )
250+ types , _ := m .store .ProjectTypes ()
251+
252+ if err := m .store .CreateProject (data.Project {
253+ Title : "Done Project" ,
254+ ProjectTypeID : types [0 ].ID ,
255+ Status : data .ProjectStatusCompleted ,
256+ }); err != nil {
257+ t .Fatalf ("CreateProject completed: %v" , err )
258+ }
259+ if err := m .store .CreateProject (data.Project {
260+ Title : "Live Project" ,
261+ ProjectTypeID : types [0 ].ID ,
262+ Status : data .ProjectStatusInProgress ,
263+ }); err != nil {
264+ t .Fatalf ("CreateProject in-progress: %v" , err )
265+ }
266+ if err := m .store .CreateProject (data.Project {
267+ Title : "Abandoned Project" ,
268+ ProjectTypeID : types [0 ].ID ,
269+ Status : data .ProjectStatusAbandoned ,
270+ }); err != nil {
271+ t .Fatalf ("CreateProject abandoned: %v" , err )
272+ }
273+
274+ m .active = tabIndex (tabProjects )
275+ if err := m .reloadActiveTab (); err != nil {
276+ t .Fatalf ("reloadActiveTab: %v" , err )
277+ }
278+ if got := len (m .activeTab ().Rows ); got != 3 {
279+ t .Fatalf ("expected 3 rows before toggles, got %d" , got )
280+ }
281+
282+ sendKey (m , "z" )
283+ if got := len (m .activeTab ().Rows ); got != 2 {
284+ t .Fatalf ("expected 2 rows after hiding completed, got %d" , got )
285+ }
286+ if m .activeTab ().HideCompleted != true {
287+ t .Fatal ("HideCompleted should be enabled after first toggle" )
288+ }
289+
290+ sendKey (m , "a" )
291+ if got := len (m .activeTab ().Rows ); got != 1 {
292+ t .Fatalf ("expected 1 row after hiding abandoned too, got %d" , got )
293+ }
294+ if ! m .activeTab ().HideAbandoned {
295+ t .Fatal ("HideAbandoned should be enabled after toggle" )
296+ }
297+
298+ sendKey (m , "t" )
299+ if got := len (m .activeTab ().Rows ); got != 3 {
300+ t .Fatalf ("expected 3 rows after clearing settled filters, got %d" , got )
301+ }
302+ if m .activeTab ().HideCompleted || m .activeTab ().HideAbandoned {
303+ t .Fatal ("settled toggle should disable both filters when both are active" )
304+ }
305+
306+ sendKey (m , "t" )
307+ if got := len (m .activeTab ().Rows ); got != 1 {
308+ t .Fatalf ("expected 1 row after settled-only filter, got %d" , got )
309+ }
310+ if ! m .activeTab ().HideCompleted || ! m .activeTab ().HideAbandoned {
311+ t .Fatal ("settled toggle should enable both filters" )
312+ }
313+
314+ sendKey (m , "z" )
315+ if m .activeTab ().HideCompleted {
316+ t .Fatal ("HideCompleted should be disabled after toggling z" )
317+ }
318+ if got := len (m .activeTab ().Rows ); got != 2 {
319+ t .Fatalf ("expected 2 rows when only abandoned filter is active, got %d" , got )
320+ }
321+
322+ sendKey (m , "a" )
323+ if m .activeTab ().HideAbandoned {
324+ t .Fatal ("HideAbandoned should be disabled after toggling a" )
325+ }
326+ if got := len (m .activeTab ().Rows ); got != 3 {
327+ t .Fatalf ("expected 3 rows after clearing individual filters, got %d" , got )
328+ }
329+ }
330+
149331// ---------------------------------------------------------------------------
150332// applianceHandler CRUD
151333// ---------------------------------------------------------------------------
0 commit comments