Tag groups can belong to groups (#10854)

Tag groups can belong to groups (#10854)

diff --git a/app/assets/javascripts/discourse/app/components/tag-groups-form.js b/app/assets/javascripts/discourse/app/components/tag-groups-form.js
index c475a6c..de2d762 100644
--- a/app/assets/javascripts/discourse/app/components/tag-groups-form.js
+++ b/app/assets/javascripts/discourse/app/components/tag-groups-form.js
@@ -4,32 +4,109 @@ import { isEmpty } from "@ember/utils";
 import Component from "@ember/component";
 import { bufferedProperty } from "discourse/mixins/buffered-content";
 import PermissionType from "discourse/models/permission-type";
+import Group from "discourse/models/group";
 import bootbox from "bootbox";
 
 export default Component.extend(bufferedProperty("model"), {
   tagName: "",
+  allGroups: null,
 
-  @discourseComputed("buffered.isSaving", "buffered.name", "buffered.tag_names")
-  savingDisabled(isSaving, name, tagNames) {
-    return isSaving || isEmpty(name) || isEmpty(tagNames);
+  init() {
+    this._super(...arguments);
+    this.setGroupOptions();
+  },
+
+  setGroupOptions() {
+    Group.findAll().then((groups) => {
+      this.set("allGroups", groups);
+    });
+  },
+
+  @discourseComputed(
+    "buffered.isSaving",
+    "buffered.name",
+    "buffered.tag_names",
+    "buffered.permissions"
+  )
+  savingDisabled(isSaving, name, tagNames, permissions) {
+    return (
+      isSaving ||
+      isEmpty(name) ||
+      isEmpty(tagNames) ||
+      (!this.everyoneSelected(permissions) &&
+        isEmpty(this.selectedGroupNames(permissions)))
+    );
+  },
+
+  @discourseComputed("buffered.permissions")
+  showPrivateChooser(permissions) {
+    if (!permissions) {
+      return true;
+    }
+
+    return permissions.everyone !== PermissionType.READONLY;
+  },
+
+  @discourseComputed("buffered.permissions", "allGroups")
+  selectedGroupIds(permissions, allGroups) {
+    if (!permissions || !allGroups) {
+      return [];
+    }
+
+    const selectedGroupNames = Object.keys(permissions);
+    let groupIds = [];
+    allGroups.forEach((group) => {
+      if (selectedGroupNames.includes(group.name)) {
+        groupIds.push(group.id);
+      }
+    });
+
+    return groupIds;
+  },
+
+  everyoneSelected(permissions) {
+    if (!permissions) {
+      return true;
+    }
+
+    return permissions.everyone === PermissionType.FULL;
+  },
+
+  selectedGroupNames(permissions) {
+    if (!permissions) {
+      return [];
+    }
+
+    return Object.keys(permissions).filter((name) => name !== "everyone");
   },
 
   actions: {
-    setPermissions(permissionName) {
+    setPermissionsType(permissionName) {
+      let updatedPermissions = Object.assign(
+        {},
+        this.buffered.get("permissions")
+      );
+
       if (permissionName === "private") {
-        this.buffered.set("permissions", {
-          staff: PermissionType.FULL,
-        });
+        delete updatedPermissions.everyone;
       } else if (permissionName === "visible") {
-        this.buffered.set("permissions", {
-          staff: PermissionType.FULL,
-          everyone: PermissionType.READONLY,
-        });
+        updatedPermissions.everyone = PermissionType.READONLY;
       } else {
-        this.buffered.set("permissions", {
-          everyone: PermissionType.FULL,
-        });
+        updatedPermissions.everyone = PermissionType.FULL;
       }
+
+      this.buffered.set("permissions", updatedPermissions);
+    },
+
+    setPermissionsGroups(groupIds) {
+      let permissions = {};
+      this.allGroups.forEach((group) => {
+        if (groupIds.includes(group.id)) {
+          permissions[group.name] = PermissionType.FULL;
+        }
+      });
+
+      this.buffered.set("permissions", permissions);
     },
 
     save() {
@@ -41,6 +118,14 @@ export default Component.extend(bufferedProperty("model"), {
         "permissions"
       );
 
+      // If 'everyone' is set to full, we can remove any groups.
+      if (
+        !attrs.permissions ||
+        attrs.permissions.everyone === PermissionType.FULL
+      ) {
+        attrs.permissions = { everyone: PermissionType.FULL };
+      }
+
       this.model.save(attrs).then(() => {
         this.commitBuffer();
 
diff --git a/app/assets/javascripts/discourse/app/templates/components/tag-groups-form.hbs b/app/assets/javascripts/discourse/app/templates/components/tag-groups-form.hbs
index 0fdf7ec..38a950b 100644
--- a/app/assets/javascripts/discourse/app/templates/components/tag-groups-form.hbs
+++ b/app/assets/javascripts/discourse/app/templates/components/tag-groups-form.hbs
@@ -38,7 +38,7 @@
         value="public"
         id="public-permission"
         selection=buffered.permissionName
-        onChange=(action "setPermissions")}}
+        onChange=(action "setPermissionsType")}}
 
       <label class="radio" for="public-permission">
         {{i18n "tagging.groups.everyone_can_use"}}
@@ -51,11 +51,20 @@
         value="visible"
         id="visible-permission"
         selection=buffered.permissionName
-        onChange=(action "setPermissions")}}
+        onChange=(action "setPermissionsType")}}
 
       <label class="radio" for="visible-permission">
-        {{i18n "tagging.groups.usable_only_by_staff"}}
+        {{i18n "tagging.groups.usable_only_by_groups"}}
       </label>
+
+      <div class="group-access-control {{if showPrivateChooser "hidden"}}">
+        {{group-chooser
+          content=allGroups
+          value=selectedGroupIds
+          labelProperty="name"
+          onChange=(action "setPermissionsGroups")
+        }}
+      </div>
     </div>
     <div>
       {{radio-button
@@ -64,12 +73,20 @@
         value="private"
         id="private-permission"
         selection=buffered.permissionName
-        onChange=(action "setPermissions")}}
+        onChange=(action "setPermissionsType")}}
 
       <label class="radio" for="private-permission">
-        {{i18n "tagging.groups.visible_only_to_staff"}}
+        {{i18n "tagging.groups.visible_only_to_groups"}}
       </label>
     </div>
+
+    <div class="group-access-control {{unless showPrivateChooser "hidden"}}">
+      {{group-chooser
+        content=allGroups
+        value=selectedGroupIds
+        labelProperty="name"
+        onChange=(action "setPermissionsGroups")}}
+    </div>
   </section>
 
   {{d-button
diff --git a/app/assets/javascripts/discourse/tests/acceptance/tag-groups-test.js b/app/assets/javascripts/discourse/tests/acceptance/tag-groups-test.js
index fe24a9b..c3183d6 100644
--- a/app/assets/javascripts/discourse/tests/acceptance/tag-groups-test.js
+++ b/app/assets/javascripts/discourse/tests/acceptance/tag-groups-test.js
@@ -18,6 +18,19 @@ acceptance("Tag Groups", {
         },
       });
     });
+
+    server.get("/groups/search.json", () => {
+      return helper.response([
+        {
+          id: 88,
+          name: "tl1",
+        },
+        {
+          id: 89,
+          name: "tl2",
+        },
+      ]);
+    });
   },
 });
 
@@ -36,3 +49,26 @@ test("tag groups can be saved and deleted", async (assert) => {
   await click(".tag-chooser .choice:first");
   assert.ok(!find(".tag-group-content .btn.btn-danger")[0].disabled);
 });
+
+QUnit.test(
+  "tag groups can have multiple groups added to them",
+  async (assert) => {
+    const tags = selectKit(".tag-chooser");
+    const groups = selectKit(".group-chooser");
+
+    await visit("/tag_groups");
+    await click(".content-list .btn");
+
+    await fillIn(".tag-group-content h1 input", "test tag group");
+    await tags.expand();
+    await tags.selectRowByValue("monkey");
+
+    await click("#private-permission");
+    assert.ok(find(".tag-group-content .btn.btn-default:disabled").length);
+
+    await groups.expand();
+    await groups.selectRowByIndex(1);
+    await groups.selectRowByIndex(0);
+    assert.ok(!find(".tag-group-content .btn.btn-default")[0].disabled);
+  }
+);
diff --git a/app/assets/stylesheets/common/base/tagging.scss b/app/assets/stylesheets/common/base/tagging.scss
index e3ce31e..8222c0f 100644

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

GitHub sha: 099bf97d

This commit appears in #10854 which was approved by eviltrout. It was merged by jbrw.