Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,13 @@ export default function ToolsComponent({
disabled = false,
template,
showParameter = true,
hideButton = false,
open,
setOpen,
}: InputProps<any[] | undefined, ToolsComponentType>): JSX.Element | null {
const [isModalOpen, setIsModalOpen] = useState(false);
const [internalOpen, setInternalOpen] = useState(false);
const isModalOpen = open ?? internalOpen;
const setIsModalOpen = setOpen ?? setInternalOpen;
const actions = value
?.filter((action) => action.status === true)
.map((action) => {
Expand Down Expand Up @@ -69,7 +74,7 @@ export default function ToolsComponent({
className="relative flex items-center w-full gap-3"
data-testid={"div-" + id}
>
{(visibleActions.length > 0 || isAction) && (
{!hideButton && (visibleActions.length > 0 || isAction) && (
<Button
variant={
ENABLE_MCP_COMPOSER && button_description ? "outline" : "ghost"
Expand Down Expand Up @@ -103,7 +108,12 @@ export default function ToolsComponent({
))}
</div>
) : visibleActions.length > 0 ? (
<div className="flex w-full flex-wrap gap-1 overflow-hidden py-1.5">
<div
className={cn(
"flex w-full flex-wrap gap-1 overflow-hidden pb-1.5",
hideButton ? "pt-0" : "pt-3",
)}
>
{visibleActions.map((action, index) => (
<Badge
key={index}
Expand All @@ -125,16 +135,21 @@ export default function ToolsComponent({
</div>
) : (
visibleActions.length === 0 &&
isAction && (
isAction &&
(hideButton ? (
<span className="py-1.5 text-sm text-muted-foreground">
No tools added to this server
</span>
) : (
<div className="mt-2 flex w-full flex-col items-center gap-2 rounded-md border border-dashed p-8">
<span className="text-sm text-muted-foreground">
No actions added to this server
No tools added to this server
</span>
<Button size={"sm"} onClick={() => setIsModalOpen(true)}>
<span>Add actions</span>
<span>Add tools</span>
</Button>
</div>
)
))
)}

{visibleActions.length === 0 && !isAction && value && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ export type ToolsComponentType = {
button_description?: string;
isAction?: boolean;
template?: APITemplateType;
hideButton?: boolean;
open?: boolean;
setOpen?: (open: boolean) => void;
Comment on lines +62 to +64
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

open and setOpen are independently optional — partial usage silently breaks the modal.

Because these two props are separate ?: fields, TypeScript permits passing only open or only setOpen. Both partial cases silently malfunction at runtime:

  • open provided, setOpen omitted → setIsModalOpen = setInternalOpen; closing the modal updates internalOpen but isModalOpen = open ?? internalOpen always returns the external open value, so the modal is permanently stuck open.
  • setOpen provided, open omitted → isModalOpen = internalOpen; every call to setIsModalOpen goes to the external setter but never updates internalOpen, so the modal never opens or closes from the component's perspective.

Constrain the type so both must be present together or absent together:

🛡️ Proposed fix — enforce controlled/uncontrolled as a unit
 export type ToolsComponentType = {
   description: string;
   title: string;
   icon?: string;
   button_description?: string;
   isAction?: boolean;
   template?: APITemplateType;
   hideButton?: boolean;
-  open?: boolean;
-  setOpen?: (open: boolean) => void;
-};
+} & (
+  | { open?: never; setOpen?: never }
+  | { open: boolean; setOpen: (open: boolean) => void }
+);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/frontend/src/components/core/parameterRenderComponent/types.ts` around
lines 62 - 64, The open/setOpen pair must be required together or not at all;
update the prop type that currently declares hideButton?: boolean; open?:
boolean; setOpen?: (open: boolean) => void to a discriminated union so consumers
cannot pass only one of open or setOpen. Replace the separate optional fields
with a combined type such as hideButton?: boolean plus a union for controlled vs
uncontrolled (controlled branch requires both open and setOpen, uncontrolled
branch forbids both), referencing the existing symbols open and setOpen in the
union so the compiler enforces they come as a pair.

};

export type FloatComponentType = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export const McpAuthSection = ({
currentAuthSettings,
setAuthModalOpen,
}: McpAuthSectionProps) => (
<div className="flex justify-between">
<div className="flex items-center justify-between">
<span className="flex gap-2 items-center text-sm cursor-default">
<span className=" font-medium">Auth:</span>
{!hasAuthentication ? (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export const McpAutoInstallContent = ({
installClient,
installedClients,
}: McpAutoInstallContentProps) => (
<div className="flex flex-col gap-1 mt-4">
<div className="flex flex-col gap-1">
{!isLocalConnection && (
<div className="mb-2 rounded-md bg-accent-amber px-3 py-2 text-sm text-accent-amber-foreground">
<div className="flex items-center gap-3">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import { useState } from "react";

import { ForwardedIconComponent } from "@/components/common/genericIconComponent";
import ShadTooltip from "@/components/common/shadTooltipComponent";
import ToolsComponent from "@/components/core/parameterRenderComponent/components/ToolsComponent";
import { Button } from "@/components/ui/button";
import { ICON_STROKE_WIDTH } from "@/constants/constants";
import { ENABLE_MCP_COMPOSER } from "@/customization/feature-flags";
import type { InputFieldType } from "@/types/api";
import type { ToolFlow } from "../utils/mcpServerUtils";

Expand All @@ -12,35 +17,56 @@ interface McpFlowsSectionProps {
export const McpFlowsSection = ({
flowsMCPData,
handleOnNewValue,
}: McpFlowsSectionProps) => (
<div className="w-full xl:w-2/5">
<div className="flex flex-row justify-between pt-1">
<ShadTooltip
content="Flows in this project can be exposed as callable MCP tools."
side="right"
>
<div className="flex items-center text-sm font-medium hover:cursor-help">
Flows/Tools
}: McpFlowsSectionProps) => {
const [isModalOpen, setIsModalOpen] = useState(false);

return (
<div className="w-full pr-4 xl:w-2/5">
<div className="flex flex-row items-center justify-between">
<ShadTooltip
content="Flows in this project can be exposed as callable MCP tools."
side="right"
>
<div className="flex items-center text-sm font-medium hover:cursor-help">
Flows/Tools
<ForwardedIconComponent
name="info"
className="ml-1.5 h-4 w-4 text-muted-foreground"
aria-hidden="true"
/>
</div>
</ShadTooltip>
<Button
variant={ENABLE_MCP_COMPOSER ? "outline" : "ghost"}
size="sm"
data-testid="button_open_actions"
onClick={() => setIsModalOpen(true)}
className="!text-mmd font-normal"
>
<ForwardedIconComponent
name="info"
className="ml-1.5 h-4 w-4 text-muted-foreground"
aria-hidden="true"
name={ENABLE_MCP_COMPOSER ? "wrench" : "Settings2"}
className="icon-size"
strokeWidth={ICON_STROKE_WIDTH}
/>
</div>
</ShadTooltip>
</div>
<div className="flex flex-row flex-wrap gap-2 pt-2">
<ToolsComponent
value={flowsMCPData}
title="MCP Server Tools"
description="Select tools to add to this server"
handleOnNewValue={handleOnNewValue}
id="mcp-server-tools"
button_description="Edit Tools"
editNode={false}
isAction
disabled={false}
/>
Edit Tools
</Button>
</div>
<div className="flex flex-row flex-wrap gap-2 pt-4">
<ToolsComponent
value={flowsMCPData}
title="MCP Server Tools"
description="Select tools to add to this server"
handleOnNewValue={handleOnNewValue}
id="mcp-server-tools"
button_description="Edit Tools"
editNode={false}
isAction
disabled={false}
hideButton
open={isModalOpen}
setOpen={setIsModalOpen}
/>
</div>
</div>
</div>
);
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ const McpServerTab = ({ folderName }: { folderName: string }) => {
</div>
</div>

<div className="flex flex-col gap-4">
<div className="flex flex-col gap-4 rounded-md border border-dashed border-border p-4">
{hasOAuthError ? (
<div className="p-4 bg-accent-red-subtle border border-accent-red-border rounded-lg">
<div className="flex items-center gap-2 mb-2">
Expand Down
Loading