From d4053812cd5596f6629ee905393237c111d5c17e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Guti=C3=A9rrez?= <35082514+alezmad@users.noreply.github.com> Date: Wed, 4 Feb 2026 00:43:16 +0100 Subject: [PATCH] Show running services as named chips with restart/stop on Overview Replace anonymous green dots with named green chips, each with restart and stop icon buttons. Now all services have visible controls on the Overview regardless of state. Co-Authored-By: Claude Opus 4.5 --- src/components/OverviewTab.tsx | 85 +++++++++++++++++++++++++--------- 1 file changed, 63 insertions(+), 22 deletions(-) diff --git a/src/components/OverviewTab.tsx b/src/components/OverviewTab.tsx index 1e050f4..210d7c9 100644 --- a/src/components/OverviewTab.tsx +++ b/src/components/OverviewTab.tsx @@ -2,6 +2,7 @@ import { useState, useCallback } from 'react'; import { usePortal } from '@/lib/PortalContext'; +import { clientConfig } from '@/lib/config'; import { Icon } from './Icons'; import { SystemTrends } from './SystemTrends'; import { formatUptime } from '@/lib/stats'; @@ -14,15 +15,6 @@ function isDiscoveredService(s: Service): s is DiscoveredService { return 'uuid' in s && 'resourceType' in s; } -const quickLinks = [ - { name: 'Coolify', url: 'http://192.168.1.3:8000', icon: 'coolify', desc: 'Service manager' }, - { name: 'Dozzle', url: 'http://192.168.1.3:9999', icon: 'scroll-text', desc: 'Container logs' }, - { name: 'Uptime Kuma', url: 'http://192.168.1.3:3001', icon: 'activity', desc: 'Monitoring' }, - { name: 'Ntfy', url: 'http://192.168.1.3:8333', icon: 'bell', desc: 'Notifications' }, - { name: 'Gitea', url: 'http://192.168.1.3:3030', icon: 'git-branch', desc: 'Git hosting' }, - { name: 'Adminer', url: 'http://192.168.1.3:8088', icon: 'database', desc: 'DB admin' }, -]; - interface ProjectDef { name: string; icon: string; @@ -135,7 +127,6 @@ export function OverviewTab() { body: JSON.stringify({ uuid: s.uuid, resourceType: s.resourceType, action }), }); if (res.ok) { - // Wait briefly for Coolify to process, then refresh setTimeout(() => refreshDiscover(), 3000); } } catch { /* ignore */ } finally { @@ -143,6 +134,26 @@ export function OverviewTab() { } }, [refreshDiscover]); + // Build quick links dynamically from discovered services + const quickLinkDefs = [ + { key: 'coolify', icon: 'coolify', desc: 'Service manager' }, + { key: 'dozzle', icon: 'scroll-text', desc: 'Container logs' }, + { key: 'uptime kuma', icon: 'activity', desc: 'Monitoring' }, + { key: 'ntfy', icon: 'bell', desc: 'Notifications' }, + { key: 'gitea', icon: 'git-branch', desc: 'Git hosting' }, + { key: 'adminer', icon: 'database', desc: 'DB admin' }, + ]; + + const quickLinks = quickLinkDefs.map(def => { + const svc = services.find(s => s.name.toLowerCase().includes(def.key)); + return { + name: svc?.name || def.key.charAt(0).toUpperCase() + def.key.slice(1), + url: svc?.url || `http://${clientConfig.nucHost}`, + icon: svc?.icon || def.icon, + desc: def.desc, + }; + }); + const runningServices = services.filter(s => healthStatus[s.name] === 'running'); const stoppedServices = services.filter(s => healthStatus[s.name] === 'stopped'); const unknownServices = services.filter(s => { @@ -184,7 +195,6 @@ export function OverviewTab() { of {totalCount} running - {/* Stopped services as named chips with start button */} {stoppedServices.length > 0 && (

Stopped

@@ -220,7 +230,6 @@ export function OverviewTab() {
)} - {/* Unknown services as named chips with start button */} {unknownServices.length > 0 && (

Unknown

@@ -256,16 +265,48 @@ export function OverviewTab() {
)} - {/* Running services as green dots */} {runningServices.length > 0 && ( -
- {runningServices.map(s => ( -
- ))} +
+

Running

+
+ {runningServices.map(s => { + const uuid = isDiscoveredService(s) ? s.uuid : null; + const loading = uuid ? controlling[uuid] : false; + return ( + + + {s.name} + {uuid && ( + + + + + )} + + ); + })} +
)}
@@ -317,7 +358,7 @@ export function OverviewTab() {
- {/* Row 3: Projects (side by side, scales with more projects) */} + {/* Row 3: Projects */}