mirror of
https://github.com/discourse/discourse.git
synced 2025-02-25 18:55:32 -06:00
DEV: routable chat part 2 (#20232)
This commit is expanding on previous work making everything chat working through an URL. Improves drawer templates to be all URLs Implements some kind of router for the drawer Removes few remaining actions for opening channels
This commit is contained in:
parent
e636abeb0d
commit
f12724b5a5
@ -18,6 +18,7 @@ export default Component.extend({
|
||||
searchIndex: 0,
|
||||
loading: false,
|
||||
chatChannelsManager: service(),
|
||||
router: service(),
|
||||
|
||||
didInsertElement() {
|
||||
this._super(...arguments);
|
||||
@ -103,13 +104,13 @@ export default Component.extend({
|
||||
return this.fetchOrCreateChannelForUser(channel).then((response) => {
|
||||
const newChannel = this.chatChannelsManager.store(response.channel);
|
||||
return this.chatChannelsManager.follow(newChannel).then((c) => {
|
||||
this.chat.openChannel(c);
|
||||
this.router.transitionTo("chat.channel", ...c.routeModels);
|
||||
this.close();
|
||||
});
|
||||
});
|
||||
} else {
|
||||
return this.chatChannelsManager.follow(channel).then((c) => {
|
||||
this.chat.openChannel(c);
|
||||
this.router.transitionTo("chat.channel", ...c.routeModels);
|
||||
this.close();
|
||||
});
|
||||
}
|
||||
|
@ -22,7 +22,6 @@
|
||||
<ChatLivePane
|
||||
@chatChannel={{this.previewedChannel}}
|
||||
@includeHeader={{false}}
|
||||
@onSwitchChannel={{action "onSwitchFromDraftChannel"}}
|
||||
/>
|
||||
{{/if}}
|
||||
</div>
|
@ -7,7 +7,6 @@ export default class ChatDraftChannelScreen extends Component {
|
||||
@service chat;
|
||||
@service router;
|
||||
tagName = "";
|
||||
onSwitchChannel = null;
|
||||
|
||||
@action
|
||||
onCancelChatDraft() {
|
||||
@ -22,7 +21,6 @@ export default class ChatDraftChannelScreen extends Component {
|
||||
@action
|
||||
onSwitchFromDraftChannel(channel) {
|
||||
channel.set("isDraft", false);
|
||||
this.onSwitchChannel?.(channel);
|
||||
}
|
||||
|
||||
_fetchPreviewedChannel(users) {
|
||||
|
@ -1,4 +1,5 @@
|
||||
{{#if this.chatStateManager.isDrawerActive}}
|
||||
|
||||
<div
|
||||
data-chat-channel-id={{this.chat.activeChannel.id}}
|
||||
class={{concat-class
|
||||
@ -10,128 +11,14 @@
|
||||
>
|
||||
<div class="chat-drawer-container">
|
||||
<div class="chat-drawer-resizer"></div>
|
||||
<div
|
||||
role="region"
|
||||
aria-label={{i18n "chat.aria_roles.header"}}
|
||||
class="chat-drawer-header"
|
||||
>
|
||||
{{#if
|
||||
(and this.draftChannelView this.chatStateManager.isDrawerExpanded)
|
||||
}}
|
||||
<div class="chat-drawer-header__left-actions">
|
||||
<div class="chat-drawer-header__top-line">
|
||||
<LinkTo
|
||||
title={{i18n "chat.return_to_list"}}
|
||||
class="chat-drawer-header__return-to-channels-btn"
|
||||
@route="chat"
|
||||
>
|
||||
{{d-icon "chevron-left"}}
|
||||
</LinkTo>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<span class="chat-drawer-header__title">
|
||||
<div class="chat-drawer-header__top-line">
|
||||
{{i18n "chat.direct_message_creator.title"}}
|
||||
</div>
|
||||
</span>
|
||||
{{else if this.chatView}}
|
||||
{{#if this.chatStateManager.isDrawerExpanded}}
|
||||
<LinkTo
|
||||
title={{i18n "chat.return_to_list"}}
|
||||
class="chat-drawer-header__return-to-channels-btn"
|
||||
@route="chat"
|
||||
>
|
||||
{{d-icon "chevron-left"}}
|
||||
</LinkTo>
|
||||
{{/if}}
|
||||
|
||||
{{#if this.chat.activeChannel}}
|
||||
{{#if this.chatStateManager.isDrawerExpanded}}
|
||||
<LinkTo
|
||||
@route={{this.infoTabRoute}}
|
||||
@models={{this.chat.activeChannel.routeModels}}
|
||||
class="chat-drawer-header__title"
|
||||
>
|
||||
<div class="chat-drawer-header__top-line">
|
||||
<ChatChannelTitle @channel={{this.chat.activeChannel}} />
|
||||
</div>
|
||||
</LinkTo>
|
||||
{{else}}
|
||||
<div
|
||||
role="button"
|
||||
{{on "click" (action "toggleExpand")}}
|
||||
class="chat-drawer-header__title"
|
||||
>
|
||||
<div class="chat-drawer-header__top-line">
|
||||
<ChatChannelTitle @channel={{this.chat.activeChannel}}>
|
||||
{{#if this.unreadCount}}
|
||||
<span
|
||||
class="chat-unread-count"
|
||||
>{{this.unreadCount}}</span>
|
||||
{{/if}}
|
||||
</ChatChannelTitle>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{else}}
|
||||
<span class="chat-drawer-header__title">
|
||||
<div class="chat-drawer-header__top-line">
|
||||
{{i18n "chat.heading"}}
|
||||
</div>
|
||||
</span>
|
||||
{{/if}}
|
||||
|
||||
<div class="chat-drawer-header__right-actions">
|
||||
<div class="chat-drawer-header__top-line {{this.topLineClass}}">
|
||||
{{#if this.chatStateManager.isDrawerExpanded}}
|
||||
<DButton
|
||||
@icon="discourse-expand"
|
||||
class="btn-flat btn-link chat-drawer-header__full-screen-btn"
|
||||
@title={{"chat.open_full_page"}}
|
||||
@action={{this.openInFullPage}}
|
||||
/>
|
||||
{{/if}}
|
||||
|
||||
<FlatButton
|
||||
@icon={{this.expandIcon}}
|
||||
@class="chat-drawer-header__expand-btn"
|
||||
@action={{action "toggleExpand"}}
|
||||
@title="chat.collapse"
|
||||
/>
|
||||
|
||||
{{#if this.showClose}}
|
||||
<FlatButton
|
||||
@icon="times"
|
||||
@action={{action "close"}}
|
||||
@title="chat.close"
|
||||
@class="chat-drawer-header__close-btn"
|
||||
/>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{#if this.chatStateManager.isDrawerExpanded}}
|
||||
<div class="chat-drawer-content">
|
||||
{{#if (and this.chatView this.chat.activeChannel)}}
|
||||
<ChatLivePane
|
||||
@chatChannel={{this.chat.activeChannel}}
|
||||
@onSwitchChannel={{action "switchChannel"}}
|
||||
/>
|
||||
{{else if this.draftChannelView}}
|
||||
<ChatDraftChannelScreen
|
||||
@onSwitchChannel={{action "switchChannel"}}
|
||||
/>
|
||||
{{else}}
|
||||
<ChannelsList
|
||||
@onOpenView={{action "openURL"}}
|
||||
@onSelect={{action "switchChannel"}}
|
||||
/>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
||||
<this.chatDrawerRouter.component
|
||||
@params={{this.chatDrawerRouter.params}}
|
||||
@openURL={{this.openURL}}
|
||||
@openInFullPage={{this.openInFullPage}}
|
||||
@toggleExpand={{this.toggleExpand}}
|
||||
@close={{this.close}}
|
||||
@drawerActions={{this.drawerActions}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
@ -1,35 +1,22 @@
|
||||
import Component from "@ember/component";
|
||||
import discourseComputed, {
|
||||
bind,
|
||||
observes,
|
||||
} from "discourse-common/utils/decorators";
|
||||
import { bind, observes } from "discourse-common/utils/decorators";
|
||||
import { action } from "@ember/object";
|
||||
import {
|
||||
CHAT_VIEW,
|
||||
DRAFT_CHANNEL_VIEW,
|
||||
LIST_VIEW,
|
||||
} from "discourse/plugins/chat/discourse/services/chat";
|
||||
import { equal } from "@ember/object/computed";
|
||||
import { cancel, next, schedule, throttle } from "@ember/runloop";
|
||||
import { cancel, throttle } from "@ember/runloop";
|
||||
import { inject as service } from "@ember/service";
|
||||
import { htmlSafe } from "@ember/template";
|
||||
import { escapeExpression } from "discourse/lib/utilities";
|
||||
|
||||
export default Component.extend({
|
||||
tagName: "",
|
||||
listView: equal("view", LIST_VIEW),
|
||||
chatView: equal("view", CHAT_VIEW),
|
||||
draftChannelView: equal("view", DRAFT_CHANNEL_VIEW),
|
||||
chat: service(),
|
||||
router: service(),
|
||||
chatDrawerSize: service(),
|
||||
chatChannelsManager: service(),
|
||||
chatStateManager: service(),
|
||||
chatDrawerRouter: service(),
|
||||
loading: false,
|
||||
showClose: true, // TODO - false when on same topic
|
||||
sizeTimer: null,
|
||||
rafTimer: null,
|
||||
view: null,
|
||||
hasUnreadMessages: false,
|
||||
drawerStyle: null,
|
||||
|
||||
@ -42,12 +29,6 @@ export default Component.extend({
|
||||
this._checkSize();
|
||||
this.appEvents.on("chat:open-url", this, "openURL");
|
||||
this.appEvents.on("chat:toggle-close", this, "close");
|
||||
this.appEvents.on("chat:open-channel", this, "switchChannel");
|
||||
this.appEvents.on(
|
||||
"chat:open-channel-at-message",
|
||||
this,
|
||||
"openChannelAtMessage"
|
||||
);
|
||||
this.appEvents.on("composer:closed", this, "_checkSize");
|
||||
this.appEvents.on("composer:opened", this, "_checkSize");
|
||||
this.appEvents.on("composer:resized", this, "_checkSize");
|
||||
@ -74,12 +55,6 @@ export default Component.extend({
|
||||
if (this.appEvents) {
|
||||
this.appEvents.off("chat:open-url", this, "openURL");
|
||||
this.appEvents.off("chat:toggle-close", this, "close");
|
||||
this.appEvents.off("chat:open-channel", this, "switchChannel");
|
||||
this.appEvents.off(
|
||||
"chat:open-channel-at-message",
|
||||
this,
|
||||
"openChannelAtMessage"
|
||||
);
|
||||
this.appEvents.off("composer:closed", this, "_checkSize");
|
||||
this.appEvents.off("composer:opened", this, "_checkSize");
|
||||
this.appEvents.off("composer:resized", this, "_checkSize");
|
||||
@ -109,26 +84,6 @@ export default Component.extend({
|
||||
this.appEvents.trigger("chat:rerender-header");
|
||||
},
|
||||
|
||||
@discourseComputed("chatStateManager.isDrawerExpanded")
|
||||
topLineClass(expanded) {
|
||||
const baseClass = "chat-drawer-header__top-line";
|
||||
return expanded ? `${baseClass}--expanded` : `${baseClass}--collapsed`;
|
||||
},
|
||||
|
||||
@discourseComputed("chatStateManager.isDrawerExpanded", "chat.activeChannel")
|
||||
displayMembers(expanded, channel) {
|
||||
return expanded && !channel?.isDirectMessageChannel;
|
||||
},
|
||||
|
||||
@discourseComputed("displayMembers")
|
||||
infoTabRoute(displayMembers) {
|
||||
if (displayMembers) {
|
||||
return "chat.channel.info.members";
|
||||
}
|
||||
|
||||
return "chat.channel.info.settings";
|
||||
},
|
||||
|
||||
computeDrawerStyle() {
|
||||
const { width, height } = this.chatDrawerSize.size;
|
||||
let style = `width: ${escapeExpression((width || "0").toString())}px;`;
|
||||
@ -136,8 +91,12 @@ export default Component.extend({
|
||||
this.set("drawerStyle", htmlSafe(style));
|
||||
},
|
||||
|
||||
openChannelAtMessage(channel, messageId) {
|
||||
this.chat.openChannel(channel, messageId);
|
||||
get drawerActions() {
|
||||
return {
|
||||
openInFullPage: this.openInFullPage,
|
||||
close: this.close,
|
||||
toggleExpand: this.toggleExpand,
|
||||
};
|
||||
},
|
||||
|
||||
@bind
|
||||
@ -204,74 +163,22 @@ export default Component.extend({
|
||||
);
|
||||
},
|
||||
|
||||
@discourseComputed("chatStateManager.isDrawerExpanded")
|
||||
expandIcon(expanded) {
|
||||
if (expanded) {
|
||||
return "angle-double-down";
|
||||
} else {
|
||||
return "angle-double-up";
|
||||
}
|
||||
},
|
||||
|
||||
@discourseComputed("chat.activeChannel.currentUserMembership.unread_count")
|
||||
unreadCount(count) {
|
||||
return count || 0;
|
||||
},
|
||||
|
||||
@action
|
||||
openURL(URL = null) {
|
||||
openURL(url = null) {
|
||||
this.chat.activeChannel = null;
|
||||
this.chatStateManager.didOpenDrawer(URL);
|
||||
|
||||
const route = this._buildRouteFromURL(
|
||||
URL || this.chatStateManager.lastKnownChatURL
|
||||
);
|
||||
|
||||
switch (route.name) {
|
||||
case "chat":
|
||||
this.set("view", LIST_VIEW);
|
||||
this.appEvents.trigger("chat:float-toggled", false);
|
||||
return;
|
||||
case "chat.draft-channel":
|
||||
this.set("view", DRAFT_CHANNEL_VIEW);
|
||||
this.appEvents.trigger("chat:float-toggled", false);
|
||||
return;
|
||||
case "chat.channel":
|
||||
return this._openChannel(
|
||||
route.params.channelId,
|
||||
this._highlightCb(route.queryParams.messageId)
|
||||
);
|
||||
case "chat.channel.near-message":
|
||||
return this._openChannel(
|
||||
route.parent.params.channelId,
|
||||
this._highlightCb(route.params.messageId)
|
||||
);
|
||||
case "chat.channel-legacy":
|
||||
return this._openChannel(
|
||||
route.params.channelId,
|
||||
this._highlightCb(route.queryParams.messageId)
|
||||
);
|
||||
}
|
||||
this.chatStateManager.didOpenDrawer(url);
|
||||
this.chatDrawerRouter.stateFor(this._routeFromURL(url));
|
||||
},
|
||||
|
||||
_highlightCb(messageId) {
|
||||
if (messageId) {
|
||||
return () => {
|
||||
this.appEvents.trigger("chat-live-pane:highlight-message", messageId);
|
||||
};
|
||||
_routeFromURL(url) {
|
||||
let route = this.router.recognize(url || "/");
|
||||
|
||||
// ember might recognize the index subroute
|
||||
if (route.localName === "index") {
|
||||
route = route.parent;
|
||||
}
|
||||
},
|
||||
|
||||
_openChannel(channelId, afterRenderFunc = null) {
|
||||
return this.chatChannelsManager.find(channelId).then((channel) => {
|
||||
this.chat.activeChannel = channel;
|
||||
this.set("view", CHAT_VIEW);
|
||||
this.appEvents.trigger("chat:float-toggled", false);
|
||||
|
||||
if (afterRenderFunc) {
|
||||
schedule("afterRender", afterRenderFunc);
|
||||
}
|
||||
});
|
||||
return route;
|
||||
},
|
||||
|
||||
@action
|
||||
@ -298,61 +205,10 @@ export default Component.extend({
|
||||
this.computeDrawerStyle();
|
||||
this.chatStateManager.didCloseDrawer();
|
||||
this.chat.activeChannel = null;
|
||||
this.appEvents.trigger("chat:float-toggled", true);
|
||||
},
|
||||
|
||||
@action
|
||||
didResize(element, { width, height }) {
|
||||
this.chatDrawerSize.size = { width, height };
|
||||
},
|
||||
|
||||
@action
|
||||
switchChannel(channel) {
|
||||
// we need next here to ensure we correctly let the time for routes transitions
|
||||
// eg: deactivate hook of full page chat routes will set activeChannel to null
|
||||
next(() => {
|
||||
if (this.isDestroying || this.isDestroyed) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.chat.activeChannel = channel;
|
||||
|
||||
if (!channel) {
|
||||
const URL = this._buildURLFromState(LIST_VIEW);
|
||||
this.openURL(URL);
|
||||
return;
|
||||
}
|
||||
|
||||
const URL = this._buildURLFromState(CHAT_VIEW, channel);
|
||||
this.openURL(URL);
|
||||
});
|
||||
},
|
||||
|
||||
_buildRouteFromURL(URL) {
|
||||
let route = this.router.recognize(URL || "/");
|
||||
|
||||
// ember might recognize the index subroute
|
||||
if (route.localName === "index") {
|
||||
route = route.parent;
|
||||
}
|
||||
|
||||
return route;
|
||||
},
|
||||
|
||||
_buildURLFromState(view, channel = null) {
|
||||
switch (view) {
|
||||
case LIST_VIEW:
|
||||
return "/chat";
|
||||
case DRAFT_CHANNEL_VIEW:
|
||||
return "/chat/draft-channel";
|
||||
case CHAT_VIEW:
|
||||
if (channel) {
|
||||
return `/chat/c/${channel.slug || "-"}/${channel.id}`;
|
||||
} else {
|
||||
return "/chat";
|
||||
}
|
||||
default:
|
||||
return "/chat";
|
||||
}
|
||||
},
|
||||
});
|
||||
|
@ -0,0 +1,25 @@
|
||||
<ChatDrawer::Header>
|
||||
<ChatDrawer::Header::LeftActions />
|
||||
|
||||
<ChatDrawer::Header::ChannelTitle
|
||||
@channel={{this.chat.activeChannel}}
|
||||
@drawerActions={{@drawerActions}}
|
||||
/>
|
||||
|
||||
<ChatDrawer::Header::RightActions @drawerActions={{@drawerActions}} />
|
||||
</ChatDrawer::Header>
|
||||
|
||||
{{#if this.chatStateManager.isDrawerExpanded}}
|
||||
<div
|
||||
class="chat-drawer-content"
|
||||
{{did-insert this.fetchChannel}}
|
||||
{{did-update this.fetchChannel @params.channelId}}
|
||||
>
|
||||
{{#if this.chat.activeChannel}}
|
||||
<ChatLivePane
|
||||
@targetMessageId={{readonly @params.messageId}}
|
||||
@chatChannel={{this.chat.activeChannel}}
|
||||
/>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
@ -0,0 +1,23 @@
|
||||
import Component from "@glimmer/component";
|
||||
import { inject as service } from "@ember/service";
|
||||
import { action } from "@ember/object";
|
||||
|
||||
export default class ChatDrawerChannel extends Component {
|
||||
@service appEvents;
|
||||
@service chat;
|
||||
@service chatStateManager;
|
||||
@service chatChannelsManager;
|
||||
|
||||
@action
|
||||
fetchChannel() {
|
||||
if (!this.args.params?.channelId) {
|
||||
return;
|
||||
}
|
||||
|
||||
return this.chatChannelsManager
|
||||
.find(this.args.params.channelId)
|
||||
.then((channel) => {
|
||||
this.chat.activeChannel = channel;
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
<ChatDrawer::Header>
|
||||
<ChatDrawer::Header::LeftActions />
|
||||
<ChatDrawer::Header::Title @title="chat.direct_message_creator.title" />
|
||||
<ChatDrawer::Header::RightActions @drawerActions={{@drawerActions}} />
|
||||
</ChatDrawer::Header>
|
||||
|
||||
{{#if this.chatStateManager.isDrawerExpanded}}
|
||||
<div class="chat-drawer-content">
|
||||
<ChatDraftChannelScreen />
|
||||
</div>
|
||||
{{/if}}
|
@ -0,0 +1,6 @@
|
||||
import Component from "@glimmer/component";
|
||||
import { inject as service } from "@ember/service";
|
||||
|
||||
export default class ChatDrawerDraftChannel extends Component {
|
||||
@service chatStateManager;
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
<div
|
||||
role="region"
|
||||
aria-label={{i18n "chat.aria_roles.header"}}
|
||||
class="chat-drawer-header"
|
||||
>
|
||||
{{yield}}
|
||||
</div>
|
@ -0,0 +1,7 @@
|
||||
<LinkTo
|
||||
title={{i18n "chat.return_to_list"}}
|
||||
class="chat-drawer-header__return-to-channels-btn"
|
||||
@route="chat"
|
||||
>
|
||||
{{d-icon "chevron-left"}}
|
||||
</LinkTo>
|
@ -0,0 +1,6 @@
|
||||
import Component from "@glimmer/component";
|
||||
import { inject as service } from "@ember/service";
|
||||
|
||||
export default class ChatDrawerHeaderBackLink extends Component {
|
||||
@service chatStateManager;
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
{{#if @channel}}
|
||||
{{#if @this.chatStateManager.isDrawerExpanded}}
|
||||
<LinkTo
|
||||
@route={{if
|
||||
@channel.isDirectMessageChannel
|
||||
"chat.channel.info.settings"
|
||||
"chat.channel.info.members"
|
||||
}}
|
||||
@models={{@channel.routeModels}}
|
||||
class="chat-drawer-header__title"
|
||||
>
|
||||
<div class="chat-drawer-header__top-line">
|
||||
<ChatChannelTitle @channel={{@channel}} />
|
||||
</div>
|
||||
</LinkTo>
|
||||
{{else}}
|
||||
<div
|
||||
role="button"
|
||||
{{on "click" @drawerActions.toggleExpand}}
|
||||
class="chat-drawer-header__title"
|
||||
>
|
||||
<div class="chat-drawer-header__top-line">
|
||||
<ChatChannelTitle @channel={{@channel}}>
|
||||
{{#if @channel.currentUserMembership.unreadCount}}
|
||||
<span class="chat-unread-count">
|
||||
{{@channel.currentUserMembership.unreadCount}}
|
||||
</span>
|
||||
{{/if}}
|
||||
</ChatChannelTitle>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{/if}}
|
@ -0,0 +1,6 @@
|
||||
import Component from "@glimmer/component";
|
||||
import { inject as service } from "@ember/service";
|
||||
|
||||
export default class ChatDrawerChannelHeaderTitle extends Component {
|
||||
@service chatStateManager;
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
<DButton
|
||||
@icon="times"
|
||||
@action={{@close}}
|
||||
@title="chat.close"
|
||||
@class="btn-flat btn-link chat-drawer-header__close-btn"
|
||||
/>
|
@ -0,0 +1,8 @@
|
||||
{{#if this.chatStateManager.isDrawerExpanded}}
|
||||
<DButton
|
||||
@icon="discourse-expand"
|
||||
class="btn-flat btn-link chat-drawer-header__full-screen-btn"
|
||||
@title={{"chat.open_full_page"}}
|
||||
@action={{@openInFullPage}}
|
||||
/>
|
||||
{{/if}}
|
@ -0,0 +1,6 @@
|
||||
import Component from "@glimmer/component";
|
||||
import { inject as service } from "@ember/service";
|
||||
|
||||
export default class ChatDrawerHeaderFullPageButton extends Component {
|
||||
@service chatStateManager;
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
{{#if this.chatStateManager.isDrawerExpanded}}
|
||||
<div class="chat-drawer-header__left-actions">
|
||||
<div class="chat-drawer-header__top-line">
|
||||
<ChatDrawer::Header::BackLink />
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
@ -0,0 +1,6 @@
|
||||
import Component from "@glimmer/component";
|
||||
import { inject as service } from "@ember/service";
|
||||
|
||||
export default class ChatDrawerHeaderLeftActions extends Component {
|
||||
@service chatStateManager;
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
<div class="chat-drawer-header__right-actions">
|
||||
<div class="chat-drawer-header__top-line">
|
||||
<ChatDrawer::Header::FullPageButton
|
||||
@openInFullPage={{@drawerActions.openInFullPage}}
|
||||
/>
|
||||
<ChatDrawer::Header::ToggleExpandButton
|
||||
@toggleExpand={{@drawerActions.toggleExpand}}
|
||||
/>
|
||||
<ChatDrawer::Header::CloseButton @close={{@drawerActions.close}} />
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,6 @@
|
||||
import Component from "@glimmer/component";
|
||||
import { inject as service } from "@ember/service";
|
||||
|
||||
export default class ChatDrawerHeaderRightActions extends Component {
|
||||
@service chatStateManager;
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
<span class="chat-drawer-header__title">
|
||||
<div class="chat-drawer-header__top-line">
|
||||
{{i18n @title}}
|
||||
</div>
|
||||
</span>
|
@ -0,0 +1,10 @@
|
||||
<DButton
|
||||
@icon={{if
|
||||
this.chatStateManager.isDrawerExpanded
|
||||
"angle-double-down"
|
||||
"angle-double-up"
|
||||
}}
|
||||
@class="btn-flat btn-link chat-drawer-header__expand-btn"
|
||||
@action={{@toggleExpand}}
|
||||
@title="chat.collapse"
|
||||
/>
|
@ -0,0 +1,6 @@
|
||||
import Component from "@glimmer/component";
|
||||
import { inject as service } from "@ember/service";
|
||||
|
||||
export default class ChatDrawerHeaderToggleExpandButton extends Component {
|
||||
@service chatStateManager;
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
<ChatDrawer::Header>
|
||||
<ChatDrawer::Header::Title @title="chat.heading" />
|
||||
<ChatDrawer::Header::RightActions @drawerActions={{@drawerActions}} />
|
||||
</ChatDrawer::Header>
|
||||
|
||||
{{#if this.chatStateManager.isDrawerExpanded}}
|
||||
<div class="chat-drawer-content">
|
||||
<ChannelsList />
|
||||
</div>
|
||||
{{/if}}
|
@ -0,0 +1,6 @@
|
||||
import Component from "@glimmer/component";
|
||||
import { inject as service } from "@ember/service";
|
||||
|
||||
export default class ChatDrawerIndex extends Component {
|
||||
@service chatStateManager;
|
||||
}
|
@ -81,7 +81,6 @@
|
||||
@afterReactionAdded={{action "reStickScrollIfNeeded"}}
|
||||
@isHovered={{eq message.id this.hoveredMessageId}}
|
||||
@onHoverMessage={{action "onHoverMessage"}}
|
||||
@onSwitchChannel={{this.onSwitchChannel}}
|
||||
@resendStagedMessage={{this.resendStagedMessage}}
|
||||
/>
|
||||
{{/each}}
|
||||
|
@ -45,7 +45,6 @@ export default Component.extend({
|
||||
loadingMorePast: false,
|
||||
loadingMoreFuture: false,
|
||||
hoveredMessageId: null,
|
||||
onSwitchChannel: null,
|
||||
|
||||
allPastMessagesLoaded: false,
|
||||
sendingLoading: false,
|
||||
@ -993,57 +992,58 @@ export default Component.extend({
|
||||
}
|
||||
|
||||
this.set("_nextStagedMessageId", this._nextStagedMessageId + 1);
|
||||
const cooked = this.cook(message);
|
||||
const stagedId = this._nextStagedMessageId;
|
||||
let data = {
|
||||
message,
|
||||
cooked,
|
||||
staged_id: stagedId,
|
||||
upload_ids: uploads.map((upload) => upload.id),
|
||||
};
|
||||
if (this.replyToMsg) {
|
||||
data.in_reply_to_id = this.replyToMsg.id;
|
||||
}
|
||||
return this.chat.loadCookFunction(this.site.categories).then((cook) => {
|
||||
const cooked = cook(message);
|
||||
const stagedId = this._nextStagedMessageId;
|
||||
let data = {
|
||||
message,
|
||||
cooked,
|
||||
staged_id: stagedId,
|
||||
upload_ids: uploads.map((upload) => upload.id),
|
||||
};
|
||||
if (this.replyToMsg) {
|
||||
data.in_reply_to_id = this.replyToMsg.id;
|
||||
}
|
||||
|
||||
// Start ajax request but don't return here, we want to stage the message instantly when all messages are loaded.
|
||||
// Otherwise, we'll fetch latest and scroll to the one we just created.
|
||||
// Return a resolved promise below.
|
||||
const msgCreationPromise = this.chatApi
|
||||
.sendMessage(this.chatChannel.id, data)
|
||||
.catch((error) => {
|
||||
this._onSendError(data.staged_id, error);
|
||||
})
|
||||
.finally(() => {
|
||||
if (this._selfDeleted) {
|
||||
return;
|
||||
}
|
||||
this.set("sendingLoading", false);
|
||||
});
|
||||
// Start ajax request but don't return here, we want to stage the message instantly when all messages are loaded.
|
||||
// Otherwise, we'll fetch latest and scroll to the one we just created.
|
||||
// Return a resolved promise below.
|
||||
const msgCreationPromise = this.chatApi
|
||||
.sendMessage(this.chatChannel.id, data)
|
||||
.catch((error) => {
|
||||
this._onSendError(data.staged_id, error);
|
||||
})
|
||||
.finally(() => {
|
||||
if (this._selfDeleted) {
|
||||
return;
|
||||
}
|
||||
this.set("sendingLoading", false);
|
||||
});
|
||||
|
||||
if (this.details?.can_load_more_future) {
|
||||
msgCreationPromise.then(() => this._fetchAndScrollToLatest());
|
||||
} else {
|
||||
const stagedMessage = this._prepareSingleMessage(
|
||||
// We need to add the user and created at for presentation of staged message
|
||||
{
|
||||
message,
|
||||
cooked,
|
||||
stagedId,
|
||||
uploads: cloneJSON(uploads),
|
||||
staged: true,
|
||||
user: this.currentUser,
|
||||
in_reply_to: this.replyToMsg,
|
||||
created_at: new Date(),
|
||||
},
|
||||
this.messages[this.messages.length - 1]
|
||||
);
|
||||
this.messages.pushObject(stagedMessage);
|
||||
this._stickScrollToBottom();
|
||||
}
|
||||
if (this.details?.can_load_more_future) {
|
||||
msgCreationPromise.then(() => this._fetchAndScrollToLatest());
|
||||
} else {
|
||||
const stagedMessage = this._prepareSingleMessage(
|
||||
// We need to add the user and created at for presentation of staged message
|
||||
{
|
||||
message,
|
||||
cooked,
|
||||
stagedId,
|
||||
uploads: cloneJSON(uploads),
|
||||
staged: true,
|
||||
user: this.currentUser,
|
||||
in_reply_to: this.replyToMsg,
|
||||
created_at: new Date(),
|
||||
},
|
||||
this.messages[this.messages.length - 1]
|
||||
);
|
||||
this.messages.pushObject(stagedMessage);
|
||||
this._stickScrollToBottom();
|
||||
}
|
||||
|
||||
this._resetAfterSend();
|
||||
this.appEvents.trigger("chat-composer:reply-to-set", null);
|
||||
return Promise.resolve();
|
||||
this._resetAfterSend();
|
||||
this.appEvents.trigger("chat-composer:reply-to-set", null);
|
||||
});
|
||||
},
|
||||
|
||||
async _upsertChannelWithMessage(channel, message, uploads) {
|
||||
@ -1063,7 +1063,7 @@ export default Component.extend({
|
||||
upload_ids: (uploads || []).mapBy("id"),
|
||||
},
|
||||
}).then(() => {
|
||||
this.onSwitchChannel(c);
|
||||
this.router.transitionTo("chat.channel", "-", c.id);
|
||||
})
|
||||
);
|
||||
},
|
||||
|
@ -12,6 +12,7 @@ export default class MoveToChannelModalInner extends Component {
|
||||
@service chatApi;
|
||||
@service router;
|
||||
@service chatChannelsManager;
|
||||
|
||||
tagName = "";
|
||||
sourceChannel = null;
|
||||
destinationChannelId = null;
|
||||
@ -40,7 +41,9 @@ export default class MoveToChannelModalInner extends Component {
|
||||
destination_channel_id: this.destinationChannelId,
|
||||
})
|
||||
.then((response) => {
|
||||
return this.chat.openChannelAtMessage(
|
||||
this.router.transitionTo(
|
||||
"chat.channel.near-message",
|
||||
"-",
|
||||
response.destination_channel_id,
|
||||
response.first_moved_message_id
|
||||
);
|
||||
|
@ -609,7 +609,7 @@ export default Component.extend({
|
||||
return this.chatChannelsManager
|
||||
.getChannel(this.chatChannel.id)
|
||||
.then((reactedChannel) => {
|
||||
this.onSwitchChannel(reactedChannel);
|
||||
this.router.transitionTo("chat.channel", "-", reactedChannel.id);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
@ -23,7 +23,6 @@ export default Component.extend({
|
||||
router: service(),
|
||||
chatStateManager: service(),
|
||||
isLoading: false,
|
||||
onSwitchChannel: null,
|
||||
|
||||
init() {
|
||||
this._super(...arguments);
|
||||
|
@ -2,7 +2,6 @@
|
||||
<ChatLivePane
|
||||
@chatChannel={{this.chat.activeChannel}}
|
||||
@onBackClick={{action "navigateToIndex"}}
|
||||
@onSwitchChannel={{action "switchChannel"}}
|
||||
@targetMessageId={{readonly @targetMessageId}}
|
||||
/>
|
||||
{{/if}}
|
@ -76,9 +76,4 @@ export default Component.extend({
|
||||
navigateToIndex() {
|
||||
this.router.transitionTo("chat.index");
|
||||
},
|
||||
|
||||
@action
|
||||
switchChannel(channel) {
|
||||
return this.chat.openChannel(channel);
|
||||
},
|
||||
});
|
||||
|
@ -1,7 +1,3 @@
|
||||
{{#if this.isDisplayed}}
|
||||
<ChannelsList
|
||||
@onSelect={{action "switchChannel"}}
|
||||
@toggleSection={{this.toggleSection}}
|
||||
@inSidebar={{true}}
|
||||
/>
|
||||
<ChannelsList @toggleSection={{this.toggleSection}} @inSidebar={{true}} />
|
||||
{{/if}}
|
@ -1,10 +1,11 @@
|
||||
import Component from "@ember/component";
|
||||
import { action, computed } from "@ember/object";
|
||||
import { computed } from "@ember/object";
|
||||
import { inject as service } from "@ember/service";
|
||||
|
||||
export default class SidebarChannels extends Component {
|
||||
@service chat;
|
||||
@service router;
|
||||
|
||||
tagName = "";
|
||||
toggleSection = null;
|
||||
|
||||
@ -12,9 +13,4 @@ export default class SidebarChannels extends Component {
|
||||
get isDisplayed() {
|
||||
return this.chat.userCanChat;
|
||||
}
|
||||
|
||||
@action
|
||||
switchChannel(channel) {
|
||||
this.chat.openChannel(channel);
|
||||
}
|
||||
}
|
||||
|
@ -4,13 +4,15 @@ import { inject as service } from "@ember/service";
|
||||
|
||||
export default class UserCardChatButton extends Component {
|
||||
@service chat;
|
||||
@service appEvents;
|
||||
@service router;
|
||||
|
||||
@action
|
||||
startChatting() {
|
||||
this.chat
|
||||
.upsertDmChannelForUsernames([this.user.username])
|
||||
.then((chatChannel) => {
|
||||
this.chat.openChannel(chatChannel);
|
||||
this.router.transitionTo("chat.channel", ...chatChannel.routeModels);
|
||||
this.appEvents.trigger("card:close");
|
||||
});
|
||||
}
|
||||
|
@ -7,12 +7,13 @@ export default class ChatChannelToggleController extends Controller.extend(
|
||||
ModalFunctionality
|
||||
) {
|
||||
@service chat;
|
||||
@service router;
|
||||
|
||||
chatChannel = null;
|
||||
|
||||
@action
|
||||
channelStatusChanged(channel) {
|
||||
this.send("closeModal");
|
||||
this.chat.openChannel(channel);
|
||||
this.router.transitionTo("chat.channel", ...channel.routeModels);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
import Controller from "@ember/controller";
|
||||
import { action } from "@ember/object";
|
||||
import { inject as service } from "@ember/service";
|
||||
|
||||
export default class ChatChannelController extends Controller {
|
||||
@ -9,9 +8,4 @@ export default class ChatChannelController extends Controller {
|
||||
|
||||
// Backwards-compatibility
|
||||
queryParams = ["messageId"];
|
||||
|
||||
@action
|
||||
switchChannel(channel) {
|
||||
this.chat.openChannel(channel);
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,6 @@
|
||||
import Controller from "@ember/controller";
|
||||
import { action } from "@ember/object";
|
||||
import { inject as service } from "@ember/service";
|
||||
|
||||
export default class ChatDraftChannelController extends Controller {
|
||||
@service chat;
|
||||
|
||||
@action
|
||||
onSwitchChannel(channel) {
|
||||
return this.chat.openChannel(channel);
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,6 @@
|
||||
import Controller from "@ember/controller";
|
||||
import { action } from "@ember/object";
|
||||
import { inject as service } from "@ember/service";
|
||||
|
||||
export default class ChatIndexController extends Controller {
|
||||
@service chat;
|
||||
|
||||
@action
|
||||
selectChannel(channel) {
|
||||
return this.chat.openChannel(channel);
|
||||
}
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ export default class CreateChannelController extends Controller.extend(
|
||||
@service dialog;
|
||||
@service chatChannelsManager;
|
||||
@service chatApi;
|
||||
@service router;
|
||||
|
||||
category = null;
|
||||
categoryId = null;
|
||||
@ -83,7 +84,7 @@ export default class CreateChannelController extends Controller.extend(
|
||||
.then((channel) => {
|
||||
this.send("closeModal");
|
||||
this.chatChannelsManager.follow(channel);
|
||||
this.chat.openChannel(channel);
|
||||
this.router.transitionTo("chat.channel", ...channel.routeModels);
|
||||
})
|
||||
.catch((e) => {
|
||||
this.flash(e.jqXHR.responseJSON.errors[0], "error");
|
||||
|
@ -16,7 +16,7 @@ export default class ChatIndexRoute extends DiscourseRoute {
|
||||
const id = this.chat.getIdealFirstChannelId();
|
||||
if (id) {
|
||||
return this.chatChannelsManager.find(id).then((c) => {
|
||||
return this.chat.openChannel(c);
|
||||
return this.router.transitionTo("chat.channel", ...c.routeModels);
|
||||
});
|
||||
} else {
|
||||
return this.router.transitionTo("chat.browse");
|
||||
|
@ -37,17 +37,17 @@ export default class ChatRoute extends DiscourseRoute {
|
||||
) {
|
||||
transition.abort();
|
||||
|
||||
let URL = transition.intent.url;
|
||||
let url = transition.intent.url;
|
||||
if (transition.targetName.startsWith("chat.channel")) {
|
||||
URL ??= this.router.urlFor(
|
||||
url ??= this.router.urlFor(
|
||||
transition.targetName,
|
||||
...transition.intent.contexts
|
||||
);
|
||||
} else {
|
||||
URL ??= this.router.urlFor(transition.targetName);
|
||||
url ??= this.router.urlFor(transition.targetName);
|
||||
}
|
||||
|
||||
this.appEvents.trigger("chat:open-url", URL);
|
||||
this.appEvents.trigger("chat:open-url", url);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,41 @@
|
||||
import Service, { inject as service } from "@ember/service";
|
||||
import { tracked } from "@glimmer/tracking";
|
||||
import ChatDrawerDraftChannel from "discourse/plugins/chat/discourse/components/chat-drawer/draft-channel";
|
||||
import ChatDrawerChannel from "discourse/plugins/chat/discourse/components/chat-drawer/channel";
|
||||
import ChatDrawerIndex from "discourse/plugins/chat/discourse/components/chat-drawer/index";
|
||||
|
||||
const COMPONENTS_MAP = {
|
||||
"chat.draft-channel": { name: ChatDrawerDraftChannel },
|
||||
"chat.channel": { name: ChatDrawerChannel },
|
||||
chat: { name: ChatDrawerIndex },
|
||||
"chat.channel.near-message": {
|
||||
name: ChatDrawerChannel,
|
||||
extractParams: (route) => {
|
||||
return {
|
||||
channelId: route.parent.params.channelId,
|
||||
messageId: route.params.messageId,
|
||||
};
|
||||
},
|
||||
},
|
||||
"chat.channel-legacy": {
|
||||
name: ChatDrawerChannel,
|
||||
extractParams: (route) => {
|
||||
return {
|
||||
channelId: route.params.channelId,
|
||||
messageId: route.queryParams.messageId,
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default class ChatDrawerRouter extends Service {
|
||||
@service router;
|
||||
@tracked component = null;
|
||||
@tracked params = null;
|
||||
|
||||
stateFor(route) {
|
||||
const component = COMPONENTS_MAP[route.name];
|
||||
this.params = component?.extractParams?.(route) || route.params;
|
||||
this.component = component?.name || ChatDrawerIndex;
|
||||
}
|
||||
}
|
@ -42,12 +42,12 @@ export default class ChatStateManager extends Service {
|
||||
this.set("isSidePanelExpanded", false);
|
||||
}
|
||||
|
||||
didOpenDrawer(URL = null) {
|
||||
didOpenDrawer(url = null) {
|
||||
this.set("isDrawerActive", true);
|
||||
this.set("isDrawerExpanded", true);
|
||||
|
||||
if (URL) {
|
||||
this.storeChatURL(URL);
|
||||
if (url) {
|
||||
this.storeChatURL(url);
|
||||
}
|
||||
|
||||
this.chat.updatePresence();
|
||||
@ -99,12 +99,12 @@ export default class ChatStateManager extends Service {
|
||||
return this.isFullPageActive || this.isDrawerActive;
|
||||
}
|
||||
|
||||
storeAppURL(URL = null) {
|
||||
this._appURL = URL || this.router.currentURL;
|
||||
storeAppURL(url = null) {
|
||||
this._appURL = url || this.router.currentURL;
|
||||
}
|
||||
|
||||
storeChatURL(URL = null) {
|
||||
this._chatURL = URL || this.router.currentURL;
|
||||
storeChatURL(url = null) {
|
||||
this._chatURL = url || this.router.currentURL;
|
||||
}
|
||||
|
||||
get lastKnownAppURL() {
|
||||
|
@ -188,7 +188,10 @@ export default class Chat extends Service {
|
||||
currentList[currentChannelIndex + (directionUp ? -1 : 1)];
|
||||
if (nextChannelInSameList) {
|
||||
// You're navigating in the same list of channels, just use index +- 1
|
||||
return this.openChannel(nextChannelInSameList);
|
||||
return this.router.transitionTo(
|
||||
"chat.channel",
|
||||
...nextChannelInSameList.routeModels
|
||||
);
|
||||
}
|
||||
|
||||
// You need to go to the next list of channels, if it exists.
|
||||
@ -198,7 +201,10 @@ export default class Chat extends Service {
|
||||
: nextList[0];
|
||||
|
||||
if (nextChannel.id !== activeChannel.id) {
|
||||
return this.openChannel(nextChannel);
|
||||
return this.router.transitionTo(
|
||||
"chat.channel",
|
||||
...nextChannel.routeModels
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -262,57 +268,14 @@ export default class Chat extends Service {
|
||||
);
|
||||
}
|
||||
|
||||
async openChannelAtMessage(channelId, messageId = null) {
|
||||
return this.chatChannelsManager.find(channelId).then((channel) => {
|
||||
return this._openFoundChannelAtMessage(channel, messageId);
|
||||
});
|
||||
}
|
||||
|
||||
async openChannel(channel) {
|
||||
return this._openFoundChannelAtMessage(channel);
|
||||
}
|
||||
|
||||
async _openFoundChannelAtMessage(channel, messageId = null) {
|
||||
if (
|
||||
(this.router.currentRouteName === "chat.channel" ||
|
||||
this.router.currentRouteName === "chat.channel.near-message") &&
|
||||
this.activeChannel?.id === channel.id
|
||||
) {
|
||||
this.activeChannel = channel;
|
||||
this._fireOpenMessageAppEvent(messageId);
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
this.activeChannel = channel;
|
||||
|
||||
if (
|
||||
this.chatStateManager.isFullPageActive ||
|
||||
this.site.mobileView ||
|
||||
this.chatStateManager.isFullPagePreferred
|
||||
) {
|
||||
if (messageId) {
|
||||
return this.router.transitionTo(
|
||||
_fireOpenFloatAppEvent(channel, messageId = null) {
|
||||
messageId
|
||||
? this.router.transitionTo(
|
||||
"chat.channel.near-message",
|
||||
...channel.routeModels,
|
||||
messageId
|
||||
);
|
||||
} else {
|
||||
return this.router.transitionTo("chat.channel", ...channel.routeModels);
|
||||
}
|
||||
} else {
|
||||
this._fireOpenFloatAppEvent(channel, messageId);
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
|
||||
_fireOpenFloatAppEvent(channel, messageId = null) {
|
||||
messageId
|
||||
? this.appEvents.trigger(
|
||||
"chat:open-channel-at-message",
|
||||
channel,
|
||||
messageId
|
||||
)
|
||||
: this.appEvents.trigger("chat:open-channel", channel);
|
||||
: this.router.transitionTo("chat.channel", ...channel.routeModels);
|
||||
}
|
||||
|
||||
_fireOpenMessageAppEvent(messageId) {
|
||||
|
@ -1 +1 @@
|
||||
<ChatDraftChannelScreen @onSwitchChannel={{action "onSwitchChannel"}} />
|
||||
<ChatDraftChannelScreen />
|
@ -1 +1 @@
|
||||
<ChannelsList @onSelect={{action "selectChannel"}} />
|
||||
<ChannelsList />
|
Loading…
Reference in New Issue
Block a user