Skip to content
Snippets Groups Projects
Unverified Commit 9b4c9a22 authored by Gustavo Saiani's avatar Gustavo Saiani Committed by GitHub
Browse files

Close collection sidebar on mobile (#17278)

parent 4a198de0
No related branches found
No related tags found
No related merge requests found
Showing
with 66 additions and 92 deletions
import styled, { css } from "styled-components"; import styled, { css } from "styled-components";
import Link from "metabase/components/Link"; import Link from "metabase/components/Link";
import { color } from "metabase/lib/colors"; import { color } from "metabase/lib/colors";
import { space } from "metabase/styled-components/theme";
import { SIDEBAR_SPACER } from "../constants"; import { SIDEBAR_SPACER } from "metabase/collections/constants";
const dimmedIconCss = css` const dimmedIconCss = css`
fill: ${color("white")}; fill: ${color("white")};
...@@ -17,9 +17,9 @@ const CollectionLink = styled(Link)` ...@@ -17,9 +17,9 @@ const CollectionLink = styled(Link)`
// now pad it by the depth so we get hover states that are the full width of the sidebar // now pad it by the depth so we get hover states that are the full width of the sidebar
props.depth * (SIDEBAR_SPACER * 2) + SIDEBAR_SPACER}px; props.depth * (SIDEBAR_SPACER * 2) + SIDEBAR_SPACER}px;
position: relative; position: relative;
padding-right: 8px; padding-right: ${space(1)};
padding-top: 8px; padding-top: ${space(1)};
padding-bottom: 8px; padding-bottom: ${space(1)};
display: flex; display: flex;
flex-shrink: 0; flex-shrink: 0;
align-items: center; align-items: center;
......
...@@ -74,13 +74,18 @@ class CollectionSidebar extends React.Component { ...@@ -74,13 +74,18 @@ class CollectionSidebar extends React.Component {
<Collection.Loader id="root"> <Collection.Loader id="root">
{({ collection: root }) => ( {({ collection: root }) => (
<RootCollectionLink isRoot={isRoot} root={root} /> <RootCollectionLink
handleToggleMobileSidebar={handleToggleMobileSidebar}
isRoot={isRoot}
root={root}
/>
)} )}
</Collection.Loader> </Collection.Loader>
<Collections <Collections
collectionId={collectionId} collectionId={collectionId}
currentUserId={currentUser.id} currentUserId={currentUser.id}
handleToggleMobileSidebar={handleToggleMobileSidebar}
list={list} list={list}
onClose={this.onClose} onClose={this.onClose}
onOpen={this.onOpen} onOpen={this.onOpen}
......
import React from "react";
import PropTypes from "prop-types";
import { t } from "ttag";
import * as Urls from "metabase/lib/urls";
import CollectionDropTarget from "metabase/containers/dnd/CollectionDropTarget";
import CollectionLink from "metabase/collections/components/CollectionLink";
import { Container } from "./CollectionSidebarHeader.styled";
const propTypes = {
isRoot: PropTypes.bool.isRequired,
root: PropTypes.object.isRequired,
};
export default function CollectionSidebarHeader({ isRoot, root }) {
return (
<Container>
<CollectionDropTarget collection={root}>
{({ highlighted, hovered }) => (
<CollectionLink
to={Urls.collection({ id: "root" })}
selected={isRoot}
highlighted={highlighted}
hovered={hovered}
>
{t`Our analytics`}
</CollectionLink>
)}
</CollectionDropTarget>
</Container>
);
}
CollectionSidebarHeader.propTypes = propTypes;
import styled from "styled-components";
import { Box } from "grid-styled";
import { space } from "metabase/styled-components/theme";
export const Container = styled(Box)`
margin-bottom: ${space(1)};
margin-top: ${space(2)};
`;
import React from "react";
import { render, screen } from "@testing-library/react";
import { DragDropContextProvider } from "react-dnd";
import HTML5Backend from "react-dnd-html5-backend";
import CollectionSidebarHeader from "./CollectionSidebarHeader";
it("displays link to main collection: Our Analytics", () => {
render(
<DragDropContextProvider backend={HTML5Backend}>
<CollectionSidebarHeader
isRoot={false}
root={{ name: "name", id: "root" }}
/>
</DragDropContextProvider>,
);
screen.getByText("Our analytics");
});
...@@ -13,6 +13,7 @@ import { Container } from "./Collections.styled"; ...@@ -13,6 +13,7 @@ import { Container } from "./Collections.styled";
const propTypes = { const propTypes = {
collectionId: PropTypes.number, collectionId: PropTypes.number,
currentUserId: PropTypes.number, currentUserId: PropTypes.number,
handleToggleMobileSidebar: PropTypes.func.isRequired,
list: PropTypes.array, list: PropTypes.array,
onClose: PropTypes.func.isRequired, onClose: PropTypes.func.isRequired,
onOpen: PropTypes.func.isRequired, onOpen: PropTypes.func.isRequired,
...@@ -22,6 +23,7 @@ const propTypes = { ...@@ -22,6 +23,7 @@ const propTypes = {
export default function Collections({ export default function Collections({
collectionId, collectionId,
currentUserId, currentUserId,
handleToggleMobileSidebar,
list, list,
onClose, onClose,
onOpen, onOpen,
...@@ -39,6 +41,7 @@ export default function Collections({ ...@@ -39,6 +41,7 @@ export default function Collections({
return ( return (
<Container> <Container>
<CollectionsList <CollectionsList
handleToggleMobileSidebar={handleToggleMobileSidebar}
openCollections={openCollections} openCollections={openCollections}
onClose={onClose} onClose={onClose}
onOpen={onOpen} onOpen={onOpen}
...@@ -49,6 +52,7 @@ export default function Collections({ ...@@ -49,6 +52,7 @@ export default function Collections({
<Box> <Box>
<CollectionsList <CollectionsList
handleToggleMobileSidebar={handleToggleMobileSidebar}
openCollections={openCollections} openCollections={openCollections}
onClose={onClose} onClose={onClose}
onOpen={onOpen} onOpen={onOpen}
......
...@@ -24,6 +24,7 @@ function ToggleChildCollectionButton({ action, collectionId, isOpen }) { ...@@ -24,6 +24,7 @@ function ToggleChildCollectionButton({ action, collectionId, isOpen }) {
function handleClick(e) { function handleClick(e) {
e.preventDefault(); e.preventDefault();
e.stopPropagation();
action(collectionId); action(collectionId);
} }
...@@ -61,6 +62,7 @@ function Collection({ ...@@ -61,6 +62,7 @@ function Collection({
depth, depth,
currentCollection, currentCollection,
filter, filter,
handleToggleMobileSidebar,
initialIcon, initialIcon,
onClose, onClose,
onOpen, onOpen,
...@@ -81,7 +83,7 @@ function Collection({ ...@@ -81,7 +83,7 @@ function Collection({
// when we click on a link, if there are children, // when we click on a link, if there are children,
// expand to show sub collections // expand to show sub collections
function handleClick() { function handleClick() {
children && action(id); handleToggleMobileSidebar();
} }
return ( return (
...@@ -110,6 +112,7 @@ function Collection({ ...@@ -110,6 +112,7 @@ function Collection({
{children && isOpen && ( {children && isOpen && (
<ChildrenContainer> <ChildrenContainer>
<CollectionsList <CollectionsList
handleToggleMobileSidebar={handleToggleMobileSidebar}
openCollections={openCollections} openCollections={openCollections}
onOpen={onOpen} onOpen={onOpen}
onClose={onClose} onClose={onClose}
...@@ -127,6 +130,7 @@ function Collection({ ...@@ -127,6 +130,7 @@ function Collection({
function CollectionsList({ function CollectionsList({
collections, collections,
filter, filter,
handleToggleMobileSidebar,
initialIcon, initialIcon,
depth = 1, depth = 1,
...otherProps ...otherProps
...@@ -140,6 +144,7 @@ function CollectionsList({ ...@@ -140,6 +144,7 @@ function CollectionsList({
collection={collection} collection={collection}
depth={depth} depth={depth}
filter={filter} filter={filter}
handleToggleMobileSidebar={handleToggleMobileSidebar}
initialIcon={initialIcon} initialIcon={initialIcon}
key={collection.id} key={collection.id}
{...otherProps} {...otherProps}
......
...@@ -11,17 +11,27 @@ import CollectionLink from "metabase/collections/components/CollectionLink"; ...@@ -11,17 +11,27 @@ import CollectionLink from "metabase/collections/components/CollectionLink";
import { Container } from "./RootCollectionLink.styled"; import { Container } from "./RootCollectionLink.styled";
const propTypes = { const propTypes = {
handleToggleMobileSidebar: PropTypes.func.isRequired,
isRoot: PropTypes.bool.isRequired, isRoot: PropTypes.bool.isRequired,
root: PropTypes.object.isRequired, root: PropTypes.object.isRequired,
}; };
export default function CollectionSidebarHeader({ isRoot, root }) { export default function RootCollectionLink({
handleToggleMobileSidebar,
isRoot,
root,
}) {
function handleClick() {
handleToggleMobileSidebar();
}
return ( return (
<Container> <Container>
<CollectionDropTarget collection={root}> <CollectionDropTarget collection={root}>
{({ highlighted, hovered }) => ( {({ highlighted, hovered }) => (
<CollectionLink <CollectionLink
to={Urls.collection({ id: "root" })} to={Urls.collection({ id: "root" })}
onClick={handleClick}
selected={isRoot} selected={isRoot}
highlighted={highlighted} highlighted={highlighted}
hovered={hovered} hovered={hovered}
...@@ -35,4 +45,4 @@ export default function CollectionSidebarHeader({ isRoot, root }) { ...@@ -35,4 +45,4 @@ export default function CollectionSidebarHeader({ isRoot, root }) {
); );
} }
CollectionSidebarHeader.propTypes = propTypes; RootCollectionLink.propTypes = propTypes;
...@@ -27,4 +27,17 @@ describe("collections sidebar (metabase#15006)", () => { ...@@ -27,4 +27,17 @@ describe("collections sidebar (metabase#15006)", () => {
cy.icon("burger"); cy.icon("burger");
}); });
it("should close collections sidebar when collection is clicked in mobile screen size", () => {
cy.viewport(480, 800);
cy.icon("burger").click();
sidebar().should("be.visible");
sidebar().within(() => {
cy.findByText("First collection").click();
});
cy.icon("burger");
});
}); });
...@@ -7,6 +7,7 @@ import { ...@@ -7,6 +7,7 @@ import {
openOrdersTable, openOrdersTable,
sidebar, sidebar,
} from "__support__/e2e/cypress"; } from "__support__/e2e/cypress";
import { displaySidebarChildOf } from "./helpers/e2e-collections-sidebar.js";
import { USERS, USER_GROUPS } from "__support__/e2e/cypress_data"; import { USERS, USER_GROUPS } from "__support__/e2e/cypress_data";
const { nocollection } = USERS; const { nocollection } = USERS;
...@@ -122,7 +123,7 @@ describe("scenarios > collection_defaults", () => { ...@@ -122,7 +123,7 @@ describe("scenarios > collection_defaults", () => {
it("should allow a user to expand a collection without navigating to it", () => { it("should allow a user to expand a collection without navigating to it", () => {
cy.visit("/collection/root"); cy.visit("/collection/root");
// 1. click on the chevron to expand the sub collection // 1. click on the chevron to expand the sub collection
openDropdownFor("First collection"); displaySidebarChildOf("First collection");
// 2. I should see the nested collection name // 2. I should see the nested collection name
cy.findByText("First collection"); cy.findByText("First collection");
cy.findByText("Second collection"); cy.findByText("Second collection");
...@@ -153,10 +154,10 @@ describe("scenarios > collection_defaults", () => { ...@@ -153,10 +154,10 @@ describe("scenarios > collection_defaults", () => {
}); });
cy.visit("/collection/root"); cy.visit("/collection/root");
// 1. Expand out via the chevrons so that all collections are showing // 1. Expand out via the chevrons so that all collections are showing
openDropdownFor("First collection"); displaySidebarChildOf("First collection");
openDropdownFor("Second collection"); displaySidebarChildOf("Second collection");
openDropdownFor("Third collection"); displaySidebarChildOf("Third collection");
openDropdownFor("Fourth collection"); displaySidebarChildOf("Fourth collection");
// 2. Ensure we can see the entire "Fifth level with a long name" collection text // 2. Ensure we can see the entire "Fifth level with a long name" collection text
cy.findByText("Fifth collection with a very long name"); cy.findByText("Fifth collection with a very long name");
}); });
...@@ -324,7 +325,7 @@ describe("scenarios > collection_defaults", () => { ...@@ -324,7 +325,7 @@ describe("scenarios > collection_defaults", () => {
cy.visit("/collection/root"); cy.visit("/collection/root");
cy.get("[class*=CollectionSidebar]").as("sidebar"); cy.get("[class*=CollectionSidebar]").as("sidebar");
openDropdownFor("Your personal collection"); displaySidebarChildOf("Your personal collection");
cy.findByText(COLLECTION); cy.findByText(COLLECTION);
cy.get("@sidebar") cy.get("@sidebar")
.contains("Our analytics") .contains("Our analytics")
...@@ -396,7 +397,7 @@ describe("scenarios > collection_defaults", () => { ...@@ -396,7 +397,7 @@ describe("scenarios > collection_defaults", () => {
it("should update UI when nested child collection is moved to the root collection (metabase#14482)", () => { it("should update UI when nested child collection is moved to the root collection (metabase#14482)", () => {
cy.visit("/collection/root"); cy.visit("/collection/root");
cy.log("Move 'Second collection' to the root"); cy.log("Move 'Second collection' to the root");
openDropdownFor("First collection"); displaySidebarChildOf("First collection");
cy.findByText("Second collection").click(); cy.findByText("Second collection").click();
cy.icon("pencil").click(); cy.icon("pencil").click();
cy.findByText("Edit this collection").click(); cy.findByText("Edit this collection").click();
...@@ -454,6 +455,7 @@ describe("scenarios > collection_defaults", () => { ...@@ -454,6 +455,7 @@ describe("scenarios > collection_defaults", () => {
it("collections without sub-collections shouldn't have chevron icon (metabase#14753)", () => { it("collections without sub-collections shouldn't have chevron icon (metabase#14753)", () => {
cy.visit("/collection/root"); cy.visit("/collection/root");
sidebar() sidebar()
.findByText("Your personal collection") .findByText("Your personal collection")
.parent() .parent()
...@@ -461,9 +463,8 @@ describe("scenarios > collection_defaults", () => { ...@@ -461,9 +463,8 @@ describe("scenarios > collection_defaults", () => {
.should("not.exist"); .should("not.exist");
// Ensure if sub-collection is archived, the chevron is not displayed // Ensure if sub-collection is archived, the chevron is not displayed
displaySidebarChildOf("First collection");
sidebar() sidebar()
.findByText("First collection")
.click()
.findByText("Second collection") .findByText("Second collection")
.click(); .click();
cy.icon("pencil").click(); cy.icon("pencil").click();
...@@ -611,14 +612,6 @@ function createPulse() { ...@@ -611,14 +612,6 @@ function createPulse() {
cy.findByText("Create pulse").click(); cy.findByText("Create pulse").click();
} }
function openDropdownFor(collectionName) {
cy.findByText(collectionName)
.parent()
.find(".Icon-chevronright")
.eq(0) // there may be more nested icons, but we need the top level one
.click();
}
function openEllipsisMenuFor(item) { function openEllipsisMenuFor(item) {
cy.findByText(item) cy.findByText(item)
.closest("tr") .closest("tr")
......
export function displaySidebarChildOf(collectionName) {
cy.findByText(collectionName)
.parent()
.find(".Icon-chevronright")
.eq(0) // there may be more nested icons, but we need the top level one
.click();
}
...@@ -17,6 +17,7 @@ import { ...@@ -17,6 +17,7 @@ import {
sidebar, sidebar,
openNativeEditor, openNativeEditor,
} from "__support__/e2e/cypress"; } from "__support__/e2e/cypress";
import { displaySidebarChildOf } from "./helpers/e2e-collections-sidebar.js";
import { USERS } from "__support__/e2e/cypress_data"; import { USERS } from "__support__/e2e/cypress_data";
const PERMISSIONS = { const PERMISSIONS = {
...@@ -45,8 +46,8 @@ describe("collection permissions", () => { ...@@ -45,8 +46,8 @@ describe("collection permissions", () => {
it("should offer to save dashboard to a currently opened collection", () => { it("should offer to save dashboard to a currently opened collection", () => {
cy.visit("/collection/root"); cy.visit("/collection/root");
sidebar().within(() => { sidebar().within(() => {
cy.findByText("First collection").click(); displaySidebarChildOf("First collection");
cy.findByText("Second collection").click(); displaySidebarChildOf("Second collection");
}); });
cy.icon("add").click(); cy.icon("add").click();
cy.findByText("New dashboard").click(); cy.findByText("New dashboard").click();
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment