Fix minor bugs in plugin details view

This commit is contained in:
dominik-zeglen 2020-08-19 13:35:35 +02:00
parent c4d70dde70
commit 48e9fe1366
13 changed files with 244 additions and 150 deletions

View file

@ -4,10 +4,7 @@ import Switch from "@material-ui/core/Switch";
import React from "react"; import React from "react";
const useStyles = makeStyles( const useStyles = makeStyles(
theme => ({ () => ({
label: {
marginLeft: theme.spacing(3.5)
},
labelText: { labelText: {
fontSize: 14 fontSize: 14
} }
@ -51,7 +48,7 @@ export const ControlledSwitch: React.FC<ControlledSwitchProps> = props => {
/> />
} }
label={ label={
<div className={classes.label}> <div>
{uncheckedLabel ? ( {uncheckedLabel ? (
checked ? ( checked ? (
label label

View file

@ -127,3 +127,10 @@ export const exportErrorFragment = gql`
field field
} }
`; `;
export const pluginErrorFragment = gql`
fragment PluginErrorFragment on PluginError {
code
field
}
`;

View file

@ -0,0 +1,15 @@
/* tslint:disable */
/* eslint-disable */
// This file was automatically generated and should not be edited.
import { PluginErrorCode } from "./../../types/globalTypes";
// ====================================================
// GraphQL fragment: PluginErrorFragment
// ====================================================
export interface PluginErrorFragment {
__typename: "PluginError";
code: PluginErrorCode;
field: string | null;
}

View file

@ -6,7 +6,10 @@ import CardTitle from "@saleor/components/CardTitle";
import ControlledCheckbox from "@saleor/components/ControlledCheckbox"; import ControlledCheckbox from "@saleor/components/ControlledCheckbox";
import FormSpacer from "@saleor/components/FormSpacer"; import FormSpacer from "@saleor/components/FormSpacer";
import Hr from "@saleor/components/Hr"; import Hr from "@saleor/components/Hr";
import { PluginErrorFragment } from "@saleor/fragments/types/PluginErrorFragment";
import { commonMessages } from "@saleor/intl"; import { commonMessages } from "@saleor/intl";
import { PluginErrorCode } from "@saleor/types/globalTypes";
import getPluginErrorMessage from "@saleor/utils/errors/plugins";
import React from "react"; import React from "react";
import { FormattedMessage, useIntl } from "react-intl"; import { FormattedMessage, useIntl } from "react-intl";
@ -15,6 +18,7 @@ import { FormData } from "../PluginsDetailsPage";
interface PluginInfoProps { interface PluginInfoProps {
data: FormData; data: FormData;
description: string; description: string;
errors: PluginErrorFragment[];
name: string; name: string;
onChange: (event: React.ChangeEvent<any>) => void; onChange: (event: React.ChangeEvent<any>) => void;
} }
@ -35,11 +39,17 @@ const useStyles = makeStyles(
const PluginInfo: React.FC<PluginInfoProps> = ({ const PluginInfo: React.FC<PluginInfoProps> = ({
data, data,
description, description,
errors,
name, name,
onChange onChange
}) => { }) => {
const classes = useStyles({}); const classes = useStyles({});
const intl = useIntl(); const intl = useIntl();
const misconfiguredError = errors.find(
err => err.code === PluginErrorCode.PLUGIN_MISCONFIGURED
);
return ( return (
<Card> <Card>
<CardTitle <CardTitle
@ -80,6 +90,11 @@ const PluginInfo: React.FC<PluginInfoProps> = ({
checked={data.active} checked={data.active}
onChange={onChange} onChange={onChange}
/> />
{misconfiguredError && (
<Typography color="error">
{getPluginErrorMessage(misconfiguredError, intl)}
</Typography>
)}
</CardContent> </CardContent>
</Card> </Card>
); );

View file

@ -2,8 +2,11 @@ import Card from "@material-ui/core/Card";
import CardContent from "@material-ui/core/CardContent"; import CardContent from "@material-ui/core/CardContent";
import makeStyles from "@material-ui/core/styles/makeStyles"; import makeStyles from "@material-ui/core/styles/makeStyles";
import TextField from "@material-ui/core/TextField"; import TextField from "@material-ui/core/TextField";
import Tooltip from "@material-ui/core/Tooltip";
import Typography from "@material-ui/core/Typography";
import InfoIcon from "@material-ui/icons/Info";
import CardTitle from "@saleor/components/CardTitle"; import CardTitle from "@saleor/components/CardTitle";
import ControlledCheckbox from "@saleor/components/ControlledCheckbox"; import ControlledSwitch from "@saleor/components/ControlledSwitch";
import { Plugin_plugin_configuration } from "@saleor/plugins/types/Plugin"; import { Plugin_plugin_configuration } from "@saleor/plugins/types/Plugin";
import { UserError } from "@saleor/types"; import { UserError } from "@saleor/types";
import { ConfigurationTypeFieldEnum } from "@saleor/types/globalTypes"; import { ConfigurationTypeFieldEnum } from "@saleor/types/globalTypes";
@ -32,7 +35,9 @@ const useStyles = makeStyles(
item: { item: {
"&:not(:last-child)": { "&:not(:last-child)": {
marginBottom: theme.spacing(3) marginBottom: theme.spacing(3)
} },
alignItems: "center",
display: "flex"
}, },
itemLabel: { itemLabel: {
fontWeight: 500 fontWeight: 500
@ -71,7 +76,8 @@ const PluginSettings: React.FC<PluginSettingsProps> = ({
return ( return (
<div className={classes.item} key={field.name}> <div className={classes.item} key={field.name}>
{fieldData.type === ConfigurationTypeFieldEnum.BOOLEAN ? ( {fieldData.type === ConfigurationTypeFieldEnum.BOOLEAN ? (
<ControlledCheckbox <>
<ControlledSwitch
name={field.name} name={field.name}
label={fieldData.label} label={fieldData.label}
checked={ checked={
@ -82,6 +88,18 @@ const PluginSettings: React.FC<PluginSettingsProps> = ({
onChange={onChange} onChange={onChange}
disabled={disabled} disabled={disabled}
/> />
{fieldData.helpText && (
<Tooltip
title={
<Typography variant="body2">
{fieldData.helpText}
</Typography>
}
>
<InfoIcon />
</Tooltip>
)}
</>
) : ( ) : (
<TextField <TextField
disabled={disabled} disabled={disabled}

View file

@ -9,11 +9,11 @@ import Grid from "@saleor/components/Grid";
import Hr from "@saleor/components/Hr"; import Hr from "@saleor/components/Hr";
import PageHeader from "@saleor/components/PageHeader"; import PageHeader from "@saleor/components/PageHeader";
import SaveButtonBar from "@saleor/components/SaveButtonBar"; import SaveButtonBar from "@saleor/components/SaveButtonBar";
import { PluginErrorFragment } from "@saleor/fragments/types/PluginErrorFragment";
import { ChangeEvent } from "@saleor/hooks/useForm"; import { ChangeEvent } from "@saleor/hooks/useForm";
import { sectionNames } from "@saleor/intl"; import { sectionNames } from "@saleor/intl";
import { maybe } from "@saleor/misc"; import { getStringOrPlaceholder } from "@saleor/misc";
import { isSecretField } from "@saleor/plugins/utils"; import { isSecretField } from "@saleor/plugins/utils";
import { UserError } from "@saleor/types";
import { ConfigurationItemInput } from "@saleor/types/globalTypes"; import { ConfigurationItemInput } from "@saleor/types/globalTypes";
import React from "react"; import React from "react";
import { useIntl } from "react-intl"; import { useIntl } from "react-intl";
@ -30,7 +30,7 @@ export interface FormData {
export interface PluginsDetailsPageProps { export interface PluginsDetailsPageProps {
disabled: boolean; disabled: boolean;
errors: UserError[]; errors: PluginErrorFragment[];
plugin: Plugin_plugin; plugin: Plugin_plugin;
saveButtonBarState: ConfirmButtonTransitionState; saveButtonBarState: ConfirmButtonTransitionState;
onBack: () => void; onBack: () => void;
@ -65,15 +65,13 @@ const PluginsDetailsPage: React.FC<PluginsDetailsPageProps> = props => {
const classes = useStyles(props); const classes = useStyles(props);
const intl = useIntl(); const intl = useIntl();
const initialForm: FormData = { const initialForm: FormData = {
active: maybe(() => plugin.active, false), active: plugin?.active || false,
configuration: maybe(() => configuration: plugin?.configuration
plugin.configuration ?.filter(field => !isSecretField(plugin?.configuration || [], field.name))
.filter(field => !isSecretField(plugin.configuration, field.name))
.map(field => ({ .map(field => ({
...field, ...field,
value: field.value || "" value: field.value || ""
})) }))
)
}; };
return ( return (
@ -108,7 +106,7 @@ const PluginsDetailsPage: React.FC<PluginsDetailsPageProps> = props => {
description: "header" description: "header"
}, },
{ {
pluginName: maybe(() => plugin.name, "...") pluginName: getStringOrPlaceholder(plugin?.name)
} }
)} )}
/> />
@ -129,8 +127,9 @@ const PluginsDetailsPage: React.FC<PluginsDetailsPageProps> = props => {
</div> </div>
<PluginInfo <PluginInfo
data={data} data={data}
description={maybe(() => plugin.description, "")} description={plugin?.description || ""}
name={maybe(() => plugin.name, "")} errors={errors}
name={plugin?.name || ""}
onChange={onChange} onChange={onChange}
/> />
{data.configuration && ( {data.configuration && (
@ -143,25 +142,17 @@ const PluginsDetailsPage: React.FC<PluginsDetailsPageProps> = props => {
description: "section header" description: "section header"
})} })}
</Typography> </Typography>
<Typography>
{intl.formatMessage({
defaultMessage:
"This adress will be used to generate invoices and calculate shipping rates. Email adress you provide here will be used as a contact adress for your customers."
})}
</Typography>
</div> </div>
<div> <div>
<PluginSettings <PluginSettings
data={data} data={data}
fields={maybe(() => plugin.configuration, [])} fields={plugin?.configuration || []}
errors={errors} errors={errors}
disabled={disabled} disabled={disabled}
onChange={onChange} onChange={onChange}
/> />
{maybe(() => {plugin?.configuration.some(field =>
plugin.configuration.some(field =>
isSecretField(plugin.configuration, field.name) isSecretField(plugin.configuration, field.name)
)
) && ( ) && (
<> <>
<CardSpacer /> <CardSpacer />

View file

@ -1,3 +1,4 @@
import { pluginErrorFragment } from "@saleor/fragments/errors";
import { pluginsDetailsFragment } from "@saleor/fragments/plugins"; import { pluginsDetailsFragment } from "@saleor/fragments/plugins";
import gql from "graphql-tag"; import gql from "graphql-tag";
@ -6,11 +7,11 @@ import { PluginUpdate, PluginUpdateVariables } from "./types/PluginUpdate";
const pluginUpdate = gql` const pluginUpdate = gql`
${pluginsDetailsFragment} ${pluginsDetailsFragment}
${pluginErrorFragment}
mutation PluginUpdate($id: ID!, $input: PluginUpdateInput!) { mutation PluginUpdate($id: ID!, $input: PluginUpdateInput!) {
pluginUpdate(id: $id, input: $input) { pluginUpdate(id: $id, input: $input) {
errors { errors: pluginsErrors {
field ...PluginErrorFragment
message
} }
plugin { plugin {
...PluginsDetailsFragment ...PluginsDetailsFragment

View file

@ -2,16 +2,16 @@
/* eslint-disable */ /* eslint-disable */
// This file was automatically generated and should not be edited. // This file was automatically generated and should not be edited.
import { PluginUpdateInput, ConfigurationTypeFieldEnum } from "./../../types/globalTypes"; import { PluginUpdateInput, PluginErrorCode, ConfigurationTypeFieldEnum } from "./../../types/globalTypes";
// ==================================================== // ====================================================
// GraphQL mutation operation: PluginUpdate // GraphQL mutation operation: PluginUpdate
// ==================================================== // ====================================================
export interface PluginUpdate_pluginUpdate_errors { export interface PluginUpdate_pluginUpdate_errors {
__typename: "Error"; __typename: "PluginError";
code: PluginErrorCode;
field: string | null; field: string | null;
message: string | null;
} }
export interface PluginUpdate_pluginUpdate_plugin_configuration { export interface PluginUpdate_pluginUpdate_plugin_configuration {

View file

@ -9,7 +9,6 @@ import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandl
import React from "react"; import React from "react";
import { FormattedMessage, useIntl } from "react-intl"; import { FormattedMessage, useIntl } from "react-intl";
import { maybe } from "../../misc";
import PluginsDetailsPage from "../components/PluginsDetailsPage"; import PluginsDetailsPage from "../components/PluginsDetailsPage";
import PluginSecretFieldDialog from "../components/PluginSecretFieldDialog"; import PluginSecretFieldDialog from "../components/PluginSecretFieldDialog";
import { TypedPluginUpdate } from "../mutations"; import { TypedPluginUpdate } from "../mutations";
@ -73,10 +72,7 @@ export const PluginsDetails: React.FC<PluginsDetailsProps> = ({
{pluginDetails => ( {pluginDetails => (
<TypedPluginUpdate onCompleted={handleUpdate}> <TypedPluginUpdate onCompleted={handleUpdate}>
{(pluginUpdate, pluginUpdateOpts) => { {(pluginUpdate, pluginUpdateOpts) => {
const formErrors = maybe( const formErrors = pluginUpdateOpts.data?.pluginUpdate.errors || [];
() => pluginUpdateOpts.data.pluginUpdate.errors,
[]
);
const handleFieldUpdate = (value: string) => const handleFieldUpdate = (value: string) =>
pluginUpdate({ pluginUpdate({
@ -95,16 +91,14 @@ export const PluginsDetails: React.FC<PluginsDetailsProps> = ({
return ( return (
<> <>
<WindowTitle <WindowTitle title={pluginDetails.data?.plugin?.name} />
title={maybe(() => pluginDetails.data.plugin.name)}
/>
<PluginsDetailsPage <PluginsDetailsPage
disabled={pluginDetails.loading} disabled={pluginDetails.loading}
errors={formErrors} errors={formErrors}
saveButtonBarState={ saveButtonBarState={
!params.action ? pluginUpdateOpts.status : "default" !params.action ? pluginUpdateOpts.status : "default"
} }
plugin={maybe(() => pluginDetails.data.plugin)} plugin={pluginDetails.data?.plugin}
onBack={() => navigate(pluginListUrl())} onBack={() => navigate(pluginListUrl())}
onClear={id => onClear={id =>
openModal("clear", { openModal("clear", {
@ -131,7 +125,7 @@ export const PluginsDetails: React.FC<PluginsDetailsProps> = ({
}) })
} }
/> />
{maybe(() => pluginDetails.data.plugin.configuration) && ( {pluginDetails.data?.plugin?.configuration && (
<> <>
<ActionDialog <ActionDialog
confirmButtonState={ confirmButtonState={
@ -153,10 +147,8 @@ export const PluginsDetails: React.FC<PluginsDetailsProps> = ({
confirmButtonState={ confirmButtonState={
!!params.action ? pluginUpdateOpts.status : "default" !!params.action ? pluginUpdateOpts.status : "default"
} }
field={maybe(() => field={pluginDetails.data?.plugin?.configuration.find(
pluginDetails.data.plugin.configuration.find(
field => field.name === params.id field => field.name === params.id
)
)} )}
onClose={closeModal} onClose={closeModal}
onConfirm={formData => handleFieldUpdate(formData.value)} onConfirm={formData => handleFieldUpdate(formData.value)}

View file

@ -111209,11 +111209,6 @@ exports[`Storyshots Views / Plugins / Plugin details default 1`] = `
> >
Plugin Settings Plugin Settings
</div> </div>
<div
class="MuiTypography-root-id MuiTypography-body1-id"
>
This adress will be used to generate invoices and calculate shipping rates. Email adress you provide here will be used as a contact adress for your customers.
</div>
</div> </div>
<div> <div>
<div <div
@ -111333,21 +111328,45 @@ exports[`Storyshots Views / Plugins / Plugin details default 1`] = `
> >
<label <label
class="MuiFormControlLabel-root-id" class="MuiFormControlLabel-root-id"
>
<span
class="MuiSwitch-root-id"
> >
<span <span
aria-disabled="false" aria-disabled="false"
class="MuiButtonBase-root-id MuiIconButton-root-id PrivateSwitchBase-root-id MuiCheckbox-root-id MuiCheckbox-colorPrimary-id PrivateSwitchBase-checked-id MuiCheckbox-checked-id MuiIconButton-colorPrimary-id" class="MuiButtonBase-root-id MuiIconButton-root-id PrivateSwitchBase-root-id MuiSwitch-switchBase-id MuiSwitch-colorPrimary-id PrivateSwitchBase-checked-id MuiSwitch-checked-id"
> >
<span <span
class="MuiIconButton-label-id" class="MuiIconButton-label-id"
> >
<input <input
checked="" checked=""
class="PrivateSwitchBase-input-id" class="PrivateSwitchBase-input-id MuiSwitch-input-id"
data-indeterminate="false"
name="Use sandbox" name="Use sandbox"
type="checkbox" type="checkbox"
/> />
<span
class="MuiSwitch-thumb-id"
/>
</span>
</span>
<span
class="MuiSwitch-track-id"
/>
</span>
<span
class="MuiTypography-root-id MuiFormControlLabel-label-id MuiTypography-body1-id"
>
<div>
<span
class="ControlledSwitch-labelText-id"
>
Use sandbox
</span>
<div />
</div>
</span>
</label>
<svg <svg
aria-hidden="true" aria-hidden="true"
class="MuiSvgIcon-root-id" class="MuiSvgIcon-root-id"
@ -111355,28 +111374,10 @@ exports[`Storyshots Views / Plugins / Plugin details default 1`] = `
role="presentation" role="presentation"
viewBox="0 0 24 24" viewBox="0 0 24 24"
> >
<rect
fill="currentColor"
height="14"
width="14"
x="5"
y="5"
/>
<path <path
clip-rule="evenodd" d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z"
d="M 16.7527 9.33783 L 10.86618 15.7595 L 8 12.32006 L 8.76822 11.67988 L 10.90204 14.24046 L 16.0155 8.66211 L 16.7527 9.33783 Z"
fill="white"
fill-rule="evenodd"
/> />
</svg> </svg>
</span>
</span>
<span
class="MuiTypography-root-id MuiFormControlLabel-label-id MuiTypography-body1-id"
>
Use sandbox
</span>
</label>
</div> </div>
</div> </div>
</div> </div>
@ -111660,6 +111661,11 @@ exports[`Storyshots Views / Plugins / Plugin details form errors 1`] = `
Set plugin as Active Set plugin as Active
</span> </span>
</label> </label>
<div
class="MuiTypography-root-id MuiTypography-body1-id MuiTypography-colorError-id"
>
Plugin is misconfigured and cannot be activated
</div>
</div> </div>
</div> </div>
<hr <hr
@ -111671,11 +111677,6 @@ exports[`Storyshots Views / Plugins / Plugin details form errors 1`] = `
> >
Plugin Settings Plugin Settings
</div> </div>
<div
class="MuiTypography-root-id MuiTypography-body1-id"
>
This adress will be used to generate invoices and calculate shipping rates. Email adress you provide here will be used as a contact adress for your customers.
</div>
</div> </div>
<div> <div>
<div <div
@ -111795,21 +111796,45 @@ exports[`Storyshots Views / Plugins / Plugin details form errors 1`] = `
> >
<label <label
class="MuiFormControlLabel-root-id" class="MuiFormControlLabel-root-id"
>
<span
class="MuiSwitch-root-id"
> >
<span <span
aria-disabled="false" aria-disabled="false"
class="MuiButtonBase-root-id MuiIconButton-root-id PrivateSwitchBase-root-id MuiCheckbox-root-id MuiCheckbox-colorPrimary-id PrivateSwitchBase-checked-id MuiCheckbox-checked-id MuiIconButton-colorPrimary-id" class="MuiButtonBase-root-id MuiIconButton-root-id PrivateSwitchBase-root-id MuiSwitch-switchBase-id MuiSwitch-colorPrimary-id PrivateSwitchBase-checked-id MuiSwitch-checked-id"
> >
<span <span
class="MuiIconButton-label-id" class="MuiIconButton-label-id"
> >
<input <input
checked="" checked=""
class="PrivateSwitchBase-input-id" class="PrivateSwitchBase-input-id MuiSwitch-input-id"
data-indeterminate="false"
name="Use sandbox" name="Use sandbox"
type="checkbox" type="checkbox"
/> />
<span
class="MuiSwitch-thumb-id"
/>
</span>
</span>
<span
class="MuiSwitch-track-id"
/>
</span>
<span
class="MuiTypography-root-id MuiFormControlLabel-label-id MuiTypography-body1-id"
>
<div>
<span
class="ControlledSwitch-labelText-id"
>
Use sandbox
</span>
<div />
</div>
</span>
</label>
<svg <svg
aria-hidden="true" aria-hidden="true"
class="MuiSvgIcon-root-id" class="MuiSvgIcon-root-id"
@ -111817,28 +111842,10 @@ exports[`Storyshots Views / Plugins / Plugin details form errors 1`] = `
role="presentation" role="presentation"
viewBox="0 0 24 24" viewBox="0 0 24 24"
> >
<rect
fill="currentColor"
height="14"
width="14"
x="5"
y="5"
/>
<path <path
clip-rule="evenodd" d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z"
d="M 16.7527 9.33783 L 10.86618 15.7595 L 8 12.32006 L 8.76822 11.67988 L 10.90204 14.24046 L 16.0155 8.66211 L 16.7527 9.33783 Z"
fill="white"
fill-rule="evenodd"
/> />
</svg> </svg>
</span>
</span>
<span
class="MuiTypography-root-id MuiFormControlLabel-label-id MuiTypography-body1-id"
>
Use sandbox
</span>
</label>
</div> </div>
</div> </div>
</div> </div>
@ -114712,9 +114719,7 @@ exports[`Storyshots Views / Product types / Product type details default 1`] = `
<span <span
class="MuiTypography-root-id MuiFormControlLabel-label-id MuiTypography-body1-id" class="MuiTypography-root-id MuiFormControlLabel-label-id MuiTypography-body1-id"
> >
<div <div>
class="ControlledSwitch-label-id"
>
<span <span
class="ControlledSwitch-labelText-id" class="ControlledSwitch-labelText-id"
> >
@ -115469,9 +115474,7 @@ exports[`Storyshots Views / Product types / Product type details form errors 1`]
<span <span
class="MuiTypography-root-id MuiFormControlLabel-label-id MuiTypography-body1-id" class="MuiTypography-root-id MuiFormControlLabel-label-id MuiTypography-body1-id"
> >
<div <div>
class="ControlledSwitch-label-id"
>
<span <span
class="ControlledSwitch-labelText-id" class="ControlledSwitch-labelText-id"
> >
@ -116013,9 +116016,7 @@ exports[`Storyshots Views / Product types / Product type details loading 1`] = `
<span <span
class="MuiTypography-root-id MuiFormControlLabel-label-id MuiFormControlLabel-disabled-id MuiTypography-body1-id" class="MuiTypography-root-id MuiFormControlLabel-label-id MuiFormControlLabel-disabled-id MuiTypography-body1-id"
> >
<div <div>
class="ControlledSwitch-label-id"
>
<span <span
class="ControlledSwitch-labelText-id" class="ControlledSwitch-labelText-id"
> >
@ -116396,9 +116397,7 @@ exports[`Storyshots Views / Product types / Product type details no attributes 1
<span <span
class="MuiTypography-root-id MuiFormControlLabel-label-id MuiTypography-body1-id" class="MuiTypography-root-id MuiFormControlLabel-label-id MuiTypography-body1-id"
> >
<div <div>
class="ControlledSwitch-label-id"
>
<span <span
class="ControlledSwitch-labelText-id" class="ControlledSwitch-labelText-id"
> >

View file

@ -1,3 +1,4 @@
import { PluginErrorCode } from "@saleor/types/globalTypes";
import { storiesOf } from "@storybook/react"; import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
@ -7,7 +8,6 @@ import PluginsDetailsPage, {
} from "../../../plugins/components/PluginsDetailsPage"; } from "../../../plugins/components/PluginsDetailsPage";
import { plugin } from "../../../plugins/fixtures"; import { plugin } from "../../../plugins/fixtures";
import Decorator from "../../Decorator"; import Decorator from "../../Decorator";
import { formError } from "../../misc";
const props: PluginsDetailsPageProps = { const props: PluginsDetailsPageProps = {
disabled: false, disabled: false,
@ -29,11 +29,20 @@ storiesOf("Views / Plugins / Plugin details", module)
.add("form errors", () => ( .add("form errors", () => (
<PluginsDetailsPage <PluginsDetailsPage
{...props} {...props}
errors={([ errors={[
"active", ...(["active", "Username or account", "Password or license"] as Array<
"Username or account", keyof FormData
"Password or license" >).map(field => ({
] as Array<keyof FormData>).map(formError)} __typename: "PluginError" as "PluginError",
code: PluginErrorCode.INVALID,
field
})),
{
__typename: "PluginError" as "PluginError",
code: PluginErrorCode.PLUGIN_MISCONFIGURED,
field: null
}
]}
/> />
)) ))
.add("not configurable", () => ( .add("not configurable", () => (

View file

@ -665,6 +665,15 @@ export enum PermissionGroupSortField {
NAME = "NAME", NAME = "NAME",
} }
export enum PluginErrorCode {
GRAPHQL_ERROR = "GRAPHQL_ERROR",
INVALID = "INVALID",
NOT_FOUND = "NOT_FOUND",
PLUGIN_MISCONFIGURED = "PLUGIN_MISCONFIGURED",
REQUIRED = "REQUIRED",
UNIQUE = "UNIQUE",
}
export enum PluginSortField { export enum PluginSortField {
IS_ACTIVE = "IS_ACTIVE", IS_ACTIVE = "IS_ACTIVE",
NAME = "NAME", NAME = "NAME",

View file

@ -0,0 +1,41 @@
import { PluginErrorFragment } from "@saleor/fragments/types/PluginErrorFragment";
import { commonMessages } from "@saleor/intl";
import { PluginErrorCode } from "@saleor/types/globalTypes";
import { defineMessages, IntlShape } from "react-intl";
import commonErrorMessages from "./common";
const messages = defineMessages({
misconfigured: {
defaultMessage: "Plugin is misconfigured and cannot be activated"
},
unique: {
defaultMessage: "This field needs to be unique"
}
});
function getPluginErrorMessage(
err: PluginErrorFragment,
intl: IntlShape
): string {
if (err) {
switch (err.code) {
case PluginErrorCode.PLUGIN_MISCONFIGURED:
return intl.formatMessage(messages.misconfigured);
case PluginErrorCode.GRAPHQL_ERROR:
return intl.formatMessage(commonErrorMessages.graphqlError);
case PluginErrorCode.INVALID:
return intl.formatMessage(commonErrorMessages.invalid);
case PluginErrorCode.REQUIRED:
return intl.formatMessage(commonMessages.requiredField);
case PluginErrorCode.UNIQUE:
return intl.formatMessage(messages.unique);
default:
return intl.formatMessage(commonErrorMessages.unknownError);
}
}
return undefined;
}
export default getPluginErrorMessage;