ISSUE-825 Improve refresh without WS (#826)
This commit is contained in:
@@ -60,6 +60,7 @@ describe('websocket messages storm', () => {
|
||||
;(getDisplayedCalendarRange as jest.Mock).mockReturnValue(mockRange)
|
||||
;(store.getState as jest.Mock).mockReturnValue(mockState)
|
||||
window.WS_DEBOUNCE_PERIOD_MS = 500
|
||||
window.WS_SKIP_DELAY_MS = 0
|
||||
mockAccumulators.calendarsToRefresh = new Map<string, any>()
|
||||
mockAccumulators.calendarsToHide = new Set()
|
||||
mockAccumulators.shouldRefreshCalendarListRef.current = false
|
||||
|
||||
@@ -53,6 +53,7 @@ describe('updateCalendars', () => {
|
||||
mockAccumulators.currentDebouncePeriod = 0
|
||||
mockAccumulators.shouldRefreshCalendarListRef.current = false
|
||||
mockAccumulators.debouncedUpdateFn = jest.fn()
|
||||
window.WS_SKIP_DELAY_MS = 0
|
||||
})
|
||||
|
||||
it('should not dispatch for non-object messages', () => {
|
||||
|
||||
+4
-1
@@ -1,4 +1,5 @@
|
||||
import eventsCalendar from '@/features/Calendars/CalendarSlice'
|
||||
import { postMutationRefreshMiddleware } from '@/features/Calendars/listeners/postMutationRefresh'
|
||||
import searchResultReducer from '@/features/Search/SearchSlice'
|
||||
import settingsReducer from '@/features/Settings/SettingsSlice'
|
||||
import userReducer from '@/features/User/userSlice'
|
||||
@@ -24,7 +25,9 @@ export const setupStore = (preloadedState?: Partial<RootState>) => {
|
||||
reducer: rootReducer,
|
||||
preloadedState,
|
||||
middleware: getDefaultMiddleware =>
|
||||
getDefaultMiddleware().concat(routerMiddleware)
|
||||
getDefaultMiddleware()
|
||||
.concat(routerMiddleware)
|
||||
.prepend(postMutationRefreshMiddleware.middleware)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
import type { AppDispatch, RootState } from '@/app/store'
|
||||
import { findCalendarById, getDisplayedCalendarRange } from '@/utils'
|
||||
import { createListenerMiddleware } from '@reduxjs/toolkit'
|
||||
import {
|
||||
deleteEventAsync,
|
||||
deleteEventInstanceAsync,
|
||||
moveEventAsync,
|
||||
putEventAsync,
|
||||
refreshCalendarWithSyncToken,
|
||||
updateEventInstanceAsync,
|
||||
updateSeriesAsync
|
||||
} from '../services'
|
||||
|
||||
export const postMutationRefreshMiddleware = createListenerMiddleware()
|
||||
|
||||
const startListening = postMutationRefreshMiddleware.startListening.withTypes<
|
||||
RootState,
|
||||
AppDispatch
|
||||
>()
|
||||
|
||||
function triggerRefresh(
|
||||
dispatch: AppDispatch,
|
||||
getState: () => RootState,
|
||||
calId: string
|
||||
): void {
|
||||
const found = findCalendarById(getState(), calId)
|
||||
if (!found) return
|
||||
void dispatch(
|
||||
refreshCalendarWithSyncToken({
|
||||
calendar: found.calendar,
|
||||
calType: found.type,
|
||||
calendarRange: getDisplayedCalendarRange()
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
startListening({
|
||||
actionCreator: putEventAsync.fulfilled,
|
||||
effect: (action, listenerApi) => {
|
||||
triggerRefresh(
|
||||
listenerApi.dispatch,
|
||||
() => listenerApi.getState(),
|
||||
action.payload.calId
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
startListening({
|
||||
actionCreator: deleteEventAsync.fulfilled,
|
||||
effect: (action, listenerApi) => {
|
||||
triggerRefresh(
|
||||
listenerApi.dispatch,
|
||||
() => listenerApi.getState(),
|
||||
action.payload.calId
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
startListening({
|
||||
actionCreator: deleteEventInstanceAsync.fulfilled,
|
||||
effect: (action, listenerApi) => {
|
||||
triggerRefresh(
|
||||
listenerApi.dispatch,
|
||||
() => listenerApi.getState(),
|
||||
action.payload.calId
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
startListening({
|
||||
actionCreator: updateEventInstanceAsync.fulfilled,
|
||||
effect: (action, listenerApi) => {
|
||||
triggerRefresh(
|
||||
listenerApi.dispatch,
|
||||
() => listenerApi.getState(),
|
||||
action.payload.calId
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
startListening({
|
||||
actionCreator: moveEventAsync.fulfilled,
|
||||
effect: (action, listenerApi) => {
|
||||
triggerRefresh(
|
||||
listenerApi.dispatch,
|
||||
() => listenerApi.getState(),
|
||||
action.payload.calId
|
||||
)
|
||||
const sourceCalId = action.meta.arg.newEvent.calId
|
||||
if (sourceCalId && sourceCalId !== action.payload.calId) {
|
||||
triggerRefresh(
|
||||
listenerApi.dispatch,
|
||||
() => listenerApi.getState(),
|
||||
sourceCalId
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
startListening({
|
||||
actionCreator: updateSeriesAsync.fulfilled,
|
||||
effect: (action, listenerApi) => {
|
||||
triggerRefresh(
|
||||
listenerApi.dispatch,
|
||||
() => listenerApi.getState(),
|
||||
action.meta.arg.cal.id
|
||||
)
|
||||
}
|
||||
})
|
||||
@@ -13,6 +13,7 @@ import { parseMessage } from './parseMessage'
|
||||
import { UpdateCalendarsAccumulators } from './type/UpdateCalendarsAccumulators'
|
||||
|
||||
const DEFAULT_DEBOUNCE_MS = 0
|
||||
const DEFAULT_WS_SKIP_DELAY_MS = 2000
|
||||
|
||||
function createDebouncedUpdate(
|
||||
debouncePeriodMs: number,
|
||||
@@ -39,7 +40,7 @@ function createDebouncedUpdate(
|
||||
resetShouldRefreshCalendarList()
|
||||
|
||||
try {
|
||||
processCalendarsToRefresh(dispatch, currentRange, calendarsToProcess)
|
||||
scheduleCalendarsRefresh(dispatch, currentRange, calendarsToProcess)
|
||||
processCalendarsToHide(calendarsToHideSnapshot)
|
||||
|
||||
if (shouldRefresh) {
|
||||
@@ -106,7 +107,7 @@ export function updateCalendars(
|
||||
accumulators.shouldRefreshCalendarListRef.current = false
|
||||
|
||||
try {
|
||||
processCalendarsToRefresh(dispatch, currentRange, calendarsToProcess)
|
||||
scheduleCalendarsRefresh(dispatch, currentRange, calendarsToProcess)
|
||||
processCalendarsToHide(calendarsToHideSnapshot)
|
||||
if (shouldRefreshCalendarList) {
|
||||
dispatch(getCalendarsListAsync())
|
||||
@@ -117,6 +118,52 @@ export function updateCalendars(
|
||||
}
|
||||
|
||||
// --- Helpers ---
|
||||
|
||||
function scheduleCalendarsRefresh(
|
||||
dispatch: AppDispatch,
|
||||
currentRange: { start: Date; end: Date },
|
||||
calendarsMap: Map<string, { calendar: Calendar; type?: 'temp' }>
|
||||
) {
|
||||
const skipDelayMs = window.WS_SKIP_DELAY_MS ?? DEFAULT_WS_SKIP_DELAY_MS
|
||||
|
||||
if (skipDelayMs === 0) {
|
||||
dispatchCalendarsRefresh(dispatch, currentRange, calendarsMap)
|
||||
return
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
const stateAfterDelay = store.getState()
|
||||
const rangeAfterDelay = getDisplayedCalendarRange()
|
||||
calendarsMap.forEach(({ calendar, type }, calId) => {
|
||||
const current = findCalendarById(stateAfterDelay, calId)
|
||||
if (current && current.calendar.syncToken !== calendar.syncToken) return
|
||||
dispatch(
|
||||
refreshCalendarWithSyncToken({
|
||||
calendar: current?.calendar ?? calendar,
|
||||
calType: type,
|
||||
calendarRange: rangeAfterDelay
|
||||
})
|
||||
)
|
||||
})
|
||||
}, skipDelayMs)
|
||||
}
|
||||
|
||||
function dispatchCalendarsRefresh(
|
||||
dispatch: AppDispatch,
|
||||
currentRange: { start: Date; end: Date },
|
||||
calendarsMap: Map<string, { calendar: Calendar; type?: 'temp' }>
|
||||
) {
|
||||
calendarsMap.forEach(({ calendar, type }) => {
|
||||
dispatch(
|
||||
refreshCalendarWithSyncToken({
|
||||
calendar,
|
||||
calType: type,
|
||||
calendarRange: currentRange
|
||||
})
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
function accumulateCalendarsToRefresh(
|
||||
state: ReturnType<typeof store.getState>,
|
||||
calendarPaths: Set<string>,
|
||||
@@ -149,22 +196,6 @@ function accumulateCalendarsToHide(
|
||||
})
|
||||
}
|
||||
|
||||
function processCalendarsToRefresh(
|
||||
dispatch: AppDispatch,
|
||||
currentRange: { start: Date; end: Date },
|
||||
calendarsMap: Map<string, { calendar: Calendar; type?: 'temp' }>
|
||||
) {
|
||||
calendarsMap.forEach(calendar => {
|
||||
dispatch(
|
||||
refreshCalendarWithSyncToken({
|
||||
calendar: calendar.calendar,
|
||||
calType: calendar.type,
|
||||
calendarRange: currentRange
|
||||
})
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
function processCalendarsToHide(calendarsToHideSnapshot: Set<string>) {
|
||||
if (calendarsToHideSnapshot.size === 0) return
|
||||
|
||||
|
||||
Vendored
+1
@@ -27,6 +27,7 @@ declare global {
|
||||
|
||||
WEBSOCKET_URL: string
|
||||
WS_DEBOUNCE_PERIOD_MS: number
|
||||
WS_SKIP_DELAY_MS: number
|
||||
WS_PING_PERIOD_MS: number
|
||||
WS_PING_TIMEOUT_PERIOD_MS: number
|
||||
|
||||
|
||||
Reference in New Issue
Block a user