FEATURE: Support tag and replace in watched words in test modal (#13100)

The modal showed only the matches, without the replacement or tags.
This commit is contained in:
Bianca Nenciu 2021-05-21 17:50:24 +03:00 committed by GitHub
parent 0df6b0bc47
commit f700f3ef00
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 148 additions and 22 deletions

View File

@ -1,10 +1,20 @@
import Component from "@ember/component";
import I18n from "I18n";
import { equal } from "@ember/object/computed";
import bootbox from "bootbox";
import discourseComputed from "discourse-common/utils/decorators";
import I18n from "I18n";
export default Component.extend({
classNames: ["watched-word"],
isReplace: equal("actionKey", "replace"),
isTag: equal("actionKey", "tag"),
@discourseComputed("word.replacement")
tags(replacement) {
return replacement.split(",");
},
click() {
this.word
.destroy()

View File

@ -1,14 +1,48 @@
import Controller from "@ember/controller";
import ModalFunctionality from "discourse/mixins/modal-functionality";
import discourseComputed from "discourse-common/utils/decorators";
import { equal } from "@ember/object/computed";
export default Controller.extend(ModalFunctionality, {
@discourseComputed("value", "model.compiledRegularExpression")
matches(value, regexpString) {
isReplace: equal("model.nameKey", "replace"),
isTag: equal("model.nameKey", "tag"),
@discourseComputed(
"value",
"model.compiledRegularExpression",
"model.words",
"isReplace",
"isTag"
)
matches(value, regexpString, words, isReplace, isTag) {
if (!value || !regexpString) {
return;
}
let censorRegexp = new RegExp(regexpString, "ig");
return value.match(censorRegexp);
const regexp = new RegExp(regexpString, "ig");
const matches = value.match(regexp) || [];
if (isReplace) {
return matches.map((match) => ({
match,
replacement: words.find((word) =>
new RegExp(word.regexp, "ig").test(match)
).replacement,
}));
} else if (isTag) {
return matches.map((match) => {
const tags = new Set();
words.forEach((word) => {
if (new RegExp(word.regexp, "ig").test(match)) {
word.replacement.split(",").forEach((tag) => tags.add(tag));
}
});
return { match, tags: Array.from(tags) };
});
}
return matches;
},
});

View File

@ -1 +1,9 @@
{{d-icon "times"}} {{word.word}} {{#if word.replacement}}&rarr; <span class="replacement">{{word.replacement}}</span>{{/if}}
{{d-icon "times"}} {{word.word}}
{{#if isReplace}}
&rarr; <span class="replacement">{{word.replacement}}</span>
{{else if isTag}}
&rarr;
{{#each tags as |tag|}}
<span class="tag">{{tag}}</span>
{{/each}}
{{/if}}

View File

@ -6,14 +6,14 @@
{{#if canReplace}}
<div class="watched-word-input">
<label for="watched-replacement">{{i18n "admin.watched_words.form.replacement_label"}}</label>
{{text-field id="watched-replacement" value=replacement disabled=formSubmitted class="watched-word-input-replace" autocorrect="off" autocapitalize="off" placeholderKey="admin.watched_words.form.replacement_placeholder"}}
{{text-field id="watched-replacement" value=replacement disabled=formSubmitted class="watched-word-input-field" autocorrect="off" autocapitalize="off" placeholderKey="admin.watched_words.form.replacement_placeholder"}}
</div>
{{/if}}
{{#if canTag}}
<div class="watched-word-input">
<label for="watched-tag">{{i18n "admin.watched_words.form.tag_label"}}</label>
{{text-field id="watched-tag" value=replacement disabled=formSubmitted class="watched-word-input" autocorrect="off" autocapitalize="off" placeholderKey="admin.watched_words.form.tag_placeholder"}}
{{text-field id="watched-tag" value=replacement disabled=formSubmitted class="watched-word-input-field" autocorrect="off" autocapitalize="off" placeholderKey="admin.watched_words.form.tag_placeholder"}}
</div>
{{/if}}

View File

@ -5,9 +5,29 @@
<p>
{{i18n "admin.watched_words.test.found_matches"}}
<ul>
{{#each matches as |match|}}
<li>{{match}}</li>
{{/each}}
{{#if isReplace}}
{{#each matches as |match|}}
<li>
<span class="match">{{match.match}}</span>
&rarr;
<span class="replacement">{{match.replacement}}</span>
</li>
{{/each}}
{{else if isTag}}
{{#each matches as |match|}}
<li>
<span class="match">{{match.match}}</span>
&rarr;
{{#each match.tags as |tag|}}
<span class="tag">{{tag}}</span>
{{/each}}
</li>
{{/each}}
{{else}}
{{#each matches as |match|}}
<li>{{match}}</li>
{{/each}}
{{/if}}
</ul>
</p>
{{else}}

View File

@ -8,6 +8,7 @@
{{watched-word-uploader uploading=uploading actionKey=actionNameKey done=(action "uploadComplete")}}
{{d-button
class="watched-word-test"
label="admin.watched_words.test.button_label"
icon="far-eye"
action=(action "test")}}
@ -37,7 +38,7 @@
{{#if showWordsList}}
<div class="watched-words-list">
{{#each filteredContent as |word| }}
<div class="watched-word-box">{{admin-watched-word word=word action=(action "recordRemoved")}}</div>
<div class="watched-word-box">{{admin-watched-word actionKey=actionNameKey word=word action=(action "recordRemoved")}}</div>
{{/each}}
</div>
{{/if}}

View File

@ -83,4 +83,20 @@ acceptance("Admin - Watched Words", function (needs) {
assert.equal(queryAll(".watched-words-list .watched-word").length, 2);
});
test("test modal - replace", async function (assert) {
await visit("/admin/customize/watched_words/action/replace");
await click(".watched-word-test");
await fillIn(".modal-body textarea", "Hi there!");
assert.equal(find(".modal-body li .match").text(), "Hi");
assert.equal(find(".modal-body li .replacement").text(), "hello");
});
test("test modal - tag", async function (assert) {
await visit("/admin/customize/watched_words/action/tag");
await click(".watched-word-test");
await fillIn(".modal-body textarea", "Hello world!");
assert.equal(find(".modal-body li .match").text(), "Hello");
assert.equal(find(".modal-body li .tag").text(), "greeting");
});
});

View File

@ -1,14 +1,35 @@
export default {
"/admin/customize/watched_words.json": {
actions: ["block", "censor", "require_approval", "flag"],
actions: ["block", "censor", "require_approval", "flag", "replace", "tag"],
words: [
{ id: 1, word: "liquorice", action: "block" },
{ id: 2, word: "anise", action: "block" },
{ id: 3, word: "pyramid", action: "flag" },
{ id: 4, word: "scheme", action: "flag" },
{ id: 5, word: "coupon", action: "require_approval" },
{ id: 6, word: '<img src="x">', action: "block" }
{ id: 6, word: '<img src="x">', action: "block" },
{
id: 7,
word: "hi",
regexp: "hi",
replacement: "hello",
action: "replace",
},
{
id: 8,
word: "hello",
regexp: "hello",
replacement: "greeting",
action: "tag",
},
],
compiled_regular_expressions: {}
}
compiled_regular_expressions: {
block: '(?:\\W|^)(liquorice|anise|<img\\ src="x">)(?=\\W|$)',
censor: null,
require_approval: "(?:\\W|^)(coupon)(?=\\W|$)",
flag: "(?:\\W|^)(pyramid|scheme)(?=\\W|$)",
replace: "(?:\\W|^)(hi)(?=\\W|$)",
tag: "(?:\\W|^)(hello)(?=\\W|$)",
},
},
};

View File

@ -330,9 +330,20 @@ table.screened-ip-addresses {
width: 250px;
margin-bottom: 1em;
vertical-align: top;
}
.watched-word-box,
.watched-words-test-modal {
.replacement {
white-space: pre;
background-color: var(--tertiary-low);
background: var(--tertiary-low);
}
.tag {
background: var(--primary-low);
font-size: $font-down-1;
margin-right: 0.1em;
padding: 0.5em;
}
}
@ -385,9 +396,6 @@ table.screened-ip-addresses {
input.watched-word-input-field {
min-width: 300px;
}
input.watched-word-input-replace {
min-width: 260px;
}
}
// Search logs

View File

@ -1,7 +1,15 @@
# frozen_string_literal: true
class WatchedWordSerializer < ApplicationSerializer
attributes :id, :word, :replacement, :action
attributes :id, :word, :regexp, :replacement, :action
def regexp
WordWatcher.word_to_regexp(word)
end
def include_regexp?
WatchedWord.has_replacement?(action)
end
def action
WatchedWord.actions[object.action]

View File

@ -4728,7 +4728,7 @@ en:
upload_successful: "Upload successful. Words have been added."
test:
button_label: "Test"
modal_title: "Test '%{action}' Watched Words"
modal_title: "Test %{action} Watched Words"
description: "Enter text below to check for matches with watched words"
found_matches: "Found matches:"
no_matches: "No matches found"