diff --git a/coderd/workspaces.go b/coderd/workspaces.go index 540fd42665761..0f77f5a172e53 100644 --- a/coderd/workspaces.go +++ b/coderd/workspaces.go @@ -1011,20 +1011,21 @@ func convertWorkspace( ttlMillis := convertWorkspaceTTLMillis(workspace.Ttl) return codersdk.Workspace{ - ID: workspace.ID, - CreatedAt: workspace.CreatedAt, - UpdatedAt: workspace.UpdatedAt, - OwnerID: workspace.OwnerID, - OwnerName: owner.Username, - TemplateID: workspace.TemplateID, - LatestBuild: workspaceBuild, - TemplateName: template.Name, - TemplateIcon: template.Icon, - Outdated: workspaceBuild.TemplateVersionID.String() != template.ActiveVersionID.String(), - Name: workspace.Name, - AutostartSchedule: autostartSchedule, - TTLMillis: ttlMillis, - LastUsedAt: workspace.LastUsedAt, + ID: workspace.ID, + CreatedAt: workspace.CreatedAt, + UpdatedAt: workspace.UpdatedAt, + OwnerID: workspace.OwnerID, + OwnerName: owner.Username, + TemplateID: workspace.TemplateID, + LatestBuild: workspaceBuild, + TemplateName: template.Name, + TemplateIcon: template.Icon, + TemplateDisplayName: template.DisplayName, + Outdated: workspaceBuild.TemplateVersionID.String() != template.ActiveVersionID.String(), + Name: workspace.Name, + AutostartSchedule: autostartSchedule, + TTLMillis: ttlMillis, + LastUsedAt: workspace.LastUsedAt, } } diff --git a/coderd/workspaces_test.go b/coderd/workspaces_test.go index 73a7ce19dd013..f4ced10d53034 100644 --- a/coderd/workspaces_test.go +++ b/coderd/workspaces_test.go @@ -115,6 +115,36 @@ func TestWorkspace(t *testing.T) { }) require.Error(t, err, "workspace rename should have failed") }) + + t.Run("TemplateProperties", func(t *testing.T) { + t.Parallel() + client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true}) + user := coderdtest.CreateFirstUser(t, client) + version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) + coderdtest.AwaitTemplateVersionJob(t, client, version.ID) + + const templateIcon = "/img/icon.svg" + const templateDisplayName = "This is template" + template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID, func(ctr *codersdk.CreateTemplateRequest) { + ctr.Icon = templateIcon + ctr.DisplayName = templateDisplayName + }) + require.NotEmpty(t, template.Name) + require.NotEmpty(t, template.DisplayName) + require.NotEmpty(t, template.Icon) + workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + + ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) + defer cancel() + + ws, err := client.Workspace(ctx, workspace.ID) + require.NoError(t, err) + assert.Equal(t, user.UserID, ws.LatestBuild.InitiatorID) + assert.Equal(t, codersdk.BuildReasonInitiator, ws.LatestBuild.Reason) + assert.Equal(t, template.Name, ws.TemplateName) + assert.Equal(t, templateIcon, ws.TemplateIcon) + assert.Equal(t, templateDisplayName, ws.TemplateDisplayName) + }) } func TestAdminViewAllWorkspaces(t *testing.T) { diff --git a/codersdk/workspaces.go b/codersdk/workspaces.go index 084fb66e96132..24cfc6b96e072 100644 --- a/codersdk/workspaces.go +++ b/codersdk/workspaces.go @@ -17,20 +17,21 @@ import ( // Workspace is a deployment of a template. It references a specific // version and can be updated. type Workspace struct { - ID uuid.UUID `json:"id"` - CreatedAt time.Time `json:"created_at"` - UpdatedAt time.Time `json:"updated_at"` - OwnerID uuid.UUID `json:"owner_id"` - OwnerName string `json:"owner_name"` - TemplateID uuid.UUID `json:"template_id"` - TemplateName string `json:"template_name"` - TemplateIcon string `json:"template_icon"` - LatestBuild WorkspaceBuild `json:"latest_build"` - Outdated bool `json:"outdated"` - Name string `json:"name"` - AutostartSchedule *string `json:"autostart_schedule,omitempty"` - TTLMillis *int64 `json:"ttl_ms,omitempty"` - LastUsedAt time.Time `json:"last_used_at"` + ID uuid.UUID `json:"id"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` + OwnerID uuid.UUID `json:"owner_id"` + OwnerName string `json:"owner_name"` + TemplateID uuid.UUID `json:"template_id"` + TemplateName string `json:"template_name"` + TemplateDisplayName string `json:"template_display_name"` + TemplateIcon string `json:"template_icon"` + LatestBuild WorkspaceBuild `json:"latest_build"` + Outdated bool `json:"outdated"` + Name string `json:"name"` + AutostartSchedule *string `json:"autostart_schedule,omitempty"` + TTLMillis *int64 `json:"ttl_ms,omitempty"` + LastUsedAt time.Time `json:"last_used_at"` } type WorkspacesRequest struct { diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index d92fd82213ca9..b5b6505bcf205 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -785,6 +785,7 @@ export interface Workspace { readonly owner_name: string readonly template_id: string readonly template_name: string + readonly template_display_name: string readonly template_icon: string readonly latest_build: WorkspaceBuild readonly outdated: boolean diff --git a/site/src/components/WorkspaceStats/WorkspaceStats.tsx b/site/src/components/WorkspaceStats/WorkspaceStats.tsx index b68bb33431e87..bbed761056ef4 100644 --- a/site/src/components/WorkspaceStats/WorkspaceStats.tsx +++ b/site/src/components/WorkspaceStats/WorkspaceStats.tsx @@ -5,7 +5,10 @@ import { FC } from "react" import { Link as RouterLink } from "react-router-dom" import { combineClasses } from "util/combineClasses" import { createDayString } from "util/createDayString" -import { getDisplayWorkspaceBuildInitiatedBy } from "util/workspace" +import { + getDisplayWorkspaceBuildInitiatedBy, + getDisplayWorkspaceTemplateName, +} from "util/workspace" import { Workspace } from "../../api/typesGenerated" const Language = { @@ -36,6 +39,7 @@ export const WorkspaceStats: FC<WorkspaceStatsProps> = ({ const initiatedBy = getDisplayWorkspaceBuildInitiatedBy( workspace.latest_build, ) + const displayTemplateName = getDisplayWorkspaceTemplateName(workspace) return ( <div className={styles.stats} aria-label={Language.workspaceDetails}> @@ -46,7 +50,7 @@ export const WorkspaceStats: FC<WorkspaceStatsProps> = ({ to={`/templates/${workspace.template_name}`} className={combineClasses([styles.statsValue, styles.link])} > - {workspace.template_name} + {displayTemplateName} </Link> </div> <div className={styles.statItem}> diff --git a/site/src/components/WorkspacesTable/WorkspacesRow.tsx b/site/src/components/WorkspacesTable/WorkspacesRow.tsx index 97e21ed5d4ae9..07beb72528337 100644 --- a/site/src/components/WorkspacesTable/WorkspacesRow.tsx +++ b/site/src/components/WorkspacesTable/WorkspacesRow.tsx @@ -7,6 +7,7 @@ import { AvatarData } from "components/AvatarData/AvatarData" import { WorkspaceStatusBadge } from "components/WorkspaceStatusBadge/WorkspaceStatusBadge" import { FC } from "react" import { useNavigate } from "react-router-dom" +import { getDisplayWorkspaceTemplateName } from "util/workspace" import { WorkspaceItemMachineRef } from "../../xServices/workspaces/workspacesXService" import { LastUsed } from "../LastUsed/LastUsed" import { @@ -32,6 +33,7 @@ export const WorkspacesRow: FC< const workspacePageLink = `/@${workspace.owner_name}/${workspace.name}` const hasTemplateIcon = workspace.template_icon && workspace.template_icon !== "" + const displayTemplateName = getDisplayWorkspaceTemplateName(workspace) return ( <TableRow @@ -61,7 +63,7 @@ export const WorkspacesRow: FC< </TableCellLink> <TableCellLink to={workspacePageLink}> - <TableCellDataPrimary>{workspace.template_name}</TableCellDataPrimary> + <TableCellDataPrimary>{displayTemplateName}</TableCellDataPrimary> </TableCellLink> <TableCellLink to={workspacePageLink}> <TableCellData> diff --git a/site/src/pages/WorkspacesPage/WorkspacesPage.test.tsx b/site/src/pages/WorkspacesPage/WorkspacesPage.test.tsx index 14e056f52d4c2..3d73efa33518a 100644 --- a/site/src/pages/WorkspacesPage/WorkspacesPage.test.tsx +++ b/site/src/pages/WorkspacesPage/WorkspacesPage.test.tsx @@ -1,7 +1,10 @@ import { screen, waitFor } from "@testing-library/react" import { rest } from "msw" import * as CreateDayString from "util/createDayString" -import { MockWorkspace } from "../../testHelpers/entities" +import { + MockWorkspace, + MockWorkspacesResponse, +} from "../../testHelpers/entities" import { history, render } from "../../testHelpers/renderHelpers" import { server } from "../../testHelpers/server" import WorkspacesPage from "./WorkspacesPage" @@ -54,5 +57,9 @@ describe("WorkspacesPage", () => { { timeout: 2000 }, ) await screen.findByText(`${MockWorkspace.name}1`) + const templateDisplayNames = await screen.findAllByText( + `${MockWorkspace.template_display_name}`, + ) + expect(templateDisplayNames).toHaveLength(MockWorkspacesResponse.count) }) }) diff --git a/site/src/testHelpers/entities.ts b/site/src/testHelpers/entities.ts index 8842c49ac9c20..c43d7a64d19a8 100644 --- a/site/src/testHelpers/entities.ts +++ b/site/src/testHelpers/entities.ts @@ -434,6 +434,7 @@ export const MockWorkspace: TypesGen.Workspace = { template_id: MockTemplate.id, template_name: MockTemplate.name, template_icon: MockTemplate.icon, + template_display_name: MockTemplate.display_name, outdated: false, owner_id: MockUser.id, owner_name: MockUser.username, diff --git a/site/src/util/workspace.test.ts b/site/src/util/workspace.test.ts index 333eebfd13e3f..26bb223c6b566 100644 --- a/site/src/util/workspace.test.ts +++ b/site/src/util/workspace.test.ts @@ -5,6 +5,7 @@ import { defaultWorkspaceExtension, getDisplayVersionStatus, getDisplayWorkspaceBuildInitiatedBy, + getDisplayWorkspaceTemplateName, isWorkspaceOn, } from "./workspace" @@ -120,4 +121,22 @@ describe("util > workspace", () => { }, ) }) + + describe("getDisplayWorkspaceTemplateName", () => { + it("display name is not set", async () => { + const workspace: TypesGen.Workspace = { + ...Mocks.MockWorkspace, + template_display_name: "", + } + const displayed = getDisplayWorkspaceTemplateName(workspace) + expect(displayed).toEqual(workspace.template_name) + }) + it("display name is set", async () => { + const workspace: TypesGen.Workspace = { + ...Mocks.MockWorkspace, + } + const displayed = getDisplayWorkspaceTemplateName(workspace) + expect(displayed).toEqual(workspace.template_display_name) + }) + }) }) diff --git a/site/src/util/workspace.ts b/site/src/util/workspace.ts index 22d74d826f7f1..7d81e644d9d6d 100644 --- a/site/src/util/workspace.ts +++ b/site/src/util/workspace.ts @@ -182,3 +182,11 @@ export const getFaviconByStatus = ( return "favicon" } } + +export const getDisplayWorkspaceTemplateName = ( + workspace: TypesGen.Workspace, +): string => { + return workspace.template_display_name.length > 0 + ? workspace.template_display_name + : workspace.template_name +}