fix: make icons display correctly in composio dialog (#7708)

* feat: update icon handling and version bump to 1.3.4

* feat: enhance icon rendering and add data-testid attributes for better testing

* revert backend and added change to frontend

* fixed jumping icons

* Fix MAC OS detection by checking if navigator is defined before accessing userAgent

* Remove uv.lock file and update package-lock.json

* Update Playwright and Playwright test dependencies to v1.52.0

* Refactor icon formatting logic into a separate variable for better readability

* Add uv.lock file with Python package dependencies

* Update UV dependencies lock file

* Skip group and ungroup test in workspace release tag

* Simplify data-testid logic in genericIconComponent using optional chaining

* Enable group and ungroup values test by removing test.skip

* Fix icon validation and update icon component data-testid logic

* Simplify icon validation by removing Font Awesome check and refactoring boolean logic

* Simplify MAC OS detection by removing unnecessary type check

* Fix icon case sensitivity in ListItem component by capitalizing first letter

---------

Co-authored-by: Gabriel Luiz Freitas Almeida <gabriel@langflow.org>
This commit is contained in:
Deon Sanchez 2025-04-29 11:28:03 -06:00 committed by GitHub
commit bdfc69d09b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 806 additions and 738 deletions

File diff suppressed because it is too large Load diff

View file

@ -55,7 +55,7 @@
"openseadragon": "^4.1.1",
"p-debounce": "^4.0.0",
"pako": "^2.1.0",
"playwright": "^1.44.1",
"playwright": "^1.52.0",
"pretty-ms": "^9.1.0",
"react": "^18.3.1",
"react-ace": "^11.0.1",
@ -118,7 +118,7 @@
},
"proxy": "http://127.0.0.1:7860",
"devDependencies": {
"@playwright/test": "^1.44.1",
"@playwright/test": "^1.52.0",
"@swc/cli": "^0.5.2",
"@swc/core": "^1.6.1",
"@tailwindcss/typography": "^0.5.13",

View file

@ -26,6 +26,8 @@ const ListItem = ({
}) => {
const [isHovered, setIsHovered] = useState(false);
const itemRef = useRef<HTMLButtonElement>(null);
const formattedIcon =
item?.icon?.charAt(0).toUpperCase() + item?.icon?.slice(1);
// Clear hover state when keyboard navigation is active
useEffect(() => {
@ -72,7 +74,10 @@ const ListItem = ({
<div className="flex w-full items-center gap-2">
{item.icon && (
<div>
<ForwardedIconComponent name={item.icon} className="mr-2 h-4 w-4" />
<ForwardedIconComponent
name={formattedIcon}
className="mr-2 h-4 w-4"
/>
</div>
)}
<div className="flex w-full flex-col truncate">

View file

@ -4,8 +4,8 @@ import dynamicIconImports from "lucide-react/dynamicIconImports";
export const checkLucideIcons = (iconName: string): boolean => {
return (
lucideIcons[iconName] ||
dynamicIconImports[iconName] ||
categoryIcons[iconName]
!!lucideIcons[iconName] ||
!!dynamicIconImports[iconName] ||
!!categoryIcons[iconName]
);
};

View file

@ -93,14 +93,34 @@ export const ForwardedIconComponent = memo(
return (
<Suspense fallback={skipFallback ? undefined : fallback}>
<ErrorBoundary onError={handleError}>
<TargetIcon
className={className}
style={style}
ref={ref}
data-testid={
dataTestId ? dataTestId : id ? `${id}-${name}` : `icon-${name}`
}
/>
{TargetIcon?.render || TargetIcon?._payload ? (
<TargetIcon
className={className}
style={style}
ref={ref}
data-testid={
dataTestId
? dataTestId
: id
? `${id}-${name}`
: `icon-${name}`
}
/>
) : (
<div
className={className}
style={style}
data-testid={
dataTestId
? dataTestId
: id
? `${id}-${name}`
: `icon-${name}`
}
>
{TargetIcon}
</div>
)}
</ErrorBoundary>
</Suspense>
);

View file

@ -0,0 +1,12 @@
import * as fa from "react-icons/fa";
import * as faV6 from "react-icons/fa6";
export const fontAwesomeIcons = {
FaApple: fa.FaApple,
FaDiscord: fa.FaDiscord,
FaGithub: fa.FaGithub,
};
export const isFontAwesomeIcon = (name: string): boolean => {
return name.startsWith("Fa") && fontAwesomeIcons[name] !== undefined;
};

View file

@ -1,5 +1,6 @@
import { BotMessageSquareIcon } from "@/icons/BotMessageSquare";
import { GradientSave } from "@/icons/GradientSparkles";
import { fontAwesomeIcons, isFontAwesomeIcon } from "@/icons/fontAwesomeIcons";
import { TwitterLogoIcon } from "@radix-ui/react-icons";
import dynamicIconImports from "lucide-react/dynamicIconImports";
import { lazy } from "react";
@ -434,7 +435,11 @@ const iconMappingsPromise = import("../icons/lazyIconImports").then(
);
export const eagerLoadedIconsMap = {
// React icons
// Custom icons
GradientSave: GradientSave,
BotMessageSquareIcon: BotMessageSquareIcon,
// React icon
FaApple: FaApple,
FaDiscord: FaDiscord,
FaGithub: FaGithub,
@ -448,6 +453,10 @@ export const getNodeIcon = async (name: string) => {
return eagerLoadedIconsMap[iconName || name];
}
if (isFontAwesomeIcon(iconName || name)) {
return fontAwesomeIcons[iconName || name];
}
const iconMappings = await iconMappingsPromise;
if (iconMappings[iconName || name]) {
@ -477,6 +486,7 @@ export const iconExists = async (name: string): Promise<boolean> => {
return !!(
eagerLoadedIconsMap[iconName] ||
isFontAwesomeIcon(iconName) ||
iconMappings[iconName] ||
dynamicIconImports[getLucideIconName(iconName)]
);