From 92f70f5a03048c7b269604f1ce33313ecf23a64b Mon Sep 17 00:00:00 2001 From: Meier Lukas Date: Sun, 26 Jan 2025 22:37:48 +0100 Subject: [PATCH] feat(user): add search in new tab preference (#2125) --- apps/nextjs/package.json | 1 + apps/nextjs/src/app/[locale]/layout.tsx | 19 + ...ine.tsx => _change-search-preferences.tsx} | 31 +- .../manage/users/[userId]/general/page.tsx | 6 +- packages/api/src/router/user.ts | 85 +- .../router/user/change-search-preferences.ts | 50 + .../migrations/mysql/0021_fluffy_jocasta.sql | 1 + .../migrations/mysql/meta/0021_snapshot.json | 1708 +++++++++++++++++ .../db/migrations/mysql/meta/_journal.json | 7 + .../sqlite/0021_famous_bruce_banner.sql | 1 + .../migrations/sqlite/meta/0021_snapshot.json | 1633 ++++++++++++++++ .../db/migrations/sqlite/meta/_journal.json | 7 + packages/db/schema/mysql.ts | 1 + packages/db/schema/sqlite.ts | 1 + packages/settings/eslint.config.js | 9 + packages/settings/index.ts | 1 + packages/settings/package.json | 40 + packages/settings/src/context.tsx | 55 + packages/settings/tsconfig.json | 8 + packages/spotlight/package.json | 1 + .../external/search-engines-search-group.tsx | 13 +- .../modes/home/home-search-engine-group.tsx | 3 + packages/translation/src/lang/en.json | 14 +- packages/validation/src/user.ts | 7 +- packages/widgets/package.json | 1 + packages/widgets/src/app/ping/ping-dot.tsx | 4 +- packages/widgets/src/calendar/component.tsx | 3 +- pnpm-lock.yaml | 49 + 28 files changed, 3673 insertions(+), 86 deletions(-) rename apps/nextjs/src/app/[locale]/manage/users/[userId]/general/_components/{_change-default-search-engine.tsx => _change-search-preferences.tsx} (54%) create mode 100644 packages/api/src/router/user/change-search-preferences.ts create mode 100644 packages/db/migrations/mysql/0021_fluffy_jocasta.sql create mode 100644 packages/db/migrations/mysql/meta/0021_snapshot.json create mode 100644 packages/db/migrations/sqlite/0021_famous_bruce_banner.sql create mode 100644 packages/db/migrations/sqlite/meta/0021_snapshot.json create mode 100644 packages/settings/eslint.config.js create mode 100644 packages/settings/index.ts create mode 100644 packages/settings/package.json create mode 100644 packages/settings/src/context.tsx create mode 100644 packages/settings/tsconfig.json diff --git a/apps/nextjs/package.json b/apps/nextjs/package.json index 21f9616a7..6f226d808 100644 --- a/apps/nextjs/package.json +++ b/apps/nextjs/package.json @@ -36,6 +36,7 @@ "@homarr/old-schema": "workspace:^0.1.0", "@homarr/redis": "workspace:^0.1.0", "@homarr/server-settings": "workspace:^0.1.0", + "@homarr/settings": "workspace:^0.1.0", "@homarr/spotlight": "workspace:^0.1.0", "@homarr/translation": "workspace:^0.1.0", "@homarr/ui": "workspace:^0.1.0", diff --git a/apps/nextjs/src/app/[locale]/layout.tsx b/apps/nextjs/src/app/[locale]/layout.tsx index 8f145ee3c..1a04d8c7e 100644 --- a/apps/nextjs/src/app/[locale]/layout.tsx +++ b/apps/nextjs/src/app/[locale]/layout.tsx @@ -9,10 +9,14 @@ import "~/styles/scroll-area.scss"; import { notFound } from "next/navigation"; import { NextIntlClientProvider } from "next-intl"; +import { api } from "@homarr/api/server"; import { env } from "@homarr/auth/env"; import { auth } from "@homarr/auth/next"; +import { db } from "@homarr/db"; +import { getServerSettingsAsync } from "@homarr/db/queries"; import { ModalProvider } from "@homarr/modals"; import { Notifications } from "@homarr/notifications"; +import { SettingsProvider } from "@homarr/settings"; import { SpotlightProvider } from "@homarr/spotlight"; import type { SupportedLanguage } from "@homarr/translation"; import { isLocaleRTL, isLocaleSupported } from "@homarr/translation"; @@ -73,6 +77,8 @@ export default async function Layout(props: { } const session = await auth(); + const user = session ? await api.user.getById({ userId: session.user.id }).catch(() => null) : null; + const serverSettings = await getServerSettingsAsync(db); const colorScheme = await getCurrentColorSchemeAsync(); const direction = isLocaleRTL((await props.params).locale) ? "rtl" : "ltr"; const i18nMessages = await getI18nMessages(); @@ -81,6 +87,19 @@ export default async function Layout(props: { (innerProps) => { return ; }, + (innerProps) => ( + + ), (innerProps) => , (innerProps) => , (innerProps) => , diff --git a/apps/nextjs/src/app/[locale]/manage/users/[userId]/general/_components/_change-default-search-engine.tsx b/apps/nextjs/src/app/[locale]/manage/users/[userId]/general/_components/_change-search-preferences.tsx similarity index 54% rename from apps/nextjs/src/app/[locale]/manage/users/[userId]/general/_components/_change-default-search-engine.tsx rename to apps/nextjs/src/app/[locale]/manage/users/[userId]/general/_components/_change-search-preferences.tsx index 952014acb..5fabe8d4f 100644 --- a/apps/nextjs/src/app/[locale]/manage/users/[userId]/general/_components/_change-default-search-engine.tsx +++ b/apps/nextjs/src/app/[locale]/manage/users/[userId]/general/_components/_change-search-preferences.tsx @@ -1,6 +1,6 @@ "use client"; -import { Button, Group, Select, Stack } from "@mantine/core"; +import { Button, Group, Select, Stack, Switch } from "@mantine/core"; import type { z } from "zod"; import type { RouterOutputs } from "@homarr/api"; @@ -11,34 +11,36 @@ import { showErrorNotification, showSuccessNotification } from "@homarr/notifica import { useI18n } from "@homarr/translation/client"; import { validation } from "@homarr/validation"; -interface ChangeDefaultSearchEngineFormProps { +interface ChangeSearchPreferencesFormProps { user: RouterOutputs["user"]["getById"]; searchEnginesData: { value: string; label: string }[]; } -export const ChangeDefaultSearchEngineForm = ({ user, searchEnginesData }: ChangeDefaultSearchEngineFormProps) => { +export const ChangeSearchPreferencesForm = ({ user, searchEnginesData }: ChangeSearchPreferencesFormProps) => { const t = useI18n(); - const { mutate, isPending } = clientApi.user.changeDefaultSearchEngine.useMutation({ + const { mutate, isPending } = clientApi.user.changeSearchPreferences.useMutation({ async onSettled() { await revalidatePathActionAsync(`/manage/users/${user.id}`); }, onSuccess(_, variables) { form.setInitialValues({ defaultSearchEngineId: variables.defaultSearchEngineId, + openInNewTab: variables.openInNewTab, }); showSuccessNotification({ - message: t("user.action.changeDefaultSearchEngine.notification.success.message"), + message: t("user.action.changeSearchPreferences.notification.success.message"), }); }, onError() { showErrorNotification({ - message: t("user.action.changeDefaultSearchEngine.notification.error.message"), + message: t("user.action.changeSearchPreferences.notification.error.message"), }); }, }); - const form = useZodForm(validation.user.changeDefaultSearchEngine, { + const form = useZodForm(validation.user.changeSearchPreferences, { initialValues: { - defaultSearchEngineId: user.defaultSearchEngineId ?? "", + defaultSearchEngineId: user.defaultSearchEngineId, + openInNewTab: user.openSearchInNewTab, }, }); @@ -52,7 +54,16 @@ export const ChangeDefaultSearchEngineForm = ({ user, searchEnginesData }: Chang return (
- +