diff --git a/app/javascript/dashboard/api/attributes.js b/app/javascript/dashboard/api/attributes.js index 3552bb909..91d288991 100644 --- a/app/javascript/dashboard/api/attributes.js +++ b/app/javascript/dashboard/api/attributes.js @@ -1,13 +1,27 @@ -/* global axios */ -import ApiClient from './ApiClient'; +import CacheEnabledApiClient from './CacheEnabledApiClient'; -class AttributeAPI extends ApiClient { +class AttributeAPI extends CacheEnabledApiClient { constructor() { super('custom_attribute_definitions', { accountScoped: true }); } + // eslint-disable-next-line class-methods-use-this + get cacheModelName() { + return 'custom_attribute_definition'; + } + + // eslint-disable-next-line class-methods-use-this + extractDataFromResponse(response) { + return response.data; + } + + // eslint-disable-next-line class-methods-use-this + marshallData(dataToParse) { + return { data: dataToParse }; + } + getAttributesByModel() { - return axios.get(this.url); + return super.get(true); } } diff --git a/app/javascript/dashboard/helper/CacheHelper/cacheableModels.js b/app/javascript/dashboard/helper/CacheHelper/cacheableModels.js index 9eec7f354..1482142fa 100644 --- a/app/javascript/dashboard/helper/CacheHelper/cacheableModels.js +++ b/app/javascript/dashboard/helper/CacheHelper/cacheableModels.js @@ -36,6 +36,11 @@ export const cacheableModels = [ dispatchPath: 'agents/revalidate', setMutation: 'agents/SET_AGENTS', }, + { + name: 'custom_attribute_definition', + dispatchPath: 'attributes/revalidate', + setMutation: 'attributes/SET_CUSTOM_ATTRIBUTE', + }, ]; export const cacheableModelNames = cacheableModels.map(model => model.name); diff --git a/app/javascript/dashboard/helper/CacheHelper/version.js b/app/javascript/dashboard/helper/CacheHelper/version.js index bdf5b04c3..3d5893b56 100644 --- a/app/javascript/dashboard/helper/CacheHelper/version.js +++ b/app/javascript/dashboard/helper/CacheHelper/version.js @@ -5,5 +5,5 @@ // idempotently creates any missing stores. So bump this whenever a cached // model's serializer shape changes, or to force all clients to refetch. // -// Wednesday, 21 May 2026 — bumped to add canned_response + account_user stores -export const DATA_VERSION = '1747785600'; +// Thursday, 28 May 2026 — bumped to add canned_response + account_user stores + custom_attribute_definition store +export const DATA_VERSION = '1748390400'; diff --git a/app/javascript/dashboard/store/modules/attributes.js b/app/javascript/dashboard/store/modules/attributes.js index 1c7826cea..84a440618 100644 --- a/app/javascript/dashboard/store/modules/attributes.js +++ b/app/javascript/dashboard/store/modules/attributes.js @@ -54,6 +54,17 @@ export const actions = { commit(types.SET_CUSTOM_ATTRIBUTE_UI_FLAG, { isFetching: false }); } }, + revalidate: async ({ commit }, { newKey }) => { + try { + const isExistingKeyValid = await AttributeAPI.validateCacheKey(newKey); + if (!isExistingKeyValid) { + const response = await AttributeAPI.refetchAndCommit(newKey); + commit(types.SET_CUSTOM_ATTRIBUTE, response.data); + } + } catch (error) { + // Ignore error + } + }, create: async function createAttribute({ commit }, attributeObj) { commit(types.SET_CUSTOM_ATTRIBUTE_UI_FLAG, { isCreating: true }); try { diff --git a/app/javascript/dashboard/store/modules/specs/attributes/actions.spec.js b/app/javascript/dashboard/store/modules/specs/attributes/actions.spec.js index d3df969ac..6fe9c0d53 100644 --- a/app/javascript/dashboard/store/modules/specs/attributes/actions.spec.js +++ b/app/javascript/dashboard/store/modules/specs/attributes/actions.spec.js @@ -1,12 +1,20 @@ import axios from 'axios'; import { actions } from '../../attributes'; import * as types from '../../../mutation-types'; +import AttributeAPI from '../../../../api/attributes'; import attributesList from './fixtures'; const commit = vi.fn(); global.axios = axios; vi.mock('axios'); +// Clear the IDB-backed cache between tests so each case starts from a known +// empty state and isn't affected by data persisted by a previous test. +beforeEach(async () => { + await AttributeAPI.dataManager.initDb(); + await AttributeAPI.dataManager.db.clear(AttributeAPI.cacheModelName); +}); + describe('#actions', () => { describe('#get', () => { it('sends correct actions if API is success', async () => { diff --git a/app/models/concerns/cache_keys.rb b/app/models/concerns/cache_keys.rb index 5cb0c9e08..dc451526b 100644 --- a/app/models/concerns/cache_keys.rb +++ b/app/models/concerns/cache_keys.rb @@ -8,7 +8,7 @@ module CacheKeys included do class_attribute :cacheable_models - self.cacheable_models = [Label, Inbox, Team, CannedResponse, AccountUser] + self.cacheable_models = [Label, Inbox, Team, CannedResponse, AccountUser, CustomAttributeDefinition] end def cache_keys diff --git a/app/models/custom_attribute_definition.rb b/app/models/custom_attribute_definition.rb index 35f822335..a37feea8e 100644 --- a/app/models/custom_attribute_definition.rb +++ b/app/models/custom_attribute_definition.rb @@ -22,6 +22,8 @@ # index_custom_attribute_definitions_on_account_id (account_id) # class CustomAttributeDefinition < ApplicationRecord + include AccountCacheRevalidator + STANDARD_ATTRIBUTES = { :conversation => %w[status priority assignee_id inbox_id team_id display_id campaign_id labels browser_language country_code referer created_at last_activity_at],