FIX: Do not offer to save draft if invalid (#13863)

An invalid draft is the draft of a topic with a short title or body.
The client does not save these, but it will ask the client if they want
to save it. Even if the answer is 'yes', the draft is discarded. This
commit skips Save button for small drafts.
This commit is contained in:
Bianca Nenciu 2021-07-30 10:43:09 +03:00 committed by GitHub
parent 849827841f
commit 531dbc5e6a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 49 additions and 15 deletions

View File

@ -1189,9 +1189,6 @@ export default Controller.extend({
}, },
onSaveDraft: () => { onSaveDraft: () => {
this._saveDraft(); this._saveDraft();
if (this.model.draftKey === Composer.NEW_TOPIC_KEY) {
this.currentUser.set("has_topic_draft", true);
}
this.model.clearState(); this.model.clearState();
this.close(); this.close();
resolve(); resolve();
@ -1242,7 +1239,9 @@ export default Controller.extend({
); );
} }
} else { } else {
this._saveDraftPromise = model.saveDraft().finally(() => { this._saveDraftPromise = model
.saveDraft(this.currentUser)
.finally(() => {
this._lastDraftSaved = Date.now(); this._lastDraftSaved = Date.now();
this._saveDraftPromise = null; this._saveDraftPromise = null;
}); });

View File

@ -1165,38 +1165,56 @@ const Composer = RestModel.extend({
return ""; return "";
}, },
saveDraft() { @discourseComputed(
"draftSaving",
"disableDrafts",
"canEditTitle",
"title",
"reply",
"titleLengthValid",
"replyLength",
"minimumPostLength"
)
canSaveDraft() {
if (this.draftSaving) { if (this.draftSaving) {
return Promise.resolve(); return false;
} }
// Do not save when drafts are disabled // Do not save when drafts are disabled
if (this.disableDrafts) { if (this.disableDrafts) {
return Promise.resolve(); return false;
} }
if (this.canEditTitle) { if (this.canEditTitle) {
// Save title and/or post body // Save title and/or post body
if (isEmpty(this.title) && isEmpty(this.reply)) { if (isEmpty(this.title) && isEmpty(this.reply)) {
return Promise.resolve(); return false;
} }
// Do not save when both title and reply's length are too small // Do not save when both title and reply's length are too small
if (!this.titleLengthValid && this.replyLength < this.minimumPostLength) { if (!this.titleLengthValid && this.replyLength < this.minimumPostLength) {
return Promise.resolve(); return false;
} }
} else { } else {
// Do not save when there is no reply // Do not save when there is no reply
if (isEmpty(this.reply)) { if (isEmpty(this.reply)) {
return Promise.resolve(); return false;
} }
// Do not save when the reply's length is too small // Do not save when the reply's length is too small
if (this.replyLength < this.minimumPostLength) { if (this.replyLength < this.minimumPostLength) {
return Promise.resolve(); return false;
} }
} }
return true;
},
saveDraft(user) {
if (!this.canSaveDraft) {
return Promise.resolve();
}
this.setProperties({ this.setProperties({
draftSaving: true, draftSaving: true,
draftConflictUser: null, draftConflictUser: null,
@ -1225,6 +1243,10 @@ const Composer = RestModel.extend({
draftConflictUser: result.conflict_user, draftConflictUser: result.conflict_user,
}); });
} else { } else {
if (this.draftKey === NEW_TOPIC_KEY && user) {
user.set("has_topic_draft", true);
}
this.setProperties({ this.setProperties({
draftStatus: null, draftStatus: null,
draftConflictUser: null, draftConflictUser: null,

View File

@ -6,6 +6,8 @@
<div class="modal-footer"> <div class="modal-footer">
{{d-button icon="far-trash-alt" label="post.cancel_composer.discard" class="btn-danger discard-draft" action=(action "destroyDraft")}} {{d-button icon="far-trash-alt" label="post.cancel_composer.discard" class="btn-danger discard-draft" action=(action "destroyDraft")}}
{{#if model.canSaveDraft}}
{{d-button label="post.cancel_composer.save_draft" class="save-draft" action=(action "saveDraftAndClose")}} {{d-button label="post.cancel_composer.save_draft" class="save-draft" action=(action "saveDraftAndClose")}}
{{/if}}
{{d-button label="post.cancel_composer.keep_editing" class="keep-editing" action=(action "dismissModal")}} {{d-button label="post.cancel_composer.keep_editing" class="keep-editing" action=(action "dismissModal")}}
</div> </div>

View File

@ -999,4 +999,15 @@ acceptance("Composer", function (needs) {
await fillIn(".d-editor-input", "@staff"); await fillIn(".d-editor-input", "@staff");
assert.ok(exists(".composer-popup"), "Shows the 'group_mentioned' notice"); assert.ok(exists(".composer-popup"), "Shows the 'group_mentioned' notice");
}); });
test("Does not save invalid draft", async function (assert) {
this.siteSettings.min_first_post_length = 20;
await visit("/");
await click("#create-topic");
await fillIn("#reply-title", "Something");
await fillIn(".d-editor-input", "Something");
await click(".save-or-cancel .cancel");
assert.notOk(exists(".discard-draft-modal .save-draft"));
});
}); });