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"
|
class="quick-access-panel"
|
||||||
tabindex="-1"
|
tabindex="-1"
|
||||||
>
|
>
|
||||||
{{component
|
<this.currentPanelComponent
|
||||||
this.currentPanelComponent
|
@closeUserMenu={{@closeUserMenu}}
|
||||||
closeUserMenu=@closeUserMenu
|
@filterByTypes={{this.currentNotificationTypes}}
|
||||||
filterByTypes=this.currentNotificationTypes
|
@ariaLabelledby={{concat "user-menu-button-" this.currentTabId}}
|
||||||
ariaLabelledby=(concat "user-menu-button-" this.currentTabId)
|
/>
|
||||||
}}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</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 { inject as service } from "@ember/service";
|
||||||
import getUrl from "discourse-common/lib/get-url";
|
import getUrl from "discourse-common/lib/get-url";
|
||||||
import { wantsNewWindow } from "discourse/lib/intercept-click";
|
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_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 REVIEW_QUEUE_TAB_ID = "review-queue";
|
||||||
|
|
||||||
const CORE_TOP_TABS = [
|
const CORE_TOP_TABS = [
|
||||||
class extends UserMenuTab {
|
class extends UserMenuTab {
|
||||||
get id() {
|
id = DEFAULT_TAB_ID;
|
||||||
return DEFAULT_TAB_ID;
|
icon = "bell";
|
||||||
}
|
panelComponent = DEFAULT_PANEL_COMPONENT;
|
||||||
|
|
||||||
get icon() {
|
|
||||||
return "bell";
|
|
||||||
}
|
|
||||||
|
|
||||||
get panelComponent() {
|
|
||||||
return DEFAULT_PANEL_COMPONENT;
|
|
||||||
}
|
|
||||||
|
|
||||||
get linkWhenActive() {
|
get linkWhenActive() {
|
||||||
return `${this.currentUser.path}/notifications`;
|
return `${this.currentUser.path}/notifications`;
|
||||||
|
@ -32,17 +34,10 @@ const CORE_TOP_TABS = [
|
||||||
},
|
},
|
||||||
|
|
||||||
class extends UserMenuTab {
|
class extends UserMenuTab {
|
||||||
get id() {
|
id = "replies";
|
||||||
return "replies";
|
icon = "reply";
|
||||||
}
|
panelComponent = UserMenuRepliesNotificationsList;
|
||||||
|
notificationTypes = ["mentioned", "posted", "quoted", "replied"];
|
||||||
get icon() {
|
|
||||||
return "reply";
|
|
||||||
}
|
|
||||||
|
|
||||||
get panelComponent() {
|
|
||||||
return "user-menu/replies-notifications-list";
|
|
||||||
}
|
|
||||||
|
|
||||||
get count() {
|
get count() {
|
||||||
return (
|
return (
|
||||||
|
@ -53,27 +48,15 @@ const CORE_TOP_TABS = [
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
get notificationTypes() {
|
|
||||||
return ["mentioned", "posted", "quoted", "replied"];
|
|
||||||
}
|
|
||||||
|
|
||||||
get linkWhenActive() {
|
get linkWhenActive() {
|
||||||
return `${this.currentUser.path}/notifications/responses`;
|
return `${this.currentUser.path}/notifications/responses`;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
class extends UserMenuTab {
|
class extends UserMenuTab {
|
||||||
get id() {
|
id = "likes";
|
||||||
return "likes";
|
icon = "heart";
|
||||||
}
|
panelComponent = UserMenuLikesNotificationsList;
|
||||||
|
|
||||||
get icon() {
|
|
||||||
return "heart";
|
|
||||||
}
|
|
||||||
|
|
||||||
get panelComponent() {
|
|
||||||
return "user-menu/likes-notifications-list";
|
|
||||||
}
|
|
||||||
|
|
||||||
get shouldDisplay() {
|
get shouldDisplay() {
|
||||||
return !this.currentUser.user_option.likes_notifications_disabled;
|
return !this.currentUser.user_option.likes_notifications_disabled;
|
||||||
|
@ -96,17 +79,10 @@ const CORE_TOP_TABS = [
|
||||||
},
|
},
|
||||||
|
|
||||||
class extends UserMenuTab {
|
class extends UserMenuTab {
|
||||||
get id() {
|
id = "messages";
|
||||||
return "messages";
|
icon = "notification.private_message";
|
||||||
}
|
panelComponent = UserMenuMessagesList;
|
||||||
|
notificationTypes = ["private_message", "group_message_summary"];
|
||||||
get icon() {
|
|
||||||
return "notification.private_message";
|
|
||||||
}
|
|
||||||
|
|
||||||
get panelComponent() {
|
|
||||||
return "user-menu/messages-list";
|
|
||||||
}
|
|
||||||
|
|
||||||
get count() {
|
get count() {
|
||||||
return this.getUnreadCountForType("private_message");
|
return this.getUnreadCountForType("private_message");
|
||||||
|
@ -116,53 +92,31 @@ const CORE_TOP_TABS = [
|
||||||
return this.currentUser?.can_send_private_messages;
|
return this.currentUser?.can_send_private_messages;
|
||||||
}
|
}
|
||||||
|
|
||||||
get notificationTypes() {
|
|
||||||
return ["private_message", "group_message_summary"];
|
|
||||||
}
|
|
||||||
|
|
||||||
get linkWhenActive() {
|
get linkWhenActive() {
|
||||||
return `${this.currentUser.path}/messages`;
|
return `${this.currentUser.path}/messages`;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
class extends UserMenuTab {
|
class extends UserMenuTab {
|
||||||
get id() {
|
id = "bookmarks";
|
||||||
return "bookmarks";
|
icon = NO_REMINDER_ICON;
|
||||||
}
|
panelComponent = UserMenuBookmarksList;
|
||||||
|
notificationTypes = ["bookmark_reminder"];
|
||||||
get icon() {
|
|
||||||
return NO_REMINDER_ICON;
|
|
||||||
}
|
|
||||||
|
|
||||||
get panelComponent() {
|
|
||||||
return "user-menu/bookmarks-list";
|
|
||||||
}
|
|
||||||
|
|
||||||
get count() {
|
get count() {
|
||||||
return this.getUnreadCountForType("bookmark_reminder");
|
return this.getUnreadCountForType("bookmark_reminder");
|
||||||
}
|
}
|
||||||
|
|
||||||
get notificationTypes() {
|
|
||||||
return ["bookmark_reminder"];
|
|
||||||
}
|
|
||||||
|
|
||||||
get linkWhenActive() {
|
get linkWhenActive() {
|
||||||
return `${this.currentUser.path}/activity/bookmarks`;
|
return `${this.currentUser.path}/activity/bookmarks`;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
class extends UserMenuTab {
|
class extends UserMenuTab {
|
||||||
get id() {
|
id = REVIEW_QUEUE_TAB_ID;
|
||||||
return REVIEW_QUEUE_TAB_ID;
|
icon = "flag";
|
||||||
}
|
panelComponent = UserMenuReviewablesList;
|
||||||
|
linkWhenActive = getUrl("/review");
|
||||||
get icon() {
|
|
||||||
return "flag";
|
|
||||||
}
|
|
||||||
|
|
||||||
get panelComponent() {
|
|
||||||
return "user-menu/reviewables-list";
|
|
||||||
}
|
|
||||||
|
|
||||||
get shouldDisplay() {
|
get shouldDisplay() {
|
||||||
return (
|
return (
|
||||||
|
@ -173,26 +127,14 @@ const CORE_TOP_TABS = [
|
||||||
get count() {
|
get count() {
|
||||||
return this.currentUser.get("reviewable_count");
|
return this.currentUser.get("reviewable_count");
|
||||||
}
|
}
|
||||||
|
|
||||||
get linkWhenActive() {
|
|
||||||
return getUrl("/review");
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const CORE_BOTTOM_TABS = [
|
const CORE_BOTTOM_TABS = [
|
||||||
class extends UserMenuTab {
|
class extends UserMenuTab {
|
||||||
get id() {
|
id = "profile";
|
||||||
return "profile";
|
icon = "user";
|
||||||
}
|
panelComponent = UserMenuProfileTabContent;
|
||||||
|
|
||||||
get icon() {
|
|
||||||
return "user";
|
|
||||||
}
|
|
||||||
|
|
||||||
get panelComponent() {
|
|
||||||
return "user-menu/profile-tab-content";
|
|
||||||
}
|
|
||||||
|
|
||||||
get linkWhenActive() {
|
get linkWhenActive() {
|
||||||
return `${this.currentUser.path}/summary`;
|
return `${this.currentUser.path}/summary`;
|
||||||
|
@ -201,23 +143,15 @@ const CORE_BOTTOM_TABS = [
|
||||||
];
|
];
|
||||||
|
|
||||||
const CORE_OTHER_NOTIFICATIONS_TAB = class extends UserMenuTab {
|
const CORE_OTHER_NOTIFICATIONS_TAB = class extends UserMenuTab {
|
||||||
|
id = "other-notifications";
|
||||||
|
icon = "discourse-other-tab";
|
||||||
|
panelComponent = UserMenuOtherNotificationsList;
|
||||||
|
|
||||||
constructor(currentUser, siteSettings, site, otherNotificationTypes) {
|
constructor(currentUser, siteSettings, site, otherNotificationTypes) {
|
||||||
super(...arguments);
|
super(...arguments);
|
||||||
this.otherNotificationTypes = otherNotificationTypes;
|
this.otherNotificationTypes = otherNotificationTypes;
|
||||||
}
|
}
|
||||||
|
|
||||||
get id() {
|
|
||||||
return "other-notifications";
|
|
||||||
}
|
|
||||||
|
|
||||||
get icon() {
|
|
||||||
return "discourse-other-tab";
|
|
||||||
}
|
|
||||||
|
|
||||||
get panelComponent() {
|
|
||||||
return "user-menu/other-notifications-list";
|
|
||||||
}
|
|
||||||
|
|
||||||
get count() {
|
get count() {
|
||||||
return this.otherNotificationTypes.reduce((sum, notificationType) => {
|
return this.otherNotificationTypes.reduce((sum, notificationType) => {
|
||||||
return sum + this.getUnreadCountForType(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 {
|
export default class UserMenu extends Component {
|
||||||
@service currentUser;
|
@service currentUser;
|
||||||
@service siteSettings;
|
@service siteSettings;
|
||||||
|
@ -323,7 +269,10 @@ export default class UserMenu extends Component {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
this.currentTabId = tab.id;
|
this.currentTabId = tab.id;
|
||||||
this.currentPanelComponent = tab.panelComponent;
|
this.currentPanelComponent = resolvePanelComponent(
|
||||||
|
getOwner(this),
|
||||||
|
tab.panelComponent
|
||||||
|
);
|
||||||
this.currentNotificationTypes = tab.notificationTypes;
|
this.currentNotificationTypes = tab.notificationTypes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2056,9 +2056,9 @@ class PluginApi {
|
||||||
* ```
|
* ```
|
||||||
* api.registerUserMenuTab((UserMenuTab) => {
|
* api.registerUserMenuTab((UserMenuTab) => {
|
||||||
* return class extends UserMenuTab {
|
* return class extends UserMenuTab {
|
||||||
* get id() {
|
* id = "custom-tab-id";
|
||||||
* return "custom-tab-id";
|
* panelComponent = MyCustomPanelGlimmerComponent;
|
||||||
* }
|
* icon = "some-fa5-icon";
|
||||||
*
|
*
|
||||||
* get shouldDisplay() {
|
* get shouldDisplay() {
|
||||||
* return this.siteSettings.enable_custom_tab && this.currentUser.admin;
|
* return this.siteSettings.enable_custom_tab && this.currentUser.admin;
|
||||||
|
@ -2067,14 +2067,6 @@ class PluginApi {
|
||||||
* get count() {
|
* get count() {
|
||||||
* return this.currentUser.my_custom_notification_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() {
|
get panelComponent() {
|
||||||
throw new Error("not implemented");
|
throw new Error("not implemented");
|
||||||
|
|
|
@ -17,6 +17,7 @@ import TopicFixtures from "discourse/tests/fixtures/topic";
|
||||||
import { Promise } from "rsvp";
|
import { Promise } from "rsvp";
|
||||||
import { later } from "@ember/runloop";
|
import { later } from "@ember/runloop";
|
||||||
import I18n from "I18n";
|
import I18n from "I18n";
|
||||||
|
import DButton from "discourse/components/d-button";
|
||||||
|
|
||||||
acceptance("User menu", function (needs) {
|
acceptance("User menu", function (needs) {
|
||||||
needs.user({
|
needs.user({
|
||||||
|
@ -178,7 +179,7 @@ acceptance("User menu", function (needs) {
|
||||||
}
|
}
|
||||||
|
|
||||||
get panelComponent() {
|
get panelComponent() {
|
||||||
return "d-button";
|
return DButton;
|
||||||
}
|
}
|
||||||
|
|
||||||
get title() {
|
get title() {
|
||||||
|
@ -246,7 +247,7 @@ acceptance("User menu", function (needs) {
|
||||||
}
|
}
|
||||||
|
|
||||||
get panelComponent() {
|
get panelComponent() {
|
||||||
return "d-button";
|
return DButton;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
@ -266,7 +267,7 @@ acceptance("User menu", function (needs) {
|
||||||
}
|
}
|
||||||
|
|
||||||
get panelComponent() {
|
get panelComponent() {
|
||||||
return "d-button";
|
return DButton;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
@ -680,7 +681,7 @@ acceptance("User menu", function (needs) {
|
||||||
}
|
}
|
||||||
|
|
||||||
get panelComponent() {
|
get panelComponent() {
|
||||||
return "d-button";
|
return DButton;
|
||||||
}
|
}
|
||||||
|
|
||||||
get linkWhenActive() {
|
get linkWhenActive() {
|
||||||
|
@ -700,7 +701,7 @@ acceptance("User menu", function (needs) {
|
||||||
}
|
}
|
||||||
|
|
||||||
get panelComponent() {
|
get panelComponent() {
|
||||||
return "d-button";
|
return DButton;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue