import { useState } from "react" import type { FlowDef_Input } from "@/client" import { Button } from "@/components/ui/button" import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "@/components/ui/dialog" import { Input } from "@/components/ui/input" import { Switch } from "@/components/ui/switch" import { PANEL_SECTION, SidePanel } from "./SidePanel" const NAME_PATTERN = /^[a-z][a-z0-9_]*$/ /** * The flow's own settings, in the same panel its nodes use. * * The name is also the namespace of every message in the flow, which is why * renaming goes through the server rather than being another autosaved field. */ export function FlowPanel({ open, definition, nodeCount, renaming, onChange, onRename, onDelete, hasDraft, discarding, onDiscardDraft, enabled, toggling, onToggleEnabled, onClose, }: { open: boolean definition: FlowDef_Input nodeCount: number renaming: boolean onChange: (next: FlowDef_Input) => void onRename: (newName: string) => void onDelete: () => void hasDraft: boolean discarding: boolean onDiscardDraft: () => void enabled: boolean toggling: boolean onToggleEnabled: (next: boolean) => void onClose: () => void }) { const [name, setName] = useState(definition.name) const [confirmOpen, setConfirmOpen] = useState(false) const [discardOpen, setDiscardOpen] = useState(false) const valid = NAME_PATTERN.test(name) const changed = name !== definition.name return ( <> onChange({ ...definition, title: event.target.value }) } /> } footer={ } >
Running

{enabled ? "The engine runs this flow: subscriptions, schedules and webhooks are live." : "Stopped. Nothing of this flow is subscribed, scheduled or reachable."}

Name
setName(event.target.value)} onKeyDown={(event) => { if (event.key === "Enter" && valid && changed) { onRename(name) } }} />

{valid || !name ? "Messages in this flow are named after it, so other flows reading them follow the rename." : "Lowercase letters, digits and underscores, starting with a letter."}

Contents

{nodeCount === 0 ? "No nodes yet." : `${nodeCount} node${nodeCount === 1 ? "" : "s"}.`}

{hasDraft ? (
Unpublished changes

The engine is still running the last published version of this flow.

) : null}
Delete {definition.title || definition.name}? This removes the flow and the code of its{" "} {nodeCount === 1 ? "node" : `${nodeCount} nodes`}. Its history stays in the flow store's git repository. Discard the unpublished changes? The canvas goes back to the version the engine is running. What you edited since is dropped, though the flow store's git history keeps it. ) }