Files
firefrost-services/services/arbiter-3.0/src/views/admin/scheduler/table.ejs
Claude (Chronicler #61) 5e8201fd22 feat: Task #94 Global Restart Scheduler
Complete implementation of staggered restart scheduler for Trinity Console.

Database:
- global_restart_config: Node-wide settings (TX1 @ 04:00 UTC, NC1 @ 04:30 UTC)
- server_restart_schedules: Per-server state with sort order
- sync_logs: Audit trail for all sync operations

Backend:
- src/utils/scheduler.js: Stagger calculation with date-fns
- src/lib/ptero-sync.js: Pterodactyl API integration (create/update/delete/audit)
- src/routes/admin/scheduler.js: All CRUD + import + sync + audit routes

Frontend:
- Drag-and-drop server ordering (SortableJS)
- Per-node config cards with base time + interval
- Audit modal to detect and nuke rogue schedules
- Skip toggle for maintenance mode
- Visual sync status indicators

Features:
- Import servers from Pterodactyl discovery
- Recalculate effective times on reorder
- Rate-limited API calls (200ms delay)
- [Trinity] Daily Restart naming convention

Signed-off-by: Claude (Chronicler #61) <claude@firefrostgaming.com>
2026-04-05 09:58:52 +00:00

53 lines
2.8 KiB
Plaintext

<table class="w-full text-left">
<thead class="bg-gray-100 dark:bg-darkbg text-gray-600 dark:text-gray-300">
<tr>
<th class="p-3 w-10"></th>
<th class="p-3">Server</th>
<th class="p-3">Node</th>
<th class="p-3">Restart Time (UTC)</th>
<th class="p-3">Status</th>
<th class="p-3">Skip</th>
</tr>
</thead>
<tbody id="sortable-servers">
<% if (servers.length === 0) { %>
<tr>
<td colspan="6" class="p-6 text-center text-gray-500">
No servers imported yet. Click "Import Servers" to populate from Pterodactyl.
</td>
</tr>
<% } else { %>
<% servers.forEach((server, i) => { %>
<tr class="border-t border-gray-200 dark:border-gray-700 hover:bg-gray-50 dark:hover:bg-gray-800 transition" data-id="<%= server.server_id %>">
<td class="p-3 cursor-grab text-gray-400 hover:text-gray-900 dark:hover:text-white">
<span class="drag-handle text-lg">☰</span>
</td>
<td class="p-3 font-medium"><%= server.server_name %></td>
<td class="p-3">
<span class="px-2 py-1 rounded text-xs font-bold <%= server.node === 'TX1' ? 'bg-fire/20 text-fire' : 'bg-frost/20 text-frost' %>">
<%= server.node %>
</span>
</td>
<td class="p-3 font-mono text-sm"><%= server.effective_time || 'Not set' %></td>
<td class="p-3 text-sm">
<% if (server.sync_status === 'SUCCESS') { %>
<span class="text-green-500" title="Last synced: <%= server.last_synced_at %>">● Synced</span>
<% } else if (server.sync_status === 'FAILED') { %>
<span class="text-red-500" title="<%= server.last_error %>">✕ Error</span>
<% } else { %>
<span class="text-yellow-500">○ Pending</span>
<% } %>
</td>
<td class="p-3">
<button hx-post="/admin/scheduler/toggle-skip/<%= server.server_id %>"
hx-swap="none"
hx-on::after-request="htmx.ajax('GET', '/admin/scheduler/table-only', '#scheduler-table')"
class="px-2 py-1 rounded text-xs <%= server.skip_restart ? 'bg-red-600 text-white' : 'bg-gray-200 dark:bg-gray-700 text-gray-600 dark:text-gray-300' %>">
<%= server.skip_restart ? 'Skipped' : 'Active' %>
</button>
</td>
</tr>
<% }) %>
<% } %>
</tbody>
</table>