fix: added truncation length as constant and reduced it to 100 (#8321)

* Added truncation items as constant and reduced it to 100

* Added truncation test to regression

* get max items length from config

* changed typo in backend
This commit is contained in:
Lucas Oliveira 2025-06-02 18:30:11 -03:00 committed by GitHub
commit 0896f51983
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 278 additions and 706 deletions

File diff suppressed because it is too large Load diff

View file

@ -377,7 +377,7 @@ class FlowDataRequest(BaseModel):
class ConfigResponse(BaseModel):
feature_flags: FeatureFlags
serialization_max_items_lenght: int = serialization_constants.MAX_ITEMS_LENGTH
serialization_max_items_length: int = serialization_constants.MAX_ITEMS_LENGTH
serialization_max_text_length: int = serialization_constants.MAX_TEXT_LENGTH
frontend_timeout: int
auto_saving: bool

View file

@ -1,4 +1,5 @@
import TableComponent from "@/components/core/parameterRenderComponent/components/tableComponent";
import { useUtilityStore } from "@/stores/utilityStore";
import { ColDef, ColGroupDef } from "ag-grid-community";
import "ag-grid-community/styles/ag-grid.css"; // Mandatory CSS required by the grid
import "ag-grid-community/styles/ag-theme-balham.css"; // Optional Theme applied to the grid
@ -14,10 +15,15 @@ function DataOutputComponent({
rows: any[];
columnMode?: "intersection" | "union";
}) {
const [rowsInternal, setRowsInternal] = useState(rows.slice(0, 1000));
const maxItemsLength = useUtilityStore(
(state) => state.serializationMaxItemsLength,
);
const [rowsInternal, setRowsInternal] = useState(
rows.slice(0, maxItemsLength),
);
useEffect(() => {
const rowsSliced = rows.slice(0, 1000);
const rowsSliced = rows.slice(0, maxItemsLength);
if (rowsSliced.some((row) => typeof row !== "object")) {
setRowsInternal(rowsSliced.map((row) => ({ data: row })));
} else {
@ -34,10 +40,15 @@ function DataOutputComponent({
return (
<TableComponent
autoSizeStrategy={{ type: "fitGridWidth", defaultMinWidth: 100 }}
autoSizeStrategy={{
type: "fitGridWidth",
defaultMinWidth: maxItemsLength,
}}
key={"dataOutputComponent"}
overlayNoRowsTemplate="No data available"
paginationInfo={rows.length > 1000 ? rows[1000] : undefined}
paginationInfo={
rows.length > maxItemsLength ? rows[maxItemsLength] : undefined
}
suppressRowClickSelection={true}
pagination={pagination}
columnDefs={columnDefs}

View file

@ -19,6 +19,7 @@ export interface ConfigResponse {
max_file_size_upload: number;
feature_flags: Record<string, any>;
webhook_polling_interval: number;
serialization_max_items_length: number;
event_delivery: EventDeliveryType;
}
@ -35,6 +36,9 @@ export const useGetConfig: useQueryFunctionType<undefined, ConfigResponse> = (
const setMaxFileSizeUpload = useUtilityStore(
(state) => state.setMaxFileSizeUpload,
);
const setSerializationMaxItemsLength = useUtilityStore(
(state) => state.setSerializationMaxItemsLength,
);
const setFeatureFlags = useUtilityStore((state) => state.setFeatureFlags);
const setWebhookPollingInterval = useUtilityStore(
(state) => state.setWebhookPollingInterval,
@ -56,6 +60,7 @@ export const useGetConfig: useQueryFunctionType<undefined, ConfigResponse> = (
setHealthCheckMaxRetries(data.health_check_max_retries);
setMaxFileSizeUpload(data.max_file_size_upload);
setFeatureFlags(data.feature_flags);
setSerializationMaxItemsLength(data.serialization_max_items_length);
setWebhookPollingInterval(
data.webhook_polling_interval ?? DEFAULT_POLLING_INTERVAL,
);

View file

@ -27,6 +27,9 @@ export const useUtilityStore = create<UtilityStoreType>((set, get) => ({
maxFileSizeUpload: 100 * 1024 * 1024, // 100MB in bytes
setMaxFileSizeUpload: (maxFileSizeUpload: number) =>
set({ maxFileSizeUpload: maxFileSizeUpload * 1024 * 1024 }),
serializationMaxItemsLength: 100,
setSerializationMaxItemsLength: (serializationMaxItemsLength: number) =>
set({ serializationMaxItemsLength }),
flowsPagination: {
page: 1,
size: 10,

View file

@ -9,6 +9,7 @@ export type UtilityStoreType = {
playgroundScrollBehaves: ScrollBehavior;
setPlaygroundScrollBehaves: (behaves: ScrollBehavior) => void;
maxFileSizeUpload: number;
setMaxFileSizeUpload: (maxFileSizeUpload: number) => void;
flowsPagination: Pagination;
setFlowsPagination: (pagination: Pagination) => void;
tags: Tag[];
@ -25,4 +26,6 @@ export type UtilityStoreType = {
clientId: string;
eventDelivery: EventDeliveryType;
setEventDelivery: (eventDelivery: EventDeliveryType) => void;
serializationMaxItemsLength: number;
setSerializationMaxItemsLength: (serializationMaxItemsLength: number) => void;
};

View file

@ -0,0 +1,51 @@
import { expect, test } from "@playwright/test";
import { awaitBootstrapTest } from "../../utils/await-bootstrap-test";
test(
"truncated values must be displayed correctly",
{ tag: ["@release", "@components"] },
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("url");
await page.waitForSelector('[data-testid="dataURL"]', {
timeout: 1000,
});
await page
.getByTestId("dataURL")
.dragTo(page.locator('//*[@id="react-flow-id"]'), {
targetPosition: { x: 300, y: 300 },
});
await page
.getByTestId("inputlist_str_urls_0")
.fill("https://docs.langflow.org/");
await page.getByTestId("default_slider_display_value").click();
await page.getByTestId("slider_input").fill("4");
await page.getByTestId("button_run_url").click();
await page.waitForSelector("text=built successfully", {
timeout: 30000,
});
await page.getByTestId("output-inspection-result-urlcomponent").click();
await page.getByText(`Inspect the output of the component below.`, {
exact: true,
});
expect(page.getByText(`[truncated`)).toBeVisible();
expect(page.locator("span.ag-header-cell-text").nth(1)).toHaveText("url");
expect(page.locator("span[data-ref=lbRecordCount]").first()).toHaveText(
"100",
);
},
);