diff --git a/package.json b/package.json
index 40c443583..68e3d6ee9 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@netdata/netdata-ui",
- "version": "5.4.16",
+ "version": "5.4.17",
"description": "netdata UI kit",
"main": "dist/index.js",
"module": "dist/es6/index.js",
diff --git a/src/components/table/body/columnFlex.js b/src/components/table/body/columnFlex.js
new file mode 100644
index 000000000..5034d27be
--- /dev/null
+++ b/src/components/table/body/columnFlex.js
@@ -0,0 +1,5 @@
+export default (column, header, hasExplicitSize) =>
+ (column.columnDef.notFlex || column.getCanResize()) &&
+ (!column.columnDef.fullWidth || hasExplicitSize)
+ ? false
+ : header.colSpan
diff --git a/src/components/table/body/header/cell.js b/src/components/table/body/header/cell.js
index 3f83b32ff..cd5062232 100644
--- a/src/components/table/body/header/cell.js
+++ b/src/components/table/body/header/cell.js
@@ -5,6 +5,7 @@ import Flex from "@/components/templates/flex"
import { Text } from "@/components/typography"
import { useTableState } from "../../provider"
import ResizeHandler from "./resizeHandler"
+import getColumnFlex from "../columnFlex"
import Sorting, { SortIconContainer } from "./sorting"
import Info from "./info"
import Filter from "./filter"
@@ -73,11 +74,7 @@ const BodyHeaderCell = ({
s + h.column.getSize(), 0) : column.getSize()}px`}
height={{ min: "45px" }}
position="relative"
@@ -125,7 +122,7 @@ const BodyHeaderCell = ({
-
+
{children}
)
diff --git a/src/components/table/body/header/resizeHandler.js b/src/components/table/body/header/resizeHandler.js
index fca349170..a52243b85 100644
--- a/src/components/table/body/header/resizeHandler.js
+++ b/src/components/table/body/header/resizeHandler.js
@@ -1,10 +1,26 @@
-import React from "react"
+import React, { useRef } from "react"
+import { flushSync } from "react-dom"
import styled from "styled-components"
import Flex from "@/components/templates/flex"
import { useTableState } from "../../provider"
const rerenderSelector = state => state.columnSizingInfo?.deltaPercentage
+const AUTO_FIT_PADDING = 8
+
+const AUTO_FIT_MAX_RATIO = 0.5
+
+const naturalWidthStyles = {
+ width: "max-content",
+ minWidth: "max-content",
+ maxWidth: "none",
+ whiteSpace: "nowrap",
+ overflow: "visible",
+ textOverflow: "clip",
+ flexWrap: "nowrap",
+ flexShrink: "0",
+}
+
export const Handler = styled(Flex).attrs({
position: "absolute",
top: "2px",
@@ -12,16 +28,93 @@ export const Handler = styled(Flex).attrs({
bottom: "2px",
})``
-const ResizeHandler = ({ header, table }) => {
+const measureNaturalWidth = (nodes, forceNowrap) => {
+ const probe = document.createElement("div")
+ probe.style.cssText = [
+ "position:absolute",
+ "visibility:hidden",
+ "pointer-events:none",
+ "left:-9999px",
+ "top:0",
+ "width:max-content",
+ "min-width:max-content",
+ "max-width:none",
+ "white-space:nowrap",
+ ].join(";")
+ document.body.appendChild(probe)
+
+ let max = 0
+ try {
+ nodes.forEach(node => {
+ const clone = node.cloneNode(true)
+ clone.style.width = "max-content"
+ clone.style.minWidth = "max-content"
+ clone.style.maxWidth = "none"
+
+ const cs = getComputedStyle(node)
+ clone.style.fontFamily = cs.fontFamily
+ clone.style.fontSize = cs.fontSize
+ clone.style.fontWeight = cs.fontWeight
+ clone.style.fontStyle = cs.fontStyle
+ clone.style.letterSpacing = cs.letterSpacing
+
+ if (forceNowrap) {
+ clone.querySelectorAll("*").forEach(el => Object.assign(el.style, naturalWidthStyles))
+ Object.assign(clone.style, naturalWidthStyles)
+ }
+
+ probe.appendChild(clone)
+ max = Math.max(max, clone.getBoundingClientRect().width, clone.scrollWidth)
+ probe.removeChild(clone)
+ })
+ } finally {
+ document.body.removeChild(probe)
+ }
+
+ return max
+}
+
+const ResizeHandler = ({ header, table, testPrefix = "" }) => {
useTableState(rerenderSelector)
+ const ref = useRef()
if (!header.column.getCanResize()) return null
- const resizingProps = header.column.getIsResizing()
+ const { column } = header
+
+ const resizingProps = column.getIsResizing()
? { transform: `translateX(${table.getState().columnSizingInfo.deltaOffset}px)` }
: {}
+ const handleResizeStart = e => {
+ if (column.columnDef.fullWidth && table.getState().columnSizing?.[column.id] == null) {
+ const width = ref.current?.parentElement?.getBoundingClientRect().width
+ if (width) flushSync(() => table.setColumnSizing(old => ({ ...old, [column.id]: width })))
+ }
+ header.getResizeHandler()(e)
+ }
+
+ const handleAutoFit = () => {
+ const headerCell = ref.current?.parentElement
+ if (!headerCell) return
+
+ const container = headerCell.closest(`[data-testid="netdata-table${testPrefix}"]`)
+ const cells = container
+ ? [...container.querySelectorAll('[data-testid^="netdata-table-cell-"]')].filter(
+ el => el.getAttribute("data-testid") === `netdata-table-cell-${column.id}${testPrefix}`
+ )
+ : []
+
+ const max = measureNaturalWidth([headerCell, ...cells], !column.columnDef.fullWidth)
+ if (!max) return
+
+ const limit = container ? container.clientWidth * AUTO_FIT_MAX_RATIO : Infinity
+ const width = Math.min(Math.ceil(max) + AUTO_FIT_PADDING, limit)
+ table.setColumnSizing(old => ({ ...old, [column.id]: width }))
+ }
+
return (
{
cursor: "col-resize",
...resizingProps,
}}
- onMouseDown={header.getResizeHandler()}
- onTouchStart={header.getResizeHandler()}
+ onMouseDown={handleResizeStart}
+ onTouchStart={handleResizeStart}
+ onDoubleClick={handleAutoFit}
/>
)
}
diff --git a/src/components/table/body/row.js b/src/components/table/body/row.js
index 9b406cac7..cf63849c3 100644
--- a/src/components/table/body/row.js
+++ b/src/components/table/body/row.js
@@ -3,8 +3,9 @@ import styled from "styled-components"
import Flex from "@/components/templates/flex"
import { getColor } from "@/theme"
import { useTableState } from "../provider"
+import getColumnFlex from "./columnFlex"
-const CellGroup = ({ cell, row, header, testPrefix, coloredSortedColumn }) => {
+const CellGroup = ({ cell, row, table, header, testPrefix, coloredSortedColumn }) => {
const { column } = cell
const tableMeta = useMemo(
@@ -32,11 +33,7 @@ const CellGroup = ({ cell, row, header, testPrefix, coloredSortedColumn }) => {
return (
({
columnVisibility: state.columnVisibility,
selectedRows: state.selectedRows,
allColumns: state.allColumns?.length,
+ visibleColumns: state.visibleColumns,
})
const StyledRow = styled(Flex)`
@@ -147,6 +145,7 @@ export default memo(
{
{
rowsById: table.getRowModel().rowsById,
selectedRows: table.getSelectedRowModel().flatRows,
allColumns: table?.getAllLeafColumns?.(),
+ visibleColumns: table?.getVisibleLeafColumns?.().map(column => column.id),
})
}, [table.getState()])