Files
nuc-portal/src/lib/services.ts
Alejandro Gutiérrez 16d81c4ec3 Add WhyOps service and show health status for all services
- Add WhyOps (whyops.nuc.lan:3002) to service catalog and registry
- Show status pill for static (non-Coolify) services too
- Merge static services into discovered list so they always appear
- Health-check static services via /api/health endpoint

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 18:54:54 +00:00

170 lines
8.9 KiB
TypeScript

export type ServiceCategory = 'infrastructure' | 'development' | 'knowledge' | 'storage' | 'monitoring' | 'security' | 'automation';
export type BookmarkCategory = 'developer' | 'ai-tools' | 'ai-platforms' | 'utilities' | 'design' | 'learning' | 'productivity' | 'other';
export interface Service {
name: string;
url: string;
port: number;
icon: string;
category: ServiceCategory;
description?: string;
container?: string;
}
export interface DiscoveredService extends Service {
source: 'discovered' | 'static';
fqdn?: string;
resourceType: 'application' | 'service' | 'database';
uuid: string;
coolifyStatus: string;
}
export function getCoolifyUrl(service: DiscoveredService): string {
const base = process.env.NEXT_PUBLIC_COOLIFY_URL || 'http://coolify.nuc.lan';
const project = process.env.NEXT_PUBLIC_COOLIFY_PROJECT_UUID || 'a8484ggc88c40w4g4k004ow0';
const env = process.env.NEXT_PUBLIC_COOLIFY_ENV_UUID || 'dckc0w4ko8s888c4gk84skoo';
return `${base}/project/${project}/environment/${env}/${service.resourceType}/${service.uuid}`;
}
export function getDozzleUrl(service?: DiscoveredService): string {
const base = process.env.NEXT_PUBLIC_DOZZLE_URL || 'http://dozzle.nuc.lan';
const hostId = process.env.NEXT_PUBLIC_DOZZLE_HOST_ID || '6c1738d9-6f12-4ed7-9293-70a91f407347';
if (service?.container) {
return `${base}/container/${hostId}~${service.container}`;
}
return base;
}
export interface Bookmark {
name: string;
url: string;
icon: string;
category: BookmarkCategory;
description?: string;
}
import { clientConfig, getServiceUrl } from './config';
const h = clientConfig.nucHost;
export const fallbackServices: Service[] = [
// Infrastructure - prefer domain-based URLs
{ name: 'Coolify', url: 'http://coolify.nuc.lan', port: 8000, icon: 'server', category: 'infrastructure', description: 'Container deployment & management' },
{ name: 'Dozzle', url: 'http://dozzle.nuc.lan', port: 9999, icon: 'scroll-text', category: 'infrastructure', description: 'Real-time Docker log viewer' },
{ name: 'Playwriter Browser', url: `http://${h}:6081/vnc.html`, port: 6081, icon: 'monitor', category: 'infrastructure', description: 'Remote browser for automation' },
// Automation
{ name: 'n8n', url: `http://${h}:5678`, port: 5678, icon: 'workflow', category: 'automation', description: 'Workflow automation platform' },
// Development - prefer domain-based URLs
{ name: 'Gitea', url: 'http://gitea.nuc.lan', port: 3030, icon: 'git-branch', category: 'development', description: 'Self-hosted Git service' },
{ name: 'CloudBeaver', url: `http://${h}:8978`, port: 8978, icon: 'database', category: 'development', description: 'Database management UI' },
{ name: 'Adminer', url: `http://${h}:8088`, port: 8088, icon: 'table', category: 'development', description: 'Lightweight database admin' },
{ name: 'WhyOps', url: 'http://whyops.nuc.lan', port: 3002, icon: 'settings', category: 'automation', description: 'WhyRating scraping, pipelines & testing' },
// Knowledge - prefer domain-based URLs
{ name: 'Outline', url: 'http://outline.nuc.lan', port: 3080, icon: 'book-open', category: 'knowledge', description: 'Team wiki & documentation' },
{ name: 'NocoDB', url: `http://${h}:8084`, port: 8084, icon: 'grid-3x3', category: 'knowledge', description: 'Airtable alternative database' },
// Storage - prefer domain-based URLs
{ name: 'FileBrowser', url: 'http://files.nuc.lan', port: 8085, icon: 'folder', category: 'storage', description: 'Web file manager' },
{ name: 'MinIO', url: `http://${h}:9001`, port: 9001, icon: 'hard-drive', category: 'storage', description: 'S3-compatible object storage' },
{ name: 'Kopia', url: `http://${h}:51515`, port: 51515, icon: 'archive', category: 'storage', description: 'Backup & restore' },
// Monitoring
{ name: 'Uptime Kuma', url: `http://${h}:3001`, port: 3001, icon: 'activity', category: 'monitoring', description: 'Service status monitoring' },
{ name: 'Ntfy', url: `http://${h}:8333`, port: 8333, icon: 'bell', category: 'monitoring', description: 'Push notifications server' },
// Security - prefer domain-based URLs
{ name: 'Vaultwarden', url: 'http://vault.nuc.lan', port: 8222, icon: 'lock', category: 'security', description: 'Password manager' },
{ name: 'Authentik', url: `http://${h}:9090`, port: 9090, icon: 'shield', category: 'security', description: 'Identity provider & SSO' },
];
// Re-export for backwards compatibility
export const services = fallbackServices;
export const bookmarks: Bookmark[] = [
// Developer Tools
{ name: 'DevDocs', url: 'https://devdocs.io', icon: 'book', category: 'developer', description: 'API documentation browser' },
{ name: 'Can I Use', url: 'https://caniuse.com', icon: 'check-circle', category: 'developer', description: 'Browser compatibility tables' },
{ name: 'Regex101', url: 'https://regex101.com', icon: 'brackets', category: 'developer', description: 'Regex tester & debugger' },
{ name: 'Bundlephobia', url: 'https://bundlephobia.com', icon: 'package', category: 'developer', description: 'NPM package size analyzer' },
{ name: 'Transform Tools', url: 'https://transform.tools', icon: 'arrow-right-left', category: 'developer', description: 'Code transformers' },
// AI Tools
{ name: 'Claude', url: 'https://claude.ai', icon: 'bot', category: 'ai-tools', description: 'Anthropic AI assistant' },
{ name: 'ChatGPT', url: 'https://chat.openai.com', icon: 'message-square', category: 'ai-tools', description: 'OpenAI chat assistant' },
{ name: 'Perplexity', url: 'https://perplexity.ai', icon: 'search', category: 'ai-tools', description: 'AI-powered search' },
{ name: 'Phind', url: 'https://phind.com', icon: 'code', category: 'ai-tools', description: 'AI for developers' },
{ name: 'Cursor', url: 'https://cursor.com', icon: 'terminal', category: 'ai-tools', description: 'AI-first code editor' },
// AI Platforms
{ name: 'v0', url: 'https://v0.dev', icon: 'layout', category: 'ai-platforms', description: 'Vercel AI UI generator' },
{ name: 'Replicate', url: 'https://replicate.com', icon: 'cpu', category: 'ai-platforms', description: 'ML model hosting' },
{ name: 'Hugging Face', url: 'https://huggingface.co', icon: 'smile', category: 'ai-platforms', description: 'ML models & datasets' },
{ name: 'Together AI', url: 'https://together.ai', icon: 'users', category: 'ai-platforms', description: 'Open model inference' },
// Utilities
{ name: 'Excalidraw', url: 'https://excalidraw.com', icon: 'pencil', category: 'utilities', description: 'Hand-drawn diagrams' },
{ name: 'JSON Crack', url: 'https://jsoncrack.com', icon: 'braces', category: 'utilities', description: 'JSON visualizer' },
{ name: 'Carbon', url: 'https://carbon.now.sh', icon: 'image', category: 'utilities', description: 'Code screenshot tool' },
{ name: 'Squoosh', url: 'https://squoosh.app', icon: 'image-down', category: 'utilities', description: 'Image compression' },
{ name: 'TinyPNG', url: 'https://tinypng.com', icon: 'file-image', category: 'utilities', description: 'PNG/JPEG compression' },
// Design
{ name: 'Figma', url: 'https://figma.com', icon: 'figma', category: 'design', description: 'Collaborative design tool' },
{ name: 'Coolors', url: 'https://coolors.co', icon: 'palette', category: 'design', description: 'Color palette generator' },
{ name: 'Heroicons', url: 'https://heroicons.com', icon: 'shapes', category: 'design', description: 'Beautiful hand-crafted icons' },
{ name: 'Lucide', url: 'https://lucide.dev', icon: 'circle', category: 'design', description: 'Icon library' },
// Learning
{ name: 'MDN Web Docs', url: 'https://developer.mozilla.org', icon: 'graduation-cap', category: 'learning', description: 'Web technology docs' },
{ name: 'web.dev', url: 'https://web.dev', icon: 'globe', category: 'learning', description: 'Modern web guidance' },
// Productivity
{ name: 'Linear', url: 'https://linear.app', icon: 'list-todo', category: 'productivity', description: 'Issue tracking' },
{ name: 'Notion', url: 'https://notion.so', icon: 'notebook', category: 'productivity', description: 'Notes & docs' },
];
export const categoryLabels: Record<ServiceCategory, string> = {
infrastructure: 'Infrastructure',
development: 'Development',
knowledge: 'Knowledge',
storage: 'Storage',
monitoring: 'Monitoring',
security: 'Security',
automation: 'Automation',
};
export const bookmarkCategoryLabels: Record<BookmarkCategory, string> = {
developer: 'Developer Tools',
'ai-tools': 'AI Tools',
'ai-platforms': 'AI Platforms',
utilities: 'Utilities',
design: 'Design',
learning: 'Learning',
productivity: 'Productivity',
other: 'Other',
};
export const categoryOrder: ServiceCategory[] = [
'infrastructure',
'automation',
'development',
'knowledge',
'storage',
'monitoring',
'security',
];
export const bookmarkCategoryOrder: BookmarkCategory[] = [
'developer',
'ai-tools',
'ai-platforms',
'utilities',
'design',
'learning',
'productivity',
'other',
];