diff --git a/cli/cliui/table.go b/cli/cliui/table.go index 90ecd0bb9211e..35fd3b1641ef1 100644 --- a/cli/cliui/table.go +++ b/cli/cliui/table.go @@ -67,7 +67,7 @@ func DisplayTable(out any, sort string, filterColumns []string) (string, error) } // Get the list of table column headers. - headersRaw, err := typeToTableHeaders(v.Type().Elem()) + headersRaw, err := TypeToTableHeaders(v.Type().Elem()) if err != nil { return "", xerrors.Errorf("get table headers recursively for type %q: %w", v.Type().Elem().String(), err) } @@ -207,10 +207,10 @@ func isStructOrStructPointer(t reflect.Type) bool { return t.Kind() == reflect.Struct || (t.Kind() == reflect.Pointer && t.Elem().Kind() == reflect.Struct) } -// typeToTableHeaders converts a type to a slice of column names. If the given +// TypeToTableHeaders converts a type to a slice of column names. If the given // type is invalid (not a struct or a pointer to a struct, has invalid table // tags, etc.), an error is returned. -func typeToTableHeaders(t reflect.Type) ([]string, error) { +func TypeToTableHeaders(t reflect.Type) ([]string, error) { if !isStructOrStructPointer(t) { return nil, xerrors.Errorf("typeToTableHeaders called with a non-struct or a non-pointer-to-a-struct type") } @@ -235,7 +235,7 @@ func typeToTableHeaders(t reflect.Type) ([]string, error) { return nil, xerrors.Errorf("field %q in type %q is marked as recursive but does not contain a struct or a pointer to a struct", field.Name, t.String()) } - childNames, err := typeToTableHeaders(fieldType) + childNames, err := TypeToTableHeaders(fieldType) if err != nil { return nil, xerrors.Errorf("get child field header names for field %q in type %q: %w", field.Name, fieldType.String(), err) } diff --git a/cli/list.go b/cli/list.go index f1dfe098e96c1..570ca5062302e 100644 --- a/cli/list.go +++ b/cli/list.go @@ -2,6 +2,8 @@ package cli import ( "fmt" + "reflect" + "strings" "time" "github.com/google/uuid" @@ -58,10 +60,12 @@ func workspaceListRowFromWorkspace(now time.Time, usersByID map[uuid.UUID]coders func list() *cobra.Command { var ( - all bool - columns []string - defaultQuery = "owner:me" - searchQuery string + all bool + columns []string + defaultQuery = "owner:me" + searchQuery string + me bool + displayWorkspaces []workspaceListRow ) cmd := &cobra.Command{ Annotations: workspaceCommand, @@ -80,6 +84,14 @@ func list() *cobra.Command { if all && searchQuery == defaultQuery { filter.FilterQuery = "" } + + if me { + myUser, err := client.User(cmd.Context(), codersdk.Me) + if err != nil { + return err + } + filter.Owner = myUser.Username + } workspaces, err := client.Workspaces(cmd.Context(), filter) if err != nil { return err @@ -101,7 +113,7 @@ func list() *cobra.Command { } now := time.Now() - displayWorkspaces := make([]workspaceListRow, len(workspaces)) + displayWorkspaces = make([]workspaceListRow, len(workspaces)) for i, workspace := range workspaces { displayWorkspaces[i] = workspaceListRowFromWorkspace(now, usersByID, workspace) } @@ -115,10 +127,21 @@ func list() *cobra.Command { return err }, } + + v := reflect.Indirect(reflect.ValueOf(displayWorkspaces)) + availColumns, err := cliui.TypeToTableHeaders(v.Type().Elem()) + if err != nil { + panic(err) + } + for i, s := range availColumns { + availColumns[i] = strings.Replace(s, " ", "_", -1) + } + columnString := strings.Join(availColumns[:], ", ") + cmd.Flags().BoolVarP(&all, "all", "a", false, "Specifies whether all workspaces will be listed or not.") cmd.Flags().StringArrayVarP(&columns, "column", "c", nil, - "Specify a column to filter in the table.") - cmd.Flags().StringVar(&searchQuery, "search", defaultQuery, "Search for a workspace with a query.") + fmt.Sprintf("Specify a column to filter in the table. Available columns are: %v", columnString)) + cmd.Flags().StringVar(&searchQuery, "search", "", "Search for a workspace with a query.") return cmd }