Allow deleting projects from the project picker with x/X.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Skruecken
2026-10-19 13:59:20 +02:00
co-authored by Cursor
parent f3a592f3ea
commit c5920ffd54
9 changed files with 288 additions and 29 deletions
+22
View File
@@ -153,6 +153,28 @@ func (s *JSONTimeStore) Delete(id string) error {
return s.writeUnlocked(out)
}
// DeleteByProject removes all time entries for a project.
func (s *JSONTimeStore) DeleteByProject(projectID string) error {
s.mu.Lock()
defer s.mu.Unlock()
if projectID == "" {
return fmt.Errorf("projectId is required")
}
entries, err := s.readUnlocked()
if err != nil {
return err
}
out := make([]TimeEntry, 0, len(entries))
for _, e := range entries {
if e.ProjectID == projectID {
continue
}
out = append(out, e)
}
return s.writeUnlocked(out)
}
// SumByTicket returns total duration for a ticket.
func (s *JSONTimeStore) SumByTicket(ticketID string) (time.Duration, error) {
entries, err := s.ListByTicket(ticketID)
+22
View File
@@ -69,3 +69,25 @@ func TestJSONTimeStoreRoundTrip(t *testing.T) {
t.Fatalf("after delete: %v len=%d path=%s", err, len(list), filepath.Join(dir, "time_entries.json"))
}
}
func TestJSONTimeStoreDeleteByProject(t *testing.T) {
dir := t.TempDir()
store := ticket.NewJSONTimeStore(dir)
for _, e := range []ticket.TimeEntry{
{TicketID: "a", ProjectID: "p1", Duration: time.Hour, Source: ticket.SourceManual},
{TicketID: "b", ProjectID: "p1", Duration: time.Minute, Source: ticket.SourceManual},
{TicketID: "c", ProjectID: "p2", Duration: 30 * time.Minute, Source: ticket.SourceManual},
} {
if _, err := store.Create(e); err != nil {
t.Fatal(err)
}
}
if err := store.DeleteByProject("p1"); err != nil {
t.Fatal(err)
}
list, err := store.List()
if err != nil || len(list) != 1 || list[0].ProjectID != "p2" {
t.Fatalf("after DeleteByProject: %v %+v", err, list)
}
}
+1
View File
@@ -9,6 +9,7 @@ type TimeStore interface {
Create(e TimeEntry) (TimeEntry, error)
Update(e TimeEntry) error
Delete(id string) error
DeleteByProject(projectID string) error
SumByTicket(ticketID string) (time.Duration, error)
LoadActiveTimer() (*ActiveTimer, error)