Allow moving tickets between projects with P.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -146,6 +146,73 @@ func (s *JSONStore) Update(t Ticket) error {
|
||||
return s.writeUnlocked(t.ProjectID, tickets)
|
||||
}
|
||||
|
||||
// Move relocates a ticket to another project directory.
|
||||
func (s *JSONStore) Move(id, toProjectID string) (Ticket, error) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
if id == "" {
|
||||
return Ticket{}, fmt.Errorf("ticket id is required")
|
||||
}
|
||||
if toProjectID == "" {
|
||||
return Ticket{}, fmt.Errorf("projectId is required")
|
||||
}
|
||||
|
||||
projects, err := os.ReadDir(filepath.Join(s.dataDir, "projects"))
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return Ticket{}, fmt.Errorf("ticket %s: not found", id)
|
||||
}
|
||||
return Ticket{}, fmt.Errorf("list projects: %w", err)
|
||||
}
|
||||
|
||||
var found Ticket
|
||||
fromProject := ""
|
||||
for _, p := range projects {
|
||||
if !p.IsDir() {
|
||||
continue
|
||||
}
|
||||
tickets, err := s.readUnlocked(p.Name())
|
||||
if err != nil {
|
||||
return Ticket{}, err
|
||||
}
|
||||
for i, t := range tickets {
|
||||
if t.ID != id {
|
||||
continue
|
||||
}
|
||||
found = t
|
||||
fromProject = p.Name()
|
||||
tickets = append(tickets[:i], tickets[i+1:]...)
|
||||
if err := s.writeUnlocked(fromProject, tickets); err != nil {
|
||||
return Ticket{}, err
|
||||
}
|
||||
break
|
||||
}
|
||||
if fromProject != "" {
|
||||
break
|
||||
}
|
||||
}
|
||||
if fromProject == "" {
|
||||
return Ticket{}, fmt.Errorf("ticket %s: not found", id)
|
||||
}
|
||||
|
||||
found.ProjectID = toProjectID
|
||||
found.UpdatedAt = time.Now().UTC()
|
||||
|
||||
if err := os.MkdirAll(s.projectPath(toProjectID), 0o755); err != nil {
|
||||
return Ticket{}, fmt.Errorf("create project dir: %w", err)
|
||||
}
|
||||
dest, err := s.readUnlocked(toProjectID)
|
||||
if err != nil {
|
||||
return Ticket{}, err
|
||||
}
|
||||
dest = append(dest, found)
|
||||
if err := s.writeUnlocked(toProjectID, dest); err != nil {
|
||||
return Ticket{}, err
|
||||
}
|
||||
return found, nil
|
||||
}
|
||||
|
||||
// Delete removes a ticket by ID from its project's file.
|
||||
func (s *JSONStore) Delete(id string) error {
|
||||
s.mu.Lock()
|
||||
|
||||
Reference in New Issue
Block a user