0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-03-25 02:31:59 -05:00

Added API call to load integrations into AdminX (#17720)

no issue
This commit is contained in:
Jono M 2023-08-15 12:41:58 +01:00 committed by GitHub
parent 6a721d4dab
commit c9012d5e6d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 96 additions and 10 deletions

View file

@ -0,0 +1,82 @@
import {Meta, createQuery} from '../utils/apiRequests';
// Types
export type IntegrationApiKey = {
id: string;
type: string;
secret: string;
role_id: string;
integration_id: string;
user_id: string | null;
last_seen_at: string | null;
last_seen_version: string | null;
created_at: string;
updated_at: string;
}
export type IntegrationWebhook = {
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 type Integration = {
id: string;
type: 'builtin' | 'core' | 'custom';
name: string;
slug: string;
icon_image: string | null;
description: string;
created_at: string;
updated_at: string;
api_keys: IntegrationApiKey[];
webhooks: IntegrationWebhook[];
}
export interface IntegrationsResponseType {
meta?: Meta;
integrations: Integration[];
}
// Requests
const dataType = 'IntegrationsResponseType';
export const useBrowseIntegrations = createQuery<IntegrationsResponseType>({
dataType,
path: '/integrations/',
defaultSearchParams: {include: 'api_keys,webhooks'}
});
// export const useEditIntegration = createMutation<IntegrationsResponseType, Integration>({
// method: 'PUT',
// path: integration => `/integrations/${integration.id}/`,
// body: integration => ({integrations: [integration]}),
// searchParams: () => ({include: 'roles'}),
// updateQueries: {
// dataType,
// update: () => {} // TODO
// }
// });
// export const useDeleteIntegration = createMutation<DeleteIntegrationResponse, 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)
// })
// }
// });

View file

@ -7,12 +7,13 @@ import TabView from '../../../admin-x-ds/global/TabView';
import useRouting from '../../../hooks/useRouting';
import {ReactComponent as AmpIcon} from '../../../assets/icons/amp.svg';
import {ReactComponent as FirstPromoterIcon} from '../../../assets/icons/firstpromoter.svg';
import {Integration, useBrowseIntegrations} from '../../../api/integrations';
import {ReactComponent as PinturaIcon} from '../../../assets/icons/pintura.svg';
import {ReactComponent as SlackIcon} from '../../../assets/icons/slack.svg';
import {ReactComponent as UnsplashIcon} from '../../../assets/icons/unsplash.svg';
import {ReactComponent as ZapierIcon} from '../../../assets/icons/zapier.svg';
const Integration: 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,
title,
detail,
@ -36,7 +37,7 @@ const BuiltInIntegrations: React.FC = () => {
return (
<List titleSeparator={false}>
<Integration
<IntegrationItem
action={() => {
openModal('integrations/zapier');
}}
@ -44,7 +45,7 @@ const BuiltInIntegrations: React.FC = () => {
icon={<ZapierIcon className='h-8 w-8' />}
title='Zapier' />
<Integration
<IntegrationItem
action={() => {
openModal('integrations/slack');
}}
@ -52,7 +53,7 @@ const BuiltInIntegrations: React.FC = () => {
icon={<SlackIcon className='h-8 w-8' />}
title='Slack' />
<Integration
<IntegrationItem
action={() => {
openModal('integrations/amp');
}}
@ -60,7 +61,7 @@ const BuiltInIntegrations: React.FC = () => {
icon={<AmpIcon className='h-8 w-8' />}
title='AMP' />
<Integration
<IntegrationItem
action={() => {
openModal('integrations/unsplash');
}}
@ -68,7 +69,7 @@ const BuiltInIntegrations: React.FC = () => {
icon={<UnsplashIcon className='h-8 w-8' />}
title='Unsplash' />
<Integration
<IntegrationItem
action={() => {
openModal('integrations/firstpromoter');
}}
@ -76,7 +77,7 @@ const BuiltInIntegrations: React.FC = () => {
icon={<FirstPromoterIcon className='h-8 w-8' />}
title='FirstPromoter' />
<Integration
<IntegrationItem
action={() => {
openModal('integrations/pintura');
}}
@ -87,16 +88,19 @@ const BuiltInIntegrations: React.FC = () => {
);
};
const CustomIntegrations: React.FC = () => {
const CustomIntegrations: React.FC<{integrations: Integration[]}> = ({integrations}) => {
return (
<List>
<Integration action={() => {}} detail='Here we go' title='A custom integration' />
{integrations.map(integration => (
<IntegrationItem action={() => {}} detail={integration.description || 'No description'} title={integration.name} />)
)}
</List>
);
};
const Integrations: React.FC<{ keywords: string[] }> = ({keywords}) => {
const [selectedTab, setSelectedTab] = useState<'built-in' | 'custom'>('built-in');
const {data: {integrations} = {integrations: []}} = useBrowseIntegrations();
const tabs = [
{
@ -107,7 +111,7 @@ const Integrations: React.FC<{ keywords: string[] }> = ({keywords}) => {
{
id: 'custom',
title: 'Custom',
contents: <CustomIntegrations />
contents: <CustomIntegrations integrations={integrations.filter(integration => integration.type === 'custom')} />
}
] as const;