DEV: Add displaySection to sidebar sections (#18479)
This PR renames the old Sidebar::Section displaySection function to displaySectionContent, and changes the meaning of displaySection to hide the entire sidebar section including the header. This is implemented via an arg passed to Sidebar::Section, which will default to true if it is not passed, and the BaseCustomSidebarSection class implements a default of `return true` for this function.
This commit is contained in:
parent
90f1e2df80
commit
e3f1e0e9bc
|
@ -1,42 +1,44 @@
|
|||
<div class={{concat "sidebar-section-wrapper sidebar-section-" @sectionName}}>
|
||||
<div class="sidebar-section-header-wrapper sidebar-row">
|
||||
<Sidebar::SectionHeader @collapsable={{@collapsable}} @toggleSectionDisplay={{this.toggleSectionDisplay}}>
|
||||
{{#if @collapsable}}
|
||||
<span class="sidebar-section-header-caret">
|
||||
{{d-icon this.headerCaretIcon}}
|
||||
{{#if this.displaySection}}
|
||||
<div class={{concat "sidebar-section-wrapper sidebar-section-" @sectionName}}>
|
||||
<div class="sidebar-section-header-wrapper sidebar-row">
|
||||
<Sidebar::SectionHeader @collapsable={{@collapsable}} @toggleSectionDisplay={{this.toggleSectionDisplay}}>
|
||||
{{#if @collapsable}}
|
||||
<span class="sidebar-section-header-caret">
|
||||
{{d-icon this.headerCaretIcon}}
|
||||
</span>
|
||||
{{/if}}
|
||||
|
||||
<span class="sidebar-section-header-text">
|
||||
{{@headerLinkText}}
|
||||
</span>
|
||||
</Sidebar::SectionHeader>
|
||||
|
||||
{{#if this.isSingleHeaderAction}}
|
||||
{{#each @headerActions as |headerAction|}}
|
||||
<button
|
||||
type="button"
|
||||
class="sidebar-section-header-button"
|
||||
{{on "click" headerAction.action}}
|
||||
title={{headerAction.title}}
|
||||
>
|
||||
{{d-icon @headerActionsIcon}}
|
||||
</button>
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
|
||||
<span class="sidebar-section-header-text">
|
||||
{{@headerLinkText}}
|
||||
</span>
|
||||
</Sidebar::SectionHeader>
|
||||
{{#if this.isMultipleHeaderActions}}
|
||||
<DropdownSelectBox
|
||||
@options={{hash icon=@headerActionsIcon placementStrategy="absolute"}}
|
||||
@content={{@headerActions}}
|
||||
@onChange={{action "handleMultipleHeaderActions"}}
|
||||
@class="sidebar-section-header-dropdown" />
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
{{#if this.isSingleHeaderAction}}
|
||||
{{#each @headerActions as |headerAction|}}
|
||||
<button
|
||||
type="button"
|
||||
class="sidebar-section-header-button"
|
||||
{{on "click" headerAction.action}}
|
||||
title={{headerAction.title}}
|
||||
>
|
||||
{{d-icon @headerActionsIcon}}
|
||||
</button>
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
|
||||
{{#if this.isMultipleHeaderActions}}
|
||||
<DropdownSelectBox
|
||||
@options={{hash icon=@headerActionsIcon placementStrategy="absolute"}}
|
||||
@content={{@headerActions}}
|
||||
@onChange={{action "handleMultipleHeaderActions"}}
|
||||
@class="sidebar-section-header-dropdown" />
|
||||
{{#if this.displaySectionContent}}
|
||||
<div class="sidebar-section-content">
|
||||
{{yield}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
{{#if this.displaySection}}
|
||||
<div class="sidebar-section-content">
|
||||
{{yield}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
||||
|
|
|
@ -7,20 +7,20 @@ import { tracked } from "@glimmer/tracking";
|
|||
export default class SidebarSection extends Component {
|
||||
@service keyValueStore;
|
||||
|
||||
@tracked displaySection;
|
||||
@tracked displaySectionContent;
|
||||
collapsedSidebarSectionKey = `sidebar-section-${this.args.sectionName}-collapsed`;
|
||||
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
|
||||
if (this.args.collapsable) {
|
||||
this.displaySection =
|
||||
this.displaySectionContent =
|
||||
this.keyValueStore.getItem(this.collapsedSidebarSectionKey) ===
|
||||
undefined
|
||||
? true
|
||||
: false;
|
||||
} else {
|
||||
this.displaySection = true;
|
||||
this.displaySectionContent = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -32,9 +32,9 @@ export default class SidebarSection extends Component {
|
|||
|
||||
@action
|
||||
toggleSectionDisplay() {
|
||||
this.displaySection = !this.displaySection;
|
||||
this.displaySectionContent = !this.displaySectionContent;
|
||||
|
||||
if (this.displaySection) {
|
||||
if (this.displaySectionContent) {
|
||||
this.keyValueStore.remove(this.collapsedSidebarSectionKey);
|
||||
} else {
|
||||
this.keyValueStore.setItem(this.collapsedSidebarSectionKey, true);
|
||||
|
@ -54,7 +54,7 @@ export default class SidebarSection extends Component {
|
|||
}
|
||||
|
||||
get headerCaretIcon() {
|
||||
return this.displaySection ? "angle-down" : "angle-right";
|
||||
return this.displaySectionContent ? "angle-down" : "angle-right";
|
||||
}
|
||||
|
||||
get isSingleHeaderAction() {
|
||||
|
@ -64,4 +64,12 @@ export default class SidebarSection extends Component {
|
|||
get isMultipleHeaderActions() {
|
||||
return this.args.headerActions?.length > 1;
|
||||
}
|
||||
|
||||
get displaySection() {
|
||||
if (this.args.displaySection === undefined) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return this.args.displaySection;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,8 @@
|
|||
@headerActionsIcon={{customSection.actionsIcon}}
|
||||
@headerActions={{customSection.actions}}
|
||||
@willDestroy={{customSection.willDestroy}}
|
||||
@collapsable={{@collapsableSections}}>
|
||||
@collapsable={{@collapsableSections}}
|
||||
@displaySection={{customSection.displaySection}}>
|
||||
|
||||
{{#each customSection.links as |link|}}
|
||||
<Sidebar::SectionLink
|
||||
|
|
|
@ -35,6 +35,13 @@ export default class BaseCustomSidebarSection {
|
|||
*/
|
||||
get links() {}
|
||||
|
||||
/**
|
||||
* @returns {Boolean} Whether or not to show the entire section including heading.
|
||||
*/
|
||||
get displaySection() {
|
||||
return true;
|
||||
}
|
||||
|
||||
_notImplemented() {
|
||||
throw "not implemented";
|
||||
}
|
||||
|
|
|
@ -564,4 +564,49 @@ acceptance("Sidebar - Plugin API", function (needs) {
|
|||
"does not display my favourite topic custom section link when current route does not match the link's route"
|
||||
);
|
||||
});
|
||||
|
||||
test("Section that is not displayed via displaySection", async function (assert) {
|
||||
withPluginApi("1.3.0", (api) => {
|
||||
api.addSidebarSection((BaseCustomSidebarSection) => {
|
||||
return class extends BaseCustomSidebarSection {
|
||||
get name() {
|
||||
return "test-chat-channels";
|
||||
}
|
||||
|
||||
get text() {
|
||||
return "chat channels text";
|
||||
}
|
||||
|
||||
get actionsIcon() {
|
||||
return "cog";
|
||||
}
|
||||
|
||||
get actions() {
|
||||
return [
|
||||
{
|
||||
id: "browseChannels",
|
||||
title: "Browse channels",
|
||||
action: () => {},
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
get links() {
|
||||
return [];
|
||||
}
|
||||
|
||||
get displaySection() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
await visit("/");
|
||||
|
||||
assert.notOk(
|
||||
exists(".sidebar-section-test-chat-channels"),
|
||||
"does not display the section"
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
import { module, test } from "qunit";
|
||||
import { hbs } from "ember-cli-htmlbars";
|
||||
import { click, render } from "@ember/test-helpers";
|
||||
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
|
||||
import { exists } from "discourse/tests/helpers/qunit-helpers";
|
||||
|
||||
module("Integration | Component | sidebar | section", function (hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
|
||||
test("default displaySection value for section", async function (assert) {
|
||||
const template = hbs`
|
||||
<Sidebar::Section
|
||||
@sectionName="test"
|
||||
@headerLinkText="test header"
|
||||
@headerLinkTitle="some title"
|
||||
@headerActionsIcon="plus"
|
||||
@headerActions={{this.headerActions}} />`;
|
||||
|
||||
this.headerActions = [];
|
||||
await render(template);
|
||||
|
||||
assert.ok(
|
||||
exists(".sidebar-section-wrapper"),
|
||||
"section is displayed by default if no display arg is provided"
|
||||
);
|
||||
});
|
||||
|
||||
test("displaySection is dynamic based on argument", async function (assert) {
|
||||
const template = hbs`
|
||||
<Sidebar::Section
|
||||
@sectionName="test"
|
||||
@headerLinkText="test header"
|
||||
@headerLinkTitle="some title"
|
||||
@headerActionsIcon="plus"
|
||||
@headerActions={{this.headerActions}}
|
||||
@displaySection={{this.displaySection}}/>`;
|
||||
|
||||
this.displaySection = false;
|
||||
this.headerActions = [];
|
||||
await render(template);
|
||||
|
||||
assert.notOk(
|
||||
exists(".sidebar-section-wrapper"),
|
||||
"section is not displayed"
|
||||
);
|
||||
|
||||
this.set("displaySection", true);
|
||||
assert.ok(exists(".sidebar-section-wrapper"), "section is displayed");
|
||||
});
|
||||
|
||||
test("can expand and collapse content when section is collapsible", async function (assert) {
|
||||
const template = hbs`
|
||||
<Sidebar::Section
|
||||
@sectionName="test"
|
||||
@headerLinkText="test header"
|
||||
@headerLinkTitle="some title"
|
||||
@headerActionsIcon="plus"
|
||||
@headerActions={{this.headerActions}}
|
||||
@collapsable=true />`;
|
||||
|
||||
this.headerActions = [];
|
||||
await render(template);
|
||||
|
||||
assert.ok(exists(".sidebar-section-content"), "shows content by default");
|
||||
|
||||
await click(".sidebar-section-header-caret");
|
||||
|
||||
assert.notOk(
|
||||
exists(".sidebar-section-content"),
|
||||
"does not show content after collapsing"
|
||||
);
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue