Skip to content

Commit c85cbba

Browse files
dbraquartayolab
andauthored
Rework user and group modification and display (#111)
Signed-off-by: David BRAQUART <[email protected]> Co-authored-by: Ayoub LABIDI <[email protected]>
1 parent 6860c2d commit c85cbba

29 files changed

+1330
-785
lines changed

src/components/Grid/GridTable.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ export const GridTable: GridTableWithRef = forwardRef(function AgGridToolbar<TDa
7676
);
7777

7878
return (
79-
<Grid container direction="column" justifyContent="flex-start" alignItems="stretch">
79+
<Grid container direction="column" justifyContent="flex-start" alignItems="stretch" width={'100%'}>
8080
<Grid item xs="auto">
8181
<AppBar position="static" color="default">
8282
<Toolbar
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/**
2+
* Copyright (c) 2025, RTE (http://www.rte-france.com)
3+
* This Source Code Form is subject to the terms of the Mozilla Public
4+
* License, v. 2.0. If a copy of the MPL was not distributed with this
5+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
6+
*/
7+
8+
import React, { useRef, useState, useEffect } from 'react';
9+
import { Chip, Grid, Tooltip } from '@mui/material';
10+
import { mergeSx } from '@gridsuite/commons-ui';
11+
12+
const maxChipWidth = 100;
13+
const counterChipWidth = 25;
14+
15+
const chipStyles = {
16+
default: {
17+
marginTop: 2,
18+
marginLeft: 1,
19+
maxWidth: maxChipWidth,
20+
},
21+
withCounter: {
22+
'&.MuiChip-root': {
23+
fontWeight: 'bold',
24+
},
25+
},
26+
};
27+
28+
export interface MultiChipCellRendererProps {
29+
value: string[];
30+
}
31+
32+
const MultiChipCellRenderer = (props: MultiChipCellRendererProps) => {
33+
const values: string[] = props.value ? [...props.value].sort((a: string, b: string) => a.localeCompare(b)) : [];
34+
const containerRef = useRef<HTMLDivElement>(null);
35+
const [chipLimit, setChipLimit] = useState<number>(5);
36+
37+
useEffect(() => {
38+
const updateChipLimit = () => {
39+
if (!containerRef.current) {
40+
return;
41+
}
42+
const zoomLevel = window.devicePixelRatio;
43+
const adjustedContainerWidth = containerRef.current.clientWidth / zoomLevel;
44+
const maxChips = Math.max(1, Math.floor(adjustedContainerWidth / (maxChipWidth + counterChipWidth)));
45+
setChipLimit(maxChips);
46+
};
47+
48+
updateChipLimit();
49+
const resizeObserver = new ResizeObserver(updateChipLimit);
50+
if (containerRef.current) {
51+
resizeObserver.observe(containerRef.current);
52+
}
53+
return () => resizeObserver.disconnect();
54+
}, [values.length]);
55+
56+
const customChip = (label: string, index: number, chipsNumber: number) => {
57+
if (index < chipLimit) {
58+
return (
59+
<Tooltip title={label} key={`tooltip-${label}`}>
60+
<Chip key={label} label={label} size="small" sx={chipStyles.default} />
61+
</Tooltip>
62+
);
63+
} else if (index === chipLimit) {
64+
const hiddenLabels = values.slice(chipLimit);
65+
const tooltipContent = (
66+
<>
67+
{hiddenLabels.map((hiddenLabel) => (
68+
<div key={`hidden-label-${hiddenLabel}`}>{'- ' + hiddenLabel}</div>
69+
))}
70+
</>
71+
);
72+
73+
return (
74+
<Tooltip title={tooltipContent} key="tooltip-counter">
75+
<Chip
76+
size="small"
77+
label={`+${chipsNumber - chipLimit}`}
78+
key="chip-counter"
79+
sx={mergeSx(chipStyles.default, chipStyles.withCounter)}
80+
/>
81+
</Tooltip>
82+
);
83+
}
84+
return null;
85+
};
86+
87+
return (
88+
<Grid container direction="row" spacing={1} wrap="nowrap" ref={containerRef}>
89+
{values.map((label: string, index: number) => customChip(label, index, values.length))}
90+
</Grid>
91+
);
92+
};
93+
94+
export default MultiChipCellRenderer;

src/pages/common/multi-chips-renderer-component.tsx

Lines changed: 0 additions & 26 deletions
This file was deleted.

src/pages/common/multi-select-editor-component.tsx

Lines changed: 0 additions & 52 deletions
This file was deleted.

src/pages/common/table-config.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/**
2+
* Copyright (c) 2025, RTE (http://www.rte-france.com)
3+
* This Source Code Form is subject to the terms of the Mozilla Public
4+
* License, v. 2.0. If a copy of the MPL was not distributed with this
5+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
6+
*/
7+
8+
import { ColDef, RowSelectionOptions } from 'ag-grid-community';
9+
10+
export const defaultColDef: ColDef = {
11+
editable: false,
12+
resizable: true,
13+
minWidth: 50,
14+
rowDrag: false,
15+
sortable: true,
16+
};
17+
18+
export const defaultRowSelection: RowSelectionOptions = {
19+
mode: 'multiRow',
20+
enableClickSelection: false,
21+
checkboxes: true,
22+
headerCheckbox: true,
23+
hideDisabledCheckboxes: false,
24+
};
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/**
2+
* Copyright (c) 2025, RTE (http://www.rte-france.com)
3+
* This Source Code Form is subject to the terms of the Mozilla Public
4+
* License, v. 2.0. If a copy of the MPL was not distributed with this
5+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
6+
*/
7+
8+
import { FunctionComponent, useCallback, useMemo, useRef, useState } from 'react';
9+
import { FormattedMessage } from 'react-intl';
10+
import { CustomAGGrid } from '@gridsuite/commons-ui';
11+
import { Grid, Typography } from '@mui/material';
12+
import { AgGridReact } from 'ag-grid-react';
13+
import { ColDef, GetRowIdParams, GridReadyEvent } from 'ag-grid-community';
14+
import { defaultColDef, defaultRowSelection } from './table-config';
15+
16+
export interface TableSelectionProps {
17+
itemName: string;
18+
tableItems: string[];
19+
tableSelectedItems?: string[];
20+
onSelectionChanged: (selectedItems: string[]) => void;
21+
}
22+
23+
const TableSelection: FunctionComponent<TableSelectionProps> = (props) => {
24+
const [selectedRowsLength, setSelectedRowsLength] = useState(0);
25+
const gridRef = useRef<AgGridReact>(null);
26+
27+
const handleEquipmentSelectionChanged = useCallback(() => {
28+
const selectedRows = gridRef.current?.api.getSelectedRows();
29+
if (selectedRows == null) {
30+
setSelectedRowsLength(0);
31+
props.onSelectionChanged([]);
32+
} else {
33+
setSelectedRowsLength(selectedRows.length);
34+
props.onSelectionChanged(selectedRows.map((r) => r.id));
35+
}
36+
}, [props]);
37+
38+
const rowData = useMemo(() => {
39+
return props.tableItems.map((str) => ({ id: str }));
40+
}, [props.tableItems]);
41+
42+
const columnDefs = useMemo(
43+
(): ColDef[] => [
44+
{
45+
field: 'id',
46+
filter: true,
47+
sortable: true,
48+
tooltipField: 'id',
49+
flex: 1,
50+
},
51+
],
52+
[]
53+
);
54+
55+
function getRowId(params: GetRowIdParams): string {
56+
return params.data.id;
57+
}
58+
59+
const onGridReady = useCallback(
60+
({ api }: GridReadyEvent) => {
61+
api?.forEachNode((n) => {
62+
if (props.tableSelectedItems !== undefined && n.id && props.tableSelectedItems.includes(n.id)) {
63+
n.setSelected(true);
64+
}
65+
});
66+
},
67+
[props.tableSelectedItems]
68+
);
69+
70+
return (
71+
<Grid item container direction={'column'} style={{ height: '100%' }}>
72+
<Grid item>
73+
<Typography variant="subtitle1">
74+
<FormattedMessage id={props.itemName}></FormattedMessage>
75+
{` (${selectedRowsLength} / ${rowData?.length ?? 0})`}
76+
</Typography>
77+
</Grid>
78+
<Grid item xs>
79+
<CustomAGGrid
80+
gridId="table-selection"
81+
ref={gridRef}
82+
rowData={rowData}
83+
columnDefs={columnDefs}
84+
defaultColDef={defaultColDef}
85+
rowSelection={defaultRowSelection}
86+
getRowId={getRowId}
87+
onSelectionChanged={handleEquipmentSelectionChanged}
88+
onGridReady={onGridReady}
89+
/>
90+
</Grid>
91+
</Grid>
92+
);
93+
};
94+
export default TableSelection;

0 commit comments

Comments
 (0)