mirror of
https://github.com/dograh-hq/dograh.git
synced 2026-06-07 07:55:16 +02:00
181 lines
8.1 KiB
TypeScript
181 lines
8.1 KiB
TypeScript
import { Suspense } from 'react';
|
|
|
|
import { getIntegrationsApiV1IntegrationGet } from "@/client/sdk.gen";
|
|
import { getServerAccessToken,getServerAuthProvider } from '@/lib/auth/server';
|
|
import logger from '@/lib/logger';
|
|
|
|
import CreateIntegrationButton from "./CreateIntegrationButton";
|
|
|
|
export const dynamic = 'force-dynamic';
|
|
|
|
// Server component for integration list
|
|
async function IntegrationList() {
|
|
const authProvider = getServerAuthProvider();
|
|
const accessToken = await getServerAccessToken();
|
|
|
|
if (!accessToken) {
|
|
const { redirect } = await import('next/navigation');
|
|
if (authProvider === 'stack') {
|
|
redirect('/');
|
|
} else {
|
|
// For OSS mode, this shouldn't happen as token is auto-generated
|
|
return (
|
|
<div className="text-red-500">
|
|
Authentication required. Please refresh the page.
|
|
</div>
|
|
);
|
|
}
|
|
}
|
|
|
|
try {
|
|
const response = await getIntegrationsApiV1IntegrationGet({
|
|
headers: {
|
|
'Authorization': `Bearer ${accessToken}`,
|
|
},
|
|
});
|
|
|
|
const integrationData = response.data ? (Array.isArray(response.data) ? response.data : [response.data]) : [];
|
|
const integrations = [...integrationData].sort((a, b) =>
|
|
new Date(b.created_at).getTime() - new Date(a.created_at).getTime()
|
|
);
|
|
|
|
if (integrations.length === 0) {
|
|
return (
|
|
<div className="text-center py-8 text-gray-500">
|
|
No integrations found. Create your first integration to get started.
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className="space-y-6">
|
|
<div className="overflow-x-auto">
|
|
<table className="min-w-full bg-white border border-gray-200">
|
|
<thead className="bg-gray-50">
|
|
<tr>
|
|
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
|
Provider
|
|
</th>
|
|
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
|
Channel
|
|
</th>
|
|
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
|
Action
|
|
</th>
|
|
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
|
Created At
|
|
</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody className="bg-white divide-y divide-gray-200">
|
|
{integrations.map((integration) => (
|
|
<tr key={integration.id} className="hover:bg-gray-50">
|
|
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">
|
|
{integration.provider}
|
|
</td>
|
|
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
|
{integration.provider === 'slack' && integration.provider_data ? (integration.provider_data.channel as string) || '-' : '-'}
|
|
</td>
|
|
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
|
{integration.action}
|
|
</td>
|
|
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
|
{new Date(integration.created_at).toLocaleDateString('en-US', {
|
|
year: 'numeric',
|
|
month: 'short',
|
|
day: 'numeric',
|
|
hour: '2-digit',
|
|
minute: '2-digit'
|
|
})}
|
|
</td>
|
|
</tr>
|
|
))}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
);
|
|
} catch (err) {
|
|
logger.error(`Error fetching integrations: ${err}`);
|
|
return (
|
|
<div className="text-red-500 text-center py-8">
|
|
Failed to load Integrations. Please Try Again Later.
|
|
</div>
|
|
);
|
|
}
|
|
}
|
|
|
|
async function PageContent() {
|
|
const integrationList = await IntegrationList();
|
|
|
|
return (
|
|
<div className="container mx-auto px-4 py-8">
|
|
<div className="mb-6">
|
|
<div className="flex justify-between items-center mb-6">
|
|
<h1 className="text-2xl font-bold">Your Integrations</h1>
|
|
<CreateIntegrationButton />
|
|
</div>
|
|
{integrationList}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
function IntegrationsLoading() {
|
|
return (
|
|
<div className="container mx-auto px-4 py-8">
|
|
<div className="mb-6">
|
|
<div className="flex justify-between items-center mb-6">
|
|
<div className="h-8 w-48 bg-gray-200 rounded"></div>
|
|
<div className="h-10 w-32 bg-gray-200 rounded"></div>
|
|
</div>
|
|
<div className="overflow-x-auto">
|
|
<table className="min-w-full bg-white border border-gray-200">
|
|
<thead className="bg-gray-50">
|
|
<tr>
|
|
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
|
Integration ID
|
|
</th>
|
|
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
|
Channel
|
|
</th>
|
|
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
|
Action
|
|
</th>
|
|
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
|
Created At
|
|
</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody className="bg-white divide-y divide-gray-200">
|
|
{Array.from({ length: 5 }, (_, i) => (
|
|
<tr key={i}>
|
|
<td className="px-6 py-4 whitespace-nowrap">
|
|
<div className="h-4 w-32 bg-gray-200 rounded"></div>
|
|
</td>
|
|
<td className="px-6 py-4 whitespace-nowrap">
|
|
<div className="h-4 w-24 bg-gray-200 rounded"></div>
|
|
</td>
|
|
<td className="px-6 py-4 whitespace-nowrap">
|
|
<div className="h-4 w-24 bg-gray-200 rounded"></div>
|
|
</td>
|
|
<td className="px-6 py-4 whitespace-nowrap">
|
|
<div className="h-4 w-24 bg-gray-200 rounded"></div>
|
|
</td>
|
|
</tr>
|
|
))}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export default function IntegrationsPage() {
|
|
return (
|
|
<Suspense fallback={<IntegrationsLoading />}>
|
|
<PageContent />
|
|
</Suspense>
|
|
);
|
|
}
|