@@ -39,12 +39,6 @@ const initialState: MainState = {
39
39
reviews : [ ] ,
40
40
}
41
41
42
- const runningDeploymentStatus : DeploymentStatusEnum [ ] = [
43
- DeploymentStatusEnum . Waiting ,
44
- DeploymentStatusEnum . Created ,
45
- DeploymentStatusEnum . Running ,
46
- ]
47
-
48
42
export const apiMiddleware : Middleware = ( api : MiddlewareAPI ) => (
49
43
next
50
44
) => ( action ) => {
@@ -81,18 +75,28 @@ export const init = createAsyncThunk<User, void, { state: { main: MainState } }>
81
75
}
82
76
)
83
77
78
+ /**
79
+ * Search all processing deployments that the user can access.
80
+ */
84
81
export const searchDeployments = createAsyncThunk < Deployment [ ] , void , { state : { main : MainState } } > (
85
82
"main/searchDeployments" ,
86
83
async ( _ , { rejectWithValue } ) => {
87
84
try {
88
- const deployments = await _searchDeployments ( runningDeploymentStatus , false )
85
+ const deployments = await _searchDeployments ( [
86
+ DeploymentStatusEnum . Waiting ,
87
+ DeploymentStatusEnum . Created ,
88
+ DeploymentStatusEnum . Running ,
89
+ ] , false )
89
90
return deployments
90
91
} catch ( e ) {
91
92
return rejectWithValue ( e )
92
93
}
93
94
}
94
95
)
95
96
97
+ /**
98
+ * Search all reviews has requested.
99
+ */
96
100
export const searchReviews = createAsyncThunk < Review [ ] , void , { state : { main : MainState } } > (
97
101
"main/searchReviews" ,
98
102
async ( _ , { rejectWithValue } ) => {
@@ -117,6 +121,87 @@ export const fetchLicense = createAsyncThunk<License, void, { state: { main: Mai
117
121
}
118
122
)
119
123
124
+ const notify = ( title : string , options ?: NotificationOptions ) => {
125
+ if ( ! ( "Notification" in window ) ) {
126
+ console . log ( "This browser doesn't support the notification." )
127
+ return
128
+ }
129
+
130
+ if ( Notification . permission === "default" ) {
131
+ Notification . requestPermission ( )
132
+ }
133
+
134
+ new Notification ( title , options )
135
+ }
136
+
137
+ /**
138
+ * The browser notifies only the user who triggers the deployment.
139
+ */
140
+ export const notifyDeploymentEvent = createAsyncThunk < void , Event , { state : { main : MainState } } > (
141
+ "main/notifyDeploymentEvent" ,
142
+ async ( event , { getState } ) => {
143
+ const { user } = getState ( ) . main
144
+
145
+ if ( event . kind !== EventKindEnum . Deployment ) {
146
+ return
147
+ }
148
+
149
+ if ( event . deployment ?. deployer ?. id !== user ?. id ) {
150
+ return
151
+ }
152
+
153
+ if ( event . type === EventTypeEnum . Created ) {
154
+ notify ( `New Deployment #${ event . deployment ?. number } ` , {
155
+ icon : "/logo192.png" ,
156
+ body : `Start to deploy ${ event . deployment ?. ref . substring ( 0 , 7 ) } to the ${ event . deployment ?. env } environment of ${ event . deployment ?. repo ?. namespace } /${ event . deployment ?. repo ?. name } .` ,
157
+ tag : String ( event . id ) ,
158
+ } )
159
+ return
160
+ }
161
+
162
+ notify ( `Deployment Updated #${ event . deployment ?. number } ` , {
163
+ icon : "/logo192.png" ,
164
+ body : `The deployment ${ event . deployment ?. number } of ${ event . deployment ?. repo ?. namespace } /${ event . deployment ?. repo ?. name } is updated ${ event . deployment ?. status } .` ,
165
+ tag : String ( event . id ) ,
166
+ } )
167
+ }
168
+ )
169
+
170
+ /**
171
+ * The browser notifies the requester when the review is responded to,
172
+ * but it should notify the reviewer when the review is requested.
173
+ */
174
+ export const notifyReviewmentEvent = createAsyncThunk < void , Event , { state : { main : MainState } } > (
175
+ "main/notifyReviewmentEvent" ,
176
+ async ( event , { getState } ) => {
177
+ const { user } = getState ( ) . main
178
+ if ( event . kind !== EventKindEnum . Review ) {
179
+ return
180
+ }
181
+
182
+ if ( event . type === EventTypeEnum . Created
183
+ && event . review ?. user ?. id === user ?. id ) {
184
+ notify ( `Review Requested` , {
185
+ icon : "/logo192.png" ,
186
+ body : `${ event . review ?. deployment ?. deployer ?. login } requested the review for the deployment ${ event . review ?. deployment ?. number } of ${ event . review ?. deployment ?. repo ?. namespace } /${ event . review ?. deployment ?. repo ?. name } ` ,
187
+ tag : String ( event . id ) ,
188
+ } )
189
+ return
190
+ }
191
+
192
+ if ( event . type === EventTypeEnum . Updated
193
+ && event . review ?. deployment ?. deployer ?. id === user ?. id ) {
194
+ notify ( `Review Responded` , {
195
+ icon : "/logo192.png" ,
196
+ body : `${ event . review ?. user ?. login } ${ event . review ?. status } the deployment ${ event . review ?. deployment ?. number } of ${ event . review ?. deployment ?. repo ?. namespace } /${ event . review ?. deployment ?. repo ?. name } ` ,
197
+ tag : String ( event . id ) ,
198
+ } )
199
+ return
200
+ }
201
+ }
202
+ )
203
+
204
+
120
205
export const mainSlice = createSlice ( {
121
206
name : "main" ,
122
207
initialState,
@@ -130,54 +215,48 @@ export const mainSlice = createSlice({
130
215
setExpired : ( state , action : PayloadAction < boolean > ) => {
131
216
state . expired = action . payload
132
217
} ,
218
+ /**
219
+ * Handle all deployment events that the user can access.
220
+ * Note that some deployments are triggered by others.
221
+ */
133
222
handleDeploymentEvent : ( state , action : PayloadAction < Event > ) => {
134
- const user = state . user
135
- if ( ! user ) {
136
- throw new Error ( "Unauthorized user." )
137
- }
138
-
139
223
const event = action . payload
224
+ if ( event . kind !== EventKindEnum . Deployment ) {
225
+ return
226
+ }
140
227
141
- // Handling the event when the owner is same.
142
- if ( event . deployment ?. deployer ?. id !== user . id ) {
228
+ if ( event . type === EventTypeEnum . Created
229
+ && event . deployment ) {
230
+ state . deployments . unshift ( event . deployment )
143
231
return
144
232
}
145
233
234
+ // Update the deployment if it exist.
146
235
const idx = state . deployments . findIndex ( ( deployment ) => {
147
236
return event . deployment ?. id === deployment . id
148
237
} )
149
238
150
239
if ( idx !== - 1 ) {
151
- // Remove from the list when the status is not one of 'waiting', 'created', and 'running'.
152
- if ( ! runningDeploymentStatus . includes ( event . deployment . status ) ) {
240
+ if ( ! ( event . deployment ?. status === DeploymentStatusEnum . Waiting
241
+ || event . deployment ?. status === DeploymentStatusEnum . Created
242
+ || event . deployment ?. status === DeploymentStatusEnum . Running ) ) {
153
243
state . deployments . splice ( idx , 1 )
154
244
return
155
245
}
156
246
157
247
state . deployments [ idx ] = event . deployment
158
248
return
159
249
}
160
-
161
- state . deployments . unshift ( event . deployment )
162
250
} ,
163
251
handleReviewEvent : ( state , action : PayloadAction < Event > ) => {
164
252
const event = action . payload
165
-
166
253
if ( action . payload . kind !== EventKindEnum . Review ) {
167
254
return
168
- }
255
+ }
169
256
170
- const user = state . user
171
- if ( ! user ) {
172
- throw new Error ( "Unauthorized user." )
173
- }
174
-
175
- // Handling the event when the user own the event.
176
- if ( event . review ?. user ?. id !== user . id ) {
177
- return
178
- }
179
-
180
- if ( event . type === EventTypeEnum . Created ) {
257
+ if ( event . type === EventTypeEnum . Created
258
+ && event . review
259
+ && event . review ?. user ?. id === state . user ?. id ) {
181
260
state . reviews . unshift ( event . review )
182
261
return
183
262
}
0 commit comments