dograh/ui/src/app/integrations/page.tsx
2025-09-09 19:10:18 +05:30

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>
);
}