Files
MikrotikManager/components/data-page-toolbar.tsx
T
DenozordecandCursor cff26813b9
Docker images / prepare-release (push) Successful in 9s
Docker images / backend-test (push) Successful in 2m18s
Docker images / frontend-image (push) Successful in 4m37s
Docker images / updater-image (push) Successful in 46s
Docker images / backend-image (push) Successful in 3m6s
Docker images / notify-webhook (push) Skipped
Docker images / publish-release (push) Successful in 16s
feat(backups): добавить S3-хранилище и обновить экран бэкапов
Сохранять снимки в S3-compatible бакет, скачивать и удалять их вместе с локальными файлами.
Привести /backups к DNA /servers: Frame, KPI, фильтры и реальное восстановление.

Co-authored-by: Cursor <[email protected]>
2026-09-08 14:06:27 +07:00

110 lines
2.7 KiB
TypeScript

"use client"
import { ReactNode } from "react"
import { ListFilterIcon, SearchIcon } from "lucide-react"
import { cn } from "@/lib/utils"
import {
InputGroup,
InputGroupAddon,
InputGroupInput,
} from "@/components/ui/input-group"
import { Button } from "@/components/ui/button"
import {
Filters,
type Filter,
type FilterFieldConfig,
} from "@/components/reui/filters"
import { SegmentedControl } from "@/components/form-kit"
import { DATA_PAGE_TOOLBAR_CLASS } from "@/components/data-grids/shared/data-grid-layout"
function DataPageToolbarFrame({
children,
className,
}: {
children: ReactNode
className?: string
}) {
return (
<div className={cn(DATA_PAGE_TOOLBAR_CLASS, className)}>
{children}
</div>
)
}
interface DataPageToolbarProps<T extends string = string> {
leading?: ReactNode
search?: string
onSearchChange?: (value: string) => void
searchPlaceholder?: string
segmented?: {
value: T
onChange: (value: T) => void
options: { value: T; label: string; count?: number }[]
}
filters?: Filter[]
onFiltersChange?: (filters: Filter[]) => void
filterFields?: FilterFieldConfig[]
countLabel?: string
actions?: ReactNode
className?: string
}
function DataPageToolbar<T extends string = string>({
leading,
search,
onSearchChange,
searchPlaceholder = "Поиск…",
segmented,
filters,
onFiltersChange,
filterFields,
countLabel,
actions,
className,
}: DataPageToolbarProps<T>) {
return (
<DataPageToolbarFrame className={className}>
{leading}
{segmented && (
<SegmentedControl
value={segmented.value}
onChange={segmented.onChange}
options={segmented.options}
/>
)}
{filterFields && filters && onFiltersChange && (
<Filters
filters={filters}
fields={filterFields}
onChange={onFiltersChange}
size="sm"
trigger={
<Button type="button" variant="outline" size="sm">
<ListFilterIcon className="size-3.5" />
Фильтры
</Button>
}
/>
)}
{onSearchChange != null && (
<InputGroup className="min-w-[220px] max-w-sm">
<InputGroupAddon>
<SearchIcon className="size-3.5" />
</InputGroupAddon>
<InputGroupInput
placeholder={searchPlaceholder}
value={search ?? ""}
onChange={(e) => onSearchChange(e.target.value)}
/>
</InputGroup>
)}
{countLabel && (
<span className="text-sm text-muted-foreground ml-auto">{countLabel}</span>
)}
{actions}
</DataPageToolbarFrame>
)
}
export { DataPageToolbar, DataPageToolbarFrame, type DataPageToolbarProps }