From 57ecc10535ed9900a8b79554dca1841b67154c8b Mon Sep 17 00:00:00 2001 From: Ubbe Date: Wed, 3 Sep 2025 15:58:07 +0900 Subject: [PATCH] fix(frontend): typed inputs in new run modal (#10799) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Changes 🏗️ ### Make the **Credentials Inputs** show up on the new Run Agent Modal Screenshot 2025-09-02 at 00 54 19 ### Fixes on other modals... Screenshot 2025-09-02 at 00 04 40 Screenshot 2025-09-02 at 00 04 44 Screenshot 2025-09-02 at 00 47 06 - always use buttons/inputs in small size ( _due to the tight space_ ) - use from the design system - always use pretty scrollbars - Configure [`tailwind-scrollbars`](https://github.com/adoxography/tailwind-scrollbar) for pretty scrollbars - prevent content in dialog to overflow when scrollable ### Checklist 📋 #### For code changes: - [x] I have clearly listed my changes in the PR description - [x] I have made a test plan - [x] I have tested my changes according to the test plan: - [x] Run the app locally with the new agent run modal flag enabled - [x] Check the above #### For configuration changes: None --- autogpt_platform/frontend/package.json | 1 + autogpt_platform/frontend/pnpm-lock.yaml | 32 +++++ .../APIKeyCredentialsModal.tsx | 109 +++++++--------- .../CredentialsInputs/CredentialsInputs.tsx | 19 ++- .../HotScopedCredentialsModal.tsx | 117 +++++++++--------- .../PasswordCredentialsModal.tsx | 106 +++++++--------- .../RunAgentInputs/RunAgentInputs.tsx | 7 ++ .../RunAgentModal/RunAgentModal.tsx | 81 +++++++----- .../AgentInputFields/AgentInputFields.tsx | 51 -------- .../DefaultRunView/DefaultRunView.tsx | 2 + .../RunAgentModal/useAgentRunModal.ts | 23 +++- autogpt_platform/frontend/src/app/globals.css | 2 - .../frontend/src/components/CustomNode.tsx | 8 +- .../src/components/atoms/Input/Input.tsx | 6 +- .../AgentSelectStep/AgentSelectStep.tsx | 7 +- .../Dialog/components/BaseFooter.tsx | 3 + .../Dialog/components/DialogWrap.tsx | 46 +++++-- .../Dialog/components/DrawerWrap.tsx | 5 +- .../Dialog/components/styles.module.css | 43 ------- .../molecules/Dialog/components/styles.ts | 4 +- .../src/components/styles/scrollbars.ts | 2 + .../src/components/ui/multiselect.tsx | 2 +- autogpt_platform/frontend/tailwind.config.ts | 3 +- 23 files changed, 332 insertions(+), 347 deletions(-) delete mode 100644 autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/AgentRunsView/components/RunAgentModal/components/AgentInputFields/AgentInputFields.tsx delete mode 100644 autogpt_platform/frontend/src/components/molecules/Dialog/components/styles.module.css create mode 100644 autogpt_platform/frontend/src/components/styles/scrollbars.ts diff --git a/autogpt_platform/frontend/package.json b/autogpt_platform/frontend/package.json index 78bdf98083..b3cfa3dcf7 100644 --- a/autogpt_platform/frontend/package.json +++ b/autogpt_platform/frontend/package.json @@ -89,6 +89,7 @@ "shepherd.js": "14.5.1", "sonner": "2.0.7", "tailwind-merge": "2.6.0", + "tailwind-scrollbar": "4.0.2", "tailwindcss-animate": "1.0.7", "uuid": "11.1.0", "vaul": "1.1.2", diff --git a/autogpt_platform/frontend/pnpm-lock.yaml b/autogpt_platform/frontend/pnpm-lock.yaml index f0da34d230..3eeff7e535 100644 --- a/autogpt_platform/frontend/pnpm-lock.yaml +++ b/autogpt_platform/frontend/pnpm-lock.yaml @@ -200,6 +200,9 @@ importers: tailwind-merge: specifier: 2.6.0 version: 2.6.0 + tailwind-scrollbar: + specifier: 4.0.2 + version: 4.0.2(react@18.3.1)(tailwindcss@3.4.17) tailwindcss-animate: specifier: 1.0.7 version: 1.0.7(tailwindcss@3.4.17) @@ -2930,6 +2933,9 @@ packages: '@types/phoenix@1.6.6': resolution: {integrity: sha512-PIzZZlEppgrpoT2QgbnDU+MMzuR6BbCjllj0bM70lWoejMeNJAxCchxnv7J3XFkI8MpygtRpzXrIlmWUBclP5A==} + '@types/prismjs@1.26.5': + resolution: {integrity: sha512-AUZTa7hQ2KY5L7AmtSiqxlhWxb4ina0yd8hNbl4TWuqnv/pFP0nDMb3YrfSBf4hJVGLh2YEIBfKaBW/9UEl6IQ==} + '@types/prop-types@15.7.15': resolution: {integrity: sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==} @@ -5909,6 +5915,11 @@ packages: resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + prism-react-renderer@2.4.1: + resolution: {integrity: sha512-ey8Ls/+Di31eqzUxC46h8MksNuGx/n0AAC8uKpwFau4RPDYLuE3EXTp8N8G2vX2N7UC/+IXeNUnlWBGGcAG+Ig==} + peerDependencies: + react: '>=16.0.0' + process-nextick-args@2.0.1: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} @@ -6612,6 +6623,12 @@ packages: tailwind-merge@2.6.0: resolution: {integrity: sha512-P+Vu1qXfzediirmHOC3xKGAYeZtPcV9g76X+xg2FD4tYgR71ewMA35Y3sCz3zhiN/dwefRpJX0yBcgwi1fXNQA==} + tailwind-scrollbar@4.0.2: + resolution: {integrity: sha512-wAQiIxAPqk0MNTPptVe/xoyWi27y+NRGnTwvn4PQnbvB9kp8QUBiGl/wsfoVBHnQxTmhXJSNt9NHTmcz9EivFA==} + engines: {node: '>=12.13.0'} + peerDependencies: + tailwindcss: 4.x + tailwindcss-animate@1.0.7: resolution: {integrity: sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==} peerDependencies: @@ -10211,6 +10228,8 @@ snapshots: '@types/phoenix@1.6.6': {} + '@types/prismjs@1.26.5': {} + '@types/prop-types@15.7.15': {} '@types/react-dom@18.3.5(@types/react@18.3.17)': @@ -13581,6 +13600,12 @@ snapshots: ansi-styles: 5.2.0 react-is: 17.0.2 + prism-react-renderer@2.4.1(react@18.3.1): + dependencies: + '@types/prismjs': 1.26.5 + clsx: 2.1.1 + react: 18.3.1 + process-nextick-args@2.0.1: {} process@0.11.10: {} @@ -14465,6 +14490,13 @@ snapshots: tailwind-merge@2.6.0: {} + tailwind-scrollbar@4.0.2(react@18.3.1)(tailwindcss@3.4.17): + dependencies: + prism-react-renderer: 2.4.1(react@18.3.1) + tailwindcss: 3.4.17 + transitivePeerDependencies: + - react + tailwindcss-animate@1.0.7(tailwindcss@3.4.17): dependencies: tailwindcss: 3.4.17 diff --git a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/AgentRunsView/components/APIKeyCredentialsModal/APIKeyCredentialsModal.tsx b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/AgentRunsView/components/APIKeyCredentialsModal/APIKeyCredentialsModal.tsx index 0e30e3afe4..4a6ca3beb7 100644 --- a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/AgentRunsView/components/APIKeyCredentialsModal/APIKeyCredentialsModal.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/AgentRunsView/components/APIKeyCredentialsModal/APIKeyCredentialsModal.tsx @@ -1,15 +1,7 @@ import { Input } from "@/components/atoms/Input/Input"; import { Button } from "@/components/atoms/Button/Button"; import { Dialog } from "@/components/molecules/Dialog/Dialog"; -import { - Form, - FormControl, - FormDescription, - FormField, - FormItem, - FormLabel, - FormMessage, -} from "@/components/ui/form"; +import { Form, FormDescription, FormField } from "@/components/ui/form"; import { BlockIOCredentialsSubSchema, CredentialsMetaInput, @@ -54,6 +46,9 @@ export function APIKeyCredentialsModal({ }, }} onClose={onClose} + styling={{ + maxWidth: "25rem", + }} > {schemaDescription && ( @@ -61,79 +56,65 @@ export function APIKeyCredentialsModal({ )}
- + ( - - API Key - {schema.credentials_scopes && ( - - Required scope(s) for this block:{" "} - {schema.credentials_scopes?.map((s, i, a) => ( - - {s} - {i < a.length - 1 && ", "} - - ))} - - )} - - - - - + <> + + Required scope(s) for this block:{" "} + {schema.credentials_scopes?.map((s, i, a) => ( + + {s} + {i < a.length - 1 && ", "} + + ))} + + ) : null + } + {...field} + /> + )} /> ( - - Name - - - - - + )} /> ( - - Expiration Date (Optional) - - - - - + )} /> - diff --git a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/AgentRunsView/components/CredentialsInputs/CredentialsInputs.tsx b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/AgentRunsView/components/CredentialsInputs/CredentialsInputs.tsx index 0f6d824e4c..71be8f7da9 100644 --- a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/AgentRunsView/components/CredentialsInputs/CredentialsInputs.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/AgentRunsView/components/CredentialsInputs/CredentialsInputs.tsx @@ -335,30 +335,39 @@ export const CredentialsInput: FC<{ // Show credentials creation UI when no relevant credentials exist if (!hasRelevantCredentials) { return ( -
+
{fieldHeader}
{supportsOAuth2 && ( - )} {supportsApiKey && ( - )} {supportsUserPassword && ( - )} {supportsHostScoped && credentials.discriminatorValue && ( - diff --git a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/AgentRunsView/components/HotScopedCredentialsModal/HotScopedCredentialsModal.tsx b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/AgentRunsView/components/HotScopedCredentialsModal/HotScopedCredentialsModal.tsx index c9bd5a3fbc..ba16a76d85 100644 --- a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/AgentRunsView/components/HotScopedCredentialsModal/HotScopedCredentialsModal.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/AgentRunsView/components/HotScopedCredentialsModal/HotScopedCredentialsModal.tsx @@ -7,12 +7,9 @@ import { Button } from "@/components/atoms/Button/Button"; import { Dialog } from "@/components/molecules/Dialog/Dialog"; import { Form, - FormControl, FormDescription, FormField, - FormItem, FormLabel, - FormMessage, } from "@/components/ui/form"; import useCredentials from "@/hooks/useCredentials"; import { @@ -20,6 +17,7 @@ import { CredentialsMetaInput, } from "@/lib/autogpt-server-api/types"; import { getHostFromUrl } from "@/lib/utils/url"; +import { PlusIcon, TrashIcon } from "@phosphor-icons/react"; type Props = { schema: BlockIOCredentialsSubSchema; @@ -139,6 +137,9 @@ export function HostScopedCredentialsModal({ }, }} onClose={onClose} + styling={{ + maxWidth: "25rem", + }} > {schema.description && ( @@ -146,81 +147,74 @@ export function HostScopedCredentialsModal({ )}
- + ( - - Host Pattern - - {currentHost + - - - - - + : "Enter the host/domain to match against request URLs (e.g., api.example.com)." + } + placeholder={ + currentHost + ? undefined + : "Enter host (e.g., api.example.com)" + } + {...field} + /> )} />
Headers - + Add sensitive headers (like Authorization, X-API-Key) that should be automatically included in requests to the specified host. {headerPairs.map((pair, index) => ( -
-
- - updateHeaderPair(index, "key", e.target.value) - } - /> -
-
- - updateHeaderPair(index, "value", e.target.value) - } - /> -
+
+ + updateHeaderPair(index, "key", e.target.value) + } + /> + + + updateHeaderPair(index, "value", e.target.value) + } + />
))} @@ -230,15 +224,16 @@ export function HostScopedCredentialsModal({ variant="outline" size="small" onClick={addHeaderPair} - className="w-full" > - Add Another Header + Add Another Header
- +
+ +
diff --git a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/AgentRunsView/components/PasswordCredentialsModal/PasswordCredentialsModal.tsx b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/AgentRunsView/components/PasswordCredentialsModal/PasswordCredentialsModal.tsx index 8196a0fa24..7052da9f3c 100644 --- a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/AgentRunsView/components/PasswordCredentialsModal/PasswordCredentialsModal.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/AgentRunsView/components/PasswordCredentialsModal/PasswordCredentialsModal.tsx @@ -1,22 +1,10 @@ import { z } from "zod"; import { useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; -import { Input } from "@/components/ui/input"; -import { Button } from "@/components/ui/button"; -import { - Dialog, - DialogContent, - DialogHeader, - DialogTitle, -} from "@/components/ui/dialog"; -import { - Form, - FormControl, - FormField, - FormItem, - FormLabel, - FormMessage, -} from "@/components/ui/form"; +import { Input } from "@/components/atoms/Input/Input"; +import { Button } from "@/components/atoms/Button/Button"; +import { Dialog } from "@/components/molecules/Dialog/Dialog"; +import { Form, FormField } from "@/components/ui/form"; import useCredentials from "@/hooks/useCredentials"; import { BlockIOCredentialsSubSchema, @@ -81,76 +69,72 @@ export function PasswordCredentialsModal({ return ( { - if (!open) onClose(); + title={`Add new username & password for ${providerName}`} + controlled={{ + isOpen: open, + set: (isOpen) => { + if (!isOpen) onClose(); + }, + }} + onClose={onClose} + styling={{ + maxWidth: "25rem", }} > - - - - Add new username & password for {providerName} - - +
- + ( - - Username - - - - - + )} /> ( - - Password - - - - - + )} /> ( - - Name - - - - - + )} /> - -
+
); } diff --git a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/AgentRunsView/components/RunAgentInputs/RunAgentInputs.tsx b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/AgentRunsView/components/RunAgentInputs/RunAgentInputs.tsx index 4f03d66d24..cce02ec909 100644 --- a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/AgentRunsView/components/RunAgentInputs/RunAgentInputs.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/AgentRunsView/components/RunAgentInputs/RunAgentInputs.tsx @@ -56,6 +56,7 @@ export function RunAgentInputs({ id={`${baseId}-number`} label={schema.title ?? placeholder ?? "Number"} hideLabel + size="small" type="number" value={value ?? ""} placeholder={placeholder || "Enter number"} @@ -73,6 +74,7 @@ export function RunAgentInputs({ id={`${baseId}-textarea`} label={schema.title ?? placeholder ?? "Text"} hideLabel + size="small" type="textarea" rows={3} value={value ?? ""} @@ -105,6 +107,7 @@ export function RunAgentInputs({ id={`${baseId}-date`} label={schema.title ?? placeholder ?? "Date"} hideLabel + size="small" type="date" value={value ? format(value as Date, "yyyy-MM-dd") : ""} onChange={(e) => { @@ -133,6 +136,7 @@ export function RunAgentInputs({ id={`${baseId}-datetime`} label={schema.title ?? placeholder ?? "Date time"} hideLabel + size="small" type="datetime-local" value={value ?? ""} onChange={(e) => onChange((e.target as HTMLInputElement).value)} @@ -167,6 +171,7 @@ export function RunAgentInputs({ label={schema.title ?? placeholder ?? "Select"} hideLabel value={value ?? ""} + size="small" onValueChange={(val: string) => onChange(val)} placeholder={placeholder || "Select an option"} options={schema.enum @@ -189,6 +194,7 @@ export function RunAgentInputs({ items={allKeys.map((key) => ({ value: key, label: _schema.properties[key]?.title ?? key, + size: "small", }))} selectedValues={selectedValues} onChange={(values: string[]) => @@ -212,6 +218,7 @@ export function RunAgentInputs({ id={`${baseId}-text`} label={schema.title ?? placeholder ?? "Text"} hideLabel + size="small" type="text" value={value ?? ""} onChange={(e) => onChange((e.target as HTMLInputElement).value)} diff --git a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/AgentRunsView/components/RunAgentModal/RunAgentModal.tsx b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/AgentRunsView/components/RunAgentModal/RunAgentModal.tsx index be22f238d4..6e51cb9e9e 100644 --- a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/AgentRunsView/components/RunAgentModal/RunAgentModal.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/AgentRunsView/components/RunAgentModal/RunAgentModal.tsx @@ -26,28 +26,45 @@ interface Props { export function RunAgentModal({ triggerSlot, agent }: Props) { const { + // UI state isOpen, setIsOpen, showScheduleView, + + // Run mode defaultRunType, + + // Form: regular inputs inputValues, setInputValues, + + // Form: credentials inputCredentials, setInputCredentials, + + // Preset/trigger labels presetName, presetDescription, setPresetName, setPresetDescription, + + // Scheduling scheduleName, cronExpression, + + // Validation/readiness allRequiredInputsAreSet, - // agentInputFields, // Available if needed for future use + + // Schemas agentInputFields, agentCredentialsInputFields, - hasInputFields, + + // Async states isExecuting, isCreatingSchedule, isSettingUpTrigger, + + // Actions handleRun, handleSchedule, handleShowSchedule, @@ -58,6 +75,10 @@ export function RunAgentModal({ triggerSlot, agent }: Props) { const [isScheduleFormValid, setIsScheduleFormValid] = useState(true); + const hasAnySetupFields = + Object.keys(agentInputFields || {}).length > 0 || + Object.keys(agentCredentialsInputFields || {}).length > 0; + function handleInputChange(key: string, value: string) { setInputValues((prev) => ({ ...prev, @@ -97,7 +118,7 @@ export function RunAgentModal({ triggerSlot, agent }: Props) { > {triggerSlot} -
+
{/* Header */}
@@ -105,13 +126,10 @@ export function RunAgentModal({ triggerSlot, agent }: Props) {
{/* Scrollable content */} -
+
{/* Setup Section */}
- {hasInputFields ? ( + {hasAnySetupFields ? (
- - {/* Fixed Actions - sticky inside dialog scroll */} - - {showScheduleView ? ( - - ) : ( - - )} -
+ + {showScheduleView ? ( + + ) : ( + + )} + diff --git a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/AgentRunsView/components/RunAgentModal/components/AgentInputFields/AgentInputFields.tsx b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/AgentRunsView/components/RunAgentModal/components/AgentInputFields/AgentInputFields.tsx deleted file mode 100644 index e6ce7c1147..0000000000 --- a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/AgentRunsView/components/RunAgentModal/components/AgentInputFields/AgentInputFields.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import { Input } from "@/components/atoms/Input/Input"; -import { LibraryAgent } from "@/app/api/__generated__/models/libraryAgent"; - -interface Props { - agent: LibraryAgent; - inputValues: Record; - onInputChange: (key: string, value: string) => void; - variant?: "default" | "schedule"; -} - -export function AgentInputFields({ - agent, - inputValues, - onInputChange, - variant = "default", -}: Props) { - const hasInputFields = - agent.input_schema && - typeof agent.input_schema === "object" && - "properties" in agent.input_schema; - - if (!hasInputFields) { - const emptyStateClass = - variant === "schedule" - ? "rounded-lg bg-neutral-50 p-4 text-sm text-neutral-500" - : "p-4 text-sm text-neutral-500"; - - return ( -
- No input fields required for this agent -
- ); - } - - return ( - <> - {Object.entries((agent.input_schema as any).properties || {}).map( - ([key, schema]: [string, any]) => ( - onInputChange(key, e.target.value)} - placeholder={schema.description} - /> - ), - )} - - ); -} diff --git a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/AgentRunsView/components/RunAgentModal/components/DefaultRunView/DefaultRunView.tsx b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/AgentRunsView/components/RunAgentModal/components/DefaultRunView/DefaultRunView.tsx index 7a70b5a9d4..9bd27dda48 100644 --- a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/AgentRunsView/components/RunAgentModal/components/DefaultRunView/DefaultRunView.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/AgentRunsView/components/RunAgentModal/components/DefaultRunView/DefaultRunView.tsx @@ -36,6 +36,7 @@ export function DefaultRunView() { -
{inputWithError} diff --git a/autogpt_platform/frontend/src/components/contextual/PublishAgentModal/components/AgentSelectStep/AgentSelectStep.tsx b/autogpt_platform/frontend/src/components/contextual/PublishAgentModal/components/AgentSelectStep/AgentSelectStep.tsx index 5361eca22a..4c3360be71 100644 --- a/autogpt_platform/frontend/src/components/contextual/PublishAgentModal/components/AgentSelectStep/AgentSelectStep.tsx +++ b/autogpt_platform/frontend/src/components/contextual/PublishAgentModal/components/AgentSelectStep/AgentSelectStep.tsx @@ -6,6 +6,8 @@ import { Button } from "../../../../atoms/Button/Button"; import { StepHeader } from "../StepHeader"; import { Skeleton } from "@/components/ui/skeleton"; import { useAgentSelectStep } from "./useAgentSelectStep"; +import { scrollbarStyles } from "@/components/styles/scrollbars"; +import { cn } from "@/lib/utils"; interface Props { onSelect: (agentId: string, agentVersion: number) => void; @@ -110,7 +112,10 @@ export function AgentSelectStep({

List of agents

diff --git a/autogpt_platform/frontend/src/components/molecules/Dialog/components/BaseFooter.tsx b/autogpt_platform/frontend/src/components/molecules/Dialog/components/BaseFooter.tsx index ce730569c8..3ed1157b6c 100644 --- a/autogpt_platform/frontend/src/components/molecules/Dialog/components/BaseFooter.tsx +++ b/autogpt_platform/frontend/src/components/molecules/Dialog/components/BaseFooter.tsx @@ -4,12 +4,14 @@ interface Props { children: React.ReactNode; testId?: string; className?: string; + style?: React.CSSProperties; } export function BaseFooter({ children, testId = "modal-footer", className = "", + style, }: Props) { const ctx = useDialogCtx(); @@ -17,6 +19,7 @@ export function BaseFooter({
{children}
diff --git a/autogpt_platform/frontend/src/components/molecules/Dialog/components/DialogWrap.tsx b/autogpt_platform/frontend/src/components/molecules/Dialog/components/DialogWrap.tsx index 23797ea18b..40089726dc 100644 --- a/autogpt_platform/frontend/src/components/molecules/Dialog/components/DialogWrap.tsx +++ b/autogpt_platform/frontend/src/components/molecules/Dialog/components/DialogWrap.tsx @@ -1,11 +1,16 @@ import { cn } from "@/lib/utils"; import { X } from "@phosphor-icons/react"; import * as RXDialog from "@radix-ui/react-dialog"; -import { CSSProperties, PropsWithChildren } from "react"; +import { + CSSProperties, + PropsWithChildren, + useEffect, + useRef, + useState, +} from "react"; import { DialogCtx } from "../useDialogCtx"; import { modalStyles } from "./styles"; -import styles from "./styles.module.css"; -import { Button } from "@/components/atoms/Button/Button"; +import { scrollbarStyles } from "@/components/styles/scrollbars"; type BaseProps = DialogCtx & PropsWithChildren; @@ -22,6 +27,25 @@ export function DialogWrap({ isForceOpen, handleClose, }: Props) { + const scrollRef = useRef(null); + const [hasVerticalScrollbar, setHasVerticalScrollbar] = useState(false); + + useEffect(() => { + function update() { + const el = scrollRef.current; + if (!el) return; + setHasVerticalScrollbar(el.scrollHeight > el.clientHeight + 1); + } + update(); + const ro = new ResizeObserver(update); + if (scrollRef.current) ro.observe(scrollRef.current); + window.addEventListener("resize", update); + return () => { + ro.disconnect(); + window.removeEventListener("resize", update); + }; + }, []); + return ( @@ -51,17 +75,23 @@ export function DialogWrap({ )} {isForceOpen && !handleClose ? null : ( - + )}
-
+
{children}
diff --git a/autogpt_platform/frontend/src/components/molecules/Dialog/components/DrawerWrap.tsx b/autogpt_platform/frontend/src/components/molecules/Dialog/components/DrawerWrap.tsx index f3e56986fd..3a830c10f6 100644 --- a/autogpt_platform/frontend/src/components/molecules/Dialog/components/DrawerWrap.tsx +++ b/autogpt_platform/frontend/src/components/molecules/Dialog/components/DrawerWrap.tsx @@ -4,7 +4,6 @@ import { PropsWithChildren } from "react"; import { Drawer } from "vaul"; import { DialogCtx } from "../useDialogCtx"; import { drawerStyles, modalStyles } from "./styles"; -import styles from "./styles.module.css"; type BaseProps = DialogCtx & PropsWithChildren; @@ -62,9 +61,7 @@ export function DrawerWrap({ ) ) : null}
-
- {children} -
+
{children}
); diff --git a/autogpt_platform/frontend/src/components/molecules/Dialog/components/styles.module.css b/autogpt_platform/frontend/src/components/molecules/Dialog/components/styles.module.css deleted file mode 100644 index 51040dbc15..0000000000 --- a/autogpt_platform/frontend/src/components/molecules/Dialog/components/styles.module.css +++ /dev/null @@ -1,43 +0,0 @@ -/* Scrollable content area for dialogs */ -.scrollableContent { - scrollbar-width: thin; - scrollbar-color: rgb(209, 213, 219) white; -} - -/* Webkit scrollbar styles */ -.scrollableContent::-webkit-scrollbar { - width: 8px; -} - -.scrollableContent::-webkit-scrollbar-track { - background: white; - border-radius: 4px; -} - -.scrollableContent::-webkit-scrollbar-thumb { - background: rgb(209, 213, 219); /* gray-300 */ - border-radius: 4px; -} - -.scrollableContent::-webkit-scrollbar-thumb:hover { - background: rgb(156, 163, 175); /* gray-400 */ -} - -/* Dark mode support */ -@media (prefers-color-scheme: dark) { - .scrollableContent { - scrollbar-color: rgb(107, 114, 128) rgb(31, 41, 55); - } - - .scrollableContent::-webkit-scrollbar-track { - background: rgb(31, 41, 55); - } - - .scrollableContent::-webkit-scrollbar-thumb { - background: rgb(107, 114, 128); /* gray-500 */ - } - - .scrollableContent::-webkit-scrollbar-thumb:hover { - background: rgb(75, 85, 99); /* gray-600 */ - } -} diff --git a/autogpt_platform/frontend/src/components/molecules/Dialog/components/styles.ts b/autogpt_platform/frontend/src/components/molecules/Dialog/components/styles.ts index e35fce8926..b04dcdd193 100644 --- a/autogpt_platform/frontend/src/components/molecules/Dialog/components/styles.ts +++ b/autogpt_platform/frontend/src/components/molecules/Dialog/components/styles.ts @@ -4,13 +4,13 @@ const commonStyles = { overlay: "fixed inset-0 z-50 bg-stone-500/20 dark:bg-black/50 backdrop-blur-md animate-fade-in", content: - "bg-white p-6 fixed rounded-2xlarge flex flex-col z-50 w-full overflow-hidden", + "overflow-y-hidden bg-white p-6 fixed rounded-2xlarge flex flex-col z-50 w-full", }; // Modal specific styles export const modalStyles = { ...commonStyles, - content: `${commonStyles.content} p-6 border border-stone-200 overflow-y-auto min-w-[40vw] max-w-[60vw] max-h-[95vh] top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 animate-fadein`, + content: `${commonStyles.content} p-6 border border-stone-200 min-w-[40vw] max-w-[60vw] max-h-[95vh] top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 animate-fadein`, iconWrap: "absolute top-2 right-3 bg-transparent p-2 rounded-full transition-colors duration-300 ease-in-out outline-none border-none", icon: "w-4 h-4 text-stone-800", diff --git a/autogpt_platform/frontend/src/components/styles/scrollbars.ts b/autogpt_platform/frontend/src/components/styles/scrollbars.ts new file mode 100644 index 0000000000..5e678dd93d --- /dev/null +++ b/autogpt_platform/frontend/src/components/styles/scrollbars.ts @@ -0,0 +1,2 @@ +export const scrollbarStyles = + "scrollbar-thin scrollbar-thumb-zinc-300 scrollbar-track-transparent"; diff --git a/autogpt_platform/frontend/src/components/ui/multiselect.tsx b/autogpt_platform/frontend/src/components/ui/multiselect.tsx index 8764442621..fe1ea66668 100644 --- a/autogpt_platform/frontend/src/components/ui/multiselect.tsx +++ b/autogpt_platform/frontend/src/components/ui/multiselect.tsx @@ -256,7 +256,7 @@ const MultiSelectorList = forwardRef< diff --git a/autogpt_platform/frontend/tailwind.config.ts b/autogpt_platform/frontend/tailwind.config.ts index 72c0018919..2a0d039b1a 100644 --- a/autogpt_platform/frontend/tailwind.config.ts +++ b/autogpt_platform/frontend/tailwind.config.ts @@ -1,5 +1,6 @@ import type { Config } from "tailwindcss"; import tailwindcssAnimate from "tailwindcss-animate"; +import scrollbar from "tailwind-scrollbar"; import { colors } from "./src/components/styles/colors"; const config = { @@ -157,7 +158,7 @@ const config = { }, }, }, - plugins: [tailwindcssAnimate], + plugins: [tailwindcssAnimate, scrollbar({ nocompatible: true })], } satisfies Config; export default config;