in packages/eui/src/components/basic_table/basic_table.tsx [974:1103]
renderItemRow(item: T, rowIndex: number, displayedRowIndex: number) {
const { columns, selection, rowHeader, itemIdToExpandedRowMap } =
this.props;
const cells = [];
const { itemId: itemIdCallback } = this.props;
const itemId: ItemIdResolved =
getItemId(item, itemIdCallback) != null
? getItemId(item, itemIdCallback)
: rowIndex;
const selected = !selection
? false
: this.state.selection &&
!!this.state.selection.find(
(selectedItem: T) =>
getItemId(selectedItem, itemIdCallback) === itemId
);
let rowSelectionDisabled = false;
if (selection) {
const [checkboxCell, isDisabled] = this.renderItemSelectionCell(
itemId,
item,
selected,
displayedRowIndex
);
cells.push(checkboxCell);
rowSelectionDisabled = !!isDisabled;
}
let hasActions: 'custom' | boolean = false;
columns.forEach((column: EuiBasicTableColumn<T>, columnIndex: number) => {
const columnActions = (column as EuiTableActionsColumnType<T>).actions;
if (columnActions) {
const hasCustomActions = columnActions.some(
(action) => !!(action as CustomItemAction<T>).render
);
cells.push(
this.renderItemActionsCell(
itemId,
item,
column as EuiTableActionsColumnType<T>,
columnIndex,
rowIndex,
hasCustomActions
)
);
// A table theoretically could have both custom and default action items
// If it has both, default action mobile row styles take precedence over custom
hasActions = !hasActions && hasCustomActions ? 'custom' : true;
} else if ((column as EuiTableFieldDataColumnType<T>).field) {
const fieldDataColumn = column as EuiTableFieldDataColumnType<T>;
cells.push(
this.renderItemFieldDataCell(
itemId,
item,
column as EuiTableFieldDataColumnType<T>,
columnIndex,
fieldDataColumn.field === rowHeader
)
);
} else {
cells.push(
this.renderItemComputedCell(
itemId,
item,
column as EuiTableComputedColumnType<T>,
columnIndex
)
);
}
});
// Occupy full width of table, taking checkbox & mobile only columns into account.
let expandedRowColSpan = selection ? columns.length + 1 : columns.length;
const mobileOnlyCols = columns.reduce<number>((num, column) => {
return (column as EuiTableFieldDataColumnType<T>)?.mobileOptions?.only
? num + 1
: num + 0; // BWC only
}, 0);
expandedRowColSpan = expandedRowColSpan - mobileOnlyCols;
// We'll use the ID to associate the expanded row with the original.
const hasExpandedRow = itemIdToExpandedRowMap?.hasOwnProperty(itemId);
const expandedRowId = hasExpandedRow
? `row_${itemId}_expansion`
: undefined;
const expandedRow = hasExpandedRow ? (
<EuiTableRow
id={expandedRowId}
isExpandedRow={true}
hasSelection={!!selection}
>
<EuiTableRowCell
colSpan={expandedRowColSpan}
textOnly={false}
append={tabularCopyMarkers.hiddenNewline}
>
{itemIdToExpandedRowMap![itemId]}
</EuiTableRowCell>
</EuiTableRow>
) : undefined;
const { rowProps: rowPropsCallback } = this.props;
const rowProps = getRowProps(item, rowPropsCallback as RowPropsCallback<T>);
const row = (
<EuiTableRow
aria-owns={expandedRowId}
hasSelection={!!selection}
isSelectable={!rowSelectionDisabled}
isSelected={selected}
hasActions={hasActions}
isExpandable={hasExpandedRow}
{...rowProps}
>
{cells}
</EuiTableRow>
);
return (
<Fragment key={`row_${itemId}`}>
{row}
{expandedRow}
</Fragment>
);
}