Skip to content

Commit 5698b9d

Browse files
authored
feat: use sse for workspace page (#4122)
* added error handling * workspace machine cleanup * renaming callback * general cleanup * fixed tests * PR comments
1 parent 3db9ea9 commit 5698b9d

File tree

9 files changed

+141
-117
lines changed

9 files changed

+141
-117
lines changed

site/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
"cronstrue": "2.11.0",
4444
"dayjs": "1.11.4",
4545
"emoji-mart": "^5.2.1",
46+
"eventsourcemock": "^2.0.0",
4647
"formik": "^2.2.9",
4748
"front-matter": "4.0.2",
4849
"history": "5.3.0",

site/src/@types/eventsourcemock.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
declare module "eventsourcemock"

site/src/api/api.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,18 @@ export const getWorkspace = async (
219219
return response.data
220220
}
221221

222+
/**
223+
*
224+
* @param workspaceId
225+
* @returns An EventSource that emits workspace event objects (ServerSentEvent)
226+
*/
227+
export const watchWorkspace = (workspaceId: string): EventSource => {
228+
return new EventSource(
229+
`${location.protocol}//${location.host}/api/v2/workspaces/${workspaceId}/watch`,
230+
{ withCredentials: true },
231+
)
232+
}
233+
222234
export const getURLWithSearchParams = (
223235
basePath: string,
224236
filter?: TypesGen.WorkspaceFilter | TypesGen.UsersRequest,

site/src/pages/WorkspacePage/WorkspacePage.test.tsx

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/* eslint-disable @typescript-eslint/no-floating-promises */
22
import { fireEvent, screen, waitFor } from "@testing-library/react"
33
import userEvent from "@testing-library/user-event"
4+
import EventSource from "eventsourcemock"
45
import i18next from "i18next"
56
import { rest } from "msw"
67
import * as api from "../../api/api"
@@ -23,6 +24,7 @@ import {
2324
MockWorkspaceAgentConnecting,
2425
MockWorkspaceAgentDisconnected,
2526
MockWorkspaceBuild,
27+
MockWorkspaceResource2,
2628
renderWithAuth,
2729
} from "../../testHelpers/renderHelpers"
2830
import { server } from "../../testHelpers/server"
@@ -71,6 +73,11 @@ const testStatus = async (ws: Workspace, label: string) => {
7173

7274
beforeEach(() => {
7375
jest.resetAllMocks()
76+
77+
// mocking out EventSource for SSE
78+
Object.defineProperty(window, "EventSource", {
79+
value: EventSource,
80+
})
7481
})
7582

7683
describe("WorkspacePage", () => {
@@ -196,18 +203,43 @@ describe("WorkspacePage", () => {
196203
describe("Resources", () => {
197204
it("shows the status of each agent in each resource", async () => {
198205
const getTemplateMock = jest.spyOn(api, "getTemplate").mockResolvedValueOnce(MockTemplate)
206+
207+
const workspaceWithResources = {
208+
...MockWorkspace,
209+
latest_build: {
210+
...MockWorkspaceBuild,
211+
resources: [
212+
{
213+
...MockWorkspaceResource2,
214+
agents: [
215+
MockWorkspaceAgent,
216+
MockWorkspaceAgentDisconnected,
217+
MockWorkspaceAgentConnecting,
218+
],
219+
},
220+
],
221+
},
222+
}
223+
224+
server.use(
225+
rest.get(`/api/v2/users/:username/workspace/:workspaceName`, (req, res, ctx) => {
226+
return res(ctx.status(200), ctx.json(workspaceWithResources))
227+
}),
228+
)
229+
199230
renderWithAuth(<WorkspacePage />, {
200231
route: `/@${MockWorkspace.owner_name}/${MockWorkspace.name}`,
201232
path: "/@:username/:workspace",
202233
})
234+
203235
const agent1Names = await screen.findAllByText(MockWorkspaceAgent.name)
204-
expect(agent1Names.length).toEqual(2)
236+
expect(agent1Names.length).toEqual(1)
205237
const agent2Names = await screen.findAllByText(MockWorkspaceAgentDisconnected.name)
206238
expect(agent2Names.length).toEqual(2)
207239
const agent1Status = await screen.findAllByText(
208240
DisplayAgentStatusLanguage[MockWorkspaceAgent.status],
209241
)
210-
expect(agent1Status.length).toEqual(4)
242+
expect(agent1Status.length).toEqual(1)
211243
const agentDisconnected = await screen.findAllByText(
212244
DisplayAgentStatusLanguage[MockWorkspaceAgentDisconnected.status],
213245
)

site/src/pages/WorkspacePage/WorkspacePage.tsx

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,8 @@ export const WorkspacePage: FC = () => {
4040
workspace,
4141
getWorkspaceError,
4242
template,
43-
refreshTemplateError,
44-
resources,
45-
getResourcesError,
43+
refreshTemplateWarning,
44+
refreshWorkspaceWarning,
4645
builds,
4746
getBuildsError,
4847
permissions,
@@ -70,7 +69,7 @@ export const WorkspacePage: FC = () => {
7069
return (
7170
<div className={styles.error}>
7271
{Boolean(getWorkspaceError) && <ErrorSummary error={getWorkspaceError} />}
73-
{Boolean(refreshTemplateError) && <ErrorSummary error={refreshTemplateError} />}
72+
{Boolean(refreshTemplateWarning) && <ErrorSummary error={refreshTemplateWarning} />}
7473
{Boolean(checkPermissionsError) && <ErrorSummary error={checkPermissionsError} />}
7574
</div>
7675
)
@@ -128,11 +127,11 @@ export const WorkspacePage: FC = () => {
128127
handleDelete={() => workspaceSend("ASK_DELETE")}
129128
handleUpdate={() => workspaceSend("UPDATE")}
130129
handleCancel={() => workspaceSend("CANCEL")}
131-
resources={resources}
130+
resources={workspace.latest_build.resources}
132131
builds={builds}
133132
canUpdateWorkspace={canUpdateWorkspace}
134133
workspaceErrors={{
135-
[WorkspaceErrors.GET_RESOURCES_ERROR]: getResourcesError,
134+
[WorkspaceErrors.GET_RESOURCES_ERROR]: refreshWorkspaceWarning,
136135
[WorkspaceErrors.GET_BUILDS_ERROR]: getBuildsError,
137136
[WorkspaceErrors.BUILD_ERROR]: buildError,
138137
[WorkspaceErrors.CANCELLATION_ERROR]: cancellationError,

site/src/testHelpers/entities.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -380,7 +380,7 @@ export const MockWorkspaceAgentOutdated: TypesGen.WorkspaceAgent = {
380380

381381
export const MockWorkspaceAgentConnecting: TypesGen.WorkspaceAgent = {
382382
...MockWorkspaceAgent,
383-
id: "test-workspace-agent-2",
383+
id: "test-workspace-agent-connecting",
384384
name: "another-workspace-agent",
385385
status: "connecting",
386386
version: "",

0 commit comments

Comments
 (0)