From 9644f671c274327848c554b15bad7a56b330e6b6 Mon Sep 17 00:00:00 2001 From: Sean Hatfield <seanhatfield5@gmail.com> Date: Thu, 13 Jun 2024 09:55:37 -0700 Subject: [PATCH] [STYLE] Agent UI mobile styles (#1665) * implement mobile styles for new agent settings ui * fix on off label not updating for generate & save files to browser * update sql connector modal for mobile * small changes for UI normalization * breakout layout from forms for mobile/desktop * add back no-borders --------- Co-authored-by: Timothy Carambat <rambat1010@gmail.com> --- .../components/ContextualSaveBar/index.jsx | 4 +- .../NewConnectionModal.jsx | 20 +- frontend/src/pages/Admin/Agents/index.jsx | 192 ++++++++++++++---- 3 files changed, 165 insertions(+), 51 deletions(-) diff --git a/frontend/src/components/ContextualSaveBar/index.jsx b/frontend/src/components/ContextualSaveBar/index.jsx index 056bf739b..aab0b36fe 100644 --- a/frontend/src/components/ContextualSaveBar/index.jsx +++ b/frontend/src/components/ContextualSaveBar/index.jsx @@ -8,8 +8,8 @@ export default function ContextualSaveBar({ if (!showing) return null; return ( - <div className="fixed top-0 left-0 right-0 h-14 bg-[#18181B] flex items-center justify-end px-4 z-[9999]"> - <div className="absolute left-1/2 transform -translate-x-1/2 flex items-center gap-x-2"> + <div className="fixed top-0 left-0 right-0 h-14 bg-[#18181B] flex items-center justify-end px-4 z-[999]"> + <div className="absolute ml-4 left-0 md:left-1/2 transform md:-translate-x-1/2 flex items-center gap-x-2"> <Warning size={18} className="text-white" /> <p className="text-white font-medium text-xs">Unsaved Changes</p> </div> diff --git a/frontend/src/pages/Admin/Agents/SQLConnectorSelection/NewConnectionModal.jsx b/frontend/src/pages/Admin/Agents/SQLConnectorSelection/NewConnectionModal.jsx index 62f4722c2..62235fedd 100644 --- a/frontend/src/pages/Admin/Agents/SQLConnectorSelection/NewConnectionModal.jsx +++ b/frontend/src/pages/Admin/Agents/SQLConnectorSelection/NewConnectionModal.jsx @@ -74,7 +74,7 @@ export default function NewSQLConnection({ isOpen, closeModal, onSubmit }) { // to the parent container form so we don't have nested forms. return createPortal( <ModalWrapper isOpen={isOpen}> - <div className="relative w-1/3 max-h-full mt-8"> + <div className="relative w-full md:w-1/3 max-w-2xl max-h-full md:mt-8"> <div className="relative bg-main-gradient rounded-xl shadow-[0_4px_14px_rgba(0,0,0,0.25)] max-h-[85vh] overflow-y-scroll no-scroll"> <div className="flex items-start justify-between p-4 border-b rounded-t border-gray-500/50"> <h3 className="text-xl font-semibold text-white"> @@ -114,7 +114,7 @@ export default function NewSQLConnection({ isOpen, closeModal, onSubmit }) { <label className="text-white text-sm font-semibold block my-4"> Select your SQL engine </label> - <div className="flex w-full flex-wrap gap-x-4"> + <div className="grid md:grid-cols-4 gap-4 grid-cols-2"> <DBEngine provider="postgresql" active={engine === "postgresql"} @@ -148,8 +148,8 @@ export default function NewSQLConnection({ isOpen, closeModal, onSubmit }) { /> </div> - <div className="flex gap-x-2"> - <div className="flex flex-col w-60"> + <div className="grid grid-cols-1 gap-4 sm:grid-cols-2"> + <div className="flex flex-col"> <label className="text-white text-sm font-semibold block mb-4"> Database user </label> @@ -163,7 +163,7 @@ export default function NewSQLConnection({ isOpen, closeModal, onSubmit }) { spellCheck={false} /> </div> - <div className="flex flex-col w-60"> + <div className="flex flex-col"> <label className="text-white text-sm font-semibold block mb-4"> Database user password </label> @@ -179,8 +179,8 @@ export default function NewSQLConnection({ isOpen, closeModal, onSubmit }) { </div> </div> - <div className="flex gap-x-2"> - <div className="flex flex-col w-full"> + <div className="grid grid-cols-1 gap-4 sm:grid-cols-3"> + <div className="sm:col-span-2"> <label className="text-white text-sm font-semibold block mb-4"> Server endpoint </label> @@ -194,7 +194,7 @@ export default function NewSQLConnection({ isOpen, closeModal, onSubmit }) { spellCheck={false} /> </div> - <div className="flex flex-col w-30"> + <div> <label className="text-white text-sm font-semibold block mb-4"> Port </label> @@ -210,7 +210,7 @@ export default function NewSQLConnection({ isOpen, closeModal, onSubmit }) { </div> </div> - <div className="flex flex-col w-60"> + <div className="flex flex-col"> <label className="text-white text-sm font-semibold block mb-4"> Database </label> @@ -264,7 +264,7 @@ function DBEngine({ provider, active, onClick }) { <img src={DB_LOGOS[provider]} className="h-[100px] rounded-md" - alt="PostgreSQL" + alt={provider} /> </button> ); diff --git a/frontend/src/pages/Admin/Agents/index.jsx b/frontend/src/pages/Admin/Agents/index.jsx index d22bba823..9cb1a93ae 100644 --- a/frontend/src/pages/Admin/Agents/index.jsx +++ b/frontend/src/pages/Admin/Agents/index.jsx @@ -4,7 +4,7 @@ import { isMobile } from "react-device-detect"; import Admin from "@/models/admin"; import System from "@/models/system"; import showToast from "@/utils/toast"; -import { CaretRight, Robot } from "@phosphor-icons/react"; +import { CaretLeft, CaretRight, Robot } from "@phosphor-icons/react"; import ContextualSaveBar from "@/components/ContextualSaveBar"; import { castToType } from "@/utils/types"; import { FullScreenLoader } from "@/components/Preloader"; @@ -17,6 +17,7 @@ export default function AdminAgents() { const [selectedSkill, setSelectedSkill] = useState(""); const [agentSkills, setAgentSkills] = useState([]); const [loading, setLoading] = useState(true); + const [showSkillModal, setShowSkillModal] = useState(false); const formEl = useRef(null); // Alert user if they try to leave the page with unsaved changes @@ -110,21 +111,19 @@ export default function AdminAgents() { </div> ); } - return ( - <div - id="workspace-agent-settings-container" - className="w-screen h-screen overflow-hidden bg-sidebar flex" - > - <Sidebar /> - <div - style={{ height: isMobile ? "100%" : "calc(100% - 32px)" }} - className="relative md:ml-[2px] md:mr-[16px] md:my-[16px] md:rounded-[16px] w-full h-full flex" + + if (isMobile) { + return ( + <SkillLayout + hasChanges={hasChanges} + handleCancel={() => setHasChanges(false)} + handleSubmit={handleSubmit} > <form onSubmit={handleSubmit} onChange={() => setHasChanges(true)} ref={formEl} - className="flex-1 flex gap-x-6 p-4 mt-10" + className="flex flex-col w-full p-4 mt-10" > <input name="system::default_agent_skills" @@ -133,56 +132,167 @@ export default function AdminAgents() { /> {/* Skill settings nav */} - <div className="flex flex-col gap-y-[18px]"> + <div hidden={showSkillModal} className="flex flex-col gap-y-[18px]"> <div className="text-white flex items-center gap-x-2"> <Robot size={24} /> <p className="text-lg font-medium">Agent Skills</p> </div> - - {/* Default skills list */} + {/* Default skills */} <SkillList isDefault={true} skills={defaultSkills} selectedSkill={selectedSkill} - handleClick={setSelectedSkill} + handleClick={(skill) => { + setSelectedSkill(skill); + setShowSkillModal(true); + }} /> {/* Configurable skills */} <SkillList skills={configurableSkills} selectedSkill={selectedSkill} - handleClick={setSelectedSkill} + handleClick={(skill) => { + setSelectedSkill(skill); + setShowSkillModal(true); + }} activeSkills={agentSkills} /> </div> - {/* Selected agent skill setting panel */} - <div className="flex-[2] flex flex-col gap-y-[18px] mt-10"> - <div className="bg-[#303237] text-white rounded-xl flex-1 p-4"> - {SelectedSkillComponent ? ( - <SelectedSkillComponent - skill={configurableSkills[selectedSkill]?.skill} - settings={settings} - toggleSkill={toggleAgentSkill} - enabled={agentSkills.includes( - configurableSkills[selectedSkill]?.skill - )} - setHasChanges={setHasChanges} - {...(configurableSkills[selectedSkill] || - defaultSkills[selectedSkill])} - /> - ) : ( - <div className="flex flex-col items-center justify-center h-full text-white/60"> - <Robot size={40} /> - <p className="font-medium">Select an agent skill</p> + {/* Selected agent skill modal */} + {showSkillModal && ( + <div className="fixed top-0 left-0 w-full h-full bg-sidebar z-30"> + <div className="flex flex-col h-full"> + <div className="flex items-center p-4"> + <button + type="button" + onClick={() => { + setShowSkillModal(false); + setSelectedSkill(""); + }} + className="text-white/60 hover:text-white transition-colors duration-200" + > + <div className="flex items-center text-sky-400"> + <CaretLeft size={24} /> + <div>Back</div> + </div> + </button> + </div> + <div className="flex-1 overflow-y-auto p-4"> + <div className="bg-[#303237] text-white rounded-xl p-4"> + {SelectedSkillComponent ? ( + <SelectedSkillComponent + skill={configurableSkills[selectedSkill]?.skill} + settings={settings} + toggleSkill={toggleAgentSkill} + enabled={agentSkills.includes( + configurableSkills[selectedSkill]?.skill + )} + setHasChanges={setHasChanges} + {...(configurableSkills[selectedSkill] || + defaultSkills[selectedSkill])} + /> + ) : ( + <div className="flex flex-col items-center justify-center h-full text-white/60"> + <Robot size={40} /> + <p className="font-medium">Select an agent skill</p> + </div> + )} + </div> </div> - )} + </div> </div> - </div> + )} </form> + </SkillLayout> + ); + } + + return ( + <SkillLayout + hasChanges={hasChanges} + handleCancel={() => setHasChanges(false)} + handleSubmit={handleSubmit} + > + <form + onSubmit={handleSubmit} + onChange={() => setHasChanges(true)} + ref={formEl} + className="flex-1 flex gap-x-6 p-4 mt-10" + > + <input + name="system::default_agent_skills" + type="hidden" + value={agentSkills.join(",")} + /> + + {/* Skill settings nav */} + <div className="flex flex-col gap-y-[18px]"> + <div className="text-white flex items-center gap-x-2"> + <Robot size={24} /> + <p className="text-lg font-medium">Agent Skills</p> + </div> + + {/* Default skills list */} + <SkillList + isDefault={true} + skills={defaultSkills} + selectedSkill={selectedSkill} + handleClick={setSelectedSkill} + /> + {/* Configurable skills */} + <SkillList + skills={configurableSkills} + selectedSkill={selectedSkill} + handleClick={setSelectedSkill} + activeSkills={agentSkills} + /> + </div> + + {/* Selected agent skill setting panel */} + <div className="flex-[2] flex flex-col gap-y-[18px] mt-10"> + <div className="bg-[#303237] text-white rounded-xl flex-1 p-4"> + {SelectedSkillComponent ? ( + <SelectedSkillComponent + skill={configurableSkills[selectedSkill]?.skill} + settings={settings} + toggleSkill={toggleAgentSkill} + enabled={agentSkills.includes( + configurableSkills[selectedSkill]?.skill + )} + setHasChanges={setHasChanges} + {...(configurableSkills[selectedSkill] || + defaultSkills[selectedSkill])} + /> + ) : ( + <div className="flex flex-col items-center justify-center h-full text-white/60"> + <Robot size={40} /> + <p className="font-medium">Select an agent skill</p> + </div> + )} + </div> + </div> + </form> + </SkillLayout> + ); +} + +function SkillLayout({ children, hasChanges, handleSubmit, handleCancel }) { + return ( + <div + id="workspace-agent-settings-container" + className="w-screen h-screen overflow-hidden bg-sidebar flex md:mt-0 mt-6" + > + <Sidebar /> + <div + style={{ height: isMobile ? "100%" : "calc(100% - 32px)" }} + className="relative md:ml-[2px] md:mr-[16px] md:my-[16px] md:rounded-[16px] w-full h-full flex" + > + {children} <ContextualSaveBar showing={hasChanges} onSave={handleSubmit} - onCancel={() => setHasChanges(false)} + onCancel={handleCancel} /> </div> </div> @@ -199,7 +309,11 @@ function SkillList({ if (skills.length === 0) return null; return ( - <div className="bg-white/5 text-white min-w-[360px] w-fit rounded-xl"> + <div + className={`bg-white/5 text-white rounded-xl ${ + isMobile ? "w-full" : "min-w-[360px] w-fit" + }`} + > {Object.entries(skills).map(([skill, settings], index) => ( <div key={skill} -- GitLab