1- import React , { memo } from "react"
1+ import React , { memo , useState , useMemo , useCallback } from "react"
22import styled from "styled-components"
3+ import {
4+ DndContext ,
5+ closestCenter ,
6+ KeyboardSensor ,
7+ PointerSensor ,
8+ useSensor ,
9+ useSensors ,
10+ } from "@dnd-kit/core"
11+ import { SortableContext , horizontalListSortingStrategy , arrayMove } from "@dnd-kit/sortable"
12+ import { restrictToHorizontalAxis } from "@dnd-kit/modifiers"
313import Flex from "@/components/templates/flex"
414import { useTableState } from "../../provider"
515import Cell from "./cell"
616import { Handler } from "./resizeHandler"
17+ import DragOverlay from "./dragOverlay"
718
819const rerenderSelector = state => {
920 const columns = state . allColumns || [ ]
@@ -19,8 +30,10 @@ const rerenderSelector = state => {
1930 }
2031}
2132
22- const HeaderGroup = ( { id, headers, testPrefix, rowReverse, ...rest } ) => {
23- return (
33+ const HeaderGroup = ( { id, headers, testPrefix, rowReverse, enableColumnReordering, ...rest } ) => {
34+ const columnIds = useMemo ( ( ) => headers . map ( h => h . column . id ) , [ headers ] )
35+
36+ const content = (
2437 < Flex
2538 id = { id }
2639 data-testid = { `netdata-table-headRow${ testPrefix } ` }
@@ -36,23 +49,37 @@ const HeaderGroup = ({ id, headers, testPrefix, rowReverse, ...rest }) => {
3649 header = { header }
3750 testPrefix = { testPrefix }
3851 hasSubheaders = { ! ! header . subHeaders . length }
52+ enableColumnReordering = {
53+ enableColumnReordering && header . column . columnDef . enableReordering !== false
54+ }
3955 >
4056 { ! ! header . subHeaders . length && (
4157 < HeaderGroup
4258 headers = { header . subHeaders }
4359 id = { header . id }
4460 key = { header . id }
4561 { ...rest }
62+ enableColumnReordering = { enableColumnReordering }
4663 isSubheader
4764 />
4865 ) }
4966 </ Cell >
5067 ) ) }
5168 </ Flex >
5269 )
70+
71+ if ( ! enableColumnReordering ) {
72+ return content
73+ }
74+
75+ return (
76+ < SortableContext items = { columnIds } strategy = { horizontalListSortingStrategy } >
77+ { content }
78+ </ SortableContext >
79+ )
5380}
5481
55- const HeaderGroups = ( { groups, size, side, flex = "grow" , ...rest } ) => {
82+ const HeaderGroups = ( { groups, size, side, flex = "grow" , enableColumnReordering , ...rest } ) => {
5683 if ( ! groups [ 0 ] . headers . length ) return null
5784
5885 return (
@@ -69,7 +96,13 @@ const HeaderGroups = ({ groups, size, side, flex = "grow", ...rest }) => {
6996 flex = { flex }
7097 column
7198 >
72- < HeaderGroup headers = { groups [ 0 ] . headers } id = { groups [ 0 ] . id } key = { groups [ 0 ] . id } { ...rest } />
99+ < HeaderGroup
100+ headers = { groups [ 0 ] . headers }
101+ id = { groups [ 0 ] . id }
102+ key = { groups [ 0 ] . id }
103+ { ...rest }
104+ enableColumnReordering = { enableColumnReordering }
105+ />
73106 </ Flex >
74107 )
75108}
@@ -82,12 +115,67 @@ const HeaderRow = styled(Flex)`
82115 &:hover ${ Handler } {
83116 display: block;
84117 }
118+
119+ &:hover .drag-handle {
120+ opacity: 1;
121+ }
85122`
86123
87- const BodyHeader = memo ( ( { table, testPrefix, ...rest } ) => {
124+ const BodyHeader = memo ( ( { table, testPrefix, enableColumnReordering , ...rest } ) => {
88125 useTableState ( rerenderSelector )
89126
90- return (
127+ const [ activeId , setActiveId ] = useState ( null )
128+
129+ const sensors = useSensors (
130+ useSensor ( PointerSensor , {
131+ activationConstraint : {
132+ distance : 5 ,
133+ } ,
134+ } ) ,
135+ useSensor ( KeyboardSensor )
136+ )
137+
138+ const activeColumn = useMemo ( ( ) => {
139+ if ( ! activeId ) return null
140+ return table . getColumn ( activeId )
141+ } , [ activeId , table ] )
142+
143+ const handleDragStart = useCallback ( event => {
144+ setActiveId ( event . active . id )
145+ } , [ ] )
146+
147+ const handleDragEnd = useCallback (
148+ event => {
149+ const { active, over } = event
150+ setActiveId ( null )
151+
152+ if ( ! active || ! over || active . id === over . id ) return
153+
154+ const currentOrder = table . getState ( ) . columnOrder
155+ const allColumns = table . getAllLeafColumns ( )
156+
157+ let columnOrder = currentOrder . length > 0 ? currentOrder : allColumns . map ( c => c . id )
158+
159+ const oldIndex = columnOrder . indexOf ( active . id )
160+ const newIndex = columnOrder . indexOf ( over . id )
161+
162+ if ( oldIndex === - 1 || newIndex === - 1 ) return
163+
164+ const activeColumn = table . getColumn ( active . id )
165+ const overColumn = table . getColumn ( over . id )
166+ if ( activeColumn ?. getIsPinned ( ) !== overColumn ?. getIsPinned ( ) ) return
167+
168+ const newOrder = arrayMove ( columnOrder , oldIndex , newIndex )
169+ table . setColumnOrder ( newOrder )
170+ } ,
171+ [ table ]
172+ )
173+
174+ const handleDragCancel = useCallback ( ( ) => {
175+ setActiveId ( null )
176+ } , [ ] )
177+
178+ const headerContent = (
91179 < HeaderRow
92180 data-testid = { `netdata-table-head${ testPrefix } ` }
93181 flex
@@ -106,13 +194,15 @@ const BodyHeader = memo(({ table, testPrefix, ...rest }) => {
106194 { ...rest }
107195 flex = { false }
108196 table = { table }
197+ enableColumnReordering = { enableColumnReordering }
109198 />
110199 < HeaderGroups
111200 groups = { table . getCenterHeaderGroups ( ) }
112201 size = { table . getCenterTotalSize ( ) }
113202 testPrefix = { testPrefix }
114203 { ...rest }
115204 table = { table }
205+ enableColumnReordering = { enableColumnReordering }
116206 />
117207 < HeaderGroups
118208 groups = { table . getRightHeaderGroups ( ) }
@@ -122,10 +212,29 @@ const BodyHeader = memo(({ table, testPrefix, ...rest }) => {
122212 { ...rest }
123213 flex = { false }
124214 table = { table }
215+ enableColumnReordering = { enableColumnReordering }
125216 rowReverse
126217 />
127218 </ HeaderRow >
128219 )
220+
221+ if ( ! enableColumnReordering ) {
222+ return headerContent
223+ }
224+
225+ return (
226+ < DndContext
227+ sensors = { sensors }
228+ collisionDetection = { closestCenter }
229+ modifiers = { [ restrictToHorizontalAxis ] }
230+ onDragStart = { handleDragStart }
231+ onDragEnd = { handleDragEnd }
232+ onDragCancel = { handleDragCancel }
233+ >
234+ { headerContent }
235+ < DragOverlay activeColumn = { activeColumn } />
236+ </ DndContext >
237+ )
129238} )
130239
131240export default BodyHeader
0 commit comments