DEV: Convert core components to native class syntax (batch 9) (#28604)

Changes made using the ember-native-class-codemod, plus some manual tweaks
This commit is contained in:
David Taylor 2024-08-28 16:25:29 +01:00 committed by GitHub
parent 2e5502c417
commit 8cc6b214dd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 377 additions and 331 deletions

View File

@ -1,38 +1,40 @@
import Component from "@ember/component"; import Component from "@ember/component";
import { alias } from "@ember/object/computed"; import { alias } from "@ember/object/computed";
import { tagName } from "@ember-decorators/component";
import UppyUploadMixin from "discourse/mixins/uppy-upload"; import UppyUploadMixin from "discourse/mixins/uppy-upload";
import discourseComputed from "discourse-common/utils/decorators"; import discourseComputed from "discourse-common/utils/decorators";
import I18n from "discourse-i18n"; import I18n from "discourse-i18n";
export default Component.extend(UppyUploadMixin, { @tagName("span")
id: "uppy-backup-uploader", export default class UppyBackupUploader extends Component.extend(
tagName: "span", UppyUploadMixin
type: "backup", ) {
id = "uppy-backup-uploader";
type = "backup";
uploadRootPath = "/admin/backups";
uploadUrl = "/admin/backups/upload";
uploadRootPath: "/admin/backups", // local backups
uploadUrl: "/admin/backups/upload", @alias("localBackupStorage") useChunkedUploads;
// direct s3 backups // direct s3 backups
@discourseComputed("localBackupStorage") @discourseComputed("localBackupStorage")
useMultipartUploadsIfAvailable(localBackupStorage) { useMultipartUploadsIfAvailable(localBackupStorage) {
return !localBackupStorage && this.siteSettings.enable_direct_s3_uploads; return !localBackupStorage && this.siteSettings.enable_direct_s3_uploads;
}, }
// local backups
useChunkedUploads: alias("localBackupStorage"),
@discourseComputed("uploading", "uploadProgress") @discourseComputed("uploading", "uploadProgress")
uploadButtonText(uploading, progress) { uploadButtonText(uploading, progress) {
return uploading return uploading
? I18n.t("admin.backups.upload.uploading_progress", { progress }) ? I18n.t("admin.backups.upload.uploading_progress", { progress })
: I18n.t("admin.backups.upload.label"); : I18n.t("admin.backups.upload.label");
}, }
validateUploadedFilesOptions() { validateUploadedFilesOptions() {
return { skipValidation: true }; return { skipValidation: true };
}, }
uploadDone(responseData) { uploadDone(responseData) {
this.done(responseData.file_name); this.done(responseData.file_name);
}, }
}); }

View File

@ -4,6 +4,8 @@ import { or } from "@ember/object/computed";
import { next } from "@ember/runloop"; import { next } from "@ember/runloop";
import { htmlSafe } from "@ember/template"; import { htmlSafe } from "@ember/template";
import { isEmpty } from "@ember/utils"; import { isEmpty } from "@ember/utils";
import { classNames } from "@ember-decorators/component";
import { on } from "@ember-decorators/object";
import $ from "jquery"; import $ from "jquery";
import lightbox, { import lightbox, {
cleanupLightboxes, cleanupLightboxes,
@ -12,24 +14,26 @@ import lightbox, {
import { authorizesOneOrMoreExtensions } from "discourse/lib/uploads"; import { authorizesOneOrMoreExtensions } from "discourse/lib/uploads";
import UppyUploadMixin from "discourse/mixins/uppy-upload"; import UppyUploadMixin from "discourse/mixins/uppy-upload";
import { getURLWithCDN } from "discourse-common/lib/get-url"; import { getURLWithCDN } from "discourse-common/lib/get-url";
import discourseComputed, { on } from "discourse-common/utils/decorators"; import discourseComputed from "discourse-common/utils/decorators";
import I18n from "discourse-i18n"; import I18n from "discourse-i18n";
export default Component.extend(UppyUploadMixin, { @classNames("image-uploader")
classNames: ["image-uploader"], export default class UppyImageUploader extends Component.extend(
disabled: or("notAllowed", "uploading", "processing"), UppyUploadMixin
) {
@or("notAllowed", "uploading", "processing") disabled;
@discourseComputed("siteSettings.enable_experimental_lightbox") @discourseComputed("siteSettings.enable_experimental_lightbox")
experimentalLightboxEnabled(experimentalLightboxEnabled) { experimentalLightboxEnabled(experimentalLightboxEnabled) {
return experimentalLightboxEnabled; return experimentalLightboxEnabled;
}, }
@discourseComputed("disabled", "notAllowed") @discourseComputed("disabled", "notAllowed")
disabledReason(disabled, notAllowed) { disabledReason(disabled, notAllowed) {
if (disabled && notAllowed) { if (disabled && notAllowed) {
return I18n.t("post.errors.no_uploads_authorized"); return I18n.t("post.errors.no_uploads_authorized");
} }
}, }
@discourseComputed( @discourseComputed(
"currentUser.staff", "currentUser.staff",
@ -40,12 +44,12 @@ export default Component.extend(UppyUploadMixin, {
this.currentUser?.staff, this.currentUser?.staff,
this.siteSettings this.siteSettings
); );
}, }
@discourseComputed("imageUrl", "placeholderUrl") @discourseComputed("imageUrl", "placeholderUrl")
showingPlaceholder(imageUrl, placeholderUrl) { showingPlaceholder(imageUrl, placeholderUrl) {
return !imageUrl && placeholderUrl; return !imageUrl && placeholderUrl;
}, }
@discourseComputed("placeholderUrl") @discourseComputed("placeholderUrl")
placeholderStyle(url) { placeholderStyle(url) {
@ -53,7 +57,7 @@ export default Component.extend(UppyUploadMixin, {
return htmlSafe(""); return htmlSafe("");
} }
return htmlSafe(`background-image: url(${url})`); return htmlSafe(`background-image: url(${url})`);
}, }
@discourseComputed("imageUrl") @discourseComputed("imageUrl")
imageCDNURL(url) { imageCDNURL(url) {
@ -62,12 +66,12 @@ export default Component.extend(UppyUploadMixin, {
} }
return getURLWithCDN(url); return getURLWithCDN(url);
}, }
@discourseComputed("imageCDNURL") @discourseComputed("imageCDNURL")
backgroundStyle(url) { backgroundStyle(url) {
return htmlSafe(`background-image: url(${url})`); return htmlSafe(`background-image: url(${url})`);
}, }
@discourseComputed("imageUrl") @discourseComputed("imageUrl")
imageBaseName(imageUrl) { imageBaseName(imageUrl) {
@ -75,17 +79,17 @@ export default Component.extend(UppyUploadMixin, {
return; return;
} }
return imageUrl.split("/").slice(-1)[0]; return imageUrl.split("/").slice(-1)[0];
}, }
validateUploadedFilesOptions() { validateUploadedFilesOptions() {
return { imagesOnly: true }; return { imagesOnly: true };
}, }
_uppyReady() { _uppyReady() {
this._onPreProcessComplete(() => { this._onPreProcessComplete(() => {
this.set("processing", false); this.set("processing", false);
}); });
}, }
uploadDone(upload) { uploadDone(upload) {
this.setProperties({ this.setProperties({
@ -103,7 +107,7 @@ export default Component.extend(UppyUploadMixin, {
} else { } else {
this.set("imageUrl", upload.url); this.set("imageUrl", upload.url);
} }
}, }
@on("didRender") @on("didRender")
_applyLightbox() { _applyLightbox() {
@ -115,7 +119,7 @@ export default Component.extend(UppyUploadMixin, {
} else { } else {
next(() => lightbox(this.element, this.siteSettings)); next(() => lightbox(this.element, this.siteSettings));
} }
}, }
@on("willDestroyElement") @on("willDestroyElement")
_closeOnRemoval() { _closeOnRemoval() {
@ -126,26 +130,25 @@ export default Component.extend(UppyUploadMixin, {
$.magnificPopup.instance.close(); $.magnificPopup.instance.close();
} }
} }
}, }
@action @action
toggleLightbox() { toggleLightbox() {
$(this.element.querySelector("a.lightbox"))?.magnificPopup("open"); $(this.element.querySelector("a.lightbox"))?.magnificPopup("open");
}, }
actions: { @action
trash() { trash() {
// uppy needs to be reset to allow for more uploads // uppy needs to be reset to allow for more uploads
this._reset(); this._reset();
// the value of the property used for imageUrl should be cleared // the value of the property used for imageUrl should be cleared
// in this callback. this should be done in cases where imageUrl // in this callback. this should be done in cases where imageUrl
// is bound to a computed property of the parent component. // is bound to a computed property of the parent component.
if (this.onUploadDeleted) { if (this.onUploadDeleted) {
this.onUploadDeleted(); this.onUploadDeleted();
} else { } else {
this.setProperties({ imageUrl: null }); this.setProperties({ imageUrl: null });
} }
}, }
}, }
});

View File

@ -1,10 +1,10 @@
import Component from "@ember/component"; import Component from "@ember/component";
import { tagName } from "@ember-decorators/component";
import autoGroupFlairForUser from "discourse/lib/avatar-flair"; import autoGroupFlairForUser from "discourse/lib/avatar-flair";
import discourseComputed from "discourse-common/utils/decorators"; import discourseComputed from "discourse-common/utils/decorators";
export default Component.extend({ @tagName("")
tagName: "", export default class UserAvatarFlair extends Component {
@discourseComputed("user") @discourseComputed("user")
flair(user) { flair(user) {
if (!user || !user.flair_group_id) { if (!user || !user.flair_group_id) {
@ -29,5 +29,5 @@ export default Component.extend({
flairColor: autoFlairAttrs.flair_color, flairColor: autoFlairAttrs.flair_color,
}; };
} }
}, }
}); }

View File

@ -143,7 +143,7 @@
{{#if this.showFilter}} {{#if this.showFilter}}
<li> <li>
<DButton <DButton
@action={{fn (action "filterPosts") this.user}} @action={{fn this.handleFilterPosts this.user}}
@icon="filter" @icon="filter"
@translatedLabel={{this.filterPostsLabel}} @translatedLabel={{this.filterPostsLabel}}
class="btn-default" class="btn-default"

View File

@ -1,9 +1,15 @@
import Component from "@ember/component"; import Component from "@ember/component";
import EmberObject, { action, set } from "@ember/object"; import EmberObject, { action, computed, set } from "@ember/object";
import { alias, and, gt, gte, not, or } from "@ember/object/computed"; import { alias, and, gt, gte, not, or } from "@ember/object/computed";
import { dasherize } from "@ember/string"; import { dasherize } from "@ember/string";
import { isEmpty } from "@ember/utils"; import { isEmpty } from "@ember/utils";
import { propertyNotEqual, setting } from "discourse/lib/computed"; import {
attributeBindings,
classNameBindings,
classNames,
} from "@ember-decorators/component";
import { observes } from "@ember-decorators/object";
import { setting } from "discourse/lib/computed";
import { durationTiny } from "discourse/lib/formatter"; import { durationTiny } from "discourse/lib/formatter";
import { wantsNewWindow } from "discourse/lib/intercept-click"; import { wantsNewWindow } from "discourse/lib/intercept-click";
import { prioritizeNameInUx } from "discourse/lib/settings"; import { prioritizeNameInUx } from "discourse/lib/settings";
@ -14,85 +20,97 @@ import CardContentsBase from "discourse/mixins/card-contents-base";
import CleansUp from "discourse/mixins/cleans-up"; import CleansUp from "discourse/mixins/cleans-up";
import User from "discourse/models/user"; import User from "discourse/models/user";
import { getURLWithCDN } from "discourse-common/lib/get-url"; import { getURLWithCDN } from "discourse-common/lib/get-url";
import discourseComputed, { observes } from "discourse-common/utils/decorators"; import discourseComputed from "discourse-common/utils/decorators";
import I18n from "discourse-i18n"; import I18n from "discourse-i18n";
export default Component.extend(CardContentsBase, CanCheckEmails, CleansUp, { @classNames("user-card")
elementId: "user-card", @classNameBindings(
classNames: "user-card", "visible:show",
avatarSelector: "[data-user-card]", "showBadges",
avatarDataAttrKey: "userCard", "user.card_background_upload_url::no-bg",
mentionSelector: "a.mention", "isFixed:fixed",
classNameBindings: [ "usernameClass",
"visible:show", "primaryGroup"
"showBadges", )
"user.card_background_upload_url::no-bg", @attributeBindings("labelledBy:aria-labelledby")
"isFixed:fixed", export default class UserCardContents extends Component.extend(
"usernameClass", CardContentsBase,
"primaryGroup", CanCheckEmails,
], CleansUp
attributeBindings: ["labelledBy:aria-labelledby"], ) {
allowBackgrounds: setting("allow_profile_backgrounds"), elementId = "user-card";
showBadges: setting("enable_badges"), avatarSelector = "[data-user-card]";
avatarDataAttrKey = "userCard";
mentionSelector = "a.mention";
postStream: alias("topic.postStream"), @setting("allow_profile_backgrounds") allowBackgrounds;
enoughPostsForFiltering: gte("topicPostCount", 2), @setting("enable_badges") showBadges;
showFilter: and( @setting("display_local_time_in_user_card") showUserLocalTime;
"viewingTopic",
"postStream.hasNoFilters", @alias("topic.postStream") postStream;
"enoughPostsForFiltering"
), @gte("topicPostCount", 2) enoughPostsForFiltering;
showName: propertyNotEqual("user.name", "user.username"),
hasUserFilters: gt("postStream.userFilters.length", 0), @and("viewingTopic", "postStream.hasNoFilters", "enoughPostsForFiltering")
showMoreBadges: gt("moreBadgesCount", 0), showFilter;
showDelete: and("viewingAdmin", "showName", "user.canBeDeleted"),
linkWebsite: not("user.isBasic"), @gt("postStream.userFilters.length", 0) hasUserFilters;
@gt("moreBadgesCount", 0) showMoreBadges;
@and("viewingAdmin", "showName", "user.canBeDeleted") showDelete;
@not("user.isBasic") linkWebsite;
@or("user.suspend_reason", "user.bio_excerpt") isSuspendedOrHasBio;
@and("user.staged", "canCheckEmails") showCheckEmail;
user = null;
// If inside a topic
topicPostCount = null;
@and(
"user.featured_topic",
"siteSettings.allow_featured_topic_on_user_profiles"
)
showFeaturedTopic;
@computed("user.name", "user.username")
get showName() {
return this.user.name !== this.user.username;
}
@discourseComputed("user") @discourseComputed("user")
labelledBy(user) { labelledBy(user) {
return user ? "discourse-user-card-title" : null; return user ? "discourse-user-card-title" : null;
}, }
@discourseComputed("user") @discourseComputed("user")
hasLocaleOrWebsite(user) { hasLocaleOrWebsite(user) {
return user.location || user.website_name || this.userTimezone; return user.location || user.website_name || this.userTimezone;
}, }
@discourseComputed("user.status") @discourseComputed("user.status")
hasStatus() { hasStatus() {
return this.siteSettings.enable_user_status && this.user.status; return this.siteSettings.enable_user_status && this.user.status;
}, }
@discourseComputed("user.status.emoji") @discourseComputed("user.status.emoji")
userStatusEmoji(emoji) { userStatusEmoji(emoji) {
return emojiUnescape(escapeExpression(`:${emoji}:`)); return emojiUnescape(escapeExpression(`:${emoji}:`));
}, }
isSuspendedOrHasBio: or("user.suspend_reason", "user.bio_excerpt"),
showCheckEmail: and("user.staged", "canCheckEmails"),
user: null,
// If inside a topic
topicPostCount: null,
showFeaturedTopic: and(
"user.featured_topic",
"siteSettings.allow_featured_topic_on_user_profiles"
),
showUserLocalTime: setting("display_local_time_in_user_card"),
@discourseComputed("user.staff") @discourseComputed("user.staff")
staff: (isStaff) => (isStaff ? "staff" : ""), staff(isStaff) {
return isStaff ? "staff" : "";
}
@discourseComputed("user.trust_level") @discourseComputed("user.trust_level")
newUser: (trustLevel) => (trustLevel === 0 ? "new-user" : ""), newUser(trustLevel) {
return trustLevel === 0 ? "new-user" : "";
}
@discourseComputed("user.name") @discourseComputed("user.name")
nameFirst(name) { nameFirst(name) {
return prioritizeNameInUx(name); return prioritizeNameInUx(name);
}, }
@discourseComputed("user") @discourseComputed("user")
userTimezone(user) { userTimezone(user) {
@ -100,20 +118,22 @@ export default Component.extend(CardContentsBase, CanCheckEmails, CleansUp, {
return; return;
} }
return user.get("user_option.timezone"); return user.get("user_option.timezone");
}, }
@discourseComputed("userTimezone") @discourseComputed("userTimezone")
formattedUserLocalTime(timezone) { formattedUserLocalTime(timezone) {
return moment.tz(timezone).format(I18n.t("dates.time")); return moment.tz(timezone).format(I18n.t("dates.time"));
}, }
@discourseComputed("username") @discourseComputed("username")
usernameClass: (username) => (username ? `user-card-${username}` : ""), usernameClass(username) {
return username ? `user-card-${username}` : "";
}
@discourseComputed("username", "topicPostCount") @discourseComputed("username", "topicPostCount")
filterPostsLabel(username, count) { filterPostsLabel(username, count) {
return I18n.t("topic.filter_to", { username, count }); return I18n.t("topic.filter_to", { username, count });
}, }
@discourseComputed("user.user_fields.@each.value") @discourseComputed("user.user_fields.@each.value")
publicUserFields() { publicUserFields() {
@ -130,25 +150,27 @@ export default Component.extend(CardContentsBase, CanCheckEmails, CleansUp, {
}) })
.compact(); .compact();
} }
}, }
@discourseComputed("user.trust_level") @discourseComputed("user.trust_level")
removeNoFollow(trustLevel) { removeNoFollow(trustLevel) {
return trustLevel > 2 && !this.siteSettings.tl3_links_no_follow; return trustLevel > 2 && !this.siteSettings.tl3_links_no_follow;
}, }
@discourseComputed("user.badge_count", "user.featured_user_badges.length") @discourseComputed("user.badge_count", "user.featured_user_badges.length")
moreBadgesCount: (badgeCount, badgeLength) => badgeCount - badgeLength, moreBadgesCount(badgeCount, badgeLength) {
return badgeCount - badgeLength;
}
@discourseComputed("user.time_read", "user.recent_time_read") @discourseComputed("user.time_read", "user.recent_time_read")
showRecentTimeRead(timeRead, recentTimeRead) { showRecentTimeRead(timeRead, recentTimeRead) {
return timeRead !== recentTimeRead && recentTimeRead !== 0; return timeRead !== recentTimeRead && recentTimeRead !== 0;
}, }
@discourseComputed("user.recent_time_read") @discourseComputed("user.recent_time_read")
recentTimeRead(recentTimeReadSeconds) { recentTimeRead(recentTimeReadSeconds) {
return durationTiny(recentTimeReadSeconds); return durationTiny(recentTimeReadSeconds);
}, }
@discourseComputed("showRecentTimeRead", "user.time_read", "recentTimeRead") @discourseComputed("showRecentTimeRead", "user.time_read", "recentTimeRead")
timeReadTooltip(showRecent, timeRead, recentTimeRead) { timeReadTooltip(showRecent, timeRead, recentTimeRead) {
@ -162,7 +184,7 @@ export default Component.extend(CardContentsBase, CanCheckEmails, CleansUp, {
time_read: durationTiny(timeRead), time_read: durationTiny(timeRead),
}); });
} }
}, }
@observes("user.card_background_upload_url") @observes("user.card_background_upload_url")
addBackground() { addBackground() {
@ -177,17 +199,17 @@ export default Component.extend(CardContentsBase, CanCheckEmails, CleansUp, {
const url = this.get("user.card_background_upload_url"); const url = this.get("user.card_background_upload_url");
const bg = isEmpty(url) ? "" : `url(${getURLWithCDN(url)})`; const bg = isEmpty(url) ? "" : `url(${getURLWithCDN(url)})`;
this.element.style.backgroundImage = bg; this.element.style.backgroundImage = bg;
}, }
@discourseComputed("user.primary_group_name") @discourseComputed("user.primary_group_name")
primaryGroup(primaryGroup) { primaryGroup(primaryGroup) {
return `group-${primaryGroup}`; return `group-${primaryGroup}`;
}, }
@discourseComputed("user.profile_hidden", "user.inactive") @discourseComputed("user.profile_hidden", "user.inactive")
contentHidden(profileHidden, inactive) { contentHidden(profileHidden, inactive) {
return profileHidden || inactive; return profileHidden || inactive;
}, }
async _showCallback(username) { async _showCallback(username) {
this.setProperties({ visible: true, loading: true }); this.setProperties({ visible: true, loading: true });
@ -215,7 +237,7 @@ export default Component.extend(CardContentsBase, CanCheckEmails, CleansUp, {
} finally { } finally {
this.set("loading", null); this.set("loading", null);
} }
}, }
_close() { _close() {
this.user?.statusManager.stopTrackingStatus(); this.user?.statusManager.stopTrackingStatus();
@ -225,12 +247,12 @@ export default Component.extend(CardContentsBase, CanCheckEmails, CleansUp, {
topicPostCount: null, topicPostCount: null,
}); });
this._super(...arguments); super._close(...arguments);
}, }
cleanUp() { cleanUp() {
this._close(); this._close();
}, }
@action @action
handleShowUser(event) { handleShowUser(event) {
@ -243,36 +265,40 @@ export default Component.extend(CardContentsBase, CanCheckEmails, CleansUp, {
// refactoring this to a glimmer component. // refactoring this to a glimmer component.
this.showUser(this.user); this.showUser(this.user);
this._close(); this._close();
}, }
actions: { @action
close() { close() {
this._close(); this._close();
}, }
composePM(user, post) { @action
this._close(); composePM(user, post) {
this.composePrivateMessage(user, post); this._close();
}, this.composePrivateMessage(user, post);
}
cancelFilter() { @action
this.postStream.cancelFilter(); cancelFilter() {
this.postStream.refresh(); this.postStream.cancelFilter();
this._close(); this.postStream.refresh();
}, this._close();
}
filterPosts() { @action
this.filterPosts(this.user); handleFilterPosts() {
this._close(); this.filterPosts(this.user);
}, this._close();
}
deleteUser() { @action
this.user.delete(); deleteUser() {
this._close(); this.user.delete();
}, this._close();
}
checkEmail(user) { @action
user.checkEmail(); checkEmail(user) {
}, user.checkEmail();
}, }
}); }

View File

@ -1,14 +1,14 @@
import Component from "@ember/component"; import Component from "@ember/component";
import { tagName } from "@ember-decorators/component";
import discourseComputed from "discourse-common/utils/decorators"; import discourseComputed from "discourse-common/utils/decorators";
import I18n from "discourse-i18n"; import I18n from "discourse-i18n";
export default Component.extend({ @tagName("")
tagName: "", export default class UserFlagPercentage extends Component {
@discourseComputed("percentage") @discourseComputed("percentage")
showPercentage(percentage) { showPercentage(percentage) {
return percentage.total >= 3; return percentage.total >= 3;
}, }
// We do a little logic to choose which icon to display and which text // We do a little logic to choose which icon to display and which text
@discourseComputed("agreed", "disagreed", "ignored") @discourseComputed("agreed", "disagreed", "ignored")
@ -51,5 +51,5 @@ export default Component.extend({
}); });
return result; return result;
}, }
}); }

View File

@ -1,34 +1,39 @@
import Component from "@ember/component"; import Component from "@ember/component";
import { alias } from "@ember/object/computed"; import { alias } from "@ember/object/computed";
import {
attributeBindings,
classNameBindings,
} from "@ember-decorators/component";
import { prioritizeNameInUx } from "discourse/lib/settings"; import { prioritizeNameInUx } from "discourse/lib/settings";
import { userPath } from "discourse/lib/url"; import { userPath } from "discourse/lib/url";
import discourseComputed from "discourse-common/utils/decorators"; import discourseComputed from "discourse-common/utils/decorators";
export default Component.extend({ @classNameBindings(":user-info", "size")
classNameBindings: [":user-info", "size"], @attributeBindings("dataUsername:data-username")
attributeBindings: ["data-username"], export default class UserInfo extends Component {
size: "small", size = "small";
"data-username": alias("user.username"), includeLink = true;
includeLink: true, includeAvatar = true;
includeAvatar: true,
@alias("user.username") dataUsername;
didInsertElement() { didInsertElement() {
this._super(...arguments); super.didInsertElement(...arguments);
this.user?.statusManager?.trackStatus(); this.user?.statusManager?.trackStatus();
}, }
willDestroyElement() { willDestroyElement() {
this._super(...arguments); super.willDestroyElement(...arguments);
this.user?.statusManager?.stopTrackingStatus(); this.user?.statusManager?.stopTrackingStatus();
}, }
@discourseComputed("user.username") @discourseComputed("user.username")
userPath(username) { userPath(username) {
return userPath(username); return userPath(username);
}, }
@discourseComputed("user.name") @discourseComputed("user.name")
nameFirst(name) { nameFirst(name) {
return prioritizeNameInUx(name); return prioritizeNameInUx(name);
}, }
}); }

View File

@ -1,8 +1,10 @@
import Component from "@ember/component"; import Component from "@ember/component";
import { alias } from "@ember/object/computed"; import { alias } from "@ember/object/computed";
export default Component.extend({ import { attributeBindings, tagName } from "@ember-decorators/component";
tagName: "a",
attributeBindings: ["href", "data-user-card"], @tagName("a")
href: alias("user.path"), @attributeBindings("href", "dataUserCard:data-user-card")
"data-user-card": alias("user.username"), export default class UserLink extends Component {
}); @alias("user.path") href;
@alias("user.username") dataUserCard;
}

View File

@ -1,7 +1,8 @@
import Component from "@ember/component"; import Component from "@ember/component";
import { tagName } from "@ember-decorators/component";
import { i18n } from "discourse/lib/computed"; import { i18n } from "discourse/lib/computed";
export default Component.extend({ @tagName("")
tagName: "", export default class UserNotificationScheduleDay extends Component {
dayLabel: i18n("day", "user.notification_schedule.%@"), @i18n("day", "user.notification_schedule.%@") dayLabel;
}); }

View File

@ -13,41 +13,41 @@ const DAYS = [
"sunday", "sunday",
]; ];
const Day = EmberObject.extend({ class Day extends EmberObject {
id: null, id = null;
startTimeOptions: null, startTimeOptions = null;
model: null, model = null;
@action @action
onChangeStartTime(val) { onChangeStartTime(val) {
this.startingTimeChangedForDay(val); this.startingTimeChangedForDay(val);
}, }
@action @action
onChangeEndTime(val) { onChangeEndTime(val) {
this.set(`model.user_notification_schedule.day_${this.id}_end_time`, val); this.set(`model.user_notification_schedule.day_${this.id}_end_time`, val);
}, }
@discourseComputed( @discourseComputed(
"model.user_notification_schedule.day_{0,1,2,3,4,5,6}_start_time" "model.user_notification_schedule.day_{0,1,2,3,4,5,6}_start_time"
) )
startTimeValue(schedule) { startTimeValue(schedule) {
return schedule[`day_${this.id}_start_time`]; return schedule[`day_${this.id}_start_time`];
}, }
@discourseComputed( @discourseComputed(
"model.user_notification_schedule.day_{0,1,2,3,4,5,6}_start_time" "model.user_notification_schedule.day_{0,1,2,3,4,5,6}_start_time"
) )
endTimeOptions(schedule) { endTimeOptions(schedule) {
return this.buildEndTimeOptionsFor(schedule[`day_${this.id}_start_time`]); return this.buildEndTimeOptionsFor(schedule[`day_${this.id}_start_time`]);
}, }
@discourseComputed( @discourseComputed(
"model.user_notification_schedule.day_{0,1,2,3,4,5,6}_end_time" "model.user_notification_schedule.day_{0,1,2,3,4,5,6}_end_time"
) )
endTimeValue(schedule) { endTimeValue(schedule) {
return schedule[`day_${this.id}_end_time`]; return schedule[`day_${this.id}_end_time`];
}, }
startingTimeChangedForDay(val) { startingTimeChangedForDay(val) {
val = parseInt(val, 10); val = parseInt(val, 10);
@ -61,7 +61,7 @@ const Day = EmberObject.extend({
val + 30 val + 30
); );
} }
}, }
buildEndTimeOptionsFor(startTime) { buildEndTimeOptionsFor(startTime) {
startTime = parseInt(startTime, 10); startTime = parseInt(startTime, 10);
@ -72,14 +72,14 @@ const Day = EmberObject.extend({
includeNone: false, includeNone: false,
showMidnight: true, showMidnight: true,
}); });
}, }
}); }
export default Component.extend({ export default class UserNotificationSchedule extends Component {
days: null, days = null;
didInsertElement() { didInsertElement() {
this._super(...arguments); super.didInsertElement(...arguments);
this.set( this.set(
"startTimeOptions", "startTimeOptions",
this.buildTimeOptions(0, { this.buildTimeOptions(0, {
@ -101,7 +101,7 @@ export default Component.extend({
}) })
); );
}); });
}, }
buildTimeOptions(startAt, opts = { includeNone: false, showMidnight: true }) { buildTimeOptions(startAt, opts = { includeNone: false, showMidnight: true }) {
let timeOptions = []; let timeOptions = [];
@ -135,5 +135,5 @@ export default Component.extend({
}); });
} }
return timeOptions; return timeOptions;
}, }
}); }

View File

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

View File

@ -1,39 +1,40 @@
import Component from "@ember/component"; import Component from "@ember/component";
import { computed } from "@ember/object"; import { computed } from "@ember/object";
import { classNameBindings, tagName } from "@ember-decorators/component";
import { propertyEqual } from "discourse/lib/computed"; import { propertyEqual } from "discourse/lib/computed";
import { userPath } from "discourse/lib/url"; import { userPath } from "discourse/lib/url";
import { actionDescription } from "discourse/widgets/post-small-action"; import { actionDescription } from "discourse/widgets/post-small-action";
import discourseComputed from "discourse-common/utils/decorators"; import discourseComputed from "discourse-common/utils/decorators";
export default Component.extend({ @tagName("li")
tagName: "li", @classNameBindings(
":user-stream-item",
":item", // DEPRECATED: 'item' class
"hidden",
"item.deleted:deleted",
"moderatorAction"
)
export default class UserStreamItem extends Component {
@propertyEqual("item.post_type", "site.post_types.moderator_action")
moderatorAction;
classNameBindings: [ @actionDescription(
":user-stream-item",
":item", // DEPRECATED: 'item' class
"hidden",
"item.deleted:deleted",
"moderatorAction",
],
hidden: computed("item.hidden", function () {
return (
this.get("item.hidden") && !(this.currentUser && this.currentUser.staff)
);
}),
moderatorAction: propertyEqual(
"item.post_type",
"site.post_types.moderator_action"
),
actionDescription: actionDescription(
"item.action_code", "item.action_code",
"item.created_at", "item.created_at",
"item.action_code_who", "item.action_code_who",
"item.action_code_path" "item.action_code_path"
), )
actionDescription;
@computed("item.hidden")
get hidden() {
return (
this.get("item.hidden") && !(this.currentUser && this.currentUser.staff)
);
}
@discourseComputed("item.draft_username", "item.username") @discourseComputed("item.draft_username", "item.username")
userUrl(draftUsername, username) { userUrl(draftUsername, username) {
return userPath((draftUsername || username).toLowerCase()); return userPath((draftUsername || username).toLowerCase());
}, }
}); }

View File

@ -1,8 +1,10 @@
import Component from "@ember/component"; import Component from "@ember/component";
import { on } from "@ember/object/evented"; import { action } from "@ember/object";
import { getOwner } from "@ember/owner"; import { getOwner } from "@ember/owner";
import { later } from "@ember/runloop"; import { later } from "@ember/runloop";
import { service } from "@ember/service"; import { service } from "@ember/service";
import { classNames, tagName } from "@ember-decorators/component";
import { on } from "@ember-decorators/object";
import $ from "jquery"; import $ from "jquery";
import { popupAjaxError } from "discourse/lib/ajax-error"; import { popupAjaxError } from "discourse/lib/ajax-error";
import ClickTrack from "discourse/lib/click-track"; import ClickTrack from "discourse/lib/click-track";
@ -13,13 +15,18 @@ import Draft from "discourse/models/draft";
import Post from "discourse/models/post"; import Post from "discourse/models/post";
import I18n from "discourse-i18n"; import I18n from "discourse-i18n";
export default Component.extend(LoadMore, { @tagName("ul")
tagName: "ul", @classNames("user-stream")
dialog: service(), export default class UserStream extends Component.extend(LoadMore) {
composer: service(), @service dialog;
_lastDecoratedElement: null, @service composer;
_initialize: on("init", function () { loading = false;
eyelineSelector = ".user-stream .item";
_lastDecoratedElement = null;
@on("init")
_initialize() {
const filter = this.get("stream.filter"); const filter = this.get("stream.filter");
if (filter) { if (filter) {
this.set("classNames", [ this.set("classNames", [
@ -27,13 +34,10 @@ export default Component.extend(LoadMore, {
"filter-" + filter.toString().replace(",", "-"), "filter-" + filter.toString().replace(",", "-"),
]); ]);
} }
}), }
loading: false, @on("didInsertElement")
eyelineSelector: ".user-stream .item", _inserted() {
classNames: ["user-stream"],
_inserted: on("didInsertElement", function () {
$(this.element).on( $(this.element).on(
"click.details-disabled", "click.details-disabled",
"details.disabled", "details.disabled",
@ -44,15 +48,16 @@ export default Component.extend(LoadMore, {
}); });
this._updateLastDecoratedElement(); this._updateLastDecoratedElement();
this.appEvents.trigger("decorate-non-stream-cooked-element", this.element); this.appEvents.trigger("decorate-non-stream-cooked-element", this.element);
}), }
// This view is being removed. Shut down operations // This view is being removed. Shut down operations
_destroyed: on("willDestroyElement", function () { @on("willDestroyElement")
_destroyed() {
$(this.element).off("click.details-disabled", "details.disabled"); $(this.element).off("click.details-disabled", "details.disabled");
// Unbind link tracking // Unbind link tracking
$(this.element).off("click.discourse-redirect", ".excerpt a"); $(this.element).off("click.discourse-redirect", ".excerpt a");
}), }
_updateLastDecoratedElement() { _updateLastDecoratedElement() {
const nodes = this.element.querySelectorAll(".user-stream-item"); const nodes = this.element.querySelectorAll(".user-stream-item");
@ -64,89 +69,88 @@ export default Component.extend(LoadMore, {
return; return;
} }
this._lastDecoratedElement = lastElement; this._lastDecoratedElement = lastElement;
}, }
actions: { @action
removeBookmark(userAction) { removeBookmark(userAction) {
const stream = this.stream; const stream = this.stream;
Post.updateBookmark(userAction.get("post_id"), false) Post.updateBookmark(userAction.get("post_id"), false)
.then(() => { .then(() => {
stream.remove(userAction); stream.remove(userAction);
})
.catch(popupAjaxError);
}
@action
resumeDraft(item) {
if (this.composer.get("model.viewOpen")) {
this.composer.close();
}
if (item.get("postUrl")) {
DiscourseURL.routeTo(item.get("postUrl"));
} else {
Draft.get(item.draft_key)
.then((d) => {
const draft = d.draft || item.data;
if (!draft) {
return;
}
this.composer.open({
draft,
draftKey: item.draft_key,
draftSequence: d.draft_sequence,
});
}) })
.catch(popupAjaxError); .catch((error) => {
}, popupAjaxError(error);
});
}
}
resumeDraft(item) { @action
if (this.composer.get("model.viewOpen")) { removeDraft(draft) {
this.composer.close(); const stream = this.stream;
}
if (item.get("postUrl")) { this.dialog.yesNoConfirm({
DiscourseURL.routeTo(item.get("postUrl")); message: I18n.t("drafts.remove_confirmation"),
} else { didConfirm: () => {
Draft.get(item.draft_key) Draft.clear(draft.draft_key, draft.sequence)
.then((d) => { .then(() => {
const draft = d.draft || item.data; stream.remove(draft);
if (!draft) { if (draft.draft_key === NEW_TOPIC_KEY) {
return; this.currentUser.set("has_topic_draft", false);
} }
this.composer.open({
draft,
draftKey: item.draft_key,
draftSequence: d.draft_sequence,
});
}) })
.catch((error) => { .catch((error) => {
popupAjaxError(error); popupAjaxError(error);
}); });
} },
}, });
}
removeDraft(draft) { @action
const stream = this.stream; loadMore() {
if (this.loading) {
return;
}
this.dialog.yesNoConfirm({ this.set("loading", true);
message: I18n.t("drafts.remove_confirmation"), const stream = this.stream;
didConfirm: () => { stream.findItems().then(() => {
Draft.clear(draft.draft_key, draft.sequence) this.set("loading", false);
.then(() => {
stream.remove(draft); // The next elements are not rendered on the page yet, we need to
if (draft.draft_key === NEW_TOPIC_KEY) { // wait for that before trying to decorate them.
this.currentUser.set("has_topic_draft", false); later(() => {
} let element = this._lastDecoratedElement?.nextElementSibling;
}) while (element) {
.catch((error) => { this.trigger("user-stream:new-item-inserted", element);
popupAjaxError(error); this.appEvents.trigger("decorate-non-stream-cooked-element", element);
}); element = element.nextElementSibling;
}, }
this._updateLastDecoratedElement();
}); });
}, });
}
loadMore() { }
if (this.loading) {
return;
}
this.set("loading", true);
const stream = this.stream;
stream.findItems().then(() => {
this.set("loading", false);
// The next elements are not rendered on the page yet, we need to
// wait for that before trying to decorate them.
later(() => {
let element = this._lastDecoratedElement?.nextElementSibling;
while (element) {
this.trigger("user-stream:new-item-inserted", element);
this.appEvents.trigger(
"decorate-non-stream-cooked-element",
element
);
element = element.nextElementSibling;
}
this._updateLastDecoratedElement();
});
});
},
},
});

View File

@ -1,11 +1,11 @@
import Component from "@ember/component"; import Component from "@ember/component";
import { tagName } from "@ember-decorators/component";
import discourseComputed from "discourse-common/utils/decorators"; import discourseComputed from "discourse-common/utils/decorators";
export default Component.extend({ @tagName("")
tagName: "", export default class UserSummaryCategorySearch extends Component {
@discourseComputed("user", "category") @discourseComputed("user", "category")
searchParams() { searchParams() {
return `@${this.get("user.username")} #${this.get("category.slug")}`; return `@${this.get("user.username")} #${this.get("category.slug")}`;
}, }
}); }

View File

@ -1,4 +1,5 @@
import Component from "@ember/component"; import Component from "@ember/component";
export default Component.extend({ import { tagName } from "@ember-decorators/component";
tagName: "li",
}); @tagName("li")
export default class UserSummaryTopic extends Component {}

View File

@ -1,14 +1,14 @@
import Component from "@ember/component"; import Component from "@ember/component";
import { tagName } from "@ember-decorators/component";
import discourseComputed from "discourse-common/utils/decorators"; import discourseComputed from "discourse-common/utils/decorators";
// should be kept in sync with 'UserSummary::MAX_SUMMARY_RESULTS' // should be kept in sync with 'UserSummary::MAX_SUMMARY_RESULTS'
const MAX_SUMMARY_RESULTS = 6; const MAX_SUMMARY_RESULTS = 6;
export default Component.extend({ @tagName("")
tagName: "", export default class UserSummaryTopicsList extends Component {
@discourseComputed("items.length") @discourseComputed("items.length")
hasMore(length) { hasMore(length) {
return length >= MAX_SUMMARY_RESULTS; return length >= MAX_SUMMARY_RESULTS;
}, }
}); }

View File

@ -1,4 +1,5 @@
import Component from "@ember/component"; import Component from "@ember/component";
export default Component.extend({ import { tagName } from "@ember-decorators/component";
tagName: "li",
}); @tagName("li")
export default class UserSummaryUser extends Component {}

View File

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