fix: update Gmail icon to Google and improve ListSelectionComponent styles (#7591)

* fix: update Gmail icon to Google and improve ListSelectionComponent styles

* fix: remove unnecessary info and improve required field handling in Composio components

* style: update ListSelectionComponent and SortableListItem for improved layout and styling

* fix: enhance ListSelectionComponent and SortableListComponent to support search functionality

* style: adjust height and padding in SortableListItem for better visual consistency

*  (intComponent.spec.ts): update test assertions to match expected behavior after changes in the component's functionality

---------

Co-authored-by: cristhianzl <cristhian.lousa@gmail.com>
This commit is contained in:
Deon Sanchez 2025-04-14 17:08:43 -06:00 committed by GitHub
commit 28675d873f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 64 additions and 45 deletions

View file

@ -38,7 +38,6 @@ class ComposioBaseComponent(Component):
name="api_key",
display_name="Composio API Key",
required=True,
info="Refer to https://docs.composio.dev/faq/api_key/api_key",
real_time_refresh=True,
value="COMPOSIO_API_KEY",
),
@ -53,12 +52,11 @@ class ComposioBaseComponent(Component):
placeholder="Select action",
options=[],
value="disabled",
info="Select action to pass to the agent",
helper_text="Please connect before selecting actions.",
helper_text_metadata={"variant": "destructive"},
show=True,
required=False,
real_time_refresh=True,
required=True,
limit=1,
),
]

View file

@ -16,9 +16,8 @@ class ComposioGmailAPIComponent(ComposioBaseComponent):
"""Gmail API component for interacting with Gmail services."""
display_name: str = "Gmail"
description: str = "Gmail API"
name = "GmailAPI"
icon = "Gmail"
icon = "Google"
documentation: str = "https://docs.composio.dev"
app_name = "gmail"

View file

@ -1,7 +1,9 @@
import ForwardedIconComponent from "@/components/common/genericIconComponent";
import ShadTooltip from "@/components/common/shadTooltipComponent";
import SearchBarComponent from "@/components/core/parameterRenderComponent/components/searchBarComponent";
import { InputProps } from "@/components/core/parameterRenderComponent/types";
import { Button } from "@/components/ui/button";
import { DialogHeader } from "@/components/ui/dialog";
import { Dialog, DialogContent } from "@/components/ui/dialog-with-no-close";
import { cn, testIdCase } from "@/utils/utils";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
@ -64,8 +66,9 @@ const ListItem = ({
unstyled
size="sm"
className={cn(
"group w-full rounded-md py-3 pl-3 pr-3",
"group flex w-full rounded-md px-2 py-0.5",
!isKeyboardNavActive && "hover:bg-muted", // Only apply hover styles when not in keyboard nav
!item.metaData && "py-2.5",
isFocused && "bg-muted",
className,
)}
@ -85,21 +88,30 @@ const ListItem = ({
>
<div className="flex w-full items-center gap-2">
{item.icon && (
<ForwardedIconComponent name={item.icon} className="h-5 w-5" />
)}
<div className="truncate text-sm">{item.name}</div>
{"metaData" in item && item.metaData && (
<div className="text-gray-500">{item.metaData}</div>
<div>
<ForwardedIconComponent name={item.icon} className="mr-2 h-4 w-4" />
</div>
)}
<div className="flex w-full flex-col truncate">
<div className="flex w-full truncate text-[13px] font-semibold">
<span className="truncate">{item.name}</span>
</div>
{"metaData" in item && item.metaData && (
<div className="flex w-full truncate text-[13px] text-gray-500">
<span className="truncate">{item.metaData}</span>
</div>
)}
</div>
{isHovered || isFocused ? (
<div className="ml-auto flex items-center justify-start rounded-md">
<div className="flex items-center pr-1.5 text-sm text-muted-foreground">
<div className="flex items-center pr-1.5 text-[13px] font-semibold text-muted-foreground">
Select
</div>
<div className="flex items-center justify-center rounded-md bg-border p-1">
<div className="flex items-center justify-center rounded-md">
<ForwardedIconComponent
name="corner-down-left"
className="h-3 w-3 text-muted-foreground"
className="h-3.5 w-3.5 text-muted-foreground"
/>
</div>
</div>
@ -129,7 +141,9 @@ const ListSelectionComponent = ({
selectedList = [],
options,
limit = 1,
}: ListSelectionComponentProps) => {
...baseInputProps
}: InputProps<any, ListSelectionComponentProps>) => {
const { nodeClass } = baseInputProps;
const [search, setSearch] = useState("");
const [hoveredItem, setHoveredItem] = useState<any | null>(null);
const [focusedIndex, setFocusedIndex] = useState<number>(-1);
@ -263,28 +277,33 @@ const ListSelectionComponent = ({
return (
<Dialog open={open} onOpenChange={(isOpen) => !isOpen && onClose()}>
<DialogContent
className="flex max-h-[65vh] min-h-[15vh] flex-col rounded-xl"
className="flex max-h-[65vh] min-h-[15vh] flex-col rounded-xl p-0"
onKeyDown={handleKeyDown}
>
<div className="flex items-center justify-between">
<SearchBarComponent
searchCategories={searchCategories}
search={search}
setSearch={setSearch}
/>
<Button
unstyled
size="icon"
className="ml-auto h-[38px]"
onClick={onClose}
>
<ForwardedIconComponent name="x" />
</Button>
</div>
<DialogHeader className="flex w-full justify-between border-b px-3 py-3">
<div className="flex items-center gap-2">
<ForwardedIconComponent
name={nodeClass?.icon || "unknown"}
className="h-[18px] w-[18px] text-muted-foreground"
/>
<div className="text-[13px] font-semibold">
{nodeClass?.display_name}
</div>
</div>
</DialogHeader>
{(filteredList?.length > 20 || search) && (
<div className="flex w-full items-center justify-between px-3">
<SearchBarComponent
searchCategories={searchCategories}
search={search}
setSearch={setSearch}
/>
</div>
)}
<div
ref={listContainerRef}
className="flex flex-col gap-1 overflow-y-auto"
className="flex w-full flex-col gap-1 overflow-y-auto px-3 pb-3"
>
{filteredList.length > 0 ? (
filteredList.map((item, index) => (

View file

@ -152,6 +152,7 @@ export default function NodeInputField({
title,
nodeId: data.id,
isFlexView,
required,
})}
</span>
}
@ -165,13 +166,13 @@ export default function NodeInputField({
title,
nodeId: data.id,
isFlexView,
required,
})}
</span>
}
</span>
</div>
)}
<span className={"text-status-red"}>{required ? "*" : ""}</span>
<div>
{info !== "" && (
<ShadTooltip content={<NodeInputInfo info={info} />}>

View file

@ -74,6 +74,8 @@ const RenderInputParameters = ({
return keyMap;
}, [templateFields, data.id, data.node?.template]);
console.log({ data });
const renderInputParameter = templateFields.map(
(templateField: string, idx) => {
const template = data.node?.template[templateField];

View file

@ -250,8 +250,6 @@ function GenericNode({
[data.node?.outputs],
);
console.log(shownOutputs, hiddenOutputs);
const [hasChangedNodeDescription, setHasChangedNodeDescription] =
useState(false);

View file

@ -236,6 +236,7 @@ const ConnectionComponent = ({
setSelectedList={setSelectedItem}
selectedList={selectedItem}
options={options}
{...baseInputProps}
/>
</div>
);

View file

@ -35,7 +35,7 @@ const SearchBarComponent = ({
};
return (
<div className="mr-10 flex w-full items-center rounded-md border">
<div className="flex w-full items-center rounded-md border">
{searchCategories && searchCategories.length > 0 && (
<DropdownMenu>
<DropdownMenuTrigger asChild>

View file

@ -33,7 +33,7 @@ const SortableListItem = memo(
<li
className={cn(
"inline-flex h-12 w-full items-center gap-2 text-sm font-medium text-gray-800",
limit === 1 ? "h-10 rounded-md bg-muted" : "group cursor-grab",
limit === 1 ? "h-6 rounded-md bg-muted" : "group cursor-grab",
)}
>
{limit !== 1 && (
@ -52,8 +52,8 @@ const SortableListItem = memo(
<span
className={cn(
"truncate text-primary",
limit === 1 ? "max-w-56 pl-3" : "max-w-48",
"truncate text-muted-foreground",
limit === 1 ? "max-w-56 pl-2" : "max-w-48",
)}
>
{data.name}
@ -63,9 +63,9 @@ const SortableListItem = memo(
size="icon"
variant={limit !== 1 ? "outline" : "ghost"}
className={cn(
"ml-auto h-7 w-7 opacity-0 transition-opacity duration-200",
"ml-auto h-6 w-6 opacity-0 transition-opacity duration-200",
limit === 1
? "group pr-3 opacity-100"
? "group pr-1 opacity-100"
: "hover:border hover:border-destructive hover:bg-transparent hover:opacity-100",
)}
onClick={onRemove}
@ -192,6 +192,7 @@ const SortableListComponent = ({
selectedList={listData}
options={options}
limit={limit}
{...baseInputProps}
/>
</div>
);

View file

@ -35,7 +35,7 @@ const DialogContent = React.forwardRef<
<DialogPrimitive.Content
ref={ref}
className={cn(
"fixed left-1/2 top-1/2 z-50 grid w-full max-w-lg -translate-x-1/2 -translate-y-1/2 gap-4 rounded-xl border bg-background p-6 shadow-lg duration-200 data-[state=closed]:animate-contentHide data-[state=open]:animate-contentShow",
"fixed left-1/2 top-1/2 z-50 grid w-full max-w-lg -translate-x-1/2 -translate-y-1/2 gap-3 rounded-xl border bg-background p-3 shadow-lg duration-200 data-[state=closed]:animate-contentHide data-[state=open]:animate-contentShow",
className,
)}
{...props}

View file

@ -88,7 +88,7 @@ test("IntComponent", { tag: ["@release", "@workspace"] }, async ({ page }) => {
await page.locator('//*[@id="showtemperature"]').click();
expect(
await page.locator('//*[@id="showtemperature"]').isChecked(),
).toBeTruthy();
).toBeFalsy();
await page.locator('//*[@id="showmodel_kwargs"]').click();
expect(
@ -108,7 +108,7 @@ test("IntComponent", { tag: ["@release", "@workspace"] }, async ({ page }) => {
await page.locator('//*[@id="showtemperature"]').click();
expect(
await page.locator('//*[@id="showtemperature"]').isChecked(),
).toBeFalsy();
).toBeTruthy();
await page.locator('//*[@id="showmodel_kwargs"]').click();
expect(
@ -128,7 +128,7 @@ test("IntComponent", { tag: ["@release", "@workspace"] }, async ({ page }) => {
await page.locator('//*[@id="showtemperature"]').click();
expect(
await page.locator('//*[@id="showtemperature"]').isChecked(),
).toBeTruthy();
).toBeFalsy();
await page.getByText("Close").last().click();