DEV: Introduce Chat Notices with publishing method (#22369)
This commit is contained in:
parent
c6cd3af5b5
commit
3171fd1a0a
|
@ -475,6 +475,12 @@ module Chat
|
|||
)
|
||||
end
|
||||
|
||||
def self.publish_notice(user_id:, channel_id:, text_content:)
|
||||
payload = { type: "notice", text_content: text_content, channel_id: channel_id }
|
||||
|
||||
MessageBus.publish("/chat/#{channel_id}", payload, user_ids: [user_id])
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def self.permissions(chat_channel)
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
@displayed={{this.includeHeader}}
|
||||
/>
|
||||
|
||||
<ChatRetentionReminder @channel={{@channel}} />
|
||||
<Chat::Notices @channel={{@channel}} />
|
||||
|
||||
<ChatMentionWarnings />
|
||||
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
<div class="chat-notices">
|
||||
<ChatRetentionReminder @channel={{@channel}} />
|
||||
|
||||
{{#each this.noticesForChannel as |notice|}}
|
||||
<div class="chat-notices__notice">
|
||||
<p class="chat-notices__notice__content">
|
||||
{{notice.textContent}}
|
||||
</p>
|
||||
|
||||
<DButton
|
||||
@icon="times"
|
||||
@class="btn-flat chat-notices__notice__clear"
|
||||
@action={{fn this.clearNotice notice}}
|
||||
/>
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
|
@ -0,0 +1,18 @@
|
|||
import Component from "@glimmer/component";
|
||||
import { inject as service } from "@ember/service";
|
||||
import { action } from "@ember/object";
|
||||
|
||||
export default class ChatNotices extends Component {
|
||||
@service("chat-channel-pane-subscriptions-manager") subscriptionsManager;
|
||||
|
||||
get noticesForChannel() {
|
||||
return this.subscriptionsManager.notices.filter(
|
||||
(notice) => notice.channelId === this.args.channel.id
|
||||
);
|
||||
}
|
||||
|
||||
@action
|
||||
clearNotice(notice) {
|
||||
this.subscriptionsManager.clearNotice(notice);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
import { tracked } from "@glimmer/tracking";
|
||||
|
||||
export default class ChatNotice {
|
||||
static create(args = {}) {
|
||||
return new ChatNotice(args);
|
||||
}
|
||||
|
||||
@tracked channelId;
|
||||
@tracked textContent;
|
||||
|
||||
constructor(args = {}) {
|
||||
this.channelId = args.channel_id;
|
||||
this.textContent = args.text_content;
|
||||
}
|
||||
}
|
|
@ -1,11 +1,16 @@
|
|||
import { inject as service } from "@ember/service";
|
||||
import { tracked } from "@glimmer/tracking";
|
||||
import { TrackedArray } from "@ember-compat/tracked-built-ins";
|
||||
import ChatPaneBaseSubscriptionsManager from "./chat-pane-base-subscriptions-manager";
|
||||
import ChatThreadPreview from "../models/chat-thread-preview";
|
||||
import ChatNotice from "../models/chat-notice";
|
||||
|
||||
export default class ChatChannelPaneSubscriptionsManager extends ChatPaneBaseSubscriptionsManager {
|
||||
@service chat;
|
||||
@service currentUser;
|
||||
|
||||
@tracked notices = new TrackedArray();
|
||||
|
||||
get messageBusChannel() {
|
||||
return `/chat/${this.model.id}`;
|
||||
}
|
||||
|
@ -18,6 +23,17 @@ export default class ChatChannelPaneSubscriptionsManager extends ChatPaneBaseSub
|
|||
return;
|
||||
}
|
||||
|
||||
handleNotice(data) {
|
||||
this.notices.push(ChatNotice.create(data));
|
||||
}
|
||||
|
||||
clearNotice(notice) {
|
||||
const index = this.notices.indexOf(notice);
|
||||
if (index > -1) {
|
||||
this.notices.splice(index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
handleThreadOriginalMessageUpdate(data) {
|
||||
const message = this.messagesManager.findMessage(data.original_message_id);
|
||||
if (message) {
|
||||
|
|
|
@ -116,6 +116,9 @@ export default class ChatPaneBaseSubscriptionsManager extends Service {
|
|||
case "update_thread_original_message":
|
||||
this.handleThreadOriginalMessageUpdate(busData);
|
||||
break;
|
||||
case "notice":
|
||||
this.handleNotice(busData);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -248,6 +251,10 @@ export default class ChatPaneBaseSubscriptionsManager extends Service {
|
|||
throw "not implemented";
|
||||
}
|
||||
|
||||
handleNotice() {
|
||||
throw "not implemented";
|
||||
}
|
||||
|
||||
_afterDeleteMessage() {
|
||||
throw "not implemented";
|
||||
}
|
||||
|
|
|
@ -32,6 +32,11 @@ export default class ChatThreadPaneSubscriptionsManager extends ChatPaneBaseSubs
|
|||
return;
|
||||
}
|
||||
|
||||
// NOTE: We don't yet handle notices inside of threads so do nothing.
|
||||
handleNotice() {
|
||||
return;
|
||||
}
|
||||
|
||||
_afterDeleteMessage(targetMsg, data) {
|
||||
if (this.model.currentUserMembership?.lastReadMessageId === targetMsg.id) {
|
||||
this.model.currentUserMembership.lastReadMessageId =
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
.chat-notices {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5em;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
z-index: 10;
|
||||
min-width: 280px;
|
||||
|
||||
&__notice,
|
||||
.chat-retention-reminder {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
background: var(--tertiary-low);
|
||||
padding: 0.5em 0 0.5em 1em;
|
||||
color: var(--primary);
|
||||
padding: 0.5em 0 0.5em 1em;
|
||||
}
|
||||
|
||||
.btn-flat {
|
||||
margin: 0 0.25em;
|
||||
color: var(--primary-medium);
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
background-color: transparent;
|
||||
.d-icon {
|
||||
color: var(--primary);
|
||||
}
|
||||
}
|
||||
.d-icon {
|
||||
color: var(--primary-medium);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.full-page-chat .chat-notices {
|
||||
top: 4rem;
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
.chat-retention-reminder {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
background: var(--tertiary-low);
|
||||
padding: 0.5em 0 0.5em 1em;
|
||||
font-size: var(--font-down-1);
|
||||
color: var(--primary);
|
||||
z-index: 10;
|
||||
min-width: 280px;
|
||||
|
||||
.btn-flat.dismiss-btn {
|
||||
margin-left: 0.25em;
|
||||
color: var(--primary-medium);
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
background-color: transparent;
|
||||
.d-icon {
|
||||
color: var(--primary);
|
||||
}
|
||||
}
|
||||
.d-icon {
|
||||
color: var(--primary-medium);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.full-page-chat .chat-retention-reminder {
|
||||
top: 4rem;
|
||||
}
|
|
@ -28,10 +28,10 @@
|
|||
@import "chat-message-separator";
|
||||
@import "chat-message-thread-indicator";
|
||||
@import "chat-message";
|
||||
@import "chat-notices";
|
||||
@import "chat-onebox";
|
||||
@import "chat-reply";
|
||||
@import "chat-replying-indicator";
|
||||
@import "chat-retention-reminder";
|
||||
@import "chat-selection-manager";
|
||||
@import "chat-side-panel";
|
||||
@import "chat-skeleton";
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
|
||||
import hbs from "htmlbars-inline-precompile";
|
||||
import fabricators from "discourse/plugins/chat/discourse/lib/fabricators";
|
||||
import { query, queryAll } from "discourse/tests/helpers/qunit-helpers";
|
||||
import { module, test } from "qunit";
|
||||
import { click, render } from "@ember/test-helpers";
|
||||
|
||||
module("Discourse Chat | Component | chat-notice", function (hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
|
||||
test("displays all notices for a channel", async function (assert) {
|
||||
this.channel = fabricators.channel();
|
||||
this.manager = this.container.lookup(
|
||||
"service:chatChannelPaneSubscriptionsManager"
|
||||
);
|
||||
this.manager.handleNotice({
|
||||
channel_id: this.channel.id,
|
||||
text_content: "hello",
|
||||
});
|
||||
this.manager.handleNotice({
|
||||
channel_id: this.channel.id,
|
||||
text_content: "goodbye",
|
||||
});
|
||||
this.manager.handleNotice({
|
||||
channel_id: this.channel.id + 1,
|
||||
text_content: "N/A",
|
||||
});
|
||||
|
||||
await render(hbs`<ChatNotices @channel={{this.channel}} />`);
|
||||
|
||||
const notices = queryAll(".chat-notices .chat-notices__notice");
|
||||
|
||||
assert.strictEqual(notices.length, 2, "Two notices are rendered");
|
||||
|
||||
assert.true(notices[0].innerText.includes("hello"));
|
||||
assert.true(notices[1].innerText.includes("goodbye"));
|
||||
});
|
||||
|
||||
test("Notices can be cleared", async function (assert) {
|
||||
this.channel = fabricators.channel();
|
||||
this.manager = this.container.lookup(
|
||||
"service:chatChannelPaneSubscriptionsManager"
|
||||
);
|
||||
this.manager.handleNotice({
|
||||
channel_id: this.channel.id,
|
||||
text_content: "hello",
|
||||
});
|
||||
|
||||
await render(hbs`<ChatNotices @channel={{this.channel}} />`);
|
||||
|
||||
assert.strictEqual(
|
||||
queryAll(".chat-notices .chat-notices__notice").length,
|
||||
1,
|
||||
"Notice is present"
|
||||
);
|
||||
|
||||
await click(query(".chat-notices__notice__clear"), "Clear the notice");
|
||||
|
||||
assert.strictEqual(
|
||||
queryAll(".chat-notices .chat-notices__notice").length,
|
||||
0,
|
||||
"Notice was cleared"
|
||||
);
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue