0
Fork 0
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:
Xiao Yijun 2023-07-10 12:26:38 +08:00 committed by GitHub
parent 50045f27f4
commit 5ce23ee7b1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 44 additions and 9 deletions

View file

@ -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'));
})

View file

@ -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'));
})

View file

@ -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 });

View file

@ -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 (

View file

@ -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 (