FEATURE: allows browse page in chat drawer (#27919)

This commit ensures the browse page can be loaded in the drawer and doesn’t force full page mode.

Other notable changes of this commit:
- be consistent about wrapping each full page route with "c-routes.--route-name" and each drawer container with "c-drawer-routes.--route-name"
- move browse channels into its own component, it was before in the template of the channels browse
This commit is contained in:
Joffrey JAFFEUX 2024-07-16 12:34:37 +02:00 committed by GitHub
parent 600f2854c7
commit c74fa300e7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
49 changed files with 882 additions and 700 deletions

View File

@ -0,0 +1,129 @@
import Component from "@glimmer/component";
import { cached, tracked } from "@glimmer/tracking";
import { concat, hash } from "@ember/helper";
import { action } from "@ember/object";
import didInsert from "@ember/render-modifiers/modifiers/did-insert";
import { LinkTo } from "@ember/routing";
import { schedule } from "@ember/runloop";
import { service } from "@ember/service";
import { eq } from "truth-helpers";
import DButton from "discourse/components/d-button";
import { INPUT_DELAY } from "discourse-common/config/environment";
import i18n from "discourse-common/helpers/i18n";
import discourseDebounce from "discourse-common/lib/debounce";
import List from "discourse/plugins/chat/discourse/components/chat/list";
import ChatModalNewMessage from "discourse/plugins/chat/discourse/components/chat/modal/new-message";
import ChatChannelCard from "discourse/plugins/chat/discourse/components/chat-channel-card";
import DcFilterInput from "discourse/plugins/chat/discourse/components/dc-filter-input";
const ARCHIVED = "archived";
const ALL = "all";
const OPEN = "open";
const CLOSED = "closed";
const TABS = [ALL, OPEN, CLOSED, ARCHIVED];
export default class BrowseChannels extends Component {
@service chatApi;
@service modal;
@service siteSettings;
@tracked filter = "";
get currentTab() {
return this.args.currentTab ?? ALL;
}
@cached
get channelsCollection() {
return this.chatApi.channels({
filter: this.filter,
status: this.currentTab,
});
}
get tabs() {
if (this.siteSettings.chat_allow_archiving_channels) {
return TABS;
} else {
return [...TABS].removeObject(ARCHIVED);
}
}
@action
showChatNewMessageModal() {
this.modal.show(ChatModalNewMessage);
}
@action
setFilter(event) {
this.filter = event.target.value;
discourseDebounce(this.debouncedLoad, INPUT_DELAY);
}
@action
debouncedLoad() {
this.channelsCollection.load({ limit: 10 });
}
@action
focusFilterInput(input) {
schedule("afterRender", () => input?.focus());
}
<template>
<div class="chat-browse-view">
<div class="chat-browse-view__actions">
<nav>
<ul class="nav-pills chat-browse-view__filters">
{{#each this.tabs as |tab|}}
<li class={{concat "chat-browse-view__filter -" tab}}>
<LinkTo
@route={{concat "chat.browse." tab}}
class={{concat "chat-browse-view__filter-link -" tab}}
@current-when={{eq tab this.currentTab}}
>
{{i18n (concat "chat.browse.filter_" tab)}}
</LinkTo>
</li>
{{/each}}
</ul>
</nav>
<DcFilterInput
{{didInsert this.focusFilterInput}}
@filterAction={{this.setFilter}}
@icons={{hash right="search"}}
@containerClass="filter-input"
placeholder={{i18n "chat.browse.filter_input_placeholder"}}
/>
</div>
<div class="chat-browse-view__content_wrapper">
<div class="chat-browse-view__content">
<List
@collection={{this.channelsCollection}}
class="chat-browse-view__cards"
as |list|
>
<list.Item as |channel|>
<ChatChannelCard @channel={{channel}} />
</list.Item>
<list.EmptyState>
<span class="empty-state-title">
{{i18n "chat.empty_state.title"}}
</span>
<div class="empty-state-body">
<p>{{i18n "chat.empty_state.direct_message"}}</p>
<DButton
@action={{this.showChatNewMessageModal}}
@label="chat.empty_state.direct_message_cta"
/>
</div>
</list.EmptyState>
</List>
</div>
</div>
</div>
</template>
}

View File

@ -702,7 +702,6 @@ export default class ChatChannel extends Component {
{{didUpdate this.loadMessages @targetMessageId}}
data-id={{@channel.id}}
>
<ChatChannelStatus @channel={{@channel}} />
<ChatNotices @channel={{@channel}} />
<ChatMentionWarnings />

View File

@ -0,0 +1,47 @@
import Component from "@glimmer/component";
import { tracked } from "@glimmer/tracking";
import { array } from "@ember/helper";
import { service } from "@ember/service";
import i18n from "discourse-common/helpers/i18n";
import BrowseChannels from "discourse/plugins/chat/discourse/components/browse-channels";
import Navbar from "discourse/plugins/chat/discourse/components/chat/navbar";
export default class ChatDrawerRoutesBrowse extends Component {
@service chat;
@service chatStateManager;
@service chatChannelsManager;
@service chatHistory;
@tracked showThreadFullTitle = false;
get showfullTitle() {
return this.chatStateManager.isDrawerExpanded && this.showThreadFullTitle;
}
<template>
<div class="c-drawer-routes --browse">
<Navbar
@onClick={{this.chat.toggleDrawer}}
@showFullTitle={{this.showfullTitle}}
as |navbar|
>
<navbar.BackButton @route="chat.channels" />
<navbar.Title @title={{i18n "chat.browse.title"}} />
<navbar.Actions as |a|>
<a.NewChannelButton />
<a.ToggleDrawerButton />
<a.FullPageButton />
<a.CloseDrawerButton />
</navbar.Actions>
</Navbar>
{{#if this.chatStateManager.isDrawerExpanded}}
<div class="chat-drawer-content">
{{#each (array @params.currentTab) as |tab|}}
<BrowseChannels @currentTab={{tab}} />
{{/each}}
</div>
{{/if}}
</div>
</template>
}

View File

@ -34,27 +34,35 @@ export default class ChatDrawerRoutesMembers extends Component {
}
<template>
<Navbar @onClick={{this.chat.toggleDrawer}} as |navbar|>
<navbar.BackButton
@title={{this.backButton.title}}
@route={{this.backButton.route}}
@routeModels={{this.backButton.models}}
/>
<navbar.ChannelTitle @channel={{this.chat.activeChannel}} />
<navbar.Actions as |a|>
<a.ToggleDrawerButton />
<a.FullPageButton />
<a.CloseDrawerButton />
</navbar.Actions>
</Navbar>
<div
class="c-drawer-routes --channel-info-members"
{{didInsert this.fetchChannel}}
>
{{#if this.chat.activeChannel}}
<Navbar @onClick={{this.chat.toggleDrawer}} as |navbar|>
<navbar.BackButton
@title={{this.backButton.title}}
@route={{this.backButton.route}}
@routeModels={{this.backButton.models}}
/>
<navbar.ChannelTitle @channel={{this.chat.activeChannel}} />
<navbar.Actions as |a|>
<a.ToggleDrawerButton />
<a.FullPageButton />
<a.CloseDrawerButton />
</navbar.Actions>
</Navbar>
{{#if this.chatStateManager.isDrawerExpanded}}
<div class="chat-drawer-content" {{didInsert this.fetchChannel}}>
{{#if this.chat.activeChannel}}
<ChannelInfoNav @channel={{this.chat.activeChannel}} @tab="members" />
<ChannelMembers @channel={{this.chat.activeChannel}} />
{{#if this.chatStateManager.isDrawerExpanded}}
<div class="chat-drawer-content">
<ChannelInfoNav
@channel={{this.chat.activeChannel}}
@tab="members"
/>
<ChannelMembers @channel={{this.chat.activeChannel}} />
</div>
{{/if}}
</div>
{{/if}}
{{/if}}
</div>
</template>
}

View File

@ -34,30 +34,35 @@ export default class ChatDrawerRoutesSettings extends Component {
}
<template>
<Navbar @onClick={{this.chat.toggleDrawer}} as |navbar|>
<navbar.BackButton
@title={{this.backButton.title}}
@route={{this.backButton.route}}
@routeModels={{this.backButton.models}}
/>
<navbar.ChannelTitle @channel={{this.chat.activeChannel}} />
<navbar.Actions as |a|>
<a.ToggleDrawerButton />
<a.FullPageButton />
<a.CloseDrawerButton />
</navbar.Actions>
</Navbar>
{{#if this.chatStateManager.isDrawerExpanded}}
<div class="chat-drawer-content" {{didInsert this.fetchChannel}}>
{{#if this.chat.activeChannel}}
<ChannelInfoNav
@channel={{this.chat.activeChannel}}
@tab="settings"
<div
class="c-drawer-routes --channel-info-settings"
{{didInsert this.fetchChannel}}
>
{{#if this.chat.activeChannel}}
<Navbar @onClick={{this.chat.toggleDrawer}} as |navbar|>
<navbar.BackButton
@title={{this.backButton.title}}
@route={{this.backButton.route}}
@routeModels={{this.backButton.models}}
/>
<ChannelSettings @channel={{this.chat.activeChannel}} />
<navbar.ChannelTitle @channel={{this.chat.activeChannel}} />
<navbar.Actions as |a|>
<a.ToggleDrawerButton />
<a.FullPageButton />
<a.CloseDrawerButton />
</navbar.Actions>
</Navbar>
{{#if this.chatStateManager.isDrawerExpanded}}
<div class="chat-drawer-content">
<ChannelInfoNav
@channel={{this.chat.activeChannel}}
@tab="settings"
/>
<ChannelSettings @channel={{this.chat.activeChannel}} />
</div>
{{/if}}
</div>
{{/if}}
{{/if}}
</div>
</template>
}

View File

@ -78,41 +78,45 @@ export default class ChatDrawerRoutesChannelThread extends Component {
}
<template>
<Navbar
@onClick={{this.chat.toggleDrawer}}
@showFullTitle={{this.showfullTitle}}
as |navbar|
<div
class="c-drawer-routes --channel-thread"
{{didInsert this.fetchChannelAndThread}}
{{didUpdate this.fetchChannelAndThread @params.channelId}}
{{didUpdate this.fetchChannelAndThread @params.threadId}}
>
<navbar.BackButton
@title={{this.backButton.title}}
@route={{this.backButton.route}}
@routeModels={{this.backButton.models}}
/>
<navbar.Title @title={{this.threadTitle}} @icon="discourse-threads" />
<navbar.Actions as |a|>
<a.ToggleDrawerButton />
<a.FullPageButton />
<a.CloseDrawerButton />
</navbar.Actions>
</Navbar>
{{#if this.chat.activeChannel}}
<Navbar
@onClick={{this.chat.toggleDrawer}}
@showFullTitle={{this.showfullTitle}}
as |navbar|
>
<navbar.BackButton
@title={{this.backButton.title}}
@route={{this.backButton.route}}
@routeModels={{this.backButton.models}}
/>
<navbar.Title @title={{this.threadTitle}} @icon="discourse-threads" />
<navbar.Actions as |a|>
<a.ToggleDrawerButton />
<a.FullPageButton />
<a.CloseDrawerButton />
</navbar.Actions>
</Navbar>
{{#if this.chatStateManager.isDrawerExpanded}}
<div
class="chat-drawer-content"
{{didInsert this.fetchChannelAndThread}}
{{didUpdate this.fetchChannelAndThread @params.channelId}}
{{didUpdate this.fetchChannelAndThread @params.threadId}}
>
{{#each (array this.chat.activeChannel.activeThread) as |thread|}}
{{#if thread}}
<ChatThread
@thread={{thread}}
@targetMessageId={{@params.messageId}}
@setFullTitle={{this.setFullTitle}}
/>
{{/if}}
{{/each}}
</div>
{{/if}}
{{#if this.chatStateManager.isDrawerExpanded}}
<div class="chat-drawer-content">
{{#each (array this.chat.activeChannel.activeThread) as |thread|}}
{{#if thread}}
<ChatThread
@thread={{thread}}
@targetMessageId={{@params.messageId}}
@setFullTitle={{this.setFullTitle}}
/>
{{/if}}
{{/each}}
</div>
{{/if}}
{{/if}}
</div>
</template>
}

View File

@ -40,29 +40,31 @@ export default class ChatDrawerRoutesChannelThreads extends Component {
}
<template>
{{#if this.chat.activeChannel}}
<Navbar @onClick={{this.chat.toggleDrawer}} as |navbar|>
<navbar.BackButton
@title={{this.backLinkTitle}}
@route="chat.channel"
@routeModels={{this.chat.activeChannel.routeModels}}
/>
<navbar.Title @title={{this.title}} @icon="discourse-threads" />
<navbar.Actions as |a|>
<a.ToggleDrawerButton />
<a.FullPageButton />
<a.CloseDrawerButton />
</navbar.Actions>
</Navbar>
{{/if}}
<div class="chat-drawer-content" {{didInsert this.fetchChannel}}>
<div class="c-drawer-routes --channel-threads">
{{#if this.chat.activeChannel}}
<ChatThreadList
@channel={{this.chat.activeChannel}}
@includeHeader={{false}}
/>
<Navbar @onClick={{this.chat.toggleDrawer}} as |navbar|>
<navbar.BackButton
@title={{this.backLinkTitle}}
@route="chat.channel"
@routeModels={{this.chat.activeChannel.routeModels}}
/>
<navbar.Title @title={{this.title}} @icon="discourse-threads" />
<navbar.Actions as |a|>
<a.ToggleDrawerButton />
<a.FullPageButton />
<a.CloseDrawerButton />
</navbar.Actions>
</Navbar>
{{/if}}
<div class="chat-drawer-content" {{didInsert this.fetchChannel}}>
{{#if this.chat.activeChannel}}
<ChatThreadList
@channel={{this.chat.activeChannel}}
@includeHeader={{false}}
/>
{{/if}}
</div>
</div>
</template>
}

View File

@ -11,9 +11,12 @@ export default class ChatDrawerRoutesChannel extends Component {
@service chat;
@service chatStateManager;
@service chatChannelsManager;
@service chatHistory;
get backBtnRoute() {
if (this.chat.activeChannel?.isDirectMessageChannel) {
if (this.chatHistory.previousRoute?.name === "chat.browse") {
return "chat.browse";
} else if (this.chat.activeChannel?.isDirectMessageChannel) {
return "chat.direct-messages";
} else {
return "chat.channels";
@ -34,34 +37,36 @@ export default class ChatDrawerRoutesChannel extends Component {
}
<template>
<Navbar @onClick={{this.chat.toggleDrawer}} as |navbar|>
<navbar.BackButton @route={{this.backBtnRoute}} />
<navbar.ChannelTitle @channel={{this.chat.activeChannel}} />
<navbar.Actions as |a|>
<a.ThreadsListButton @channel={{this.chat.activeChannel}} />
<a.ToggleDrawerButton />
<a.FullPageButton />
<a.CloseDrawerButton />
</navbar.Actions>
</Navbar>
<div class="c-drawer-routes --channel">
<Navbar @onClick={{this.chat.toggleDrawer}} as |navbar|>
<navbar.BackButton @route={{this.backBtnRoute}} />
<navbar.ChannelTitle @channel={{this.chat.activeChannel}} />
<navbar.Actions as |a|>
<a.ThreadsListButton @channel={{this.chat.activeChannel}} />
<a.ToggleDrawerButton />
<a.FullPageButton />
<a.CloseDrawerButton />
</navbar.Actions>
</Navbar>
{{#if this.chatStateManager.isDrawerExpanded}}
<div
class="chat-drawer-content"
{{didInsert this.fetchChannel}}
{{didUpdate this.fetchChannel @params.channelId}}
>
{{#if this.chat.activeChannel}}
{{#each (array this.chat.activeChannel) as |channel|}}
{{#if channel}}
<ChatChannel
@targetMessageId={{readonly @params.messageId}}
@channel={{channel}}
/>
{{/if}}
{{/each}}
{{/if}}
</div>
{{/if}}
{{#if this.chatStateManager.isDrawerExpanded}}
<div
class="chat-drawer-content"
{{didInsert this.fetchChannel}}
{{didUpdate this.fetchChannel @params.channelId}}
>
{{#if this.chat.activeChannel}}
{{#each (array this.chat.activeChannel) as |channel|}}
{{#if channel}}
<ChatChannel
@targetMessageId={{readonly @params.messageId}}
@channel={{channel}}
/>
{{/if}}
{{/each}}
{{/if}}
</div>
{{/if}}
</div>
</template>
}

View File

@ -10,21 +10,23 @@ export default class ChatDrawerRoutesChannels extends Component {
@service chatStateManager;
<template>
<Navbar @onClick={{this.chat.toggleDrawer}} as |navbar|>
<navbar.Title @title={{i18n "chat.heading"}} />
<navbar.Actions as |a|>
<a.ToggleDrawerButton />
<a.FullPageButton />
<a.CloseDrawerButton />
</navbar.Actions>
</Navbar>
<div class="c-drawer-routes --channels">
<Navbar @onClick={{this.chat.toggleDrawer}} as |navbar|>
<navbar.Title @title={{i18n "chat.heading"}} />
<navbar.Actions as |a|>
<a.ToggleDrawerButton />
<a.FullPageButton />
<a.CloseDrawerButton />
</navbar.Actions>
</Navbar>
{{#if this.chatStateManager.isDrawerExpanded}}
<div class="chat-drawer-content">
<ChannelsListPublic />
</div>
{{#if this.chatStateManager.isDrawerExpanded}}
<div class="chat-drawer-content">
<ChannelsListPublic />
</div>
<ChatFooter />
{{/if}}
<ChatFooter />
{{/if}}
</div>
</template>
}

View File

@ -5,26 +5,28 @@ import ChannelsListDirect from "discourse/plugins/chat/discourse/components/chan
import Navbar from "discourse/plugins/chat/discourse/components/chat/navbar";
import ChatFooter from "discourse/plugins/chat/discourse/components/chat-footer";
export default class ChatDrawerRoutesChannels extends Component {
export default class ChatDrawerRoutesDirectMessages extends Component {
@service chat;
@service chatStateManager;
<template>
<Navbar @onClick={{this.chat.toggleDrawer}} as |navbar|>
<navbar.Title @title={{i18n "chat.heading"}} />
<navbar.Actions as |a|>
<a.ToggleDrawerButton />
<a.FullPageButton />
<a.CloseDrawerButton />
</navbar.Actions>
</Navbar>
<div class="c-drawer-routes --direct-messages">
<Navbar @onClick={{this.chat.toggleDrawer}} as |navbar|>
<navbar.Title @title={{i18n "chat.heading"}} />
<navbar.Actions as |a|>
<a.ToggleDrawerButton />
<a.FullPageButton />
<a.CloseDrawerButton />
</navbar.Actions>
</Navbar>
{{#if this.chatStateManager.isDrawerExpanded}}
<div class="chat-drawer-content">
<ChannelsListDirect />
</div>
{{#if this.chatStateManager.isDrawerExpanded}}
<div class="chat-drawer-content">
<ChannelsListDirect />
</div>
<ChatFooter />
{{/if}}
<ChatFooter />
{{/if}}
</div>
</template>
}

View File

@ -10,22 +10,24 @@ export default class ChatDrawerRoutesThreads extends Component {
@service chatStateManager;
<template>
<Navbar @onClick={{this.chat.toggleDrawer}} as |navbar|>
<navbar.Title @title={{i18n "chat.heading"}} />
<navbar.Actions as |action|>
<action.ThreadsListButton />
<action.ToggleDrawerButton />
<action.FullPageButton />
<action.CloseDrawerButton />
</navbar.Actions>
</Navbar>
<div class="c-drawer-routes --threads">
<Navbar @onClick={{this.chat.toggleDrawer}} as |navbar|>
<navbar.Title @title={{i18n "chat.heading"}} />
<navbar.Actions as |action|>
<action.ThreadsListButton />
<action.ToggleDrawerButton />
<action.FullPageButton />
<action.CloseDrawerButton />
</navbar.Actions>
</Navbar>
{{#if this.chatStateManager.isDrawerExpanded}}
<div class="chat-drawer-content">
<UserThreads />
</div>
{{/if}}
{{#if this.chatStateManager.isDrawerExpanded}}
<div class="chat-drawer-content">
<UserThreads />
</div>
{{/if}}
<ChatFooter />
<ChatFooter />
</div>
</template>
}

View File

@ -2,7 +2,6 @@ import Component from "@glimmer/component";
import { LinkTo } from "@ember/routing";
import icon from "discourse-common/helpers/d-icon";
import I18n from "I18n";
import { FOOTER_NAV_ROUTES } from "discourse/plugins/chat/discourse/lib/chat-constants";
export default class ChatNavbarBackButton extends Component {
get icon() {
@ -14,11 +13,7 @@ export default class ChatNavbarBackButton extends Component {
}
get targetRoute() {
if (FOOTER_NAV_ROUTES.includes(this.args.route)) {
return this.args.route;
} else {
return "chat";
}
return this.args.route ?? "chat";
}
<template>

View File

@ -1,131 +0,0 @@
import { cached, tracked } from "@glimmer/tracking";
import Component from "@ember/component";
import { concat, hash } from "@ember/helper";
import { action, computed } from "@ember/object";
import didInsert from "@ember/render-modifiers/modifiers/did-insert";
import { LinkTo } from "@ember/routing";
import { schedule } from "@ember/runloop";
import { service } from "@ember/service";
import DButton from "discourse/components/d-button";
import { INPUT_DELAY } from "discourse-common/config/environment";
import i18n from "discourse-common/helpers/i18n";
import discourseDebounce from "discourse-common/lib/debounce";
import List from "discourse/plugins/chat/discourse/components/chat/list";
import ChatModalNewMessage from "discourse/plugins/chat/discourse/components/chat/modal/new-message";
import Navbar from "discourse/plugins/chat/discourse/components/chat/navbar";
import ChatChannelCard from "discourse/plugins/chat/discourse/components/chat-channel-card";
import DcFilterInput from "discourse/plugins/chat/discourse/components/dc-filter-input";
const TABS = ["all", "open", "closed", "archived"];
export default class ChatRoutesBrowse extends Component {
@service chatApi;
@service modal;
@tracked filter = "";
@cached
get channelsCollection() {
return this.chatApi.channels({
filter: this.filter,
status: this.status,
});
}
@computed("siteSettings.chat_allow_archiving_channels")
get tabs() {
if (this.siteSettings.chat_allow_archiving_channels) {
return TABS;
} else {
return [...TABS].removeObject("archived");
}
}
@action
showChatNewMessageModal() {
this.modal.show(ChatModalNewMessage);
}
@action
setFilter(event) {
this.filter = event.target.value;
discourseDebounce(this.debouncedLoad, INPUT_DELAY);
}
@action
debouncedLoad() {
this.channelsCollection.load({ limit: 10 });
}
@action
focusFilterInput(input) {
schedule("afterRender", () => input?.focus());
}
<template>
<div class="c-routes-browse">
<Navbar as |navbar|>
<navbar.BackButton />
<navbar.Title @title={{i18n "chat.browse.title"}} />
<navbar.Actions as |a|>
<a.NewChannelButton />
</navbar.Actions>
</Navbar>
<div class="chat-browse-view">
<div class="chat-browse-view__actions">
<nav>
<ul class="nav-pills chat-browse-view__filters">
{{#each this.tabs as |tab|}}
<li class={{concat "chat-browse-view__filter -" tab}}>
<LinkTo
@route={{concat "chat.browse." tab}}
class={{concat "chat-browse-view__filter-link -" tab}}
>
{{i18n (concat "chat.browse.filter_" tab)}}
</LinkTo>
</li>
{{/each}}
</ul>
</nav>
<DcFilterInput
{{didInsert this.focusFilterInput}}
@filterAction={{this.setFilter}}
@icons={{hash right="search"}}
@containerClass="filter-input"
placeholder={{i18n "chat.browse.filter_input_placeholder"}}
/>
</div>
<div class="chat-browse-view__content_wrapper">
<div class="chat-browse-view__content">
<List
@collection={{this.channelsCollection}}
class="chat-browse-view__cards"
as |list|
>
<list.Item as |channel|>
<ChatChannelCard @channel={{channel}} />
</list.Item>
<list.EmptyState>
<span class="empty-state-title">
{{i18n "chat.empty_state.title"}}
</span>
<div class="empty-state-body">
<p>{{i18n "chat.empty_state.direct_message"}}</p>
<DButton
@action={{this.showChatNewMessageModal}}
@label="chat.empty_state.direct_message_cta"
/>
</div>
</list.EmptyState>
</List>
</div>
</div>
</div>
</div>
</template>
}

View File

@ -125,76 +125,78 @@ export default class ChatRouteChannelInfoMembers extends Component {
}
<template>
{{#if this.site.mobileView}}
<LinkTo
class="c-back-button"
@route="chat.channel.info.settings"
@model={{@channel}}
>
{{icon "chevron-left"}}
{{i18n "chat.members_view.back_to_settings"}}
</LinkTo>
{{/if}}
{{#if this.showAddMembers}}
<MessageCreator
@mode={{this.addMembersMode}}
@channel={{@channel}}
@onClose={{this.hideAddMember}}
@onCancel={{this.hideAddMember}}
/>
{{else}}
<div class="c-channel-members">
<DcFilterInput
{{autoFocus}}
@filterAction={{this.mutFilter}}
@icons={{hash right="search"}}
@containerClass="c-channel-members__filter"
placeholder={{this.filterPlaceholder}}
<div class="c-routes --channel-info-members">
{{#if this.site.mobileView}}
<LinkTo
class="c-back-button"
@route="chat.channel.info.settings"
@model={{@channel}}
>
{{icon "chevron-left"}}
{{i18n "chat.members_view.back_to_settings"}}
</LinkTo>
{{/if}}
{{#if this.showAddMembers}}
<MessageCreator
@mode={{this.addMembersMode}}
@channel={{@channel}}
@onClose={{this.hideAddMember}}
@onCancel={{this.hideAddMember}}
/>
{{else}}
<div class="c-channel-members">
<DcFilterInput
{{autoFocus}}
@filterAction={{this.mutFilter}}
@icons={{hash right="search"}}
@containerClass="c-channel-members__filter"
placeholder={{this.filterPlaceholder}}
/>
<ul class="c-channel-members__list" {{this.fill}}>
{{#if @channel.chatable.group}}
<li
class="c-channel-members__list-item -add-member"
role="button"
{{on "click" this.addMember}}
{{this.onEnter this.addMember}}
tabindex="0"
>
{{icon "plus"}}
<span>{{this.addMemberLabel}}</span>
</li>
{{/if}}
{{#each this.members as |membership|}}
<li
class="c-channel-members__list-item -member"
{{on "click" (fn this.openMemberCard membership.user)}}
{{this.onEnter (fn this.openMemberCard membership.user)}}
tabindex="0"
>
<ChatUserInfo
@user={{membership.user}}
@avatarSize="tiny"
@interactive={{false}}
@showStatus={{true}}
@showStatusDescription={{true}}
/>
</li>
{{else}}
{{#if this.noResults}}
<ul class="c-channel-members__list" {{this.fill}}>
{{#if @channel.chatable.group}}
<li
class="c-channel-members__list-item -no-results alert alert-info"
class="c-channel-members__list-item -add-member"
role="button"
{{on "click" this.addMember}}
{{this.onEnter this.addMember}}
tabindex="0"
>
{{this.noMembershipsFoundLabel}}
{{icon "plus"}}
<span>{{this.addMemberLabel}}</span>
</li>
{{/if}}
{{/each}}
</ul>
{{#each this.members as |membership|}}
<li
class="c-channel-members__list-item -member"
{{on "click" (fn this.openMemberCard membership.user)}}
{{this.onEnter (fn this.openMemberCard membership.user)}}
tabindex="0"
>
<ChatUserInfo
@user={{membership.user}}
@avatarSize="tiny"
@interactive={{false}}
@showStatus={{true}}
@showStatusDescription={{true}}
/>
</li>
{{else}}
{{#if this.noResults}}
<li
class="c-channel-members__list-item -no-results alert alert-info"
>
{{this.noMembershipsFoundLabel}}
</li>
{{/if}}
{{/each}}
</ul>
<div {{this.loadMore}}>
<br />
<div {{this.loadMore}}>
<br />
</div>
</div>
</div>
{{/if}}
{{/if}}
</div>
</template>
}

View File

@ -12,36 +12,38 @@ export default class ChatRoutesChannelInfoNav extends Component {
}
<template>
{{#if this.showTabs}}
<nav class="c-channel-info__nav">
<ul class="nav nav-pills">
<li>
<LinkTo
@route="chat.channel.info.settings"
@models={{@channel.routeModels}}
class={{if (eq @tab "settings") "active"}}
@replace={{true}}
>
{{i18n "chat.channel_info.tabs.settings"}}
</LinkTo>
</li>
<li>
<LinkTo
@route="chat.channel.info.members"
@models={{@channel.routeModels}}
class={{if (eq @tab "members") "active"}}
@replace={{true}}
>
{{i18n "chat.channel_info.tabs.members"}}
{{#if @channel.isCategoryChannel}}
<span
class="c-channel-info__member-count"
>({{@channel.membershipsCount}})</span>
{{/if}}
</LinkTo>
</li>
</ul>
</nav>
{{/if}}
<div class="c-routes --channel-info-nav">
{{#if this.showTabs}}
<nav class="c-channel-info__nav">
<ul class="nav nav-pills">
<li>
<LinkTo
@route="chat.channel.info.settings"
@models={{@channel.routeModels}}
class={{if (eq @tab "settings") "active"}}
@replace={{true}}
>
{{i18n "chat.channel_info.tabs.settings"}}
</LinkTo>
</li>
<li>
<LinkTo
@route="chat.channel.info.members"
@models={{@channel.routeModels}}
class={{if (eq @tab "members") "active"}}
@replace={{true}}
>
{{i18n "chat.channel_info.tabs.members"}}
{{#if @channel.isCategoryChannel}}
<span
class="c-channel-info__member-count"
>({{@channel.membershipsCount}})</span>
{{/if}}
</LinkTo>
</li>
</ul>
</nav>
{{/if}}
</div>
</template>
}

View File

@ -327,280 +327,283 @@ export default class ChatRouteChannelInfoSettings extends Component {
}
<template>
<div class="c-channel-settings">
<ChatForm as |form|>
<form.section @title={{this.titleSectionTitle}} as |section|>
<section.row>
<:default>
<div class="c-channel-settings__name">
{{replaceEmoji @channel.title}}
</div>
{{#if @channel.isCategoryChannel}}
<div class="c-channel-settings__slug">
<LinkTo
@route="chat.channel"
@models={{@channel.routeModels}}
>
/chat/c/{{@channel.slug}}/{{@channel.id}}
</LinkTo>
</div>
{{/if}}
</:default>
<:action>
{{#if this.canEditChannel}}
<DButton
@label="chat.channel_settings.edit"
@action={{this.onEditChannelTitle}}
class="edit-name-slug-btn btn-flat"
/>
{{/if}}
</:action>
</section.row>
</form.section>
{{#if this.shouldRenderDescriptionSection}}
<form.section @title={{this.descriptionSectionTitle}} as |section|>
<div class="c-routes --channel-info-settings">
<div class="c-channel-settings">
<ChatForm as |form|>
<form.section @title={{this.titleSectionTitle}} as |section|>
<section.row>
<:default>
{{#if @channel.description.length}}
{{@channel.description}}
{{else}}
{{this.descriptionPlaceholder}}
<div class="c-channel-settings__name">
{{replaceEmoji @channel.title}}
</div>
{{#if @channel.isCategoryChannel}}
<div class="c-channel-settings__slug">
<LinkTo
@route="chat.channel"
@models={{@channel.routeModels}}
>
/chat/c/{{@channel.slug}}/{{@channel.id}}
</LinkTo>
</div>
{{/if}}
</:default>
<:action>
{{#if this.canEditChannel}}
<DButton
@label={{if
@channel.description.length
"chat.channel_settings.edit"
"chat.channel_settings.add"
}}
@action={{this.onEditChannelDescription}}
class="edit-description-btn btn-flat"
@label="chat.channel_settings.edit"
@action={{this.onEditChannelTitle}}
class="edit-name-slug-btn btn-flat"
/>
{{/if}}
</:action>
</section.row>
</form.section>
{{/if}}
{{#if this.site.mobileView}}
<form.section as |section|>
<section.row
@label={{this.membersLabel}}
@route="chat.channel.info.members"
@routeModels={{@channel.routeModels}}
/>
</form.section>
{{/if}}
{{#if this.shouldRenderDescriptionSection}}
<form.section @title={{this.descriptionSectionTitle}} as |section|>
<section.row>
<:default>
{{#if @channel.description.length}}
{{@channel.description}}
{{else}}
{{this.descriptionPlaceholder}}
{{/if}}
</:default>
{{#if @channel.isOpen}}
<form.section @title={{this.settingsSectionTitle}} as |section|>
<section.row @label={{this.muteSectionLabel}}>
<:action>
<DToggleSwitch
@state={{@channel.currentUserMembership.muted}}
class="c-channel-settings__mute-switch"
{{on "click" this.onToggleMuted}}
/>
</:action>
</section.row>
{{#if this.shouldRenderDesktopNotificationsLevelSection}}
<section.row @label={{this.desktopNotificationsLevelLabel}}>
<:action>
<ComboBox
@content={{this.notificationLevels}}
@value={{@channel.currentUserMembership.desktopNotificationLevel}}
@valueProperty="value"
@onChange={{fn
this.saveNotificationSettings
"desktopNotificationLevel"
"desktop_notification_level"
}}
class="c-channel-settings__selector c-channel-settings__desktop-notifications-selector"
/>
{{#if this.canEditChannel}}
<DButton
@label={{if
@channel.description.length
"chat.channel_settings.edit"
"chat.channel_settings.add"
}}
@action={{this.onEditChannelDescription}}
class="edit-description-btn btn-flat"
/>
{{/if}}
</:action>
</section.row>
{{/if}}
{{#if this.shouldRenderMobileNotificationsLevelSection}}
<section.row @label={{this.mobileNotificationsLevelLabel}}>
<:action>
<ComboBox
@content={{this.notificationLevels}}
@value={{@channel.currentUserMembership.mobileNotificationLevel}}
@valueProperty="value"
@onChange={{fn
this.saveNotificationSettings
"mobileNotificationLevel"
"mobile_notification_level"
}}
class="c-channel-settings__selector c-channel-settings__mobile-notifications-selector"
/>
</:action>
</section.row>
{{/if}}
</form.section>
{{/if}}
<form.section @title={{this.channelInfoSectionTitle}} as |section|>
{{#if @channel.isCategoryChannel}}
<section.row @label={{this.categoryLabel}}>
{{categoryBadge
@channel.chatable
link=true
allowUncategorized=true
}}
</section.row>
</form.section>
{{/if}}
<section.row @label={{this.historyLabel}}>
<ChatRetentionReminderText @channel={{@channel}} @type="short" />
</section.row>
</form.section>
{{#if this.site.mobileView}}
<form.section as |section|>
<section.row
@label={{this.membersLabel}}
@route="chat.channel.info.members"
@routeModels={{@channel.routeModels}}
/>
</form.section>
{{/if}}
{{#if this.shouldRenderAdminSection}}
<form.section
@title={{this.adminSectionTitle}}
data-section="admin"
as |section|
>
{{#if this.autoJoinAvailable}}
<section.row @label={{this.autoJoinLabel}}>
{{#if @channel.isOpen}}
<form.section @title={{this.settingsSectionTitle}} as |section|>
<section.row @label={{this.muteSectionLabel}}>
<:action>
<DToggleSwitch
@state={{@channel.autoJoinUsers}}
class="c-channel-settings__auto-join-switch"
{{on
"click"
(fn this.onToggleAutoJoinUsers @channel.autoJoinUsers)
}}
@state={{@channel.currentUserMembership.muted}}
class="c-channel-settings__mute-switch"
{{on "click" this.onToggleMuted}}
/>
</:action>
</section.row>
{{/if}}
{{#if this.toggleChannelWideMentionsAvailable}}
<section.row @label={{this.channelWideMentionsLabel}}>
<:action>
<DToggleSwitch
class="c-channel-settings__channel-wide-mentions"
@state={{@channel.allowChannelWideMentions}}
{{on
"click"
(fn
this.onToggleChannelWideMentions
@channel.allowChannelWideMentions
)
}}
/>
</:action>
<:description>
{{this.channelWideMentionsDescription}}
</:description>
</section.row>
{{/if}}
{{#if this.toggleThreadingAvailable}}
<section.row @label={{this.toggleThreadingLabel}}>
<:action>
<DToggleSwitch
@state={{@channel.threadingEnabled}}
class="c-channel-settings__threading-switch"
{{on
"click"
(fn
this.onToggleThreadingEnabled @channel.threadingEnabled
)
}}
/>
</:action>
<:description>
{{this.toggleThreadingDescription}}
</:description>
</section.row>
{{/if}}
{{#if this.shouldRenderStatusSection}}
{{#if this.shouldRenderArchiveRow}}
<section.row>
{{#if this.shouldRenderDesktopNotificationsLevelSection}}
<section.row @label={{this.desktopNotificationsLevelLabel}}>
<:action>
<DButton
@action={{this.onArchiveChannel}}
@label="chat.channel_settings.archive_channel"
@icon="archive"
class="archive-btn chat-form__btn btn-transparent"
<ComboBox
@content={{this.notificationLevels}}
@value={{@channel.currentUserMembership.desktopNotificationLevel}}
@valueProperty="value"
@onChange={{fn
this.saveNotificationSettings
"desktopNotificationLevel"
"desktop_notification_level"
}}
class="c-channel-settings__selector c-channel-settings__desktop-notifications-selector"
/>
</:action>
</section.row>
{{/if}}
<section.row>
<:action>
{{#if @channel.isOpen}}
<DButton
@action={{this.onToggleChannelState}}
@label="chat.channel_settings.close_channel"
@icon="lock"
class="close-btn chat-form__btn btn-transparent"
{{#if this.shouldRenderMobileNotificationsLevelSection}}
<section.row @label={{this.mobileNotificationsLevelLabel}}>
<:action>
<ComboBox
@content={{this.notificationLevels}}
@value={{@channel.currentUserMembership.mobileNotificationLevel}}
@valueProperty="value"
@onChange={{fn
this.saveNotificationSettings
"mobileNotificationLevel"
"mobile_notification_level"
}}
class="c-channel-settings__selector c-channel-settings__mobile-notifications-selector"
/>
{{else}}
<DButton
@action={{this.onToggleChannelState}}
@label="chat.channel_settings.open_channel"
@icon="unlock"
class="open-btn chat-form__btn btn-transparent"
/>
{{/if}}
</:action>
</section.row>
</:action>
</section.row>
{{/if}}
</form.section>
{{/if}}
<section.row>
<:action>
<DButton
@action={{this.onDeleteChannel}}
@label="chat.channel_settings.delete_channel"
@icon="trash-alt"
class="delete-btn chat-form__btn btn-transparent"
/>
</:action>
<form.section @title={{this.channelInfoSectionTitle}} as |section|>
{{#if @channel.isCategoryChannel}}
<section.row @label={{this.categoryLabel}}>
{{categoryBadge
@channel.chatable
link=true
allowUncategorized=true
}}
</section.row>
{{/if}}
<section.row @label={{this.historyLabel}}>
<ChatRetentionReminderText @channel={{@channel}} @type="short" />
</section.row>
</form.section>
{{/if}}
<form.section class="--leave-channel" as |section|>
{{#if @channel.chatable.group}}
<div class="c-channel-settings__leave-info">
{{icon "exclamation-triangle"}}
{{i18n "chat.channel_settings.leave_groupchat_info"}}
</div>
{{#if this.shouldRenderAdminSection}}
<form.section
@title={{this.adminSectionTitle}}
data-section="admin"
as |section|
>
{{#if this.autoJoinAvailable}}
<section.row @label={{this.autoJoinLabel}}>
<:action>
<DToggleSwitch
@state={{@channel.autoJoinUsers}}
class="c-channel-settings__auto-join-switch"
{{on
"click"
(fn this.onToggleAutoJoinUsers @channel.autoJoinUsers)
}}
/>
</:action>
</section.row>
{{/if}}
{{#if this.toggleChannelWideMentionsAvailable}}
<section.row @label={{this.channelWideMentionsLabel}}>
<:action>
<DToggleSwitch
class="c-channel-settings__channel-wide-mentions"
@state={{@channel.allowChannelWideMentions}}
{{on
"click"
(fn
this.onToggleChannelWideMentions
@channel.allowChannelWideMentions
)
}}
/>
</:action>
<:description>
{{this.channelWideMentionsDescription}}
</:description>
</section.row>
{{/if}}
{{#if this.toggleThreadingAvailable}}
<section.row @label={{this.toggleThreadingLabel}}>
<:action>
<DToggleSwitch
@state={{@channel.threadingEnabled}}
class="c-channel-settings__threading-switch"
{{on
"click"
(fn
this.onToggleThreadingEnabled
@channel.threadingEnabled
)
}}
/>
</:action>
<:description>
{{this.toggleThreadingDescription}}
</:description>
</section.row>
{{/if}}
{{#if this.shouldRenderStatusSection}}
{{#if this.shouldRenderArchiveRow}}
<section.row>
<:action>
<DButton
@action={{this.onArchiveChannel}}
@label="chat.channel_settings.archive_channel"
@icon="archive"
class="archive-btn chat-form__btn btn-transparent"
/>
</:action>
</section.row>
{{/if}}
<section.row>
<:action>
{{#if @channel.isOpen}}
<DButton
@action={{this.onToggleChannelState}}
@label="chat.channel_settings.close_channel"
@icon="lock"
class="close-btn chat-form__btn btn-transparent"
/>
{{else}}
<DButton
@action={{this.onToggleChannelState}}
@label="chat.channel_settings.open_channel"
@icon="unlock"
class="open-btn chat-form__btn btn-transparent"
/>
{{/if}}
</:action>
</section.row>
<section.row>
<:action>
<DButton
@action={{this.onDeleteChannel}}
@label="chat.channel_settings.delete_channel"
@icon="trash-alt"
class="delete-btn chat-form__btn btn-transparent"
/>
</:action>
</section.row>
{{/if}}
</form.section>
{{/if}}
<section.row>
<:action>
<ToggleChannelMembershipButton
@channel={{@channel}}
@onLeave={{this.onLeaveChannel}}
@options={{hash
joinClass="btn-primary"
leaveClass="btn-danger"
joinIcon="sign-in-alt"
leaveIcon="sign-out-alt"
}}
/>
</:action>
</section.row>
</form.section>
</ChatForm>
<form.section class="--leave-channel" as |section|>
{{#if @channel.chatable.group}}
<div class="c-channel-settings__leave-info">
{{icon "exclamation-triangle"}}
{{i18n "chat.channel_settings.leave_groupchat_info"}}
</div>
{{/if}}
<section.row>
<:action>
<ToggleChannelMembershipButton
@channel={{@channel}}
@onLeave={{this.onLeaveChannel}}
@options={{hash
joinClass="btn-primary"
leaveClass="btn-danger"
joinIcon="sign-in-alt"
leaveIcon="sign-out-alt"
}}
/>
</:action>
</section.row>
</form.section>
</ChatForm>
</div>
</div>
</template>
}

View File

@ -30,7 +30,7 @@ export default class ChatRoutesChannelInfo extends Component {
}
<template>
<div class="c-routes-channel-info">
<div class="c-routes --channel-info">
<Navbar as |navbar|>
{{#if this.chatChannelInfoRouteOriginManager.isBrowse}}
<navbar.BackButton

View File

@ -14,7 +14,7 @@ export default class ChatRoutesChannelThread extends Component {
}
<template>
<div class="c-routes-channel-thread">
<div class="c-routes --channel-thread">
{{#each (array @thread) as |thread|}}
<ThreadHeader
@thread={{thread}}

View File

@ -2,7 +2,7 @@ import ChatThreadListHeader from "discourse/plugins/chat/discourse/components/ch
import ChatThreadList from "discourse/plugins/chat/discourse/components/chat-thread-list";
const ChatRoutesChannelThreads = <template>
<div class="c-routes-channel-threads">
<div class="c-routes --channel-threads">
<ChatThreadListHeader @channel={{@channel}} />
<ChatThreadList @channel={{@channel}} @includeHeader={{true}} />
</div>

View File

@ -14,7 +14,7 @@ export default class ChatRoutesChannel extends Component {
}
<template>
<div class="c-routes-channel">
<div class="c-routes --channel">
<Navbar as |navbar|>
{{#if this.site.mobileView}}
<navbar.BackButton @route={{this.getChannelsRoute}} />

View File

@ -8,7 +8,7 @@ export default class ChatRoutesChannels extends Component {
@service site;
<template>
<div class="c-routes-channels">
<div class="c-routes --channels">
<Navbar as |navbar|>
<navbar.Title @title={{i18n "chat.chat_channels"}} />
<navbar.Actions as |action|>

View File

@ -8,7 +8,7 @@ export default class ChatRoutesDirectMessages extends Component {
@service site;
<template>
<div class="c-routes-direct-messages">
<div class="c-routes --direct-messages">
<Navbar as |navbar|>
<navbar.Title @title={{i18n "chat.direct_messages.title"}} />
<navbar.Actions as |action|>

View File

@ -8,7 +8,7 @@ export default class ChatRoutesThreads extends Component {
@service site;
<template>
<div class="c-routes-threads">
<div class="c-routes --threads">
<Navbar as |navbar|>
<navbar.Title @title={{i18n "chat.my_threads.title"}} />

View File

@ -78,10 +78,16 @@ export default class ChatChannelComposer extends Service {
message.channel.resetDraft(this.currentUser);
await this.router.transitionTo(
"chat.channel.thread",
...message.thread.routeModels
);
try {
await this.router.transitionTo(
"chat.channel.thread",
...message.thread.routeModels
);
} catch (e) {
if (e.name !== "TransitionAborted") {
throw e;
}
}
this.threadComposer.focus({ ensureAtEnd: true, refreshHeight: true });
} else {

View File

@ -1,16 +1,43 @@
import { tracked } from "@glimmer/tracking";
import Service, { service } from "@ember/service";
import ChatDrawerRoutesBrowse from "discourse/plugins/chat/discourse/components/chat/drawer-routes/browse";
import ChatDrawerRoutesChannel from "discourse/plugins/chat/discourse/components/chat/drawer-routes/channel";
import ChatDrawerRoutesChannelInfoMembers from "discourse/plugins/chat/discourse/components/chat/drawer-routes/channel-info-members";
import ChatDrawerRoutesChannelInfoSettings from "discourse/plugins/chat/discourse/components/chat/drawer-routes/channel-info-settings";
import ChatDrawerRoutesChannelThread from "discourse/plugins/chat/discourse/components/chat/drawer-routes/channel-thread";
import ChatDrawerRoutesChannelThreads from "discourse/plugins/chat/discourse/components/chat/drawer-routes/channel-threads";
import ChatDrawerRoutesChannels from "discourse/plugins/chat/discourse/components/chat/drawer-routes/channels";
import ChatDrawerRoutesDirectMessages from "discourse/plugins/chat/discourse/components/chat/drawer-routes/direct-messages";
import ChatDrawerRoutesMembers from "discourse/plugins/chat/discourse/components/chat/drawer-routes/members";
import ChatDrawerRoutesSettings from "discourse/plugins/chat/discourse/components/chat/drawer-routes/settings";
import ChatDrawerRoutesThreads from "discourse/plugins/chat/discourse/components/chat/drawer-routes/threads";
const ROUTES = {
chat: { name: ChatDrawerRoutesChannels },
"chat.index": { name: ChatDrawerRoutesChannels },
// order matters, non index before index
"chat.browse": {
name: ChatDrawerRoutesBrowse,
extractParams: () => ({ currentTab: "all" }),
},
"chat.browse.index": {
name: ChatDrawerRoutesBrowse,
extractParams: () => ({ currentTab: "all" }),
},
"chat.browse.open": {
name: ChatDrawerRoutesBrowse,
extractParams: (r) => ({ currentTab: r.localName }),
},
"chat.browse.archived": {
name: ChatDrawerRoutesBrowse,
extractParams: (r) => ({ currentTab: r.localName }),
},
"chat.browse.closed": {
name: ChatDrawerRoutesBrowse,
extractParams: (r) => ({ currentTab: r.localName }),
},
"chat.browse.all": {
name: ChatDrawerRoutesBrowse,
extractParams: (r) => ({ currentTab: r.localName }),
},
"chat.channels": { name: ChatDrawerRoutesChannels },
"chat.channel": { name: ChatDrawerRoutesChannel },
"chat.channel.index": { name: ChatDrawerRoutesChannel },
@ -56,7 +83,6 @@ const ROUTES = {
"chat.threads": {
name: ChatDrawerRoutesThreads,
},
chat: { name: ChatDrawerRoutesChannels },
"chat.channel.near-message": {
name: ChatDrawerRoutesChannel,
extractParams: (route) => {
@ -76,7 +102,7 @@ const ROUTES = {
},
},
"chat.channel.info.settings": {
name: ChatDrawerRoutesSettings,
name: ChatDrawerRoutesChannelInfoSettings,
extractParams: (route) => {
return {
channelId: route.parent.params.channelId,
@ -84,7 +110,7 @@ const ROUTES = {
},
},
"chat.channel.info.members": {
name: ChatDrawerRoutesMembers,
name: ChatDrawerRoutesChannelInfoMembers,
extractParams: (route) => {
return {
channelId: route.parent.params.channelId,

View File

@ -1 +1 @@
<Chat::Routes::Browse @status="all" />
<BrowseChannels @currentTab="all" />

View File

@ -1 +1 @@
<Chat::Routes::Browse @status="archived" />
<BrowseChannels @currentTab="archived" />

View File

@ -1 +1 @@
<Chat::Routes::Browse @status="closed" />
<BrowseChannels @currentTab="closed" />

View File

@ -1 +1 @@
<Chat::Routes::Browse @status="open" />
<BrowseChannels @currentTab="open" />

View File

@ -1 +1,13 @@
{{outlet}}
<div class="c-routes --browse">
<Chat::Navbar as |navbar|>
<navbar.BackButton />
<navbar.Title @title={{i18n "chat.browse.title"}} />
<navbar.Actions as |a|>
<a.NewChannelButton />
<a.OpenDrawerButton />
</navbar.Actions>
</Chat::Navbar>
{{outlet}}
</div>

View File

@ -35,6 +35,16 @@
justify-content: space-between;
align-items: end;
.c-drawer-routes.--browse & {
flex-direction: column;
gap: 1rem;
align-items: flex-start;
.filter-input {
width: 100%;
}
}
@include breakpoint(tablet) {
flex-direction: column;

View File

@ -0,0 +1,6 @@
.c-drawer-routes {
display: flex;
flex-direction: column;
flex: 1 0 auto;
height: 100%;
}

View File

@ -2,6 +2,7 @@
@import "chat-height-mixin";
@import "base-common";
@import "sidebar-extensions";
@import "chat-drawer-routes";
@import "chat-browse";
@import "chat-channel";
@import "chat-channel-card";

View File

@ -1,7 +1,7 @@
.c-navbar-container {
.chat-drawer &,
.c-routes-channel-thread &,
.c-routes-channel-info & {
.c-routes-channel.--thread &,
.c-routes-channel.--info & {
padding-inline: 0;
}
}

View File

@ -21,7 +21,7 @@ html.has-full-page-chat {
&.has-side-panel-expanded {
grid-template-columns: 1fr;
.c-routes-channel {
.c-routes.--channel {
display: none;
}
}

View File

@ -8,9 +8,9 @@
}
}
.c-routes-direct-messages,
.c-routes-channels,
.c-routes-threads {
.c-routes.--direct-messages,
.c-routes.--channels,
.c-routes.--threads {
background: var(--primary-very-low);
max-width: 100vw;
}

View File

@ -1,5 +1,5 @@
.chat-message-thread-indicator {
.c-routes-threads & {
.c-routes.--threads & {
background: var(--secondary);
}
grid-template-areas:

View File

@ -0,0 +1,24 @@
# frozen_string_literal: true
RSpec.describe "Drawer - Browse", type: :system do
fab!(:current_user) { Fabricate(:user) }
let(:drawer_page) { PageObjects::Pages::ChatDrawer.new }
fab!(:channel_1) { Fabricate(:chat_channel) }
before do
chat_system_bootstrap
sign_in(current_user)
end
it "can change status" do
drawer_page.visit_browse
expect(drawer_page.browse).to have_channel(name: channel_1.name)
drawer_page.browse.change_status("closed")
expect(drawer_page.browse).to have_no_channel(name: channel_1.name)
end
end

View File

@ -42,4 +42,13 @@ RSpec.describe "Drawer - index", type: :system do
expect(row).to be_non_existent
end
it "can open browse" do
channel = Fabricate(:chat_channel)
drawer_page.visit_index
drawer_page.channels_index.open_browse
expect(drawer_page.browse).to have_channel(name: channel.name)
end
end

View File

@ -9,8 +9,8 @@ describe "Using #hashtag autocompletion to search for and lookup channels", type
fab!(:topic)
fab!(:post) { Fabricate(:post, topic: topic) }
fab!(:message1) { Fabricate(:chat_message, chat_channel: channel1) }
let(:chat_page) { PageObjects::Pages::Chat.new }
let(:chat_drawer_page) { PageObjects::Pages::ChatDrawer.new }
let(:chat_channel_page) { PageObjects::Pages::ChatChannel.new }
let(:topic_page) { PageObjects::Pages::Topic.new }

View File

@ -5,7 +5,7 @@ RSpec.describe "Message notifications - mobile", type: :system, mobile: true do
let!(:chat_page) { PageObjects::Pages::Chat.new }
let!(:chat_channel_page) { PageObjects::Pages::ChatChannel.new }
let!(:channel_index_page) { PageObjects::Components::Chat::ChannelIndex.new }
let!(:channels_index_page) { PageObjects::Components::Chat::ChannelsIndex.new }
before do
SiteSetting.navigation_menu = "sidebar"
@ -35,7 +35,7 @@ RSpec.describe "Message notifications - mobile", type: :system, mobile: true do
create_message(channel_1, user: user_1)
expect(page).to have_no_css(".chat-header-icon .chat-channel-unread-indicator")
expect(page).to have_no_css(channel_index_page.channel_row_selector(channel_1))
expect(page).to have_no_css(channels_index_page.channel_row_selector(channel_1))
end
end
end
@ -73,7 +73,7 @@ RSpec.describe "Message notifications - mobile", type: :system, mobile: true do
create_message(channel_1, user: user_1)
expect(page).to have_no_css(".chat-header-icon .chat-channel-unread-indicator")
expect(channel_index_page).to have_no_unread_channel(channel_1)
expect(channels_index_page).to have_no_unread_channel(channel_1)
end
end
end
@ -85,7 +85,7 @@ RSpec.describe "Message notifications - mobile", type: :system, mobile: true do
create_message(channel_1, user: user_1)
expect(page).to have_css(".chat-header-icon .chat-channel-unread-indicator", text: "")
expect(channel_index_page).to have_unread_channel(channel_1)
expect(channels_index_page).to have_unread_channel(channel_1)
end
end
@ -102,7 +102,7 @@ RSpec.describe "Message notifications - mobile", type: :system, mobile: true do
)
expect(page).to have_css(".chat-header-icon .chat-channel-unread-indicator")
expect(channel_index_page).to have_unread_channel(channel_1, count: 1)
expect(channels_index_page).to have_unread_channel(channel_1, count: 1)
end
it "shows correct count when there are multiple messages but only 1 is urgent" do
@ -122,7 +122,7 @@ RSpec.describe "Message notifications - mobile", type: :system, mobile: true do
".chat-header-icon .chat-channel-unread-indicator",
text: "1",
)
expect(channel_index_page).to have_unread_channel(channel_1, count: 1)
expect(channels_index_page).to have_unread_channel(channel_1, count: 1)
end
end
end
@ -147,7 +147,7 @@ RSpec.describe "Message notifications - mobile", type: :system, mobile: true do
text: "1",
wait: 25,
)
expect(channel_index_page).to have_unread_channel(dm_channel_1, wait: 25)
expect(channels_index_page).to have_unread_channel(dm_channel_1, wait: 25)
create_message(dm_channel_1, user: user_1)
@ -198,13 +198,13 @@ RSpec.describe "Message notifications - mobile", type: :system, mobile: true do
create_message(channel_1, user: user_1)
expect(page).to have_css(".chat-header-icon .chat-channel-unread-indicator", text: "")
expect(channel_index_page).to have_unread_channel(channel_1)
expect(channels_index_page).to have_unread_channel(channel_1)
visit("/chat/direct-messages")
create_message(dm_channel_1, user: user_1)
expect(channel_index_page).to have_unread_channel(dm_channel_1)
expect(channels_index_page).to have_unread_channel(dm_channel_1)
expect(page).to have_css(".chat-header-icon .chat-channel-unread-indicator", text: "1")
end
end

View File

@ -305,25 +305,13 @@ RSpec.describe "Navigation", type: :system do
end
end
context "when opening browse page from drawer in drawer mode" do
it "opens browser page in full page" do
visit("/")
chat_page.open_from_header
chat_drawer_page.open_browse
expect(page).to have_current_path("/chat/browse/open")
expect(page).not_to have_css(".chat-drawer.is-expanded")
end
end
context "when opening browse page from sidebar in drawer mode" do
it "opens browser page in full page" do
visit("/")
chat_page.open_from_header
sidebar_page.open_browse
expect(page).to have_current_path("/chat/browse/open")
expect(page).not_to have_css(".chat-drawer.is-expanded")
expect(chat_drawer_page.browse).to have_channel(name: category_channel.name)
end
end

View File

@ -3,8 +3,19 @@
module PageObjects
module Pages
class ChatBrowse < PageObjects::Pages::Base
SELECTOR = ".c-routes.--browse"
def initialize(context = SELECTOR)
@context = context
end
def component
find(".chat-browse-view")
find("#{@context} .chat-browse-view")
end
def change_status(status = "all")
component.find(".chat-browse-view__filter.-#{status}").click
has_finished_loading?
end
def has_finished_loading?

View File

@ -4,11 +4,11 @@ module PageObjects
module Pages
class ChatChannelThreads < PageObjects::Pages::Base
def close
find(".c-routes-channel-threads .c-navbar__close-threads-button").click
find(".c-routes.--channel-threads .c-navbar__close-threads-button").click
end
def back
find(".c-routes-channel-threads .c-navbar__back-button").click
find(".c-routes.--channel-threads .c-navbar__back-button").click
end
end
end

View File

@ -17,7 +17,7 @@ module PageObjects
end
def header
@header ||= PageObjects::Components::Chat::ThreadHeader.new(".c-routes-channel-thread")
@header ||= PageObjects::Components::Chat::ThreadHeader.new(".c-routes.--channel-thread")
end
def notifications_button

View File

@ -3,10 +3,10 @@
module PageObjects
module Components
module Chat
class ChannelIndex < PageObjects::Components::Base
class ChannelsIndex < PageObjects::Components::Base
attr_reader :context
SELECTOR = ".channels-list-container"
SELECTOR = ".c-drawer-routes.--channels"
def initialize(context = nil)
@context = context
@ -17,6 +17,10 @@ module PageObjects
find(context).find(SELECTOR)
end
def open_browse
component.find(".open-browse-page-btn").click
end
def open_channel(channel)
component.find("#{channel_row_selector(channel)}").click
end

View File

@ -5,7 +5,7 @@ module PageObjects
class UserThreads < PageObjects::Pages::Base
def has_threads?(count: nil)
has_no_css?(".spinner")
has_css?(".c-user-thread", count: count)
has_css?(".c-user-thread", count: count, visible: :all)
end
def open_thread(thread)

View File

@ -5,8 +5,12 @@ module PageObjects
class ChatDrawer < PageObjects::Pages::Base
VISIBLE_DRAWER = ".chat-drawer.is-expanded"
def channel_index
@channel_index ||= ::PageObjects::Components::Chat::ChannelIndex.new(VISIBLE_DRAWER)
def channels_index
@channels_index ||= ::PageObjects::Components::Chat::ChannelsIndex.new(VISIBLE_DRAWER)
end
def browse
@browse ||= ::PageObjects::Pages::ChatBrowse.new(".c-drawer-routes.--browse")
end
def open_browse
@ -34,17 +38,22 @@ module PageObjects
open_channel(channel)
end
def visit_browse
visit_index
open_browse
end
def open_channel(channel)
channel_index.open_channel(channel)
channels_index.open_channel(channel)
has_no_css?(".chat-skeleton")
end
def has_unread_channel?(channel)
channel_index.has_unread_channel?(channel)
channels_index.has_unread_channel?(channel)
end
def has_no_unread_channel?(channel)
channel_index.has_no_unread_channel?(channel)
channels_index.has_no_unread_channel?(channel)
end
def has_user_threads_section?

View File

@ -102,7 +102,7 @@ describe "Single thread in side panel", type: :system do
it "doesnt show back button " do
chat_page.visit_thread(thread)
expect(page).to have_no_css(".c-routes-channel-thread .c-navbar__back-button")
expect(page).to have_no_css(".c-routes.--channel-thread .c-navbar__back-button")
end
end