diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 00000000..f69c55ab --- /dev/null +++ b/.prettierignore @@ -0,0 +1,7 @@ +# Legacy object-literal decorators are not supported by Prettier 3. +assets/javascripts/discourse/components/admin-language-list.js +assets/javascripts/discourse/components/admin-language.js +assets/javascripts/discourse/components/language-switcher-bar.js +assets/javascripts/discourse/components/legacy-table-header-toggle.js +assets/javascripts/discourse/controllers/admin-multilingual-languages.js +assets/javascripts/select-kit/components/content-languages-header.js diff --git a/.template-lintrc.cjs b/.template-lintrc.cjs deleted file mode 100644 index 5355ea06..00000000 --- a/.template-lintrc.cjs +++ /dev/null @@ -1 +0,0 @@ -module.exports = require("@discourse/lint-configs/template-lint"); diff --git a/Gemfile.lock b/Gemfile.lock index eff8f6ad..7d426ab4 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,85 +1,99 @@ GEM remote: https://rubygems.org/ specs: - activesupport (8.0.0) + activesupport (8.1.3.1) base64 - benchmark (>= 0.3) bigdecimal concurrent-ruby (~> 1.0, >= 1.3.1) connection_pool (>= 2.2.5) drb i18n (>= 1.6, < 2) + json logger (>= 1.4.2) minitest (>= 5.1) securerandom (>= 0.3) tzinfo (~> 2.0, >= 2.0.5) uri (>= 0.13.1) - ast (2.4.2) - base64 (0.2.0) - benchmark (0.4.0) - bigdecimal (3.1.8) - concurrent-ruby (1.3.4) - connection_pool (2.4.1) - drb (2.2.1) - i18n (1.14.6) + ast (2.4.3) + base64 (0.3.0) + bigdecimal (4.1.2) + concurrent-ruby (1.3.8) + connection_pool (3.0.2) + drb (2.2.3) + i18n (1.15.2) concurrent-ruby (~> 1.0) - json (2.8.2) - language_server-protocol (3.17.0.3) - logger (1.6.1) - minitest (5.25.2) - parallel (1.26.3) - parser (3.3.6.0) + json (2.21.1) + language_server-protocol (3.17.0.6) + lint_roller (1.1.0) + logger (1.7.0) + minitest (6.0.6) + drb (~> 2.0) + prism (~> 1.5) + parallel (2.1.0) + parser (3.3.12.0) ast (~> 2.4.1) racc prettier_print (1.2.1) + prism (1.9.0) racc (1.8.1) - rack (3.1.10) + rack (3.2.6) rainbow (3.1.1) - regexp_parser (2.9.2) - rubocop (1.69.0) + regexp_parser (2.12.0) + rubocop (1.88.2) json (~> 2.3) - language_server-protocol (>= 3.17.0) - parallel (~> 1.10) + language_server-protocol (~> 3.17.0.2) + lint_roller (~> 1.1.0) + parallel (>= 1.10) parser (>= 3.3.0.2) rainbow (>= 2.2.2, < 4.0) - regexp_parser (>= 2.4, < 3.0) - rubocop-ast (>= 1.36.1, < 2.0) + regexp_parser (>= 2.9.3, < 3.0) + rubocop-ast (>= 1.49.0, < 2.0) ruby-progressbar (~> 1.7) unicode-display_width (>= 2.4.0, < 4.0) - rubocop-ast (1.36.2) - parser (>= 3.3.1.0) - rubocop-capybara (2.21.0) - rubocop (~> 1.41) - rubocop-discourse (3.8.6) + rubocop-ast (1.50.0) + parser (>= 3.3.7.2) + prism (~> 1.7) + rubocop-capybara (3.0.0) + lint_roller (~> 1.1) + rubocop (~> 1.81) + rubocop-discourse (3.18.0) activesupport (>= 6.1) - rubocop (>= 1.59.0) - rubocop-capybara (>= 2.0.0) - rubocop-factory_bot (>= 2.0.0) - rubocop-rails (>= 2.25.0) + lint_roller (>= 1.1.0) + rubocop-capybara (>= 2.23.0) + rubocop-discourse-base (>= 1.0.0) + rubocop-factory_bot (>= 2.27.0) + rubocop-rails (>= 2.30.3) rubocop-rspec (>= 3.0.1) - rubocop-rspec_rails (>= 2.30.0) - rubocop-factory_bot (2.26.1) - rubocop (~> 1.61) - rubocop-rails (2.27.0) + rubocop-rspec_rails (>= 2.31.0) + rubocop-discourse-base (1.0.0) + rubocop (>= 1.80.0) + rubocop-factory_bot (2.28.0) + lint_roller (~> 1.1) + rubocop (~> 1.72, >= 1.72.1) + rubocop-rails (2.36.0) activesupport (>= 4.2.0) + lint_roller (~> 1.1) rack (>= 1.1) - rubocop (>= 1.52.0, < 2.0) - rubocop-ast (>= 1.31.1, < 2.0) - rubocop-rspec (3.2.0) - rubocop (~> 1.61) - rubocop-rspec_rails (2.30.0) - rubocop (~> 1.61) - rubocop-rspec (~> 3, >= 3.0.1) + rubocop (>= 1.75.0, < 2.0) + rubocop-ast (>= 1.44.0, < 2.0) + rubocop-rspec (3.10.2) + lint_roller (~> 1.1) + regexp_parser (>= 2.0) + rubocop (~> 1.86, >= 1.86.2) + rubocop-rspec_rails (2.32.0) + lint_roller (~> 1.1) + rubocop (~> 1.72, >= 1.72.1) + rubocop-rspec (~> 3.5) ruby-progressbar (1.13.0) - securerandom (0.3.2) - syntax_tree (6.2.0) + securerandom (0.4.1) + syntax_tree (6.3.0) prettier_print (>= 1.2.0) tzinfo (2.0.6) concurrent-ruby (~> 1.0) - unicode-display_width (3.1.2) - unicode-emoji (~> 4.0, >= 4.0.4) - unicode-emoji (4.0.4) - uri (1.0.2) + unicode-display_width (3.2.0) + unicode-emoji (~> 4.1) + unicode-emoji (4.2.0) + uri (1.1.1) PLATFORMS ruby @@ -89,4 +103,4 @@ DEPENDENCIES syntax_tree BUNDLED WITH - 2.5.23 + 4.0.11 diff --git a/assets/javascripts/discourse/templates/components/admin-language-list.hbs b/assets/javascripts/discourse/components/admin-language-list.hbs similarity index 100% rename from assets/javascripts/discourse/templates/components/admin-language-list.hbs rename to assets/javascripts/discourse/components/admin-language-list.hbs diff --git a/assets/javascripts/discourse/components/admin-language-list.js b/assets/javascripts/discourse/components/admin-language-list.js index 5dc72cde..11aec805 100644 --- a/assets/javascripts/discourse/components/admin-language-list.js +++ b/assets/javascripts/discourse/components/admin-language-list.js @@ -1,19 +1,22 @@ +/* eslint-disable ember/no-classic-components, ember/require-tagless-components */ + import Component from "@ember/component"; import { set } from "@ember/object"; -import { observes } from "discourse-common/utils/decorators"; +import { classNames } from "@ember-decorators/component"; +import { observes } from "discourse/lib/decorators"; -export default Component.extend({ - classNames: "admin-language-list", - controlColumnClassNames: ["language-control"], - allContentEnabled: false, - allInterfaceEnabled: false, +@classNames("admin-language-list") +export default class AdminLanguageList extends Component { + controlColumnClassNames = ["language-control"]; + allContentEnabled = false; + allInterfaceEnabled = false; @observes("allContentEnabled") updateAllContent() { this.languages.forEach((l) => { set(l, "content_enabled", this.allContentEnabled); }); - }, + } @observes("allInterfaceEnabled") updateAllInterface() { @@ -22,5 +25,5 @@ export default Component.extend({ set(l, "interface_enabled", this.allInterfaceEnabled); } }); - }, -}); + } +} diff --git a/assets/javascripts/discourse/templates/components/admin-language.hbs b/assets/javascripts/discourse/components/admin-language.hbs similarity index 100% rename from assets/javascripts/discourse/templates/components/admin-language.hbs rename to assets/javascripts/discourse/components/admin-language.hbs diff --git a/assets/javascripts/discourse/components/admin-language.js b/assets/javascripts/discourse/components/admin-language.js index 330b36de..55fd6411 100644 --- a/assets/javascripts/discourse/components/admin-language.js +++ b/assets/javascripts/discourse/components/admin-language.js @@ -1,70 +1,79 @@ +/* eslint-disable ember/no-classic-components, ember/require-tagless-components */ + import Component from "@ember/component"; -import { deepEqual } from "discourse-common/lib/object"; -import { - default as discourseComputed, - observes, -} from "discourse-common/utils/decorators"; +import { action, computed } from "@ember/object"; +import { classNames, tagName } from "@ember-decorators/component"; +import { observes } from "discourse/lib/decorators"; +import { deepEqual } from "discourse/lib/object"; import MultilingualLanguage from "../models/multilingual-language"; -export default Component.extend({ - tagName: "tr", - classNames: "language", - +@tagName("tr") +@classNames("language") +export default class AdminLanguage extends Component { didInsertElement() { - this._super(...arguments); + super.didInsertElement(...arguments); this.currentLanguage = JSON.parse(JSON.stringify(this.language)); - }, + } @observes("language.content_enabled", "language.interface_enabled") trackUpdates() { if (deepEqual(this.currentLanguage, this.language)) { - this.updatedLanguages.removeObject(this.language); - } else { - this.updatedLanguages.addObject(this.language); + const index = this.updatedLanguages.indexOf(this.language); + if (index !== -1) { + this.updatedLanguages.splice(index, 1); + } + } else if (!this.updatedLanguages.includes(this.language)) { + this.updatedLanguages.push(this.language); } - }, + } - @discourseComputed("language.custom") - typeKey(custom) { - return `multilingual.languages.${custom ? "custom" : "base"}`; - }, + @computed("language.custom") + get typeKey() { + return `multilingual.languages.${ + this.language.custom ? "custom" : "base" + }`; + } - @discourseComputed("language.locale") - interfaceToggleDisabled(locale) { - return locale === "en"; - }, + @computed("language.locale") + get interfaceToggleDisabled() { + return this.language.locale === "en"; + } - @discourseComputed("language.content_tag_conflict") - contentDisabled(tagConflict) { + @computed( + "language.content_tag_conflict", + "siteSettings.multilingual_content_languages_enabled" + ) + get contentDisabled() { return ( - !this.siteSettings.multilingual_content_languages_enabled || tagConflict + !this.siteSettings.multilingual_content_languages_enabled || + this.language.content_tag_conflict ); - }, + } - @discourseComputed - interfaceDisabled() { + @computed("siteSettings.allow_user_locale") + get interfaceDisabled() { return !this.siteSettings.allow_user_locale; - }, + } - @discourseComputed("language.custom") - actionsDisabled(custom) { - return !custom; - }, + @computed("language.custom") + get actionsDisabled() { + return !this.language.custom; + } - @discourseComputed - contentClass() { + @computed("contentDisabled") + get contentClass() { return this.generateControlColumnClass("content"); - }, + } - @discourseComputed - interfaceClass() { + @computed("interfaceDisabled") + get interfaceClass() { return this.generateControlColumnClass("interface"); - }, + } - @discourseComputed - actionsClass() { + @computed("actionsDisabled") + get actionsClass() { return this.generateControlColumnClass("actions"); - }, + } generateControlColumnClass(type) { let columnClass = `language-control ${type}`; @@ -72,16 +81,15 @@ export default Component.extend({ columnClass += " disabled"; } return columnClass; - }, + } - actions: { - remove() { - this.set("removing", true); - let locales = [this.get("language.locale")]; - MultilingualLanguage.remove(locales).then((result) => { - this.set("removing", false); - this.removed(result); - }); - }, - }, -}); + @action + remove() { + this.set("removing", true); + const locales = [this.get("language.locale")]; + MultilingualLanguage.remove(locales).then((result) => { + this.set("removing", false); + this.removed(result); + }); + } +} diff --git a/assets/javascripts/discourse/templates/components/admin-multilingual-translations.hbs b/assets/javascripts/discourse/components/admin-multilingual-translations.hbs similarity index 100% rename from assets/javascripts/discourse/templates/components/admin-multilingual-translations.hbs rename to assets/javascripts/discourse/components/admin-multilingual-translations.hbs diff --git a/assets/javascripts/discourse/templates/components/admin-translation.hbs b/assets/javascripts/discourse/components/admin-translation.hbs similarity index 100% rename from assets/javascripts/discourse/templates/components/admin-translation.hbs rename to assets/javascripts/discourse/components/admin-translation.hbs diff --git a/assets/javascripts/discourse/templates/components/category-name-fields.hbs b/assets/javascripts/discourse/components/category-name-fields.hbs similarity index 100% rename from assets/javascripts/discourse/templates/components/category-name-fields.hbs rename to assets/javascripts/discourse/components/category-name-fields.hbs diff --git a/assets/javascripts/discourse/templates/components/content-language-discovery.hbs b/assets/javascripts/discourse/components/content-language-discovery.hbs similarity index 100% rename from assets/javascripts/discourse/templates/components/content-language-discovery.hbs rename to assets/javascripts/discourse/components/content-language-discovery.hbs diff --git a/assets/javascripts/discourse/components/content-language-discovery.js b/assets/javascripts/discourse/components/content-language-discovery.js index 896a9526..8220337c 100644 --- a/assets/javascripts/discourse/components/content-language-discovery.js +++ b/assets/javascripts/discourse/components/content-language-discovery.js @@ -1,7 +1,7 @@ import Component from "@glimmer/component"; import { set } from "@ember/object"; import { service } from "@ember/service"; -import I18n from "I18n"; +import { i18n } from "discourse-i18n"; import { isContentLanguage } from "../lib/multilingual"; import { contentLanguageParam, @@ -36,7 +36,7 @@ export default class ContentLanguageDiscovery extends Component { contentLangs.push({ icon: "plus", locale: "set_content_language", - name: I18n.t("user.content_languages.set"), + name: i18n("user.content_languages.set"), }); } } else { diff --git a/assets/javascripts/discourse/templates/components/content-tag-groups-form.hbs b/assets/javascripts/discourse/components/content-tag-groups-form.hbs similarity index 100% rename from assets/javascripts/discourse/templates/components/content-tag-groups-form.hbs rename to assets/javascripts/discourse/components/content-tag-groups-form.hbs diff --git a/assets/javascripts/discourse/components/content-tag-groups-form.js b/assets/javascripts/discourse/components/content-tag-groups-form.js index 247863c9..e68eab2f 100644 --- a/assets/javascripts/discourse/components/content-tag-groups-form.js +++ b/assets/javascripts/discourse/components/content-tag-groups-form.js @@ -1,15 +1,17 @@ +import { action } from "@ember/object"; import { service } from "@ember/service"; import TagGroupsForm from "discourse/components/tag-groups-form"; import { ajax } from "discourse/lib/ajax"; import { popupAjaxError } from "discourse/lib/ajax-error"; -import I18n from "I18n"; +import { i18n } from "discourse-i18n"; -export default TagGroupsForm.extend({ - dialog: service(), - updateContentTags() { +export default class ContentTagGroupsForm extends TagGroupsForm { + @service dialog; + + _updateContentTags() { this.set( "changingContentTags", - I18n.t("tagging.groups.content_tags.update.message") + i18n("tagging.groups.content_tags.update.message") ); ajax(`/tag_groups/${this.model.id}/content-tags`, { @@ -18,12 +20,12 @@ export default TagGroupsForm.extend({ .catch(popupAjaxError) .then(() => this.set("changingContentTags", null)) .finally(() => this.tagsChanged()); - }, + } - destroyContentTags() { + _destroyContentTags() { this.set( "changingContentTags", - I18n.t("tagging.groups.content_tags.delete.message") + i18n("tagging.groups.content_tags.delete.message") ); ajax(`/tag_groups/${this.model.id}/content-tags`, { @@ -32,18 +34,18 @@ export default TagGroupsForm.extend({ .catch(popupAjaxError) .then(() => this.set("changingContentTags", null)) .finally(() => this.tagsChanged()); - }, + } - actions: { - destroyContentTags() { - this.dialog.deleteConfirm({ - title: I18n.t("tagging.groups.content_tags.delete.confirm"), - didConfirm: () => this.destroyContentTags(), - }); - }, + @action + destroyContentTags() { + this.dialog.deleteConfirm({ + title: i18n("tagging.groups.content_tags.delete.confirm"), + didConfirm: () => this._destroyContentTags(), + }); + } - updateContentTags() { - this.updateContentTags(); - }, - }, -}); + @action + updateContentTags() { + this._updateContentTags(); + } +} diff --git a/assets/javascripts/discourse/templates/components/language-switcher-bar.hbs b/assets/javascripts/discourse/components/language-switcher-bar.hbs similarity index 100% rename from assets/javascripts/discourse/templates/components/language-switcher-bar.hbs rename to assets/javascripts/discourse/components/language-switcher-bar.hbs diff --git a/assets/javascripts/discourse/components/language-switcher-bar.js b/assets/javascripts/discourse/components/language-switcher-bar.js index df346d9d..5590f38c 100644 --- a/assets/javascripts/discourse/components/language-switcher-bar.js +++ b/assets/javascripts/discourse/components/language-switcher-bar.js @@ -1,16 +1,21 @@ +/* eslint-disable ember/no-classic-components, ember/require-tagless-components */ + import Component from "@ember/component"; -import EmberObject from "@ember/object"; -import { notEmpty } from "@ember/object/computed"; +import EmberObject, { action, computed } from "@ember/object"; import { bind } from "@ember/runloop"; -import $ from "jquery"; -import { on } from "discourse-common/utils/decorators"; -import I18n from "I18n"; +import { classNames } from "@ember-decorators/component"; +import { on } from "discourse/lib/decorators"; +import I18n from "discourse-i18n"; import { addParam, localeParam } from "../lib/multilingual-route"; -export default Component.extend({ - classNames: "language-switcher-bar", - showHidden: false, - showHiddenToggle: notEmpty("hiddenLanguages"), +@classNames("language-switcher-bar") +export default class LanguageSwitcherBar extends Component { + showHidden = false; + + @computed("hiddenLanguages.[]") + get showHiddenToggle() { + return this.hiddenLanguages?.length > 0; + } @on("init") setup() { @@ -47,42 +52,43 @@ export default Component.extend({ }); this.setProperties({ visibleLanguages, hiddenLanguages }); - }, + } availableLanguages() { return this.site.interface_languages.map((l) => { return EmberObject.create(Object.assign({}, l, { class: "language" })); }); - }, + } didInsertElement() { - this._super(...arguments); + super.didInsertElement(...arguments); this.set("clickOutsideHandler", bind(this, this.clickOutside)); - $(document).on("click", this.clickOutsideHandler); - }, + document.addEventListener("click", this.clickOutsideHandler); + } willDestroyElement() { - this._super(...arguments); - $(document).off("click", this.clickOutsideHandler); - }, + super.willDestroyElement(...arguments); + document.removeEventListener("click", this.clickOutsideHandler); + } clickOutside(e) { - const $hidden = $(".language-switcher-bar .hidden-languages"); - const $target = $(e.target); + const hidden = document.querySelector( + ".language-switcher-bar .hidden-languages" + ); - if (!$target.closest($hidden).length) { + if (!hidden?.contains(e.target)) { this.set("showHidden", false); } - }, + } - actions: { - change(locale) { - this.set("showHidden", false); - addParam(localeParam, locale, { add_cookie: true, ctx: this }); - }, + @action + change(locale) { + this.set("showHidden", false); + addParam(localeParam, locale, { add_cookie: true, ctx: this }); + } - toggleHidden() { - this.toggleProperty("showHidden"); - }, - }, -}); + @action + toggleHidden() { + this.toggleProperty("showHidden"); + } +} diff --git a/assets/javascripts/discourse/components/language-switcher-menu.gjs b/assets/javascripts/discourse/components/language-switcher-menu.gjs index 889ccc85..ee1f1c10 100644 --- a/assets/javascripts/discourse/components/language-switcher-menu.gjs +++ b/assets/javascripts/discourse/components/language-switcher-menu.gjs @@ -3,9 +3,9 @@ import { fn } from "@ember/helper"; import { on } from "@ember/modifier"; import { action } from "@ember/object"; import { service } from "@ember/service"; -import concatClass from "discourse/helpers/concat-class"; +import { eq } from "discourse/truth-helpers"; +import dConcatClass from "discourse/ui-kit/helpers/d-concat-class"; import I18n from "discourse-i18n"; -import eq from "truth-helpers/helpers/eq"; import { addParam, localeParam } from "../lib/multilingual-route"; export default class LanguageSwitcherMenu extends Component { @@ -25,9 +25,9 @@ export default class LanguageSwitcherMenu extends Component {