mirror of https://github.com/buster-so/buster.git
make a few refernces more stable
This commit is contained in:
parent
c7311dafd5
commit
5796ebf222
|
@ -25,10 +25,8 @@ export const OverviewData: React.FC<{
|
||||||
) : !isEmpty(data) ? (
|
) : !isEmpty(data) ? (
|
||||||
<AppDataGrid
|
<AppDataGrid
|
||||||
rows={data || []}
|
rows={data || []}
|
||||||
headerFormat={isAdmin ? (v) => String(v) : undefined}
|
headerFormat={isAdmin ? stableHeaderFormat : undefined}
|
||||||
cellFormat={defaultCellFormatter}
|
cellFormat={defaultCellFormatter}
|
||||||
resizable={true}
|
|
||||||
sortable={false}
|
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<EmptyState />
|
<EmptyState />
|
||||||
|
@ -54,3 +52,7 @@ const LoadingState: React.FC<{}> = () => {
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const stableHeaderFormat = (value: string | number | Date | null, key: string): string => {
|
||||||
|
return String(value);
|
||||||
|
};
|
||||||
|
|
|
@ -26,7 +26,7 @@ export const DataContainer: React.FC<{
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{hasData ? (
|
{hasData ? (
|
||||||
<AppDataGrid rows={data} resizable={true} sortable={false} />
|
<AppDataGrid rows={data} />
|
||||||
) : (
|
) : (
|
||||||
<div className="flex h-full items-center justify-center">
|
<div className="flex h-full items-center justify-center">
|
||||||
{fetchingData ? 'Loading data...' : 'No data returned'}
|
{fetchingData ? 'Loading data...' : 'No data returned'}
|
||||||
|
|
|
@ -85,6 +85,7 @@ const BusterTableChartBase: React.FC<
|
||||||
columnWidths={tableColumnWidths || undefined}
|
columnWidths={tableColumnWidths || undefined}
|
||||||
sortable={!readOnly}
|
sortable={!readOnly}
|
||||||
resizable={!readOnly}
|
resizable={!readOnly}
|
||||||
|
draggable={!readOnly}
|
||||||
onReady={onReady}
|
onReady={onReady}
|
||||||
headerFormat={onFormatHeader}
|
headerFormat={onFormatHeader}
|
||||||
cellFormat={onFormatCell}
|
cellFormat={onFormatCell}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import React, { CSSProperties } from 'react';
|
import React, { CSSProperties } from 'react';
|
||||||
import { DragOverlay, useDraggable, useDroppable } from '@dnd-kit/core';
|
import { useDraggable, useDroppable } from '@dnd-kit/core';
|
||||||
import { Header, Table } from '@tanstack/react-table';
|
import { Header, Table } from '@tanstack/react-table';
|
||||||
import { flexRender } from '@tanstack/react-table';
|
import { flexRender } from '@tanstack/react-table';
|
||||||
import { cn } from '@/lib/classMerge';
|
import { cn } from '@/lib/classMerge';
|
||||||
|
@ -16,86 +16,95 @@ interface DraggableHeaderProps {
|
||||||
draggable: boolean;
|
draggable: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const DraggableHeader: React.FC<DraggableHeaderProps> = React.memo(
|
const DraggableHeader: React.FC<DraggableHeaderProps> = ({
|
||||||
({ header, sortable, resizable, isOverTarget, draggable }) => {
|
header,
|
||||||
// Set up dnd-kit's useDraggable for this header cell
|
sortable,
|
||||||
const {
|
resizable,
|
||||||
attributes,
|
isOverTarget,
|
||||||
listeners,
|
draggable
|
||||||
isDragging,
|
}) => {
|
||||||
setNodeRef: setDragNodeRef
|
// Set up dnd-kit's useDraggable for this header cell
|
||||||
} = useDraggable({
|
const {
|
||||||
disabled: !draggable,
|
attributes,
|
||||||
id: header.id
|
listeners,
|
||||||
});
|
isDragging,
|
||||||
|
setNodeRef: setDragNodeRef
|
||||||
|
} = useDraggable({
|
||||||
|
disabled: !draggable,
|
||||||
|
id: header.id
|
||||||
|
});
|
||||||
|
|
||||||
// Set up droppable area to detect when a header is over this target
|
// Set up droppable area to detect when a header is over this target
|
||||||
const { setNodeRef: setDropNodeRef } = useDroppable({
|
const { setNodeRef: setDropNodeRef } = useDroppable({
|
||||||
id: `droppable-${header.id}`
|
id: `droppable-${header.id}`
|
||||||
});
|
});
|
||||||
|
|
||||||
const style: CSSProperties = {
|
const style: CSSProperties = {
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
whiteSpace: 'nowrap',
|
whiteSpace: 'nowrap',
|
||||||
width: header.column.getSize(),
|
width: header.column.getSize(),
|
||||||
opacity: isDragging ? 0.65 : 1,
|
opacity: isDragging ? 0.65 : 1,
|
||||||
transition: 'none', // Prevent any transitions for snappy changes
|
transition: 'none', // Prevent any transitions for snappy changes
|
||||||
height: `${HEADER_HEIGHT}px` // Set fixed header height
|
height: `${HEADER_HEIGHT}px` // Set fixed header height
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<th
|
<th
|
||||||
ref={draggable ? setDropNodeRef : undefined}
|
ref={draggable ? setDropNodeRef : undefined}
|
||||||
style={style}
|
style={style}
|
||||||
|
className={cn(
|
||||||
|
'group bg-background relative border-r select-none last:border-r-0',
|
||||||
|
header.column.getIsResizing() ? 'bg-primary/10' : 'hover:bg-item-hover',
|
||||||
|
isOverTarget && 'bg-primary/10 border-primary inset border border-r! border-dashed'
|
||||||
|
)}
|
||||||
|
// onClick toggles sorting if enabled
|
||||||
|
onClick={header.column.getCanSort() ? header.column.getToggleSortingHandler() : undefined}>
|
||||||
|
<span
|
||||||
className={cn(
|
className={cn(
|
||||||
'group bg-background relative border-r select-none last:border-r-0',
|
'flex h-full flex-1 items-center space-x-1.5 p-2',
|
||||||
header.column.getIsResizing() ? 'bg-primary/10' : 'hover:bg-item-hover',
|
draggable && 'cursor-grab'
|
||||||
isOverTarget && 'bg-primary/10 border-primary inset border border-r! border-dashed'
|
|
||||||
)}
|
)}
|
||||||
// onClick toggles sorting if enabled
|
ref={draggable ? setDragNodeRef : undefined}
|
||||||
onClick={header.column.getCanSort() ? header.column.getToggleSortingHandler() : undefined}>
|
{...attributes}
|
||||||
<span
|
{...listeners}>
|
||||||
className={cn(
|
<span className="text-gray-dark text-base font-normal">
|
||||||
'flex h-full flex-1 items-center space-x-1.5 p-2',
|
{flexRender(header.column.columnDef.header, header.getContext())}
|
||||||
draggable && 'cursor-grab'
|
|
||||||
)}
|
|
||||||
ref={draggable ? setDragNodeRef : undefined}
|
|
||||||
{...attributes}
|
|
||||||
{...listeners}>
|
|
||||||
<span className="text-gray-dark text-base font-normal">
|
|
||||||
{flexRender(header.column.columnDef.header, header.getContext())}
|
|
||||||
</span>
|
|
||||||
{header.column.getIsSorted() === 'asc' && (
|
|
||||||
<span className="text-icon-color text-xs">
|
|
||||||
<CaretUp />
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
{header.column.getIsSorted() === 'desc' && (
|
|
||||||
<span className="text-icon-color text-xs">
|
|
||||||
<CaretDown />
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</span>
|
</span>
|
||||||
{resizable && (
|
|
||||||
<span
|
{sortable && (
|
||||||
onClick={(e) => {
|
<>
|
||||||
e.stopPropagation();
|
{header.column.getIsSorted() === 'asc' && (
|
||||||
e.preventDefault();
|
<span className="text-icon-color text-xs">
|
||||||
}}>
|
<CaretUp />
|
||||||
<span
|
</span>
|
||||||
onMouseDown={header.getResizeHandler()}
|
)}
|
||||||
onTouchStart={header.getResizeHandler()}
|
{header.column.getIsSorted() === 'desc' && (
|
||||||
className={cn(
|
<span className="text-icon-color text-xs">
|
||||||
'group-hover:bg-border hover:bg-primary absolute inset-y-0 -right-0.5 z-10 w-1 cursor-col-resize transition-colors duration-100 select-none',
|
<CaretDown />
|
||||||
header.column.getIsResizing() && 'bg-primary'
|
</span>
|
||||||
)}
|
)}
|
||||||
/>
|
</>
|
||||||
</span>
|
|
||||||
)}
|
)}
|
||||||
</th>
|
</span>
|
||||||
);
|
{resizable && (
|
||||||
}
|
<span
|
||||||
);
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
e.preventDefault();
|
||||||
|
}}>
|
||||||
|
<span
|
||||||
|
onMouseDown={header.getResizeHandler()}
|
||||||
|
onTouchStart={header.getResizeHandler()}
|
||||||
|
className={cn(
|
||||||
|
'group-hover:bg-border hover:bg-primary absolute inset-y-0 -right-0.5 z-10 w-1 cursor-col-resize transition-colors duration-100 select-none',
|
||||||
|
header.column.getIsResizing() && 'bg-primary'
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</th>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
DraggableHeader.displayName = 'DraggableHeader';
|
DraggableHeader.displayName = 'DraggableHeader';
|
||||||
|
|
||||||
|
|
|
@ -71,6 +71,22 @@ export const NonDraggable: Story = {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const NonResizable: Story = {
|
||||||
|
args: {
|
||||||
|
...meta.args,
|
||||||
|
rows: sampleData,
|
||||||
|
resizable: false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const NonSortable: Story = {
|
||||||
|
args: {
|
||||||
|
...meta.args,
|
||||||
|
rows: sampleData,
|
||||||
|
sortable: false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
export const CustomColumnOrder: Story = {
|
export const CustomColumnOrder: Story = {
|
||||||
args: {
|
args: {
|
||||||
...meta.args,
|
...meta.args,
|
||||||
|
|
Loading…
Reference in New Issue