feat: service categories end-to-end + monitoring widgets on main dashboard
Service categories (described in README roadmap, never wired): - Backend: POST /services now persists category/containerId/port/ip/tailscaleOnly - Backend: POST /services/update accepts category for in-place changes - Frontend: category <select> in add-service modal (local + external) - Frontend: category <select> in edit-service modal with current value - Frontend: All Categories dropdown in service filter bar (auto-populated from both API categories and any categories present on rendered cards) - Frontend: colored category badge (icon + name) on service cards - Frontend: filter auto-refreshes after buildGrid Monitoring on main dashboard (replaces orphaned monitoring-dashboard.html): - New monitoring-widgets.js embeds a 5-card System Overview panel above the filter bar: Services, Containers Up, Avg CPU, Avg Memory, Health - Pulls /api/v1/monitoring/stats + /api/v1/health-checks/status - Auto-refreshes on DC.POLL.STATS (5s), color-coded bars (warn >=65%, bad >=85%) Build: - Added monitoring-widgets.js to init.js bundle in build.js - Rebuilt dist/ bundles (core.js, features.js, init.js) - sw.js cache version bumped automatically - CSP hash regenerated
This commit is contained in:
@@ -372,7 +372,7 @@ module.exports = function({
|
||||
// Add a new service
|
||||
router.post('/services', asyncHandler(async (req, res) => {
|
||||
try {
|
||||
const { id, name, logo } = req.body;
|
||||
const { id, name, logo, category, containerId, port, ip, tailscaleOnly } = req.body;
|
||||
|
||||
if (!id || !name) {
|
||||
throw new ValidationError('id and name are required');
|
||||
@@ -391,7 +391,14 @@ module.exports = function({
|
||||
throw new ConflictError(`Service "${id}" already exists`, id);
|
||||
}
|
||||
|
||||
services.push({ id, name, logo: logo || `/assets/${id}.png` });
|
||||
const newService = { id, name, logo: logo || `/assets/${id}.png` };
|
||||
// Persist optional metadata fields if provided
|
||||
if (category) newService.category = category;
|
||||
if (containerId) newService.containerId = containerId;
|
||||
if (port) newService.port = port;
|
||||
if (ip) newService.ip = ip;
|
||||
if (typeof tailscaleOnly === 'boolean') newService.tailscaleOnly = tailscaleOnly;
|
||||
services.push(newService);
|
||||
return services;
|
||||
});
|
||||
|
||||
@@ -542,6 +549,8 @@ module.exports = function({
|
||||
};
|
||||
if (name) services[serviceIndex].name = name;
|
||||
if (logo) services[serviceIndex].logo = logo;
|
||||
// Allow category update via update endpoint too (optional body field)
|
||||
if (req.body.category !== undefined) services[serviceIndex].category = req.body.category || undefined;
|
||||
results.services = 'updated';
|
||||
} else {
|
||||
results.services = 'not found';
|
||||
|
||||
Reference in New Issue
Block a user