diff options
Diffstat (limited to 'sdnr/wt/odlux/framework/src/components')
3 files changed, 73 insertions, 39 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 7d4633bc6..c74fd1a38 100644 --- a/sdnr/wt/odlux/framework/src/components/material-table/index.tsx +++ b/sdnr/wt/odlux/framework/src/components/material-table/index.tsx @@ -32,13 +32,14 @@ import { EnhancedTableHead } from './tableHead'; import { EnhancedTableFilter } from './tableFilter'; import { ColumnModel, ColumnType } from './columnModel'; -import { Omit, Menu } from '@material-ui/core'; +import { Omit, Menu, makeStyles } from '@material-ui/core'; import { SvgIconProps } from '@material-ui/core/SvgIcon/SvgIcon'; import { DividerTypeMap } from '@material-ui/core/Divider'; import { MenuItemProps } from '@material-ui/core/MenuItem'; import { flexbox } from '@material-ui/system'; +import { RowDisabled } from './utilities'; export { ColumnModel, ColumnType } from './columnModel'; type propType = string | number | null | undefined | (string | number)[]; @@ -103,6 +104,34 @@ const styles = (theme: Theme) => createStyles({ } }); +const useTableRowExtStyles = makeStyles((theme: Theme) => createStyles({ + disabled: { + color: "rgba(180, 180, 180, 0.7)", + }, +})); + +type GetStatelessComponentProps<T> = T extends (props: infer P & { children?: React.ReactNode }) => any ? P : any; +type TableRowExtProps = GetStatelessComponentProps<typeof TableRow> & { disabled: boolean }; +const TableRowExt : React.FC<TableRowExtProps> = (props) => { + const [disabled, setDisabled] = React.useState(true); + const classes = useTableRowExtStyles(); + + const onMouseDown = (ev: React.MouseEvent<HTMLElement>) => { + if (ev.button ===1){ + setDisabled(!disabled); + ev.preventDefault(); + ev.stopPropagation(); + } else if (props.disabled && disabled) { + ev.preventDefault(); + ev.stopPropagation(); + } + }; + + return ( + <TableRow {...{...props, color: props.disabled && disabled ? '#a0a0a0' : undefined , className: props.disabled && disabled ? classes.disabled : '', onMouseDown, onContextMenu: props.disabled && disabled ? onMouseDown : props.onContextMenu } } /> + ); +}; + export type MaterialTableComponentState<TData = {}> = { order: 'asc' | 'desc'; orderBy: string | null; @@ -130,7 +159,7 @@ type MaterialTableComponentBaseProps<TData> = WithStyles<typeof styles> & { enableSelection?: boolean; disableSorting?: boolean; disableFilter?: boolean; - customActionButtons?: { icon: React.ComponentType<SvgIconProps>, tooltip?: string, onClick: () => void }[]; + customActionButtons?: { icon: React.ComponentType<SvgIconProps>, tooltip?: string, onClick: () => void, disabled?: boolean }[]; onHandleClick?(event: React.MouseEvent<HTMLTableRowElement>, rowData: TData): void; createContextMenu?: (row: TData) => React.ReactElement<MenuItemProps | DividerTypeMap<{}, "hr">, React.ComponentType<MenuItemProps | DividerTypeMap<{}, "hr">>>[]; }; @@ -222,12 +251,12 @@ class MaterialTableComponent<TData extends {} = {}> extends React.Component<Mate <TableBody> {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 }, index) => { + .map((entry: TData & { [RowDisabled]?: boolean, [kex: string]: any }, index) => { const entryId = getId(entry); const isSelected = this.isSelected(entryId); const contextMenu = (this.props.createContextMenu && this.state.contextMenuInfo.index === index && this.props.createContextMenu(entry)) || null; return ( - <TableRow + <TableRowExt hover onClick={event => { if (this.props.createContextMenu) { @@ -252,9 +281,10 @@ class MaterialTableComponent<TData extends {} = {}> extends React.Component<Mate tabIndex={-1} key={entryId} selected={isSelected} + disabled={entry[RowDisabled] || false} > {this.props.enableSelection - ? <TableCell padding="checkbox" style={{ width: "50px" }}> + ? <TableCell padding="checkbox" style={{ width: "50px", color: entry[RowDisabled] || false ? "inherit" : undefined } }> <Checkbox checked={isSelected} /> </TableCell> : null @@ -264,7 +294,7 @@ class MaterialTableComponent<TData extends {} = {}> extends React.Component<Mate col => { const style = col.width ? { width: col.width } : {}; return ( - <TableCell 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} style={style}> + <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} > {col.type === ColumnType.custom && col.customControl ? <col.customControl className={col.className} style={col.style} rowData={entry} /> : col.type === ColumnType.boolean @@ -280,7 +310,7 @@ class MaterialTableComponent<TData extends {} = {}> extends React.Component<Mate anchorPosition={this.state.contextMenuInfo.mouseY != null && this.state.contextMenuInfo.mouseX != null ? { top: this.state.contextMenuInfo.mouseY, left: this.state.contextMenuInfo.mouseX } : undefined}> {contextMenu} </Menu> || null} - </TableRow> + </TableRowExt> ); })} {emptyRows > 0 && ( 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 3b2f8e0a8..f7de0a062 100644 --- a/sdnr/wt/odlux/framework/src/components/material-table/tableToolbar.tsx +++ b/sdnr/wt/odlux/framework/src/components/material-table/tableToolbar.tsx @@ -67,7 +67,7 @@ interface ITableToolbarComponentProps extends WithStyles<typeof styles> { numSelected: number | null; title?: string; tableId?: string; - customActionButtons?: { icon: React.ComponentType<SvgIconProps>, tooltip?: string, onClick: () => void }[]; + customActionButtons?: { icon: React.ComponentType<SvgIconProps>, tooltip?: string, onClick: () => void, disabled?: boolean }[]; onToggleFilter: () => void; onExportToCsv: () => void; } @@ -110,7 +110,7 @@ class TableToolbarComponent extends React.Component<ITableToolbarComponentProps, {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()}> + <IconButton disabled={action.disabled} aria-label={buttonPrefix + `custom-action-${ind}`} onClick={() => action.onClick()}> <action.icon /> </IconButton> </Tooltip> 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 07ffe2ff5..544e14e01 100644 --- a/sdnr/wt/odlux/framework/src/components/material-table/utilities.ts +++ b/sdnr/wt/odlux/framework/src/components/material-table/utilities.ts @@ -21,12 +21,14 @@ import { Dispatch } from '../../flux/store'; import { AddErrorInfoAction } from '../../actions/errorActions'; import { IApplicationStoreState } from '../../store/applicationStore'; +export const RowDisabled = Symbol("RowDisabled"); import { DataCallback } from "."; + export interface IExternalTableState<TData> { order: 'asc' | 'desc'; orderBy: string | null; selected: any[] | null; - rows: TData[]; + rows: (TData & { [RowDisabled]?: boolean })[]; total: number; page: number; rowsPerPage: number; @@ -36,8 +38,31 @@ export interface IExternalTableState<TData> { preFilter: { [property: string]: string }; } +export type ExternalMethodes<TData> = { + reloadAction: (dispatch: Dispatch, getAppState: () => IApplicationStoreState) => Promise<void | AddErrorInfoAction>; + createActions: (dispatch: Dispatch, skipRefresh?: boolean) => { + onRefresh: () => void; + onHandleRequestSort: (orderBy: string) => void; + onHandleExplicitRequestSort: (property: string, sortOrder: "asc" | "desc") => void; + onToggleFilter: (refresh?: boolean | undefined) => void; + onFilterChanged: (property: string, filterTerm: string) => void; + onHandleChangePage: (page: number) => void; + onHandleChangeRowsPerPage: (rowsPerPage: number | null) => void; + }; + createPreActions: (dispatch: Dispatch, skipRefresh?: boolean) => { + onPreFilterChanged: (preFilter: { + [key: string]: string; + }) => void; + }; + createProperties: (state: IApplicationStoreState) => IExternalTableState<TData>; + actionHandler: IActionHandler<IExternalTableState<TData>, Action>; +} + + /** Create an actionHandler and actions for external table states. */ -export function createExternal<TData>(callback: DataCallback<TData>, selectState: (appState: IApplicationStoreState) => IExternalTableState<TData>) { +export function createExternal<TData>(callback: DataCallback<TData>, selectState: (appState: IApplicationStoreState) => IExternalTableState<TData>) : ExternalMethodes<TData> ; +export function createExternal<TData>(callback: DataCallback<TData>, selectState: (appState: IApplicationStoreState) => IExternalTableState<TData>, disableRow: (data: TData) => boolean) : ExternalMethodes<TData>; +export function createExternal<TData>(callback: DataCallback<TData>, selectState: (appState: IApplicationStoreState) => IExternalTableState<TData>, disableRow?: (data: TData) => boolean) : ExternalMethodes<TData> { //#region Actions abstract class TableAction extends Action { } @@ -131,7 +156,9 @@ export function createExternal<TData>(callback: DataCallback<TData>, selectState state = { ...state, loading: false, - rows: action.result.rows, + rows: disableRow + ? action.result.rows.map((row: TData) => ({...row, [RowDisabled]: disableRow(row) })) + : action.result.rows, total: action.result.total, page: action.result.page, } @@ -191,7 +218,7 @@ export function createExternal<TData>(callback: DataCallback<TData>, selectState 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 => { + return 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 @@ -207,30 +234,7 @@ export function createExternal<TData>(callback: DataCallback<TData>, selectState } - }).catch(error => new AddErrorInfoAction(error)); - }; - - const reloadActionAsync = async (dispatch: Dispatch, getAppState: () => IApplicationStoreState) => { - dispatch(new RefreshAction()); - const ownState = selectState(getAppState()); - const filter = { ...ownState.preFilter, ...(ownState.showFilter && ownState.filter || {}) }; - - try { - const result = await Promise.resolve(callback(ownState.page, ownState.rowsPerPage, ownState.orderBy, ownState.order, filter)); - - - 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); - - const repaginationResult = await Promise.resolve(callback(newPage, ownState.rowsPerPage, ownState.orderBy, ownState.order, filter)); - dispatch(new SetResultAction(repaginationResult)); - } else { - dispatch(new SetResultAction(result)); - } - } catch (error) { - new AddErrorInfoAction(error); - } + }).catch(error => dispatch(new AddErrorInfoAction(error))); }; const createPreActions = (dispatch: Dispatch, skipRefresh: boolean = false) => { @@ -303,6 +307,6 @@ export function createExternal<TData>(callback: DataCallback<TData>, selectState createProperties: createProperties, createPreActions: createPreActions, actionHandler: externalTableStateActionHandler, - reloadActionAsync: reloadActionAsync, } -}
\ No newline at end of file +} + |