diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 46c605ec1..5e5810f49 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -31,6 +31,7 @@ body: label: Version description: What version of Homarr are you running? options: + - 1.14.0 - 1.13.1 - 1.13.0 - 1.12.0 diff --git a/apps/nextjs/package.json b/apps/nextjs/package.json index e793feb9e..a70e5cc62 100644 --- a/apps/nextjs/package.json +++ b/apps/nextjs/package.json @@ -6,7 +6,7 @@ "scripts": { "build": "pnpm with-env next build", "clean": "git clean -xdf .next .turbo node_modules", - "dev": "pnpm with-env next dev --turbopack", + "dev": "pnpm with-env next dev", "format": "prettier --check . --ignore-path ../../.gitignore", "lint": "eslint", "start": "pnpm with-env next start", @@ -48,21 +48,21 @@ "@homarr/ui": "workspace:^0.1.0", "@homarr/validation": "workspace:^0.1.0", "@homarr/widgets": "workspace:^0.1.0", - "@mantine/colors-generator": "^7.17.3", - "@mantine/core": "^7.17.3", - "@mantine/dropzone": "^7.17.3", - "@mantine/hooks": "^7.17.3", - "@mantine/modals": "^7.17.3", - "@mantine/tiptap": "^7.17.3", + "@mantine/colors-generator": "^7.17.4", + "@mantine/core": "^7.17.4", + "@mantine/dropzone": "^7.17.4", + "@mantine/hooks": "^7.17.4", + "@mantine/modals": "^7.17.4", + "@mantine/tiptap": "^7.17.4", "@million/lint": "1.0.14", "@tabler/icons-react": "^3.31.0", - "@tanstack/react-query": "^5.71.10", - "@tanstack/react-query-devtools": "^5.71.10", - "@tanstack/react-query-next-experimental": "^5.71.10", - "@trpc/client": "^11.0.2", - "@trpc/next": "^11.0.2", - "@trpc/react-query": "^11.0.2", - "@trpc/server": "^11.0.2", + "@tanstack/react-query": "^5.72.1", + "@tanstack/react-query-devtools": "^5.72.1", + "@tanstack/react-query-next-experimental": "^5.72.1", + "@trpc/client": "^11.0.4", + "@trpc/next": "^11.0.4", + "@trpc/react-query": "^11.0.4", + "@trpc/server": "^11.0.4", "@xterm/addon-canvas": "^0.7.0", "@xterm/addon-fit": "0.10.0", "@xterm/xterm": "^5.5.0", @@ -74,7 +74,7 @@ "glob": "^11.0.1", "jotai": "^2.12.2", "mantine-react-table": "2.0.0-beta.9", - "next": "15.2.4", + "next": "15.2.5", "postcss-preset-mantine": "^1.17.0", "prismjs": "^1.30.0", "react": "19.1.0", @@ -83,7 +83,7 @@ "react-simple-code-editor": "^0.14.1", "sass": "^1.86.3", "superjson": "2.2.2", - "swagger-ui-react": "^5.20.6", + "swagger-ui-react": "^5.20.7", "use-deep-compare-effect": "^1.8.1", "zod": "^3.24.2" }, @@ -95,12 +95,12 @@ "@types/node": "^22.14.0", "@types/prismjs": "^1.26.5", "@types/react": "19.1.0", - "@types/react-dom": "19.1.1", + "@types/react-dom": "19.1.2", "@types/swagger-ui-react": "^5.18.0", "concurrently": "^9.1.2", - "eslint": "^9.23.0", + "eslint": "^9.24.0", "node-loader": "^2.1.0", "prettier": "^3.5.3", - "typescript": "^5.8.2" + "typescript": "^5.8.3" } } diff --git a/apps/nextjs/src/app/[locale]/auth/invite/[id]/_registration-form.tsx b/apps/nextjs/src/app/[locale]/auth/invite/[id]/_registration-form.tsx index 3f2689234..034001c28 100644 --- a/apps/nextjs/src/app/[locale]/auth/invite/[id]/_registration-form.tsx +++ b/apps/nextjs/src/app/[locale]/auth/invite/[id]/_registration-form.tsx @@ -9,7 +9,7 @@ import { useZodForm } from "@homarr/form"; import { showErrorNotification, showSuccessNotification } from "@homarr/notifications"; import { useScopedI18n } from "@homarr/translation/client"; import { CustomPasswordInput } from "@homarr/ui"; -import { validation } from "@homarr/validation"; +import { userRegistrationSchema } from "@homarr/validation/user"; interface RegistrationFormProps { invite: { @@ -22,7 +22,7 @@ export const RegistrationForm = ({ invite }: RegistrationFormProps) => { const t = useScopedI18n("user"); const router = useRouter(); const { mutate, isPending } = clientApi.user.register.useMutation(); - const form = useZodForm(validation.user.registration, { + const form = useZodForm(userRegistrationSchema, { initialValues: { username: "", password: "", @@ -30,7 +30,7 @@ export const RegistrationForm = ({ invite }: RegistrationFormProps) => { }, }); - const handleSubmit = (values: z.infer) => { + const handleSubmit = (values: z.infer) => { mutate( { ...values, diff --git a/apps/nextjs/src/app/[locale]/auth/login/_login-form.tsx b/apps/nextjs/src/app/[locale]/auth/login/_login-form.tsx index 6a013101f..a494c42cb 100644 --- a/apps/nextjs/src/app/[locale]/auth/login/_login-form.tsx +++ b/apps/nextjs/src/app/[locale]/auth/login/_login-form.tsx @@ -13,7 +13,7 @@ import type { useForm } from "@homarr/form"; import { useZodForm } from "@homarr/form"; import { showErrorNotification, showSuccessNotification } from "@homarr/notifications"; import { useScopedI18n } from "@homarr/translation/client"; -import { validation } from "@homarr/validation"; +import { userSignInSchema } from "@homarr/validation/user"; interface LoginFormProps { providers: string[]; @@ -22,7 +22,7 @@ interface LoginFormProps { callbackUrl: string; } -const extendedValidation = validation.user.signIn.extend({ provider: z.enum(["credentials", "ldap"]) }); +const extendedValidation = userSignInSchema.extend({ provider: z.enum(["credentials", "ldap"]) }); export const LoginForm = ({ providers, oidcClientName, isOidcAutoLoginEnabled, callbackUrl }: LoginFormProps) => { const t = useScopedI18n("user"); diff --git a/apps/nextjs/src/app/[locale]/boards/(content)/_theme.tsx b/apps/nextjs/src/app/[locale]/boards/(content)/_theme.tsx index 76d68a6b3..27f3e9152 100644 --- a/apps/nextjs/src/app/[locale]/boards/(content)/_theme.tsx +++ b/apps/nextjs/src/app/[locale]/boards/(content)/_theme.tsx @@ -2,7 +2,7 @@ import type { PropsWithChildren } from "react"; import type { MantineColorsTuple } from "@mantine/core"; -import { colorsTuple, createTheme, darken, lighten, MantineProvider } from "@mantine/core"; +import { colorsTuple, createTheme, darken, lighten, MantineProvider, rem } from "@mantine/core"; import { useRequiredBoard } from "@homarr/boards/context"; import type { ColorScheme } from "@homarr/definitions"; @@ -24,6 +24,11 @@ export const BoardMantineProvider = ({ }, primaryColor: "primaryColor", autoContrast: true, + fontSizes: { + "2xl": rem(24), + "3xl": rem(28), + "4xl": rem(36), + }, }); return ( diff --git a/apps/nextjs/src/app/[locale]/boards/[name]/settings/_appereance.tsx b/apps/nextjs/src/app/[locale]/boards/[name]/settings/_appereance.tsx index b96d99a88..0da5fa64a 100644 --- a/apps/nextjs/src/app/[locale]/boards/[name]/settings/_appereance.tsx +++ b/apps/nextjs/src/app/[locale]/boards/[name]/settings/_appereance.tsx @@ -20,7 +20,7 @@ import { useDisclosure } from "@mantine/hooks"; import { useZodForm } from "@homarr/form"; import { useI18n } from "@homarr/translation/client"; -import { validation } from "@homarr/validation"; +import { boardSavePartialSettingsSchema } from "@homarr/validation/board"; import type { Board } from "../../_types"; import { generateColors } from "../../(content)/_theme"; @@ -35,7 +35,7 @@ const hexRegex = /^#[0-9a-fA-F]{6}$/; const progressPercentageLabel = (value: number) => `${value}%`; export const ColorSettingsContent = ({ board }: Props) => { - const form = useZodForm(validation.board.savePartialSettings, { + const form = useZodForm(boardSavePartialSettingsSchema, { initialValues: { primaryColor: board.primaryColor, secondaryColor: board.secondaryColor, diff --git a/apps/nextjs/src/app/[locale]/boards/[name]/settings/_background.tsx b/apps/nextjs/src/app/[locale]/boards/[name]/settings/_background.tsx index 9f790cf7c..1471ff26d 100644 --- a/apps/nextjs/src/app/[locale]/boards/[name]/settings/_background.tsx +++ b/apps/nextjs/src/app/[locale]/boards/[name]/settings/_background.tsx @@ -1,14 +1,18 @@ "use client"; -import { Button, Grid, Group, Stack, TextInput } from "@mantine/core"; +import { Autocomplete, Button, Center, Grid, Group, Popover, Stack, Text } from "@mantine/core"; +import { useDebouncedValue } from "@mantine/hooks"; +import { IconPhotoOff } from "@tabler/icons-react"; +import { clientApi } from "@homarr/api/client"; +import { useSession } from "@homarr/auth/client"; import { backgroundImageAttachments, backgroundImageRepeats, backgroundImageSizes } from "@homarr/definitions"; import { useZodForm } from "@homarr/form"; import type { TranslationObject } from "@homarr/translation"; import { useI18n } from "@homarr/translation/client"; import type { SelectItemWithDescriptionBadge } from "@homarr/ui"; import { SelectWithDescriptionBadge } from "@homarr/ui"; -import { validation } from "@homarr/validation"; +import { boardSavePartialSettingsSchema } from "@homarr/validation/board"; import type { Board } from "../../_types"; import { useSavePartialSettingsMutation } from "./_shared"; @@ -18,8 +22,9 @@ interface Props { } export const BackgroundSettingsContent = ({ board }: Props) => { const t = useI18n(); + const { data: session } = useSession(); const { mutate: savePartialSettings, isPending } = useSavePartialSettingsMutation(board); - const form = useZodForm(validation.board.savePartialSettings, { + const form = useZodForm(boardSavePartialSettingsSchema, { initialValues: { backgroundImageUrl: board.backgroundImageUrl ?? "", backgroundImageAttachment: board.backgroundImageAttachment, @@ -28,6 +33,16 @@ export const BackgroundSettingsContent = ({ board }: Props) => { }, }); + const [debouncedSearch] = useDebouncedValue(form.values.backgroundImageUrl, 200); + const medias = clientApi.media.getPaginated.useQuery({ + page: 1, + pageSize: 10, + includeFromAllUsers: true, + search: debouncedSearch ?? "", + }); + const images = medias.data?.items.filter((media) => media.contentType.startsWith("image/")) ?? []; + const imageMap = new Map(images.map((image) => [`/api/user-medias/${image.id}`, image])); + const backgroundImageAttachmentData = useBackgroundOptionData( "backgroundImageAttachment", backgroundImageAttachments, @@ -47,8 +62,56 @@ export const BackgroundSettingsContent = ({ board }: Props) => { - = 2 && ( + + +
+ +
+
+ + + +
+ ) + } + // We filter it on the server + filter={({ options }) => options} label={t("board.field.backgroundImageUrl.label")} + placeholder={`${t("board.field.backgroundImageUrl.placeholder")}...`} + renderOption={({ option }) => { + const current = imageMap.get(option.value); + if (!current) return null; + + return ( + + + + {current.name} + + {option.value} + + + + ); + }} + data={[ + { + group: t("board.field.backgroundImageUrl.group.your"), + items: images + .filter((media) => media.creatorId === session?.user.id) + .map((media) => `/api/user-medias/${media.id}`), + }, + { + group: t("board.field.backgroundImageUrl.group.other"), + items: images + .filter((media) => media.creatorId !== session?.user.id) + .map((media) => `/api/user-medias/${media.id}`), + }, + ]} {...form.getInputProps("backgroundImageUrl")} />
@@ -85,6 +148,21 @@ export const BackgroundSettingsContent = ({ board }: Props) => { ); }; +interface ImagePreviewProps { + src: string; + w: string | number; + h?: string | number; +} + +const ImagePreview = ({ src, w, h }: ImagePreviewProps) => { + if (!["/", "http://", "https://"].some((prefix) => src.startsWith(prefix))) { + return ; + } + + // eslint-disable-next-line @next/next/no-img-element + return preview image; +}; + type BackgroundImageKey = "backgroundImageAttachment" | "backgroundImageSize" | "backgroundImageRepeat"; type inferOptions = TranslationObject["board"]["field"][TKey]["option"]; diff --git a/apps/nextjs/src/app/[locale]/boards/[name]/settings/_general.tsx b/apps/nextjs/src/app/[locale]/boards/[name]/settings/_general.tsx index efa640f93..10d27037f 100644 --- a/apps/nextjs/src/app/[locale]/boards/[name]/settings/_general.tsx +++ b/apps/nextjs/src/app/[locale]/boards/[name]/settings/_general.tsx @@ -1,14 +1,14 @@ "use client"; import { useEffect, useRef } from "react"; -import { Button, Grid, Group, Loader, Stack, TextInput, Tooltip } from "@mantine/core"; +import { Button, Grid, Group, Loader, Stack, TextInput } from "@mantine/core"; import { useDebouncedValue, useDocumentTitle, useFavicon } from "@mantine/hooks"; -import { IconAlertTriangle } from "@tabler/icons-react"; import { useUpdateBoard } from "@homarr/boards/updater"; import { useZodForm } from "@homarr/form"; +import { IconPicker } from "@homarr/forms-collection"; import { useI18n } from "@homarr/translation/client"; -import { validation } from "@homarr/validation"; +import { boardSavePartialSettingsSchema } from "@homarr/validation/board"; import { createMetaTitle } from "~/metadata"; import type { Board } from "../../_types"; @@ -28,7 +28,7 @@ export const GeneralSettingsContent = ({ board }: Props) => { const { mutate: savePartialSettings, isPending } = useSavePartialSettingsMutation(board); const form = useZodForm( - validation.board.savePartialSettings + boardSavePartialSettingsSchema .pick({ pageTitle: true, logoImageUrl: true, @@ -52,9 +52,9 @@ export const GeneralSettingsContent = ({ board }: Props) => { }, ); + useLogoPreview(form.values.logoImageUrl); + useFaviconPreview(form.values.faviconImageUrl); const metaTitleStatus = useMetaTitlePreview(form.values.metaTitle); - const faviconStatus = useFaviconPreview(form.values.faviconImageUrl); - const logoStatus = useLogoPreview(form.values.logoImageUrl); // Cleanup for not applied changes of the page title and logo image URL useEffect(() => { @@ -94,24 +94,24 @@ export const GeneralSettingsContent = ({ board }: Props) => { } + rightSection={metaTitleStatus.isPending && } {...form.getInputProps("metaTitle")} /> - } - {...form.getInputProps("logoImageUrl")} + withAsterisk={false} /> - } - {...form.getInputProps("faviconImageUrl")} + withAsterisk={false} />
@@ -125,40 +125,16 @@ export const GeneralSettingsContent = ({ board }: Props) => { ); }; -const PendingOrInvalidIndicator = ({ isPending, isInvalid }: { isPending: boolean; isInvalid?: boolean }) => { - const t = useI18n(); - - if (isInvalid) { - return ( - - - - ); - } - - if (isPending) { - return ; - } - - return null; -}; - const useLogoPreview = (url: string | null) => { const { updateBoard } = useUpdateBoard(); const [logoDebounced] = useDebouncedValue(url ?? "", 500); useEffect(() => { - if (!logoDebounced.includes(".") && logoDebounced.length >= 1) return; updateBoard((previous) => ({ ...previous, logoImageUrl: logoDebounced.length >= 1 ? logoDebounced : null, })); }, [logoDebounced, updateBoard]); - - return { - isPending: (url ?? "") !== logoDebounced, - isInvalid: logoDebounced.length >= 1 && !logoDebounced.includes("."), - }; }; const useMetaTitlePreview = (title: string | null) => { @@ -170,16 +146,7 @@ const useMetaTitlePreview = (title: string | null) => { }; }; -const validFaviconExtensions = ["ico", "png", "svg", "gif"]; -const isValidUrl = (url: string) => - url.includes("/") && validFaviconExtensions.some((extension) => url.endsWith(`.${extension}`)); - const useFaviconPreview = (url: string | null) => { const [faviconDebounced] = useDebouncedValue(url ?? "", 500); - useFavicon(isValidUrl(faviconDebounced) ? faviconDebounced : ""); - - return { - isPending: (url ?? "") !== faviconDebounced, - isInvalid: faviconDebounced.length >= 1 && !isValidUrl(faviconDebounced), - }; + useFavicon(faviconDebounced); }; diff --git a/apps/nextjs/src/app/[locale]/boards/[name]/settings/_layout.tsx b/apps/nextjs/src/app/[locale]/boards/[name]/settings/_layout.tsx index 99c0a7f41..2c6661cde 100644 --- a/apps/nextjs/src/app/[locale]/boards/[name]/settings/_layout.tsx +++ b/apps/nextjs/src/app/[locale]/boards/[name]/settings/_layout.tsx @@ -6,7 +6,7 @@ import { clientApi } from "@homarr/api/client"; import { createId } from "@homarr/db/client"; import { useZodForm } from "@homarr/form"; import { useI18n } from "@homarr/translation/client"; -import { validation } from "@homarr/validation"; +import { boardSaveLayoutsSchema } from "@homarr/validation/board"; import type { Board } from "../../_types"; @@ -22,7 +22,7 @@ export const LayoutSettingsContent = ({ board }: Props) => { void utils.board.getHomeBoard.invalidate(); }, }); - const form = useZodForm(validation.board.saveLayouts.omit({ id: true }).required(), { + const form = useZodForm(boardSaveLayoutsSchema.omit({ id: true }).required(), { initialValues: { layouts: board.layouts, }, diff --git a/apps/nextjs/src/app/[locale]/init/_steps/group/init-group.tsx b/apps/nextjs/src/app/[locale]/init/_steps/group/init-group.tsx index 849891220..976a8848a 100644 --- a/apps/nextjs/src/app/[locale]/init/_steps/group/init-group.tsx +++ b/apps/nextjs/src/app/[locale]/init/_steps/group/init-group.tsx @@ -8,18 +8,18 @@ import { clientApi } from "@homarr/api/client"; import { revalidatePathActionAsync } from "@homarr/common/client"; import { useZodForm } from "@homarr/form"; import { useI18n } from "@homarr/translation/client"; -import { validation } from "@homarr/validation"; +import { groupCreateSchema } from "@homarr/validation/group"; export const InitGroup = () => { const t = useI18n(); const { mutateAsync } = clientApi.group.createInitialExternalGroup.useMutation(); - const form = useZodForm(validation.group.create, { + const form = useZodForm(groupCreateSchema, { initialValues: { name: "", }, }); - const handleSubmitAsync = async (values: z.infer) => { + const handleSubmitAsync = async (values: z.infer) => { await mutateAsync(values, { async onSuccess() { await revalidatePathActionAsync("/init"); diff --git a/apps/nextjs/src/app/[locale]/init/_steps/settings/init-settings.tsx b/apps/nextjs/src/app/[locale]/init/_steps/settings/init-settings.tsx index 3d40a4445..f83612f1a 100644 --- a/apps/nextjs/src/app/[locale]/init/_steps/settings/init-settings.tsx +++ b/apps/nextjs/src/app/[locale]/init/_steps/settings/init-settings.tsx @@ -12,13 +12,13 @@ import type { CheckboxProps } from "@homarr/form/types"; import { defaultServerSettings } from "@homarr/server-settings"; import type { TranslationObject } from "@homarr/translation"; import { useI18n, useScopedI18n } from "@homarr/translation/client"; -import { validation } from "@homarr/validation"; +import { settingsInitSchema } from "@homarr/validation/settings"; export const InitSettings = () => { const tSection = useScopedI18n("management.page.settings.section"); const t = useI18n(); const { mutateAsync } = clientApi.serverSettings.initSettings.useMutation(); - const form = useZodForm(validation.settings.init, { initialValues: defaultServerSettings }); + const form = useZodForm(settingsInitSchema, { initialValues: defaultServerSettings }); form.watch("analytics.enableGeneral", ({ value }) => { if (!value) { @@ -30,7 +30,7 @@ export const InitSettings = () => { } }); - const handleSubmitAsync = async (values: z.infer) => { + const handleSubmitAsync = async (values: z.infer) => { await mutateAsync(values, { async onSuccess() { await revalidatePathActionAsync("/init"); diff --git a/apps/nextjs/src/app/[locale]/init/_steps/user/init-user-form.tsx b/apps/nextjs/src/app/[locale]/init/_steps/user/init-user-form.tsx index 2dd2df722..5e43cbc32 100644 --- a/apps/nextjs/src/app/[locale]/init/_steps/user/init-user-form.tsx +++ b/apps/nextjs/src/app/[locale]/init/_steps/user/init-user-form.tsx @@ -10,13 +10,13 @@ import { useZodForm } from "@homarr/form"; import { showErrorNotification, showSuccessNotification } from "@homarr/notifications"; import { useScopedI18n } from "@homarr/translation/client"; import { CustomPasswordInput } from "@homarr/ui"; -import { validation } from "@homarr/validation"; +import { userInitSchema } from "@homarr/validation/user"; export const InitUserForm = () => { const t = useScopedI18n("user"); const tUser = useScopedI18n("init.step.user"); const { mutateAsync, isPending } = clientApi.user.initUser.useMutation(); - const form = useZodForm(validation.user.init, { + const form = useZodForm(userInitSchema, { initialValues: { username: "", password: "", @@ -74,4 +74,4 @@ export const InitUserForm = () => { ); }; -type FormType = z.infer; +type FormType = z.infer; diff --git a/apps/nextjs/src/app/[locale]/manage/apps/edit/[id]/_app-edit-form.tsx b/apps/nextjs/src/app/[locale]/manage/apps/edit/[id]/_app-edit-form.tsx index 61e3693d3..2dc13dc27 100644 --- a/apps/nextjs/src/app/[locale]/manage/apps/edit/[id]/_app-edit-form.tsx +++ b/apps/nextjs/src/app/[locale]/manage/apps/edit/[id]/_app-edit-form.tsx @@ -10,7 +10,7 @@ import { revalidatePathActionAsync } from "@homarr/common/client"; import { AppForm } from "@homarr/forms-collection"; import { showErrorNotification, showSuccessNotification } from "@homarr/notifications"; import { useI18n, useScopedI18n } from "@homarr/translation/client"; -import type { validation } from "@homarr/validation"; +import type { appManageSchema } from "@homarr/validation/app"; interface AppEditFormProps { app: RouterOutputs["app"]["byId"]; @@ -40,7 +40,7 @@ export const AppEditForm = ({ app }: AppEditFormProps) => { }); const handleSubmit = useCallback( - (values: z.infer) => { + (values: z.infer) => { mutate({ id: app.id, ...values, diff --git a/apps/nextjs/src/app/[locale]/manage/integrations/edit/[id]/_integration-edit-form.tsx b/apps/nextjs/src/app/[locale]/manage/integrations/edit/[id]/_integration-edit-form.tsx index dd15d0005..06fb662ec 100644 --- a/apps/nextjs/src/app/[locale]/manage/integrations/edit/[id]/_integration-edit-form.tsx +++ b/apps/nextjs/src/app/[locale]/manage/integrations/edit/[id]/_integration-edit-form.tsx @@ -14,7 +14,7 @@ import { convertIntegrationTestConnectionError } from "@homarr/integrations/clie import { useConfirmModal } from "@homarr/modals"; import { showErrorNotification, showSuccessNotification } from "@homarr/notifications"; import { useI18n } from "@homarr/translation/client"; -import { validation } from "@homarr/validation"; +import { integrationUpdateSchema } from "@homarr/validation/integration"; import { SecretCard } from "../../_components/secrets/integration-secret-card"; import { IntegrationSecretInput } from "../../_components/secrets/integration-secret-inputs"; @@ -32,7 +32,7 @@ export const EditIntegrationForm = ({ integration }: EditIntegrationForm) => { ) ?? getDefaultSecretKinds(integration.kind); const router = useRouter(); - const form = useZodForm(validation.integration.update.omit({ id: true }), { + const form = useZodForm(integrationUpdateSchema.omit({ id: true }), { initialValues: { name: integration.name, url: integration.url, @@ -141,4 +141,4 @@ export const EditIntegrationForm = ({ integration }: EditIntegrationForm) => { ); }; -type FormType = Omit, "id">; +type FormType = Omit, "id">; diff --git a/apps/nextjs/src/app/[locale]/manage/integrations/new/_integration-new-form.tsx b/apps/nextjs/src/app/[locale]/manage/integrations/new/_integration-new-form.tsx index ed93ba822..c795aed54 100644 --- a/apps/nextjs/src/app/[locale]/manage/integrations/new/_integration-new-form.tsx +++ b/apps/nextjs/src/app/[locale]/manage/integrations/new/_integration-new-form.tsx @@ -27,20 +27,21 @@ import { useZodForm } from "@homarr/form"; import { convertIntegrationTestConnectionError } from "@homarr/integrations/client"; import { showErrorNotification, showSuccessNotification } from "@homarr/notifications"; import { useI18n, useScopedI18n } from "@homarr/translation/client"; -import { validation } from "@homarr/validation"; +import { appHrefSchema } from "@homarr/validation/app"; +import { integrationCreateSchema } from "@homarr/validation/integration"; import { IntegrationSecretInput } from "../_components/secrets/integration-secret-inputs"; interface NewIntegrationFormProps { - searchParams: Partial> & { + searchParams: Partial> & { kind: IntegrationKind; }; } -const formSchema = validation.integration.create.omit({ kind: true }).and( +const formSchema = integrationCreateSchema.omit({ kind: true }).and( z.object({ createApp: z.boolean(), - appHref: validation.app.manage.shape.href, + appHref: appHrefSchema, }), ); diff --git a/apps/nextjs/src/app/[locale]/manage/integrations/new/page.tsx b/apps/nextjs/src/app/[locale]/manage/integrations/new/page.tsx index dba8e5c1f..deb544491 100644 --- a/apps/nextjs/src/app/[locale]/manage/integrations/new/page.tsx +++ b/apps/nextjs/src/app/[locale]/manage/integrations/new/page.tsx @@ -7,14 +7,14 @@ import type { IntegrationKind } from "@homarr/definitions"; import { getIntegrationName, integrationKinds } from "@homarr/definitions"; import { getScopedI18n } from "@homarr/translation/server"; import { IntegrationAvatar } from "@homarr/ui"; -import type { validation } from "@homarr/validation"; +import type { integrationCreateSchema } from "@homarr/validation/integration"; import { DynamicBreadcrumb } from "~/components/navigation/dynamic-breadcrumb"; import { NewIntegrationForm } from "./_integration-new-form"; interface NewIntegrationPageProps { searchParams: Promise< - Partial> & { + Partial> & { kind: IntegrationKind; } >; diff --git a/apps/nextjs/src/app/[locale]/manage/search-engines/_form.tsx b/apps/nextjs/src/app/[locale]/manage/search-engines/_form.tsx index c1bcaa225..e34f78dc5 100644 --- a/apps/nextjs/src/app/[locale]/manage/search-engines/_form.tsx +++ b/apps/nextjs/src/app/[locale]/manage/search-engines/_form.tsx @@ -12,9 +12,9 @@ import { useZodForm } from "@homarr/form"; import { IconPicker } from "@homarr/forms-collection"; import type { TranslationFunction } from "@homarr/translation"; import { useI18n } from "@homarr/translation/client"; -import { validation } from "@homarr/validation"; +import { searchEngineManageSchema } from "@homarr/validation/search-engine"; -type FormType = z.infer; +type FormType = z.infer; interface SearchEngineFormProps { submitButtonTranslation: (t: TranslationFunction) => string; @@ -30,7 +30,7 @@ export const SearchEngineForm = (props: SearchEngineFormProps) => { const [integrationData] = clientApi.integration.allThatSupportSearch.useSuspenseQuery(); - const form = useZodForm(validation.searchEngine.manage, { + const form = useZodForm(searchEngineManageSchema, { initialValues: initialValues ?? { name: "", short: "", diff --git a/apps/nextjs/src/app/[locale]/manage/search-engines/edit/[id]/_search-engine-edit-form.tsx b/apps/nextjs/src/app/[locale]/manage/search-engines/edit/[id]/_search-engine-edit-form.tsx index cc4c1eb79..dbd2b949d 100644 --- a/apps/nextjs/src/app/[locale]/manage/search-engines/edit/[id]/_search-engine-edit-form.tsx +++ b/apps/nextjs/src/app/[locale]/manage/search-engines/edit/[id]/_search-engine-edit-form.tsx @@ -10,7 +10,7 @@ import { revalidatePathActionAsync } from "@homarr/common/client"; import { showErrorNotification, showSuccessNotification } from "@homarr/notifications"; import type { TranslationFunction } from "@homarr/translation"; import { useScopedI18n } from "@homarr/translation/client"; -import type { validation } from "@homarr/validation"; +import type { searchEngineManageSchema } from "@homarr/validation/search-engine"; import { SearchEngineForm } from "../../_form"; @@ -41,7 +41,7 @@ export const SearchEngineEditForm = ({ searchEngine }: SearchEngineEditFormProps }); const handleSubmit = useCallback( - (values: z.infer) => { + (values: z.infer) => { mutate({ id: searchEngine.id, ...values, diff --git a/apps/nextjs/src/app/[locale]/manage/search-engines/new/_search-engine-new-form.tsx b/apps/nextjs/src/app/[locale]/manage/search-engines/new/_search-engine-new-form.tsx index b5824d3c1..5bd5a6ae1 100644 --- a/apps/nextjs/src/app/[locale]/manage/search-engines/new/_search-engine-new-form.tsx +++ b/apps/nextjs/src/app/[locale]/manage/search-engines/new/_search-engine-new-form.tsx @@ -9,7 +9,7 @@ import { revalidatePathActionAsync } from "@homarr/common/client"; import { showErrorNotification, showSuccessNotification } from "@homarr/notifications"; import type { TranslationFunction } from "@homarr/translation"; import { useScopedI18n } from "@homarr/translation/client"; -import type { validation } from "@homarr/validation"; +import type { searchEngineManageSchema } from "@homarr/validation/search-engine"; import { SearchEngineForm } from "../_form"; @@ -35,7 +35,7 @@ export const SearchEngineNewForm = () => { }); const handleSubmit = useCallback( - (values: z.infer) => { + (values: z.infer) => { mutate(values); }, [mutate], diff --git a/apps/nextjs/src/app/[locale]/manage/tools/certificates/_components/add-certificate.tsx b/apps/nextjs/src/app/[locale]/manage/tools/certificates/_components/add-certificate.tsx index 87aaa058f..d16c60248 100644 --- a/apps/nextjs/src/app/[locale]/manage/tools/certificates/_components/add-certificate.tsx +++ b/apps/nextjs/src/app/[locale]/manage/tools/certificates/_components/add-certificate.tsx @@ -10,7 +10,7 @@ import { useZodForm } from "@homarr/form"; import { createModal, useModalAction } from "@homarr/modals"; import { showErrorNotification, showSuccessNotification } from "@homarr/notifications"; import { useI18n } from "@homarr/translation/client"; -import { superRefineCertificateFile } from "@homarr/validation"; +import { superRefineCertificateFile } from "@homarr/validation/certificates"; export const AddCertificateButton = () => { const { openModal } = useModalAction(AddCertificateModal); diff --git a/apps/nextjs/src/app/[locale]/manage/users/[userId]/general/_components/_change-home-board.tsx b/apps/nextjs/src/app/[locale]/manage/users/[userId]/general/_components/_change-home-board.tsx index d544a3c8d..1ad8c30b2 100644 --- a/apps/nextjs/src/app/[locale]/manage/users/[userId]/general/_components/_change-home-board.tsx +++ b/apps/nextjs/src/app/[locale]/manage/users/[userId]/general/_components/_change-home-board.tsx @@ -9,7 +9,7 @@ import { revalidatePathActionAsync } from "@homarr/common/client"; import { useZodForm } from "@homarr/form"; import { showErrorNotification, showSuccessNotification } from "@homarr/notifications"; import { useI18n } from "@homarr/translation/client"; -import { validation } from "@homarr/validation"; +import { userChangeHomeBoardsSchema } from "@homarr/validation/user"; import type { Board } from "~/app/[locale]/boards/_types"; import { BoardSelect } from "~/components/board/board-select"; @@ -40,7 +40,7 @@ export const ChangeHomeBoardForm = ({ user, boardsData }: ChangeHomeBoardFormPro }); }, }); - const form = useZodForm(validation.user.changeHomeBoards, { + const form = useZodForm(userChangeHomeBoardsSchema, { initialValues: { homeBoardId: user.homeBoardId, mobileHomeBoardId: user.mobileHomeBoardId, @@ -82,4 +82,4 @@ export const ChangeHomeBoardForm = ({ user, boardsData }: ChangeHomeBoardFormPro ); }; -type FormType = z.infer; +type FormType = z.infer; diff --git a/apps/nextjs/src/app/[locale]/manage/users/[userId]/general/_components/_change-search-preferences.tsx b/apps/nextjs/src/app/[locale]/manage/users/[userId]/general/_components/_change-search-preferences.tsx index 5fabe8d4f..5a8a051bd 100644 --- a/apps/nextjs/src/app/[locale]/manage/users/[userId]/general/_components/_change-search-preferences.tsx +++ b/apps/nextjs/src/app/[locale]/manage/users/[userId]/general/_components/_change-search-preferences.tsx @@ -9,7 +9,7 @@ import { revalidatePathActionAsync } from "@homarr/common/client"; import { useZodForm } from "@homarr/form"; import { showErrorNotification, showSuccessNotification } from "@homarr/notifications"; import { useI18n } from "@homarr/translation/client"; -import { validation } from "@homarr/validation"; +import { userChangeSearchPreferencesSchema } from "@homarr/validation/user"; interface ChangeSearchPreferencesFormProps { user: RouterOutputs["user"]["getById"]; @@ -37,7 +37,7 @@ export const ChangeSearchPreferencesForm = ({ user, searchEnginesData }: ChangeS }); }, }); - const form = useZodForm(validation.user.changeSearchPreferences, { + const form = useZodForm(userChangeSearchPreferencesSchema, { initialValues: { defaultSearchEngineId: user.defaultSearchEngineId, openInNewTab: user.openSearchInNewTab, @@ -75,4 +75,4 @@ export const ChangeSearchPreferencesForm = ({ user, searchEnginesData }: ChangeS ); }; -type FormType = z.infer; +type FormType = z.infer; diff --git a/apps/nextjs/src/app/[locale]/manage/users/[userId]/general/_components/_first-day-of-week.tsx b/apps/nextjs/src/app/[locale]/manage/users/[userId]/general/_components/_first-day-of-week.tsx index 1b5c27dc2..d15379b76 100644 --- a/apps/nextjs/src/app/[locale]/manage/users/[userId]/general/_components/_first-day-of-week.tsx +++ b/apps/nextjs/src/app/[locale]/manage/users/[userId]/general/_components/_first-day-of-week.tsx @@ -12,7 +12,7 @@ import { revalidatePathActionAsync } from "@homarr/common/client"; import { useZodForm } from "@homarr/form"; import { showErrorNotification, showSuccessNotification } from "@homarr/notifications"; import { useI18n } from "@homarr/translation/client"; -import { validation } from "@homarr/validation"; +import { userFirstDayOfWeekSchema } from "@homarr/validation/user"; dayjs.extend(localeData); @@ -42,7 +42,7 @@ export const FirstDayOfWeek = ({ user }: FirstDayOfWeekProps) => { }); }, }); - const form = useZodForm(validation.user.firstDayOfWeek, { + const form = useZodForm(userFirstDayOfWeekSchema, { initialValues: { firstDayOfWeek: user.firstDayOfWeek as DayOfWeek, }, @@ -80,4 +80,4 @@ export const FirstDayOfWeek = ({ user }: FirstDayOfWeekProps) => { ); }; -type FormType = z.infer; +type FormType = z.infer; diff --git a/apps/nextjs/src/app/[locale]/manage/users/[userId]/general/_components/_ping-icons-enabled.tsx b/apps/nextjs/src/app/[locale]/manage/users/[userId]/general/_components/_ping-icons-enabled.tsx index ce34378e6..6c5010d52 100644 --- a/apps/nextjs/src/app/[locale]/manage/users/[userId]/general/_components/_ping-icons-enabled.tsx +++ b/apps/nextjs/src/app/[locale]/manage/users/[userId]/general/_components/_ping-icons-enabled.tsx @@ -9,7 +9,7 @@ import { revalidatePathActionAsync } from "@homarr/common/client"; import { useZodForm } from "@homarr/form"; import { showErrorNotification, showSuccessNotification } from "@homarr/notifications"; import { useI18n } from "@homarr/translation/client"; -import { validation } from "@homarr/validation"; +import { userPingIconsEnabledSchema } from "@homarr/validation/user"; interface PingIconsEnabledProps { user: RouterOutputs["user"]["getById"]; @@ -35,7 +35,7 @@ export const PingIconsEnabled = ({ user }: PingIconsEnabledProps) => { }); }, }); - const form = useZodForm(validation.user.pingIconsEnabled, { + const form = useZodForm(userPingIconsEnabledSchema, { initialValues: { pingIconsEnabled: user.pingIconsEnabled, }, @@ -66,4 +66,4 @@ export const PingIconsEnabled = ({ user }: PingIconsEnabledProps) => { ); }; -type FormType = z.infer; +type FormType = z.infer; diff --git a/apps/nextjs/src/app/[locale]/manage/users/[userId]/general/_components/_profile-form.tsx b/apps/nextjs/src/app/[locale]/manage/users/[userId]/general/_components/_profile-form.tsx index b2d5ab87e..f94458108 100644 --- a/apps/nextjs/src/app/[locale]/manage/users/[userId]/general/_components/_profile-form.tsx +++ b/apps/nextjs/src/app/[locale]/manage/users/[userId]/general/_components/_profile-form.tsx @@ -9,7 +9,7 @@ import { revalidatePathActionAsync } from "@homarr/common/client"; import { useZodForm } from "@homarr/form"; import { showErrorNotification, showSuccessNotification } from "@homarr/notifications"; import { useI18n } from "@homarr/translation/client"; -import { validation } from "@homarr/validation"; +import { userEditProfileSchema } from "@homarr/validation/user"; interface UserProfileFormProps { user: RouterOutputs["user"]["getById"]; @@ -43,7 +43,7 @@ export const UserProfileForm = ({ user }: UserProfileFormProps) => { }); }, }); - const form = useZodForm(validation.user.editProfile.omit({ id: true }), { + const form = useZodForm(userEditProfileSchema.omit({ id: true }), { initialValues: { name: user.name ?? "", email: user.email ?? "", diff --git a/apps/nextjs/src/app/[locale]/manage/users/[userId]/security/_components/_change-password-form.tsx b/apps/nextjs/src/app/[locale]/manage/users/[userId]/security/_components/_change-password-form.tsx index e8ea4e96c..9fac22f51 100644 --- a/apps/nextjs/src/app/[locale]/manage/users/[userId]/security/_components/_change-password-form.tsx +++ b/apps/nextjs/src/app/[locale]/manage/users/[userId]/security/_components/_change-password-form.tsx @@ -10,7 +10,7 @@ import { useZodForm } from "@homarr/form"; import { showErrorNotification, showSuccessNotification } from "@homarr/notifications"; import { useI18n } from "@homarr/translation/client"; import { CustomPasswordInput } from "@homarr/ui"; -import { validation } from "@homarr/validation"; +import { userChangePasswordSchema } from "@homarr/validation/user"; interface ChangePasswordFormProps { user: RouterOutputs["user"]["getById"]; @@ -34,7 +34,7 @@ export const ChangePasswordForm = ({ user }: ChangePasswordFormProps) => { }); }, }); - const form = useZodForm(validation.user.changePassword, { + const form = useZodForm(userChangePasswordSchema, { initialValues: { /* Require previous password if the current user want's to change his password */ previousPassword: session?.user.id === user.id ? "" : "_", diff --git a/apps/nextjs/src/app/[locale]/manage/users/create/_components/create-user-stepper.tsx b/apps/nextjs/src/app/[locale]/manage/users/create/_components/create-user-stepper.tsx index e848a8182..97eeb9ff0 100644 --- a/apps/nextjs/src/app/[locale]/manage/users/create/_components/create-user-stepper.tsx +++ b/apps/nextjs/src/app/[locale]/manage/users/create/_components/create-user-stepper.tsx @@ -27,8 +27,8 @@ import { useModalAction } from "@homarr/modals"; import { showErrorNotification } from "@homarr/notifications"; import { useI18n, useScopedI18n } from "@homarr/translation/client"; import { CustomPasswordInput, UserAvatar } from "@homarr/ui"; -import { validation } from "@homarr/validation"; -import { createCustomErrorParams } from "@homarr/validation/form"; +import { createCustomErrorParams } from "@homarr/validation/form/i18n"; +import { userPasswordSchema } from "@homarr/validation/user"; import { GroupSelectModal } from "~/components/access/group-select-modal"; import { StepperNavigationComponent } from "./stepper-navigation"; @@ -84,7 +84,7 @@ export const UserCreateStepperComponent = ({ initialGroups }: UserCreateStepperC const securityForm = useZodForm( z .object({ - password: validation.user.password, + password: userPasswordSchema, confirmPassword: z.string(), }) .refine((data) => data.password === data.confirmPassword, { diff --git a/apps/nextjs/src/app/[locale]/manage/users/groups/[id]/_rename-group-form.tsx b/apps/nextjs/src/app/[locale]/manage/users/groups/[id]/_rename-group-form.tsx index 407ee2429..23585056d 100644 --- a/apps/nextjs/src/app/[locale]/manage/users/groups/[id]/_rename-group-form.tsx +++ b/apps/nextjs/src/app/[locale]/manage/users/groups/[id]/_rename-group-form.tsx @@ -8,7 +8,7 @@ import { revalidatePathActionAsync } from "@homarr/common/client"; import { useZodForm } from "@homarr/form"; import { showErrorNotification, showSuccessNotification } from "@homarr/notifications"; import { useI18n } from "@homarr/translation/client"; -import { validation } from "@homarr/validation"; +import { groupUpdateSchema } from "@homarr/validation/group"; interface RenameGroupFormProps { group: { @@ -21,7 +21,7 @@ interface RenameGroupFormProps { export const RenameGroupForm = ({ group, disabled }: RenameGroupFormProps) => { const t = useI18n(); const { mutate, isPending } = clientApi.group.updateGroup.useMutation(); - const form = useZodForm(validation.group.update.pick({ name: true }), { + const form = useZodForm(groupUpdateSchema.pick({ name: true }), { initialValues: { name: group.name, }, diff --git a/apps/nextjs/src/app/[locale]/manage/users/groups/[id]/settings/_group-home-boards.tsx b/apps/nextjs/src/app/[locale]/manage/users/groups/[id]/settings/_group-home-boards.tsx index b64ad7a61..62c7e1989 100644 --- a/apps/nextjs/src/app/[locale]/manage/users/groups/[id]/settings/_group-home-boards.tsx +++ b/apps/nextjs/src/app/[locale]/manage/users/groups/[id]/settings/_group-home-boards.tsx @@ -6,7 +6,7 @@ import { clientApi } from "@homarr/api/client"; import { useZodForm } from "@homarr/form"; import { showErrorNotification, showSuccessNotification } from "@homarr/notifications"; import { useI18n } from "@homarr/translation/client"; -import { validation } from "@homarr/validation"; +import { groupSettingsSchema } from "@homarr/validation/group"; import { BoardSelect } from "~/components/board/board-select"; @@ -19,7 +19,7 @@ interface GroupHomeBoardsProps { export const GroupHomeBoards = ({ homeBoardId, mobileHomeBoardId, groupId }: GroupHomeBoardsProps) => { const t = useI18n(); const [availableBoards] = clientApi.board.getBoardsForGroup.useSuspenseQuery({ groupId }); - const form = useZodForm(validation.group.settings.pick({ homeBoardId: true, mobileHomeBoardId: true }), { + const form = useZodForm(groupSettingsSchema.pick({ homeBoardId: true, mobileHomeBoardId: true }), { initialValues: { homeBoardId, mobileHomeBoardId, diff --git a/apps/nextjs/src/app/[locale]/widgets/[kind]/_content.tsx b/apps/nextjs/src/app/[locale]/widgets/[kind]/_content.tsx index 362236300..37ba09d52 100644 --- a/apps/nextjs/src/app/[locale]/widgets/[kind]/_content.tsx +++ b/apps/nextjs/src/app/[locale]/widgets/[kind]/_content.tsx @@ -11,7 +11,7 @@ import { useModalAction } from "@homarr/modals"; import { showSuccessNotification } from "@homarr/notifications"; import { useSettings } from "@homarr/settings"; import { useScopedI18n } from "@homarr/translation/client"; -import type { BoardItemAdvancedOptions } from "@homarr/validation"; +import type { BoardItemAdvancedOptions } from "@homarr/validation/shared"; import { loadWidgetDynamic, reduceWidgetOptionsWithDefaultValues, widgetImports } from "@homarr/widgets"; import { WidgetError } from "@homarr/widgets/errors"; import { WidgetEditModal } from "@homarr/widgets/modals"; diff --git a/apps/nextjs/src/components/board/items/item-actions.tsx b/apps/nextjs/src/components/board/items/item-actions.tsx index 609cfa0aa..29b5615e2 100644 --- a/apps/nextjs/src/components/board/items/item-actions.tsx +++ b/apps/nextjs/src/components/board/items/item-actions.tsx @@ -1,7 +1,7 @@ import { useCallback } from "react"; import { useUpdateBoard } from "@homarr/boards/updater"; -import type { BoardItemAdvancedOptions } from "@homarr/validation"; +import type { BoardItemAdvancedOptions } from "@homarr/validation/shared"; import type { CreateItemInput } from "./actions/create-item"; import { createItemCallback } from "./actions/create-item"; diff --git a/apps/nextjs/src/components/board/modals/board-rename-modal.tsx b/apps/nextjs/src/components/board/modals/board-rename-modal.tsx index fafa334b0..c2f2e08e0 100644 --- a/apps/nextjs/src/components/board/modals/board-rename-modal.tsx +++ b/apps/nextjs/src/components/board/modals/board-rename-modal.tsx @@ -7,7 +7,7 @@ import { clientApi } from "@homarr/api/client"; import { useZodForm } from "@homarr/form"; import { createModal } from "@homarr/modals"; import { useI18n } from "@homarr/translation/client"; -import { validation } from "@homarr/validation"; +import { boardRenameSchema } from "@homarr/validation/board"; interface InnerProps { id: string; @@ -26,7 +26,7 @@ export const BoardRenameModal = createModal(({ actions, innerProps } void utils.board.getHomeBoard.invalidate(); }, }); - const form = useZodForm(validation.board.rename.omit({ id: true }), { + const form = useZodForm(boardRenameSchema.omit({ id: true }), { initialValues: { name: innerProps.previousName, }, @@ -66,4 +66,4 @@ export const BoardRenameModal = createModal(({ actions, innerProps } defaultTitle: (t) => t("board.setting.section.dangerZone.action.rename.modal.title"), }); -type FormType = Omit, "id">; +type FormType = Omit, "id">; diff --git a/apps/nextjs/src/components/board/sections/dynamic/dynamic-actions.ts b/apps/nextjs/src/components/board/sections/dynamic/dynamic-actions.ts index 324f4df1b..553172905 100644 --- a/apps/nextjs/src/components/board/sections/dynamic/dynamic-actions.ts +++ b/apps/nextjs/src/components/board/sections/dynamic/dynamic-actions.ts @@ -2,7 +2,7 @@ import { useCallback } from "react"; import type { z } from "zod"; import { useUpdateBoard } from "@homarr/boards/updater"; -import type { dynamicSectionOptionsSchema } from "@homarr/validation"; +import type { dynamicSectionOptionsSchema } from "@homarr/validation/shared"; import { addDynamicSectionCallback } from "./actions/add-dynamic-section"; import type { RemoveDynamicSectionInput } from "./actions/remove-dynamic-section"; diff --git a/apps/nextjs/src/components/board/sections/dynamic/dynamic-edit-modal.tsx b/apps/nextjs/src/components/board/sections/dynamic/dynamic-edit-modal.tsx index 85ffc7e79..3ce026800 100644 --- a/apps/nextjs/src/components/board/sections/dynamic/dynamic-edit-modal.tsx +++ b/apps/nextjs/src/components/board/sections/dynamic/dynamic-edit-modal.tsx @@ -6,7 +6,7 @@ import type { z } from "zod"; import { useZodForm } from "@homarr/form"; import { createModal } from "@homarr/modals"; import { useI18n } from "@homarr/translation/client"; -import { dynamicSectionOptionsSchema } from "@homarr/validation"; +import { dynamicSectionOptionsSchema } from "@homarr/validation/shared"; interface ModalProps { value: z.infer; diff --git a/apps/tasks/package.json b/apps/tasks/package.json index efbbbda5b..0c6efc00c 100644 --- a/apps/tasks/package.json +++ b/apps/tasks/package.json @@ -46,9 +46,9 @@ "@homarr/tsconfig": "workspace:^0.1.0", "@types/node": "^22.14.0", "dotenv-cli": "^8.0.0", - "eslint": "^9.23.0", + "eslint": "^9.24.0", "prettier": "^3.5.3", "tsx": "4.19.3", - "typescript": "^5.8.2" + "typescript": "^5.8.3" } } diff --git a/apps/websocket/package.json b/apps/websocket/package.json index 033bcf9b8..e643bca4a 100644 --- a/apps/websocket/package.json +++ b/apps/websocket/package.json @@ -34,8 +34,8 @@ "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", "@types/ws": "^8.18.1", - "eslint": "^9.23.0", + "eslint": "^9.24.0", "prettier": "^3.5.3", - "typescript": "^5.8.2" + "typescript": "^5.8.3" } } diff --git a/nginx.conf b/nginx.conf index dbfeba55a..e53f7b740 100644 --- a/nginx.conf +++ b/nginx.conf @@ -22,6 +22,7 @@ http { proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto; + client_max_body_size 32M; } } } \ No newline at end of file diff --git a/package.json b/package.json index d782248ff..f7b3c3c58 100644 --- a/package.json +++ b/package.json @@ -47,13 +47,13 @@ "jsdom": "^26.0.0", "prettier": "^3.5.3", "semantic-release": "^24.2.3", - "testcontainers": "^10.24.0", + "testcontainers": "^10.24.1", "turbo": "^2.5.0", - "typescript": "^5.8.2", + "typescript": "^5.8.3", "vite-tsconfig-paths": "^5.1.4", "vitest": "^3.1.1" }, - "packageManager": "pnpm@10.7.1", + "packageManager": "pnpm@10.8.0", "engines": { "node": ">=22.14.0" }, diff --git a/packages/analytics/package.json b/packages/analytics/package.json index 7b805f092..dd45047d7 100644 --- a/packages/analytics/package.json +++ b/packages/analytics/package.json @@ -32,7 +32,7 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.23.0", - "typescript": "^5.8.2" + "eslint": "^9.24.0", + "typescript": "^5.8.3" } } diff --git a/packages/api/package.json b/packages/api/package.json index 9699a24e4..7d574fb8d 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -40,12 +40,12 @@ "@homarr/request-handler": "workspace:^0.1.0", "@homarr/server-settings": "workspace:^0.1.0", "@homarr/validation": "workspace:^0.1.0", - "@kubernetes/client-node": "^1.1.1", - "@trpc/client": "^11.0.2", - "@trpc/react-query": "^11.0.2", - "@trpc/server": "^11.0.2", + "@kubernetes/client-node": "^1.1.2", + "@trpc/client": "^11.0.4", + "@trpc/react-query": "^11.0.4", + "@trpc/server": "^11.0.4", "lodash.clonedeep": "^4.5.0", - "next": "15.2.4", + "next": "15.2.5", "pretty-print-error": "^1.1.2", "react": "19.1.0", "react-dom": "19.1.0", @@ -57,8 +57,8 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.23.0", + "eslint": "^9.24.0", "prettier": "^3.5.3", - "typescript": "^5.8.2" + "typescript": "^5.8.3" } } diff --git a/packages/api/src/router/app.ts b/packages/api/src/router/app.ts index 6bd53c948..77b18b6b8 100644 --- a/packages/api/src/router/app.ts +++ b/packages/api/src/router/app.ts @@ -5,7 +5,8 @@ import { asc, createId, eq, inArray, like } from "@homarr/db"; import { apps } from "@homarr/db/schema"; import { selectAppSchema } from "@homarr/db/validationSchemas"; import { getIconForName } from "@homarr/icons"; -import { validation } from "@homarr/validation"; +import { appCreateManySchema, appEditSchema, appManageSchema } from "@homarr/validation/app"; +import { byIdSchema, paginatedSchema } from "@homarr/validation/common"; import { convertIntersectionToZodObject } from "../schema-merger"; import { createTRPCRouter, permissionRequiredProcedure, protectedProcedure, publicProcedure } from "../trpc"; @@ -15,7 +16,7 @@ const defaultIcon = "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@mas export const appRouter = createTRPCRouter({ getPaginated: protectedProcedure - .input(validation.common.paginated) + .input(paginatedSchema) .output(z.object({ items: z.array(selectAppSchema), totalCount: z.number() })) .meta({ openapi: { method: "GET", path: "/api/apps/paginated", tags: ["apps"], protect: true } }) .query(async ({ input, ctx }) => { @@ -83,7 +84,7 @@ export const appRouter = createTRPCRouter({ }); }), byId: publicProcedure - .input(validation.common.byId) + .input(byIdSchema) .output(selectAppSchema) .meta({ openapi: { method: "GET", path: "/api/apps/{id}", tags: ["apps"], protect: true } }) .query(async ({ ctx, input }) => { @@ -115,7 +116,7 @@ export const appRouter = createTRPCRouter({ }), create: permissionRequiredProcedure .requiresPermission("app-create") - .input(validation.app.manage) + .input(appManageSchema) .output(z.object({ appId: z.string() })) .meta({ openapi: { method: "POST", path: "/api/apps", tags: ["apps"], protect: true } }) .mutation(async ({ ctx, input }) => { @@ -133,7 +134,7 @@ export const appRouter = createTRPCRouter({ }), createMany: permissionRequiredProcedure .requiresPermission("app-create") - .input(validation.app.createMany) + .input(appCreateManySchema) .output(z.void()) .mutation(async ({ ctx, input }) => { await ctx.db.insert(apps).values( @@ -148,7 +149,7 @@ export const appRouter = createTRPCRouter({ }), update: permissionRequiredProcedure .requiresPermission("app-modify-all") - .input(convertIntersectionToZodObject(validation.app.edit)) + .input(convertIntersectionToZodObject(appEditSchema)) .output(z.void()) .meta({ openapi: { method: "PATCH", path: "/api/apps/{id}", tags: ["apps"], protect: true } }) .mutation(async ({ ctx, input }) => { @@ -178,7 +179,7 @@ export const appRouter = createTRPCRouter({ .requiresPermission("app-full-all") .output(z.void()) .meta({ openapi: { method: "DELETE", path: "/api/apps/{id}", tags: ["apps"], protect: true } }) - .input(validation.common.byId) + .input(byIdSchema) .mutation(async ({ ctx, input }) => { await ctx.db.delete(apps).where(eq(apps.id, input.id)); }), diff --git a/packages/api/src/router/board.ts b/packages/api/src/router/board.ts index 80e58393d..e8b096c09 100644 --- a/packages/api/src/router/board.ts +++ b/packages/api/src/router/board.ts @@ -37,8 +37,21 @@ import { import { importOldmarrAsync } from "@homarr/old-import"; import { importJsonFileSchema } from "@homarr/old-import/shared"; import { oldmarrConfigSchema } from "@homarr/old-schema"; -import type { BoardItemAdvancedOptions } from "@homarr/validation"; -import { sectionSchema, sharedItemSchema, validation, zodUnionFromArray } from "@homarr/validation"; +import { + boardByNameSchema, + boardChangeVisibilitySchema, + boardCreateSchema, + boardDuplicateSchema, + boardRenameSchema, + boardSaveLayoutsSchema, + boardSavePartialSettingsSchema, + boardSavePermissionsSchema, + boardSaveSchema, +} from "@homarr/validation/board"; +import { byIdSchema } from "@homarr/validation/common"; +import { zodUnionFromArray } from "@homarr/validation/enums"; +import type { BoardItemAdvancedOptions } from "@homarr/validation/shared"; +import { sectionSchema, sharedItemSchema } from "@homarr/validation/shared"; import { createTRPCRouter, permissionRequiredProcedure, protectedProcedure, publicProcedure } from "../trpc"; import { throwIfActionForbiddenAsync } from "./board/board-access"; @@ -247,7 +260,7 @@ export const boardRouter = createTRPCRouter({ }), createBoard: permissionRequiredProcedure .requiresPermission("board-create") - .input(validation.board.create) + .input(boardCreateSchema) .mutation(async ({ ctx, input }) => { const boardId = createId(); @@ -291,7 +304,7 @@ export const boardRouter = createTRPCRouter({ }), duplicateBoard: permissionRequiredProcedure .requiresPermission("board-create") - .input(validation.board.duplicate) + .input(boardDuplicateSchema) .mutation(async ({ ctx, input }) => { await throwIfActionForbiddenAsync(ctx, eq(boards.id, input.id), "view"); await noBoardWithSimilarNameAsync(ctx.db, input.name); @@ -506,34 +519,32 @@ export const boardRouter = createTRPCRouter({ }, }); }), - renameBoard: protectedProcedure.input(validation.board.rename).mutation(async ({ ctx, input }) => { + renameBoard: protectedProcedure.input(boardRenameSchema).mutation(async ({ ctx, input }) => { await throwIfActionForbiddenAsync(ctx, eq(boards.id, input.id), "full"); await noBoardWithSimilarNameAsync(ctx.db, input.name, [input.id]); await ctx.db.update(boards).set({ name: input.name }).where(eq(boards.id, input.id)); }), - changeBoardVisibility: protectedProcedure - .input(validation.board.changeVisibility) - .mutation(async ({ ctx, input }) => { - await throwIfActionForbiddenAsync(ctx, eq(boards.id, input.id), "full"); - const boardSettings = await getServerSettingByKeyAsync(ctx.db, "board"); + changeBoardVisibility: protectedProcedure.input(boardChangeVisibilitySchema).mutation(async ({ ctx, input }) => { + await throwIfActionForbiddenAsync(ctx, eq(boards.id, input.id), "full"); + const boardSettings = await getServerSettingByKeyAsync(ctx.db, "board"); - if ( - input.visibility !== "public" && - (boardSettings.homeBoardId === input.id || boardSettings.mobileHomeBoardId === input.id) - ) { - throw new TRPCError({ - code: "BAD_REQUEST", - message: "Cannot make home board private", - }); - } + if ( + input.visibility !== "public" && + (boardSettings.homeBoardId === input.id || boardSettings.mobileHomeBoardId === input.id) + ) { + throw new TRPCError({ + code: "BAD_REQUEST", + message: "Cannot make home board private", + }); + } - await ctx.db - .update(boards) - .set({ isPublic: input.visibility === "public" }) - .where(eq(boards.id, input.id)); - }), + await ctx.db + .update(boards) + .set({ isPublic: input.visibility === "public" }) + .where(eq(boards.id, input.id)); + }), deleteBoard: protectedProcedure.input(z.object({ id: z.string() })).mutation(async ({ ctx, input }) => { await throwIfActionForbiddenAsync(ctx, eq(boards.id, input.id), "full"); @@ -572,13 +583,13 @@ export const boardRouter = createTRPCRouter({ return await getFullBoardWithWhereAsync(ctx.db, boardWhere, ctx.session?.user.id ?? null); }), - getBoardByName: publicProcedure.input(validation.board.byName).query(async ({ input, ctx }) => { + getBoardByName: publicProcedure.input(boardByNameSchema).query(async ({ input, ctx }) => { const boardWhere = eq(sql`UPPER(${boards.name})`, input.name.toUpperCase()); await throwIfActionForbiddenAsync(ctx, boardWhere, "view"); return await getFullBoardWithWhereAsync(ctx.db, boardWhere, ctx.session?.user.id ?? null); }), - saveLayouts: protectedProcedure.input(validation.board.saveLayouts).mutation(async ({ ctx, input }) => { + saveLayouts: protectedProcedure.input(boardSaveLayoutsSchema).mutation(async ({ ctx, input }) => { await throwIfActionForbiddenAsync(ctx, eq(boards.id, input.id), "modify"); const board = await getFullBoardWithWhereAsync(ctx.db, eq(boards.id, input.id), ctx.session.user.id); @@ -704,7 +715,7 @@ export const boardRouter = createTRPCRouter({ } }), savePartialBoardSettings: protectedProcedure - .input(validation.board.savePartialSettings.and(z.object({ id: z.string() }))) + .input(boardSavePartialSettingsSchema.and(z.object({ id: z.string() }))) .mutation(async ({ ctx, input }) => { await throwIfActionForbiddenAsync(ctx, eq(boards.id, input.id), "modify"); @@ -738,7 +749,7 @@ export const boardRouter = createTRPCRouter({ }) .where(eq(boards.id, input.id)); }), - saveBoard: protectedProcedure.input(validation.board.save).mutation(async ({ input, ctx }) => { + saveBoard: protectedProcedure.input(boardSaveSchema).mutation(async ({ input, ctx }) => { await throwIfActionForbiddenAsync(ctx, eq(boards.id, input.id), "modify"); const dbBoard = await getFullBoardWithWhereAsync(ctx.db, eq(boards.id, input.id), ctx.session.user.id); @@ -1154,8 +1165,7 @@ export const boardRouter = createTRPCRouter({ }, }); }), - - getBoardPermissions: protectedProcedure.input(validation.board.permissions).query(async ({ input, ctx }) => { + getBoardPermissions: protectedProcedure.input(byIdSchema).query(async ({ input, ctx }) => { await throwIfActionForbiddenAsync(ctx, eq(boards.id, input.id), "full"); const dbGroupPermissions = await ctx.db.query.groupPermissions.findMany({ @@ -1226,92 +1236,86 @@ export const boardRouter = createTRPCRouter({ }), }; }), - saveUserBoardPermissions: protectedProcedure - .input(validation.board.savePermissions) - .mutation(async ({ input, ctx }) => { - await throwIfActionForbiddenAsync(ctx, eq(boards.id, input.entityId), "full"); + saveUserBoardPermissions: protectedProcedure.input(boardSavePermissionsSchema).mutation(async ({ input, ctx }) => { + await throwIfActionForbiddenAsync(ctx, eq(boards.id, input.entityId), "full"); - await handleTransactionsAsync(ctx.db, { - async handleAsync(db, schema) { - await db.transaction(async (transaction) => { - await transaction - .delete(schema.boardUserPermissions) - .where(eq(boardUserPermissions.boardId, input.entityId)); - if (input.permissions.length === 0) { - return; - } - await transaction.insert(schema.boardUserPermissions).values( + await handleTransactionsAsync(ctx.db, { + async handleAsync(db, schema) { + await db.transaction(async (transaction) => { + await transaction.delete(schema.boardUserPermissions).where(eq(boardUserPermissions.boardId, input.entityId)); + if (input.permissions.length === 0) { + return; + } + await transaction.insert(schema.boardUserPermissions).values( + input.permissions.map((permission) => ({ + userId: permission.principalId, + permission: permission.permission, + boardId: input.entityId, + })), + ); + }); + }, + handleSync(db) { + db.transaction((transaction) => { + transaction.delete(boardUserPermissions).where(eq(boardUserPermissions.boardId, input.entityId)).run(); + if (input.permissions.length === 0) { + return; + } + transaction + .insert(boardUserPermissions) + .values( input.permissions.map((permission) => ({ userId: permission.principalId, permission: permission.permission, boardId: input.entityId, })), - ); - }); - }, - handleSync(db) { - db.transaction((transaction) => { - transaction.delete(boardUserPermissions).where(eq(boardUserPermissions.boardId, input.entityId)).run(); - if (input.permissions.length === 0) { - return; - } - transaction - .insert(boardUserPermissions) - .values( - input.permissions.map((permission) => ({ - userId: permission.principalId, - permission: permission.permission, - boardId: input.entityId, - })), - ) - .run(); - }); - }, - }); - }), - saveGroupBoardPermissions: protectedProcedure - .input(validation.board.savePermissions) - .mutation(async ({ input, ctx }) => { - await throwIfActionForbiddenAsync(ctx, eq(boards.id, input.entityId), "full"); + ) + .run(); + }); + }, + }); + }), + saveGroupBoardPermissions: protectedProcedure.input(boardSavePermissionsSchema).mutation(async ({ input, ctx }) => { + await throwIfActionForbiddenAsync(ctx, eq(boards.id, input.entityId), "full"); - await handleTransactionsAsync(ctx.db, { - async handleAsync(db, schema) { - await db.transaction(async (transaction) => { - await transaction - .delete(schema.boardGroupPermissions) - .where(eq(boardGroupPermissions.boardId, input.entityId)); - if (input.permissions.length === 0) { - return; - } - await transaction.insert(schema.boardGroupPermissions).values( + await handleTransactionsAsync(ctx.db, { + async handleAsync(db, schema) { + await db.transaction(async (transaction) => { + await transaction + .delete(schema.boardGroupPermissions) + .where(eq(boardGroupPermissions.boardId, input.entityId)); + if (input.permissions.length === 0) { + return; + } + await transaction.insert(schema.boardGroupPermissions).values( + input.permissions.map((permission) => ({ + groupId: permission.principalId, + permission: permission.permission, + boardId: input.entityId, + })), + ); + }); + }, + handleSync(db) { + db.transaction((transaction) => { + transaction.delete(boardGroupPermissions).where(eq(boardGroupPermissions.boardId, input.entityId)).run(); + if (input.permissions.length === 0) { + return; + } + transaction + .insert(boardGroupPermissions) + .values( input.permissions.map((permission) => ({ groupId: permission.principalId, permission: permission.permission, boardId: input.entityId, })), - ); - }); - }, - handleSync(db) { - db.transaction((transaction) => { - transaction.delete(boardGroupPermissions).where(eq(boardGroupPermissions.boardId, input.entityId)).run(); - if (input.permissions.length === 0) { - return; - } - transaction - .insert(boardGroupPermissions) - .values( - input.permissions.map((permission) => ({ - groupId: permission.principalId, - permission: permission.permission, - boardId: input.entityId, - })), - ) - .run(); - }); - }, - }); - }), + ) + .run(); + }); + }, + }); + }), importOldmarrConfig: permissionRequiredProcedure .requiresPermission("board-create") .input(importJsonFileSchema) diff --git a/packages/api/src/router/certificates/certificate-router.ts b/packages/api/src/router/certificates/certificate-router.ts index d50150c80..96d638f70 100644 --- a/packages/api/src/router/certificates/certificate-router.ts +++ b/packages/api/src/router/certificates/certificate-router.ts @@ -2,7 +2,7 @@ import { z } from "zod"; import { zfd } from "zod-form-data"; import { addCustomRootCertificateAsync, removeCustomRootCertificateAsync } from "@homarr/certificates/server"; -import { superRefineCertificateFile, validation } from "@homarr/validation"; +import { certificateValidFileNameSchema, superRefineCertificateFile } from "@homarr/validation/certificates"; import { createTRPCRouter, permissionRequiredProcedure } from "../../trpc"; @@ -20,7 +20,7 @@ export const certificateRouter = createTRPCRouter({ }), removeCertificate: permissionRequiredProcedure .requiresPermission("admin") - .input(z.object({ fileName: validation.certificates.validFileNameSchema })) + .input(z.object({ fileName: certificateValidFileNameSchema })) .mutation(async ({ input }) => { await removeCustomRootCertificateAsync(input.fileName); }), diff --git a/packages/api/src/router/group.ts b/packages/api/src/router/group.ts index 36fa8ba3d..3407b066a 100644 --- a/packages/api/src/router/group.ts +++ b/packages/api/src/router/group.ts @@ -6,7 +6,15 @@ import { and, createId, eq, handleTransactionsAsync, like, not } from "@homarr/d import { getMaxGroupPositionAsync } from "@homarr/db/queries"; import { groupMembers, groupPermissions, groups } from "@homarr/db/schema"; import { everyoneGroup } from "@homarr/definitions"; -import { validation } from "@homarr/validation"; +import { byIdSchema, paginatedSchema } from "@homarr/validation/common"; +import { + groupCreateSchema, + groupSavePartialSettingsSchema, + groupSavePermissionsSchema, + groupSavePositionsSchema, + groupUpdateSchema, + groupUserSchema, +} from "@homarr/validation/group"; import { createTRPCRouter, onboardingProcedure, permissionRequiredProcedure, protectedProcedure } from "../trpc"; import { throwIfCredentialsDisabled } from "./invite/checks"; @@ -39,7 +47,7 @@ export const groupRouter = createTRPCRouter({ getPaginated: permissionRequiredProcedure .requiresPermission("admin") - .input(validation.common.paginated) + .input(paginatedSchema) .query(async ({ input, ctx }) => { const whereQuery = input.search ? like(groups.name, `%${input.search.trim()}%`) : undefined; const groupCount = await ctx.db.$count(groups, whereQuery); @@ -74,7 +82,7 @@ export const groupRouter = createTRPCRouter({ }), getById: permissionRequiredProcedure .requiresPermission("admin") - .input(validation.common.byId) + .input(byIdSchema) .query(async ({ input, ctx }) => { const group = await ctx.db.query.groups.findFirst({ where: eq(groups.id, input.id), @@ -169,7 +177,7 @@ export const groupRouter = createTRPCRouter({ }), createInitialExternalGroup: onboardingProcedure .requiresStep("group") - .input(validation.group.create) + .input(groupCreateSchema) .mutation(async ({ input, ctx }) => { await checkSimilarNameAndThrowAsync(ctx.db, input.name); @@ -191,7 +199,7 @@ export const groupRouter = createTRPCRouter({ }), createGroup: permissionRequiredProcedure .requiresPermission("admin") - .input(validation.group.create) + .input(groupCreateSchema) .mutation(async ({ input, ctx }) => { await checkSimilarNameAndThrowAsync(ctx.db, input.name); @@ -209,7 +217,7 @@ export const groupRouter = createTRPCRouter({ }), updateGroup: permissionRequiredProcedure .requiresPermission("admin") - .input(validation.group.update) + .input(groupUpdateSchema) .mutation(async ({ input, ctx }) => { await throwIfGroupNotFoundAsync(ctx.db, input.id); await throwIfGroupNameIsReservedAsync(ctx.db, input.id); @@ -225,7 +233,7 @@ export const groupRouter = createTRPCRouter({ }), savePartialSettings: permissionRequiredProcedure .requiresPermission("admin") - .input(validation.group.savePartialSettings) + .input(groupSavePartialSettingsSchema) .mutation(async ({ input, ctx }) => { await throwIfGroupNotFoundAsync(ctx.db, input.id); @@ -239,7 +247,7 @@ export const groupRouter = createTRPCRouter({ }), savePositions: permissionRequiredProcedure .requiresPermission("admin") - .input(validation.group.savePositions) + .input(groupSavePositionsSchema) .mutation(async ({ input, ctx }) => { const positions = input.positions.map((id, index) => ({ id, position: index + 1 })); @@ -262,7 +270,7 @@ export const groupRouter = createTRPCRouter({ }), savePermissions: permissionRequiredProcedure .requiresPermission("admin") - .input(validation.group.savePermissions) + .input(groupSavePermissionsSchema) .mutation(async ({ input, ctx }) => { await throwIfGroupNotFoundAsync(ctx.db, input.groupId); @@ -277,7 +285,7 @@ export const groupRouter = createTRPCRouter({ }), transferOwnership: permissionRequiredProcedure .requiresPermission("admin") - .input(validation.group.groupUser) + .input(groupUserSchema) .mutation(async ({ input, ctx }) => { await throwIfGroupNotFoundAsync(ctx.db, input.groupId); await throwIfGroupNameIsReservedAsync(ctx.db, input.groupId); @@ -291,7 +299,7 @@ export const groupRouter = createTRPCRouter({ }), deleteGroup: permissionRequiredProcedure .requiresPermission("admin") - .input(validation.common.byId) + .input(byIdSchema) .mutation(async ({ input, ctx }) => { await throwIfGroupNotFoundAsync(ctx.db, input.id); await throwIfGroupNameIsReservedAsync(ctx.db, input.id); @@ -300,7 +308,7 @@ export const groupRouter = createTRPCRouter({ }), addMember: permissionRequiredProcedure .requiresPermission("admin") - .input(validation.group.groupUser) + .input(groupUserSchema) .mutation(async ({ input, ctx }) => { await throwIfGroupNotFoundAsync(ctx.db, input.groupId); await throwIfGroupNameIsReservedAsync(ctx.db, input.groupId); @@ -324,7 +332,7 @@ export const groupRouter = createTRPCRouter({ }), removeMember: permissionRequiredProcedure .requiresPermission("admin") - .input(validation.group.groupUser) + .input(groupUserSchema) .mutation(async ({ input, ctx }) => { await throwIfGroupNotFoundAsync(ctx.db, input.groupId); await throwIfGroupNameIsReservedAsync(ctx.db, input.groupId); diff --git a/packages/api/src/router/icons.ts b/packages/api/src/router/icons.ts index 4a3b33051..04f15fc2d 100644 --- a/packages/api/src/router/icons.ts +++ b/packages/api/src/router/icons.ts @@ -1,11 +1,11 @@ import { and, like } from "@homarr/db"; import { icons } from "@homarr/db/schema"; -import { validation } from "@homarr/validation"; +import { iconsFindSchema } from "@homarr/validation/icons"; import { createTRPCRouter, publicProcedure } from "../trpc"; export const iconsRouter = createTRPCRouter({ - findIcons: publicProcedure.input(validation.icons.findIcons).query(async ({ ctx, input }) => { + findIcons: publicProcedure.input(iconsFindSchema).query(async ({ ctx, input }) => { return { icons: await ctx.db.query.iconRepositories.findMany({ with: { diff --git a/packages/api/src/router/integration/integration-router.ts b/packages/api/src/router/integration/integration-router.ts index e133e2b9c..014ca1429 100644 --- a/packages/api/src/router/integration/integration-router.ts +++ b/packages/api/src/router/integration/integration-router.ts @@ -24,7 +24,12 @@ import { integrationSecretKindObject, } from "@homarr/definitions"; import { createIntegrationAsync } from "@homarr/integrations"; -import { validation } from "@homarr/validation"; +import { byIdSchema } from "@homarr/validation/common"; +import { + integrationCreateSchema, + integrationSavePermissionsSchema, + integrationUpdateSchema, +} from "@homarr/validation/integration"; import { createOneIntegrationMiddleware } from "../../middlewares/integration"; import { createTRPCRouter, permissionRequiredProcedure, protectedProcedure, publicProcedure } from "../../trpc"; @@ -141,7 +146,7 @@ export const integrationRouter = createTRPCRouter({ }, }); }), - byId: protectedProcedure.input(validation.integration.byId).query(async ({ ctx, input }) => { + byId: protectedProcedure.input(byIdSchema).query(async ({ ctx, input }) => { await throwIfActionForbiddenAsync(ctx, eq(integrations.id, input.id), "full"); const integration = await ctx.db.query.integrations.findFirst({ where: eq(integrations.id, input.id), @@ -178,7 +183,7 @@ export const integrationRouter = createTRPCRouter({ }), create: permissionRequiredProcedure .requiresPermission("integration-create") - .input(validation.integration.create) + .input(integrationCreateSchema) .mutation(async ({ ctx, input }) => { await testConnectionAsync({ id: "new", @@ -221,7 +226,7 @@ export const integrationRouter = createTRPCRouter({ }); } }), - update: protectedProcedure.input(validation.integration.update).mutation(async ({ ctx, input }) => { + update: protectedProcedure.input(integrationUpdateSchema).mutation(async ({ ctx, input }) => { await throwIfActionForbiddenAsync(ctx, eq(integrations.id, input.id), "full"); const integration = await ctx.db.query.integrations.findFirst({ @@ -282,7 +287,7 @@ export const integrationRouter = createTRPCRouter({ } } }), - delete: protectedProcedure.input(validation.integration.delete).mutation(async ({ ctx, input }) => { + delete: protectedProcedure.input(byIdSchema).mutation(async ({ ctx, input }) => { await throwIfActionForbiddenAsync(ctx, eq(integrations.id, input.id), "full"); const integration = await ctx.db.query.integrations.findFirst({ @@ -298,7 +303,7 @@ export const integrationRouter = createTRPCRouter({ await ctx.db.delete(integrations).where(eq(integrations.id, input.id)); }), - getIntegrationPermissions: protectedProcedure.input(validation.board.permissions).query(async ({ input, ctx }) => { + getIntegrationPermissions: protectedProcedure.input(byIdSchema).query(async ({ input, ctx }) => { await throwIfActionForbiddenAsync(ctx, eq(integrations.id, input.id), "full"); const dbGroupPermissions = await ctx.db.query.groupPermissions.findMany({ @@ -370,7 +375,7 @@ export const integrationRouter = createTRPCRouter({ }; }), saveUserIntegrationPermissions: protectedProcedure - .input(validation.integration.savePermissions) + .input(integrationSavePermissionsSchema) .mutation(async ({ input, ctx }) => { await throwIfActionForbiddenAsync(ctx, eq(integrations.id, input.entityId), "full"); @@ -416,7 +421,7 @@ export const integrationRouter = createTRPCRouter({ }); }), saveGroupIntegrationPermissions: protectedProcedure - .input(validation.integration.savePermissions) + .input(integrationSavePermissionsSchema) .mutation(async ({ input, ctx }) => { await throwIfActionForbiddenAsync(ctx, eq(integrations.id, input.entityId), "full"); diff --git a/packages/api/src/router/location.ts b/packages/api/src/router/location.ts index 7d3f3d980..5ecae7db6 100644 --- a/packages/api/src/router/location.ts +++ b/packages/api/src/router/location.ts @@ -1,16 +1,42 @@ -import type { z } from "zod"; +import { z } from "zod"; import { fetchWithTimeout } from "@homarr/common"; -import { validation } from "@homarr/validation"; import { createTRPCRouter, publicProcedure } from "../trpc"; +const citySchema = z.object({ + id: z.number(), + name: z.string(), + country: z.string().optional(), + country_code: z.string().optional(), + latitude: z.number(), + longitude: z.number(), + population: z.number().optional(), +}); + +export const locationSearchCityInput = z.object({ + query: z.string(), +}); + +export const locationSearchCityOutput = z + .object({ + results: z.array(citySchema), + }) + .or( + z + .object({ + generationtime_ms: z.number(), + }) + .refine((data) => Object.keys(data).length === 1, { message: "Invalid response" }) + .transform(() => ({ results: [] })), // We fallback to empty array if no results + ); + export const locationRouter = createTRPCRouter({ searchCity: publicProcedure - .input(validation.location.searchCity.input) - .output(validation.location.searchCity.output) + .input(locationSearchCityInput) + .output(locationSearchCityOutput) .query(async ({ input }) => { const res = await fetchWithTimeout(`https://geocoding-api.open-meteo.com/v1/search?name=${input.query}`); - return (await res.json()) as z.infer; + return (await res.json()) as z.infer; }), }); diff --git a/packages/api/src/router/medias/media-router.ts b/packages/api/src/router/medias/media-router.ts index d6ed0223b..9b4dbfb36 100644 --- a/packages/api/src/router/medias/media-router.ts +++ b/packages/api/src/router/medias/media-router.ts @@ -5,14 +5,15 @@ import type { InferInsertModel } from "@homarr/db"; import { and, createId, desc, eq, like } from "@homarr/db"; import { iconRepositories, icons, medias } from "@homarr/db/schema"; import { createLocalImageUrl, LOCAL_ICON_REPOSITORY_SLUG, mapMediaToIcon } from "@homarr/icons/local"; -import { validation } from "@homarr/validation"; +import { byIdSchema, paginatedSchema } from "@homarr/validation/common"; +import { mediaUploadSchema } from "@homarr/validation/media"; import { createTRPCRouter, permissionRequiredProcedure, protectedProcedure } from "../../trpc"; export const mediaRouter = createTRPCRouter({ getPaginated: protectedProcedure .input( - validation.common.paginated.and( + paginatedSchema.and( z.object({ includeFromAllUsers: z.boolean().default(false), search: z.string().trim().default("") }), ), ) @@ -51,7 +52,7 @@ export const mediaRouter = createTRPCRouter({ }), uploadMedia: permissionRequiredProcedure .requiresPermission("media-upload") - .input(validation.media.uploadMedia) + .input(mediaUploadSchema) .mutation(async ({ ctx, input }) => { const content = Buffer.from(await input.file.arrayBuffer()); const id = createId(); @@ -82,7 +83,7 @@ export const mediaRouter = createTRPCRouter({ return id; }), - deleteMedia: protectedProcedure.input(validation.common.byId).mutation(async ({ ctx, input }) => { + deleteMedia: protectedProcedure.input(byIdSchema).mutation(async ({ ctx, input }) => { const dbMedia = await ctx.db.query.medias.findFirst({ where: eq(medias.id, input.id), columns: { diff --git a/packages/api/src/router/onboard/onboard-router.ts b/packages/api/src/router/onboard/onboard-router.ts index a9a97d474..b68fbd44f 100644 --- a/packages/api/src/router/onboard/onboard-router.ts +++ b/packages/api/src/router/onboard/onboard-router.ts @@ -2,7 +2,7 @@ import { z } from "zod"; import { onboarding } from "@homarr/db/schema"; import { onboardingSteps } from "@homarr/definitions"; -import { zodEnumFromArray } from "@homarr/validation"; +import { zodEnumFromArray } from "@homarr/validation/enums"; import { createTRPCRouter, publicProcedure } from "../../trpc"; import { getOnboardingOrFallbackAsync, nextOnboardingStepAsync } from "./onboard-queries"; diff --git a/packages/api/src/router/search-engine/search-engine-router.ts b/packages/api/src/router/search-engine/search-engine-router.ts index 7b6eee219..e361b3bc9 100644 --- a/packages/api/src/router/search-engine/search-engine-router.ts +++ b/packages/api/src/router/search-engine/search-engine-router.ts @@ -5,13 +5,15 @@ import { asc, createId, eq, like } from "@homarr/db"; import { getServerSettingByKeyAsync } from "@homarr/db/queries"; import { searchEngines, users } from "@homarr/db/schema"; import { createIntegrationAsync } from "@homarr/integrations"; -import { validation } from "@homarr/validation"; +import { byIdSchema, paginatedSchema, searchSchema } from "@homarr/validation/common"; +import { searchEngineEditSchema, searchEngineManageSchema } from "@homarr/validation/search-engine"; +import { mediaRequestOptionsSchema, mediaRequestRequestSchema } from "@homarr/validation/widgets/media-request"; import { createOneIntegrationMiddleware } from "../../middlewares/integration"; import { createTRPCRouter, permissionRequiredProcedure, protectedProcedure, publicProcedure } from "../../trpc"; export const searchEngineRouter = createTRPCRouter({ - getPaginated: protectedProcedure.input(validation.common.paginated).query(async ({ input, ctx }) => { + getPaginated: protectedProcedure.input(paginatedSchema).query(async ({ input, ctx }) => { const whereQuery = input.search ? like(searchEngines.name, `%${input.search.trim()}%`) : undefined; const searchEngineCount = await ctx.db.$count(searchEngines, whereQuery); @@ -41,7 +43,7 @@ export const searchEngineRouter = createTRPCRouter({ .then((engines) => engines.map((engine) => ({ value: engine.id, label: engine.name }))); }), - byId: protectedProcedure.input(validation.common.byId).query(async ({ ctx, input }) => { + byId: protectedProcedure.input(byIdSchema).query(async ({ ctx, input }) => { const searchEngine = await ctx.db.query.searchEngines.findFirst({ where: eq(searchEngines.id, input.id), }); @@ -115,7 +117,7 @@ export const searchEngineRouter = createTRPCRouter({ return null; }), - search: protectedProcedure.input(validation.common.search).query(async ({ ctx, input }) => { + search: protectedProcedure.input(searchSchema).query(async ({ ctx, input }) => { return await ctx.db.query.searchEngines.findMany({ where: like(searchEngines.short, `${input.query.toLowerCase().trim()}%`), with: { @@ -132,21 +134,21 @@ export const searchEngineRouter = createTRPCRouter({ }), getMediaRequestOptions: protectedProcedure .unstable_concat(createOneIntegrationMiddleware("query", "jellyseerr", "overseerr")) - .input(validation.common.mediaRequestOptions) + .input(mediaRequestOptionsSchema) .query(async ({ ctx, input }) => { const integration = await createIntegrationAsync(ctx.integration); return await integration.getSeriesInformationAsync(input.mediaType, input.mediaId); }), requestMedia: protectedProcedure .unstable_concat(createOneIntegrationMiddleware("interact", "jellyseerr", "overseerr")) - .input(validation.common.requestMedia) + .input(mediaRequestRequestSchema) .mutation(async ({ ctx, input }) => { const integration = await createIntegrationAsync(ctx.integration); return await integration.requestMediaAsync(input.mediaType, input.mediaId, input.seasons); }), create: permissionRequiredProcedure .requiresPermission("search-engine-create") - .input(validation.searchEngine.manage) + .input(searchEngineManageSchema) .mutation(async ({ ctx, input }) => { await ctx.db.insert(searchEngines).values({ id: createId(), @@ -161,7 +163,7 @@ export const searchEngineRouter = createTRPCRouter({ }), update: permissionRequiredProcedure .requiresPermission("search-engine-modify-all") - .input(validation.searchEngine.edit) + .input(searchEngineEditSchema) .mutation(async ({ ctx, input }) => { const searchEngine = await ctx.db.query.searchEngines.findFirst({ where: eq(searchEngines.id, input.id), @@ -188,7 +190,7 @@ export const searchEngineRouter = createTRPCRouter({ }), delete: permissionRequiredProcedure .requiresPermission("search-engine-full-all") - .input(validation.common.byId) + .input(byIdSchema) .mutation(async ({ ctx, input }) => { await ctx.db .update(users) diff --git a/packages/api/src/router/serverSettings.ts b/packages/api/src/router/serverSettings.ts index a4bb5eeca..c7035aa1f 100644 --- a/packages/api/src/router/serverSettings.ts +++ b/packages/api/src/router/serverSettings.ts @@ -3,7 +3,7 @@ import { z } from "zod"; import { getServerSettingByKeyAsync, getServerSettingsAsync, updateServerSettingByKeyAsync } from "@homarr/db/queries"; import type { ServerSettings } from "@homarr/server-settings"; import { defaultServerSettingsKeys } from "@homarr/server-settings"; -import { validation } from "@homarr/validation"; +import { settingsInitSchema } from "@homarr/validation/settings"; import { createTRPCRouter, onboardingProcedure, permissionRequiredProcedure, publicProcedure } from "../trpc"; import { nextOnboardingStepAsync } from "./onboard/onboard-queries"; @@ -32,7 +32,7 @@ export const serverSettingsRouter = createTRPCRouter({ }), initSettings: onboardingProcedure .requiresStep("settings") - .input(validation.settings.init) + .input(settingsInitSchema) .mutation(async ({ ctx, input }) => { await updateServerSettingByKeyAsync(ctx.db, "analytics", input.analytics); await updateServerSettingByKeyAsync(ctx.db, "crawlingAndIndexing", input.crawlingAndIndexing); diff --git a/packages/api/src/router/user.ts b/packages/api/src/router/user.ts index 9aefff564..ff802e1df 100644 --- a/packages/api/src/router/user.ts +++ b/packages/api/src/router/user.ts @@ -10,7 +10,20 @@ import { selectUserSchema } from "@homarr/db/validationSchemas"; import { credentialsAdminGroup } from "@homarr/definitions"; import type { SupportedAuthProvider } from "@homarr/definitions"; import { logger } from "@homarr/log"; -import { validation } from "@homarr/validation"; +import { byIdSchema } from "@homarr/validation/common"; +import type { userBaseCreateSchema } from "@homarr/validation/user"; +import { + userChangeColorSchemeSchema, + userChangeHomeBoardsSchema, + userChangePasswordApiSchema, + userChangeSearchPreferencesSchema, + userCreateSchema, + userEditProfileSchema, + userFirstDayOfWeekSchema, + userInitSchema, + userPingIconsEnabledSchema, + userRegistrationApiSchema, +} from "@homarr/validation/user"; import { convertIntersectionToZodObject } from "../schema-merger"; import { @@ -28,7 +41,7 @@ import { changeSearchPreferencesAsync, changeSearchPreferencesInputSchema } from export const userRouter = createTRPCRouter({ initUser: onboardingProcedure .requiresStep("user") - .input(validation.user.init) + .input(userInitSchema) .mutation(async ({ ctx, input }) => { throwIfCredentialsDisabled(); @@ -52,7 +65,7 @@ export const userRouter = createTRPCRouter({ await nextOnboardingStepAsync(ctx.db, undefined); }), register: publicProcedure - .input(validation.user.registrationApi) + .input(userRegistrationApiSchema) .output(z.void()) .mutation(async ({ ctx, input }) => { throwIfCredentialsDisabled(); @@ -82,7 +95,7 @@ export const userRouter = createTRPCRouter({ create: permissionRequiredProcedure .requiresPermission("admin") .meta({ openapi: { method: "POST", path: "/api/users", tags: ["users"], protect: true } }) - .input(validation.user.create) + .input(userCreateSchema) .output(z.void()) .mutation(async ({ ctx, input }) => { throwIfCredentialsDisabled(); @@ -259,7 +272,7 @@ export const userRouter = createTRPCRouter({ return user; }), editProfile: protectedProcedure - .input(validation.user.editProfile) + .input(userEditProfileSchema) .output(z.void()) .meta({ openapi: { method: "PUT", path: "/api/users/profile", tags: ["users"], protect: true } }) .mutation(async ({ input, ctx }) => { @@ -318,7 +331,7 @@ export const userRouter = createTRPCRouter({ await ctx.db.delete(users).where(eq(users.id, input.userId)); }), changePassword: protectedProcedure - .input(validation.user.changePasswordApi) + .input(userChangePasswordApiSchema) .output(z.void()) .meta({ openapi: { method: "PATCH", path: "/api/users/{userId}/changePassword", tags: ["users"], protect: true } }) .mutation(async ({ ctx, input }) => { @@ -384,7 +397,7 @@ export const userRouter = createTRPCRouter({ .where(eq(users.id, input.userId)); }), changeHomeBoards: protectedProcedure - .input(convertIntersectionToZodObject(validation.user.changeHomeBoards.and(z.object({ userId: z.string() })))) + .input(convertIntersectionToZodObject(userChangeHomeBoardsSchema.and(z.object({ userId: z.string() })))) .output(z.void()) .meta({ openapi: { method: "PATCH", path: "/api/users/changeHome", tags: ["users"], protect: true } }) .mutation(async ({ input, ctx }) => { @@ -430,7 +443,7 @@ export const userRouter = createTRPCRouter({ changeDefaultSearchEngine: protectedProcedure .input( convertIntersectionToZodObject( - validation.user.changeSearchPreferences.omit({ openInNewTab: true }).and(z.object({ userId: z.string() })), + userChangeSearchPreferencesSchema.omit({ openInNewTab: true }).and(z.object({ userId: z.string() })), ), ) .output(z.void()) @@ -457,7 +470,7 @@ export const userRouter = createTRPCRouter({ await changeSearchPreferencesAsync(ctx.db, ctx.session, input); }), changeColorScheme: protectedProcedure - .input(validation.user.changeColorScheme) + .input(userChangeColorSchemeSchema) .output(z.void()) .meta({ openapi: { method: "PATCH", path: "/api/users/changeScheme", tags: ["users"], protect: true } }) .mutation(async ({ input, ctx }) => { @@ -469,7 +482,7 @@ export const userRouter = createTRPCRouter({ .where(eq(users.id, ctx.session.user.id)); }), changePingIconsEnabled: protectedProcedure - .input(validation.user.pingIconsEnabled.and(validation.common.byId)) + .input(userPingIconsEnabledSchema.and(byIdSchema)) .mutation(async ({ input, ctx }) => { // Only admins can change other users ping icons enabled if (!ctx.session.user.permissions.includes("admin") && ctx.session.user.id !== input.id) { @@ -487,7 +500,7 @@ export const userRouter = createTRPCRouter({ .where(eq(users.id, ctx.session.user.id)); }), changeFirstDayOfWeek: protectedProcedure - .input(convertIntersectionToZodObject(validation.user.firstDayOfWeek.and(validation.common.byId))) + .input(convertIntersectionToZodObject(userFirstDayOfWeekSchema.and(byIdSchema))) .output(z.void()) .meta({ openapi: { method: "PATCH", path: "/api/users/firstDayOfWeek", tags: ["users"], protect: true } }) .mutation(async ({ input, ctx }) => { @@ -522,7 +535,7 @@ export const userRouter = createTRPCRouter({ }), }); -const createUserAsync = async (db: Database, input: Omit, "groupIds">) => { +const createUserAsync = async (db: Database, input: Omit, "groupIds">) => { const salt = await createSaltAsync(); const hashedPassword = await hashPasswordAsync(input.password, salt); diff --git a/packages/api/src/router/user/change-search-preferences.ts b/packages/api/src/router/user/change-search-preferences.ts index 1231b4e48..927418331 100644 --- a/packages/api/src/router/user/change-search-preferences.ts +++ b/packages/api/src/router/user/change-search-preferences.ts @@ -6,9 +6,9 @@ import type { Modify } from "@homarr/common/types"; import { eq } from "@homarr/db"; import type { Database } from "@homarr/db"; import { users } from "@homarr/db/schema"; -import { validation } from "@homarr/validation"; +import { userChangeSearchPreferencesSchema } from "@homarr/validation/user"; -export const changeSearchPreferencesInputSchema = validation.user.changeSearchPreferences.and( +export const changeSearchPreferencesInputSchema = userChangeSearchPreferencesSchema.and( z.object({ userId: z.string() }), ); diff --git a/packages/api/src/router/widgets/index.ts b/packages/api/src/router/widgets/index.ts index f3716459c..ddce0b9a0 100644 --- a/packages/api/src/router/widgets/index.ts +++ b/packages/api/src/router/widgets/index.ts @@ -9,6 +9,7 @@ import { mediaRequestsRouter } from "./media-requests"; import { mediaServerRouter } from "./media-server"; import { mediaTranscodingRouter } from "./media-transcoding"; import { minecraftRouter } from "./minecraft"; +import { networkControllerRouter } from "./network-controller"; import { notebookRouter } from "./notebook"; import { optionsRouter } from "./options"; import { rssFeedRouter } from "./rssFeed"; @@ -33,4 +34,5 @@ export const widgetRouter = createTRPCRouter({ mediaTranscoding: mediaTranscodingRouter, minecraft: minecraftRouter, options: optionsRouter, + networkController: networkControllerRouter, }); diff --git a/packages/api/src/router/widgets/media-transcoding.ts b/packages/api/src/router/widgets/media-transcoding.ts index d6d1ce7e8..c2f0b0d9b 100644 --- a/packages/api/src/router/widgets/media-transcoding.ts +++ b/packages/api/src/router/widgets/media-transcoding.ts @@ -1,6 +1,6 @@ import { getIntegrationKindsByCategory } from "@homarr/definitions"; import { mediaTranscodingRequestHandler } from "@homarr/request-handler/media-transcoding"; -import { validation } from "@homarr/validation"; +import { paginatedSchema } from "@homarr/validation/common"; import type { IntegrationAction } from "../../middlewares/integration"; import { createOneIntegrationMiddleware } from "../../middlewares/integration"; @@ -12,7 +12,7 @@ const createIndexerManagerIntegrationMiddleware = (action: IntegrationAction) => export const mediaTranscodingRouter = createTRPCRouter({ getDataAsync: publicProcedure .unstable_concat(createIndexerManagerIntegrationMiddleware("query")) - .input(validation.common.paginated.pick({ page: true, pageSize: true })) + .input(paginatedSchema.pick({ page: true, pageSize: true })) .query(async ({ ctx, input }) => { const innerHandler = mediaTranscodingRequestHandler.handler(ctx.integration, { pageOffset: input.page, diff --git a/packages/api/src/router/widgets/network-controller.ts b/packages/api/src/router/widgets/network-controller.ts new file mode 100644 index 000000000..662a8063b --- /dev/null +++ b/packages/api/src/router/widgets/network-controller.ts @@ -0,0 +1,62 @@ +import { observable } from "@trpc/server/observable"; + +import type { Modify } from "@homarr/common/types"; +import type { Integration } from "@homarr/db/schema"; +import type { IntegrationKindByCategory } from "@homarr/definitions"; +import { getIntegrationKindsByCategory } from "@homarr/definitions"; +import type { NetworkControllerSummary } from "@homarr/integrations/types"; +import { networkControllerRequestHandler } from "@homarr/request-handler/network-controller"; + +import { createManyIntegrationMiddleware } from "../../middlewares/integration"; +import { createTRPCRouter, publicProcedure } from "../../trpc"; + +export const networkControllerRouter = createTRPCRouter({ + summary: publicProcedure + .unstable_concat(createManyIntegrationMiddleware("query", ...getIntegrationKindsByCategory("networkController"))) + .query(async ({ ctx }) => { + const results = await Promise.all( + ctx.integrations.map(async (integration) => { + const innerHandler = networkControllerRequestHandler.handler(integration, {}); + const { data, timestamp } = await innerHandler.getCachedOrUpdatedDataAsync({ forceUpdate: false }); + + return { + integration: { + id: integration.id, + name: integration.name, + kind: integration.kind, + }, + summary: data, + updatedAt: timestamp, + }; + }), + ); + return results; + }), + + subscribeToSummary: publicProcedure + .unstable_concat(createManyIntegrationMiddleware("query", ...getIntegrationKindsByCategory("networkController"))) + .subscription(({ ctx }) => { + return observable<{ + integration: Modify }>; + summary: NetworkControllerSummary; + }>((emit) => { + const unsubscribes: (() => void)[] = []; + for (const integrationWithSecrets of ctx.integrations) { + const { decryptedSecrets: _, ...integration } = integrationWithSecrets; + const innerHandler = networkControllerRequestHandler.handler(integrationWithSecrets, {}); + const unsubscribe = innerHandler.subscribe((summary) => { + emit.next({ + integration, + summary, + }); + }); + unsubscribes.push(unsubscribe); + } + return () => { + unsubscribes.forEach((unsubscribe) => { + unsubscribe(); + }); + }; + }); + }), +}); diff --git a/packages/api/src/router/widgets/notebook.ts b/packages/api/src/router/widgets/notebook.ts index 53d4e0fdd..86bf61e3a 100644 --- a/packages/api/src/router/widgets/notebook.ts +++ b/packages/api/src/router/widgets/notebook.ts @@ -3,9 +3,10 @@ import SuperJSON from "superjson"; import { z } from "zod"; import { eq } from "@homarr/db"; -import { items } from "@homarr/db/schema"; +import { boards, items } from "@homarr/db/schema"; import { createTRPCRouter, protectedProcedure } from "../../trpc"; +import { throwIfActionForbiddenAsync } from "../board/board-access"; export const notebookRouter = createTRPCRouter({ updateContent: protectedProcedure @@ -17,6 +18,8 @@ export const notebookRouter = createTRPCRouter({ }), ) .mutation(async ({ ctx, input }) => { + await throwIfActionForbiddenAsync(ctx, eq(boards.id, input.boardId), "modify"); + const item = await ctx.db.query.items.findFirst({ where: eq(items.id, input.itemId), }); diff --git a/packages/api/src/router/widgets/weather.ts b/packages/api/src/router/widgets/weather.ts index ded3bc5b0..94555c666 100644 --- a/packages/api/src/router/widgets/weather.ts +++ b/packages/api/src/router/widgets/weather.ts @@ -1,15 +1,39 @@ +import { z } from "zod"; + import { fetchWithTimeout } from "@homarr/common"; -import { validation } from "@homarr/validation"; import { createTRPCRouter, publicProcedure } from "../../trpc"; +const atLocationInput = z.object({ + longitude: z.number(), + latitude: z.number(), +}); + +const atLocationOutput = z.object({ + current_weather: z.object({ + weathercode: z.number(), + temperature: z.number(), + windspeed: z.number(), + }), + daily: z.object({ + time: z.array(z.string()), + weathercode: z.array(z.number()), + temperature_2m_max: z.array(z.number()), + temperature_2m_min: z.array(z.number()), + sunrise: z.array(z.string()), + sunset: z.array(z.string()), + wind_speed_10m_max: z.array(z.number()), + wind_gusts_10m_max: z.array(z.number()), + }), +}); + export const weatherRouter = createTRPCRouter({ - atLocation: publicProcedure.input(validation.widget.weather.atLocationInput).query(async ({ input }) => { + atLocation: publicProcedure.input(atLocationInput).query(async ({ input }) => { const res = await fetchWithTimeout( `https://api.open-meteo.com/v1/forecast?latitude=${input.latitude}&longitude=${input.longitude}&daily=weathercode,temperature_2m_max,temperature_2m_min,sunrise,sunset,wind_speed_10m_max,wind_gusts_10m_max¤t_weather=true&timezone=auto`, ); const json: unknown = await res.json(); - const weather = await validation.widget.weather.atLocationOutput.parseAsync(json); + const weather = await atLocationOutput.parseAsync(json); return { current: weather.current_weather, daily: weather.daily.time.map((value, index) => { diff --git a/packages/auth/package.json b/packages/auth/package.json index 9e2b62e7f..209ad018c 100644 --- a/packages/auth/package.json +++ b/packages/auth/package.json @@ -34,8 +34,8 @@ "@homarr/validation": "workspace:^0.1.0", "bcrypt": "^5.1.1", "cookies": "^0.9.1", - "ldapts": "7.3.3", - "next": "15.2.4", + "ldapts": "7.4.0", + "next": "15.2.5", "next-auth": "5.0.0-beta.25", "pretty-print-error": "^1.1.2", "react": "19.1.0", @@ -48,8 +48,8 @@ "@homarr/tsconfig": "workspace:^0.1.0", "@types/bcrypt": "5.0.2", "@types/cookies": "0.9.0", - "eslint": "^9.23.0", + "eslint": "^9.24.0", "prettier": "^3.5.3", - "typescript": "^5.8.2" + "typescript": "^5.8.3" } } diff --git a/packages/auth/providers/credentials/authorization/basic-authorization.ts b/packages/auth/providers/credentials/authorization/basic-authorization.ts index 6cbd4d16a..596716c1b 100644 --- a/packages/auth/providers/credentials/authorization/basic-authorization.ts +++ b/packages/auth/providers/credentials/authorization/basic-authorization.ts @@ -5,11 +5,11 @@ import type { Database } from "@homarr/db"; import { and, eq } from "@homarr/db"; import { users } from "@homarr/db/schema"; import { logger } from "@homarr/log"; -import type { validation } from "@homarr/validation"; +import type { userSignInSchema } from "@homarr/validation/user"; export const authorizeWithBasicCredentialsAsync = async ( db: Database, - credentials: z.infer, + credentials: z.infer, ) => { const user = await db.query.users.findFirst({ where: and(eq(users.name, credentials.name.toLowerCase()), eq(users.provider, "credentials")), diff --git a/packages/auth/providers/credentials/authorization/ldap-authorization.ts b/packages/auth/providers/credentials/authorization/ldap-authorization.ts index 84f7733ac..9bfa90c2a 100644 --- a/packages/auth/providers/credentials/authorization/ldap-authorization.ts +++ b/packages/auth/providers/credentials/authorization/ldap-authorization.ts @@ -6,14 +6,14 @@ import type { Database, InferInsertModel } from "@homarr/db"; import { and, createId, eq } from "@homarr/db"; import { users } from "@homarr/db/schema"; import { logger } from "@homarr/log"; -import type { validation } from "@homarr/validation"; +import type { userSignInSchema } from "@homarr/validation/user"; import { env } from "../../../env"; import { LdapClient } from "../ldap-client"; export const authorizeWithLdapCredentialsAsync = async ( db: Database, - credentials: z.infer, + credentials: z.infer, ) => { logger.info(`user ${credentials.name} is trying to log in using LDAP. Connecting to LDAP server...`); const client = new LdapClient(); diff --git a/packages/auth/providers/credentials/credentials-provider.ts b/packages/auth/providers/credentials/credentials-provider.ts index 571541b7a..79e5eddf6 100644 --- a/packages/auth/providers/credentials/credentials-provider.ts +++ b/packages/auth/providers/credentials/credentials-provider.ts @@ -1,7 +1,7 @@ import type Credentials from "@auth/core/providers/credentials"; import type { Database } from "@homarr/db"; -import { validation } from "@homarr/validation"; +import { userSignInSchema } from "@homarr/validation/user"; import { authorizeWithBasicCredentialsAsync } from "./authorization/basic-authorization"; import { authorizeWithLdapCredentialsAsync } from "./authorization/ldap-authorization"; @@ -15,7 +15,7 @@ export const createCredentialsConfiguration = (db: Database) => name: "Credentials", // eslint-disable-next-line no-restricted-syntax async authorize(credentials) { - const data = await validation.user.signIn.parseAsync(credentials); + const data = await userSignInSchema.parseAsync(credentials); return await authorizeWithBasicCredentialsAsync(db, data); }, @@ -28,7 +28,7 @@ export const createLdapConfiguration = (db: Database) => name: "Ldap", // eslint-disable-next-line no-restricted-syntax async authorize(credentials) { - const data = await validation.user.signIn.parseAsync(credentials); + const data = await userSignInSchema.parseAsync(credentials); return await authorizeWithLdapCredentialsAsync(db, data).catch(() => null); }, }) satisfies CredentialsConfiguration; diff --git a/packages/boards/package.json b/packages/boards/package.json index 3b24ad43d..79232e483 100644 --- a/packages/boards/package.json +++ b/packages/boards/package.json @@ -32,7 +32,7 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.23.0", - "typescript": "^5.8.2" + "eslint": "^9.24.0", + "typescript": "^5.8.3" } } diff --git a/packages/certificates/package.json b/packages/certificates/package.json index eeef93d2d..024c38f5f 100644 --- a/packages/certificates/package.json +++ b/packages/certificates/package.json @@ -29,7 +29,7 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.23.0", - "typescript": "^5.8.2" + "eslint": "^9.24.0", + "typescript": "^5.8.3" } } diff --git a/packages/cli/package.json b/packages/cli/package.json index f6bd416b8..0384efe0b 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -34,7 +34,7 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.23.0", - "typescript": "^5.8.2" + "eslint": "^9.24.0", + "typescript": "^5.8.3" } } diff --git a/packages/cli/src/commands/recreate-admin.ts b/packages/cli/src/commands/recreate-admin.ts index 59af3bade..29d7027df 100644 --- a/packages/cli/src/commands/recreate-admin.ts +++ b/packages/cli/src/commands/recreate-admin.ts @@ -5,7 +5,7 @@ import { generateSecureRandomToken } from "@homarr/common/server"; import { and, count, createId, db, eq } from "@homarr/db"; import { getMaxGroupPositionAsync } from "@homarr/db/queries"; import { groupMembers, groupPermissions, groups, users } from "@homarr/db/schema"; -import { usernameSchema } from "@homarr/validation"; +import { usernameSchema } from "@homarr/validation/user"; export const recreateAdmin = command({ name: "recreate-admin", diff --git a/packages/common/package.json b/packages/common/package.json index de9c0a1a6..8920e5e73 100644 --- a/packages/common/package.json +++ b/packages/common/package.json @@ -30,7 +30,7 @@ "@homarr/env": "workspace:^0.1.0", "@homarr/log": "workspace:^0.1.0", "dayjs": "^1.11.13", - "next": "15.2.4", + "next": "15.2.5", "react": "19.1.0", "react-dom": "19.1.0", "undici": "7.7.0", @@ -40,7 +40,7 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.23.0", - "typescript": "^5.8.2" + "eslint": "^9.24.0", + "typescript": "^5.8.3" } } diff --git a/packages/cron-job-runner/package.json b/packages/cron-job-runner/package.json index 4fb511f28..c5187c924 100644 --- a/packages/cron-job-runner/package.json +++ b/packages/cron-job-runner/package.json @@ -33,7 +33,7 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.23.0", - "typescript": "^5.8.2" + "eslint": "^9.24.0", + "typescript": "^5.8.3" } } diff --git a/packages/cron-job-runner/src/index.ts b/packages/cron-job-runner/src/index.ts index 9042241c3..e1e851da6 100644 --- a/packages/cron-job-runner/src/index.ts +++ b/packages/cron-job-runner/src/index.ts @@ -1,7 +1,7 @@ import { objectKeys } from "@homarr/common"; import type { JobGroupKeys } from "@homarr/cron-jobs"; import { createSubPubChannel } from "@homarr/redis"; -import { zodEnumFromArray } from "@homarr/validation"; +import { zodEnumFromArray } from "@homarr/validation/enums"; export const cronJobRunnerChannel = createSubPubChannel("cron-job-runner", { persist: false }); @@ -23,6 +23,7 @@ export const cronJobs = { updateChecker: { preventManualExecution: false }, mediaTranscoding: { preventManualExecution: false }, minecraftServerStatus: { preventManualExecution: false }, + networkController: { preventManualExecution: false }, } satisfies Record; /** diff --git a/packages/cron-job-status/package.json b/packages/cron-job-status/package.json index 95ff056e3..fe86beb26 100644 --- a/packages/cron-job-status/package.json +++ b/packages/cron-job-status/package.json @@ -29,7 +29,7 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.23.0", - "typescript": "^5.8.2" + "eslint": "^9.24.0", + "typescript": "^5.8.3" } } diff --git a/packages/cron-jobs-core/package.json b/packages/cron-jobs-core/package.json index bf0e99913..320636aad 100644 --- a/packages/cron-jobs-core/package.json +++ b/packages/cron-jobs-core/package.json @@ -32,7 +32,7 @@ "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", "@types/node-cron": "^3.0.11", - "eslint": "^9.23.0", - "typescript": "^5.8.2" + "eslint": "^9.24.0", + "typescript": "^5.8.3" } } diff --git a/packages/cron-jobs/package.json b/packages/cron-jobs/package.json index aa596906d..1612d34fb 100644 --- a/packages/cron-jobs/package.json +++ b/packages/cron-jobs/package.json @@ -44,7 +44,7 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.23.0", - "typescript": "^5.8.2" + "eslint": "^9.24.0", + "typescript": "^5.8.3" } } diff --git a/packages/cron-jobs/src/index.ts b/packages/cron-jobs/src/index.ts index fe8e1b94e..b141c7146 100644 --- a/packages/cron-jobs/src/index.ts +++ b/packages/cron-jobs/src/index.ts @@ -9,6 +9,7 @@ import { mediaOrganizerJob } from "./jobs/integrations/media-organizer"; import { mediaRequestListJob, mediaRequestStatsJob } from "./jobs/integrations/media-requests"; import { mediaServerJob } from "./jobs/integrations/media-server"; import { mediaTranscodingJob } from "./jobs/integrations/media-transcoding"; +import { networkControllerJob } from "./jobs/integrations/network-controller"; import { minecraftServerStatusJob } from "./jobs/minecraft-server-status"; import { pingJob } from "./jobs/ping"; import { rssFeedsJob } from "./jobs/rss-feeds"; @@ -34,6 +35,7 @@ export const jobGroup = createCronJobGroup({ updateChecker: updateCheckerJob, mediaTranscoding: mediaTranscodingJob, minecraftServerStatus: minecraftServerStatusJob, + networkController: networkControllerJob, }); export type JobGroupKeys = ReturnType<(typeof jobGroup)["getKeys"]>[number]; diff --git a/packages/cron-jobs/src/jobs/integrations/network-controller.ts b/packages/cron-jobs/src/jobs/integrations/network-controller.ts new file mode 100644 index 000000000..5d9354588 --- /dev/null +++ b/packages/cron-jobs/src/jobs/integrations/network-controller.ts @@ -0,0 +1,14 @@ +import { EVERY_MINUTE } from "@homarr/cron-jobs-core/expressions"; +import { createRequestIntegrationJobHandler } from "@homarr/request-handler/lib/cached-request-integration-job-handler"; +import { networkControllerRequestHandler } from "@homarr/request-handler/network-controller"; + +import { createCronJob } from "../../lib"; + +export const networkControllerJob = createCronJob("networkController", EVERY_MINUTE).withCallback( + createRequestIntegrationJobHandler(networkControllerRequestHandler.handler, { + widgetKinds: ["networkControllerSummary"], + getInput: { + networkControllerSummary: () => ({}), + }, + }), +); diff --git a/packages/db/package.json b/packages/db/package.json index aae99317c..bfd9090b0 100644 --- a/packages/db/package.json +++ b/packages/db/package.json @@ -44,9 +44,9 @@ "@homarr/env": "workspace:^0.1.0", "@homarr/log": "workspace:^0.1.0", "@homarr/server-settings": "workspace:^0.1.0", - "@mantine/core": "^7.17.3", + "@mantine/core": "^7.17.4", "@paralleldrive/cuid2": "^2.2.2", - "@testcontainers/mysql": "^10.24.0", + "@testcontainers/mysql": "^10.24.1", "better-sqlite3": "^11.9.1", "dotenv": "^16.4.7", "drizzle-kit": "^0.30.6", @@ -60,9 +60,9 @@ "@homarr/tsconfig": "workspace:^0.1.0", "@types/better-sqlite3": "7.6.13", "dotenv-cli": "^8.0.0", - "eslint": "^9.23.0", + "eslint": "^9.24.0", "prettier": "^3.5.3", "tsx": "4.19.3", - "typescript": "^5.8.2" + "typescript": "^5.8.3" } } diff --git a/packages/definitions/package.json b/packages/definitions/package.json index 69e6a99ec..101c090f8 100644 --- a/packages/definitions/package.json +++ b/packages/definitions/package.json @@ -29,7 +29,7 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.23.0", - "typescript": "^5.8.2" + "eslint": "^9.24.0", + "typescript": "^5.8.3" } } diff --git a/packages/definitions/src/docs/homarr-docs-sitemap.ts b/packages/definitions/src/docs/homarr-docs-sitemap.ts index 0fd30d8eb..efaa2303c 100644 --- a/packages/definitions/src/docs/homarr-docs-sitemap.ts +++ b/packages/definitions/src/docs/homarr-docs-sitemap.ts @@ -556,6 +556,185 @@ export type HomarrDocumentationPath = | "/docs/1.12.0/widgets/stocks" | "/docs/1.12.0/widgets/video" | "/docs/1.12.0/widgets/weather" + | "/docs/1.13.1/tags" + | "/docs/1.13.1/tags/active-directory" + | "/docs/1.13.1/tags/ad-guard" + | "/docs/1.13.1/tags/ad-guard-home" + | "/docs/1.13.1/tags/administration" + | "/docs/1.13.1/tags/advanced" + | "/docs/1.13.1/tags/analytics" + | "/docs/1.13.1/tags/api" + | "/docs/1.13.1/tags/apps" + | "/docs/1.13.1/tags/banner" + | "/docs/1.13.1/tags/blocking" + | "/docs/1.13.1/tags/boards" + | "/docs/1.13.1/tags/bookmark" + | "/docs/1.13.1/tags/bookmarks" + | "/docs/1.13.1/tags/caddy" + | "/docs/1.13.1/tags/certificates" + | "/docs/1.13.1/tags/checklist" + | "/docs/1.13.1/tags/code" + | "/docs/1.13.1/tags/community" + | "/docs/1.13.1/tags/configuration" + | "/docs/1.13.1/tags/connections" + | "/docs/1.13.1/tags/customization" + | "/docs/1.13.1/tags/data-sources" + | "/docs/1.13.1/tags/database" + | "/docs/1.13.1/tags/developer" + | "/docs/1.13.1/tags/development" + | "/docs/1.13.1/tags/dns" + | "/docs/1.13.1/tags/docker" + | "/docs/1.13.1/tags/donation" + | "/docs/1.13.1/tags/edit-mode" + | "/docs/1.13.1/tags/env" + | "/docs/1.13.1/tags/environment-variables" + | "/docs/1.13.1/tags/feeds" + | "/docs/1.13.1/tags/finance" + | "/docs/1.13.1/tags/getting-started" + | "/docs/1.13.1/tags/google" + | "/docs/1.13.1/tags/grafana" + | "/docs/1.13.1/tags/groups" + | "/docs/1.13.1/tags/hardware" + | "/docs/1.13.1/tags/health" + | "/docs/1.13.1/tags/help" + | "/docs/1.13.1/tags/icon-picker" + | "/docs/1.13.1/tags/icon-repositories" + | "/docs/1.13.1/tags/icons" + | "/docs/1.13.1/tags/iframe" + | "/docs/1.13.1/tags/images" + | "/docs/1.13.1/tags/installation" + | "/docs/1.13.1/tags/integrade" + | "/docs/1.13.1/tags/integration" + | "/docs/1.13.1/tags/integrations" + | "/docs/1.13.1/tags/interface" + | "/docs/1.13.1/tags/jellyserr" + | "/docs/1.13.1/tags/layout" + | "/docs/1.13.1/tags/ldap" + | "/docs/1.13.1/tags/links" + | "/docs/1.13.1/tags/lists" + | "/docs/1.13.1/tags/management" + | "/docs/1.13.1/tags/market" + | "/docs/1.13.1/tags/media" + | "/docs/1.13.1/tags/minecraft" + | "/docs/1.13.1/tags/monitoring" + | "/docs/1.13.1/tags/news" + | "/docs/1.13.1/tags/notebook" + | "/docs/1.13.1/tags/notes" + | "/docs/1.13.1/tags/oidc" + | "/docs/1.13.1/tags/open-collective" + | "/docs/1.13.1/tags/open-media-vault" + | "/docs/1.13.1/tags/overseerr" + | "/docs/1.13.1/tags/permissions" + | "/docs/1.13.1/tags/pgid" + | "/docs/1.13.1/tags/pi-hole" + | "/docs/1.13.1/tags/ping" + | "/docs/1.13.1/tags/programming" + | "/docs/1.13.1/tags/proxmox" + | "/docs/1.13.1/tags/proxy" + | "/docs/1.13.1/tags/puid" + | "/docs/1.13.1/tags/responsive" + | "/docs/1.13.1/tags/roles" + | "/docs/1.13.1/tags/rss" + | "/docs/1.13.1/tags/search" + | "/docs/1.13.1/tags/search-engines" + | "/docs/1.13.1/tags/security" + | "/docs/1.13.1/tags/self-signed" + | "/docs/1.13.1/tags/seo" + | "/docs/1.13.1/tags/server" + | "/docs/1.13.1/tags/settings" + | "/docs/1.13.1/tags/sinkhole" + | "/docs/1.13.1/tags/sso" + | "/docs/1.13.1/tags/stocks" + | "/docs/1.13.1/tags/system" + | "/docs/1.13.1/tags/table" + | "/docs/1.13.1/tags/technical-documentation" + | "/docs/1.13.1/tags/text" + | "/docs/1.13.1/tags/torrent" + | "/docs/1.13.1/tags/traefik" + | "/docs/1.13.1/tags/translations" + | "/docs/1.13.1/tags/unraid" + | "/docs/1.13.1/tags/uploads" + | "/docs/1.13.1/tags/usenet" + | "/docs/1.13.1/tags/users" + | "/docs/1.13.1/tags/variables" + | "/docs/1.13.1/tags/widgets" + | "/docs/1.13.1/advanced/command-line" + | "/docs/1.13.1/advanced/command-line/fix-usernames" + | "/docs/1.13.1/advanced/command-line/password-recovery" + | "/docs/1.13.1/advanced/development/getting-started" + | "/docs/1.13.1/advanced/development/kubernetes" + | "/docs/1.13.1/advanced/environment-variables" + | "/docs/1.13.1/advanced/icons" + | "/docs/1.13.1/advanced/keyboard-shortcuts" + | "/docs/1.13.1/advanced/proxy" + | "/docs/1.13.1/advanced/running-as-different-user" + | "/docs/1.13.1/advanced/single-sign-on" + | "/docs/1.13.1/advanced/styling" + | "/docs/1.13.1/category/advanced" + | "/docs/1.13.1/category/community" + | "/docs/1.13.1/category/developer-guides" + | "/docs/1.13.1/category/getting-started" + | "/docs/1.13.1/category/installation" + | "/docs/1.13.1/category/installation-1" + | "/docs/1.13.1/category/integrations" + | "/docs/1.13.1/category/management" + | "/docs/1.13.1/category/widgets" + | "/docs/1.13.1/community/donate" + | "/docs/1.13.1/community/faq" + | "/docs/1.13.1/community/get-in-touch" + | "/docs/1.13.1/community/license" + | "/docs/1.13.1/community/translations" + | "/docs/1.13.1/getting-started" + | "/docs/1.13.1/getting-started/after-the-installation" + | "/docs/1.13.1/getting-started/glossary" + | "/docs/1.13.1/getting-started/installation/docker" + | "/docs/1.13.1/getting-started/installation/easy-panel" + | "/docs/1.13.1/getting-started/installation/helm" + | "/docs/1.13.1/getting-started/installation/home-assistant" + | "/docs/1.13.1/getting-started/installation/portainer" + | "/docs/1.13.1/getting-started/installation/proxmox" + | "/docs/1.13.1/getting-started/installation/qnap" + | "/docs/1.13.1/getting-started/installation/railway" + | "/docs/1.13.1/getting-started/installation/saltbox" + | "/docs/1.13.1/getting-started/installation/source" + | "/docs/1.13.1/getting-started/installation/synology" + | "/docs/1.13.1/getting-started/installation/unraid" + | "/docs/1.13.1/integrations/cloud" + | "/docs/1.13.1/integrations/containers" + | "/docs/1.13.1/integrations/dns" + | "/docs/1.13.1/integrations/hardware" + | "/docs/1.13.1/integrations/kubernetes" + | "/docs/1.13.1/integrations/media-requester" + | "/docs/1.13.1/integrations/media-server" + | "/docs/1.13.1/integrations/servarr" + | "/docs/1.13.1/integrations/torrent" + | "/docs/1.13.1/integrations/usenet" + | "/docs/1.13.1/management/api" + | "/docs/1.13.1/management/apps" + | "/docs/1.13.1/management/boards" + | "/docs/1.13.1/management/certificates" + | "/docs/1.13.1/management/integrations" + | "/docs/1.13.1/management/media" + | "/docs/1.13.1/management/search-engines" + | "/docs/1.13.1/management/settings" + | "/docs/1.13.1/management/users" + | "/docs/1.13.1/widgets/bookmarks" + | "/docs/1.13.1/widgets/calendar" + | "/docs/1.13.1/widgets/clock" + | "/docs/1.13.1/widgets/dns-hole" + | "/docs/1.13.1/widgets/downloads" + | "/docs/1.13.1/widgets/health-monitoring" + | "/docs/1.13.1/widgets/home-assistant" + | "/docs/1.13.1/widgets/iframe" + | "/docs/1.13.1/widgets/indexer-manager" + | "/docs/1.13.1/widgets/media-requests" + | "/docs/1.13.1/widgets/media-server" + | "/docs/1.13.1/widgets/minecraft-server-status" + | "/docs/1.13.1/widgets/notebook" + | "/docs/1.13.1/widgets/rss" + | "/docs/1.13.1/widgets/stocks" + | "/docs/1.13.1/widgets/video" + | "/docs/1.13.1/widgets/weather" | "/docs/next/tags" | "/docs/next/tags/active-directory" | "/docs/next/tags/ad-guard" diff --git a/packages/definitions/src/integration.ts b/packages/definitions/src/integration.ts index ab2097f73..8e23e5127 100644 --- a/packages/definitions/src/integration.ts +++ b/packages/definitions/src/integration.ts @@ -157,6 +157,12 @@ export const integrationDefs = { category: ["calendar"], iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/nextcloud.svg", }, + unifiController: { + name: "Unifi Controller", + secretKinds: [["username", "password"]], + iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/png/unifi.png", + category: ["networkController"], + }, } as const satisfies Record; export const integrationKinds = objectKeys(integrationDefs) as AtLeastOneOf; @@ -209,4 +215,5 @@ export type IntegrationCategory = | "indexerManager" | "healthMonitoring" | "search" - | "mediaTranscoding"; + | "mediaTranscoding" + | "networkController"; diff --git a/packages/definitions/src/widget.ts b/packages/definitions/src/widget.ts index 7f586358c..aff019899 100644 --- a/packages/definitions/src/widget.ts +++ b/packages/definitions/src/widget.ts @@ -17,6 +17,8 @@ export const widgetKinds = [ "mediaRequests-requestStats", "mediaTranscoding", "minecraftServerStatus", + "networkControllerSummary", + "networkControllerStatus", "rssFeed", "bookmarks", "indexerManager", diff --git a/packages/docker/package.json b/packages/docker/package.json index 8cae93c69..bc8e1bfaa 100644 --- a/packages/docker/package.json +++ b/packages/docker/package.json @@ -32,7 +32,7 @@ "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", "@types/dockerode": "^3.3.37", - "eslint": "^9.23.0", - "typescript": "^5.8.2" + "eslint": "^9.24.0", + "typescript": "^5.8.3" } } diff --git a/packages/env/package.json b/packages/env/package.json index f13b22ae9..8cfe4db6b 100644 --- a/packages/env/package.json +++ b/packages/env/package.json @@ -30,7 +30,7 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.23.0", - "typescript": "^5.8.2" + "eslint": "^9.24.0", + "typescript": "^5.8.3" } } diff --git a/packages/form/package.json b/packages/form/package.json index eb8d9d604..1608fd927 100644 --- a/packages/form/package.json +++ b/packages/form/package.json @@ -26,14 +26,14 @@ "@homarr/common": "workspace:^0.1.0", "@homarr/translation": "workspace:^0.1.0", "@homarr/validation": "workspace:^0.1.0", - "@mantine/form": "^7.17.3", + "@mantine/form": "^7.17.4", "zod": "^3.24.2" }, "devDependencies": { "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.23.0", - "typescript": "^5.8.2" + "eslint": "^9.24.0", + "typescript": "^5.8.3" } } diff --git a/packages/form/src/index.ts b/packages/form/src/index.ts index 328315b5b..59192a2a6 100644 --- a/packages/form/src/index.ts +++ b/packages/form/src/index.ts @@ -3,7 +3,7 @@ import { z } from "zod"; import type { AnyZodObject, ZodDiscriminatedUnion, ZodEffects, ZodIntersection } from "zod"; import { useI18n } from "@homarr/translation/client"; -import { zodErrorMap } from "@homarr/validation/form"; +import { zodErrorMap } from "@homarr/validation/form/i18n"; export const useZodForm = < TSchema extends diff --git a/packages/forms-collection/package.json b/packages/forms-collection/package.json index bc86c2337..44cc819af 100644 --- a/packages/forms-collection/package.json +++ b/packages/forms-collection/package.json @@ -29,7 +29,7 @@ "@homarr/notifications": "workspace:^0.1.0", "@homarr/translation": "workspace:^0.1.0", "@homarr/validation": "workspace:^0.1.0", - "@mantine/core": "^7.17.3", + "@mantine/core": "^7.17.4", "react": "19.1.0", "zod": "^3.24.2" }, @@ -37,7 +37,7 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.23.0", - "typescript": "^5.8.2" + "eslint": "^9.24.0", + "typescript": "^5.8.3" } } diff --git a/packages/forms-collection/src/icon-picker/icon-picker.tsx b/packages/forms-collection/src/icon-picker/icon-picker.tsx index a571abbe2..aa18248d7 100644 --- a/packages/forms-collection/src/icon-picker/icon-picker.tsx +++ b/packages/forms-collection/src/icon-picker/icon-picker.tsx @@ -33,6 +33,9 @@ interface IconPickerProps { error?: string | null; onFocus?: FocusEventHandler; onBlur?: FocusEventHandler; + + label?: string; + placeholder?: string; withAsterisk?: boolean; } @@ -43,6 +46,8 @@ export const IconPicker = ({ onFocus, onBlur, withAsterisk = true, + label, + placeholder, }: IconPickerProps) => { const [value, setValue] = useUncontrolled({ value: propsValue, @@ -155,8 +160,8 @@ export const IconPicker = ({ rightSectionPointerEvents="none" withAsterisk={withAsterisk} error={error} - label={tCommon("iconPicker.label")} - placeholder={tCommon("iconPicker.header", { countIcons: String(data?.countIcons ?? 0) })} + label={label ?? tCommon("iconPicker.label")} + placeholder={placeholder ?? tCommon("iconPicker.header", { countIcons: String(data?.countIcons ?? 0) })} /> {session?.user.permissions.includes("media-upload") && ( , redirect: boolean, afterSuccess?: () => void) => { + (values: z.infer, redirect: boolean, afterSuccess?: () => void) => { mutate(values, { onSuccess() { showSuccessNotification({ diff --git a/packages/forms-collection/src/new-app/_form.tsx b/packages/forms-collection/src/new-app/_form.tsx index 146ed5151..559b2160a 100644 --- a/packages/forms-collection/src/new-app/_form.tsx +++ b/packages/forms-collection/src/new-app/_form.tsx @@ -10,12 +10,12 @@ import type { z } from "zod"; import { clientApi } from "@homarr/api/client"; import { useZodForm } from "@homarr/form"; import { useI18n } from "@homarr/translation/client"; -import { validation } from "@homarr/validation"; +import { appManageSchema } from "@homarr/validation/app"; import { IconPicker } from "../icon-picker/icon-picker"; import { findBestIconMatch } from "./icon-matcher"; -type FormType = z.infer; +type FormType = z.infer; interface AppFormProps { showBackToOverview: boolean; @@ -37,7 +37,7 @@ export const AppForm = ({ }: AppFormProps) => { const t = useI18n(); - const form = useZodForm(validation.app.manage, { + const form = useZodForm(appManageSchema, { initialValues: { name: initialValues?.name ?? "", description: initialValues?.description ?? "", diff --git a/packages/forms-collection/src/upload-media/upload-media.tsx b/packages/forms-collection/src/upload-media/upload-media.tsx index ca3305f1c..2d48e9004 100644 --- a/packages/forms-collection/src/upload-media/upload-media.tsx +++ b/packages/forms-collection/src/upload-media/upload-media.tsx @@ -5,7 +5,7 @@ import { clientApi } from "@homarr/api/client"; import type { MaybePromise } from "@homarr/common/types"; import { showErrorNotification, showSuccessNotification } from "@homarr/notifications"; import { useI18n } from "@homarr/translation/client"; -import { supportedMediaUploadFormats } from "@homarr/validation"; +import { supportedMediaUploadFormats } from "@homarr/validation/media"; interface UploadMediaProps { children: (props: { onClick: () => void; loading: boolean }) => JSX.Element; diff --git a/packages/icons/package.json b/packages/icons/package.json index 86b387af9..7445d6e6e 100644 --- a/packages/icons/package.json +++ b/packages/icons/package.json @@ -31,7 +31,7 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.23.0", - "typescript": "^5.8.2" + "eslint": "^9.24.0", + "typescript": "^5.8.3" } } diff --git a/packages/integrations/package.json b/packages/integrations/package.json index 5b51dc0fd..2cfffbb6d 100644 --- a/packages/integrations/package.json +++ b/packages/integrations/package.json @@ -48,7 +48,7 @@ "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", "@types/xml2js": "^0.4.14", - "eslint": "^9.23.0", - "typescript": "^5.8.2" + "eslint": "^9.24.0", + "typescript": "^5.8.3" } } diff --git a/packages/integrations/src/base/creator.ts b/packages/integrations/src/base/creator.ts index 7664e86bc..90467c71c 100644 --- a/packages/integrations/src/base/creator.ts +++ b/packages/integrations/src/base/creator.ts @@ -26,6 +26,7 @@ import { createPiHoleIntegrationAsync } from "../pi-hole/pi-hole-integration-fac import { PlexIntegration } from "../plex/plex-integration"; import { ProwlarrIntegration } from "../prowlarr/prowlarr-integration"; import { ProxmoxIntegration } from "../proxmox/proxmox-integration"; +import { UnifiControllerIntegration } from "../unifi-controller/unifi-controller-integration"; import type { Integration, IntegrationInput } from "./integration"; export const createIntegrationAsync = async ( @@ -88,6 +89,7 @@ export const integrationCreators = { proxmox: ProxmoxIntegration, emby: EmbyIntegration, nextcloud: NextcloudIntegration, + unifiController: UnifiControllerIntegration, } satisfies Record Promise]>; type IntegrationInstanceOfKind = { diff --git a/packages/integrations/src/base/integration.ts b/packages/integrations/src/base/integration.ts index cfab939f6..b3c1141e6 100644 --- a/packages/integrations/src/base/integration.ts +++ b/packages/integrations/src/base/integration.ts @@ -114,7 +114,7 @@ export type TestConnectionResult = success: true; }; -const throwErrorByStatusCode = (statusCode: number) => { +export const throwErrorByStatusCode = (statusCode: number) => { switch (statusCode) { case 400: throw new IntegrationTestConnectionError("badRequest"); @@ -124,6 +124,8 @@ const throwErrorByStatusCode = (statusCode: number) => { throw new IntegrationTestConnectionError("forbidden"); case 404: throw new IntegrationTestConnectionError("notFound"); + case 429: + throw new IntegrationTestConnectionError("tooManyRequests"); case 500: throw new IntegrationTestConnectionError("internalServerError"); case 503: diff --git a/packages/integrations/src/interfaces/network-controller-summary/network-controller-summary-integration.ts b/packages/integrations/src/interfaces/network-controller-summary/network-controller-summary-integration.ts new file mode 100644 index 000000000..3f21e1dff --- /dev/null +++ b/packages/integrations/src/interfaces/network-controller-summary/network-controller-summary-integration.ts @@ -0,0 +1,5 @@ +import type { NetworkControllerSummary } from "./network-controller-summary-types"; + +export interface NetworkControllerSummaryIntegration { + getNetworkSummaryAsync(): Promise; +} diff --git a/packages/integrations/src/interfaces/network-controller-summary/network-controller-summary-types.ts b/packages/integrations/src/interfaces/network-controller-summary/network-controller-summary-types.ts new file mode 100644 index 000000000..587b5470d --- /dev/null +++ b/packages/integrations/src/interfaces/network-controller-summary/network-controller-summary-types.ts @@ -0,0 +1,27 @@ +export interface NetworkControllerSummary { + wanStatus: "enabled" | "disabled"; + + www: { + status: "enabled" | "disabled"; + latency: number; + ping: number; + uptime: number; + }; + + wifi: { + status: "enabled" | "disabled"; + users: number; + guests: number; + }; + + lan: { + status: "enabled" | "disabled"; + users: number; + guests: number; + }; + + vpn: { + status: "enabled" | "disabled"; + users: number; + }; +} diff --git a/packages/integrations/src/types.ts b/packages/integrations/src/types.ts index 66a3d0de2..2262164c4 100644 --- a/packages/integrations/src/types.ts +++ b/packages/integrations/src/types.ts @@ -1,8 +1,10 @@ export * from "./calendar-types"; export * from "./interfaces/dns-hole-summary/dns-hole-summary-types"; +export * from "./interfaces/network-controller-summary/network-controller-summary-types"; export * from "./interfaces/health-monitoring/healt-monitoring"; export * from "./interfaces/indexer-manager/indexer"; export * from "./interfaces/media-requests/media-request"; export * from "./base/searchable-integration"; export * from "./homeassistant/homeassistant-types"; export * from "./proxmox/proxmox-types"; +export * from "./unifi-controller/unifi-controller-types"; diff --git a/packages/integrations/src/unifi-controller/unifi-controller-integration.ts b/packages/integrations/src/unifi-controller/unifi-controller-integration.ts new file mode 100644 index 000000000..06e45adae --- /dev/null +++ b/packages/integrations/src/unifi-controller/unifi-controller-integration.ts @@ -0,0 +1,228 @@ +import type z from "zod"; + +import { fetchWithTrustedCertificatesAsync } from "@homarr/certificates/server"; +import { logger } from "@homarr/log"; + +import { ParseError } from "../base/error"; +import { Integration, throwErrorByStatusCode } from "../base/integration"; +import { IntegrationTestConnectionError } from "../base/test-connection-error"; +import type { NetworkControllerSummaryIntegration } from "../interfaces/network-controller-summary/network-controller-summary-integration"; +import type { NetworkControllerSummary } from "../interfaces/network-controller-summary/network-controller-summary-types"; +import { unifiSummaryResponseSchema } from "./unifi-controller-types"; + +const udmpPrefix = "proxy/network"; +type Subsystem = "www" | "wan" | "wlan" | "lan" | "vpn"; + +export class UnifiControllerIntegration extends Integration implements NetworkControllerSummaryIntegration { + private prefix: string | undefined; + + public async getNetworkSummaryAsync(): Promise { + if (!this.headers) { + await this.authenticateAndConstructSessionInHeaderAsync(); + } + + const requestUrl = this.url(`/${this.prefix}/api/stat/sites`); + + const requestHeaders: Record = { + "Content-Type": "application/json", + ...this.headers, + }; + if (this.csrfToken) { + requestHeaders["X-CSRF-TOKEN"] = this.csrfToken; + } + + const statsResponse = await fetchWithTrustedCertificatesAsync(requestUrl, { + method: "GET", + headers: { + ...requestHeaders, + }, + }).catch((err: TypeError) => { + const detailMessage = String(err.cause); + throw new IntegrationTestConnectionError("invalidUrl", detailMessage); + }); + + if (!statsResponse.ok) { + throwErrorByStatusCode(statsResponse.status); + } + + const result = unifiSummaryResponseSchema.safeParse(await statsResponse.json()); + + if (!result.success) { + throw new ParseError("Unifi controller", result.error); + } + + return { + wanStatus: this.getStatusValueOverAllSites(result.data, "wan", (site) => site.status === "ok"), + www: { + status: this.getStatusValueOverAllSites(result.data, "wan", (site) => site.status === "ok"), + latency: this.getNumericValueOverAllSites(result.data, "www", (site) => site.latency, "max"), + ping: this.getNumericValueOverAllSites(result.data, "www", (site) => site.speedtest_ping, "max"), + uptime: this.getNumericValueOverAllSites(result.data, "www", (site) => site.uptime, "max"), + }, + wifi: { + status: this.getStatusValueOverAllSites(result.data, "wlan", (site) => site.status === "ok"), + users: this.getNumericValueOverAllSites(result.data, "wlan", (site) => site.num_user, "sum"), + guests: this.getNumericValueOverAllSites(result.data, "wlan", (site) => site.num_guest, "sum"), + }, + lan: { + status: this.getStatusValueOverAllSites(result.data, "lan", (site) => site.status === "ok"), + users: this.getNumericValueOverAllSites(result.data, "lan", (site) => site.num_user, "sum"), + guests: this.getNumericValueOverAllSites(result.data, "lan", (site) => site.num_guest, "sum"), + }, + vpn: { + status: this.getStatusValueOverAllSites(result.data, "vpn", (site) => site.status === "ok"), + users: this.getNumericValueOverAllSites(result.data, "vpn", (site) => site.remote_user_num_active, "sum"), + }, + } satisfies NetworkControllerSummary; + } + + public async testConnectionAsync(): Promise { + await this.authenticateAndConstructSessionInHeaderAsync(); + } + + private getStatusValueOverAllSites( + data: z.infer, + subsystem: Subsystem, + selectCallback: (obj: z.infer["data"][number]["health"][number]) => boolean, + ) { + return this.getBooleanValueOverAllSites(data, subsystem, selectCallback) ? "enabled" : "disabled"; + } + + private getNumericValueOverAllSites< + S extends Subsystem, + T extends Extract["data"][number]["health"][number], { subsystem: S }>, + >( + data: z.infer, + subsystem: S, + selectCallback: (obj: T) => number, + strategy: "average" | "sum" | "max", + ): number { + const values = data.data.map((site) => selectCallback(this.getSubsystem(site.health, subsystem) as T)); + + if (strategy === "sum") { + return values.reduce((first, second) => first + second, 0); + } + + if (strategy === "average") { + return values.reduce((first, second, _, array) => first + second / array.length, 0); + } + + return Math.max(...values); + } + + private getBooleanValueOverAllSites( + data: z.infer, + subsystem: Subsystem, + selectCallback: (obj: z.infer["data"][number]["health"][number]) => boolean, + ): boolean { + return data.data.every((site) => selectCallback(this.getSubsystem(site.health, subsystem))); + } + + private getSubsystem( + health: z.infer["data"][number]["health"], + subsystem: Subsystem, + ) { + const value = health.find((health) => health.subsystem === subsystem); + if (!value) { + throw new Error(`Subsystem ${subsystem} not found!`); + } + return value; + } + + private headers: Record | undefined = undefined; + private csrfToken: string | undefined; + + private async authenticateAndConstructSessionInHeaderAsync(): Promise { + await this.determineUDMVariantAsync(); + await this.authenticateAndSetCookieAsync(); + } + + private async authenticateAndSetCookieAsync(): Promise { + if (this.headers) { + return; + } + + const endpoint = this.prefix === udmpPrefix ? "auth/login" : "login"; + logger.debug("Authenticating at network console: " + endpoint); + + const loginUrl = this.url(`/api/${endpoint}`); + + const loginBody = { + username: this.getSecretValue("username"), + password: this.getSecretValue("password"), + remember: true, + }; + + const requestHeaders: Record = { "Content-Type": "application/json" }; + if (this.csrfToken) { + requestHeaders["X-CSRF-TOKEN"] = this.csrfToken; + } + + const loginResponse = await fetchWithTrustedCertificatesAsync(loginUrl, { + method: "POST", + headers: { + ...requestHeaders, + }, + body: JSON.stringify(loginBody), + }).catch((err: TypeError) => { + const detailMessage = String(err.cause); + throw new IntegrationTestConnectionError("invalidUrl", detailMessage); + }); + + if (!loginResponse.ok) { + throwErrorByStatusCode(loginResponse.status); + } + + const responseHeaders = loginResponse.headers; + const newHeaders: Record = {}; + const loginToken = UnifiControllerIntegration.extractLoginTokenFromCookies(responseHeaders); + newHeaders.Cookie = `${loginToken};`; + this.headers = newHeaders; + } + + private async determineUDMVariantAsync(): Promise { + if (this.prefix) { + return; + } + + logger.debug("Prefix for authentication not set; initial connect to determine UDM variant"); + const url = this.url("/"); + + const { status, ok, headers } = await fetchWithTrustedCertificatesAsync(url, { method: "HEAD" }) + .then((res) => res) + .catch((err: TypeError) => { + const detailMessage = String(err.cause); + throw new IntegrationTestConnectionError("invalidUrl", detailMessage); + }); + + if (!ok) { + throw new IntegrationTestConnectionError("invalidUrl", "status code: " + status); + } + + let prefix = ""; + if (headers.get("x-csrf-token") !== null) { + // Unifi OS < 3.2.5 passes & requires csrf-token + prefix = udmpPrefix; + const headersCSRFToken = headers.get("x-csrf-token"); + if (headersCSRFToken) { + this.csrfToken = headersCSRFToken; + } + } else if (headers.get("access-control-expose-headers") !== null) { + // Unifi OS ≥ 3.2.5 doesnt pass csrf token but still uses different endpoint + prefix = udmpPrefix; + } + this.prefix = prefix; + logger.debug("Final prefix: " + this.prefix); + } + + private static extractLoginTokenFromCookies(headers: Headers): string { + const cookies = headers.get("set-cookie") ?? ""; + const loginToken = cookies.split(";").find((cookie) => cookie.includes("TOKEN")); + + if (loginToken) { + return loginToken; + } + + throw new Error("Login token not found in cookies"); + } +} diff --git a/packages/integrations/src/unifi-controller/unifi-controller-types.ts b/packages/integrations/src/unifi-controller/unifi-controller-types.ts new file mode 100644 index 000000000..cbca72820 --- /dev/null +++ b/packages/integrations/src/unifi-controller/unifi-controller-types.ts @@ -0,0 +1,130 @@ +import { z } from "zod"; + +export const healthSchema = z.discriminatedUnion("subsystem", [ + z.object({ + subsystem: z.literal("wlan"), + num_user: z.number(), + num_guest: z.number(), + num_iot: z.number(), + "tx_bytes-r": z.number(), + "rx_bytes-r": z.number(), + status: z.string(), + num_ap: z.number(), + num_adopted: z.number(), + num_disabled: z.number(), + num_disconnected: z.number(), + num_pending: z.number(), + }), + z.object({ + subsystem: z.literal("wan"), + num_gw: z.number(), + num_adopted: z.number(), + num_disconnected: z.number(), + num_pending: z.number(), + status: z.string(), + wan_ip: z.string().ip(), + gateways: z.array(z.string().ip()), + netmask: z.string().ip(), + nameservers: z.array(z.string().ip()).optional(), + num_sta: z.number(), + "tx_bytes-r": z.number(), + "rx_bytes-r": z.number(), + gw_mac: z.string(), + gw_name: z.string(), + "gw_system-stats": z.object({ + cpu: z.string(), + mem: z.string(), + uptime: z.string(), + }), + gw_version: z.string(), + isp_name: z.string(), + isp_organization: z.string(), + uptime_stats: z.object({ + WAN: z.object({ + alerting_monitors: z.array( + z.object({ + availability: z.number(), + latency_average: z.number(), + target: z.string(), + type: z.enum(["icmp", "dns"]), + }), + ), + availability: z.number(), + latency_average: z.number(), + monitors: z.array( + z.object({ + availability: z.number(), + latency_average: z.number(), + target: z.string(), + type: z.enum(["icmp", "dns"]), + }), + ), + time_period: z.number(), + uptime: z.number(), + }), + }), + }), + z.object({ + subsystem: z.literal("www"), + status: z.string(), + "tx_bytes-r": z.number(), + "rx_bytes-r": z.number(), + latency: z.number(), + uptime: z.number(), + drops: z.number(), + xput_up: z.number(), + xput_down: z.number(), + speedtest_status: z.string(), + speedtest_lastrun: z.number(), + speedtest_ping: z.number(), + gw_mac: z.string(), + }), + z.object({ + subsystem: z.literal("lan"), + lan_ip: z.string().ip().nullish(), + status: z.string(), + num_user: z.number(), + num_guest: z.number(), + num_iot: z.number(), + "tx_bytes-r": z.number(), + "rx_bytes-r": z.number(), + num_sw: z.number(), + num_adopted: z.number(), + num_disconnected: z.number(), + num_pending: z.number(), + }), + z.object({ + subsystem: z.literal("vpn"), + status: z.string(), + remote_user_enabled: z.boolean(), + remote_user_num_active: z.number(), + remote_user_num_inactive: z.number(), + remote_user_rx_bytes: z.number(), + remote_user_tx_bytes: z.number(), + remote_user_rx_packets: z.number(), + remote_user_tx_packets: z.number(), + site_to_site_enabled: z.boolean(), + }), +]); + +export type Health = z.infer; + +export const siteSchema = z.object({ + anonymous_id: z.string().uuid(), + name: z.string(), + external_id: z.string().uuid(), + _id: z.string(), + attr_no_delete: z.boolean(), + attr_hidden_id: z.string(), + desc: z.string(), + health: z.array(healthSchema), + num_new_alarms: z.number(), +}); +export type Site = z.infer; + +export const unifiSummaryResponseSchema = z.object({ + meta: z.object({ + rc: z.enum(["ok"]), + }), + data: z.array(siteSchema), +}); diff --git a/packages/log/package.json b/packages/log/package.json index d41775252..79cf2cac1 100644 --- a/packages/log/package.json +++ b/packages/log/package.json @@ -33,7 +33,7 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.23.0", - "typescript": "^5.8.2" + "eslint": "^9.24.0", + "typescript": "^5.8.3" } } diff --git a/packages/modals-collection/package.json b/packages/modals-collection/package.json index 9b0fb58a6..4aa4dd932 100644 --- a/packages/modals-collection/package.json +++ b/packages/modals-collection/package.json @@ -33,10 +33,10 @@ "@homarr/translation": "workspace:^0.1.0", "@homarr/ui": "workspace:^0.1.0", "@homarr/validation": "workspace:^0.1.0", - "@mantine/core": "^7.17.3", + "@mantine/core": "^7.17.4", "@tabler/icons-react": "^3.31.0", "dayjs": "^1.11.13", - "next": "15.2.4", + "next": "15.2.5", "react": "19.1.0", "react-dom": "19.1.0", "zod": "^3.24.2" @@ -45,7 +45,7 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.23.0", - "typescript": "^5.8.2" + "eslint": "^9.24.0", + "typescript": "^5.8.3" } } diff --git a/packages/modals-collection/src/apps/quick-add-app/quick-add-app-modal.tsx b/packages/modals-collection/src/apps/quick-add-app/quick-add-app-modal.tsx index 5e007821e..9f2e5e290 100644 --- a/packages/modals-collection/src/apps/quick-add-app/quick-add-app-modal.tsx +++ b/packages/modals-collection/src/apps/quick-add-app/quick-add-app-modal.tsx @@ -5,7 +5,7 @@ import { AppForm } from "@homarr/forms-collection"; import { createModal } from "@homarr/modals"; import { showErrorNotification, showSuccessNotification } from "@homarr/notifications"; import { useI18n, useScopedI18n } from "@homarr/translation/client"; -import type { validation } from "@homarr/validation"; +import type { appManageSchema } from "@homarr/validation/app"; interface QuickAddAppModalProps { onClose: (createdAppId: string) => Promise; @@ -24,7 +24,7 @@ export const QuickAddAppModal = createModal(({ actions, i }, }); - const handleSubmit = (values: z.infer) => { + const handleSubmit = (values: z.infer) => { mutate(values, { async onSuccess({ appId }) { showSuccessNotification({ diff --git a/packages/modals-collection/src/boards/add-board-modal.tsx b/packages/modals-collection/src/boards/add-board-modal.tsx index 45990aad0..83a5d3509 100644 --- a/packages/modals-collection/src/boards/add-board-modal.tsx +++ b/packages/modals-collection/src/boards/add-board-modal.tsx @@ -8,11 +8,11 @@ import { useZodForm } from "@homarr/form"; import { createModal } from "@homarr/modals"; import { showErrorNotification, showSuccessNotification } from "@homarr/notifications"; import { useI18n } from "@homarr/translation/client"; -import { validation } from "@homarr/validation"; +import { boardColumnCountSchema, boardCreateSchema, boardNameSchema } from "@homarr/validation/board"; export const AddBoardModal = createModal(({ actions }) => { const t = useI18n(); - const form = useZodForm(validation.board.create, { + const form = useZodForm(boardCreateSchema, { mode: "controlled", initialValues: { name: "", @@ -28,7 +28,7 @@ export const AddBoardModal = createModal(({ actions }) => { const boardNameStatus = useBoardNameStatus(form.values.name); - const columnCountChecks = validation.board.create.shape.columnCount._def.checks; + const columnCountChecks = boardColumnCountSchema._def.checks; const minColumnCount = columnCountChecks.find((check) => check.kind === "min")?.value; const maxColumnCount = columnCountChecks.find((check) => check.kind === "max")?.value; @@ -97,7 +97,7 @@ export const useBoardNameStatus = (name: string) => { const t = useI18n(); const [debouncedName] = useDebouncedValue(name, 250); const { data: boardExists, isLoading } = clientApi.board.exists.useQuery(debouncedName, { - enabled: validation.board.create.shape.name.safeParse(debouncedName).success, + enabled: boardNameSchema.safeParse(debouncedName).success, }); return { diff --git a/packages/modals-collection/src/boards/duplicate-board-modal.tsx b/packages/modals-collection/src/boards/duplicate-board-modal.tsx index 083cb716b..441e16edf 100644 --- a/packages/modals-collection/src/boards/duplicate-board-modal.tsx +++ b/packages/modals-collection/src/boards/duplicate-board-modal.tsx @@ -5,7 +5,7 @@ import type { MaybePromise } from "@homarr/common/types"; import { useZodForm } from "@homarr/form"; import { showErrorNotification, showSuccessNotification } from "@homarr/notifications"; import { useI18n } from "@homarr/translation/client"; -import { validation } from "@homarr/validation"; +import { boardDuplicateSchema } from "@homarr/validation/board"; import { createModal } from "../../../modals/src/creator"; import { useBoardNameStatus } from "./add-board-modal"; @@ -20,7 +20,7 @@ interface InnerProps { export const DuplicateBoardModal = createModal(({ actions, innerProps }) => { const t = useI18n(); - const form = useZodForm(validation.board.duplicate.omit({ id: true }), { + const form = useZodForm(boardDuplicateSchema.omit({ id: true }), { mode: "controlled", initialValues: { name: innerProps.board.name, diff --git a/packages/modals-collection/src/groups/add-group-modal.tsx b/packages/modals-collection/src/groups/add-group-modal.tsx index 2ba0af1a3..178d89581 100644 --- a/packages/modals-collection/src/groups/add-group-modal.tsx +++ b/packages/modals-collection/src/groups/add-group-modal.tsx @@ -6,12 +6,12 @@ import { useZodForm } from "@homarr/form"; import { createModal } from "@homarr/modals"; import { showErrorNotification, showSuccessNotification } from "@homarr/notifications"; import { useI18n } from "@homarr/translation/client"; -import { validation } from "@homarr/validation"; +import { groupCreateSchema } from "@homarr/validation/group"; export const AddGroupModal = createModal(({ actions }) => { const t = useI18n(); const { mutate, isPending } = clientApi.group.createGroup.useMutation(); - const form = useZodForm(validation.group.create, { + const form = useZodForm(groupCreateSchema, { initialValues: { name: "", }, diff --git a/packages/modals/package.json b/packages/modals/package.json index af9c36f15..792cf1279 100644 --- a/packages/modals/package.json +++ b/packages/modals/package.json @@ -24,15 +24,15 @@ "dependencies": { "@homarr/translation": "workspace:^0.1.0", "@homarr/ui": "workspace:^0.1.0", - "@mantine/core": "^7.17.3", - "@mantine/hooks": "^7.17.3", + "@mantine/core": "^7.17.4", + "@mantine/hooks": "^7.17.4", "react": "19.1.0" }, "devDependencies": { "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.23.0", - "typescript": "^5.8.2" + "eslint": "^9.24.0", + "typescript": "^5.8.3" } } diff --git a/packages/notifications/package.json b/packages/notifications/package.json index 2e5bd0d7e..02738687c 100644 --- a/packages/notifications/package.json +++ b/packages/notifications/package.json @@ -24,14 +24,14 @@ "prettier": "@homarr/prettier-config", "dependencies": { "@homarr/ui": "workspace:^0.1.0", - "@mantine/notifications": "^7.17.3", + "@mantine/notifications": "^7.17.4", "@tabler/icons-react": "^3.31.0" }, "devDependencies": { "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.23.0", - "typescript": "^5.8.2" + "eslint": "^9.24.0", + "typescript": "^5.8.3" } } diff --git a/packages/old-import/package.json b/packages/old-import/package.json index e86656bbe..1ebb11bac 100644 --- a/packages/old-import/package.json +++ b/packages/old-import/package.json @@ -37,10 +37,10 @@ "@homarr/translation": "workspace:^0.1.0", "@homarr/ui": "workspace:^0.1.0", "@homarr/validation": "workspace:^0.1.0", - "@mantine/core": "^7.17.3", - "@mantine/hooks": "^7.17.3", + "@mantine/core": "^7.17.4", + "@mantine/hooks": "^7.17.4", "adm-zip": "0.5.16", - "next": "15.2.4", + "next": "15.2.5", "react": "19.1.0", "react-dom": "19.1.0", "superjson": "2.2.2", @@ -52,7 +52,7 @@ "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", "@types/adm-zip": "0.5.7", - "eslint": "^9.23.0", - "typescript": "^5.8.2" + "eslint": "^9.24.0", + "typescript": "^5.8.3" } } diff --git a/packages/old-import/src/settings.ts b/packages/old-import/src/settings.ts index 9c2fb2f9e..a4944562b 100644 --- a/packages/old-import/src/settings.ts +++ b/packages/old-import/src/settings.ts @@ -1,15 +1,15 @@ import { z } from "zod"; import { zfd } from "zod-form-data"; -import { validation } from "@homarr/validation"; -import { createCustomErrorParams } from "@homarr/validation/form"; +import { boardNameSchema } from "@homarr/validation/board"; +import { createCustomErrorParams } from "@homarr/validation/form/i18n"; export const sidebarBehaviours = ["remove-items", "last-section"] as const; export const defaultSidebarBehaviour = "last-section"; export type SidebarBehaviour = (typeof sidebarBehaviours)[number]; export const oldmarrImportConfigurationSchema = z.object({ - name: validation.board.name, + name: boardNameSchema, onlyImportApps: z.boolean().default(false), sidebarBehaviour: z.enum(sidebarBehaviours).default(defaultSidebarBehaviour), }); diff --git a/packages/old-schema/package.json b/packages/old-schema/package.json index 23ccfe8d3..1da45db01 100644 --- a/packages/old-schema/package.json +++ b/packages/old-schema/package.json @@ -29,7 +29,7 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.23.0", - "typescript": "^5.8.2" + "eslint": "^9.24.0", + "typescript": "^5.8.3" } } diff --git a/packages/ping/package.json b/packages/ping/package.json index 8caba6d05..654993489 100644 --- a/packages/ping/package.json +++ b/packages/ping/package.json @@ -31,7 +31,7 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.23.0", - "typescript": "^5.8.2" + "eslint": "^9.24.0", + "typescript": "^5.8.3" } } diff --git a/packages/redis/package.json b/packages/redis/package.json index 5dc362c90..98e1f2eee 100644 --- a/packages/redis/package.json +++ b/packages/redis/package.json @@ -33,7 +33,7 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.23.0", - "typescript": "^5.8.2" + "eslint": "^9.24.0", + "typescript": "^5.8.3" } } diff --git a/packages/request-handler/package.json b/packages/request-handler/package.json index 5483e469c..14c27dd9a 100644 --- a/packages/request-handler/package.json +++ b/packages/request-handler/package.json @@ -38,7 +38,7 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.23.0", - "typescript": "^5.8.2" + "eslint": "^9.24.0", + "typescript": "^5.8.3" } } diff --git a/packages/request-handler/src/network-controller.ts b/packages/request-handler/src/network-controller.ts new file mode 100644 index 000000000..f5975acf2 --- /dev/null +++ b/packages/request-handler/src/network-controller.ts @@ -0,0 +1,20 @@ +import dayjs from "dayjs"; + +import type { IntegrationKindByCategory } from "@homarr/definitions"; +import { createIntegrationAsync } from "@homarr/integrations"; +import type { NetworkControllerSummary } from "@homarr/integrations/types"; + +import { createCachedIntegrationRequestHandler } from "./lib/cached-integration-request-handler"; + +export const networkControllerRequestHandler = createCachedIntegrationRequestHandler< + NetworkControllerSummary, + IntegrationKindByCategory<"networkController">, + Record +>({ + async requestAsync(integration, _input) { + const integrationInstance = await createIntegrationAsync(integration); + return await integrationInstance.getNetworkSummaryAsync(); + }, + cacheDuration: dayjs.duration(5, "minutes"), + queryKey: "networkControllerSummary", +}); diff --git a/packages/server-settings/package.json b/packages/server-settings/package.json index 1aa5f0b0f..cccdc5d3f 100644 --- a/packages/server-settings/package.json +++ b/packages/server-settings/package.json @@ -29,7 +29,7 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.23.0", - "typescript": "^5.8.2" + "eslint": "^9.24.0", + "typescript": "^5.8.3" } } diff --git a/packages/settings/package.json b/packages/settings/package.json index c876758c7..812b230d7 100644 --- a/packages/settings/package.json +++ b/packages/settings/package.json @@ -25,8 +25,8 @@ "@homarr/api": "workspace:^0.1.0", "@homarr/db": "workspace:^0.1.0", "@homarr/server-settings": "workspace:^0.1.0", - "@mantine/dates": "^7.17.3", - "next": "15.2.4", + "@mantine/dates": "^7.17.4", + "next": "15.2.5", "react": "19.1.0", "react-dom": "19.1.0" }, @@ -34,7 +34,7 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.23.0", - "typescript": "^5.8.2" + "eslint": "^9.24.0", + "typescript": "^5.8.3" } } diff --git a/packages/spotlight/package.json b/packages/spotlight/package.json index dc800c9f4..e886f763d 100644 --- a/packages/spotlight/package.json +++ b/packages/spotlight/package.json @@ -33,12 +33,12 @@ "@homarr/settings": "workspace:^0.1.0", "@homarr/translation": "workspace:^0.1.0", "@homarr/ui": "workspace:^0.1.0", - "@mantine/core": "^7.17.3", - "@mantine/hooks": "^7.17.3", - "@mantine/spotlight": "^7.17.3", + "@mantine/core": "^7.17.4", + "@mantine/hooks": "^7.17.4", + "@mantine/spotlight": "^7.17.4", "@tabler/icons-react": "^3.31.0", "jotai": "^2.12.2", - "next": "15.2.4", + "next": "15.2.5", "react": "19.1.0", "react-dom": "19.1.0", "use-deep-compare-effect": "^1.8.1" @@ -47,7 +47,7 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.23.0", - "typescript": "^5.8.2" + "eslint": "^9.24.0", + "typescript": "^5.8.3" } } diff --git a/packages/translation/package.json b/packages/translation/package.json index f1353173f..0f19e1104 100644 --- a/packages/translation/package.json +++ b/packages/translation/package.json @@ -32,7 +32,7 @@ "dayjs": "^1.11.13", "deepmerge": "4.3.1", "mantine-react-table": "2.0.0-beta.9", - "next": "15.2.4", + "next": "15.2.5", "next-intl": "4.0.2", "react": "19.1.0", "react-dom": "19.1.0" @@ -41,7 +41,7 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.23.0", - "typescript": "^5.8.2" + "eslint": "^9.24.0", + "typescript": "^5.8.3" } } diff --git a/packages/translation/src/lang/ca.json b/packages/translation/src/lang/ca.json index d9788e2d0..c61f6f889 100644 --- a/packages/translation/src/lang/ca.json +++ b/packages/translation/src/lang/ca.json @@ -757,6 +757,10 @@ "wrongPath": { "title": "", "message": "" + }, + "tooManyRequests": { + "title": "", + "message": "" } } }, @@ -2026,6 +2030,62 @@ "label": "" } } + }, + "networkControllerSummary": { + "option": {}, + "card": { + "vpn": { + "countConnected": "" + } + }, + "error": { + "integrationsDisconnected": "", + "unknownContentOption": "" + }, + "name": "", + "description": "" + }, + "networkControllerStatus": { + "card": { + "variants": { + "wired": { + "name": "" + }, + "wifi": { + "name": "" + } + }, + "users": { + "label": "" + }, + "guests": { + "label": "" + } + }, + "option": { + "content": { + "option": { + "wifi": { + "label": "" + }, + "wired": { + "label": "" + } + }, + "label": "" + } + }, + "error": { + "integrationsDisconnected": "", + "unknownContentOption": "" + }, + "name": "", + "description": "" + }, + "networkController": { + "error": { + "internalServerError": "" + } } }, "widgetPreview": { @@ -2146,7 +2206,12 @@ "label": "" }, "backgroundImageUrl": { - "label": "" + "label": "", + "placeholder": "", + "group": { + "your": "", + "other": "" + } }, "backgroundImageAttachment": { "label": "", @@ -2782,6 +2847,9 @@ }, "mediaTranscoding": { "label": "" + }, + "networkController": { + "label": "" } } }, diff --git a/packages/translation/src/lang/cn.json b/packages/translation/src/lang/cn.json index f064fbf92..aa6da7f9e 100644 --- a/packages/translation/src/lang/cn.json +++ b/packages/translation/src/lang/cn.json @@ -757,6 +757,10 @@ "wrongPath": { "title": "路径错误", "message": "该路径可能不正确" + }, + "tooManyRequests": { + "title": "", + "message": "" } } }, @@ -2026,6 +2030,62 @@ "label": "帖子数量限制" } } + }, + "networkControllerSummary": { + "option": {}, + "card": { + "vpn": { + "countConnected": "" + } + }, + "error": { + "integrationsDisconnected": "", + "unknownContentOption": "" + }, + "name": "", + "description": "" + }, + "networkControllerStatus": { + "card": { + "variants": { + "wired": { + "name": "" + }, + "wifi": { + "name": "" + } + }, + "users": { + "label": "" + }, + "guests": { + "label": "" + } + }, + "option": { + "content": { + "option": { + "wifi": { + "label": "" + }, + "wired": { + "label": "" + } + }, + "label": "" + } + }, + "error": { + "integrationsDisconnected": "", + "unknownContentOption": "" + }, + "name": "", + "description": "" + }, + "networkController": { + "error": { + "internalServerError": "" + } } }, "widgetPreview": { @@ -2146,7 +2206,12 @@ "label": "Favicon 图像 URL" }, "backgroundImageUrl": { - "label": "背景图片 URL" + "label": "背景图片 URL", + "placeholder": "", + "group": { + "your": "", + "other": "" + } }, "backgroundImageAttachment": { "label": "背景图片附件", @@ -2782,6 +2847,9 @@ }, "mediaTranscoding": { "label": "媒体转码" + }, + "networkController": { + "label": "" } } }, diff --git a/packages/translation/src/lang/cs.json b/packages/translation/src/lang/cs.json index 18cbef6d3..d801402de 100644 --- a/packages/translation/src/lang/cs.json +++ b/packages/translation/src/lang/cs.json @@ -757,6 +757,10 @@ "wrongPath": { "title": "", "message": "Cesta pravděpodobně není správná" + }, + "tooManyRequests": { + "title": "", + "message": "" } } }, @@ -2026,6 +2030,62 @@ "label": "" } } + }, + "networkControllerSummary": { + "option": {}, + "card": { + "vpn": { + "countConnected": "" + } + }, + "error": { + "integrationsDisconnected": "", + "unknownContentOption": "" + }, + "name": "", + "description": "" + }, + "networkControllerStatus": { + "card": { + "variants": { + "wired": { + "name": "" + }, + "wifi": { + "name": "" + } + }, + "users": { + "label": "" + }, + "guests": { + "label": "" + } + }, + "option": { + "content": { + "option": { + "wifi": { + "label": "" + }, + "wired": { + "label": "" + } + }, + "label": "" + } + }, + "error": { + "integrationsDisconnected": "", + "unknownContentOption": "" + }, + "name": "", + "description": "" + }, + "networkController": { + "error": { + "internalServerError": "" + } } }, "widgetPreview": { @@ -2146,7 +2206,12 @@ "label": "URL obrázku Favicon" }, "backgroundImageUrl": { - "label": "Adresa URL obrázku na pozadí" + "label": "Adresa URL obrázku na pozadí", + "placeholder": "", + "group": { + "your": "", + "other": "" + } }, "backgroundImageAttachment": { "label": "Příloha obrázku na pozadí", @@ -2782,6 +2847,9 @@ }, "mediaTranscoding": { "label": "" + }, + "networkController": { + "label": "" } } }, diff --git a/packages/translation/src/lang/da.json b/packages/translation/src/lang/da.json index 0e53e09c5..b914f530b 100644 --- a/packages/translation/src/lang/da.json +++ b/packages/translation/src/lang/da.json @@ -757,6 +757,10 @@ "wrongPath": { "title": "Forkert sti", "message": "Stien er sandsynligvis ikke korrekt" + }, + "tooManyRequests": { + "title": "", + "message": "" } } }, @@ -2026,6 +2030,62 @@ "label": "Grænse for antal indlæg" } } + }, + "networkControllerSummary": { + "option": {}, + "card": { + "vpn": { + "countConnected": "" + } + }, + "error": { + "integrationsDisconnected": "", + "unknownContentOption": "" + }, + "name": "", + "description": "" + }, + "networkControllerStatus": { + "card": { + "variants": { + "wired": { + "name": "" + }, + "wifi": { + "name": "" + } + }, + "users": { + "label": "" + }, + "guests": { + "label": "" + } + }, + "option": { + "content": { + "option": { + "wifi": { + "label": "" + }, + "wired": { + "label": "" + } + }, + "label": "" + } + }, + "error": { + "integrationsDisconnected": "", + "unknownContentOption": "" + }, + "name": "", + "description": "" + }, + "networkController": { + "error": { + "internalServerError": "" + } } }, "widgetPreview": { @@ -2146,7 +2206,12 @@ "label": "Favicon billede URL" }, "backgroundImageUrl": { - "label": "Baggrundsbillede URL" + "label": "Baggrundsbillede URL", + "placeholder": "", + "group": { + "your": "", + "other": "" + } }, "backgroundImageAttachment": { "label": "Vedhæftning af baggrundsbillede", @@ -2782,6 +2847,9 @@ }, "mediaTranscoding": { "label": "Omkodning af medier" + }, + "networkController": { + "label": "" } } }, diff --git a/packages/translation/src/lang/de-CH.json b/packages/translation/src/lang/de-CH.json index bf51da1e9..3b39d670b 100644 --- a/packages/translation/src/lang/de-CH.json +++ b/packages/translation/src/lang/de-CH.json @@ -757,6 +757,10 @@ "wrongPath": { "title": "Falscher Pfad", "message": "Der Pfad ist vermutlich nicht korrekt" + }, + "tooManyRequests": { + "title": "", + "message": "" } } }, @@ -2026,6 +2030,62 @@ "label": "Limit für Beiträge" } } + }, + "networkControllerSummary": { + "option": {}, + "card": { + "vpn": { + "countConnected": "" + } + }, + "error": { + "integrationsDisconnected": "", + "unknownContentOption": "" + }, + "name": "", + "description": "" + }, + "networkControllerStatus": { + "card": { + "variants": { + "wired": { + "name": "" + }, + "wifi": { + "name": "" + } + }, + "users": { + "label": "" + }, + "guests": { + "label": "" + } + }, + "option": { + "content": { + "option": { + "wifi": { + "label": "" + }, + "wired": { + "label": "" + } + }, + "label": "" + } + }, + "error": { + "integrationsDisconnected": "", + "unknownContentOption": "" + }, + "name": "", + "description": "" + }, + "networkController": { + "error": { + "internalServerError": "" + } } }, "widgetPreview": { @@ -2146,7 +2206,12 @@ "label": "URL des Favicons" }, "backgroundImageUrl": { - "label": "URL des Hintergrundbildes" + "label": "URL des Hintergrundbildes", + "placeholder": "", + "group": { + "your": "", + "other": "" + } }, "backgroundImageAttachment": { "label": "Anhang des Hintergrundbildes", @@ -2782,6 +2847,9 @@ }, "mediaTranscoding": { "label": "Medien Transkodierung" + }, + "networkController": { + "label": "" } } }, diff --git a/packages/translation/src/lang/de.json b/packages/translation/src/lang/de.json index 2e2e05fdc..54434ff66 100644 --- a/packages/translation/src/lang/de.json +++ b/packages/translation/src/lang/de.json @@ -757,6 +757,10 @@ "wrongPath": { "title": "Falscher Pfad", "message": "Der Pfad ist vermutlich nicht korrekt" + }, + "tooManyRequests": { + "title": "", + "message": "" } } }, @@ -2026,6 +2030,62 @@ "label": "Limit für Beiträge" } } + }, + "networkControllerSummary": { + "option": {}, + "card": { + "vpn": { + "countConnected": "" + } + }, + "error": { + "integrationsDisconnected": "", + "unknownContentOption": "" + }, + "name": "", + "description": "" + }, + "networkControllerStatus": { + "card": { + "variants": { + "wired": { + "name": "" + }, + "wifi": { + "name": "" + } + }, + "users": { + "label": "" + }, + "guests": { + "label": "" + } + }, + "option": { + "content": { + "option": { + "wifi": { + "label": "" + }, + "wired": { + "label": "" + } + }, + "label": "" + } + }, + "error": { + "integrationsDisconnected": "", + "unknownContentOption": "" + }, + "name": "", + "description": "" + }, + "networkController": { + "error": { + "internalServerError": "" + } } }, "widgetPreview": { @@ -2146,7 +2206,12 @@ "label": "URL des Favicons" }, "backgroundImageUrl": { - "label": "URL des Hintergrundbildes" + "label": "URL des Hintergrundbildes", + "placeholder": "", + "group": { + "your": "", + "other": "" + } }, "backgroundImageAttachment": { "label": "Anhang des Hintergrundbildes", @@ -2782,6 +2847,9 @@ }, "mediaTranscoding": { "label": "Medien Transkodierung" + }, + "networkController": { + "label": "" } } }, diff --git a/packages/translation/src/lang/el.json b/packages/translation/src/lang/el.json index 502849e4e..4f33f6133 100644 --- a/packages/translation/src/lang/el.json +++ b/packages/translation/src/lang/el.json @@ -757,6 +757,10 @@ "wrongPath": { "title": "", "message": "" + }, + "tooManyRequests": { + "title": "", + "message": "" } } }, @@ -2026,6 +2030,62 @@ "label": "" } } + }, + "networkControllerSummary": { + "option": {}, + "card": { + "vpn": { + "countConnected": "" + } + }, + "error": { + "integrationsDisconnected": "", + "unknownContentOption": "" + }, + "name": "", + "description": "" + }, + "networkControllerStatus": { + "card": { + "variants": { + "wired": { + "name": "" + }, + "wifi": { + "name": "" + } + }, + "users": { + "label": "" + }, + "guests": { + "label": "" + } + }, + "option": { + "content": { + "option": { + "wifi": { + "label": "" + }, + "wired": { + "label": "" + } + }, + "label": "" + } + }, + "error": { + "integrationsDisconnected": "", + "unknownContentOption": "" + }, + "name": "", + "description": "" + }, + "networkController": { + "error": { + "internalServerError": "" + } } }, "widgetPreview": { @@ -2146,7 +2206,12 @@ "label": "" }, "backgroundImageUrl": { - "label": "" + "label": "", + "placeholder": "", + "group": { + "your": "", + "other": "" + } }, "backgroundImageAttachment": { "label": "Συνημμένη εικόνα φόντου", @@ -2782,6 +2847,9 @@ }, "mediaTranscoding": { "label": "" + }, + "networkController": { + "label": "" } } }, diff --git a/packages/translation/src/lang/en-gb.json b/packages/translation/src/lang/en-gb.json index a7d05726e..1cc1eb3d7 100644 --- a/packages/translation/src/lang/en-gb.json +++ b/packages/translation/src/lang/en-gb.json @@ -757,6 +757,10 @@ "wrongPath": { "title": "Wrong path", "message": "The path is incorrect. Please double-check the URL" + }, + "tooManyRequests": { + "title": "", + "message": "" } } }, @@ -2026,6 +2030,62 @@ "label": "" } } + }, + "networkControllerSummary": { + "option": {}, + "card": { + "vpn": { + "countConnected": "" + } + }, + "error": { + "integrationsDisconnected": "", + "unknownContentOption": "" + }, + "name": "", + "description": "" + }, + "networkControllerStatus": { + "card": { + "variants": { + "wired": { + "name": "" + }, + "wifi": { + "name": "" + } + }, + "users": { + "label": "" + }, + "guests": { + "label": "" + } + }, + "option": { + "content": { + "option": { + "wifi": { + "label": "" + }, + "wired": { + "label": "" + } + }, + "label": "" + } + }, + "error": { + "integrationsDisconnected": "", + "unknownContentOption": "" + }, + "name": "", + "description": "" + }, + "networkController": { + "error": { + "internalServerError": "" + } } }, "widgetPreview": { @@ -2146,7 +2206,12 @@ "label": "" }, "backgroundImageUrl": { - "label": "" + "label": "", + "placeholder": "", + "group": { + "your": "", + "other": "" + } }, "backgroundImageAttachment": { "label": "", @@ -2782,6 +2847,9 @@ }, "mediaTranscoding": { "label": "" + }, + "networkController": { + "label": "" } } }, diff --git a/packages/translation/src/lang/en.json b/packages/translation/src/lang/en.json index 966700f5e..5ea1ce039 100644 --- a/packages/translation/src/lang/en.json +++ b/packages/translation/src/lang/en.json @@ -757,6 +757,10 @@ "wrongPath": { "title": "Wrong path", "message": "The path is probably not correct" + }, + "tooManyRequests": { + "title": "Too many requests in a given time", + "message": "There were too many requests. You are likely being rate-limited or rejected by the target system" } } }, @@ -2026,6 +2030,62 @@ "label": "Amount posts limit" } } + }, + "networkControllerSummary": { + "option": {}, + "card": { + "vpn": { + "countConnected": "{count} connected" + } + }, + "error": { + "integrationsDisconnected": "No data available, all integrations disconnected", + "unknownContentOption": "Unknown content option for network controller summary widget: " + }, + "name": "Network Controller Summary", + "description": "Displays the summary of a Network Controller (like UniFi Controller)" + }, + "networkControllerStatus": { + "card": { + "variants": { + "wired": { + "name": "Wired" + }, + "wifi": { + "name": "Wi-Fi" + } + }, + "users": { + "label": "Users" + }, + "guests": { + "label": "Guests" + } + }, + "option": { + "content": { + "option": { + "wifi": { + "label": "Wi-Fi" + }, + "wired": { + "label": "Wired" + } + }, + "label": "Widget Content" + } + }, + "error": { + "integrationsDisconnected": "No data available, all integrations disconnected", + "unknownContentOption": "Unknown content option for network status widget: " + }, + "name": "Network Status", + "description": "Display connected devices on a network" + }, + "networkController": { + "error": { + "internalServerError": "Failed to fetch Network Controller Summary" + } } }, "widgetPreview": { @@ -2146,7 +2206,12 @@ "label": "Favicon image URL" }, "backgroundImageUrl": { - "label": "Background image URL" + "label": "Background image URL", + "placeholder": "Start typing to search local images", + "group": { + "your": "Your images", + "other": "Other images" + } }, "backgroundImageAttachment": { "label": "Background image attachment", @@ -2782,6 +2847,9 @@ }, "mediaTranscoding": { "label": "Media transcoding" + }, + "networkController": { + "label": "Network Controller" } } }, diff --git a/packages/translation/src/lang/es.json b/packages/translation/src/lang/es.json index 977b4c109..c5ac9b185 100644 --- a/packages/translation/src/lang/es.json +++ b/packages/translation/src/lang/es.json @@ -757,6 +757,10 @@ "wrongPath": { "title": "", "message": "" + }, + "tooManyRequests": { + "title": "", + "message": "" } } }, @@ -2026,6 +2030,62 @@ "label": "" } } + }, + "networkControllerSummary": { + "option": {}, + "card": { + "vpn": { + "countConnected": "" + } + }, + "error": { + "integrationsDisconnected": "", + "unknownContentOption": "" + }, + "name": "", + "description": "" + }, + "networkControllerStatus": { + "card": { + "variants": { + "wired": { + "name": "" + }, + "wifi": { + "name": "" + } + }, + "users": { + "label": "" + }, + "guests": { + "label": "" + } + }, + "option": { + "content": { + "option": { + "wifi": { + "label": "" + }, + "wired": { + "label": "" + } + }, + "label": "" + } + }, + "error": { + "integrationsDisconnected": "", + "unknownContentOption": "" + }, + "name": "", + "description": "" + }, + "networkController": { + "error": { + "internalServerError": "" + } } }, "widgetPreview": { @@ -2146,7 +2206,12 @@ "label": "" }, "backgroundImageUrl": { - "label": "" + "label": "", + "placeholder": "", + "group": { + "your": "", + "other": "" + } }, "backgroundImageAttachment": { "label": "Adjuntar imagen de fondo", @@ -2782,6 +2847,9 @@ }, "mediaTranscoding": { "label": "" + }, + "networkController": { + "label": "" } } }, diff --git a/packages/translation/src/lang/et.json b/packages/translation/src/lang/et.json index 35dfddbc4..459d55f84 100644 --- a/packages/translation/src/lang/et.json +++ b/packages/translation/src/lang/et.json @@ -757,6 +757,10 @@ "wrongPath": { "title": "", "message": "" + }, + "tooManyRequests": { + "title": "", + "message": "" } } }, @@ -2026,6 +2030,62 @@ "label": "" } } + }, + "networkControllerSummary": { + "option": {}, + "card": { + "vpn": { + "countConnected": "" + } + }, + "error": { + "integrationsDisconnected": "", + "unknownContentOption": "" + }, + "name": "", + "description": "" + }, + "networkControllerStatus": { + "card": { + "variants": { + "wired": { + "name": "" + }, + "wifi": { + "name": "" + } + }, + "users": { + "label": "" + }, + "guests": { + "label": "" + } + }, + "option": { + "content": { + "option": { + "wifi": { + "label": "" + }, + "wired": { + "label": "" + } + }, + "label": "" + } + }, + "error": { + "integrationsDisconnected": "", + "unknownContentOption": "" + }, + "name": "", + "description": "" + }, + "networkController": { + "error": { + "internalServerError": "" + } } }, "widgetPreview": { @@ -2146,7 +2206,12 @@ "label": "" }, "backgroundImageUrl": { - "label": "" + "label": "", + "placeholder": "", + "group": { + "your": "", + "other": "" + } }, "backgroundImageAttachment": { "label": "", @@ -2782,6 +2847,9 @@ }, "mediaTranscoding": { "label": "" + }, + "networkController": { + "label": "" } } }, diff --git a/packages/translation/src/lang/fr.json b/packages/translation/src/lang/fr.json index a8ac7712a..460e9d551 100644 --- a/packages/translation/src/lang/fr.json +++ b/packages/translation/src/lang/fr.json @@ -757,6 +757,10 @@ "wrongPath": { "title": "Mauvais chemin d'accès", "message": "Le chemin d'accès n'est probablement pas correct" + }, + "tooManyRequests": { + "title": "", + "message": "" } } }, @@ -2026,6 +2030,62 @@ "label": "Nombre maximum de publications" } } + }, + "networkControllerSummary": { + "option": {}, + "card": { + "vpn": { + "countConnected": "" + } + }, + "error": { + "integrationsDisconnected": "", + "unknownContentOption": "" + }, + "name": "", + "description": "" + }, + "networkControllerStatus": { + "card": { + "variants": { + "wired": { + "name": "" + }, + "wifi": { + "name": "" + } + }, + "users": { + "label": "" + }, + "guests": { + "label": "" + } + }, + "option": { + "content": { + "option": { + "wifi": { + "label": "" + }, + "wired": { + "label": "" + } + }, + "label": "" + } + }, + "error": { + "integrationsDisconnected": "", + "unknownContentOption": "" + }, + "name": "", + "description": "" + }, + "networkController": { + "error": { + "internalServerError": "" + } } }, "widgetPreview": { @@ -2146,7 +2206,12 @@ "label": "URL du Favicon" }, "backgroundImageUrl": { - "label": "URL de l'arrière-plan" + "label": "URL de l'arrière-plan", + "placeholder": "", + "group": { + "your": "", + "other": "" + } }, "backgroundImageAttachment": { "label": "Pièce jointe de l'image d'arrière-plan", @@ -2782,6 +2847,9 @@ }, "mediaTranscoding": { "label": "Transcodage des médias" + }, + "networkController": { + "label": "" } } }, diff --git a/packages/translation/src/lang/he.json b/packages/translation/src/lang/he.json index 456324fbb..ea1aef292 100644 --- a/packages/translation/src/lang/he.json +++ b/packages/translation/src/lang/he.json @@ -757,6 +757,10 @@ "wrongPath": { "title": "נתיב שגוי", "message": "כנראה שהנתיב שגוי" + }, + "tooManyRequests": { + "title": "", + "message": "" } } }, @@ -2026,6 +2030,62 @@ "label": "הגבלת כמות הודעות" } } + }, + "networkControllerSummary": { + "option": {}, + "card": { + "vpn": { + "countConnected": "" + } + }, + "error": { + "integrationsDisconnected": "", + "unknownContentOption": "" + }, + "name": "", + "description": "" + }, + "networkControllerStatus": { + "card": { + "variants": { + "wired": { + "name": "" + }, + "wifi": { + "name": "" + } + }, + "users": { + "label": "" + }, + "guests": { + "label": "" + } + }, + "option": { + "content": { + "option": { + "wifi": { + "label": "" + }, + "wired": { + "label": "" + } + }, + "label": "" + } + }, + "error": { + "integrationsDisconnected": "", + "unknownContentOption": "" + }, + "name": "", + "description": "" + }, + "networkController": { + "error": { + "internalServerError": "" + } } }, "widgetPreview": { @@ -2146,7 +2206,12 @@ "label": "כתובת אתר של תמונת Favicon" }, "backgroundImageUrl": { - "label": "כתובת אתר של תמונת רקע" + "label": "כתובת אתר של תמונת רקע", + "placeholder": "", + "group": { + "your": "", + "other": "" + } }, "backgroundImageAttachment": { "label": "צירוף תמונת רקע", @@ -2782,6 +2847,9 @@ }, "mediaTranscoding": { "label": "המרת קידוד מדיה" + }, + "networkController": { + "label": "" } } }, diff --git a/packages/translation/src/lang/hr.json b/packages/translation/src/lang/hr.json index 1d926c85a..0415ab265 100644 --- a/packages/translation/src/lang/hr.json +++ b/packages/translation/src/lang/hr.json @@ -757,6 +757,10 @@ "wrongPath": { "title": "", "message": "" + }, + "tooManyRequests": { + "title": "", + "message": "" } } }, @@ -2026,6 +2030,62 @@ "label": "" } } + }, + "networkControllerSummary": { + "option": {}, + "card": { + "vpn": { + "countConnected": "" + } + }, + "error": { + "integrationsDisconnected": "", + "unknownContentOption": "" + }, + "name": "", + "description": "" + }, + "networkControllerStatus": { + "card": { + "variants": { + "wired": { + "name": "" + }, + "wifi": { + "name": "" + } + }, + "users": { + "label": "" + }, + "guests": { + "label": "" + } + }, + "option": { + "content": { + "option": { + "wifi": { + "label": "" + }, + "wired": { + "label": "" + } + }, + "label": "" + } + }, + "error": { + "integrationsDisconnected": "", + "unknownContentOption": "" + }, + "name": "", + "description": "" + }, + "networkController": { + "error": { + "internalServerError": "" + } } }, "widgetPreview": { @@ -2146,7 +2206,12 @@ "label": "" }, "backgroundImageUrl": { - "label": "" + "label": "", + "placeholder": "", + "group": { + "your": "", + "other": "" + } }, "backgroundImageAttachment": { "label": "", @@ -2782,6 +2847,9 @@ }, "mediaTranscoding": { "label": "" + }, + "networkController": { + "label": "" } } }, diff --git a/packages/translation/src/lang/hu.json b/packages/translation/src/lang/hu.json index 4f84efc69..d543356f8 100644 --- a/packages/translation/src/lang/hu.json +++ b/packages/translation/src/lang/hu.json @@ -757,6 +757,10 @@ "wrongPath": { "title": "Rossz útvonal", "message": "Az útvonal valószínűleg nem helyes" + }, + "tooManyRequests": { + "title": "", + "message": "" } } }, @@ -2026,6 +2030,62 @@ "label": "" } } + }, + "networkControllerSummary": { + "option": {}, + "card": { + "vpn": { + "countConnected": "" + } + }, + "error": { + "integrationsDisconnected": "", + "unknownContentOption": "" + }, + "name": "", + "description": "" + }, + "networkControllerStatus": { + "card": { + "variants": { + "wired": { + "name": "" + }, + "wifi": { + "name": "" + } + }, + "users": { + "label": "" + }, + "guests": { + "label": "" + } + }, + "option": { + "content": { + "option": { + "wifi": { + "label": "" + }, + "wired": { + "label": "" + } + }, + "label": "" + } + }, + "error": { + "integrationsDisconnected": "", + "unknownContentOption": "" + }, + "name": "", + "description": "" + }, + "networkController": { + "error": { + "internalServerError": "" + } } }, "widgetPreview": { @@ -2146,7 +2206,12 @@ "label": "" }, "backgroundImageUrl": { - "label": "" + "label": "", + "placeholder": "", + "group": { + "your": "", + "other": "" + } }, "backgroundImageAttachment": { "label": "Háttérkép csatolása", @@ -2782,6 +2847,9 @@ }, "mediaTranscoding": { "label": "" + }, + "networkController": { + "label": "" } } }, diff --git a/packages/translation/src/lang/it.json b/packages/translation/src/lang/it.json index 7796657b4..533785557 100644 --- a/packages/translation/src/lang/it.json +++ b/packages/translation/src/lang/it.json @@ -757,6 +757,10 @@ "wrongPath": { "title": "Percorso sbagliato", "message": "Il percorso probabilmente non è corretto" + }, + "tooManyRequests": { + "title": "", + "message": "" } } }, @@ -2026,6 +2030,62 @@ "label": "" } } + }, + "networkControllerSummary": { + "option": {}, + "card": { + "vpn": { + "countConnected": "" + } + }, + "error": { + "integrationsDisconnected": "", + "unknownContentOption": "" + }, + "name": "", + "description": "" + }, + "networkControllerStatus": { + "card": { + "variants": { + "wired": { + "name": "" + }, + "wifi": { + "name": "" + } + }, + "users": { + "label": "" + }, + "guests": { + "label": "" + } + }, + "option": { + "content": { + "option": { + "wifi": { + "label": "" + }, + "wired": { + "label": "" + } + }, + "label": "" + } + }, + "error": { + "integrationsDisconnected": "", + "unknownContentOption": "" + }, + "name": "", + "description": "" + }, + "networkController": { + "error": { + "internalServerError": "" + } } }, "widgetPreview": { @@ -2146,7 +2206,12 @@ "label": "" }, "backgroundImageUrl": { - "label": "" + "label": "", + "placeholder": "", + "group": { + "your": "", + "other": "" + } }, "backgroundImageAttachment": { "label": "Immagine di background", @@ -2782,6 +2847,9 @@ }, "mediaTranscoding": { "label": "" + }, + "networkController": { + "label": "" } } }, diff --git a/packages/translation/src/lang/ja.json b/packages/translation/src/lang/ja.json index 873bff14b..123cebe3c 100644 --- a/packages/translation/src/lang/ja.json +++ b/packages/translation/src/lang/ja.json @@ -757,6 +757,10 @@ "wrongPath": { "title": "", "message": "" + }, + "tooManyRequests": { + "title": "", + "message": "" } } }, @@ -2026,6 +2030,62 @@ "label": "" } } + }, + "networkControllerSummary": { + "option": {}, + "card": { + "vpn": { + "countConnected": "" + } + }, + "error": { + "integrationsDisconnected": "", + "unknownContentOption": "" + }, + "name": "", + "description": "" + }, + "networkControllerStatus": { + "card": { + "variants": { + "wired": { + "name": "" + }, + "wifi": { + "name": "" + } + }, + "users": { + "label": "" + }, + "guests": { + "label": "" + } + }, + "option": { + "content": { + "option": { + "wifi": { + "label": "" + }, + "wired": { + "label": "" + } + }, + "label": "" + } + }, + "error": { + "integrationsDisconnected": "", + "unknownContentOption": "" + }, + "name": "", + "description": "" + }, + "networkController": { + "error": { + "internalServerError": "" + } } }, "widgetPreview": { @@ -2146,7 +2206,12 @@ "label": "" }, "backgroundImageUrl": { - "label": "" + "label": "", + "placeholder": "", + "group": { + "your": "", + "other": "" + } }, "backgroundImageAttachment": { "label": "背景画像の添付ファイル", @@ -2782,6 +2847,9 @@ }, "mediaTranscoding": { "label": "" + }, + "networkController": { + "label": "" } } }, diff --git a/packages/translation/src/lang/ko.json b/packages/translation/src/lang/ko.json index 586d27e7d..39c584361 100644 --- a/packages/translation/src/lang/ko.json +++ b/packages/translation/src/lang/ko.json @@ -757,6 +757,10 @@ "wrongPath": { "title": "", "message": "" + }, + "tooManyRequests": { + "title": "", + "message": "" } } }, @@ -2026,6 +2030,62 @@ "label": "" } } + }, + "networkControllerSummary": { + "option": {}, + "card": { + "vpn": { + "countConnected": "" + } + }, + "error": { + "integrationsDisconnected": "", + "unknownContentOption": "" + }, + "name": "", + "description": "" + }, + "networkControllerStatus": { + "card": { + "variants": { + "wired": { + "name": "" + }, + "wifi": { + "name": "" + } + }, + "users": { + "label": "" + }, + "guests": { + "label": "" + } + }, + "option": { + "content": { + "option": { + "wifi": { + "label": "" + }, + "wired": { + "label": "" + } + }, + "label": "" + } + }, + "error": { + "integrationsDisconnected": "", + "unknownContentOption": "" + }, + "name": "", + "description": "" + }, + "networkController": { + "error": { + "internalServerError": "" + } } }, "widgetPreview": { @@ -2146,7 +2206,12 @@ "label": "" }, "backgroundImageUrl": { - "label": "" + "label": "", + "placeholder": "", + "group": { + "your": "", + "other": "" + } }, "backgroundImageAttachment": { "label": "", @@ -2782,6 +2847,9 @@ }, "mediaTranscoding": { "label": "" + }, + "networkController": { + "label": "" } } }, diff --git a/packages/translation/src/lang/lt.json b/packages/translation/src/lang/lt.json index 58fa2f72b..6b54052da 100644 --- a/packages/translation/src/lang/lt.json +++ b/packages/translation/src/lang/lt.json @@ -757,6 +757,10 @@ "wrongPath": { "title": "", "message": "" + }, + "tooManyRequests": { + "title": "", + "message": "" } } }, @@ -2026,6 +2030,62 @@ "label": "" } } + }, + "networkControllerSummary": { + "option": {}, + "card": { + "vpn": { + "countConnected": "" + } + }, + "error": { + "integrationsDisconnected": "", + "unknownContentOption": "" + }, + "name": "", + "description": "" + }, + "networkControllerStatus": { + "card": { + "variants": { + "wired": { + "name": "" + }, + "wifi": { + "name": "" + } + }, + "users": { + "label": "" + }, + "guests": { + "label": "" + } + }, + "option": { + "content": { + "option": { + "wifi": { + "label": "" + }, + "wired": { + "label": "" + } + }, + "label": "" + } + }, + "error": { + "integrationsDisconnected": "", + "unknownContentOption": "" + }, + "name": "", + "description": "" + }, + "networkController": { + "error": { + "internalServerError": "" + } } }, "widgetPreview": { @@ -2146,7 +2206,12 @@ "label": "" }, "backgroundImageUrl": { - "label": "" + "label": "", + "placeholder": "", + "group": { + "your": "", + "other": "" + } }, "backgroundImageAttachment": { "label": "", @@ -2782,6 +2847,9 @@ }, "mediaTranscoding": { "label": "" + }, + "networkController": { + "label": "" } } }, diff --git a/packages/translation/src/lang/lv.json b/packages/translation/src/lang/lv.json index b7b1afcc4..ff03fc44a 100644 --- a/packages/translation/src/lang/lv.json +++ b/packages/translation/src/lang/lv.json @@ -757,6 +757,10 @@ "wrongPath": { "title": "", "message": "" + }, + "tooManyRequests": { + "title": "", + "message": "" } } }, @@ -2026,6 +2030,62 @@ "label": "" } } + }, + "networkControllerSummary": { + "option": {}, + "card": { + "vpn": { + "countConnected": "" + } + }, + "error": { + "integrationsDisconnected": "", + "unknownContentOption": "" + }, + "name": "", + "description": "" + }, + "networkControllerStatus": { + "card": { + "variants": { + "wired": { + "name": "" + }, + "wifi": { + "name": "" + } + }, + "users": { + "label": "" + }, + "guests": { + "label": "" + } + }, + "option": { + "content": { + "option": { + "wifi": { + "label": "" + }, + "wired": { + "label": "" + } + }, + "label": "" + } + }, + "error": { + "integrationsDisconnected": "", + "unknownContentOption": "" + }, + "name": "", + "description": "" + }, + "networkController": { + "error": { + "internalServerError": "" + } } }, "widgetPreview": { @@ -2146,7 +2206,12 @@ "label": "" }, "backgroundImageUrl": { - "label": "" + "label": "", + "placeholder": "", + "group": { + "your": "", + "other": "" + } }, "backgroundImageAttachment": { "label": "Fona attēla pielikums", @@ -2782,6 +2847,9 @@ }, "mediaTranscoding": { "label": "" + }, + "networkController": { + "label": "" } } }, diff --git a/packages/translation/src/lang/nl.json b/packages/translation/src/lang/nl.json index 3a7b55ce6..41aabdfbe 100644 --- a/packages/translation/src/lang/nl.json +++ b/packages/translation/src/lang/nl.json @@ -757,6 +757,10 @@ "wrongPath": { "title": "Verkeerde pad", "message": "Het pad is waarschijnlijk niet juist" + }, + "tooManyRequests": { + "title": "Te veel verzoeken in een bepaalde tijd", + "message": "Er waren te veel aanvragen. Je wordt waarschijnlijk beperkt in snelheid of afgewezen door het doelsysteem" } } }, @@ -981,7 +985,7 @@ }, "option": { "title": { - "label": "" + "label": "Titel" }, "borderColor": { "label": "Randkleur" @@ -2026,6 +2030,62 @@ "label": "Aantal berichtenlimiet" } } + }, + "networkControllerSummary": { + "option": {}, + "card": { + "vpn": { + "countConnected": "{count} verbonden" + } + }, + "error": { + "integrationsDisconnected": "Geen gegevens beschikbaar, alle integraties verbroken", + "unknownContentOption": "Onbekende inhoudsoptie voor netwerkcontroller samenvatting widget:" + }, + "name": "Netwerkcontroller samenvatting", + "description": "Geeft de samenvatting weer van een netwerkcontroller (zoals UniFi Controller)" + }, + "networkControllerStatus": { + "card": { + "variants": { + "wired": { + "name": "Bedraad" + }, + "wifi": { + "name": "Wi-Fi" + } + }, + "users": { + "label": "Gebruikers" + }, + "guests": { + "label": "Gasten" + } + }, + "option": { + "content": { + "option": { + "wifi": { + "label": "Wi-Fi" + }, + "wired": { + "label": "Bedraad" + } + }, + "label": "Widget inhoud" + } + }, + "error": { + "integrationsDisconnected": "Geen gegevens beschikbaar, alle integraties verbroken", + "unknownContentOption": "Onbekende inhoudsoptie voor netwerkstatus widget:" + }, + "name": "Netwerkstatus", + "description": "Verbonden apparaten op een netwerk weergeven" + }, + "networkController": { + "error": { + "internalServerError": "Netwerkcontroller samenvatting ophalen mislukt" + } } }, "widgetPreview": { @@ -2146,7 +2206,12 @@ "label": "Favicon afbeeldings-URL" }, "backgroundImageUrl": { - "label": "Achtergrondafbeelding URL" + "label": "Achtergrondafbeelding URL", + "placeholder": "Begin met typen om lokale afbeeldingen te zoeken", + "group": { + "your": "Jouw afbeeldingen", + "other": "Andere afbeeldingen" + } }, "backgroundImageAttachment": { "label": "Achtergrondafbeelding bijlage", @@ -2782,6 +2847,9 @@ }, "mediaTranscoding": { "label": "Mediatranscodering" + }, + "networkController": { + "label": "Netwerkcontroller" } } }, diff --git a/packages/translation/src/lang/no.json b/packages/translation/src/lang/no.json index 5dcc88c8c..b6649f358 100644 --- a/packages/translation/src/lang/no.json +++ b/packages/translation/src/lang/no.json @@ -757,6 +757,10 @@ "wrongPath": { "title": "Feil bane", "message": "Banen er sannsynligvis ikke riktig" + }, + "tooManyRequests": { + "title": "", + "message": "" } } }, @@ -2026,6 +2030,62 @@ "label": "Antall poster grense" } } + }, + "networkControllerSummary": { + "option": {}, + "card": { + "vpn": { + "countConnected": "" + } + }, + "error": { + "integrationsDisconnected": "", + "unknownContentOption": "" + }, + "name": "", + "description": "" + }, + "networkControllerStatus": { + "card": { + "variants": { + "wired": { + "name": "" + }, + "wifi": { + "name": "" + } + }, + "users": { + "label": "" + }, + "guests": { + "label": "" + } + }, + "option": { + "content": { + "option": { + "wifi": { + "label": "" + }, + "wired": { + "label": "" + } + }, + "label": "" + } + }, + "error": { + "integrationsDisconnected": "", + "unknownContentOption": "" + }, + "name": "", + "description": "" + }, + "networkController": { + "error": { + "internalServerError": "" + } } }, "widgetPreview": { @@ -2146,7 +2206,12 @@ "label": "Favicon bilde URL" }, "backgroundImageUrl": { - "label": "URL for bakgrunnsbilde" + "label": "URL for bakgrunnsbilde", + "placeholder": "", + "group": { + "your": "", + "other": "" + } }, "backgroundImageAttachment": { "label": "Bakgrunnsbildevedlegg", @@ -2782,6 +2847,9 @@ }, "mediaTranscoding": { "label": "Media transkoding" + }, + "networkController": { + "label": "" } } }, diff --git a/packages/translation/src/lang/pl.json b/packages/translation/src/lang/pl.json index 3ce1b3d40..e938b9123 100644 --- a/packages/translation/src/lang/pl.json +++ b/packages/translation/src/lang/pl.json @@ -757,6 +757,10 @@ "wrongPath": { "title": "Błędna ścieżka", "message": "Ścieżka jest prawdopodobnie niepoprawna" + }, + "tooManyRequests": { + "title": "", + "message": "" } } }, @@ -2026,6 +2030,62 @@ "label": "" } } + }, + "networkControllerSummary": { + "option": {}, + "card": { + "vpn": { + "countConnected": "" + } + }, + "error": { + "integrationsDisconnected": "", + "unknownContentOption": "" + }, + "name": "", + "description": "" + }, + "networkControllerStatus": { + "card": { + "variants": { + "wired": { + "name": "" + }, + "wifi": { + "name": "" + } + }, + "users": { + "label": "" + }, + "guests": { + "label": "" + } + }, + "option": { + "content": { + "option": { + "wifi": { + "label": "" + }, + "wired": { + "label": "" + } + }, + "label": "" + } + }, + "error": { + "integrationsDisconnected": "", + "unknownContentOption": "" + }, + "name": "", + "description": "" + }, + "networkController": { + "error": { + "internalServerError": "" + } } }, "widgetPreview": { @@ -2146,7 +2206,12 @@ "label": "" }, "backgroundImageUrl": { - "label": "" + "label": "", + "placeholder": "", + "group": { + "your": "", + "other": "" + } }, "backgroundImageAttachment": { "label": "Ustawienie obrazu tła", @@ -2782,6 +2847,9 @@ }, "mediaTranscoding": { "label": "" + }, + "networkController": { + "label": "" } } }, diff --git a/packages/translation/src/lang/pt.json b/packages/translation/src/lang/pt.json index 6d5f7c8bd..e6c68fe84 100644 --- a/packages/translation/src/lang/pt.json +++ b/packages/translation/src/lang/pt.json @@ -757,6 +757,10 @@ "wrongPath": { "title": "", "message": "" + }, + "tooManyRequests": { + "title": "", + "message": "" } } }, @@ -2026,6 +2030,62 @@ "label": "" } } + }, + "networkControllerSummary": { + "option": {}, + "card": { + "vpn": { + "countConnected": "" + } + }, + "error": { + "integrationsDisconnected": "", + "unknownContentOption": "" + }, + "name": "", + "description": "" + }, + "networkControllerStatus": { + "card": { + "variants": { + "wired": { + "name": "" + }, + "wifi": { + "name": "" + } + }, + "users": { + "label": "" + }, + "guests": { + "label": "" + } + }, + "option": { + "content": { + "option": { + "wifi": { + "label": "" + }, + "wired": { + "label": "" + } + }, + "label": "" + } + }, + "error": { + "integrationsDisconnected": "", + "unknownContentOption": "" + }, + "name": "", + "description": "" + }, + "networkController": { + "error": { + "internalServerError": "" + } } }, "widgetPreview": { @@ -2146,7 +2206,12 @@ "label": "" }, "backgroundImageUrl": { - "label": "" + "label": "", + "placeholder": "", + "group": { + "your": "", + "other": "" + } }, "backgroundImageAttachment": { "label": "Anexo de imagem de fundo", @@ -2782,6 +2847,9 @@ }, "mediaTranscoding": { "label": "" + }, + "networkController": { + "label": "" } } }, diff --git a/packages/translation/src/lang/ro.json b/packages/translation/src/lang/ro.json index ca5b3ccad..bb157449c 100644 --- a/packages/translation/src/lang/ro.json +++ b/packages/translation/src/lang/ro.json @@ -757,6 +757,10 @@ "wrongPath": { "title": "", "message": "" + }, + "tooManyRequests": { + "title": "", + "message": "" } } }, @@ -2026,6 +2030,62 @@ "label": "" } } + }, + "networkControllerSummary": { + "option": {}, + "card": { + "vpn": { + "countConnected": "" + } + }, + "error": { + "integrationsDisconnected": "", + "unknownContentOption": "" + }, + "name": "", + "description": "" + }, + "networkControllerStatus": { + "card": { + "variants": { + "wired": { + "name": "" + }, + "wifi": { + "name": "" + } + }, + "users": { + "label": "" + }, + "guests": { + "label": "" + } + }, + "option": { + "content": { + "option": { + "wifi": { + "label": "" + }, + "wired": { + "label": "" + } + }, + "label": "" + } + }, + "error": { + "integrationsDisconnected": "", + "unknownContentOption": "" + }, + "name": "", + "description": "" + }, + "networkController": { + "error": { + "internalServerError": "" + } } }, "widgetPreview": { @@ -2146,7 +2206,12 @@ "label": "" }, "backgroundImageUrl": { - "label": "" + "label": "", + "placeholder": "", + "group": { + "your": "", + "other": "" + } }, "backgroundImageAttachment": { "label": "Atașare imagine de fundal", @@ -2782,6 +2847,9 @@ }, "mediaTranscoding": { "label": "" + }, + "networkController": { + "label": "" } } }, diff --git a/packages/translation/src/lang/ru.json b/packages/translation/src/lang/ru.json index da16ccc38..045a64e01 100644 --- a/packages/translation/src/lang/ru.json +++ b/packages/translation/src/lang/ru.json @@ -757,6 +757,10 @@ "wrongPath": { "title": "Неверный путь", "message": "Возможно, указан неверный путь" + }, + "tooManyRequests": { + "title": "", + "message": "" } } }, @@ -2026,6 +2030,62 @@ "label": "Максимальное количество записей" } } + }, + "networkControllerSummary": { + "option": {}, + "card": { + "vpn": { + "countConnected": "" + } + }, + "error": { + "integrationsDisconnected": "", + "unknownContentOption": "" + }, + "name": "", + "description": "" + }, + "networkControllerStatus": { + "card": { + "variants": { + "wired": { + "name": "" + }, + "wifi": { + "name": "" + } + }, + "users": { + "label": "" + }, + "guests": { + "label": "" + } + }, + "option": { + "content": { + "option": { + "wifi": { + "label": "" + }, + "wired": { + "label": "" + } + }, + "label": "" + } + }, + "error": { + "integrationsDisconnected": "", + "unknownContentOption": "" + }, + "name": "", + "description": "" + }, + "networkController": { + "error": { + "internalServerError": "" + } } }, "widgetPreview": { @@ -2146,7 +2206,12 @@ "label": "URL изображения favicon" }, "backgroundImageUrl": { - "label": "URL фонового изображения" + "label": "URL фонового изображения", + "placeholder": "", + "group": { + "your": "", + "other": "" + } }, "backgroundImageAttachment": { "label": "Поведение фонового изображения", @@ -2782,6 +2847,9 @@ }, "mediaTranscoding": { "label": "Перекодирование медиафайлов" + }, + "networkController": { + "label": "" } } }, diff --git a/packages/translation/src/lang/sk.json b/packages/translation/src/lang/sk.json index b91c4cb88..54ee5478a 100644 --- a/packages/translation/src/lang/sk.json +++ b/packages/translation/src/lang/sk.json @@ -757,6 +757,10 @@ "wrongPath": { "title": "Nesprávna cesta", "message": "Cesta pravdepodobne nie je správna" + }, + "tooManyRequests": { + "title": "", + "message": "" } } }, @@ -2026,6 +2030,62 @@ "label": "Limit počtu príspevkov" } } + }, + "networkControllerSummary": { + "option": {}, + "card": { + "vpn": { + "countConnected": "" + } + }, + "error": { + "integrationsDisconnected": "", + "unknownContentOption": "" + }, + "name": "", + "description": "" + }, + "networkControllerStatus": { + "card": { + "variants": { + "wired": { + "name": "" + }, + "wifi": { + "name": "" + } + }, + "users": { + "label": "" + }, + "guests": { + "label": "" + } + }, + "option": { + "content": { + "option": { + "wifi": { + "label": "" + }, + "wired": { + "label": "" + } + }, + "label": "" + } + }, + "error": { + "integrationsDisconnected": "", + "unknownContentOption": "" + }, + "name": "", + "description": "" + }, + "networkController": { + "error": { + "internalServerError": "" + } } }, "widgetPreview": { @@ -2146,7 +2206,12 @@ "label": "Adresa URL obrázka Favicon" }, "backgroundImageUrl": { - "label": "URL obrázku pozadia" + "label": "URL obrázku pozadia", + "placeholder": "", + "group": { + "your": "", + "other": "" + } }, "backgroundImageAttachment": { "label": "Pripojenie obrázku na pozadí", @@ -2782,6 +2847,9 @@ }, "mediaTranscoding": { "label": "Prekódovanie médií" + }, + "networkController": { + "label": "" } } }, diff --git a/packages/translation/src/lang/sl.json b/packages/translation/src/lang/sl.json index 266aa00dd..393a253c1 100644 --- a/packages/translation/src/lang/sl.json +++ b/packages/translation/src/lang/sl.json @@ -757,6 +757,10 @@ "wrongPath": { "title": "", "message": "" + }, + "tooManyRequests": { + "title": "", + "message": "" } } }, @@ -2026,6 +2030,62 @@ "label": "" } } + }, + "networkControllerSummary": { + "option": {}, + "card": { + "vpn": { + "countConnected": "" + } + }, + "error": { + "integrationsDisconnected": "", + "unknownContentOption": "" + }, + "name": "", + "description": "" + }, + "networkControllerStatus": { + "card": { + "variants": { + "wired": { + "name": "" + }, + "wifi": { + "name": "" + } + }, + "users": { + "label": "" + }, + "guests": { + "label": "" + } + }, + "option": { + "content": { + "option": { + "wifi": { + "label": "" + }, + "wired": { + "label": "" + } + }, + "label": "" + } + }, + "error": { + "integrationsDisconnected": "", + "unknownContentOption": "" + }, + "name": "", + "description": "" + }, + "networkController": { + "error": { + "internalServerError": "" + } } }, "widgetPreview": { @@ -2146,7 +2206,12 @@ "label": "" }, "backgroundImageUrl": { - "label": "" + "label": "", + "placeholder": "", + "group": { + "your": "", + "other": "" + } }, "backgroundImageAttachment": { "label": "Pritrditev slike v ozadju", @@ -2782,6 +2847,9 @@ }, "mediaTranscoding": { "label": "" + }, + "networkController": { + "label": "" } } }, diff --git a/packages/translation/src/lang/sv.json b/packages/translation/src/lang/sv.json index 891c0f0a2..7edf9a9c5 100644 --- a/packages/translation/src/lang/sv.json +++ b/packages/translation/src/lang/sv.json @@ -757,6 +757,10 @@ "wrongPath": { "title": "", "message": "" + }, + "tooManyRequests": { + "title": "", + "message": "" } } }, @@ -2026,6 +2030,62 @@ "label": "" } } + }, + "networkControllerSummary": { + "option": {}, + "card": { + "vpn": { + "countConnected": "" + } + }, + "error": { + "integrationsDisconnected": "", + "unknownContentOption": "" + }, + "name": "", + "description": "" + }, + "networkControllerStatus": { + "card": { + "variants": { + "wired": { + "name": "" + }, + "wifi": { + "name": "" + } + }, + "users": { + "label": "" + }, + "guests": { + "label": "" + } + }, + "option": { + "content": { + "option": { + "wifi": { + "label": "" + }, + "wired": { + "label": "" + } + }, + "label": "" + } + }, + "error": { + "integrationsDisconnected": "", + "unknownContentOption": "" + }, + "name": "", + "description": "" + }, + "networkController": { + "error": { + "internalServerError": "" + } } }, "widgetPreview": { @@ -2146,7 +2206,12 @@ "label": "" }, "backgroundImageUrl": { - "label": "" + "label": "", + "placeholder": "", + "group": { + "your": "", + "other": "" + } }, "backgroundImageAttachment": { "label": "Bilaga till bakgrundsbild", @@ -2782,6 +2847,9 @@ }, "mediaTranscoding": { "label": "" + }, + "networkController": { + "label": "" } } }, diff --git a/packages/translation/src/lang/tr.json b/packages/translation/src/lang/tr.json index 1ac62c392..2a7a84512 100644 --- a/packages/translation/src/lang/tr.json +++ b/packages/translation/src/lang/tr.json @@ -757,6 +757,10 @@ "wrongPath": { "title": " Yol hatalı", "message": "Yol muhtemelen doğru değil" + }, + "tooManyRequests": { + "title": "Belirli bir sürede çok fazla istek gönderildi", + "message": "Çok fazla istek gönderildi. Muhtemelen hedef sistem tarafından rate-limit'e (hız sınırlaması) uğradınız veya engellendiniz." } } }, @@ -2026,6 +2030,62 @@ "label": "Gönderi sayısı sınırı" } } + }, + "networkControllerSummary": { + "option": {}, + "card": { + "vpn": { + "countConnected": "{count} bağlantı" + } + }, + "error": { + "integrationsDisconnected": "Veri bulunamadı, tüm entegrasyonların bağlantısı kesildi", + "unknownContentOption": "Ağ denetleyicisi özet widget'ında bilinmeyen içerik ayarı: " + }, + "name": "Ağ Denetleyicisi Özeti", + "description": "Bir Ağ Denetleyicisinin (UniFi Denetleyicisi gibi) özetini görüntüler" + }, + "networkControllerStatus": { + "card": { + "variants": { + "wired": { + "name": "Kablolu" + }, + "wifi": { + "name": "Kablosuz" + } + }, + "users": { + "label": "Kullanıcılar" + }, + "guests": { + "label": "Misafirler" + } + }, + "option": { + "content": { + "option": { + "wifi": { + "label": "Kablosuz" + }, + "wired": { + "label": "Kablolu" + } + }, + "label": "Widget içeriği" + } + }, + "error": { + "integrationsDisconnected": "Veri bulunamadı, tüm entegrasyonların bağlantısı kesildi", + "unknownContentOption": "Ağ durumu widget'ı için bilinmeyen içerik seçeneği: " + }, + "name": "Ağ Durumu", + "description": "Bir ağdaki bağlı cihazları görüntüle" + }, + "networkController": { + "error": { + "internalServerError": "Ağ Denetleyicisi Özeti alınamadı" + } } }, "widgetPreview": { @@ -2146,7 +2206,12 @@ "label": "Favicon Görseli URL'si" }, "backgroundImageUrl": { - "label": "Arkaplan Resmi URL'si" + "label": "Arkaplan Resmi URL'si", + "placeholder": "Aramak istediğiniz yerel görseller için yazmaya başlayın", + "group": { + "your": "Görselleriniz", + "other": "Diğer görseller" + } }, "backgroundImageAttachment": { "label": "Arka Plan Yerleşimi", @@ -2782,6 +2847,9 @@ }, "mediaTranscoding": { "label": "Medya Kod Dönüştürme" + }, + "networkController": { + "label": "Ağ Denetleyicisi" } } }, diff --git a/packages/translation/src/lang/uk.json b/packages/translation/src/lang/uk.json index e612d9bb3..4ef16a9c2 100644 --- a/packages/translation/src/lang/uk.json +++ b/packages/translation/src/lang/uk.json @@ -757,6 +757,10 @@ "wrongPath": { "title": "Неправильний шлях", "message": "Ймовірно, шлях не правильний" + }, + "tooManyRequests": { + "title": "", + "message": "" } } }, @@ -2026,6 +2030,62 @@ "label": "" } } + }, + "networkControllerSummary": { + "option": {}, + "card": { + "vpn": { + "countConnected": "" + } + }, + "error": { + "integrationsDisconnected": "", + "unknownContentOption": "" + }, + "name": "", + "description": "" + }, + "networkControllerStatus": { + "card": { + "variants": { + "wired": { + "name": "" + }, + "wifi": { + "name": "" + } + }, + "users": { + "label": "" + }, + "guests": { + "label": "" + } + }, + "option": { + "content": { + "option": { + "wifi": { + "label": "" + }, + "wired": { + "label": "" + } + }, + "label": "" + } + }, + "error": { + "integrationsDisconnected": "", + "unknownContentOption": "" + }, + "name": "", + "description": "" + }, + "networkController": { + "error": { + "internalServerError": "" + } } }, "widgetPreview": { @@ -2146,7 +2206,12 @@ "label": "" }, "backgroundImageUrl": { - "label": "" + "label": "", + "placeholder": "", + "group": { + "your": "", + "other": "" + } }, "backgroundImageAttachment": { "label": "Прикріплене фонове зображення", @@ -2782,6 +2847,9 @@ }, "mediaTranscoding": { "label": "" + }, + "networkController": { + "label": "" } } }, diff --git a/packages/translation/src/lang/vi.json b/packages/translation/src/lang/vi.json index c2d81c77e..0824d14d7 100644 --- a/packages/translation/src/lang/vi.json +++ b/packages/translation/src/lang/vi.json @@ -757,6 +757,10 @@ "wrongPath": { "title": "", "message": "" + }, + "tooManyRequests": { + "title": "", + "message": "" } } }, @@ -2026,6 +2030,62 @@ "label": "" } } + }, + "networkControllerSummary": { + "option": {}, + "card": { + "vpn": { + "countConnected": "" + } + }, + "error": { + "integrationsDisconnected": "", + "unknownContentOption": "" + }, + "name": "", + "description": "" + }, + "networkControllerStatus": { + "card": { + "variants": { + "wired": { + "name": "" + }, + "wifi": { + "name": "" + } + }, + "users": { + "label": "" + }, + "guests": { + "label": "" + } + }, + "option": { + "content": { + "option": { + "wifi": { + "label": "" + }, + "wired": { + "label": "" + } + }, + "label": "" + } + }, + "error": { + "integrationsDisconnected": "", + "unknownContentOption": "" + }, + "name": "", + "description": "" + }, + "networkController": { + "error": { + "internalServerError": "" + } } }, "widgetPreview": { @@ -2146,7 +2206,12 @@ "label": "" }, "backgroundImageUrl": { - "label": "" + "label": "", + "placeholder": "", + "group": { + "your": "", + "other": "" + } }, "backgroundImageAttachment": { "label": "Vị trí ảnh nền", @@ -2782,6 +2847,9 @@ }, "mediaTranscoding": { "label": "" + }, + "networkController": { + "label": "" } } }, diff --git a/packages/translation/src/lang/zh.json b/packages/translation/src/lang/zh.json index 5740276e7..120e9d68d 100644 --- a/packages/translation/src/lang/zh.json +++ b/packages/translation/src/lang/zh.json @@ -757,6 +757,10 @@ "wrongPath": { "title": "路徑錯誤", "message": "路徑可能是錯誤" + }, + "tooManyRequests": { + "title": "", + "message": "" } } }, @@ -2026,6 +2030,62 @@ "label": "帖子數量限制" } } + }, + "networkControllerSummary": { + "option": {}, + "card": { + "vpn": { + "countConnected": "" + } + }, + "error": { + "integrationsDisconnected": "", + "unknownContentOption": "" + }, + "name": "", + "description": "" + }, + "networkControllerStatus": { + "card": { + "variants": { + "wired": { + "name": "" + }, + "wifi": { + "name": "" + } + }, + "users": { + "label": "" + }, + "guests": { + "label": "" + } + }, + "option": { + "content": { + "option": { + "wifi": { + "label": "" + }, + "wired": { + "label": "" + } + }, + "label": "" + } + }, + "error": { + "integrationsDisconnected": "", + "unknownContentOption": "" + }, + "name": "", + "description": "" + }, + "networkController": { + "error": { + "internalServerError": "" + } } }, "widgetPreview": { @@ -2146,7 +2206,12 @@ "label": "Favicon 圖案網址" }, "backgroundImageUrl": { - "label": "背景圖案網址" + "label": "背景圖案網址", + "placeholder": "", + "group": { + "your": "", + "other": "" + } }, "backgroundImageAttachment": { "label": "背景圖案附件", @@ -2782,6 +2847,9 @@ }, "mediaTranscoding": { "label": "多媒體轉碼中" + }, + "networkController": { + "label": "" } } }, diff --git a/packages/ui/package.json b/packages/ui/package.json index 6b0613a3c..8b0ce7d84 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -29,12 +29,12 @@ "@homarr/log": "workspace:^0.1.0", "@homarr/translation": "workspace:^0.1.0", "@homarr/validation": "workspace:^0.1.0", - "@mantine/core": "^7.17.3", - "@mantine/dates": "^7.17.3", - "@mantine/hooks": "^7.17.3", + "@mantine/core": "^7.17.4", + "@mantine/dates": "^7.17.4", + "@mantine/hooks": "^7.17.4", "@tabler/icons-react": "^3.31.0", "mantine-react-table": "2.0.0-beta.9", - "next": "15.2.4", + "next": "15.2.5", "react": "19.1.0", "react-dom": "19.1.0" }, @@ -43,7 +43,7 @@ "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", "@types/css-modules": "^1.0.5", - "eslint": "^9.23.0", - "typescript": "^5.8.2" + "eslint": "^9.24.0", + "typescript": "^5.8.3" } } diff --git a/packages/ui/src/components/password-input/password-requirements-popover.tsx b/packages/ui/src/components/password-input/password-requirements-popover.tsx index b340ac473..5d10611f9 100644 --- a/packages/ui/src/components/password-input/password-requirements-popover.tsx +++ b/packages/ui/src/components/password-input/password-requirements-popover.tsx @@ -3,7 +3,7 @@ import { useState } from "react"; import { Popover, Progress } from "@mantine/core"; import { useScopedI18n } from "@homarr/translation/client"; -import { passwordRequirements } from "@homarr/validation"; +import { passwordRequirements } from "@homarr/validation/user"; import { PasswordRequirement } from "./password-requirement"; diff --git a/packages/validation/index.ts b/packages/validation/index.ts deleted file mode 100644 index 3bd16e178..000000000 --- a/packages/validation/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./src"; diff --git a/packages/validation/package.json b/packages/validation/package.json index c0aa3f3c9..c52198bb4 100644 --- a/packages/validation/package.json +++ b/packages/validation/package.json @@ -5,8 +5,7 @@ "license": "Apache-2.0", "type": "module", "exports": { - ".": "./index.ts", - "./form": "./src/form/i18n.ts" + "./*": "./src/*.ts" }, "typesVersions": { "*": { @@ -32,7 +31,7 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.23.0", - "typescript": "^5.8.2" + "eslint": "^9.24.0", + "typescript": "^5.8.3" } } diff --git a/packages/validation/src/app.ts b/packages/validation/src/app.ts index 42d170691..278f4a8b5 100644 --- a/packages/validation/src/app.ts +++ b/packages/validation/src/app.ts @@ -1,6 +1,15 @@ import { z } from "zod"; -const manageAppSchema = z.object({ +export const appHrefSchema = z + .string() + .trim() + .url() + .regex(/^https?:\/\//) // Only allow http and https for security reasons (javascript: is not allowed) + .or(z.literal("")) + .transform((value) => (value.length === 0 ? null : value)) + .nullable(); + +export const appManageSchema = z.object({ name: z.string().trim().min(1).max(64), description: z .string() @@ -9,14 +18,7 @@ const manageAppSchema = z.object({ .transform((value) => (value.length === 0 ? null : value)) .nullable(), iconUrl: z.string().trim().min(1), - href: z - .string() - .trim() - .url() - .regex(/^https?:\/\//) // Only allow http and https for security reasons (javascript: is not allowed) - .or(z.literal("")) - .transform((value) => (value.length === 0 ? null : value)) - .nullable(), + href: appHrefSchema, pingUrl: z .string() .trim() @@ -27,12 +29,8 @@ const manageAppSchema = z.object({ .nullable(), }); -const editAppSchema = manageAppSchema.and(z.object({ id: z.string() })); +export const appCreateManySchema = z + .array(appManageSchema.omit({ iconUrl: true }).and(z.object({ iconUrl: z.string().min(1).nullable() }))) + .min(1); -export const appSchemas = { - manage: manageAppSchema, - createMany: z - .array(manageAppSchema.omit({ iconUrl: true }).and(z.object({ iconUrl: z.string().min(1).nullable() }))) - .min(1), - edit: editAppSchema, -}; +export const appEditSchema = appManageSchema.and(z.object({ id: z.string() })); diff --git a/packages/validation/src/board.ts b/packages/validation/src/board.ts index 093d2042a..87facae3e 100644 --- a/packages/validation/src/board.ts +++ b/packages/validation/src/board.ts @@ -18,27 +18,28 @@ const hexColorNullableSchema = hexColorSchema .nullable() .transform((value) => (value?.trim().length === 0 ? null : value)); -const boardNameSchema = z +export const boardNameSchema = z .string() .min(1) .max(255) .regex(/^[A-Za-z0-9-\\_]*$/); +export const boardColumnCountSchema = z.number().min(1).max(24); -const byNameSchema = z.object({ +export const boardByNameSchema = z.object({ name: boardNameSchema, }); -const renameSchema = z.object({ +export const boardRenameSchema = z.object({ id: z.string(), name: boardNameSchema, }); -const duplicateSchema = z.object({ +export const boardDuplicateSchema = z.object({ id: z.string(), name: boardNameSchema, }); -const changeVisibilitySchema = z.object({ +export const boardChangeVisibilitySchema = z.object({ id: z.string(), visibility: z.enum(["public", "private"]), }); @@ -48,7 +49,7 @@ const trimmedNullableString = z .nullable() .transform((value) => (value?.trim().length === 0 ? null : value)); -const savePartialSettingsSchema = z +export const boardSavePartialSettingsSchema = z .object({ pageTitle: trimmedNullableString, metaTitle: trimmedNullableString, @@ -68,52 +69,28 @@ const savePartialSettingsSchema = z }) .partial(); -const saveLayoutsSchema = z.object({ +export const boardSaveLayoutsSchema = z.object({ id: z.string(), layouts: z.array( z.object({ id: z.string(), name: z.string().trim().nonempty().max(32), - columnCount: z.number().min(1).max(24), + columnCount: boardColumnCountSchema, breakpoint: z.number().min(0).max(32767), }), ), }); -const saveSchema = z.object({ +export const boardSaveSchema = z.object({ id: z.string(), sections: z.array(sectionSchema), items: z.array(commonItemSchema), }); -const createSchema = z.object({ name: boardNameSchema, columnCount: z.number().min(1).max(24), isPublic: z.boolean() }); - -const permissionsSchema = z.object({ - id: z.string(), -}); - -const savePermissionsSchema = createSavePermissionsSchema(zodEnumFromArray(boardPermissions)); - -z.object({ - entityId: z.string(), - permissions: z.array( - z.object({ - principalId: z.string(), - permission: zodEnumFromArray(boardPermissions), - }), - ), -}); - -export const boardSchemas = { +export const boardCreateSchema = z.object({ name: boardNameSchema, - byName: byNameSchema, - savePartialSettings: savePartialSettingsSchema, - saveLayouts: saveLayoutsSchema, - save: saveSchema, - create: createSchema, - duplicate: duplicateSchema, - rename: renameSchema, - changeVisibility: changeVisibilitySchema, - permissions: permissionsSchema, - savePermissions: savePermissionsSchema, -}; + columnCount: boardColumnCountSchema, + isPublic: z.boolean(), +}); + +export const boardSavePermissionsSchema = createSavePermissionsSchema(zodEnumFromArray(boardPermissions)); diff --git a/packages/validation/src/certificates.ts b/packages/validation/src/certificates.ts index 7ad6d3aeb..08a11ef11 100644 --- a/packages/validation/src/certificates.ts +++ b/packages/validation/src/certificates.ts @@ -2,7 +2,7 @@ import { z } from "zod"; import { createCustomErrorParams } from "./form/i18n"; -const validFileNameSchema = z.string().regex(/^[\w\-. ]+$/); +export const certificateValidFileNameSchema = z.string().regex(/^[\w\-. ]+$/); export const superRefineCertificateFile = (value: File | null, context: z.RefinementCtx) => { if (!value) { @@ -13,7 +13,7 @@ export const superRefineCertificateFile = (value: File | null, context: z.Refine }); } - const result = validFileNameSchema.safeParse(value.name); + const result = certificateValidFileNameSchema.safeParse(value.name); if (!result.success) { return context.addIssue({ code: "custom", @@ -46,7 +46,3 @@ export const superRefineCertificateFile = (value: File | null, context: z.Refine return null; }; - -export const certificateSchemas = { - validFileNameSchema, -}; diff --git a/packages/validation/src/common.ts b/packages/validation/src/common.ts index 3decf20be..20c7a175b 100644 --- a/packages/validation/src/common.ts +++ b/packages/validation/src/common.ts @@ -1,6 +1,6 @@ import { z } from "zod"; -const paginatedSchema = z.object({ +export const paginatedSchema = z.object({ search: z.string().optional(), pageSize: z.number().int().positive().default(10), page: z.number().int().positive().default(1), @@ -10,26 +10,7 @@ export const byIdSchema = z.object({ id: z.string(), }); -const searchSchema = z.object({ +export const searchSchema = z.object({ query: z.string(), limit: z.number().int().positive().default(10), }); - -const mediaRequestOptionsSchema = z.object({ - mediaId: z.number(), - mediaType: z.enum(["tv", "movie"]), -}); - -const requestMediaSchema = z.object({ - mediaType: z.enum(["tv", "movie"]), - mediaId: z.number(), - seasons: z.array(z.number().min(0)).optional(), -}); - -export const commonSchemas = { - paginated: paginatedSchema, - byId: byIdSchema, - search: searchSchema, - mediaRequestOptions: mediaRequestOptionsSchema, - requestMedia: requestMediaSchema, -}; diff --git a/packages/validation/src/group.ts b/packages/validation/src/group.ts index 25e1fa4ed..d621a93d4 100644 --- a/packages/validation/src/group.ts +++ b/packages/validation/src/group.ts @@ -5,7 +5,7 @@ import { everyoneGroup, groupPermissionKeys } from "@homarr/definitions"; import { byIdSchema } from "./common"; import { zodEnumFromArray } from "./enums"; -const createSchema = z.object({ +export const groupCreateSchema = z.object({ name: z .string() .trim() @@ -16,35 +16,25 @@ const createSchema = z.object({ }), }); -const updateSchema = createSchema.merge(byIdSchema); +export const groupUpdateSchema = groupCreateSchema.merge(byIdSchema); -const settingsSchema = z.object({ +export const groupSettingsSchema = z.object({ homeBoardId: z.string().nullable(), mobileHomeBoardId: z.string().nullable(), }); -const savePartialSettingsSchema = z.object({ +export const groupSavePartialSettingsSchema = z.object({ id: z.string(), - settings: settingsSchema.partial(), + settings: groupSettingsSchema.partial(), }); -const savePermissionsSchema = z.object({ +export const groupSavePermissionsSchema = z.object({ groupId: z.string(), permissions: z.array(zodEnumFromArray(groupPermissionKeys)), }); -const savePositionsSchema = z.object({ +export const groupSavePositionsSchema = z.object({ positions: z.array(z.string()), }); -const groupUserSchema = z.object({ groupId: z.string(), userId: z.string() }); - -export const groupSchemas = { - create: createSchema, - update: updateSchema, - savePermissions: savePermissionsSchema, - groupUser: groupUserSchema, - savePartialSettings: savePartialSettingsSchema, - settings: settingsSchema, - savePositions: savePositionsSchema, -}; +export const groupUserSchema = z.object({ groupId: z.string(), userId: z.string() }); diff --git a/packages/validation/src/icons.ts b/packages/validation/src/icons.ts index c621ecea5..6d134097f 100644 --- a/packages/validation/src/icons.ts +++ b/packages/validation/src/icons.ts @@ -1,10 +1,6 @@ import { z } from "zod"; -const findIconsSchema = z.object({ +export const iconsFindSchema = z.object({ searchText: z.string().optional(), limitPerGroup: z.number().min(1).max(500).default(12), }); - -export const iconsSchemas = { - findIcons: findIconsSchema, -}; diff --git a/packages/validation/src/index.ts b/packages/validation/src/index.ts deleted file mode 100644 index 7bc9e9407..000000000 --- a/packages/validation/src/index.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { appSchemas } from "./app"; -import { boardSchemas } from "./board"; -import { certificateSchemas } from "./certificates"; -import { commonSchemas } from "./common"; -import { groupSchemas } from "./group"; -import { iconsSchemas } from "./icons"; -import { integrationSchemas } from "./integration"; -import { locationSchemas } from "./location"; -import { mediaSchemas } from "./media"; -import { searchEngineSchemas } from "./search-engine"; -import { settingsSchemas } from "./settings"; -import { userSchemas } from "./user"; -import { widgetSchemas } from "./widgets"; - -export const validation = { - user: userSchemas, - group: groupSchemas, - integration: integrationSchemas, - board: boardSchemas, - app: appSchemas, - widget: widgetSchemas, - location: locationSchemas, - icons: iconsSchemas, - searchEngine: searchEngineSchemas, - media: mediaSchemas, - settings: settingsSchemas, - common: commonSchemas, - certificates: certificateSchemas, -}; - -export { - sectionSchema, - itemAdvancedOptionsSchema, - sharedItemSchema, - dynamicSectionOptionsSchema, - type BoardItemAdvancedOptions, - type BoardItemIntegration, -} from "./shared"; -export { superRefineCertificateFile } from "./certificates"; -export { passwordRequirements, usernameSchema } from "./user"; -export { supportedMediaUploadFormats } from "./media"; -export { zodEnumFromArray, zodUnionFromArray } from "./enums"; diff --git a/packages/validation/src/integration.ts b/packages/validation/src/integration.ts index e9606a268..00b3783fa 100644 --- a/packages/validation/src/integration.ts +++ b/packages/validation/src/integration.ts @@ -5,7 +5,7 @@ import { integrationKinds, integrationPermissions, integrationSecretKinds } from import { zodEnumFromArray } from "./enums"; import { createSavePermissionsSchema } from "./permissions"; -const integrationCreateSchema = z.object({ +export const integrationCreateSchema = z.object({ name: z.string().nonempty().max(127), url: z .string() @@ -21,7 +21,7 @@ const integrationCreateSchema = z.object({ attemptSearchEngineCreation: z.boolean(), }); -const integrationUpdateSchema = z.object({ +export const integrationUpdateSchema = z.object({ id: z.string().cuid2(), name: z.string().nonempty().max(127), url: z.string().url(), @@ -33,29 +33,4 @@ const integrationUpdateSchema = z.object({ ), }); -const idSchema = z.object({ - id: z.string(), -}); - -const testConnectionSchema = z.object({ - id: z.string().cuid2().nullable(), // Is used to use existing secrets if they have not been updated - url: z.string().url(), - kind: zodEnumFromArray(integrationKinds), - secrets: z.array( - z.object({ - kind: zodEnumFromArray(integrationSecretKinds), - value: z.string().nullable(), - }), - ), -}); - -const savePermissionsSchema = createSavePermissionsSchema(zodEnumFromArray(integrationPermissions)); - -export const integrationSchemas = { - create: integrationCreateSchema, - update: integrationUpdateSchema, - delete: idSchema, - byId: idSchema, - testConnection: testConnectionSchema, - savePermissions: savePermissionsSchema, -}; +export const integrationSavePermissionsSchema = createSavePermissionsSchema(zodEnumFromArray(integrationPermissions)); diff --git a/packages/validation/src/location.ts b/packages/validation/src/location.ts deleted file mode 100644 index b8d71ca3c..000000000 --- a/packages/validation/src/location.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { z } from "zod"; - -const citySchema = z.object({ - id: z.number(), - name: z.string(), - country: z.string().optional(), - country_code: z.string().optional(), - latitude: z.number(), - longitude: z.number(), - population: z.number().optional(), -}); - -const searchCityInput = z.object({ - query: z.string(), -}); - -const searchCityOutput = z - .object({ - results: z.array(citySchema), - }) - .or( - z - .object({ - generationtime_ms: z.number(), - }) - .refine((data) => Object.keys(data).length === 1, { message: "Invalid response" }) - .transform(() => ({ results: [] })), // We fallback to empty array if no results - ); - -export const locationSchemas = { - searchCity: { - input: searchCityInput, - output: searchCityOutput, - }, -}; diff --git a/packages/validation/src/media.ts b/packages/validation/src/media.ts index d18e87589..98f186c3d 100644 --- a/packages/validation/src/media.ts +++ b/packages/validation/src/media.ts @@ -5,7 +5,7 @@ import { createCustomErrorParams } from "./form/i18n"; export const supportedMediaUploadFormats = ["image/png", "image/jpeg", "image/webp", "image/gif", "image/svg+xml"]; -export const uploadMediaSchema = zfd.formData({ +export const mediaUploadSchema = zfd.formData({ file: zfd.file().superRefine((value: File | null, context: z.RefinementCtx) => { if (!value) { return context.addIssue({ @@ -26,6 +26,7 @@ export const uploadMediaSchema = zfd.formData({ } if (value.size > 1024 * 1024 * 32) { + // Don't forget to update the limit in nginx.conf (client_max_body_size) return context.addIssue({ code: "custom", params: createCustomErrorParams({ @@ -38,7 +39,3 @@ export const uploadMediaSchema = zfd.formData({ return null; }), }); - -export const mediaSchemas = { - uploadMedia: uploadMediaSchema, -}; diff --git a/packages/validation/src/search-engine.ts b/packages/validation/src/search-engine.ts index 720f5fb86..c84c77d9e 100644 --- a/packages/validation/src/search-engine.ts +++ b/packages/validation/src/search-engine.ts @@ -13,7 +13,7 @@ const fromIntegrationSearchEngine = z.object({ integrationId: z.string().optional(), }); -const manageSearchEngineSchema = z.object({ +const baseSearchEngineManageSchema = z.object({ name: z.string().min(1).max(64), short: z.string().min(1).max(8), iconUrl: z.string().min(1), @@ -21,21 +21,18 @@ const manageSearchEngineSchema = z.object({ }); const createManageSearchEngineSchema = ( - callback: (schema: typeof manageSearchEngineSchema) => T, + callback: (schema: typeof baseSearchEngineManageSchema) => T, ) => z .discriminatedUnion("type", [genericSearchEngine, fromIntegrationSearchEngine]) - .and(callback(manageSearchEngineSchema)); + .and(callback(baseSearchEngineManageSchema)); -const editSearchEngineSchema = createManageSearchEngineSchema((schema) => +export const searchEngineManageSchema = createManageSearchEngineSchema((schema) => schema); + +export const searchEngineEditSchema = createManageSearchEngineSchema((schema) => schema .extend({ id: z.string(), }) .omit({ short: true }), ); - -export const searchEngineSchemas = { - manage: createManageSearchEngineSchema((schema) => schema), - edit: editSearchEngineSchema, -}; diff --git a/packages/validation/src/settings.ts b/packages/validation/src/settings.ts index 8eb5225ac..7110dfb3e 100644 --- a/packages/validation/src/settings.ts +++ b/packages/validation/src/settings.ts @@ -1,6 +1,6 @@ import { z } from "zod"; -const initSettingsSchema = z.object({ +export const settingsInitSchema = z.object({ analytics: z.object({ enableGeneral: z.boolean(), enableWidgetData: z.boolean(), @@ -14,7 +14,3 @@ const initSettingsSchema = z.object({ noSiteLinksSearchBox: z.boolean(), }), }); - -export const settingsSchemas = { - init: initSettingsSchema, -}; diff --git a/packages/validation/src/user.ts b/packages/validation/src/user.ts index 9e7c9da73..b8d78e8ee 100644 --- a/packages/validation/src/user.ts +++ b/packages/validation/src/user.ts @@ -22,7 +22,7 @@ export const passwordRequirements = [ value: keyof TranslationObject["user"]["field"]["password"]["requirement"]; }[]; -const passwordSchema = z +export const userPasswordSchema = z .string() .min(8) .max(255) @@ -51,39 +51,39 @@ const addConfirmPasswordRefinement = ((value) => z.number().min(0).max(6).safeParse(value).success), }); -const pingIconsEnabledSchema = z.object({ +export const userPingIconsEnabledSchema = z.object({ pingIconsEnabled: z.boolean(), }); - -export const userSchemas = { - signIn: signInSchema, - registration: registrationSchema, - registrationApi: registrationSchemaApi, - init: initUserSchema, - create: createUserSchema, - baseCreate: baseCreateUserSchema, - password: passwordSchema, - editProfile: editProfileSchema, - changePassword: changePasswordSchema, - changeHomeBoards: changeHomeBoardSchema, - changeSearchPreferences: changeSearchPreferencesSchema, - changePasswordApi: changePasswordApiSchema, - changeColorScheme: changeColorSchemeSchema, - firstDayOfWeek: firstDayOfWeekSchema, - pingIconsEnabled: pingIconsEnabledSchema, -}; diff --git a/packages/validation/src/widgets/index.ts b/packages/validation/src/widgets/index.ts deleted file mode 100644 index bf007766d..000000000 --- a/packages/validation/src/widgets/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { weatherWidgetSchemas } from "./weather"; - -export const widgetSchemas = { - weather: weatherWidgetSchemas, -}; diff --git a/packages/validation/src/widgets/media-request.ts b/packages/validation/src/widgets/media-request.ts new file mode 100644 index 000000000..aa0f85c6e --- /dev/null +++ b/packages/validation/src/widgets/media-request.ts @@ -0,0 +1,12 @@ +import { z } from "zod"; + +export const mediaRequestOptionsSchema = z.object({ + mediaId: z.number(), + mediaType: z.enum(["tv", "movie"]), +}); + +export const mediaRequestRequestSchema = z.object({ + mediaType: z.enum(["tv", "movie"]), + mediaId: z.number(), + seasons: z.array(z.number().min(0)).optional(), +}); diff --git a/packages/validation/src/widgets/weather.ts b/packages/validation/src/widgets/weather.ts deleted file mode 100644 index 6b9bf74b9..000000000 --- a/packages/validation/src/widgets/weather.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { z } from "zod"; - -export const atLocationInput = z.object({ - longitude: z.number(), - latitude: z.number(), -}); - -export const atLocationOutput = z.object({ - current_weather: z.object({ - weathercode: z.number(), - temperature: z.number(), - windspeed: z.number(), - }), - daily: z.object({ - time: z.array(z.string()), - weathercode: z.array(z.number()), - temperature_2m_max: z.array(z.number()), - temperature_2m_min: z.array(z.number()), - sunrise: z.array(z.string()), - sunset: z.array(z.string()), - wind_speed_10m_max: z.array(z.number()), - wind_gusts_10m_max: z.array(z.number()), - }), -}); - -export const weatherWidgetSchemas = { - atLocationInput, - atLocationOutput, -}; diff --git a/packages/widgets/package.json b/packages/widgets/package.json index 265c38d3f..6e1be6c8b 100644 --- a/packages/widgets/package.json +++ b/packages/widgets/package.json @@ -44,9 +44,9 @@ "@homarr/translation": "workspace:^0.1.0", "@homarr/ui": "workspace:^0.1.0", "@homarr/validation": "workspace:^0.1.0", - "@mantine/charts": "^7.17.3", - "@mantine/core": "^7.17.3", - "@mantine/hooks": "^7.17.3", + "@mantine/charts": "^7.17.4", + "@mantine/core": "^7.17.4", + "@mantine/hooks": "^7.17.4", "@tabler/icons-react": "^3.31.0", "@tiptap/extension-color": "2.11.7", "@tiptap/extension-highlight": "2.11.7", @@ -66,7 +66,7 @@ "clsx": "^2.1.1", "dayjs": "^1.11.13", "mantine-react-table": "2.0.0-beta.9", - "next": "15.2.4", + "next": "15.2.5", "react": "19.1.0", "react-dom": "19.1.0", "recharts": "^2.15.2", @@ -78,7 +78,7 @@ "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", "@types/video.js": "^7.3.58", - "eslint": "^9.23.0", - "typescript": "^5.8.2" + "eslint": "^9.24.0", + "typescript": "^5.8.3" } } diff --git a/packages/widgets/src/index.tsx b/packages/widgets/src/index.tsx index dab575965..b9d21e825 100644 --- a/packages/widgets/src/index.tsx +++ b/packages/widgets/src/index.tsx @@ -24,6 +24,8 @@ import * as mediaRequestsStats from "./media-requests/stats"; import * as mediaServer from "./media-server"; import * as mediaTranscoding from "./media-transcoding"; import * as minecraftServerStatus from "./minecraft/server-status"; +import * as networkControllerStatus from "./network-controller/network-status"; +import * as networkControllerSummary from "./network-controller/summary"; import * as notebook from "./notebook"; import type { WidgetOptionDefinition } from "./options"; import * as rssFeed from "./rssFeed"; @@ -53,6 +55,8 @@ export const widgetImports = { downloads, "mediaRequests-requestList": mediaRequestsList, "mediaRequests-requestStats": mediaRequestsStats, + networkControllerSummary, + networkControllerStatus, rssFeed, bookmarks, indexerManager, diff --git a/packages/widgets/src/modals/widget-advanced-options-modal.tsx b/packages/widgets/src/modals/widget-advanced-options-modal.tsx index f957b100a..f2dd98db9 100644 --- a/packages/widgets/src/modals/widget-advanced-options-modal.tsx +++ b/packages/widgets/src/modals/widget-advanced-options-modal.tsx @@ -6,7 +6,7 @@ import { useForm } from "@homarr/form"; import { createModal } from "@homarr/modals"; import { useI18n } from "@homarr/translation/client"; import { TextMultiSelect } from "@homarr/ui"; -import type { BoardItemAdvancedOptions } from "@homarr/validation"; +import type { BoardItemAdvancedOptions } from "@homarr/validation/shared"; interface InnerProps { advancedOptions: BoardItemAdvancedOptions; diff --git a/packages/widgets/src/modals/widget-edit-modal.tsx b/packages/widgets/src/modals/widget-edit-modal.tsx index 6667637ed..05fca7fd4 100644 --- a/packages/widgets/src/modals/widget-edit-modal.tsx +++ b/packages/widgets/src/modals/widget-edit-modal.tsx @@ -10,7 +10,7 @@ import { zodResolver } from "@homarr/form"; import { createModal, useModalAction } from "@homarr/modals"; import type { SettingsContextProps } from "@homarr/settings"; import { useI18n } from "@homarr/translation/client"; -import { zodErrorMap } from "@homarr/validation/form"; +import { zodErrorMap } from "@homarr/validation/form/i18n"; import { widgetImports } from ".."; import { getInputForType } from "../_inputs"; diff --git a/packages/widgets/src/network-controller/network-status/component.tsx b/packages/widgets/src/network-controller/network-status/component.tsx new file mode 100644 index 000000000..f87973252 --- /dev/null +++ b/packages/widgets/src/network-controller/network-status/component.tsx @@ -0,0 +1,84 @@ +"use client"; + +import { useMemo } from "react"; +import { Box } from "@mantine/core"; +import dayjs from "dayjs"; +import duration from "dayjs/plugin/duration"; +import objectSupport from "dayjs/plugin/objectSupport"; +import relativeTime from "dayjs/plugin/relativeTime"; + +import { clientApi } from "@homarr/api/client"; + +import type { WidgetComponentProps } from "../../definition"; +import { WifiVariant } from "./variants/wifi-variant"; +import { WiredVariant } from "./variants/wired-variant"; + +dayjs.extend(objectSupport); +dayjs.extend(relativeTime); +dayjs.extend(duration); + +export default function NetworkControllerNetworkStatusWidget({ + options, + integrationIds, +}: WidgetComponentProps<"networkControllerStatus">) { + const [summaries] = clientApi.widget.networkController.summary.useSuspenseQuery( + { + integrationIds, + }, + { + refetchOnMount: false, + refetchOnWindowFocus: false, + refetchOnReconnect: false, + retry: false, + }, + ); + const utils = clientApi.useUtils(); + + clientApi.widget.networkController.subscribeToSummary.useSubscription( + { + integrationIds, + }, + { + onData: (data) => { + utils.widget.networkController.summary.setData( + { + integrationIds, + }, + (prevData) => { + if (!prevData) { + return undefined; + } + + return prevData.map((item) => + item.integration.id === data.integration.id + ? { + ...item, + summary: data.summary, + updatedAt: new Date(), + } + : item, + ); + }, + ); + }, + }, + ); + + const data = useMemo(() => summaries.flatMap(({ summary }) => summary), [summaries]); + + return ( + + {options.content === "wifi" ? ( + sum + summary.wifi.guests, 0)} + countUsers={data.reduce((sum, summary) => sum + summary.wifi.users, 0)} + /> + ) : ( + sum + summary.lan.guests, 0)} + countUsers={data.reduce((sum, summary) => sum + summary.lan.users, 0)} + /> + )} + + ); +} diff --git a/packages/widgets/src/network-controller/network-status/index.ts b/packages/widgets/src/network-controller/network-status/index.ts new file mode 100644 index 000000000..4af2fbaf0 --- /dev/null +++ b/packages/widgets/src/network-controller/network-status/index.ts @@ -0,0 +1,28 @@ +import { IconServerOff, IconTopologyFull } from "@tabler/icons-react"; + +import { getIntegrationKindsByCategory } from "@homarr/definitions"; + +import { createWidgetDefinition } from "../../definition"; +import { optionsBuilder } from "../../options"; + +export const { definition, componentLoader } = createWidgetDefinition("networkControllerStatus", { + icon: IconTopologyFull, + createOptions() { + return optionsBuilder.from((factory) => ({ + content: factory.select({ + options: (["wifi", "wired"] as const).map((value) => ({ + value, + label: (t) => t(`widget.networkControllerStatus.option.content.option.${value}.label`), + })), + defaultValue: "wifi", + }), + })); + }, + supportedIntegrations: getIntegrationKindsByCategory("networkController"), + errors: { + INTERNAL_SERVER_ERROR: { + icon: IconServerOff, + message: (t) => t("widget.networkController.error.internalServerError"), + }, + }, +}).withDynamicImport(() => import("./component")); diff --git a/packages/widgets/src/network-controller/network-status/variants/stat-row.tsx b/packages/widgets/src/network-controller/network-status/variants/stat-row.tsx new file mode 100644 index 000000000..aa6c1998b --- /dev/null +++ b/packages/widgets/src/network-controller/network-status/variants/stat-row.tsx @@ -0,0 +1,14 @@ +import { Stack, Text } from "@mantine/core"; + +export const StatRow = ({ label, value }: { label: string; value: string | number }) => { + return ( + + + {value} + + + {label} + + + ); +}; diff --git a/packages/widgets/src/network-controller/network-status/variants/wifi-variant.tsx b/packages/widgets/src/network-controller/network-status/variants/wifi-variant.tsx new file mode 100644 index 000000000..85b7e2355 --- /dev/null +++ b/packages/widgets/src/network-controller/network-status/variants/wifi-variant.tsx @@ -0,0 +1,24 @@ +import { Group, Stack, Text } from "@mantine/core"; +import { IconWifi } from "@tabler/icons-react"; + +import { useScopedI18n } from "@homarr/translation/client"; + +import { StatRow } from "./stat-row"; + +export const WifiVariant = ({ countGuests, countUsers }: { countUsers: number; countGuests: number }) => { + const t = useScopedI18n("widget.networkControllerStatus.card"); + return ( + <> + + + + {t("variants.wifi.name")} + + + + + + + + ); +}; diff --git a/packages/widgets/src/network-controller/network-status/variants/wired-variant.tsx b/packages/widgets/src/network-controller/network-status/variants/wired-variant.tsx new file mode 100644 index 000000000..f635dd897 --- /dev/null +++ b/packages/widgets/src/network-controller/network-status/variants/wired-variant.tsx @@ -0,0 +1,24 @@ +import { Group, Stack, Text } from "@mantine/core"; +import { IconNetwork } from "@tabler/icons-react"; + +import { useScopedI18n } from "@homarr/translation/client"; + +import { StatRow } from "./stat-row"; + +export const WiredVariant = ({ countGuests, countUsers }: { countUsers: number; countGuests: number }) => { + const t = useScopedI18n("widget.networkControllerStatus.card"); + return ( + <> + + + + {t("variants.wired.name")} + + + + + + + + ); +}; diff --git a/packages/widgets/src/network-controller/summary/component.tsx b/packages/widgets/src/network-controller/summary/component.tsx new file mode 100644 index 000000000..bbd9775cd --- /dev/null +++ b/packages/widgets/src/network-controller/summary/component.tsx @@ -0,0 +1,98 @@ +"use client"; + +import { useMemo } from "react"; +import { Box, Center, List, Text, useMantineTheme } from "@mantine/core"; +import { IconCircleCheckFilled, IconCircleXFilled } from "@tabler/icons-react"; +import dayjs from "dayjs"; +import duration from "dayjs/plugin/duration"; +import objectSupport from "dayjs/plugin/objectSupport"; +import relativeTime from "dayjs/plugin/relativeTime"; + +import { clientApi } from "@homarr/api/client"; +import { useI18n } from "@homarr/translation/client"; + +import type { WidgetComponentProps } from "../../definition"; + +dayjs.extend(objectSupport); +dayjs.extend(relativeTime); +dayjs.extend(duration); + +export default function NetworkControllerSummaryWidget({ + integrationIds, +}: WidgetComponentProps<"networkControllerSummary">) { + const [summaries] = clientApi.widget.networkController.summary.useSuspenseQuery( + { + integrationIds, + }, + { + refetchOnMount: false, + refetchOnWindowFocus: false, + refetchOnReconnect: false, + retry: false, + }, + ); + const utils = clientApi.useUtils(); + + const t = useI18n(); + + clientApi.widget.networkController.subscribeToSummary.useSubscription( + { + integrationIds, + }, + { + onData: (data) => { + utils.widget.networkController.summary.setData( + { + integrationIds, + }, + (prevData) => { + if (!prevData) { + return undefined; + } + + return prevData.map((item) => + item.integration.id === data.integration.id ? { ...item, summary: data.summary } : item, + ); + }, + ); + }, + }, + ); + + const data = useMemo(() => summaries.flatMap(({ summary }) => summary), [summaries]); + + return ( + +
+ + }>WAN + }> + + WWW + + {data[0]?.www.latency}ms + + + + }>Wi-Fi + }> + + VPN + + {t("widget.networkControllerSummary.card.vpn.countConnected", { count: `${data[0]?.vpn.users}` })} + + + + +
+
+ ); +} + +const StatusIcon = ({ status }: { status?: "enabled" | "disabled" }) => { + const mantineTheme = useMantineTheme(); + if (status === "enabled") { + return ; + } + return ; +}; diff --git a/packages/widgets/src/network-controller/summary/index.ts b/packages/widgets/src/network-controller/summary/index.ts new file mode 100644 index 000000000..dd541024a --- /dev/null +++ b/packages/widgets/src/network-controller/summary/index.ts @@ -0,0 +1,20 @@ +import { IconServerOff, IconTopologyFull } from "@tabler/icons-react"; + +import { getIntegrationKindsByCategory } from "@homarr/definitions"; + +import { createWidgetDefinition } from "../../definition"; +import { optionsBuilder } from "../../options"; + +export const { definition, componentLoader } = createWidgetDefinition("networkControllerSummary", { + icon: IconTopologyFull, + createOptions() { + return optionsBuilder.from(() => ({})); + }, + supportedIntegrations: getIntegrationKindsByCategory("networkController"), + errors: { + INTERNAL_SERVER_ERROR: { + icon: IconServerOff, + message: (t) => t("widget.networkController.error.internalServerError"), + }, + }, +}).withDynamicImport(() => import("./component")); diff --git a/packages/widgets/src/notebook/notebook.tsx b/packages/widgets/src/notebook/notebook.tsx index a30048427..acb22d73e 100644 --- a/packages/widgets/src/notebook/notebook.tsx +++ b/packages/widgets/src/notebook/notebook.tsx @@ -67,6 +67,10 @@ import type { WidgetComponentProps } from "../definition"; import "./notebook.css"; +import { useSession } from "@homarr/auth/client"; +import { constructBoardPermissions } from "@homarr/auth/shared"; +import { useRequiredBoard } from "@homarr/boards/context"; + const iconProps = { size: 30, stroke: 1.5, @@ -81,8 +85,11 @@ export function Notebook({ options, isEditMode, boardId, itemId }: WidgetCompone const [content, setContent] = useState(options.content); const [toSaveContent, setToSaveContent] = useState(content); - // TODO: Add check for user permissions - const enabled = !isEditMode; + const board = useRequiredBoard(); + const { data: session } = useSession(); + const { hasChangeAccess } = constructBoardPermissions(board, session); + + const enabled = !isEditMode && hasChangeAccess; const [isEditing, setIsEditing] = useState(false); const { primaryColor } = useMantineTheme(); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c4309cdaf..a4b9e4543 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -21,25 +21,25 @@ importers: version: link:tooling/prettier '@semantic-release/changelog': specifier: ^6.0.3 - version: 6.0.3(semantic-release@24.2.3(typescript@5.8.2)) + version: 6.0.3(semantic-release@24.2.3(typescript@5.8.3)) '@semantic-release/commit-analyzer': specifier: ^13.0.1 - version: 13.0.1(semantic-release@24.2.3(typescript@5.8.2)) + version: 13.0.1(semantic-release@24.2.3(typescript@5.8.3)) '@semantic-release/git': specifier: ^10.0.1 - version: 10.0.1(semantic-release@24.2.3(typescript@5.8.2)) + version: 10.0.1(semantic-release@24.2.3(typescript@5.8.3)) '@semantic-release/github': specifier: ^11.0.1 - version: 11.0.1(semantic-release@24.2.3(typescript@5.8.2)) + version: 11.0.1(semantic-release@24.2.3(typescript@5.8.3)) '@semantic-release/npm': specifier: ^12.0.1 - version: 12.0.1(semantic-release@24.2.3(typescript@5.8.2)) + version: 12.0.1(semantic-release@24.2.3(typescript@5.8.3)) '@semantic-release/release-notes-generator': specifier: ^14.0.3 - version: 14.0.3(semantic-release@24.2.3(typescript@5.8.2)) + version: 14.0.3(semantic-release@24.2.3(typescript@5.8.3)) '@turbo/gen': specifier: ^2.5.0 - version: 2.5.0(@types/node@22.14.0)(typescript@5.8.2) + version: 2.5.0(@types/node@22.14.0)(typescript@5.8.3) '@vitejs/plugin-react': specifier: ^4.3.4 version: 4.3.4(vite@5.4.5(@types/node@22.14.0)(sass@1.86.3)(sugarss@4.0.1(postcss@8.4.47))(terser@5.39.0)) @@ -63,19 +63,19 @@ importers: version: 3.5.3 semantic-release: specifier: ^24.2.3 - version: 24.2.3(typescript@5.8.2) + version: 24.2.3(typescript@5.8.3) testcontainers: - specifier: ^10.24.0 - version: 10.24.0 + specifier: ^10.24.1 + version: 10.24.1 turbo: specifier: ^2.5.0 version: 2.5.0 typescript: - specifier: ^5.8.2 - version: 5.8.2 + specifier: ^5.8.3 + version: 5.8.3 vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.8.2)(vite@5.4.5(@types/node@22.14.0)(sass@1.86.3)(sugarss@4.0.1(postcss@8.4.47))(terser@5.39.0)) + version: 5.1.4(typescript@5.8.3)(vite@5.4.5(@types/node@22.14.0)(sass@1.86.3)(sugarss@4.0.1(postcss@8.4.47))(terser@5.39.0)) vitest: specifier: ^3.1.1 version: 3.1.1(@types/node@22.14.0)(@vitest/ui@3.1.1)(jsdom@26.0.0)(sass@1.86.3)(sugarss@4.0.1(postcss@8.4.47))(terser@5.39.0) @@ -182,23 +182,23 @@ importers: specifier: workspace:^0.1.0 version: link:../../packages/widgets '@mantine/colors-generator': - specifier: ^7.17.3 - version: 7.17.3(chroma-js@3.1.2) + specifier: ^7.17.4 + version: 7.17.4(chroma-js@3.1.2) '@mantine/core': - specifier: ^7.17.3 - version: 7.17.3(@mantine/hooks@7.17.3(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + specifier: ^7.17.4 + version: 7.17.4(@mantine/hooks@7.17.4(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@mantine/dropzone': - specifier: ^7.17.3 - version: 7.17.3(@mantine/core@7.17.3(@mantine/hooks@7.17.3(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@mantine/hooks@7.17.3(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + specifier: ^7.17.4 + version: 7.17.4(@mantine/core@7.17.4(@mantine/hooks@7.17.4(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@mantine/hooks@7.17.4(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@mantine/hooks': - specifier: ^7.17.3 - version: 7.17.3(react@19.1.0) + specifier: ^7.17.4 + version: 7.17.4(react@19.1.0) '@mantine/modals': - specifier: ^7.17.3 - version: 7.17.3(@mantine/core@7.17.3(@mantine/hooks@7.17.3(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@mantine/hooks@7.17.3(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + specifier: ^7.17.4 + version: 7.17.4(@mantine/core@7.17.4(@mantine/hooks@7.17.4(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@mantine/hooks@7.17.4(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@mantine/tiptap': - specifier: ^7.17.3 - version: 7.17.3(@mantine/core@7.17.3(@mantine/hooks@7.17.3(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@mantine/hooks@7.17.3(react@19.1.0))(@tiptap/extension-link@2.11.7(@tiptap/core@2.11.7(@tiptap/pm@2.11.7))(@tiptap/pm@2.11.7))(@tiptap/react@2.11.7(@tiptap/core@2.11.7(@tiptap/pm@2.11.7))(@tiptap/pm@2.11.7)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + specifier: ^7.17.4 + version: 7.17.4(@mantine/core@7.17.4(@mantine/hooks@7.17.4(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@mantine/hooks@7.17.4(react@19.1.0))(@tiptap/extension-link@2.11.7(@tiptap/core@2.11.7(@tiptap/pm@2.11.7))(@tiptap/pm@2.11.7))(@tiptap/react@2.11.7(@tiptap/core@2.11.7(@tiptap/pm@2.11.7))(@tiptap/pm@2.11.7)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@million/lint': specifier: 1.0.14 version: 1.0.14(rollup@4.21.3)(webpack-sources@3.2.3) @@ -206,26 +206,26 @@ importers: specifier: ^3.31.0 version: 3.31.0(react@19.1.0) '@tanstack/react-query': - specifier: ^5.71.10 - version: 5.71.10(react@19.1.0) + specifier: ^5.72.1 + version: 5.72.1(react@19.1.0) '@tanstack/react-query-devtools': - specifier: ^5.71.10 - version: 5.71.10(@tanstack/react-query@5.71.10(react@19.1.0))(react@19.1.0) + specifier: ^5.72.1 + version: 5.72.1(@tanstack/react-query@5.72.1(react@19.1.0))(react@19.1.0) '@tanstack/react-query-next-experimental': - specifier: ^5.71.10 - version: 5.71.10(@tanstack/react-query@5.71.10(react@19.1.0))(next@15.2.4(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.3))(react@19.1.0) + specifier: ^5.72.1 + version: 5.72.1(@tanstack/react-query@5.72.1(react@19.1.0))(next@15.2.5(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.3))(react@19.1.0) '@trpc/client': - specifier: ^11.0.2 - version: 11.0.2(@trpc/server@11.0.2(typescript@5.8.2))(typescript@5.8.2) + specifier: ^11.0.4 + version: 11.0.4(@trpc/server@11.0.4(typescript@5.8.3))(typescript@5.8.3) '@trpc/next': - specifier: ^11.0.2 - version: 11.0.2(@tanstack/react-query@5.71.10(react@19.1.0))(@trpc/client@11.0.2(@trpc/server@11.0.2(typescript@5.8.2))(typescript@5.8.2))(@trpc/react-query@11.0.2(@tanstack/react-query@5.71.10(react@19.1.0))(@trpc/client@11.0.2(@trpc/server@11.0.2(typescript@5.8.2))(typescript@5.8.2))(@trpc/server@11.0.2(typescript@5.8.2))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(typescript@5.8.2))(@trpc/server@11.0.2(typescript@5.8.2))(next@15.2.4(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.3))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(typescript@5.8.2) + specifier: ^11.0.4 + version: 11.0.4(@tanstack/react-query@5.72.1(react@19.1.0))(@trpc/client@11.0.4(@trpc/server@11.0.4(typescript@5.8.3))(typescript@5.8.3))(@trpc/react-query@11.0.4(@tanstack/react-query@5.72.1(react@19.1.0))(@trpc/client@11.0.4(@trpc/server@11.0.4(typescript@5.8.3))(typescript@5.8.3))(@trpc/server@11.0.4(typescript@5.8.3))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(typescript@5.8.3))(@trpc/server@11.0.4(typescript@5.8.3))(next@15.2.5(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.3))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(typescript@5.8.3) '@trpc/react-query': - specifier: ^11.0.2 - version: 11.0.2(@tanstack/react-query@5.71.10(react@19.1.0))(@trpc/client@11.0.2(@trpc/server@11.0.2(typescript@5.8.2))(typescript@5.8.2))(@trpc/server@11.0.2(typescript@5.8.2))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(typescript@5.8.2) + specifier: ^11.0.4 + version: 11.0.4(@tanstack/react-query@5.72.1(react@19.1.0))(@trpc/client@11.0.4(@trpc/server@11.0.4(typescript@5.8.3))(typescript@5.8.3))(@trpc/server@11.0.4(typescript@5.8.3))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(typescript@5.8.3) '@trpc/server': - specifier: ^11.0.2 - version: 11.0.2(typescript@5.8.2) + specifier: ^11.0.4 + version: 11.0.4(typescript@5.8.3) '@xterm/addon-canvas': specifier: ^0.7.0 version: 0.7.0(@xterm/xterm@5.5.0) @@ -258,10 +258,10 @@ importers: version: 2.12.2(@types/react@19.1.0)(react@19.1.0) mantine-react-table: specifier: 2.0.0-beta.9 - version: 2.0.0-beta.9(@mantine/core@7.17.3(@mantine/hooks@7.17.3(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@mantine/dates@7.17.3(@mantine/core@7.17.3(@mantine/hooks@7.17.3(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@mantine/hooks@7.17.3(react@19.1.0))(dayjs@1.11.13)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@mantine/hooks@7.17.3(react@19.1.0))(@tabler/icons-react@3.31.0(react@19.1.0))(clsx@2.1.1)(dayjs@1.11.13)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + version: 2.0.0-beta.9(@mantine/core@7.17.4(@mantine/hooks@7.17.4(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@mantine/dates@7.17.4(@mantine/core@7.17.4(@mantine/hooks@7.17.4(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@mantine/hooks@7.17.4(react@19.1.0))(dayjs@1.11.13)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@mantine/hooks@7.17.4(react@19.1.0))(@tabler/icons-react@3.31.0(react@19.1.0))(clsx@2.1.1)(dayjs@1.11.13)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) next: - specifier: 15.2.4 - version: 15.2.4(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.3) + specifier: 15.2.5 + version: 15.2.5(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.3) postcss-preset-mantine: specifier: ^1.17.0 version: 1.17.0(postcss@8.4.47) @@ -287,8 +287,8 @@ importers: specifier: 2.2.2 version: 2.2.2 swagger-ui-react: - specifier: ^5.20.6 - version: 5.20.6(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + specifier: ^5.20.7 + version: 5.20.7(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) use-deep-compare-effect: specifier: ^1.8.1 version: 1.8.1(react@19.1.0) @@ -318,8 +318,8 @@ importers: specifier: 19.1.0 version: 19.1.0 '@types/react-dom': - specifier: 19.1.1 - version: 19.1.1(@types/react@19.1.0) + specifier: 19.1.2 + version: 19.1.2(@types/react@19.1.0) '@types/swagger-ui-react': specifier: ^5.18.0 version: 5.18.0 @@ -327,8 +327,8 @@ importers: specifier: ^9.1.2 version: 9.1.2 eslint: - specifier: ^9.23.0 - version: 9.23.0 + specifier: ^9.24.0 + version: 9.24.0 node-loader: specifier: ^2.1.0 version: 2.1.0(webpack@5.94.0) @@ -336,8 +336,8 @@ importers: specifier: ^3.5.3 version: 3.5.3 typescript: - specifier: ^5.8.2 - version: 5.8.2 + specifier: ^5.8.3 + version: 5.8.3 apps/tasks: dependencies: @@ -415,8 +415,8 @@ importers: specifier: ^8.0.0 version: 8.0.0 eslint: - specifier: ^9.23.0 - version: 9.23.0 + specifier: ^9.24.0 + version: 9.24.0 prettier: specifier: ^3.5.3 version: 3.5.3 @@ -424,8 +424,8 @@ importers: specifier: 4.19.3 version: 4.19.3 typescript: - specifier: ^5.8.2 - version: 5.8.2 + specifier: ^5.8.3 + version: 5.8.3 apps/websocket: dependencies: @@ -476,14 +476,14 @@ importers: specifier: ^8.18.1 version: 8.18.1 eslint: - specifier: ^9.23.0 - version: 9.23.0 + specifier: ^9.24.0 + version: 9.24.0 prettier: specifier: ^3.5.3 version: 3.5.3 typescript: - specifier: ^5.8.2 - version: 5.8.2 + specifier: ^5.8.3 + version: 5.8.3 packages/analytics: dependencies: @@ -513,11 +513,11 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript eslint: - specifier: ^9.23.0 - version: 9.23.0 + specifier: ^9.24.0 + version: 9.24.0 typescript: - specifier: ^5.8.2 - version: 5.8.2 + specifier: ^5.8.3 + version: 5.8.3 packages/api: dependencies: @@ -579,23 +579,23 @@ importers: specifier: workspace:^0.1.0 version: link:../validation '@kubernetes/client-node': - specifier: ^1.1.1 - version: 1.1.1 + specifier: ^1.1.2 + version: 1.1.2 '@trpc/client': - specifier: ^11.0.2 - version: 11.0.2(@trpc/server@11.0.2(typescript@5.8.2))(typescript@5.8.2) + specifier: ^11.0.4 + version: 11.0.4(@trpc/server@11.0.4(typescript@5.8.3))(typescript@5.8.3) '@trpc/react-query': - specifier: ^11.0.2 - version: 11.0.2(@tanstack/react-query@5.71.10(react@19.1.0))(@trpc/client@11.0.2(@trpc/server@11.0.2(typescript@5.8.2))(typescript@5.8.2))(@trpc/server@11.0.2(typescript@5.8.2))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(typescript@5.8.2) + specifier: ^11.0.4 + version: 11.0.4(@tanstack/react-query@5.72.1(react@19.1.0))(@trpc/client@11.0.4(@trpc/server@11.0.4(typescript@5.8.3))(typescript@5.8.3))(@trpc/server@11.0.4(typescript@5.8.3))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(typescript@5.8.3) '@trpc/server': - specifier: ^11.0.2 - version: 11.0.2(typescript@5.8.2) + specifier: ^11.0.4 + version: 11.0.4(typescript@5.8.3) lodash.clonedeep: specifier: ^4.5.0 version: 4.5.0 next: - specifier: 15.2.4 - version: 15.2.4(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.3) + specifier: 15.2.5 + version: 15.2.5(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.3) pretty-print-error: specifier: ^1.1.2 version: 1.1.2(patch_hash=d1432e02330bdaf8359eb0e54528a74ed6b7e5cce6bb65c13310c82e34fd1e4d) @@ -610,7 +610,7 @@ importers: version: 2.2.2 trpc-to-openapi: specifier: ^2.1.5 - version: 2.1.5(@trpc/server@11.0.2(typescript@5.8.2))(zod-openapi@2.19.0(zod@3.24.2))(zod@3.24.2) + version: 2.1.5(@trpc/server@11.0.4(typescript@5.8.3))(zod-openapi@2.19.0(zod@3.24.2))(zod@3.24.2) zod: specifier: ^3.24.2 version: 3.24.2 @@ -625,14 +625,14 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript eslint: - specifier: ^9.23.0 - version: 9.23.0 + specifier: ^9.24.0 + version: 9.24.0 prettier: specifier: ^3.5.3 version: 3.5.3 typescript: - specifier: ^5.8.2 - version: 5.8.2 + specifier: ^5.8.3 + version: 5.8.3 packages/auth: dependencies: @@ -670,14 +670,14 @@ importers: specifier: ^0.9.1 version: 0.9.1 ldapts: - specifier: 7.3.3 - version: 7.3.3 + specifier: 7.4.0 + version: 7.4.0 next: - specifier: 15.2.4 - version: 15.2.4(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.3) + specifier: 15.2.5 + version: 15.2.5(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.3) next-auth: specifier: 5.0.0-beta.25 - version: 5.0.0-beta.25(next@15.2.4(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.3))(react@19.1.0) + version: 5.0.0-beta.25(next@15.2.5(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.3))(react@19.1.0) pretty-print-error: specifier: ^1.1.2 version: 1.1.2(patch_hash=d1432e02330bdaf8359eb0e54528a74ed6b7e5cce6bb65c13310c82e34fd1e4d) @@ -707,14 +707,14 @@ importers: specifier: 0.9.0 version: 0.9.0 eslint: - specifier: ^9.23.0 - version: 9.23.0 + specifier: ^9.24.0 + version: 9.24.0 prettier: specifier: ^3.5.3 version: 3.5.3 typescript: - specifier: ^5.8.2 - version: 5.8.2 + specifier: ^5.8.3 + version: 5.8.3 packages/boards: dependencies: @@ -738,11 +738,11 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript eslint: - specifier: ^9.23.0 - version: 9.23.0 + specifier: ^9.24.0 + version: 9.24.0 typescript: - specifier: ^5.8.2 - version: 5.8.2 + specifier: ^5.8.3 + version: 5.8.3 packages/certificates: dependencies: @@ -763,11 +763,11 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript eslint: - specifier: ^9.23.0 - version: 9.23.0 + specifier: ^9.24.0 + version: 9.24.0 typescript: - specifier: ^5.8.2 - version: 5.8.2 + specifier: ^5.8.3 + version: 5.8.3 packages/cli: dependencies: @@ -800,11 +800,11 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript eslint: - specifier: ^9.23.0 - version: 9.23.0 + specifier: ^9.24.0 + version: 9.24.0 typescript: - specifier: ^5.8.2 - version: 5.8.2 + specifier: ^5.8.3 + version: 5.8.3 packages/common: dependencies: @@ -818,8 +818,8 @@ importers: specifier: ^1.11.13 version: 1.11.13 next: - specifier: 15.2.4 - version: 15.2.4(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.3) + specifier: 15.2.5 + version: 15.2.5(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.3) react: specifier: 19.1.0 version: 19.1.0 @@ -843,11 +843,11 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript eslint: - specifier: ^9.23.0 - version: 9.23.0 + specifier: ^9.24.0 + version: 9.24.0 typescript: - specifier: ^5.8.2 - version: 5.8.2 + specifier: ^5.8.3 + version: 5.8.3 packages/cron-job-runner: dependencies: @@ -877,11 +877,11 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript eslint: - specifier: ^9.23.0 - version: 9.23.0 + specifier: ^9.24.0 + version: 9.24.0 typescript: - specifier: ^5.8.2 - version: 5.8.2 + specifier: ^5.8.3 + version: 5.8.3 packages/cron-job-status: dependencies: @@ -899,11 +899,11 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript eslint: - specifier: ^9.23.0 - version: 9.23.0 + specifier: ^9.24.0 + version: 9.24.0 typescript: - specifier: ^5.8.2 - version: 5.8.2 + specifier: ^5.8.3 + version: 5.8.3 packages/cron-jobs: dependencies: @@ -969,11 +969,11 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript eslint: - specifier: ^9.23.0 - version: 9.23.0 + specifier: ^9.24.0 + version: 9.24.0 typescript: - specifier: ^5.8.2 - version: 5.8.2 + specifier: ^5.8.3 + version: 5.8.3 packages/cron-jobs-core: dependencies: @@ -997,11 +997,11 @@ importers: specifier: ^3.0.11 version: 3.0.11 eslint: - specifier: ^9.23.0 - version: 9.23.0 + specifier: ^9.24.0 + version: 9.24.0 typescript: - specifier: ^5.8.2 - version: 5.8.2 + specifier: ^5.8.3 + version: 5.8.3 packages/db: dependencies: @@ -1024,14 +1024,14 @@ importers: specifier: workspace:^0.1.0 version: link:../server-settings '@mantine/core': - specifier: ^7.17.3 - version: 7.17.3(@mantine/hooks@7.17.3(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + specifier: ^7.17.4 + version: 7.17.4(@mantine/hooks@7.17.4(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@paralleldrive/cuid2': specifier: ^2.2.2 version: 2.2.2 '@testcontainers/mysql': - specifier: ^10.24.0 - version: 10.24.0 + specifier: ^10.24.1 + version: 10.24.1 better-sqlite3: specifier: ^11.9.1 version: 11.9.1 @@ -1067,8 +1067,8 @@ importers: specifier: ^8.0.0 version: 8.0.0 eslint: - specifier: ^9.23.0 - version: 9.23.0 + specifier: ^9.24.0 + version: 9.24.0 prettier: specifier: ^3.5.3 version: 3.5.3 @@ -1076,8 +1076,8 @@ importers: specifier: 4.19.3 version: 4.19.3 typescript: - specifier: ^5.8.2 - version: 5.8.2 + specifier: ^5.8.3 + version: 5.8.3 packages/definitions: dependencies: @@ -1095,11 +1095,11 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript eslint: - specifier: ^9.23.0 - version: 9.23.0 + specifier: ^9.24.0 + version: 9.24.0 typescript: - specifier: ^5.8.2 - version: 5.8.2 + specifier: ^5.8.3 + version: 5.8.3 packages/docker: dependencies: @@ -1126,17 +1126,17 @@ importers: specifier: ^3.3.37 version: 3.3.37 eslint: - specifier: ^9.23.0 - version: 9.23.0 + specifier: ^9.24.0 + version: 9.24.0 typescript: - specifier: ^5.8.2 - version: 5.8.2 + specifier: ^5.8.3 + version: 5.8.3 packages/env: dependencies: '@t3-oss/env-nextjs': specifier: ^0.12.0 - version: 0.12.0(typescript@5.8.2)(zod@3.24.2) + version: 0.12.0(typescript@5.8.3)(zod@3.24.2) zod: specifier: ^3.24.2 version: 3.24.2 @@ -1151,11 +1151,11 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript eslint: - specifier: ^9.23.0 - version: 9.23.0 + specifier: ^9.24.0 + version: 9.24.0 typescript: - specifier: ^5.8.2 - version: 5.8.2 + specifier: ^5.8.3 + version: 5.8.3 packages/form: dependencies: @@ -1169,8 +1169,8 @@ importers: specifier: workspace:^0.1.0 version: link:../validation '@mantine/form': - specifier: ^7.17.3 - version: 7.17.3(react@19.1.0) + specifier: ^7.17.4 + version: 7.17.4(react@19.1.0) zod: specifier: ^3.24.2 version: 3.24.2 @@ -1185,11 +1185,11 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript eslint: - specifier: ^9.23.0 - version: 9.23.0 + specifier: ^9.24.0 + version: 9.24.0 typescript: - specifier: ^5.8.2 - version: 5.8.2 + specifier: ^5.8.3 + version: 5.8.3 packages/forms-collection: dependencies: @@ -1215,8 +1215,8 @@ importers: specifier: workspace:^0.1.0 version: link:../validation '@mantine/core': - specifier: ^7.17.3 - version: 7.17.3(@mantine/hooks@7.17.3(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + specifier: ^7.17.4 + version: 7.17.4(@mantine/hooks@7.17.4(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) react: specifier: 19.1.0 version: 19.1.0 @@ -1234,11 +1234,11 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript eslint: - specifier: ^9.23.0 - version: 9.23.0 + specifier: ^9.24.0 + version: 9.24.0 typescript: - specifier: ^5.8.2 - version: 5.8.2 + specifier: ^5.8.3 + version: 5.8.3 packages/icons: dependencies: @@ -1262,11 +1262,11 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript eslint: - specifier: ^9.23.0 - version: 9.23.0 + specifier: ^9.24.0 + version: 9.24.0 typescript: - specifier: ^5.8.2 - version: 5.8.2 + specifier: ^5.8.3 + version: 5.8.3 packages/integrations: dependencies: @@ -1338,11 +1338,11 @@ importers: specifier: ^0.4.14 version: 0.4.14 eslint: - specifier: ^9.23.0 - version: 9.23.0 + specifier: ^9.24.0 + version: 9.24.0 typescript: - specifier: ^5.8.2 - version: 5.8.2 + specifier: ^5.8.3 + version: 5.8.3 packages/log: dependencies: @@ -1372,11 +1372,11 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript eslint: - specifier: ^9.23.0 - version: 9.23.0 + specifier: ^9.24.0 + version: 9.24.0 typescript: - specifier: ^5.8.2 - version: 5.8.2 + specifier: ^5.8.3 + version: 5.8.3 packages/modals: dependencies: @@ -1387,11 +1387,11 @@ importers: specifier: workspace:^0.1.0 version: link:../ui '@mantine/core': - specifier: ^7.17.3 - version: 7.17.3(@mantine/hooks@7.17.3(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + specifier: ^7.17.4 + version: 7.17.4(@mantine/hooks@7.17.4(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@mantine/hooks': - specifier: ^7.17.3 - version: 7.17.3(react@19.1.0) + specifier: ^7.17.4 + version: 7.17.4(react@19.1.0) react: specifier: 19.1.0 version: 19.1.0 @@ -1406,11 +1406,11 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript eslint: - specifier: ^9.23.0 - version: 9.23.0 + specifier: ^9.24.0 + version: 9.24.0 typescript: - specifier: ^5.8.2 - version: 5.8.2 + specifier: ^5.8.3 + version: 5.8.3 packages/modals-collection: dependencies: @@ -1448,8 +1448,8 @@ importers: specifier: workspace:^0.1.0 version: link:../validation '@mantine/core': - specifier: ^7.17.3 - version: 7.17.3(@mantine/hooks@7.17.3(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + specifier: ^7.17.4 + version: 7.17.4(@mantine/hooks@7.17.4(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@tabler/icons-react': specifier: ^3.31.0 version: 3.31.0(react@19.1.0) @@ -1457,8 +1457,8 @@ importers: specifier: ^1.11.13 version: 1.11.13 next: - specifier: 15.2.4 - version: 15.2.4(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.3) + specifier: 15.2.5 + version: 15.2.5(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.3) react: specifier: 19.1.0 version: 19.1.0 @@ -1479,11 +1479,11 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript eslint: - specifier: ^9.23.0 - version: 9.23.0 + specifier: ^9.24.0 + version: 9.24.0 typescript: - specifier: ^5.8.2 - version: 5.8.2 + specifier: ^5.8.3 + version: 5.8.3 packages/notifications: dependencies: @@ -1491,8 +1491,8 @@ importers: specifier: workspace:^0.1.0 version: link:../ui '@mantine/notifications': - specifier: ^7.17.3 - version: 7.17.3(@mantine/core@7.17.3(@mantine/hooks@7.17.3(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@mantine/hooks@7.17.3(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + specifier: ^7.17.4 + version: 7.17.4(@mantine/core@7.17.4(@mantine/hooks@7.17.4(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@mantine/hooks@7.17.4(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@tabler/icons-react': specifier: ^3.31.0 version: 3.31.0(react@19.1.0) @@ -1507,11 +1507,11 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript eslint: - specifier: ^9.23.0 - version: 9.23.0 + specifier: ^9.24.0 + version: 9.24.0 typescript: - specifier: ^5.8.2 - version: 5.8.2 + specifier: ^5.8.3 + version: 5.8.3 packages/old-import: dependencies: @@ -1549,17 +1549,17 @@ importers: specifier: workspace:^0.1.0 version: link:../validation '@mantine/core': - specifier: ^7.17.3 - version: 7.17.3(@mantine/hooks@7.17.3(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + specifier: ^7.17.4 + version: 7.17.4(@mantine/hooks@7.17.4(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@mantine/hooks': - specifier: ^7.17.3 - version: 7.17.3(react@19.1.0) + specifier: ^7.17.4 + version: 7.17.4(react@19.1.0) adm-zip: specifier: 0.5.16 version: 0.5.16 next: - specifier: 15.2.4 - version: 15.2.4(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.3) + specifier: 15.2.5 + version: 15.2.5(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.3) react: specifier: 19.1.0 version: 19.1.0 @@ -1589,11 +1589,11 @@ importers: specifier: 0.5.7 version: 0.5.7 eslint: - specifier: ^9.23.0 - version: 9.23.0 + specifier: ^9.24.0 + version: 9.24.0 typescript: - specifier: ^5.8.2 - version: 5.8.2 + specifier: ^5.8.3 + version: 5.8.3 packages/old-schema: dependencies: @@ -1614,11 +1614,11 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript eslint: - specifier: ^9.23.0 - version: 9.23.0 + specifier: ^9.24.0 + version: 9.24.0 typescript: - specifier: ^5.8.2 - version: 5.8.2 + specifier: ^5.8.3 + version: 5.8.3 packages/ping: dependencies: @@ -1645,11 +1645,11 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript eslint: - specifier: ^9.23.0 - version: 9.23.0 + specifier: ^9.24.0 + version: 9.24.0 typescript: - specifier: ^5.8.2 - version: 5.8.2 + specifier: ^5.8.3 + version: 5.8.3 packages/redis: dependencies: @@ -1682,11 +1682,11 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript eslint: - specifier: ^9.23.0 - version: 9.23.0 + specifier: ^9.24.0 + version: 9.24.0 typescript: - specifier: ^5.8.2 - version: 5.8.2 + specifier: ^5.8.3 + version: 5.8.3 packages/request-handler: dependencies: @@ -1734,11 +1734,11 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript eslint: - specifier: ^9.23.0 - version: 9.23.0 + specifier: ^9.24.0 + version: 9.24.0 typescript: - specifier: ^5.8.2 - version: 5.8.2 + specifier: ^5.8.3 + version: 5.8.3 packages/server-settings: dependencies: @@ -1759,11 +1759,11 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript eslint: - specifier: ^9.23.0 - version: 9.23.0 + specifier: ^9.24.0 + version: 9.24.0 typescript: - specifier: ^5.8.2 - version: 5.8.2 + specifier: ^5.8.3 + version: 5.8.3 packages/settings: dependencies: @@ -1777,11 +1777,11 @@ importers: specifier: workspace:^0.1.0 version: link:../server-settings '@mantine/dates': - specifier: ^7.17.3 - version: 7.17.3(@mantine/core@7.17.3(@mantine/hooks@7.17.3(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@mantine/hooks@7.17.3(react@19.1.0))(dayjs@1.11.13)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + specifier: ^7.17.4 + version: 7.17.4(@mantine/core@7.17.4(@mantine/hooks@7.17.4(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@mantine/hooks@7.17.4(react@19.1.0))(dayjs@1.11.13)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) next: - specifier: 15.2.4 - version: 15.2.4(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.3) + specifier: 15.2.5 + version: 15.2.5(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.3) react: specifier: 19.1.0 version: 19.1.0 @@ -1799,11 +1799,11 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript eslint: - specifier: ^9.23.0 - version: 9.23.0 + specifier: ^9.24.0 + version: 9.24.0 typescript: - specifier: ^5.8.2 - version: 5.8.2 + specifier: ^5.8.3 + version: 5.8.3 packages/spotlight: dependencies: @@ -1838,14 +1838,14 @@ importers: specifier: workspace:^0.1.0 version: link:../ui '@mantine/core': - specifier: ^7.17.3 - version: 7.17.3(@mantine/hooks@7.17.3(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + specifier: ^7.17.4 + version: 7.17.4(@mantine/hooks@7.17.4(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@mantine/hooks': - specifier: ^7.17.3 - version: 7.17.3(react@19.1.0) + specifier: ^7.17.4 + version: 7.17.4(react@19.1.0) '@mantine/spotlight': - specifier: ^7.17.3 - version: 7.17.3(@mantine/core@7.17.3(@mantine/hooks@7.17.3(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@mantine/hooks@7.17.3(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + specifier: ^7.17.4 + version: 7.17.4(@mantine/core@7.17.4(@mantine/hooks@7.17.4(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@mantine/hooks@7.17.4(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@tabler/icons-react': specifier: ^3.31.0 version: 3.31.0(react@19.1.0) @@ -1853,8 +1853,8 @@ importers: specifier: ^2.12.2 version: 2.12.2(@types/react@19.1.0)(react@19.1.0) next: - specifier: 15.2.4 - version: 15.2.4(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.3) + specifier: 15.2.5 + version: 15.2.5(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.3) react: specifier: 19.1.0 version: 19.1.0 @@ -1875,11 +1875,11 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript eslint: - specifier: ^9.23.0 - version: 9.23.0 + specifier: ^9.24.0 + version: 9.24.0 typescript: - specifier: ^5.8.2 - version: 5.8.2 + specifier: ^5.8.3 + version: 5.8.3 packages/translation: dependencies: @@ -1897,13 +1897,13 @@ importers: version: 4.3.1 mantine-react-table: specifier: 2.0.0-beta.9 - version: 2.0.0-beta.9(@mantine/core@7.17.3(@mantine/hooks@7.17.3(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@mantine/dates@7.17.3(@mantine/core@7.17.3(@mantine/hooks@7.17.3(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@mantine/hooks@7.17.3(react@19.1.0))(dayjs@1.11.13)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@mantine/hooks@7.17.3(react@19.1.0))(@tabler/icons-react@3.31.0(react@19.1.0))(clsx@2.1.1)(dayjs@1.11.13)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + version: 2.0.0-beta.9(@mantine/core@7.17.4(@mantine/hooks@7.17.4(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@mantine/dates@7.17.4(@mantine/core@7.17.4(@mantine/hooks@7.17.4(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@mantine/hooks@7.17.4(react@19.1.0))(dayjs@1.11.13)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@mantine/hooks@7.17.4(react@19.1.0))(@tabler/icons-react@3.31.0(react@19.1.0))(clsx@2.1.1)(dayjs@1.11.13)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) next: - specifier: 15.2.4 - version: 15.2.4(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.3) + specifier: 15.2.5 + version: 15.2.5(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.3) next-intl: specifier: 4.0.2 - version: 4.0.2(next@15.2.4(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.3))(react@19.1.0)(typescript@5.8.2) + version: 4.0.2(next@15.2.5(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.3))(react@19.1.0)(typescript@5.8.3) react: specifier: 19.1.0 version: 19.1.0 @@ -1921,11 +1921,11 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript eslint: - specifier: ^9.23.0 - version: 9.23.0 + specifier: ^9.24.0 + version: 9.24.0 typescript: - specifier: ^5.8.2 - version: 5.8.2 + specifier: ^5.8.3 + version: 5.8.3 packages/ui: dependencies: @@ -1945,23 +1945,23 @@ importers: specifier: workspace:^0.1.0 version: link:../validation '@mantine/core': - specifier: ^7.17.3 - version: 7.17.3(@mantine/hooks@7.17.3(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + specifier: ^7.17.4 + version: 7.17.4(@mantine/hooks@7.17.4(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@mantine/dates': - specifier: ^7.17.3 - version: 7.17.3(@mantine/core@7.17.3(@mantine/hooks@7.17.3(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@mantine/hooks@7.17.3(react@19.1.0))(dayjs@1.11.13)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + specifier: ^7.17.4 + version: 7.17.4(@mantine/core@7.17.4(@mantine/hooks@7.17.4(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@mantine/hooks@7.17.4(react@19.1.0))(dayjs@1.11.13)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@mantine/hooks': - specifier: ^7.17.3 - version: 7.17.3(react@19.1.0) + specifier: ^7.17.4 + version: 7.17.4(react@19.1.0) '@tabler/icons-react': specifier: ^3.31.0 version: 3.31.0(react@19.1.0) mantine-react-table: specifier: 2.0.0-beta.9 - version: 2.0.0-beta.9(@mantine/core@7.17.3(@mantine/hooks@7.17.3(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@mantine/dates@7.17.3(@mantine/core@7.17.3(@mantine/hooks@7.17.3(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@mantine/hooks@7.17.3(react@19.1.0))(dayjs@1.11.13)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@mantine/hooks@7.17.3(react@19.1.0))(@tabler/icons-react@3.31.0(react@19.1.0))(clsx@2.1.1)(dayjs@1.11.13)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + version: 2.0.0-beta.9(@mantine/core@7.17.4(@mantine/hooks@7.17.4(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@mantine/dates@7.17.4(@mantine/core@7.17.4(@mantine/hooks@7.17.4(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@mantine/hooks@7.17.4(react@19.1.0))(dayjs@1.11.13)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@mantine/hooks@7.17.4(react@19.1.0))(@tabler/icons-react@3.31.0(react@19.1.0))(clsx@2.1.1)(dayjs@1.11.13)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) next: - specifier: 15.2.4 - version: 15.2.4(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.3) + specifier: 15.2.5 + version: 15.2.5(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.3) react: specifier: 19.1.0 version: 19.1.0 @@ -1982,11 +1982,11 @@ importers: specifier: ^1.0.5 version: 1.0.5 eslint: - specifier: ^9.23.0 - version: 9.23.0 + specifier: ^9.24.0 + version: 9.24.0 typescript: - specifier: ^5.8.2 - version: 5.8.2 + specifier: ^5.8.3 + version: 5.8.3 packages/validation: dependencies: @@ -2013,11 +2013,11 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript eslint: - specifier: ^9.23.0 - version: 9.23.0 + specifier: ^9.24.0 + version: 9.24.0 typescript: - specifier: ^5.8.2 - version: 5.8.2 + specifier: ^5.8.3 + version: 5.8.3 packages/widgets: dependencies: @@ -2082,14 +2082,14 @@ importers: specifier: workspace:^0.1.0 version: link:../validation '@mantine/charts': - specifier: ^7.17.3 - version: 7.17.3(@mantine/core@7.17.3(@mantine/hooks@7.17.3(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@mantine/hooks@7.17.3(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(recharts@2.15.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0)) + specifier: ^7.17.4 + version: 7.17.4(@mantine/core@7.17.4(@mantine/hooks@7.17.4(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@mantine/hooks@7.17.4(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(recharts@2.15.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0)) '@mantine/core': - specifier: ^7.17.3 - version: 7.17.3(@mantine/hooks@7.17.3(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + specifier: ^7.17.4 + version: 7.17.4(@mantine/hooks@7.17.4(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@mantine/hooks': - specifier: ^7.17.3 - version: 7.17.3(react@19.1.0) + specifier: ^7.17.4 + version: 7.17.4(react@19.1.0) '@tabler/icons-react': specifier: ^3.31.0 version: 3.31.0(react@19.1.0) @@ -2146,10 +2146,10 @@ importers: version: 1.11.13 mantine-react-table: specifier: 2.0.0-beta.9 - version: 2.0.0-beta.9(@mantine/core@7.17.3(@mantine/hooks@7.17.3(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@mantine/dates@7.17.3(@mantine/core@7.17.3(@mantine/hooks@7.17.3(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@mantine/hooks@7.17.3(react@19.1.0))(dayjs@1.11.13)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@mantine/hooks@7.17.3(react@19.1.0))(@tabler/icons-react@3.31.0(react@19.1.0))(clsx@2.1.1)(dayjs@1.11.13)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + version: 2.0.0-beta.9(@mantine/core@7.17.4(@mantine/hooks@7.17.4(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@mantine/dates@7.17.4(@mantine/core@7.17.4(@mantine/hooks@7.17.4(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@mantine/hooks@7.17.4(react@19.1.0))(dayjs@1.11.13)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@mantine/hooks@7.17.4(react@19.1.0))(@tabler/icons-react@3.31.0(react@19.1.0))(clsx@2.1.1)(dayjs@1.11.13)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) next: - specifier: 15.2.4 - version: 15.2.4(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.3) + specifier: 15.2.5 + version: 15.2.5(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.3) react: specifier: 19.1.0 version: 19.1.0 @@ -2179,38 +2179,38 @@ importers: specifier: ^7.3.58 version: 7.3.58 eslint: - specifier: ^9.23.0 - version: 9.23.0 + specifier: ^9.24.0 + version: 9.24.0 typescript: - specifier: ^5.8.2 - version: 5.8.2 + specifier: ^5.8.3 + version: 5.8.3 tooling/eslint: dependencies: '@next/eslint-plugin-next': - specifier: 15.2.4 - version: 15.2.4 + specifier: 15.2.5 + version: 15.2.5 eslint-config-prettier: specifier: ^10.1.1 - version: 10.1.1(eslint@9.23.0) + version: 10.1.1(eslint@9.24.0) eslint-config-turbo: specifier: ^2.5.0 - version: 2.5.0(eslint@9.23.0)(turbo@2.5.0) + version: 2.5.0(eslint@9.24.0)(turbo@2.5.0) eslint-plugin-import: specifier: ^2.31.0 - version: 2.31.0(@typescript-eslint/parser@8.29.0(eslint@9.23.0)(typescript@5.8.2))(eslint@9.23.0) + version: 2.31.0(@typescript-eslint/parser@8.29.1(eslint@9.24.0)(typescript@5.8.3))(eslint@9.24.0) eslint-plugin-jsx-a11y: specifier: ^6.10.2 - version: 6.10.2(eslint@9.23.0) + version: 6.10.2(eslint@9.24.0) eslint-plugin-react: specifier: ^7.37.5 - version: 7.37.5(eslint@9.23.0) + version: 7.37.5(eslint@9.24.0) eslint-plugin-react-hooks: specifier: ^5.2.0 - version: 5.2.0(eslint@9.23.0) + version: 5.2.0(eslint@9.24.0) typescript-eslint: - specifier: ^8.29.0 - version: 8.29.0(eslint@9.23.0)(typescript@5.8.2) + specifier: ^8.29.1 + version: 8.29.1(eslint@9.24.0)(typescript@5.8.3) devDependencies: '@homarr/prettier-config': specifier: workspace:^0.1.0 @@ -2219,11 +2219,11 @@ importers: specifier: workspace:^0.1.0 version: link:../typescript eslint: - specifier: ^9.23.0 - version: 9.23.0 + specifier: ^9.24.0 + version: 9.24.0 typescript: - specifier: ^5.8.2 - version: 5.8.2 + specifier: ^5.8.3 + version: 5.8.3 tooling/github: {} @@ -2243,8 +2243,8 @@ importers: specifier: ^2.5.10 version: 2.5.10(prettier@3.5.3) typescript: - specifier: ^5.8.2 - version: 5.8.2 + specifier: ^5.8.3 + version: 5.8.3 tooling/typescript: {} @@ -3228,8 +3228,8 @@ packages: resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - '@eslint/config-array@0.19.2': - resolution: {integrity: sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w==} + '@eslint/config-array@0.20.0': + resolution: {integrity: sha512-fxlS1kkIjx8+vy2SjuCB94q3htSNrufYTXubwiBFeaQHbH6Ipi43gFJq2zCMt6PHhImH3Xmr0NksKDvchWlpQQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@eslint/config-helpers@0.2.0': @@ -3244,8 +3244,8 @@ packages: resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/js@9.23.0': - resolution: {integrity: sha512-35MJ8vCPU0ZMxo7zfev2pypqTwWTofFZO6m4KAtdoFhRpLJUpHTZZ+KB3C7Hb1d7bULYwO4lJXGCi5Se+8OMbw==} + '@eslint/js@9.24.0': + resolution: {integrity: sha512-uIY/y3z0uvOGX8cp1C2fiC4+ZmBhp6yZWkojtHL1YEMnRt1Y63HB9TM17proGEmeG7HeUY+UP36F0aknKYTpYA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@eslint/object-schema@2.1.6': @@ -3518,8 +3518,8 @@ packages: peerDependencies: jsep: ^0.4.0||^1.0.0 - '@kubernetes/client-node@1.1.1': - resolution: {integrity: sha512-8xD9J8vFhYSZprpp7aEj9UhzqySG0IDH8C26o6e3TuknRcCBMa/fLnRJmJwF+c4CCaFO69Z65VgB4WPsi/P5zw==} + '@kubernetes/client-node@1.1.2': + resolution: {integrity: sha512-kkE0D8zB5rIQoR6SUwlHUyQtpLvrW0gXOd2MabQsql7I2oPnMA8pb50A1MWB4yH0eX29t45gxs7lOVlS0UPsiw==} '@libsql/client-wasm@0.14.0': resolution: {integrity: sha512-gB/jtz0xuwrqAHApBv9e9JSew2030Fhj2edyZ83InZ4yPj/Q2LTUlEhaspEYT0T0xsAGqPy38uGrmq/OGS+DdQ==} @@ -3529,88 +3529,88 @@ packages: '@libsql/core@0.14.0': resolution: {integrity: sha512-nhbuXf7GP3PSZgdCY2Ecj8vz187ptHlZQ0VRc751oB2C1W8jQUXKKklvt7t1LJiUTQBVJuadF628eUk+3cRi4Q==} - '@mantine/charts@7.17.3': - resolution: {integrity: sha512-YGx8hLi4E3yyiRx9fNAoPPF+YrFkLWM+fnzqKIVvRbWqMbUw920AU+K5XSDjPmNB7cuYWSVwxxA/hIstQ8x3VA==} + '@mantine/charts@7.17.4': + resolution: {integrity: sha512-datvi9GkMRrL9SY2R5Pd7MpP6d7QxRFYMY7DcdE/V3JnwMmg+gCg+QfzvrT947R8sEiBZECirTI0yNLWDSwkGw==} peerDependencies: - '@mantine/core': 7.17.3 - '@mantine/hooks': 7.17.3 + '@mantine/core': 7.17.4 + '@mantine/hooks': 7.17.4 react: ^18.x || ^19.x react-dom: ^18.x || ^19.x recharts: ^2.13.3 - '@mantine/colors-generator@7.17.3': - resolution: {integrity: sha512-d/noQeEyeiuuQyl1dPdEdOihMgUDwPSnYGz60eJOCc4HfOY8zNZLgfsfZf7d+1cIlySNbqK9GARUunZyfSiu3g==} + '@mantine/colors-generator@7.17.4': + resolution: {integrity: sha512-1KqfD0hnC76i43HnaAkSrT3szXC/0crfa450hx4cJqjBf5ZZ9pFWwB8qnoubtsmMpdRlHjDBhPRn/j22m1vpTg==} peerDependencies: chroma-js: '>=2.4.2' - '@mantine/core@7.17.3': - resolution: {integrity: sha512-N/AfV5eMnfEMx9WzI7AU5pNFBEzAfT/KtE2XDKS+0ht6RifUmolIxyIvoGMYz2yUEsCBMJZqmBq33Rabf5W7Ug==} + '@mantine/core@7.17.4': + resolution: {integrity: sha512-Ea4M/98jxgIWCuxCdM0YIotVYjfLTGQsfIA6zDg0LsClgjo/ZLnnh4zbi+bLNgM+GGjP4ju7gv4MZvaTKuLO8g==} peerDependencies: - '@mantine/hooks': 7.17.3 + '@mantine/hooks': 7.17.4 react: ^18.x || ^19.x react-dom: ^18.x || ^19.x - '@mantine/dates@7.17.3': - resolution: {integrity: sha512-gegLSlK7mi3jAaL/JMLdy6oK9CmY08nXoLvbeO03i+751bmbbbzpoFAaxMzbR6vkP9tPuoapOxJqgDzn2Jm+Dw==} + '@mantine/dates@7.17.4': + resolution: {integrity: sha512-6oqcmcJb0Pypju+/z6s9nEVa3B9Pdj5DTrdj/FP/RD7RFx4k7nHi+jFstn4qcso6nghRRROKMHErfqrBybjzKA==} peerDependencies: - '@mantine/core': 7.17.3 - '@mantine/hooks': 7.17.3 + '@mantine/core': 7.17.4 + '@mantine/hooks': 7.17.4 dayjs: '>=1.0.0' react: ^18.x || ^19.x react-dom: ^18.x || ^19.x - '@mantine/dropzone@7.17.3': - resolution: {integrity: sha512-dwqmSgBS+fn57h2V2Ko4VN9g3nn/4DYr5poCElYhfYKzGqsDxqe9ZW3rYIg+VtmIAqBpWxX5YuWl4ea5h9xRZA==} + '@mantine/dropzone@7.17.4': + resolution: {integrity: sha512-jtKbesdCXrn3QLiHz0Ed3hLcY72rTmAhmB4gztL916LUOptYY+eFwQzXQdPOrquJgxQDt1A9LOA2Nug9cgP7tw==} peerDependencies: - '@mantine/core': 7.17.3 - '@mantine/hooks': 7.17.3 + '@mantine/core': 7.17.4 + '@mantine/hooks': 7.17.4 react: ^18.x || ^19.x react-dom: ^18.x || ^19.x - '@mantine/form@7.17.3': - resolution: {integrity: sha512-ktERldD8f9lrjjz6wIbwMnNbAZq8XEWPx4K5WuFyjXaK0PI8D+gsXIGKMtA5rVrAUFHCWCdbK3yLgtjJNki8ew==} + '@mantine/form@7.17.4': + resolution: {integrity: sha512-faCz44IpvLSv8ekG962SIOtRQc4gfC+zeXasbycWNYMW0k8ge7ch689KIuSYN00gdZat2UOaCbrr+yrTYjeuCQ==} peerDependencies: react: ^18.x || ^19.x - '@mantine/hooks@7.17.3': - resolution: {integrity: sha512-6o65Rbfl8jd1C1nF9icvungqL0qZViEOmrZgkyKXxBYkC3x91fz4zftwQgNjt1tZHWDNO6Bo4GpRjJyAdwl48g==} + '@mantine/hooks@7.17.4': + resolution: {integrity: sha512-PBcJxDAfGm8k1/JJmaDcxzRVQ3JSE1iXGktbgGz+qEOJmCxwbbAYe+CtGFFgi1xX2bPZ+7dtRr/+XFhnKtt/aw==} peerDependencies: react: ^18.x || ^19.x - '@mantine/modals@7.17.3': - resolution: {integrity: sha512-ZwNDTmfqyVRPUNl+vtBDbgZ9aVeQw6H+KLDSZxEsIYjc8p6u7FgCQ/FaBpsJOf//Oc7gHTLF0al27AqvW8jmOA==} + '@mantine/modals@7.17.4': + resolution: {integrity: sha512-KQYzLCQRBs9bq0svdpSda8fgxmqrwEy4tgvoXpmlr02srsyySvpOxhXmAUZsjPZapG+D97sYi7BscVZKZoIqgA==} peerDependencies: - '@mantine/core': 7.17.3 - '@mantine/hooks': 7.17.3 + '@mantine/core': 7.17.4 + '@mantine/hooks': 7.17.4 react: ^18.x || ^19.x react-dom: ^18.x || ^19.x - '@mantine/notifications@7.17.3': - resolution: {integrity: sha512-MqakDqu/CZzO4arZGpXs3TmGTajqL4xm28vtqW4qWFSU5HZWQ4EosqipqvIJ+swC6YbxNiWvFcfnxxPlHdYk9g==} + '@mantine/notifications@7.17.4': + resolution: {integrity: sha512-YxNmnZSfIG69lPMFItOZZsizYL3DsOLVUSPkkJILG5pW2F798dc4IA5mhRIbdmzDEx0ArWHJ7gsdd3Vmm5ubPg==} peerDependencies: - '@mantine/core': 7.17.3 - '@mantine/hooks': 7.17.3 + '@mantine/core': 7.17.4 + '@mantine/hooks': 7.17.4 react: ^18.x || ^19.x react-dom: ^18.x || ^19.x - '@mantine/spotlight@7.17.3': - resolution: {integrity: sha512-RBmPjhyxGyel6S63tW5Pl9Xdx1OfBAxjGDyz3N3sdAY/4WaM4PSJTC10mCkxd9G5RKvyDtOBAYFKY9FHeUYY0A==} + '@mantine/spotlight@7.17.4': + resolution: {integrity: sha512-HAAK8svSoNLKtwVHEYL4t9cQgR/lKDdXRHTUjmkuqgW5QzpX6A1GYtkHnHlDuVHFdDvInPlk+N63BMysUzw4cg==} peerDependencies: - '@mantine/core': 7.17.3 - '@mantine/hooks': 7.17.3 + '@mantine/core': 7.17.4 + '@mantine/hooks': 7.17.4 react: ^18.x || ^19.x react-dom: ^18.x || ^19.x - '@mantine/store@7.17.3': - resolution: {integrity: sha512-wXQXe/Ljv2N6TDRsoVwOHmTGZey7Nt/SS6VeeMujKeNnAybPPXaP1jIbN50MKJoDS4qVPCHJNaHwVKIgMur2aQ==} + '@mantine/store@7.17.4': + resolution: {integrity: sha512-a/EecHPtYVxhu3oMX9uTymGolmOBWxW8Qs4fLCjiazEJbS1ScI4lS71GK/SuOa2rGuuOJkaotpyritbx3paIRg==} peerDependencies: react: ^18.x || ^19.x - '@mantine/tiptap@7.17.3': - resolution: {integrity: sha512-kfMqrHpMq1dcdKsjUjdcHVCGmeRuZq4MclYIIulU5xNaUGyIzspQCeLa8XTH47QDS7ZSNV+8aXR93lPNZdCouA==} + '@mantine/tiptap@7.17.4': + resolution: {integrity: sha512-5r6dPzw3rfcU6W+zrT06N5cFaISDwYmvVemqz1hXX1cNj7Y9UOb3ymH6lmmXsyqroUv+bHurbi/SlcYd8R0YIA==} peerDependencies: - '@mantine/core': 7.17.3 - '@mantine/hooks': 7.17.3 + '@mantine/core': 7.17.4 + '@mantine/hooks': 7.17.4 '@tiptap/extension-link': '>=2.1.12' '@tiptap/react': '>=2.1.12' react: ^18.x || ^19.x @@ -3628,56 +3628,56 @@ packages: resolution: {integrity: sha512-u6/kglVwZRu5+GMmtkNlGLqJVkgTl0TtM+hLa9rBg7pldx+5NG5bk45NvL37uZmAr2Xfa1C6qHb7GrFwfP372g==} hasBin: true - '@next/env@15.2.4': - resolution: {integrity: sha512-+SFtMgoiYP3WoSswuNmxJOCwi06TdWE733D+WPjpXIe4LXGULwEaofiiAy6kbS0+XjM5xF5n3lKuBwN2SnqD9g==} + '@next/env@15.2.5': + resolution: {integrity: sha512-uWkCf9C8wKTyQjqrNk+BA7eL3LOQdhL+xlmJUf2O85RM4lbzwBwot3Sqv2QGe/RGnc3zysIf1oJdtq9S00pkmQ==} - '@next/eslint-plugin-next@15.2.4': - resolution: {integrity: sha512-O8ScvKtnxkp8kL9TpJTTKnMqlkZnS+QxwoQnJwPGBxjBbzd6OVVPEJ5/pMNrktSyXQD/chEfzfFzYLM6JANOOQ==} + '@next/eslint-plugin-next@15.2.5': + resolution: {integrity: sha512-Q1ncASVFKSy+AbabimYxr/2HH/h+qlKlwu1fYV48xUefGzVimS3i3nKwYsM2w+rLdpMFdJyoVowrYyjKu47rBw==} - '@next/swc-darwin-arm64@15.2.4': - resolution: {integrity: sha512-1AnMfs655ipJEDC/FHkSr0r3lXBgpqKo4K1kiwfUf3iE68rDFXZ1TtHdMvf7D0hMItgDZ7Vuq3JgNMbt/+3bYw==} + '@next/swc-darwin-arm64@15.2.5': + resolution: {integrity: sha512-4OimvVlFTbgzPdA0kh8A1ih6FN9pQkL4nPXGqemEYgk+e7eQhsst/p35siNNqA49eQA6bvKZ1ASsDtu9gtXuog==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@next/swc-darwin-x64@15.2.4': - resolution: {integrity: sha512-3qK2zb5EwCwxnO2HeO+TRqCubeI/NgCe+kL5dTJlPldV/uwCnUgC7VbEzgmxbfrkbjehL4H9BPztWOEtsoMwew==} + '@next/swc-darwin-x64@15.2.5': + resolution: {integrity: sha512-ohzRaE9YbGt1ctE0um+UGYIDkkOxHV44kEcHzLqQigoRLaiMtZzGrA11AJh2Lu0lv51XeiY1ZkUvkThjkVNBMA==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@next/swc-linux-arm64-gnu@15.2.4': - resolution: {integrity: sha512-HFN6GKUcrTWvem8AZN7tT95zPb0GUGv9v0d0iyuTb303vbXkkbHDp/DxufB04jNVD+IN9yHy7y/6Mqq0h0YVaQ==} + '@next/swc-linux-arm64-gnu@15.2.5': + resolution: {integrity: sha512-FMSdxSUt5bVXqqOoZCc/Seg4LQep9w/fXTazr/EkpXW2Eu4IFI9FD7zBDlID8TJIybmvKk7mhd9s+2XWxz4flA==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@next/swc-linux-arm64-musl@15.2.4': - resolution: {integrity: sha512-Oioa0SORWLwi35/kVB8aCk5Uq+5/ZIumMK1kJV+jSdazFm2NzPDztsefzdmzzpx5oGCJ6FkUC7vkaUseNTStNA==} + '@next/swc-linux-arm64-musl@15.2.5': + resolution: {integrity: sha512-4ZNKmuEiW5hRKkGp2HWwZ+JrvK4DQLgf8YDaqtZyn7NYdl0cHfatvlnLFSWUayx9yFAUagIgRGRk8pFxS8Qniw==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@next/swc-linux-x64-gnu@15.2.4': - resolution: {integrity: sha512-yb5WTRaHdkgOqFOZiu6rHV1fAEK0flVpaIN2HB6kxHVSy/dIajWbThS7qON3W9/SNOH2JWkVCyulgGYekMePuw==} + '@next/swc-linux-x64-gnu@15.2.5': + resolution: {integrity: sha512-bE6lHQ9GXIf3gCDE53u2pTl99RPZW5V1GLHSRMJ5l/oB/MT+cohu9uwnCK7QUph2xIOu2a6+27kL0REa/kqwZw==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@next/swc-linux-x64-musl@15.2.4': - resolution: {integrity: sha512-Dcdv/ix6srhkM25fgXiyOieFUkz+fOYkHlydWCtB0xMST6X9XYI3yPDKBZt1xuhOytONsIFJFB08xXYsxUwJLw==} + '@next/swc-linux-x64-musl@15.2.5': + resolution: {integrity: sha512-y7EeQuSkQbTAkCEQnJXm1asRUuGSWAchGJ3c+Qtxh8LVjXleZast8Mn/rL7tZOm7o35QeIpIcid6ufG7EVTTcA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@next/swc-win32-arm64-msvc@15.2.4': - resolution: {integrity: sha512-dW0i7eukvDxtIhCYkMrZNQfNicPDExt2jPb9AZPpL7cfyUo7QSNl1DjsHjmmKp6qNAqUESyT8YFl/Aw91cNJJg==} + '@next/swc-win32-arm64-msvc@15.2.5': + resolution: {integrity: sha512-gQMz0yA8/dskZM2Xyiq2FRShxSrsJNha40Ob/M2n2+JGRrZ0JwTVjLdvtN6vCxuq4ByhOd4a9qEf60hApNR2gQ==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@next/swc-win32-x64-msvc@15.2.4': - resolution: {integrity: sha512-SbnWkJmkS7Xl3kre8SdMF6F/XDh1DTFEhp0jRTj/uB8iPKoU2bb2NDfcu+iifv1+mxQEd1g2vvSxcZbXSKyWiQ==} + '@next/swc-win32-x64-msvc@15.2.5': + resolution: {integrity: sha512-tBDNVUcI7U03+3oMvJ11zrtVin5p0NctiuKmTGyaTIEAVj9Q77xukLXGXRnWxKRIIdFG4OTA2rUVGZDYOwgmAA==} engines: {node: '>= 10'} cpu: [x64] os: [win32] @@ -4313,27 +4313,27 @@ packages: resolution: {integrity: sha512-Wo1iKt2b9OT7d+YGhvEPD3DXvPv2etTusIMhMUoG7fbhmxcXCtIjJDEygy91Y2JFlwGyjqiBPRozme7UD8hoqg==} engines: {node: '>=12'} - '@tanstack/query-core@5.71.10': - resolution: {integrity: sha512-/fKEY8fO1nbszfrBatzmhJa1nEwIKn0c6Tv2A1ocSA5OiD2GukOIV8nnBbvJRgZb/VIoBy9/N4PVbABI8YQLow==} + '@tanstack/query-core@5.72.1': + resolution: {integrity: sha512-nOu0EEkZuJ0BZnYgeaEfo44+psq1jBO7/zp3KudixD4dvgOVerrhAhDEKsWx2N7MxB59mjO4r0ddP/VqWGPK+Q==} - '@tanstack/query-devtools@5.71.5': - resolution: {integrity: sha512-Fq1JeAp+I52Md/KnyeFxzG7G0RpdHgeOfDNhSPkZQs/JqqXuAfpUf+wFHDz+vP0GZbSnla2JmcLSQebOkIb1yA==} + '@tanstack/query-devtools@5.72.1': + resolution: {integrity: sha512-D0vEoQaiVq9ayCqvvxA9XkDq7TIesyPpvgP69arRtt5FQF6n/Hrta4SlkfXC4m9BCvFLlhLDcKGYa2eMQ4ZIIA==} - '@tanstack/react-query-devtools@5.71.10': - resolution: {integrity: sha512-n0xsIzwNvkIoZCmfHww28jFmnVTVzOt5dHj/py3LNFMJHGnJq9o9ttQESzVt2Hr7as00Aqf8ElVwH6na1o6dnw==} + '@tanstack/react-query-devtools@5.72.1': + resolution: {integrity: sha512-ckNRgABst3MLjpM2nD/CzQToCiaT3jb3Xhtf+GP/0/9ij9SPT/SC+lc3wUDSkT0OupnHobBBF5E1/Xp6B+XZLg==} peerDependencies: - '@tanstack/react-query': ^5.71.10 + '@tanstack/react-query': ^5.72.1 react: ^18 || ^19 - '@tanstack/react-query-next-experimental@5.71.10': - resolution: {integrity: sha512-9SD/PvQQngfSY/KNeKCb94tVbYoFIHTofoIxnnfMe1yK0IZrlpweDj5Gc3MafZOEPDM4BAA4/qrkyPnKgCkoeA==} + '@tanstack/react-query-next-experimental@5.72.1': + resolution: {integrity: sha512-tmhQm4Tqhcg8S4DtlXROEN6BLawWzGBAJrbUM/80sXgEX6Ak8D3PvkUFaewzFrIjNtLcu3zTfll34xdr68gilg==} peerDependencies: - '@tanstack/react-query': ^5.71.10 + '@tanstack/react-query': ^5.72.1 next: ^13 || ^14 || ^15 react: ^18 || ^19 - '@tanstack/react-query@5.71.10': - resolution: {integrity: sha512-mQYM/ObpL8YMDz8vCoUuHkbe8Yu7NnVRH8aBaBa/3zlufjp1f1VuWjeO3TcumNHfuVMDwEAGinsgwrB7OKADiQ==} + '@tanstack/react-query@5.72.1': + resolution: {integrity: sha512-4UEMyRx54xj144D2nDvDIMiXSG5BrqyCJrmyNoGbymNS+VWODcBDFrmRk9p2fe12UGZ4JtKPTNuW2Jg0aisUgQ==} peerDependencies: react: ^18 || ^19 @@ -4357,8 +4357,8 @@ packages: '@tanstack/virtual-core@3.11.2': resolution: {integrity: sha512-vTtpNt7mKCiZ1pwU9hfKPhpdVO2sVzFQsxoVBGtOSHxlrRRzYr8iQ2TlwbAcRYCcEiZ9ECAM8kBzH0v2+VzfKw==} - '@testcontainers/mysql@10.24.0': - resolution: {integrity: sha512-ffeMsMK5tBO+dQRCIlST6+P8TS0YFr7t63T6lcOo5DH9b4dAvddK3Lsrs9jPFXSREets2IwG9ThhGhjM/6d5Fw==} + '@testcontainers/mysql@10.24.1': + resolution: {integrity: sha512-XGA8ayEXxWs1HgKA3w61CI3BIflpgOuAkF6I++ilCJey1clWQzAawlM3MjqJUnjznSGJk7g6bAP1FwNXNUlTmA==} '@tiptap/core@2.11.7': resolution: {integrity: sha512-zN+NFFxLsxNEL8Qioc+DL6b8+Tt2bmRbXH22Gk6F6nD30x83eaUSFlSv3wqvgyCq3I1i1NO394So+Agmayx6rQ==} @@ -4566,20 +4566,20 @@ packages: tree-sitter: optional: true - '@trpc/client@11.0.2': - resolution: {integrity: sha512-GlPEedbMTerkUfAJBsrwU6dg8N65lt3LBwrCoqR3MTZ64lRU/DQqyLjzpz5nRkEN0x4S2JmX0hASV9vc2KlSHA==} + '@trpc/client@11.0.4': + resolution: {integrity: sha512-2xIXqRNc8wH3zgcGp1yZ8P2ZL15BoFWq2RS8S3ldjvxsdJfnoYmcvCNzySw8nIrWbKiXl9prdw+bGIUOdG/omw==} peerDependencies: - '@trpc/server': 11.0.2 + '@trpc/server': 11.0.4 typescript: '>=5.7.2' - '@trpc/next@11.0.2': - resolution: {integrity: sha512-+xlWBQWKcc3vduRIn5xJfw7mKVYlQj2C6T36M6QQwe7gFEo6ZgZx8O+nT1rCQNjdw2LMr8fhEwqOH5qIcKRLAw==} + '@trpc/next@11.0.4': + resolution: {integrity: sha512-s85jVlUwEDNOoC+MkXLjonVPEemlvGMfcnUGpuOuWFPn0FBeH94JYqITJSzyjzHG+Hk7RfC3pEqc5UXPZ1VIGw==} peerDependencies: '@tanstack/react-query': ^5.59.15 - '@trpc/client': 11.0.2 - '@trpc/react-query': 11.0.2 - '@trpc/server': 11.0.2 - next: '>=15.2.2' + '@trpc/client': 11.0.4 + '@trpc/react-query': 11.0.4 + '@trpc/server': 11.0.4 + next: '*' react: '>=16.8.0' react-dom: '>=16.8.0' typescript: '>=5.7.2' @@ -4589,18 +4589,18 @@ packages: '@trpc/react-query': optional: true - '@trpc/react-query@11.0.2': - resolution: {integrity: sha512-i/u6cbZspGekRAHhEk/jdG1J/XR0ccF+UGFTCEozwPBMBX6eBOe3LTVJ6FLXL2n8IHbSaJEP9h76rzIMXv44lg==} + '@trpc/react-query@11.0.4': + resolution: {integrity: sha512-rpzwKzE4r1bhuVvNZXI0eLaXZz7SkEAJ0VsJUo172gN3r8HqUoQjXcVKw+ZUre1RgxWbUf9jpILdfDOUTNZEvw==} peerDependencies: '@tanstack/react-query': ^5.67.1 - '@trpc/client': 11.0.2 - '@trpc/server': 11.0.2 + '@trpc/client': 11.0.4 + '@trpc/server': 11.0.4 react: '>=18.2.0' react-dom: '>=18.2.0' typescript: '>=5.7.2' - '@trpc/server@11.0.2': - resolution: {integrity: sha512-PIcm8UWFyE0AnIYjxsyc1zfVa6X10m9Opm1SJ2ou9Vu8dlXO6rMtmafLUXJsMeQk/3ecxObFtEiZIX8TvB3eCg==} + '@trpc/server@11.0.4': + resolution: {integrity: sha512-beDEGEw+slNiYxLUpZ8HKU1mnZBoP/VLMtrKh2ABKl7VC0PQV9XcDMVjB0GcSW15nTSiOnGDGyFDeudp4dH2qw==} peerDependencies: typescript: '>=5.7.2' @@ -4792,8 +4792,8 @@ packages: '@types/range-parser@1.2.7': resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==} - '@types/react-dom@19.1.1': - resolution: {integrity: sha512-jFf/woGTVTjUJsl2O7hcopJ1r0upqoq/vIOoCj0yLh3RIXxWcljlpuZ+vEBRXsymD1jhfeJrlyTy/S1UW+4y1w==} + '@types/react-dom@19.1.2': + resolution: {integrity: sha512-XGJkWF41Qq305SKWEILa1O8vzhb3aOo3ogBlSmiqNko/WmRb6QIaweuZCXjKygVDXpzXb5wyxKTSOsmkuqj+Qw==} peerDependencies: '@types/react': ^19.0.0 @@ -4854,51 +4854,51 @@ packages: '@types/xml2js@0.4.14': resolution: {integrity: sha512-4YnrRemBShWRO2QjvUin8ESA41rH+9nQGLUGZV/1IDhi3SL9OhdpNC/MrulTWuptXKwhx/aDxE7toV0f/ypIXQ==} - '@typescript-eslint/eslint-plugin@8.29.0': - resolution: {integrity: sha512-PAIpk/U7NIS6H7TEtN45SPGLQaHNgB7wSjsQV/8+KYokAb2T/gloOA/Bee2yd4/yKVhPKe5LlaUGhAZk5zmSaQ==} + '@typescript-eslint/eslint-plugin@8.29.1': + resolution: {integrity: sha512-ba0rr4Wfvg23vERs3eB+P3lfj2E+2g3lhWcCVukUuhtcdUx5lSIFZlGFEBHKr+3zizDa/TvZTptdNHVZWAkSBg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: '@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0 eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.9.0' - '@typescript-eslint/parser@8.29.0': - resolution: {integrity: sha512-8C0+jlNJOwQso2GapCVWWfW/rzaq7Lbme+vGUFKE31djwNncIpgXD7Cd4weEsDdkoZDjH0lwwr3QDQFuyrMg9g==} + '@typescript-eslint/parser@8.29.1': + resolution: {integrity: sha512-zczrHVEqEaTwh12gWBIJWj8nx+ayDcCJs06yoNMY0kwjMWDM6+kppljY+BxWI06d2Ja+h4+WdufDcwMnnMEWmg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.9.0' - '@typescript-eslint/scope-manager@8.29.0': - resolution: {integrity: sha512-aO1PVsq7Gm+tcghabUpzEnVSFMCU4/nYIgC2GOatJcllvWfnhrgW0ZEbnTxm36QsikmCN1K/6ZgM7fok2I7xNw==} + '@typescript-eslint/scope-manager@8.29.1': + resolution: {integrity: sha512-2nggXGX5F3YrsGN08pw4XpMLO1Rgtnn4AzTegC2MDesv6q3QaTU5yU7IbS1tf1IwCR0Hv/1EFygLn9ms6LIpDA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/type-utils@8.29.0': - resolution: {integrity: sha512-ahaWQ42JAOx+NKEf5++WC/ua17q5l+j1GFrbbpVKzFL/tKVc0aYY8rVSYUpUvt2hUP1YBr7mwXzx+E/DfUWI9Q==} + '@typescript-eslint/type-utils@8.29.1': + resolution: {integrity: sha512-DkDUSDwZVCYN71xA4wzySqqcZsHKic53A4BLqmrWFFpOpNSoxX233lwGu/2135ymTCR04PoKiEEEvN1gFYg4Tw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.9.0' - '@typescript-eslint/types@8.29.0': - resolution: {integrity: sha512-wcJL/+cOXV+RE3gjCyl/V2G877+2faqvlgtso/ZRbTCnZazh0gXhe+7gbAnfubzN2bNsBtZjDvlh7ero8uIbzg==} + '@typescript-eslint/types@8.29.1': + resolution: {integrity: sha512-VT7T1PuJF1hpYC3AGm2rCgJBjHL3nc+A/bhOp9sGMKfi5v0WufsX/sHCFBfNTx2F+zA6qBc/PD0/kLRLjdt8mQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.29.0': - resolution: {integrity: sha512-yOfen3jE9ISZR/hHpU/bmNvTtBW1NjRbkSFdZOksL1N+ybPEE7UVGMwqvS6CP022Rp00Sb0tdiIkhSCe6NI8ow==} + '@typescript-eslint/typescript-estree@8.29.1': + resolution: {integrity: sha512-l1enRoSaUkQxOQnbi0KPUtqeZkSiFlqrx9/3ns2rEDhGKfTa+88RmXqedC1zmVTOWrLc2e6DEJrTA51C9iLH5g==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <5.9.0' - '@typescript-eslint/utils@8.29.0': - resolution: {integrity: sha512-gX/A0Mz9Bskm8avSWFcK0gP7cZpbY4AIo6B0hWYFCaIsz750oaiWR4Jr2CI+PQhfW1CpcQr9OlfPS+kMFegjXA==} + '@typescript-eslint/utils@8.29.1': + resolution: {integrity: sha512-QAkFEbytSaB8wnmB+DflhUPz6CLbFWE2SnSCrRMEa+KnXIzDYbpsn++1HGvnfAsUY44doDXmvRkO5shlM/3UfA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.9.0' - '@typescript-eslint/visitor-keys@8.29.0': - resolution: {integrity: sha512-Sne/pVz8ryR03NFK21VpN88dZ2FdQXOlq3VIklbrTYEt8yXtRFr9tvUhqvCeKjqYk5FSim37sHbooT6vzBTZcg==} + '@typescript-eslint/visitor-keys@8.29.1': + resolution: {integrity: sha512-RGLh5CRaUEf02viP5c1Vh1cMGffQscyHe7HPAzGpfmfflFg1wUz2rYxd+OZqwpeypYvZ8UxSxuIpF++fmOzEcg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@umami/node@0.4.0': @@ -5312,9 +5312,6 @@ packages: balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - bare-events@2.4.2: - resolution: {integrity: sha512-qMKFd2qG/36aA4GwvKq8MxnPgCQAmBWmSyLWsJcbn8v03wvIPQ/hG1Ms8bPzndZxMDoHpxez5VOS+gC9Yi24/Q==} - bare-events@2.5.4: resolution: {integrity: sha512-+gFfDkR8pj4/TrWCGUGWmJIkBwuxPS5F+a5yWjOHQt2hHvNZd5YLzadjmDUtFmMM4y429bnKLa8bYBMHcYdnQA==} @@ -6470,8 +6467,8 @@ packages: resolution: {integrity: sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - eslint@9.23.0: - resolution: {integrity: sha512-jV7AbNoFPAY1EkFYpLq5bslU9NLNO8xnEeQXwErNibVryjk67wHVmddTBilc5srIttJDBrB0eMHKZBFbSIABCw==} + eslint@9.24.0: + resolution: {integrity: sha512-eh/jxIEJyZrvbWRe4XuVclLPDYSYYYgLy5zXGGxD6j8zjSAxFEzI2fL/8xNq6O2yKqVt+eF2YhV+hxjV6UKXwQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} hasBin: true peerDependencies: @@ -7588,8 +7585,8 @@ packages: resolution: {integrity: sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==} engines: {node: '>= 0.6.3'} - ldapts@7.3.3: - resolution: {integrity: sha512-y70KDgoszK9OP6wmtH4kOzXqKAb5qfjuni9UH0pws2Z8kGbl1q9us0Ldo9j1jSzJg/Gz+rHHJV1t5BOVxmopUA==} + ldapts@7.4.0: + resolution: {integrity: sha512-QLgx2pLvxMXY1nCc85Fx+cwVJDvC0sQ3l4CJZSl1FJ/iV8Ypfl6m+5xz4lm1lhoXcUlvhPqxEoyIj/8LR6ut+A==} engines: {node: '>=18'} levn@0.4.1: @@ -8001,8 +7998,8 @@ packages: typescript: optional: true - next@15.2.4: - resolution: {integrity: sha512-VwL+LAaPSxEkd3lU2xWbgEOtrM8oedmyhBqaVNmgKB+GvZlCy9rgaEc+y2on0wv+l0oSFqLtYD6dcC1eAedUaQ==} + next@15.2.5: + resolution: {integrity: sha512-LlqS8ljc7RWR3riUwxB5+14v7ULAa5EuLUyarD/sFgXPd6Hmmscg8DXcu9hDdh5atybrIDVBrFhjDpRIQo/4pQ==} engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} hasBin: true peerDependencies: @@ -8760,9 +8757,6 @@ packages: queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} - queue-tick@1.0.1: - resolution: {integrity: sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==} - radix3@1.1.2: resolution: {integrity: sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==} @@ -8912,8 +8906,8 @@ packages: peerDependencies: react: '>= 0.14.0' - react-textarea-autosize@8.5.6: - resolution: {integrity: sha512-aT3ioKXMa8f6zHYGebhbdMD2L00tKeRX1zuVuDx9YQK/JLLRSaSxq3ugECEmUB9z2kvk6bFSIoRHLkkUv0RJiw==} + react-textarea-autosize@8.5.9: + resolution: {integrity: sha512-U1DGlIQN5AwgjTyOEnI1oCcMuEr1pv1qOtklB2l4nyMGbHzWrI0eFsYK0zos2YWqAolJyG0IWJaqWmWj5ETh0A==} engines: {node: '>=10'} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 @@ -9443,9 +9437,6 @@ packages: resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} engines: {node: '>=10.0.0'} - streamx@2.20.1: - resolution: {integrity: sha512-uTa0mU6WUC65iUvzKH4X9hEdvSW7rbPxPtwfWiLMSj3qTdQbAiUboZTxauKfpFuGIGa1C2BYijZ7wgdUXICJhA==} - streamx@2.22.0: resolution: {integrity: sha512-sLh1evHOzBy/iWRiR6d1zRcLao4gGZr3C1kzNz4fopCOKJb6xD9ub8Mpi9Mr1R6id5o43S+d93fI48UC5uM9aw==} @@ -9584,8 +9575,8 @@ packages: swagger-client@3.34.4: resolution: {integrity: sha512-Qvtu8DtARAx5GwefA0eV1WRLa4Q9bhczrtNAsiBMOx3HkxAOczy1APQhrcblJdLys0xEGQ4xYizYFXfIL9BhpA==} - swagger-ui-react@5.20.6: - resolution: {integrity: sha512-fBNIZ/MdWdr2egmJVFgZ4KX9TqRF8b8is8ew4dFPDw5Yr2tzOTu7G6XxuVcNZUGUs5XBXX7p1LTdeiqqRZCInA==} + swagger-ui-react@5.20.7: + resolution: {integrity: sha512-TmWWER0OKkwx/IC1G82AaU265oOpETZFt2KjYxvsGwRWB4cN0NYd85jVogd6tATS8YxbiUHfVpUUJp662CCljg==} peerDependencies: react: '>=16.8.0 <19' react-dom: '>=16.8.0 <19' @@ -9664,8 +9655,8 @@ packages: resolution: {integrity: sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg==} engines: {node: '>=18'} - testcontainers@10.24.0: - resolution: {integrity: sha512-akkNb3LO2IhxnJzl5kj6dDt2c5q0bWHSTUSLSsqqLuZkaJTYCyWCE76uSzJLGpCkASV7Bw4XOOKvn4Tu0GHeFA==} + testcontainers@10.24.1: + resolution: {integrity: sha512-72eJwXrGNg2fyN8LfGrniOI5hpkur7t74w8MEZPrpUZ/YojfBQY8z6ZU/P586TzfJTWEakAH49DO6f8niHsrBQ==} text-decoder@1.2.0: resolution: {integrity: sha512-n1yg1mOj9DNpk3NeZOx7T6jchTbyJS3i3cucbNN6FcdPriMZx7NsgrGpWWdWZZGxD7ES1XB+3uoqHMgOKaN+fg==} @@ -9934,10 +9925,6 @@ packages: resolution: {integrity: sha512-UJShLPYi1aWqCdq9HycOL/gwsuqda1OISdBO3t8RlXQC4QvtuIz4b5FCfe2dQIWEpmlRExKmcTBfP1r9bhY7ig==} engines: {node: '>=16'} - type-fest@4.34.1: - resolution: {integrity: sha512-6kSc32kT0rbwxD6QL1CYe8IqdzN/J/ILMrNK+HMQCKH3insCDRY/3ITb0vcBss0a3t72fzh2YSzj8ko1HgwT3g==} - engines: {node: '>=16'} - type-fest@4.39.1: resolution: {integrity: sha512-uW9qzd66uyHYxwyVBYiwS4Oi0qZyUqwjU+Oevr6ZogYiXt99EOYtwvzMSLw1c3lYo2HzJsep/NB23iEVEgjG/w==} engines: {node: '>=16'} @@ -9984,15 +9971,15 @@ packages: types-ramda@0.30.1: resolution: {integrity: sha512-1HTsf5/QVRmLzcGfldPFvkVsAdi1db1BBKzi7iW3KBUlOICg/nKnFS+jGqDJS3YD8VsWbAh7JiHeBvbsw8RPxA==} - typescript-eslint@8.29.0: - resolution: {integrity: sha512-ep9rVd9B4kQsZ7ZnWCVxUE/xDLUUUsRzE0poAeNu+4CkFErLfuvPt/qtm2EpnSyfvsR0S6QzDFSrPCFBwf64fg==} + typescript-eslint@8.29.1: + resolution: {integrity: sha512-f8cDkvndhbQMPcysk6CUSGBWV+g1utqdn71P5YKwMumVMOG/5k7cHq0KyG4O52nB0oKS4aN2Tp5+wB4APJGC+w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.9.0' - typescript@5.8.2: - resolution: {integrity: sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==} + typescript@5.8.3: + resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==} engines: {node: '>=14.17'} hasBin: true @@ -11251,14 +11238,14 @@ snapshots: '@esbuild/win32-x64@0.25.0': optional: true - '@eslint-community/eslint-utils@4.4.0(eslint@9.23.0)': + '@eslint-community/eslint-utils@4.4.0(eslint@9.24.0)': dependencies: - eslint: 9.23.0 + eslint: 9.24.0 eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.1': {} - '@eslint/config-array@0.19.2': + '@eslint/config-array@0.20.0': dependencies: '@eslint/object-schema': 2.1.6 debug: 4.4.0 @@ -11286,7 +11273,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@eslint/js@9.23.0': {} + '@eslint/js@9.24.0': {} '@eslint/object-schema@2.1.6': {} @@ -11539,7 +11526,7 @@ snapshots: dependencies: jsep: 1.4.0 - '@kubernetes/client-node@1.1.1': + '@kubernetes/client-node@1.1.2': dependencies: '@types/js-yaml': 4.0.9 '@types/node': 22.14.0 @@ -11577,91 +11564,91 @@ snapshots: js-base64: 3.7.7 optional: true - '@mantine/charts@7.17.3(@mantine/core@7.17.3(@mantine/hooks@7.17.3(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@mantine/hooks@7.17.3(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(recharts@2.15.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0))': + '@mantine/charts@7.17.4(@mantine/core@7.17.4(@mantine/hooks@7.17.4(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@mantine/hooks@7.17.4(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(recharts@2.15.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0))': dependencies: - '@mantine/core': 7.17.3(@mantine/hooks@7.17.3(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@mantine/hooks': 7.17.3(react@19.1.0) + '@mantine/core': 7.17.4(@mantine/hooks@7.17.4(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@mantine/hooks': 7.17.4(react@19.1.0) react: 19.1.0 react-dom: 19.1.0(react@19.1.0) recharts: 2.15.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@mantine/colors-generator@7.17.3(chroma-js@3.1.2)': + '@mantine/colors-generator@7.17.4(chroma-js@3.1.2)': dependencies: chroma-js: 3.1.2 - '@mantine/core@7.17.3(@mantine/hooks@7.17.3(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@mantine/core@7.17.4(@mantine/hooks@7.17.4(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: '@floating-ui/react': 0.26.28(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@mantine/hooks': 7.17.3(react@19.1.0) + '@mantine/hooks': 7.17.4(react@19.1.0) clsx: 2.1.1 react: 19.1.0 react-dom: 19.1.0(react@19.1.0) react-number-format: 5.4.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0) react-remove-scroll: 2.6.2(@types/react@19.1.0)(react@19.1.0) - react-textarea-autosize: 8.5.6(@types/react@19.1.0)(react@19.1.0) - type-fest: 4.34.1 + react-textarea-autosize: 8.5.9(@types/react@19.1.0)(react@19.1.0) + type-fest: 4.39.1 transitivePeerDependencies: - '@types/react' - '@mantine/dates@7.17.3(@mantine/core@7.17.3(@mantine/hooks@7.17.3(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@mantine/hooks@7.17.3(react@19.1.0))(dayjs@1.11.13)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@mantine/dates@7.17.4(@mantine/core@7.17.4(@mantine/hooks@7.17.4(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@mantine/hooks@7.17.4(react@19.1.0))(dayjs@1.11.13)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: - '@mantine/core': 7.17.3(@mantine/hooks@7.17.3(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@mantine/hooks': 7.17.3(react@19.1.0) + '@mantine/core': 7.17.4(@mantine/hooks@7.17.4(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@mantine/hooks': 7.17.4(react@19.1.0) clsx: 2.1.1 dayjs: 1.11.13 react: 19.1.0 react-dom: 19.1.0(react@19.1.0) - '@mantine/dropzone@7.17.3(@mantine/core@7.17.3(@mantine/hooks@7.17.3(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@mantine/hooks@7.17.3(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@mantine/dropzone@7.17.4(@mantine/core@7.17.4(@mantine/hooks@7.17.4(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@mantine/hooks@7.17.4(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: - '@mantine/core': 7.17.3(@mantine/hooks@7.17.3(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@mantine/hooks': 7.17.3(react@19.1.0) + '@mantine/core': 7.17.4(@mantine/hooks@7.17.4(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@mantine/hooks': 7.17.4(react@19.1.0) react: 19.1.0 react-dom: 19.1.0(react@19.1.0) react-dropzone-esm: 15.2.0(react@19.1.0) - '@mantine/form@7.17.3(react@19.1.0)': + '@mantine/form@7.17.4(react@19.1.0)': dependencies: fast-deep-equal: 3.1.3 klona: 2.0.6 react: 19.1.0 - '@mantine/hooks@7.17.3(react@19.1.0)': + '@mantine/hooks@7.17.4(react@19.1.0)': dependencies: react: 19.1.0 - '@mantine/modals@7.17.3(@mantine/core@7.17.3(@mantine/hooks@7.17.3(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@mantine/hooks@7.17.3(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@mantine/modals@7.17.4(@mantine/core@7.17.4(@mantine/hooks@7.17.4(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@mantine/hooks@7.17.4(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: - '@mantine/core': 7.17.3(@mantine/hooks@7.17.3(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@mantine/hooks': 7.17.3(react@19.1.0) + '@mantine/core': 7.17.4(@mantine/hooks@7.17.4(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@mantine/hooks': 7.17.4(react@19.1.0) react: 19.1.0 react-dom: 19.1.0(react@19.1.0) - '@mantine/notifications@7.17.3(@mantine/core@7.17.3(@mantine/hooks@7.17.3(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@mantine/hooks@7.17.3(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@mantine/notifications@7.17.4(@mantine/core@7.17.4(@mantine/hooks@7.17.4(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@mantine/hooks@7.17.4(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: - '@mantine/core': 7.17.3(@mantine/hooks@7.17.3(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@mantine/hooks': 7.17.3(react@19.1.0) - '@mantine/store': 7.17.3(react@19.1.0) + '@mantine/core': 7.17.4(@mantine/hooks@7.17.4(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@mantine/hooks': 7.17.4(react@19.1.0) + '@mantine/store': 7.17.4(react@19.1.0) react: 19.1.0 react-dom: 19.1.0(react@19.1.0) react-transition-group: 4.4.5(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@mantine/spotlight@7.17.3(@mantine/core@7.17.3(@mantine/hooks@7.17.3(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@mantine/hooks@7.17.3(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@mantine/spotlight@7.17.4(@mantine/core@7.17.4(@mantine/hooks@7.17.4(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@mantine/hooks@7.17.4(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: - '@mantine/core': 7.17.3(@mantine/hooks@7.17.3(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@mantine/hooks': 7.17.3(react@19.1.0) - '@mantine/store': 7.17.3(react@19.1.0) + '@mantine/core': 7.17.4(@mantine/hooks@7.17.4(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@mantine/hooks': 7.17.4(react@19.1.0) + '@mantine/store': 7.17.4(react@19.1.0) react: 19.1.0 react-dom: 19.1.0(react@19.1.0) - '@mantine/store@7.17.3(react@19.1.0)': + '@mantine/store@7.17.4(react@19.1.0)': dependencies: react: 19.1.0 - '@mantine/tiptap@7.17.3(@mantine/core@7.17.3(@mantine/hooks@7.17.3(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@mantine/hooks@7.17.3(react@19.1.0))(@tiptap/extension-link@2.11.7(@tiptap/core@2.11.7(@tiptap/pm@2.11.7))(@tiptap/pm@2.11.7))(@tiptap/react@2.11.7(@tiptap/core@2.11.7(@tiptap/pm@2.11.7))(@tiptap/pm@2.11.7)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@mantine/tiptap@7.17.4(@mantine/core@7.17.4(@mantine/hooks@7.17.4(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@mantine/hooks@7.17.4(react@19.1.0))(@tiptap/extension-link@2.11.7(@tiptap/core@2.11.7(@tiptap/pm@2.11.7))(@tiptap/pm@2.11.7))(@tiptap/react@2.11.7(@tiptap/core@2.11.7(@tiptap/pm@2.11.7))(@tiptap/pm@2.11.7)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: - '@mantine/core': 7.17.3(@mantine/hooks@7.17.3(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@mantine/hooks': 7.17.3(react@19.1.0) + '@mantine/core': 7.17.4(@mantine/hooks@7.17.4(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@mantine/hooks': 7.17.4(react@19.1.0) '@tiptap/extension-link': 2.11.7(@tiptap/core@2.11.7(@tiptap/pm@2.11.7))(@tiptap/pm@2.11.7) '@tiptap/react': 2.11.7(@tiptap/core@2.11.7(@tiptap/pm@2.11.7))(@tiptap/pm@2.11.7)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) react: 19.1.0 @@ -11735,34 +11722,34 @@ snapshots: - utf-8-validate - webpack-sources - '@next/env@15.2.4': {} + '@next/env@15.2.5': {} - '@next/eslint-plugin-next@15.2.4': + '@next/eslint-plugin-next@15.2.5': dependencies: fast-glob: 3.3.1 - '@next/swc-darwin-arm64@15.2.4': + '@next/swc-darwin-arm64@15.2.5': optional: true - '@next/swc-darwin-x64@15.2.4': + '@next/swc-darwin-x64@15.2.5': optional: true - '@next/swc-linux-arm64-gnu@15.2.4': + '@next/swc-linux-arm64-gnu@15.2.5': optional: true - '@next/swc-linux-arm64-musl@15.2.4': + '@next/swc-linux-arm64-musl@15.2.5': optional: true - '@next/swc-linux-x64-gnu@15.2.4': + '@next/swc-linux-x64-gnu@15.2.5': optional: true - '@next/swc-linux-x64-musl@15.2.4': + '@next/swc-linux-x64-musl@15.2.5': optional: true - '@next/swc-win32-arm64-msvc@15.2.4': + '@next/swc-win32-arm64-msvc@15.2.5': optional: true - '@next/swc-win32-x64-msvc@15.2.4': + '@next/swc-win32-x64-msvc@15.2.5': optional: true '@noble/hashes@1.5.0': {} @@ -12177,15 +12164,15 @@ snapshots: '@sec-ant/readable-stream@0.4.1': {} - '@semantic-release/changelog@6.0.3(semantic-release@24.2.3(typescript@5.8.2))': + '@semantic-release/changelog@6.0.3(semantic-release@24.2.3(typescript@5.8.3))': dependencies: '@semantic-release/error': 3.0.0 aggregate-error: 3.1.0 fs-extra: 11.2.0 lodash: 4.17.21 - semantic-release: 24.2.3(typescript@5.8.2) + semantic-release: 24.2.3(typescript@5.8.3) - '@semantic-release/commit-analyzer@13.0.1(semantic-release@24.2.3(typescript@5.8.2))': + '@semantic-release/commit-analyzer@13.0.1(semantic-release@24.2.3(typescript@5.8.3))': dependencies: conventional-changelog-angular: 8.0.0 conventional-changelog-writer: 8.0.0 @@ -12195,7 +12182,7 @@ snapshots: import-from-esm: 2.0.0 lodash-es: 4.17.21 micromatch: 4.0.8 - semantic-release: 24.2.3(typescript@5.8.2) + semantic-release: 24.2.3(typescript@5.8.3) transitivePeerDependencies: - supports-color @@ -12203,7 +12190,7 @@ snapshots: '@semantic-release/error@4.0.0': {} - '@semantic-release/git@10.0.1(semantic-release@24.2.3(typescript@5.8.2))': + '@semantic-release/git@10.0.1(semantic-release@24.2.3(typescript@5.8.3))': dependencies: '@semantic-release/error': 3.0.0 aggregate-error: 3.1.0 @@ -12213,11 +12200,11 @@ snapshots: lodash: 4.17.21 micromatch: 4.0.8 p-reduce: 2.1.0 - semantic-release: 24.2.3(typescript@5.8.2) + semantic-release: 24.2.3(typescript@5.8.3) transitivePeerDependencies: - supports-color - '@semantic-release/github@11.0.1(semantic-release@24.2.3(typescript@5.8.2))': + '@semantic-release/github@11.0.1(semantic-release@24.2.3(typescript@5.8.3))': dependencies: '@octokit/core': 6.1.2 '@octokit/plugin-paginate-rest': 11.3.6(@octokit/core@6.1.2) @@ -12234,12 +12221,12 @@ snapshots: lodash-es: 4.17.21 mime: 4.0.4 p-filter: 4.1.0 - semantic-release: 24.2.3(typescript@5.8.2) + semantic-release: 24.2.3(typescript@5.8.3) url-join: 5.0.0 transitivePeerDependencies: - supports-color - '@semantic-release/npm@12.0.1(semantic-release@24.2.3(typescript@5.8.2))': + '@semantic-release/npm@12.0.1(semantic-release@24.2.3(typescript@5.8.3))': dependencies: '@semantic-release/error': 4.0.0 aggregate-error: 5.0.0 @@ -12252,11 +12239,11 @@ snapshots: rc: 1.2.8 read-pkg: 9.0.1 registry-auth-token: 5.0.2 - semantic-release: 24.2.3(typescript@5.8.2) + semantic-release: 24.2.3(typescript@5.8.3) semver: 7.6.3 tempy: 3.1.0 - '@semantic-release/release-notes-generator@14.0.3(semantic-release@24.2.3(typescript@5.8.2))': + '@semantic-release/release-notes-generator@14.0.3(semantic-release@24.2.3(typescript@5.8.3))': dependencies: conventional-changelog-angular: 8.0.0 conventional-changelog-writer: 8.0.0 @@ -12268,7 +12255,7 @@ snapshots: into-stream: 7.0.0 lodash-es: 4.17.21 read-package-up: 11.0.0 - semantic-release: 24.2.3(typescript@5.8.2) + semantic-release: 24.2.3(typescript@5.8.3) transitivePeerDependencies: - supports-color @@ -12645,16 +12632,16 @@ snapshots: dependencies: tslib: 2.8.1 - '@t3-oss/env-core@0.12.0(typescript@5.8.2)(zod@3.24.2)': + '@t3-oss/env-core@0.12.0(typescript@5.8.3)(zod@3.24.2)': optionalDependencies: - typescript: 5.8.2 + typescript: 5.8.3 zod: 3.24.2 - '@t3-oss/env-nextjs@0.12.0(typescript@5.8.2)(zod@3.24.2)': + '@t3-oss/env-nextjs@0.12.0(typescript@5.8.3)(zod@3.24.2)': dependencies: - '@t3-oss/env-core': 0.12.0(typescript@5.8.2)(zod@3.24.2) + '@t3-oss/env-core': 0.12.0(typescript@5.8.3)(zod@3.24.2) optionalDependencies: - typescript: 5.8.2 + typescript: 5.8.3 zod: 3.24.2 '@tabler/icons-react@3.31.0(react@19.1.0)': @@ -12668,25 +12655,25 @@ snapshots: dependencies: remove-accents: 0.5.0 - '@tanstack/query-core@5.71.10': {} + '@tanstack/query-core@5.72.1': {} - '@tanstack/query-devtools@5.71.5': {} + '@tanstack/query-devtools@5.72.1': {} - '@tanstack/react-query-devtools@5.71.10(@tanstack/react-query@5.71.10(react@19.1.0))(react@19.1.0)': + '@tanstack/react-query-devtools@5.72.1(@tanstack/react-query@5.72.1(react@19.1.0))(react@19.1.0)': dependencies: - '@tanstack/query-devtools': 5.71.5 - '@tanstack/react-query': 5.71.10(react@19.1.0) + '@tanstack/query-devtools': 5.72.1 + '@tanstack/react-query': 5.72.1(react@19.1.0) react: 19.1.0 - '@tanstack/react-query-next-experimental@5.71.10(@tanstack/react-query@5.71.10(react@19.1.0))(next@15.2.4(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.3))(react@19.1.0)': + '@tanstack/react-query-next-experimental@5.72.1(@tanstack/react-query@5.72.1(react@19.1.0))(next@15.2.5(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.3))(react@19.1.0)': dependencies: - '@tanstack/react-query': 5.71.10(react@19.1.0) - next: 15.2.4(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.3) + '@tanstack/react-query': 5.72.1(react@19.1.0) + next: 15.2.5(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.3) react: 19.1.0 - '@tanstack/react-query@5.71.10(react@19.1.0)': + '@tanstack/react-query@5.72.1(react@19.1.0)': dependencies: - '@tanstack/query-core': 5.71.10 + '@tanstack/query-core': 5.72.1 react: 19.1.0 '@tanstack/react-table@8.20.5(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': @@ -12705,9 +12692,9 @@ snapshots: '@tanstack/virtual-core@3.11.2': {} - '@testcontainers/mysql@10.24.0': + '@testcontainers/mysql@10.24.1': dependencies: - testcontainers: 10.24.0 + testcontainers: 10.24.1 transitivePeerDependencies: - bare-buffer - supports-color @@ -12929,35 +12916,35 @@ snapshots: tree-sitter: 0.22.1 optional: true - '@trpc/client@11.0.2(@trpc/server@11.0.2(typescript@5.8.2))(typescript@5.8.2)': + '@trpc/client@11.0.4(@trpc/server@11.0.4(typescript@5.8.3))(typescript@5.8.3)': dependencies: - '@trpc/server': 11.0.2(typescript@5.8.2) - typescript: 5.8.2 + '@trpc/server': 11.0.4(typescript@5.8.3) + typescript: 5.8.3 - '@trpc/next@11.0.2(@tanstack/react-query@5.71.10(react@19.1.0))(@trpc/client@11.0.2(@trpc/server@11.0.2(typescript@5.8.2))(typescript@5.8.2))(@trpc/react-query@11.0.2(@tanstack/react-query@5.71.10(react@19.1.0))(@trpc/client@11.0.2(@trpc/server@11.0.2(typescript@5.8.2))(typescript@5.8.2))(@trpc/server@11.0.2(typescript@5.8.2))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(typescript@5.8.2))(@trpc/server@11.0.2(typescript@5.8.2))(next@15.2.4(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.3))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(typescript@5.8.2)': + '@trpc/next@11.0.4(@tanstack/react-query@5.72.1(react@19.1.0))(@trpc/client@11.0.4(@trpc/server@11.0.4(typescript@5.8.3))(typescript@5.8.3))(@trpc/react-query@11.0.4(@tanstack/react-query@5.72.1(react@19.1.0))(@trpc/client@11.0.4(@trpc/server@11.0.4(typescript@5.8.3))(typescript@5.8.3))(@trpc/server@11.0.4(typescript@5.8.3))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(typescript@5.8.3))(@trpc/server@11.0.4(typescript@5.8.3))(next@15.2.5(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.3))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(typescript@5.8.3)': dependencies: - '@trpc/client': 11.0.2(@trpc/server@11.0.2(typescript@5.8.2))(typescript@5.8.2) - '@trpc/server': 11.0.2(typescript@5.8.2) - next: 15.2.4(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.3) + '@trpc/client': 11.0.4(@trpc/server@11.0.4(typescript@5.8.3))(typescript@5.8.3) + '@trpc/server': 11.0.4(typescript@5.8.3) + next: 15.2.5(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.3) react: 19.1.0 react-dom: 19.1.0(react@19.1.0) - typescript: 5.8.2 + typescript: 5.8.3 optionalDependencies: - '@tanstack/react-query': 5.71.10(react@19.1.0) - '@trpc/react-query': 11.0.2(@tanstack/react-query@5.71.10(react@19.1.0))(@trpc/client@11.0.2(@trpc/server@11.0.2(typescript@5.8.2))(typescript@5.8.2))(@trpc/server@11.0.2(typescript@5.8.2))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(typescript@5.8.2) + '@tanstack/react-query': 5.72.1(react@19.1.0) + '@trpc/react-query': 11.0.4(@tanstack/react-query@5.72.1(react@19.1.0))(@trpc/client@11.0.4(@trpc/server@11.0.4(typescript@5.8.3))(typescript@5.8.3))(@trpc/server@11.0.4(typescript@5.8.3))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(typescript@5.8.3) - '@trpc/react-query@11.0.2(@tanstack/react-query@5.71.10(react@19.1.0))(@trpc/client@11.0.2(@trpc/server@11.0.2(typescript@5.8.2))(typescript@5.8.2))(@trpc/server@11.0.2(typescript@5.8.2))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(typescript@5.8.2)': + '@trpc/react-query@11.0.4(@tanstack/react-query@5.72.1(react@19.1.0))(@trpc/client@11.0.4(@trpc/server@11.0.4(typescript@5.8.3))(typescript@5.8.3))(@trpc/server@11.0.4(typescript@5.8.3))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(typescript@5.8.3)': dependencies: - '@tanstack/react-query': 5.71.10(react@19.1.0) - '@trpc/client': 11.0.2(@trpc/server@11.0.2(typescript@5.8.2))(typescript@5.8.2) - '@trpc/server': 11.0.2(typescript@5.8.2) + '@tanstack/react-query': 5.72.1(react@19.1.0) + '@trpc/client': 11.0.4(@trpc/server@11.0.4(typescript@5.8.3))(typescript@5.8.3) + '@trpc/server': 11.0.4(typescript@5.8.3) react: 19.1.0 react-dom: 19.1.0(react@19.1.0) - typescript: 5.8.2 + typescript: 5.8.3 - '@trpc/server@11.0.2(typescript@5.8.2)': + '@trpc/server@11.0.4(typescript@5.8.3)': dependencies: - typescript: 5.8.2 + typescript: 5.8.3 '@tsconfig/node10@1.0.11': {} @@ -12969,7 +12956,7 @@ snapshots: '@tsconfig/svelte@1.0.13': {} - '@turbo/gen@2.5.0(@types/node@22.14.0)(typescript@5.8.2)': + '@turbo/gen@2.5.0(@types/node@22.14.0)(typescript@5.8.3)': dependencies: '@turbo/workspaces': 2.5.0 commander: 10.0.1 @@ -12979,7 +12966,7 @@ snapshots: node-plop: 0.26.3 picocolors: 1.0.1 proxy-agent: 6.5.0 - ts-node: 10.9.2(@types/node@22.14.0)(typescript@5.8.2) + ts-node: 10.9.2(@types/node@22.14.0)(typescript@5.8.3) update-check: 1.5.4 validate-npm-package-name: 5.0.1 transitivePeerDependencies: @@ -13189,7 +13176,7 @@ snapshots: '@types/range-parser@1.2.7': {} - '@types/react-dom@19.1.1(@types/react@19.1.0)': + '@types/react-dom@19.1.2(@types/react@19.1.0)': dependencies: '@types/react': 19.1.0 @@ -13261,81 +13248,81 @@ snapshots: dependencies: '@types/node': 22.14.0 - '@typescript-eslint/eslint-plugin@8.29.0(@typescript-eslint/parser@8.29.0(eslint@9.23.0)(typescript@5.8.2))(eslint@9.23.0)(typescript@5.8.2)': + '@typescript-eslint/eslint-plugin@8.29.1(@typescript-eslint/parser@8.29.1(eslint@9.24.0)(typescript@5.8.3))(eslint@9.24.0)(typescript@5.8.3)': dependencies: '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 8.29.0(eslint@9.23.0)(typescript@5.8.2) - '@typescript-eslint/scope-manager': 8.29.0 - '@typescript-eslint/type-utils': 8.29.0(eslint@9.23.0)(typescript@5.8.2) - '@typescript-eslint/utils': 8.29.0(eslint@9.23.0)(typescript@5.8.2) - '@typescript-eslint/visitor-keys': 8.29.0 - eslint: 9.23.0 + '@typescript-eslint/parser': 8.29.1(eslint@9.24.0)(typescript@5.8.3) + '@typescript-eslint/scope-manager': 8.29.1 + '@typescript-eslint/type-utils': 8.29.1(eslint@9.24.0)(typescript@5.8.3) + '@typescript-eslint/utils': 8.29.1(eslint@9.24.0)(typescript@5.8.3) + '@typescript-eslint/visitor-keys': 8.29.1 + eslint: 9.24.0 graphemer: 1.4.0 ignore: 5.3.2 natural-compare: 1.4.0 - ts-api-utils: 2.0.1(typescript@5.8.2) - typescript: 5.8.2 + ts-api-utils: 2.0.1(typescript@5.8.3) + typescript: 5.8.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.29.0(eslint@9.23.0)(typescript@5.8.2)': + '@typescript-eslint/parser@8.29.1(eslint@9.24.0)(typescript@5.8.3)': dependencies: - '@typescript-eslint/scope-manager': 8.29.0 - '@typescript-eslint/types': 8.29.0 - '@typescript-eslint/typescript-estree': 8.29.0(typescript@5.8.2) - '@typescript-eslint/visitor-keys': 8.29.0 + '@typescript-eslint/scope-manager': 8.29.1 + '@typescript-eslint/types': 8.29.1 + '@typescript-eslint/typescript-estree': 8.29.1(typescript@5.8.3) + '@typescript-eslint/visitor-keys': 8.29.1 debug: 4.4.0 - eslint: 9.23.0 - typescript: 5.8.2 + eslint: 9.24.0 + typescript: 5.8.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.29.0': + '@typescript-eslint/scope-manager@8.29.1': dependencies: - '@typescript-eslint/types': 8.29.0 - '@typescript-eslint/visitor-keys': 8.29.0 + '@typescript-eslint/types': 8.29.1 + '@typescript-eslint/visitor-keys': 8.29.1 - '@typescript-eslint/type-utils@8.29.0(eslint@9.23.0)(typescript@5.8.2)': + '@typescript-eslint/type-utils@8.29.1(eslint@9.24.0)(typescript@5.8.3)': dependencies: - '@typescript-eslint/typescript-estree': 8.29.0(typescript@5.8.2) - '@typescript-eslint/utils': 8.29.0(eslint@9.23.0)(typescript@5.8.2) + '@typescript-eslint/typescript-estree': 8.29.1(typescript@5.8.3) + '@typescript-eslint/utils': 8.29.1(eslint@9.24.0)(typescript@5.8.3) debug: 4.4.0 - eslint: 9.23.0 - ts-api-utils: 2.0.1(typescript@5.8.2) - typescript: 5.8.2 + eslint: 9.24.0 + ts-api-utils: 2.0.1(typescript@5.8.3) + typescript: 5.8.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.29.0': {} + '@typescript-eslint/types@8.29.1': {} - '@typescript-eslint/typescript-estree@8.29.0(typescript@5.8.2)': + '@typescript-eslint/typescript-estree@8.29.1(typescript@5.8.3)': dependencies: - '@typescript-eslint/types': 8.29.0 - '@typescript-eslint/visitor-keys': 8.29.0 + '@typescript-eslint/types': 8.29.1 + '@typescript-eslint/visitor-keys': 8.29.1 debug: 4.4.0 fast-glob: 3.3.2 is-glob: 4.0.3 minimatch: 9.0.5 semver: 7.6.3 - ts-api-utils: 2.0.1(typescript@5.8.2) - typescript: 5.8.2 + ts-api-utils: 2.0.1(typescript@5.8.3) + typescript: 5.8.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.29.0(eslint@9.23.0)(typescript@5.8.2)': + '@typescript-eslint/utils@8.29.1(eslint@9.24.0)(typescript@5.8.3)': dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@9.23.0) - '@typescript-eslint/scope-manager': 8.29.0 - '@typescript-eslint/types': 8.29.0 - '@typescript-eslint/typescript-estree': 8.29.0(typescript@5.8.2) - eslint: 9.23.0 - typescript: 5.8.2 + '@eslint-community/eslint-utils': 4.4.0(eslint@9.24.0) + '@typescript-eslint/scope-manager': 8.29.1 + '@typescript-eslint/types': 8.29.1 + '@typescript-eslint/typescript-estree': 8.29.1(typescript@5.8.3) + eslint: 9.24.0 + typescript: 5.8.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.29.0': + '@typescript-eslint/visitor-keys@8.29.1': dependencies: - '@typescript-eslint/types': 8.29.0 + '@typescript-eslint/types': 8.29.1 eslint-visitor-keys: 4.2.0 '@umami/node@0.4.0': {} @@ -13853,9 +13840,6 @@ snapshots: balanced-match@1.0.2: {} - bare-events@2.4.2: - optional: true - bare-events@2.5.4: optional: true @@ -14333,14 +14317,14 @@ snapshots: object-assign: 4.1.1 vary: 1.1.2 - cosmiconfig@9.0.0(typescript@5.8.2): + cosmiconfig@9.0.0(typescript@5.8.3): dependencies: env-paths: 2.2.1 import-fresh: 3.3.0 js-yaml: 4.1.0 parse-json: 5.2.0 optionalDependencies: - typescript: 5.8.2 + typescript: 5.8.3 cpu-features@0.0.10: dependencies: @@ -14453,7 +14437,7 @@ snapshots: data-urls@5.0.0: dependencies: whatwg-mimetype: 4.0.0 - whatwg-url: 14.1.0 + whatwg-url: 14.2.0 data-view-buffer@1.0.1: dependencies: @@ -15075,14 +15059,14 @@ snapshots: optionalDependencies: source-map: 0.6.1 - eslint-config-prettier@10.1.1(eslint@9.23.0): + eslint-config-prettier@10.1.1(eslint@9.24.0): dependencies: - eslint: 9.23.0 + eslint: 9.24.0 - eslint-config-turbo@2.5.0(eslint@9.23.0)(turbo@2.5.0): + eslint-config-turbo@2.5.0(eslint@9.24.0)(turbo@2.5.0): dependencies: - eslint: 9.23.0 - eslint-plugin-turbo: 2.5.0(eslint@9.23.0)(turbo@2.5.0) + eslint: 9.24.0 + eslint-plugin-turbo: 2.5.0(eslint@9.24.0)(turbo@2.5.0) turbo: 2.5.0 eslint-import-resolver-node@0.3.9: @@ -15093,17 +15077,17 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@8.29.0(eslint@9.23.0)(typescript@5.8.2))(eslint-import-resolver-node@0.3.9)(eslint@9.23.0): + eslint-module-utils@2.12.0(@typescript-eslint/parser@8.29.1(eslint@9.24.0)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint@9.24.0): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 8.29.0(eslint@9.23.0)(typescript@5.8.2) - eslint: 9.23.0 + '@typescript-eslint/parser': 8.29.1(eslint@9.24.0)(typescript@5.8.3) + eslint: 9.24.0 eslint-import-resolver-node: 0.3.9 transitivePeerDependencies: - supports-color - eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.29.0(eslint@9.23.0)(typescript@5.8.2))(eslint@9.23.0): + eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.29.1(eslint@9.24.0)(typescript@5.8.3))(eslint@9.24.0): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.8 @@ -15112,9 +15096,9 @@ snapshots: array.prototype.flatmap: 1.3.2 debug: 3.2.7 doctrine: 2.1.0 - eslint: 9.23.0 + eslint: 9.24.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.29.0(eslint@9.23.0)(typescript@5.8.2))(eslint-import-resolver-node@0.3.9)(eslint@9.23.0) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.29.1(eslint@9.24.0)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint@9.24.0) hasown: 2.0.2 is-core-module: 2.15.1 is-glob: 4.0.3 @@ -15126,13 +15110,13 @@ snapshots: string.prototype.trimend: 1.0.8 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 8.29.0(eslint@9.23.0)(typescript@5.8.2) + '@typescript-eslint/parser': 8.29.1(eslint@9.24.0)(typescript@5.8.3) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack - supports-color - eslint-plugin-jsx-a11y@6.10.2(eslint@9.23.0): + eslint-plugin-jsx-a11y@6.10.2(eslint@9.24.0): dependencies: aria-query: 5.3.2 array-includes: 3.1.8 @@ -15142,7 +15126,7 @@ snapshots: axobject-query: 4.1.0 damerau-levenshtein: 1.0.8 emoji-regex: 9.2.2 - eslint: 9.23.0 + eslint: 9.24.0 hasown: 2.0.2 jsx-ast-utils: 3.3.5 language-tags: 1.0.9 @@ -15151,11 +15135,11 @@ snapshots: safe-regex-test: 1.0.3 string.prototype.includes: 2.0.1 - eslint-plugin-react-hooks@5.2.0(eslint@9.23.0): + eslint-plugin-react-hooks@5.2.0(eslint@9.24.0): dependencies: - eslint: 9.23.0 + eslint: 9.24.0 - eslint-plugin-react@7.37.5(eslint@9.23.0): + eslint-plugin-react@7.37.5(eslint@9.24.0): dependencies: array-includes: 3.1.8 array.prototype.findlast: 1.2.5 @@ -15163,7 +15147,7 @@ snapshots: array.prototype.tosorted: 1.1.4 doctrine: 2.1.0 es-iterator-helpers: 1.2.1 - eslint: 9.23.0 + eslint: 9.24.0 estraverse: 5.3.0 hasown: 2.0.2 jsx-ast-utils: 3.3.5 @@ -15177,10 +15161,10 @@ snapshots: string.prototype.matchall: 4.0.12 string.prototype.repeat: 1.0.0 - eslint-plugin-turbo@2.5.0(eslint@9.23.0)(turbo@2.5.0): + eslint-plugin-turbo@2.5.0(eslint@9.24.0)(turbo@2.5.0): dependencies: dotenv: 16.0.3 - eslint: 9.23.0 + eslint: 9.24.0 turbo: 2.5.0 eslint-scope@5.1.1: @@ -15197,15 +15181,15 @@ snapshots: eslint-visitor-keys@4.2.0: {} - eslint@9.23.0: + eslint@9.24.0: dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@9.23.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@9.24.0) '@eslint-community/regexpp': 4.12.1 - '@eslint/config-array': 0.19.2 + '@eslint/config-array': 0.20.0 '@eslint/config-helpers': 0.2.0 '@eslint/core': 0.12.0 '@eslint/eslintrc': 3.3.1 - '@eslint/js': 9.23.0 + '@eslint/js': 9.24.0 '@eslint/plugin-kit': 0.2.7 '@humanfs/node': 0.16.6 '@humanwhocodes/module-importer': 1.0.1 @@ -16418,7 +16402,7 @@ snapshots: dependencies: readable-stream: 2.3.8 - ldapts@7.3.3: + ldapts@7.4.0: dependencies: '@types/asn1': 0.2.4 asn1: 0.2.6 @@ -16569,11 +16553,11 @@ snapshots: make-error@1.3.6: {} - mantine-react-table@2.0.0-beta.9(@mantine/core@7.17.3(@mantine/hooks@7.17.3(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@mantine/dates@7.17.3(@mantine/core@7.17.3(@mantine/hooks@7.17.3(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@mantine/hooks@7.17.3(react@19.1.0))(dayjs@1.11.13)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@mantine/hooks@7.17.3(react@19.1.0))(@tabler/icons-react@3.31.0(react@19.1.0))(clsx@2.1.1)(dayjs@1.11.13)(react-dom@19.1.0(react@19.1.0))(react@19.1.0): + mantine-react-table@2.0.0-beta.9(@mantine/core@7.17.4(@mantine/hooks@7.17.4(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@mantine/dates@7.17.4(@mantine/core@7.17.4(@mantine/hooks@7.17.4(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@mantine/hooks@7.17.4(react@19.1.0))(dayjs@1.11.13)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@mantine/hooks@7.17.4(react@19.1.0))(@tabler/icons-react@3.31.0(react@19.1.0))(clsx@2.1.1)(dayjs@1.11.13)(react-dom@19.1.0(react@19.1.0))(react@19.1.0): dependencies: - '@mantine/core': 7.17.3(@mantine/hooks@7.17.3(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@mantine/dates': 7.17.3(@mantine/core@7.17.3(@mantine/hooks@7.17.3(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@mantine/hooks@7.17.3(react@19.1.0))(dayjs@1.11.13)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@mantine/hooks': 7.17.3(react@19.1.0) + '@mantine/core': 7.17.4(@mantine/hooks@7.17.4(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@mantine/dates': 7.17.4(@mantine/core@7.17.4(@mantine/hooks@7.17.4(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@mantine/hooks@7.17.4(react@19.1.0))(dayjs@1.11.13)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@mantine/hooks': 7.17.4(react@19.1.0) '@tabler/icons-react': 3.31.0(react@19.1.0) '@tanstack/match-sorter-utils': 8.19.4 '@tanstack/react-table': 8.20.5(react-dom@19.1.0(react@19.1.0))(react@19.1.0) @@ -16771,25 +16755,25 @@ snapshots: netmask@2.0.2: {} - next-auth@5.0.0-beta.25(next@15.2.4(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.3))(react@19.1.0): + next-auth@5.0.0-beta.25(next@15.2.5(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.3))(react@19.1.0): dependencies: '@auth/core': 0.37.2 - next: 15.2.4(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.3) + next: 15.2.5(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.3) react: 19.1.0 - next-intl@4.0.2(next@15.2.4(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.3))(react@19.1.0)(typescript@5.8.2): + next-intl@4.0.2(next@15.2.5(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.3))(react@19.1.0)(typescript@5.8.3): dependencies: '@formatjs/intl-localematcher': 0.5.5 negotiator: 1.0.0 - next: 15.2.4(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.3) + next: 15.2.5(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.3) react: 19.1.0 use-intl: 4.0.2(react@19.1.0) optionalDependencies: - typescript: 5.8.2 + typescript: 5.8.3 - next@15.2.4(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.3): + next@15.2.5(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.3): dependencies: - '@next/env': 15.2.4 + '@next/env': 15.2.5 '@swc/counter': 0.1.3 '@swc/helpers': 0.5.15 busboy: 1.6.0 @@ -16799,14 +16783,14 @@ snapshots: react-dom: 19.1.0(react@19.1.0) styled-jsx: 5.1.6(@babel/core@7.26.0)(react@19.1.0) optionalDependencies: - '@next/swc-darwin-arm64': 15.2.4 - '@next/swc-darwin-x64': 15.2.4 - '@next/swc-linux-arm64-gnu': 15.2.4 - '@next/swc-linux-arm64-musl': 15.2.4 - '@next/swc-linux-x64-gnu': 15.2.4 - '@next/swc-linux-x64-musl': 15.2.4 - '@next/swc-win32-arm64-msvc': 15.2.4 - '@next/swc-win32-x64-msvc': 15.2.4 + '@next/swc-darwin-arm64': 15.2.5 + '@next/swc-darwin-x64': 15.2.5 + '@next/swc-linux-arm64-gnu': 15.2.5 + '@next/swc-linux-arm64-musl': 15.2.5 + '@next/swc-linux-x64-gnu': 15.2.5 + '@next/swc-linux-x64-musl': 15.2.5 + '@next/swc-win32-arm64-msvc': 15.2.5 + '@next/swc-win32-x64-msvc': 15.2.5 '@playwright/test': 1.49.1 sass: 1.86.3 sharp: 0.33.5 @@ -17575,8 +17559,6 @@ snapshots: queue-microtask@1.2.3: {} - queue-tick@1.0.1: {} - radix3@1.1.2: {} ramda-adjunct@5.1.0(ramda@0.30.1): @@ -17728,7 +17710,7 @@ snapshots: react: 19.1.0 refractor: 3.6.0 - react-textarea-autosize@8.5.6(@types/react@19.1.0)(react@19.1.0): + react-textarea-autosize@8.5.9(@types/react@19.1.0)(react@19.1.0): dependencies: '@babel/runtime': 7.25.6 react: 19.1.0 @@ -17752,14 +17734,14 @@ snapshots: dependencies: find-up-simple: 1.0.0 read-pkg: 9.0.1 - type-fest: 4.34.1 + type-fest: 4.39.1 read-pkg@9.0.1: dependencies: '@types/normalize-package-data': 2.4.4 normalize-package-data: 6.0.2 parse-json: 8.1.0 - type-fest: 4.34.1 + type-fest: 4.39.1 unicorn-magic: 0.1.0 readable-stream@2.3.8: @@ -18069,15 +18051,15 @@ snapshots: ajv-formats: 2.1.1(ajv@8.17.1) ajv-keywords: 5.1.0(ajv@8.17.1) - semantic-release@24.2.3(typescript@5.8.2): + semantic-release@24.2.3(typescript@5.8.3): dependencies: - '@semantic-release/commit-analyzer': 13.0.1(semantic-release@24.2.3(typescript@5.8.2)) + '@semantic-release/commit-analyzer': 13.0.1(semantic-release@24.2.3(typescript@5.8.3)) '@semantic-release/error': 4.0.0 - '@semantic-release/github': 11.0.1(semantic-release@24.2.3(typescript@5.8.2)) - '@semantic-release/npm': 12.0.1(semantic-release@24.2.3(typescript@5.8.2)) - '@semantic-release/release-notes-generator': 14.0.3(semantic-release@24.2.3(typescript@5.8.2)) + '@semantic-release/github': 11.0.1(semantic-release@24.2.3(typescript@5.8.3)) + '@semantic-release/npm': 12.0.1(semantic-release@24.2.3(typescript@5.8.3)) + '@semantic-release/release-notes-generator': 14.0.3(semantic-release@24.2.3(typescript@5.8.3)) aggregate-error: 5.0.0 - cosmiconfig: 9.0.0(typescript@5.8.2) + cosmiconfig: 9.0.0(typescript@5.8.3) debug: 4.4.0 env-ci: 11.1.0 execa: 9.5.2 @@ -18411,21 +18393,12 @@ snapshots: streamsearch@1.1.0: {} - streamx@2.20.1: - dependencies: - fast-fifo: 1.3.2 - queue-tick: 1.0.1 - text-decoder: 1.2.0 - optionalDependencies: - bare-events: 2.4.2 - streamx@2.22.0: dependencies: fast-fifo: 1.3.2 text-decoder: 1.2.0 optionalDependencies: bare-events: 2.5.4 - optional: true strict-event-emitter-types@2.0.0: {} @@ -18598,7 +18571,7 @@ snapshots: transitivePeerDependencies: - debug - swagger-ui-react@5.20.6(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0): + swagger-ui-react@5.20.7(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0): dependencies: '@babel/runtime-corejs3': 7.27.0 '@scarf/scarf': 1.4.0 @@ -18691,7 +18664,7 @@ snapshots: dependencies: b4a: 1.6.6 fast-fifo: 1.3.2 - streamx: 2.20.1 + streamx: 2.22.0 tar@6.2.1: dependencies: @@ -18742,7 +18715,7 @@ snapshots: glob: 10.4.5 minimatch: 9.0.5 - testcontainers@10.24.0: + testcontainers@10.24.1: dependencies: '@balena/dockerignore': 1.0.2 '@types/dockerode': 3.3.37 @@ -18883,9 +18856,9 @@ snapshots: triple-beam@1.4.1: {} - trpc-to-openapi@2.1.5(@trpc/server@11.0.2(typescript@5.8.2))(zod-openapi@2.19.0(zod@3.24.2))(zod@3.24.2): + trpc-to-openapi@2.1.5(@trpc/server@11.0.4(typescript@5.8.3))(zod-openapi@2.19.0(zod@3.24.2))(zod@3.24.2): dependencies: - '@trpc/server': 11.0.2(typescript@5.8.2) + '@trpc/server': 11.0.4(typescript@5.8.3) co-body: 6.2.0 h3: 1.13.0 openapi3-ts: 4.4.0 @@ -18894,13 +18867,13 @@ snapshots: optionalDependencies: '@rollup/rollup-linux-x64-gnu': 4.6.1 - ts-api-utils@2.0.1(typescript@5.8.2): + ts-api-utils@2.0.1(typescript@5.8.3): dependencies: - typescript: 5.8.2 + typescript: 5.8.3 ts-mixer@6.0.4: {} - ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.2): + ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.3): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.11 @@ -18914,15 +18887,15 @@ snapshots: create-require: 1.1.1 diff: 4.0.2 make-error: 1.3.6 - typescript: 5.8.2 + typescript: 5.8.3 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 ts-toolbelt@9.6.0: {} - tsconfck@3.1.3(typescript@5.8.2): + tsconfck@3.1.3(typescript@5.8.3): optionalDependencies: - typescript: 5.8.2 + typescript: 5.8.3 tsconfig-paths@3.15.0: dependencies: @@ -19003,8 +18976,6 @@ snapshots: type-fest@4.30.2: {} - type-fest@4.34.1: {} - type-fest@4.39.1: {} type-is@1.6.18: @@ -19085,17 +19056,17 @@ snapshots: dependencies: ts-toolbelt: 9.6.0 - typescript-eslint@8.29.0(eslint@9.23.0)(typescript@5.8.2): + typescript-eslint@8.29.1(eslint@9.24.0)(typescript@5.8.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.29.0(@typescript-eslint/parser@8.29.0(eslint@9.23.0)(typescript@5.8.2))(eslint@9.23.0)(typescript@5.8.2) - '@typescript-eslint/parser': 8.29.0(eslint@9.23.0)(typescript@5.8.2) - '@typescript-eslint/utils': 8.29.0(eslint@9.23.0)(typescript@5.8.2) - eslint: 9.23.0 - typescript: 5.8.2 + '@typescript-eslint/eslint-plugin': 8.29.1(@typescript-eslint/parser@8.29.1(eslint@9.24.0)(typescript@5.8.3))(eslint@9.24.0)(typescript@5.8.3) + '@typescript-eslint/parser': 8.29.1(eslint@9.24.0)(typescript@5.8.3) + '@typescript-eslint/utils': 8.29.1(eslint@9.24.0)(typescript@5.8.3) + eslint: 9.24.0 + typescript: 5.8.3 transitivePeerDependencies: - supports-color - typescript@5.8.2: {} + typescript@5.8.3: {} uc.micro@2.1.0: {} @@ -19357,11 +19328,11 @@ snapshots: - supports-color - terser - vite-tsconfig-paths@5.1.4(typescript@5.8.2)(vite@5.4.5(@types/node@22.14.0)(sass@1.86.3)(sugarss@4.0.1(postcss@8.4.47))(terser@5.39.0)): + vite-tsconfig-paths@5.1.4(typescript@5.8.3)(vite@5.4.5(@types/node@22.14.0)(sass@1.86.3)(sugarss@4.0.1(postcss@8.4.47))(terser@5.39.0)): dependencies: debug: 4.3.7 globrex: 0.1.2 - tsconfck: 3.1.3(typescript@5.8.2) + tsconfck: 3.1.3(typescript@5.8.3) optionalDependencies: vite: 5.4.5(@types/node@22.14.0)(sass@1.86.3)(sugarss@4.0.1(postcss@8.4.47))(terser@5.39.0) transitivePeerDependencies: diff --git a/tooling/eslint/package.json b/tooling/eslint/package.json index 8c4877aeb..3547c0bd7 100644 --- a/tooling/eslint/package.json +++ b/tooling/eslint/package.json @@ -17,19 +17,19 @@ }, "prettier": "@homarr/prettier-config", "dependencies": { - "@next/eslint-plugin-next": "15.2.4", + "@next/eslint-plugin-next": "15.2.5", "eslint-config-prettier": "^10.1.1", "eslint-config-turbo": "^2.5.0", "eslint-plugin-import": "^2.31.0", "eslint-plugin-jsx-a11y": "^6.10.2", "eslint-plugin-react": "^7.37.5", "eslint-plugin-react-hooks": "^5.2.0", - "typescript-eslint": "^8.29.0" + "typescript-eslint": "^8.29.1" }, "devDependencies": { "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.23.0", - "typescript": "^5.8.2" + "eslint": "^9.24.0", + "typescript": "^5.8.3" } } diff --git a/tooling/prettier/package.json b/tooling/prettier/package.json index e5d4b97aa..ed449d6d6 100644 --- a/tooling/prettier/package.json +++ b/tooling/prettier/package.json @@ -16,6 +16,6 @@ "devDependencies": { "@homarr/tsconfig": "workspace:^0.1.0", "prettier-plugin-packagejson": "^2.5.10", - "typescript": "^5.8.2" + "typescript": "^5.8.3" } }