DEV: Convert core components to native class syntax (batch 1) (#28465)

Changes made using the ember-native-class-codemod, plus some manual tweaks
This commit is contained in:
David Taylor 2024-08-22 09:39:28 +01:00 committed by GitHub
parent 3e3c051164
commit c91dcd0447
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 216 additions and 210 deletions

View File

@ -1,15 +1,14 @@
import Component from "@ember/component";
import { computed } from "@ember/object";
import { attributeBindings } from "@ember-decorators/component";
import { getTopicFooterButtons } from "discourse/lib/register-topic-footer-button";
export default Component.extend({
elementId: "topic-footer-buttons",
@attributeBindings("role")
export default class AnonymousTopicFooterButtons extends Component {
elementId = "topic-footer-buttons";
role = "region";
attributeBindings: ["role"],
role: "region",
allButtons: getTopicFooterButtons(),
@getTopicFooterButtons() allButtons;
@computed("allButtons.[]")
get buttons() {
@ -17,5 +16,5 @@ export default Component.extend({
.filterBy("anonymousOnly", true)
.sortBy("priority")
.reverse();
},
});
}
}

View File

@ -1,13 +1,13 @@
import { observes } from "@ember-decorators/object";
import MountWidget from "discourse/components/mount-widget";
import { observes } from "discourse-common/utils/decorators";
export default MountWidget.extend({
widget: "avatar-flair",
export default class AvatarFlair extends MountWidget {
widget = "avatar-flair";
@observes("flairName", "flairUrl", "flairBgColor", "flairColor")
_rerender() {
this.queueRerender();
},
}
buildArgs() {
return {
@ -16,5 +16,5 @@ export default MountWidget.extend({
flair_bg_color: this.flairBgColor,
flair_color: this.flairColor,
};
},
});
}
}

View File

@ -1,23 +1,24 @@
import Component from "@ember/component";
import { action } from "@ember/object";
import { isBlank } from "@ember/utils";
import { tagName } from "@ember-decorators/component";
import UppyUploadMixin from "discourse/mixins/uppy-upload";
import discourseComputed from "discourse-common/utils/decorators";
import I18n from "discourse-i18n";
export default Component.extend(UppyUploadMixin, {
type: "avatar",
tagName: "span",
imageIsNotASquare: false,
@tagName("span")
export default class AvatarUploader extends Component.extend(UppyUploadMixin) {
type = "avatar";
imageIsNotASquare = false;
@discourseComputed("uploading", "uploadedAvatarId")
customAvatarUploaded() {
return !this.uploading && !isBlank(this.uploadedAvatarId);
},
}
validateUploadedFilesOptions() {
return { imagesOnly: true };
},
}
uploadDone(upload) {
this.setProperties({
@ -27,22 +28,22 @@ export default Component.extend(UppyUploadMixin, {
});
this.done();
},
}
@discourseComputed("user_id")
data(user_id) {
return { user_id };
},
}
@discourseComputed("uploading", "uploadProgress")
uploadLabel() {
return this.uploading
? `${I18n.t("uploading")} ${this.uploadProgress}%`
: I18n.t("upload");
},
}
@action
chooseImage() {
this.fileInputEl.click();
},
});
}
}

View File

@ -1,26 +1,28 @@
import Component from "@ember/component";
import { action } from "@ember/object";
import { service } from "@ember/service";
import { tagName } from "@ember-decorators/component";
import { ajax } from "discourse/lib/ajax";
import I18n from "discourse-i18n";
export default Component.extend({
dialog: service(),
tagName: "",
selectableUserBadges: null,
_selectedUserBadgeId: null,
_isSaved: false,
_isSaving: false,
@tagName("")
export default class BadgeTitle extends Component {
@service dialog;
selectableUserBadges = null;
_selectedUserBadgeId = null;
_isSaved = false;
_isSaving = false;
init() {
this._super(...arguments);
super.init(...arguments);
const badge = this._findBadgeByTitle(
this.selectableUserBadges,
this.currentUser.title
);
this.set("_selectedUserBadgeId", badge?.id || 0);
},
}
@action
saveBadgeTitle() {
@ -45,13 +47,13 @@ export default Component.extend({
}
)
.finally(() => this.set("_isSaving", false));
},
}
_findBadgeById(badges, id) {
return (badges || []).findBy("id", id);
},
}
_findBadgeByTitle(badges, title) {
return (badges || []).findBy("badge.name", title);
},
});
}
}

View File

@ -1,14 +1,13 @@
import Component from "@ember/component";
import { alias, not } from "@ember/object/computed";
import { observes } from "@ember-decorators/object";
import $ from "jquery";
import discourseComputed, {
bind,
observes,
} from "discourse-common/utils/decorators";
import discourseComputed, { bind } from "discourse-common/utils/decorators";
export default Component.extend({
loadingMore: alias("topicList.loadingMore"),
loading: not("loaded"),
export default class BasicTopicList extends Component {
@alias("topicList.loadingMore") loadingMore;
@not("loaded") loading;
@discourseComputed("topicList.loaded")
loaded() {
@ -18,30 +17,30 @@ export default Component.extend({
} else {
return true;
}
},
}
@observes("topicList.[]")
_topicListChanged() {
this._initFromTopicList(this.topicList);
},
}
_initFromTopicList(topicList) {
if (topicList !== null) {
this.set("topics", topicList.get("topics"));
this.rerender();
}
},
}
init() {
this._super(...arguments);
super.init(...arguments);
const topicList = this.topicList;
if (topicList) {
this._initFromTopicList(topicList);
}
},
}
didInsertElement() {
this._super(...arguments);
super.didInsertElement(...arguments);
this.topics.forEach((topic) => {
if (typeof topic.unread_by_group_member !== "undefined") {
@ -51,16 +50,16 @@ export default Component.extend({
);
}
});
},
}
willDestroyElement() {
this._super(...arguments);
super.willDestroyElement(...arguments);
this.messageBus.unsubscribe(
"/private-messages/unread-indicator/*",
this.onMessage
);
},
}
@bind
onMessage(data) {
@ -69,14 +68,14 @@ export default Component.extend({
).classList;
nodeClassList.toggle("read", !data.show_indicator);
},
}
@discourseComputed("topics")
showUnreadIndicator(topics) {
return topics.some(
(topic) => typeof topic.unread_by_group_member !== "undefined"
);
},
}
click(e) {
// Mobile basic-topic-list doesn't use the `topic-list-item` view so
@ -111,5 +110,5 @@ export default Component.extend({
}
return false;
}
},
});
}
}

View File

@ -2,6 +2,7 @@ import Component from "@ember/component";
import { action } from "@ember/object";
import { dependentKeyCompat } from "@ember/object/compat";
import { service } from "@ember/service";
import { classNames } from "@ember-decorators/component";
import { Promise } from "rsvp";
import BookmarkModal from "discourse/components/modal/bookmark";
import { ajax } from "discourse/lib/ajax";
@ -12,22 +13,22 @@ import {
} from "discourse/lib/click-track";
import I18n from "discourse-i18n";
export default Component.extend({
dialog: service(),
modal: service(),
classNames: ["bookmark-list-wrapper"],
@classNames("bookmark-list-wrapper")
export default class BookmarkList extends Component {
@service dialog;
@service modal;
get canDoBulkActions() {
return this.bulkSelectHelper?.selected.length;
},
}
get selected() {
return this.bulkSelectHelper?.selected;
},
}
get selectedCount() {
return this.selected?.length || 0;
},
}
@action
removeBookmark(bookmark) {
@ -57,7 +58,7 @@ export default Component.extend({
didCancel: () => resolve(false),
});
});
},
}
@action
screenExcerptForExternalLink(event) {
@ -66,7 +67,7 @@ export default Component.extend({
openLinkInNewTab(event, event.target);
}
}
},
}
@action
editBookmark(bookmark) {
@ -86,7 +87,7 @@ export default Component.extend({
},
},
});
},
}
@action
clearBookmarkReminder(bookmark) {
@ -96,18 +97,18 @@ export default Component.extend({
}).then(() => {
bookmark.set("reminder_at", null);
});
},
}
@action
togglePinBookmark(bookmark) {
bookmark.togglePin().then(this.reload);
},
}
@action
toggleBulkSelect() {
this.bulkSelectHelper?.toggleBulkSelect();
this.rerender();
},
}
@action
selectAll() {
@ -115,7 +116,7 @@ export default Component.extend({
document
.querySelectorAll("input.bulk-select:not(:checked)")
.forEach((el) => el.click());
},
}
@action
clearAll() {
@ -123,16 +124,16 @@ export default Component.extend({
document
.querySelectorAll("input.bulk-select:checked")
.forEach((el) => el.click());
},
}
@dependentKeyCompat // for the classNameBindings
get bulkSelectEnabled() {
return this.bulkSelectHelper?.bulkSelectEnabled;
},
}
_removeBookmarkFromList(bookmark) {
this.content.removeObject(bookmark);
},
}
_toggleSelection(target, bookmark, isSelectingRange) {
const selected = this.selected;
@ -161,7 +162,7 @@ export default Component.extend({
selected.removeObject(bookmark);
this.set("lastChecked", null);
}
},
}
click(e) {
const onClick = (sel, callback) => {
@ -180,5 +181,5 @@ export default Component.extend({
);
this._toggleSelection(target, bookmark, this.lastChecked && e.shiftKey);
});
},
});
}
}

View File

@ -1,14 +1,32 @@
import Component from "@ember/component";
import { filter } from "@ember/object/computed";
import { classNameBindings, tagName } from "@ember-decorators/component";
import deprecated from "discourse-common/lib/deprecated";
import discourseComputed from "discourse-common/utils/decorators";
// A breadcrumb including category drop downs
export default Component.extend({
classNameBindings: ["hidden:hidden", ":category-breadcrumb"],
tagName: "ol",
editingCategory: false,
editingCategoryTab: null,
@tagName("ol")
@classNameBindings("hidden:hidden", ":category-breadcrumb")
export default class BreadCrumbs extends Component {
editingCategory = false;
editingCategoryTab = null;
@filter("categories", function (c) {
deprecated(
"The parentCategories property of the bread-crumbs component is deprecated",
{ id: "discourse.breadcrumbs.parentCategories" }
);
if (
c.id === this.site.get("uncategorized_category_id") &&
!this.siteSettings.allow_uncategorized_topics
) {
// Don't show "uncategorized" if allow_uncategorized_topics setting is false.
return false;
}
return !c.get("parentCategory");
})
parentCategories;
@discourseComputed("category", "categories", "noSubcategories")
categoryBreadcrumbs(category, filteredCategories, noSubcategories) {
@ -35,12 +53,12 @@ export default Component.extend({
hasOptions: !parentCategory || parentCategory.has_children,
};
});
},
}
@discourseComputed("siteSettings.tagging_enabled", "editingCategory")
showTagsSection(taggingEnabled, editingCategory) {
return taggingEnabled && !editingCategory;
},
}
@discourseComputed("category")
parentCategory(category) {
@ -49,23 +67,7 @@ export default Component.extend({
{ id: "discourse.breadcrumbs.parentCategory" }
);
return category && category.parentCategory;
},
parentCategories: filter("categories", function (c) {
deprecated(
"The parentCategories property of the bread-crumbs component is deprecated",
{ id: "discourse.breadcrumbs.parentCategories" }
);
if (
c.id === this.site.get("uncategorized_category_id") &&
!this.siteSettings.allow_uncategorized_topics
) {
// Don't show "uncategorized" if allow_uncategorized_topics setting is false.
return false;
}
return !c.get("parentCategory");
}),
}
@discourseComputed("parentCategories")
parentCategoriesSorted(parentCategories) {
@ -78,12 +80,12 @@ export default Component.extend({
}
return parentCategories.sortBy("totalTopicCount").reverse();
},
}
@discourseComputed("category")
hidden(category) {
return this.site.mobileView && !category;
},
}
@discourseComputed("category", "parentCategory")
firstCategory(category, parentCategory) {
@ -92,7 +94,7 @@ export default Component.extend({
{ id: "discourse.breadcrumbs.firstCategory" }
);
return parentCategory || category;
},
}
@discourseComputed("category", "parentCategory")
secondCategory(category, parentCategory) {
@ -101,7 +103,7 @@ export default Component.extend({
{ id: "discourse.breadcrumbs.secondCategory" }
);
return parentCategory && category;
},
}
@discourseComputed("firstCategory", "hideSubcategories")
childCategories(firstCategory, hideSubcategories) {
@ -120,5 +122,5 @@ export default Component.extend({
return this.categories.filter(
(c) => c.get("parentCategory") === firstCategory
);
},
});
}
}

View File

@ -1,4 +1,5 @@
import Component from "@ember/component";
export default Component.extend({
classNames: ["categories-and-latest"],
});
import { classNames } from "@ember-decorators/component";
@classNames("categories-and-latest")
export default class CategoriesAndLatestTopics extends Component {}

View File

@ -1,4 +1,5 @@
import Component from "@ember/component";
export default Component.extend({
classNames: ["categories-and-top"],
});
import { classNames } from "@ember-decorators/component";
@classNames("categories-and-top")
export default class CategoriesAndTopTopics extends Component {}

View File

@ -1,10 +1,10 @@
import Component from "@ember/component";
import { attributeBindings, tagName } from "@ember-decorators/component";
import discourseComputed from "discourse-common/utils/decorators";
export default Component.extend({
tagName: "li",
attributeBindings: ["topic.id:data-topic-id"],
@tagName("li")
@attributeBindings("topic.id:data-topic-id")
export default class CategoriesBoxesTopic extends Component {
@discourseComputed("topic.pinned", "topic.closed", "topic.archived")
topicStatusIcon(pinned, closed, archived) {
if (pinned) {
@ -14,5 +14,5 @@ export default Component.extend({
return "lock";
}
return "far-file-alt";
},
});
}
}

View File

@ -1,19 +1,20 @@
import Component from "@ember/component";
import { isEmpty } from "@ember/utils";
import { classNameBindings, tagName } from "@ember-decorators/component";
import discourseComputed from "discourse-common/utils/decorators";
export default Component.extend({
tagName: "section",
classNameBindings: [
":category-boxes-with-topics",
"anyLogos:with-logos:no-logos",
],
lockIcon: "lock",
@tagName("section")
@classNameBindings(
":category-boxes-with-topics",
"anyLogos:with-logos:no-logos"
)
export default class CategoriesBoxesWithTopics extends Component {
lockIcon = "lock";
@discourseComputed("categories.[].uploaded_logo.url")
anyLogos() {
return this.categories.any((c) => {
return !isEmpty(c.get("uploaded_logo.url"));
});
},
});
}
}

View File

@ -1,23 +1,24 @@
import Component from "@ember/component";
import { isEmpty } from "@ember/utils";
import { classNameBindings, tagName } from "@ember-decorators/component";
import discourseComputed from "discourse-common/utils/decorators";
export default Component.extend({
tagName: "section",
classNameBindings: [
":category-boxes",
"anyLogos:with-logos:no-logos",
"hasSubcategories:with-subcategories",
],
lockIcon: "lock",
@tagName("section")
@classNameBindings(
":category-boxes",
"anyLogos:with-logos:no-logos",
"hasSubcategories:with-subcategories"
)
export default class CategoriesBoxes extends Component {
lockIcon = "lock";
@discourseComputed("categories.[].uploaded_logo.url")
anyLogos() {
return this.categories.any((c) => !isEmpty(c.get("uploaded_logo.url")));
},
}
@discourseComputed("categories.[].subcategories")
hasSubcategories() {
return this.categories.any((c) => !isEmpty(c.get("subcategories")));
},
});
}
}

View File

@ -1,10 +1,11 @@
import Component from "@ember/component";
import { action } from "@ember/object";
import { tagName } from "@ember-decorators/component";
import discourseComputed from "discourse-common/utils/decorators";
export default Component.extend({
tagName: "",
showMuted: false,
@tagName("")
export default class CategoriesOnly extends Component {
showMuted = false;
@discourseComputed("showMutedCategories", "filteredCategories.length")
mutedToggleIcon(showMutedCategories, filteredCategoriesLength) {
@ -17,12 +18,12 @@ export default Component.extend({
}
return "plus";
},
}
@discourseComputed("showMuted", "filteredCategories.length")
showMutedCategories(showMuted, filteredCategoriesLength) {
return showMuted || filteredCategoriesLength === 0;
},
}
@discourseComputed("categories", "categories.length")
filteredCategories(categories, categoriesLength) {
@ -31,7 +32,7 @@ export default Component.extend({
}
return categories.filter((cat) => !cat.isHidden);
},
}
@discourseComputed("categories", "categories.length")
mutedCategories(categories, categoriesLength) {
@ -45,11 +46,11 @@ export default Component.extend({
}
return categories.filterBy("hasMuted");
},
}
@action
toggleShowMuted(event) {
event?.preventDefault();
this.toggleProperty("showMuted");
},
});
}
}

View File

@ -1,3 +1,3 @@
import Component from "@ember/component";
// Exists so plugins can use it
export default Component.extend();
export default class CategoriesTopicList extends Component {}

View File

@ -1,3 +1,3 @@
import Component from "@ember/component";
export default Component.extend({});
export default class CategoriesWithFeaturedTopics extends Component {}

View File

@ -13,32 +13,32 @@ import discourseComputed from "discourse-common/utils/decorators";
import I18n from "discourse-i18n";
import { FORMAT } from "select-kit/components/future-date-input-selector";
export default Component.extend(bufferedProperty("invite"), {
allGroups: null,
topics: null,
export default class CreateInvite extends Component.extend(
bufferedProperty("invite")
) {
allGroups = null;
topics = null;
flashText = null;
flashClass = null;
flashLink = false;
inviteToTopic = false;
limitToEmail = false;
flashText: null,
flashClass: null,
flashLink: false,
editing: readOnly("model.editing"),
inviteToTopic: false,
limitToEmail: false,
@readOnly("model.editing") editing;
@not("isEmail") isLink;
@discourseComputed("buffered.emailOrDomain")
isEmail(emailOrDomain) {
return emailValid(emailOrDomain?.trim());
},
}
@discourseComputed("buffered.emailOrDomain")
isDomain(emailOrDomain) {
return hostnameValid(emailOrDomain?.trim());
},
isLink: not("isEmail"),
}
init() {
this._super();
super.init();
Group.findAll().then((groups) => {
this.set("allGroups", groups.filterBy("automatic", false));
@ -58,7 +58,7 @@ export default Component.extend(bufferedProperty("invite"), {
topicId: this.model.invite?.topicId,
topicTitle: this.model.invite?.topicTitle,
});
},
}
save(opts) {
const data = { ...this.buffered.buffer };
@ -129,7 +129,7 @@ export default Component.extend(bufferedProperty("invite"), {
flashLink: false,
})
);
},
}
@discourseComputed(
"currentUser.staff",
@ -138,7 +138,7 @@ export default Component.extend(bufferedProperty("invite"), {
)
maxRedemptionsAllowedLimit(staff, staffLimit, usersLimit) {
return staff ? staffLimit : usersLimit;
},
}
@discourseComputed("buffered.expires_at")
expiresAtLabel(expires_at) {
@ -151,12 +151,12 @@ export default Component.extend(bufferedProperty("invite"), {
: I18n.t("user.invited.invite.expires_in_time", {
time: moment.duration(expiresAt - moment()).humanize(),
});
},
}
@discourseComputed("currentUser.staff", "currentUser.groups")
canInviteToGroup(staff, groups) {
return staff || groups.any((g) => g.owner);
},
}
@discourseComputed("currentUser.staff")
canArriveAtTopic(staff) {
@ -164,7 +164,7 @@ export default Component.extend(bufferedProperty("invite"), {
return true;
}
return false;
},
}
@discourseComputed
timeShortcuts() {
@ -182,28 +182,28 @@ export default Component.extend(bufferedProperty("invite"), {
shortcuts.fourMonths(),
shortcuts.sixMonths(),
];
},
}
@action
copied() {
this.save({ sendEmail: false, copy: true });
},
}
@action
saveInvite(sendEmail) {
this.save({ sendEmail });
},
}
@action
searchContact() {
getNativeContact(this.capabilities, ["email"], false).then((result) => {
this.set("buffered.email", result[0].email[0]);
});
},
}
@action
onChangeTopic(topicId, topic) {
this.set("topics", [topic]);
this.set("buffered.topicId", topicId);
},
});
}
}

View File

@ -14,18 +14,21 @@ import discourseComputed, {
} from "discourse-common/utils/decorators";
import I18n from "discourse-i18n";
const ShareTopicModal = Component.extend(bufferedProperty("invite"), {
topic: readOnly("model.topic"),
post: readOnly("model.post"),
category: readOnly("model.category"),
allowInvites: readOnly("model.allowInvites"),
modal: service(),
export default class ShareTopicModal extends Component.extend(
bufferedProperty("invite")
) {
@service modal;
@readOnly("model.topic") topic;
@readOnly("model.post") post;
@readOnly("model.category") category;
@readOnly("model.allowInvites") allowInvites;
didInsertElement() {
this._showRestrictedGroupWarning();
this._selectUrl();
this._super();
},
super.didInsertElement();
}
@afterRender
_showRestrictedGroupWarning() {
@ -44,7 +47,7 @@ const ShareTopicModal = Component.extend(bufferedProperty("invite"), {
});
}
});
},
}
@afterRender
_selectUrl() {
@ -54,7 +57,7 @@ const ShareTopicModal = Component.extend(bufferedProperty("invite"), {
input.setSelectionRange(0, this.url.length);
input.focus();
}
},
}
@discourseComputed("post.shareUrl", "topic.shareUrl")
url(postUrl, topicUrl) {
@ -63,13 +66,13 @@ const ShareTopicModal = Component.extend(bufferedProperty("invite"), {
} else if (topicUrl) {
return getAbsoluteURL(topicUrl);
}
},
}
@discourseComputed("post.created_at", "post.wiki", "post.last_wiki_edit")
displayDate(createdAt, wiki, lastWikiEdit) {
const date = wiki && lastWikiEdit ? lastWikiEdit : createdAt;
return longDateNoYear(new Date(date));
},
}
@discourseComputed(
"topic.{isPrivateMessage,invisible,category.read_restricted}"
@ -82,7 +85,7 @@ const ShareTopicModal = Component.extend(bufferedProperty("invite"), {
topic?.category?.read_restricted;
return Sharing.activeSources(this.siteSettings.share_links, privateContext);
},
}
@action
share(source) {
@ -90,7 +93,7 @@ const ShareTopicModal = Component.extend(bufferedProperty("invite"), {
title: this.topic.title,
url: this.url,
});
},
}
@action
inviteUsers() {
@ -102,7 +105,7 @@ const ShareTopicModal = Component.extend(bufferedProperty("invite"), {
topicTitle: this.topic.title,
},
});
},
}
@action
replyAsNewTopic() {
@ -112,11 +115,5 @@ const ShareTopicModal = Component.extend(bufferedProperty("invite"), {
const topicController = getOwner(this).lookup("controller:topic");
topicController.actions.replyAsNewTopic.call(topicController, post);
this.closeModal();
},
});
ShareTopicModal.reopenClass({
modalClass: "share-topic-modal",
});
export default ShareTopicModal;
}
}

View File

@ -1,23 +1,23 @@
import Component from "@ember/component";
import { classNameBindings } from "@ember-decorators/component";
import discourseComputed from "discourse-common/utils/decorators";
export default Component.extend({
classNameBindings: [":user-field", "field.field_type", "customFieldClass"],
@classNameBindings(":user-field", "field.field_type", "customFieldClass")
export default class UserFieldBase extends Component {
didInsertElement() {
this._super(...arguments);
super.didInsertElement(...arguments);
let element = this.element.querySelector(
".user-field.dropdown .select-kit-header"
);
element = element || this.element.querySelector("input");
this.field.element = element;
},
}
@discourseComputed
noneLabel() {
return "user_fields.none";
},
}
@discourseComputed("field.name")
customFieldClass(fieldName) {
@ -28,5 +28,5 @@ export default Component.extend({
.toLowerCase();
return fieldName && `user-field-${fieldName}`;
}
},
});
}
}