New macaw ui (#3069)
Co-authored-by: Krzysztof Żuraw <9116238+krzysztofzuraw@users.noreply.github.com> Co-authored-by: Michał Droń <dron.official@yahoo.com> Co-authored-by: Paweł Chyła <chyla1988@gmail.com>
This commit is contained in:
parent
91bd9c772d
commit
3789f5bb52
279 changed files with 11146 additions and 21463 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -21,7 +21,6 @@
|
||||||
!.travis*
|
!.travis*
|
||||||
!.tx
|
!.tx
|
||||||
!.husky
|
!.husky
|
||||||
*.css
|
|
||||||
*.log
|
*.log
|
||||||
*.pyc
|
*.pyc
|
||||||
*.mo
|
*.mo
|
||||||
|
|
BIN
assets/images/sidebar-default-logo.png
Normal file
BIN
assets/images/sidebar-default-logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4 KiB |
|
@ -116,6 +116,7 @@ describe("As an admin I want to manage categories", () => {
|
||||||
createCategory({ name: categoryName, description: categoryName })
|
createCategory({ name: categoryName, description: categoryName })
|
||||||
.visit(categoryDetailsUrl(category.id))
|
.visit(categoryDetailsUrl(category.id))
|
||||||
.contains(CATEGORY_DETAILS.categoryChildrenRow, categoryName)
|
.contains(CATEGORY_DETAILS.categoryChildrenRow, categoryName)
|
||||||
|
.scrollIntoView()
|
||||||
.should("be.visible");
|
.should("be.visible");
|
||||||
getCategory(category.id).then(categoryResp => {
|
getCategory(category.id).then(categoryResp => {
|
||||||
expect(categoryResp.children.edges[0].node.name).to.eq(categoryName);
|
expect(categoryResp.children.edges[0].node.name).to.eq(categoryName);
|
||||||
|
|
|
@ -9,7 +9,8 @@ import {
|
||||||
import { PERMISSIONS_OPTIONS } from "../fixtures/permissionsUsers";
|
import { PERMISSIONS_OPTIONS } from "../fixtures/permissionsUsers";
|
||||||
import * as permissionsSteps from "../support/pages/permissionsPage";
|
import * as permissionsSteps from "../support/pages/permissionsPage";
|
||||||
|
|
||||||
describe("As a staff user I want to navigate through shop using different permissions", () => {
|
// TODO: fix this test after release of new dashboard with sidebar
|
||||||
|
describe.skip("As a staff user I want to navigate through shop using different permissions", () => {
|
||||||
const permissionsOptions = PERMISSIONS_OPTIONS;
|
const permissionsOptions = PERMISSIONS_OPTIONS;
|
||||||
|
|
||||||
before(() => {
|
before(() => {
|
||||||
|
|
|
@ -11,21 +11,21 @@ export const LEFT_MENU_SELECTORS = {
|
||||||
customers: "[data-test-id='menu-item-label-customers']",
|
customers: "[data-test-id='menu-item-label-customers']",
|
||||||
};
|
};
|
||||||
export const DISCOUNTS_MENU_SELECTORS = {
|
export const DISCOUNTS_MENU_SELECTORS = {
|
||||||
sales: "[data-test-id='submenu-item-label-sales']",
|
sales: "[data-test-id='menu-item-label-sales']",
|
||||||
vouchers: "[data-test-id='submenu-item-label-vouchers']",
|
vouchers: "[data-test-id='menu-item-label-vouchers']",
|
||||||
};
|
};
|
||||||
export const ORDERS = {
|
export const ORDERS = {
|
||||||
orders: "[data-test-id='submenu-item-label-orders']",
|
orders: "[data-test-id='menu-item-label-orders']",
|
||||||
draftOrders: "[data-test-id='submenu-item-label-order-drafts']",
|
draftOrders: "[data-test-id='menu-item-label-order-drafts']",
|
||||||
};
|
};
|
||||||
export const CATALOG = {
|
export const CATALOG = {
|
||||||
products: "[data-test-id='submenu-item-label-products']",
|
products: "[data-test-id='menu-item-label-products']",
|
||||||
categories: "[data-test-id='submenu-item-label-categories']",
|
categories: "[data-test-id='menu-item-label-categories']",
|
||||||
collections: "[data-test-id='submenu-item-label-collections']",
|
collections: "[data-test-id='menu-item-label-collections']",
|
||||||
};
|
};
|
||||||
|
|
||||||
export const APP_MENU_SELECTORS = {
|
export const APP_MENU_SELECTORS = {
|
||||||
app: "[data-test-id='submenu-item-label-apps']",
|
app: "[data-test-id='menu-item-label-apps']",
|
||||||
};
|
};
|
||||||
|
|
||||||
export const appCommonSelector = "[data-test-id*='apps']";
|
export const appCommonSelector = "[data-test-id*='apps']";
|
||||||
|
|
|
@ -2,8 +2,8 @@ export const CATEGORY_DETAILS = {
|
||||||
nameInput: '[name="name"]',
|
nameInput: '[name="name"]',
|
||||||
descriptionInput: '[data-test-id="rich-text-editor-description"]',
|
descriptionInput: '[data-test-id="rich-text-editor-description"]',
|
||||||
createSubcategoryButton: '[data-test-id="create-subcategory"]',
|
createSubcategoryButton: '[data-test-id="create-subcategory"]',
|
||||||
categoryChildrenRow: '[data-test-id*="id"]',
|
categoryChildrenRow: "[data-test-id^='id-']",
|
||||||
productsTab: '[data-test-id="products-tab"]',
|
productsTab: '[data-test-id="products-tab"]',
|
||||||
addProducts: '[data-test-id="add-products"]',
|
addProducts: '[data-test-id="add-products"]',
|
||||||
productRow: '[data-test-id="product-row"]'
|
productRow: '[data-test-id="product-row"]',
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
export const PRODUCTS_LIST = {
|
export const PRODUCTS_LIST = {
|
||||||
productsList: "[data-test-id*='id']",
|
productsList: "[data-test-id^='id-']",
|
||||||
productsNames: "[data-test-id='name']",
|
productsNames: "[data-test-id='name']",
|
||||||
dialogProductTypeInput: "[data-test-id='dialog-product-type']",
|
dialogProductTypeInput: "[data-test-id='dialog-product-type']",
|
||||||
createProductBtn: "[data-test-id='add-product']",
|
createProductBtn: "[data-test-id='add-product']",
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
export const ORDERS_SELECTORS = {
|
export const ORDERS_SELECTORS = {
|
||||||
orders: "[data-test-id='submenu-item-label'][data-test-id='orders']",
|
orders: "[data-test-id='menu-item-label'][data-test-id='orders']",
|
||||||
createOrder: "[data-test-id='create-order-button']",
|
createOrder: "[data-test-id='create-order-button']",
|
||||||
orderRow: "[data-test-id='order-table-row']",
|
orderRow: "[data-test-id='order-table-row']",
|
||||||
salesChannel: "[data-test-id='order-sales-channel']",
|
salesChannel: "[data-test-id='order-sales-channel']",
|
||||||
|
|
|
@ -40,6 +40,8 @@ export function fillUpShippingZoneData({
|
||||||
.get(SHIPPING_ZONE_DETAILS.autocompleteContentDialog);
|
.get(SHIPPING_ZONE_DETAILS.autocompleteContentDialog);
|
||||||
cy.contains(SHIPPING_ZONE_DETAILS.option, warehouseName)
|
cy.contains(SHIPPING_ZONE_DETAILS.option, warehouseName)
|
||||||
.click({ force: true })
|
.click({ force: true })
|
||||||
|
.get(SHIPPING_ZONE_DETAILS.warehouseSelector)
|
||||||
|
.click()
|
||||||
.get(SHIPPING_ZONE_DETAILS.channelSelector)
|
.get(SHIPPING_ZONE_DETAILS.channelSelector)
|
||||||
.click()
|
.click()
|
||||||
.get(SHIPPING_ZONE_DETAILS.option)
|
.get(SHIPPING_ZONE_DETAILS.option)
|
||||||
|
|
|
@ -543,10 +543,6 @@
|
||||||
"context": "order status",
|
"context": "order status",
|
||||||
"string": "Partially returned"
|
"string": "Partially returned"
|
||||||
},
|
},
|
||||||
"26VlBZ": {
|
|
||||||
"context": "information",
|
|
||||||
"string": "Problem occured during installation."
|
|
||||||
},
|
|
||||||
"28GZnc": {
|
"28GZnc": {
|
||||||
"string": "Start typing to begin search..."
|
"string": "Start typing to begin search..."
|
||||||
},
|
},
|
||||||
|
@ -966,6 +962,9 @@
|
||||||
"5LRkEs": {
|
"5LRkEs": {
|
||||||
"string": "The new dashboard and the GraphQL API are preview-quality software."
|
"string": "The new dashboard and the GraphQL API are preview-quality software."
|
||||||
},
|
},
|
||||||
|
"5ObBlW": {
|
||||||
|
"string": "Dark Mode"
|
||||||
|
},
|
||||||
"5OtU+V": {
|
"5OtU+V": {
|
||||||
"context": "dialog title",
|
"context": "dialog title",
|
||||||
"string": "Unassign products from collection"
|
"string": "Unassign products from collection"
|
||||||
|
@ -1716,6 +1715,10 @@
|
||||||
"context": "header",
|
"context": "header",
|
||||||
"string": "Activity"
|
"string": "Activity"
|
||||||
},
|
},
|
||||||
|
"BYGJ/j": {
|
||||||
|
"context": "button label",
|
||||||
|
"string": "Settings"
|
||||||
|
},
|
||||||
"BZ7BkQ": {
|
"BZ7BkQ": {
|
||||||
"context": "capture payment, button",
|
"context": "capture payment, button",
|
||||||
"string": "Capture"
|
"string": "Capture"
|
||||||
|
@ -2391,9 +2394,6 @@
|
||||||
"context": "webhooks inactive label",
|
"context": "webhooks inactive label",
|
||||||
"string": "Inactive"
|
"string": "Inactive"
|
||||||
},
|
},
|
||||||
"GOdq5V": {
|
|
||||||
"string": "Catalog"
|
|
||||||
},
|
|
||||||
"GVM/fi": {
|
"GVM/fi": {
|
||||||
"context": "order history message",
|
"context": "order history message",
|
||||||
"string": "Payment was authorized"
|
"string": "Payment was authorized"
|
||||||
|
@ -3333,6 +3333,9 @@
|
||||||
"context": "webhook input label",
|
"context": "webhook input label",
|
||||||
"string": "Secret Key"
|
"string": "Secret Key"
|
||||||
},
|
},
|
||||||
|
"NQgbYA": {
|
||||||
|
"string": "Account Settings"
|
||||||
|
},
|
||||||
"NUevU9": {
|
"NUevU9": {
|
||||||
"context": "attribute values list: slug column header",
|
"context": "attribute values list: slug column header",
|
||||||
"string": "Swatch"
|
"string": "Swatch"
|
||||||
|
@ -3572,9 +3575,6 @@
|
||||||
"context": "dialog header",
|
"context": "dialog header",
|
||||||
"string": "Cancel Order"
|
"string": "Cancel Order"
|
||||||
},
|
},
|
||||||
"PRlD0A": {
|
|
||||||
"string": "Shipping"
|
|
||||||
},
|
|
||||||
"PTW56s": {
|
"PTW56s": {
|
||||||
"context": "alert",
|
"context": "alert",
|
||||||
"string": "Channel limit reached"
|
"string": "Channel limit reached"
|
||||||
|
@ -3886,6 +3886,10 @@
|
||||||
"context": "copy code button label",
|
"context": "copy code button label",
|
||||||
"string": "Copy code"
|
"string": "Copy code"
|
||||||
},
|
},
|
||||||
|
"RY4PJY": {
|
||||||
|
"context": "information",
|
||||||
|
"string": "Installation failed"
|
||||||
|
},
|
||||||
"RZ32u5": {
|
"RZ32u5": {
|
||||||
"context": "PageTypeDeleteWarningDialog single consent label",
|
"context": "PageTypeDeleteWarningDialog single consent label",
|
||||||
"string": "Yes, I want to delete this page type and assigned pages"
|
"string": "Yes, I want to delete this page type and assigned pages"
|
||||||
|
@ -5895,6 +5899,9 @@
|
||||||
"context": "channel publication date",
|
"context": "channel publication date",
|
||||||
"string": "Will become published on {date}"
|
"string": "Will become published on {date}"
|
||||||
},
|
},
|
||||||
|
"hVPucN": {
|
||||||
|
"string": "Light Mode"
|
||||||
|
},
|
||||||
"hWO1SD": {
|
"hWO1SD": {
|
||||||
"context": "order history message",
|
"context": "order history message",
|
||||||
"string": "Draft order was created"
|
"string": "Draft order was created"
|
||||||
|
@ -6387,6 +6394,10 @@
|
||||||
"context": "selectt all options",
|
"context": "selectt all options",
|
||||||
"string": "Select All"
|
"string": "Select All"
|
||||||
},
|
},
|
||||||
|
"lSd5Zo": {
|
||||||
|
"context": "app permissions label",
|
||||||
|
"string": "None"
|
||||||
|
},
|
||||||
"lT5MYM": {
|
"lT5MYM": {
|
||||||
"context": "dialog title",
|
"context": "dialog title",
|
||||||
"string": "Unassign users"
|
"string": "Unassign users"
|
||||||
|
@ -7008,6 +7019,9 @@
|
||||||
"context": "bulk delete label",
|
"context": "bulk delete label",
|
||||||
"string": "Delete"
|
"string": "Delete"
|
||||||
},
|
},
|
||||||
|
"qnPzX7": {
|
||||||
|
"string": "Channels that don’t have assigned discounts will use their parent channel to define the value. Value will be converted to channel’s currency"
|
||||||
|
},
|
||||||
"qov29K": {
|
"qov29K": {
|
||||||
"context": "dialog content",
|
"context": "dialog content",
|
||||||
"string": "Select one of customer addresses or add a new address:"
|
"string": "Select one of customer addresses or add a new address:"
|
||||||
|
@ -7948,9 +7962,6 @@
|
||||||
"y/UWBR": {
|
"y/UWBR": {
|
||||||
"string": "There is no address to show for this customer"
|
"string": "There is no address to show for this customer"
|
||||||
},
|
},
|
||||||
"y1Z3or": {
|
|
||||||
"string": "Language"
|
|
||||||
},
|
|
||||||
"y7mfbl": {
|
"y7mfbl": {
|
||||||
"string": "Currently, there are no countries assigned to this shipping zone"
|
"string": "Currently, there are no countries assigned to this shipping zone"
|
||||||
},
|
},
|
||||||
|
|
18963
package-lock.json
generated
18963
package-lock.json
generated
File diff suppressed because it is too large
Load diff
11
package.json
11
package.json
|
@ -24,7 +24,6 @@
|
||||||
"@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",
|
||||||
|
@ -34,13 +33,14 @@
|
||||||
"@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.7.2",
|
"@saleor/macaw-ui": "^0.8.0-pre.31",
|
||||||
"@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",
|
||||||
"@uiw/react-color-hue": "0.0.34",
|
"@uiw/react-color-hue": "0.0.34",
|
||||||
"@uiw/react-color-material": "^0.1.0",
|
"@uiw/react-color-material": "^0.1.0",
|
||||||
"@uiw/react-color-saturation": "0.0.34",
|
"@uiw/react-color-saturation": "0.0.34",
|
||||||
|
"@vanilla-extract/css-utils": "^0.1.3",
|
||||||
"apollo-upload-client": "^17.0.0",
|
"apollo-upload-client": "^17.0.0",
|
||||||
"clsx": "^1.2.1",
|
"clsx": "^1.2.1",
|
||||||
"color-convert": "^2.0.1",
|
"color-convert": "^2.0.1",
|
||||||
|
@ -88,8 +88,10 @@
|
||||||
"react-sortable-tree": "^2.6.2",
|
"react-sortable-tree": "^2.6.2",
|
||||||
"semver-compare": "^1.0.0",
|
"semver-compare": "^1.0.0",
|
||||||
"slugify": "^1.4.6",
|
"slugify": "^1.4.6",
|
||||||
|
"tslib": "^2.4.1",
|
||||||
"url-join": "^4.0.1",
|
"url-join": "^4.0.1",
|
||||||
"use-react-router": "^1.0.7"
|
"use-react-router": "^1.0.7",
|
||||||
|
"usehooks-ts": "^2.9.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/cli": "^7.5.5",
|
"@babel/cli": "^7.5.5",
|
||||||
|
@ -126,7 +128,6 @@
|
||||||
"@types/fuzzaldrin": "^2.1.2",
|
"@types/fuzzaldrin": "^2.1.2",
|
||||||
"@types/is-ci": "^3.0.0",
|
"@types/is-ci": "^3.0.0",
|
||||||
"@types/jscodeshift": "^0.11.3",
|
"@types/jscodeshift": "^0.11.3",
|
||||||
"@types/lodash-es": "^4.17.3",
|
|
||||||
"@types/pollyjs__adapter-node-http": "^2.0.1",
|
"@types/pollyjs__adapter-node-http": "^2.0.1",
|
||||||
"@types/pollyjs__persister-fs": "^2.0.1",
|
"@types/pollyjs__persister-fs": "^2.0.1",
|
||||||
"@types/react": "^17.0.50",
|
"@types/react": "^17.0.50",
|
||||||
|
@ -250,10 +251,10 @@
|
||||||
"@locale(.*)$": "<rootDir>/locale/$1",
|
"@locale(.*)$": "<rootDir>/locale/$1",
|
||||||
"@dashboard(.*)$": "<rootDir>/src/$1",
|
"@dashboard(.*)$": "<rootDir>/src/$1",
|
||||||
"@test/(.*)$": "<rootDir>/testUtils/$1",
|
"@test/(.*)$": "<rootDir>/testUtils/$1",
|
||||||
"^lodash-es(.*)$": "lodash/$1",
|
|
||||||
"^@material-ui/core$": "<rootDir>/node_modules/@material-ui/core",
|
"^@material-ui/core$": "<rootDir>/node_modules/@material-ui/core",
|
||||||
"^@material-ui/icons$": "<rootDir>/node_modules/@material-ui/icons",
|
"^@material-ui/icons$": "<rootDir>/node_modules/@material-ui/icons",
|
||||||
"^@material-ui/styles$": "<rootDir>/node_modules/@material-ui/styles",
|
"^@material-ui/styles$": "<rootDir>/node_modules/@material-ui/styles",
|
||||||
|
"^@saleor/macaw-ui/next$": "<rootDir>/node_modules/@saleor/macaw-ui/dist/macaw-ui.cjs",
|
||||||
"^react$": "<rootDir>/node_modules/react",
|
"^react$": "<rootDir>/node_modules/react",
|
||||||
"^react-dom$": "<rootDir>/node_modules/react-dom"
|
"^react-dom$": "<rootDir>/node_modules/react-dom"
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,13 @@
|
||||||
import { appsListPath } from "@dashboard/apps/urls";
|
import { appsListPath } from "@dashboard/apps/urls";
|
||||||
import { Backlink } from "@dashboard/components/Backlink";
|
import { TopNav } from "@dashboard/components/AppLayout/TopNav";
|
||||||
import { Button } from "@dashboard/components/Button";
|
|
||||||
import CardSpacer from "@dashboard/components/CardSpacer";
|
import CardSpacer from "@dashboard/components/CardSpacer";
|
||||||
import CardTitle from "@dashboard/components/CardTitle";
|
import CardTitle from "@dashboard/components/CardTitle";
|
||||||
import Container from "@dashboard/components/Container";
|
|
||||||
import ExternalLink from "@dashboard/components/ExternalLink";
|
import ExternalLink from "@dashboard/components/ExternalLink";
|
||||||
import PageHeader from "@dashboard/components/PageHeader";
|
|
||||||
import Skeleton from "@dashboard/components/Skeleton";
|
import Skeleton from "@dashboard/components/Skeleton";
|
||||||
import { AppQuery } from "@dashboard/graphql";
|
import { AppQuery } from "@dashboard/graphql";
|
||||||
import { buttonMessages, sectionNames } from "@dashboard/intl";
|
import { buttonMessages } from "@dashboard/intl";
|
||||||
import { ButtonBase, Card, CardContent, Typography } from "@material-ui/core";
|
import { ButtonBase, Card, CardContent, Typography } from "@material-ui/core";
|
||||||
|
import { Box, Button } from "@saleor/macaw-ui/next";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import SVG from "react-inlinesvg";
|
import SVG from "react-inlinesvg";
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
|
@ -42,11 +40,9 @@ export const AppDetailsPage: React.FC<AppDetailsPageProps> = ({
|
||||||
const classes = useStyles({});
|
const classes = useStyles({});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container>
|
<>
|
||||||
<Backlink href={appsListPath}>
|
<TopNav
|
||||||
{intl.formatMessage(sectionNames.apps)}
|
href={appsListPath}
|
||||||
</Backlink>
|
|
||||||
<PageHeader
|
|
||||||
title={
|
title={
|
||||||
<>
|
<>
|
||||||
{data?.name} {!data?.isActive && <DeactivatedText />}
|
{data?.name} {!data?.isActive && <DeactivatedText />}
|
||||||
|
@ -60,8 +56,8 @@ export const AppDetailsPage: React.FC<AppDetailsPageProps> = ({
|
||||||
description="button"
|
description="button"
|
||||||
/>
|
/>
|
||||||
</Button>
|
</Button>
|
||||||
</PageHeader>
|
</TopNav>
|
||||||
<div className={classes.appHeader}>
|
<Box marginX={10}>
|
||||||
{data ? (
|
{data ? (
|
||||||
<div className={classes.appHeaderLinks}>
|
<div className={classes.appHeaderLinks}>
|
||||||
<ExternalLink
|
<ExternalLink
|
||||||
|
@ -101,7 +97,7 @@ export const AppDetailsPage: React.FC<AppDetailsPageProps> = ({
|
||||||
<Skeleton />
|
<Skeleton />
|
||||||
)}
|
)}
|
||||||
<div className={classes.hr} />
|
<div className={classes.hr} />
|
||||||
</div>
|
</Box>
|
||||||
|
|
||||||
<Card>
|
<Card>
|
||||||
<CardTitle
|
<CardTitle
|
||||||
|
@ -182,7 +178,7 @@ export const AppDetailsPage: React.FC<AppDetailsPageProps> = ({
|
||||||
</Card>
|
</Card>
|
||||||
)}
|
)}
|
||||||
<CardSpacer />
|
<CardSpacer />
|
||||||
</Container>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,21 @@
|
||||||
import saleorDarkLogoSmall from "@assets/images/logo-dark-small.svg";
|
import saleorDarkLogoSmall from "@assets/images/logo-dark-small.svg";
|
||||||
import plusIcon from "@assets/images/plus-icon.svg";
|
import plusIcon from "@assets/images/plus-icon.svg";
|
||||||
import { Button } from "@dashboard/components/Button";
|
import { Content } from "@dashboard/components/AppLayout/Content";
|
||||||
|
import { DetailedContent } from "@dashboard/components/AppLayout/DetailedContent";
|
||||||
import CardSpacer from "@dashboard/components/CardSpacer";
|
import CardSpacer from "@dashboard/components/CardSpacer";
|
||||||
import CardTitle from "@dashboard/components/CardTitle";
|
import CardTitle from "@dashboard/components/CardTitle";
|
||||||
import Container from "@dashboard/components/Container";
|
|
||||||
import Hr from "@dashboard/components/Hr";
|
import Hr from "@dashboard/components/Hr";
|
||||||
import Skeleton from "@dashboard/components/Skeleton";
|
import Skeleton from "@dashboard/components/Skeleton";
|
||||||
import { AppFetchMutation, AppInstallMutation } from "@dashboard/graphql";
|
import { AppFetchMutation, AppInstallMutation } from "@dashboard/graphql";
|
||||||
import { SubmitPromise } from "@dashboard/hooks/useForm";
|
import { SubmitPromise } from "@dashboard/hooks/useForm";
|
||||||
import { buttonMessages } from "@dashboard/intl";
|
import { buttonMessages } from "@dashboard/intl";
|
||||||
import { Card, CardContent, Grid, Typography } from "@material-ui/core";
|
import {
|
||||||
|
Card,
|
||||||
|
CardContent,
|
||||||
|
CircularProgress,
|
||||||
|
Typography,
|
||||||
|
} from "@material-ui/core";
|
||||||
|
import { Box, Button, GenericAppIcon } from "@saleor/macaw-ui/next";
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
|
@ -37,7 +43,8 @@ export const AppInstallPage: React.FC<AppInstallPageProps> = ({
|
||||||
const name = data?.name || "";
|
const name = data?.name || "";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container>
|
<DetailedContent useSingleColumn constHeight>
|
||||||
|
<Content>
|
||||||
<CardSpacer />
|
<CardSpacer />
|
||||||
<Card>
|
<Card>
|
||||||
<CardTitle
|
<CardTitle
|
||||||
|
@ -58,17 +65,20 @@ export const AppInstallPage: React.FC<AppInstallPageProps> = ({
|
||||||
/>
|
/>
|
||||||
<CardContent className={classes.installCard}>
|
<CardContent className={classes.installCard}>
|
||||||
{loading ? (
|
{loading ? (
|
||||||
<Skeleton />
|
<CircularProgress />
|
||||||
) : (
|
) : (
|
||||||
<div className={classes.installAppContainer}>
|
<div className={classes.installAppContainer}>
|
||||||
<div
|
<div
|
||||||
className={clsx(classes.installIcon, classes.installSaleorIcon)}
|
className={clsx(
|
||||||
|
classes.installIcon,
|
||||||
|
classes.installSaleorIcon,
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
<img src={saleorDarkLogoSmall} alt="" />
|
<img src={saleorDarkLogoSmall} alt="" />
|
||||||
</div>
|
</div>
|
||||||
<img src={plusIcon} alt="" />
|
<img src={plusIcon} alt="" />
|
||||||
<div className={classes.installIcon}>
|
<div className={classes.installIcon}>
|
||||||
<h2>{name?.charAt(0).toUpperCase()}</h2>
|
<GenericAppIcon />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
@ -76,6 +86,7 @@ export const AppInstallPage: React.FC<AppInstallPageProps> = ({
|
||||||
</Card>
|
</Card>
|
||||||
<CardSpacer />
|
<CardSpacer />
|
||||||
<Card>
|
<Card>
|
||||||
|
{!loading && (
|
||||||
<CardTitle
|
<CardTitle
|
||||||
title={intl.formatMessage({
|
title={intl.formatMessage({
|
||||||
id: "VsGcdP",
|
id: "VsGcdP",
|
||||||
|
@ -83,6 +94,7 @@ export const AppInstallPage: React.FC<AppInstallPageProps> = ({
|
||||||
description: "section header",
|
description: "section header",
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
<CardContent>
|
<CardContent>
|
||||||
{loading ? (
|
{loading ? (
|
||||||
<Skeleton />
|
<Skeleton />
|
||||||
|
@ -133,13 +145,10 @@ export const AppInstallPage: React.FC<AppInstallPageProps> = ({
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
<CardSpacer />
|
<CardSpacer />
|
||||||
<Grid container justify="space-between">
|
<Box display="flex" justifyContent="space-between">
|
||||||
<Grid xs={6} item>
|
|
||||||
<Button variant="secondary" onClick={navigateToAppsList}>
|
<Button variant="secondary" onClick={navigateToAppsList}>
|
||||||
<FormattedMessage {...buttonMessages.cancel} />
|
<FormattedMessage {...buttonMessages.cancel} />
|
||||||
</Button>
|
</Button>
|
||||||
</Grid>
|
|
||||||
<Grid xs={6} item className={classes.alignRight}>
|
|
||||||
<Button variant="primary" onClick={onSubmit}>
|
<Button variant="primary" onClick={onSubmit}>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id="PkCmGU"
|
id="PkCmGU"
|
||||||
|
@ -147,9 +156,9 @@ export const AppInstallPage: React.FC<AppInstallPageProps> = ({
|
||||||
description="install button"
|
description="install button"
|
||||||
/>
|
/>
|
||||||
</Button>
|
</Button>
|
||||||
</Grid>
|
</Box>
|
||||||
</Grid>
|
</Content>
|
||||||
</Container>
|
</DetailedContent>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import Container from "@dashboard/components/Container";
|
|
||||||
import { AppQuery } from "@dashboard/graphql";
|
import { AppQuery } from "@dashboard/graphql";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
|
@ -21,7 +20,6 @@ export const AppPage: React.FC<AppPageProps> = ({
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container className={classes.container}>
|
|
||||||
<div className={classes.iframeContainer}>
|
<div className={classes.iframeContainer}>
|
||||||
{url && (
|
{url && (
|
||||||
<AppFrame
|
<AppFrame
|
||||||
|
@ -33,7 +31,6 @@ export const AppPage: React.FC<AppPageProps> = ({
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</Container>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ export const useStyles = makeStyles(
|
||||||
height: "100%",
|
height: "100%",
|
||||||
"& > iframe": {
|
"& > iframe": {
|
||||||
border: "none",
|
border: "none",
|
||||||
minHeight: "60vh",
|
minHeight: "100vh",
|
||||||
height: "100%",
|
height: "100%",
|
||||||
width: "100%",
|
width: "100%",
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
import { AppPageTabs } from "@dashboard/apps/components/AppPageTabs/AppPageTabs";
|
import { AppPageTabs } from "@dashboard/apps/components/AppPageTabs/AppPageTabs";
|
||||||
import { useAppsPageNavigation } from "@dashboard/apps/hooks/useAppsPageNavigation";
|
import { useAppsPageNavigation } from "@dashboard/apps/hooks/useAppsPageNavigation";
|
||||||
import { useSaleorApps } from "@dashboard/apps/hooks/useSaleorApps";
|
import { useSaleorApps } from "@dashboard/apps/hooks/useSaleorApps";
|
||||||
|
import { TopNav } from "@dashboard/components/AppLayout/TopNav";
|
||||||
import CardSpacer from "@dashboard/components/CardSpacer";
|
import CardSpacer from "@dashboard/components/CardSpacer";
|
||||||
import Container from "@dashboard/components/Container";
|
|
||||||
import PageHeader from "@dashboard/components/PageHeader";
|
|
||||||
import {
|
import {
|
||||||
AppListItemFragment,
|
AppListItemFragment,
|
||||||
AppsInstallationsQuery,
|
AppsInstallationsQuery,
|
||||||
|
@ -175,8 +174,8 @@ const AppsListPage: React.FC<AppsListPageProps> = ({
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container>
|
<>
|
||||||
<PageHeader title={intl.formatMessage(sectionNames.apps)} />
|
<TopNav title={intl.formatMessage(sectionNames.apps)} />
|
||||||
<AppPageTabs
|
<AppPageTabs
|
||||||
showSaleorApps={saleorAppsEnabled}
|
showSaleorApps={saleorAppsEnabled}
|
||||||
className={styles.topTabs}
|
className={styles.topTabs}
|
||||||
|
@ -184,7 +183,7 @@ const AppsListPage: React.FC<AppsListPageProps> = ({
|
||||||
value={activeTab}
|
value={activeTab}
|
||||||
/>
|
/>
|
||||||
{renderContent()}
|
{renderContent()}
|
||||||
</Container>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ export const useStyles = makeStyles(
|
||||||
theme => ({
|
theme => ({
|
||||||
[theme.breakpoints.up("lg")]: {
|
[theme.breakpoints.up("lg")]: {
|
||||||
colName: {
|
colName: {
|
||||||
|
paddingLeft: "0 !important",
|
||||||
"&&": {
|
"&&": {
|
||||||
width: "auto",
|
width: "auto",
|
||||||
},
|
},
|
||||||
|
|
|
@ -64,10 +64,8 @@ export const AppsList: React.FC<AppsListProps> = ({ params }) => {
|
||||||
installations.filter(item => item.id !== id),
|
installations.filter(item => item.id !== id),
|
||||||
);
|
);
|
||||||
|
|
||||||
const {
|
const { data: appsInProgressData, refetch: appsInProgressRefetch } =
|
||||||
data: appsInProgressData,
|
useAppsInstallationsQuery({
|
||||||
refetch: appsInProgressRefetch,
|
|
||||||
} = useAppsInstallationsQuery({
|
|
||||||
displayLoader: false,
|
displayLoader: false,
|
||||||
});
|
});
|
||||||
const { data, loading, refetch } = useAppsListQuery({
|
const { data, loading, refetch } = useAppsListQuery({
|
||||||
|
@ -121,10 +119,8 @@ export const AppsList: React.FC<AppsListProps> = ({ params }) => {
|
||||||
AppListUrlQueryParams
|
AppListUrlQueryParams
|
||||||
>(navigate, appsListUrl, params);
|
>(navigate, appsListUrl, params);
|
||||||
|
|
||||||
const [
|
const [deleteInProgressApp, deleteInProgressAppOpts] =
|
||||||
deleteInProgressApp,
|
useAppDeleteFailedInstallationMutation({
|
||||||
deleteInProgressAppOpts,
|
|
||||||
] = useAppDeleteFailedInstallationMutation({
|
|
||||||
onCompleted: data => {
|
onCompleted: data => {
|
||||||
if (!data?.appDeleteFailedInstallation?.errors?.length) {
|
if (!data?.appDeleteFailedInstallation?.errors?.length) {
|
||||||
removeAppNotify();
|
removeAppNotify();
|
||||||
|
|
|
@ -2,7 +2,7 @@ import {
|
||||||
attributeAddUrl,
|
attributeAddUrl,
|
||||||
AttributeListUrlSortField,
|
AttributeListUrlSortField,
|
||||||
} from "@dashboard/attributes/urls";
|
} from "@dashboard/attributes/urls";
|
||||||
import { Backlink } from "@dashboard/components/Backlink";
|
import { TopNav } from "@dashboard/components/AppLayout/TopNav";
|
||||||
import { Button } from "@dashboard/components/Button";
|
import { Button } from "@dashboard/components/Button";
|
||||||
import FilterBar from "@dashboard/components/FilterBar";
|
import FilterBar from "@dashboard/components/FilterBar";
|
||||||
import { configurationMenuUrl } from "@dashboard/configuration";
|
import { configurationMenuUrl } from "@dashboard/configuration";
|
||||||
|
@ -12,8 +12,6 @@ import { Card } from "@material-ui/core";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
|
|
||||||
import Container from "../../../components/Container";
|
|
||||||
import PageHeader from "../../../components/PageHeader";
|
|
||||||
import {
|
import {
|
||||||
FilterPageProps,
|
FilterPageProps,
|
||||||
ListActions,
|
ListActions,
|
||||||
|
@ -55,11 +53,11 @@ const AttributeListPage: React.FC<AttributeListPageProps> = ({
|
||||||
const structure = createFilterStructure(intl, filterOpts);
|
const structure = createFilterStructure(intl, filterOpts);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container>
|
<>
|
||||||
<Backlink href={configurationMenuUrl}>
|
<TopNav
|
||||||
<FormattedMessage {...sectionNames.configuration} />
|
href={configurationMenuUrl}
|
||||||
</Backlink>
|
title={intl.formatMessage(sectionNames.attributes)}
|
||||||
<PageHeader title={intl.formatMessage(sectionNames.attributes)}>
|
>
|
||||||
<Button
|
<Button
|
||||||
href={attributeAddUrl()}
|
href={attributeAddUrl()}
|
||||||
variant="primary"
|
variant="primary"
|
||||||
|
@ -71,7 +69,7 @@ const AttributeListPage: React.FC<AttributeListPageProps> = ({
|
||||||
description="button"
|
description="button"
|
||||||
/>
|
/>
|
||||||
</Button>
|
</Button>
|
||||||
</PageHeader>
|
</TopNav>
|
||||||
<Card>
|
<Card>
|
||||||
<FilterBar
|
<FilterBar
|
||||||
allTabLabel={intl.formatMessage({
|
allTabLabel={intl.formatMessage({
|
||||||
|
@ -96,7 +94,7 @@ const AttributeListPage: React.FC<AttributeListPageProps> = ({
|
||||||
/>
|
/>
|
||||||
<AttributeList {...listProps} />
|
<AttributeList {...listProps} />
|
||||||
</Card>
|
</Card>
|
||||||
</Container>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
AttributeListPage.displayName = "AttributeListPage";
|
AttributeListPage.displayName = "AttributeListPage";
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
import { attributeListUrl } from "@dashboard/attributes/urls";
|
import { attributeListUrl } from "@dashboard/attributes/urls";
|
||||||
import { ATTRIBUTE_TYPES_WITH_DEDICATED_VALUES } from "@dashboard/attributes/utils/data";
|
import { ATTRIBUTE_TYPES_WITH_DEDICATED_VALUES } from "@dashboard/attributes/utils/data";
|
||||||
import { Backlink } from "@dashboard/components/Backlink";
|
import { Content } from "@dashboard/components/AppLayout/Content";
|
||||||
|
import { DetailedContent } from "@dashboard/components/AppLayout/DetailedContent";
|
||||||
|
import { RightSidebar } from "@dashboard/components/AppLayout/RightSidebar";
|
||||||
|
import { TopNav } from "@dashboard/components/AppLayout/TopNav";
|
||||||
import CardSpacer from "@dashboard/components/CardSpacer";
|
import CardSpacer from "@dashboard/components/CardSpacer";
|
||||||
import Container from "@dashboard/components/Container";
|
|
||||||
import Form from "@dashboard/components/Form";
|
import Form from "@dashboard/components/Form";
|
||||||
import Grid from "@dashboard/components/Grid";
|
|
||||||
import Metadata from "@dashboard/components/Metadata/Metadata";
|
import Metadata from "@dashboard/components/Metadata/Metadata";
|
||||||
import { MetadataFormData } from "@dashboard/components/Metadata/types";
|
import { MetadataFormData } from "@dashboard/components/Metadata/types";
|
||||||
import PageHeader from "@dashboard/components/PageHeader";
|
|
||||||
import Savebar from "@dashboard/components/Savebar";
|
import Savebar from "@dashboard/components/Savebar";
|
||||||
import { ListSettingsUpdate } from "@dashboard/components/TablePagination";
|
import { ListSettingsUpdate } from "@dashboard/components/TablePagination";
|
||||||
import {
|
import {
|
||||||
|
@ -21,7 +21,7 @@ import {
|
||||||
} from "@dashboard/graphql";
|
} from "@dashboard/graphql";
|
||||||
import { SubmitPromise } from "@dashboard/hooks/useForm";
|
import { SubmitPromise } from "@dashboard/hooks/useForm";
|
||||||
import useNavigator from "@dashboard/hooks/useNavigator";
|
import useNavigator from "@dashboard/hooks/useNavigator";
|
||||||
import { sectionNames } from "@dashboard/intl";
|
import { maybe } from "@dashboard/misc";
|
||||||
import { ListSettings, ReorderAction } from "@dashboard/types";
|
import { ListSettings, ReorderAction } from "@dashboard/types";
|
||||||
import { mapEdgesToItems, mapMetadataItemToInput } from "@dashboard/utils/maps";
|
import { mapEdgesToItems, mapMetadataItemToInput } from "@dashboard/utils/maps";
|
||||||
import useMetadataChangeTrigger from "@dashboard/utils/metadata/useMetadataChangeTrigger";
|
import useMetadataChangeTrigger from "@dashboard/utils/metadata/useMetadataChangeTrigger";
|
||||||
|
@ -173,23 +173,20 @@ const AttributePage: React.FC<AttributePageProps> = ({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Container>
|
<DetailedContent>
|
||||||
<Backlink href={attributeListUrl()}>
|
<TopNav
|
||||||
{intl.formatMessage(sectionNames.attributes)}
|
href={attributeListUrl()}
|
||||||
</Backlink>
|
|
||||||
<PageHeader
|
|
||||||
title={
|
title={
|
||||||
!attribute
|
attribute === null
|
||||||
? intl.formatMessage({
|
? intl.formatMessage({
|
||||||
id: "8cUEPV",
|
id: "8cUEPV",
|
||||||
defaultMessage: "Create New Attribute",
|
defaultMessage: "Create New Attribute",
|
||||||
description: "page title",
|
description: "page title",
|
||||||
})
|
})
|
||||||
: attribute.name
|
: maybe(() => attribute.name)
|
||||||
}
|
}
|
||||||
/>
|
></TopNav>
|
||||||
<Grid>
|
<Content>
|
||||||
<div>
|
|
||||||
<AttributeDetails
|
<AttributeDetails
|
||||||
canChangeType={attribute === null}
|
canChangeType={attribute === null}
|
||||||
data={data}
|
data={data}
|
||||||
|
@ -209,7 +206,7 @@ const AttributePage: React.FC<AttributePageProps> = ({
|
||||||
<AttributeValues
|
<AttributeValues
|
||||||
inputType={data.inputType}
|
inputType={data.inputType}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
values={mapEdgesToItems(values) ?? []}
|
values={mapEdgesToItems(values)}
|
||||||
onValueAdd={onValueAdd}
|
onValueAdd={onValueAdd}
|
||||||
onValueDelete={onValueDelete}
|
onValueDelete={onValueDelete}
|
||||||
onValueReorder={onValueReorder}
|
onValueReorder={onValueReorder}
|
||||||
|
@ -224,8 +221,8 @@ const AttributePage: React.FC<AttributePageProps> = ({
|
||||||
)}
|
)}
|
||||||
<CardSpacer />
|
<CardSpacer />
|
||||||
<Metadata data={data} onChange={changeMetadata} />
|
<Metadata data={data} onChange={changeMetadata} />
|
||||||
</div>
|
</Content>
|
||||||
<div>
|
<RightSidebar>
|
||||||
<AttributeOrganization
|
<AttributeOrganization
|
||||||
canChangeType={attribute === null}
|
canChangeType={attribute === null}
|
||||||
data={data}
|
data={data}
|
||||||
|
@ -239,8 +236,7 @@ const AttributePage: React.FC<AttributePageProps> = ({
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
onChange={change}
|
onChange={change}
|
||||||
/>
|
/>
|
||||||
</div>
|
</RightSidebar>
|
||||||
</Grid>
|
|
||||||
<Savebar
|
<Savebar
|
||||||
disabled={!!isSaveDisabled}
|
disabled={!!isSaveDisabled}
|
||||||
state={saveButtonBarState}
|
state={saveButtonBarState}
|
||||||
|
@ -248,7 +244,7 @@ const AttributePage: React.FC<AttributePageProps> = ({
|
||||||
onSubmit={submit}
|
onSubmit={submit}
|
||||||
onDelete={attribute === null ? undefined : onDelete}
|
onDelete={attribute === null ? undefined : onDelete}
|
||||||
/>
|
/>
|
||||||
</Container>
|
</DetailedContent>
|
||||||
{children(data)}
|
{children(data)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
|
@ -62,7 +62,7 @@ const AttributeValueEditDialog: React.FC<AttributeValueEditDialogProps> = ({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog onClose={onClose} open={open} fullWidth maxWidth="sm">
|
<Dialog onClose={onClose} open={open} fullWidth maxWidth="sm">
|
||||||
<DialogTitle>
|
<DialogTitle disableTypography>
|
||||||
{attributeValue === null ? (
|
{attributeValue === null ? (
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id="PqMbma"
|
id="PqMbma"
|
||||||
|
|
|
@ -8,6 +8,7 @@ import { CategoryDetailsFragment } from "@dashboard/graphql";
|
||||||
import { commonMessages } from "@dashboard/intl";
|
import { commonMessages } from "@dashboard/intl";
|
||||||
import { Card, CardContent, TextField } from "@material-ui/core";
|
import { Card, CardContent, TextField } from "@material-ui/core";
|
||||||
import { makeStyles } from "@saleor/macaw-ui";
|
import { makeStyles } from "@saleor/macaw-ui";
|
||||||
|
import { vars } 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";
|
||||||
|
|
||||||
|
@ -26,7 +27,7 @@ const useStyles = makeStyles(
|
||||||
},
|
},
|
||||||
imageContainer: {
|
imageContainer: {
|
||||||
background: "#ffffff",
|
background: "#ffffff",
|
||||||
border: "1px solid #eaeaea",
|
border: `1px solid ${vars.colors.border.neutralPlain}`,
|
||||||
borderRadius: theme.spacing(),
|
borderRadius: theme.spacing(),
|
||||||
height: 148,
|
height: 148,
|
||||||
justifySelf: "start",
|
justifySelf: "start",
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
import { Backlink } from "@dashboard/components/Backlink";
|
import { Content } from "@dashboard/components/AppLayout/Content";
|
||||||
|
import { DetailedContent } from "@dashboard/components/AppLayout/DetailedContent";
|
||||||
|
import { TopNav } from "@dashboard/components/AppLayout/TopNav";
|
||||||
import { CardSpacer } from "@dashboard/components/CardSpacer";
|
import { CardSpacer } from "@dashboard/components/CardSpacer";
|
||||||
import Container from "@dashboard/components/Container";
|
|
||||||
import Metadata from "@dashboard/components/Metadata";
|
import Metadata from "@dashboard/components/Metadata";
|
||||||
import PageHeader from "@dashboard/components/PageHeader";
|
|
||||||
import Savebar from "@dashboard/components/Savebar";
|
import Savebar from "@dashboard/components/Savebar";
|
||||||
import SeoForm from "@dashboard/components/SeoForm";
|
import SeoForm from "@dashboard/components/SeoForm";
|
||||||
import { ProductErrorFragment } from "@dashboard/graphql";
|
import { ProductErrorFragment } from "@dashboard/graphql";
|
||||||
import useNavigator from "@dashboard/hooks/useNavigator";
|
import useNavigator from "@dashboard/hooks/useNavigator";
|
||||||
import { sectionNames } from "@dashboard/intl";
|
|
||||||
import { ConfirmButtonTransitionState } from "@saleor/macaw-ui";
|
import { ConfirmButtonTransitionState } from "@saleor/macaw-ui";
|
||||||
|
import { Box } from "@saleor/macaw-ui/next";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useIntl } from "react-intl";
|
import { useIntl } from "react-intl";
|
||||||
|
|
||||||
|
@ -36,18 +36,17 @@ 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 }) => (
|
||||||
<Container>
|
<DetailedContent>
|
||||||
<Backlink href={backUrl}>
|
<TopNav
|
||||||
{intl.formatMessage(sectionNames.categories)}
|
href={backUrl}
|
||||||
</Backlink>
|
|
||||||
<PageHeader
|
|
||||||
title={intl.formatMessage({
|
title={intl.formatMessage({
|
||||||
id: "cgsY/X",
|
id: "cgsY/X",
|
||||||
defaultMessage: "Create New Category",
|
defaultMessage: "Create New Category",
|
||||||
description: "page header",
|
description: "page header",
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
<div>
|
<Content>
|
||||||
|
<Box height="100vh" __marginBottom="auto">
|
||||||
<CategoryDetailsForm
|
<CategoryDetailsForm
|
||||||
data={data}
|
data={data}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
|
@ -74,14 +73,15 @@ export const CategoryCreatePage: React.FC<CategoryCreatePageProps> = ({
|
||||||
/>
|
/>
|
||||||
<CardSpacer />
|
<CardSpacer />
|
||||||
<Metadata data={data} onChange={handlers.changeMetadata} />
|
<Metadata data={data} onChange={handlers.changeMetadata} />
|
||||||
|
</Box>
|
||||||
|
</Content>
|
||||||
<Savebar
|
<Savebar
|
||||||
onCancel={() => navigate(backUrl)}
|
onCancel={() => navigate(backUrl)}
|
||||||
onSubmit={submit}
|
onSubmit={submit}
|
||||||
state={saveButtonBarState}
|
state={saveButtonBarState}
|
||||||
disabled={isSaveDisabled}
|
disabled={isSaveDisabled}
|
||||||
/>
|
/>
|
||||||
</div>
|
</DetailedContent>
|
||||||
</Container>
|
|
||||||
)}
|
)}
|
||||||
</CategoryCreateForm>
|
</CategoryCreateForm>
|
||||||
);
|
);
|
||||||
|
|
|
@ -41,7 +41,7 @@ const CategoryDeleteDialog: React.FC<CategoryDeleteDialogProps> = props => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog onClose={onClose} open={open}>
|
<Dialog onClose={onClose} open={open}>
|
||||||
<DialogTitle>
|
<DialogTitle disableTypography>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id="xo5UIb"
|
id="xo5UIb"
|
||||||
defaultMessage="Delete category"
|
defaultMessage="Delete category"
|
||||||
|
|
|
@ -2,9 +2,8 @@ import {
|
||||||
categoryAddUrl,
|
categoryAddUrl,
|
||||||
CategoryListUrlSortField,
|
CategoryListUrlSortField,
|
||||||
} from "@dashboard/categories/urls";
|
} from "@dashboard/categories/urls";
|
||||||
|
import { TopNav } from "@dashboard/components/AppLayout/TopNav";
|
||||||
import { Button } from "@dashboard/components/Button";
|
import { Button } from "@dashboard/components/Button";
|
||||||
import Container from "@dashboard/components/Container";
|
|
||||||
import PageHeader from "@dashboard/components/PageHeader";
|
|
||||||
import SearchBar from "@dashboard/components/SearchBar";
|
import SearchBar from "@dashboard/components/SearchBar";
|
||||||
import { CategoryFragment } from "@dashboard/graphql";
|
import { CategoryFragment } from "@dashboard/graphql";
|
||||||
import { sectionNames } from "@dashboard/intl";
|
import { sectionNames } from "@dashboard/intl";
|
||||||
|
@ -53,8 +52,8 @@ export const CategoryListPage: React.FC<CategoryTableProps> = ({
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container>
|
<>
|
||||||
<PageHeader title={intl.formatMessage(sectionNames.categories)}>
|
<TopNav title={intl.formatMessage(sectionNames.categories)}>
|
||||||
<Button
|
<Button
|
||||||
variant="primary"
|
variant="primary"
|
||||||
href={categoryAddUrl()}
|
href={categoryAddUrl()}
|
||||||
|
@ -66,7 +65,7 @@ export const CategoryListPage: React.FC<CategoryTableProps> = ({
|
||||||
description="button"
|
description="button"
|
||||||
/>
|
/>
|
||||||
</Button>
|
</Button>
|
||||||
</PageHeader>
|
</TopNav>
|
||||||
<Card>
|
<Card>
|
||||||
<SearchBar
|
<SearchBar
|
||||||
allTabLabel={intl.formatMessage({
|
allTabLabel={intl.formatMessage({
|
||||||
|
@ -101,7 +100,7 @@ export const CategoryListPage: React.FC<CategoryTableProps> = ({
|
||||||
{...listProps}
|
{...listProps}
|
||||||
/>
|
/>
|
||||||
</Card>
|
</Card>
|
||||||
</Container>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
CategoryListPage.displayName = "CategoryListPage";
|
CategoryListPage.displayName = "CategoryListPage";
|
||||||
|
|
|
@ -3,22 +3,22 @@ import {
|
||||||
categoryListUrl,
|
categoryListUrl,
|
||||||
categoryUrl,
|
categoryUrl,
|
||||||
} from "@dashboard/categories/urls";
|
} from "@dashboard/categories/urls";
|
||||||
import { Backlink } from "@dashboard/components/Backlink";
|
import { Content } from "@dashboard/components/AppLayout/Content";
|
||||||
|
import { DetailedContent } from "@dashboard/components/AppLayout/DetailedContent";
|
||||||
|
import { TopNav } from "@dashboard/components/AppLayout/TopNav";
|
||||||
import { Button } from "@dashboard/components/Button";
|
import { Button } from "@dashboard/components/Button";
|
||||||
import { CardSpacer } from "@dashboard/components/CardSpacer";
|
import { CardSpacer } from "@dashboard/components/CardSpacer";
|
||||||
import CardTitle from "@dashboard/components/CardTitle";
|
import CardTitle from "@dashboard/components/CardTitle";
|
||||||
import Container from "@dashboard/components/Container";
|
|
||||||
import Metadata from "@dashboard/components/Metadata/Metadata";
|
import Metadata from "@dashboard/components/Metadata/Metadata";
|
||||||
import PageHeader from "@dashboard/components/PageHeader";
|
|
||||||
import Savebar from "@dashboard/components/Savebar";
|
import Savebar from "@dashboard/components/Savebar";
|
||||||
import SeoForm from "@dashboard/components/SeoForm";
|
import SeoForm from "@dashboard/components/SeoForm";
|
||||||
import { Tab, TabContainer } from "@dashboard/components/Tab";
|
import { Tab, TabContainer } from "@dashboard/components/Tab";
|
||||||
import { CategoryDetailsQuery, ProductErrorFragment } from "@dashboard/graphql";
|
import { CategoryDetailsQuery, ProductErrorFragment } from "@dashboard/graphql";
|
||||||
import { SubmitPromise } from "@dashboard/hooks/useForm";
|
import { SubmitPromise } from "@dashboard/hooks/useForm";
|
||||||
import useNavigator from "@dashboard/hooks/useNavigator";
|
import useNavigator from "@dashboard/hooks/useNavigator";
|
||||||
import { sectionNames } from "@dashboard/intl";
|
|
||||||
import { Card } from "@material-ui/core";
|
import { Card } from "@material-ui/core";
|
||||||
import { ConfirmButtonTransitionState } from "@saleor/macaw-ui";
|
import { ConfirmButtonTransitionState } from "@saleor/macaw-ui";
|
||||||
|
import { sprinkles } 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";
|
||||||
|
|
||||||
|
@ -91,11 +91,9 @@ export const CategoryUpdatePage: React.FC<CategoryUpdatePageProps> = ({
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
>
|
>
|
||||||
{({ data, change, handlers, submit, isSaveDisabled }) => (
|
{({ data, change, handlers, submit, isSaveDisabled }) => (
|
||||||
<Container>
|
<DetailedContent>
|
||||||
<Backlink href={backHref}>
|
<TopNav href={backHref} title={category?.name} />
|
||||||
{intl.formatMessage(sectionNames.categories)}
|
<Content>
|
||||||
</Backlink>
|
|
||||||
<PageHeader title={category?.name} />
|
|
||||||
<CategoryDetailsForm
|
<CategoryDetailsForm
|
||||||
data={data}
|
data={data}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
|
@ -131,7 +129,7 @@ export const CategoryUpdatePage: React.FC<CategoryUpdatePageProps> = ({
|
||||||
<CardSpacer />
|
<CardSpacer />
|
||||||
<Metadata data={data} onChange={handlers.changeMetadata} />
|
<Metadata data={data} onChange={handlers.changeMetadata} />
|
||||||
<CardSpacer />
|
<CardSpacer />
|
||||||
<TabContainer>
|
<TabContainer className={sprinkles({ paddingX: 9 })}>
|
||||||
<CategoriesTab
|
<CategoriesTab
|
||||||
isActive={currentTab === CategoryPageTab.categories}
|
isActive={currentTab === CategoryPageTab.categories}
|
||||||
changeTab={changeTab}
|
changeTab={changeTab}
|
||||||
|
@ -211,7 +209,8 @@ export const CategoryUpdatePage: React.FC<CategoryUpdatePageProps> = ({
|
||||||
state={saveButtonBarState}
|
state={saveButtonBarState}
|
||||||
disabled={isSaveDisabled}
|
disabled={isSaveDisabled}
|
||||||
/>
|
/>
|
||||||
</Container>
|
</Content>
|
||||||
|
</DetailedContent>
|
||||||
)}
|
)}
|
||||||
</CategoryUpdateForm>
|
</CategoryUpdateForm>
|
||||||
);
|
);
|
||||||
|
|
|
@ -3,9 +3,12 @@ import ShippingZones from "@dashboard/channels/components/ShippingZones";
|
||||||
import Warehouses from "@dashboard/channels/components/Warehouses";
|
import Warehouses from "@dashboard/channels/components/Warehouses";
|
||||||
import { channelsListUrl } from "@dashboard/channels/urls";
|
import { channelsListUrl } from "@dashboard/channels/urls";
|
||||||
import { validateChannelFormData } from "@dashboard/channels/validation";
|
import { validateChannelFormData } from "@dashboard/channels/validation";
|
||||||
|
import { Content } from "@dashboard/components/AppLayout/Content";
|
||||||
|
import { DetailedContent } from "@dashboard/components/AppLayout/DetailedContent";
|
||||||
|
import { RightSidebar } from "@dashboard/components/AppLayout/RightSidebar";
|
||||||
|
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 RequirePermissions from "@dashboard/components/RequirePermissions";
|
import RequirePermissions from "@dashboard/components/RequirePermissions";
|
||||||
import Savebar from "@dashboard/components/Savebar";
|
import Savebar from "@dashboard/components/Savebar";
|
||||||
import { SingleAutocompleteChoiceType } from "@dashboard/components/SingleAutocompleteSelectField";
|
import { SingleAutocompleteChoiceType } from "@dashboard/components/SingleAutocompleteSelectField";
|
||||||
|
@ -30,6 +33,7 @@ import createSingleAutocompleteSelectHandler from "@dashboard/utils/handlers/sin
|
||||||
import { mapCountriesToChoices } from "@dashboard/utils/maps";
|
import { mapCountriesToChoices } from "@dashboard/utils/maps";
|
||||||
import { ConfirmButtonTransitionState } from "@saleor/macaw-ui";
|
import { ConfirmButtonTransitionState } from "@saleor/macaw-ui";
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
|
import { useIntl } from "react-intl";
|
||||||
|
|
||||||
import { ChannelForm, FormData } from "../../components/ChannelForm";
|
import { ChannelForm, FormData } from "../../components/ChannelForm";
|
||||||
import { ChannelStatus } from "../../components/ChannelStatus/ChannelStatus";
|
import { ChannelStatus } from "../../components/ChannelStatus/ChannelStatus";
|
||||||
|
@ -43,7 +47,7 @@ import {
|
||||||
import { ChannelShippingZones, ChannelWarehouses } from "./types";
|
import { ChannelShippingZones, ChannelWarehouses } from "./types";
|
||||||
|
|
||||||
export interface ChannelDetailsPageProps<
|
export interface ChannelDetailsPageProps<
|
||||||
TErrors extends ChannelErrorFragment[]
|
TErrors extends ChannelErrorFragment[],
|
||||||
> {
|
> {
|
||||||
channel?: ChannelDetailsFragment;
|
channel?: ChannelDetailsFragment;
|
||||||
currencyCodes?: SingleAutocompleteChoiceType[];
|
currencyCodes?: SingleAutocompleteChoiceType[];
|
||||||
|
@ -90,16 +94,15 @@ const ChannelDetailsPage = function<TErrors extends ChannelErrorFragment[]>({
|
||||||
countries,
|
countries,
|
||||||
}: ChannelDetailsPageProps<TErrors>) {
|
}: ChannelDetailsPageProps<TErrors>) {
|
||||||
const navigate = useNavigator();
|
const navigate = useNavigator();
|
||||||
|
const intl = useIntl();
|
||||||
|
|
||||||
const [validationErrors, setValidationErrors] = useState<
|
const [validationErrors, setValidationErrors] = useState<
|
||||||
ChannelErrorFragment[]
|
ChannelErrorFragment[]
|
||||||
>([]);
|
>([]);
|
||||||
|
|
||||||
const [selectedCurrencyCode, setSelectedCurrencyCode] = useState("");
|
const [selectedCurrencyCode, setSelectedCurrencyCode] = useState("");
|
||||||
const [
|
const [selectedCountryDisplayName, setSelectedCountryDisplayName] =
|
||||||
selectedCountryDisplayName,
|
useStateFromProps(channel?.defaultCountry.country || "");
|
||||||
setSelectedCountryDisplayName,
|
|
||||||
] = useStateFromProps(channel?.defaultCountry.country || "");
|
|
||||||
|
|
||||||
const countryChoices = mapCountriesToChoices(countries || []);
|
const countryChoices = mapCountriesToChoices(countries || []);
|
||||||
|
|
||||||
|
@ -160,7 +163,8 @@ const ChannelDetailsPage = function<TErrors extends ChannelErrorFragment[]>({
|
||||||
setSelectedCurrencyCode,
|
setSelectedCurrencyCode,
|
||||||
currencyCodes,
|
currencyCodes,
|
||||||
);
|
);
|
||||||
const handleDefaultCountrySelect = createSingleAutocompleteSelectHandler(
|
const handleDefaultCountrySelect =
|
||||||
|
createSingleAutocompleteSelectHandler(
|
||||||
change,
|
change,
|
||||||
setSelectedCountryDisplayName,
|
setSelectedCountryDisplayName,
|
||||||
countryChoices,
|
countryChoices,
|
||||||
|
@ -194,9 +198,19 @@ const ChannelDetailsPage = function<TErrors extends ChannelErrorFragment[]>({
|
||||||
const allErrors = [...errors, ...validationErrors];
|
const allErrors = [...errors, ...validationErrors];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<DetailedContent>
|
||||||
<Grid>
|
<TopNav
|
||||||
<div>
|
href={channelsListUrl()}
|
||||||
|
title={
|
||||||
|
channel?.name ||
|
||||||
|
intl.formatMessage({
|
||||||
|
id: "DnghuS",
|
||||||
|
defaultMessage: "New Channel",
|
||||||
|
description: "channel create",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<Content>
|
||||||
<ChannelForm
|
<ChannelForm
|
||||||
data={data}
|
data={data}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
|
@ -209,8 +223,8 @@ const ChannelDetailsPage = function<TErrors extends ChannelErrorFragment[]>({
|
||||||
onDefaultCountryChange={handleDefaultCountrySelect}
|
onDefaultCountryChange={handleDefaultCountrySelect}
|
||||||
errors={allErrors}
|
errors={allErrors}
|
||||||
/>
|
/>
|
||||||
</div>
|
</Content>
|
||||||
<div>
|
<RightSidebar>
|
||||||
{!!updateChannelStatus && (
|
{!!updateChannelStatus && (
|
||||||
<>
|
<>
|
||||||
<ChannelStatus
|
<ChannelStatus
|
||||||
|
@ -265,8 +279,7 @@ const ChannelDetailsPage = function<TErrors extends ChannelErrorFragment[]>({
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
onChange={change}
|
onChange={change}
|
||||||
/>
|
/>
|
||||||
</div>
|
</RightSidebar>
|
||||||
</Grid>
|
|
||||||
<Savebar
|
<Savebar
|
||||||
onCancel={() => navigate(channelsListUrl())}
|
onCancel={() => navigate(channelsListUrl())}
|
||||||
onSubmit={submit}
|
onSubmit={submit}
|
||||||
|
@ -274,7 +287,7 @@ const ChannelDetailsPage = function<TErrors extends ChannelErrorFragment[]>({
|
||||||
state={saveButtonBarState}
|
state={saveButtonBarState}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
/>
|
/>
|
||||||
</>
|
</DetailedContent>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
</Form>
|
</Form>
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
import { channelAddUrl, channelUrl } from "@dashboard/channels/urls";
|
import { channelAddUrl, channelUrl } from "@dashboard/channels/urls";
|
||||||
import { Backlink } from "@dashboard/components/Backlink";
|
import { LimitsInfo } from "@dashboard/components/AppLayout/LimitsInfo";
|
||||||
|
import { TopNav } from "@dashboard/components/AppLayout/TopNav";
|
||||||
import { Button } from "@dashboard/components/Button";
|
import { Button } from "@dashboard/components/Button";
|
||||||
import Container from "@dashboard/components/Container";
|
|
||||||
import LimitReachedAlert from "@dashboard/components/LimitReachedAlert";
|
import LimitReachedAlert from "@dashboard/components/LimitReachedAlert";
|
||||||
import PageHeader from "@dashboard/components/PageHeader";
|
|
||||||
import ResponsiveTable from "@dashboard/components/ResponsiveTable";
|
import ResponsiveTable from "@dashboard/components/ResponsiveTable";
|
||||||
import Skeleton from "@dashboard/components/Skeleton";
|
import Skeleton from "@dashboard/components/Skeleton";
|
||||||
import { TableButtonWrapper } from "@dashboard/components/TableButtonWrapper/TableButtonWrapper";
|
import { TableButtonWrapper } from "@dashboard/components/TableButtonWrapper/TableButtonWrapper";
|
||||||
|
@ -40,26 +39,10 @@ export const ChannelsListPage: React.FC<ChannelsListPageProps> = ({
|
||||||
const limitReached = isLimitReached(limits, "channels");
|
const limitReached = isLimitReached(limits, "channels");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container>
|
<>
|
||||||
<Backlink href={configurationMenuUrl}>
|
<TopNav
|
||||||
{intl.formatMessage(sectionNames.configuration)}
|
href={configurationMenuUrl}
|
||||||
</Backlink>
|
|
||||||
<PageHeader
|
|
||||||
title={intl.formatMessage(sectionNames.channels)}
|
title={intl.formatMessage(sectionNames.channels)}
|
||||||
limitText={
|
|
||||||
hasLimits(limits, "channels") &&
|
|
||||||
intl.formatMessage(
|
|
||||||
{
|
|
||||||
id: "rZMT44",
|
|
||||||
defaultMessage: "{count}/{max} channels used",
|
|
||||||
description: "created channels counter",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
count: limits.currentUsage.channels,
|
|
||||||
max: limits.allowedUsage.channels,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
disabled={limitReached}
|
disabled={limitReached}
|
||||||
|
@ -73,7 +56,22 @@ export const ChannelsListPage: React.FC<ChannelsListPageProps> = ({
|
||||||
description="button"
|
description="button"
|
||||||
/>
|
/>
|
||||||
</Button>
|
</Button>
|
||||||
</PageHeader>
|
{hasLimits(limits, "channels") && (
|
||||||
|
<LimitsInfo
|
||||||
|
text={intl.formatMessage(
|
||||||
|
{
|
||||||
|
id: "rZMT44",
|
||||||
|
defaultMessage: "{count}/{max} channels used",
|
||||||
|
description: "created channels counter",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
count: limits.currentUsage.channels,
|
||||||
|
max: limits.allowedUsage.channels,
|
||||||
|
},
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</TopNav>
|
||||||
{limitReached && (
|
{limitReached && (
|
||||||
<LimitReachedAlert
|
<LimitReachedAlert
|
||||||
title={intl.formatMessage({
|
title={intl.formatMessage({
|
||||||
|
@ -156,7 +154,7 @@ export const ChannelsListPage: React.FC<ChannelsListPageProps> = ({
|
||||||
</TableBody>
|
</TableBody>
|
||||||
</ResponsiveTable>
|
</ResponsiveTable>
|
||||||
</Card>
|
</Card>
|
||||||
</Container>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,4 @@
|
||||||
import { FormData } from "@dashboard/channels/components/ChannelForm/ChannelForm";
|
import { FormData } from "@dashboard/channels/components/ChannelForm/ChannelForm";
|
||||||
import { Backlink } from "@dashboard/components/Backlink";
|
|
||||||
import Container from "@dashboard/components/Container";
|
|
||||||
import PageHeader from "@dashboard/components/PageHeader";
|
|
||||||
import { WindowTitle } from "@dashboard/components/WindowTitle";
|
import { WindowTitle } from "@dashboard/components/WindowTitle";
|
||||||
import {
|
import {
|
||||||
ChannelCreateMutation,
|
ChannelCreateMutation,
|
||||||
|
@ -14,7 +11,6 @@ import useNavigator from "@dashboard/hooks/useNavigator";
|
||||||
import useNotifier from "@dashboard/hooks/useNotifier";
|
import useNotifier from "@dashboard/hooks/useNotifier";
|
||||||
import { getDefaultNotifierSuccessErrorData } from "@dashboard/hooks/useNotifier/utils";
|
import { getDefaultNotifierSuccessErrorData } from "@dashboard/hooks/useNotifier/utils";
|
||||||
import useShop from "@dashboard/hooks/useShop";
|
import useShop from "@dashboard/hooks/useShop";
|
||||||
import { sectionNames } from "@dashboard/intl";
|
|
||||||
import { extractMutationErrors } from "@dashboard/misc";
|
import { extractMutationErrors } from "@dashboard/misc";
|
||||||
import getChannelsErrorMessage from "@dashboard/utils/errors/channels";
|
import getChannelsErrorMessage from "@dashboard/utils/errors/channels";
|
||||||
import currencyCodes from "currency-codes";
|
import currencyCodes from "currency-codes";
|
||||||
|
@ -22,7 +18,7 @@ import React from "react";
|
||||||
import { useIntl } from "react-intl";
|
import { useIntl } from "react-intl";
|
||||||
|
|
||||||
import ChannelDetailsPage from "../../pages/ChannelDetailsPage";
|
import ChannelDetailsPage from "../../pages/ChannelDetailsPage";
|
||||||
import { channelPath, channelsListUrl } from "../../urls";
|
import { channelPath } from "../../urls";
|
||||||
import { calculateItemsOrderMoves } from "../ChannelDetails/handlers";
|
import { calculateItemsOrderMoves } from "../ChannelDetails/handlers";
|
||||||
import { useShippingZones } from "../ChannelDetails/useShippingZones";
|
import { useShippingZones } from "../ChannelDetails/useShippingZones";
|
||||||
import { useWarehouses } from "../ChannelDetails/useWarehouses";
|
import { useWarehouses } from "../ChannelDetails/useWarehouses";
|
||||||
|
@ -146,17 +142,7 @@ export const ChannelCreateView = ({}) => {
|
||||||
description: "window title",
|
description: "window title",
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
<Container>
|
<>
|
||||||
<Backlink href={channelsListUrl()}>
|
|
||||||
{intl.formatMessage(sectionNames.channels)}
|
|
||||||
</Backlink>
|
|
||||||
<PageHeader
|
|
||||||
title={intl.formatMessage({
|
|
||||||
id: "DnghuS",
|
|
||||||
defaultMessage: "New Channel",
|
|
||||||
description: "channel create",
|
|
||||||
})}
|
|
||||||
/>
|
|
||||||
<ChannelDetailsPage
|
<ChannelDetailsPage
|
||||||
allShippingZonesCount={
|
allShippingZonesCount={
|
||||||
shippingZonesCountData?.shippingZones?.totalCount
|
shippingZonesCountData?.shippingZones?.totalCount
|
||||||
|
@ -186,7 +172,7 @@ export const ChannelCreateView = ({}) => {
|
||||||
saveButtonBarState={createChannelOpts.status}
|
saveButtonBarState={createChannelOpts.status}
|
||||||
countries={shop?.countries || []}
|
countries={shop?.countries || []}
|
||||||
/>
|
/>
|
||||||
</Container>
|
</>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
import ChannelDeleteDialog from "@dashboard/channels/components/ChannelDeleteDialog";
|
import ChannelDeleteDialog from "@dashboard/channels/components/ChannelDeleteDialog";
|
||||||
import { FormData } from "@dashboard/channels/components/ChannelForm/ChannelForm";
|
import { FormData } from "@dashboard/channels/components/ChannelForm/ChannelForm";
|
||||||
import { getChannelsCurrencyChoices } from "@dashboard/channels/utils";
|
import { getChannelsCurrencyChoices } from "@dashboard/channels/utils";
|
||||||
import { Backlink } from "@dashboard/components/Backlink";
|
|
||||||
import Container from "@dashboard/components/Container";
|
|
||||||
import PageHeader from "@dashboard/components/PageHeader";
|
|
||||||
import { WindowTitle } from "@dashboard/components/WindowTitle";
|
import { WindowTitle } from "@dashboard/components/WindowTitle";
|
||||||
import {
|
import {
|
||||||
ChannelDeleteMutation,
|
ChannelDeleteMutation,
|
||||||
|
@ -22,7 +19,6 @@ import useNavigator from "@dashboard/hooks/useNavigator";
|
||||||
import useNotifier from "@dashboard/hooks/useNotifier";
|
import useNotifier from "@dashboard/hooks/useNotifier";
|
||||||
import { getDefaultNotifierSuccessErrorData } from "@dashboard/hooks/useNotifier/utils";
|
import { getDefaultNotifierSuccessErrorData } from "@dashboard/hooks/useNotifier/utils";
|
||||||
import useShop from "@dashboard/hooks/useShop";
|
import useShop from "@dashboard/hooks/useShop";
|
||||||
import { sectionNames } from "@dashboard/intl";
|
|
||||||
import { extractMutationErrors } from "@dashboard/misc";
|
import { extractMutationErrors } from "@dashboard/misc";
|
||||||
import getChannelsErrorMessage from "@dashboard/utils/errors/channels";
|
import getChannelsErrorMessage from "@dashboard/utils/errors/channels";
|
||||||
import createDialogActionHandlers from "@dashboard/utils/handlers/dialogActionHandlers";
|
import createDialogActionHandlers from "@dashboard/utils/handlers/dialogActionHandlers";
|
||||||
|
@ -230,11 +226,6 @@ export const ChannelDetails: React.FC<ChannelDetailsProps> = ({
|
||||||
description: "window title",
|
description: "window title",
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
<Container>
|
|
||||||
<Backlink href={channelsListUrl()}>
|
|
||||||
{intl.formatMessage(sectionNames.channels)}
|
|
||||||
</Backlink>
|
|
||||||
<PageHeader title={data?.channel?.name} />
|
|
||||||
<ChannelDetailsPage
|
<ChannelDetailsPage
|
||||||
channelShippingZones={channelShippingZones}
|
channelShippingZones={channelShippingZones}
|
||||||
allShippingZonesCount={
|
allShippingZonesCount={
|
||||||
|
@ -277,7 +268,6 @@ export const ChannelDetails: React.FC<ChannelDetailsProps> = ({
|
||||||
saveButtonBarState={updateChannelOpts.status}
|
saveButtonBarState={updateChannelOpts.status}
|
||||||
countries={shop?.countries || []}
|
countries={shop?.countries || []}
|
||||||
/>
|
/>
|
||||||
</Container>
|
|
||||||
<ChannelDeleteDialog
|
<ChannelDeleteDialog
|
||||||
channelsChoices={channelsChoices}
|
channelsChoices={channelsChoices}
|
||||||
hasOrders={data?.channel?.hasOrders}
|
hasOrders={data?.channel?.hasOrders}
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import { ChannelCollectionData } from "@dashboard/channels/utils";
|
import { ChannelCollectionData } from "@dashboard/channels/utils";
|
||||||
import { collectionListUrl } from "@dashboard/collections/urls";
|
import { collectionListUrl } from "@dashboard/collections/urls";
|
||||||
import { Backlink } from "@dashboard/components/Backlink";
|
import { Content } from "@dashboard/components/AppLayout/Content";
|
||||||
|
import { DetailedContent } from "@dashboard/components/AppLayout/DetailedContent";
|
||||||
|
import { RightSidebar } from "@dashboard/components/AppLayout/RightSidebar";
|
||||||
|
import { TopNav } from "@dashboard/components/AppLayout/TopNav";
|
||||||
import { CardSpacer } from "@dashboard/components/CardSpacer";
|
import { CardSpacer } from "@dashboard/components/CardSpacer";
|
||||||
import ChannelsAvailabilityCard from "@dashboard/components/ChannelsAvailabilityCard";
|
import ChannelsAvailabilityCard from "@dashboard/components/ChannelsAvailabilityCard";
|
||||||
import { Container } from "@dashboard/components/Container";
|
|
||||||
import Grid from "@dashboard/components/Grid";
|
|
||||||
import Metadata from "@dashboard/components/Metadata";
|
import Metadata from "@dashboard/components/Metadata";
|
||||||
import PageHeader from "@dashboard/components/PageHeader";
|
|
||||||
import Savebar from "@dashboard/components/Savebar";
|
import Savebar from "@dashboard/components/Savebar";
|
||||||
import SeoForm from "@dashboard/components/SeoForm";
|
import SeoForm from "@dashboard/components/SeoForm";
|
||||||
import {
|
import {
|
||||||
|
@ -16,7 +16,6 @@ import {
|
||||||
} from "@dashboard/graphql";
|
} from "@dashboard/graphql";
|
||||||
import { SubmitPromise } from "@dashboard/hooks/useForm";
|
import { SubmitPromise } from "@dashboard/hooks/useForm";
|
||||||
import useNavigator from "@dashboard/hooks/useNavigator";
|
import useNavigator from "@dashboard/hooks/useNavigator";
|
||||||
import { sectionNames } from "@dashboard/intl";
|
|
||||||
import { ConfirmButtonTransitionState } from "@saleor/macaw-ui";
|
import { ConfirmButtonTransitionState } from "@saleor/macaw-ui";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useIntl } from "react-intl";
|
import { useIntl } from "react-intl";
|
||||||
|
@ -59,19 +58,16 @@ const CollectionCreatePage: React.FC<CollectionCreatePageProps> = ({
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
>
|
>
|
||||||
{({ change, data, handlers, submit, isSaveDisabled }) => (
|
{({ change, data, handlers, submit, isSaveDisabled }) => (
|
||||||
<Container>
|
<DetailedContent>
|
||||||
<Backlink href={collectionListUrl()}>
|
<TopNav
|
||||||
{intl.formatMessage(sectionNames.collections)}
|
href={collectionListUrl()}
|
||||||
</Backlink>
|
|
||||||
<PageHeader
|
|
||||||
title={intl.formatMessage({
|
title={intl.formatMessage({
|
||||||
id: "Fxa6xp",
|
id: "Fxa6xp",
|
||||||
defaultMessage: "Add Collection",
|
defaultMessage: "Add Collection",
|
||||||
description: "page header",
|
description: "page header",
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
<Grid>
|
<Content>
|
||||||
<div>
|
|
||||||
<CollectionDetails
|
<CollectionDetails
|
||||||
data={data}
|
data={data}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
|
@ -133,8 +129,8 @@ const CollectionCreatePage: React.FC<CollectionCreatePageProps> = ({
|
||||||
/>
|
/>
|
||||||
<CardSpacer />
|
<CardSpacer />
|
||||||
<Metadata data={data} onChange={handlers.changeMetadata} />
|
<Metadata data={data} onChange={handlers.changeMetadata} />
|
||||||
</div>
|
</Content>
|
||||||
<div>
|
<RightSidebar>
|
||||||
<ChannelsAvailabilityCard
|
<ChannelsAvailabilityCard
|
||||||
messages={{
|
messages={{
|
||||||
hiddenLabel: intl.formatMessage({
|
hiddenLabel: intl.formatMessage({
|
||||||
|
@ -157,15 +153,14 @@ const CollectionCreatePage: React.FC<CollectionCreatePageProps> = ({
|
||||||
onChange={handlers.changeChannels}
|
onChange={handlers.changeChannels}
|
||||||
openModal={openChannelsModal}
|
openModal={openChannelsModal}
|
||||||
/>
|
/>
|
||||||
</div>
|
</RightSidebar>
|
||||||
</Grid>
|
|
||||||
<Savebar
|
<Savebar
|
||||||
state={saveButtonBarState}
|
state={saveButtonBarState}
|
||||||
disabled={isSaveDisabled}
|
disabled={isSaveDisabled}
|
||||||
onCancel={() => navigate(collectionListUrl())}
|
onCancel={() => navigate(collectionListUrl())}
|
||||||
onSubmit={submit}
|
onSubmit={submit}
|
||||||
/>
|
/>
|
||||||
</Container>
|
</DetailedContent>
|
||||||
)}
|
)}
|
||||||
</CollectionCreateForm>
|
</CollectionCreateForm>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import { ChannelCollectionData } from "@dashboard/channels/utils";
|
import { ChannelCollectionData } from "@dashboard/channels/utils";
|
||||||
import { collectionListUrl } from "@dashboard/collections/urls";
|
import { collectionListUrl } from "@dashboard/collections/urls";
|
||||||
import { Backlink } from "@dashboard/components/Backlink";
|
import { Content } from "@dashboard/components/AppLayout/Content";
|
||||||
|
import { DetailedContent } from "@dashboard/components/AppLayout/DetailedContent";
|
||||||
|
import { RightSidebar } from "@dashboard/components/AppLayout/RightSidebar";
|
||||||
|
import { TopNav } from "@dashboard/components/AppLayout/TopNav";
|
||||||
import { CardSpacer } from "@dashboard/components/CardSpacer";
|
import { CardSpacer } from "@dashboard/components/CardSpacer";
|
||||||
import ChannelsAvailabilityCard from "@dashboard/components/ChannelsAvailabilityCard";
|
import ChannelsAvailabilityCard from "@dashboard/components/ChannelsAvailabilityCard";
|
||||||
import { Container } from "@dashboard/components/Container";
|
|
||||||
import Grid from "@dashboard/components/Grid";
|
|
||||||
import Metadata from "@dashboard/components/Metadata/Metadata";
|
import Metadata from "@dashboard/components/Metadata/Metadata";
|
||||||
import PageHeader from "@dashboard/components/PageHeader";
|
|
||||||
import Savebar from "@dashboard/components/Savebar";
|
import Savebar from "@dashboard/components/Savebar";
|
||||||
import SeoForm from "@dashboard/components/SeoForm";
|
import SeoForm from "@dashboard/components/SeoForm";
|
||||||
import {
|
import {
|
||||||
|
@ -17,7 +17,6 @@ import {
|
||||||
} from "@dashboard/graphql";
|
} from "@dashboard/graphql";
|
||||||
import { SubmitPromise } from "@dashboard/hooks/useForm";
|
import { SubmitPromise } from "@dashboard/hooks/useForm";
|
||||||
import useNavigator from "@dashboard/hooks/useNavigator";
|
import useNavigator from "@dashboard/hooks/useNavigator";
|
||||||
import { sectionNames } from "@dashboard/intl";
|
|
||||||
import { ConfirmButtonTransitionState } from "@saleor/macaw-ui";
|
import { ConfirmButtonTransitionState } from "@saleor/macaw-ui";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useIntl } from "react-intl";
|
import { useIntl } from "react-intl";
|
||||||
|
@ -76,13 +75,9 @@ const CollectionDetailsPage: React.FC<CollectionDetailsPageProps> = ({
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
>
|
>
|
||||||
{({ change, data, handlers, submit, isSaveDisabled }) => (
|
{({ change, data, handlers, submit, isSaveDisabled }) => (
|
||||||
<Container>
|
<DetailedContent>
|
||||||
<Backlink href={collectionListUrl()}>
|
<TopNav href={collectionListUrl()} title={collection?.name} />
|
||||||
{intl.formatMessage(sectionNames.collections)}
|
<Content>
|
||||||
</Backlink>
|
|
||||||
<PageHeader title={collection?.name} />
|
|
||||||
<Grid>
|
|
||||||
<div>
|
|
||||||
<CollectionDetails
|
<CollectionDetails
|
||||||
data={data}
|
data={data}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
|
@ -122,8 +117,8 @@ const CollectionDetailsPage: React.FC<CollectionDetailsPageProps> = ({
|
||||||
titlePlaceholder={collection?.name}
|
titlePlaceholder={collection?.name}
|
||||||
onChange={change}
|
onChange={change}
|
||||||
/>
|
/>
|
||||||
</div>
|
</Content>
|
||||||
<div>
|
<RightSidebar>
|
||||||
<div>
|
<div>
|
||||||
<ChannelsAvailabilityCard
|
<ChannelsAvailabilityCard
|
||||||
managePermissions={[PermissionEnum.MANAGE_PRODUCTS]}
|
managePermissions={[PermissionEnum.MANAGE_PRODUCTS]}
|
||||||
|
@ -148,8 +143,7 @@ const CollectionDetailsPage: React.FC<CollectionDetailsPageProps> = ({
|
||||||
openModal={openChannelsModal}
|
openModal={openChannelsModal}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</RightSidebar>
|
||||||
</Grid>
|
|
||||||
<Savebar
|
<Savebar
|
||||||
state={saveButtonBarState}
|
state={saveButtonBarState}
|
||||||
disabled={isSaveDisabled}
|
disabled={isSaveDisabled}
|
||||||
|
@ -157,7 +151,7 @@ const CollectionDetailsPage: React.FC<CollectionDetailsPageProps> = ({
|
||||||
onDelete={onCollectionRemove}
|
onDelete={onCollectionRemove}
|
||||||
onSubmit={submit}
|
onSubmit={submit}
|
||||||
/>
|
/>
|
||||||
</Container>
|
</DetailedContent>
|
||||||
)}
|
)}
|
||||||
</CollectionUpdateForm>
|
</CollectionUpdateForm>
|
||||||
);
|
);
|
||||||
|
|
|
@ -8,6 +8,7 @@ import { CollectionDetailsFragment } from "@dashboard/graphql";
|
||||||
import { commonMessages } from "@dashboard/intl";
|
import { commonMessages } from "@dashboard/intl";
|
||||||
import { Card, CardContent, TextField } from "@material-ui/core";
|
import { Card, CardContent, TextField } from "@material-ui/core";
|
||||||
import { makeStyles } from "@saleor/macaw-ui";
|
import { makeStyles } from "@saleor/macaw-ui";
|
||||||
|
import { vars } 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";
|
||||||
|
|
||||||
|
@ -33,7 +34,7 @@ const useStyles = makeStyles(
|
||||||
},
|
},
|
||||||
imageContainer: {
|
imageContainer: {
|
||||||
background: "#ffffff",
|
background: "#ffffff",
|
||||||
border: "1px solid #eaeaea",
|
border: `1px solid ${vars.colors.border.neutralPlain}`,
|
||||||
borderRadius: theme.spacing(),
|
borderRadius: theme.spacing(),
|
||||||
height: 148,
|
height: 148,
|
||||||
justifySelf: "start",
|
justifySelf: "start",
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
import { collectionAddUrl } from "@dashboard/collections/urls";
|
import { collectionAddUrl } from "@dashboard/collections/urls";
|
||||||
|
import { TopNav } from "@dashboard/components/AppLayout/TopNav";
|
||||||
import { Button } from "@dashboard/components/Button";
|
import { Button } from "@dashboard/components/Button";
|
||||||
import { Container } from "@dashboard/components/Container";
|
|
||||||
import { getByName } from "@dashboard/components/Filter/utils";
|
import { getByName } from "@dashboard/components/Filter/utils";
|
||||||
import FilterBar from "@dashboard/components/FilterBar";
|
import FilterBar from "@dashboard/components/FilterBar";
|
||||||
import PageHeader from "@dashboard/components/PageHeader";
|
|
||||||
import { sectionNames } from "@dashboard/intl";
|
import { sectionNames } from "@dashboard/intl";
|
||||||
import {
|
import {
|
||||||
FilterPageProps,
|
FilterPageProps,
|
||||||
|
@ -52,8 +51,8 @@ const CollectionListPage: React.FC<CollectionListPageProps> = ({
|
||||||
const filterDependency = filterStructure.find(getByName("channel"));
|
const filterDependency = filterStructure.find(getByName("channel"));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container>
|
<>
|
||||||
<PageHeader title={intl.formatMessage(sectionNames.collections)}>
|
<TopNav title={intl.formatMessage(sectionNames.collections)}>
|
||||||
<Button
|
<Button
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
variant="primary"
|
variant="primary"
|
||||||
|
@ -66,7 +65,7 @@ const CollectionListPage: React.FC<CollectionListPageProps> = ({
|
||||||
description="button"
|
description="button"
|
||||||
/>
|
/>
|
||||||
</Button>
|
</Button>
|
||||||
</PageHeader>
|
</TopNav>
|
||||||
<Card>
|
<Card>
|
||||||
<FilterBar
|
<FilterBar
|
||||||
allTabLabel={intl.formatMessage({
|
allTabLabel={intl.formatMessage({
|
||||||
|
@ -97,7 +96,7 @@ const CollectionListPage: React.FC<CollectionListPageProps> = ({
|
||||||
{...listProps}
|
{...listProps}
|
||||||
/>
|
/>
|
||||||
</Card>
|
</Card>
|
||||||
</Container>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
CollectionListPage.displayName = "CollectionListPage";
|
CollectionListPage.displayName = "CollectionListPage";
|
||||||
|
|
|
@ -98,7 +98,7 @@ const AccountPermissions: React.FC<AccountPermissionsProps> = props => {
|
||||||
/>
|
/>
|
||||||
{permissionsExceeded && (
|
{permissionsExceeded && (
|
||||||
<>
|
<>
|
||||||
<CardContent>
|
<CardContent style={{ paddingLeft: 0 }}>
|
||||||
<Typography variant="body2">
|
<Typography variant="body2">
|
||||||
{intl.formatMessage({
|
{intl.formatMessage({
|
||||||
id: "MVU6ol",
|
id: "MVU6ol",
|
||||||
|
|
|
@ -22,7 +22,7 @@ const ActionDialog: React.FC<ActionDialogProps> = props => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog fullWidth onClose={onClose} open={open} maxWidth={maxWidth}>
|
<Dialog fullWidth onClose={onClose} open={open} maxWidth={maxWidth}>
|
||||||
<DialogTitle>{title}</DialogTitle>
|
<DialogTitle disableTypography>{title}</DialogTitle>
|
||||||
<DialogContent>{children}</DialogContent>
|
<DialogContent>{children}</DialogContent>
|
||||||
<DialogButtons {...rest} onClose={onClose} variant={variant} />
|
<DialogButtons {...rest} onClose={onClose} variant={variant} />
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
|
|
@ -2,23 +2,24 @@ import { ChannelFragment } from "@dashboard/graphql";
|
||||||
import { ChannelProps } from "@dashboard/types";
|
import { ChannelProps } from "@dashboard/types";
|
||||||
import { mapNodeToChoice } from "@dashboard/utils/maps";
|
import { mapNodeToChoice } from "@dashboard/utils/maps";
|
||||||
import { makeStyles } from "@saleor/macaw-ui";
|
import { makeStyles } from "@saleor/macaw-ui";
|
||||||
|
import { vars } from "@saleor/macaw-ui/next";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import SingleSelectField from "../SingleSelectField";
|
import SingleSelectField from "../SingleSelectField";
|
||||||
|
|
||||||
const useStyles = makeStyles(
|
const useStyles = makeStyles(
|
||||||
theme => ({
|
{
|
||||||
input: {
|
input: {
|
||||||
height: 40,
|
height: 40,
|
||||||
},
|
},
|
||||||
root: {
|
root: {
|
||||||
"&& fieldset": {
|
"&& fieldset": {
|
||||||
borderColor: theme.palette.divider,
|
borderColor: vars.colors.border.neutralPlain,
|
||||||
},
|
},
|
||||||
marginRight: theme.spacing(2),
|
|
||||||
width: 192,
|
width: 192,
|
||||||
|
padding: 10,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}),
|
|
||||||
{
|
{
|
||||||
name: "AppChannelSelect",
|
name: "AppChannelSelect",
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,66 +1,24 @@
|
||||||
import { useUser } from "@dashboard/auth";
|
|
||||||
import useAppState from "@dashboard/hooks/useAppState";
|
import useAppState from "@dashboard/hooks/useAppState";
|
||||||
import { isDarkTheme } from "@dashboard/misc";
|
import { LinearProgress } from "@material-ui/core";
|
||||||
import { LinearProgress, useMediaQuery } from "@material-ui/core";
|
import { useActionBar } from "@saleor/macaw-ui";
|
||||||
import {
|
import { Box } from "@saleor/macaw-ui/next";
|
||||||
SaleorTheme,
|
|
||||||
Sidebar,
|
|
||||||
SidebarDrawer,
|
|
||||||
useActionBar,
|
|
||||||
useBacklink,
|
|
||||||
useTheme,
|
|
||||||
} from "@saleor/macaw-ui";
|
|
||||||
import clsx from "clsx";
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useIntl } from "react-intl";
|
|
||||||
import useRouter from "use-react-router";
|
|
||||||
|
|
||||||
import Container from "../Container";
|
|
||||||
import Navigator from "../Navigator";
|
import Navigator from "../Navigator";
|
||||||
import NavigatorButton from "../NavigatorButton/NavigatorButton";
|
import { Sidebar } from "../Sidebar";
|
||||||
import UserChip from "../UserChip";
|
import { contentMaxWidth } from "./consts";
|
||||||
import useAppChannel from "./AppChannelContext";
|
import { useStyles } from "./styles";
|
||||||
import AppChannelSelect from "./AppChannelSelect";
|
|
||||||
import useMenuStructure from "./menuStructure";
|
|
||||||
import { SidebarLink } from "./SidebarLink";
|
|
||||||
import { useFullSizeStyles, useStyles } from "./styles";
|
|
||||||
import { isMenuActive } from "./utils";
|
|
||||||
|
|
||||||
interface AppLayoutProps {
|
interface AppLayoutProps {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
fullSize?: boolean;
|
fullSize?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const AppLayout: React.FC<AppLayoutProps> = ({
|
const AppLayout: React.FC<AppLayoutProps> = ({ children }) => {
|
||||||
children,
|
|
||||||
fullSize = false,
|
|
||||||
}) => {
|
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
const fullSizeClasses = useFullSizeStyles();
|
|
||||||
const { themeType, setTheme } = useTheme();
|
|
||||||
const { anchor: appActionAnchor } = useActionBar();
|
const { anchor: appActionAnchor } = useActionBar();
|
||||||
const appHeaderAnchor = useBacklink();
|
|
||||||
const { logout, user } = useUser();
|
|
||||||
const intl = useIntl();
|
|
||||||
const [appState] = useAppState();
|
const [appState] = useAppState();
|
||||||
const { location } = useRouter();
|
|
||||||
const [isNavigatorVisible, setNavigatorVisibility] = React.useState(false);
|
const [isNavigatorVisible, setNavigatorVisibility] = React.useState(false);
|
||||||
const isMdUp = useMediaQuery((theme: SaleorTheme) =>
|
|
||||||
theme.breakpoints.up("md"),
|
|
||||||
);
|
|
||||||
|
|
||||||
const {
|
|
||||||
availableChannels,
|
|
||||||
channel,
|
|
||||||
isPickerActive,
|
|
||||||
setChannel,
|
|
||||||
} = useAppChannel(false);
|
|
||||||
const [menuStructure, handleMenuItemClick] = useMenuStructure(intl, user);
|
|
||||||
const activeMenu = menuStructure.find(menuItem =>
|
|
||||||
isMenuActive(location.pathname, menuItem),
|
|
||||||
)?.id;
|
|
||||||
|
|
||||||
const toggleTheme = () => setTheme(isDarkTheme(themeType) ? "light" : "dark");
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -68,80 +26,45 @@ const AppLayout: React.FC<AppLayoutProps> = ({
|
||||||
visible={isNavigatorVisible}
|
visible={isNavigatorVisible}
|
||||||
setVisibility={setNavigatorVisibility}
|
setVisibility={setNavigatorVisibility}
|
||||||
/>
|
/>
|
||||||
<div className={classes.root}>
|
<Box display="grid" __gridTemplateColumns="auto 1fr">
|
||||||
{isMdUp && (
|
{appState.loading && (
|
||||||
<Sidebar
|
|
||||||
activeId={activeMenu}
|
|
||||||
menuItems={menuStructure}
|
|
||||||
onMenuItemClick={handleMenuItemClick}
|
|
||||||
logoHref="/"
|
|
||||||
linkComponent={SidebarLink}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<div
|
|
||||||
className={clsx(classes.content, {
|
|
||||||
[fullSizeClasses.content]: fullSize,
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
{appState.loading ? (
|
|
||||||
<LinearProgress className={classes.appLoader} color="primary" />
|
<LinearProgress className={classes.appLoader} color="primary" />
|
||||||
) : (
|
|
||||||
<div className={classes.appLoaderPlaceholder} />
|
|
||||||
)}
|
)}
|
||||||
<div
|
<Box
|
||||||
className={clsx(classes.viewContainer, {
|
height="100vh"
|
||||||
[fullSizeClasses.viewContainer]: fullSize,
|
borderColor="neutralPlain"
|
||||||
})}
|
borderRightWidth={1}
|
||||||
>
|
backgroundColor="subdued"
|
||||||
<div>
|
borderStyle="solid"
|
||||||
<Container>
|
position="sticky"
|
||||||
<div className={classes.header}>
|
top={0}
|
||||||
<div className={classes.headerAnchor} ref={appHeaderAnchor} />
|
borderLeftWidth={0}
|
||||||
<div className={classes.headerToolbar}>
|
borderTopWidth={0}
|
||||||
{!isMdUp && (
|
borderBottomWidth={0}
|
||||||
<SidebarDrawer
|
|
||||||
menuItems={menuStructure}
|
|
||||||
logoHref="/"
|
|
||||||
onMenuItemClick={handleMenuItemClick}
|
|
||||||
linkComponent={SidebarLink}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<div className={classes.spacer} />
|
|
||||||
<div className={classes.userBar}>
|
|
||||||
<NavigatorButton
|
|
||||||
isMac={navigator.platform.toLowerCase().includes("mac")}
|
|
||||||
onClick={() => setNavigatorVisibility(true)}
|
|
||||||
/>
|
|
||||||
{isPickerActive && (
|
|
||||||
<AppChannelSelect
|
|
||||||
channels={availableChannels}
|
|
||||||
selectedChannelId={channel?.id}
|
|
||||||
onChannelSelect={setChannel}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<UserChip
|
|
||||||
isDarkThemeEnabled={isDarkTheme(themeType)}
|
|
||||||
user={user}
|
|
||||||
onLogout={logout}
|
|
||||||
onThemeToggle={toggleTheme}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Container>
|
|
||||||
</div>
|
|
||||||
<main
|
|
||||||
className={clsx(classes.view, {
|
|
||||||
[classes.viewMargins]: !fullSize,
|
|
||||||
[fullSizeClasses.view]: fullSize,
|
|
||||||
})}
|
|
||||||
>
|
>
|
||||||
|
<Sidebar />
|
||||||
|
</Box>
|
||||||
|
<Box height="100%" width="100%">
|
||||||
|
<Box as="main" width="100%">
|
||||||
{children}
|
{children}
|
||||||
</main>
|
</Box>
|
||||||
</div>
|
<Box
|
||||||
<div className={classes.appAction} ref={appActionAnchor} />
|
ref={appActionAnchor}
|
||||||
</div>
|
position="sticky"
|
||||||
</div>
|
bottom={0}
|
||||||
|
left={0}
|
||||||
|
right={0}
|
||||||
|
backgroundColor="plain"
|
||||||
|
borderTopWidth={1}
|
||||||
|
borderTopStyle="solid"
|
||||||
|
borderColor="neutralPlain"
|
||||||
|
__maxWidth={contentMaxWidth}
|
||||||
|
margin="auto"
|
||||||
|
// @ts-ignore
|
||||||
|
__zIndex="3"
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
21
src/components/AppLayout/Content.tsx
Normal file
21
src/components/AppLayout/Content.tsx
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
import { Box } from "@saleor/macaw-ui/next";
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
import { borderHeight, savebarHeight, topBarHeight } from "./consts";
|
||||||
|
|
||||||
|
interface ContentProps {
|
||||||
|
[key: `data-${string}`]: string;
|
||||||
|
children: React.ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Content: React.FC<ContentProps> = ({ children, ...rest }) => (
|
||||||
|
<Box
|
||||||
|
__gridArea="content"
|
||||||
|
__height={`calc(100vh - ${topBarHeight} - ${savebarHeight} - ${borderHeight})`}
|
||||||
|
overflowY="auto"
|
||||||
|
className="hide-scrollbar"
|
||||||
|
{...rest}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</Box>
|
||||||
|
);
|
42
src/components/AppLayout/DetailedContent.tsx
Normal file
42
src/components/AppLayout/DetailedContent.tsx
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
import { Box, tabletMediaQuery } from "@saleor/macaw-ui/next";
|
||||||
|
import React from "react";
|
||||||
|
import { useMediaQuery } from "usehooks-ts";
|
||||||
|
|
||||||
|
import { contentMaxWidth } from "./consts";
|
||||||
|
|
||||||
|
interface DetailedContentProps {
|
||||||
|
children: React.ReactNode;
|
||||||
|
useSingleColumn?: boolean;
|
||||||
|
constHeight?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const getLayoutAreas = (useSingleColumn: boolean, isTablet: boolean) => {
|
||||||
|
if (useSingleColumn) {
|
||||||
|
return '"nav" "content"';
|
||||||
|
}
|
||||||
|
|
||||||
|
return isTablet ? '"nav right" "content right"' : '"nav" "content" "right"';
|
||||||
|
};
|
||||||
|
|
||||||
|
export const DetailedContent: React.FC<DetailedContentProps> = ({
|
||||||
|
children,
|
||||||
|
useSingleColumn = false,
|
||||||
|
constHeight = false,
|
||||||
|
}) => {
|
||||||
|
const isTablet = useMediaQuery(tabletMediaQuery);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box
|
||||||
|
as="div"
|
||||||
|
display="grid"
|
||||||
|
height={constHeight ? "100vh" : "100%"}
|
||||||
|
margin="auto"
|
||||||
|
__maxWidth={contentMaxWidth}
|
||||||
|
__gridTemplateColumns={useSingleColumn ? "1fr" : "9fr 4fr"}
|
||||||
|
__gridTemplateRows="auto 1fr"
|
||||||
|
__gridTemplateAreas={getLayoutAreas(useSingleColumn, isTablet)}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
12
src/components/AppLayout/LimitsInfo.tsx
Normal file
12
src/components/AppLayout/LimitsInfo.tsx
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
import { Box } from "@saleor/macaw-ui/next";
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
interface LimitsInfoProps {
|
||||||
|
text: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const LimitsInfo: React.FC<LimitsInfoProps> = ({ text }) => (
|
||||||
|
<Box position="absolute" left={10} bottom={3}>
|
||||||
|
{text}
|
||||||
|
</Box>
|
||||||
|
);
|
33
src/components/AppLayout/RightSidebar.tsx
Normal file
33
src/components/AppLayout/RightSidebar.tsx
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
import { Box } from "@saleor/macaw-ui/next";
|
||||||
|
import clsx from "clsx";
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
import { borderHeight, savebarHeight } from "./consts";
|
||||||
|
|
||||||
|
interface RightSidebarProps {
|
||||||
|
children: React.ReactNode;
|
||||||
|
className?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const RightSidebar: React.FC<RightSidebarProps> = ({
|
||||||
|
children,
|
||||||
|
className,
|
||||||
|
}) => (
|
||||||
|
<Box
|
||||||
|
borderStyle="solid"
|
||||||
|
borderColor="neutralPlain"
|
||||||
|
borderLeftWidth={1}
|
||||||
|
__height={`calc(100vh - ${savebarHeight} - ${borderHeight})`}
|
||||||
|
position="sticky"
|
||||||
|
top={0}
|
||||||
|
overflowY="auto"
|
||||||
|
borderYWidth={0}
|
||||||
|
borderTopWidth={0}
|
||||||
|
borderBottomWidth={0}
|
||||||
|
borderRightWidth={0}
|
||||||
|
__gridArea="right"
|
||||||
|
className={clsx("hide-scrollbar", className)}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</Box>
|
||||||
|
);
|
|
@ -1,13 +0,0 @@
|
||||||
import React from "react";
|
|
||||||
import { Link, LinkProps } from "react-router-dom";
|
|
||||||
|
|
||||||
interface SidebarLinkProps extends Omit<LinkProps, "to"> {
|
|
||||||
href?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const SidebarLink = React.forwardRef<
|
|
||||||
HTMLAnchorElement,
|
|
||||||
SidebarLinkProps
|
|
||||||
>(({ href, ...props }, ref) => <Link to={href} {...props} innerRef={ref} />);
|
|
||||||
|
|
||||||
SidebarLink.displayName = "SidebarLink";
|
|
72
src/components/AppLayout/TopNav.tsx
Normal file
72
src/components/AppLayout/TopNav.tsx
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
import { ArrowLeftIcon, Box, sprinkles, Text } from "@saleor/macaw-ui/next";
|
||||||
|
import React, { PropsWithChildren } from "react";
|
||||||
|
import { Link } from "react-router-dom";
|
||||||
|
|
||||||
|
import useAppChannel from "./AppChannelContext";
|
||||||
|
import AppChannelSelect from "./AppChannelSelect";
|
||||||
|
import { topBarHeight } from "./consts";
|
||||||
|
|
||||||
|
interface TopNavProps {
|
||||||
|
title: string | React.ReactNode;
|
||||||
|
href?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const TopNav: React.FC<PropsWithChildren<TopNavProps>> = ({
|
||||||
|
title,
|
||||||
|
href,
|
||||||
|
children,
|
||||||
|
}) => {
|
||||||
|
const { availableChannels, channel, isPickerActive, setChannel } =
|
||||||
|
useAppChannel(false);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box
|
||||||
|
display="flex"
|
||||||
|
alignItems="center"
|
||||||
|
paddingX={9}
|
||||||
|
paddingRight={9}
|
||||||
|
paddingY={8}
|
||||||
|
borderBottomWidth={1}
|
||||||
|
borderBottomStyle="solid"
|
||||||
|
borderColor="neutralPlain"
|
||||||
|
position="relative"
|
||||||
|
__gridArea="nav"
|
||||||
|
data-test-id="page-header"
|
||||||
|
__height={topBarHeight}
|
||||||
|
>
|
||||||
|
{href && (
|
||||||
|
<Link
|
||||||
|
to={href}
|
||||||
|
data-test-id="app-header-back-button"
|
||||||
|
className={sprinkles({
|
||||||
|
borderColor: "neutralPlain",
|
||||||
|
borderStyle: "solid",
|
||||||
|
borderWidth: 1,
|
||||||
|
padding: 5,
|
||||||
|
borderRadius: 2,
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "center",
|
||||||
|
marginRight: 7,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<ArrowLeftIcon />
|
||||||
|
</Link>
|
||||||
|
)}
|
||||||
|
<Box __flex={1}>
|
||||||
|
<Text variant="title">{title}</Text>
|
||||||
|
</Box>
|
||||||
|
<Box display="flex" flexWrap="nowrap">
|
||||||
|
{isPickerActive && (
|
||||||
|
<AppChannelSelect
|
||||||
|
channels={availableChannels}
|
||||||
|
selectedChannelId={channel?.id}
|
||||||
|
onChannelSelect={setChannel}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{children}
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
|
@ -1,6 +1,5 @@
|
||||||
export const drawerWidthExpanded = 210;
|
export const topBarHeight = "77px";
|
||||||
export const drawerWidthExpandedMobile = 250;
|
export const appLoaderHeight = 2;
|
||||||
export const drawerWidth = 80;
|
export const contentMaxWidth = "1440px";
|
||||||
export const drawerNestedMenuWidth = 300;
|
export const savebarHeight = "64px";
|
||||||
export const navigationBarHeight = 64;
|
export const borderHeight = "1px";
|
||||||
export const appLoaderHeight = 4;
|
|
||||||
|
|
|
@ -16,14 +16,10 @@ export const useStyles = makeStyles(
|
||||||
},
|
},
|
||||||
appLoader: {
|
appLoader: {
|
||||||
height: appLoaderHeight,
|
height: appLoaderHeight,
|
||||||
marginBottom: theme.spacing(4),
|
|
||||||
zIndex: 1201,
|
zIndex: 1201,
|
||||||
|
position: "fixed",
|
||||||
|
width: "100%",
|
||||||
},
|
},
|
||||||
appLoaderPlaceholder: {
|
|
||||||
height: appLoaderHeight,
|
|
||||||
marginBottom: theme.spacing(4),
|
|
||||||
},
|
|
||||||
|
|
||||||
content: {
|
content: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
[theme.breakpoints.up("md")]: {
|
[theme.breakpoints.up("md")]: {
|
||||||
|
|
|
@ -123,7 +123,7 @@ const AssignAttributeDialog: React.FC<AssignAttributeDialogProps> = ({
|
||||||
paper: classes.dialogPaper,
|
paper: classes.dialogPaper,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<DialogTitle>
|
<DialogTitle disableTypography>
|
||||||
<FormattedMessage {...messages.title} />
|
<FormattedMessage {...messages.title} />
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
<DialogContent className={classes.searchArea}>
|
<DialogContent className={classes.searchArea}>
|
||||||
|
|
|
@ -92,7 +92,7 @@ const AssignContainerDialog: React.FC<AssignContainerDialogProps> = props => {
|
||||||
fullWidth
|
fullWidth
|
||||||
maxWidth="sm"
|
maxWidth="sm"
|
||||||
>
|
>
|
||||||
<DialogTitle>{labels.title}</DialogTitle>
|
<DialogTitle disableTypography>{labels.title}</DialogTitle>
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
<TextField
|
<TextField
|
||||||
name="query"
|
name="query"
|
||||||
|
|
|
@ -108,7 +108,7 @@ const AssignProductDialog: React.FC<AssignProductDialogProps> = props => {
|
||||||
fullWidth
|
fullWidth
|
||||||
maxWidth="sm"
|
maxWidth="sm"
|
||||||
>
|
>
|
||||||
<DialogTitle>
|
<DialogTitle disableTypography>
|
||||||
<FormattedMessage {...messages.assignVariantDialogHeader} />
|
<FormattedMessage {...messages.assignVariantDialogHeader} />
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
|
|
|
@ -94,7 +94,7 @@ const AssignVariantDialog: React.FC<AssignVariantDialogProps> = props => {
|
||||||
fullWidth
|
fullWidth
|
||||||
maxWidth="sm"
|
maxWidth="sm"
|
||||||
>
|
>
|
||||||
<DialogTitle>
|
<DialogTitle disableTypography>
|
||||||
<FormattedMessage {...messages.assignVariantDialogHeader} />
|
<FormattedMessage {...messages.assignVariantDialogHeader} />
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
|
|
|
@ -12,6 +12,7 @@ const useStyles = makeStyles(
|
||||||
);
|
);
|
||||||
|
|
||||||
interface ControlledSwitchProps {
|
interface ControlledSwitchProps {
|
||||||
|
className?: string;
|
||||||
checked: boolean;
|
checked: boolean;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
label: string | React.ReactNode;
|
label: string | React.ReactNode;
|
||||||
|
@ -30,12 +31,14 @@ export const ControlledSwitch: React.FC<ControlledSwitchProps> = props => {
|
||||||
name,
|
name,
|
||||||
secondLabel,
|
secondLabel,
|
||||||
uncheckedLabel,
|
uncheckedLabel,
|
||||||
|
className,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const classes = useStyles(props);
|
const classes = useStyles(props);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FormControlLabel
|
<FormControlLabel
|
||||||
|
className={className}
|
||||||
control={
|
control={
|
||||||
<Switch
|
<Switch
|
||||||
onChange={() =>
|
onChange={() =>
|
||||||
|
|
|
@ -21,7 +21,11 @@ import ColumnPicker from "../ColumnPicker";
|
||||||
import { FullScreenContainer } from "./FullScreenContainer";
|
import { FullScreenContainer } from "./FullScreenContainer";
|
||||||
import { Header } from "./Header";
|
import { Header } from "./Header";
|
||||||
import { RowActions } from "./RowActions";
|
import { RowActions } from "./RowActions";
|
||||||
import useStyles, { useDatagridTheme, useFullScreenStyles } from "./styles";
|
import useStyles, {
|
||||||
|
cellHeight,
|
||||||
|
useDatagridTheme,
|
||||||
|
useFullScreenStyles,
|
||||||
|
} from "./styles";
|
||||||
import { AvailableColumn } from "./types";
|
import { AvailableColumn } from "./types";
|
||||||
import useCells from "./useCells";
|
import useCells from "./useCells";
|
||||||
import useColumns from "./useColumns";
|
import useColumns from "./useColumns";
|
||||||
|
@ -108,9 +112,8 @@ export const Datagrid: React.FC<DatagridProps> = ({
|
||||||
|
|
||||||
const [scrolledToRight, setScrolledToRight] = React.useState(false);
|
const [scrolledToRight, setScrolledToRight] = React.useState(false);
|
||||||
const scroller: HTMLDivElement = document.querySelector(".dvn-scroller");
|
const scroller: HTMLDivElement = document.querySelector(".dvn-scroller");
|
||||||
const scrollerInner: HTMLDivElement = document.querySelector(
|
const scrollerInner: HTMLDivElement =
|
||||||
".dvn-scroll-inner",
|
document.querySelector(".dvn-scroll-inner");
|
||||||
);
|
|
||||||
|
|
||||||
usePreventHistoryBack(scroller);
|
usePreventHistoryBack(scroller);
|
||||||
|
|
||||||
|
@ -260,8 +263,8 @@ export const Datagrid: React.FC<DatagridProps> = ({
|
||||||
onColumnResize={onColumnResize}
|
onColumnResize={onColumnResize}
|
||||||
onGridSelectionChange={setSelection}
|
onGridSelectionChange={setSelection}
|
||||||
gridSelection={selection}
|
gridSelection={selection}
|
||||||
rowHeight={48}
|
rowHeight={cellHeight}
|
||||||
headerHeight={48}
|
headerHeight={cellHeight}
|
||||||
ref={editor}
|
ref={editor}
|
||||||
onPaste
|
onPaste
|
||||||
rightElementProps={{
|
rightElementProps={{
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
import { Theme } from "@glideapps/glide-data-grid";
|
import { Theme } from "@glideapps/glide-data-grid";
|
||||||
import { Typography } from "@material-ui/core/styles/createTypography";
|
|
||||||
import { makeStyles, useTheme } from "@saleor/macaw-ui";
|
import { makeStyles, useTheme } from "@saleor/macaw-ui";
|
||||||
|
import { themes } from "@saleor/macaw-ui/next";
|
||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
|
|
||||||
|
export const cellHeight = 36;
|
||||||
|
|
||||||
const useStyles = makeStyles(
|
const useStyles = makeStyles(
|
||||||
theme => {
|
theme => {
|
||||||
const rowActionSelected = {
|
const rowActionSelected = {
|
||||||
|
@ -19,10 +21,10 @@ const useStyles = makeStyles(
|
||||||
background: theme.palette.background.paper,
|
background: theme.palette.background.paper,
|
||||||
borderRadius: 8,
|
borderRadius: 8,
|
||||||
// Right and left toolbars
|
// Right and left toolbars
|
||||||
width: "calc(100% - 64px - 48px - 1px)",
|
width: `calc(100% - 64px - ${cellHeight} - 1px)`,
|
||||||
marginTop: 1,
|
marginTop: 1,
|
||||||
marginLeft: 50,
|
marginLeft: 50,
|
||||||
height: 48,
|
height: cellHeight,
|
||||||
display: "flex",
|
display: "flex",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
justifyContent: "flex-end",
|
justifyContent: "flex-end",
|
||||||
|
@ -32,13 +34,14 @@ const useStyles = makeStyles(
|
||||||
display: "flex",
|
display: "flex",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
height: 48,
|
height: cellHeight,
|
||||||
},
|
},
|
||||||
ghostIcon: {
|
ghostIcon: {
|
||||||
color: theme.palette.saleor.main[3],
|
color: theme.palette.saleor.main[3],
|
||||||
},
|
},
|
||||||
portal: {
|
portal: {
|
||||||
"& input::-webkit-outer-spin-button, input::-webkit-inner-spin-button": {
|
"& input::-webkit-outer-spin-button, input::-webkit-inner-spin-button":
|
||||||
|
{
|
||||||
appearance: "none",
|
appearance: "none",
|
||||||
margin: 0,
|
margin: 0,
|
||||||
},
|
},
|
||||||
|
@ -61,13 +64,14 @@ const useStyles = makeStyles(
|
||||||
padding: "0 !important",
|
padding: "0 !important",
|
||||||
},
|
},
|
||||||
"& input, & textarea": {
|
"& input, & textarea": {
|
||||||
...theme.typography.body1,
|
|
||||||
appearance: "none",
|
appearance: "none",
|
||||||
background: "none",
|
background: "none",
|
||||||
border: "none",
|
border: "none",
|
||||||
fontSize: theme.typography.body1.fontSize,
|
fontSize: themes.defaultLight.fontSize.bodySmall,
|
||||||
letterSpacing: "0.44px",
|
letterSpacing: "0.015em",
|
||||||
padding: `1.4rem ${theme.spacing(1)}`,
|
lineHeight: themes.defaultLight.lineHeight.bodySmall,
|
||||||
|
fontWeight: themes.defaultLight.fontWeight.bodySmall,
|
||||||
|
padding: themes.defaultLight.space[3],
|
||||||
outline: 0,
|
outline: 0,
|
||||||
},
|
},
|
||||||
'& input[type="number"]': {
|
'& input[type="number"]': {
|
||||||
|
@ -98,7 +102,7 @@ const useStyles = makeStyles(
|
||||||
height: "100%",
|
height: "100%",
|
||||||
background: theme.palette.background.paper,
|
background: theme.palette.background.paper,
|
||||||
borderLeft: `1px solid ${activeBorderColor}`,
|
borderLeft: `1px solid ${activeBorderColor}`,
|
||||||
width: 48,
|
width: 36,
|
||||||
},
|
},
|
||||||
rowActionBarScrolledToRight: {
|
rowActionBarScrolledToRight: {
|
||||||
borderLeftColor: theme.palette.divider,
|
borderLeftColor: theme.palette.divider,
|
||||||
|
@ -119,7 +123,7 @@ const useStyles = makeStyles(
|
||||||
display: "flex",
|
display: "flex",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
height: 47,
|
height: `calc(${cellHeight}px - 1px)`,
|
||||||
},
|
},
|
||||||
rowActionScrolledToRight: {
|
rowActionScrolledToRight: {
|
||||||
borderLeftColor: theme.palette.divider,
|
borderLeftColor: theme.palette.divider,
|
||||||
|
@ -128,7 +132,7 @@ const useStyles = makeStyles(
|
||||||
position: "absolute",
|
position: "absolute",
|
||||||
top: 1,
|
top: 1,
|
||||||
left: 0,
|
left: 0,
|
||||||
height: 48,
|
height: cellHeight,
|
||||||
width: 10,
|
width: 10,
|
||||||
borderLeft: 0,
|
borderLeft: 0,
|
||||||
background: theme.palette.background.paper,
|
background: theme.palette.background.paper,
|
||||||
|
@ -176,21 +180,9 @@ export const useFullScreenStyles = makeStyles<ReturnType<typeof useStyles>>(
|
||||||
{ name: "Datagrid-fullscreen" },
|
{ name: "Datagrid-fullscreen" },
|
||||||
);
|
);
|
||||||
|
|
||||||
const calculateFontToPx = (remValue: string | number, base: number) => {
|
|
||||||
if (typeof remValue === "string") {
|
|
||||||
return `${parseFloat(remValue) * base}px`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return `${remValue * base}px`;
|
|
||||||
};
|
|
||||||
|
|
||||||
type HtmlTypography = Typography & { htmlFontSize: number };
|
|
||||||
|
|
||||||
export function useDatagridTheme() {
|
export function useDatagridTheme() {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
|
||||||
const base = (theme.typography as HtmlTypography).htmlFontSize * 0.625;
|
|
||||||
|
|
||||||
const datagridTheme = useMemo(
|
const datagridTheme = useMemo(
|
||||||
(): Partial<Theme> => ({
|
(): Partial<Theme> => ({
|
||||||
accentColor: theme.palette.secondary.main,
|
accentColor: theme.palette.secondary.main,
|
||||||
|
@ -203,15 +195,18 @@ export function useDatagridTheme() {
|
||||||
bgBubbleSelected: theme.palette.background.paper,
|
bgBubbleSelected: theme.palette.background.paper,
|
||||||
textHeader: theme.palette.text.secondary,
|
textHeader: theme.palette.text.secondary,
|
||||||
borderColor: theme.palette.divider,
|
borderColor: theme.palette.divider,
|
||||||
fontFamily: theme.typography.fontFamily,
|
fontFamily: themes.defaultLight.fontFamily.body,
|
||||||
baseFontStyle: calculateFontToPx(theme.typography.body1.fontSize, base),
|
baseFontStyle: themes.defaultLight.fontSize.bodySmall,
|
||||||
headerFontStyle: calculateFontToPx(theme.typography.body2.fontSize, base),
|
headerFontStyle: themes.defaultLight.fontSize.bodySmall,
|
||||||
editorFontSize: calculateFontToPx(theme.typography.body1.fontSize, base),
|
editorFontSize: themes.defaultLight.fontSize.bodySmall,
|
||||||
textMedium: theme.palette.text.primary,
|
textMedium: theme.palette.text.primary,
|
||||||
textGroupHeader: theme.palette.text.secondary,
|
textGroupHeader: theme.palette.text.secondary,
|
||||||
textBubble: theme.palette.text.primary,
|
textBubble: theme.palette.text.primary,
|
||||||
textDark: theme.palette.text.primary,
|
textDark: theme.palette.text.primary,
|
||||||
textLight: theme.palette.text.primary,
|
textLight: theme.palette.text.primary,
|
||||||
|
cellHorizontalPadding: 8,
|
||||||
|
cellVerticalPadding: 8,
|
||||||
|
lineHeight: 20,
|
||||||
}),
|
}),
|
||||||
[theme],
|
[theme],
|
||||||
);
|
);
|
||||||
|
|
|
@ -42,7 +42,7 @@ const useStyles = makeStyles(
|
||||||
root: {
|
root: {
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
display: "flex",
|
display: "flex",
|
||||||
height: "calc(100vh - 180px)",
|
height: "100vh",
|
||||||
},
|
},
|
||||||
header: {
|
header: {
|
||||||
marginBottom: theme.spacing(2),
|
marginBottom: theme.spacing(2),
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { ClickAwayListener, Grow, Popper, Typography } from "@material-ui/core";
|
import { ClickAwayListener, Grow, Popper, Typography } from "@material-ui/core";
|
||||||
import { alpha } from "@material-ui/core/styles";
|
import { alpha } from "@material-ui/core/styles";
|
||||||
import { Button, makeStyles } from "@saleor/macaw-ui";
|
import { Button, makeStyles } from "@saleor/macaw-ui";
|
||||||
|
import { vars } from "@saleor/macaw-ui/next";
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { FormattedMessage } from "react-intl";
|
import { FormattedMessage } from "react-intl";
|
||||||
|
@ -66,6 +67,10 @@ const useStyles = makeStyles(
|
||||||
width: 240,
|
width: 240,
|
||||||
},
|
},
|
||||||
popover: {
|
popover: {
|
||||||
|
backgroundColor: vars.colors.background.surfaceNeutralPlain,
|
||||||
|
overflowY: "scroll",
|
||||||
|
boxShadow: `0px 6px 11px 9px ${theme.palette.divider}`,
|
||||||
|
height: 450,
|
||||||
width: 376,
|
width: 376,
|
||||||
zIndex: 3,
|
zIndex: 3,
|
||||||
},
|
},
|
||||||
|
@ -182,14 +187,8 @@ const Filter: React.FC<FilterProps> = props => {
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{({ TransitionProps, placement }) => (
|
{() => (
|
||||||
<Grow
|
<Grow>
|
||||||
{...TransitionProps}
|
|
||||||
style={{
|
|
||||||
transformOrigin:
|
|
||||||
placement === "bottom" ? "right top" : "right bottom",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<FilterContent
|
<FilterContent
|
||||||
errorMessages={errorMessages}
|
errorMessages={errorMessages}
|
||||||
errors={filterErrors}
|
errors={filterErrors}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import CollectionWithDividers from "@dashboard/components/CollectionWithDividers";
|
import CollectionWithDividers from "@dashboard/components/CollectionWithDividers";
|
||||||
import Hr from "@dashboard/components/Hr";
|
|
||||||
import useStateFromProps from "@dashboard/hooks/useStateFromProps";
|
import useStateFromProps from "@dashboard/hooks/useStateFromProps";
|
||||||
import { makeStyles, Paper, Typography } from "@material-ui/core";
|
import { makeStyles, Paper, Typography } from "@material-ui/core";
|
||||||
import { Accordion, AccordionSummary } from "@saleor/macaw-ui";
|
import { Accordion, AccordionSummary } from "@saleor/macaw-ui";
|
||||||
|
@ -121,10 +120,8 @@ const FilterContent: React.FC<FilterContentProps> = ({
|
||||||
{},
|
{},
|
||||||
);
|
);
|
||||||
|
|
||||||
const [
|
const [autocompleteDisplayValues, setAutocompleteDisplayValues] =
|
||||||
autocompleteDisplayValues,
|
useStateFromProps<FilterAutocompleteDisplayValues>(
|
||||||
setAutocompleteDisplayValues,
|
|
||||||
] = useStateFromProps<FilterAutocompleteDisplayValues>(
|
|
||||||
initialAutocompleteDisplayValues,
|
initialAutocompleteDisplayValues,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -155,7 +152,7 @@ const FilterContent: React.FC<FilterContentProps> = ({
|
||||||
|
|
||||||
const handleFilterPropertyGroupChange = function <
|
const handleFilterPropertyGroupChange = function <
|
||||||
K extends string,
|
K extends string,
|
||||||
T extends FieldType
|
T extends FieldType,
|
||||||
>(action: FilterReducerAction<K, T>, filter: FilterElement<string>) {
|
>(action: FilterReducerAction<K, T>, filter: FilterElement<string>) {
|
||||||
const switchToActive = action.payload.update.active;
|
const switchToActive = action.payload.update.active;
|
||||||
if (switchToActive && filter.name !== openedFilter?.name) {
|
if (switchToActive && filter.name !== openedFilter?.name) {
|
||||||
|
@ -171,7 +168,7 @@ const FilterContent: React.FC<FilterContentProps> = ({
|
||||||
|
|
||||||
const handleMultipleFieldPropertyChange = function <
|
const handleMultipleFieldPropertyChange = function <
|
||||||
K extends string,
|
K extends string,
|
||||||
T extends FieldType
|
T extends FieldType,
|
||||||
>(action: FilterReducerAction<K, T>) {
|
>(action: FilterReducerAction<K, T>) {
|
||||||
const { update } = action.payload;
|
const { update } = action.payload;
|
||||||
onFilterPropertyChange({
|
onFilterPropertyChange({
|
||||||
|
@ -195,7 +192,7 @@ const FilterContent: React.FC<FilterContentProps> = ({
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<FilterContentHeader onClear={onClear} />
|
<FilterContentHeader onClear={onClear} />
|
||||||
<Hr />
|
|
||||||
{dataStructure
|
{dataStructure
|
||||||
.sort((a, b) => (a.name > b.name ? 1 : -1))
|
.sort((a, b) => (a.name > b.name ? 1 : -1))
|
||||||
.map(filter => {
|
.map(filter => {
|
||||||
|
|
|
@ -5,7 +5,6 @@ import { useCommonStyles } from "@dashboard/components/Filter/FilterContent/util
|
||||||
import { MultiAutocompleteChoiceType } from "@dashboard/components/MultiAutocompleteSelectField";
|
import { MultiAutocompleteChoiceType } from "@dashboard/components/MultiAutocompleteSelectField";
|
||||||
import Skeleton from "@dashboard/components/Skeleton";
|
import Skeleton from "@dashboard/components/Skeleton";
|
||||||
import { FormControlLabel, Radio, TextField } from "@material-ui/core";
|
import { FormControlLabel, Radio, TextField } from "@material-ui/core";
|
||||||
import { alpha } from "@material-ui/core/styles";
|
|
||||||
import { makeStyles } from "@saleor/macaw-ui";
|
import { makeStyles } from "@saleor/macaw-ui";
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
@ -27,7 +26,6 @@ import {
|
||||||
const useStyles = makeStyles(
|
const useStyles = makeStyles(
|
||||||
theme => ({
|
theme => ({
|
||||||
filterSettings: {
|
filterSettings: {
|
||||||
background: alpha(theme.palette.primary.main, 0.1),
|
|
||||||
padding: theme.spacing(2, 3),
|
padding: theme.spacing(2, 3),
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ import { Button } from "@dashboard/components/Button";
|
||||||
import { buttonMessages } from "@dashboard/intl";
|
import { buttonMessages } from "@dashboard/intl";
|
||||||
import { Typography } from "@material-ui/core";
|
import { Typography } from "@material-ui/core";
|
||||||
import { makeStyles } from "@saleor/macaw-ui";
|
import { makeStyles } from "@saleor/macaw-ui";
|
||||||
|
import { vars } from "@saleor/macaw-ui/next";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { FormattedMessage } from "react-intl";
|
import { FormattedMessage } from "react-intl";
|
||||||
|
|
||||||
|
@ -11,7 +12,12 @@ const useStyles = makeStyles(
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
display: "flex",
|
display: "flex",
|
||||||
justifyContent: "space-between",
|
justifyContent: "space-between",
|
||||||
|
position: "sticky",
|
||||||
|
top: 0,
|
||||||
padding: theme.spacing(1, 3),
|
padding: theme.spacing(1, 3),
|
||||||
|
backgroundColor: vars.colors.background.surfaceNeutralPlain,
|
||||||
|
borderBottom: `1px solid ${vars.colors.border.neutralPlain}`,
|
||||||
|
zIndex: 1,
|
||||||
},
|
},
|
||||||
clear: {
|
clear: {
|
||||||
marginRight: theme.spacing(1),
|
marginRight: theme.spacing(1),
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import { alpha } from "@material-ui/core";
|
|
||||||
import { makeStyles } from "@saleor/macaw-ui";
|
import { makeStyles } from "@saleor/macaw-ui";
|
||||||
|
|
||||||
const useStyles = makeStyles(
|
const useStyles = makeStyles(
|
||||||
|
@ -10,7 +9,6 @@ const useStyles = makeStyles(
|
||||||
marginRight: theme.spacing(2),
|
marginRight: theme.spacing(2),
|
||||||
},
|
},
|
||||||
filterSettings: {
|
filterSettings: {
|
||||||
background: alpha(theme.palette.primary.main, 0.1),
|
|
||||||
padding: theme.spacing(2, 3),
|
padding: theme.spacing(2, 3),
|
||||||
},
|
},
|
||||||
inputRange: {
|
inputRange: {
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { makeStyles } from "@saleor/macaw-ui";
|
import { makeStyles } from "@saleor/macaw-ui";
|
||||||
|
import { vars } from "@saleor/macaw-ui/next";
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
|
@ -7,16 +8,16 @@ interface HrProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
const useStyles = makeStyles(
|
const useStyles = makeStyles(
|
||||||
theme => ({
|
{
|
||||||
root: {
|
root: {
|
||||||
backgroundColor: theme.palette.divider,
|
backgroundColor: vars.colors.border.neutralPlain,
|
||||||
border: "none",
|
border: "none",
|
||||||
display: "block",
|
display: "block",
|
||||||
height: 1,
|
height: 1,
|
||||||
margin: 0,
|
margin: 0,
|
||||||
width: "100%",
|
width: "100%",
|
||||||
},
|
},
|
||||||
}),
|
},
|
||||||
{ name: "Hr" },
|
{ name: "Hr" },
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { Typography } from "@material-ui/core";
|
import { Typography } from "@material-ui/core";
|
||||||
import { alpha } from "@material-ui/core/styles";
|
import { alpha } from "@material-ui/core/styles";
|
||||||
import { ImageIcon, makeStyles } from "@saleor/macaw-ui";
|
import { ImageIcon, makeStyles } from "@saleor/macaw-ui";
|
||||||
|
import { vars } from "@saleor/macaw-ui/next";
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { FormattedMessage } from "react-intl";
|
import { FormattedMessage } from "react-intl";
|
||||||
|
@ -29,7 +30,7 @@ const useStyles = makeStyles(
|
||||||
},
|
},
|
||||||
imageContainer: {
|
imageContainer: {
|
||||||
background: "#ffffff",
|
background: "#ffffff",
|
||||||
border: "1px solid #eaeaea",
|
border: `1px solid ${vars.colors.border.neutralPlain}`,
|
||||||
borderRadius: theme.spacing(),
|
borderRadius: theme.spacing(),
|
||||||
height: 148,
|
height: 148,
|
||||||
justifySelf: "start",
|
justifySelf: "start",
|
||||||
|
|
|
@ -35,6 +35,7 @@ const useStyles = makeStyles(
|
||||||
interface LinkProps extends React.AnchorHTMLAttributes<HTMLAnchorElement> {
|
interface LinkProps extends React.AnchorHTMLAttributes<HTMLAnchorElement> {
|
||||||
href?: string;
|
href?: string;
|
||||||
color?: "primary" | "secondary";
|
color?: "primary" | "secondary";
|
||||||
|
inline?: boolean;
|
||||||
underline?: boolean;
|
underline?: boolean;
|
||||||
typographyProps?: TypographyProps;
|
typographyProps?: TypographyProps;
|
||||||
onClick?: React.MouseEventHandler;
|
onClick?: React.MouseEventHandler;
|
||||||
|
@ -45,6 +46,7 @@ const Link: React.FC<LinkProps> = props => {
|
||||||
const {
|
const {
|
||||||
className,
|
className,
|
||||||
children,
|
children,
|
||||||
|
inline = true,
|
||||||
color = "primary",
|
color = "primary",
|
||||||
underline = false,
|
underline = false,
|
||||||
onClick,
|
onClick,
|
||||||
|
@ -60,13 +62,16 @@ const Link: React.FC<LinkProps> = props => {
|
||||||
const opensNewTab = target === "_blank";
|
const opensNewTab = target === "_blank";
|
||||||
|
|
||||||
const commonLinkProps = {
|
const commonLinkProps = {
|
||||||
className: clsx(className, {
|
className: clsx(
|
||||||
[classes.root]: true,
|
{
|
||||||
|
[classes.root]: inline,
|
||||||
[classes[color]]: true,
|
[classes[color]]: true,
|
||||||
[classes.underline]: underline,
|
[classes.underline]: underline,
|
||||||
[classes.noUnderline]: !underline,
|
[classes.noUnderline]: !underline,
|
||||||
[classes.disabled]: disabled,
|
[classes.disabled]: disabled,
|
||||||
}),
|
},
|
||||||
|
className,
|
||||||
|
),
|
||||||
onClick: event => {
|
onClick: event => {
|
||||||
if (disabled || !onClick) {
|
if (disabled || !onClick) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -31,6 +31,7 @@ const useStyles = makeStyles(
|
||||||
"&&": {
|
"&&": {
|
||||||
paddingBottom: theme.spacing(2),
|
paddingBottom: theme.spacing(2),
|
||||||
paddingTop: theme.spacing(2),
|
paddingTop: theme.spacing(2),
|
||||||
|
paddingLeft: theme.spacing(4),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
content: {
|
content: {
|
||||||
|
|
|
@ -43,7 +43,7 @@ const useStyles = makeStyles(
|
||||||
root: {
|
root: {
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
display: "flex",
|
display: "flex",
|
||||||
height: "calc(100vh - 180px)",
|
height: "100vh",
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
{ name: "NotFoundPage" },
|
{ name: "NotFoundPage" },
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import VerticalSpacer from "@dashboard/apps/components/VerticalSpacer";
|
import VerticalSpacer from "@dashboard/apps/components/VerticalSpacer";
|
||||||
import { Typography } from "@material-ui/core";
|
import { Typography } from "@material-ui/core";
|
||||||
|
import { Box } from "@saleor/macaw-ui/next";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
interface PageSectionHeaderProps {
|
interface PageSectionHeaderProps {
|
||||||
|
@ -11,11 +12,11 @@ const PageSectionHeader: React.FC<PageSectionHeaderProps> = props => {
|
||||||
const { title, description } = props;
|
const { title, description } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<Box paddingTop={9}>
|
||||||
{title && <Typography variant="h5">{title}</Typography>}
|
{title && <Typography variant="h5">{title}</Typography>}
|
||||||
{title && description && <VerticalSpacer />}
|
{title && description && <VerticalSpacer />}
|
||||||
{description && <Typography variant="body2">{description}</Typography>}
|
{description && <Typography variant="body2">{description}</Typography>}
|
||||||
</div>
|
</Box>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -99,11 +99,6 @@ const useStyles = makeStyles(
|
||||||
borderColor: isDarkMode
|
borderColor: isDarkMode
|
||||||
? theme.palette.saleor.main[2]
|
? theme.palette.saleor.main[2]
|
||||||
: theme.palette.saleor.main[4],
|
: theme.palette.saleor.main[4],
|
||||||
boxShadow: `0 0 0 3px ${
|
|
||||||
isDarkMode
|
|
||||||
? theme.palette.saleor.main[4]
|
|
||||||
: theme.palette.saleor.main[6]
|
|
||||||
}`,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
root: {
|
root: {
|
||||||
|
|
|
@ -48,7 +48,7 @@ const SaveFilterTabDialog: React.FC<SaveFilterTabDialogProps> = ({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog onClose={onClose} open={open} fullWidth maxWidth="sm">
|
<Dialog onClose={onClose} open={open} fullWidth maxWidth="sm">
|
||||||
<DialogTitle>
|
<DialogTitle disableTypography>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id="liLrVs"
|
id="liLrVs"
|
||||||
defaultMessage="Save Custom Search"
|
defaultMessage="Save Custom Search"
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { buttonMessages, commonMessages } from "@dashboard/intl";
|
import { buttonMessages, commonMessages } from "@dashboard/intl";
|
||||||
import {
|
import {
|
||||||
|
makeStyles,
|
||||||
Savebar as MacawSavebar,
|
Savebar as MacawSavebar,
|
||||||
SavebarLabels,
|
SavebarLabels,
|
||||||
SavebarProps as MacawSavebarProps,
|
SavebarProps as MacawSavebarProps,
|
||||||
|
@ -7,12 +8,38 @@ import {
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useIntl } from "react-intl";
|
import { useIntl } from "react-intl";
|
||||||
|
|
||||||
|
import { contentMaxWidth, savebarHeight } from "./AppLayout/consts";
|
||||||
|
|
||||||
export interface SavebarProps extends Omit<MacawSavebarProps, "labels"> {
|
export interface SavebarProps extends Omit<MacawSavebarProps, "labels"> {
|
||||||
labels?: Partial<SavebarLabels>;
|
labels?: Partial<SavebarLabels>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const useStyles = makeStyles(
|
||||||
|
{
|
||||||
|
root: {
|
||||||
|
height: savebarHeight,
|
||||||
|
"& .MuiContainer-root": {
|
||||||
|
paddingRight: 0,
|
||||||
|
paddingLeft: 0,
|
||||||
|
maxWidth: contentMaxWidth,
|
||||||
|
margin: "0 auto",
|
||||||
|
},
|
||||||
|
"& .MuiPaper-root": {
|
||||||
|
boxShadow: "none",
|
||||||
|
},
|
||||||
|
"& .MuiCardContent-root": {
|
||||||
|
marginTop: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Savebar",
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
export const Savebar: React.FC<SavebarProps> = ({ labels = {}, ...rest }) => {
|
export const Savebar: React.FC<SavebarProps> = ({ labels = {}, ...rest }) => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
const classes = useStyles();
|
||||||
|
|
||||||
const defaultLabels: SavebarLabels = {
|
const defaultLabels: SavebarLabels = {
|
||||||
cancel: intl.formatMessage(buttonMessages.back),
|
cancel: intl.formatMessage(buttonMessages.back),
|
||||||
|
@ -25,7 +52,9 @@ export const Savebar: React.FC<SavebarProps> = ({ labels = {}, ...rest }) => {
|
||||||
...labels,
|
...labels,
|
||||||
};
|
};
|
||||||
|
|
||||||
return <MacawSavebar labels={componentLabels} {...rest} />;
|
return (
|
||||||
|
<MacawSavebar labels={componentLabels} {...rest} className={classes.root} />
|
||||||
|
);
|
||||||
};
|
};
|
||||||
Savebar.displayName = "SaveBar";
|
Savebar.displayName = "SaveBar";
|
||||||
export default Savebar;
|
export default Savebar;
|
||||||
|
|
20
src/components/Sidebar/Content.tsx
Normal file
20
src/components/Sidebar/Content.tsx
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
import { Box } from "@saleor/macaw-ui/next";
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
import { Menu } from "./menu";
|
||||||
|
import { MountingPoint } from "./MountingPoint";
|
||||||
|
import { UserInfo } from "./user";
|
||||||
|
|
||||||
|
export const SidebarContent = () => (
|
||||||
|
<Box
|
||||||
|
backgroundColor="subdued"
|
||||||
|
as="aside"
|
||||||
|
height="100%"
|
||||||
|
display="grid"
|
||||||
|
__gridTemplateRows="auto 1fr auto"
|
||||||
|
>
|
||||||
|
<MountingPoint />
|
||||||
|
<Menu />
|
||||||
|
<UserInfo />
|
||||||
|
</Box>
|
||||||
|
);
|
12
src/components/Sidebar/MountingPoint.tsx
Normal file
12
src/components/Sidebar/MountingPoint.tsx
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
import sideBarDefaultLogo from "@assets/images/sidebar-default-logo.png";
|
||||||
|
import { Avatar, Box, Text } from "@saleor/macaw-ui/next";
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
export const MountingPoint = () => (
|
||||||
|
<Box display="flex" gap={6} paddingX={7} paddingY={8}>
|
||||||
|
<Avatar.Store src={sideBarDefaultLogo} scheme="decorative2" size="small" />
|
||||||
|
<Text variant="bodyStrong" size="small">
|
||||||
|
Saleor Dashboard
|
||||||
|
</Text>
|
||||||
|
</Box>
|
||||||
|
);
|
37
src/components/Sidebar/Sidebar.tsx
Normal file
37
src/components/Sidebar/Sidebar.tsx
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
import { Box, Drawer, MenuIcon } from "@saleor/macaw-ui/next";
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
import { SidebarContent } from "./Content";
|
||||||
|
|
||||||
|
export const Sidebar = () => (
|
||||||
|
<>
|
||||||
|
<Box
|
||||||
|
display={{ mobile: "none", tablet: "none", desktop: "block" }}
|
||||||
|
height="100%"
|
||||||
|
>
|
||||||
|
<SidebarContent />
|
||||||
|
</Box>
|
||||||
|
<Box display={{ mobile: "block", tablet: "block", desktop: "none" }}>
|
||||||
|
<Drawer>
|
||||||
|
<Drawer.Trigger>
|
||||||
|
<Box
|
||||||
|
as="button"
|
||||||
|
borderWidth={0}
|
||||||
|
backgroundColor="interactiveNeutralHighlightDefault"
|
||||||
|
cursor="pointer"
|
||||||
|
data-test-id="sidebar-drawer-open"
|
||||||
|
>
|
||||||
|
<MenuIcon />
|
||||||
|
</Box>
|
||||||
|
</Drawer.Trigger>
|
||||||
|
<Drawer.Content
|
||||||
|
backgroundColor="subdued"
|
||||||
|
data-test-id="sidebar-drawer-content"
|
||||||
|
paddingTop={0}
|
||||||
|
>
|
||||||
|
<SidebarContent />
|
||||||
|
</Drawer.Content>
|
||||||
|
</Drawer>
|
||||||
|
</Box>
|
||||||
|
</>
|
||||||
|
);
|
1
src/components/Sidebar/index.ts
Normal file
1
src/components/Sidebar/index.ts
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export * from "./Sidebar";
|
16
src/components/Sidebar/menu/Divider.tsx
Normal file
16
src/components/Sidebar/menu/Divider.tsx
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
import { List, Text } from "@saleor/macaw-ui/next";
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
import { SidebarMenuItem } from "./types";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
menuItem: SidebarMenuItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Divider: React.FC<Props> = ({ menuItem }) => (
|
||||||
|
<List.Divider paddingY={menuItem.paddingY ?? 4} paddingX={3}>
|
||||||
|
<Text variant="caption" size="small" color="textNeutralSubdued">
|
||||||
|
{menuItem.label}
|
||||||
|
</Text>
|
||||||
|
</List.Divider>
|
||||||
|
);
|
22
src/components/Sidebar/menu/Item.tsx
Normal file
22
src/components/Sidebar/menu/Item.tsx
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
import { Divider } from "./Divider";
|
||||||
|
import { ItemGroup } from "./ItemGroup";
|
||||||
|
import { SingleItem } from "./SingleItem";
|
||||||
|
import { SidebarMenuItem } from "./types";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
menuItem: SidebarMenuItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const MenuItem: React.FC<Props> = props => {
|
||||||
|
const { menuItem } = props;
|
||||||
|
switch (menuItem.type) {
|
||||||
|
case "item":
|
||||||
|
return <SingleItem {...props} />;
|
||||||
|
case "itemGroup":
|
||||||
|
return <ItemGroup {...props} />;
|
||||||
|
case "divider":
|
||||||
|
return <Divider menuItem={menuItem} />;
|
||||||
|
}
|
||||||
|
};
|
47
src/components/Sidebar/menu/ItemGroup.tsx
Normal file
47
src/components/Sidebar/menu/ItemGroup.tsx
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
import { Box, List, Text } from "@saleor/macaw-ui/next";
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
import { MenuItem } from "./Item";
|
||||||
|
import { SidebarMenuItem } from "./types";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
menuItem: SidebarMenuItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ItemGroup: React.FC<Props> = ({ menuItem }) => (
|
||||||
|
<List.ItemGroup>
|
||||||
|
<List.ItemGroup.Trigger
|
||||||
|
paddingX={5}
|
||||||
|
paddingY={4}
|
||||||
|
borderRadius={3}
|
||||||
|
size="small"
|
||||||
|
justifyContent="space-between"
|
||||||
|
data-test-id={`menu-item-label-${menuItem.id}`}
|
||||||
|
>
|
||||||
|
<Box display="flex" alignItems="center" gap={6}>
|
||||||
|
{menuItem.icon}
|
||||||
|
<Text size="small" variant="bodyEmp">
|
||||||
|
{menuItem.label}
|
||||||
|
</Text>
|
||||||
|
</Box>
|
||||||
|
</List.ItemGroup.Trigger>
|
||||||
|
<List.ItemGroup.Content>
|
||||||
|
<Box
|
||||||
|
borderLeftWidth={1}
|
||||||
|
borderLeftStyle="solid"
|
||||||
|
borderColor="neutralPlain"
|
||||||
|
paddingLeft={7}
|
||||||
|
marginLeft={7}
|
||||||
|
display="flex"
|
||||||
|
flexDirection="column"
|
||||||
|
marginBottom={5}
|
||||||
|
marginTop={3}
|
||||||
|
gap={1}
|
||||||
|
>
|
||||||
|
{menuItem.children?.map(child => (
|
||||||
|
<MenuItem menuItem={child} key={child.id} />
|
||||||
|
))}
|
||||||
|
</Box>
|
||||||
|
</List.ItemGroup.Content>
|
||||||
|
</List.ItemGroup>
|
||||||
|
);
|
19
src/components/Sidebar/menu/Menu.tsx
Normal file
19
src/components/Sidebar/menu/Menu.tsx
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
import { Box, List } from "@saleor/macaw-ui/next";
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
import { MenuItem } from "./Item";
|
||||||
|
import { useMenuStructure } from "./useMenuStructure";
|
||||||
|
|
||||||
|
export const Menu = () => {
|
||||||
|
const menuStructure = useMenuStructure();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box padding={6} overflowY="auto" className="hide-scrollbar">
|
||||||
|
<List as="ol" display="grid" gap={3}>
|
||||||
|
{menuStructure.map(menuItem => (
|
||||||
|
<MenuItem menuItem={menuItem} key={menuItem.id} />
|
||||||
|
))}
|
||||||
|
</List>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
52
src/components/Sidebar/menu/SingleItem.tsx
Normal file
52
src/components/Sidebar/menu/SingleItem.tsx
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
import {
|
||||||
|
extensionMountPoints,
|
||||||
|
useExtensions,
|
||||||
|
} from "@dashboard/apps/useExtensions";
|
||||||
|
import { Box, List, sprinkles, Text } from "@saleor/macaw-ui/next";
|
||||||
|
import React from "react";
|
||||||
|
import { Link } from "react-router-dom";
|
||||||
|
|
||||||
|
import { SidebarMenuItem } from "./types";
|
||||||
|
import { getMenuItemExtension, isMenuActive } from "./utils";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
menuItem: SidebarMenuItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const SingleItem: React.FC<Props> = ({ menuItem }) => {
|
||||||
|
const extensions = useExtensions(extensionMountPoints.NAVIGATION_SIDEBAR);
|
||||||
|
const active = isMenuActive(location.pathname, menuItem);
|
||||||
|
|
||||||
|
const handleMenuItemClick = () => {
|
||||||
|
const extension = getMenuItemExtension(extensions, menuItem.id);
|
||||||
|
if (extension) {
|
||||||
|
extension.open();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<List.Item
|
||||||
|
borderRadius={3}
|
||||||
|
active={active}
|
||||||
|
onClick={handleMenuItemClick}
|
||||||
|
data-test-id={`menu-item-label-${menuItem.id}`}
|
||||||
|
>
|
||||||
|
<Link
|
||||||
|
to={menuItem.url}
|
||||||
|
className={sprinkles({
|
||||||
|
paddingY: 4,
|
||||||
|
paddingX: 5,
|
||||||
|
display: "block",
|
||||||
|
width: "100%",
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<Box display="flex" alignItems="center" gap={6}>
|
||||||
|
{menuItem.icon}
|
||||||
|
<Text size="small" variant="bodyEmp">
|
||||||
|
{menuItem.label}
|
||||||
|
</Text>
|
||||||
|
</Box>
|
||||||
|
</Link>
|
||||||
|
</List.Item>
|
||||||
|
);
|
||||||
|
};
|
1
src/components/Sidebar/menu/index.ts
Normal file
1
src/components/Sidebar/menu/index.ts
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export * from "./Menu";
|
14
src/components/Sidebar/menu/types.ts
Normal file
14
src/components/Sidebar/menu/types.ts
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
import { PermissionEnum } from "@dashboard/graphql";
|
||||||
|
import { Sprinkles } from "@saleor/macaw-ui/next";
|
||||||
|
|
||||||
|
export interface SidebarMenuItem {
|
||||||
|
label?: string;
|
||||||
|
id: string;
|
||||||
|
url?: string;
|
||||||
|
permissions?: PermissionEnum[];
|
||||||
|
type: "item" | "itemGroup" | "divider";
|
||||||
|
icon?: React.ReactNode;
|
||||||
|
onClick?: () => void;
|
||||||
|
children?: SidebarMenuItem[];
|
||||||
|
paddingY?: Sprinkles["paddingY"];
|
||||||
|
}
|
|
@ -1,284 +1,294 @@
|
||||||
import appsIcon from "@assets/images/menu-apps-icon.svg";
|
import { appsListPath } from "@dashboard/apps/urls";
|
||||||
import catalogIcon from "@assets/images/menu-catalog-icon.svg";
|
|
||||||
import configurationIcon from "@assets/images/menu-configure-icon.svg";
|
|
||||||
import customerIcon from "@assets/images/menu-customers-icon.svg";
|
|
||||||
import discountsIcon from "@assets/images/menu-discounts-icon.svg";
|
|
||||||
import homeIcon from "@assets/images/menu-home-icon.svg";
|
|
||||||
import ordersIcon from "@assets/images/menu-orders-icon.svg";
|
|
||||||
import pagesIcon from "@assets/images/menu-pages-icon.svg";
|
|
||||||
import translationIcon from "@assets/images/menu-translation-icon.svg";
|
|
||||||
import {
|
import {
|
||||||
extensionMountPoints,
|
extensionMountPoints,
|
||||||
useExtensions,
|
useExtensions,
|
||||||
} from "@dashboard/apps/useExtensions";
|
} from "@dashboard/apps/useExtensions";
|
||||||
|
import { useUser } from "@dashboard/auth";
|
||||||
|
import { categoryListUrl } from "@dashboard/categories/urls";
|
||||||
|
import { collectionListUrl } from "@dashboard/collections/urls";
|
||||||
import { MARKETPLACE_URL } from "@dashboard/config";
|
import { MARKETPLACE_URL } from "@dashboard/config";
|
||||||
import { configurationMenuUrl } from "@dashboard/configuration";
|
import { configurationMenuUrl } from "@dashboard/configuration";
|
||||||
import { getConfigMenuItemsPermissions } from "@dashboard/configuration/utils";
|
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 { giftCardListUrl } from "@dashboard/giftCards/urls";
|
||||||
import { PermissionEnum, UserFragment } from "@dashboard/graphql";
|
import { PermissionEnum } from "@dashboard/graphql";
|
||||||
import { commonMessages, sectionNames } from "@dashboard/intl";
|
import { commonMessages, sectionNames } from "@dashboard/intl";
|
||||||
import { marketplaceUrlResolver } from "@dashboard/marketplace/marketplace-url-resolver";
|
import { marketplaceUrlResolver } from "@dashboard/marketplace/marketplace-url-resolver";
|
||||||
|
import { orderDraftListUrl, orderListUrl } from "@dashboard/orders/urls";
|
||||||
import { pageListPath } from "@dashboard/pages/urls";
|
import { pageListPath } from "@dashboard/pages/urls";
|
||||||
import { SidebarMenuItem } from "@saleor/macaw-ui";
|
import { productListUrl } from "@dashboard/products/urls";
|
||||||
import { IntlShape } from "react-intl";
|
import { languageListUrl } from "@dashboard/translations/urls";
|
||||||
|
import {
|
||||||
|
ConfigurationIcon,
|
||||||
|
CustomersIcon,
|
||||||
|
HomeIcon,
|
||||||
|
MarketplaceIcon,
|
||||||
|
OrdersIcon,
|
||||||
|
ProductsIcons,
|
||||||
|
StorefrontIcon,
|
||||||
|
TranslationsIcon,
|
||||||
|
VouchersIcon,
|
||||||
|
} from "@saleor/macaw-ui/next";
|
||||||
|
import isEmpty from "lodash/isEmpty";
|
||||||
|
import React from "react";
|
||||||
|
import { useIntl } from "react-intl";
|
||||||
|
|
||||||
import { appsListPath } from "../../apps/urls";
|
import { SidebarMenuItem } from "./types";
|
||||||
import { categoryListUrl } from "../../categories/urls";
|
import { mapToExtensionsItems } from "./utils";
|
||||||
import { collectionListUrl } from "../../collections/urls";
|
|
||||||
import { customerListUrl } from "../../customers/urls";
|
|
||||||
import { saleListUrl, voucherListUrl } from "../../discounts/urls";
|
|
||||||
import { orderDraftListUrl, orderListUrl } from "../../orders/urls";
|
|
||||||
import { productListUrl } from "../../products/urls";
|
|
||||||
import { languageListUrl } from "../../translations/urls";
|
|
||||||
import { getMenuItemExtension, mapToExtensionsItems } from "./utils";
|
|
||||||
|
|
||||||
export interface FilterableMenuItem extends Omit<SidebarMenuItem, "children"> {
|
const iconSettings = {
|
||||||
children?: FilterableMenuItem[];
|
color: "iconNeutralSubdued",
|
||||||
permissions?: PermissionEnum[];
|
size: "medium",
|
||||||
}
|
} as const;
|
||||||
|
|
||||||
function useMenuStructure(
|
export function useMenuStructure() {
|
||||||
intl: IntlShape,
|
|
||||||
user: UserFragment,
|
|
||||||
): [SidebarMenuItem[], (menuItem: SidebarMenuItem) => void] {
|
|
||||||
const extensions = useExtensions(extensionMountPoints.NAVIGATION_SIDEBAR);
|
const extensions = useExtensions(extensionMountPoints.NAVIGATION_SIDEBAR);
|
||||||
|
const intl = useIntl();
|
||||||
|
const { user } = useUser();
|
||||||
|
|
||||||
const handleMenuItemClick = (menuItem: SidebarMenuItem) => {
|
const appExtensionsHeaderItem: SidebarMenuItem = {
|
||||||
const extension = getMenuItemExtension(extensions, menuItem);
|
|
||||||
if (extension) {
|
|
||||||
extension.open();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const appExtensionsHeaderItem = {
|
|
||||||
id: "extensions",
|
id: "extensions",
|
||||||
ariaLabel: "apps",
|
|
||||||
label: intl.formatMessage(sectionNames.appExtensions),
|
label: intl.formatMessage(sectionNames.appExtensions),
|
||||||
|
type: "divider",
|
||||||
|
paddingY: 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
// This will be deleted when Marketplace is released
|
// This will be deleted when Marketplace is released
|
||||||
// Consider this solution as temporary
|
// Consider this solution as temporary
|
||||||
const getAppSection = () => {
|
const getAppSection = (): SidebarMenuItem => {
|
||||||
if (MARKETPLACE_URL) {
|
if (MARKETPLACE_URL) {
|
||||||
return {
|
return {
|
||||||
ariaLabel: "apps_section",
|
icon: <MarketplaceIcon {...iconSettings} />,
|
||||||
iconSrc: appsIcon,
|
|
||||||
label: intl.formatMessage(sectionNames.apps),
|
label: intl.formatMessage(sectionNames.apps),
|
||||||
permissions: [PermissionEnum.MANAGE_APPS],
|
permissions: [PermissionEnum.MANAGE_APPS],
|
||||||
id: "apps_section",
|
id: "apps_section",
|
||||||
|
type: "itemGroup",
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
label: intl.formatMessage(sectionNames.apps),
|
label: intl.formatMessage(sectionNames.apps),
|
||||||
id: "apps",
|
id: "apps",
|
||||||
url: appsListPath,
|
url: appsListPath,
|
||||||
|
type: "item",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ariaLabel: "marketplace",
|
|
||||||
label: intl.formatMessage(sectionNames.marketplace),
|
label: intl.formatMessage(sectionNames.marketplace),
|
||||||
id: "marketplace-saleor-apps",
|
id: "marketplace-saleor-apps",
|
||||||
url: marketplaceUrlResolver.getSaleorAppsDashboardPath(),
|
url: marketplaceUrlResolver.getSaleorAppsDashboardPath(),
|
||||||
|
type: "item",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ariaLabel: "marketplace",
|
|
||||||
label: intl.formatMessage(sectionNames.appTemplateGallery),
|
label: intl.formatMessage(sectionNames.appTemplateGallery),
|
||||||
id: "marketplace-template-gallery",
|
id: "marketplace-template-gallery",
|
||||||
url: marketplaceUrlResolver.getTemplateGalleryDashboardPath(),
|
url: marketplaceUrlResolver.getTemplateGalleryDashboardPath(),
|
||||||
|
type: "item",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
ariaLabel: "apps",
|
icon: <MarketplaceIcon {...iconSettings} />,
|
||||||
iconSrc: appsIcon,
|
|
||||||
label: intl.formatMessage(sectionNames.apps),
|
label: intl.formatMessage(sectionNames.apps),
|
||||||
permissions: [PermissionEnum.MANAGE_APPS],
|
permissions: [PermissionEnum.MANAGE_APPS],
|
||||||
id: "apps",
|
id: "apps",
|
||||||
url: appsListPath,
|
url: appsListPath,
|
||||||
|
type: "item",
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const menuItems: FilterableMenuItem[] = [
|
const menuItems: SidebarMenuItem[] = [
|
||||||
{
|
{
|
||||||
ariaLabel: "home",
|
icon: <HomeIcon {...iconSettings} />,
|
||||||
iconSrc: homeIcon,
|
|
||||||
label: intl.formatMessage(sectionNames.home),
|
label: intl.formatMessage(sectionNames.home),
|
||||||
id: "home",
|
id: "home",
|
||||||
url: "/",
|
url: "/",
|
||||||
|
type: "item",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ariaLabel: "catalogue",
|
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
ariaLabel: "products",
|
|
||||||
label: intl.formatMessage(sectionNames.products),
|
label: intl.formatMessage(sectionNames.products),
|
||||||
id: "products",
|
id: "products",
|
||||||
url: productListUrl(),
|
url: productListUrl(),
|
||||||
permissions: [PermissionEnum.MANAGE_PRODUCTS],
|
permissions: [PermissionEnum.MANAGE_PRODUCTS],
|
||||||
|
type: "item",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ariaLabel: "categories",
|
|
||||||
label: intl.formatMessage(sectionNames.categories),
|
label: intl.formatMessage(sectionNames.categories),
|
||||||
id: "categories",
|
id: "categories",
|
||||||
url: categoryListUrl(),
|
url: categoryListUrl(),
|
||||||
permissions: [PermissionEnum.MANAGE_PRODUCTS],
|
permissions: [PermissionEnum.MANAGE_PRODUCTS],
|
||||||
|
type: "item",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ariaLabel: "collections",
|
|
||||||
label: intl.formatMessage(sectionNames.collections),
|
label: intl.formatMessage(sectionNames.collections),
|
||||||
id: "collections",
|
id: "collections",
|
||||||
url: collectionListUrl(),
|
url: collectionListUrl(),
|
||||||
permissions: [PermissionEnum.MANAGE_PRODUCTS],
|
permissions: [PermissionEnum.MANAGE_PRODUCTS],
|
||||||
|
type: "item",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ariaLabel: "giftCards",
|
|
||||||
label: intl.formatMessage(sectionNames.giftCards),
|
label: intl.formatMessage(sectionNames.giftCards),
|
||||||
id: "giftCards",
|
id: "giftCards",
|
||||||
url: giftCardListUrl(),
|
url: giftCardListUrl(),
|
||||||
permissions: [PermissionEnum.MANAGE_GIFT_CARD],
|
permissions: [PermissionEnum.MANAGE_GIFT_CARD],
|
||||||
|
type: "item",
|
||||||
},
|
},
|
||||||
...mapToExtensionsItems(
|
...mapToExtensionsItems(
|
||||||
extensions.NAVIGATION_CATALOG,
|
extensions.NAVIGATION_CATALOG,
|
||||||
appExtensionsHeaderItem,
|
appExtensionsHeaderItem,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
iconSrc: catalogIcon,
|
icon: <ProductsIcons {...iconSettings} />,
|
||||||
label: intl.formatMessage(commonMessages.catalog),
|
label: intl.formatMessage(commonMessages.products),
|
||||||
permissions: [
|
permissions: [
|
||||||
PermissionEnum.MANAGE_GIFT_CARD,
|
PermissionEnum.MANAGE_GIFT_CARD,
|
||||||
PermissionEnum.MANAGE_PRODUCTS,
|
PermissionEnum.MANAGE_PRODUCTS,
|
||||||
],
|
],
|
||||||
id: "catalogue",
|
id: "products",
|
||||||
|
type: "itemGroup",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "divider-1",
|
||||||
|
type: "divider",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ariaLabel: "orders",
|
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
ariaLabel: "orders",
|
|
||||||
label: intl.formatMessage(sectionNames.orders),
|
label: intl.formatMessage(sectionNames.orders),
|
||||||
permissions: [PermissionEnum.MANAGE_ORDERS],
|
permissions: [PermissionEnum.MANAGE_ORDERS],
|
||||||
id: "orders",
|
id: "orders",
|
||||||
url: orderListUrl(),
|
url: orderListUrl(),
|
||||||
|
type: "item",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ariaLabel: "order drafts",
|
|
||||||
label: intl.formatMessage(commonMessages.drafts),
|
label: intl.formatMessage(commonMessages.drafts),
|
||||||
permissions: [PermissionEnum.MANAGE_ORDERS],
|
permissions: [PermissionEnum.MANAGE_ORDERS],
|
||||||
id: "order-drafts",
|
id: "order-drafts",
|
||||||
url: orderDraftListUrl(),
|
url: orderDraftListUrl(),
|
||||||
|
type: "item",
|
||||||
},
|
},
|
||||||
...mapToExtensionsItems(
|
...mapToExtensionsItems(
|
||||||
extensions.NAVIGATION_ORDERS,
|
extensions.NAVIGATION_ORDERS,
|
||||||
appExtensionsHeaderItem,
|
appExtensionsHeaderItem,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
iconSrc: ordersIcon,
|
icon: <OrdersIcon {...iconSettings} />,
|
||||||
label: intl.formatMessage(sectionNames.orders),
|
label: intl.formatMessage(sectionNames.orders),
|
||||||
permissions: [PermissionEnum.MANAGE_ORDERS],
|
permissions: [PermissionEnum.MANAGE_ORDERS],
|
||||||
id: "orders",
|
id: "orders",
|
||||||
|
type: "itemGroup",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ariaLabel: "customers",
|
children: !isEmpty(extensions.NAVIGATION_CUSTOMERS) && [
|
||||||
children: extensions.NAVIGATION_CUSTOMERS.length > 0 && [
|
|
||||||
{
|
{
|
||||||
ariaLabel: "customers",
|
|
||||||
label: intl.formatMessage(sectionNames.customers),
|
label: intl.formatMessage(sectionNames.customers),
|
||||||
permissions: [PermissionEnum.MANAGE_USERS],
|
permissions: [PermissionEnum.MANAGE_USERS],
|
||||||
id: "customers",
|
id: "customers",
|
||||||
url: customerListUrl(),
|
url: customerListUrl(),
|
||||||
|
type: "item",
|
||||||
},
|
},
|
||||||
...mapToExtensionsItems(
|
...mapToExtensionsItems(
|
||||||
extensions.NAVIGATION_CUSTOMERS,
|
extensions.NAVIGATION_CUSTOMERS,
|
||||||
appExtensionsHeaderItem,
|
appExtensionsHeaderItem,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
iconSrc: customerIcon,
|
icon: <CustomersIcon {...iconSettings} />,
|
||||||
label: intl.formatMessage(sectionNames.customers),
|
label: intl.formatMessage(sectionNames.customers),
|
||||||
permissions: [PermissionEnum.MANAGE_USERS],
|
permissions: [PermissionEnum.MANAGE_USERS],
|
||||||
id: "customers",
|
id: "customers",
|
||||||
url: customerListUrl(),
|
url: customerListUrl(),
|
||||||
|
type: !isEmpty(extensions.NAVIGATION_CUSTOMERS) ? "itemGroup" : "item",
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
ariaLabel: "discounts",
|
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
ariaLabel: "sales",
|
|
||||||
label: intl.formatMessage(sectionNames.sales),
|
label: intl.formatMessage(sectionNames.sales),
|
||||||
id: "sales",
|
id: "sales",
|
||||||
url: saleListUrl(),
|
url: saleListUrl(),
|
||||||
|
type: "item",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ariaLabel: "vouchers",
|
|
||||||
label: intl.formatMessage(sectionNames.vouchers),
|
label: intl.formatMessage(sectionNames.vouchers),
|
||||||
id: "vouchers",
|
id: "vouchers",
|
||||||
url: voucherListUrl(),
|
url: voucherListUrl(),
|
||||||
|
type: "item",
|
||||||
},
|
},
|
||||||
...mapToExtensionsItems(
|
...mapToExtensionsItems(
|
||||||
extensions.NAVIGATION_DISCOUNTS,
|
extensions.NAVIGATION_DISCOUNTS,
|
||||||
appExtensionsHeaderItem,
|
appExtensionsHeaderItem,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
iconSrc: discountsIcon,
|
icon: <VouchersIcon {...iconSettings} />,
|
||||||
label: intl.formatMessage(commonMessages.discounts),
|
label: intl.formatMessage(commonMessages.discounts),
|
||||||
permissions: [PermissionEnum.MANAGE_DISCOUNTS],
|
permissions: [PermissionEnum.MANAGE_DISCOUNTS],
|
||||||
id: "discounts",
|
id: "discounts",
|
||||||
|
type: "itemGroup",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ariaLabel: "pages",
|
id: "divider-2",
|
||||||
children: extensions.NAVIGATION_PAGES.length > 0 && [
|
type: "divider",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
children: !isEmpty(extensions.NAVIGATION_PAGES) && [
|
||||||
{
|
{
|
||||||
ariaLabel: "pages",
|
|
||||||
label: intl.formatMessage(sectionNames.pages),
|
label: intl.formatMessage(sectionNames.pages),
|
||||||
permissions: [PermissionEnum.MANAGE_PAGES],
|
permissions: [PermissionEnum.MANAGE_PAGES],
|
||||||
id: "pages",
|
id: "pages",
|
||||||
url: pageListPath,
|
url: pageListPath,
|
||||||
|
type: "item",
|
||||||
},
|
},
|
||||||
...mapToExtensionsItems(
|
...mapToExtensionsItems(
|
||||||
extensions.NAVIGATION_PAGES,
|
extensions.NAVIGATION_PAGES,
|
||||||
appExtensionsHeaderItem,
|
appExtensionsHeaderItem,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
iconSrc: pagesIcon,
|
icon: <StorefrontIcon {...iconSettings} />,
|
||||||
label: intl.formatMessage(sectionNames.pages),
|
label: intl.formatMessage(sectionNames.pages),
|
||||||
permissions: [PermissionEnum.MANAGE_PAGES],
|
permissions: [PermissionEnum.MANAGE_PAGES],
|
||||||
id: "pages",
|
id: "pages",
|
||||||
url: pageListPath,
|
url: pageListPath,
|
||||||
|
type: !isEmpty(extensions.NAVIGATION_PAGES) ? "itemGroup" : "item",
|
||||||
},
|
},
|
||||||
getAppSection(),
|
getAppSection(),
|
||||||
{
|
{
|
||||||
ariaLabel: "translations",
|
children: !isEmpty(extensions.NAVIGATION_TRANSLATIONS) && [
|
||||||
children: extensions.NAVIGATION_TRANSLATIONS.length > 0 && [
|
|
||||||
{
|
{
|
||||||
ariaLabel: "translations",
|
|
||||||
label: intl.formatMessage(sectionNames.translations),
|
label: intl.formatMessage(sectionNames.translations),
|
||||||
permissions: [PermissionEnum.MANAGE_TRANSLATIONS],
|
permissions: [PermissionEnum.MANAGE_TRANSLATIONS],
|
||||||
id: "translations",
|
id: "translations",
|
||||||
url: languageListUrl,
|
url: languageListUrl,
|
||||||
|
type: "item",
|
||||||
},
|
},
|
||||||
...mapToExtensionsItems(
|
...mapToExtensionsItems(
|
||||||
extensions.NAVIGATION_TRANSLATIONS,
|
extensions.NAVIGATION_TRANSLATIONS,
|
||||||
appExtensionsHeaderItem,
|
appExtensionsHeaderItem,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
iconSrc: translationIcon,
|
icon: <TranslationsIcon {...iconSettings} />,
|
||||||
label: intl.formatMessage(sectionNames.translations),
|
label: intl.formatMessage(sectionNames.translations),
|
||||||
permissions: [PermissionEnum.MANAGE_TRANSLATIONS],
|
permissions: [PermissionEnum.MANAGE_TRANSLATIONS],
|
||||||
id: "translations",
|
id: "translations",
|
||||||
url: languageListUrl,
|
url: languageListUrl,
|
||||||
|
type: !isEmpty(extensions.NAVIGATION_TRANSLATIONS) ? "itemGroup" : "item",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ariaLabel: "configure",
|
id: "divider-3",
|
||||||
iconSrc: configurationIcon,
|
type: "divider",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: <ConfigurationIcon {...iconSettings} />,
|
||||||
label: intl.formatMessage(sectionNames.configuration),
|
label: intl.formatMessage(sectionNames.configuration),
|
||||||
permissions: getConfigMenuItemsPermissions(intl),
|
permissions: getConfigMenuItemsPermissions(intl),
|
||||||
id: "configure",
|
id: "configure",
|
||||||
url: configurationMenuUrl,
|
url: configurationMenuUrl,
|
||||||
|
type: "item",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const isMenuItemPermitted = (menuItem: FilterableMenuItem) => {
|
const isMenuItemPermitted = (menuItem: SidebarMenuItem) => {
|
||||||
const userPermissions = (user?.userPermissions || []).map(
|
const userPermissions = (user?.userPermissions || []).map(
|
||||||
permission => permission.code,
|
permission => permission.code,
|
||||||
);
|
);
|
||||||
|
@ -290,12 +300,11 @@ function useMenuStructure(
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getFilteredMenuItems = (menuItems: FilterableMenuItem[]) =>
|
const getFilteredMenuItems = (menuItems: SidebarMenuItem[]) =>
|
||||||
menuItems.filter(isMenuItemPermitted);
|
menuItems.filter(isMenuItemPermitted);
|
||||||
|
|
||||||
return [
|
return menuItems.reduce(
|
||||||
menuItems.reduce(
|
(resultItems: SidebarMenuItem[], menuItem: SidebarMenuItem) => {
|
||||||
(resultItems: FilterableMenuItem[], menuItem: FilterableMenuItem) => {
|
|
||||||
if (!isMenuItemPermitted(menuItem)) {
|
if (!isMenuItemPermitted(menuItem)) {
|
||||||
return resultItems;
|
return resultItems;
|
||||||
}
|
}
|
||||||
|
@ -306,10 +315,6 @@ function useMenuStructure(
|
||||||
|
|
||||||
return [...resultItems, { ...menuItem, children: filteredChildren }];
|
return [...resultItems, { ...menuItem, children: filteredChildren }];
|
||||||
},
|
},
|
||||||
[] as FilterableMenuItem[],
|
[],
|
||||||
),
|
);
|
||||||
handleMenuItemClick,
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default useMenuStructure;
|
|
|
@ -2,19 +2,31 @@ import { getDashboardUrFromAppCompleteUrl } from "@dashboard/apps/urls";
|
||||||
import { Extension } from "@dashboard/apps/useExtensions";
|
import { Extension } from "@dashboard/apps/useExtensions";
|
||||||
import { AppExtensionMountEnum } from "@dashboard/graphql";
|
import { AppExtensionMountEnum } from "@dashboard/graphql";
|
||||||
import { orderDraftListUrl, orderListUrl } from "@dashboard/orders/urls";
|
import { orderDraftListUrl, orderListUrl } from "@dashboard/orders/urls";
|
||||||
import { SidebarMenuItem } from "@saleor/macaw-ui";
|
|
||||||
import { matchPath } from "react-router";
|
import { matchPath } from "react-router";
|
||||||
|
|
||||||
import { FilterableMenuItem } from "./menuStructure";
|
import { SidebarMenuItem } from "./types";
|
||||||
|
|
||||||
|
export const mapToExtensionsItems = (
|
||||||
|
extensions: Extension[],
|
||||||
|
header: SidebarMenuItem,
|
||||||
|
) => {
|
||||||
|
const items: SidebarMenuItem[] = extensions.map(
|
||||||
|
({ label, id, app, url, permissions, open }) => ({
|
||||||
|
id: `extension-${id}`,
|
||||||
|
label,
|
||||||
|
url: getDashboardUrFromAppCompleteUrl(url, app.appUrl, app.id),
|
||||||
|
permissions,
|
||||||
|
onClick: open,
|
||||||
|
type: "item",
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
if (items.length) {
|
||||||
|
items.unshift(header);
|
||||||
|
}
|
||||||
|
return items;
|
||||||
|
};
|
||||||
|
|
||||||
export function isMenuActive(location: string, menuItem: SidebarMenuItem) {
|
export function isMenuActive(location: string, menuItem: SidebarMenuItem) {
|
||||||
if (menuItem.children) {
|
|
||||||
return menuItem.children.reduce(
|
|
||||||
(acc, subMenuItem) => acc || isMenuActive(location, subMenuItem),
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!menuItem.url) {
|
if (!menuItem.url) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -39,39 +51,19 @@ export function isMenuActive(location: string, menuItem: SidebarMenuItem) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export const mapToExtensionsItems = (
|
|
||||||
extensions: Extension[],
|
|
||||||
header: FilterableMenuItem,
|
|
||||||
) => {
|
|
||||||
const items: FilterableMenuItem[] = extensions.map(
|
|
||||||
({ label, id, app, url, permissions, open }) => ({
|
|
||||||
ariaLabel: `app-${label}`,
|
|
||||||
id: `extension-${id}`,
|
|
||||||
label,
|
|
||||||
url: getDashboardUrFromAppCompleteUrl(url, app.appUrl, app.id),
|
|
||||||
onClick: open,
|
|
||||||
permissions,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
if (items.length) {
|
|
||||||
items.unshift(header);
|
|
||||||
}
|
|
||||||
return items;
|
|
||||||
};
|
|
||||||
|
|
||||||
const isMenuItemExtension = (menuItem: SidebarMenuItem) =>
|
const isMenuItemExtension = (menuItem: SidebarMenuItem) =>
|
||||||
menuItem.id.startsWith("extension-");
|
menuItem.id.startsWith("extension-");
|
||||||
|
|
||||||
export const getMenuItemExtension = (
|
export const getMenuItemExtension = (
|
||||||
extensions: Record<AppExtensionMountEnum, Extension[]>,
|
extensions: Record<AppExtensionMountEnum, Extension[]>,
|
||||||
menuItem: SidebarMenuItem,
|
id: string,
|
||||||
) => {
|
) => {
|
||||||
const extensionsList = Object.values(extensions).reduce(
|
const extensionsList = Object.values(extensions).reduce(
|
||||||
(list, extensions) => list.concat(extensions),
|
(list, extensions) => list.concat(extensions),
|
||||||
[],
|
[],
|
||||||
);
|
);
|
||||||
const extension = extensionsList.find(
|
const extension = extensionsList.find(
|
||||||
extension => menuItem.id === `extension-${extension.id}`,
|
extension => id === `extension-${extension.id}`,
|
||||||
);
|
);
|
||||||
return extension;
|
return extension;
|
||||||
};
|
};
|
111
src/components/Sidebar/user/Controls.tsx
Normal file
111
src/components/Sidebar/user/Controls.tsx
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
import { useUser } from "@dashboard/auth";
|
||||||
|
import { isDarkTheme } from "@dashboard/misc";
|
||||||
|
import { staffMemberDetailsUrl } from "@dashboard/staff/urls";
|
||||||
|
import { useTheme } from "@dashboard/theme";
|
||||||
|
import { useTheme as useLegacyTheme } from "@saleor/macaw-ui";
|
||||||
|
import {
|
||||||
|
Box,
|
||||||
|
Button,
|
||||||
|
Dropdown,
|
||||||
|
List,
|
||||||
|
MoreOptionsIcon,
|
||||||
|
sprinkles,
|
||||||
|
Text,
|
||||||
|
} from "@saleor/macaw-ui/next";
|
||||||
|
import React from "react";
|
||||||
|
import { FormattedMessage } from "react-intl";
|
||||||
|
import { Link } from "react-router-dom";
|
||||||
|
|
||||||
|
import { ThemeSwitcher } from "./ThemeSwitcher";
|
||||||
|
|
||||||
|
export const UserControls = () => {
|
||||||
|
const { user, logout } = useUser();
|
||||||
|
const { theme, setTheme } = useTheme();
|
||||||
|
const { themeType: legacyThemeType, setTheme: setLegacyTheme } =
|
||||||
|
useLegacyTheme();
|
||||||
|
|
||||||
|
const handleClick = () => {
|
||||||
|
setLegacyTheme(isDarkTheme(legacyThemeType) ? "light" : "dark");
|
||||||
|
setTheme(theme === "defaultLight" ? "defaultDark" : "defaultLight");
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dropdown>
|
||||||
|
<Dropdown.Trigger>
|
||||||
|
<Button
|
||||||
|
variant="tertiary"
|
||||||
|
icon={<MoreOptionsIcon />}
|
||||||
|
data-test-id="userMenu"
|
||||||
|
size="medium"
|
||||||
|
/>
|
||||||
|
</Dropdown.Trigger>
|
||||||
|
<Dropdown.Content align="end">
|
||||||
|
<Box __minWidth={192}>
|
||||||
|
<List
|
||||||
|
padding={5}
|
||||||
|
borderRadius={4}
|
||||||
|
boxShadow="overlay"
|
||||||
|
backgroundColor="surfaceNeutralPlain"
|
||||||
|
>
|
||||||
|
<Dropdown.Item>
|
||||||
|
<List.Item
|
||||||
|
borderRadius={4}
|
||||||
|
data-test-id="account-settings-button"
|
||||||
|
>
|
||||||
|
<Link
|
||||||
|
to={staffMemberDetailsUrl(user?.id)}
|
||||||
|
className={sprinkles({
|
||||||
|
display: "block",
|
||||||
|
width: "100%",
|
||||||
|
...listItemStyles,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<Text>
|
||||||
|
<FormattedMessage
|
||||||
|
id="NQgbYA"
|
||||||
|
defaultMessage="Account Settings"
|
||||||
|
/>
|
||||||
|
</Text>
|
||||||
|
</Link>
|
||||||
|
</List.Item>
|
||||||
|
</Dropdown.Item>
|
||||||
|
<Dropdown.Item>
|
||||||
|
<List.Item
|
||||||
|
onClick={logout}
|
||||||
|
{...listItemStyles}
|
||||||
|
data-test-id="log-out-button"
|
||||||
|
>
|
||||||
|
<Text>
|
||||||
|
<FormattedMessage
|
||||||
|
id="qLbse5"
|
||||||
|
defaultMessage="Log out"
|
||||||
|
description="button"
|
||||||
|
/>
|
||||||
|
</Text>
|
||||||
|
</List.Item>
|
||||||
|
</Dropdown.Item>
|
||||||
|
<Dropdown.Item>
|
||||||
|
<List.Item
|
||||||
|
display="flex"
|
||||||
|
alignItems="center"
|
||||||
|
gap={5}
|
||||||
|
marginTop={3}
|
||||||
|
onClick={handleClick}
|
||||||
|
{...listItemStyles}
|
||||||
|
data-test-id="theme-switch"
|
||||||
|
>
|
||||||
|
<ThemeSwitcher theme={theme} />
|
||||||
|
</List.Item>
|
||||||
|
</Dropdown.Item>
|
||||||
|
</List>
|
||||||
|
</Box>
|
||||||
|
</Dropdown.Content>
|
||||||
|
</Dropdown>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const listItemStyles = {
|
||||||
|
paddingX: 4,
|
||||||
|
paddingY: 5,
|
||||||
|
borderRadius: 4,
|
||||||
|
} as const;
|
38
src/components/Sidebar/user/Info.tsx
Normal file
38
src/components/Sidebar/user/Info.tsx
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
import { useUser } from "@dashboard/auth";
|
||||||
|
import { getUserInitials, getUserName } from "@dashboard/misc";
|
||||||
|
import { Avatar, Box, Text } from "@saleor/macaw-ui/next";
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
import { UserControls } from "./Controls";
|
||||||
|
|
||||||
|
export const UserInfo = () => {
|
||||||
|
const { user } = useUser();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box
|
||||||
|
display="flex"
|
||||||
|
gap={6}
|
||||||
|
paddingX={6}
|
||||||
|
paddingY={7}
|
||||||
|
alignItems="center"
|
||||||
|
borderTopWidth={1}
|
||||||
|
borderColor="neutralPlain"
|
||||||
|
borderTopStyle="solid"
|
||||||
|
justifyContent="space-between"
|
||||||
|
>
|
||||||
|
<Box display="flex" gap={6} alignItems="center">
|
||||||
|
<Avatar.User
|
||||||
|
initials={getUserInitials(user)}
|
||||||
|
scheme="decorative2"
|
||||||
|
src={user?.avatar?.url}
|
||||||
|
/>
|
||||||
|
<Box __width={128} className="ellipsis">
|
||||||
|
<Text variant="bodyStrong" size="small">
|
||||||
|
{getUserName(user, true)}
|
||||||
|
</Text>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
<UserControls />
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
29
src/components/Sidebar/user/ThemeSwitcher.tsx
Normal file
29
src/components/Sidebar/user/ThemeSwitcher.tsx
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
import {
|
||||||
|
DarkModeIcon,
|
||||||
|
DefaultTheme,
|
||||||
|
LightModeIcon,
|
||||||
|
Text,
|
||||||
|
} from "@saleor/macaw-ui/next";
|
||||||
|
import React from "react";
|
||||||
|
import { FormattedMessage } from "react-intl";
|
||||||
|
|
||||||
|
export const ThemeSwitcher = ({ theme }: { theme: DefaultTheme }) => {
|
||||||
|
if (theme === "defaultLight") {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<DarkModeIcon color="iconNeutralSubdued" />
|
||||||
|
<Text>
|
||||||
|
<FormattedMessage id="5ObBlW" defaultMessage="Dark Mode" />
|
||||||
|
</Text>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<LightModeIcon color="iconNeutralSubdued" />
|
||||||
|
<Text>
|
||||||
|
<FormattedMessage id="hVPucN" defaultMessage="Light Mode" />
|
||||||
|
</Text>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
1
src/components/Sidebar/user/index.ts
Normal file
1
src/components/Sidebar/user/index.ts
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export * from "./Info";
|
|
@ -1,8 +1,10 @@
|
||||||
import { makeStyles } from "@saleor/macaw-ui";
|
import { makeStyles } from "@saleor/macaw-ui";
|
||||||
|
import clsx from "clsx";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
export interface TabContainerProps {
|
export interface TabContainerProps {
|
||||||
children: React.ReactNode | React.ReactNodeArray;
|
children: React.ReactNode | React.ReactNodeArray;
|
||||||
|
className?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const useStyles = makeStyles(
|
const useStyles = makeStyles(
|
||||||
|
@ -19,7 +21,7 @@ const TabContainer: React.FC<TabContainerProps> = props => {
|
||||||
|
|
||||||
const classes = useStyles(props);
|
const classes = useStyles(props);
|
||||||
|
|
||||||
return <div className={classes.root}>{children}</div>;
|
return <div className={clsx(classes.root, props.className)}>{children}</div>;
|
||||||
};
|
};
|
||||||
TabContainer.displayName = "TabContainer";
|
TabContainer.displayName = "TabContainer";
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { TableCell } from "@material-ui/core";
|
import { TableCell } from "@material-ui/core";
|
||||||
import { TableCellProps } from "@material-ui/core/TableCell";
|
import { TableCellProps } from "@material-ui/core/TableCell";
|
||||||
import { makeStyles } from "@saleor/macaw-ui";
|
import { makeStyles } from "@saleor/macaw-ui";
|
||||||
|
import { vars } from "@saleor/macaw-ui/next";
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
|
@ -10,6 +11,7 @@ const useStyles = makeStyles(
|
||||||
theme => ({
|
theme => ({
|
||||||
arrow: {
|
arrow: {
|
||||||
transition: theme.transitions.duration.short + "ms",
|
transition: theme.transitions.duration.short + "ms",
|
||||||
|
marginBottom: vars.space[3],
|
||||||
},
|
},
|
||||||
arrowLeft: {
|
arrowLeft: {
|
||||||
marginLeft: -24,
|
marginLeft: -24,
|
||||||
|
@ -33,7 +35,6 @@ const useStyles = makeStyles(
|
||||||
color: theme.palette.text.primary,
|
color: theme.palette.text.primary,
|
||||||
},
|
},
|
||||||
display: "flex",
|
display: "flex",
|
||||||
height: 24,
|
|
||||||
},
|
},
|
||||||
labelContainerActive: {
|
labelContainerActive: {
|
||||||
color: theme.palette.text.primary,
|
color: theme.palette.text.primary,
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { isExternalURL } from "@dashboard/utils/urls";
|
||||||
import { TableRow, TableRowTypeMap } from "@material-ui/core";
|
import { TableRow, TableRowTypeMap } from "@material-ui/core";
|
||||||
import { makeStyles } from "@saleor/macaw-ui";
|
import { makeStyles } from "@saleor/macaw-ui";
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import React from "react";
|
import React, { forwardRef } from "react";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
|
|
||||||
type MaterialTableRowPropsType = TableRowTypeMap["props"];
|
type MaterialTableRowPropsType = TableRowTypeMap["props"];
|
||||||
|
@ -25,31 +25,28 @@ const useStyles = makeStyles(
|
||||||
{ name: "TableRowLink" },
|
{ name: "TableRowLink" },
|
||||||
);
|
);
|
||||||
|
|
||||||
const TableRowLink = ({
|
const TableRowLink = forwardRef<HTMLTableRowElement, TableRowLinkProps>(
|
||||||
href,
|
(props, ref) => {
|
||||||
children,
|
const { href, children, linkClassName, onClick, ...restProps } = props;
|
||||||
linkClassName,
|
|
||||||
onClick,
|
|
||||||
...props
|
|
||||||
}: TableRowLinkProps) => {
|
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
|
|
||||||
if (!href || isExternalURL(href)) {
|
if (!href || isExternalURL(href)) {
|
||||||
return (
|
return (
|
||||||
<TableRow hover={!!onClick} onClick={onClick} {...props}>
|
<TableRow ref={ref} hover={!!onClick} onClick={onClick} {...restProps}>
|
||||||
{children}
|
{children}
|
||||||
</TableRow>
|
</TableRow>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TableRow hover={true} onClick={onClick} {...props}>
|
<TableRow ref={ref} hover={true} onClick={onClick} {...restProps}>
|
||||||
<Link className={clsx(classes.link, linkClassName)} to={href}>
|
<Link className={clsx(classes.link, linkClassName)} to={href}>
|
||||||
{children}
|
{children}
|
||||||
</Link>
|
</Link>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
);
|
);
|
||||||
};
|
},
|
||||||
|
);
|
||||||
|
|
||||||
TableRowLink.displayName = "TableRowLink";
|
TableRowLink.displayName = "TableRowLink";
|
||||||
export default TableRowLink;
|
export default TableRowLink;
|
||||||
|
|
|
@ -17,7 +17,6 @@ const useStyles = makeStyles(
|
||||||
marginRight: theme.spacing(3.5),
|
marginRight: theme.spacing(3.5),
|
||||||
},
|
},
|
||||||
button: {
|
button: {
|
||||||
zIndex: 2,
|
|
||||||
padding: `7px`,
|
padding: `7px`,
|
||||||
borderTopLeftRadius: 0,
|
borderTopLeftRadius: 0,
|
||||||
borderBottomLeftRadius: 0,
|
borderBottomLeftRadius: 0,
|
||||||
|
@ -33,15 +32,15 @@ const useStyles = makeStyles(
|
||||||
"&::placeholder": {
|
"&::placeholder": {
|
||||||
opacity: [[1], "!important"] as any,
|
opacity: [[1], "!important"] as any,
|
||||||
},
|
},
|
||||||
zIndex: 2,
|
|
||||||
},
|
},
|
||||||
background: theme.palette.background.paper,
|
background: theme.palette.background.paper,
|
||||||
},
|
},
|
||||||
noteRoot: {
|
noteRoot: {
|
||||||
left: theme.spacing(-8.5),
|
|
||||||
marginBottom: theme.spacing(3),
|
marginBottom: theme.spacing(3),
|
||||||
position: "relative",
|
position: "absolute",
|
||||||
width: `calc(100% + ${theme.spacing(8.5)})`,
|
top: 0,
|
||||||
|
left: -19,
|
||||||
|
right: 0,
|
||||||
},
|
},
|
||||||
noteTitle: {
|
noteTitle: {
|
||||||
"&:last-child": {
|
"&:last-child": {
|
||||||
|
@ -49,16 +48,14 @@ const useStyles = makeStyles(
|
||||||
paddingRight: 0,
|
paddingRight: 0,
|
||||||
},
|
},
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
background: theme.palette.background.default,
|
|
||||||
display: "flex",
|
display: "flex",
|
||||||
paddingLeft: theme.spacing(3),
|
paddingLeft: 0,
|
||||||
},
|
},
|
||||||
root: {
|
root: {
|
||||||
borderColor: theme.palette.divider,
|
|
||||||
borderStyle: "solid",
|
|
||||||
borderWidth: "0 0 0 2px",
|
|
||||||
marginLeft: 20,
|
marginLeft: 20,
|
||||||
paddingLeft: theme.spacing(3),
|
paddingTop: theme.spacing(12),
|
||||||
|
paddingLeft: theme.spacing(3.27),
|
||||||
|
position: "relative",
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
{ name: "Timeline" },
|
{ name: "Timeline" },
|
||||||
|
|
|
@ -1,15 +1,17 @@
|
||||||
|
import { Content } from "@dashboard/components/AppLayout/Content";
|
||||||
|
import { DetailedContent } from "@dashboard/components/AppLayout/DetailedContent";
|
||||||
|
import { TopNav } from "@dashboard/components/AppLayout/TopNav";
|
||||||
import { UserFragment } from "@dashboard/graphql";
|
import { UserFragment } from "@dashboard/graphql";
|
||||||
import { sectionNames } from "@dashboard/intl";
|
import { sectionNames } from "@dashboard/intl";
|
||||||
import { Typography } from "@material-ui/core";
|
import { Typography } from "@material-ui/core";
|
||||||
import { useTheme } from "@material-ui/core/styles";
|
import { useTheme } from "@material-ui/core/styles";
|
||||||
import useMediaQuery from "@material-ui/core/useMediaQuery";
|
import useMediaQuery from "@material-ui/core/useMediaQuery";
|
||||||
import { makeStyles, NavigationCard } from "@saleor/macaw-ui";
|
import { makeStyles, NavigationCard } from "@saleor/macaw-ui";
|
||||||
|
import { Box, vars } from "@saleor/macaw-ui/next";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useIntl } from "react-intl";
|
import { useIntl } from "react-intl";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
|
|
||||||
import Container from "../components/Container";
|
|
||||||
import PageHeader from "../components/PageHeader";
|
|
||||||
import VersionInfo from "../components/VersionInfo";
|
import VersionInfo from "../components/VersionInfo";
|
||||||
import { MenuSection } from "./types";
|
import { MenuSection } from "./types";
|
||||||
import { hasUserMenuItemPermissions } from "./utils";
|
import { hasUserMenuItemPermissions } from "./utils";
|
||||||
|
@ -25,7 +27,6 @@ const useStyles = makeStyles(
|
||||||
[theme.breakpoints.down("md")]: {
|
[theme.breakpoints.down("md")]: {
|
||||||
gridTemplateColumns: "1fr",
|
gridTemplateColumns: "1fr",
|
||||||
},
|
},
|
||||||
borderTop: `solid 1px ${theme.palette.divider}`,
|
|
||||||
display: "grid",
|
display: "grid",
|
||||||
gap: theme.spacing(4),
|
gap: theme.spacing(4),
|
||||||
gridTemplateColumns: "1fr 3fr",
|
gridTemplateColumns: "1fr 3fr",
|
||||||
|
@ -33,9 +34,6 @@ const useStyles = makeStyles(
|
||||||
},
|
},
|
||||||
|
|
||||||
configurationItem: {
|
configurationItem: {
|
||||||
[theme.breakpoints.down("md")]: {
|
|
||||||
gridTemplateColumns: "1fr",
|
|
||||||
},
|
|
||||||
display: "grid",
|
display: "grid",
|
||||||
gap: theme.spacing(4),
|
gap: theme.spacing(4),
|
||||||
gridTemplateColumns: "1fr 1fr",
|
gridTemplateColumns: "1fr 1fr",
|
||||||
|
@ -59,6 +57,14 @@ const useStyles = makeStyles(
|
||||||
fontSize: 20,
|
fontSize: 20,
|
||||||
fontWeight: 600 as 600,
|
fontWeight: 600 as 600,
|
||||||
},
|
},
|
||||||
|
navigationCard: {
|
||||||
|
border: `1px solid ${vars.colors.border.neutralDefault}`,
|
||||||
|
height: 130,
|
||||||
|
boxShadow: "none !important",
|
||||||
|
"& .MuiCardContent-root": {
|
||||||
|
borderRadius: vars.borderRadius[3],
|
||||||
|
},
|
||||||
|
},
|
||||||
}),
|
}),
|
||||||
{ name: "ConfigurationPage" },
|
{ name: "ConfigurationPage" },
|
||||||
);
|
);
|
||||||
|
@ -89,11 +95,12 @@ export const ConfigurationPage: React.FC<ConfigurationPageProps> = props => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container>
|
<DetailedContent useSingleColumn>
|
||||||
{!isSmUp && renderVersionInfo}
|
<TopNav title={intl.formatMessage(sectionNames.configuration)}>
|
||||||
<PageHeader title={intl.formatMessage(sectionNames.configuration)}>
|
|
||||||
{isSmUp && renderVersionInfo}
|
{isSmUp && renderVersionInfo}
|
||||||
</PageHeader>
|
</TopNav>
|
||||||
|
<Content>
|
||||||
|
<Box paddingX={9} __maxWidth={"1024px"} margin="auto">
|
||||||
{menus
|
{menus
|
||||||
.filter(menu =>
|
.filter(menu =>
|
||||||
menu.menuItems.some(menuItem =>
|
menu.menuItems.some(menuItem =>
|
||||||
|
@ -107,10 +114,13 @@ export const ConfigurationPage: React.FC<ConfigurationPageProps> = props => {
|
||||||
</div>
|
</div>
|
||||||
<div className={classes.configurationItem}>
|
<div className={classes.configurationItem}>
|
||||||
{menu.menuItems
|
{menu.menuItems
|
||||||
.filter(menuItem => hasUserMenuItemPermissions(menuItem, user))
|
.filter(menuItem =>
|
||||||
|
hasUserMenuItemPermissions(menuItem, user),
|
||||||
|
)
|
||||||
.map((item, itemIndex) => (
|
.map((item, itemIndex) => (
|
||||||
<Link className={classes.link} to={item.url}>
|
<Link className={classes.link} to={item.url}>
|
||||||
<NavigationCard
|
<NavigationCard
|
||||||
|
className={classes.navigationCard}
|
||||||
key={itemIndex}
|
key={itemIndex}
|
||||||
icon={item.icon}
|
icon={item.icon}
|
||||||
title={item.title}
|
title={item.title}
|
||||||
|
@ -126,7 +136,9 @@ export const ConfigurationPage: React.FC<ConfigurationPageProps> = props => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</Container>
|
</Box>
|
||||||
|
</Content>
|
||||||
|
</DetailedContent>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
ConfigurationPage.displayName = "ConfigurationPage";
|
ConfigurationPage.displayName = "ConfigurationPage";
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import AccountPermissions from "@dashboard/components/AccountPermissions";
|
import AccountPermissions from "@dashboard/components/AccountPermissions";
|
||||||
import { Backlink } from "@dashboard/components/Backlink";
|
import { Content } from "@dashboard/components/AppLayout/Content";
|
||||||
import Container from "@dashboard/components/Container";
|
import { DetailedContent } from "@dashboard/components/AppLayout/DetailedContent";
|
||||||
|
import { RightSidebar } from "@dashboard/components/AppLayout/RightSidebar";
|
||||||
|
import { TopNav } from "@dashboard/components/AppLayout/TopNav";
|
||||||
import Form from "@dashboard/components/Form";
|
import Form from "@dashboard/components/Form";
|
||||||
import Grid from "@dashboard/components/Grid";
|
|
||||||
import PageHeader from "@dashboard/components/PageHeader";
|
|
||||||
import Savebar from "@dashboard/components/Savebar";
|
import Savebar from "@dashboard/components/Savebar";
|
||||||
import { CustomAppUrls } from "@dashboard/custom-apps/urls";
|
import { CustomAppUrls } from "@dashboard/custom-apps/urls";
|
||||||
import {
|
import {
|
||||||
|
@ -13,7 +13,6 @@ import {
|
||||||
} from "@dashboard/graphql";
|
} from "@dashboard/graphql";
|
||||||
import { SubmitPromise } from "@dashboard/hooks/useForm";
|
import { SubmitPromise } from "@dashboard/hooks/useForm";
|
||||||
import useNavigator from "@dashboard/hooks/useNavigator";
|
import useNavigator from "@dashboard/hooks/useNavigator";
|
||||||
import { sectionNames } from "@dashboard/intl";
|
|
||||||
import { getFormErrors } from "@dashboard/utils/errors";
|
import { getFormErrors } from "@dashboard/utils/errors";
|
||||||
import getAppErrorMessage from "@dashboard/utils/errors/app";
|
import getAppErrorMessage from "@dashboard/utils/errors/app";
|
||||||
import { ConfirmButtonTransitionState } from "@saleor/macaw-ui";
|
import { ConfirmButtonTransitionState } from "@saleor/macaw-ui";
|
||||||
|
@ -59,26 +58,24 @@ const CustomAppCreatePage: React.FC<CustomAppCreatePageProps> = props => {
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
>
|
>
|
||||||
{({ data, change, submit, isSaveDisabled }) => (
|
{({ data, change, submit, isSaveDisabled }) => (
|
||||||
<Container>
|
<DetailedContent>
|
||||||
<Backlink href={CustomAppUrls.resolveAppListUrl()}>
|
<TopNav
|
||||||
{intl.formatMessage(sectionNames.apps)}
|
href={CustomAppUrls.resolveAppListUrl()}
|
||||||
</Backlink>
|
|
||||||
<PageHeader
|
|
||||||
title={intl.formatMessage({
|
title={intl.formatMessage({
|
||||||
id: "GjH9uy",
|
id: "GjH9uy",
|
||||||
defaultMessage: "Create New App",
|
defaultMessage: "Create New App",
|
||||||
description: "header",
|
description: "header",
|
||||||
})}
|
})}
|
||||||
/>
|
></TopNav>
|
||||||
<Grid>
|
<Content>
|
||||||
<div>
|
|
||||||
<CustomAppInformation
|
<CustomAppInformation
|
||||||
data={data}
|
data={data}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
errors={errors}
|
errors={errors}
|
||||||
onChange={change}
|
onChange={change}
|
||||||
/>
|
/>
|
||||||
</div>
|
</Content>
|
||||||
|
<RightSidebar>
|
||||||
<AccountPermissions
|
<AccountPermissions
|
||||||
data={data}
|
data={data}
|
||||||
errorMessage={permissionsError}
|
errorMessage={permissionsError}
|
||||||
|
@ -98,14 +95,14 @@ const CustomAppCreatePage: React.FC<CustomAppCreatePageProps> = props => {
|
||||||
description: "card description",
|
description: "card description",
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</RightSidebar>
|
||||||
<Savebar
|
<Savebar
|
||||||
disabled={isSaveDisabled}
|
disabled={isSaveDisabled}
|
||||||
state={saveButtonBarState}
|
state={saveButtonBarState}
|
||||||
onCancel={() => navigate(CustomAppUrls.resolveAppListUrl())}
|
onCancel={() => navigate(CustomAppUrls.resolveAppListUrl())}
|
||||||
onSubmit={submit}
|
onSubmit={submit}
|
||||||
/>
|
/>
|
||||||
</Container>
|
</DetailedContent>
|
||||||
)}
|
)}
|
||||||
</Form>
|
</Form>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import AccountPermissions from "@dashboard/components/AccountPermissions";
|
import AccountPermissions from "@dashboard/components/AccountPermissions";
|
||||||
import { Backlink } from "@dashboard/components/Backlink";
|
import { Content } from "@dashboard/components/AppLayout/Content";
|
||||||
|
import { DetailedContent } from "@dashboard/components/AppLayout/DetailedContent";
|
||||||
|
import { RightSidebar } from "@dashboard/components/AppLayout/RightSidebar";
|
||||||
|
import { TopNav } from "@dashboard/components/AppLayout/TopNav";
|
||||||
import CardSpacer from "@dashboard/components/CardSpacer";
|
import CardSpacer from "@dashboard/components/CardSpacer";
|
||||||
import Container from "@dashboard/components/Container";
|
|
||||||
import Form from "@dashboard/components/Form";
|
import Form from "@dashboard/components/Form";
|
||||||
import Grid from "@dashboard/components/Grid";
|
|
||||||
import PageHeader from "@dashboard/components/PageHeader";
|
|
||||||
import Savebar from "@dashboard/components/Savebar";
|
import Savebar from "@dashboard/components/Savebar";
|
||||||
import WebhooksList from "@dashboard/custom-apps/components/WebhooksList";
|
import WebhooksList from "@dashboard/custom-apps/components/WebhooksList";
|
||||||
import { CustomAppUrls } from "@dashboard/custom-apps/urls";
|
import { CustomAppUrls } from "@dashboard/custom-apps/urls";
|
||||||
|
@ -16,11 +16,11 @@ import {
|
||||||
} from "@dashboard/graphql";
|
} from "@dashboard/graphql";
|
||||||
import { SubmitPromise } from "@dashboard/hooks/useForm";
|
import { SubmitPromise } from "@dashboard/hooks/useForm";
|
||||||
import useNavigator from "@dashboard/hooks/useNavigator";
|
import useNavigator from "@dashboard/hooks/useNavigator";
|
||||||
import { sectionNames } from "@dashboard/intl";
|
|
||||||
import { getFormErrors } from "@dashboard/utils/errors";
|
import { getFormErrors } from "@dashboard/utils/errors";
|
||||||
import getAppErrorMessage from "@dashboard/utils/errors/app";
|
import getAppErrorMessage from "@dashboard/utils/errors/app";
|
||||||
import { Button, ConfirmButtonTransitionState } from "@saleor/macaw-ui";
|
import { Button, ConfirmButtonTransitionState } from "@saleor/macaw-ui";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
import SVG from "react-inlinesvg";
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
|
|
||||||
import activateIcon from "../../../../assets/images/activate-icon.svg";
|
import activateIcon from "../../../../assets/images/activate-icon.svg";
|
||||||
|
@ -104,18 +104,15 @@ const CustomAppDetailsPage: React.FC<CustomAppDetailsPageProps> = props => {
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
>
|
>
|
||||||
{({ data, change, submit, isSaveDisabled }) => (
|
{({ data, change, submit, isSaveDisabled }) => (
|
||||||
<Container>
|
<DetailedContent>
|
||||||
<Backlink href={CustomAppUrls.resolveAppListUrl()}>
|
<TopNav href={CustomAppUrls.resolveAppListUrl()} title={app?.name}>
|
||||||
{intl.formatMessage(sectionNames.apps)}
|
|
||||||
</Backlink>
|
|
||||||
<PageHeader title={app?.name}>
|
|
||||||
<Button
|
<Button
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
className={classes.activateButton}
|
className={classes.activateButton}
|
||||||
disableFocusRipple
|
disableFocusRipple
|
||||||
onClick={data.isActive ? onAppDeactivateOpen : onAppActivateOpen}
|
onClick={data.isActive ? onAppDeactivateOpen : onAppActivateOpen}
|
||||||
>
|
>
|
||||||
<img src={activateIcon} alt="" />
|
<SVG src={activateIcon} />
|
||||||
{data?.isActive ? (
|
{data?.isActive ? (
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id="whTEcF"
|
id="whTEcF"
|
||||||
|
@ -130,9 +127,8 @@ const CustomAppDetailsPage: React.FC<CustomAppDetailsPageProps> = props => {
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Button>
|
</Button>
|
||||||
</PageHeader>
|
</TopNav>
|
||||||
<Grid>
|
<Content>
|
||||||
<div>
|
|
||||||
{token && (
|
{token && (
|
||||||
<>
|
<>
|
||||||
<CustomAppDefaultToken
|
<CustomAppDefaultToken
|
||||||
|
@ -162,8 +158,8 @@ const CustomAppDetailsPage: React.FC<CustomAppDetailsPageProps> = props => {
|
||||||
onRemove={onWebhookRemove}
|
onRemove={onWebhookRemove}
|
||||||
createHref={app?.isActive && webhookCreateHref}
|
createHref={app?.isActive && webhookCreateHref}
|
||||||
/>
|
/>
|
||||||
</div>
|
</Content>
|
||||||
<div>
|
<RightSidebar>
|
||||||
<AccountPermissions
|
<AccountPermissions
|
||||||
data={data}
|
data={data}
|
||||||
errorMessage={permissionsError}
|
errorMessage={permissionsError}
|
||||||
|
@ -183,15 +179,14 @@ const CustomAppDetailsPage: React.FC<CustomAppDetailsPageProps> = props => {
|
||||||
description: "card description",
|
description: "card description",
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
</div>
|
</RightSidebar>
|
||||||
</Grid>
|
|
||||||
<Savebar
|
<Savebar
|
||||||
disabled={isSaveDisabled}
|
disabled={isSaveDisabled}
|
||||||
state={saveButtonBarState}
|
state={saveButtonBarState}
|
||||||
onCancel={() => navigate(CustomAppUrls.resolveAppListUrl())}
|
onCancel={() => navigate(CustomAppUrls.resolveAppListUrl())}
|
||||||
onSubmit={submit}
|
onSubmit={submit}
|
||||||
/>
|
/>
|
||||||
</Container>
|
</DetailedContent>
|
||||||
)}
|
)}
|
||||||
</Form>
|
</Form>
|
||||||
);
|
);
|
||||||
|
|
|
@ -4,9 +4,19 @@ import { FormChange } from "@dashboard/hooks/useForm";
|
||||||
import { getFormErrors } from "@dashboard/utils/errors";
|
import { getFormErrors } from "@dashboard/utils/errors";
|
||||||
import getAppErrorMessage from "@dashboard/utils/errors/app";
|
import getAppErrorMessage from "@dashboard/utils/errors/app";
|
||||||
import { Card, CardContent, TextField } from "@material-ui/core";
|
import { Card, CardContent, TextField } from "@material-ui/core";
|
||||||
|
import { makeStyles } from "@saleor/macaw-ui";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useIntl } from "react-intl";
|
import { useIntl } from "react-intl";
|
||||||
|
|
||||||
|
const useStyles = makeStyles(
|
||||||
|
{
|
||||||
|
cardTitle: {
|
||||||
|
paddingRight: 16,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ name: "AccountPermissions" },
|
||||||
|
);
|
||||||
|
|
||||||
export interface CustomAppInfoProps {
|
export interface CustomAppInfoProps {
|
||||||
data: {
|
data: {
|
||||||
name: string;
|
name: string;
|
||||||
|
@ -23,12 +33,14 @@ const CustomAppInformation: React.FC<CustomAppInfoProps> = ({
|
||||||
onChange,
|
onChange,
|
||||||
}) => {
|
}) => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
const classes = useStyles();
|
||||||
|
|
||||||
const formErrors = getFormErrors(["name"], errors);
|
const formErrors = getFormErrors(["name"], errors);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card>
|
<Card>
|
||||||
<CardTitle
|
<CardTitle
|
||||||
|
className={classes.cardTitle}
|
||||||
title={intl.formatMessage({
|
title={intl.formatMessage({
|
||||||
id: "imYxM9",
|
id: "imYxM9",
|
||||||
defaultMessage: "App Information",
|
defaultMessage: "App Information",
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
|
import { Content } from "@dashboard/components/AppLayout/Content";
|
||||||
|
import { TopNav } from "@dashboard/components/AppLayout/TopNav";
|
||||||
import { Button } from "@dashboard/components/Button";
|
import { Button } from "@dashboard/components/Button";
|
||||||
import CardTitle from "@dashboard/components/CardTitle";
|
|
||||||
import Container from "@dashboard/components/Container";
|
|
||||||
import PageHeader from "@dashboard/components/PageHeader";
|
|
||||||
import { TableButtonWrapper } from "@dashboard/components/TableButtonWrapper/TableButtonWrapper";
|
import { TableButtonWrapper } from "@dashboard/components/TableButtonWrapper/TableButtonWrapper";
|
||||||
import TableRowLink from "@dashboard/components/TableRowLink";
|
import TableRowLink from "@dashboard/components/TableRowLink";
|
||||||
import { CustomAppUrls } from "@dashboard/custom-apps/urls";
|
import { CustomAppUrls } from "@dashboard/custom-apps/urls";
|
||||||
import { AppListItemFragment } from "@dashboard/graphql";
|
import { AppListItemFragment } from "@dashboard/graphql";
|
||||||
import { commonMessages, sectionNames } from "@dashboard/intl";
|
import { sectionNames } from "@dashboard/intl";
|
||||||
import { renderCollection } from "@dashboard/misc";
|
import { renderCollection } from "@dashboard/misc";
|
||||||
import { Card, TableBody, TableCell, Typography } from "@material-ui/core";
|
import { TableBody, TableCell, Typography } from "@material-ui/core";
|
||||||
import { DeleteIcon, IconButton, ResponsiveTable } from "@saleor/macaw-ui";
|
import { DeleteIcon, IconButton, ResponsiveTable } from "@saleor/macaw-ui";
|
||||||
|
import { Box, Text } 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";
|
||||||
|
|
||||||
|
@ -32,18 +32,8 @@ const CustomAppListPage: React.FC<CustomAppListPageProps> = ({
|
||||||
const classes = useStyles({});
|
const classes = useStyles({});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container>
|
<>
|
||||||
<PageHeader title={intl.formatMessage(sectionNames.webhooksAndEvents)} />
|
<TopNav title={intl.formatMessage(sectionNames.webhooksAndEvents)}>
|
||||||
<p>
|
|
||||||
<FormattedMessage
|
|
||||||
defaultMessage="Local apps are custom webhooks & token pairs that can be used to
|
|
||||||
connect apps and access Saleor API."
|
|
||||||
id="L/sNGY"
|
|
||||||
/>
|
|
||||||
</p>
|
|
||||||
<Card className={classes.customApps}>
|
|
||||||
<CardTitle
|
|
||||||
toolbar={
|
|
||||||
<Button
|
<Button
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
href={CustomAppUrls.appAddUrl}
|
href={CustomAppUrls.appAddUrl}
|
||||||
|
@ -55,9 +45,19 @@ const CustomAppListPage: React.FC<CustomAppListPageProps> = ({
|
||||||
description="create app button"
|
description="create app button"
|
||||||
/>
|
/>
|
||||||
</Button>
|
</Button>
|
||||||
}
|
</TopNav>
|
||||||
title={intl.formatMessage(commonMessages.customApps)}
|
<Content>
|
||||||
|
<Box padding={9}>
|
||||||
|
<Box marginBottom={4}>
|
||||||
|
<Text as="p">
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage="Local apps are custom webhooks & token pairs that can be used to
|
||||||
|
connect apps and access Saleor API."
|
||||||
|
id="L/sNGY"
|
||||||
/>
|
/>
|
||||||
|
</Text>
|
||||||
|
</Box>
|
||||||
|
|
||||||
<ResponsiveTable>
|
<ResponsiveTable>
|
||||||
<TableBody>
|
<TableBody>
|
||||||
{renderCollection(
|
{renderCollection(
|
||||||
|
@ -110,8 +110,9 @@ const CustomAppListPage: React.FC<CustomAppListPageProps> = ({
|
||||||
)}
|
)}
|
||||||
</TableBody>
|
</TableBody>
|
||||||
</ResponsiveTable>
|
</ResponsiveTable>
|
||||||
</Card>
|
</Box>
|
||||||
</Container>
|
</Content>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,13 @@ import Skeleton from "@dashboard/components/Skeleton";
|
||||||
import TableRowLink from "@dashboard/components/TableRowLink";
|
import TableRowLink from "@dashboard/components/TableRowLink";
|
||||||
import { AppUpdateMutation } from "@dashboard/graphql";
|
import { AppUpdateMutation } from "@dashboard/graphql";
|
||||||
import { renderCollection } from "@dashboard/misc";
|
import { renderCollection } from "@dashboard/misc";
|
||||||
import { Card, TableBody, TableCell, TableHead } from "@material-ui/core";
|
import {
|
||||||
|
Card,
|
||||||
|
CardContent,
|
||||||
|
TableBody,
|
||||||
|
TableCell,
|
||||||
|
TableHead,
|
||||||
|
} from "@material-ui/core";
|
||||||
import { DeleteIcon, IconButton } from "@saleor/macaw-ui";
|
import { DeleteIcon, IconButton } from "@saleor/macaw-ui";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
|
@ -33,6 +39,7 @@ const CustomAppTokens: React.FC<CustomAppTokensProps> = props => {
|
||||||
defaultMessage: "Tokens",
|
defaultMessage: "Tokens",
|
||||||
description: "header",
|
description: "header",
|
||||||
})}
|
})}
|
||||||
|
className={classes.cardTitle}
|
||||||
toolbar={
|
toolbar={
|
||||||
<Button
|
<Button
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
|
@ -47,6 +54,7 @@ const CustomAppTokens: React.FC<CustomAppTokensProps> = props => {
|
||||||
</Button>
|
</Button>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
<CardContent>
|
||||||
<ResponsiveTable>
|
<ResponsiveTable>
|
||||||
<TableHead>
|
<TableHead>
|
||||||
<TableRowLink>
|
<TableRowLink>
|
||||||
|
@ -78,7 +86,11 @@ const CustomAppTokens: React.FC<CustomAppTokensProps> = props => {
|
||||||
{token?.name || <Skeleton />}
|
{token?.name || <Skeleton />}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell className={classes.colKey}>
|
<TableCell className={classes.colKey}>
|
||||||
{token?.authToken ? `**** ${token.authToken}` : <Skeleton />}
|
{token?.authToken ? (
|
||||||
|
`**** ${token.authToken}`
|
||||||
|
) : (
|
||||||
|
<Skeleton />
|
||||||
|
)}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell className={classes.colActions}>
|
<TableCell className={classes.colActions}>
|
||||||
<IconButton
|
<IconButton
|
||||||
|
@ -104,6 +116,7 @@ const CustomAppTokens: React.FC<CustomAppTokensProps> = props => {
|
||||||
)}
|
)}
|
||||||
</TableBody>
|
</TableBody>
|
||||||
</ResponsiveTable>
|
</ResponsiveTable>
|
||||||
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -69,7 +69,7 @@ const TokenCreateDialog: React.FC<TokenCreateDialogProps> = props => {
|
||||||
<Form initial={{ name: "" }} onSubmit={data => onCreate(data.name)}>
|
<Form initial={{ name: "" }} onSubmit={data => onCreate(data.name)}>
|
||||||
{({ change, data, submit }) => (
|
{({ change, data, submit }) => (
|
||||||
<>
|
<>
|
||||||
<DialogTitle>
|
<DialogTitle disableTypography>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id="T5nU7u"
|
id="T5nU7u"
|
||||||
defaultMessage="Create Token"
|
defaultMessage="Create Token"
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import { Backlink } from "@dashboard/components/Backlink";
|
import { Content } from "@dashboard/components/AppLayout/Content";
|
||||||
import Container from "@dashboard/components/Container";
|
import { DetailedContent } from "@dashboard/components/AppLayout/DetailedContent";
|
||||||
|
import { TopNav } from "@dashboard/components/AppLayout/TopNav";
|
||||||
import Form from "@dashboard/components/Form";
|
import Form from "@dashboard/components/Form";
|
||||||
import FormSpacer from "@dashboard/components/FormSpacer";
|
import FormSpacer from "@dashboard/components/FormSpacer";
|
||||||
import PageHeader from "@dashboard/components/PageHeader";
|
|
||||||
import Savebar from "@dashboard/components/Savebar";
|
import Savebar from "@dashboard/components/Savebar";
|
||||||
import WebhookEvents from "@dashboard/custom-apps/components/WebhookEvents";
|
import WebhookEvents from "@dashboard/custom-apps/components/WebhookEvents";
|
||||||
import WebhookInfo from "@dashboard/custom-apps/components/WebhookInfo";
|
import WebhookInfo from "@dashboard/custom-apps/components/WebhookInfo";
|
||||||
|
@ -21,11 +21,12 @@ import {
|
||||||
import { SubmitPromise } from "@dashboard/hooks/useForm";
|
import { SubmitPromise } from "@dashboard/hooks/useForm";
|
||||||
import useNavigator from "@dashboard/hooks/useNavigator";
|
import useNavigator from "@dashboard/hooks/useNavigator";
|
||||||
import { ConfirmButtonTransitionState } from "@saleor/macaw-ui";
|
import { ConfirmButtonTransitionState } from "@saleor/macaw-ui";
|
||||||
|
import { Box } from "@saleor/macaw-ui/next";
|
||||||
import { parse, print } from "graphql";
|
import { parse, print } from "graphql";
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { useIntl } from "react-intl";
|
import { useIntl } from "react-intl";
|
||||||
|
|
||||||
import WebhookSubscriptionQuery from "../WebhookSubscriptionQuery/WebhookSubscriptionQuery";
|
import WebhookSubscriptionQuery from "../WebhookSubscriptionQuery";
|
||||||
import { getHeaderTitle } from "./messages";
|
import { getHeaderTitle } from "./messages";
|
||||||
|
|
||||||
export interface WebhookFormData {
|
export interface WebhookFormData {
|
||||||
|
@ -50,7 +51,6 @@ export interface WebhookDetailsPageProps {
|
||||||
|
|
||||||
const WebhookDetailsPage: React.FC<WebhookDetailsPageProps> = ({
|
const WebhookDetailsPage: React.FC<WebhookDetailsPageProps> = ({
|
||||||
appId,
|
appId,
|
||||||
appName,
|
|
||||||
disabled,
|
disabled,
|
||||||
errors,
|
errors,
|
||||||
webhook,
|
webhook,
|
||||||
|
@ -105,15 +105,15 @@ const WebhookDetailsPage: React.FC<WebhookDetailsPageProps> = ({
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container>
|
<DetailedContent useSingleColumn>
|
||||||
<Backlink href={backUrl}>{appName}</Backlink>
|
<TopNav href={backUrl} title={getHeaderTitle(intl, webhook)} />
|
||||||
<PageHeader title={getHeaderTitle(intl, webhook)}>
|
<Content>
|
||||||
|
<Box paddingX={9}>
|
||||||
<WebhookStatus
|
<WebhookStatus
|
||||||
data={data.isActive}
|
data={data.isActive}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
onChange={change}
|
onChange={change}
|
||||||
/>
|
/>
|
||||||
</PageHeader>
|
|
||||||
<WebhookInfo
|
<WebhookInfo
|
||||||
data={data}
|
data={data}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
|
@ -126,19 +126,20 @@ const WebhookDetailsPage: React.FC<WebhookDetailsPageProps> = ({
|
||||||
onSyncEventChange={handleSyncEventsSelect}
|
onSyncEventChange={handleSyncEventsSelect}
|
||||||
onAsyncEventChange={handleAsyncEventsSelect}
|
onAsyncEventChange={handleAsyncEventsSelect}
|
||||||
/>
|
/>
|
||||||
<FormSpacer />
|
|
||||||
<WebhookSubscriptionQuery
|
<WebhookSubscriptionQuery
|
||||||
query={query}
|
query={query}
|
||||||
setQuery={setQuery}
|
setQuery={setQuery}
|
||||||
data={data}
|
data={data}
|
||||||
/>
|
/>
|
||||||
|
</Box>
|
||||||
|
</Content>
|
||||||
<Savebar
|
<Savebar
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
state={saveButtonBarState}
|
state={saveButtonBarState}
|
||||||
onCancel={() => navigate(backUrl)}
|
onCancel={() => navigate(backUrl)}
|
||||||
onSubmit={submit}
|
onSubmit={submit}
|
||||||
/>
|
/>
|
||||||
</Container>
|
</DetailedContent>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
</Form>
|
</Form>
|
||||||
|
|
|
@ -72,7 +72,7 @@ const WebhookEvents: React.FC<WebhookEventsProps> = ({
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Card>
|
<Card>
|
||||||
<CardContent>
|
<CardContent className={classes.card}>
|
||||||
<PageTabs value={tab} onChange={handleTabChange}>
|
<PageTabs value={tab} onChange={handleTabChange}>
|
||||||
<PageTab
|
<PageTab
|
||||||
label={intl.formatMessage(messages.asynchronous)}
|
label={intl.formatMessage(messages.asynchronous)}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { makeStyles } from "@saleor/macaw-ui";
|
import { makeStyles } from "@saleor/macaw-ui";
|
||||||
|
import { vars } from "@saleor/macaw-ui/next";
|
||||||
|
|
||||||
export const useStyles = makeStyles(
|
export const useStyles = makeStyles(
|
||||||
theme => ({
|
theme => ({
|
||||||
|
@ -8,7 +9,7 @@ export const useStyles = makeStyles(
|
||||||
},
|
},
|
||||||
objectsWrapper: {
|
objectsWrapper: {
|
||||||
borderRight: "1px solid",
|
borderRight: "1px solid",
|
||||||
borderRightColor: theme.palette.divider,
|
borderRightColor: vars.colors.border.neutralPlain,
|
||||||
padding: theme.spacing(3),
|
padding: theme.spacing(3),
|
||||||
},
|
},
|
||||||
listHeader: {
|
listHeader: {
|
||||||
|
@ -18,7 +19,7 @@ export const useStyles = makeStyles(
|
||||||
},
|
},
|
||||||
listBody: {
|
listBody: {
|
||||||
height: 300,
|
height: 300,
|
||||||
overflow: "scroll",
|
overflowY: "auto",
|
||||||
},
|
},
|
||||||
listItem: {
|
listItem: {
|
||||||
minHeight: 0,
|
minHeight: 0,
|
||||||
|
@ -32,6 +33,9 @@ export const useStyles = makeStyles(
|
||||||
checkbox: {
|
checkbox: {
|
||||||
padding: 0,
|
padding: 0,
|
||||||
},
|
},
|
||||||
|
card: {
|
||||||
|
paddingLeft: 0,
|
||||||
|
},
|
||||||
}),
|
}),
|
||||||
{ name: "WebhookEvents" },
|
{ name: "WebhookEvents" },
|
||||||
);
|
);
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue