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", "camelcase": "off",
"capitalized-comments": "off", "capitalized-comments": "off",
"chai-friendly/no-unused-expressions": "error", "chai-friendly/no-unused-expressions": "error",
"comma-dangle": "off", "comma-dangle": ["error", "always-multiline"],
"complexity": "off", "complexity": "off",
"constructor-super": "error", "constructor-super": "error",
"curly": "error", "curly": "error",

View file

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

View file

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

View file

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

View file

@ -18,7 +18,7 @@ const AppActivateDialog: React.FC<AppActivateDialogProps> = ({
open, open,
name, name,
onClose, onClose,
onConfirm onConfirm,
}) => { }) => {
const intl = useIntl(); const intl = useIntl();
@ -27,7 +27,7 @@ const AppActivateDialog: React.FC<AppActivateDialogProps> = ({
confirmButtonLabel={intl.formatMessage({ confirmButtonLabel={intl.formatMessage({
id: "D3E2b5", id: "D3E2b5",
defaultMessage: "Activate", defaultMessage: "Activate",
description: "button label" description: "button label",
})} })}
confirmButtonState={confirmButtonState} confirmButtonState={confirmButtonState}
open={open} open={open}
@ -36,7 +36,7 @@ const AppActivateDialog: React.FC<AppActivateDialogProps> = ({
title={intl.formatMessage({ title={intl.formatMessage({
id: "YHNozE", id: "YHNozE",
defaultMessage: "Activate App", defaultMessage: "Activate App",
description: "dialog header" description: "dialog header",
})} })}
variant="default" 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." defaultMessage="Are you sure you want to activate {name}? Activating will start gathering events."
description="activate app" description="activate app"
values={{ 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 React from "react";
import AppDeactivateDialog, { import AppDeactivateDialog, {
AppDeactivateDialogProps AppDeactivateDialogProps,
} from "./AppDeactivateDialog"; } from "./AppDeactivateDialog";
const props: AppDeactivateDialogProps = { const props: AppDeactivateDialogProps = {
@ -11,7 +11,7 @@ const props: AppDeactivateDialogProps = {
name: "App", name: "App",
onClose: () => undefined, onClose: () => undefined,
onConfirm: () => undefined, onConfirm: () => undefined,
open: true open: true,
}; };
storiesOf("Views / Apps / Deactivate app", module) storiesOf("Views / Apps / Deactivate app", module)

View file

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

View file

@ -5,24 +5,24 @@ export default defineMessages({
id: "73RU3R", id: "73RU3R",
defaultMessage: 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.", "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: { deactivateNamedApp: {
id: "w6Gau0", id: "w6Gau0",
defaultMessage: 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.", "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: { deactivateLocalApp: {
id: "7O2EsY", id: "7O2EsY",
defaultMessage: defaultMessage:
"Are you sure you want to disable this app? Your data will be kept until you reactivate the app.", "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: { deactivateLocalNamedApp: {
id: "Np7J92", id: "Np7J92",
defaultMessage: defaultMessage:
"Are you sure you want to disable {name}? Your data will be kept until you reactivate the app.", "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, onClose: () => undefined,
onConfirm: () => undefined, onConfirm: () => undefined,
open: true, open: true,
type: "EXTERNAL" type: "EXTERNAL",
}; };
storiesOf("Views / Apps / Delete app", module) storiesOf("Views / Apps / Delete app", module)

View file

@ -20,7 +20,7 @@ const AppDeleteDialog: React.FC<AppDeleteDialogProps> = ({
name, name,
onClose, onClose,
onConfirm, onConfirm,
type type,
}) => { }) => {
const intl = useIntl(); const intl = useIntl();
@ -33,7 +33,7 @@ const AppDeleteDialog: React.FC<AppDeleteDialogProps> = ({
title={intl.formatMessage({ title={intl.formatMessage({
id: "zQX6xO", id: "zQX6xO",
defaultMessage: "Delete App", defaultMessage: "Delete App",
description: "dialog header" description: "dialog header",
})} })}
variant="delete" 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?" 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" description="delete app"
values={{ 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?" 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" description="delete custom app"
values={{ values={{
name: <strong>{getStringOrPlaceholder(name)}</strong> name: <strong>{getStringOrPlaceholder(name)}</strong>,
}} }}
/> />
)} )}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -7,25 +7,25 @@ import { useExternalApp } from "../ExternalAppContext";
const sendResponseStatus = ( const sendResponseStatus = (
actionId: string, actionId: string,
ok: boolean ok: boolean,
): DispatchResponseEvent => ({ ): DispatchResponseEvent => ({
type: "response", type: "response",
payload: { payload: {
actionId, actionId,
ok ok,
} },
}); });
export const useAppActions = ( export const useAppActions = (
frameEl: React.MutableRefObject<HTMLIFrameElement>, frameEl: React.MutableRefObject<HTMLIFrameElement>,
appOrigin: string appOrigin: string,
) => { ) => {
const navigate = useNavigator(); const navigate = useNavigator();
const { closeApp } = useExternalApp(); const { closeApp } = useExternalApp();
const intl = useIntl(); const intl = useIntl();
const actionReducer = ( const actionReducer = (
action: Actions | undefined action: Actions | undefined,
): DispatchResponseEvent => { ): DispatchResponseEvent => {
switch (action?.type) { switch (action?.type) {
case "redirect": { case "redirect": {
@ -48,8 +48,8 @@ export const useAppActions = (
intl.formatMessage({ intl.formatMessage({
id: "MSItJD", id: "MSItJD",
defaultMessage: 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 { return {
postToExtension postToExtension,
}; };
}; };

View file

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

View file

@ -18,7 +18,7 @@ const AppInProgressDeleteDialog: React.FC<AppInProgressDeleteDialogProps> = ({
open, open,
name, name,
onClose, onClose,
onConfirm onConfirm,
}) => { }) => {
const intl = useIntl(); const intl = useIntl();
@ -31,7 +31,7 @@ const AppInProgressDeleteDialog: React.FC<AppInProgressDeleteDialogProps> = ({
title={intl.formatMessage({ title={intl.formatMessage({
id: "zQX6xO", id: "zQX6xO",
defaultMessage: "Delete App", defaultMessage: "Delete App",
description: "dialog header" description: "dialog header",
})} })}
variant="delete" 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?" 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" description="delete app"
values={{ 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> = ({ export const AppInstallErrorPage: React.FC<AppInstallErrorPageProps> = ({
onBack onBack,
}) => { }) => {
const classes = useStyles({}); const classes = useStyles({});

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -4,35 +4,35 @@ import { makeStyles } from "@saleor/macaw-ui";
export const useStyles = makeStyles( export const useStyles = makeStyles(
theme => ({ theme => ({
cancel: { cancel: {
marginRight: theme.spacing(1) marginRight: theme.spacing(1),
}, },
closeContainer: { closeContainer: {
display: "flex", display: "flex",
justifyContent: "flex-end", justifyContent: "flex-end",
position: "relative", position: "relative",
right: theme.spacing(-1), right: theme.spacing(-1),
top: theme.spacing(-1) top: theme.spacing(-1),
}, },
content: { content: {
display: "grid", display: "grid",
gridColumnGap: theme.spacing(3), gridColumnGap: theme.spacing(3),
gridTemplateColumns: "1fr 60px", gridTemplateColumns: "1fr 60px",
marginBottom: theme.spacing(3) marginBottom: theme.spacing(3),
}, },
copy: { copy: {
marginTop: theme.spacing(), marginTop: theme.spacing(),
position: "relative", position: "relative",
right: theme.spacing(1) right: theme.spacing(1),
}, },
paper: { paper: {
background: fade(theme.palette.primary.main, 0.05), background: fade(theme.palette.primary.main, 0.05),
padding: theme.spacing(2, 3) padding: theme.spacing(2, 3),
}, },
root: { 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, AppErrorFragment,
AppUpdateMutation, AppUpdateMutation,
PermissionEnum, PermissionEnum,
ShopInfoQuery ShopInfoQuery,
} from "@saleor/graphql"; } from "@saleor/graphql";
import { SubmitPromise } from "@saleor/hooks/useForm"; import { SubmitPromise } from "@saleor/hooks/useForm";
import useNavigator from "@saleor/hooks/useNavigator"; import useNavigator from "@saleor/hooks/useNavigator";
@ -48,7 +48,7 @@ export interface CustomAppDetailsPageProps {
onTokenClose: () => void; onTokenClose: () => void;
onTokenCreate: () => void; onTokenCreate: () => void;
onSubmit: ( onSubmit: (
data: CustomAppDetailsPageFormData data: CustomAppDetailsPageFormData,
) => SubmitPromise<AppErrorFragment[]>; ) => SubmitPromise<AppErrorFragment[]>;
webhookCreateHref: string; webhookCreateHref: string;
onWebhookRemove: (id: string) => void; onWebhookRemove: (id: string) => void;
@ -73,7 +73,7 @@ const CustomAppDetailsPage: React.FC<CustomAppDetailsPageProps> = props => {
webhookCreateHref, webhookCreateHref,
onWebhookRemove, onWebhookRemove,
onAppActivateOpen, onAppActivateOpen,
onAppDeactivateOpen onAppDeactivateOpen,
} = props; } = props;
const intl = useIntl(); const intl = useIntl();
const classes = useStyles({}); const classes = useStyles({});
@ -89,11 +89,11 @@ const CustomAppDetailsPage: React.FC<CustomAppDetailsPageProps> = props => {
permissions?.filter( permissions?.filter(
perm => perm =>
app?.permissions?.filter(userPerm => userPerm.code === perm.code) app?.permissions?.filter(userPerm => userPerm.code === perm.code)
.length === 0 .length === 0,
).length === 0 || false, ).length === 0 || false,
isActive: !!app?.isActive, isActive: !!app?.isActive,
name: app?.name || "", name: app?.name || "",
permissions: app?.permissions?.map(perm => perm.code) || [] permissions: app?.permissions?.map(perm => perm.code) || [],
}; };
return ( return (
@ -174,13 +174,13 @@ const CustomAppDetailsPage: React.FC<CustomAppDetailsPageProps> = props => {
fullAccessLabel={intl.formatMessage({ fullAccessLabel={intl.formatMessage({
id: "D4nzdD", id: "D4nzdD",
defaultMessage: "Grant this app full access to the store", defaultMessage: "Grant this app full access to the store",
description: "checkbox label" description: "checkbox label",
})} })}
description={intl.formatMessage({ description={intl.formatMessage({
id: "flP8Hj", id: "flP8Hj",
defaultMessage: defaultMessage:
"Expand or restrict app permissions to access certain part of Saleor system.", "Expand or restrict app permissions to access certain part of Saleor system.",
description: "card description" description: "card description",
})} })}
/> />
</div> </div>

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -4,19 +4,19 @@ import { makeStyles } from "@saleor/macaw-ui";
export const useStyles = makeStyles( export const useStyles = makeStyles(
theme => ({ theme => ({
cancel: { cancel: {
marginRight: theme.spacing(1) marginRight: theme.spacing(1),
}, },
copy: { copy: {
marginTop: theme.spacing(), marginTop: theme.spacing(),
position: "relative", position: "relative",
right: theme.spacing(1) right: theme.spacing(1),
}, },
paper: { paper: {
background: fade(theme.palette.primary.main, 0.05), 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", name: "Slack",
onClose: () => undefined, onClose: () => undefined,
onConfirm: () => undefined, onConfirm: () => undefined,
open: true open: true,
}; };
storiesOf("Views / Apps / Custom app details / Token delete", module) storiesOf("Views / Apps / Custom app details / Token delete", module)

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -4,31 +4,31 @@ export const messages = defineMessages({
appInstalled: { appInstalled: {
id: "0fM/pV", id: "0fM/pV",
defaultMessage: "App installed", defaultMessage: "App installed",
description: "message title" description: "message title",
}, },
appRemoved: { appRemoved: {
id: "uIPD1i", id: "uIPD1i",
defaultMessage: "App successfully removed", defaultMessage: "App successfully removed",
description: "app has been removed" description: "app has been removed",
}, },
appReadyToUse: { appReadyToUse: {
id: "ZprV2g", id: "ZprV2g",
defaultMessage: "{name} is ready to be used", defaultMessage: "{name} is ready to be used",
description: "app has been installed" description: "app has been installed",
}, },
appCouldntInstall: { appCouldntInstall: {
id: "5t/4um", id: "5t/4um",
defaultMessage: "Couldnt Install {name}", defaultMessage: "Couldnt Install {name}",
description: "message title" description: "message title",
}, },
appActivated: { appActivated: {
id: "D/+84n", id: "D/+84n",
defaultMessage: "App activated", defaultMessage: "App activated",
description: "snackbar text" description: "snackbar text",
}, },
appDeactivated: { appDeactivated: {
id: "USO8PB", id: "USO8PB",
defaultMessage: "App deactivated", 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 { useIntl } from "react-intl";
import CustomAppCreatePage, { import CustomAppCreatePage, {
CustomAppCreatePageFormData CustomAppCreatePageFormData,
} from "../../components/CustomAppCreatePage"; } from "../../components/CustomAppCreatePage";
import { customAppUrl } from "../../urls"; import { customAppUrl } from "../../urls";
import { messages } from "./messages"; import { messages } from "./messages";
@ -18,7 +18,7 @@ interface CustomAppCreateProps {
setToken: (token: string) => void; setToken: (token: string) => void;
} }
export const CustomAppCreate: React.FC<CustomAppCreateProps> = ({ export const CustomAppCreate: React.FC<CustomAppCreateProps> = ({
setToken setToken,
}) => { }) => {
const navigate = useNavigator(); const navigate = useNavigator();
const notify = useNotifier(); const notify = useNotifier();
@ -29,7 +29,7 @@ export const CustomAppCreate: React.FC<CustomAppCreateProps> = ({
if (data.appCreate.errors.length === 0) { if (data.appCreate.errors.length === 0) {
notify({ notify({
status: "success", status: "success",
text: intl.formatMessage(commonMessages.savedChanges) text: intl.formatMessage(commonMessages.savedChanges),
}); });
navigate(customAppUrl(data.appCreate.app.id)); navigate(customAppUrl(data.appCreate.app.id));
setToken(data.appCreate.authToken); setToken(data.appCreate.authToken);
@ -37,7 +37,7 @@ export const CustomAppCreate: React.FC<CustomAppCreateProps> = ({
}; };
const [createApp, createAppOpts] = useAppCreateMutation({ const [createApp, createAppOpts] = useAppCreateMutation({
onCompleted: onSubmit onCompleted: onSubmit,
}); });
const handleSubmit = async (data: CustomAppCreatePageFormData) => const handleSubmit = async (data: CustomAppCreatePageFormData) =>
@ -48,10 +48,10 @@ export const CustomAppCreate: React.FC<CustomAppCreateProps> = ({
name: data.name, name: data.name,
permissions: data.hasFullAccess permissions: data.hasFullAccess
? shop.permissions.map(permission => permission.code) ? shop.permissions.map(permission => permission.code)
: data.permissions : data.permissions,
} },
} },
}) }),
); );
return ( return (

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -5,144 +5,144 @@ export const messages = defineMessages({
attributeLabel: { attributeLabel: {
id: "xOEZjV", id: "xOEZjV",
defaultMessage: "Default Label", defaultMessage: "Default Label",
description: "attribute's label" description: "attribute's label",
}, },
attributeSlug: { attributeSlug: {
id: "P79U4b", id: "P79U4b",
defaultMessage: "Attribute Code", defaultMessage: "Attribute Code",
description: "attribute's slug short code label" description: "attribute's slug short code label",
}, },
attributeSlugHelperText: { attributeSlugHelperText: {
id: "Q7uuDr", id: "Q7uuDr",
defaultMessage: "This is used internally. Make sure you dont use spaces", 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: { entityType: {
id: "LnRlch", id: "LnRlch",
defaultMessage: "Entity", defaultMessage: "Entity",
description: "attribute's editor component entity" description: "attribute's editor component entity",
}, },
inputType: { inputType: {
id: "oIvtua", id: "oIvtua",
defaultMessage: "Catalog Input type for Store Owner", defaultMessage: "Catalog Input type for Store Owner",
description: "attribute's editor component" description: "attribute's editor component",
}, },
valueRequired: { valueRequired: {
id: "njBulj", id: "njBulj",
defaultMessage: "Value Required", defaultMessage: "Value Required",
description: "check to require attribute to have value" description: "check to require attribute to have value",
}, },
selectUnit: { selectUnit: {
id: "PiSXjb", id: "PiSXjb",
defaultMessage: "Select unit", defaultMessage: "Select unit",
description: "check to require numeric attribute unit" description: "check to require numeric attribute unit",
}, },
unitSystem: { unitSystem: {
id: "ghje1I", id: "ghje1I",
defaultMessage: "System", defaultMessage: "System",
description: "numeric attribute unit system" description: "numeric attribute unit system",
}, },
unitOf: { unitOf: {
id: "zWM89r", id: "zWM89r",
defaultMessage: "Units of", defaultMessage: "Units of",
description: "numeric attribute units of" description: "numeric attribute units of",
}, },
unit: { unit: {
id: "Orgqv4", id: "Orgqv4",
defaultMessage: "Unit", defaultMessage: "Unit",
description: "numeric attribute unit" description: "numeric attribute unit",
} },
}); });
export const inputTypeMessages = defineMessages({ export const inputTypeMessages = defineMessages({
dropdown: { dropdown: {
id: "bZksto", id: "bZksto",
defaultMessage: "Dropdown", defaultMessage: "Dropdown",
description: "product attribute type" description: "product attribute type",
}, },
file: { file: {
id: "z1y9oL", id: "z1y9oL",
defaultMessage: "File", defaultMessage: "File",
description: "file attribute type" description: "file attribute type",
}, },
multiselect: { multiselect: {
id: "cKjFfl", id: "cKjFfl",
defaultMessage: "Multiple Select", defaultMessage: "Multiple Select",
description: "product attribute type" description: "product attribute type",
}, },
references: { references: {
id: "5dLpx0", id: "5dLpx0",
defaultMessage: "References", defaultMessage: "References",
description: "references attribute type" description: "references attribute type",
}, },
text: { text: {
id: "fdbqIs", id: "fdbqIs",
defaultMessage: "Text", defaultMessage: "Text",
description: "text attribute type" description: "text attribute type",
}, },
numeric: { numeric: {
id: "SNiyXb", id: "SNiyXb",
defaultMessage: "Numeric", defaultMessage: "Numeric",
description: "numeric attribute type" description: "numeric attribute type",
}, },
boolean: { boolean: {
id: "l5V0QT", id: "l5V0QT",
defaultMessage: "Boolean", defaultMessage: "Boolean",
description: "boolean attribute type" description: "boolean attribute type",
}, },
date: { date: {
id: "fU+a9k", id: "fU+a9k",
defaultMessage: "Date", defaultMessage: "Date",
description: "date attribute type" description: "date attribute type",
}, },
dateTime: { dateTime: {
id: "DzPVnj", id: "DzPVnj",
defaultMessage: "Date Time", defaultMessage: "Date Time",
description: "date time attribute type" description: "date time attribute type",
}, },
swatch: { swatch: {
id: "gx4wCT", id: "gx4wCT",
defaultMessage: "Swatch", defaultMessage: "Swatch",
description: "swatch attribute type" description: "swatch attribute type",
} },
}); });
export const unitSystemMessages = defineMessages({ export const unitSystemMessages = defineMessages({
metric: { metric: {
id: "ZayvsI", id: "ZayvsI",
defaultMessage: "Metric", defaultMessage: "Metric",
description: "metric unit system" description: "metric unit system",
}, },
imperial: { imperial: {
id: "YgE6ga", id: "YgE6ga",
defaultMessage: "Imperial", defaultMessage: "Imperial",
description: "imperial unit system" description: "imperial unit system",
} },
}); });
export const unitTypeMessages = defineMessages({ export const unitTypeMessages = defineMessages({
volume: { volume: {
id: "cy8sV7", id: "cy8sV7",
defaultMessage: "Volume", defaultMessage: "Volume",
description: "volume units types" description: "volume units types",
}, },
distance: { distance: {
id: "k/mTEl", id: "k/mTEl",
defaultMessage: "Distance", defaultMessage: "Distance",
description: "distance units type" description: "distance units type",
}, },
weight: { weight: {
id: "Vdy5g7", id: "Vdy5g7",
defaultMessage: "Weight", defaultMessage: "Weight",
description: "weight units type" description: "weight units type",
}, },
area: { area: {
id: "A9QSur", id: "A9QSur",
defaultMessage: "Area", defaultMessage: "Area",
description: "area units type" description: "area units type",
} },
}); });
export const unitMessages = defineMessages({ export const unitMessages = defineMessages({
@ -150,13 +150,13 @@ export const unitMessages = defineMessages({
acreInch: { acreInch: {
id: "jBu2yj", id: "jBu2yj",
defaultMessage: "acre-inch", defaultMessage: "acre-inch",
description: "acre-inch unit" description: "acre-inch unit",
}, },
acreFt: { acreFt: {
id: "5XG1CO", id: "5XG1CO",
defaultMessage: "acre-ft", defaultMessage: "acre-ft",
description: "acre-ft unit" description: "acre-ft unit",
} },
}); });
export const units = { export const units = {
@ -188,5 +188,5 @@ export const units = {
lbs: "lbs", lbs: "lbs",
squareFt: <>ft&sup2;</>, squareFt: <>ft&sup2;</>,
squareYd: <>yd&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.TONNE]: M.units.tonne,
[MeasurementUnitsEnum.SQ_CM]: M.units.squareCentimeter, [MeasurementUnitsEnum.SQ_CM]: M.units.squareCentimeter,
[MeasurementUnitsEnum.SQ_M]: M.units.squareMeter, [MeasurementUnitsEnum.SQ_M]: M.units.squareMeter,
[MeasurementUnitsEnum.SQ_KM]: M.units.squareKilometer [MeasurementUnitsEnum.SQ_KM]: M.units.squareKilometer,
}; };
export const getMeasurementUnitMessage = ( export const getMeasurementUnitMessage = (
unit: MeasurementUnitsEnum, unit: MeasurementUnitsEnum,
formatMessage: IntlShape["formatMessage"] formatMessage: IntlShape["formatMessage"],
): MessageDescriptor | React.ReactNode => { ): MessageDescriptor | React.ReactNode => {
const message = UNIT_MESSAGES_MAPPING[unit]; const message = UNIT_MESSAGES_MAPPING[unit];
return typeof message === "string" || React.isValidElement(message) return typeof message === "string" || React.isValidElement(message)
@ -53,31 +53,31 @@ export const getMeasurementUnitMessage = (
export const unitSystemChoices: Array<Choice<UnitSystem, MessageDescriptor>> = [ export const unitSystemChoices: Array<Choice<UnitSystem, MessageDescriptor>> = [
{ {
label: M.unitSystemMessages.metric, label: M.unitSystemMessages.metric,
value: "metric" value: "metric",
}, },
{ {
label: M.unitSystemMessages.imperial, label: M.unitSystemMessages.imperial,
value: "imperial" value: "imperial",
} },
]; ];
export const unitTypeChoices: Array<Choice<UnitType, MessageDescriptor>> = [ export const unitTypeChoices: Array<Choice<UnitType, MessageDescriptor>> = [
{ {
label: M.unitTypeMessages.volume, label: M.unitTypeMessages.volume,
value: "volume" value: "volume",
}, },
{ {
label: M.unitTypeMessages.distance, label: M.unitTypeMessages.distance,
value: "distance" value: "distance",
}, },
{ {
label: M.unitTypeMessages.weight, label: M.unitTypeMessages.weight,
value: "weight" value: "weight",
}, },
{ {
label: M.unitTypeMessages.area, label: M.unitTypeMessages.area,
value: "area" value: "area",
} },
]; ];
export const unitMapping = { export const unitMapping = {
@ -90,64 +90,64 @@ export const unitMapping = {
MeasurementUnitsEnum.FL_OZ, MeasurementUnitsEnum.FL_OZ,
MeasurementUnitsEnum.PINT, MeasurementUnitsEnum.PINT,
MeasurementUnitsEnum.ACRE_IN, MeasurementUnitsEnum.ACRE_IN,
MeasurementUnitsEnum.ACRE_FT MeasurementUnitsEnum.ACRE_FT,
], ],
distance: [ distance: [
MeasurementUnitsEnum.FT, MeasurementUnitsEnum.FT,
MeasurementUnitsEnum.YD, MeasurementUnitsEnum.YD,
MeasurementUnitsEnum.INCH MeasurementUnitsEnum.INCH,
], ],
weight: [MeasurementUnitsEnum.LB, MeasurementUnitsEnum.OZ], weight: [MeasurementUnitsEnum.LB, MeasurementUnitsEnum.OZ],
area: [ area: [
MeasurementUnitsEnum.SQ_FT, MeasurementUnitsEnum.SQ_FT,
MeasurementUnitsEnum.SQ_YD, MeasurementUnitsEnum.SQ_YD,
MeasurementUnitsEnum.SQ_INCH MeasurementUnitsEnum.SQ_INCH,
] ],
}, },
metric: { metric: {
volume: [ volume: [
MeasurementUnitsEnum.CUBIC_CENTIMETER, MeasurementUnitsEnum.CUBIC_CENTIMETER,
MeasurementUnitsEnum.CUBIC_DECIMETER, MeasurementUnitsEnum.CUBIC_DECIMETER,
MeasurementUnitsEnum.CUBIC_METER, MeasurementUnitsEnum.CUBIC_METER,
MeasurementUnitsEnum.LITER MeasurementUnitsEnum.LITER,
], ],
distance: [ distance: [
MeasurementUnitsEnum.CM, MeasurementUnitsEnum.CM,
MeasurementUnitsEnum.M, MeasurementUnitsEnum.M,
MeasurementUnitsEnum.KM MeasurementUnitsEnum.KM,
], ],
weight: [ weight: [
MeasurementUnitsEnum.G, MeasurementUnitsEnum.G,
MeasurementUnitsEnum.KG, MeasurementUnitsEnum.KG,
MeasurementUnitsEnum.TONNE MeasurementUnitsEnum.TONNE,
], ],
area: [ area: [
MeasurementUnitsEnum.SQ_CM, MeasurementUnitsEnum.SQ_CM,
MeasurementUnitsEnum.SQ_M, MeasurementUnitsEnum.SQ_M,
MeasurementUnitsEnum.SQ_KM MeasurementUnitsEnum.SQ_KM,
] ],
} },
}; };
const extractTypeChoices = ( const extractTypeChoices = (
typeEnums: { typeEnums: {
[key in UnitType]: MeasurementUnitsEnum[]; [key in UnitType]: MeasurementUnitsEnum[];
}, },
formatMessage: IntlShape["formatMessage"] formatMessage: IntlShape["formatMessage"],
) => ) =>
Object.entries(typeEnums).reduce( Object.entries(typeEnums).reduce(
(acc, [type, units]) => ({ (acc, [type, units]) => ({
...acc, ...acc,
[type]: units.map(unit => ({ [type]: units.map(unit => ({
value: unit, value: unit,
label: getMeasurementUnitMessage(unit, formatMessage) label: getMeasurementUnitMessage(unit, formatMessage),
})) })),
}), }),
{} {},
); );
export const getUnitChoices = ( export const getUnitChoices = (
formatMessage: IntlShape["formatMessage"] formatMessage: IntlShape["formatMessage"],
): { ): {
[key in UnitSystem]: { [key in UnitSystem]: {
[key in UnitType]: Array<Choice<MeasurementUnitsEnum>>; [key in UnitType]: Array<Choice<MeasurementUnitsEnum>>;
@ -156,9 +156,9 @@ export const getUnitChoices = (
Object.entries(unitMapping).reduce( Object.entries(unitMapping).reduce(
(acc, [system, typeEnums]) => ({ (acc, [system, typeEnums]) => ({
...acc, ...acc,
[system]: extractTypeChoices(typeEnums, formatMessage) [system]: extractTypeChoices(typeEnums, formatMessage),
}), }),
{} {},
) as { ) as {
[key in UnitSystem]: { [key in UnitSystem]: {
[key in UnitType]: Array<Choice<MeasurementUnitsEnum>>; [key in UnitType]: Array<Choice<MeasurementUnitsEnum>>;

View file

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

View file

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

View file

@ -8,7 +8,7 @@ export enum AttributeFilterKeys {
filterableInStorefront = "filterableInStorefront", filterableInStorefront = "filterableInStorefront",
isVariantOnly = "isVariantOnly", isVariantOnly = "isVariantOnly",
valueRequired = "valueRequired", valueRequired = "valueRequired",
visibleInStorefront = "visibleInStorefront" visibleInStorefront = "visibleInStorefront",
} }
export interface AttributeListFilterOpts { export interface AttributeListFilterOpts {
@ -22,28 +22,28 @@ const messages = defineMessages({
filterableInStorefront: { filterableInStorefront: {
id: "PsRG+v", id: "PsRG+v",
defaultMessage: "Filterable in Storefront", defaultMessage: "Filterable in Storefront",
description: "use attribute in filtering" description: "use attribute in filtering",
}, },
isVariantOnly: { isVariantOnly: {
id: "rvk9ls", id: "rvk9ls",
defaultMessage: "Variant Only", defaultMessage: "Variant Only",
description: "attribute can be used only in variants" description: "attribute can be used only in variants",
}, },
valueRequired: { valueRequired: {
id: "HQR2y0", id: "HQR2y0",
defaultMessage: "Value Required", defaultMessage: "Value Required",
description: "attribute value is required" description: "attribute value is required",
}, },
visibleInStorefront: { visibleInStorefront: {
id: "cvbqJu", id: "cvbqJu",
defaultMessage: "Visible on Product Page in Storefront", defaultMessage: "Visible on Product Page in Storefront",
description: "attribute" description: "attribute",
} },
}); });
export function createFilterStructure( export function createFilterStructure(
intl: IntlShape, intl: IntlShape,
opts: AttributeListFilterOpts opts: AttributeListFilterOpts,
): IFilter<AttributeFilterKeys> { ): IFilter<AttributeFilterKeys> {
return [ return [
{ {
@ -53,10 +53,10 @@ export function createFilterStructure(
opts.filterableInStorefront.value, opts.filterableInStorefront.value,
{ {
negative: intl.formatMessage(commonMessages.no), negative: intl.formatMessage(commonMessages.no),
positive: intl.formatMessage(commonMessages.yes) positive: intl.formatMessage(commonMessages.yes),
} },
), ),
active: opts.filterableInStorefront.active active: opts.filterableInStorefront.active,
}, },
{ {
...createBooleanField( ...createBooleanField(
@ -65,10 +65,10 @@ export function createFilterStructure(
opts.isVariantOnly.value, opts.isVariantOnly.value,
{ {
negative: intl.formatMessage(commonMessages.no), negative: intl.formatMessage(commonMessages.no),
positive: intl.formatMessage(commonMessages.yes) positive: intl.formatMessage(commonMessages.yes),
} },
), ),
active: opts.isVariantOnly.active active: opts.isVariantOnly.active,
}, },
{ {
...createBooleanField( ...createBooleanField(
@ -77,10 +77,10 @@ export function createFilterStructure(
opts.valueRequired.value, opts.valueRequired.value,
{ {
negative: intl.formatMessage(commonMessages.no), negative: intl.formatMessage(commonMessages.no),
positive: intl.formatMessage(commonMessages.yes) positive: intl.formatMessage(commonMessages.yes),
} },
), ),
active: opts.valueRequired.active active: opts.valueRequired.active,
}, },
{ {
...createBooleanField( ...createBooleanField(
@ -89,10 +89,10 @@ export function createFilterStructure(
opts.visibleInStorefront.value, opts.visibleInStorefront.value,
{ {
negative: intl.formatMessage(commonMessages.no), 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: { contentAttribute: {
id: "zbJHl7", id: "zbJHl7",
defaultMessage: "Content Attribute", defaultMessage: "Content Attribute",
description: "attribute type" description: "attribute type",
}, },
productAttribute: { productAttribute: {
id: "qkRuT0", id: "qkRuT0",
defaultMessage: "Product Attribute", defaultMessage: "Product Attribute",
description: "attribute type" description: "attribute type",
} },
}); });
const useStyles = makeStyles( const useStyles = makeStyles(
theme => ({ theme => ({
card: { card: {
overflow: "visible" overflow: "visible",
}, },
cardSubtitle: { cardSubtitle: {
fontSize: theme.typography.body1.fontSize, fontSize: theme.typography.body1.fontSize,
marginBottom: theme.spacing(0.5) marginBottom: theme.spacing(0.5),
}, },
label: { label: {
marginBottom: theme.spacing(0.5) marginBottom: theme.spacing(0.5),
} },
}), }),
{ name: "AttributeOrganization" } { name: "AttributeOrganization" },
); );
const AttributeOrganization: React.FC<AttributeOrganizationProps> = props => { const AttributeOrganization: React.FC<AttributeOrganizationProps> = props => {
@ -56,7 +56,7 @@ const AttributeOrganization: React.FC<AttributeOrganizationProps> = props => {
title={intl.formatMessage({ title={intl.formatMessage({
id: "nwvQPg", id: "nwvQPg",
defaultMessage: "Organization", defaultMessage: "Organization",
description: "section header" description: "section header",
})} })}
/> />
<CardContent> <CardContent>
@ -65,12 +65,12 @@ const AttributeOrganization: React.FC<AttributeOrganizationProps> = props => {
choices={[ choices={[
{ {
label: intl.formatMessage(messages.productAttribute), label: intl.formatMessage(messages.productAttribute),
value: AttributeTypeEnum.PRODUCT_TYPE value: AttributeTypeEnum.PRODUCT_TYPE,
}, },
{ {
label: intl.formatMessage(messages.contentAttribute), label: intl.formatMessage(messages.contentAttribute),
value: AttributeTypeEnum.PAGE_TYPE value: AttributeTypeEnum.PAGE_TYPE,
} },
]} ]}
disabled={disabled} disabled={disabled}
label={ label={

View file

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

View file

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

View file

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

View file

@ -4,11 +4,11 @@ export const swatchFieldMessages = defineMessages({
image: { image: {
id: "I2wCwj", id: "I2wCwj",
defaultMessage: "Image", defaultMessage: "Image",
description: "swatch attribute image label" description: "swatch attribute image label",
}, },
picker: { picker: {
id: "0DgA8v", id: "0DgA8v",
defaultMessage: "Picker", 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, width: 216,
height: 216, height: 216,
backgroundSize: "cover", backgroundSize: "cover",
backgroundPosition: "center" backgroundPosition: "center",
} },
}), }),
{ name: "AttributeSwatchField" } { name: "AttributeSwatchField" },
); );

View file

@ -21,7 +21,7 @@ const AttributeValueDeleteDialog: React.FC<AttributeValueDeleteDialogProps> = ({
useName, useName,
onClose, onClose,
onConfirm, onConfirm,
open open,
}) => { }) => {
const intl = useIntl(); const intl = useIntl();
@ -35,7 +35,7 @@ const AttributeValueDeleteDialog: React.FC<AttributeValueDeleteDialogProps> = ({
title={intl.formatMessage({ title={intl.formatMessage({
id: "WWV8aZ", id: "WWV8aZ",
defaultMessage: "Delete attribute value", defaultMessage: "Delete attribute value",
description: "dialog title" description: "dialog title",
})} })}
> >
<DialogContentText> <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.' 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={{ values={{
attributeName, attributeName,
name name,
}} }}
/> />
) : ( ) : (
@ -54,7 +54,7 @@ const AttributeValueDeleteDialog: React.FC<AttributeValueDeleteDialogProps> = ({
defaultMessage='Are you sure you want to delete "{name}" value?' defaultMessage='Are you sure you want to delete "{name}" value?'
description="delete attribute value" description="delete attribute value"
values={{ values={{
name name,
}} }}
/> />
)} )}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -5,21 +5,21 @@ import {
getFiltersCurrentTab, getFiltersCurrentTab,
getFilterTabs, getFilterTabs,
getFilterVariables, getFilterVariables,
saveFilterTab saveFilterTab,
} from "@saleor/attributes/views/AttributeList/filters"; } from "@saleor/attributes/views/AttributeList/filters";
import DeleteFilterTabDialog from "@saleor/components/DeleteFilterTabDialog"; import DeleteFilterTabDialog from "@saleor/components/DeleteFilterTabDialog";
import SaveFilterTabDialog, { import SaveFilterTabDialog, {
SaveFilterTabDialogFormData SaveFilterTabDialogFormData,
} from "@saleor/components/SaveFilterTabDialog"; } from "@saleor/components/SaveFilterTabDialog";
import { import {
useAttributeBulkDeleteMutation, useAttributeBulkDeleteMutation,
useAttributeListQuery useAttributeListQuery,
} from "@saleor/graphql"; } from "@saleor/graphql";
import useNavigator from "@saleor/hooks/useNavigator"; import useNavigator from "@saleor/hooks/useNavigator";
import useNotifier from "@saleor/hooks/useNotifier"; import useNotifier from "@saleor/hooks/useNotifier";
import usePaginator, { import usePaginator, {
createPaginationState, createPaginationState,
PaginatorContext PaginatorContext,
} from "@saleor/hooks/usePaginator"; } from "@saleor/hooks/usePaginator";
import { DeleteIcon, IconButton } from "@saleor/macaw-ui"; import { DeleteIcon, IconButton } from "@saleor/macaw-ui";
import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers"; import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers";
@ -38,7 +38,7 @@ import AttributeListPage from "../../components/AttributeListPage";
import { import {
attributeListUrl, attributeListUrl,
AttributeListUrlDialog, AttributeListUrlDialog,
AttributeListUrlQueryParams AttributeListUrlQueryParams,
} from "../../urls"; } from "../../urls";
import { getFilterQueryParam } from "./filters"; import { getFilterQueryParam } from "./filters";
import { getSortQueryVariables } from "./sort"; import { getSortQueryVariables } from "./sort";
@ -51,7 +51,7 @@ const AttributeList: React.FC<AttributeListProps> = ({ params }) => {
const navigate = useNavigator(); const navigate = useNavigator();
const notify = useNotifier(); const notify = useNotifier();
const { isSelected, listElements, reset, toggle, toggleAll } = useBulkActions( const { isSelected, listElements, reset, toggle, toggleAll } = useBulkActions(
params.ids params.ids,
); );
const intl = useIntl(); const intl = useIntl();
@ -60,17 +60,17 @@ const AttributeList: React.FC<AttributeListProps> = ({ params }) => {
() => ({ () => ({
...paginationState, ...paginationState,
filter: getFilterVariables(params), filter: getFilterVariables(params),
sort: getSortQueryVariables(params) sort: getSortQueryVariables(params),
}), }),
[params] [params],
); );
const { data, loading, refetch } = useAttributeListQuery({ const { data, loading, refetch } = useAttributeListQuery({
variables: queryVariables variables: queryVariables,
}); });
const [ const [
attributeBulkDelete, attributeBulkDelete,
attributeBulkDeleteOpts attributeBulkDeleteOpts,
] = useAttributeBulkDeleteMutation({ ] = useAttributeBulkDeleteMutation({
onCompleted: data => { onCompleted: data => {
if (data.attributeBulkDelete.errors.length === 0) { if (data.attributeBulkDelete.errors.length === 0) {
@ -80,13 +80,13 @@ const AttributeList: React.FC<AttributeListProps> = ({ params }) => {
text: intl.formatMessage({ text: intl.formatMessage({
id: "lw9WIk", id: "lw9WIk",
defaultMessage: "Attributes successfully delete", defaultMessage: "Attributes successfully delete",
description: "deleted multiple attributes" description: "deleted multiple attributes",
}) }),
}); });
reset(); reset();
refetch(); refetch();
} }
} },
}); });
const tabs = getFilterTabs(); const tabs = getFilterTabs();
@ -101,13 +101,13 @@ const AttributeList: React.FC<AttributeListProps> = ({ params }) => {
const [ const [
changeFilters, changeFilters,
resetFilters, resetFilters,
handleSearchChange handleSearchChange,
] = createFilterHandlers({ ] = createFilterHandlers({
cleanupFn: reset, cleanupFn: reset,
createUrl: attributeListUrl, createUrl: attributeListUrl,
getFilterQueryParam, getFilterQueryParam,
navigate, navigate,
params params,
}); });
const handleTabChange = (tab: number) => { const handleTabChange = (tab: number) => {
@ -115,8 +115,8 @@ const AttributeList: React.FC<AttributeListProps> = ({ params }) => {
navigate( navigate(
attributeListUrl({ attributeListUrl({
activeTab: tab.toString(), activeTab: tab.toString(),
...getFilterTabs()[tab - 1].data ...getFilterTabs()[tab - 1].data,
}) }),
); );
}; };
@ -134,7 +134,7 @@ const AttributeList: React.FC<AttributeListProps> = ({ params }) => {
const paginationValues = usePaginator({ const paginationValues = usePaginator({
pageInfo: maybe(() => data.attributes.pageInfo), pageInfo: maybe(() => data.attributes.pageInfo),
paginationState, paginationState,
queryString: params queryString: params,
}); });
const handleSort = createSortHandler(navigate, attributeListUrl, params); const handleSort = createSortHandler(navigate, attributeListUrl, params);
@ -166,7 +166,7 @@ const AttributeList: React.FC<AttributeListProps> = ({ params }) => {
color="primary" color="primary"
onClick={() => onClick={() =>
openModal("remove", { 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", () => { it("should not be empty object if params given", () => {
const params: AttributeListUrlFilters = { const params: AttributeListUrlFilters = {
isVariantOnly: true.toString() isVariantOnly: true.toString(),
}; };
const filterVariables = getFilterVariables(params); const filterVariables = getFilterVariables(params);
@ -32,26 +32,26 @@ describe("Filtering URL params", () => {
const filters = createFilterStructure(intl, { const filters = createFilterStructure(intl, {
filterableInStorefront: { filterableInStorefront: {
active: false, active: false,
value: true value: true,
}, },
isVariantOnly: { isVariantOnly: {
active: false, active: false,
value: true value: true,
}, },
valueRequired: { valueRequired: {
active: false, active: false,
value: true value: true,
}, },
visibleInStorefront: { visibleInStorefront: {
active: false, active: false,
value: true value: true,
} },
}); });
it("should be empty if no active filters", () => { it("should be empty if no active filters", () => {
const filterQueryParams = getFilterQueryParams( const filterQueryParams = getFilterQueryParams(
filters, filters,
getFilterQueryParam getFilterQueryParam,
); );
expect(getExistingKeys(filterQueryParams)).toHaveLength(0); expect(getExistingKeys(filterQueryParams)).toHaveLength(0);
@ -60,7 +60,7 @@ describe("Filtering URL params", () => {
it("should not be empty if active filters are present", () => { it("should not be empty if active filters are present", () => {
const filterQueryParams = getFilterQueryParams( const filterQueryParams = getFilterQueryParams(
setFilterOptsStatus(filters, true), setFilterOptsStatus(filters, true),
getFilterQueryParam getFilterQueryParam,
); );
expect(filterQueryParams).toMatchSnapshot(); expect(filterQueryParams).toMatchSnapshot();

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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