Skip to content

Commit 32927b1

Browse files
authored
feat: show template.display_name on Workspace pages (#5082)
* feat: expose template.display_name via Workspaces endpoint * Fix: MockWorkspace * UI: Workspace stats and row * Show template.display_name on pages * Fix: address PR comments * Add helper function: getDisplayWorkspaceTemplateName
1 parent c1ecc91 commit 32927b1

File tree

10 files changed

+106
-32
lines changed

10 files changed

+106
-32
lines changed

coderd/workspaces.go

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1011,20 +1011,21 @@ func convertWorkspace(
10111011

10121012
ttlMillis := convertWorkspaceTTLMillis(workspace.Ttl)
10131013
return codersdk.Workspace{
1014-
ID: workspace.ID,
1015-
CreatedAt: workspace.CreatedAt,
1016-
UpdatedAt: workspace.UpdatedAt,
1017-
OwnerID: workspace.OwnerID,
1018-
OwnerName: owner.Username,
1019-
TemplateID: workspace.TemplateID,
1020-
LatestBuild: workspaceBuild,
1021-
TemplateName: template.Name,
1022-
TemplateIcon: template.Icon,
1023-
Outdated: workspaceBuild.TemplateVersionID.String() != template.ActiveVersionID.String(),
1024-
Name: workspace.Name,
1025-
AutostartSchedule: autostartSchedule,
1026-
TTLMillis: ttlMillis,
1027-
LastUsedAt: workspace.LastUsedAt,
1014+
ID: workspace.ID,
1015+
CreatedAt: workspace.CreatedAt,
1016+
UpdatedAt: workspace.UpdatedAt,
1017+
OwnerID: workspace.OwnerID,
1018+
OwnerName: owner.Username,
1019+
TemplateID: workspace.TemplateID,
1020+
LatestBuild: workspaceBuild,
1021+
TemplateName: template.Name,
1022+
TemplateIcon: template.Icon,
1023+
TemplateDisplayName: template.DisplayName,
1024+
Outdated: workspaceBuild.TemplateVersionID.String() != template.ActiveVersionID.String(),
1025+
Name: workspace.Name,
1026+
AutostartSchedule: autostartSchedule,
1027+
TTLMillis: ttlMillis,
1028+
LastUsedAt: workspace.LastUsedAt,
10281029
}
10291030
}
10301031

coderd/workspaces_test.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,36 @@ func TestWorkspace(t *testing.T) {
115115
})
116116
require.Error(t, err, "workspace rename should have failed")
117117
})
118+
119+
t.Run("TemplateProperties", func(t *testing.T) {
120+
t.Parallel()
121+
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
122+
user := coderdtest.CreateFirstUser(t, client)
123+
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
124+
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
125+
126+
const templateIcon = "/img/icon.svg"
127+
const templateDisplayName = "This is template"
128+
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID, func(ctr *codersdk.CreateTemplateRequest) {
129+
ctr.Icon = templateIcon
130+
ctr.DisplayName = templateDisplayName
131+
})
132+
require.NotEmpty(t, template.Name)
133+
require.NotEmpty(t, template.DisplayName)
134+
require.NotEmpty(t, template.Icon)
135+
workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID)
136+
137+
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
138+
defer cancel()
139+
140+
ws, err := client.Workspace(ctx, workspace.ID)
141+
require.NoError(t, err)
142+
assert.Equal(t, user.UserID, ws.LatestBuild.InitiatorID)
143+
assert.Equal(t, codersdk.BuildReasonInitiator, ws.LatestBuild.Reason)
144+
assert.Equal(t, template.Name, ws.TemplateName)
145+
assert.Equal(t, templateIcon, ws.TemplateIcon)
146+
assert.Equal(t, templateDisplayName, ws.TemplateDisplayName)
147+
})
118148
}
119149

120150
func TestAdminViewAllWorkspaces(t *testing.T) {

codersdk/workspaces.go

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,20 +17,21 @@ import (
1717
// Workspace is a deployment of a template. It references a specific
1818
// version and can be updated.
1919
type Workspace struct {
20-
ID uuid.UUID `json:"id"`
21-
CreatedAt time.Time `json:"created_at"`
22-
UpdatedAt time.Time `json:"updated_at"`
23-
OwnerID uuid.UUID `json:"owner_id"`
24-
OwnerName string `json:"owner_name"`
25-
TemplateID uuid.UUID `json:"template_id"`
26-
TemplateName string `json:"template_name"`
27-
TemplateIcon string `json:"template_icon"`
28-
LatestBuild WorkspaceBuild `json:"latest_build"`
29-
Outdated bool `json:"outdated"`
30-
Name string `json:"name"`
31-
AutostartSchedule *string `json:"autostart_schedule,omitempty"`
32-
TTLMillis *int64 `json:"ttl_ms,omitempty"`
33-
LastUsedAt time.Time `json:"last_used_at"`
20+
ID uuid.UUID `json:"id"`
21+
CreatedAt time.Time `json:"created_at"`
22+
UpdatedAt time.Time `json:"updated_at"`
23+
OwnerID uuid.UUID `json:"owner_id"`
24+
OwnerName string `json:"owner_name"`
25+
TemplateID uuid.UUID `json:"template_id"`
26+
TemplateName string `json:"template_name"`
27+
TemplateDisplayName string `json:"template_display_name"`
28+
TemplateIcon string `json:"template_icon"`
29+
LatestBuild WorkspaceBuild `json:"latest_build"`
30+
Outdated bool `json:"outdated"`
31+
Name string `json:"name"`
32+
AutostartSchedule *string `json:"autostart_schedule,omitempty"`
33+
TTLMillis *int64 `json:"ttl_ms,omitempty"`
34+
LastUsedAt time.Time `json:"last_used_at"`
3435
}
3536

3637
type WorkspacesRequest struct {

site/src/api/typesGenerated.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -788,6 +788,7 @@ export interface Workspace {
788788
readonly owner_name: string
789789
readonly template_id: string
790790
readonly template_name: string
791+
readonly template_display_name: string
791792
readonly template_icon: string
792793
readonly latest_build: WorkspaceBuild
793794
readonly outdated: boolean

site/src/components/WorkspaceStats/WorkspaceStats.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@ import { FC } from "react"
55
import { Link as RouterLink } from "react-router-dom"
66
import { combineClasses } from "util/combineClasses"
77
import { createDayString } from "util/createDayString"
8-
import { getDisplayWorkspaceBuildInitiatedBy } from "util/workspace"
8+
import {
9+
getDisplayWorkspaceBuildInitiatedBy,
10+
getDisplayWorkspaceTemplateName,
11+
} from "util/workspace"
912
import { Workspace } from "../../api/typesGenerated"
1013

1114
const Language = {
@@ -36,6 +39,7 @@ export const WorkspaceStats: FC<WorkspaceStatsProps> = ({
3639
const initiatedBy = getDisplayWorkspaceBuildInitiatedBy(
3740
workspace.latest_build,
3841
)
42+
const displayTemplateName = getDisplayWorkspaceTemplateName(workspace)
3943

4044
return (
4145
<div className={styles.stats} aria-label={Language.workspaceDetails}>
@@ -46,7 +50,7 @@ export const WorkspaceStats: FC<WorkspaceStatsProps> = ({
4650
to={`/templates/${workspace.template_name}`}
4751
className={combineClasses([styles.statsValue, styles.link])}
4852
>
49-
{workspace.template_name}
53+
{displayTemplateName}
5054
</Link>
5155
</div>
5256
<div className={styles.statItem}>

site/src/components/WorkspacesTable/WorkspacesRow.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { AvatarData } from "components/AvatarData/AvatarData"
77
import { WorkspaceStatusBadge } from "components/WorkspaceStatusBadge/WorkspaceStatusBadge"
88
import { FC } from "react"
99
import { useNavigate } from "react-router-dom"
10+
import { getDisplayWorkspaceTemplateName } from "util/workspace"
1011
import { WorkspaceItemMachineRef } from "../../xServices/workspaces/workspacesXService"
1112
import { LastUsed } from "../LastUsed/LastUsed"
1213
import {
@@ -32,6 +33,7 @@ export const WorkspacesRow: FC<
3233
const workspacePageLink = `/@${workspace.owner_name}/${workspace.name}`
3334
const hasTemplateIcon =
3435
workspace.template_icon && workspace.template_icon !== ""
36+
const displayTemplateName = getDisplayWorkspaceTemplateName(workspace)
3537

3638
return (
3739
<TableRow
@@ -61,7 +63,7 @@ export const WorkspacesRow: FC<
6163
</TableCellLink>
6264

6365
<TableCellLink to={workspacePageLink}>
64-
<TableCellDataPrimary>{workspace.template_name}</TableCellDataPrimary>
66+
<TableCellDataPrimary>{displayTemplateName}</TableCellDataPrimary>
6567
</TableCellLink>
6668
<TableCellLink to={workspacePageLink}>
6769
<TableCellData>

site/src/pages/WorkspacesPage/WorkspacesPage.test.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
import { screen, waitFor } from "@testing-library/react"
22
import { rest } from "msw"
33
import * as CreateDayString from "util/createDayString"
4-
import { MockWorkspace } from "../../testHelpers/entities"
4+
import {
5+
MockWorkspace,
6+
MockWorkspacesResponse,
7+
} from "../../testHelpers/entities"
58
import { history, render } from "../../testHelpers/renderHelpers"
69
import { server } from "../../testHelpers/server"
710
import WorkspacesPage from "./WorkspacesPage"
@@ -54,5 +57,9 @@ describe("WorkspacesPage", () => {
5457
{ timeout: 2000 },
5558
)
5659
await screen.findByText(`${MockWorkspace.name}1`)
60+
const templateDisplayNames = await screen.findAllByText(
61+
`${MockWorkspace.template_display_name}`,
62+
)
63+
expect(templateDisplayNames).toHaveLength(MockWorkspacesResponse.count)
5764
})
5865
})

site/src/testHelpers/entities.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,7 @@ export const MockWorkspace: TypesGen.Workspace = {
434434
template_id: MockTemplate.id,
435435
template_name: MockTemplate.name,
436436
template_icon: MockTemplate.icon,
437+
template_display_name: MockTemplate.display_name,
437438
outdated: false,
438439
owner_id: MockUser.id,
439440
owner_name: MockUser.username,

site/src/util/workspace.test.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
defaultWorkspaceExtension,
66
getDisplayVersionStatus,
77
getDisplayWorkspaceBuildInitiatedBy,
8+
getDisplayWorkspaceTemplateName,
89
isWorkspaceOn,
910
} from "./workspace"
1011

@@ -120,4 +121,22 @@ describe("util > workspace", () => {
120121
},
121122
)
122123
})
124+
125+
describe("getDisplayWorkspaceTemplateName", () => {
126+
it("display name is not set", async () => {
127+
const workspace: TypesGen.Workspace = {
128+
...Mocks.MockWorkspace,
129+
template_display_name: "",
130+
}
131+
const displayed = getDisplayWorkspaceTemplateName(workspace)
132+
expect(displayed).toEqual(workspace.template_name)
133+
})
134+
it("display name is set", async () => {
135+
const workspace: TypesGen.Workspace = {
136+
...Mocks.MockWorkspace,
137+
}
138+
const displayed = getDisplayWorkspaceTemplateName(workspace)
139+
expect(displayed).toEqual(workspace.template_display_name)
140+
})
141+
})
123142
})

site/src/util/workspace.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,3 +182,11 @@ export const getFaviconByStatus = (
182182
return "favicon"
183183
}
184184
}
185+
186+
export const getDisplayWorkspaceTemplateName = (
187+
workspace: TypesGen.Workspace,
188+
): string => {
189+
return workspace.template_display_name.length > 0
190+
? workspace.template_display_name
191+
: workspace.template_name
192+
}

0 commit comments

Comments
 (0)