Skip to content

Commit fa87b2a

Browse files
authored
Merge pull request #2508 from visualize-admin/feat/table-ellipsis
feat: Add a way to make table columns responsive
2 parents 334982b + 6f5b62d commit fa87b2a

File tree

21 files changed

+232
-50
lines changed

21 files changed

+232
-50
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ You can also check the
1111

1212
## Unreleased
1313

14-
Nothing yet.
14+
- Features
15+
- Added a way to make table columns responsive
1516

1617
### 6.2.5 - 2025-12-02
1718

app/charts/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -616,6 +616,7 @@ export const getInitialConfig = (
616616
settings: {
617617
showSearch: true,
618618
showAllRows: false,
619+
limitColumnWidths: false,
619620
},
620621
links: {
621622
enabled: false,

app/charts/table/cell-desktop.tsx

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Box, Theme } from "@mui/material";
1+
import { Box, Theme, Typography } from "@mui/material";
22
import { makeStyles } from "@mui/styles";
33
import { hcl } from "d3-color";
44
import { ScaleLinear } from "d3-scale";
@@ -10,6 +10,7 @@ import { LinkedCellWrapper } from "@/charts/table/linked-cell-wrapper";
1010
import { ColumnMeta, TableChartState } from "@/charts/table/table-state";
1111
import { Tag } from "@/charts/table/tag";
1212
import { Flex } from "@/components/flex";
13+
import { OverflowTooltip } from "@/components/overflow-tooltip";
1314
import { Observation } from "@/domain/data";
1415

1516
const useStyles = makeStyles((theme: Theme) => ({
@@ -61,12 +62,15 @@ export const CellDesktop = ({
6162
barShowBackground,
6263
} = columnMeta;
6364
const classes = useStyles();
64-
const { links } = useChartState() as TableChartState;
65+
const { links, shouldApplyWidthLimits } = useChartState() as TableChartState;
6566

6667
switch (columnMeta.type) {
6768
case "text":
69+
const textContent = columnMeta.formatter(cell);
70+
6871
return (
6972
<Flex
73+
{...cell.getCellProps()}
7074
sx={{
7175
alignItems: "center",
7276
justifyContent:
@@ -78,19 +82,33 @@ export const CellDesktop = ({
7882
fontWeight: textStyle,
7983
px: 3,
8084
}}
81-
{...cell.getCellProps()}
8285
>
8386
<LinkedCellWrapper cell={cell} columnMeta={columnMeta} links={links}>
84-
{columnMeta.formatter(cell)}
87+
{shouldApplyWidthLimits ? (
88+
<OverflowTooltip arrow title={textContent}>
89+
<Typography
90+
component="span"
91+
variant="inherit"
92+
noWrap
93+
sx={{ lineHeight: 1.5 }}
94+
>
95+
{textContent}
96+
</Typography>
97+
</OverflowTooltip>
98+
) : (
99+
<Box component="span" sx={{ lineHeight: 1.5 }}>
100+
{textContent}
101+
</Box>
102+
)}
85103
</LinkedCellWrapper>
86104
</Flex>
87105
);
88106
case "category":
89107
const { colorScale: cColorScale } = columnMeta;
90108
return (
91109
<Flex
92-
sx={{ alignItems: "center", fontWeight: textStyle, pl: 1, pr: 3 }}
93110
{...cell.getCellProps()}
111+
sx={{ alignItems: "center", fontWeight: textStyle, pl: 1, pr: 3 }}
94112
>
95113
<LinkedCellWrapper cell={cell} columnMeta={columnMeta} links={links}>
96114
<Tag tagColor={cColorScale(cell.value)}>
@@ -128,6 +146,7 @@ export const CellDesktop = ({
128146
sx={{
129147
flexDirection: "column",
130148
justifyContent: "center",
149+
alignItems: "flex-end",
131150
// Padding is a constant accounted for in the
132151
// widthScale domain (see table state).
133152
px: `${BAR_CELL_PADDING}px`,

app/charts/table/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
export const TABLE_HEIGHT = 600;
22
export const BAR_CELL_PADDING = 12;
33
export const SORTING_ARROW_WIDTH = 24;
4+
export const LIMITED_COLUMN_WIDTH = 120;

app/charts/table/linked-cell-wrapper.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,11 @@ import { Icon } from "@/icons";
1111

1212
const useStyles = makeStyles((theme: Theme) => ({
1313
link: {
14+
overflow: "hidden",
1415
display: "inline-flex",
1516
alignItems: "center",
1617
gap: theme.spacing(1),
18+
minWidth: 0,
1719
color: "inherit",
1820
fontWeight: "inherit",
1921
textDecoration: "none",

app/charts/table/table-content.tsx

Lines changed: 47 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
1-
import { Box, TableSortLabel, Theme } from "@mui/material";
1+
import { Box, TableSortLabel, Theme, Typography } from "@mui/material";
22
import { makeStyles } from "@mui/styles";
33
import clsx from "clsx";
44
import { createContext, ReactNode, useContext, useMemo } from "react";
55
import { HeaderGroup } from "react-table";
66

77
import { SORTING_ARROW_WIDTH } from "@/charts/table/constants";
88
import { ColumnMeta } from "@/charts/table/table-state";
9+
import { columnCanBeWidthLimited } from "@/charts/table/width-limit";
910
import { Flex } from "@/components/flex";
1011
import { OpenMetadataPanelWrapper } from "@/components/metadata-panel";
12+
import { OverflowTooltip } from "@/components/overflow-tooltip";
1113
import { Observation } from "@/domain/data";
1214

1315
/** Workaround because react-window can't pass props to inner element */
@@ -16,6 +18,7 @@ type TableContentProps = {
1618
tableColumnsMeta: Record<string, ColumnMeta>;
1719
customSortCount: number;
1820
totalColumnsWidth: number;
21+
shouldApplyWidthLimits: boolean;
1922
};
2023

2124
const TableContentContext = createContext<TableContentProps | undefined>(
@@ -27,6 +30,7 @@ export const TableContentProvider = ({
2730
tableColumnsMeta,
2831
customSortCount,
2932
totalColumnsWidth,
33+
shouldApplyWidthLimits,
3034
children,
3135
}: TableContentProps & { children: ReactNode }) => {
3236
const value = useMemo(() => {
@@ -35,8 +39,15 @@ export const TableContentProvider = ({
3539
tableColumnsMeta,
3640
customSortCount,
3741
totalColumnsWidth,
42+
shouldApplyWidthLimits,
3843
};
39-
}, [headerGroups, tableColumnsMeta, customSortCount, totalColumnsWidth]);
44+
}, [
45+
headerGroups,
46+
tableColumnsMeta,
47+
customSortCount,
48+
totalColumnsWidth,
49+
shouldApplyWidthLimits,
50+
]);
4051

4152
return (
4253
<TableContentContext.Provider value={value}>
@@ -75,8 +86,13 @@ export const TableContent = ({ children }: { children: ReactNode }) => {
7586
throw Error("Please wrap TableContent in TableContentProvider");
7687
}
7788

78-
const { headerGroups, tableColumnsMeta, customSortCount, totalColumnsWidth } =
79-
ctx;
89+
const {
90+
headerGroups,
91+
tableColumnsMeta,
92+
customSortCount,
93+
totalColumnsWidth,
94+
shouldApplyWidthLimits,
95+
} = ctx;
8096

8197
return (
8298
<>
@@ -87,10 +103,13 @@ export const TableContent = ({ children }: { children: ReactNode }) => {
87103
// eslint-disable-next-line react/jsx-key
88104
<Box {...headerGroup.getHeaderGroupProps()}>
89105
{headerGroup.headers.map((column) => {
90-
const { dim, columnComponentType } =
106+
const { type, dim, columnComponentType } =
91107
tableColumnsMeta[column.id];
92108
// We assume that the customSortCount items are at the beginning of the sorted array, so any item with a lower index must be a custom sorted one
93109
const isCustomSorted = column.sortedIndex < customSortCount;
110+
const hasWidthLimit =
111+
shouldApplyWidthLimits && columnCanBeWidthLimited(type);
112+
const headerText = `${column.Header}`;
94113

95114
return (
96115
// eslint-disable-next-line react/jsx-key
@@ -102,6 +121,7 @@ export const TableContent = ({ children }: { children: ReactNode }) => {
102121
: undefined
103122
)}
104123
{...column.getHeaderProps(column.getSortByToggleProps())}
124+
title={headerText}
105125
>
106126
<TableSortLabel
107127
active={isCustomSorted}
@@ -110,12 +130,31 @@ export const TableContent = ({ children }: { children: ReactNode }) => {
110130
"& svg": {
111131
opacity: isCustomSorted ? 1 : 0.5,
112132
},
133+
...(hasWidthLimit && {
134+
minWidth: 0,
135+
}),
113136
}}
114137
>
115138
<OpenMetadataPanelWrapper component={dim}>
116-
<span style={{ fontWeight: "bold" }}>
117-
{column.render("Header")}
118-
</span>
139+
{hasWidthLimit ? (
140+
<OverflowTooltip arrow title={headerText}>
141+
<Typography
142+
component="span"
143+
variant="inherit"
144+
noWrap
145+
sx={{ fontWeight: "bold", lineHeight: 1.5 }}
146+
>
147+
{column.render("Header")}
148+
</Typography>
149+
</OverflowTooltip>
150+
) : (
151+
<Box
152+
component="span"
153+
sx={{ fontWeight: "bold", lineHeight: 1.5 }}
154+
>
155+
{column.render("Header")}
156+
</Box>
157+
)}
119158
</OpenMetadataPanelWrapper>
120159
</TableSortLabel>
121160
</Flex>

0 commit comments

Comments
 (0)