mirror of
https://github.com/logto-io/logto.git
synced 2025-04-07 23:01:25 -05:00
fix(console): avoid updating dirty form data (#4138)
This commit is contained in:
parent
50045f27f4
commit
5ce23ee7b1
5 changed files with 44 additions and 9 deletions
|
@ -85,8 +85,12 @@ function ApplicationDetails() {
|
|||
return;
|
||||
}
|
||||
|
||||
if (isDirty) {
|
||||
return;
|
||||
}
|
||||
|
||||
reset(data);
|
||||
}, [data, reset]);
|
||||
}, [data, isDirty, reset]);
|
||||
|
||||
const onSubmit = handleSubmit(
|
||||
trySubmitSafe(async (formData) => {
|
||||
|
@ -114,6 +118,7 @@ function ApplicationDetails() {
|
|||
},
|
||||
})
|
||||
.json<Application>();
|
||||
reset(formData);
|
||||
void mutate();
|
||||
toast.success(t('general.saved'));
|
||||
})
|
||||
|
|
|
@ -68,8 +68,14 @@ function ConnectorContent({ isDeleted, connectorData, onConnectorUpdated }: Prop
|
|||
const isEmailServiceConnector = connectorId === ServiceConnector.Email;
|
||||
|
||||
useEffect(() => {
|
||||
/**
|
||||
* Note: should not refresh form data when the form is dirty.
|
||||
*/
|
||||
if (isDirty) {
|
||||
return;
|
||||
}
|
||||
reset(formData);
|
||||
}, [formData, reset]);
|
||||
}, [formData, isDirty, reset]);
|
||||
|
||||
const configParser = useConnectorFormConfigParser();
|
||||
|
||||
|
@ -97,6 +103,10 @@ function ConnectorContent({ isDeleted, connectorData, onConnectorUpdated }: Prop
|
|||
json: body,
|
||||
})
|
||||
.json<ConnectorResponse>();
|
||||
/**
|
||||
* Note: reset form dirty state before updating the form data.
|
||||
*/
|
||||
reset();
|
||||
onConnectorUpdated(updatedConnector);
|
||||
toast.success(t('general.saved'));
|
||||
})
|
||||
|
|
|
@ -111,10 +111,13 @@ function SignInExperience() {
|
|||
}, [data]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isDirty) {
|
||||
return;
|
||||
}
|
||||
if (defaultFormData) {
|
||||
reset(defaultFormData);
|
||||
}
|
||||
}, [reset, defaultFormData]);
|
||||
}, [reset, defaultFormData, isDirty]);
|
||||
|
||||
const saveData = async () => {
|
||||
setIsSaving(true);
|
||||
|
@ -125,6 +128,7 @@ function SignInExperience() {
|
|||
json: signInExperienceParser.toRemoteModel(getValues()),
|
||||
})
|
||||
.json<SignInExperienceType>();
|
||||
reset(signInExperienceParser.toLocalForm(updatedData));
|
||||
void mutate(updatedData);
|
||||
setDataToCompare(undefined);
|
||||
await updateConfigs({ signInExperienceCustomized: true });
|
||||
|
|
|
@ -39,7 +39,8 @@ function LanguageDetails() {
|
|||
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
|
||||
const { data: signInExperience } = useSWR<SignInExperience, RequestError>('api/sign-in-exp');
|
||||
const { languages } = useUiLanguages();
|
||||
const { selectedLanguage, setIsDirty, setSelectedLanguage } = useContext(LanguageEditorContext);
|
||||
const { selectedLanguage, isDirty, setIsDirty, setSelectedLanguage } =
|
||||
useContext(LanguageEditorContext);
|
||||
const [isDeletionAlertOpen, setIsDeletionAlertOpen] = useState(false);
|
||||
const isBuiltIn = isBuiltInLanguageTag(selectedLanguage);
|
||||
const isDefaultLanguage = signInExperience?.languageInfo.fallbackLanguage === selectedLanguage;
|
||||
|
@ -79,7 +80,7 @@ function LanguageDetails() {
|
|||
reset,
|
||||
setValue,
|
||||
register,
|
||||
formState: { isSubmitting, isDirty, dirtyFields },
|
||||
formState: { isSubmitting, isDirty: isFormStateDirty, dirtyFields },
|
||||
} = useForm<Translation>({
|
||||
defaultValues: defaultFormValues,
|
||||
});
|
||||
|
@ -90,13 +91,13 @@ function LanguageDetails() {
|
|||
* for the `isDirty` state does not work correctly when comparing form data with empty / undefined values.
|
||||
* Reference: https://github.com/react-hook-form/react-hook-form/issues/4740
|
||||
*/
|
||||
setIsDirty(isDirty && Object.keys(dirtyFields).length > 0);
|
||||
setIsDirty(isFormStateDirty && Object.keys(dirtyFields).length > 0);
|
||||
}, [
|
||||
/**
|
||||
* Note: `isDirty` is used to trigger this `useEffect`; for `dirtyFields` object only marks filed dirty at field level.
|
||||
* When `dirtyFields` is changed from `{keyA: false}` to `{keyA: true}`, this `useEffect` won't be triggered.
|
||||
*/
|
||||
isDirty,
|
||||
isFormStateDirty,
|
||||
dirtyFields,
|
||||
setIsDirty,
|
||||
]);
|
||||
|
@ -131,19 +132,31 @@ function LanguageDetails() {
|
|||
await api.delete(`api/custom-phrases/${selectedLanguage}`);
|
||||
|
||||
await globalMutate('api/custom-phrases');
|
||||
|
||||
setIsDirty(false);
|
||||
setSelectedLanguage(languages.find((languageTag) => languageTag !== selectedLanguage) ?? 'en');
|
||||
}, [api, globalMutate, isDefaultLanguage, languages, selectedLanguage, setSelectedLanguage]);
|
||||
}, [
|
||||
api,
|
||||
globalMutate,
|
||||
isDefaultLanguage,
|
||||
languages,
|
||||
selectedLanguage,
|
||||
setIsDirty,
|
||||
setSelectedLanguage,
|
||||
]);
|
||||
|
||||
const onSubmit = handleSubmit(
|
||||
trySubmitSafe(async (formData: Translation) => {
|
||||
const updatedCustomPhrase = await upsertCustomPhrase(selectedLanguage, formData);
|
||||
reset(updatedCustomPhrase.translation);
|
||||
void mutate(updatedCustomPhrase);
|
||||
toast.success(t('general.saved'));
|
||||
})
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (isDirty) {
|
||||
return;
|
||||
}
|
||||
reset(defaultFormValues);
|
||||
}, [
|
||||
/**
|
||||
|
@ -153,6 +166,7 @@ function LanguageDetails() {
|
|||
selectedLanguage,
|
||||
defaultFormValues,
|
||||
reset,
|
||||
isDirty,
|
||||
]);
|
||||
|
||||
return (
|
||||
|
|
|
@ -34,6 +34,7 @@ function LanguageEditorModal({ isOpen, onClose }: Props) {
|
|||
setPreSelectedLanguage,
|
||||
setPreAddedLanguage,
|
||||
setConfirmationState,
|
||||
setIsDirty,
|
||||
} = useContext(LanguageEditorContext);
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -68,6 +69,7 @@ function LanguageEditorModal({ isOpen, onClose }: Props) {
|
|||
}
|
||||
|
||||
setConfirmationState('none');
|
||||
setIsDirty(false);
|
||||
};
|
||||
|
||||
return (
|
||||
|
|
Loading…
Add table
Reference in a new issue