feat(NetworkConfigManager): enhance gateway IP generation logic to support direct and recursive gateways, improving template-based configuration and user experience
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m43s

This commit is contained in:
2026-01-25 19:17:20 +07:00
parent 604d45ed92
commit 80c91d9c54
2 changed files with 114 additions and 32 deletions
@@ -10,6 +10,7 @@ function GatewayAutocompleteInput({
onChange,
gateways = [],
interfaces = [],
templateGateways = [], // Gateways из шаблона, которые еще не созданы
excludeGatewayId = null, // ID gateway, который нужно исключить (текущий редактируемый)
placeholder = '',
className = 'form-control',
@@ -25,7 +26,23 @@ function GatewayAutocompleteInput({
const allItems = useMemo(() => {
const items = [];
// Добавляем прямые gateway
// Добавляем прямые gateway из шаблона (которые еще не созданы)
templateGateways
.filter(g => g.id !== excludeGatewayId && g.type === 'direct' && g.ip)
.forEach(g => {
items.push({
type: 'gateway',
id: g.id,
value: g.id,
label: g.ip,
description: g.description || '',
ip: g.ip,
isTemplate: true, // Помечаем как шаблонный gateway
search: [g.ip, g.description, 'gateway', 'template'].filter(Boolean).join(' ').toLowerCase(),
});
});
// Добавляем прямые gateway (уже созданные)
gateways
.filter(g => g.id !== excludeGatewayId && g.type === 'direct' && g.ip)
.forEach(g => {
@@ -36,6 +53,7 @@ function GatewayAutocompleteInput({
label: g.ip,
description: g.description || '',
ip: g.ip,
isTemplate: false,
search: [g.ip, g.description, 'gateway'].filter(Boolean).join(' ').toLowerCase(),
});
});
@@ -57,7 +75,7 @@ function GatewayAutocompleteInput({
});
return items;
}, [gateways, interfaces, excludeGatewayId]);
}, [gateways, interfaces, templateGateways, excludeGatewayId]);
const suggestions = useMemo(() => {
const q = String(value || '').toLowerCase();
@@ -182,16 +200,17 @@ function GatewayAutocompleteInput({
onMouseEnter={() => setActiveIndex(globalIdx)}
>
<div className="d-flex align-items-start">
<span className="avatar me-2 bg-green-lt text-green border-0" style={{ width: 24, height: 24 }}>
<span className={`avatar me-2 ${s.isTemplate ? 'bg-yellow-lt text-yellow' : 'bg-green-lt text-green'} border-0`} style={{ width: 24, height: 24 }}>
<IconWorld size={14} />
</span>
<div className="flex-fill text-start">
<div className="fw-medium">
<code>{s.label}</code>
{s.description && <span className="text-muted ms-2">({s.description})</span>}
{s.isTemplate && <span className="badge bg-yellow-lt text-yellow ms-2" style={{ fontSize: '0.7rem' }}>Шаблон</span>}
</div>
<div className="text-muted small text-truncate" style={{ maxWidth: '100%' }}>
Gateway
Gateway {s.isTemplate ? '(из шаблона)' : ''}
</div>
</div>
</div>