This commit is contained in:
jarek committed 2026-01-28 07:34:12 +01:00
1 parent a88d3d5788
commit 8f3a7eb435
96 files changed
+5235 -1870

No files matched your search

@@ -0,0 +1,38 @@
<script lang="ts">
import { Label } from '$lib/components/ui/label';
import { TogglePill } from '$lib/components/ui/toggle-pill';
interface Props {
collectActivity: boolean;
collectMetrics: boolean;
highlightChanges: boolean;
}
let {
collectActivity = $bindable(),
collectMetrics = $bindable(),
highlightChanges = $bindable()
}: Props = $props();
</script>
<div class="flex items-start gap-3">
<div class="flex-1">
<Label>Collect container activity</Label>
<p class="text-xs text-muted-foreground">Track container events (start, stop, restart, etc.) from this environment in real-time</p>
</div>
<TogglePill bind:checked={collectActivity} />
</div>
<div class="flex items-start gap-3">
<div class="flex-1">
<Label>Collect system metrics</Label>
<p class="text-xs text-muted-foreground">Collect CPU and memory usage statistics from this environment</p>
</div>
<TogglePill bind:checked={collectMetrics} />
</div>
<div class="flex items-start gap-3">
<div class="flex-1">
<Label>Highlight value changes</Label>
<p class="text-xs text-muted-foreground">Show amber glow when container values change in the containers list</p>
</div>
<TogglePill bind:checked={highlightChanges} />
</div>
@@ -0,0 +1,219 @@
<script lang="ts">
import { Label } from '$lib/components/ui/label';
import * as Select from '$lib/components/ui/select';
import { TogglePill } from '$lib/components/ui/toggle-pill';
import CronEditor from '$lib/components/cron-editor.svelte';
import TimezoneSelector from '$lib/components/TimezoneSelector.svelte';
import VulnerabilityCriteriaSelector, { type VulnerabilityCriteria } from '$lib/components/VulnerabilityCriteriaSelector.svelte';
import { CircleFadingArrowUp, CircleArrowUp, RefreshCw, Info, Trash2 } from 'lucide-svelte';
import { formatDateTime } from '$lib/stores/settings';
interface Props {
// Update check settings
updateCheckLoading: boolean;
updateCheckEnabled: boolean;
updateCheckCron: string;
updateCheckAutoUpdate: boolean;
updateCheckVulnerabilityCriteria: VulnerabilityCriteria;
scannerEnabled: boolean;
// Image prune settings
imagePruneLoading: boolean;
imagePruneEnabled: boolean;
imagePruneCron: string;
imagePruneMode: 'dangling' | 'all';
imagePruneLastPruned?: string;
imagePruneLastResult?: { spaceReclaimed: number; imagesRemoved: number };
// Timezone
timezone: string;
}
let {
updateCheckLoading,
updateCheckEnabled = $bindable(),
updateCheckCron = $bindable(),
updateCheckAutoUpdate = $bindable(),
updateCheckVulnerabilityCriteria = $bindable(),
scannerEnabled,
imagePruneLoading,
imagePruneEnabled = $bindable(),
imagePruneCron = $bindable(),
imagePruneMode = $bindable(),
imagePruneLastPruned,
imagePruneLastResult,
timezone = $bindable()
}: Props = $props();
// Format bytes to human-readable string
function formatBytes(bytes: number): string {
if (bytes === 0) return '0 B';
const k = 1024;
const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`;
}
</script>
<!-- Scheduled Update Check Section -->
<div class="space-y-4">
<div class="text-sm font-medium">
Scheduled update check
</div>
<p class="text-xs text-muted-foreground">
Periodically check all containers in this environment for available image updates.
</p>
{#if updateCheckLoading}
<div class="flex items-center justify-center py-4">
<RefreshCw class="w-5 h-5 animate-spin text-muted-foreground" />
</div>
{:else}
<div class="flex items-start gap-2">
<CircleFadingArrowUp class="w-4 h-4 text-green-500 glow-green mt-0.5 shrink-0" />
<div class="flex-1">
<Label>Enable scheduled update check</Label>
<p class="text-xs text-muted-foreground">Automatically check for container updates on a schedule</p>
</div>
<TogglePill bind:checked={updateCheckEnabled} />
</div>
{#if updateCheckEnabled}
<div class="flex items-start gap-2">
<div class="w-4 shrink-0"></div>
<div class="flex-1 space-y-2">
<Label>Schedule</Label>
<CronEditor value={updateCheckCron} onchange={(cron) => updateCheckCron = cron} />
</div>
</div>
<div class="flex items-start gap-2">
<CircleArrowUp class="w-4 h-4 text-muted-foreground mt-0.5 shrink-0" />
<div class="flex-1">
<Label>Automatically update containers</Label>
<p class="text-xs text-muted-foreground">
When enabled, containers will be updated automatically when new images are found.
When disabled, only sends notifications about available updates.
</p>
</div>
<TogglePill bind:checked={updateCheckAutoUpdate} />
</div>
{#if updateCheckAutoUpdate && scannerEnabled}
<div class="flex items-start gap-2">
<div class="w-4 shrink-0"></div>
<div class="flex-1">
<Label>Block updates with vulnerabilities</Label>
<p class="text-xs text-muted-foreground">
Block auto-updates if the new image has vulnerabilities exceeding this criteria
</p>
</div>
<VulnerabilityCriteriaSelector
bind:value={updateCheckVulnerabilityCriteria}
class="w-[200px]"
/>
</div>
{/if}
<div class="text-xs text-muted-foreground bg-muted/50 rounded-md p-2 flex items-start gap-2">
<Info class="w-3 h-3 mt-0.5 shrink-0" />
{#if updateCheckAutoUpdate}
{#if scannerEnabled && updateCheckVulnerabilityCriteria !== 'never'}
<span>New images are pulled to a temporary tag, scanned, then deployed if they pass the vulnerability check. Blocked images are deleted automatically.</span>
{:else}
<span>Containers will be updated automatically when new images are available.</span>
{/if}
{:else}
<span>You'll receive notifications when updates are available. Containers won't be modified.</span>
{/if}
</div>
{/if}
{/if}
</div>
<!-- Image Pruning Section -->
<div class="space-y-4 pt-4 border-t">
<div class="text-sm font-medium">
Automatic image pruning
</div>
<p class="text-xs text-muted-foreground">
Automatically remove unused Docker images on a schedule to free up disk space.
</p>
{#if imagePruneLoading}
<div class="flex items-center justify-center py-4">
<RefreshCw class="w-5 h-5 animate-spin text-muted-foreground" />
</div>
{:else}
<div class="flex items-start gap-2">
<Trash2 class="w-4 h-4 text-amber-500 glow-amber mt-0.5 shrink-0" />
<div class="flex-1">
<Label>Enable automatic image pruning</Label>
<p class="text-xs text-muted-foreground">Automatically remove unused images on a schedule</p>
</div>
<TogglePill bind:checked={imagePruneEnabled} />
</div>
{#if imagePruneEnabled}
<div class="flex items-start gap-2">
<div class="w-4 shrink-0"></div>
<div class="flex-1 space-y-2">
<Label>Schedule</Label>
<CronEditor value={imagePruneCron} onchange={(cron) => imagePruneCron = cron} />
</div>
</div>
<div class="flex items-start gap-2">
<div class="w-4 shrink-0"></div>
<div class="flex-1 space-y-2">
<Label>Prune mode</Label>
<Select.Root type="single" bind:value={imagePruneMode}>
<Select.Trigger class="w-full">
{imagePruneMode === 'dangling' ? 'Dangling images only' : 'All unused images'}
</Select.Trigger>
<Select.Content>
<Select.Item value="dangling">Dangling images only</Select.Item>
<Select.Item value="all">All unused images</Select.Item>
</Select.Content>
</Select.Root>
<p class="text-xs text-muted-foreground">
{#if imagePruneMode === 'dangling'}
Only removes untagged image layers (safest option)
{:else}
Removes all images not used by any container (more aggressive)
{/if}
</p>
</div>
</div>
{#if imagePruneLastPruned}
<div class="flex items-start gap-2">
<div class="w-4 shrink-0"></div>
<div class="flex-1">
<p class="text-xs text-muted-foreground">
Last pruned: {formatDateTime(imagePruneLastPruned)}
{#if imagePruneLastResult}
- {imagePruneLastResult.imagesRemoved} images removed, {formatBytes(imagePruneLastResult.spaceReclaimed)} reclaimed
{/if}
</p>
</div>
</div>
{/if}
<div class="text-xs text-muted-foreground bg-muted/50 rounded-md p-2 flex items-start gap-2">
<Info class="w-3 h-3 mt-0.5 shrink-0" />
<span>Images in use by running or stopped containers will never be removed.</span>
</div>
{/if}
{/if}
</div>
<!-- Timezone selector -->
<div class="space-y-2">
<Label>Timezone</Label>
<TimezoneSelector
bind:value={timezone}
id="edit-env-timezone"
/>
<p class="text-xs text-muted-foreground">
Used for scheduling auto-updates, git syncs, and image pruning
</p>
</div>