|
4 | 4 | import ActionButtons from '$lib/components/action-buttons.svelte'; |
5 | 5 | import StatusBadge from '$lib/components/badges/status-badge.svelte'; |
6 | 6 | import bytes from 'bytes'; |
7 | | - import { onDestroy, untrack } from 'svelte'; |
| 7 | + import { onDestroy, tick, untrack } from 'svelte'; |
8 | 8 | import { page } from '$app/state'; |
9 | 9 | import type { |
10 | 10 | ContainerDetailsDto, |
|
213 | 213 | const hasEnvVars = $derived(!!(container?.config?.env && container.config.env.length > 0)); |
214 | 214 | const hasPorts = $derived(!!(container?.ports && container.ports.length > 0)); |
215 | 215 | const hasLabels = $derived(!!(container?.labels && Object.keys(container.labels).length > 0)); |
216 | | - const showConfiguration = $derived(hasEnvVars || hasPorts || hasLabels); |
| 216 | + const showConfiguration = $derived(hasEnvVars || hasLabels); |
217 | 217 |
|
218 | 218 | const hasNetworks = $derived( |
219 | 219 | !!(container?.networkSettings?.networks && Object.keys(container.networkSettings.networks).length > 0) |
220 | 220 | ); |
| 221 | + const showNetworkTab = $derived(hasNetworks || hasPorts); |
221 | 222 | const hasMounts = $derived(!!(container?.mounts && container.mounts.length > 0)); |
222 | 223 | const showStats = $derived(!!container?.state?.running); |
223 | 224 | const showShell = $derived(!!container?.state?.running); |
|
228 | 229 | { value: 'logs', label: m.containers_nav_logs(), icon: FileTextIcon }, |
229 | 230 | ...(showShell ? [{ value: 'shell', label: m.common_shell(), icon: TerminalIcon }] : []), |
230 | 231 | ...(showConfiguration ? [{ value: 'config', label: m.common_configuration(), icon: SettingsIcon }] : []), |
231 | | - ...(hasNetworks ? [{ value: 'network', label: m.containers_nav_networks(), icon: NetworksIcon }] : []), |
| 232 | + ...(showNetworkTab ? [{ value: 'network', label: m.containers_nav_networks(), icon: NetworksIcon }] : []), |
232 | 233 | ...(hasMounts ? [{ value: 'storage', label: m.containers_nav_storage(), icon: VolumesIcon }] : []) |
233 | 234 | ]); |
234 | 235 |
|
|
242 | 243 | selectedTab = value; |
243 | 244 | } |
244 | 245 |
|
| 246 | + async function navigateToNetworkPortMappings() { |
| 247 | + if (!showNetworkTab) return; |
| 248 | +
|
| 249 | + selectedTab = 'network'; |
| 250 | + await tick(); |
| 251 | +
|
| 252 | + requestAnimationFrame(() => { |
| 253 | + document.getElementById('container-port-mappings')?.scrollIntoView({ behavior: 'smooth', block: 'start' }); |
| 254 | + }); |
| 255 | + } |
| 256 | +
|
245 | 257 | function parseDockerDate(input: string | Date | undefined | null): Date | null { |
246 | 258 | if (!input) return null; |
247 | 259 | if (input instanceof Date) return isNaN(input.getTime()) ? null : input; |
|
310 | 322 |
|
311 | 323 | {#snippet tabContent(activeTab)} |
312 | 324 | <Tabs.Content value="overview" class="h-full"> |
313 | | - <ContainerOverview {container} {primaryIpAddress} /> |
| 325 | + <ContainerOverview |
| 326 | + {container} |
| 327 | + {primaryIpAddress} |
| 328 | + onViewPortMappings={showNetworkTab ? navigateToNetworkPortMappings : undefined} |
| 329 | + /> |
314 | 330 | </Tabs.Content> |
315 | 331 |
|
316 | 332 | {#if showStats} |
|
357 | 373 | </Tabs.Content> |
358 | 374 | {/if} |
359 | 375 |
|
360 | | - {#if hasNetworks} |
| 376 | + {#if showNetworkTab} |
361 | 377 | <Tabs.Content value="network" class="h-full"> |
362 | 378 | <ContainerNetwork {container} /> |
363 | 379 | </Tabs.Content> |
|
0 commit comments