Introduces the web backend (auth, RBAC, project tokens, revisions), YouTrack-or-taskmaster backend choice in the TUI, and a first-pass embedded Svelte UI. The frontend is functional but needs a major rework. Co-authored-by: Cursor <cursoragent@cursor.com>
77 lines
1.8 KiB
Go
77 lines
1.8 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"`
|
|
|
|
// 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"`
|
|
}
|