Overhaul: real metrics, Git integration UI, open-source hygiene, root cleanup

Backend:
- GET /services/:id/metrics with real Docker container stats
- DELETE /git/providers/:id and GET repo branches endpoint

Frontend:
- Service detail shows real telemetry or honest empty states
- Live status distinguishes idle/polling/reconnecting
- Git providers section in Settings; repo+branch pickers in Add Service
- Real logo, compact Projects header, canvas fitView fix
- index.css deduplicated (1725 -> 1384 lines)
- Fixed smoke tests, lint errors, ToastProvider/context unification

Repo hygiene:
- Added LICENSE (MIT), CONTRIBUTING.md, SECURITY.md; rewrote README
- Untracked .env.prod and data/letsencrypt secrets; fixed .gitignore
- Removed legacy root src/internal/cmd and stale configs/docs/artifacts
- Moved guides and design references under docs/

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
Tomas DvorakandDevin committed 2026-09-15 18:59:40 +02:00
1 parent 355a97bab4
commit 9f3b196032
499 files changed
+4471 -94235

No files matched your search

@@ -184,7 +184,6 @@ export function CacheMetricCard({
}: CacheMetricCardProps) {
const cachePercent = Math.round((cacheMB / totalMB) * 100);
const nonCachePercent = Math.round((nonCacheMB / totalMB) * 100);
const freePercent = 100 - cachePercent - nonCachePercent;
return (
<div
@@ -316,7 +315,6 @@ export function PerformanceMetricCard({
percentage,
upSpeed,
downSpeed,
datasets,
onClick,
animationDelay = 0,
}: PerformanceMetricCardProps) {
@@ -1,4 +1,5 @@
import { Component, ErrorInfo, ReactNode } from 'react';
import { Component } from 'react';
import type { ErrorInfo, ReactNode } from 'react';
interface Props {
children: ReactNode;
+8 -18
View File
@@ -1,8 +1,8 @@
import * as ToastPrimitive from '@radix-ui/react-toast';
import { createContext, useContext, useState, ReactNode } from 'react';
import { useState } from 'react';
import type { ReactNode } from 'react';
import { IconX, IconCheck, IconAlertCircle, IconInfoCircle } from '@tabler/icons-react';
type ToastType = 'success' | 'error' | 'info' | 'warning';
import { ToastContext, type ToastType } from '../hooks/use-toast';
interface Toast {
id: string;
@@ -11,20 +11,6 @@ interface Toast {
description?: string;
}
interface ToastContextValue {
showToast: (type: ToastType, title: string, description?: string) => void;
}
const ToastContext = createContext<ToastContextValue | undefined>(undefined);
export function useToast() {
const context = useContext(ToastContext);
if (!context) {
throw new Error('useToast must be used within ToastProvider');
}
return context;
}
interface ToastProviderProps {
children: ReactNode;
}
@@ -32,7 +18,11 @@ interface ToastProviderProps {
export function ToastProvider({ children }: ToastProviderProps) {
const [toasts, setToasts] = useState<Toast[]>([]);
const showToast = (type: ToastType, title: string, description?: string) => {
const showToast = (first: ToastType | string, second: ToastType | string, description?: string) => {
const toastTypes: ToastType[] = ['success', 'error', 'info', 'warning'];
const firstIsType = toastTypes.includes(first as ToastType);
const type = (firstIsType ? first : second) as ToastType;
const title = (firstIsType ? second : first) as string;
const id = Math.random().toString(36).substring(7);
setToasts((prev) => [...prev, { id, type, title, description }]);
@@ -6,3 +6,5 @@ export * from './DonutChart';
export * from './EnhancedMetricCard';
export * from './CommandPalette';
export * from './StatusBadge';
export { useToast } from '../hooks/use-toast';
export type { ToastType, ToastContextValue } from '../hooks/use-toast';