diff --git a/PRODUCT.md b/PRODUCT.md
index adcf7f24e..8b4a6c01a 100644
--- a/PRODUCT.md
+++ b/PRODUCT.md
@@ -1,5 +1,9 @@
# Product
+## Register
+
+product
+
## Users
Homarr is used by self-hosters and administrators who assemble dashboards for services running across home labs and private infrastructure. They need dense, reliable controls and status at a glance, with enough guidance to configure advanced features without hiding how they work.
diff --git a/apps/nextjs/src/app/[locale]/boards/(content)/_board-add-menu.tsx b/apps/nextjs/src/app/[locale]/boards/(content)/_board-add-menu.tsx
deleted file mode 100644
index 0448e1097..000000000
--- a/apps/nextjs/src/app/[locale]/boards/(content)/_board-add-menu.tsx
+++ /dev/null
@@ -1,86 +0,0 @@
-"use client";
-
-import { useCallback } from "react";
-import { Group, Menu } from "@mantine/core";
-import { IconBox, IconBoxAlignTop, IconChevronDown, IconPlug, IconPlus, IconResize } from "@tabler/icons-react";
-
-import { useSession } from "@homarr/auth/client";
-import { useRequiredBoard } from "@homarr/boards/context";
-import { useModalAction } from "@homarr/modals";
-import { AppSelectModal } from "@homarr/modals-collection";
-import { useI18n } from "@homarr/translation/client";
-
-import { useItemActions } from "~/components/board/items/item-actions";
-import { ItemSelectModal } from "~/components/board/items/item-select-modal";
-import { useCategoryActions } from "~/components/board/sections/category/category-actions";
-import { CategoryEditModal } from "~/components/board/sections/category/category-edit-modal";
-import { useDynamicSectionActions } from "~/components/board/sections/dynamic/dynamic-actions";
-import { IntegrationSelectModal } from "~/components/integration/integration-select-modal";
-import { HeaderButton } from "~/components/layout/header/button";
-
-export const BoardAddMenu = () => {
- const { data: session } = useSession();
- const board = useRequiredBoard();
- const { openModal: openCategoryEditModal } = useModalAction(CategoryEditModal);
- const { openModal: openItemSelectModal } = useModalAction(ItemSelectModal);
- const { openModal: openAppSelectModal } = useModalAction(AppSelectModal);
- const { openModal: openIntegrationSelectModal } = useModalAction(IntegrationSelectModal);
- const { addCategoryToEnd } = useCategoryActions();
- const { addDynamicSection } = useDynamicSectionActions();
- const { createItem } = useItemActions();
- const t = useI18n();
-
- const handleAddCategory = useCallback(
- () =>
- openCategoryEditModal(
- {
- category: { id: "new", name: "" },
- onSuccess({ name }) {
- addCategoryToEnd({ name });
- },
- submitLabel: t("section.category.create.submit"),
- },
- { title: (translate) => translate("section.category.create.title") },
- ),
- [addCategoryToEnd, openCategoryEditModal, t],
- );
-
- return (
-
- );
-};
diff --git a/apps/nextjs/src/app/[locale]/boards/(content)/_edit-actions.tsx b/apps/nextjs/src/app/[locale]/boards/(content)/_edit-actions.tsx
index c869e0d62..ca2990680 100644
--- a/apps/nextjs/src/app/[locale]/boards/(content)/_edit-actions.tsx
+++ b/apps/nextjs/src/app/[locale]/boards/(content)/_edit-actions.tsx
@@ -4,6 +4,7 @@ import { Group, Menu } from "@mantine/core";
import { IconBox, IconChevronDown, IconLayoutGridAdd, IconPlug, IconPlus, IconResize } from "@tabler/icons-react";
import { useSession } from "@homarr/auth/client";
+import { useRequiredBoard } from "@homarr/boards/context";
import { useModalAction } from "@homarr/modals";
import { AppSelectModal } from "@homarr/modals-collection";
import { useI18n } from "@homarr/translation/client";
@@ -20,6 +21,7 @@ export default function BoardEditActions() {
const AddMenu = () => {
const { data: session } = useSession();
+ const board = useRequiredBoard();
const { openModal: openItemSelectModal } = useModalAction(ItemSelectModal);
const { openModal: openAppSelectModal } = useModalAction(AppSelectModal);
const { openModal: openIntegrationSelectModal } = useModalAction(IntegrationSelectModal);
@@ -28,7 +30,7 @@ const AddMenu = () => {
const t = useI18n();
const handleSelectItem = () => {
- openItemSelectModal();
+ openItemSelectModal({ boardId: board.id });
};
const handleSelectApp = () => {
diff --git a/apps/nextjs/src/components/board/items/lazy-item-move-modal.tsx b/apps/nextjs/src/components/board/items/lazy-item-move-modal.tsx
deleted file mode 100644
index 836017bc1..000000000
--- a/apps/nextjs/src/components/board/items/lazy-item-move-modal.tsx
+++ /dev/null
@@ -1,67 +0,0 @@
-"use client";
-
-import { Suspense, use } from "react";
-import { Center, Loader } from "@mantine/core";
-import { ErrorBoundary } from "react-error-boundary";
-
-import { createModal, modalSizeForm } from "@homarr/modals";
-import { WidgetError } from "@homarr/widgets/errors";
-
-import type { ItemMoveModalProps } from "./item-move-modal";
-
-let itemMoveModalPromise: Promise | undefined;
-
-const loadItemMoveModal = () => {
- if (itemMoveModalPromise) return itemMoveModalPromise;
-
- const currentPromise = import("./item-move-modal");
- itemMoveModalPromise = currentPromise;
- void currentPromise.catch(() => {
- if (itemMoveModalPromise === currentPromise) itemMoveModalPromise = undefined;
- });
- return currentPromise;
-};
-
-export const preloadItemMoveModal = () => void loadItemMoveModal().catch(() => undefined);
-
-interface LazyItemMoveModalContentProps {
- actions: { closeModal: () => void };
- innerProps: ItemMoveModalProps;
-}
-
-const LazyItemMoveModalContent = (props: LazyItemMoveModalContentProps) => {
- const { ItemMoveModal } = use(loadItemMoveModal());
- const Component = ItemMoveModal.component;
- return ;
-};
-
-export const LazyItemMoveModal = createModal((props) => (
- (
-
- {
- itemMoveModalPromise = undefined;
- resetErrorBoundary();
- }}
- />
-
- )}
- >
-
-
-
- }
- >
-
-
-
-)).withOptions({
- defaultTitle(t) {
- return t("item.moveResize.title");
- },
- size: modalSizeForm,
-});
diff --git a/apps/nextjs/src/components/board/sections/grid/grid-portal-host.tsx b/apps/nextjs/src/components/board/sections/grid/grid-portal-host.tsx
index 5e5e9a297..f08afa600 100644
--- a/apps/nextjs/src/components/board/sections/grid/grid-portal-host.tsx
+++ b/apps/nextjs/src/components/board/sections/grid/grid-portal-host.tsx
@@ -5,8 +5,10 @@ import { createContext, useCallback, useContext, useEffect, useMemo, useRef, use
import { createPortal } from "react-dom";
import type { RouterOutputs } from "@homarr/api";
-import { useIntegrations } from "@homarr/auth/client";
+import { clientApi } from "@homarr/api/client";
+import { useSession } from "@homarr/auth/client";
import { useCurrentLayout, useRequiredBoard } from "@homarr/boards/context";
+import { useEditMode } from "@homarr/boards/edit-mode";
import { getRootSectionLane } from "@homarr/definitions";
import type { ContainerSectionItem, Section } from "~/app/[locale]/boards/_types";
@@ -33,7 +35,11 @@ const GridPortalHostContext = createContext(n
*/
export const BoardGridPortalHost = ({ children }: PropsWithChildren) => {
const board = useRequiredBoard();
- const integrations = useIntegrations();
+ const { data: session } = useSession();
+ const [isEditMode] = useEditMode();
+ const { data: integrations } = clientApi.integration.all.useQuery(undefined, {
+ enabled: Boolean(session) && isEditMode,
+ });
const containersRef = useRef