First follow-up to the feature introduced in #19034. We don't want to pollute main components like `chat-live-pane`, so we'll use a service to track and manage the state needed to display before-send warnings while composing a chat message. We also move from acceptance tests to system specs.
147 lines
3.8 KiB
JavaScript
147 lines
3.8 KiB
JavaScript
import Service, { inject as service } from "@ember/service";
|
|
import { ajax } from "discourse/lib/ajax";
|
|
import discourseDebounce from "discourse-common/lib/debounce";
|
|
import { bind } from "discourse-common/utils/decorators";
|
|
import { mentionRegex } from "pretty-text/mentions";
|
|
import { cancel } from "@ember/runloop";
|
|
import { tracked } from "@glimmer/tracking";
|
|
|
|
const MENTION_RESULT = {
|
|
invalid: -1,
|
|
unreachable: 0,
|
|
over_members_limit: 1,
|
|
};
|
|
|
|
const MENTION_DEBOUNCE_MS = 1000;
|
|
|
|
export default class ChatComposerWarningsTracker extends Service {
|
|
@service siteSettings;
|
|
|
|
// Track mention hints to display warnings
|
|
@tracked unreachableGroupMentions = [];
|
|
@tracked overMembersLimitGroupMentions = [];
|
|
@tracked tooManyMentions = false;
|
|
@tracked mentionsCount = 0;
|
|
@tracked mentionsTimer = null;
|
|
|
|
// Complimentary structure to avoid repeating mention checks.
|
|
_mentionWarningsSeen = {};
|
|
|
|
willDestroy() {
|
|
cancel(this.mentionsTimer);
|
|
}
|
|
|
|
@bind
|
|
trackMentions(message) {
|
|
this.mentionsTimer = discourseDebounce(
|
|
this,
|
|
this._trackMentions,
|
|
message,
|
|
MENTION_DEBOUNCE_MS
|
|
);
|
|
}
|
|
|
|
@bind
|
|
_trackMentions(message) {
|
|
if (!this.siteSettings.enable_mentions) {
|
|
return;
|
|
}
|
|
|
|
const mentions = this._extractMentions(message);
|
|
this.mentionsCount = mentions?.length;
|
|
|
|
if (this.mentionsCount > 0) {
|
|
this.tooManyMentions =
|
|
this.mentionsCount > this.siteSettings.max_mentions_per_chat_message;
|
|
|
|
if (!this.tooManyMentions) {
|
|
const newMentions = mentions.filter(
|
|
(mention) => !(mention in this._mentionWarningsSeen)
|
|
);
|
|
|
|
if (newMentions?.length > 0) {
|
|
this._recordNewWarnings(newMentions, mentions);
|
|
} else {
|
|
this._rebuildWarnings(mentions);
|
|
}
|
|
}
|
|
} else {
|
|
this.tooManyMentions = false;
|
|
this.unreachableGroupMentions = [];
|
|
this.overMembersLimitGroupMentions = [];
|
|
}
|
|
}
|
|
|
|
_extractMentions(message) {
|
|
const regex = mentionRegex(this.siteSettings.unicode_usernames);
|
|
const mentions = [];
|
|
let mentionsLeft = true;
|
|
|
|
while (mentionsLeft) {
|
|
const matches = message.match(regex);
|
|
|
|
if (matches) {
|
|
const mention = matches[1] || matches[2];
|
|
mentions.push(mention);
|
|
message = message.replaceAll(`${mention}`, "");
|
|
|
|
if (mentions.length > this.siteSettings.max_mentions_per_chat_message) {
|
|
mentionsLeft = false;
|
|
}
|
|
} else {
|
|
mentionsLeft = false;
|
|
}
|
|
}
|
|
|
|
return mentions;
|
|
}
|
|
|
|
_recordNewWarnings(newMentions, mentions) {
|
|
ajax("/chat/api/mentions/groups.json", {
|
|
data: { mentions: newMentions },
|
|
})
|
|
.then((newWarnings) => {
|
|
newWarnings.unreachable.forEach((warning) => {
|
|
this._mentionWarningsSeen[warning] = MENTION_RESULT["unreachable"];
|
|
});
|
|
|
|
newWarnings.over_members_limit.forEach((warning) => {
|
|
this._mentionWarningsSeen[warning] =
|
|
MENTION_RESULT["over_members_limit"];
|
|
});
|
|
|
|
newWarnings.invalid.forEach((warning) => {
|
|
this._mentionWarningsSeen[warning] = MENTION_RESULT["invalid"];
|
|
});
|
|
|
|
this._rebuildWarnings(mentions);
|
|
})
|
|
.catch(this._rebuildWarnings(mentions));
|
|
}
|
|
|
|
_rebuildWarnings(mentions) {
|
|
const newWarnings = mentions.reduce(
|
|
(memo, mention) => {
|
|
if (
|
|
mention in this._mentionWarningsSeen &&
|
|
!(this._mentionWarningsSeen[mention] === MENTION_RESULT["invalid"])
|
|
) {
|
|
if (
|
|
this._mentionWarningsSeen[mention] === MENTION_RESULT["unreachable"]
|
|
) {
|
|
memo[0].push(mention);
|
|
} else {
|
|
memo[1].push(mention);
|
|
}
|
|
}
|
|
|
|
return memo;
|
|
},
|
|
[[], []]
|
|
);
|
|
|
|
this.unreachableGroupMentions = newWarnings[0];
|
|
this.overMembersLimitGroupMentions = newWarnings[1];
|
|
}
|
|
}
|