diff --git a/CHANGELOG.md b/CHANGELOG.md index 9ec62614f..562113134 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -48,3 +48,4 @@ All notable, unreleased changes to this project will be documented in this file. - Add readonly mode - #229 by @dominik-zeglen - Add mailing configuration - #222 by @dominik-zeglen - Fix minor bugs - #230 by @dominik-zeglen +- Fix permission handling - #231 by @dominik-zeglen diff --git a/locale/messages.pot b/locale/messages.pot index 7814d1e13..61dbc4569 100644 --- a/locale/messages.pot +++ b/locale/messages.pot @@ -1,6 +1,6 @@ msgid "" msgstr "" -"POT-Creation-Date: 2019-10-24T13:17:27.157Z\n" +"POT-Creation-Date: 2019-10-25T13:36:05.943Z\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "MIME-Version: 1.0\n" @@ -9667,14 +9667,6 @@ msgctxt "button" msgid "{languageName} - {languageCode}" msgstr "" -#: build/locale/src/translations/components/TranslationFields/TranslationFields.json -#. [src.translations.components.TranslationFields.282734765] -#. defaultMessage is: -#. {numberOFields} Translations, {numberOfTranslatedFields} Completed -msgctxt "description" -msgid "{numberOFields} Translations, {numberOfTranslatedFields} Completed" -msgstr "" - #: build/locale/src/components/SeoForm/SeoForm.json #. [src.components.SeoForm.3877274856] - character limit #. defaultMessage is: @@ -9683,6 +9675,14 @@ msgctxt "character limit" msgid "{numberOfCharacters} of {maxCharacters} characters" msgstr "" +#: build/locale/src/translations/components/TranslationFields/TranslationFields.json +#. [src.translations.components.TranslationFields.1308081812] +#. defaultMessage is: +#. {numberOfFields} Translations, {numberOfTranslatedFields} Completed +msgctxt "description" +msgid "{numberOfFields} Translations, {numberOfTranslatedFields} Completed" +msgstr "" + #: build/locale/src/components/ColumnPicker/ColumnPickerContent.json #. [src.components.ColumnPicker.2715399461] - pick columns to display #. defaultMessage is: diff --git a/src/auth/mutations.ts b/src/auth/mutations.ts index 6791e4b0d..5138d6c2f 100644 --- a/src/auth/mutations.ts +++ b/src/auth/mutations.ts @@ -15,8 +15,6 @@ export const fragmentUser = gql` email firstName lastName - isStaff - note permissions { code name diff --git a/src/auth/types/SetPassword.ts b/src/auth/types/SetPassword.ts index 708560696..9a4c04509 100644 --- a/src/auth/types/SetPassword.ts +++ b/src/auth/types/SetPassword.ts @@ -31,8 +31,6 @@ export interface SetPassword_setPassword_user { email: string; firstName: string; lastName: string; - isStaff: boolean; - note: string | null; permissions: (SetPassword_setPassword_user_permissions | null)[] | null; avatar: SetPassword_setPassword_user_avatar | null; } diff --git a/src/auth/types/TokenAuth.ts b/src/auth/types/TokenAuth.ts index 3cae7fada..fa49d6998 100644 --- a/src/auth/types/TokenAuth.ts +++ b/src/auth/types/TokenAuth.ts @@ -31,8 +31,6 @@ export interface TokenAuth_tokenCreate_user { email: string; firstName: string; lastName: string; - isStaff: boolean; - note: string | null; permissions: (TokenAuth_tokenCreate_user_permissions | null)[] | null; avatar: TokenAuth_tokenCreate_user_avatar | null; } diff --git a/src/auth/types/User.ts b/src/auth/types/User.ts index 6609b9897..60ddc5c9c 100644 --- a/src/auth/types/User.ts +++ b/src/auth/types/User.ts @@ -25,8 +25,6 @@ export interface User { email: string; firstName: string; lastName: string; - isStaff: boolean; - note: string | null; permissions: (User_permissions | null)[] | null; avatar: User_avatar | null; } diff --git a/src/auth/types/VerifyToken.ts b/src/auth/types/VerifyToken.ts index 10e83496e..9daf9abf7 100644 --- a/src/auth/types/VerifyToken.ts +++ b/src/auth/types/VerifyToken.ts @@ -25,8 +25,6 @@ export interface VerifyToken_tokenVerify_user { email: string; firstName: string; lastName: string; - isStaff: boolean; - note: string | null; permissions: (VerifyToken_tokenVerify_user_permissions | null)[] | null; avatar: VerifyToken_tokenVerify_user_avatar | null; } diff --git a/src/components/AppLayout/AppLayout.tsx b/src/components/AppLayout/AppLayout.tsx index b8c7f7193..a379b5350 100644 --- a/src/components/AppLayout/AppLayout.tsx +++ b/src/components/AppLayout/AppLayout.tsx @@ -24,11 +24,13 @@ import saleorDarkLogoSmall from "@assets/images/logo-dark-small.svg"; import saleorDarkLogo from "@assets/images/logo-dark.svg"; import menuArrowIcon from "@assets/images/menu-arrow-icon.svg"; import AppProgressProvider from "@saleor/components/AppProgress"; +import { createConfigurationMenu } from "@saleor/configuration"; import useLocalStorage from "@saleor/hooks/useLocalStorage"; import useNavigator from "@saleor/hooks/useNavigator"; import useTheme from "@saleor/hooks/useTheme"; import useUser from "@saleor/hooks/useUser"; import ArrowDropdown from "@saleor/icons/ArrowDropdown"; +import { maybe } from "@saleor/misc"; import { staffMemberDetailsUrl } from "@saleor/staff/urls"; import Container from "../Container"; import AppActionContext from "./AppActionContext"; @@ -297,6 +299,17 @@ const AppLayout = withStyles(styles, { const intl = useIntl(); const menuStructure = createMenuStructure(intl); + const configurationMenu = createConfigurationMenu(intl); + const userPermissions = maybe(() => user.permissions, []); + + const renderConfigure = configurationMenu.some(section => + section.menuItems.some( + menuItem => + !!userPermissions.find( + userPermission => userPermission.code === menuItem.permission + ) + ) + ); const handleLogout = () => { setMenuState(false); @@ -365,7 +378,7 @@ const AppLayout = withStyles(styles, { isMenuSmall={!isMenuSmall} location={location.pathname} user={user} - renderConfigure={true} + renderConfigure={renderConfigure} onMenuItemClick={handleMenuItemClick} /> diff --git a/src/components/RequirePermissions.tsx b/src/components/RequirePermissions.tsx new file mode 100644 index 000000000..176ec0076 --- /dev/null +++ b/src/components/RequirePermissions.tsx @@ -0,0 +1,31 @@ +import React from "react"; + +import { User_permissions } from "@saleor/auth/types/User"; +import { PermissionEnum } from "@saleor/types/globalTypes"; + +export function hasPermissions( + userPermissions: User_permissions[], + requiredPermissions: PermissionEnum[] +): boolean { + return requiredPermissions.reduce( + (acc, perm) => + acc && !!userPermissions.find(userPerm => userPerm.code === perm), + true + ); +} + +export interface RequirePermissionsProps { + children: React.ReactNode | React.ReactNodeArray; + requiredPermissions: PermissionEnum[]; + userPermissions: User_permissions[]; +} + +const RequirePermissions: React.FC = ({ + children, + requiredPermissions, + userPermissions +}) => + hasPermissions(userPermissions, requiredPermissions) ? <>{children} : null; + +RequirePermissions.displayName = "RequirePermissions"; +export default RequirePermissions; diff --git a/src/configuration/ConfigurationPage.tsx b/src/configuration/ConfigurationPage.tsx index afbc61155..62c2beeaa 100644 --- a/src/configuration/ConfigurationPage.tsx +++ b/src/configuration/ConfigurationPage.tsx @@ -99,7 +99,7 @@ export const ConfigurationPage = withStyles(styles, { })( ({ classes, - menu, + menu: menus, user, onSectionClick }: ConfigurationPageProps & WithStyles) => { @@ -110,9 +110,11 @@ export const ConfigurationPage = withStyles(styles, { className={classes.header} title={intl.formatMessage(sectionNames.configuration)} /> - {menu + {menus .filter(menu => - menu.menuItems.map(item => hasPermission(item.permission, user)) + menu.menuItems.some(menuItem => + hasPermission(menuItem.permission, user) + ) ) .map((menu, menuIndex) => (
@@ -120,28 +122,30 @@ export const ConfigurationPage = withStyles(styles, { {menu.label}
- {menu.menuItems.map((item, itemIndex) => ( - onSectionClick(item.url)} - key={itemIndex} - > - -
{item.icon}
-
- - {item.title} - - - {item.description} - -
-
-
- ))} + {menu.menuItems + .filter(menuItem => hasPermission(menuItem.permission, user)) + .map((item, itemIndex) => ( + onSectionClick(item.url)} + key={itemIndex} + > + +
{item.icon}
+
+ + {item.title} + + + {item.description} + +
+
+
+ ))}
))} diff --git a/src/configuration/index.tsx b/src/configuration/index.tsx index 1ca93d41a..2eb77c4ba 100644 --- a/src/configuration/index.tsx +++ b/src/configuration/index.tsx @@ -81,7 +81,7 @@ export function createConfigurationMenu(intl: IntlShape): MenuSection[] { id: "configurationMenuTaxes" }), icon: , - permission: PermissionEnum.MANAGE_PRODUCTS, + permission: PermissionEnum.MANAGE_SETTINGS, title: intl.formatMessage(sectionNames.taxes), url: taxSection } @@ -151,7 +151,7 @@ export function createConfigurationMenu(intl: IntlShape): MenuSection[] { preserveAspectRatio="xMinYMin meet" /> ), - permission: PermissionEnum.MANAGE_SETTINGS, + permission: PermissionEnum.MANAGE_PLUGINS, title: intl.formatMessage(sectionNames.plugins), url: pluginsListUrl() }, diff --git a/src/fixtures.ts b/src/fixtures.ts index 9c3394411..77e9e4264 100644 --- a/src/fixtures.ts +++ b/src/fixtures.ts @@ -430,6 +430,18 @@ export const permissions: ShopInfo_shop_permissions[] = [ { code: PermissionEnum.MANAGE_USERS, name: "Manage customers." + }, + { + code: PermissionEnum.MANAGE_PLUGINS, + name: "Manage plugins." + }, + { + code: PermissionEnum.MANAGE_SERVICE_ACCOUNTS, + name: "Manage service accounts." + }, + { + code: PermissionEnum.MANAGE_WEBHOOKS, + name: "Manage webhooks." } ].map(perm => ({ __typename: "PermissionDisplay" as "PermissionDisplay", diff --git a/src/home/components/HomeNotificationTable/HomeNotificationTable.tsx b/src/home/components/HomeNotificationTable/HomeNotificationTable.tsx index f87dc12c7..2e66422b4 100644 --- a/src/home/components/HomeNotificationTable/HomeNotificationTable.tsx +++ b/src/home/components/HomeNotificationTable/HomeNotificationTable.tsx @@ -14,7 +14,10 @@ import KeyboardArrowRight from "@material-ui/icons/KeyboardArrowRight"; import React from "react"; import { FormattedMessage } from "react-intl"; +import RequirePermissions from "@saleor/components/RequirePermissions"; import Skeleton from "@saleor/components/Skeleton"; +import { UserPermissionProps } from "@saleor/types"; +import { PermissionEnum } from "@saleor/types/globalTypes"; const styles = (theme: Theme) => createStyles({ @@ -26,7 +29,7 @@ const styles = (theme: Theme) => } }); -interface HomeNotificationTableProps extends WithStyles { +interface HomeNotificationTableProps extends UserPermissionProps { ordersToCapture: number; ordersToFulfill: number; productsOutOfStock: number; @@ -45,101 +48,112 @@ const HomeNotificationTable = withStyles(styles, { onProductsOutOfStockClick, ordersToCapture, ordersToFulfill, - productsOutOfStock - }: HomeNotificationTableProps) => ( + productsOutOfStock, + userPermissions + }: HomeNotificationTableProps & WithStyles) => ( - - - {ordersToFulfill === undefined ? ( - - ) : ordersToFulfill === 0 ? ( - - - - ) : ( - - + + ) : ( + + {ordersToFulfill} - }} - /> - - )} - - - - - - - - {ordersToCapture === undefined ? ( - - ) : ordersToCapture === 0 ? ( - - - - ) : ( - - {ordersToFulfill} + }} + /> + + )} + + + + + + + + {ordersToCapture === undefined ? ( + + ) : ordersToCapture === 0 ? ( + + + + ) : ( + + {ordersToCapture} - }} - /> - - )} - - - - - - - - {productsOutOfStock === undefined ? ( - - ) : productsOutOfStock === 0 ? ( - - - - ) : ( - - {ordersToCapture} + }} + /> + + )} + + + + + + + + + + {productsOutOfStock === undefined ? ( + + ) : productsOutOfStock === 0 ? ( + + + + ) : ( + + {productsOutOfStock} - }} - /> - - )} - - - - - + id="homeNotificationTableProducts" + values={{ + amount: {productsOutOfStock} + }} + /> + + )} + + + + + +
diff --git a/src/home/components/HomePage/HomePage.tsx b/src/home/components/HomePage/HomePage.tsx index 4a34bf0ab..12c1368ab 100644 --- a/src/home/components/HomePage/HomePage.tsx +++ b/src/home/components/HomePage/HomePage.tsx @@ -10,7 +10,10 @@ import CardSpacer from "@saleor/components/CardSpacer"; import Container from "@saleor/components/Container"; import Grid from "@saleor/components/Grid"; import Money from "@saleor/components/Money"; +import RequirePermissions from "@saleor/components/RequirePermissions"; import Skeleton from "@saleor/components/Skeleton"; +import { UserPermissionProps } from "@saleor/types"; +import { PermissionEnum } from "@saleor/types/globalTypes"; import Orders from "../../../icons/Orders"; import Sales from "../../../icons/Sales"; import { @@ -39,7 +42,7 @@ const styles = (theme: Theme) => } }); -export interface HomePageProps extends WithStyles { +export interface HomePageProps extends UserPermissionProps { activities: Home_activities_edges_node[]; orders: number; ordersToCapture: number; @@ -68,35 +71,41 @@ const HomePage = withStyles(styles, { name: "HomePage" })( onProductsOutOfStockClick, ordersToCapture, ordersToFulfill, - productsOutOfStock - }: HomePageProps) => ( + productsOutOfStock, + userPermissions + }: HomePageProps & WithStyles) => (
-
- } - > - {sales ? ( - - ) : ( - - )} - - } - > - {orders === undefined ? ( - - ) : ( - orders - )} - -
+ +
+ } + > + {sales ? ( + + ) : ( + + )} + + } + > + {orders === undefined ? ( + + ) : ( + orders + )} + +
+
- - + + + +
- + + +
diff --git a/src/home/views/index.tsx b/src/home/views/index.tsx index 63bba5deb..8e6aaa1f8 100644 --- a/src/home/views/index.tsx +++ b/src/home/views/index.tsx @@ -56,6 +56,7 @@ const HomeSection = () => { ordersToFulfill={maybe(() => data.ordersToFulfill.totalCount)} productsOutOfStock={maybe(() => data.productsOutOfStock.totalCount)} userName={getUserName(user, true)} + userPermissions={maybe(() => user.permissions, [])} /> )} diff --git a/src/orders/components/OrderCustomer/OrderCustomer.tsx b/src/orders/components/OrderCustomer/OrderCustomer.tsx index ab07c3220..8b3677557 100644 --- a/src/orders/components/OrderCustomer/OrderCustomer.tsx +++ b/src/orders/components/OrderCustomer/OrderCustomer.tsx @@ -16,11 +16,13 @@ import ExternalLink from "@saleor/components/ExternalLink"; import Form from "@saleor/components/Form"; import Hr from "@saleor/components/Hr"; import Link from "@saleor/components/Link"; +import RequirePermissions from "@saleor/components/RequirePermissions"; import SingleAutocompleteSelectField from "@saleor/components/SingleAutocompleteSelectField"; import Skeleton from "@saleor/components/Skeleton"; import useStateFromProps from "@saleor/hooks/useStateFromProps"; import { buttonMessages } from "@saleor/intl"; -import { FetchMoreProps } from "@saleor/types"; +import { FetchMoreProps, UserPermissionProps } from "@saleor/types"; +import { PermissionEnum } from "@saleor/types/globalTypes"; import createSingleAutocompleteSelectHandler from "@saleor/utils/handlers/singleAutocompleteSelectChangeHandler"; import { SearchCustomers_search_edges_node } from "../../../containers/SearchCustomers/types/SearchCustomers"; import { customerUrl } from "../../../customers/urls"; @@ -49,7 +51,9 @@ const styles = (theme: Theme) => } }); -export interface OrderCustomerProps extends Partial { +export interface OrderCustomerProps + extends Partial, + UserPermissionProps { order: OrderDetails_order; users?: SearchCustomers_search_edges_node[]; loading?: boolean; @@ -72,6 +76,7 @@ const OrderCustomer = withStyles(styles, { name: "OrderCustomer" })( loading, order, users, + userPermissions, onCustomerEdit, onBillingAddressEdit, onFetchMore: onFetchMoreUsers, @@ -81,6 +86,7 @@ const OrderCustomer = withStyles(styles, { name: "OrderCustomer" })( const intl = useIntl(); const user = maybe(() => order.user); + const userEmail = maybe(()=>order.userEmail) const [userDisplayName, setUserDisplayName] = useStateFromProps( maybe(() => user.email, "") @@ -100,14 +106,19 @@ const OrderCustomer = withStyles(styles, { name: "OrderCustomer" })( })} toolbar={ !!canEditCustomer && ( - + + ) } /> @@ -155,26 +166,35 @@ const OrderCustomer = withStyles(styles, { name: "OrderCustomer" })( }} ) : user === null ? ( - - - + userEmail === null ? ( + + + + ) : ( + {userEmail} + ) ) : ( <> {user.email} -
- - - -
+ +
+ + + +
+
{/* TODO: Uncomment it after adding ability to filter orders by customer */} {/*
@@ -187,36 +207,40 @@ const OrderCustomer = withStyles(styles, { name: "OrderCustomer" })( )} -
- -
- - - -
+ {!!user && ( + <> +
+ +
+ + + +
- {maybe(() => order.userEmail) === undefined ? ( - - ) : order.userEmail === null ? ( - - - - ) : ( - order.userEmail)}`} - typographyProps={{ color: "primary" }} - > - {maybe(() => order.userEmail)} - - )} -
+ {maybe(() => order.userEmail) === undefined ? ( + + ) : order.userEmail === null ? ( + + + + ) : ( + order.userEmail)}`} + typographyProps={{ color: "primary" }} + > + {maybe(() => order.userEmail)} + + )} +
+ + )}
diff --git a/src/orders/components/OrderDetailsPage/OrderDetailsPage.tsx b/src/orders/components/OrderDetailsPage/OrderDetailsPage.tsx index 8e2b332bd..871ca148e 100644 --- a/src/orders/components/OrderDetailsPage/OrderDetailsPage.tsx +++ b/src/orders/components/OrderDetailsPage/OrderDetailsPage.tsx @@ -17,6 +17,7 @@ import Grid from "@saleor/components/Grid"; import PageHeader from "@saleor/components/PageHeader"; import Skeleton from "@saleor/components/Skeleton"; import { sectionNames } from "@saleor/intl"; +import { UserPermissionProps } from "@saleor/types"; import { maybe, renderCollection } from "../../../misc"; import { OrderStatus } from "../../../types/globalTypes"; import { OrderDetails_order } from "../../types/OrderDetails"; @@ -38,7 +39,7 @@ const styles = (theme: Theme) => } }); -export interface OrderDetailsPageProps extends WithStyles { +export interface OrderDetailsPageProps extends UserPermissionProps { order: OrderDetails_order; shippingMethods?: Array<{ id: string; @@ -68,12 +69,13 @@ const OrderDetailsPage = withStyles(styles, { name: "OrderDetailsPage" })( ({ classes, order, - onOrderCancel, + userPermissions, onBack, onBillingAddressEdit, onFulfillmentCancel, onFulfillmentTrackingNumberUpdate, onNoteAdd, + onOrderCancel, onOrderFulfill, onPaymentCapture, onPaymentPaid, @@ -81,7 +83,7 @@ const OrderDetailsPage = withStyles(styles, { name: "OrderDetailsPage" })( onPaymentVoid, onShippingAddressEdit, onProfileView - }: OrderDetailsPageProps) => { + }: OrderDetailsPageProps & WithStyles) => { const intl = useIntl(); const canCancel = maybe(() => order.status) !== OrderStatus.CANCELED; @@ -170,6 +172,7 @@ const OrderDetailsPage = withStyles(styles, { name: "OrderDetailsPage" })( canEditAddresses={canEditAddresses} canEditCustomer={false} order={order} + userPermissions={userPermissions} onBillingAddressEdit={onBillingAddressEdit} onShippingAddressEdit={onShippingAddressEdit} onProfileView={onProfileView} diff --git a/src/orders/components/OrderDraftPage/OrderDraftPage.tsx b/src/orders/components/OrderDraftPage/OrderDraftPage.tsx index 92518ea54..e32a241ed 100644 --- a/src/orders/components/OrderDraftPage/OrderDraftPage.tsx +++ b/src/orders/components/OrderDraftPage/OrderDraftPage.tsx @@ -18,7 +18,7 @@ import PageHeader from "@saleor/components/PageHeader"; import SaveButtonBar from "@saleor/components/SaveButtonBar"; import Skeleton from "@saleor/components/Skeleton"; import { sectionNames } from "@saleor/intl"; -import { FetchMoreProps } from "@saleor/types"; +import { FetchMoreProps, UserPermissionProps } from "@saleor/types"; import { SearchCustomers_search_edges_node } from "../../../containers/SearchCustomers/types/SearchCustomers"; import { maybe } from "../../../misc"; import { DraftOrderInput } from "../../../types/globalTypes"; @@ -39,7 +39,9 @@ const styles = (theme: Theme) => } }); -export interface OrderDraftPageProps extends FetchMoreProps { +export interface OrderDraftPageProps + extends FetchMoreProps, + UserPermissionProps { disabled: boolean; order: OrderDetails_order; users: SearchCustomers_search_edges_node[]; @@ -90,7 +92,8 @@ const OrderDraftPage = withStyles(styles, { name: "OrderDraftPage" })( onProfileView, order, users, - usersLoading + usersLoading, + userPermissions }: OrderDraftPageProps & WithStyles) => { const intl = useIntl(); @@ -147,6 +150,7 @@ const OrderDraftPage = withStyles(styles, { name: "OrderDraftPage" })( loading={usersLoading} order={order} users={users} + userPermissions={userPermissions} onBillingAddressEdit={onBillingAddressEdit} onCustomerEdit={onCustomerEdit} onFetchMore={onFetchMore} diff --git a/src/orders/views/OrderDetails/index.tsx b/src/orders/views/OrderDetails/index.tsx index a33c405d4..051368fb9 100644 --- a/src/orders/views/OrderDetails/index.tsx +++ b/src/orders/views/OrderDetails/index.tsx @@ -2,6 +2,7 @@ import React from "react"; import { WindowTitle } from "@saleor/components/WindowTitle"; import useNavigator from "@saleor/hooks/useNavigator"; +import useUser from "@saleor/hooks/useUser"; import { DEFAULT_INITIAL_SEARCH_DATA } from "../../../config"; import SearchCustomers from "../../../containers/SearchCustomers"; import { customerUrl } from "../../../customers/urls"; @@ -80,6 +81,7 @@ export const OrderDetails: React.StatelessComponent = ({ params }) => { const navigate = useNavigator(); + const { user } = useUser(); return ( = ({ () => data.order.availableShippingMethods, [] )} + userPermissions={maybe( + () => user.permissions, + [] + )} onOrderCancel={() => openModal("cancel")} onOrderFulfill={() => openModal("fulfill")} onFulfillmentCancel={fulfillmentId => @@ -466,6 +472,10 @@ export const OrderDetails: React.StatelessComponent = ({ onProfileView={() => navigate(customerUrl(order.user.id)) } + userPermissions={maybe( + () => user.permissions, + [] + )} /> { loadMore: ( @@ -81,12 +81,21 @@ export function TypedQuery( variables={variables} skip={skip} context={{ useBatching: true }} + errorPolicy="all" > {(queryData: QueryResult) => { if (queryData.error) { - pushMessage({ - text: intl.formatMessage(commonMessages.somethingWentWrong) - }); + if ( + !queryData.error.graphQLErrors.every( + err => + maybe(() => err.extensions.exception.code) === + "PermissionDenied" + ) + ) { + pushMessage({ + text: intl.formatMessage(commonMessages.somethingWentWrong) + }); + } } const loadMore = ( diff --git a/src/shipping/components/ShippingZonesListPage/ShippingZonesListPage.tsx b/src/shipping/components/ShippingZonesListPage/ShippingZonesListPage.tsx index 49dc9c600..06a3c84f8 100644 --- a/src/shipping/components/ShippingZonesListPage/ShippingZonesListPage.tsx +++ b/src/shipping/components/ShippingZonesListPage/ShippingZonesListPage.tsx @@ -5,14 +5,18 @@ import AppHeader from "@saleor/components/AppHeader"; import Container from "@saleor/components/Container"; import Grid from "@saleor/components/Grid"; import PageHeader from "@saleor/components/PageHeader"; +import RequirePermissions from "@saleor/components/RequirePermissions"; import { sectionNames } from "@saleor/intl"; -import { ListActions, PageListProps } from "@saleor/types"; -import { WeightUnitsEnum } from "@saleor/types/globalTypes"; +import { ListActions, PageListProps, UserPermissionProps } from "@saleor/types"; +import { PermissionEnum, WeightUnitsEnum } from "@saleor/types/globalTypes"; import { ShippingZoneFragment } from "../../types/ShippingZoneFragment"; import ShippingWeightUnitForm from "../ShippingWeightUnitForm"; import ShippingZonesList from "../ShippingZonesList"; -export interface ShippingZonesListPageProps extends PageListProps, ListActions { +export interface ShippingZonesListPageProps + extends PageListProps, + ListActions, + UserPermissionProps { defaultWeightUnit: WeightUnitsEnum; shippingZones: ShippingZoneFragment[]; onBack: () => void; @@ -22,7 +26,14 @@ export interface ShippingZonesListPageProps extends PageListProps, ListActions { const ShippingZonesListPage: React.StatelessComponent< ShippingZonesListPageProps -> = ({ defaultWeightUnit, disabled, onBack, onSubmit, ...listProps }) => { +> = ({ + defaultWeightUnit, + disabled, + userPermissions, + onBack, + onSubmit, + ...listProps +}) => { const intl = useIntl(); return ( @@ -41,11 +52,16 @@ const ShippingZonesListPage: React.StatelessComponent<
- + + +
diff --git a/src/shipping/views/ShippingZonesList.tsx b/src/shipping/views/ShippingZonesList.tsx index d15a80b0e..f4076dc9d 100644 --- a/src/shipping/views/ShippingZonesList.tsx +++ b/src/shipping/views/ShippingZonesList.tsx @@ -14,6 +14,7 @@ import usePaginator, { createPaginationState } from "@saleor/hooks/usePaginator"; import useShop from "@saleor/hooks/useShop"; +import useUser from "@saleor/hooks/useUser"; import { commonMessages } from "@saleor/intl"; import { getMutationState, maybe } from "@saleor/misc"; import { ListViews } from "@saleor/types"; @@ -45,6 +46,7 @@ export const ShippingZonesList: React.StatelessComponent< const notify = useNotifier(); const paginate = usePaginator(); const shop = useShop(); + const { user } = useUser(); const { isSelected, listElements, reset, toggle, toggleAll } = useBulkActions( params.ids ); @@ -195,6 +197,7 @@ export const ShippingZonesList: React.StatelessComponent< } + userPermissions={maybe(() => user.permissions, [])} /> ({ - __typename: "PermissionDisplay" as "PermissionDisplay", - ...perm - })) + permissions }; diff --git a/src/storybook/__snapshots__/Stories.test.ts.snap b/src/storybook/__snapshots__/Stories.test.ts.snap index d3f3bcc56..391c45ee5 100644 --- a/src/storybook/__snapshots__/Stories.test.ts.snap +++ b/src/storybook/__snapshots__/Stories.test.ts.snap @@ -7067,40 +7067,14 @@ exports[`Storyshots Orders / OrderCustomer default 1`] = ` class="MuiCardContent-root-id" >

- Anonymous user + melissa.simon@example.com


-
-
-

- Contact Information -

-
- -

- melissa.simon@example.com -

-
-
-
@@ -7205,40 +7179,14 @@ exports[`Storyshots Orders / OrderCustomer editable 1`] = ` class="MuiCardContent-root-id" >

- Anonymous user + melissa.simon@example.com


-
-
-

- Contact Information -

-
- -

- melissa.simon@example.com -

-
-
-
@@ -7381,27 +7329,6 @@ exports[`Storyshots Orders / OrderCustomer loading 1`] = `
-
-
-

- Contact Information -

-
- - ‌ - -
-
@@ -7445,6 +7372,105 @@ exports[`Storyshots Orders / OrderCustomer loading 1`] = `
`; +exports[`Storyshots Orders / OrderCustomer no user permissions 1`] = ` +
+
+
+ + Customer + +
+
+
+
+
+

+ melissa.simon@example.com +

+
+
+
+
+

+ Shipping Address +

+
+

+ Melissa Simon +

+

+ 487 Roberto Shores +
+

+

+ 66272 West Patriciastad +

+

+ Wyspy Salomona +

+

+

+
+
+
+

+ Billing Address +

+
+

+ Same as shipping address +

+
+
+
+`; + exports[`Storyshots Orders / OrderCustomer with different addresses 1`] = `

- Anonymous user + melissa.simon@example.com


-
-
-

- Contact Information -

-
- -

- melissa.simon@example.com -

-
-
-
@@ -29357,154 +29357,6 @@ exports[`Storyshots Views / Configuration partial access 1`] = `
-
-
-

- Product Settings -

-
-
-
-
-
- -
-
-

- Shipping Methods -

-

- Manage how you ship out orders -

-
-
-
-
-
-
- -
-
-

- Taxes -

-

- Manage how your store charges tax -

-
-
-
-
-
-
-
-

- Staff Settings -

-
-
-
-
-
- -
-
-

- Staff Members -

-

- Manage your employees and their permissions -

-
-
-
-
-
@@ -29558,44 +29410,6 @@ exports[`Storyshots Views / Configuration partial access 1`] = `
-
-
-
- -
-
-

- Site Settings -

-

- View and update your site settings -

-
-
-
@@ -29634,123 +29448,6 @@ exports[`Storyshots Views / Configuration partial access 1`] = `
-
-
-
- -
-
-

- Plugins -

-

- View and update your plugins and their settings. -

-
-
-
-
-
-
- -
-
-

- Service Accounts -

-

- Manage external integrations accounts -

-
-
-
-
-
-
- -
-
-

- Webhooks -

-

- View and update your webhook and their settings -

-
-
-
@@ -51796,6 +51493,686 @@ exports[`Storyshots Views / HomePage no data 1`] = ` `; +exports[`Storyshots Views / HomePage no permissions 1`] = ` +
+
+
+

+ Hello there, admin@example.com +

+

+ Here is some information we gathered about your store +

+
+
+
+
+
+ + +
+
+
+
+
+
+
+
+`; + +exports[`Storyshots Views / HomePage order permissions 1`] = ` +
+
+
+

+ Hello there, admin@example.com +

+

+ Here is some information we gathered about your store +

+
+
+
+
+
+
+
+
+
+ Sales +
+ + Today + +

+ $57.15 +

+
+
+ +
+
+
+
+
+
+
+ Orders +
+ + Today + +

+ 1 +

+
+
+ +
+
+
+
+
+ + + + + + + + + + + +
+

+ + 1 + + Orders are ready to fulfill +

+
+ +
+

+ No payments waiting for capture +

+
+ +
+
+
+
+
+
+
+ + Activity + +
+
+
+
+
    +
  • +
    +

    + Order #15 was placed from draft by admin@example.com +

    +

    + +

    +
    +
  • +
  • +
    +

    + Order #15 was placed +

    +

    + +

    +
    +
  • +
  • +
    +

    + Order #15 was fully paid +

    +

    + +

    +
    +
  • +
  • +
    +

    + Order #15 was placed from draft by admin@example.com +

    +

    + +

    +
    +
  • +
  • +
    +

    + Order #15 was placed from draft by admin@example.com +

    +

    + +

    +
    +
  • +
  • +
    +

    + Order #15 was placed from draft by admin@example.com +

    +

    + +

    +
    +
  • +
  • +
    +

    + Order #15 was placed from draft by admin@example.com +

    +

    + +

    +
    +
  • +
  • +
    +

    + Order #15 was placed +

    +

    + +

    +
    +
  • +
  • +
    +

    + Order #15 was placed from draft by admin@example.com +

    +

    + +

    +
    +
  • +
  • +
    +

    + Order #15 was placed +

    +

    + +

    +
    +
  • +
  • +
    +

    + Order #15 was placed +

    +

    + +

    +
    +
  • +
  • +
    +

    + Order #15 was fully paid +

    +

    + +

    +
    +
  • +
  • +
    +

    + Order #15 was fully paid +

    +

    + +

    +
    +
  • +
+
+
+
+
+
+`; + +exports[`Storyshots Views / HomePage product permissions 1`] = ` +
+
+
+

+ Hello there, admin@example.com +

+

+ Here is some information we gathered about your store +

+
+
+
+
+
+ + + + + + + +
+

+ No products out of stock +

+
+ +
+
+
+
+
+
+
+
+`; + exports[`Storyshots Views / Navigation / Menu details default 1`] = `

- Anonymous user + melissa.simon@example.com


-
-
-

- Contact Information -

-
- -

- melissa.simon@example.com -

-
-
-
@@ -57345,40 +57696,14 @@ exports[`Storyshots Views / Orders / Order details default 1`] = ` class="MuiCardContent-root-id" >

- Anonymous user + melissa.simon@example.com


-
-
-

- Contact Information -

-
- -

- melissa.simon@example.com -

-
-
-
@@ -58377,40 +58702,14 @@ exports[`Storyshots Views / Orders / Order details fulfilled 1`] = ` class="MuiCardContent-root-id" >

- Anonymous user + melissa.simon@example.com


-
-
-

- Contact Information -

-
- -

- melissa.simon@example.com -

-
-
-
@@ -58980,27 +59279,6 @@ exports[`Storyshots Views / Orders / Order details loading 1`] = `
-
-
-

- Contact Information -

-
- - ‌ - -
-
@@ -59982,40 +60260,14 @@ exports[`Storyshots Views / Orders / Order details no customer note 1`] = ` class="MuiCardContent-root-id" >

- Anonymous user + melissa.simon@example.com


-
-
-

- Contact Information -

-
- -

- melissa.simon@example.com -

-
-
-
@@ -61014,40 +61266,14 @@ exports[`Storyshots Views / Orders / Order details no payment 1`] = ` class="MuiCardContent-root-id" >

- Anonymous user + melissa.simon@example.com


-
-
-

- Contact Information -

-
- -

- melissa.simon@example.com -

-
-
-
@@ -62046,40 +62272,14 @@ exports[`Storyshots Views / Orders / Order details no shipping address 1`] = ` class="MuiCardContent-root-id" >

- Anonymous user + melissa.simon@example.com


-
-
-

- Contact Information -

-
- -

- melissa.simon@example.com -

-
-
-
@@ -63078,40 +63278,14 @@ exports[`Storyshots Views / Orders / Order details partially fulfilled 1`] = ` class="MuiCardContent-root-id" >

- Anonymous user + melissa.simon@example.com


-
-
-

- Contact Information -

-
- -

- melissa.simon@example.com -

-
-
-
@@ -64110,40 +64284,14 @@ exports[`Storyshots Views / Orders / Order details payment confirmed 1`] = ` class="MuiCardContent-root-id" >

- Anonymous user + melissa.simon@example.com


-
-
-

- Contact Information -

-
- -

- melissa.simon@example.com -

-
-
-
@@ -65142,40 +65290,14 @@ exports[`Storyshots Views / Orders / Order details payment error 1`] = ` class="MuiCardContent-root-id" >

- Anonymous user + melissa.simon@example.com


-
-
-

- Contact Information -

-
- -

- melissa.simon@example.com -

-
-
-
@@ -66174,40 +66296,14 @@ exports[`Storyshots Views / Orders / Order details pending payment 1`] = ` class="MuiCardContent-root-id" >

- Anonymous user + melissa.simon@example.com


-
-
-

- Contact Information -

-
- -

- melissa.simon@example.com -

-
-
-
@@ -67206,40 +67302,14 @@ exports[`Storyshots Views / Orders / Order details refunded payment 1`] = ` class="MuiCardContent-root-id" >

- Anonymous user + melissa.simon@example.com


-
-
-

- Contact Information -

-
- -

- melissa.simon@example.com -

-
-
-
@@ -68238,40 +68308,14 @@ exports[`Storyshots Views / Orders / Order details rejected payment 1`] = ` class="MuiCardContent-root-id" >

- Anonymous user + melissa.simon@example.com


-
-
-

- Contact Information -

-
- -

- melissa.simon@example.com -

-
-
-
@@ -69270,40 +69314,14 @@ exports[`Storyshots Views / Orders / Order details unfulfilled 1`] = ` class="MuiCardContent-root-id" >

- Anonymous user + melissa.simon@example.com


-
-
-

- Contact Information -

-
- -

- melissa.simon@example.com -

-
-
-
@@ -70000,27 +70018,6 @@ exports[`Storyshots Views / Orders / Order draft default 1`] = `
-
-
-

- Contact Information -

-
-

- Not set -

-
-
@@ -70425,27 +70422,6 @@ exports[`Storyshots Views / Orders / Order draft loading 1`] = `
-
-
-

- Contact Information -

-
- - ‌ - -
-
@@ -70524,6 +70500,637 @@ exports[`Storyshots Views / Orders / Order draft loading 1`] = `
`; +exports[`Storyshots Views / Orders / Order draft no user permissions 1`] = ` +
+
+
+
+ #24 +
+
+
+
+ +
+
+
+
+
+ + + +
+
+
+
+
+ + Order Details + +
+ +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
+ + Product + + + Quantity + + Price + + Total + +
+
+
+ +
+
+

+ Davis Group (Hard) +

+ + 58-1338 + +
+
+
+
+
+
+ + +
+
+
+
+ $65.95 + + $131.90 + + +
+
+
+ +
+
+

+ Anderson PLC (15-1337) +

+ + 15-1337 + +
+
+
+
+
+
+ + +
+
+
+
+ $68.20 + + $136.40 + + +
+
+ + + + + + + + + + + + + + + + + + +
+ Subtotal + + $168.30 +
+ No applicable shipping carriers +
+ Taxes (VAT included) + + $68.30 +
+ Total + + $168.30 +
+
+
+
+

+ Order History +

+
+
+
+
+
+
+ +
+
+
+ +
+