UX: Add image uploader widget for uploading badge images (#12377)

Currently the process of adding a custom image to badge is quite clunky; you have to upload your image to a topic, and then copy the image URL and pasting it in a text field. Besides being clucky, if the topic or post that contains the image is deleted, the image will be garbage-collected in a few days and the badge will lose the image because the application is not that the image is referenced by a badge.

This commit improves that by adding a proper image uploader widget for badge images.
This commit is contained in:
Osama Sayegh
2021-03-17 08:55:23 +03:00
committed by GitHub
parent 26bfb5d6b9
commit a23d0f9961
21 changed files with 456 additions and 27 deletions

View File

@@ -5,19 +5,27 @@ import bootbox from "bootbox";
import { bufferedProperty } from "discourse/mixins/buffered-content";
import { popupAjaxError } from "discourse/lib/ajax-error";
import { propertyNotEqual } from "discourse/lib/computed";
import { reads } from "@ember/object/computed";
import { equal, reads } from "@ember/object/computed";
import { run } from "@ember/runloop";
import { action } from "@ember/object";
import getURL from "discourse-common/lib/get-url";
const IMAGE = "image";
const ICON = "icon";
export default Controller.extend(bufferedProperty("model"), {
adminBadges: controller(),
saving: false,
savingStatus: "",
selectedGraphicType: null,
badgeTypes: reads("adminBadges.badgeTypes"),
badgeGroupings: reads("adminBadges.badgeGroupings"),
badgeTriggers: reads("adminBadges.badgeTriggers"),
protectedSystemFields: reads("adminBadges.protectedSystemFields"),
readOnly: reads("buffered.system"),
showDisplayName: propertyNotEqual("name", "displayName"),
iconSelectorSelected: equal("selectedGraphicType", ICON),
imageUploaderSelected: equal("selectedGraphicType", IMAGE),
init() {
this._super(...arguments);
@@ -67,6 +75,41 @@ export default Controller.extend(bufferedProperty("model"), {
this.set("savingStatus", "");
},
showIconSelector() {
this.set("selectedGraphicType", ICON);
},
showImageUploader() {
this.set("selectedGraphicType", IMAGE);
},
@action
changeGraphicType(newType) {
if (newType === IMAGE) {
this.showImageUploader();
} else if (newType === ICON) {
this.showIconSelector();
} else {
throw new Error(`Unknown badge graphic type "${newType}"`);
}
},
@action
setImage(upload) {
this.buffered.setProperties({
image_upload_id: upload.id,
image_url: getURL(upload.url),
});
},
@action
removeImage() {
this.buffered.setProperties({
image_upload_id: null,
image_url: null,
});
},
actions: {
save() {
if (!this.saving) {
@@ -82,7 +125,7 @@ export default Controller.extend(bufferedProperty("model"), {
"description",
"long_description",
"icon",
"image",
"image_upload_id",
"query",
"badge_grouping_id",
"trigger",

View File

@@ -23,6 +23,15 @@ export default Route.extend({
);
},
setupController(controller, model) {
this._super(...arguments);
if (model.image_url) {
controller.showImageUploader();
} else if (model.icon) {
controller.showIconSelector();
}
},
actions: {
saveError(e) {
let msg = I18n.t("generic_error");

View File

@@ -15,23 +15,48 @@
</div>
<div>
<label for="icon">{{i18n "admin.badges.icon"}}</label>
{{icon-picker
name="icon"
value=buffered.icon
options=(hash
maximum=1
)
onChange=(action (mut buffered.icon))
}}
<label for="graphic">{{i18n "admin.badges.graphic"}}</label>
<div class="radios">
<label class="radio-label" for="badge-icon">
{{radio-button
name="badge-icon"
id="badge-icon"
value="icon"
selection=selectedGraphicType
onChange=(action "changeGraphicType")
}}
<span>{{i18n "admin.badges.select_an_icon"}}</span>
</label>
<p class="help">{{i18n "admin.badges.icon_help"}}</p>
</div>
<div>
<label for="image">{{i18n "admin.badges.image"}}</label>
{{input type="text" name="image" value=buffered.image}}
<p class="help">{{i18n "admin.badges.image_help"}}</p>
<label class="radio-label" for="badge-image">
{{radio-button
name="badge-image"
id="badge-image"
value="image"
selection=selectedGraphicType
onChange=(action "changeGraphicType")
}}
<span>{{i18n "admin.badges.upload_an_image"}}</span>
</label>
</div>
{{#if imageUploaderSelected}}
{{image-uploader
imageUrl=buffered.image_url
onUploadDone=(action "setImage")
onUploadDeleted=(action "removeImage")
type="badge_image"
class="no-repeat contain-image"}}
<div class="control-instructions">
<p class="help">{{i18n "admin.badges.image_help"}}</p>
</div>
{{else if iconSelectorSelected}}
{{icon-picker
name="icon"
value=buffered.icon
options=(hash maximum=1)
onChange=(action (mut buffered.icon))
}}
{{/if}}
</div>
<div>