33 createAsyncThunk ,
44 createSelector ,
55 createSlice ,
6- isAnyOf ,
76 PayloadAction ,
87} from '@reduxjs/toolkit' ;
98import { SNAPSHOT_EVENTS } from '@studio/common/lib/cli-events' ;
@@ -41,14 +40,7 @@ type DeleteOperation = BaseOperation & {
4140 optimistic ?: boolean ;
4241} ;
4342
44- type BulkOperation = Omit < BaseOperation , 'progress' > & {
45- operationIds : UUID [ ] ;
46- siteId ?: string ;
47- type : 'bulk' ;
48- userId ?: number ;
49- } ;
50-
51- export type SnapshotOperation = CreateOperation | UpdateOperation | DeleteOperation | BulkOperation ;
43+ export type SnapshotOperation = CreateOperation | UpdateOperation | DeleteOperation ;
5244
5345type SnapshotState = {
5446 operations : Record < UUID , SnapshotOperation > ;
@@ -97,41 +89,6 @@ const deleteSnapshot = createTypedAsyncThunk(
9789 }
9890) ;
9991
100- async function deleteMultipleSnapshots (
101- snapshots : Snapshot [ ]
102- ) : Promise < [ url : string , operationId : UUID ] [ ] > {
103- return await Promise . all (
104- snapshots . map ( async ( snapshot ) => {
105- const { operationId } = await getIpcApi ( ) . deleteSnapshot ( snapshot . url ) ;
106- return [ snapshot . url , operationId ] ;
107- } )
108- ) ;
109- }
110-
111- const deleteAllSnapshotsForSite = createTypedAsyncThunk <
112- { operations : [ url : string , operationId : UUID ] [ ] ; bulkOperationId : UUID } ,
113- { siteId : string }
114- > ( 'snapshot/deleteAllSnapshotsForSite' , async ( { siteId } , thunkAPI ) => {
115- const state = thunkAPI . getState ( ) ;
116- const snapshots = snapshotSelectors . selectSnapshotsBySite ( state , siteId ) ;
117- const operations = await deleteMultipleSnapshots ( snapshots ) ;
118- const bulkOperationId = window . crypto . randomUUID ( ) ;
119-
120- return { operations, bulkOperationId } ;
121- } ) ;
122-
123- const deleteAllSnapshotsForUser = createTypedAsyncThunk <
124- { operations : [ url : string , operationId : UUID ] [ ] ; bulkOperationId : UUID } ,
125- { userId : number }
126- > ( 'snapshot/deleteAllSnapshotsForUser' , async ( { userId } , thunkAPI ) => {
127- const state = thunkAPI . getState ( ) ;
128- const snapshots = snapshotSelectors . selectSnapshotsByUser ( state , userId ) ;
129- const operations = await deleteMultipleSnapshots ( snapshots ) ;
130- const bulkOperationId = window . crypto . randomUUID ( ) ;
131-
132- return { operations, bulkOperationId } ;
133- } ) ;
134-
13592const updateSnapshotLocally = createAction < {
13693 atomicSiteId : number ;
13794 snapshot : Partial < Omit < Snapshot , 'atomicSiteId' > > ;
@@ -200,47 +157,9 @@ const snapshotSlice = createSlice( {
200157 type : 'delete' ,
201158 optimistic : action . meta . arg . optimistic ?? false ,
202159 } ;
203- } )
204- . addMatcher (
205- isAnyOf ( deleteAllSnapshotsForSite . fulfilled , deleteAllSnapshotsForUser . fulfilled ) ,
206- ( state , action ) => {
207- if ( ! action . payload . operations . length ) {
208- return ;
209- }
210-
211- const bulkOperation : BulkOperation = {
212- error : null ,
213- operationIds : action . payload . operations . map ( ( [ _ , operationId ] ) => operationId ) ,
214- status : 'pending' ,
215- type : 'bulk' ,
216- } ;
217-
218- if ( 'siteId' in action . meta . arg ) {
219- bulkOperation . siteId = action . meta . arg . siteId ;
220- } else if ( 'userId' in action . meta . arg ) {
221- bulkOperation . userId = action . meta . arg . userId ;
222- }
223-
224- state . operations [ action . payload . bulkOperationId ] = bulkOperation ;
225-
226- action . payload . operations . forEach ( ( [ url , operationId ] ) => {
227- state . operations [ operationId ] = {
228- error : null ,
229- progress : 0 ,
230- snapshotUrl : url ,
231- status : 'pending' ,
232- type : 'delete' ,
233- } ;
234- } ) ;
235- }
236- ) ;
160+ } ) ;
237161 } ,
238162 selectors : {
239- selectActiveBulkOperationForUser : ( state , userId : number ) : BulkOperation | undefined =>
240- Object . values ( state . operations ) . find (
241- ( operation ) : operation is BulkOperation =>
242- operation . status === 'pending' && operation . type === 'bulk' && operation . userId === userId
243- ) ,
244163 selectActiveCreateOperationForSite : ( state , siteId : string ) : CreateOperation | undefined =>
245164 Object . values ( state . operations ) . find (
246165 ( operation ) : operation is CreateOperation =>
@@ -268,6 +187,9 @@ const snapshotSlice = createSlice( {
268187 } ,
269188} ) ;
270189
190+ // We use the `createSelector` API here to memoize the result. Whenever a selector returns a
191+ // reference type (array, object, etc), it's good to use `createSelector` to avoid unnecessary
192+ // React re-renders.
271193const selectActiveCreateUpdateOperationsForAnySite = createSelector (
272194 [ ( state : RootState ) => state . snapshot . operations ] ,
273195 ( operations ) =>
@@ -373,27 +295,6 @@ function getOperation( operationId: UUID ) {
373295 return state . snapshot . operations [ operationId ] ;
374296}
375297
376- function getAssociatedBulkOperation ( targetOperationId : UUID ) : [ UUID , BulkOperation ] | [ ] {
377- const state = store . getState ( ) ;
378- // `Object.entries()` always returns a string type for the key, but we know the type is actually constrained to UUID
379- const entries = Object . entries ( state . snapshot . operations ) as [ UUID , SnapshotOperation ] [ ] ;
380-
381- for ( const [ operationId , operation ] of entries ) {
382- if ( operation . type === 'bulk' && operation . operationIds . includes ( targetOperationId ) ) {
383- return [ operationId , operation ] ;
384- }
385- }
386-
387- return [ ] ;
388- }
389-
390- function isBulkOperationSettled ( bulkOperation : BulkOperation ) {
391- return bulkOperation . operationIds . every ( ( operationId ) => {
392- const operation = getOperation ( operationId ) ;
393- return operation && operation . status !== 'pending' ;
394- } ) ;
395- }
396-
397298window . ipcListener . subscribe ( 'snapshot-event' , ( _ , snapshotEvent ) => {
398299 const { event : eventType } = snapshotEvent ;
399300
@@ -528,18 +429,6 @@ window.ipcListener.subscribe( 'snapshot-success', ( event, payload ) => {
528429 } )
529430 ) ;
530431
531- const [ bulkOperationId , bulkOperation ] = getAssociatedBulkOperation ( payload . operationId ) ;
532- const bulkOperationIsSettled = bulkOperation && isBulkOperationSettled ( bulkOperation ) ;
533-
534- if ( bulkOperationId && bulkOperationIsSettled ) {
535- store . dispatch (
536- snapshotActions . updateOperation ( {
537- operationId : bulkOperationId ,
538- operation : { status : 'fulfilled' } ,
539- } )
540- ) ;
541- }
542-
543432 const { snapshotUrl = '' } = operation ;
544433
545434 if ( operation . type === 'create' ) {
@@ -553,18 +442,11 @@ window.ipcListener.subscribe( 'snapshot-success', ( event, payload ) => {
553442 body : sprintf ( __ ( "Preview site '%s' has been updated." ) , snapshotUrl ) ,
554443 } ) ;
555444 } else if ( operation . type === 'delete' ) {
556- if ( operation . optimistic ) {
557- // Do nothing
558- } else if ( ! bulkOperation ) {
445+ if ( ! operation . optimistic ) {
559446 getIpcApi ( ) . showNotification ( {
560447 title : operation . snapshotName ,
561448 body : sprintf ( __ ( "Preview site '%s' has been deleted." ) , snapshotUrl ) ,
562449 } ) ;
563- } else if ( bulkOperationIsSettled ) {
564- getIpcApi ( ) . showNotification ( {
565- title : __ ( 'Delete Successful' ) ,
566- body : __ ( 'All preview sites have been deleted.' ) ,
567- } ) ;
568450 }
569451 }
570452} ) ;
@@ -584,7 +466,5 @@ export const snapshotThunks = {
584466 createSnapshot,
585467 updateSnapshot,
586468 deleteSnapshot,
587- deleteAllSnapshotsForSite,
588- deleteAllSnapshotsForUser,
589469} ;
590470export const reducer = snapshotSlice . reducer ;
0 commit comments