Files
skrueckenandCursor efeb4a74a8 Assign readable ticket keys from project code and sequence.
Replace UUID-looking sync labels in TUI and web with keys like TAS-1,
while keeping the remote UUID for task-master matching.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-28 00:09:14 +01:00

90 lines
2.2 KiB
Go

package ticket
import (
"time"
"unicode"
)
// Status represents the workflow state of a ticket.
type Status string
const (
StatusTodo Status = "todo"
StatusInProgress Status = "in_progress"
StatusDone Status = "done"
)
// AllStatuses is the ordered list shown in the status picker.
var AllStatuses = []Status{StatusTodo, StatusInProgress, StatusDone}
// Label returns a short display label for the status.
func (s Status) Label() string {
switch s {
case StatusTodo:
return "OPEN"
case StatusInProgress:
return "WIP"
case StatusDone:
return "DONE"
default:
return string(s)
}
}
// Shortcut returns the status-menu hotkey (first letter of the label).
func (s Status) Shortcut() rune {
label := s.Label()
if label == "" {
return 0
}
return unicode.ToLower([]rune(label)[0])
}
// Index returns the position in AllStatuses, or 0 if unknown.
func (s Status) Index() int {
for i, st := range AllStatuses {
if st == s {
return i
}
}
return 0
}
const (
// SourceYouTrack marks tickets imported from YouTrack.
SourceYouTrack = "youtrack"
// SourceTaskMaster marks tickets synced from a task-master server.
SourceTaskMaster = "taskmaster"
)
// Ticket is the domain model for a work item.
// Title (headline) and Description are Markdown.
type Ticket struct {
ID string `json:"id"`
Title string `json:"title"`
Description string `json:"description,omitempty"`
Status Status `json:"status"`
ProjectID string `json:"projectId"`
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
// Readable key assigned by the server (e.g. "ABC-42"). Optional on local-only tickets.
Number int `json:"number,omitempty"`
Key string `json:"key,omitempty"`
// External sync (optional). Local UUID stays in ID.
Source string `json:"source,omitempty"`
ExternalID string `json:"externalId,omitempty"`
ExternalURL string `json:"externalUrl,omitempty"`
SyncedAt time.Time `json:"syncedAt,omitempty"`
}
// DisplayID returns the human-readable ticket label for UI.
// Prefers the server key; falls back to ExternalID (e.g. YouTrack idReadable).
func (t Ticket) DisplayID() string {
if t.Key != "" {
return t.Key
}
return t.ExternalID
}