import { type PluginButton, type PluginButtonContentProps, type PluginButtonIconProps, type PluginClientContext, useWorkspace, } from "@getpaseo/plugin/client"; import { useMemo } from "react"; import { Pressable, Text, View } from "react-native"; export type ButtonMode = "action" | "menu" | "popover"; const composerPresentation = { action: { title: "Refresh context", label: "Refresh" }, menu: { title: "Composer tools", label: "Tools" }, popover: { title: "Context details", label: "Details" }, }; function WorkspaceStatusIcon({ workspaceId, size, color, theme }: PluginButtonIconProps) { const status = useWorkspace(workspaceId, (workspace) => workspace.status); let fill = color; if (status === "failed") fill = theme.colors.statusDanger; else if (status === "needs_input") fill = theme.colors.statusWarning; else if (status === "done") fill = theme.colors.statusSuccess; const style = useMemo( () => ({ width: size, height: size, borderRadius: size / 2, backgroundColor: fill }), [size, fill], ); return ; } function WorkspaceDetails({ workspaceId, theme, close }: PluginButtonContentProps) { const workspace = useWorkspace(workspaceId, ({ name, projectDisplayName, status, diffStat }) => ({ name, projectDisplayName, status, diffStat, })); const styles = useMemo( () => ({ body: { gap: 12 }, title: { color: theme.colors.foreground, fontSize: 18 }, text: { color: theme.colors.foreground }, detail: { color: theme.colors.foregroundMuted }, button: { padding: 8, borderRadius: 6, backgroundColor: theme.colors.surface2 }, }), [theme], ); return ( Workspace details {workspace?.name} {workspace?.projectDisplayName} Status: {workspace?.status} {workspace?.diffStat ? ( +{workspace.diffStat.additions} / −{workspace.diffStat.deletions} lines ) : null} Done ); } export function createButtonExamples( client: PluginClientContext, workspaceId: string, agentId: string, ) { let mode: ButtonMode = "action"; let refreshes = 0; async function refreshWorkspace() { // Return the real operation's promise: Paseo supplies pending, double-press prevention, and errors. await client.paseo.workspaces.ref(workspaceId).refresh(); refreshes += 1; if (mode === "action") { header.update({ title: `Refresh workspace (${refreshes})` }); pill.update({ label: `Refreshed · ${refreshes}` }); } } function button(next: ButtonMode): PluginButton { if (next === "action") return { title: "Refresh workspace", icon: "RefreshCw", label: undefined, // The header is icon-only. The composer supplies its own label below. behavior: { kind: "action", onPress: refreshWorkspace }, }; if (next === "popover") return { title: "Workspace details", icon: WorkspaceStatusIcon, label: "Details", behavior: { kind: "popover", Content: WorkspaceDetails }, }; return { title: "Workspace tools", icon: "Wrench", label: "Tools", behavior: { kind: "menu", items: [ { kind: "item", id: "refresh", title: "Refresh workspace", icon: "RefreshCw", behavior: { kind: "action", onPress: refreshWorkspace }, }, { kind: "separator", id: "details-divider" }, { kind: "item", id: "details", title: "Workspace details", icon: WorkspaceStatusIcon, behavior: { kind: "popover", Content: WorkspaceDetails }, }, { kind: "item", id: "display", title: "Display", icon: "Eye", behavior: { kind: "menu", items: [ { kind: "item", id: "hide", title: "Hide example buttons", icon: "EyeOff", behavior: { kind: "action", onPress() { setVisible(false); }, }, }, { kind: "item", id: "disable", title: "Disable example buttons", behavior: { kind: "action", onPress() { setDisabled(true); }, }, }, ], }, }, { kind: "item", id: "publish", title: "Publish (unavailable in example)", icon: "Upload", disabled: true, behavior: { kind: "action", onPress() {} }, }, ], }, }; } function composerButton(next: ButtonMode): PluginButton { return { ...button(next), ...composerPresentation[next], }; } const header = client.addHeaderButton({ id: "example", workspaceId, button: button(mode) }); const pill = client.addComposerPill({ id: "example", workspaceId, agentId, button: composerButton(mode), }); function setVisible(visible: boolean) { header.update({ visible }); pill.update({ visible }); } function setDisabled(disabled: boolean) { header.update({ disabled }); pill.update({ disabled }); } return { setMode(next: ButtonMode) { mode = next; header.update({ ...button(next), visible: true, disabled: false }); pill.update({ ...composerButton(next), visible: true, disabled: false }); }, setVisible, setDisabled, remove() { header.remove(); pill.remove(); }, }; }