feat(server): expand server types to include BGP and DNS; enhance validation for required fields and tunnel requirements in server configuration
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m25s

This commit is contained in:
2026-01-20 19:04:55 +07:00
parent ff7c26f6f7
commit fe665ebc1f
2 changed files with 40 additions and 17 deletions
+26 -13
View File
@@ -10,9 +10,12 @@ import {
IconNetwork,
IconCloud,
IconRouter,
IconArrowsRightLeft
IconArrowsRightLeft,
IconRoute,
IconWorldWww
} from '@tabler/icons-react';
import { useState } from 'react';
import { needsTunnel } from '../../utils/serverUtils.js';
// Преобразование кода страны в emoji-флаг
function countryToFlag(isoCode) {
@@ -42,10 +45,20 @@ export default function ServerCard({
}) {
const [expanded, setExpanded] = useState(false);
const isExit = server.type === 'exit';
const serverType = (server.type || 'jumphost').toLowerCase();
const primaryGateway = server.gateways?.find(g => g.primary)?.name || server.gateway || '';
const connectionsCount = server.gateways?.length || 0;
const serverName = server.dns?.split('.')[0] || server.ip;
const showTunnel = needsTunnel(serverType);
// Конфигурация отображения типов серверов
const typeConfig = {
jumphost: { label: 'JUMP', color: 'blue', icon: IconRouter },
exit: { label: 'EXIT', color: 'red', icon: IconArrowsRightLeft },
bgp: { label: 'BGP', color: 'purple', icon: IconRoute },
dns: { label: 'DNS', color: 'cyan', icon: IconWorldWww },
};
const currentTypeConfig = typeConfig[serverType] || typeConfig.jumphost;
return (
<div
@@ -62,7 +75,7 @@ export default function ServerCard({
<div className="d-flex align-items-stretch">
{/* Левая часть: тип сервера */}
<div
className={`d-flex align-items-center justify-content-center px-3 ${isExit ? 'bg-red-lt' : 'bg-blue-lt'}`}
className={`d-flex align-items-center justify-content-center px-3 bg-${currentTypeConfig.color}-lt`}
style={{
minWidth: '80px',
borderTopLeftRadius: selected ? '10px' : '11px',
@@ -74,15 +87,13 @@ export default function ServerCard({
<div className="text-center">
<div className="mb-1">
{selected ? (
<IconCircleCheck size={20} className={isExit ? 'text-red' : 'text-blue'} />
) : isExit ? (
<IconArrowsRightLeft size={20} className="text-red" />
<IconCircleCheck size={20} className={`text-${currentTypeConfig.color}`} />
) : (
<IconRouter size={20} className="text-blue" />
<currentTypeConfig.icon size={20} className={`text-${currentTypeConfig.color}`} />
)}
</div>
<div className={`fw-bold ${isExit ? 'text-red' : 'text-blue'}`} style={{ fontSize: '0.65rem', letterSpacing: '0.5px' }}>
{isExit ? 'EXIT' : 'JUMP'}
<div className={`fw-bold text-${currentTypeConfig.color}`} style={{ fontSize: '0.65rem', letterSpacing: '0.5px' }}>
{currentTypeConfig.label}
</div>
</div>
</div>
@@ -114,10 +125,12 @@ export default function ServerCard({
<code className="text-muted" style={{ fontSize: '0.8rem' }}>
{server.dns || server.ip}
</code>
<span className="badge bg-secondary-lt text-secondary">
<IconNetwork size={12} className="me-1" />
{server.tunnel}
</span>
{showTunnel && server.tunnel && (
<span className="badge bg-secondary-lt text-secondary">
<IconNetwork size={12} className="me-1" />
{server.tunnel}
</span>
)}
{connectionsCount > 0 && (
<span className="badge bg-green-lt text-green">
<IconCloud size={12} className="me-1" />