feat: Enhance EasySwitchManager with initial state tracking and server expansion toggle, improving user interaction and state management for gateway selections.
Publish Fast Tabler Docker image / build-and-push-fast (push) Failing after 1m15s
Publish Fast Tabler Docker image / build-and-push-fast (push) Failing after 1m15s
This commit is contained in:
@@ -11,7 +11,9 @@ import {
|
|||||||
IconX,
|
IconX,
|
||||||
IconSettings,
|
IconSettings,
|
||||||
IconDeviceFloppy,
|
IconDeviceFloppy,
|
||||||
IconBolt
|
IconBolt,
|
||||||
|
IconChevronDown,
|
||||||
|
IconChevronUp
|
||||||
} from '@tabler/icons-react';
|
} from '@tabler/icons-react';
|
||||||
|
|
||||||
// Функция для получения флага по коду страны
|
// Функция для получения флага по коду страны
|
||||||
@@ -41,7 +43,9 @@ function EasySwitchManager() {
|
|||||||
|
|
||||||
// Активные шлюзы для каждого community (ключ: community, значение: gateway name)
|
// Активные шлюзы для каждого community (ключ: community, значение: gateway name)
|
||||||
const [activeGateways, setActiveGateways] = useState({});
|
const [activeGateways, setActiveGateways] = useState({});
|
||||||
|
const [initialGateways, setInitialGateways] = useState({}); // Исходное состояние для отслеживания изменений
|
||||||
const [hasChanges, setHasChanges] = useState(false);
|
const [hasChanges, setHasChanges] = useState(false);
|
||||||
|
const [expandedServers, setExpandedServers] = useState(new Set()); // Развернутые серверы
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const initData = async () => {
|
const initData = async () => {
|
||||||
@@ -142,21 +146,26 @@ function EasySwitchManager() {
|
|||||||
const serversWithGateways = serversWithData.filter(s => s.gateways.length > 0);
|
const serversWithGateways = serversWithData.filter(s => s.gateways.length > 0);
|
||||||
setServers(serversWithGateways);
|
setServers(serversWithGateways);
|
||||||
|
|
||||||
// Устанавливаем активные шлюзы из filters или первый gateway
|
// Автоматически разворачиваем первый сервер
|
||||||
|
if (serversWithGateways.length > 0 && expandedServers.size === 0) {
|
||||||
|
setExpandedServers(new Set([serversWithGateways[0].id]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Устанавливаем активные шлюзы ТОЛЬКО из filters (не добавляем дефолтные)
|
||||||
const initialActive = {};
|
const initialActive = {};
|
||||||
serversWithGateways.forEach(server => {
|
serversWithGateways.forEach(server => {
|
||||||
communities.forEach(comm => {
|
communities.forEach(comm => {
|
||||||
const key = `${server.id}:${comm.value}`;
|
const key = `${server.id}:${comm.value}`;
|
||||||
// Берем gateway из filters, если есть, иначе первый доступный
|
// Берем gateway ТОЛЬКО из filters
|
||||||
const gatewayFromFilter = server.filtersMap.get(comm.value);
|
const gatewayFromFilter = server.filtersMap.get(comm.value);
|
||||||
if (gatewayFromFilter && server.gateways.find(g => g.name === gatewayFromFilter)) {
|
if (gatewayFromFilter && server.gateways.find(g => g.name === gatewayFromFilter)) {
|
||||||
initialActive[key] = gatewayFromFilter;
|
initialActive[key] = gatewayFromFilter;
|
||||||
} else if (server.gateways.length > 0) {
|
|
||||||
initialActive[key] = server.gateways[0].name;
|
|
||||||
}
|
}
|
||||||
|
// Если нет в filters - НЕ устанавливаем дефолтное значение
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
setActiveGateways(initialActive);
|
setActiveGateways(initialActive);
|
||||||
|
setInitialGateways({ ...initialActive }); // Сохраняем исходное состояние
|
||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Error loading data:', err);
|
console.error('Error loading data:', err);
|
||||||
@@ -168,11 +177,32 @@ function EasySwitchManager() {
|
|||||||
|
|
||||||
const handleGatewaySelect = (serverId, community, gateway) => {
|
const handleGatewaySelect = (serverId, community, gateway) => {
|
||||||
const key = `${serverId}:${community}`;
|
const key = `${serverId}:${community}`;
|
||||||
setActiveGateways(prev => ({
|
setActiveGateways(prev => {
|
||||||
...prev,
|
const newState = {
|
||||||
[key]: gateway
|
...prev,
|
||||||
}));
|
[key]: gateway
|
||||||
setHasChanges(true);
|
};
|
||||||
|
|
||||||
|
// Проверяем, есть ли реальные изменения относительно исходного состояния
|
||||||
|
const hasRealChanges = Object.keys(newState).some(k => {
|
||||||
|
return newState[k] !== initialGateways[k];
|
||||||
|
});
|
||||||
|
|
||||||
|
setHasChanges(hasRealChanges);
|
||||||
|
return newState;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const toggleServerExpanded = (serverId) => {
|
||||||
|
setExpandedServers(prev => {
|
||||||
|
const newSet = new Set(prev);
|
||||||
|
if (newSet.has(serverId)) {
|
||||||
|
newSet.delete(serverId);
|
||||||
|
} else {
|
||||||
|
newSet.add(serverId);
|
||||||
|
}
|
||||||
|
return newSet;
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleApplyChanges = async () => {
|
const handleApplyChanges = async () => {
|
||||||
@@ -180,10 +210,22 @@ function EasySwitchManager() {
|
|||||||
setError('');
|
setError('');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Группируем изменения по serverId
|
// Находим только РЕАЛЬНО измененные записи
|
||||||
|
const changedEntries = Object.entries(activeGateways).filter(([key, gateway]) => {
|
||||||
|
return initialGateways[key] !== gateway;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (changedEntries.length === 0) {
|
||||||
|
setError('Нет изменений для сохранения');
|
||||||
|
setLoading(false);
|
||||||
|
setTimeout(() => setError(''), 3000);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Группируем ТОЛЬКО измененные записи по serverId
|
||||||
const changesByServer = new Map();
|
const changesByServer = new Map();
|
||||||
|
|
||||||
Object.entries(activeGateways).forEach(([key, gateway]) => {
|
changedEntries.forEach(([key, gateway]) => {
|
||||||
const [serverId, community] = key.split(':');
|
const [serverId, community] = key.split(':');
|
||||||
if (!changesByServer.has(serverId)) {
|
if (!changesByServer.has(serverId)) {
|
||||||
changesByServer.set(serverId, new Map());
|
changesByServer.set(serverId, new Map());
|
||||||
@@ -191,7 +233,7 @@ function EasySwitchManager() {
|
|||||||
changesByServer.get(serverId).set(community, gateway);
|
changesByServer.get(serverId).set(community, gateway);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Обновляем фильтры для каждого сервера
|
// Обновляем фильтры ТОЛЬКО для серверов с изменениями
|
||||||
const updatePromises = Array.from(changesByServer.entries()).map(async ([serverId, communitiesMap]) => {
|
const updatePromises = Array.from(changesByServer.entries()).map(async ([serverId, communitiesMap]) => {
|
||||||
try {
|
try {
|
||||||
// Получаем текущие фильтры сервера
|
// Получаем текущие фильтры сервера
|
||||||
@@ -250,7 +292,7 @@ function EasySwitchManager() {
|
|||||||
setHasChanges(false);
|
setHasChanges(false);
|
||||||
setSuccess(`✅ Изменения успешно применены для ${successCount} ${successCount === 1 ? 'сервера' : 'серверов'}`);
|
setSuccess(`✅ Изменения успешно применены для ${successCount} ${successCount === 1 ? 'сервера' : 'серверов'}`);
|
||||||
setTimeout(() => setSuccess(''), 3000);
|
setTimeout(() => setSuccess(''), 3000);
|
||||||
// Перезагружаем данные чтобы обновить бейджи "настроен"
|
// Перезагружаем данные чтобы обновить бейджи "настроен" и сбросить initialGateways
|
||||||
await handleRefresh();
|
await handleRefresh();
|
||||||
} else {
|
} else {
|
||||||
setError(`Не удалось обновить ${errorCount} ${errorCount === 1 ? 'сервер' : 'серверов'}. Успешно: ${successCount}.`);
|
setError(`Не удалось обновить ${errorCount} ${errorCount === 1 ? 'сервер' : 'серверов'}. Успешно: ${successCount}.`);
|
||||||
@@ -469,6 +511,31 @@ function EasySwitchManager() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Инструменты */}
|
{/* Инструменты */}
|
||||||
|
<div className="col-auto">
|
||||||
|
<button
|
||||||
|
className="btn btn-outline-secondary btn-sm"
|
||||||
|
onClick={() => {
|
||||||
|
if (expandedServers.size === filteredServers.length) {
|
||||||
|
setExpandedServers(new Set());
|
||||||
|
} else {
|
||||||
|
setExpandedServers(new Set(filteredServers.map(s => s.id)));
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
title={expandedServers.size === filteredServers.length ? "Свернуть все" : "Развернуть все"}
|
||||||
|
>
|
||||||
|
{expandedServers.size === filteredServers.length ? (
|
||||||
|
<>
|
||||||
|
<IconChevronUp size={18} className="me-1" />
|
||||||
|
Свернуть все
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<IconChevronDown size={18} className="me-1" />
|
||||||
|
Развернуть все
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
<div className="col-auto">
|
<div className="col-auto">
|
||||||
<button className="btn btn-icon" title="Настройки">
|
<button className="btn btn-icon" title="Настройки">
|
||||||
<IconSettings size={18} />
|
<IconSettings size={18} />
|
||||||
@@ -511,11 +578,28 @@ function EasySwitchManager() {
|
|||||||
// Не показываем сервер, если нет отфильтрованных communities
|
// Не показываем сервер, если нет отфильтрованных communities
|
||||||
if (filteredCommunitiesForServer.length === 0) return null;
|
if (filteredCommunitiesForServer.length === 0) return null;
|
||||||
|
|
||||||
|
const isExpanded = expandedServers.has(server.id);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div key={server.id} className="card mb-3">
|
<div key={server.id} className="card mb-3">
|
||||||
{/* Заголовок сервера */}
|
{/* Заголовок сервера (кликабельный) */}
|
||||||
<div className="card-header py-2" style={{ backgroundColor: 'rgba(32, 107, 196, 0.05)' }}>
|
<div
|
||||||
|
className="card-header py-2"
|
||||||
|
style={{
|
||||||
|
backgroundColor: 'rgba(32, 107, 196, 0.05)',
|
||||||
|
cursor: 'pointer',
|
||||||
|
userSelect: 'none'
|
||||||
|
}}
|
||||||
|
onClick={() => toggleServerExpanded(server.id)}
|
||||||
|
>
|
||||||
<div className="d-flex align-items-center">
|
<div className="d-flex align-items-center">
|
||||||
|
{/* Иконка сворачивания */}
|
||||||
|
{isExpanded ? (
|
||||||
|
<IconChevronUp size={20} className="me-2 text-muted" />
|
||||||
|
) : (
|
||||||
|
<IconChevronDown size={20} className="me-2 text-muted" />
|
||||||
|
)}
|
||||||
|
|
||||||
{flag && <span className="me-2" style={{ fontSize: '1.5rem' }}>{flag}</span>}
|
{flag && <span className="me-2" style={{ fontSize: '1.5rem' }}>{flag}</span>}
|
||||||
<IconServer size={20} className="me-2 text-primary" />
|
<IconServer size={20} className="me-2 text-primary" />
|
||||||
<h3 className="card-title mb-0 me-2">{server.name}</h3>
|
<h3 className="card-title mb-0 me-2">{server.name}</h3>
|
||||||
@@ -528,7 +612,9 @@ function EasySwitchManager() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="card-body p-3">
|
{/* Контент (сворачиваемый) */}
|
||||||
|
{isExpanded && (
|
||||||
|
<div className="card-body p-3">
|
||||||
{/* Сетка Communities для этого сервера */}
|
{/* Сетка Communities для этого сервера */}
|
||||||
<div className="row g-3">
|
<div className="row g-3">
|
||||||
{filteredCommunitiesForServer.map((comm) => {
|
{filteredCommunitiesForServer.map((comm) => {
|
||||||
@@ -647,7 +733,7 @@ function EasySwitchManager() {
|
|||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
|||||||
Reference in New Issue
Block a user