feat(data-provider-tool): add enhanced UI components for data provider tool views

This commit is contained in:
Zanyar 2025-07-30 15:01:02 +08:00
parent d129c808d5
commit 88dc5dfc44
2 changed files with 197 additions and 191 deletions

View File

@ -19,6 +19,7 @@ import { cn } from '@/lib/utils';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Badge } from '@/components/ui/badge';
import { extractDataProviderEndpointsData } from './_utils';
import { ScrollArea } from '@/components/ui/scroll-area';
const PROVIDER_CONFIG = {
'linkedin': {
@ -147,113 +148,115 @@ export function DataProviderEndpointsToolView({
</div>
</div>
) : (
<div className="p-4 space-y-6">
<div className="flex items-center gap-4 p-4 bg-zinc-50 dark:bg-zinc-900/50 rounded-lg border border-zinc-200 dark:border-zinc-800">
<div className={cn(
"w-12 h-12 rounded-lg flex items-center justify-center shadow-sm border-2",
`bg-gradient-to-br ${providerConfig.color}`,
"border-white/20"
)}>
<IconComponent className="h-6 w-6 text-white drop-shadow-sm" />
</div>
<div className="flex-1">
<h3 className="text-lg font-semibold text-zinc-900 dark:text-zinc-100">
{providerConfig.name}
</h3>
<p className="text-sm text-zinc-500 dark:text-zinc-400">
{endpointCount > 0 ? `${endpointCount} endpoints loaded and ready` : 'Endpoints loaded and ready'}
</p>
</div>
<Badge
variant="secondary"
className={cn(
"text-xs font-medium",
actualIsSuccess
? "bg-emerald-50 text-emerald-700 border-emerald-200 dark:bg-emerald-900/20 dark:text-emerald-300 dark:border-emerald-800"
: "bg-red-50 text-red-700 border-red-200 dark:bg-red-900/20 dark:text-red-300 dark:border-red-800"
)}
>
{actualIsSuccess ? (
<CheckCircle className="h-3 w-3 mr-1" />
) : (
<AlertTriangle className="h-3 w-3 mr-1" />
)}
{actualIsSuccess ? 'Connected' : 'Failed'}
</Badge>
</div>
<div className="space-y-4">
<div className="flex items-center gap-2 text-sm font-medium text-zinc-700 dark:text-zinc-300">
<Database className="h-4 w-4" />
<span>Provider Status</span>
<ChevronRight className="h-3 w-3 text-zinc-400" />
</div>
<div className="grid gap-3">
<div className="flex items-center justify-between p-3 bg-white dark:bg-zinc-900 rounded-lg border border-zinc-200 dark:border-zinc-800">
<div className="flex items-center gap-3">
<div className="w-2 h-2 rounded-full bg-emerald-500"></div>
<span className="text-sm font-medium text-zinc-900 dark:text-zinc-100">
Connection Status
</span>
</div>
<Badge
variant="secondary"
className={cn(
"text-xs font-medium",
actualIsSuccess
? "bg-emerald-50 text-emerald-700 border-emerald-200 dark:bg-emerald-900/20 dark:text-emerald-300 dark:border-emerald-800"
: "bg-red-50 text-red-700 border-red-200 dark:bg-red-900/20 dark:text-red-300 dark:border-red-800"
)}
>
{actualIsSuccess ? (
<CheckCircle className="h-3 w-3 mr-1" />
) : (
<AlertTriangle className="h-3 w-3 mr-1" />
)}
{actualIsSuccess ? 'Active' : 'Inactive'}
</Badge>
<ScrollArea className="h-full w-full">
<div className="p-4 space-y-6">
<div className="flex items-center gap-4 p-4 bg-zinc-50 dark:bg-zinc-900/50 rounded-lg border border-zinc-200 dark:border-zinc-800">
<div className={cn(
"w-12 h-12 rounded-lg flex items-center justify-center shadow-sm border-2",
`bg-gradient-to-br ${providerConfig.color}`,
"border-white/20"
)}>
<IconComponent className="h-6 w-6 text-white drop-shadow-sm" />
</div>
<div className="flex items-center justify-between p-3 bg-white dark:bg-zinc-900 rounded-lg border border-zinc-200 dark:border-zinc-800">
<div className="flex items-center gap-3">
<div className="w-2 h-2 rounded-full bg-blue-500"></div>
<span className="text-sm font-medium text-zinc-900 dark:text-zinc-100">
Endpoints Available
</span>
</div>
<Badge variant="outline" className="text-xs">
{endpointCount > 0 ? `${endpointCount} endpoints` : 'Ready'}
</Badge>
</div>
<div className="flex items-center justify-between p-3 bg-white dark:bg-zinc-900 rounded-lg border border-zinc-200 dark:border-zinc-800">
<div className="flex items-center gap-3">
<div className="w-2 h-2 rounded-full bg-purple-500"></div>
<span className="text-sm font-medium text-zinc-900 dark:text-zinc-100">
Data Provider
</span>
</div>
<span className="text-sm text-zinc-600 dark:text-zinc-400 font-mono">
{serviceName || 'linkedin'}
</span>
</div>
</div>
{actualIsSuccess && (
<div className="p-4 bg-emerald-50 dark:bg-emerald-900/10 rounded-lg border border-emerald-200 dark:border-emerald-800/50">
<div className="flex items-center gap-2 mb-2">
<CheckCircle className="h-4 w-4 text-emerald-600 dark:text-emerald-400/70" />
<span className="text-sm font-medium text-emerald-800 dark:text-emerald-300/70">
Provider Ready
</span>
</div>
<p className="text-xs text-emerald-700 dark:text-emerald-300/70">
Data provider endpoints have been loaded successfully and are ready to process requests.
<div className="flex-1">
<h3 className="text-lg font-semibold text-zinc-900 dark:text-zinc-100">
{providerConfig.name}
</h3>
<p className="text-sm text-zinc-500 dark:text-zinc-400">
{endpointCount > 0 ? `${endpointCount} endpoints loaded and ready` : 'Endpoints loaded and ready'}
</p>
</div>
)}
<Badge
variant="secondary"
className={cn(
"text-xs font-medium",
actualIsSuccess
? "bg-emerald-50 text-emerald-700 border-emerald-200 dark:bg-emerald-900/20 dark:text-emerald-300 dark:border-emerald-800"
: "bg-red-50 text-red-700 border-red-200 dark:bg-red-900/20 dark:text-red-300 dark:border-red-800"
)}
>
{actualIsSuccess ? (
<CheckCircle className="h-3 w-3 mr-1" />
) : (
<AlertTriangle className="h-3 w-3 mr-1" />
)}
{actualIsSuccess ? 'Connected' : 'Failed'}
</Badge>
</div>
<div className="space-y-4">
<div className="flex items-center gap-2 text-sm font-medium text-zinc-700 dark:text-zinc-300">
<Database className="h-4 w-4" />
<span>Provider Status</span>
<ChevronRight className="h-3 w-3 text-zinc-400" />
</div>
<div className="grid gap-3">
<div className="flex items-center justify-between p-3 bg-white dark:bg-zinc-900 rounded-lg border border-zinc-200 dark:border-zinc-800">
<div className="flex items-center gap-3">
<div className="w-2 h-2 rounded-full bg-emerald-500"></div>
<span className="text-sm font-medium text-zinc-900 dark:text-zinc-100">
Connection Status
</span>
</div>
<Badge
variant="secondary"
className={cn(
"text-xs font-medium",
actualIsSuccess
? "bg-emerald-50 text-emerald-700 border-emerald-200 dark:bg-emerald-900/20 dark:text-emerald-300 dark:border-emerald-800"
: "bg-red-50 text-red-700 border-red-200 dark:bg-red-900/20 dark:text-red-300 dark:border-red-800"
)}
>
{actualIsSuccess ? (
<CheckCircle className="h-3 w-3 mr-1" />
) : (
<AlertTriangle className="h-3 w-3 mr-1" />
)}
{actualIsSuccess ? 'Active' : 'Inactive'}
</Badge>
</div>
<div className="flex items-center justify-between p-3 bg-white dark:bg-zinc-900 rounded-lg border border-zinc-200 dark:border-zinc-800">
<div className="flex items-center gap-3">
<div className="w-2 h-2 rounded-full bg-blue-500"></div>
<span className="text-sm font-medium text-zinc-900 dark:text-zinc-100">
Endpoints Available
</span>
</div>
<Badge variant="outline" className="text-xs">
{endpointCount > 0 ? `${endpointCount} endpoints` : 'Ready'}
</Badge>
</div>
<div className="flex items-center justify-between p-3 bg-white dark:bg-zinc-900 rounded-lg border border-zinc-200 dark:border-zinc-800">
<div className="flex items-center gap-3">
<div className="w-2 h-2 rounded-full bg-purple-500"></div>
<span className="text-sm font-medium text-zinc-900 dark:text-zinc-100">
Data Provider
</span>
</div>
<span className="text-sm text-zinc-600 dark:text-zinc-400 font-mono">
{serviceName || 'linkedin'}
</span>
</div>
</div>
{actualIsSuccess && (
<div className="p-4 bg-emerald-50 dark:bg-emerald-900/10 rounded-lg border border-emerald-200 dark:border-emerald-800/50">
<div className="flex items-center gap-2 mb-2">
<CheckCircle className="h-4 w-4 text-emerald-600 dark:text-emerald-400/70" />
<span className="text-sm font-medium text-emerald-800 dark:text-emerald-300/70">
Provider Ready
</span>
</div>
<p className="text-xs text-emerald-700 dark:text-emerald-300/70">
Data provider endpoints have been loaded successfully and are ready to process requests.
</p>
</div>
)}
</div>
</div>
</div>
</ScrollArea>
)}
</CardContent>

View File

@ -21,6 +21,7 @@ import { cn } from '@/lib/utils';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Badge } from '@/components/ui/badge';
import { extractDataProviderCallData } from './_utils';
import { ScrollArea } from '@/components/ui/scroll-area';
const PROVIDER_CONFIG = {
'linkedin': {
@ -158,102 +159,104 @@ export function ExecuteDataProviderCallToolView({
</div>
</div>
) : (
<div className="p-4 space-y-6">
<div className="flex items-center gap-4 p-4 bg-zinc-50 dark:bg-zinc-900/50 rounded-lg border border-zinc-200 dark:border-zinc-800">
<div className={cn(
"w-12 h-12 rounded-lg flex items-center justify-center shadow-sm border-2",
`bg-gradient-to-br ${providerConfig.color}`,
"border-white/20"
)}>
<IconComponent className="h-6 w-6 text-white drop-shadow-sm" />
</div>
<ScrollArea className="h-full w-full">
<div className="p-4 space-y-6">
<div className="flex items-center gap-4 p-4 bg-zinc-50 dark:bg-zinc-900/50 rounded-lg border border-zinc-200 dark:border-zinc-800">
<div className={cn(
"w-12 h-12 rounded-lg flex items-center justify-center shadow-sm border-2",
`bg-gradient-to-br ${providerConfig.color}`,
"border-white/20"
)}>
<IconComponent className="h-6 w-6 text-white drop-shadow-sm" />
</div>
<div className="flex-1">
<h3 className="text-lg font-semibold text-zinc-900 dark:text-zinc-100">
{providerConfig.name}
</h3>
{serviceName && (
<p className="text-sm text-zinc-500 dark:text-zinc-400">
Service: {serviceName}
</p>
<div className="flex-1">
<h3 className="text-lg font-semibold text-zinc-900 dark:text-zinc-100">
{providerConfig.name}
</h3>
{serviceName && (
<p className="text-sm text-zinc-500 dark:text-zinc-400">
Service: {serviceName}
</p>
)}
</div>
{route && (
<Badge variant="outline" className="text-xs font-mono">
{route}
</Badge>
)}
</div>
{route && (
<Badge variant="outline" className="text-xs font-mono">
{route}
</Badge>
)}
</div>
{output && !actualIsSuccess && (
<div className="p-4 bg-red-50 dark:bg-red-900/10 rounded-lg border border-red-200 dark:border-red-800/50">
<div className="flex items-center gap-2 mb-2">
<AlertTriangle className="h-4 w-4 text-red-600 dark:text-red-400" />
<span className="text-sm font-medium text-red-800 dark:text-red-300">
Execution Failed
</span>
</div>
<p className="text-xs text-red-700 dark:text-red-300 font-mono">
{output}
</p>
</div>
)}
{payload && (
<div className="space-y-4">
<div className="flex items-center gap-2 text-sm font-medium text-zinc-700 dark:text-zinc-300">
<Settings className="h-4 w-4" />
<span>Call Parameters</span>
<ChevronRight className="h-3 w-3 text-zinc-400" />
</div>
<div className="grid gap-3">
{Object.entries(payload).map(([key, value]) => (
<div
key={key}
className="flex items-center justify-between p-3 bg-white dark:bg-zinc-900 rounded-lg border border-zinc-200 dark:border-zinc-800 hover:bg-zinc-50 dark:hover:bg-zinc-800/50 transition-colors"
>
<div className="flex items-center gap-3">
<div className="w-2 h-2 rounded-full bg-zinc-300 dark:bg-zinc-600"></div>
<code className="text-sm font-mono font-medium text-zinc-900 dark:text-zinc-100">
{key}
</code>
</div>
<span className="text-sm text-zinc-600 dark:text-zinc-400 max-w-xs truncate font-mono">
{typeof value === 'string' ? `"${value}"` : String(value)}
</span>
</div>
))}
</div>
<details className="group">
<summary className="flex items-center gap-2 text-sm font-medium text-zinc-700 dark:text-zinc-300 cursor-pointer hover:text-zinc-900 dark:hover:text-zinc-100 transition-colors">
<Code className="h-4 w-4" />
<span>Raw JSON</span>
<ChevronRight className="h-3 w-3 text-zinc-400 group-open:rotate-90 transition-transform" />
</summary>
<div className="mt-3 p-4 bg-zinc-900 dark:bg-zinc-950 rounded-lg border border-zinc-200 dark:border-zinc-800">
<pre className="text-xs font-mono text-emerald-400 dark:text-emerald-300 overflow-x-auto">
{JSON.stringify(payload, null, 2)}
</pre>
{output && !actualIsSuccess && (
<div className="p-4 bg-red-50 dark:bg-red-900/10 rounded-lg border border-red-200 dark:border-red-800/50">
<div className="flex items-center gap-2 mb-2">
<AlertTriangle className="h-4 w-4 text-red-600 dark:text-red-400" />
<span className="text-sm font-medium text-red-800 dark:text-red-300">
Execution Failed
</span>
</div>
</details>
</div>
)}
{!serviceName && !route && !payload && (
<div className="flex flex-col items-center justify-center py-8 text-center">
<div className="w-12 h-12 rounded-lg bg-zinc-100 dark:bg-zinc-800 border border-zinc-200 dark:border-zinc-700 flex items-center justify-center mb-3">
<Database className="h-6 w-6 text-zinc-400" />
</div>
<div className='flex items-center gap-2'>
<Loader2 className="h-4 w-4 animate-spin text-zinc-500 dark:text-zinc-400" />
<p className="text-sm text-zinc-500 dark:text-zinc-400">
Will be populated when the call is executed...
<p className="text-xs text-red-700 dark:text-red-300 font-mono">
{output}
</p>
</div>
</div>
)}
</div>
)}
{payload && (
<div className="space-y-4">
<div className="flex items-center gap-2 text-sm font-medium text-zinc-700 dark:text-zinc-300">
<Settings className="h-4 w-4" />
<span>Call Parameters</span>
<ChevronRight className="h-3 w-3 text-zinc-400" />
</div>
<div className="grid gap-3">
{Object.entries(payload).map(([key, value]) => (
<div
key={key}
className="flex items-center justify-between p-3 bg-white dark:bg-zinc-900 rounded-lg border border-zinc-200 dark:border-zinc-800 hover:bg-zinc-50 dark:hover:bg-zinc-800/50 transition-colors"
>
<div className="flex items-center gap-3">
<div className="w-2 h-2 rounded-full bg-zinc-300 dark:bg-zinc-600"></div>
<code className="text-sm font-mono font-medium text-zinc-900 dark:text-zinc-100">
{key}
</code>
</div>
<span className="text-sm text-zinc-600 dark:text-zinc-400 max-w-xs truncate font-mono">
{typeof value === 'string' ? `"${value}"` : String(value)}
</span>
</div>
))}
</div>
<details className="group">
<summary className="flex items-center gap-2 text-sm font-medium text-zinc-700 dark:text-zinc-300 cursor-pointer hover:text-zinc-900 dark:hover:text-zinc-100 transition-colors">
<Code className="h-4 w-4" />
<span>Raw JSON</span>
<ChevronRight className="h-3 w-3 text-zinc-400 group-open:rotate-90 transition-transform" />
</summary>
<div className="mt-3 p-4 bg-zinc-900 dark:bg-zinc-950 rounded-lg border border-zinc-200 dark:border-zinc-800">
<pre className="text-xs font-mono text-emerald-400 dark:text-emerald-300 overflow-x-auto">
{JSON.stringify(payload, null, 2)}
</pre>
</div>
</details>
</div>
)}
{!serviceName && !route && !payload && (
<div className="flex flex-col items-center justify-center py-8 text-center">
<div className="w-12 h-12 rounded-lg bg-zinc-100 dark:bg-zinc-800 border border-zinc-200 dark:border-zinc-700 flex items-center justify-center mb-3">
<Database className="h-6 w-6 text-zinc-400" />
</div>
<div className='flex items-center gap-2'>
<Loader2 className="h-4 w-4 animate-spin text-zinc-500 dark:text-zinc-400" />
<p className="text-sm text-zinc-500 dark:text-zinc-400">
Will be populated when the call is executed...
</p>
</div>
</div>
)}
</div>
</ScrollArea>
)}
</CardContent>
<div className="px-4 py-2 h-10 bg-zinc-50/50 dark:bg-zinc-900/50 backdrop-blur-sm border-t border-zinc-200 dark:border-zinc-800 flex justify-between items-center gap-4">