diff --git a/dashboard/src/App.jsx b/dashboard/src/App.jsx index eb4dda1..35aef32 100644 --- a/dashboard/src/App.jsx +++ b/dashboard/src/App.jsx @@ -119,7 +119,7 @@ function CustomersTab() { חדש - {showForm && { setShowForm(false); reload() }} />} + {showForm && { setShowForm(false); reload() }} onCancel={() => setShowForm(false)} />}
{customers.map(c => (
setSelected(c.id)} @@ -134,7 +134,7 @@ function CustomersTab() {
- {c.extension_count} הרחבות + {c.installed_count || 0}/{c.extension_count} מותקנות {c.is_active ? 'פעיל' : 'לא פעיל'}
@@ -154,29 +154,43 @@ function CustomersTab() { ) } -function CustomerForm({ onDone }) { - const [form, setForm] = useState({ name: '', email: '', espocrm_url: '', espocrm_api_key: '' }) +function CustomerForm({ onDone, onCancel, customer }) { + const isEdit = !!customer + const [form, setForm] = useState({ + name: customer?.name || '', email: customer?.email || '', + espocrm_url: customer?.espocrm_url || '', espocrm_api_key: '' + }) const submit = async () => { - await fetch(`${API}/customers`, { - method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(form) + const url = isEdit ? `${API}/customers/${customer.id}` : `${API}/customers` + await fetch(url, { + method: isEdit ? 'PUT' : 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(form) }) onDone() } + const inputClass = "w-full bg-slate-50 border-none rounded-xl px-4 py-2.5 text-sm focus:ring-2 focus:ring-blue-500" return (
setForm({ ...form, name: e.target.value })} - className="w-full bg-slate-50 border-none rounded-xl px-4 py-2.5 text-sm focus:ring-2 focus:ring-blue-500 text-right" /> + className={`${inputClass} text-right`} /> setForm({ ...form, email: e.target.value })} - className="w-full bg-slate-50 border-none rounded-xl px-4 py-2.5 text-sm focus:ring-2 focus:ring-blue-500" dir="ltr" /> + className={inputClass} dir="ltr" /> setForm({ ...form, espocrm_url: e.target.value })} - className="w-full bg-slate-50 border-none rounded-xl px-4 py-2.5 text-sm focus:ring-2 focus:ring-blue-500" dir="ltr" /> - setForm({ ...form, espocrm_api_key: e.target.value })} - className="w-full bg-slate-50 border-none rounded-xl px-4 py-2.5 text-sm font-mono focus:ring-2 focus:ring-blue-500" dir="ltr" /> - + className={inputClass} dir="ltr" /> + setForm({ ...form, espocrm_api_key: e.target.value })} + className={`${inputClass} font-mono`} dir="ltr" /> +
+ + +
) } @@ -186,6 +200,7 @@ function CustomerDetail({ customerId }) { const { data: allExtensions } = useFetch(`${API}/extensions`) const [deploying, setDeploying] = useState(null) const [deployResult, setDeployResult] = useState(null) + const [editing, setEditing] = useState(false) if (!customer) return @@ -224,15 +239,24 @@ function CustomerDetail({ customerId }) { return (
-
-
- + {editing ? ( + { setEditing(false); reload() }} onCancel={() => setEditing(false)} /> + ) : ( +
+
+ +
+
+

{customer.name}

+

{customer.espocrm_url}

+
+
-
-

{customer.name}

-

{customer.espocrm_url}

-
-
+ )} {deployResult && (
diff --git a/server.py b/server.py index d2057e5..1720926 100644 --- a/server.py +++ b/server.py @@ -394,6 +394,7 @@ class APIHandler(BaseHTTPRequestHandler): rows = query("""SELECT c.id, c.name, c.email, c.espocrm_url, c.is_active, c.notes, c.created_at, c.updated_at, c.coolify_url, c.coolify_app_uuid, (SELECT COUNT(*) FROM customer_extensions ce WHERE ce.customer_id = c.id AND ce.license_status = 'active') as extension_count, + (SELECT COUNT(*) FROM customer_extensions ce WHERE ce.customer_id = c.id AND ce.license_status = 'active' AND ce.installed_version IS NOT NULL) as installed_count, (SELECT MAX(dl.started_at) FROM deployment_log dl WHERE dl.customer_id = c.id) as last_deploy FROM customers c ORDER BY c.name""") self._respond(200, rows)