feat: single shared Spaces key, deactivate/reactivate customer, status badge for inactive
Some checks failed
Build & Release / build (push) Has been cancelled
Some checks failed
Build & Release / build (push) Has been cancelled
This commit is contained in:
@@ -345,6 +345,8 @@
|
||||
<!-- Kebab dropdown (shared, repositioned via JS) -->
|
||||
<div id="kebab-menu">
|
||||
<div class="kebab-item" onclick="kebabAction('view')">View Details</div>
|
||||
<div class="kebab-item" id="kebab-deactivate" onclick="kebabAction('deactivate')">Deactivate</div>
|
||||
<div class="kebab-item" id="kebab-reactivate" onclick="kebabAction('reactivate')" style="display:none">Reactivate</div>
|
||||
<div class="kebab-item danger" onclick="kebabAction('delete')">Delete</div>
|
||||
<div class="kebab-item" onclick="kebabAction('record')">Remove Record Only</div>
|
||||
</div>
|
||||
@@ -466,6 +468,7 @@
|
||||
}
|
||||
|
||||
function customerStatusBadge(r) {
|
||||
if (r.status === 'inactive') return '<span class="badge badge-gray">Inactive</span>';
|
||||
if (r.status === 'provisioning') return '<span class="badge badge-yellow">Provisioning</span>';
|
||||
if (r.status === 'failed') {
|
||||
const failedStep = Object.entries(r.steps || {}).find(([,v]) => v === 'failed');
|
||||
@@ -500,7 +503,7 @@
|
||||
<td>${expiry}</td>
|
||||
<td style="color:#8b949e">${fmtDateTime(r.created_at)}</td>
|
||||
<td style="color:#8b949e">${fmtDateTime(r.updated_at)}</td>
|
||||
<td><button class="kebab-btn" onclick="openKebab(event,'${r.slug}')">⋮</button></td>
|
||||
<td><button class="kebab-btn" onclick="openKebab(event,'${r.slug}','${r.status}')">⋮</button></td>
|
||||
</tr>`;
|
||||
}).join('');
|
||||
}
|
||||
@@ -552,9 +555,12 @@
|
||||
|
||||
// ── Kebab menu ────────────────────────────────────────────────────────────
|
||||
|
||||
function openKebab(event, slug) {
|
||||
function openKebab(event, slug, status) {
|
||||
event.stopPropagation();
|
||||
kebabSlug = slug;
|
||||
// Show deactivate or reactivate depending on status
|
||||
document.getElementById('kebab-deactivate').style.display = status === 'inactive' ? 'none' : '';
|
||||
document.getElementById('kebab-reactivate').style.display = status === 'inactive' ? '' : 'none';
|
||||
const menu = document.getElementById('kebab-menu');
|
||||
const rect = event.currentTarget.getBoundingClientRect();
|
||||
menu.style.top = (rect.bottom + 4) + 'px';
|
||||
@@ -572,6 +578,8 @@
|
||||
closeKebab();
|
||||
if (!slug) return;
|
||||
if (action === 'view') openDetail(slug);
|
||||
else if (action === 'deactivate') deactivate(slug);
|
||||
else if (action === 'reactivate') reactivate(slug);
|
||||
else if (action === 'delete') openDeleteDialog(slug);
|
||||
else if (action === 'record') removeRecord(slug);
|
||||
}
|
||||
@@ -758,6 +766,20 @@
|
||||
}
|
||||
}
|
||||
|
||||
async function deactivate(slug) {
|
||||
if (!confirm(`Deactivate "${slug}"?\n\nThis removes the deployment but keeps the database and storage. You can reactivate later.`)) return;
|
||||
const res = await apiFetch(`/api/customers/${slug}/deactivate`, { method: 'POST' });
|
||||
if (res.ok) { loadCustomers(); if (currentDetailSlug === slug) loadDetail(slug, false); }
|
||||
else { const d = await res.json().catch(() => ({})); alert(d.message ?? 'Failed'); }
|
||||
}
|
||||
|
||||
async function reactivate(slug) {
|
||||
if (!confirm(`Reactivate "${slug}"?\n\nThis will redeploy the application.`)) return;
|
||||
const res = await apiFetch(`/api/customers/${slug}/reactivate`, { method: 'POST' });
|
||||
if (res.ok) { loadCustomers(); if (currentDetailSlug === slug) loadDetail(slug, false); }
|
||||
else { const d = await res.json().catch(() => ({})); alert(d.message ?? 'Failed'); }
|
||||
}
|
||||
|
||||
async function removeRecord(slug) {
|
||||
if (!confirm(`Remove "${slug}" from the manager database only?\n\nThis will NOT delete the ArgoCD app or DO database.`)) return;
|
||||
const res = await apiFetch(`/api/customers/${slug}/record`, { method: 'DELETE' });
|
||||
|
||||
Reference in New Issue
Block a user