diff --git a/frontend/src/FilterManager.jsx b/frontend/src/FilterManager.jsx index 1229038..8a8bcf9 100644 --- a/frontend/src/FilterManager.jsx +++ b/frontend/src/FilterManager.jsx @@ -330,7 +330,7 @@ function CommunityAutocomplete({ label, value, onChange, communities = [], requi ); } -// Компонент автокомплита для выбора Gateway +// Компонент выбора Gateway в виде карточек (вместо выпадающего списка) function GatewayAutocomplete({ label, value, onChange, gateways = [], required = false, placeholder = 'Введите или выберите gateway...' }) { const [inputValue, setInputValue] = useState(value || ''); const [isOpen, setIsOpen] = useState(false); @@ -369,7 +369,7 @@ function GatewayAutocomplete({ label, value, onChange, gateways = [], required = const val = e.target.value; setInputValue(val); onChange(val); - setIsOpen(true); + setIsOpen(true); // показываем список карточек при вводе setHighlightedIndex(-1); }; @@ -392,6 +392,7 @@ function GatewayAutocomplete({ label, value, onChange, gateways = [], required = switch (e.key) { case 'ArrowDown': e.preventDefault(); + setIsOpen(true); setHighlightedIndex(prev => Math.min(prev + 1, filteredGateways.length - 1)); break; case 'ArrowUp': @@ -402,12 +403,17 @@ function GatewayAutocomplete({ label, value, onChange, gateways = [], required = e.preventDefault(); if (highlightedIndex >= 0 && filteredGateways[highlightedIndex]) { handleSelect(filteredGateways[highlightedIndex]); + } else if (filteredGateways.length === 1) { + // Удобный выбор единственного варианта + handleSelect(filteredGateways[0]); } break; case 'Escape': setIsOpen(false); setHighlightedIndex(-1); break; + default: + break; } }; @@ -430,7 +436,7 @@ function GatewayAutocomplete({ label, value, onChange, gateways = [], required = onFocus={() => setIsOpen(true)} onKeyDown={handleKeyDown} placeholder={placeholder} - required={required} + required={required && !value} autoComplete="off" /> - - {/* Dropdown */} - {isOpen && ( -
- {gateways.length === 0 ? ( -
- - Нет доступных gateway -
- ) : filteredGateways.length === 0 ? ( -
- Ничего не найдено. Нажмите Enter чтобы использовать "{inputValue}" -
- ) : ( - <> - {inputValue && !gateways.some(g => g.name === inputValue) && ( -
Без привязки
- )} - {filteredGateways.map((gw, idx) => ( -
handleSelect(gw)} - onMouseEnter={() => setHighlightedIndex(idx)} - > -
- - {gw.country ? countryToFlag(gw.country) : } - -
-
- {gw.name} - {gw.comment && ({gw.comment})} - {gw.serverDns && — {gw.serverDns}} -
-
- {[gw.comment, gw.country].filter(Boolean).join(' · ') || '—'} -
-
- {gw.primary && Основной} -
-
- ))} - - )} -
- )} - {/* Показываем выбранный gateway */} + {/* Карточки gateway вместо выпадающего списка */} + {isOpen && ( +
+ {gateways.length === 0 ? ( +
+ + Нет доступных gateway для выбранного сервера +
+ ) : filteredGateways.length === 0 ? ( +
+ Ничего не найдено. Уточните запрос по IP, имени или описанию. +
+ ) : ( +
+ {filteredGateways.map((gw, idx) => { + const isSelected = gw.name === value; + const isHighlighted = highlightedIndex === idx; + return ( +
+ +
+ ); + })} +
+ )} +
+ )} + + + {/* Показываем выбранный gateway отдельной карточкой под полем */} {value && selectedGateway && !isOpen && (