From 40cb46631f8a34326304edd24d23b71ff6d89bfe Mon Sep 17 00:00:00 2001 From: Peter Wagenet Date: Wed, 3 Aug 2022 02:12:17 -0700 Subject: [PATCH] DEV: Update `/admin/badges` to modern Ember patterns (#17672) * Nest admin badges controller and route files * Use standard file names for admin-badges * Update resolver to allow standardized file structure for admin * Add adminBadges.index controller for property tracking * Modernize admin badges controller * Modernize admin-badges route * Add admin-badges index route * Modernize admin-badges.show controller and route * Modernize admin-badges.award controller and route * Convert BadgeButton to a Glimmer component --- .../addon/controllers/admin-badges-award.js | 99 -------- .../addon/controllers/admin-badges-show.js | 216 ---------------- .../admin/addon/controllers/admin-badges.js | 23 +- .../addon/controllers/admin-badges/award.js | 90 +++++++ .../addon/controllers/admin-badges/index.js | 8 + .../addon/controllers/admin-badges/show.js | 238 ++++++++++++++++++ .../admin/addon/routes/admin-badges-show.js | 64 ----- .../admin/addon/routes/admin-badges.js | 32 ++- .../award.js} | 10 +- .../index.js} | 12 +- .../admin/addon/routes/admin-badges/show.js | 64 +++++ .../{badges.hbs => admin-badges.hbs} | 0 .../award.hbs} | 0 .../index.hbs} | 0 .../show.hbs} | 2 +- .../discourse-common/addon/resolver.js | 1 + .../discourse/app/components/badge-button.js | 14 +- .../app/templates/components/badge-button.hbs | 6 +- 18 files changed, 449 insertions(+), 430 deletions(-) delete mode 100644 app/assets/javascripts/admin/addon/controllers/admin-badges-award.js delete mode 100644 app/assets/javascripts/admin/addon/controllers/admin-badges-show.js create mode 100644 app/assets/javascripts/admin/addon/controllers/admin-badges/award.js create mode 100644 app/assets/javascripts/admin/addon/controllers/admin-badges/index.js create mode 100644 app/assets/javascripts/admin/addon/controllers/admin-badges/show.js delete mode 100644 app/assets/javascripts/admin/addon/routes/admin-badges-show.js rename app/assets/javascripts/admin/addon/routes/{admin-badges-award.js => admin-badges/award.js} (72%) rename app/assets/javascripts/admin/addon/routes/{admin-badges-index.js => admin-badges/index.js} (70%) create mode 100644 app/assets/javascripts/admin/addon/routes/admin-badges/show.js rename app/assets/javascripts/admin/addon/templates/{badges.hbs => admin-badges.hbs} (100%) rename app/assets/javascripts/admin/addon/templates/{badges-award.hbs => admin-badges/award.hbs} (100%) rename app/assets/javascripts/admin/addon/templates/{badges-index.hbs => admin-badges/index.hbs} (100%) rename app/assets/javascripts/admin/addon/templates/{badges-show.hbs => admin-badges/show.hbs} (98%) diff --git a/app/assets/javascripts/admin/addon/controllers/admin-badges-award.js b/app/assets/javascripts/admin/addon/controllers/admin-badges-award.js deleted file mode 100644 index 4318575a34..0000000000 --- a/app/assets/javascripts/admin/addon/controllers/admin-badges-award.js +++ /dev/null @@ -1,99 +0,0 @@ -import Controller from "@ember/controller"; -import I18n from "I18n"; -import { ajax } from "discourse/lib/ajax"; -import bootbox from "bootbox"; -import { extractError } from "discourse/lib/ajax-error"; -import { action } from "@ember/object"; -import discourseComputed from "discourse-common/utils/decorators"; - -export default Controller.extend({ - saving: false, - replaceBadgeOwners: false, - grantExistingHolders: false, - fileSelected: false, - unmatchedEntries: null, - resultsMessage: null, - success: false, - unmatchedEntriesCount: 0, - - resetState() { - this.setProperties({ - saving: false, - unmatchedEntries: null, - resultsMessage: null, - success: false, - unmatchedEntriesCount: 0, - }); - this.send("updateFileSelected"); - }, - - @discourseComputed("fileSelected", "saving") - massAwardButtonDisabled(fileSelected, saving) { - return !fileSelected || saving; - }, - - @discourseComputed("unmatchedEntriesCount", "unmatchedEntries.length") - unmatchedEntriesTruncated(unmatchedEntriesCount, length) { - return unmatchedEntriesCount && length && unmatchedEntriesCount > length; - }, - - @action - updateFileSelected() { - this.set( - "fileSelected", - !!document.querySelector("#massAwardCSVUpload")?.files?.length - ); - }, - - @action - massAward() { - const file = document.querySelector("#massAwardCSVUpload").files[0]; - - if (this.model && file) { - const options = { - type: "POST", - processData: false, - contentType: false, - data: new FormData(), - }; - - options.data.append("file", file); - options.data.append("replace_badge_owners", this.replaceBadgeOwners); - options.data.append("grant_existing_holders", this.grantExistingHolders); - - this.resetState(); - this.set("saving", true); - - ajax(`/admin/badges/award/${this.model.id}`, options) - .then( - ({ - matched_users_count: matchedCount, - unmatched_entries: unmatchedEntries, - unmatched_entries_count: unmatchedEntriesCount, - }) => { - this.setProperties({ - resultsMessage: I18n.t("admin.badges.mass_award.success", { - count: matchedCount, - }), - success: true, - }); - if (unmatchedEntries.length) { - this.setProperties({ - unmatchedEntries, - unmatchedEntriesCount, - }); - } - } - ) - .catch((error) => { - this.setProperties({ - resultsMessage: extractError(error), - success: false, - }); - }) - .finally(() => this.set("saving", false)); - } else { - bootbox.alert(I18n.t("admin.badges.mass_award.aborted")); - } - }, -}); diff --git a/app/assets/javascripts/admin/addon/controllers/admin-badges-show.js b/app/assets/javascripts/admin/addon/controllers/admin-badges-show.js deleted file mode 100644 index 91a2687346..0000000000 --- a/app/assets/javascripts/admin/addon/controllers/admin-badges-show.js +++ /dev/null @@ -1,216 +0,0 @@ -import Controller, { inject as controller } from "@ember/controller"; -import discourseComputed, { observes } from "discourse-common/utils/decorators"; -import I18n from "I18n"; -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 { equal, reads } from "@ember/object/computed"; -import { next } 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); - - // this is needed because the model doesnt have default values - // and as we are using a bufferedProperty it's not accessible - // in any other way - next(() => { - if (this.model) { - if (!this.model.badge_type_id) { - this.model.set( - "badge_type_id", - this.get("badgeTypes.firstObject.id") - ); - } - - if (!this.model.badge_grouping_id) { - this.model.set( - "badge_grouping_id", - this.get("badgeGroupings.firstObject.id") - ); - } - - if (!this.model.trigger) { - this.model.set("trigger", this.get("badgeTriggers.firstObject.id")); - } - } - }); - }, - - @discourseComputed("model.query", "buffered.query") - hasQuery(modelQuery, bufferedQuery) { - if (bufferedQuery) { - return bufferedQuery.trim().length > 0; - } - return modelQuery && modelQuery.trim().length > 0; - }, - - @discourseComputed("model.i18n_name") - textCustomizationPrefix(i18n_name) { - return `badges.${i18n_name}.`; - }, - - @observes("model.id") - _resetSaving() { - this.set("saving", false); - 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) { - let fields = [ - "allow_title", - "multiple_grant", - "listable", - "auto_revoke", - "enabled", - "show_posts", - "target_posts", - "name", - "description", - "long_description", - "icon", - "image_upload_id", - "query", - "badge_grouping_id", - "trigger", - "badge_type_id", - ]; - - if (this.get("buffered.system")) { - let protectedFields = this.protectedSystemFields || []; - fields = fields.filter((f) => !protectedFields.includes(f)); - } - - this.set("saving", true); - this.set("savingStatus", I18n.t("saving")); - - const boolFields = [ - "allow_title", - "multiple_grant", - "listable", - "auto_revoke", - "enabled", - "show_posts", - "target_posts", - ]; - - const data = {}; - const buffered = this.buffered; - fields.forEach(function (field) { - let d = buffered.get(field); - if (boolFields.includes(field)) { - d = !!d; - } - data[field] = d; - }); - - const newBadge = !this.id; - const model = this.model; - this.model - .save(data) - .then(() => { - if (newBadge) { - const adminBadges = this.get("adminBadges.model"); - if (!adminBadges.includes(model)) { - adminBadges.pushObject(model); - } - this.transitionToRoute("adminBadges.show", model.get("id")); - } else { - this.commitBuffer(); - this.set("savingStatus", I18n.t("saved")); - } - }) - .catch(popupAjaxError) - .finally(() => { - this.set("saving", false); - this.set("savingStatus", ""); - }); - } - }, - - destroy() { - const adminBadges = this.get("adminBadges.model"); - const model = this.model; - - if (!model.get("id")) { - this.transitionToRoute("adminBadges.index"); - return; - } - - return bootbox.confirm( - I18n.t("admin.badges.delete_confirm"), - I18n.t("no_value"), - I18n.t("yes_value"), - (result) => { - if (result) { - model - .destroy() - .then(() => { - adminBadges.removeObject(model); - this.transitionToRoute("adminBadges.index"); - }) - .catch(() => { - bootbox.alert(I18n.t("generic_error")); - }); - } - } - ); - }, - }, -}); diff --git a/app/assets/javascripts/admin/addon/controllers/admin-badges.js b/app/assets/javascripts/admin/addon/controllers/admin-badges.js index 11d78fc4cc..50af52d17f 100644 --- a/app/assets/javascripts/admin/addon/controllers/admin-badges.js +++ b/app/assets/javascripts/admin/addon/controllers/admin-badges.js @@ -1,18 +1,23 @@ import Controller from "@ember/controller"; -import discourseComputed from "discourse-common/utils/decorators"; import { inject as service } from "@ember/service"; +import { tracked } from "@glimmer/tracking"; -export default Controller.extend({ - routing: service("-routing"), +export default class AdminBadgesController extends Controller { + @service router; - @discourseComputed("routing.currentRouteName") - selectedRoute() { - const currentRoute = this.routing.currentRouteName; + // Set by the route + @tracked badgeGroupings; + @tracked badgeTypes; + @tracked protectedSystemFields; + @tracked badgeTriggers; + + get selectedRoute() { + const currentRoute = this.router.currentRouteName; const indexRoute = "adminBadges.index"; if (currentRoute === indexRoute) { return "adminBadges.show"; } else { - return this.routing.currentRouteName; + return currentRoute; } - }, -}); + } +} diff --git a/app/assets/javascripts/admin/addon/controllers/admin-badges/award.js b/app/assets/javascripts/admin/addon/controllers/admin-badges/award.js new file mode 100644 index 0000000000..e564840115 --- /dev/null +++ b/app/assets/javascripts/admin/addon/controllers/admin-badges/award.js @@ -0,0 +1,90 @@ +import Controller from "@ember/controller"; +import I18n from "I18n"; +import { ajax } from "discourse/lib/ajax"; +import bootbox from "bootbox"; +import { extractError } from "discourse/lib/ajax-error"; +import { action } from "@ember/object"; +import { tracked } from "@glimmer/tracking"; + +export default class AdminBadgesAwardController extends Controller { + @tracked saving = false; + @tracked replaceBadgeOwners = false; + @tracked grantExistingHolders = false; + @tracked fileSelected = false; + @tracked unmatchedEntries = null; + @tracked resultsMessage = null; + @tracked success = false; + @tracked unmatchedEntriesCount = 0; + + resetState() { + this.saving = false; + this.unmatchedEntries = null; + this.resultsMessage = null; + this.success = false; + this.unmatchedEntriesCount = 0; + + this.updateFileSelected(); + } + + get massAwardButtonDisabled() { + return !this.fileSelected || this.saving; + } + + get unmatchedEntriesTruncated() { + let count = this.unmatchedEntriesCount; + let length = this.unmatchedEntries.length; + return count && length && count > length; + } + + @action + updateFileSelected() { + this.fileSelected = !!document.querySelector("#massAwardCSVUpload")?.files + ?.length; + } + + @action + massAward() { + const file = document.querySelector("#massAwardCSVUpload").files[0]; + + if (this.model && file) { + const options = { + type: "POST", + processData: false, + contentType: false, + data: new FormData(), + }; + + options.data.append("file", file); + options.data.append("replace_badge_owners", this.replaceBadgeOwners); + options.data.append("grant_existing_holders", this.grantExistingHolders); + + this.resetState(); + this.saving = true; + + ajax(`/admin/badges/award/${this.model.id}`, options) + .then( + ({ + matched_users_count: matchedCount, + unmatched_entries: unmatchedEntries, + unmatched_entries_count: unmatchedEntriesCount, + }) => { + this.resultsMessage = I18n.t("admin.badges.mass_award.success", { + count: matchedCount, + }); + this.success = true; + if (unmatchedEntries.length) { + this.unmatchedEntries = unmatchedEntries; + this.unmatchedEntriesCount = unmatchedEntriesCount; + } + } + ) + .catch((error) => { + this.resultsMessage = extractError(error); + this.success = false; + }) + .finally(() => (this.saving = false)); + } else { + bootbox.alert(I18n.t("admin.badges.mass_award.aborted")); + } + } +} diff --git a/app/assets/javascripts/admin/addon/controllers/admin-badges/index.js b/app/assets/javascripts/admin/addon/controllers/admin-badges/index.js new file mode 100644 index 0000000000..a2981cc4a0 --- /dev/null +++ b/app/assets/javascripts/admin/addon/controllers/admin-badges/index.js @@ -0,0 +1,8 @@ +import Controller from "@ember/controller"; +import { tracked } from "@glimmer/tracking"; + +export default class AdminBadgesIndexController extends Controller { + // Set by the route + @tracked badgeIntroLinks; + @tracked badgeIntroEmoji; +} diff --git a/app/assets/javascripts/admin/addon/controllers/admin-badges/show.js b/app/assets/javascripts/admin/addon/controllers/admin-badges/show.js new file mode 100644 index 0000000000..29d95f2c0f --- /dev/null +++ b/app/assets/javascripts/admin/addon/controllers/admin-badges/show.js @@ -0,0 +1,238 @@ +import Controller, { inject as controller } from "@ember/controller"; +import { observes } from "discourse-common/utils/decorators"; +import I18n from "I18n"; +import bootbox from "bootbox"; +import { bufferedProperty } from "discourse/mixins/buffered-content"; +import { popupAjaxError } from "discourse/lib/ajax-error"; +import { next } from "@ember/runloop"; +import { action } from "@ember/object"; +import { inject as service } from "@ember/service"; +import getURL from "discourse-common/lib/get-url"; +import { tracked } from "@glimmer/tracking"; + +const IMAGE = "image"; +const ICON = "icon"; + +// TODO: Stop using Mixin here +export default class AdminBadgesShowController extends Controller.extend( + bufferedProperty("model") +) { + @controller adminBadges; + @service router; + + @tracked saving = false; + @tracked savingStatus = ""; + @tracked selectedGraphicType = null; + + get badgeTypes() { + return this.adminBadges.badgeTypes; + } + + get badgeGroupings() { + return this.adminBadges.badgeGroupings; + } + + get badgeTriggers() { + return this.adminBadges.badgeTriggers; + } + + get protectedSystemFields() { + return this.adminBadges.protectedSystemFields; + } + + get readOnly() { + return this.buffered.get("system"); + } + + get showDisplayName() { + return this.name !== this.displayName; + } + + get iconSelectorSelected() { + return this.selectedGraphicType === ICON; + } + + get imageUploaderSelected() { + return this.selectedGraphicType === IMAGE; + } + + init() { + super.init(...arguments); + + // this is needed because the model doesnt have default values + // and as we are using a bufferedProperty it's not accessible + // in any other way + next(() => { + // Using `set` here isn't ideal, but we don't know that tracking is set up on the model yet. + if (this.model) { + if (!this.model.badge_type_id) { + this.model.set("badge_type_id", this.badgeTypes?.[0]?.id); + } + + if (!this.model.badge_grouping_id) { + this.model.set("badge_grouping_id", this.badgeGroupings?.[0]?.id); + } + + if (!this.model.trigger) { + this.model.set("trigger", this.badgeTriggers?.[0]?.id); + } + } + }); + } + + get hasQuery() { + let modelQuery = this.model.query; + let bufferedQuery = this.bufferedQuery; + + if (bufferedQuery) { + return bufferedQuery.trim().length > 0; + } + return modelQuery && modelQuery.trim().length > 0; + } + + get textCustomizationPrefix() { + return `badges.${this.model.i18n_name}.`; + } + + // FIXME: Remove observer + @observes("model.id") + _resetSaving() { + this.saving = false; + this.savingStatus = ""; + } + + showIconSelector() { + this.selectedGraphicType = ICON; + } + + showImageUploader() { + this.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.set("image_upload_id", upload.id); + this.buffered.set("image_url", getURL(upload.url)); + } + + @action + removeImage() { + this.buffered.set("image_upload_id", null); + this.buffered.set("image_url", null); + } + + @action + save() { + if (!this.saving) { + let fields = [ + "allow_title", + "multiple_grant", + "listable", + "auto_revoke", + "enabled", + "show_posts", + "target_posts", + "name", + "description", + "long_description", + "icon", + "image_upload_id", + "query", + "badge_grouping_id", + "trigger", + "badge_type_id", + ]; + + if (this.buffered.get("system")) { + let protectedFields = this.protectedSystemFields || []; + fields = fields.filter((f) => !protectedFields.includes(f)); + } + + this.saving = true; + this.savingStatus = I18n.t("saving"); + + const boolFields = [ + "allow_title", + "multiple_grant", + "listable", + "auto_revoke", + "enabled", + "show_posts", + "target_posts", + ]; + + const data = {}; + const buffered = this.buffered; + fields.forEach(function (field) { + let d = buffered.get(field); + if (boolFields.includes(field)) { + d = !!d; + } + data[field] = d; + }); + + const newBadge = !this.id; + const model = this.model; + this.model + .save(data) + .then(() => { + if (newBadge) { + const adminBadges = this.get("adminBadges.model"); + if (!adminBadges.includes(model)) { + adminBadges.pushObject(model); + } + this.transitionToRoute("adminBadges.show", model.get("id")); + } else { + this.commitBuffer(); + this.savingStatus = I18n.t("saved"); + } + }) + .catch(popupAjaxError) + .finally(() => { + this.saving = false; + this.savingStatus = ""; + }); + } + } + + @action + destroyBadge() { + const adminBadges = this.adminBadges.model; + const model = this.model; + + if (!model?.get("id")) { + this.router.transitionTo("adminBadges.index"); + return; + } + + return bootbox.confirm( + I18n.t("admin.badges.delete_confirm"), + I18n.t("no_value"), + I18n.t("yes_value"), + (result) => { + if (result) { + model + .destroy() + .then(() => { + adminBadges.removeObject(model); + this.transitionToRoute("adminBadges.index"); + }) + .catch(() => { + bootbox.alert(I18n.t("generic_error")); + }); + } + } + ); + } +} diff --git a/app/assets/javascripts/admin/addon/routes/admin-badges-show.js b/app/assets/javascripts/admin/addon/routes/admin-badges-show.js deleted file mode 100644 index 2727046762..0000000000 --- a/app/assets/javascripts/admin/addon/routes/admin-badges-show.js +++ /dev/null @@ -1,64 +0,0 @@ -import Badge from "discourse/models/badge"; -import I18n from "I18n"; -import Route from "@ember/routing/route"; -import { ajax } from "discourse/lib/ajax"; -import bootbox from "bootbox"; -import { get } from "@ember/object"; -import showModal from "discourse/lib/show-modal"; - -export default Route.extend({ - serialize(m) { - return { badge_id: get(m, "id") || "new" }; - }, - - model(params) { - if (params.badge_id === "new") { - return Badge.create({ - name: I18n.t("admin.badges.new_badge"), - }); - } - return this.modelFor("adminBadges").findBy( - "id", - parseInt(params.badge_id, 10) - ); - }, - - setupController(controller, model) { - this._super(...arguments); - if (model.image_url) { - controller.showImageUploader(); - } else if (model.icon) { - controller.showIconSelector(); - } - }, - - actions: { - editGroupings() { - const model = this.controllerFor("admin-badges").get("badgeGroupings"); - showModal("admin-edit-badge-groupings", { model, admin: true }); - }, - - preview(badge, explain) { - badge.set("preview_loading", true); - ajax("/admin/badges/preview.json", { - type: "POST", - data: { - sql: badge.get("query"), - target_posts: !!badge.get("target_posts"), - trigger: badge.get("trigger"), - explain, - }, - }) - .then(function (model) { - badge.set("preview_loading", false); - showModal("admin-badge-preview", { model, admin: true }); - }) - .catch(function (error) { - badge.set("preview_loading", false); - // eslint-disable-next-line no-console - console.error(error); - bootbox.alert("Network error"); - }); - }, - }, -}); diff --git a/app/assets/javascripts/admin/addon/routes/admin-badges.js b/app/assets/javascripts/admin/addon/routes/admin-badges.js index c966b7a161..b316996635 100644 --- a/app/assets/javascripts/admin/addon/routes/admin-badges.js +++ b/app/assets/javascripts/admin/addon/routes/admin-badges.js @@ -4,15 +4,14 @@ import DiscourseRoute from "discourse/routes/discourse"; import I18n from "I18n"; import { ajax } from "discourse/lib/ajax"; -export default DiscourseRoute.extend({ - _json: null, +export default class AdminBadgesRoute extends DiscourseRoute { + _json = null; - model() { - return ajax("/admin/badges.json").then((json) => { - this._json = json; - return Badge.createFromJson(json); - }); - }, + async model() { + let json = await ajax("/admin/badges.json"); + this._json = json; + return Badge.createFromJson(json); + } setupController(controller, model) { const json = this._json; @@ -31,12 +30,11 @@ export default DiscourseRoute.extend({ badgeGroupings.push(BadgeGrouping.create(badgeGroupingJson)); }); - controller.setProperties({ - badgeGroupings, - badgeTypes: json.badge_types, - protectedSystemFields: json.admin_badges.protected_system_fields, - badgeTriggers, - model, - }); - }, -}); + controller.badgeGroupings = badgeGroupings; + controller.badgeTypes = json.badge_types; + controller.protectedSystemFields = + json.admin_badges.protected_system_fields; + controller.badgeTriggers = badgeTriggers; + controller.model = model; + } +} diff --git a/app/assets/javascripts/admin/addon/routes/admin-badges-award.js b/app/assets/javascripts/admin/addon/routes/admin-badges/award.js similarity index 72% rename from app/assets/javascripts/admin/addon/routes/admin-badges-award.js rename to app/assets/javascripts/admin/addon/routes/admin-badges/award.js index 6fe72a6bf1..957bb1ba17 100644 --- a/app/assets/javascripts/admin/addon/routes/admin-badges-award.js +++ b/app/assets/javascripts/admin/addon/routes/admin-badges/award.js @@ -1,6 +1,6 @@ import Route from "discourse/routes/discourse"; -export default Route.extend({ +export default class AdminBadgesAwardRoute extends Route { model(params) { if (params.badge_id !== "new") { return this.modelFor("adminBadges").findBy( @@ -8,10 +8,10 @@ export default Route.extend({ parseInt(params.badge_id, 10) ); } - }, + } setupController(controller) { - this._super(...arguments); + super.setupController(...arguments); controller.resetState(); - }, -}); + } +} diff --git a/app/assets/javascripts/admin/addon/routes/admin-badges-index.js b/app/assets/javascripts/admin/addon/routes/admin-badges/index.js similarity index 70% rename from app/assets/javascripts/admin/addon/routes/admin-badges-index.js rename to app/assets/javascripts/admin/addon/routes/admin-badges/index.js index 0f44e83d04..d16f408c23 100644 --- a/app/assets/javascripts/admin/addon/routes/admin-badges-index.js +++ b/app/assets/javascripts/admin/addon/routes/admin-badges/index.js @@ -14,11 +14,9 @@ const badgeIntroLinks = [ }, ]; -export default Route.extend({ +export default class AdminBadgesIndexRoute extends Route { setupController(controller) { - controller.setProperties({ - badgeIntroLinks, - badgeIntroEmoji: emojiUrlFor("woman_student:t4"), - }); - }, -}); + controller.badgeIntroLinks = badgeIntroLinks; + controller.badgeIntroEmoji = emojiUrlFor("woman_student:t4"); + } +} diff --git a/app/assets/javascripts/admin/addon/routes/admin-badges/show.js b/app/assets/javascripts/admin/addon/routes/admin-badges/show.js new file mode 100644 index 0000000000..4d1eb1db76 --- /dev/null +++ b/app/assets/javascripts/admin/addon/routes/admin-badges/show.js @@ -0,0 +1,64 @@ +import Badge from "discourse/models/badge"; +import I18n from "I18n"; +import Route from "@ember/routing/route"; +import { ajax } from "discourse/lib/ajax"; +import bootbox from "bootbox"; +import { action, get } from "@ember/object"; +import showModal from "discourse/lib/show-modal"; + +export default class AdminBadgesShowRoute extends Route { + serialize(m) { + return { badge_id: get(m, "id") || "new" }; + } + + model(params) { + if (params.badge_id === "new") { + return Badge.create({ + name: I18n.t("admin.badges.new_badge"), + }); + } + return this.modelFor("adminBadges").findBy( + "id", + parseInt(params.badge_id, 10) + ); + } + + setupController(controller, model) { + super.setupController(...arguments); + if (model.image_url) { + controller.showImageUploader(); + } else if (model.icon) { + controller.showIconSelector(); + } + } + + @action + editGroupings() { + const model = this.controllerFor("admin-badges").get("badgeGroupings"); + showModal("admin-edit-badge-groupings", { model, admin: true }); + } + + @action + preview(badge, explain) { + badge.set("preview_loading", true); + ajax("/admin/badges/preview.json", { + type: "POST", + data: { + sql: badge.get("query"), + target_posts: !!badge.get("target_posts"), + trigger: badge.get("trigger"), + explain, + }, + }) + .then(function (model) { + badge.set("preview_loading", false); + showModal("admin-badge-preview", { model, admin: true }); + }) + .catch(function (error) { + badge.set("preview_loading", false); + // eslint-disable-next-line no-console + console.error(error); + bootbox.alert("Network error"); + }); + } +} diff --git a/app/assets/javascripts/admin/addon/templates/badges.hbs b/app/assets/javascripts/admin/addon/templates/admin-badges.hbs similarity index 100% rename from app/assets/javascripts/admin/addon/templates/badges.hbs rename to app/assets/javascripts/admin/addon/templates/admin-badges.hbs diff --git a/app/assets/javascripts/admin/addon/templates/badges-award.hbs b/app/assets/javascripts/admin/addon/templates/admin-badges/award.hbs similarity index 100% rename from app/assets/javascripts/admin/addon/templates/badges-award.hbs rename to app/assets/javascripts/admin/addon/templates/admin-badges/award.hbs diff --git a/app/assets/javascripts/admin/addon/templates/badges-index.hbs b/app/assets/javascripts/admin/addon/templates/admin-badges/index.hbs similarity index 100% rename from app/assets/javascripts/admin/addon/templates/badges-index.hbs rename to app/assets/javascripts/admin/addon/templates/admin-badges/index.hbs diff --git a/app/assets/javascripts/admin/addon/templates/badges-show.hbs b/app/assets/javascripts/admin/addon/templates/admin-badges/show.hbs similarity index 98% rename from app/assets/javascripts/admin/addon/templates/badges-show.hbs rename to app/assets/javascripts/admin/addon/templates/admin-badges/show.hbs index 520790be3b..1cf2bbab5a 100644 --- a/app/assets/javascripts/admin/addon/templates/badges-show.hbs +++ b/app/assets/javascripts/admin/addon/templates/admin-badges/show.hbs @@ -159,7 +159,7 @@ {{this.savingStatus}} {{#unless this.readOnly}} - + {{/unless}} diff --git a/app/assets/javascripts/discourse-common/addon/resolver.js b/app/assets/javascripts/discourse-common/addon/resolver.js index 7ba6dd1f1f..e2683c37d0 100644 --- a/app/assets/javascripts/discourse-common/addon/resolver.js +++ b/app/assets/javascripts/discourse-common/addon/resolver.js @@ -353,6 +353,7 @@ export function buildResolver(baseName) { resolved = // Built-in this.findTemplate(adminParsedName, "admin/templates/") || + this.findTemplate(parsedName, "admin/templates/") || // Plugin this.findTemplate(adminParsedName, "javascripts/admin/"); } diff --git a/app/assets/javascripts/discourse/app/components/badge-button.js b/app/assets/javascripts/discourse/app/components/badge-button.js index 0627cd5c91..8b44d859cd 100644 --- a/app/assets/javascripts/discourse/app/components/badge-button.js +++ b/app/assets/javascripts/discourse/app/components/badge-button.js @@ -1,16 +1,12 @@ -import Component from "@ember/component"; -import { computed } from "@ember/object"; +import Component from "@glimmer/component"; import domFromString from "discourse-common/lib/dom-from-string"; +// Takes @badge as argument. export default class BadgeButtonComponent extends Component { - tagName = ""; - badge = null; - - @computed("badge.description") get title() { - if (this.badge?.description) { - return domFromString(`
${this.badge?.description}
`)[0] - .innerText; + const description = this.args.badge?.description; + if (description) { + return domFromString(`
${description}
`)[0].innerText; } } } diff --git a/app/assets/javascripts/discourse/app/templates/components/badge-button.hbs b/app/assets/javascripts/discourse/app/templates/components/badge-button.hbs index a6ece24e8b..a763243d11 100644 --- a/app/assets/javascripts/discourse/app/templates/components/badge-button.hbs +++ b/app/assets/javascripts/discourse/app/templates/components/badge-button.hbs @@ -1,5 +1,5 @@ - - {{icon-or-image this.badge}} - {{this.badge.name}} + + {{icon-or-image @badge}} + {{@badge.name}} {{yield}}