chore: Enable Participating tab for conversations (#11714)

## Summary

This PR enables the **Participating** conversation view in the main
sidebar and keeps the behavior aligned with existing conversation views.

## What changed

- Added **Participating** under Conversations in the new sidebar.
- Added a guard in conversation realtime `addConversation` flow so
generic `conversation.created` events are not injected while the user is
on Participating view.
- Added participating route mapping in conversation-list redirect helper
so list redirects resolve correctly to `/participating/conversations`.

## Scope notes

- Kept changes minimal and consistent with current `develop` behavior.
- No additional update-event filtering was added beyond what existing
views already do.

---------


Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
Co-authored-by: iamsivin <iamsivin@gmail.com>
This commit is contained in:
Sojan Jose
2026-04-15 17:03:39 +05:30
committed by GitHub
parent 3f9f054c43
commit b96bf41234
13 changed files with 216 additions and 9 deletions

View File

@@ -183,6 +183,73 @@ describe('#getters', () => {
]);
});
});
describe('#getParticipatingChats', () => {
const conversationList = [
{ id: 1, inbox_id: 2, status: 1, meta: { assignee: { id: 1 } } },
{ id: 2, inbox_id: 2, status: 1, meta: {} },
{ id: 3, inbox_id: 3, status: 1, meta: { assignee: { id: 2 } } },
];
it('returns all conversations when watchers are not loaded', () => {
const state = {
allConversations: conversationList,
participatingConversationIds: {},
};
const rootGetters = {
getCurrentUser: { id: 1 },
'conversationWatchers/getByConversationId': () => undefined,
};
const result = getters.getParticipatingChats(
state,
{},
{},
rootGetters
)({ status: 1 });
expect(result).toEqual(conversationList);
});
it('filters out conversation when watchers loaded and user not participating', () => {
const state = {
allConversations: conversationList,
participatingConversationIds: {},
};
const rootGetters = {
getCurrentUser: { id: 1 },
'conversationWatchers/getByConversationId': id => {
if (id === 2) return [{ id: 3 }];
return undefined;
},
};
const result = getters.getParticipatingChats(
state,
{},
{},
rootGetters
)({ status: 1 });
expect(result).toEqual([conversationList[0], conversationList[2]]);
});
it('keeps conversation when watchers loaded and user is participating', () => {
const state = {
allConversations: conversationList,
participatingConversationIds: {},
};
const rootGetters = {
getCurrentUser: { id: 1 },
'conversationWatchers/getByConversationId': id => {
if (id === 1) return [{ id: 1 }, { id: 2 }];
return undefined;
},
};
const result = getters.getParticipatingChats(
state,
{},
{},
rootGetters
)({ status: 1 });
expect(result).toEqual(conversationList);
});
});
describe('#getConversationById', () => {
it('get conversations based on id', () => {
const state = {

View File

@@ -786,9 +786,55 @@ describe('#mutations', () => {
});
});
it('should add conversation if not found', () => {
it('should add conversation if not found on normal view', () => {
const state = {
allConversations: [],
conversationFilters: {},
};
const conversation = {
id: 1,
status: 'open',
};
mutations[types.UPDATE_CONVERSATION](state, conversation);
expect(state.allConversations).toEqual([conversation]);
});
it('should not add conversation if not found on participating view', () => {
const state = {
allConversations: [],
conversationFilters: { conversationType: 'participating' },
};
const conversation = {
id: 1,
status: 'open',
};
mutations[types.UPDATE_CONVERSATION](state, conversation);
expect(state.allConversations).toEqual([]);
});
it('should not add conversation if not found on mention view', () => {
const state = {
allConversations: [],
conversationFilters: { conversationType: 'mention' },
};
const conversation = {
id: 1,
status: 'open',
};
mutations[types.UPDATE_CONVERSATION](state, conversation);
expect(state.allConversations).toEqual([]);
});
it('should add conversation if not found on unattended view', () => {
const state = {
allConversations: [],
conversationFilters: { conversationType: 'unattended' },
};
const conversation = {