Skip to content

Commit f4192e3

Browse files
committed
fix: treat admin Renew Now as natural expiration (no suspend_reason), show Expired status in orange when renewable
1 parent 01c2175 commit f4192e3

3 files changed

Lines changed: 47 additions & 16 deletions

File tree

public/css/style.css

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -930,6 +930,11 @@ cap-widget {
930930
color: var(--accent-red);
931931
}
932932

933+
.status-expired {
934+
background: rgba(245, 158, 11, 0.12);
935+
color: var(--accent-orange);
936+
}
937+
933938
.status-installing {
934939
background: rgba(245, 158, 11, 0.12);
935940
color: var(--accent-orange);

public/js/app.js

Lines changed: 40 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -975,12 +975,14 @@ function renderServerCard(s) {
975975
const alloc = s.allocationDetails;
976976
const isInstalling = s.status === 'installing' || s.installed === 0 || s.installed === '0' || s.installed === false;
977977
const isSuspended = s.status === 'suspended';
978-
const statusClass = isSuspended ? 'status-suspended' : (isInstalling ? 'status-installing' : 'status-active');
979-
const statusLabel = isSuspended ? 'Suspended' : (isInstalling ? 'Installing' : 'Active');
980-
const allocStr = alloc ? `${alloc.alias || alloc.nodeFqdn || alloc.ip}:${alloc.port}` : (s.nodeFqdn || `Node #${s.node}`);
981978
const meta = s.serverMeta;
982979
const days = meta ? daysRemaining(meta.expires_at) : null;
983980
const canRenew = days !== null && days <= 7 && days >= -7;
981+
const isAdminSuspended = isSuspended && meta?.suspended_by === 'admin';
982+
const isExpiredRenewable = isSuspended && canRenew && !isAdminSuspended;
983+
const statusClass = isAdminSuspended ? 'status-suspended' : (isExpiredRenewable ? 'status-expired' : (isInstalling ? 'status-installing' : 'status-active'));
984+
const statusLabel = isAdminSuspended ? 'Suspended' : (isExpiredRenewable ? 'Expired' : (isInstalling ? 'Installing' : 'Active'));
985+
const allocStr = alloc ? `${alloc.alias || alloc.nodeFqdn || alloc.ip}:${alloc.port}` : (s.nodeFqdn || `Node #${s.node}`);
984986
const expClass = days !== null && days <= 0 ? 'expired' : (days !== null && days <= 7 ? 'expiring' : '');
985987
return html`
986988
<div class="server-card">
@@ -1017,13 +1019,15 @@ function renderServerRow(s) {
10171019
const alloc = s.allocationDetails;
10181020
const isInstalling = s.status === 'installing' || s.installed === 0 || s.installed === '0' || s.installed === false;
10191021
const isSuspended = s.status === 'suspended';
1020-
const powerState = s.currentState ? s.currentState.charAt(0).toUpperCase() + s.currentState.slice(1) : null;
1021-
const statusClass = isSuspended ? 'status-suspended' : (isInstalling ? 'status-installing' : (powerState === 'Offline' ? 'status-offline' : 'status-active'));
1022-
const statusLabel = isSuspended ? 'Suspended' : (isInstalling ? 'Installing' : (powerState || 'Active'));
1023-
const allocStr = alloc ? `${alloc.alias || alloc.nodeFqdn || alloc.ip}:${alloc.port}` : (s.nodeFqdn || `Node #${s.node}`);
10241022
const meta = s.serverMeta;
10251023
const days = meta ? daysRemaining(meta.expires_at) : null;
10261024
const canRenew = days !== null && days <= 7 && days >= -7;
1025+
const isAdminSuspended = isSuspended && meta?.suspended_by === 'admin';
1026+
const isExpiredRenewable = isSuspended && canRenew && !isAdminSuspended;
1027+
const powerState = s.currentState ? s.currentState.charAt(0).toUpperCase() + s.currentState.slice(1) : null;
1028+
const statusClass = isAdminSuspended ? 'status-suspended' : (isExpiredRenewable ? 'status-expired' : (isInstalling ? 'status-installing' : (powerState === 'Offline' ? 'status-offline' : 'status-active')));
1029+
const statusLabel = isAdminSuspended ? 'Suspended' : (isExpiredRenewable ? 'Expired' : (isInstalling ? 'Installing' : (powerState || 'Active')));
1030+
const allocStr = alloc ? `${alloc.alias || alloc.nodeFqdn || alloc.ip}:${alloc.port}` : (s.nodeFqdn || `Node #${s.node}`);
10271031
return html`
10281032
<tr>
10291033
<td><strong><a href="/server/${s.id}" onclick="event.preventDefault();navigateTo('server/${s.id}')" style="color:inherit;text-decoration:none">${s.name}</a></strong></td>
@@ -1923,10 +1927,12 @@ async function renderServerDetail(serverId) {
19231927
const allocStr = alloc ? `${alloc.alias || alloc.nodeFqdn || alloc.ip}:${alloc.port}` : (s.nodeFqdn || `Node #${s.node}`);
19241928
const isInstalling = s.status === 'installing' || s.installed === 0 || s.installed === '0' || s.installed === false;
19251929
const isSuspended = s.status === 'suspended';
1926-
const statusClass = isSuspended ? 'status-suspended' : (isInstalling ? 'status-installing' : 'status-active');
1927-
const statusLabel = isSuspended ? 'Suspended' : (isInstalling ? 'Installing' : 'Active');
19281930
const days = meta ? daysRemaining(meta.expires_at) : null;
19291931
const canRenew = days !== null && days <= 7 && days >= -7;
1932+
const isAdminSuspended = isSuspended && meta?.suspended_by === 'admin';
1933+
const isExpiredRenewable = isSuspended && canRenew && !isAdminSuspended;
1934+
const statusClass = isAdminSuspended ? 'status-suspended' : (isExpiredRenewable ? 'status-expired' : (isInstalling ? 'status-installing' : 'status-active'));
1935+
const statusLabel = isAdminSuspended ? 'Suspended' : (isExpiredRenewable ? 'Expired' : (isInstalling ? 'Installing' : 'Active'));
19301936
const expClass = days !== null && days <= 0 ? 'expired' : (days !== null && days <= 7 ? 'expiring' : '');
19311937

19321938
const activeTab = state.serverDetailTab || 'info';
@@ -1946,12 +1952,18 @@ async function renderServerDetail(serverId) {
19461952
</div>
19471953
</div>
19481954
1949-
${isSuspended && meta?.suspend_reason ? html`
1955+
${isAdminSuspended && meta?.suspend_reason ? html`
19501956
<div style="background:rgba(239,68,68,0.1);border:1px solid rgba(239,68,68,0.3);border-radius:8px;padding:16px;margin-bottom:24px">
19511957
<div style="font-weight:700;color:var(--accent-red);margin-bottom:4px">Server Suspended</div>
19521958
<div style="color:var(--text-secondary);font-size:0.88rem">${meta.suspend_reason}</div>
19531959
</div>
19541960
` : ''}
1961+
${isExpiredRenewable ? html`
1962+
<div style="background:rgba(245,158,11,0.1);border:1px solid rgba(245,158,11,0.3);border-radius:8px;padding:16px;margin-bottom:24px">
1963+
<div style="font-weight:700;color:var(--accent-orange);margin-bottom:4px">Server Expired</div>
1964+
<div style="color:var(--text-secondary);font-size:0.88rem">This server has expired. Renew it to reactivate it instantly.</div>
1965+
</div>
1966+
` : ''}
19551967
19561968
<div class="tabs" id="server-detail-tabs">
19571969
<button class="tab ${activeTab === 'info' ? 'active' : ''}" data-tab="info">Info</button>
@@ -2003,8 +2015,8 @@ async function renderServerDetail(serverId) {
20032015
<div class="detail-list">
20042016
<div class="detail-item"><span class="detail-label">Created</span><span class="detail-value">${formatDate(meta.created_at)}</span></div>
20052017
<div class="detail-item ${expClass}"><span class="detail-label">Expires</span><span class="detail-value">${formatDate(meta.expires_at)} ${days !== null ? '(' + (days > 0 ? days + ' days' : 'Expired') + ')' : ''}</span></div>
2006-
<div class="detail-item"><span class="detail-label">Status</span><span class="detail-value" style="text-transform:capitalize">${meta.status}</span></div>
2007-
${meta.status === 'suspended' && meta.suspend_reason ? html`
2018+
<div class="detail-item"><span class="detail-label">Status</span><span class="detail-value" style="text-transform:capitalize">${isExpiredRenewable ? 'expired' : meta.status}</span></div>
2019+
${isAdminSuspended && meta.suspend_reason ? html`
20082020
<div class="detail-item"><span class="detail-label">Reason</span><span class="detail-value" style="color:var(--accent-red)">${meta.suspend_reason}</span></div>
20092021
` : ''}
20102022
</div>
@@ -2037,13 +2049,27 @@ async function renderServerDetail(serverId) {
20372049
</div>
20382050
20392051
<div id="server-tab-actions" class="tab-content" style="display:${activeTab === 'actions' ? 'block' : 'none'}">
2040-
${isSuspended ? html`
2052+
${isAdminSuspended ? html`
20412053
<div style="text-align:center;padding:48px 24px">
20422054
<svg width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="var(--accent-red)" stroke-width="1.5" style="margin-bottom:16px"><rect x="3" y="11" width="18" height="11" rx="2" ry="2"/><path d="M7 11V7a5 5 0 0110 0v4"/></svg>
20432055
<h2 style="margin:0 0 8px 0;color:var(--text-primary)">Server Suspended</h2>
2044-
<p style="color:var(--text-secondary);font-size:0.95rem;margin:0 0 4px 0">This server has been suspended. No actions are available.</p>
2056+
<p style="color:var(--text-secondary);font-size:0.95rem;margin:0 0 4px 0">This server has been suspended by an administrator. No actions are available.</p>
20452057
<p style="color:var(--text-secondary);font-size:0.95rem;margin:0">Please contact support via <a href="https://discord.zero-host.org" target="_blank" style="color:var(--accent-1);text-decoration:underline">Discord</a> for assistance.</p>
20462058
</div>
2059+
` : isExpiredRenewable ? html`
2060+
<div style="text-align:center;padding:48px 24px">
2061+
<svg width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="var(--accent-orange)" stroke-width="1.5" style="margin-bottom:16px"><circle cx="12" cy="12" r="10"/><path d="M12 6v6l4 2"/></svg>
2062+
<h2 style="margin:0 0 8px 0;color:var(--text-primary)">Server Expired</h2>
2063+
<p style="color:var(--text-secondary);font-size:0.95rem;margin:0 0 4px 0">This server has expired. Renew it to reactivate it instantly and get 90 more days.</p>
2064+
<button class="btn btn-primary btn-renew-server" data-server-id="${s.id}" style="margin-top:16px">Renew Server (90 days)</button>
2065+
</div>
2066+
` : isSuspended ? html`
2067+
<div style="text-align:center;padding:48px 24px">
2068+
<svg width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="var(--accent-red)" stroke-width="1.5" style="margin-bottom:16px"><rect x="3" y="11" width="18" height="11" rx="2" ry="2"/><path d="M7 11V7a5 5 0 0110 0v4"/></svg>
2069+
<h2 style="margin:0 0 8px 0;color:var(--text-primary)">Server Expired</h2>
2070+
<p style="color:var(--text-secondary);font-size:0.95rem;margin:0 0 4px 0">This server has been expired for too long. Please contact support to renew.</p>
2071+
<p style="color:var(--text-secondary);font-size:0.95rem;margin:0">Reach out via <a href="https://discord.zero-host.org" target="_blank" style="color:var(--accent-1);text-decoration:underline">Discord</a> for assistance.</p>
2072+
</div>
20472073
` : html`
20482074
<div class="action-card">
20492075
<div class="action-card-header">

routes/admin.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -199,8 +199,8 @@ router.post('/servers/:id/renew-now', authenticateToken, requireAdmin, async (re
199199

200200
await suspendPteroServer(serverId);
201201
await query(
202-
'UPDATE server_meta SET expires_at = DATE_SUB(NOW(), INTERVAL 1 DAY), status = ?, suspend_reason = ?, suspended_by = NULL WHERE ptero_server_id = ?',
203-
['suspended', 'Expired by admin', serverId]
202+
'UPDATE server_meta SET expires_at = DATE_SUB(NOW(), INTERVAL 1 DAY), status = ?, suspend_reason = NULL, suspended_by = NULL WHERE ptero_server_id = ?',
203+
['suspended', serverId]
204204
);
205205

206206
await logActivity(req.user.userId, 'admin_renew_now', `Admin force-expired server #${serverId}`, serverId);

0 commit comments

Comments
 (0)