mirror of
https://github.com/Syngnat/GoNavi.git
synced 2026-08-11 01:03:51 +08:00
🐛 fix(datagrid): 修复空结果横向滚动条位置异常
- 实测表格 DOM 溢出与轨道宽度,轻微溢出时仍将滚动条固定到底部 - 空结果时关闭数据预览面板并清理聚焦状态,避免残留布局占位 - 扩展性能复现页支持零行数据并补充布局与预览面板回归测试
This commit is contained in:
@@ -740,7 +740,7 @@ describe('DataGrid layout', () => {
|
||||
|
||||
const handleDataPanelSaveSource = sliceCallback(
|
||||
'const handleDataPanelSave = useCallback(() => {',
|
||||
'const handleCellSetNull = useCallback(() => {',
|
||||
"const lastReportedDataFingerprintRef = useRef('');",
|
||||
);
|
||||
const handleCellSetNullSource = sliceCallback(
|
||||
'const handleCellSetNull = useCallback(() => {',
|
||||
@@ -2953,5 +2953,7 @@ describe('DataGrid layout', () => {
|
||||
expect(harnessSource).toContain("document.body.setAttribute('data-ui-version', uiVersion);");
|
||||
expect(harnessSource).toContain("if (value === null || value === undefined || value === '') {");
|
||||
expect(harnessSource).toContain("const currentState = useStore.getState();");
|
||||
expect(harnessSource).toContain("new URLSearchParams(window.location.search).get('rows')");
|
||||
expect(harnessSource).toContain('Math.max(0, Math.min(50000');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -48,11 +48,11 @@ import { filterRowsByGridConditions } from '../utils/dataGridClientFilter';
|
||||
import { resolveGridSortInfoFromTableSorter } from '../utils/dataGridSort';
|
||||
import {
|
||||
absorbExtraWidthIntoFlexibleColumns,
|
||||
calculateExternalHorizontalScrollInnerWidth,
|
||||
calculateTableBodyBottomPadding,
|
||||
calculateVirtualTableScrollX,
|
||||
resolveDataGridColumnQuickFindScrollLeft,
|
||||
resolveDataGridHorizontalWheelDelta,
|
||||
resolveExternalHorizontalScrollMetrics,
|
||||
} from './dataGridLayout';
|
||||
import {
|
||||
createDataGridIdleCommitScheduler,
|
||||
@@ -942,29 +942,6 @@ const DataGrid: React.FC<DataGridProps> = ({
|
||||
const virtualInlineInputRef = useRef<any>(null);
|
||||
const virtualInlinePickerOpenRef = useRef(false);
|
||||
const virtualInlineScrollLockRef = useRef<{ el: HTMLElement; handler: (e: WheelEvent) => void } | null>(null);
|
||||
const {
|
||||
dataPanelOpen,
|
||||
dataPanelOpenRef,
|
||||
focusedCellInfo,
|
||||
dataPanelValue,
|
||||
setDataPanelValue,
|
||||
dataPanelIsJson,
|
||||
dataPanelDirtyRef,
|
||||
dataPanelOriginalRef,
|
||||
toggleDataPanel,
|
||||
updateFocusedCell,
|
||||
handleDataPanelFormatJson,
|
||||
} = useDataGridPreviewPanel({
|
||||
toEditableText: mongoAwareEditableText,
|
||||
looksLikeJsonText,
|
||||
normalizeDateTimeString,
|
||||
});
|
||||
const focusedCellWritable = useMemo(() => (
|
||||
canModifyData &&
|
||||
!!focusedCellInfo &&
|
||||
isWritableResultColumn(focusedCellInfo.dataIndex, effectiveEditLocator)
|
||||
), [canModifyData, focusedCellInfo, effectiveEditLocator]);
|
||||
|
||||
// Cell Context Menu State
|
||||
const [cellContextMenu, setCellContextMenu] = useState<{
|
||||
visible: boolean;
|
||||
@@ -1409,6 +1386,11 @@ const DataGrid: React.FC<DataGridProps> = ({
|
||||
// Dynamic Height
|
||||
const [tableHeight, setTableHeight] = useState(500);
|
||||
const [tableViewportWidth, setTableViewportWidth] = useState(0);
|
||||
const [measuredHorizontalScrollMetrics, setMeasuredHorizontalScrollMetrics] = useState({
|
||||
scrollWidth: 0,
|
||||
clientWidth: 0,
|
||||
trackClientWidth: 0,
|
||||
});
|
||||
const [tableBodyBottomPadding, setTableBodyBottomPadding] = useState(0);
|
||||
|
||||
// P0 性能优化:CSS 模板字符串 memoize,仅在主题/布局变量变化时重算
|
||||
@@ -1494,7 +1476,21 @@ const DataGrid: React.FC<DataGridProps> = ({
|
||||
const rcVirtualHolderEl = target.querySelector('.rc-virtual-list-holder') as HTMLElement | null;
|
||||
const virtualScrollbarEl = target.querySelector('.ant-table-tbody-virtual-scrollbar-horizontal') as HTMLElement | null;
|
||||
const scrollableEl = virtualBodyEl || rcVirtualHolderEl || bodyEl;
|
||||
const hasHorizontalOverflow = !!scrollableEl && (scrollableEl.scrollWidth - scrollableEl.clientWidth > 1);
|
||||
const measuredScrollWidth = scrollableEl?.scrollWidth || 0;
|
||||
const measuredClientWidth = scrollableEl?.clientWidth || 0;
|
||||
const measuredTrackClientWidth = externalHorizontalScrollRef.current?.clientWidth || 0;
|
||||
const hasHorizontalOverflow = measuredScrollWidth - measuredClientWidth > 1;
|
||||
setMeasuredHorizontalScrollMetrics((current) => (
|
||||
current.scrollWidth === measuredScrollWidth
|
||||
&& current.clientWidth === measuredClientWidth
|
||||
&& current.trackClientWidth === measuredTrackClientWidth
|
||||
? current
|
||||
: {
|
||||
scrollWidth: measuredScrollWidth,
|
||||
clientWidth: measuredClientWidth,
|
||||
trackClientWidth: measuredTrackClientWidth,
|
||||
}
|
||||
));
|
||||
// 普通表格可通过 body 底部内边距避开悬浮横向滚动条;
|
||||
// 但虚拟表格的内部横向滚动轨道会直接覆盖在可视区底部,需要同时从 y 高度里扣掉安全区。
|
||||
const nextBodyBottomPadding = calculateTableBodyBottomPadding({
|
||||
@@ -2260,25 +2256,6 @@ const DataGrid: React.FC<DataGridProps> = ({
|
||||
const handleCellSaveRef = useRef(handleCellSave);
|
||||
handleCellSaveRef.current = handleCellSave;
|
||||
|
||||
const handleDataPanelSave = useCallback(() => {
|
||||
if (!focusedCellInfo) return;
|
||||
if (!focusedCellWritable) {
|
||||
void message.info(translateDataGrid('data_grid.message.current_field_not_editable'));
|
||||
return;
|
||||
}
|
||||
// 与 updateFocusedCell 设置的原始值比较,避免幽灵变更
|
||||
if (dataPanelValue === dataPanelOriginalRef.current) {
|
||||
dataPanelDirtyRef.current = false;
|
||||
void message.info(translateDataGrid('data_grid.message.no_data_changes'));
|
||||
return;
|
||||
}
|
||||
const nextRow: any = { ...focusedCellInfo.record, [focusedCellInfo.dataIndex]: dataPanelValue };
|
||||
handleCellSave(nextRow);
|
||||
dataPanelOriginalRef.current = dataPanelValue;
|
||||
dataPanelDirtyRef.current = false;
|
||||
void message.success(translateDataGrid('data_grid.message.saved'));
|
||||
}, [focusedCellInfo, focusedCellWritable, dataPanelValue, handleCellSave, translateDataGrid]);
|
||||
|
||||
const handleCellSetNull = useCallback(() => {
|
||||
if (!cellContextMenu.record) return;
|
||||
if (!isWritableResultColumn(cellContextMenu.dataIndex, effectiveEditLocator)) {
|
||||
@@ -2451,6 +2428,47 @@ const DataGrid: React.FC<DataGridProps> = ({
|
||||
});
|
||||
}, [displayData, modifiedRows, deletedRowKeys]);
|
||||
mergedDisplayDataRef.current = mergedDisplayData;
|
||||
const {
|
||||
dataPanelOpen,
|
||||
dataPanelOpenRef,
|
||||
focusedCellInfo,
|
||||
dataPanelValue,
|
||||
setDataPanelValue,
|
||||
dataPanelIsJson,
|
||||
dataPanelDirtyRef,
|
||||
dataPanelOriginalRef,
|
||||
toggleDataPanel,
|
||||
updateFocusedCell,
|
||||
handleDataPanelFormatJson,
|
||||
} = useDataGridPreviewPanel({
|
||||
previewAvailable: mergedDisplayData.length > 0,
|
||||
toEditableText: mongoAwareEditableText,
|
||||
looksLikeJsonText,
|
||||
normalizeDateTimeString,
|
||||
});
|
||||
const focusedCellWritable = useMemo(() => (
|
||||
canModifyData &&
|
||||
!!focusedCellInfo &&
|
||||
isWritableResultColumn(focusedCellInfo.dataIndex, effectiveEditLocator)
|
||||
), [canModifyData, focusedCellInfo, effectiveEditLocator]);
|
||||
const handleDataPanelSave = useCallback(() => {
|
||||
if (!focusedCellInfo) return;
|
||||
if (!focusedCellWritable) {
|
||||
void message.info(translateDataGrid('data_grid.message.current_field_not_editable'));
|
||||
return;
|
||||
}
|
||||
// 与 updateFocusedCell 设置的原始值比较,避免幽灵变更
|
||||
if (dataPanelValue === dataPanelOriginalRef.current) {
|
||||
dataPanelDirtyRef.current = false;
|
||||
void message.info(translateDataGrid('data_grid.message.no_data_changes'));
|
||||
return;
|
||||
}
|
||||
const nextRow: any = { ...focusedCellInfo.record, [focusedCellInfo.dataIndex]: dataPanelValue };
|
||||
handleCellSave(nextRow);
|
||||
dataPanelOriginalRef.current = dataPanelValue;
|
||||
dataPanelDirtyRef.current = false;
|
||||
void message.success(translateDataGrid('data_grid.message.saved'));
|
||||
}, [focusedCellInfo, focusedCellWritable, dataPanelValue, handleCellSave, translateDataGrid]);
|
||||
const lastReportedDataFingerprintRef = useRef('');
|
||||
useEffect(() => {
|
||||
if (!onDataChange) return;
|
||||
@@ -3942,11 +3960,23 @@ const DataGrid: React.FC<DataGridProps> = ({
|
||||
isMacLike,
|
||||
});
|
||||
}, [totalWidth, isMacLike, tableViewportWidth]);
|
||||
const horizontalScrollVisible = isTableSurfaceActive && tableScrollX > tableViewportWidth + 1;
|
||||
const horizontalScrollWidth = useMemo(() => calculateExternalHorizontalScrollInnerWidth({
|
||||
const externalHorizontalScrollMetrics = useMemo(() => resolveExternalHorizontalScrollMetrics({
|
||||
tableScrollWidth: tableScrollX,
|
||||
tableViewportWidth,
|
||||
measuredScrollWidth: measuredHorizontalScrollMetrics.scrollWidth,
|
||||
measuredClientWidth: measuredHorizontalScrollMetrics.clientWidth,
|
||||
measuredTrackClientWidth: measuredHorizontalScrollMetrics.trackClientWidth,
|
||||
trackInset: floatingScrollbarInset,
|
||||
}), [tableScrollX, floatingScrollbarInset]);
|
||||
}), [
|
||||
floatingScrollbarInset,
|
||||
measuredHorizontalScrollMetrics.clientWidth,
|
||||
measuredHorizontalScrollMetrics.scrollWidth,
|
||||
measuredHorizontalScrollMetrics.trackClientWidth,
|
||||
tableScrollX,
|
||||
tableViewportWidth,
|
||||
]);
|
||||
const horizontalScrollVisible = isTableSurfaceActive && externalHorizontalScrollMetrics.visible;
|
||||
const horizontalScrollWidth = externalHorizontalScrollMetrics.innerWidth;
|
||||
const tableScrollConfig = useMemo(() => ({ x: tableScrollX, y: tableHeight }), [tableScrollX, tableHeight]);
|
||||
const virtualRowHeightSignature = `${displayRenderVersion}|${effectiveUiScale}`;
|
||||
const measuredVirtualRowHeight = virtualRowHeightMeasurement?.signature === virtualRowHeightSignature
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
calculateExternalHorizontalScrollInnerWidth,
|
||||
calculateTableBodyBottomPadding,
|
||||
calculateVirtualTableScrollX,
|
||||
resolveExternalHorizontalScrollMetrics,
|
||||
resolveDataGridColumnQuickFindScrollLeft,
|
||||
resolveDataGridHorizontalWheelDelta,
|
||||
} from './dataGridLayout';
|
||||
@@ -83,6 +84,21 @@ describe('dataGridLayout helpers', () => {
|
||||
})).toBe(1);
|
||||
});
|
||||
|
||||
it('uses measured DOM overflow when stretched columns exceed the theoretical table width', () => {
|
||||
expect(resolveExternalHorizontalScrollMetrics({
|
||||
tableScrollWidth: 1537,
|
||||
tableViewportWidth: 1537,
|
||||
measuredScrollWidth: 1539,
|
||||
measuredClientWidth: 1526,
|
||||
measuredTrackClientWidth: 1517,
|
||||
trackInset: 10,
|
||||
})).toEqual({
|
||||
visible: true,
|
||||
innerWidth: 1530,
|
||||
maxScrollLeft: 13,
|
||||
});
|
||||
});
|
||||
|
||||
it('resolves quick-find target scrollLeft by centering the target column when possible', () => {
|
||||
expect(resolveDataGridColumnQuickFindScrollLeft({
|
||||
currentScrollLeft: 0,
|
||||
|
||||
@@ -21,6 +21,19 @@ export interface ExternalHorizontalScrollInnerWidthOptions {
|
||||
trackInset: number;
|
||||
}
|
||||
|
||||
export interface ExternalHorizontalScrollMetricsOptions extends ExternalHorizontalScrollInnerWidthOptions {
|
||||
tableViewportWidth: number;
|
||||
measuredScrollWidth: number;
|
||||
measuredClientWidth: number;
|
||||
measuredTrackClientWidth?: number;
|
||||
}
|
||||
|
||||
export interface ExternalHorizontalScrollMetrics {
|
||||
visible: boolean;
|
||||
innerWidth: number;
|
||||
maxScrollLeft: number;
|
||||
}
|
||||
|
||||
export interface DataGridColumnQuickFindScrollLeftOptions {
|
||||
currentScrollLeft: number;
|
||||
columnLeft: number;
|
||||
@@ -146,6 +159,36 @@ export const calculateExternalHorizontalScrollInnerWidth = ({
|
||||
return Math.max(1, safeTableScrollWidth - safeTrackInset * 2);
|
||||
};
|
||||
|
||||
export const resolveExternalHorizontalScrollMetrics = ({
|
||||
tableScrollWidth,
|
||||
tableViewportWidth,
|
||||
measuredScrollWidth,
|
||||
measuredClientWidth,
|
||||
measuredTrackClientWidth,
|
||||
trackInset,
|
||||
}: ExternalHorizontalScrollMetricsOptions): ExternalHorizontalScrollMetrics => {
|
||||
const safeTableScrollWidth = Math.max(0, Math.ceil(tableScrollWidth));
|
||||
const safeViewportWidth = Math.max(0, Math.floor(tableViewportWidth));
|
||||
const safeMeasuredScrollWidth = Math.max(0, Math.ceil(measuredScrollWidth));
|
||||
const safeMeasuredClientWidth = Math.max(0, Math.floor(measuredClientWidth));
|
||||
const safeMeasuredTrackClientWidth = Math.max(0, Math.floor(measuredTrackClientWidth || 0));
|
||||
const safeTrackInset = Math.max(0, Math.ceil(trackInset));
|
||||
const calculatedMaxScrollLeft = safeViewportWidth > 0
|
||||
? Math.max(0, safeTableScrollWidth - safeViewportWidth)
|
||||
: 0;
|
||||
const measuredMaxScrollLeft = Math.max(0, safeMeasuredScrollWidth - safeMeasuredClientWidth);
|
||||
const maxScrollLeft = Math.max(calculatedMaxScrollLeft, measuredMaxScrollLeft);
|
||||
const innerWidth = safeViewportWidth > 0
|
||||
? Math.max(1, safeMeasuredTrackClientWidth || (safeViewportWidth - safeTrackInset * 2)) + maxScrollLeft
|
||||
: calculateExternalHorizontalScrollInnerWidth({ tableScrollWidth, trackInset });
|
||||
|
||||
return {
|
||||
visible: maxScrollLeft > 1,
|
||||
innerWidth,
|
||||
maxScrollLeft,
|
||||
};
|
||||
};
|
||||
|
||||
export const resolveDataGridColumnQuickFindScrollLeft = ({
|
||||
currentScrollLeft,
|
||||
columnLeft,
|
||||
|
||||
60
frontend/src/components/useDataGridPreviewPanel.test.tsx
Normal file
60
frontend/src/components/useDataGridPreviewPanel.test.tsx
Normal file
@@ -0,0 +1,60 @@
|
||||
import React from 'react';
|
||||
import { act, create, type ReactTestRenderer } from 'react-test-renderer';
|
||||
import { afterEach, describe, expect, it } from 'vitest';
|
||||
|
||||
import { useDataGridPreviewPanel, type UseDataGridPreviewPanelResult } from './useDataGridPreviewPanel';
|
||||
|
||||
describe('useDataGridPreviewPanel', () => {
|
||||
let renderer: ReactTestRenderer | null = null;
|
||||
|
||||
afterEach(() => {
|
||||
act(() => {
|
||||
renderer?.unmount();
|
||||
});
|
||||
renderer = null;
|
||||
});
|
||||
|
||||
it('closes the preview when the result becomes empty and keeps it closed', () => {
|
||||
let controller!: UseDataGridPreviewPanelResult;
|
||||
let setPreviewAvailable!: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
|
||||
const Harness = () => {
|
||||
const [previewAvailable, setAvailable] = React.useState(true);
|
||||
setPreviewAvailable = setAvailable;
|
||||
controller = useDataGridPreviewPanel({
|
||||
previewAvailable,
|
||||
toEditableText: (value) => String(value ?? ''),
|
||||
looksLikeJsonText: () => false,
|
||||
normalizeDateTimeString: (value) => value,
|
||||
});
|
||||
return null;
|
||||
};
|
||||
|
||||
act(() => {
|
||||
renderer = create(<Harness />);
|
||||
});
|
||||
act(() => {
|
||||
controller.toggleDataPanel();
|
||||
controller.updateFocusedCell({ id: 1 }, 'id');
|
||||
});
|
||||
|
||||
expect(controller.dataPanelOpen).toBe(true);
|
||||
expect(controller.focusedCellInfo?.dataIndex).toBe('id');
|
||||
|
||||
act(() => {
|
||||
setPreviewAvailable(false);
|
||||
});
|
||||
|
||||
expect(controller.dataPanelOpen).toBe(false);
|
||||
expect(controller.dataPanelOpenRef.current).toBe(false);
|
||||
expect(controller.focusedCellInfo).toBeNull();
|
||||
expect(controller.dataPanelValue).toBe('');
|
||||
|
||||
act(() => {
|
||||
controller.toggleDataPanel();
|
||||
});
|
||||
|
||||
expect(controller.dataPanelOpen).toBe(false);
|
||||
expect(controller.dataPanelOpenRef.current).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -9,6 +9,7 @@ export interface DataGridFocusedCellInfo {
|
||||
}
|
||||
|
||||
interface UseDataGridPreviewPanelParams {
|
||||
previewAvailable: boolean;
|
||||
toEditableText: (value: any, columnName?: string) => string;
|
||||
looksLikeJsonText: (text: string) => boolean;
|
||||
normalizeDateTimeString: (value: string) => string;
|
||||
@@ -29,6 +30,7 @@ export interface UseDataGridPreviewPanelResult {
|
||||
}
|
||||
|
||||
export const useDataGridPreviewPanel = ({
|
||||
previewAvailable,
|
||||
toEditableText,
|
||||
looksLikeJsonText,
|
||||
normalizeDateTimeString,
|
||||
@@ -41,6 +43,16 @@ export const useDataGridPreviewPanel = ({
|
||||
const dataPanelDirtyRef = React.useRef(false);
|
||||
const dataPanelOriginalRef = React.useRef('');
|
||||
|
||||
const closeDataPanel = React.useCallback(() => {
|
||||
dataPanelOpenRef.current = false;
|
||||
setDataPanelOpen(false);
|
||||
setFocusedCellInfo(null);
|
||||
setDataPanelValue('');
|
||||
setDataPanelIsJson(false);
|
||||
dataPanelDirtyRef.current = false;
|
||||
dataPanelOriginalRef.current = '';
|
||||
}, []);
|
||||
|
||||
const updateFocusedCell = React.useCallback((record: GridRecord, dataIndex: string) => {
|
||||
if (!record || !dataIndex) return;
|
||||
const raw = record?.[dataIndex];
|
||||
@@ -68,24 +80,30 @@ export const useDataGridPreviewPanel = ({
|
||||
}, [dataPanelIsJson, dataPanelValue]);
|
||||
|
||||
const toggleDataPanel = React.useCallback(() => {
|
||||
if (!previewAvailable) {
|
||||
closeDataPanel();
|
||||
return;
|
||||
}
|
||||
const next = !dataPanelOpenRef.current;
|
||||
dataPanelOpenRef.current = next;
|
||||
setDataPanelOpen(next);
|
||||
if (!next) {
|
||||
setFocusedCellInfo(null);
|
||||
setDataPanelValue('');
|
||||
setDataPanelIsJson(false);
|
||||
dataPanelDirtyRef.current = false;
|
||||
dataPanelOriginalRef.current = '';
|
||||
closeDataPanel();
|
||||
}
|
||||
}, []);
|
||||
}, [closeDataPanel, previewAvailable]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!previewAvailable) {
|
||||
closeDataPanel();
|
||||
}
|
||||
}, [closeDataPanel, previewAvailable]);
|
||||
|
||||
React.useEffect(() => {
|
||||
dataPanelOpenRef.current = dataPanelOpen;
|
||||
}, [dataPanelOpen]);
|
||||
|
||||
return {
|
||||
dataPanelOpen,
|
||||
dataPanelOpen: previewAvailable && dataPanelOpen,
|
||||
dataPanelOpenRef,
|
||||
focusedCellInfo,
|
||||
dataPanelValue,
|
||||
|
||||
@@ -72,6 +72,19 @@ const clampHarnessFontSize = (value: unknown): number => {
|
||||
return Math.min(20, Math.max(12, Math.round(numeric)));
|
||||
};
|
||||
|
||||
const readHarnessRowCount = (): number => {
|
||||
if (typeof window === 'undefined') return 10000;
|
||||
try {
|
||||
const rawValue = new URLSearchParams(window.location.search).get('rows');
|
||||
if (rawValue === null || rawValue === '') return 10000;
|
||||
const numeric = Number(rawValue);
|
||||
if (!Number.isFinite(numeric)) return 10000;
|
||||
return Math.min(50000, Math.max(0, Math.trunc(numeric)));
|
||||
} catch {
|
||||
return 10000;
|
||||
}
|
||||
};
|
||||
|
||||
const readHarnessRuntimeConfig = (): HarnessRuntimeConfig => {
|
||||
if (typeof window === 'undefined') {
|
||||
return { ...DEFAULT_HARNESS_CONFIG };
|
||||
@@ -119,7 +132,7 @@ const buildHarnessColumns = (count: number): string[] => {
|
||||
};
|
||||
|
||||
const buildHarnessData = (rowCount: number, columnNames: string[]): HarnessRow[] => {
|
||||
const safeRows = Math.max(200, Math.min(50000, Math.trunc(rowCount || 0)));
|
||||
const safeRows = Math.max(0, Math.min(50000, Math.trunc(rowCount || 0)));
|
||||
return Array.from({ length: safeRows }, (_, rowIndex) => {
|
||||
const rowNumber = rowIndex + 1;
|
||||
const nextRow: HarnessRow = {
|
||||
@@ -164,7 +177,7 @@ const PerfDataGridHarness: React.FC = () => {
|
||||
const setTheme = useStore((state) => state.setTheme);
|
||||
const setUiScale = useStore((state) => state.setUiScale);
|
||||
const setFontSize = useStore((state) => state.setFontSize);
|
||||
const [rowCount, setRowCount] = useState(10000);
|
||||
const [rowCount, setRowCount] = useState(readHarnessRowCount);
|
||||
const [columnCount, setColumnCount] = useState(24);
|
||||
const [uiVersion, setUiVersion] = useState<HarnessUiVersion>(initialConfig.uiVersion);
|
||||
const [density, setDensity] = useState<DataTableDensity>(initialConfig.density);
|
||||
@@ -297,11 +310,11 @@ const PerfDataGridHarness: React.FC = () => {
|
||||
]}
|
||||
/>
|
||||
<InputNumber
|
||||
min={200}
|
||||
min={0}
|
||||
max={50000}
|
||||
step={500}
|
||||
value={rowCount}
|
||||
onChange={(value) => setRowCount(Number(value) || 10000)}
|
||||
onChange={(value) => setRowCount(value === null ? 0 : Number(value))}
|
||||
addonBefore={t('dev.perf_data_grid.rows')}
|
||||
/>
|
||||
<InputNumber
|
||||
|
||||
Reference in New Issue
Block a user