[REF] mail: move ChannelInvitation code to discuss folder

Part of task-3265211

Part-of: odoo/odoo#120314
This commit is contained in:
Sébastien Theys
2023-05-02 22:26:43 +02:00
parent 546ba05e5b
commit a843eb776f
16 changed files with 138 additions and 89 deletions
+7
View File
@@ -130,6 +130,9 @@ For more specific needs, you may also assign custom-defined actions
('remove', 'mail/static/src/public/**/*'),
('remove', 'mail/static/src/**/*.dark.scss'),
('remove', 'mail/static/src/emoji_picker/emoji_data.js'),
# discuss (loaded last to fix dependencies)
('remove', 'mail/static/src/discuss/**/*'),
'mail/static/src/discuss/**/*',
],
"web.dark_mode_assets_backend": [
'mail/static/src/**/*.dark.scss',
@@ -184,6 +187,10 @@ For more specific needs, you may also assign custom-defined actions
('remove', 'mail/static/src/web/**/*'),
('remove', 'mail/static/src/emoji_picker/emoji_data.js'),
('remove', 'mail/static/src/**/*.dark.scss'),
# discuss (loaded last to fix dependencies)
('remove', 'mail/static/src/discuss/**/*'),
'mail/static/src/discuss/**/*',
('remove', 'mail/static/src/discuss/web/**/*'),
]
},
'license': 'LGPL-3',
@@ -2,14 +2,15 @@
import { Component, useRef, useState, onMounted, onWillStart } from "@odoo/owl";
import { useMessaging, useStore } from "@mail/core/messaging_hook";
import { ImStatus } from "./im_status";
import { ImStatus } from "@mail/discuss_app/im_status";
import { _t } from "@web/core/l10n/translation";
import { useService } from "@web/core/utils/hooks";
export class ChannelInvitation extends Component {
static components = { ImStatus };
static props = ["thread", "close?", "chatState?"];
static defaultProps = { hasSizeConstraints: false };
static props = ["hasSizeConstraints?", "thread", "close?", "chatState?"];
static template = "discuss.ChannelInvitation";
setup() {
@@ -1,13 +1,13 @@
.o-mail-ChannelInvitation {
.o-discuss-ChannelInvitation-has-size-constraints {
width: Min(95vw, 400px);
max-height: Min(calc(100vh - 140px), 530px);
}
.o-mail-ChannelInvitation-selectedList {
.o-discuss-ChannelInvitation-selectedList {
max-height: 100px;
}
.o-mail-ChannelInvitation-avatar {
.o-discuss-ChannelInvitation-avatar {
width: $o-mail-Avatar-size;
height: $o-mail-Avatar-size;
}
@@ -2,17 +2,17 @@
<templates xml:space="preserve">
<t t-name="discuss.ChannelInvitation" owl="1">
<div class="o-mail-ChannelInvitation d-flex flex-column" t-attf-class="{{ className }}" t-ref="root">
<div class="o-discuss-ChannelInvitation d-flex flex-column" t-att-class="{ 'o-discuss-ChannelInvitation-has-size-constraints': props.hasSizeConstraints }">
<t t-if="store.user">
<h3 class="mx-3 mt-3 mb-2">Invite people</h3>
<div class="mx-3 my-2">
<input class="o-mail-ChannelInvitation-search form-control" t-ref="input" placeholder="Type the name of a person" t-on-input="onInput"/>
<input class="o-discuss-ChannelInvitation-search form-control" t-ref="input" placeholder="Type the name of a person" t-on-input="onInput"/>
</div>
<div class="d-flex flex-column flex-grow-1 mx-0 py-2 overflow-auto">
<t t-foreach="state.selectablePartners" t-as="selectablePartner" t-key="selectablePartner.id">
<div class="o-mail-ChannelInvitation-selectable o_object_fit_cover d-flex align-items-center px-3 py-1 btn-light" t-on-click="() => this.onClickSelectablePartner(selectablePartner)">
<div class="o-discuss-ChannelInvitation-selectable o_object_fit_cover d-flex align-items-center px-3 py-1 btn-light" t-on-click="() => this.onClickSelectablePartner(selectablePartner)">
<div class="d-flex align-items-center p-2">
<div class="o-mail-ChannelInvitation-avatar position-relative d-flex flex-shrink-0 bg-100">
<div class="o-discuss-ChannelInvitation-avatar position-relative d-flex flex-shrink-0 bg-100">
<img class="w-100 h-100 rounded-circle o_object_fit_cover o_redirect"
t-att-src="threadService.avatarUrl(selectablePartner, props.thread)"/>
<ImStatus className="'position-absolute bottom-0 end-0'" persona="selectablePartner"/>
@@ -33,7 +33,7 @@
</div>
<div t-if="state.selectedPartners.length > 0" class="mx-3 mt-3">
<h4>Selected users:</h4>
<div class="o-mail-ChannelInvitation-selectedList overflow-auto">
<div class="o-discuss-ChannelInvitation-selectedList overflow-auto">
<t t-foreach="state.selectedPartners" t-as="selectedPartner" t-key="selectedPartner.id">
<button class="btn btn-secondary" t-on-click="() => this.onClickSelectedPartner(selectedPartner)">
<t t-esc="selectedPartner.name"/> <i class="fa fa-times"/>
@@ -0,0 +1,29 @@
/* @odoo-module */
import { ChannelInvitation } from "@mail/discuss/channel_invitation";
import { Discuss } from "@mail/discuss_app/discuss";
import { useRef } from "@odoo/owl";
import { usePopover } from "@web/core/popover/popover_hook";
import { patch } from "@web/core/utils/patch";
patch(Discuss.prototype, "discuss", {
setup() {
this._super();
this.addUsersRef = useRef("addUsers");
this.popover = usePopover(ChannelInvitation, {
onClose: () => (this.state.isAddingUsers = false),
});
this.state.isAddingUsers = false;
},
toggleInviteForm() {
if (this.popover.isOpen) {
this.popover.close();
} else {
this.state.isAddingUsers = true;
this.popover.open(this.addUsersRef.el, {
hasSizeConstraints: true,
thread: this.thread,
});
}
},
});
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve">
<t t-inherit="mail.Discuss" t-inherit-mode="extension">
<xpath expr="//*[@t-ref='startCall']" position="after">
<button t-if="thread.model === 'discuss.channel'" class="btn rounded px-2 shadow-none" t-att-class="{ 'o-isActive': state.isAddingUsers }" title="Add Users" t-on-click.stop="toggleInviteForm" t-ref="addUsers">
<i class="fa fa-lg fa-user-plus text-700"/>
</button>
</xpath>
</t>
</templates>
@@ -0,0 +1,15 @@
/* @odoo-module */
import { ChannelInvitation } from "@mail/discuss/channel_invitation";
import { ChatWindow } from "@mail/web/chat_window/chat_window";
import { patch } from "@web/core/utils/patch";
patch(ChatWindow, "discuss", {
components: { ...ChatWindow.components, ChannelInvitation },
});
patch(ChatWindow.prototype, "discuss", {
toggleAddUsers() {
this.state.activeMode = this.state.activeMode === "add-users" ? "" : "add-users";
},
});
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve">
<t t-inherit="mail.ChatWindow" t-inherit-mode="extension">
<xpath expr="//*[@t-ref='startCall']" position="after">
<div t-if="env.isSmall and thread and thread.type === 'channel'" class="o-mail-ChatWindow-command d-flex align-items-center h-100 px-3 py-0 m-0 opacity-50 opacity-100-hover" t-att-title="state.activeMode === 'add-users' ? 'Stop adding users' : 'Add users'" t-on-click.stop="toggleAddUsers">
<i class="fa fa-lg fa-user-plus"/>
</div>
</xpath>
<xpath expr="//ChannelMemberList" position="after">
<ChannelInvitation t-elif="state.activeMode === 'add-users'" thread="thread" chatState="state"/>
</xpath>
</t>
</templates>
+1 -19
View File
@@ -20,9 +20,7 @@ import {
useEffect,
} from "@odoo/owl";
import { CallSettings } from "../rtc/call_settings";
import { usePopover } from "@web/core/popover/popover_hook";
import { useService } from "@web/core/utils/hooks";
import { ChannelInvitation } from "./channel_invitation";
import { _t } from "@web/core/l10n/translation";
import { PinnedMessagesPanel } from "./pinned_messages_panel";
@@ -60,14 +58,7 @@ export class Discuss extends Component {
this.messageEdition = useMessageEdition();
this.messageToReplyTo = useMessageToReplyTo();
this.contentRef = useRef("content");
this.popover = usePopover(ChannelInvitation, {
onClose: () => (this.state.isAddingUsers = false),
});
this.addUsersRef = useRef("addUsers");
this.state = useState({
activeMode: this.MODES.NONE,
isAddingUsers: false,
});
this.state = useState({ activeMode: this.MODES.NONE });
this.orm = useService("orm");
this.effect = useService("effect");
this.prevInboxCounter = this.store.discuss.inbox.counter;
@@ -120,15 +111,6 @@ export class Discuss extends Component {
: this.MODES.PINNED_MESSAGES;
}
toggleInviteForm() {
if (this.popover.isOpen) {
this.popover.close();
} else {
this.state.isAddingUsers = true;
this.popover.open(this.addUsersRef.el, { thread: this.thread });
}
}
toggleSettings() {
this.state.activeMode =
this.state.activeMode === this.MODES.SETTINGS ? this.MODES.NONE : this.MODES.SETTINGS;
@@ -31,12 +31,9 @@
<button t-if="thread.model === 'discuss.channel'" class="btn rounded px-2 shadow-none" t-att-class="{ 'o-isActive': state.activeMode === MODES.PINNED_MESSAGES }" title="Pinned messages" t-on-click.stop="togglePinMenu">
<i class="fa fa-lg fa-thumb-tack text-700"/>
</button>
<button t-if="thread.allowCalls and thread.type !== 'mailbox' and thread !== rtc.state.channel" class="btn rounded px-2 shadow-none" title="Start a Call" t-on-click="() => this.rtc.toggleCall(this.thread)">
<button t-if="thread.allowCalls and thread.type !== 'mailbox' and thread !== rtc.state.channel" class="btn rounded px-2 shadow-none" title="Start a Call" t-on-click="() => this.rtc.toggleCall(this.thread)" t-ref="startCall">
<i class="fa fa-lg fa-phone text-700"/>
</button>
<button t-if="thread.model === 'discuss.channel'" t-att-class="{ 'o-isActive': state.isAddingUsers }" class="btn rounded px-2 shadow-none" t-ref="addUsers" title="Add Users" t-on-click.stop="toggleInviteForm">
<i class="fa fa-lg fa-user-plus text-700"/>
</button>
<button t-if="thread.hasMemberList" class="btn rounded px-2 shadow-none" t-att-class="{ 'o-isActive': state.activeMode === MODES.MEMBER_LIST }" t-att-title="state.activeMode === MODES.MEMBER_LIST ? 'Hide Member List' : 'Show Member List'" t-on-click.stop="toggleMemberList">
<i class="fa fa-lg fa-users text-700"/>
</button>
@@ -12,7 +12,6 @@ import { localization } from "@web/core/l10n/localization";
import { CallSettings } from "@mail/rtc/call_settings";
import { ChannelMemberList } from "@mail/discuss_app/channel_member_list";
import { ThreadIcon } from "@mail/discuss_app/thread_icon";
import { ChannelInvitation } from "@mail/discuss_app/channel_invitation";
import { isEventHandled } from "@mail/utils/misc";
import { ChannelSelector } from "@mail/discuss_app/channel_selector";
import { PinnedMessagesPanel } from "@mail/discuss_app/pinned_messages_panel";
@@ -33,7 +32,6 @@ export class ChatWindow extends Component {
CallSettings,
ChannelMemberList,
ThreadIcon,
ChannelInvitation,
PinnedMessagesPanel,
};
static props = ["chatWindow", "right?"];
@@ -140,10 +138,6 @@ export class ChatWindow extends Component {
this.state.activeMode = this.state.activeMode === "member-list" ? "" : "member-list";
}
toggleAddUsers() {
this.state.activeMode = this.state.activeMode === "add-users" ? "" : "add-users";
}
expand() {
if (this.thread.type === "chatter") {
this.action.doAction({
@@ -29,12 +29,9 @@
<div t-if="thread?.model === 'discuss.channel' and env.isSmall" class="o-mail-ChatWindow-command d-flex align-items-center h-100 px-3 py-0 m-0 opacity-50 opacity-100-hover" title="Pinned messages" t-on-click.stop="togglePinMenu">
<i class="fa fa-lg fa-thumb-tack"/>
</div>
<div t-if="thread and thread.allowCalls and thread !== rtc.state.channel and !props.chatWindow.hidden" class="o-mail-ChatWindow-command d-flex align-items-center h-100 px-3 py-0 m-0 opacity-50 opacity-100-hover" title="Start a Call" t-on-click.stop="() => this.rtc.toggleCall(this.props.chatWindow.thread)">
<div t-if="thread and thread.allowCalls and thread !== rtc.state.channel and !props.chatWindow.hidden" class="o-mail-ChatWindow-command d-flex align-items-center h-100 px-3 py-0 m-0 opacity-50 opacity-100-hover" title="Start a Call" t-on-click.stop="() => this.rtc.toggleCall(this.props.chatWindow.thread)" t-ref="startCall">
<i class="fa fa-phone"/>
</div>
<div t-if="env.isSmall and thread and thread.type === 'channel'" class="o-mail-ChatWindow-command d-flex align-items-center h-100 px-3 py-0 m-0 opacity-50 opacity-100-hover" t-att-title="state.activeMode === 'add-users' ? 'Stop adding users' : 'Add users'" t-on-click.stop="toggleAddUsers">
<i class="fa fa-lg fa-user-plus"/>
</div>
<t t-if="thread">
<div t-if="thread and thread.hasMemberList and !props.chatWindow.hidden and !props.chatWindow.folded" class="o-mail-ChatWindow-command d-flex align-items-center h-100 px-3 py-0 m-0 opacity-50 opacity-100-hover" t-att-title="state.activeMode === 'member-list' ? 'Hide Member List' : 'Show Member List'" t-on-click.stop="toggleMemberList">
<i class="fa fa-users"/>
@@ -55,7 +52,6 @@
<PinnedMessagesPanel t-if="state.activeMode === 'pinned-messages'" thread="thread"/>
<CallSettings t-elif="state.activeMode === 'in-settings'" thread="thread" className="'flex-grow-1'"/>
<ChannelMemberList t-elif="state.activeMode === 'member-list'" thread="thread" className="'o-mail-Discuss-channelMemberList flex-shrink-0 border-start w-100 h-100'"/>
<ChannelInvitation t-elif="state.activeMode === 'add-users'" thread="thread" chatState="state"/>
<t t-else="">
<Call t-if="Object.keys(thread.rtcSessions).length > 0" thread="thread" compact="true"/>
<Thread isInChatWindow="true" thread="thread" t-key="thread.localId" messageEdition="messageEdition" messageToReplyTo="messageToReplyTo"/>
@@ -184,44 +184,6 @@ QUnit.test("Remove attachment from message", async (assert) => {
assert.containsNone(tab1.target, ".o-mail-AttachmentCard:contains(test.txt)");
});
QUnit.test("Add member to channel", async (assert) => {
const pyEnv = await startServer();
const channelId = pyEnv["discuss.channel"].create({ name: "General" });
const userId = pyEnv["res.users"].create({ name: "Harry" });
pyEnv["res.partner"].create({ name: "Harry", user_ids: [userId] });
const { openDiscuss } = await start();
await openDiscuss(channelId);
await click("button[title='Show Member List']");
assert.containsOnce($, ".o-mail-ChannelMember:contains(Mitchell Admin)");
await click("button[title='Add Users']");
await click(".o-mail-ChannelInvitation-selectable:contains(Harry)");
await click("button[title='Invite to Channel']");
assert.containsOnce($, ".o-mail-ChannelMember:contains(Harry)");
});
QUnit.test("Remove member from channel", async (assert) => {
const pyEnv = await startServer();
const userId = pyEnv["res.users"].create({ name: "Harry" });
const partnerId = pyEnv["res.partner"].create({
name: "Harry",
user_ids: [userId],
});
const channelId = pyEnv["discuss.channel"].create({
name: "General",
channel_member_ids: [
[0, 0, { partner_id: pyEnv.currentPartnerId }],
[0, 0, { partner_id: partnerId }],
],
});
const { env, openDiscuss } = await start();
await openDiscuss(channelId);
await click("button[title='Show Member List']");
assert.containsOnce($, ".o-mail-ChannelMember:contains(Harry)");
env.services.orm.call("discuss.channel", "action_unfollow", [channelId], {
context: { mockedUserId: userId },
});
});
QUnit.test("Message delete notification", async (assert) => {
const pyEnv = await startServer();
const messageId = pyEnv["mail.message"].create({
@@ -1,4 +1,4 @@
/** @odoo-module **/
/* @odoo-module */
import { click, insertText, start, startServer } from "@mail/../tests/helpers/test_utils";
@@ -24,7 +24,7 @@ QUnit.test(
const { openDiscuss } = await start({ hasTimeControl: true });
await openDiscuss(channelId);
await click(".o-mail-Discuss-header button[title='Add Users']");
assert.containsOnce($, ".o-mail-ChannelInvitation");
assert.containsOnce($, ".o-discuss-ChannelInvitation");
}
);
@@ -53,8 +53,8 @@ QUnit.test(
const { openDiscuss } = await start();
await openDiscuss(channelId);
await click(".o-mail-Discuss-header button[title='Add Users']");
await insertText(".o-mail-ChannelInvitation-search", "TestPartner2");
assert.strictEqual($(".o-mail-ChannelInvitation-selectable").text(), "TestPartner2");
await insertText(".o-discuss-ChannelInvitation-search", "TestPartner2");
assert.strictEqual($(".o-discuss-ChannelInvitation-selectable").text(), "TestPartner2");
}
);
@@ -79,7 +79,7 @@ QUnit.test("Invitation form should display channel group restriction", async (as
await click(".o-mail-Discuss-header button[title='Add Users']");
assert.containsOnce(
$,
'.o-mail-ChannelInvitation:contains(Access restricted to group "testGroup")'
'.o-discuss-ChannelInvitation:contains(Access restricted to group "testGroup")'
);
});
@@ -106,7 +106,7 @@ QUnit.test("should be able to create a new group chat from an existing chat", as
const { openDiscuss } = await start();
await openDiscuss(channelId);
await click(".o-mail-Discuss-header button[title='Add Users']");
await insertText(".o-mail-ChannelInvitation-search", "TestPartner2");
await insertText(".o-discuss-ChannelInvitation-search", "TestPartner2");
await click(".form-check-input");
await click("button[title='Create Group Chat']");
assert.strictEqual(
@@ -0,0 +1,43 @@
/* @odoo-module */
import { click, start, startServer } from "@mail/../tests/helpers/test_utils";
QUnit.module("crosstab");
QUnit.test("Add member to channel", async (assert) => {
const pyEnv = await startServer();
const channelId = pyEnv["discuss.channel"].create({ name: "General" });
const userId = pyEnv["res.users"].create({ name: "Harry" });
pyEnv["res.partner"].create({ name: "Harry", user_ids: [userId] });
const { openDiscuss } = await start();
await openDiscuss(channelId);
await click("button[title='Show Member List']");
assert.containsOnce($, ".o-mail-ChannelMember:contains(Mitchell Admin)");
await click("button[title='Add Users']");
await click(".o-discuss-ChannelInvitation-selectable:contains(Harry)");
await click("button[title='Invite to Channel']");
assert.containsOnce($, ".o-mail-ChannelMember:contains(Harry)");
});
QUnit.test("Remove member from channel", async (assert) => {
const pyEnv = await startServer();
const userId = pyEnv["res.users"].create({ name: "Harry" });
const partnerId = pyEnv["res.partner"].create({
name: "Harry",
user_ids: [userId],
});
const channelId = pyEnv["discuss.channel"].create({
name: "General",
channel_member_ids: [
[0, 0, { partner_id: pyEnv.currentPartnerId }],
[0, 0, { partner_id: partnerId }],
],
});
const { env, openDiscuss } = await start();
await openDiscuss(channelId);
await click("button[title='Show Member List']");
assert.containsOnce($, ".o-mail-ChannelMember:contains(Harry)");
env.services.orm.call("discuss.channel", "action_unfollow", [channelId], {
context: { mockedUserId: userId },
});
});
@@ -156,7 +156,7 @@ QUnit.test("Channel member count update after user joined", async (assert) => {
assert.strictEqual(thread.memberCount, 1);
await click("button[title='Show Member List']");
await click("button[title='Add Users']");
await click(".o-mail-ChannelInvitation-selectable:contains(Harry)");
await click(".o-discuss-ChannelInvitation-selectable:contains(Harry)");
await click("button[title='Invite to Channel']");
assert.strictEqual(thread.memberCount, 2);
});