Skip to content
This repository was archived by the owner on May 30, 2024. It is now read-only.

Commit b926519

Browse files
author
noah
committed
Subscribe the deployment status event in UI
1 parent 277d562 commit b926519

File tree

8 files changed

+129
-5
lines changed

8 files changed

+129
-5
lines changed

ui/src/apis/deployment.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,14 +117,21 @@ function mapDeploymentStatusEnum(s: string) {
117117
}
118118
}
119119

120-
function mapDataToDeploymentStatus(data: any): DeploymentStatus {
120+
// eslint-disable-next-line
121+
export function mapDataToDeploymentStatus(data: any): DeploymentStatus {
121122
return {
122123
id: data.id,
123124
status: data.status,
124125
description: data.description,
125126
logUrl: data.log_url,
126127
createdAt: data.created_at,
127128
updatedAt: data.updated_at,
129+
deploymentId: data.deployment_id,
130+
repoId: data.repo_id,
131+
edges: {
132+
deployment: (data.edges.deployment)? mapDataToDeployment(data.edges.deployment) : undefined,
133+
repo: (data.edges.repo)? mapDataToRepo(data.edges.repo) : undefined
134+
}
128135
}
129136
}
130137

ui/src/apis/events.ts

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { instance } from './setting'
22

3-
import { mapDataToDeployment } from "./deployment"
4-
import { mapDataToReview } from "./review"
5-
import { Deployment, Review } from "../models"
3+
import { mapDataToDeployment, mapDataToDeploymentStatus } from "./deployment"
4+
import { mapDataToReview } from "./review"
5+
import { Deployment, DeploymentStatus, Review } from "../models"
66

77

88
export const subscribeDeploymentEvents = (cb: (deployment: Deployment) => void): EventSource => {
@@ -20,6 +20,21 @@ export const subscribeDeploymentEvents = (cb: (deployment: Deployment) => void):
2020
return sse
2121
}
2222

23+
export const subscribeDeploymentStatusEvents = (cb: (status: DeploymentStatus) => void): EventSource => {
24+
const sse = new EventSource(`${instance}/api/v1/stream/events`, {
25+
withCredentials: true,
26+
})
27+
28+
sse.addEventListener("deployment_status", (e: any) => {
29+
const data = JSON.parse(e.data)
30+
const status = mapDataToDeploymentStatus(data)
31+
32+
cb(status)
33+
})
34+
35+
return sse
36+
}
37+
2338
export const subscribeReviewEvents = (cb: (review: Review) => void): EventSource => {
2439
const sse = new EventSource(`${instance}/api/v1/stream/events`, {
2540
withCredentials: true,

ui/src/apis/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,5 +66,6 @@ export {
6666
} from "./license"
6767
export {
6868
subscribeDeploymentEvents,
69+
subscribeDeploymentStatusEvents,
6970
subscribeReviewEvents,
7071
} from "./events"

ui/src/models/Deployment.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,10 @@ export interface DeploymentStatus {
4141
logUrl: string
4242
createdAt: string
4343
updatedAt: string
44+
deploymentId: number
45+
repoId: number
46+
edges?: {
47+
deployment?: Deployment
48+
repo?: Repo
49+
}
4450
}

ui/src/redux/deployment.tsx

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { createSlice, createAsyncThunk, PayloadAction } from '@reduxjs/toolkit'
33

44
import {
55
Deployment,
6+
DeploymentStatus,
67
Commit,
78
Review,
89
RequestStatus,
@@ -165,6 +166,21 @@ export const fetchUserReview = createAsyncThunk<Review, void, { state: {deployme
165166
},
166167
)
167168

169+
export const handleDeploymentStatusEvent = createAsyncThunk<Deployment, DeploymentStatus, { state: { deployment: DeploymentState } }>(
170+
"deployment/handleDeploymentStatusEvent",
171+
async (deploymentStatus, { rejectWithValue }) => {
172+
if (deploymentStatus.edges === undefined) {
173+
return rejectWithValue(new Error("Edges is not included."))
174+
}
175+
176+
const { repo, deployment } = deploymentStatus.edges
177+
if (repo === undefined || deployment === undefined) {
178+
return rejectWithValue(new Error("Repo or Deployment is not included in the edges."))
179+
}
180+
181+
return await getDeployment(repo.namespace, repo.name, deployment.number)
182+
}
183+
)
168184

169185
export const deploymentSlice = createSlice({
170186
name: "deployment",
@@ -228,5 +244,10 @@ export const deploymentSlice = createSlice({
228244
.addCase(fetchUserReview.fulfilled, (state, action) => {
229245
state.userReview = action.payload
230246
})
247+
.addCase(handleDeploymentStatusEvent.fulfilled, (state, action) => {
248+
if (action.payload.id === state.deployment?.id) {
249+
state.deployment = action.payload
250+
}
251+
})
231252
}
232253
})

ui/src/redux/main.ts

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,13 @@ import {
1111
HttpPaymentRequiredError,
1212
License,
1313
ReviewStatusEnum,
14+
DeploymentStatus,
1415
} from "../models"
1516
import {
1617
getMe,
1718
searchDeployments as _searchDeployments,
1819
searchReviews as _searchReviews,
20+
getDeployment,
1921
getLicense
2022
} from "../apis"
2123
import { getShortRef } from "../libs"
@@ -157,6 +159,27 @@ export const notifyDeploymentEvent = createAsyncThunk<void, Deployment, { state:
157159
}
158160
)
159161

162+
export const notifyDeploymentStatusEvent = createAsyncThunk<void, DeploymentStatus, { state: { main: MainState } }>(
163+
"main/notifyDeploymentStatusEvent",
164+
async (deploymentStatus, {rejectWithValue}) => {
165+
if (deploymentStatus.edges === undefined) {
166+
return rejectWithValue(new Error("Edges is not included."))
167+
}
168+
169+
const { repo, deployment } = deploymentStatus.edges
170+
if (repo === undefined || deployment === undefined) {
171+
return rejectWithValue(new Error("Repo or Deployment is not included in the edges."))
172+
}
173+
174+
notify(`${repo.namespace}/${repo.name} #${deployment.number}`, {
175+
icon: "/logo192.png",
176+
body: `${deploymentStatus.status} - ${deploymentStatus.description}`,
177+
tag: String(deployment.id),
178+
179+
})
180+
}
181+
)
182+
160183
/**
161184
* The browser notifies the requester when the review is responded to,
162185
* but it should notify the reviewer when the review is requested.
@@ -183,6 +206,22 @@ export const notifyReviewmentEvent = createAsyncThunk<void, Review, { state: { m
183206
)
184207

185208

209+
export const handleDeploymentStatusEvent = createAsyncThunk<Deployment, DeploymentStatus, { state: { main: MainState } }>(
210+
"main/handleDeploymentStatusEvent",
211+
async (deploymentStatus, { rejectWithValue }) => {
212+
if (deploymentStatus.edges === undefined) {
213+
return rejectWithValue(new Error("Edges is not included."))
214+
}
215+
216+
const { repo, deployment } = deploymentStatus.edges
217+
if (repo === undefined || deployment === undefined) {
218+
return rejectWithValue(new Error("Repo or Deployment is not included in the edges."))
219+
}
220+
221+
return await getDeployment(repo.namespace, repo.name, deployment.number)
222+
}
223+
)
224+
186225
export const mainSlice = createSlice({
187226
name: "main",
188227
initialState,
@@ -240,5 +279,21 @@ export const mainSlice = createSlice({
240279
.addCase(fetchLicense.fulfilled, (state, action) => {
241280
state.license = action.payload
242281
})
282+
283+
.addCase(handleDeploymentStatusEvent.fulfilled, (state, { payload: deployment }) => {
284+
if (deployment.status === DeploymentStatusEnum.Created) {
285+
state.deployments.unshift(deployment)
286+
return
287+
}
288+
289+
state.deployments = state.deployments.map((item) => {
290+
return (item.id === deployment.id)? deployment : item
291+
})
292+
293+
state.deployments = state.deployments.filter((item) => {
294+
return !(item.status === DeploymentStatusEnum.Success
295+
|| item.status === DeploymentStatusEnum.Failure)
296+
})
297+
})
243298
}
244299
})

ui/src/views/deployment/index.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
fetchUserReview,
1515
approve,
1616
reject,
17+
handleDeploymentStatusEvent
1718
} from "../../redux/deployment"
1819
import {
1920
Deployment,
@@ -24,6 +25,7 @@ import {
2425
} from "../../models"
2526
import {
2627
subscribeDeploymentEvents,
28+
subscribeDeploymentStatusEvents,
2729
subscribeReviewEvents
2830
} from "../../apis"
2931

@@ -68,12 +70,17 @@ export default (): JSX.Element => {
6870
dispatch(slice.actions.handleDeploymentEvent(deployment))
6971
})
7072

73+
const deploymentStatusEvent = subscribeDeploymentStatusEvents((deploymentStatus) => {
74+
dispatch(handleDeploymentStatusEvent(deploymentStatus))
75+
})
76+
7177
const reviewEvent = subscribeReviewEvents((review) => {
7278
dispatch(slice.actions.handleReviewEvent(review))
7379
})
7480

7581
return () => {
7682
deploymentEvent.close()
83+
deploymentStatusEvent.close()
7784
reviewEvent.close()
7885
}
7986
// eslint-disable-next-line

ui/src/views/main/index.tsx

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,20 @@ import { Helmet } from "react-helmet"
55
import moment from "moment"
66

77
import { useAppSelector, useAppDispatch } from "../../redux/hooks"
8-
import { subscribeDeploymentEvents, subscribeReviewEvents } from "../../apis"
8+
import {
9+
subscribeDeploymentEvents,
10+
subscribeDeploymentStatusEvents,
11+
subscribeReviewEvents
12+
} from "../../apis"
913
import {
1014
init,
1115
searchDeployments,
1216
searchReviews,
1317
fetchLicense,
1418
notifyDeploymentEvent,
19+
notifyDeploymentStatusEvent,
1520
notifyReviewmentEvent,
21+
handleDeploymentStatusEvent,
1622
mainSlice as slice
1723
} from "../../redux/main"
1824

@@ -45,13 +51,19 @@ export default (props: React.PropsWithChildren<any>): JSX.Element => {
4551
dispatch(notifyDeploymentEvent(deployment))
4652
})
4753

54+
const deploymentStatusEvents = subscribeDeploymentStatusEvents((deploymentStatus) => {
55+
dispatch(handleDeploymentStatusEvent(deploymentStatus))
56+
dispatch(notifyDeploymentStatusEvent(deploymentStatus))
57+
})
58+
4859
const reviewEvents = subscribeReviewEvents((review) => {
4960
dispatch(slice.actions.handleReviewEvent(review))
5061
dispatch(notifyReviewmentEvent(review))
5162
})
5263

5364
return () => {
5465
deploymentEvents.close()
66+
deploymentStatusEvents.close()
5567
reviewEvents.close()
5668
}
5769
}, [dispatch])

0 commit comments

Comments
 (0)