DEV: converts models to native classes (#21418)
- `ChatChannel` - `UserChatChannelMembership` Also creates a new `chat-direct-message` model used as the object for the`chatable` property of the `ChatChannel` when the `ChatChannel` is a direct message channel. When the chatable is a category a real `Category` object will now be returned. Archive state of a `ChatChannel` is now hold in a `ChatChannelArchive` object.
This commit is contained in:
parent
afbeeea09f
commit
22521d3428
|
@ -42,7 +42,7 @@ class Chat::Api::ChatablesController < Chat::ApiController
|
|||
direct_message_channels =
|
||||
if users.count > 0
|
||||
# FIXME: investigate the cost of this query
|
||||
Chat::Channel
|
||||
Chat::DirectMessageChannel
|
||||
.includes(chatable: :users)
|
||||
.joins(direct_message: :direct_message_users)
|
||||
.group(1)
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
module Chat
|
||||
class DirectMessageSerializer < ApplicationSerializer
|
||||
attributes :id
|
||||
|
||||
has_many :users, serializer: Chat::UserWithCustomFieldsAndStatusSerializer, embed: :objects
|
||||
|
||||
def users
|
||||
|
|
|
@ -40,7 +40,7 @@ export default Component.extend(ModalFunctionality, {
|
|||
.createChannelArchive(this.chatChannel.id, this._data())
|
||||
.then(() => {
|
||||
this.flash(I18n.t("chat.channel_archive.process_started"), "success");
|
||||
this.chatChannel.set("status", CHANNEL_STATUSES.archived);
|
||||
this.chatChannel.status = CHANNEL_STATUSES.archived;
|
||||
|
||||
discourseLater(() => {
|
||||
this.closeModal();
|
||||
|
|
|
@ -1,18 +1,25 @@
|
|||
{{#if (and this.channel.archive_failed this.currentUser.admin)}}
|
||||
<div class="alert alert-warn chat-channel-retry-archive">
|
||||
<div class="chat-channel-archive-failed-message">
|
||||
{{this.channelArchiveFailedMessage}}
|
||||
</div>
|
||||
{{#if this.shouldRender}}
|
||||
{{#if @channel.archive.failed}}
|
||||
<div
|
||||
class={{concat-class
|
||||
"alert alert-warn chat-channel-retry-archive"
|
||||
@channel.status
|
||||
}}
|
||||
>
|
||||
<div class="chat-channel-archive-failed-message">
|
||||
{{this.channelArchiveFailedMessage}}
|
||||
</div>
|
||||
|
||||
<div class="chat-channel-archive-failed-retry">
|
||||
<DButton
|
||||
@action={{action "retryArchive"}}
|
||||
@label="chat.channel_archive.retry"
|
||||
/>
|
||||
<div class="chat-channel-archive-failed-retry">
|
||||
<DButton
|
||||
@action={{this.retryArchive}}
|
||||
@label="chat.channel_archive.retry"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{else if (and this.channel.archive_completed this.currentUser.admin)}}
|
||||
<div class="chat-channel-archive-status">
|
||||
{{this.channelArchiveCompletedMessage}}
|
||||
</div>
|
||||
{{else if @channel.archive.completed}}
|
||||
<div class={{concat-class "chat-channel-archive-status" @channel.status}}>
|
||||
{{this.channelArchiveCompletedMessage}}
|
||||
</div>
|
||||
{{/if}}
|
||||
{{/if}}
|
|
@ -1,61 +1,53 @@
|
|||
import Component from "@ember/component";
|
||||
import Component from "@glimmer/component";
|
||||
import { htmlSafe } from "@ember/template";
|
||||
import I18n from "I18n";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
import getURL from "discourse-common/lib/get-url";
|
||||
import { action } from "@ember/object";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { inject as service } from "@ember/service";
|
||||
import { isPresent } from "@ember/utils";
|
||||
|
||||
export default Component.extend({
|
||||
channel: null,
|
||||
tagName: "",
|
||||
chatApi: service(),
|
||||
export default class ChatChannelArchiveStatus extends Component {
|
||||
@service chatApi;
|
||||
@service currentUser;
|
||||
|
||||
@discourseComputed(
|
||||
"channel.status",
|
||||
"channel.archived_messages",
|
||||
"channel.total_messages",
|
||||
"channel.archive_failed"
|
||||
)
|
||||
channelArchiveFailedMessage() {
|
||||
const translationKey = !this.channel.archive_topic_id
|
||||
get shouldRender() {
|
||||
return this.currentUser.admin && isPresent(this.args.channel.archive);
|
||||
}
|
||||
|
||||
get channelArchiveFailedMessage() {
|
||||
const archive = this.args.channel.archive;
|
||||
const translationKey = !archive.topicId
|
||||
? "chat.channel_status.archive_failed_no_topic"
|
||||
: "chat.channel_status.archive_failed";
|
||||
return htmlSafe(
|
||||
I18n.t(translationKey, {
|
||||
completed: this.channel.archived_messages,
|
||||
total: this.channel.total_messages,
|
||||
topic_url: this._getTopicUrl(),
|
||||
completed: archive.messages,
|
||||
total: archive.totalMessages,
|
||||
topic_url: this.#getTopicUrl(),
|
||||
})
|
||||
);
|
||||
},
|
||||
}
|
||||
|
||||
@discourseComputed(
|
||||
"channel.status",
|
||||
"channel.archived_messages",
|
||||
"channel.total_messages",
|
||||
"channel.archive_completed"
|
||||
)
|
||||
channelArchiveCompletedMessage() {
|
||||
get channelArchiveCompletedMessage() {
|
||||
return htmlSafe(
|
||||
I18n.t("chat.channel_status.archive_completed", {
|
||||
topic_url: this._getTopicUrl(),
|
||||
topic_url: this.#getTopicUrl(),
|
||||
})
|
||||
);
|
||||
},
|
||||
}
|
||||
|
||||
@action
|
||||
retryArchive() {
|
||||
return this.chatApi
|
||||
.createChannelArchive(this.channel.id)
|
||||
.createChannelArchive(this.args.channel.id)
|
||||
.catch(popupAjaxError);
|
||||
},
|
||||
}
|
||||
|
||||
_getTopicUrl() {
|
||||
if (!this.channel.archive_topic_id) {
|
||||
get #getTopicUrl() {
|
||||
if (!this.args.channel.archive.topicId) {
|
||||
return "";
|
||||
}
|
||||
return getURL(`/t/-/${this.channel.archive_topic_id}`);
|
||||
},
|
||||
});
|
||||
return getURL(`/t/-/${this.args.channel.archive.topicId}`);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
{{#unless this.site.mobileView}}
|
||||
{{#if this.shouldRender}}
|
||||
<DButton
|
||||
@icon="times"
|
||||
@action={{this.onLeaveChannel}}
|
||||
@action={{@onLeaveChannel}}
|
||||
@class="btn-flat chat-channel-leave-btn"
|
||||
@title={{this.leaveChatTitleKey}}
|
||||
/>
|
||||
{{/unless}}
|
||||
{{/if}}
|
|
@ -1,25 +1,19 @@
|
|||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import Component from "@ember/component";
|
||||
import { equal } from "@ember/object/computed";
|
||||
import Component from "@glimmer/component";
|
||||
import { inject as service } from "@ember/service";
|
||||
import { CHATABLE_TYPES } from "discourse/plugins/chat/discourse/models/chat-channel";
|
||||
import { isPresent } from "@ember/utils";
|
||||
export default class ChatChannelLeaveBtn extends Component {
|
||||
@service chat;
|
||||
@service site;
|
||||
|
||||
export default Component.extend({
|
||||
tagName: "",
|
||||
channel: null,
|
||||
chat: service(),
|
||||
get shouldRender() {
|
||||
return !this.site.mobileView && isPresent(this.args.channel);
|
||||
}
|
||||
|
||||
isDirectMessageRow: equal(
|
||||
"channel.chatable_type",
|
||||
CHATABLE_TYPES.directMessageChannel
|
||||
),
|
||||
|
||||
@discourseComputed("isDirectMessageRow")
|
||||
leaveChatTitleKey(isDirectMessageRow) {
|
||||
if (isDirectMessageRow) {
|
||||
get leaveChatTitleKey() {
|
||||
if (this.args.channel.isDirectMessageChannel) {
|
||||
return "chat.direct_messages.leave";
|
||||
} else {
|
||||
return "chat.leave";
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ export default class ChatChannelRow extends Component {
|
|||
}
|
||||
|
||||
get channelHasUnread() {
|
||||
return this.args.channel.currentUserMembership.unread_count > 0;
|
||||
return this.args.channel.currentUserMembership.unreadCount > 0;
|
||||
}
|
||||
|
||||
get #firstDirectMessageUser() {
|
||||
|
|
|
@ -5,9 +5,11 @@ import { action } from "@ember/object";
|
|||
export default Component.extend({
|
||||
tagName: "",
|
||||
|
||||
@discourseComputed("model", "model.focused")
|
||||
rowClassNames(model, focused) {
|
||||
return `chat-channel-selection-row ${focused ? "focused" : ""} ${
|
||||
isFocused: false,
|
||||
|
||||
@discourseComputed("model", "isFocused")
|
||||
rowClassNames(model, isFocused) {
|
||||
return `chat-channel-selection-row ${isFocused ? "focused" : ""} ${
|
||||
this.model.user ? "user-row" : "channel-row"
|
||||
}`;
|
||||
},
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
<ConditionalLoadingSpinner @condition={{this.loading}}>
|
||||
{{#each this.channels as |channel|}}
|
||||
<ChatChannelSelectionRow
|
||||
@isFocused={{eq channel this.focusedRow}}
|
||||
@model={{channel}}
|
||||
@onClick={{this.switchChannel}}
|
||||
/>
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import Component from "@ember/component";
|
||||
import { action } from "@ember/object";
|
||||
import ChatChannel from "discourse/plugins/chat/discourse/models/chat-channel";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
import { bind } from "discourse-common/utils/decorators";
|
||||
import { schedule } from "@ember/runloop";
|
||||
|
@ -9,6 +8,8 @@ import { popupAjaxError } from "discourse/lib/ajax-error";
|
|||
import discourseDebounce from "discourse-common/lib/debounce";
|
||||
import { INPUT_DELAY } from "discourse-common/config/environment";
|
||||
import { isPresent } from "@ember/utils";
|
||||
import ChatChannel from "discourse/plugins/chat/discourse/models/chat-channel";
|
||||
import User from "discourse/models/user";
|
||||
|
||||
export default Component.extend({
|
||||
chat: service(),
|
||||
|
@ -19,6 +20,7 @@ export default Component.extend({
|
|||
loading: false,
|
||||
chatChannelsManager: service(),
|
||||
router: service(),
|
||||
focusedRow: null,
|
||||
|
||||
didInsertElement() {
|
||||
this._super(...arguments);
|
||||
|
@ -53,19 +55,16 @@ export default Component.extend({
|
|||
} else {
|
||||
channel = this.channels.find((c) => c.user && c.id === id);
|
||||
}
|
||||
channel?.set("focused", true);
|
||||
this.channels.forEach((c) => {
|
||||
if (c !== channel) {
|
||||
c.set("focused", false);
|
||||
}
|
||||
});
|
||||
if (channel) {
|
||||
this.set("focusedRow", channel);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@bind
|
||||
onKeyUp(e) {
|
||||
if (e.key === "Enter") {
|
||||
let focusedChannel = this.channels.find((c) => c.focused);
|
||||
let focusedChannel = this.channels.find((c) => c === this.focusedRow);
|
||||
this.switchChannel(focusedChannel);
|
||||
e.preventDefault();
|
||||
} else if (e.key === "ArrowDown") {
|
||||
|
@ -78,16 +77,17 @@ export default Component.extend({
|
|||
},
|
||||
|
||||
arrowNavigateChannels(direction) {
|
||||
const indexOfFocused = this.channels.findIndex((c) => c.focused);
|
||||
const indexOfFocused = this.channels.findIndex(
|
||||
(c) => c === this.focusedRow
|
||||
);
|
||||
if (indexOfFocused > -1) {
|
||||
const nextIndex = direction === "down" ? 1 : -1;
|
||||
const nextChannel = this.channels[indexOfFocused + nextIndex];
|
||||
if (nextChannel) {
|
||||
this.channels[indexOfFocused].set("focused", false);
|
||||
nextChannel.set("focused", true);
|
||||
this.set("focusedRow", nextChannel);
|
||||
}
|
||||
} else {
|
||||
this.channels[0].set("focused", true);
|
||||
this.set("focusedRow", this.channels[0]);
|
||||
}
|
||||
|
||||
schedule("afterRender", () => {
|
||||
|
@ -100,7 +100,7 @@ export default Component.extend({
|
|||
|
||||
@action
|
||||
switchChannel(channel) {
|
||||
if (channel.user) {
|
||||
if (channel instanceof User) {
|
||||
return this.fetchOrCreateChannelForUser(channel).then((response) => {
|
||||
const newChannel = this.chatChannelsManager.store(response.channel);
|
||||
return this.chatChannelsManager.follow(newChannel).then((c) => {
|
||||
|
@ -145,21 +145,21 @@ export default Component.extend({
|
|||
.then((searchModel) => {
|
||||
if (this.searchIndex === thisSearchIndex) {
|
||||
this.set("searchModel", searchModel);
|
||||
const channels = searchModel.public_channels.concat(
|
||||
searchModel.direct_message_channels,
|
||||
searchModel.users
|
||||
);
|
||||
channels.forEach((c) => {
|
||||
if (c.username) {
|
||||
c.user = true; // This is used by the `chat-channel-selection-row` component
|
||||
}
|
||||
});
|
||||
let channels = searchModel.public_channels
|
||||
.concat(searchModel.direct_message_channels, searchModel.users)
|
||||
.map((c) => {
|
||||
if (
|
||||
c.chatable_type === "DirectMessage" ||
|
||||
c.chatable_type === "Category"
|
||||
) {
|
||||
return ChatChannel.create(c);
|
||||
}
|
||||
|
||||
return User.create(c);
|
||||
});
|
||||
|
||||
this.setProperties({
|
||||
channels: channels.map((channel) => {
|
||||
return channel.user
|
||||
? ChatChannel.create(channel)
|
||||
: this.chatChannelsManager.store(channel);
|
||||
}),
|
||||
channels,
|
||||
loading: false,
|
||||
});
|
||||
this.focusFirstChannel(this.channels);
|
||||
|
@ -188,8 +188,11 @@ export default Component.extend({
|
|||
},
|
||||
|
||||
focusFirstChannel(channels) {
|
||||
channels.forEach((c) => c.set("focused", false));
|
||||
channels[0]?.set("focused", true);
|
||||
if (channels[0]) {
|
||||
this.set("focusedRow", channels[0]);
|
||||
} else {
|
||||
this.set("focusedRow", null);
|
||||
}
|
||||
},
|
||||
|
||||
getChannelsWithFilter(filter, opts = { excludeActiveChannel: true }) {
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
@value={{this.channel.currentUserMembership.muted}}
|
||||
@valueProperty="value"
|
||||
@class="channel-settings-view__muted-selector"
|
||||
@onChange={{action (fn this.saveNotificationSettings "muted")}}
|
||||
@onChange={{fn this.saveNotificationSettings "muted" "muted"}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -22,17 +22,19 @@
|
|||
<label class="chat-form__label">
|
||||
<span>{{i18n "chat.settings.desktop_notification_level"}}</span>
|
||||
<ChatChannelSettingsSavedIndicator
|
||||
@property={{this.channel.currentUserMembership.desktop_notification_level}}
|
||||
@property={{this.channel.currentUserMembership.desktopNotificationLevel}}
|
||||
/>
|
||||
</label>
|
||||
<div class="chat-form__control">
|
||||
<ComboBox
|
||||
@content={{this.notificationLevels}}
|
||||
@value={{this.channel.currentUserMembership.desktop_notification_level}}
|
||||
@value={{this.channel.currentUserMembership.desktopNotificationLevel}}
|
||||
@valueProperty="value"
|
||||
@class="channel-settings-view__desktop-notification-level-selector"
|
||||
@onChange={{action
|
||||
(fn this.saveNotificationSettings "desktop_notification_level")
|
||||
@onChange={{fn
|
||||
this.saveNotificationSettings
|
||||
"desktopNotificationLevel"
|
||||
"desktop_notification_level"
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
@ -42,17 +44,19 @@
|
|||
<label class="chat-form__label">
|
||||
<span>{{i18n "chat.settings.mobile_notification_level"}}</span>
|
||||
<ChatChannelSettingsSavedIndicator
|
||||
@property={{this.channel.currentUserMembership.mobile_notification_level}}
|
||||
@property={{this.channel.currentUserMembership.mobileNotificationLevel}}
|
||||
/>
|
||||
</label>
|
||||
<div class="chat-form__control">
|
||||
<ComboBox
|
||||
@content={{this.notificationLevels}}
|
||||
@value={{this.channel.currentUserMembership.mobile_notification_level}}
|
||||
@value={{this.channel.currentUserMembership.mobileNotificationLevel}}
|
||||
@valueProperty="value"
|
||||
@class="channel-settings-view__mobile-notification-level-selector"
|
||||
@onChange={{action
|
||||
(fn this.saveNotificationSettings "mobile_notification_level")
|
||||
@onChange={{fn
|
||||
this.saveNotificationSettings
|
||||
"mobileNotificationLevel"
|
||||
"mobile_notification_level"
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
@ -74,16 +78,16 @@
|
|||
<label class="chat-form__label">
|
||||
<span>{{i18n "chat.settings.auto_join_users_label"}}</span>
|
||||
<ChatChannelSettingsSavedIndicator
|
||||
@property={{this.channel.auto_join_users}}
|
||||
@property={{this.channel.autoJoinUsers}}
|
||||
/>
|
||||
</label>
|
||||
<ComboBox
|
||||
@content={{this.autoAddUsersOptions}}
|
||||
@value={{this.channel.auto_join_users}}
|
||||
@value={{this.channel.autoJoinUsers}}
|
||||
@valueProperty="value"
|
||||
@class="channel-settings-view__auto-join-selector"
|
||||
@onChange={{action
|
||||
(fn this.onToggleAutoJoinUsers this.channel.auto_join_users)
|
||||
(fn this.onToggleAutoJoinUsers this.channel.autoJoinUsers)
|
||||
}}
|
||||
/>
|
||||
<p class="chat-form__description -autojoin">
|
||||
|
@ -102,12 +106,12 @@
|
|||
<label class="chat-form__label">
|
||||
<span>{{i18n "chat.settings.channel_wide_mentions_label"}}</span>
|
||||
<ChatChannelSettingsSavedIndicator
|
||||
@property={{this.channel.allow_channel_wide_mentions}}
|
||||
@property={{this.channel.allowChannelWideMentions}}
|
||||
/>
|
||||
</label>
|
||||
<ComboBox
|
||||
@content={{this.channelWideMentionsOptions}}
|
||||
@value={{this.channel.allow_channel_wide_mentions}}
|
||||
@value={{this.channel.allowChannelWideMentions}}
|
||||
@valueProperty="value"
|
||||
@class="channel-settings-view__channel-wide-mentions-selector"
|
||||
@onChange={{this.onToggleChannelWideMentions}}
|
||||
|
|
|
@ -3,7 +3,6 @@ import { action, computed } from "@ember/object";
|
|||
import { inject as service } from "@ember/service";
|
||||
import showModal from "discourse/lib/show-modal";
|
||||
import I18n from "I18n";
|
||||
import { Promise } from "rsvp";
|
||||
import { reads } from "@ember/object/computed";
|
||||
|
||||
const NOTIFICATION_LEVELS = [
|
||||
|
@ -79,29 +78,18 @@ export default class ChatChannelSettingsView extends Component {
|
|||
}
|
||||
|
||||
@action
|
||||
saveNotificationSettings(key, value) {
|
||||
if (this.channel[key] === value) {
|
||||
saveNotificationSettings(frontendKey, backendKey, newValue) {
|
||||
if (this.channel.currentUserMembership[frontendKey] === newValue) {
|
||||
return;
|
||||
}
|
||||
|
||||
const settings = {};
|
||||
settings[key] = value;
|
||||
settings[backendKey] = newValue;
|
||||
return this.chatApi
|
||||
.updateCurrentUserChannelNotificationsSettings(this.channel.id, settings)
|
||||
.then((result) => {
|
||||
[
|
||||
"muted",
|
||||
"desktop_notification_level",
|
||||
"mobile_notification_level",
|
||||
].forEach((property) => {
|
||||
if (
|
||||
result.membership[property] !==
|
||||
this.channel.currentUserMembership[property]
|
||||
) {
|
||||
this.channel.currentUserMembership[property] =
|
||||
result.membership[property];
|
||||
}
|
||||
});
|
||||
this.channel.currentUserMembership[frontendKey] =
|
||||
result.membership[backendKey];
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -125,7 +113,7 @@ export default class ChatChannelSettingsView extends Component {
|
|||
|
||||
@action
|
||||
onToggleAutoJoinUsers() {
|
||||
if (!this.channel.auto_join_users) {
|
||||
if (!this.channel.autoJoinUsers) {
|
||||
this.onEnableAutoJoinUsers();
|
||||
} else {
|
||||
this.onDisableAutoJoinUsers();
|
||||
|
@ -134,43 +122,61 @@ export default class ChatChannelSettingsView extends Component {
|
|||
|
||||
@action
|
||||
onToggleChannelWideMentions() {
|
||||
const newValue = !this.channel.allowChannelWideMentions;
|
||||
if (this.channel.allowChannelWideMentions === newValue) {
|
||||
return;
|
||||
}
|
||||
|
||||
return this._updateChannelProperty(
|
||||
this.channel,
|
||||
"allow_channel_wide_mentions",
|
||||
!this.channel.allow_channel_wide_mentions
|
||||
);
|
||||
newValue
|
||||
).then((result) => {
|
||||
this.channel.allowChannelWideMentions =
|
||||
result.channel.allow_channel_wide_mentions;
|
||||
});
|
||||
}
|
||||
|
||||
onDisableAutoJoinUsers() {
|
||||
return this._updateChannelProperty(this.channel, "auto_join_users", false);
|
||||
if (this.channel.autoJoinUsers === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
return this._updateChannelProperty(
|
||||
this.channel,
|
||||
"auto_join_users",
|
||||
false
|
||||
).then((result) => {
|
||||
this.channel.autoJoinUsers = result.channel.auto_join_users;
|
||||
});
|
||||
}
|
||||
|
||||
onEnableAutoJoinUsers() {
|
||||
if (this.channel.autoJoinUsers === true) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.dialog.confirm({
|
||||
message: I18n.t("chat.settings.auto_join_users_warning", {
|
||||
category: this.channel.chatable.name,
|
||||
}),
|
||||
didConfirm: () =>
|
||||
this._updateChannelProperty(this.channel, "auto_join_users", true),
|
||||
this._updateChannelProperty(this.channel, "auto_join_users", true).then(
|
||||
(result) => {
|
||||
this.channel.autoJoinUsers = result.channel.auto_join_users;
|
||||
}
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
_updateChannelProperty(channel, property, value) {
|
||||
if (channel[property] === value) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
const payload = {};
|
||||
payload[property] = value;
|
||||
return this.chatApi
|
||||
.updateChannel(channel.id, payload)
|
||||
.then((result) => {
|
||||
channel.set(property, result.channel[property]);
|
||||
})
|
||||
.catch((event) => {
|
||||
if (event.jqXHR?.responseJSON?.errors) {
|
||||
this.flash(event.jqXHR.responseJSON.errors.join("\n"), "error");
|
||||
}
|
||||
});
|
||||
|
||||
return this.chatApi.updateChannel(channel.id, payload).catch((event) => {
|
||||
if (event.jqXHR?.responseJSON?.errors) {
|
||||
this.flash(event.jqXHR.responseJSON.errors.join("\n"), "error");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
{{#if this.channel.isDraft}}
|
||||
{{#if @channel.isDraft}}
|
||||
<div class="chat-channel-title is-draft">
|
||||
<span class="chat-channel-title__name">{{this.channel.title}}</span>
|
||||
<span class="chat-channel-title__name">{{@channel.title}}</span>
|
||||
{{#if (has-block)}}
|
||||
{{yield}}
|
||||
{{/if}}
|
||||
</div>
|
||||
{{else}}
|
||||
{{#if this.channel.isDirectMessageChannel}}
|
||||
{{#if @channel.isDirectMessageChannel}}
|
||||
<div class="chat-channel-title is-dm">
|
||||
|
||||
<div class="chat-channel-title__avatar">
|
||||
{{#if this.multiDm}}
|
||||
<span class="chat-channel-title__users-count">
|
||||
{{this.channel.chatable.users.length}}
|
||||
{{@channel.chatable.users.length}}
|
||||
</span>
|
||||
{{else}}
|
||||
<ChatUserAvatar @user={{this.channel.chatable.users.firstObject}} />
|
||||
<ChatUserAvatar @user={{@channel.chatable.users.firstObject}} />
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
|
@ -24,12 +24,12 @@
|
|||
{{#if this.multiDm}}
|
||||
<span class="chat-channel-title__name">{{this.usernames}}</span>
|
||||
{{else}}
|
||||
{{#let this.channel.chatable.users.firstObject as |user|}}
|
||||
{{#let @channel.chatable.users.firstObject as |user|}}
|
||||
<span class="chat-channel-title__name">{{user.username}}</span>
|
||||
{{#if this.showUserStatus}}
|
||||
<UserStatusMessage
|
||||
@class="chat-channel-title__user-status-message"
|
||||
@status={{this.channel.chatable.users.firstObject.status}}
|
||||
@status={{@channel.chatable.users.firstObject.status}}
|
||||
@showDescription={{if this.site.mobileView "true"}}
|
||||
/>
|
||||
{{/if}}
|
||||
|
@ -48,19 +48,19 @@
|
|||
{{yield}}
|
||||
{{/if}}
|
||||
</div>
|
||||
{{else if this.channel.isCategoryChannel}}
|
||||
{{else if @channel.isCategoryChannel}}
|
||||
<div class="chat-channel-title is-category">
|
||||
<span
|
||||
class="chat-channel-title__category-badge"
|
||||
style={{this.channelColorStyle}}
|
||||
>
|
||||
{{d-icon "d-chat"}}
|
||||
{{#if this.channel.chatable.read_restricted}}
|
||||
{{#if @channel.chatable.read_restricted}}
|
||||
{{d-icon "lock" class="chat-channel-title__restricted-category-icon"}}
|
||||
{{/if}}
|
||||
</span>
|
||||
<span class="chat-channel-title__name">
|
||||
{{replace-emoji this.channel.title}}
|
||||
{{replace-emoji @channel.title}}
|
||||
</span>
|
||||
|
||||
{{#if (has-block)}}
|
||||
|
|
|
@ -1,33 +1,24 @@
|
|||
import Component from "@ember/component";
|
||||
import Component from "@glimmer/component";
|
||||
import { htmlSafe } from "@ember/template";
|
||||
import { computed } from "@ember/object";
|
||||
import { gt, reads } from "@ember/object/computed";
|
||||
|
||||
export default class ChatChannelTitle extends Component {
|
||||
tagName = "";
|
||||
channel = null;
|
||||
get users() {
|
||||
return this.args.channel.chatable.users;
|
||||
}
|
||||
|
||||
@reads("channel.chatable.users.[]") users;
|
||||
@gt("users.length", 1) multiDm;
|
||||
get multiDm() {
|
||||
return this.users.length > 1;
|
||||
}
|
||||
|
||||
@computed("users")
|
||||
get usernames() {
|
||||
return this.users.mapBy("username").join(", ");
|
||||
}
|
||||
|
||||
@computed("channel.chatable.color")
|
||||
get channelColorStyle() {
|
||||
return htmlSafe(`color: #${this.channel.chatable.color}`);
|
||||
return htmlSafe(`color: #${this.args.channel.chatable.color}`);
|
||||
}
|
||||
|
||||
@computed(
|
||||
"channel.chatable.users.length",
|
||||
"channel.chatable.users.@each.status"
|
||||
)
|
||||
get showUserStatus() {
|
||||
return !!(
|
||||
this.channel.chatable.users.length === 1 &&
|
||||
this.channel.chatable.users[0].status
|
||||
);
|
||||
return !!(this.users.length === 1 && this.users[0].status);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
{{#if (gt @channel.currentUserMembership.unread_count 0)}}
|
||||
{{#if (gt @channel.currentUserMembership.unreadCount 0)}}
|
||||
<div
|
||||
class={{concat-class
|
||||
"chat-channel-unread-indicator"
|
||||
(if
|
||||
(or
|
||||
@channel.isDirectMessageChannel
|
||||
(gt @channel.currentUserMembership.unread_mentions 0)
|
||||
(gt @channel.currentUserMembership.unreadMentions 0)
|
||||
)
|
||||
"urgent"
|
||||
)
|
||||
}}
|
||||
>
|
||||
<div class="number">{{@channel.currentUserMembership.unread_count}}</div>
|
||||
<div class="number">{{@channel.currentUserMembership.unreadCount}}</div>
|
||||
</div>
|
||||
{{/if}}
|
|
@ -165,7 +165,7 @@ export default class ChatLivePane extends Component {
|
|||
findArgs["targetMessageId"] = this.requestedTargetMessageId;
|
||||
} else if (fetchingFromLastRead) {
|
||||
findArgs["targetMessageId"] =
|
||||
this.args.channel.currentUserMembership.last_read_message_id;
|
||||
this.args.channel.currentUserMembership.lastReadMessageId;
|
||||
}
|
||||
|
||||
return this.chatApi
|
||||
|
@ -346,7 +346,7 @@ export default class ChatLivePane extends Component {
|
|||
if (
|
||||
!foundFirstNew &&
|
||||
messageData.id >
|
||||
this.args.channel.currentUserMembership.last_read_message_id &&
|
||||
this.args.channel.currentUserMembership.lastReadMessageId &&
|
||||
!channel.messages.some((m) => m.newest)
|
||||
) {
|
||||
foundFirstNew = true;
|
||||
|
@ -444,7 +444,7 @@ export default class ChatLivePane extends Component {
|
|||
}
|
||||
|
||||
const lastReadId =
|
||||
this.args.channel.currentUserMembership?.last_read_message_id;
|
||||
this.args.channel.currentUserMembership?.lastReadMessageId;
|
||||
let lastUnreadVisibleMessage = this.args.channel.visibleMessages.findLast(
|
||||
(message) => !lastReadId || message.id > lastReadId
|
||||
);
|
||||
|
|
|
@ -93,7 +93,7 @@
|
|||
|
||||
{{#if this.shouldRenderReplyingIndicator}}
|
||||
<div class="chat-replying-indicator-container">
|
||||
<ChatReplyingIndicator @chatChannel={{@channel}} />
|
||||
<ChatReplyingIndicator @channel={{@channel}} />
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ import { inject as service } from "@ember/service";
|
|||
import Component from "@ember/component";
|
||||
import { action } from "@ember/object";
|
||||
import { cloneJSON } from "discourse-common/lib/object";
|
||||
|
||||
export default class ChatDraftChannelScreen extends Component {
|
||||
@service chat;
|
||||
@service router;
|
||||
|
@ -20,7 +21,7 @@ export default class ChatDraftChannelScreen extends Component {
|
|||
|
||||
@action
|
||||
onSwitchFromDraftChannel(channel) {
|
||||
channel.set("isDraft", false);
|
||||
channel.isDraft = false;
|
||||
}
|
||||
|
||||
_fetchPreviewedChannel(users) {
|
||||
|
@ -29,20 +30,16 @@ export default class ChatDraftChannelScreen extends Component {
|
|||
return this.chat
|
||||
.getDmChannelForUsernames(users.mapBy("username"))
|
||||
.then((response) => {
|
||||
this.set(
|
||||
"previewedChannel",
|
||||
ChatChannel.create(
|
||||
Object.assign({}, response.channel, { isDraft: true })
|
||||
)
|
||||
);
|
||||
const channel = ChatChannel.create(response.channel);
|
||||
channel.isDraft = true;
|
||||
this.set("previewedChannel", channel);
|
||||
})
|
||||
.catch((error) => {
|
||||
if (error?.jqXHR?.status === 404) {
|
||||
this.set(
|
||||
"previewedChannel",
|
||||
ChatChannel.create({
|
||||
chatable: { users: cloneJSON(users) },
|
||||
isDraft: true,
|
||||
ChatChannel.createDirectMessageChannelDraft({
|
||||
users: cloneJSON(users),
|
||||
})
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,10 +1,21 @@
|
|||
<div class="chat-replying-indicator">
|
||||
{{#if this.shouldDisplay}}
|
||||
<span class="chat-replying-indicator__text">{{this.text}}</span>
|
||||
<span class="chat-replying-indicator__wave">
|
||||
<span class="chat-replying-indicator__dot">.</span>
|
||||
<span class="chat-replying-indicator__dot">.</span>
|
||||
<span class="chat-replying-indicator__dot">.</span>
|
||||
</span>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{#if @channel}}
|
||||
<div
|
||||
class={{concat-class
|
||||
"chat-replying-indicator"
|
||||
(if this.presenceChannel.subscribed "is-subscribed")
|
||||
}}
|
||||
{{did-insert this.subscribe}}
|
||||
{{did-update this.handleDraft @channel.isDraft}}
|
||||
{{did-update this.subscribe this.channelName}}
|
||||
{{will-destroy this.teardown}}
|
||||
>
|
||||
{{#if this.shouldRender}}
|
||||
<span class="chat-replying-indicator__text">{{this.text}}</span>
|
||||
<span class="chat-replying-indicator__wave">
|
||||
<span class="chat-replying-indicator__dot">.</span>
|
||||
<span class="chat-replying-indicator__dot">.</span>
|
||||
<span class="chat-replying-indicator__dot">.</span>
|
||||
</span>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
|
@ -1,89 +1,93 @@
|
|||
import { isBlank, isPresent } from "@ember/utils";
|
||||
import Component from "@ember/component";
|
||||
import Component from "@glimmer/component";
|
||||
import { inject as service } from "@ember/service";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import I18n from "I18n";
|
||||
import { fmt } from "discourse/lib/computed";
|
||||
import { next } from "@ember/runloop";
|
||||
import { action } from "@ember/object";
|
||||
import { tracked } from "@glimmer/tracking";
|
||||
|
||||
export default Component.extend({
|
||||
tagName: "",
|
||||
presence: service(),
|
||||
presenceChannel: null,
|
||||
chatChannel: null,
|
||||
export default class ChatReplyingIndicator extends Component {
|
||||
@service currentUser;
|
||||
@service presence;
|
||||
|
||||
@discourseComputed("presenceChannel.users.[]")
|
||||
usernames(users) {
|
||||
return users
|
||||
?.filter((u) => u.id !== this.currentUser.id)
|
||||
?.mapBy("username");
|
||||
},
|
||||
@tracked presenceChannel = null;
|
||||
@tracked users = [];
|
||||
|
||||
@discourseComputed("usernames.[]")
|
||||
text(usernames) {
|
||||
if (isBlank(usernames)) {
|
||||
@action
|
||||
async subscribe() {
|
||||
this.presenceChannel = this.presence.getChannel(this.channelName);
|
||||
this.presenceChannel.on("change", this.handlePresenceChange);
|
||||
await this.presenceChannel.subscribe();
|
||||
}
|
||||
|
||||
@action
|
||||
async resubscribe() {
|
||||
await this.teardown();
|
||||
await this.subscribe();
|
||||
}
|
||||
|
||||
@action
|
||||
handlePresenceChange(presenceChannel) {
|
||||
this.users = presenceChannel.users || [];
|
||||
}
|
||||
|
||||
@action
|
||||
async handleDraft() {
|
||||
if (this.args.channel.isDraft) {
|
||||
await this.teardown();
|
||||
} else {
|
||||
await this.resubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
async teardown() {
|
||||
if (this.presenceChannel) {
|
||||
await this.presenceChannel.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
get usernames() {
|
||||
return this.users
|
||||
.filter((u) => u.id !== this.currentUser.id)
|
||||
.mapBy("username");
|
||||
}
|
||||
|
||||
get text() {
|
||||
if (isBlank(this.usernames)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (usernames.length === 1) {
|
||||
if (this.usernames.length === 1) {
|
||||
return I18n.t("chat.replying_indicator.single_user", {
|
||||
username: usernames[0],
|
||||
username: this.usernames[0],
|
||||
});
|
||||
}
|
||||
|
||||
if (usernames.length < 4) {
|
||||
const lastUsername = usernames.pop();
|
||||
const commaSeparatedUsernames = usernames.join(
|
||||
I18n.t("word_connector.comma")
|
||||
);
|
||||
if (this.usernames.length < 4) {
|
||||
const lastUsername = this.usernames[this.usernames.length - 1];
|
||||
const commaSeparatedUsernames = this.usernames
|
||||
.slice(0, this.usernames.length - 1)
|
||||
.join(I18n.t("word_connector.comma"));
|
||||
return I18n.t("chat.replying_indicator.multiple_users", {
|
||||
commaSeparatedUsernames,
|
||||
lastUsername,
|
||||
});
|
||||
}
|
||||
|
||||
const commaSeparatedUsernames = usernames
|
||||
const commaSeparatedUsernames = this.usernames
|
||||
.slice(0, 2)
|
||||
.join(I18n.t("word_connector.comma"));
|
||||
return I18n.t("chat.replying_indicator.many_users", {
|
||||
commaSeparatedUsernames,
|
||||
count: usernames.length - 2,
|
||||
count: this.usernames.length - 2,
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
@discourseComputed("usernames.[]")
|
||||
shouldDisplay(usernames) {
|
||||
return isPresent(usernames);
|
||||
},
|
||||
get shouldRender() {
|
||||
return isPresent(this.usernames);
|
||||
}
|
||||
|
||||
channelName: fmt("chatChannel.id", "/chat-reply/%@"),
|
||||
|
||||
didReceiveAttrs() {
|
||||
this._super(...arguments);
|
||||
|
||||
if (!this.chatChannel || this.chatChannel.isDraft) {
|
||||
this.presenceChannel?.unsubscribe();
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.presenceChannel?.name !== this.channelName) {
|
||||
this.presenceChannel?.unsubscribe();
|
||||
|
||||
next(() => {
|
||||
if (this.isDestroyed || this.isDestroying) {
|
||||
return;
|
||||
}
|
||||
|
||||
const presenceChannel = this.presence.getChannel(this.channelName);
|
||||
this.set("presenceChannel", presenceChannel);
|
||||
presenceChannel.subscribe();
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
willDestroyElement() {
|
||||
this._super(...arguments);
|
||||
|
||||
this.presenceChannel?.unsubscribe();
|
||||
},
|
||||
});
|
||||
get channelName() {
|
||||
return `/chat-reply/${this.args.channel.id}`;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -75,14 +75,14 @@ export default class ChatSelectionManager extends Component {
|
|||
const openOpts = {};
|
||||
|
||||
if (this.chatChannel.isCategoryChannel) {
|
||||
openOpts.categoryId = this.chatChannel.chatable_id;
|
||||
openOpts.categoryId = this.chatChannel.chatableId;
|
||||
}
|
||||
|
||||
if (this.site.mobileView) {
|
||||
// go to the relevant chatable (e.g. category) and open the
|
||||
// composer to insert text
|
||||
if (this.chatChannel.chatable_url) {
|
||||
this.router.transitionTo(this.chatChannel.chatable_url);
|
||||
if (this.chatChannel.chatableUrl) {
|
||||
this.router.transitionTo(this.chatChannel.chatableUrl);
|
||||
}
|
||||
|
||||
await composer.focusComposer({
|
||||
|
|
|
@ -8,7 +8,7 @@ import { INPUT_DELAY } from "discourse-common/config/environment";
|
|||
import { inject as service } from "@ember/service";
|
||||
import { schedule } from "@ember/runloop";
|
||||
import { gt, not } from "@ember/object/computed";
|
||||
import { createDirectMessageChannelDraft } from "discourse/plugins/chat/discourse/models/chat-channel";
|
||||
import ChatChannel from "discourse/plugins/chat/discourse/models/chat-channel";
|
||||
|
||||
export default Component.extend({
|
||||
tagName: "",
|
||||
|
@ -29,7 +29,7 @@ export default Component.extend({
|
|||
|
||||
this.set("users", []);
|
||||
this.set("selectedUsers", []);
|
||||
this.set("channel", createDirectMessageChannelDraft());
|
||||
this.set("channel", ChatChannel.createDirectMessageChannelDraft());
|
||||
},
|
||||
|
||||
didInsertElement() {
|
||||
|
|
|
@ -154,7 +154,7 @@ export default {
|
|||
}
|
||||
|
||||
const highlightable = [`@${this.currentUser.username}`];
|
||||
if (chatChannel.allow_channel_wide_mentions) {
|
||||
if (chatChannel.allowChannelWideMentions) {
|
||||
highlightable.push(...MENTION_KEYWORDS.map((k) => `@${k}`));
|
||||
}
|
||||
|
||||
|
|
|
@ -88,13 +88,13 @@ export default {
|
|||
}
|
||||
|
||||
get suffixValue() {
|
||||
return this.channel.currentUserMembership.unread_count > 0
|
||||
return this.channel.currentUserMembership.unreadCount > 0
|
||||
? "circle"
|
||||
: "";
|
||||
}
|
||||
|
||||
get suffixCSSClass() {
|
||||
return this.channel.currentUserMembership.unread_mentions > 0
|
||||
return this.channel.currentUserMembership.unreadMentions > 0
|
||||
? "urgent"
|
||||
: "unread";
|
||||
}
|
||||
|
@ -282,7 +282,7 @@ export default {
|
|||
}
|
||||
|
||||
get suffixValue() {
|
||||
return this.channel.currentUserMembership.unread_count > 0
|
||||
return this.channel.currentUserMembership.unreadCount > 0
|
||||
? "circle"
|
||||
: "";
|
||||
}
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
import { tracked } from "@glimmer/tracking";
|
||||
|
||||
export default class ChatChannelArchive {
|
||||
static create(args = {}) {
|
||||
return new ChatChannelArchive(args);
|
||||
}
|
||||
|
||||
@tracked failed;
|
||||
@tracked completed;
|
||||
@tracked messages;
|
||||
@tracked topicId;
|
||||
@tracked totalMessages;
|
||||
|
||||
constructor(args = {}) {
|
||||
this.failed = args.archive_failed;
|
||||
this.completed = args.archive_completed;
|
||||
this.messages = args.archived_messages;
|
||||
this.topicId = args.archive_topic_id;
|
||||
this.totalMessages = args.total_messages;
|
||||
}
|
||||
}
|
|
@ -1,5 +1,3 @@
|
|||
import RestModel from "discourse/models/rest";
|
||||
import User from "discourse/models/user";
|
||||
import UserChatChannelMembership from "discourse/plugins/chat/discourse/models/user-chat-channel-membership";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
import { escapeExpression } from "discourse/lib/utilities";
|
||||
|
@ -10,6 +8,9 @@ import ChatMessagesManager from "discourse/plugins/chat/discourse/lib/chat-messa
|
|||
import { getOwner } from "discourse-common/lib/get-owner";
|
||||
import guid from "pretty-text/guid";
|
||||
import ChatThread from "discourse/plugins/chat/discourse/models/chat-thread";
|
||||
import ChatDirectMessage from "discourse/plugins/chat/discourse/models/chat-direct-message";
|
||||
import ChatChannelArchive from "discourse/plugins/chat/discourse/models/chat-channel-archive";
|
||||
import Category from "discourse/models/category";
|
||||
|
||||
export const CHATABLE_TYPES = {
|
||||
directMessageChannel: "DirectMessage",
|
||||
|
@ -49,25 +50,79 @@ const READONLY_STATUSES = [
|
|||
CHANNEL_STATUSES.archived,
|
||||
];
|
||||
|
||||
export default class ChatChannel extends RestModel {
|
||||
export default class ChatChannel {
|
||||
static create(args = {}) {
|
||||
return new ChatChannel(args);
|
||||
}
|
||||
|
||||
static createDirectMessageChannelDraft(args = {}) {
|
||||
const channel = ChatChannel.create({
|
||||
chatable_type: CHATABLE_TYPES.directMessageChannel,
|
||||
chatable: {
|
||||
users: args.users || [],
|
||||
},
|
||||
});
|
||||
channel.isDraft = true;
|
||||
return channel;
|
||||
}
|
||||
|
||||
@tracked currentUserMembership = null;
|
||||
@tracked isDraft = false;
|
||||
@tracked title;
|
||||
@tracked slug;
|
||||
@tracked description;
|
||||
@tracked chatableType;
|
||||
@tracked status;
|
||||
@tracked activeThread;
|
||||
@tracked activeThread = null;
|
||||
@tracked lastMessageSentAt;
|
||||
@tracked canDeleteOthers;
|
||||
@tracked canDeleteSelf;
|
||||
@tracked canFlag;
|
||||
@tracked canModerate;
|
||||
@tracked userSilenced;
|
||||
@tracked draft;
|
||||
@tracked draft = null;
|
||||
@tracked meta;
|
||||
@tracked chatableType;
|
||||
@tracked chatableUrl;
|
||||
@tracked autoJoinUsers = false;
|
||||
@tracked allowChannelWideMentions = true;
|
||||
@tracked membershipsCount = 0;
|
||||
@tracked archive;
|
||||
|
||||
threadsManager = new ChatThreadsManager(getOwner(this));
|
||||
messagesManager = new ChatMessagesManager(getOwner(this));
|
||||
|
||||
constructor(args = {}) {
|
||||
this.id = args.id;
|
||||
this.chatableId = args.chatable_id;
|
||||
this.chatableUrl = args.chatable_url;
|
||||
this.chatableType = args.chatable_type;
|
||||
this.membershipsCount = args.memberships_count;
|
||||
this.meta = args.meta;
|
||||
this.slug = args.slug;
|
||||
this.title = args.title;
|
||||
this.status = args.status;
|
||||
this.canDeleteSelf = args.can_delete_self;
|
||||
this.canDeleteOthers = args.can_delete_others;
|
||||
this.canFlag = args.can_flag;
|
||||
this.userSilenced = args.user_silenced;
|
||||
this.canModerate = args.can_moderate;
|
||||
this.description = args.description;
|
||||
this.lastMessageSentAt = args.last_message_sent_at;
|
||||
this.threadingEnabled = args.threading_enabled;
|
||||
this.autoJoinUsers = args.auto_join_users;
|
||||
this.allowChannelWideMentions = args.allow_channel_wide_mentions;
|
||||
this.chatable = this.isDirectMessageChannel
|
||||
? ChatDirectMessage.create(args)
|
||||
: Category.create(args.chatable);
|
||||
this.currentUserMembership = UserChatChannelMembership.create(
|
||||
args.current_user_membership
|
||||
);
|
||||
|
||||
if (args.archive_completed || args.archive_failed) {
|
||||
this.archive = ChatChannelArchive.create(args);
|
||||
}
|
||||
}
|
||||
|
||||
findIndexOfMessage(id) {
|
||||
return this.messagesManager.findIndexOfMessage(id);
|
||||
}
|
||||
|
@ -223,14 +278,14 @@ export default class ChatChannel extends RestModel {
|
|||
|
||||
updateMembership(membership) {
|
||||
this.currentUserMembership.following = membership.following;
|
||||
this.currentUserMembership.last_read_message_id =
|
||||
this.currentUserMembership.lastReadMessage_id =
|
||||
membership.last_read_message_id;
|
||||
this.currentUserMembership.desktop_notification_level =
|
||||
this.currentUserMembership.desktopNotificationLevel =
|
||||
membership.desktop_notification_level;
|
||||
this.currentUserMembership.mobile_notification_level =
|
||||
this.currentUserMembership.mobileNotificationLevel =
|
||||
membership.mobile_notification_level;
|
||||
this.currentUserMembership.unread_count = membership.unread_count;
|
||||
this.currentUserMembership.unread_mentions = membership.unread_mentions;
|
||||
this.currentUserMembership.unreadCount = membership.unread_count;
|
||||
this.currentUserMembership.unreadMentions = membership.unread_mentions;
|
||||
this.currentUserMembership.muted = membership.muted;
|
||||
}
|
||||
|
||||
|
@ -239,7 +294,7 @@ export default class ChatChannel extends RestModel {
|
|||
return;
|
||||
}
|
||||
|
||||
if (this.currentUserMembership.last_read_message_id >= messageId) {
|
||||
if (this.currentUserMembership.lastReadMessageId >= messageId) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -250,59 +305,3 @@ export default class ChatChannel extends RestModel {
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
ChatChannel.reopenClass({
|
||||
create(args) {
|
||||
args = args || {};
|
||||
|
||||
this._initUserModels(args);
|
||||
this._initUserMembership(args);
|
||||
|
||||
this._remapKey(args, "chatable_type", "chatableType");
|
||||
this._remapKey(args, "memberships_count", "membershipsCount");
|
||||
this._remapKey(args, "last_message_sent_at", "lastMessageSentAt");
|
||||
this._remapKey(args, "threading_enabled", "threadingEnabled");
|
||||
|
||||
return this._super(args);
|
||||
},
|
||||
|
||||
_remapKey(obj, oldKey, newKey) {
|
||||
delete Object.assign(obj, { [newKey]: obj[oldKey] })[oldKey];
|
||||
},
|
||||
|
||||
_initUserModels(args) {
|
||||
if (args.chatable?.users?.length) {
|
||||
for (let i = 0; i < args.chatable?.users?.length; i++) {
|
||||
const userData = args.chatable.users[i];
|
||||
args.chatable.users[i] = User.create(userData);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_initUserMembership(args) {
|
||||
if (args.currentUserMembership instanceof UserChatChannelMembership) {
|
||||
return;
|
||||
}
|
||||
|
||||
args.currentUserMembership = UserChatChannelMembership.create(
|
||||
args.current_user_membership || {
|
||||
following: false,
|
||||
muted: false,
|
||||
unread_count: 0,
|
||||
unread_mentions: 0,
|
||||
}
|
||||
);
|
||||
|
||||
delete args.current_user_membership;
|
||||
},
|
||||
});
|
||||
|
||||
export function createDirectMessageChannelDraft() {
|
||||
return ChatChannel.create({
|
||||
isDraft: true,
|
||||
chatable_type: CHATABLE_TYPES.directMessageChannel,
|
||||
chatable: {
|
||||
users: [],
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
import User from "discourse/models/user";
|
||||
import { tracked } from "@glimmer/tracking";
|
||||
|
||||
export default class ChatDirectMessage {
|
||||
static create(args = {}) {
|
||||
return new ChatDirectMessage(args);
|
||||
}
|
||||
|
||||
@tracked id;
|
||||
@tracked users = null;
|
||||
|
||||
constructor(args = {}) {
|
||||
this.id = args.chatable.id;
|
||||
this.users = this.#initUsers(args.chatable.users || []);
|
||||
}
|
||||
|
||||
#initUsers(users) {
|
||||
return users.map((user) => {
|
||||
if (!user || user instanceof User) {
|
||||
return user;
|
||||
}
|
||||
|
||||
return User.create(user);
|
||||
});
|
||||
}
|
||||
}
|
|
@ -166,7 +166,7 @@ export default class ChatMessage {
|
|||
}
|
||||
|
||||
get read() {
|
||||
return this.channel.currentUserMembership?.last_read_message_id >= this.id;
|
||||
return this.channel.currentUserMembership?.lastReadMessageId >= this.id;
|
||||
}
|
||||
|
||||
get firstMessageOfTheDayAt() {
|
||||
|
|
|
@ -1,28 +1,36 @@
|
|||
import RestModel from "discourse/models/rest";
|
||||
import { tracked } from "@glimmer/tracking";
|
||||
import User from "discourse/models/user";
|
||||
export default class UserChatChannelMembership extends RestModel {
|
||||
|
||||
export default class UserChatChannelMembership {
|
||||
static create(args = {}) {
|
||||
return new UserChatChannelMembership(args);
|
||||
}
|
||||
|
||||
@tracked following = false;
|
||||
@tracked muted = false;
|
||||
@tracked unread_count = 0;
|
||||
@tracked unread_mentions = 0;
|
||||
@tracked desktop_notification_level = null;
|
||||
@tracked mobile_notification_level = null;
|
||||
@tracked last_read_message_id = null;
|
||||
}
|
||||
@tracked unreadCount = 0;
|
||||
@tracked unreadMentions = 0;
|
||||
@tracked desktopNotificationLevel = null;
|
||||
@tracked mobileNotificationLevel = null;
|
||||
@tracked lastReadMessageId = null;
|
||||
@tracked user = null;
|
||||
|
||||
UserChatChannelMembership.reopenClass({
|
||||
create(args) {
|
||||
args = args || {};
|
||||
this._initUser(args);
|
||||
return this._super(args);
|
||||
},
|
||||
constructor(args = {}) {
|
||||
this.following = args.following;
|
||||
this.muted = args.muted;
|
||||
this.unreadCount = args.unread_count;
|
||||
this.unreadMentions = args.unread_mentions;
|
||||
this.desktopNotificationLevel = args.desktop_notification_level;
|
||||
this.mobileNotificationLevel = args.mobile_notification_level;
|
||||
this.lastReadMessageId = args.last_read_message_id;
|
||||
this.user = this.#initUserModel(args.user);
|
||||
}
|
||||
|
||||
_initUser(args) {
|
||||
if (!args.user || args.user instanceof User) {
|
||||
return;
|
||||
#initUserModel(user) {
|
||||
if (!user || user instanceof User) {
|
||||
return user;
|
||||
}
|
||||
|
||||
args.user = User.create(args.user);
|
||||
},
|
||||
});
|
||||
return User.create(user);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,11 +61,10 @@ export default class ChatChannelsManager extends Service {
|
|||
return this.chatApi.followChannel(model.id).then((membership) => {
|
||||
model.currentUserMembership.following = membership.following;
|
||||
model.currentUserMembership.muted = membership.muted;
|
||||
model.currentUserMembership.desktop_notification_level =
|
||||
membership.desktop_notification_level;
|
||||
model.currentUserMembership.mobile_notification_level =
|
||||
membership.mobile_notification_level;
|
||||
|
||||
model.currentUserMembership.desktopNotificationLevel =
|
||||
membership.desktopNotificationLevel;
|
||||
model.currentUserMembership.mobileNotificationLevel =
|
||||
membership.mobileNotificationLevel;
|
||||
return model;
|
||||
});
|
||||
} else {
|
||||
|
@ -97,7 +96,7 @@ export default class ChatChannelsManager extends Service {
|
|||
get unreadCount() {
|
||||
let count = 0;
|
||||
this.publicMessageChannels.forEach((channel) => {
|
||||
count += channel.currentUserMembership.unread_count || 0;
|
||||
count += channel.currentUserMembership.unreadCount || 0;
|
||||
});
|
||||
return count;
|
||||
}
|
||||
|
@ -106,9 +105,9 @@ export default class ChatChannelsManager extends Service {
|
|||
let count = 0;
|
||||
this.channels.forEach((channel) => {
|
||||
if (channel.isDirectMessageChannel) {
|
||||
count += channel.currentUserMembership.unread_count || 0;
|
||||
count += channel.currentUserMembership.unreadCount || 0;
|
||||
}
|
||||
count += channel.currentUserMembership.unread_mentions || 0;
|
||||
count += channel.currentUserMembership.unreadMentions || 0;
|
||||
});
|
||||
return count;
|
||||
}
|
||||
|
@ -159,8 +158,8 @@ export default class ChatChannelsManager extends Service {
|
|||
|
||||
#sortDirectMessageChannels(channels) {
|
||||
return channels.sort((a, b) => {
|
||||
const unreadCountA = a.currentUserMembership.unread_count || 0;
|
||||
const unreadCountB = b.currentUserMembership.unread_count || 0;
|
||||
const unreadCountA = a.currentUserMembership.unreadCount || 0;
|
||||
const unreadCountB = b.currentUserMembership.unreadCount || 0;
|
||||
if (unreadCountA === unreadCountB) {
|
||||
return new Date(a.lastMessageSentAt) > new Date(b.lastMessageSentAt)
|
||||
? -1
|
||||
|
|
|
@ -2,6 +2,7 @@ import Service, { inject as service } from "@ember/service";
|
|||
import I18n from "I18n";
|
||||
import { bind } from "discourse-common/utils/decorators";
|
||||
import { CHANNEL_STATUSES } from "discourse/plugins/chat/discourse/models/chat-channel";
|
||||
import ChatChannelArchive from "../models/chat-channel-archive";
|
||||
|
||||
export default class ChatSubscriptionsManager extends Service {
|
||||
@service store;
|
||||
|
@ -125,13 +126,7 @@ export default class ChatSubscriptionsManager extends Service {
|
|||
return;
|
||||
}
|
||||
|
||||
channel.setProperties({
|
||||
archive_failed: busData.archive_failed,
|
||||
archive_completed: busData.archive_completed,
|
||||
archived_messages: busData.archived_messages,
|
||||
archive_topic_id: busData.archive_topic_id,
|
||||
total_messages: busData.total_messages,
|
||||
});
|
||||
channel.archive = ChatChannelArchive.create(busData);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -139,8 +134,8 @@ export default class ChatSubscriptionsManager extends Service {
|
|||
_onNewMentions(busData) {
|
||||
this.chatChannelsManager.find(busData.channel_id).then((channel) => {
|
||||
const membership = channel.currentUserMembership;
|
||||
if (busData.message_id > membership?.last_read_message_id) {
|
||||
membership.unread_mentions = (membership.unread_mentions || 0) + 1;
|
||||
if (busData.message_id > membership?.lastReadMessageId) {
|
||||
membership.unreadMentions = (membership.unreadMentions || 0) + 1;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -186,20 +181,18 @@ export default class ChatSubscriptionsManager extends Service {
|
|||
this.chatChannelsManager.find(busData.channel_id).then((channel) => {
|
||||
if (busData.user_id === this.currentUser.id) {
|
||||
// User sent message, update tracking state to no unread
|
||||
channel.currentUserMembership.last_read_message_id = busData.message_id;
|
||||
channel.currentUserMembership.lastReadMessageId = busData.message_id;
|
||||
} else {
|
||||
// Ignored user sent message, update tracking state to no unread
|
||||
if (this.currentUser.ignored_users.includes(busData.username)) {
|
||||
channel.currentUserMembership.last_read_message_id =
|
||||
busData.message_id;
|
||||
channel.currentUserMembership.lastReadMessageId = busData.message_id;
|
||||
} else {
|
||||
// Message from other user. Increment trackings state
|
||||
if (
|
||||
busData.message_id >
|
||||
(channel.currentUserMembership.last_read_message_id || 0)
|
||||
(channel.currentUserMembership.lastReadMessageId || 0)
|
||||
) {
|
||||
channel.currentUserMembership.unread_count =
|
||||
channel.currentUserMembership.unread_count + 1;
|
||||
channel.currentUserMembership.unreadCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -256,11 +249,10 @@ export default class ChatSubscriptionsManager extends Service {
|
|||
@bind
|
||||
_updateChannelTrackingData(channelId, trackingData) {
|
||||
this.chatChannelsManager.find(channelId).then((channel) => {
|
||||
channel.currentUserMembership.last_read_message_id =
|
||||
channel.currentUserMembership.lastReadMessageId =
|
||||
trackingData.last_read_message_id;
|
||||
channel.currentUserMembership.unread_count = trackingData.unread_count;
|
||||
channel.currentUserMembership.unread_mentions =
|
||||
trackingData.mention_count;
|
||||
channel.currentUserMembership.unreadCount = trackingData.unread_count;
|
||||
channel.currentUserMembership.unreadMentions = trackingData.mention_count;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -289,7 +281,7 @@ export default class ChatSubscriptionsManager extends Service {
|
|||
channel.isDirectMessageChannel &&
|
||||
!channel.currentUserMembership.following
|
||||
) {
|
||||
channel.currentUserMembership.unread_count = 1;
|
||||
channel.currentUserMembership.unreadCount = 1;
|
||||
}
|
||||
|
||||
this.chatChannelsManager.follow(channel);
|
||||
|
@ -341,9 +333,7 @@ export default class ChatSubscriptionsManager extends Service {
|
|||
.find(busData.chat_channel_id, { fetchIfNotFound: false })
|
||||
.then((channel) => {
|
||||
if (channel) {
|
||||
channel.setProperties({
|
||||
memberships_count: busData.memberships_count,
|
||||
});
|
||||
channel.membershipsCount = busData.memberships_count;
|
||||
this.appEvents.trigger("chat:refresh-channel-members");
|
||||
}
|
||||
});
|
||||
|
@ -353,11 +343,9 @@ export default class ChatSubscriptionsManager extends Service {
|
|||
_onChannelEdits(busData) {
|
||||
this.chatChannelsManager.find(busData.chat_channel_id).then((channel) => {
|
||||
if (channel) {
|
||||
channel.setProperties({
|
||||
title: busData.name,
|
||||
description: busData.description,
|
||||
slug: busData.slug,
|
||||
});
|
||||
channel.title = busData.name;
|
||||
channel.description = busData.description;
|
||||
channel.slug = busData.slug;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -365,15 +353,15 @@ export default class ChatSubscriptionsManager extends Service {
|
|||
@bind
|
||||
_onChannelStatus(busData) {
|
||||
this.chatChannelsManager.find(busData.chat_channel_id).then((channel) => {
|
||||
channel.set("status", busData.status);
|
||||
channel.status = busData.status;
|
||||
|
||||
// it is not possible for the user to set their last read message id
|
||||
// if the channel has been archived, because all the messages have
|
||||
// been deleted. we don't want them seeing the blue dot anymore so
|
||||
// just completely reset the unreads
|
||||
if (busData.status === CHANNEL_STATUSES.archived) {
|
||||
channel.currentUserMembership.unread_count = 0;
|
||||
channel.currentUserMembership.unread_mentions = 0;
|
||||
channel.currentUserMembership.unreadCount = 0;
|
||||
channel.currentUserMembership.unreadMentions = 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -283,7 +283,7 @@ export default class Chat extends Service {
|
|||
const membership = channel.currentUserMembership;
|
||||
|
||||
if (channel.isDirectMessageChannel) {
|
||||
if (!dmChannelWithUnread && membership.unread_count > 0) {
|
||||
if (!dmChannelWithUnread && membership.unreadCount > 0) {
|
||||
dmChannelWithUnread = channel.id;
|
||||
} else if (!dmChannel) {
|
||||
dmChannel = channel.id;
|
||||
|
@ -292,7 +292,7 @@ export default class Chat extends Service {
|
|||
if (membership.unread_mentions > 0) {
|
||||
publicChannelWithMention = channel.id;
|
||||
return; // <- We have a public channel with a mention. Break and return this.
|
||||
} else if (!publicChannelWithUnread && membership.unread_count > 0) {
|
||||
} else if (!publicChannelWithUnread && membership.unreadCount > 0) {
|
||||
publicChannelWithUnread = channel.id;
|
||||
} else if (
|
||||
!defaultChannel &&
|
||||
|
|
|
@ -20,6 +20,7 @@ RSpec.describe "Channel selector modal", type: :system, js: true do
|
|||
find("body").send_keys([key_modifier, "k"])
|
||||
find("#chat-channel-selector-input").fill_in(with: channel_1.title)
|
||||
find(".chat-channel-selection-row[data-id='#{channel_1.id}']").click
|
||||
|
||||
channel_page.send_message("Hello world")
|
||||
|
||||
expect(channel_page).to have_message(text: "Hello world")
|
||||
|
@ -33,6 +34,7 @@ RSpec.describe "Channel selector modal", type: :system, js: true do
|
|||
find("body").send_keys([key_modifier, "k"])
|
||||
find("#chat-channel-selector-input").fill_in(with: user_1.username)
|
||||
find(".chat-channel-selection-row[data-id='#{user_1.id}']").click
|
||||
|
||||
channel_page.send_message("Hello world")
|
||||
|
||||
expect(channel_page).to have_message(text: "Hello world")
|
||||
|
@ -69,7 +71,6 @@ RSpec.describe "Channel selector modal", type: :system, js: true do
|
|||
fab!(:channel_1) { Fabricate(:private_category_channel, group: group_1) }
|
||||
|
||||
it "it doesn’t include limited access channel" do
|
||||
chat_page.visit_channel(channel_1)
|
||||
find("body").send_keys([key_modifier, "k"])
|
||||
find("#chat-channel-selector-input").fill_in(with: channel_1.title)
|
||||
|
||||
|
|
|
@ -126,11 +126,11 @@ RSpec.describe "Drawer", type: :system, js: true do
|
|||
session.quit
|
||||
end
|
||||
|
||||
expect(page).to have_content("onlyonce", count: 1)
|
||||
expect(page).to have_content("onlyonce", count: 1, wait: 20)
|
||||
|
||||
chat_page.visit_channel(channel_2)
|
||||
|
||||
expect(page).to have_content("onlyonce", count: 0)
|
||||
expect(page).to have_content("onlyonce", count: 0, wait: 20)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -10,15 +10,13 @@ module("Discourse Chat | Component | chat-channel-card", function (hooks) {
|
|||
setupRenderingTest(hooks);
|
||||
|
||||
hooks.beforeEach(function () {
|
||||
this.set("channel", fabricators.chatChannel());
|
||||
this.channel.set(
|
||||
"description",
|
||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."
|
||||
);
|
||||
this.channel = fabricators.chatChannel();
|
||||
this.channel.description =
|
||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.";
|
||||
});
|
||||
|
||||
test("escapes channel title", async function (assert) {
|
||||
this.channel.set("title", "<div class='xss'>evil</div>");
|
||||
this.channel.title = "<div class='xss'>evil</div>";
|
||||
|
||||
await render(hbs`<ChatChannelCard @channel={{this.channel}} />`);
|
||||
|
||||
|
@ -26,7 +24,7 @@ module("Discourse Chat | Component | chat-channel-card", function (hooks) {
|
|||
});
|
||||
|
||||
test("escapes channel description", async function (assert) {
|
||||
this.channel.set("description", "<div class='xss'>evil</div>");
|
||||
this.channel.description = "<div class='xss'>evil</div>";
|
||||
|
||||
await render(hbs`<ChatChannelCard @channel={{this.channel}} />`);
|
||||
|
||||
|
@ -34,14 +32,14 @@ module("Discourse Chat | Component | chat-channel-card", function (hooks) {
|
|||
});
|
||||
|
||||
test("Closed channel", async function (assert) {
|
||||
this.channel.set("status", "closed");
|
||||
this.channel.status = "closed";
|
||||
await render(hbs`<ChatChannelCard @channel={{this.channel}} />`);
|
||||
|
||||
assert.true(exists(".chat-channel-card.-closed"));
|
||||
});
|
||||
|
||||
test("Archived channel", async function (assert) {
|
||||
this.channel.set("status", "archived");
|
||||
this.channel.status = "archived";
|
||||
await render(hbs`<ChatChannelCard @channel={{this.channel}} />`);
|
||||
|
||||
assert.true(exists(".chat-channel-card.-archived"));
|
||||
|
@ -59,7 +57,7 @@ module("Discourse Chat | Component | chat-channel-card", function (hooks) {
|
|||
});
|
||||
|
||||
test("Joined channel", async function (assert) {
|
||||
this.channel.currentUserMembership.set("following", true);
|
||||
this.channel.currentUserMembership.following = true;
|
||||
await render(hbs`<ChatChannelCard @channel={{this.channel}} />`);
|
||||
|
||||
assert.strictEqual(
|
||||
|
@ -77,7 +75,7 @@ module("Discourse Chat | Component | chat-channel-card", function (hooks) {
|
|||
});
|
||||
|
||||
test("Memberships count", async function (assert) {
|
||||
this.channel.set("membershipsCount", 4);
|
||||
this.channel.membershipsCount = 4;
|
||||
await render(hbs`<ChatChannelCard @channel={{this.channel}} />`);
|
||||
|
||||
assert.strictEqual(
|
||||
|
@ -87,7 +85,7 @@ module("Discourse Chat | Component | chat-channel-card", function (hooks) {
|
|||
});
|
||||
|
||||
test("No description", async function (assert) {
|
||||
this.channel.set("description", null);
|
||||
this.channel.description = null;
|
||||
await render(hbs`<ChatChannelCard @channel={{this.channel}} />`);
|
||||
|
||||
assert.false(exists(".chat-channel-card__description"));
|
||||
|
@ -118,7 +116,7 @@ module("Discourse Chat | Component | chat-channel-card", function (hooks) {
|
|||
});
|
||||
|
||||
test("Read restricted chatable", async function (assert) {
|
||||
this.channel.set("chatable.read_restricted", true);
|
||||
this.channel.chatable.read_restricted = true;
|
||||
await render(hbs`<ChatChannelCard @channel={{this.channel}} />`);
|
||||
|
||||
assert.true(exists(".d-icon-lock"));
|
||||
|
|
|
@ -5,20 +5,15 @@ import hbs from "htmlbars-inline-precompile";
|
|||
import pretender from "discourse/tests/helpers/create-pretender";
|
||||
import I18n from "I18n";
|
||||
import { module, test } from "qunit";
|
||||
import fabricators from "../helpers/fabricators";
|
||||
|
||||
module("Discourse Chat | Component | chat-channel-leave-btn", function (hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
|
||||
test("accepts an optional onLeaveChannel callback", async function (assert) {
|
||||
this.set("foo", 1);
|
||||
this.set("onLeaveChannel", () => this.set("foo", 2));
|
||||
this.set("channel", {
|
||||
id: 1,
|
||||
chatable_type: "DirectMessage",
|
||||
chatable: {
|
||||
users: [{ id: 1 }],
|
||||
},
|
||||
});
|
||||
this.foo = 1;
|
||||
this.onLeaveChannel = () => (this.foo = 2);
|
||||
this.channel = fabricators.directMessageChatChannel({ users: [{ id: 1 }] });
|
||||
|
||||
await render(
|
||||
hbs`<ChatChannelLeaveBtn @channel={{this.channel}} @onLeaveChannel={{this.onLeaveChannel}} />`
|
||||
|
@ -34,7 +29,7 @@ module("Discourse Chat | Component | chat-channel-leave-btn", function (hooks) {
|
|||
});
|
||||
|
||||
test("has a specific title for direct message channel", async function (assert) {
|
||||
this.set("channel", { chatable_type: "DirectMessage" });
|
||||
this.channel = fabricators.directMessageChatChannel();
|
||||
|
||||
await render(hbs`<ChatChannelLeaveBtn @channel={{this.channel}} />`);
|
||||
|
||||
|
@ -43,7 +38,7 @@ module("Discourse Chat | Component | chat-channel-leave-btn", function (hooks) {
|
|||
});
|
||||
|
||||
test("has a specific title for message channel", async function (assert) {
|
||||
this.set("channel", { chatable_type: "Topic" });
|
||||
this.channel = fabricators.chatChannel();
|
||||
|
||||
await render(hbs`<ChatChannelLeaveBtn @channel={{this.channel}} />`);
|
||||
|
||||
|
@ -53,7 +48,7 @@ module("Discourse Chat | Component | chat-channel-leave-btn", function (hooks) {
|
|||
|
||||
test("is not visible on mobile", async function (assert) {
|
||||
this.site.mobileView = true;
|
||||
this.set("channel", { chatable_type: "Topic" });
|
||||
this.channel = fabricators.chatChannel();
|
||||
|
||||
await render(hbs`<ChatChannelLeaveBtn @channel={{this.channel}} />`);
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ module("Discourse Chat | Component | chat-channel-metadata", function (hooks) {
|
|||
|
||||
test("unreadIndicator", async function (assert) {
|
||||
this.channel = fabricators.directMessageChatChannel();
|
||||
this.channel.currentUserMembership.unread_count = 1;
|
||||
this.channel.currentUserMembership.unreadCount = 1;
|
||||
|
||||
this.unreadIndicator = true;
|
||||
await render(
|
||||
|
|
|
@ -15,10 +15,9 @@ module(
|
|||
"channel",
|
||||
fabricators.chatChannel({ chatable_type: "Category" })
|
||||
);
|
||||
this.channel.setProperties({
|
||||
description: "Important stuff is announced here.",
|
||||
title: "announcements",
|
||||
});
|
||||
|
||||
this.channel.description = "Important stuff is announced here.";
|
||||
this.channel.title = "announcements";
|
||||
this.currentUser.set("has_chat_enabled", true);
|
||||
this.siteSettings.chat_enabled = true;
|
||||
});
|
||||
|
@ -49,7 +48,7 @@ module(
|
|||
});
|
||||
|
||||
test("no channel description", async function (assert) {
|
||||
this.channel.set("description", null);
|
||||
this.channel.description = null;
|
||||
|
||||
await render(hbs`<ChatChannelPreviewCard @channel={{this.channel}} />`);
|
||||
|
||||
|
@ -83,7 +82,7 @@ module(
|
|||
});
|
||||
|
||||
test("closed channel", async function (assert) {
|
||||
this.channel.set("status", "closed");
|
||||
this.channel.status = "closed";
|
||||
await render(hbs`<ChatChannelPreviewCard @channel={{this.channel}} />`);
|
||||
|
||||
assert.false(
|
||||
|
|
|
@ -131,7 +131,7 @@ module("Discourse Chat | Component | chat-channel-row", function (hooks) {
|
|||
|
||||
assert.dom(".chat-channel-row").doesNotHaveClass("has-unread");
|
||||
|
||||
this.categoryChatChannel.currentUserMembership.unread_count = 1;
|
||||
this.categoryChatChannel.currentUserMembership.unreadCount = 1;
|
||||
|
||||
await render(hbs`<ChatChannelRow @channel={{this.categoryChatChannel}} />`);
|
||||
|
||||
|
|
|
@ -10,12 +10,9 @@ module("Discourse Chat | Component | chat-channel-title", function (hooks) {
|
|||
setupRenderingTest(hooks);
|
||||
|
||||
test("category channel", async function (assert) {
|
||||
this.set(
|
||||
"channel",
|
||||
fabricators.chatChannel({
|
||||
chatable_type: CHATABLE_TYPES.categoryChannel,
|
||||
})
|
||||
);
|
||||
this.channel = fabricators.chatChannel({
|
||||
chatable_type: CHATABLE_TYPES.categoryChannel,
|
||||
});
|
||||
|
||||
await render(hbs`<ChatChannelTitle @channel={{this.channel}} />`);
|
||||
|
||||
|
@ -30,13 +27,10 @@ module("Discourse Chat | Component | chat-channel-title", function (hooks) {
|
|||
});
|
||||
|
||||
test("category channel - escapes title", async function (assert) {
|
||||
this.set(
|
||||
"channel",
|
||||
fabricators.chatChannel({
|
||||
chatable_type: CHATABLE_TYPES.categoryChannel,
|
||||
title: "<div class='xss'>evil</div>",
|
||||
})
|
||||
);
|
||||
this.channel = fabricators.chatChannel({
|
||||
chatable_type: CHATABLE_TYPES.categoryChannel,
|
||||
title: "<div class='xss'>evil</div>",
|
||||
});
|
||||
|
||||
await render(hbs`<ChatChannelTitle @channel={{this.channel}} />`);
|
||||
|
||||
|
@ -44,13 +38,10 @@ module("Discourse Chat | Component | chat-channel-title", function (hooks) {
|
|||
});
|
||||
|
||||
test("category channel - read restricted", async function (assert) {
|
||||
this.set(
|
||||
"channel",
|
||||
fabricators.chatChannel({
|
||||
chatable_type: CHATABLE_TYPES.categoryChannel,
|
||||
chatable: { read_restricted: true },
|
||||
})
|
||||
);
|
||||
this.channel = fabricators.chatChannel({
|
||||
chatable_type: CHATABLE_TYPES.categoryChannel,
|
||||
chatable: { read_restricted: true },
|
||||
});
|
||||
|
||||
await render(hbs`<ChatChannelTitle @channel={{this.channel}} />`);
|
||||
|
||||
|
@ -58,13 +49,10 @@ module("Discourse Chat | Component | chat-channel-title", function (hooks) {
|
|||
});
|
||||
|
||||
test("category channel - not read restricted", async function (assert) {
|
||||
this.set(
|
||||
"channel",
|
||||
fabricators.chatChannel({
|
||||
chatable_type: CHATABLE_TYPES.categoryChannel,
|
||||
chatable: { read_restricted: false },
|
||||
})
|
||||
);
|
||||
this.channel = fabricators.chatChannel({
|
||||
chatable_type: CHATABLE_TYPES.categoryChannel,
|
||||
chatable: { read_restricted: false },
|
||||
});
|
||||
|
||||
await render(hbs`<ChatChannelTitle @channel={{this.channel}} />`);
|
||||
|
||||
|
@ -72,7 +60,7 @@ module("Discourse Chat | Component | chat-channel-title", function (hooks) {
|
|||
});
|
||||
|
||||
test("direct message channel - one user", async function (assert) {
|
||||
this.set("channel", fabricators.directMessageChatChannel());
|
||||
this.channel = fabricators.directMessageChatChannel();
|
||||
|
||||
await render(hbs`<ChatChannelTitle @channel={{this.channel}} />`);
|
||||
|
||||
|
@ -98,7 +86,7 @@ module("Discourse Chat | Component | chat-channel-title", function (hooks) {
|
|||
avatar_template: "/letter_avatar_proxy/v3/letter/t/31188e/{size}.png",
|
||||
});
|
||||
|
||||
this.set("channel", channel);
|
||||
this.channel = channel;
|
||||
|
||||
await render(hbs`<ChatChannelTitle @channel={{this.channel}} />`);
|
||||
|
||||
|
|
|
@ -11,8 +11,8 @@ module("Discourse Chat | Component | chat-message", function (hooks) {
|
|||
setupRenderingTest(hooks);
|
||||
|
||||
function generateMessageProps(messageData = {}) {
|
||||
const chatChannel = ChatChannel.create({
|
||||
chatable: { id: 1 },
|
||||
const channel = ChatChannel.create({
|
||||
chatable_id: 1,
|
||||
chatable_type: "Category",
|
||||
id: 9,
|
||||
title: "Site",
|
||||
|
@ -21,15 +21,15 @@ module("Discourse Chat | Component | chat-message", function (hooks) {
|
|||
unread_count: 0,
|
||||
muted: false,
|
||||
},
|
||||
canDeleteSelf: true,
|
||||
canDeleteOthers: true,
|
||||
canFlag: true,
|
||||
userSilenced: false,
|
||||
canModerate: true,
|
||||
can_delete_self: true,
|
||||
can_delete_others: true,
|
||||
can_flag: true,
|
||||
user_silenced: false,
|
||||
can_moderate: true,
|
||||
});
|
||||
return {
|
||||
message: ChatMessage.create(
|
||||
chatChannel,
|
||||
channel,
|
||||
Object.assign(
|
||||
{
|
||||
id: 178,
|
||||
|
@ -44,7 +44,7 @@ module("Discourse Chat | Component | chat-message", function (hooks) {
|
|||
messageData
|
||||
)
|
||||
),
|
||||
chatChannel,
|
||||
channel,
|
||||
afterExpand: () => {},
|
||||
onHoverMessage: () => {},
|
||||
messageDidEnterViewport: () => {},
|
||||
|
@ -55,7 +55,7 @@ module("Discourse Chat | Component | chat-message", function (hooks) {
|
|||
const template = hbs`
|
||||
<ChatMessage
|
||||
@message={{this.message}}
|
||||
@channel={{this.chatChannel}}
|
||||
@channel={{this.channel}}
|
||||
@messageDidEnterViewport={{this.messageDidEnterViewport}}
|
||||
@messageDidLeaveViewport={{this.messageDidLeaveViewport}}
|
||||
/>
|
||||
|
@ -64,6 +64,7 @@ module("Discourse Chat | Component | chat-message", function (hooks) {
|
|||
test("Message with edits", async function (assert) {
|
||||
this.setProperties(generateMessageProps({ edited: true }));
|
||||
await render(template);
|
||||
|
||||
assert.true(
|
||||
exists(".chat-message-edited"),
|
||||
"has the correct edited css class"
|
||||
|
@ -83,6 +84,7 @@ module("Discourse Chat | Component | chat-message", function (hooks) {
|
|||
test("Hidden message", async function (assert) {
|
||||
this.setProperties(generateMessageProps({ hidden: true }));
|
||||
await render(template);
|
||||
|
||||
assert.true(
|
||||
exists(".chat-message-hidden .chat-message-expand"),
|
||||
"has the correct hidden css class and expand button within"
|
||||
|
|
|
@ -2,9 +2,9 @@ import { setupRenderingTest } from "discourse/tests/helpers/component-test";
|
|||
import { exists, query } from "discourse/tests/helpers/qunit-helpers";
|
||||
import hbs from "htmlbars-inline-precompile";
|
||||
import fabricators from "../helpers/fabricators";
|
||||
import MockPresenceChannel from "../helpers/mock-presence-channel";
|
||||
import { module, test } from "qunit";
|
||||
import { render } from "@ember/test-helpers";
|
||||
import { render, settled } from "@ember/test-helpers";
|
||||
import { joinChannel } from "discourse/tests/helpers/presence-pretender";
|
||||
|
||||
module(
|
||||
"Discourse Chat | Component | chat-replying-indicator",
|
||||
|
@ -12,155 +12,148 @@ module(
|
|||
setupRenderingTest(hooks);
|
||||
|
||||
test("not displayed when no one is replying", async function (assert) {
|
||||
this.set("chatChannel", fabricators.chatChannel());
|
||||
this.set(
|
||||
"presenceChannel",
|
||||
MockPresenceChannel.create({
|
||||
name: `/chat-reply/${this.chatChannel.id}`,
|
||||
})
|
||||
);
|
||||
this.channel = fabricators.chatChannel();
|
||||
|
||||
await render(
|
||||
hbs`<ChatReplyingIndicator @presenceChannel={{this.presenceChannel}} @chatChannel={{this.chatChannel}} />`
|
||||
);
|
||||
await render(hbs`<ChatReplyingIndicator @channel={{this.channel}} />`);
|
||||
|
||||
assert.false(exists(".chat-replying-indicator__text"));
|
||||
});
|
||||
|
||||
test("displays indicator when user is replying", async function (assert) {
|
||||
this.set("chatChannel", fabricators.chatChannel());
|
||||
this.set(
|
||||
"presenceChannel",
|
||||
MockPresenceChannel.create({
|
||||
name: `/chat-reply/${this.chatChannel.id}`,
|
||||
})
|
||||
);
|
||||
this.channel = fabricators.chatChannel();
|
||||
|
||||
await render(
|
||||
hbs`<ChatReplyingIndicator @presenceChannel={{this.presenceChannel}} @chatChannel={{this.chatChannel}} />`
|
||||
);
|
||||
await render(hbs`<ChatReplyingIndicator @channel={{this.channel}} />`);
|
||||
|
||||
const sam = { id: 1, username: "sam" };
|
||||
this.set("presenceChannel.users", [sam]);
|
||||
await joinChannel("/chat-reply/1", {
|
||||
id: 1,
|
||||
avatar_template: "/images/avatar.png",
|
||||
username: "sam",
|
||||
});
|
||||
|
||||
assert.strictEqual(
|
||||
query(".chat-replying-indicator__text").innerText,
|
||||
`${sam.username} is typing`
|
||||
`sam is typing`
|
||||
);
|
||||
});
|
||||
|
||||
test("displays indicator when 2 or 3 users are replying", async function (assert) {
|
||||
this.set("chatChannel", fabricators.chatChannel());
|
||||
this.set(
|
||||
"presenceChannel",
|
||||
MockPresenceChannel.create({
|
||||
name: `/chat-reply/${this.chatChannel.id}`,
|
||||
})
|
||||
);
|
||||
this.channel = fabricators.chatChannel();
|
||||
|
||||
await render(
|
||||
hbs`<ChatReplyingIndicator @presenceChannel={{this.presenceChannel}} @chatChannel={{this.chatChannel}} />`
|
||||
);
|
||||
await render(hbs`<ChatReplyingIndicator @channel={{this.channel}} />`);
|
||||
|
||||
const sam = { id: 1, username: "sam" };
|
||||
const mark = { id: 2, username: "mark" };
|
||||
this.set("presenceChannel.users", [sam, mark]);
|
||||
await joinChannel("/chat-reply/1", {
|
||||
id: 1,
|
||||
avatar_template: "/images/avatar.png",
|
||||
username: "sam",
|
||||
});
|
||||
|
||||
await joinChannel("/chat-reply/1", {
|
||||
id: 2,
|
||||
avatar_template: "/images/avatar.png",
|
||||
username: "mark",
|
||||
});
|
||||
|
||||
assert.strictEqual(
|
||||
query(".chat-replying-indicator__text").innerText,
|
||||
`${sam.username} and ${mark.username} are typing`
|
||||
`sam and mark are typing`
|
||||
);
|
||||
});
|
||||
|
||||
test("displays indicator when 3 users are replying", async function (assert) {
|
||||
this.set("chatChannel", fabricators.chatChannel());
|
||||
this.set(
|
||||
"presenceChannel",
|
||||
MockPresenceChannel.create({
|
||||
name: `/chat-reply/${this.chatChannel.id}`,
|
||||
})
|
||||
);
|
||||
this.channel = fabricators.chatChannel();
|
||||
|
||||
await render(
|
||||
hbs`<ChatReplyingIndicator @presenceChannel={{this.presenceChannel}} @chatChannel={{this.chatChannel}} />`
|
||||
);
|
||||
await render(hbs`<ChatReplyingIndicator @channel={{this.channel}} />`);
|
||||
|
||||
const sam = { id: 1, username: "sam" };
|
||||
const mark = { id: 2, username: "mark" };
|
||||
const joffrey = { id: 3, username: "joffrey" };
|
||||
this.set("presenceChannel.users", [sam, mark, joffrey]);
|
||||
await joinChannel("/chat-reply/1", {
|
||||
id: 1,
|
||||
avatar_template: "/images/avatar.png",
|
||||
username: "sam",
|
||||
});
|
||||
|
||||
await joinChannel("/chat-reply/1", {
|
||||
id: 2,
|
||||
avatar_template: "/images/avatar.png",
|
||||
username: "mark",
|
||||
});
|
||||
|
||||
await joinChannel("/chat-reply/1", {
|
||||
id: 3,
|
||||
avatar_template: "/images/avatar.png",
|
||||
username: "joffrey",
|
||||
});
|
||||
|
||||
assert.strictEqual(
|
||||
query(".chat-replying-indicator__text").innerText,
|
||||
`${sam.username}, ${mark.username} and ${joffrey.username} are typing`
|
||||
`sam, mark and joffrey are typing`
|
||||
);
|
||||
});
|
||||
|
||||
test("displays indicator when more than 3 users are replying", async function (assert) {
|
||||
this.set("chatChannel", fabricators.chatChannel());
|
||||
this.set(
|
||||
"presenceChannel",
|
||||
MockPresenceChannel.create({
|
||||
name: `/chat-reply/${this.chatChannel.id}`,
|
||||
})
|
||||
);
|
||||
this.channel = fabricators.chatChannel();
|
||||
|
||||
await render(
|
||||
hbs`<ChatReplyingIndicator @presenceChannel={{this.presenceChannel}} @chatChannel={{this.chatChannel}} />`
|
||||
);
|
||||
await render(hbs`<ChatReplyingIndicator @channel={{this.channel}} />`);
|
||||
|
||||
const sam = { id: 1, username: "sam" };
|
||||
const mark = { id: 2, username: "mark" };
|
||||
const joffrey = { id: 3, username: "joffrey" };
|
||||
const taylor = { id: 4, username: "taylor" };
|
||||
this.set("presenceChannel.users", [sam, mark, joffrey, taylor]);
|
||||
await joinChannel("/chat-reply/1", {
|
||||
id: 1,
|
||||
avatar_template: "/images/avatar.png",
|
||||
username: "sam",
|
||||
});
|
||||
|
||||
await joinChannel("/chat-reply/1", {
|
||||
id: 2,
|
||||
avatar_template: "/images/avatar.png",
|
||||
username: "mark",
|
||||
});
|
||||
|
||||
await joinChannel("/chat-reply/1", {
|
||||
id: 3,
|
||||
avatar_template: "/images/avatar.png",
|
||||
username: "joffrey",
|
||||
});
|
||||
|
||||
await joinChannel("/chat-reply/1", {
|
||||
id: 4,
|
||||
avatar_template: "/images/avatar.png",
|
||||
username: "taylor",
|
||||
});
|
||||
|
||||
assert.strictEqual(
|
||||
query(".chat-replying-indicator__text").innerText,
|
||||
`${sam.username}, ${mark.username} and 2 others are typing`
|
||||
`sam, mark and 2 others are typing`
|
||||
);
|
||||
});
|
||||
|
||||
test("filters current user from list of repliers", async function (assert) {
|
||||
this.set("chatChannel", fabricators.chatChannel());
|
||||
this.set(
|
||||
"presenceChannel",
|
||||
MockPresenceChannel.create({
|
||||
name: `/chat-reply/${this.chatChannel.id}`,
|
||||
})
|
||||
);
|
||||
this.channel = fabricators.chatChannel();
|
||||
|
||||
await render(
|
||||
hbs`<ChatReplyingIndicator @presenceChannel={{this.presenceChannel}} @chatChannel={{this.chatChannel}} />`
|
||||
);
|
||||
await render(hbs`<ChatReplyingIndicator @channel={{this.channel}} />`);
|
||||
|
||||
const sam = { id: 1, username: "sam" };
|
||||
this.set("presenceChannel.users", [sam, this.currentUser]);
|
||||
await joinChannel("/chat-reply/1", {
|
||||
id: 1,
|
||||
avatar_template: "/images/avatar.png",
|
||||
username: "sam",
|
||||
});
|
||||
|
||||
await joinChannel("/chat-reply/1", this.currentUser);
|
||||
|
||||
assert.strictEqual(
|
||||
query(".chat-replying-indicator__text").innerText,
|
||||
`${sam.username} is typing`
|
||||
`sam is typing`
|
||||
);
|
||||
});
|
||||
|
||||
test("resets presence when channel is draft", async function (assert) {
|
||||
this.set("chatChannel", fabricators.chatChannel());
|
||||
this.set(
|
||||
"presenceChannel",
|
||||
MockPresenceChannel.create({
|
||||
name: `/chat-reply/${this.chatChannel.id}`,
|
||||
subscribed: true,
|
||||
})
|
||||
);
|
||||
this.channel = fabricators.chatChannel();
|
||||
|
||||
await render(
|
||||
hbs`<ChatReplyingIndicator @presenceChannel={{this.presenceChannel}} @chatChannel={{this.chatChannel}} />`
|
||||
);
|
||||
await render(hbs`<ChatReplyingIndicator @channel={{this.channel}} />`);
|
||||
|
||||
assert.true(this.presenceChannel.subscribed);
|
||||
assert.dom(".chat-replying-indicator.is-subscribed").exists();
|
||||
|
||||
this.set("chatChannel", fabricators.chatChannel({ isDraft: true }));
|
||||
assert.false(this.presenceChannel.subscribed);
|
||||
this.channel.isDraft = true;
|
||||
|
||||
await settled();
|
||||
|
||||
assert.dom(".chat-replying-indicator.is-subscribed").doesNotExist();
|
||||
});
|
||||
}
|
||||
);
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import ChatChannel from "discourse/plugins/chat/discourse/models/chat-channel";
|
||||
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
|
||||
import hbs from "htmlbars-inline-precompile";
|
||||
import I18n from "I18n";
|
||||
import { module, test } from "qunit";
|
||||
import { render } from "@ember/test-helpers";
|
||||
import fabricators from "../helpers/fabricators";
|
||||
|
||||
module(
|
||||
"Discourse Chat | Component | chat-retention-reminder-text",
|
||||
|
@ -11,7 +11,7 @@ module(
|
|||
setupRenderingTest(hooks);
|
||||
|
||||
test("when setting is set on 0", async function (assert) {
|
||||
this.channel = ChatChannel.create({ chatable_type: "Category" });
|
||||
this.channel = fabricators.chatChannel();
|
||||
this.siteSettings.chat_channel_retention_days = 0;
|
||||
|
||||
await render(
|
||||
|
@ -25,7 +25,7 @@ module(
|
|||
|
||||
test("when channel is a public channel", async function (assert) {
|
||||
const count = 10;
|
||||
this.channel = ChatChannel.create({ chatable_type: "Category" });
|
||||
this.channel = fabricators.chatChannel();
|
||||
this.siteSettings.chat_channel_retention_days = count;
|
||||
|
||||
await render(
|
||||
|
@ -39,9 +39,7 @@ module(
|
|||
|
||||
test("when channel is a DM channel", async function (assert) {
|
||||
const count = 10;
|
||||
this.channel = ChatChannel.create({
|
||||
chatable_type: "DirectMessage",
|
||||
});
|
||||
this.channel = fabricators.directMessageChatChannel();
|
||||
this.siteSettings.chat_dm_retention_days = count;
|
||||
|
||||
await render(
|
||||
|
|
|
@ -2,7 +2,7 @@ import { setupRenderingTest } from "discourse/tests/helpers/component-test";
|
|||
import { click, fillIn, render } from "@ember/test-helpers";
|
||||
import hbs from "htmlbars-inline-precompile";
|
||||
import { exists, query } from "discourse/tests/helpers/qunit-helpers";
|
||||
import { createDirectMessageChannelDraft } from "discourse/plugins/chat/discourse/models/chat-channel";
|
||||
import ChatChannel from "discourse/plugins/chat/discourse/models/chat-channel";
|
||||
import { Promise } from "rsvp";
|
||||
import fabricators from "../helpers/fabricators";
|
||||
import { module, test } from "qunit";
|
||||
|
@ -25,7 +25,7 @@ module("Discourse Chat | Component | direct-message-creator", function (hooks) {
|
|||
|
||||
test("search", async function (assert) {
|
||||
this.set("chat", mockChat(this));
|
||||
this.set("channel", createDirectMessageChannelDraft());
|
||||
this.set("channel", ChatChannel.createDirectMessageChannelDraft());
|
||||
|
||||
await render(
|
||||
hbs`<DirectMessageCreator @channel={{this.channel}} @chat={{this.chat}} />`
|
||||
|
@ -37,7 +37,7 @@ module("Discourse Chat | Component | direct-message-creator", function (hooks) {
|
|||
|
||||
test("select/deselect", async function (assert) {
|
||||
this.set("chat", mockChat(this));
|
||||
this.set("channel", createDirectMessageChannelDraft());
|
||||
this.set("channel", ChatChannel.createDirectMessageChannelDraft());
|
||||
|
||||
await render(
|
||||
hbs`<DirectMessageCreator @channel={{this.channel}} @chat={{this.chat}} />`
|
||||
|
@ -54,7 +54,7 @@ module("Discourse Chat | Component | direct-message-creator", function (hooks) {
|
|||
|
||||
test("no search results", async function (assert) {
|
||||
this.set("chat", mockChat(this, { users: [] }));
|
||||
this.set("channel", createDirectMessageChannelDraft());
|
||||
this.set("channel", ChatChannel.createDirectMessageChannelDraft());
|
||||
|
||||
await render(
|
||||
hbs`<DirectMessageCreator @channel={{this.channel}} @chat={{this.chat}} />`
|
||||
|
@ -66,7 +66,7 @@ module("Discourse Chat | Component | direct-message-creator", function (hooks) {
|
|||
|
||||
test("loads user on first load", async function (assert) {
|
||||
this.set("chat", mockChat(this));
|
||||
this.set("channel", createDirectMessageChannelDraft());
|
||||
this.set("channel", ChatChannel.createDirectMessageChannelDraft());
|
||||
|
||||
await render(
|
||||
hbs`<DirectMessageCreator @channel={{this.channel}} @chat={{this.chat}} />`
|
||||
|
@ -78,7 +78,7 @@ module("Discourse Chat | Component | direct-message-creator", function (hooks) {
|
|||
|
||||
test("do not load more users after selection", async function (assert) {
|
||||
this.set("chat", mockChat(this));
|
||||
this.set("channel", createDirectMessageChannelDraft());
|
||||
this.set("channel", ChatChannel.createDirectMessageChannelDraft());
|
||||
|
||||
await render(
|
||||
hbs`<DirectMessageCreator @channel={{this.channel}} @chat={{this.chat}} />`
|
||||
|
@ -90,7 +90,7 @@ module("Discourse Chat | Component | direct-message-creator", function (hooks) {
|
|||
|
||||
test("apply is-focused to filter-area on focus input", async function (assert) {
|
||||
this.set("chat", mockChat(this));
|
||||
this.set("channel", createDirectMessageChannelDraft());
|
||||
this.set("channel", ChatChannel.createDirectMessageChannelDraft());
|
||||
|
||||
await render(
|
||||
hbs`<DirectMessageCreator @channel={{this.channel}} @chat={{this.chat}} /><button class="test-blur">blur</button>`
|
||||
|
@ -105,7 +105,7 @@ module("Discourse Chat | Component | direct-message-creator", function (hooks) {
|
|||
|
||||
test("state is reset on channel change", async function (assert) {
|
||||
this.set("chat", mockChat(this));
|
||||
this.set("channel", createDirectMessageChannelDraft());
|
||||
this.set("channel", ChatChannel.createDirectMessageChannelDraft());
|
||||
|
||||
await render(
|
||||
hbs`<DirectMessageCreator @channel={{this.channel}} @chat={{this.chat}} />`
|
||||
|
@ -115,7 +115,7 @@ module("Discourse Chat | Component | direct-message-creator", function (hooks) {
|
|||
assert.strictEqual(query(".filter-usernames").value, "hawk");
|
||||
|
||||
this.set("channel", fabricators.chatChannel());
|
||||
this.set("channel", createDirectMessageChannelDraft());
|
||||
this.set("channel", ChatChannel.createDirectMessageChannelDraft());
|
||||
|
||||
assert.strictEqual(query(".filter-usernames").value, "");
|
||||
assert.true(exists(".filter-area.is-focused"));
|
||||
|
@ -129,7 +129,7 @@ module("Discourse Chat | Component | direct-message-creator", function (hooks) {
|
|||
};
|
||||
const chat = mockChat(this, { users: [userWithStatus] });
|
||||
this.set("chat", chat);
|
||||
this.set("channel", createDirectMessageChannelDraft());
|
||||
this.set("channel", ChatChannel.createDirectMessageChannelDraft());
|
||||
|
||||
await render(
|
||||
hbs`<DirectMessageCreator @channel={{this.channel}} @chat={{this.chat}} />`
|
||||
|
|
|
@ -138,7 +138,7 @@ export function directMessageChannelPretender(
|
|||
opts = { unread_count: 0, muted: false }
|
||||
) {
|
||||
let copy = cloneJSON(directMessageChannels[0]);
|
||||
copy.chat_channel.currentUserMembership.unread_count = opts.unread_count;
|
||||
copy.chat_channel.currentUserMembership.unreadCount = opts.unread_count;
|
||||
copy.chat_channel.currentUserMembership.muted = opts.muted;
|
||||
server.get("/chat/chat_channels/75.json", () => helper.response(copy));
|
||||
}
|
||||
|
@ -150,13 +150,13 @@ export function chatChannelPretender(server, helper, changes = []) {
|
|||
let found;
|
||||
found = copy.public_channels.find((c) => c.id === change.id);
|
||||
if (found) {
|
||||
found.currentUserMembership.unread_count = change.unread_count;
|
||||
found.currentUserMembership.unreadCount = change.unread_count;
|
||||
found.currentUserMembership.muted = change.muted;
|
||||
}
|
||||
if (!found) {
|
||||
found = copy.direct_message_channels.find((c) => c.id === change.id);
|
||||
if (found) {
|
||||
found.currentUserMembership.unread_count = change.unread_count;
|
||||
found.currentUserMembership.unreadCount = change.unread_count;
|
||||
found.currentUserMembership.muted = change.muted;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
import EmberObject from "@ember/object";
|
||||
|
||||
export default class MockPresenceChannel extends EmberObject {
|
||||
users = [];
|
||||
name = null;
|
||||
subscribed = false;
|
||||
|
||||
async unsubscribe() {
|
||||
this.set("subscribed", false);
|
||||
}
|
||||
|
||||
async subscribe() {
|
||||
this.set("subscribed", true);
|
||||
}
|
||||
}
|
|
@ -83,12 +83,12 @@ acceptance("Discourse Chat | Unit | Service | chat-guardian", function (needs) {
|
|||
set(this.currentUser, "admin", true);
|
||||
set(this.currentUser, "moderator", true);
|
||||
|
||||
channel.set("status", "read_only");
|
||||
channel.status = "read_only";
|
||||
assert.notOk(this.chatGuardian.canArchiveChannel(channel));
|
||||
channel.set("status", "open");
|
||||
channel.status = "open";
|
||||
|
||||
channel.set("status", "archived");
|
||||
channel.status = "archived";
|
||||
assert.notOk(this.chatGuardian.canArchiveChannel(channel));
|
||||
channel.set("status", "open");
|
||||
channel.status = "open";
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue