Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import './details-expander.cell-renderer.css';

interface DetailsExpanderRendererProps extends ICellRendererParams {
detailsRowCellRendererPresencePredicate?: (data: any) => boolean;
// setPageSize: (val: number) => void;
}

export const DetailsExpanderRenderer: React.FC<DetailsExpanderRendererProps> = (
Expand All @@ -19,6 +20,11 @@ export const DetailsExpanderRenderer: React.FC<DetailsExpanderRendererProps> = (
const rowNode = props.api.getRowNode(`${props.data?.id as string}${DETAILS_ROW_ID_SUFFIX}`);
const isVisible = (rowNode?.data as IGridRowDataDetailsExt).isVisible;
rowNode?.setDataValue('isVisible', !isVisible);
// if (!isVisible) {
// props.setPageSize(1)
// } else {
// props.setPageSize(-1)
// }
props.api.onFilterChanged();
};
if (shouldRenderBtn) return <CollapseButton onClick={handleCollapseExpand} />;
Expand Down
75 changes: 61 additions & 14 deletions src/common/components/grid/grid.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import React, { CSSProperties, useCallback, useEffect, useState } from 'react';
import React, {
CSSProperties,
ReactElement,
useCallback,
useEffect,
useMemo,
useState,
} from 'react';
import { AgGridReact } from 'ag-grid-react';
import {
GridReadyEvent as AgGridReadyEvent,
Expand Down Expand Up @@ -43,6 +50,12 @@ interface GridComponentProps {
focusByRowId?: string;
setIsRowFound?: (val: boolean) => void;
handleFocusError?: (error: IError | undefined) => void;
customPagination?: {
renderPaginationBar: (data: any) => ReactElement;
filteredData: any[];
getPageByProperty: (key: string, value: unknown) => { page: number; index: number } | null;
paginate: (page: number) => void;
};
}

export interface GridApi extends AgGridApi {}
Expand Down Expand Up @@ -77,7 +90,7 @@ export interface IRowPosition {
export interface GridRowNode extends IRowNode {}

export const GridComponent: React.FC<GridComponentProps> = (props) => {
const [rowData, setRowData] = useState<any[]>();
const [allRowsData, setAllRowsData] = useState<any[]>();
const theme = useTheme();
const [gridApi, setGridApi] = useState<GridApi>();

Expand Down Expand Up @@ -202,7 +215,7 @@ export const GridComponent: React.FC<GridComponentProps> = (props) => {
result.push(...(props.rowData as []));
}
if (typeof props.isLoading === 'undefined' || props.isLoading === false) {
setRowData(result);
setAllRowsData(result);
if (result) {
gridApi?.setGridOption('loading', false);
}
Expand All @@ -217,9 +230,9 @@ export const GridComponent: React.FC<GridComponentProps> = (props) => {
}

focusAndExpandRow(gridApi, focusByRowId);
}, [rowData]);
}, [allRowsData, props.customPagination?.filteredData]);

const getRowPosition = (gridApi: GridApi, id: string): IRowPosition | undefined => {
const getNativeRowPosition = (gridApi: GridApi, id: string): IRowPosition | undefined => {
const node = gridApi.getRowNode(id);

if (!node || node.rowIndex == null) {
Expand All @@ -236,8 +249,22 @@ export const GridComponent: React.FC<GridComponentProps> = (props) => {
};
};

const getRowPosition = (gridApi: GridApi, id: string): IRowPosition | undefined => {
const nativePagination = getNativeRowPosition(gridApi, id);
const customPagination = props.customPagination?.getPageByProperty('id', id);
const row: IRowPosition | undefined = customPagination
? {
pageNumber: customPagination.page,
rowIndex: customPagination.index,
}
: nativePagination;

return row;
};

const goToRowAndFocus = (gridApi: GridApi, row: IRowPosition) => {
gridApi.paginationGoToPage(row.pageNumber);
props.customPagination?.paginate(row.pageNumber);
gridApi?.paginationGoToPage(row.pageNumber);
gridApi.ensureIndexVisible(row.rowIndex, 'middle');
gridApi.getDisplayedRowAtIndex(row.rowIndex)?.setSelected(true);
};
Expand Down Expand Up @@ -266,15 +293,35 @@ export const GridComponent: React.FC<GridComponentProps> = (props) => {

const agGridThemeOverrides = GridThemes.getTheme(theme);

const containerStyle = useMemo(() => {
return {
...props.style,
display: 'flex' as const,
flexDirection: 'column' as const,
};
}, [props.style]);

const gridStyle = useMemo(() => {
return {
...agGridThemeOverrides,
flex: 1,
minHeight: 0,
overflow: 'hidden',
};
}, [agGridThemeOverrides]);

return (
<Box
className={theme.type === 'dark' ? 'ag-theme-alpine-dark' : 'ag-theme-alpine'}
style={{
...props.style,
...agGridThemeOverrides,
}}
>
<AgGridReact gridOptions={gridOptions} rowData={rowData} />
<Box style={containerStyle}>
<Box
className={theme.type === 'dark' ? 'ag-theme-alpine-dark' : 'ag-theme-alpine'}
style={gridStyle}
>
<AgGridReact
gridOptions={gridOptions}
rowData={props.customPagination?.filteredData ?? allRowsData}
/>
</Box>
{gridApi && props.customPagination?.renderPaginationBar?.(allRowsData)}
</Box>
);
};
3 changes: 3 additions & 0 deletions src/common/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -673,6 +673,9 @@

"system-status.job.filter.status.all": "All",

"job.pagination.pages-count": "Page {pageNumber} of {totalPages}",
"job.pagination.rows-count": "{rowNumber} to {totalPageRows} of {totalRows}",

"system-status.job-priority-lowest": "Lowest",
"system-status.job-priority-low": "Low",
"system-status.job-priority-normal": "Normal",
Expand Down
3 changes: 3 additions & 0 deletions src/common/i18n/he.json
Original file line number Diff line number Diff line change
Expand Up @@ -894,6 +894,9 @@
"export-layer.validations.relations.equal": "שווה ל-",
"export-layer.validations.againstOtherField": "הערך צריך להיות {relation} שדה {fieldName}",

"job.pagination.pages-count": "דף {pageNumber} מ{totalPages}",
"job.pagination.rows-count": "{rowNumber} עד {totalPageRows} מתוך {totalRows} רשומות",

"progress.titleProcess": "תהליך",
"progress.titleProgress": "התקדמות",
"progress.titleTime": "זמן (ms)",
Expand Down
3 changes: 3 additions & 0 deletions src/common/i18n/helper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const isRtl = (locale: string) => {
return locale === 'he';
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/* .paginationIcon.mdc-icon-button button {
font-size: 14px !important;
} */

.paginationIcon .material-icons {
font-size: 18px;
}

.navigateBar {
position: relative;
flex-shrink: 0;
color: #afbfda;
display: flex;
align-items: center;
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
import { ColDef, ColGroupDef, GetRowIdParams } from 'ag-grid-community';
import {
ColDef,
ColGroupDef,
ColumnState,
GetRowIdParams,
GridApi,

Check failure on line 6 in src/discrete-layer/components/job-manager/grids/job-manager-grid.common.tsx

View workflow job for this annotation

GitHub Actions / build_and_test

Duplicate identifier 'GridApi'.
SortChangedEvent,
} from 'ag-grid-community';
import React, { useCallback, useContext, useEffect, useMemo, useState } from 'react';
import { useIntl } from 'react-intl';
import { FormattedMessage, useIntl } from 'react-intl';
import CONFIG from '../../../../common/config';
import {
GridComponent,

Check failure on line 13 in src/discrete-layer/components/job-manager/grids/job-manager-grid.common.tsx

View workflow job for this annotation

GitHub Actions / build_and_test

Duplicate identifier 'GridApi'.
GridComponentOptions,
GridReadyEvent,
} from '../../../../common/components/grid';
Expand All @@ -24,6 +31,12 @@
import { StatusRenderer } from '../cell-renderer/status.cell-renderer';
import { TooltippedCellRenderer } from '../cell-renderer/tool-tipped.cell-renderer';
import { JOB_ENTITY } from '../job.types';
import { IconButton } from '@map-colonies/react-core';
import { Box } from '@material-ui/core';
import { usePagination } from './pagination.hook';
import { isRtl } from '../../../../common/i18n/helper';

import './job-manager-grid.common.css';

export interface ICommonJobManagerGridProps {
rowData: unknown[];
Expand All @@ -44,7 +57,7 @@
handleFocusError?: (error: IError | undefined) => void;
}

const pagination = true;
const pagination = false;
const pageSize = 10;

const JobManagerGrid: React.FC<ICommonJobManagerGridProps> = (props) => {
Expand Down Expand Up @@ -74,6 +87,11 @@
const { enumsMap } = useContext(EnumsMapContext);
const [focusJobId, setFocusJobId] = useState<string | undefined>(undefined);
const [isRowFound, setIsRowFound] = useState<boolean>(false);
const [sortState, setSortState] = useState<{
colId: string;
field: string;
sort: 'asc' | 'desc';
} | null>(null);

useEffect(() => {
if (!focusOnJob?.id) {
Expand Down Expand Up @@ -222,8 +240,8 @@
},
valueFormatter: primitiveValueFormatter,
sortable: true,
// @ts-ignore
comparator: (valueA, valueB, nodeA, nodeB, isInverted): number => valueA - valueB,
comparator: (valueA: any, valueB: any, nodeA: any, nodeB: any, isInverted: any): number =>
valueA - valueB,
},
// {
// headerName: intl.formatMessage({
Expand Down Expand Up @@ -339,6 +357,7 @@
enableFilterHandlers: true,
suppressRowTransform: true,
pagination: pagination,
suppressPaginationPanel: true,
paginationPageSize: pageSize,
paginationPageSizeSelector: false, //[pageSize, 20, 50, 100],
getRowId: (params: GetRowIdParams): string => {
Expand Down Expand Up @@ -377,6 +396,17 @@
unSortIcon: true,
},
onGridReady,
onSortChanged: (event: SortChangedEvent) => {
const sortedCol: ColumnState | undefined = event.api
.getColumnState()
.find((col) => col.sort !== null);
if (sortedCol) {
const field = event.api.getColumn(sortedCol.colId)?.getColDef().field ?? sortedCol.colId;
setSortState({ colId: sortedCol.colId, field, sort: sortedCol.sort as 'asc' | 'desc' });
} else {
setSortState(null);
}
},
// eslint-disable-next-line @typescript-eslint/no-explicit-any
context: {
detailsRowCellRendererPresencePredicate: (rowData: any) => {
Expand All @@ -397,16 +427,115 @@
padding: '12px',
};

const [dataWithDetails, setDataWithDetails] = useState<Record<string, unknown>[] | null>(null);

const sortedDataWithDetails = useMemo(() => {
if (!dataWithDetails || !sortState?.sort) return dataWithDetails ?? [];

// eslint-disable-next-line @typescript-eslint/no-explicit-any
const colDef = (defaultColDef as any[]).find((col) => col.field === sortState.field);

// Data is interleaved [master, detail, master, detail, ...]; sort master+detail pairs together
const pairs: [Record<string, unknown>, Record<string, unknown>][] = [];
for (let i = 0; i < dataWithDetails.length; i += 2) {
pairs.push([dataWithDetails[i], dataWithDetails[i + 1] ?? {}]);
}

const sorted = pairs.sort((pairA, pairB) => {
const aVal = pairA[0][sortState.field];
const bVal = pairB[0][sortState.field];
let result: number;
if (colDef?.comparator) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
result = colDef.comparator(aVal, bVal, null, null, false) as number;
} else {
result = String(aVal ?? '').localeCompare(String(bVal ?? ''));
}
return sortState.sort === 'desc' ? -result : result;
});

return sorted.flatMap((pair) => [...pair]);
}, [dataWithDetails, sortState]);

const customPagination = usePagination<Record<string, unknown>>({
data: sortedDataWithDetails,
itemsPerPage: 20,
});

const renderPaginationBar = (rowsAndTheirDetails: any) => {
setDataWithDetails(rowsAndTheirDetails);
const masterRows = 10;
const rowsWithDetails = 20;

const startRow = (customPagination.currentPage - 1) * masterRows + 1;

const endRow =
Math.min(
customPagination.currentPage * rowsWithDetails,
rowsAndTheirDetails?.length ?? Infinity
) / 2;

const isRtlVal = isRtl(intl.locale);

const backIcon = isRtlVal ? 'mc-icon-Arrow-Right' : 'mc-icon-Arrow-Left';
const nextIcon = isRtlVal ? 'mc-icon-Arrow-Left' : 'mc-icon-Arrow-Right';
const arrowsBackIcon = isRtlVal ? 'mc-icon-Arrows-Right' : 'mc-icon-Arrows-Left';
const arrowsNextIcon = isRtlVal ? 'mc-icon-Arrows-Left' : 'mc-icon-Arrows-Right';

return (
<Box className="navigateBar paginationIcon">
<IconButton className={arrowsBackIcon} onClick={() => customPagination.paginate(1)}>
prev page
</IconButton>
<IconButton className={backIcon} onClick={() => customPagination.prevPage()}>
prev page
</IconButton>
<FormattedMessage
id="job.pagination.pages-count"
values={{
pageNumber: customPagination.currentPage,
totalPages: customPagination.totalPages,
}}
/>
<IconButton className={nextIcon} onClick={() => customPagination.nextPage()}>
next page
</IconButton>
<IconButton
className={arrowsNextIcon}
onClick={() => customPagination.paginate(customPagination.totalPages)}
>
next page
</IconButton>
<FormattedMessage
id="job.pagination.rows-count"
values={{
rowNumber: startRow,
totalPageRows: endRow,
totalRows: (rowsAndTheirDetails?.length ?? 0) / 2,
}}
/>
</Box>
);
};

return (
<GridComponent
gridOptions={gridOptions}
rowData={rowData}
style={{ ...defaultGridStyle, ...gridStyleOverride }}
isLoading={areJobsLoading}
focusByRowId={focusJobId}
setIsRowFound={setIsRowFound}
handleFocusError={handleFocusError}
/>
<>
<GridComponent
gridOptions={gridOptions}
rowData={rowData}
style={{ ...defaultGridStyle, ...gridStyleOverride }}
isLoading={areJobsLoading}
focusByRowId={focusJobId}
setIsRowFound={setIsRowFound}
handleFocusError={handleFocusError}
customPagination={{
renderPaginationBar,
filteredData: customPagination.data,
getPageByProperty: customPagination.getPageByProperty,
paginate: customPagination.paginate,
}}
></GridComponent>
</>
);
};

Expand Down
Loading
Loading