Files
router-lists-ui/frontend/src/components/PageHeaderActions.jsx
T

224 lines
8.9 KiB
React

import {
IconRefresh,
IconUpload,
IconDownload,
IconDeviceFloppy,
IconPlayerPlay,
IconBolt,
IconEraser,
IconDots,
IconEye
} from '@tabler/icons-react';
import PortalDropdown from './PortalDropdown.jsx';
import { IconClock } from '@tabler/icons-react';
import { formatDateTimeWithRelative } from '../lib/datetime.js';
function PageHeaderActions({
loading = false,
onPreview,
disablePreview = false,
onRefresh,
disableRefresh = false,
onImport,
onExport,
disableExport = false,
onClear,
disableClear = false,
onClearCommunities,
disableClearCommunities = false,
onSave,
disableSave = false,
onHistory,
lastModified,
onOnlineUpdate,
onBackgroundUpdate,
}) {
const secondaryButtons = Boolean(onPreview || onImport || onExport || onClear || onClearCommunities || onHistory);
// Рендер плейсхолдеров во время загрузки/перезагрузки страницы
if (loading) {
const showUpdateGroup = Boolean(onBackgroundUpdate || onOnlineUpdate);
const placeholderBtn = (width = 120) => (
<span
className="btn disabled placeholder me-2"
style={{ height: 38, width }}
aria-hidden="true"
/>
);
return (
<div className="header-actions" role="toolbar" aria-label="Действия страницы (загрузка)">
<div className="btn-group">
{showUpdateGroup && (
<div className="btn-group">
{placeholderBtn(170)}
</div>
)}
</div>
<span className="vr d-none d-lg-inline" />
<div className="btn-group">
{onRefresh && placeholderBtn(120)}
{(onImport || onExport) && placeholderBtn(160)}
{onClear && placeholderBtn(130)}
{onClearCommunities && placeholderBtn(180)}
{onSave && placeholderBtn(140)}
{onHistory && placeholderBtn(110)}
</div>
</div>
);
}
return (
<div className="header-actions" role="toolbar" aria-label="Действия страницы">
<div className="btn-group">
{(onBackgroundUpdate || onOnlineUpdate) && (
<div className="btn-group">
{/* Дефолтное действие — фоновое обновление */}
<button
className="btn btn-outline-success"
type="button"
onClick={onBackgroundUpdate || onOnlineUpdate}
title="Фоновое обновление BGP (POST)"
>
<IconPlayerPlay className="me-1" /> Фоновое обновление
</button>
{(onBackgroundUpdate && onOnlineUpdate) && (
<PortalDropdown
buttonClassName="btn btn-outline-success dropdown-toggle dropdown-toggle-split"
buttonProps={{ 'aria-label': 'Другие варианты обновления' }}
align="right"
buttonContent={null}
>
<button className="dropdown-item" type="button" onClick={onBackgroundUpdate}>
<IconPlayerPlay className="me-1" /> Фоновое обновление
</button>
<button className="dropdown-item" type="button" onClick={onOnlineUpdate}>
<IconBolt className="me-1" /> Online-обновление
</button>
</PortalDropdown>
)}
</div>
)}
</div>
<span className="vr d-none d-lg-inline" />
<div className="btn-group d-none d-sm-inline-flex">
{onPreview && (
<button className="btn btn-outline-primary" type="button" onClick={onPreview} disabled={disablePreview} title="Предпросмотр изменений">
<IconEye className="me-1" /> Предпросмотр
</button>
)}
{onRefresh && (
<button className="btn btn-outline-secondary" type="button" onClick={onRefresh} disabled={disableRefresh} title="Обновить данные">
<IconRefresh className={loading ? 'spin me-1' : 'me-1'} /> Обновить
</button>
)}
{(onImport || onExport) && (
<div className="dropdown">
<PortalDropdown
buttonClassName="btn btn-outline-primary dropdown-toggle"
buttonProps={{ title: 'Импорт/Экспорт' }}
align="left"
buttonContent={<><IconDownload className="me-1" /> Импорт/Экспорт</>}
>
{onImport && (
<button className="dropdown-item" type="button" onClick={onImport}>
<IconUpload className="me-1" /> Импорт
</button>
)}
{onExport && (
<button className="dropdown-item" type="button" onClick={onExport} disabled={disableExport}>
<IconDownload className="me-1" /> Экспорт
</button>
)}
</PortalDropdown>
</div>
)}
{onClear && (
<button className="btn btn-outline-secondary" type="button" onClick={onClear} disabled={disableClear} title="Очистить пустые/невалидные">
Очистить
</button>
)}
{onClearCommunities && (
<button className="btn btn-outline-secondary" type="button" onClick={onClearCommunities} disabled={disableClearCommunities} title="Удалить все записи выбранного community">
<IconEraser className="me-1" /> Очистить community
</button>
)}
{onSave && (
<button className="btn btn-primary" type="button" onClick={onSave} disabled={disableSave} title="Сохранить">
{loading ? (
<>
<span className="spinner-border spinner-border-sm me-2" role="status"></span>
Сохранение...
</>
) : (
<>
<IconDeviceFloppy className="me-1" /> Сохранить
</>
)}
</button>
)}
{onHistory && (
<div className="btn-group">
<button className="btn btn-outline-secondary" type="button" onClick={onHistory} title="История версий">История</button>
{lastModified && (
<button className="btn btn-outline-secondary" type="button" onClick={onHistory} title={`Последние изменения: ${formatDateTimeWithRelative(lastModified)}`}>
<IconClock className="me-1" />
<span className="d-none d-sm-inline">{formatDateTimeWithRelative(lastModified)}</span>
<span className="d-inline d-sm-none">{formatDateTimeWithRelative(lastModified)}</span>
</button>
)}
</div>
)}
</div>
{/* Компактное меню для маленьких экранов */}
{secondaryButtons && (
<div className="btn-group d-inline-flex d-sm-none">
<PortalDropdown
buttonClassName="btn btn-outline-secondary"
buttonProps={{ title: 'Ещё действия' }}
align="left"
buttonContent={<><IconDots className="me-1" /> Ещё</>}
>
{onPreview && (
<button className="dropdown-item" type="button" onClick={onPreview} disabled={disablePreview}>
<IconEye className="me-1" /> Предпросмотр
</button>
)}
{onRefresh && (
<button className="dropdown-item" type="button" onClick={onRefresh} disabled={disableRefresh}>
<IconRefresh className="me-1" /> Обновить
</button>
)}
{onImport && (
<button className="dropdown-item" type="button" onClick={onImport}>
<IconUpload className="me-1" /> Импорт
</button>
)}
{onExport && (
<button className="dropdown-item" type="button" onClick={onExport} disabled={disableExport}>
<IconDownload className="me-1" /> Экспорт
</button>
)}
{onClear && (
<button className="dropdown-item" type="button" onClick={onClear} disabled={disableClear}>
Очистить
</button>
)}
{onClearCommunities && (
<button className="dropdown-item" type="button" onClick={onClearCommunities} disabled={disableClearCommunities}>
<IconEraser className="me-1" /> Очистить community
</button>
)}
{onHistory && (
<button className="dropdown-item" type="button" onClick={onHistory}>
История
</button>
)}
</PortalDropdown>
</div>
)}
</div>
);
}
export default PageHeaderActions;