Use new table formatter everywhere (#3544)

This commit is contained in:
Dean Sheather
2022-08-19 02:41:00 +10:00
committed by GitHub
parent c43297937b
commit 3610402cd8
13 changed files with 199 additions and 198 deletions

View File

@ -90,7 +90,7 @@ func DisplayTable(out any, sort string, filterColumns []string) (string, error)
sort = strings.ToLower(strings.ReplaceAll(sort, "_", " ")) sort = strings.ToLower(strings.ReplaceAll(sort, "_", " "))
h, ok := headersMap[sort] h, ok := headersMap[sort]
if !ok { if !ok {
return "", xerrors.Errorf("specified sort column %q not found in table headers, available columns are %q", sort, strings.Join(headersRaw, `", "`)) return "", xerrors.Errorf(`specified sort column %q not found in table headers, available columns are "%v"`, sort, strings.Join(headersRaw, `", "`))
} }
// Autocorrect // Autocorrect
@ -101,7 +101,7 @@ func DisplayTable(out any, sort string, filterColumns []string) (string, error)
column := strings.ToLower(strings.ReplaceAll(column, "_", " ")) column := strings.ToLower(strings.ReplaceAll(column, "_", " "))
h, ok := headersMap[column] h, ok := headersMap[column]
if !ok { if !ok {
return "", xerrors.Errorf("specified filter column %q not found in table headers, available columns are %q", sort, strings.Join(headersRaw, `", "`)) return "", xerrors.Errorf(`specified filter column %q not found in table headers, available columns are "%v"`, sort, strings.Join(headersRaw, `", "`))
} }
// Autocorrect // Autocorrect
@ -158,6 +158,10 @@ func DisplayTable(out any, sort string, filterColumns []string) (string, error)
if val != nil { if val != nil {
v = val.Format(time.Stamp) v = val.Format(time.Stamp)
} }
case fmt.Stringer:
if val != nil {
v = val.String()
}
} }
rowSlice[i] = v rowSlice[i] = v
@ -301,19 +305,3 @@ func valueToTableMap(val reflect.Value) (map[string]any, error) {
return row, nil return row, nil
} }
func ValidateColumns(all, given []string) error {
for _, col := range given {
found := false
for _, c := range all {
if strings.EqualFold(strings.ReplaceAll(col, "_", " "), c) {
found = true
break
}
}
if !found {
return fmt.Errorf("unknown column: %s", col)
}
}
return nil
}

View File

@ -1,6 +1,7 @@
package cliui_test package cliui_test
import ( import (
"fmt"
"log" "log"
"strings" "strings"
"testing" "testing"
@ -12,6 +13,16 @@ import (
"github.com/coder/coder/cli/cliui" "github.com/coder/coder/cli/cliui"
) )
type stringWrapper struct {
str string
}
var _ fmt.Stringer = stringWrapper{}
func (s stringWrapper) String() string {
return s.str
}
type tableTest1 struct { type tableTest1 struct {
Name string `table:"name"` Name string `table:"name"`
NotIncluded string // no table tag NotIncluded string // no table tag
@ -28,7 +39,7 @@ type tableTest1 struct {
} }
type tableTest2 struct { type tableTest2 struct {
Name string `table:"name"` Name stringWrapper `table:"name"`
Age int `table:"age"` Age int `table:"age"`
NotIncluded string `table:"-"` NotIncluded string `table:"-"`
} }
@ -48,21 +59,21 @@ func Test_DisplayTable(t *testing.T) {
Age: 10, Age: 10,
Roles: []string{"a", "b", "c"}, Roles: []string{"a", "b", "c"},
Sub1: tableTest2{ Sub1: tableTest2{
Name: "foo1", Name: stringWrapper{str: "foo1"},
Age: 11, Age: 11,
}, },
Sub2: &tableTest2{ Sub2: &tableTest2{
Name: "foo2", Name: stringWrapper{str: "foo2"},
Age: 12, Age: 12,
}, },
Sub3: tableTest3{ Sub3: tableTest3{
Sub: tableTest2{ Sub: tableTest2{
Name: "foo3", Name: stringWrapper{str: "foo3"},
Age: 13, Age: 13,
}, },
}, },
Sub4: tableTest2{ Sub4: tableTest2{
Name: "foo4", Name: stringWrapper{str: "foo4"},
Age: 14, Age: 14,
}, },
Time: someTime, Time: someTime,
@ -73,18 +84,18 @@ func Test_DisplayTable(t *testing.T) {
Age: 20, Age: 20,
Roles: []string{"a"}, Roles: []string{"a"},
Sub1: tableTest2{ Sub1: tableTest2{
Name: "bar1", Name: stringWrapper{str: "bar1"},
Age: 21, Age: 21,
}, },
Sub2: nil, Sub2: nil,
Sub3: tableTest3{ Sub3: tableTest3{
Sub: tableTest2{ Sub: tableTest2{
Name: "bar3", Name: stringWrapper{str: "bar3"},
Age: 23, Age: 23,
}, },
}, },
Sub4: tableTest2{ Sub4: tableTest2{
Name: "bar4", Name: stringWrapper{str: "bar4"},
Age: 24, Age: 24,
}, },
Time: someTime, Time: someTime,
@ -95,18 +106,18 @@ func Test_DisplayTable(t *testing.T) {
Age: 30, Age: 30,
Roles: nil, Roles: nil,
Sub1: tableTest2{ Sub1: tableTest2{
Name: "baz1", Name: stringWrapper{str: "baz1"},
Age: 31, Age: 31,
}, },
Sub2: nil, Sub2: nil,
Sub3: tableTest3{ Sub3: tableTest3{
Sub: tableTest2{ Sub: tableTest2{
Name: "baz3", Name: stringWrapper{str: "baz3"},
Age: 33, Age: 33,
}, },
}, },
Sub4: tableTest2{ Sub4: tableTest2{
Name: "baz4", Name: stringWrapper{str: "baz4"},
Age: 34, Age: 34,
}, },
Time: someTime, Time: someTime,

View File

@ -5,12 +5,10 @@ import (
"fmt" "fmt"
"strings" "strings"
"github.com/coder/coder/cli/cliui"
"github.com/jedib0t/go-pretty/v6/table"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"golang.org/x/xerrors" "golang.org/x/xerrors"
"github.com/coder/coder/cli/cliui"
"github.com/coder/coder/codersdk" "github.com/coder/coder/codersdk"
) )
@ -38,10 +36,6 @@ func featuresList() *cobra.Command {
Use: "list", Use: "list",
Aliases: []string{"ls"}, Aliases: []string{"ls"},
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
err := cliui.ValidateColumns(featureColumns, columns)
if err != nil {
return err
}
client, err := createClient(cmd) client, err := createClient(cmd)
if err != nil { if err != nil {
return err return err
@ -54,11 +48,14 @@ func featuresList() *cobra.Command {
out := "" out := ""
switch outputFormat { switch outputFormat {
case "table", "": case "table", "":
out = displayFeatures(columns, entitlements.Features) out, err = displayFeatures(columns, entitlements.Features)
if err != nil {
return xerrors.Errorf("render table: %w", err)
}
case "json": case "json":
outBytes, err := json.Marshal(entitlements) outBytes, err := json.Marshal(entitlements)
if err != nil { if err != nil {
return xerrors.Errorf("marshal users to JSON: %w", err) return xerrors.Errorf("marshal features to JSON: %w", err)
} }
out = string(outBytes) out = string(outBytes)
@ -78,35 +75,28 @@ func featuresList() *cobra.Command {
return cmd return cmd
} }
type featureRow struct {
Name string `table:"name"`
Entitlement string `table:"entitlement"`
Enabled bool `table:"enabled"`
Limit *int64 `table:"limit"`
Actual *int64 `table:"actual"`
}
// displayFeatures will return a table displaying all features passed in. // displayFeatures will return a table displaying all features passed in.
// filterColumns must be a subset of the feature fields and will determine which // filterColumns must be a subset of the feature fields and will determine which
// columns to display // columns to display
func displayFeatures(filterColumns []string, features map[string]codersdk.Feature) string { func displayFeatures(filterColumns []string, features map[string]codersdk.Feature) (string, error) {
tableWriter := cliui.Table() rows := make([]featureRow, 0, len(features))
header := table.Row{}
for _, h := range featureColumns {
header = append(header, h)
}
tableWriter.AppendHeader(header)
tableWriter.SetColumnConfigs(cliui.FilterTableColumns(header, filterColumns))
tableWriter.SortBy([]table.SortBy{{
Name: "username",
}})
for name, feat := range features { for name, feat := range features {
tableWriter.AppendRow(table.Row{ rows = append(rows, featureRow{
name, Name: name,
feat.Entitlement, Entitlement: string(feat.Entitlement),
feat.Enabled, Enabled: feat.Enabled,
intOrNil(feat.Limit), Limit: feat.Limit,
intOrNil(feat.Actual), Actual: feat.Actual,
}) })
} }
return tableWriter.Render()
}
func intOrNil(i *int64) string { return cliui.DisplayTable(rows, "name", filterColumns)
if i == nil {
return ""
}
return fmt.Sprintf("%d", *i)
} }

View File

@ -5,7 +5,6 @@ import (
"time" "time"
"github.com/google/uuid" "github.com/google/uuid"
"github.com/jedib0t/go-pretty/v6/table"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/coder/coder/cli/cliui" "github.com/coder/coder/cli/cliui"
@ -14,6 +13,49 @@ import (
"github.com/coder/coder/codersdk" "github.com/coder/coder/codersdk"
) )
type workspaceListRow struct {
Workspace string `table:"workspace"`
Template string `table:"template"`
Status string `table:"status"`
LastBuilt string `table:"last built"`
Outdated bool `table:"outdated"`
StartsAt string `table:"starts at"`
StopsAfter string `table:"stops after"`
}
func workspaceListRowFromWorkspace(now time.Time, usersByID map[uuid.UUID]codersdk.User, workspace codersdk.Workspace) workspaceListRow {
status := codersdk.WorkspaceDisplayStatus(workspace.LatestBuild.Job.Status, workspace.LatestBuild.Transition)
lastBuilt := now.UTC().Sub(workspace.LatestBuild.Job.CreatedAt).Truncate(time.Second)
autostartDisplay := "-"
if !ptr.NilOrEmpty(workspace.AutostartSchedule) {
if sched, err := schedule.Weekly(*workspace.AutostartSchedule); err == nil {
autostartDisplay = fmt.Sprintf("%s %s (%s)", sched.Time(), sched.DaysOfWeek(), sched.Location())
}
}
autostopDisplay := "-"
if !ptr.NilOrZero(workspace.TTLMillis) {
dur := time.Duration(*workspace.TTLMillis) * time.Millisecond
autostopDisplay = durationDisplay(dur)
if !workspace.LatestBuild.Deadline.IsZero() && workspace.LatestBuild.Deadline.After(now) && status == "Running" {
remaining := time.Until(workspace.LatestBuild.Deadline)
autostopDisplay = fmt.Sprintf("%s (%s)", autostopDisplay, relative(remaining))
}
}
user := usersByID[workspace.OwnerID]
return workspaceListRow{
Workspace: user.Username + "/" + workspace.Name,
Template: workspace.TemplateName,
Status: status,
LastBuilt: durationDisplay(lastBuilt),
Outdated: workspace.Outdated,
StartsAt: autostartDisplay,
StopsAfter: autostopDisplay,
}
}
func list() *cobra.Command { func list() *cobra.Command {
var columns []string var columns []string
cmd := &cobra.Command{ cmd := &cobra.Command{
@ -32,10 +74,10 @@ func list() *cobra.Command {
return err return err
} }
if len(workspaces) == 0 { if len(workspaces) == 0 {
_, _ = fmt.Fprintln(cmd.OutOrStdout(), cliui.Styles.Prompt.String()+"No workspaces found! Create one:") _, _ = fmt.Fprintln(cmd.ErrOrStderr(), cliui.Styles.Prompt.String()+"No workspaces found! Create one:")
_, _ = fmt.Fprintln(cmd.OutOrStdout()) _, _ = fmt.Fprintln(cmd.ErrOrStderr())
_, _ = fmt.Fprintln(cmd.OutOrStdout(), " "+cliui.Styles.Code.Render("coder create <name>")) _, _ = fmt.Fprintln(cmd.ErrOrStderr(), " "+cliui.Styles.Code.Render("coder create <name>"))
_, _ = fmt.Fprintln(cmd.OutOrStdout()) _, _ = fmt.Fprintln(cmd.ErrOrStderr())
return nil return nil
} }
users, err := client.Users(cmd.Context(), codersdk.UsersRequest{}) users, err := client.Users(cmd.Context(), codersdk.UsersRequest{})
@ -47,48 +89,18 @@ func list() *cobra.Command {
usersByID[user.ID] = user usersByID[user.ID] = user
} }
tableWriter := cliui.Table()
header := table.Row{"workspace", "template", "status", "last built", "outdated", "starts at", "stops after"}
tableWriter.AppendHeader(header)
tableWriter.SortBy([]table.SortBy{{
Name: "workspace",
}})
tableWriter.SetColumnConfigs(cliui.FilterTableColumns(header, columns))
now := time.Now() now := time.Now()
for _, workspace := range workspaces { displayWorkspaces := make([]workspaceListRow, len(workspaces))
status := codersdk.WorkspaceDisplayStatus(workspace.LatestBuild.Job.Status, workspace.LatestBuild.Transition) for i, workspace := range workspaces {
displayWorkspaces[i] = workspaceListRowFromWorkspace(now, usersByID, workspace)
lastBuilt := time.Now().UTC().Sub(workspace.LatestBuild.Job.CreatedAt).Truncate(time.Second)
autostartDisplay := "-"
if !ptr.NilOrEmpty(workspace.AutostartSchedule) {
if sched, err := schedule.Weekly(*workspace.AutostartSchedule); err == nil {
autostartDisplay = fmt.Sprintf("%s %s (%s)", sched.Time(), sched.DaysOfWeek(), sched.Location())
}
} }
autostopDisplay := "-" out, err := cliui.DisplayTable(displayWorkspaces, "workspace", columns)
if !ptr.NilOrZero(workspace.TTLMillis) { if err != nil {
dur := time.Duration(*workspace.TTLMillis) * time.Millisecond return err
autostopDisplay = durationDisplay(dur)
if !workspace.LatestBuild.Deadline.IsZero() && workspace.LatestBuild.Deadline.After(now) && status == "Running" {
remaining := time.Until(workspace.LatestBuild.Deadline)
autostopDisplay = fmt.Sprintf("%s (%s)", autostopDisplay, relative(remaining))
}
} }
user := usersByID[workspace.OwnerID] _, err = fmt.Fprintln(cmd.OutOrStdout(), out)
tableWriter.AppendRow(table.Row{
user.Username + "/" + workspace.Name,
workspace.TemplateName,
status,
durationDisplay(lastBuilt),
workspace.Outdated,
autostartDisplay,
autostopDisplay,
})
}
_, err = fmt.Fprintln(cmd.OutOrStdout(), tableWriter.Render())
return err return err
}, },
} }

View File

@ -1,11 +1,7 @@
package cli package cli
import ( import (
"github.com/jedib0t/go-pretty/v6/table"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/coder/coder/cli/cliui"
"github.com/coder/coder/codersdk"
) )
func parameters() *cobra.Command { func parameters() *cobra.Command {
@ -30,29 +26,3 @@ func parameters() *cobra.Command {
) )
return cmd return cmd
} }
// displayParameters will return a table displaying all parameters passed in.
// filterColumns must be a subset of the parameter fields and will determine which
// columns to display
func displayParameters(filterColumns []string, params ...codersdk.Parameter) string {
tableWriter := cliui.Table()
header := table.Row{"id", "scope", "scope id", "name", "source scheme", "destination scheme", "created at", "updated at"}
tableWriter.AppendHeader(header)
tableWriter.SetColumnConfigs(cliui.FilterTableColumns(header, filterColumns))
tableWriter.SortBy([]table.SortBy{{
Name: "name",
}})
for _, param := range params {
tableWriter.AppendRow(table.Row{
param.ID.String(),
param.Scope,
param.ScopeID.String(),
param.Name,
param.SourceScheme,
param.DestinationScheme,
param.CreatedAt,
param.UpdatedAt,
})
}
return tableWriter.Render()
}

View File

@ -7,6 +7,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"golang.org/x/xerrors" "golang.org/x/xerrors"
"github.com/coder/coder/cli/cliui"
"github.com/coder/coder/codersdk" "github.com/coder/coder/codersdk"
) )
@ -70,11 +71,16 @@ func parameterList() *cobra.Command {
return xerrors.Errorf("fetch params: %w", err) return xerrors.Errorf("fetch params: %w", err)
} }
_, err = fmt.Fprintln(cmd.OutOrStdout(), displayParameters(columns, params...)) out, err := cliui.DisplayTable(params, "name", columns)
if err != nil {
return xerrors.Errorf("render table: %w", err)
}
_, err = fmt.Fprintln(cmd.OutOrStdout(), out)
return err return err
}, },
} }
cmd.Flags().StringArrayVarP(&columns, "column", "c", []string{"name", "scope", "destination_scheme"}, cmd.Flags().StringArrayVarP(&columns, "column", "c", []string{"name", "scope", "destination scheme"},
"Specify a column to filter in the table.") "Specify a column to filter in the table.")
return cmd return cmd
} }

View File

@ -30,12 +30,17 @@ func templateList() *cobra.Command {
} }
if len(templates) == 0 { if len(templates) == 0 {
_, _ = fmt.Fprintf(cmd.OutOrStdout(), "%s No templates found in %s! Create one:\n\n", caret, color.HiWhiteString(organization.Name)) _, _ = fmt.Fprintf(cmd.ErrOrStderr(), "%s No templates found in %s! Create one:\n\n", caret, color.HiWhiteString(organization.Name))
_, _ = fmt.Fprintln(cmd.OutOrStdout(), color.HiMagentaString(" $ coder templates create <directory>\n")) _, _ = fmt.Fprintln(cmd.ErrOrStderr(), color.HiMagentaString(" $ coder templates create <directory>\n"))
return nil return nil
} }
_, err = fmt.Fprintln(cmd.OutOrStdout(), displayTemplates(columns, templates...)) out, err := displayTemplates(columns, templates...)
if err != nil {
return err
}
_, err = fmt.Fprintln(cmd.OutOrStdout(), out)
return err return err
}, },
} }

View File

@ -57,7 +57,7 @@ func TestTemplateList(t *testing.T) {
pty := ptytest.New(t) pty := ptytest.New(t)
cmd.SetIn(pty.Input()) cmd.SetIn(pty.Input())
cmd.SetOut(pty.Output()) cmd.SetErr(pty.Output())
errC := make(chan error) errC := make(chan error)
go func() { go func() {

View File

@ -4,7 +4,7 @@ import (
"fmt" "fmt"
"time" "time"
"github.com/jedib0t/go-pretty/v6/table" "github.com/google/uuid"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/coder/coder/cli/cliui" "github.com/coder/coder/cli/cliui"
@ -46,35 +46,41 @@ func templates() *cobra.Command {
return cmd return cmd
} }
type templateTableRow struct {
Name string `table:"name"`
CreatedAt string `table:"created at"`
LastUpdated string `table:"last updated"`
OrganizationID uuid.UUID `table:"organization id"`
Provisioner codersdk.ProvisionerType `table:"provisioner"`
ActiveVersionID uuid.UUID `table:"active version id"`
UsedBy string `table:"used by"`
MaxTTL time.Duration `table:"max ttl"`
MinAutostartInterval time.Duration `table:"min autostart"`
}
// displayTemplates will return a table displaying all templates passed in. // displayTemplates will return a table displaying all templates passed in.
// filterColumns must be a subset of the template fields and will determine which // filterColumns must be a subset of the template fields and will determine which
// columns to display // columns to display
func displayTemplates(filterColumns []string, templates ...codersdk.Template) string { func displayTemplates(filterColumns []string, templates ...codersdk.Template) (string, error) {
tableWriter := cliui.Table() rows := make([]templateTableRow, len(templates))
header := table.Row{ for i, template := range templates {
"Name", "Created At", "Last Updated", "Organization ID", "Provisioner",
"Active Version ID", "Used By", "Max TTL", "Min Autostart"}
tableWriter.AppendHeader(header)
tableWriter.SetColumnConfigs(cliui.FilterTableColumns(header, filterColumns))
tableWriter.SortBy([]table.SortBy{{
Name: "name",
}})
for _, template := range templates {
suffix := "" suffix := ""
if template.WorkspaceOwnerCount != 1 { if template.WorkspaceOwnerCount != 1 {
suffix = "s" suffix = "s"
} }
tableWriter.AppendRow(table.Row{
template.Name, rows[i] = templateTableRow{
template.CreatedAt.Format("January 2, 2006"), Name: template.Name,
template.UpdatedAt.Format("January 2, 2006"), CreatedAt: template.CreatedAt.Format("January 2, 2006"),
template.OrganizationID.String(), LastUpdated: template.UpdatedAt.Format("January 2, 2006"),
template.Provisioner, OrganizationID: template.OrganizationID,
template.ActiveVersionID.String(), Provisioner: template.Provisioner,
cliui.Styles.Fuchsia.Render(fmt.Sprintf("%d developer%s", template.WorkspaceOwnerCount, suffix)), ActiveVersionID: template.ActiveVersionID,
(time.Duration(template.MaxTTLMillis) * time.Millisecond).String(), UsedBy: cliui.Styles.Fuchsia.Render(fmt.Sprintf("%d developer%s", template.WorkspaceOwnerCount, suffix)),
(time.Duration(template.MinAutostartIntervalMillis) * time.Millisecond).String(), MaxTTL: (time.Duration(template.MaxTTLMillis) * time.Millisecond),
}) MinAutostartInterval: (time.Duration(template.MinAutostartIntervalMillis) * time.Millisecond),
} }
return tableWriter.Render() }
return cliui.DisplayTable(rows, "name", filterColumns)
} }

View File

@ -3,9 +3,9 @@ package cli
import ( import (
"fmt" "fmt"
"strings" "strings"
"time"
"github.com/google/uuid" "github.com/google/uuid"
"github.com/jedib0t/go-pretty/v6/table"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"golang.org/x/xerrors" "golang.org/x/xerrors"
@ -58,31 +58,44 @@ func templateVersionsList() *cobra.Command {
if err != nil { if err != nil {
return xerrors.Errorf("get template versions by template: %w", err) return xerrors.Errorf("get template versions by template: %w", err)
} }
_, err = fmt.Fprintln(cmd.OutOrStdout(), displayTemplateVersions(template.ActiveVersionID, versions...))
out, err := displayTemplateVersions(template.ActiveVersionID, versions...)
if err != nil {
return xerrors.Errorf("render table: %w", err)
}
_, err = fmt.Fprintln(cmd.OutOrStdout(), out)
return err return err
}, },
} }
} }
type templateVersionRow struct {
Name string `table:"name"`
CreatedAt time.Time `table:"created at"`
CreatedBy string `table:"created by"`
Status string `table:"status"`
Active string `table:"active"`
}
// displayTemplateVersions will return a table displaying existing // displayTemplateVersions will return a table displaying existing
// template versions for the specified template. // template versions for the specified template.
func displayTemplateVersions(activeVersionID uuid.UUID, templateVersions ...codersdk.TemplateVersion) string { func displayTemplateVersions(activeVersionID uuid.UUID, templateVersions ...codersdk.TemplateVersion) (string, error) {
tableWriter := cliui.Table() rows := make([]templateVersionRow, len(templateVersions))
header := table.Row{ for i, templateVersion := range templateVersions {
"Name", "Created At", "Created By", "Status", ""}
tableWriter.AppendHeader(header)
for _, templateVersion := range templateVersions {
var activeStatus = "" var activeStatus = ""
if templateVersion.ID == activeVersionID { if templateVersion.ID == activeVersionID {
activeStatus = cliui.Styles.Code.Render(cliui.Styles.Keyword.Render("Active")) activeStatus = cliui.Styles.Code.Render(cliui.Styles.Keyword.Render("Active"))
} }
tableWriter.AppendRow(table.Row{
templateVersion.Name, rows[i] = templateVersionRow{
templateVersion.CreatedAt.Format("03:04:05 PM MST on Jan 2, 2006"), Name: templateVersion.Name,
templateVersion.CreatedByName, CreatedAt: templateVersion.CreatedAt,
strings.Title(string(templateVersion.Job.Status)), CreatedBy: templateVersion.CreatedByName,
activeStatus, Status: strings.Title(string(templateVersion.Job.Status)),
}) Active: activeStatus,
} }
return tableWriter.Render() }
return cliui.DisplayTable(rows, "name", nil)
} }

View File

@ -111,13 +111,13 @@ func userSingle() *cobra.Command {
} }
func displayUser(ctx context.Context, stderr io.Writer, client *codersdk.Client, user codersdk.User) string { func displayUser(ctx context.Context, stderr io.Writer, client *codersdk.Client, user codersdk.User) string {
tableWriter := cliui.Table() tw := cliui.Table()
addRow := func(name string, value interface{}) { addRow := func(name string, value interface{}) {
key := "" key := ""
if name != "" { if name != "" {
key = name + ":" key = name + ":"
} }
tableWriter.AppendRow(table.Row{ tw.AppendRow(table.Row{
key, value, key, value,
}) })
} }
@ -170,5 +170,5 @@ func displayUser(ctx context.Context, stderr io.Writer, client *codersdk.Client,
addRow("Organizations", "(none)") addRow("Organizations", "(none)")
} }
return tableWriter.Render() return tw.Render()
} }

View File

@ -50,14 +50,14 @@ type ComputedParameter struct {
// Parameter represents a set value for the scope. // Parameter represents a set value for the scope.
type Parameter struct { type Parameter struct {
ID uuid.UUID `json:"id"` ID uuid.UUID `json:"id" table:"id"`
CreatedAt time.Time `json:"created_at"` Scope ParameterScope `json:"scope" table:"scope"`
UpdatedAt time.Time `json:"updated_at"` ScopeID uuid.UUID `json:"scope_id" table:"scope id"`
Scope ParameterScope `json:"scope"` Name string `json:"name" table:"name"`
ScopeID uuid.UUID `json:"scope_id"` SourceScheme ParameterSourceScheme `json:"source_scheme" table:"source scheme"`
Name string `json:"name"` DestinationScheme ParameterDestinationScheme `json:"destination_scheme" table:"destination scheme"`
SourceScheme ParameterSourceScheme `json:"source_scheme"` CreatedAt time.Time `json:"created_at" table:"created at"`
DestinationScheme ParameterDestinationScheme `json:"destination_scheme"` UpdatedAt time.Time `json:"updated_at" table:"updated at"`
} }
type ParameterSchema struct { type ParameterSchema struct {

View File

@ -205,13 +205,13 @@ export interface Pagination {
// From codersdk/parameters.go // From codersdk/parameters.go
export interface Parameter { export interface Parameter {
readonly id: string readonly id: string
readonly created_at: string
readonly updated_at: string
readonly scope: ParameterScope readonly scope: ParameterScope
readonly scope_id: string readonly scope_id: string
readonly name: string readonly name: string
readonly source_scheme: ParameterSourceScheme readonly source_scheme: ParameterSourceScheme
readonly destination_scheme: ParameterDestinationScheme readonly destination_scheme: ParameterDestinationScheme
readonly created_at: string
readonly updated_at: string
} }
// From codersdk/parameters.go // From codersdk/parameters.go