diff --git a/app/assets/javascripts/admin/addon/mixins/setting-component.js b/app/assets/javascripts/admin/addon/mixins/setting-component.js index 226ff97de36..44518324536 100644 --- a/app/assets/javascripts/admin/addon/mixins/setting-component.js +++ b/app/assets/javascripts/admin/addon/mixins/setting-component.js @@ -81,6 +81,79 @@ const DEFAULT_USER_PREFERENCES = [ "default_sidebar_show_count_of_new_items", ]; +const ACRONYMS = new Set([ + "acl", + "ai", + "api", + "bg", + "cdn", + "cors", + "cta", + "dm", + "eu", + "faq", + "fg", + "ga", + "gb", + "gtm", + "hd", + "http", + "https", + "iam", + "id", + "imap", + "ip", + "jpg", + "json", + "kb", + "mb", + "oidc", + "pm", + "png", + "pop3", + "s3", + "smtp", + "svg", + "tl", + "tl0", + "tl1", + "tl2", + "tl3", + "tl4", + "tld", + "txt", + "url", + "ux", +]); + +const MIXED_CASE = [ + ["adobe analytics", "Adobe Analytics"], + ["android", "Android"], + ["chinese", "Chinese"], + ["discord", "Discord"], + ["discourse", "Discourse"], + ["discourse connect", "Discourse Connect"], + ["discourse discover", "Discourse Discover"], + ["discourse narrative bot", "Discourse Narrative Bot"], + ["facebook", "Facebook"], + ["github", "GitHub"], + ["google", "Google"], + ["gravatar", "Gravatar"], + ["gravatars", "Gravatars"], + ["ios", "iOS"], + ["japanese", "Japanese"], + ["linkedin", "LinkedIn"], + ["oauth2", "OAuth2"], + ["opengraph", "OpenGraph"], + ["powered by discourse", "Powered by Discourse"], + ["tiktok", "TikTok"], + ["tos", "ToS"], + ["twitter", "Twitter"], + ["vimeo", "Vimeo"], + ["wordpress", "WordPress"], + ["youtube", "YouTube"], +]; + export default Mixin.create({ modal: service(), router: service(), @@ -143,7 +216,27 @@ export default Mixin.create({ settingName: computed("setting.setting", "setting.label", function () { const setting = this.setting?.setting; const label = this.setting?.label; - return label || setting.replace(/\_/g, " "); + const name = label || setting.replace(/\_/g, " "); + + const formattedName = (name.charAt(0).toUpperCase() + name.slice(1)) + .split(" ") + .map((word) => + ACRONYMS.has(word.toLowerCase()) ? word.toUpperCase() : word + ) + .map((word) => { + if (word.endsWith("s")) { + const singular = word.slice(0, -1).toLowerCase(); + return ACRONYMS.has(singular) ? singular.toUpperCase() + "s" : word; + } + return word; + }) + .join(" "); + + return MIXED_CASE.reduce( + (acc, [key, value]) => + acc.replaceAll(new RegExp(`\\b${key}\\b`, "gi"), value), + formattedName + ); }), componentType: computed("type", function () { diff --git a/spec/system/admin_flags_spec.rb b/spec/system/admin_flags_spec.rb index 790953e3015..d0ebf90fe66 100644 --- a/spec/system/admin_flags_spec.rb +++ b/spec/system/admin_flags_spec.rb @@ -162,7 +162,7 @@ describe "Admin Flags Page", type: :system do ) admin_flags_page.click_settings_tab - expect(page.all(".setting-label h3").map(&:text)).to eq( + expect(page.all(".setting-label h3").map(&:text).map(&:downcase)).to eq( [ "silence new user sensitivity", "num users to silence new user", diff --git a/spec/system/admin_site_setting_label_formatting_spec.rb b/spec/system/admin_site_setting_label_formatting_spec.rb new file mode 100644 index 00000000000..7fbc0631c79 --- /dev/null +++ b/spec/system/admin_site_setting_label_formatting_spec.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true + +describe "Admin Site Setting Formatting", type: :system do + let(:settings_page) { PageObjects::Pages::AdminSiteSettings.new } + fab!(:admin) + + before { sign_in(admin) } + + it "capitalises the first letter of labels" do + setting_name = "default_locale" + + settings_page.visit(setting_name) + + expect(setting_label(setting_name)).to eq("Default locale") + end + + it "capitalises acronyms in labels" do + setting_name = "faq_url" + + settings_page.visit(setting_name) + + expect(setting_label(setting_name)).to eq("FAQ URL") + end + + it "matches multi-word replacements" do + setting_name = "enable_discourse_connect" + + settings_page.visit(setting_name) + + expect(setting_label(setting_name)).to eq("Enable Discourse Connect") + end + + it "matches multiple types of replacements" do + setting_name = "google_oauth2_client_id" + + settings_page.visit(setting_name) + + expect(setting_label(setting_name)).to eq("Google OAuth2 client ID") + end + + def setting_label(setting_name) + settings_page.find(settings_page.setting_row_selector(setting_name) + " h3").text + end +end