From 071c3799c2261424fe7eb7983e6afc0085089bf6 Mon Sep 17 00:00:00 2001 From: Hongbo Wu Date: Thu, 9 Mar 2023 14:48:24 +0800 Subject: [PATCH 1/4] Change LABEL_CREATED to LABEL_ADDED in webhook events label --- .../web/components/elements/FormElements.tsx | 87 ++++++++++++++----- packages/web/pages/settings/webhooks.tsx | 17 ++-- 2 files changed, 75 insertions(+), 29 deletions(-) diff --git a/packages/web/components/elements/FormElements.tsx b/packages/web/components/elements/FormElements.tsx index cdb98a1ca..088588bda 100644 --- a/packages/web/components/elements/FormElements.tsx +++ b/packages/web/components/elements/FormElements.tsx @@ -4,6 +4,11 @@ import Checkbox from './Checkbox' import { HStack, VStack } from './LayoutPrimitives' import { Label } from '@radix-ui/react-dropdown-menu' +interface FormInputPropsOption { + label: string + value: string +} + export interface FormInputProps { name: string label: string @@ -15,7 +20,7 @@ export interface FormInputProps { hidden?: boolean required?: boolean css?: any - options?: string[] + options?: string[] | FormInputPropsOption[] min?: any } @@ -69,23 +74,49 @@ export function GeneralFormInput(props: FormInputProps): JSX.Element { return ( - {input.options?.map((label, index) => ( - - { - input.value[index] = arg - setInput(input) - props.onChange && - props.onChange( - input.options?.filter((_, i) => input.value[i]) - ) - }} - > - {label} - - ))} + {input.options?.map((option, index) => { + if (typeof option === 'string') { + return ( + + { + input.value[index] = arg + setInput(input) + props.onChange && + props.onChange( + (input.options as string[]).filter( + (_, i) => input.value[i] + ) + ) + }} + > + {option} + + ) + } else { + return ( + + { + input.value[index] = arg + setInput(input) + props.onChange && + props.onChange( + (input.options as FormInputPropsOption[]) + .filter((_, i) => input.value[i]) + .map((option) => option.value) + ) + }} + > + {option.label} + + ) + } + })} ) } else if (props.type === 'select') { @@ -100,11 +131,21 @@ export function GeneralFormInput(props: FormInputProps): JSX.Element { minWidth: '196px', }} > - {input.options?.map((label, index) => ( - - ))} + {input.options?.map((option, index) => { + if (typeof option === 'string') { + return ( + + ) + } else { + return ( + + ) + } + })} ) } else { diff --git a/packages/web/pages/settings/webhooks.tsx b/packages/web/pages/settings/webhooks.tsx index 99d7ac7ba..4769351f9 100644 --- a/packages/web/pages/settings/webhooks.tsx +++ b/packages/web/pages/settings/webhooks.tsx @@ -25,16 +25,21 @@ interface Webhook { updatedAt?: Date } +interface EventTypeOption { + label: string + value: WebhookEvent +} + export default function Webhooks(): JSX.Element { const { webhooks, revalidate } = useGetWebhooksQuery() const [onDeleteId, setOnDeleteId] = useState(null) const [addModelOpen, setAddModelOpen] = useState(false) const [onEditWebhook, setOnEditWebhook] = useState(null) const [url, setUrl] = useState('') - const eventTypeOptions = [ - 'PAGE_CREATED', - 'HIGHLIGHT_CREATED', - 'LABEL_CREATED', + const eventTypeOptions: EventTypeOption[] = [ + { label: 'PAGE_CREATED', value: 'PAGE_CREATED' }, + { label: 'HIGHLIGHT_CREATED', value: 'HIGHLIGHT_CREATED' }, + { label: 'LABEL_ADDED', value: 'LABEL_CREATED' }, ] const [eventTypes, setEventTypes] = useState([]) const [contentType, setContentType] = useState('application/json') @@ -167,7 +172,7 @@ export default function Webhooks(): JSX.Element { }, ]) setUrl('') - setEventTypes(eventTypeOptions as WebhookEvent[]) + setEventTypes(['PAGE_CREATED', 'HIGHLIGHT_CREATED']) setAddModelOpen(true) }} onEdit={(webhook) => { @@ -183,7 +188,7 @@ export default function Webhooks(): JSX.Element { label: 'Event Types', name: 'eventTypes', value: eventTypeOptions.map((option) => - webhook?.eventTypes.includes(option) + webhook?.eventTypes.includes(option.value) ), onChange: setEventTypes, options: eventTypeOptions, From b206f8e6b11876e9a95e56058a00f935346b7a5f Mon Sep 17 00:00:00 2001 From: Hongbo Wu Date: Thu, 9 Mar 2023 14:53:06 +0800 Subject: [PATCH 2/4] Remove unique constraint of user_id and event_types on webhooks table --- .../migrations/0111.do.remove_unique_key_on_webhooks.sql | 9 +++++++++ .../0111.undo.remove_unique_key_on_webhooks.sql | 9 +++++++++ 2 files changed, 18 insertions(+) create mode 100755 packages/db/migrations/0111.do.remove_unique_key_on_webhooks.sql create mode 100755 packages/db/migrations/0111.undo.remove_unique_key_on_webhooks.sql diff --git a/packages/db/migrations/0111.do.remove_unique_key_on_webhooks.sql b/packages/db/migrations/0111.do.remove_unique_key_on_webhooks.sql new file mode 100755 index 000000000..6142b79fe --- /dev/null +++ b/packages/db/migrations/0111.do.remove_unique_key_on_webhooks.sql @@ -0,0 +1,9 @@ +-- Type: DO +-- Name: remove_unique_key_on_webhooks +-- Description: Remove unique constraint of user_id and event_types on webhooks table + +BEGIN; + +ALTER TABLE omnivore.webhooks DROP CONSTRAINT webhooks_user_id_event_types_key; + +COMMIT; diff --git a/packages/db/migrations/0111.undo.remove_unique_key_on_webhooks.sql b/packages/db/migrations/0111.undo.remove_unique_key_on_webhooks.sql new file mode 100755 index 000000000..8a0bd7c21 --- /dev/null +++ b/packages/db/migrations/0111.undo.remove_unique_key_on_webhooks.sql @@ -0,0 +1,9 @@ +-- Type: UNDO +-- Name: remove_unique_key_on_webhooks +-- Description: Remove unique constraint of user_id and event_types on webhooks table + +BEGIN; + +ALTER TABLE omnivore.webhooks ADD CONSTRAINT webhooks_user_id_event_types_key UNIQUE (user_id, event_types); + +COMMIT; From 104da191d265c87ec9816a27e240b5fc4a524102 Mon Sep 17 00:00:00 2001 From: Hongbo Wu Date: Thu, 9 Mar 2023 15:00:06 +0800 Subject: [PATCH 3/4] Allow webhooks with same event types --- packages/api/src/resolvers/webhooks/index.ts | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/packages/api/src/resolvers/webhooks/index.ts b/packages/api/src/resolvers/webhooks/index.ts index 718c7f6fc..5ec23d9fe 100644 --- a/packages/api/src/resolvers/webhooks/index.ts +++ b/packages/api/src/resolvers/webhooks/index.ts @@ -194,20 +194,7 @@ export const setWebhookResolver = authorized< } webhookToSave.id = input.id - } else { - // Create - const existingWebhook = await getRepository(Webhook).findOneBy({ - user: { id: uid }, - eventTypes: `{${input.eventTypes.join(',')}}`, - }) - - if (existingWebhook) { - return { - errorCodes: [SetWebhookErrorCode.AlreadyExists], - } - } } - const webhook = await getRepository(Webhook).save({ user, ...webhookToSave, From 2c10068c2ab2b677d136c056d77de60cceab9e85 Mon Sep 17 00:00:00 2001 From: Hongbo Wu Date: Thu, 9 Mar 2023 15:06:28 +0800 Subject: [PATCH 4/4] Add checking for the emptiness of event types --- packages/web/pages/settings/webhooks.tsx | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/packages/web/pages/settings/webhooks.tsx b/packages/web/pages/settings/webhooks.tsx index 4769351f9..777066ed5 100644 --- a/packages/web/pages/settings/webhooks.tsx +++ b/packages/web/pages/settings/webhooks.tsx @@ -62,6 +62,14 @@ export default function Webhooks(): JSX.Element { applyStoredTheme(false) + function validateEventTypes(eventTypes: WebhookEvent[]): boolean { + if (eventTypes.length > 0) return true + showErrorToast('Please select at least one event type', { + position: 'bottom-right', + }) + return false + } + async function onDelete(id: string): Promise { const result = await deleteWebhookMutation(id) if (result) { @@ -73,6 +81,7 @@ export default function Webhooks(): JSX.Element { } async function onCreate(): Promise { + if (!validateEventTypes(eventTypes)) return const result = await setWebhookMutation({ url, eventTypes }) if (result) { showSuccessToast('Webhook created', { position: 'bottom-right' }) @@ -83,6 +92,7 @@ export default function Webhooks(): JSX.Element { } async function onUpdate(): Promise { + if (!validateEventTypes(eventTypes)) return const result = await setWebhookMutation({ id: onEditWebhook?.id, url,