[IMP] mail: add rename guest button
This commit will display the name of the current guest in the thread view top bar and make it editable. closes odoo/odoo#77936 X-original-commit: 659c6a83245a396054cf26c204a7fc72fbbb971f Signed-off-by: Sébastien Theys (seb) <seb@odoo.com>
This commit is contained in:
committed by
Sébastien Theys
parent
3ffad9f8a0
commit
71f6d736cc
@@ -546,8 +546,11 @@ class DiscussController(http.Controller):
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
@http.route('/mail/guest/update_name', methods=['POST'], type='json', auth='public')
|
||||
def mail_guest_update_name(self, name):
|
||||
def mail_guest_update_name(self, guest_id, name):
|
||||
guest = request.env['mail.guest']._get_guest_from_request(request)
|
||||
if not guest:
|
||||
guest_to_rename_sudo = guest.env['mail.guest'].browse(guest_id).sudo().exists()
|
||||
if not guest_to_rename_sudo:
|
||||
raise NotFound()
|
||||
guest.sudo()._update_name(name)
|
||||
if guest_to_rename_sudo != guest and not request.env.user._is_admin():
|
||||
raise NotFound()
|
||||
guest_to_rename_sudo._update_name(name)
|
||||
|
||||
@@ -52,19 +52,21 @@ class MailGuest(models.Model):
|
||||
def _update_name(self, name):
|
||||
self.ensure_one()
|
||||
name = name.strip()
|
||||
if name == "":
|
||||
if len(name) < 1:
|
||||
raise UserError(_("Guest's name cannot be empty."))
|
||||
if len(name) > 512:
|
||||
raise UserError(_("Guest's name is too long."))
|
||||
self.name = name
|
||||
self.env['bus.bus'].sendmany([(
|
||||
(self._cr.dbname, 'mail.channel', channel.id),
|
||||
{
|
||||
'type': 'mail.guest_update',
|
||||
'payload': {
|
||||
'id': self.id,
|
||||
'name': self.name,
|
||||
},
|
||||
}
|
||||
) for channel in self.channel_ids])
|
||||
message = {
|
||||
'type': 'mail.guest_update',
|
||||
'payload': {
|
||||
'id': self.id,
|
||||
'name': self.name,
|
||||
},
|
||||
}
|
||||
bus_notifs = [((self._cr.dbname, 'mail.channel', channel.id), message) for channel in self.channel_ids]
|
||||
bus_notifs.append(((self._cr.dbname, 'mail.guest', self.id), message))
|
||||
self.env['bus.bus'].sendmany(bus_notifs)
|
||||
|
||||
def _update_timezone(self, timezone):
|
||||
query = """
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
<img class="o_Composer_currentPartnerAvatar rounded-circle" t-att-src="currentPartnerAvatar" alt="Avatar of user"/>
|
||||
</t>
|
||||
<t t-if="messaging.currentGuest and composerView.composer.activeThread.model === 'mail.channel'">
|
||||
<img class="o_Composer_currentPartnerAvatar rounded-circle" t-attf-src="/mail/channel/{{ composerView.composer.activeThread.id }}/guest/{{ messaging.currentGuest.id }}/avatar_128" alt="Avatar of guest"/>
|
||||
<img class="o_Composer_currentPartnerAvatar rounded-circle" t-attf-src="/mail/channel/{{ composerView.composer.activeThread.id }}/guest/{{ messaging.currentGuest.id }}/avatar_128?unique={{ messaging.currentGuest.name }}" alt="Avatar of guest"/>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
@@ -96,7 +96,7 @@ export class Message extends Component {
|
||||
} else if (this.messageView.message.guestAuthor && (!this.messageView.message.originThread || this.messageView.message.originThread.model !== 'mail.channel')) {
|
||||
return this.messageView.message.guestAuthor.avatarUrl;
|
||||
} else if (this.messageView.message.guestAuthor && this.messageView.message.originThread && this.messageView.message.originThread.model === 'mail.channel') {
|
||||
return `/mail/channel/${this.messageView.message.originThread.id}/guest/${this.messageView.message.guestAuthor.id}/avatar_128`;
|
||||
return `/mail/channel/${this.messageView.message.originThread.id}/guest/${this.messageView.message.guestAuthor.id}/avatar_128?unique=${this.messageView.message.guestAuthor.name}`;
|
||||
} else if (this.messageView.message.message_type === 'email') {
|
||||
return '/mail/static/src/img/email_icon.png';
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ export class ThreadViewTopbar extends Component {
|
||||
*/
|
||||
setup() {
|
||||
super.setup();
|
||||
useRefToModel({ fieldName: 'guestNameInputRef', modelName: 'mail.thread_view_topbar', propNameAsRecordLocalId: 'localId', refName: 'guestNameInput' });
|
||||
useRefToModel({ fieldName: 'threadNameInputRef', modelName: 'mail.thread_view_topbar', propNameAsRecordLocalId: 'localId', refName: 'threadNameInput' });
|
||||
useRefToModel({ fieldName: 'threadDescriptionInputRef', modelName: 'mail.thread_view_topbar', propNameAsRecordLocalId: 'localId', refName: 'threadDescriptionInput' });
|
||||
useUpdateToModel({ methodName: 'onComponentUpdate', modelName: 'mail.thread_view_topbar', propNameAsRecordLocalId: 'localId' });
|
||||
@@ -22,6 +23,16 @@ export class ThreadViewTopbar extends Component {
|
||||
// Public
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @returns {string}
|
||||
*/
|
||||
get avatarUrl() {
|
||||
if (this.messaging.isCurrentUserGuest) {
|
||||
return `/mail/channel/${this.threadViewTopBar.thread.id}/guest/${this.messaging.currentGuest.id}/avatar_128?unique=${this.messaging.currentGuest.name}`;
|
||||
}
|
||||
return this.messaging.currentPartner.avatarUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {mail.thread_view_topbar}
|
||||
*/
|
||||
|
||||
@@ -6,15 +6,21 @@
|
||||
height: $o-statusbar-height * 1.25;
|
||||
}
|
||||
|
||||
.o_ThreadViewTopbar_avatar {
|
||||
height: 26px;
|
||||
width: 26px;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.o_ThreadViewTopbar_editableItem {
|
||||
border: $border-width solid;
|
||||
}
|
||||
|
||||
.o_ThreadViewTopbar_threadDescriptionSeparator {
|
||||
width: $border-width;
|
||||
height: $font-size-sm;
|
||||
}
|
||||
|
||||
.o_ThreadViewTopbar_threadName, .o_ThreadViewTopbar_threadDescription {
|
||||
border: $border-width solid;
|
||||
}
|
||||
|
||||
.o_ThreadViewTopbar_title {
|
||||
min-width: 0;
|
||||
}
|
||||
@@ -46,6 +52,11 @@
|
||||
}
|
||||
}
|
||||
|
||||
// use selector specificity to override bootstrap style
|
||||
input.o_ThreadViewTopBar_guestNameInput {
|
||||
width: 150px;
|
||||
}
|
||||
|
||||
.o_ThreadViewTopbar_invitePopover .popover-body {
|
||||
padding: 0; // cancel unwanted padding
|
||||
}
|
||||
@@ -87,3 +98,14 @@
|
||||
color: gray('900');
|
||||
}
|
||||
}
|
||||
|
||||
.o_ThreadViewTopBar_userName {
|
||||
&:not(.o-userNameEditable) {
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
&.o-userNameEditable {
|
||||
background-color: $white;
|
||||
border-color: $border-color;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<div class="o_ThreadViewTopbar_title d-flex flex-grow-1 align-self-center align-items-center">
|
||||
<t t-if="threadViewTopBar.thread">
|
||||
<t t-if="!threadViewTopBar.isEditingThreadName">
|
||||
<div class="o_ThreadViewTopbar_threadName flex-shrink-0 px-1 text-truncate lead font-weight-bold" t-att-title="threadViewTopBar.thread.displayName" t-on-click="threadViewTopBar.onClickTopbarThreadName" t-on-mouseenter="threadViewTopBar.onMouseEnterTopBarThreadName" t-on-mouseleave="threadViewTopBar.onMouseLeaveTopBarThreadName" t-att-class="{ 'o-threadNameEditable': threadViewTopBar.isMouseOverThreadName and !messaging.isCurrentUserGuest }">
|
||||
<div class="o_ThreadViewTopbar_threadName o_ThreadViewTopbar_editableItem flex-shrink-0 px-1 text-truncate lead font-weight-bold" t-att-title="threadViewTopBar.thread.displayName" t-on-click="threadViewTopBar.onClickTopbarThreadName" t-on-mouseenter="threadViewTopBar.onMouseEnterTopBarThreadName" t-on-mouseleave="threadViewTopBar.onMouseLeaveTopBarThreadName" t-att-class="{ 'o-threadNameEditable': threadViewTopBar.isMouseOverThreadName and !messaging.isCurrentUserGuest }">
|
||||
<t t-esc="threadViewTopBar.thread.displayName"/>
|
||||
</div>
|
||||
</t>
|
||||
@@ -27,7 +27,7 @@
|
||||
<div class="o_ThreadViewTopbar_threadDescriptionSeparator flex-shrink-0 mx-2"/>
|
||||
<t t-if="!threadViewTopBar.isEditingThreadDescription">
|
||||
<t t-if="threadViewTopBar.thread.description">
|
||||
<div class="o_ThreadViewTopbar_threadDescription text-truncate px-1" t-att-title="threadViewTopBar.thread.description" t-on-click="threadViewTopBar.onClickTopbarThreadDescription" t-on-mouseenter="threadViewTopBar.onMouseEnterTopBarThreadDescription" t-on-mouseleave="threadViewTopBar.onMouseLeaveTopBarThreadDescription" t-att-class="{ 'o-threadDescriptionEditable': threadViewTopBar.isMouseOverThreadDescription and !messaging.isCurrentUserGuest }">
|
||||
<div class="o_ThreadViewTopbar_threadDescription o_ThreadViewTopbar_editableItem text-truncate px-1" t-att-title="threadViewTopBar.thread.description" t-on-click="threadViewTopBar.onClickTopbarThreadDescription" t-on-mouseenter="threadViewTopBar.onMouseEnterTopBarThreadDescription" t-on-mouseleave="threadViewTopBar.onMouseLeaveTopBarThreadDescription" t-att-class="{ 'o-threadDescriptionEditable': threadViewTopBar.isMouseOverThreadDescription and !messaging.isCurrentUserGuest }">
|
||||
<t t-esc="threadViewTopBar.thread.description"/>
|
||||
</div>
|
||||
</t>
|
||||
@@ -42,7 +42,7 @@
|
||||
</t>
|
||||
</t>
|
||||
</div>
|
||||
<div class="o_ThreadViewTopbar_actions d-flex align-items-center">
|
||||
<div class="o_ThreadViewTopbar_actions d-flex align-items-center ml-1">
|
||||
<t t-if="threadViewTopBar.thread and threadViewTopBar.thread === messaging.inbox">
|
||||
<button class="o_ThreadViewTopbar_markAllReadButton btn btn-secondary" t-att-disabled="threadViewTopBar.threadView.messages.length === 0" t-on-click="threadViewTopBar.onClickInboxMarkAllAsRead">Mark all read</button>
|
||||
</t>
|
||||
@@ -79,6 +79,20 @@
|
||||
</button>
|
||||
</t>
|
||||
</div>
|
||||
<!-- FIXME: handle display on mobile -->
|
||||
<t t-if="threadViewTopBar.threadView.threadViewer.discussPublicView and !messaging.device.isMobile">
|
||||
<div class="o_ThreadViewTopbar_userInfo d-flex align-items-center">
|
||||
<img class="o_ThreadViewTopbar_avatar ml-1 mr-1 rounded-circle" t-att-src="avatarUrl" alt="Avatar"/>
|
||||
<t t-if="!threadViewTopBar.isEditingGuestName">
|
||||
<span class="o_ThreadViewTopBar_userName o_ThreadViewTopbar_editableItem px-1 font-weight-bold text-truncate" t-att-class="{ 'o-userNameEditable': threadViewTopBar.isMouseOverUserInfo and messaging.isCurrentUserGuest }" t-on-click="threadViewTopBar.onClickUserName" t-on-mouseenter="threadViewTopBar.onMouseEnterUserName" t-on-mouseleave="threadViewTopBar.onMouseLeaveUserName">
|
||||
<t t-esc="messaging.isCurrentUserGuest ? messaging.currentGuest.name : messaging.currentUser.nameOrDisplayName"/>
|
||||
</span>
|
||||
</t>
|
||||
<t t-if="threadViewTopBar.isEditingGuestName">
|
||||
<input class="o_ThreadViewTopBar_guestNameInput" type="text" t-att-value="messaging.currentGuest.name" t-on-input="threadViewTopBar.onInputGuestNameInput" t-on-keydown="threadViewTopBar.onKeyDownGuestNameInput" t-ref="guestNameInput"/>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
@@ -7,23 +7,47 @@ function factory(dependencies) {
|
||||
|
||||
class Guest extends dependencies['mail.model'] {
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Public
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @static
|
||||
* @param {Object} param0
|
||||
* @param {number} param0.id The id of the guest to rename.
|
||||
* @param {string} param0.name The new name to use to rename the guest.
|
||||
*/
|
||||
static async performRpcGuestUpdateName({ id, name }) {
|
||||
await this.env.services.rpc({
|
||||
route: '/mail/guest/update_name',
|
||||
params: {
|
||||
guest_id: id,
|
||||
name,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Private
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @returns {string}
|
||||
*/
|
||||
_computeAvatarUrl() {
|
||||
return `/web/image/mail.guest/${this.id}/avatar_128`;
|
||||
return `/web/image/mail.guest/${this.id}/avatar_128?unique=${this.name}`;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Guest.fields = {
|
||||
avatarUrl: attr({
|
||||
compute: '_computeAvatarUrl',
|
||||
}),
|
||||
authoredMessages: one2many('mail.message', {
|
||||
inverse: 'guestAuthor',
|
||||
}),
|
||||
avatarUrl: attr({
|
||||
compute: '_computeAvatarUrl',
|
||||
}),
|
||||
id: attr({
|
||||
required: true,
|
||||
readonly: true,
|
||||
|
||||
@@ -13,15 +13,20 @@ function factory(dependencies) {
|
||||
*/
|
||||
_created() {
|
||||
// Bind necessary until OWL supports arrow function in handlers: https://github.com/odoo/owl/issues/876
|
||||
this.onClickUserName = this.onClickUserName.bind(this);
|
||||
this.onClickHideMemberList = this.onClickHideMemberList.bind(this);
|
||||
this.onClickInboxMarkAllAsRead = this.onClickInboxMarkAllAsRead.bind(this);
|
||||
this.onClickInviteButton = this.onClickInviteButton.bind(this);
|
||||
this.onClickShowMemberList = this.onClickShowMemberList.bind(this);
|
||||
this.onClickTopbarThreadName = this.onClickTopbarThreadName.bind(this);
|
||||
this.onClickUnstarAll = this.onClickUnstarAll.bind(this);
|
||||
this.onInputGuestNameInput = this.onInputGuestNameInput.bind(this);
|
||||
this.onInputThreadNameInput = this.onInputThreadNameInput.bind(this);
|
||||
this.onKeyDownGuestNameInput = this.onKeyDownGuestNameInput.bind(this);
|
||||
this.onKeyDownThreadNameInput = this.onKeyDownThreadNameInput.bind(this);
|
||||
this.onMouseEnterUserName = this.onMouseEnterUserName.bind(this);
|
||||
this.onMouseEnterTopBarThreadName = this.onMouseEnterTopBarThreadName.bind(this);
|
||||
this.onMouseLeaveUserName = this.onMouseLeaveUserName.bind(this);
|
||||
this.onMouseLeaveTopBarThreadName = this.onMouseLeaveTopBarThreadName.bind(this);
|
||||
this._onClickCaptureGlobal = this._onClickCaptureGlobal.bind(this);
|
||||
this.onClickTopbarThreadDescription = this.onClickTopbarThreadDescription.bind(this);
|
||||
@@ -147,10 +152,35 @@ function factory(dependencies) {
|
||||
this.messaging.models['mail.message'].unstarAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles click on the guest name.
|
||||
*
|
||||
* @param {MouseEvent} ev
|
||||
*/
|
||||
onClickUserName(ev) {
|
||||
if (!this.messaging.isCurrentUserGuest) {
|
||||
return;
|
||||
}
|
||||
const selection = window.getSelection();
|
||||
this.update({
|
||||
doFocusOnGuestNameInput: true,
|
||||
doSetSelectionDirectionOnGuestNameInput: selection.anchorOffset < selection.focusOffset ? 'forward' : 'backward',
|
||||
doSetSelectionEndOnGuestNameInput: Math.max(selection.focusOffset, selection.anchorOffset),
|
||||
doSetSelectionStartOnGuestNameInput: Math.min(selection.focusOffset, selection.anchorOffset),
|
||||
isEditingGuestName: true,
|
||||
isMouseOverUserInfo: false,
|
||||
pendingGuestName: this.messaging.currentGuest.name,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles OWL update on this top bar component.
|
||||
*/
|
||||
onComponentUpdate() {
|
||||
if (this.doFocusOnGuestNameInput) {
|
||||
this.guestNameInputRef.el.focus();
|
||||
this.update({ doFocusOnGuestNameInput: clear() });
|
||||
}
|
||||
if (this.doFocusOnThreadNameInput) {
|
||||
this.threadNameInputRef.el.focus();
|
||||
this.update({ doFocusOnThreadNameInput: clear() });
|
||||
@@ -159,6 +189,22 @@ function factory(dependencies) {
|
||||
this.threadDescriptionInputRef.el.focus();
|
||||
this.update({ doFocusOnThreadDescriptionInput: clear() });
|
||||
}
|
||||
if (
|
||||
this.doSetSelectionStartOnGuestNameInput !== undefined &&
|
||||
this.doSetSelectionEndOnGuestNameInput !== undefined &&
|
||||
this.doSetSelectionDirectionOnGuestNameInput !== undefined
|
||||
) {
|
||||
this.guestNameInputRef.el.setSelectionRange(
|
||||
this.doSetSelectionStartOnGuestNameInput,
|
||||
this.doSetSelectionEndOnGuestNameInput,
|
||||
this.doSetSelectionDirectionOnGuestNameInput
|
||||
);
|
||||
this.update({
|
||||
doSetSelectionDirectionOnGuestNameInput: clear(),
|
||||
doSetSelectionEndOnGuestNameInput: clear(),
|
||||
doSetSelectionStartOnGuestNameInput: clear(),
|
||||
});
|
||||
}
|
||||
if (
|
||||
this.doSetSelectionStartOnThreadNameInput !== undefined &&
|
||||
this.doSetSelectionEndOnThreadNameInput !== undefined &&
|
||||
@@ -193,6 +239,13 @@ function factory(dependencies) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {KeyboardEvent} ev
|
||||
*/
|
||||
onInputGuestNameInput(ev) {
|
||||
this.update({ pendingGuestName: this.guestNameInputRef.el.value });
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles input on the "thread name" input of this top bar.
|
||||
*
|
||||
@@ -211,6 +264,24 @@ function factory(dependencies) {
|
||||
this.update({ pendingThreadDescription: ev.target.value });
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles keydown on the "guest name" input of this top bar.
|
||||
*
|
||||
* @param {KeyboardEvent} ev
|
||||
*/
|
||||
onKeyDownGuestNameInput(ev) {
|
||||
switch (ev.key) {
|
||||
case 'Enter':
|
||||
if (this.pendingGuestName.trim() !== '') {
|
||||
this._applyGuestRename();
|
||||
}
|
||||
break;
|
||||
case 'Escape':
|
||||
this._discardGuestRename();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles keydown on the "thread name" input of this top bar.
|
||||
*
|
||||
@@ -267,6 +338,15 @@ function factory(dependencies) {
|
||||
this.update({ isMouseOverThreadDescription: true });
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles mouseenter on the "guest name" of this top bar.
|
||||
*
|
||||
* @param {MouseEvent} ev
|
||||
*/
|
||||
onMouseEnterUserName(ev) {
|
||||
this.update({ isMouseOverUserInfo: true });
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles mouseleave on the "thread name" of this top bar.
|
||||
*
|
||||
@@ -285,10 +365,32 @@ function factory(dependencies) {
|
||||
this.update({ isMouseOverThreadDescription: false });
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles mouseleave on the "guest name" of this top bar.
|
||||
*
|
||||
* @param {MouseEvent} ev
|
||||
*/
|
||||
onMouseLeaveUserName(ev) {
|
||||
this.update({ isMouseOverUserInfo: false });
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Private
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_applyGuestRename() {
|
||||
this.update({ isEditingGuestName: false });
|
||||
if (this.hasGuestNameChanged) {
|
||||
this.messaging.models['mail.guest'].performRpcGuestUpdateName({
|
||||
id: this.messaging.currentGuest.id,
|
||||
name: this.pendingGuestName.trim(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
@@ -323,6 +425,27 @@ function factory(dependencies) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @returns {boolean}
|
||||
*/
|
||||
_computeHasGuestNameChanged() {
|
||||
return Boolean(
|
||||
this.messaging.currentGuest &&
|
||||
this.pendingGuestName !== this.messaging.currentGuest.name
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_discardGuestRename() {
|
||||
this.update({
|
||||
isEditingGuestName: false,
|
||||
pendingGuestName: clear(),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
@@ -348,6 +471,13 @@ function factory(dependencies) {
|
||||
* @param {MouseEvent} ev
|
||||
*/
|
||||
_onClickCaptureGlobal(ev) {
|
||||
if (this.isEditingGuestName && this.guestNameInputRef.el && !this.guestNameInputRef.el.contains(ev.target)) {
|
||||
if (this.pendingGuestName.trim() !== '') {
|
||||
this._applyGuestRename();
|
||||
} else {
|
||||
this._discardGuestRename();
|
||||
}
|
||||
}
|
||||
if (this.isEditingThreadName && this.threadNameInputRef.el && !this.threadNameInputRef.el.contains(ev.target)) {
|
||||
this._applyThreadRename();
|
||||
}
|
||||
@@ -359,6 +489,10 @@ function factory(dependencies) {
|
||||
}
|
||||
|
||||
ThreadViewTopBar.fields = {
|
||||
/**
|
||||
* Determines whether the guest name input needs to be focused.
|
||||
*/
|
||||
doFocusOnGuestNameInput: attr(),
|
||||
/**
|
||||
* Determines whether this thread name input needs to be focused.
|
||||
*/
|
||||
@@ -367,7 +501,15 @@ function factory(dependencies) {
|
||||
* Determines whether this thread description input needs to be focused.
|
||||
*/
|
||||
doFocusOnThreadDescriptionInput: attr(),
|
||||
/**
|
||||
/**
|
||||
* Determines the direction to set on the selection of this guest name
|
||||
* input. This value is not a representation of current selection, but
|
||||
* an instruction to set a new selection. Must be set together with
|
||||
* `doSetSelectionEndOnGuestNameInput` and `doSetSelectionStartOnGuestNameInput`
|
||||
* to have an effect.
|
||||
*/
|
||||
doSetSelectionDirectionOnGuestNameInput: attr(),
|
||||
/**
|
||||
* Determines the direction to set on the selection of this thread name
|
||||
* input. This value is not a representation of current selection, but
|
||||
* an instruction to set a new selection. Must be set together with
|
||||
@@ -382,7 +524,15 @@ function factory(dependencies) {
|
||||
* `doSetSelectionEndOnThreadDescriptionInput` and `doSetSelectionStartOnThreadDescriptionInput`
|
||||
* to have an effect.
|
||||
*/
|
||||
doSetSelectionDirectionOnThreadDescriptionInput: attr(),
|
||||
doSetSelectionDirectionOnThreadDescriptionInput: attr(),
|
||||
/**
|
||||
* Determines the ending position where to place the selection on this
|
||||
* guest name input (zero-based index). This value is not a
|
||||
* representation of current selection, but an instruction to set a new
|
||||
* selection. Must be set together with `doSetSelectionDirectionOnGuestNameInput`
|
||||
* and `doSetSelectionStartOnGuestNameInput` to have an effect.
|
||||
*/
|
||||
doSetSelectionEndOnGuestNameInput: attr(),
|
||||
/**
|
||||
* Determines the ending position where to place the selection on this
|
||||
* thread name input (zero-based index). This value is not a
|
||||
@@ -399,6 +549,14 @@ function factory(dependencies) {
|
||||
* and `doSetSelectionStartOnThreadDescriptionInput` to have an effect.
|
||||
*/
|
||||
doSetSelectionEndOnThreadDescriptionInput: attr(),
|
||||
/**
|
||||
* Determines the starting position where to place the selection on this
|
||||
* guest name input (zero-based index). This value is not a
|
||||
* representation of current selection, but an instruction to set a new
|
||||
* selection. Must be set together with `doSetSelectionDirectionOnGuestNameInput` and
|
||||
* `doSetSelectionEndOnGuestNameInput` to have an effect.
|
||||
*/
|
||||
doSetSelectionStartOnGuestNameInput: attr(),
|
||||
/**
|
||||
* Determines the starting position where to place the selection on this
|
||||
* thread name input (zero-based index). This value is not a
|
||||
@@ -415,6 +573,27 @@ function factory(dependencies) {
|
||||
* `doSetSelectionEndOnThreadDescriptionInput` to have an effect.
|
||||
*/
|
||||
doSetSelectionStartOnThreadDescriptionInput: attr(),
|
||||
/**
|
||||
* States the OWL ref of the "guest name" input of this top bar.
|
||||
* Useful to focus it, or to know when a click is done outside of it.
|
||||
*/
|
||||
guestNameInputRef: attr(),
|
||||
/**
|
||||
* Determines whether the guest's name has been updated.
|
||||
*
|
||||
* Useful to determine whether a RPC should be done to update the name
|
||||
* server side.
|
||||
*/
|
||||
hasGuestNameChanged: attr({
|
||||
compute: '_computeHasGuestNameChanged',
|
||||
readonly: true,
|
||||
}),
|
||||
/**
|
||||
* Determines whether the guest is currently being renamed.
|
||||
*/
|
||||
isEditingGuestName: attr({
|
||||
default: false,
|
||||
}),
|
||||
/**
|
||||
* Determines whether this thread is currently being renamed.
|
||||
*/
|
||||
@@ -441,6 +620,22 @@ function factory(dependencies) {
|
||||
isMouseOverThreadDescription: attr({
|
||||
default: false,
|
||||
}),
|
||||
/**
|
||||
* States whether the cursor is currently over the guest name in this
|
||||
* top bar.
|
||||
*/
|
||||
isMouseOverUserInfo: attr({
|
||||
default: false,
|
||||
}),
|
||||
/**
|
||||
* Determines the pending name of the guest, which is the new name of
|
||||
* the guest as the current guest is currently typing it, with the goal
|
||||
* of renaming the guest.
|
||||
* This value can either be applied or discarded.
|
||||
*/
|
||||
pendingGuestName: attr({
|
||||
default: "",
|
||||
}),
|
||||
/**
|
||||
* Determines the pending name of this thread, which is the new name of
|
||||
* the thread as the current user is currently typing it, with the goal
|
||||
|
||||
@@ -28,24 +28,16 @@ function factory(dependencies) {
|
||||
// Public
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @static
|
||||
* @param {string} name
|
||||
*/
|
||||
static async performRpcGuestUpdateName(name) {
|
||||
await this.env.services.rpc({
|
||||
route: '/mail/guest/update_name',
|
||||
params: { name },
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates guest if needed then displays the thread view instead of the
|
||||
* welcome view.
|
||||
*/
|
||||
async joinChannel() {
|
||||
if (this.hasGuestNameChanged) {
|
||||
await this.messaging.models['mail.welcome_view'].performRpcGuestUpdateName(this.pendingGuestName.trim());
|
||||
await this.messaging.models['mail.guest'].performRpcGuestUpdateName({
|
||||
id: this.messaging.currentGuest.id,
|
||||
name: this.pendingGuestName.trim(),
|
||||
});
|
||||
}
|
||||
if (this.discussPublicView.shouldAddGuestAsMemberOnJoin) {
|
||||
await this.performRpcAddGuestAsMember();
|
||||
|
||||
Reference in New Issue
Block a user