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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy