Skip to content

Commit 74d1101

Browse files
Add spreadsheet type: branch (#3065)
* Spreadsheet types alone and sorted (more readable) * remove unnecessary `EquipmentUpdateType` * remove unnecessary equipment fetchers by types * remove duplicate TABLES_TYPES * add branch type
1 parent b2a013e commit 74d1101

25 files changed

+576
-1019
lines changed

src/components/spreadsheet-view/add-spreadsheet/add-spreadsheet-button.tsx

Lines changed: 19 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,23 @@
55
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
66
*/
77

8-
import { FC, MouseEvent, useCallback, useState } from 'react';
9-
import { Button, Menu, MenuItem, Theme, Tooltip } from '@mui/material';
8+
import { useCallback, useState } from 'react';
9+
import { Button, type ButtonProps, Menu, MenuItem, Theme, Tooltip } from '@mui/material';
1010
import AddIcon from '@mui/icons-material/Add';
11-
import { useStateBoolean, UseStateBooleanReturn } from '@gridsuite/commons-ui';
11+
import { useStateBoolean } from '@gridsuite/commons-ui';
1212
import { FormattedMessage } from 'react-intl';
1313
import { SpreadsheetTabDefinition } from '../types/spreadsheet.type';
1414
import { ResetNodeAliasCallback } from '../hooks/use-node-aliases';
1515
import AddEmptySpreadsheetDialog from './dialogs/add-empty-spreadsheet-dialog';
1616
import AddSpreadsheetFromModelDialog from './dialogs/add-spreadsheet-from-model-dialog';
1717
import AddSpreadsheetsFromCollectionDialog from './dialogs/add-spreadsheets-from-collection-dialog';
18+
import type { DialogComponent } from './types';
1819

19-
interface AddSpreadsheetButtonProps {
20+
export type AddSpreadsheetButtonProps = {
2021
disabled: boolean;
2122
resetTabIndex: (newTablesDefinitions: SpreadsheetTabDefinition[]) => void;
2223
resetNodeAliases: ResetNodeAliasCallback;
23-
}
24+
};
2425

2526
const styles = {
2627
addButton: (theme: Theme) => ({
@@ -29,12 +30,6 @@ const styles = {
2930
}),
3031
};
3132

32-
type DialogComponent = FC<{
33-
open: UseStateBooleanReturn;
34-
resetTabIndex: (newTablesDefinitions: SpreadsheetTabDefinition[]) => void;
35-
resetNodeAliases: ResetNodeAliasCallback;
36-
}>;
37-
3833
export interface SpreadsheetOption {
3934
id: string;
4035
label: string;
@@ -44,7 +39,7 @@ export interface SpreadsheetOption {
4439
/**
4540
* Constants for spreadsheet creation options with associated dialog components
4641
*/
47-
const NEW_SPREADSHEET_CREATION_OPTIONS: Record<string, SpreadsheetOption> = {
42+
const NEW_SPREADSHEET_CREATION_OPTIONS = {
4843
EMPTY: {
4944
id: 'EMPTY',
5045
label: 'spreadsheet/create_new_spreadsheet/empty_spreadsheet_option',
@@ -60,20 +55,23 @@ const NEW_SPREADSHEET_CREATION_OPTIONS: Record<string, SpreadsheetOption> = {
6055
label: 'spreadsheet/create_new_spreadsheet/apply_collection_option',
6156
dialog: AddSpreadsheetsFromCollectionDialog,
6257
},
63-
};
58+
} as const satisfies Record<string, SpreadsheetOption>;
6459

65-
const AddSpreadsheetButton: React.FC<AddSpreadsheetButtonProps> = ({ disabled, resetTabIndex, resetNodeAliases }) => {
60+
export default function AddSpreadsheetButton({
61+
disabled,
62+
resetTabIndex,
63+
resetNodeAliases,
64+
}: Readonly<AddSpreadsheetButtonProps>) {
6665
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
6766
const dialogOpen = useStateBoolean(false);
6867
const [selectedOption, setSelectedOption] = useState<SpreadsheetOption | undefined>();
6968

70-
const handleClick = useCallback((event: MouseEvent<HTMLButtonElement>) => {
71-
setAnchorEl(event.currentTarget);
72-
}, []);
69+
const handleClick = useCallback<NonNullable<ButtonProps['onClick']>>(
70+
(event) => setAnchorEl(event.currentTarget),
71+
[]
72+
);
7373

74-
const handleClose = useCallback(() => {
75-
setAnchorEl(null);
76-
}, []);
74+
const handleClose = useCallback(() => setAnchorEl(null), []);
7775

7876
const handleMenuItemClick = useCallback(
7977
(option: SpreadsheetOption) => {
@@ -102,12 +100,9 @@ const AddSpreadsheetButton: React.FC<AddSpreadsheetButtonProps> = ({ disabled, r
102100
</MenuItem>
103101
))}
104102
</Menu>
105-
106103
{SelectedDialog && (
107104
<SelectedDialog open={dialogOpen} resetTabIndex={resetTabIndex} resetNodeAliases={resetNodeAliases} />
108105
)}
109106
</>
110107
);
111-
};
112-
113-
export default AddSpreadsheetButton;
108+
}

src/components/spreadsheet-view/add-spreadsheet/dialogs/add-empty-spreadsheet-dialog.tsx

Lines changed: 24 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -7,65 +7,46 @@
77

88
import { useCallback, useEffect, useMemo } from 'react';
99
import { Grid } from '@mui/material';
10-
import {
11-
CustomFormProvider,
12-
EquipmentType,
13-
SelectInput,
14-
TextInput,
15-
UseStateBooleanReturn,
16-
useSnackMessage,
17-
} from '@gridsuite/commons-ui';
10+
import { CustomFormProvider, SelectInput, TextInput, useSnackMessage } from '@gridsuite/commons-ui';
1811
import { useForm } from 'react-hook-form';
1912
import { yupResolver } from '@hookform/resolvers/yup';
2013
import { useDispatch, useSelector } from 'react-redux';
2114
import { EQUIPMENT_TYPE_FIELD } from 'components/utils/field-constants';
2215
import { AppState } from 'redux/reducer';
2316
import { UUID } from 'crypto';
2417
import { dialogStyles } from '../styles/styles';
25-
import { ModificationDialog } from 'components/dialogs/commons/modificationDialog';
26-
import { getEmptySpreadsheetFormSchema, initialEmptySpreadsheetForm, SPREADSHEET_NAME } from './add-spreadsheet-form';
18+
import { ModificationDialog, type ModificationDialogProps } from 'components/dialogs/commons/modificationDialog';
19+
import {
20+
type EmptySpreadsheetForm,
21+
getEmptySpreadsheetFormSchema,
22+
initialEmptySpreadsheetForm,
23+
SPREADSHEET_NAME,
24+
} from './add-spreadsheet-form';
2725
import { addNewSpreadsheet } from './add-spreadsheet-utils';
2826
import { COLUMN_TYPES } from 'components/custom-aggrid/custom-aggrid-header.type';
29-
import { ColumnDefinitionDto } from '../../types/spreadsheet.type';
27+
import { ColumnDefinitionDto, SpreadsheetEquipmentType } from '../../types/spreadsheet.type';
3028
import { v4 as uuid4 } from 'uuid';
29+
import type { DialogComponentProps } from '../types';
3130

32-
interface AddEmptySpreadsheetDialogProps {
33-
open: UseStateBooleanReturn;
34-
}
31+
export type AddEmptySpreadsheetDialogProps = Pick<DialogComponentProps, 'open'>;
3532

36-
const TABLES_TYPES = [
37-
EquipmentType.SUBSTATION,
38-
EquipmentType.VOLTAGE_LEVEL,
39-
EquipmentType.LINE,
40-
EquipmentType.TWO_WINDINGS_TRANSFORMER,
41-
EquipmentType.THREE_WINDINGS_TRANSFORMER,
42-
EquipmentType.GENERATOR,
43-
EquipmentType.LOAD,
44-
EquipmentType.SHUNT_COMPENSATOR,
45-
EquipmentType.STATIC_VAR_COMPENSATOR,
46-
EquipmentType.BATTERY,
47-
EquipmentType.HVDC_LINE,
48-
EquipmentType.LCC_CONVERTER_STATION,
49-
EquipmentType.VSC_CONVERTER_STATION,
50-
EquipmentType.TIE_LINE,
51-
EquipmentType.DANGLING_LINE,
52-
EquipmentType.BUS,
53-
EquipmentType.BUSBAR_SECTION,
54-
];
33+
const TABLES_OPTIONS = Object.values(SpreadsheetEquipmentType).map(
34+
(elementType) => ({ id: elementType, label: elementType }) as const
35+
);
5536

56-
const DEFAULT_ID_COLUMN: ColumnDefinitionDto = {
37+
const DEFAULT_ID_COLUMN = {
5738
uuid: uuid4() as UUID,
5839
name: 'ID',
5940
id: 'id',
6041
type: COLUMN_TYPES.TEXT,
6142
formula: 'id',
6243
visible: true,
63-
};
44+
} as const satisfies ColumnDefinitionDto;
6445

6546
/**
6647
* Dialog for creating an empty spreadsheet
6748
*/
68-
export default function AddEmptySpreadsheetDialog({ open, ...dialogProps }: Readonly<AddEmptySpreadsheetDialogProps>) {
49+
export default function AddEmptySpreadsheetDialog({ open }: Readonly<AddEmptySpreadsheetDialogProps>) {
6950
const dispatch = useDispatch();
7051
const { snackError } = useSnackMessage();
7152
const studyUuid = useSelector((state: AppState) => state.studyUuid);
@@ -88,21 +69,17 @@ export default function AddEmptySpreadsheetDialog({ open, ...dialogProps }: Read
8869
reset(initialEmptySpreadsheetForm);
8970
}, [open.value, reset]);
9071

91-
const onSubmit = useCallback(
92-
(formData: any) => {
72+
const onSubmit = useCallback<ModificationDialogProps<EmptySpreadsheetForm>['onSave']>(
73+
(formData) => {
9374
if (!studyUuid) {
9475
return;
9576
}
96-
const tabIndex = tablesDefinitions.length;
97-
const tabName = formData[SPREADSHEET_NAME];
98-
const equipmentType = formData.equipmentType;
99-
10077
addNewSpreadsheet({
10178
studyUuid,
10279
columns: [DEFAULT_ID_COLUMN],
103-
sheetType: equipmentType,
104-
tabIndex,
105-
tabName,
80+
sheetType: formData.equipmentType,
81+
tabIndex: tablesDefinitions.length,
82+
tabName: formData[SPREADSHEET_NAME],
10683
spreadsheetsCollectionUuid: spreadsheetsCollectionUuid as UUID,
10784
dispatch,
10885
snackError,
@@ -119,9 +96,8 @@ export default function AddEmptySpreadsheetDialog({ open, ...dialogProps }: Read
11996
open={open.value}
12097
onClose={open.setFalse}
12198
onSave={onSubmit}
122-
onClear={() => null}
99+
onClear={() => {}}
123100
PaperProps={{ sx: dialogStyles.dialogContent }}
124-
{...dialogProps}
125101
>
126102
<Grid container spacing={2} direction="column" marginTop="auto">
127103
<Grid item xs>
@@ -133,10 +109,7 @@ export default function AddEmptySpreadsheetDialog({ open, ...dialogProps }: Read
133109
</Grid>
134110
<Grid item xs>
135111
<SelectInput
136-
options={Object.values(TABLES_TYPES).map((elementType) => ({
137-
id: elementType,
138-
label: elementType,
139-
}))}
112+
options={TABLES_OPTIONS}
140113
name={EQUIPMENT_TYPE_FIELD}
141114
label="spreadsheet/create_new_spreadsheet/element_type"
142115
size="small"

src/components/spreadsheet-view/add-spreadsheet/dialogs/add-spreadsheet-form.ts

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
import { EQUIPMENT_TYPE_FIELD, ID, NAME } from 'components/utils/field-constants';
99
import yup from '../../../utils/yup-config';
10+
import { SpreadsheetEquipmentType } from '../../types/spreadsheet.type';
1011

1112
export const SPREADSHEET_NAME = 'spreadsheetName';
1213
export const SPREADSHEET_MODEL = 'spreadsheetModel';
@@ -15,13 +16,14 @@ export const SPREADSHEET_COLLECTION_IMPORT_MODE = 'spreadsheetCollectionMode';
1516

1617
export const initialEmptySpreadsheetForm: EmptySpreadsheetForm = {
1718
[SPREADSHEET_NAME]: '',
19+
//@ts-expect-error TS2418: Type of computed property's value is '', which is not assignable to type NonNullable<SpreadsheetEquipmentType | undefined>
1820
[EQUIPMENT_TYPE_FIELD]: '',
19-
};
21+
} as const;
2022

2123
export const initialSpreadsheetFromModelForm: SpreadsheetFromModelForm = {
2224
[SPREADSHEET_NAME]: '',
2325
[SPREADSHEET_MODEL]: [],
24-
};
26+
} as const;
2527

2628
export enum SpreadsheetCollectionImportMode {
2729
REPLACE = 'REPLACE',
@@ -33,28 +35,28 @@ export const initialSpreadsheetCollectionForm: SpreadsheetCollectionForm = {
3335
[SPREADSHEET_COLLECTION_IMPORT_MODE]: SpreadsheetCollectionImportMode.REPLACE,
3436
};
3537

36-
export const getEmptySpreadsheetFormSchema = (tablesNames: string[]) => {
38+
function schemaSpreadsheetName(tablesNames: string[]) {
39+
return yup
40+
.string()
41+
.required()
42+
.max(60, 'spreadsheet/spreadsheet_name_le_60')
43+
.test(
44+
'unique',
45+
'spreadsheet/create_new_spreadsheet/spreadsheet_name_already_exists',
46+
(value) => !tablesNames.includes(value || '')
47+
);
48+
}
49+
50+
export function getEmptySpreadsheetFormSchema(tablesNames: string[]) {
3751
return yup.object().shape({
38-
[SPREADSHEET_NAME]: yup
39-
.string()
40-
.required()
41-
.max(60, 'spreadsheet/spreadsheet_name_le_60')
42-
.test('unique', 'spreadsheet/create_new_spreadsheet/spreadsheet_name_already_exists', (value) => {
43-
return !tablesNames.includes(value || '');
44-
}),
45-
[EQUIPMENT_TYPE_FIELD]: yup.string().required(),
52+
[SPREADSHEET_NAME]: schemaSpreadsheetName(tablesNames),
53+
[EQUIPMENT_TYPE_FIELD]: yup.string().oneOf(Object.values(SpreadsheetEquipmentType)).required(),
4654
});
47-
};
55+
}
4856

49-
export const getSpreadsheetFromModelFormSchema = (tablesNames: string[]) => {
57+
export function getSpreadsheetFromModelFormSchema(tablesNames: string[]) {
5058
return yup.object().shape({
51-
[SPREADSHEET_NAME]: yup
52-
.string()
53-
.required()
54-
.max(60, 'spreadsheet/spreadsheet_name_le_60')
55-
.test('unique', 'spreadsheet/create_new_spreadsheet/spreadsheet_name_already_exists', (value) => {
56-
return !tablesNames.includes(value || '');
57-
}),
59+
[SPREADSHEET_NAME]: schemaSpreadsheetName(tablesNames),
5860
[SPREADSHEET_MODEL]: yup
5961
.array()
6062
.of(
@@ -67,7 +69,7 @@ export const getSpreadsheetFromModelFormSchema = (tablesNames: string[]) => {
6769
.min(1, 'spreadsheet/create_new_spreadsheet/must_select_spreadsheet_model')
6870
.max(1, 'spreadsheet/create_new_spreadsheet/must_select_only_one_spreadsheet_model'),
6971
});
70-
};
72+
}
7173

7274
export const getSpreadsheetCollectionFormSchema = () => {
7375
return yup.object().shape({

src/components/spreadsheet-view/add-spreadsheet/dialogs/add-spreadsheet-from-model-dialog.tsx

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,38 +12,33 @@ import {
1212
DirectoryItemsInput,
1313
ElementType,
1414
TextInput,
15-
UseStateBooleanReturn,
1615
useSnackMessage,
1716
} from '@gridsuite/commons-ui';
1817
import { useForm, useWatch } from 'react-hook-form';
1918
import { yupResolver } from '@hookform/resolvers/yup';
2019
import { useDispatch, useSelector } from 'react-redux';
2120
import { AppState } from 'redux/reducer';
2221
import {
23-
SPREADSHEET_MODEL,
24-
SPREADSHEET_NAME,
2522
getSpreadsheetFromModelFormSchema,
2623
initialSpreadsheetFromModelForm,
24+
SPREADSHEET_MODEL,
25+
SPREADSHEET_NAME,
2726
} from './add-spreadsheet-form';
2827
import { addNewSpreadsheet } from './add-spreadsheet-utils';
2928
import { getSpreadsheetModel } from 'services/study-config';
3029
import { UUID } from 'crypto';
3130
import { ModificationDialog } from 'components/dialogs/commons/modificationDialog';
3231
import { dialogStyles } from '../styles/styles';
33-
import { ResetNodeAliasCallback } from '../../hooks/use-node-aliases';
32+
import type { DialogComponentProps } from '../types';
3433

35-
interface AddSpreadsheetFromModelDialogProps {
36-
open: UseStateBooleanReturn;
37-
resetNodeAliases: ResetNodeAliasCallback;
38-
}
34+
export type AddSpreadsheetFromModelDialogProps = Pick<DialogComponentProps, 'open' | 'resetNodeAliases'>;
3935

4036
/**
4137
* Dialog for creating a spreadsheet from an existing model
4238
*/
4339
export default function AddSpreadsheetFromModelDialog({
4440
open,
4541
resetNodeAliases,
46-
...dialogProps
4742
}: Readonly<AddSpreadsheetFromModelDialogProps>) {
4843
const dispatch = useDispatch();
4944
const { snackError } = useSnackMessage();
@@ -126,7 +121,6 @@ export default function AddSpreadsheetFromModelDialog({
126121
onSave={onSubmit}
127122
onClear={() => null}
128123
PaperProps={{ sx: dialogStyles.dialogContent }}
129-
{...dialogProps}
130124
>
131125
<Grid container spacing={2} direction="column" marginTop="auto">
132126
<Grid item xs>

0 commit comments

Comments
 (0)