import { useEffect, useMemo, useRef } from "react"; import { ActionIcon, Menu } from "@mantine/core"; import { IconCopy, IconDotsVertical, IconLayoutKanban, IconPencil, IconTrash } from "@tabler/icons-react"; import { clientApi } from "@homarr/api/client"; import { useSession } from "@homarr/auth/client"; import { isWidgetRestricted } from "@homarr/auth/shared"; import { useEditMode } from "@homarr/boards/edit-mode"; import { useConfirmModal, useModalAction } from "@homarr/modals"; import { useSettings } from "@homarr/settings"; import { useI18n, useScopedI18n } from "@homarr/translation/client"; import { widgetImports } from "@homarr/widgets"; import { WidgetEditModal } from "@homarr/widgets/modals"; import type { SectionItem } from "~/app/[locale]/boards/_types"; import { useSectionContext } from "../sections/section-context"; import { useItemActions } from "./item-actions"; import { ItemMoveModal } from "./item-move-modal"; export const BoardItemMenu = ({ offset, item, resetErrorBoundary, }: { offset: number; item: SectionItem; resetErrorBoundary?: () => void; }) => { const refResetErrorBoundaryOnNextRender = useRef(false); const tItem = useScopedI18n("item"); const t = useI18n(); const { openModal } = useModalAction(WidgetEditModal); const { openModal: openMoveModal } = useModalAction(ItemMoveModal); const { openConfirmModal } = useConfirmModal(); const [isEditMode] = useEditMode(); const { updateItemOptions, updateItemAdvancedOptions, updateItemIntegrations, duplicateItem, removeItem } = useItemActions(); const { data: integrationData, isPending } = clientApi.integration.all.useQuery(); const currentDefinition = useMemo(() => widgetImports[item.kind].definition, [item.kind]); const { gridstack } = useSectionContext().refs; const settings = useSettings(); const { data: session } = useSession(); // Reset error boundary on next render if item has been edited useEffect(() => { if (refResetErrorBoundaryOnNextRender.current) { resetErrorBoundary?.(); refResetErrorBoundaryOnNextRender.current = false; } }, [item, resetErrorBoundary]); if (!isEditMode || isPending) return null; const openEditModal = () => { openModal({ kind: item.kind, value: { advancedOptions: item.advancedOptions, options: item.options, integrationIds: item.integrationIds, }, onSuccessfulEdit: ({ options, integrationIds, advancedOptions }) => { updateItemOptions({ itemId: item.id, newOptions: options, }); updateItemAdvancedOptions({ itemId: item.id, newAdvancedOptions: advancedOptions, }); updateItemIntegrations({ itemId: item.id, newIntegrations: integrationIds, }); refResetErrorBoundaryOnNextRender.current = true; }, integrationData: (integrationData ?? []).filter( (integration) => "supportedIntegrations" in currentDefinition && (currentDefinition.supportedIntegrations as string[]).some((kind) => kind === integration.kind), ), integrationSupport: "supportedIntegrations" in currentDefinition, settings, }); }; const openRemoveModal = () => { openConfirmModal({ title: tItem("remove.title"), children: tItem("remove.message"), onConfirm: () => { removeItem({ itemId: item.id }); }, }); }; if ( isWidgetRestricted({ definition: currentDefinition, user: session?.user ?? null, check: (level) => level !== "none", }) ) { return null; } return (
); };