diff --git a/cli/list.go b/cli/list.go index 05ae08bf1585d..1a578c887371b 100644 --- a/cli/list.go +++ b/cli/list.go @@ -6,6 +6,7 @@ import ( "strconv" "time" + "github.com/google/uuid" "golang.org/x/xerrors" "github.com/coder/coder/v2/cli/cliui" @@ -22,19 +23,21 @@ type workspaceListRow struct { codersdk.Workspace `table:"-"` // For table format: - Favorite bool `json:"-" table:"favorite"` - WorkspaceName string `json:"-" table:"workspace,default_sort"` - Template string `json:"-" table:"template"` - Status string `json:"-" table:"status"` - Healthy string `json:"-" table:"healthy"` - LastBuilt string `json:"-" table:"last built"` - CurrentVersion string `json:"-" table:"current version"` - Outdated bool `json:"-" table:"outdated"` - StartsAt string `json:"-" table:"starts at"` - StartsNext string `json:"-" table:"starts next"` - StopsAfter string `json:"-" table:"stops after"` - StopsNext string `json:"-" table:"stops next"` - DailyCost string `json:"-" table:"daily cost"` + Favorite bool `json:"-" table:"favorite"` + WorkspaceName string `json:"-" table:"workspace,default_sort"` + OrganizationID uuid.UUID `json:"-" table:"organization id"` + OrganizationName string `json:"-" table:"organization name"` + Template string `json:"-" table:"template"` + Status string `json:"-" table:"status"` + Healthy string `json:"-" table:"healthy"` + LastBuilt string `json:"-" table:"last built"` + CurrentVersion string `json:"-" table:"current version"` + Outdated bool `json:"-" table:"outdated"` + StartsAt string `json:"-" table:"starts at"` + StartsNext string `json:"-" table:"starts next"` + StopsAfter string `json:"-" table:"stops after"` + StopsNext string `json:"-" table:"stops next"` + DailyCost string `json:"-" table:"daily cost"` } func workspaceListRowFromWorkspace(now time.Time, workspace codersdk.Workspace) workspaceListRow { @@ -53,20 +56,22 @@ func workspaceListRowFromWorkspace(now time.Time, workspace codersdk.Workspace) } workspaceName := favIco + " " + workspace.OwnerName + "/" + workspace.Name return workspaceListRow{ - Favorite: workspace.Favorite, - Workspace: workspace, - WorkspaceName: workspaceName, - Template: workspace.TemplateName, - Status: status, - Healthy: healthy, - LastBuilt: durationDisplay(lastBuilt), - CurrentVersion: workspace.LatestBuild.TemplateVersionName, - Outdated: workspace.Outdated, - StartsAt: schedRow.StartsAt, - StartsNext: schedRow.StartsNext, - StopsAfter: schedRow.StopsAfter, - StopsNext: schedRow.StopsNext, - DailyCost: strconv.Itoa(int(workspace.LatestBuild.DailyCost)), + Favorite: workspace.Favorite, + Workspace: workspace, + WorkspaceName: workspaceName, + OrganizationID: workspace.OrganizationID, + OrganizationName: workspace.OrganizationName, + Template: workspace.TemplateName, + Status: status, + Healthy: healthy, + LastBuilt: durationDisplay(lastBuilt), + CurrentVersion: workspace.LatestBuild.TemplateVersionName, + Outdated: workspace.Outdated, + StartsAt: schedRow.StartsAt, + StartsNext: schedRow.StartsNext, + StopsAfter: schedRow.StopsAfter, + StopsNext: schedRow.StopsNext, + DailyCost: strconv.Itoa(int(workspace.LatestBuild.DailyCost)), } } diff --git a/cli/testdata/coder_list_--help.golden b/cli/testdata/coder_list_--help.golden index adc1ae74a7d03..407260244cc45 100644 --- a/cli/testdata/coder_list_--help.golden +++ b/cli/testdata/coder_list_--help.golden @@ -13,8 +13,9 @@ OPTIONS: -c, --column string-array (default: workspace,template,status,healthy,last built,current version,outdated,starts at,stops after) Columns to display in table output. Available columns: favorite, - workspace, template, status, healthy, last built, current version, - outdated, starts at, starts next, stops after, stops next, daily cost. + workspace, organization id, organization name, template, status, + healthy, last built, current version, outdated, starts at, starts + next, stops after, stops next, daily cost. -o, --output string (default: table) Output format. Available formats: table, json. diff --git a/cli/testdata/coder_list_--output_json.golden b/cli/testdata/coder_list_--output_json.golden index 903e5681c2689..c65c1cd61db80 100644 --- a/cli/testdata/coder_list_--output_json.golden +++ b/cli/testdata/coder_list_--output_json.golden @@ -7,6 +7,7 @@ "owner_name": "testuser", "owner_avatar_url": "", "organization_id": "[first org ID]", + "organization_name": "first-organization", "template_id": "[template ID]", "template_name": "test-template", "template_display_name": "", diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index 68a3773f0d1e8..cb59b53023644 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -12500,6 +12500,9 @@ const docTemplate = `{ "type": "string", "format": "uuid" }, + "organization_name": { + "type": "string" + }, "outdated": { "type": "boolean" }, diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index 36bae814a59a8..ee6dde53c0258 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -11338,6 +11338,9 @@ "type": "string", "format": "uuid" }, + "organization_name": { + "type": "string" + }, "outdated": { "type": "boolean" }, diff --git a/coderd/workspaces.go b/coderd/workspaces.go index 7e6698736eeb6..bed982d5e2511 100644 --- a/coderd/workspaces.go +++ b/coderd/workspaces.go @@ -1774,6 +1774,7 @@ func convertWorkspace( OwnerName: username, OwnerAvatarURL: avatarURL, OrganizationID: workspace.OrganizationID, + OrganizationName: template.OrganizationName, TemplateID: workspace.TemplateID, LatestBuild: workspaceBuild, TemplateName: template.Name, diff --git a/coderd/workspaces_test.go b/coderd/workspaces_test.go index e5a01df9f8edc..a657b5ce149dd 100644 --- a/coderd/workspaces_test.go +++ b/coderd/workspaces_test.go @@ -64,6 +64,10 @@ func TestWorkspace(t *testing.T) { require.NoError(t, err) require.Equal(t, user.UserID, ws.LatestBuild.InitiatorID) require.Equal(t, codersdk.BuildReasonInitiator, ws.LatestBuild.Reason) + + org, err := client.Organization(ctx, ws.OrganizationID) + require.NoError(t, err) + require.Equal(t, ws.OrganizationName, org.Name) }) t.Run("Deleted", func(t *testing.T) { @@ -1496,6 +1500,9 @@ func TestWorkspaceFilterManual(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) defer cancel() + org, err := client.Organization(ctx, user.OrganizationID) + require.NoError(t, err) + // single workspace res, err := client.Workspaces(ctx, codersdk.WorkspaceFilter{ FilterQuery: fmt.Sprintf("template:%s %s/%s", template.Name, workspace.OwnerName, workspace.Name), @@ -1503,6 +1510,7 @@ func TestWorkspaceFilterManual(t *testing.T) { require.NoError(t, err) require.Len(t, res.Workspaces, 1) require.Equal(t, workspace.ID, res.Workspaces[0].ID) + require.Equal(t, workspace.OrganizationName, org.Name) }) t.Run("FilterQueryHasAgentConnecting", func(t *testing.T) { t.Parallel() diff --git a/codersdk/workspaces.go b/codersdk/workspaces.go index 69472f8d4579d..1864a97a0c418 100644 --- a/codersdk/workspaces.go +++ b/codersdk/workspaces.go @@ -33,6 +33,7 @@ type Workspace struct { OwnerName string `json:"owner_name"` OwnerAvatarURL string `json:"owner_avatar_url"` OrganizationID uuid.UUID `json:"organization_id" format:"uuid"` + OrganizationName string `json:"organization_name"` TemplateID uuid.UUID `json:"template_id" format:"uuid"` TemplateName string `json:"template_name"` TemplateDisplayName string `json:"template_display_name"` diff --git a/docs/api/schemas.md b/docs/api/schemas.md index a9b3d613be318..e7611c2b03253 100644 --- a/docs/api/schemas.md +++ b/docs/api/schemas.md @@ -5815,6 +5815,7 @@ If the schedule is empty, the user will be updated to use the default schedule.| }, "name": "string", "organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6", + "organization_name": "string", "outdated": true, "owner_avatar_url": "string", "owner_id": "8826ee2e-7933-4665-aef2-2393f84a0d05", @@ -5848,6 +5849,7 @@ If the schedule is empty, the user will be updated to use the default schedule.| | `latest_build` | [codersdk.WorkspaceBuild](#codersdkworkspacebuild) | false | | | | `name` | string | false | | | | `organization_id` | string | false | | | +| `organization_name` | string | false | | | | `outdated` | boolean | false | | | | `owner_avatar_url` | string | false | | | | `owner_id` | string | false | | | @@ -7068,6 +7070,7 @@ If the schedule is empty, the user will be updated to use the default schedule.| }, "name": "string", "organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6", + "organization_name": "string", "outdated": true, "owner_avatar_url": "string", "owner_id": "8826ee2e-7933-4665-aef2-2393f84a0d05", diff --git a/docs/api/workspaces.md b/docs/api/workspaces.md index f16d9be857fef..ddaa70c9df292 100644 --- a/docs/api/workspaces.md +++ b/docs/api/workspaces.md @@ -215,6 +215,7 @@ of the template will be used. }, "name": "string", "organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6", + "organization_name": "string", "outdated": true, "owner_avatar_url": "string", "owner_id": "8826ee2e-7933-4665-aef2-2393f84a0d05", @@ -429,6 +430,7 @@ curl -X GET http://coder-server:8080/api/v2/users/{user}/workspace/{workspacenam }, "name": "string", "organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6", + "organization_name": "string", "outdated": true, "owner_avatar_url": "string", "owner_id": "8826ee2e-7933-4665-aef2-2393f84a0d05", @@ -642,6 +644,7 @@ curl -X GET http://coder-server:8080/api/v2/workspaces \ }, "name": "string", "organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6", + "organization_name": "string", "outdated": true, "owner_avatar_url": "string", "owner_id": "8826ee2e-7933-4665-aef2-2393f84a0d05", @@ -857,6 +860,7 @@ curl -X GET http://coder-server:8080/api/v2/workspaces/{workspace} \ }, "name": "string", "organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6", + "organization_name": "string", "outdated": true, "owner_avatar_url": "string", "owner_id": "8826ee2e-7933-4665-aef2-2393f84a0d05", @@ -1187,6 +1191,7 @@ curl -X PUT http://coder-server:8080/api/v2/workspaces/{workspace}/dormant \ }, "name": "string", "organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6", + "organization_name": "string", "outdated": true, "owner_avatar_url": "string", "owner_id": "8826ee2e-7933-4665-aef2-2393f84a0d05", diff --git a/docs/cli/list.md b/docs/cli/list.md index 2c67fac0f927e..e64adf399dd6a 100644 --- a/docs/cli/list.md +++ b/docs/cli/list.md @@ -40,7 +40,7 @@ Search for a workspace with a query. | Type | string-array | | Default | workspace,template,status,healthy,last built,current version,outdated,starts at,stops after | -Columns to display in table output. Available columns: favorite, workspace, template, status, healthy, last built, current version, outdated, starts at, starts next, stops after, stops next, daily cost. +Columns to display in table output. Available columns: favorite, workspace, organization id, organization name, template, status, healthy, last built, current version, outdated, starts at, starts next, stops after, stops next, daily cost. ### -o, --output diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index 219f46da10938..e878b25e1f452 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -1574,6 +1574,7 @@ export interface Workspace { readonly owner_name: string; readonly owner_avatar_url: string; readonly organization_id: string; + readonly organization_name: string; readonly template_id: string; readonly template_name: string; readonly template_display_name: string; diff --git a/site/src/testHelpers/entities.ts b/site/src/testHelpers/entities.ts index 1cd0ff5d76ee4..8c5ec8c79a2ce 100644 --- a/site/src/testHelpers/entities.ts +++ b/site/src/testHelpers/entities.ts @@ -1057,6 +1057,7 @@ export const MockWorkspace: TypesGen.Workspace = { outdated: false, owner_id: MockUser.id, organization_id: MockOrganization.id, + organization_name: "default", owner_name: MockUser.username, owner_avatar_url: "https://avatars.githubusercontent.com/u/7122116?v=4", autostart_schedule: MockWorkspaceAutostartEnabled.schedule,