From fd39ab1b85a9439f3dce5074a5136cb07d800645 Mon Sep 17 00:00:00 2001 From: Krzysztof Bialoglowicz Date: Tue, 15 Oct 2019 12:06:19 +0200 Subject: [PATCH] Add Webhooks list search and fix events any event --- schema.graphql | 9 +- src/types/globalTypes.ts | 7 +- .../WebhookEvents/WebhookEvents.tsx | 2 +- .../WebhooksDetailsPage.tsx | 2 +- .../WebhooksListPage/WebhooksListPage.tsx | 59 +++++++----- src/webhooks/fixtures.ts | 6 -- src/webhooks/index.tsx | 2 +- src/webhooks/queries.ts | 26 ++++-- src/webhooks/types/WebhookCreate.ts | 10 +- src/webhooks/types/WebhookDetails.ts | 14 +-- src/webhooks/types/WebhookFragment.ts | 10 -- src/webhooks/types/WebhookUpdate.ts | 10 +- src/webhooks/types/Webhooks.ts | 11 +-- src/webhooks/types/WebhooksDetailsFragment.ts | 10 -- src/webhooks/urls.ts | 19 +++- src/webhooks/views/WebhooksCreate.tsx | 2 +- src/webhooks/views/WebhooksDetails.tsx | 2 +- src/webhooks/views/WebhooksList.tsx | 92 ++++++++++++++++++- src/webhooks/views/filter.ts | 28 ++++++ 19 files changed, 218 insertions(+), 103 deletions(-) create mode 100644 src/webhooks/views/filter.ts diff --git a/schema.graphql b/schema.graphql index 4dbc36710..4efcdaaa4 100644 --- a/schema.graphql +++ b/schema.graphql @@ -3327,7 +3327,7 @@ type ProductVariantUpdatePrivateMeta { type Query { webhook(id: ID!): Webhook - webhooks(before: String, after: String, first: Int, last: Int): WebhookCountableConnection + webhooks(filter: WebhookFilterInput, before: String, after: String, first: Int, last: Int): WebhookCountableConnection translations(kind: TranslatableKinds!, before: String, after: String, first: Int, last: Int): TranslatableItemConnection shop: Shop shippingZone(id: ID!): ShippingZone @@ -4319,7 +4319,7 @@ type WebhookEvent { } enum WebhookEventTypeEnum { - ALL_EVENTS + ANY_EVENTS ORDER_CREATED ORDER_FULLY_PAID ORDER_UPDATED @@ -4328,6 +4328,11 @@ enum WebhookEventTypeEnum { PRODUCT_CREATED } +input WebhookFilterInput { + search: String + isActive: Boolean +} + type WebhookUpdate { errors: [Error!] webhook: Webhook diff --git a/src/types/globalTypes.ts b/src/types/globalTypes.ts index d3754b168..509193af8 100644 --- a/src/types/globalTypes.ts +++ b/src/types/globalTypes.ts @@ -273,7 +273,7 @@ export enum VoucherTypeEnum { } export enum WebhookEventTypeEnum { - ALL_EVENTS = "ALL_EVENTS", + ANY_EVENTS = "ANY_EVENTS", CUSTOMER_CREATED = "CUSTOMER_CREATED", ORDER_CANCELLED = "ORDER_CANCELLED", ORDER_CREATED = "ORDER_CREATED", @@ -794,6 +794,11 @@ export interface WebhookCreateInput { secretKey?: string | null; } +export interface WebhookFilterInput { + search?: string | null; + isActive?: boolean | null; +} + export interface WebhookUpdateInput { name?: string | null; targetUrl?: string | null; diff --git a/src/webhooks/components/WebhookEvents/WebhookEvents.tsx b/src/webhooks/components/WebhookEvents/WebhookEvents.tsx index 8c42d96cc..3b1d3319b 100644 --- a/src/webhooks/components/WebhookEvents/WebhookEvents.tsx +++ b/src/webhooks/components/WebhookEvents/WebhookEvents.tsx @@ -32,7 +32,7 @@ const WebhookEvents: React.StatelessComponent = ({ target: { name: "events", value: event.target.value - ? WebhookEventTypeEnum.ALL_EVENTS + ? WebhookEventTypeEnum.ANY_EVENTS : data.events } } as any) diff --git a/src/webhooks/components/WebhooksDetailsPage/WebhooksDetailsPage.tsx b/src/webhooks/components/WebhooksDetailsPage/WebhooksDetailsPage.tsx index ac66d82a5..8f03f9142 100644 --- a/src/webhooks/components/WebhooksDetailsPage/WebhooksDetailsPage.tsx +++ b/src/webhooks/components/WebhooksDetailsPage/WebhooksDetailsPage.tsx @@ -62,7 +62,7 @@ const WebhooksDetailsPage: React.StatelessComponent< const intl = useIntl(); const initialForm: FormData = { allEvents: !!maybe(() => webhook.events, []).find( - event => event.eventType === WebhookEventTypeEnum.ALL_EVENTS + event => event.eventType === WebhookEventTypeEnum.ANY_EVENTS ), events: maybe(() => webhook.events, []).map(event => event.eventType), id: maybe(() => webhook.id, null), diff --git a/src/webhooks/components/WebhooksListPage/WebhooksListPage.tsx b/src/webhooks/components/WebhooksListPage/WebhooksListPage.tsx index 27a096ece..f184c04fb 100644 --- a/src/webhooks/components/WebhooksListPage/WebhooksListPage.tsx +++ b/src/webhooks/components/WebhooksListPage/WebhooksListPage.tsx @@ -1,33 +1,39 @@ import Button from "@material-ui/core/Button"; +import Card from "@material-ui/core/Card"; import React from "react"; import { FormattedMessage, useIntl } from "react-intl"; import AppHeader from "@saleor/components/AppHeader"; import Container from "@saleor/components/Container"; import PageHeader from "@saleor/components/PageHeader"; +import SearchBar from "@saleor/components/SearchBar"; import { sectionNames } from "@saleor/intl"; -import { PageListProps } from "@saleor/types"; +import { PageListProps, SearchPageProps, TabPageProps } from "@saleor/types"; import { Webhooks_webhooks_edges_node } from "../../types/Webhooks"; import WebhooksList from "../WebhooksList/WebhooksList"; -export interface WebhooksListPageProps extends PageListProps { +export interface WebhooksListPageProps + extends PageListProps, + SearchPageProps, + TabPageProps { webhooks: Webhooks_webhooks_edges_node[]; onBack: () => void; onRemove: (id: string) => void; } const WebhooksListPage: React.StatelessComponent = ({ - disabled, - settings, + currentTab, + initialSearch, onAdd, + onAll, onBack, - onNextPage, - onPreviousPage, - onRowClick, - onRemove, - onUpdateListSettings, - pageInfo, - webhooks + onSearchChange, + onTabChange, + onTabDelete, + onTabSave, + tabs, + webhooks, + ...listProps }) => { const intl = useIntl(); return ( @@ -43,17 +49,26 @@ const WebhooksListPage: React.StatelessComponent = ({ /> - + + + + ); }; diff --git a/src/webhooks/fixtures.ts b/src/webhooks/fixtures.ts index c92090dd4..4149bdb9c 100644 --- a/src/webhooks/fixtures.ts +++ b/src/webhooks/fixtures.ts @@ -19,31 +19,25 @@ export const services: ServiceList_serviceAccounts_edges_node[] = [ export const webhookList: Webhooks_webhooks_edges_node[] = [ { __typename: "Webhook", - events: [], id: "Jzx123sEt==", isActive: true, name: "Webhook Test", - secretKey: "dsdasdasd_asdas", serviceAccount: { __typename: "ServiceAccount", id: "Jzx123sEt==", name: "Test Account" }, - targetUrl: "http://www.getsaleor.com" }, { __typename: "Webhook", - events: [], id: "Jzx123sEt==", isActive: true, name: "Webhook Test 2", - secretKey: "zxczx_asdas", serviceAccount: { __typename: "ServiceAccount", id: "Jzx1ss23sEt==", name: "Test Account 2" }, - targetUrl: "http://www.getsaleor.com" } ]; export const webhook: Webhook_webhook = { diff --git a/src/webhooks/index.tsx b/src/webhooks/index.tsx index 28fee49ad..ac0497816 100644 --- a/src/webhooks/index.tsx +++ b/src/webhooks/index.tsx @@ -38,7 +38,7 @@ const Component = () => { const intl = useIntl(); return ( <> - + diff --git a/src/webhooks/queries.ts b/src/webhooks/queries.ts index f31a92524..bee136ee3 100644 --- a/src/webhooks/queries.ts +++ b/src/webhooks/queries.ts @@ -8,12 +8,7 @@ export const webhooksFragment = gql` fragment WebhookFragment on Webhook { id name - events { - eventType - } isActive - secretKey - targetUrl serviceAccount { id name @@ -30,8 +25,20 @@ export const webhooksDetailsFragment = gql` const webhooksList = gql` ${webhooksFragment} - query Webhooks($first: Int, $after: String, $last: Int, $before: String) { - webhooks(before: $before, after: $after, first: $first, last: $last) { + query Webhooks( + $first: Int + $after: String + $last: Int + $before: String + $filter: WebhookFilterInput + ) { + webhooks( + first: $first + after: $after + before: $before + last: $last + filter: $filter + ) { edges { node { ...WebhookFragment @@ -55,6 +62,11 @@ const webhooksDetails = gql` query WebhookDetails($id: ID!) { webhook(id: $id) { ...WebhookFragment + events { + eventType + } + secretKey + targetUrl } } `; diff --git a/src/webhooks/types/WebhookCreate.ts b/src/webhooks/types/WebhookCreate.ts index 9874ecbbd..e402b0116 100644 --- a/src/webhooks/types/WebhookCreate.ts +++ b/src/webhooks/types/WebhookCreate.ts @@ -2,7 +2,7 @@ /* eslint-disable */ // This file was automatically generated and should not be edited. -import { WebhookCreateInput, WebhookEventTypeEnum } from "./../../types/globalTypes"; +import { WebhookCreateInput } from "./../../types/globalTypes"; // ==================================================== // GraphQL mutation operation: WebhookCreate @@ -14,11 +14,6 @@ export interface WebhookCreate_webhookCreate_errors { message: string | null; } -export interface WebhookCreate_webhookCreate_webhook_events { - __typename: "WebhookEvent"; - eventType: WebhookEventTypeEnum | null; -} - export interface WebhookCreate_webhookCreate_webhook_serviceAccount { __typename: "ServiceAccount"; id: string; @@ -29,10 +24,7 @@ export interface WebhookCreate_webhookCreate_webhook { __typename: "Webhook"; id: string; name: string | null; - events: (WebhookCreate_webhookCreate_webhook_events | null)[] | null; isActive: boolean; - secretKey: string | null; - targetUrl: string; serviceAccount: WebhookCreate_webhookCreate_webhook_serviceAccount; } diff --git a/src/webhooks/types/WebhookDetails.ts b/src/webhooks/types/WebhookDetails.ts index 657d47ca0..0f68b655e 100644 --- a/src/webhooks/types/WebhookDetails.ts +++ b/src/webhooks/types/WebhookDetails.ts @@ -8,26 +8,26 @@ import { WebhookEventTypeEnum } from "./../../types/globalTypes"; // GraphQL query operation: WebhookDetails // ==================================================== -export interface WebhookDetails_webhook_events { - __typename: "WebhookEvent"; - eventType: WebhookEventTypeEnum | null; -} - export interface WebhookDetails_webhook_serviceAccount { __typename: "ServiceAccount"; id: string; name: string | null; } +export interface WebhookDetails_webhook_events { + __typename: "WebhookEvent"; + eventType: WebhookEventTypeEnum | null; +} + export interface WebhookDetails_webhook { __typename: "Webhook"; id: string; name: string | null; - events: (WebhookDetails_webhook_events | null)[] | null; isActive: boolean; + serviceAccount: WebhookDetails_webhook_serviceAccount; + events: (WebhookDetails_webhook_events | null)[] | null; secretKey: string | null; targetUrl: string; - serviceAccount: WebhookDetails_webhook_serviceAccount; } export interface WebhookDetails { diff --git a/src/webhooks/types/WebhookFragment.ts b/src/webhooks/types/WebhookFragment.ts index fa750b732..ad61edf7b 100644 --- a/src/webhooks/types/WebhookFragment.ts +++ b/src/webhooks/types/WebhookFragment.ts @@ -2,17 +2,10 @@ /* eslint-disable */ // This file was automatically generated and should not be edited. -import { WebhookEventTypeEnum } from "./../../types/globalTypes"; - // ==================================================== // GraphQL fragment: WebhookFragment // ==================================================== -export interface WebhookFragment_events { - __typename: "WebhookEvent"; - eventType: WebhookEventTypeEnum | null; -} - export interface WebhookFragment_serviceAccount { __typename: "ServiceAccount"; id: string; @@ -23,9 +16,6 @@ export interface WebhookFragment { __typename: "Webhook"; id: string; name: string | null; - events: (WebhookFragment_events | null)[] | null; isActive: boolean; - secretKey: string | null; - targetUrl: string; serviceAccount: WebhookFragment_serviceAccount; } diff --git a/src/webhooks/types/WebhookUpdate.ts b/src/webhooks/types/WebhookUpdate.ts index ca174bdfe..b8ce15cf7 100644 --- a/src/webhooks/types/WebhookUpdate.ts +++ b/src/webhooks/types/WebhookUpdate.ts @@ -2,7 +2,7 @@ /* eslint-disable */ // This file was automatically generated and should not be edited. -import { WebhookUpdateInput, WebhookEventTypeEnum } from "./../../types/globalTypes"; +import { WebhookUpdateInput } from "./../../types/globalTypes"; // ==================================================== // GraphQL mutation operation: WebhookUpdate @@ -14,11 +14,6 @@ export interface WebhookUpdate_webhookUpdate_errors { message: string | null; } -export interface WebhookUpdate_webhookUpdate_webhook_events { - __typename: "WebhookEvent"; - eventType: WebhookEventTypeEnum | null; -} - export interface WebhookUpdate_webhookUpdate_webhook_serviceAccount { __typename: "ServiceAccount"; id: string; @@ -29,10 +24,7 @@ export interface WebhookUpdate_webhookUpdate_webhook { __typename: "Webhook"; id: string; name: string | null; - events: (WebhookUpdate_webhookUpdate_webhook_events | null)[] | null; isActive: boolean; - secretKey: string | null; - targetUrl: string; serviceAccount: WebhookUpdate_webhookUpdate_webhook_serviceAccount; } diff --git a/src/webhooks/types/Webhooks.ts b/src/webhooks/types/Webhooks.ts index 95a458f51..d995aa7f5 100644 --- a/src/webhooks/types/Webhooks.ts +++ b/src/webhooks/types/Webhooks.ts @@ -2,17 +2,12 @@ /* eslint-disable */ // This file was automatically generated and should not be edited. -import { WebhookEventTypeEnum } from "./../../types/globalTypes"; +import { WebhookFilterInput } from "./../../types/globalTypes"; // ==================================================== // GraphQL query operation: Webhooks // ==================================================== -export interface Webhooks_webhooks_edges_node_events { - __typename: "WebhookEvent"; - eventType: WebhookEventTypeEnum | null; -} - export interface Webhooks_webhooks_edges_node_serviceAccount { __typename: "ServiceAccount"; id: string; @@ -23,10 +18,7 @@ export interface Webhooks_webhooks_edges_node { __typename: "Webhook"; id: string; name: string | null; - events: (Webhooks_webhooks_edges_node_events | null)[] | null; isActive: boolean; - secretKey: string | null; - targetUrl: string; serviceAccount: Webhooks_webhooks_edges_node_serviceAccount; } @@ -58,4 +50,5 @@ export interface WebhooksVariables { after?: string | null; last?: number | null; before?: string | null; + filter?: WebhookFilterInput | null; } diff --git a/src/webhooks/types/WebhooksDetailsFragment.ts b/src/webhooks/types/WebhooksDetailsFragment.ts index 321a86b04..777f7875c 100644 --- a/src/webhooks/types/WebhooksDetailsFragment.ts +++ b/src/webhooks/types/WebhooksDetailsFragment.ts @@ -2,17 +2,10 @@ /* eslint-disable */ // This file was automatically generated and should not be edited. -import { WebhookEventTypeEnum } from "./../../types/globalTypes"; - // ==================================================== // GraphQL fragment: WebhooksDetailsFragment // ==================================================== -export interface WebhooksDetailsFragment_events { - __typename: "WebhookEvent"; - eventType: WebhookEventTypeEnum | null; -} - export interface WebhooksDetailsFragment_serviceAccount { __typename: "ServiceAccount"; id: string; @@ -23,9 +16,6 @@ export interface WebhooksDetailsFragment { __typename: "Webhook"; id: string; name: string | null; - events: (WebhooksDetailsFragment_events | null)[] | null; isActive: boolean; - secretKey: string | null; - targetUrl: string; serviceAccount: WebhooksDetailsFragment_serviceAccount; } diff --git a/src/webhooks/urls.ts b/src/webhooks/urls.ts index 9edbe362f..7319aa36c 100644 --- a/src/webhooks/urls.ts +++ b/src/webhooks/urls.ts @@ -1,13 +1,26 @@ import { stringify as stringifyQs } from "qs"; import urlJoin from "url-join"; -import { Dialog, Pagination, SingleAction } from "../types"; +import { + ActiveTab, + Dialog, + Filters, + Pagination, + SingleAction, + TabActionDialog +} from "../types"; export const webhooksSection = "/webhooks/"; export const webhooksListPath = webhooksSection; -export type WebhookListUrlDialog = "remove"; -export type WebhooksListUrlQueryParams = Dialog & +export enum WebhookListUrlFiltersEnum { + query = "query" +} +export type WebhookListUrlFilters = Filters; +export type WebhookListUrlDialog = "remove" | TabActionDialog; +export type WebhooksListUrlQueryParams = ActiveTab & + WebhookListUrlFilters & + Dialog & Pagination & SingleAction; export const webhooksListUrl = (params?: WebhooksListUrlQueryParams) => diff --git a/src/webhooks/views/WebhooksCreate.tsx b/src/webhooks/views/WebhooksCreate.tsx index 3b6628ec5..95489131e 100644 --- a/src/webhooks/views/WebhooksCreate.tsx +++ b/src/webhooks/views/WebhooksCreate.tsx @@ -50,7 +50,7 @@ export const WebhooksCreate: React.StatelessComponent< variables: { input: { events: data.allEvents - ? [WebhookEventTypeEnum.ALL_EVENTS] + ? [WebhookEventTypeEnum.ANY_EVENTS] : data.events, isActive: data.isActive, name: data.name, diff --git a/src/webhooks/views/WebhooksDetails.tsx b/src/webhooks/views/WebhooksDetails.tsx index f6511ea98..8e492ead3 100644 --- a/src/webhooks/views/WebhooksDetails.tsx +++ b/src/webhooks/views/WebhooksDetails.tsx @@ -127,7 +127,7 @@ export const WebhooksDetails: React.StatelessComponent< id, input: { events: data.allEvents - ? [WebhookEventTypeEnum.ALL_EVENTS] + ? [WebhookEventTypeEnum.ANY_EVENTS] : data.events, isActive: data.isActive, name: data.name, diff --git a/src/webhooks/views/WebhooksList.tsx b/src/webhooks/views/WebhooksList.tsx index db35f81a0..44ed2bdd5 100644 --- a/src/webhooks/views/WebhooksList.tsx +++ b/src/webhooks/views/WebhooksList.tsx @@ -1,3 +1,7 @@ +import DeleteFilterTabDialog from "@saleor/components/DeleteFilterTabDialog"; +import SaveFilterTabDialog, { + SaveFilterTabDialogFormData +} from "@saleor/components/SaveFilterTabDialog"; import { configurationMenuUrl } from "@saleor/configuration"; import useListSettings from "@saleor/hooks/useListSettings"; import useNavigator from "@saleor/hooks/useNavigator"; @@ -16,12 +20,21 @@ import { useIntl } from "react-intl"; import WebhooksListPage from "../components/WebhooksListPage/WebhooksListPage"; import { TypedWebhookDelete } from "../mutations"; import { TypedWebhooksListQuery } from "../queries"; -import { +import { WebhookListUrlDialog, + WebhookListUrlFilters, webhooksAddUrl, webhooksListUrl, WebhooksListUrlQueryParams, webhooksUrl } from "../urls"; +import { + areFiltersApplied, + deleteFilterTab, + getActiveFilters, + getFilterTabs, + getFilterVariables, + saveFilterTab +} from "./filter"; interface WebhooksListProps { params: WebhooksListUrlQueryParams; @@ -37,8 +50,23 @@ export const WebhooksList: React.StatelessComponent = ({ const { updateListSettings, settings } = useListSettings( ListViews.WEBHOOK_LIST ); - const paginationState = createPaginationState(settings.rowNumber, params); + const tabs = getFilterTabs(); + const currentTab = + params.activeTab === undefined + ? areFiltersApplied(params) + ? tabs.length + 1 + : 0 + : parseInt(params.activeTab, 0); + + const changeFilterField = (filter: WebhookListUrlFilters) => + navigate( + webhooksListUrl({ + ...getActiveFilters(params), + ...filter, + activeTab: undefined + }) + ); const closeModal = () => navigate( webhooksListUrl({ @@ -49,8 +77,45 @@ export const WebhooksList: React.StatelessComponent = ({ true ); + const openModal = (action: WebhookListUrlDialog, id?: string) => + navigate( + webhooksListUrl({ + ...params, + action, + id + }) + ); + + const handleTabChange = (tab: number) => { + navigate( + webhooksListUrl({ + activeTab: tab.toString(), + ...getFilterTabs()[tab - 1].data + }) + ); + }; + + const handleTabDelete = () => { + deleteFilterTab(currentTab); + navigate(webhooksListUrl()); + }; + + const handleTabSave = (data: SaveFilterTabDialogFormData) => { + saveFilterTab(data.name, getActiveFilters(params)); + handleTabChange(tabs.length + 1); + }; + + const paginationState = createPaginationState(settings.rowNumber, params); + const queryVariables = React.useMemo( + () => ({ + ...paginationState, + filter: getFilterVariables(params) + }), + [params] + ); + return ( - + {({ data, loading, refetch }) => { const onWebhookDelete = (data: WebhookDelete) => { if (data.webhookDelete.errors.length === 0) { @@ -95,6 +160,14 @@ export const WebhooksList: React.StatelessComponent = ({ return ( <> changeFilterField({ query })} + onAll={() => navigate(webhooksListUrl())} + onTabChange={handleTabChange} + onTabDelete={() => openModal("delete-search")} + onTabSave={() => openModal("save-search")} + tabs={tabs.map(tab => tab.name)} disabled={loading} settings={settings} webhooks={maybe(() => @@ -122,6 +195,19 @@ export const WebhooksList: React.StatelessComponent = ({ onConfirm={handleRemoveConfirm} open={params.action === "remove"} /> + + tabs[currentTab - 1].name, "...")} + /> ); }} diff --git a/src/webhooks/views/filter.ts b/src/webhooks/views/filter.ts new file mode 100644 index 000000000..1f7365ebc --- /dev/null +++ b/src/webhooks/views/filter.ts @@ -0,0 +1,28 @@ +import { WebhookFilterInput } from "@saleor/types/globalTypes"; +import { createFilterTabUtils, createFilterUtils } from "../../utils/filters"; +import { + WebhookListUrlFilters, + WebhookListUrlFiltersEnum, + WebhooksListUrlQueryParams +} from "../urls"; + +export const WEBHOOK_FILTERS_KEY = "webhookFilters"; + +export function getFilterVariables( + params: WebhookListUrlFilters +): WebhookFilterInput { + return { + search: params.query + }; +} + +export const { + deleteFilterTab, + getFilterTabs, + saveFilterTab +} = createFilterTabUtils(WEBHOOK_FILTERS_KEY); + +export const { areFiltersApplied, getActiveFilters } = createFilterUtils< + WebhooksListUrlQueryParams, + WebhookListUrlFilters +>(WebhookListUrlFiltersEnum);