Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5b41d169c0 | ||
|
|
62b3c0aa5e | ||
|
|
a07e6a2188 | ||
|
|
c09f3e7501 |
No files matched your search
@@ -13,7 +13,7 @@ tags:
|
|||||||
The settings page applies options to the whole Homarr application.
|
The settings page applies options to the whole Homarr application.
|
||||||
Some changes need a full page reload before they take effect.
|
Some changes need a full page reload before they take effect.
|
||||||
|
|
||||||
All changes are collected in a single form. Click the **Save changes** button in the save bar at the bottom of the page to apply them. The save bar only appears when you have unsaved changes, and the **Discard** button reverts your changes.
|
All settings sections remain visible in a single form. Click the **Save changes** button in the save bar at the bottom of the page to apply them. The save bar only appears when you have unsaved changes, and the **Discard** button reverts your changes.
|
||||||
|
|
||||||
## Analytics
|
## Analytics
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ export const AppearanceSettingsForm = ({ form }: AppearanceSettingsFormProps) =>
|
|||||||
}))}
|
}))}
|
||||||
{...form.getInputProps("defaultColorScheme")}
|
{...form.getInputProps("defaultColorScheme")}
|
||||||
SelectOption={AppearanceCustomOption}
|
SelectOption={AppearanceCustomOption}
|
||||||
|
withinPortal
|
||||||
/>
|
/>
|
||||||
</SectionCard>
|
</SectionCard>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import { Switch, Text } from "@mantine/core";
|
import { Switch, Text } from "@mantine/core";
|
||||||
|
|
||||||
import { clientApi } from "@homarr/api/client";
|
import type { RouterOutputs } from "@homarr/api";
|
||||||
import type { UseFormReturnType } from "@homarr/form";
|
import type { UseFormReturnType } from "@homarr/form";
|
||||||
import { useScopedI18n } from "@homarr/translation/client";
|
import { useScopedI18n } from "@homarr/translation/client";
|
||||||
|
|
||||||
@@ -12,11 +12,11 @@ import type { FormValues } from "./settings-form";
|
|||||||
|
|
||||||
interface BoardSettingsFormProps {
|
interface BoardSettingsFormProps {
|
||||||
form: UseFormReturnType<FormValues>;
|
form: UseFormReturnType<FormValues>;
|
||||||
|
selectableBoards: RouterOutputs["board"]["getPublicBoards"];
|
||||||
}
|
}
|
||||||
|
|
||||||
export const BoardSettingsForm = ({ form }: BoardSettingsFormProps) => {
|
export const BoardSettingsForm = ({ form, selectableBoards }: BoardSettingsFormProps) => {
|
||||||
const tBoard = useScopedI18n("management.page.settings.section.board");
|
const tBoard = useScopedI18n("management.page.settings.section.board");
|
||||||
const [selectableBoards] = clientApi.board.getPublicBoards.useSuspenseQuery();
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SectionCard title={tBoard("title")}>
|
<SectionCard title={tBoard("title")}>
|
||||||
@@ -26,6 +26,7 @@ export const BoardSettingsForm = ({ form }: BoardSettingsFormProps) => {
|
|||||||
clearable
|
clearable
|
||||||
boards={selectableBoards}
|
boards={selectableBoards}
|
||||||
{...form.getInputProps("homeBoardId")}
|
{...form.getInputProps("homeBoardId")}
|
||||||
|
withinPortal
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<BoardSelect
|
<BoardSelect
|
||||||
@@ -34,6 +35,7 @@ export const BoardSettingsForm = ({ form }: BoardSettingsFormProps) => {
|
|||||||
clearable
|
clearable
|
||||||
boards={selectableBoards}
|
boards={selectableBoards}
|
||||||
{...form.getInputProps("mobileHomeBoardId")}
|
{...form.getInputProps("mobileHomeBoardId")}
|
||||||
|
withinPortal
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Text fw={500}>{tBoard("status.title")}</Text>
|
<Text fw={500}>{tBoard("status.title")}</Text>
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ export const CultureSettingsForm = ({ form }: CultureSettingsFormProps) => {
|
|||||||
label={tCulture("defaultLocale.label")}
|
label={tCulture("defaultLocale.label")}
|
||||||
{...localeInputProps}
|
{...localeInputProps}
|
||||||
value={localeInputProps.value as SupportedLanguage}
|
value={localeInputProps.value as SupportedLanguage}
|
||||||
|
withinPortal
|
||||||
/>
|
/>
|
||||||
</SectionCard>
|
</SectionCard>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import { Select } from "@mantine/core";
|
import { Select } from "@mantine/core";
|
||||||
|
|
||||||
import { clientApi } from "@homarr/api/client";
|
import type { RouterOutputs } from "@homarr/api";
|
||||||
import type { UseFormReturnType } from "@homarr/form";
|
import type { UseFormReturnType } from "@homarr/form";
|
||||||
import { useScopedI18n } from "@homarr/translation/client";
|
import { useScopedI18n } from "@homarr/translation/client";
|
||||||
|
|
||||||
@@ -11,11 +11,11 @@ import type { FormValues } from "./settings-form";
|
|||||||
|
|
||||||
interface SearchSettingsFormProps {
|
interface SearchSettingsFormProps {
|
||||||
form: UseFormReturnType<FormValues>;
|
form: UseFormReturnType<FormValues>;
|
||||||
|
selectableSearchEngines: RouterOutputs["searchEngine"]["getSelectable"];
|
||||||
}
|
}
|
||||||
|
|
||||||
export const SearchSettingsForm = ({ form }: SearchSettingsFormProps) => {
|
export const SearchSettingsForm = ({ form, selectableSearchEngines }: SearchSettingsFormProps) => {
|
||||||
const tSearch = useScopedI18n("management.page.settings.section.search");
|
const tSearch = useScopedI18n("management.page.settings.section.search");
|
||||||
const [selectableSearchEngines] = clientApi.searchEngine.getSelectable.useSuspenseQuery({ withIntegrations: false });
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SectionCard title={tSearch("title")}>
|
<SectionCard title={tSearch("title")}>
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { useEffect, useRef, useState } from "react";
|
|||||||
import { Button, Stack } from "@mantine/core";
|
import { Button, Stack } from "@mantine/core";
|
||||||
import { z } from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
|
|
||||||
|
import type { RouterOutputs } from "@homarr/api";
|
||||||
import { clientApi } from "@homarr/api/client";
|
import { clientApi } from "@homarr/api/client";
|
||||||
import { revalidatePathActionAsync } from "@homarr/common/client";
|
import { revalidatePathActionAsync } from "@homarr/common/client";
|
||||||
import { env } from "@homarr/common/env";
|
import { env } from "@homarr/common/env";
|
||||||
@@ -58,9 +59,11 @@ const buildInitialValues = (initialData: ServerSettings): FormValues => ({
|
|||||||
|
|
||||||
interface SettingsFormProps {
|
interface SettingsFormProps {
|
||||||
initialData: ServerSettings;
|
initialData: ServerSettings;
|
||||||
|
selectableBoards: RouterOutputs["board"]["getPublicBoards"];
|
||||||
|
selectableSearchEngines: RouterOutputs["searchEngine"]["getSelectable"];
|
||||||
}
|
}
|
||||||
|
|
||||||
export const SettingsForm = ({ initialData }: SettingsFormProps) => {
|
export const SettingsForm = ({ initialData, selectableBoards, selectableSearchEngines }: SettingsFormProps) => {
|
||||||
const t = useI18n();
|
const t = useI18n();
|
||||||
const tSettings = useScopedI18n("management.page.settings");
|
const tSettings = useScopedI18n("management.page.settings");
|
||||||
|
|
||||||
@@ -169,13 +172,13 @@ export const SettingsForm = ({ initialData }: SettingsFormProps) => {
|
|||||||
return (
|
return (
|
||||||
<form onSubmit={form.onSubmit((values) => void handleSubmitAsync(values))}>
|
<form onSubmit={form.onSubmit((values) => void handleSubmitAsync(values))}>
|
||||||
<Stack gap="xl">
|
<Stack gap="xl">
|
||||||
<AnalyticsSettings form={form} />
|
<BoardSettingsForm form={form} selectableBoards={selectableBoards} />
|
||||||
<CrawlingAndIndexingSettings form={form} />
|
|
||||||
<BoardSettingsForm form={form} />
|
|
||||||
<UserSettingsForm form={form} />
|
<UserSettingsForm form={form} />
|
||||||
<SearchSettingsForm form={form} />
|
<SearchSettingsForm form={form} selectableSearchEngines={selectableSearchEngines} />
|
||||||
<AppearanceSettingsForm form={form} />
|
<AppearanceSettingsForm form={form} />
|
||||||
<CultureSettingsForm form={form} />
|
<CultureSettingsForm form={form} />
|
||||||
|
<AnalyticsSettings form={form} />
|
||||||
|
<CrawlingAndIndexingSettings form={form} />
|
||||||
|
|
||||||
{form.isDirty() && (
|
{form.isDirty() && (
|
||||||
<UnsavedChangesBar>
|
<UnsavedChangesBar>
|
||||||
|
|||||||
@@ -23,12 +23,20 @@ export default async function SettingsPage() {
|
|||||||
notFound();
|
notFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
const serverSettings = await api.serverSettings.getAll();
|
const [serverSettings, selectableBoards, selectableSearchEngines, tSettings] = await Promise.all([
|
||||||
const tSettings = await getScopedI18n("management.page.settings");
|
api.serverSettings.getAll(),
|
||||||
|
api.board.getPublicBoards(),
|
||||||
|
api.searchEngine.getSelectable({ withIntegrations: false }),
|
||||||
|
getScopedI18n("management.page.settings"),
|
||||||
|
]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ManagePageLayout title={tSettings("title")}>
|
<ManagePageLayout title={tSettings("title")}>
|
||||||
<SettingsForm initialData={serverSettings} />
|
<SettingsForm
|
||||||
|
initialData={serverSettings}
|
||||||
|
selectableBoards={selectableBoards}
|
||||||
|
selectableSearchEngines={selectableSearchEngines}
|
||||||
|
/>
|
||||||
</ManagePageLayout>
|
</ManagePageLayout>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user