summaryrefslogtreecommitdiffstats
path: root/sdnr/wt/odlux/framework/src/components/material-table
diff options
context:
space:
mode:
Diffstat (limited to 'sdnr/wt/odlux/framework/src/components/material-table')
-rw-r--r--sdnr/wt/odlux/framework/src/components/material-table/index.tsx231
-rw-r--r--sdnr/wt/odlux/framework/src/components/material-table/tableFilter.tsx30
-rw-r--r--sdnr/wt/odlux/framework/src/components/material-table/tableToolbar.tsx61
-rw-r--r--sdnr/wt/odlux/framework/src/components/material-table/utilities.ts40
4 files changed, 224 insertions, 138 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);
diff --git a/sdnr/wt/odlux/framework/src/components/material-table/tableFilter.tsx b/sdnr/wt/odlux/framework/src/components/material-table/tableFilter.tsx
index 0356aa225..737ea85f9 100644
--- a/sdnr/wt/odlux/framework/src/components/material-table/tableFilter.tsx
+++ b/sdnr/wt/odlux/framework/src/components/material-table/tableFilter.tsx
@@ -33,7 +33,7 @@ const styles = (theme: Theme) => createStyles({
flexWrap: 'wrap',
},
input: {
- margin: theme.spacing.unit,
+ margin: theme.spacing(1),
},
});
@@ -45,7 +45,7 @@ interface IEnhancedTableFilterComponentProps extends WithStyles<typeof styles> {
}
class EnhancedTableFilterComponent extends React.Component<IEnhancedTableFilterComponentProps> {
- createFilterHandler = (property: string) => (event: React.ChangeEvent<HTMLInputElement|HTMLSelectElement|HTMLTextAreaElement>) => {
+ createFilterHandler = (property: string) => (event: React.ChangeEvent<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>) => {
this.props.onFilterChanged && this.props.onFilterChanged(property, event.target.value);
};
@@ -53,33 +53,33 @@ class EnhancedTableFilterComponent extends React.Component<IEnhancedTableFilterC
const { columns, filter, classes } = this.props;
return (
<TableRow>
- { this.props.enableSelection
- ? <TableCell padding="checkbox" style={ { width: "50px" } }>
- </TableCell>
- : null
- }
- { columns.map(col => {
+ {this.props.enableSelection
+ ? <TableCell padding="checkbox" style={{ width: "50px" }}>
+ </TableCell>
+ : null
+ }
+ {columns.map(col => {
const style = col.width ? { width: col.width } : {};
return (
<TableCell
- key={ col.property }
- padding={ col.disablePadding ? 'none' : 'default' }
- style={ style }
+ key={col.property}
+ padding={col.disablePadding ? 'none' : 'default'}
+ style={style}
>
- { col.disableFilter || (col.type === ColumnType.custom)
+ {col.disableFilter || (col.type === ColumnType.custom)
? null
: (col.type === ColumnType.boolean)
? <Select className={classes.input} value={filter[col.property] !== undefined ? filter[col.property] : ''} onChange={this.createFilterHandler(col.property)} inputProps={{ name: `${col.property}-bool`, id: `${col.property}-bool` }} >
<MenuItem value={undefined}>
<em>None</em>
</MenuItem>
- <MenuItem value={true as any as string}>{ col.labels ? col.labels["true"]:"true"}</MenuItem>
- <MenuItem value={false as any as string}>{ col.labels ? col.labels["false"] : "false"}</MenuItem>
+ <MenuItem value={true as any as string}>{col.labels ? col.labels["true"] : "true"}</MenuItem>
+ <MenuItem value={false as any as string}>{col.labels ? col.labels["false"] : "false"}</MenuItem>
</Select>
: <Input className={classes.input} inputProps={{ 'aria-label': 'Filter' }} value={filter[col.property] || ''} onChange={this.createFilterHandler(col.property)} />}
</TableCell>
);
- }, this) }
+ }, this)}
</TableRow>
);
}
diff --git a/sdnr/wt/odlux/framework/src/components/material-table/tableToolbar.tsx b/sdnr/wt/odlux/framework/src/components/material-table/tableToolbar.tsx
index 80d38ab52..a4080b51b 100644
--- a/sdnr/wt/odlux/framework/src/components/material-table/tableToolbar.tsx
+++ b/sdnr/wt/odlux/framework/src/components/material-table/tableToolbar.tsx
@@ -32,7 +32,7 @@ import { SvgIconProps } from '@material-ui/core/SvgIcon/SvgIcon';
const styles = (theme: Theme) => createStyles({
root: {
- paddingRight: theme.spacing.unit,
+ paddingRight: theme.spacing(1),
},
highlight:
theme.palette.type === 'light'
@@ -65,6 +65,7 @@ const styles = (theme: Theme) => createStyles({
interface ITableToolbarComponentProps extends WithStyles<typeof styles> {
numSelected: number | null;
title?: string;
+ tableId?: string;
customActionButtons?: { icon: React.ComponentType<SvgIconProps>, tooltip?: string, onClick: () => void }[];
onToggleFilter: () => void;
onExportToCsv: () => void;
@@ -79,7 +80,7 @@ class TableToolbarComponent extends React.Component<ITableToolbarComponentProps,
};
}
- private handleMenu = (event: React.MouseEvent<HTMLElement>) => {
+ private handleMenu = (event: React.MouseEvent<HTMLElement>) => {
this.setState({ anchorEl: event.currentTarget });
};
@@ -89,55 +90,55 @@ class TableToolbarComponent extends React.Component<ITableToolbarComponentProps,
render() {
const { numSelected, classes } = this.props;
const open = !!this.state.anchorEl;
-
+ const buttonPrefix = this.props.tableId !== undefined ? this.props.tableId + '-' : '';
return (
- <Toolbar className={ `${ classes.root } ${ numSelected && numSelected > 0 ? classes.highlight : '' } ` } >
- <div className={ classes.title }>
- { numSelected && numSelected > 0 ? (
- <Typography color="inherit" variant="subheading">
- { numSelected } selected
+ <Toolbar className={`${classes.root} ${numSelected && numSelected > 0 ? classes.highlight : ''} `} >
+ <div className={classes.title}>
+ {numSelected && numSelected > 0 ? (
+ <Typography color="inherit" variant="subtitle1">
+ {numSelected} selected
</Typography>
) : (
- <Typography variant="headline" id="tableTitle">
- { this.props.title || null }
+ <Typography variant="h5" id="tableTitle">
+ {this.props.title || null}
</Typography>
- ) }
+ )}
</div>
- <div className={ classes.spacer } />
- <div className={ classes.actions }>
- { this.props.customActionButtons
- ? this.props.customActionButtons.map((action, ind) =>(
- <Tooltip key={ `custom-action-${ ind }`} title={action.tooltip}>
- <IconButton aria-label={ `custom-action-${ind}` } onClick={() => action.onClick() }>
- <action.icon />
- </IconButton>
- </Tooltip>
+ <div className={classes.spacer} />
+ <div className={classes.actions}>
+ {this.props.customActionButtons
+ ? this.props.customActionButtons.map((action, ind) => (
+ <Tooltip key={`custom-action-${ind}`} title={action.tooltip}>
+ <IconButton aria-label={buttonPrefix + `custom-action-${ind}`} onClick={() => action.onClick()}>
+ <action.icon />
+ </IconButton>
+ </Tooltip>
))
- : null }
- { numSelected && numSelected > 0 ? (
+ : null}
+ {numSelected && numSelected > 0 ? (
<Tooltip title="Delete">
- <IconButton aria-label="Delete">
+ <IconButton aria-label={buttonPrefix + "delete"}>
<DeleteIcon />
</IconButton>
</Tooltip>
) : (
<Tooltip title="Filter list">
- <IconButton aria-label="Filter list" onClick={ () => { this.props.onToggleFilter && this.props.onToggleFilter() } }>
+ <IconButton aria-label={buttonPrefix + "filter-list"} onClick={() => { this.props.onToggleFilter && this.props.onToggleFilter() }}>
<FilterListIcon />
</IconButton>
</Tooltip>
- ) }
+ )}
<Tooltip title="Actions">
<IconButton color="inherit"
- aria-owns={ open ? 'menu-appbar' : undefined }
+ aria-owns={open ? 'menu-appbar' : undefined}
aria-haspopup="true"
- onClick={ this.handleMenu } >
+ onClick={this.handleMenu} >
<MoreIcon />
</IconButton>
</Tooltip>
- <Menu id="menu-appbar" anchorEl={ this.state.anchorEl } anchorOrigin={ { vertical: 'top', horizontal: 'right' } }
- transformOrigin={ { vertical: 'top', horizontal: 'right' } } open={ open } onClose={ this.handleClose } >
- <MenuItem onClick={ this.props.onExportToCsv }>Export as CSV</MenuItem>
+ <Menu id="menu-appbar" anchorEl={this.state.anchorEl} anchorOrigin={{ vertical: 'top', horizontal: 'right' }}
+ transformOrigin={{ vertical: 'top', horizontal: 'right' }} open={open} onClose={this.handleClose} >
+ <MenuItem onClick={this.props.onExportToCsv}>Export as CSV</MenuItem>
</Menu>
</div>
</Toolbar>
diff --git a/sdnr/wt/odlux/framework/src/components/material-table/utilities.ts b/sdnr/wt/odlux/framework/src/components/material-table/utilities.ts
index 43c3b5e35..6e8902c07 100644
--- a/sdnr/wt/odlux/framework/src/components/material-table/utilities.ts
+++ b/sdnr/wt/odlux/framework/src/components/material-table/utilities.ts
@@ -27,7 +27,7 @@ export interface IExternalTableState<TData> {
orderBy: string | null;
selected: any[] | null;
rows: TData[];
- rowCount: number;
+ total: number;
page: number;
rowsPerPage: number;
loading: boolean;
@@ -68,13 +68,13 @@ export function createExternal<TData>(callback: DataCallback<TData>, selectState
}
class SetPreFilterChangedAction extends TableAction {
- constructor(public preFilter: {[key: string]: string}) {
+ constructor(public preFilter: { [key: string]: string }) {
super();
}
}
class SetFilterChangedAction extends TableAction {
- constructor (public filter: { [key: string]: string }) {
+ constructor(public filter: { [key: string]: string }) {
super();
}
}
@@ -92,7 +92,7 @@ export function createExternal<TData>(callback: DataCallback<TData>, selectState
}
class SetResultAction extends TableAction {
- constructor(public result: { page: number, rowCount: number, rows: TData[] }) {
+ constructor(public result: { page: number, total: number, rows: TData[] }) {
super();
}
}
@@ -105,7 +105,7 @@ export function createExternal<TData>(callback: DataCallback<TData>, selectState
orderBy: null,
selected: null,
rows: [],
- rowCount: 0,
+ total: 0,
page: 0,
rowsPerPage: 10,
loading: false,
@@ -126,14 +126,14 @@ export function createExternal<TData>(callback: DataCallback<TData>, selectState
...state,
loading: false,
rows: action.result.rows,
- rowCount: action.result.rowCount,
+ total: action.result.total,
page: action.result.page,
}
} else if (action instanceof RequestSortAction) {
state = {
...state,
loading: true,
- orderBy : state.orderBy === action.orderBy && state.order === 'desc' ? null : action.orderBy ,
+ orderBy: state.orderBy === action.orderBy && state.order === 'desc' ? null : action.orderBy,
order: state.orderBy === action.orderBy && state.order === 'asc' ? 'desc' : 'asc',
}
} else if (action instanceof SetShowFilterAction) {
@@ -176,9 +176,23 @@ export function createExternal<TData>(callback: DataCallback<TData>, selectState
const reloadAction = (dispatch: Dispatch, getAppState: () => IApplicationStoreState) => {
dispatch(new RefreshAction());
const ownState = selectState(getAppState());
- const filter = { ...ownState.preFilter, ...(ownState.showFilter && ownState.filter || {})};
- Promise.resolve(callback(ownState.page, ownState.rowsPerPage, ownState.orderBy, ownState.order, filter )).then(result => {
- dispatch(new SetResultAction(result));
+ const filter = { ...ownState.preFilter, ...(ownState.showFilter && ownState.filter || {}) };
+ Promise.resolve(callback(ownState.page, ownState.rowsPerPage, ownState.orderBy, ownState.order, filter)).then(result => {
+
+ if (ownState.page > 0 && ownState.rowsPerPage * ownState.page > result.total) { //if result is smaller than the currently shown page, new search and repaginate
+
+ let newPage = Math.floor(result.total / ownState.rowsPerPage);
+
+ Promise.resolve(callback(newPage, ownState.rowsPerPage, ownState.orderBy, ownState.order, filter)).then(result1 => {
+ dispatch(new SetResultAction(result1));
+ });
+
+
+ } else {
+ dispatch(new SetResultAction(result));
+ }
+
+
}).catch(error => new AddErrorInfoAction(error));
};
@@ -186,8 +200,8 @@ export function createExternal<TData>(callback: DataCallback<TData>, selectState
return {
onPreFilterChanged: (preFilter: { [key: string]: string }) => {
dispatch(new SetPreFilterChangedAction(preFilter));
- (!skipRefresh) && dispatch(reloadAction);
- }
+ (!skipRefresh) && dispatch(reloadAction);
+ }
};
}
@@ -236,7 +250,7 @@ export function createExternal<TData>(callback: DataCallback<TData>, selectState
const createProperties = (state: IApplicationStoreState) => {
return {
...selectState(state)
- }
+ }
}
return {