feat(design-preview): перетаскивание строк в «Ссылках приложений» через dnd-kit
quality / changes (push) Successful in 9s
quality / commitlint (push) Skipped
quality / docker-check (push) Skipped
quality / web (push) Successful in 1m32s
quality / api (push) Successful in 42s
CD / quality (push) Successful in 2m25s
CD / publish (push) Successful in 2m52s
quality / changes (push) Successful in 9s
quality / commitlint (push) Skipped
quality / docker-check (push) Skipped
quality / web (push) Successful in 1m32s
quality / api (push) Successful in 42s
CD / quality (push) Successful in 2m25s
CD / publish (push) Successful in 2m52s
PreviewSectionGrid получил onReorder: ручка DataGridTableDndRowHandle и DataGridTableDndRows из ReUI. Порядок меняется перетаскиванием, меню строки осталось запасным путём. Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
This commit is contained in:
1 parent
4f5026980a
commit
41f5669812
2 files changed
+50
-9
No files matched your search
@@ -4,7 +4,6 @@ import {
|
||||
CloudIcon,
|
||||
EyeIcon,
|
||||
FingerprintIcon,
|
||||
GripVerticalIcon,
|
||||
KeyRoundIcon,
|
||||
LayoutDashboardIcon,
|
||||
LayoutGridIcon,
|
||||
@@ -141,6 +140,15 @@ export function AppLinksPage() {
|
||||
[addChange],
|
||||
)
|
||||
|
||||
/** Перетаскивание: строка встаёт на место той, на которую её бросили. */
|
||||
const dropOn = useCallback(
|
||||
(activeId: string, overId: string) => {
|
||||
const to = rowsRef.current.findIndex((r) => r.id === overId)
|
||||
if (to >= 0) moveTo(activeId as AppId, () => to)
|
||||
},
|
||||
[moveTo],
|
||||
)
|
||||
|
||||
const resetOrder = useCallback(() => {
|
||||
const before = rowsRef.current
|
||||
if (before.every((r, i) => r.id === INITIAL[i]?.id)) return
|
||||
@@ -158,10 +166,9 @@ export function AppLinksPage() {
|
||||
{
|
||||
id: 'order',
|
||||
title: '№',
|
||||
size: 76,
|
||||
size: 52,
|
||||
cell: (r) => (
|
||||
<span className="text-muted-foreground flex items-center gap-1 text-xs tabular-nums">
|
||||
<GripVerticalIcon className="size-4" aria-hidden />
|
||||
<span className="text-muted-foreground text-sm tabular-nums">
|
||||
{rows.findIndex((x) => x.id === r.id) + 1}
|
||||
</span>
|
||||
),
|
||||
@@ -267,7 +274,7 @@ export function AppLinksPage() {
|
||||
<TabsContent value="list" className="min-w-0">
|
||||
<PreviewSectionGrid
|
||||
title="Ссылки сервисов"
|
||||
description="Порядок строк = порядок в меню · изменения применяются после сохранения"
|
||||
description="Перетащите строку за ручку: порядок строк = порядок в меню · изменения применяются после сохранения"
|
||||
rows={rows}
|
||||
columns={columns}
|
||||
getRowId={(r) => r.id}
|
||||
@@ -296,6 +303,7 @@ export function AppLinksPage() {
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
onReorder={dropOn}
|
||||
onRowClick={setEditing}
|
||||
/>
|
||||
</TabsContent>
|
||||
|
||||
@@ -6,6 +6,11 @@ import { DataGrid, dataGridFeatures, type DataGridFeatures } from '@/components/
|
||||
import { DataGridColumnHeader } from '@/components/reui/data-grid/data-grid-column-header'
|
||||
import { DataGridPagination } from '@/components/reui/data-grid/data-grid-pagination'
|
||||
import { DataGridScrollArea } from '@/components/reui/data-grid/data-grid-scroll-area'
|
||||
import {
|
||||
DataGridTableDndRowHandle,
|
||||
DataGridTableDndRows,
|
||||
} from '@/components/reui/data-grid/data-grid-table-dnd-rows'
|
||||
import type { DragEndEvent } from '@dnd-kit/core'
|
||||
import {
|
||||
DataGridTable,
|
||||
DataGridTableRowSelect,
|
||||
@@ -40,6 +45,7 @@ export type GridColumn<T> = {
|
||||
export type GridView<T> = { label: string; match: (row: T) => boolean }
|
||||
|
||||
const SELECT_COLUMN_SIZE = 44
|
||||
const DRAG_COLUMN_SIZE = 44
|
||||
|
||||
/**
|
||||
* Секция-таблица макета: Frame + Filters-подобная панель + DataGrid на DataGridScrollArea.
|
||||
@@ -59,6 +65,7 @@ export function PreviewSectionGrid<T extends object>({
|
||||
selectable = false,
|
||||
bulkActions,
|
||||
toolbar,
|
||||
onReorder,
|
||||
pageSize = 8,
|
||||
emptyMessage = 'Нет записей по текущим фильтрам.',
|
||||
className,
|
||||
@@ -75,6 +82,8 @@ export function PreviewSectionGrid<T extends object>({
|
||||
selectable?: boolean
|
||||
bulkActions?: (selectedIds: string[], clear: () => void) => ReactNode
|
||||
toolbar?: ReactNode
|
||||
/** Включает перетаскивание строк (dnd-kit). Передаёт id строки и id строки, на место которой её бросили. */
|
||||
onReorder?: (activeId: string, overId: string) => void
|
||||
pageSize?: number
|
||||
emptyMessage?: string
|
||||
className?: string
|
||||
@@ -113,6 +122,16 @@ export function PreviewSectionGrid<T extends object>({
|
||||
|
||||
const defs = useMemo<ColumnDef<DataGridFeatures, T>[]>(() => {
|
||||
const list: ColumnDef<DataGridFeatures, T>[] = []
|
||||
if (onReorder) {
|
||||
list.push({
|
||||
id: 'drag',
|
||||
header: () => <span className="sr-only">Порядок</span>,
|
||||
cell: () => <DataGridTableDndRowHandle />,
|
||||
enableSorting: false,
|
||||
enableResizing: false,
|
||||
size: DRAG_COLUMN_SIZE,
|
||||
})
|
||||
}
|
||||
if (selectable) {
|
||||
list.push({
|
||||
id: 'select',
|
||||
@@ -140,7 +159,7 @@ export function PreviewSectionGrid<T extends object>({
|
||||
})
|
||||
}
|
||||
return list
|
||||
}, [columns, selectable])
|
||||
}, [columns, selectable, onReorder])
|
||||
|
||||
const table = useTable({
|
||||
features: dataGridFeatures,
|
||||
@@ -154,7 +173,17 @@ export function PreviewSectionGrid<T extends object>({
|
||||
onPaginationChange: setPagination,
|
||||
})
|
||||
|
||||
const minWidth = columns.reduce((sum, c) => sum + c.size, selectable ? SELECT_COLUMN_SIZE : 0)
|
||||
const dataIds = table.getRowModel().rows.map((r) => r.id)
|
||||
const handleDragEnd = (event: DragEndEvent) => {
|
||||
const { active, over } = event
|
||||
if (!onReorder || !active || !over || active.id === over.id) return
|
||||
onReorder(String(active.id), String(over.id))
|
||||
}
|
||||
|
||||
const minWidth = columns.reduce(
|
||||
(sum, c) => sum + c.size,
|
||||
(selectable ? SELECT_COLUMN_SIZE : 0) + (onReorder ? DRAG_COLUMN_SIZE : 0),
|
||||
)
|
||||
const selectedIds = table.getSelectedRowModel().rows.map((r) => r.id)
|
||||
const paged = data.length > pageSize
|
||||
|
||||
@@ -165,7 +194,7 @@ export function PreviewSectionGrid<T extends object>({
|
||||
recordCount={data.length}
|
||||
onRowClick={onRowClick}
|
||||
emptyMessage={emptyMessage}
|
||||
tableLayout={{ headerSticky: false, dense: true, width: 'auto' }}
|
||||
tableLayout={{ headerSticky: false, dense: true, width: 'auto', rowsDraggable: Boolean(onReorder) }}
|
||||
>
|
||||
<Frame spacing="sm" className={cn('w-full min-w-0', className)}>
|
||||
<FrameHeader>
|
||||
@@ -226,7 +255,11 @@ export function PreviewSectionGrid<T extends object>({
|
||||
) : null}
|
||||
<DataGridScrollArea>
|
||||
<div className="pb-3" style={{ minWidth }}>
|
||||
<DataGridTable />
|
||||
{onReorder ? (
|
||||
<DataGridTableDndRows dataIds={dataIds} handleDragEnd={handleDragEnd} />
|
||||
) : (
|
||||
<DataGridTable />
|
||||
)}
|
||||
</div>
|
||||
</DataGridScrollArea>
|
||||
<Separator />
|
||||
|
||||
Reference in new issue
Block a user