UNPKG

@grafana/ui

Version:
331 lines (328 loc) • 11.1 kB
import { jsxs, jsx } from 'react/jsx-runtime'; import { css, cx } from '@emotion/css'; import { useState, useMemo, useCallback, useEffect } from 'react'; import { VariableSizeList } from 'react-window'; import { Subscription, debounceTime } from 'rxjs'; import { FieldType, DataHoverEvent, DataHoverClearEvent, hasTimeField } from '@grafana/data'; import { TableCellHeight, TableCellDisplayMode } from '@grafana/schema'; import { useTheme2 } from '../../../themes/ThemeContext.mjs'; import { CustomScrollbar } from '../../CustomScrollbar/CustomScrollbar.mjs'; import '../../PanelChrome/index.mjs'; import { TableCell } from '../Cells/TableCell.mjs'; import { calculateAroundPointThreshold, isPointTimeValAroundTableTimeVal, guessTextBoundingBox, getCellColors } from '../utils.mjs'; import { ExpandedRow, getExpandedRowHeight } from './ExpandedRow.mjs'; import { usePanelContext } from '../../PanelChrome/PanelContext.mjs'; const RowsList = (props) => { const { data, rows, headerHeight, footerPaginationEnabled, rowHeight, itemCount, pageIndex, tableState, prepareRow, onCellFilterAdded, width, cellHeight = TableCellHeight.Sm, timeRange, tableStyles, nestedDataField, listHeight, listRef, enableSharedCrosshair = false, initialRowIndex = void 0, headerGroups, longestField, textWrapField, getActions, replaceVariables, setInspectCell } = props; const [rowHighlightIndex, setRowHighlightIndex] = useState(initialRowIndex); if (initialRowIndex === void 0 && rowHighlightIndex !== void 0) { setRowHighlightIndex(void 0); } const theme = useTheme2(); const panelContext = usePanelContext(); let osContext = null; if (window.OffscreenCanvas !== void 0) { osContext = new OffscreenCanvas(256, 1024).getContext("2d"); } if (osContext !== void 0 && osContext !== null) { osContext.font = `${theme.typography.fontSize}px ${theme.typography.body.fontFamily}`; } const threshold = useMemo(() => { const timeField = data.fields.find((f) => f.type === FieldType.time); if (!timeField) { return 0; } return calculateAroundPointThreshold(timeField); }, [data]); const onRowHover = useCallback( (idx, frame) => { if (!panelContext || !enableSharedCrosshair) { return; } const timeField = frame.fields.find((f) => f.type === FieldType.time); if (!timeField) { return; } panelContext.eventBus.publish( new DataHoverEvent({ point: { time: timeField.values[idx] } }) ); }, [enableSharedCrosshair, panelContext] ); const onRowLeave = useCallback(() => { if (!panelContext || !enableSharedCrosshair) { return; } panelContext.eventBus.publish(new DataHoverClearEvent()); }, [enableSharedCrosshair, panelContext]); const onDataHoverEvent = useCallback( (evt) => { var _a; if (((_a = evt.payload.point) == null ? void 0 : _a.time) && evt.payload.rowIndex !== void 0) { const timeField = data.fields.find((f) => f.type === FieldType.time); const time = timeField.values[evt.payload.rowIndex]; const pointTime = evt.payload.point.time; if (isPointTimeValAroundTableTimeVal(pointTime, time, threshold)) { setRowHighlightIndex(evt.payload.rowIndex); return; } const matchedRowIndex = timeField.values.findIndex( (t) => isPointTimeValAroundTableTimeVal(pointTime, t, threshold) ); if (matchedRowIndex !== -1) { setRowHighlightIndex(matchedRowIndex); return; } setRowHighlightIndex(void 0); } }, [data.fields, threshold] ); useEffect(() => { if (!panelContext || !enableSharedCrosshair || !hasTimeField(data) || footerPaginationEnabled) { return; } const subs = new Subscription(); subs.add( panelContext.eventBus.getStream(DataHoverEvent).pipe(debounceTime(250)).subscribe({ next: (evt) => { if (panelContext.eventBus === evt.origin) { return; } onDataHoverEvent(evt); } }) ); subs.add( panelContext.eventBus.getStream(DataHoverClearEvent).pipe(debounceTime(250)).subscribe({ next: (evt) => { if (panelContext.eventBus === evt.origin) { return; } setRowHighlightIndex(void 0); } }) ); return () => { subs.unsubscribe(); }; }, [data, enableSharedCrosshair, footerPaginationEnabled, onDataHoverEvent, panelContext]); let scrollTop = void 0; if (rowHighlightIndex !== void 0) { const firstMatchedRowIndex = rows.findIndex((row) => row.index === rowHighlightIndex); if (firstMatchedRowIndex !== -1) { scrollTop = headerHeight + (firstMatchedRowIndex - 1) * rowHeight; } } const rowIndexForPagination = useCallback( (index) => { return tableState.pageIndex * tableState.pageSize + index; }, [tableState.pageIndex, tableState.pageSize] ); let rowBg = void 0; let textWrapFinal; for (const field of data.fields) { const fieldOptions = field.config.custom; const cellOptionsExist = fieldOptions !== void 0 && fieldOptions.cellOptions !== void 0; if (cellOptionsExist && fieldOptions.cellOptions.type === TableCellDisplayMode.ColorBackground && fieldOptions.cellOptions.applyToRow) { rowBg = (rowIndex) => { const display = field.display(field.values.get(rowIndex)); const colors = getCellColors(tableStyles.theme, fieldOptions.cellOptions, display); return colors; }; } if (textWrapField !== void 0) { textWrapFinal = textWrapField; } else if (longestField !== void 0) { textWrapFinal = longestField; } } const RenderRow = useCallback( ({ index, style, rowHighlightIndex: rowHighlightIndex2 }) => { const indexForPagination = rowIndexForPagination(index); const row = rows[indexForPagination]; let additionalProps = {}; prepareRow(row); const expandedRowStyle = tableState.expanded[row.id] ? css({ "&:hover": { background: "inherit" } }) : {}; const rowExpanded = nestedDataField && tableState.expanded[row.id]; if (rowHighlightIndex2 !== void 0 && row.index === rowHighlightIndex2) { style = { ...style, backgroundColor: theme.components.table.rowSelected }; additionalProps = { "aria-selected": "true" }; } if (rowBg) { const { bgColor, textColor } = rowBg(row.index); style.background = bgColor; style.color = textColor; style.borderLeft = `2px solid ${bgColor}`; } if (textWrapFinal) { const visibleFields = data.fields.filter((field) => { var _a; return !Boolean((_a = field.config.custom) == null ? void 0 : _a.hidden); }); const seriesIndex = visibleFields.findIndex((field) => field.name === textWrapFinal.name); const pxLineHeight = theme.typography.body.lineHeight * theme.typography.fontSize; const bbox = guessTextBoundingBox( textWrapFinal.values[row.index], headerGroups[0].headers[seriesIndex], osContext, pxLineHeight, tableStyles.rowHeight, tableStyles.cellPadding ); style.height = bbox.height; } const { key, ...rowProps } = row.getRowProps({ style, ...additionalProps }); return /* @__PURE__ */ jsxs( "div", { ...rowProps, className: cx(tableStyles.row, expandedRowStyle), onMouseEnter: () => onRowHover(row.index, data), onMouseLeave: onRowLeave, children: [ rowExpanded && /* @__PURE__ */ jsx( ExpandedRow, { nestedData: nestedDataField, tableStyles, rowIndex: row.index, width, cellHeight } ), row.cells.map((cell, index2) => /* @__PURE__ */ jsx( TableCell, { tableStyles, cell, onCellFilterAdded, columnIndex: index2, columnCount: row.cells.length, timeRange, frame: data, rowStyled: rowBg !== void 0, rowExpanded, textWrapped: textWrapFinal !== void 0, height: Number(style.height) - 1, getActions, replaceVariables, setInspectCell }, index2 )) ] }, key ); }, [ rowIndexForPagination, rows, prepareRow, tableState.expanded, nestedDataField, rowBg, textWrapFinal, tableStyles, onRowLeave, width, cellHeight, theme.components.table.rowSelected, theme.typography.body.lineHeight, theme.typography.fontSize, data, headerGroups, osContext, onRowHover, onCellFilterAdded, timeRange, getActions, replaceVariables, setInspectCell ] ); const getItemSize = (index) => { const indexForPagination = rowIndexForPagination(index); const row = rows[indexForPagination]; if (tableState.expanded[row.id] && nestedDataField) { return getExpandedRowHeight(nestedDataField, row.index, tableStyles); } if (textWrapFinal) { const visibleFields = data.fields.filter((field) => { var _a; return !Boolean((_a = field.config.custom) == null ? void 0 : _a.hidden); }); const seriesIndex = visibleFields.findIndex((field) => field.name === textWrapFinal.name); const pxLineHeight = theme.typography.fontSize * theme.typography.body.lineHeight; return guessTextBoundingBox( textWrapFinal.values[row.index], headerGroups[0].headers[seriesIndex], osContext, pxLineHeight, tableStyles.rowHeight, tableStyles.cellPadding ).height; } return tableStyles.rowHeight; }; const handleScroll = (event) => { const { scrollTop: scrollTop2 } = event.currentTarget; if (listRef.current !== null) { listRef.current.scrollTo(scrollTop2); } }; useEffect(() => { if (listRef.current) { listRef.current.resetAfterIndex(0); } }, [rows, listRef]); return /* @__PURE__ */ jsx(CustomScrollbar, { onScroll: handleScroll, hideHorizontalTrack: true, scrollTop, children: /* @__PURE__ */ jsx( VariableSizeList, { height: listHeight, itemCount, itemSize: getItemSize, width: "100%", ref: listRef, style: { overflow: void 0 }, children: ({ index, style }) => RenderRow({ index, style, rowHighlightIndex }) }, `${rowHeight}${pageIndex}` ) }); }; export { RowsList }; //# sourceMappingURL=RowsList.mjs.map