feat(builder): Addition of SaveControl component for ControlPanel (#7687)

Co-authored-by: Nicholas Tindle <nicholas.tindle@agpt.co>
pull/7688/head^2
Andy Hooker 2024-08-04 23:39:42 -05:00 committed by GitHub
parent 183c2a4845
commit 533d7b7da8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 186 additions and 0 deletions

View File

@ -11,6 +11,7 @@
"dependencies": {
"@hookform/resolvers": "^3.9.0",
"@radix-ui/react-avatar": "^1.1.0",
"@radix-ui/react-collapsible": "^1.1.0",
"@radix-ui/react-dialog": "^1.1.1",
"@radix-ui/react-dropdown-menu": "^2.1.1",
"@radix-ui/react-icons": "^1.3.0",

View File

@ -0,0 +1,61 @@
import {Card, CardContent} from "@/components/ui/card";
import {Tooltip, TooltipContent, TooltipTrigger} from "@/components/ui/tooltip";
import {Button} from "@/components/ui/button";
import {Separator} from "@/components/ui/separator";
import React from "react";
/**
* Represents a control element for the ControlPanel Component.
* @type {Object} Control
* @property {React.ReactNode} icon - The icon of the control from lucide-react https://lucide.dev/icons/
* @property {string} label - The label of the control, to be leveraged by ToolTip.
* @property {onclick} onClick - The function to be executed when the control is clicked.
*/
export type Control = {
icon: React.ReactNode;
label: string;
onClick: () => void;
}
interface ControlPanelProps {
controls: Control[];
children?: React.ReactNode;
}
/**
* ControlPanel component displays a panel with controls as icons with the ability to take in children.
* @param {Object} ControlPanelProps - The properties of the control panel component.
* @param {Array} ControlPanelProps.controls - An array of control objects representing actions to be preformed.
* @param {Array} ControlPanelProps.children - The child components of the control panel.
* @returns The rendered control panel component.
*/
export const ControlPanel= ( {controls, children}: ControlPanelProps) => {
return (
<aside className="hidden w-14 flex-col sm:flex">
<Card>
<CardContent className="p-0">
<div className="flex flex-col items-center gap-4 px-2 sm:py-5 rounded-radius">
{children}
<Separator />
{controls.map((control, index) => (
<Tooltip key={index} delayDuration={500}>
<TooltipTrigger asChild>
<Button
variant="ghost"
size="icon"
onClick={() => control.onClick()}
>
{control.icon}
<span className="sr-only">{control.label}</span>
</Button>
</TooltipTrigger>
<TooltipContent side="right">{control.label}</TooltipContent>
</Tooltip>
))}
</div>
</CardContent>
</Card>
</aside>
);
}
export default ControlPanel;

View File

@ -0,0 +1,99 @@
import React from "react";
import {Popover, PopoverContent, PopoverTrigger} from "@/components/ui/popover";
import {Card, CardContent, CardFooter} from "@/components/ui/card";
import {Input} from "@/components/ui/input";
import {Button} from "@/components/ui/button";
import {GraphMeta} from "@/lib/autogpt-server-api";
import {Label} from "@/components/ui/label";
import {Save} from "lucide-react";
interface SaveControlProps {
agentMeta: GraphMeta | null;
onSave: (isTemplate: boolean | undefined) => void;
onNameChange: (name: string) => void;
onDescriptionChange: (description: string) => void;
}
/**
* A SaveControl component to be used within the ControlPanel. It allows the user to save the agent / template.
* @param {Object} SaveControlProps - The properties of the SaveControl component.
* @param {GraphMeta | null} SaveControlProps.agentMeta - The agent's metadata, or null if creating a new agent.
* @param {(isTemplate: boolean | undefined) => void} SaveControlProps.onSave - Function to save the agent or template.
* @param {(name: string) => void} SaveControlProps.onNameChange - Function to handle name changes.
* @param {(description: string) => void} SaveControlProps.onDescriptionChange - Function to handle description changes.
* @returns The SaveControl component.
*/
export const SaveControl= ({
agentMeta,
onSave,
onNameChange,
onDescriptionChange
}: SaveControlProps) => {
/**
* Note for improvement:
* At the moment we are leveraging onDescriptionChange and onNameChange to handle the changes in the description and name of the agent.
* We should migrate this to be handled with form controls and a form library.
*/
// Determines if we're saving a template or an agent
let isTemplate = agentMeta?.is_template ? true : undefined;
const handleSave = () => {
onSave(isTemplate);
};
const getType = () => {
return agentMeta?.is_template ? 'template' : 'agent';
}
return (
<Popover >
<PopoverTrigger
className="hover:bg-gray-100 hover:text-gray-900 dark:hover:bg-gray-800 dark:hover:text-gray-50 dark:text-white"
>
<Save className="size-4"/>
</PopoverTrigger>
<PopoverContent side="right" sideOffset={15} align="start">
<Card className="border-none shadow-none">
<CardContent>
<div className="grid gap-3">
<Label htmlFor="name">
Name
</Label>
<Input
id="name"
placeholder="Enter your agent name"
className="col-span-3"
defaultValue={agentMeta?.name || ''}
onChange={(e) => onNameChange(e.target.value)}
/>
<Label htmlFor="description">
Description
</Label>
<Input
id="description"
placeholder="Your agent description"
className="col-span-3"
defaultValue={agentMeta?.description || ''}
onChange={(e) => onDescriptionChange(e.target.value)}
/>
</div>
</CardContent>
<CardFooter className="flex flex-col items-stretch gap-2 ">
<Button className="w-full" onClick={handleSave}>
Save {getType()}
</Button>
{!agentMeta && (
<Button variant="secondary" className="w-full" onClick={() => {
isTemplate = true;
handleSave();
}}>
Save as Template
</Button>
)}
</CardFooter>
</Card>
</PopoverContent>
</Popover>
);
}

View File

@ -0,0 +1,11 @@
"use client"
import * as CollapsiblePrimitive from "@radix-ui/react-collapsible"
const Collapsible = CollapsiblePrimitive.Root
const CollapsibleTrigger = CollapsiblePrimitive.CollapsibleTrigger
const CollapsibleContent = CollapsiblePrimitive.CollapsibleContent
export { Collapsible, CollapsibleTrigger, CollapsibleContent }

View File

@ -246,6 +246,20 @@
"@radix-ui/react-use-callback-ref" "1.1.0"
"@radix-ui/react-use-layout-effect" "1.1.0"
"@radix-ui/react-collapsible@^1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@radix-ui/react-collapsible/-/react-collapsible-1.1.0.tgz#4d49ddcc7b7d38f6c82f1fd29674f6fab5353e77"
integrity sha512-zQY7Epa8sTL0mq4ajSJpjgn2YmCgyrG7RsQgLp3C0LQVkG7+Tf6Pv1CeNWZLyqMjhdPkBa5Lx7wYBeSu7uCSTA==
dependencies:
"@radix-ui/primitive" "1.1.0"
"@radix-ui/react-compose-refs" "1.1.0"
"@radix-ui/react-context" "1.1.0"
"@radix-ui/react-id" "1.1.0"
"@radix-ui/react-presence" "1.1.0"
"@radix-ui/react-primitive" "2.0.0"
"@radix-ui/react-use-controllable-state" "1.1.0"
"@radix-ui/react-use-layout-effect" "1.1.0"
"@radix-ui/react-collection@1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@radix-ui/react-collection/-/react-collection-1.1.0.tgz#f18af78e46454a2360d103c2251773028b7724ed"