discourse/app/assets/javascripts/admin/addon/services/admin-nav-manager.js
Penar Musaraj 8cbc3bcdfc
UX: Better separate login and authentication settings (#33711)
This splits the Login and Authentication admin page into multiple
sections: Settings, social logins, DiscourseConnect, OAuth2.0, OIDC.
Internal ticket `t/161648`

This PR also adds a new extension point for plugins that want to extend
this area of the app.

```
register_site_setting_area("oauth2")
register_admin_config_login_route("oauth2")
```

Adding this to a plugin allows it to extend both the setting areas
(existing functionality) and add a tab to this admin settings screen via
`register_admin_config_login_route`.
2025-10-09 15:29:21 -04:00

97 lines
2.5 KiB
JavaScript
Vendored

import Service, { service } from "@ember/service";
import { cloneJSON } from "discourse/lib/object";
import { ADMIN_NAV_MAP } from "discourse/lib/sidebar/admin-nav-map";
export default class AdminNavManager extends Service {
@service currentUser;
#adminNavMap = cloneJSON(ADMIN_NAV_MAP);
#filteredNavMap = null;
get filteredNavMap() {
if (this.#filteredNavMap) {
return this.#filteredNavMap;
}
let navConfig = cloneJSON(this.#adminNavMap);
if (this.currentUser.admin) {
return navConfig;
}
navConfig.forEach((section) => {
section.links = section.links.filter((link) => {
return link.moderator;
});
});
navConfig = navConfig.filter((section) => section.links.length);
this.#filteredNavMap = navConfig;
return this.#filteredNavMap;
}
findSection(sectionName) {
this.#guardFilteredNavAccess();
return this.#adminNavMap.find((section) => section.name === sectionName);
}
findSubSection(subSectionName) {
this.#guardFilteredNavAccess();
return this.#adminNavMap
.flatMap((section) => section.links)
.find((subSection) => subSection.name === subSectionName);
}
amendLinksToSection(sectionName, links) {
this.#guardFilteredNavAccess();
const section = this.findSection(sectionName);
if (!section) {
// eslint-disable-next-line no-console
console.warn(`[AdminNavManager] Section ${sectionName} not found`);
return;
}
section.links.push(...links);
}
amendLinksToSubSection(subSectionName, links) {
this.#guardFilteredNavAccess();
const subSection = this.findSubSection(subSectionName);
if (!subSection) {
// eslint-disable-next-line no-console
console.warn(`[AdminNavManager] SubSection ${subSectionName} not found`);
return;
}
subSection.links.push(...links);
}
overrideSectionLink(sectionName, linkName, newAttrs = {}) {
this.#guardFilteredNavAccess();
const section = this.findSection(sectionName);
const foundLink = section.links.find((link) => link.name === linkName);
if (foundLink) {
Object.assign(foundLink, newAttrs);
} else {
// eslint-disable-next-line no-console
console.warn(
`[AdminNavManager] Link ${linkName} not found in section ${sectionName}`
);
}
}
#guardFilteredNavAccess() {
if (this.#filteredNavMap) {
throw new Error(
"Cannot call findSection after filteredNavMap has been accessed, admin nav state can only be modified in admin-sidebar.js"
);
}
}
}