Publish Docker image / build-and-push (push) Successful in 2m12s
Restore project files to match the requested baseline before subsequent updates. Made-with: Cursor
183 lines
7.3 KiB
React
183 lines
7.3 KiB
React
import { useState, useEffect, useRef } from 'react';
|
|
import { IconLink, IconDownload } from '@tabler/icons-react';
|
|
|
|
/**
|
|
* Модальное окно генератора ссылок для сервера
|
|
*/
|
|
function LinkGeneratorModal({ show, server, urlSettings, onUrlSettingsChange, onGenerateUrl, onCopyToClipboard, onClose }) {
|
|
const modalRef = useRef(null);
|
|
const [localUrlSettings, setLocalUrlSettings] = useState(urlSettings);
|
|
|
|
useEffect(() => {
|
|
setLocalUrlSettings(urlSettings);
|
|
}, [urlSettings]);
|
|
|
|
useEffect(() => {
|
|
const modalEl = modalRef.current;
|
|
if (window.Tabler && window.Tabler.Modal && modalEl) {
|
|
const modalInstance = window.Tabler.Modal.getOrCreateInstance(modalEl);
|
|
if (show) {
|
|
modalInstance.show();
|
|
} else {
|
|
modalInstance.hide();
|
|
}
|
|
const handler = () => onClose && onClose();
|
|
modalEl.addEventListener('hide.bs.modal', handler);
|
|
return () => {
|
|
modalEl.removeEventListener('hide.bs.modal', handler);
|
|
};
|
|
}
|
|
}, [show, onClose]);
|
|
|
|
const handleSettingChange = (key, value) => {
|
|
const updated = { ...localUrlSettings, [key]: value };
|
|
setLocalUrlSettings(updated);
|
|
onUrlSettingsChange(updated);
|
|
};
|
|
|
|
const handleSaveSettings = () => {
|
|
onUrlSettingsChange(localUrlSettings);
|
|
localStorage.setItem('urlSettings', JSON.stringify(localUrlSettings));
|
|
};
|
|
|
|
const generatedUrl = server ? onGenerateUrl(server) : '';
|
|
|
|
return (
|
|
<div className="modal modal-lg" tabIndex="-1" ref={modalRef}>
|
|
<div className="modal-dialog">
|
|
<div className="modal-content">
|
|
<div className="modal-header">
|
|
<h5 className="modal-title">
|
|
<IconLink className="icon me-2" />
|
|
Генератор ссылок для {server?.ip}
|
|
</h5>
|
|
<button type="button" className="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
</div>
|
|
<div className="modal-body">
|
|
<div className="row g-2">
|
|
<div className="col-12 col-md-6">
|
|
<h6 className="mb-3">Настройки URL</h6>
|
|
<div className="mb-3">
|
|
<label className="form-label">Базовый URL</label>
|
|
<input
|
|
type="text"
|
|
className="form-control"
|
|
value={localUrlSettings.baseUrl}
|
|
onChange={e => handleSettingChange('baseUrl', e.target.value)}
|
|
placeholder="https://functions.yandexcloud.net/d4eno3im0qgsr4tj5hdo"
|
|
/>
|
|
</div>
|
|
<div className="mb-3">
|
|
<label className="form-label">Cloudflare Gateway</label>
|
|
<input
|
|
type="text"
|
|
className="form-control"
|
|
value={localUrlSettings.cloudflare_gateway}
|
|
onChange={e => handleSettingChange('cloudflare_gateway', e.target.value)}
|
|
placeholder="SWE-IHOR или IP"
|
|
/>
|
|
</div>
|
|
<div className="mb-3">
|
|
<label className="form-label">Bunny Gateway</label>
|
|
<input
|
|
type="text"
|
|
className="form-control"
|
|
value={localUrlSettings.bunny_gateway}
|
|
onChange={e => handleSettingChange('bunny_gateway', e.target.value)}
|
|
placeholder="SWE-IHOR или IP"
|
|
/>
|
|
</div>
|
|
<div className="mb-3">
|
|
<label className="form-label">Fastly Gateway</label>
|
|
<input
|
|
type="text"
|
|
className="form-control"
|
|
value={localUrlSettings.fastly_gateway}
|
|
onChange={e => handleSettingChange('fastly_gateway', e.target.value)}
|
|
placeholder="SWE-IHOR или IP"
|
|
/>
|
|
</div>
|
|
</div>
|
|
<div className="col-12 col-md-6">
|
|
<div className="mb-3">
|
|
<label className="form-label">Telegram Gateway</label>
|
|
<input
|
|
type="text"
|
|
className="form-control"
|
|
value={localUrlSettings.telegram_gateway}
|
|
onChange={e => handleSettingChange('telegram_gateway', e.target.value)}
|
|
placeholder="IP адрес"
|
|
/>
|
|
</div>
|
|
<div className="mb-3">
|
|
<label className="form-label">Hetzner Gateway</label>
|
|
<input
|
|
type="text"
|
|
className="form-control"
|
|
value={localUrlSettings.hetzner_gateway}
|
|
onChange={e => handleSettingChange('hetzner_gateway', e.target.value)}
|
|
placeholder="IP адрес"
|
|
/>
|
|
</div>
|
|
<div className="mb-3">
|
|
<label className="form-label">Тип</label>
|
|
<input
|
|
type="text"
|
|
className="form-control"
|
|
value={localUrlSettings.type}
|
|
onChange={e => handleSettingChange('type', e.target.value)}
|
|
placeholder="routes"
|
|
/>
|
|
</div>
|
|
<div className="mb-3">
|
|
<label className="form-label">Версия</label>
|
|
<input
|
|
type="text"
|
|
className="form-control"
|
|
value={localUrlSettings.version}
|
|
onChange={e => handleSettingChange('version', e.target.value)}
|
|
placeholder="v4.rsc"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="mt-4">
|
|
<h6 className="mb-3">Сгенерированная ссылка</h6>
|
|
<div className="input-group">
|
|
<input
|
|
type="text"
|
|
className="form-control"
|
|
value={generatedUrl}
|
|
readOnly
|
|
style={{ fontFamily: 'monospace', fontSize: '0.875rem' }}
|
|
/>
|
|
<button
|
|
className="btn btn-outline-secondary d-flex align-items-center"
|
|
type="button"
|
|
onClick={() => onCopyToClipboard(generatedUrl)}
|
|
title="Копировать в буфер обмена"
|
|
>
|
|
<span className="me-2 d-flex align-items-center"><IconDownload size={18} /></span>
|
|
<span className="fw-bold">Копировать</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div className="modal-footer">
|
|
<button type="button" className="btn btn-secondary d-flex align-items-center" data-bs-dismiss="modal">
|
|
<span className="fw-bold">Закрыть</span>
|
|
</button>
|
|
<button type="button" className="btn btn-primary d-flex align-items-center" onClick={handleSaveSettings}>
|
|
<span className="fw-bold">Сохранить настройки</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export default LinkGeneratorModal;
|
|
|