From 4021b8ec62db16945b4e83c46ee61c8d059b5bf4 Mon Sep 17 00:00:00 2001 From: Krzysztof Bialoglowicz Date: Wed, 9 Oct 2019 08:01:52 +0200 Subject: [PATCH] Add webhook components --- src/intl.ts | 4 + .../WebhookEvents/WebhookEvents.tsx | 57 +++++++ .../components/WebhookEvents/index.ts | 2 + .../components/WebhookInfo/WebhookInfo.tsx | 53 ++++++ src/webhooks/components/WebhookInfo/index.ts | 2 + .../WebhookStatus/WebhookStatus.tsx | 57 +++++++ .../components/WebhookStatus/index.ts | 2 + .../WebhooksDetailsPage.tsx | 78 +++++++++ .../components/WebhooksDetailsPage/index.ts | 2 + .../components/WebhooksList/WebhooksList.tsx | 155 ++++++++++++++++++ src/webhooks/components/WebhooksList/index.ts | 2 + .../WebhooksListPage/WebhooksListPage.tsx | 49 ++++++ .../components/WebhooksListPage/index.ts | 2 + src/webhooks/fixtures.ts | 57 +++++++ src/webhooks/index.tsx | 51 ++++++ src/webhooks/mutations.ts | 60 +++++++ src/webhooks/queries.ts | 62 +++++++ src/webhooks/urls.ts | 16 ++ src/webhooks/views/WebhooksDetails.tsx | 100 +++++++++++ src/webhooks/views/WebhooksList.tsx | 58 +++++++ 20 files changed, 869 insertions(+) create mode 100644 src/webhooks/components/WebhookEvents/WebhookEvents.tsx create mode 100644 src/webhooks/components/WebhookEvents/index.ts create mode 100644 src/webhooks/components/WebhookInfo/WebhookInfo.tsx create mode 100644 src/webhooks/components/WebhookInfo/index.ts create mode 100644 src/webhooks/components/WebhookStatus/WebhookStatus.tsx create mode 100644 src/webhooks/components/WebhookStatus/index.ts create mode 100644 src/webhooks/components/WebhooksDetailsPage/WebhooksDetailsPage.tsx create mode 100644 src/webhooks/components/WebhooksDetailsPage/index.ts create mode 100644 src/webhooks/components/WebhooksList/WebhooksList.tsx create mode 100644 src/webhooks/components/WebhooksList/index.ts create mode 100644 src/webhooks/components/WebhooksListPage/WebhooksListPage.tsx create mode 100644 src/webhooks/components/WebhooksListPage/index.ts create mode 100644 src/webhooks/fixtures.ts create mode 100644 src/webhooks/index.tsx create mode 100644 src/webhooks/mutations.ts create mode 100644 src/webhooks/queries.ts create mode 100644 src/webhooks/urls.ts create mode 100644 src/webhooks/views/WebhooksDetails.tsx create mode 100644 src/webhooks/views/WebhooksList.tsx diff --git a/src/intl.ts b/src/intl.ts index a15b105a1..867bf279c 100644 --- a/src/intl.ts +++ b/src/intl.ts @@ -202,6 +202,10 @@ export const sectionNames = defineMessages({ vouchers: { defaultMessage: "Vouchers", description: "vouchers section name" + }, + webhooks: { + defaultMessage: "Webhooks", + description: "webhooks section name" } }); diff --git a/src/webhooks/components/WebhookEvents/WebhookEvents.tsx b/src/webhooks/components/WebhookEvents/WebhookEvents.tsx new file mode 100644 index 000000000..cf2b168ef --- /dev/null +++ b/src/webhooks/components/WebhookEvents/WebhookEvents.tsx @@ -0,0 +1,57 @@ +import Card from "@material-ui/core/Card"; +import CardContent from "@material-ui/core/CardContent"; +import TextField from "@material-ui/core/TextField"; +import makeStyles from "@material-ui/styles/makeStyles"; +import CardTitle from "@saleor/components/CardTitle"; +import ControlledCheckbox from "@saleor/components/ControlledCheckbox"; +import { FormErrors } from "@saleor/types"; +import { ConfigurationTypeFieldEnum } from "@saleor/types/globalTypes"; +import React from "react"; +import { useIntl } from "react-intl"; + +import { FormData } from "../WebhookDetailsPage"; + +interface WebhookEventsProps { + data: FormData; + errors: FormErrors<"name" | "configuration">; + disabled: boolean; + onChange: (event: React.ChangeEvent) => void; + fields: Array<{ + name: string; + type: ConfigurationTypeFieldEnum | null; + value: string; + helpText: string | null; + label: string | null; + }>; +} + +const useStyles = makeStyles(() => ({ + item: { + paddingBottom: 10, + paddingTop: 10 + } +})); + +const WebhookEvents: React.StatelessComponent = ({ + data, + disabled, + errors, + onChange, + fields +}) => { + const classes = useStyles({}); + const intl = useIntl(); + return ( + + + + + ); +}; +WebhookEvents.displayName = "WebhookEvents"; +export default WebhookEvents; diff --git a/src/webhooks/components/WebhookEvents/index.ts b/src/webhooks/components/WebhookEvents/index.ts new file mode 100644 index 000000000..a756533f2 --- /dev/null +++ b/src/webhooks/components/WebhookEvents/index.ts @@ -0,0 +1,2 @@ +export { default } from "./WebhookEvents; +export * from "./WebhookEvents; diff --git a/src/webhooks/components/WebhookInfo/WebhookInfo.tsx b/src/webhooks/components/WebhookInfo/WebhookInfo.tsx new file mode 100644 index 000000000..64ac09fda --- /dev/null +++ b/src/webhooks/components/WebhookInfo/WebhookInfo.tsx @@ -0,0 +1,53 @@ +import Card from "@material-ui/core/Card"; +import CardContent from "@material-ui/core/CardContent"; +import Typography from "@material-ui/core/Typography"; +import makeStyles from "@material-ui/styles/makeStyles"; +import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; + +import CardTitle from "@saleor/components/CardTitle"; +import ControlledCheckbox from "@saleor/components/ControlledCheckbox"; +import FormSpacer from "@saleor/components/FormSpacer"; +import Hr from "@saleor/components/Hr"; +import { commonMessages } from "@saleor/intl"; +import { FormData } from "../WebhooksDetailsPage"; + +interface WebhookInfoProps { + data: FormData; + description: string; + name: string; + onChange: (event: React.ChangeEvent) => void; +} + +const useStyles = makeStyles(() => ({ + status: { + paddingTop: 20 + }, + title: { + fontSize: 14, + paddingTop: 10 + } +})); + +const WebhookInfo: React.StatelessComponent = ({ + data, + description, + name, + onChange +}) => { + const classes = useStyles({}); + const intl = useIntl(); + return ( + + + + + ); +}; +WebhookInfo.displayName = "WebhookInfo"; +export default WebhookInfo; diff --git a/src/webhooks/components/WebhookInfo/index.ts b/src/webhooks/components/WebhookInfo/index.ts new file mode 100644 index 000000000..8c767a478 --- /dev/null +++ b/src/webhooks/components/WebhookInfo/index.ts @@ -0,0 +1,2 @@ +export { default } from "./WebhookInfoo"; +export * from "./WebhookInfoo"; diff --git a/src/webhooks/components/WebhookStatus/WebhookStatus.tsx b/src/webhooks/components/WebhookStatus/WebhookStatus.tsx new file mode 100644 index 000000000..f674f9539 --- /dev/null +++ b/src/webhooks/components/WebhookStatus/WebhookStatus.tsx @@ -0,0 +1,57 @@ +import Card from "@material-ui/core/Card"; +import CardContent from "@material-ui/core/CardContent"; +import TextField from "@material-ui/core/TextField"; +import makeStyles from "@material-ui/styles/makeStyles"; +import CardTitle from "@saleor/components/CardTitle"; +import ControlledCheckbox from "@saleor/components/ControlledCheckbox"; +import { FormErrors } from "@saleor/types"; +import { ConfigurationTypeFieldEnum } from "@saleor/types/globalTypes"; +import React from "react"; +import { useIntl } from "react-intl"; + +import { FormData } from "../WebhooksDetailsPage"; + +interface WebhookStatusProps { + data: FormData; + errors: FormErrors<"name" | "configuration">; + disabled: boolean; + onChange: (event: React.ChangeEvent) => void; + fields: Array<{ + name: string; + type: ConfigurationTypeFieldEnum | null; + value: string; + helpText: string | null; + label: string | null; + }>; +} + +const useStyles = makeStyles(() => ({ + item: { + paddingBottom: 10, + paddingTop: 10 + } +})); + +const WebhookStatus: React.StatelessComponent = ({ + data, + disabled, + errors, + onChange, + fields +}) => { + const classes = useStyles({}); + const intl = useIntl(); + return ( + + + + + ); +}; +WebhookStatus.displayName = "WebhookStatus"; +export default WebhookStatus; diff --git a/src/webhooks/components/WebhookStatus/index.ts b/src/webhooks/components/WebhookStatus/index.ts new file mode 100644 index 000000000..87e64e1c3 --- /dev/null +++ b/src/webhooks/components/WebhookStatus/index.ts @@ -0,0 +1,2 @@ +export { default } from "./WebhookStatus; +export * from "./WebhookStatus; diff --git a/src/webhooks/components/WebhooksDetailsPage/WebhooksDetailsPage.tsx b/src/webhooks/components/WebhooksDetailsPage/WebhooksDetailsPage.tsx new file mode 100644 index 000000000..0a9f722d0 --- /dev/null +++ b/src/webhooks/components/WebhooksDetailsPage/WebhooksDetailsPage.tsx @@ -0,0 +1,78 @@ +import Typography from "@material-ui/core/Typography"; +import AppHeader from "@saleor/components/AppHeader"; +import { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton"; +import Container from "@saleor/components/Container"; +import Form from "@saleor/components/Form"; +import Grid from "@saleor/components/Grid"; +import PageHeader from "@saleor/components/PageHeader"; +import SaveButtonBar from "@saleor/components/SaveButtonBar"; +import { sectionNames } from "@saleor/intl"; +import { maybe } from "@saleor/misc"; +import { UserError } from "@saleor/types"; +import { ConfigurationItemInput } from "@saleor/types/globalTypes"; +import React from "react"; +import { useIntl } from "react-intl"; + +import { Plugin_plugin } from "../../types/Plugin"; +import WebhookInfo from "../WebhookInfo"; +import WebhookEvents from "../WebhookEvents"; + +export interface FormData { + active: boolean; + configuration: ConfigurationItemInput[]; +} + +export interface WebhooksDetailsPageProps { + disabled: boolean; + errors: UserError[]; + plugin: Plugin_plugin; + saveButtonBarState: ConfirmButtonTransitionState; + onBack: () => void; + onSubmit: (data: FormData) => void; +} + +const WebhooksDetailsPage: React.StatelessComponent< + WebhooksDetailsPageProps +> = ({ disabled, errors, plugin, saveButtonBarState, onBack, onSubmit }) => { + const intl = useIntl(); + const initialForm: FormData = { + active: maybe(() => plugin.active, false), + configuration: maybe(() => plugin.configuration, []) + }; + + return ( +
+ {({ data, errors, hasChanged, submit, set, triggerChange }) => { + return ( + + + {intl.formatMessage(sectionNames.plugins)} + + plugin.name, "...") + } + )} + /> + +
+
+ +
+ ); + }} +
+ ); +}; +WebhooksDetailsPage.displayName = "WebhooksDetailsPage"; +export default WebhooksDetailsPage; diff --git a/src/webhooks/components/WebhooksDetailsPage/index.ts b/src/webhooks/components/WebhooksDetailsPage/index.ts new file mode 100644 index 000000000..c09cb2fe6 --- /dev/null +++ b/src/webhooks/components/WebhooksDetailsPage/index.ts @@ -0,0 +1,2 @@ +export { default } from "./WebhooksDetailsPage"; +export * from "./WebhooksDetailsPage"; diff --git a/src/webhooks/components/WebhooksList/WebhooksList.tsx b/src/webhooks/components/WebhooksList/WebhooksList.tsx new file mode 100644 index 000000000..19643d3e6 --- /dev/null +++ b/src/webhooks/components/WebhooksList/WebhooksList.tsx @@ -0,0 +1,155 @@ +import Card from "@material-ui/core/Card"; +import { + createStyles, + Theme, + withStyles, + WithStyles +} from "@material-ui/core/styles"; +import Table from "@material-ui/core/Table"; +import TableBody from "@material-ui/core/TableBody"; +import TableCell from "@material-ui/core/TableCell"; +import TableFooter from "@material-ui/core/TableFooter"; +import TableHead from "@material-ui/core/TableHead"; +import TableRow from "@material-ui/core/TableRow"; +import EditIcon from "@material-ui/icons/Edit"; +import React from "react"; +import { useIntl } from "react-intl"; + +import Skeleton from "@saleor/components/Skeleton"; +import StatusLabel from "@saleor/components/StatusLabel"; +import TablePagination from "@saleor/components/TablePagination"; +import { translateBoolean } from "@saleor/intl"; +import { maybe, renderCollection } from "@saleor/misc"; +import { ListProps } from "@saleor/types"; +import { Plugins_plugins_edges_node } from "../../types/Plugins"; + +export interface WebhooksListProps extends ListProps { + webhooks: Plugins_plugins_edges_node[]; +} + +const styles = (theme: Theme) => + createStyles({ + [theme.breakpoints.up("lg")]: { + colAction: { + "& svg": { + color: theme.palette.primary.main + }, + textAlign: "right" + }, + colActive: {}, + colName: {} + }, + colAction: {}, + colActive: {}, + colName: {}, + link: { + cursor: "pointer" + } + }); + +const numberOfColumns = 4; + +const WebhooksList = withStyles(styles, { name: "PluginList" })( + ({ + classes, + settings, + webhooks, + disabled, + onNextPage, + pageInfo, + onRowClick, + onUpdateListSettings, + onPreviousPage + }: WebhooksListProps & WithStyles) => { + const intl = useIntl(); + return ( + + + + + {intl.formatMessage({ + defaultMessage: "Name", + description: "webhook name" + })} + + + {intl.formatMessage({ + defaultMessage: "Service Account", + description: "webhook service account" + })} + + + {intl.formatMessage({ + defaultMessage: "Action", + description: "user action bar" + })} + + + + + + + + + {renderCollection( + webhooks, + webhook => { + return ( + // + // + // {maybe(() => plugin.name, )} + // + // + // {maybe( + // () => ( + // + // ), + // + // )} + // + // + //
+ // + //
+ //
+ //
+ ); + }, + () => ( + + + {intl.formatMessage({ + defaultMessage: "No plugins found" + })} + + + ) + )} +
+
+
+ ); + } +); +WebhooksList.displayName = "WebhooksList"; +export default WebhooksList; diff --git a/src/webhooks/components/WebhooksList/index.ts b/src/webhooks/components/WebhooksList/index.ts new file mode 100644 index 000000000..b3d7c9391 --- /dev/null +++ b/src/webhooks/components/WebhooksList/index.ts @@ -0,0 +1,2 @@ +export { default } from "./WebhooksListt"; +export * from "./WebhooksListt"; diff --git a/src/webhooks/components/WebhooksListPage/WebhooksListPage.tsx b/src/webhooks/components/WebhooksListPage/WebhooksListPage.tsx new file mode 100644 index 000000000..20ced1671 --- /dev/null +++ b/src/webhooks/components/WebhooksListPage/WebhooksListPage.tsx @@ -0,0 +1,49 @@ +import React from "react"; +import { useIntl } from "react-intl"; + +import AppHeader from "@saleor/components/AppHeader"; +import Container from "@saleor/components/Container"; +import PageHeader from "@saleor/components/PageHeader"; +import { sectionNames } from "@saleor/intl"; +import { PageListProps } from "@saleor/types"; +import { Plugins_plugins_edges_node } from "../../types/Plugins"; +import WebhooksList from "../WebhooksList/WebhooksList"; + +export interface WebhooksListPageProps extends PageListProps { + plugins: Plugins_plugins_edges_node[]; + onBack: () => void; +} + +const WebhooksListPage: React.StatelessComponent = ({ + disabled, + settings, + onBack, + onNextPage, + onPreviousPage, + onRowClick, + onUpdateListSettings, + pageInfo, + webhooks +}) => { + const intl = useIntl(); + return ( + + + {intl.formatMessage(sectionNames.configuration)} + + + + + ); +}; +WebhooksListPage.displayName = "WebhooksListPage"; +export default WebhooksListPage; diff --git a/src/webhooks/components/WebhooksListPage/index.ts b/src/webhooks/components/WebhooksListPage/index.ts new file mode 100644 index 000000000..68f52d520 --- /dev/null +++ b/src/webhooks/components/WebhooksListPage/index.ts @@ -0,0 +1,2 @@ +export { default } from "./WebhooksListPage"; +export * from "./WebhooksListPage"; diff --git a/src/webhooks/fixtures.ts b/src/webhooks/fixtures.ts new file mode 100644 index 000000000..4da3ce27b --- /dev/null +++ b/src/webhooks/fixtures.ts @@ -0,0 +1,57 @@ +import { ConfigurationTypeFieldEnum } from "@saleor/types/globalTypes"; +import { Plugin_plugin } from "./types/Plugin"; +import { Plugins_plugins_edges_node } from "./types/Plugins"; + +export const pluginList: Plugins_plugins_edges_node[] = [ + { + __typename: "Plugin", + active: true, + description: + "Lorem ipsum dolor sit amet enim. Etiam ullamcorper. Suspendisse a pellentesque dui, non felis. Maecenas malesuada elit lectus felis, malesuada ultricies. Curabitur et ligula. Ut molestie a, ultricies porta urna. Vestibulum commodo volutpat a, convallis ac, laoreet enim. Phasellus fermentum in, dolor. Pellentesque facilisis. Nulla imperdiet sit amet magna.", + id: "Jzx123sEt==", + name: "Avalara" + }, + { + __typename: "Plugin", + active: false, + description: + "Lorem ipsum dolor sit amet enim. Etiam ullamcorper. Suspendisse a pellentesque dui, non felis. Maecenas malesuada elit lectus felis, malesuada ultricies. Curabitur et ligula. Ut molestie a, ultricies porta urna. Vestibulum commodo volutpat a, convallis ac, laoreet enim. Phasellus fermentum in, dolor. Pellentesque facilisis. Nulla imperdiet sit amet magna.", + id: "Jzx123sEt==", + name: "VatLayer" + } +]; +export const plugin: Plugin_plugin = { + __typename: "Plugin", + active: true, + configuration: [ + { + __typename: "ConfigurationItem", + helpText: "Provide user or account details", + label: "Username or account", + name: "Username or account", + type: ConfigurationTypeFieldEnum.STRING, + value: "" + }, + { + __typename: "ConfigurationItem", + helpText: "Provide password or license details", + label: "Password or license", + name: "Password or license", + type: ConfigurationTypeFieldEnum.STRING, + value: "" + }, + { + __typename: "ConfigurationItem", + helpText: "Determines if Saleor should use Avatax sandbox API.", + label: "Use sandbox", + name: "Use sandbox", + type: ConfigurationTypeFieldEnum.BOOLEAN, + value: "true" + } + ], + description: + "Lorem ipsum dolor sit amet enim. Etiam ullamcorper. Suspendisse a pellentesque dui, non felis. Maecenas malesuada elit lectus felis, malesuada ultricies. Curabitur et ligula. Ut molestie a, ultricies porta urna. Vestibulum commodo volutpat a, convallis ac, laoreet enim. Phasellus fermentum in, dolor. Pellentesque facilisis. Nulla imperdiet sit amet magna.", + + id: "UGx1Z2luQ29uZmlndXJhdGlvbjoy", + name: "Username or account" +}; diff --git a/src/webhooks/index.tsx b/src/webhooks/index.tsx new file mode 100644 index 000000000..e6fe869ed --- /dev/null +++ b/src/webhooks/index.tsx @@ -0,0 +1,51 @@ +import { parse as parseQs } from "qs"; +import React from "react"; +import { useIntl } from "react-intl"; +import { Route, RouteComponentProps, Switch } from "react-router-dom"; + +import { sectionNames } from "@saleor/intl"; +import { WindowTitle } from "../components/WindowTitle"; +import { + webhooksListPath, + WebhooksListUrlQueryParams, + webhooksPath +} from "./urls"; +import PluginsDetailsComponent from "./views/WebhooksDetails"; +import PluginsListComponent from "./views/WebhooksList"; + +const PluginList: React.StatelessComponent> = ({ + location +}) => { + const qs = parseQs(location.search.substr(1)); + const params: WebhooksListUrlQueryParams = qs; + return ; +}; + +const PageDetails: React.StatelessComponent> = ({ + match +}) => { + const qs = parseQs(location.search.substr(1)); + const params: WebhooksListUrlQueryParams = qs; + + return ( + + ); +}; + +const Component = () => { + const intl = useIntl(); + return ( + <> + + + + + + + ); +}; + +export default Component; diff --git a/src/webhooks/mutations.ts b/src/webhooks/mutations.ts new file mode 100644 index 000000000..e766cd8f4 --- /dev/null +++ b/src/webhooks/mutations.ts @@ -0,0 +1,60 @@ +import gql from "graphql-tag"; + +import { TypedMutation } from "../mutations"; +import { webhooksDetailsFragment } from "./queries"; +import { WebhookCreate, WebhookCreateVariables } from "./types/WebhookCreate"; +import { WebhookDelete, WebhookDeleteVariables } from "./types/WebhookDelete"; +import { WebhookUpdate, WebhookUpdateVariables } from "./types/WebhookUpdate"; + +const webhookCreate = gql` + ${webhooksDetailsFragment} + mutation WebhookCreate($input: WebhookCreateInput!) { + WebhookCreate(input: $input) { + errors { + field + message + } + webhook { + ...WebhooksDetailsFragment + } + } + } +`; +export const TypedWebhookCreate = TypedMutation< + WebhookCreate, + WebhookCreateVariables +>(webhookCreate); + +const webhookUpdate = gql` + ${webhooksDetailsFragment} + mutation WebhookUpdate($id: ID!, $input: WebhookUpdateInput!) { + WebhookUpdate(id: $id, input: $input) { + errors { + field + message + } + webhook { + ...WebhooksDetailsFragment + } + } + } +`; +export const TypedWebhookUpdate = TypedMutation< + WebhookUpdate, + WebhookUpdateVariables +>(webhookUpdate); + +const WebhookDelete = gql` + mutation WebhookDelete($id: ID!) { + WebhookDelete(id: $id) { + errors { + field + message + } + } + } +`; +export const TypedWebhookDelete = TypedMutation< + WebhookDelete, + WebhookDeleteVariables +>(WebhookDelete); diff --git a/src/webhooks/queries.ts b/src/webhooks/queries.ts new file mode 100644 index 000000000..f24e185ee --- /dev/null +++ b/src/webhooks/queries.ts @@ -0,0 +1,62 @@ +import gql from "graphql-tag"; + +import { TypedQuery } from "../queries"; +import { Webhook, WebhookVariables } from "./types/Webhook"; +import { Webhooks, WebhooksVariables } from "./types/Webhooks"; + +export const webhooksFragment = gql` + fragment WebhookFragment on Webhook { + id + events { + eventType + } + isActive + secretKey + targetUrl + serviceAccount { + id + name + } + } +`; + +export const webhooksDetailsFragment = gql` + ${webhooksFragment} + fragment WebhooksDetailsFragment on Webhook { + ...WebhooksFragment + } +`; + +const webhooksList = gql` + ${webhooksFragment} + query Webhooks($first: Int, $after: String, $last: Int, $before: String) { + webhooks(before: $before, after: $after, first: $first, last: $last) { + edges { + node { + ...WebhooksFragment + } + } + pageInfo { + hasPreviousPage + hasNextPage + startCursor + endCursor + } + } + } +`; +export const TypedWebhooksListQuery = TypedQuery( + webhooksList +); + +const webhooksDetails = gql` + ${webhooksFragment} + query Webhook($id: ID!) { + webhook(id: $id) { + ...WebhooksFragment + } + } +`; +export const TypedWebhooksDetailsQuery = TypedQuery( + webhooksDetails +); diff --git a/src/webhooks/urls.ts b/src/webhooks/urls.ts new file mode 100644 index 000000000..f12eae33a --- /dev/null +++ b/src/webhooks/urls.ts @@ -0,0 +1,16 @@ +import { stringify as stringifyQs } from "qs"; +import urlJoin from "url-join"; + +import { Pagination, SingleAction } from "../types"; + +export const webhooksSection = "/webhooks/"; + +export const webhooksListPath = webhooksSection; +export type WebhooksListUrlQueryParams = Pagination & SingleAction; +export const webhooksListUrl = (params?: WebhooksListUrlQueryParams) => + webhooksPath + "?" + stringifyQs(params); + +export const webhooksPath = (id: string) => urlJoin(webhooksSection, id); +export type WebhooksUrlQueryParams = SingleAction; +export const webhooksUrl = (id: string, params?: WebhooksUrlQueryParams) => + webhooksPath(encodeURIComponent(id)) + "?" + stringifyQs(params); diff --git a/src/webhooks/views/WebhooksDetails.tsx b/src/webhooks/views/WebhooksDetails.tsx new file mode 100644 index 000000000..a6e8d6cd9 --- /dev/null +++ b/src/webhooks/views/WebhooksDetails.tsx @@ -0,0 +1,100 @@ +import { WindowTitle } from "@saleor/components/WindowTitle"; +import useNavigator from "@saleor/hooks/useNavigator"; +import useNotifier from "@saleor/hooks/useNotifier"; +import React from "react"; +import { useIntl } from "react-intl"; + +import { getMutationState, maybe } from "../../misc"; +import WebhooksDetailsPage from "../components/WebhooksDetailsPage"; +import { TypedPluginUpdate } from "../mutations"; +import { TypedPluginsDetailsQuery } from "../queries"; +import { pluginsListUrl, PluginsListUrlQueryParams } from "../urls"; + +export interface PluginsDetailsProps { + id: string; + params: PluginsListUrlQueryParams; +} + +export const PluginsDetails: React.StatelessComponent = ({ + id +}) => { + const navigate = useNavigator(); + const notify = useNotifier(); + const intl = useIntl(); + + return ( + + {(pluginUpdate, pluginUpdateOpts) => ( + + {PluginDetails => { + const formTransitionState = getMutationState( + pluginUpdateOpts.called, + pluginUpdateOpts.loading, + maybe(() => pluginUpdateOpts.data.pluginUpdate.errors) + ); + + const formErrors = maybe( + () => pluginUpdateOpts.data.pluginUpdate.errors, + [] + ); + + if (formErrors.length) { + formErrors.map(error => { + notify({ + text: error.message + }); + }); + } else { + if (pluginUpdateOpts.data) { + notify({ + text: intl.formatMessage({ + defaultMessage: "Succesfully updated plugin settings", + description: "plugin success message" + }) + }); + } + } + + return ( + <> + PluginDetails.data.plugin.name)} + /> + PluginDetails.data.plugin)} + onBack={() => navigate(pluginsListUrl())} + onSubmit={formData => { + const configurationInput = + formData.configuration && + formData.configuration.map(item => { + return { + name: item.name, + value: item.value.toString() + }; + }); + pluginUpdate({ + variables: { + id, + input: { + active: formData.active, + configuration: configurationInput + ? configurationInput + : null + } + } + }); + }} + /> + + ); + }} + + )} + + ); +}; +PluginsDetails.displayName = "PluginsDetails"; +export default PluginsDetails; diff --git a/src/webhooks/views/WebhooksList.tsx b/src/webhooks/views/WebhooksList.tsx new file mode 100644 index 000000000..67d7793d7 --- /dev/null +++ b/src/webhooks/views/WebhooksList.tsx @@ -0,0 +1,58 @@ +import { configurationMenuUrl } from "@saleor/configuration"; +import useListSettings from "@saleor/hooks/useListSettings"; +import useNavigator from "@saleor/hooks/useNavigator"; +import usePaginator, { + createPaginationState +} from "@saleor/hooks/usePaginator"; +import { maybe } from "@saleor/misc"; +import { ListViews } from "@saleor/types"; +import React from "react"; + +import WebhooksListPage from "../components/WebhooksListPage/PluginsListPage"; +import { TypedWebhooksListQuery } from "../queries"; +import { WebhooksListUrlQueryParams, webhooksUrl } from "../urls"; + +interface PluginsListProps { + params: WebhooksListUrlQueryParams; +} + +export const PluginsList: React.StatelessComponent = ({ + params +}) => { + const navigate = useNavigator(); + const paginate = usePaginator(); + const { updateListSettings, settings } = useListSettings( + ListViews.PLUGINS_LIST + ); + const paginationState = createPaginationState(settings.rowNumber, params); + + return ( + + {({ data, loading }) => { + const { loadNextPage, loadPreviousPage, pageInfo } = paginate( + maybe(() => data.plugins.pageInfo), + paginationState, + params + ); + return ( + <> + data.plugins.edges.map(edge => edge.node))} + pageInfo={pageInfo} + onAdd={() => navigate(configurationMenuUrl)} + onBack={() => navigate(configurationMenuUrl)} + onNextPage={loadNextPage} + onPreviousPage={loadPreviousPage} + onUpdateListSettings={updateListSettings} + onRowClick={id => () => navigate(webhooksUrl(id))} + /> + + ); + }} + + ); +}; + +export default PluginsList;