FIX: when destroying a draft always ensure saving is done

FIX: when destroying a draft always ensure saving is done

There was a race condition where drafts could be either saving or queued to be saved and a user canceled draft leading to destroying it.

This cancels debounce save and waits for save in the pipeline to be over prior to firing off a DELETE on the draft

diff --git a/app/assets/javascripts/discourse/app/controllers/composer.js b/app/assets/javascripts/discourse/app/controllers/composer.js
index 41fb94c..d030c88 100644
--- a/app/assets/javascripts/discourse/app/controllers/composer.js
+++ b/app/assets/javascripts/discourse/app/controllers/composer.js
@@ -1,7 +1,7 @@
 import I18n from "I18n";
 import { isEmpty } from "@ember/utils";
 import { and, or, alias, reads } from "@ember/object/computed";
-import { debounce } from "@ember/runloop";
+import { cancel, debounce } from "@ember/runloop";
 import { inject as service } from "@ember/service";
 import { inject } from "@ember/controller";
 import Controller from "@ember/controller";
@@ -982,6 +982,10 @@ export default Controller.extend({
         this.send("clearTopicDraft");
       }
 
+      if (this._saveDraftPromise) {
+        return this._saveDraftPromise.then(() => this.destroyDraft());
+      }
+
       return Draft.clear(key, this.get("model.draftSequence")).then(() =>
         this.appEvents.trigger("draft:destroyed", key)
       );
@@ -1028,6 +1032,10 @@ export default Controller.extend({
   cancelComposer(differentDraft = false) {
     this.skipAutoSave = true;
 
+    if (this._saveDraftDebounce) {
+      cancel(this._saveDraftDebounce);
+    }
+
     const keyPrefix =
       this.model.action === "edit" ? "post.abandon_edit" : "post.abandon";
 
@@ -1102,11 +1110,12 @@ export default Controller.extend({
         // in test debounce is Ember.run, this will cause
         // an infinite loop
         if (ENV.environment !== "test") {
-          debounce(this, this._saveDraft, 2000);
+          this._saveDraftDebounce = debounce(this, this._saveDraft, 2000);
         }
       } else {
-        model.saveDraft().finally(() => {
+        this._saveDraftPromise = model.saveDraft().finally(() => {
           this._lastDraftSaved = Date.now();
+          this._saveDraftPromise = null;
         });
       }
     }
@@ -1127,7 +1136,7 @@ export default Controller.extend({
       if (Date.now() - this._lastDraftSaved > 15000) {
         this._saveDraft();
       } else {
-        debounce(this, this._saveDraft, 2000);
+        this._saveDraftDebounce = debounce(this, this._saveDraft, 2000);
       }
     }
   },

GitHub sha: 1cf2d1f9

1 Like