feat: Introduce baseAS state management in FilterManager and SettingsModal, enhancing community search normalization and user settings configuration for improved filtering accuracy.
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m54s
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m54s
This commit is contained in:
@@ -71,7 +71,7 @@ const countryToFlag = (code) => {
|
||||
};
|
||||
|
||||
// Компонент автокомплита для выбора Community
|
||||
function CommunityAutocomplete({ label, value, onChange, communities = [], required = false, placeholder = 'Введите или выберите community...' }) {
|
||||
function CommunityAutocomplete({ label, value, onChange, communities = [], required = false, placeholder = 'Введите или выберите community...', baseAS = '65001' }) {
|
||||
const [inputValue, setInputValue] = useState(value || '');
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [highlightedIndex, setHighlightedIndex] = useState(-1);
|
||||
@@ -89,9 +89,22 @@ function CommunityAutocomplete({ label, value, onChange, communities = [], requi
|
||||
|
||||
const cValue = (c.value || '').toLowerCase();
|
||||
|
||||
// Поиск по полному значению
|
||||
// Нормализуем значение из справочника с учётом baseAS
|
||||
// Если в справочнике просто число (например "120"), считаем его как "baseAS:120"
|
||||
const normalizedCValue = cValue.includes(':') ? cValue : `${baseAS}:${cValue}`;
|
||||
|
||||
// Нормализуем поисковый запрос
|
||||
// Если введено просто число, считаем его как "baseAS:число"
|
||||
const normalizedSearch = search.includes(':') ? search : `${baseAS}:${search}`;
|
||||
|
||||
// Поиск по полному значению (с нормализацией)
|
||||
if (normalizedCValue.includes(search)) return true;
|
||||
if (cValue.includes(search)) return true;
|
||||
|
||||
// Поиск нормализованного значения
|
||||
if (normalizedCValue === normalizedSearch) return true;
|
||||
if (normalizedCValue.includes(normalizedSearch)) return true;
|
||||
|
||||
// Поиск по части после двоеточия (например, "120" найдёт "65001:120")
|
||||
if (cValue.includes(':')) {
|
||||
const parts = cValue.split(':');
|
||||
@@ -108,6 +121,11 @@ function CommunityAutocomplete({ label, value, onChange, communities = [], requi
|
||||
if (searchParts[1] && cValue.includes(searchParts[1])) return true;
|
||||
}
|
||||
|
||||
// Поиск просто по числу без AS
|
||||
if (!search.includes(':') && !cValue.includes(':')) {
|
||||
if (cValue.includes(search)) return true;
|
||||
}
|
||||
|
||||
// Поиск по названию и описанию
|
||||
if (c.name && c.name.toLowerCase().includes(search)) return true;
|
||||
if (c.description && c.description.toLowerCase().includes(search)) return true;
|
||||
@@ -586,6 +604,8 @@ function FilterManager() {
|
||||
|
||||
// Communities directory for autocomplete
|
||||
const [communities, setCommunities] = useState([]);
|
||||
// Базовая AS из настроек
|
||||
const [baseAS, setBaseAS] = useState('65001');
|
||||
// Inventory servers (from /servers endpoint)
|
||||
const [inventoryServers, setInventoryServers] = useState([]);
|
||||
|
||||
@@ -647,6 +667,17 @@ function FilterManager() {
|
||||
})();
|
||||
|
||||
useEffect(() => {
|
||||
// Загружаем базовую AS из настроек
|
||||
(async () => {
|
||||
try {
|
||||
const res = await api.get('/ui-settings');
|
||||
const data = res?.data || {};
|
||||
if (data?.baseAS) setBaseAS(String(data.baseAS));
|
||||
} catch (e) {
|
||||
// мягко игнорируем, используем значение по умолчанию
|
||||
}
|
||||
})();
|
||||
|
||||
(async () => {
|
||||
try {
|
||||
const res = await api.get(`/communities`);
|
||||
@@ -1815,6 +1846,7 @@ function FilterManager() {
|
||||
value={newFilter.community}
|
||||
onChange={(val) => setNewFilter({ ...newFilter, community: val })}
|
||||
communities={communities}
|
||||
baseAS={baseAS}
|
||||
required
|
||||
/>
|
||||
|
||||
@@ -1855,6 +1887,7 @@ function FilterManager() {
|
||||
value={editingFilter.community}
|
||||
onChange={(val) => setEditingFilter({ ...editingFilter, community: val })}
|
||||
communities={communities}
|
||||
baseAS={baseAS}
|
||||
required
|
||||
/>
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ export default function SettingsModal({ open, onClose }) {
|
||||
const [etag, setEtag] = useState('');
|
||||
const [dohServer, setDohServer] = useState('');
|
||||
const [wsUrl, setWsUrl] = useState('');
|
||||
const [baseAS, setBaseAS] = useState('65001');
|
||||
|
||||
useEffect(() => {
|
||||
if (!open) return;
|
||||
@@ -29,6 +30,7 @@ export default function SettingsModal({ open, onClose }) {
|
||||
const data = res?.data || {};
|
||||
setDohServer(String(data?.dohServer || ''));
|
||||
setWsUrl(String(data?.wsUpdateUrl || ''));
|
||||
setBaseAS(String(data?.baseAS || '65001'));
|
||||
const e = res?.headers?.etag || res?.headers?.ETag || '';
|
||||
setEtag(e ? String(e) : '');
|
||||
} catch (e) {
|
||||
@@ -87,7 +89,8 @@ export default function SettingsModal({ open, onClose }) {
|
||||
const payload = {
|
||||
settings: {
|
||||
dohServer: String(dohServer || '').trim(),
|
||||
wsUpdateUrl: String(wsUrl || '').trim()
|
||||
wsUpdateUrl: String(wsUrl || '').trim(),
|
||||
baseAS: String(baseAS || '65001').trim()
|
||||
},
|
||||
etag
|
||||
};
|
||||
@@ -172,6 +175,17 @@ export default function SettingsModal({ open, onClose }) {
|
||||
helpText="HTTPS URL для DNS-over-HTTPS"
|
||||
disabled={loading || saving}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
label="Базовая AS"
|
||||
name="baseAS"
|
||||
type="text"
|
||||
value={baseAS}
|
||||
onChange={setBaseAS}
|
||||
placeholder="65001"
|
||||
helpText="AS по умолчанию для community (например, 65001). Используется при поиске и нормализации community."
|
||||
disabled={loading || saving}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="modal-footer">
|
||||
|
||||
Reference in New Issue
Block a user