import { useId, useRef, useState } from "react"; import { Button, ConfirmationDialog, DialogFooter, Input, Popover, PopoverContent, PopoverTrigger, ScrollArea, Spinner, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@tutti-os/ui-system"; import { AddIcon, ArrowLeftIcon, ArrowRightIcon, CheckIcon, GripVerticalIcon, MessageSquareTextIcon, SearchIcon } from "@tutti-os/ui-system/icons"; import { cn } from "../../../../app/renderer/lib/utils"; import styles from "../../AgentGUINode.styles"; import { AgentQuickPromptEditorDialog } from "./AgentQuickPromptEditorDialog"; import { AgentQuickPromptList } from "./AgentQuickPromptList"; import type { AgentQuickPromptTemplate } from "./agentQuickPromptLabels"; import type { AgentQuickPromptLibraryController } from "./useAgentQuickPromptLibrary"; import { type PrimaryPointerAction, usePrimaryPointerAction } from "./usePrimaryPointerAction"; export function AgentQuickPromptPopover({ controller, disabled }: { controller: AgentQuickPromptLibraryController; disabled: boolean; }): React.JSX.Element | null { const searchRef = useRef(null); const rowRefs = useRef(new Map()); const firstTemplateRef = useRef(null); const preserveExternalFocusRef = useRef(false); const [view, setView] = useState<"prompts" | "templates">("prompts"); let activeView = view; if (controller.insertionError && activeView !== "prompts") { activeView = "prompts"; setView("prompts"); } const [sortingState, setSortingState] = useState({ isPopoverOpen: controller.isPopoverOpen, isSorting: false }); let isSorting = sortingState.isSorting; if (sortingState.isPopoverOpen !== controller.isPopoverOpen) { isSorting = false; setSortingState({ isPopoverOpen: controller.isPopoverOpen, isSorting: false }); } const setIsSorting = (next: boolean): void => { setSortingState({ isPopoverOpen: controller.isPopoverOpen, isSorting: next }); }; const titleId = useId(); const { labels, snapshot } = controller; const templateEntryAction = usePrimaryPointerAction(() => setView("templates") ); const returnToPromptsAction = usePrimaryPointerAction(() => setView("prompts") ); const createAction = usePrimaryPointerAction(() => { if (controller.isInteractionLocked) return; preserveExternalFocusRef.current = true; controller.openCreate(); }); const deleteCancelAction = usePrimaryPointerAction(controller.closeDialog); const deleteConfirmAction = usePrimaryPointerAction(() => { void controller.submitDelete(); }); const startSortingAction = usePrimaryPointerAction(() => setIsSorting(true)); const finishSortingAction = usePrimaryPointerAction(() => setIsSorting(false) ); if (!controller.capabilityAvailable) { return null; } const focusRow = (index: number): void => { const prompt = controller.filteredPrompts[index]; if (prompt) rowRefs.current.get(prompt.id)?.focus(); }; const errorLabel = controller.mutationError === "conflict" ? labels.conflict : controller.mutationError === "generic" ? labels.mutationError : null; const requestTemplate = (template: AgentQuickPromptTemplate): void => { preserveExternalFocusRef.current = true; controller.openCreate( { title: template.title, content: template.content }, { insertIntoComposerAfterSave: true, usagePromptType: "recommended_template" } ); }; const isTemplateView = activeView === "templates"; const reorderDisabledMessage = resolveReorderDisabledMessage(controller); const startSortingButton = ( ); return ( <> { if (!open) { setView("prompts"); setIsSorting(false); } controller.setPopoverOpen(open); }} > {labels.triggerTooltip} { event.preventDefault(); window.requestAnimationFrame(() => { if (isTemplateView) { firstTemplateRef.current?.focus(); return; } const selectedId = controller.selectedPrompt?.id; const selectedRow = selectedId ? rowRefs.current.get(selectedId) : null; (selectedRow ?? searchRef.current)?.focus(); }); }} onCloseAutoFocus={(event) => { if (preserveExternalFocusRef.current) event.preventDefault(); preserveExternalFocusRef.current = false; }} >

{isTemplateView ? labels.recommendedTemplatesTitle : labels.title}

{isTemplateView ? ( ) : (
{isSorting ? ( ) : ( <> {reorderDisabledMessage ? ( {startSortingButton} {reorderDisabledMessage} ) : ( startSortingButton )} )}
)}
{!isTemplateView && !isSorting ? (
controller.setSearchQuery(event.target.value) } onKeyDown={(event) => { if (event.key === "ArrowDown") { event.preventDefault(); focusRow(0); } }} />
) : null} {!isTemplateView && snapshot.status === "error" && snapshot.prompts.length > 0 ? (
{labels.loadError}
) : null} {!isTemplateView && controller.reorderError ? (
{controller.reorderError === "conflict" ? labels.reorderConflict : labels.reorderError}
) : null} {!isTemplateView && controller.insertionError ? (
{labels.insertionError}
) : null} {isTemplateView ? ( ) : snapshot.status === "loading" && snapshot.prompts.length === 0 ? ( } label={labels.loading} /> ) : snapshot.status === "error" && snapshot.prompts.length === 0 ? ( {labels.retry} } /> ) : snapshot.prompts.length === 0 && !controller.searchQuery.trim() ? ( ) : controller.filteredPrompts.length === 0 ? ( ) : (
{ preserveExternalFocusRef.current = true; controller.deletePrompt(prompt); }} onEdit={(prompt) => { preserveExternalFocusRef.current = true; controller.openEdit(prompt); }} onSelect={(prompt) => { if (isSorting) return; preserveExternalFocusRef.current = true; controller.selectPrompt(prompt); }} /> {!isSorting ? ( ) : null}
)}
{controller.isEditorOpen ? ( ) : null} } onOpenChange={(open) => { if (!open && !controller.isDeleting) controller.closeDialog(); }} open={controller.mode === "delete"} title={labels.deleteTitle} tone="destructive" > {errorLabel ? (

{errorLabel}

) : null}
); } function resolveReorderDisabledMessage( controller: AgentQuickPromptLibraryController ): string | null { const { labels, snapshot } = controller; if (!controller.reorderCapabilityAvailable) { return labels.reorderDisabledUnsupported; } if (snapshot.status === "idle" || snapshot.status === "loading") { return labels.loading; } if (snapshot.status === "error" && snapshot.prompts.length === 0) { return labels.loadError; } if (controller.isInteractionLocked) { return labels.reorderDisabledPending; } if (controller.searchQuery.trim()) { return labels.reorderDisabledSearch; } if (controller.filteredPrompts.length < 2) { return labels.reorderDisabledMinimum; } return null; } function RecommendedTemplateList({ disabled, firstTemplateRef, labels, onSelect }: { disabled: boolean; firstTemplateRef: React.RefObject; labels: AgentQuickPromptLibraryController["labels"]; onSelect: (template: AgentQuickPromptTemplate) => void; }): React.JSX.Element { return (

{labels.recommendedTemplatesTitle}

{labels.recommendedTemplatesDescription}

{labels.recommendedTemplates.map((template, index) => ( ))}
); } function RecommendedTemplateButton({ disabled, labels, onSelect, selectionRef, template }: { disabled: boolean; labels: AgentQuickPromptLibraryController["labels"]; onSelect: (template: AgentQuickPromptTemplate) => void; selectionRef?: React.RefObject; template: AgentQuickPromptTemplate; }): React.JSX.Element { const selectionAction = usePrimaryPointerAction(() => { if (!disabled) onSelect(template); }); return ( ); } function TemplateEntry({ action, disabled, label }: { action: PrimaryPointerAction; disabled: boolean; label: string; }): React.JSX.Element { return ( ); } function PromptState({ action, icon, label }: { action?: React.ReactNode; icon?: React.ReactNode; label: string; }): React.JSX.Element { return (
{icon} {label} {action}
); }