FEATURE: allows to enable/disable threading in UI (#22307)
Enabling/Disabling threading has been possible through command line until now. This commit introduces two new UIs: - When creating a channel, it will be available once the category has been selected - On the settings page of a channel for admins
This commit is contained in:
parent
de2febcc0c
commit
ea0b8ca38c
|
@ -1,7 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
CHANNEL_EDITABLE_PARAMS = %i[name description slug]
|
||||
CATEGORY_CHANNEL_EDITABLE_PARAMS = %i[auto_join_users allow_channel_wide_mentions]
|
||||
CATEGORY_CHANNEL_EDITABLE_PARAMS = %i[auto_join_users allow_channel_wide_mentions threading_enabled]
|
||||
|
||||
class Chat::Api::ChannelsController < Chat::ApiController
|
||||
def index
|
||||
|
@ -36,7 +36,14 @@ class Chat::Api::ChannelsController < Chat::ApiController
|
|||
|
||||
def create
|
||||
channel_params =
|
||||
params.require(:channel).permit(:chatable_id, :name, :slug, :description, :auto_join_users)
|
||||
params.require(:channel).permit(
|
||||
:chatable_id,
|
||||
:name,
|
||||
:slug,
|
||||
:description,
|
||||
:auto_join_users,
|
||||
:threading_enabled,
|
||||
)
|
||||
|
||||
# NOTE: We don't allow creating channels for anything but category chatable types
|
||||
# at the moment. This may change in future, at which point we will need to pass in
|
||||
|
|
|
@ -10,6 +10,7 @@ module Chat
|
|||
# description: "This is the best channel",
|
||||
# slug: "super-channel",
|
||||
# category_id: category.id,
|
||||
# threading_enabled: true,
|
||||
# )
|
||||
#
|
||||
class CreateCategoryChannel
|
||||
|
@ -23,6 +24,7 @@ module Chat
|
|||
# @option params_to_create [String] slug
|
||||
# @option params_to_create [Boolean] auto_join_users
|
||||
# @option params_to_create [Integer] category_id
|
||||
# @option params_to_create [Boolean] threading_enabled
|
||||
# @return [Service::Base::Context]
|
||||
|
||||
policy :can_create_channel
|
||||
|
@ -42,8 +44,12 @@ module Chat
|
|||
attribute :slug, :string
|
||||
attribute :category_id, :integer
|
||||
attribute :auto_join_users, :boolean, default: false
|
||||
attribute :threading_enabled, :boolean, default: false
|
||||
|
||||
before_validation { self.auto_join_users = auto_join_users.presence || false }
|
||||
before_validation do
|
||||
self.auto_join_users = auto_join_users.presence || false
|
||||
self.threading_enabled = threading_enabled.presence || false
|
||||
end
|
||||
|
||||
validates :category_id, presence: true
|
||||
validates :name, length: { maximum: SiteSetting.max_topic_title_length }
|
||||
|
@ -70,6 +76,7 @@ module Chat
|
|||
description: contract.description,
|
||||
user_count: 1,
|
||||
auto_join_users: contract.auto_join_users,
|
||||
threading_enabled: contract.threading_enabled,
|
||||
)
|
||||
end
|
||||
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
module Chat
|
||||
# Service responsible for updating a chat channel's name, slug, and description.
|
||||
#
|
||||
# For a CategoryChannel, the settings for auto_join_users and allow_channel_wide_mentions
|
||||
# are also editable.
|
||||
# For a CategoryChannel, the settings for auto_join_users, allow_channel_wide_mentions
|
||||
# and threading_enabled are also editable.
|
||||
#
|
||||
# @example
|
||||
# Service::Chat::UpdateChannel.call(
|
||||
|
@ -13,6 +13,7 @@ module Chat
|
|||
# name: "SuperChannel",
|
||||
# description: "This is the best channel",
|
||||
# slug: "super-channel",
|
||||
# threading_enaled: true,
|
||||
# )
|
||||
#
|
||||
class UpdateChannel
|
||||
|
@ -43,6 +44,7 @@ module Chat
|
|||
attribute :name, :string
|
||||
attribute :description, :string
|
||||
attribute :slug, :string
|
||||
attribute :threading_enabled, :boolean, default: false
|
||||
attribute :auto_join_users, :boolean, default: false
|
||||
attribute :allow_channel_wide_mentions, :boolean, default: true
|
||||
|
||||
|
|
|
@ -1,36 +1,36 @@
|
|||
<div class="chat-form__section">
|
||||
<div class="chat-form__field">
|
||||
<div class="chat-form__field -mute">
|
||||
<label class="chat-form__label">
|
||||
<span>{{i18n "chat.settings.mute"}}</span>
|
||||
<ChatChannelSettingsSavedIndicator
|
||||
@property={{this.channel.currentUserMembership.muted}}
|
||||
@property={{@channel.currentUserMembership.muted}}
|
||||
/>
|
||||
</label>
|
||||
<div class="chat-form__control">
|
||||
<ComboBox
|
||||
@content={{this.mutedOptions}}
|
||||
@value={{this.channel.currentUserMembership.muted}}
|
||||
@value={{@channel.currentUserMembership.muted}}
|
||||
@valueProperty="value"
|
||||
@class="channel-settings-view__muted-selector"
|
||||
@class="channel-settings-view__selector"
|
||||
@onChange={{fn this.saveNotificationSettings "muted" "muted"}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{#unless this.channel.currentUserMembership.muted}}
|
||||
<div class="chat-form__field">
|
||||
{{#unless @channel.currentUserMembership.muted}}
|
||||
<div class="chat-form__field -desktop-notification-level">
|
||||
<label class="chat-form__label">
|
||||
<span>{{i18n "chat.settings.desktop_notification_level"}}</span>
|
||||
<ChatChannelSettingsSavedIndicator
|
||||
@property={{this.channel.currentUserMembership.desktopNotificationLevel}}
|
||||
@property={{@channel.currentUserMembership.desktopNotificationLevel}}
|
||||
/>
|
||||
</label>
|
||||
<div class="chat-form__control">
|
||||
<ComboBox
|
||||
@content={{this.notificationLevels}}
|
||||
@value={{this.channel.currentUserMembership.desktopNotificationLevel}}
|
||||
@value={{@channel.currentUserMembership.desktopNotificationLevel}}
|
||||
@valueProperty="value"
|
||||
@class="channel-settings-view__desktop-notification-level-selector"
|
||||
@class="channel-settings-view__selector"
|
||||
@onChange={{fn
|
||||
this.saveNotificationSettings
|
||||
"desktopNotificationLevel"
|
||||
|
@ -40,19 +40,19 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="chat-form__field">
|
||||
<div class="chat-form__field -mobile-notification-level">
|
||||
<label class="chat-form__label">
|
||||
<span>{{i18n "chat.settings.mobile_notification_level"}}</span>
|
||||
<ChatChannelSettingsSavedIndicator
|
||||
@property={{this.channel.currentUserMembership.mobileNotificationLevel}}
|
||||
@property={{@channel.currentUserMembership.mobileNotificationLevel}}
|
||||
/>
|
||||
</label>
|
||||
<div class="chat-form__control">
|
||||
<ComboBox
|
||||
@content={{this.notificationLevels}}
|
||||
@value={{this.channel.currentUserMembership.mobileNotificationLevel}}
|
||||
@value={{@channel.currentUserMembership.mobileNotificationLevel}}
|
||||
@valueProperty="value"
|
||||
@class="channel-settings-view__mobile-notification-level-selector"
|
||||
@class="channel-settings-view__selector"
|
||||
@onChange={{fn
|
||||
this.saveNotificationSettings
|
||||
"mobileNotificationLevel"
|
||||
|
@ -64,7 +64,7 @@
|
|||
{{/unless}}
|
||||
<div class="chat-retention-info">
|
||||
{{d-icon "info-circle"}}
|
||||
<ChatRetentionReminderText @channel={{this.channel}} />
|
||||
<ChatRetentionReminderText @channel={{@channel}} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -72,28 +72,29 @@
|
|||
<h3 class="chat-form__section-admin-title">
|
||||
{{i18n "chat.settings.admin_title"}}
|
||||
</h3>
|
||||
|
||||
{{#if this.autoJoinAvailable}}
|
||||
<div class="chat-form__section">
|
||||
<div class="chat-form__section -autojoin">
|
||||
<div class="chat-form__field">
|
||||
<label class="chat-form__label">
|
||||
<span>{{i18n "chat.settings.auto_join_users_label"}}</span>
|
||||
<ChatChannelSettingsSavedIndicator
|
||||
@property={{this.channel.autoJoinUsers}}
|
||||
@property={{@channel.autoJoinUsers}}
|
||||
/>
|
||||
</label>
|
||||
<ComboBox
|
||||
@content={{this.autoAddUsersOptions}}
|
||||
@value={{this.channel.autoJoinUsers}}
|
||||
@value={{@channel.autoJoinUsers}}
|
||||
@valueProperty="value"
|
||||
@class="channel-settings-view__auto-join-selector"
|
||||
@class="channel-settings-view__selector"
|
||||
@onChange={{action
|
||||
(fn this.onToggleAutoJoinUsers this.channel.autoJoinUsers)
|
||||
(fn this.onToggleAutoJoinUsers @channel.autoJoinUsers)
|
||||
}}
|
||||
/>
|
||||
<p class="chat-form__description -autojoin">
|
||||
<p class="chat-form__description">
|
||||
{{i18n
|
||||
"chat.settings.auto_join_users_info"
|
||||
category=this.channel.chatable.name
|
||||
category=@channel.chatable.name
|
||||
}}
|
||||
</p>
|
||||
</div>
|
||||
|
@ -101,36 +102,62 @@
|
|||
{{/if}}
|
||||
|
||||
{{#if this.togglingChannelWideMentionsAvailable}}
|
||||
<div class="chat-form__section">
|
||||
<div class="chat-form__section -channel-wide-mentions">
|
||||
<div class="chat-form__field">
|
||||
<label class="chat-form__label">
|
||||
<span>{{i18n "chat.settings.channel_wide_mentions_label"}}</span>
|
||||
<ChatChannelSettingsSavedIndicator
|
||||
@property={{this.channel.allowChannelWideMentions}}
|
||||
@property={{@channel.allowChannelWideMentions}}
|
||||
/>
|
||||
</label>
|
||||
<ComboBox
|
||||
@content={{this.channelWideMentionsOptions}}
|
||||
@value={{this.channel.allowChannelWideMentions}}
|
||||
@value={{@channel.allowChannelWideMentions}}
|
||||
@valueProperty="value"
|
||||
@class="channel-settings-view__channel-wide-mentions-selector"
|
||||
@class="channel-settings-view__selector"
|
||||
@onChange={{this.onToggleChannelWideMentions}}
|
||||
/>
|
||||
<p class="chat-form__description -channel-wide-mentions">
|
||||
<p class="chat-form__description">
|
||||
{{i18n
|
||||
"chat.settings.channel_wide_mentions_description"
|
||||
channel=this.channel.title
|
||||
channel=@channel.title
|
||||
}}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if this.togglingThreadingAvailable}}
|
||||
<div class="chat-form__section -threading">
|
||||
<div class="chat-form__field">
|
||||
<label class="chat-form__label">
|
||||
<span>{{i18n "chat.settings.channel_threading_label"}}</span>
|
||||
<span class="channel-settings-view__channel-threading-tooltip">
|
||||
{{d-icon "info-circle"}}
|
||||
<DTooltip>
|
||||
{{i18n "chat.settings.channel_threading_description"}}
|
||||
</DTooltip>
|
||||
</span>
|
||||
<ChatChannelSettingsSavedIndicator
|
||||
@property={{@channel.threadingEnabled}}
|
||||
/>
|
||||
</label>
|
||||
<ComboBox
|
||||
@content={{this.threadingEnabledOptions}}
|
||||
@value={{@channel.threadingEnabled}}
|
||||
@valueProperty="value"
|
||||
@class="channel-settings-view__selector"
|
||||
@onChange={{this.onToggleThreadingEnabled}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
||||
{{#unless this.channel.isDirectMessageChannel}}
|
||||
{{#unless @channel.isDirectMessageChannel}}
|
||||
<div class="chat-form__section">
|
||||
{{#if (chat-guardian "can-edit-chat-channel")}}
|
||||
{{#if (chat-guardian "can-archive-channel" this.channel)}}
|
||||
{{#if (chat-guardian "can-archive-channel" @channel)}}
|
||||
<div class="chat-form__field">
|
||||
<DButton
|
||||
@action={{action "onArchiveChannel"}}
|
||||
|
@ -141,7 +168,7 @@
|
|||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if this.channel.isClosed}}
|
||||
{{#if @channel.isClosed}}
|
||||
<div class="chat-form__field">
|
||||
<DButton
|
||||
@action={{action "onToggleChannelState"}}
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
import Component from "@ember/component";
|
||||
import { action, computed } from "@ember/object";
|
||||
import Component from "@glimmer/component";
|
||||
import { action } from "@ember/object";
|
||||
import { inject as service } from "@ember/service";
|
||||
import showModal from "discourse/lib/show-modal";
|
||||
import I18n from "I18n";
|
||||
import { reads } from "@ember/object/computed";
|
||||
|
||||
const NOTIFICATION_LEVELS = [
|
||||
{ name: I18n.t("chat.notification_levels.never"), value: "never" },
|
||||
|
@ -21,6 +20,11 @@ const AUTO_ADD_USERS_OPTIONS = [
|
|||
{ name: I18n.t("no_value"), value: false },
|
||||
];
|
||||
|
||||
const THREADING_ENABLED_OPTIONS = [
|
||||
{ name: I18n.t("chat.settings.threading_enabled"), value: true },
|
||||
{ name: I18n.t("chat.settings.threading_disabled"), value: false },
|
||||
];
|
||||
|
||||
const CHANNEL_WIDE_MENTIONS_OPTIONS = [
|
||||
{ name: I18n.t("yes_value"), value: true },
|
||||
{
|
||||
|
@ -33,13 +37,14 @@ export default class ChatChannelSettingsView extends Component {
|
|||
@service chat;
|
||||
@service chatApi;
|
||||
@service chatGuardian;
|
||||
@service currentUser;
|
||||
@service siteSettings;
|
||||
@service router;
|
||||
@service dialog;
|
||||
tagName = "";
|
||||
channel = null;
|
||||
|
||||
notificationLevels = NOTIFICATION_LEVELS;
|
||||
mutedOptions = MUTED_OPTIONS;
|
||||
threadingEnabledOptions = THREADING_ENABLED_OPTIONS;
|
||||
autoAddUsersOptions = AUTO_ADD_USERS_OPTIONS;
|
||||
channelWideMentionsOptions = CHANNEL_WIDE_MENTIONS_OPTIONS;
|
||||
isSavingNotificationSetting = false;
|
||||
|
@ -47,17 +52,25 @@ export default class ChatChannelSettingsView extends Component {
|
|||
savedMobileNotificationLevel = false;
|
||||
savedMuted = false;
|
||||
|
||||
@reads("channel.isCategoryChannel") togglingChannelWideMentionsAvailable;
|
||||
get togglingChannelWideMentionsAvailable() {
|
||||
return this.args.channel.isCategoryChannel;
|
||||
}
|
||||
|
||||
@computed("channel.isCategoryChannel")
|
||||
get autoJoinAvailable() {
|
||||
get togglingThreadingAvailable() {
|
||||
return (
|
||||
this.siteSettings.max_chat_auto_joined_users > 0 &&
|
||||
this.channel.isCategoryChannel
|
||||
this.siteSettings.enable_experimental_chat_threaded_discussions &&
|
||||
this.args.channel.isCategoryChannel &&
|
||||
this.currentUser?.admin
|
||||
);
|
||||
}
|
||||
|
||||
get autoJoinAvailable() {
|
||||
return (
|
||||
this.siteSettings.max_chat_auto_joined_users > 0 &&
|
||||
this.args.channel.isCategoryChannel
|
||||
);
|
||||
}
|
||||
|
||||
@computed("autoJoinAvailable", "togglingChannelWideMentionsAvailable")
|
||||
get adminSectionAvailable() {
|
||||
return (
|
||||
this.chatGuardian.canEditChatChannel() &&
|
||||
|
@ -65,30 +78,29 @@ export default class ChatChannelSettingsView extends Component {
|
|||
);
|
||||
}
|
||||
|
||||
@computed(
|
||||
"siteSettings.chat_allow_archiving_channels",
|
||||
"channel.{isArchived,isReadOnly}"
|
||||
)
|
||||
get canArchiveChannel() {
|
||||
return (
|
||||
this.siteSettings.chat_allow_archiving_channels &&
|
||||
!this.channel.isArchived &&
|
||||
!this.channel.isReadOnly
|
||||
!this.args.channel.isArchived &&
|
||||
!this.args.channel.isReadOnly
|
||||
);
|
||||
}
|
||||
|
||||
@action
|
||||
saveNotificationSettings(frontendKey, backendKey, newValue) {
|
||||
if (this.channel.currentUserMembership[frontendKey] === newValue) {
|
||||
if (this.args.channel.currentUserMembership[frontendKey] === newValue) {
|
||||
return;
|
||||
}
|
||||
|
||||
const settings = {};
|
||||
settings[backendKey] = newValue;
|
||||
return this.chatApi
|
||||
.updateCurrentUserChannelNotificationsSettings(this.channel.id, settings)
|
||||
.updateCurrentUserChannelNotificationsSettings(
|
||||
this.args.channel.id,
|
||||
settings
|
||||
)
|
||||
.then((result) => {
|
||||
this.channel.currentUserMembership[frontendKey] =
|
||||
this.args.channel.currentUserMembership[frontendKey] =
|
||||
result.membership[backendKey];
|
||||
});
|
||||
}
|
||||
|
@ -96,76 +108,89 @@ export default class ChatChannelSettingsView extends Component {
|
|||
@action
|
||||
onArchiveChannel() {
|
||||
const controller = showModal("chat-channel-archive-modal");
|
||||
controller.set("chatChannel", this.channel);
|
||||
controller.set("chatChannel", this.args.channel);
|
||||
}
|
||||
|
||||
@action
|
||||
onDeleteChannel() {
|
||||
const controller = showModal("chat-channel-delete-modal");
|
||||
controller.set("chatChannel", this.channel);
|
||||
controller.set("chatChannel", this.args.channel);
|
||||
}
|
||||
|
||||
@action
|
||||
onToggleChannelState() {
|
||||
const controller = showModal("chat-channel-toggle");
|
||||
controller.set("chatChannel", this.channel);
|
||||
controller.set("chatChannel", this.args.channel);
|
||||
}
|
||||
|
||||
@action
|
||||
onToggleAutoJoinUsers() {
|
||||
if (!this.channel.autoJoinUsers) {
|
||||
if (!this.args.channel.autoJoinUsers) {
|
||||
this.onEnableAutoJoinUsers();
|
||||
} else {
|
||||
this.onDisableAutoJoinUsers();
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
onToggleThreadingEnabled(value) {
|
||||
return this._updateChannelProperty(
|
||||
this.args.channel,
|
||||
"threading_enabled",
|
||||
value
|
||||
).then((result) => {
|
||||
this.args.channel.threadingEnabled = result.channel.threading_enabled;
|
||||
});
|
||||
}
|
||||
|
||||
@action
|
||||
onToggleChannelWideMentions() {
|
||||
const newValue = !this.channel.allowChannelWideMentions;
|
||||
if (this.channel.allowChannelWideMentions === newValue) {
|
||||
const newValue = !this.args.channel.allowChannelWideMentions;
|
||||
if (this.args.channel.allowChannelWideMentions === newValue) {
|
||||
return;
|
||||
}
|
||||
|
||||
return this._updateChannelProperty(
|
||||
this.channel,
|
||||
this.args.channel,
|
||||
"allow_channel_wide_mentions",
|
||||
newValue
|
||||
).then((result) => {
|
||||
this.channel.allowChannelWideMentions =
|
||||
this.args.channel.allowChannelWideMentions =
|
||||
result.channel.allow_channel_wide_mentions;
|
||||
});
|
||||
}
|
||||
|
||||
onDisableAutoJoinUsers() {
|
||||
if (this.channel.autoJoinUsers === false) {
|
||||
if (this.args.channel.autoJoinUsers === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
return this._updateChannelProperty(
|
||||
this.channel,
|
||||
this.args.channel,
|
||||
"auto_join_users",
|
||||
false
|
||||
).then((result) => {
|
||||
this.channel.autoJoinUsers = result.channel.auto_join_users;
|
||||
this.args.channel.autoJoinUsers = result.channel.auto_join_users;
|
||||
});
|
||||
}
|
||||
|
||||
onEnableAutoJoinUsers() {
|
||||
if (this.channel.autoJoinUsers === true) {
|
||||
if (this.args.channel.autoJoinUsers === true) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.dialog.confirm({
|
||||
message: I18n.t("chat.settings.auto_join_users_warning", {
|
||||
category: this.channel.chatable.name,
|
||||
category: this.args.channel.chatable.name,
|
||||
}),
|
||||
didConfirm: () =>
|
||||
this._updateChannelProperty(this.channel, "auto_join_users", true).then(
|
||||
(result) => {
|
||||
this.channel.autoJoinUsers = result.channel.auto_join_users;
|
||||
}
|
||||
),
|
||||
this._updateChannelProperty(
|
||||
this.args.channel,
|
||||
"auto_join_users",
|
||||
true
|
||||
).then((result) => {
|
||||
this.args.channel.autoJoinUsers = result.channel.auto_join_users;
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,8 @@ export default class CreateChannelController extends Controller.extend(
|
|||
@service chatChannelsManager;
|
||||
@service chatApi;
|
||||
@service router;
|
||||
@service currentUser;
|
||||
@service siteSettings;
|
||||
|
||||
category = null;
|
||||
categoryId = null;
|
||||
|
@ -37,10 +39,18 @@ export default class CreateChannelController extends Controller.extend(
|
|||
autoJoinUsers = false;
|
||||
autoJoinWarning = "";
|
||||
loadingPermissionHint = false;
|
||||
threadingEnabled = false;
|
||||
|
||||
@notEmpty("category") categorySelected;
|
||||
@gt("siteSettings.max_chat_auto_joined_users", 0) autoJoinAvailable;
|
||||
|
||||
get threadingAvailable() {
|
||||
return (
|
||||
this.siteSettings.enable_experimental_chat_threaded_discussions &&
|
||||
this.categorySelected
|
||||
);
|
||||
}
|
||||
|
||||
@computed("categorySelected", "name")
|
||||
get createDisabled() {
|
||||
return !this.categorySelected || isBlank(this.name);
|
||||
|
@ -78,6 +88,7 @@ export default class CreateChannelController extends Controller.extend(
|
|||
slug: this.slug || this.autoGeneratedSlug,
|
||||
description: this.description,
|
||||
auto_join_users: this.autoJoinUsers,
|
||||
threading_enabled: this.threadingEnabled,
|
||||
};
|
||||
|
||||
return this.chatApi
|
||||
|
|
|
@ -1,50 +1,50 @@
|
|||
<DModalBody @title="chat.create_channel.title">
|
||||
<div class="create-channel-control">
|
||||
<label for="channel-name" class="create-channel-label">
|
||||
<div class="create-channel__control -name">
|
||||
<label for="channel-name" class="create-channel__label">
|
||||
{{i18n "chat.create_channel.name"}}
|
||||
</label>
|
||||
<Input
|
||||
name="channel-name"
|
||||
class="create-channel-name-input"
|
||||
class="create-channel__input"
|
||||
@type="text"
|
||||
@value={{this.name}}
|
||||
{{on "input" (action "onNameChange" value="target.value")}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="create-channel-control">
|
||||
<label for="channel-slug" class="create-channel-label">
|
||||
<div class="create-channel__control -slug">
|
||||
<label for="channel-slug" class="create-channel__label">
|
||||
{{i18n "chat.create_channel.slug"}}
|
||||
<span>
|
||||
{{d-icon "info-circle"}}
|
||||
<DTooltip>{{i18n
|
||||
"chat.channel_edit_name_slug_modal.slug_description"
|
||||
}}</DTooltip>
|
||||
<DTooltip>
|
||||
{{i18n "chat.channel_edit_name_slug_modal.slug_description"}}
|
||||
</DTooltip>
|
||||
</span>
|
||||
</label>
|
||||
<Input
|
||||
name="channel-slug"
|
||||
class="create-channel-slug-input"
|
||||
class="create-channel__input"
|
||||
@type="text"
|
||||
@value={{this.slug}}
|
||||
placeholder={{this.autoGeneratedSlug}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="create-channel-control">
|
||||
<label for="channel-description" class="create-channel-label">
|
||||
<div class="create-channel__control -description">
|
||||
<label for="channel-description" class="create-channel__label">
|
||||
{{i18n "chat.create_channel.description"}}
|
||||
</label>
|
||||
<Input
|
||||
name="channel-description"
|
||||
class="create-channel-description-input"
|
||||
class="create-channel__input"
|
||||
@type="textarea"
|
||||
@value={{this.description}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="create-channel-control">
|
||||
<label class="create-channel-label">
|
||||
<div class="create-channel__control">
|
||||
<label class="create-channel__label">
|
||||
{{i18n "chat.create_channel.choose_category.label"}}
|
||||
</label>
|
||||
<CategoryChooser
|
||||
|
@ -56,7 +56,7 @@
|
|||
{{#if this.categoryPermissionsHint}}
|
||||
<div
|
||||
class={{concat-class
|
||||
"create-channel-hint"
|
||||
"create-channel__hint"
|
||||
(if this.loadingPermissionHint "loading-permissions")
|
||||
}}
|
||||
>
|
||||
|
@ -66,14 +66,14 @@
|
|||
</div>
|
||||
|
||||
{{#if this.autoJoinAvailable}}
|
||||
<div class="create-channel-control">
|
||||
<label class="create-channel-label">
|
||||
<div class="create-channel__control -auto-join">
|
||||
<label class="create-channel__label">
|
||||
<Input @type="checkbox" @checked={{this.autoJoinUsers}} />
|
||||
<div class="auto-join-channel">
|
||||
<span class="auto-join-channel__label">
|
||||
<span class="create-channel__label-title">
|
||||
{{i18n "chat.settings.auto_join_users_label"}}
|
||||
</span>
|
||||
<p class="auto-join-channel__description">
|
||||
<p class="create-channel__label-description">
|
||||
{{#if this.categoryName}}
|
||||
{{i18n
|
||||
"chat.settings.auto_join_users_info"
|
||||
|
@ -87,6 +87,22 @@
|
|||
</label>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if this.threadingAvailable}}
|
||||
<div class="create-channel__control -threading-toggle">
|
||||
<label class="create-channel__label">
|
||||
<Input @type="checkbox" @checked={{this.threadingEnabled}} />
|
||||
<div class="threading-channel">
|
||||
<span class="create-channel__label-title">
|
||||
{{i18n "chat.create_channel.threading.label"}}
|
||||
</span>
|
||||
<p class="create-channel__label-description">
|
||||
{{i18n "chat.settings.channel_threading_description"}}
|
||||
</p>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
{{/if}}
|
||||
</DModalBody>
|
||||
|
||||
<div class="modal-footer">
|
||||
|
|
|
@ -37,14 +37,17 @@
|
|||
font-size: var(--font-down-2);
|
||||
}
|
||||
|
||||
.channel-settings-view__desktop-notification-level-selector,
|
||||
.channel-settings-view__mobile-notification-level-selector,
|
||||
.channel-settings-view__muted-selector,
|
||||
.channel-settings-view__auto-join-selector,
|
||||
.channel-settings-view__channel-wide-mentions-selector {
|
||||
.channel-settings-view__selector {
|
||||
width: 220px;
|
||||
}
|
||||
|
||||
.channel-settings-view__channel-threading-tooltip {
|
||||
padding-left: 0.25rem;
|
||||
color: var(--tertiary);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.channel-settings-view__muted-selector,
|
||||
.chat-form__btn.delete-btn {
|
||||
.d-icon {
|
||||
color: var(--danger);
|
||||
|
|
|
@ -9,9 +9,7 @@
|
|||
}
|
||||
|
||||
.select-kit.combo-box,
|
||||
.create-channel-name-input,
|
||||
.create-channel-slug-input,
|
||||
.create-channel-description-input,
|
||||
.create-channel__input,
|
||||
#choose-topic-title {
|
||||
width: 100%;
|
||||
margin-bottom: 0;
|
||||
|
@ -24,23 +22,21 @@
|
|||
}
|
||||
}
|
||||
|
||||
.create-channel-hint {
|
||||
.create-channel__hint {
|
||||
font-size: var(--font-down-1);
|
||||
padding-top: 0.25rem;
|
||||
color: var(--secondary-low);
|
||||
}
|
||||
|
||||
.create-channel-control,
|
||||
.create-channel__control,
|
||||
.edit-channel-control {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.auto-join-channel {
|
||||
&__description {
|
||||
.create-channel__label-description {
|
||||
margin: 0;
|
||||
padding-top: 0.25rem;
|
||||
color: var(--secondary-low);
|
||||
font-size: var(--font-down-1) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -354,6 +354,8 @@ en:
|
|||
other: "%{count} members"
|
||||
|
||||
create_channel:
|
||||
threading:
|
||||
label: "Enable threading"
|
||||
auto_join_users:
|
||||
public_category_warning: "%{category} is a public category. Automatically add all recently active users to this channel?"
|
||||
warning_1_group:
|
||||
|
@ -431,6 +433,8 @@ en:
|
|||
settings:
|
||||
channel_wide_mentions_label: "Allow @all and @here mentions"
|
||||
channel_wide_mentions_description: "Allow users to notify all members of #%{channel} with @all or only those who are active in the moment with @here"
|
||||
channel_threading_label: "Threading"
|
||||
channel_threading_description: "When threading is enabled, replies to a chat message will create a separate conversation, which will exist alongside the main channel."
|
||||
auto_join_users_label: "Automatically add users"
|
||||
auto_join_users_info: "Check hourly which users have been active in the last 3 months. Add them to this channel if they have access to the %{category} category."
|
||||
auto_join_users_info_no_category: "Check hourly which users have been active in the last 3 months. Add them to this channel if they have access to the selected category."
|
||||
|
@ -440,6 +444,8 @@ en:
|
|||
followed: "Joined"
|
||||
mobile_notification_level: "Mobile push notifications"
|
||||
mute: "Mute channel"
|
||||
threading_enabled: "Enabled"
|
||||
threading_disabled: "Disabled"
|
||||
muted_on: "On"
|
||||
muted_off: "Off"
|
||||
notifications: "Notifications"
|
||||
|
|
|
@ -629,6 +629,7 @@ RSpec.describe Chat::Api::ChannelsController do
|
|||
chatable_id: category.id,
|
||||
name: "channel name",
|
||||
description: "My new channel",
|
||||
threading_enabled: false,
|
||||
},
|
||||
}
|
||||
end
|
||||
|
@ -691,6 +692,25 @@ RSpec.describe Chat::Api::ChannelsController do
|
|||
expect(new_channel.auto_join_users).to eq(true)
|
||||
end
|
||||
|
||||
it "creates a channel sets threading_enabled to false by default" do
|
||||
post "/chat/api/channels", params: params
|
||||
expect(response.status).to eq(200)
|
||||
|
||||
new_channel = Chat::Channel.find(response.parsed_body.dig("channel", "id"))
|
||||
|
||||
expect(new_channel.threading_enabled).to eq(false)
|
||||
end
|
||||
|
||||
it "creates a channel with threading_enabled set to true" do
|
||||
params[:channel][:threading_enabled] = true
|
||||
post "/chat/api/channels", params: params
|
||||
expect(response.status).to eq(200)
|
||||
|
||||
new_channel = Chat::Channel.find(response.parsed_body.dig("channel", "id"))
|
||||
|
||||
expect(new_channel.threading_enabled).to eq(true)
|
||||
end
|
||||
|
||||
describe "triggers the auto-join process" do
|
||||
fab!(:chatters_group) { Fabricate(:group) }
|
||||
fab!(:user) { Fabricate(:user, last_seen_at: 15.minute.ago) }
|
||||
|
@ -884,6 +904,18 @@ RSpec.describe Chat::Api::ChannelsController do
|
|||
expect(response.parsed_body["channel"]).to match_response_schema("category_chat_channel")
|
||||
end
|
||||
|
||||
describe "when updating threading_enabled" do
|
||||
before { SiteSetting.enable_experimental_chat_threaded_discussions = true }
|
||||
|
||||
it "sets the new value" do
|
||||
expect {
|
||||
put "/chat/api/channels/#{channel.id}", params: { channel: { threading_enabled: true } }
|
||||
}.to change { channel.reload.threading_enabled }.from(false).to(true)
|
||||
|
||||
expect(response.parsed_body["channel"]["threading_enabled"]).to eq(true)
|
||||
end
|
||||
end
|
||||
|
||||
describe "when updating allow_channel_wide_mentions" do
|
||||
it "sets the new value" do
|
||||
put "/chat/api/channels/#{channel.id}",
|
||||
|
|
|
@ -93,6 +93,29 @@ RSpec.describe Chat::CreateCategoryChannel do
|
|||
result
|
||||
end
|
||||
end
|
||||
|
||||
describe "threading_enabled" do
|
||||
context "when true" do
|
||||
it "sets threading_enabled to true" do
|
||||
params[:threading_enabled] = true
|
||||
expect(result.channel.threading_enabled).to eq(true)
|
||||
end
|
||||
end
|
||||
|
||||
context "when blank" do
|
||||
it "sets threading_enabled to false" do
|
||||
params[:threading_enabled] = nil
|
||||
expect(result.channel.threading_enabled).to eq(false)
|
||||
end
|
||||
end
|
||||
|
||||
context "when false" do
|
||||
it "sets threading_enabled to false" do
|
||||
params[:threading_enabled] = false
|
||||
expect(result.channel.threading_enabled).to eq(false)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -63,7 +63,8 @@ RSpec.describe Chat::UpdateChannel do
|
|||
)
|
||||
end
|
||||
|
||||
context "when the name is blank" do
|
||||
describe "name" do
|
||||
context "when blank" do
|
||||
before { params[:name] = "" }
|
||||
|
||||
it "nils out the name" do
|
||||
|
@ -71,8 +72,10 @@ RSpec.describe Chat::UpdateChannel do
|
|||
expect(channel.reload.name).to be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "when the description is blank" do
|
||||
describe "description" do
|
||||
context "when blank" do
|
||||
before do
|
||||
channel.update!(description: "something")
|
||||
params[:description] = ""
|
||||
|
@ -83,8 +86,10 @@ RSpec.describe Chat::UpdateChannel do
|
|||
expect(channel.reload.description).to be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "when auto_join_users is set to 'true'" do
|
||||
describe "#auto_join_users" do
|
||||
context "when set to 'true'" do
|
||||
before do
|
||||
channel.update!(auto_join_users: false)
|
||||
params[:auto_join_users] = true
|
||||
|
@ -105,5 +110,28 @@ RSpec.describe Chat::UpdateChannel do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "threading_enabled" do
|
||||
context "when true" do
|
||||
it "changes the value to true" do
|
||||
expect {
|
||||
params[:threading_enabled] = true
|
||||
result
|
||||
}.to change { channel.reload.threading_enabled }.from(false).to(true)
|
||||
end
|
||||
end
|
||||
|
||||
context "when false" do
|
||||
it "changes the value to true" do
|
||||
channel.update!(threading_enabled: true)
|
||||
|
||||
expect {
|
||||
params[:threading_enabled] = false
|
||||
result
|
||||
}.to change { channel.reload.threading_enabled }.from(true).to(false)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -56,7 +56,7 @@ RSpec.describe "Channel - Info - Settings page", type: :system do
|
|||
context "as a member" do
|
||||
before { channel_1.add(current_user) }
|
||||
|
||||
context "when visitng the settings of a recently joined channel" do
|
||||
context "when visiting the settings of a recently joined channel" do
|
||||
fab!(:channel_2) { Fabricate(:category_channel) }
|
||||
|
||||
it "is correctly populated" do
|
||||
|
@ -82,8 +82,11 @@ RSpec.describe "Channel - Info - Settings page", type: :system do
|
|||
membership = channel_1.membership_for(current_user)
|
||||
|
||||
expect {
|
||||
find(".channel-settings-view__muted-selector").click
|
||||
find(".channel-settings-view__muted-selector [data-name='On']").click
|
||||
select_kit =
|
||||
PageObjects::Components::SelectKit.new(".-mute .channel-settings-view__selector")
|
||||
select_kit.expand
|
||||
select_kit.select_row_by_name("On")
|
||||
|
||||
expect(page).to have_content(I18n.t("js.chat.settings.saved"))
|
||||
}.to change { membership.reload.muted }.from(false).to(true)
|
||||
end
|
||||
|
@ -93,10 +96,13 @@ RSpec.describe "Channel - Info - Settings page", type: :system do
|
|||
membership = channel_1.membership_for(current_user)
|
||||
|
||||
expect {
|
||||
find(".channel-settings-view__desktop-notification-level-selector").click
|
||||
find(
|
||||
".channel-settings-view__desktop-notification-level-selector [data-name='Never']",
|
||||
).click
|
||||
select_kit =
|
||||
PageObjects::Components::SelectKit.new(
|
||||
".-desktop-notification-level .channel-settings-view__selector",
|
||||
)
|
||||
select_kit.expand
|
||||
select_kit.select_row_by_name("Never")
|
||||
|
||||
expect(page).to have_content(I18n.t("js.chat.settings.saved"))
|
||||
}.to change { membership.reload.desktop_notification_level }.from("mention").to("never")
|
||||
end
|
||||
|
@ -106,10 +112,13 @@ RSpec.describe "Channel - Info - Settings page", type: :system do
|
|||
membership = channel_1.membership_for(current_user)
|
||||
|
||||
expect {
|
||||
find(".channel-settings-view__mobile-notification-level-selector").click
|
||||
find(
|
||||
".channel-settings-view__mobile-notification-level-selector [data-name='Never']",
|
||||
).click
|
||||
select_kit =
|
||||
PageObjects::Components::SelectKit.new(
|
||||
".-mobile-notification-level .channel-settings-view__selector",
|
||||
)
|
||||
select_kit.expand
|
||||
select_kit.select_row_by_name("Never")
|
||||
|
||||
expect(page).to have_content(I18n.t("js.chat.settings.saved"))
|
||||
}.to change { membership.reload.mobile_notification_level }.from("mention").to("never")
|
||||
end
|
||||
|
@ -133,9 +142,12 @@ RSpec.describe "Channel - Info - Settings page", type: :system do
|
|||
chat_page.visit_channel_settings(channel_1)
|
||||
|
||||
expect {
|
||||
find(".channel-settings-view__auto-join-selector").click
|
||||
find(".channel-settings-view__auto-join-selector [data-name='Yes']").click
|
||||
select_kit =
|
||||
PageObjects::Components::SelectKit.new(".-autojoin .channel-settings-view__selector")
|
||||
select_kit.expand
|
||||
select_kit.select_row_by_name("Yes")
|
||||
find("#dialog-holder .btn-primary").click
|
||||
|
||||
expect(page).to have_content(I18n.t("js.chat.settings.saved"))
|
||||
}.to change { channel_1.reload.auto_join_users }.from(false).to(true)
|
||||
end
|
||||
|
@ -144,8 +156,13 @@ RSpec.describe "Channel - Info - Settings page", type: :system do
|
|||
chat_page.visit_channel_settings(channel_1)
|
||||
|
||||
expect {
|
||||
find(".channel-settings-view__channel-wide-mentions-selector").click
|
||||
find(".channel-settings-view__channel-wide-mentions-selector [data-name='No']").click
|
||||
select_kit =
|
||||
PageObjects::Components::SelectKit.new(
|
||||
".-channel-wide-mentions .channel-settings-view__selector",
|
||||
)
|
||||
select_kit.expand
|
||||
select_kit.select_row_by_name("No")
|
||||
|
||||
expect(page).to have_content(I18n.t("js.chat.settings.saved"))
|
||||
}.to change { channel_1.reload.allow_channel_wide_mentions }.from(true).to(false)
|
||||
end
|
||||
|
@ -160,6 +177,19 @@ RSpec.describe "Channel - Info - Settings page", type: :system do
|
|||
}.to change { channel_1.reload.status }.from("open").to("closed")
|
||||
end
|
||||
|
||||
it "can enable threading" do
|
||||
SiteSetting.enable_experimental_chat_threaded_discussions = true
|
||||
chat_page.visit_channel_settings(channel_1)
|
||||
|
||||
expect {
|
||||
select_kit =
|
||||
PageObjects::Components::SelectKit.new(".-threading .channel-settings-view__selector")
|
||||
select_kit.expand
|
||||
select_kit.select_row_by_name("Enabled")
|
||||
expect(page).to have_content(I18n.t("js.chat.settings.saved"))
|
||||
}.to change { channel_1.reload.threading_enabled }.from(false).to(true)
|
||||
end
|
||||
|
||||
it "can delete channel" do
|
||||
chat_page.visit_channel_settings(channel_1)
|
||||
|
||||
|
|
|
@ -32,6 +32,16 @@ RSpec.describe "Create channel", type: :system do
|
|||
expect(channel_modal).to have_create_hint(Group[:everyone].name)
|
||||
end
|
||||
|
||||
it "shows threading toggle" do
|
||||
SiteSetting.enable_experimental_chat_threaded_discussions = true
|
||||
|
||||
chat_page.visit_browse
|
||||
chat_page.new_channel_button.click
|
||||
channel_modal.select_category(category_1)
|
||||
|
||||
expect(channel_modal).to have_threading_toggle
|
||||
end
|
||||
|
||||
it "does not override channel name if that was already specified" do
|
||||
chat_page.visit_browse
|
||||
chat_page.new_channel_button.click
|
||||
|
@ -138,7 +148,7 @@ RSpec.describe "Create channel", type: :system do
|
|||
context "for a public category" do
|
||||
before do
|
||||
channel_modal.select_category(category_1)
|
||||
find(".auto-join-channel__label").click
|
||||
find(".-auto-join .create-channel__label").click
|
||||
channel_modal.click_primary_button
|
||||
end
|
||||
|
||||
|
@ -175,7 +185,7 @@ RSpec.describe "Create channel", type: :system do
|
|||
before do
|
||||
group_1.add(user_1)
|
||||
channel_modal.select_category(private_category)
|
||||
find(".auto-join-channel__label").click
|
||||
find(".-auto-join .create-channel__label").click
|
||||
channel_modal.click_primary_button
|
||||
end
|
||||
|
||||
|
|
|
@ -9,17 +9,21 @@ module PageObjects
|
|||
end
|
||||
|
||||
def create_channel_hint
|
||||
find(".create-channel-hint")
|
||||
find(".create-channel__hint")
|
||||
end
|
||||
|
||||
def slug_input
|
||||
find(".create-channel-slug-input")
|
||||
find(".-slug .create-channel__input")
|
||||
end
|
||||
|
||||
def has_create_hint?(content)
|
||||
create_channel_hint.has_content?(content)
|
||||
end
|
||||
|
||||
def has_threading_toggle?
|
||||
has_selector?(".create-channel__control.-threading-toggle")
|
||||
end
|
||||
|
||||
def fill_name(name)
|
||||
fill_in("channel-name", with: name)
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue