import { DialogClose } from "@radix-ui/react-dialog"; import { useFetcher, useNavigate } from "@remix-run/react"; import { IconCheck } from "@tabler/icons-react"; import { useEffect, useState } from "react"; import { useEnvironment } from "~/hooks/useEnvironment"; import { useCustomDashboards, useOrganization, useWidgetLimitPerDashboard, } from "~/hooks/useOrganizations"; import { useProject } from "~/hooks/useProject"; import { cn } from "~/utils/cn"; import { v3CustomDashboardPath } from "~/utils/pathBuilder"; import { Button } from "../primitives/Buttons"; import { Dialog, DialogContent, DialogHeader } from "../primitives/Dialog"; import { FormButtons } from "../primitives/FormButtons"; import { Paragraph } from "../primitives/Paragraph"; import type { QueryWidgetConfig } from "./QueryWidget"; export type SaveToDashboardDialogProps = { title: string; query: string; config: QueryWidgetConfig; isOpen: boolean; onOpenChange: (open: boolean) => void; }; export function SaveToDashboardDialog({ title, query, config, isOpen, onOpenChange, }: SaveToDashboardDialogProps) { const organization = useOrganization(); const project = useProject(); const environment = useEnvironment(); const customDashboards = useCustomDashboards(); const widgetLimit = useWidgetLimitPerDashboard(); const fetcher = useFetcher<{ success: boolean }>(); const navigate = useNavigate(); // Find the first dashboard that isn't at the widget limit const firstAvailableDashboard = customDashboards.find((d) => d.widgetCount < widgetLimit); const [selectedDashboardId, setSelectedDashboardId] = useState( firstAvailableDashboard?.friendlyId ?? customDashboards[0]?.friendlyId ?? null ); // Build the form action URL const formAction = selectedDashboardId ? `/resources/orgs/${organization.slug}/projects/${project.slug}/env/${environment.slug}/dashboards/${selectedDashboardId}/widgets` : ""; const isLoading = fetcher.state === "submitting"; // Check if selected dashboard is at widget limit const selectedDashboard = customDashboards.find((d) => d.friendlyId === selectedDashboardId); const isSelectedAtLimit = selectedDashboard ? selectedDashboard.widgetCount >= widgetLimit : false; // Navigate to the dashboard when the fetcher completes successfully useEffect(() => { if (fetcher.state === "idle" && fetcher.data?.success && selectedDashboardId) { onOpenChange(false); navigate( v3CustomDashboardPath( { slug: organization.slug }, { slug: project.slug }, { slug: environment.slug }, { friendlyId: selectedDashboardId } ) ); } }, [ fetcher.state, fetcher.data, selectedDashboardId, onOpenChange, navigate, organization.slug, project.slug, environment.slug, ]); // Update selection if dashboards change useEffect(() => { if (customDashboards.length > 0 && !selectedDashboardId) { const available = customDashboards.find((d) => d.widgetCount < widgetLimit); setSelectedDashboardId(available?.friendlyId ?? customDashboards[0].friendlyId); } }, [customDashboards, selectedDashboardId, widgetLimit]); if (customDashboards.length === 0) { return ( Add to dashboard
You don't have any custom dashboards yet. Create one first from the sidebar menu. } />
); } return ( Add to dashboard
Select a dashboard to add this chart to:
{customDashboards.map((dashboard) => { const isAtLimit = dashboard.widgetCount >= widgetLimit; return ( ); })}
{isLoading ? "Saving..." : "Save"} } cancelButton={ } />
); }