mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-01-20 22:42:53 -05:00
Added remaining API calls for webhooks (#17723)
refs https://github.com/TryGhost/Product/issues/3729
This commit is contained in:
parent
c9012d5e6d
commit
50c36a4c17
3 changed files with 152 additions and 24 deletions
|
@ -1,4 +1,4 @@
|
||||||
import {Meta, createQuery} from '../utils/apiRequests';
|
import {Meta, createMutation, createQuery} from '../utils/apiRequests';
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
|
|
||||||
|
@ -52,31 +52,53 @@ export interface IntegrationsResponseType {
|
||||||
|
|
||||||
const dataType = 'IntegrationsResponseType';
|
const dataType = 'IntegrationsResponseType';
|
||||||
|
|
||||||
|
export const integrationsDataType = dataType;
|
||||||
|
|
||||||
export const useBrowseIntegrations = createQuery<IntegrationsResponseType>({
|
export const useBrowseIntegrations = createQuery<IntegrationsResponseType>({
|
||||||
dataType,
|
dataType,
|
||||||
path: '/integrations/',
|
path: '/integrations/',
|
||||||
defaultSearchParams: {include: 'api_keys,webhooks'}
|
defaultSearchParams: {include: 'api_keys,webhooks'}
|
||||||
});
|
});
|
||||||
|
|
||||||
// export const useEditIntegration = createMutation<IntegrationsResponseType, Integration>({
|
export const useCreateIntegration = createMutation<IntegrationsResponseType, Partial<Integration>>({
|
||||||
// method: 'PUT',
|
method: 'POST',
|
||||||
// path: integration => `/integrations/${integration.id}/`,
|
path: () => '/integrations/',
|
||||||
// body: integration => ({integrations: [integration]}),
|
body: integration => ({integrations: [integration]}),
|
||||||
// searchParams: () => ({include: 'roles'}),
|
searchParams: () => ({include: 'api_keys,webhooks'}),
|
||||||
// updateQueries: {
|
updateQueries: {
|
||||||
// dataType,
|
dataType,
|
||||||
// update: () => {} // TODO
|
update: (newData, currentData) => ({
|
||||||
// }
|
...(currentData as IntegrationsResponseType),
|
||||||
// });
|
integrations: (currentData as IntegrationsResponseType).integrations.concat(newData.integrations)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// export const useDeleteIntegration = createMutation<DeleteIntegrationResponse, string>({
|
export const useEditIntegration = createMutation<IntegrationsResponseType, Integration>({
|
||||||
// method: 'DELETE',
|
method: 'PUT',
|
||||||
// path: id => `/integrations/${id}/`,
|
path: integration => `/integrations/${integration.id}/`,
|
||||||
// updateQueries: {
|
body: integration => ({integrations: [integration]}),
|
||||||
// dataType,
|
searchParams: () => ({include: 'api_keys,webhooks'}),
|
||||||
// update: (_, currentData, id) => ({
|
updateQueries: {
|
||||||
// ...(currentData as IntegrationsResponseType),
|
dataType,
|
||||||
// integrations: (currentData as IntegrationsResponseType).integrations.filter(user => user.id !== id)
|
update: (newData, currentData) => ({
|
||||||
// })
|
...(currentData as IntegrationsResponseType),
|
||||||
// }
|
integrations: (currentData as IntegrationsResponseType).integrations.map((integration) => {
|
||||||
// });
|
const newIntegration = newData.integrations.find(({id}) => id === integration.id);
|
||||||
|
return newIntegration || integration;
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export const useDeleteIntegration = createMutation<unknown, string>({
|
||||||
|
method: 'DELETE',
|
||||||
|
path: id => `/integrations/${id}/`,
|
||||||
|
updateQueries: {
|
||||||
|
dataType,
|
||||||
|
update: (_, currentData, id) => ({
|
||||||
|
...(currentData as IntegrationsResponseType),
|
||||||
|
integrations: (currentData as IntegrationsResponseType).integrations.filter(user => user.id !== id)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
80
apps/admin-x-settings/src/api/webhooks.ts
Normal file
80
apps/admin-x-settings/src/api/webhooks.ts
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
import {IntegrationsResponseType, integrationsDataType} from './integrations';
|
||||||
|
import {Meta, createMutation} from '../utils/apiRequests';
|
||||||
|
|
||||||
|
// Types
|
||||||
|
|
||||||
|
export type Webhook = {
|
||||||
|
id: string;
|
||||||
|
event: string;
|
||||||
|
target_url: string;
|
||||||
|
name: string;
|
||||||
|
secret: string | null;
|
||||||
|
api_version: string;
|
||||||
|
integration_id: string;
|
||||||
|
last_triggered_at: string | null;
|
||||||
|
last_triggered_status: string | null;
|
||||||
|
last_triggered_error: string | null;
|
||||||
|
created_at: string;
|
||||||
|
updated_at: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface WebhooksResponseType {
|
||||||
|
meta?: Meta;
|
||||||
|
webhooks: Webhook[];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Requests
|
||||||
|
|
||||||
|
export const useCreateWebhook = createMutation<WebhooksResponseType, Partial<Webhook>>({
|
||||||
|
method: 'POST',
|
||||||
|
path: () => '/webhooks/',
|
||||||
|
body: webhook => ({webhooks: [webhook]}),
|
||||||
|
updateQueries: {
|
||||||
|
dataType: integrationsDataType,
|
||||||
|
update: (newData, currentData) => ({
|
||||||
|
...(currentData as IntegrationsResponseType),
|
||||||
|
integrations: (currentData as IntegrationsResponseType).integrations.map((integration) => {
|
||||||
|
const webhook = newData.webhooks[0];
|
||||||
|
|
||||||
|
if (webhook.integration_id === integration.id) {
|
||||||
|
return {...integration, webhooks: [...integration.webhooks, webhook]};
|
||||||
|
}
|
||||||
|
|
||||||
|
return integration;
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export const useEditWebhook = createMutation<WebhooksResponseType, Webhook>({
|
||||||
|
method: 'PUT',
|
||||||
|
path: webhook => `/webhooks/${webhook.id}/`,
|
||||||
|
body: webhook => ({webhooks: [webhook]}),
|
||||||
|
updateQueries: {
|
||||||
|
dataType: integrationsDataType,
|
||||||
|
update: (newData, currentData) => ({
|
||||||
|
...(currentData as IntegrationsResponseType),
|
||||||
|
integrations: (currentData as IntegrationsResponseType).integrations.map(integration => ({
|
||||||
|
...integration,
|
||||||
|
webhooks: integration.webhooks.map(webhook => (
|
||||||
|
webhook.id === newData.webhooks[0].id ? newData.webhooks[0] : webhook
|
||||||
|
))
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export const useDeleteWebhook = createMutation<unknown, string>({
|
||||||
|
method: 'DELETE',
|
||||||
|
path: id => `/webhooks/${id}/`,
|
||||||
|
updateQueries: {
|
||||||
|
dataType: integrationsDataType,
|
||||||
|
update: (_, currentData, id) => ({
|
||||||
|
...(currentData as IntegrationsResponseType),
|
||||||
|
integrations: (currentData as IntegrationsResponseType).integrations.map(integration => ({
|
||||||
|
...integration,
|
||||||
|
webhooks: integration.webhooks.filter(webhook => webhook.id !== id)
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
});
|
|
@ -1,17 +1,20 @@
|
||||||
import Button from '../../../admin-x-ds/global/Button';
|
import Button from '../../../admin-x-ds/global/Button';
|
||||||
|
import ConfirmationModal from '../../../admin-x-ds/global/modal/ConfirmationModal';
|
||||||
import List from '../../../admin-x-ds/global/List';
|
import List from '../../../admin-x-ds/global/List';
|
||||||
import ListItem from '../../../admin-x-ds/global/ListItem';
|
import ListItem from '../../../admin-x-ds/global/ListItem';
|
||||||
|
import NiceModal from '@ebay/nice-modal-react';
|
||||||
import React, {useState} from 'react';
|
import React, {useState} from 'react';
|
||||||
import SettingGroup from '../../../admin-x-ds/settings/SettingGroup';
|
import SettingGroup from '../../../admin-x-ds/settings/SettingGroup';
|
||||||
import TabView from '../../../admin-x-ds/global/TabView';
|
import TabView from '../../../admin-x-ds/global/TabView';
|
||||||
import useRouting from '../../../hooks/useRouting';
|
import useRouting from '../../../hooks/useRouting';
|
||||||
import {ReactComponent as AmpIcon} from '../../../assets/icons/amp.svg';
|
import {ReactComponent as AmpIcon} from '../../../assets/icons/amp.svg';
|
||||||
import {ReactComponent as FirstPromoterIcon} from '../../../assets/icons/firstpromoter.svg';
|
import {ReactComponent as FirstPromoterIcon} from '../../../assets/icons/firstpromoter.svg';
|
||||||
import {Integration, useBrowseIntegrations} from '../../../api/integrations';
|
import {Integration, useBrowseIntegrations, useCreateIntegration, useDeleteIntegration, useEditIntegration} from '../../../api/integrations';
|
||||||
import {ReactComponent as PinturaIcon} from '../../../assets/icons/pintura.svg';
|
import {ReactComponent as PinturaIcon} from '../../../assets/icons/pintura.svg';
|
||||||
import {ReactComponent as SlackIcon} from '../../../assets/icons/slack.svg';
|
import {ReactComponent as SlackIcon} from '../../../assets/icons/slack.svg';
|
||||||
import {ReactComponent as UnsplashIcon} from '../../../assets/icons/unsplash.svg';
|
import {ReactComponent as UnsplashIcon} from '../../../assets/icons/unsplash.svg';
|
||||||
import {ReactComponent as ZapierIcon} from '../../../assets/icons/zapier.svg';
|
import {ReactComponent as ZapierIcon} from '../../../assets/icons/zapier.svg';
|
||||||
|
import {useCreateWebhook, useDeleteWebhook, useEditWebhook} from '../../../api/webhooks';
|
||||||
|
|
||||||
const IntegrationItem: React.FC<{icon?: React.ReactNode, title: string, detail:string, action:() => void}> = ({
|
const IntegrationItem: React.FC<{icon?: React.ReactNode, title: string, detail:string, action:() => void}> = ({
|
||||||
icon,
|
icon,
|
||||||
|
@ -89,10 +92,33 @@ const BuiltInIntegrations: React.FC = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const CustomIntegrations: React.FC<{integrations: Integration[]}> = ({integrations}) => {
|
const CustomIntegrations: React.FC<{integrations: Integration[]}> = ({integrations}) => {
|
||||||
|
const {mutateAsync: createIntegration} = useCreateIntegration();
|
||||||
|
const {mutateAsync: editIntegration} = useEditIntegration();
|
||||||
|
const {mutateAsync: deleteIntegration} = useDeleteIntegration();
|
||||||
|
const {mutateAsync: createWebhook} = useCreateWebhook();
|
||||||
|
const {mutateAsync: editWebhook} = useEditWebhook();
|
||||||
|
const {mutateAsync: deleteWebhook} = useDeleteWebhook();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<List>
|
<List>
|
||||||
{integrations.map(integration => (
|
{integrations.map(integration => (
|
||||||
<IntegrationItem action={() => {}} detail={integration.description || 'No description'} title={integration.name} />)
|
<IntegrationItem action={() => {
|
||||||
|
NiceModal.show(ConfirmationModal, {
|
||||||
|
title: 'TEST API actions',
|
||||||
|
prompt: <>
|
||||||
|
Webhooks (will not update until you close and reopen this modal)
|
||||||
|
<pre><code>{JSON.stringify(integration.webhooks)}</code></pre>
|
||||||
|
|
||||||
|
<Button label='Create integration' onClick={() => createIntegration({name: 'Test'})} />
|
||||||
|
<Button label='Update integration' onClick={() => editIntegration({...integration, name: integration.name + '*'})} />
|
||||||
|
<Button label='Delete integration' onClick={() => deleteIntegration(integration.id)} />
|
||||||
|
<Button label='Create webhook' onClick={() => createWebhook({integration_id: integration.id, event: 'post.edited', name: 'Test', target_url: 'https://test.com'})} />
|
||||||
|
<Button label='Update webhook' onClick={() => editWebhook({...integration.webhooks[0], name: integration.webhooks[0].name + '*'})} />
|
||||||
|
<Button label='Delete webhook' onClick={() => deleteWebhook(integration.webhooks[0].id)} />
|
||||||
|
</>,
|
||||||
|
onOk: modal => modal?.remove()
|
||||||
|
});
|
||||||
|
}} detail={integration.description || 'No description'} title={integration.name} />)
|
||||||
)}
|
)}
|
||||||
</List>
|
</List>
|
||||||
);
|
);
|
||||||
|
|
Loading…
Add table
Reference in a new issue