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:
parent
ae2ef5d8e4
commit
28675d873f
11 changed files with 64 additions and 45 deletions
|
|
@ -38,7 +38,6 @@ class ComposioBaseComponent(Component):
|
||||||
name="api_key",
|
name="api_key",
|
||||||
display_name="Composio API Key",
|
display_name="Composio API Key",
|
||||||
required=True,
|
required=True,
|
||||||
info="Refer to https://docs.composio.dev/faq/api_key/api_key",
|
|
||||||
real_time_refresh=True,
|
real_time_refresh=True,
|
||||||
value="COMPOSIO_API_KEY",
|
value="COMPOSIO_API_KEY",
|
||||||
),
|
),
|
||||||
|
|
@ -53,12 +52,11 @@ class ComposioBaseComponent(Component):
|
||||||
placeholder="Select action",
|
placeholder="Select action",
|
||||||
options=[],
|
options=[],
|
||||||
value="disabled",
|
value="disabled",
|
||||||
info="Select action to pass to the agent",
|
|
||||||
helper_text="Please connect before selecting actions.",
|
helper_text="Please connect before selecting actions.",
|
||||||
helper_text_metadata={"variant": "destructive"},
|
helper_text_metadata={"variant": "destructive"},
|
||||||
show=True,
|
show=True,
|
||||||
|
required=False,
|
||||||
real_time_refresh=True,
|
real_time_refresh=True,
|
||||||
required=True,
|
|
||||||
limit=1,
|
limit=1,
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -16,9 +16,8 @@ class ComposioGmailAPIComponent(ComposioBaseComponent):
|
||||||
"""Gmail API component for interacting with Gmail services."""
|
"""Gmail API component for interacting with Gmail services."""
|
||||||
|
|
||||||
display_name: str = "Gmail"
|
display_name: str = "Gmail"
|
||||||
description: str = "Gmail API"
|
|
||||||
name = "GmailAPI"
|
name = "GmailAPI"
|
||||||
icon = "Gmail"
|
icon = "Google"
|
||||||
documentation: str = "https://docs.composio.dev"
|
documentation: str = "https://docs.composio.dev"
|
||||||
app_name = "gmail"
|
app_name = "gmail"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
import ForwardedIconComponent from "@/components/common/genericIconComponent";
|
import ForwardedIconComponent from "@/components/common/genericIconComponent";
|
||||||
import ShadTooltip from "@/components/common/shadTooltipComponent";
|
import ShadTooltip from "@/components/common/shadTooltipComponent";
|
||||||
import SearchBarComponent from "@/components/core/parameterRenderComponent/components/searchBarComponent";
|
import SearchBarComponent from "@/components/core/parameterRenderComponent/components/searchBarComponent";
|
||||||
|
import { InputProps } from "@/components/core/parameterRenderComponent/types";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { DialogHeader } from "@/components/ui/dialog";
|
||||||
import { Dialog, DialogContent } from "@/components/ui/dialog-with-no-close";
|
import { Dialog, DialogContent } from "@/components/ui/dialog-with-no-close";
|
||||||
import { cn, testIdCase } from "@/utils/utils";
|
import { cn, testIdCase } from "@/utils/utils";
|
||||||
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||||
|
|
@ -64,8 +66,9 @@ const ListItem = ({
|
||||||
unstyled
|
unstyled
|
||||||
size="sm"
|
size="sm"
|
||||||
className={cn(
|
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
|
!isKeyboardNavActive && "hover:bg-muted", // Only apply hover styles when not in keyboard nav
|
||||||
|
!item.metaData && "py-2.5",
|
||||||
isFocused && "bg-muted",
|
isFocused && "bg-muted",
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
|
|
@ -85,21 +88,30 @@ const ListItem = ({
|
||||||
>
|
>
|
||||||
<div className="flex w-full items-center gap-2">
|
<div className="flex w-full items-center gap-2">
|
||||||
{item.icon && (
|
{item.icon && (
|
||||||
<ForwardedIconComponent name={item.icon} className="h-5 w-5" />
|
<div>
|
||||||
)}
|
<ForwardedIconComponent name={item.icon} className="mr-2 h-4 w-4" />
|
||||||
<div className="truncate text-sm">{item.name}</div>
|
</div>
|
||||||
{"metaData" in item && item.metaData && (
|
|
||||||
<div className="text-gray-500">{item.metaData}</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 ? (
|
{isHovered || isFocused ? (
|
||||||
<div className="ml-auto flex items-center justify-start rounded-md">
|
<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
|
Select
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center justify-center rounded-md bg-border p-1">
|
<div className="flex items-center justify-center rounded-md">
|
||||||
<ForwardedIconComponent
|
<ForwardedIconComponent
|
||||||
name="corner-down-left"
|
name="corner-down-left"
|
||||||
className="h-3 w-3 text-muted-foreground"
|
className="h-3.5 w-3.5 text-muted-foreground"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -129,7 +141,9 @@ const ListSelectionComponent = ({
|
||||||
selectedList = [],
|
selectedList = [],
|
||||||
options,
|
options,
|
||||||
limit = 1,
|
limit = 1,
|
||||||
}: ListSelectionComponentProps) => {
|
...baseInputProps
|
||||||
|
}: InputProps<any, ListSelectionComponentProps>) => {
|
||||||
|
const { nodeClass } = baseInputProps;
|
||||||
const [search, setSearch] = useState("");
|
const [search, setSearch] = useState("");
|
||||||
const [hoveredItem, setHoveredItem] = useState<any | null>(null);
|
const [hoveredItem, setHoveredItem] = useState<any | null>(null);
|
||||||
const [focusedIndex, setFocusedIndex] = useState<number>(-1);
|
const [focusedIndex, setFocusedIndex] = useState<number>(-1);
|
||||||
|
|
@ -263,28 +277,33 @@ const ListSelectionComponent = ({
|
||||||
return (
|
return (
|
||||||
<Dialog open={open} onOpenChange={(isOpen) => !isOpen && onClose()}>
|
<Dialog open={open} onOpenChange={(isOpen) => !isOpen && onClose()}>
|
||||||
<DialogContent
|
<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}
|
onKeyDown={handleKeyDown}
|
||||||
>
|
>
|
||||||
<div className="flex items-center justify-between">
|
<DialogHeader className="flex w-full justify-between border-b px-3 py-3">
|
||||||
<SearchBarComponent
|
<div className="flex items-center gap-2">
|
||||||
searchCategories={searchCategories}
|
<ForwardedIconComponent
|
||||||
search={search}
|
name={nodeClass?.icon || "unknown"}
|
||||||
setSearch={setSearch}
|
className="h-[18px] w-[18px] text-muted-foreground"
|
||||||
/>
|
/>
|
||||||
<Button
|
<div className="text-[13px] font-semibold">
|
||||||
unstyled
|
{nodeClass?.display_name}
|
||||||
size="icon"
|
</div>
|
||||||
className="ml-auto h-[38px]"
|
</div>
|
||||||
onClick={onClose}
|
</DialogHeader>
|
||||||
>
|
{(filteredList?.length > 20 || search) && (
|
||||||
<ForwardedIconComponent name="x" />
|
<div className="flex w-full items-center justify-between px-3">
|
||||||
</Button>
|
<SearchBarComponent
|
||||||
</div>
|
searchCategories={searchCategories}
|
||||||
|
search={search}
|
||||||
|
setSearch={setSearch}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<div
|
<div
|
||||||
ref={listContainerRef}
|
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.length > 0 ? (
|
||||||
filteredList.map((item, index) => (
|
filteredList.map((item, index) => (
|
||||||
|
|
|
||||||
|
|
@ -152,6 +152,7 @@ export default function NodeInputField({
|
||||||
title,
|
title,
|
||||||
nodeId: data.id,
|
nodeId: data.id,
|
||||||
isFlexView,
|
isFlexView,
|
||||||
|
required,
|
||||||
})}
|
})}
|
||||||
</span>
|
</span>
|
||||||
}
|
}
|
||||||
|
|
@ -165,13 +166,13 @@ export default function NodeInputField({
|
||||||
title,
|
title,
|
||||||
nodeId: data.id,
|
nodeId: data.id,
|
||||||
isFlexView,
|
isFlexView,
|
||||||
|
required,
|
||||||
})}
|
})}
|
||||||
</span>
|
</span>
|
||||||
}
|
}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<span className={"text-status-red"}>{required ? "*" : ""}</span>
|
|
||||||
<div>
|
<div>
|
||||||
{info !== "" && (
|
{info !== "" && (
|
||||||
<ShadTooltip content={<NodeInputInfo info={info} />}>
|
<ShadTooltip content={<NodeInputInfo info={info} />}>
|
||||||
|
|
|
||||||
|
|
@ -74,6 +74,8 @@ const RenderInputParameters = ({
|
||||||
return keyMap;
|
return keyMap;
|
||||||
}, [templateFields, data.id, data.node?.template]);
|
}, [templateFields, data.id, data.node?.template]);
|
||||||
|
|
||||||
|
console.log({ data });
|
||||||
|
|
||||||
const renderInputParameter = templateFields.map(
|
const renderInputParameter = templateFields.map(
|
||||||
(templateField: string, idx) => {
|
(templateField: string, idx) => {
|
||||||
const template = data.node?.template[templateField];
|
const template = data.node?.template[templateField];
|
||||||
|
|
|
||||||
|
|
@ -250,8 +250,6 @@ function GenericNode({
|
||||||
[data.node?.outputs],
|
[data.node?.outputs],
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log(shownOutputs, hiddenOutputs);
|
|
||||||
|
|
||||||
const [hasChangedNodeDescription, setHasChangedNodeDescription] =
|
const [hasChangedNodeDescription, setHasChangedNodeDescription] =
|
||||||
useState(false);
|
useState(false);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -236,6 +236,7 @@ const ConnectionComponent = ({
|
||||||
setSelectedList={setSelectedItem}
|
setSelectedList={setSelectedItem}
|
||||||
selectedList={selectedItem}
|
selectedList={selectedItem}
|
||||||
options={options}
|
options={options}
|
||||||
|
{...baseInputProps}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ const SearchBarComponent = ({
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
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 && (
|
{searchCategories && searchCategories.length > 0 && (
|
||||||
<DropdownMenu>
|
<DropdownMenu>
|
||||||
<DropdownMenuTrigger asChild>
|
<DropdownMenuTrigger asChild>
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ const SortableListItem = memo(
|
||||||
<li
|
<li
|
||||||
className={cn(
|
className={cn(
|
||||||
"inline-flex h-12 w-full items-center gap-2 text-sm font-medium text-gray-800",
|
"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 && (
|
{limit !== 1 && (
|
||||||
|
|
@ -52,8 +52,8 @@ const SortableListItem = memo(
|
||||||
|
|
||||||
<span
|
<span
|
||||||
className={cn(
|
className={cn(
|
||||||
"truncate text-primary",
|
"truncate text-muted-foreground",
|
||||||
limit === 1 ? "max-w-56 pl-3" : "max-w-48",
|
limit === 1 ? "max-w-56 pl-2" : "max-w-48",
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{data.name}
|
{data.name}
|
||||||
|
|
@ -63,9 +63,9 @@ const SortableListItem = memo(
|
||||||
size="icon"
|
size="icon"
|
||||||
variant={limit !== 1 ? "outline" : "ghost"}
|
variant={limit !== 1 ? "outline" : "ghost"}
|
||||||
className={cn(
|
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
|
limit === 1
|
||||||
? "group pr-3 opacity-100"
|
? "group pr-1 opacity-100"
|
||||||
: "hover:border hover:border-destructive hover:bg-transparent hover:opacity-100",
|
: "hover:border hover:border-destructive hover:bg-transparent hover:opacity-100",
|
||||||
)}
|
)}
|
||||||
onClick={onRemove}
|
onClick={onRemove}
|
||||||
|
|
@ -192,6 +192,7 @@ const SortableListComponent = ({
|
||||||
selectedList={listData}
|
selectedList={listData}
|
||||||
options={options}
|
options={options}
|
||||||
limit={limit}
|
limit={limit}
|
||||||
|
{...baseInputProps}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ const DialogContent = React.forwardRef<
|
||||||
<DialogPrimitive.Content
|
<DialogPrimitive.Content
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
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,
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|
|
||||||
|
|
@ -88,7 +88,7 @@ test("IntComponent", { tag: ["@release", "@workspace"] }, async ({ page }) => {
|
||||||
await page.locator('//*[@id="showtemperature"]').click();
|
await page.locator('//*[@id="showtemperature"]').click();
|
||||||
expect(
|
expect(
|
||||||
await page.locator('//*[@id="showtemperature"]').isChecked(),
|
await page.locator('//*[@id="showtemperature"]').isChecked(),
|
||||||
).toBeTruthy();
|
).toBeFalsy();
|
||||||
|
|
||||||
await page.locator('//*[@id="showmodel_kwargs"]').click();
|
await page.locator('//*[@id="showmodel_kwargs"]').click();
|
||||||
expect(
|
expect(
|
||||||
|
|
@ -108,7 +108,7 @@ test("IntComponent", { tag: ["@release", "@workspace"] }, async ({ page }) => {
|
||||||
await page.locator('//*[@id="showtemperature"]').click();
|
await page.locator('//*[@id="showtemperature"]').click();
|
||||||
expect(
|
expect(
|
||||||
await page.locator('//*[@id="showtemperature"]').isChecked(),
|
await page.locator('//*[@id="showtemperature"]').isChecked(),
|
||||||
).toBeFalsy();
|
).toBeTruthy();
|
||||||
|
|
||||||
await page.locator('//*[@id="showmodel_kwargs"]').click();
|
await page.locator('//*[@id="showmodel_kwargs"]').click();
|
||||||
expect(
|
expect(
|
||||||
|
|
@ -128,7 +128,7 @@ test("IntComponent", { tag: ["@release", "@workspace"] }, async ({ page }) => {
|
||||||
await page.locator('//*[@id="showtemperature"]').click();
|
await page.locator('//*[@id="showtemperature"]').click();
|
||||||
expect(
|
expect(
|
||||||
await page.locator('//*[@id="showtemperature"]').isChecked(),
|
await page.locator('//*[@id="showtemperature"]').isChecked(),
|
||||||
).toBeTruthy();
|
).toBeFalsy();
|
||||||
|
|
||||||
await page.getByText("Close").last().click();
|
await page.getByText("Close").last().click();
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue