From 8a9bc4c55ecf168a3a57da5c229e3928310bde97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexandre=20K=C3=BChn?= Date: Wed, 7 Jun 2023 09:29:54 +0000 Subject: [PATCH] [FIX] mail: Send message/log note in chatter style with MILK MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Send button has text "Send" or "Log" depending on composer mode - When button is active, it has `btn-primary` and composer mode buttons use `btn-outline-primary` - Add hint to use Send keyboard shortcut for fast send in chatter Other changes: - Re-introduce missing feature to jump to present when posting a new message in a thread. - In chatter, the topbar and composer are sticky. Whole chatter is scrollable rather than just a part of it. As a result, `Chatter-scrollable` becomes `Chatter-content`. - Editing a message in chatter now uses the extended composer Task-3356271 closes odoo/odoo#124905 X-original-commit: 894ec7e7757d2bb78574e8cd210012b83fad1cf6 Related: odoo/enterprise#42508 Signed-off-by: Sébastien Theys (seb) Signed-off-by: Alexandre Kühn (aku) --- .../src/embed/core/disabled_features.js | 3 + .../static/src/core/common/chat_window.js | 2 +- .../static/src/core/common/chat_window.xml | 4 +- .../mail/static/src/core/common/composer.js | 55 +++++- .../mail/static/src/core/common/composer.scss | 6 +- .../mail/static/src/core/common/composer.xml | 23 ++- addons/mail/static/src/core/common/discuss.js | 1 + .../mail/static/src/core/common/discuss.xml | 4 +- addons/mail/static/src/core/common/message.js | 6 +- .../mail/static/src/core/common/message.scss | 4 +- .../mail/static/src/core/common/message.xml | 6 +- .../src/core/common/messaging_service.js | 1 + addons/mail/static/src/core/common/thread.js | 22 ++- .../mail/static/src/core/common/thread.scss | 2 +- addons/mail/static/src/core/common/thread.xml | 4 +- .../static/src/core/common/thread_model.js | 1 + .../static/src/core/common/thread_service.js | 26 ++- addons/mail/static/src/core/web/chatter.js | 21 ++- addons/mail/static/src/core/web/chatter.scss | 9 + addons/mail/static/src/core/web/chatter.xml | 178 +++++++++--------- .../message_pin/common/message_patch.xml | 2 +- .../mail/static/tests/helpers/test_utils.js | 1 + .../static/tests/web/attachment_box_tests.js | 38 +--- addons/mail/static/tests/web/chatter_tests.js | 33 ++-- .../static/tests/web/chatter_topbar_tests.js | 32 ++-- 25 files changed, 298 insertions(+), 186 deletions(-) diff --git a/addons/im_livechat/static/src/embed/core/disabled_features.js b/addons/im_livechat/static/src/embed/core/disabled_features.js index 6a4c3cacffd..84fa35c94d8 100644 --- a/addons/im_livechat/static/src/embed/core/disabled_features.js +++ b/addons/im_livechat/static/src/embed/core/disabled_features.js @@ -41,6 +41,9 @@ patch(ThreadService.prototype, "im_livechat/disabled", { async fetchNewMessages(thread) { return; }, + async loadAround() { + return; + }, }); patch(Store.prototype, "im_livechat/disabled", { diff --git a/addons/mail/static/src/core/common/chat_window.js b/addons/mail/static/src/core/common/chat_window.js index 88c0e68bd5f..6cd295d8a92 100644 --- a/addons/mail/static/src/core/common/chat_window.js +++ b/addons/mail/static/src/core/common/chat_window.js @@ -48,7 +48,7 @@ export class ChatWindow extends Component { this.messageEdition = useMessageEdition(); this.messageHighlight = useMessageHighlight(); this.messageToReplyTo = useMessageToReplyTo(); - this.state = useState({ moreActionsExpanded: false }); + this.state = useState({ moreActionsExpanded: false, jumpThreadPresent: 0 }); this.ui = useState(useService("ui")); this.contentRef = useRef("content"); this.threadActions = useThreadActions(); diff --git a/addons/mail/static/src/core/common/chat_window.xml b/addons/mail/static/src/core/common/chat_window.xml index 290cfce2186..3239e3e3130 100644 --- a/addons/mail/static/src/core/common/chat_window.xml +++ b/addons/mail/static/src/core/common/chat_window.xml @@ -60,8 +60,8 @@ - - + + diff --git a/addons/mail/static/src/core/common/composer.js b/addons/mail/static/src/core/common/composer.js index 23569eeed7e..9b47dd20a96 100644 --- a/addons/mail/static/src/core/common/composer.js +++ b/addons/mail/static/src/core/common/composer.js @@ -16,13 +16,26 @@ import { markEventHandled, } from "@mail/utils/common/misc"; -import { Component, onMounted, useChildSubEnv, useEffect, useRef, useState } from "@odoo/owl"; +import { + Component, + markup, + onMounted, + useChildSubEnv, + useEffect, + useRef, + useState, +} from "@odoo/owl"; import { _t } from "@web/core/l10n/translation"; import { useService } from "@web/core/utils/hooks"; import { sprintf } from "@web/core/utils/strings"; import { FileUploader } from "@web/views/fields/file_handler"; +const EDIT_CLICK_TYPE = { + CANCEL: "cancel", + SAVE: "save", +}; + /** * @typedef {Object} Props * @property {import("@mail/core/common/composer_model").Composer} composer @@ -47,6 +60,7 @@ export class Composer extends Component { static defaultProps = { mode: "normal", className: "", + sidebar: true, }; static props = [ "composer", @@ -60,10 +74,16 @@ export class Composer extends Component { "messageEdition?", "messageComponent?", "className?", + "sidebar?", ]; static template = "mail.Composer"; setup() { + this.SEND_KEYBIND_TO_SEND = markup( + sprintf(_t("%(send_keybind)s to send"), { + send_keybind: this.sendKeybind, + }) + ); this.messaging = useMessaging(); this.store = useStore(); if (this.allowUpload) { @@ -180,6 +200,39 @@ export class Composer extends Component { return ""; } + onClickCancelOrSaveEditText(ev) { + if (this.props.composer.message && ev.target.dataset?.type === EDIT_CLICK_TYPE.CANCEL) { + this.props.onDiscardCallback(ev); + } + if (this.props.composer.message && ev.target.dataset?.type === EDIT_CLICK_TYPE.SAVE) { + this.editMessage(ev); + } + } + + get CANCEL_OR_SAVE_EDIT_TEXT() { + return markup( + sprintf( + _t( + "%(cancel_keybind)s to cancel, %(save_keybind)s to save" + ), + { + cancel_keybind: _t("Escape"), + cancel_type: EDIT_CLICK_TYPE.CANCEL, + save_keybind: this.sendKeybind, + save_type: EDIT_CLICK_TYPE.SAVE, + } + ) + ); + } + + get SEND_TEXT() { + return this.props.composer.type === "note" ? _t("Log") : _t("Send"); + } + + get sendKeybind() { + return this.props.mode === "extended" ? _t("CTRL-Enter") : _t("Enter"); + } + get thread() { return this.props.composer.thread ?? null; } diff --git a/addons/mail/static/src/core/common/composer.scss b/addons/mail/static/src/core/common/composer.scss index 4283d5b5a90..1c04322c361 100644 --- a/addons/mail/static/src/core/common/composer.scss +++ b/addons/mail/static/src/core/common/composer.scss @@ -46,10 +46,14 @@ max-height: 100px; resize: none; - .o-extended & { + .o-extended:not(.o-isUiSmall) & { max-height: 400px; } + .o-extended.o-isUiSmall & { + max-height: Min(400px, 30vh); + } + &::placeholder { @include text-truncate(); } diff --git a/addons/mail/static/src/core/common/composer.xml b/addons/mail/static/src/core/common/composer.xml index c9c0ff95a45..4119cd02a4e 100644 --- a/addons/mail/static/src/core/common/composer.xml +++ b/addons/mail/static/src/core/common/composer.xml @@ -8,11 +8,15 @@
-
+
Avatar of user
@@ -81,7 +85,10 @@
- +
+ + +
- escape to cancel, enter to save +
diff --git a/addons/mail/static/src/core/common/discuss.js b/addons/mail/static/src/core/common/discuss.js index 200f38225ac..7c611fcd6a0 100644 --- a/addons/mail/static/src/core/common/discuss.js +++ b/addons/mail/static/src/core/common/discuss.js @@ -51,6 +51,7 @@ export class Discuss extends Component { this.messageToReplyTo = useMessageToReplyTo(); this.contentRef = useRef("content"); this.root = useRef("root"); + this.state = useState({ jumpThreadPresent: 0 }); this.orm = useService("orm"); this.effect = useService("effect"); this.ui = useState(useService("ui")); diff --git a/addons/mail/static/src/core/common/discuss.xml b/addons/mail/static/src/core/common/discuss.xml index acffddc9519..5de23cb70f8 100644 --- a/addons/mail/static/src/core/common/discuss.xml +++ b/addons/mail/static/src/core/common/discuss.xml @@ -62,8 +62,8 @@
- - + +
diff --git a/addons/mail/static/src/core/common/message.js b/addons/mail/static/src/core/common/message.js index 9f7c346a6f4..fe1aa6a12d3 100644 --- a/addons/mail/static/src/core/common/message.js +++ b/addons/mail/static/src/core/common/message.js @@ -238,8 +238,10 @@ export class Message extends Component { return Boolean(!this.message.isTransient && this.message.resId); } - get canUnfollow() { - return Boolean(this.message.originThread?.followerOfSelf); + get showUnfollow() { + return Boolean( + this.message.originThread?.followerOfSelf && this.props.thread?.model === "mail.box" + ); } get isActive() { diff --git a/addons/mail/static/src/core/common/message.scss b/addons/mail/static/src/core/common/message.scss index 4f60775c365..b3322222861 100644 --- a/addons/mail/static/src/core/common/message.scss +++ b/addons/mail/static/src/core/common/message.scss @@ -51,10 +51,10 @@ } .o-mail-Message-actions { - z-index: $o-mail-NavigableList-zIndex - 2; + z-index: $o-mail-NavigableList-zIndex - 3; &.o-expanded { - z-index: $o-mail-NavigableList-zIndex - 1; + z-index: $o-mail-NavigableList-zIndex - 2; } button:hover, .focus { diff --git a/addons/mail/static/src/core/common/message.xml b/addons/mail/static/src/core/common/message.xml index 1d351fd0856..c0d51294878 100644 --- a/addons/mail/static/src/core/common/message.xml +++ b/addons/mail/static/src/core/common/message.xml @@ -79,7 +79,7 @@
- + Subject: @@ -131,7 +131,7 @@ View Reactions Mark as Read - Unfollow + Unfollow Mark as Unread Edit Delete diff --git a/addons/mail/static/src/core/common/messaging_service.js b/addons/mail/static/src/core/common/messaging_service.js index 9edb6ddfc08..b1957d23f5f 100644 --- a/addons/mail/static/src/core/common/messaging_service.js +++ b/addons/mail/static/src/core/common/messaging_service.js @@ -237,6 +237,7 @@ export class Messaging { Object.assign(notif.payload, { body: markup(notif.payload.body) }) ); channel.messages.push(message); + channel.transientMessages.push(message); break; } case "mail.link.preview/delete": diff --git a/addons/mail/static/src/core/common/thread.js b/addons/mail/static/src/core/common/thread.js index c2d942e7d88..8597889378c 100644 --- a/addons/mail/static/src/core/common/thread.js +++ b/addons/mail/static/src/core/common/thread.js @@ -28,6 +28,7 @@ export const PRESENT_THRESHOLD = 2500; /** * @typedef {Object} Props * @property {boolean} [isInChatWindow=false] + * @property {number} [jumpPresent=0] * @property {import("@mail/utils/common/hooks").MessageEdition} [messageEdition] * @property {import("@mail/utils/common/hooks").MessageToReplyTo} [messageToReplyTo] * @property {"asc"|"desc"} [order="asc"] @@ -39,6 +40,7 @@ export class Thread extends Component { static props = [ "isInChatWindow?", "hasScrollAdjust?", + "jumpPresent?", "thread", "messageEdition?", "messageToReplyTo?", @@ -47,6 +49,7 @@ export class Thread extends Component { static defaultProps = { isInChatWindow: false, hasScrollAdjust: true, + jumpPresent: 0, order: "asc", // 'asc' or 'desc' }; static template = "mail.Thread"; @@ -127,6 +130,15 @@ export class Thread extends Component { () => this.updateShowJumpPresent(), () => [this.props.thread.loadNewer] ); + useEffect( + () => { + if (this.props.jumpPresent !== this.lastJumpPresent) { + this.jumpToPresent("instant"); + this.lastJumpPresent = this.props.jumpPresent; + } + }, + () => [this.props.jumpPresent] + ); onMounted(() => { this.oldestPersistentMessage = this.props.thread.oldestPersistentMessage?.id; if (!this.env.inChatter || !this.props.hasScrollAdjust) { @@ -135,9 +147,13 @@ export class Thread extends Component { } }); onWillStart(() => { + this.lastJumpPresent = this.props.jumpPresent; this.threadService.fetchNewMessages(this.props.thread); }); onWillUpdateProps((nextProps) => { + if (nextProps.thread !== this.props.thread) { + this.lastJumpPresent = nextProps.jumpPresent; + } this.threadService.fetchNewMessages(nextProps.thread); }); } @@ -155,12 +171,12 @@ export class Thread extends Component { this.threadService.fetchMoreMessages(this.props.thread); } - async onClickJumpPresent() { + async jumpToPresent(behavior) { this.isJumpingRecent = true; await this.threadService.loadAround(this.props.thread); this.props.thread.loadNewer = false; - this.present.el.scrollIntoView({ - behavior: this.props.order === "asc" ? "smooth" : "instant", // FIXME somehow smooth not working in desc mode + this.present.el?.scrollIntoView({ + behavior: behavior ?? (this.props.order === "asc" ? "smooth" : "instant"), // FIXME somehow smooth not working in desc mode block: "center", }); // Let smooth scroll a bit so load more is not visible diff --git a/addons/mail/static/src/core/common/thread.scss b/addons/mail/static/src/core/common/thread.scss index e43d0e6ff78..a1de9a0c285 100644 --- a/addons/mail/static/src/core/common/thread.scss +++ b/addons/mail/static/src/core/common/thread.scss @@ -27,7 +27,7 @@ .o-mail-Thread-jumpPresent { background-color: mix(map-get($theme-colors, 'info'), $o-webclient-background-color, 5%); - z-index: $o-mail-NavigableList-zIndex - 2; + z-index: $o-mail-NavigableList-zIndex - 1; } .o-mail-NotificationMessage p { diff --git a/addons/mail/static/src/core/common/thread.xml b/addons/mail/static/src/core/common/thread.xml index 24e9c03d5d7..73659a60c02 100644 --- a/addons/mail/static/src/core/common/thread.xml +++ b/addons/mail/static/src/core/common/thread.xml @@ -3,7 +3,7 @@ -
+