Merge pull request #1882 from omnivore-app/fix/webhooks

Replace LABEL_CREATED with LABEL_ADDED in webhooks page
This commit is contained in:
Hongbo Wu 2023-03-09 17:08:43 +08:00 committed by GitHub
commit 3667dc32a7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 103 additions and 42 deletions

View file

@ -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,

View file

@ -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;

View file

@ -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;

View file

@ -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 (
<VStack>
{input.options?.map((label, index) => (
<HStack key={index} alignment="center">
<Checkbox
key={index}
checked={input.value[index]}
setChecked={(arg) => {
input.value[index] = arg
setInput(input)
props.onChange &&
props.onChange(
input.options?.filter((_, i) => input.value[i])
)
}}
></Checkbox>
<StyledLabel>{label}</StyledLabel>
</HStack>
))}
{input.options?.map((option, index) => {
if (typeof option === 'string') {
return (
<HStack key={index} alignment="center">
<Checkbox
key={index}
checked={input.value[index]}
setChecked={(arg) => {
input.value[index] = arg
setInput(input)
props.onChange &&
props.onChange(
(input.options as string[]).filter(
(_, i) => input.value[i]
)
)
}}
></Checkbox>
<StyledLabel>{option}</StyledLabel>
</HStack>
)
} else {
return (
<HStack key={index} alignment="center">
<Checkbox
key={index}
checked={input.value[index]}
setChecked={(arg) => {
input.value[index] = arg
setInput(input)
props.onChange &&
props.onChange(
(input.options as FormInputPropsOption[])
.filter((_, i) => input.value[i])
.map((option) => option.value)
)
}}
></Checkbox>
<StyledLabel>{option.label}</StyledLabel>
</HStack>
)
}
})}
</VStack>
)
} else if (props.type === 'select') {
@ -100,11 +131,21 @@ export function GeneralFormInput(props: FormInputProps): JSX.Element {
minWidth: '196px',
}}
>
{input.options?.map((label, index) => (
<option key={index} value={label}>
{label}
</option>
))}
{input.options?.map((option, index) => {
if (typeof option === 'string') {
return (
<option key={index} value={option}>
{option}
</option>
)
} else {
return (
<option key={index} value={option.value}>
{option.label}
</option>
)
}
})}
</select>
)
} else {

View file

@ -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<string | null>(null)
const [addModelOpen, setAddModelOpen] = useState(false)
const [onEditWebhook, setOnEditWebhook] = useState<Webhook | null>(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<WebhookEvent[]>([])
const [contentType, setContentType] = useState('application/json')
@ -57,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<void> {
const result = await deleteWebhookMutation(id)
if (result) {
@ -68,6 +81,7 @@ export default function Webhooks(): JSX.Element {
}
async function onCreate(): Promise<void> {
if (!validateEventTypes(eventTypes)) return
const result = await setWebhookMutation({ url, eventTypes })
if (result) {
showSuccessToast('Webhook created', { position: 'bottom-right' })
@ -78,6 +92,7 @@ export default function Webhooks(): JSX.Element {
}
async function onUpdate(): Promise<void> {
if (!validateEventTypes(eventTypes)) return
const result = await setWebhookMutation({
id: onEditWebhook?.id,
url,
@ -167,7 +182,7 @@ export default function Webhooks(): JSX.Element {
},
])
setUrl('')
setEventTypes(eventTypeOptions as WebhookEvent[])
setEventTypes(['PAGE_CREATED', 'HIGHLIGHT_CREATED'])
setAddModelOpen(true)
}}
onEdit={(webhook) => {
@ -183,7 +198,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,