Files
telemt-api/web/src/lib/components/app-sidebar.svelte
T
Denozordec d021e4b1d7
Publish telemt-api gateway Docker image / test (push) Successful in 23s
Publish telemt-api gateway Docker image / build-and-push (push) Successful in 2m9s
Add Radar DC Telegram functionality and configuration
- Introduced new `RadarConfig` structure in `config.go` to manage radar settings, including `statuses_url`, `http_timeout_ms`, and `ping_from`.
- Implemented validation for radar configuration in `config_test.go` to ensure correct URL schemes and timeout limits.
- Added new API routes for radar statuses and ping functionality in the gateway, enhancing the service's capabilities.
- Updated documentation in `GATEWAY_RUN.md` to include details about the new radar features and their usage.
- Enhanced the user interface to include navigation and display options for the Radar DC section in the sidebar and page titles.
- Added client-side API functions for fetching radar statuses and ping responses, improving integration with the frontend.
2026-04-12 12:53:20 +07:00

242 lines
8.1 KiB
Svelte

<script lang="ts">
import { page } from '$app/state';
import LayoutDashboardIcon from '@lucide/svelte/icons/layout-dashboard';
import UsersIcon from '@lucide/svelte/icons/users';
import GlobeIcon from '@lucide/svelte/icons/globe';
import ServerIcon from '@lucide/svelte/icons/server';
import ActivityIcon from '@lucide/svelte/icons/activity';
import ShieldIcon from '@lucide/svelte/icons/shield';
import NetworkIcon from '@lucide/svelte/icons/network';
import SettingsIcon from '@lucide/svelte/icons/settings';
import RefreshCwIcon from '@lucide/svelte/icons/refresh-cw';
import ZapIcon from '@lucide/svelte/icons/zap';
import SirenIcon from '@lucide/svelte/icons/siren';
import RadioIcon from '@lucide/svelte/icons/radio';
import RadarIcon from '@lucide/svelte/icons/radar';
import * as Sidebar from '$lib/components/ui/sidebar/index.js';
let {
serverAliases = [] as string[],
serverPath = '' as string
}: {
serverAliases?: string[];
serverPath?: string;
} = $props();
function active(href: string): boolean {
const p = page.url.pathname;
if (href === '/') return p === '/';
return p === href || p.startsWith(href + '/');
}
/** Только точное совпадение (для корня ноды `/servers/{alias}` — иначе вложенные страницы вроде …/mihomo подсвечивали бы и Dashboard). */
function activeExact(href: string): boolean {
return page.url.pathname === href;
}
</script>
<Sidebar.Root collapsible="icon">
<Sidebar.Header>
<Sidebar.Menu>
<Sidebar.MenuItem>
<Sidebar.MenuButton size="lg" class="data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground">
<div class="flex aspect-square size-8 items-center justify-center rounded-lg bg-sidebar-primary text-sidebar-primary-foreground">
<ServerIcon class="size-4" />
</div>
<div class="grid flex-1 text-left text-sm leading-tight">
<span class="truncate font-semibold">Telemt Panel</span>
<span class="truncate text-xs text-muted-foreground">мультисервер</span>
</div>
</Sidebar.MenuButton>
</Sidebar.MenuItem>
</Sidebar.Menu>
</Sidebar.Header>
<Sidebar.Content>
<Sidebar.Group>
<Sidebar.GroupLabel>Флот</Sidebar.GroupLabel>
<Sidebar.Menu>
<Sidebar.MenuItem>
<Sidebar.MenuButton isActive={active('/')} tooltipContent="Обзор">
{#snippet child({ props })}
<a href="/" {...props}>
<LayoutDashboardIcon />
<span>Обзор</span>
</a>
{/snippet}
</Sidebar.MenuButton>
</Sidebar.MenuItem>
<Sidebar.MenuItem>
<Sidebar.MenuButton isActive={active('/users')} tooltipContent="Пользователи">
{#snippet child({ props })}
<a href="/users" {...props}>
<UsersIcon />
<span>Пользователи</span>
</a>
{/snippet}
</Sidebar.MenuButton>
</Sidebar.MenuItem>
<Sidebar.MenuItem>
<Sidebar.MenuButton isActive={active('/ips')} tooltipContent="IP">
{#snippet child({ props })}
<a href="/ips" {...props}>
<GlobeIcon />
<span>Уникальные IP</span>
</a>
{/snippet}
</Sidebar.MenuButton>
</Sidebar.MenuItem>
<Sidebar.MenuItem>
<Sidebar.MenuButton isActive={active('/incidents')} tooltipContent="Инциденты">
{#snippet child({ props })}
<a href="/incidents" {...props}>
<SirenIcon />
<span>Инциденты</span>
</a>
{/snippet}
</Sidebar.MenuButton>
</Sidebar.MenuItem>
<Sidebar.MenuItem>
<Sidebar.MenuButton isActive={active('/live')} tooltipContent="Live">
{#snippet child({ props })}
<a href="/live" {...props}>
<RadioIcon />
<span>Live</span>
</a>
{/snippet}
</Sidebar.MenuButton>
</Sidebar.MenuItem>
<Sidebar.MenuItem>
<Sidebar.MenuButton isActive={active('/radar')} tooltipContent="Радар DC Telegram">
{#snippet child({ props })}
<a href="/radar" {...props}>
<RadarIcon />
<span>Радар DC</span>
</a>
{/snippet}
</Sidebar.MenuButton>
</Sidebar.MenuItem>
<Sidebar.MenuItem>
<Sidebar.MenuButton isActive={active('/mihomo')} tooltipContent="Mihomo (флот)">
{#snippet child({ props })}
<a href="/mihomo" {...props}>
<ZapIcon />
<span>Mihomo</span>
</a>
{/snippet}
</Sidebar.MenuButton>
</Sidebar.MenuItem>
</Sidebar.Menu>
</Sidebar.Group>
{#if serverAliases.length > 0}
<Sidebar.Group>
<Sidebar.GroupLabel>Серверы</Sidebar.GroupLabel>
<Sidebar.Menu>
{#each serverAliases as a (a)}
<Sidebar.MenuItem>
<Sidebar.MenuButton
isActive={serverPath.startsWith('/servers/' + a)}
tooltipContent={a}
>
{#snippet child({ props })}
<a href="/servers/{encodeURIComponent(a)}" {...props}>
<ServerIcon />
<span>{a}</span>
</a>
{/snippet}
</Sidebar.MenuButton>
</Sidebar.MenuItem>
{/each}
</Sidebar.Menu>
</Sidebar.Group>
{/if}
{#if serverPath}
<Sidebar.Group>
<Sidebar.GroupLabel>Нода</Sidebar.GroupLabel>
<Sidebar.Menu>
<Sidebar.MenuItem>
<Sidebar.MenuButton isActive={activeExact(serverPath)} tooltipContent="Обзор">
{#snippet child({ props })}
<a href={serverPath} {...props}>
<LayoutDashboardIcon />
<span>Обзор</span>
</a>
{/snippet}
</Sidebar.MenuButton>
</Sidebar.MenuItem>
<Sidebar.MenuItem>
<Sidebar.MenuButton isActive={active(serverPath + '/mihomo')} tooltipContent="Mihomo">
{#snippet child({ props })}
<a href="{serverPath}/mihomo" {...props}>
<ZapIcon />
<span>Mihomo</span>
</a>
{/snippet}
</Sidebar.MenuButton>
</Sidebar.MenuItem>
<Sidebar.MenuItem>
<Sidebar.MenuButton isActive={active(serverPath + '/runtime')} tooltipContent="Состояние">
{#snippet child({ props })}
<a href="{serverPath}/runtime" {...props}>
<ActivityIcon />
<span>Состояние</span>
</a>
{/snippet}
</Sidebar.MenuButton>
</Sidebar.MenuItem>
<Sidebar.MenuItem>
<Sidebar.MenuButton isActive={active(serverPath + '/users')} tooltipContent="Пользователи">
{#snippet child({ props })}
<a href="{serverPath}/users" {...props}>
<UsersIcon />
<span>Пользователи</span>
</a>
{/snippet}
</Sidebar.MenuButton>
</Sidebar.MenuItem>
<Sidebar.MenuItem>
<Sidebar.MenuButton isActive={active(serverPath + '/security')} tooltipContent="Безопасность">
{#snippet child({ props })}
<a href="{serverPath}/security" {...props}>
<ShieldIcon />
<span>Безопасность</span>
</a>
{/snippet}
</Sidebar.MenuButton>
</Sidebar.MenuItem>
<Sidebar.MenuItem>
<Sidebar.MenuButton isActive={active(serverPath + '/upstreams')} tooltipContent="Апстримы и ДЦ">
{#snippet child({ props })}
<a href="{serverPath}/upstreams" {...props}>
<NetworkIcon />
<span>Апстримы и ДЦ</span>
</a>
{/snippet}
</Sidebar.MenuButton>
</Sidebar.MenuItem>
<Sidebar.MenuItem>
<Sidebar.MenuButton isActive={active(serverPath + '/config')} tooltipContent="Конфигурация">
{#snippet child({ props })}
<a href="{serverPath}/config" {...props}>
<SettingsIcon />
<span>Конфигурация</span>
</a>
{/snippet}
</Sidebar.MenuButton>
</Sidebar.MenuItem>
<Sidebar.MenuItem>
<Sidebar.MenuButton isActive={active(serverPath + '/update')} tooltipContent="Обновление">
{#snippet child({ props })}
<a href="{serverPath}/update" {...props}>
<RefreshCwIcon />
<span>Обновление</span>
</a>
{/snippet}
</Sidebar.MenuButton>
</Sidebar.MenuItem>
</Sidebar.Menu>
</Sidebar.Group>
{/if}
</Sidebar.Content>
<Sidebar.Rail />
</Sidebar.Root>