FIX: Selected group cleared between emoji uploads (#15581)

FIX: Selected group cleared between emoji uploads (#15581)

When uploading multiple emoji in Admin/Customize/Emojis with an emoji Group selected, the group was cleared between each file uploaded, making bulk uploading of emojis a chore if anything but the default group was needed.

This commit fixes the issue, introduces tests for emoji-uploader, and also adds add-files appEvents for uppy-upload mixin, same as the composer-upload-uppy mixin, for interop with tests and so we don’t have to rely on a file upload element’s change event.

diff --git a/app/assets/javascripts/discourse/app/components/emoji-uploader.js b/app/assets/javascripts/discourse/app/components/emoji-uploader.js
index 474aba6..16b9d5e 100644
--- a/app/assets/javascripts/discourse/app/components/emoji-uploader.js
+++ b/app/assets/javascripts/discourse/app/components/emoji-uploader.js
@@ -56,6 +56,6 @@ export default Component.extend(UppyUploadMixin, {
 
   uploadDone(upload) {
     this.done(upload, this.group);
-    this.setProperties({ name: null, group: DEFAULT_GROUP });
+    this.setProperties({ name: null });
   },
 });
diff --git a/app/assets/javascripts/discourse/app/mixins/uppy-upload.js b/app/assets/javascripts/discourse/app/mixins/uppy-upload.js
index 0b59c07..5b5e7f6 100644
--- a/app/assets/javascripts/discourse/app/mixins/uppy-upload.js
+++ b/app/assets/javascripts/discourse/app/mixins/uppy-upload.js
@@ -17,7 +17,7 @@ import AwsS3 from "@uppy/aws-s3";
 import UppyChecksum from "discourse/lib/uppy-checksum-plugin";
 import UppyS3Multipart from "discourse/mixins/uppy-s3-multipart";
 import UppyChunkedUploader from "discourse/lib/uppy-chunked-uploader-plugin";
-import { on } from "discourse-common/utils/decorators";
+import { bind, on } from "discourse-common/utils/decorators";
 import { warn } from "@ember/debug";
 import bootbox from "bootbox";
 
@@ -54,6 +54,7 @@ export default Mixin.create(UppyS3Multipart, {
       "change",
       this.fileInputEventListener
     );
+    this.appEvents.off(`upload-mixin:${this.id}:add-files`, this._addFiles);
     this._uppyInstance?.close();
     this._uppyInstance = null;
   },
@@ -228,6 +229,7 @@ export default Mixin.create(UppyS3Multipart, {
       }
     }
 
+    this.appEvents.on(`upload-mixin:${this.id}:add-files`, this._addFiles);
     this._uppyReady();
   },
 
@@ -320,21 +322,30 @@ export default Mixin.create(UppyS3Multipart, {
   _bindFileInputChange() {
     this.fileInputEventListener = bindFileInputChangeListener(
       this.fileInputEl,
-      (file) => {
-        try {
-          this._uppyInstance.addFile({
-            source: `${this.id} file input`,
+      this._addFiles
+    );
+  },
+
+  @bind
+  _addFiles(files, opts = {}) {
+    files = Array.isArray(files) ? files : [files];
+    try {
+      this._uppyInstance.addFiles(
+        files.map((file) => {
+          return {
+            source: this.id,
             name: file.name,
             type: file.type,
             data: file,
-          });
-        } catch (err) {
-          warn(`error adding files to uppy: ${err}`, {
-            id: "discourse.upload.uppy-add-files-error",
-          });
-        }
-      }
-    );
+            meta: { pasted: opts.pasted },
+          };
+        })
+      );
+    } catch (err) {
+      warn(`error adding files to uppy: ${err}`, {
+        id: "discourse.upload.uppy-add-files-error",
+      });
+    }
   },
 
   _completeExternalUpload(file) {
diff --git a/app/assets/javascripts/discourse/app/templates/components/emoji-uploader.hbs b/app/assets/javascripts/discourse/app/templates/components/emoji-uploader.hbs
index 4f4bdf7..2c3b01a 100644
--- a/app/assets/javascripts/discourse/app/templates/components/emoji-uploader.hbs
+++ b/app/assets/javascripts/discourse/app/templates/components/emoji-uploader.hbs
@@ -19,6 +19,7 @@
     <div class="input">
       {{combo-box
         name="group"
+        id="emoji-group-selector"
         value=group
         content=newEmojiGroups
         onChange=(action "createEmojiGroup")
diff --git a/app/assets/javascripts/discourse/tests/integration/components/emoji-uploader-test.js b/app/assets/javascripts/discourse/tests/integration/components/emoji-uploader-test.js
new file mode 100644
index 0000000..25e1032
--- /dev/null
+++ b/app/assets/javascripts/discourse/tests/integration/components/emoji-uploader-test.js
@@ -0,0 +1,89 @@
+import componentTest, {
+  setupRenderingTest,
+} from "discourse/tests/helpers/component-test";
+import selectKit from "discourse/tests/helpers/select-kit-helper";
+import {
+  createFile,
+  discourseModule,
+} from "discourse/tests/helpers/qunit-helpers";
+import hbs from "htmlbars-inline-precompile";
+import pretender from "discourse/tests/helpers/create-pretender";
+
+discourseModule("Integration | Component | emoji-uploader", function (hooks) {
+  setupRenderingTest(hooks);
+
+  const template = hbs` {{emoji-uploader
+    emojiGroups=emojiGroups
+    done=(action "emojiUploaded")
+    id="emoji-uploader"
+  }}`;
+
+  hooks.beforeEach(function () {
+    this.setProperties({
+      emojiGroups: ["default", "coolemojis"],
+      actions: {
+        emojiUploaded: (upload, group) => {
+          this.doneUpload(upload, group);
+        },
+      },
+    });
+
+    pretender.post("/admin/customize/emojis.json", () => {
+      return [
+        200,
+        { "Content-Type": "application/json" },
+        {
+          group: "default",
+          name: "test",
+          url:
+            "//upload.s3.dualstack.us-east-2.amazonaws.com/original/1X/123.png",
+        },
+      ];
+    });
+  });
+
+  componentTest("uses the selected group for the upload", {
+    template,
+
+    async test(assert) {
+      const done = assert.async();
+      await selectKit("#emoji-group-selector").expand();
+      await selectKit("#emoji-group-selector").selectRowByValue("coolemojis");
+
+      this.set("doneUpload", (upload, group) => {
+        assert.equal("coolemojis", group);
+        done();
+      });
+      const image = createFile("avatar.png");
+      await this.container
+        .lookup("service:app-events")
+        .trigger("upload-mixin:emoji-uploader:add-files", image);
+    },
+  });
+
+  componentTest("does not clear the selected group between multiple uploads", {
+    template,
+
+    async test(assert) {
+      const done = assert.async();
+      await selectKit("#emoji-group-selector").expand();
+      await selectKit("#emoji-group-selector").selectRowByValue("coolemojis");
+
+      let uploadDoneCount = 0;
+      this.set("doneUpload", (upload, group) => {
+        uploadDoneCount += 1;
+        assert.equal("coolemojis", group);
+
+        if (uploadDoneCount === 2) {
+          done();
+        }
+      });
+
+      const image = createFile("avatar.png");
+      const image2 = createFile("avatar2.png");
+      await this.container
+        .lookup("service:app-events")
+        .trigger("upload-mixin:emoji-uploader:add-files", [image, image2]);
+    },
+  });
+});

GitHub sha: 48f70dcd5f5e0c151342efd094f79cba8949872f

This commit appears in #15581 which was merged by martin.