feat: structured extensions table in customer detail view
4 columns: name, installed version, available update, actions Actions: install (if not installed), update + remove (if installed)
This commit is contained in:
+55
-16
@@ -161,6 +161,11 @@ function CustomerDetail({ customerId }) {
|
||||
setDeploying(null)
|
||||
}
|
||||
|
||||
const remove = async (extId) => {
|
||||
await fetch(`${API}/customers/${customerId}/extensions/${extId}`, { method: 'DELETE' })
|
||||
reload()
|
||||
}
|
||||
|
||||
const assign = async (extId) => {
|
||||
await fetch(`${API}/customers/${customerId}/extensions`, {
|
||||
method: 'POST', headers: { 'Content-Type': 'application/json' },
|
||||
@@ -180,27 +185,61 @@ function CustomerDetail({ customerId }) {
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="bg-white rounded-lg shadow divide-y">
|
||||
{(customer.extensions || []).map(e => (
|
||||
<div key={e.id} className="p-3 flex items-center justify-between">
|
||||
<div>
|
||||
<span className="font-medium">{e.name}</span>
|
||||
<span className="text-sm text-gray-500 mr-2">
|
||||
{e.installed_version ? `v${e.installed_version}` : 'לא מותקן'}
|
||||
</span>
|
||||
{e.installed_version && e.latest_version && e.installed_version !== e.latest_version && (
|
||||
<span className="text-xs bg-yellow-100 text-yellow-800 px-2 py-0.5 rounded mr-2">
|
||||
עדכון: v{e.latest_version}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<div className="bg-white rounded-lg shadow overflow-hidden">
|
||||
<table className="w-full text-right">
|
||||
<thead className="bg-gray-50">
|
||||
<tr>
|
||||
<th className="px-4 py-3 text-sm font-medium text-gray-500">שם ההרחבה</th>
|
||||
<th className="px-4 py-3 text-sm font-medium text-gray-500">מותקנת</th>
|
||||
<th className="px-4 py-3 text-sm font-medium text-gray-500">עדכון זמין</th>
|
||||
<th className="px-4 py-3 text-sm font-medium text-gray-500">פעולות</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="divide-y divide-gray-200">
|
||||
{(customer.extensions || []).map(e => {
|
||||
const installed = e.installed_version
|
||||
const hasUpdate = installed && e.latest_version && installed !== e.latest_version
|
||||
return (
|
||||
<tr key={e.id} className="hover:bg-gray-50">
|
||||
<td className="px-4 py-3 font-medium">{e.name}</td>
|
||||
<td className="px-4 py-3">
|
||||
{installed
|
||||
? <Badge>v{installed}</Badge>
|
||||
: <span className="text-sm text-red-500">לא מותקן</span>}
|
||||
</td>
|
||||
<td className="px-4 py-3">
|
||||
{hasUpdate
|
||||
? <span className="text-sm font-medium text-amber-600">v{e.latest_version}</span>
|
||||
: <span className="text-sm text-gray-300">—</span>}
|
||||
</td>
|
||||
<td className="px-4 py-3">
|
||||
<div className="flex gap-2 justify-end">
|
||||
{!installed ? (
|
||||
<button onClick={() => deploy(e.name, e.latest_version)}
|
||||
disabled={deploying === e.name}
|
||||
className="bg-blue-500 text-white px-3 py-1 rounded text-sm hover:bg-blue-600 disabled:opacity-50">
|
||||
{deploying === e.name ? '...' : 'דחוף'}
|
||||
{deploying === e.name ? '...' : 'התקנה'}
|
||||
</button>
|
||||
) : (
|
||||
<>
|
||||
<button onClick={() => deploy(e.name, e.latest_version)}
|
||||
disabled={deploying === e.name}
|
||||
className="bg-blue-500 text-white px-3 py-1 rounded text-sm hover:bg-blue-600 disabled:opacity-50">
|
||||
{deploying === e.name ? '...' : 'עדכון'}
|
||||
</button>
|
||||
<button onClick={() => remove(e.id)}
|
||||
className="bg-red-500 text-white px-3 py-1 rounded text-sm hover:bg-red-600">
|
||||
הסרה
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</td>
|
||||
</tr>
|
||||
)
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{available.length > 0 && (
|
||||
|
||||
Reference in New Issue
Block a user