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

View File

@ -1,14 +1,48 @@
import Controller from "@ember/controller"; import Controller from "@ember/controller";
import ModalFunctionality from "discourse/mixins/modal-functionality"; import ModalFunctionality from "discourse/mixins/modal-functionality";
import discourseComputed from "discourse-common/utils/decorators"; import discourseComputed from "discourse-common/utils/decorators";
import { equal } from "@ember/object/computed";
export default Controller.extend(ModalFunctionality, { export default Controller.extend(ModalFunctionality, {
@discourseComputed("value", "model.compiledRegularExpression") isReplace: equal("model.nameKey", "replace"),
matches(value, regexpString) { isTag: equal("model.nameKey", "tag"),
@discourseComputed(
"value",
"model.compiledRegularExpression",
"model.words",
"isReplace",
"isTag"
)
matches(value, regexpString, words, isReplace, isTag) {
if (!value || !regexpString) { if (!value || !regexpString) {
return; 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}} {{#if canReplace}}
<div class="watched-word-input"> <div class="watched-word-input">
<label for="watched-replacement">{{i18n "admin.watched_words.form.replacement_label"}}</label> <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> </div>
{{/if}} {{/if}}
{{#if canTag}} {{#if canTag}}
<div class="watched-word-input"> <div class="watched-word-input">
<label for="watched-tag">{{i18n "admin.watched_words.form.tag_label"}}</label> <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> </div>
{{/if}} {{/if}}

View File

@ -5,9 +5,29 @@
<p> <p>
{{i18n "admin.watched_words.test.found_matches"}} {{i18n "admin.watched_words.test.found_matches"}}
<ul> <ul>
{{#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|}} {{#each matches as |match|}}
<li>{{match}}</li> <li>{{match}}</li>
{{/each}} {{/each}}
{{/if}}
</ul> </ul>
</p> </p>
{{else}} {{else}}

View File

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

View File

@ -83,4 +83,20 @@ acceptance("Admin - Watched Words", function (needs) {
assert.equal(queryAll(".watched-words-list .watched-word").length, 2); 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 { export default {
"/admin/customize/watched_words.json": { "/admin/customize/watched_words.json": {
actions: ["block", "censor", "require_approval", "flag"], actions: ["block", "censor", "require_approval", "flag", "replace", "tag"],
words: [ words: [
{ id: 1, word: "liquorice", action: "block" }, { id: 1, word: "liquorice", action: "block" },
{ id: 2, word: "anise", action: "block" }, { id: 2, word: "anise", action: "block" },
{ id: 3, word: "pyramid", action: "flag" }, { id: 3, word: "pyramid", action: "flag" },
{ id: 4, word: "scheme", action: "flag" }, { id: 4, word: "scheme", action: "flag" },
{ id: 5, word: "coupon", action: "require_approval" }, { 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; width: 250px;
margin-bottom: 1em; margin-bottom: 1em;
vertical-align: top; vertical-align: top;
}
.watched-word-box,
.watched-words-test-modal {
.replacement { .replacement {
white-space: pre; 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 { input.watched-word-input-field {
min-width: 300px; min-width: 300px;
} }
input.watched-word-input-replace {
min-width: 260px;
}
} }
// Search logs // Search logs

View File

@ -1,7 +1,15 @@
# frozen_string_literal: true # frozen_string_literal: true
class WatchedWordSerializer < ApplicationSerializer 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 def action
WatchedWord.actions[object.action] WatchedWord.actions[object.action]

View File

@ -4728,7 +4728,7 @@ en:
upload_successful: "Upload successful. Words have been added." upload_successful: "Upload successful. Words have been added."
test: test:
button_label: "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" description: "Enter text below to check for matches with watched words"
found_matches: "Found matches:" found_matches: "Found matches:"
no_matches: "No matches found" no_matches: "No matches found"