FEATURE: allow names in chat channel title (#28843)

This change adds full names to direct message channel titles when the following conditions are met:

- SiteSetting.enable_names = true
- SiteSetting.display_name_on_posts = true
- SiteSetting.prioritize_username_in_ux = false

If a user's full name is blank, it will fallback to their username in both 1-1 channels and Group DM channels.
This commit is contained in:
David Battersby 2024-09-16 18:12:13 +04:00 committed by GitHub
parent 8a57e50664
commit b60f4606e5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 141 additions and 30 deletions

View File

@ -38,29 +38,52 @@ module Chat
.map { |user| user || Chat::NullUser.new } .map { |user| user || Chat::NullUser.new }
.reject { |u| u.is_system_user? } .reject { |u| u.is_system_user? }
prefers_name =
SiteSetting.enable_names && SiteSetting.display_name_on_posts &&
!SiteSetting.prioritize_username_in_ux
# direct message to self # direct message to self
if users.empty? if users.empty?
return I18n.t("chat.channel.dm_title.single_user", username: "@#{acting_user.username}") return(
I18n.t(
"chat.channel.dm_title.single_user",
username:
(
if prefers_name
acting_user.name.presence || "@#{acting_user.username}"
else
"@#{acting_user.username}"
end
),
)
)
end end
# all users deleted # all users deleted
return chat_channel.id if !users.first return chat_channel.id if !users.first
usernames_formatted = users.sort_by(&:username).map { |u| "@#{u.username}" } formatted_names =
if usernames_formatted.size > 7 (
if prefers_name
users.map { |u| u.name.presence || "@#{u.username}" }.sort_by { |name| name[1..-1] }
else
users.sort_by(&:username).map { |u| "@#{u.username}" }
end
)
if formatted_names.size > 7
return( return(
I18n.t( I18n.t(
"chat.channel.dm_title.multi_user_truncated", "chat.channel.dm_title.multi_user_truncated",
comma_separated_usernames: comma_separated_usernames: formatted_names[0..5].join(I18n.t("word_connector.comma")),
usernames_formatted[0..5].join(I18n.t("word_connector.comma")), count: formatted_names.length - 6,
count: usernames_formatted.length - 6,
) )
) )
end end
I18n.t( I18n.t(
"chat.channel.dm_title.multi_user", "chat.channel.dm_title.multi_user",
comma_separated_usernames: usernames_formatted.join(I18n.t("word_connector.comma")), comma_separated_usernames: formatted_names.join(I18n.t("word_connector.comma")),
) )
end end
end end

View File

@ -9,32 +9,33 @@ import ChatChannelUnreadIndicator from "../chat-channel-unread-indicator";
export default class ChatChannelName extends Component { export default class ChatChannelName extends Component {
@service currentUser; @service currentUser;
@service siteSettings;
get unreadIndicator() { get unreadIndicator() {
return this.args.unreadIndicator ?? false; return this.args.unreadIndicator ?? false;
} }
get firstUser() {
return this.args.channel.chatable.users[0];
}
get users() { get users() {
return this.args.channel.chatable.users; return this.args.channel.chatable.users;
} }
get groupDirectMessage() { get prefersName() {
return ( return (
this.args.channel.isDirectMessageChannel && this.siteSettings.enable_names &&
this.args.channel.chatable.group this.siteSettings.display_name_on_posts &&
!this.siteSettings.prioritize_username_in_ux
); );
} }
get groupsDirectMessageTitle() { get directMessageTitle() {
return this.args.channel.title || this.usernames; if (this.users.length === 0) {
return this.prefersName
? this.currentUser.name || this.currentUser.username
: this.currentUser.username;
} }
return this.prefersName
get usernames() { ? this.users.map((user) => user.name || user.username).join(", ")
return this.users.mapBy("username").join(", "); : this.users.mapBy("username").join(", ");
} }
get channelColorStyle() { get channelColorStyle() {
@ -50,15 +51,17 @@ export default class ChatChannelName extends Component {
get channelTitle() { get channelTitle() {
if (this.args.channel.isDirectMessageChannel) { if (this.args.channel.isDirectMessageChannel) {
return this.groupDirectMessage return this.args.channel.title ?? this.directMessageTitle;
? this.groupsDirectMessageTitle
: this.firstUser.username;
} }
return this.args.channel.title; return this.args.channel.title;
} }
get showPluginOutlet() { get showPluginOutlet() {
return this.args.channel.isDirectMessageChannel && !this.groupDirectMessage; return (
this.args.channel.isDirectMessageChannel &&
!this.args.channel.chatable.group
);
} }
<template> <template>

View File

@ -72,5 +72,52 @@ describe Chat::DirectMessage do
) )
end end
end end
context "when names are enabled" do
before do
SiteSetting.enable_names = true
SiteSetting.display_name_on_posts = true
SiteSetting.prioritize_username_in_ux = false
end
it "returns full name of user" do
new_user = Fabricate.build(:user, username: "johndoe", name: "John Doe")
direct_message = Fabricate(:direct_message, users: [user1, new_user])
expect(direct_message.chat_channel_title_for_user(chat_channel, user1)).to eq(
I18n.t("chat.channel.dm_title.single_user", username: "John Doe"),
)
end
it "returns full names when chatting with multiple users" do
user2.update!(name: "John Doe")
user3 = Fabricate.build(:user, username: "chatdmbot", name: "Chat Bot")
direct_message = Fabricate(:direct_message, users: [user1, user2, user3])
expect(direct_message.chat_channel_title_for_user(chat_channel, user1)).to eq(
I18n.t(
"chat.channel.dm_title.multi_user",
comma_separated_usernames:
[user3.name, user2.name].map { |u| u }.join(I18n.t("word_connector.comma")),
),
)
end
it "returns both full names and usernames when no name available" do
new_user = Fabricate.build(:user, username: "johndoe", name: "John Doe")
direct_message = Fabricate(:direct_message, users: [user1, new_user, user2])
user2.update!(name: nil)
expect(direct_message.chat_channel_title_for_user(chat_channel, user1)).to eq(
I18n.t(
"chat.channel.dm_title.multi_user",
comma_separated_usernames: ["@#{user2.username}", new_user.name].join(
I18n.t("word_connector.comma"),
),
),
)
end
end
end end
end end

View File

@ -67,21 +67,59 @@ module("Discourse Chat | Component | <ChannelName />", function (hooks) {
); );
}); });
test("dm channel - self", async function (assert) {
const channel = new ChatFabricators(getOwner(this)).directMessageChannel({
chatable: new ChatFabricators(getOwner(this)).directMessage({
users: [],
}),
});
await render(<template><ChannelName @channel={{channel}} /></template>);
assert.strictEqual(
query(CHANNEL_NAME_LABEL).innerText.trim(),
this.currentUser.username
);
});
test("dm channel - prefers name", async function (assert) {
const siteSettings = getOwner(this).lookup("service:site-settings");
siteSettings.enable_names = true;
siteSettings.display_name_on_posts = true;
siteSettings.prioritize_username_in_ux = false;
const channel = new ChatFabricators(getOwner(this)).directMessageChannel({
users: [
new CoreFabricators(getOwner(this)).user({ name: "Alice" }),
new CoreFabricators(getOwner(this)).user({ name: "Bob" }),
],
});
channel.chatable.group = true;
const users = channel.chatable.users;
await render(<template><ChannelName @channel={{channel}} /></template>);
assert.strictEqual(
query(CHANNEL_NAME_LABEL).innerText.trim(),
users.mapBy("name").join(", ")
);
});
test("unreadIndicator", async function (assert) { test("unreadIndicator", async function (assert) {
const channel = new ChatFabricators(getOwner(this)).directMessageChannel(); const channel = new ChatFabricators(getOwner(this)).directMessageChannel();
channel.tracking.unreadCount = 1; channel.tracking.unreadCount = 1;
let unreadIndicator = true; let unreadIndicator = true;
await render( await render(<template>
<template><ChannelName @channel={{channel}} @unreadIndicator={{unreadIndicator}}/></template> <ChannelName @channel={{channel}} @unreadIndicator={{unreadIndicator}} />
); </template>);
assert.true(exists(".chat-channel-unread-indicator")); assert.true(exists(".chat-channel-unread-indicator"));
unreadIndicator = false; unreadIndicator = false;
await render( await render(<template>
<template><ChannelName @channel={{channel}} @unreadIndicator={{unreadIndicator}}/></template> <ChannelName @channel={{channel}} @unreadIndicator={{unreadIndicator}} />
); </template>);
assert.false(exists(".chat-channel-unread-indicator")); assert.false(exists(".chat-channel-unread-indicator"));
}); });