Add WebhookHeaders component (#3107)
* Add custom request headers to webhook form
This commit is contained in:
parent
0093f8dad4
commit
ab2ce01c8a
20 changed files with 713 additions and 16 deletions
|
@ -20,6 +20,7 @@ All notable, unreleased changes to this project will be documented in this file.
|
||||||
- Add GraphiQL editor to webhook form for defining the subscription query #2885 by @2can @zaiste
|
- Add GraphiQL editor to webhook form for defining the subscription query #2885 by @2can @zaiste
|
||||||
- Add redirect to GraphiQL from product & order details pages - #2940 by @zaiste
|
- Add redirect to GraphiQL from product & order details pages - #2940 by @zaiste
|
||||||
- Extract permissions for subscription query - #3155 by @zaiste
|
- Extract permissions for subscription query - #3155 by @zaiste
|
||||||
|
- Add custom request headers to webhook form - #3107 by @2can
|
||||||
|
|
||||||
## 3.4
|
## 3.4
|
||||||
|
|
||||||
|
|
|
@ -3811,6 +3811,12 @@
|
||||||
"isDeprecated": false,
|
"isDeprecated": false,
|
||||||
"deprecationReason": null
|
"deprecationReason": null
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "INVALID_CUSTOM_HEADERS",
|
||||||
|
"description": null,
|
||||||
|
"isDeprecated": false,
|
||||||
|
"deprecationReason": null
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "MANIFEST_URL_CANT_CONNECT",
|
"name": "MANIFEST_URL_CANT_CONNECT",
|
||||||
"description": null,
|
"description": null,
|
||||||
|
@ -56083,13 +56089,9 @@
|
||||||
"name": "oldPassword",
|
"name": "oldPassword",
|
||||||
"description": "Current user password.",
|
"description": "Current user password.",
|
||||||
"type": {
|
"type": {
|
||||||
"kind": "NON_NULL",
|
|
||||||
"name": null,
|
|
||||||
"ofType": {
|
|
||||||
"kind": "SCALAR",
|
"kind": "SCALAR",
|
||||||
"name": "String",
|
"name": "String",
|
||||||
"ofType": null
|
"ofType": null
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"defaultValue": null,
|
"defaultValue": null,
|
||||||
"isDeprecated": false,
|
"isDeprecated": false,
|
||||||
|
@ -112428,6 +112430,18 @@
|
||||||
},
|
},
|
||||||
"isDeprecated": false,
|
"isDeprecated": false,
|
||||||
"deprecationReason": null
|
"deprecationReason": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "customHeaders",
|
||||||
|
"description": "Custom headers, which will be added to HTTP request.\n\nAdded in Saleor 3.12.\n\nNote: this API is currently in Feature Preview and can be subject to changes at later point.",
|
||||||
|
"args": [],
|
||||||
|
"type": {
|
||||||
|
"kind": "SCALAR",
|
||||||
|
"name": "JSONString",
|
||||||
|
"ofType": null
|
||||||
|
},
|
||||||
|
"isDeprecated": false,
|
||||||
|
"deprecationReason": null
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"inputFields": null,
|
"inputFields": null,
|
||||||
|
@ -112649,6 +112663,18 @@
|
||||||
"defaultValue": null,
|
"defaultValue": null,
|
||||||
"isDeprecated": false,
|
"isDeprecated": false,
|
||||||
"deprecationReason": null
|
"deprecationReason": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "customHeaders",
|
||||||
|
"description": "Custom headers, which will be added to HTTP request. There is a limitation of 5 headers per webhook and 998 characters per header.Only \"X-*\" and \"Authorization*\" keys are allowed.\n\nAdded in Saleor 3.12.\n\nNote: this API is currently in Feature Preview and can be subject to changes at later point.",
|
||||||
|
"type": {
|
||||||
|
"kind": "SCALAR",
|
||||||
|
"name": "JSONString",
|
||||||
|
"ofType": null
|
||||||
|
},
|
||||||
|
"defaultValue": null,
|
||||||
|
"isDeprecated": false,
|
||||||
|
"deprecationReason": null
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"interfaces": null,
|
"interfaces": null,
|
||||||
|
@ -113007,6 +113033,12 @@
|
||||||
"description": null,
|
"description": null,
|
||||||
"isDeprecated": false,
|
"isDeprecated": false,
|
||||||
"deprecationReason": null
|
"deprecationReason": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "INVALID_CUSTOM_HEADERS",
|
||||||
|
"description": null,
|
||||||
|
"isDeprecated": false,
|
||||||
|
"deprecationReason": null
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"possibleTypes": null
|
"possibleTypes": null
|
||||||
|
@ -115715,6 +115747,18 @@
|
||||||
"defaultValue": null,
|
"defaultValue": null,
|
||||||
"isDeprecated": false,
|
"isDeprecated": false,
|
||||||
"deprecationReason": null
|
"deprecationReason": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "customHeaders",
|
||||||
|
"description": "Custom headers, which will be added to HTTP request. There is a limitation of 5 headers per webhook and 998 characters per header.Only \"X-*\" and \"Authorization*\" keys are allowed.\n\nAdded in Saleor 3.12.\n\nNote: this API is currently in Feature Preview and can be subject to changes at later point.",
|
||||||
|
"type": {
|
||||||
|
"kind": "SCALAR",
|
||||||
|
"name": "JSONString",
|
||||||
|
"ofType": null
|
||||||
|
},
|
||||||
|
"defaultValue": null,
|
||||||
|
"isDeprecated": false,
|
||||||
|
"deprecationReason": null
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"interfaces": null,
|
"interfaces": null,
|
||||||
|
|
|
@ -156,6 +156,10 @@
|
||||||
"context": "product type shipping settings, section header",
|
"context": "product type shipping settings, section header",
|
||||||
"string": "Shipping"
|
"string": "Shipping"
|
||||||
},
|
},
|
||||||
|
"/4bJkA": {
|
||||||
|
"context": "header field value, header",
|
||||||
|
"string": "Value"
|
||||||
|
},
|
||||||
"/5r4he": {
|
"/5r4he": {
|
||||||
"context": "label for button",
|
"context": "label for button",
|
||||||
"string": "Add country"
|
"string": "Add country"
|
||||||
|
@ -550,6 +554,10 @@
|
||||||
"context": "gift card not found message",
|
"context": "gift card not found message",
|
||||||
"string": "Couldn't find gift card"
|
"string": "Couldn't find gift card"
|
||||||
},
|
},
|
||||||
|
"2BHjVL": {
|
||||||
|
"context": "header",
|
||||||
|
"string": "Custom request headers"
|
||||||
|
},
|
||||||
"2CBcub": {
|
"2CBcub": {
|
||||||
"context": "CreateVariantTitle manage",
|
"context": "CreateVariantTitle manage",
|
||||||
"string": "Manage"
|
"string": "Manage"
|
||||||
|
@ -1443,6 +1451,10 @@
|
||||||
"9UHfux": {
|
"9UHfux": {
|
||||||
"string": "Voucher Specific Information"
|
"string": "Voucher Specific Information"
|
||||||
},
|
},
|
||||||
|
"9Y5i/8": {
|
||||||
|
"context": "number of webhook headers in model",
|
||||||
|
"string": "{number,plural,one{{number} header} other{{number} custom request headers}}"
|
||||||
|
},
|
||||||
"9Y6vg+": {
|
"9Y6vg+": {
|
||||||
"context": "dialog header",
|
"context": "dialog header",
|
||||||
"string": "Add product"
|
"string": "Add product"
|
||||||
|
@ -3375,6 +3387,10 @@
|
||||||
"context": "channels section name",
|
"context": "channels section name",
|
||||||
"string": "Channels"
|
"string": "Channels"
|
||||||
},
|
},
|
||||||
|
"No4lyL": {
|
||||||
|
"context": "header field name, header",
|
||||||
|
"string": "Name"
|
||||||
|
},
|
||||||
"Np7J92": {
|
"Np7J92": {
|
||||||
"context": "deactivate local named app",
|
"context": "deactivate local named app",
|
||||||
"string": "Are you sure you want to disable {name}? Your data will be kept until you reactivate the app."
|
"string": "Are you sure you want to disable {name}? Your data will be kept until you reactivate the app."
|
||||||
|
@ -5185,6 +5201,10 @@
|
||||||
"b+jcaN": {
|
"b+jcaN": {
|
||||||
"string": "There are still fulfillments created for this order. Cancel the fulfillments first before you cancel the order."
|
"string": "There are still fulfillments created for this order. Cancel the fulfillments first before you cancel the order."
|
||||||
},
|
},
|
||||||
|
"b1t9bM": {
|
||||||
|
"context": "empty headers text",
|
||||||
|
"string": "No custom request headers created for this webhook. Use the button below to add new custom request header."
|
||||||
|
},
|
||||||
"b1zuN9": {
|
"b1zuN9": {
|
||||||
"string": "Price"
|
"string": "Price"
|
||||||
},
|
},
|
||||||
|
@ -5980,6 +6000,10 @@
|
||||||
"context": "sale start date",
|
"context": "sale start date",
|
||||||
"string": "Starts"
|
"string": "Starts"
|
||||||
},
|
},
|
||||||
|
"iERn5G": {
|
||||||
|
"context": "header name input",
|
||||||
|
"string": "Should start with `x-` or `authorization`"
|
||||||
|
},
|
||||||
"iEeIhY": {
|
"iEeIhY": {
|
||||||
"context": "draft order",
|
"context": "draft order",
|
||||||
"string": "Customer"
|
"string": "Customer"
|
||||||
|
@ -7495,6 +7519,10 @@
|
||||||
"uMpv1v": {
|
"uMpv1v": {
|
||||||
"string": "Fulfillment successfully cancelled"
|
"string": "Fulfillment successfully cancelled"
|
||||||
},
|
},
|
||||||
|
"uQNm59": {
|
||||||
|
"context": "add header,button",
|
||||||
|
"string": "Add custom request header"
|
||||||
|
},
|
||||||
"uQk8gB": {
|
"uQk8gB": {
|
||||||
"context": "export all items to csv file",
|
"context": "export all items to csv file",
|
||||||
"string": "All gift cards ({number})"
|
"string": "All gift cards ({number})"
|
||||||
|
@ -7776,6 +7804,10 @@
|
||||||
"context": "see error log label in notification",
|
"context": "see error log label in notification",
|
||||||
"string": "See error log"
|
"string": "See error log"
|
||||||
},
|
},
|
||||||
|
"wChjN/": {
|
||||||
|
"context": "accepted header names",
|
||||||
|
"string": "Headers with in following format are accepted: `authorization*`, `x-*`"
|
||||||
|
},
|
||||||
"wDUBLR": {
|
"wDUBLR": {
|
||||||
"context": "order refund amount",
|
"context": "order refund amount",
|
||||||
"string": "Proposed refund amount"
|
"string": "Proposed refund amount"
|
||||||
|
|
|
@ -727,6 +727,7 @@ enum AppErrorCode {
|
||||||
INVALID_PERMISSION
|
INVALID_PERMISSION
|
||||||
INVALID_URL_FORMAT
|
INVALID_URL_FORMAT
|
||||||
INVALID_MANIFEST_FORMAT
|
INVALID_MANIFEST_FORMAT
|
||||||
|
INVALID_CUSTOM_HEADERS
|
||||||
MANIFEST_URL_CANT_CONNECT
|
MANIFEST_URL_CANT_CONNECT
|
||||||
NOT_FOUND
|
NOT_FOUND
|
||||||
REQUIRED
|
REQUIRED
|
||||||
|
@ -12947,7 +12948,7 @@ type Mutation {
|
||||||
newPassword: String!
|
newPassword: String!
|
||||||
|
|
||||||
"""Current user password."""
|
"""Current user password."""
|
||||||
oldPassword: String!
|
oldPassword: String
|
||||||
): PasswordChange
|
): PasswordChange
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
@ -26045,6 +26046,15 @@ type Webhook implements Node {
|
||||||
|
|
||||||
"""Used to define payloads for specific events."""
|
"""Used to define payloads for specific events."""
|
||||||
subscriptionQuery: String
|
subscriptionQuery: String
|
||||||
|
|
||||||
|
"""
|
||||||
|
Custom headers, which will be added to HTTP request.
|
||||||
|
|
||||||
|
Added in Saleor 3.12.
|
||||||
|
|
||||||
|
Note: this API is currently in Feature Preview and can be subject to changes at later point.
|
||||||
|
"""
|
||||||
|
customHeaders: JSONString
|
||||||
}
|
}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
@ -26099,6 +26109,15 @@ input WebhookCreateInput {
|
||||||
Note: this API is currently in Feature Preview and can be subject to changes at later point.
|
Note: this API is currently in Feature Preview and can be subject to changes at later point.
|
||||||
"""
|
"""
|
||||||
query: String
|
query: String
|
||||||
|
|
||||||
|
"""
|
||||||
|
Custom headers, which will be added to HTTP request. There is a limitation of 5 headers per webhook and 998 characters per header.Only "X-*" and "Authorization*" keys are allowed.
|
||||||
|
|
||||||
|
Added in Saleor 3.12.
|
||||||
|
|
||||||
|
Note: this API is currently in Feature Preview and can be subject to changes at later point.
|
||||||
|
"""
|
||||||
|
customHeaders: JSONString
|
||||||
}
|
}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
@ -26178,6 +26197,7 @@ enum WebhookErrorCode {
|
||||||
MISSING_SUBSCRIPTION
|
MISSING_SUBSCRIPTION
|
||||||
UNABLE_TO_PARSE
|
UNABLE_TO_PARSE
|
||||||
MISSING_EVENT
|
MISSING_EVENT
|
||||||
|
INVALID_CUSTOM_HEADERS
|
||||||
}
|
}
|
||||||
|
|
||||||
"""Webhook event."""
|
"""Webhook event."""
|
||||||
|
@ -27380,6 +27400,15 @@ input WebhookUpdateInput {
|
||||||
Note: this API is currently in Feature Preview and can be subject to changes at later point.
|
Note: this API is currently in Feature Preview and can be subject to changes at later point.
|
||||||
"""
|
"""
|
||||||
query: String
|
query: String
|
||||||
|
|
||||||
|
"""
|
||||||
|
Custom headers, which will be added to HTTP request. There is a limitation of 5 headers per webhook and 998 characters per header.Only "X-*" and "Authorization*" keys are allowed.
|
||||||
|
|
||||||
|
Added in Saleor 3.12.
|
||||||
|
|
||||||
|
Note: this API is currently in Feature Preview and can be subject to changes at later point.
|
||||||
|
"""
|
||||||
|
customHeaders: JSONString
|
||||||
}
|
}
|
||||||
|
|
||||||
"""Represents weight value in a specific weight unit."""
|
"""Represents weight value in a specific weight unit."""
|
||||||
|
|
|
@ -27,6 +27,7 @@ import React, { useEffect, useState } from "react";
|
||||||
import { useIntl } from "react-intl";
|
import { useIntl } from "react-intl";
|
||||||
|
|
||||||
import PermissionAlert from "../PermissionAlert";
|
import PermissionAlert from "../PermissionAlert";
|
||||||
|
import WebhookHeaders from "../WebhookHeaders";
|
||||||
import WebhookSubscriptionQuery from "../WebhookSubscriptionQuery";
|
import WebhookSubscriptionQuery from "../WebhookSubscriptionQuery";
|
||||||
import { getHeaderTitle } from "./messages";
|
import { getHeaderTitle } from "./messages";
|
||||||
|
|
||||||
|
@ -38,6 +39,7 @@ export interface WebhookFormData {
|
||||||
secretKey?: string;
|
secretKey?: string;
|
||||||
targetUrl: string;
|
targetUrl: string;
|
||||||
subscriptionQuery: string;
|
subscriptionQuery: string;
|
||||||
|
customHeaders: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface WebhookDetailsPageProps {
|
export interface WebhookDetailsPageProps {
|
||||||
|
@ -63,7 +65,7 @@ const WebhookDetailsPage: React.FC<WebhookDetailsPageProps> = ({
|
||||||
|
|
||||||
let prettified: string;
|
let prettified: string;
|
||||||
try {
|
try {
|
||||||
prettified = print(parse(webhook?.subscriptionQuery));
|
prettified = print(parse(webhook?.subscriptionQuery || ""));
|
||||||
} catch {
|
} catch {
|
||||||
prettified = webhook?.subscriptionQuery || "";
|
prettified = webhook?.subscriptionQuery || "";
|
||||||
}
|
}
|
||||||
|
@ -76,6 +78,7 @@ const WebhookDetailsPage: React.FC<WebhookDetailsPageProps> = ({
|
||||||
secretKey: webhook?.secretKey || "",
|
secretKey: webhook?.secretKey || "",
|
||||||
targetUrl: webhook?.targetUrl || "",
|
targetUrl: webhook?.targetUrl || "",
|
||||||
subscriptionQuery: prettified || "",
|
subscriptionQuery: prettified || "",
|
||||||
|
customHeaders: webhook?.customHeaders || "{}",
|
||||||
};
|
};
|
||||||
|
|
||||||
const backUrl = CustomAppUrls.resolveAppUrl(appId);
|
const backUrl = CustomAppUrls.resolveAppUrl(appId);
|
||||||
|
@ -134,6 +137,8 @@ const WebhookDetailsPage: React.FC<WebhookDetailsPageProps> = ({
|
||||||
/>
|
/>
|
||||||
<FormSpacer />
|
<FormSpacer />
|
||||||
<PermissionAlert query={query} />
|
<PermissionAlert query={query} />
|
||||||
|
<FormSpacer />
|
||||||
|
<WebhookHeaders data={data} onChange={change} />
|
||||||
</Box>
|
</Box>
|
||||||
</Content>
|
</Content>
|
||||||
<Savebar
|
<Savebar
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
import useForm from "@dashboard/hooks/useForm";
|
||||||
|
import Wrapper from "@test/wrapper";
|
||||||
|
import { act, render, screen } from "@testing-library/react";
|
||||||
|
import userEvent from "@testing-library/user-event";
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
import { customHeaders } from "./utils.test";
|
||||||
|
import WebhookHeaders, { WebhookHeadersProps } from "./WebhookHeaders";
|
||||||
|
|
||||||
|
export const props: WebhookHeadersProps = {
|
||||||
|
data: {
|
||||||
|
syncEvents: [],
|
||||||
|
asyncEvents: [],
|
||||||
|
isActive: true,
|
||||||
|
name: "Test webhook",
|
||||||
|
targetUrl: "http://localhost:3000",
|
||||||
|
subscriptionQuery: "",
|
||||||
|
customHeaders,
|
||||||
|
},
|
||||||
|
onChange: () => undefined,
|
||||||
|
};
|
||||||
|
|
||||||
|
const Component = () => {
|
||||||
|
const { change, data } = useForm(props.data, jest.fn());
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Wrapper>
|
||||||
|
<WebhookHeaders data={data} onChange={change} />
|
||||||
|
</Wrapper>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getExpandIcon = () => screen.getByTestId("expand");
|
||||||
|
|
||||||
|
describe("WebhookHeaders", () => {
|
||||||
|
it("is available on the webhook page", async () => {
|
||||||
|
// Arrange
|
||||||
|
render(<Component />);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(screen.queryByTestId("webhook-headers-editor")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("can expand field", async () => {
|
||||||
|
// Arrange
|
||||||
|
render(<Component />);
|
||||||
|
const user = userEvent.setup();
|
||||||
|
const isExpandedAttribute = "data-test-expanded";
|
||||||
|
const editor = screen.getByTestId("webhook-headers-editor");
|
||||||
|
// Assert
|
||||||
|
expect(editor).toHaveAttribute(isExpandedAttribute, "true");
|
||||||
|
// Act
|
||||||
|
await act(async () => {
|
||||||
|
await user.click(getExpandIcon());
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(editor).toHaveAttribute(isExpandedAttribute, "false");
|
||||||
|
});
|
||||||
|
});
|
159
src/custom-apps/components/WebhookHeaders/WebhookHeaders.tsx
Normal file
159
src/custom-apps/components/WebhookHeaders/WebhookHeaders.tsx
Normal file
|
@ -0,0 +1,159 @@
|
||||||
|
import { Button } from "@dashboard/components/Button";
|
||||||
|
import CardTitle from "@dashboard/components/CardTitle";
|
||||||
|
import Skeleton from "@dashboard/components/Skeleton";
|
||||||
|
import TableRowLink from "@dashboard/components/TableRowLink";
|
||||||
|
import { FormChange } from "@dashboard/hooks/useForm";
|
||||||
|
import {
|
||||||
|
Card,
|
||||||
|
CardActions,
|
||||||
|
CardContent,
|
||||||
|
Table,
|
||||||
|
TableCell,
|
||||||
|
TableHead,
|
||||||
|
Typography,
|
||||||
|
} from "@material-ui/core";
|
||||||
|
import { ExpandIcon, IconButton } from "@saleor/macaw-ui";
|
||||||
|
import clsx from "clsx";
|
||||||
|
import React, { useEffect, useMemo, useState } from "react";
|
||||||
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
|
|
||||||
|
import { WebhookFormData } from "../WebhookDetailsPage";
|
||||||
|
import { messages } from "./messages";
|
||||||
|
import useStyles from "./styles";
|
||||||
|
import { mapHeaders, stringifyHeaders } from "./utils";
|
||||||
|
import WebhookHeadersTableBody from "./WebhookHeadersTableBody";
|
||||||
|
|
||||||
|
export interface WebhookHeadersProps {
|
||||||
|
data: WebhookFormData;
|
||||||
|
onChange: FormChange;
|
||||||
|
}
|
||||||
|
|
||||||
|
const WebhookHeaders: React.FC<WebhookHeadersProps> = ({
|
||||||
|
data: { customHeaders },
|
||||||
|
onChange,
|
||||||
|
}) => {
|
||||||
|
const intl = useIntl();
|
||||||
|
const [expanded, setExpanded] = useState(false);
|
||||||
|
const classes = useStyles();
|
||||||
|
const headers = useMemo(() => mapHeaders(customHeaders), [customHeaders]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (headers.length > 0) {
|
||||||
|
setExpanded(true);
|
||||||
|
}
|
||||||
|
}, [headers.length]);
|
||||||
|
|
||||||
|
const add = () => {
|
||||||
|
const items = [...headers];
|
||||||
|
items.push({ name: "", value: "", error: false });
|
||||||
|
|
||||||
|
onChange({
|
||||||
|
target: {
|
||||||
|
name: "customHeaders",
|
||||||
|
value: stringifyHeaders(items),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card data-test-id="webhook-headers-editor" data-test-expanded={expanded}>
|
||||||
|
<CardTitle
|
||||||
|
className={classes.header}
|
||||||
|
title={
|
||||||
|
<>
|
||||||
|
{intl.formatMessage(messages.header)}
|
||||||
|
<IconButton
|
||||||
|
className={clsx(classes.expandBtn, {
|
||||||
|
[classes.rotate]: expanded,
|
||||||
|
})}
|
||||||
|
hoverOutline={false}
|
||||||
|
variant="secondary"
|
||||||
|
data-test-id="expand"
|
||||||
|
onClick={() => setExpanded(!expanded)}
|
||||||
|
>
|
||||||
|
<ExpandIcon />
|
||||||
|
</IconButton>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
{headers === undefined ? (
|
||||||
|
<CardContent>
|
||||||
|
<Skeleton />
|
||||||
|
</CardContent>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<CardContent className={classes.content}>
|
||||||
|
{headers.length > 0 && (
|
||||||
|
<Typography color="textSecondary" variant="body2">
|
||||||
|
<FormattedMessage
|
||||||
|
{...messages.headersCount}
|
||||||
|
values={{
|
||||||
|
number: headers.length,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
</CardContent>
|
||||||
|
{expanded && (
|
||||||
|
<>
|
||||||
|
{headers.length === 0 ? (
|
||||||
|
<CardContent className={classes.emptyContainer}>
|
||||||
|
<Typography variant="body2" color="textSecondary">
|
||||||
|
<FormattedMessage {...messages.noHeaders} />
|
||||||
|
</Typography>
|
||||||
|
</CardContent>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<CardContent>
|
||||||
|
<Typography variant="body2">
|
||||||
|
<FormattedMessage {...messages.acceptedFormat} />
|
||||||
|
</Typography>
|
||||||
|
</CardContent>
|
||||||
|
|
||||||
|
<Table className={classes.table}>
|
||||||
|
<TableHead>
|
||||||
|
<TableRowLink>
|
||||||
|
<TableCell
|
||||||
|
className={clsx(
|
||||||
|
classes.colNameHeader,
|
||||||
|
classes.tableCell,
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<FormattedMessage {...messages.headerName} />
|
||||||
|
</TableCell>
|
||||||
|
<TableCell
|
||||||
|
className={clsx(classes.colValue, classes.tableCell)}
|
||||||
|
>
|
||||||
|
<FormattedMessage {...messages.headerValue} />
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className={classes.colActionHeader}>
|
||||||
|
<FormattedMessage {...messages.actions} />
|
||||||
|
</TableCell>
|
||||||
|
</TableRowLink>
|
||||||
|
</TableHead>
|
||||||
|
<WebhookHeadersTableBody
|
||||||
|
onChange={onChange}
|
||||||
|
headers={headers}
|
||||||
|
/>
|
||||||
|
</Table>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
<CardActions className={classes.actions}>
|
||||||
|
<Button
|
||||||
|
variant="secondary"
|
||||||
|
data-test-id="add-header"
|
||||||
|
onClick={add}
|
||||||
|
>
|
||||||
|
<FormattedMessage {...messages.add} />
|
||||||
|
</Button>
|
||||||
|
</CardActions>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
WebhookHeaders.displayName = "WebhookHeaders";
|
||||||
|
export default WebhookHeaders;
|
|
@ -0,0 +1,125 @@
|
||||||
|
import TableRowLink from "@dashboard/components/TableRowLink";
|
||||||
|
import { FormChange } from "@dashboard/hooks/useForm";
|
||||||
|
import { removeAtIndex, updateAtIndex } from "@dashboard/utils/lists";
|
||||||
|
import { TableBody, TableCell, TextField } from "@material-ui/core";
|
||||||
|
import { DeleteIcon, IconButton } from "@saleor/macaw-ui";
|
||||||
|
import clsx from "clsx";
|
||||||
|
import React, { ChangeEvent } from "react";
|
||||||
|
import { useIntl } from "react-intl";
|
||||||
|
|
||||||
|
import { messages } from "./messages";
|
||||||
|
import useStyles from "./styles";
|
||||||
|
import { Header, stringifyHeaders } from "./utils";
|
||||||
|
|
||||||
|
const nameSeparator = ":";
|
||||||
|
const nameInputPrefix = "name";
|
||||||
|
const valueInputPrefix = "value";
|
||||||
|
|
||||||
|
export interface WebhookHeadersTableBodyProps {
|
||||||
|
onChange: FormChange;
|
||||||
|
headers: Header[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const WebhookHeadersTableBody: React.FC<WebhookHeadersTableBodyProps> = ({
|
||||||
|
onChange,
|
||||||
|
headers,
|
||||||
|
}) => {
|
||||||
|
const classes = useStyles();
|
||||||
|
const intl = useIntl();
|
||||||
|
|
||||||
|
const updateWebhookItem = (target: EventTarget & HTMLTextAreaElement) => {
|
||||||
|
const { name, value } = target;
|
||||||
|
const [field, index] = name.split(nameSeparator);
|
||||||
|
|
||||||
|
const item: Header = headers[index];
|
||||||
|
|
||||||
|
// lowercase header name
|
||||||
|
if (field === nameInputPrefix) {
|
||||||
|
item[field] = value.toLowerCase();
|
||||||
|
} else {
|
||||||
|
item[field] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
item,
|
||||||
|
index: parseInt(index, 10),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const change = ({ target }: ChangeEvent<HTMLTextAreaElement>) => {
|
||||||
|
const { item, index } = updateWebhookItem(target);
|
||||||
|
|
||||||
|
onChange({
|
||||||
|
target: {
|
||||||
|
name: "customHeaders",
|
||||||
|
value: stringifyHeaders(updateAtIndex(item, headers, index)),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TableBody>
|
||||||
|
{headers.map((field, fieldIndex) => (
|
||||||
|
<TableRowLink data-test-id="field" key={fieldIndex}>
|
||||||
|
<TableCell className={clsx(classes.colName, classes.tableCell)}>
|
||||||
|
<TextField
|
||||||
|
InputProps={{
|
||||||
|
classes: {
|
||||||
|
input: classes.input,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
inputProps={{
|
||||||
|
"aria-label": `${nameInputPrefix}${nameSeparator}${fieldIndex}`,
|
||||||
|
}}
|
||||||
|
name={`${nameInputPrefix}${nameSeparator}${fieldIndex}`}
|
||||||
|
fullWidth
|
||||||
|
onChange={change}
|
||||||
|
value={field.name}
|
||||||
|
error={field.error}
|
||||||
|
helperText={
|
||||||
|
(field.error && intl.formatMessage(messages.headerNameError)) ||
|
||||||
|
" "
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className={clsx(classes.colValue, classes.tableCell)}>
|
||||||
|
<TextField
|
||||||
|
InputProps={{
|
||||||
|
classes: {
|
||||||
|
input: classes.input,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
inputProps={{
|
||||||
|
"aria-label": `${valueInputPrefix}${nameSeparator}${fieldIndex}`,
|
||||||
|
}}
|
||||||
|
name={`${valueInputPrefix}${nameSeparator}${fieldIndex}`}
|
||||||
|
fullWidth
|
||||||
|
onChange={change}
|
||||||
|
value={field.value}
|
||||||
|
helperText={" "}
|
||||||
|
/>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className={classes.colAction}>
|
||||||
|
<IconButton
|
||||||
|
variant="secondary"
|
||||||
|
data-test-id={"delete-field-" + fieldIndex}
|
||||||
|
onClick={() =>
|
||||||
|
onChange({
|
||||||
|
target: {
|
||||||
|
name: "customHeaders",
|
||||||
|
value: stringifyHeaders(removeAtIndex(headers, fieldIndex)),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<DeleteIcon />
|
||||||
|
</IconButton>
|
||||||
|
</TableCell>
|
||||||
|
</TableRowLink>
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
WebhookHeadersTableBody.displayName = "WebhookHeadersTableRow";
|
||||||
|
export default WebhookHeadersTableBody;
|
2
src/custom-apps/components/WebhookHeaders/index.ts
Normal file
2
src/custom-apps/components/WebhookHeaders/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
export { default } from "./WebhookHeaders";
|
||||||
|
export * from "./WebhookHeaders";
|
52
src/custom-apps/components/WebhookHeaders/messages.ts
Normal file
52
src/custom-apps/components/WebhookHeaders/messages.ts
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
import { defineMessages } from "react-intl";
|
||||||
|
|
||||||
|
export const messages = defineMessages({
|
||||||
|
header: {
|
||||||
|
id: "2BHjVL",
|
||||||
|
defaultMessage: "Custom request headers",
|
||||||
|
description: "header",
|
||||||
|
},
|
||||||
|
noHeaders: {
|
||||||
|
id: "b1t9bM",
|
||||||
|
defaultMessage:
|
||||||
|
"No custom request headers created for this webhook. Use the button below to add new custom request header.",
|
||||||
|
description: "empty headers text",
|
||||||
|
},
|
||||||
|
acceptedFormat: {
|
||||||
|
id: "wChjN/",
|
||||||
|
defaultMessage:
|
||||||
|
"Headers with in following format are accepted: `authorization*`, `x-*`",
|
||||||
|
description: "accepted header names",
|
||||||
|
},
|
||||||
|
headerName: {
|
||||||
|
defaultMessage: "Name",
|
||||||
|
id: "No4lyL",
|
||||||
|
description: "header field name, header",
|
||||||
|
},
|
||||||
|
headerNameError: {
|
||||||
|
id: "iERn5G",
|
||||||
|
defaultMessage: "Should start with `x-` or `authorization`",
|
||||||
|
description: "header name input",
|
||||||
|
},
|
||||||
|
headerValue: {
|
||||||
|
id: "/4bJkA",
|
||||||
|
defaultMessage: "Value",
|
||||||
|
description: "header field value, header",
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
id: "nEixpu",
|
||||||
|
defaultMessage: "Actions",
|
||||||
|
description: "table action",
|
||||||
|
},
|
||||||
|
add: {
|
||||||
|
id: "uQNm59",
|
||||||
|
defaultMessage: "Add custom request header",
|
||||||
|
description: "add header,button",
|
||||||
|
},
|
||||||
|
headersCount: {
|
||||||
|
id: "9Y5i/8",
|
||||||
|
defaultMessage:
|
||||||
|
"{number,plural,one{{number} header} other{{number} custom request headers}}",
|
||||||
|
description: "number of webhook headers in model",
|
||||||
|
},
|
||||||
|
});
|
94
src/custom-apps/components/WebhookHeaders/styles.ts
Normal file
94
src/custom-apps/components/WebhookHeaders/styles.ts
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
import { makeStyles } from "@saleor/macaw-ui";
|
||||||
|
|
||||||
|
const useStyles = makeStyles(
|
||||||
|
theme => {
|
||||||
|
const colAction: React.CSSProperties = {
|
||||||
|
textAlign: "right",
|
||||||
|
width: 130,
|
||||||
|
};
|
||||||
|
const colName: React.CSSProperties = {
|
||||||
|
width: 250,
|
||||||
|
textAlign: "right",
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
tableCell: {
|
||||||
|
paddingTop: theme.spacing(3),
|
||||||
|
paddingLeft: theme.spacing(1),
|
||||||
|
paddingRight: theme.spacing(1),
|
||||||
|
|
||||||
|
"& .MuiFormHelperText-root": {
|
||||||
|
margin: 0,
|
||||||
|
},
|
||||||
|
|
||||||
|
"&.MuiTableCell-root:first-child:not(.MuiTableCell-paddingCheckbox)": {
|
||||||
|
paddingRight: theme.spacing(0),
|
||||||
|
paddingTop: theme.spacing(3),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
colAction: {
|
||||||
|
"&:last-child": {
|
||||||
|
...colAction,
|
||||||
|
paddingRight: theme.spacing(3),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
colActionHeader: {
|
||||||
|
...colAction,
|
||||||
|
},
|
||||||
|
colName: {
|
||||||
|
...colName,
|
||||||
|
},
|
||||||
|
colNameHeader: {
|
||||||
|
...colName,
|
||||||
|
},
|
||||||
|
colValue: {},
|
||||||
|
actions: {
|
||||||
|
"&&": {
|
||||||
|
paddingBottom: theme.spacing(2),
|
||||||
|
paddingTop: theme.spacing(2),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
content: {
|
||||||
|
paddingBottom: 0,
|
||||||
|
paddingTop: theme.spacing(),
|
||||||
|
},
|
||||||
|
emptyContainer: {
|
||||||
|
paddingBottom: 0,
|
||||||
|
paddingTop: 0,
|
||||||
|
},
|
||||||
|
expandBtn: {
|
||||||
|
position: "relative",
|
||||||
|
left: theme.spacing(1),
|
||||||
|
top: -2,
|
||||||
|
transition: theme.transitions.create("transform", {
|
||||||
|
duration: theme.transitions.duration.shorter,
|
||||||
|
}),
|
||||||
|
border: 0,
|
||||||
|
},
|
||||||
|
header: {
|
||||||
|
"&&": {
|
||||||
|
paddingBottom: theme.spacing(1),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
input: {
|
||||||
|
padding: theme.spacing(1.5, 2),
|
||||||
|
},
|
||||||
|
table: {
|
||||||
|
marginTop: theme.spacing(2),
|
||||||
|
tableLayout: "fixed",
|
||||||
|
|
||||||
|
head: {
|
||||||
|
padding: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
rotate: {
|
||||||
|
transform: "rotate(-180deg)",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "WebhookHeaders",
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
export default useStyles;
|
35
src/custom-apps/components/WebhookHeaders/utils.test.ts
Normal file
35
src/custom-apps/components/WebhookHeaders/utils.test.ts
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
import {
|
||||||
|
mapHeaders,
|
||||||
|
stringifyHeaders,
|
||||||
|
} from "@dashboard/custom-apps/components/WebhookHeaders/utils";
|
||||||
|
|
||||||
|
export const customHeaders = '{"x-auth-token":"ABC","authorization":"XYZ"}';
|
||||||
|
|
||||||
|
const parsedHeaders = [
|
||||||
|
{
|
||||||
|
name: "x-auth-token",
|
||||||
|
value: "ABC",
|
||||||
|
error: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "authorization",
|
||||||
|
value: "XYZ",
|
||||||
|
error: false,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
describe("mapHeaders", () => {
|
||||||
|
it("should map customHeaders string to Object", () => {
|
||||||
|
const headers = mapHeaders(customHeaders);
|
||||||
|
|
||||||
|
expect(headers).toEqual(parsedHeaders);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("stringifyHeaders", () => {
|
||||||
|
it("should return stringified headers", () => {
|
||||||
|
const stringified = stringifyHeaders(parsedHeaders);
|
||||||
|
|
||||||
|
expect(stringified).toEqual(customHeaders);
|
||||||
|
});
|
||||||
|
});
|
35
src/custom-apps/components/WebhookHeaders/utils.ts
Normal file
35
src/custom-apps/components/WebhookHeaders/utils.ts
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
import keyBy from "lodash/keyBy";
|
||||||
|
import mapValues from "lodash/mapValues";
|
||||||
|
|
||||||
|
export interface Header {
|
||||||
|
name: string;
|
||||||
|
value: string;
|
||||||
|
error?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const stringifyHeaders = (headers: Header[]): string =>
|
||||||
|
JSON.stringify(mapValues(keyBy(headers, "name"), "value"));
|
||||||
|
|
||||||
|
const validateName = (name: string) => {
|
||||||
|
if (
|
||||||
|
name.toLowerCase().match("(^x$)|(^x-)|(^authorization$)|(^authorization-)")
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name === "") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const mapHeaders = (customHeaders: string): Header[] => {
|
||||||
|
const parsedHeaders = JSON.parse(customHeaders);
|
||||||
|
|
||||||
|
return Object.keys(parsedHeaders).map(key => ({
|
||||||
|
name: key,
|
||||||
|
value: parsedHeaders[key],
|
||||||
|
error: validateName(key),
|
||||||
|
}));
|
||||||
|
};
|
|
@ -47,6 +47,7 @@ describe("WebhookSubscriptionQuery", () => {
|
||||||
name: "",
|
name: "",
|
||||||
targetUrl: "",
|
targetUrl: "",
|
||||||
subscriptionQuery: "",
|
subscriptionQuery: "",
|
||||||
|
customHeaders: "",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -16,4 +16,5 @@ export const webhook: WebhookDetailsFragment = {
|
||||||
subscriptionQuery:
|
subscriptionQuery:
|
||||||
"subscription { event { ... on ProductUpdated { product { name } } } }",
|
"subscription { event { ... on ProductUpdated { product { name } } } }",
|
||||||
targetUrl: "http://www.getsaleor.com",
|
targetUrl: "http://www.getsaleor.com",
|
||||||
|
customHeaders: "{}",
|
||||||
};
|
};
|
||||||
|
|
|
@ -63,6 +63,7 @@ export const CustomAppWebhookDetails: React.FC<
|
||||||
secretKey: data.secretKey,
|
secretKey: data.secretKey,
|
||||||
targetUrl: data.targetUrl,
|
targetUrl: data.targetUrl,
|
||||||
query: data.subscriptionQuery,
|
query: data.subscriptionQuery,
|
||||||
|
customHeaders: data.customHeaders,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -24,5 +24,6 @@ export const webhookDetailsFragment = gql`
|
||||||
secretKey
|
secretKey
|
||||||
targetUrl
|
targetUrl
|
||||||
subscriptionQuery
|
subscriptionQuery
|
||||||
|
customHeaders
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
|
@ -2841,6 +2841,7 @@ export const WebhookDetailsFragmentDoc = gql`
|
||||||
secretKey
|
secretKey
|
||||||
targetUrl
|
targetUrl
|
||||||
subscriptionQuery
|
subscriptionQuery
|
||||||
|
customHeaders
|
||||||
}
|
}
|
||||||
${WebhookFragmentDoc}`;
|
${WebhookFragmentDoc}`;
|
||||||
export const AppCreateDocument = gql`
|
export const AppCreateDocument = gql`
|
||||||
|
|
|
@ -5545,7 +5545,7 @@ export type WarehouseUpdatedFieldPolicy = {
|
||||||
recipient?: FieldPolicy<any> | FieldReadFunction<any>,
|
recipient?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
warehouse?: FieldPolicy<any> | FieldReadFunction<any>
|
warehouse?: FieldPolicy<any> | FieldReadFunction<any>
|
||||||
};
|
};
|
||||||
export type WebhookKeySpecifier = ('id' | 'name' | 'events' | 'syncEvents' | 'asyncEvents' | 'app' | 'eventDeliveries' | 'targetUrl' | 'isActive' | 'secretKey' | 'subscriptionQuery' | WebhookKeySpecifier)[];
|
export type WebhookKeySpecifier = ('id' | 'name' | 'events' | 'syncEvents' | 'asyncEvents' | 'app' | 'eventDeliveries' | 'targetUrl' | 'isActive' | 'secretKey' | 'subscriptionQuery' | 'customHeaders' | WebhookKeySpecifier)[];
|
||||||
export type WebhookFieldPolicy = {
|
export type WebhookFieldPolicy = {
|
||||||
id?: FieldPolicy<any> | FieldReadFunction<any>,
|
id?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
name?: FieldPolicy<any> | FieldReadFunction<any>,
|
name?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
|
@ -5557,7 +5557,8 @@ export type WebhookFieldPolicy = {
|
||||||
targetUrl?: FieldPolicy<any> | FieldReadFunction<any>,
|
targetUrl?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
isActive?: FieldPolicy<any> | FieldReadFunction<any>,
|
isActive?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
secretKey?: FieldPolicy<any> | FieldReadFunction<any>,
|
secretKey?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
subscriptionQuery?: FieldPolicy<any> | FieldReadFunction<any>
|
subscriptionQuery?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||||
|
customHeaders?: FieldPolicy<any> | FieldReadFunction<any>
|
||||||
};
|
};
|
||||||
export type WebhookCreateKeySpecifier = ('webhookErrors' | 'errors' | 'webhook' | WebhookCreateKeySpecifier)[];
|
export type WebhookCreateKeySpecifier = ('webhookErrors' | 'errors' | 'webhook' | WebhookCreateKeySpecifier)[];
|
||||||
export type WebhookCreateFieldPolicy = {
|
export type WebhookCreateFieldPolicy = {
|
||||||
|
|
|
@ -179,6 +179,7 @@ export enum AppErrorCode {
|
||||||
INVALID_PERMISSION = 'INVALID_PERMISSION',
|
INVALID_PERMISSION = 'INVALID_PERMISSION',
|
||||||
INVALID_URL_FORMAT = 'INVALID_URL_FORMAT',
|
INVALID_URL_FORMAT = 'INVALID_URL_FORMAT',
|
||||||
INVALID_MANIFEST_FORMAT = 'INVALID_MANIFEST_FORMAT',
|
INVALID_MANIFEST_FORMAT = 'INVALID_MANIFEST_FORMAT',
|
||||||
|
INVALID_CUSTOM_HEADERS = 'INVALID_CUSTOM_HEADERS',
|
||||||
MANIFEST_URL_CANT_CONNECT = 'MANIFEST_URL_CANT_CONNECT',
|
MANIFEST_URL_CANT_CONNECT = 'MANIFEST_URL_CANT_CONNECT',
|
||||||
NOT_FOUND = 'NOT_FOUND',
|
NOT_FOUND = 'NOT_FOUND',
|
||||||
REQUIRED = 'REQUIRED',
|
REQUIRED = 'REQUIRED',
|
||||||
|
@ -5813,6 +5814,14 @@ export type WebhookCreateInput = {
|
||||||
* Note: this API is currently in Feature Preview and can be subject to changes at later point.
|
* Note: this API is currently in Feature Preview and can be subject to changes at later point.
|
||||||
*/
|
*/
|
||||||
query?: InputMaybe<Scalars['String']>;
|
query?: InputMaybe<Scalars['String']>;
|
||||||
|
/**
|
||||||
|
* Custom headers, which will be added to HTTP request. There is a limitation of 5 headers per webhook and 998 characters per header.Only "X-*" and "Authorization*" keys are allowed.
|
||||||
|
*
|
||||||
|
* Added in Saleor 3.12.
|
||||||
|
*
|
||||||
|
* Note: this API is currently in Feature Preview and can be subject to changes at later point.
|
||||||
|
*/
|
||||||
|
customHeaders?: InputMaybe<Scalars['JSONString']>;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** An enumeration. */
|
/** An enumeration. */
|
||||||
|
@ -5839,7 +5848,8 @@ export enum WebhookErrorCode {
|
||||||
SYNTAX = 'SYNTAX',
|
SYNTAX = 'SYNTAX',
|
||||||
MISSING_SUBSCRIPTION = 'MISSING_SUBSCRIPTION',
|
MISSING_SUBSCRIPTION = 'MISSING_SUBSCRIPTION',
|
||||||
UNABLE_TO_PARSE = 'UNABLE_TO_PARSE',
|
UNABLE_TO_PARSE = 'UNABLE_TO_PARSE',
|
||||||
MISSING_EVENT = 'MISSING_EVENT'
|
MISSING_EVENT = 'MISSING_EVENT',
|
||||||
|
INVALID_CUSTOM_HEADERS = 'INVALID_CUSTOM_HEADERS'
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Enum determining type of webhook. */
|
/** Enum determining type of webhook. */
|
||||||
|
@ -6712,6 +6722,14 @@ export type WebhookUpdateInput = {
|
||||||
* Note: this API is currently in Feature Preview and can be subject to changes at later point.
|
* Note: this API is currently in Feature Preview and can be subject to changes at later point.
|
||||||
*/
|
*/
|
||||||
query?: InputMaybe<Scalars['String']>;
|
query?: InputMaybe<Scalars['String']>;
|
||||||
|
/**
|
||||||
|
* Custom headers, which will be added to HTTP request. There is a limitation of 5 headers per webhook and 998 characters per header.Only "X-*" and "Authorization*" keys are allowed.
|
||||||
|
*
|
||||||
|
* Added in Saleor 3.12.
|
||||||
|
*
|
||||||
|
* Note: this API is currently in Feature Preview and can be subject to changes at later point.
|
||||||
|
*/
|
||||||
|
customHeaders?: InputMaybe<Scalars['JSONString']>;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** An enumeration. */
|
/** An enumeration. */
|
||||||
|
@ -7236,7 +7254,7 @@ export type WebhookCreateMutationVariables = Exact<{
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
|
||||||
export type WebhookCreateMutation = { __typename: 'Mutation', webhookCreate: { __typename: 'WebhookCreate', errors: Array<{ __typename: 'WebhookError', code: WebhookErrorCode, field: string | null, message: string | null }>, webhook: { __typename: 'Webhook', secretKey: string | null, targetUrl: string, subscriptionQuery: string | null, id: string, name: string, isActive: boolean, syncEvents: Array<{ __typename: 'WebhookEventSync', eventType: WebhookEventTypeSyncEnum }>, asyncEvents: Array<{ __typename: 'WebhookEventAsync', eventType: WebhookEventTypeAsyncEnum }>, app: { __typename: 'App', id: string, name: string | null } } | null } | null };
|
export type WebhookCreateMutation = { __typename: 'Mutation', webhookCreate: { __typename: 'WebhookCreate', errors: Array<{ __typename: 'WebhookError', code: WebhookErrorCode, field: string | null, message: string | null }>, webhook: { __typename: 'Webhook', secretKey: string | null, targetUrl: string, subscriptionQuery: string | null, customHeaders: any | null, id: string, name: string, isActive: boolean, syncEvents: Array<{ __typename: 'WebhookEventSync', eventType: WebhookEventTypeSyncEnum }>, asyncEvents: Array<{ __typename: 'WebhookEventAsync', eventType: WebhookEventTypeAsyncEnum }>, app: { __typename: 'App', id: string, name: string | null } } | null } | null };
|
||||||
|
|
||||||
export type WebhookUpdateMutationVariables = Exact<{
|
export type WebhookUpdateMutationVariables = Exact<{
|
||||||
id: Scalars['ID'];
|
id: Scalars['ID'];
|
||||||
|
@ -7244,7 +7262,7 @@ export type WebhookUpdateMutationVariables = Exact<{
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
|
||||||
export type WebhookUpdateMutation = { __typename: 'Mutation', webhookUpdate: { __typename: 'WebhookUpdate', errors: Array<{ __typename: 'WebhookError', code: WebhookErrorCode, field: string | null, message: string | null }>, webhook: { __typename: 'Webhook', secretKey: string | null, targetUrl: string, subscriptionQuery: string | null, id: string, name: string, isActive: boolean, syncEvents: Array<{ __typename: 'WebhookEventSync', eventType: WebhookEventTypeSyncEnum }>, asyncEvents: Array<{ __typename: 'WebhookEventAsync', eventType: WebhookEventTypeAsyncEnum }>, app: { __typename: 'App', id: string, name: string | null } } | null } | null };
|
export type WebhookUpdateMutation = { __typename: 'Mutation', webhookUpdate: { __typename: 'WebhookUpdate', errors: Array<{ __typename: 'WebhookError', code: WebhookErrorCode, field: string | null, message: string | null }>, webhook: { __typename: 'Webhook', secretKey: string | null, targetUrl: string, subscriptionQuery: string | null, customHeaders: any | null, id: string, name: string, isActive: boolean, syncEvents: Array<{ __typename: 'WebhookEventSync', eventType: WebhookEventTypeSyncEnum }>, asyncEvents: Array<{ __typename: 'WebhookEventAsync', eventType: WebhookEventTypeAsyncEnum }>, app: { __typename: 'App', id: string, name: string | null } } | null } | null };
|
||||||
|
|
||||||
export type WebhookDeleteMutationVariables = Exact<{
|
export type WebhookDeleteMutationVariables = Exact<{
|
||||||
id: Scalars['ID'];
|
id: Scalars['ID'];
|
||||||
|
@ -7258,7 +7276,7 @@ export type WebhookDetailsQueryVariables = Exact<{
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
|
||||||
export type WebhookDetailsQuery = { __typename: 'Query', webhook: { __typename: 'Webhook', secretKey: string | null, targetUrl: string, subscriptionQuery: string | null, id: string, name: string, isActive: boolean, syncEvents: Array<{ __typename: 'WebhookEventSync', eventType: WebhookEventTypeSyncEnum }>, asyncEvents: Array<{ __typename: 'WebhookEventAsync', eventType: WebhookEventTypeAsyncEnum }>, app: { __typename: 'App', id: string, name: string | null } } | null };
|
export type WebhookDetailsQuery = { __typename: 'Query', webhook: { __typename: 'Webhook', secretKey: string | null, targetUrl: string, subscriptionQuery: string | null, customHeaders: any | null, id: string, name: string, isActive: boolean, syncEvents: Array<{ __typename: 'WebhookEventSync', eventType: WebhookEventTypeSyncEnum }>, asyncEvents: Array<{ __typename: 'WebhookEventAsync', eventType: WebhookEventTypeAsyncEnum }>, app: { __typename: 'App', id: string, name: string | null } } | null };
|
||||||
|
|
||||||
export type UpdateCustomerMutationVariables = Exact<{
|
export type UpdateCustomerMutationVariables = Exact<{
|
||||||
id: Scalars['ID'];
|
id: Scalars['ID'];
|
||||||
|
@ -7999,7 +8017,7 @@ export type WarehouseDetailsFragment = { __typename: 'Warehouse', isPrivate: boo
|
||||||
|
|
||||||
export type WebhookFragment = { __typename: 'Webhook', id: string, name: string, isActive: boolean, app: { __typename: 'App', id: string, name: string | null } };
|
export type WebhookFragment = { __typename: 'Webhook', id: string, name: string, isActive: boolean, app: { __typename: 'App', id: string, name: string | null } };
|
||||||
|
|
||||||
export type WebhookDetailsFragment = { __typename: 'Webhook', secretKey: string | null, targetUrl: string, subscriptionQuery: string | null, id: string, name: string, isActive: boolean, syncEvents: Array<{ __typename: 'WebhookEventSync', eventType: WebhookEventTypeSyncEnum }>, asyncEvents: Array<{ __typename: 'WebhookEventAsync', eventType: WebhookEventTypeAsyncEnum }>, app: { __typename: 'App', id: string, name: string | null } };
|
export type WebhookDetailsFragment = { __typename: 'Webhook', secretKey: string | null, targetUrl: string, subscriptionQuery: string | null, customHeaders: any | null, id: string, name: string, isActive: boolean, syncEvents: Array<{ __typename: 'WebhookEventSync', eventType: WebhookEventTypeSyncEnum }>, asyncEvents: Array<{ __typename: 'WebhookEventAsync', eventType: WebhookEventTypeAsyncEnum }>, app: { __typename: 'App', id: string, name: string | null } };
|
||||||
|
|
||||||
export type WeightFragment = { __typename: 'Weight', unit: WeightUnitsEnum, value: number };
|
export type WeightFragment = { __typename: 'Weight', unit: WeightUnitsEnum, value: number };
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue