mirror of
https://github.com/apache/superset.git
synced 2026-04-30 21:44:40 +00:00
Compare commits
1 Commits
docs/db-ca
...
sc-91230-c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fa05dc705f |
86
superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx
Normal file → Executable file
86
superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx
Normal file → Executable file
@@ -796,45 +796,65 @@ const config: ControlPanelConfig = {
|
||||
},
|
||||
);
|
||||
}
|
||||
const { colnames, coltypes } =
|
||||
const { colnames: queryColnames, coltypes: queryColtypes } =
|
||||
chart?.queriesResponse?.[0] ?? {};
|
||||
const allColumns =
|
||||
Array.isArray(colnames) && Array.isArray(coltypes)
|
||||
? [
|
||||
{
|
||||
value: ObjectFormattingEnum.ENTIRE_ROW,
|
||||
label: t('entire row'),
|
||||
dataType: GenericDataType.String,
|
||||
},
|
||||
...colnames.map((colname: string, index: number) => ({
|
||||
const hasQueryColumns =
|
||||
Array.isArray(queryColnames) &&
|
||||
Array.isArray(queryColtypes) &&
|
||||
queryColnames.length > 0;
|
||||
|
||||
// Fall back to datasource columns when query results are empty
|
||||
const datasourceColumns = ensureIsArray(
|
||||
(explore?.datasource as Dataset)?.columns,
|
||||
);
|
||||
const colnames = hasQueryColumns
|
||||
? queryColnames
|
||||
: datasourceColumns.map(
|
||||
(col: ColumnMeta) => col.column_name,
|
||||
);
|
||||
const coltypes = hasQueryColumns
|
||||
? queryColtypes
|
||||
: datasourceColumns.map(
|
||||
(col: ColumnMeta) =>
|
||||
col.type_generic ?? GenericDataType.String,
|
||||
);
|
||||
|
||||
const hasColumns = colnames.length > 0;
|
||||
const allColumns = hasColumns
|
||||
? [
|
||||
{
|
||||
value: ObjectFormattingEnum.ENTIRE_ROW,
|
||||
label: t('entire row'),
|
||||
dataType: GenericDataType.String,
|
||||
},
|
||||
...colnames.map((colname: string, index: number) => ({
|
||||
value: colname,
|
||||
label: Array.isArray(verboseMap)
|
||||
? colname
|
||||
: (verboseMap[colname] ?? colname),
|
||||
dataType: coltypes[index],
|
||||
})),
|
||||
]
|
||||
: [];
|
||||
const numericColumns = hasColumns
|
||||
? colnames.reduce((acc, colname, index) => {
|
||||
if (
|
||||
coltypes[index] === GenericDataType.Numeric ||
|
||||
(!hasTimeComparison &&
|
||||
(coltypes[index] === GenericDataType.String ||
|
||||
coltypes[index] === GenericDataType.Boolean))
|
||||
) {
|
||||
acc.push({
|
||||
value: colname,
|
||||
label: Array.isArray(verboseMap)
|
||||
? colname
|
||||
: (verboseMap[colname] ?? colname),
|
||||
dataType: coltypes[index],
|
||||
})),
|
||||
]
|
||||
: [];
|
||||
const numericColumns =
|
||||
Array.isArray(colnames) && Array.isArray(coltypes)
|
||||
? colnames.reduce((acc, colname, index) => {
|
||||
if (
|
||||
coltypes[index] === GenericDataType.Numeric ||
|
||||
(!hasTimeComparison &&
|
||||
(coltypes[index] === GenericDataType.String ||
|
||||
coltypes[index] === GenericDataType.Boolean))
|
||||
) {
|
||||
acc.push({
|
||||
value: colname,
|
||||
label: Array.isArray(verboseMap)
|
||||
? colname
|
||||
: (verboseMap[colname] ?? colname),
|
||||
dataType: coltypes[index],
|
||||
});
|
||||
}
|
||||
return acc;
|
||||
}, [])
|
||||
: [];
|
||||
});
|
||||
}
|
||||
return acc;
|
||||
}, [])
|
||||
: [];
|
||||
const columnOptions = hasTimeComparison
|
||||
? processComparisonColumns(
|
||||
numericColumns || [],
|
||||
|
||||
122
superset-frontend/plugins/plugin-chart-table/test/controlPanel.test.tsx
Normal file → Executable file
122
superset-frontend/plugins/plugin-chart-table/test/controlPanel.test.tsx
Normal file → Executable file
@@ -55,11 +55,12 @@ const createMockControlState = (value: string[] | undefined): ControlState => ({
|
||||
|
||||
const createMockExplore = (
|
||||
timeCompareValue: string[] | undefined,
|
||||
datasourceColumns: Partial<Dataset>['columns'] = [],
|
||||
): ControlPanelState => ({
|
||||
slice: { slice_id: 123 },
|
||||
datasource: {
|
||||
verbose_map: { col1: 'Column 1', col2: 'Column 2' },
|
||||
columns: [],
|
||||
columns: datasourceColumns,
|
||||
} as Partial<Dataset> as Dataset,
|
||||
controls: {
|
||||
time_compare: createMockControlState(timeCompareValue),
|
||||
@@ -206,3 +207,122 @@ test('static extraColorChoices removed from config', () => {
|
||||
|
||||
expect(controlConfig?.extraColorChoices).toBeUndefined();
|
||||
});
|
||||
|
||||
test('columnOptions falls back to datasource columns when queriesResponse is empty', () => {
|
||||
const controlConfig = findConditionalFormattingControl();
|
||||
expect(controlConfig).toBeTruthy();
|
||||
|
||||
const datasourceColumns = [
|
||||
{ column_name: 'revenue', type_generic: GenericDataType.Numeric },
|
||||
{ column_name: 'name', type_generic: GenericDataType.String },
|
||||
];
|
||||
const explore = createMockExplore(undefined, datasourceColumns);
|
||||
const chart = { chartStatus: 'success' as const, queriesResponse: null };
|
||||
const result = controlConfig!.mapStateToProps!(
|
||||
explore,
|
||||
createMockControlStateForConditionalFormatting(),
|
||||
chart,
|
||||
);
|
||||
|
||||
expect(result.columnOptions).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({ value: 'revenue' }),
|
||||
expect.objectContaining({ value: 'name' }),
|
||||
]),
|
||||
);
|
||||
expect(result.allColumns).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({ value: 'revenue' }),
|
||||
expect.objectContaining({ value: 'name' }),
|
||||
]),
|
||||
);
|
||||
});
|
||||
|
||||
test('columnOptions prefers queriesResponse over datasource columns', () => {
|
||||
const controlConfig = findConditionalFormattingControl();
|
||||
expect(controlConfig).toBeTruthy();
|
||||
|
||||
const datasourceColumns = [
|
||||
{ column_name: 'revenue', type_generic: GenericDataType.Numeric },
|
||||
{ column_name: 'extra_col', type_generic: GenericDataType.String },
|
||||
];
|
||||
const explore = createMockExplore(undefined, datasourceColumns);
|
||||
const chart = createMockChart();
|
||||
const result = controlConfig!.mapStateToProps!(
|
||||
explore,
|
||||
createMockControlStateForConditionalFormatting(),
|
||||
chart,
|
||||
);
|
||||
|
||||
expect(result.columnOptions).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({ value: 'col1' }),
|
||||
expect.objectContaining({ value: 'col2' }),
|
||||
]),
|
||||
);
|
||||
expect(result.columnOptions).not.toEqual(
|
||||
expect.arrayContaining([expect.objectContaining({ value: 'extra_col' })]),
|
||||
);
|
||||
});
|
||||
|
||||
test('columnOptions falls back to datasource when queriesResponse has empty colnames', () => {
|
||||
const controlConfig = findConditionalFormattingControl();
|
||||
expect(controlConfig).toBeTruthy();
|
||||
|
||||
const datasourceColumns = [
|
||||
{ column_name: 'revenue', type_generic: GenericDataType.Numeric },
|
||||
];
|
||||
const explore = createMockExplore(undefined, datasourceColumns);
|
||||
const chart = {
|
||||
chartStatus: 'success' as const,
|
||||
queriesResponse: [{ colnames: [], coltypes: [] }],
|
||||
};
|
||||
const result = controlConfig!.mapStateToProps!(
|
||||
explore,
|
||||
createMockControlStateForConditionalFormatting(),
|
||||
chart,
|
||||
);
|
||||
|
||||
expect(result.columnOptions).toEqual(
|
||||
expect.arrayContaining([expect.objectContaining({ value: 'revenue' })]),
|
||||
);
|
||||
});
|
||||
|
||||
test('columnOptions returns empty when both queriesResponse and datasource have no columns', () => {
|
||||
const controlConfig = findConditionalFormattingControl();
|
||||
expect(controlConfig).toBeTruthy();
|
||||
|
||||
const explore = createMockExplore(undefined, []);
|
||||
const chart = { chartStatus: 'success' as const, queriesResponse: null };
|
||||
const result = controlConfig!.mapStateToProps!(
|
||||
explore,
|
||||
createMockControlStateForConditionalFormatting(),
|
||||
chart,
|
||||
);
|
||||
|
||||
expect(result.columnOptions).toEqual([]);
|
||||
expect(result.allColumns).toEqual([]);
|
||||
});
|
||||
|
||||
test('columnOptions defaults type_generic to String when missing from datasource columns', () => {
|
||||
const controlConfig = findConditionalFormattingControl();
|
||||
expect(controlConfig).toBeTruthy();
|
||||
|
||||
const datasourceColumns = [{ column_name: 'untyped_col' }];
|
||||
const explore = createMockExplore(undefined, datasourceColumns);
|
||||
const chart = { chartStatus: 'success' as const, queriesResponse: null };
|
||||
const result = controlConfig!.mapStateToProps!(
|
||||
explore,
|
||||
createMockControlStateForConditionalFormatting(),
|
||||
chart,
|
||||
);
|
||||
|
||||
expect(result.columnOptions).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
value: 'untyped_col',
|
||||
dataType: GenericDataType.String,
|
||||
}),
|
||||
]),
|
||||
);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user