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 */}