Skip to content

Commit e9547df

Browse files
refactor(AnalyticalTable): clean up hooks & update react-table (#407)
1 parent 528d048 commit e9547df

15 files changed

+483
-424
lines changed

packages/main/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
"lodash.debounce": "^4.0.8",
2929
"react-content-loader": "^5.0.2",
3030
"react-jss": "10.0.4",
31-
"react-table": "7.0.0",
31+
"react-table": "7.0.4",
3232
"react-window": "^1.8.5"
3333
},
3434
"peerDependencies": {

packages/main/src/components/AnalyticalTable/hooks/useColumnsDependencies.ts

Lines changed: 0 additions & 10 deletions
This file was deleted.

packages/main/src/components/AnalyticalTable/hooks/useDynamicColumnWidths.ts

Lines changed: 134 additions & 128 deletions
Original file line numberDiff line numberDiff line change
@@ -10,163 +10,169 @@ const approximateHeaderPxFromCharLength = (charLength) =>
1010
charLength < 15 ? Math.sqrt(charLength * 1500) : 8 * charLength;
1111
const approximateContentPxFromCharLength = (charLength) => 8 * charLength;
1212

13-
export const useDynamicColumnWidths = (hooks) => {
14-
hooks.columns.push((columns, { instance }) => {
15-
if (!instance.state || !instance.rows) {
16-
return columns;
17-
}
18-
19-
const { rows, state } = instance;
20-
21-
const { hiddenColumns, tableClientWidth: totalWidth } = state;
22-
const { scaleWidthMode, loading } = instance.webComponentsReactProperties;
13+
const columnsDeps = (deps, { instance: { state, webComponentsReactProperties } }) => [
14+
...deps,
15+
state.tableClientWidth,
16+
webComponentsReactProperties.scaleWidthMode,
17+
webComponentsReactProperties.loading
18+
];
2319

24-
const visibleColumns = columns.filter(Boolean).filter((item) => {
25-
return (item.isVisible ?? true) && !hiddenColumns.includes(item.accessor);
26-
});
20+
const columns = (columns, { instance }) => {
21+
if (!instance.state || !instance.rows) {
22+
return columns;
23+
}
2724

28-
const calculateDefaultTableWidth = () => {
29-
const columnsWithFixedWidth = visibleColumns.filter(({ width }) => width ?? false).map(({ width }) => width);
30-
const fixedWidth = columnsWithFixedWidth.reduce((acc, val) => acc + val, 0);
25+
const { rows, state } = instance;
3126

32-
const defaultColumnsCount = visibleColumns.length - columnsWithFixedWidth.length;
27+
const { hiddenColumns, tableClientWidth: totalWidth } = state;
28+
const { scaleWidthMode, loading } = instance.webComponentsReactProperties;
3329

34-
// check if columns are visible and table has width
35-
if (visibleColumns.length > 0 && totalWidth > 0) {
36-
// set fixedWidth as defaultWidth if visible columns have fixed value
37-
if (visibleColumns.length === columnsWithFixedWidth.length) {
38-
return fixedWidth / visibleColumns.length;
39-
}
40-
// spread default columns
41-
if (totalWidth >= fixedWidth + defaultColumnsCount * DEFAULT_COLUMN_WIDTH) {
42-
return (totalWidth - fixedWidth) / defaultColumnsCount;
43-
} else {
44-
// set defaultWidth for default columns if table is overflowing
45-
return DEFAULT_COLUMN_WIDTH;
46-
}
47-
} else {
48-
return DEFAULT_COLUMN_WIDTH;
49-
}
50-
};
30+
const visibleColumns = columns.filter(Boolean).filter((item) => {
31+
return (item.isVisible ?? true) && !hiddenColumns.includes(item.accessor);
32+
});
5133

52-
if (columns.length === 0 || !totalWidth) return columns;
34+
const calculateDefaultTableWidth = () => {
35+
const columnsWithFixedWidth = visibleColumns.filter(({ width }) => width ?? false).map(({ width }) => width);
36+
const fixedWidth = columnsWithFixedWidth.reduce((acc, val) => acc + val, 0);
5337

54-
const hasData = rows.some((row) => !row.original?.emptyRow);
38+
const defaultColumnsCount = visibleColumns.length - columnsWithFixedWidth.length;
5539

56-
if (scaleWidthMode === TableScaleWidthMode.Default || (!hasData && loading)) {
57-
const defaultWidth = calculateDefaultTableWidth();
58-
return columns.map((column) => ({ ...column, width: column.width ?? defaultWidth }));
40+
// check if columns are visible and table has width
41+
if (visibleColumns.length > 0 && totalWidth > 0) {
42+
// set fixedWidth as defaultWidth if visible columns have fixed value
43+
if (visibleColumns.length === columnsWithFixedWidth.length) {
44+
return fixedWidth / visibleColumns.length;
45+
}
46+
// spread default columns
47+
if (totalWidth >= fixedWidth + defaultColumnsCount * DEFAULT_COLUMN_WIDTH) {
48+
return (totalWidth - fixedWidth) / defaultColumnsCount;
49+
}
5950
}
51+
return DEFAULT_COLUMN_WIDTH;
52+
};
6053

61-
const rowSample = rows.slice(0, ROW_SAMPLE_SIZE);
54+
if (columns.length === 0 || !totalWidth) return columns;
6255

63-
const columnMeta = visibleColumns.reduce((acc, column) => {
64-
if (column.id === '__ui5wcr__internal_selection_column' || column.id === '__ui5wcr__internal_highlight_column') {
65-
acc[column.accessor] = {
66-
minHeaderWidth: column.width,
67-
fullWidth: column.width,
68-
contentCharAvg: 0
69-
};
70-
return acc;
71-
}
56+
const hasData = rows.some((row) => !row.original?.emptyRow);
57+
58+
if (scaleWidthMode === TableScaleWidthMode.Default || (!hasData && loading)) {
59+
const defaultWidth = calculateDefaultTableWidth();
60+
return columns.map((column) => ({ ...column, width: column.width ?? defaultWidth }));
61+
}
7262

73-
const headerLength = typeof column.Header === 'string' ? column.Header.length : DEFAULT_HEADER_NUM_CHAR;
74-
75-
// max character length
76-
const contentMaxCharLength = Math.max(
77-
headerLength,
78-
...rowSample.map((row) => {
79-
const dataPoint = row.values?.[column.accessor];
80-
if (dataPoint) {
81-
if (typeof dataPoint === 'string') return dataPoint.length;
82-
if (typeof dataPoint === 'number') return (dataPoint + '').length;
83-
}
84-
return 0;
85-
})
86-
);
87-
88-
// avg character length
89-
const contentCharAvg =
90-
rowSample.reduce((acc, item) => {
91-
const dataPoint = item.values?.[column.accessor];
92-
let val = 0;
93-
if (dataPoint) {
94-
if (typeof dataPoint === 'string') val = dataPoint.length;
95-
if (typeof dataPoint === 'number') val = (dataPoint + '').length;
96-
}
97-
return acc + val;
98-
}, 0) / rowSample.length;
99-
100-
const minHeaderWidth = approximateHeaderPxFromCharLength(headerLength);
63+
const rowSample = rows.slice(0, ROW_SAMPLE_SIZE);
10164

65+
const columnMeta = visibleColumns.reduce((acc, column) => {
66+
if (column.id === '__ui5wcr__internal_selection_column' || column.id === '__ui5wcr__internal_highlight_column') {
10267
acc[column.accessor] = {
103-
minHeaderWidth,
104-
fullWidth: Math.max(minHeaderWidth, approximateContentPxFromCharLength(contentMaxCharLength)),
105-
contentCharAvg
68+
minHeaderWidth: column.width,
69+
fullWidth: column.width,
70+
contentCharAvg: 0
10671
};
10772
return acc;
108-
}, {});
109-
110-
const totalCharNum = Object.values(columnMeta).reduce(
111-
(acc: number, item: any) => acc + item.contentCharAvg,
112-
0
113-
) as number;
114-
115-
let reservedWidth = visibleColumns.reduce((acc, column) => {
116-
const { minHeaderWidth, fullWidth } = columnMeta[column.accessor];
117-
return (
118-
acc +
119-
Math.max(
120-
column.minWidth || 0,
121-
column.width || 0,
122-
minHeaderWidth || 0,
123-
scaleWidthMode === TableScaleWidthMode.Grow ? fullWidth : 0
124-
) || 0
125-
);
126-
}, 0);
127-
128-
let availableWidth = totalWidth - reservedWidth;
129-
130-
if (scaleWidthMode === TableScaleWidthMode.Smart || availableWidth > 0) {
131-
if (scaleWidthMode === TableScaleWidthMode.Grow) {
132-
reservedWidth = visibleColumns.reduce((acc, column) => {
133-
const { minHeaderWidth } = columnMeta[column.accessor];
134-
return acc + Math.max(column.minWidth || 0, column.width || 0, minHeaderWidth || 0) || 0;
135-
}, 0);
136-
availableWidth = totalWidth - reservedWidth;
137-
}
138-
139-
return columns.map((column) => {
140-
const isColumnVisible = (column.isVisible ?? true) && !hiddenColumns.includes(column.accessor);
141-
if (isColumnVisible) {
142-
const { minHeaderWidth, contentCharAvg } = columnMeta[column.accessor];
143-
const additionalSpaceFactor = totalCharNum > 0 ? contentCharAvg / totalCharNum : 1 / visibleColumns.length;
73+
}
14474

145-
const targetWidth = additionalSpaceFactor * availableWidth + minHeaderWidth;
75+
const headerLength = typeof column.Header === 'string' ? column.Header.length : DEFAULT_HEADER_NUM_CHAR;
14676

147-
return {
148-
...column,
149-
width: column.width ?? targetWidth,
150-
minWidth: column.minWidth ?? minHeaderWidth
151-
};
77+
// max character length
78+
const contentMaxCharLength = Math.max(
79+
headerLength,
80+
...rowSample.map((row) => {
81+
const dataPoint = row.values?.[column.accessor];
82+
if (dataPoint) {
83+
if (typeof dataPoint === 'string') return dataPoint.length;
84+
if (typeof dataPoint === 'number') return (dataPoint + '').length;
85+
}
86+
return 0;
87+
})
88+
);
89+
90+
// avg character length
91+
const contentCharAvg =
92+
rowSample.reduce((acc, item) => {
93+
const dataPoint = item.values?.[column.accessor];
94+
let val = 0;
95+
if (dataPoint) {
96+
if (typeof dataPoint === 'string') val = dataPoint.length;
97+
if (typeof dataPoint === 'number') val = (dataPoint + '').length;
15298
}
99+
return acc + val;
100+
}, 0) / rowSample.length;
153101

154-
return column;
155-
});
102+
const minHeaderWidth = approximateHeaderPxFromCharLength(headerLength);
103+
104+
acc[column.accessor] = {
105+
minHeaderWidth,
106+
fullWidth: Math.max(minHeaderWidth, approximateContentPxFromCharLength(contentMaxCharLength)),
107+
contentCharAvg
108+
};
109+
return acc;
110+
}, {});
111+
112+
const totalCharNum = Object.values(columnMeta).reduce(
113+
(acc: number, item: any) => acc + item.contentCharAvg,
114+
0
115+
) as number;
116+
117+
let reservedWidth = visibleColumns.reduce((acc, column) => {
118+
const { minHeaderWidth, fullWidth } = columnMeta[column.accessor];
119+
return (
120+
acc +
121+
Math.max(
122+
column.minWidth || 0,
123+
column.width || 0,
124+
minHeaderWidth || 0,
125+
scaleWidthMode === TableScaleWidthMode.Grow ? fullWidth : 0
126+
) || 0
127+
);
128+
}, 0);
129+
130+
let availableWidth = totalWidth - reservedWidth;
131+
132+
if (scaleWidthMode === TableScaleWidthMode.Smart || availableWidth > 0) {
133+
if (scaleWidthMode === TableScaleWidthMode.Grow) {
134+
reservedWidth = visibleColumns.reduce((acc, column) => {
135+
const { minHeaderWidth } = columnMeta[column.accessor];
136+
return acc + Math.max(column.minWidth || 0, column.width || 0, minHeaderWidth || 0) || 0;
137+
}, 0);
138+
availableWidth = totalWidth - reservedWidth;
156139
}
157140

158-
// TableScaleWidthMode Grow
159141
return columns.map((column) => {
160142
const isColumnVisible = (column.isVisible ?? true) && !hiddenColumns.includes(column.accessor);
161143
if (isColumnVisible) {
162-
const { fullWidth } = columnMeta[column.accessor];
144+
const { minHeaderWidth, contentCharAvg } = columnMeta[column.accessor];
145+
const additionalSpaceFactor = totalCharNum > 0 ? contentCharAvg / totalCharNum : 1 / visibleColumns.length;
146+
147+
const targetWidth = additionalSpaceFactor * availableWidth + minHeaderWidth;
148+
163149
return {
164150
...column,
165-
width: column.width ?? fullWidth,
166-
maxWidth: MAX_WIDTH
151+
width: column.width ?? targetWidth,
152+
minWidth: column.minWidth ?? minHeaderWidth
167153
};
168154
}
155+
169156
return column;
170157
});
158+
}
159+
160+
// TableScaleWidthMode Grow
161+
return columns.map((column) => {
162+
const isColumnVisible = (column.isVisible ?? true) && !hiddenColumns.includes(column.accessor);
163+
if (isColumnVisible) {
164+
const { fullWidth } = columnMeta[column.accessor];
165+
return {
166+
...column,
167+
width: column.width ?? fullWidth,
168+
maxWidth: MAX_WIDTH
169+
};
170+
}
171+
return column;
171172
});
172173
};
174+
175+
export const useDynamicColumnWidths = (hooks) => {
176+
hooks.columns.push(columns);
177+
hooks.columnsDeps.push(columnsDeps);
178+
};

0 commit comments

Comments
 (0)