diff --git a/apps/nextjs/src/app/[locale]/_client-providers/mantine.tsx b/apps/nextjs/src/app/[locale]/_client-providers/mantine.tsx
index e5e867815..b5b4a5b34 100644
--- a/apps/nextjs/src/app/[locale]/_client-providers/mantine.tsx
+++ b/apps/nextjs/src/app/[locale]/_client-providers/mantine.tsx
@@ -16,7 +16,7 @@ export const CustomMantineProvider = ({ children }: PropsWithChildren) => {
   return (
     <DirectionProvider>
       <MantineProvider
-        defaultColorScheme="auto"
+        defaultColorScheme="dark"
         colorSchemeManager={manager}
         theme={createTheme({
           primaryColor: "red",
@@ -62,6 +62,7 @@ function useColorSchemeManager(): MantineColorSchemeManager {
     },
 
     set: (value) => {
+      if (value === "auto") return;
       try {
         if (session) {
           mutateColorScheme({ colorScheme: value });
diff --git a/apps/nextjs/src/app/[locale]/boards/(content)/_context.tsx b/apps/nextjs/src/app/[locale]/boards/(content)/_context.tsx
index 346baff75..808759af1 100644
--- a/apps/nextjs/src/app/[locale]/boards/(content)/_context.tsx
+++ b/apps/nextjs/src/app/[locale]/boards/(content)/_context.tsx
@@ -49,6 +49,7 @@ export const BoardProvider = ({
 
   useEffect(() => {
     setReadySections((previous) => previous.filter((id) => data.sections.some((section) => section.id === id)));
+    // eslint-disable-next-line react-hooks/exhaustive-deps
   }, [data.sections.length, setReadySections]);
 
   const markAsReady = useCallback((id: string) => {
diff --git a/apps/nextjs/src/app/[locale]/layout.tsx b/apps/nextjs/src/app/[locale]/layout.tsx
index d11e50b33..22888ea0b 100644
--- a/apps/nextjs/src/app/[locale]/layout.tsx
+++ b/apps/nextjs/src/app/[locale]/layout.tsx
@@ -77,7 +77,15 @@ export default async function Layout(props: { children: React.ReactNode; params:
 
   return (
     // Instead of ColorSchemScript we use data-mantine-color-scheme to prevent flickering
-    <html lang="en" dir={direction} data-mantine-color-scheme={colorScheme} suppressHydrationWarning>
+    <html
+      lang="en"
+      dir={direction}
+      data-mantine-color-scheme={colorScheme}
+      style={{
+        backgroundColor: colorScheme === "dark" ? "#242424" : "#fff",
+      }}
+      suppressHydrationWarning
+    >
       <head>
         <Analytics />
         <SearchEngineOptimization />
@@ -93,5 +101,5 @@ export default async function Layout(props: { children: React.ReactNode; params:
 }
 
 const getColorScheme = () => {
-  return cookies().get("homarr-color-scheme")?.value ?? "light";
+  return cookies().get("homarr-color-scheme")?.value ?? "dark";
 };
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 25eacf9b9..791be2938 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
@@ -9,7 +9,7 @@ import { IconInfoCircle } from "@tabler/icons-react";
 import { clientApi } from "@homarr/api/client";
 import { revalidatePathActionAsync } from "@homarr/common/client";
 import type { IntegrationKind, IntegrationSecretKind } from "@homarr/definitions";
-import { getAllSecretKindOptions } from "@homarr/definitions";
+import { getAllSecretKindOptions, getIntegrationName } from "@homarr/definitions";
 import type { UseFormReturnType } from "@homarr/form";
 import { useZodForm } from "@homarr/form";
 import { convertIntegrationTestConnectionError } from "@homarr/integrations/client";
@@ -32,7 +32,7 @@ export const NewIntegrationForm = ({ searchParams }: NewIntegrationFormProps) =>
   const router = useRouter();
   const form = useZodForm(validation.integration.create.omit({ kind: true }), {
     initialValues: {
-      name: searchParams.name ?? "",
+      name: searchParams.name ?? getIntegrationName(searchParams.kind),
       url: searchParams.url ?? "",
       secrets: secretKinds[0].map((kind) => ({
         kind,
@@ -81,7 +81,7 @@ export const NewIntegrationForm = ({ searchParams }: NewIntegrationFormProps) =>
   return (
     <form onSubmit={form.onSubmit((value) => void handleSubmitAsync(value))}>
       <Stack>
-        <TextInput withAsterisk label={t("integration.field.name.label")} {...form.getInputProps("name")} />
+        <TextInput withAsterisk label={t("integration.field.name.label")} autoFocus {...form.getInputProps("name")} />
 
         <TextInput withAsterisk label={t("integration.field.url.label")} {...form.getInputProps("url")} />
 
diff --git a/apps/nextjs/src/app/[locale]/manage/tools/api/components/api-keys.tsx b/apps/nextjs/src/app/[locale]/manage/tools/api/components/api-keys.tsx
index 86503427c..71a0efb1b 100644
--- a/apps/nextjs/src/app/[locale]/manage/tools/api/components/api-keys.tsx
+++ b/apps/nextjs/src/app/[locale]/manage/tools/api/components/api-keys.tsx
@@ -47,7 +47,7 @@ export const ApiKeysManagement = ({ apiKeys }: ApiKeysManagementProps) => {
         ),
       },
     ],
-    [],
+    [t],
   );
 
   const table = useMantineReactTable({
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 0099dcbd8..b2d5ab87e 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
@@ -61,7 +61,7 @@ export const UserProfileForm = ({ user }: UserProfileFormProps) => {
         id: user.id,
       });
     },
-    [user.id, mutate],
+    [isProviderCredentials, mutate, user.id],
   );
 
   return (
diff --git a/apps/nextjs/src/components/board/items/item-move-modal.tsx b/apps/nextjs/src/components/board/items/item-move-modal.tsx
index 64df4424b..b04a80195 100644
--- a/apps/nextjs/src/components/board/items/item-move-modal.tsx
+++ b/apps/nextjs/src/components/board/items/item-move-modal.tsx
@@ -8,7 +8,6 @@ import { useI18n, useScopedI18n } from "@homarr/translation/client";
 import { z } from "@homarr/validation";
 
 import type { Item } from "~/app/[locale]/boards/_types";
-import { useItemActions } from "./item-actions";
 
 interface InnerProps {
   gridStack: GridStack;
@@ -21,7 +20,6 @@ export const ItemMoveModal = createModal<InnerProps>(({ actions, innerProps }) =
   const t = useI18n();
   // Keep track of the maximum width based on the x offset
   const maxWidthRef = useRef(innerProps.columnCount - innerProps.item.xOffset);
-  const { moveAndResizeItem } = useItemActions();
   const form = useZodForm(
     z.object({
       xOffset: z
@@ -62,7 +60,7 @@ export const ItemMoveModal = createModal<InnerProps>(({ actions, innerProps }) =
       });
       actions.closeModal();
     },
-    [moveAndResizeItem],
+    [actions, innerProps.gridStack, innerProps.item.id],
   );
 
   return (
diff --git a/apps/nextjs/src/components/board/sections/gridstack/gridstack-item.tsx b/apps/nextjs/src/components/board/sections/gridstack/gridstack-item.tsx
index 554a376fa..beff12f66 100644
--- a/apps/nextjs/src/components/board/sections/gridstack/gridstack-item.tsx
+++ b/apps/nextjs/src/components/board/sections/gridstack/gridstack-item.tsx
@@ -39,7 +39,7 @@ export const GridStackItem = ({
     if (type !== "section") return;
     innerRef.current.gridstackNode.minW = minWidth;
     innerRef.current.gridstackNode.minH = minHeight;
-  }, [minWidth, minHeight, innerRef]);
+  }, [minWidth, minHeight, innerRef, type]);
 
   return (
     <Box
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 636065131..5c3fb207b 100644
--- a/apps/nextjs/src/components/board/sections/gridstack/use-gridstack.ts
+++ b/apps/nextjs/src/components/board/sections/gridstack/use-gridstack.ts
@@ -215,6 +215,7 @@ export const useGridstack = (section: Omit<Section, "items">, itemIds: string[])
     }
 
     // Only run this effect when the section items change
+    // eslint-disable-next-line react-hooks/exhaustive-deps
   }, [itemIds.length, columnCount]);
 
   /**
diff --git a/apps/nextjs/src/components/user-avatar-menu.tsx b/apps/nextjs/src/components/user-avatar-menu.tsx
index 9a03b4200..1dafdce25 100644
--- a/apps/nextjs/src/components/user-avatar-menu.tsx
+++ b/apps/nextjs/src/components/user-avatar-menu.tsx
@@ -58,7 +58,7 @@ export const UserAvatarMenu = ({ children }: UserAvatarMenuProps) => {
         router.refresh();
       },
     });
-  }, [openModal, router]);
+  }, [logoutUrl, openModal, router]);
 
   return (
     <Menu width={300} withArrow withinPortal>
diff --git a/package.json b/package.json
index 961682993..35e5bc009 100644
--- a/package.json
+++ b/package.json
@@ -40,7 +40,7 @@
     "vite-tsconfig-paths": "^5.0.1",
     "vitest": "^2.1.3"
   },
-  "packageManager": "pnpm@9.12.1",
+  "packageManager": "pnpm@9.12.2",
   "engines": {
     "node": ">=20.18.0"
   },
diff --git a/packages/auth/callbacks.ts b/packages/auth/callbacks.ts
index 6a381f57a..d5fac0b7a 100644
--- a/packages/auth/callbacks.ts
+++ b/packages/auth/callbacks.ts
@@ -36,7 +36,7 @@ export const createSessionAsync = async (
       ...user,
       email: user.email ?? "",
       permissions: await getCurrentUserPermissionsAsync(db, user.id),
-      colorScheme: "auto",
+      colorScheme: "dark",
     },
   } as Session;
 };
diff --git a/packages/db/schema/mysql.ts b/packages/db/schema/mysql.ts
index ec92ee53b..510ddaf89 100644
--- a/packages/db/schema/mysql.ts
+++ b/packages/db/schema/mysql.ts
@@ -43,7 +43,7 @@ export const users = mysqlTable("user", {
   homeBoardId: varchar("homeBoardId", { length: 64 }).references((): AnyMySqlColumn => boards.id, {
     onDelete: "set null",
   }),
-  colorScheme: varchar("colorScheme", { length: 5 }).$type<ColorScheme>().default("auto").notNull(),
+  colorScheme: varchar("colorScheme", { length: 5 }).$type<ColorScheme>().default("dark").notNull(),
   firstDayOfWeek: tinyint("firstDayOfWeek").$type<DayOfWeek>().default(1).notNull(), // Defaults to Monday
   pingIconsEnabled: boolean("pingIconsEnabled").default(false).notNull(),
 });
diff --git a/packages/db/schema/sqlite.ts b/packages/db/schema/sqlite.ts
index 2b593b9d5..f0d1a52e4 100644
--- a/packages/db/schema/sqlite.ts
+++ b/packages/db/schema/sqlite.ts
@@ -44,7 +44,7 @@ export const users = sqliteTable("user", {
   homeBoardId: text("homeBoardId").references((): AnySQLiteColumn => boards.id, {
     onDelete: "set null",
   }),
-  colorScheme: text("colorScheme").$type<ColorScheme>().default("auto").notNull(),
+  colorScheme: text("colorScheme").$type<ColorScheme>().default("dark").notNull(),
   firstDayOfWeek: int("firstDayOfWeek").$type<DayOfWeek>().default(1).notNull(), // Defaults to Monday
   pingIconsEnabled: int("pingIconsEnabled", { mode: "boolean" }).default(false).notNull(),
 });
diff --git a/packages/definitions/src/user.ts b/packages/definitions/src/user.ts
index 28f24ae7b..77d8d4138 100644
--- a/packages/definitions/src/user.ts
+++ b/packages/definitions/src/user.ts
@@ -1,2 +1,2 @@
-export const colorSchemes = ["light", "dark", "auto"] as const;
+export const colorSchemes = ["light", "dark"] as const;
 export type ColorScheme = (typeof colorSchemes)[number];
diff --git a/packages/modals/src/confirm-modal.tsx b/packages/modals/src/confirm-modal.tsx
index 752506cb8..9f3f2b4ac 100644
--- a/packages/modals/src/confirm-modal.tsx
+++ b/packages/modals/src/confirm-modal.tsx
@@ -53,7 +53,7 @@ export const ConfirmModal = createModal<Omit<ConfirmModalProps, "title">>(({ act
         actions.closeModal();
       }
     },
-    [cancelProps?.onClick, onCancel, actions.closeModal],
+    [cancelProps, onCancel, closeOnCancel, actions],
   );
 
   const handleConfirm = useCallback(
@@ -73,7 +73,7 @@ export const ConfirmModal = createModal<Omit<ConfirmModalProps, "title">>(({ act
       }
       setLoading(false);
     },
-    [confirmProps?.onClick, onConfirm, actions.closeModal],
+    [confirmProps, onConfirm, closeOnConfirm, actions],
   );
 
   return (
diff --git a/packages/modals/src/index.tsx b/packages/modals/src/index.tsx
index f3c9e1386..02bc4cff4 100644
--- a/packages/modals/src/index.tsx
+++ b/packages/modals/src/index.tsx
@@ -38,7 +38,7 @@ export const ModalProvider = ({ children }: PropsWithChildren) => {
     (id: string, canceled?: boolean) => {
       dispatch({ type: "CLOSE", modalId: id, canceled });
     },
-    [stateRef, dispatch],
+    [dispatch],
   );
 
   const openModalInner: ModalContextProps["openModalInner"] = useCallback(
@@ -63,10 +63,7 @@ export const ModalProvider = ({ children }: PropsWithChildren) => {
     [dispatch],
   );
 
-  const handleCloseModal = useCallback(
-    () => state.current && closeModal(state.current.id),
-    [closeModal, state.current?.id],
-  );
+  const handleCloseModal = useCallback(() => state.current && closeModal(state.current.id), [closeModal, state]);
 
   const activeModals = state.modals.filter((modal) => modal.id === state.current?.id || modal.props.keepMounted);
 
diff --git a/packages/spotlight/src/components/actions/items/children-action-item.tsx b/packages/spotlight/src/components/actions/items/children-action-item.tsx
index c36fb3c65..0b070b147 100644
--- a/packages/spotlight/src/components/actions/items/children-action-item.tsx
+++ b/packages/spotlight/src/components/actions/items/children-action-item.tsx
@@ -24,7 +24,7 @@ export const ChildrenActionItem = ({ childrenOptions, action, query }: ChildrenA
 
   return (
     <Spotlight.Action renderRoot={renderRoot} onClick={onClick} className={classes.spotlightAction}>
-      <action.component {...childrenOptions.option} />
+      <action.Component {...childrenOptions.option} />
     </Spotlight.Action>
   );
 };
diff --git a/packages/spotlight/src/components/actions/items/group-action-item.tsx b/packages/spotlight/src/components/actions/items/group-action-item.tsx
index 1b2ebe1c5..6dd70c5ff 100644
--- a/packages/spotlight/src/components/actions/items/group-action-item.tsx
+++ b/packages/spotlight/src/components/actions/items/group-action-item.tsx
@@ -48,7 +48,7 @@ export const SpotlightGroupActionItem = <TOption extends Record<string, unknown>
       closeSpotlightOnTrigger={interaction.type !== "mode" && interaction.type !== "children"}
       className={classes.spotlightAction}
     >
-      <group.component {...option} />
+      <group.Component {...option} />
     </Spotlight.Action>
   );
 };
diff --git a/packages/spotlight/src/components/spotlight.tsx b/packages/spotlight/src/components/spotlight.tsx
index f84af4add..2de76db8c 100644
--- a/packages/spotlight/src/components/spotlight.tsx
+++ b/packages/spotlight/src/components/spotlight.tsx
@@ -92,7 +92,7 @@ export const Spotlight = () => {
 
       {childrenOptions ? (
         <Group>
-          <childrenOptions.detailComponent options={childrenOptions.option as never} />
+          <childrenOptions.DetailComponent options={childrenOptions.option as never} />
         </Group>
       ) : null}
 
diff --git a/packages/spotlight/src/lib/children.ts b/packages/spotlight/src/lib/children.ts
index 1a792a2b6..69b3c00b1 100644
--- a/packages/spotlight/src/lib/children.ts
+++ b/packages/spotlight/src/lib/children.ts
@@ -3,13 +3,13 @@ import type { ReactNode } from "react";
 import type { inferSearchInteractionDefinition } from "./interaction";
 
 export interface CreateChildrenOptionsProps<TParentOptions extends Record<string, unknown>> {
-  detailComponent: ({ options }: { options: TParentOptions }) => ReactNode;
+  DetailComponent: ({ options }: { options: TParentOptions }) => ReactNode;
   useActions: (options: TParentOptions, query: string) => ChildrenAction<TParentOptions>[];
 }
 
 export interface ChildrenAction<TParentOptions extends Record<string, unknown>> {
   key: string;
-  component: (option: TParentOptions) => JSX.Element;
+  Component: (option: TParentOptions) => JSX.Element;
   useInteraction: (option: TParentOptions, query: string) => inferSearchInteractionDefinition<"link" | "javaScript">;
   hide?: boolean | ((option: TParentOptions) => boolean);
 }
diff --git a/packages/spotlight/src/lib/group.ts b/packages/spotlight/src/lib/group.ts
index dda1fa7a8..900990e4a 100644
--- a/packages/spotlight/src/lib/group.ts
+++ b/packages/spotlight/src/lib/group.ts
@@ -8,7 +8,7 @@ type CommonSearchGroup<TOption extends Record<string, unknown>, TOptionProps ext
   // key path is used to define the path to a unique key in the option object
   keyPath: keyof TOption;
   title: stringOrTranslation;
-  component: (option: TOption) => JSX.Element;
+  Component: (option: TOption) => JSX.Element;
   useInteraction: (option: TOption, query: string) => inferSearchInteractionDefinition<SearchInteraction>;
   onKeyDown?: (
     event: KeyboardEvent,
diff --git a/packages/spotlight/src/lib/interaction.ts b/packages/spotlight/src/lib/interaction.ts
index 1528a39ca..b917b3bcd 100644
--- a/packages/spotlight/src/lib/interaction.ts
+++ b/packages/spotlight/src/lib/interaction.ts
@@ -16,7 +16,7 @@ const searchInteractions = [
     // eslint-disable-next-line @typescript-eslint/no-explicit-any
     useActions: CreateChildrenOptionsProps<any>["useActions"];
     // eslint-disable-next-line @typescript-eslint/no-explicit-any
-    detailComponent: CreateChildrenOptionsProps<any>["detailComponent"];
+    DetailComponent: CreateChildrenOptionsProps<any>["DetailComponent"];
     // eslint-disable-next-line @typescript-eslint/no-explicit-any
     option: any;
   }>(),
diff --git a/packages/spotlight/src/modes/app-integration-board/apps-search-group.tsx b/packages/spotlight/src/modes/app-integration-board/apps-search-group.tsx
index 5d2dc98a6..477842ac2 100644
--- a/packages/spotlight/src/modes/app-integration-board/apps-search-group.tsx
+++ b/packages/spotlight/src/modes/app-integration-board/apps-search-group.tsx
@@ -16,7 +16,7 @@ const appChildrenOptions = createChildrenOptions<App>({
   useActions: () => [
     {
       key: "open",
-      component: () => {
+      Component: () => {
         const t = useI18n();
 
         return (
@@ -34,7 +34,7 @@ const appChildrenOptions = createChildrenOptions<App>({
     },
     {
       key: "edit",
-      component: () => {
+      Component: () => {
         const t = useI18n();
 
         return (
@@ -47,7 +47,7 @@ const appChildrenOptions = createChildrenOptions<App>({
       useInteraction: interaction.link(({ id }) => ({ href: `/manage/apps/edit/${id}` })),
     },
   ],
-  detailComponent: ({ options }) => {
+  DetailComponent: ({ options }) => {
     const t = useI18n();
 
     return (
@@ -75,7 +75,7 @@ const appChildrenOptions = createChildrenOptions<App>({
 export const appsSearchGroup = createGroup<App>({
   keyPath: "id",
   title: (t) => t("search.mode.appIntegrationBoard.group.app.title"),
-  component: (app) => (
+  Component: (app) => (
     <Group px="md" py="sm">
       <Avatar
         size="sm"
diff --git a/packages/spotlight/src/modes/app-integration-board/boards-search-group.tsx b/packages/spotlight/src/modes/app-integration-board/boards-search-group.tsx
index 089fb732c..ca201b5bc 100644
--- a/packages/spotlight/src/modes/app-integration-board/boards-search-group.tsx
+++ b/packages/spotlight/src/modes/app-integration-board/boards-search-group.tsx
@@ -23,7 +23,7 @@ const boardChildrenOptions = createChildrenOptions<Board>({
     const actions: (ChildrenAction<Board> & { hidden?: boolean })[] = [
       {
         key: "open",
-        component: () => {
+        Component: () => {
           const t = useI18n();
 
           return (
@@ -37,7 +37,7 @@ const boardChildrenOptions = createChildrenOptions<Board>({
       },
       {
         key: "homeBoard",
-        component: () => {
+        Component: () => {
           const t = useI18n();
 
           return (
@@ -61,7 +61,7 @@ const boardChildrenOptions = createChildrenOptions<Board>({
       },
       {
         key: "settings",
-        component: () => {
+        Component: () => {
           const t = useI18n();
 
           return (
@@ -78,7 +78,7 @@ const boardChildrenOptions = createChildrenOptions<Board>({
 
     return actions;
   },
-  detailComponent: ({ options: board }) => {
+  DetailComponent: ({ options: board }) => {
     const t = useI18n();
 
     return (
@@ -102,7 +102,7 @@ const boardChildrenOptions = createChildrenOptions<Board>({
 export const boardsSearchGroup = createGroup<Board>({
   keyPath: "id",
   title: "Boards",
-  component: (board) => (
+  Component: (board) => (
     <Group px="md" py="sm">
       {board.logoImageUrl ? (
         <img src={board.logoImageUrl} alt={board.name} width={24} height={24} />
diff --git a/packages/spotlight/src/modes/app-integration-board/integrations-search-group.tsx b/packages/spotlight/src/modes/app-integration-board/integrations-search-group.tsx
index 55fd14eca..28926a165 100644
--- a/packages/spotlight/src/modes/app-integration-board/integrations-search-group.tsx
+++ b/packages/spotlight/src/modes/app-integration-board/integrations-search-group.tsx
@@ -10,7 +10,7 @@ import { interaction } from "../../lib/interaction";
 export const integrationsSearchGroup = createGroup<{ id: string; kind: IntegrationKind; name: string }>({
   keyPath: "id",
   title: (t) => t("search.mode.appIntegrationBoard.group.integration.title"),
-  component: (integration) => (
+  Component: (integration) => (
     <Group px="md" py="sm">
       <IntegrationAvatar size="sm" kind={integration.kind} />
 
diff --git a/packages/spotlight/src/modes/command/children/language.tsx b/packages/spotlight/src/modes/command/children/language.tsx
index 7a248275a..848139b68 100644
--- a/packages/spotlight/src/modes/command/children/language.tsx
+++ b/packages/spotlight/src/modes/command/children/language.tsx
@@ -30,7 +30,7 @@ export const languageChildrenOptions = createChildrenOptions<Record<string, unkn
       )
       .map(({ localeKey, attributes }) => ({
         key: localeKey,
-        component() {
+        Component() {
           return (
             <Group mx="md" my="sm" wrap="nowrap" justify="space-between" w="100%">
               <Group wrap="nowrap">
@@ -53,7 +53,7 @@ export const languageChildrenOptions = createChildrenOptions<Record<string, unkn
         },
       }));
   },
-  detailComponent: () => {
+  DetailComponent: () => {
     const t = useI18n();
 
     return (
diff --git a/packages/spotlight/src/modes/command/children/new-integration.tsx b/packages/spotlight/src/modes/command/children/new-integration.tsx
index d70a719f3..aebb6ede1 100644
--- a/packages/spotlight/src/modes/command/children/new-integration.tsx
+++ b/packages/spotlight/src/modes/command/children/new-integration.tsx
@@ -20,7 +20,7 @@ export const newIntegrationChildrenOptions = createChildrenOptions<Record<string
       )
       .map(([kind, integrationDef]) => ({
         key: kind,
-        component() {
+        Component() {
           return (
             <Group mx="md" my="sm" wrap="nowrap" w="100%">
               <IntegrationAvatar kind={kind} size="sm" />
@@ -31,7 +31,7 @@ export const newIntegrationChildrenOptions = createChildrenOptions<Record<string
         useInteraction: interaction.link(() => ({ href: `/manage/integrations/new?kind=${kind}` })),
       }));
   },
-  detailComponent() {
+  DetailComponent() {
     const t = useI18n();
 
     return (
diff --git a/packages/spotlight/src/modes/command/index.tsx b/packages/spotlight/src/modes/command/index.tsx
index 240fd13b5..88f208104 100644
--- a/packages/spotlight/src/modes/command/index.tsx
+++ b/packages/spotlight/src/modes/command/index.tsx
@@ -44,7 +44,7 @@ export const commandMode = {
       keyPath: "commandKey",
       title: "Global commands",
       useInteraction: (option, query) => option.useInteraction(option, query),
-      component: ({ icon: Icon, name }) => (
+      Component: ({ icon: Icon, name }) => (
         <Group px="md" py="sm">
           <Icon stroke={1.5} />
           <Text>{name}</Text>
diff --git a/packages/spotlight/src/modes/external/search-engines-search-group.tsx b/packages/spotlight/src/modes/external/search-engines-search-group.tsx
index 4c76532e9..fd7563207 100644
--- a/packages/spotlight/src/modes/external/search-engines-search-group.tsx
+++ b/packages/spotlight/src/modes/external/search-engines-search-group.tsx
@@ -15,7 +15,7 @@ export const searchEnginesChildrenOptions = createChildrenOptions<SearchEngine>(
   useActions: () => [
     {
       key: "search",
-      component: ({ name }) => {
+      Component: ({ name }) => {
         const tChildren = useScopedI18n("search.mode.external.group.searchEngine.children");
 
         return (
@@ -30,7 +30,7 @@ export const searchEnginesChildrenOptions = createChildrenOptions<SearchEngine>(
       })),
     },
   ],
-  detailComponent({ options }) {
+  DetailComponent({ options }) {
     const tChildren = useScopedI18n("search.mode.external.group.searchEngine.children");
     return (
       <Stack mx="md" my="sm">
@@ -47,7 +47,7 @@ export const searchEnginesChildrenOptions = createChildrenOptions<SearchEngine>(
 export const searchEnginesSearchGroups = createGroup<SearchEngine>({
   keyPath: "short",
   title: (t) => t("search.mode.external.group.searchEngine.title"),
-  component: ({ iconUrl, name, short, description }) => {
+  Component: ({ iconUrl, name, short, description }) => {
     return (
       <Group w="100%" wrap="nowrap" justify="space-between" align="center" px="md" py="xs">
         <Group wrap="nowrap">
diff --git a/packages/spotlight/src/modes/index.tsx b/packages/spotlight/src/modes/index.tsx
index 077e8fa11..afb613e74 100644
--- a/packages/spotlight/src/modes/index.tsx
+++ b/packages/spotlight/src/modes/index.tsx
@@ -22,7 +22,7 @@ const helpMode = {
       keyPath: "character",
       title: (t) => t("search.mode.help.group.mode.title"),
       options: searchModesWithoutHelp.map(({ character, modeKey }) => ({ character, modeKey })),
-      component: ({ modeKey, character }) => {
+      Component: ({ modeKey, character }) => {
         const t = useScopedI18n(`search.mode.${modeKey}`);
 
         return (
@@ -59,7 +59,7 @@ const helpMode = {
           },
         ];
       },
-      component: (props) => (
+      Component: (props) => (
         <Group px="md" py="xs" w="100%" wrap="nowrap" align="center">
           <props.icon />
           <Text>{props.label}</Text>
diff --git a/packages/spotlight/src/modes/page/pages-search-group.tsx b/packages/spotlight/src/modes/page/pages-search-group.tsx
index e0b268a12..698f6166c 100644
--- a/packages/spotlight/src/modes/page/pages-search-group.tsx
+++ b/packages/spotlight/src/modes/page/pages-search-group.tsx
@@ -29,7 +29,7 @@ export const pagesSearchGroup = createGroup<{
 }>({
   keyPath: "path",
   title: (t) => t("search.mode.page.group.page.title"),
-  component: ({ name, icon: Icon }) => (
+  Component: ({ name, icon: Icon }) => (
     <Group px="md" py="sm">
       <Icon stroke={1.5} />
       <Text>{name}</Text>
diff --git a/packages/spotlight/src/modes/user-group/groups-search-group.tsx b/packages/spotlight/src/modes/user-group/groups-search-group.tsx
index 507c7cb80..8ffb2a6e2 100644
--- a/packages/spotlight/src/modes/user-group/groups-search-group.tsx
+++ b/packages/spotlight/src/modes/user-group/groups-search-group.tsx
@@ -16,7 +16,7 @@ const groupChildrenOptions = createChildrenOptions<Group>({
   useActions: () => [
     {
       key: "detail",
-      component: () => {
+      Component: () => {
         const t = useI18n();
         return (
           <Group mx="md" my="sm">
@@ -29,7 +29,7 @@ const groupChildrenOptions = createChildrenOptions<Group>({
     },
     {
       key: "manageMember",
-      component: () => {
+      Component: () => {
         const t = useI18n();
         return (
           <Group mx="md" my="sm">
@@ -42,7 +42,7 @@ const groupChildrenOptions = createChildrenOptions<Group>({
     },
     {
       key: "managePermission",
-      component: () => {
+      Component: () => {
         const t = useI18n();
         return (
           <Group mx="md" my="sm">
@@ -54,7 +54,7 @@ const groupChildrenOptions = createChildrenOptions<Group>({
       useInteraction: interaction.link(({ id }) => ({ href: `/manage/users/groups/${id}/permissions` })),
     },
   ],
-  detailComponent: ({ options }) => {
+  DetailComponent: ({ options }) => {
     const t = useI18n();
     return (
       <Stack mx="md" my="sm">
@@ -71,7 +71,7 @@ const groupChildrenOptions = createChildrenOptions<Group>({
 export const groupsSearchGroup = createGroup<Group>({
   keyPath: "id",
   title: "Groups",
-  component: ({ name }) => (
+  Component: ({ name }) => (
     <Group px="md" py="sm">
       <Text>{name}</Text>
     </Group>
diff --git a/packages/spotlight/src/modes/user-group/users-search-group.tsx b/packages/spotlight/src/modes/user-group/users-search-group.tsx
index ec750f182..b27dfbc37 100644
--- a/packages/spotlight/src/modes/user-group/users-search-group.tsx
+++ b/packages/spotlight/src/modes/user-group/users-search-group.tsx
@@ -17,7 +17,7 @@ const userChildrenOptions = createChildrenOptions<User>({
   useActions: () => [
     {
       key: "detail",
-      component: () => {
+      Component: () => {
         const t = useI18n();
 
         return (
@@ -30,7 +30,7 @@ const userChildrenOptions = createChildrenOptions<User>({
       useInteraction: interaction.link(({ id }) => ({ href: `/manage/users/${id}/general` })),
     },
   ],
-  detailComponent: ({ options }) => {
+  DetailComponent: ({ options }) => {
     const t = useI18n();
 
     return (
@@ -49,7 +49,7 @@ const userChildrenOptions = createChildrenOptions<User>({
 export const usersSearchGroup = createGroup<User>({
   keyPath: "id",
   title: (t) => t("search.mode.userGroup.group.user.title"),
-  component: (user) => (
+  Component: (user) => (
     <Group px="md" py="sm">
       <UserAvatar user={user} size="sm" />
       <Text>{user.name}</Text>
diff --git a/packages/translation/src/lang/en.ts b/packages/translation/src/lang/en.ts
index 24a149631..8aecc2fb2 100644
--- a/packages/translation/src/lang/en.ts
+++ b/packages/translation/src/lang/en.ts
@@ -576,6 +576,7 @@ export default {
       tryAgain: "Try again",
       loading: "Loading",
     },
+    here: "here",
     iconPicker: {
       label: "Icon URL",
       header: "Type name or objects to filter for icons... Homarr will search through {countIcons} icons for you.",
@@ -1157,6 +1158,14 @@ export default {
           },
         },
       },
+      integration: {
+        noData: "No integration found",
+        description: "Click {here} to create a new integration",
+      },
+      app: {
+        noData: "No app found",
+        description: "Click {here} to create a new app",
+      },
       error: {
         action: {
           logs: "Check logs for more details",
diff --git a/packages/ui/src/components/table-pagination.tsx b/packages/ui/src/components/table-pagination.tsx
index 83420ba54..e2380f821 100644
--- a/packages/ui/src/components/table-pagination.tsx
+++ b/packages/ui/src/components/table-pagination.tsx
@@ -34,7 +34,7 @@ export const TablePagination = ({ total }: TablePaginationProps) => {
     (control: ControlType) => {
       return getItemProps(calculatePageFor(control, current, total));
     },
-    [current],
+    [current, getItemProps, total],
   );
 
   const handleChange = useCallback(
@@ -43,7 +43,7 @@ export const TablePagination = ({ total }: TablePaginationProps) => {
       params.set("page", page.toString());
       replace(`${pathName}?${params.toString()}`);
     },
-    [pathName, searchParams],
+    [pathName, replace, searchParams],
   );
 
   return (
diff --git a/packages/widgets/src/_inputs/widget-app-input.tsx b/packages/widgets/src/_inputs/widget-app-input.tsx
index 04a85d468..ee22b08da 100644
--- a/packages/widgets/src/_inputs/widget-app-input.tsx
+++ b/packages/widgets/src/_inputs/widget-app-input.tsx
@@ -1,19 +1,22 @@
 "use client";
 
 import { memo, useMemo } from "react";
+import Link from "next/link";
 import type { SelectProps } from "@mantine/core";
-import { Group, Loader, Select } from "@mantine/core";
+import { Anchor, Group, Loader, Select, Text } from "@mantine/core";
 import { IconCheck } from "@tabler/icons-react";
 
 import type { RouterOutputs } from "@homarr/api";
 import { clientApi } from "@homarr/api/client";
+import { useI18n } from "@homarr/translation/client";
 
 import type { CommonWidgetInputProps } from "./common";
 import { useWidgetInputTranslation } from "./common";
 import { useFormContext } from "./form";
 
-export const WidgetAppInput = ({ property, kind, options }: CommonWidgetInputProps<"app">) => {
-  const t = useWidgetInputTranslation(kind, property);
+export const WidgetAppInput = ({ property, kind }: CommonWidgetInputProps<"app">) => {
+  const t = useI18n();
+  const tInput = useWidgetInputTranslation(kind, property);
   const form = useFormContext();
   const { data: apps, isPending } = clientApi.app.selectable.useQuery();
 
@@ -24,10 +27,11 @@ export const WidgetAppInput = ({ property, kind, options }: CommonWidgetInputPro
 
   return (
     <Select
-      label={t("label")}
+      label={tInput("label")}
       searchable
       limit={10}
       leftSection={<MemoizedLeftSection isPending={isPending} currentApp={currentApp} />}
+      nothingFoundMessage={t("widget.common.app.noData")}
       renderOption={renderSelectOption}
       data={
         apps?.map((app) => ({
@@ -36,7 +40,18 @@ export const WidgetAppInput = ({ property, kind, options }: CommonWidgetInputPro
           iconUrl: app.iconUrl,
         })) ?? []
       }
-      description={options.withDescription ? t("description") : undefined}
+      inputWrapperOrder={["label", "input", "description", "error"]}
+      description={
+        <Text size="xs">
+          {t("widget.common.app.description", {
+            here: (
+              <Anchor size="xs" component={Link} target="_blank" href="/manage/apps/new">
+                {t("common.here")}
+              </Anchor>
+            ),
+          })}
+        </Text>
+      }
       {...form.getInputProps(`options.${property}`)}
     />
   );
diff --git a/packages/widgets/src/_inputs/widget-location-input.tsx b/packages/widgets/src/_inputs/widget-location-input.tsx
index e264aee64..a27be85cb 100644
--- a/packages/widgets/src/_inputs/widget-location-input.tsx
+++ b/packages/widgets/src/_inputs/widget-location-input.tsx
@@ -46,7 +46,7 @@ export const WidgetLocationInput = ({ property, kind }: CommonWidgetInputProps<"
       form.clearFieldError(`options.${property}.latitude`);
       form.clearFieldError(`options.${property}.longitude`);
     },
-    [handleChange],
+    [form, handleChange, property],
   );
 
   const onSearch = useCallback(() => {
diff --git a/packages/widgets/src/_inputs/widget-multi-text-input.tsx b/packages/widgets/src/_inputs/widget-multi-text-input.tsx
index 2da483fac..9d1e9113f 100644
--- a/packages/widgets/src/_inputs/widget-multi-text-input.tsx
+++ b/packages/widgets/src/_inputs/widget-multi-text-input.tsx
@@ -39,7 +39,7 @@ export const WidgetMultiTextInput = ({ property, kind, options }: CommonWidgetIn
       success: validationResult.success,
       result: validationResult,
     };
-  }, [search]);
+  }, [options.validate, search]);
 
   const error = React.useMemo(() => {
     /* hide the error when nothing is being typed since "" is not valid but is not an explicit error */
diff --git a/packages/widgets/src/downloads/component.tsx b/packages/widgets/src/downloads/component.tsx
index 329565e3f..e437787ef 100644
--- a/packages/widgets/src/downloads/component.tsx
+++ b/packages/widgets/src/downloads/component.tsx
@@ -2,7 +2,7 @@
 
 import "../widgets-common.css";
 
-import { useMemo, useState } from "react";
+import { useCallback, useMemo, useState } from "react";
 import type { MantineStyleProp } from "@mantine/core";
 import {
   ActionIcon,
@@ -233,7 +233,19 @@ export default function DownloadClientsWidget({
         )
         //flatMap already sorts by integration by nature, add sorting by integration type (usenet | torrent)
         .sort(({ type: typeA }, { type: typeB }) => typeA.length - typeB.length),
-    [currentItems, integrationIds, options],
+    [
+      currentItems,
+      integrationIds,
+      integrationsWithInteractions,
+      mutateDeleteItem,
+      mutatePauseItem,
+      mutateResumeItem,
+      options.activeTorrentThreshold,
+      options.categoryFilter,
+      options.filterIsWhitelist,
+      options.showCompletedTorrent,
+      options.showCompletedUsenet,
+    ],
   );
 
   //Flatten Clients Array for which each elements has the integration and general client infos.
@@ -278,7 +290,14 @@ export default function DownloadClientsWidget({
           ({ status: statusA }, { status: statusB }) =>
             (statusA?.type.length ?? Infinity) - (statusB?.type.length ?? Infinity),
         ),
-    [currentItems, integrationIds, options],
+    [
+      currentItems,
+      integrationIds,
+      integrationsWithInteractions,
+      options.applyFilterToRatio,
+      options.categoryFilter,
+      options.filterIsWhitelist,
+    ],
   );
 
   //Check existing types between torrents and usenet
@@ -333,37 +352,40 @@ export default function DownloadClientsWidget({
   };
 
   //Base element in common with all columns
-  const columnsDefBase = ({
-    key,
-    showHeader,
-    align,
-  }: {
-    key: keyof ExtendedDownloadClientItem;
-    showHeader: boolean;
-    align?: "center" | "left" | "right" | "justify" | "char";
-  }): MRT_ColumnDef<ExtendedDownloadClientItem> => {
-    const style: MantineStyleProp = {
-      minWidth: 0,
-      width: "var(--column-width)",
-      height: "var(--ratio-width)",
-      padding: "var(--space-size)",
-      transition: "unset",
-      "--key-width": columnsRatios[key],
-      "--column-width": "calc((var(--key-width)/var(--total-width) * 100cqw))",
-    };
-    return {
-      id: key,
-      accessorKey: key,
-      header: key,
-      size: columnsRatios[key],
-      mantineTableBodyCellProps: { style, align },
-      mantineTableHeadCellProps: {
-        style,
-        align: isEditMode ? "center" : align,
-      },
-      Header: () => (showHeader && !isEditMode ? <Text fw={700}>{t(`items.${key}.columnTitle`)}</Text> : ""),
-    };
-  };
+  const columnsDefBase = useCallback(
+    ({
+      key,
+      showHeader,
+      align,
+    }: {
+      key: keyof ExtendedDownloadClientItem;
+      showHeader: boolean;
+      align?: "center" | "left" | "right" | "justify" | "char";
+    }): MRT_ColumnDef<ExtendedDownloadClientItem> => {
+      const style: MantineStyleProp = {
+        minWidth: 0,
+        width: "var(--column-width)",
+        height: "var(--ratio-width)",
+        padding: "var(--space-size)",
+        transition: "unset",
+        "--key-width": columnsRatios[key],
+        "--column-width": "calc((var(--key-width)/var(--total-width) * 100cqw))",
+      };
+      return {
+        id: key,
+        accessorKey: key,
+        header: key,
+        size: columnsRatios[key],
+        mantineTableBodyCellProps: { style, align },
+        mantineTableHeadCellProps: {
+          style,
+          align: isEditMode ? "center" : align,
+        },
+        Header: () => (showHeader && !isEditMode ? <Text fw={700}>{t(`items.${key}.columnTitle`)}</Text> : ""),
+      };
+    },
+    [isEditMode, t],
+  );
 
   //Make columns and cell elements, Memoized to data with deps on data and EditMode
   const columns = useMemo<MRT_ColumnDef<ExtendedDownloadClientItem>[]>(
@@ -580,7 +602,7 @@ export default function DownloadClientsWidget({
         },
       },
     ],
-    [clickedIndex, isEditMode, data, integrationIds, options],
+    [columnsDefBase, t, tCommon],
   );
 
   //Table build and config
@@ -704,10 +726,7 @@ interface ItemInfoModalProps {
 }
 
 const ItemInfoModal = ({ items, currentIndex, opened, onClose }: ItemInfoModalProps) => {
-  const item = useMemo<ExtendedDownloadClientItem | undefined>(
-    () => items[currentIndex],
-    [items, currentIndex, opened],
-  );
+  const item = useMemo<ExtendedDownloadClientItem | undefined>(() => items[currentIndex], [items, currentIndex]);
   const t = useScopedI18n("widget.downloads.states");
   //The use case for "No item found" should be impossible, hence no translation
   return (
diff --git a/packages/widgets/src/health-monitoring/component.tsx b/packages/widgets/src/health-monitoring/component.tsx
index dec33ff08..9e55872aa 100644
--- a/packages/widgets/src/health-monitoring/component.tsx
+++ b/packages/widgets/src/health-monitoring/component.tsx
@@ -57,22 +57,19 @@ export default function HealthMonitoringWidget({ options, integrationIds }: Widg
     throw new NoIntegrationSelectedError();
   }
   return (
-    <Box h="100%" className="health-monitoring">
+    <Stack h="100%" gap="2.5cqmin" className="health-monitoring">
       {healthData.map(({ integrationId, integrationName, healthInfo }) => {
-        const memoryUsage = formatMemoryUsage(healthInfo.memAvailable, healthInfo.memUsed);
         const disksData = matchFileSystemAndSmart(healthInfo.fileSystem, healthInfo.smart);
-        const { ref, width } = useElementSize();
-        const ringSize = width * 0.95;
-        const ringThickness = width / 10;
-        const progressSize = width * 0.2;
-
+        const memoryUsage = formatMemoryUsage(healthInfo.memAvailable, healthInfo.memUsed);
         return (
-          <Box
+          <Stack
+            gap="2.5cqmin"
             key={integrationId}
             h="100%"
             className={`health-monitoring-information health-monitoring-${integrationName}`}
+            p="2.5cqmin"
           >
-            <Card className="health-monitoring-information-card" m="2.5cqmin" p="2.5cqmin" withBorder>
+            <Card className="health-monitoring-information-card" p="2.5cqmin" withBorder>
               <Flex
                 className="health-monitoring-information-card-elements"
                 h="100%"
@@ -155,95 +152,17 @@ export default function HealthMonitoringWidget({ options, integrationIds }: Widg
                     </Stack>
                   </Modal>
                 </Box>
-                {options.cpu && (
-                  <Box ref={ref} w="100%" h="100%" className="health-monitoring-cpu">
-                    <RingProgress
-                      className="health-monitoring-cpu-utilization"
-                      roundCaps
-                      size={ringSize}
-                      thickness={ringThickness}
-                      label={
-                        <Center style={{ flexDirection: "column" }}>
-                          <Text
-                            className="health-monitoring-cpu-utilization-value"
-                            size="3cqmin"
-                          >{`${healthInfo.cpuUtilization.toFixed(2)}%`}</Text>
-                          <IconCpu className="health-monitoring-cpu-utilization-icon" size="7cqmin" />
-                        </Center>
-                      }
-                      sections={[
-                        {
-                          value: Number(healthInfo.cpuUtilization.toFixed(2)),
-                          color: progressColor(Number(healthInfo.cpuUtilization.toFixed(2))),
-                        },
-                      ]}
-                    />
-                  </Box>
-                )}
+                {options.cpu && <CpuRing cpuUtilization={healthInfo.cpuUtilization} />}
                 {healthInfo.cpuTemp && options.cpu && (
-                  <Box ref={ref} w="100%" h="100%" className="health-monitoring-cpu-temperature">
-                    <RingProgress
-                      ref={ref}
-                      className="health-monitoring-cpu-temp"
-                      roundCaps
-                      size={ringSize}
-                      thickness={ringThickness}
-                      label={
-                        <Center style={{ flexDirection: "column" }}>
-                          <Text className="health-monitoring-cpu-temp-value" size="3cqmin">
-                            {options.fahrenheit
-                              ? `${(healthInfo.cpuTemp * 1.8 + 32).toFixed(1)}°F`
-                              : `${healthInfo.cpuTemp}°C`}
-                          </Text>
-                          <IconCpu className="health-monitoring-cpu-temp-icon" size="7cqmin" />
-                        </Center>
-                      }
-                      sections={[
-                        {
-                          value: healthInfo.cpuTemp,
-                          color: progressColor(healthInfo.cpuTemp),
-                        },
-                      ]}
-                    />
-                  </Box>
-                )}
-                {options.memory && (
-                  <Box ref={ref} w="100%" h="100%" className="health-monitoring-memory">
-                    <RingProgress
-                      className="health-monitoring-memory-use"
-                      roundCaps
-                      size={ringSize}
-                      thickness={ringThickness}
-                      label={
-                        <Center style={{ flexDirection: "column" }}>
-                          <Text className="health-monitoring-memory-value" size="3cqmin">
-                            {memoryUsage.memUsed.GB}GiB
-                          </Text>
-                          <IconBrain className="health-monitoring-memory-icon" size="7cqmin" />
-                        </Center>
-                      }
-                      sections={[
-                        {
-                          value: Number(memoryUsage.memUsed.percent),
-                          color: progressColor(Number(memoryUsage.memUsed.percent)),
-                          tooltip: `${memoryUsage.memUsed.percent}%`,
-                        },
-                      ]}
-                    />
-                  </Box>
+                  <CpuTempRing fahrenheit={options.fahrenheit} cpuTemp={healthInfo.cpuTemp} />
                 )}
+                {options.memory && <MemoryRing available={healthInfo.memAvailable} used={healthInfo.memUsed} />}
               </Flex>
             </Card>
             {options.fileSystem &&
               disksData.map((disk) => {
                 return (
-                  <Card
-                    className="health-monitoring-disk-card"
-                    key={disk.deviceName}
-                    m="2.5cqmin"
-                    p="2.5cqmin"
-                    withBorder
-                  >
+                  <Card className="health-monitoring-disk-card" key={disk.deviceName} p="2.5cqmin" withBorder>
                     <Flex className="health-monitoring-disk-status" justify="space-between" align="center" m="1.5cqmin">
                       <Group gap="1cqmin">
                         <IconServer className="health-monitoring-disk-icon" size="5cqmin" />
@@ -266,14 +185,14 @@ export default function HealthMonitoringWidget({ options, integrationIds }: Widg
                         </Text>
                       </Group>
                     </Flex>
-                    <Progress.Root className="health-monitoring-disk-use" size={progressSize}>
+                    <Progress.Root className="health-monitoring-disk-use" h="6cqmin">
                       <Tooltip label={disk.used}>
                         <Progress.Section
                           value={disk.percentage}
                           color={progressColor(disk.percentage)}
                           className="health-monitoring-disk-use-percentage"
                         >
-                          <Progress.Label className="health-monitoring-disk-use-value">
+                          <Progress.Label className="health-monitoring-disk-use-value" fz="2.5cqmin">
                             {t("widget.healthMonitoring.popover.used")}
                           </Progress.Label>
                         </Progress.Section>
@@ -291,7 +210,7 @@ export default function HealthMonitoringWidget({ options, integrationIds }: Widg
                           value={100 - disk.percentage}
                           color="default"
                         >
-                          <Progress.Label className="health-monitoring-disk-available-value">
+                          <Progress.Label className="health-monitoring-disk-available-value" fz="2.5cqmin">
                             {t("widget.healthMonitoring.popover.diskAvailable")}
                           </Progress.Label>
                         </Progress.Section>
@@ -300,10 +219,10 @@ export default function HealthMonitoringWidget({ options, integrationIds }: Widg
                   </Card>
                 );
               })}
-          </Box>
+          </Stack>
         );
       })}
-    </Box>
+    </Stack>
   );
 }
 
@@ -349,6 +268,95 @@ export const matchFileSystemAndSmart = (fileSystems: FileSystem[], smartData: Sm
   });
 };
 
+const CpuRing = ({ cpuUtilization }: { cpuUtilization: number }) => {
+  const { width, ref } = useElementSize();
+
+  return (
+    <Box ref={ref} w="100%" h="100%" className="health-monitoring-cpu">
+      <RingProgress
+        className="health-monitoring-cpu-utilization"
+        roundCaps
+        size={width * 0.95}
+        thickness={width / 10}
+        label={
+          <Center style={{ flexDirection: "column" }}>
+            <Text
+              className="health-monitoring-cpu-utilization-value"
+              size="3cqmin"
+            >{`${cpuUtilization.toFixed(2)}%`}</Text>
+            <IconCpu className="health-monitoring-cpu-utilization-icon" size="7cqmin" />
+          </Center>
+        }
+        sections={[
+          {
+            value: Number(cpuUtilization.toFixed(2)),
+            color: progressColor(Number(cpuUtilization.toFixed(2))),
+          },
+        ]}
+      />
+    </Box>
+  );
+};
+
+const CpuTempRing = ({ fahrenheit, cpuTemp }: { fahrenheit: boolean; cpuTemp: number }) => {
+  const { width, ref } = useElementSize();
+  return (
+    <Box ref={ref} w="100%" h="100%" className="health-monitoring-cpu-temperature">
+      <RingProgress
+        className="health-monitoring-cpu-temp"
+        roundCaps
+        size={width * 0.95}
+        thickness={width / 10}
+        label={
+          <Center style={{ flexDirection: "column" }}>
+            <Text className="health-monitoring-cpu-temp-value" size="3cqmin">
+              {fahrenheit ? `${(cpuTemp * 1.8 + 32).toFixed(1)}°F` : `${cpuTemp}°C`}
+            </Text>
+            <IconCpu className="health-monitoring-cpu-temp-icon" size="7cqmin" />
+          </Center>
+        }
+        sections={[
+          {
+            value: cpuTemp,
+            color: progressColor(cpuTemp),
+          },
+        ]}
+      />
+    </Box>
+  );
+};
+
+const MemoryRing = ({ available, used }: { available: string; used: string }) => {
+  const { width, ref } = useElementSize();
+  const memoryUsage = formatMemoryUsage(available, used);
+
+  return (
+    <Box ref={ref} w="100%" h="100%" className="health-monitoring-memory">
+      <RingProgress
+        className="health-monitoring-memory-use"
+        roundCaps
+        size={width * 0.95}
+        thickness={width / 10}
+        label={
+          <Center style={{ flexDirection: "column" }}>
+            <Text className="health-monitoring-memory-value" size="3cqmin">
+              {memoryUsage.memUsed.GB}GiB
+            </Text>
+            <IconBrain className="health-monitoring-memory-icon" size="7cqmin" />
+          </Center>
+        }
+        sections={[
+          {
+            value: Number(memoryUsage.memUsed.percent),
+            color: progressColor(Number(memoryUsage.memUsed.percent)),
+            tooltip: `${memoryUsage.memUsed.percent}%`,
+          },
+        ]}
+      />
+    </Box>
+  );
+};
+
 export const formatMemoryUsage = (memFree: string, memUsed: string) => {
   const memFreeBytes = Number(memFree);
   const memUsedBytes = Number(memUsed);
diff --git a/packages/widgets/src/media-requests/list/component.tsx b/packages/widgets/src/media-requests/list/component.tsx
index bc6df6b25..ce67166ba 100644
--- a/packages/widgets/src/media-requests/list/component.tsx
+++ b/packages/widgets/src/media-requests/list/component.tsx
@@ -46,7 +46,7 @@ export default function MediaServerWidget({
           }
           return 0;
         }),
-    [mediaRequests, integrationIds],
+    [mediaRequests],
   );
 
   const { mutate: mutateRequestAnswer } = clientApi.widget.mediaRequests.answerRequest.useMutation();
diff --git a/packages/widgets/src/notebook/notebook.tsx b/packages/widgets/src/notebook/notebook.tsx
index 9eebb48a0..295227201 100644
--- a/packages/widgets/src/notebook/notebook.tsx
+++ b/packages/widgets/src/notebook/notebook.tsx
@@ -189,17 +189,31 @@ export function Notebook({ options, isEditMode, boardId, itemId }: WidgetCompone
 
   addEventListener("onReadOnlyCheck", handleOnReadOnlyCheck);
 
-  const handleEditToggleCallback = (previous: boolean) => {
-    const current = !previous;
-    if (!editor) return current;
-    editor.setEditable(current);
+  const handleContentUpdate = useCallback(
+    (contentUpdate: string) => {
+      setToSaveContent(contentUpdate);
+      // This is not available in preview mode
+      if (boardId && itemId) {
+        void mutateAsync({ boardId, itemId, content: contentUpdate });
+      }
+    },
+    [boardId, itemId, mutateAsync],
+  );
 
-    handleContentUpdate(content);
+  const handleEditToggleCallback = useCallback(
+    (previous: boolean) => {
+      const current = !previous;
+      if (!editor) return current;
+      editor.setEditable(current);
 
-    return current;
-  };
+      handleContentUpdate(content);
 
-  const handleEditCancelCallback = () => {
+      return current;
+    },
+    [content, editor, handleContentUpdate],
+  );
+
+  const handleEditCancelCallback = useCallback(() => {
     if (!editor) return false;
     editor.setEditable(false);
 
@@ -207,20 +221,12 @@ export function Notebook({ options, isEditMode, boardId, itemId }: WidgetCompone
     editor.commands.setContent(toSaveContent);
 
     return false;
-  };
+  }, [editor, toSaveContent]);
 
   const handleEditCancel = useCallback(() => {
     setIsEditing(handleEditCancelCallback);
   }, [setIsEditing, handleEditCancelCallback]);
 
-  const handleContentUpdate = (contentUpdate: string) => {
-    setToSaveContent(contentUpdate);
-    // This is not available in preview mode
-    if (boardId && itemId) {
-      void mutateAsync({ boardId, itemId, content: contentUpdate });
-    }
-  };
-
   const handleEditToggle = useCallback(() => {
     setIsEditing(handleEditToggleCallback);
   }, [setIsEditing, handleEditToggleCallback]);
diff --git a/packages/widgets/src/options.ts b/packages/widgets/src/options.ts
index abe108dfb..91d547c5c 100644
--- a/packages/widgets/src/options.ts
+++ b/packages/widgets/src/options.ts
@@ -104,10 +104,10 @@ const optionsFactory = {
     values: [] as string[],
     validate: input?.validate,
   }),
-  app: (input?: Omit<CommonInput<string>, "defaultValue">) => ({
+  app: () => ({
     type: "app" as const,
     defaultValue: "",
-    withDescription: input?.withDescription ?? false,
+    withDescription: false,
   }),
 };
 
diff --git a/packages/widgets/src/smart-home/entity-state/component.tsx b/packages/widgets/src/smart-home/entity-state/component.tsx
index c7e590b71..b627e5f73 100644
--- a/packages/widgets/src/smart-home/entity-state/component.tsx
+++ b/packages/widgets/src/smart-home/entity-state/component.tsx
@@ -1,6 +1,6 @@
 "use client";
 
-import React, { useState } from "react";
+import React, { useCallback, useState } from "react";
 import { Center, Stack, Text, UnstyledButton } from "@mantine/core";
 
 import { clientApi } from "@homarr/api/client";
@@ -38,7 +38,7 @@ export default function SmartHomeEntityStateWidget({
 
   const attribute = options.entityUnit.length > 0 ? " " + options.entityUnit : "";
 
-  const handleClick = React.useCallback(() => {
+  const handleClick = useCallback(() => {
     if (isEditMode) {
       return;
     }
@@ -51,7 +51,7 @@ export default function SmartHomeEntityStateWidget({
       entityId: options.entityId,
       integrationId: integrationIds[0] ?? "",
     });
-  }, []);
+  }, [integrationIds, isEditMode, mutate, options.clickable, options.entityId]);
 
   return (
     <UnstyledButton
diff --git a/packages/widgets/src/smart-home/execute-automation/component.tsx b/packages/widgets/src/smart-home/execute-automation/component.tsx
index f05417e60..e174cdb2b 100644
--- a/packages/widgets/src/smart-home/execute-automation/component.tsx
+++ b/packages/widgets/src/smart-home/execute-automation/component.tsx
@@ -31,7 +31,7 @@ export default function SmartHomeTriggerAutomationWidget({
       automationId: options.automationId,
       integrationId: integrationIds[0] ?? "",
     });
-  }, [isEditMode]);
+  }, [integrationIds, isEditMode, mutateAsync, options.automationId]);
   return (
     <UnstyledButton onClick={handleClick} style={{ cursor: !isEditMode ? "pointer" : "initial" }} w="100%" h="100%">
       {isShowSuccess && (
diff --git a/packages/widgets/src/video/component.tsx b/packages/widgets/src/video/component.tsx
index 8832d2390..0893e6d8d 100644
--- a/packages/widgets/src/video/component.tsx
+++ b/packages/widgets/src/video/component.tsx
@@ -72,7 +72,7 @@ const Feed = ({ options }: Pick<WidgetComponentProps<"video">, "options">) => {
         () => undefined,
       );
     }
-  }, [videoRef]);
+  }, [options.hasAutoPlay, options.hasControls, options.isMuted, videoRef]);
 
   return (
     <Group justify="center" w="100%" h="100%" pos="relative">
diff --git a/packages/widgets/src/widget-integration-select.tsx b/packages/widgets/src/widget-integration-select.tsx
index 39bef4d2d..3aa27fcd6 100644
--- a/packages/widgets/src/widget-integration-select.tsx
+++ b/packages/widgets/src/widget-integration-select.tsx
@@ -1,7 +1,9 @@
 "use client";
 
 import type { FocusEventHandler } from "react";
+import Link from "next/link";
 import {
+  Anchor,
   Avatar,
   CheckIcon,
   CloseButton,
@@ -86,7 +88,23 @@ export const WidgetIntegrationSelect = ({
   return (
     <Combobox store={combobox} onOptionSubmit={handleValueSelect} withinPortal={false}>
       <Combobox.DropdownTarget>
-        <PillsInput pointer onClick={() => combobox.toggleDropdown()} {...props}>
+        <PillsInput
+          inputWrapperOrder={["label", "input", "description", "error"]}
+          description={
+            <Text size="xs">
+              {t("widget.common.integration.description", {
+                here: (
+                  <Anchor size="xs" component={Link} target="_blank" href="/manage/integrations">
+                    {t("common.here")}
+                  </Anchor>
+                ),
+              })}
+            </Text>
+          }
+          pointer
+          onClick={() => combobox.toggleDropdown()}
+          {...props}
+        >
           <Pill.Group>
             {values.length > 0 ? values : <Input.Placeholder>{t("common.multiSelect.placeholder")}</Input.Placeholder>}
 
@@ -108,7 +126,15 @@ export const WidgetIntegrationSelect = ({
       </Combobox.DropdownTarget>
 
       <Combobox.Dropdown>
-        <Combobox.Options>{options}</Combobox.Options>
+        <Combobox.Options>
+          {options.length >= 1 ? (
+            options
+          ) : (
+            <Text p={4} size="sm" ta="center" c="var(--mantine-color-dimmed)">
+              {t("widget.common.integration.noData")}
+            </Text>
+          )}
+        </Combobox.Options>
       </Combobox.Dropdown>
     </Combobox>
   );
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index afa7095dc..fec5e8b66 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -24,7 +24,7 @@ importers:
         version: 4.3.2(vite@5.4.5(@types/node@20.16.11)(sass@1.79.5)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0))
       '@vitest/coverage-v8':
         specifier: ^2.1.3
-        version: 2.1.3(vitest@2.1.3)
+        version: 2.1.3(vitest@2.1.3(@types/node@20.16.11)(@vitest/ui@2.1.3)(jsdom@25.0.1)(sass@1.79.5)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0))
       '@vitest/ui':
         specifier: ^2.1.3
         version: 2.1.3(vitest@2.1.3)
@@ -1655,8 +1655,8 @@ importers:
         specifier: ^7.37.1
         version: 7.37.1(eslint@9.12.0)
       eslint-plugin-react-hooks:
-        specifier: ^4.6.2
-        version: 4.6.2(eslint@9.12.0)
+        specifier: ^5.0.0
+        version: 5.0.0(eslint@9.12.0)
       typescript-eslint:
         specifier: ^8.9.0
         version: 8.9.0(eslint@9.12.0)(typescript@5.6.3)
@@ -4795,11 +4795,11 @@ packages:
     peerDependencies:
       eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9
 
-  eslint-plugin-react-hooks@4.6.2:
-    resolution: {integrity: sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==}
+  eslint-plugin-react-hooks@5.0.0:
+    resolution: {integrity: sha512-hIOwI+5hYGpJEc4uPRmz2ulCjAGD/N13Lukkh8cLV0i2IRk/bdZDYjgLVHj+U9Z704kLIdIO6iueGvxNur0sgw==}
     engines: {node: '>=10'}
     peerDependencies:
-      eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0
+      eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0
 
   eslint-plugin-react@7.37.1:
     resolution: {integrity: sha512-xwTnwDqzbDRA8uJ7BMxPs/EXRB3i8ZfnOIp8BsxEQkT0nHPp+WWceqGgo6rKb9ctNi8GJLDT4Go5HAWELa/WMg==}
@@ -9967,7 +9967,7 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
-  '@vitest/coverage-v8@2.1.3(vitest@2.1.3)':
+  '@vitest/coverage-v8@2.1.3(vitest@2.1.3(@types/node@20.16.11)(@vitest/ui@2.1.3)(jsdom@25.0.1)(sass@1.79.5)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0))':
     dependencies:
       '@ampproject/remapping': 2.3.0
       '@bcoe/v8-coverage': 0.2.3
@@ -11361,7 +11361,7 @@ snapshots:
       safe-regex-test: 1.0.3
       string.prototype.includes: 2.0.0
 
-  eslint-plugin-react-hooks@4.6.2(eslint@9.12.0):
+  eslint-plugin-react-hooks@5.0.0(eslint@9.12.0):
     dependencies:
       eslint: 9.12.0
 
diff --git a/tooling/eslint/package.json b/tooling/eslint/package.json
index 599d84db2..a2d50fa83 100644
--- a/tooling/eslint/package.json
+++ b/tooling/eslint/package.json
@@ -22,7 +22,7 @@
     "eslint-plugin-import": "^2.31.0",
     "eslint-plugin-jsx-a11y": "^6.10.0",
     "eslint-plugin-react": "^7.37.1",
-    "eslint-plugin-react-hooks": "^4.6.2",
+    "eslint-plugin-react-hooks": "^5.0.0",
     "typescript-eslint": "^8.9.0"
   },
   "devDependencies": {
diff --git a/tooling/eslint/react.js b/tooling/eslint/react.js
index c36e835df..abbf8f1d1 100644
--- a/tooling/eslint/react.js
+++ b/tooling/eslint/react.js
@@ -12,9 +12,6 @@ export default [
     rules: {
       ...reactPlugin.configs["jsx-runtime"].rules,
       ...hooksPlugin.configs.recommended.rules,
-      // context.getSource is not a function
-      "react-hooks/rules-of-hooks": "off",
-      "react-hooks/exhaustive-deps": "off",
     },
     languageOptions: {
       globals: {