Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions internal/presenter/format.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ func FormatField(spec FieldSpec, key string, val any, locale Locale) string {
return formatPeople(val)
case "number":
return formatNumber(val, locale)
case "dock":
return formatDock(val)
default:
return formatText(val)
}
Expand Down Expand Up @@ -131,6 +133,39 @@ func formatPeople(val any) string {
return strings.Join(names, ", ")
}

// formatDock formats a project dock (array of tool maps) as a multi-line listing.
func formatDock(val any) string {
arr, ok := val.([]any)
if !ok || len(arr) == 0 {
return ""
}

var lines []string
for _, item := range arr {
m, ok := item.(map[string]any)
if !ok {
continue
}
if enabled, ok := m["enabled"].(bool); ok && !enabled {
continue
}
title, _ := m["title"].(string)
name, _ := m["name"].(string)
id := formatText(m["id"])
if title == "" {
title = name
}
if name != "" && id != "" {
lines = append(lines, fmt.Sprintf("%s (%s, ID: %s)", title, name, id))
} else if name != "" {
lines = append(lines, fmt.Sprintf("%s (%s)", title, name))
} else {
lines = append(lines, title)
}
}
return strings.Join(lines, "\n")
Comment thread
jeremy marked this conversation as resolved.
}
Comment thread
jeremy marked this conversation as resolved.
Comment thread
jeremy marked this conversation as resolved.

// formatPerson formats a single person object (map with "name" field).
func formatPerson(val any) string {
if m, ok := val.(map[string]any); ok {
Expand Down
53 changes: 53 additions & 0 deletions internal/presenter/format_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package presenter

import (
"testing"
)

func TestFormatDock(t *testing.T) {
dock := []any{
map[string]any{"name": "todoset", "title": "To-dos", "enabled": true, "id": float64(1)},
map[string]any{"name": "message_board", "title": "Message Board", "enabled": true, "id": float64(2)},
}

got := formatDock(dock)
want := "To-dos (todoset, ID: 1)\nMessage Board (message_board, ID: 2)"
if got != want {
t.Errorf("formatDock(enabled items) = %q, want %q", got, want)
}
}

func TestFormatDockSkipsDisabled(t *testing.T) {
dock := []any{
map[string]any{"name": "todoset", "title": "To-dos", "enabled": true, "id": float64(1)},
map[string]any{"name": "vault", "title": "Docs & Files", "enabled": false, "id": float64(3)},
}

got := formatDock(dock)
want := "To-dos (todoset, ID: 1)"
if got != want {
t.Errorf("formatDock(with disabled) = %q, want %q", got, want)
}
}

func TestFormatDockDefaultsEnabledWhenAbsent(t *testing.T) {
dock := []any{
map[string]any{"name": "todoset", "title": "To-dos", "id": float64(1)},
map[string]any{"name": "schedule", "title": "Schedule", "id": float64(2)},
}

got := formatDock(dock)
want := "To-dos (todoset, ID: 1)\nSchedule (schedule, ID: 2)"
if got != want {
t.Errorf("formatDock(no enabled field) = %q, want %q", got, want)
}
}

func TestFormatDockEmpty(t *testing.T) {
if got := formatDock([]any{}); got != "" {
t.Errorf("formatDock(empty) = %q, want empty", got)
}
if got := formatDock(nil); got != "" {
t.Errorf("formatDock(nil) = %q, want empty", got)
}
}
6 changes: 5 additions & 1 deletion internal/presenter/schemas/comment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ fields:
role: detail
format: person

app_url:
role: meta
format: text

created_at:
role: meta
emphasis: muted
Expand All @@ -34,7 +38,7 @@ views:
sections:
- fields: [content]
- heading: Metadata
fields: [id, created_at, creator]
fields: [id, app_url, created_at, creator]

affordances:
- action: update
Expand Down
13 changes: 11 additions & 2 deletions internal/presenter/schemas/project.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,21 @@ fields:
role: detail
format: text

dock:
role: body
format: dock

app_url:
role: meta
format: text

created_at:
role: meta
emphasis: muted
format: relative_time

id:
role: meta
emphasis: muted

views:
list:
Expand All @@ -46,8 +53,10 @@ views:
- fields: [name, description]
- heading: Info
fields: [status, bookmarked]
- heading: Dock
fields: [dock]
- heading: Metadata
fields: [id, created_at]
fields: [id, app_url, created_at]
compact:
show: [name, status]
inline: true
6 changes: 5 additions & 1 deletion internal/presenter/schemas/todo.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ fields:
format: people
collapse: true

app_url:
role: meta
format: text

created_at:
role: meta
emphasis: muted
Expand All @@ -63,7 +67,7 @@ views:
- heading: Status
fields: [completed, due_on, assignees]
- heading: Metadata
fields: [id, created_at]
fields: [id, app_url, created_at]
compact:
show: [content, completed]
inline: true
Expand Down
6 changes: 5 additions & 1 deletion internal/presenter/schemas/todolist.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ fields:
role: detail
format: number

app_url:
role: meta
format: text

created_at:
role: meta
emphasis: muted
Expand All @@ -55,4 +59,4 @@ views:
- heading: Status
fields: [completed, completed_ratio, comments_count]
- heading: Metadata
fields: [id, created_at]
fields: [id, app_url, created_at]
Loading