DEV: Supports href attribute for hamburger links API bridge to sidebar (#17750)

In the old `decorateWidget("hamburger-menu:generalLinks", callbackFn)`
API, the return value of the callback function can either return a
`route` or `href`. The API bridge added in
de54bdd73d supported `route` but not `href` and
hence the need for this commit.
This commit is contained in:
Alan Guo Xiang Tan 2022-08-02 15:30:13 +08:00 committed by GitHub
parent b9c1e63bd1
commit df264e49a9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 140 additions and 19 deletions

View File

@ -9,6 +9,7 @@ import MyPostsSectionLink from "discourse/lib/sidebar/community-section/my-posts
import GroupsSectionLink from "discourse/lib/sidebar/community-section/groups-section-link";
import UsersSectionLink from "discourse/lib/sidebar/community-section/users-section-link";
import { inject as service } from "@ember/service";
import { action } from "@ember/object";
import { next } from "@ember/runloop";
@ -21,12 +22,15 @@ const MAIN_SECTION_LINKS = [
const MORE_SECTION_LINKS = [GroupsSectionLink, UsersSectionLink];
export default class SidebarCommunitySection extends GlimmerComponent {
@service router;
moreSectionLinks = [...MORE_SECTION_LINKS, ...customSectionLinks].map(
(sectionLinkClass) => {
return new sectionLinkClass({
topicTrackingState: this.topicTrackingState,
currentUser: this.currentUser,
appEvents: this.appEvents,
router: this.router,
});
}
);

View File

@ -10,9 +10,11 @@ export default class SectionLink extends GlimmerComponent {
get prefixCSS() {
const color = this.args.prefixColor;
if (!color || !color.match(/^\w{6}$/)) {
return htmlSafe("");
}
return htmlSafe("color: #" + color);
}
}

View File

@ -97,6 +97,7 @@ import { downloadCalendar } from "discourse/lib/download-calendar";
import { consolePrefix } from "discourse/lib/source-identifier";
import { addSectionLink } from "discourse/lib/sidebar/custom-community-section-links";
import { addSidebarSection } from "discourse/lib/sidebar/custom-sections";
import DiscourseURL from "discourse/lib/url";
// If you add any methods to the API ensure you bump up the version number
// based on Semantic Versioning 2.0.0. Please update the changelog at
@ -484,15 +485,27 @@ class PluginApi {
if (siteSettings.enable_experimental_sidebar_hamburger) {
try {
const { route, label, rawLabel, className } = fn();
const { href, route, label, rawLabel, className } = fn();
const textContent = rawLabel || I18n.t(label);
this.addCommunitySectionLink({
const args = {
name: className || textContent.replace(/\s+/g, "-").toLowerCase(),
route,
title: textContent,
text: textContent,
});
};
if (href) {
if (DiscourseURL.isInternal(href)) {
args.href = href;
} else {
// Skip external links support for now
return;
}
} else {
args.route = route;
}
this.addCommunitySectionLink(args);
} catch {
deprecated(
`Usage of \`api.decorateWidget('hamburger-menu:generalLinks')\` is incompatible with the \`enable_experimental_sidebar_hamburger\` site setting. Please use \`api.addCommunitySectionLink\` instead.`
@ -1699,7 +1712,8 @@ class PluginApi {
*
* @param {(addCommunitySectionLinkCallback|Object)} arg - A callback function or an Object.
* @param {string} arg.name - The name of the link. Needs to be dasherized and lowercase.
* @param {string} arg.route - The Ember route of the link.
* @param {string=} arg.route - The Ember route name to generate the href attribute for the link.
* @param {string=} arg.href - The href attribute for the link.
* @param {string} arg.title - The title attribute for the link.
* @param {string} arg.text - The text to display for the link.
*/

View File

@ -2,7 +2,8 @@
* Base class representing a sidebar topics section link interface.
*/
export default class BaseSectionLink {
constructor({ topicTrackingState, currentUser, appEvents } = {}) {
constructor({ topicTrackingState, currentUser, appEvents, router } = {}) {
this.router = router;
this.topicTrackingState = topicTrackingState;
this.currentUser = currentUser;
this.appEvents = appEvents;
@ -32,6 +33,11 @@ export default class BaseSectionLink {
*/
get model() {}
/**
* @returns {Object} Models for <LinkTo> component. See https://api.emberjs.com/ember/release/classes/Ember.Templates.components/methods/LinkTo?anchor=LinkTo
*/
get models() {}
/**
* @returns {Object} Query parameters for <LinkTo> component. See https://api.emberjs.com/ember/release/classes/Ember.Templates.components/methods/LinkTo?anchor=LinkTo
*/

View File

@ -1,6 +1,42 @@
import BaseSectionLink from "discourse/lib/sidebar/community-section/base-section-link";
export let customSectionLinks = [];
class RouteInfoHelper {
constructor(router, url) {
this.routeInfo = router.recognize(url);
}
get route() {
return this.routeInfo.name;
}
get models() {
return this.#getParameters;
}
get query() {
return this.routeInfo.queryParams;
}
/**
* Extracted from https://github.com/emberjs/rfcs/issues/658
* Retrieves all parameters for a `RouteInfo` object and its parents in
* correct oder, so that you can pass them to e.g.
* `transitionTo(routeName, ...params)`.
*/
get #getParameters() {
let allParameters = [];
let current = this.routeInfo;
do {
const { params, paramNames } = current;
const currentParameters = paramNames.map((n) => params[n]);
allParameters = [...currentParameters, ...allParameters];
} while ((current = current.parent));
return allParameters;
}
}
/**
* Appends an additional section link under the topics section
@ -8,31 +44,56 @@ export let customSectionLinks = [];
* @param {BaseSectionLink} baseSectionLink Factory class to inherit from.
* @returns {BaseSectionLink} A class that extends BaseSectionLink.
*
* @param {(addSectionLinkCallback|Object)} arg - A callback function or an Object.
* @param {(addSectionLinkCallback|Object)} args - A callback function or an Object.
* @param {string} arg.name - The name of the link. Needs to be dasherized and lowercase.
* @param {string} arg.route - The Ember route of the link.
* @param {string} arg.title - The title attribute for the link.
* @param {string=} arg.route - The Ember route name to generate the href attribute for the link.
* @param {string=} arg.href - The href attribute for the link.
* @param {string=} arg.title - The title attribute for the link.
* @param {string} arg.text - The text to display for the link.
*/
export function addSectionLink(arg) {
if (typeof arg === "function") {
customSectionLinks.push(arg.call(this, BaseSectionLink));
export function addSectionLink(args) {
if (typeof args === "function") {
customSectionLinks.push(args.call(this, BaseSectionLink));
} else {
const klass = class extends BaseSectionLink {
constructor() {
super(...arguments);
if (args.href) {
this.routeInfoHelper = new RouteInfoHelper(this.router, args.href);
}
}
get name() {
return arg.name;
return args.name;
}
get route() {
return arg.route;
if (args.href) {
return this.routeInfoHelper.route;
} else {
return args.route;
}
}
get models() {
if (args.href) {
return this.routeInfoHelper.models;
}
}
get query() {
if (args.href) {
return this.routeInfoHelper.query;
}
}
get text() {
return arg.text;
return args.text;
}
get title() {
return arg.title;
return args.title;
}
};

View File

@ -17,7 +17,8 @@
@content={{sectionLink.text}}
@currentWhen={{sectionLink.currentWhen}}
@badgeText={{sectionLink.badgeText}}
@model={{sectionLink.model}} />
@model={{sectionLink.model}}
@models={{sectionLink.models}} />
{{/each}}
<Sidebar::MoreSectionLinks @sectionLinks={{this.moreSectionLinks}} />

View File

@ -7,7 +7,8 @@
@content={{this.activeSectionLink.text}}
@currentWhen={{this.activeSectionLink.currentWhen}}
@badgeText={{this.activeSectionLink.badgeText}}
@model={{this.activeSectionLink.model}} />
@model={{this.activeSectionLink.model}}
@models={{this.activeSectionLink.models}} />
{{/if}}
<details class="sidebar-more-section-links-details" {{on "toggle" this.toggleSectionLinks}}>
@ -29,7 +30,8 @@
@content={{sectionLink.text}}
@currentWhen={{sectionLink.currentWhen}}
@badgeText={{sectionLink.badgeText}}
@model={{sectionLink.model}} />
@model={{sectionLink.model}}
@models={{sectionLink.models}} />
{{/each}}
</div>
{{/if}}

View File

@ -444,6 +444,13 @@ acceptance("Sidebar - Plugin API", function (needs) {
className: "my-custom-top",
};
});
api.decorateWidget("hamburger-menu:generalLinks", () => {
return {
href: "/c/bug?status=open",
rawLabel: "open bugs",
};
});
});
await visit("/");
@ -457,6 +464,11 @@ acceptance("Sidebar - Plugin API", function (needs) {
"adds custom latest section link to community section"
);
assert.ok(
customlatestSectionLink.href.endsWith("/latest"),
"sets the right href attribute for the custom latest section link"
);
assert.strictEqual(
customlatestSectionLink.textContent.trim(),
I18n.t("filters.latest.title"),
@ -476,6 +488,11 @@ acceptance("Sidebar - Plugin API", function (needs) {
"adds custom unread section link to community section"
);
assert.ok(
customUnreadSectionLink.href.endsWith("/unread"),
"sets the right href attribute for the custom unread section link"
);
assert.strictEqual(
customUnreadSectionLink.textContent.trim(),
"my unreads",
@ -490,5 +507,19 @@ acceptance("Sidebar - Plugin API", function (needs) {
customTopSectionLInk,
"adds custom top section link to community section with right link class"
);
const openBugsSectionLink = query(
".sidebar-section-community .sidebar-section-link-open-bugs"
);
assert.ok(
openBugsSectionLink,
"adds custom open bugs section link to community section with right link class"
);
assert.ok(
openBugsSectionLink.href.endsWith("/c/bug?status=open"),
"sets the right href attribute for the custom open bugs section link"
);
});
});