feat(NetworkConfigManager, PreviewConfigModal): improve clipboard functionality for MikroTik code; add title and description props to preview modal
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m37s

This commit is contained in:
2026-01-22 11:14:54 +07:00
parent 682c2ce96b
commit 03a47e7346
2 changed files with 70 additions and 18 deletions
+27 -1
View File
@@ -552,7 +552,31 @@ function NetworkConfigManager() {
// === Копирование кода MikroTik ===
const handleCopyMikrotikCode = async () => {
await copyToClipboard(generatedMikrotikCode);
try {
if (navigator.clipboard && navigator.clipboard.writeText) {
await navigator.clipboard.writeText(generatedMikrotikCode);
notify.success('Код скопирован в буфер обмена!');
} else {
// Fallback для старых браузеров
const textArea = document.createElement('textarea');
textArea.value = generatedMikrotikCode;
textArea.style.position = 'fixed';
textArea.style.left = '-999999px';
document.body.appendChild(textArea);
textArea.focus();
textArea.select();
try {
document.execCommand('copy');
notify.success('Код скопирован в буфер обмена!');
} catch (err) {
notify.error('Не удалось скопировать код');
}
document.body.removeChild(textArea);
}
} catch (err) {
console.error('Error copying to clipboard:', err);
notify.error('Не удалось скопировать код');
}
};
// === Получение цвета провайдера ===
@@ -1621,6 +1645,8 @@ function NetworkConfigManager() {
show={mikrotikCodeModalOpen}
config={generatedMikrotikCode}
mode="advanced"
title="Предварительный просмотр конфигурации"
description="Конфигурация MikroTik RouterOS для рекурсивных маршрутов"
onClose={() => setMikrotikCodeModalOpen(false)}
onCopy={handleCopyMikrotikCode}
/>
@@ -1,12 +1,13 @@
import { IconFilter, IconCopy } from '@tabler/icons-react';
import { IconFilter, IconCopy, IconEye } from '@tabler/icons-react';
/**
* Модальное окно предварительного просмотра конфигурации
*/
function PreviewConfigModal({ show, config, mode, onClose, onCopy }) {
function PreviewConfigModal({ show, config, mode, onClose, onCopy, title, description }) {
if (!show) return null;
const getModalTitle = () => {
if (title) return title;
if (mode === 'simple') {
return 'Предварительный просмотр конфигурации MikroTik (упрощённый режим)';
} else if (mode === 'advanced') {
@@ -25,7 +26,16 @@ function PreviewConfigModal({ show, config, mode, onClose, onCopy }) {
};
const getConfigInfo = () => {
if (config.includes('// Сначала выберите сервер') || config.includes('// Нет фильтров для генерации конфигурации')) {
if (description) {
return (
<div className="alert alert-info mb-3">
<IconEye className="me-2" />
{description}
</div>
);
}
if (config.includes('// Сначала выберите сервер') || config.includes('// Нет фильтров для генерации конфигурации') || config.includes('// Нет рекурсивных gateway')) {
return <div className="alert alert-warning mb-3">Нет данных для генерации конфигурации</div>;
}
@@ -42,9 +52,18 @@ function PreviewConfigModal({ show, config, mode, onClose, onCopy }) {
);
}
return null;
return (
<div className="alert alert-info mb-3">
<IconEye className="me-2" />
Конфигурация MikroTik RouterOS для применения фильтров
</div>
);
};
const isConfigEmpty = config.includes('// Сначала выберите сервер') ||
config.includes('// Нет фильтров для генерации конфигурации') ||
config.includes('// Нет рекурсивных gateway');
return (
<div className="modal show d-block" style={{ backgroundColor: 'rgba(0,0,0,0.5)' }}>
<div className="modal-dialog modal-lg">
@@ -58,26 +77,33 @@ function PreviewConfigModal({ show, config, mode, onClose, onCopy }) {
</div>
<div className="modal-body">
{getConfigInfo()}
<div className="mb-3">
<div className="btn-list">
<button
className="btn btn-outline-primary"
onClick={onCopy}
disabled={config.includes('// Сначала выберите сервер') || config.includes('// Нет фильтров для генерации конфигурации')}
>
<IconCopy className="me-2" />
Копировать в буфер обмена
</button>
</div>
</div>
<pre className="bg-dark text-light p-3 rounded" style={{ maxHeight: '400px', overflow: 'auto' }}>
<pre className="bg-dark text-white p-3 rounded" style={{ maxHeight: '500px', overflow: 'auto' }}>
<code>{config}</code>
</pre>
<div className="mt-3 text-muted small">
<p className="mb-1"><strong>Инструкция по применению:</strong></p>
<ol className="mb-0">
<li>Скопируйте конфигурацию в буфер обмена</li>
<li>Подключитесь к MikroTik через SSH или Winbox</li>
<li>Вставьте конфигурацию в терминал</li>
<li>Проверьте применение командой: <code>/routing filter print</code> или <code>/ip route print</code></li>
</ol>
</div>
</div>
<div className="modal-footer">
<button type="button" className="btn btn-secondary" onClick={onClose}>
Закрыть
</button>
<button
type="button"
className="btn btn-primary"
onClick={onCopy}
disabled={isConfigEmpty}
>
<IconCopy className="me-2" />
Копировать в буфер
</button>
</div>
</div>
</div>