mirror of
https://github.com/discourse/discourse.git
synced 2025-03-20 17:07:24 +08:00
FEATURE: the ability to expand/collapse all admin sections (#26358)
By default, admin sections should be collapsed. In addition, a button to expand/collapse all sections has been added.
This commit is contained in:
parent
8e08a3b31f
commit
0932b146d9
@ -0,0 +1,28 @@
|
|||||||
|
import Component from "@glimmer/component";
|
||||||
|
import { service } from "@ember/service";
|
||||||
|
import { ADMIN_PANEL } from "discourse/lib/sidebar/panels";
|
||||||
|
import BackToForum from "./back-to-forum";
|
||||||
|
import Filter from "./filter";
|
||||||
|
import ToggleAllSections from "./toggle-all-sections";
|
||||||
|
|
||||||
|
export default class AdminHeader extends Component {
|
||||||
|
@service sidebarState;
|
||||||
|
|
||||||
|
get shouldDisplay() {
|
||||||
|
return this.sidebarState.isCurrentPanel(ADMIN_PANEL);
|
||||||
|
}
|
||||||
|
|
||||||
|
<template>
|
||||||
|
{{#if this.shouldDisplay}}
|
||||||
|
<div class="sidebar-admin-header">
|
||||||
|
<div class="sidebar-admin-header__row">
|
||||||
|
<BackToForum />
|
||||||
|
<ToggleAllSections @sections={{@sections}} />
|
||||||
|
</div>
|
||||||
|
<div class="sidebar-admin-header__row">
|
||||||
|
<Filter />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
</template>
|
||||||
|
}
|
@ -9,6 +9,7 @@
|
|||||||
@collapsable={{@collapsable}}
|
@collapsable={{@collapsable}}
|
||||||
@displaySection={{this.section.displaySection}}
|
@displaySection={{this.section.displaySection}}
|
||||||
@hideSectionHeader={{this.section.hideSectionHeader}}
|
@hideSectionHeader={{this.section.hideSectionHeader}}
|
||||||
|
@collapsedByDefault={{this.section.collapsedByDefault}}
|
||||||
>
|
>
|
||||||
{{#each this.filteredLinks key="name" as |link|}}
|
{{#each this.filteredLinks key="name" as |link|}}
|
||||||
<Sidebar::SectionLink
|
<Sidebar::SectionLink
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
<Sidebar::BackToForum />
|
<Sidebar::AdminHeader />
|
||||||
<Sidebar::Filter />
|
|
||||||
{{#each this.sections as |sectionConfig|}}
|
{{#each this.sections as |sectionConfig|}}
|
||||||
<Sidebar::ApiSection
|
<Sidebar::ApiSection
|
||||||
@sectionConfig={{sectionConfig}}
|
@sectionConfig={{sectionConfig}}
|
||||||
|
@ -10,7 +10,7 @@ export default class BackToForum extends Component {
|
|||||||
@service sidebarState;
|
@service sidebarState;
|
||||||
|
|
||||||
get shouldDisplay() {
|
get shouldDisplay() {
|
||||||
return this.sidebarState.currentPanel.key === ADMIN_PANEL;
|
return this.sidebarState.isCurrentPanel(ADMIN_PANEL);
|
||||||
}
|
}
|
||||||
|
|
||||||
get homepage() {
|
get homepage() {
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
data-section-name={{@sectionName}}
|
data-section-name={{@sectionName}}
|
||||||
class="sidebar-section-wrapper sidebar-section"
|
class="sidebar-section-wrapper sidebar-section"
|
||||||
...attributes
|
...attributes
|
||||||
|
{{did-insert this.setExpandedState}}
|
||||||
>
|
>
|
||||||
{{#unless @hideSectionHeader}}
|
{{#unless @hideSectionHeader}}
|
||||||
<div class="sidebar-section-header-wrapper sidebar-row">
|
<div class="sidebar-section-header-wrapper sidebar-row">
|
||||||
|
@ -2,26 +2,41 @@ import Component from "@glimmer/component";
|
|||||||
import { tracked } from "@glimmer/tracking";
|
import { tracked } from "@glimmer/tracking";
|
||||||
import { action } from "@ember/object";
|
import { action } from "@ember/object";
|
||||||
import { service } from "@ember/service";
|
import { service } from "@ember/service";
|
||||||
|
import { bind } from "discourse-common/utils/decorators";
|
||||||
|
|
||||||
export default class SidebarSection extends Component {
|
export default class SidebarSection extends Component {
|
||||||
@service keyValueStore;
|
@service keyValueStore;
|
||||||
|
@service sidebarState;
|
||||||
|
|
||||||
@tracked displaySectionContent;
|
@tracked collapsedSections = this.sidebarState.collapsedSections;
|
||||||
sidebarSectionContentID = `sidebar-section-content-${this.args.sectionName}`;
|
sidebarSectionContentID = `sidebar-section-content-${this.args.sectionName}`;
|
||||||
collapsedSidebarSectionKey = `sidebar-section-${this.args.sectionName}-collapsed`;
|
collapsedSidebarSectionKey = `sidebar-section-${this.args.sectionName}-collapsed`;
|
||||||
|
|
||||||
constructor() {
|
get isCollapsed() {
|
||||||
super(...arguments);
|
if (!this.args.collapsable) {
|
||||||
|
return false;
|
||||||
if (this.args.collapsable) {
|
|
||||||
this.displaySectionContent =
|
|
||||||
this.keyValueStore.getItem(this.collapsedSidebarSectionKey) ===
|
|
||||||
undefined
|
|
||||||
? true
|
|
||||||
: false;
|
|
||||||
} else {
|
|
||||||
this.displaySectionContent = true;
|
|
||||||
}
|
}
|
||||||
|
if (
|
||||||
|
this.keyValueStore.getItem(this.collapsedSidebarSectionKey) === undefined
|
||||||
|
) {
|
||||||
|
return this.args.collapsedByDefault;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
this.keyValueStore.getItem(this.collapsedSidebarSectionKey) === "true"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@bind
|
||||||
|
setExpandedState() {
|
||||||
|
if (this.isCollapsed) {
|
||||||
|
this.sidebarState.collapseSection(this.args.sectionName);
|
||||||
|
} else {
|
||||||
|
this.sidebarState.expandSection(this.args.sectionName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get displaySectionContent() {
|
||||||
|
return !this.collapsedSections.includes(this.collapsedSidebarSectionKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
willDestroy() {
|
willDestroy() {
|
||||||
@ -31,12 +46,10 @@ export default class SidebarSection extends Component {
|
|||||||
|
|
||||||
@action
|
@action
|
||||||
toggleSectionDisplay() {
|
toggleSectionDisplay() {
|
||||||
this.displaySectionContent = !this.displaySectionContent;
|
|
||||||
|
|
||||||
if (this.displaySectionContent) {
|
if (this.displaySectionContent) {
|
||||||
this.keyValueStore.remove(this.collapsedSidebarSectionKey);
|
this.sidebarState.collapseSection(this.args.sectionName);
|
||||||
} else {
|
} else {
|
||||||
this.keyValueStore.setItem(this.collapsedSidebarSectionKey, true);
|
this.sidebarState.expandSection(this.args.sectionName);
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove focus from the toggle, but only on click
|
// remove focus from the toggle, but only on click
|
||||||
|
@ -0,0 +1,53 @@
|
|||||||
|
import Component from "@glimmer/component";
|
||||||
|
import { tracked } from "@glimmer/tracking";
|
||||||
|
import { action } from "@ember/object";
|
||||||
|
import { service } from "@ember/service";
|
||||||
|
import DButton from "discourse/components/d-button";
|
||||||
|
import { ADMIN_NAV_MAP } from "discourse/lib/sidebar/admin-nav-map";
|
||||||
|
|
||||||
|
export default class ToggleAllSections extends Component {
|
||||||
|
@service sidebarState;
|
||||||
|
@service keyValueStore;
|
||||||
|
@tracked collapsedSections = this.sidebarState.collapsedSections;
|
||||||
|
|
||||||
|
get allSectionsExpanded() {
|
||||||
|
return ADMIN_NAV_MAP.every((adminNav) => {
|
||||||
|
return !this.collapsedSections.includes(
|
||||||
|
`sidebar-section-${this.sidebarState.currentPanel.key}-${adminNav.name}-collapsed`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
get title() {
|
||||||
|
return this.allSectionsExpanded
|
||||||
|
? "admin.collapse_all_sections"
|
||||||
|
: "admin.expand_all_sections";
|
||||||
|
}
|
||||||
|
|
||||||
|
get icon() {
|
||||||
|
return this.allSectionsExpanded
|
||||||
|
? "discourse-chevron-collapse"
|
||||||
|
: "discourse-chevron-expand";
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
toggleAllSections() {
|
||||||
|
const collapseOrExpand = this.allSectionsExpanded
|
||||||
|
? this.sidebarState.collapseSection.bind(this)
|
||||||
|
: this.sidebarState.expandSection.bind(this);
|
||||||
|
ADMIN_NAV_MAP.forEach((adminNav) => {
|
||||||
|
collapseOrExpand(
|
||||||
|
`${this.sidebarState.currentPanel.key}-${adminNav.name}`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<DButton
|
||||||
|
@action={{this.toggleAllSections}}
|
||||||
|
@icon={{this.icon}}
|
||||||
|
@title={{this.title}}
|
||||||
|
class="btn-transparent sidebar-toggle-all-sections"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
}
|
@ -108,7 +108,7 @@ function defineAdminSection(
|
|||||||
}
|
}
|
||||||
|
|
||||||
get name() {
|
get name() {
|
||||||
return `admin-nav-section-${this.adminNavSectionData.name}`;
|
return `${ADMIN_PANEL}-${this.adminNavSectionData.name}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
get title() {
|
get title() {
|
||||||
@ -135,6 +135,10 @@ function defineAdminSection(
|
|||||||
get displaySection() {
|
get displaySection() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get collapsedByDefault() {
|
||||||
|
return this.adminNavSectionData.name !== "root";
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return AdminNavSection;
|
return AdminNavSection;
|
||||||
|
@ -38,6 +38,13 @@ export default class BaseCustomSidebarSection {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {Boolean} Whether or not to collapse the entire section by default.
|
||||||
|
*/
|
||||||
|
get collapsedByDefault() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
_notImplemented() {
|
_notImplemented() {
|
||||||
throw "not implemented";
|
throw "not implemented";
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { tracked } from "@glimmer/tracking";
|
import { tracked } from "@glimmer/tracking";
|
||||||
import Service from "@ember/service";
|
import { A } from "@ember/array";
|
||||||
|
import Service, { service } from "@ember/service";
|
||||||
import { disableImplicitInjections } from "discourse/lib/implicit-injections";
|
import { disableImplicitInjections } from "discourse/lib/implicit-injections";
|
||||||
import {
|
import {
|
||||||
currentPanelKey,
|
currentPanelKey,
|
||||||
@ -13,11 +14,14 @@ import {
|
|||||||
|
|
||||||
@disableImplicitInjections
|
@disableImplicitInjections
|
||||||
export default class SidebarState extends Service {
|
export default class SidebarState extends Service {
|
||||||
|
@service keyValueStore;
|
||||||
@tracked currentPanelKey = currentPanelKey;
|
@tracked currentPanelKey = currentPanelKey;
|
||||||
@tracked panels = panels;
|
@tracked panels = panels;
|
||||||
@tracked mode = COMBINED_MODE;
|
@tracked mode = COMBINED_MODE;
|
||||||
@tracked displaySwitchPanelButtons = false;
|
@tracked displaySwitchPanelButtons = false;
|
||||||
@tracked filter = "";
|
@tracked filter = "";
|
||||||
|
@tracked collapsedSections = A([]);
|
||||||
|
|
||||||
previousState = {};
|
previousState = {};
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -63,6 +67,22 @@ export default class SidebarState extends Service {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
collapseSection(sectionKey) {
|
||||||
|
const collapsedSidebarSectionKey = `sidebar-section-${sectionKey}-collapsed`;
|
||||||
|
this.keyValueStore.setItem(collapsedSidebarSectionKey, true);
|
||||||
|
this.collapsedSections.pushObject(collapsedSidebarSectionKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
expandSection(sectionKey) {
|
||||||
|
const collapsedSidebarSectionKey = `sidebar-section-${sectionKey}-collapsed`;
|
||||||
|
this.keyValueStore.setItem(collapsedSidebarSectionKey, false);
|
||||||
|
this.collapsedSections.removeObject(collapsedSidebarSectionKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
isCurrentPanel(panel) {
|
||||||
|
return this.currentPanel.key === panel;
|
||||||
|
}
|
||||||
|
|
||||||
restorePreviousState() {
|
restorePreviousState() {
|
||||||
const state = this.previousState[this.currentPanelKey];
|
const state = this.previousState[this.currentPanelKey];
|
||||||
if (!state) {
|
if (!state) {
|
||||||
|
@ -33,65 +33,54 @@ acceptance("Admin Sidebar - Sections", function (needs) {
|
|||||||
await visit("/admin");
|
await visit("/admin");
|
||||||
|
|
||||||
assert.ok(
|
assert.ok(
|
||||||
exists(".sidebar-section[data-section-name='admin-nav-section-root']"),
|
exists(".sidebar-section[data-section-name='admin-root']"),
|
||||||
"root section is displayed"
|
"root section is displayed"
|
||||||
);
|
);
|
||||||
assert.ok(
|
assert.ok(
|
||||||
exists(".sidebar-section[data-section-name='admin-nav-section-account']"),
|
exists(".sidebar-section[data-section-name='admin-account']"),
|
||||||
"account section is displayed"
|
"account section is displayed"
|
||||||
);
|
);
|
||||||
assert.ok(
|
assert.ok(
|
||||||
exists(".sidebar-section[data-section-name='admin-nav-section-reports']"),
|
exists(".sidebar-section[data-section-name='admin-reports']"),
|
||||||
"reports section is displayed"
|
"reports section is displayed"
|
||||||
);
|
);
|
||||||
assert.ok(
|
assert.ok(
|
||||||
exists(
|
exists(".sidebar-section[data-section-name='admin-community']"),
|
||||||
".sidebar-section[data-section-name='admin-nav-section-community']"
|
|
||||||
),
|
|
||||||
"community section is displayed"
|
"community section is displayed"
|
||||||
);
|
);
|
||||||
assert.ok(
|
assert.ok(
|
||||||
exists(
|
exists(".sidebar-section[data-section-name='admin-appearance']"),
|
||||||
".sidebar-section[data-section-name='admin-nav-section-appearance']"
|
|
||||||
),
|
|
||||||
"appearance section is displayed"
|
"appearance section is displayed"
|
||||||
);
|
);
|
||||||
assert.ok(
|
assert.ok(
|
||||||
exists(
|
exists(".sidebar-section[data-section-name='admin-email_settings']"),
|
||||||
".sidebar-section[data-section-name='admin-nav-section-email_settings']"
|
|
||||||
),
|
|
||||||
"email settings section is displayed"
|
"email settings section is displayed"
|
||||||
);
|
);
|
||||||
assert.ok(
|
assert.ok(
|
||||||
exists(
|
exists(".sidebar-section[data-section-name='admin-email_logs']"),
|
||||||
".sidebar-section[data-section-name='admin-nav-section-email_logs']"
|
|
||||||
),
|
|
||||||
"email logs settings section is displayed"
|
"email logs settings section is displayed"
|
||||||
);
|
);
|
||||||
assert.ok(
|
assert.ok(
|
||||||
exists(
|
exists(".sidebar-section[data-section-name='admin-security']"),
|
||||||
".sidebar-section[data-section-name='admin-nav-section-security']"
|
|
||||||
),
|
|
||||||
"security settings section is displayed"
|
"security settings section is displayed"
|
||||||
);
|
);
|
||||||
assert.ok(
|
assert.ok(
|
||||||
exists(".sidebar-section[data-section-name='admin-nav-section-plugins']"),
|
exists(".sidebar-section[data-section-name='admin-plugins']"),
|
||||||
"plugins section is displayed"
|
"plugins section is displayed"
|
||||||
);
|
);
|
||||||
assert.ok(
|
assert.ok(
|
||||||
exists(
|
exists(".sidebar-section[data-section-name='admin-advanced']"),
|
||||||
".sidebar-section[data-section-name='admin-nav-section-advanced']"
|
|
||||||
),
|
|
||||||
"advanced section is displayed"
|
"advanced section is displayed"
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("enabled plugin admin routes have links added", async function (assert) {
|
test("enabled plugin admin routes have links added", async function (assert) {
|
||||||
await visit("/admin");
|
await visit("/admin");
|
||||||
|
await click(".sidebar-toggle-all-sections");
|
||||||
|
|
||||||
assert.ok(
|
assert.ok(
|
||||||
exists(
|
exists(
|
||||||
".sidebar-section[data-section-name='admin-nav-section-plugins'] .sidebar-section-link-wrapper[data-list-item-name=\"admin_installed_plugins\"]"
|
".sidebar-section[data-section-name='admin-plugins'] .sidebar-section-link-wrapper[data-list-item-name=\"admin_installed_plugins\"]"
|
||||||
),
|
),
|
||||||
"the admin plugin route is added to the plugins section"
|
"the admin plugin route is added to the plugins section"
|
||||||
);
|
);
|
||||||
@ -99,6 +88,7 @@ acceptance("Admin Sidebar - Sections", function (needs) {
|
|||||||
|
|
||||||
test("Visit reports page", async function (assert) {
|
test("Visit reports page", async function (assert) {
|
||||||
await visit("/admin");
|
await visit("/admin");
|
||||||
|
await click(".sidebar-toggle-all-sections");
|
||||||
await click(".sidebar-section-link[data-link-name='admin_all_reports']");
|
await click(".sidebar-section-link[data-link-name='admin_all_reports']");
|
||||||
|
|
||||||
assert.strictEqual(count(".admin-reports-list__report"), 1);
|
assert.strictEqual(count(".admin-reports-list__report"), 1);
|
||||||
@ -170,28 +160,28 @@ acceptance("Admin Sidebar - Sections - Plugin API", function (needs) {
|
|||||||
|
|
||||||
assert.ok(
|
assert.ok(
|
||||||
exists(
|
exists(
|
||||||
".sidebar-section[data-section-name='admin-nav-section-root'] .sidebar-section-link-wrapper[data-list-item-name=\"admin_additional_root_test_section_link\"]"
|
".sidebar-section[data-section-name='admin-root'] .sidebar-section-link-wrapper[data-list-item-name=\"admin_additional_root_test_section_link\"]"
|
||||||
),
|
),
|
||||||
"link is appended to the root section"
|
"link is appended to the root section"
|
||||||
);
|
);
|
||||||
|
|
||||||
assert.notOk(
|
assert.notOk(
|
||||||
exists(
|
exists(
|
||||||
".sidebar-section[data-section-name='admin-nav-section-root'] .sidebar-section-link-wrapper[data-list-item-name=\"admin_additional_root_test_section_link_no_route_or_href\"]"
|
".sidebar-section[data-section-name='admin-root'] .sidebar-section-link-wrapper[data-list-item-name=\"admin_additional_root_test_section_link_no_route_or_href\"]"
|
||||||
),
|
),
|
||||||
"invalid link that has no route or href is not appended to the root section"
|
"invalid link that has no route or href is not appended to the root section"
|
||||||
);
|
);
|
||||||
|
|
||||||
assert.notOk(
|
assert.notOk(
|
||||||
exists(
|
exists(
|
||||||
".sidebar-section[data-section-name='admin-nav-section-root'] .sidebar-section-link-wrapper[data-list-item-name=\"admin_additional_root_test_section_link_no_label_or_text\"]"
|
".sidebar-section[data-section-name='admin-root'] .sidebar-section-link-wrapper[data-list-item-name=\"admin_additional_root_test_section_link_no_label_or_text\"]"
|
||||||
),
|
),
|
||||||
"invalid link that has no label or text is not appended to the root section"
|
"invalid link that has no label or text is not appended to the root section"
|
||||||
);
|
);
|
||||||
|
|
||||||
assert.notOk(
|
assert.notOk(
|
||||||
exists(
|
exists(
|
||||||
".sidebar-section[data-section-name='admin-nav-section-root'] .sidebar-section-link-wrapper[data-list-item-name=\"admin_additional_root_test_section_link_invalid_label\"]"
|
".sidebar-section[data-section-name='admin-root'] .sidebar-section-link-wrapper[data-list-item-name=\"admin_additional_root_test_section_link_invalid_label\"]"
|
||||||
),
|
),
|
||||||
"invalid link with an invalid I18n key is not appended to the root section"
|
"invalid link with an invalid I18n key is not appended to the root section"
|
||||||
);
|
);
|
||||||
|
@ -91,6 +91,10 @@
|
|||||||
.badge-notification {
|
.badge-notification {
|
||||||
vertical-align: text-bottom;
|
vertical-align: text-bottom;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.sidebar-filter {
|
||||||
|
width: calc(320px - 2 * var(--d-sidebar-row-horizontal-padding));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.search-menu .menu-panel {
|
.search-menu .menu-panel {
|
||||||
@ -345,14 +349,12 @@
|
|||||||
font-size: var(--font-down-1);
|
font-size: var(--font-down-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-filter {
|
.sidebar-admin-header__row {
|
||||||
width: calc(100% - 2.35rem);
|
width: calc(320px - 2 * var(--d-sidebar-row-horizontal-padding));
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-sections {
|
.sidebar-sections {
|
||||||
&__back-to-forum {
|
&__back-to-forum {
|
||||||
margin: 0 var(--d-sidebar-row-horizontal-padding) 0.5em
|
|
||||||
var(--d-sidebar-row-horizontal-padding);
|
|
||||||
color: var(--d-sidebar-link-color);
|
color: var(--d-sidebar-link-color);
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
@ -116,9 +116,8 @@
|
|||||||
|
|
||||||
transition-delay: 0s;
|
transition-delay: 0s;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__back-to-forum {
|
&__back-to-forum {
|
||||||
margin: 0 var(--d-sidebar-row-horizontal-padding) 1em
|
|
||||||
var(--d-sidebar-row-horizontal-padding);
|
|
||||||
color: var(--d-sidebar-link-color);
|
color: var(--d-sidebar-link-color);
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -310,8 +309,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-filter {
|
.sidebar-filter {
|
||||||
margin: 0 var(--d-sidebar-row-horizontal-padding) 0.5em
|
margin-top: 1em;
|
||||||
var(--d-sidebar-row-horizontal-padding);
|
margin-bottom: 1em;
|
||||||
display: flex;
|
display: flex;
|
||||||
border: 1px solid var(--primary-400);
|
border: 1px solid var(--primary-400);
|
||||||
border-radius: var(--d-input-border-radius);
|
border-radius: var(--d-input-border-radius);
|
||||||
@ -319,7 +318,7 @@
|
|||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
background: var(--secondary);
|
background: var(--secondary);
|
||||||
width: calc(
|
width: calc(
|
||||||
var(--d-sidebar-width) - var(--d-sidebar-row-horizontal-padding) * 2
|
var(--d-sidebar-width) - 2 * var(--d-sidebar-row-horizontal-padding)
|
||||||
);
|
);
|
||||||
|
|
||||||
&:focus-within {
|
&:focus-within {
|
||||||
@ -336,7 +335,7 @@
|
|||||||
&:focus-within {
|
&:focus-within {
|
||||||
outline: 0;
|
outline: 0;
|
||||||
}
|
}
|
||||||
width: calc(100% - 2em);
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__clear {
|
&__clear {
|
||||||
@ -346,6 +345,7 @@
|
|||||||
background-color: var(--secondary);
|
background-color: var(--secondary);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-no-results {
|
.sidebar-no-results {
|
||||||
margin: 0.5em var(--d-sidebar-row-horizontal-padding) 0
|
margin: 0.5em var(--d-sidebar-row-horizontal-padding) 0
|
||||||
var(--d-sidebar-row-horizontal-padding);
|
var(--d-sidebar-row-horizontal-padding);
|
||||||
@ -359,3 +359,22 @@
|
|||||||
.sidebar-section-wrapper + .sidebar-no-results {
|
.sidebar-section-wrapper + .sidebar-no-results {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.sidebar-admin-header__row {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin: 0 var(--d-sidebar-row-horizontal-padding) 0
|
||||||
|
var(--d-sidebar-row-horizontal-padding);
|
||||||
|
color: var(--d-sidebar-link-color);
|
||||||
|
width: calc(
|
||||||
|
var(--d-sidebar-width) - 2 * var(--d-sidebar-row-horizontal-padding) + 2px
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-toggle-all-sections.btn-transparent {
|
||||||
|
padding-right: 0;
|
||||||
|
color: var(--d-sidebar-link-color);
|
||||||
|
svg {
|
||||||
|
width: 0.75em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -4817,6 +4817,8 @@ en:
|
|||||||
moderator: "Moderator"
|
moderator: "Moderator"
|
||||||
back_to_forum: "Back to Forum"
|
back_to_forum: "Back to Forum"
|
||||||
filter_reports: Filter reports
|
filter_reports: Filter reports
|
||||||
|
expand_all_sections: "Expand all sections"
|
||||||
|
collapse_all_sections: "Collapse all sections"
|
||||||
|
|
||||||
tags:
|
tags:
|
||||||
remove_muted_tags_from_latest:
|
remove_muted_tags_from_latest:
|
||||||
|
@ -13,11 +13,13 @@ describe "Admin Revamp | Sidebar Navigation | Plugin Links", type: :system do
|
|||||||
|
|
||||||
it "shows links to enabled plugin admin routes" do
|
it "shows links to enabled plugin admin routes" do
|
||||||
visit("/admin")
|
visit("/admin")
|
||||||
|
sidebar.toggle_all_sections
|
||||||
expect(sidebar).to have_section_link("Chat", href: "/admin/plugins/chat")
|
expect(sidebar).to have_section_link("Chat", href: "/admin/plugins/chat")
|
||||||
end
|
end
|
||||||
|
|
||||||
it "does not duplicate links to enabled plugin admin routes when showing and hiding sidebar" do
|
it "does not duplicate links to enabled plugin admin routes when showing and hiding sidebar" do
|
||||||
visit("/admin")
|
visit("/admin")
|
||||||
|
sidebar.toggle_all_sections
|
||||||
expect(sidebar).to have_section_link("Chat", href: "/admin/plugins/chat", count: 1)
|
expect(sidebar).to have_section_link("Chat", href: "/admin/plugins/chat", count: 1)
|
||||||
find(".header-sidebar-toggle").click
|
find(".header-sidebar-toggle").click
|
||||||
find(".header-sidebar-toggle").click
|
find(".header-sidebar-toggle").click
|
||||||
@ -68,12 +70,12 @@ describe "Admin Revamp | Sidebar Navigation | Plugin Links", type: :system do
|
|||||||
admin.upsert_custom_fields(::Chat::LAST_CHAT_CHANNEL_ID => membership.chat_channel.id)
|
admin.upsert_custom_fields(::Chat::LAST_CHAT_CHANNEL_ID => membership.chat_channel.id)
|
||||||
chat_page.prefers_full_page
|
chat_page.prefers_full_page
|
||||||
visit("/admin")
|
visit("/admin")
|
||||||
expect(sidebar).to have_section("admin-nav-section-root")
|
expect(sidebar).to have_section("admin-root")
|
||||||
chat_page.open_from_header
|
chat_page.open_from_header
|
||||||
expect(sidebar).to have_no_section("admin-nav-section-root")
|
expect(sidebar).to have_no_section("admin-root")
|
||||||
chat_page.minimize_full_page
|
chat_page.minimize_full_page
|
||||||
expect(chat_page).to have_drawer
|
expect(chat_page).to have_drawer
|
||||||
expect(sidebar).to have_section("admin-nav-section-root")
|
expect(sidebar).to have_section("admin-root")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -14,15 +14,22 @@ describe "Admin Revamp | Sidebar Navigation", type: :system do
|
|||||||
|
|
||||||
it "shows the sidebar when navigating to an admin route and hides it when leaving" do
|
it "shows the sidebar when navigating to an admin route and hides it when leaving" do
|
||||||
visit("/latest")
|
visit("/latest")
|
||||||
expect(sidebar).to have_section("community")
|
expect(sidebar).to have_section("categories")
|
||||||
sidebar.click_link_in_section("community", "admin")
|
sidebar.click_link_in_section("community", "admin")
|
||||||
expect(page).to have_current_path("/admin")
|
expect(page).to have_current_path("/admin")
|
||||||
expect(sidebar).to be_visible
|
expect(sidebar).to be_visible
|
||||||
expect(sidebar).to have_no_section("community")
|
expect(sidebar).to have_no_section("categories")
|
||||||
expect(page).to have_no_css(".admin-main-nav")
|
expect(page).to have_no_css(".admin-main-nav")
|
||||||
filter.click_back_to_forum
|
filter.click_back_to_forum
|
||||||
expect(page).to have_current_path("/latest")
|
expect(page).to have_current_path("/latest")
|
||||||
expect(sidebar).to have_no_section("admin-nav-section-root")
|
expect(sidebar).to have_no_section("admin-root")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "collapses sections by default" do
|
||||||
|
visit("/admin")
|
||||||
|
links = page.all(".sidebar-section-link-content-text")
|
||||||
|
expect(links.count).to eq(2)
|
||||||
|
expect(links.map(&:text)).to eq(["Dashboard", "All Site Settings"])
|
||||||
end
|
end
|
||||||
|
|
||||||
it "respects the user homepage preference for the Back to Forum link" do
|
it "respects the user homepage preference for the Back to Forum link" do
|
||||||
@ -47,7 +54,7 @@ describe "Admin Revamp | Sidebar Navigation", type: :system do
|
|||||||
filter.click_back_to_forum
|
filter.click_back_to_forum
|
||||||
expect(page).to have_current_path("/latest")
|
expect(page).to have_current_path("/latest")
|
||||||
sidebar_dropdown.click
|
sidebar_dropdown.click
|
||||||
expect(sidebar).to have_no_section("admin-nav-section-root")
|
expect(sidebar).to have_no_section("admin-root")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -58,12 +65,13 @@ describe "Admin Revamp | Sidebar Navigation", type: :system do
|
|||||||
visit("/latest")
|
visit("/latest")
|
||||||
sidebar.click_link_in_section("community", "admin")
|
sidebar.click_link_in_section("community", "admin")
|
||||||
expect(page).to have_current_path("/admin")
|
expect(page).to have_current_path("/admin")
|
||||||
expect(sidebar).to have_no_section("admin-nav-section-root")
|
expect(sidebar).to have_no_section("admin-root")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it "allows links to be filtered" do
|
it "allows links to be filtered" do
|
||||||
visit("/admin")
|
visit("/admin")
|
||||||
|
sidebar.toggle_all_sections
|
||||||
all_links_count = page.all(".sidebar-section-link-content-text").count
|
all_links_count = page.all(".sidebar-section-link-content-text").count
|
||||||
|
|
||||||
links = page.all(".sidebar-section-link-content-text")
|
links = page.all(".sidebar-section-link-content-text")
|
||||||
@ -93,6 +101,21 @@ describe "Admin Revamp | Sidebar Navigation", type: :system do
|
|||||||
expect(links.map(&:text)).to eq(["Appearance", "Preview Summary", "Server Setup"])
|
expect(links.map(&:text)).to eq(["Appearance", "Preview Summary", "Server Setup"])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "allows sections to be expanded" do
|
||||||
|
visit("/admin")
|
||||||
|
sidebar.toggle_all_sections
|
||||||
|
all_links_count = page.all(".sidebar-section-link-content-text").count
|
||||||
|
sidebar.toggle_all_sections
|
||||||
|
|
||||||
|
links = page.all(".sidebar-section-link-content-text")
|
||||||
|
expect(links.count).to eq(2)
|
||||||
|
expect(links.map(&:text)).to eq(["Dashboard", "All Site Settings"])
|
||||||
|
|
||||||
|
sidebar.toggle_all_sections
|
||||||
|
links = page.all(".sidebar-section-link-content-text")
|
||||||
|
expect(links.count).to eq(all_links_count)
|
||||||
|
end
|
||||||
|
|
||||||
it "accepts hidden keywords like installed plugin names for filter" do
|
it "accepts hidden keywords like installed plugin names for filter" do
|
||||||
Discourse.instance_variable_set(
|
Discourse.instance_variable_set(
|
||||||
"@plugins",
|
"@plugins",
|
||||||
@ -100,6 +123,7 @@ describe "Admin Revamp | Sidebar Navigation", type: :system do
|
|||||||
)
|
)
|
||||||
|
|
||||||
visit("/admin")
|
visit("/admin")
|
||||||
|
sidebar.toggle_all_sections
|
||||||
filter.filter("csp_extension")
|
filter.filter("csp_extension")
|
||||||
links = page.all(".sidebar-section-link-content-text")
|
links = page.all(".sidebar-section-link-content-text")
|
||||||
expect(links.count).to eq(1)
|
expect(links.count).to eq(1)
|
||||||
|
@ -40,6 +40,10 @@ module PageObjects
|
|||||||
def custom_section_modal_title
|
def custom_section_modal_title
|
||||||
find("#discourse-modal-title")
|
find("#discourse-modal-title")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def toggle_all_sections
|
||||||
|
find(".sidebar-toggle-all-sections").click
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
Loading…
x
Reference in New Issue
Block a user