DEV: Use component class instead of string in user-menu API (#20806)
In the future we'll be looking at things like tree-shaking and code-splitting. Using 'magic strings' to resolve components is not compatible with those techniques. It makes sense to switch to a more modern pattern now, before the new user-tab API is used too widely. This commit is backwards-compatible. API consumers which pass a string will see a deprecation message asking them to pass a component class instead. This commit also turns some unneeded getters into simple class properties (no need to use a getter when it just returns a constant).
This commit is contained in:
parent
142d2ab65e
commit
9b41700f87
|
@ -35,12 +35,11 @@
|
|||
class="quick-access-panel"
|
||||
tabindex="-1"
|
||||
>
|
||||
{{component
|
||||
this.currentPanelComponent
|
||||
closeUserMenu=@closeUserMenu
|
||||
filterByTypes=this.currentNotificationTypes
|
||||
ariaLabelledby=(concat "user-menu-button-" this.currentTabId)
|
||||
}}
|
||||
<this.currentPanelComponent
|
||||
@closeUserMenu={{@closeUserMenu}}
|
||||
@filterByTypes={{this.currentNotificationTypes}}
|
||||
@ariaLabelledby={{concat "user-menu-button-" this.currentTabId}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -6,25 +6,27 @@ import UserMenuTab, { CUSTOM_TABS_CLASSES } from "discourse/lib/user-menu/tab";
|
|||
import { inject as service } from "@ember/service";
|
||||
import getUrl from "discourse-common/lib/get-url";
|
||||
import { wantsNewWindow } from "discourse/lib/intercept-click";
|
||||
import UserMenuNotificationsList from "./notifications-list";
|
||||
import UserMenuRepliesNotificationsList from "./replies-notifications-list";
|
||||
import UserMenuLikesNotificationsList from "./likes-notifications-list";
|
||||
import UserMenuMessagesList from "./messages-list";
|
||||
import UserMenuBookmarksList from "./bookmarks-list";
|
||||
import UserMenuReviewablesList from "./reviewables-list";
|
||||
import UserMenuProfileTabContent from "./profile-tab-content";
|
||||
import UserMenuOtherNotificationsList from "./other-notifications-list";
|
||||
import deprecated from "discourse-common/lib/deprecated";
|
||||
import { getOwner } from "discourse-common/lib/get-owner";
|
||||
|
||||
const DEFAULT_TAB_ID = "all-notifications";
|
||||
const DEFAULT_PANEL_COMPONENT = "user-menu/notifications-list";
|
||||
const DEFAULT_PANEL_COMPONENT = UserMenuNotificationsList;
|
||||
|
||||
const REVIEW_QUEUE_TAB_ID = "review-queue";
|
||||
|
||||
const CORE_TOP_TABS = [
|
||||
class extends UserMenuTab {
|
||||
get id() {
|
||||
return DEFAULT_TAB_ID;
|
||||
}
|
||||
|
||||
get icon() {
|
||||
return "bell";
|
||||
}
|
||||
|
||||
get panelComponent() {
|
||||
return DEFAULT_PANEL_COMPONENT;
|
||||
}
|
||||
id = DEFAULT_TAB_ID;
|
||||
icon = "bell";
|
||||
panelComponent = DEFAULT_PANEL_COMPONENT;
|
||||
|
||||
get linkWhenActive() {
|
||||
return `${this.currentUser.path}/notifications`;
|
||||
|
@ -32,17 +34,10 @@ const CORE_TOP_TABS = [
|
|||
},
|
||||
|
||||
class extends UserMenuTab {
|
||||
get id() {
|
||||
return "replies";
|
||||
}
|
||||
|
||||
get icon() {
|
||||
return "reply";
|
||||
}
|
||||
|
||||
get panelComponent() {
|
||||
return "user-menu/replies-notifications-list";
|
||||
}
|
||||
id = "replies";
|
||||
icon = "reply";
|
||||
panelComponent = UserMenuRepliesNotificationsList;
|
||||
notificationTypes = ["mentioned", "posted", "quoted", "replied"];
|
||||
|
||||
get count() {
|
||||
return (
|
||||
|
@ -53,27 +48,15 @@ const CORE_TOP_TABS = [
|
|||
);
|
||||
}
|
||||
|
||||
get notificationTypes() {
|
||||
return ["mentioned", "posted", "quoted", "replied"];
|
||||
}
|
||||
|
||||
get linkWhenActive() {
|
||||
return `${this.currentUser.path}/notifications/responses`;
|
||||
}
|
||||
},
|
||||
|
||||
class extends UserMenuTab {
|
||||
get id() {
|
||||
return "likes";
|
||||
}
|
||||
|
||||
get icon() {
|
||||
return "heart";
|
||||
}
|
||||
|
||||
get panelComponent() {
|
||||
return "user-menu/likes-notifications-list";
|
||||
}
|
||||
id = "likes";
|
||||
icon = "heart";
|
||||
panelComponent = UserMenuLikesNotificationsList;
|
||||
|
||||
get shouldDisplay() {
|
||||
return !this.currentUser.user_option.likes_notifications_disabled;
|
||||
|
@ -96,17 +79,10 @@ const CORE_TOP_TABS = [
|
|||
},
|
||||
|
||||
class extends UserMenuTab {
|
||||
get id() {
|
||||
return "messages";
|
||||
}
|
||||
|
||||
get icon() {
|
||||
return "notification.private_message";
|
||||
}
|
||||
|
||||
get panelComponent() {
|
||||
return "user-menu/messages-list";
|
||||
}
|
||||
id = "messages";
|
||||
icon = "notification.private_message";
|
||||
panelComponent = UserMenuMessagesList;
|
||||
notificationTypes = ["private_message", "group_message_summary"];
|
||||
|
||||
get count() {
|
||||
return this.getUnreadCountForType("private_message");
|
||||
|
@ -116,53 +92,31 @@ const CORE_TOP_TABS = [
|
|||
return this.currentUser?.can_send_private_messages;
|
||||
}
|
||||
|
||||
get notificationTypes() {
|
||||
return ["private_message", "group_message_summary"];
|
||||
}
|
||||
|
||||
get linkWhenActive() {
|
||||
return `${this.currentUser.path}/messages`;
|
||||
}
|
||||
},
|
||||
|
||||
class extends UserMenuTab {
|
||||
get id() {
|
||||
return "bookmarks";
|
||||
}
|
||||
|
||||
get icon() {
|
||||
return NO_REMINDER_ICON;
|
||||
}
|
||||
|
||||
get panelComponent() {
|
||||
return "user-menu/bookmarks-list";
|
||||
}
|
||||
id = "bookmarks";
|
||||
icon = NO_REMINDER_ICON;
|
||||
panelComponent = UserMenuBookmarksList;
|
||||
notificationTypes = ["bookmark_reminder"];
|
||||
|
||||
get count() {
|
||||
return this.getUnreadCountForType("bookmark_reminder");
|
||||
}
|
||||
|
||||
get notificationTypes() {
|
||||
return ["bookmark_reminder"];
|
||||
}
|
||||
|
||||
get linkWhenActive() {
|
||||
return `${this.currentUser.path}/activity/bookmarks`;
|
||||
}
|
||||
},
|
||||
|
||||
class extends UserMenuTab {
|
||||
get id() {
|
||||
return REVIEW_QUEUE_TAB_ID;
|
||||
}
|
||||
|
||||
get icon() {
|
||||
return "flag";
|
||||
}
|
||||
|
||||
get panelComponent() {
|
||||
return "user-menu/reviewables-list";
|
||||
}
|
||||
id = REVIEW_QUEUE_TAB_ID;
|
||||
icon = "flag";
|
||||
panelComponent = UserMenuReviewablesList;
|
||||
linkWhenActive = getUrl("/review");
|
||||
|
||||
get shouldDisplay() {
|
||||
return (
|
||||
|
@ -173,26 +127,14 @@ const CORE_TOP_TABS = [
|
|||
get count() {
|
||||
return this.currentUser.get("reviewable_count");
|
||||
}
|
||||
|
||||
get linkWhenActive() {
|
||||
return getUrl("/review");
|
||||
}
|
||||
},
|
||||
];
|
||||
|
||||
const CORE_BOTTOM_TABS = [
|
||||
class extends UserMenuTab {
|
||||
get id() {
|
||||
return "profile";
|
||||
}
|
||||
|
||||
get icon() {
|
||||
return "user";
|
||||
}
|
||||
|
||||
get panelComponent() {
|
||||
return "user-menu/profile-tab-content";
|
||||
}
|
||||
id = "profile";
|
||||
icon = "user";
|
||||
panelComponent = UserMenuProfileTabContent;
|
||||
|
||||
get linkWhenActive() {
|
||||
return `${this.currentUser.path}/summary`;
|
||||
|
@ -201,23 +143,15 @@ const CORE_BOTTOM_TABS = [
|
|||
];
|
||||
|
||||
const CORE_OTHER_NOTIFICATIONS_TAB = class extends UserMenuTab {
|
||||
id = "other-notifications";
|
||||
icon = "discourse-other-tab";
|
||||
panelComponent = UserMenuOtherNotificationsList;
|
||||
|
||||
constructor(currentUser, siteSettings, site, otherNotificationTypes) {
|
||||
super(...arguments);
|
||||
this.otherNotificationTypes = otherNotificationTypes;
|
||||
}
|
||||
|
||||
get id() {
|
||||
return "other-notifications";
|
||||
}
|
||||
|
||||
get icon() {
|
||||
return "discourse-other-tab";
|
||||
}
|
||||
|
||||
get panelComponent() {
|
||||
return "user-menu/other-notifications-list";
|
||||
}
|
||||
|
||||
get count() {
|
||||
return this.otherNotificationTypes.reduce((sum, notificationType) => {
|
||||
return sum + this.getUnreadCountForType(notificationType);
|
||||
|
@ -229,6 +163,18 @@ const CORE_OTHER_NOTIFICATIONS_TAB = class extends UserMenuTab {
|
|||
}
|
||||
};
|
||||
|
||||
function resolvePanelComponent(owner, panelComponent) {
|
||||
if (typeof panelComponent === "string") {
|
||||
const nameForConsole = JSON.stringify(panelComponent);
|
||||
deprecated(
|
||||
`user-menu tab panelComponent must be passed as a component class (passed ${nameForConsole})`,
|
||||
{ id: "discourse.user-menu.panel-component-class" }
|
||||
);
|
||||
return owner.resolveRegistration(`component:${panelComponent}`);
|
||||
}
|
||||
return panelComponent;
|
||||
}
|
||||
|
||||
export default class UserMenu extends Component {
|
||||
@service currentUser;
|
||||
@service siteSettings;
|
||||
|
@ -323,7 +269,10 @@ export default class UserMenu extends Component {
|
|||
event.preventDefault();
|
||||
|
||||
this.currentTabId = tab.id;
|
||||
this.currentPanelComponent = tab.panelComponent;
|
||||
this.currentPanelComponent = resolvePanelComponent(
|
||||
getOwner(this),
|
||||
tab.panelComponent
|
||||
);
|
||||
this.currentNotificationTypes = tab.notificationTypes;
|
||||
}
|
||||
|
||||
|
|
|
@ -2056,9 +2056,9 @@ class PluginApi {
|
|||
* ```
|
||||
* api.registerUserMenuTab((UserMenuTab) => {
|
||||
* return class extends UserMenuTab {
|
||||
* get id() {
|
||||
* return "custom-tab-id";
|
||||
* }
|
||||
* id = "custom-tab-id";
|
||||
* panelComponent = MyCustomPanelGlimmerComponent;
|
||||
* icon = "some-fa5-icon";
|
||||
*
|
||||
* get shouldDisplay() {
|
||||
* return this.siteSettings.enable_custom_tab && this.currentUser.admin;
|
||||
|
@ -2067,14 +2067,6 @@ class PluginApi {
|
|||
* get count() {
|
||||
* return this.currentUser.my_custom_notification_count;
|
||||
* }
|
||||
*
|
||||
* get panelComponent() {
|
||||
* return "your-custom-glimmer-component";
|
||||
* }
|
||||
*
|
||||
* get icon() {
|
||||
* return "some-fa5-icon";
|
||||
* }
|
||||
* }
|
||||
* });
|
||||
* ```
|
||||
|
|
|
@ -45,7 +45,7 @@ export default class UserMenuTab {
|
|||
}
|
||||
|
||||
/**
|
||||
* @returns {string} Dasherized version of the component name that should be rendered in the panel area when the tab is active.
|
||||
* @returns {Component} Component class that should be rendered in the panel area when the tab is active.
|
||||
*/
|
||||
get panelComponent() {
|
||||
throw new Error("not implemented");
|
||||
|
|
|
@ -17,6 +17,7 @@ import TopicFixtures from "discourse/tests/fixtures/topic";
|
|||
import { Promise } from "rsvp";
|
||||
import { later } from "@ember/runloop";
|
||||
import I18n from "I18n";
|
||||
import DButton from "discourse/components/d-button";
|
||||
|
||||
acceptance("User menu", function (needs) {
|
||||
needs.user({
|
||||
|
@ -178,7 +179,7 @@ acceptance("User menu", function (needs) {
|
|||
}
|
||||
|
||||
get panelComponent() {
|
||||
return "d-button";
|
||||
return DButton;
|
||||
}
|
||||
|
||||
get title() {
|
||||
|
@ -246,7 +247,7 @@ acceptance("User menu", function (needs) {
|
|||
}
|
||||
|
||||
get panelComponent() {
|
||||
return "d-button";
|
||||
return DButton;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
@ -266,7 +267,7 @@ acceptance("User menu", function (needs) {
|
|||
}
|
||||
|
||||
get panelComponent() {
|
||||
return "d-button";
|
||||
return DButton;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
@ -680,7 +681,7 @@ acceptance("User menu", function (needs) {
|
|||
}
|
||||
|
||||
get panelComponent() {
|
||||
return "d-button";
|
||||
return DButton;
|
||||
}
|
||||
|
||||
get linkWhenActive() {
|
||||
|
@ -700,7 +701,7 @@ acceptance("User menu", function (needs) {
|
|||
}
|
||||
|
||||
get panelComponent() {
|
||||
return "d-button";
|
||||
return DButton;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue