diff --git a/src/frontend/src/CustomNodes/GenericNode/components/NodeLegacyComponent/index.tsx b/src/frontend/src/CustomNodes/GenericNode/components/NodeLegacyComponent/index.tsx
index c1710765aa..03c49e6bc1 100644
--- a/src/frontend/src/CustomNodes/GenericNode/components/NodeLegacyComponent/index.tsx
+++ b/src/frontend/src/CustomNodes/GenericNode/components/NodeLegacyComponent/index.tsx
@@ -23,6 +23,7 @@ export default function NodeLegacyComponent({
};
const foundComponents = useGetReplacementComponents(replacement);
+
return (
- {replacement && Array.isArray(replacement) && replacement.length > 0 ? (
+ {replacement &&
+ Array.isArray(replacement) &&
+ replacement.length > 0 &&
+ foundComponents.some((component) => component) ? (
Use{" "}
{foundComponents.map((component, index) => (
<>
- {index > 0 && ", "}
-
+ {component && (
+ <>
+ {index > 0 && ", "}
+
+ >
+ )}
>
))}
.
diff --git a/src/frontend/src/CustomNodes/GenericNode/hooks/use-get-replacement-components.ts b/src/frontend/src/CustomNodes/GenericNode/hooks/use-get-replacement-components.ts
index efbe7c52de..1e28572802 100644
--- a/src/frontend/src/CustomNodes/GenericNode/hooks/use-get-replacement-components.ts
+++ b/src/frontend/src/CustomNodes/GenericNode/hooks/use-get-replacement-components.ts
@@ -11,7 +11,7 @@ export const useGetReplacementComponents = (replacement?: string[]) => {
return (
categoryName &&
componentName &&
- data[categoryName][componentName].display_name
+ data[categoryName]?.[componentName]?.display_name
);
})
: [];
diff --git a/src/frontend/tests/extended/features/userSettings.spec.ts b/src/frontend/tests/extended/features/userSettings.spec.ts
index 9d71da385d..a68ef71b46 100644
--- a/src/frontend/tests/extended/features/userSettings.spec.ts
+++ b/src/frontend/tests/extended/features/userSettings.spec.ts
@@ -14,7 +14,9 @@ test(
{ tag: ["@release"] },
async ({ page }) => {
- await page.goto("/");
+ await awaitBootstrapTest(page, {
+ skipModal: true,
+ });
await page.waitForSelector('[data-testid="mainpage_title"]', {
timeout: 30000,
});
@@ -42,7 +44,9 @@ test(
const randomName2 = Math.random().toString(36).substring(2);
const randomName3 = Math.random().toString(36).substring(2);
- await page.goto("/");
+ await awaitBootstrapTest(page, {
+ skipModal: true,
+ });
await page.getByTestId("user-profile-settings").click();
await page.getByText("Settings").click();
await page.getByText("Global Variables").click();
@@ -134,7 +138,9 @@ test(
);
test("should see shortcuts", { tag: ["@release"] }, async ({ page }) => {
- await page.goto("/");
+ await awaitBootstrapTest(page, {
+ skipModal: true,
+ });
await page.waitForSelector('[data-testid="mainpage_title"]', {
timeout: 30000,
});
@@ -172,7 +178,9 @@ test(
"should interact with API Keys",
{ tag: ["@release", "@api"] },
async ({ page }) => {
- await page.goto("/");
+ await awaitBootstrapTest(page, {
+ skipModal: true,
+ });
await page.getByTestId("user-profile-settings").click();
await page.getByText("Settings").click();
await page.getByText("Langflow API").first().click();
diff --git a/src/frontend/tests/extended/regression/general-bugs-frontend-crashing-on-invalid-replace.spec.ts b/src/frontend/tests/extended/regression/general-bugs-frontend-crashing-on-invalid-replace.spec.ts
new file mode 100644
index 0000000000..aac55443f2
--- /dev/null
+++ b/src/frontend/tests/extended/regression/general-bugs-frontend-crashing-on-invalid-replace.spec.ts
@@ -0,0 +1,75 @@
+import { expect, test } from "../../fixtures";
+import { awaitBootstrapTest } from "../../utils/await-bootstrap-test";
+
+test(
+ "user must be able to use a component with undefined replacement",
+ {
+ tag: ["@release"],
+ },
+ async ({ page }) => {
+ await awaitBootstrapTest(page);
+
+ await page.waitForSelector('[data-testid="blank-flow"]', {
+ timeout: 30000,
+ });
+
+ await page.getByTestId("blank-flow").click();
+
+ await page.getByTestId("sidebar-custom-component-button").click();
+
+ await page.getByTestId("title-Custom Component").click();
+
+ await page.getByTestId("code-button-modal").last().click();
+
+ const problematicCode = `
+# from lfx.field_typing import Data
+from lfx.custom.custom_component.component import Component
+from lfx.io import MessageTextInput, Output
+from lfx.schema.data import Data
+
+
+class CustomComponent(Component):
+ display_name = "Custom Component"
+ description = "Use as a template to create your own component."
+ documentation: str = "https://docs.langflow.org/components-custom-components"
+ icon = "code"
+ name = "CustomComponent"
+ replacement = ["knowledgebases.KnowledgeRetrieval", "knowledgebases.KnowledgeIngestion", "THISISNOTEXISTING.COMPONENT"] # This line was causing the crash
+ inputs = [
+ MessageTextInput(
+ name="input_value",
+ display_name="Input Value",
+ info="This is a custom component Input",
+ value="Hello, World!",
+ tool_mode=True,
+ ),
+ ]
+
+ outputs = [
+ Output(display_name="Output", name="output", method="build_output"),
+ ]
+
+ def build_output(self) -> Data:
+ data = Data(value=self.input_value)
+ self.status = data
+ return data
+
+ `;
+
+ await page.locator(".ace_content").click();
+ await page.keyboard.press(`ControlOrMeta+A`);
+ await page.locator("textarea").fill(problematicCode);
+
+ await page.getByText("Check & Save").last().click();
+
+ await page.waitForTimeout(1000);
+ await page.waitForSelector("text=No direct replacement", {
+ timeout: 30000,
+ });
+
+ const numberOfDirectReplacementText = await page
+ .getByText("No direct replacement")
+ .count();
+ expect(numberOfDirectReplacementText).toBe(1);
+ },
+);
diff --git a/src/lfx/src/lfx/components/vectorstores/local_db.py b/src/lfx/src/lfx/components/vectorstores/local_db.py
index 8ed50b36f9..3245d70920 100644
--- a/src/lfx/src/lfx/components/vectorstores/local_db.py
+++ b/src/lfx/src/lfx/components/vectorstores/local_db.py
@@ -22,7 +22,6 @@ class LocalDBComponent(LCVectorStoreComponent):
name = "LocalDB"
icon = "database"
legacy = True
- replacement = ["knowledgebases.KnowledgeRetrieval", "knowledgebases.KnowledgeIngestion"]
inputs = [
TabInput(