diff --git a/app/assets/javascripts/discourse/app/components/sidebar/switch-panel-buttons.hbs b/app/assets/javascripts/discourse/app/components/sidebar/switch-panel-buttons.hbs index e558957c56cba6..214eec48cc68f9 100644 --- a/app/assets/javascripts/discourse/app/components/sidebar/switch-panel-buttons.hbs +++ b/app/assets/javascripts/discourse/app/components/sidebar/switch-panel-buttons.hbs @@ -5,5 +5,6 @@ @icon={{button.switchButtonIcon}} @disabled={{this.isSwitching}} @translatedLabel={{button.switchButtonLabel}} + data-key={{button.key}} /> {{/each}} \ No newline at end of file diff --git a/app/assets/javascripts/discourse/app/components/sidebar/switch-panel-buttons.js b/app/assets/javascripts/discourse/app/components/sidebar/switch-panel-buttons.js index 329bf69863e3d1..613de5909d2fd4 100644 --- a/app/assets/javascripts/discourse/app/components/sidebar/switch-panel-buttons.js +++ b/app/assets/javascripts/discourse/app/components/sidebar/switch-panel-buttons.js @@ -16,9 +16,13 @@ export default class SwitchPanelButtons extends Component { const url = panel.lastKnownURL || panel.switchButtonDefaultUrl; const destination = url === "/" ? `discovery.${defaultHomepage()}` : url; - this.router.transitionTo(destination).finally(() => { - this.isSwitching = false; - this.sidebarState.setPanel(panel.key); - }); + this.router + .transitionTo(destination) + .then(() => { + this.sidebarState.setPanel(panel.key); + }) + .finally(() => { + this.isSwitching = false; + }); } } diff --git a/app/models/user_option.rb b/app/models/user_option.rb index 87232465f5d457..1fb652a271f685 100644 --- a/app/models/user_option.rb +++ b/app/models/user_option.rb @@ -292,6 +292,7 @@ def update_tracked_topics # sidebar_link_to_filtered_list :boolean default(FALSE), not null # sidebar_show_count_of_new_items :boolean default(FALSE), not null # watched_precedence_over_muted :boolean +# chat_separate_sidebar_mode :integer default(0), not null # # Indexes # diff --git a/plugins/chat/app/models/chat/separate_sidebar_mode_site_setting.rb b/plugins/chat/app/models/chat/separate_sidebar_mode_site_setting.rb new file mode 100644 index 00000000000000..f435457acfdb60 --- /dev/null +++ b/plugins/chat/app/models/chat/separate_sidebar_mode_site_setting.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +module Chat + class SeparateSidebarModeSiteSetting < EnumSiteSetting + def self.valid_value?(val) + values.any? { |v| v[:value] == val } + end + + def self.values + @values ||= [ + { name: "admin.site_settings.chat_separate_sidebar_mode.never", value: "never" }, + { name: "admin.site_settings.chat_separate_sidebar_mode.always", value: "always" }, + { name: "admin.site_settings.chat_separate_sidebar_mode.fullscreen", value: "fullscreen" }, + ] + end + + def self.translate_names? + true + end + end +end diff --git a/plugins/chat/assets/javascripts/discourse/components/chat-drawer.js b/plugins/chat/assets/javascripts/discourse/components/chat-drawer.js index 7732db38cff3eb..543143d4689709 100644 --- a/plugins/chat/assets/javascripts/discourse/components/chat-drawer.js +++ b/plugins/chat/assets/javascripts/discourse/components/chat-drawer.js @@ -171,8 +171,8 @@ export default Component.extend({ @action openURL(url = null) { this.chat.activeChannel = null; - this.chatStateManager.didOpenDrawer(url); this.chatDrawerRouter.stateFor(this._routeFromURL(url)); + this.chatStateManager.didOpenDrawer(url); }, _routeFromURL(url) { diff --git a/plugins/chat/assets/javascripts/discourse/components/chat/header/icon.hbs b/plugins/chat/assets/javascripts/discourse/components/chat/header/icon.hbs index 00fb2474a4fcd7..3fd922ddef2b5a 100644 --- a/plugins/chat/assets/javascripts/discourse/components/chat/header/icon.hbs +++ b/plugins/chat/assets/javascripts/discourse/components/chat/header/icon.hbs @@ -2,8 +2,9 @@ href={{this.href}} tabindex="0" class={{concat-class "icon" "btn-flat" (if this.isActive "active")}} + title={{i18n this.title}} > - {{d-icon "d-chat"}} + {{d-icon this.icon}} {{#unless this.currentUserInDnD}} { + api.addSidebarPanel( + (BaseCustomSidebarPanel) => + class ChatSidebarPanel extends BaseCustomSidebarPanel { + key = "chat"; + switchButtonLabel = I18n.t("sidebar.panels.chat.label"); + switchButtonIcon = "d-chat"; + switchButtonDefaultUrl = getURL("/chat"); + } + ); + }); + withPluginApi("1.3.0", (api) => { if (this.siteSettings.enable_public_channels) { api.addSidebarSection( @@ -180,7 +193,8 @@ export default { }; return SidebarChatChannelsSection; - } + }, + "chat" ); } @@ -414,7 +428,8 @@ export default { }; return SidebarChatDirectMessagesSection; - } + }, + "chat" ); }); }, diff --git a/plugins/chat/assets/javascripts/discourse/initializers/chat-user-options.js b/plugins/chat/assets/javascripts/discourse/initializers/chat-user-options.js index c410763d71334e..5fdc01b7fd57b8 100644 --- a/plugins/chat/assets/javascripts/discourse/initializers/chat-user-options.js +++ b/plugins/chat/assets/javascripts/discourse/initializers/chat-user-options.js @@ -6,6 +6,7 @@ const IGNORE_CHANNEL_WIDE_MENTION = "ignore_channel_wide_mention"; const CHAT_SOUND = "chat_sound"; const CHAT_EMAIL_FREQUENCY = "chat_email_frequency"; const CHAT_HEADER_INDICATOR_PREFERENCE = "chat_header_indicator_preference"; +const CHAT_SEPARATE_SIDEBAR_MODE = "chat_separate_sidebar_mode"; export default { name: "chat-user-options", @@ -20,6 +21,7 @@ export default { api.addSaveableUserOptionField(CHAT_SOUND); api.addSaveableUserOptionField(CHAT_EMAIL_FREQUENCY); api.addSaveableUserOptionField(CHAT_HEADER_INDICATOR_PREFERENCE); + api.addSaveableUserOptionField(CHAT_SEPARATE_SIDEBAR_MODE); } }); }, diff --git a/plugins/chat/assets/javascripts/discourse/lib/get-user-chat-separate-sidebar-mode.js b/plugins/chat/assets/javascripts/discourse/lib/get-user-chat-separate-sidebar-mode.js new file mode 100644 index 00000000000000..456f364b15aabc --- /dev/null +++ b/plugins/chat/assets/javascripts/discourse/lib/get-user-chat-separate-sidebar-mode.js @@ -0,0 +1,9 @@ +export function getUserChatSeparateSidebarMode(user) { + const mode = user?.get("user_option.chat_separate_sidebar_mode"); + + return { + never: "never" === mode, + always: "always" === mode, + fullscreen: "fullscreen" === mode, + }; +} diff --git a/plugins/chat/assets/javascripts/discourse/routes/chat.js b/plugins/chat/assets/javascripts/discourse/routes/chat.js index cae606d06b2156..3186d64d233b00 100644 --- a/plugins/chat/assets/javascripts/discourse/routes/chat.js +++ b/plugins/chat/assets/javascripts/discourse/routes/chat.js @@ -4,11 +4,13 @@ import { defaultHomepage } from "discourse/lib/utilities"; import { inject as service } from "@ember/service"; import { scrollTop } from "discourse/mixins/scroll-top"; import { schedule } from "@ember/runloop"; - +import { withPluginApi } from "discourse/lib/plugin-api"; +import { getUserChatSeparateSidebarMode } from "discourse/plugins/chat/discourse/lib/get-user-chat-separate-sidebar-mode"; export default class ChatRoute extends DiscourseRoute { @service chat; @service router; @service chatStateManager; + @service currentUser; titleToken() { return I18n.t("chat.title_capitalized"); @@ -57,6 +59,16 @@ export default class ChatRoute extends DiscourseRoute { } activate() { + withPluginApi("1.8.0", (api) => { + api.setSidebarPanel("chat"); + if (getUserChatSeparateSidebarMode(this.currentUser).never) { + api.setCombinedSidebarMode(); + api.hideSidebarSwitchPanelButtons(); + } else { + api.setSeparatedSidebarMode(); + } + }); + this.chatStateManager.storeAppURL(); this.chat.updatePresence(); @@ -68,6 +80,23 @@ export default class ChatRoute extends DiscourseRoute { } deactivate(transition) { + withPluginApi("1.8.0", (api) => { + api.setSidebarPanel("main"); + + const chatSeparateSidebarMode = getUserChatSeparateSidebarMode( + this.currentUser + ); + if (chatSeparateSidebarMode.fullscreen) { + api.setCombinedSidebarMode(); + api.showSidebarSwitchPanelButtons(); + } else if (chatSeparateSidebarMode.always) { + api.setSeparatedSidebarMode(); + } else { + api.setCombinedSidebarMode(); + api.hideSidebarSwitchPanelButtons(); + } + }); + if (transition) { const url = this.router.urlFor(transition.from.name); this.chatStateManager.storeChatURL(url); diff --git a/plugins/chat/assets/javascripts/discourse/services/chat-state-manager.js b/plugins/chat/assets/javascripts/discourse/services/chat-state-manager.js index 88608e1a41dd04..c1956798632b71 100644 --- a/plugins/chat/assets/javascripts/discourse/services/chat-state-manager.js +++ b/plugins/chat/assets/javascripts/discourse/services/chat-state-manager.js @@ -4,6 +4,8 @@ import { tracked } from "@glimmer/tracking"; import KeyValueStore from "discourse/lib/key-value-store"; import Site from "discourse/models/site"; import getURL from "discourse-common/lib/get-url"; +import { getUserChatSeparateSidebarMode } from "discourse/plugins/chat/discourse/lib/get-user-chat-separate-sidebar-mode"; +import { withPluginApi } from "discourse/lib/plugin-api"; const PREFERRED_MODE_KEY = "preferred_mode"; const PREFERRED_MODE_STORE_NAMESPACE = "discourse_chat_"; @@ -56,6 +58,16 @@ export default class ChatStateManager extends Service { } didOpenDrawer(url = null) { + withPluginApi("1.8.0", (api) => { + if (getUserChatSeparateSidebarMode(this.currentUser).always) { + api.setSidebarPanel("main"); + api.setSeparatedSidebarMode(); + api.hideSidebarSwitchPanelButtons(); + } else { + api.setCombinedSidebarMode(); + } + }); + this.isDrawerActive = true; this.isDrawerExpanded = true; @@ -68,6 +80,24 @@ export default class ChatStateManager extends Service { } didCloseDrawer() { + withPluginApi("1.8.0", (api) => { + api.setSidebarPanel("main"); + + const chatSeparateSidebarMode = getUserChatSeparateSidebarMode( + this.currentUser + ); + if (chatSeparateSidebarMode.fullscreen) { + api.setCombinedSidebarMode(); + api.showSidebarSwitchPanelButtons(); + } else if (chatSeparateSidebarMode.always) { + api.setSeparatedSidebarMode(); + api.showSidebarSwitchPanelButtons(); + } else { + api.setCombinedSidebarMode(); + api.hideSidebarSwitchPanelButtons(); + } + }); + this.isDrawerActive = false; this.isDrawerExpanded = false; this.chat.updatePresence(); diff --git a/plugins/chat/assets/javascripts/discourse/templates/preferences/chat.hbs b/plugins/chat/assets/javascripts/discourse/templates/preferences/chat.hbs index 15eb67ad18188d..b90fe1b44b8995 100644 --- a/plugins/chat/assets/javascripts/discourse/templates/preferences/chat.hbs +++ b/plugins/chat/assets/javascripts/discourse/templates/preferences/chat.hbs @@ -99,6 +99,23 @@ /> +
+ + + +
+ `); + + assert + .dom(".icon.btn-flat") + .hasAttribute("title", I18n.t("chat.title_capitalized")) + .hasAttribute("href", "/chat"); + + assert.dom(".d-icon-d-chat").exists(); + }); + + test("full page - always separated mode", async function (assert) { + this.currentUser.user_option.chat_separate_sidebar_mode = "always"; + sinon + .stub(this.owner.lookup("service:chat-state-manager"), "isFullPageActive") + .value(true); + + await render(hbs``); + + assert + .dom(".icon.btn-flat") + .hasAttribute("title", I18n.t("sidebar.panels.forum.label")) + .hasAttribute("href", "/latest"); + + assert.dom(".d-icon-random").exists(); + }); +}); diff --git a/spec/system/page_objects/components/navigation_menu/base.rb b/spec/system/page_objects/components/navigation_menu/base.rb index a7b1ab7edcd161..7f41ea2447a8bd 100644 --- a/spec/system/page_objects/components/navigation_menu/base.rb +++ b/spec/system/page_objects/components/navigation_menu/base.rb @@ -34,6 +34,22 @@ def has_no_section?(name) has_no_css?(".sidebar-sections [data-section-name='#{name.parameterize}']") end + def has_switch_button?(key = nil) + if key + page.has_css?(".sidebar__panel-switch-button[data-key='#{key.parameterize}']") + else + page.has_css?(".sidebar__panel-switch-button") + end + end + + def has_no_switch_button?(key = nil) + if key + page.has_no_css?(".sidebar__panel-switch-button[data-key='#{key.parameterize}']") + else + page.has_no_css?(".sidebar__panel-switch-button") + end + end + def has_categories_section? has_section?("Categories") end