Merge branch 'feature/cw-7495-api' into feature/cw-7496-frontend

This commit is contained in:
Aakash Bakhle
2026-07-17 18:04:41 +05:30
committed by GitHub
103 changed files with 2929 additions and 405 deletions
@@ -25,24 +25,32 @@ const fetchMetaData = async (commit, params) => {
}
};
const debouncedFetchMetaData = debounce(fetchMetaData, 500, false, 2000);
const longDebouncedFetchMetaData = debounce(fetchMetaData, 5000, false, 10000);
const debouncedFetchMetaData = debounce(fetchMetaData, 1000, false, 5000);
const longDebouncedFetchMetaData = debounce(fetchMetaData, 7500, false, 20000);
const superLongDebouncedFetchMetaData = debounce(
fetchMetaData,
10000,
15000,
false,
20000
30000
);
const metaDebouncers = {
default: debouncedFetchMetaData,
long: longDebouncedFetchMetaData,
superLong: superLongDebouncedFetchMetaData,
};
// allCount is 0 until a meta request succeeds; under load it stays 0, so treat
// the unknown case as a large account and poll slowest instead of fastest.
export const getMetaDebounceKey = allCount => {
if (allCount > 2000 || allCount === 0) return 'superLong';
if (allCount > 100) return 'long';
return 'default';
};
export const actions = {
get: async ({ commit, state: $state }, params) => {
if ($state.allCount > 2000) {
superLongDebouncedFetchMetaData(commit, params);
} else if ($state.allCount > 100) {
longDebouncedFetchMetaData(commit, params);
} else {
debouncedFetchMetaData(commit, params);
}
get: ({ commit, state: $state }, params) => {
metaDebouncers[getMetaDebounceKey($state.allCount)](commit, params);
},
set({ commit }, meta) {
commit(types.SET_CONV_TAB_META, meta);
@@ -96,6 +96,32 @@ export const actions = {
}
},
// Push the draft to live and clear it, optionally changing status in the same
// update. Only edited fields are sent so an untouched live value survives.
publishDraft: ({ dispatch, state }, { portalSlug, articleId, status }) => {
const article = state.articles.byId[articleId];
const payload = {
portalSlug,
articleId,
status,
draft_title: null,
draft_content: null,
};
if (article?.draftTitle != null) payload.title = article.draftTitle;
if (article?.draftContent != null) payload.content = article.draftContent;
return dispatch('update', payload);
},
// Clear the draft (optionally changing status); live content is left untouched.
discardDraft: ({ dispatch }, { portalSlug, articleId, status }) =>
dispatch('update', {
portalSlug,
articleId,
status,
draft_title: null,
draft_content: null,
}),
updateArticleMeta: async ({ commit }, { portalSlug, locale }) => {
try {
const { data } = await articlesAPI.getArticles({
@@ -150,6 +150,101 @@ describe('#actions', () => {
});
});
describe('#publishDraft', () => {
const state = {
articles: {
byId: {
1: {
id: 1,
draftTitle: 'Draft title',
draftContent: 'Draft content',
},
},
},
};
it('dispatches update promoting the edited fields and clearing the draft', async () => {
await actions.publishDraft(
{ dispatch, state },
{ portalSlug: 'room-rental', articleId: 1 }
);
expect(dispatch).toHaveBeenCalledWith('update', {
portalSlug: 'room-rental',
articleId: 1,
status: undefined,
draft_title: null,
draft_content: null,
title: 'Draft title',
content: 'Draft content',
});
});
it('only sends the fields that were actually edited', async () => {
const partialState = {
articles: { byId: { 1: { id: 1, draftContent: 'Only content' } } },
};
await actions.publishDraft(
{ dispatch, state: partialState },
{ portalSlug: 'room-rental', articleId: 1 }
);
expect(dispatch).toHaveBeenCalledWith('update', {
portalSlug: 'room-rental',
articleId: 1,
status: undefined,
draft_title: null,
draft_content: null,
content: 'Only content',
});
});
it('forwards a status to change it in the same update', async () => {
await actions.publishDraft(
{ dispatch, state },
{ portalSlug: 'room-rental', articleId: 1, status: 'archived' }
);
expect(dispatch).toHaveBeenCalledWith(
'update',
expect.objectContaining({
status: 'archived',
title: 'Draft title',
content: 'Draft content',
draft_title: null,
draft_content: null,
})
);
});
});
describe('#discardDraft', () => {
it('dispatches update clearing the draft columns', async () => {
await actions.discardDraft(
{ dispatch },
{ portalSlug: 'room-rental', articleId: 1 }
);
expect(dispatch).toHaveBeenCalledWith('update', {
portalSlug: 'room-rental',
articleId: 1,
status: undefined,
draft_title: null,
draft_content: null,
});
});
it('forwards a status to change it in the same update', async () => {
await actions.discardDraft(
{ dispatch },
{ portalSlug: 'room-rental', articleId: 1, status: 'draft' }
);
expect(dispatch).toHaveBeenCalledWith('update', {
portalSlug: 'room-rental',
articleId: 1,
status: 'draft',
draft_title: null,
draft_content: null,
});
});
});
describe('#updateArticleMeta', () => {
it('sends correct actions if API is success', async () => {
axios.get.mockResolvedValue({