mirror of
https://github.com/apache/superset.git
synced 2026-04-07 10:31:50 +00:00
feat(dashboard): show dataset column labels in View as table (#37140)
This commit is contained in:
@@ -457,6 +457,7 @@ const SliceHeaderControls = (
|
|||||||
isRequest
|
isRequest
|
||||||
isVisible
|
isVisible
|
||||||
canDownload={!!props.supersetCanCSV}
|
canDownload={!!props.supersetCanCSV}
|
||||||
|
columnDisplayNames={datasetWithVerboseMap?.verbose_map}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -164,6 +164,7 @@ const DataTableTemporalHeaderCell = ({
|
|||||||
onTimeColumnChange,
|
onTimeColumnChange,
|
||||||
datasourceId,
|
datasourceId,
|
||||||
isOriginalTimeColumn,
|
isOriginalTimeColumn,
|
||||||
|
displayLabel,
|
||||||
}: {
|
}: {
|
||||||
columnName: string;
|
columnName: string;
|
||||||
onTimeColumnChange: (
|
onTimeColumnChange: (
|
||||||
@@ -172,6 +173,7 @@ const DataTableTemporalHeaderCell = ({
|
|||||||
) => void;
|
) => void;
|
||||||
datasourceId?: string;
|
datasourceId?: string;
|
||||||
isOriginalTimeColumn: boolean;
|
isOriginalTimeColumn: boolean;
|
||||||
|
displayLabel?: string;
|
||||||
}) => {
|
}) => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
|
||||||
@@ -215,10 +217,10 @@ const DataTableTemporalHeaderCell = ({
|
|||||||
onClick={(e: React.MouseEvent<HTMLElement>) => e.stopPropagation()}
|
onClick={(e: React.MouseEvent<HTMLElement>) => e.stopPropagation()}
|
||||||
/>
|
/>
|
||||||
</Popover>
|
</Popover>
|
||||||
{columnName}
|
{displayLabel ?? columnName}
|
||||||
</span>
|
</span>
|
||||||
) : (
|
) : (
|
||||||
<span>{columnName}</span>
|
<span>{displayLabel ?? columnName}</span>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -258,6 +260,7 @@ export const useTableColumns = (
|
|||||||
isVisible?: boolean,
|
isVisible?: boolean,
|
||||||
moreConfigs?: { [key: string]: Partial<Column> },
|
moreConfigs?: { [key: string]: Partial<Column> },
|
||||||
allowHTML?: boolean,
|
allowHTML?: boolean,
|
||||||
|
columnDisplayNames?: Record<string, string>,
|
||||||
) => {
|
) => {
|
||||||
const [originalFormattedTimeColumns, setOriginalFormattedTimeColumns] =
|
const [originalFormattedTimeColumns, setOriginalFormattedTimeColumns] =
|
||||||
useState<string[]>(getTimeColumns(datasourceId));
|
useState<string[]>(getTimeColumns(datasourceId));
|
||||||
@@ -302,6 +305,7 @@ export const useTableColumns = (
|
|||||||
.map((key, index) => {
|
.map((key, index) => {
|
||||||
const colType = coltypes?.[index];
|
const colType = coltypes?.[index];
|
||||||
const firstValue = data[0][key];
|
const firstValue = data[0][key];
|
||||||
|
const headerLabel = columnDisplayNames?.[key] ?? key;
|
||||||
const originalFormattedTimeColumnIndex =
|
const originalFormattedTimeColumnIndex =
|
||||||
colType === GenericDataType.Temporal
|
colType === GenericDataType.Temporal
|
||||||
? originalFormattedTimeColumns.indexOf(key)
|
? originalFormattedTimeColumns.indexOf(key)
|
||||||
@@ -320,9 +324,10 @@ export const useTableColumns = (
|
|||||||
datasourceId={datasourceId}
|
datasourceId={datasourceId}
|
||||||
onTimeColumnChange={onTimeColumnChange}
|
onTimeColumnChange={onTimeColumnChange}
|
||||||
isOriginalTimeColumn={isOriginalTimeColumn}
|
isOriginalTimeColumn={isOriginalTimeColumn}
|
||||||
|
displayLabel={headerLabel}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
key
|
headerLabel
|
||||||
),
|
),
|
||||||
Cell: ({ value }) => {
|
Cell: ({ value }) => {
|
||||||
if (value === true) {
|
if (value === true) {
|
||||||
@@ -357,6 +362,7 @@ export const useTableColumns = (
|
|||||||
datasourceId,
|
datasourceId,
|
||||||
moreConfigs,
|
moreConfigs,
|
||||||
originalFormattedTimeColumns,
|
originalFormattedTimeColumns,
|
||||||
|
columnDisplayNames,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -105,6 +105,7 @@ test('useTableColumns with no options', () => {
|
|||||||
"Cell": [Function],
|
"Cell": [Function],
|
||||||
"Header": <DataTableTemporalHeaderCell
|
"Header": <DataTableTemporalHeaderCell
|
||||||
columnName="numtime"
|
columnName="numtime"
|
||||||
|
displayLabel="numtime"
|
||||||
isOriginalTimeColumn={false}
|
isOriginalTimeColumn={false}
|
||||||
onTimeColumnChange={[Function]}
|
onTimeColumnChange={[Function]}
|
||||||
/>,
|
/>,
|
||||||
@@ -168,6 +169,7 @@ test('useTableColumns with options', () => {
|
|||||||
"Cell": [Function],
|
"Cell": [Function],
|
||||||
"Header": <DataTableTemporalHeaderCell
|
"Header": <DataTableTemporalHeaderCell
|
||||||
columnName="numtime"
|
columnName="numtime"
|
||||||
|
displayLabel="numtime"
|
||||||
isOriginalTimeColumn={false}
|
isOriginalTimeColumn={false}
|
||||||
onTimeColumnChange={[Function]}
|
onTimeColumnChange={[Function]}
|
||||||
/>,
|
/>,
|
||||||
@@ -194,3 +196,29 @@ test('useTableColumns with options', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('useTableColumns applies columnDisplayNames to headers', () => {
|
||||||
|
const columnDisplayNames = {
|
||||||
|
col01: 'Column One',
|
||||||
|
[NUMTIME_KEY]: 'Verbose Numtime',
|
||||||
|
} as Record<string, string>;
|
||||||
|
const hook = renderHook(() =>
|
||||||
|
useTableColumns(
|
||||||
|
colnames,
|
||||||
|
coltypes,
|
||||||
|
data,
|
||||||
|
undefined,
|
||||||
|
true,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
columnDisplayNames,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
const cols = hook.result.current as JsonObject[];
|
||||||
|
const col01 = cols.find(c => c.id === 'col01');
|
||||||
|
const numtime = cols.find(c => c.id === NUMTIME_KEY);
|
||||||
|
expect(col01?.Header).toBe('Column One');
|
||||||
|
// Temporal header is a component; ensure it received the displayLabel prop
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
||||||
|
expect(numtime?.Header.props.displayLabel).toBe('Verbose Numtime');
|
||||||
|
});
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ export const ResultsPaneOnDashboard = ({
|
|||||||
isVisible,
|
isVisible,
|
||||||
dataSize = 50,
|
dataSize = 50,
|
||||||
canDownload,
|
canDownload,
|
||||||
|
columnDisplayNames,
|
||||||
}: ResultsPaneProps) => {
|
}: ResultsPaneProps) => {
|
||||||
const resultsPanes = useResultsPane({
|
const resultsPanes = useResultsPane({
|
||||||
errorMessage,
|
errorMessage,
|
||||||
@@ -66,6 +67,7 @@ export const ResultsPaneOnDashboard = ({
|
|||||||
dataSize,
|
dataSize,
|
||||||
isVisible,
|
isVisible,
|
||||||
canDownload,
|
canDownload,
|
||||||
|
columnDisplayNames,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (resultsPanes.length === 1) {
|
if (resultsPanes.length === 1) {
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ export const SingleQueryResultPane = ({
|
|||||||
dataSize = 50,
|
dataSize = 50,
|
||||||
isVisible,
|
isVisible,
|
||||||
canDownload,
|
canDownload,
|
||||||
|
columnDisplayNames,
|
||||||
}: SingleQueryResultPaneProp) => {
|
}: SingleQueryResultPaneProp) => {
|
||||||
const [filterText, setFilterText] = useState('');
|
const [filterText, setFilterText] = useState('');
|
||||||
|
|
||||||
@@ -52,6 +53,7 @@ export const SingleQueryResultPane = ({
|
|||||||
isVisible,
|
isVisible,
|
||||||
{}, // moreConfig
|
{}, // moreConfig
|
||||||
true, // allowHTML
|
true, // allowHTML
|
||||||
|
columnDisplayNames,
|
||||||
);
|
);
|
||||||
const filteredData = useFilteredTableData(filterText, data);
|
const filteredData = useFilteredTableData(filterText, data);
|
||||||
|
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ export const useResultsPane = ({
|
|||||||
isVisible,
|
isVisible,
|
||||||
dataSize = 50,
|
dataSize = 50,
|
||||||
canDownload,
|
canDownload,
|
||||||
|
columnDisplayNames,
|
||||||
}: ResultsPaneProps): ReactElement[] => {
|
}: ResultsPaneProps): ReactElement[] => {
|
||||||
const metadata = getChartMetadataRegistry().get(
|
const metadata = getChartMetadataRegistry().get(
|
||||||
queryFormData?.viz_type || queryFormData?.vizType,
|
queryFormData?.viz_type || queryFormData?.vizType,
|
||||||
@@ -164,6 +165,7 @@ export const useResultsPane = ({
|
|||||||
datasourceId={queryFormData.datasource}
|
datasourceId={queryFormData.datasource}
|
||||||
isVisible={isVisible}
|
isVisible={isVisible}
|
||||||
canDownload={canDownload}
|
canDownload={canDownload}
|
||||||
|
columnDisplayNames={columnDisplayNames}
|
||||||
/>
|
/>
|
||||||
</StyledDiv>
|
</StyledDiv>
|
||||||
));
|
));
|
||||||
|
|||||||
@@ -49,6 +49,8 @@ export interface ResultsPaneProps {
|
|||||||
// reload OriginalFormattedTimeColumns from localStorage when isVisible is true
|
// reload OriginalFormattedTimeColumns from localStorage when isVisible is true
|
||||||
isVisible: boolean;
|
isVisible: boolean;
|
||||||
canDownload: boolean;
|
canDownload: boolean;
|
||||||
|
// Optional map of column/metric name -> verbose label
|
||||||
|
columnDisplayNames?: Record<string, string>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SamplesPaneProps {
|
export interface SamplesPaneProps {
|
||||||
@@ -88,4 +90,6 @@ export interface SingleQueryResultPaneProp extends QueryResultInterface {
|
|||||||
// reload OriginalFormattedTimeColumns from localStorage when isVisible is true
|
// reload OriginalFormattedTimeColumns from localStorage when isVisible is true
|
||||||
isVisible: boolean;
|
isVisible: boolean;
|
||||||
canDownload: boolean;
|
canDownload: boolean;
|
||||||
|
// Optional map of column/metric name -> verbose label
|
||||||
|
columnDisplayNames?: Record<string, string>;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user