[IMP] mail: introduce ComposerSuggestable model
This will allow to remove AND/OR mix in identifying fields of composer suggestion view. Part of task-2741982 closes odoo/odoo#94999 Signed-off-by: Alexandre Kühn (aku) <aku@odoo.com>
This commit is contained in:
@@ -4,27 +4,27 @@
|
||||
<t t-name="mail.ComposerSuggestion" owl="1">
|
||||
<t t-if="composerSuggestion">
|
||||
<a class="o_ComposerSuggestion dropdown-item d-flex w-100 py-2 px-4" t-att-class="{ 'active bg-300': composerSuggestion.isActive }" t-attf-class="{{ className }}" href="#" t-att-title="composerSuggestion.title" role="menuitem" t-on-click="composerSuggestion.onClick" t-ref="root">
|
||||
<t t-if="composerSuggestion.cannedResponse">
|
||||
<strong class="o_ComposerSuggestion_part1 flex-shrink-0 mw-100 pr-2 text-truncate"><t t-esc="composerSuggestion.record.source"/></strong>
|
||||
<em class="o_ComposerSuggestion_part2 text-600 text-truncate"><t t-esc="composerSuggestion.record.substitution"/></em>
|
||||
<t t-if="composerSuggestion.suggestable.cannedResponse">
|
||||
<strong class="o_ComposerSuggestion_part1 flex-shrink-0 mw-100 pr-2 text-truncate"><t t-esc="composerSuggestion.suggestable.cannedResponse.source"/></strong>
|
||||
<em class="o_ComposerSuggestion_part2 text-600 text-truncate"><t t-esc="composerSuggestion.suggestable.cannedResponse.substitution"/></em>
|
||||
</t>
|
||||
<t t-if="composerSuggestion.thread">
|
||||
<strong class="o_ComposerSuggestion_part1 flex-shrink-0 mw-100 pr-2 text-truncate"><t t-esc="composerSuggestion.record.name"/></strong>
|
||||
<t t-if="composerSuggestion.suggestable.thread">
|
||||
<strong class="o_ComposerSuggestion_part1 flex-shrink-0 mw-100 pr-2 text-truncate"><t t-esc="composerSuggestion.suggestable.thread.name"/></strong>
|
||||
</t>
|
||||
<t t-if="composerSuggestion.channelCommand">
|
||||
<strong class="o_ComposerSuggestion_part1 flex-shrink-0 mw-100 pr-2 text-truncate"><t t-esc="composerSuggestion.record.name"/></strong>
|
||||
<em class="o_ComposerSuggestion_part2 text-600 text-truncate"><t t-esc="composerSuggestion.record.help"/></em>
|
||||
<t t-if="composerSuggestion.suggestable.channelCommand">
|
||||
<strong class="o_ComposerSuggestion_part1 flex-shrink-0 mw-100 pr-2 text-truncate"><t t-esc="composerSuggestion.suggestable.channelCommand.name"/></strong>
|
||||
<em class="o_ComposerSuggestion_part2 text-600 text-truncate"><t t-esc="composerSuggestion.suggestable.channelCommand.help"/></em>
|
||||
</t>
|
||||
<t t-if="composerSuggestion.partner">
|
||||
<t t-if="composerSuggestion.suggestable.partner">
|
||||
<PersonaImStatusIcon
|
||||
t-if="composerSuggestion.personaImStatusIconView"
|
||||
className="'o_ComposerSuggestion_personaImStatusIcon flex-shrink-0 mr-1'"
|
||||
hasBackground="false"
|
||||
record="composerSuggestion.personaImStatusIconView"
|
||||
/>
|
||||
<strong class="o_ComposerSuggestion_part1 flex-shrink-0 mw-100 pr-2 text-truncate"><t t-esc="composerSuggestion.record.nameOrDisplayName"/></strong>
|
||||
<t t-if="composerSuggestion.record.email">
|
||||
<em class="o_ComposerSuggestion_part2 text-600 text-truncate">(<t t-esc="composerSuggestion.record.email"/>)</em>
|
||||
<strong class="o_ComposerSuggestion_part1 flex-shrink-0 mw-100 pr-2 text-truncate"><t t-esc="composerSuggestion.suggestable.partner.nameOrDisplayName"/></strong>
|
||||
<t t-if="composerSuggestion.suggestable.partner.email">
|
||||
<em class="o_ComposerSuggestion_part2 text-600 text-truncate">(<t t-esc="composerSuggestion.suggestable.partner.email"/>)</em>
|
||||
</t>
|
||||
</t>
|
||||
</a>
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { registerModel } from '@mail/model/model_core';
|
||||
import { attr } from '@mail/model/model_field';
|
||||
import { attr, one } from '@mail/model/model_field';
|
||||
import { insertAndReplace } from '@mail/model/model_field_command';
|
||||
import { cleanSearchTerm } from '@mail/utils/utils';
|
||||
|
||||
registerModel({
|
||||
@@ -82,5 +83,12 @@ registerModel({
|
||||
* entered.
|
||||
*/
|
||||
substitution: attr(),
|
||||
suggestable: one('ComposerSuggestable', {
|
||||
default: insertAndReplace(),
|
||||
inverse: 'cannedResponse',
|
||||
isCausal: true,
|
||||
readonly: true,
|
||||
required: true,
|
||||
}),
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { registerModel } from '@mail/model/model_core';
|
||||
import { attr } from '@mail/model/model_field';
|
||||
import { attr, one } from '@mail/model/model_field';
|
||||
import { insertAndReplace } from '@mail/model/model_field_command';
|
||||
import { cleanSearchTerm } from '@mail/utils/utils';
|
||||
|
||||
registerModel({
|
||||
@@ -130,5 +131,12 @@ registerModel({
|
||||
readonly: true,
|
||||
required: true,
|
||||
}),
|
||||
suggestable: one('ComposerSuggestable', {
|
||||
default: insertAndReplace(),
|
||||
inverse: 'channelCommand',
|
||||
isCausal: true,
|
||||
readonly: true,
|
||||
required: true,
|
||||
}),
|
||||
},
|
||||
});
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { registerModel } from '@mail/model/model_core';
|
||||
import { many, one } from '@mail/model/model_field';
|
||||
|
||||
registerModel({
|
||||
name: 'ComposerSuggestable',
|
||||
identifyingFields: [['cannedResponse', 'channelCommand', 'partner', 'thread']],
|
||||
fields: {
|
||||
cannedResponse: one('CannedResponse', {
|
||||
inverse: 'suggestable',
|
||||
readonly: true,
|
||||
}),
|
||||
channelCommand: one('ChannelCommand', {
|
||||
inverse: 'suggestable',
|
||||
readonly: true,
|
||||
}),
|
||||
composerSuggestions: many('ComposerSuggestion', {
|
||||
inverse: 'suggestable',
|
||||
isCausal: true,
|
||||
}),
|
||||
partner: one('Partner', {
|
||||
inverse: 'suggestable',
|
||||
readonly: true,
|
||||
}),
|
||||
thread: one('Thread', {
|
||||
inverse: 'suggestable',
|
||||
readonly: true,
|
||||
}),
|
||||
},
|
||||
});
|
||||
@@ -13,7 +13,7 @@ import { sprintf } from '@web/core/utils/strings';
|
||||
*/
|
||||
registerModel({
|
||||
name: 'ComposerSuggestion',
|
||||
identifyingFields: [['composerViewOwnerAsExtraSuggestion', 'composerViewOwnerAsMainSuggestion'], ['cannedResponse', 'channelCommand', 'partner', 'thread']],
|
||||
identifyingFields: [['composerViewOwnerAsExtraSuggestion', 'composerViewOwnerAsMainSuggestion'], 'suggestable'],
|
||||
recordMethods: {
|
||||
/**
|
||||
* @param {Event} ev
|
||||
@@ -53,17 +53,17 @@ registerModel({
|
||||
* @returns {string}
|
||||
*/
|
||||
_computeMentionText() {
|
||||
if (this.cannedResponse) {
|
||||
return this.cannedResponse.substitution;
|
||||
if (this.suggestable.cannedResponse) {
|
||||
return this.suggestable.cannedResponse.substitution;
|
||||
}
|
||||
if (this.channelCommand) {
|
||||
return this.channelCommand.name;
|
||||
if (this.suggestable.channelCommand) {
|
||||
return this.suggestable.channelCommand.name;
|
||||
}
|
||||
if (this.partner) {
|
||||
return this.partner.name;
|
||||
if (this.suggestable.partner) {
|
||||
return this.suggestable.partner.name;
|
||||
}
|
||||
if (this.thread) {
|
||||
return this.thread.name;
|
||||
if (this.suggestable.thread) {
|
||||
return this.suggestable.thread.name;
|
||||
}
|
||||
},
|
||||
/**
|
||||
@@ -71,57 +71,32 @@ registerModel({
|
||||
* @returns {FieldCommand}
|
||||
*/
|
||||
_computePersonaImStatusIconView() {
|
||||
return this.partner && this.partner.isImStatusSet ? insertAndReplace() : clear();
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @returns {FieldCommand}
|
||||
*/
|
||||
_computeRecord() {
|
||||
if (this.cannedResponse) {
|
||||
return replace(this.cannedResponse);
|
||||
}
|
||||
if (this.channelCommand) {
|
||||
return replace(this.channelCommand);
|
||||
}
|
||||
if (this.partner) {
|
||||
return replace(this.partner);
|
||||
}
|
||||
if (this.thread) {
|
||||
return replace(this.thread);
|
||||
}
|
||||
return clear();
|
||||
return this.suggestable.partner && this.suggestable.partner.isImStatusSet ? insertAndReplace() : clear();
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @returns {string|FieldCommand}
|
||||
*/
|
||||
_computeTitle() {
|
||||
if (this.cannedResponse) {
|
||||
return sprintf("%s: %s", this.record.source, this.record.substitution);
|
||||
if (this.suggestable.cannedResponse) {
|
||||
return sprintf("%s: %s", this.suggestable.cannedResponse.source, this.suggestable.cannedResponse.substitution);
|
||||
}
|
||||
if (this.thread) {
|
||||
return this.record.name;
|
||||
if (this.suggestable.thread) {
|
||||
return this.suggestable.thread.name;
|
||||
}
|
||||
if (this.channelCommand) {
|
||||
return sprintf("%s: %s", this.record.name, this.record.help);
|
||||
if (this.suggestable.channelCommand) {
|
||||
return sprintf("%s: %s", this.suggestable.channelCommand.name, this.suggestable.channelCommand.help);
|
||||
}
|
||||
if (this.partner) {
|
||||
if (this.record.email) {
|
||||
return sprintf("%s (%s)", this.record.nameOrDisplayName, this.record.email);
|
||||
if (this.suggestable.partner) {
|
||||
if (this.suggestable.partner.email) {
|
||||
return sprintf("%s (%s)", this.suggestable.partner.nameOrDisplayName, this.suggestable.partner.email);
|
||||
}
|
||||
return this.record.nameOrDisplayName;
|
||||
return this.suggestable.partner.nameOrDisplayName;
|
||||
}
|
||||
return clear();
|
||||
},
|
||||
},
|
||||
fields: {
|
||||
cannedResponse: one('CannedResponse', {
|
||||
readonly: true,
|
||||
}),
|
||||
channelCommand: one('ChannelCommand', {
|
||||
readonly: true,
|
||||
}),
|
||||
composerViewOwner: one('ComposerView', {
|
||||
compute: '_computeComposerViewOwner',
|
||||
required: true,
|
||||
@@ -144,20 +119,16 @@ registerModel({
|
||||
mentionText: attr({
|
||||
compute: '_computeMentionText',
|
||||
}),
|
||||
record: one('Record', {
|
||||
compute: '_computeRecord',
|
||||
}),
|
||||
partner: one('Partner', {
|
||||
readonly: true,
|
||||
}),
|
||||
personaImStatusIconView: one('PersonaImStatusIconView', {
|
||||
compute: '_computePersonaImStatusIconView',
|
||||
inverse: 'composerSuggestionViewOwner',
|
||||
isCausal: true,
|
||||
readonly: true,
|
||||
}),
|
||||
thread: one('Thread', {
|
||||
suggestable: one('ComposerSuggestable', {
|
||||
inverse: 'composerSuggestions',
|
||||
readonly: true,
|
||||
required: true,
|
||||
}),
|
||||
/**
|
||||
* Descriptive title for this suggestion. Useful to be able to
|
||||
|
||||
@@ -143,11 +143,11 @@ registerModel({
|
||||
// Specific cases for channel and partner mentions: the message with
|
||||
// the mention will appear in the target channel, or be notified to
|
||||
// the target partner.
|
||||
if (this.activeSuggestion.thread) {
|
||||
Object.assign(updateData, { mentionedChannels: link(this.activeSuggestion.thread) });
|
||||
if (this.activeSuggestion.suggestable.thread) {
|
||||
Object.assign(updateData, { mentionedChannels: link(this.activeSuggestion.suggestable.thread) });
|
||||
}
|
||||
if (this.activeSuggestion.partner) {
|
||||
Object.assign(updateData, { mentionedPartners: link(this.activeSuggestion.partner) });
|
||||
if (this.activeSuggestion.suggestable.partner) {
|
||||
Object.assign(updateData, { mentionedPartners: link(this.activeSuggestion.suggestable.partner) });
|
||||
}
|
||||
this.composer.update(updateData);
|
||||
for (const composerView of this.composer.composerViews) {
|
||||
@@ -1389,31 +1389,17 @@ registerModel({
|
||||
this.update({
|
||||
extraSuggestions: insertAndReplace(
|
||||
extraSuggestedRecords.map(record => {
|
||||
switch (record.constructor.name) {
|
||||
case 'CannedResponse':
|
||||
return { cannedResponse: replace(record) };
|
||||
case 'ChannelCommand':
|
||||
return { channelCommand: replace(record) };
|
||||
case 'Partner':
|
||||
return { partner: replace(record) };
|
||||
case 'Thread':
|
||||
return { thread: replace(record) };
|
||||
}
|
||||
return {
|
||||
suggestable: replace(record.suggestable),
|
||||
};
|
||||
}),
|
||||
),
|
||||
hasToScrollToActiveSuggestion: true,
|
||||
mainSuggestions: insertAndReplace(
|
||||
mainSuggestedRecords.map(record => {
|
||||
switch (record.constructor.name) {
|
||||
case 'CannedResponse':
|
||||
return { cannedResponse: replace(record) };
|
||||
case 'ChannelCommand':
|
||||
return { channelCommand: replace(record) };
|
||||
case 'Partner':
|
||||
return { partner: replace(record) };
|
||||
case 'Thread':
|
||||
return { thread: replace(record) };
|
||||
}
|
||||
return {
|
||||
suggestable: replace(record.suggestable),
|
||||
};
|
||||
}),
|
||||
),
|
||||
});
|
||||
|
||||
@@ -451,6 +451,13 @@ registerModel({
|
||||
rtcSessions: many('RtcSession', {
|
||||
inverse: 'partner',
|
||||
}),
|
||||
suggestable: one('ComposerSuggestable', {
|
||||
default: insertAndReplace(),
|
||||
inverse: 'partner',
|
||||
isCausal: true,
|
||||
readonly: true,
|
||||
required: true,
|
||||
}),
|
||||
user: one('User', {
|
||||
inverse: 'partner',
|
||||
}),
|
||||
|
||||
@@ -28,7 +28,7 @@ registerModel({
|
||||
return replace(this.channelMemberViewOwner.channelMember.partner.persona);
|
||||
}
|
||||
if (this.composerSuggestionViewOwner) {
|
||||
return replace(this.composerSuggestionViewOwner.partner.persona);
|
||||
return replace(this.composerSuggestionViewOwner.suggestable.partner.persona);
|
||||
}
|
||||
if (this.messageViewOwner) {
|
||||
return replace(this.messageViewOwner.message.author.persona);
|
||||
|
||||
@@ -2257,6 +2257,13 @@ registerModel({
|
||||
serverMessageUnreadCounter: attr({
|
||||
default: 0,
|
||||
}),
|
||||
suggestable: one('ComposerSuggestable', {
|
||||
default: insertAndReplace(),
|
||||
inverse: 'thread',
|
||||
isCausal: true,
|
||||
readonly: true,
|
||||
required: true,
|
||||
}),
|
||||
/**
|
||||
* Determines the `SuggestedRecipientInfo` concerning `this`.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user