From f7ea1b33a0586926230f8522edebd2316acb7b58 Mon Sep 17 00:00:00 2001 From: "homarr-renovate[bot]" <158783068+homarr-renovate[bot]@users.noreply.github.com> Date: Wed, 27 May 2026 17:29:52 +0200 Subject: [PATCH] chore(deps): update mantine monorepo to v9 (#5411) Co-authored-by: Thomas Camlong --- .github/workflows/code-quality.yml | 10 +- .../[locale]/_client-providers/mantine.tsx | 1 + .../app/[locale]/auth/login/_login-form.tsx | 6 +- .../app/[locale]/boards/(content)/_theme.tsx | 1 + .../boards/[name]/settings/_appereance.tsx | 2 +- apps/nextjs/src/app/[locale]/layout.tsx | 2 +- .../secrets/integration-secret-card.tsx | 2 +- .../integration-secret-segmented-control.tsx | 2 +- .../new/_integration-new-form.tsx | 2 +- .../settings/_components/setting-switch.tsx | 2 +- .../manage/tools/logs/level-selection.tsx | 11 +- .../_components/_first-day-of-week.tsx | 2 +- .../board/sections/category-section.tsx | 2 +- .../board/sections/gridstack/use-gridstack.ts | 17 +- e2e/lldap.spec.ts | 2 +- packages/form/package.json | 1 - packages/form/src/index.ts | 5 +- .../forms-collection/src/new-app/_form.tsx | 2 +- packages/ui/src/theme.ts | 1 + packages/widgets/package.json | 2 +- .../_inputs/widget-dynamic-select-input.tsx | 48 +- .../src/_inputs/widget-select-input.tsx | 2 +- packages/widgets/src/downloads/component.tsx | 2 +- packages/widgets/src/firewall/component.tsx | 4 +- .../src/media-requests/stats/component.tsx | 2 +- .../src/media-transcoding/component.tsx | 9 +- .../widgets/src/modals/widget-edit-modal.tsx | 5 +- pnpm-lock.yaml | 991 +++++++++++------- pnpm-workspace.yaml | 24 +- 29 files changed, 707 insertions(+), 455 deletions(-) diff --git a/.github/workflows/code-quality.yml b/.github/workflows/code-quality.yml index 6b08b4e10..40d4ceb08 100644 --- a/.github/workflows/code-quality.yml +++ b/.github/workflows/code-quality.yml @@ -42,14 +42,14 @@ jobs: - name: Get changed files id: changed run: | - FILES=$(git diff --name-only --diff-filter=ACMR origin/${{ github.base_ref }}...HEAD -- '*.ts' '*.tsx' '*.js' '*.jsx' | tr '\n' ' ') - echo "files=$FILES" >> $GITHUB_OUTPUT + git diff --name-only --diff-filter=ACMR origin/${{ github.base_ref }}...HEAD -- '*.ts' '*.tsx' '*.js' '*.jsx' > /tmp/changed-files + echo "count=$(wc -l < /tmp/changed-files | tr -d '[:space:]')" >> $GITHUB_OUTPUT - name: Auto-fix lint + format - if: steps.changed.outputs.files != '' + if: steps.changed.outputs.count != '0' run: | - pnpm exec oxlint --fix ${{ steps.changed.outputs.files }} || true - pnpm exec oxfmt --write ${{ steps.changed.outputs.files }} + xargs -r -a /tmp/changed-files pnpm exec oxlint --fix || true + xargs -r -a /tmp/changed-files pnpm exec oxfmt --write - name: Commit fixes uses: stefanzweifel/git-auto-commit-action@v5 diff --git a/apps/nextjs/src/app/[locale]/_client-providers/mantine.tsx b/apps/nextjs/src/app/[locale]/_client-providers/mantine.tsx index d81b828f3..dc240d764 100644 --- a/apps/nextjs/src/app/[locale]/_client-providers/mantine.tsx +++ b/apps/nextjs/src/app/[locale]/_client-providers/mantine.tsx @@ -23,6 +23,7 @@ export const CustomMantineProvider = ({ theme={createTheme({ primaryColor: "red", autoContrast: true, + defaultRadius: "sm", })} > {children} 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 71d249cf5..8d36d1e79 100644 --- a/apps/nextjs/src/app/[locale]/auth/login/_login-form.tsx +++ b/apps/nextjs/src/app/[locale]/auth/login/_login-form.tsx @@ -9,7 +9,7 @@ import { z } from "zod/v4"; import { signIn } from "@homarr/auth/client"; import { revalidatePathActionAsync } from "@homarr/common/client"; -import type { useForm } from "@homarr/form"; +import type { UseFormReturnType } from "@homarr/form"; import { useZodForm } from "@homarr/form"; import { showErrorNotification, showSuccessNotification } from "@homarr/notifications"; import { useScopedI18n } from "@homarr/translation/client"; @@ -162,7 +162,7 @@ export const LoginForm = ({ providers, oidcClientName, isOidcAutoLoginEnabled, c interface SubmitButtonProps { isPending: boolean; - form: ReturnType FormType>>; + form: UseFormReturnType; provider: "credentials" | "ldap"; } @@ -198,7 +198,7 @@ const PasswordForgottenCollapse = ({ username }: PasswordForgottenCollapseProps) {tForgotPassword("label")} - + {tForgotPassword("description")} diff --git a/apps/nextjs/src/app/[locale]/boards/(content)/_theme.tsx b/apps/nextjs/src/app/[locale]/boards/(content)/_theme.tsx index 27f3e9152..8fa031ad0 100644 --- a/apps/nextjs/src/app/[locale]/boards/(content)/_theme.tsx +++ b/apps/nextjs/src/app/[locale]/boards/(content)/_theme.tsx @@ -24,6 +24,7 @@ export const BoardMantineProvider = ({ }, primaryColor: "primaryColor", autoContrast: true, + defaultRadius: "sm", fontSizes: { "2xl": rem(24), "3xl": rem(28), 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 95b3602e6..4af4af15f 100644 --- a/apps/nextjs/src/app/[locale]/boards/[name]/settings/_appereance.tsx +++ b/apps/nextjs/src/app/[locale]/boards/[name]/settings/_appereance.tsx @@ -83,7 +83,7 @@ export const ColorSettingsContent = ({ board }: Props) => { {showPreview ? t("common.preview.hide") : t("common.preview.show")} - + diff --git a/apps/nextjs/src/app/[locale]/layout.tsx b/apps/nextjs/src/app/[locale]/layout.tsx index 5449e1252..9342e0d30 100644 --- a/apps/nextjs/src/app/[locale]/layout.tsx +++ b/apps/nextjs/src/app/[locale]/layout.tsx @@ -142,7 +142,7 @@ export default async function Layout(props: { - + {props.children} diff --git a/apps/nextjs/src/app/[locale]/manage/integrations/_components/secrets/integration-secret-card.tsx b/apps/nextjs/src/app/[locale]/manage/integrations/_components/secrets/integration-secret-card.tsx index 06c4baff3..cc6a0a752 100644 --- a/apps/nextjs/src/app/[locale]/manage/integrations/_components/secrets/integration-secret-card.tsx +++ b/apps/nextjs/src/app/[locale]/manage/integrations/_components/secrets/integration-secret-card.tsx @@ -79,7 +79,7 @@ export const SecretCard = ({ secret, children, onCancel }: SecretCardProps) => { - {children} + {children} ); diff --git a/apps/nextjs/src/app/[locale]/manage/integrations/_components/secrets/integration-secret-segmented-control.tsx b/apps/nextjs/src/app/[locale]/manage/integrations/_components/secrets/integration-secret-segmented-control.tsx index e524b3870..9272e47c2 100644 --- a/apps/nextjs/src/app/[locale]/manage/integrations/_components/secrets/integration-secret-segmented-control.tsx +++ b/apps/nextjs/src/app/[locale]/manage/integrations/_components/secrets/integration-secret-segmented-control.tsx @@ -12,7 +12,7 @@ interface FormType { interface SecretKindsSegmentedControlProps { defaultKinds?: IntegrationSecretKind[]; secretKinds: IntegrationSecretKind[][]; - form: UseFormReturnType TFormType>; + form: UseFormReturnType; } export const SecretKindsSegmentedControl = ({ 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 016b9336c..b7fbf3291 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 @@ -226,7 +226,7 @@ const AppForm = ({ form, canCreateApps }: { form: UseFormReturnType; c description={t("integration.field.createApp.description")} /> - +
{canCreateApps && ( diff --git a/apps/nextjs/src/app/[locale]/manage/settings/_components/setting-switch.tsx b/apps/nextjs/src/app/[locale]/manage/settings/_components/setting-switch.tsx index 293a8fa96..adec086ad 100644 --- a/apps/nextjs/src/app/[locale]/manage/settings/_components/setting-switch.tsx +++ b/apps/nextjs/src/app/[locale]/manage/settings/_components/setting-switch.tsx @@ -15,7 +15,7 @@ export const SwitchSetting = >({ disabled, }: { form: Modify< - UseFormReturnType TFormValue>, + UseFormReturnType, { setFieldValue: (key: keyof TFormValue, value: (previous: boolean) => boolean) => void; } diff --git a/apps/nextjs/src/app/[locale]/manage/tools/logs/level-selection.tsx b/apps/nextjs/src/app/[locale]/manage/tools/logs/level-selection.tsx index 71846ca02..243521471 100644 --- a/apps/nextjs/src/app/[locale]/manage/tools/logs/level-selection.tsx +++ b/apps/nextjs/src/app/[locale]/manage/tools/logs/level-selection.tsx @@ -2,12 +2,14 @@ import { Select } from "@mantine/core"; -import type { LogLevel } from "@homarr/core/infrastructure/logs/constants"; import { logLevelConfiguration, logLevels } from "@homarr/core/infrastructure/logs/constants"; +import type { LogLevel } from "@homarr/core/infrastructure/logs/constants"; import { useI18n } from "@homarr/translation/client"; import { useLogContext } from "./log-context"; +const levelByValue = Object.fromEntries(logLevels.map((logLevel) => [logLevel, logLevel])) as Record; + export const LogLevelSelection = () => { const { level, setLevel } = useLogContext(); const t = useI18n(); @@ -19,7 +21,12 @@ export const LogLevelSelection = () => { label: `${logLevelConfiguration[level].prefix} ${t(`log.level.option.${level}`)}`, }))} value={level} - onChange={(value) => setLevel(value as LogLevel)} + onChange={(value) => { + const nextLevel = value && levelByValue[value]; + if (nextLevel) { + setLevel(nextLevel); + } + }} checkIconPosition="right" /> ); 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 71bef0737..2bf43a3bc 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 @@ -62,7 +62,7 @@ export const FirstDayOfWeek = ({ user }: FirstDayOfWeekProps) => { return (
- onChange(parseInt(value))}> + onChange(parseInt(nextValue, 10))}> diff --git a/apps/nextjs/src/components/board/sections/category-section.tsx b/apps/nextjs/src/components/board/sections/category-section.tsx index 592b39c68..feedcb964 100644 --- a/apps/nextjs/src/components/board/sections/category-section.tsx +++ b/apps/nextjs/src/components/board/sections/category-section.tsx @@ -62,7 +62,7 @@ export const BoardCategorySection = ({ section }: Props) => { - + diff --git a/apps/nextjs/src/components/board/sections/gridstack/use-gridstack.ts b/apps/nextjs/src/components/board/sections/gridstack/use-gridstack.ts index eda89a8e6..b5e468de6 100644 --- a/apps/nextjs/src/components/board/sections/gridstack/use-gridstack.ts +++ b/apps/nextjs/src/components/board/sections/gridstack/use-gridstack.ts @@ -1,6 +1,6 @@ -import type { RefObject } from "react"; +import type { Ref, RefObject } from "react"; import { createRef, useCallback, useEffect, useRef } from "react"; -import { useElementSize } from "@mantine/hooks"; +import { useElementSize, useMergedRef } from "@mantine/hooks"; import { useCurrentLayout, useRequiredBoard } from "@homarr/boards/context"; import { useEditMode } from "@homarr/boards/edit-mode"; @@ -13,7 +13,7 @@ import { useSectionActions } from "../section-actions"; import { initializeGridstack } from "./init-gridstack"; export interface UseGridstackRefs { - wrapper: RefObject; + wrapper: Ref; items: RefObject>>; gridstack: RefObject; } @@ -59,8 +59,9 @@ export const useGridstack = (section: Omit, itemIds: string[]) const { moveAndResizeItem, moveItemToSection } = useItemActions(); const { moveAndResizeInnerSection, moveInnerSectionToSection } = useSectionActions(); - // define reference for wrapper - is used to calculate the width of the wrapper - const { ref: wrapperRef, width, height } = useElementSize(); + const wrapperElementRef = useRef(null); + const { ref: measureWrapperRef, width, height } = useElementSize(); + const wrapperRef = useMergedRef(measureWrapperRef, wrapperElementRef); // references to the diffrent items contained in the gridstack const itemRefs = useRef>>({}); // reference of the gridstack object for modifications after initialization @@ -193,7 +194,7 @@ export const useGridstack = (section: Omit, itemIds: string[]) itemIds, refs: { items: itemRefs, - wrapper: wrapperRef, + wrapper: wrapperElementRef, gridstack: gridRef, }, sectionColumnCount: columnCount, @@ -276,7 +277,7 @@ export const useGridstack = (section: Omit, itemIds: string[]) useCssVariableConfiguration({ columnCount, gridRef, - wrapperRef, + wrapperRef: wrapperElementRef, width, height, isDynamic: section.kind === "dynamic", @@ -293,7 +294,7 @@ export const useGridstack = (section: Omit, itemIds: string[]) interface UseCssVariableConfiguration { gridRef: UseGridstackRefs["gridstack"]; - wrapperRef: UseGridstackRefs["wrapper"]; + wrapperRef: RefObject; width: number; height: number; columnCount: number; diff --git a/e2e/lldap.spec.ts b/e2e/lldap.spec.ts index a7fb2a7ef..f1f07790d 100644 --- a/e2e/lldap.spec.ts +++ b/e2e/lldap.spec.ts @@ -45,7 +45,7 @@ describe("LLDAP authorization", () => { // Act await page.goto(`http://${homarrContainer.getHost()}:${homarrContainer.getMappedPort(7575)}/auth/login`); await page.getByLabel("Username").fill(defaultCredentials.username); - await page.getByLabel("Password").fill(defaultCredentials.password); + await page.locator("#password").fill(defaultCredentials.password); await page.locator("css=button[type='submit']").click(); // Assert diff --git a/packages/form/package.json b/packages/form/package.json index 46c7ad29e..72f2b2ab8 100644 --- a/packages/form/package.json +++ b/packages/form/package.json @@ -26,7 +26,6 @@ "@homarr/translation": "workspace:^0.1.0", "@homarr/validation": "workspace:^0.1.0", "@mantine/form": "catalog:", - "mantine-form-zod-resolver": "catalog:", "zod": "catalog:" }, "devDependencies": { diff --git a/packages/form/src/index.ts b/packages/form/src/index.ts index f1d34f193..af8e4198e 100644 --- a/packages/form/src/index.ts +++ b/packages/form/src/index.ts @@ -1,5 +1,4 @@ -import { useForm } from "@mantine/form"; -import { zod4Resolver } from "mantine-form-zod-resolver"; +import { schemaResolver, useForm } from "@mantine/form"; import type { ZodDiscriminatedUnion, ZodIntersection, ZodObject, ZodPipe } from "zod/v4"; import { z } from "zod/v4"; @@ -34,6 +33,6 @@ export const useZodForm = < ...options, validateInputOnBlur: true, validateInputOnChange: true, - validate: zod4Resolver(schema), + validate: schemaResolver(schema, { sync: true }), }); }; diff --git a/packages/forms-collection/src/new-app/_form.tsx b/packages/forms-collection/src/new-app/_form.tsx index 82f5a7caa..05c7e3f6f 100644 --- a/packages/forms-collection/src/new-app/_form.tsx +++ b/packages/forms-collection/src/new-app/_form.tsx @@ -114,7 +114,7 @@ export const AppForm = ({ mt="md" /> - + diff --git a/packages/ui/src/theme.ts b/packages/ui/src/theme.ts index e1e928d57..7439ae440 100644 --- a/packages/ui/src/theme.ts +++ b/packages/ui/src/theme.ts @@ -9,4 +9,5 @@ export const theme = createTheme({ secondaryColor, }, primaryColor: "primaryColor", + defaultRadius: "sm", }); diff --git a/packages/widgets/package.json b/packages/widgets/package.json index 6be5b29be..8b8444b3d 100644 --- a/packages/widgets/package.json +++ b/packages/widgets/package.json @@ -49,6 +49,7 @@ "@homarr/validation": "workspace:^0.1.0", "@mantine/charts": "catalog:", "@mantine/core": "catalog:", + "@mantine/form": "catalog:", "@mantine/hooks": "catalog:", "@tabler/icons-react": "catalog:", "@tiptap/extension-color": "catalog:", @@ -69,7 +70,6 @@ "@tiptap/starter-kit": "catalog:", "clsx": "catalog:", "dayjs": "catalog:", - "mantine-form-zod-resolver": "catalog:", "mantine-react-table": "catalog:", "next": "catalog:", "react": "catalog:", diff --git a/packages/widgets/src/_inputs/widget-dynamic-select-input.tsx b/packages/widgets/src/_inputs/widget-dynamic-select-input.tsx index 39b70b325..de8ef5021 100644 --- a/packages/widgets/src/_inputs/widget-dynamic-select-input.tsx +++ b/packages/widgets/src/_inputs/widget-dynamic-select-input.tsx @@ -25,9 +25,22 @@ export const WidgetDynamicSelectInput = ({ property, kind, options }: CommonWidg const [search, setSearch] = useState(""); const [debouncedSearch] = useDebouncedValue(search, 300); const { isPending, options: selectOptions } = options.useOptions(debouncedSearch, form.values.integrationIds); - const value = inputProps.value as DynamicSelectOption | null; + const currentOption = inputProps.value as DynamicSelectOption | null; const onChange = inputProps.onChange as (value: DynamicSelectOption | null) => void; + const getLabelForValue = (selectedValue: string) => { + const matched = selectOptions.find((option) => + typeof option === "string" ? option === selectedValue : option.value === selectedValue, + ); + if (!matched) { + return selectedValue; + } + if (typeof matched === "string") { + return matched; + } + return translateIfNecessary(t, matched.label) ?? selectedValue; + }; + return (