Files
LazyPM/internal/models/beads.go
2026-03-11 15:31:47 +01:00

161 lines
4.2 KiB
Go

package models
import (
"fmt"
"os"
"strings"
"text/tabwriter"
"unicode"
"charm.land/lipgloss/v2"
"github.com/muesli/reflow/truncate"
"github.com/steveyegge/beads"
)
type (
Issue = beads.Issue
Status = beads.Status
IssueType = beads.IssueType
Dependency = beads.Dependency
DependencyType = beads.DependencyType
Label = beads.Label
Comment = beads.Comment
Event = beads.Event
EventType = beads.EventType
BlockedIssue = beads.BlockedIssue
TreeNode = beads.TreeNode
IssueFilter = beads.IssueFilter
WorkFilter = beads.WorkFilter
StaleFilter = beads.StaleFilter
DependencyCounts = beads.DependencyCounts
IssueWithCounts = beads.IssueWithCounts
SortPolicy = beads.SortPolicy
EpicStatus = beads.EpicStatus
)
// Status constants
const (
StatusOpen = beads.StatusOpen
StatusInProgress = beads.StatusInProgress
StatusBlocked = beads.StatusBlocked
StatusDeferred = beads.StatusDeferred
StatusClosed = beads.StatusClosed
StatusReadyToSprint Status = "ready_to_sprint"
)
// IssueType constants
const (
TypeBug = beads.TypeBug
TypeFeature = beads.TypeFeature
TypeTask = beads.TypeTask
TypeEpic = beads.TypeEpic
TypeChore = beads.TypeChore
)
// DependencyType constants
const (
DepBlocks = beads.DepBlocks
DepRelated = beads.DepRelated
DepParentChild = beads.DepParentChild
DepDiscoveredFrom = beads.DepDiscoveredFrom
DepConditionalBlocks = beads.DepConditionalBlocks // B runs only if A fails (bd-kzda)
)
// SortPolicy constants
const (
SortPolicyHybrid = beads.SortPolicyHybrid
SortPolicyPriority = beads.SortPolicyPriority
SortPolicyOldest = beads.SortPolicyOldest
)
// EventType constants
const (
EventCreated = beads.EventCreated
EventUpdated = beads.EventUpdated
EventStatusChanged = beads.EventStatusChanged
EventCommented = beads.EventCommented
EventClosed = beads.EventClosed
EventReopened = beads.EventReopened
EventDependencyAdded = beads.EventDependencyAdded
EventDependencyRemoved = beads.EventDependencyRemoved
EventLabelAdded = beads.EventLabelAdded
EventLabelRemoved = beads.EventLabelRemoved
EventCompacted = beads.EventCompacted
)
func IssueString(issue Issue) string {
labelStyle := lipgloss.NewStyle().
Bold(true).Foreground(lipgloss.Color("5"))
titleStyle := lipgloss.NewStyle().
Bold(true).Foreground(lipgloss.Color("6"))
boxStyle := lipgloss.NewStyle().Padding(1)
line := func(label, value string) string {
return labelStyle.Render(label) + ": " + value + "\t"
}
content := lipgloss.JoinVertical(
lipgloss.Left,
line("Title", titleStyle.Render(issue.Title)+"\t"+line("Assignee", issue.Assignee)),
line("ID", issue.ID+"\t"+line("Type", string(issue.IssueType))+line("Status", string(issue.Status))+line("Priority", fmt.Sprintf("%d", issue.Priority))),
line("Description", "\n"+issue.Description),
)
return boxStyle.Render(content)
}
func IssuesPtrToIssues(issuePtr []*Issue) []Issue {
issues := make([]Issue, 0, len(issuePtr))
for _, issuePtr := range issuePtr {
if issuePtr != nil {
issues = append(issues, *issuePtr)
}
}
return issues
}
func sanitizeCell(s string) string {
s = strings.Map(func(r rune) rune {
switch r {
case '\n', '\r', '\t':
return ' '
default:
return r
}
}, s)
return strings.Join(strings.FieldsFunc(s, unicode.IsSpace), " ")
}
func FormatIssueRow(issue Issue) string {
id := truncate.String(sanitizeCell(issue.ID), 10)
title := truncate.StringWithTail(sanitizeCell(issue.Title), 35, "...")
description := truncate.StringWithTail(sanitizeCell(issue.Description), 40, "...")
status := sanitizeCell(string(issue.Status))
issueType := sanitizeCell(string(issue.IssueType))
return fmt.Sprintf(
"%s\t%s\t%s\t%s\t%s\t%d",
id,
title,
description,
status,
issueType,
issue.Priority,
)
}
func PrintIssues(issues []Issue) {
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
fmt.Fprintln(w, "ID\tTITLE\tDESCRIPTION\tSTATUS\tTYPE\tPRIORITY")
for _, issue := range issues {
fmt.Fprintln(w, FormatIssueRow(issue))
}
_ = w.Flush()
}