Do not show sidebar if it is not needed (#3198)

This commit is contained in:
Krzysztof Żuraw 2023-02-22 14:00:03 +01:00 committed by GitHub
parent 6434f277e8
commit 0f81e158ce
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 266 additions and 203 deletions

View file

@ -36,7 +36,7 @@ export const CategoryCreatePage: React.FC<CategoryCreatePageProps> = ({
return ( return (
<CategoryCreateForm onSubmit={onSubmit} disabled={disabled}> <CategoryCreateForm onSubmit={onSubmit} disabled={disabled}>
{({ data, change, handlers, submit, isSaveDisabled }) => ( {({ data, change, handlers, submit, isSaveDisabled }) => (
<DetailedContent> <DetailedContent useSingleColumn>
<TopNav <TopNav
href={backUrl} href={backUrl}
title={intl.formatMessage({ title={intl.formatMessage({

View file

@ -91,7 +91,7 @@ export const CategoryUpdatePage: React.FC<CategoryUpdatePageProps> = ({
disabled={disabled} disabled={disabled}
> >
{({ data, change, handlers, submit, isSaveDisabled }) => ( {({ data, change, handlers, submit, isSaveDisabled }) => (
<DetailedContent> <DetailedContent useSingleColumn>
<TopNav href={backHref} title={category?.name} /> <TopNav href={backHref} title={category?.name} />
<Content> <Content>
<CategoryDetailsForm <CategoryDetailsForm

View file

@ -60,8 +60,7 @@ const AppLayout: React.FC<AppLayoutProps> = ({ children }) => {
borderColor="neutralPlain" borderColor="neutralPlain"
__maxWidth={contentMaxWidth} __maxWidth={contentMaxWidth}
margin="auto" margin="auto"
// @ts-ignore zIndex="3"
__zIndex="3"
/> />
</Box> </Box>
</Box> </Box>

View file

@ -1,21 +1,32 @@
import { Box } from "@saleor/macaw-ui/next"; import { Box } from "@saleor/macaw-ui/next";
import React from "react"; import React from "react";
import { borderHeight, savebarHeight, topBarHeight } from "./consts"; import { useContentHeight } from "./useContentHeight";
interface ContentProps { interface ContentProps {
[key: `data-${string}`]: string; [key: `data-${string}`]: string;
children: React.ReactNode; children: React.ReactNode;
noSavebar?: boolean;
noTopNav?: boolean;
} }
export const Content: React.FC<ContentProps> = ({ children, ...rest }) => ( export const Content: React.FC<ContentProps> = ({
<Box children,
__gridArea="content" noSavebar = false,
__height={`calc(100vh - ${topBarHeight} - ${savebarHeight} - ${borderHeight})`} noTopNav = false,
overflowY="auto" ...rest
className="hide-scrollbar" }) => {
{...rest} const { withoutSaveBar, withSaveBar } = useContentHeight();
>
{children} return (
</Box> <Box
); __gridArea="content"
__height={noSavebar ? withoutSaveBar() : withSaveBar({ noTopNav })}
overflowY="auto"
className="hide-scrollbar"
{...rest}
>
{children}
</Box>
);
};

View file

@ -7,17 +7,21 @@ import { borderHeight, savebarHeight } from "./consts";
interface RightSidebarProps { interface RightSidebarProps {
children: React.ReactNode; children: React.ReactNode;
className?: string; className?: string;
noSavebar?: boolean;
} }
export const RightSidebar: React.FC<RightSidebarProps> = ({ export const RightSidebar: React.FC<RightSidebarProps> = ({
children, children,
noSavebar = false,
className, className,
}) => ( }) => (
<Box <Box
borderStyle="solid" borderStyle="solid"
borderColor="neutralPlain" borderColor="neutralPlain"
borderLeftWidth={1} borderLeftWidth={1}
__height={`calc(100vh - ${savebarHeight} - ${borderHeight})`} __height={
noSavebar ? "100%" : `calc(100vh - ${savebarHeight} - ${borderHeight})`
}
position="sticky" position="sticky"
top={0} top={0}
overflowY="auto" overflowY="auto"

View file

@ -0,0 +1,24 @@
import { useContentHeight } from "./useContentHeight";
describe("useContentHeight", () => {
it("should return the correct height without savebar", () => {
const { withoutSaveBar } = useContentHeight();
const height = withoutSaveBar();
expect(height).toEqual("calc(100vh - 77px - 1px)");
});
it("should return the correct height with savebar", () => {
const { withSaveBar } = useContentHeight();
const height = withSaveBar({ noTopNav: false });
expect(height).toEqual("calc(100vh - 77px - 64px - 1px)");
});
it("should return the correct height with savebar and no top nav", () => {
const { withSaveBar } = useContentHeight();
const height = withSaveBar({ noTopNav: true });
expect(height).toEqual("calc(100vh - 0px - 64px - 1px)");
});
});

View file

@ -0,0 +1,14 @@
import { borderHeight, savebarHeight, topBarHeight } from "./consts";
export const useContentHeight = () => {
const withoutSaveBar = () =>
`calc(100vh - ${topBarHeight} - ${borderHeight})`;
const withSaveBar = ({ noTopNav }) => {
const topHeight = noTopNav ? "0px" : topBarHeight;
return `calc(100vh - ${topHeight} - ${savebarHeight} - ${borderHeight})`;
};
return { withoutSaveBar, withSaveBar };
};

View file

@ -99,7 +99,7 @@ export const ConfigurationPage: React.FC<ConfigurationPageProps> = props => {
<TopNav title={intl.formatMessage(sectionNames.configuration)}> <TopNav title={intl.formatMessage(sectionNames.configuration)}>
{isSmUp && renderVersionInfo} {isSmUp && renderVersionInfo}
</TopNav> </TopNav>
<Content> <Content noSavebar>
<Box paddingX={9} __maxWidth={"1024px"} margin="auto"> <Box paddingX={9} __maxWidth={"1024px"} margin="auto">
{menus {menus
.filter(menu => .filter(menu =>

View file

@ -1,4 +1,7 @@
import { Content } from "@dashboard/components/AppLayout/Content"; import {
borderHeight,
topBarHeight,
} from "@dashboard/components/AppLayout/consts";
import { TopNav } from "@dashboard/components/AppLayout/TopNav"; import { TopNav } from "@dashboard/components/AppLayout/TopNav";
import { Button } from "@dashboard/components/Button"; import { Button } from "@dashboard/components/Button";
import { TableButtonWrapper } from "@dashboard/components/TableButtonWrapper/TableButtonWrapper"; import { TableButtonWrapper } from "@dashboard/components/TableButtonWrapper/TableButtonWrapper";
@ -46,72 +49,73 @@ const CustomAppListPage: React.FC<CustomAppListPageProps> = ({
/> />
</Button> </Button>
</TopNav> </TopNav>
<Content> <Box
<Box padding={9}> padding={9}
<Box marginBottom={4}> __height={`calc(100vh - ${topBarHeight} - ${borderHeight})`}
<Text as="p"> >
<FormattedMessage <Box marginBottom={4}>
defaultMessage="Local apps are custom webhooks & token pairs that can be used to <Text as="p">
<FormattedMessage
defaultMessage="Local apps are custom webhooks & token pairs that can be used to
connect apps and access Saleor API." connect apps and access Saleor API."
id="L/sNGY" id="L/sNGY"
/> />
</Text> </Text>
</Box> </Box>
<ResponsiveTable> <ResponsiveTable>
<TableBody> <TableBody>
{renderCollection( {renderCollection(
appsList, appsList,
(app, index) => (app, index) =>
app ? ( app ? (
<TableRowLink <TableRowLink
key={app.id} key={app.id}
className={classes.tableRow} className={classes.tableRow}
href={getCustomAppHref(app.id)} href={getCustomAppHref(app.id)}
> >
<TableCell className={classes.colName}>
<span data-tc="name" className={classes.appName}>
{app.name}
</span>
{!app.isActive && (
<div className={classes.statusWrapper}>
<DeactivatedText />
</div>
)}
</TableCell>
<TableCell className={classes.colAction}>
<TableButtonWrapper>
<IconButton
variant="secondary"
color="primary"
onClick={() => onRemove(app.id)}
>
<DeleteIcon />
</IconButton>
</TableButtonWrapper>
</TableCell>
</TableRowLink>
) : (
<AppsSkeleton key={index} />
),
() => (
<TableRowLink className={classes.tableRow}>
<TableCell className={classes.colName}> <TableCell className={classes.colName}>
<Typography className={classes.text} variant="body2"> <span data-tc="name" className={classes.appName}>
<FormattedMessage {app.name}
id="voRaz3" </span>
defaultMessage="Your custom-created apps will be shown here." {!app.isActive && (
description="custom apps content" <div className={classes.statusWrapper}>
/> <DeactivatedText />
</Typography> </div>
)}
</TableCell>
<TableCell className={classes.colAction}>
<TableButtonWrapper>
<IconButton
variant="secondary"
color="primary"
onClick={() => onRemove(app.id)}
>
<DeleteIcon />
</IconButton>
</TableButtonWrapper>
</TableCell> </TableCell>
</TableRowLink> </TableRowLink>
) : (
<AppsSkeleton key={index} />
), ),
)} () => (
</TableBody> <TableRowLink className={classes.tableRow}>
</ResponsiveTable> <TableCell className={classes.colName}>
</Box> <Typography className={classes.text} variant="body2">
</Content> <FormattedMessage
id="voRaz3"
defaultMessage="Your custom-created apps will be shown here."
description="custom apps content"
/>
</Typography>
</TableCell>
</TableRowLink>
),
)}
</TableBody>
</ResponsiveTable>
</Box>
</> </>
); );
}; };

View file

@ -1,9 +1,9 @@
import { createCountryHandler } from "@dashboard/components/AddressEdit/createCountryHandler"; import { createCountryHandler } from "@dashboard/components/AddressEdit/createCountryHandler";
import { Content } from "@dashboard/components/AppLayout/Content"; import { Content } from "@dashboard/components/AppLayout/Content";
import { DetailedContent } from "@dashboard/components/AppLayout/DetailedContent";
import { TopNav } from "@dashboard/components/AppLayout/TopNav"; import { TopNav } from "@dashboard/components/AppLayout/TopNav";
import { CardSpacer } from "@dashboard/components/CardSpacer"; import { CardSpacer } from "@dashboard/components/CardSpacer";
import Form from "@dashboard/components/Form"; import Form from "@dashboard/components/Form";
import Grid from "@dashboard/components/Grid";
import Savebar from "@dashboard/components/Savebar"; import Savebar from "@dashboard/components/Savebar";
import { customerListUrl } from "@dashboard/customers/urls"; import { customerListUrl } from "@dashboard/customers/urls";
import { import {
@ -152,7 +152,7 @@ const CustomerCreatePage: React.FC<CustomerCreatePageProps> = ({
const handleCountrySelect = createCountryHandler(countrySelect, set); const handleCountrySelect = createCountryHandler(countrySelect, set);
return ( return (
<> <DetailedContent useSingleColumn>
<TopNav <TopNav
href={customerListUrl()} href={customerListUrl()}
title={intl.formatMessage({ title={intl.formatMessage({
@ -162,33 +162,31 @@ const CustomerCreatePage: React.FC<CustomerCreatePageProps> = ({
})} })}
/> />
<Content> <Content>
<Grid> <div>
<div> <CustomerCreateDetails
<CustomerCreateDetails data={data}
data={data} disabled={disabled}
disabled={disabled} errors={errors}
errors={errors} onChange={change}
onChange={change} />
/> <CardSpacer />
<CardSpacer /> <CustomerCreateAddress
<CustomerCreateAddress countries={countryChoices}
countries={countryChoices} countryDisplayName={countryDisplayName}
countryDisplayName={countryDisplayName} data={data}
data={data} disabled={disabled}
disabled={disabled} errors={errors}
errors={errors} onChange={change}
onChange={change} onCountryChange={handleCountrySelect}
onCountryChange={handleCountrySelect} />
/> <CardSpacer />
<CardSpacer /> <CustomerCreateNote
<CustomerCreateNote data={data}
data={data} disabled={disabled}
disabled={disabled} errors={errors}
errors={errors} onChange={change}
onChange={change} />
/> </div>
</div>
</Grid>
<Savebar <Savebar
disabled={isSaveDisabled} disabled={isSaveDisabled}
state={saveButtonBar} state={saveButtonBar}
@ -196,7 +194,7 @@ const CustomerCreatePage: React.FC<CustomerCreatePageProps> = ({
onCancel={() => navigate(customerListUrl())} onCancel={() => navigate(customerListUrl())}
/> />
</Content> </Content>
</> </DetailedContent>
); );
}} }}
</Form> </Form>

View file

@ -80,7 +80,7 @@ const HomePage: React.FC<HomePageProps> = props => {
return ( return (
<DetailedContent> <DetailedContent>
<TopNav title={<HomeHeader userName={userName} />} /> <TopNav title={<HomeHeader userName={userName} />} />
<Content> <Content noSavebar>
<Box paddingLeft={9} paddingRight={11}> <Box paddingLeft={9} paddingRight={11}>
<CardSpacer /> <CardSpacer />
<RequirePermissions <RequirePermissions
@ -155,7 +155,7 @@ const HomePage: React.FC<HomePageProps> = props => {
</Box> </Box>
</Content> </Content>
{activities && ( {activities && (
<RightSidebar> <RightSidebar noSavebar>
<RequirePermissions <RequirePermissions
requiredPermissions={[PermissionEnum.MANAGE_ORDERS]} requiredPermissions={[PermissionEnum.MANAGE_ORDERS]}
> >

View file

@ -86,8 +86,8 @@ const MenuDetailsPage: React.FC<MenuDetailsPageProps> = ({
return ( return (
<Form confirmLeave initial={initialForm} onSubmit={handleSubmit}> <Form confirmLeave initial={initialForm} onSubmit={handleSubmit}>
{({ change, data, submit }) => ( {({ change, data, submit }) => (
<DetailedContent> <DetailedContent useSingleColumn>
<Content> <Content noTopNav>
<Box padding={9} margin="auto" height="100vh"> <Box padding={9} margin="auto" height="100vh">
<Backlink href={menuListUrl()}> <Backlink href={menuListUrl()}>
{intl.formatMessage(sectionNames.navigation)} {intl.formatMessage(sectionNames.navigation)}

View file

@ -1,3 +1,7 @@
import {
borderHeight,
topBarHeight,
} from "@dashboard/components/AppLayout/consts";
import { TopNav } from "@dashboard/components/AppLayout/TopNav"; import { TopNav } from "@dashboard/components/AppLayout/TopNav";
import { Button } from "@dashboard/components/Button"; import { Button } from "@dashboard/components/Button";
import { configurationMenuUrl } from "@dashboard/configuration"; import { configurationMenuUrl } from "@dashboard/configuration";
@ -5,6 +9,7 @@ import { MenuFragment } from "@dashboard/graphql";
import { sectionNames } from "@dashboard/intl"; import { sectionNames } from "@dashboard/intl";
import { menuListUrl, MenuListUrlSortField } from "@dashboard/navigation/urls"; import { menuListUrl, MenuListUrlSortField } from "@dashboard/navigation/urls";
import { ListActions, PageListProps, SortPage } from "@dashboard/types"; import { ListActions, PageListProps, SortPage } from "@dashboard/types";
import { Box } from "@saleor/macaw-ui/next";
import React from "react"; import React from "react";
import { FormattedMessage, useIntl } from "react-intl"; import { FormattedMessage, useIntl } from "react-intl";
@ -38,7 +43,9 @@ const MenuListPage: React.FC<MenuListPageProps> = ({ ...listProps }) => {
/> />
</Button> </Button>
</TopNav> </TopNav>
<MenuList {...listProps} /> <Box __height={`calc(100vh - ${topBarHeight} - ${borderHeight})`}>
<MenuList {...listProps} />
</Box>
</> </>
); );
}; };

View file

@ -14,7 +14,7 @@ import TableRowLink from "@dashboard/components/TableRowLink";
import { AttributeFragment, AttributeTypeEnum } from "@dashboard/graphql"; import { AttributeFragment, AttributeTypeEnum } from "@dashboard/graphql";
import { renderCollection } from "@dashboard/misc"; import { renderCollection } from "@dashboard/misc";
import { ListActions, ReorderAction } from "@dashboard/types"; import { ListActions, ReorderAction } from "@dashboard/types";
import { Card, TableCell } from "@material-ui/core"; import { Card, CardContent, TableCell } from "@material-ui/core";
import { DeleteIcon, IconButton, makeStyles } from "@saleor/macaw-ui"; import { DeleteIcon, IconButton, makeStyles } from "@saleor/macaw-ui";
import React from "react"; import React from "react";
import { FormattedMessage, useIntl } from "react-intl"; import { FormattedMessage, useIntl } from "react-intl";
@ -95,93 +95,95 @@ const PageTypeAttributes: React.FC<PageTypeAttributesProps> = props => {
</Button> </Button>
} }
/> />
<ResponsiveTable> <CardContent>
<colgroup> <ResponsiveTable>
<col className={classes.colGrab} /> <colgroup>
<col /> <col className={classes.colGrab} />
<col className={classes.colName} /> <col />
<col className={classes.colSlug} /> <col className={classes.colName} />
<col className={classes.colAction} /> <col className={classes.colSlug} />
</colgroup> <col className={classes.colAction} />
{attributes?.length > 0 && ( </colgroup>
<TableHead {attributes?.length > 0 && (
colSpan={numberOfColumns} <TableHead
disabled={disabled} colSpan={numberOfColumns}
dragRows disabled={disabled}
selected={selected} dragRows
items={attributes} selected={selected}
toggleAll={toggleAll} items={attributes}
toolbar={toolbar} toggleAll={toggleAll}
> toolbar={toolbar}
<TableCell className={classes.colName}> >
<FormattedMessage id="kTr2o8" defaultMessage="Attribute name" /> <TableCell className={classes.colName}>
</TableCell> <FormattedMessage id="kTr2o8" defaultMessage="Attribute name" />
<TableCell className={classes.colName}> </TableCell>
<FormattedMessage <TableCell className={classes.colName}>
id="nf3XSt" <FormattedMessage
defaultMessage="Slug" id="nf3XSt"
description="attribute internal name" defaultMessage="Slug"
/> description="attribute internal name"
</TableCell> />
<TableCell /> </TableCell>
</TableHead> <TableCell />
)} </TableHead>
<SortableTableBody onSortEnd={onAttributeReorder}> )}
{renderCollection( <SortableTableBody onSortEnd={onAttributeReorder}>
attributes, {renderCollection(
(attribute, attributeIndex) => { attributes,
const isSelected = attribute ? isChecked(attribute.id) : false; (attribute, attributeIndex) => {
const isSelected = attribute ? isChecked(attribute.id) : false;
return ( return (
<SortableTableRow <SortableTableRow
selected={isSelected} selected={isSelected}
className={!!attribute ? classes.link : undefined} className={!!attribute ? classes.link : undefined}
hover={!!attribute} hover={!!attribute}
href={attribute ? attributeUrl(attribute.id) : undefined} href={attribute ? attributeUrl(attribute.id) : undefined}
key={attribute?.id} key={attribute?.id}
index={attributeIndex || 0} index={attributeIndex || 0}
data-test-id={"id-" + attribute?.id} data-test-id={"id-" + attribute?.id}
> >
<TableCell padding="checkbox"> <TableCell padding="checkbox">
<Checkbox <Checkbox
checked={isSelected} checked={isSelected}
disabled={disabled} disabled={disabled}
disableClickPropagation disableClickPropagation
onChange={() => toggle(attribute.id)} onChange={() => toggle(attribute.id)}
/>
</TableCell>
<TableCell className={classes.colName} data-test-id="name">
{attribute?.name || <Skeleton />}
</TableCell>
<TableCell className={classes.colSlug} data-test-id="slug">
{attribute?.slug || <Skeleton />}
</TableCell>
<TableCell className={classes.colAction}>
<TableButtonWrapper>
<IconButton
variant="secondary"
onClick={() => onAttributeUnassign(attribute.id)}
>
<DeleteIcon color="primary" />
</IconButton>
</TableButtonWrapper>
</TableCell>
</SortableTableRow>
);
},
() => (
<TableRowLink>
<TableCell colSpan={numberOfColumns}>
<FormattedMessage
id="ztQgD8"
defaultMessage="No attributes found"
/> />
</TableCell> </TableCell>
<TableCell className={classes.colName} data-test-id="name"> </TableRowLink>
{attribute?.name || <Skeleton />} ),
</TableCell> )}
<TableCell className={classes.colSlug} data-test-id="slug"> </SortableTableBody>
{attribute?.slug || <Skeleton />} </ResponsiveTable>
</TableCell> </CardContent>
<TableCell className={classes.colAction}>
<TableButtonWrapper>
<IconButton
variant="secondary"
onClick={() => onAttributeUnassign(attribute.id)}
>
<DeleteIcon color="primary" />
</IconButton>
</TableButtonWrapper>
</TableCell>
</SortableTableRow>
);
},
() => (
<TableRowLink>
<TableCell colSpan={numberOfColumns}>
<FormattedMessage
id="ztQgD8"
defaultMessage="No attributes found"
/>
</TableCell>
</TableRowLink>
),
)}
</SortableTableBody>
</ResponsiveTable>
</Card> </Card>
); );
}; };

View file

@ -118,7 +118,7 @@ const PageTypeDetailsPage: React.FC<PageTypeDetailsPageProps> = props => {
const changeMetadata = makeMetadataChangeHandler(change); const changeMetadata = makeMetadataChangeHandler(change);
return ( return (
<DetailedContent> <DetailedContent useSingleColumn>
<TopNav href={pageTypeListUrl()} title={pageTitle} /> <TopNav href={pageTypeListUrl()} title={pageTitle} />
<Content> <Content>
<Grid <Grid

View file

@ -49,10 +49,10 @@ const ShippingZonesListPage: React.FC<ShippingZonesListPageProps> = ({
description: "header", description: "header",
})} })}
/> />
<Content> <Content noSavebar>
<ShippingZonesList disabled={disabled} {...listProps} /> <ShippingZonesList disabled={disabled} {...listProps} />
</Content> </Content>
<RightSidebar> <RightSidebar noSavebar>
<RequirePermissions <RequirePermissions
requiredPermissions={[PermissionEnum.MANAGE_SETTINGS]} requiredPermissions={[PermissionEnum.MANAGE_SETTINGS]}
> >

View file

@ -139,7 +139,7 @@ const SiteSettingsPage: React.FC<SiteSettingsPageProps> = props => {
const handleCountrySelect = createCountryHandler(countrySelect, set); const handleCountrySelect = createCountryHandler(countrySelect, set);
return ( return (
<DetailedContent> <DetailedContent useSingleColumn>
<TopNav <TopNav
href={configurationMenuUrl} href={configurationMenuUrl}
title={intl.formatMessage(commonMessages.generalInformations)} title={intl.formatMessage(commonMessages.generalInformations)}