mirror of
https://github.com/discourse/discourse.git
synced 2025-06-03 19:39:30 +08:00
UX: Remove section heading for community section (#22405)
Why is this change being made? We've decided that the previous "community" section should look more like a primary section that holds the most important navigation links for the site and the word "community" doesn't quite fit that description. Therefore, we've made the decision to drop the section heading for the community section. As part of removing the section heading, the following changes are made as well: 1. Button to customize the section has been moved to the "footer" of the "More..." section when `navigation_menu` site setting is set to `sidebar`. When `navigation_menu` is set to `header dropdown`, a button to customize the section is shown inline. 2. The section will no longer be collapsable. 3. The title of the section is no longer customisable as it is no longer displayed. As a technical note, we have not dropped any previous customisations of the section's title previously in case we have to bring back the header in the future. 4. The new topic button that was previously present in the header has been removed alongside the header. Admins can add a custom section link to the `/new-topic` route if there would like to make it easier for users to create a new topic in the sidebar.
This commit is contained in:

committed by
GitHub

parent
41c3b42412
commit
ab053ac669
@ -6,38 +6,46 @@
|
||||
class="sidebar-section-form-modal"
|
||||
>
|
||||
<:body>
|
||||
<form class="form-horizontal">
|
||||
<div class="input-group">
|
||||
<label for="section-name">{{i18n
|
||||
"sidebar.sections.custom.title.label"
|
||||
}}</label>
|
||||
<Input
|
||||
name="section-name"
|
||||
@type="text"
|
||||
@value={{this.transformedModel.title}}
|
||||
class={{this.transformedModel.titleCssClass}}
|
||||
{{on
|
||||
"input"
|
||||
(action (mut this.transformedModel.title) value="target.value")
|
||||
}}
|
||||
/>
|
||||
{{#if this.transformedModel.invalidTitleMessage}}
|
||||
<div class="title warning">
|
||||
{{this.transformedModel.invalidTitleMessage}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
<form class="form-horizontal sidebar-section-form">
|
||||
{{#unless this.transformedModel.hideTitleInput}}
|
||||
<div class="sidebar-section-form__input-wrapper">
|
||||
<label for="section-name">
|
||||
{{i18n "sidebar.sections.custom.title.label"}}
|
||||
</label>
|
||||
|
||||
<Input
|
||||
name="section-name"
|
||||
@type="text"
|
||||
@value={{this.transformedModel.title}}
|
||||
class={{this.transformedModel.titleCssClass}}
|
||||
{{on
|
||||
"input"
|
||||
(action (mut this.transformedModel.title) value="target.value")
|
||||
}}
|
||||
/>
|
||||
|
||||
{{#if this.transformedModel.invalidTitleMessage}}
|
||||
<div class="title warning">
|
||||
{{this.transformedModel.invalidTitleMessage}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/unless}}
|
||||
|
||||
<div class="row-wrapper header">
|
||||
<div class="input-group link-icon">
|
||||
<label>{{i18n "sidebar.sections.custom.links.icon.label"}}</label>
|
||||
</div>
|
||||
|
||||
<div class="input-group link-name">
|
||||
<label>{{i18n "sidebar.sections.custom.links.name.label"}}</label>
|
||||
</div>
|
||||
|
||||
<div class="input-group link-url">
|
||||
<label>{{i18n "sidebar.sections.custom.links.value.label"}}</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{#each this.activeLinks as |link|}}
|
||||
<Sidebar::SectionFormLink
|
||||
@link={{link}}
|
||||
|
@ -29,6 +29,7 @@ class Section {
|
||||
id,
|
||||
publicSection,
|
||||
sectionType,
|
||||
hideTitleInput,
|
||||
}) {
|
||||
this.title = title;
|
||||
this.public = publicSection;
|
||||
@ -36,6 +37,7 @@ class Section {
|
||||
this.links = links;
|
||||
this.secondaryLinks = secondaryLinks;
|
||||
this.id = id;
|
||||
this.hideTitleInput = hideTitleInput;
|
||||
}
|
||||
|
||||
get valid() {
|
||||
@ -243,26 +245,29 @@ export default class SidebarSectionForm extends Component {
|
||||
|
||||
@cached
|
||||
get transformedModel() {
|
||||
if (this.model) {
|
||||
const section = this.model?.section;
|
||||
|
||||
if (section) {
|
||||
return new Section({
|
||||
title: this.model.title,
|
||||
publicSection: this.model.public,
|
||||
sectionType: this.model.section_type,
|
||||
links: this.model.links.reduce((acc, link) => {
|
||||
title: section.title,
|
||||
publicSection: section.public,
|
||||
sectionType: section.section_type,
|
||||
links: section.links.reduce((acc, link) => {
|
||||
if (link.segment === "primary") {
|
||||
this.nextObjectId++;
|
||||
acc.push(this.initLink(link));
|
||||
}
|
||||
return acc;
|
||||
}, A()),
|
||||
secondaryLinks: this.model.links.reduce((acc, link) => {
|
||||
secondaryLinks: section.links.reduce((acc, link) => {
|
||||
if (link.segment === "secondary") {
|
||||
this.nextObjectId++;
|
||||
acc.push(this.initLink(link));
|
||||
}
|
||||
return acc;
|
||||
}, A()),
|
||||
id: this.model.id,
|
||||
id: section.id,
|
||||
hideTitleInput: this.model.hideSectionHeader,
|
||||
});
|
||||
} else {
|
||||
return new Section({
|
||||
|
@ -6,6 +6,7 @@
|
||||
@headerActions={{this.section.headerActions}}
|
||||
@headerActionsIcon={{this.section.headerActionIcon}}
|
||||
@class={{this.section.dragCss}}
|
||||
@hideSectionHeader={{this.section.hideSectionHeader}}
|
||||
>
|
||||
{{#each this.section.links as |link|}}
|
||||
{{#if link.externalOrFullReload}}
|
||||
@ -61,12 +62,25 @@
|
||||
{{/each}}
|
||||
|
||||
{{#if this.section.moreLinks}}
|
||||
{{#if this.isDesktopDropdownMode}}
|
||||
{{#if this.navigationMenu.isDesktopDropdownMode}}
|
||||
{{#each this.section.moreLinks as |sectionLink|}}
|
||||
<Sidebar::MoreSectionLink @sectionLink={{sectionLink}} />
|
||||
{{/each}}
|
||||
|
||||
{{#if this.section.moreSectionButtonAction}}
|
||||
<Sidebar::SectionLinkButton
|
||||
@action={{this.section.moreSectionButtonAction}}
|
||||
@icon={{this.section.moreSectionButtonIcon}}
|
||||
@text={{this.section.moreSectionButtonText}}
|
||||
/>
|
||||
{{/if}}
|
||||
{{else if this.section.moreLinks}}
|
||||
<Sidebar::MoreSectionLinks @sectionLinks={{this.section.moreLinks}} />
|
||||
<Sidebar::MoreSectionLinks
|
||||
@sectionLinks={{this.section.moreLinks}}
|
||||
@moreButtonAction={{this.section.moreSectionButtonAction}}
|
||||
@moreButtonText={{this.section.moreSectionButtonText}}
|
||||
@moreButtonIcon={{this.section.moreSectionButtonIcon}}
|
||||
/>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</Sidebar::Section>
|
@ -4,9 +4,12 @@ import { tracked } from "@glimmer/tracking";
|
||||
import { inject as service } from "@ember/service";
|
||||
|
||||
import Section from "discourse/lib/sidebar/section";
|
||||
import CommunitySection from "discourse/lib/sidebar/community-section";
|
||||
import AdminCommunitySection from "discourse/lib/sidebar/user/community-section/admin-section";
|
||||
import CommonCommunitySection from "discourse/lib/sidebar/common/community-section/section";
|
||||
|
||||
export default class SidebarCustomSection extends Component {
|
||||
@service currentUser;
|
||||
@service navigationMenu;
|
||||
@service site;
|
||||
@service siteSettings;
|
||||
|
||||
@ -22,19 +25,14 @@ export default class SidebarCustomSection extends Component {
|
||||
super.willDestroy();
|
||||
}
|
||||
|
||||
get isDesktopDropdownMode() {
|
||||
const headerDropdownMode =
|
||||
this.siteSettings.navigation_menu === "header dropdown";
|
||||
|
||||
return !this.site.mobileView && headerDropdownMode;
|
||||
}
|
||||
|
||||
#initializeSection() {
|
||||
let sectionClass = Section;
|
||||
|
||||
switch (this.args.sectionData.section_type) {
|
||||
case "community":
|
||||
sectionClass = CommunitySection;
|
||||
sectionClass = this.currentUser?.admin
|
||||
? AdminCommunitySection
|
||||
: CommonCommunitySection;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -20,11 +20,21 @@
|
||||
>
|
||||
|
||||
<div class="sidebar-more-section-links-details-content">
|
||||
<div class="sidebar-more-section-links-details-content-main">
|
||||
<ul class="sidebar-more-section-links-details-content-main">
|
||||
{{#each this.sectionLinks as |sectionLink|}}
|
||||
<Sidebar::MoreSectionLink @sectionLink={{sectionLink}} />
|
||||
{{/each}}
|
||||
</div>
|
||||
</ul>
|
||||
|
||||
{{#if @moreButtonAction}}
|
||||
<div class="sidebar-more-section-links-details-content-footer">
|
||||
<Sidebar::SectionLinkButton
|
||||
@action={{@moreButtonAction}}
|
||||
@icon={{@moreButtonIcon}}
|
||||
@text={{@moreButtonText}}
|
||||
/>
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -48,9 +48,9 @@ export default class SidebarMoreSectionLinks extends Component {
|
||||
@bind
|
||||
closeDetails(event) {
|
||||
if (this.open) {
|
||||
const isLinkClick = event.target.className.includes(
|
||||
"sidebar-section-link"
|
||||
);
|
||||
const isLinkClick =
|
||||
event.target.className.includes("sidebar-section-link") ||
|
||||
event.target.className.includes("sidebar-section-link-button");
|
||||
|
||||
if (isLinkClick || this.#isOutsideDetailsClick(event)) {
|
||||
this.open = false;
|
||||
|
@ -0,0 +1,15 @@
|
||||
<div class="sidebar-section-link-wrapper">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-flat sidebar-section-link-button sidebar-row"
|
||||
{{on "click" @action}}
|
||||
>
|
||||
<span class="sidebar-section-link-prefix icon">
|
||||
{{d-icon @icon}}
|
||||
</span>
|
||||
|
||||
<span class="sidebar-section-link-content-text">
|
||||
{{@text}}
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
@ -3,54 +3,59 @@
|
||||
class={{concat-class "sidebar-section-wrapper sidebar-section" @class}}
|
||||
data-section-name={{@sectionName}}
|
||||
>
|
||||
<div class="sidebar-section-header-wrapper sidebar-row">
|
||||
<Sidebar::SectionHeader
|
||||
@collapsable={{@collapsable}}
|
||||
@sidebarSectionContentID={{this.sidebarSectionContentID}}
|
||||
@toggleSectionDisplay={{this.toggleSectionDisplay}}
|
||||
@isExpanded={{this.displaySectionContent}}
|
||||
>
|
||||
{{#if @collapsable}}
|
||||
<span class="sidebar-section-header-caret">
|
||||
{{d-icon this.headerCaretIcon}}
|
||||
{{#unless @hideSectionHeader}}
|
||||
<div class="sidebar-section-header-wrapper sidebar-row">
|
||||
<Sidebar::SectionHeader
|
||||
@collapsable={{@collapsable}}
|
||||
@sidebarSectionContentID={{this.sidebarSectionContentID}}
|
||||
@toggleSectionDisplay={{this.toggleSectionDisplay}}
|
||||
@isExpanded={{this.displaySectionContent}}
|
||||
>
|
||||
{{#if @collapsable}}
|
||||
<span class="sidebar-section-header-caret">
|
||||
{{d-icon this.headerCaretIcon}}
|
||||
</span>
|
||||
{{/if}}
|
||||
|
||||
<span class="sidebar-section-header-text">
|
||||
{{@headerLinkText}}
|
||||
</span>
|
||||
{{#if @indicatePublic}}
|
||||
<span class="sidebar-section-header-global-indicator">
|
||||
{{d-icon "globe"}}
|
||||
<DTooltip @placement="top">{{d-icon "shield-alt"}}
|
||||
{{i18n "sidebar.sections.global_section"}}
|
||||
</DTooltip>
|
||||
</span>
|
||||
{{/if}}
|
||||
</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>
|
||||
{{#if @indicatePublic}}
|
||||
<span class="sidebar-section-header-global-indicator">
|
||||
{{d-icon "globe"}}
|
||||
<DTooltip @placement="top">{{d-icon "shield-alt"}}
|
||||
{{i18n "sidebar.sections.global_section"}}
|
||||
</DTooltip>
|
||||
</span>
|
||||
{{#if this.isMultipleHeaderActions}}
|
||||
<DropdownSelectBox
|
||||
@options={{hash
|
||||
icon=@headerActionsIcon
|
||||
placementStrategy="absolute"
|
||||
}}
|
||||
@content={{@headerActions}}
|
||||
@onChange={{action "handleMultipleHeaderActions"}}
|
||||
@class="sidebar-section-header-dropdown"
|
||||
/>
|
||||
{{/if}}
|
||||
</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}}
|
||||
|
||||
{{#if this.isMultipleHeaderActions}}
|
||||
<DropdownSelectBox
|
||||
@options={{hash icon=@headerActionsIcon placementStrategy="absolute"}}
|
||||
@content={{@headerActions}}
|
||||
@onChange={{action "handleMultipleHeaderActions"}}
|
||||
@class="sidebar-section-header-dropdown"
|
||||
/>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
{{/unless}}
|
||||
|
||||
{{#if this.displaySectionContent}}
|
||||
<ul class="sidebar-section-content" id={{this.sidebarSectionContentID}}>
|
||||
|
@ -1,12 +1,8 @@
|
||||
import I18n from "I18n";
|
||||
import SectionLink from "discourse/lib/sidebar/section-link";
|
||||
import Composer from "discourse/models/composer";
|
||||
import { getOwner, setOwner } from "@ember/application";
|
||||
import { setOwner } from "@ember/application";
|
||||
import { inject as service } from "@ember/service";
|
||||
import { tracked } from "@glimmer/tracking";
|
||||
import { action } from "@ember/object";
|
||||
import { next } from "@ember/runloop";
|
||||
import PermissionType from "discourse/models/permission-type";
|
||||
|
||||
import EverythingSectionLink from "discourse/lib/sidebar/common/community-section/everything-section-link";
|
||||
import MyPostsSectionLink from "discourse/lib/sidebar/user/community-section/my-posts-section-link";
|
||||
import AdminSectionLink from "discourse/lib/sidebar/user/community-section/admin-section-link";
|
||||
@ -20,7 +16,6 @@ import {
|
||||
customSectionLinks,
|
||||
secondaryCustomSectionLinks,
|
||||
} from "discourse/lib/sidebar/custom-community-section-links";
|
||||
import SidebarSectionForm from "discourse/components/modal/sidebar-section-form";
|
||||
|
||||
const SPECIAL_LINKS_MAP = {
|
||||
"/latest": EverythingSectionLink,
|
||||
@ -46,6 +41,7 @@ export default class CommunitySection {
|
||||
@tracked moreLinks;
|
||||
|
||||
reorderable = false;
|
||||
hideSectionHeader = true;
|
||||
|
||||
constructor({ section, owner }) {
|
||||
setOwner(this, owner);
|
||||
@ -137,64 +133,4 @@ export default class CommunitySection {
|
||||
overridenIcon,
|
||||
});
|
||||
}
|
||||
|
||||
get decoratedTitle() {
|
||||
return I18n.t(
|
||||
`sidebar.sections.${this.section.title.toLowerCase()}.header_link_text`,
|
||||
{ defaultValue: this.section.title }
|
||||
);
|
||||
}
|
||||
|
||||
get headerActions() {
|
||||
if (this.currentUser?.admin) {
|
||||
return [
|
||||
{
|
||||
action: this.editSection,
|
||||
title: I18n.t(
|
||||
"sidebar.sections.community.header_action_edit_section_title"
|
||||
),
|
||||
},
|
||||
];
|
||||
}
|
||||
if (this.currentUser) {
|
||||
return [
|
||||
{
|
||||
action: this.composeTopic,
|
||||
title: I18n.t(
|
||||
"sidebar.sections.community.header_action_create_topic_title"
|
||||
),
|
||||
},
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
get headerActionIcon() {
|
||||
return this.currentUser?.admin ? "pencil-alt" : "plus";
|
||||
}
|
||||
|
||||
@action
|
||||
editSection() {
|
||||
return this.modal.show(SidebarSectionForm, {
|
||||
model: this.section,
|
||||
});
|
||||
}
|
||||
|
||||
@action
|
||||
composeTopic() {
|
||||
const composerArgs = {
|
||||
action: Composer.CREATE_TOPIC,
|
||||
draftKey: Composer.NEW_TOPIC_KEY,
|
||||
};
|
||||
|
||||
const controller = getOwner(this).lookup("controller:navigation/category");
|
||||
const category = controller.category;
|
||||
|
||||
if (category && category.permission === PermissionType.FULL) {
|
||||
composerArgs.categoryId = category.id;
|
||||
}
|
||||
|
||||
next(() => {
|
||||
getOwner(this).lookup("controller:composer").open(composerArgs);
|
||||
});
|
||||
}
|
||||
}
|
@ -45,6 +45,7 @@ export default class SectionLink {
|
||||
if (event.button === 0 || event.targetTouches) {
|
||||
this.startMouseY = this.#calcMouseY(event);
|
||||
this.willDrag = true;
|
||||
|
||||
discourseLater(
|
||||
() => {
|
||||
this.delayedStart(event);
|
||||
@ -53,9 +54,11 @@ export default class SectionLink {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
delayedStart(event) {
|
||||
if (this.willDrag) {
|
||||
const currentMouseY = this.#calcMouseY(event);
|
||||
|
||||
if (currentMouseY === this.startMouseY) {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
@ -80,24 +83,29 @@ export default class SectionLink {
|
||||
@bind
|
||||
dragMove(event) {
|
||||
this.startMouseY = this.#calcMouseY(event);
|
||||
|
||||
if (!this.drag) {
|
||||
return;
|
||||
}
|
||||
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
const currentMouseY = this.#calcMouseY(event);
|
||||
const distance = currentMouseY - this.mouseY;
|
||||
|
||||
if (!this.linkHeight) {
|
||||
this.linkHeight = document.getElementsByClassName(
|
||||
"sidebar-section-link-wrapper"
|
||||
)[0].clientHeight;
|
||||
}
|
||||
|
||||
if (distance >= this.linkHeight) {
|
||||
if (this.section.links.indexOf(this) !== this.section.links.length - 1) {
|
||||
this.section.moveLinkDown(this);
|
||||
this.mouseY = currentMouseY;
|
||||
}
|
||||
}
|
||||
|
||||
if (distance <= -this.linkHeight) {
|
||||
if (this.section.links.indexOf(this) !== 0) {
|
||||
this.section.moveLinkUp(this);
|
||||
|
@ -42,7 +42,7 @@ export default class Section {
|
||||
{
|
||||
action: () => {
|
||||
return this.modal.show(SidebarSectionForm, {
|
||||
model: this.section,
|
||||
model: this,
|
||||
});
|
||||
},
|
||||
title: I18n.t("sidebar.sections.custom.edit"),
|
||||
@ -78,6 +78,7 @@ export default class Section {
|
||||
this.links = this.links.removeObject(link);
|
||||
this.links.splice(position, 0, link);
|
||||
}
|
||||
|
||||
@bind
|
||||
reorder() {
|
||||
return ajax(`/sidebar_sections/reorder`, {
|
||||
|
@ -0,0 +1,30 @@
|
||||
import I18n from "I18n";
|
||||
import { action } from "@ember/object";
|
||||
import { inject as service } from "@ember/service";
|
||||
|
||||
import CommonCommunitySection from "discourse/lib/sidebar/common/community-section/section";
|
||||
import SidebarSectionForm from "discourse/components/modal/sidebar-section-form";
|
||||
|
||||
export default class extends CommonCommunitySection {
|
||||
@service modal;
|
||||
@service navigationMenu;
|
||||
|
||||
@action
|
||||
moreSectionButtonAction() {
|
||||
return this.modal.show(SidebarSectionForm, { model: this });
|
||||
}
|
||||
|
||||
get moreSectionButtonText() {
|
||||
return I18n.t(
|
||||
`sidebar.sections.community.edit_section.${
|
||||
this.navigationMenu.isDesktopDropdownMode
|
||||
? "header_dropdown"
|
||||
: "sidebar"
|
||||
}`
|
||||
);
|
||||
}
|
||||
|
||||
get moreSectionButtonIcon() {
|
||||
return "pencil-alt";
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
import Service, { inject as service } from "@ember/service";
|
||||
|
||||
export default class NavigationMenu extends Service {
|
||||
@service site;
|
||||
@service siteSettings;
|
||||
|
||||
get isDesktopDropdownMode() {
|
||||
const headerDropdownMode =
|
||||
this.siteSettings.navigation_menu === "header dropdown";
|
||||
|
||||
return !this.site.mobileView && headerDropdownMode;
|
||||
}
|
||||
}
|
@ -386,6 +386,7 @@ createWidget("revamped-hamburger-menu-wrapper", {
|
||||
click(event) {
|
||||
if (
|
||||
event.target.closest(".sidebar-section-header-button") ||
|
||||
event.target.closest(".sidebar-section-link-button") ||
|
||||
event.target.closest(".sidebar-section-link")
|
||||
) {
|
||||
this.sendWidgetAction("toggleHamburger");
|
||||
|
@ -46,72 +46,6 @@ acceptance("Sidebar - Logged on user - Community Section", function (needs) {
|
||||
});
|
||||
});
|
||||
|
||||
test("clicking on section header button", async function (assert) {
|
||||
await visit("/");
|
||||
|
||||
await click(
|
||||
".sidebar-section[data-section-name='community'] .sidebar-section-header-button"
|
||||
);
|
||||
|
||||
assert.ok(exists("#reply-control"), "it opens the composer");
|
||||
});
|
||||
|
||||
test("clicking on section header button while viewing a category", async function (assert) {
|
||||
await visit("/c/bug");
|
||||
await click(
|
||||
".sidebar-section[data-section-name='community'] .sidebar-section-header-button"
|
||||
);
|
||||
|
||||
assert.ok(exists("#reply-control"), "it opens the composer");
|
||||
|
||||
assert.strictEqual(
|
||||
query(".category-input .selected-name .category-name").textContent,
|
||||
"bug",
|
||||
"the current category is prefilled in the composer input"
|
||||
);
|
||||
});
|
||||
|
||||
test("clicking on section header link", async function (assert) {
|
||||
await visit("/t/280");
|
||||
|
||||
assert.ok(
|
||||
exists(
|
||||
".sidebar-section[data-section-name='community'] .sidebar-section-content"
|
||||
),
|
||||
"shows content section"
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
query(
|
||||
".sidebar-section[data-section-name='community'] .sidebar-section-header"
|
||||
).title,
|
||||
I18n.t("sidebar.toggle_section"),
|
||||
"caret has the right title"
|
||||
);
|
||||
|
||||
await click(
|
||||
".sidebar-section[data-section-name='community'] .sidebar-section-header"
|
||||
);
|
||||
|
||||
assert.notOk(
|
||||
exists(
|
||||
".sidebar-section[data-section-name='community'] .sidebar-section-content"
|
||||
),
|
||||
"hides the content of the section"
|
||||
);
|
||||
|
||||
await click(
|
||||
".sidebar-section[data-section-name='community'] .sidebar-section-header"
|
||||
);
|
||||
|
||||
assert.ok(
|
||||
exists(
|
||||
".sidebar-section[data-section-name='community'] .sidebar-section-content"
|
||||
),
|
||||
"shows content section"
|
||||
);
|
||||
});
|
||||
|
||||
test("clicking on more... link", async function (assert) {
|
||||
await visit("/");
|
||||
|
||||
|
@ -208,7 +208,7 @@ acceptance(
|
||||
|
||||
assert.ok(
|
||||
exists(
|
||||
".sidebar-section[data-section-name='community'] .sidebar-section-header[aria-expanded='true'][aria-controls='sidebar-section-content-community']"
|
||||
".sidebar-section[data-section-name='categories'] .sidebar-section-header[aria-expanded='true'][aria-controls='sidebar-section-content-categories']"
|
||||
),
|
||||
"accessibility attributes are set correctly on sidebar section header when section is expanded"
|
||||
);
|
||||
@ -217,7 +217,7 @@ acceptance(
|
||||
|
||||
assert.ok(
|
||||
exists(
|
||||
".sidebar-section[data-section-name='community'] .sidebar-section-header[aria-expanded='false'][aria-controls='sidebar-section-content-community']"
|
||||
".sidebar-section[data-section-name='categories'] .sidebar-section-header[aria-expanded='false'][aria-controls='sidebar-section-content-categories']"
|
||||
),
|
||||
"accessibility attributes are set correctly on sidebar section header when section is collapsed"
|
||||
);
|
||||
|
@ -7,6 +7,7 @@
|
||||
color: var(--d-sidebar-highlight-color);
|
||||
}
|
||||
}
|
||||
|
||||
height: var(--d-sidebar-row-height);
|
||||
color: var(--d-sidebar-link-color);
|
||||
display: flex;
|
||||
@ -23,6 +24,7 @@
|
||||
font-size: var(--font-down-1);
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar-more-section-links-details-content {
|
||||
background-color: var(--d-sidebar-background);
|
||||
transition: background-color 0.25s;
|
||||
@ -34,14 +36,28 @@
|
||||
padding: 0.33rem calc(var(--d-sidebar-row-horizontal-padding) / 3);
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar-more-section-links-details-content-main {
|
||||
position: sticky;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.sidebar-more-section-links-details-content-footer {
|
||||
border-top: 2px solid var(--primary-low);
|
||||
display: flex;
|
||||
width: 100%;
|
||||
|
||||
.sidebar-section-link-wrapper {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar-more-section-links-details-content-wrapper {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
z-index: z("modal", "content") + 1;
|
||||
}
|
||||
|
||||
.sidebar-more-section-links-details {
|
||||
position: relative;
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
:root {
|
||||
--d-sidebar-section-link-prefix-margin-right: 0.35rem;
|
||||
--d-sidebar-section-link-prefix-width: 1.35rem;
|
||||
--d-sidebar-section-link-icon-size: 0.8em;
|
||||
}
|
||||
|
||||
.sidebar-section-link-wrapper {
|
||||
@ -81,6 +82,26 @@
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar-section-link-button {
|
||||
color: var(--d-sidebar-link-color);
|
||||
background-color: var(--secondary);
|
||||
width: 100%;
|
||||
justify-content: flex-start;
|
||||
|
||||
&:hover {
|
||||
color: var(--d-sidebar-link-color);
|
||||
background-color: var(--primary-low);
|
||||
|
||||
.d-icon {
|
||||
color: var(--d-sidebar-link-icon-color);
|
||||
}
|
||||
}
|
||||
|
||||
.d-icon {
|
||||
color: var(--d-sidebar-link-icon-color);
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar-section-link[data-link-name="personal-messages-sent"],
|
||||
.sidebar-section-link[data-link-name="personal-messages-new"],
|
||||
.sidebar-section-link[data-link-name="personal-messages-archive"],
|
||||
@ -130,7 +151,7 @@
|
||||
color: var(--d-sidebar-link-icon-color);
|
||||
|
||||
svg {
|
||||
font-size: 0.8em;
|
||||
font-size: var(--d-sidebar-section-link-icon-size);
|
||||
}
|
||||
|
||||
.prefix-badge {
|
||||
|
@ -128,6 +128,7 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar-section-form-modal {
|
||||
.draggable {
|
||||
display: flex;
|
||||
@ -162,6 +163,15 @@
|
||||
.value.warning {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.sidebar-section-form__input-wrapper {
|
||||
margin-bottom: 1em;
|
||||
|
||||
input {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.row-wrapper {
|
||||
display: grid;
|
||||
grid-template-columns: 2em 4.5em repeat(2, 1fr) 2em;
|
||||
@ -172,9 +182,10 @@
|
||||
border-top: 2px solid transparent;
|
||||
border-bottom: 2px solid transparent;
|
||||
margin-bottom: -2px;
|
||||
|
||||
&.header {
|
||||
padding-bottom: 0;
|
||||
padding-top: 1em;
|
||||
|
||||
label {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
@ -4473,9 +4473,9 @@ en:
|
||||
header_action_title: "Edit your sidebar categories"
|
||||
configure_defaults: "Configure defaults"
|
||||
community:
|
||||
header_link_text: "Community"
|
||||
header_action_create_topic_title: "Create a topic"
|
||||
header_action_edit_section_title: "Edit Community section"
|
||||
edit_section:
|
||||
sidebar: "Customize this section"
|
||||
header_dropdown: "Customize"
|
||||
links:
|
||||
about:
|
||||
content: "About"
|
||||
|
@ -3,7 +3,7 @@
|
||||
RSpec.describe "Deleted message", type: :system do
|
||||
let(:chat_page) { PageObjects::Pages::Chat.new }
|
||||
let(:channel_page) { PageObjects::Pages::ChatChannel.new }
|
||||
let(:sidebar_component) { PageObjects::Components::Sidebar.new }
|
||||
let(:sidebar_component) { PageObjects::Components::NavigationMenu::Sidebar.new }
|
||||
|
||||
fab!(:current_user) { Fabricate(:admin) }
|
||||
fab!(:channel_1) { Fabricate(:category_channel) }
|
||||
|
@ -14,7 +14,7 @@ RSpec.describe "Navigation", type: :system do
|
||||
let(:channel_page) { PageObjects::Pages::ChatChannel.new }
|
||||
let(:side_panel_page) { PageObjects::Pages::ChatSidePanel.new }
|
||||
let(:sidebar_page) { PageObjects::Pages::Sidebar.new }
|
||||
let(:sidebar_component) { PageObjects::Components::Sidebar.new }
|
||||
let(:sidebar_component) { PageObjects::Components::NavigationMenu::Sidebar.new }
|
||||
let(:chat_drawer_page) { PageObjects::Pages::ChatDrawer.new }
|
||||
|
||||
before do
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
RSpec.describe "Sidebar navigation menu", type: :system do
|
||||
let(:sidebar_page) { PageObjects::Pages::Sidebar.new }
|
||||
let(:sidebar_component) { PageObjects::Components::Sidebar.new }
|
||||
let(:sidebar_component) { PageObjects::Components::NavigationMenu::Sidebar.new }
|
||||
|
||||
fab!(:current_user) { Fabricate(:user) }
|
||||
|
||||
|
@ -4,7 +4,7 @@ describe "Custom sidebar sections", type: :system do
|
||||
fab!(:user) { Fabricate(:user) }
|
||||
fab!(:admin) { Fabricate(:admin) }
|
||||
let(:section_modal) { PageObjects::Modals::SidebarSectionForm.new }
|
||||
let(:sidebar) { PageObjects::Components::Sidebar.new }
|
||||
let(:sidebar) { PageObjects::Components::NavigationMenu::Sidebar.new }
|
||||
|
||||
before { user.user_option.update!(external_links_in_new_tab: true) }
|
||||
|
||||
@ -112,24 +112,36 @@ describe "Custom sidebar sections", type: :system do
|
||||
|
||||
it "allows the user to reorder links in custom section" do
|
||||
sidebar_section = Fabricate(:sidebar_section, title: "My section", user: user)
|
||||
sidebar_url_1 = Fabricate(:sidebar_url, name: "Sidebar Tags", value: "/tags")
|
||||
Fabricate(:sidebar_section_link, sidebar_section: sidebar_section, linkable: sidebar_url_1)
|
||||
sidebar_url_2 = Fabricate(:sidebar_url, name: "Sidebar Categories", value: "/categories")
|
||||
Fabricate(:sidebar_section_link, sidebar_section: sidebar_section, linkable: sidebar_url_2)
|
||||
|
||||
sidebar_url_1 =
|
||||
Fabricate(:sidebar_url, name: "Sidebar Tags", value: "/tags").tap do |sidebar_url|
|
||||
Fabricate(:sidebar_section_link, sidebar_section: sidebar_section, linkable: sidebar_url)
|
||||
end
|
||||
|
||||
sidebar_url_2 =
|
||||
Fabricate(:sidebar_url, name: "Sidebar Categories", value: "/categories").tap do |sidebar_url|
|
||||
Fabricate(:sidebar_section_link, sidebar_section: sidebar_section, linkable: sidebar_url)
|
||||
end
|
||||
|
||||
sidebar_url_3 =
|
||||
Fabricate(:sidebar_url, name: "Sidebar Latest", value: "/latest").tap do |sidebar_url|
|
||||
Fabricate(:sidebar_section_link, sidebar_section: sidebar_section, linkable: sidebar_url)
|
||||
end
|
||||
|
||||
sign_in user
|
||||
|
||||
visit("/latest")
|
||||
|
||||
expect(sidebar.primary_section_links("my-section")).to eq(
|
||||
["Sidebar Tags", "Sidebar Categories"],
|
||||
["Sidebar Tags", "Sidebar Categories", "Sidebar Latest"],
|
||||
)
|
||||
|
||||
tags_link = find(".sidebar-section-link[data-link-name='Sidebar Tags']")
|
||||
categories_link = find(".sidebar-section-link[data-link-name='Sidebar Categories']")
|
||||
tags_link.drag_to(categories_link, html5: true, delay: 0.4)
|
||||
latest_link = find(".sidebar-section-link[data-link-name='Sidebar Latest']")
|
||||
tags_link.drag_to(latest_link, html5: true, delay: 0.4)
|
||||
|
||||
expect(sidebar.primary_section_links("my-section")).to eq(
|
||||
["Sidebar Categories", "Sidebar Tags"],
|
||||
["Sidebar Categories", "Sidebar Tags", "Sidebar Latest"],
|
||||
)
|
||||
end
|
||||
|
||||
@ -199,40 +211,6 @@ describe "Custom sidebar sections", type: :system do
|
||||
expect(sidebar).to have_no_section("Edited public section")
|
||||
end
|
||||
|
||||
it "allows admin to edit community section and reset to default" do
|
||||
sign_in admin
|
||||
visit("/latest")
|
||||
|
||||
expect(sidebar.primary_section_icons("community")).to eq(
|
||||
%w[layer-group user flag wrench ellipsis-v],
|
||||
)
|
||||
|
||||
sidebar.edit_custom_section("Community")
|
||||
section_modal.fill_link("Topics", "/latest", "paper-plane")
|
||||
section_modal.fill_name("Edited community section")
|
||||
section_modal.topics_link.drag_to(section_modal.review_link, delay: 0.4)
|
||||
section_modal.save
|
||||
|
||||
expect(sidebar).to have_section("Edited community section")
|
||||
expect(sidebar.primary_section_links("edited-community-section")).to eq(
|
||||
["My Posts", "Topics", "Review", "Admin", "More"],
|
||||
)
|
||||
expect(sidebar.primary_section_icons("edited-community-section")).to eq(
|
||||
%w[user paper-plane flag wrench ellipsis-v],
|
||||
)
|
||||
|
||||
sidebar.edit_custom_section("Edited community section")
|
||||
section_modal.reset
|
||||
|
||||
expect(sidebar).to have_section("Community")
|
||||
expect(sidebar.primary_section_links("community")).to eq(
|
||||
["Topics", "My Posts", "Review", "Admin", "More"],
|
||||
)
|
||||
expect(sidebar.primary_section_icons("community")).to eq(
|
||||
%w[layer-group user flag wrench ellipsis-v],
|
||||
)
|
||||
end
|
||||
|
||||
it "shows anonymous public sections" do
|
||||
sidebar_section = Fabricate(:sidebar_section, title: "Public section", public: true)
|
||||
sidebar_url_1 = Fabricate(:sidebar_url, name: "Sidebar Tags", value: "/tags")
|
||||
|
@ -19,7 +19,7 @@ RSpec.describe "Editing sidebar categories navigation", type: :system do
|
||||
Fabricate(:category, parent_category_id: category.id, name: "category subcategory")
|
||||
end
|
||||
|
||||
let(:sidebar) { PageObjects::Components::Sidebar.new }
|
||||
let(:sidebar) { PageObjects::Components::NavigationMenu::Sidebar.new }
|
||||
|
||||
before { sign_in(user) }
|
||||
|
||||
|
67
spec/system/editing_sidebar_community_section_spec.rb
Normal file
67
spec/system/editing_sidebar_community_section_spec.rb
Normal file
@ -0,0 +1,67 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
RSpec.describe "Editing Sidebar Community Section", type: :system do
|
||||
fab!(:admin) { Fabricate(:admin) }
|
||||
fab!(:user) { Fabricate(:user) }
|
||||
|
||||
let(:sidebar) { PageObjects::Components::NavigationMenu::Sidebar.new }
|
||||
let(:sidebar_header_dropdown) { PageObjects::Components::NavigationMenu::HeaderDropdown.new }
|
||||
|
||||
it "should not display the edit section button to non admins" do
|
||||
sign_in(user)
|
||||
|
||||
visit("/latest")
|
||||
|
||||
sidebar.click_community_section_more_button
|
||||
|
||||
expect(sidebar).to have_no_customize_community_section_button
|
||||
end
|
||||
|
||||
it "allows admin to edit community section and reset to default" do
|
||||
sign_in(admin)
|
||||
|
||||
visit("/latest")
|
||||
|
||||
expect(sidebar.primary_section_icons("community")).to eq(
|
||||
%w[layer-group user flag wrench ellipsis-v],
|
||||
)
|
||||
|
||||
modal = sidebar.click_community_section_more_button.click_customize_community_section_button
|
||||
modal.fill_link("Topics", "/latest", "paper-plane")
|
||||
modal.topics_link.drag_to(modal.review_link, delay: 0.4)
|
||||
modal.save
|
||||
|
||||
expect(sidebar.primary_section_links("community")).to eq(
|
||||
["My Posts", "Topics", "Review", "Admin", "More"],
|
||||
)
|
||||
|
||||
expect(sidebar.primary_section_icons("community")).to eq(
|
||||
%w[user paper-plane flag wrench ellipsis-v],
|
||||
)
|
||||
|
||||
modal = sidebar.click_community_section_more_button.click_customize_community_section_button
|
||||
modal.reset
|
||||
|
||||
expect(sidebar).to have_section("Community")
|
||||
|
||||
expect(sidebar.primary_section_links("community")).to eq(
|
||||
["Topics", "My Posts", "Review", "Admin", "More"],
|
||||
)
|
||||
|
||||
expect(sidebar.primary_section_icons("community")).to eq(
|
||||
%w[layer-group user flag wrench ellipsis-v],
|
||||
)
|
||||
end
|
||||
|
||||
it "should allow admins to open modal to edit the section when `navigation_menu` site setting is `header dropdown`" do
|
||||
SiteSetting.navigation_menu = "header dropdown"
|
||||
|
||||
sign_in(admin)
|
||||
|
||||
visit("/latest")
|
||||
|
||||
modal = sidebar_header_dropdown.open.click_customize_community_section_button
|
||||
|
||||
expect(modal).to be_visible
|
||||
end
|
||||
end
|
@ -24,7 +24,7 @@ RSpec.describe "Editing sidebar tags navigation", type: :system do
|
||||
# This tag should not be displayed in the modal as it has not been used in a topic
|
||||
fab!(:tag5) { Fabricate(:tag, name: "tag5") }
|
||||
|
||||
let(:sidebar) { PageObjects::Components::Sidebar.new }
|
||||
let(:sidebar) { PageObjects::Components::NavigationMenu::Sidebar.new }
|
||||
|
||||
before { sign_in(user) }
|
||||
|
||||
|
129
spec/system/page_objects/components/navigation_menu/base.rb
Normal file
129
spec/system/page_objects/components/navigation_menu/base.rb
Normal file
@ -0,0 +1,129 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module PageObjects
|
||||
module Components
|
||||
module NavigationMenu
|
||||
class Base < PageObjects::Components::Base
|
||||
def community_section
|
||||
find(".sidebar-section[data-section-name='community']")
|
||||
end
|
||||
|
||||
SIDEBAR_SECTION_LINK_SELECTOR = "sidebar-section-link"
|
||||
|
||||
def click_section_link(name)
|
||||
find(".#{SIDEBAR_SECTION_LINK_SELECTOR}", text: name).click
|
||||
end
|
||||
|
||||
def has_one_active_section_link?
|
||||
has_css?(".#{SIDEBAR_SECTION_LINK_SELECTOR}--active", count: 1)
|
||||
end
|
||||
|
||||
def has_section_link?(name, href: nil, active: false, target: nil)
|
||||
section_link_present?(name, href: href, active: active, target: target, present: true)
|
||||
end
|
||||
|
||||
def has_no_section_link?(name, href: nil, active: false)
|
||||
section_link_present?(name, href: href, active: active, present: false)
|
||||
end
|
||||
def has_section?(name)
|
||||
has_css?(".sidebar-sections [data-section-name='#{name.parameterize}']")
|
||||
end
|
||||
|
||||
def has_no_section?(name)
|
||||
has_no_css?(".sidebar-sections [data-section-name='#{name.parameterize}']")
|
||||
end
|
||||
|
||||
def has_categories_section?
|
||||
has_section?("Categories")
|
||||
end
|
||||
|
||||
def has_tags_section?
|
||||
has_section?("Tags")
|
||||
end
|
||||
|
||||
def has_no_tags_section?
|
||||
has_no_section?("Tags")
|
||||
end
|
||||
|
||||
def has_all_tags_section_link?
|
||||
has_section_link?(I18n.t("js.sidebar.all_tags"))
|
||||
end
|
||||
|
||||
def has_tag_section_links?(tags)
|
||||
tag_names = tags.map(&:name)
|
||||
|
||||
tag_section_links =
|
||||
all(
|
||||
".sidebar-section[data-section-name='tags'] .sidebar-section-link-wrapper[data-tag-name]",
|
||||
count: tag_names.length,
|
||||
)
|
||||
|
||||
expect(tag_section_links.map(&:text)).to eq(tag_names)
|
||||
end
|
||||
|
||||
def primary_section_links(slug)
|
||||
all("[data-section-name='#{slug}'] .sidebar-section-link-wrapper").map(&:text)
|
||||
end
|
||||
|
||||
def primary_section_icons(slug)
|
||||
all("[data-section-name='#{slug}'] .sidebar-section-link-wrapper use").map do |icon|
|
||||
icon[:href].delete_prefix("#")
|
||||
end
|
||||
end
|
||||
|
||||
def has_category_section_link?(category)
|
||||
page.has_link?(category.name, class: "sidebar-section-link")
|
||||
end
|
||||
|
||||
def click_add_section_button
|
||||
click_button(add_section_button_text)
|
||||
end
|
||||
|
||||
def has_no_add_section_button?
|
||||
page.has_no_button?(add_section_button_text)
|
||||
end
|
||||
|
||||
def click_edit_categories_button
|
||||
within(".sidebar-section[data-section-name='categories']") do
|
||||
click_button(class: "sidebar-section-header-button", visible: false)
|
||||
end
|
||||
|
||||
PageObjects::Modals::SidebarEditCategories.new
|
||||
end
|
||||
|
||||
def click_edit_tags_button
|
||||
within(".sidebar-section[data-section-name='tags']") do
|
||||
click_button(class: "sidebar-section-header-button", visible: false)
|
||||
end
|
||||
|
||||
PageObjects::Modals::SidebarEditTags.new
|
||||
end
|
||||
|
||||
def edit_custom_section(name)
|
||||
name = name.parameterize
|
||||
|
||||
find(".sidebar-section[data-section-name='#{name}']").hover
|
||||
|
||||
find(
|
||||
".sidebar-section[data-section-name='#{name}'] button.sidebar-section-header-button",
|
||||
).click
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def section_link_present?(name, href: nil, active: false, target: nil, present:)
|
||||
attributes = { exact_text: name }
|
||||
attributes[:href] = href if href
|
||||
attributes[:class] = SIDEBAR_SECTION_LINK_SELECTOR
|
||||
attributes[:class] += "--active" if active
|
||||
attributes[:target] = target if target
|
||||
page.public_send(present ? :has_link? : :has_no_link?, **attributes)
|
||||
end
|
||||
|
||||
def add_section_button_text
|
||||
I18n.t("js.sidebar.sections.custom.add")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -0,0 +1,25 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module PageObjects
|
||||
module Components
|
||||
module NavigationMenu
|
||||
class HeaderDropdown < Base
|
||||
def open
|
||||
find(".header-dropdown-toggle.hamburger-dropdown").click
|
||||
expect(page).to have_css(".sidebar-hamburger-dropdown")
|
||||
self
|
||||
end
|
||||
|
||||
def click_customize_community_section_button
|
||||
community_section.click_button(
|
||||
I18n.t("js.sidebar.sections.community.edit_section.header_dropdown"),
|
||||
)
|
||||
|
||||
expect(page).to have_no_css(".sidebar-hamburger-dropdown")
|
||||
|
||||
PageObjects::Modals::SidebarSectionForm.new
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -0,0 +1,45 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module PageObjects
|
||||
module Components
|
||||
module NavigationMenu
|
||||
class Sidebar < Base
|
||||
def open_on_mobile
|
||||
click_button("toggle-hamburger-menu")
|
||||
end
|
||||
|
||||
def visible?
|
||||
page.has_css?("#d-sidebar")
|
||||
end
|
||||
|
||||
def not_visible?
|
||||
page.has_no_css?("#d-sidebar")
|
||||
end
|
||||
|
||||
def has_no_customize_community_section_button?
|
||||
community_section.has_no_button?(class: "sidebar-section-link-button")
|
||||
end
|
||||
|
||||
def click_customize_community_section_button
|
||||
community_section.click_button(
|
||||
I18n.t("js.sidebar.sections.community.edit_section.sidebar"),
|
||||
)
|
||||
|
||||
expect(community_section).to have_no_css(".sidebar-more-section-links-details")
|
||||
|
||||
PageObjects::Modals::SidebarSectionForm.new
|
||||
end
|
||||
|
||||
def click_community_section_more_button
|
||||
community_section.click_button(class: "sidebar-more-section-links-details-summary")
|
||||
expect(community_section).to have_css(".sidebar-more-section-links-details")
|
||||
self
|
||||
end
|
||||
|
||||
def custom_section_modal_title
|
||||
find("#discourse-modal-title")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -1,138 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module PageObjects
|
||||
module Components
|
||||
class Sidebar < PageObjects::Components::Base
|
||||
def open_on_mobile
|
||||
click_button("toggle-hamburger-menu")
|
||||
end
|
||||
|
||||
def visible?
|
||||
page.has_css?("#d-sidebar")
|
||||
end
|
||||
|
||||
def not_visible?
|
||||
page.has_no_css?("#d-sidebar")
|
||||
end
|
||||
|
||||
def has_category_section_link?(category)
|
||||
page.has_link?(category.name, class: "sidebar-section-link")
|
||||
end
|
||||
|
||||
def click_add_section_button
|
||||
click_button(add_section_button_text)
|
||||
end
|
||||
|
||||
def has_no_add_section_button?
|
||||
page.has_no_button?(add_section_button_text)
|
||||
end
|
||||
|
||||
def click_edit_categories_button
|
||||
within(".sidebar-section[data-section-name='categories']") do
|
||||
click_button(class: "sidebar-section-header-button", visible: false)
|
||||
end
|
||||
|
||||
PageObjects::Modals::SidebarEditCategories.new
|
||||
end
|
||||
|
||||
def click_edit_tags_button
|
||||
within(".sidebar-section[data-section-name='tags']") do
|
||||
click_button(class: "sidebar-section-header-button", visible: false)
|
||||
end
|
||||
|
||||
PageObjects::Modals::SidebarEditTags.new
|
||||
end
|
||||
|
||||
def edit_custom_section(name)
|
||||
find(".sidebar-section[data-section-name='#{name.parameterize}']").hover
|
||||
|
||||
find(
|
||||
".sidebar-section[data-section-name='#{name.parameterize}'] button.sidebar-section-header-button",
|
||||
).click
|
||||
end
|
||||
|
||||
SIDEBAR_SECTION_LINK_SELECTOR = "sidebar-section-link"
|
||||
|
||||
def click_section_link(name)
|
||||
find(".#{SIDEBAR_SECTION_LINK_SELECTOR}", text: name).click
|
||||
end
|
||||
|
||||
def has_one_active_section_link?
|
||||
has_css?(".#{SIDEBAR_SECTION_LINK_SELECTOR}--active", count: 1)
|
||||
end
|
||||
|
||||
def has_section_link?(name, href: nil, active: false, target: nil)
|
||||
section_link_present?(name, href: href, active: active, target: target, present: true)
|
||||
end
|
||||
|
||||
def has_no_section_link?(name, href: nil, active: false)
|
||||
section_link_present?(name, href: href, active: active, present: false)
|
||||
end
|
||||
|
||||
def custom_section_modal_title
|
||||
find("#discourse-modal-title")
|
||||
end
|
||||
|
||||
def has_section?(name)
|
||||
has_css?(".sidebar-sections [data-section-name='#{name.parameterize}']")
|
||||
end
|
||||
|
||||
def has_no_section?(name)
|
||||
has_no_css?(".sidebar-sections [data-section-name='#{name.parameterize}']")
|
||||
end
|
||||
|
||||
def has_categories_section?
|
||||
has_section?("Categories")
|
||||
end
|
||||
|
||||
def has_tags_section?
|
||||
has_section?("Tags")
|
||||
end
|
||||
|
||||
def has_no_tags_section?
|
||||
has_no_section?("Tags")
|
||||
end
|
||||
|
||||
def has_all_tags_section_link?
|
||||
has_section_link?(I18n.t("js.sidebar.all_tags"))
|
||||
end
|
||||
|
||||
def has_tag_section_links?(tags)
|
||||
tag_names = tags.map(&:name)
|
||||
|
||||
tag_section_links =
|
||||
all(
|
||||
".sidebar-section[data-section-name='tags'] .sidebar-section-link-wrapper[data-tag-name]",
|
||||
count: tag_names.length,
|
||||
)
|
||||
|
||||
expect(tag_section_links.map(&:text)).to eq(tag_names)
|
||||
end
|
||||
|
||||
def primary_section_links(slug)
|
||||
all("[data-section-name='#{slug}'] .sidebar-section-link-wrapper").map(&:text)
|
||||
end
|
||||
|
||||
def primary_section_icons(slug)
|
||||
all("[data-section-name='#{slug}'] .sidebar-section-link-wrapper use").map do |icon|
|
||||
icon[:href].delete_prefix("#")
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def section_link_present?(name, href: nil, active: false, target: nil, present:)
|
||||
attributes = { exact_text: name }
|
||||
attributes[:href] = href if href
|
||||
attributes[:class] = SIDEBAR_SECTION_LINK_SELECTOR
|
||||
attributes[:class] += "--active" if active
|
||||
attributes[:target] = target if target
|
||||
page.public_send(present ? :has_link? : :has_no_link?, **attributes)
|
||||
end
|
||||
|
||||
def add_section_button_text
|
||||
I18n.t("js.sidebar.sections.custom.add")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -23,9 +23,9 @@ module PageObjects
|
||||
page.has_no_css?(".sidebar-footer-actions-keyboard-shortcuts")
|
||||
end
|
||||
|
||||
def click_community_header_button
|
||||
def click_categories_header_button
|
||||
page.click_button(
|
||||
I18n.t("js.sidebar.sections.community.header_action_create_topic_title"),
|
||||
I18n.t("js.sidebar.sections.categories.header_action_title"),
|
||||
class: "sidebar-section-header-button",
|
||||
)
|
||||
end
|
||||
|
@ -34,16 +34,24 @@ module PageObjects
|
||||
def reset
|
||||
find(".reset-link").click
|
||||
find(".dialog-footer .btn-primary").click
|
||||
closed?
|
||||
self
|
||||
end
|
||||
|
||||
def save
|
||||
find("#save-section").click
|
||||
closed?
|
||||
self
|
||||
end
|
||||
|
||||
def visible?
|
||||
page.has_css?(".sidebar-section-form-modal")
|
||||
end
|
||||
|
||||
def closed?
|
||||
page.has_no_css?(".sidebar-section-form-modal")
|
||||
end
|
||||
|
||||
def has_disabled_save?
|
||||
find_button("Save", disabled: true)
|
||||
end
|
||||
|
@ -25,7 +25,7 @@ describe "Viewing sidebar as anonymous user", type: :system do
|
||||
Fabricate(:tag, name: "tag 6").tap { |tag| Fabricate.times(1, :topic, tags: [tag]) }
|
||||
end
|
||||
|
||||
let(:sidebar) { PageObjects::Components::Sidebar.new }
|
||||
let(:sidebar) { PageObjects::Components::NavigationMenu::Sidebar.new }
|
||||
|
||||
describe "when viewing the tags section" do
|
||||
it "should not display the tags section when tagging has been disabled" do
|
||||
|
@ -53,9 +53,8 @@ describe "Viewing sidebar mobile", type: :system, mobile: true do
|
||||
|
||||
expect(sidebar_dropdown).to be_visible
|
||||
|
||||
sidebar_dropdown.click_community_header_button
|
||||
sidebar_dropdown.click_categories_header_button
|
||||
|
||||
expect(composer).to be_opened
|
||||
expect(sidebar_dropdown).to be_hidden
|
||||
end
|
||||
|
||||
|
@ -5,6 +5,8 @@ describe "Viewing sidebar", type: :system do
|
||||
fab!(:user) { Fabricate(:user) }
|
||||
fab!(:category_sidebar_section_link) { Fabricate(:category_sidebar_section_link, user: user) }
|
||||
|
||||
let(:sidebar) { PageObjects::Components::NavigationMenu::Sidebar.new }
|
||||
|
||||
before { sign_in(user) }
|
||||
|
||||
describe "when using the legacy navigation menu" do
|
||||
@ -13,8 +15,6 @@ describe "Viewing sidebar", type: :system do
|
||||
it "should display the sidebar when `navigation_menu` query param is 'sidebar'" do
|
||||
visit("/latest?navigation_menu=sidebar")
|
||||
|
||||
sidebar = PageObjects::Components::Sidebar.new
|
||||
|
||||
expect(sidebar).to be_visible
|
||||
expect(sidebar).to have_category_section_link(category_sidebar_section_link.linkable)
|
||||
expect(page).not_to have_css(".hamburger-dropdown")
|
||||
@ -23,8 +23,6 @@ describe "Viewing sidebar", type: :system do
|
||||
it "should display the sidebar dropdown menu when `navigation_menu` query param is 'header_dropdown'" do
|
||||
visit("/latest?navigation_menu=header_dropdown")
|
||||
|
||||
sidebar = PageObjects::Components::Sidebar.new
|
||||
|
||||
expect(sidebar).to be_not_visible
|
||||
|
||||
header_dropdown = PageObjects::Components::SidebarHeaderDropdown.new
|
||||
@ -40,8 +38,6 @@ describe "Viewing sidebar", type: :system do
|
||||
it "should display the sidebar when `navigation_menu` query param is 'sidebar'" do
|
||||
visit("/latest?navigation_menu=sidebar")
|
||||
|
||||
sidebar = PageObjects::Components::Sidebar.new
|
||||
|
||||
expect(sidebar).to be_visible
|
||||
expect(page).not_to have_css(".hamburger-dropdown")
|
||||
end
|
||||
@ -49,8 +45,6 @@ describe "Viewing sidebar", type: :system do
|
||||
it "should display the legacy dropdown menu when `navigation_menu` query param is 'legacy'" do
|
||||
visit("/latest?navigation_menu=legacy")
|
||||
|
||||
sidebar = PageObjects::Components::Sidebar.new
|
||||
|
||||
expect(sidebar).to be_not_visible
|
||||
|
||||
legacy_header_dropdown = PageObjects::Components::LegacyHeaderDropdown.new
|
||||
@ -66,8 +60,6 @@ describe "Viewing sidebar", type: :system do
|
||||
it "should display the legacy dropdown menu when `navigation_menu` query param is 'legacy'" do
|
||||
visit("/latest?navigation_menu=legacy")
|
||||
|
||||
sidebar = PageObjects::Components::Sidebar.new
|
||||
|
||||
expect(sidebar).to be_not_visible
|
||||
|
||||
legacy_header_dropdown = PageObjects::Components::LegacyHeaderDropdown.new
|
||||
@ -79,8 +71,6 @@ describe "Viewing sidebar", type: :system do
|
||||
it "should display the sidebar dropdown menu when `navigation_menu` query param is 'header_dropdown'" do
|
||||
visit("/latest?navigation_menu=header_dropdown")
|
||||
|
||||
sidebar = PageObjects::Components::Sidebar.new
|
||||
|
||||
expect(sidebar).to be_not_visible
|
||||
|
||||
header_dropdown = PageObjects::Components::SidebarHeaderDropdown.new
|
||||
|
Reference in New Issue
Block a user