fix: avoid nested board settings forms
This commit is contained in:
1 parent
6a5162d615
commit
7adc18b1ce
1 file changed
+36
-27
@@ -36,6 +36,11 @@ const boardSettingsFormSchema = boardSavePartialSettingsSchema
|
||||
|
||||
export type FormValues = z.infer<typeof boardSettingsFormSchema>;
|
||||
|
||||
const normalizeMobileLayoutGutters = (layouts: readonly FormValues["layouts"][number][]) =>
|
||||
layouts.map((layout) =>
|
||||
layout.role === "mobile" ? { ...layout, leftGutterColumnCount: 0, rightGutterColumnCount: 0 } : layout,
|
||||
);
|
||||
|
||||
const PARTIAL_FORM_KEYS = [
|
||||
"pageTitle",
|
||||
"metaTitle",
|
||||
@@ -70,7 +75,7 @@ const buildInitialValues = (board: Board): FormValues => ({
|
||||
itemRadius: board.itemRadius,
|
||||
customCss: board.customCss ?? "",
|
||||
disableStatus: board.disableStatus,
|
||||
layouts: board.layouts,
|
||||
layouts: normalizeMobileLayoutGutters(board.layouts),
|
||||
});
|
||||
|
||||
interface BoardSettingsFormProps {
|
||||
@@ -122,46 +127,45 @@ export const BoardSettingsForm = ({ board, permissions, hasFullAccess, hideVisib
|
||||
return () => window.removeEventListener("beforeunload", handler);
|
||||
}, []);
|
||||
|
||||
const handleSubmitAsync = async (values: FormValues) => {
|
||||
const saveSettingsAsync = async (values: FormValues): Promise<FormValues | null> => {
|
||||
const defaults = initialValuesRef.current;
|
||||
const changed = <TKey extends keyof FormValues>(...fields: TKey[]) =>
|
||||
fields.some((field) => values[field] !== defaults[field]);
|
||||
|
||||
const { layouts, ...partialSettings } = values;
|
||||
|
||||
const saveActions: { when: boolean; action: () => Promise<unknown> }[] = [
|
||||
{
|
||||
when: changed(...PARTIAL_FORM_KEYS),
|
||||
action: () =>
|
||||
savePartialSettings.mutateAsync({ id: board.id, ...partialSettings }).then(() => {
|
||||
updateFavicon(values.faviconImageUrl ?? homarrLogoPath);
|
||||
}),
|
||||
},
|
||||
{
|
||||
when: changed("layouts"),
|
||||
action: () => saveLayouts.mutateAsync({ id: board.id, layouts }),
|
||||
},
|
||||
];
|
||||
|
||||
const promises = saveActions.filter((saveAction) => saveAction.when).map((saveAction) => saveAction.action());
|
||||
if (promises.length === 0) return;
|
||||
const { layouts: submittedLayouts, ...partialSettings } = values;
|
||||
const layouts = normalizeMobileLayoutGutters(submittedLayouts);
|
||||
const partialSettingsChanged = changed(...PARTIAL_FORM_KEYS);
|
||||
const layoutsChanged = changed("layouts");
|
||||
if (!partialSettingsChanged && !layoutsChanged) return values;
|
||||
|
||||
try {
|
||||
await Promise.all(promises);
|
||||
lastSavedRef.current = { pageTitle: values.pageTitle, logoImageUrl: values.logoImageUrl };
|
||||
initialValuesRef.current = values;
|
||||
form.setInitialValues(values);
|
||||
form.resetDirty();
|
||||
const [, canonicalLayouts] = await Promise.all([
|
||||
partialSettingsChanged
|
||||
? savePartialSettings.mutateAsync({ id: board.id, ...partialSettings }).then(() => {
|
||||
updateFavicon(values.faviconImageUrl ?? homarrLogoPath);
|
||||
})
|
||||
: Promise.resolve(),
|
||||
layoutsChanged ? saveLayouts.mutateAsync({ id: board.id, layouts }) : Promise.resolve(null),
|
||||
]);
|
||||
const canonicalValues = canonicalLayouts ? { ...values, layouts: canonicalLayouts } : values;
|
||||
|
||||
lastSavedRef.current = { pageTitle: canonicalValues.pageTitle, logoImageUrl: canonicalValues.logoImageUrl };
|
||||
initialValuesRef.current = canonicalValues;
|
||||
form.setValues(canonicalValues);
|
||||
form.setInitialValues(canonicalValues);
|
||||
form.resetDirty(canonicalValues);
|
||||
await revalidatePathActionAsync(`/boards/${board.name}/settings`);
|
||||
showSuccessNotification({
|
||||
title: t("common.notification.update.success"),
|
||||
message: t("common.notification.update.success"),
|
||||
});
|
||||
return canonicalValues;
|
||||
} catch {
|
||||
showErrorNotification({
|
||||
title: t("common.notification.update.error"),
|
||||
message: t("common.notification.update.error"),
|
||||
});
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -179,10 +183,15 @@ export const BoardSettingsForm = ({ board, permissions, hasFullAccess, hideVisib
|
||||
|
||||
return (
|
||||
<Stack gap="xl">
|
||||
<form onSubmit={form.onSubmit((values) => void handleSubmitAsync(values))}>
|
||||
<form onSubmit={form.onSubmit((values) => void saveSettingsAsync(values))}>
|
||||
<Stack gap="xl">
|
||||
<GeneralSettingsContent board={board} form={form} />
|
||||
<LayoutSettingsContent form={form} />
|
||||
<LayoutSettingsContent
|
||||
board={board}
|
||||
form={form}
|
||||
isSaving={isPending}
|
||||
saveSettingsAsync={() => saveSettingsAsync(form.values)}
|
||||
/>
|
||||
<BackgroundSettingsContent form={form} />
|
||||
<ColorSettingsContent form={form} />
|
||||
<CustomCssSettingsContent form={form} />
|
||||
|
||||
Reference in new issue
Block a user