FIX: ensures successive tags can be renamed (#12818)

Original bug report: https://meta.discourse.org/t/rename-tag-not-working-as-expected/184950

This bug was caused by the use of `oneWay` which can be very dangerous in this case, from the documentation:

> computed.oneWay only provides an aliased get. The set will not mutate the upstream property, rather causes the current property to become the value set. **This causes the downstream property to permanently diverge from the upstream property.**
This commit is contained in:
Joffrey JAFFEUX 2021-04-23 16:18:23 +02:00 committed by GitHub
parent ce4017ab33
commit 6b10ada752
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 30 additions and 28 deletions

View File

@ -1,37 +1,33 @@
import { action } from "@ember/object";
import BufferedContent from "discourse/mixins/buffered-content"; import BufferedContent from "discourse/mixins/buffered-content";
import Controller from "@ember/controller"; import Controller from "@ember/controller";
import ModalFunctionality from "discourse/mixins/modal-functionality"; import ModalFunctionality from "discourse/mixins/modal-functionality";
import discourseComputed from "discourse-common/utils/decorators"; import discourseComputed from "discourse-common/utils/decorators";
import { extractError } from "discourse/lib/ajax-error"; import { extractError } from "discourse/lib/ajax-error";
import { oneWay } from "@ember/object/computed";
export default Controller.extend(ModalFunctionality, BufferedContent, { export default Controller.extend(ModalFunctionality, BufferedContent, {
tagId: oneWay("model.id"), newTag: null,
@discourseComputed("tagId", "model.id") @discourseComputed("newTag", "model.id")
renameDisabled(inputTagName, currentTagName) { renameDisabled(newTag, currentTag) {
const filterRegexp = new RegExp(this.site.tags_filter_regexp, "g"); const filterRegexp = new RegExp(this.site.tags_filter_regexp, "g");
const newTagName = inputTagName newTag = newTag ? newTag.replace(filterRegexp, "").trim() : "";
? inputTagName.replace(filterRegexp, "").trim() return newTag.length === 0 || newTag === currentTag;
: "";
return newTagName.length === 0 || newTagName === currentTagName;
}, },
actions: { @action
performRename() { performRename() {
this.model this.model
.update({ id: this.get("tagId") }) .update({ id: this.newTag })
.then((result) => { .then((result) => {
this.send("closeModal"); this.send("closeModal");
if (result.responseJson.tag) { if (result.responseJson.tag) {
this.transitionToRoute("tag.show", result.responseJson.tag.id); this.transitionToRoute("tag.show", result.responseJson.tag.id);
} else { } else {
this.flash(extractError(result.responseJson.errors[0]), "error"); this.flash(extractError(result.responseJson.errors[0]), "error");
} }
}) })
.catch((error) => this.flash(extractError(error), "error")); .catch((error) => this.flash(extractError(error), "error"));
},
}, },
}); });

View File

@ -3,13 +3,19 @@
{{i18n "tagging.rename_instructions"}} {{i18n "tagging.rename_instructions"}}
</label> </label>
<div class="controls"> <div class="controls">
{{input value=tagId maxlength=siteSettings.max_tag_length}} {{input
value=(readonly model.id)
maxlength=siteSettings.max_tag_length
input=(action (mut newTag) value="target.value")
}}
</div> </div>
{{/d-modal-body}} {{/d-modal-body}}
<div class="modal-footer"> <div class="modal-footer">
{{d-button class="btn-primary" {{d-button
action=(action "performRename") class="btn-primary"
label="tagging.rename_tag" action=(action "performRename")
disabled=renameDisabled}} label="tagging.rename_tag"
disabled=renameDisabled
}}
</div> </div>