mirror of
https://github.com/discourse/discourse.git
synced 2025-01-31 14:03:02 +08:00
FEATURE: load chat channel settings within drawer (#27346)
This change allows chat drawer users to edit channel settings and members without leaving drawer mode. If a channel is open within chat drawer and the user clicks the Channel name, it will load channel settings within the drawer.
This commit is contained in:
parent
6e56a76b20
commit
891fb17f60
|
@ -0,0 +1,60 @@
|
||||||
|
import Component from "@glimmer/component";
|
||||||
|
import { action } from "@ember/object";
|
||||||
|
import didInsert from "@ember/render-modifiers/modifiers/did-insert";
|
||||||
|
import { service } from "@ember/service";
|
||||||
|
import I18n from "discourse-i18n";
|
||||||
|
import Navbar from "discourse/plugins/chat/discourse/components/chat/navbar";
|
||||||
|
import ChannelMembers from "discourse/plugins/chat/discourse/components/chat/routes/channel-info-members";
|
||||||
|
import ChannelInfoNav from "discourse/plugins/chat/discourse/components/chat/routes/channel-info-nav";
|
||||||
|
|
||||||
|
export default class ChatDrawerRoutesMembers extends Component {
|
||||||
|
@service chat;
|
||||||
|
@service chatStateManager;
|
||||||
|
@service chatChannelsManager;
|
||||||
|
|
||||||
|
get backButton() {
|
||||||
|
return {
|
||||||
|
route: "chat.channel",
|
||||||
|
models: this.chat.activeChannel?.routeModels,
|
||||||
|
title: I18n.t("chat.return_to_channel"),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
async fetchChannel() {
|
||||||
|
if (!this.args.params?.channelId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const channel = await this.chatChannelsManager.find(
|
||||||
|
this.args.params.channelId
|
||||||
|
);
|
||||||
|
|
||||||
|
this.chat.activeChannel = channel;
|
||||||
|
}
|
||||||
|
|
||||||
|
<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="members" />
|
||||||
|
<ChannelMembers @channel={{this.chat.activeChannel}} />
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
</template>
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
import Component from "@glimmer/component";
|
||||||
|
import { action } from "@ember/object";
|
||||||
|
import didInsert from "@ember/render-modifiers/modifiers/did-insert";
|
||||||
|
import { service } from "@ember/service";
|
||||||
|
import I18n from "discourse-i18n";
|
||||||
|
import Navbar from "discourse/plugins/chat/discourse/components/chat/navbar";
|
||||||
|
import ChannelInfoNav from "discourse/plugins/chat/discourse/components/chat/routes/channel-info-nav";
|
||||||
|
import ChannelSettings from "discourse/plugins/chat/discourse/components/chat/routes/channel-info-settings";
|
||||||
|
|
||||||
|
export default class ChatDrawerRoutesSettings extends Component {
|
||||||
|
@service chat;
|
||||||
|
@service chatStateManager;
|
||||||
|
@service chatChannelsManager;
|
||||||
|
|
||||||
|
get backButton() {
|
||||||
|
return {
|
||||||
|
route: "chat.channel",
|
||||||
|
models: this.chat.activeChannel?.routeModels,
|
||||||
|
title: I18n.t("chat.return_to_channel"),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
async fetchChannel() {
|
||||||
|
if (!this.args.params?.channelId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const channel = await this.chatChannelsManager.find(
|
||||||
|
this.args.params.channelId
|
||||||
|
);
|
||||||
|
|
||||||
|
this.chat.activeChannel = channel;
|
||||||
|
}
|
||||||
|
|
||||||
|
<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"
|
||||||
|
/>
|
||||||
|
<ChannelSettings @channel={{this.chat.activeChannel}} />
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
</template>
|
||||||
|
}
|
|
@ -54,10 +54,7 @@ export default class ChatModalEditChannelName extends Component {
|
||||||
this.channel.title = result.channel.title;
|
this.channel.title = result.channel.title;
|
||||||
this.channel.slug = result.channel.slug;
|
this.channel.slug = result.channel.slug;
|
||||||
await this.args.closeModal();
|
await this.args.closeModal();
|
||||||
await this.router.replaceWith(
|
this.router.replaceWith("chat.channel", ...this.channel.routeModels);
|
||||||
"chat.channel",
|
|
||||||
...this.channel.routeModels
|
|
||||||
);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.flash = extractError(error);
|
this.flash = extractError(error);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
import Component from "@glimmer/component";
|
||||||
|
import { LinkTo } from "@ember/routing";
|
||||||
|
import { service } from "@ember/service";
|
||||||
|
import { eq } from "truth-helpers";
|
||||||
|
import i18n from "discourse-common/helpers/i18n";
|
||||||
|
|
||||||
|
export default class ChatRoutesChannelInfoNav extends Component {
|
||||||
|
@service site;
|
||||||
|
|
||||||
|
get showTabs() {
|
||||||
|
return this.site.desktopView && this.args.channel.isOpen;
|
||||||
|
}
|
||||||
|
|
||||||
|
<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}}
|
||||||
|
</template>
|
||||||
|
}
|
|
@ -1,11 +1,11 @@
|
||||||
import Component from "@glimmer/component";
|
import Component from "@glimmer/component";
|
||||||
import { action } from "@ember/object";
|
import { action } from "@ember/object";
|
||||||
import { LinkTo } from "@ember/routing";
|
|
||||||
import { service } from "@ember/service";
|
import { service } from "@ember/service";
|
||||||
import I18n from "discourse-i18n";
|
import i18n from "discourse-common/helpers/i18n";
|
||||||
import ChatModalEditChannelName from "discourse/plugins/chat/discourse/components/chat/modal/edit-channel-name";
|
import ChatModalEditChannelName from "discourse/plugins/chat/discourse/components/chat/modal/edit-channel-name";
|
||||||
import Navbar from "discourse/plugins/chat/discourse/components/chat/navbar";
|
import Navbar from "discourse/plugins/chat/discourse/components/chat/navbar";
|
||||||
import ChatChannelStatus from "discourse/plugins/chat/discourse/components/chat-channel-status";
|
import ChatChannelStatus from "discourse/plugins/chat/discourse/components/chat-channel-status";
|
||||||
|
import ChannelInfoNav from "./channel-info-nav";
|
||||||
|
|
||||||
export default class ChatRoutesChannelInfo extends Component {
|
export default class ChatRoutesChannelInfo extends Component {
|
||||||
@service chatChannelInfoRouteOriginManager;
|
@service chatChannelInfoRouteOriginManager;
|
||||||
|
@ -13,15 +13,6 @@ export default class ChatRoutesChannelInfo extends Component {
|
||||||
@service modal;
|
@service modal;
|
||||||
@service chatGuardian;
|
@service chatGuardian;
|
||||||
|
|
||||||
membersLabel = I18n.t("chat.channel_info.tabs.members");
|
|
||||||
settingsLabel = I18n.t("chat.channel_info.tabs.settings");
|
|
||||||
backToChannelLabel = I18n.t("chat.channel_info.back_to_all_channels");
|
|
||||||
backToAllChannelsLabel = I18n.t("chat.channel_info.back_to_channel");
|
|
||||||
|
|
||||||
get showTabs() {
|
|
||||||
return this.site.desktopView && this.args.channel.isOpen;
|
|
||||||
}
|
|
||||||
|
|
||||||
get canEditChannel() {
|
get canEditChannel() {
|
||||||
return (
|
return (
|
||||||
this.chatGuardian.canEditChatChannel() &&
|
this.chatGuardian.canEditChatChannel() &&
|
||||||
|
@ -44,13 +35,13 @@ export default class ChatRoutesChannelInfo extends Component {
|
||||||
{{#if this.chatChannelInfoRouteOriginManager.isBrowse}}
|
{{#if this.chatChannelInfoRouteOriginManager.isBrowse}}
|
||||||
<navbar.BackButton
|
<navbar.BackButton
|
||||||
@route="chat.browse"
|
@route="chat.browse"
|
||||||
@title={{this.backToAllChannelsLabel}}
|
@title={{i18n "chat.channel_info.back_to_all_channels"}}
|
||||||
/>
|
/>
|
||||||
{{else}}
|
{{else}}
|
||||||
<navbar.BackButton
|
<navbar.BackButton
|
||||||
@route="chat.channel"
|
@route="chat.channel"
|
||||||
@routeModels={{@channel.routeModels}}
|
@routeModels={{@channel.routeModels}}
|
||||||
@title={{this.backToChannelLabel}}
|
@title={{i18n "chat.channel_info.back_to_channel"}}
|
||||||
/>
|
/>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
<navbar.ChannelTitle @channel={{@channel}} />
|
<navbar.ChannelTitle @channel={{@channel}} />
|
||||||
|
@ -59,36 +50,7 @@ export default class ChatRoutesChannelInfo extends Component {
|
||||||
<ChatChannelStatus @channel={{@channel}} />
|
<ChatChannelStatus @channel={{@channel}} />
|
||||||
|
|
||||||
<div class="c-channel-info">
|
<div class="c-channel-info">
|
||||||
{{#if this.showTabs}}
|
<ChannelInfoNav @channel={{@channel}} />
|
||||||
<nav class="c-channel-info__nav">
|
|
||||||
<ul class="nav nav-pills">
|
|
||||||
<li>
|
|
||||||
<LinkTo
|
|
||||||
@route="chat.channel.info.settings"
|
|
||||||
@model={{@channel}}
|
|
||||||
@replace={{true}}
|
|
||||||
>
|
|
||||||
{{this.settingsLabel}}
|
|
||||||
</LinkTo>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<LinkTo
|
|
||||||
@route="chat.channel.info.members"
|
|
||||||
@model={{@channel}}
|
|
||||||
@replace={{true}}
|
|
||||||
>
|
|
||||||
{{this.membersLabel}}
|
|
||||||
{{#if @channel.isCategoryChannel}}
|
|
||||||
<span
|
|
||||||
class="c-channel-info__member-count"
|
|
||||||
>({{@channel.membershipsCount}})</span>
|
|
||||||
{{/if}}
|
|
||||||
</LinkTo>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
{{outlet}}
|
{{outlet}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -39,6 +39,8 @@ export default class ChatRoute extends DiscourseRoute {
|
||||||
"chat.channel.index",
|
"chat.channel.index",
|
||||||
"chat.channel.near-message",
|
"chat.channel.near-message",
|
||||||
"chat.channel-legacy",
|
"chat.channel-legacy",
|
||||||
|
"chat.channel.info.settings",
|
||||||
|
"chat.channel.info.members",
|
||||||
"chat",
|
"chat",
|
||||||
"chat.index",
|
"chat.index",
|
||||||
];
|
];
|
||||||
|
|
|
@ -97,6 +97,9 @@ export default class ChatChannelsManager extends Service {
|
||||||
}
|
}
|
||||||
|
|
||||||
remove(model) {
|
remove(model) {
|
||||||
|
if (!model) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
this.chatSubscriptionsManager.stopChannelSubscription(model);
|
this.chatSubscriptionsManager.stopChannelSubscription(model);
|
||||||
delete this._cached[model.id];
|
delete this._cached[model.id];
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,8 @@ import ChatDrawerRoutesChannel from "discourse/plugins/chat/discourse/components
|
||||||
import ChatDrawerRoutesChannelThread from "discourse/plugins/chat/discourse/components/chat/drawer-routes/channel-thread";
|
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 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 ChatDrawerRoutesChannels from "discourse/plugins/chat/discourse/components/chat/drawer-routes/channels";
|
||||||
|
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";
|
import ChatDrawerRoutesThreads from "discourse/plugins/chat/discourse/components/chat/drawer-routes/threads";
|
||||||
|
|
||||||
const ROUTES = {
|
const ROUTES = {
|
||||||
|
@ -66,6 +68,22 @@ const ROUTES = {
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"chat.channel.info.settings": {
|
||||||
|
name: ChatDrawerRoutesSettings,
|
||||||
|
extractParams: (route) => {
|
||||||
|
return {
|
||||||
|
channelId: route.parent.params.channelId,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"chat.channel.info.members": {
|
||||||
|
name: ChatDrawerRoutesMembers,
|
||||||
|
extractParams: (route) => {
|
||||||
|
return {
|
||||||
|
channelId: route.parent.params.channelId,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
"chat.channel-legacy": {
|
"chat.channel-legacy": {
|
||||||
name: ChatDrawerRoutesChannel,
|
name: ChatDrawerRoutesChannel,
|
||||||
extractParams: (route) => {
|
extractParams: (route) => {
|
||||||
|
|
|
@ -43,6 +43,19 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.chat-drawer-container .c-channel-settings,
|
||||||
|
.chat-drawer-container .c-channel-info__nav,
|
||||||
|
.chat-drawer-container .c-channel-members,
|
||||||
|
.chat-drawer-container .chat-message-creator-container {
|
||||||
|
padding: 1rem;
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-drawer-container .c-channel-info__nav,
|
||||||
|
.chat-drawer-container .c-channel-info__nav .nav-pills {
|
||||||
|
padding-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.chat-drawer-container .c-footer .chat-channel-unread-indicator.-urgent {
|
.chat-drawer-container .c-footer .chat-channel-unread-indicator.-urgent {
|
||||||
width: min-content;
|
width: min-content;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ RSpec.describe "Drawer", type: :system do
|
||||||
before do
|
before do
|
||||||
chat_system_bootstrap
|
chat_system_bootstrap
|
||||||
sign_in(current_user)
|
sign_in(current_user)
|
||||||
|
chat_page.prefers_drawer
|
||||||
end
|
end
|
||||||
|
|
||||||
context "when on channel" do
|
context "when on channel" do
|
||||||
|
@ -18,13 +19,32 @@ RSpec.describe "Drawer", type: :system do
|
||||||
end
|
end
|
||||||
|
|
||||||
context "when clicking channel title" do
|
context "when clicking channel title" do
|
||||||
it "opens channel settings page" do
|
before do
|
||||||
visit("/")
|
visit("/")
|
||||||
chat_page.open_from_header
|
chat_page.open_from_header
|
||||||
drawer_page.open_channel(channel)
|
drawer_page.open_channel(channel)
|
||||||
page.find(".c-navbar__channel-title").click
|
page.find(".c-navbar__channel-title").click
|
||||||
|
end
|
||||||
|
|
||||||
expect(page).to have_current_path("/chat/c/#{channel.slug}/#{channel.id}/info/settings")
|
it "opens channel settings page" do
|
||||||
|
expect(drawer_page).to have_channel_settings
|
||||||
|
end
|
||||||
|
|
||||||
|
it "has tabs for settings and members" do
|
||||||
|
expect(drawer_page).to have_css(".c-channel-info__nav li a", text: "Settings")
|
||||||
|
expect(drawer_page).to have_css(".c-channel-info__nav li a", text: "Members")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "opens correct tab when clicked" do
|
||||||
|
page.find(".c-channel-info__nav li a", text: "Members").click
|
||||||
|
expect(drawer_page).to have_channel_members
|
||||||
|
|
||||||
|
page.find(".c-channel-info__nav li a", text: "Settings").click
|
||||||
|
expect(drawer_page).to have_channel_settings
|
||||||
|
end
|
||||||
|
|
||||||
|
it "has a back button" do
|
||||||
|
expect(drawer_page).to have_css(".c-navbar__back-button")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -88,6 +88,14 @@ module PageObjects
|
||||||
has_css?("#{VISIBLE_DRAWER} .chat-channel[data-id='#{channel.id}']")
|
has_css?("#{VISIBLE_DRAWER} .chat-channel[data-id='#{channel.id}']")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def has_channel_settings?
|
||||||
|
has_css?("#{VISIBLE_DRAWER} .c-channel-settings")
|
||||||
|
end
|
||||||
|
|
||||||
|
def has_channel_members?
|
||||||
|
has_css?("#{VISIBLE_DRAWER} .c-channel-members")
|
||||||
|
end
|
||||||
|
|
||||||
def has_open_thread_list?
|
def has_open_thread_list?
|
||||||
has_css?("#{VISIBLE_DRAWER} .chat-thread-list")
|
has_css?("#{VISIBLE_DRAWER} .chat-thread-list")
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue
Block a user