import { Trans, useLingui } from "@lingui/react/macro"; import type { Bot, BotSection } from "@rakazo/contracts"; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, Button, Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, Input, } from "@rakazo/ui-web"; import { FolderOpen, Lock, Users } from "lucide-react"; import { useId, useState } from "react"; import { desktopBridge } from "../../lib/desktop"; /** Each dialog is mounted only while open, so `open` is always true and the * parent unmounts it from `onCancel`. Escape and backdrop presses are ignored * while a request is in flight. */ function closeUnlessBusy(busy: boolean, onCancel: () => void) { return (open: boolean) => { if (!open && !busy) onCancel(); }; } export type NewSpaceConfirmInput = { name: string; workspacePath?: string; }; export function NewSpaceDialog({ variant = "space", canLinkFolder, onCancel, onConfirm, }: { variant?: "space" | "project"; /** Folders live on the host, which only the deployment owner may link. */ canLinkFolder: boolean; onCancel: () => void; onConfirm: (input: NewSpaceConfirmInput) => Promise; }) { const { t } = useLingui(); const nameId = useId(); const folderId = useId(); const [name, setName] = useState(""); const [workspacePath, setWorkspacePath] = useState(""); const [saving, setSaving] = useState(false); const [error, setError] = useState(null); const isProject = variant === "project"; const showFolder = isProject && canLinkFolder; const desktop = desktopBridge(); const trimmedWorkspacePath = workspacePath.trim(); const create = () => { const trimmed = name.trim(); if (!trimmed || saving) return; setSaving(true); setError(null); void onConfirm({ name: trimmed, ...(showFolder && trimmedWorkspacePath ? { workspacePath: trimmedWorkspacePath } : {}), }).catch((reason: unknown) => { setError( reason instanceof Error ? reason.message : isProject ? t`Could not create project` : t`Could not create space`, ); setSaving(false); }); }; return ( {showFolder ? (

{desktop?.files?.pickDirectory ? ( Choose an existing folder on this computer. Git remotes are linked automatically when a repository is present. ) : ( Enter an absolute folder path on the server. Git remotes are linked automatically when a repository is present. )}

) : null} {error ?

{error}

: null}
); } export function PickerInfoDialog({ topic, onClose, }: { topic: "group" | "space"; onClose: () => void; }) { return ( { if (!open) onClose(); }} > {topic === "group" ? ( {topic === "group" ? ( Shared chat with 2-6 bots. They all reply in the same thread. ) : ( Private workspace with its own bots and groups. )} ); } export function NewBotSectionDialog({ bot, onCancel, onConfirm, }: { bot: Pick; onCancel: () => void; onConfirm: (name: string) => Promise; }) { const { t } = useLingui(); const nameId = useId(); const [name, setName] = useState(""); const [saving, setSaving] = useState(false); const [error, setError] = useState(null); return (
{ event.preventDefault(); const trimmed = name.trim(); if (!trimmed || saving) return; setSaving(true); setError(null); void onConfirm(trimmed).catch((err: unknown) => { setError(err instanceof Error ? err.message : t`Could not create section`); setSaving(false); }); }} > New section Create a section and move {bot.name} into it. {error ?

{error}

: null}
); } export function RenameBotSectionDialog({ section, onCancel, onConfirm, }: { section: Pick; onCancel: () => void; onConfirm: (name: string) => Promise; }) { const { t } = useLingui(); const nameId = useId(); const [name, setName] = useState(section.name); const [saving, setSaving] = useState(false); const [error, setError] = useState(null); const trimmed = name.trim(); const unchanged = trimmed === section.name; return (
{ event.preventDefault(); if (!trimmed || saving || unchanged) return; setSaving(true); setError(null); void onConfirm(trimmed).catch((err: unknown) => { setError(err instanceof Error ? err.message : t`Could not rename section`); setSaving(false); }); }} > Rename section {error ?

{error}

: null}
); } export function ClearConversationDialog({ bot, onCancel, onConfirm, }: { bot: Pick; onCancel: () => void; onConfirm: () => Promise; }) { const { t } = useLingui(); const [clearing, setClearing] = useState(false); const [error, setError] = useState(null); return ( Clear {bot.name}’s conversation? This permanently removes every message and stops current work. The chat remains available. {error ?

{error}

: null} Cancel { setClearing(true); setError(null); void onConfirm().catch((err: unknown) => { setError(err instanceof Error ? err.message : t`Could not clear conversation`); setClearing(false); }); }} > {clearing ? Clearing… : Clear}
); } export function DeleteBotDialog({ bot, onCancel, onConfirm, }: { bot: Bot; onCancel: () => void; onConfirm: (deleteMemories: boolean) => Promise; }) { const { t } = useLingui(); const [deleting, setDeleting] = useState(false); const [deleteMemories, setDeleteMemories] = useState(false); const [error, setError] = useState(null); return ( Delete {bot.name}? Its conversation, files, and routines will be permanently deleted. Bots it created stay in your list.
What about its memories?
{error ?

{error}

: null} Cancel { setDeleting(true); setError(null); void onConfirm(deleteMemories).catch((err: unknown) => { setError(err instanceof Error ? err.message : t`Could not delete bot`); setDeleting(false); }); }} > {deleting ? Deleting… : Delete}
); } export function DeleteItemDialog({ item, noun, description, onCancel, onConfirm, }: { item: { name: string }; noun: "group" | "routine" | "space"; description?: React.ReactNode; onCancel: () => void; onConfirm: () => Promise; }) { const { t } = useLingui(); const [deleting, setDeleting] = useState(false); const [error, setError] = useState(null); return ( Delete {item.name}? {description ?? This cannot be undone.} {error ?

{error}

: null} Cancel { setDeleting(true); setError(null); void onConfirm().catch((err: unknown) => { setError( err instanceof Error ? err.message : noun === "group" ? t`Could not delete group` : noun === "space" ? t`Could not delete space` : t`Could not delete routine`, ); setDeleting(false); }); }} > {deleting ? Deleting… : Delete}
); }