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

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

diff --git a/app/assets/javascripts/admin/components/simple-list.js b/app/assets/javascripts/admin/components/simple-list.js
new file mode 100644
index 0000000..3f43885
--- /dev/null
+++ b/app/assets/javascripts/admin/components/simple-list.js
@@ -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)
+      : [];
+  }
+});
diff --git a/app/assets/javascripts/admin/components/site-settings/simple-list.js b/app/assets/javascripts/admin/components/site-settings/simple-list.js
new file mode 100644
index 0000000..aab078b
--- /dev/null
+++ b/app/assets/javascripts/admin/components/site-settings/simple-list.js
@@ -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"));
+  }
+});
diff --git a/app/assets/javascripts/admin/mixins/setting-component.js b/app/assets/javascripts/admin/mixins/setting-component.js
index 83dcc31..699cecd 100644
--- a/app/assets/javascripts/admin/mixins/setting-component.js
+++ b/app/assets/javascripts/admin/mixins/setting-component.js
@@ -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"];
diff --git a/app/assets/javascripts/admin/templates/components/simple-list.hbs b/app/assets/javascripts/admin/templates/components/simple-list.hbs
new file mode 100644
index 0000000..3e78f77
--- /dev/null
+++ b/app/assets/javascripts/admin/templates/components/simple-list.hbs
@@ -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>
diff --git a/app/assets/javascripts/admin/templates/components/site-settings/simple-list.hbs b/app/assets/javascripts/admin/templates/components/site-settings/simple-list.hbs
new file mode 100644
index 0000000..3eca57d
--- /dev/null
+++ b/app/assets/javascripts/admin/templates/components/site-settings/simple-list.hbs
@@ -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>
diff --git a/app/assets/stylesheets/common/admin/admin_base.scss b/app/assets/stylesheets/common/admin/admin_base.scss
index afdc9a7..208e912 100644
--- a/app/assets/stylesheets/common/admin/admin_base.scss
+++ b/app/assets/stylesheets/common/admin/admin_base.scss
@@ -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"] {
diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml
index b5db1f5..308944b 100644
--- a/config/locales/client.en.yml
+++ b/config/locales/client.en.yml
@@ -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
diff --git a/config/site_settings.yml b/config/site_settings.yml
index 5901d6d..c658ec7 100644
--- a/config/site_settings.yml
+++ b/config/site_settings.yml
@@ -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
diff --git a/lib/site_settings/type_supervisor.rb b/lib/site_settings/type_supervisor.rb
index 26cc20b..ae78d5d 100644
--- a/lib/site_settings/type_supervisor.rb
+++ b/lib/site_settings/type_supervisor.rb
@@ -34,7 +34,8 @@ class SiteSettings::TypeSupervisor
       group: 19,
       group_list: 20,
       tag_list: 21,
-      color: 22
+      color: 22,
+      simple_list: 23
     )
   end
 
diff --git a/spec/components/site_settings/type_supervisor_spec.rb b/spec/components/site_settings/type_supervisor_spec.rb
index caea601..cc697c0 100644
--- a/spec/components/site_settings/type_supervisor_spec.rb
+++ b/spec/components/site_settings/type_supervisor_spec.rb
@@ -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
 
diff --git a/test/javascripts/components/simple-list-test.js b/test/javascripts/components/simple-list-test.js
new file mode 100644
index 0000000..5c8d26d
--- /dev/null
+++ b/test/javascripts/components/simple-list-test.js
@@ -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",

[... diff too long, it was truncated ...]

GitHub sha: 2d880b42

1 Like

This commit appears in #9970 which was merged by pmusaraj.