[IMP] mail: display guest in channel member list
Part of task-2664860 closes odoo/odoo#95859 Signed-off-by: Louis Wicket (wil) <wil@odoo.com>
This commit is contained in:
@@ -1176,15 +1176,29 @@ class Channel(models.Model):
|
||||
count = self.env['mail.channel.partner'].search_count(
|
||||
domain=[('channel_id', '=', self.id)],
|
||||
)
|
||||
return {
|
||||
'channelMembers': [('insert', [{
|
||||
members_data = []
|
||||
for member in channel_partners:
|
||||
if member.partner_id:
|
||||
persona = {
|
||||
'partner': [('insert-and-replace', {
|
||||
'id': member.partner_id.id,
|
||||
'name': member.partner_id.name,
|
||||
'im_status': member.partner_id.im_status,
|
||||
})],
|
||||
}
|
||||
if member.guest_id:
|
||||
persona = {
|
||||
'guest': [('insert-and-replace', {
|
||||
'id': member.guest_id.id,
|
||||
'name': member.guest_id.name,
|
||||
})],
|
||||
}
|
||||
members_data.append({
|
||||
'id': member.id,
|
||||
'partner': [('insert', {
|
||||
'id': member.partner_id.id,
|
||||
'name': member.partner_id.name,
|
||||
'im_status': member.partner_id.im_status,
|
||||
})] if member.partner_id else [('clear',)],
|
||||
} for member in channel_partners])],
|
||||
'persona': [('insert-and-replace', persona)],
|
||||
})
|
||||
return {
|
||||
'channelMembers': [('insert', members_data)],
|
||||
'memberCount': count,
|
||||
}
|
||||
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
<templates xml:space="preserve">
|
||||
|
||||
<t t-name="mail.ChannelMember" owl="1">
|
||||
<div class="o_ChannelMember d-flex align-items-center mx-2 p-2" t-att-class="{'o_cursor_pointer': channelMemberView.hasOpenChat}" t-attf-class="{{ className }}" t-att-data-partner-local-id="channelMemberView.channelMember.partner.localId" t-att-title="channelMemberView.memberTitleText" t-on-click="channelMemberView.onClickMember" t-ref="root">
|
||||
<div class="o_ChannelMember d-flex align-items-center mx-2 p-2" t-att-class="{'o_cursor_pointer': channelMemberView.hasOpenChat}" t-attf-class="{{ className }}" t-att-data-partner-id="channelMemberView.channelMember.persona.partner and channelMemberView.channelMember.persona.partner.id" t-att-title="channelMemberView.memberTitleText" t-on-click="channelMemberView.onClickMember" t-ref="root">
|
||||
<div class="o_ChannelMember_avatarContainer position-relative flex-shrink-0">
|
||||
<img class="o_ChannelMember_avatar rounded-circle w-100 h-100" t-attf-src="/mail/channel/{{ channelMemberView.channelMember.channel.id }}/partner/{{ channelMemberView.channelMember.partner.id }}/avatar_128" alt="Avatar"/>
|
||||
<img class="o_ChannelMember_avatar rounded-circle w-100 h-100" t-att-src="channelMemberView.channelMember.avatarUrl" alt="Avatar"/>
|
||||
|
||||
<t t-if="channelMemberView.personaImStatusIconView">
|
||||
<PersonaImStatusIcon
|
||||
@@ -19,7 +19,7 @@
|
||||
</t>
|
||||
</div>
|
||||
<span class="o_ChannelMember_name ms-2 flex-column-1 text-truncate">
|
||||
<t t-esc="channelMemberView.channelMember.partner.nameOrDisplayName"/>
|
||||
<t t-esc="channelMemberView.channelMember.persona.name"/>
|
||||
</span>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
@@ -52,8 +52,8 @@ registerModel({
|
||||
*/
|
||||
_sortMembers() {
|
||||
return [
|
||||
['truthy-first', 'name'],
|
||||
['case-insensitive-asc', 'name'],
|
||||
['truthy-first', 'persona.name'],
|
||||
['case-insensitive-asc', 'persona.name'],
|
||||
];
|
||||
},
|
||||
},
|
||||
|
||||
@@ -8,32 +8,50 @@ registerModel({
|
||||
name: 'ChannelMember',
|
||||
identifyingFields: ['id'],
|
||||
recordMethods: {
|
||||
/**
|
||||
* @private
|
||||
* @returns {string|FieldCommand}
|
||||
*/
|
||||
_computeAvatarUrl() {
|
||||
if (this.persona.partner) {
|
||||
return `/mail/channel/${this.channel.id}/partner/${this.persona.partner.id}/avatar_128`;
|
||||
}
|
||||
if (this.persona.guest) {
|
||||
return `/mail/channel/${this.channel.id}/guest/${this.persona.guest.id}/avatar_128?unique=${this.persona.guest.name}`;
|
||||
}
|
||||
return clear();
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @returns {FieldCommand}
|
||||
*/
|
||||
_computeChannelAsOfflineMember() {
|
||||
return this.partner && !this.partner.isOnline ? replace(this.channel) : clear();
|
||||
if (this.persona.partner) {
|
||||
return !this.persona.partner.isOnline ? replace(this.channel) : clear();
|
||||
}
|
||||
if (this.persona.guest) {
|
||||
return replace(this.channel);
|
||||
}
|
||||
return clear();
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @returns {FieldCommand}
|
||||
*/
|
||||
_computeChannelAsOnlineMember() {
|
||||
return this.partner && this.partner.isOnline ? replace(this.channel) : clear();
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @returns {string}
|
||||
*/
|
||||
_computeName() {
|
||||
if (!this.partner) {
|
||||
return;
|
||||
if (this.persona.partner) {
|
||||
return this.persona.partner.isOnline ? replace(this.channel) : clear();
|
||||
}
|
||||
return this.partner.nameOrDisplayName;
|
||||
if (this.persona.guest) {
|
||||
return clear();
|
||||
}
|
||||
return clear();
|
||||
},
|
||||
},
|
||||
fields: {
|
||||
avatarUrl: attr({
|
||||
compute: '_computeAvatarUrl',
|
||||
}),
|
||||
channel: one('Channel', {
|
||||
inverse: 'channelMembers',
|
||||
readonly: true,
|
||||
@@ -55,12 +73,10 @@ registerModel({
|
||||
readonly: true,
|
||||
required: true,
|
||||
}),
|
||||
name: attr({
|
||||
compute: '_computeName',
|
||||
}),
|
||||
partner: one('Partner', {
|
||||
persona: one('Persona', {
|
||||
inverse: 'channelMembers',
|
||||
readonly: true,
|
||||
required: true,
|
||||
}),
|
||||
},
|
||||
});
|
||||
|
||||
@@ -15,17 +15,17 @@ registerModel({
|
||||
* @param {MouseEvent} ev
|
||||
*/
|
||||
onClickMember(ev) {
|
||||
if (isEventHandled(ev, 'PersonaImStatusIcon.Click') || !this.channelMember.partner) {
|
||||
if (isEventHandled(ev, 'PersonaImStatusIcon.Click') || !this.channelMember.persona.partner) {
|
||||
return;
|
||||
}
|
||||
this.channelMember.partner.openChat();
|
||||
this.channelMember.persona.partner.openChat();
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
_computeHasOpenChat() {
|
||||
return this.channelMember.partner ? true : false;
|
||||
return this.channelMember.persona.partner ? true : false;
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
@@ -39,7 +39,7 @@ registerModel({
|
||||
* @returns {FieldCommand}
|
||||
*/
|
||||
_computePersonaImStatusIconView() {
|
||||
return this.channelMember.partner && this.channelMember.partner.isImStatusSet ? insertAndReplace() : clear();
|
||||
return this.channelMember.persona.partner && this.channelMember.persona.partner.isImStatusSet ? insertAndReplace() : clear();
|
||||
},
|
||||
},
|
||||
fields: {
|
||||
|
||||
@@ -383,10 +383,6 @@ registerModel({
|
||||
inverse: 'partner',
|
||||
isCausal: true,
|
||||
}),
|
||||
channelMembers: many('ChannelMember', {
|
||||
inverse: 'partner',
|
||||
isCausal: true,
|
||||
}),
|
||||
country: one('Country'),
|
||||
/**
|
||||
* Deprecated.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { registerModel } from '@mail/model/model_core';
|
||||
import { attr, one } from '@mail/model/model_field';
|
||||
import { attr, many, one } from '@mail/model/model_field';
|
||||
import { clear } from '@mail/model/model_field_command';
|
||||
|
||||
registerModel({
|
||||
@@ -36,6 +36,10 @@ registerModel({
|
||||
},
|
||||
},
|
||||
fields: {
|
||||
channelMembers: many('ChannelMember', {
|
||||
inverse: 'persona',
|
||||
isCausal: true,
|
||||
}),
|
||||
guest: one('Guest', {
|
||||
inverse: 'persona',
|
||||
readonly: true,
|
||||
|
||||
@@ -25,7 +25,7 @@ registerModel({
|
||||
return replace(this.channelInvitationFormSelectablePartnerViewOwner.partner.persona);
|
||||
}
|
||||
if (this.channelMemberViewOwner) {
|
||||
return replace(this.channelMemberViewOwner.channelMember.partner.persona);
|
||||
return replace(this.channelMemberViewOwner.channelMember.persona);
|
||||
}
|
||||
if (this.composerSuggestionViewOwner) {
|
||||
return replace(this.composerSuggestionViewOwner.suggestable.partner.persona);
|
||||
|
||||
@@ -1329,17 +1329,41 @@ patch(MockServer.prototype, 'mail', {
|
||||
const memberCount = this.pyEnv['mail.channel.partner'].searchCount([
|
||||
['channel_id', 'in', channel_ids],
|
||||
]);
|
||||
return {
|
||||
channelMembers: [['insert', channelPartners.map(channelPartner => {
|
||||
const membersData = [];
|
||||
for (const channelPartner of channelPartners) {
|
||||
let persona;
|
||||
if (channelPartner.partner_id) {
|
||||
const [partner] = this.pyEnv['res.partner'].searchRead(
|
||||
[['id', '=', channelPartner.partner_id[0]]],
|
||||
{ fields: ['id', 'name', 'im_status'] }
|
||||
);
|
||||
return {
|
||||
id: channelPartner.id,
|
||||
partner: [['insert', partner]],
|
||||
persona = {
|
||||
'partner': [['insert-and-replace', {
|
||||
'id': partner.id,
|
||||
'name': partner.name,
|
||||
'im_status': partner.im_status,
|
||||
}]],
|
||||
};
|
||||
})]],
|
||||
}
|
||||
if (channelPartner.guest_id) {
|
||||
const [guest] = this.pyEnv['mail.guest'].searchRead(
|
||||
[['id', '=', channelPartner.guest_id[0]]],
|
||||
{ fields: ['id', 'name'] }
|
||||
);
|
||||
persona = {
|
||||
'guest': [['insert-and-replace', {
|
||||
'id': guest.id,
|
||||
'name': guest.name,
|
||||
}]],
|
||||
};
|
||||
}
|
||||
membersData.push({
|
||||
'id': channelPartner.id,
|
||||
'persona': [['insert-and-replace', persona]],
|
||||
});
|
||||
}
|
||||
return {
|
||||
channelMembers: [['insert', membersData]],
|
||||
memberCount,
|
||||
};
|
||||
},
|
||||
|
||||
@@ -79,7 +79,7 @@ QUnit.test('should have correct members in member list', async function (assert)
|
||||
channel_type: 'group',
|
||||
public: 'private',
|
||||
});
|
||||
const { click, messaging, openDiscuss } = await start({
|
||||
const { click, openDiscuss } = await start({
|
||||
discuss: {
|
||||
context: {
|
||||
active_id: `mail.channel_${mailChannelId1}`,
|
||||
@@ -96,16 +96,12 @@ QUnit.test('should have correct members in member list', async function (assert)
|
||||
);
|
||||
assert.containsOnce(
|
||||
document.body,
|
||||
`.o_ChannelMember[data-partner-local-id="${
|
||||
messaging.models['Partner'].findFromIdentifyingData({ id: pyEnv.currentPartnerId }).localId
|
||||
}"]`,
|
||||
`.o_ChannelMember[data-partner-id="${pyEnv.currentPartnerId}"]`,
|
||||
"should have current partner in member list (current partner is a member)",
|
||||
);
|
||||
assert.containsOnce(
|
||||
document.body,
|
||||
`.o_ChannelMember[data-partner-local-id="${
|
||||
messaging.models['Partner'].findFromIdentifyingData({ id: resPartnerId1 }).localId
|
||||
}"]`,
|
||||
`.o_ChannelMember[data-partner-id="${resPartnerId1}"]`,
|
||||
"should have 'Demo' in member list ('Demo' is a member)",
|
||||
);
|
||||
});
|
||||
@@ -215,7 +211,7 @@ QUnit.test('chat with member should be opened after clicking on channel member',
|
||||
channel_type: 'group',
|
||||
public: 'private',
|
||||
});
|
||||
const { click, messaging, openDiscuss } = await start({
|
||||
const { click, openDiscuss } = await start({
|
||||
discuss: {
|
||||
context: {
|
||||
active_id: `mail.channel_${mailChannelId1}`,
|
||||
@@ -225,7 +221,7 @@ QUnit.test('chat with member should be opened after clicking on channel member',
|
||||
await openDiscuss();
|
||||
|
||||
await click('.o_ThreadViewTopbar_showMemberListButton');
|
||||
await click(`.o_ChannelMember[data-partner-local-id="${messaging.models['Partner'].findFromIdentifyingData({ id: resPartnerId1 }).localId}"]`);
|
||||
await click(`.o_ChannelMember[data-partner-id="${resPartnerId1}"]`);
|
||||
assert.containsOnce(
|
||||
document.body,
|
||||
`.o_ThreadView[data-correspondent-id="${resPartnerId1}"]`,
|
||||
|
||||
Reference in New Issue
Block a user