Files
chatwoot/app/javascript/dashboard/store/modules/agents.js
T
Shivam Mishra fe5c353106 feat: cache canned responses and agents in IndexedDB
Converts the canned-response and agent API clients to CacheEnabledApiClient
subclasses and wires revalidate actions into the corresponding Vuex modules,
so settings pages and pickers stop fetching the same lists on every visit.
The canned-response search box continues to bypass the cache and hit the
network directly, so server-side ordering stays authoritative.

Also fixes a pre-existing gap in teams/revalidate: SET_TEAMS merges into a
record dict by id and never removes missing entries, so a team deleted
server-side would survive a reconnect-driven revalidate. Now matches the
get action by emitting CLEAR_TEAMS first.

Each affected spec clears its IDB store before every case, since the
preflight-throws-on-axios-reject pattern they relied on is going away in the
next commit.
2026-05-21 17:21:53 +05:30

145 lines
4.2 KiB
JavaScript

import * as MutationHelpers from 'shared/helpers/vuex/mutationHelpers';
import * as types from '../mutation-types';
import AgentAPI from '../../api/agents';
export const state = {
records: [],
uiFlags: {
isFetching: false,
isCreating: false,
isUpdating: false,
isDeleting: false,
},
};
export const getters = {
getAgents($state) {
return $state.records;
},
getVerifiedAgents($state) {
return $state.records.filter(record => record.confirmed);
},
getUIFlags($state) {
return $state.uiFlags;
},
getAgentById: $state => id => {
return $state.records.find(record => record.id === Number(id)) || {};
},
getAgentStatus($state) {
let status = {
online: $state.records.filter(
agent => agent.availability_status === 'online'
).length,
busy: $state.records.filter(agent => agent.availability_status === 'busy')
.length,
offline: $state.records.filter(
agent => agent.availability_status === 'offline'
).length,
};
return status;
},
};
export const actions = {
get: async ({ commit }) => {
commit(types.default.SET_AGENT_FETCHING_STATUS, true);
try {
const response = await AgentAPI.get(true);
commit(types.default.SET_AGENT_FETCHING_STATUS, false);
commit(types.default.SET_AGENTS, response.data);
} catch (error) {
commit(types.default.SET_AGENT_FETCHING_STATUS, false);
}
},
revalidate: async ({ commit }, { newKey }) => {
try {
const isExistingKeyValid = await AgentAPI.validateCacheKey(newKey);
if (!isExistingKeyValid) {
const response = await AgentAPI.refetchAndCommit(newKey);
commit(types.default.SET_AGENTS, response.data);
}
} catch (error) {
// Ignore error
}
},
create: async ({ commit }, agentInfo) => {
commit(types.default.SET_AGENT_CREATING_STATUS, true);
try {
const response = await AgentAPI.create(agentInfo);
commit(types.default.ADD_AGENT, response.data);
commit(types.default.SET_AGENT_CREATING_STATUS, false);
} catch (error) {
commit(types.default.SET_AGENT_CREATING_STATUS, false);
throw error;
}
},
update: async ({ commit }, { id, ...agentParams }) => {
commit(types.default.SET_AGENT_UPDATING_STATUS, true);
try {
const response = await AgentAPI.update(id, agentParams);
commit(types.default.EDIT_AGENT, response.data);
commit(types.default.SET_AGENT_UPDATING_STATUS, false);
} catch (error) {
commit(types.default.SET_AGENT_UPDATING_STATUS, false);
throw new Error(error);
}
},
updateSingleAgentPresence: ({ commit }, { id, availabilityStatus }) => {
commit(types.default.UPDATE_SINGLE_AGENT_PRESENCE, {
id,
availabilityStatus,
});
},
updatePresence: async ({ commit }, data) => {
commit(types.default.UPDATE_AGENTS_PRESENCE, data);
},
delete: async ({ commit }, agentId) => {
commit(types.default.SET_AGENT_DELETING_STATUS, true);
try {
await AgentAPI.delete(agentId);
commit(types.default.DELETE_AGENT, agentId);
commit(types.default.SET_AGENT_DELETING_STATUS, false);
} catch (error) {
commit(types.default.SET_AGENT_DELETING_STATUS, false);
throw new Error(error);
}
},
};
export const mutations = {
[types.default.SET_AGENT_FETCHING_STATUS]($state, status) {
$state.uiFlags.isFetching = status;
},
[types.default.SET_AGENT_CREATING_STATUS]($state, status) {
$state.uiFlags.isCreating = status;
},
[types.default.SET_AGENT_UPDATING_STATUS]($state, status) {
$state.uiFlags.isUpdating = status;
},
[types.default.SET_AGENT_DELETING_STATUS]($state, status) {
$state.uiFlags.isDeleting = status;
},
[types.default.SET_AGENTS]: MutationHelpers.set,
[types.default.ADD_AGENT]: MutationHelpers.create,
[types.default.EDIT_AGENT]: MutationHelpers.update,
[types.default.DELETE_AGENT]: MutationHelpers.destroy,
[types.default.UPDATE_AGENTS_PRESENCE]: MutationHelpers.updatePresence,
[types.default.UPDATE_SINGLE_AGENT_PRESENCE]: (
$state,
{ id, availabilityStatus }
) =>
MutationHelpers.updateSingleRecordPresence($state.records, {
id,
availabilityStatus,
}),
};
export default {
namespaced: true,
state,
getters,
actions,
mutations,
};