mirror of
https://github.com/discourse/discourse.git
synced 2025-02-16 08:15:00 +00:00
FEATURE: Chat header icon indicator preference (#20474)
This commit allows the user to set their preference vis-a-vis the chat icon in the header of the page. There are three options: - All New (default) - This maintains the existing behaviour where all new messages in the channel show a blue dot on the icon - Direct Messages and Mentions - Only show the green dot on the icon when you are directly messaged or mentioned, the blue dot is never shown - Never - Never show any dot on the chat icon, for those who want tractor-beam-laser-focus
This commit is contained in:
parent
c051992098
commit
d3a1b09361
@ -292,6 +292,7 @@ end
|
|||||||
# enable_experimental_sidebar :boolean default(FALSE)
|
# enable_experimental_sidebar :boolean default(FALSE)
|
||||||
# seen_popups :integer is an Array
|
# seen_popups :integer is an Array
|
||||||
# sidebar_list_destination :integer default("none_selected"), not null
|
# sidebar_list_destination :integer default("none_selected"), not null
|
||||||
|
# chat_header_indicator_preference :integer default(0), not null
|
||||||
#
|
#
|
||||||
# Indexes
|
# Indexes
|
||||||
#
|
#
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
{{#if (gt this.chatChannelsManager.unreadUrgentCount 0)}}
|
{{#if this.showUrgentIndicator}}
|
||||||
<div class="chat-channel-unread-indicator urgent">
|
<div class="chat-channel-unread-indicator urgent">
|
||||||
<div class="number-wrap">
|
<div class="number-wrap">
|
||||||
<div class="number">{{this.chatChannelsManager.unreadUrgentCount}}</div>
|
<div class="number">{{this.chatChannelsManager.unreadUrgentCount}}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{else if (gt this.chatChannelsManager.unreadCount 0)}}
|
{{else if this.showUnreadIndicator}}
|
||||||
<div class="chat-channel-unread-indicator"></div>
|
<div class="chat-channel-unread-indicator"></div>
|
||||||
{{/if}}
|
{{/if}}
|
@ -1,6 +1,44 @@
|
|||||||
import { inject as service } from "@ember/service";
|
import { inject as service } from "@ember/service";
|
||||||
import Component from "@glimmer/component";
|
import Component from "@glimmer/component";
|
||||||
|
import {
|
||||||
|
HEADER_INDICATOR_PREFERENCE_ALL_NEW,
|
||||||
|
HEADER_INDICATOR_PREFERENCE_DM_AND_MENTIONS,
|
||||||
|
HEADER_INDICATOR_PREFERENCE_NEVER,
|
||||||
|
} from "../controllers/preferences-chat";
|
||||||
|
|
||||||
export default class ChatHeaderIconUnreadIndicator extends Component {
|
export default class ChatHeaderIconUnreadIndicator extends Component {
|
||||||
@service chatChannelsManager;
|
@service chatChannelsManager;
|
||||||
|
@service currentUser;
|
||||||
|
|
||||||
|
get showUrgentIndicator() {
|
||||||
|
return (
|
||||||
|
this.chatChannelsManager.unreadUrgentCount > 0 &&
|
||||||
|
this.#hasAnyIndicatorPreference([
|
||||||
|
HEADER_INDICATOR_PREFERENCE_ALL_NEW,
|
||||||
|
HEADER_INDICATOR_PREFERENCE_DM_AND_MENTIONS,
|
||||||
|
])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
get showUnreadIndicator() {
|
||||||
|
return (
|
||||||
|
this.chatChannelsManager.unreadCount > 0 &&
|
||||||
|
this.#hasAnyIndicatorPreference([HEADER_INDICATOR_PREFERENCE_ALL_NEW])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
get indicatorPreference() {
|
||||||
|
return this.currentUser.user_option.chat_header_indicator_preference;
|
||||||
|
}
|
||||||
|
|
||||||
|
#hasAnyIndicatorPreference(preferences) {
|
||||||
|
if (
|
||||||
|
!this.currentUser ||
|
||||||
|
this.indicatorPreference === HEADER_INDICATOR_PREFERENCE_NEVER
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return preferences.includes(this.indicatorPreference);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,18 +13,39 @@ const CHAT_ATTRS = [
|
|||||||
"ignore_channel_wide_mention",
|
"ignore_channel_wide_mention",
|
||||||
"chat_sound",
|
"chat_sound",
|
||||||
"chat_email_frequency",
|
"chat_email_frequency",
|
||||||
|
"chat_header_indicator_preference",
|
||||||
];
|
];
|
||||||
|
|
||||||
|
export const HEADER_INDICATOR_PREFERENCE_NEVER = "never";
|
||||||
|
export const HEADER_INDICATOR_PREFERENCE_DM_AND_MENTIONS = "dm_and_mentions";
|
||||||
|
export const HEADER_INDICATOR_PREFERENCE_ALL_NEW = "all_new";
|
||||||
|
|
||||||
const EMAIL_FREQUENCY_OPTIONS = [
|
const EMAIL_FREQUENCY_OPTIONS = [
|
||||||
{ name: I18n.t(`chat.email_frequency.never`), value: "never" },
|
{ name: I18n.t(`chat.email_frequency.never`), value: "never" },
|
||||||
{ name: I18n.t(`chat.email_frequency.when_away`), value: "when_away" },
|
{ name: I18n.t(`chat.email_frequency.when_away`), value: "when_away" },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const HEADER_INDICATOR_OPTIONS = [
|
||||||
|
{
|
||||||
|
name: I18n.t(`chat.header_indicator_preference.all_new`),
|
||||||
|
value: HEADER_INDICATOR_PREFERENCE_ALL_NEW,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: I18n.t(`chat.header_indicator_preference.dm_and_mentions`),
|
||||||
|
value: HEADER_INDICATOR_PREFERENCE_DM_AND_MENTIONS,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: I18n.t(`chat.header_indicator_preference.never`),
|
||||||
|
value: HEADER_INDICATOR_PREFERENCE_NEVER,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
export default class PreferencesChatController extends Controller {
|
export default class PreferencesChatController extends Controller {
|
||||||
@service chatAudioManager;
|
@service chatAudioManager;
|
||||||
subpageTitle = I18n.t("chat.admin.title");
|
subpageTitle = I18n.t("chat.admin.title");
|
||||||
|
|
||||||
emailFrequencyOptions = EMAIL_FREQUENCY_OPTIONS;
|
emailFrequencyOptions = EMAIL_FREQUENCY_OPTIONS;
|
||||||
|
headerIndicatorOptions = HEADER_INDICATOR_OPTIONS;
|
||||||
|
|
||||||
@discourseComputed
|
@discourseComputed
|
||||||
chatSounds() {
|
chatSounds() {
|
||||||
|
@ -5,6 +5,7 @@ const ONLY_CHAT_PUSH_NOTIFICATIONS_FIELD = "only_chat_push_notifications";
|
|||||||
const IGNORE_CHANNEL_WIDE_MENTION = "ignore_channel_wide_mention";
|
const IGNORE_CHANNEL_WIDE_MENTION = "ignore_channel_wide_mention";
|
||||||
const CHAT_SOUND = "chat_sound";
|
const CHAT_SOUND = "chat_sound";
|
||||||
const CHAT_EMAIL_FREQUENCY = "chat_email_frequency";
|
const CHAT_EMAIL_FREQUENCY = "chat_email_frequency";
|
||||||
|
const CHAT_HEADER_INDICATOR_PREFERENCE = "chat_header_indicator_preference";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "chat-user-options",
|
name: "chat-user-options",
|
||||||
@ -18,6 +19,7 @@ export default {
|
|||||||
api.addSaveableUserOptionField(IGNORE_CHANNEL_WIDE_MENTION);
|
api.addSaveableUserOptionField(IGNORE_CHANNEL_WIDE_MENTION);
|
||||||
api.addSaveableUserOptionField(CHAT_SOUND);
|
api.addSaveableUserOptionField(CHAT_SOUND);
|
||||||
api.addSaveableUserOptionField(CHAT_EMAIL_FREQUENCY);
|
api.addSaveableUserOptionField(CHAT_EMAIL_FREQUENCY);
|
||||||
|
api.addSaveableUserOptionField(CHAT_HEADER_INDICATOR_PREFERENCE);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -69,6 +69,21 @@
|
|||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="control-group chat-setting controls-dropdown">
|
||||||
|
<label for="user_chat_header_indicator_preference">
|
||||||
|
{{i18n "chat.header_indicator_preference.title"}}
|
||||||
|
</label>
|
||||||
|
<ComboBox
|
||||||
|
@valueProperty="value"
|
||||||
|
@content={{this.headerIndicatorOptions}}
|
||||||
|
@value={{this.model.user_option.chat_header_indicator_preference}}
|
||||||
|
@id="user_chat_header_indicator_preference"
|
||||||
|
@onChange={{action
|
||||||
|
(mut this.model.user_option.chat_header_indicator_preference)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<SaveControls
|
<SaveControls
|
||||||
@id="user_chat_preference_save"
|
@id="user_chat_preference_save"
|
||||||
@model={{this.model}}
|
@model={{this.model}}
|
||||||
|
@ -94,6 +94,11 @@ en:
|
|||||||
never: "Never"
|
never: "Never"
|
||||||
title: "Email Notifications"
|
title: "Email Notifications"
|
||||||
when_away: "Only when away"
|
when_away: "Only when away"
|
||||||
|
header_indicator_preference:
|
||||||
|
title: "Show activity indicator in header"
|
||||||
|
all_new: "All New Messages"
|
||||||
|
dm_and_mentions: "Direct Messages and Mentions"
|
||||||
|
never: "Never"
|
||||||
enable: "Enable chat"
|
enable: "Enable chat"
|
||||||
flag: "Flag"
|
flag: "Flag"
|
||||||
emoji: "Insert emoji"
|
emoji: "Insert emoji"
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class AddChatHeaderIndicatorPreference < ActiveRecord::Migration[7.0]
|
||||||
|
def change
|
||||||
|
add_column :user_options, :chat_header_indicator_preference, :integer, default: 0, null: false
|
||||||
|
end
|
||||||
|
end
|
@ -13,6 +13,11 @@ module Chat::UserOptionExtension
|
|||||||
@chat_email_frequencies ||= { never: 0, when_away: 1 }
|
@chat_email_frequencies ||= { never: 0, when_away: 1 }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def base.chat_header_indicator_preferences
|
||||||
|
@chat_header_indicator_preferences ||= { all_new: 0, dm_and_mentions: 1, never: 2 }
|
||||||
|
end
|
||||||
|
|
||||||
base.enum :chat_email_frequency, base.chat_email_frequencies, prefix: "send_chat_email"
|
base.enum :chat_email_frequency, base.chat_email_frequencies, prefix: "send_chat_email"
|
||||||
|
base.enum :chat_header_indicator_preference, base.chat_header_indicator_preferences
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -264,6 +264,7 @@ after_initialize do
|
|||||||
UserUpdater::OPTION_ATTR.push(:chat_sound)
|
UserUpdater::OPTION_ATTR.push(:chat_sound)
|
||||||
UserUpdater::OPTION_ATTR.push(:ignore_channel_wide_mention)
|
UserUpdater::OPTION_ATTR.push(:ignore_channel_wide_mention)
|
||||||
UserUpdater::OPTION_ATTR.push(:chat_email_frequency)
|
UserUpdater::OPTION_ATTR.push(:chat_email_frequency)
|
||||||
|
UserUpdater::OPTION_ATTR.push(:chat_header_indicator_preference)
|
||||||
|
|
||||||
register_reviewable_type ReviewableChatMessage
|
register_reviewable_type ReviewableChatMessage
|
||||||
|
|
||||||
@ -475,6 +476,14 @@ after_initialize do
|
|||||||
|
|
||||||
add_to_serializer(:user_option, :chat_email_frequency) { object.chat_email_frequency }
|
add_to_serializer(:user_option, :chat_email_frequency) { object.chat_email_frequency }
|
||||||
|
|
||||||
|
add_to_serializer(:user_option, :chat_header_indicator_preference) do
|
||||||
|
object.chat_header_indicator_preference
|
||||||
|
end
|
||||||
|
|
||||||
|
add_to_serializer(:current_user_option, :chat_header_indicator_preference) do
|
||||||
|
object.chat_header_indicator_preference
|
||||||
|
end
|
||||||
|
|
||||||
RETENTION_SETTINGS_TO_USER_OPTION_FIELDS = {
|
RETENTION_SETTINGS_TO_USER_OPTION_FIELDS = {
|
||||||
chat_channel_retention_days: :dismissed_channel_retention_reminder,
|
chat_channel_retention_days: :dismissed_channel_retention_reminder,
|
||||||
chat_dm_retention_days: :dismissed_dm_retention_reminder,
|
chat_dm_retention_days: :dismissed_dm_retention_reminder,
|
||||||
|
@ -79,6 +79,60 @@ RSpec.describe "Message notifications - with sidebar", type: :system, js: true d
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "when user chat_header_indicator_preference is set to 'never'" do
|
||||||
|
before do
|
||||||
|
current_user.user_option.update!(
|
||||||
|
chat_header_indicator_preference:
|
||||||
|
UserOption.chat_header_indicator_preferences[:never],
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when a message is created" do
|
||||||
|
it "doesn't show any indicator on chat-header-icon" do
|
||||||
|
visit("/")
|
||||||
|
using_session(:user_1) { create_message(channel: channel_1, creator: user_1) }
|
||||||
|
|
||||||
|
expect(page).to have_no_css(".chat-header-icon .chat-channel-unread-indicator")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when user chat_header_indicator_preference is set to 'dm_and_mentions'" do
|
||||||
|
before do
|
||||||
|
current_user.user_option.update!(
|
||||||
|
chat_header_indicator_preference:
|
||||||
|
UserOption.chat_header_indicator_preferences[:dm_and_mentions],
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when a message is created" do
|
||||||
|
it "doesn't show any indicator on chat-header-icon" do
|
||||||
|
visit("/")
|
||||||
|
using_session(:user_1) { create_message(channel: channel_1, creator: user_1) }
|
||||||
|
|
||||||
|
expect(page).to have_no_css(
|
||||||
|
".chat-header-icon .chat-channel-unread-indicator.urgent",
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when a message with a mention is created" do
|
||||||
|
it "does show an indicator on chat-header-icon" do
|
||||||
|
Jobs.run_immediately!
|
||||||
|
|
||||||
|
visit("/")
|
||||||
|
using_session(:user_1) do
|
||||||
|
create_message(
|
||||||
|
text: "hey what's going on @#{current_user.username}?",
|
||||||
|
channel: channel_1,
|
||||||
|
creator: user_1,
|
||||||
|
)
|
||||||
|
end
|
||||||
|
expect(page).to have_css(".chat-header-icon .chat-channel-unread-indicator.urgent")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context "when a message is created" do
|
context "when a message is created" do
|
||||||
it "correctly renders notifications" do
|
it "correctly renders notifications" do
|
||||||
visit("/")
|
visit("/")
|
||||||
|
@ -32,6 +32,17 @@ RSpec.describe "User chat preferences", type: :system, js: true do
|
|||||||
expect(page).to have_css("#user_chat_sounds .select-kit-header[data-value='bell']")
|
expect(page).to have_css("#user_chat_sounds .select-kit-header[data-value='bell']")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "can select header_indicator_preference" do
|
||||||
|
visit("/u/#{current_user.username}/preferences/chat")
|
||||||
|
find("#user_chat_header_indicator_preference .select-kit-header[data-value]").click
|
||||||
|
find("[data-value='dm_and_mentions']").click
|
||||||
|
find(".save-changes").click
|
||||||
|
|
||||||
|
expect(page).to have_css(
|
||||||
|
"#user_chat_header_indicator_preference .select-kit-header[data-value='dm_and_mentions']",
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
context "as an admin on another user's preferences" do
|
context "as an admin on another user's preferences" do
|
||||||
fab!(:current_user) { Fabricate(:admin) }
|
fab!(:current_user) { Fabricate(:admin) }
|
||||||
fab!(:user_1) { Fabricate(:user) }
|
fab!(:user_1) { Fabricate(:user) }
|
||||||
|
Loading…
x
Reference in New Issue
Block a user