UNPKG

@grafana/ui

Version:
320 lines (317 loc) • 11.2 kB
import { jsxs, jsx, Fragment } from 'react/jsx-runtime'; import { memo, useRef, useState, useMemo, useEffect, useCallback } from 'react'; import { useTable, useFilters, useSortBy, useAbsoluteLayout, useResizeColumns, useExpanded, usePagination } from 'react-table'; import { ReducerID, FieldType, getRowUniqueId, getFieldMatcher } from '@grafana/data'; import { selectors } from '@grafana/e2e-selectors'; import { Trans } from '@grafana/i18n'; import { TableCellHeight } from '@grafana/schema'; import { useTheme2 } from '../../../themes/ThemeContext.mjs'; import { CustomScrollbar } from '../../CustomScrollbar/CustomScrollbar.mjs'; import { Pagination } from '../../Pagination/Pagination.mjs'; import { TableCellInspector } from '../TableCellInspector.mjs'; import { useResetVariableListSizeCache, useFixScrollbarContainer } from '../hooks.mjs'; import { useTableStateReducer, getInitialState } from '../reducer.mjs'; import { getColumns, sortCaseInsensitive, sortNumber, getFooterItems, createFooterCalculationValues, guessLongestField } from '../utils.mjs'; import { FooterRow } from './FooterRow.mjs'; import { HeaderRow } from './HeaderRow.mjs'; import { RowsList } from './RowsList.mjs'; import { useTableStyles } from './styles.mjs'; "use strict"; const COLUMN_MIN_WIDTH = 150; const FOOTER_ROW_HEIGHT = 36; const NO_DATA_TEXT = "No data"; const Table = memo((props) => { var _a, _b, _c, _d; const { ariaLabel, data, height, onCellFilterAdded, onColumnResize, width, columnMinWidth = COLUMN_MIN_WIDTH, noHeader, resizable = true, initialSortBy, footerOptions, showTypeIcons, footerValues, enablePagination, cellHeight = TableCellHeight.Sm, timeRange, enableSharedCrosshair = false, initialRowIndex = void 0, fieldConfig, getActions, replaceVariables } = props; const listRef = useRef(null); const tableDivRef = useRef(null); const variableSizeListScrollbarRef = useRef(null); const theme = useTheme2(); const tableStyles = useTableStyles(theme, cellHeight); const headerHeight = noHeader ? 0 : tableStyles.rowHeight; const [footerItems, setFooterItems] = useState(footerValues); const noValuesDisplayText = (_b = (_a = fieldConfig == null ? void 0 : fieldConfig.defaults) == null ? void 0 : _a.noValue) != null ? _b : NO_DATA_TEXT; const [inspectCell, setInspectCell] = useState(null); const footerHeight = useMemo(() => { const EXTENDED_ROW_HEIGHT = FOOTER_ROW_HEIGHT; let length = 0; if (!footerItems) { return 0; } for (const fv of footerItems) { if (Array.isArray(fv) && fv.length > length) { length = fv.length; } } if (length > 1) { return EXTENDED_ROW_HEIGHT * length; } return EXTENDED_ROW_HEIGHT; }, [footerItems]); const memoizedData = useMemo(() => { if (!data.fields.length) { return []; } return Array(data.length).fill(0); }, [data]); const isCountRowsSet = Boolean( (footerOptions == null ? void 0 : footerOptions.countRows) && footerOptions.reducer && footerOptions.reducer.length && footerOptions.reducer[0] === ReducerID.count ); const nestedDataField = data.fields.find((f) => f.type === FieldType.nestedFrames); const hasNestedData = nestedDataField !== void 0; const memoizedColumns = useMemo( () => getColumns(data, width, columnMinWidth, hasNestedData, footerItems, isCountRowsSet), [data, width, columnMinWidth, hasNestedData, footerItems, isCountRowsSet] ); const toggleAllRowsExpandedRef = useRef(); const stateReducer = useTableStateReducer({ onColumnResize, onSortByChange: (state2) => { toggleAllRowsExpandedRef.current(false); if (props.onSortByChange) { props.onSortByChange(state2); } }, data }); const hasUniqueId = !!((_d = (_c = data.meta) == null ? void 0 : _c.uniqueRowIdFields) == null ? void 0 : _d.length); const options = useMemo(() => { const options2 = { columns: memoizedColumns, data: memoizedData, disableResizing: !resizable, stateReducer, autoResetPage: false, initialState: getInitialState(initialSortBy, memoizedColumns), autoResetFilters: false, sortTypes: { // the builtin number type on react-table does not handle NaN values number: sortNumber, // should be replaced with the builtin string when react-table is upgraded, // see https://github.com/tannerlinsley/react-table/pull/3235 "alphanumeric-insensitive": sortCaseInsensitive } }; if (hasUniqueId) { options2.getRowId = (row, relativeIndex) => getRowUniqueId(data, relativeIndex); options2.autoResetExpanded = false; } return options2; }, [initialSortBy, memoizedColumns, memoizedData, resizable, stateReducer, hasUniqueId, data]); const { getTableProps, headerGroups, footerGroups, rows, prepareRow, totalColumnsWidth, page, state, gotoPage, setPageSize, pageOptions, toggleAllRowsExpanded } = useTable(options, useFilters, useSortBy, useAbsoluteLayout, useResizeColumns, useExpanded, usePagination); const extendedState = state; toggleAllRowsExpandedRef.current = toggleAllRowsExpanded; useEffect(() => { if (!footerOptions) { setFooterItems(footerValues); } }, [footerValues, footerOptions]); useEffect(() => { var _a2; if (!footerOptions) { return; } if (!footerOptions.show) { setFooterItems(void 0); return; } if (isCountRowsSet) { const footerItemsCountRows = []; footerItemsCountRows[0] = (_a2 = rows.length.toString()) != null ? _a2 : data.length.toString(); setFooterItems(footerItemsCountRows); return; } const footerItems2 = getFooterItems( headerGroups[0].headers, createFooterCalculationValues(rows), footerOptions, theme ); setFooterItems(footerItems2); }, [footerOptions, theme, state.filters, data]); let listHeight = height - (headerHeight + footerHeight); if (enablePagination) { listHeight -= tableStyles.cellHeight; } const pageSize = Math.round(listHeight / tableStyles.rowHeight) - 1; useEffect(() => { if (pageSize <= 0) { return; } setPageSize(pageSize); }, [pageSize, setPageSize]); useEffect(() => { if (data.length / pageSize < state.pageIndex) { gotoPage(0); } }, [data]); useResetVariableListSizeCache(extendedState, listRef, data, hasUniqueId); useFixScrollbarContainer(variableSizeListScrollbarRef, tableDivRef); const onNavigate = useCallback( (toPage) => { gotoPage(toPage - 1); }, [gotoPage] ); const itemCount = enablePagination ? page.length : rows.length; let paginationEl = null; if (enablePagination) { const itemsRangeStart = state.pageIndex * state.pageSize + 1; let itemsRangeEnd = itemsRangeStart + state.pageSize - 1; const isSmall = width < 550; if (itemsRangeEnd > data.length) { itemsRangeEnd = data.length; } const numRows = rows.length; const displayedEnd = itemsRangeEnd < rows.length ? itemsRangeEnd : rows.length; paginationEl = /* @__PURE__ */ jsxs("div", { className: tableStyles.paginationWrapper, children: [ /* @__PURE__ */ jsx( Pagination, { currentPage: state.pageIndex + 1, numberOfPages: pageOptions.length, showSmallVersion: isSmall, onNavigate } ), isSmall ? null : /* @__PURE__ */ jsx("div", { className: tableStyles.paginationSummary, children: /* @__PURE__ */ jsxs(Trans, { i18nKey: "grafana-ui.table.pagination-summary", children: [ { itemsRangeStart }, " - ", { displayedEnd }, " of ", { numRows }, " rows" ] }) }) ] }); } const longestField = fieldConfig ? guessLongestField(fieldConfig, data) : void 0; let textWrapField = void 0; if (fieldConfig !== void 0) { data.fields.forEach((field) => { fieldConfig.overrides.forEach((override) => { const matcher = getFieldMatcher(override.matcher); if (matcher(field, data, [data])) { for (const property of override.properties) { if (property.id === "custom.cellOptions" && property.value.wrapText) { textWrapField = field; } } } }); }); } return /* @__PURE__ */ jsxs(Fragment, { children: [ /* @__PURE__ */ jsxs( "div", { ...getTableProps(), className: tableStyles.table, "aria-label": ariaLabel, role: "table", ref: tableDivRef, style: { width, height }, children: [ /* @__PURE__ */ jsx(CustomScrollbar, { hideVerticalTrack: true, children: /* @__PURE__ */ jsxs("div", { className: tableStyles.tableContentWrapper(totalColumnsWidth), children: [ !noHeader && /* @__PURE__ */ jsx(HeaderRow, { headerGroups, showTypeIcons, tableStyles }), itemCount > 0 ? /* @__PURE__ */ jsx( "div", { "data-testid": selectors.components.Panels.Visualization.Table.body, ref: variableSizeListScrollbarRef, children: /* @__PURE__ */ jsx( RowsList, { headerGroups, data, rows, width, cellHeight, headerHeight, rowHeight: tableStyles.rowHeight, itemCount, pageIndex: state.pageIndex, listHeight, listRef, tableState: state, prepareRow, timeRange, onCellFilterAdded, nestedDataField, tableStyles, footerPaginationEnabled: Boolean(enablePagination), enableSharedCrosshair, initialRowIndex, longestField, textWrapField, getActions, replaceVariables, setInspectCell } ) } ) : /* @__PURE__ */ jsx("div", { style: { height: height - headerHeight, width }, className: tableStyles.noData, children: noValuesDisplayText }), footerItems && /* @__PURE__ */ jsx( FooterRow, { isPaginationVisible: Boolean(enablePagination), footerValues: footerItems, footerGroups, totalColumnsWidth, tableStyles } ) ] }) }), paginationEl ] } ), inspectCell !== null && /* @__PURE__ */ jsx( TableCellInspector, { mode: inspectCell.mode, value: inspectCell.value, onDismiss: () => { setInspectCell(null); } } ) ] }); }); Table.displayName = "Table"; export { Table }; //# sourceMappingURL=Table.mjs.map