aboutsummaryrefslogtreecommitdiffstats
path: root/sdnr/wt/odlux/framework/src/components/material-table/index.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'sdnr/wt/odlux/framework/src/components/material-table/index.tsx')
-rw-r--r--sdnr/wt/odlux/framework/src/components/material-table/index.tsx231
1 files changed, 151 insertions, 80 deletions
diff --git a/sdnr/wt/odlux/framework/src/components/material-table/index.tsx b/sdnr/wt/odlux/framework/src/components/material-table/index.tsx
index d89ced23a..3e31c5e03 100644
--- a/sdnr/wt/odlux/framework/src/components/material-table/index.tsx
+++ b/sdnr/wt/odlux/framework/src/components/material-table/index.tsx
@@ -33,19 +33,21 @@ import { EnhancedTableFilter } from './tableFilter';
import { ColumnModel, ColumnType } from './columnModel';
import { Omit } from '@material-ui/core';
import { SvgIconProps } from '@material-ui/core/SvgIcon/SvgIcon';
+import { replaceHyphen } from '../../utilities/yangHelper';
+import { string } from 'prop-types';
export { ColumnModel, ColumnType } from './columnModel';
-type propType = string | number | null | undefined | (string|number)[];
+type propType = string | number | null | undefined | (string | number)[];
type dataType = { [prop: string]: propType };
-type resultType<TData = dataType> = { page: number, rowCount: number, rows: TData[] };
+type resultType<TData = dataType> = { page: number, total: number, rows: TData[] };
-export type DataCallback<TData = dataType> = (page?: number, rowsPerPage?: number, orderBy?: string | null, order?: 'asc' | 'desc' | null, filter?: { [property: string]: string }) =>resultType<TData> | Promise<resultType<TData>>;
+export type DataCallback<TData = dataType> = (page?: number, rowsPerPage?: number, orderBy?: string | null, order?: 'asc' | 'desc' | null, filter?: { [property: string]: string }) => resultType<TData> | Promise<resultType<TData>>;
function desc(a: dataType, b: dataType, orderBy: string) {
- if ((b[orderBy] || "") < (a[orderBy] || "") ) {
+ if ((b[orderBy] || "") < (a[orderBy] || "")) {
return -1;
}
- if ((b[orderBy] || "") > (a[orderBy] || "") ) {
+ if ((b[orderBy] || "") > (a[orderBy] || "")) {
return 1;
}
return 0;
@@ -68,7 +70,7 @@ function getSorting(order: 'asc' | 'desc' | null, orderBy: string) {
const styles = (theme: Theme) => createStyles({
root: {
width: '100%',
- marginTop: theme.spacing.unit * 3,
+ marginTop: theme.spacing(3),
},
table: {
minWidth: 1020,
@@ -83,7 +85,7 @@ export type MaterialTableComponentState<TData = {}> = {
orderBy: string | null;
selected: any[] | null;
rows: TData[];
- rowCount: number;
+ total: number;
page: number;
rowsPerPage: number;
loading: boolean;
@@ -95,18 +97,19 @@ export type TableApi = { forceRefresh?: () => Promise<void> };
type MaterialTableComponentBaseProps<TData> = WithStyles<typeof styles> & {
columns: ColumnModel<TData>[];
- idProperty: keyof TData | ((data: TData) => React.Key );
+ idProperty: keyof TData | ((data: TData) => React.Key);
+ tableId?: string;
title?: string;
enableSelection?: boolean;
disableSorting?: boolean;
disableFilter?: boolean;
- customActionButtons?: { icon: React.ComponentType<SvgIconProps>, tooltip?: string, onClick: () => void }[];
+ customActionButtons?: { icon: React.ComponentType<SvgIconProps>, tooltip?: string, onClick: () => void }[];
onHandleClick?(event: React.MouseEvent<HTMLTableRowElement>, rowData: TData): void;
};
-type MaterialTableComponentPropsWithRows<TData={}> = MaterialTableComponentBaseProps<TData> & { rows: TData[]; asynchronus?: boolean; };
-type MaterialTableComponentPropsWithRequestData<TData={}> = MaterialTableComponentBaseProps<TData> & { onRequestData: DataCallback; tableApi?: TableApi; };
-type MaterialTableComponentPropsWithExternalState<TData={}> = MaterialTableComponentBaseProps<TData> & MaterialTableComponentState & {
+type MaterialTableComponentPropsWithRows<TData = {}> = MaterialTableComponentBaseProps<TData> & { rows: TData[]; asynchronus?: boolean; };
+type MaterialTableComponentPropsWithRequestData<TData = {}> = MaterialTableComponentBaseProps<TData> & { onRequestData: DataCallback; tableApi?: TableApi; };
+type MaterialTableComponentPropsWithExternalState<TData = {}> = MaterialTableComponentBaseProps<TData> & MaterialTableComponentState & {
onToggleFilter: () => void;
onFilterChanged: (property: string, filterTerm: string) => void;
onHandleChangePage: (page: number) => void;
@@ -152,7 +155,7 @@ class MaterialTableComponent<TData extends {} = {}> extends React.Component<Mate
orderBy: isMaterialTableComponentPropsWithRowsAndRequestData(this.props) ? this.props.orderBy : null,
selected: isMaterialTableComponentPropsWithRowsAndRequestData(this.props) ? this.props.selected : null,
rows: isMaterialTableComponentPropsWithRows(this.props) && this.props.rows.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage) || [],
- rowCount: isMaterialTableComponentPropsWithRows(this.props) && this.props.rows.length || 0,
+ total: isMaterialTableComponentPropsWithRows(this.props) && this.props.rows.length || 0,
page,
rowsPerPage,
};
@@ -167,58 +170,58 @@ class MaterialTableComponent<TData extends {} = {}> extends React.Component<Mate
}
render(): JSX.Element {
const { classes, columns } = this.props;
- const { rows, rowCount, order, orderBy, selected, rowsPerPage, page, showFilter, filter } = this.state;
+ 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 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) }
return (
- <Paper className={ classes.root }>
- <TableToolbar numSelected={ selected && selected.length } title={ this.props.title } customActionButtons={ this.props.customActionButtons } onExportToCsv={ this.exportToCsv }
- onToggleFilter={ toggleFilter } />
- <div className={ classes.tableWrapper }>
- <Table className={ classes.table } aria-labelledby="tableTitle">
+ <Paper className={classes.root}>
+ <TableToolbar tableId={this.props.tableId} numSelected={selected && selected.length} title={this.props.title} customActionButtons={this.props.customActionButtons} onExportToCsv={this.exportToCsv}
+ onToggleFilter={toggleFilter} />
+ <div className={classes.tableWrapper}>
+ <Table className={classes.table} aria-labelledby="tableTitle">
<EnhancedTableHead
- columns={ columns }
- numSelected={ selected && selected.length }
- order={ order }
- orderBy={ orderBy }
- onSelectAllClick={ this.handleSelectAllClick }
- onRequestSort={ this.onHandleRequestSort }
- rowCount={ rows.length }
- enableSelection={ this.props.enableSelection }
+ columns={columns}
+ numSelected={selected && selected.length}
+ order={order}
+ orderBy={orderBy}
+ onSelectAllClick={this.handleSelectAllClick}
+ onRequestSort={this.onHandleRequestSort}
+ rowCount={rows.length}
+ enableSelection={this.props.enableSelection}
/>
<TableBody>
- { showFilter && <EnhancedTableFilter columns={ columns } filter={ filter } onFilterChanged={ this.onFilterChanged } enableSelection={this.props.enableSelection} /> || null }
- { rows // may need ordering here
+ {showFilter && <EnhancedTableFilter columns={columns} filter={filter} onFilterChanged={this.onFilterChanged} enableSelection={this.props.enableSelection} /> || null}
+ {rows // may need ordering here
.map((entry: TData & { [key: string]: any }) => {
const entryId = getId(entry);
const isSelected = this.isSelected(entryId);
return (
<TableRow
hover
- onClick={ event => this.handleClick(event, entry, entryId) }
+ onClick={event => this.handleClick(event, entry, entryId)}
role="checkbox"
- aria-checked={ isSelected }
- tabIndex={ -1 }
- key={ entryId }
- selected={ isSelected }
+ aria-checked={isSelected}
+ tabIndex={-1}
+ key={entryId}
+ selected={isSelected}
>
- { this.props.enableSelection
- ? <TableCell padding="checkbox" style={ { width: "50px" } }>
- <Checkbox checked={ isSelected } />
+ {this.props.enableSelection
+ ? <TableCell padding="checkbox" style={{ width: "50px" }}>
+ <Checkbox checked={isSelected} />
</TableCell>
- : null
+ : null
}
{
this.props.columns.map(
col => {
- const style = col.width ? { width: col.width } : { };
+ const style = col.width ? { width: col.width } : {};
return (
- <TableCell key={ col.property } align={ col.type === ColumnType.numeric && !col.align ? "right": col.align } style={ style }>
- { col.type === ColumnType.custom && col.customControl
- ? <col.customControl className={col.className} style={col.style} rowData={ entry } />
+ <TableCell key={col.property} align={col.type === ColumnType.numeric && !col.align ? "right" : col.align} style={style}>
+ {col.type === ColumnType.custom && col.customControl
+ ? <col.customControl className={col.className} style={col.style} rowData={entry} />
: col.type === ColumnType.boolean
- ? <span className={col.className} style={col.style}>{col.labels ? col.labels[entry[col.property] ? "true": "false"] : String(entry[col.property]) }</span>
+ ? <span className={col.className} style={col.style}>{col.labels ? col.labels[entry[col.property] ? "true" : "false"] : String(entry[col.property])}</span>
: <span className={col.className} style={col.style}>{String(entry[col.property])}</span>
}
</TableCell>
@@ -228,29 +231,29 @@ class MaterialTableComponent<TData extends {} = {}> extends React.Component<Mate
}
</TableRow>
);
- }) }
- { emptyRows > 0 && (
- <TableRow style={ { height: 49 * emptyRows } }>
- <TableCell colSpan={ this.props.columns.length } />
+ })}
+ {emptyRows > 0 && (
+ <TableRow style={{ height: 49 * emptyRows }}>
+ <TableCell colSpan={this.props.columns.length} />
</TableRow>
- ) }
+ )}
</TableBody>
</Table>
</div>
<TablePagination
- rowsPerPageOptions={[5, 10, 20, 50] }
+ rowsPerPageOptions={[5, 10, 20, 50]}
component="div"
- count={ rowCount }
- rowsPerPage={ rowsPerPage }
- page={ page }
- backIconButtonProps={ {
+ count={rowCount}
+ rowsPerPage={rowsPerPage}
+ page={page}
+ backIconButtonProps={{
'aria-label': 'Previous Page',
- } }
- nextIconButtonProps={ {
+ }}
+ nextIconButtonProps={{
'aria-label': 'Next Page',
- } }
- onChangePage={ this.onHandleChangePage }
- onChangeRowsPerPage={ this.onHandleChangeRowsPerPage }
+ }}
+ onChangePage={this.onHandleChangePage}
+ onChangeRowsPerPage={this.onHandleChangeRowsPerPage}
/>
</Paper>
);
@@ -261,7 +264,7 @@ class MaterialTableComponent<TData extends {} = {}> extends React.Component<Mate
return {
...state,
rows: props.rows,
- rowCount: props.rowCount,
+ total: props.total,
orderBy: props.orderBy,
order: props.order,
filter: props.filter,
@@ -281,9 +284,11 @@ class MaterialTableComponent<TData extends {} = {}> extends React.Component<Mate
return state;
}
- private static updateRows(props: MaterialTableComponentPropsWithRows, state: MaterialTableComponentState): { rows: {}[], rowCount: number } {
+ private static updateRows(props: MaterialTableComponentPropsWithRows, state: MaterialTableComponentState): { rows: {}[], total: number, page: number } {
+
+ const { page, rowsPerPage, order, orderBy, filter } = state;
+
try {
- const { page, rowsPerPage, order, orderBy, filter } = state;
let data: dataType[] = props.rows || [];
let filtered = false;
if (state.showFilter) {
@@ -292,25 +297,84 @@ class MaterialTableComponent<TData extends {} = {}> extends React.Component<Mate
filtered = filtered || exp !== undefined;
data = exp !== undefined ? data.filter((val) => {
const value = val[prop];
- return (value == exp) || (value && value.toString().indexOf(String(exp)) > -1);
+
+ if (value) {
+
+ if (typeof exp === 'boolean') {
+ return value == exp;
+
+ } else if (typeof exp === 'string') {
+
+ const valueAsString = value.toString();
+ if (exp.length === 0) return value;
+
+ const regex = new RegExp("\\*", "g");
+ const regex2 = new RegExp("\\?", "g");
+
+ const countStar = (exp.match(regex) || []).length;
+ const countQuestionmarks = (exp.match(regex2) || []).length;
+
+ if (countStar > 0 || countQuestionmarks > 0) {
+ let editableExpression = exp;
+
+ if (!exp.startsWith('*')) {
+ editableExpression = '^' + exp;
+ }
+
+ if (!exp.endsWith('*')) {
+ editableExpression = editableExpression + '$';
+ }
+
+ const expressionAsRegex = editableExpression.replace(/\*/g, ".*").replace(/\?/g, ".");
+
+ return valueAsString.match(new RegExp(expressionAsRegex, "g"));
+ }
+ else if (exp.includes('>=')) {
+ return Number(valueAsString) >= Number(exp.replace('>=', ''));
+ } else if (exp.includes('<=')) {
+ return Number(valueAsString) <= Number(exp.replace('<=', ''));
+ } else
+ if (exp.includes('>')) {
+ return Number(valueAsString) > Number(exp.replace('>', ''));
+ } else if (exp.includes('<')) {
+ return Number(valueAsString) < Number(exp.replace('<', ''));
+ }
+ }
+ }
+
+ return (value == exp)
}) : data;
});
}
const rowCount = data.length;
- data = (orderBy && order
- ? stableSort(data, getSorting(order, orderBy))
- : data).slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage);
+ if (page > 0 && rowsPerPage * page > rowCount) { //if result is smaller than the currently shown page, new search and repaginate
+ let newPage = Math.floor(rowCount / rowsPerPage);
+ return {
+ rows: data,
+ total: rowCount,
+ page: newPage
+ };
+ } else {
+ data = (orderBy && order
+ ? stableSort(data, getSorting(order, orderBy))
+ : data).slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage);
+
+ return {
+ rows: data,
+ total: rowCount,
+ page: page
+ };
+ }
- return {
- rows: data,
- rowCount
- };
- } catch{
+
+ } catch (e) {
+ console.error(e);
return {
rows: [],
- rowCount: 0
+ total: 0,
+ page: page
}
}
}
@@ -323,7 +387,8 @@ class MaterialTableComponent<TData extends {} = {}> extends React.Component<Mate
);
this.setState(response);
} else {
- this.setState(MaterialTableComponent.updateRows(this.props, this.state));
+ let updateResult = MaterialTableComponent.updateRows(this.props, this.state);
+ this.setState(updateResult);
}
}
@@ -361,7 +426,7 @@ class MaterialTableComponent<TData extends {} = {}> extends React.Component<Mate
handleSelectAllClick: () => {};
- private onHandleChangePage = (event: React.MouseEvent<HTMLButtonElement> | null, page: number) => {
+ private onHandleChangePage = (event: any | null, page: number) => {
if (isMaterialTableComponentPropsWithRowsAndRequestData(this.props)) {
this.props.onHandleChangePage(page);
return;
@@ -390,12 +455,12 @@ class MaterialTableComponent<TData extends {} = {}> extends React.Component<Mate
return (selectedIndex > -1);
}
- private handleClick(event: React.MouseEvent<HTMLTableRowElement>, rowData: TData, id: string | number): void {
+ private handleClick(event: any, rowData: TData, id: string | number): void {
if (this.props.onHandleClick instanceof Function) {
this.props.onHandleClick(event, rowData);
return;
}
- if (!this.props.enableSelection){
+ if (!this.props.enableSelection) {
return;
}
let selected = this.state.selected || [];
@@ -416,20 +481,26 @@ class MaterialTableComponent<TData extends {} = {}> extends React.Component<Mate
});
}
+
private exportToCsv = async () => {
let file;
let data: dataType[] | null = null;
let csv: string[] = [];
-
if (isMaterialTableComponentPropsWithRequestData(this.props)) {
+ // table with extra request handler
this.setState({ loading: true });
const result = await Promise.resolve(
- this.props.onRequestData( 0, 1000, this.state.orderBy, this.state.order, this.state.showFilter && this.state.filter || {})
+ this.props.onRequestData(0, 1000, this.state.orderBy, this.state.order, this.state.showFilter && this.state.filter || {})
);
data = result.rows;
this.setState({ loading: true });
- } else {
+ } else if (isMaterialTableComponentPropsWithRowsAndRequestData(this.props)) {
+ // table with generated handlers note: exports data shown on current page
+ data = this.props.rows;
+ }
+ else {
+ // table with local data
data = MaterialTableComponent.updateRows(this.props, this.state).rows;
}
@@ -438,7 +509,7 @@ class MaterialTableComponent<TData extends {} = {}> extends React.Component<Mate
this.state.rows && this.state.rows.forEach((row: any) => {
csv.push(this.props.columns.map(col => row[col.property]).join(',') + "\r\n");
});
- const properties = { type: "text/csv;charset=utf-8" }; // Specify the file's mime-type.
+ const properties = { type: "text/csv;charset=utf-8" }; // Specify the file's mime-type.
try {
// Specify the filename using the File constructor, but ...
file = new File(csv, "export.csv", properties);