cli + tui to publish to leaflet (wip) & manage tasks, notes & watch/read lists 馃崈
charm leaflet readability golang
29
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 119 lines 3.0 kB view raw
1package ui 2 3import ( 4 "context" 5 "fmt" 6 "io" 7 "time" 8 9 "github.com/stormlightlabs/noteleaf/internal/repo" 10) 11 12// ProjectRepository interface for dependency injection in tests 13type ProjectRepository interface { 14 GetProjects(ctx context.Context) ([]repo.ProjectSummary, error) 15} 16 17func pluralizeCount(count int) string { 18 if count == 1 { 19 return "" 20 } 21 return "s" 22} 23 24// ProjectSummaryRecord adapts repo.ProjectSummary to work with DataTable 25type ProjectSummaryRecord struct { 26 summary repo.ProjectSummary 27} 28 29func (p *ProjectSummaryRecord) GetField(name string) any { 30 switch name { 31 case "name": 32 return p.summary.Name 33 case "task_count": 34 return p.summary.TaskCount 35 default: 36 return "" 37 } 38} 39 40func (p *ProjectSummaryRecord) GetTableName() string { 41 return "projects" 42} 43 44// Use task count as pseudo-ID since projects don't have IDs 45func (p *ProjectSummaryRecord) GetID() int64 { return int64(p.summary.TaskCount) } 46func (p *ProjectSummaryRecord) SetID(id int64) {} 47func (p *ProjectSummaryRecord) GetCreatedAt() time.Time { return time.Time{} } 48func (p *ProjectSummaryRecord) SetCreatedAt(t time.Time) {} 49func (p *ProjectSummaryRecord) GetUpdatedAt() time.Time { return time.Time{} } 50func (p *ProjectSummaryRecord) SetUpdatedAt(t time.Time) {} 51 52// ProjectDataSource adapts ProjectRepository to work with DataTable 53type ProjectDataSource struct { 54 repo ProjectRepository 55} 56 57func (p *ProjectDataSource) Load(ctx context.Context, opts DataOptions) ([]DataRecord, error) { 58 projects, err := p.repo.GetProjects(ctx) 59 if err != nil { 60 return nil, err 61 } 62 63 records := make([]DataRecord, len(projects)) 64 for i, project := range projects { 65 records[i] = &ProjectSummaryRecord{summary: project} 66 } 67 68 return records, nil 69} 70 71func (p *ProjectDataSource) Count(ctx context.Context, opts DataOptions) (int, error) { 72 projects, err := p.repo.GetProjects(ctx) 73 if err != nil { 74 return 0, err 75 } 76 return len(projects), nil 77} 78 79// NewProjectDataTable creates a new DataTable for browsing projects 80func NewProjectDataTable(repo ProjectRepository, opts DataTableOptions) *DataTable { 81 if opts.Title == "" { 82 opts.Title = "Projects" 83 } 84 85 if len(opts.Fields) == 0 { 86 opts.Fields = []Field{ 87 { 88 Name: "name", 89 Title: "Project Name", 90 Width: 30, 91 }, 92 { 93 Name: "task_count", 94 Title: "Task Count", 95 Width: 15, 96 Formatter: func(value any) string { 97 if count, ok := value.(int); ok { 98 return fmt.Sprintf("%d task%s", count, pluralizeCount(count)) 99 } 100 return fmt.Sprintf("%v", value) 101 }, 102 }, 103 } 104 } 105 106 source := &ProjectDataSource{repo: repo} 107 return NewDataTable(source, opts) 108} 109 110// NewProjectListFromTable creates a ProjectList-compatible interface using DataTable 111func NewProjectListFromTable(repo ProjectRepository, output io.Writer, input io.Reader, static bool) *DataTable { 112 opts := DataTableOptions{ 113 Output: output, 114 Input: input, 115 Static: static, 116 Title: "Projects", 117 } 118 return NewProjectDataTable(repo, opts) 119}