feat: Kunden-Panel zeigt Agents + API-Keys nebeneinander
This commit is contained in:
parent
ebd8f1ebb8
commit
4a79305eee
@ -1,7 +1,7 @@
|
|||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import api from '../api/client'
|
import api from '../api/client'
|
||||||
import { copyToClipboard } from '../utils/clipboard'
|
import { copyToClipboard } from '../utils/clipboard'
|
||||||
import { Plus, Trash2, Edit2, X, Check, ChevronDown, ChevronRight, Copy, Key } from 'lucide-react'
|
import { Plus, Trash2, Edit2, X, Check, ChevronDown, ChevronRight, Copy, Key, Monitor } from 'lucide-react'
|
||||||
|
|
||||||
const PERM_LABELS = {
|
const PERM_LABELS = {
|
||||||
agent: { label: 'Agent', color: 'text-blue-400 bg-blue-900/30 border-blue-700/50' },
|
agent: { label: 'Agent', color: 'text-blue-400 bg-blue-900/30 border-blue-700/50' },
|
||||||
@ -198,10 +198,12 @@ export default function Customers() {
|
|||||||
|
|
||||||
function CustomerKeyPanel({ customerId }) {
|
function CustomerKeyPanel({ customerId }) {
|
||||||
const [keys, setKeys] = useState(null)
|
const [keys, setKeys] = useState(null)
|
||||||
|
const [agents, setAgents] = useState(null)
|
||||||
const [copied, setCopied] = useState(null)
|
const [copied, setCopied] = useState(null)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
api.getCustomerAPIKeys(customerId).then(setKeys)
|
api.getCustomerAPIKeys(customerId).then(setKeys)
|
||||||
|
api.getCustomerAgents(customerId).then(setAgents)
|
||||||
}, [customerId])
|
}, [customerId])
|
||||||
|
|
||||||
const copyKey = (key, id) => {
|
const copyKey = (key, id) => {
|
||||||
@ -210,34 +212,56 @@ function CustomerKeyPanel({ customerId }) {
|
|||||||
setTimeout(() => setCopied(null), 2000)
|
setTimeout(() => setCopied(null), 2000)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (keys === null) {
|
const loading = keys === null || agents === null
|
||||||
|
if (loading) {
|
||||||
return <div className="px-8 py-3 text-gray-500 text-xs bg-gray-800/20 border-t border-gray-800">Laden...</div>
|
return <div className="px-8 py-3 text-gray-500 text-xs bg-gray-800/20 border-t border-gray-800">Laden...</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
if (keys.length === 0) {
|
// Agent-Key fuer diesen Kunden ermitteln (zum Abgleich welcher Agent ihn nutzt)
|
||||||
return (
|
const agentKey = keys.find(k => k.permissions === 'agent')
|
||||||
<div className="px-8 py-3 text-gray-500 text-xs bg-gray-800/20 border-t border-gray-800 flex items-center gap-2">
|
|
||||||
<Key className="w-3.5 h-3.5" />
|
|
||||||
Keine API-Keys fuer diesen Kunden
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-gray-800/20 border-t border-gray-800 px-8 py-3 space-y-1.5">
|
<div className="bg-gray-800/20 border-t border-gray-800 px-8 py-3 grid grid-cols-1 md:grid-cols-2 gap-x-10 gap-y-3">
|
||||||
|
|
||||||
|
{/* Agents */}
|
||||||
|
<div className="space-y-1.5">
|
||||||
|
<div className="flex items-center gap-2 mb-2">
|
||||||
|
<Monitor className="w-3.5 h-3.5 text-gray-500" />
|
||||||
|
<span className="text-xs text-gray-500 font-medium">Agents ({agents.length})</span>
|
||||||
|
</div>
|
||||||
|
{agents.length === 0 ? (
|
||||||
|
<div className="text-xs text-gray-600">Keine Agents zugeordnet</div>
|
||||||
|
) : (
|
||||||
|
agents.map((a) => (
|
||||||
|
<div key={a.id} className="flex items-center gap-2.5">
|
||||||
|
<span className={`w-1.5 h-1.5 rounded-full flex-shrink-0 ${
|
||||||
|
a.status === 'online' ? 'bg-green-400' :
|
||||||
|
a.status === 'stale' ? 'bg-yellow-400' : 'bg-gray-600'
|
||||||
|
}`} />
|
||||||
|
<span className="text-xs text-gray-300 flex-1 min-w-0 truncate">{a.name}</span>
|
||||||
|
<span className="text-[10px] text-gray-600 font-mono flex-shrink-0">{a.agent_version || '—'}</span>
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* API-Keys */}
|
||||||
|
<div className="space-y-1.5">
|
||||||
<div className="flex items-center gap-2 mb-2">
|
<div className="flex items-center gap-2 mb-2">
|
||||||
<Key className="w-3.5 h-3.5 text-gray-500" />
|
<Key className="w-3.5 h-3.5 text-gray-500" />
|
||||||
<span className="text-xs text-gray-500 font-medium">API-Keys</span>
|
<span className="text-xs text-gray-500 font-medium">API-Keys</span>
|
||||||
</div>
|
</div>
|
||||||
{keys.map((k) => {
|
{keys.length === 0 ? (
|
||||||
|
<div className="text-xs text-gray-600">Keine Keys</div>
|
||||||
|
) : (
|
||||||
|
keys.map((k) => {
|
||||||
const perm = PERM_LABELS[k.permissions] || PERM_LABELS.read
|
const perm = PERM_LABELS[k.permissions] || PERM_LABELS.read
|
||||||
return (
|
return (
|
||||||
<div key={k.id} className="flex items-center gap-3">
|
<div key={k.id} className="flex items-center gap-2.5">
|
||||||
<span className={`text-[10px] font-bold px-1.5 py-0.5 rounded border leading-none w-16 text-center flex-shrink-0 ${perm.color}`}>
|
<span className={`text-[10px] font-bold px-1.5 py-0.5 rounded border leading-none w-16 text-center flex-shrink-0 ${perm.color}`}>
|
||||||
{perm.label}
|
{perm.label}
|
||||||
</span>
|
</span>
|
||||||
<span className="text-xs text-gray-400 flex-1 min-w-0 truncate">{k.name}</span>
|
<code className="text-xs text-gray-500 font-mono flex-1 min-w-0 truncate">
|
||||||
<code className="text-xs text-gray-500 font-mono flex-shrink-0">
|
|
||||||
{k.key.substring(0, 8)}...{k.key.substring(k.key.length - 4)}
|
{k.key.substring(0, 8)}...{k.key.substring(k.key.length - 4)}
|
||||||
</code>
|
</code>
|
||||||
<button
|
<button
|
||||||
@ -252,7 +276,10 @@ function CustomerKeyPanel({ customerId }) {
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
})}
|
})
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user