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