diff --git a/app/javascript/dashboard/api/CacheEnabledApiClient.js b/app/javascript/dashboard/api/CacheEnabledApiClient.js index 2002a3a73..26e73ed2f 100644 --- a/app/javascript/dashboard/api/CacheEnabledApiClient.js +++ b/app/javascript/dashboard/api/CacheEnabledApiClient.js @@ -50,12 +50,11 @@ class CacheEnabledApiClient extends ApiClient { return this.getFromNetwork(); } - // Trust the IDB cache. Freshness is maintained by: - // - boot-time hydrateStoresFromCache (compares server keys once on boot) - // - ActionCable ACCOUNT_CACHE_INVALIDATED broadcasts (live updates) - // - ReconnectService.revalidateCaches (on WebSocket reconnect) - // Skipping the per-call /cache_keys preflight eliminates N GET requests per - // cold settings-page load. + // Trust the IDB cache. Freshness is maintained by the + // account.cache_invalidated event alone: RoomChannel pushes the cache-key + // map on every (re)subscribe — boot and reconnect included — and the + // server broadcasts it on every change. Skipping a per-call /cache_keys + // preflight eliminates N GET requests per cold settings-page load. const localData = await this.dataManager.get({ modelName: this.cacheModelName, }); diff --git a/app/javascript/dashboard/api/account.js b/app/javascript/dashboard/api/account.js index c0dcf05f3..82b0c434c 100644 --- a/app/javascript/dashboard/api/account.js +++ b/app/javascript/dashboard/api/account.js @@ -9,13 +9,6 @@ class AccountAPI extends ApiClient { createAccount(data) { return axios.post(`${this.apiVersion}/accounts`, data); } - - async getCacheKeys() { - const response = await axios.get( - `/api/v1/accounts/${this.accountIdFromRoute}/cache_keys` - ); - return response.data.cache_keys; - } } export default new AccountAPI(); diff --git a/app/javascript/dashboard/helper/ReconnectService.js b/app/javascript/dashboard/helper/ReconnectService.js index 59467ca55..f2149a380 100644 --- a/app/javascript/dashboard/helper/ReconnectService.js +++ b/app/javascript/dashboard/helper/ReconnectService.js @@ -6,7 +6,6 @@ import { isAInboxViewRoute, isNotificationRoute, } from 'dashboard/helper/routeHelpers'; -import { dispatchCacheRevalidations } from 'dashboard/helper/CacheHelper/dispatchCacheRevalidations'; const MAX_DISCONNECT_SECONDS = 10800; @@ -99,11 +98,6 @@ class ReconnectService { await this.store.dispatch('notifications/index', { ...filter, page: 1 }); }; - revalidateCaches = async () => { - const keys = (await this.store.dispatch('accounts/getCacheKeys')) || {}; - await dispatchCacheRevalidations(this.store, keys); - }; - handleRouteSpecificFetch = async () => { const currentRoute = this.router.currentRoute.value.name; if (isAConversationRoute(currentRoute, true)) { @@ -133,9 +127,11 @@ class ReconnectService { this.setConversationLastMessageId(); }; + // Cached workspace config needs no explicit revalidation here: ActionCable + // auto-resubscribes after a drop, and RoomChannel pushes the cache-key map + // on every subscribe via the account.cache_invalidated event. onReconnect = async () => { await this.handleRouteSpecificFetch(); - await this.revalidateCaches(); emitter.emit(BUS_EVENTS.WEBSOCKET_RECONNECT_COMPLETED); }; } diff --git a/app/javascript/dashboard/helper/specs/ReconnectService.spec.js b/app/javascript/dashboard/helper/specs/ReconnectService.spec.js index 6b0894662..608451d82 100644 --- a/app/javascript/dashboard/helper/specs/ReconnectService.spec.js +++ b/app/javascript/dashboard/helper/specs/ReconnectService.spec.js @@ -253,54 +253,6 @@ describe('ReconnectService', () => { }); }); - describe('revalidateCaches', () => { - it('should dispatch revalidate actions for every cacheable model returned by the server', async () => { - storeMock.dispatch.mockResolvedValueOnce({ - label: 'labelKey', - inbox: 'inboxKey', - team: 'teamKey', - canned_response: 'cannedKey', - account_user: 'accountUserKey', - }); - await reconnectService.revalidateCaches(); - expect(storeMock.dispatch).toHaveBeenCalledWith('accounts/getCacheKeys'); - expect(storeMock.dispatch).toHaveBeenCalledWith('labels/revalidate', { - newKey: 'labelKey', - }); - expect(storeMock.dispatch).toHaveBeenCalledWith('inboxes/revalidate', { - newKey: 'inboxKey', - }); - expect(storeMock.dispatch).toHaveBeenCalledWith('teams/revalidate', { - newKey: 'teamKey', - }); - expect(storeMock.dispatch).toHaveBeenCalledWith( - 'revalidateCannedResponses', - { newKey: 'cannedKey' } - ); - expect(storeMock.dispatch).toHaveBeenCalledWith('agents/revalidate', { - newKey: 'accountUserKey', - }); - }); - - it('should skip dispatches for models the server does not yet emit', async () => { - storeMock.dispatch.mockResolvedValueOnce({ - label: 'labelKey', - inbox: 'inboxKey', - team: 'teamKey', - // canned_response / account_user omitted (older server) - }); - await reconnectService.revalidateCaches(); - expect(storeMock.dispatch).not.toHaveBeenCalledWith( - 'revalidateCannedResponses', - expect.anything() - ); - expect(storeMock.dispatch).not.toHaveBeenCalledWith( - 'agents/revalidate', - expect.anything() - ); - }); - }); - describe('handleRouteSpecificFetch', () => { it('should fetch conversations and messages if current route is a conversation route', async () => { isAConversationRoute.mockReturnValue(true); @@ -362,12 +314,10 @@ describe('ReconnectService', () => { }); describe('onReconnect', () => { - it('should handle route-specific fetch, revalidate caches, and emit WEBSOCKET_RECONNECT_COMPLETED event', async () => { + it('should handle route-specific fetch and emit WEBSOCKET_RECONNECT_COMPLETED event', async () => { reconnectService.handleRouteSpecificFetch = vi.fn(); - reconnectService.revalidateCaches = vi.fn(); await reconnectService.onReconnect(); expect(reconnectService.handleRouteSpecificFetch).toHaveBeenCalled(); - expect(reconnectService.revalidateCaches).toHaveBeenCalled(); expect(emitter.emit).toHaveBeenCalledWith( BUS_EVENTS.WEBSOCKET_RECONNECT_COMPLETED ); diff --git a/app/javascript/dashboard/store/modules/accounts.js b/app/javascript/dashboard/store/modules/accounts.js index 68fd37010..a7521fd6f 100644 --- a/app/javascript/dashboard/store/modules/accounts.js +++ b/app/javascript/dashboard/store/modules/accounts.js @@ -163,10 +163,6 @@ export const actions = { commit(types.default.SET_ACCOUNT_UI_FLAG, { isFetchingLimits: false }); } }, - - getCacheKeys: async () => { - return AccountAPI.getCacheKeys(); - }, }; export const mutations = { diff --git a/app/javascript/shared/helpers/BaseActionCableConnector.js b/app/javascript/shared/helpers/BaseActionCableConnector.js index 846c815cd..06f529dde 100644 --- a/app/javascript/shared/helpers/BaseActionCableConnector.js +++ b/app/javascript/shared/helpers/BaseActionCableConnector.js @@ -14,9 +14,6 @@ class BaseActionCableConnector { ) { const websocketURL = websocketHost ? `${websocketHost}/cable` : undefined; - this.connected = new Promise(resolve => { - this.resolveConnected = resolve; - }); this.consumer = createConsumer(websocketURL); this.subscription = this.consumer.subscriptions.create( { @@ -29,10 +26,6 @@ class BaseActionCableConnector { updatePresence() { this.perform('update_presence'); }, - connected: () => { - this.resolveConnected(); - this.onConnected(); - }, received: this.onReceived, disconnected: () => { BaseActionCableConnector.isDisconnected = true; @@ -81,9 +74,6 @@ class BaseActionCableConnector { }, RECONNECT_INTERVAL); }; - // eslint-disable-next-line class-methods-use-this - onConnected = () => {}; - // eslint-disable-next-line class-methods-use-this onReconnect = () => {};