Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow editing description from filter edition dialogs #660

Merged
merged 15 commits into from
Jan 9, 2025
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { FieldConstants } from '../../../utils/constants/fieldConstants';
import { useSnackMessage } from '../../../hooks/useSnackMessage';
import { CustomMuiDialog } from '../customMuiDialog/CustomMuiDialog';
import { ExpandingTextField } from '../../inputs/reactHookForm/text/ExpandingTextField';
import { MAX_CHAR_DESCRIPTION } from '../../../utils/constants/uiConstants';

export interface DescriptionModificationDialogProps {
elementUuid: string;
Expand All @@ -24,7 +25,7 @@ export interface DescriptionModificationDialogProps {
}

const schema = yup.object().shape({
[FieldConstants.DESCRIPTION]: yup.string().max(500, 'descriptionLimitError'),
[FieldConstants.DESCRIPTION]: yup.string().max(MAX_CHAR_DESCRIPTION, 'descriptionLimitError'),
});
type SchemaType = yup.InferType<typeof schema>;

Expand Down
3 changes: 2 additions & 1 deletion src/components/filter/FilterCreationDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { FilterForm } from './FilterForm';
import { EXPERT_FILTER_QUERY, expertFilterSchema, getExpertFilterEmptyFormData } from './expert/ExpertFilterForm';
import { FilterType } from './constants/FilterConstants';
import { ElementExistsType } from '../../utils/types/elementType';
import { MAX_CHAR_DESCRIPTION } from '../../utils/constants/uiConstants';

const emptyFormData = {
[FieldConstants.NAME]: '',
Expand All @@ -38,7 +39,7 @@ const formSchema = yup
.object()
.shape({
[FieldConstants.NAME]: yup.string().trim().required('nameEmpty'),
[FieldConstants.DESCRIPTION]: yup.string().max(500, 'descriptionLimitError'),
[FieldConstants.DESCRIPTION]: yup.string().max(MAX_CHAR_DESCRIPTION, 'descriptionLimitError'),
[FieldConstants.FILTER_TYPE]: yup.string().required(),
[FieldConstants.EQUIPMENT_TYPE]: yup.string().required(),
...explicitNamingFilterSchema,
Expand Down
37 changes: 22 additions & 15 deletions src/components/filter/HeaderFilterForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import { UniqueNameInput } from '../inputs/reactHookForm/text/UniqueNameInput';
import { ElementExistsType, ElementType } from '../../utils/types/elementType';
import { DescriptionField } from '../inputs/reactHookForm/text/DescriptionField';
import { RadioInput } from '../inputs/reactHookForm/booleans/RadioInput';
import yup from '../../utils/yupConfig';
import { MAX_CHAR_DESCRIPTION } from '../../utils/constants/uiConstants';

export interface FilterFormProps {
creation?: boolean;
Expand All @@ -25,6 +27,13 @@ export interface FilterFormProps {
handleFilterTypeChange?: (event: React.ChangeEvent<HTMLInputElement>, value: string) => void;
}

export const HeaderFilterSchema = {
[FieldConstants.NAME]: yup.string().trim().required('nameEmpty'),
[FieldConstants.FILTER_TYPE]: yup.string().required(),
[FieldConstants.EQUIPMENT_TYPE]: yup.string().required(),
[FieldConstants.DESCRIPTION]: yup.string().max(MAX_CHAR_DESCRIPTION, 'descriptionLimitError'),
};

export function HeaderFilterForm({
sourceFilterForExplicitNamingConversion,
creation,
Expand All @@ -46,22 +55,20 @@ export function HeaderFilterForm({
elementExists={elementExists}
/>
</Grid>
{creation && (
<>
<Grid item xs={12}>
<DescriptionField />
<>
<Grid item xs={12}>
<DescriptionField />
</Grid>
{creation && !sourceFilterForExplicitNamingConversion && (
<Grid item>
<RadioInput
name={FieldConstants.FILTER_TYPE}
options={filterTypes}
formProps={{ onChange: handleFilterTypeChange }} // need to override this in order to do not activate the validate button when changing the filter type
/>
</Grid>
{!sourceFilterForExplicitNamingConversion && (
<Grid item>
<RadioInput
name={FieldConstants.FILTER_TYPE}
options={filterTypes}
formProps={{ onChange: handleFilterTypeChange }} // need to override this in order to do not activate the validate button when changing the filter type
/>
</Grid>
)}
</>
)}
)}
</>
</Grid>
);
}
32 changes: 8 additions & 24 deletions src/components/filter/expert/ExpertFilterEditionDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,47 +6,29 @@
*/

import { yupResolver } from '@hookform/resolvers/yup';
import { UUID } from 'crypto';
import { useCallback, useEffect, useState } from 'react';
import { useForm } from 'react-hook-form';
import { useSnackMessage } from '../../../hooks/useSnackMessage';
import { FetchStatus } from '../../../utils/constants/fetchStatus';
import { FieldConstants } from '../../../utils/constants/fieldConstants';
import { ElementExistsType } from '../../../utils/types/elementType';
import yup from '../../../utils/yupConfig';
import { CustomMuiDialog } from '../../dialogs/customMuiDialog/CustomMuiDialog';
import { FilterType, NO_ITEM_SELECTION_FOR_COPY } from '../constants/FilterConstants';
import { ItemSelectionForCopy } from '../filter.type';
import { FilterEditionProps } from '../filter.type';
import { FilterForm } from '../FilterForm';
import { saveExpertFilter } from '../utils/filterApi';
import { EXPERT_FILTER_QUERY, expertFilterSchema } from './ExpertFilterForm';
import { importExpertRules } from './expertFilterUtils';
import { HeaderFilterSchema } from '../HeaderFilterForm';

const formSchema = yup
.object()
.shape({
[FieldConstants.NAME]: yup.string().trim().required('nameEmpty'),
[FieldConstants.FILTER_TYPE]: yup.string().required(),
[FieldConstants.EQUIPMENT_TYPE]: yup.string().required(),
...HeaderFilterSchema,
...expertFilterSchema,
})
.required();

export interface ExpertFilterEditionDialogProps {
id: string;
name: string;
titleId: string;
open: boolean;
onClose: () => void;
broadcastChannel: BroadcastChannel;
itemSelectionForCopy: ItemSelectionForCopy;
setItemSelectionForCopy: (selection: ItemSelectionForCopy) => void;
getFilterById: (id: string) => Promise<{ [prop: string]: any }>;
activeDirectory?: UUID;
elementExists?: ElementExistsType;
language?: string;
}

export function ExpertFilterEditionDialog({
id,
name,
Expand All @@ -60,7 +42,8 @@ export function ExpertFilterEditionDialog({
activeDirectory,
elementExists,
language,
}: Readonly<ExpertFilterEditionDialogProps>) {
description,
}: Readonly<FilterEditionProps>) {
const { snackError } = useSnackMessage();
const [dataFetchStatus, setDataFetchStatus] = useState(FetchStatus.IDLE);

Expand All @@ -86,6 +69,7 @@ export function ExpertFilterEditionDialog({
setDataFetchStatus(FetchStatus.FETCH_SUCCESS);
reset({
[FieldConstants.NAME]: name,
[FieldConstants.DESCRIPTION]: description,
[FieldConstants.FILTER_TYPE]: FilterType.EXPERT.id,
[FieldConstants.EQUIPMENT_TYPE]: response[FieldConstants.EQUIPMENT_TYPE],
[EXPERT_FILTER_QUERY]: importExpertRules(response[EXPERT_FILTER_QUERY]),
Expand All @@ -99,7 +83,7 @@ export function ExpertFilterEditionDialog({
});
});
}
}, [id, name, open, reset, snackError, getFilterById]);
}, [id, name, open, reset, snackError, getFilterById, description]);

const onSubmit = useCallback(
(filterForm: { [prop: string]: any }) => {
Expand All @@ -108,7 +92,7 @@ export function ExpertFilterEditionDialog({
filterForm[EXPERT_FILTER_QUERY],
filterForm[FieldConstants.EQUIPMENT_TYPE],
filterForm[FieldConstants.NAME],
'', // The description can not be edited from this dialog
filterForm[FieldConstants.DESCRIPTION] ?? '',
false,
null,
onClose,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
*/

import { yupResolver } from '@hookform/resolvers/yup';
import { UUID } from 'crypto';
import PropTypes from 'prop-types';
import { useCallback, useEffect, useState } from 'react';
import { SubmitHandler, useForm, UseFormReturn } from 'react-hook-form';
Expand All @@ -19,36 +18,20 @@ import { saveExplicitNamingFilter } from '../utils/filterApi';
import { explicitNamingFilterSchema, FILTER_EQUIPMENTS_ATTRIBUTES } from './ExplicitNamingFilterForm';

import { FetchStatus } from '../../../utils/constants/fetchStatus';
import { ElementExistsType } from '../../../utils/types/elementType';
import { FilterForm } from '../FilterForm';
import { FilterType, NO_ITEM_SELECTION_FOR_COPY } from '../constants/FilterConstants';
import { ItemSelectionForCopy } from '../filter.type';
import { FilterEditionProps } from '../filter.type';
import { HeaderFilterSchema } from '../HeaderFilterForm';

const formSchema = yup
.object()
.shape({
[FieldConstants.NAME]: yup.string().trim().required('nameEmpty'),
[FieldConstants.FILTER_TYPE]: yup.string().required(),
[FieldConstants.EQUIPMENT_TYPE]: yup.string().required(),
...HeaderFilterSchema,
...explicitNamingFilterSchema,
})
.required();

type FormSchemaType = yup.InferType<typeof formSchema>;
export interface ExplicitNamingFilterEditionDialogProps {
id: string;
name: string;
titleId: string;
open: boolean;
onClose: () => void;
broadcastChannel: BroadcastChannel;
itemSelectionForCopy: ItemSelectionForCopy;
setItemSelectionForCopy: (selection: ItemSelectionForCopy) => void;
getFilterById: (id: string) => Promise<any>;
activeDirectory?: UUID;
elementExists?: ElementExistsType;
language?: string;
}

export function ExplicitNamingFilterEditionDialog({
id,
Expand All @@ -63,7 +46,8 @@ export function ExplicitNamingFilterEditionDialog({
activeDirectory,
elementExists,
language,
}: Readonly<ExplicitNamingFilterEditionDialogProps>) {
description,
}: Readonly<FilterEditionProps>) {
const { snackError } = useSnackMessage();
const [dataFetchStatus, setDataFetchStatus] = useState(FetchStatus.IDLE);

Expand All @@ -88,6 +72,7 @@ export function ExplicitNamingFilterEditionDialog({
setDataFetchStatus(FetchStatus.FETCH_SUCCESS);
reset({
[FieldConstants.NAME]: name,
[FieldConstants.DESCRIPTION]: description,
[FieldConstants.FILTER_TYPE]: FilterType.EXPLICIT_NAMING.id,
[FieldConstants.EQUIPMENT_TYPE]: response[FieldConstants.EQUIPMENT_TYPE],
[FILTER_EQUIPMENTS_ATTRIBUTES]: response[FILTER_EQUIPMENTS_ATTRIBUTES].map((row: any) => ({
Expand All @@ -104,7 +89,7 @@ export function ExplicitNamingFilterEditionDialog({
});
});
}
}, [id, name, open, reset, snackError, getFilterById]);
}, [id, name, open, reset, snackError, getFilterById, description]);

const onSubmit = useCallback<SubmitHandler<FormSchemaType>>(
(filterForm) => {
Expand All @@ -113,7 +98,7 @@ export function ExplicitNamingFilterEditionDialog({
false,
filterForm[FieldConstants.EQUIPMENT_TYPE],
filterForm[FieldConstants.NAME],
'', // The description can not be edited from this dialog
filterForm[FieldConstants.DESCRIPTION] ?? '',
id,
(error) => {
snackError({
Expand Down
17 changes: 17 additions & 0 deletions src/components/filter/filter.type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*/

import { UUID } from 'crypto';
import { ElementExistsType } from '../../utils';

/**
* Represent an item/object in directories.
Expand All @@ -18,3 +19,19 @@ export type ItemSelectionForCopy = {
parentDirectoryUuid: UUID | null;
specificTypeItem: string | null;
};

export interface FilterEditionProps {
id: string;
name: string;
titleId: string;
open: boolean;
onClose: () => void;
broadcastChannel: BroadcastChannel;
itemSelectionForCopy: ItemSelectionForCopy;
setItemSelectionForCopy: (selection: ItemSelectionForCopy) => void;
getFilterById: (id: string) => Promise<{ [prop: string]: any }>;
activeDirectory?: UUID;
elementExists?: ElementExistsType;
language?: string;
description?: string;
}
2 changes: 2 additions & 0 deletions src/components/filter/utils/filterApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ export const saveExplicitNamingFilter = (
filterEquipmentsAttributes: cleanedTableValues,
},
name,
description,
token
)
.then(() => {
Expand Down Expand Up @@ -113,6 +114,7 @@ export const saveExpertFilter = (
rules: exportExpertRules(query),
},
name,
description,
token
)
.then(() => {
Expand Down
7 changes: 4 additions & 3 deletions src/components/inputs/reactHookForm/text/DescriptionField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,17 @@ import { FieldConstants } from '../../../../utils/constants/fieldConstants';
import { ExpandingTextField } from './ExpandingTextField';

export function DescriptionField() {
const [isDescriptionFieldVisible, setIsDescriptionFieldVisible] = useState(false);
const { setValue } = useFormContext();
const { setValue, getValues } = useFormContext();
const description = getValues(FieldConstants.DESCRIPTION);
const [isDescriptionFieldVisible, setIsDescriptionFieldVisible] = useState(!!description);

const handleOpenDescription = () => {
setIsDescriptionFieldVisible(true);
};

const handleCloseDescription = () => {
setIsDescriptionFieldVisible(false);
setValue(FieldConstants.DESCRIPTION, '');
setValue(FieldConstants.DESCRIPTION, '', { shouldDirty: true });
};

return (
Expand Down
3 changes: 2 additions & 1 deletion src/services/explore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,10 @@ export function createFilter(
);
}

export function saveFilter(filter: any, name: string, token?: string) {
export function saveFilter(filter: any, name: string, description: string, token?: string) {
const urlSearchParams = new URLSearchParams();
urlSearchParams.append('name', name);
urlSearchParams.append('description', description);
return backendFetch(
`${PREFIX_EXPLORE_SERVER_QUERIES}/v1/explore/filters/${filter.id}?${urlSearchParams.toString()}`,
{
Expand Down
1 change: 1 addition & 0 deletions src/utils/constants/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@
export * from './browserConstants';
export * from './fetchStatus';
export * from './fieldConstants';
export * from './uiConstants';
8 changes: 8 additions & 0 deletions src/utils/constants/uiConstants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/*
* Copyright © 2025, RTE (http://www.rte-france.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

export const MAX_CHAR_DESCRIPTION = 500;
Loading