refactor: fold cache revalidation into the event dispatcher

This commit is contained in:
Shivam Mishra
2026-06-10 12:59:26 +05:30
parent 343b25842a
commit 3e65534e68
11 changed files with 136 additions and 184 deletions
@@ -4,39 +4,18 @@
// so the server's `cache_keys` payload (and the IDB object store name) lines up
// with what the client looks up.
//
// `dispatchPath` is the full Vuex dispatch path for the revalidate action.
// `setMutation` is the full commit path used by paintStoresFromCache to seed
// Vuex from IDB. Every SET_* mutation must REPLACE its records (not merge) so
// rows deleted server-side never survive as phantoms.
// `setMutation` is the full commit path used to seed Vuex from IDB (boot
// paint) and to swap in refetched rows (event-driven revalidation). Every
// SET_* mutation must REPLACE its records (not merge) so rows deleted
// server-side never survive as phantoms.
export const cacheableModels = [
{
name: 'inbox',
dispatchPath: 'inboxes/revalidate',
setMutation: 'inboxes/SET_INBOXES',
},
{
name: 'label',
dispatchPath: 'labels/revalidate',
setMutation: 'labels/SET_LABELS',
},
{
name: 'team',
dispatchPath: 'teams/revalidate',
setMutation: 'teams/SET_TEAMS',
},
{
name: 'canned_response',
dispatchPath: 'revalidateCannedResponses',
setMutation: 'SET_CANNED',
},
{
name: 'account_user',
dispatchPath: 'agents/revalidate',
setMutation: 'agents/SET_AGENTS',
},
{ name: 'inbox', setMutation: 'inboxes/SET_INBOXES' },
{ name: 'label', setMutation: 'labels/SET_LABELS' },
{ name: 'team', setMutation: 'teams/SET_TEAMS' },
{ name: 'canned_response', setMutation: 'SET_CANNED' },
{ name: 'account_user', setMutation: 'agents/SET_AGENTS' },
{
name: 'custom_attribute_definition',
dispatchPath: 'attributes/revalidate',
setMutation: 'attributes/SET_CUSTOM_ATTRIBUTE',
},
];
@@ -1,10 +1,42 @@
import AgentAPI from 'dashboard/api/agents';
import AttributeAPI from 'dashboard/api/attributes';
import CannedResponseAPI from 'dashboard/api/cannedResponse';
import InboxesAPI from 'dashboard/api/inboxes';
import LabelsAPI from 'dashboard/api/labels';
import TeamsAPI from 'dashboard/api/teams';
import { cacheableModels } from './cacheableModels';
// model name → cache-enabled API client. Lives here rather than in
// cacheableModels to keep that module import-cycle-free: the API clients
// import DataManager, which imports cacheableModels.
const apiByModel = {
inbox: InboxesAPI,
label: LabelsAPI,
team: TeamsAPI,
canned_response: CannedResponseAPI,
account_user: AgentAPI,
custom_attribute_definition: AttributeAPI,
};
const revalidateModel = async (store, model, newKey) => {
try {
const api = apiByModel[model.name];
if (await api.validateCacheKey(newKey)) return;
const response = await api.refetchAndCommit(newKey);
store.commit(model.setMutation, api.extractDataFromResponse(response));
} catch {
// Ignore error — a failed refetch leaves the painted data in place; the
// next pushed key map retries.
}
};
// The single freshness engine: given a pushed { model_name => key } map
// (RoomChannel transmits one on every (re)subscribe, the server broadcasts
// one on every change), diff each key against IDB and refetch mismatches.
export const dispatchCacheRevalidations = (store, keys = {}) =>
Promise.all(
cacheableModels
.filter(model => keys[model.name] !== undefined)
.map(model =>
store.dispatch(model.dispatchPath, { newKey: keys[model.name] })
)
.map(model => revalidateModel(store, model, keys[model.name]))
);