50e8519220
- Add 6 renderer components: StatCard, Gauge, List, Progress, AlertBanner, Chart - Add IntegrationWidget container with auto-refresh, loading, error states - Add IntegrationAlertOverlay for layout-level critical alerts - Add IntegrationConfigFields for dynamic form generation from Zod schemas - Register integration type in WidgetRenderer - Extend WidgetCreationForm with integration app/endpoint pickers - Extend AppForm with integration config section and test connection button - Add /api/integrations/alerts endpoint
48 lines
1.6 KiB
Svelte
48 lines
1.6 KiB
Svelte
<script lang="ts">
|
|
import type { GaugeData } from '$lib/server/integrations/types.js';
|
|
|
|
interface Props {
|
|
data: GaugeData;
|
|
}
|
|
|
|
let { data }: Props = $props();
|
|
|
|
const percentage = $derived(data.max > 0 ? Math.min((data.value / data.max) * 100, 100) : 0);
|
|
|
|
const color = $derived.by(() => {
|
|
const warn = data.thresholds?.warning ?? 60;
|
|
const crit = data.thresholds?.critical ?? 85;
|
|
if (percentage >= crit) return '#ef4444'; // red
|
|
if (percentage >= warn) return '#eab308'; // yellow
|
|
return '#22c55e'; // green
|
|
});
|
|
|
|
// SVG circle math
|
|
const radius = 40;
|
|
const circumference = 2 * Math.PI * radius;
|
|
const strokeDashoffset = $derived(circumference - (percentage / 100) * circumference);
|
|
</script>
|
|
|
|
<div class="flex flex-col items-center justify-center gap-2 p-3">
|
|
<div class="relative h-24 w-24">
|
|
<svg viewBox="0 0 100 100" class="h-full w-full -rotate-90">
|
|
<circle cx="50" cy="50" r={radius} fill="none" stroke="currentColor" stroke-width="8" class="text-muted/20" />
|
|
<circle
|
|
cx="50" cy="50" r={radius} fill="none"
|
|
stroke={color} stroke-width="8"
|
|
stroke-linecap="round"
|
|
stroke-dasharray={circumference}
|
|
stroke-dashoffset={strokeDashoffset}
|
|
class="transition-all duration-700 ease-out"
|
|
/>
|
|
</svg>
|
|
<div class="absolute inset-0 flex flex-col items-center justify-center">
|
|
<span class="text-lg font-bold text-foreground">{Math.round(percentage)}%</span>
|
|
</div>
|
|
</div>
|
|
<div class="text-center">
|
|
<span class="text-sm font-medium text-muted-foreground">{data.label}</span>
|
|
<span class="block text-xs text-muted-foreground/70">{data.value}{data.unit} / {data.max}{data.unit}</span>
|
|
</div>
|
|
</div>
|