DEV: rename chat preferred mobile index to chat preferred index (#27953)

* DEV: rename chat preferred mobile index to chat preferred index

* UX: change routing to be consistent with mobile

* DEV: change migration file to use script

* UX: show footer only if more than one option is available

* UX: Remove desktopView only checks for chat

* DEV: Remove unused imports

* UX: Update chat footer checks and Add rerouting to chat drawer

* UX: Add margin to chat row in desktop and update chat drawer logic

* UX: Change chat in desktop to use flexbox

* UX: Add drawer actions to chat navbar

* DEV: Update page object with new chat css classes

removed `.open-browse-page-btn` usage in 7bd65006d7

* DEV: rename `browse/open` in chat url to `channels`

* UX: Adjust css for when in threads mode

* DEV: change css class name in no_sidebar_spec.rb

* DEV: rename tests to be more descriptive with the action they are testing

update chat template to not rely on `:has`

* DEV: update test and add method to chat page object

* DEV: update no_sidebar_spec for chat changes

* DEV: remove tests from navigation_spec that no longer apply

* DEV: revert typo in test

* DEV: change url path for mobile chat in test specs

* DEV: Add check for when is desktop in rerouting

* UX: Removed footer from desktop.

Made `hasThreads` and `hasDirectMessages` methods in chat-drawer public

* UX: remove sidebar on desktop full page if dm list is empty

* DEV: Address review comments

* DEV: Adjust reroute logic for chat browse

remove unused code

* UX: Adjust rerouting to go to browse.open

* UX: Change rerouting to be more consistent

Add chat_default_channel_id routing

* UX: Update rerouting configuration for chat routes

* DEV: Update tests with the new chat behavior

* DEV: revert changes made in tests and bring back toggle for drawer

* DEV: revert classes in page objects

* DEV: Add tests to new chat navigation behavior

remove unused stylesheets
revert deleted lines in tests
update concat class logic in chat dm template

* DEV: update css on test
This commit is contained in:
Gabriel Grubba 2024-07-30 10:25:22 -03:00 committed by GitHub
parent 731fcad3d5
commit a3d61ba1c4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 232 additions and 62 deletions

View File

@ -0,0 +1,11 @@
# frozen_string_literal: true
class RenameChatPreferredMobileIndexSetting < ActiveRecord::Migration[7.0]
def up
execute "UPDATE site_settings SET name = 'chat_preferred_index' WHERE name = 'chat_preferred_mobile_index'"
end
def down
execute "UPDATE site_settings SET name = 'chat_preferred_mobile_index' WHERE name = 'chat_preferred_index'"
end
end

View File

@ -6,6 +6,7 @@ import { service } from "@ember/service";
import { and } from "truth-helpers";
import DButton from "discourse/components/d-button";
import PluginOutlet from "discourse/components/plugin-outlet";
import concatClass from "discourse/helpers/concat-class";
import dIcon from "discourse-common/helpers/d-icon";
import i18n from "discourse-common/helpers/i18n";
import ChatModalNewMessage from "discourse/plugins/chat/discourse/components/chat/modal/new-message";
@ -15,6 +16,7 @@ import ChatChannelRow from "./chat-channel-row";
export default class ChannelsListDirect extends Component {
@service chat;
@service chatChannelsManager;
@service chatStateManager;
@service site;
@service modal;
@ -40,12 +42,6 @@ export default class ChannelsListDirect extends Component {
return this.chat.userCanDirectMessage;
}
get directMessageChannelClasses() {
return `channels-list-container direct-message-channels ${
this.inSidebar ? "collapsible-sidebar-section" : ""
}`;
}
get directMessageChannelsEmpty() {
return this.chatChannelsManager.directMessageChannels?.length === 0;
}
@ -66,8 +62,13 @@ export default class ChannelsListDirect extends Component {
@tagName=""
@outletArgs={{hash inSidebar=this.inSidebar}}
/>
{{#if (and this.showDirectMessageChannels this.site.desktopView)}}
{{#if
(and
this.showDirectMessageChannels
this.site.desktopView
this.chatStateManager.isDrawerActive
)
}}
<div class="chat-channel-divider direct-message-channels-section">
{{#if this.inSidebar}}
<span
@ -100,7 +101,12 @@ export default class ChannelsListDirect extends Component {
<div
id="direct-message-channels"
class={{this.directMessageChannelClasses}}
class={{concatClass
"channels-list-container"
"direct-message-channels"
(if this.inSidebar "collapsible-sidebar-section")
(if this.directMessageChannelsEmpty "center-empty-channels-list")
}}
>
{{#if this.directMessageChannelsEmpty}}
<EmptyChannelsList

View File

@ -15,6 +15,7 @@ export default class ChatFooter extends Component {
@service chat;
@service chatHistory;
@service siteSettings;
@service site;
@service currentUser;
@service chatChannelsManager;
@service chatStateManager;
@ -35,10 +36,18 @@ export default class ChatFooter extends Component {
return routeName === "chat" ? "chat.channels" : routeName;
}
get enabledRouteCount() {
return [
this.includeThreads,
this.directMessagesEnabled,
this.siteSettings.enable_public_channels,
].filter(Boolean).length;
}
get shouldRenderFooter() {
return (
(this.site.mobileView || this.chatStateManager.isDrawerExpanded) &&
this.chatStateManager.hasPreloadedChannels &&
(this.includeThreads || this.directMessagesEnabled)
this.enabledRouteCount > 1
);
}

View File

@ -12,6 +12,7 @@ export default class ChatRoutesChannels extends Component {
<Navbar as |navbar|>
<navbar.Title @title={{i18n "chat.chat_channels"}} />
<navbar.Actions as |action|>
<action.OpenDrawerButton />
<action.BrowseChannelsButton />
</navbar.Actions>
</Navbar>

View File

@ -12,6 +12,7 @@ export default class ChatRoutesDirectMessages extends Component {
<Navbar as |navbar|>
<navbar.Title @title={{i18n "chat.direct_messages.title"}} />
<navbar.Actions as |action|>
<action.OpenDrawerButton />
<action.NewDirectMessageButton />
</navbar.Actions>
</Navbar>

View File

@ -5,6 +5,8 @@ import { FOOTER_NAV_ROUTES } from "discourse/plugins/chat/discourse/lib/chat-con
export default class ChatController extends Controller {
@service chat;
@service chatStateManager;
@service chatChannelsManager;
@service siteSettings;
@service router;
get shouldUseChatSidebar() {
@ -15,18 +17,38 @@ export default class ChatController extends Controller {
if (this.shouldUseCoreSidebar) {
return false;
}
if (
this.publicMessageChannelsEmpty &&
this.enabledRouteCount === 1 &&
this.chat.userCanAccessDirectMessages
) {
return false;
}
return true;
}
get publicMessageChannelsEmpty() {
return (
this.chatChannelsManager.publicMessageChannels?.length === 0 &&
this.chatStateManager.hasPreloadedChannels
);
}
get shouldUseCoreSidebar() {
return this.siteSettings.navigation_menu === "sidebar";
}
get enabledRouteCount() {
return [
this.siteSettings.chat_threads_enabled,
this.chat.userCanAccessDirectMessages,
this.siteSettings.enable_public_channels,
].filter(Boolean).length;
}
get shouldUseChatFooter() {
return (
this.site.mobileView &&
FOOTER_NAV_ROUTES.includes(this.router.currentRouteName)
FOOTER_NAV_ROUTES.includes(this.router.currentRouteName) &&
this.enabledRouteCount > 1
);
}

View File

@ -4,14 +4,39 @@ import DiscourseRoute from "discourse/routes/discourse";
export default class ChatChannelsRoute extends DiscourseRoute {
@service chat;
@service chatChannelsManager;
@service siteSettings;
activate() {
this.chat.activeChannel = null;
}
beforeModel() {
const id = this.currentUser.custom_fields.last_chat_channel_id;
const defaultChannelId = this.siteSettings.chat_default_channel_id;
if (this.site.desktopView) {
this.router.transitionTo("chat");
if (id) {
this.chatChannelsManager.find(id).then((c) => {
return this.router.replaceWith("chat.channel", ...c.routeModels);
});
} else {
// first time browsing chat in desktop and the preferred index is channels
if (defaultChannelId) {
this.chatChannelsManager.find(defaultChannelId).then((c) => {
return this.router.replaceWith("chat.channel", ...c.routeModels);
});
} else {
this.router.replaceWith("chat.browse.open");
}
}
} else {
if (
defaultChannelId &&
this.router.currentRoute?.parent?.params?.channelId !== defaultChannelId
) {
this.chatChannelsManager.find(defaultChannelId).then((c) => {
return this.router.replaceWith("chat.channel", ...c.routeModels);
});
}
}
}

View File

@ -11,7 +11,17 @@ export default class ChatDirectMessagesRoute extends DiscourseRoute {
beforeModel() {
if (this.site.desktopView) {
this.router.transitionTo("chat");
if (this.chatChannelsManager.directMessageChannels.length === 0) {
// first time browsing chat and the preferred index is dms
this.router.replaceWith("chat.direct-messages");
} else {
// there should be at least one dm channel
// we can reroute using the last channel id
const id = this.currentUser.custom_fields.last_chat_channel_id;
this.chatChannelsManager.find(id).then((c) => {
return this.router.replaceWith("chat.channel", ...c.routeModels);
});
}
}
}

View File

@ -20,6 +20,10 @@ export default class ChatIndexRoute extends DiscourseRoute {
return this.chat.userCanAccessDirectMessages;
}
get isPublicChannelsEnabled() {
return this.siteSettings.enable_public_channels;
}
activate() {
this.chat.activeChannel = null;
}
@ -29,31 +33,25 @@ export default class ChatIndexRoute extends DiscourseRoute {
}
async redirect() {
// on mobile redirect user to the first footer tab route
if (this.site.mobileView) {
if (
this.siteSettings.chat_preferred_mobile_index === "my_threads" &&
this.hasThreads
) {
return this.router.replaceWith("chat.threads");
} else if (
this.siteSettings.chat_preferred_mobile_index === "direct_messages" &&
this.hasDirectMessages
) {
return this.router.replaceWith("chat.direct-messages");
} else {
return this.router.replaceWith("chat.channels");
}
if (
this.siteSettings.chat_preferred_index === "my_threads" &&
this.hasThreads
) {
return this.router.replaceWith("chat.threads");
} else if (
this.siteSettings.chat_preferred_index === "direct_messages" &&
this.hasDirectMessages
) {
return this.router.replaceWith("chat.direct-messages");
} else if (
this.siteSettings.chat_preferred_index === "channels" &&
this.isPublicChannelsEnabled
) {
return this.router.replaceWith("chat.channels");
}
// We are on desktop. Check for last visited channel and transition if so
const id = this.currentUser.custom_fields.last_chat_channel_id;
if (id) {
return this.chatChannelsManager.find(id).then((c) => {
return this.router.replaceWith("chat.channel", ...c.routeModels);
});
} else {
return this.router.replaceWith("chat.browse");
if (!this.isPublicChannelsEnabled && this.hasDirectMessages) {
return this.router.replaceWith("chat.direct-messages");
}
return this.router.replaceWith("chat.browse.open");
}
}

View File

@ -16,11 +16,11 @@ const ROUTES = {
// order matters, non index before index
"chat.browse": {
name: ChatDrawerRoutesBrowse,
extractParams: () => ({ currentTab: "all" }),
extractParams: () => ({ currentTab: "open" }),
},
"chat.browse.index": {
name: ChatDrawerRoutesBrowse,
extractParams: () => ({ currentTab: "all" }),
extractParams: () => ({ currentTab: "open" }),
},
"chat.browse.open": {
name: ChatDrawerRoutesBrowse,
@ -131,6 +131,10 @@ const ROUTES = {
export default class ChatDrawerRouter extends Service {
@service router;
@service chatHistory;
@service chat;
@service siteSettings;
@service chatStateManager;
@service chatChannelsManager;
@tracked component = null;
@tracked drawerRoute = null;
@ -138,16 +142,72 @@ export default class ChatDrawerRouter extends Service {
routeNames = Object.keys(ROUTES);
get hasThreads() {
if (!this.siteSettings.chat_threads_enabled) {
return false;
}
return this.chatChannelsManager.hasThreadedChannels;
}
get hasDirectMessages() {
return this.chat.userCanAccessDirectMessages;
}
#routeFromURL(url) {
let route = this.router.recognize(url);
// ember might recognize the index subroute
if (route.localName === "index") {
route = route.parent;
}
return route;
}
#redirect() {
if (
this.siteSettings.chat_preferred_index === "my_threads" &&
this.hasThreads
) {
return this.stateFor(this.#routeFromURL("/chat/threads"));
}
if (
this.siteSettings.chat_preferred_index === "direct_messages" &&
this.hasDirectMessages
) {
return this.stateFor(this.#routeFromURL("/chat/direct-messages"));
}
if (this.siteSettings.chat_default_channel_id) {
return this.chatChannelsManager
.find(this.siteSettings.chat_default_channel_id)
.then((c) => {
return this.router.replaceWith("chat.channel", ...c.routeModels);
});
}
if (!this.siteSettings.enable_public_channels) {
return this.stateFor(this.#routeFromURL("/chat/direct-messages"));
}
}
stateFor(route) {
this.drawerRoute?.deactivate?.(this.chatHistory.currentRoute);
this.chatHistory.visit(route);
this.drawerRoute = ROUTES[route.name];
this.params = this.drawerRoute?.extractParams?.(route) || route.params;
this.component = this.drawerRoute?.name || ChatDrawerRoutesChannels;
this.currentRouteName = route.name;
if (
!this.chatStateManager.isDrawerActive && // only when opening the drawer
this.component.name === "ChatDrawerRoutesChannels" // we should check if redirect to channels
) {
this.#redirect();
}
this.currentRouteName = route.name;
this.drawerRoute.activate?.(route);
}
}

View File

@ -54,5 +54,8 @@
.channels-list-container {
height: auto;
}
.channels-list-container.center-empty-channels-list {
height: 90%;
}
}
}

View File

@ -25,7 +25,7 @@ en:
chat_editing_grace_period: "For (n) seconds after sending a chat, editing will not display the (edited) tag by the chat message."
chat_editing_grace_period_max_diff_low_trust: "Maximum number of character changes allowed in chat editing grace period, if more changed display the (edited) tag by the chat message (trust level 0 and 1)."
chat_editing_grace_period_max_diff_high_trust: "Maximum number of character changes allowed in chat editing grace period, if more changed display the (edited) tag by the chat message (trust level 2 and up)."
chat_preferred_mobile_index: "Preferred tab when loading /chat on mobile."
chat_preferred_index: "Preferred tab when loading /chat."
errors:
chat_default_channel: "The default chat channel must be a public channel."
direct_message_enabled_groups_invalid: "You must specify at least one group for this setting. If you do not want anyone except staff to send direct messages, choose the staff group."

View File

@ -139,7 +139,7 @@ chat:
type: integer
default: 40
min: 0
chat_preferred_mobile_index:
chat_preferred_index:
client: true
type: enum
default: channels

View File

@ -51,4 +51,11 @@ RSpec.describe "Drawer - index", type: :system do
expect(drawer_page.browse).to have_channel(name: channel.name)
end
it "shows empty state when no dms" do
drawer_page.visit_index
drawer_page.click_direct_messages
expect(page).to have_css("#c-footer-direct-messages.--active")
expect(page).to have_selector(".channel-list-empty-message")
end
end

View File

@ -201,8 +201,8 @@ RSpec.describe "List channels | mobile", type: :system, mobile: true do
end
end
context "when chat_preferred_mobile_index is set to direct_messages" do
before { SiteSetting.chat_preferred_mobile_index = "direct_messages" }
context "when chat_preferred_index is set to direct_messages" do
before { SiteSetting.chat_preferred_index = "direct_messages" }
it "changes the default index" do
visit("/chat")
@ -213,15 +213,15 @@ RSpec.describe "List channels | mobile", type: :system, mobile: true do
context "when user can't use direct messages" do
before { SiteSetting.direct_message_enabled_groups = Group::AUTO_GROUPS[:staff] }
it "redirects to channels" do
it "redirects to browse" do
visit("/chat")
expect(page).to have_current_path("/chat/channels")
expect(page).to have_current_path("/chat/browse/open")
end
end
end
context "when chat_preferred_mobile_index is not set" do
context "when chat_preferred_index is not set" do
it "redirects to channels" do
visit("/chat")
@ -229,10 +229,10 @@ RSpec.describe "List channels | mobile", type: :system, mobile: true do
end
end
context "when chat_preferred_mobile_index is set to my_threads" do
context "when chat_preferred_index is set to my_threads" do
before do
SiteSetting.chat_threads_enabled = true
SiteSetting.chat_preferred_mobile_index = "my_threads"
SiteSetting.chat_preferred_index = "my_threads"
end
it "redirects to threads" do
@ -247,10 +247,10 @@ RSpec.describe "List channels | mobile", type: :system, mobile: true do
context "when no threads" do
before { SiteSetting.chat_threads_enabled = false }
it "redirects to channels" do
it "redirects to browse" do
visit("/chat")
expect(page).to have_current_path("/chat/channels")
expect(page).to have_current_path("/chat/browse/open")
end
end
end

View File

@ -95,14 +95,6 @@ RSpec.describe "Navigation", type: :system do
chat.channel_path(category_channel.slug, category_channel.id),
)
end
it "redirects /chat/direct-messages to browse" do
visit("/chat/direct-messages")
expect(page).to have_current_path(
chat.channel_path(category_channel.slug, category_channel.id),
)
end
end
context "when opening chat" do
@ -265,6 +257,27 @@ RSpec.describe "Navigation", type: :system do
end
end
context "when public channels are disabled" do
before { SiteSetting.enable_public_channels = false }
it "only show dms in drawer" do
visit("/")
chat_page.open_from_header
expect(page).to have_css(".direct-message-channels.center-empty-channels-list")
expect(chat_page).to have_no_messages
end
it "only show dms in desktop" do
visit("/")
chat_page.prefers_full_page
chat_page.open_from_header
expect(chat_page).to have_no_messages
expect(page).to have_css(".c-routes.--direct-messages")
end
end
context "when sidebar is configured as the navigation menu" do
before { SiteSetting.navigation_menu = "sidebar" }

View File

@ -130,6 +130,10 @@ module PageObjects
has_no_css?(NEW_CHANNEL_BUTTON_SELECTOR)
end
def has_no_messages?
have_selector(".channel-list-empty-message")
end
private
def drawer?(expectation:, channel_id: nil, expanded: true)