discourse/app/assets/javascripts/admin/addon/models/admin-plugin.js
Martin Brennan 964945a11f
DEV: Add case-converter common lib and use with AdminPlugin (#27725)
The AdminPlugin JS model uses a similar pattern to chat models,
where it is a plain JS class manually converting provided
snake_case attributes from the serializer to JS camelCase.

However this doesn't work when it comes to using `add_to_serializer`
in plugins since core does not know about these new attributes.

Instead, we can use a JS function to convert snake_case to camelCase
and use that when initializing AdminPlugin. This commit also moves
similar functions to a new case-converter.js file in
discourse-common/lib.
2024-07-05 13:22:48 +10:00

91 lines
2.4 KiB
JavaScript

import { cached, tracked } from "@glimmer/tracking";
import { capitalize } from "@ember/string";
import { snakeCaseToCamelCase } from "discourse-common/lib/case-converter";
import I18n from "discourse-i18n";
export default class AdminPlugin {
static create(args = {}) {
return new AdminPlugin(args);
}
@tracked enabled;
constructor(args = {}) {
Object.keys(args).forEach((key) => {
this[snakeCaseToCamelCase(key)] = args[key];
});
}
get useNewShowRoute() {
return this.adminRoute?.use_new_show_route;
}
get snakeCaseName() {
return this.name.replaceAll("-", "_");
}
get translatedCategoryName() {
// We do this because the site setting list is grouped by category,
// with plugins that have their root site setting key defined as `plugins:`
// being grouped under the generic "plugins" category.
//
// If a site setting has defined a proper root key and translated category name,
// we can use that instead to go directly to the setting category.
//
// Over time, no plugins should be missing this data.
return I18n.lookup(`admin.site_settings.categories.${this.snakeCaseName}`);
}
get settingCategoryName() {
if (this.translatedCategoryName) {
return this.snakeCaseName;
}
return "plugins";
}
@cached
get nameTitleized() {
// The category name is better in a lot of cases, as it's a human-inputted
// translation, and we can handle things like SAML instead of showing them
// as Saml from discourse-saml. We can fall back to the programmatic version
// though if needed.
let name;
if (this.translatedCategoryName) {
name = this.translatedCategoryName;
} else {
name = this.name
.split("-")
.map((word) => {
return capitalize(word);
})
.join(" ");
}
// Cuts down on repetition.
const discoursePrefix = "Discourse ";
if (name.startsWith(discoursePrefix)) {
name = name.slice(discoursePrefix.length);
}
return name;
}
@cached
get nameTitleizedLower() {
return this.nameTitleized.toLowerCase();
}
get author() {
if (this.isOfficial || this.isDiscourseOwned) {
return I18n.t("admin.plugins.author", { author: "Discourse" });
}
return I18n.t("admin.plugins.author", { author: this.authors });
}
get linkUrl() {
return this.metaUrl || this.url;
}
}