chore: merge mcp components (#7167)

* take1

* depreacate stdio and sse mcp components

* optionals

* rodrigo fixes

* session management

* update init

* mcp component integration test

* broken

* [autofix.ci] apply automated fixes

* fix url input name

* upated MCP

* Update mcp_component.py

* [autofix.ci] apply automated fixes

* update to the MCP component

* [autofix.ci] apply automated fixes

* mostly working

* [autofix.ci] apply automated fixes

* Update mcp_component.py

* [autofix.ci] apply automated fixes

* update component

* [autofix.ci] apply automated fixes

* Update mcp_component.py

* rename component because Simon

* icon and description for simon

* fix integration test

* fix test

* Update mcp_component.py

* update and basic QoL

* [autofix.ci] apply automated fixes

* refactor clients to util and use flow names not IDs in mcp.py

* integration test

* take out traces

*  (edit-tools.spec.ts): add test for user to be able to edit tools in the frontend application.

* session fix

* fix content output

* ♻️ (util.py): remove redundant constant HTTP_TEMPORARY_REDIRECT and replace its usage with httpx.codes.TEMPORARY_REDIRECT for better code readability and maintainability

* [autofix.ci] apply automated fixes

* 🐛 (utils.ts): fix potential null pointer error when converting words to title case by adding null check before accessing properties

* 🐛 (genericIconComponent/index.tsx): Fix issue with optional chaining in mapping function
🐛 (renderIconComponent/index.tsx): Fix issue with optional chaining in mapping function
🐛 (button.tsx): Fix issue with optional chaining in mapping function
🐛 (utils.ts): Fix issue with optional chaining in mapping functions

* 🐛 (language-select.tsx): Fix potential null pointer error when mapping over allLanguages array

*  (constants.ts): add support for multiple languages in the application by defining an array of language options
♻️ (audio-settings-dialog.tsx, language-select.tsx): refactor to import the array of all languages from constants.ts instead of duplicating it in each file

*  (auto-login-off.spec.ts): add a 2-second delay before continuing the test to ensure proper loading and rendering of elements on the page

* ⬆️ (filterEdge-shard-0.spec.ts): reduce wait time for page interactions to improve test performance
⬆️ (playground.spec.ts): optimize wait times for page interactions to enhance test efficiency

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Edwin Jose <edwin.jose@datastax.com>
Co-authored-by: cristhianzl <cristhian.lousa@gmail.com>
This commit is contained in:
Sebastián Estévez 2025-03-21 18:11:01 -04:00 committed by GitHub
commit 59b2ed7765
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
25 changed files with 1200 additions and 331 deletions

View file

@ -706,6 +706,7 @@
},
"node_modules/@clack/prompts/node_modules/is-unicode-supported": {
"version": "1.3.0",
"extraneous": true,
"inBundle": true,
"license": "MIT",
"engines": {

View file

@ -37,7 +37,7 @@ export const ForwardedIconComponent = memo(
nodeIconsLucide[
name
?.split("-")
?.map((x) => String(x[0]).toUpperCase() + String(x).slice(1))
?.map((x) => String(x[0])?.toUpperCase() + String(x).slice(1))
?.join("")
];
if (!TargetIcon) {

View file

@ -32,7 +32,7 @@ export default function RenderKey({
className={cn(tableRender ? "h-4 w-4" : "h-3 w-3")}
/>
) : (
<span>{value.toUpperCase()}</span>
<span>{value?.toUpperCase()}</span>
)}
</div>
);

View file

@ -61,9 +61,11 @@ export interface ButtonProps
function toTitleCase(text: string) {
return text
.split(" ")
.map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
.join(" ");
?.split(" ")
?.map(
(word) => word?.charAt(0)?.toUpperCase() + word?.slice(1)?.toLowerCase(),
)
?.join(" ");
}
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(

View file

@ -1022,3 +1022,18 @@ export const IS_AUTO_LOGIN =
export const AUTO_LOGIN_RETRY_DELAY = 2000;
export const AUTO_LOGIN_MAX_RETRY_DELAY = 60000;
export const ALL_LANGUAGES = [
{ value: "en-US", name: "English (US)" },
{ value: "en-GB", name: "English (UK)" },
{ value: "it-IT", name: "Italian" },
{ value: "fr-FR", name: "French" },
{ value: "es-ES", name: "Spanish" },
{ value: "de-DE", name: "German" },
{ value: "ja-JP", name: "Japanese" },
{ value: "pt-BR", name: "Portuguese (Brazil)" },
{ value: "zh-CN", name: "Chinese (Simplified)" },
{ value: "ru-RU", name: "Russian" },
{ value: "ar-SA", name: "Arabic" },
{ value: "hi-IN", name: "Hindi" },
];

View file

@ -21,21 +21,6 @@ import LanguageSelect from "./components/language-select";
import MicrophoneSelect from "./components/microphone-select";
import VoiceSelect from "./components/voice-select";
const ALL_LANGUAGES = [
{ value: "en-US", name: "English (US)" },
{ value: "en-GB", name: "English (UK)" },
{ value: "it-IT", name: "Italian" },
{ value: "fr-FR", name: "French" },
{ value: "es-ES", name: "Spanish" },
{ value: "de-DE", name: "German" },
{ value: "ja-JP", name: "Japanese" },
{ value: "pt-BR", name: "Portuguese (Brazil)" },
{ value: "zh-CN", name: "Chinese (Simplified)" },
{ value: "ru-RU", name: "Russian" },
{ value: "ar-SA", name: "Arabic" },
{ value: "hi-IN", name: "Hindi" },
];
interface SettingsVoiceModalProps {
children?: React.ReactNode;
userOpenaiApiKey?: string;
@ -415,7 +400,6 @@ const SettingsVoiceModal = ({
<LanguageSelect
language={currentLanguage}
handleSetLanguage={handleSetLanguage}
allLanguages={ALL_LANGUAGES}
/>
</>
)}

View file

@ -1,3 +1,4 @@
import { ALL_LANGUAGES } from "@/constants/constants";
import IconComponent from "../../../../../../../../../../components/common/genericIconComponent";
import ShadTooltip from "../../../../../../../../../../components/common/shadTooltipComponent";
import {
@ -12,13 +13,11 @@ import {
interface LanguageSelectProps {
language: string;
handleSetLanguage: (value: string) => void;
allLanguages: { value: string; name: string }[];
}
const LanguageSelect = ({
language,
handleSetLanguage,
allLanguages,
}: LanguageSelectProps) => {
return (
<div className="grid w-full items-center gap-2">
@ -41,7 +40,7 @@ const LanguageSelect = ({
</SelectTrigger>
<SelectContent className="max-h-[200px]">
<SelectGroup>
{allLanguages.map((lang) => (
{ALL_LANGUAGES?.map((lang) => (
<SelectItem key={lang?.value} value={lang?.value}>
<div className="max-w-[220px] truncate text-left">
{lang?.name}

View file

@ -47,9 +47,9 @@ export function toNormalCase(str: string): string {
.split("_")
.map((word, index) => {
if (index === 0) {
return word[0].toUpperCase() + word.slice(1).toLowerCase();
return word[0]?.toUpperCase() + word.slice(1)?.toLowerCase();
}
return word.toLowerCase();
return word?.toLowerCase();
})
.join(" ");
@ -57,9 +57,9 @@ export function toNormalCase(str: string): string {
.split("-")
.map((word, index) => {
if (index === 0) {
return word[0].toUpperCase() + word.slice(1).toLowerCase();
return word[0]?.toUpperCase() + word.slice(1)?.toLowerCase();
}
return word.toLowerCase();
return word?.toLowerCase();
})
.join(" ");
}
@ -69,11 +69,11 @@ export function normalCaseToSnakeCase(str: string): string {
.split(" ")
.map((word, index) => {
if (index === 0) {
return word[0].toUpperCase() + word.slice(1).toLowerCase();
return word[0]?.toUpperCase() + word.slice(1)?.toLowerCase();
}
return word.toLowerCase();
return word?.toLowerCase();
})
.join("_");
?.join("_");
}
export function toTitleCase(
@ -82,41 +82,41 @@ export function toTitleCase(
): string {
if (!str) return "";
let result = str
.split("_")
.map((word, index) => {
?.split("_")
?.map((word, index) => {
if (isNodeField) return word;
if (index === 0) {
return checkUpperWords(
word[0].toUpperCase() + word.slice(1).toLowerCase(),
word[0]?.toUpperCase() + word.slice(1)?.toLowerCase(),
);
}
return checkUpperWords(word.toLowerCase());
return checkUpperWords(word?.toLowerCase());
})
.join(" ");
return result
.split("-")
.map((word, index) => {
?.split("-")
?.map((word, index) => {
if (isNodeField) return word;
if (index === 0) {
return checkUpperWords(
word[0].toUpperCase() + word.slice(1).toLowerCase(),
word[0]?.toUpperCase() + word.slice(1)?.toLowerCase(),
);
}
return checkUpperWords(word.toLowerCase());
return checkUpperWords(word?.toLowerCase());
})
.join(" ");
?.join(" ");
}
export const upperCaseWords: string[] = ["llm", "uri"];
export function checkUpperWords(str: string): string {
const words = str.split(" ").map((word) => {
return upperCaseWords.includes(word.toLowerCase())
? word.toUpperCase()
: word[0].toUpperCase() + word.slice(1).toLowerCase();
const words = str?.split(" ")?.map((word) => {
return upperCaseWords.includes(word?.toLowerCase())
? word?.toUpperCase()
: word[0]?.toUpperCase() + word.slice(1)?.toLowerCase();
});
return words.join(" ");
return words?.join(" ");
}
export function buildInputs(): string {

View file

@ -215,6 +215,8 @@ test(
).isVisible(),
);
await page.waitForTimeout(2000);
await awaitBootstrapTest(page, { skipGoto: true });
await page.getByTestId("side_nav_options_all-templates").click();

View file

@ -73,9 +73,11 @@ test(
}
}
await page.waitForTimeout(1000);
await page.waitForTimeout(500);
await visibleElementHandle.hover().then(async () => {
await page.waitForTimeout(1000);
await expect(
page.getByText("Drag to connect compatible outputs").first(),
).toBeVisible();
@ -105,7 +107,11 @@ test(
}
}
await page.waitForTimeout(500);
await visibleElementHandle.hover().then(async () => {
await page.waitForTimeout(1000);
await expect(
page.getByText("Drag to connect compatible outputs").first(),
).toBeVisible();

View file

@ -164,13 +164,21 @@ test(
await page.getByTestId("chat-message-User-session_after_delete").click();
await expect(page.getByTestId("session-selector")).toBeVisible();
await page.waitForTimeout(500);
// check helpful button
await page.getByTestId("chat-message-AI-session_after_delete").hover();
await page.getByTestId("helpful-button").click();
await page.waitForTimeout(500);
await page.getByTestId("chat-message-AI-session_after_delete").hover();
await expect(page.getByTestId("icon-ThumbUpIconCustom")).toBeVisible({
timeout: 10000,
});
await page.waitForTimeout(500);
await page.getByTestId("helpful-button").click();
await page.getByTestId("chat-message-AI-session_after_delete").hover();
await expect(page.getByTestId("icon-ThumbUpIconCustom")).toBeVisible({
@ -178,26 +186,38 @@ test(
visible: false,
});
// check not helpful button
await page.waitForTimeout(500);
await page.getByTestId("chat-message-AI-session_after_delete").hover();
await page.getByTestId("not-helpful-button").click();
await page.waitForTimeout(500);
await page.getByTestId("chat-message-AI-session_after_delete").hover();
await expect(page.getByTestId("icon-ThumbDownIconCustom")).toBeVisible({
timeout: 10000,
});
await page.getByTestId("not-helpful-button").click();
await page.waitForTimeout(500);
await page.getByTestId("chat-message-AI-session_after_delete").hover();
await expect(page.getByTestId("icon-ThumbDownIconCustom")).toBeVisible({
timeout: 10000,
visible: false,
});
// check switch feedback
await page.waitForTimeout(500);
await page.getByTestId("chat-message-AI-session_after_delete").hover();
await page.getByTestId("helpful-button").click();
await page.waitForTimeout(500);
await page.getByTestId("chat-message-AI-session_after_delete").hover();
await expect(page.getByTestId("icon-ThumbUpIconCustom")).toBeVisible({
timeout: 10000,
});
await page.getByTestId("not-helpful-button").click();
await page.waitForTimeout(500);
await page.getByTestId("chat-message-AI-session_after_delete").hover();
await expect(page.getByTestId("icon-ThumbDownIconCustom")).toBeVisible({
timeout: 10000,

View file

@ -0,0 +1,76 @@
import { expect, test } from "@playwright/test";
import { awaitBootstrapTest } from "../../utils/await-bootstrap-test";
test(
"user should be able to edit tools",
{ tag: ["@release"] },
async ({ page }) => {
await awaitBootstrapTest(page);
await page.getByTestId("blank-flow").click();
await page.getByTestId("sidebar-search-input").click();
await page.getByTestId("sidebar-search-input").fill("api request");
await page.waitForSelector('[data-testid="dataAPI Request"]', {
timeout: 3000,
});
await page
.getByTestId("dataAPI Request")
.hover()
.then(async () => {
await page.getByTestId("add-component-button-api-request").click();
});
await page.waitForSelector(
'[data-testid="generic-node-title-arrangement"]',
{
timeout: 3000,
},
);
await page.getByTestId("generic-node-title-arrangement").click();
await page.waitForTimeout(500);
await page.getByTestId("tool-mode-button").click();
await page.locator('[data-testid="icon-Hammer"]').nth(1).waitFor({
timeout: 3000,
state: "visible",
});
await page.getByTestId("icon-Hammer").nth(1).click();
await page.waitForSelector("text=edit tools", { timeout: 30000 });
const rowsCount = await page.getByRole("gridcell").count();
expect(rowsCount).toBeGreaterThan(3);
expect(await page.getByRole("switch").nth(0).isChecked()).toBe(true);
await page.getByRole("switch").nth(0).click();
expect(await page.getByRole("switch").nth(0).isChecked()).toBe(false);
await page.getByText("Save").last().click();
await page.waitForSelector(
'[data-testid="generic-node-title-arrangement"]',
{
timeout: 3000,
},
);
await page.waitForTimeout(500);
await page.getByTestId("icon-Hammer").nth(1).click();
await page.waitForSelector("text=edit tools", { timeout: 30000 });
await page.waitForTimeout(500);
expect(await page.getByRole("switch").nth(0).isChecked()).toBe(false);
},
);