FEATURE: new jump to channel menu (#22383)

This commit replaces two existing screens:
- draft
- channel selection modal

Main features compared to existing solutions
- features are now combined, meaning you can for example create multi users DM
- it will show users with chat disabled
- it shows unread state
- hopefully a better look/feel
- lots of small details and fixes...

Other noticeable fixes
- starting a DM with a user, even from the user card and clicking <kbd>Chat</kbd> will not show a green dot for the target user (or even the channel) until a message is actually sent
- it should almost never do a full page reload anymore

---------

Co-authored-by: Martin Brennan <mjrbrennan@gmail.com>
Co-authored-by: Jordan Vidrine <30537603+jordanvidrine@users.noreply.github.com>
Co-authored-by: chapoi <101828855+chapoi@users.noreply.github.com>
Co-authored-by: Mark VanLandingham <markvanlan@gmail.com>
This commit is contained in:
Joffrey JAFFEUX
2023-07-05 18:18:27 +02:00
committed by GitHub
parent e72153dd1a
commit d75d64bf16
95 changed files with 2331 additions and 2004 deletions

View File

@ -37,7 +37,7 @@ module("Discourse Chat | Component | chat-user-avatar", function (hooks) {
});
await render(
hbs`<ChatUserAvatar @chat={{this.chat}} @user={{this.user}} />`
hbs`<ChatUserAvatar @showPresence={{true}} @chat={{this.chat}} @user={{this.user}} />`
);
assert.true(

View File

@ -1,141 +0,0 @@
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
import { click, fillIn, render } from "@ember/test-helpers";
import hbs from "htmlbars-inline-precompile";
import { exists, query } from "discourse/tests/helpers/qunit-helpers";
import ChatChannel from "discourse/plugins/chat/discourse/models/chat-channel";
import { Promise } from "rsvp";
import fabricators from "discourse/plugins/chat/discourse/lib/fabricators";
import { module, test } from "qunit";
function mockChat(context, options = {}) {
const mock = context.container.lookup("service:chat");
mock.searchPossibleDirectMessageUsers = () => {
return Promise.resolve({
users: options.users || [{ username: "hawk" }, { username: "mark" }],
});
};
mock.getDmChannelForUsernames = () => {
return Promise.resolve({ chat_channel: fabricators.channel() });
};
return mock;
}
module("Discourse Chat | Component | direct-message-creator", function (hooks) {
setupRenderingTest(hooks);
test("search", async function (assert) {
this.set("chat", mockChat(this));
this.set("channel", ChatChannel.createDirectMessageChannelDraft());
await render(
hbs`<DirectMessageCreator @channel={{this.channel}} @chat={{this.chat}} />`
);
await fillIn(".filter-usernames", "hawk");
assert.true(exists("li.user[data-username='hawk']"));
});
test("select/deselect", async function (assert) {
this.set("chat", mockChat(this));
this.set("channel", ChatChannel.createDirectMessageChannelDraft());
await render(
hbs`<DirectMessageCreator @channel={{this.channel}} @chat={{this.chat}} />`
);
assert.false(exists(".selected-user"));
await fillIn(".filter-usernames", "hawk");
await click("li.user[data-username='hawk']");
assert.true(exists(".selected-user"));
await click(".selected-user");
assert.false(exists(".selected-user"));
});
test("no search results", async function (assert) {
this.set("chat", mockChat(this, { users: [] }));
this.set("channel", ChatChannel.createDirectMessageChannelDraft());
await render(
hbs`<DirectMessageCreator @channel={{this.channel}} @chat={{this.chat}} />`
);
await fillIn(".filter-usernames", "bad cat");
assert.true(exists(".no-results"));
});
test("loads user on first load", async function (assert) {
this.set("chat", mockChat(this));
this.set("channel", ChatChannel.createDirectMessageChannelDraft());
await render(
hbs`<DirectMessageCreator @channel={{this.channel}} @chat={{this.chat}} />`
);
assert.true(exists("li.user[data-username='hawk']"));
assert.true(exists("li.user[data-username='mark']"));
});
test("do not load more users after selection", async function (assert) {
this.set("chat", mockChat(this));
this.set("channel", ChatChannel.createDirectMessageChannelDraft());
await render(
hbs`<DirectMessageCreator @channel={{this.channel}} @chat={{this.chat}} />`
);
await click("li.user[data-username='hawk']");
assert.false(exists("li.user[data-username='mark']"));
});
test("apply is-focused to filter-area on focus input", async function (assert) {
this.set("chat", mockChat(this));
this.set("channel", ChatChannel.createDirectMessageChannelDraft());
await render(
hbs`<DirectMessageCreator @channel={{this.channel}} @chat={{this.chat}} /><button class="test-blur">blur</button>`
);
await click(".filter-usernames");
assert.true(exists(".filter-area.is-focused"));
await click(".test-blur");
assert.false(exists(".filter-area.is-focused"));
});
test("state is reset on channel change", async function (assert) {
this.set("chat", mockChat(this));
this.set("channel", ChatChannel.createDirectMessageChannelDraft());
await render(
hbs`<DirectMessageCreator @channel={{this.channel}} @chat={{this.chat}} />`
);
await fillIn(".filter-usernames", "hawk");
assert.strictEqual(query(".filter-usernames").value, "hawk");
this.set("channel", fabricators.channel());
this.set("channel", ChatChannel.createDirectMessageChannelDraft());
assert.strictEqual(query(".filter-usernames").value, "");
assert.true(exists(".filter-area.is-focused"));
assert.true(exists("li.user[data-username='hawk']"));
});
test("shows user status", async function (assert) {
const userWithStatus = {
username: "hawk",
status: { emoji: "tooth", description: "off to dentist" },
};
const chat = mockChat(this, { users: [userWithStatus] });
this.set("chat", chat);
this.set("channel", ChatChannel.createDirectMessageChannelDraft());
await render(
hbs`<DirectMessageCreator @channel={{this.channel}} @chat={{this.chat}} />`
);
await fillIn(".filter-usernames", "hawk");
assert.true(exists(".user-status-message"));
});
});