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