diff options
Diffstat (limited to 'addons/mail/static/src/models/thread/thread.js')
| -rw-r--r-- | addons/mail/static/src/models/thread/thread.js | 113 |
1 files changed, 90 insertions, 23 deletions
diff --git a/addons/mail/static/src/models/thread/thread.js b/addons/mail/static/src/models/thread/thread.js index 06c41652ff8..2267d170f10 100644 --- a/addons/mail/static/src/models/thread/thread.js +++ b/addons/mail/static/src/models/thread/thread.js @@ -171,6 +171,16 @@ function factory(dependencies) { if ('is_moderator' in data) { data2.is_moderator = data.is_moderator; } + if ('is_pinned' in data) { + data2.isServerPinned = data.is_pinned; + // FIXME: The following is admittedly odd. + // Fixing it should entail a deeper reflexion on the group_based_subscription + // and is_pinned functionalities, especially in python. + // task-2284357 + if ('group_based_subscription' in data && data.group_based_subscription) { + data2.isServerPinned = true; + } + } if ('mass_mailing' in data) { data2.mass_mailing = data.mass_mailing; } @@ -298,10 +308,7 @@ function factory(dependencies) { }), } }); - const thread = this.insert(Object.assign( - { isPinned: true }, - this.convertData(data) - )); + const thread = this.insert(this.convertData(data)); if (autoselect) { thread.open({ chatWindowMode: autoselectChatWindowMode }); } @@ -316,7 +323,7 @@ function factory(dependencies) { * @param {boolean} [param1.autoselect=false] */ static async joinChannel(channelId, { autoselect = false } = {}) { - const channel = this.find(thread => + let channel = this.find(thread => thread.id === channelId && thread.model === 'mail.channel' ); @@ -328,12 +335,17 @@ function factory(dependencies) { method: 'channel_join_and_get_info', args: [[channelId]] }); - const thread = this.insert(Object.assign( - { isPinned: true }, - this.convertData(data) - )); + // We just joined the channel because of the previous rpc + // the main assumption here is that we didn't have the channel + // in memory. If we did though, clear the pending state and + // let the server's data be the master + const convertedData = Object.assign( + { isPendingPinned: undefined }, + this.convertData(data), + ); + channel = this.insert(convertedData); if (autoselect) { - thread.open({ resetDiscussDomain: true }); + channel.open({ resetDiscussDomain: true }); } } @@ -483,6 +495,20 @@ function factory(dependencies) { } /** + * Notify server to leave the current channel. Useful for cross-tab + * and cross-device chat window state synchronization. + * + * Only makes sense if pendingServerState is set to 'unpin'. + */ + async notifyUnPinToServer() { + return this.async(() => this.env.services.rpc({ + model: 'mail.channel', + method: 'execute_command', + args: [[this.id], 'leave'] + })); + } + + /** * Open provided thread, either in discuss app or as a chat window. * * @param {Object} param0 @@ -728,19 +754,11 @@ function factory(dependencies) { /** * Unsubscribe current user from provided channel. */ - async unsubscribe() { - if (this.channel_type === 'mail.channel') { - return this.async(() => this.env.services.rpc({ - model: 'mail.channel', - method: 'action_unfollow', - args: [[this.id]] - })); - } - return this.async(() => this.env.services.rpc({ - model: 'mail.channel', - method: 'channel_pin', - args: [this.uuid, false] - })); + unsubscribe() { + this.update({ + pendingFoldState: 'closed', + isPendingPinned: false, + }); } //---------------------------------------------------------------------- @@ -821,6 +839,14 @@ function factory(dependencies) { /** * @private + * @returns {boolean} + */ + _computeIsPinned() { + return this.isPendingPinned !== undefined ? this.isPendingPinned : this.isServerPinned; + } + + /** + * @private * @returns {mail.message} */ _computeLastCurrentPartnerMessageSeenByEveryone() { @@ -1059,6 +1085,17 @@ function factory(dependencies) { ) { this.update({ pendingFoldState: undefined }); } + if ( + this.isPendingPinned === false && + previous.isPendingPinned !== this.isPendingPinned + ) { + this.notifyUnPinToServer(); + } + if ( + this.isServerPinned === this.isPendingPinned + ) { + this.update({ isPendingPinned: undefined }); + } // TODO FIXME prevent to open/close a channel on mobile when you // open/close it on desktop (task-2267593) @@ -1090,6 +1127,7 @@ function factory(dependencies) { _updateBefore() { return { foldState: this.foldState, + isPendingPinned: this.isPendingPinned, pendingFoldState: this.pendingFoldState, }; } @@ -1222,7 +1260,36 @@ function factory(dependencies) { 'messagingCurrentPartner', ], }), + /** + * Determine if there is a pending pin state change, which is a change + * of pin state requested by the client but not yet confirmed by the + * server. + * + * This field can be updated to immediately change the pin state on the + * interface and to notify the server of the new state. + */ + isPendingPinned: attr(), + /** + * Boolean that determines whether this thread is pinned + * in discuss and present in the messaging menu. + */ isPinned: attr({ + compute: '_computeIsPinned', + dependencies: [ + 'isPendingPinned', + 'isServerPinned', + ], + }), + /** + * Determine the last pin state known by the server, which is the pin + * state displayed after initialization or when the last pending + * pin state change was confirmed by the server. + * + * This field should be considered read only in most situations. Only + * the code handling pin state change from the server should typically + * update it. + */ + isServerPinned: attr({ default: false, }), isTemporary: attr({ |
