Skip to content

Commit 3beddf3

Browse files
committed
fix: Update routing for workspace schedule
This was broken as part of #2101. It was a silly mistake, but unfortunate our tests didn't catch it. This is a rare change so unlikely to occur again, so I won't make an issue adding tests.
1 parent 3878e64 commit 3beddf3

File tree

11 files changed

+95
-45
lines changed

11 files changed

+95
-45
lines changed

coderd/workspacebuilds.go

Lines changed: 56 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,16 @@ func (api *API) workspaceBuild(rw http.ResponseWriter, r *http.Request) {
3737
return
3838
}
3939

40-
httpapi.Write(rw, http.StatusOK, convertWorkspaceBuild(workspace, workspaceBuild, job))
40+
owner, err := api.Database.GetUserByID(r.Context(), workspace.OwnerID)
41+
if err != nil {
42+
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
43+
Message: "Internal error fetching user",
44+
Detail: err.Error(),
45+
})
46+
return
47+
}
48+
49+
httpapi.Write(rw, http.StatusOK, convertWorkspaceBuild(owner, workspace, workspaceBuild, job))
4150
}
4251

4352
func (api *API) workspaceBuilds(rw http.ResponseWriter, r *http.Request) {
@@ -100,8 +109,8 @@ func (api *API) workspaceBuilds(rw http.ResponseWriter, r *http.Request) {
100109
}
101110

102111
jobIDs := make([]uuid.UUID, 0, len(builds))
103-
for _, version := range builds {
104-
jobIDs = append(jobIDs, version.JobID)
112+
for _, build := range builds {
113+
jobIDs = append(jobIDs, build.JobID)
105114
}
106115
jobs, err := api.Database.GetProvisionerJobsByIDs(r.Context(), jobIDs)
107116
if errors.Is(err, sql.ErrNoRows) {
@@ -119,6 +128,15 @@ func (api *API) workspaceBuilds(rw http.ResponseWriter, r *http.Request) {
119128
jobByID[job.ID.String()] = job
120129
}
121130

131+
owner, err := api.Database.GetUserByID(r.Context(), workspace.OwnerID)
132+
if err != nil {
133+
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
134+
Message: "Internal error fetching user",
135+
Detail: err.Error(),
136+
})
137+
return
138+
}
139+
122140
apiBuilds := make([]codersdk.WorkspaceBuild, 0)
123141
for _, build := range builds {
124142
job, exists := jobByID[build.JobID.String()]
@@ -128,7 +146,7 @@ func (api *API) workspaceBuilds(rw http.ResponseWriter, r *http.Request) {
128146
})
129147
return
130148
}
131-
apiBuilds = append(apiBuilds, convertWorkspaceBuild(workspace, build, job))
149+
apiBuilds = append(apiBuilds, convertWorkspaceBuild(owner, workspace, build, job))
132150
}
133151

134152
httpapi.Write(rw, http.StatusOK, apiBuilds)
@@ -167,8 +185,16 @@ func (api *API) workspaceBuildByName(rw http.ResponseWriter, r *http.Request) {
167185
})
168186
return
169187
}
188+
owner, err := api.Database.GetUserByID(r.Context(), workspace.OwnerID)
189+
if err != nil {
190+
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
191+
Message: "Internal error getting user",
192+
Detail: err.Error(),
193+
})
194+
return
195+
}
170196

171-
httpapi.Write(rw, http.StatusOK, convertWorkspaceBuild(workspace, workspaceBuild, job))
197+
httpapi.Write(rw, http.StatusOK, convertWorkspaceBuild(owner, workspace, workspaceBuild, job))
172198
}
173199

174200
func (api *API) postWorkspaceBuilds(rw http.ResponseWriter, r *http.Request) {
@@ -342,8 +368,17 @@ func (api *API) postWorkspaceBuilds(rw http.ResponseWriter, r *http.Request) {
342368
return
343369
}
344370

371+
owner, err := api.Database.GetUserByID(r.Context(), workspace.OwnerID)
372+
if err != nil {
373+
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
374+
Message: "Internal error getting user",
375+
Detail: err.Error(),
376+
})
377+
return
378+
}
379+
345380
httpapi.Write(rw, http.StatusCreated,
346-
convertWorkspaceBuild(workspace, workspaceBuild, provisionerJob))
381+
convertWorkspaceBuild(owner, workspace, workspaceBuild, provisionerJob))
347382
}
348383

349384
func (api *API) patchCancelWorkspaceBuild(rw http.ResponseWriter, r *http.Request) {
@@ -473,6 +508,7 @@ func (api *API) workspaceBuildState(rw http.ResponseWriter, r *http.Request) {
473508
}
474509

475510
func convertWorkspaceBuild(
511+
workspaceOwner database.User,
476512
workspace database.Workspace,
477513
workspaceBuild database.WorkspaceBuild,
478514
job database.ProvisionerJob) codersdk.WorkspaceBuild {
@@ -481,18 +517,20 @@ func convertWorkspaceBuild(
481517
panic("workspace and build do not match")
482518
}
483519
return codersdk.WorkspaceBuild{
484-
ID: workspaceBuild.ID,
485-
CreatedAt: workspaceBuild.CreatedAt,
486-
UpdatedAt: workspaceBuild.UpdatedAt,
487-
WorkspaceID: workspaceBuild.WorkspaceID,
488-
WorkspaceName: workspace.Name,
489-
TemplateVersionID: workspaceBuild.TemplateVersionID,
490-
BuildNumber: workspaceBuild.BuildNumber,
491-
Name: workspaceBuild.Name,
492-
Transition: codersdk.WorkspaceTransition(workspaceBuild.Transition),
493-
InitiatorID: workspaceBuild.InitiatorID,
494-
Job: convertProvisionerJob(job),
495-
Deadline: workspaceBuild.Deadline,
520+
ID: workspaceBuild.ID,
521+
CreatedAt: workspaceBuild.CreatedAt,
522+
UpdatedAt: workspaceBuild.UpdatedAt,
523+
WorkspaceOwnerID: workspace.OwnerID,
524+
WorkspaceOwnerName: workspaceOwner.Username,
525+
WorkspaceID: workspaceBuild.WorkspaceID,
526+
WorkspaceName: workspace.Name,
527+
TemplateVersionID: workspaceBuild.TemplateVersionID,
528+
BuildNumber: workspaceBuild.BuildNumber,
529+
Name: workspaceBuild.Name,
530+
Transition: codersdk.WorkspaceTransition(workspaceBuild.Transition),
531+
InitiatorID: workspaceBuild.InitiatorID,
532+
Job: convertProvisionerJob(job),
533+
Deadline: workspaceBuild.Deadline,
496534
}
497535
}
498536

coderd/workspaces.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -796,7 +796,7 @@ func convertWorkspace(
796796
OwnerID: workspace.OwnerID,
797797
OwnerName: owner.Username,
798798
TemplateID: workspace.TemplateID,
799-
LatestBuild: convertWorkspaceBuild(workspace, workspaceBuild, job),
799+
LatestBuild: convertWorkspaceBuild(owner, workspace, workspaceBuild, job),
800800
TemplateName: template.Name,
801801
Outdated: workspaceBuild.TemplateVersionID.String() != template.ActiveVersionID.String(),
802802
Name: workspace.Name,

codersdk/workspacebuilds.go

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,18 +22,20 @@ const (
2222
// WorkspaceBuild is an at-point representation of a workspace state.
2323
// BuildNumbers start at 1 and increase by 1 for each subsequent build
2424
type WorkspaceBuild struct {
25-
ID uuid.UUID `json:"id"`
26-
CreatedAt time.Time `json:"created_at"`
27-
UpdatedAt time.Time `json:"updated_at"`
28-
WorkspaceID uuid.UUID `json:"workspace_id"`
29-
WorkspaceName string `json:"workspace_name"`
30-
TemplateVersionID uuid.UUID `json:"template_version_id"`
31-
BuildNumber int32 `json:"build_number"`
32-
Name string `json:"name"`
33-
Transition WorkspaceTransition `json:"transition"`
34-
InitiatorID uuid.UUID `json:"initiator_id"`
35-
Job ProvisionerJob `json:"job"`
36-
Deadline time.Time `json:"deadline"`
25+
ID uuid.UUID `json:"id"`
26+
CreatedAt time.Time `json:"created_at"`
27+
UpdatedAt time.Time `json:"updated_at"`
28+
WorkspaceID uuid.UUID `json:"workspace_id"`
29+
WorkspaceName string `json:"workspace_name"`
30+
WorkspaceOwnerID uuid.UUID `json:"workspace_owner_id"`
31+
WorkspaceOwnerName string `json:"workspace_owner_name"`
32+
TemplateVersionID uuid.UUID `json:"template_version_id"`
33+
BuildNumber int32 `json:"build_number"`
34+
Name string `json:"name"`
35+
Transition WorkspaceTransition `json:"transition"`
36+
InitiatorID uuid.UUID `json:"initiator_id"`
37+
Job ProvisionerJob `json:"job"`
38+
Deadline time.Time `json:"deadline"`
3739
}
3840

3941
// WorkspaceBuild returns a single workspace build for a workspace.

site/src/api/typesGenerated.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,8 @@ export interface WorkspaceBuild {
436436
readonly updated_at: string
437437
readonly workspace_id: string
438438
readonly workspace_name: string
439+
readonly workspace_owner_id: string
440+
readonly workspace_owner_name: string
439441
readonly template_version_id: string
440442
readonly build_number: number
441443
readonly name: string

site/src/components/WorkspaceBuildStats/WorkspaceBuildStats.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export const WorkspaceBuildStats: FC<WorkspaceBuildStatsProps> = ({ build }) =>
2222
<span className={styles.statsLabel}>Workspace Name</span>
2323
<Link
2424
component={RouterLink}
25-
to={`/workspaces/${build.workspace_id}`}
25+
to={`/@${build.workspace_owner_name}/${build.workspace_name}`}
2626
className={combineClasses([styles.statsValue, styles.link])}
2727
>
2828
{build.workspace_name}

site/src/components/WorkspaceSchedule/WorkspaceSchedule.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ export const WorkspaceSchedule: FC<WorkspaceScheduleProps> = ({ workspace }) =>
9292
<span className={styles.scheduleValue}>{Language.autoStopDisplay(workspace)}</span>
9393
</div>
9494
<div>
95-
<Link className={styles.scheduleAction} component={RouterLink} to={`/workspaces/${workspace.id}/schedule`}>
95+
<Link className={styles.scheduleAction} component={RouterLink} to={`/@${workspace.owner_name}/${workspace.name}/schedule`}>
9696
{Language.editScheduleLink}
9797
</Link>
9898
</div>

site/src/pages/CreateWorkspacePage/CreateWorkspacePage.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ const CreateWorkspacePage: FC = () => {
1717
context: { organizationId, preSelectedTemplateName },
1818
actions: {
1919
onCreateWorkspace: (_, event) => {
20-
navigate("/workspaces/" + event.data.id)
20+
navigate(`/@${event.data.owner_name}/${event.data.name}`)
2121
},
2222
},
2323
})

site/src/pages/WorkspaceSchedulePage/WorkspaceSchedulePage.tsx

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -142,33 +142,39 @@ export const workspaceToInitialValues = (
142142
}
143143

144144
export const WorkspaceSchedulePage: React.FC = () => {
145+
const { username: usernameQueryParam, workspace: workspaceQueryParam } = useParams()
145146
const navigate = useNavigate()
146-
const { workspace: workspaceQueryParam } = useParams()
147-
const workspaceId = firstOrItem(workspaceQueryParam, null)
147+
const username = firstOrItem(usernameQueryParam, null)
148+
const workspaceName = firstOrItem(workspaceQueryParam, null)
148149
const [scheduleState, scheduleSend] = useMachine(workspaceSchedule)
149150
const { formErrors, getWorkspaceError, workspace } = scheduleState.context
150151

151152
// Get workspace on mount and whenever workspaceId changes.
152153
// scheduleSend should not change.
153154
useEffect(() => {
154-
workspaceId && scheduleSend({ type: "GET_WORKSPACE", workspaceId })
155-
}, [workspaceId, scheduleSend])
155+
username && workspaceName && scheduleSend({ type: "GET_WORKSPACE", username, workspaceName })
156+
}, [username, workspaceName, scheduleSend])
156157

157-
if (!workspaceId) {
158+
if (!username || !workspaceName) {
158159
navigate("/workspaces")
159160
return null
160161
} else if (scheduleState.matches("idle") || scheduleState.matches("gettingWorkspace") || !workspace) {
161162
return <FullScreenLoader />
162163
} else if (scheduleState.matches("error")) {
163-
return <ErrorSummary error={getWorkspaceError} retry={() => scheduleSend({ type: "GET_WORKSPACE", workspaceId })} />
164+
return (
165+
<ErrorSummary
166+
error={getWorkspaceError}
167+
retry={() => scheduleSend({ type: "GET_WORKSPACE", username, workspaceName })}
168+
/>
169+
)
164170
} else if (scheduleState.matches("presentForm") || scheduleState.matches("submittingSchedule")) {
165171
return (
166172
<WorkspaceScheduleForm
167173
fieldErrors={formErrors}
168174
initialValues={workspaceToInitialValues(workspace, dayjs.tz.guess())}
169175
isLoading={scheduleState.tags.has("loading")}
170176
onCancel={() => {
171-
navigate(`/workspaces/${workspaceId}`)
177+
navigate(`/@${username}/${workspaceName}`)
172178
}}
173179
onSubmit={(values) => {
174180
scheduleSend({
@@ -180,7 +186,7 @@ export const WorkspaceSchedulePage: React.FC = () => {
180186
/>
181187
)
182188
} else if (scheduleState.matches("submitSuccess")) {
183-
navigate(`/workspaces/${workspaceId}`)
189+
navigate(`/@${username}/${workspaceName}`)
184190
return <FullScreenLoader />
185191
} else {
186192
// Theoretically impossible - log and bail

site/src/testHelpers/entities.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,8 @@ export const MockWorkspaceBuild: TypesGen.WorkspaceBuild = {
135135
transition: "start",
136136
updated_at: "2022-05-17T17:39:01.382927298Z",
137137
workspace_name: "test-workspace",
138+
workspace_owner_id: MockUser.id,
139+
workspace_owner_name: MockUser.username,
138140
workspace_id: "759f1d46-3174-453d-aa60-980a9c1442f3",
139141
deadline: "2022-05-17T23:39:00.00Z",
140142
}

site/src/xServices/workspaceSchedule/workspaceScheduleXService.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export interface WorkspaceScheduleContext {
2626
}
2727

2828
export type WorkspaceScheduleEvent =
29-
| { type: "GET_WORKSPACE"; workspaceId: string }
29+
| { type: "GET_WORKSPACE"; username: string; workspaceName: string }
3030
| {
3131
type: "SUBMIT_SCHEDULE"
3232
autoStart: TypesGen.UpdateWorkspaceAutostartRequest
@@ -132,7 +132,7 @@ export const workspaceSchedule = createMachine(
132132

133133
services: {
134134
getWorkspace: async (_, event) => {
135-
return await API.getWorkspace(event.workspaceId)
135+
return await API.getWorkspaceByOwnerAndName(event.username, event.workspaceName)
136136
},
137137
submitSchedule: async (context, event) => {
138138
if (!context.workspace?.id) {

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