react-table#TableState TypeScript Examples
The following examples show how to use
react-table#TableState.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: index.tsx From ke with MIT License | 4 votes |
Table = ({
resourceName,
listFilters,
listFilterTemplates,
columns,
data,
pageCount: controlledPageCount,
setBackendPage,
user,
analytics,
filterable = false,
provider,
}: TableProps): JSX.Element => {
const {
getTableProps,
headerGroups,
prepareRow,
page,
canPreviousPage,
canNextPage,
pageOptions,
gotoPage,
nextPage,
previousPage,
pageCount,
state: { pageIndex },
} = useTable(
{
columns,
data,
manualPagination: true,
initialState: { pageIndex: 0 },
pageCount: controlledPageCount,
autoResetPage: false,
stateReducer: (newState: TableState, action: ActionType) => {
if (action.type === 'gotoPage' && setBackendPage) {
const newPageIndex = newState.pageIndex
setBackendPage(newPageIndex + 1)
}
return newState
},
},
useFilters,
usePagination
)
return (
<Flex flexDirection="row" width="100%" flex={1} bg="gray.50" p={4}>
<Flex
flexDirection="column"
flex={1}
maxWidth="100%"
bg="white"
width="auto"
rounded="md"
borderWidth="1px"
onClick={() => false}
>
{filterable && listFilters && (
<FilterBlock
listFilters={listFilters}
listFilterTemplates={listFilterTemplates}
user={user}
analytics={analytics}
resourceName={resourceName}
provider={provider}
gotoPage={gotoPage}
/>
)}
<StyledTable {...getTableProps()}>
<TableHead>{mountHeader(headerGroups)}</TableHead>
<Flex flexDirection="column">{mountRows(page, prepareRow)}</Flex>
</StyledTable>
<Bottom
analytics={analytics}
resourceName={resourceName}
pageIndex={pageIndex}
canPreviousPage={canPreviousPage}
canNextPage={canNextPage}
pageOptions={pageOptions}
pageCount={pageCount}
gotoPage={gotoPage}
nextPage={nextPage}
previousPage={previousPage}
/>
</Flex>
</Flex>
)
}
Example #2
Source File: Table.tsx From frontegg-react with MIT License | 4 votes |
Table: FC<TableProps> = <T extends object>(props: TableProps<T>) => { const classes = useStyles(); const tableRef = useRef<HTMLTableElement>(null); const firstRender = useRef<boolean>(true); const columns = useMemo(() => { const columns = props.columns.map( ({ sortable, Filter, Header, ...rest }) => ({ ...rest, disableSortBy: !sortable, disableFilters: !Filter, Filter, Header: Header ?? <div style={{ minWidth: rest.minWidth, maxWidth: rest.maxWidth }} />, } as FeTableColumnOptions<T>) ); if (props.expandable) { columns.unshift({ id: 'fe-expander', minWidth: 60, maxWidth: '60px' as any, Header: <div style={{ minWidth: '1.5rem', maxWidth: '1.5rem' }} />, Cell: (cell: Cell<T>) => { const row = cell.row as Row<T> & UseExpandedRowProps<T>; return ( <IconButton className={classes.expandIcon} {...row.getToggleRowExpandedProps()}> {row.isExpanded ? <KeyboardArrowUpIcon /> : <KeyboardArrowDownIcon />} </IconButton> ); }, }); } if (props.selection) { columns.unshift({ id: 'fe-selection', minWidth: 60, maxWidth: '60px' as any, Cell: (cell: Cell<T>) => { const row = cell.row as Row<T> & UseRowSelectRowProps<T>; return ( <Checkbox className={classes.checkBox} {...row.getToggleRowSelectedProps()} checked={row.isSelected} onChange={(e) => onRowSelected(row.original, e.target.checked)} /> ); }, }); } return columns as Column<T>[]; }, [props.columns, props.expandable]); const tableHooks: PluginHook<T>[] = [useFilters, useSortBy]; if (props.expandable) { tableHooks.push(useExpanded); } if (props.pagination) { tableHooks.push(usePagination); } if (props.selection) { tableHooks.push(useRowSelect); } tableHooks.push(useFlexLayout); const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow, state, // The page controls ;) page, // canPreviousPage, // canNextPage, pageOptions, pageCount, gotoPage, nextPage, previousPage, // setPageSize, // select props toggleAllRowsSelected, isAllRowsSelected, selectedFlatRows, toggleRowSelected, } = useTable( { columns, data: props.data, getRowId: (row: any) => row[props.rowKey], manualSortBy: !!props.onSortChange, manualFilters: !!props.onFilterChange, manualPagination: !!props.onPageChange, manualRowSelectedKey: props.rowKey, pageCount: !!props.onPageChange ? props.pageCount : undefined, autoResetPage: !props.onPageChange, useControlledState: (state1: any) => { return { ...state1, sortBy: props.sortBy ?? state1.sortBy, filters: props.filters ?? state1.filters, selectedRowIds: props.selectedRowIds ?? state1.selectedRowIds, } as TableState<T> & UseFiltersState<T> & UseSortByState<T> & UseRowSelectState<T>; }, expandSubRows: false, initialState: { pageIndex: 0, pageSize: props.pageSize ?? 0, selectedRowIds: props.selectedRowIds || {}, }, } as UseTableOptions<T> & UseFiltersOptions<T> & UseSortByOptions<T> & UseExpandedOptions<T> & UseRowSelectOptions<T> & UsePaginationOptions<T>, ...tableHooks ) as TableInstance<T> & UseTableInstanceProps<T> & UsePaginationInstanceProps<T> & UseRowSelectInstanceProps<T>; if (props.expandable && !props.renderExpandedComponent) { throw Error('FeTable: you must provide renderExpandedComponent property if the table is expandable'); } if (props.hasOwnProperty('sortBy') && !props.onSortChange) { throw Error('FeTable: you must provide onSortChange property if sortBy is controlled'); } if (props.hasOwnProperty('filters') && !props.onFilterChange) { throw Error('FeTable: you must provide onFilterChange property if filters is controlled'); } if (props.hasOwnProperty('pagination') && !props.pageSize) { throw Error('FeTable: you must provide pageSize property if pagination enabled'); } if (props.hasOwnProperty('onPageChange') && !props.pageCount) { throw Error('FeTable: you must provide pageCount property if onPageChange is controlled'); } const tableState = state as UseSortByState<T> & UseFiltersState<T> & UsePaginationState<T> & UseRowSelectState<T>; const onSortChange = useCallback( (column: FeTableColumnProps<T>) => { if (props.hasOwnProperty('sortBy')) { const sortBy = props.isMultiSort ? tableState.sortBy.filter(({ id }) => id !== column.id) : []; if (!column.isSorted) { sortBy.push({ id: column.id, desc: false }); } else if (!column.isSortedDesc) { sortBy.push({ id: column.id, desc: true }); } props.onSortChange?.(sortBy); } else { if (column.isSorted && column.isSortedDesc) { column.clearSortBy(); } else { column.toggleSortBy(column.isSorted, props.isMultiSort ?? false); } } }, [props.onSortChange] ); const onFilterChange = useCallback( (column: FeTableColumnProps<T>, filterValue?: any) => { if (props.hasOwnProperty('filters')) { const filters = tableState.filters.filter(({ id }) => id !== column.id); if (filterValue != null) { filters.push({ id: column.id, value: filterValue }); } props.onFilterChange?.(filters); } else { column.setFilter(filterValue); } }, [props.onFilterChange, tableState] ); const onToggleAllRowsSelected = useCallback( (value: boolean) => { if (props.hasOwnProperty('selectedRowIds')) { const selectedIds = props.data.reduce((p, n: any) => ({ ...p, [n[props.rowKey]]: true }), {}); props.onRowSelected?.(value ? selectedIds : {}); } else { toggleAllRowsSelected(value); } }, [props.onRowSelected] ); const onRowSelected = useCallback( (row: any, value: boolean) => { const id = row[props.rowKey]; if (props.hasOwnProperty('selectedRowIds')) { const newSelectedRows: any = { ...props.selectedRowIds }; if (value) { newSelectedRows[id] = true; } else { delete newSelectedRows[id]; } props.onRowSelected?.(newSelectedRows); } else { toggleRowSelected(id, value); } }, [props.onRowSelected] ); const handleOnPageChange = useCallback(() => { if (pagination === 'pages') { tableRef.current?.scroll?.({ top: 0, left: 0, behavior: 'smooth' }); } props.onPageChange?.(tableState.pageSize, tableState.pageIndex); }, [tableState.pageIndex]); useEffect(() => { !props.hasOwnProperty('sortBy') && props.onSortChange?.(tableState.sortBy); }, [props.sortBy, tableState.sortBy]); useEffect(() => { !props.hasOwnProperty('filters') && props.onFilterChange?.(tableState.filters); }, [props.filters, tableState.filters]); useEffect(() => { firstRender.current ? (firstRender.current = false) : handleOnPageChange(); }, [tableState.pageIndex]); useEffect(() => { !props.hasOwnProperty('selectedRowIds') && props.onRowSelected?.(tableState.selectedRowIds as any); }, [tableState.selectedRowIds]); const onPageChangeHandler = (page: number) => { if (page > tableState.pageIndex) { nextPage(); } else { previousPage(); } }; const { className, loading, pagination, totalData, pageSize } = props; return ( <Paper ref={tableRef} className={classes.paper}> <MaUTable className={classNames(classes.table, className)} {...getTableProps()}> <TableHead headerGroups={headerGroups} onSortChange={onSortChange} onFilterChange={onFilterChange} toggleAllRowsSelected={onToggleAllRowsSelected} isAllRowsSelected={isAllRowsSelected} selectedFlatRows={selectedFlatRows} /> <TableBody pageSize={pageSize} pagination={pagination} getTableBodyProps={getTableBodyProps} prepareRow={prepareRow} loading={loading} rows={(pagination ? page : rows) as (Row<T> & UseExpandedRowProps<T>)[]} renderExpandedComponent={props.renderExpandedComponent} onInfiniteScroll={handleOnPageChange} /> </MaUTable> {loading && pagination === 'pages' && rows.length > 0 && <Loader center size={24} />} {pagination === 'pages' && ( <TablePagination className={classes.footer} rowsPerPageOptions={[]} component='div' count={totalData || rows.length} rowsPerPage={tableState.pageSize} page={tableState.pageIndex} onChangePage={(e, page) => onPageChangeHandler(page)} ActionsComponent={(props) => ( <TablePaginationActions {...props} gotoPage={gotoPage} pageOptions={pageOptions} /> )} /> )} </Paper> ); }
Example #3
Source File: Table.tsx From opensaas with MIT License | 4 votes |
Table: React.FC<TableProps> = <T extends object>(props: TableProps<T>) => { const { expandable, selection, pagination, sortBy, pageCount, data, selectedRowIds, pageSize, rowKey, loading, isMultiSort, renderExpandedComponent, onPageChange, filters: propsFilters, onSortChange: propsOnSortChange, onRowSelected: propsOnRowSelected, onFilterChange: propsOnFilterChange, columns: propsColumns, } = props; const classes = useStyles(); const tableRef = useRef<HTMLTableElement>(null); const hasSortBy = props.hasOwnProperty('sortBy'); const hasFilters = props.hasOwnProperty('filters'); const hasPagination = props.hasOwnProperty('pagination'); const hasOnPageChange = props.hasOwnProperty('onPageChange'); const hasSelectedRowIds = props.hasOwnProperty('selectedRowIds'); const onRowSelected = useCallback( (row: UseRowSelectRowProps<T> & Row<T> & UseTableRowProps<T>, value: boolean) => { const id = (row.original as any)[rowKey]; if (hasSelectedRowIds) { const newSelectedRows: any = { ...selectedRowIds }; if (value) { newSelectedRows[id] = true; } else { delete newSelectedRows[id]; } propsOnRowSelected?.(newSelectedRows); } else { row.toggleRowSelected(value); } }, [hasSelectedRowIds, rowKey, selectedRowIds, propsOnRowSelected], ); const columns = useMemo(() => { const columns = propsColumns.map( ({ sortable, Filter, Header, ...rest }) => ({ ...rest, disableSortBy: !sortable, disableFilters: !Filter, Filter, Header: Header ?? <div style={{ minWidth: rest.minWidth, maxWidth: rest.maxWidth }} />, } as TableColumnOptions<T>), ); if (expandable) { columns.unshift({ id: 'expander', minWidth: 60, maxWidth: '60px' as any, Cell: (cell: UseTableCellProps<T>) => { const row = cell.row as Row<T> & UseExpandedRowProps<T>; return ( <IconButton className={classes.expandIcon} {...row.getToggleRowExpandedProps()}> {row.isExpanded ? <KeyboardArrowUpIcon /> : <KeyboardArrowDownIcon />} </IconButton> ); }, }); } if (selection) { columns.unshift({ id: 'selection', minWidth: 60, maxWidth: '60px' as any, Cell: (cell: UseTableCellProps<T>) => { const row = cell.row as UseRowSelectRowProps<T> & Row<T> & UseTableRowProps<T>; return ( <Checkbox className={classes.checkBox} {...row.getToggleRowSelectedProps()} checked={row.isSelected} onChange={(e) => onRowSelected(row, e.target.checked)} /> ); }, }); } return columns as Column<T>[]; }, [propsColumns, expandable, classes, selection, onRowSelected]); const tableHooks: PluginHook<T>[] = [useFilters, useSortBy]; if (expandable) { tableHooks.push(useExpanded); } if (pagination) { tableHooks.push(usePagination); } if (selection) { tableHooks.push(useRowSelect); } tableHooks.push(useFlexLayout); const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow, state, page, pageOptions, gotoPage, nextPage, previousPage, toggleAllRowsSelected, isAllRowsSelected, selectedFlatRows, } = useTable( { columns, data, getRowId: (row: any) => row[rowKey], manualSortBy: !!propsOnSortChange, manualFilters: !!propsOnFilterChange, manualPagination: !!onPageChange, manualRowSelectedKey: rowKey, pageCount: pageCount ?? 0, useControlledState: (state1: any) => ({ ...state1, sortBy: sortBy ?? state1.sortBy, filters: propsFilters ?? state1.filters, selectedRowIds: selectedRowIds ?? state1.selectedRowIds, } as TableState<T> & UseFiltersState<T> & UseSortByState<T> & UseRowSelectState<T>), expandSubRows: false, initialState: { pageIndex: 0, pageSize: pageSize ?? 0, selectedRowIds: selectedRowIds || {}, }, } as UseTableOptions<T> & UseFiltersOptions<T> & UseSortByOptions<T> & UseExpandedOptions<T> & UseRowSelectOptions<T> & UsePaginationOptions<T>, ...tableHooks, ) as TableInstance<T> & UseTableInstanceProps<T> & UsePaginationInstanceProps<T> & UseRowSelectInstanceProps<T>; if (expandable && !renderExpandedComponent) { throw Error('Table: you must provide renderExpandedComponent property if the table is expandable'); } if (hasSortBy && !propsOnSortChange) { throw Error('Table: you must provide onSortChange property if sortBy is controlled'); } if (hasFilters && !propsOnFilterChange) { throw Error('Table: you must provide onFilterChange property if filters is controlled'); } if (hasPagination && !pageSize) { throw Error('Table: you must provide pageSize property if pagination enabled'); } if (hasOnPageChange && !pageCount) { throw Error('Table: you must provide pageCount property if onPageChange is controlled'); } const tableState = state as UseSortByState<T> & UseFiltersState<T> & UsePaginationState<T> & UseRowSelectState<T>; const onSortChange = useCallback( (column: TableColumnProps<T>) => { if (hasSortBy) { const sortBy = isMultiSort ? tableState.sortBy.filter(({ id }) => id !== column.id) : []; if (!column.isSorted) { sortBy.push({ id: column.id, desc: false }); } else if (!column.isSortedDesc) { sortBy.push({ id: column.id, desc: true }); } propsOnSortChange?.(sortBy); } else { if (column.isSorted && column.isSortedDesc) { column.clearSortBy(); } else { column.toggleSortBy(column.isSorted, isMultiSort ?? false); } } }, [hasSortBy, isMultiSort, tableState.sortBy, propsOnSortChange], ); const onFilterChange = useCallback( (column: TableColumnProps<T>, filterValue?: any) => { if (hasFilters) { const filters = tableState.filters.filter(({ id }) => id !== column.id); if (filterValue != null) { filters.push({ id: column.id, value: filterValue }); } propsOnFilterChange?.(filters); } else { column.setFilter(filterValue); } }, [propsOnFilterChange, hasFilters, tableState.filters], ); const onToggleAllRowsSelected = useCallback( (value: boolean) => { if (hasSelectedRowIds) { const selectedIds = data.reduce((p, n: any) => ({ ...p, [n[rowKey]]: true }), {}); propsOnRowSelected?.(value ? selectedIds : {}); } else { toggleAllRowsSelected(value); } }, [hasSelectedRowIds, data, rowKey, propsOnRowSelected, toggleAllRowsSelected], ); useEffect(() => { if (!hasSortBy) propsOnSortChange?.(tableState.sortBy); }, [hasSortBy, propsOnSortChange, tableState.sortBy]); useEffect(() => { if (!hasFilters) propsOnFilterChange?.(tableState.filters); }, [hasFilters, propsOnFilterChange, tableState.filters]); useEffect(() => { tableRef.current?.querySelector('.table-tbody')?.scroll?.({ top: 0, left: 0, behavior: 'smooth' }); onPageChange?.(tableState.pageSize, tableState.pageIndex); }, [onPageChange, tableState.pageSize, tableState.pageIndex]); useEffect(() => { if (!hasSelectedRowIds) propsOnRowSelected?.(tableState.selectedRowIds as any); }, [hasSelectedRowIds, propsOnRowSelected, tableState.selectedRowIds]); const onPageChangeHandler = (page: number) => { if (page > tableState.pageIndex) { nextPage(); } else { previousPage(); } }; return ( <Paper className={classes.paper}> <MaterialUITable className={classes.table} ref={tableRef} {...getTableProps()}> <TableHead headerGroups={headerGroups} onSortChange={onSortChange} onFilterChange={onFilterChange} toggleAllRowsSelected={onToggleAllRowsSelected} isAllRowsSelected={isAllRowsSelected} selectedFlatRows={selectedFlatRows} /> <TableBody getTableBodyProps={getTableBodyProps} prepareRow={prepareRow} loading={loading} rows={(pagination ? page : rows) as (Row<T> & UseExpandedRowProps<T>)[]} renderExpandedComponent={renderExpandedComponent} /> </MaterialUITable> {pagination === 'pages' && ( <TablePagination className={classes.footer} rowsPerPageOptions={[]} component='div' count={rows.length} rowsPerPage={tableState.pageSize} page={tableState.pageIndex} onChangePage={(e, page) => onPageChangeHandler(page)} ActionsComponent={(props) => ( <TablePaginationActions {...props} gotoPage={gotoPage} pageOptions={pageOptions} /> )} /> )} </Paper> ); }
Example #4
Source File: Grouping.tsx From viewer-components-react with MIT License | 4 votes |
Groupings = ({ mapping, goBack }: GroupsTreeProps) => {
const iModelConnection = useActiveIModelConnection() as IModelConnection;
const apiContext = useContext(ApiContext);
const iModelId = useActiveIModelConnection()?.iModelId as string;
const [showDeleteModal, setShowDeleteModal] = useState<boolean>(false);
const [isLoading, setIsLoading] = useState<boolean>(true);
const [groupsView, setGroupsView] = useState<GroupsView>(GroupsView.GROUPS);
const [selectedGroup, setSelectedGroup] = useState<GroupType | undefined>(
undefined,
);
const hilitedElements = useRef<Map<string, string[]>>(new Map());
const [selectedRows, setSelectedRows] = useState<Record<string, boolean>>({});
const [isLoadingQuery, setLoadingQuery] = useState<boolean>(false);
const [groups, setGroups] = useState<Group[]>([]);
useEffect(() => {
void fetchGroups(setGroups, iModelId, mapping.id ?? "", setIsLoading, apiContext);
}, [apiContext, iModelId, mapping.id, setIsLoading]);
const refresh = useCallback(async () => {
setGroupsView(GroupsView.GROUPS);
setSelectedGroup(undefined);
setGroups([]);
await fetchGroups(setGroups, iModelId, mapping.id ?? "", setIsLoading, apiContext);
}, [apiContext, iModelId, mapping.id, setGroups]);
const addGroup = () => {
// TODO Retain selection in view without emphasizes. Goal is to make it so we can distinguish
// hilited elements from regular elements without emphasis due to it blocking selection. For now clearing
// selection.
clearEmphasizedElements();
setGroupsView(GroupsView.ADD);
};
const onModify = useCallback((value) => {
clearEmphasizedElements();
setSelectedGroup(value.row.original);
setGroupsView(GroupsView.MODIFYING);
}, []);
const openProperties = useCallback((value) => {
clearEmphasizedElements();
setSelectedGroup(value.row.original);
setGroupsView(GroupsView.PROPERTIES);
}, []);
const groupsColumns = useMemo(
() => [
{
Header: "Table",
columns: [
{
id: "groupName",
Header: "Group",
accessor: "groupName",
Cell: (value: CellProps<GroupType>) => (
<>
{isLoadingQuery ? (
value.row.original.groupName
) : (
<div
className='iui-anchor'
onClick={(e) => {
e.stopPropagation();
openProperties(value);
}}
>
{value.row.original.groupName}
</div>
)}
</>
),
},
{
id: "description",
Header: "Description",
accessor: "description",
},
{
id: "dropdown",
Header: "",
width: 80,
Cell: (value: CellProps<GroupType>) => {
return (
<div onClick={(e) => e.stopPropagation()}>
<DropdownMenu
disabled={isLoadingQuery}
menuItems={(close: () => void) => [
<MenuItem
key={0}
onClick={() => onModify(value)}
icon={<SvgEdit />}
>
Modify
</MenuItem>,
<MenuItem
key={1}
onClick={() => openProperties(value)}
icon={<SvgList />}
>
Properties
</MenuItem>,
<MenuItem
key={2}
onClick={() => {
setSelectedGroup(value.row.original);
setShowDeleteModal(true);
close();
}}
icon={<SvgDelete />}
>
Remove
</MenuItem>,
]}
>
<IconButton
disabled={isLoadingQuery}
styleType='borderless'
>
<SvgMore
style={{
width: "16px",
height: "16px",
}}
/>
</IconButton>
</DropdownMenu>
</div>
);
},
},
],
},
],
[isLoadingQuery, onModify, openProperties],
);
// Temp
const stringToColor = function (str: string) {
let hash = 0;
for (let i = 0; i < str.length; i++) {
hash = str.charCodeAt(i) + ((hash << 5) - hash);
}
let colour = "#";
for (let i = 0; i < 3; i++) {
const value = (hash >> (i * 8)) & 0xff;
colour += (`00${value.toString(16)}`).substr(-2);
}
return colour;
};
const onSelect = useCallback(
async (selectedData: GroupType[] | undefined) => {
clearEmphasizedElements();
if (selectedData && selectedData.length > 0) {
setLoadingQuery(true);
let allIds: string[] = [];
for (const row of selectedData) {
const query = row.query ?? "";
if (hilitedElements.current.has(query)) {
const hilitedIds = hilitedElements.current.get(query) ?? [];
visualizeElements(hilitedIds, stringToColor(row.id ?? ""));
allIds = allIds.concat(hilitedIds);
} else {
try {
const ids: string[] = await fetchIdsFromQuery(
query,
iModelConnection,
);
if (ids.length === 0) {
toaster.warning(`${row.groupName}'s query is valid but produced no results.`);
}
const hiliteIds = await visualizeElementsById(
ids,
stringToColor(row.id ?? ""),
iModelConnection,
);
hilitedElements.current.set(query, hiliteIds);
allIds = allIds.concat(ids);
} catch {
const index = groups.findIndex((group) => group.id === row.id);
setSelectedRows((rowIds) => {
const selectedRowIds = { ...rowIds };
delete selectedRowIds[index];
return selectedRowIds;
});
toaster.negative(`Could not load ${row.groupName}. Query could not be resolved.`);
}
}
}
await zoomToElements(allIds);
setLoadingQuery(false);
}
},
[iModelConnection, groups],
);
const controlledState = useCallback(
(state) => {
return {
...state,
selectedRowIds: { ...selectedRows },
};
},
[selectedRows],
);
const propertyMenuGoBack = useCallback(async () => {
clearEmphasizedElements();
setGroupsView(GroupsView.GROUPS);
await refresh();
}, [refresh]);
const tableStateReducer = (
newState: TableState,
action: ActionType,
_previousState: TableState,
instance?: TableInstance,
): TableState => {
switch (action.type) {
case actions.toggleRowSelected: {
const newSelectedRows = {
...selectedRows,
};
if (action.value) {
newSelectedRows[action.id] = true;
} else {
delete newSelectedRows[action.id];
}
setSelectedRows(newSelectedRows);
newState.selectedRowIds = newSelectedRows;
break;
}
case actions.toggleAllRowsSelected: {
if (!instance?.rowsById) {
break;
}
const newSelectedRows = {} as Record<string, boolean>;
if (action.value) {
Object.keys(instance.rowsById).forEach(
(id) => (newSelectedRows[id] = true),
);
}
setSelectedRows(newSelectedRows);
newState.selectedRowIds = newSelectedRows;
break;
}
default:
break;
}
return newState;
};
switch (groupsView) {
case GroupsView.ADD:
return (
<GroupAction
iModelId={iModelId}
mappingId={mapping.id ?? ""}
goBack={async () => {
clearEmphasizedElements();
setGroupsView(GroupsView.GROUPS);
await refresh();
}}
/>
);
case GroupsView.MODIFYING:
return selectedGroup ? (
<GroupAction
iModelId={iModelId}
mappingId={mapping.id ?? ""}
group={selectedGroup}
goBack={async () => {
clearEmphasizedElements();
setGroupsView(GroupsView.GROUPS);
await refresh();
}}
/>
) : null;
case GroupsView.PROPERTIES:
return selectedGroup ? (
<PropertyMenu
iModelId={iModelId}
mappingId={mapping.id ?? ""}
group={selectedGroup}
goBack={propertyMenuGoBack}
/>
) : null;
default:
return (
<>
<WidgetHeader
title={mapping.mappingName ?? ""}
disabled={isLoading || isLoadingQuery}
returnFn={async () => {
clearEmphasizedElements();
await goBack();
}}
/>
<div className='groups-container'>
<Button
startIcon={
isLoadingQuery ? <ProgressRadial size="small" indeterminate /> : <SvgAdd />
}
styleType='high-visibility'
disabled={isLoadingQuery}
onClick={() => addGroup()}
>
{isLoadingQuery ? "Loading Group(s)" : "Add Group"}
</Button>
<Table<GroupType>
data={groups}
density='extra-condensed'
columns={groupsColumns}
emptyTableContent='No Groups available.'
isSortable
isSelectable
onSelect={onSelect}
isLoading={isLoading}
isRowDisabled={() => isLoadingQuery}
stateReducer={tableStateReducer}
useControlledState={controlledState}
/>
</div>
<DeleteModal
entityName={selectedGroup?.groupName ?? ""}
show={showDeleteModal}
setShow={setShowDeleteModal}
onDelete={async () => {
const reportingClientApi = new ReportingClient(apiContext.prefix);
await reportingClientApi.deleteGroup(
apiContext.accessToken,
iModelId,
mapping.id ?? "",
selectedGroup?.id ?? "",
);
}}
refresh={refresh}
/>
</>
);
}
}
Example #5
Source File: ValidationTableWidget.tsx From frontend-sample-showcase with MIT License | 4 votes |
ValidationTableWidget: React.FunctionComponent = () => {
const iModelConnection = useActiveIModelConnection();
const [validationResults, setValidationResults] = React.useState<ValidationResults>();
const [ruleData, setRuleData] = React.useState<Record<string, PropertyValueValidationRule | undefined>>();
const [selectedElement, setSelectedElement] = useState<string | undefined>();
useEffect(() => {
const removeDataListener = ValidationApi.onValidationDataChanged.addListener((dat) => {
setValidationResults(dat.validationData);
setRuleData(dat.ruleData);
});
const removeElementListener = ValidationApi.onMarkerClicked.addListener((elementId) => {
setSelectedElement(elementId);
});
if (iModelConnection) {
ValidationApi.getValidationData(iModelConnection.iTwinId!).catch((error) => {
// eslint-disable-next-line no-console
console.error(error);
});
}
return () => {
removeDataListener();
removeElementListener();
};
}, [iModelConnection]);
const columnDefinition = useMemo((): Column<TableRow>[] => [
{
Header: "Table",
columns: [
{
Header: "Element Id",
accessor: "elementId",
},
{
Header: "Element Label",
accessor: "elementLabel",
},
{
Header: "Rule Name",
accessor: "ruleName",
},
{
Header: "Legal Range",
accessor: "legalValues",
},
{
Header: "Invalid Value",
accessor: "badValue",
},
],
},
], []);
const data = useMemo(() => {
const rows: TableRow[] = [];
if (validationResults !== undefined && validationResults.result !== undefined && validationResults.ruleList !== undefined && ruleData !== undefined) {
const getLegalValue = (item: any) => {
const currentRuleData = ruleData[validationResults.ruleList[item.ruleIndex].id];
if (!currentRuleData)
return "";
if (currentRuleData.functionParameters.lowerBound) {
if (currentRuleData.functionParameters.upperBound) {
// Range of values
return `[${currentRuleData.functionParameters.lowerBound},${currentRuleData.functionParameters.upperBound}]`;
} else {
// Value has a lower bound
return `>${currentRuleData.functionParameters.lowerBound}`;
}
} else {
// Value needs to be defined
return "Must be Defined";
}
};
validationResults.result.forEach((rowData) => {
const row: TableRow = {
elementId: rowData.elementId,
elementLabel: rowData.elementLabel,
ruleName: validationResults.ruleList[rowData.ruleIndex].displayName,
legalValues: getLegalValue(rowData),
badValue: rowData.badValue,
};
rows.push(row);
});
}
return rows;
}, [validationResults, ruleData]);
const controlledState = useCallback(
(state: TableState<TableRow>, meta: MetaBase<TableRow>) => {
state.selectedRowIds = {};
if (selectedElement) {
const row = meta.instance.rows.find((r: { original: { elementId: string } }) => r.original.elementId === selectedElement);
if (row) {
state.selectedRowIds[row.id] = true;
}
}
return { ...state };
},
[selectedElement],
);
const tableStateReducer = (
newState: TableState<TableRow>,
action: ActionType,
_previousState: TableState<TableRow>,
instance?: TableInstance<TableRow> | undefined,
): TableState<TableRow> => {
switch (action.type) {
case actions.toggleRowSelected: {
newState.selectedRowIds = {};
if (action.value)
newState.selectedRowIds[action.id] = true;
if (instance) {
const elementId = instance.rowsById[action.id].original.elementId;
ValidationApi.visualizeViolation(elementId);
setSelectedElement(elementId);
}
break;
}
default:
break;
}
return newState;
};
return (
<Table<TableRow>
useControlledState={controlledState}
stateReducer={tableStateReducer}
isSelectable={true}
data={data}
columns={columnDefinition}
isLoading={!validationResults}
emptyTableContent="No data"
density="extra-condensed" />
);
}