Basic sidebar version (#3039)
This commit is contained in:
parent
112747a51c
commit
1e6b53e249
4 changed files with 343 additions and 12 deletions
14
package-lock.json
generated
14
package-lock.json
generated
|
@ -27,7 +27,7 @@
|
||||||
"@material-ui/lab": "^4.0.0-alpha.61",
|
"@material-ui/lab": "^4.0.0-alpha.61",
|
||||||
"@material-ui/styles": "^4.11.4",
|
"@material-ui/styles": "^4.11.4",
|
||||||
"@reach/auto-id": "^0.16.0",
|
"@reach/auto-id": "^0.16.0",
|
||||||
"@saleor/macaw-ui": "^0.8.0-pre.1",
|
"@saleor/macaw-ui": "^0.8.0-pre.4",
|
||||||
"@saleor/sdk": "^0.4.4",
|
"@saleor/sdk": "^0.4.4",
|
||||||
"@sentry/react": "^6.0.0",
|
"@sentry/react": "^6.0.0",
|
||||||
"@types/faker": "^5.1.6",
|
"@types/faker": "^5.1.6",
|
||||||
|
@ -7235,9 +7235,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@saleor/macaw-ui": {
|
"node_modules/@saleor/macaw-ui": {
|
||||||
"version": "0.8.0-pre.1",
|
"version": "0.8.0-pre.4",
|
||||||
"resolved": "https://registry.npmjs.org/@saleor/macaw-ui/-/macaw-ui-0.8.0-pre.1.tgz",
|
"resolved": "https://registry.npmjs.org/@saleor/macaw-ui/-/macaw-ui-0.8.0-pre.4.tgz",
|
||||||
"integrity": "sha512-zNnLJcm13HMqGJjHmjyoLL/lQ5dIefUbOq/Ws7wxPn1Bh0wwhY/3T+Qc6iG5W9gvIcpTXJojwL7tT31DHQ2KRw==",
|
"integrity": "sha512-9x97IhjCxZ5FD0b3pJfNs2U3YEvsnlJWZHXvGZKPztr0XbtkGbMy5EdHazSH/lNeI3g2T9CE9uKONyatiXAvmw==",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=16 <19"
|
"node": ">=16 <19"
|
||||||
},
|
},
|
||||||
|
@ -44660,9 +44660,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@saleor/macaw-ui": {
|
"@saleor/macaw-ui": {
|
||||||
"version": "0.8.0-pre.1",
|
"version": "0.8.0-pre.4",
|
||||||
"resolved": "https://registry.npmjs.org/@saleor/macaw-ui/-/macaw-ui-0.8.0-pre.1.tgz",
|
"resolved": "https://registry.npmjs.org/@saleor/macaw-ui/-/macaw-ui-0.8.0-pre.4.tgz",
|
||||||
"integrity": "sha512-zNnLJcm13HMqGJjHmjyoLL/lQ5dIefUbOq/Ws7wxPn1Bh0wwhY/3T+Qc6iG5W9gvIcpTXJojwL7tT31DHQ2KRw=="
|
"integrity": "sha512-9x97IhjCxZ5FD0b3pJfNs2U3YEvsnlJWZHXvGZKPztr0XbtkGbMy5EdHazSH/lNeI3g2T9CE9uKONyatiXAvmw=="
|
||||||
},
|
},
|
||||||
"@saleor/sdk": {
|
"@saleor/sdk": {
|
||||||
"version": "0.4.4",
|
"version": "0.4.4",
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
"@editorjs/list": "^1.7.0",
|
"@editorjs/list": "^1.7.0",
|
||||||
"@editorjs/paragraph": "^2.8.0",
|
"@editorjs/paragraph": "^2.8.0",
|
||||||
"@editorjs/quote": "^2.4.0",
|
"@editorjs/quote": "^2.4.0",
|
||||||
|
"@floating-ui/react-dom-interactions": "^0.5.0",
|
||||||
"@glideapps/glide-data-grid": "^5.0.0",
|
"@glideapps/glide-data-grid": "^5.0.0",
|
||||||
"@graphiql/plugin-explorer": "^0.1.12",
|
"@graphiql/plugin-explorer": "^0.1.12",
|
||||||
"@graphiql/react": "^0.15.0",
|
"@graphiql/react": "^0.15.0",
|
||||||
|
@ -33,9 +34,8 @@
|
||||||
"@material-ui/lab": "^4.0.0-alpha.61",
|
"@material-ui/lab": "^4.0.0-alpha.61",
|
||||||
"@material-ui/styles": "^4.11.4",
|
"@material-ui/styles": "^4.11.4",
|
||||||
"@reach/auto-id": "^0.16.0",
|
"@reach/auto-id": "^0.16.0",
|
||||||
"@saleor/macaw-ui": "^0.8.0-pre.1",
|
"@saleor/macaw-ui": "^0.8.0-pre.4",
|
||||||
"@saleor/sdk": "^0.4.4",
|
"@saleor/sdk": "^0.4.4",
|
||||||
"@floating-ui/react-dom-interactions": "^0.5.0",
|
|
||||||
"@sentry/react": "^6.0.0",
|
"@sentry/react": "^6.0.0",
|
||||||
"@types/faker": "^5.1.6",
|
"@types/faker": "^5.1.6",
|
||||||
"@uiw/react-color-hue": "0.0.34",
|
"@uiw/react-color-hue": "0.0.34",
|
||||||
|
@ -204,6 +204,7 @@
|
||||||
"husky": "^8.0.0",
|
"husky": "^8.0.0",
|
||||||
"jest": "^27.5.1",
|
"jest": "^27.5.1",
|
||||||
"jest-canvas-mock": "^2.4.0",
|
"jest-canvas-mock": "^2.4.0",
|
||||||
|
"jest-environment-jsdom": "^27.5.1",
|
||||||
"jest-file": "^1.0.0",
|
"jest-file": "^1.0.0",
|
||||||
"jest-localstorage-mock": "^2.4.3",
|
"jest-localstorage-mock": "^2.4.3",
|
||||||
"lint-staged": "^10.5.1",
|
"lint-staged": "^10.5.1",
|
||||||
|
@ -213,8 +214,7 @@
|
||||||
"mochawesome-report-generator": "^6.0.1",
|
"mochawesome-report-generator": "^6.0.1",
|
||||||
"prettier": "^2.8.3",
|
"prettier": "^2.8.3",
|
||||||
"setup-polly-jest": "^0.9.1",
|
"setup-polly-jest": "^0.9.1",
|
||||||
"ts-jest": "^27.1.5",
|
"ts-jest": "^27.1.5"
|
||||||
"jest-environment-jsdom": "^27.5.1"
|
|
||||||
},
|
},
|
||||||
"jest": {
|
"jest": {
|
||||||
"resetMocks": false,
|
"resetMocks": false,
|
||||||
|
|
|
@ -1,3 +1,42 @@
|
||||||
|
import { useUser } from "@dashboard/auth";
|
||||||
|
import { Box, List, sprinkles, Text } from "@saleor/macaw-ui/next";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
import { useIntl } from "react-intl";
|
||||||
|
import { Link } from "react-router-dom";
|
||||||
|
|
||||||
export const NewSidebar = () => <div>Work in progress</div>;
|
import useMenuStructure from "./useMenuStructure";
|
||||||
|
|
||||||
|
export const NewSidebar = () => {
|
||||||
|
const intl = useIntl();
|
||||||
|
const { user } = useUser();
|
||||||
|
const [menuStructure] = useMenuStructure(intl, user);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box
|
||||||
|
backgroundColor="subdued"
|
||||||
|
as="aside"
|
||||||
|
padding={5}
|
||||||
|
borderColor="neutralPlain"
|
||||||
|
borderRightWidth={1}
|
||||||
|
borderRightStyle="solid"
|
||||||
|
>
|
||||||
|
<List as="ol">
|
||||||
|
{menuStructure.map(menuItem => (
|
||||||
|
<List.Item borderRadius={3} key={menuItem.id}>
|
||||||
|
<Link
|
||||||
|
to={menuItem.url}
|
||||||
|
className={sprinkles({
|
||||||
|
padding: 4,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<Box display="flex" alignItems="center" gap={5}>
|
||||||
|
{menuItem.icon}
|
||||||
|
<Text>{menuItem.label}</Text>
|
||||||
|
</Box>
|
||||||
|
</Link>
|
||||||
|
</List.Item>
|
||||||
|
))}
|
||||||
|
</List>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
292
src/components/Sidebar/useMenuStructure.tsx
Normal file
292
src/components/Sidebar/useMenuStructure.tsx
Normal file
|
@ -0,0 +1,292 @@
|
||||||
|
import { appsListPath } from "@dashboard/apps/urls";
|
||||||
|
import {
|
||||||
|
extensionMountPoints,
|
||||||
|
useExtensions,
|
||||||
|
} from "@dashboard/apps/useExtensions";
|
||||||
|
import { categoryListUrl } from "@dashboard/categories/urls";
|
||||||
|
import { collectionListUrl } from "@dashboard/collections/urls";
|
||||||
|
import { MARKETPLACE_URL } from "@dashboard/config";
|
||||||
|
import { configurationMenuUrl } from "@dashboard/configuration";
|
||||||
|
import { getConfigMenuItemsPermissions } from "@dashboard/configuration/utils";
|
||||||
|
import { customerListUrl } from "@dashboard/customers/urls";
|
||||||
|
import { saleListUrl, voucherListUrl } from "@dashboard/discounts/urls";
|
||||||
|
import { giftCardListUrl } from "@dashboard/giftCards/urls";
|
||||||
|
import { PermissionEnum, UserFragment } from "@dashboard/graphql";
|
||||||
|
import { commonMessages, sectionNames } from "@dashboard/intl";
|
||||||
|
import { marketplaceUrlResolver } from "@dashboard/marketplace/marketplace-url-resolver";
|
||||||
|
import { orderDraftListUrl, orderListUrl } from "@dashboard/orders/urls";
|
||||||
|
import { pageListPath } from "@dashboard/pages/urls";
|
||||||
|
import { productListUrl } from "@dashboard/products/urls";
|
||||||
|
import { languageListUrl } from "@dashboard/translations/urls";
|
||||||
|
import { SidebarMenuItem } from "@saleor/macaw-ui";
|
||||||
|
import {
|
||||||
|
ConfigurationIcon,
|
||||||
|
CustomersIcon,
|
||||||
|
HomeIcon,
|
||||||
|
MarketplaceIcon,
|
||||||
|
OrdersIcon,
|
||||||
|
ProductsIcons,
|
||||||
|
TableEditIcon,
|
||||||
|
TranslationsIcon,
|
||||||
|
VouchersIcon,
|
||||||
|
} from "@saleor/macaw-ui/next";
|
||||||
|
import React from "react";
|
||||||
|
import { IntlShape } from "react-intl";
|
||||||
|
|
||||||
|
import { getMenuItemExtension, mapToExtensionsItems } from "./legacy/utils";
|
||||||
|
|
||||||
|
export interface FilterableMenuItem extends Omit<any, "children"> {
|
||||||
|
children?: FilterableMenuItem[];
|
||||||
|
permissions?: PermissionEnum[];
|
||||||
|
}
|
||||||
|
|
||||||
|
function useMenuStructure(intl: IntlShape, user: UserFragment) {
|
||||||
|
const extensions = useExtensions(extensionMountPoints.NAVIGATION_SIDEBAR);
|
||||||
|
|
||||||
|
const handleMenuItemClick = (menuItem: SidebarMenuItem) => {
|
||||||
|
const extension = getMenuItemExtension(extensions, menuItem);
|
||||||
|
if (extension) {
|
||||||
|
extension.open();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const appExtensionsHeaderItem = {
|
||||||
|
id: "extensions",
|
||||||
|
label: intl.formatMessage(sectionNames.appExtensions),
|
||||||
|
};
|
||||||
|
|
||||||
|
// This will be deleted when Marketplace is released
|
||||||
|
// Consider this solution as temporary
|
||||||
|
const getAppSection = () => {
|
||||||
|
if (MARKETPLACE_URL) {
|
||||||
|
return {
|
||||||
|
icon: <MarketplaceIcon color="iconNeutralSubdued" />,
|
||||||
|
label: intl.formatMessage(sectionNames.apps),
|
||||||
|
permissions: [PermissionEnum.MANAGE_APPS],
|
||||||
|
id: "apps_section",
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
label: intl.formatMessage(sectionNames.apps),
|
||||||
|
id: "apps",
|
||||||
|
url: appsListPath,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: intl.formatMessage(sectionNames.marketplace),
|
||||||
|
id: "marketplace-saleor-apps",
|
||||||
|
url: marketplaceUrlResolver.getSaleorAppsDashboardPath(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ariaLabel: "marketplace",
|
||||||
|
label: intl.formatMessage(sectionNames.appTemplateGallery),
|
||||||
|
id: "marketplace-template-gallery",
|
||||||
|
url: marketplaceUrlResolver.getTemplateGalleryDashboardPath(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
icon: <MarketplaceIcon color="iconNeutralSubdued" />,
|
||||||
|
label: intl.formatMessage(sectionNames.apps),
|
||||||
|
permissions: [PermissionEnum.MANAGE_APPS],
|
||||||
|
id: "apps",
|
||||||
|
url: appsListPath,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const menuItems = [
|
||||||
|
{
|
||||||
|
icon: <HomeIcon color="iconNeutralSubdued" />,
|
||||||
|
label: intl.formatMessage(sectionNames.home),
|
||||||
|
id: "home",
|
||||||
|
url: "/",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
label: intl.formatMessage(sectionNames.products),
|
||||||
|
id: "products",
|
||||||
|
url: productListUrl(),
|
||||||
|
permissions: [PermissionEnum.MANAGE_PRODUCTS],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: intl.formatMessage(sectionNames.categories),
|
||||||
|
id: "categories",
|
||||||
|
url: categoryListUrl(),
|
||||||
|
permissions: [PermissionEnum.MANAGE_PRODUCTS],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: intl.formatMessage(sectionNames.collections),
|
||||||
|
id: "collections",
|
||||||
|
url: collectionListUrl(),
|
||||||
|
permissions: [PermissionEnum.MANAGE_PRODUCTS],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: intl.formatMessage(sectionNames.giftCards),
|
||||||
|
id: "giftCards",
|
||||||
|
url: giftCardListUrl(),
|
||||||
|
permissions: [PermissionEnum.MANAGE_GIFT_CARD],
|
||||||
|
},
|
||||||
|
...mapToExtensionsItems(
|
||||||
|
extensions.NAVIGATION_CATALOG,
|
||||||
|
appExtensionsHeaderItem,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
icon: <ProductsIcons color="iconNeutralSubdued" />,
|
||||||
|
label: intl.formatMessage(commonMessages.catalog),
|
||||||
|
permissions: [
|
||||||
|
PermissionEnum.MANAGE_GIFT_CARD,
|
||||||
|
PermissionEnum.MANAGE_PRODUCTS,
|
||||||
|
],
|
||||||
|
id: "catalogue",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
label: intl.formatMessage(sectionNames.orders),
|
||||||
|
permissions: [PermissionEnum.MANAGE_ORDERS],
|
||||||
|
id: "orders",
|
||||||
|
url: orderListUrl(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: intl.formatMessage(commonMessages.drafts),
|
||||||
|
permissions: [PermissionEnum.MANAGE_ORDERS],
|
||||||
|
id: "order-drafts",
|
||||||
|
url: orderDraftListUrl(),
|
||||||
|
},
|
||||||
|
...mapToExtensionsItems(
|
||||||
|
extensions.NAVIGATION_ORDERS,
|
||||||
|
appExtensionsHeaderItem,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
icon: <OrdersIcon color="iconNeutralSubdued" />,
|
||||||
|
label: intl.formatMessage(sectionNames.orders),
|
||||||
|
permissions: [PermissionEnum.MANAGE_ORDERS],
|
||||||
|
id: "orders",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
children: extensions.NAVIGATION_CUSTOMERS.length > 0 && [
|
||||||
|
{
|
||||||
|
label: intl.formatMessage(sectionNames.customers),
|
||||||
|
permissions: [PermissionEnum.MANAGE_USERS],
|
||||||
|
id: "customers",
|
||||||
|
url: customerListUrl(),
|
||||||
|
},
|
||||||
|
...mapToExtensionsItems(
|
||||||
|
extensions.NAVIGATION_CUSTOMERS,
|
||||||
|
appExtensionsHeaderItem,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
icon: <CustomersIcon color="iconNeutralSubdued" />,
|
||||||
|
label: intl.formatMessage(sectionNames.customers),
|
||||||
|
permissions: [PermissionEnum.MANAGE_USERS],
|
||||||
|
id: "customers",
|
||||||
|
url: customerListUrl(),
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
label: intl.formatMessage(sectionNames.sales),
|
||||||
|
id: "sales",
|
||||||
|
url: saleListUrl(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: intl.formatMessage(sectionNames.vouchers),
|
||||||
|
id: "vouchers",
|
||||||
|
url: voucherListUrl(),
|
||||||
|
},
|
||||||
|
...mapToExtensionsItems(
|
||||||
|
extensions.NAVIGATION_DISCOUNTS,
|
||||||
|
appExtensionsHeaderItem,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
icon: <VouchersIcon color="iconNeutralSubdued" />,
|
||||||
|
label: intl.formatMessage(commonMessages.discounts),
|
||||||
|
permissions: [PermissionEnum.MANAGE_DISCOUNTS],
|
||||||
|
id: "discounts",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
children: extensions.NAVIGATION_PAGES.length > 0 && [
|
||||||
|
{
|
||||||
|
label: intl.formatMessage(sectionNames.pages),
|
||||||
|
permissions: [PermissionEnum.MANAGE_PAGES],
|
||||||
|
id: "pages",
|
||||||
|
url: pageListPath,
|
||||||
|
},
|
||||||
|
...mapToExtensionsItems(
|
||||||
|
extensions.NAVIGATION_PAGES,
|
||||||
|
appExtensionsHeaderItem,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
icon: <TableEditIcon color="iconNeutralSubdued" />,
|
||||||
|
label: intl.formatMessage(sectionNames.pages),
|
||||||
|
permissions: [PermissionEnum.MANAGE_PAGES],
|
||||||
|
id: "pages",
|
||||||
|
url: pageListPath,
|
||||||
|
},
|
||||||
|
getAppSection(),
|
||||||
|
{
|
||||||
|
children: extensions.NAVIGATION_TRANSLATIONS.length > 0 && [
|
||||||
|
{
|
||||||
|
label: intl.formatMessage(sectionNames.translations),
|
||||||
|
permissions: [PermissionEnum.MANAGE_TRANSLATIONS],
|
||||||
|
id: "translations",
|
||||||
|
url: languageListUrl,
|
||||||
|
},
|
||||||
|
...mapToExtensionsItems(
|
||||||
|
extensions.NAVIGATION_TRANSLATIONS,
|
||||||
|
appExtensionsHeaderItem,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
icon: <TranslationsIcon color="iconNeutralSubdued" />,
|
||||||
|
label: intl.formatMessage(sectionNames.translations),
|
||||||
|
permissions: [PermissionEnum.MANAGE_TRANSLATIONS],
|
||||||
|
id: "translations",
|
||||||
|
url: languageListUrl,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: <ConfigurationIcon color="iconNeutralSubdued" />,
|
||||||
|
label: intl.formatMessage(sectionNames.configuration),
|
||||||
|
permissions: getConfigMenuItemsPermissions(intl),
|
||||||
|
id: "configure",
|
||||||
|
url: configurationMenuUrl,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const isMenuItemPermitted = (menuItem: FilterableMenuItem) => {
|
||||||
|
const userPermissions = (user?.userPermissions || []).map(
|
||||||
|
permission => permission.code,
|
||||||
|
);
|
||||||
|
if (!menuItem?.permissions || menuItem?.permissions?.length < 1) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return menuItem.permissions.some(permission =>
|
||||||
|
userPermissions.includes(permission),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getFilteredMenuItems = (menuItems: FilterableMenuItem[]) =>
|
||||||
|
menuItems.filter(isMenuItemPermitted);
|
||||||
|
|
||||||
|
return [
|
||||||
|
menuItems.reduce(
|
||||||
|
(resultItems: FilterableMenuItem[], menuItem: FilterableMenuItem) => {
|
||||||
|
if (!isMenuItemPermitted(menuItem)) {
|
||||||
|
return resultItems;
|
||||||
|
}
|
||||||
|
const { children } = menuItem;
|
||||||
|
const filteredChildren = children
|
||||||
|
? getFilteredMenuItems(children)
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
return [...resultItems, { ...menuItem, children: filteredChildren }];
|
||||||
|
},
|
||||||
|
[],
|
||||||
|
),
|
||||||
|
handleMenuItemClick,
|
||||||
|
] as const;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default useMenuStructure;
|
Loading…
Reference in a new issue