Fix strict null checks in webhooks (#2678)

* Fix strict null errors in webhooks

* Disable strict null checks

* Update snapshots

* Add migration comment in tsconfig

* Fix 404 on loading

* Fix loading case
This commit is contained in:
Michał Droń 2022-12-01 14:42:18 +01:00 committed by GitHub
parent c46ec15e14
commit e900f2e1df
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 385 additions and 874 deletions

View file

@ -1,6 +1,6 @@
import { gql } from "@apollo/client";
export const webhooksFragment = gql`
export const webhookFragment = gql`
fragment Webhook on Webhook {
id
name
@ -12,8 +12,16 @@ export const webhooksFragment = gql`
}
`;
export const webhooksDetailsFragment = gql`
fragment WebhooksDetails on Webhook {
export const webhookDetailsFragment = gql`
fragment WebhookDetails on Webhook {
...Webhook
syncEvents {
eventType
}
asyncEvents {
eventType
}
secretKey
targetUrl
}
`;

View file

@ -2784,9 +2784,17 @@ export const WarehouseDetailsFragmentDoc = gql`
}
${WarehouseWithShippingFragmentDoc}
${AddressFragmentDoc}`;
export const WebhooksDetailsFragmentDoc = gql`
fragment WebhooksDetails on Webhook {
export const WebhookDetailsFragmentDoc = gql`
fragment WebhookDetails on Webhook {
...Webhook
syncEvents {
eventType
}
asyncEvents {
eventType
}
secretKey
targetUrl
}
${WebhookFragmentDoc}`;
export const AppCreateDocument = gql`
@ -16970,12 +16978,12 @@ export const WebhookCreateDocument = gql`
...WebhookError
}
webhook {
...WebhooksDetails
...WebhookDetails
}
}
}
${WebhookErrorFragmentDoc}
${WebhooksDetailsFragmentDoc}`;
${WebhookDetailsFragmentDoc}`;
export type WebhookCreateMutationFn = Apollo.MutationFunction<Types.WebhookCreateMutation, Types.WebhookCreateMutationVariables>;
/**
@ -17009,12 +17017,12 @@ export const WebhookUpdateDocument = gql`
...WebhookError
}
webhook {
...WebhooksDetails
...WebhookDetails
}
}
}
${WebhookErrorFragmentDoc}
${WebhooksDetailsFragmentDoc}`;
${WebhookDetailsFragmentDoc}`;
export type WebhookUpdateMutationFn = Apollo.MutationFunction<Types.WebhookUpdateMutation, Types.WebhookUpdateMutationVariables>;
/**
@ -17080,18 +17088,10 @@ export type WebhookDeleteMutationOptions = Apollo.BaseMutationOptions<Types.Webh
export const WebhookDetailsDocument = gql`
query WebhookDetails($id: ID!) {
webhook(id: $id) {
...Webhook
syncEvents {
eventType
}
asyncEvents {
eventType
}
secretKey
targetUrl
...WebhookDetails
}
}
${WebhookFragmentDoc}`;
${WebhookDetailsFragmentDoc}`;
/**
* __useWebhookDetailsQuery__

View file

@ -7451,7 +7451,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 WebhooksDetailsFragment = { __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, 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 };
@ -9410,7 +9410,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', id: string, name: string, isActive: boolean, 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, 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<{
id: Scalars['ID'];
@ -9418,7 +9418,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', id: string, name: string, isActive: boolean, 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, 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<{
id: Scalars['ID'];

File diff suppressed because it is too large Load diff

View file

@ -7,7 +7,7 @@ import { MultiAutocompleteChoiceType } from "./components/MultiAutocompleteSelec
export interface UserError {
field: string | null;
message?: string;
message?: string | null;
}
export interface DialogProps {

View file

@ -2,7 +2,7 @@ import { getAppDefaultUri, getAppMountUri } from "@saleor/config";
import isArray from "lodash/isArray";
import { stringify } from "qs";
export function stringifyQs(params: {}, arrayFormat?: string): string {
export function stringifyQs(params: unknown, arrayFormat?: string): string {
return stringify(params, {
arrayFormat: arrayFormat || "indices",
});

View file

@ -17,4 +17,6 @@ const props: WebhookDeleteDialogProps = {
storiesOf("Views / Apps / Webhooks / Delete webhook", module)
.addDecorator(Decorator)
.add("default", () => <WebhookDeleteDialog {...props} />)
.add("unnamed webhook", () => <WebhookDeleteDialog {...props} name={null} />);
.add("unnamed webhook", () => (
<WebhookDeleteDialog {...props} name={undefined} />
));

View file

@ -1,14 +1,13 @@
import { DialogContentText } from "@material-ui/core";
import ActionDialog from "@saleor/components/ActionDialog";
import { ConfirmButtonTransitionState } from "@saleor/macaw-ui";
import { getStringOrPlaceholder } from "@saleor/misc";
import React from "react";
import { FormattedMessage, useIntl } from "react-intl";
export interface WebhookDeleteDialogProps {
confirmButtonState: ConfirmButtonTransitionState;
open: boolean;
name: string;
name?: string;
onClose: () => void;
onConfirm: () => void;
}
@ -36,7 +35,7 @@ const WebhookDeleteDialog: React.FC<WebhookDeleteDialogProps> = ({
variant="delete"
>
<DialogContentText>
{["", null].includes(name) ? (
{!name ? (
<FormattedMessage
id="hS+ZjH"
defaultMessage="Are you sure you want to delete this webhook?"
@ -48,7 +47,7 @@ const WebhookDeleteDialog: React.FC<WebhookDeleteDialogProps> = ({
defaultMessage="Are you sure you want to delete {name}?"
description="delete webhook"
values={{
name: <strong>{getStringOrPlaceholder(name)}</strong>,
name: <strong>{name}</strong>,
}}
/>
)}

View file

@ -21,9 +21,6 @@ storiesOf("Views / Apps / Webhooks / Webhook details", module)
.addDecorator(Decorator)
.add("default", () => <WebhookDetailsPage {...props} />)
.add("undefined", () => <WebhookDetailsPage {...props} webhook={undefined} />)
.add("unnamed", () => (
<WebhookDetailsPage {...props} webhook={{ ...webhook, name: null }} />
))
.add("loading", () => (
<WebhookDetailsPage {...props} webhook={undefined} disabled={true} />
))

View file

@ -7,7 +7,7 @@ import Grid from "@saleor/components/Grid";
import PageHeader from "@saleor/components/PageHeader";
import Savebar from "@saleor/components/Savebar";
import {
WebhookDetailsQuery,
WebhookDetailsFragment,
WebhookErrorFragment,
WebhookEventTypeAsyncEnum,
WebhookEventTypeSyncEnum,
@ -44,7 +44,7 @@ export interface WebhookDetailsPageProps {
appId: string;
disabled: boolean;
errors: WebhookErrorFragment[];
webhook?: WebhookDetailsQuery["webhook"];
webhook?: WebhookDetailsFragment | null;
saveButtonBarState: ConfirmButtonTransitionState;
onSubmit: (data: FormData) => void;
}

View file

@ -1,4 +1,4 @@
import { customAppUrl } from "@saleor/apps/urls";
import { appsListUrl, customAppUrl } from "@saleor/apps/urls";
import { Backlink } from "@saleor/components/Backlink";
import Container from "@saleor/components/Container";
import Form from "@saleor/components/Form";
@ -7,7 +7,7 @@ import Grid from "@saleor/components/Grid";
import PageHeader from "@saleor/components/PageHeader";
import Savebar from "@saleor/components/Savebar";
import {
WebhookDetailsQuery,
WebhookDetailsFragment,
WebhookErrorFragment,
WebhookEventTypeAsyncEnum,
WebhookEventTypeSyncEnum,
@ -44,7 +44,7 @@ export interface WebhookDetailsPageProps {
appName: string;
disabled: boolean;
errors: WebhookErrorFragment[];
webhook?: WebhookDetailsQuery["webhook"];
webhook?: WebhookDetailsFragment;
saveButtonBarState: ConfirmButtonTransitionState;
onSubmit: (data: WebhookFormData) => SubmitPromise<any[]>;
}
@ -69,6 +69,8 @@ const WebhookDetailsPage: React.FC<WebhookDetailsPageProps> = ({
targetUrl: webhook?.targetUrl || "",
};
const backUrl = webhook ? customAppUrl(webhook.app.id) : appsListUrl();
return (
<Form confirmLeave initial={initialForm} onSubmit={onSubmit}>
{({ data, submit, change }) => {
@ -93,7 +95,7 @@ const WebhookDetailsPage: React.FC<WebhookDetailsPageProps> = ({
return (
<Container>
<Backlink href={customAppUrl(webhook?.app?.id)}>{appName}</Backlink>
<Backlink href={backUrl}>{appName}</Backlink>
<PageHeader title={getHeaderTitle(intl, webhook)} />
<Grid>
<div>
@ -123,7 +125,7 @@ const WebhookDetailsPage: React.FC<WebhookDetailsPageProps> = ({
<Savebar
disabled={disabled}
state={saveButtonBarState}
onCancel={() => navigate(customAppUrl(webhook.app.id))}
onCancel={() => navigate(backUrl)}
onSubmit={submit}
/>
</Container>

View file

@ -6,7 +6,7 @@ import Skeleton from "@saleor/components/Skeleton";
import { TableButtonWrapper } from "@saleor/components/TableButtonWrapper/TableButtonWrapper";
import TableCellHeader from "@saleor/components/TableCellHeader";
import TableRowLink from "@saleor/components/TableRowLink";
import { AppQuery } from "@saleor/graphql";
import { WebhookFragment } from "@saleor/graphql";
import {
commonMessages,
commonStatusMessages,
@ -24,7 +24,7 @@ import { messages } from "./messages";
import { useStyles } from "./styles";
export interface WebhooksListProps {
webhooks: AppQuery["app"]["webhooks"];
webhooks: WebhookFragment[];
onRemove: (id: string) => void;
createHref?: string;
}

View file

@ -1,6 +1,6 @@
import { WebhookDetailsQuery } from "@saleor/graphql";
import { WebhookDetailsFragment } from "@saleor/graphql";
export const webhook: WebhookDetailsQuery["webhook"] = {
export const webhook: WebhookDetailsFragment = {
__typename: "Webhook",
app: {
__typename: "App",

View file

@ -7,7 +7,7 @@ export const webhookCreate = gql`
...WebhookError
}
webhook {
...WebhooksDetails
...WebhookDetails
}
}
}
@ -20,7 +20,7 @@ export const webhookUpdate = gql`
...WebhookError
}
webhook {
...WebhooksDetails
...WebhookDetails
}
}
}

View file

@ -3,15 +3,7 @@ import { gql } from "@apollo/client";
export const webhooksDetails = gql`
query WebhookDetails($id: ID!) {
webhook(id: $id) {
...Webhook
syncEvents {
eventType
}
asyncEvents {
eventType
}
secretKey
targetUrl
...WebhookDetails
}
}
`;

View file

@ -7,8 +7,8 @@ import {
} from "@saleor/graphql";
import React from "react";
export function isUnnamed(webhook: WebhookFragment): boolean {
return ["", null].includes(webhook?.name);
export function isUnnamed(webhook: WebhookFragment | undefined): boolean {
return !webhook?.name;
}
type WebhookEventType = WebhookEventTypeSyncEnum | WebhookEventTypeAsyncEnum;

View file

@ -27,12 +27,13 @@ export const WebhooksCreate: React.FC<WebhooksCreateProps> = ({ id }) => {
const [webhookCreate, webhookCreateOpts] = useWebhookCreateMutation({
onCompleted: data => {
if (data.webhookCreate.errors.length === 0) {
const webhook = data.webhookCreate?.webhook;
if (webhook && data?.webhookCreate?.errors.length === 0) {
notify({
status: "success",
text: intl.formatMessage(commonMessages.savedChanges),
});
navigate(webhookUrl(data.webhookCreate.webhook.id));
navigate(webhookUrl(webhook.id));
}
},
});
@ -68,10 +69,10 @@ export const WebhooksCreate: React.FC<WebhooksCreateProps> = ({ id }) => {
})}
/>
<WebhookDetailsPage
appName={data?.app?.name}
appName={data?.app?.name ?? ""}
appId={id}
disabled={false}
errors={webhookCreateOpts.data?.webhookCreate.errors || []}
errors={webhookCreateOpts.data?.webhookCreate?.errors ?? []}
onSubmit={handleSubmit}
saveButtonBarState={webhookCreateOpts.status}
/>

View file

@ -1,4 +1,4 @@
import { customAppUrl } from "@saleor/apps/urls";
import { appsListUrl } from "@saleor/apps/urls";
import NotFoundPage from "@saleor/components/NotFoundPage";
import { WindowTitle } from "@saleor/components/WindowTitle";
import {
@ -31,7 +31,7 @@ export const WebhooksDetails: React.FC<WebhooksDetailsProps> = ({ id }) => {
const errors = data.webhookUpdate?.errors;
const webhook = data.webhookUpdate?.webhook;
if (errors.length === 0 && webhook) {
if (errors?.length === 0 && webhook) {
notify({
status: "success",
text: intl.formatMessage(commonMessages.savedChanges),
@ -41,11 +41,7 @@ export const WebhooksDetails: React.FC<WebhooksDetailsProps> = ({ id }) => {
});
const webhook = webhookDetails?.webhook;
const formErrors = webhookUpdateOpts.data?.webhookUpdate.errors || [];
if (webhook === null) {
return <NotFoundPage backHref={customAppUrl(webhook.app.id)} />;
}
const formErrors = webhookUpdateOpts.data?.webhookUpdate?.errors || [];
const handleSubmit = (data: WebhookFormData) =>
extractMutationErrors(
@ -67,6 +63,9 @@ export const WebhooksDetails: React.FC<WebhooksDetailsProps> = ({ id }) => {
},
}),
);
if (!webhook && !loading) {
return <NotFoundPage backHref={appsListUrl()} />;
}
return (
<>
@ -74,8 +73,8 @@ export const WebhooksDetails: React.FC<WebhooksDetailsProps> = ({ id }) => {
title={getStringOrPlaceholder(webhookDetails?.webhook?.name)}
/>
<WebhookDetailsPage
appId={webhook?.app?.id}
appName={webhook?.app?.name}
appId={webhook?.app.id ?? ""}
appName={webhook?.app.name ?? ""}
disabled={loading}
errors={formErrors}
saveButtonBarState={webhookUpdateOpts.status}

View file

@ -1,6 +1,9 @@
{
"compilerOptions": {
"baseUrl": ".",
// Migration to strict null checks is in progress.
// https://github.com/saleor/saleor-dashboard/issues/2584
"strictNullChecks": false,
"esModuleInterop": true,
"jsx": "react",
"lib": ["es2017", "dom", "esnext"],