mirror of
https://github.com/ToolJet/ToolJet
synced 2026-05-23 08:58:26 +00:00
[ Feature ] :: Reorder Table columns using drag and drop (#4327)
* column reordering using dnd * fix :: drag handler area made as whole header * setting drag item close to cursor * removing padding * style fix :: sort and dragger * removing width :: making draggable element width same as th row width * temperory fix :: table drag attachment to cursor
This commit is contained in:
parent
e99fff4508
commit
a7f925d52e
2 changed files with 97 additions and 25 deletions
|
|
@ -11,6 +11,7 @@ import {
|
|||
useBlockLayout,
|
||||
useResizeColumns,
|
||||
useRowSelect,
|
||||
useColumnOrder,
|
||||
} from 'react-table';
|
||||
import cx from 'classnames';
|
||||
import { resolveReferences, validateWidget } from '@/_helpers/utils';
|
||||
|
|
@ -28,6 +29,7 @@ import generateActionsData from './columns/actions';
|
|||
import autogenerateColumns from './columns/autogenerateColumns';
|
||||
import IndeterminateCheckbox from './IndeterminateCheckbox';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd';
|
||||
// eslint-disable-next-line import/no-unresolved
|
||||
import { IconEyeOff } from '@tabler/icons';
|
||||
import * as XLSX from 'xlsx/xlsx.mjs';
|
||||
|
|
@ -86,6 +88,22 @@ export function Table({
|
|||
disabledSort,
|
||||
} = loadPropertiesAndStyles(properties, styles, darkMode, component);
|
||||
|
||||
const getItemStyle = ({ isDragging, isDropAnimating }, draggableStyle) => ({
|
||||
...draggableStyle,
|
||||
userSelect: 'none',
|
||||
background: isDragging ? 'rgba(77, 114, 250, 0.2)' : '',
|
||||
top: 'auto',
|
||||
borderRadius: '4px',
|
||||
...(isDragging && {
|
||||
marginLeft: '-120px',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
paddingLeft: '10px',
|
||||
height: '30px',
|
||||
}),
|
||||
...(!isDragging && { transform: 'translate(0,0)', width: '100%' }),
|
||||
...(isDropAnimating && { transitionDuration: '0.001s' }),
|
||||
});
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [tableDetails, dispatch] = useReducer(reducer, initialState());
|
||||
|
|
@ -340,12 +358,13 @@ export function Table({
|
|||
setAllFilters,
|
||||
preGlobalFilteredRows,
|
||||
setGlobalFilter,
|
||||
allColumns,
|
||||
setColumnOrder,
|
||||
state: { pageIndex, globalFilter },
|
||||
exportData,
|
||||
selectedFlatRows,
|
||||
globalFilteredRows,
|
||||
getToggleHideAllColumnsProps,
|
||||
allColumns,
|
||||
} = useTable(
|
||||
{
|
||||
autoResetPage: false,
|
||||
|
|
@ -363,6 +382,7 @@ export function Table({
|
|||
disableSortBy: disabledSort,
|
||||
manualSortBy: serverSideSort,
|
||||
},
|
||||
useColumnOrder,
|
||||
useFilters,
|
||||
useGlobalFilter,
|
||||
useSortBy,
|
||||
|
|
@ -393,6 +413,7 @@ export function Table({
|
|||
]);
|
||||
}
|
||||
);
|
||||
const currentColOrder = React.useRef();
|
||||
|
||||
const sortOptions = useMemo(() => {
|
||||
if (state?.sortBy?.length === 0) {
|
||||
|
|
@ -609,27 +630,75 @@ export function Table({
|
|||
<table {...getTableProps()} className={`table table-vcenter table-nowrap ${tableType}`} style={computedStyles}>
|
||||
<thead>
|
||||
{headerGroups.map((headerGroup, index) => (
|
||||
<tr key={index} {...headerGroup.getHeaderGroupProps()} tabIndex="0" className="tr">
|
||||
{headerGroup.headers.map((column, index) => (
|
||||
<th className="th" key={index} {...column.getHeaderProps()}>
|
||||
<div
|
||||
className={column.isSorted ? (column.isSortedDesc ? 'sort-desc' : 'sort-asc') : ''}
|
||||
{...column.getSortByToggleProps()}
|
||||
<DragDropContext
|
||||
key={index}
|
||||
onDragStart={() => {
|
||||
currentColOrder.current = allColumns?.map((o) => o.id);
|
||||
}}
|
||||
onDragUpdate={(dragUpdateObj) => {
|
||||
const colOrder = [...currentColOrder.current];
|
||||
const sIndex = dragUpdateObj.source.index;
|
||||
const dIndex = dragUpdateObj.destination && dragUpdateObj.destination.index;
|
||||
|
||||
if (typeof sIndex === 'number' && typeof dIndex === 'number') {
|
||||
colOrder.splice(sIndex, 1);
|
||||
colOrder.splice(dIndex, 0, dragUpdateObj.draggableId);
|
||||
setColumnOrder(colOrder);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Droppable droppableId="droppable" direction="horizontal">
|
||||
{(droppableProvided, snapshot) => (
|
||||
<tr
|
||||
ref={droppableProvided.innerRef}
|
||||
key={index}
|
||||
{...headerGroup.getHeaderGroupProps()}
|
||||
tabIndex="0"
|
||||
className="tr"
|
||||
>
|
||||
{column.render('Header')}
|
||||
</div>
|
||||
<div
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}}
|
||||
draggable="true"
|
||||
{...column.getResizerProps()}
|
||||
className={`resizer ${column.isResizing ? 'isResizing' : ''}`}
|
||||
/>
|
||||
</th>
|
||||
))}
|
||||
</tr>
|
||||
{headerGroup.headers.map((column, index) => (
|
||||
<Draggable
|
||||
key={column.id}
|
||||
draggableId={column.id}
|
||||
index={index}
|
||||
isDragDisabled={!column.accessor}
|
||||
>
|
||||
{(provided, snapshot) => {
|
||||
return (
|
||||
<th
|
||||
key={index}
|
||||
{...column.getHeaderProps(column.getSortByToggleProps())}
|
||||
className={
|
||||
column.isSorted ? (column.isSortedDesc ? 'sort-desc th' : 'sort-asc th') : 'th'
|
||||
}
|
||||
>
|
||||
<div
|
||||
{...provided.draggableProps}
|
||||
{...provided.dragHandleProps}
|
||||
// {...extraProps}
|
||||
ref={provided.innerRef}
|
||||
style={{ ...getItemStyle(snapshot, provided.draggableProps.style) }}
|
||||
>
|
||||
{column.render('Header')}
|
||||
</div>
|
||||
<div
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}}
|
||||
draggable="true"
|
||||
{...column.getResizerProps()}
|
||||
className={`resizer ${column.isResizing ? 'isResizing' : ''}`}
|
||||
/>
|
||||
</th>
|
||||
);
|
||||
}}
|
||||
</Draggable>
|
||||
))}
|
||||
</tr>
|
||||
)}
|
||||
</Droppable>
|
||||
</DragDropContext>
|
||||
))}
|
||||
</thead>
|
||||
|
||||
|
|
|
|||
|
|
@ -1902,8 +1902,8 @@ button {
|
|||
border-right: 5px solid transparent;
|
||||
border-top: 5px solid #767676;
|
||||
border-bottom: 5px solid transparent;
|
||||
left: 6px;
|
||||
top: 8px;
|
||||
left: 0px;
|
||||
top: 7px;
|
||||
}
|
||||
|
||||
.sort-asc:after {
|
||||
|
|
@ -1911,8 +1911,8 @@ button {
|
|||
border-right: 5px solid transparent;
|
||||
border-top: 0px solid transparent;
|
||||
border-bottom: 5px solid #767676;
|
||||
left: 6px;
|
||||
bottom: 8px;
|
||||
left: 0px;
|
||||
top: 7px;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3441,6 +3441,9 @@ input:focus-visible {
|
|||
.gui-select-wrappper .select-search__input {
|
||||
height: 30px;
|
||||
}
|
||||
.table thead th {
|
||||
display: flex !important;
|
||||
}
|
||||
|
||||
.theme-dark .input-group-text,
|
||||
.theme-dark .markdown>table thead th,
|
||||
|
|
|
|||
Loading…
Reference in a new issue