@grafana/ui
Version:
Grafana Components Library
331 lines (328 loc) • 11.1 kB
JavaScript
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