* ============LICENSE_END==========================================================================
*/
import * as React from 'react';
-import { withStyles, WithStyles, createStyles, Theme } from '@material-ui/core/styles';
+import { Theme } from '@mui/material/styles';
-import Table from '@material-ui/core/Table';
-import TableBody from '@material-ui/core/TableBody';
-import TableCell from '@material-ui/core/TableCell';
-import TableContainer from '@material-ui/core/TableContainer';
-import TablePagination from '@material-ui/core/TablePagination';
-import TableRow from '@material-ui/core/TableRow';
-import Paper from '@material-ui/core/Paper';
-import Checkbox from '@material-ui/core/Checkbox';
+import { WithStyles } from '@mui/styles';
+import withStyles from '@mui/styles/withStyles';
+import createStyles from '@mui/styles/createStyles';
+
+import Table from '@mui/material/Table';
+import TableBody from '@mui/material/TableBody';
+import TableCell from '@mui/material/TableCell';
+import TableContainer from '@mui/material/TableContainer';
+import TablePagination from '@mui/material/TablePagination';
+import TableRow from '@mui/material/TableRow';
+import Paper from '@mui/material/Paper';
+import Checkbox from '@mui/material/Checkbox';
import { TableToolbar } from './tableToolbar';
import { EnhancedTableHead } from './tableHead';
import { EnhancedTableFilter } from './tableFilter';
import { ColumnModel, ColumnType } from './columnModel';
-import { Omit, Menu, makeStyles } from '@material-ui/core';
+import { Menu, Typography } from '@mui/material';
+import { DistributiveOmit } from '@mui/types';
+
+import makeStyles from '@mui/styles/makeStyles';
-import { SvgIconProps } from '@material-ui/core/SvgIcon/SvgIcon';
+import { SvgIconProps } from '@mui/material/SvgIcon';
-import { DividerTypeMap } from '@material-ui/core/Divider';
-import { MenuItemProps } from '@material-ui/core/MenuItem';
-import { flexbox } from '@material-ui/system';
+import { DividerTypeMap } from '@mui/material/Divider';
+import { MenuItemProps } from '@mui/material/MenuItem';
+import { flexbox } from '@mui/system';
import { RowDisabled } from './utilities';
+import { toAriaLabel } from '../../utilities/yangHelper';
export { ColumnModel, ColumnType } from './columnModel';
type propType = string | number | null | undefined | (string | number)[];
function regExpEscape(s: string) {
return s.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&');
-};
+}
function wildcardCheck(input: string, pattern: string) {
if (!pattern) return true;
(!pattern.endsWith('*') ? '$' : '')
);
return input.match(regex) !== null && input.match(regex)!.length >= 1;
-};
+}
function desc(a: dataType, b: dataType, orderBy: string) {
if ((b[orderBy] || "") < (a[orderBy] || "")) {
flex: "1 1 100%"
},
pagination: {
- overflow: "hidden"
+ overflow: "hidden",
+ minHeight: "52px"
}
});
rowsPerPage: number;
loading: boolean;
showFilter: boolean;
+ hiddenColumns: string[];
filter: { [property: string]: string };
};
export type TableApi = { forceRefresh?: () => Promise<void> };
-type MaterialTableComponentBaseProps<TData> = WithStyles<typeof styles> & {
+type MaterialTableComponentBaseProps<TData> = WithStyles<typeof styles> & {
className?: string;
columns: ColumnModel<TData>[];
idProperty: keyof TData | ((data: TData) => React.Key);
- tableId?: string;
+
+ //Note: used to save settings as well. Must be unique across apps. Null tableIds will not get saved to the settings
+ tableId: string | null;
+ isPopup?: boolean;
title?: string;
stickyHeader?: boolean;
+ allowHtmlHeader?: boolean;
defaultSortOrder?: 'asc' | 'desc';
defaultSortColumn?: keyof TData;
enableSelection?: boolean;
onHandleChangePage: (page: number) => void;
onHandleChangeRowsPerPage: (rowsPerPage: number | null) => void;
onHandleRequestSort: (property: string) => void;
+ onHideColumns : (columnNames: string[]) => void
+ onShowColumns: (columnNames: string[]) => void
};
type MaterialTableComponentProps<TData = {}> =
propsWithExternalState.onHandleChangePage instanceof Function ||
propsWithExternalState.onHandleChangeRowsPerPage instanceof Function ||
propsWithExternalState.onToggleFilter instanceof Function ||
+ propsWithExternalState.onHideColumns instanceof Function ||
propsWithExternalState.onHandleRequestSort instanceof Function
}
+// get settings in here!
+
+
class MaterialTableComponent<TData extends {} = {}> extends React.Component<MaterialTableComponentProps, MaterialTableComponentState & { contextMenuInfo: { index: number; mouseX?: number; mouseY?: number }; }> {
constructor(props: MaterialTableComponentProps) {
super(props);
+
const page = isMaterialTableComponentPropsWithRowsAndRequestData(this.props) ? this.props.page : 0;
const rowsPerPage = isMaterialTableComponentPropsWithRowsAndRequestData(this.props) ? this.props.rowsPerPage || 10 : 10;
selected: isMaterialTableComponentPropsWithRowsAndRequestData(this.props) ? this.props.selected : null,
rows: isMaterialTableComponentPropsWithRows(this.props) && this.props.rows.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage) || [],
total: isMaterialTableComponentPropsWithRows(this.props) && this.props.rows.length || 0,
+ hiddenColumns: isMaterialTableComponentPropsWithRowsAndRequestData(this.props) && this.props.hiddenColumns || [],
page,
rowsPerPage,
};
}
}
render(): JSX.Element {
- const { classes, columns } = this.props;
+ const { classes, columns, allowHtmlHeader } = this.props;
const { rows, total: rowCount, order, orderBy, selected, rowsPerPage, page, showFilter, filter } = this.state;
const emptyRows = rowsPerPage - Math.min(rowsPerPage, rowCount - page * rowsPerPage);
const getId = typeof this.props.idProperty !== "function" ? (data: TData) => ((data as { [key: string]: any })[this.props.idProperty as any as string] as string | number) : this.props.idProperty;
const toggleFilter = isMaterialTableComponentPropsWithRowsAndRequestData(this.props) ? this.props.onToggleFilter : () => { !this.props.disableFilter && this.setState({ showFilter: !showFilter }, this.update) }
+
+ const hideColumns = isMaterialTableComponentPropsWithRowsAndRequestData(this.props) ? this.props.onHideColumns : (data: string[]) => { const newArray = [...new Set([...this.state.hiddenColumns, ...data])]; this.setState({hiddenColumns:newArray}); }
+ const showColumns = isMaterialTableComponentPropsWithRowsAndRequestData(this.props) ? this.props.onShowColumns : (data: string[]) => { const newArray = this.state.hiddenColumns.filter(el=> !data.includes(el)); this.setState({hiddenColumns:newArray}); }
+
+ const allColumnsHidden = this.props.columns.length === this.state.hiddenColumns.length;
return (
<Paper className={this.props.className ? `${classes.root} ${this.props.className}` : classes.root}>
<TableContainer className={classes.container}>
<TableToolbar tableId={this.props.tableId} numSelected={selected && selected.length} title={this.props.title} customActionButtons={this.props.customActionButtons} onExportToCsv={this.exportToCsv}
- onToggleFilter={toggleFilter} />
- <Table aria-label={this.props.tableId ? this.props.tableId : 'tableTitle'} stickyHeader={this.props.stickyHeader || false} >
+ onToggleFilter={toggleFilter}
+ columns={columns}
+ onHideColumns={hideColumns}
+ onShowColumns={showColumns} />
+ <Table padding="normal" aria-label={this.props.tableId ? this.props.tableId : 'tableTitle'} stickyHeader={this.props.stickyHeader || false} >
<EnhancedTableHead
+ allowHtmlHeader={allowHtmlHeader || false}
columns={columns}
numSelected={selected && selected.length}
order={order}
onRequestSort={this.onHandleRequestSort}
rowCount={rows.length}
enableSelection={this.props.enableSelection}
+ hiddenColumns={this.state.hiddenColumns}
/>
<TableBody>
- {showFilter && <EnhancedTableFilter columns={columns} filter={filter} onFilterChanged={this.onFilterChanged} enableSelection={this.props.enableSelection} /> || null}
- {rows // may need ordering here
+ {showFilter && <EnhancedTableFilter columns={columns} hiddenColumns={this.state.hiddenColumns} filter={filter} onFilterChanged={this.onFilterChanged} enableSelection={this.props.enableSelection} /> || null}
+
+ {allColumnsHidden ? <Typography variant="body1" textAlign="center">All columns of this table are hidden.</Typography> :
+
+ rows // may need ordering here
.map((entry: TData & { [RowDisabled]?: boolean, [kex: string]: any }, index) => {
const entryId = getId(entry);
const contextMenu = (this.props.createContextMenu && this.state.contextMenuInfo.index === index && this.props.createContextMenu(entry)) || null;
>
{this.props.enableSelection
? <TableCell padding="checkbox" style={{ width: "50px", color: entry[RowDisabled] || false ? "inherit" : undefined } }>
- <Checkbox checked={isSelected} />
+ <Checkbox color='secondary' checked={isSelected} />
</TableCell>
: null
}
{
+
this.props.columns.map(
col => {
const style = col.width ? { width: col.width } : {};
- return (
- <TableCell style={ entry[RowDisabled] || false ? { ...style, color: "inherit" } : style } aria-label={col.title? col.title.toLowerCase().replace(/\s/g, "-") : col.property.toLowerCase().replace(/\s/g, "-")} key={col.property} align={col.type === ColumnType.numeric && !col.align ? "right" : col.align} >
+ const tableCell = (
+
+ <TableCell style={ entry[RowDisabled] || false ? { ...style, color: "inherit" } : style } aria-label={col.title? toAriaLabel(col.title) : toAriaLabel(col.property)} key={col.property} align={col.type === ColumnType.numeric && !col.align ? "right" : col.align} >
{col.type === ColumnType.custom && col.customControl
? <col.customControl className={col.className} style={col.style} rowData={entry} />
: col.type === ColumnType.boolean
}
</TableCell>
);
+
+ //show column if...
+ const showColumn = !this.state.hiddenColumns.includes(col.property);
+ return showColumn && tableCell
}
)
}
count={rowCount}
rowsPerPage={rowsPerPage}
page={page}
- aria-label="table-pagination-footer"
+ aria-label={this.props.isPopup ? "popup-table-pagination-footer" : "table-pagination-footer" }
backIconButtonProps={{
- 'aria-label': 'previous-page',
+ 'aria-label': this.props.isPopup ? 'popup-previous-page' : 'previous-page',
}}
nextIconButtonProps={{
- 'aria-label': 'next-page',
+ 'aria-label': this.props.isPopup ? 'popup-next-page': 'next-page',
}}
- onChangePage={this.onHandleChangePage}
- onChangeRowsPerPage={this.onHandleChangeRowsPerPage}
+ onPageChange={this.onHandleChangePage}
+ onRowsPerPageChange={this.onHandleChangeRowsPerPage}
/>
</Paper>
);
}
static getDerivedStateFromProps(props: MaterialTableComponentProps, state: MaterialTableComponentState & { _rawRows: {}[] }): MaterialTableComponentState & { _rawRows: {}[] } {
+
if (isMaterialTableComponentPropsWithRowsAndRequestData(props)) {
return {
...state,
loading: props.loading,
showFilter: props.showFilter,
page: props.page,
+ hiddenColumns: props.hiddenColumns,
rowsPerPage: props.rowsPerPage
}
} else if (isMaterialTableComponentPropsWithRows(props) && props.asynchronus && state._rawRows !== props.rows) {
private static updateRows(props: MaterialTableComponentPropsWithRows, state: MaterialTableComponentState): { rows: {}[], total: number, page: number } {
- let data = [...props.rows as dataType[] || []];
+ let data = [...(props.rows as dataType[] || [])];
const columns = props.columns;
const { page, rowsPerPage, order, orderBy, filter } = state;
if (filterExpressionAsString.length === 0 || isNaN(valueAsNumber)) return true;
if (filterExpressionAsString.startsWith('>=')) {
- return valueAsNumber >= Number(filterExpressionAsString.substr(2).trim());
+ return valueAsNumber >= Number(filterExpressionAsString.substring(2).trim());
} else if (filterExpressionAsString.startsWith('<=')) {
- return valueAsNumber <= Number(filterExpressionAsString.substr(2).trim());
+ return valueAsNumber <= Number(filterExpressionAsString.substring(2).trim());
} else if (filterExpressionAsString.startsWith('>')) {
- return valueAsNumber > Number(filterExpressionAsString.substr(1).trim());
+ return valueAsNumber > Number(filterExpressionAsString.substring(1).trim());
} else if (filterExpressionAsString.startsWith('<')) {
- return valueAsNumber < Number(filterExpressionAsString.substr(1).trim());
+ return valueAsNumber < Number(filterExpressionAsString.substring(1).trim());
}
} else if (column.type === ColumnType.date){
const valueAsString = String(dataValue);
const filterExpressionAsString = String(filterExpression).trim();
if (filterExpressionAsString.startsWith('>=')) {
- return valueAsDate >= convertToDate(filterExpressionAsString.substr(2).trim());
+ return valueAsDate >= convertToDate(filterExpressionAsString.substring(2).trim());
} else if (filterExpressionAsString.startsWith('<=')) {
- return valueAsDate <= convertToDate(filterExpressionAsString.substr(2).trim());
+ return valueAsDate <= convertToDate(filterExpressionAsString.substring(2).trim());
} else if (filterExpressionAsString.startsWith('>')) {
- return valueAsDate > convertToDate(filterExpressionAsString.substr(1).trim());
+ return valueAsDate > convertToDate(filterExpressionAsString.substring(1).trim());
} else if (filterExpressionAsString.startsWith('<')) {
- return valueAsDate < convertToDate(filterExpressionAsString.substr(1).trim());
+ return valueAsDate < convertToDate(filterExpressionAsString.substring(1).trim());
}
}
}
-export type MaterialTableCtorType<TData extends {} = {}> = new () => React.Component<Omit<MaterialTableComponentProps<TData>, 'classes'>>;
+export type MaterialTableCtorType<TData extends {} = {}> = new () => React.Component<DistributiveOmit<MaterialTableComponentProps<TData>, 'classes'>>;
export const MaterialTable = withStyles(styles)(MaterialTableComponent);
export default MaterialTable;
\ No newline at end of file