Add trailing commas (#2062)

* Require trailing commas

* Add trailing commas

* Add trailing commas in testUtils dir

* Add trailing commas
This commit is contained in:
Michał Droń 2022-06-21 11:36:55 +02:00 committed by GitHub
parent 8bd7824f27
commit d5c9a3dae8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
1539 changed files with 18628 additions and 18574 deletions

View file

@ -76,7 +76,7 @@
"camelcase": "off",
"capitalized-comments": "off",
"chai-friendly/no-unused-expressions": "error",
"comma-dangle": "off",
"comma-dangle": ["error", "always-multiline"],
"complexity": "off",
"constructor-super": "error",
"curly": "error",

View file

@ -1,4 +1,4 @@
{
"arrowParens": "avoid",
"trailingComma": "none"
"trailingComma": "all"
}

View file

@ -5,10 +5,10 @@ import { extensionList } from "./queries";
export const mocks: MockedResponse[] = [
{
request: {
query: extensionList
query: extensionList,
},
result: {
data: []
}
}
data: [],
},
},
];

View file

@ -9,7 +9,7 @@ const props: AppActivateDialogProps = {
name: "App",
onClose: () => undefined,
onConfirm: () => undefined,
open: true
open: true,
};
storiesOf("Views / Apps / Activate app", module)

View file

@ -18,7 +18,7 @@ const AppActivateDialog: React.FC<AppActivateDialogProps> = ({
open,
name,
onClose,
onConfirm
onConfirm,
}) => {
const intl = useIntl();
@ -27,7 +27,7 @@ const AppActivateDialog: React.FC<AppActivateDialogProps> = ({
confirmButtonLabel={intl.formatMessage({
id: "D3E2b5",
defaultMessage: "Activate",
description: "button label"
description: "button label",
})}
confirmButtonState={confirmButtonState}
open={open}
@ -36,7 +36,7 @@ const AppActivateDialog: React.FC<AppActivateDialogProps> = ({
title={intl.formatMessage({
id: "YHNozE",
defaultMessage: "Activate App",
description: "dialog header"
description: "dialog header",
})}
variant="default"
>
@ -53,7 +53,7 @@ const AppActivateDialog: React.FC<AppActivateDialogProps> = ({
defaultMessage="Are you sure you want to activate {name}? Activating will start gathering events."
description="activate app"
values={{
name: <strong>{getStringOrPlaceholder(name)}</strong>
name: <strong>{getStringOrPlaceholder(name)}</strong>,
}}
/>
)}

View file

@ -3,7 +3,7 @@ import { storiesOf } from "@storybook/react";
import React from "react";
import AppDeactivateDialog, {
AppDeactivateDialogProps
AppDeactivateDialogProps,
} from "./AppDeactivateDialog";
const props: AppDeactivateDialogProps = {
@ -11,7 +11,7 @@ const props: AppDeactivateDialogProps = {
name: "App",
onClose: () => undefined,
onConfirm: () => undefined,
open: true
open: true,
};
storiesOf("Views / Apps / Deactivate app", module)

View file

@ -22,7 +22,7 @@ const AppDeactivateDialog: React.FC<AppDeactivateDialogProps> = ({
name,
thirdParty = true,
onClose,
onConfirm
onConfirm,
}) => {
const intl = useIntl();
@ -31,7 +31,7 @@ const AppDeactivateDialog: React.FC<AppDeactivateDialogProps> = ({
confirmButtonLabel={intl.formatMessage({
id: "W+AFZY",
defaultMessage: "Deactivate",
description: "button label"
description: "button label",
})}
confirmButtonState={confirmButtonState}
open={open}
@ -40,7 +40,7 @@ const AppDeactivateDialog: React.FC<AppDeactivateDialogProps> = ({
title={intl.formatMessage({
id: "yMi8I8",
defaultMessage: "Dectivate App",
description: "dialog header"
description: "dialog header",
})}
variant="delete"
>
@ -55,7 +55,7 @@ const AppDeactivateDialog: React.FC<AppDeactivateDialogProps> = ({
? msgs.deactivateNamedApp
: msgs.deactivateLocalNamedApp)}
values={{
name: <strong>{getStringOrPlaceholder(name)}</strong>
name: <strong>{getStringOrPlaceholder(name)}</strong>,
}}
/>
)}

View file

@ -5,24 +5,24 @@ export default defineMessages({
id: "73RU3R",
defaultMessage:
"Are you sure you want to disable this app? Your data will be kept until you reactivate the app. You will be still billed for the app.",
description: "deactivate app"
description: "deactivate app",
},
deactivateNamedApp: {
id: "w6Gau0",
defaultMessage:
"Are you sure you want to disable {name}? Your data will be kept until you reactivate the app. You will be still billed for the app.",
description: "deactivate named app"
description: "deactivate named app",
},
deactivateLocalApp: {
id: "7O2EsY",
defaultMessage:
"Are you sure you want to disable this app? Your data will be kept until you reactivate the app.",
description: "deactivate local app"
description: "deactivate local app",
},
deactivateLocalNamedApp: {
id: "Np7J92",
defaultMessage:
"Are you sure you want to disable {name}? Your data will be kept until you reactivate the app.",
description: "deactivate local named app"
}
description: "deactivate local named app",
},
});

View file

@ -10,7 +10,7 @@ const props: AppDeleteDialogProps = {
onClose: () => undefined,
onConfirm: () => undefined,
open: true,
type: "EXTERNAL"
type: "EXTERNAL",
};
storiesOf("Views / Apps / Delete app", module)

View file

@ -20,7 +20,7 @@ const AppDeleteDialog: React.FC<AppDeleteDialogProps> = ({
name,
onClose,
onConfirm,
type
type,
}) => {
const intl = useIntl();
@ -33,7 +33,7 @@ const AppDeleteDialog: React.FC<AppDeleteDialogProps> = ({
title={intl.formatMessage({
id: "zQX6xO",
defaultMessage: "Delete App",
description: "dialog header"
description: "dialog header",
})}
variant="delete"
>
@ -50,7 +50,7 @@ const AppDeleteDialog: React.FC<AppDeleteDialogProps> = ({
defaultMessage="Deleting {name}, you will remove installation of the app. If you are paying for app subscription, remember to unsubscribe from the app in Saleor Marketplace. Are you sure you want to delete the app?"
description="delete app"
values={{
name: <strong>{getStringOrPlaceholder(name)}</strong>
name: <strong>{getStringOrPlaceholder(name)}</strong>,
}}
/>
) : (
@ -59,7 +59,7 @@ const AppDeleteDialog: React.FC<AppDeleteDialogProps> = ({
defaultMessage="Deleting {name}, you will delete all the data and webhooks regarding this app. Are you sure you want to do that?"
description="delete custom app"
values={{
name: <strong>{getStringOrPlaceholder(name)}</strong>
name: <strong>{getStringOrPlaceholder(name)}</strong>,
}}
/>
)}

View file

@ -10,7 +10,7 @@ const props: AppDetailsPageProps = {
loading: false,
navigateToApp: () => undefined,
onAppActivateOpen: () => undefined,
onAppDeactivateOpen: () => undefined
onAppDeactivateOpen: () => undefined,
};
storiesOf("Views / Apps / App details", module)

View file

@ -33,7 +33,7 @@ export const AppDetailsPage: React.FC<AppDetailsPageProps> = ({
loading,
navigateToApp,
onAppActivateOpen,
onAppDeactivateOpen
onAppDeactivateOpen,
}) => {
const intl = useIntl();
const classes = useStyles({});
@ -105,7 +105,7 @@ export const AppDetailsPage: React.FC<AppDetailsPageProps> = ({
title={intl.formatMessage({
id: "jDIRQV",
defaultMessage: "About this app",
description: "section header"
description: "section header",
})}
/>
<CardContent>
@ -118,7 +118,7 @@ export const AppDetailsPage: React.FC<AppDetailsPageProps> = ({
title={intl.formatMessage({
id: "VsGcdP",
defaultMessage: "App permissions",
description: "section header"
description: "section header",
})}
/>
<CardContent>
@ -152,7 +152,7 @@ export const AppDetailsPage: React.FC<AppDetailsPageProps> = ({
title={intl.formatMessage({
id: "a55zOn",
defaultMessage: "Data privacy",
description: "section header"
description: "section header",
})}
/>
<CardContent>

View file

@ -4,7 +4,7 @@ import {
DialogProps,
DialogTitle,
IconButton,
Typography
Typography,
} from "@material-ui/core";
import CloseIcon from "@material-ui/icons/Close";
import React from "react";

View file

@ -5,15 +5,15 @@ export const useStyles = makeStyles(
header: {
display: "flex",
justifyContent: "space-between",
alignItems: "center"
alignItems: "center",
},
content: {
margin: 0,
padding: 0,
overflow: "hidden",
width: 600,
height: 600
}
height: 600,
},
}),
{ name: "AppDialog" }
{ name: "AppDialog" },
);

View file

@ -24,7 +24,7 @@ export const AppFrame: React.FC<Props> = ({
appId,
className,
onLoad,
onError
onError,
}) => {
const shop = useShop();
const frameRef = React.useRef<HTMLIFrameElement>();
@ -38,8 +38,8 @@ export const AppFrame: React.FC<Props> = ({
type: "handshake",
payload: {
token: appToken,
version: 1
}
version: 1,
},
});
sendThemeToExtension();

View file

@ -5,8 +5,8 @@ export const useStyles = makeStyles(
iframe: {
width: "100%",
height: "100%",
border: "none"
}
border: "none",
},
}),
{ name: "AppFrame" }
{ name: "AppFrame" },
);

View file

@ -7,25 +7,25 @@ import { useExternalApp } from "../ExternalAppContext";
const sendResponseStatus = (
actionId: string,
ok: boolean
ok: boolean,
): DispatchResponseEvent => ({
type: "response",
payload: {
actionId,
ok
}
ok,
},
});
export const useAppActions = (
frameEl: React.MutableRefObject<HTMLIFrameElement>,
appOrigin: string
appOrigin: string,
) => {
const navigate = useNavigator();
const { closeApp } = useExternalApp();
const intl = useIntl();
const actionReducer = (
action: Actions | undefined
action: Actions | undefined,
): DispatchResponseEvent => {
switch (action?.type) {
case "redirect": {
@ -48,8 +48,8 @@ export const useAppActions = (
intl.formatMessage({
id: "MSItJD",
defaultMessage:
"You are about to leave the Dashboard. Do you want to continue?"
})
"You are about to leave the Dashboard. Do you want to continue?",
}),
);
}
@ -92,6 +92,6 @@ export const useAppActions = (
}, []);
return {
postToExtension
postToExtension,
};
};

View file

@ -3,7 +3,7 @@ import { storiesOf } from "@storybook/react";
import React from "react";
import AppInProgressDeleteDialog, {
AppInProgressDeleteDialogProps
AppInProgressDeleteDialogProps,
} from "./AppInProgressDeleteDialog";
const props: AppInProgressDeleteDialogProps = {
@ -11,7 +11,7 @@ const props: AppInProgressDeleteDialogProps = {
name: "App",
onClose: () => undefined,
onConfirm: () => undefined,
open: true
open: true,
};
storiesOf("Views / Apps / Delete app failed installation", module)

View file

@ -18,7 +18,7 @@ const AppInProgressDeleteDialog: React.FC<AppInProgressDeleteDialogProps> = ({
open,
name,
onClose,
onConfirm
onConfirm,
}) => {
const intl = useIntl();
@ -31,7 +31,7 @@ const AppInProgressDeleteDialog: React.FC<AppInProgressDeleteDialogProps> = ({
title={intl.formatMessage({
id: "zQX6xO",
defaultMessage: "Delete App",
description: "dialog header"
description: "dialog header",
})}
variant="delete"
>
@ -48,7 +48,7 @@ const AppInProgressDeleteDialog: React.FC<AppInProgressDeleteDialogProps> = ({
defaultMessage="Deleting {name}, you will remove installation of the app. If you are paying for app subscription, remember to unsubscribe from the app in Saleor Marketplace. Are you sure you want to delete the app?"
description="delete app"
values={{
name: <strong>{getStringOrPlaceholder(name)}</strong>
name: <strong>{getStringOrPlaceholder(name)}</strong>,
}}
/>
)}

View file

@ -12,7 +12,7 @@ interface AppInstallErrorPageProps {
}
export const AppInstallErrorPage: React.FC<AppInstallErrorPageProps> = ({
onBack
onBack,
}) => {
const classes = useStyles({});

View file

@ -4,23 +4,23 @@ export const useStyles = makeStyles(
theme => ({
button: {
marginTop: theme.spacing(2),
padding: theme.spacing(1.5, 2)
padding: theme.spacing(1.5, 2),
},
root: {
"& > div": {
minHeight: "80vh"
minHeight: "80vh",
},
"& h3": {
fontWeight: 600,
marginBottom: theme.spacing(3),
maxWidth: theme.spacing(60)
maxWidth: theme.spacing(60),
},
"& img": {
maxWidth: "100%"
}
}
maxWidth: "100%",
},
},
}),
{
name: "AppInstallErrorPage"
}
name: "AppInstallErrorPage",
},
);

View file

@ -9,7 +9,7 @@ const props: AppInstallPageProps = {
data: installApp,
loading: false,
navigateToAppsList: () => undefined,
onSubmit: () => undefined
onSubmit: () => undefined,
};
storiesOf("Views / Apps / Install App", module)

View file

@ -27,7 +27,7 @@ export const AppInstallPage: React.FC<AppInstallPageProps> = ({
data,
loading,
navigateToAppsList,
onSubmit
onSubmit,
}) => {
const intl = useIntl();
const classes = useStyles({});
@ -47,9 +47,9 @@ export const AppInstallPage: React.FC<AppInstallPageProps> = ({
{
id: "Id7C0X",
defaultMessage: `You are about to install {name}`,
description: "section header"
description: "section header",
},
{ name }
{ name },
)
)
}
@ -62,7 +62,7 @@ export const AppInstallPage: React.FC<AppInstallPageProps> = ({
<div
className={classNames(
classes.installIcon,
classes.installSaleorIcon
classes.installSaleorIcon,
)}
>
<img src={saleorDarkLogoSmall} alt="" />
@ -81,7 +81,7 @@ export const AppInstallPage: React.FC<AppInstallPageProps> = ({
title={intl.formatMessage({
id: "VsGcdP",
defaultMessage: "App permissions",
description: "section header"
description: "section header",
})}
/>
<CardContent>

View file

@ -9,7 +9,7 @@ const props: AppPageProps = {
data: appDetails,
url: appDetails.appUrl,
aboutHref: "",
onError: () => undefined
onError: () => undefined,
};
storiesOf("Views / Apps / App", module)

View file

@ -27,7 +27,7 @@ export const AppPage: React.FC<AppPageProps> = ({
data,
url,
aboutHref,
onError
onError,
}) => {
const intl = useIntl();
const classes = useStyles({});
@ -44,7 +44,7 @@ export const AppPage: React.FC<AppPageProps> = ({
<Typography
className={classNames(
classes.breadcrumb,
classes.breadcrumbDisabled
classes.breadcrumbDisabled,
)}
variant="h5"
>

View file

@ -5,12 +5,12 @@ export const useStyles = makeStyles(
appSettingsHeader: {
"& > button, & > a": {
"&:last-child": {
marginRight: 0
marginRight: 0,
},
marginRight: theme.spacing(2)
marginRight: theme.spacing(2),
},
display: "flex",
justifyContent: "flex-end"
justifyContent: "flex-end",
},
breadcrumb: {
"&:not(:last-child)": {
@ -19,28 +19,28 @@ export const useStyles = makeStyles(
display: "block",
position: "absolute",
right: theme.spacing(-2),
top: 0
top: 0,
},
"&:not(:first-child):hover": {
cursor: "pointer",
textDecoration: "underline"
}
textDecoration: "underline",
},
},
marginRight: theme.spacing(3),
position: "relative"
position: "relative",
},
breadcrumbContainer: {
alignItems: "center",
display: "flex"
display: "flex",
},
breadcrumbDisabled: {
"&:hover": {
textDecoration: "none"
textDecoration: "none",
},
color: theme.palette.text.disabled
color: theme.palette.text.disabled,
},
breadcrumbs: {
display: "flex"
display: "flex",
},
hr: {
border: "none",
@ -48,15 +48,15 @@ export const useStyles = makeStyles(
height: 0,
marginBottom: 0,
marginTop: 0,
width: "100%"
width: "100%",
},
iframeContainer: {
"& > iframe": {
border: "none",
minHeight: "75vh",
width: "100%"
}
}
width: "100%",
},
},
}),
{ name: "AppPage" }
{ name: "AppPage" },
);

View file

@ -5,7 +5,7 @@ import {
ExtensionMessageEvent,
ExtensionMessageType,
sendMessageToExtension,
useExtensionMessage
useExtensionMessage,
} from "@saleor/macaw-ui";
import { useState } from "react";
@ -14,7 +14,7 @@ function useSettingsBreadcrumbs(): UseSettingsBreadcrumbs {
const [breadcrumbs, setBreadcrumbs] = useState<Breadcrumb[]>([]);
const handleBreadcrumbSet = (
event: ExtensionMessageEvent<BreadcrumbChangeMessage>
event: ExtensionMessageEvent<BreadcrumbChangeMessage>,
) => {
if (event.data.type === ExtensionMessageType.BREADCRUMB_SET) {
setBreadcrumbs(event.data.breadcrumbs);
@ -27,9 +27,9 @@ function useSettingsBreadcrumbs(): UseSettingsBreadcrumbs {
sendMessageToExtension<BreadcrumbClickMessage>(
{
breadcrumb: value,
type: ExtensionMessageType.BREADCRUMB_CLICK
type: ExtensionMessageType.BREADCRUMB_CLICK,
},
"*"
"*",
);
return [breadcrumbs, handleBreadcrumbClick];

View file

@ -3,7 +3,7 @@ import {
IconButton,
makeStyles,
PermissionsIcon,
Tooltip
Tooltip,
} from "@saleor/macaw-ui";
import React from "react";
import { FormattedMessage } from "react-intl";
@ -12,10 +12,10 @@ const useStyles = makeStyles(
() => ({
list: {
margin: 0,
paddingLeft: "16px"
}
paddingLeft: "16px",
},
}),
{ name: "AppPermissions" }
{ name: "AppPermissions" },
);
interface AppPermissionsProps {

View file

@ -4,7 +4,7 @@ import {
TableBody,
TableCell,
TableRow,
Typography
Typography,
} from "@material-ui/core";
import { Button } from "@saleor/components/Button";
import CardTitle from "@saleor/components/CardTitle";
@ -16,7 +16,7 @@ import {
Indicator,
ResponsiveTable,
Tooltip,
TooltipMountWrapper
TooltipMountWrapper,
} from "@saleor/macaw-ui";
import { renderCollection } from "@saleor/misc";
import classNames from "classnames";
@ -48,7 +48,7 @@ const AppsInProgress: React.FC<AppsInProgressProps> = ({
title={intl.formatMessage({
id: "nIrjSR",
defaultMessage: "Ongoing Installations",
description: "section header"
description: "section header",
})}
/>
<ResponsiveTable>
@ -62,7 +62,7 @@ const AppsInProgress: React.FC<AppsInProgressProps> = ({
<TableCell
className={classNames(
classes.colAction,
classes.colInstallAction
classes.colInstallAction,
)}
>
<Typography variant="body2" className={classes.text}>
@ -81,7 +81,7 @@ const AppsInProgress: React.FC<AppsInProgressProps> = ({
<TableCell
className={classNames(
classes.colAction,
classes.colInstallAction
classes.colInstallAction,
)}
>
<Typography variant="body2" className={classes.error}>

View file

@ -4,7 +4,7 @@ import {
pageListProps,
searchPageProps,
sortPageProps,
tabPageProps
tabPageProps,
} from "@saleor/fixtures";
import Decorator from "@saleor/storybook/Decorator";
import { PaginatorContextDecorator } from "@saleor/storybook/PaginatorContextDecorator";
@ -22,7 +22,7 @@ const props: AppsListPageProps = {
...tabPageProps,
appsInProgressList: {
__typename: "Query",
appsInstallations: appsInProgress
appsInstallations: appsInProgress,
},
customAppsList,
disabled: false,
@ -32,7 +32,7 @@ const props: AppsListPageProps = {
onAppInProgressRemove: () => undefined,
onAppInstallRetry: () => undefined,
onCustomAppRemove: () => undefined,
onInstalledAppRemove: () => undefined
onInstalledAppRemove: () => undefined,
};
storiesOf("Views / Apps / Apps list", module)

View file

@ -9,7 +9,7 @@ import Savebar from "@saleor/components/Savebar";
import {
AppErrorFragment,
PermissionEnum,
PermissionFragment
PermissionFragment,
} from "@saleor/graphql";
import { SubmitPromise } from "@saleor/hooks/useForm";
import useNavigator from "@saleor/hooks/useNavigator";
@ -33,7 +33,7 @@ export interface CustomAppCreatePageProps {
permissions: PermissionFragment[];
saveButtonBarState: ConfirmButtonTransitionState;
onSubmit: (
data: CustomAppCreatePageFormData
data: CustomAppCreatePageFormData,
) => SubmitPromise<AppErrorFragment[]>;
}
@ -45,7 +45,7 @@ const CustomAppCreatePage: React.FC<CustomAppCreatePageProps> = props => {
const initialForm: CustomAppCreatePageFormData = {
hasFullAccess: false,
name: "",
permissions: []
permissions: [],
};
const formErrors = getFormErrors(["permissions"], errors || []);
@ -67,7 +67,7 @@ const CustomAppCreatePage: React.FC<CustomAppCreatePageProps> = props => {
title={intl.formatMessage({
id: "GjH9uy",
defaultMessage: "Create New App",
description: "header"
description: "header",
})}
/>
<Grid>
@ -89,13 +89,13 @@ const CustomAppCreatePage: React.FC<CustomAppCreatePageProps> = props => {
fullAccessLabel={intl.formatMessage({
id: "D4nzdD",
defaultMessage: "Grant this app full access to the store",
description: "checkbox label"
description: "checkbox label",
})}
description={intl.formatMessage({
id: "flP8Hj",
defaultMessage:
"Expand or restrict app permissions to access certain part of Saleor system.",
description: "card description"
description: "card description",
})}
/>
</Grid>

View file

@ -41,7 +41,7 @@ const CustomAppDefaultToken: React.FC<CustomAppDefaultTokenProps> = props => {
<Link href={apiUri} onClick={onApiUriClick}>
{apiUri}
</Link>
)
),
}}
/>
</Typography>

View file

@ -4,35 +4,35 @@ import { makeStyles } from "@saleor/macaw-ui";
export const useStyles = makeStyles(
theme => ({
cancel: {
marginRight: theme.spacing(1)
marginRight: theme.spacing(1),
},
closeContainer: {
display: "flex",
justifyContent: "flex-end",
position: "relative",
right: theme.spacing(-1),
top: theme.spacing(-1)
top: theme.spacing(-1),
},
content: {
display: "grid",
gridColumnGap: theme.spacing(3),
gridTemplateColumns: "1fr 60px",
marginBottom: theme.spacing(3)
marginBottom: theme.spacing(3),
},
copy: {
marginTop: theme.spacing(),
position: "relative",
right: theme.spacing(1)
right: theme.spacing(1),
},
paper: {
background: fade(theme.palette.primary.main, 0.05),
padding: theme.spacing(2, 3)
padding: theme.spacing(2, 3),
},
root: {
boxShadow: "0px 5px 10px rgba(0, 0, 0, 0.05)"
}
boxShadow: "0px 5px 10px rgba(0, 0, 0, 0.05)",
},
}),
{
name: "CustomAppTokenCreateDialog"
}
name: "CustomAppTokenCreateDialog",
},
);

View file

@ -11,7 +11,7 @@ import {
AppErrorFragment,
AppUpdateMutation,
PermissionEnum,
ShopInfoQuery
ShopInfoQuery,
} from "@saleor/graphql";
import { SubmitPromise } from "@saleor/hooks/useForm";
import useNavigator from "@saleor/hooks/useNavigator";
@ -48,7 +48,7 @@ export interface CustomAppDetailsPageProps {
onTokenClose: () => void;
onTokenCreate: () => void;
onSubmit: (
data: CustomAppDetailsPageFormData
data: CustomAppDetailsPageFormData,
) => SubmitPromise<AppErrorFragment[]>;
webhookCreateHref: string;
onWebhookRemove: (id: string) => void;
@ -73,7 +73,7 @@ const CustomAppDetailsPage: React.FC<CustomAppDetailsPageProps> = props => {
webhookCreateHref,
onWebhookRemove,
onAppActivateOpen,
onAppDeactivateOpen
onAppDeactivateOpen,
} = props;
const intl = useIntl();
const classes = useStyles({});
@ -89,11 +89,11 @@ const CustomAppDetailsPage: React.FC<CustomAppDetailsPageProps> = props => {
permissions?.filter(
perm =>
app?.permissions?.filter(userPerm => userPerm.code === perm.code)
.length === 0
.length === 0,
).length === 0 || false,
isActive: !!app?.isActive,
name: app?.name || "",
permissions: app?.permissions?.map(perm => perm.code) || []
permissions: app?.permissions?.map(perm => perm.code) || [],
};
return (
@ -174,13 +174,13 @@ const CustomAppDetailsPage: React.FC<CustomAppDetailsPageProps> = props => {
fullAccessLabel={intl.formatMessage({
id: "D4nzdD",
defaultMessage: "Grant this app full access to the store",
description: "checkbox label"
description: "checkbox label",
})}
description={intl.formatMessage({
id: "flP8Hj",
defaultMessage:
"Expand or restrict app permissions to access certain part of Saleor system.",
description: "card description"
description: "card description",
})}
/>
</div>

View file

@ -20,7 +20,7 @@ const CustomAppInformation: React.FC<CustomAppInfoProps> = ({
data,
disabled,
errors,
onChange
onChange,
}) => {
const intl = useIntl();
@ -32,7 +32,7 @@ const CustomAppInformation: React.FC<CustomAppInfoProps> = ({
title={intl.formatMessage({
id: "imYxM9",
defaultMessage: "App Information",
description: "header"
description: "header",
})}
/>
<CardContent>
@ -42,7 +42,7 @@ const CustomAppInformation: React.FC<CustomAppInfoProps> = ({
label={intl.formatMessage({
id: "foNlhn",
defaultMessage: "App Name",
description: "custom app name"
description: "custom app name",
})}
helperText={getAppErrorMessage(formErrors.name, intl)}
fullWidth

View file

@ -3,7 +3,7 @@ import {
TableBody,
TableCell,
TableHead,
TableRow
TableRow,
} from "@material-ui/core";
import { Button } from "@saleor/components/Button";
import CardTitle from "@saleor/components/CardTitle";
@ -36,7 +36,7 @@ const CustomAppTokens: React.FC<CustomAppTokensProps> = props => {
title={intl.formatMessage({
id: "0Mg8o5",
defaultMessage: "Tokens",
description: "header"
description: "header",
})}
toolbar={
<Button
@ -105,7 +105,7 @@ const CustomAppTokens: React.FC<CustomAppTokensProps> = props => {
/>
</TableCell>
</TableRow>
)
),
)}
</TableBody>
</ResponsiveTable>

View file

@ -4,20 +4,20 @@ export const useStyles = makeStyles(
theme => ({
[theme.breakpoints.down("md")]: {
colNote: {
width: 200
}
width: 200,
},
},
colActions: {
textAlign: "right",
width: 100
width: 100,
},
colKey: {
width: 200
width: 200,
},
colNote: {},
table: {
tableLayout: "fixed"
}
tableLayout: "fixed",
},
}),
{ name: "CustomAppTokens" }
{ name: "CustomAppTokens" },
);

View file

@ -3,7 +3,7 @@ import {
TableBody,
TableCell,
TableRow,
Typography
Typography,
} from "@material-ui/core";
import { customAppAddUrl } from "@saleor/apps/urls";
import { Button } from "@saleor/components/Button";
@ -30,7 +30,7 @@ export interface CustomAppsProps {
const CustomApps: React.FC<CustomAppsProps> = ({
appsList,
onRemove,
getCustomAppHref
getCustomAppHref,
}) => {
const intl = useIntl();
const classes = useStyles({});
@ -101,7 +101,7 @@ const CustomApps: React.FC<CustomAppsProps> = ({
</Typography>
</TableCell>
</TableRow>
)
),
)}
</TableBody>
</ResponsiveTable>

View file

@ -13,14 +13,14 @@ export const useStyles = makeStyles(
position: "absolute",
top: "50%",
transform: "translateY(-50%)",
width: 8
width: 8,
},
color: theme.palette.error.main,
display: "inline-block",
marginLeft: theme.spacing(1.5),
paddingLeft: theme.spacing(2),
position: "relative"
}
position: "relative",
},
}),
{ name: "DeactivatedText" }
{ name: "DeactivatedText" },
);

View file

@ -8,10 +8,10 @@ export interface HorizontalSpacerProps {
const useStyles = makeStyles(
theme => ({
container: ({ spacing }: HorizontalSpacerProps) => ({
width: theme.spacing(spacing)
})
width: theme.spacing(spacing),
}),
{ name: "HorizontalSpacer" }
}),
{ name: "HorizontalSpacer" },
);
const HorizontalSpacer: React.FC<HorizontalSpacerProps> = ({ spacing = 1 }) => {

View file

@ -4,7 +4,7 @@ import {
TableBody,
TableCell,
TableRow,
Typography
Typography,
} from "@material-ui/core";
import { useAppListContext } from "@saleor/apps/context";
import { appUrl } from "@saleor/apps/urls";
@ -55,7 +55,7 @@ const InstalledApps: React.FC<InstalledAppsProps> = ({
title={intl.formatMessage({
id: "BvmnJq",
defaultMessage: "Third Party Apps",
description: "section header"
description: "section header",
})}
/>
<ResponsiveTable>
@ -116,7 +116,7 @@ const InstalledApps: React.FC<InstalledAppsProps> = ({
</Typography>
</TableCell>
</TableRow>
)
),
)}
</TableBody>
</ResponsiveTable>

View file

@ -18,7 +18,7 @@ const Marketplace: React.FC<MarketplaceProps> = ({ link }) => {
title={intl.formatMessage({
id: "SwISVH",
defaultMessage: "Saleor Marketplace",
description: "section header"
description: "section header",
})}
/>
<CardContent>

View file

@ -5,7 +5,7 @@ import {
DialogTitle,
Paper,
TextField,
Typography
Typography,
} from "@material-ui/core";
import BackButton from "@saleor/components/BackButton";
import { Button } from "@saleor/components/Button";
@ -49,7 +49,7 @@ const TokenCreateDialog: React.FC<TokenCreateDialogProps> = props => {
}, [token]);
useModalDialogOpen(open, {
onClose: () => setStep("form")
onClose: () => setStep("form"),
});
return (
@ -77,7 +77,7 @@ const TokenCreateDialog: React.FC<TokenCreateDialogProps> = props => {
<TextField
label={intl.formatMessage({
id: "0DRBjg",
defaultMessage: "Token Note"
defaultMessage: "Token Note",
})}
value={data.name}
onChange={change}

View file

@ -4,19 +4,19 @@ import { makeStyles } from "@saleor/macaw-ui";
export const useStyles = makeStyles(
theme => ({
cancel: {
marginRight: theme.spacing(1)
marginRight: theme.spacing(1),
},
copy: {
marginTop: theme.spacing(),
position: "relative",
right: theme.spacing(1)
right: theme.spacing(1),
},
paper: {
background: fade(theme.palette.primary.main, 0.05),
padding: theme.spacing(2, 3)
}
padding: theme.spacing(2, 3),
},
}),
{
name: "TokenCreateDialog"
}
name: "TokenCreateDialog",
},
);

View file

@ -9,7 +9,7 @@ const props: TokenDeleteDialogProps = {
name: "Slack",
onClose: () => undefined,
onConfirm: () => undefined,
open: true
open: true,
};
storiesOf("Views / Apps / Custom app details / Token delete", module)

View file

@ -17,7 +17,7 @@ const TokenDeleteDialog: React.FC<TokenDeleteDialogProps> = ({
confirmButtonState,
onClose,
onConfirm,
open
open,
}) => {
const intl = useIntl();
@ -31,7 +31,7 @@ const TokenDeleteDialog: React.FC<TokenDeleteDialogProps> = ({
title={intl.formatMessage({
id: "quV5zH",
defaultMessage: "Delete Token",
description: "dialog title"
description: "dialog title",
})}
>
<DialogContentText>
@ -40,7 +40,7 @@ const TokenDeleteDialog: React.FC<TokenDeleteDialogProps> = ({
defaultMessage="Are you sure you want to delete token {token}?"
description="delete token"
values={{
token: <strong>{name}</strong>
token: <strong>{name}</strong>,
}}
/>
</DialogContentText>

View file

@ -8,10 +8,10 @@ export interface VerticalSpacerProps {
const useStyles = makeStyles(
theme => ({
container: ({ spacing }: VerticalSpacerProps) => ({
height: theme.spacing(spacing)
})
height: theme.spacing(spacing),
}),
{ name: "VerticalSpacer" }
}),
{ name: "VerticalSpacer" },
);
const VerticalSpacer: React.FC<VerticalSpacerProps> = ({ spacing = 1 }) => {

View file

@ -5,7 +5,7 @@ import {
AppsListQuery,
AppTypeEnum,
JobStatusEnum,
PermissionEnum
PermissionEnum,
} from "@saleor/graphql";
export const appsList: AppsListQuery["apps"]["edges"] = [
@ -22,10 +22,10 @@ export const appsList: AppsListQuery["apps"]["edges"] = [
{
__typename: "Permission",
code: PermissionEnum.MANAGE_USERS,
name: "Manage customers."
}
]
}
name: "Manage customers.",
},
],
},
},
{
__typename: "AppCountableEdge",
@ -40,16 +40,16 @@ export const appsList: AppsListQuery["apps"]["edges"] = [
{
__typename: "Permission",
code: PermissionEnum.MANAGE_ORDERS,
name: "Manage orders."
name: "Manage orders.",
},
{
__typename: "Permission",
code: PermissionEnum.MANAGE_USERS,
name: "Manage customers."
}
]
}
}
name: "Manage customers.",
},
],
},
},
];
export const customAppsList: AppsListQuery["apps"]["edges"] = [
@ -66,16 +66,16 @@ export const customAppsList: AppsListQuery["apps"]["edges"] = [
{
__typename: "Permission",
code: PermissionEnum.MANAGE_ORDERS,
name: "Manage orders."
name: "Manage orders.",
},
{
__typename: "Permission",
code: PermissionEnum.MANAGE_USERS,
name: "Manage customers."
}
]
}
}
name: "Manage customers.",
},
],
},
},
];
export const appsInProgress: AppsInstallationsQuery["appsInstallations"] = [
@ -85,7 +85,7 @@ export const appsInProgress: AppsInstallationsQuery["appsInstallations"] = [
id: "QXBwSW5zdGFsbGF0aW9uOjk2",
manifestUrl: "http://localhost:3000/manifest",
message: "Failed to connect to app. Try later or contact with app support.",
status: JobStatusEnum.FAILED
status: JobStatusEnum.FAILED,
},
{
__typename: "AppInstallation",
@ -93,7 +93,7 @@ export const appsInProgress: AppsInstallationsQuery["appsInstallations"] = [
id: "QXBwSW5zdGFsbGF0aW9uOjk2",
manifestUrl: "http://localhost:3000/manifest",
message: "Pending.",
status: JobStatusEnum.PENDING
status: JobStatusEnum.PENDING,
},
{
__typename: "AppInstallation",
@ -101,8 +101,8 @@ export const appsInProgress: AppsInstallationsQuery["appsInstallations"] = [
id: "QXBwSW5zdGFsbGF0aW9uOjk2",
manifestUrl: "http://localhost:3000/manifest",
message: "Success.",
status: JobStatusEnum.SUCCESS
}
status: JobStatusEnum.SUCCESS,
},
];
export const appDetails: AppQuery["app"] = {
@ -123,20 +123,20 @@ export const appDetails: AppQuery["app"] = {
{
__typename: "Permission",
code: PermissionEnum.MANAGE_ORDERS,
name: "Manage orders."
name: "Manage orders.",
},
{
__typename: "Permission",
code: PermissionEnum.MANAGE_USERS,
name: "Manage customers."
}
name: "Manage customers.",
},
],
privateMetadata: [],
supportUrl: "http://localhost:8888/support",
tokens: [],
type: AppTypeEnum.THIRDPARTY,
version: "1.0.0",
webhooks: []
webhooks: [],
};
export const installApp: AppFetchMutation["appFetchManifest"]["manifest"] = {
@ -153,15 +153,15 @@ export const installApp: AppFetchMutation["appFetchManifest"]["manifest"] = {
{
__typename: "Permission",
code: PermissionEnum.MANAGE_USERS,
name: "Manage users"
name: "Manage users",
},
{
__typename: "Permission",
code: PermissionEnum.MANAGE_ORDERS,
name: "Manage orders"
}
name: "Manage orders",
},
],
supportUrl: null,
tokenTargetUrl: null,
version: "1.0"
version: "1.0",
};

View file

@ -17,7 +17,7 @@ import {
appsListPath,
customAppAddPath,
customAppPath,
CustomAppUrlQueryParams
CustomAppUrlQueryParams,
} from "./urls";
import AppView from "./views/App";
import AppDetailsView from "./views/AppDetails";
@ -28,7 +28,7 @@ import CustomAppCreateView from "./views/CustomAppCreate";
import CustomAppDetailsView from "./views/CustomAppDetails";
const AppDetails: React.FC<RouteComponentProps<{ id: string }>> = ({
match
match,
}) => {
const qs = parseQs(location.search.substr(1));
const params: AppDetailsUrlQueryParams = qs;
@ -39,7 +39,7 @@ const AppDetails: React.FC<RouteComponentProps<{ id: string }>> = ({
};
const AppSettings: React.FC<RouteComponentProps<{ id: string }>> = ({
match
match,
}) => <AppSettingsView id={decodeURIComponent(match.params.id)} />;
const App: React.FC<RouteComponentProps<{ id: string }>> = ({ match }) => (
@ -61,7 +61,7 @@ interface CustomAppDetailsProps extends RouteComponentProps<{ id?: string }> {
const CustomAppDetails: React.FC<CustomAppDetailsProps> = ({
match,
token,
onTokenClose
onTokenClose,
}) => {
const qs = parseQs(location.search.substr(1));
const params: CustomAppUrlQueryParams = qs;

View file

@ -4,16 +4,16 @@ export const appMessages = defineMessages({
failedToFetchAppSettings: {
id: "ac+Y98",
defaultMessage: "Failed to fetch app settings",
description: "app settings error"
description: "app settings error",
},
appActivated: {
id: "D/+84n",
defaultMessage: "App activated",
description: "snackbar text"
description: "snackbar text",
},
appDeactivated: {
id: "USO8PB",
defaultMessage: "App deactivated",
description: "snackbar text"
}
description: "snackbar text",
},
});

View file

@ -5,89 +5,89 @@ export const useStyles = makeStyles(
[theme.breakpoints.up("lg")]: {
colName: {
"&&": {
width: "auto"
}
}
width: "auto",
},
},
},
alignRight: {
textAlign: "right"
textAlign: "right",
},
apps: {
marginBottom: theme.spacing(4)
marginBottom: theme.spacing(4),
},
appContent: {
"&:last-child": {
padding: "0!important"
padding: "0!important",
},
padding: 0
padding: 0,
},
appHeader: {
marginBottom: theme.spacing(3)
marginBottom: theme.spacing(3),
},
appHeaderLinks: {
"& img": {
marginRight: theme.spacing(1)
marginRight: theme.spacing(1),
},
alignItems: "center",
display: "flex",
padding: theme.spacing(2, 0)
padding: theme.spacing(2, 0),
},
appName: {
color: theme.palette.primary.main
color: theme.palette.primary.main,
},
colAction: {
"&&": {
paddingRight: theme.spacing(3),
textAlign: "right"
textAlign: "right",
},
alignItems: "center",
display: "flex",
flexDirection: "row",
justifyContent: "flex-end",
textAlign: "right"
textAlign: "right",
},
colInstallAction: {
"& > *": {
display: "inline-flex"
}
display: "inline-flex",
},
},
colName: {
paddingLeft: 0,
width: theme.spacing(30)
width: theme.spacing(30),
},
colSpinner: {
"& svg": {
textAlign: "right"
textAlign: "right",
},
paddingLeft: theme.spacing(3),
paddingRight: theme.spacing(2)
paddingRight: theme.spacing(2),
},
customApps: {
marginBottom: theme.spacing(4)
marginBottom: theme.spacing(4),
},
customTooltip: {
"& > div": {
backgroundColor: theme.palette.error.main,
borderRadius: theme.spacing(1),
color: theme.palette.primary.contrastText,
padding: theme.spacing(2)
padding: theme.spacing(2),
},
padding: "0!important"
padding: "0!important",
},
error: {
"& button": {
marginLeft: theme.spacing(0.6)
marginLeft: theme.spacing(0.6),
},
color: theme.palette.error.main,
marginRight: theme.spacing(1),
alignItems: "flex-end"
alignItems: "flex-end",
},
headerLinkContainer: {
"& svg": {
marginRight: theme.spacing()
marginRight: theme.spacing(),
},
"& span": {
fontWeight: 500
fontWeight: 500,
},
alignItems: "center",
color: theme.palette.text.primary,
@ -97,7 +97,7 @@ export const useStyles = makeStyles(
lineHeight: 1.2,
marginRight: theme.spacing(3),
padding: 0,
textTransform: "none"
textTransform: "none",
},
hr: {
border: "none",
@ -105,20 +105,20 @@ export const useStyles = makeStyles(
height: 0,
marginBottom: 0,
marginTop: 0,
width: "100%"
width: "100%",
},
installAppContainer: {
"& > div": {
position: "relative"
position: "relative",
},
"& img": {
position: "relative"
position: "relative",
},
display: "flex",
justifyContent: "space-between",
padding: theme.spacing(2, 0),
position: "relative",
width: theme.spacing(35)
width: theme.spacing(35),
},
installCard: {
"&:before": {
@ -128,11 +128,11 @@ export const useStyles = makeStyles(
position: "absolute",
top: "50%",
transform: "translateY(-50%)",
width: theme.spacing(30)
width: theme.spacing(30),
},
display: "flex",
justifyContent: "center",
position: "relative"
position: "relative",
},
installIcon: {
alignItems: "center",
@ -143,76 +143,76 @@ export const useStyles = makeStyles(
height: theme.spacing(9),
justifyContent: "center",
overflow: "hidden",
width: theme.spacing(9)
width: theme.spacing(9),
},
installPermissionTitle: {
fontWeight: 500
fontWeight: 500,
},
installPrivacyText: {
"& a": {
color: theme.palette.primary.main,
textDecoration: "none"
textDecoration: "none",
},
color: theme.palette.text.hint,
marginTop: theme.spacing(1)
marginTop: theme.spacing(1),
},
installSaleorIcon: {
backgroundColor: theme.palette.secondary.main,
border: "none"
border: "none",
},
installSpacer: {
margin: theme.spacing(2, 0)
margin: theme.spacing(2, 0),
},
installText: {
color: theme.palette.primary.contrastText
color: theme.palette.primary.contrastText,
},
linkContainer: {
fontWeight: 500,
marginTop: theme.spacing(1.5)
marginTop: theme.spacing(1.5),
},
marketplaceContent: {
"& button": {
marginTop: theme.spacing(1)
marginTop: theme.spacing(1),
},
"&:last-child": {
padding: theme.spacing(2, 3, 2, 3)
padding: theme.spacing(2, 3, 2, 3),
},
padding: theme.spacing(1)
padding: theme.spacing(1),
},
permissionsContainer: {
"& li": {
"&:last-child": {
marginBottom: 0
marginBottom: 0,
},
marginBottom: theme.spacing(1)
marginBottom: theme.spacing(1),
},
paddingLeft: theme.spacing(2)
paddingLeft: theme.spacing(2),
},
retryBtnCol: {
paddingRight: theme.spacing(1),
width: theme.spacing(14)
width: theme.spacing(14),
},
statusWrapper: {
display: "inline-block",
marginLeft: theme.spacing(2.5)
marginLeft: theme.spacing(2.5),
},
table: {
tableLayout: "fixed"
tableLayout: "fixed",
},
tableRow: {
cursor: "pointer"
cursor: "pointer",
},
text: {
color: theme.palette.text.secondary
color: theme.palette.text.secondary,
},
activateButton: {
"& img": {
marginRight: theme.spacing(1)
}
marginRight: theme.spacing(1),
},
},
appUrl: {
marginRight: theme.spacing(1)
}
marginRight: theme.spacing(1),
},
}),
{ name: "AppList" }
{ name: "AppList" },
);

View file

@ -26,7 +26,7 @@ export type AppInstallUrlQueryParams = Partial<{ [MANIFEST_ATTR]: string }>;
export enum AppListUrlSortField {
name = "name",
active = "active"
active = "active",
}
export type CustomAppUrlDialog =
@ -60,20 +60,20 @@ export const appUrl = (id: string, params?: AppDetailsUrlQueryParams) =>
export const appDeepUrl = (
id: string,
subPath: string,
params?: AppDetailsUrlQueryParams
params?: AppDetailsUrlQueryParams,
) => appDeepPath(encodeURIComponent(id), subPath) + "?" + stringifyQs(params);
export const getAppCompleteUrlFromDashboardUrl = (
dashboardUrl: string,
appUrl?: string,
appId?: string
appId?: string,
) => {
if (!appUrl || !appId) {
return appUrl;
}
const deepSubPath = dashboardUrl.replace(
appPath(encodeURIComponent(appId)),
""
"",
);
const appCompleteUrl = urlJoin(appUrl, deepSubPath);
return appCompleteUrl;
@ -81,7 +81,7 @@ export const getAppCompleteUrlFromDashboardUrl = (
export const getDashboardUrFromAppCompleteUrl = (
appCompleteUrl: string,
appUrl?: string,
appId?: string
appId?: string,
) => {
if (!appUrl || !appId) {
return appUrl;

View file

@ -3,7 +3,7 @@ import {
AppExtensionMountEnum,
ExtensionListQuery,
PermissionEnum,
useExtensionListQuery
useExtensionListQuery,
} from "@saleor/graphql";
import { RelayToFlat } from "@saleor/types";
import { mapEdgesToItems } from "@saleor/utils/maps";
@ -23,11 +23,11 @@ export interface Extension {
export const extensionMountPoints = {
PRODUCT_LIST: [
AppExtensionMountEnum.PRODUCT_OVERVIEW_CREATE,
AppExtensionMountEnum.PRODUCT_OVERVIEW_MORE_ACTIONS
AppExtensionMountEnum.PRODUCT_OVERVIEW_MORE_ACTIONS,
],
ORDER_LIST: [
AppExtensionMountEnum.ORDER_OVERVIEW_CREATE,
AppExtensionMountEnum.ORDER_OVERVIEW_MORE_ACTIONS
AppExtensionMountEnum.ORDER_OVERVIEW_MORE_ACTIONS,
],
ORDER_DETAILS: [AppExtensionMountEnum.ORDER_DETAILS_MORE_ACTIONS],
PRODUCT_DETAILS: [AppExtensionMountEnum.PRODUCT_DETAILS_MORE_ACTIONS],
@ -37,13 +37,13 @@ export const extensionMountPoints = {
AppExtensionMountEnum.NAVIGATION_DISCOUNTS,
AppExtensionMountEnum.NAVIGATION_ORDERS,
AppExtensionMountEnum.NAVIGATION_PAGES,
AppExtensionMountEnum.NAVIGATION_TRANSLATIONS
]
AppExtensionMountEnum.NAVIGATION_TRANSLATIONS,
],
};
const filterAndMapToTarget = (
extensions: RelayToFlat<ExtensionListQuery["appExtensions"]>,
openApp: (appData: AppData) => void
openApp: (appData: AppData) => void,
): Extension[] =>
extensions.map(
({ id, accessToken, permissions, url, label, mount, target, app }) => ({
@ -55,44 +55,44 @@ const filterAndMapToTarget = (
label,
mount,
open: () =>
openApp({ id: app.id, appToken: accessToken, src: url, label, target })
})
openApp({ id: app.id, appToken: accessToken, src: url, label, target }),
}),
);
export const mapToMenuItems = (extensions: Extension[]) =>
extensions.map(({ label, id, open }) => ({
label,
testId: `extension-${id}`,
onSelect: open
onSelect: open,
}));
export const useExtensions = <T extends AppExtensionMountEnum>(
mountList: T[]
mountList: T[],
): Record<T, Extension[]> => {
const { openApp } = useExternalApp();
const permissions = useUserPermissions();
const extensionsPermissions = permissions?.find(
perm => perm.code === PermissionEnum.MANAGE_APPS
perm => perm.code === PermissionEnum.MANAGE_APPS,
);
const { data } = useExtensionListQuery({
fetchPolicy: "cache-first",
variables: {
filter: {
mount: mountList
}
mount: mountList,
},
skip: !extensionsPermissions
},
skip: !extensionsPermissions,
});
const extensions = filterAndMapToTarget(
mapEdgesToItems(data?.appExtensions) || [],
openApp
openApp,
);
const extensionsMap = mountList.reduce(
(extensionsMap, mount) => ({ ...extensionsMap, [mount]: [] }),
{} as Record<T, Extension[]>
{} as Record<T, Extension[]>,
);
return extensions.reduce(
@ -100,9 +100,9 @@ export const useExtensions = <T extends AppExtensionMountEnum>(
...prevExtensionsMap,
[extension.mount]: [
...(prevExtensionsMap[extension.mount] || []),
extension
]
extension,
],
}),
extensionsMap
extensionsMap,
);
};

View file

@ -11,7 +11,7 @@ import AppPage from "../../components/AppPage";
import {
appDetailsUrl,
appsListPath,
getAppCompleteUrlFromDashboardUrl
getAppCompleteUrlFromDashboardUrl,
} from "../../urls";
interface AppProps {
@ -22,7 +22,7 @@ export const App: React.FC<AppProps> = ({ id }) => {
const location = useLocation();
const { data } = useAppQuery({
displayLoader: true,
variables: { id }
variables: { id },
});
const appExists = data?.app !== null;
@ -38,7 +38,7 @@ export const App: React.FC<AppProps> = ({ id }) => {
const appCompleteUrl = getAppCompleteUrlFromDashboardUrl(
location.pathname,
data?.app.appUrl,
id
id,
);
return (
@ -49,7 +49,7 @@ export const App: React.FC<AppProps> = ({ id }) => {
onError={() =>
notify({
status: "error",
text: intl.formatMessage(appMessages.failedToFetchAppSettings)
text: intl.formatMessage(appMessages.failedToFetchAppSettings),
})
}
/>

View file

@ -3,7 +3,7 @@ import NotFoundPage from "@saleor/components/NotFoundPage";
import {
useAppActivateMutation,
useAppDeactivateMutation,
useAppQuery
useAppQuery,
} from "@saleor/graphql";
import useNavigator from "@saleor/hooks/useNavigator";
import useNotifier from "@saleor/hooks/useNotifier";
@ -20,7 +20,7 @@ import {
AppDetailsUrlDialog,
AppDetailsUrlQueryParams,
appsListPath,
appUrl
appUrl,
} from "../../urls";
interface AppDetailsProps {
@ -31,7 +31,7 @@ interface AppDetailsProps {
export const AppDetails: React.FC<AppDetailsProps> = ({ id, params }) => {
const { data, loading, refetch } = useAppQuery({
displayLoader: true,
variables: { id }
variables: { id },
});
const appExists = data?.app !== null;
@ -46,7 +46,7 @@ export const AppDetails: React.FC<AppDetailsProps> = ({ id, params }) => {
if (errors?.length === 0) {
notify({
status: "success",
text: intl.formatMessage(appMessages.appActivated)
text: intl.formatMessage(appMessages.appActivated),
});
refetch();
closeModal();
@ -55,12 +55,12 @@ export const AppDetails: React.FC<AppDetailsProps> = ({ id, params }) => {
errors.forEach(error =>
notify({
status: "error",
text: getAppErrorMessage(error, intl)
})
text: getAppErrorMessage(error, intl),
}),
);
}
}
}
},
});
const [deactivateApp, deactivateAppResult] = useAppDeactivateMutation({
onCompleted: data => {
@ -68,7 +68,7 @@ export const AppDetails: React.FC<AppDetailsProps> = ({ id, params }) => {
if (errors.length === 0) {
notify({
status: "success",
text: intl.formatMessage(appMessages.appDeactivated)
text: intl.formatMessage(appMessages.appDeactivated),
});
refetch();
closeModal();
@ -77,12 +77,12 @@ export const AppDetails: React.FC<AppDetailsProps> = ({ id, params }) => {
errors.forEach(error =>
notify({
status: "error",
text: getAppErrorMessage(error, intl)
})
text: getAppErrorMessage(error, intl),
}),
);
}
}
}
},
});
const [openModal, closeModal] = createDialogActionHandlers<

View file

@ -14,7 +14,7 @@ import AppInstallPage from "../../components/AppInstallPage";
import {
AppInstallUrlQueryParams,
appsListUrl,
MANIFEST_ATTR
MANIFEST_ATTR,
} from "../../urls";
import { messages } from "./messages";
@ -22,7 +22,7 @@ interface InstallAppCreateProps extends RouteComponentProps {
params: AppInstallUrlQueryParams;
}
export const InstallAppCreate: React.FC<InstallAppCreateProps> = ({
params
params,
}) => {
const [, setActiveInstallations] = useLocalStorage("activeInstallations", []);
const navigate = useNavigator();
@ -36,11 +36,11 @@ export const InstallAppCreate: React.FC<InstallAppCreateProps> = ({
data.appFetchManifest.errors.forEach(error => {
notify({
status: "error",
text: getAppErrorMessage(error, intl)
text: getAppErrorMessage(error, intl),
});
});
}
}
},
});
const [installApp] = useAppInstallMutation({
onCompleted: data => {
@ -48,18 +48,18 @@ export const InstallAppCreate: React.FC<InstallAppCreateProps> = ({
if (data.appInstall.errors.length === 0) {
setActiveInstallations(activeInstallations => [
...activeInstallations,
{ id: installationData.id, name: installationData.appName }
{ id: installationData.id, name: installationData.appName },
]);
navigateToAppsList();
} else {
data.appInstall.errors.forEach(error => {
notify({
status: "error",
text: getAppErrorMessage(error, intl)
text: getAppErrorMessage(error, intl),
});
});
}
}
},
});
const navigateToAppsList = () => navigate(appsListUrl());
@ -73,11 +73,11 @@ export const InstallAppCreate: React.FC<InstallAppCreateProps> = ({
appName: manifest?.name,
manifestUrl,
permissions: manifest?.permissions.map(
permission => permission.code
)
}
}
})
permission => permission.code,
),
},
},
}),
);
};

View file

@ -4,6 +4,6 @@ export const messages = defineMessages({
installApp: {
id: "2cjt25",
defaultMessage: "Install App",
description: "window title"
}
description: "window title",
},
});

View file

@ -15,7 +15,7 @@ interface AppSettingsProps {
export const AppSettings: React.FC<AppSettingsProps> = ({ id }) => {
const { data } = useAppQuery({
displayLoader: true,
variables: { id }
variables: { id },
});
const appExists = data?.app !== null;
@ -35,7 +35,7 @@ export const AppSettings: React.FC<AppSettingsProps> = ({ id }) => {
onError={() =>
notify({
status: "error",
text: intl.formatMessage(appMessages.failedToFetchAppSettings)
text: intl.formatMessage(appMessages.failedToFetchAppSettings),
})
}
/>

View file

@ -15,7 +15,7 @@ import {
useAppDeleteMutation,
useAppRetryInstallMutation,
useAppsInstallationsQuery,
useAppsListQuery
useAppsListQuery,
} from "@saleor/graphql";
import useListSettings from "@saleor/hooks/useListSettings";
import useLocalStorage from "@saleor/hooks/useLocalStorage";
@ -23,7 +23,7 @@ import useNavigator from "@saleor/hooks/useNavigator";
import useNotifier from "@saleor/hooks/useNotifier";
import usePaginator, {
createPaginationState,
PaginatorContext
PaginatorContext,
} from "@saleor/hooks/usePaginator";
import { ListViews } from "@saleor/types";
import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers";
@ -38,18 +38,18 @@ import {
AppListUrlDialog,
AppListUrlQueryParams,
appsListUrl,
customAppUrl
customAppUrl,
} from "../../urls";
import { messages } from "./messages";
const getCurrentAppName = (
id: string,
collection?: AppsListQuery["apps"]["edges"]
collection?: AppsListQuery["apps"]["edges"],
) => collection?.find(edge => edge.node.id === id)?.node?.name;
const getAppInProgressName = (
id: string,
collection?: AppsInstallationsQuery["appsInstallations"]
collection?: AppsInstallationsQuery["appsInstallations"],
) => collection?.find(app => app.id === id)?.appName;
interface AppsListProps {
params: AppListUrlQueryParams;
@ -69,22 +69,22 @@ export const AppsList: React.FC<AppsListProps> = ({ params }) => {
const queryVariables = {
sort: {
direction: OrderDirection.DESC,
field: AppSortField.CREATION_DATE
}
field: AppSortField.CREATION_DATE,
},
};
const intervalId = useRef<null | number>(null);
const removeInstallation = (id: string) =>
setActiveInstallations(installations =>
installations.filter(item => item.id !== id)
installations.filter(item => item.id !== id),
);
const {
data: appsInProgressData,
loading: loadingAppsInProgress,
refetch: appsInProgressRefetch
refetch: appsInProgressRefetch,
} = useAppsInstallationsQuery({
displayLoader: false
displayLoader: false,
});
const { data, loading, refetch } = useAppsListQuery({
displayLoader: true,
@ -92,35 +92,35 @@ export const AppsList: React.FC<AppsListProps> = ({ params }) => {
...paginationState,
...queryVariables,
filter: {
type: AppTypeEnum.THIRDPARTY
}
}
type: AppTypeEnum.THIRDPARTY,
},
},
});
const paginationValues = usePaginator({
pageInfo: data?.apps?.pageInfo,
paginationState,
queryString: params
queryString: params,
});
const {
data: customAppsData,
loading: customAppsLoading,
refetch: customAppsRefetch
refetch: customAppsRefetch,
} = useAppsListQuery({
displayLoader: true,
variables: {
first: 100,
...queryVariables,
filter: {
type: AppTypeEnum.LOCAL
}
}
type: AppTypeEnum.LOCAL,
},
},
});
const refetchExtensionList = () => {
client.refetchQueries({
include: [EXTENSION_LIST_QUERY]
include: [EXTENSION_LIST_QUERY],
});
};
@ -128,7 +128,7 @@ export const AppsList: React.FC<AppsListProps> = ({ params }) => {
notify({
status: "success",
text: intl.formatMessage(messages.appReadyToUse, { name }),
title: intl.formatMessage(messages.appInstalled)
title: intl.formatMessage(messages.appInstalled),
});
};
const [retryInstallApp] = useAppRetryInstallMutation({
@ -137,34 +137,34 @@ export const AppsList: React.FC<AppsListProps> = ({ params }) => {
const appInstallation = data.appRetryInstall.appInstallation;
setActiveInstallations(installations => [
...installations,
{ id: appInstallation.id, name: appInstallation.appName }
{ id: appInstallation.id, name: appInstallation.appName },
]);
}
}
},
});
const [activateApp, activateAppResult] = useAppActivateMutation({
onCompleted: data => {
if (!data?.appActivate?.errors?.length) {
notify({
status: "success",
text: intl.formatMessage(messages.appActivated)
text: intl.formatMessage(messages.appActivated),
});
refetch();
closeModal();
}
}
},
});
const [deactivateApp, deactivateAppResult] = useAppDeactivateMutation({
onCompleted: data => {
if (!data?.appDeactivate?.errors?.length) {
notify({
status: "success",
text: intl.formatMessage(messages.appDeactivated)
text: intl.formatMessage(messages.appDeactivated),
});
refetch();
closeModal();
}
}
},
});
const [openModal, closeModal] = createDialogActionHandlers<
AppListUrlDialog,
@ -183,11 +183,11 @@ export const AppsList: React.FC<AppsListProps> = ({ params }) => {
refetchExtensionList();
removeAppNotify();
}
}
},
});
const [
deleteInProgressApp,
deleteInProgressAppOpts
deleteInProgressAppOpts,
] = useAppDeleteFailedInstallationMutation({
onCompleted: data => {
if (!data?.appDeleteFailedInstallation?.errors?.length) {
@ -195,7 +195,7 @@ export const AppsList: React.FC<AppsListProps> = ({ params }) => {
appsInProgressRefetch();
closeModal();
}
}
},
});
useEffect(() => {
@ -204,7 +204,7 @@ export const AppsList: React.FC<AppsListProps> = ({ params }) => {
if (!intervalId.current) {
intervalId.current = window.setInterval(
() => appsInProgressRefetch(),
2000
2000,
);
}
let newAppInstalled = false;
@ -226,8 +226,8 @@ export const AppsList: React.FC<AppsListProps> = ({ params }) => {
status: "error",
text: item.message,
title: intl.formatMessage(messages.appCouldntInstall, {
name: item.appName
})
name: item.appName,
}),
});
}
});
@ -251,21 +251,21 @@ export const AppsList: React.FC<AppsListProps> = ({ params }) => {
const handleRemoveInProgressConfirm = () =>
deleteInProgressApp({
variables: {
id: params.id
}
id: params.id,
},
});
const handleRemoveConfirm = () =>
deleteApp({
variables: {
id: params.id
}
id: params.id,
},
});
const removeAppNotify = () => {
notify({
status: "success",
text: intl.formatMessage(messages.appRemoved)
text: intl.formatMessage(messages.appRemoved),
});
};
@ -284,9 +284,9 @@ export const AppsList: React.FC<AppsListProps> = ({ params }) => {
const context: AppListContextValues = React.useMemo(
() => ({
activateApp: id => openModal("app-activate", { id }),
deactivateApp: id => openModal("app-deactivate", { id })
deactivateApp: id => openModal("app-deactivate", { id }),
}),
[activateApp, deactivateApp]
[activateApp, deactivateApp],
);
return (
@ -296,7 +296,7 @@ export const AppsList: React.FC<AppsListProps> = ({ params }) => {
confirmButtonState={deleteAppOpts.status}
name={getCurrentAppName(
params.id,
action === "remove-app" ? installedApps : customApps
action === "remove-app" ? installedApps : customApps,
)}
onClose={closeModal}
onConfirm={handleRemoveConfirm}
@ -321,7 +321,7 @@ export const AppsList: React.FC<AppsListProps> = ({ params }) => {
confirmButtonState={deleteInProgressAppOpts.status}
name={getAppInProgressName(
params.id,
appsInProgressData?.appsInstallations
appsInProgressData?.appsInstallations,
)}
onClose={closeModal}
onConfirm={handleRemoveInProgressConfirm}
@ -339,17 +339,17 @@ export const AppsList: React.FC<AppsListProps> = ({ params }) => {
getCustomAppHref={id => customAppUrl(id)}
onInstalledAppRemove={id =>
openModal("remove-app", {
id
id,
})
}
onCustomAppRemove={id =>
openModal("remove-custom-app", {
id
id,
})
}
onAppInProgressRemove={id =>
openModal("remove", {
id
id,
})
}
/>

View file

@ -4,31 +4,31 @@ export const messages = defineMessages({
appInstalled: {
id: "0fM/pV",
defaultMessage: "App installed",
description: "message title"
description: "message title",
},
appRemoved: {
id: "uIPD1i",
defaultMessage: "App successfully removed",
description: "app has been removed"
description: "app has been removed",
},
appReadyToUse: {
id: "ZprV2g",
defaultMessage: "{name} is ready to be used",
description: "app has been installed"
description: "app has been installed",
},
appCouldntInstall: {
id: "5t/4um",
defaultMessage: "Couldnt Install {name}",
description: "message title"
description: "message title",
},
appActivated: {
id: "D/+84n",
defaultMessage: "App activated",
description: "snackbar text"
description: "snackbar text",
},
appDeactivated: {
id: "USO8PB",
defaultMessage: "App deactivated",
description: "snackbar text"
}
description: "snackbar text",
},
});

View file

@ -9,7 +9,7 @@ import React from "react";
import { useIntl } from "react-intl";
import CustomAppCreatePage, {
CustomAppCreatePageFormData
CustomAppCreatePageFormData,
} from "../../components/CustomAppCreatePage";
import { customAppUrl } from "../../urls";
import { messages } from "./messages";
@ -18,7 +18,7 @@ interface CustomAppCreateProps {
setToken: (token: string) => void;
}
export const CustomAppCreate: React.FC<CustomAppCreateProps> = ({
setToken
setToken,
}) => {
const navigate = useNavigator();
const notify = useNotifier();
@ -29,7 +29,7 @@ export const CustomAppCreate: React.FC<CustomAppCreateProps> = ({
if (data.appCreate.errors.length === 0) {
notify({
status: "success",
text: intl.formatMessage(commonMessages.savedChanges)
text: intl.formatMessage(commonMessages.savedChanges),
});
navigate(customAppUrl(data.appCreate.app.id));
setToken(data.appCreate.authToken);
@ -37,7 +37,7 @@ export const CustomAppCreate: React.FC<CustomAppCreateProps> = ({
};
const [createApp, createAppOpts] = useAppCreateMutation({
onCompleted: onSubmit
onCompleted: onSubmit,
});
const handleSubmit = async (data: CustomAppCreatePageFormData) =>
@ -48,10 +48,10 @@ export const CustomAppCreate: React.FC<CustomAppCreateProps> = ({
name: data.name,
permissions: data.hasFullAccess
? shop.permissions.map(permission => permission.code)
: data.permissions
}
}
})
: data.permissions,
},
},
}),
);
return (

View file

@ -4,6 +4,6 @@ export const messages = defineMessages({
createApp: {
id: "agZQkB",
defaultMessage: "Create App",
description: "window title"
}
description: "window title",
},
});

View file

@ -17,7 +17,7 @@ import {
useAppTokenDeleteMutation,
useAppUpdateMutation,
useWebhookDeleteMutation,
WebhookDeleteMutation
WebhookDeleteMutation,
} from "@saleor/graphql";
import useNavigator from "@saleor/hooks/useNavigator";
import useNotifier from "@saleor/hooks/useNotifier";
@ -32,13 +32,13 @@ import React from "react";
import { useIntl } from "react-intl";
import CustomAppDetailsPage, {
CustomAppDetailsPageFormData
CustomAppDetailsPageFormData,
} from "../../components/CustomAppDetailsPage";
import {
appsListUrl,
customAppUrl,
CustomAppUrlDialog,
CustomAppUrlQueryParams
CustomAppUrlQueryParams,
} from "../../urls";
interface OrderListProps {
@ -52,7 +52,7 @@ export const CustomAppDetails: React.FC<OrderListProps> = ({
id,
params,
token,
onTokenClose
onTokenClose,
}) => {
const navigate = useNavigator();
const notify = useNotifier();
@ -68,7 +68,7 @@ export const CustomAppDetails: React.FC<OrderListProps> = ({
const { data, loading, refetch } = useAppQuery({
displayLoader: true,
variables: { id }
variables: { id },
});
const [activateApp, activateAppResult] = useAppActivateMutation({
onCompleted: data => {
@ -76,7 +76,7 @@ export const CustomAppDetails: React.FC<OrderListProps> = ({
if (errors?.length === 0) {
notify({
status: "success",
text: intl.formatMessage(appMessages.appActivated)
text: intl.formatMessage(appMessages.appActivated),
});
refetch();
closeModal();
@ -84,11 +84,11 @@ export const CustomAppDetails: React.FC<OrderListProps> = ({
errors.forEach(error =>
notify({
status: "error",
text: getAppErrorMessage(error, intl)
})
text: getAppErrorMessage(error, intl),
}),
);
}
}
},
});
const [deactivateApp, deactivateAppResult] = useAppDeactivateMutation({
onCompleted: data => {
@ -96,7 +96,7 @@ export const CustomAppDetails: React.FC<OrderListProps> = ({
if (errors.length === 0) {
notify({
status: "success",
text: intl.formatMessage(appMessages.appDeactivated)
text: intl.formatMessage(appMessages.appDeactivated),
});
refetch();
closeModal();
@ -104,18 +104,18 @@ export const CustomAppDetails: React.FC<OrderListProps> = ({
errors.forEach(error =>
notify({
status: "error",
text: getAppErrorMessage(error, intl)
})
text: getAppErrorMessage(error, intl),
}),
);
}
}
},
});
const onWebhookDelete = (data: WebhookDeleteMutation) => {
if (data.webhookDelete.errors.length === 0) {
notify({
status: "success",
text: intl.formatMessage(commonMessages.savedChanges)
text: intl.formatMessage(commonMessages.savedChanges),
});
navigate(customAppUrl(id));
closeModal();
@ -124,14 +124,14 @@ export const CustomAppDetails: React.FC<OrderListProps> = ({
};
const [webhookDelete, webhookDeleteOpts] = useWebhookDeleteMutation({
onCompleted: onWebhookDelete
onCompleted: onWebhookDelete,
});
const handleRemoveWebhookConfirm = () => {
webhookDelete({
variables: {
id: params.id
}
id: params.id,
},
});
};
@ -139,7 +139,7 @@ export const CustomAppDetails: React.FC<OrderListProps> = ({
if (data?.appUpdate?.errors?.length === 0) {
notify({
status: "success",
text: intl.formatMessage(commonMessages.savedChanges)
text: intl.formatMessage(commonMessages.savedChanges),
});
}
};
@ -158,7 +158,7 @@ export const CustomAppDetails: React.FC<OrderListProps> = ({
if (data?.appTokenDelete?.errors.length === 0) {
notify({
status: "success",
text: intl.formatMessage(commonMessages.savedChanges)
text: intl.formatMessage(commonMessages.savedChanges),
});
refetch();
closeModal();
@ -166,13 +166,13 @@ export const CustomAppDetails: React.FC<OrderListProps> = ({
};
const [updateApp, updateAppOpts] = useAppUpdateMutation({
onCompleted: onAppUpdate
onCompleted: onAppUpdate,
});
const [createToken, createTokenOpts] = useAppTokenCreateMutation({
onCompleted: onTokenCreate
onCompleted: onTokenCreate,
});
const [deleteToken, deleteTokenOpts] = useAppTokenDeleteMutation({
onCompleted: onTokenDelete
onCompleted: onTokenDelete,
});
const handleSubmit = async (data: CustomAppDetailsPageFormData) =>
@ -184,10 +184,10 @@ export const CustomAppDetails: React.FC<OrderListProps> = ({
name: data.name,
permissions: data.hasFullAccess
? shop.permissions.map(permission => permission.code)
: data.permissions
}
}
})
: data.permissions,
},
},
}),
);
const handleTokenCreate = (name: string) =>
@ -195,16 +195,16 @@ export const CustomAppDetails: React.FC<OrderListProps> = ({
variables: {
input: {
app: id,
name
}
}
name,
},
},
});
const handleTokenDelete = () =>
deleteToken({
variables: {
id: params.id
}
id: params.id,
},
});
const handleActivateConfirm = () => {
@ -230,13 +230,13 @@ export const CustomAppDetails: React.FC<OrderListProps> = ({
onTokenCreate={() => openModal("create-token")}
onTokenDelete={id =>
openModal("remove-token", {
id
id,
})
}
webhookCreateHref={webhookAddPath(id)}
onWebhookRemove={id =>
openModal("remove-webhook", {
id
id,
})
}
onAppActivateOpen={() => openModal("app-activate")}

View file

@ -17,7 +17,7 @@ const AttributeBulkDeleteDialog: React.FC<AttributeBulkDeleteDialogProps> = ({
quantity,
onClose,
onConfirm,
open
open,
}) => {
const intl = useIntl();
@ -30,7 +30,7 @@ const AttributeBulkDeleteDialog: React.FC<AttributeBulkDeleteDialogProps> = ({
title={intl.formatMessage({
id: "rKf4LU",
defaultMessage: "Delete attributes",
description: "dialog title"
description: "dialog title",
})}
variant="delete"
>
@ -41,7 +41,7 @@ const AttributeBulkDeleteDialog: React.FC<AttributeBulkDeleteDialogProps> = ({
description="dialog content"
values={{
counter: quantity,
displayQuantity: <strong>{quantity}</strong>
displayQuantity: <strong>{quantity}</strong>,
}}
/>
</DialogContentText>

View file

@ -17,7 +17,7 @@ const AttributeDeleteDialog: React.FC<AttributeDeleteDialogProps> = ({
confirmButtonState,
onClose,
onConfirm,
open
open,
}) => {
const intl = useIntl();
@ -31,7 +31,7 @@ const AttributeDeleteDialog: React.FC<AttributeDeleteDialogProps> = ({
title={intl.formatMessage({
id: "JI2Xwp",
defaultMessage: "Delete attribute",
description: "dialog title"
description: "dialog title",
})}
>
<DialogContentText>
@ -40,7 +40,7 @@ const AttributeDeleteDialog: React.FC<AttributeDeleteDialogProps> = ({
defaultMessage="Are you sure you want to delete {attributeName}?"
description="dialog content"
values={{
attributeName: <strong>{name}</strong>
attributeName: <strong>{name}</strong>,
}}
/>
</DialogContentText>

View file

@ -7,7 +7,7 @@ import SingleSelectField from "@saleor/components/SingleSelectField";
import {
AttributeEntityTypeEnum,
AttributeErrorFragment,
AttributeInputTypeEnum
AttributeInputTypeEnum,
} from "@saleor/graphql";
import { UseFormResult } from "@saleor/hooks/useForm";
import { commonMessages } from "@saleor/intl";
@ -26,13 +26,13 @@ const entityTypeMessages = defineMessages({
page: {
id: "Iafyt5",
defaultMessage: "Pages",
description: "page attribute entity type"
description: "page attribute entity type",
},
product: {
id: "5TUpjG",
defaultMessage: "Products",
description: "product attribute entity type"
}
description: "product attribute entity type",
},
});
const useStyles = makeStyles(
@ -42,11 +42,11 @@ const useStyles = makeStyles(
display: "flex",
[theme.breakpoints.down("md")]: {
flexFlow: "wrap",
rowGap: theme.spacing(3)
}
}
rowGap: theme.spacing(3),
},
},
}),
{ name: "AttributeDetails" }
{ name: "AttributeDetails" },
);
export interface AttributeDetailsProps
@ -70,66 +70,66 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = props => {
disabled,
apiErrors,
onChange,
set
set,
} = props;
const classes = useStyles(props);
const intl = useIntl();
const inputTypeChoices = [
{
label: intl.formatMessage(inputTypeMessages.dropdown),
value: AttributeInputTypeEnum.DROPDOWN
value: AttributeInputTypeEnum.DROPDOWN,
},
{
label: intl.formatMessage(inputTypeMessages.multiselect),
value: AttributeInputTypeEnum.MULTISELECT
value: AttributeInputTypeEnum.MULTISELECT,
},
{
label: intl.formatMessage(inputTypeMessages.file),
value: AttributeInputTypeEnum.FILE
value: AttributeInputTypeEnum.FILE,
},
{
label: intl.formatMessage(inputTypeMessages.references),
value: AttributeInputTypeEnum.REFERENCE
value: AttributeInputTypeEnum.REFERENCE,
},
{
label: intl.formatMessage(inputTypeMessages.text),
value: AttributeInputTypeEnum.RICH_TEXT
value: AttributeInputTypeEnum.RICH_TEXT,
},
{
label: intl.formatMessage(inputTypeMessages.numeric),
value: AttributeInputTypeEnum.NUMERIC
value: AttributeInputTypeEnum.NUMERIC,
},
{
label: intl.formatMessage(inputTypeMessages.boolean),
value: AttributeInputTypeEnum.BOOLEAN
value: AttributeInputTypeEnum.BOOLEAN,
},
{
label: intl.formatMessage(inputTypeMessages.date),
value: AttributeInputTypeEnum.DATE
value: AttributeInputTypeEnum.DATE,
},
{
label: intl.formatMessage(inputTypeMessages.dateTime),
value: AttributeInputTypeEnum.DATE_TIME
value: AttributeInputTypeEnum.DATE_TIME,
},
{
label: intl.formatMessage(inputTypeMessages.swatch),
value: AttributeInputTypeEnum.SWATCH
}
value: AttributeInputTypeEnum.SWATCH,
},
];
const entityTypeChoices = [
{
label: intl.formatMessage(entityTypeMessages.page),
value: AttributeEntityTypeEnum.PAGE
value: AttributeEntityTypeEnum.PAGE,
},
{
label: intl.formatMessage(entityTypeMessages.product),
value: AttributeEntityTypeEnum.PRODUCT
}
value: AttributeEntityTypeEnum.PRODUCT,
},
];
const formApiErrors = getFormErrors(
["name", "slug", "inputType", "entityType", "unit"],
apiErrors
apiErrors,
);
return (

View file

@ -15,7 +15,7 @@ import {
UnitSystem,
unitSystemChoices,
UnitType,
unitTypeChoices
unitTypeChoices,
} from "./utils";
const useStyles = makeStyles(
@ -25,18 +25,18 @@ const useStyles = makeStyles(
display: "flex",
[theme.breakpoints.down("sm")]: {
flexFlow: "wrap",
rowGap: theme.spacing(3)
}
rowGap: theme.spacing(3),
},
},
hr: {
border: "none",
borderTop: `1px solid ${theme.palette.divider}`,
height: 0,
margin: "0.5rem 0",
width: "100%"
}
width: "100%",
},
}),
{ name: "NumericUnits" }
{ name: "NumericUnits" },
);
interface UnitData {
@ -59,32 +59,32 @@ export const NumericUnits: React.FC<NumericUnitsProps> = ({
errors,
set,
setError,
clearErrors
clearErrors,
}) => {
const { formatMessage } = useIntl();
const classes = useStyles();
const [unitData, setUnitData] = useState<UnitData>({
unit: data.unit ?? null
unit: data.unit ?? null,
});
const { unit, system, type } = unitData;
const errorProps = {
error: !!errors.unit,
hint: formatMessage(commonMessages.requiredField)
hint: formatMessage(commonMessages.requiredField),
};
const [typeChoices, systemChoices, unitChoices] = useMemo(
() => [
unitTypeChoices.map(choice => ({
...choice,
label: formatMessage(choice.label)
label: formatMessage(choice.label),
})),
unitSystemChoices.map(choice => ({
...choice,
label: formatMessage(choice.label)
label: formatMessage(choice.label),
})),
getUnitChoices(formatMessage)
getUnitChoices(formatMessage),
],
[]
[],
);
useEffect(() => set({ unit }), [unit]);
@ -158,7 +158,7 @@ export const NumericUnits: React.FC<NumericUnitsProps> = ({
onChange={({ target }: React.ChangeEvent<HTMLSelectElement>) =>
setUnitData(({ system }) => ({
system,
type: target.value as UnitType
type: target.value as UnitType,
}))
}
disabled={!system || disabled}
@ -172,7 +172,7 @@ export const NumericUnits: React.FC<NumericUnitsProps> = ({
onChange={({ target }: React.ChangeEvent<HTMLSelectElement>) =>
setUnitData(data => ({
...data,
unit: target.value as MeasurementUnitsEnum
unit: target.value as MeasurementUnitsEnum,
}))
}
disabled={!type || disabled}

View file

@ -5,144 +5,144 @@ export const messages = defineMessages({
attributeLabel: {
id: "xOEZjV",
defaultMessage: "Default Label",
description: "attribute's label"
description: "attribute's label",
},
attributeSlug: {
id: "P79U4b",
defaultMessage: "Attribute Code",
description: "attribute's slug short code label"
description: "attribute's slug short code label",
},
attributeSlugHelperText: {
id: "Q7uuDr",
defaultMessage: "This is used internally. Make sure you dont use spaces",
description: "attribute slug input field helper text"
description: "attribute slug input field helper text",
},
entityType: {
id: "LnRlch",
defaultMessage: "Entity",
description: "attribute's editor component entity"
description: "attribute's editor component entity",
},
inputType: {
id: "oIvtua",
defaultMessage: "Catalog Input type for Store Owner",
description: "attribute's editor component"
description: "attribute's editor component",
},
valueRequired: {
id: "njBulj",
defaultMessage: "Value Required",
description: "check to require attribute to have value"
description: "check to require attribute to have value",
},
selectUnit: {
id: "PiSXjb",
defaultMessage: "Select unit",
description: "check to require numeric attribute unit"
description: "check to require numeric attribute unit",
},
unitSystem: {
id: "ghje1I",
defaultMessage: "System",
description: "numeric attribute unit system"
description: "numeric attribute unit system",
},
unitOf: {
id: "zWM89r",
defaultMessage: "Units of",
description: "numeric attribute units of"
description: "numeric attribute units of",
},
unit: {
id: "Orgqv4",
defaultMessage: "Unit",
description: "numeric attribute unit"
}
description: "numeric attribute unit",
},
});
export const inputTypeMessages = defineMessages({
dropdown: {
id: "bZksto",
defaultMessage: "Dropdown",
description: "product attribute type"
description: "product attribute type",
},
file: {
id: "z1y9oL",
defaultMessage: "File",
description: "file attribute type"
description: "file attribute type",
},
multiselect: {
id: "cKjFfl",
defaultMessage: "Multiple Select",
description: "product attribute type"
description: "product attribute type",
},
references: {
id: "5dLpx0",
defaultMessage: "References",
description: "references attribute type"
description: "references attribute type",
},
text: {
id: "fdbqIs",
defaultMessage: "Text",
description: "text attribute type"
description: "text attribute type",
},
numeric: {
id: "SNiyXb",
defaultMessage: "Numeric",
description: "numeric attribute type"
description: "numeric attribute type",
},
boolean: {
id: "l5V0QT",
defaultMessage: "Boolean",
description: "boolean attribute type"
description: "boolean attribute type",
},
date: {
id: "fU+a9k",
defaultMessage: "Date",
description: "date attribute type"
description: "date attribute type",
},
dateTime: {
id: "DzPVnj",
defaultMessage: "Date Time",
description: "date time attribute type"
description: "date time attribute type",
},
swatch: {
id: "gx4wCT",
defaultMessage: "Swatch",
description: "swatch attribute type"
}
description: "swatch attribute type",
},
});
export const unitSystemMessages = defineMessages({
metric: {
id: "ZayvsI",
defaultMessage: "Metric",
description: "metric unit system"
description: "metric unit system",
},
imperial: {
id: "YgE6ga",
defaultMessage: "Imperial",
description: "imperial unit system"
}
description: "imperial unit system",
},
});
export const unitTypeMessages = defineMessages({
volume: {
id: "cy8sV7",
defaultMessage: "Volume",
description: "volume units types"
description: "volume units types",
},
distance: {
id: "k/mTEl",
defaultMessage: "Distance",
description: "distance units type"
description: "distance units type",
},
weight: {
id: "Vdy5g7",
defaultMessage: "Weight",
description: "weight units type"
description: "weight units type",
},
area: {
id: "A9QSur",
defaultMessage: "Area",
description: "area units type"
}
description: "area units type",
},
});
export const unitMessages = defineMessages({
@ -150,13 +150,13 @@ export const unitMessages = defineMessages({
acreInch: {
id: "jBu2yj",
defaultMessage: "acre-inch",
description: "acre-inch unit"
description: "acre-inch unit",
},
acreFt: {
id: "5XG1CO",
defaultMessage: "acre-ft",
description: "acre-ft unit"
}
description: "acre-ft unit",
},
});
export const units = {
@ -188,5 +188,5 @@ export const units = {
lbs: "lbs",
squareFt: <>ft&sup2;</>,
squareYd: <>yd&sup2;</>,
squareInch: <>in&sup2;</>
squareInch: <>in&sup2;</>,
};

View file

@ -37,12 +37,12 @@ const UNIT_MESSAGES_MAPPING = {
[MeasurementUnitsEnum.TONNE]: M.units.tonne,
[MeasurementUnitsEnum.SQ_CM]: M.units.squareCentimeter,
[MeasurementUnitsEnum.SQ_M]: M.units.squareMeter,
[MeasurementUnitsEnum.SQ_KM]: M.units.squareKilometer
[MeasurementUnitsEnum.SQ_KM]: M.units.squareKilometer,
};
export const getMeasurementUnitMessage = (
unit: MeasurementUnitsEnum,
formatMessage: IntlShape["formatMessage"]
formatMessage: IntlShape["formatMessage"],
): MessageDescriptor | React.ReactNode => {
const message = UNIT_MESSAGES_MAPPING[unit];
return typeof message === "string" || React.isValidElement(message)
@ -53,31 +53,31 @@ export const getMeasurementUnitMessage = (
export const unitSystemChoices: Array<Choice<UnitSystem, MessageDescriptor>> = [
{
label: M.unitSystemMessages.metric,
value: "metric"
value: "metric",
},
{
label: M.unitSystemMessages.imperial,
value: "imperial"
}
value: "imperial",
},
];
export const unitTypeChoices: Array<Choice<UnitType, MessageDescriptor>> = [
{
label: M.unitTypeMessages.volume,
value: "volume"
value: "volume",
},
{
label: M.unitTypeMessages.distance,
value: "distance"
value: "distance",
},
{
label: M.unitTypeMessages.weight,
value: "weight"
value: "weight",
},
{
label: M.unitTypeMessages.area,
value: "area"
}
value: "area",
},
];
export const unitMapping = {
@ -90,64 +90,64 @@ export const unitMapping = {
MeasurementUnitsEnum.FL_OZ,
MeasurementUnitsEnum.PINT,
MeasurementUnitsEnum.ACRE_IN,
MeasurementUnitsEnum.ACRE_FT
MeasurementUnitsEnum.ACRE_FT,
],
distance: [
MeasurementUnitsEnum.FT,
MeasurementUnitsEnum.YD,
MeasurementUnitsEnum.INCH
MeasurementUnitsEnum.INCH,
],
weight: [MeasurementUnitsEnum.LB, MeasurementUnitsEnum.OZ],
area: [
MeasurementUnitsEnum.SQ_FT,
MeasurementUnitsEnum.SQ_YD,
MeasurementUnitsEnum.SQ_INCH
]
MeasurementUnitsEnum.SQ_INCH,
],
},
metric: {
volume: [
MeasurementUnitsEnum.CUBIC_CENTIMETER,
MeasurementUnitsEnum.CUBIC_DECIMETER,
MeasurementUnitsEnum.CUBIC_METER,
MeasurementUnitsEnum.LITER
MeasurementUnitsEnum.LITER,
],
distance: [
MeasurementUnitsEnum.CM,
MeasurementUnitsEnum.M,
MeasurementUnitsEnum.KM
MeasurementUnitsEnum.KM,
],
weight: [
MeasurementUnitsEnum.G,
MeasurementUnitsEnum.KG,
MeasurementUnitsEnum.TONNE
MeasurementUnitsEnum.TONNE,
],
area: [
MeasurementUnitsEnum.SQ_CM,
MeasurementUnitsEnum.SQ_M,
MeasurementUnitsEnum.SQ_KM
]
}
MeasurementUnitsEnum.SQ_KM,
],
},
};
const extractTypeChoices = (
typeEnums: {
[key in UnitType]: MeasurementUnitsEnum[];
},
formatMessage: IntlShape["formatMessage"]
formatMessage: IntlShape["formatMessage"],
) =>
Object.entries(typeEnums).reduce(
(acc, [type, units]) => ({
...acc,
[type]: units.map(unit => ({
value: unit,
label: getMeasurementUnitMessage(unit, formatMessage)
}))
label: getMeasurementUnitMessage(unit, formatMessage),
})),
}),
{}
{},
);
export const getUnitChoices = (
formatMessage: IntlShape["formatMessage"]
formatMessage: IntlShape["formatMessage"],
): {
[key in UnitSystem]: {
[key in UnitType]: Array<Choice<MeasurementUnitsEnum>>;
@ -156,9 +156,9 @@ export const getUnitChoices = (
Object.entries(unitMapping).reduce(
(acc, [system, typeEnums]) => ({
...acc,
[system]: extractTypeChoices(typeEnums, formatMessage)
[system]: extractTypeChoices(typeEnums, formatMessage),
}),
{}
{},
) as {
[key in UnitSystem]: {
[key in UnitType]: Array<Choice<MeasurementUnitsEnum>>;

View file

@ -1,7 +1,7 @@
import { TableBody, TableCell, TableFooter, TableRow } from "@material-ui/core";
import {
AttributeListUrlSortField,
attributeUrl
attributeUrl,
} from "@saleor/attributes/urls";
import Checkbox from "@saleor/components/Checkbox";
import ResponsiveTable from "@saleor/components/ResponsiveTable";
@ -30,39 +30,39 @@ const useStyles = makeStyles(
theme => ({
[theme.breakpoints.up("lg")]: {
colFaceted: {
width: 180
width: 180,
},
colName: {
width: "auto"
width: "auto",
},
colSearchable: {
width: 180
width: 180,
},
colSlug: {
width: 200
width: 200,
},
colVisible: {
width: 180
}
width: 180,
},
},
colFaceted: {
textAlign: "center"
textAlign: "center",
},
colName: {},
colSearchable: {
textAlign: "center"
textAlign: "center",
},
colSlug: {
paddingLeft: 0
paddingLeft: 0,
},
colVisible: {
textAlign: "center"
textAlign: "center",
},
link: {
cursor: "pointer"
}
cursor: "pointer",
},
}),
{ name: "AttributeList" }
{ name: "AttributeList" },
);
const numberOfColumns = 6;
@ -76,7 +76,7 @@ const AttributeList: React.FC<AttributeListProps> = ({
toggle,
toggleAll,
toolbar,
onSort
onSort,
}) => {
const classes = useStyles({});
const intl = useIntl();
@ -216,7 +216,7 @@ const AttributeList: React.FC<AttributeListProps> = ({
className={classes.colSearchable}
data-test-id="searchable"
data-test-searchable={maybe(
() => attribute.filterableInDashboard
() => attribute.filterableInDashboard,
)}
>
{attribute ? (
@ -229,7 +229,7 @@ const AttributeList: React.FC<AttributeListProps> = ({
className={classes.colFaceted}
data-test-id="use-in-faceted-search"
data-test-use-in-faceted-search={maybe(
() => attribute.filterableInStorefront
() => attribute.filterableInStorefront,
)}
>
{attribute ? (
@ -250,7 +250,7 @@ const AttributeList: React.FC<AttributeListProps> = ({
/>
</TableCell>
</TableRow>
)
),
)}
</TableBody>
</ResponsiveTable>

View file

@ -1,7 +1,7 @@
import { Card } from "@material-ui/core";
import {
attributeAddUrl,
AttributeListUrlSortField
AttributeListUrlSortField,
} from "@saleor/attributes/urls";
import { Backlink } from "@saleor/components/Backlink";
import { Button } from "@saleor/components/Button";
@ -19,13 +19,13 @@ import {
ListActions,
PageListProps,
SortPage,
TabPageProps
TabPageProps,
} from "../../../types";
import AttributeList from "../AttributeList/AttributeList";
import {
AttributeFilterKeys,
AttributeListFilterOpts,
createFilterStructure
createFilterStructure,
} from "./filters";
export interface AttributeListPageProps
@ -77,14 +77,14 @@ const AttributeListPage: React.FC<AttributeListPageProps> = ({
allTabLabel={intl.formatMessage({
id: "dKPMyh",
defaultMessage: "All Attributes",
description: "tab name"
description: "tab name",
})}
currentTab={currentTab}
filterStructure={structure}
initialSearch={initialSearch}
searchPlaceholder={intl.formatMessage({
id: "1div9r",
defaultMessage: "Search Attribute"
defaultMessage: "Search Attribute",
})}
tabs={tabs}
onAll={onAll}

View file

@ -8,7 +8,7 @@ export enum AttributeFilterKeys {
filterableInStorefront = "filterableInStorefront",
isVariantOnly = "isVariantOnly",
valueRequired = "valueRequired",
visibleInStorefront = "visibleInStorefront"
visibleInStorefront = "visibleInStorefront",
}
export interface AttributeListFilterOpts {
@ -22,28 +22,28 @@ const messages = defineMessages({
filterableInStorefront: {
id: "PsRG+v",
defaultMessage: "Filterable in Storefront",
description: "use attribute in filtering"
description: "use attribute in filtering",
},
isVariantOnly: {
id: "rvk9ls",
defaultMessage: "Variant Only",
description: "attribute can be used only in variants"
description: "attribute can be used only in variants",
},
valueRequired: {
id: "HQR2y0",
defaultMessage: "Value Required",
description: "attribute value is required"
description: "attribute value is required",
},
visibleInStorefront: {
id: "cvbqJu",
defaultMessage: "Visible on Product Page in Storefront",
description: "attribute"
}
description: "attribute",
},
});
export function createFilterStructure(
intl: IntlShape,
opts: AttributeListFilterOpts
opts: AttributeListFilterOpts,
): IFilter<AttributeFilterKeys> {
return [
{
@ -53,10 +53,10 @@ export function createFilterStructure(
opts.filterableInStorefront.value,
{
negative: intl.formatMessage(commonMessages.no),
positive: intl.formatMessage(commonMessages.yes)
}
positive: intl.formatMessage(commonMessages.yes),
},
),
active: opts.filterableInStorefront.active
active: opts.filterableInStorefront.active,
},
{
...createBooleanField(
@ -65,10 +65,10 @@ export function createFilterStructure(
opts.isVariantOnly.value,
{
negative: intl.formatMessage(commonMessages.no),
positive: intl.formatMessage(commonMessages.yes)
}
positive: intl.formatMessage(commonMessages.yes),
},
),
active: opts.isVariantOnly.active
active: opts.isVariantOnly.active,
},
{
...createBooleanField(
@ -77,10 +77,10 @@ export function createFilterStructure(
opts.valueRequired.value,
{
negative: intl.formatMessage(commonMessages.no),
positive: intl.formatMessage(commonMessages.yes)
}
positive: intl.formatMessage(commonMessages.yes),
},
),
active: opts.valueRequired.active
active: opts.valueRequired.active,
},
{
...createBooleanField(
@ -89,10 +89,10 @@ export function createFilterStructure(
opts.visibleInStorefront.value,
{
negative: intl.formatMessage(commonMessages.no),
positive: intl.formatMessage(commonMessages.yes)
}
positive: intl.formatMessage(commonMessages.yes),
},
),
active: opts.visibleInStorefront.active
}
active: opts.visibleInStorefront.active,
},
];
}

View file

@ -19,29 +19,29 @@ const messages = defineMessages({
contentAttribute: {
id: "zbJHl7",
defaultMessage: "Content Attribute",
description: "attribute type"
description: "attribute type",
},
productAttribute: {
id: "qkRuT0",
defaultMessage: "Product Attribute",
description: "attribute type"
}
description: "attribute type",
},
});
const useStyles = makeStyles(
theme => ({
card: {
overflow: "visible"
overflow: "visible",
},
cardSubtitle: {
fontSize: theme.typography.body1.fontSize,
marginBottom: theme.spacing(0.5)
marginBottom: theme.spacing(0.5),
},
label: {
marginBottom: theme.spacing(0.5)
}
marginBottom: theme.spacing(0.5),
},
}),
{ name: "AttributeOrganization" }
{ name: "AttributeOrganization" },
);
const AttributeOrganization: React.FC<AttributeOrganizationProps> = props => {
@ -56,7 +56,7 @@ const AttributeOrganization: React.FC<AttributeOrganizationProps> = props => {
title={intl.formatMessage({
id: "nwvQPg",
defaultMessage: "Organization",
description: "section header"
description: "section header",
})}
/>
<CardContent>
@ -65,12 +65,12 @@ const AttributeOrganization: React.FC<AttributeOrganizationProps> = props => {
choices={[
{
label: intl.formatMessage(messages.productAttribute),
value: AttributeTypeEnum.PRODUCT_TYPE
value: AttributeTypeEnum.PRODUCT_TYPE,
},
{
label: intl.formatMessage(messages.contentAttribute),
value: AttributeTypeEnum.PAGE_TYPE
}
value: AttributeTypeEnum.PAGE_TYPE,
},
]}
disabled={disabled}
label={

View file

@ -17,7 +17,7 @@ import {
AttributeErrorFragment,
AttributeInputTypeEnum,
AttributeTypeEnum,
MeasurementUnitsEnum
MeasurementUnitsEnum,
} from "@saleor/graphql";
import { SubmitPromise } from "@saleor/hooks/useForm";
import useNavigator from "@saleor/hooks/useNavigator";
@ -91,7 +91,7 @@ const AttributePage: React.FC<AttributePageProps> = ({
pageInfo,
onNextPage,
onPreviousPage,
children
children,
}) => {
const intl = useIntl();
const navigate = useNavigator();
@ -99,7 +99,7 @@ const AttributePage: React.FC<AttributePageProps> = ({
const {
isMetadataModified,
isPrivateMetadataModified,
makeChangeHandler: makeMetadataChangeHandler
makeChangeHandler: makeMetadataChangeHandler,
} = useMetadataChangeTrigger();
const initialForm: AttributePageFormData =
@ -118,7 +118,7 @@ const AttributePage: React.FC<AttributePageProps> = ({
type: AttributeTypeEnum.PRODUCT_TYPE,
valueRequired: true,
visibleInStorefront: true,
unit: undefined
unit: undefined,
}
: {
availableInGrid: attribute?.availableInGrid ?? true,
@ -129,7 +129,7 @@ const AttributePage: React.FC<AttributePageProps> = ({
metadata: attribute?.metadata?.map(mapMetadataItemToInput),
name: attribute?.name ?? "",
privateMetadata: attribute?.privateMetadata?.map(
mapMetadataItemToInput
mapMetadataItemToInput,
),
slug: attribute?.slug ?? "",
storefrontSearchPosition:
@ -137,7 +137,7 @@ const AttributePage: React.FC<AttributePageProps> = ({
type: attribute?.type || AttributeTypeEnum.PRODUCT_TYPE,
valueRequired: !!attribute?.valueRequired ?? true,
visibleInStorefront: attribute?.visibleInStorefront ?? true,
unit: attribute?.unit || null
unit: attribute?.unit || null,
};
const handleSubmit = (data: AttributePageFormData) => {
@ -154,7 +154,7 @@ const AttributePage: React.FC<AttributePageProps> = ({
metadata,
privateMetadata,
slug: data.slug || slugify(data.name).toLowerCase(),
type
type,
});
};
@ -173,7 +173,7 @@ const AttributePage: React.FC<AttributePageProps> = ({
submit,
errors,
setError,
clearErrors
clearErrors,
}) => {
const changeMetadata = makeMetadataChangeHandler(change);
@ -189,7 +189,7 @@ const AttributePage: React.FC<AttributePageProps> = ({
? intl.formatMessage({
id: "8cUEPV",
defaultMessage: "Create New Attribute",
description: "page title"
description: "page title",
})
: maybe(() => attribute.name)
}
@ -208,7 +208,7 @@ const AttributePage: React.FC<AttributePageProps> = ({
clearErrors={clearErrors}
/>
{ATTRIBUTE_TYPES_WITH_DEDICATED_VALUES.includes(
data.inputType
data.inputType,
) && (
<>
<CardSpacer />

View file

@ -17,55 +17,55 @@ const messages = defineMessages({
availableInGrid: {
id: "jswILH",
defaultMessage: "Add to Column Options",
description: "add attribute as column in product list table"
description: "add attribute as column in product list table",
},
availableInGridCaption: {
id: "AzMSmb",
defaultMessage:
"If enabled this attribute can be used as a column in product table.",
description: "caption"
description: "caption",
},
dashboardPropertiesTitle: {
id: "lCxfDe",
defaultMessage: "Dashboard Properties",
description: "attribute properties regarding dashboard"
description: "attribute properties regarding dashboard",
},
filterableInDashboard: {
id: "RH+aOF",
defaultMessage: "Use in Filtering",
description: "use attribute in filtering"
description: "use attribute in filtering",
},
filterableInDashboardCaption: {
id: "Q9wTrz",
defaultMessage:
"If enabled, youll be able to use this attribute to filter products in product list.",
description: "caption"
description: "caption",
},
filterableInStorefront: {
defaultMessage: "Use as filter",
id: "e1vU/4",
description: "attribute is filterable in storefront"
description: "attribute is filterable in storefront",
},
storefrontPropertiesTitle: {
id: "AgY5Mv",
defaultMessage: "Storefront Properties",
description: "attribute properties regarding storefront"
description: "attribute properties regarding storefront",
},
storefrontSearchPosition: {
id: "cJ5ASN",
defaultMessage: "Position in faceted navigation",
description: "attribute position in storefront filters"
description: "attribute position in storefront filters",
},
visibleInStorefront: {
id: "x8V/xS",
defaultMessage: "Public",
description: "attribute visibility in storefront"
description: "attribute visibility in storefront",
},
visibleInStorefrontCaption: {
id: "h2Hta6",
defaultMessage: "If enabled, attribute will be accessible to customers.",
description: "caption"
}
description: "caption",
},
});
export interface AttributePropertiesProps {
@ -79,7 +79,7 @@ const AttributeProperties: React.FC<AttributePropertiesProps> = ({
data,
errors,
disabled,
onChange
onChange,
}) => {
const intl = useIntl();
@ -87,7 +87,7 @@ const AttributeProperties: React.FC<AttributePropertiesProps> = ({
const storefrontFacetedNavigationProperties =
ATTRIBUTE_TYPES_WITH_CONFIGURABLE_FACED_NAVIGATION.includes(
data.inputType
data.inputType,
) && data.type === AttributeTypeEnum.PRODUCT_TYPE;
return (
@ -112,7 +112,7 @@ const AttributeProperties: React.FC<AttributePropertiesProps> = ({
fullWidth
helperText={getAttributeErrorMessage(
formErrors.storefrontSearchPosition,
intl
intl,
)}
name={
"storefrontSearchPosition" as keyof AttributePageFormData

View file

@ -32,7 +32,7 @@ const AttributeSwatchField: React.FC<AttributeSwatchFieldProps<
const [processing, setProcessing] = useState(false);
const [uploadFile] = useFileUploadMutation({});
const [type, setType] = useState<SwatchType>(
data.fileUrl ? "image" : "picker"
data.fileUrl ? "image" : "picker",
);
const handleColorChange = (hex: string) =>
@ -42,20 +42,20 @@ const AttributeSwatchField: React.FC<AttributeSwatchFieldProps<
setProcessing(true);
const {
data: { fileUpload }
data: { fileUpload },
} = await uploadFile({ variables: { file } });
if (fileUpload.errors?.length) {
notify({
status: "error",
title: intl.formatMessage(errorMessages.imgageUploadErrorTitle),
text: intl.formatMessage(errorMessages.imageUploadErrorText)
text: intl.formatMessage(errorMessages.imageUploadErrorText),
});
} else {
set({
fileUrl: fileUpload.uploadedFile.url,
contentType: fileUpload.uploadedFile.contentType,
value: undefined
value: undefined,
});
}
@ -66,7 +66,7 @@ const AttributeSwatchField: React.FC<AttributeSwatchFieldProps<
set({
fileUrl: undefined,
contentType: undefined,
value: undefined
value: undefined,
});
return (
@ -76,12 +76,12 @@ const AttributeSwatchField: React.FC<AttributeSwatchFieldProps<
choices={[
{
label: formatMessage(swatchFieldMessages.picker),
value: "picker"
value: "picker",
},
{
label: formatMessage(swatchFieldMessages.image),
value: "image"
}
value: "image",
},
]}
variant="inline"
label={<FormattedMessage {...inputTypeMessages.swatch} />}
@ -99,7 +99,7 @@ const AttributeSwatchField: React.FC<AttributeSwatchFieldProps<
onFileUpload={handleFileUpload}
onFileDelete={handleFileDelete}
inputProps={{
accept: "image/*"
accept: "image/*",
}}
/>

View file

@ -4,11 +4,11 @@ export const swatchFieldMessages = defineMessages({
image: {
id: "I2wCwj",
defaultMessage: "Image",
description: "swatch attribute image label"
description: "swatch attribute image label",
},
picker: {
id: "0DgA8v",
defaultMessage: "Picker",
description: "swatch attribute color picker label"
}
description: "swatch attribute color picker label",
},
});

View file

@ -7,8 +7,8 @@ export const useStyles = makeStyles(
width: 216,
height: 216,
backgroundSize: "cover",
backgroundPosition: "center"
}
backgroundPosition: "center",
},
}),
{ name: "AttributeSwatchField" }
{ name: "AttributeSwatchField" },
);

View file

@ -21,7 +21,7 @@ const AttributeValueDeleteDialog: React.FC<AttributeValueDeleteDialogProps> = ({
useName,
onClose,
onConfirm,
open
open,
}) => {
const intl = useIntl();
@ -35,7 +35,7 @@ const AttributeValueDeleteDialog: React.FC<AttributeValueDeleteDialogProps> = ({
title={intl.formatMessage({
id: "WWV8aZ",
defaultMessage: "Delete attribute value",
description: "dialog title"
description: "dialog title",
})}
>
<DialogContentText>
@ -45,7 +45,7 @@ const AttributeValueDeleteDialog: React.FC<AttributeValueDeleteDialogProps> = ({
defaultMessage='Are you sure you want to delete "{name}" value? If you delete it you wont be able to assign it to any of the products with "{attributeName}" attribute.'
values={{
attributeName,
name
name,
}}
/>
) : (
@ -54,7 +54,7 @@ const AttributeValueDeleteDialog: React.FC<AttributeValueDeleteDialogProps> = ({
defaultMessage='Are you sure you want to delete "{name}" value?'
description="delete attribute value"
values={{
name
name,
}}
/>
)}

View file

@ -3,7 +3,7 @@ import {
DialogActions,
DialogContent,
DialogTitle,
TextField
TextField,
} from "@material-ui/core";
import { getAttributeValueErrorMessage } from "@saleor/attributes/errors";
import BackButton from "@saleor/components/BackButton";
@ -11,7 +11,7 @@ import ConfirmButton from "@saleor/components/ConfirmButton";
import Form from "@saleor/components/Form";
import {
AttributeErrorFragment,
AttributeInputTypeEnum
AttributeInputTypeEnum,
} from "@saleor/graphql";
import useModalDialogErrors from "@saleor/hooks/useModalDialogErrors";
import { buttonMessages } from "@saleor/intl";
@ -42,19 +42,19 @@ const AttributeValueEditDialog: React.FC<AttributeValueEditDialogProps> = ({
onClose,
onSubmit,
open,
inputType
inputType,
}) => {
const intl = useIntl();
const attributeValueFields = attributeValue?.fileUrl
? {
fileUrl: attributeValue?.fileUrl,
contentType: attributeValue?.contentType
contentType: attributeValue?.contentType,
}
: { value: attributeValue?.value ?? "" };
const initialForm: AttributeValueEditDialogFormData = {
name: attributeValue?.name ?? "",
...attributeValueFields
...attributeValueFields,
};
const errors = useModalDialogErrors(apiErrors, open);
const formErrors = getFormErrors(["name"], errors);
@ -89,13 +89,13 @@ const AttributeValueEditDialog: React.FC<AttributeValueEditDialogProps> = ({
fullWidth
helperText={getAttributeValueErrorMessage(
formErrors.name,
intl
intl,
)}
name={"name" as keyof AttributeValueEditDialogFormData}
label={intl.formatMessage({
id: "UhcALJ",
defaultMessage: "Name",
description: "attribute name"
description: "attribute name",
})}
value={data.name}
onChange={change}

View file

@ -3,7 +3,7 @@ import {
TableCell,
TableFooter,
TableHead,
TableRow
TableRow,
} from "@material-ui/core";
import { Button } from "@saleor/components/Button";
import CardTitle from "@saleor/components/CardTitle";
@ -11,12 +11,12 @@ import ResponsiveTable from "@saleor/components/ResponsiveTable";
import Skeleton from "@saleor/components/Skeleton";
import {
SortableTableBody,
SortableTableRow
SortableTableRow,
} from "@saleor/components/SortableTable";
import TablePagination from "@saleor/components/TablePagination";
import {
AttributeInputTypeEnum,
AttributeValueListFragment
AttributeValueListFragment,
} from "@saleor/graphql";
import { DeleteIcon, IconButton, makeStyles } from "@saleor/macaw-ui";
import { renderCollection, stopPropagation } from "@saleor/misc";
@ -24,7 +24,7 @@ import {
ListProps,
PaginateListProps,
RelayToFlat,
ReorderAction
ReorderAction,
} from "@saleor/types";
import React from "react";
import { FormattedMessage, useIntl } from "react-intl";
@ -44,35 +44,35 @@ export interface AttributeValuesProps
const useStyles = makeStyles(
theme => ({
columnSwatch: {
width: 100
width: 100,
},
columnAdmin: {
width: 300
width: 300,
},
columnDrag: {
width: theme.spacing(6 + 1.5)
width: theme.spacing(6 + 1.5),
},
columnStore: {
width: "auto"
width: "auto",
},
dragIcon: {
cursor: "grab"
cursor: "grab",
},
iconCell: {
width: 84
width: 84,
},
link: {
cursor: "pointer"
cursor: "pointer",
},
swatch: {
width: 32,
height: 32,
borderRadius: 4,
backgroundSize: "cover",
backgroundPosition: "center"
}
backgroundPosition: "center",
},
}),
{ name: "AttributeValues" }
{ name: "AttributeValues" },
);
const AttributeValues: React.FC<AttributeValuesProps> = ({
@ -87,7 +87,7 @@ const AttributeValues: React.FC<AttributeValuesProps> = ({
pageInfo,
onNextPage,
onPreviousPage,
inputType
inputType,
}) => {
const classes = useStyles({});
const intl = useIntl();
@ -101,7 +101,7 @@ const AttributeValues: React.FC<AttributeValuesProps> = ({
title={intl.formatMessage({
id: "J3uE0t",
defaultMessage: "Attribute Values",
description: "section header"
description: "section header",
})}
toolbar={
<Button
@ -214,7 +214,7 @@ const AttributeValues: React.FC<AttributeValuesProps> = ({
/>
</TableCell>
</TableRow>
)
),
)}
</SortableTableBody>
</ResponsiveTable>

View file

@ -5,17 +5,17 @@ import { defineMessages, IntlShape } from "react-intl";
const messages = defineMessages({
attributeSlugUnique: {
id: "eWV760",
defaultMessage: "Attribute with this slug already exists"
defaultMessage: "Attribute with this slug already exists",
},
attributeValueAlreadyExists: {
id: "J/QqOI",
defaultMessage: "This value already exists within this attribute"
}
defaultMessage: "This value already exists within this attribute",
},
});
export function getAttributeSlugErrorMessage(
err: AttributeErrorFragment,
intl: IntlShape
intl: IntlShape,
): string {
switch (err?.code) {
case AttributeErrorCode.UNIQUE:
@ -27,7 +27,7 @@ export function getAttributeSlugErrorMessage(
export function getAttributeValueErrorMessage(
err: AttributeErrorFragment,
intl: IntlShape
intl: IntlShape,
): string {
switch (err?.code) {
case AttributeErrorCode.ALREADY_EXISTS:

View file

@ -4,7 +4,7 @@ import {
AttributeInputTypeEnum,
AttributeListQuery,
AttributeTypeEnum,
ProductDetailsQuery
ProductDetailsQuery,
} from "@saleor/graphql";
export const attribute: AttributeDetailsQuery["attribute"] = {
@ -19,8 +19,8 @@ export const attribute: AttributeDetailsQuery["attribute"] = {
{
__typename: "MetadataItem",
key: "integration.id",
value: "100023123"
}
value: "100023123",
},
],
name: "Author",
privateMetadata: [],
@ -36,7 +36,7 @@ export const attribute: AttributeDetailsQuery["attribute"] = {
endCursor: "",
hasNextPage: false,
hasPreviousPage: false,
startCursor: ""
startCursor: "",
},
edges: [
{
@ -53,8 +53,8 @@ export const attribute: AttributeDetailsQuery["attribute"] = {
boolean: null,
date: null,
dateTime: null,
value: null
}
value: null,
},
},
{
__typename: "AttributeValueCountableEdge" as "AttributeValueCountableEdge",
@ -70,12 +70,12 @@ export const attribute: AttributeDetailsQuery["attribute"] = {
boolean: null,
date: null,
dateTime: null,
value: null
}
}
]
value: null,
},
visibleInStorefront: true
},
],
},
visibleInStorefront: true,
};
export const attributes: Array<AttributeListQuery["attributes"]["edges"][0]["node"] &
@ -99,7 +99,7 @@ export const attributes: Array<AttributeListQuery["attributes"]["edges"][0]["nod
hasNextPage: false,
hasPreviousPage: false,
startCursor: "WyIwIiwgIjQ5Il0=",
__typename: "PageInfo" as "PageInfo"
__typename: "PageInfo" as "PageInfo",
},
edges: [
{
@ -117,8 +117,8 @@ export const attributes: Array<AttributeListQuery["attributes"]["edges"][0]["nod
richText: null,
boolean: null,
date: null,
dateTime: null
}
dateTime: null,
},
},
{
__typename: "AttributeValueCountableEdge" as "AttributeValueCountableEdge",
@ -135,12 +135,12 @@ export const attributes: Array<AttributeListQuery["attributes"]["edges"][0]["nod
richText: null,
boolean: null,
date: null,
dateTime: null
}
}
]
dateTime: null,
},
visibleInStorefront: true
},
],
},
visibleInStorefront: true,
},
{
__typename: "Attribute" as "Attribute",
@ -161,7 +161,7 @@ export const attributes: Array<AttributeListQuery["attributes"]["edges"][0]["nod
hasNextPage: false,
hasPreviousPage: false,
startCursor: "WyIwIiwgIjQ5Il0=",
__typename: "PageInfo" as "PageInfo"
__typename: "PageInfo" as "PageInfo",
},
edges: [
{
@ -179,8 +179,8 @@ export const attributes: Array<AttributeListQuery["attributes"]["edges"][0]["nod
richText: null,
boolean: null,
date: null,
dateTime: null
}
dateTime: null,
},
},
{
__typename: "AttributeValueCountableEdge" as "AttributeValueCountableEdge",
@ -197,8 +197,8 @@ export const attributes: Array<AttributeListQuery["attributes"]["edges"][0]["nod
richText: null,
boolean: null,
date: null,
dateTime: null
}
dateTime: null,
},
},
{
__typename: "AttributeValueCountableEdge" as "AttributeValueCountableEdge",
@ -215,8 +215,8 @@ export const attributes: Array<AttributeListQuery["attributes"]["edges"][0]["nod
richText: null,
boolean: null,
date: null,
dateTime: null
}
dateTime: null,
},
},
{
__typename: "AttributeValueCountableEdge" as "AttributeValueCountableEdge",
@ -233,12 +233,12 @@ export const attributes: Array<AttributeListQuery["attributes"]["edges"][0]["nod
richText: null,
boolean: null,
date: null,
dateTime: null
}
}
]
dateTime: null,
},
visibleInStorefront: false
},
],
},
visibleInStorefront: false,
},
{
__typename: "Attribute" as "Attribute",
@ -259,7 +259,7 @@ export const attributes: Array<AttributeListQuery["attributes"]["edges"][0]["nod
hasNextPage: false,
hasPreviousPage: false,
startCursor: "WyIwIiwgIjQ5Il0=",
__typename: "PageInfo" as "PageInfo"
__typename: "PageInfo" as "PageInfo",
},
edges: [
{
@ -277,12 +277,12 @@ export const attributes: Array<AttributeListQuery["attributes"]["edges"][0]["nod
richText: null,
boolean: null,
date: null,
dateTime: null
}
}
]
dateTime: null,
},
visibleInStorefront: false
},
],
},
visibleInStorefront: false,
},
{
__typename: "Attribute" as "Attribute",
@ -303,7 +303,7 @@ export const attributes: Array<AttributeListQuery["attributes"]["edges"][0]["nod
hasNextPage: false,
hasPreviousPage: false,
startCursor: "WyIwIiwgIjQ5Il0=",
__typename: "PageInfo" as "PageInfo"
__typename: "PageInfo" as "PageInfo",
},
edges: [
{
@ -321,8 +321,8 @@ export const attributes: Array<AttributeListQuery["attributes"]["edges"][0]["nod
richText: null,
boolean: null,
date: null,
dateTime: null
}
dateTime: null,
},
},
{
__typename: "AttributeValueCountableEdge" as "AttributeValueCountableEdge",
@ -339,8 +339,8 @@ export const attributes: Array<AttributeListQuery["attributes"]["edges"][0]["nod
richText: null,
boolean: null,
date: null,
dateTime: null
}
dateTime: null,
},
},
{
__typename: "AttributeValueCountableEdge" as "AttributeValueCountableEdge",
@ -357,12 +357,12 @@ export const attributes: Array<AttributeListQuery["attributes"]["edges"][0]["nod
richText: null,
boolean: null,
date: null,
dateTime: null
}
}
]
dateTime: null,
},
visibleInStorefront: false
},
],
},
visibleInStorefront: false,
},
{
__typename: "Attribute" as "Attribute",
@ -383,7 +383,7 @@ export const attributes: Array<AttributeListQuery["attributes"]["edges"][0]["nod
hasNextPage: false,
hasPreviousPage: false,
startCursor: "WyIwIiwgIjQ5Il0=",
__typename: "PageInfo" as "PageInfo"
__typename: "PageInfo" as "PageInfo",
},
edges: [
{
@ -401,8 +401,8 @@ export const attributes: Array<AttributeListQuery["attributes"]["edges"][0]["nod
richText: null,
boolean: null,
date: null,
dateTime: null
}
dateTime: null,
},
},
{
__typename: "AttributeValueCountableEdge" as "AttributeValueCountableEdge",
@ -419,12 +419,12 @@ export const attributes: Array<AttributeListQuery["attributes"]["edges"][0]["nod
richText: null,
boolean: null,
date: null,
dateTime: null
}
}
]
dateTime: null,
},
visibleInStorefront: true
},
],
},
visibleInStorefront: true,
},
{
__typename: "Attribute" as "Attribute",
@ -445,7 +445,7 @@ export const attributes: Array<AttributeListQuery["attributes"]["edges"][0]["nod
hasNextPage: false,
hasPreviousPage: false,
startCursor: "WyIwIiwgIjQ5Il0=",
__typename: "PageInfo" as "PageInfo"
__typename: "PageInfo" as "PageInfo",
},
edges: [
{
@ -463,8 +463,8 @@ export const attributes: Array<AttributeListQuery["attributes"]["edges"][0]["nod
richText: null,
boolean: null,
date: null,
dateTime: null
}
dateTime: null,
},
},
{
__typename: "AttributeValueCountableEdge" as "AttributeValueCountableEdge",
@ -481,8 +481,8 @@ export const attributes: Array<AttributeListQuery["attributes"]["edges"][0]["nod
richText: null,
boolean: null,
date: null,
dateTime: null
}
dateTime: null,
},
},
{
__typename: "AttributeValueCountableEdge" as "AttributeValueCountableEdge",
@ -499,12 +499,12 @@ export const attributes: Array<AttributeListQuery["attributes"]["edges"][0]["nod
richText: null,
boolean: null,
date: null,
dateTime: null
}
}
]
dateTime: null,
},
visibleInStorefront: true
},
],
},
visibleInStorefront: true,
},
{
__typename: "Attribute" as "Attribute",
@ -525,7 +525,7 @@ export const attributes: Array<AttributeListQuery["attributes"]["edges"][0]["nod
hasNextPage: false,
hasPreviousPage: false,
startCursor: "WyIwIiwgIjQ5Il0=",
__typename: "PageInfo" as "PageInfo"
__typename: "PageInfo" as "PageInfo",
},
edges: [
{
@ -543,8 +543,8 @@ export const attributes: Array<AttributeListQuery["attributes"]["edges"][0]["nod
richText: null,
boolean: null,
date: null,
dateTime: null
}
dateTime: null,
},
},
{
__typename: "AttributeValueCountableEdge" as "AttributeValueCountableEdge",
@ -561,12 +561,12 @@ export const attributes: Array<AttributeListQuery["attributes"]["edges"][0]["nod
richText: null,
boolean: null,
date: null,
dateTime: null
}
}
]
dateTime: null,
},
visibleInStorefront: true
},
],
},
visibleInStorefront: true,
},
{
__typename: "Attribute" as "Attribute",
@ -587,7 +587,7 @@ export const attributes: Array<AttributeListQuery["attributes"]["edges"][0]["nod
hasNextPage: false,
hasPreviousPage: false,
startCursor: "WyIwIiwgIjQ5Il0=",
__typename: "PageInfo" as "PageInfo"
__typename: "PageInfo" as "PageInfo",
},
edges: [
{
@ -605,8 +605,8 @@ export const attributes: Array<AttributeListQuery["attributes"]["edges"][0]["nod
richText: null,
boolean: null,
date: null,
dateTime: null
}
dateTime: null,
},
},
{
__typename: "AttributeValueCountableEdge" as "AttributeValueCountableEdge",
@ -623,8 +623,8 @@ export const attributes: Array<AttributeListQuery["attributes"]["edges"][0]["nod
richText: null,
boolean: null,
date: null,
dateTime: null
}
dateTime: null,
},
},
{
__typename: "AttributeValueCountableEdge" as "AttributeValueCountableEdge",
@ -641,8 +641,8 @@ export const attributes: Array<AttributeListQuery["attributes"]["edges"][0]["nod
richText: null,
boolean: null,
date: null,
dateTime: null
}
dateTime: null,
},
},
{
__typename: "AttributeValueCountableEdge" as "AttributeValueCountableEdge",
@ -659,8 +659,8 @@ export const attributes: Array<AttributeListQuery["attributes"]["edges"][0]["nod
richText: null,
boolean: null,
date: null,
dateTime: null
}
dateTime: null,
},
},
{
__typename: "AttributeValueCountableEdge" as "AttributeValueCountableEdge",
@ -677,8 +677,8 @@ export const attributes: Array<AttributeListQuery["attributes"]["edges"][0]["nod
richText: null,
boolean: null,
date: null,
dateTime: null
}
dateTime: null,
},
},
{
__typename: "AttributeValueCountableEdge" as "AttributeValueCountableEdge",
@ -695,12 +695,12 @@ export const attributes: Array<AttributeListQuery["attributes"]["edges"][0]["nod
richText: null,
boolean: null,
date: null,
dateTime: null
}
}
]
dateTime: null,
},
visibleInStorefront: false
},
],
},
visibleInStorefront: false,
},
{
__typename: "Attribute" as "Attribute",
@ -721,7 +721,7 @@ export const attributes: Array<AttributeListQuery["attributes"]["edges"][0]["nod
hasNextPage: false,
hasPreviousPage: false,
startCursor: "WyIwIiwgIjQ5Il0=",
__typename: "PageInfo" as "PageInfo"
__typename: "PageInfo" as "PageInfo",
},
edges: [
{
@ -739,8 +739,8 @@ export const attributes: Array<AttributeListQuery["attributes"]["edges"][0]["nod
richText: null,
boolean: null,
date: null,
dateTime: null
}
dateTime: null,
},
},
{
__typename: "AttributeValueCountableEdge" as "AttributeValueCountableEdge",
@ -757,12 +757,12 @@ export const attributes: Array<AttributeListQuery["attributes"]["edges"][0]["nod
richText: null,
boolean: null,
date: null,
dateTime: null
}
}
]
dateTime: null,
},
visibleInStorefront: true
},
],
},
visibleInStorefront: true,
},
{
__typename: "Attribute" as "Attribute",
@ -783,7 +783,7 @@ export const attributes: Array<AttributeListQuery["attributes"]["edges"][0]["nod
hasNextPage: false,
hasPreviousPage: false,
startCursor: "WyIwIiwgIjQ5Il0=",
__typename: "PageInfo" as "PageInfo"
__typename: "PageInfo" as "PageInfo",
},
edges: [
{
@ -801,8 +801,8 @@ export const attributes: Array<AttributeListQuery["attributes"]["edges"][0]["nod
richText: null,
boolean: null,
date: null,
dateTime: null
}
dateTime: null,
},
},
{
__typename: "AttributeValueCountableEdge" as "AttributeValueCountableEdge",
@ -819,12 +819,12 @@ export const attributes: Array<AttributeListQuery["attributes"]["edges"][0]["nod
richText: null,
boolean: null,
date: null,
dateTime: null
}
}
]
dateTime: null,
},
visibleInStorefront: true
},
],
},
visibleInStorefront: true,
},
{
__typename: "Attribute" as "Attribute",
@ -845,7 +845,7 @@ export const attributes: Array<AttributeListQuery["attributes"]["edges"][0]["nod
hasNextPage: false,
hasPreviousPage: false,
startCursor: "WyIwIiwgIjQ5Il0=",
__typename: "PageInfo" as "PageInfo"
__typename: "PageInfo" as "PageInfo",
},
edges: [
{
@ -863,8 +863,8 @@ export const attributes: Array<AttributeListQuery["attributes"]["edges"][0]["nod
richText: null,
boolean: null,
date: null,
dateTime: null
}
dateTime: null,
},
},
{
__typename: "AttributeValueCountableEdge" as "AttributeValueCountableEdge",
@ -881,12 +881,12 @@ export const attributes: Array<AttributeListQuery["attributes"]["edges"][0]["nod
richText: null,
boolean: null,
date: null,
dateTime: null
}
}
]
dateTime: null,
},
visibleInStorefront: true
},
],
},
visibleInStorefront: true,
},
{
__typename: "Attribute" as "Attribute",
@ -907,7 +907,7 @@ export const attributes: Array<AttributeListQuery["attributes"]["edges"][0]["nod
hasNextPage: false,
hasPreviousPage: false,
startCursor: "WyIwIiwgIjQ5Il0=",
__typename: "PageInfo" as "PageInfo"
__typename: "PageInfo" as "PageInfo",
},
edges: [
{
@ -925,8 +925,8 @@ export const attributes: Array<AttributeListQuery["attributes"]["edges"][0]["nod
richText: null,
boolean: null,
date: null,
dateTime: null
}
dateTime: null,
},
},
{
__typename: "AttributeValueCountableEdge" as "AttributeValueCountableEdge",
@ -943,8 +943,8 @@ export const attributes: Array<AttributeListQuery["attributes"]["edges"][0]["nod
richText: null,
boolean: null,
date: null,
dateTime: null
}
dateTime: null,
},
},
{
__typename: "AttributeValueCountableEdge" as "AttributeValueCountableEdge",
@ -961,8 +961,8 @@ export const attributes: Array<AttributeListQuery["attributes"]["edges"][0]["nod
richText: null,
boolean: null,
date: null,
dateTime: null
}
dateTime: null,
},
},
{
__typename: "AttributeValueCountableEdge" as "AttributeValueCountableEdge",
@ -979,8 +979,8 @@ export const attributes: Array<AttributeListQuery["attributes"]["edges"][0]["nod
richText: null,
boolean: null,
date: null,
dateTime: null
}
dateTime: null,
},
},
{
__typename: "AttributeValueCountableEdge" as "AttributeValueCountableEdge",
@ -997,8 +997,8 @@ export const attributes: Array<AttributeListQuery["attributes"]["edges"][0]["nod
richText: null,
boolean: null,
date: null,
dateTime: null
}
dateTime: null,
},
},
{
__typename: "AttributeValueCountableEdge" as "AttributeValueCountableEdge",
@ -1015,11 +1015,11 @@ export const attributes: Array<AttributeListQuery["attributes"]["edges"][0]["nod
richText: null,
boolean: null,
date: null,
dateTime: null
}
}
]
dateTime: null,
},
},
],
},
visibleInStorefront: true,
},
visibleInStorefront: true
}
];

View file

@ -13,7 +13,7 @@ import {
AttributeListUrlQueryParams,
AttributeListUrlSortField,
attributePath,
AttributeUrlQueryParams
AttributeUrlQueryParams,
} from "./urls";
import AttributeCreateComponent from "./views/AttributeCreate";
import AttributeDetailsComponent from "./views/AttributeDetails";
@ -23,7 +23,7 @@ const AttributeList: React.FC<RouteComponentProps<{}>> = ({ location }) => {
const qs = parseQs(location.search.substr(1));
const params: AttributeListUrlQueryParams = asSortParams(
qs,
AttributeListUrlSortField
AttributeListUrlSortField,
);
return <AttributeListComponent params={params} />;
@ -37,7 +37,7 @@ const AttributeCreate: React.FC<RouteComponentProps<{}>> = ({ location }) => {
const AttributeDetails: React.FC<RouteComponentProps<{ id: string }>> = ({
location,
match
match,
}) => {
const qs = parseQs(location.search.substr(1));
const params: AttributeUrlQueryParams = qs;

View file

@ -9,7 +9,7 @@ import {
Pagination,
SingleAction,
Sort,
TabActionDialog
TabActionDialog,
} from "../types";
export const attributeSection = "/attributes/";
@ -19,7 +19,7 @@ export enum AttributeListUrlFiltersEnum {
isVariantOnly = "isVariantOnly",
valueRequired = "valueRequired",
visibleInStorefront = "visibleInStorefront",
query = "query"
query = "query",
}
export type AttributeListUrlFilters = Filters<AttributeListUrlFiltersEnum>;
export type AttributeListUrlDialog = "remove" | TabActionDialog;
@ -28,7 +28,7 @@ export enum AttributeListUrlSortField {
slug = "slug",
visible = "visible",
searchable = "searchable",
useInFacetedSearch = "use-in-faceted-search"
useInFacetedSearch = "use-in-faceted-search",
}
export type AttributeListUrlSort = Sort<AttributeListUrlSortField>;
export type AttributeListUrlQueryParams = ActiveTab &

View file

@ -1,7 +1,7 @@
import { FetchResult } from "@apollo/client";
import {
AttributeInput,
AttributeInputData
AttributeInputData,
} from "@saleor/components/Attributes";
import {
AttributeEntityTypeEnum,
@ -19,19 +19,19 @@ import {
SearchProductsQuery,
SelectedVariantAttributeFragment,
UploadErrorFragment,
VariantAttributeFragment
VariantAttributeFragment,
} from "@saleor/graphql";
import { FormsetData } from "@saleor/hooks/useFormset";
import { RelayToFlat } from "@saleor/types";
import {
mapEdgesToItems,
mapNodeToChoice,
mapPagesToChoices
mapPagesToChoices,
} from "@saleor/utils/maps";
import { RichTextContextValues } from "@saleor/utils/richText/context";
import {
GetRichTextValues,
RichTextGetters
RichTextGetters,
} from "@saleor/utils/richText/useMultipleRichText";
import { AttributePageFormData } from "../components/AttributePage";
@ -49,7 +49,7 @@ export interface RichTextProps {
export const ATTRIBUTE_TYPES_WITH_DEDICATED_VALUES = [
AttributeInputTypeEnum.DROPDOWN,
AttributeInputTypeEnum.MULTISELECT,
AttributeInputTypeEnum.SWATCH
AttributeInputTypeEnum.SWATCH,
];
export const ATTRIBUTE_TYPES_WITH_CONFIGURABLE_FACED_NAVIGATION = [
@ -59,14 +59,14 @@ export const ATTRIBUTE_TYPES_WITH_CONFIGURABLE_FACED_NAVIGATION = [
AttributeInputTypeEnum.DATE,
AttributeInputTypeEnum.DATE_TIME,
AttributeInputTypeEnum.NUMERIC,
AttributeInputTypeEnum.SWATCH
AttributeInputTypeEnum.SWATCH,
];
export function filterable(
attribute: Pick<AttributeFragment, "inputType">
attribute: Pick<AttributeFragment, "inputType">,
): boolean {
return ATTRIBUTE_TYPES_WITH_CONFIGURABLE_FACED_NAVIGATION.includes(
attribute.inputType
attribute.inputType,
);
}
@ -83,19 +83,19 @@ export interface AttributeValueEditDialogFormData {
}
export function attributeValueFragmentToFormData(
data: AttributeValueFragment | null
data: AttributeValueFragment | null,
): AttributeValueEditDialogFormData {
return {
name: data?.name,
value: data?.value,
contentType: data?.file?.contentType,
fileUrl: data?.file?.url
fileUrl: data?.file?.url,
};
}
function getSimpleAttributeData(
data: AttributePageFormData,
values: AttributeValueEditDialogFormData[]
values: AttributeValueEditDialogFormData[],
) {
return {
...data,
@ -103,8 +103,8 @@ function getSimpleAttributeData(
privateMetadata: undefined,
storefrontSearchPosition: parseInt(data.storefrontSearchPosition, 10),
values: values.map(value => ({
name: value.name
}))
name: value.name,
})),
};
}
@ -112,42 +112,42 @@ function getAttributeValueTypeFields({
fileUrl,
value,
name,
contentType
contentType,
}: AttributeValueEditDialogFormData) {
return {
name,
...(fileUrl ? { fileUrl, contentType } : { value })
...(fileUrl ? { fileUrl, contentType } : { value }),
};
}
function getSwatchAttributeData(
data: AttributePageFormData,
values: AttributeValueEditDialogFormData[]
values: AttributeValueEditDialogFormData[],
) {
return {
...data,
metadata: undefined,
privateMetadata: undefined,
storefrontSearchPosition: parseInt(data.storefrontSearchPosition, 10),
values: values.map(getAttributeValueTypeFields)
values: values.map(getAttributeValueTypeFields),
};
}
function getFileOrReferenceAttributeData(
data: AttributePageFormData,
values: AttributeValueEditDialogFormData[]
values: AttributeValueEditDialogFormData[],
) {
return {
...getSimpleAttributeData(data, values),
availableInGrid: undefined,
filterableInDashboard: undefined,
filterableInStorefront: undefined
filterableInStorefront: undefined,
};
}
export function getAttributeData(
data: AttributePageFormData,
values: AttributeValueEditDialogFormData[]
values: AttributeValueEditDialogFormData[],
) {
if (data.inputType === AttributeInputTypeEnum.SWATCH) {
return getSwatchAttributeData(data, values);
@ -172,7 +172,7 @@ export function getSelectedAttributeValues(
attribute:
| PageSelectedAttributeFragment
| ProductFragment["attributes"][0]
| SelectedVariantAttributeFragment
| SelectedVariantAttributeFragment,
) {
switch (attribute.attribute.inputType) {
case AttributeInputTypeEnum.REFERENCE:
@ -203,7 +203,7 @@ export const isFileValueUnused = (
existingAttribute:
| PageSelectedAttributeFragment
| ProductFragment["attributes"][0]
| SelectedVariantAttributeFragment
| SelectedVariantAttributeFragment,
) => {
if (existingAttribute.attribute.inputType !== AttributeInputTypeEnum.FILE) {
return false;
@ -213,14 +213,14 @@ export const isFileValueUnused = (
}
const modifiedAttribute = attributesWithNewFileValue.find(
dataAttribute => dataAttribute.id === existingAttribute.attribute.id
dataAttribute => dataAttribute.id === existingAttribute.attribute.id,
);
return !!modifiedAttribute;
};
export const mergeFileUploadErrors = (
uploadFilesResult: Array<FetchResult<FileUploadMutation>>
uploadFilesResult: Array<FetchResult<FileUploadMutation>>,
): UploadErrorFragment[] =>
uploadFilesResult.reduce((errors, uploadFileResult) => {
const uploadErrors = uploadFileResult?.data?.fileUpload?.errors;
@ -231,7 +231,7 @@ export const mergeFileUploadErrors = (
}, []);
export const mergeAttributeValueDeleteErrors = (
deleteAttributeValuesResult: Array<FetchResult<AttributeValueDeleteMutation>>
deleteAttributeValuesResult: Array<FetchResult<AttributeValueDeleteMutation>>,
): AttributeErrorFragment[] =>
deleteAttributeValuesResult.reduce((errors, deleteValueResult) => {
const deleteErrors = deleteValueResult?.data?.attributeValueDelete?.errors;
@ -245,11 +245,11 @@ export const mergeChoicesWithValues = (
attribute:
| ProductFragment["attributes"][0]
| PageSelectedAttributeFragment
| SelectedVariantAttributeFragment
| SelectedVariantAttributeFragment,
) => {
const choices = mapEdgesToItems(attribute.attribute.choices) || [];
const valuesToConcat = attribute.values.filter(
value => !choices.some(choice => choice.id === value.id)
value => !choices.some(choice => choice.id === value.id),
);
return choices.concat(valuesToConcat);
@ -258,7 +258,7 @@ export const mergeChoicesWithValues = (
export const mergeAttributeValues = (
attributeId: string,
attributeValues: string[],
attributes: FormsetData<AttributeInputData, string[]>
attributes: FormsetData<AttributeInputData, string[]>,
) => {
const attribute = attributes.find(attribute => attribute.id === attributeId);
@ -274,28 +274,29 @@ export const mergeAttributes = (
const newAttributeIds = new Set(attributes.map(attr => attr.id));
return [
...prev.filter(attr => !newAttributeIds.has(attr.id)),
...attributes
...attributes,
];
}, []);
export function getRichTextAttributesFromMap(
attributes: AttributeInput[],
values: GetRichTextValues
values: GetRichTextValues,
): AttributeInput[] {
return attributes
.filter(({ data }) => data.inputType === AttributeInputTypeEnum.RICH_TEXT)
.map(attribute => ({
...attribute,
value: [JSON.stringify(values[attribute.id])]
value: [JSON.stringify(values[attribute.id])],
}));
}
export function getRichTextDataFromAttributes(
attributes: AttributeInput[] = []
attributes: AttributeInput[] = [],
): Record<string, string> {
const keyValuePairs = attributes
.filter(
attribute => attribute.data.inputType === AttributeInputTypeEnum.RICH_TEXT
attribute =>
attribute.data.inputType === AttributeInputTypeEnum.RICH_TEXT,
)
.map(attribute => [attribute.id, attribute.value[0]]);
@ -303,26 +304,26 @@ export function getRichTextDataFromAttributes(
}
export const getFileValuesToUploadFromAttributes = (
attributesWithNewFileValue: FormsetData<null, File>
attributesWithNewFileValue: FormsetData<null, File>,
) => attributesWithNewFileValue.filter(fileAttribute => !!fileAttribute.value);
export const getFileValuesRemovedFromAttributes = (
attributesWithNewFileValue: FormsetData<null, File>
attributesWithNewFileValue: FormsetData<null, File>,
) => attributesWithNewFileValue.filter(attribute => !attribute.value);
export const getAttributesOfRemovedFiles = (
fileAttributesRemoved: FormsetData<null, File>
fileAttributesRemoved: FormsetData<null, File>,
): AtributesOfFiles[] =>
fileAttributesRemoved.map(attribute => ({
file: undefined,
id: attribute.id,
contentType: attribute.value?.type,
values: []
values: [],
}));
export const getAttributesOfUploadedFiles = (
fileValuesToUpload: FormsetData<null, File>,
uploadFilesResult: Array<FetchResult<FileUploadMutation>>
uploadFilesResult: Array<FetchResult<FileUploadMutation>>,
): AtributesOfFiles[] =>
uploadFilesResult.map((uploadFileResult, index) => {
const attribute = fileValuesToUpload[index];
@ -331,25 +332,25 @@ export const getAttributesOfUploadedFiles = (
file: uploadFileResult.data.fileUpload.uploadedFile.url,
contentType: uploadFileResult.data.fileUpload.uploadedFile.contentType,
id: attribute.id,
values: []
values: [],
};
});
export const getAttributesAfterFileAttributesUpdate = (
attributesWithNewFileValue: FormsetData<null, File>,
uploadFilesResult: Array<FetchResult<FileUploadMutation>>
uploadFilesResult: Array<FetchResult<FileUploadMutation>>,
): AttributeValueInput[] => {
const removedFileValues = getFileValuesRemovedFromAttributes(
attributesWithNewFileValue
attributesWithNewFileValue,
);
const fileValuesToUpload = getFileValuesToUploadFromAttributes(
attributesWithNewFileValue
attributesWithNewFileValue,
);
const removedFileAttributes = getAttributesOfRemovedFiles(removedFileValues);
const uploadedFileAttributes = getAttributesOfUploadedFiles(
fileValuesToUpload,
uploadFilesResult
uploadFilesResult,
);
return uploadedFileAttributes.concat(removedFileAttributes);
@ -357,10 +358,10 @@ export const getAttributesAfterFileAttributesUpdate = (
export const getFileAttributeDisplayData = (
attribute: AttributeInput,
attributesWithNewFileValue: FormsetData<null, File>
attributesWithNewFileValue: FormsetData<null, File>,
) => {
const attributeWithNewFileValue = attributesWithNewFileValue.find(
attributeWithNewFile => attribute.id === attributeWithNewFile.id
attributeWithNewFile => attribute.id === attributeWithNewFile.id,
);
if (attributeWithNewFileValue) {
@ -368,7 +369,7 @@ export const getFileAttributeDisplayData = (
...attribute,
value: attributeWithNewFileValue?.value?.name
? [attributeWithNewFileValue.value.name]
: []
: [],
};
}
return attribute;
@ -376,7 +377,7 @@ export const getFileAttributeDisplayData = (
export const getPageReferenceAttributeDisplayData = (
attribute: AttributeInput,
referencePages: RelayToFlat<SearchPagesQuery["search"]>
referencePages: RelayToFlat<SearchPagesQuery["search"]>,
) => ({
...attribute,
data: {
@ -386,18 +387,18 @@ export const getPageReferenceAttributeDisplayData = (
? mapPagesToChoices(
attribute.value.map(value => {
const reference = referencePages.find(
reference => reference.id === value
reference => reference.id === value,
);
return { ...reference };
})
}),
)
: []
}
: [],
},
});
export const getProductReferenceAttributeDisplayData = (
attribute: AttributeInput,
referenceProducts: RelayToFlat<SearchProductsQuery["search"]>
referenceProducts: RelayToFlat<SearchProductsQuery["search"]>,
) => ({
...attribute,
data: {
@ -407,26 +408,26 @@ export const getProductReferenceAttributeDisplayData = (
? mapNodeToChoice(
attribute.value.map(value => {
const reference = referenceProducts.find(
reference => reference.id === value
reference => reference.id === value,
);
return { ...reference };
})
}),
)
: []
}
: [],
},
});
export const getReferenceAttributeDisplayData = (
attribute: AttributeInput,
referencePages: RelayToFlat<SearchPagesQuery["search"]>,
referenceProducts: RelayToFlat<SearchProductsQuery["search"]>
referenceProducts: RelayToFlat<SearchProductsQuery["search"]>,
) => {
if (attribute.data.entityType === AttributeEntityTypeEnum.PAGE) {
return getPageReferenceAttributeDisplayData(attribute, referencePages);
} else if (attribute.data.entityType === AttributeEntityTypeEnum.PRODUCT) {
return getProductReferenceAttributeDisplayData(
attribute,
referenceProducts
referenceProducts,
);
}
};
@ -435,14 +436,14 @@ export const getAttributesDisplayData = (
attributes: AttributeInput[],
attributesWithNewFileValue: FormsetData<null, File>,
referencePages: RelayToFlat<SearchPagesQuery["search"]>,
referenceProducts: RelayToFlat<SearchProductsQuery["search"]>
referenceProducts: RelayToFlat<SearchProductsQuery["search"]>,
) =>
attributes.map(attribute => {
if (attribute.data.inputType === AttributeInputTypeEnum.REFERENCE) {
return getReferenceAttributeDisplayData(
attribute,
referencePages,
referenceProducts
referenceProducts,
);
}
if (attribute.data.inputType === AttributeInputTypeEnum.FILE) {
@ -453,28 +454,28 @@ export const getAttributesDisplayData = (
export const getSelectedReferencesFromAttribute = <T extends Node>(
attribute?: AttributeInput,
references?: T[]
references?: T[],
) =>
references?.filter(
value =>
!attribute?.value?.some(selectedValue => selectedValue === value.id)
!attribute?.value?.some(selectedValue => selectedValue === value.id),
) || [];
export const getAttributeValuesFromReferences = (
attributeId: string,
attributes?: AttributeInput[],
referencePages?: RelayToFlat<SearchPagesQuery["search"]>,
referenceProducts?: RelayToFlat<SearchProductsQuery["search"]>
referenceProducts?: RelayToFlat<SearchProductsQuery["search"]>,
) => {
const attribute = attributes?.find(attribute => attribute.id === attributeId);
if (attribute?.data?.entityType === AttributeEntityTypeEnum.PAGE) {
return mapPagesToChoices(
getSelectedReferencesFromAttribute(attribute, referencePages)
getSelectedReferencesFromAttribute(attribute, referencePages),
);
} else if (attribute?.data?.entityType === AttributeEntityTypeEnum.PRODUCT) {
return mapNodeToChoice(
getSelectedReferencesFromAttribute(attribute, referenceProducts)
getSelectedReferencesFromAttribute(attribute, referenceProducts),
);
}
return [];

View file

@ -1,14 +1,14 @@
import {
createAttributeMultiChangeHandler,
prepareAttributesInput
prepareAttributesInput,
} from "@saleor/attributes/utils/handlers";
import {
AttributeInput,
AttributeInputData
AttributeInputData,
} from "@saleor/components/Attributes";
import {
AttributeInputTypeEnum,
AttributeValueDetailsFragment
AttributeValueDetailsFragment,
} from "@saleor/graphql";
import { FormsetData } from "@saleor/hooks/useFormset";
@ -29,13 +29,13 @@ const multipleValueAttributes: FormsetData<AttributeInputData, string[]> = [
boolean: null,
date: null,
dateTime: null,
value: null
}
]
value: null,
},
],
},
id: "attr-1",
label: "Attribute 1",
value: []
value: [],
},
{
data: {
@ -53,7 +53,7 @@ const multipleValueAttributes: FormsetData<AttributeInputData, string[]> = [
boolean: null,
date: null,
dateTime: null,
value: null
value: null,
},
{
__typename: "AttributeValue",
@ -66,7 +66,7 @@ const multipleValueAttributes: FormsetData<AttributeInputData, string[]> = [
boolean: null,
date: null,
dateTime: null,
value: null
value: null,
},
{
__typename: "AttributeValue",
@ -79,13 +79,13 @@ const multipleValueAttributes: FormsetData<AttributeInputData, string[]> = [
boolean: null,
date: null,
dateTime: null,
value: null
}
]
value: null,
},
],
},
id: "attr-2",
label: "Attribute 2",
value: ["attr-2-v-3"]
value: ["attr-2-v-3"],
},
{
data: {
@ -97,7 +97,7 @@ const multipleValueAttributes: FormsetData<AttributeInputData, string[]> = [
file: {
__typename: "File",
contentType: "image/png",
url: "some-non-existing-url"
url: "some-non-existing-url",
},
id: "gdghdgdhkkdae",
name: "File First Value",
@ -107,14 +107,14 @@ const multipleValueAttributes: FormsetData<AttributeInputData, string[]> = [
boolean: null,
date: null,
dateTime: null,
value: null
}
]
value: null,
},
],
},
id: "ifudbgidfsb",
label: "File Attribute",
value: []
}
value: [],
},
];
const ATTR_ID = "123" as const;
@ -128,7 +128,7 @@ interface CreateAttribute {
const createAttribute = ({
inputType,
value
value,
}: CreateAttribute): AttributeInput => ({
data: {
entityType: null,
@ -137,29 +137,29 @@ const createAttribute = ({
// those values don't matter
selectedValues: [],
values: [],
unit: null
unit: null,
},
id: ATTR_ID,
label: "MyAttribute",
value: value !== null ? [value] : []
value: value !== null ? [value] : [],
});
const createSelectAttribute = (value: string) =>
createAttribute({
inputType: AttributeInputTypeEnum.DROPDOWN,
value
value,
});
const createReferenceAttribute = (value: string) =>
createAttribute({
inputType: AttributeInputTypeEnum.REFERENCE,
value
value,
});
const createBooleanAttribute = (value: string) =>
createAttribute({
inputType: AttributeInputTypeEnum.BOOLEAN,
value
value,
});
const createRichTextAttribute = (value: string) =>
@ -187,7 +187,7 @@ describe("Multiple select change handler", () => {
const handler = createAttributeMultiChangeHandler(
change,
multipleValueAttributes,
trigger
trigger,
);
handler("attr-2", "attr-2-v-1");
@ -206,7 +206,7 @@ describe("Multiple select change handler", () => {
const handler = createAttributeMultiChangeHandler(
change,
multipleValueAttributes,
trigger
trigger,
);
handler("attr-2", "attr-2-v-3");
@ -223,7 +223,7 @@ describe("Multiple select change handler", () => {
const handler = createAttributeMultiChangeHandler(
change,
multipleValueAttributes,
trigger
trigger,
);
handler("attr-2", "A Value");
@ -255,13 +255,13 @@ describe("Sending only changed attributes", () => {
const result = prepareAttributesInput({
attributes: [attribute],
prevAttributes: [prevAttribute],
updatedFileAttributes: []
updatedFileAttributes: [],
});
const expectedResult =
expected !== null ? [{ id: ATTR_ID, references: expected }] : [];
expect(result).toEqual(expectedResult);
}
},
);
});
describe("works with select attributes", () => {
@ -280,13 +280,13 @@ describe("Sending only changed attributes", () => {
const result = prepareAttributesInput({
attributes: [attribute],
prevAttributes: [prevAttribute],
updatedFileAttributes: []
updatedFileAttributes: [],
});
const expectedResult =
expected !== null ? [{ id: ATTR_ID, values: expected }] : [];
expect(result).toEqual(expectedResult);
}
},
);
});
describe("works with boolean attributes", () => {
@ -308,13 +308,13 @@ describe("Sending only changed attributes", () => {
const result = prepareAttributesInput({
attributes: [attribute],
prevAttributes: [prevAttribute],
updatedFileAttributes: []
updatedFileAttributes: [],
});
const expectedResult =
expected !== null ? [{ id: ATTR_ID, boolean: expected }] : [];
expect(result).toEqual(expectedResult);
}
},
);
});
describe("works with rich text attributes", () => {
@ -333,13 +333,13 @@ describe("Sending only changed attributes", () => {
const result = prepareAttributesInput({
attributes: [attribute],
prevAttributes: [prevAttribute],
updatedFileAttributes: []
updatedFileAttributes: [],
});
const expectedResult =
expected !== null ? [{ id: ATTR_ID, richText: expected }] : [];
expect(result).toEqual(expectedResult);
}
},
);
});
describe("works with date attributes", () => {
@ -358,13 +358,13 @@ describe("Sending only changed attributes", () => {
const result = prepareAttributesInput({
attributes: [attribute],
prevAttributes: [prevAttribute],
updatedFileAttributes: []
updatedFileAttributes: [],
});
const expectedResult =
expected !== null ? [{ id: ATTR_ID, date: expected }] : [];
expect(result).toEqual(expectedResult);
}
},
);
});
describe("works with date time attributes", () => {
@ -384,13 +384,13 @@ describe("Sending only changed attributes", () => {
const result = prepareAttributesInput({
attributes: [attribute],
prevAttributes: [prevAttribute],
updatedFileAttributes: []
updatedFileAttributes: [],
});
const expectedResult =
expected !== null ? [{ id: ATTR_ID, dateTime: expected }] : [];
expect(result).toEqual(expectedResult);
}
},
);
});
describe("works with swatch attributes", () => {
@ -409,13 +409,13 @@ describe("Sending only changed attributes", () => {
const result = prepareAttributesInput({
attributes: [attribute],
prevAttributes: [prevAttribute],
updatedFileAttributes: []
updatedFileAttributes: [],
});
const expectedResult =
expected !== null ? [{ id: ATTR_ID, values: expected }] : [];
expect(result).toEqual(expectedResult);
}
},
);
});
describe("works with numeric attributes", () => {
@ -434,13 +434,13 @@ describe("Sending only changed attributes", () => {
const result = prepareAttributesInput({
attributes: [attribute],
prevAttributes: [prevAttribute],
updatedFileAttributes: []
updatedFileAttributes: [],
});
const expectedResult =
expected !== null ? [{ id: ATTR_ID, values: expected }] : [];
expect(result).toEqual(expectedResult);
}
},
);
});
describe("works with file attributes", () => {
@ -452,8 +452,8 @@ describe("Sending only changed attributes", () => {
attributes: [attribute],
prevAttributes: [prevAttribute],
updatedFileAttributes: [
{ file: undefined, id: ATTR_ID, contentType: undefined, values: [] }
]
{ file: undefined, id: ATTR_ID, contentType: undefined, values: [] },
],
});
// Files are deleted by using AttributeValueDetele mutation
@ -472,17 +472,17 @@ describe("Sending only changed attributes", () => {
file: uploadUrl,
id: ATTR_ID,
contentType: "image/jpeg",
values: []
}
]
values: [],
},
],
});
expect(result).toEqual([
{
id: ATTR_ID,
file: uploadUrl,
contentType: "image/jpeg"
}
contentType: "image/jpeg",
},
]);
});
it("replaces existing image (bob.jpg -> juice.png)", () => {
@ -498,17 +498,17 @@ describe("Sending only changed attributes", () => {
file: uploadUrl,
id: ATTR_ID,
contentType: "image/png",
values: []
}
]
values: [],
},
],
});
expect(result).toEqual([
{
id: ATTR_ID,
file: uploadUrl,
contentType: "image/png"
}
contentType: "image/png",
},
]);
});
});

View file

@ -1,7 +1,7 @@
import { FetchResult } from "@apollo/client";
import {
AttributeInput,
AttributeInputData
AttributeInputData,
} from "@saleor/components/Attributes";
import {
AttributeEntityTypeEnum,
@ -13,12 +13,12 @@ import {
FileUploadMutationVariables,
PageSelectedAttributeFragment,
ProductFragment,
ProductVariantDetailsQuery
ProductVariantDetailsQuery,
} from "@saleor/graphql";
import {
FormsetAtomicData,
FormsetChange,
FormsetData
FormsetData,
} from "@saleor/hooks/useFormset";
import { FetchMoreProps, ReorderEvent } from "@saleor/types";
import { move, toggle } from "@saleor/utils/lists";
@ -28,7 +28,7 @@ import { getFileValuesToUploadFromAttributes, isFileValueUnused } from "./data";
export function createAttributeChangeHandler(
changeAttributeData: FormsetChange<string[]>,
triggerChange: () => void
triggerChange: () => void,
): FormsetChange<string> {
return (attributeId: string, value: string) => {
triggerChange();
@ -39,17 +39,17 @@ export function createAttributeChangeHandler(
export function createAttributeMultiChangeHandler(
changeAttributeData: FormsetChange<string[]>,
attributes: FormsetData<AttributeInputData, string[]>,
triggerChange: () => void
triggerChange: () => void,
): FormsetChange<string> {
return (attributeId: string, value: string) => {
const attribute = attributes.find(
attribute => attribute.id === attributeId
attribute => attribute.id === attributeId,
);
const newAttributeValues = toggle(
value,
attribute.value,
(a, b) => a === b
(a, b) => a === b,
);
triggerChange();
@ -59,7 +59,7 @@ export function createAttributeMultiChangeHandler(
export function createAttributeReferenceChangeHandler(
changeAttributeData: FormsetChange<string[]>,
triggerChange: () => void
triggerChange: () => void,
): FormsetChange<string[]> {
return (attributeId: string, values: string[]) => {
changeAttributeData(attributeId, values);
@ -71,11 +71,11 @@ export function createFetchReferencesHandler(
attributes: FormsetData<AttributeInputData, string[]>,
assignReferencesAttributeId: string,
fetchReferencePages?: (data: string) => void,
fetchReferenceProducts?: (data: string) => void
fetchReferenceProducts?: (data: string) => void,
) {
return (value: string) => {
const attribute = attributes?.find(
attribute => attribute.id === assignReferencesAttributeId
attribute => attribute.id === assignReferencesAttributeId,
);
if (!attribute) {
@ -100,10 +100,10 @@ export function createFetchMoreReferencesHandler(
attributes: FormsetData<AttributeInputData, string[]>,
assignReferencesAttributeId: string,
fetchMoreReferencePages?: FetchMoreProps,
fetchMoreReferenceProducts?: FetchMoreProps
fetchMoreReferenceProducts?: FetchMoreProps,
) {
const attribute = attributes?.find(
attribute => attribute.id === assignReferencesAttributeId
attribute => attribute.id === assignReferencesAttributeId,
);
if (!attribute) {
@ -122,13 +122,13 @@ export function createAttributeFileChangeHandler(
attributesWithNewFileValue: FormsetData<FormsetData<null, File>>,
addAttributeNewFileValue: (data: FormsetAtomicData<null, File>) => void,
changeAttributeNewFileValue: FormsetChange<File>,
triggerChange: () => void
triggerChange: () => void,
): FormsetChange<File> {
return (attributeId: string, value: File) => {
triggerChange();
const newFileValueAssigned = attributesWithNewFileValue.find(
attribute => attribute.id === attributeId
attribute => attribute.id === attributeId,
);
if (newFileValueAssigned) {
@ -138,7 +138,7 @@ export function createAttributeFileChangeHandler(
data: null,
id: attributeId,
label: null,
value
value,
});
}
@ -149,20 +149,20 @@ export function createAttributeFileChangeHandler(
export function createAttributeValueReorderHandler(
changeAttributeData: FormsetChange<string[]>,
attributes: FormsetData<AttributeInputData, string[]>,
triggerChange: () => void
triggerChange: () => void,
): FormsetChange<ReorderEvent> {
return (attributeId: string, reorder: ReorderEvent) => {
triggerChange();
const attribute = attributes.find(
attribute => attribute.id === attributeId
attribute => attribute.id === attributeId,
);
const reorderedValues = move(
attribute.value[reorder.oldIndex],
attribute.value,
(a, b) => a === b,
reorder.newIndex
reorder.newIndex,
);
changeAttributeData(attributeId, reorderedValues);
@ -171,37 +171,37 @@ export function createAttributeValueReorderHandler(
function getFileInput(
attribute: AttributeInput,
updatedFileAttributes: AttributeValueInput[]
updatedFileAttributes: AttributeValueInput[],
) {
const updatedFileAttribute = updatedFileAttributes.find(
attributeWithNewFile => attribute.id === attributeWithNewFile.id
attributeWithNewFile => attribute.id === attributeWithNewFile.id,
);
if (updatedFileAttribute) {
return {
file: updatedFileAttribute.file,
id: updatedFileAttribute.id,
contentType: updatedFileAttribute.contentType
contentType: updatedFileAttribute.contentType,
};
}
return {
file: attribute.data.selectedValues?.[0]?.file?.url,
contentType: attribute.data.selectedValues?.[0]?.file.contentType,
id: attribute.id
id: attribute.id,
};
}
function getBooleanInput(attribute: AttributeInput) {
return {
id: attribute.id,
boolean: JSON.parse(attribute.value[0] ?? "false")
boolean: JSON.parse(attribute.value[0] ?? "false"),
};
}
function getAttributesMap(attributes: AttributeInput[] | null) {
if (attributes && attributes?.length !== 0) {
return new Map(
attributes.map(attribute => [attribute.id, attribute.value])
attributes.map(attribute => [attribute.id, attribute.value]),
);
}
return new Map();
@ -216,7 +216,7 @@ interface AttributesArgs {
export const prepareAttributesInput = ({
attributes,
prevAttributes,
updatedFileAttributes
updatedFileAttributes,
}: AttributesArgs): AttributeValueInput[] => {
const prevAttributesMap = getAttributesMap(prevAttributes);
@ -247,7 +247,7 @@ export const prepareAttributesInput = ({
if (inputType === AttributeInputTypeEnum.RICH_TEXT) {
attrInput.push({
id: attr.id,
richText: attr.value[0]
richText: attr.value[0],
});
return attrInput;
}
@ -255,28 +255,28 @@ export const prepareAttributesInput = ({
if (inputType === AttributeInputTypeEnum.REFERENCE) {
attrInput.push({
id: attr.id,
references: attr.value
references: attr.value,
});
return attrInput;
}
if (inputType === AttributeInputTypeEnum.DATE) {
attrInput.push({
id: attr.id,
date: attr.value[0]
date: attr.value[0],
});
return attrInput;
}
if (inputType === AttributeInputTypeEnum.DATE_TIME) {
attrInput.push({
id: attr.id,
dateTime: attr.value[0]
dateTime: attr.value[0],
});
return attrInput;
}
attrInput.push({
id: attr.id,
values: attr.value
values: attr.value,
});
return attrInput;
@ -286,16 +286,16 @@ export const prepareAttributesInput = ({
export const handleUploadMultipleFiles = async (
attributesWithNewFileValue: FormsetData<null, File>,
uploadFile: (
variables: FileUploadMutationVariables
) => Promise<FetchResult<FileUploadMutation>>
variables: FileUploadMutationVariables,
) => Promise<FetchResult<FileUploadMutation>>,
) =>
Promise.all(
getFileValuesToUploadFromAttributes(attributesWithNewFileValue).map(
fileAttribute =>
uploadFile({
file: fileAttribute.value
})
)
file: fileAttribute.value,
}),
),
);
export const handleDeleteMultipleAttributeValues = async (
@ -306,21 +306,21 @@ export const handleDeleteMultipleAttributeValues = async (
| ProductVariantDetailsQuery["productVariant"]["nonSelectionAttributes"][0]
>,
deleteAttributeValue: (
variables: AttributeValueDeleteMutationVariables
) => Promise<FetchResult<AttributeValueDeleteMutation>>
variables: AttributeValueDeleteMutationVariables,
) => Promise<FetchResult<AttributeValueDeleteMutation>>,
) =>
Promise.all(
attributes.map(existingAttribute => {
const fileValueUnused = isFileValueUnused(
attributesWithNewFileValue,
existingAttribute
existingAttribute,
);
if (fileValueUnused) {
return deleteAttributeValue({
id: existingAttribute.values[0].id,
firstValues: 20
firstValues: 20,
});
}
})
}),
);

View file

@ -3,7 +3,7 @@ import {
AttributeErrorFragment,
useAttributeCreateMutation,
useUpdateMetadataMutation,
useUpdatePrivateMetadataMutation
useUpdatePrivateMetadataMutation,
} from "@saleor/graphql";
import useListSettings from "@saleor/hooks/useListSettings";
import useLocalPageInfo, { getMaxPage } from "@saleor/hooks/useLocalPageInfo";
@ -18,14 +18,14 @@ import {
isSelected,
move,
remove,
updateAtIndex
updateAtIndex,
} from "@saleor/utils/lists";
import React from "react";
import { useIntl } from "react-intl";
import slugify from "slugify";
import AttributePage, {
AttributePageFormData
AttributePageFormData,
} from "../../components/AttributePage";
import AttributeValueDeleteDialog from "../../components/AttributeValueDeleteDialog";
import AttributeValueEditDialog from "../../components/AttributeValueEditDialog";
@ -33,11 +33,11 @@ import {
attributeAddUrl,
AttributeAddUrlDialog,
AttributeAddUrlQueryParams,
attributeUrl
attributeUrl,
} from "../../urls";
import {
AttributeValueEditDialogFormData,
getAttributeData
getAttributeData,
} from "../../utils/data";
interface AttributeDetailsProps {
@ -48,12 +48,12 @@ const attributeValueAlreadyExistsError: AttributeErrorFragment = {
__typename: "AttributeError",
code: AttributeErrorCode.ALREADY_EXISTS,
field: "name",
message: ""
message: "",
};
function areValuesEqual(
a: AttributeValueEditDialogFormData,
b: AttributeValueEditDialogFormData
b: AttributeValueEditDialogFormData,
) {
return a.name === b.name;
}
@ -71,7 +71,7 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ params }) => {
>([]);
const { updateListSettings, settings } = useListSettings(
ListViews.ATTRIBUTE_VALUE_LIST
ListViews.ATTRIBUTE_VALUE_LIST,
);
const {
@ -79,7 +79,7 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ params }) => {
pageValues,
loadNextPage,
loadPreviousPage,
loadPage
loadPage,
} = useLocalPageInfo(values, settings?.rowNumber);
const [attributeCreate, attributeCreateOpts] = useAttributeCreateMutation({
@ -89,12 +89,12 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ params }) => {
status: "success",
text: intl.formatMessage({
id: "jTifz+",
defaultMessage: "Successfully created attribute"
})
defaultMessage: "Successfully created attribute",
}),
});
navigate(attributeUrl(data.attributeCreate.attribute.id));
}
}
},
});
const [updateMetadata] = useUpdateMetadataMutation({});
const [updatePrivateMetadata] = useUpdatePrivateMetadataMutation({});
@ -150,27 +150,27 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ params }) => {
values[pageInfo.startCursor + oldIndex],
values,
areValuesEqual,
pageInfo.startCursor + newIndex
)
pageInfo.startCursor + newIndex,
),
);
const handleCreate = async (data: AttributePageFormData) => {
const result = await attributeCreate({
variables: {
input: getAttributeData(data, values)
}
input: getAttributeData(data, values),
},
});
return {
id: result.data.attributeCreate?.attribute?.id || null,
errors: getMutationErrors(result)
errors: getMutationErrors(result),
};
};
const handleSubmit = createMetadataCreateHandler(
handleCreate,
updateMetadata,
updatePrivateMetadata
updatePrivateMetadata,
);
return (
@ -183,13 +183,13 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ params }) => {
onValueAdd={() => openModal("add-value")}
onValueDelete={id =>
openModal("remove-value", {
id
id,
})
}
onValueReorder={handleValueReorder}
onValueUpdate={id =>
openModal("edit-value", {
id
id,
})
}
saveButtonBarState={attributeCreateOpts.status}
@ -200,7 +200,7 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ params }) => {
endCursor: "",
hasNextPage: false,
hasPreviousPage: false,
startCursor: ""
startCursor: "",
},
edges: pageValues.map((value, valueIndex) => ({
__typename: "AttributeValueCountableEdge" as "AttributeValueCountableEdge",
@ -211,7 +211,7 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ params }) => {
? {
url: value.fileUrl,
contentType: value.contentType,
__typename: "File"
__typename: "File",
}
: null,
id: valueIndex.toString(),
@ -223,9 +223,9 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ params }) => {
boolean: null,
date: null,
dateTime: null,
...value
}
}))
...value,
},
})),
}}
settings={settings}
onUpdateListSettings={updateListSettings}

View file

@ -8,11 +8,11 @@ import {
useAttributeValueReorderMutation,
useAttributeValueUpdateMutation,
useUpdateMetadataMutation,
useUpdatePrivateMetadataMutation
useUpdatePrivateMetadataMutation,
} from "@saleor/graphql";
import useListSettings from "@saleor/hooks/useListSettings";
import useLocalPaginator, {
useLocalPaginationState
useLocalPaginationState,
} from "@saleor/hooks/useLocalPaginator";
import useNavigator from "@saleor/hooks/useNavigator";
import useNotifier from "@saleor/hooks/useNotifier";
@ -29,7 +29,7 @@ import { useIntl } from "react-intl";
import AttributeDeleteDialog from "../../components/AttributeDeleteDialog";
import AttributePage, {
AttributePageFormData
AttributePageFormData,
} from "../../components/AttributePage";
import AttributeValueDeleteDialog from "../../components/AttributeValueDeleteDialog";
import AttributeValueEditDialog from "../../components/AttributeValueEditDialog";
@ -37,7 +37,7 @@ import {
attributeListUrl,
attributeUrl,
AttributeUrlDialog,
AttributeUrlQueryParams
AttributeUrlQueryParams,
} from "../../urls";
interface AttributeDetailsProps {
@ -58,12 +58,12 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ id, params }) => {
>(navigate, params => attributeUrl(id, params), params);
const { updateListSettings, settings } = useListSettings(
ListViews.ATTRIBUTE_VALUE_LIST
ListViews.ATTRIBUTE_VALUE_LIST,
);
const [
valuesPaginationState,
setValuesPaginationState
setValuesPaginationState,
] = useLocalPaginationState(settings?.rowNumber);
const { data, loading } = useAttributeDetailsQuery({
@ -72,21 +72,21 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ id, params }) => {
firstValues: valuesPaginationState.first,
lastValues: valuesPaginationState.last,
afterValues: valuesPaginationState.after,
beforeValues: valuesPaginationState.before
beforeValues: valuesPaginationState.before,
},
skip: !settings
skip: !settings,
});
const paginateValues = useLocalPaginator(setValuesPaginationState);
const { loadNextPage, loadPreviousPage, pageInfo } = paginateValues(
data?.attribute?.choices?.pageInfo,
valuesPaginationState
valuesPaginationState,
);
const notifySaved = () =>
notify({
status: "success",
text: intl.formatMessage(commonMessages.savedChanges)
text: intl.formatMessage(commonMessages.savedChanges),
});
const [attributeDelete, attributeDeleteOpts] = useAttributeDeleteMutation({
@ -96,17 +96,17 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ id, params }) => {
status: "success",
text: intl.formatMessage({
id: "V/VAHG",
defaultMessage: "Attribute deleted"
})
defaultMessage: "Attribute deleted",
}),
});
navigate(attributeListUrl());
}
}
},
});
const [
attributeValueDelete,
attributeValueDeleteOpts
attributeValueDeleteOpts,
] = useAttributeValueDeleteMutation({
onCompleted: data => {
if (data?.attributeValueDelete.errors.length === 0) {
@ -115,24 +115,24 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ id, params }) => {
text: intl.formatMessage({
id: "7H2D5m",
defaultMessage: "Value deleted",
description: "attribute value deleted"
})
description: "attribute value deleted",
}),
});
closeModal();
}
}
},
});
const [
attributeValueUpdate,
attributeValueUpdateOpts
attributeValueUpdateOpts,
] = useAttributeValueUpdateMutation({
onCompleted: data => {
if (data?.attributeValueUpdate.errors.length === 0) {
notifySaved();
closeModal();
}
}
},
});
const [attributeUpdate, attributeUpdateOpts] = useAttributeUpdateMutation({
@ -140,12 +140,12 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ id, params }) => {
if (data?.attributeUpdate.errors.length === 0) {
notifySaved();
}
}
},
});
const [
attributeValueCreate,
attributeValueCreateOpts
attributeValueCreateOpts,
] = useAttributeValueCreateMutation({
onCompleted: data => {
if (data?.attributeValueCreate.errors.length === 0) {
@ -154,12 +154,12 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ id, params }) => {
text: intl.formatMessage({
id: "xVn5B0",
defaultMessage: "Added new value",
description: "added new attribute value"
})
description: "added new attribute value",
}),
});
closeModal();
}
}
},
});
const [attributeValueReorder] = useAttributeValueReorderMutation({
@ -169,13 +169,13 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ id, params }) => {
status: "error",
text: getAttributeErrorMessage(
data?.attributeReorderValues.errors[0],
intl
)
intl,
),
});
} else {
notifySaved();
}
}
},
});
const handleValueReorder = ({ newIndex, oldIndex }: ReorderEvent) =>
@ -189,30 +189,30 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ id, params }) => {
choices: {
__typename: "AttributeValueCountableConnection",
pageInfo: {
...data?.attribute.choices.pageInfo
...data?.attribute.choices.pageInfo,
},
edges: move(
data?.attribute.choices.edges[oldIndex],
data?.attribute.choices.edges,
(a, b) => a.node.id === b.node.id,
newIndex
)
}
newIndex,
),
},
},
errors: [],
},
errors: []
}
},
variables: {
id,
move: {
id: data?.attribute.choices.edges[oldIndex].node.id,
sortOrder: newIndex - oldIndex
sortOrder: newIndex - oldIndex,
},
firstValues: valuesPaginationState.first,
lastValues: valuesPaginationState.last,
afterValues: valuesPaginationState.after,
beforeValues: valuesPaginationState.before
}
beforeValues: valuesPaginationState.before,
},
});
const handleUpdate = async (data: AttributePageFormData) =>
@ -225,22 +225,22 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ id, params }) => {
"entityType",
"inputType",
"metadata",
"privateMetadata"
"privateMetadata",
]),
storefrontSearchPosition: parseInt(
data.storefrontSearchPosition,
10
)
}
}
})
10,
),
},
},
}),
);
const handleSubmit = createMetadataUpdateHandler(
data?.attribute,
handleUpdate,
variables => updateMetadata({ variables }),
variables => updatePrivateMetadata({ variables })
variables => updatePrivateMetadata({ variables }),
);
return (
@ -253,13 +253,13 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ id, params }) => {
onValueAdd={() => openModal("add-value")}
onValueDelete={id =>
openModal("remove-value", {
id
id,
})
}
onValueReorder={handleValueReorder}
onValueUpdate={id =>
openModal("edit-value", {
id
id,
})
}
saveButtonBarState={attributeUpdateOpts.status}
@ -280,8 +280,8 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ id, params }) => {
onConfirm={() =>
attributeDelete({
variables: {
id
}
id,
},
})
}
/>
@ -290,8 +290,8 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ id, params }) => {
open={params.action === "remove-value"}
name={getStringOrPlaceholder(
data?.attribute?.choices?.edges?.find(
value => params.id === value.node.id
)?.node.name
value => params.id === value.node.id,
)?.node.name,
)}
useName={true}
confirmButtonState={attributeValueDeleteOpts.status}
@ -303,8 +303,8 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ id, params }) => {
firstValues: valuesPaginationState.first,
lastValues: valuesPaginationState.last,
afterValues: valuesPaginationState.after,
beforeValues: valuesPaginationState.before
}
beforeValues: valuesPaginationState.before,
},
})
}
/>
@ -326,8 +326,8 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ id, params }) => {
firstValues: valuesPaginationState.first,
lastValues: valuesPaginationState.last,
afterValues: valuesPaginationState.after,
beforeValues: valuesPaginationState.before
}
beforeValues: valuesPaginationState.before,
},
})
}
/>
@ -335,8 +335,8 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ id, params }) => {
inputType={attributeFormData.inputType}
attributeValue={attributeValueFragmentToFormData(
data?.attribute?.choices?.edges?.find(
value => params.id === value.node.id
)?.node
value => params.id === value.node.id,
)?.node,
)}
confirmButtonState={attributeValueUpdateOpts.status}
disabled={loading}
@ -349,14 +349,14 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ id, params }) => {
attributeValueUpdate({
variables: {
id: data?.attribute.choices.edges.find(
value => params.id === value.node.id
value => params.id === value.node.id,
).node.id,
input,
firstValues: valuesPaginationState.first,
lastValues: valuesPaginationState.last,
afterValues: valuesPaginationState.after,
beforeValues: valuesPaginationState.before
}
beforeValues: valuesPaginationState.before,
},
})
}
/>

View file

@ -5,21 +5,21 @@ import {
getFiltersCurrentTab,
getFilterTabs,
getFilterVariables,
saveFilterTab
saveFilterTab,
} from "@saleor/attributes/views/AttributeList/filters";
import DeleteFilterTabDialog from "@saleor/components/DeleteFilterTabDialog";
import SaveFilterTabDialog, {
SaveFilterTabDialogFormData
SaveFilterTabDialogFormData,
} from "@saleor/components/SaveFilterTabDialog";
import {
useAttributeBulkDeleteMutation,
useAttributeListQuery
useAttributeListQuery,
} from "@saleor/graphql";
import useNavigator from "@saleor/hooks/useNavigator";
import useNotifier from "@saleor/hooks/useNotifier";
import usePaginator, {
createPaginationState,
PaginatorContext
PaginatorContext,
} from "@saleor/hooks/usePaginator";
import { DeleteIcon, IconButton } from "@saleor/macaw-ui";
import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers";
@ -38,7 +38,7 @@ import AttributeListPage from "../../components/AttributeListPage";
import {
attributeListUrl,
AttributeListUrlDialog,
AttributeListUrlQueryParams
AttributeListUrlQueryParams,
} from "../../urls";
import { getFilterQueryParam } from "./filters";
import { getSortQueryVariables } from "./sort";
@ -51,7 +51,7 @@ const AttributeList: React.FC<AttributeListProps> = ({ params }) => {
const navigate = useNavigator();
const notify = useNotifier();
const { isSelected, listElements, reset, toggle, toggleAll } = useBulkActions(
params.ids
params.ids,
);
const intl = useIntl();
@ -60,17 +60,17 @@ const AttributeList: React.FC<AttributeListProps> = ({ params }) => {
() => ({
...paginationState,
filter: getFilterVariables(params),
sort: getSortQueryVariables(params)
sort: getSortQueryVariables(params),
}),
[params]
[params],
);
const { data, loading, refetch } = useAttributeListQuery({
variables: queryVariables
variables: queryVariables,
});
const [
attributeBulkDelete,
attributeBulkDeleteOpts
attributeBulkDeleteOpts,
] = useAttributeBulkDeleteMutation({
onCompleted: data => {
if (data.attributeBulkDelete.errors.length === 0) {
@ -80,13 +80,13 @@ const AttributeList: React.FC<AttributeListProps> = ({ params }) => {
text: intl.formatMessage({
id: "lw9WIk",
defaultMessage: "Attributes successfully delete",
description: "deleted multiple attributes"
})
description: "deleted multiple attributes",
}),
});
reset();
refetch();
}
}
},
});
const tabs = getFilterTabs();
@ -101,13 +101,13 @@ const AttributeList: React.FC<AttributeListProps> = ({ params }) => {
const [
changeFilters,
resetFilters,
handleSearchChange
handleSearchChange,
] = createFilterHandlers({
cleanupFn: reset,
createUrl: attributeListUrl,
getFilterQueryParam,
navigate,
params
params,
});
const handleTabChange = (tab: number) => {
@ -115,8 +115,8 @@ const AttributeList: React.FC<AttributeListProps> = ({ params }) => {
navigate(
attributeListUrl({
activeTab: tab.toString(),
...getFilterTabs()[tab - 1].data
})
...getFilterTabs()[tab - 1].data,
}),
);
};
@ -134,7 +134,7 @@ const AttributeList: React.FC<AttributeListProps> = ({ params }) => {
const paginationValues = usePaginator({
pageInfo: maybe(() => data.attributes.pageInfo),
paginationState,
queryString: params
queryString: params,
});
const handleSort = createSortHandler(navigate, attributeListUrl, params);
@ -166,7 +166,7 @@ const AttributeList: React.FC<AttributeListProps> = ({ params }) => {
color="primary"
onClick={() =>
openModal("remove", {
ids: listElements
ids: listElements,
})
}
>

View file

@ -18,7 +18,7 @@ describe("Filtering query params", () => {
it("should not be empty object if params given", () => {
const params: AttributeListUrlFilters = {
isVariantOnly: true.toString()
isVariantOnly: true.toString(),
};
const filterVariables = getFilterVariables(params);
@ -32,26 +32,26 @@ describe("Filtering URL params", () => {
const filters = createFilterStructure(intl, {
filterableInStorefront: {
active: false,
value: true
value: true,
},
isVariantOnly: {
active: false,
value: true
value: true,
},
valueRequired: {
active: false,
value: true
value: true,
},
visibleInStorefront: {
active: false,
value: true
}
value: true,
},
});
it("should be empty if no active filters", () => {
const filterQueryParams = getFilterQueryParams(
filters,
getFilterQueryParam
getFilterQueryParam,
);
expect(getExistingKeys(filterQueryParams)).toHaveLength(0);
@ -60,7 +60,7 @@ describe("Filtering URL params", () => {
it("should not be empty if active filters are present", () => {
const filterQueryParams = getFilterQueryParams(
setFilterOptsStatus(filters, true),
getFilterQueryParam
getFilterQueryParam,
);
expect(filterQueryParams).toMatchSnapshot();

View file

@ -1,6 +1,6 @@
import {
AttributeFilterKeys,
AttributeListFilterOpts
AttributeListFilterOpts,
} from "@saleor/attributes/components/AttributeListPage";
import { FilterElement } from "@saleor/components/Filter";
import { AttributeFilterInput } from "@saleor/graphql";
@ -9,41 +9,41 @@ import { maybe, parseBoolean } from "@saleor/misc";
import {
createFilterTabUtils,
createFilterUtils,
getSingleValueQueryParam
getSingleValueQueryParam,
} from "../../../utils/filters";
import {
AttributeListUrlFilters,
AttributeListUrlFiltersEnum,
AttributeListUrlQueryParams
AttributeListUrlQueryParams,
} from "../../urls";
export const ATTRIBUTE_FILTERS_KEY = "attributeFilters";
export function getFilterOpts(
params: AttributeListUrlFilters
params: AttributeListUrlFilters,
): AttributeListFilterOpts {
return {
filterableInStorefront: {
active: params.filterableInStorefront !== undefined,
value: maybe(() => parseBoolean(params.filterableInStorefront, true))
value: maybe(() => parseBoolean(params.filterableInStorefront, true)),
},
isVariantOnly: {
active: params.isVariantOnly !== undefined,
value: maybe(() => parseBoolean(params.isVariantOnly, true))
value: maybe(() => parseBoolean(params.isVariantOnly, true)),
},
valueRequired: {
active: params.valueRequired !== undefined,
value: maybe(() => parseBoolean(params.valueRequired, true))
value: maybe(() => parseBoolean(params.valueRequired, true)),
},
visibleInStorefront: {
active: params.visibleInStorefront !== undefined,
value: maybe(() => parseBoolean(params.visibleInStorefront, true))
}
value: maybe(() => parseBoolean(params.visibleInStorefront, true)),
},
};
}
export function getFilterVariables(
params: AttributeListUrlFilters
params: AttributeListUrlFilters,
): AttributeFilterInput {
return {
filterableInStorefront:
@ -62,12 +62,12 @@ export function getFilterVariables(
visibleInStorefront:
params.visibleInStorefront !== undefined
? parseBoolean(params.visibleInStorefront, false)
: undefined
: undefined,
};
}
export function getFilterQueryParam(
filter: FilterElement<AttributeFilterKeys>
filter: FilterElement<AttributeFilterKeys>,
): AttributeListUrlFilters {
const { name } = filter;
@ -75,25 +75,25 @@ export function getFilterQueryParam(
case AttributeFilterKeys.filterableInStorefront:
return getSingleValueQueryParam(
filter,
AttributeListUrlFiltersEnum.filterableInStorefront
AttributeListUrlFiltersEnum.filterableInStorefront,
);
case AttributeFilterKeys.isVariantOnly:
return getSingleValueQueryParam(
filter,
AttributeListUrlFiltersEnum.isVariantOnly
AttributeListUrlFiltersEnum.isVariantOnly,
);
case AttributeFilterKeys.valueRequired:
return getSingleValueQueryParam(
filter,
AttributeListUrlFiltersEnum.valueRequired
AttributeListUrlFiltersEnum.valueRequired,
);
case AttributeFilterKeys.visibleInStorefront:
return getSingleValueQueryParam(
filter,
AttributeListUrlFiltersEnum.visibleInStorefront
AttributeListUrlFiltersEnum.visibleInStorefront,
);
}
}
@ -101,13 +101,13 @@ export function getFilterQueryParam(
export const {
deleteFilterTab,
getFilterTabs,
saveFilterTab
saveFilterTab,
} = createFilterTabUtils<AttributeListUrlFilters>(ATTRIBUTE_FILTERS_KEY);
export const {
areFiltersApplied,
getActiveFilters,
getFiltersCurrentTab
getFiltersCurrentTab,
} = createFilterUtils<AttributeListUrlQueryParams, AttributeListUrlFilters>(
AttributeListUrlFiltersEnum
AttributeListUrlFiltersEnum,
);

View file

@ -3,7 +3,7 @@ import { AttributeSortField } from "@saleor/graphql";
import { createGetSortQueryVariables } from "@saleor/utils/sort";
export function getSortQueryField(
sort: AttributeListUrlSortField
sort: AttributeListUrlSortField,
): AttributeSortField {
switch (sort) {
case AttributeListUrlSortField.name:
@ -22,5 +22,5 @@ export function getSortQueryField(
}
export const getSortQueryVariables = createGetSortQueryVariables(
getSortQueryField
getSortQueryField,
);

View file

@ -11,12 +11,12 @@ const apolloClient = setupApi();
function renderAuthProvider() {
const intl = {
formatMessage: ({ defaultMessage }) => defaultMessage
formatMessage: ({ defaultMessage }) => defaultMessage,
};
const notify = jest.fn();
const saleorClient = createSaleorClient({
apiUrl: process.env.API_URI,
channel: ""
channel: "",
});
const wrapper = ({ children }) => (
<IntlProvider defaultLocale="en" locale="en">
@ -28,7 +28,7 @@ function renderAuthProvider() {
const { result } = renderHook(
() => useAuthProvider({ intl: intl as any, notify, apolloClient }),
{ wrapper }
{ wrapper },
);
return result;
@ -37,12 +37,12 @@ function renderAuthProvider() {
const adminCredentials = {
email: "admin@example.com",
password: "admin",
token: null
token: null,
};
const nonStaffUserCredentials = {
email: "client@example.com",
password: "password"
password: "password",
};
beforeEach(() => {
@ -57,7 +57,7 @@ xdescribe("User", () => {
await act(async () => {
const result = await hook.current.login(
adminCredentials.email,
adminCredentials.password
adminCredentials.password,
);
expect(result.user?.email).toBe(adminCredentials.email);
});
@ -72,7 +72,7 @@ xdescribe("User", () => {
await act(async () => {
const result = await hook.current.login(
adminCredentials.email,
"NotAValidPassword123!"
"NotAValidPassword123!",
);
expect(result.user).toBe(null);
});
@ -87,7 +87,7 @@ xdescribe("User", () => {
await act(async () => {
const result = await hook.current.login(
nonStaffUserCredentials.email,
nonStaffUserCredentials.password
nonStaffUserCredentials.password,
);
expect(result.user).toBe(null);
});

View file

@ -9,16 +9,16 @@ const useStyles = makeStyles(
theme => ({
footer: {
position: "absolute",
bottom: theme.spacing(4)
bottom: theme.spacing(4),
},
logo: {
display: "block",
height: 40,
marginBottom: theme.spacing(4)
marginBottom: theme.spacing(4),
},
mainPanel: {
[theme.breakpoints.down("sm")]: {
padding: theme.spacing(2)
padding: theme.spacing(2),
},
background: theme.palette.background.paper,
display: "flex",
@ -26,27 +26,27 @@ const useStyles = makeStyles(
height: "100vh",
justifyContent: "center",
padding: theme.spacing(5, 6, 4, 6),
width: "100%"
width: "100%",
},
mainPanelContent: {
[theme.breakpoints.up("xs")]: {
width: "100%"
width: "100%",
},
[theme.breakpoints.up("sm")]: {
width: 328
width: 328,
},
"@media (min-width: 1440px)": {
width: 380
width: 380,
},
margin: "auto",
width: "100%"
width: "100%",
},
root: {
[theme.breakpoints.up("lg")]: {
gridTemplateColumns: "560px 1fr"
gridTemplateColumns: "560px 1fr",
},
"@media (min-width: 1440px)": {
gridTemplateColumns: "780px 1fr"
gridTemplateColumns: "780px 1fr",
},
display: "grid",
gridTemplateColumns: "1fr",
@ -54,24 +54,24 @@ const useStyles = makeStyles(
height: "100vh",
overflow: "hidden",
position: "relative",
width: "100vw"
width: "100vw",
},
sidebar: {
[theme.breakpoints.up("lg")]: {
alignItems: "center",
display: "flex"
display: "flex",
},
display: "none"
display: "none",
},
sidebarArt: {
"& svg": {
width: "100%"
}
}
width: "100%",
},
},
}),
{
name: "Layout"
}
name: "Layout",
},
);
const Layout: React.FC = props => {

View file

@ -8,10 +8,10 @@ const useStyles = makeStyles(
alignItems: "center",
display: "flex",
height: "100vh",
justifyContent: "center"
}
justifyContent: "center",
},
{ name: "LoginLoading" }
},
{ name: "LoginLoading" },
);
const LoginLoading: React.FC = props => {
const classes = useStyles(props);

View file

@ -11,12 +11,12 @@ const props: Omit<LoginCardProps, "classes"> = {
{
__typename: "ExternalAuthentication",
id: "auth.plugin.example",
name: "Example auth plugin"
}
name: "Example auth plugin",
},
],
loading: false,
onExternalAuthentication: () => undefined,
onSubmit: () => undefined
onSubmit: () => undefined,
};
storiesOf("Views / Authentication / Log in", module)

View file

@ -2,7 +2,7 @@ import {
CircularProgress,
Divider,
TextField,
Typography
Typography,
} from "@material-ui/core";
import { UserContextError } from "@saleor/auth/types";
import { passwordResetUrl } from "@saleor/auth/urls";
@ -36,7 +36,7 @@ const LoginCard: React.FC<LoginCardProps> = props => {
loading,
externalAuthentications = [],
onExternalAuthentication,
onSubmit
onSubmit,
} = props;
const classes = useStyles(props);
@ -76,7 +76,7 @@ const LoginCard: React.FC<LoginCardProps> = props => {
onChange={handleChange}
value={data.email}
inputProps={{
"data-test-id": "email"
"data-test-id": "email",
}}
disabled={disabled}
/>
@ -87,14 +87,14 @@ const LoginCard: React.FC<LoginCardProps> = props => {
autoComplete="password"
label={intl.formatMessage({
id: "5sg7KC",
defaultMessage: "Password"
defaultMessage: "Password",
})}
name="password"
onChange={handleChange}
type={showPassword ? "text" : "password"}
value={data.password}
inputProps={{
"data-test-id": "password"
"data-test-id": "password",
}}
disabled={disabled}
/>

View file

@ -23,14 +23,14 @@ const getLoginFormData = () => {
if (DEMO_MODE) {
return {
email: "admin@example.com",
password: "admin"
password: "admin",
};
}
return { email: "", password: "" };
};
function useLoginForm(
onSubmit: (data: LoginFormData) => SubmitPromise
onSubmit: (data: LoginFormData) => SubmitPromise,
): UseLoginFormResult {
const form = useForm(getLoginFormData());
@ -43,7 +43,7 @@ function useLoginForm(
return {
change,
data,
submit
submit,
};
}

Some files were not shown because too many files have changed in this diff Show more