mirror of
https://github.com/omnivore-app/omnivore.git
synced 2026-03-11 08:54:26 +00:00
Merge pull request #1882 from omnivore-app/fix/webhooks
Replace LABEL_CREATED with LABEL_ADDED in webhooks page
This commit is contained in:
commit
3667dc32a7
5 changed files with 103 additions and 42 deletions
|
|
@ -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,
|
||||
|
|
|
|||
9
packages/db/migrations/0111.do.remove_unique_key_on_webhooks.sql
Executable file
9
packages/db/migrations/0111.do.remove_unique_key_on_webhooks.sql
Executable 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;
|
||||
9
packages/db/migrations/0111.undo.remove_unique_key_on_webhooks.sql
Executable file
9
packages/db/migrations/0111.undo.remove_unique_key_on_webhooks.sql
Executable 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;
|
||||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Reference in a new issue