Released v1

This commit is contained in:
Steve Cliff
2026-02-12 10:37:19 +00:00
commit b07572fed5
77 changed files with 19518 additions and 0 deletions
+239
View File
@@ -0,0 +1,239 @@
package output
import (
"encoding/json"
"fmt"
"io"
"os"
"reflect"
"text/tabwriter"
"git.franklin.lab/steve.cliff/pcli/model"
)
func Print(data any, format string, w io.Writer) error {
if format == "table" {
return printTable(data, w)
}
return printJSON(data, w)
}
func printJSON(data any, w io.Writer) error {
envelope := model.Envelope{
Data: data,
Error: nil,
}
encoder := json.NewEncoder(w)
encoder.SetIndent("", " ")
return encoder.Encode(envelope)
}
func PrintError(err error, format string, w io.Writer) error {
if format == "table" {
fmt.Fprintf(os.Stderr, "Error: %s\n", err.Error())
return nil
}
errMsg := err.Error()
envelope := model.Envelope{
Data: nil,
Error: &errMsg,
}
encoder := json.NewEncoder(w)
encoder.SetIndent("", " ")
return encoder.Encode(envelope)
}
func PrintErrorWithCommand(err error, format string, w io.Writer, command string) error {
if format == "table" {
fmt.Fprintf(os.Stderr, "Error in %s command: %s\n", command, err.Error())
return nil
}
errMsg := fmt.Sprintf("Error in %s command: %s", command, err.Error())
envelope := model.Envelope{
Data: nil,
Error: &errMsg,
}
encoder := json.NewEncoder(w)
encoder.SetIndent("", " ")
return encoder.Encode(envelope)
}
func printTable(data any, w io.Writer) error {
if data == nil {
return nil
}
tw := tabwriter.NewWriter(w, 0, 0, 2, ' ', 0)
defer tw.Flush()
v := reflect.ValueOf(data)
if v.Kind() == reflect.Slice {
if v.Len() == 0 {
return nil
}
elemType := v.Index(0).Type()
switch elemType.Name() {
case "Project":
return printProjectTable(data.([]model.Project), tw)
case "Board":
return printBoardTable(data.([]model.Board), tw)
case "Card":
return printCardTable(data.([]model.Card), tw)
case "CardWithList":
return printCardWithListTable(data.([]model.CardWithList), tw)
case "Comment":
return printCommentTable(data.([]model.Comment), tw)
case "TaskList":
return printTaskListTable(data.([]model.TaskList), tw)
case "Task":
return printTaskTable(data.([]model.Task), tw)
case "Label":
return printLabelTable(data.([]model.Label), tw)
case "Action":
return printActionTable(data.([]model.Action), tw)
default:
return fmt.Errorf("unsupported slice type for table output: %s", elemType.Name())
}
}
switch data := data.(type) {
case *model.Project:
return printProjectTable([]model.Project{*data}, tw)
case *model.Board:
return printBoardTable([]model.Board{*data}, tw)
case *model.Card:
return printCardTable([]model.Card{*data}, tw)
case *model.Comment:
return printCommentTable([]model.Comment{*data}, tw)
case *model.TaskList:
return printTaskListTable([]model.TaskList{*data}, tw)
case *model.Task:
return printTaskTable([]model.Task{*data}, tw)
case *model.Label:
return printLabelTable([]model.Label{*data}, tw)
case model.StatusSummary:
return printStatusTable(data, tw)
case *model.StatusSummary:
return printStatusTable(*data, tw)
default:
return fmt.Errorf("unsupported type for table output: %T", data)
}
}
func printProjectTable(projects []model.Project, tw *tabwriter.Writer) error {
fmt.Fprintln(tw, "ID\tNAME\tDESCRIPTION\tHIDDEN")
for _, p := range projects {
desc := ""
if p.Description != nil {
desc = *p.Description
}
fmt.Fprintf(tw, "%s\t%s\t%s\t%v\n", p.ID, p.Name, desc, p.IsHidden)
}
return nil
}
func printBoardTable(boards []model.Board, tw *tabwriter.Writer) error {
fmt.Fprintln(tw, "ID\tNAME\tPROJECT_ID\tDEFAULT_VIEW")
for _, b := range boards {
fmt.Fprintf(tw, "%s\t%s\t%s\t%s\n", b.ID, b.Name, b.ProjectID, b.DefaultView)
}
return nil
}
func printCardTable(cards []model.Card, tw *tabwriter.Writer) error {
fmt.Fprintln(tw, "ID\tNAME\tLIST_ID\tTYPE\tCLOSED")
for _, c := range cards {
fmt.Fprintf(tw, "%s\t%s\t%s\t%s\t%v\n", c.ID, c.Name, c.ListID, c.Type, c.IsClosed)
}
return nil
}
func printCardWithListTable(cards []model.CardWithList, tw *tabwriter.Writer) error {
fmt.Fprintln(tw, "ID\tNAME\tLIST\tTYPE\tCLOSED")
for _, c := range cards {
fmt.Fprintf(tw, "%s\t%s\t%s\t%s\t%v\n", c.ID, c.Name, c.ListName, c.Type, c.IsClosed)
}
return nil
}
func printCommentTable(comments []model.Comment, tw *tabwriter.Writer) error {
fmt.Fprintln(tw, "ID\tCARD_ID\tTEXT\tCREATED_AT")
for _, c := range comments {
createdAt := ""
if c.CreatedAt != nil {
createdAt = *c.CreatedAt
}
fmt.Fprintf(tw, "%s\t%s\t%s\t%s\n", c.ID, c.CardID, c.Text, createdAt)
}
return nil
}
func printTaskListTable(taskLists []model.TaskList, tw *tabwriter.Writer) error {
fmt.Fprintln(tw, "ID\tNAME\tCARD_ID\tPOSITION")
for _, tl := range taskLists {
fmt.Fprintf(tw, "%s\t%s\t%s\t%.0f\n", tl.ID, tl.Name, tl.CardID, tl.Position)
}
return nil
}
func printTaskTable(tasks []model.Task, tw *tabwriter.Writer) error {
fmt.Fprintln(tw, "ID\tNAME\tTASK_LIST_ID\tCOMPLETED")
for _, t := range tasks {
fmt.Fprintf(tw, "%s\t%s\t%s\t%v\n", t.ID, t.Name, t.TaskListID, t.IsCompleted)
}
return nil
}
func printLabelTable(labels []model.Label, tw *tabwriter.Writer) error {
fmt.Fprintln(tw, "ID\tNAME\tCOLOR\tBOARD_ID")
for _, l := range labels {
name := ""
if l.Name != nil {
name = *l.Name
}
fmt.Fprintf(tw, "%s\t%s\t%s\t%s\n", l.ID, name, l.Color, l.BoardID)
}
return nil
}
func printActionTable(actions []model.Action, tw *tabwriter.Writer) error {
fmt.Fprintln(tw, "ID\tTYPE\tCARD_ID\tCREATED_AT")
for _, a := range actions {
createdAt := ""
if a.CreatedAt != nil {
createdAt = *a.CreatedAt
}
fmt.Fprintf(tw, "%s\t%s\t%s\t%s\n", a.ID, a.Type, a.CardID, createdAt)
}
return nil
}
func printStatusTable(summary model.StatusSummary, tw *tabwriter.Writer) error {
// Print total board count
fmt.Fprintf(tw, "%d boards\n\n", summary.TotalBoards)
// Print each board with its lists
for i, board := range summary.Boards {
fmt.Fprintf(tw, "Board: %s\n", board.Name)
fmt.Fprintln(tw, "LIST\tCARDS")
for _, list := range board.Lists {
cardsText := fmt.Sprintf("%d", list.OpenCards)
if list.ClosedCards > 0 {
cardsText += fmt.Sprintf(" (%d closed)", list.ClosedCards)
}
fmt.Fprintf(tw, "%s\t%s\n", list.Name, cardsText)
}
// Add blank line between boards (except last one)
if i < len(summary.Boards)-1 {
fmt.Fprintln(tw)
}
}
return nil
}