This commit is contained in:
jarek committed 2026-06-17 08:21:38 +02:00
1 parent aa45be6844
commit efb634701c
56 files changed
+9101 -117

No files matched your search

+35
View File
@@ -18,6 +18,9 @@
import { Play, Square, Trash2, Plus, ArrowBigDown, Search, Pencil, ExternalLink, GitBranch, RefreshCw, Loader2, FileCode, FileText, FileOutput, Box, RotateCcw, ScrollText, Terminal, Eye, Network, HardDrive, Heart, HeartPulse, HeartOff, ChevronsUpDown, ChevronsDownUp, Rocket, AlertTriangle, X, Layers, Pause, CircleDashed, Skull, FolderOpen, Variable, Clock, RotateCw, Import, Ship, Cable, LayoutPanelLeft, Rows3, GripVertical, Globe } from 'lucide-svelte';
import { formatPorts } from '$lib/utils/port-format';
import { parseCustomUrl } from '$lib/utils/custom-url';
import { extractTraefikUrls } from '$lib/utils/traefik-urls';
import { extractPangolinUrls } from '$lib/utils/pangolin-urls';
import { appSettings } from '$lib/stores/settings';
import ConfirmPopover from '$lib/components/ConfirmPopover.svelte';
import BatchOperationModal from '$lib/components/BatchOperationModal.svelte';
import type { ComposeStackInfo, ContainerStats } from '$lib/types';
@@ -2059,6 +2062,38 @@
<ExternalLink class="w-2.5 h-2.5 opacity-60" />
</a>
{/if}
{:else}
<!-- Traefik fallback URLs (#2). dockhand.url suppresses these, as does the
"Honor Traefik/Pangolin labels" setting being off. -->
{#each ($appSettings.honorProxyLabels ? extractTraefikUrls(container.labels) : []) as t}
<a
href={t.url}
target="_blank"
rel="noopener noreferrer"
onclick={(e) => e.stopPropagation()}
class="inline-flex items-center gap-0.5 px-1.5 py-0.5 rounded bg-primary/10 text-primary hover:bg-primary/20 transition-colors"
title="Traefik router {t.router} → {t.url}"
>
<Globe class="w-2.5 h-2.5" />
<span class="max-w-[120px] truncate">{t.url.replace(/^https?:\/\//, '')}</span>
<ExternalLink class="w-2.5 h-2.5 opacity-60" />
</a>
{/each}
<!-- Pangolin fallback URLs (#2 follow-up). Same suppression rules. -->
{#each ($appSettings.honorProxyLabels ? extractPangolinUrls(container.labels) : []) as p}
<a
href={p.url}
target="_blank"
rel="noopener noreferrer"
onclick={(e) => e.stopPropagation()}
class="inline-flex items-center gap-0.5 px-1.5 py-0.5 rounded bg-primary/10 text-primary hover:bg-primary/20 transition-colors"
title="Pangolin resource {p.resource} → {p.url}"
>
<Globe class="w-2.5 h-2.5" />
<span class="max-w-[120px] truncate">{p.displayName ?? p.url.replace(/^https?:\/\//, '')}</span>
<ExternalLink class="w-2.5 h-2.5 opacity-60" />
</a>
{/each}
{/if}
<!-- Clickable ports with range collapsing -->
{#if container.ports.length > 0}
+11 -3
View File
@@ -35,11 +35,13 @@
open: boolean;
mode: 'create' | 'edit';
stackName?: string; // Required for edit mode, optional for create
initialCompose?: string; // Pre-fill compose content (for library deploy)
initialStackName?: string; // Pre-fill stack name (for library deploy)
onClose: () => void;
onSuccess: () => void; // Called after create or save
}
let { open = $bindable(), mode: propMode, stackName: propStackName = '', onClose, onSuccess }: Props = $props();
let { open = $bindable(), mode: propMode, stackName: propStackName = '', initialCompose, initialStackName, onClose, onSuccess }: Props = $props();
// Local effective state - can transition from create → edit after failed deploy
let mode = $state(propMode);
@@ -1222,8 +1224,11 @@
validateEnvVars();
});
} else if (mode === 'create') {
// Set default compose content for create mode
composeContent = defaultCompose;
// Set default compose content for create mode (library templates override default)
composeContent = initialCompose || defaultCompose;
if (initialStackName) {
newStackName = initialStackName;
}
isDirty = false; // Reset dirty flag for new modal
loading = false;
// Auto-validate default compose
@@ -1351,6 +1356,9 @@
{:else}
{stackName}
{/if}
{#if $currentEnvironment}
<span class="font-medium">on <span class="text-amber-600 dark:text-amber-400">{$currentEnvironment.name}</span></span>
{/if}
</Dialog.Title>
<Dialog.Description class="text-xs text-zinc-500 dark:text-zinc-400">
{#if mode === 'create'}