mirror of
https://github.com/apache/superset.git
synced 2026-07-19 13:15:49 +00:00
feat(table v2): agGridTableChart add row numer column (#39284)
Co-authored-by: Evan Rusackas <evan@preset.io> Co-authored-by: codeant-ai-for-open-source[bot] <244253245+codeant-ai-for-open-source[bot]@users.noreply.github.com>
This commit is contained in:
@@ -28,6 +28,7 @@ import tinycolor from 'tinycolor2';
|
||||
import { createElement, type ComponentProps, ReactNode } from 'react';
|
||||
import { useColDefs } from '../../src/utils/useColDefs';
|
||||
import { InputColumn } from '../../src/types';
|
||||
import { ROW_NUMBER_COL_ID } from '../../src/consts';
|
||||
|
||||
type TestCellStyleFunc = (params: unknown) => unknown;
|
||||
|
||||
@@ -122,6 +123,9 @@ const defaultThemeWrapper = makeThemeWrapper(supersetTheme);
|
||||
const defaultProps = {
|
||||
data: [{ test_col: 'value' }],
|
||||
serverPagination: false,
|
||||
serverPaginationData: {},
|
||||
serverPageLength: 0,
|
||||
showNumberedColumn: false,
|
||||
isRawRecords: true,
|
||||
defaultAlignPN: false,
|
||||
showCellBars: false,
|
||||
@@ -136,6 +140,12 @@ const defaultProps = {
|
||||
slice_id: 1,
|
||||
};
|
||||
|
||||
const basePropsNumericColumns = {
|
||||
...defaultProps,
|
||||
columns: [makeColumn({ key: 'a', label: 'A' })],
|
||||
data: [{ a: 1 }, { a: 2 }, { a: 3 }],
|
||||
};
|
||||
|
||||
test('boolean columns use agCheckboxCellRenderer', () => {
|
||||
const booleanCol = makeColumn({
|
||||
key: 'is_active',
|
||||
@@ -828,3 +838,233 @@ test('cellStyle respects explicit horizontal alignment overrides', () => {
|
||||
textAlign: 'center',
|
||||
});
|
||||
});
|
||||
|
||||
test('is not added when showNumberedColumn is false', () => {
|
||||
const { result } = renderHook(
|
||||
() => useColDefs({ ...basePropsNumericColumns, showNumberedColumn: false }),
|
||||
{ wrapper: defaultThemeWrapper },
|
||||
);
|
||||
expect(result.current.some(col => col.field === ROW_NUMBER_COL_ID)).toBe(
|
||||
false,
|
||||
);
|
||||
expect(result.current.length).toBe(1);
|
||||
});
|
||||
|
||||
test('is added as first column when showNumberedColumn is true', () => {
|
||||
const { result } = renderHook(
|
||||
() => useColDefs({ ...basePropsNumericColumns, showNumberedColumn: true }),
|
||||
{ wrapper: defaultThemeWrapper },
|
||||
);
|
||||
expect(result.current[0].field).toBe(ROW_NUMBER_COL_ID);
|
||||
expect(result.current[0].headerName).toBe('№');
|
||||
expect(result.current.length).toBe(2);
|
||||
});
|
||||
|
||||
test('width defaults to 36 when maxVisibleRowNumber is 0 (empty data)', () => {
|
||||
const emptyProps = {
|
||||
...basePropsNumericColumns,
|
||||
data: [],
|
||||
showNumberedColumn: true,
|
||||
};
|
||||
const { result } = renderHook(() => useColDefs(emptyProps), {
|
||||
wrapper: defaultThemeWrapper,
|
||||
});
|
||||
expect(result.current[0].width).toBe(36);
|
||||
});
|
||||
|
||||
test('width uses server pagination row count when available', () => {
|
||||
const serverProps = {
|
||||
...basePropsNumericColumns,
|
||||
serverPagination: true,
|
||||
serverPaginationData: { currentPage: 0, pageSize: 5 },
|
||||
data: [{ a: 1 }, { a: 2 }],
|
||||
showNumberedColumn: true,
|
||||
};
|
||||
const { result } = renderHook(() => useColDefs(serverProps), {
|
||||
wrapper: defaultThemeWrapper,
|
||||
});
|
||||
|
||||
expect(result.current[0].width).toBe(36);
|
||||
|
||||
const laterPageProps = {
|
||||
...serverProps,
|
||||
serverPaginationData: { currentPage: 3, pageSize: 5 },
|
||||
data: [{ a: 21 }, { a: 22 }],
|
||||
};
|
||||
const { result: resultLater } = renderHook(() => useColDefs(laterPageProps), {
|
||||
wrapper: defaultThemeWrapper,
|
||||
});
|
||||
expect(resultLater.current[0].width).toBe(42);
|
||||
});
|
||||
|
||||
test('valueGetter returns row numbers without server pagination', () => {
|
||||
const { result } = renderHook(
|
||||
() => useColDefs({ ...basePropsNumericColumns, showNumberedColumn: true }),
|
||||
{ wrapper: defaultThemeWrapper },
|
||||
);
|
||||
const colDef = result.current[0];
|
||||
const { valueGetter } = colDef;
|
||||
expect(valueGetter).toBeDefined();
|
||||
expect(typeof valueGetter).toBe('function');
|
||||
|
||||
const getter = valueGetter as (params: {
|
||||
node?: { rowIndex?: number };
|
||||
data?: Record<string, unknown>;
|
||||
}) => number;
|
||||
|
||||
const params = (rowIndex: number) => ({
|
||||
node: { rowIndex },
|
||||
data: basePropsNumericColumns.data[rowIndex],
|
||||
});
|
||||
|
||||
expect(getter(params(0))).toBe(1);
|
||||
expect(getter(params(1))).toBe(2);
|
||||
expect(getter(params(2))).toBe(3);
|
||||
});
|
||||
|
||||
test('valueGetter respects server pagination', () => {
|
||||
const serverProps = {
|
||||
...basePropsNumericColumns,
|
||||
serverPagination: true,
|
||||
serverPaginationData: { currentPage: 2, pageSize: 5 },
|
||||
data: [{ a: 11 }, { a: 12 }],
|
||||
};
|
||||
const { result } = renderHook(
|
||||
() => useColDefs({ ...serverProps, showNumberedColumn: true }),
|
||||
{ wrapper: defaultThemeWrapper },
|
||||
);
|
||||
const { valueGetter } = result.current[0];
|
||||
expect(typeof valueGetter).toBe('function');
|
||||
|
||||
const getter = valueGetter as (params: {
|
||||
node?: { rowIndex?: number };
|
||||
data?: Record<string, unknown>;
|
||||
}) => number;
|
||||
|
||||
expect(getter({ node: { rowIndex: 0 } })).toBe(11);
|
||||
expect(getter({ node: { rowIndex: 1 } })).toBe(12);
|
||||
});
|
||||
|
||||
test('has correct static column properties', () => {
|
||||
const { result } = renderHook(
|
||||
() => useColDefs({ ...basePropsNumericColumns, showNumberedColumn: true }),
|
||||
{ wrapper: defaultThemeWrapper },
|
||||
);
|
||||
const colDef = result.current[0];
|
||||
expect(colDef.sortable).toBe(false);
|
||||
expect(colDef.filter).toBe(false);
|
||||
expect(colDef.pinned).toBe('left');
|
||||
expect(colDef.lockPosition).toBe(true);
|
||||
expect(colDef.suppressNavigable).toBe(true);
|
||||
expect(colDef.suppressSizeToFit).toBe(true);
|
||||
expect(colDef.resizable).toBe(false);
|
||||
expect(colDef.suppressMovable).toBe(true);
|
||||
expect(colDef.headerStyle).toBeDefined();
|
||||
expect(colDef.cellStyle).toBeDefined();
|
||||
});
|
||||
|
||||
test('pageSize priority chain works correctly', () => {
|
||||
const props1 = {
|
||||
...basePropsNumericColumns,
|
||||
serverPagination: true,
|
||||
serverPaginationData: { currentPage: 2, pageSize: 10 },
|
||||
serverPageLength: 5,
|
||||
data: Array.from({ length: 3 }, () => ({ a: 1 })),
|
||||
showNumberedColumn: true,
|
||||
};
|
||||
const { result: res1 } = renderHook(() => useColDefs(props1), {
|
||||
wrapper: defaultThemeWrapper,
|
||||
});
|
||||
|
||||
expect(res1.current[0].width).toBe(42);
|
||||
|
||||
const props2 = {
|
||||
...props1,
|
||||
serverPaginationData: { currentPage: 2 },
|
||||
serverPageLength: 20,
|
||||
};
|
||||
const { result: res2 } = renderHook(() => useColDefs(props2), {
|
||||
wrapper: defaultThemeWrapper,
|
||||
});
|
||||
|
||||
expect(res2.current[0].width).toBe(42);
|
||||
});
|
||||
|
||||
test('column width adapts to max row number length in client mode', () => {
|
||||
const base = {
|
||||
...basePropsNumericColumns,
|
||||
showNumberedColumn: true,
|
||||
serverPagination: false,
|
||||
};
|
||||
|
||||
const props9 = { ...base, data: Array.from({ length: 9 }, () => ({ a: 1 })) };
|
||||
const { result: res9 } = renderHook(() => useColDefs(props9), {
|
||||
wrapper: defaultThemeWrapper,
|
||||
});
|
||||
expect(res9.current[0].width).toBe(36);
|
||||
|
||||
const props10 = {
|
||||
...base,
|
||||
data: Array.from({ length: 10 }, () => ({ a: 1 })),
|
||||
};
|
||||
const { result: res10 } = renderHook(() => useColDefs(props10), {
|
||||
wrapper: defaultThemeWrapper,
|
||||
});
|
||||
expect(res10.current[0].width).toBe(42);
|
||||
|
||||
const props100 = {
|
||||
...base,
|
||||
data: Array.from({ length: 100 }, () => ({ a: 1 })),
|
||||
};
|
||||
const { result: res100 } = renderHook(() => useColDefs(props100), {
|
||||
wrapper: defaultThemeWrapper,
|
||||
});
|
||||
expect(res100.current[0].width).toBe(48);
|
||||
});
|
||||
|
||||
test('row number column uses theme variables for styling', () => {
|
||||
const { result } = renderHook(
|
||||
() => useColDefs({ ...basePropsNumericColumns, showNumberedColumn: true }),
|
||||
{ wrapper: defaultThemeWrapper },
|
||||
);
|
||||
const colDef = result.current[0];
|
||||
expect(colDef.cellStyle).toMatchObject({
|
||||
backgroundColor: expect.any(String),
|
||||
padding: '0',
|
||||
textAlign: 'center',
|
||||
fontSize: '0.9em',
|
||||
color: expect.any(String),
|
||||
});
|
||||
expect(colDef.headerStyle).toMatchObject({
|
||||
backgroundColor: expect.any(String),
|
||||
fontSize: '1em',
|
||||
color: expect.any(String),
|
||||
});
|
||||
});
|
||||
|
||||
test('valueGetter handles missing node or rowIndex gracefully', () => {
|
||||
const { result } = renderHook(
|
||||
() => useColDefs({ ...basePropsNumericColumns, showNumberedColumn: true }),
|
||||
{ wrapper: defaultThemeWrapper },
|
||||
);
|
||||
const getter = result.current[0].valueGetter as (params: {
|
||||
node?: { rowIndex?: number };
|
||||
}) => number;
|
||||
expect(getter({})).toBe(1);
|
||||
expect(getter({ node: {} })).toBe(1);
|
||||
|
||||
const serverProps = {
|
||||
...basePropsNumericColumns,
|
||||
serverPagination: true,
|
||||
serverPaginationData: { currentPage: 2, pageSize: 5 },
|
||||
showNumberedColumn: true,
|
||||
};
|
||||
const { result: serverResult } = renderHook(() => useColDefs(serverProps), {
|
||||
wrapper: defaultThemeWrapper,
|
||||
});
|
||||
const serverGetter = serverResult.current[0].valueGetter as (params: {
|
||||
node?: { rowIndex?: number };
|
||||
}) => number;
|
||||
expect(serverGetter({})).toBe(2 * 5 + 1);
|
||||
expect(serverGetter({ node: {} })).toBe(11);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user