Fix webhook api errors

This commit is contained in:
Krzysztof Bialoglowicz 2019-10-18 14:01:26 +02:00
parent 4f12124b4f
commit 9a5f95b68f
11 changed files with 114 additions and 22 deletions

View file

@ -286,6 +286,14 @@ export enum VoucherTypeEnum {
SPECIFIC_PRODUCT = "SPECIFIC_PRODUCT", SPECIFIC_PRODUCT = "SPECIFIC_PRODUCT",
} }
export enum WebhookErrorCode {
GRAPHQL_ERROR = "GRAPHQL_ERROR",
INVALID = "INVALID",
NOT_FOUND = "NOT_FOUND",
REQUIRED = "REQUIRED",
UNIQUE = "UNIQUE",
}
export enum WebhookEventTypeEnum { export enum WebhookEventTypeEnum {
ANY_EVENTS = "ANY_EVENTS", ANY_EVENTS = "ANY_EVENTS",
CUSTOMER_CREATED = "CUSTOMER_CREATED", CUSTOMER_CREATED = "CUSTOMER_CREATED",

View file

@ -9,12 +9,12 @@ import SaveButtonBar from "@saleor/components/SaveButtonBar";
import { SearchServiceAccount_search_edges_node } from "@saleor/containers/SearchServiceAccount/types/SearchServiceAccount"; import { SearchServiceAccount_search_edges_node } from "@saleor/containers/SearchServiceAccount/types/SearchServiceAccount";
import { sectionNames } from "@saleor/intl"; import { sectionNames } from "@saleor/intl";
import { maybe } from "@saleor/misc"; import { maybe } from "@saleor/misc";
import { UserError } from "@saleor/types";
import { WebhookEventTypeEnum } from "@saleor/types/globalTypes"; import { WebhookEventTypeEnum } from "@saleor/types/globalTypes";
import createSingleAutocompleteSelectHandler from "@saleor/utils/handlers/singleAutocompleteSelectChangeHandler"; import createSingleAutocompleteSelectHandler from "@saleor/utils/handlers/singleAutocompleteSelectChangeHandler";
import WebhookEvents from "@saleor/webhooks/components/WebhookEvents"; import WebhookEvents from "@saleor/webhooks/components/WebhookEvents";
import WebhookInfo from "@saleor/webhooks/components/WebhookInfo"; import WebhookInfo from "@saleor/webhooks/components/WebhookInfo";
import WebhookStatus from "@saleor/webhooks/components/WebhookStatus"; import WebhookStatus from "@saleor/webhooks/components/WebhookStatus";
import { WebhookCreate_webhookCreate_webhookErrors } from "@saleor/webhooks/types/WebhookCreate";
import React from "react"; import React from "react";
import { useIntl } from "react-intl"; import { useIntl } from "react-intl";
@ -31,7 +31,7 @@ export interface FormData {
export interface WebhookCreatePageProps { export interface WebhookCreatePageProps {
disabled: boolean; disabled: boolean;
errors: UserError[]; errors: WebhookCreate_webhookCreate_webhookErrors[];
services?: SearchServiceAccount_search_edges_node[]; services?: SearchServiceAccount_search_edges_node[];
saveButtonBarState: ConfirmButtonTransitionState; saveButtonBarState: ConfirmButtonTransitionState;
fetchServiceAccounts: (data: string) => void; fetchServiceAccounts: (data: string) => void;
@ -39,9 +39,9 @@ export interface WebhookCreatePageProps {
onSubmit: (data: FormData) => void; onSubmit: (data: FormData) => void;
} }
const WebhookCreatePage: React.StatelessComponent<WebhookCreatePageProps> = ({ const WebhookCreatePage: React.FC<WebhookCreatePageProps> = ({
disabled, disabled,
errors, errors: apiErrors,
saveButtonBarState, saveButtonBarState,
services, services,
fetchServiceAccounts, fetchServiceAccounts,
@ -72,7 +72,7 @@ const WebhookCreatePage: React.StatelessComponent<WebhookCreatePageProps> = ({
); );
return ( return (
<Form errors={errors} initial={initialForm} onSubmit={onSubmit}> <Form errors={apiErrors} initial={initialForm} onSubmit={onSubmit}>
{({ data, errors, hasChanged, submit, change }) => { {({ data, errors, hasChanged, submit, change }) => {
const handleServiceSelect = createSingleAutocompleteSelectHandler( const handleServiceSelect = createSingleAutocompleteSelectHandler(
change, change,
@ -98,6 +98,7 @@ const WebhookCreatePage: React.StatelessComponent<WebhookCreatePageProps> = ({
serviceDisplayValue={selectedServiceAcccount} serviceDisplayValue={selectedServiceAcccount}
services={servicesChoiceList} services={servicesChoiceList}
fetchServiceAccounts={fetchServiceAccounts} fetchServiceAccounts={fetchServiceAccounts}
apiErrors={apiErrors}
errors={errors} errors={errors}
serviceOnChange={handleServiceSelect} serviceOnChange={handleServiceSelect}
onChange={change} onChange={change}

View file

@ -2,7 +2,7 @@ import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
import Decorator from "@saleor/storybook/Decorator"; import Decorator from "@saleor/storybook/Decorator";
import { formError } from "@saleor/storybook/misc"; import { WebhookErrorCode } from "@saleor/types/globalTypes";
import WebhookCreatePage, { WebhookCreatePageProps } from "./WebhookCreatePage"; import WebhookCreatePage, { WebhookCreatePageProps } from "./WebhookCreatePage";
const props: WebhookCreatePageProps = { const props: WebhookCreatePageProps = {
@ -21,6 +21,15 @@ storiesOf("Views / Webhooks / Create webhook", module)
.add("form errors", () => ( .add("form errors", () => (
<WebhookCreatePage <WebhookCreatePage
{...props} {...props}
errors={["name"].map(field => formError(field))} errors={[
{
code: WebhookErrorCode.INVALID,
field: null
}
].map(error => ({
__typename: "WebhookError",
message: "Generic form error",
...error
}))}
/> />
)); ));

View file

@ -4,7 +4,7 @@ import TextField from "@material-ui/core/TextField";
import Typography from "@material-ui/core/Typography"; import Typography from "@material-ui/core/Typography";
import makeStyles from "@material-ui/styles/makeStyles"; import makeStyles from "@material-ui/styles/makeStyles";
import React from "react"; import React from "react";
import { useIntl } from "react-intl"; import { IntlShape, useIntl } from "react-intl";
import CardTitle from "@saleor/components/CardTitle"; import CardTitle from "@saleor/components/CardTitle";
import FormSpacer from "@saleor/components/FormSpacer"; import FormSpacer from "@saleor/components/FormSpacer";
@ -15,9 +15,12 @@ import SingleAutocompleteSelectField, {
import { ChangeEvent } from "@saleor/hooks/useForm"; import { ChangeEvent } from "@saleor/hooks/useForm";
import { commonMessages } from "@saleor/intl"; import { commonMessages } from "@saleor/intl";
import { FormErrors } from "@saleor/types"; import { FormErrors } from "@saleor/types";
import { WebhookErrorCode } from "@saleor/types/globalTypes";
import { WebhookCreate_webhookCreate_webhookErrors } from "@saleor/webhooks/types/WebhookCreate";
import { FormData } from "../WebhooksDetailsPage"; import { FormData } from "../WebhooksDetailsPage";
interface WebhookInfoProps { interface WebhookInfoProps {
apiErrors: WebhookCreate_webhookCreate_webhookErrors[];
data: FormData; data: FormData;
disabled: boolean; disabled: boolean;
serviceDisplayValue: string; serviceDisplayValue: string;
@ -40,6 +43,7 @@ const useStyles = makeStyles(() => ({
})); }));
const WebhookInfo: React.StatelessComponent<WebhookInfoProps> = ({ const WebhookInfo: React.StatelessComponent<WebhookInfoProps> = ({
apiErrors,
data, data,
disabled, disabled,
services, services,
@ -51,6 +55,18 @@ const WebhookInfo: React.StatelessComponent<WebhookInfoProps> = ({
}) => { }) => {
const classes = useStyles({}); const classes = useStyles({});
const intl = useIntl(); const intl = useIntl();
const translatedErrors = translateErrors(intl);
const serviceAccountsError =
apiErrors.filter(error => error.field === null).length > 0;
function translateErrors(intl: IntlShape) {
return {
[WebhookErrorCode.INVALID]: intl.formatMessage({
defaultMessage: "Missing token or serviceAccount",
description: "webhook service account error"
})
};
}
return ( return (
<Card> <Card>
@ -92,6 +108,14 @@ const WebhookInfo: React.StatelessComponent<WebhookInfoProps> = ({
label={intl.formatMessage({ label={intl.formatMessage({
defaultMessage: "Assign to Service Account" defaultMessage: "Assign to Service Account"
})} })}
error={serviceAccountsError}
helperText={
serviceAccountsError &&
intl.formatMessage({
defaultMessage: "Missing token or serviceAccount",
description: "webhook service account error"
})
}
name="serviceAccount" name="serviceAccount"
onChange={serviceOnChange} onChange={serviceOnChange}
value={data.serviceAccount} value={data.serviceAccount}
@ -136,6 +160,18 @@ const WebhookInfo: React.StatelessComponent<WebhookInfoProps> = ({
value={data.secretKey} value={data.secretKey}
onChange={onChange} onChange={onChange}
/> />
{apiErrors.length > 0 && (
<>
<FormSpacer />
{apiErrors
.filter(error => error.field === null)
.map(error => (
<Typography color="error" key={error.code}>
{translatedErrors[error.code]}
</Typography>
))}
</>
)}
</CardContent> </CardContent>
</Card> </Card>
); );

View file

@ -2,7 +2,7 @@ import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
import Decorator from "@saleor/storybook/Decorator"; import Decorator from "@saleor/storybook/Decorator";
import { formError } from "@saleor/storybook/misc"; import { WebhookErrorCode } from "@saleor/types/globalTypes";
import WebhooksDetailsPage, { import WebhooksDetailsPage, {
WebhooksDetailsPageProps WebhooksDetailsPageProps
} from "./WebhooksDetailsPage"; } from "./WebhooksDetailsPage";
@ -32,6 +32,15 @@ storiesOf("Views / Webhooks / Webhook details", module)
.add("form errors", () => ( .add("form errors", () => (
<WebhooksDetailsPage <WebhooksDetailsPage
{...props} {...props}
errors={["name"].map(field => formError(field))} errors={[
{
code: WebhookErrorCode.INVALID,
field: null
}
].map(error => ({
__typename: "WebhookError",
message: "Generic form error",
...error
}))}
/> />
)); ));

View file

@ -10,12 +10,12 @@ import { SearchServiceAccount_search_edges_node } from "@saleor/containers/Searc
import useStateFromProps from "@saleor/hooks/useStateFromProps"; import useStateFromProps from "@saleor/hooks/useStateFromProps";
import { sectionNames } from "@saleor/intl"; import { sectionNames } from "@saleor/intl";
import { maybe } from "@saleor/misc"; import { maybe } from "@saleor/misc";
import { UserError } from "@saleor/types";
import { WebhookEventTypeEnum } from "@saleor/types/globalTypes"; import { WebhookEventTypeEnum } from "@saleor/types/globalTypes";
import createSingleAutocompleteSelectHandler from "@saleor/utils/handlers/singleAutocompleteSelectChangeHandler"; import createSingleAutocompleteSelectHandler from "@saleor/utils/handlers/singleAutocompleteSelectChangeHandler";
import WebhookEvents from "@saleor/webhooks/components/WebhookEvents"; import WebhookEvents from "@saleor/webhooks/components/WebhookEvents";
import WebhookInfo from "@saleor/webhooks/components/WebhookInfo"; import WebhookInfo from "@saleor/webhooks/components/WebhookInfo";
import WebhookStatus from "@saleor/webhooks/components/WebhookStatus"; import WebhookStatus from "@saleor/webhooks/components/WebhookStatus";
import { WebhookCreate_webhookCreate_webhookErrors } from "@saleor/webhooks/types/WebhookCreate";
import { WebhookDetails_webhook } from "@saleor/webhooks/types/WebhookDetails"; import { WebhookDetails_webhook } from "@saleor/webhooks/types/WebhookDetails";
import React from "react"; import React from "react";
@ -34,7 +34,7 @@ export interface FormData {
export interface WebhooksDetailsPageProps { export interface WebhooksDetailsPageProps {
disabled: boolean; disabled: boolean;
errors: UserError[]; errors: WebhookCreate_webhookCreate_webhookErrors[];
webhook: WebhookDetails_webhook; webhook: WebhookDetails_webhook;
services?: SearchServiceAccount_search_edges_node[]; services?: SearchServiceAccount_search_edges_node[];
saveButtonBarState: ConfirmButtonTransitionState; saveButtonBarState: ConfirmButtonTransitionState;
@ -46,7 +46,7 @@ export interface WebhooksDetailsPageProps {
const WebhooksDetailsPage: React.FC<WebhooksDetailsPageProps> = ({ const WebhooksDetailsPage: React.FC<WebhooksDetailsPageProps> = ({
disabled, disabled,
errors, errors: apiErrors,
webhook, webhook,
saveButtonBarState, saveButtonBarState,
services, services,
@ -83,7 +83,7 @@ const WebhooksDetailsPage: React.FC<WebhooksDetailsPageProps> = ({
[] []
); );
return ( return (
<Form errors={errors} initial={initialForm} onSubmit={onSubmit}> <Form errors={apiErrors} initial={initialForm} onSubmit={onSubmit}>
{({ data, errors, hasChanged, submit, change }) => { {({ data, errors, hasChanged, submit, change }) => {
const handleServiceSelect = createSingleAutocompleteSelectHandler( const handleServiceSelect = createSingleAutocompleteSelectHandler(
change, change,
@ -109,6 +109,7 @@ const WebhooksDetailsPage: React.FC<WebhooksDetailsPageProps> = ({
<Grid> <Grid>
<div> <div>
<WebhookInfo <WebhookInfo
apiErrors={apiErrors}
data={data} data={data}
disabled={disabled} disabled={disabled}
serviceDisplayValue={selectedServiceAcccounts} serviceDisplayValue={selectedServiceAcccounts}

View file

@ -14,6 +14,11 @@ const webhookCreate = gql`
field field
message message
} }
webhookErrors {
code
message
field
}
webhook { webhook {
...WebhooksDetailsFragment ...WebhooksDetailsFragment
} }
@ -33,6 +38,11 @@ const webhookUpdate = gql`
field field
message message
} }
webhookErrors {
code
message
field
}
webhook { webhook {
...WebhooksDetailsFragment ...WebhooksDetailsFragment
} }

View file

@ -2,7 +2,7 @@
/* 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 { WebhookCreateInput } from "./../../types/globalTypes"; import { WebhookCreateInput, WebhookErrorCode } from "./../../types/globalTypes";
// ==================================================== // ====================================================
// GraphQL mutation operation: WebhookCreate // GraphQL mutation operation: WebhookCreate
@ -14,6 +14,13 @@ export interface WebhookCreate_webhookCreate_errors {
message: string | null; message: string | null;
} }
export interface WebhookCreate_webhookCreate_webhookErrors {
__typename: "WebhookError";
code: WebhookErrorCode | null;
message: string | null;
field: string | null;
}
export interface WebhookCreate_webhookCreate_webhook_serviceAccount { export interface WebhookCreate_webhookCreate_webhook_serviceAccount {
__typename: "ServiceAccount"; __typename: "ServiceAccount";
id: string; id: string;
@ -31,6 +38,7 @@ export interface WebhookCreate_webhookCreate_webhook {
export interface WebhookCreate_webhookCreate { export interface WebhookCreate_webhookCreate {
__typename: "WebhookCreate"; __typename: "WebhookCreate";
errors: WebhookCreate_webhookCreate_errors[] | null; errors: WebhookCreate_webhookCreate_errors[] | null;
webhookErrors: WebhookCreate_webhookCreate_webhookErrors[] | null;
webhook: WebhookCreate_webhookCreate_webhook | null; webhook: WebhookCreate_webhookCreate_webhook | null;
} }

View file

@ -2,7 +2,7 @@
/* 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 { WebhookUpdateInput } from "./../../types/globalTypes"; import { WebhookUpdateInput, WebhookErrorCode } from "./../../types/globalTypes";
// ==================================================== // ====================================================
// GraphQL mutation operation: WebhookUpdate // GraphQL mutation operation: WebhookUpdate
@ -14,6 +14,13 @@ export interface WebhookUpdate_webhookUpdate_errors {
message: string | null; message: string | null;
} }
export interface WebhookUpdate_webhookUpdate_webhookErrors {
__typename: "WebhookError";
code: WebhookErrorCode | null;
message: string | null;
field: string | null;
}
export interface WebhookUpdate_webhookUpdate_webhook_serviceAccount { export interface WebhookUpdate_webhookUpdate_webhook_serviceAccount {
__typename: "ServiceAccount"; __typename: "ServiceAccount";
id: string; id: string;
@ -31,6 +38,7 @@ export interface WebhookUpdate_webhookUpdate_webhook {
export interface WebhookUpdate_webhookUpdate { export interface WebhookUpdate_webhookUpdate {
__typename: "WebhookUpdate"; __typename: "WebhookUpdate";
errors: WebhookUpdate_webhookUpdate_errors[] | null; errors: WebhookUpdate_webhookUpdate_errors[] | null;
webhookErrors: WebhookUpdate_webhookUpdate_webhookErrors[] | null;
webhook: WebhookUpdate_webhookUpdate_webhook | null; webhook: WebhookUpdate_webhookUpdate_webhook | null;
} }

View file

@ -30,7 +30,7 @@ export const WebhooksCreate: React.StatelessComponent<
const intl = useIntl(); const intl = useIntl();
const onSubmit = (data: WebhookCreateData) => { const onSubmit = (data: WebhookCreateData) => {
if (data.webhookCreate.errors.length === 0) { if (data.webhookCreate.webhookErrors.length === 0) {
notify({ notify({
text: intl.formatMessage(commonMessages.savedChanges) text: intl.formatMessage(commonMessages.savedChanges)
}); });
@ -64,7 +64,7 @@ export const WebhooksCreate: React.StatelessComponent<
const formTransitionState = getMutationState( const formTransitionState = getMutationState(
webhookCreateOpts.called, webhookCreateOpts.called,
webhookCreateOpts.loading, webhookCreateOpts.loading,
maybe(() => webhookCreateOpts.data.webhookCreate.errors) maybe(() => webhookCreateOpts.data.webhookCreate.webhookErrors)
); );
return ( return (
@ -78,7 +78,7 @@ export const WebhooksCreate: React.StatelessComponent<
<WebhookCreatePage <WebhookCreatePage
disabled={false} disabled={false}
errors={maybe( errors={maybe(
() => webhookCreateOpts.data.webhookCreate.errors, () => webhookCreateOpts.data.webhookCreate.webhookErrors,
[] []
)} )}
fetchServiceAccounts={searchServiceAccount} fetchServiceAccounts={searchServiceAccount}

View file

@ -63,7 +63,7 @@ export const WebhooksDetails: React.FC<WebhooksDetailsProps> = ({
}; };
const onWebhookUpdate = (data: WebhookUpdate) => { const onWebhookUpdate = (data: WebhookUpdate) => {
if (data.webhookUpdate.errors.length === 0) { if (data.webhookUpdate.webhookErrors.length === 0) {
notify({ notify({
text: intl.formatMessage(commonMessages.savedChanges) text: intl.formatMessage(commonMessages.savedChanges)
}); });
@ -83,7 +83,9 @@ export const WebhooksDetails: React.FC<WebhooksDetailsProps> = ({
const formTransitionState = getMutationState( const formTransitionState = getMutationState(
webhookUpdateOpts.called, webhookUpdateOpts.called,
webhookUpdateOpts.loading, webhookUpdateOpts.loading,
maybe(() => webhookUpdateOpts.data.webhookUpdate.errors) maybe(
() => webhookUpdateOpts.data.webhookUpdate.webhookErrors
)
); );
const handleRemoveConfirm = () => const handleRemoveConfirm = () =>
@ -94,7 +96,7 @@ export const WebhooksDetails: React.FC<WebhooksDetailsProps> = ({
}); });
const formErrors = maybe( const formErrors = maybe(
() => webhookUpdateOpts.data.webhookUpdate.errors, () => webhookUpdateOpts.data.webhookUpdate.webhookErrors,
[] []
); );