Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m52s
224 lines
8.9 KiB
React
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;
|
|
|
|
|