Skip to content
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,10 @@ jest.mock("../../../ui/select", () => {
children: React.ReactNode;
value: string;
}) => <option value={value}>{children}</option>,
SelectTrigger: ({ children }: { children: React.ReactNode }) => (
<>{children}</>
SelectTrigger: ({ children, ...rest }: any) => (
<div data-testid="page-select-trigger" aria-label={rest["aria-label"]}>
{children}
</div>
),

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

Use a semantic trigger mock that forwards props.

Suggested test-fidelity fix
-    SelectTrigger: ({ children, ...rest }: any) => (
-      <div data-testid="page-select-trigger" aria-label={rest["aria-label"]}>
-        {children}
-      </div>
-    ),
+    SelectTrigger: ({ children, ...rest }: any) => (
+      <button type="button" data-testid="page-select-trigger" {...rest}>
+        {children}
+      </button>
+    ),

As per coding guidelines: "Ensure mocks are used appropriately for external dependencies, not core logic" and "Warn when mocks are used instead of testing real behavior and interactions."

Also applies to: 70-76

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/frontend/src/components/common/paginatorComponent/__tests__/PaginatorComponent.test.tsx`
around lines 43 - 47, The SelectTrigger mock in the test file does not properly
forward all props to the underlying div element, which reduces test fidelity.
Instead of only explicitly handling the aria-label prop, use the spread operator
to forward all rest props to the div element (for example, replace
aria-label={rest["aria-label"]} with {...rest}). This change should be applied
at the anchor location in
src/frontend/src/components/common/paginatorComponent/__tests__/PaginatorComponent.test.tsx
at lines 43-47 in the SelectTrigger mock, and at the sibling location at lines
70-76 where the same mock pattern appears, to ensure consistent prop forwarding
behavior across all mocks.

Source: Coding guidelines

SelectValue: () => null,
};
Expand All @@ -64,6 +66,16 @@ const renderPaginator = (
};

describe("PaginatorComponent", () => {
describe("accessibility", () => {
it("page select trigger has an aria-label", () => {
renderPaginator({ totalRowsCount: 45, pageIndex: 1 });
const trigger = screen.getByTestId("page-select-trigger");
// i18n resolves "paginator.pageLabel" → "Page"
expect(trigger).toHaveAttribute("aria-label");
expect(trigger.getAttribute("aria-label")).toBeTruthy();
});
});

describe("empty state", () => {
it("renders '0 items' instead of '1-0 of 0 items' when there are no rows", () => {
renderPaginator({ totalRowsCount: 0 });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ export default function PaginatorComponent({
<SelectTrigger
direction="up"
className="h-7 w-fit gap-1 border-none p-1 pl-1.5 text-mmd focus:border-none focus:ring-0 focus:!ring-offset-0"
aria-label={t("paginator.pageLabel")}
>
<SelectValue placeholder={t("paginator.placeholder")} />
</SelectTrigger>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import { render, screen } from "@testing-library/react";
import AppHeader from "../index";

// i18n — returns the key so aria-label values are predictable
jest.mock("react-i18next", () => ({
useTranslation: () => ({ t: (key: string) => key }),
}));

jest.mock("@/components/common/genericIconComponent", () => ({
__esModule: true,
default: ({ name }: { name: string }) => (
<span data-testid={`icon-${name}`}>{name}</span>
),
}));

jest.mock("@/components/ui/button", () => ({
Button: ({
children,
"aria-label": ariaLabel,
"data-testid": testId,
unstyled,
...props
}: any) => (
<button aria-label={ariaLabel} data-testid={testId} {...props}>
{children}
</button>
),
}));

jest.mock("@/components/ui/separator", () => ({
Separator: () => <hr />,
}));

jest.mock("@/components/common/shadTooltipComponent", () => ({
__esModule: true,
default: ({ children }: any) => <>{children}</>,
}));

jest.mock("@/components/common/modelProviderCountComponent", () => ({
__esModule: true,
default: () => null,
}));

jest.mock("@/alerts/alertDropDown", () => ({
__esModule: true,
default: ({ children }: any) => <>{children}</>,
}));

jest.mock("@/assets/LangflowLogo.svg?react", () => ({
__esModule: true,
default: () => <svg data-testid="langflow-logo" />,
}));

jest.mock("@/customization/components/custom-AccountMenu", () => ({
__esModule: true,
default: () => null,
}));

jest.mock("@/customization/components/custom-langflow-counts", () => ({
__esModule: true,
default: () => null,
}));

jest.mock("@/customization/components/custom-org-selector", () => ({
CustomOrgSelector: () => null,
}));

jest.mock("@/customization/hooks/use-custom-navigate", () => ({
useCustomNavigate: () => jest.fn(),
}));

jest.mock("@/customization/hooks/use-custom-theme", () => ({
__esModule: true,
default: () => ({ dark: false }),
}));

jest.mock("@/stores/alertStore", () => ({
__esModule: true,
default: () => ({
notificationCenter: false,
setNotificationCenter: jest.fn(),
}),
}));

jest.mock("./components/FlowMenu", () => ({ FlowMenu: () => null }), {
virtual: true,
});
jest.mock("../components/FlowMenu", () => ({
__esModule: true,
default: () => null,
}));

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 | 🟠 Major | 🏗️ Heavy lift

Test is over-mocked and diverges from the frontend testing pattern

This suite mocks most of AppHeader’s runtime surface (UI primitives, dropdowns, hooks/store), so it mostly verifies mocked wiring rather than real accessibility behavior. It also uses Jest/RTL instead of the frontend Playwright pattern.

Please keep unit mocking minimal (external boundaries only) and add/port coverage to a Playwright test that asserts accessible names on the rendered UI.

As per coding guidelines, “Frontend test files should follow the naming convention *.test.ts or *.test.tsx using Playwright” and “Warn when mocks are used instead of testing real behavior and interactions … Recommend integration tests when unit tests become overly mocked.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/frontend/src/components/core/appHeaderComponent/__tests__/app-header-a11y.test.tsx`
around lines 5 - 91, This test file (app-header-a11y.test.tsx) is over-mocked
and diverges from the frontend Playwright testing pattern. The excessive mocking
of internal UI components (Button, Separator, genericIconComponent, etc.),
hooks, and stores means the test verifies mocked wiring rather than real
accessibility behavior. To fix this: convert the test from Jest/RTL to
Playwright following the frontend testing conventions, minimize mocks to only
external boundaries (API calls, third-party libraries), and rewrite the test to
assert on actual accessible names and ARIA attributes rendered in the real
AppHeader UI rather than testing mocked component interactions. This will ensure
the test validates genuine accessibility behavior as intended.

Source: Coding guidelines


describe("AppHeader — accessible button names", () => {
beforeEach(() => {
render(<AppHeader />);
});

it("home/back button has an aria-label", () => {
const btn = screen.getByTestId("icon-ChevronLeft");
expect(btn.closest("button")).toHaveAttribute("aria-label", "header.home");
});

it("notification bell button has an aria-label", () => {
const btn = screen.getByTestId("notification_button");
expect(btn).toHaveAttribute("aria-label", "header.notifications");
});
});
2 changes: 2 additions & 0 deletions src/frontend/src/components/core/appHeaderComponent/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ export default function AppHeader(): JSX.Element {
onClick={() => navigate("/")}
className="mr-1 flex h-8 w-8 items-center"
data-testid="icon-ChevronLeft"
aria-label={t("header.home")}
>
<LangflowLogo className="h-5 w-5" />
</Button>
Expand Down Expand Up @@ -100,6 +101,7 @@ export default function AppHeader(): JSX.Element {
)
}
data-testid="notification_button"
aria-label={t("header.notifications")}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

bug: duplicate aria-label prop on same JSX element. npx tsc --noEmit reports TS17001: JSX elements cannot have multiple attributes with the same name.

Suggested change: remove this duplicate and keep the existing aria-label above.

>
<div className="hit-area-hover group relative items-center rounded-md px-2 py-2 text-muted-foreground">
<span className={getNotificationBadge()} />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { render, screen } from "@testing-library/react";
import { AddFolderButton } from "../add-folder-button";

jest.mock("react-i18next", () => ({
useTranslation: () => ({ t: (key: string) => key }),
}));

jest.mock("@/components/common/genericIconComponent", () => ({
__esModule: true,
default: ({ name }: { name: string }) => (
<span data-testid={`icon-${name}`}>{name}</span>
),
}));

jest.mock("@/components/common/shadTooltipComponent", () => ({
__esModule: true,
default: ({ children }: { children: React.ReactNode }) => <>{children}</>,
}));

jest.mock("@/components/ui/button", () => ({
Button: ({
children,
"aria-label": ariaLabel,
disabled,
loading,
...props
}: any) => (
<button
aria-label={ariaLabel}
disabled={disabled}
data-loading={loading}
{...props}
>
{children}
</button>
),
}));

describe("AddFolderButton", () => {
const defaultProps = { onClick: jest.fn(), disabled: false, loading: false };

it("renders the add project button", () => {
render(<AddFolderButton {...defaultProps} />);
expect(screen.getByTestId("add-project-button")).toBeInTheDocument();
});

it("has an aria-label for screen readers", () => {
render(<AddFolderButton {...defaultProps} />);
const btn = screen.getByTestId("add-project-button");
expect(btn).toHaveAttribute("aria-label", "folder.createNewProject");
});

it("is disabled when disabled prop is true", () => {
render(<AddFolderButton {...defaultProps} disabled />);
expect(screen.getByTestId("add-project-button")).toBeDisabled();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { render, screen } from "@testing-library/react";
import { UploadFolderButton } from "../upload-folder-button";

jest.mock("react-i18next", () => ({
useTranslation: () => ({ t: (key: string) => key }),
}));

jest.mock("@/components/common/genericIconComponent", () => ({
__esModule: true,
default: ({ name }: { name: string }) => (
<span data-testid={`icon-${name}`}>{name}</span>
),
}));

jest.mock("@/components/common/shadTooltipComponent", () => ({
__esModule: true,
default: ({ children }: { children: React.ReactNode }) => <>{children}</>,
}));

jest.mock("@/components/ui/button", () => ({
Button: ({ children, "aria-label": ariaLabel, disabled, ...props }: any) => (
<button aria-label={ariaLabel} disabled={disabled} {...props}>
{children}
</button>
),
}));
Comment on lines +4 to +33

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify frontend test framework usage and mock density (read-only).
# Expected: if guideline is enforced, frontend *.test.ts/tsx should primarily use Playwright APIs.

echo "== Frontend test files =="
fd -e ts -e tsx '.test$' src/frontend/src

echo
echo "== Files importing Jest/RTL in frontend tests =="
rg -n --type=ts --type=tsx '(`@testing-library/react`|jest\.mock|describe\(|it\()' src/frontend/src --iglob '**/*.test.ts' --iglob '**/*.test.tsx'

echo
echo "== Files importing Playwright in frontend tests =="
rg -n --type=ts --type=tsx '(`@playwright/test`|test\(|expect\()' src/frontend/src --iglob '**/*.test.ts' --iglob '**/*.test.tsx'

Repository: langflow-ai/langflow

Length of output: 266


🏁 Script executed:

#!/bin/bash
# Find all test files in frontend with correct syntax
echo "== All test files in frontend =="
find src/frontend -name "*.test.ts" -o -name "*.test.tsx" 2>/dev/null | head -20

echo
echo "== Check specific file existence =="
ls -la "src/frontend/src/components/core/folderSidebarComponent/components/sideBarFolderButtons/components/__tests__/upload-folder-button.test.tsx" 2>&1

echo
echo "== Checking package.json for testing framework dependencies =="
cat package.json | grep -A 10 -B 2 '"jest"\|"playwright"\|"vitest"' 2>/dev/null || echo "Not found in top-level search"

Repository: langflow-ai/langflow

Length of output: 2229


🏁 Script executed:

#!/bin/bash
# Search for test framework usage without type flags
echo "== Jest usage in frontend tests =="
grep -r "jest.mock\|describe(\|it(" src/frontend --include="*.test.ts*" 2>/dev/null | head -5

echo
echo "== Playwright usage in frontend tests =="
grep -r "`@playwright/test`\|test(" src/frontend --include="*.test.ts*" 2>/dev/null | head -5

echo
echo "== Looking for jest/vitest in package.json =="
grep -i "jest\|vitest\|playwright" package*.json 2>/dev/null | head -20

Repository: langflow-ai/langflow

Length of output: 1565


🏁 Script executed:

#!/bin/bash
# Read package.json to check testing framework dependencies
echo "== Frontend package.json test dependencies =="
cat src/frontend/package.json | grep -A 30 '"devDependencies"' | head -40

Repository: langflow-ai/langflow

Length of output: 1197


🏁 Script executed:

#!/bin/bash
# Read the specific test file to assess mock usage
echo "== Content of upload-folder-button.test.tsx =="
cat src/frontend/src/components/core/folderSidebarComponent/components/sideBarFolderButtons/components/__tests__/upload-folder-button.test.tsx

Repository: langflow-ai/langflow

Length of output: 1655


Reduce internal component mocks to test real interaction behavior.

The test mocks internal UI components (Button, shadTooltipComponent, genericIconComponent) that should be rendered for real to verify actual behavior. Per coding guidelines, mocks should be limited to external dependencies (like react-i18next); mocking core UI logic obscures what's actually being tested. Consider importing and rendering the real components, or replacing mocks with minimal test doubles that preserve behavior.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/frontend/src/components/core/folderSidebarComponent/components/sideBarFolderButtons/components/__tests__/upload-folder-button.test.tsx`
around lines 4 - 26, Remove the jest.mock calls for the internal UI components
Button, shadTooltipComponent, and genericIconComponent in the test setup. These
mocks are obscuring actual component behavior and should not be mocked according
to testing guidelines. Keep the mock for react-i18next since it is an external
dependency. Either allow the real components to render naturally (by removing
their mock definitions) or replace the mocks with minimal test doubles that
preserve the expected behavior without hiding implementation details. This will
ensure the test verifies real interaction behavior with the actual UI
components.

Source: Coding guidelines


describe("UploadFolderButton", () => {
const defaultProps = { onClick: jest.fn(), disabled: false };

it("renders the upload project button", () => {
render(<UploadFolderButton {...defaultProps} />);
expect(screen.getByTestId("upload-project-button")).toBeInTheDocument();
});

it("has an aria-label for screen readers", () => {
render(<UploadFolderButton {...defaultProps} />);
const btn = screen.getByTestId("upload-project-button");
expect(btn).toHaveAttribute("aria-label", "folder.uploadFlow");
});

it("is disabled when disabled prop is true", () => {
render(<UploadFolderButton {...defaultProps} disabled />);
expect(screen.getByTestId("upload-project-button")).toBeDisabled();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export const AddFolderButton = ({
className="h-7 w-7 border-0 text-muted-foreground hover:bg-muted"
onClick={onClick}
data-testid="add-project-button"
aria-label={t("folder.createNewProject")}
disabled={disabled}
loading={loading}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,12 @@ export const SelectOptions = ({
styleClasses="z-50"
>
<SelectTrigger
className="w-fit"
className="h-6 w-6 min-h-[24px] min-w-[24px]"
id={`options-trigger-${item.name}`}
data-testid={
"more-options-button" + `_${convertTestName(item?.name ?? "")}`
}
aria-label={t("folder.optionsFor", { name: item.name })}
>
<IconComponent
name={"MoreHorizontal"}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export const UploadFolderButton = ({ onClick, disabled }) => {
className="h-7 w-7 border-0 text-muted-foreground hover:bg-muted"
onClick={onClick}
data-testid="upload-project-button"
aria-label={t("folder.uploadFlow")}
disabled={disabled}
>
<IconComponent name="Upload" className="h-4 w-4" />
Expand Down
12 changes: 9 additions & 3 deletions src/frontend/src/locales/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
"assistant.loading": "Ladevorgang läuft...",
"assistant.maxSessionsLabel": "Max. Sitzungen",
"assistant.maxSessionsTooltip": "Die maximale Anzahl von {{max}} -Sitzungen wurde erreicht. Löschen Sie eine Sitzung, um eine neue zu erstellen.",
"assistant.mentionNoMatches": "Keine passenden Komponenten auf der Arbeitsfläche",
"assistant.messageCounts": "{{count}} Nachrichten",
"assistant.newConversation": "Neue Konversation",
"assistant.newPill": "Neu",
Expand Down Expand Up @@ -143,7 +144,6 @@
"assistant.welcomeText": "So kann ich Ihnen helfen",
"assistant.working": "Wird geladen...",
"assistant.workingOnIt": "Ich arbeite daran...",
"assistant.mentionNoMatches": "Keine passenden Komponenten auf der Arbeitsfläche",
"auth.adminLoginButton": "Anmeldung",
"auth.adminTitle": "Administrator",
"auth.alertSaveWithApi": "⚠️ Achtung: Durch das Exportieren dieses Flows können vertrauliche Anmeldedaten offengelegt werden.",
Expand Down Expand Up @@ -709,8 +709,6 @@
"files.uploadedSuccessfully": "Datei erfolgreich hochgeladen",
"flow.addDescription": "Beschreibung hinzufügen...",
"flow.brokenEdgesWarning": "Einige Verbindungen wurden entfernt, da sie ungültig waren:",
"flow.exclusiveComponentsNotPasted": "Einige Komponenten wurden nicht eingefügt, da sie nicht zusammen mit bereits im Flow vorhandenen Komponenten verwendet werden können.",
"flow.duplicateComponentsNotPasted": "Einige Komponenten wurden nicht eingefügt, da pro Flow nur eine Instanz erlaubt ist.",
"flow.buildStatus": "Erstellen, um den Status zu überprüfen.",
"flow.buildSuccess": "Erfolgreich erstellt ✨",
"flow.characterLimitReached": "Zeichenlimit erreicht",
Expand Down Expand Up @@ -779,10 +777,12 @@
"flow.deletedSuccessfully": "Die ausgewählten Elemente wurden erfolgreich gelöscht",
"flow.descriptionLabel": "Beschreibung",
"flow.descriptionPlaceholder": "Beschreibung des Ablaufs",
"flow.duplicateComponentsNotPasted": "Einige Komponenten wurden nicht eingefügt, da in einem Ablauf jeweils nur eine davon zulässig ist.",
"flow.duplicatedSuccess": "{{type}} Erfolgreich dupliziert",
"flow.enableAutoSaving": "Automatisches Speichern aktivieren",
"flow.errorDeleting": "Fehler beim Löschen von Elementen",
"flow.errorDeletingRetry": "Wiederholen Sie die Operation",
"flow.exclusiveComponentsNotPasted": "Einige Komponenten wurden nicht eingefügt, da sie nicht zusammen mit den bereits im Ablauf vorhandenen Komponenten verwendet werden können.",
"flow.exitAnyway": "Trotzdem beenden",
"flow.lastSaved": "Zuletzt gespeichert: {{time}}",
"flow.lastSavedNever": "Niemals",
Expand Down Expand Up @@ -1148,8 +1148,11 @@
"mcp.configErrorFix": "Bitte passen Sie die Einstellung „ OAuth “ in Ihren Projekteinstellungen an, um die MCP-Serverkonfiguration zu generieren.",
"mcp.editAuth": "Bearbeitung Auth",
"mcp.editTools": "Bearbeitungswerkzeuge",
"mcp.failedToInstall": "Die Installation des MCP-Servers unter {{client}} ist fehlgeschlagen",
"mcp.flowsTools": "Abläufe/Tools",
"mcp.flowsTooltip": "Die Abläufe in diesem Projekt können als aufrufbare MCP-Tools bereitgestellt werden.",
"mcp.installDisabledWarning": "Die Ein-Klick-Installation ist deaktiviert, da der Langflow-Server nicht auf Ihrem lokalen Rechner läuft. Verwenden Sie die Registerkarte „JSON“, um Ihren Client manuell zu konfigurieren.",
"mcp.installTooltip": "Installieren Sie „ {{name}} “, um die automatische Installation zu aktivieren.",
"mcp.installedSuccessfully": "Der MCP-Server wurde erfolgreich unter {{client}} installiert. Möglicherweise müssen Sie Ihren Client neu starten, damit die Änderungen sichtbar werden.",
"mcp.loading": "Ladevorgang läuft...",
"mcp.loadingServers": "Server werden geladen...",
Expand Down Expand Up @@ -1195,6 +1198,7 @@
"mcp.selectServer": "Wähle einen Server aus...",
"mcp.serverDescription": "Greifen Sie auf die Abläufe Ihres Projekts als Tools innerhalb eines MCP-Servers zu. Erfahren Sie mehr in unserem",
"mcp.serverGuideLink": "Leitfaden für Projekte als MCP-Server.",
"mcp.serverNotRunning": "Der MCP-Server läuft nicht: {{message}}",
"mcp.serverTitle": "MCP-Server",
"mcp.servers.addButton": "MCP-Server hinzufügen",
"mcp.servers.addedServers": "MCP-Server hinzugefügt",
Expand Down Expand Up @@ -1551,6 +1555,8 @@
"paramRender.addOrEditData": "Daten hinzufügen oder bearbeiten",
"playground.cancelButton": "Abbrechen",
"playground.defaultSession": "Standardsitzung",
"playground.noInputHint": "Fügen Sie Ihrem Ablauf eine „ <1>Chat “ ( Input</1> )-Komponente hinzu, um Nachrichten zu versenden.",
"playground.runFlow": "Ablauf",
"playground.sendButton": "Senden",
"playgroundComponent.chatSessions": "Chat-Sitzungen",
"playgroundComponent.clearChat": "Chat löschen",
Expand Down
8 changes: 8 additions & 0 deletions src/frontend/src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,7 @@
"modal.api.exposeApiDescription": "Select which component fields to expose as inputs in this flow's API schema.",
"header.notifications": "Notifications and errors",
"header.notificationsLabel": "Notifications",
"header.home": "Go to home",
"account.version": "Version",
"account.latest": "(latest)",
"account.updateAvailable": "(update available)",
Expand Down Expand Up @@ -707,7 +708,13 @@
"mainPage.timeElapsed.hour_other": "{{count}} hours",
"mainPage.timeElapsed.minute_one": "{{count}} minute",
"mainPage.timeElapsed.minute_other": "{{count}} minutes",
"flows.viewList": "List view",

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

bug: these new a11y i18n keys were added only to en.json. de, es, fr, ja, pt, and zh-Hans are missing header.home, flows.viewList, flows.viewGrid, flows.downloadSelected, flows.selectFlow, flows.moreOptions, folder.optionsFor, and paginator.pageLabel, so localized UIs expose raw keys as accessible names.

Suggested change: add the same keys to all locale files, using English placeholders if translations are not ready.

"flows.viewGrid": "Grid view",
"flows.downloadSelected": "Download selected flows",
"flows.selectFlow": "Select {{name}}",
"flows.moreOptions": "More options for {{name}}",
"folder.options": "Options",
"folder.optionsFor": "Options for {{name}}",
"folder.rename": "Rename",
"folder.download": "Download",
"folder.delete": "Delete",
Expand Down Expand Up @@ -1345,6 +1352,7 @@
"paginator.ofPages": "of {{maxIndex}} pages",
"paginator.previousPage": "Go to previous page",
"paginator.nextPage": "Go to next page",
"paginator.pageLabel": "Page",
"alerts.modelsRefreshed": "{{count}} model(s) refreshed",
"mcp.servers.toolsCount": "{{count}} tool(s)",
"misc.fetchErrorDescription": "Check if the server is running and try again.",
Expand Down
Loading
Loading