UX: Add simple-list setting type (#9970)

This commit is contained in:
Penar Musaraj 2020-06-04 10:44:54 -04:00 committed by GitHub
parent 76af25f753
commit 2d880b42a3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 219 additions and 3 deletions

View File

@ -0,0 +1,57 @@
import { empty } from "@ember/object/computed";
import Component from "@ember/component";
import { action } from "@ember/object";
import { on } from "discourse-common/utils/decorators";
export default Component.extend({
classNameBindings: [":simple-list", ":value-list"],
inputEmpty: empty("newValue"),
inputDelimiter: null,
newValue: "",
collection: null,
values: null,
@on("didReceiveAttrs")
_setupCollection() {
this.set("collection", this._splitValues(this.values, this.inputDelimiter));
},
keyDown(event) {
if (event.which === 13) {
this.addValue(this.newValue);
return;
}
},
@action
changeValue(index, newValue) {
this.collection.replace(index, 1, [newValue]);
this.collection.arrayContentDidChange(index);
this._onChange();
},
@action
addValue(newValue) {
if (this.inputEmpty) return;
this.set("newValue", null);
this.collection.addObject(newValue);
this._onChange();
},
@action
removeValue(value) {
this.collection.removeObject(value);
this._onChange();
},
_onChange() {
this.attrs.onChange && this.attrs.onChange(this.collection);
},
_splitValues(values, delimiter) {
return values && values.length
? values.split(delimiter || "\n").filter(Boolean)
: [];
}
});

View File

@ -0,0 +1,11 @@
import Component from "@ember/component";
import { action } from "@ember/object";
export default Component.extend({
inputDelimiter: "|",
@action
onChange(value) {
this.set("value", value.join(this.inputDelimiter || "\n"));
}
});

View File

@ -25,7 +25,8 @@ const CUSTOM_TYPES = [
"upload",
"group_list",
"tag_list",
"color"
"color",
"simple_list"
];
const AUTO_REFRESH_ON_SAVE = ["logo", "logo_small", "large_icon"];

View File

@ -0,0 +1,40 @@
{{#if collection}}
<div class="values">
{{#each collection as |value index|}}
<div data-index={{index}} class="value">
{{d-button
action=(action "removeValue")
actionParam=value
icon="times"
class="remove-value-btn btn-small"
}}
{{input
title=value
value=value
class="value-input"
focus-out=(action "changeValue" index)
}}
</div>
{{/each}}
</div>
{{/if}}
<div class="simple-list-input">
{{input
type="text"
value=newValue
placeholderKey="admin.site_settings.simple_list.add_item"
class="add-value-input"
autocomplete="discourse"
autocorrect="off"
autocapitalize="off"}}
{{d-button
action=(action "addValue")
actionParam=newValue
disabled=inputEmpty
icon="plus"
class="add-value-btn btn-small"
}}
</div>

View File

@ -0,0 +1,3 @@
{{simple-list values=value inputDelimiter=inputDelimiter onChange=(action "onChange")}}
{{setting-validation-message message=validationMessage}}
<div class="desc">{{html-safe setting.description}}</div>

View File

@ -931,6 +931,20 @@ table#user-badges {
}
}
.simple-list-input {
display: flex;
.add-value-input {
margin: 0;
box-sizing: border-box;
flex: 1 0 0px;
}
.add-value-btn {
margin-left: 0.25em;
}
}
// Mobile view text-inputs need some padding
.mobile-view .admin-contents {
input[type="text"] {

View File

@ -4588,6 +4588,8 @@ en:
modal_description: "Would you like to apply this change historically? This will change preferences for %{count} existing users."
modal_yes: "Yes"
modal_no: "No, only apply change going forward"
simple_list:
add_item: "Add item..."
badges:
title: Badges

View File

@ -1445,7 +1445,7 @@ security:
content_security_policy_collect_reports:
default: false
content_security_policy_script_src:
type: list
type: simple_list
default: ""
invalidate_inactive_admin_email_after_days:
default: 365

View File

@ -34,7 +34,8 @@ class SiteSettings::TypeSupervisor
group: 19,
group_list: 20,
tag_list: 21,
color: 22
color: 22,
simple_list: 23
)
end

View File

@ -88,6 +88,9 @@ describe SiteSettings::TypeSupervisor do
it "'color' should be at the right position" do
expect(SiteSettings::TypeSupervisor.types[:color]).to eq(22)
end
it "'simple_list' should be at the right position" do
expect(SiteSettings::TypeSupervisor.types[:simple_list]).to eq(23)
end
end
end

View File

@ -0,0 +1,84 @@
import componentTest from "helpers/component-test";
moduleForComponent("simple-list", { integration: true });
componentTest("adding a value", {
template: "{{simple-list values=values}}",
beforeEach() {
this.set("values", "vinkas\nosama");
},
async test(assert) {
assert.ok(
find(".add-value-btn[disabled]").length,
"while loading the + button is disabled"
);
await fillIn(".add-value-input", "penar");
await click(".add-value-btn");
assert.ok(
find(".values .value").length === 3,
"it adds the value to the list of values"
);
assert.ok(
find(".values .value[data-index='2'] .value-input")[0].value === "penar",
"it sets the correct value for added item"
);
await fillIn(".add-value-input", "eviltrout");
await keyEvent(".add-value-input", "keydown", 13); // enter
assert.ok(
find(".values .value").length === 4,
"it adds the value when keying Enter"
);
}
});
componentTest("removing a value", {
template: "{{simple-list values=values}}",
beforeEach() {
this.set("values", "vinkas\nosama");
},
async test(assert) {
await click(".values .value[data-index='0'] .remove-value-btn");
assert.ok(
find(".values .value").length === 1,
"it removes the value from the list of values"
);
assert.ok(
find(".values .value[data-index='0'] .value-input")[0].value === "osama",
"it removes the correct value"
);
}
});
componentTest("delimiter support", {
template: "{{simple-list values=values inputDelimiter='|'}}",
beforeEach() {
this.set("values", "vinkas|osama");
},
async test(assert) {
await fillIn(".add-value-input", "eviltrout");
await click(".add-value-btn");
assert.ok(
find(".values .value").length === 3,
"it adds the value to the list of values"
);
assert.ok(
find(".values .value[data-index='2'] .value-input")[0].value ===
"eviltrout",
"it adds the correct value"
);
}
});