🐛 Fix missing result columns in CSV export (#2513)
Some checks failed
Create Tag / create-tag (push) Has been cancelled
Deploy Workflows (Fly.io) / deploy (push) Has been cancelled

- Append missing result headers to saved column orders so newly added
response blocks stay visible.
- Reuse the normalized column order for selected-results CSV export
instead of a local missing-header fallback.
- Add regression coverage for default, saved, and legacy column orders.
This commit is contained in:
Baptiste Arnaud 2026-05-25 11:33:23 +02:00 committed by GitHub
parent b4a7aab16d
commit 08cb6ea10f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 69 additions and 29 deletions

View File

@ -76,32 +76,18 @@ export const SelectionToolbar = ({
const headerIds = parseColumnsOrder(
typebot?.resultsTablePreferences?.columnsOrder,
resultHeader,
)
.reduce<string[]>((currentHeaderIds, columnId) => {
if (
typebot?.resultsTablePreferences?.columnsVisibility[columnId] ===
false
)
return currentHeaderIds;
const columnLabel = resultHeader.find(
(headerCell) => headerCell.id === columnId,
)?.id;
if (!columnLabel) return currentHeaderIds;
currentHeaderIds.push(columnLabel);
).reduce<string[]>((currentHeaderIds, columnId) => {
if (
typebot?.resultsTablePreferences?.columnsVisibility[columnId] === false
)
return currentHeaderIds;
}, [])
.concat(
typebot?.resultsTablePreferences?.columnsOrder
? resultHeader
.filter(
(headerCell) =>
!typebot?.resultsTablePreferences?.columnsOrder.includes(
headerCell.id,
),
)
.map((headerCell) => headerCell.id)
: [],
);
const columnLabel = resultHeader.find(
(headerCell) => headerCell.id === columnId,
)?.id;
if (!columnLabel) return currentHeaderIds;
currentHeaderIds.push(columnLabel);
return currentHeaderIds;
}, []);
const data = dataToUnparse.map<{ [key: string]: string }>((data) => {
const newObject: { [key: string]: string } = {};

View File

@ -0,0 +1,46 @@
import { describe, expect, it } from "bun:test";
import { parseColumnsOrder } from "./parseColumnsOrder";
import type { ResultHeaderCell } from "./schemas/results";
const resultHeader = [
{
id: "createdAt",
label: "Created at",
},
{
id: "email",
label: "Email",
},
{
id: "name",
label: "Name",
},
] satisfies ResultHeaderCell[];
describe("parseColumnsOrder", () => {
it("returns the default order when no order is saved", () => {
expect(parseColumnsOrder(undefined, resultHeader)).toEqual([
"select",
"createdAt",
"email",
"name",
"logs",
]);
});
it("keeps the saved order and appends missing result headers", () => {
expect(parseColumnsOrder(["email", "createdAt"], resultHeader)).toEqual([
"select",
"email",
"createdAt",
"name",
"logs",
]);
});
it("resets orders saved with the old control column format", () => {
expect(
parseColumnsOrder(["select", "email", "logs"], resultHeader),
).toEqual(["select", "createdAt", "email", "name", "logs"]);
});
});

View File

@ -4,8 +4,16 @@ export const parseColumnsOrder = (
existingOrder: string[] | undefined,
resultHeader: ResultHeaderCell[],
) => {
return existingOrder?.at(0) === "select"
? // Old format potentially broken, reset to default
["select", ...resultHeader.map((h) => h.id), "logs"]
: ["select", ...(existingOrder ?? resultHeader.map((h) => h.id)), "logs"];
const resultHeaderIds = resultHeader.map((header) => header.id);
if (existingOrder?.at(0) === "select")
// Old format potentially broken, reset to default
return ["select", ...resultHeaderIds, "logs"];
const orderedHeaderIds = existingOrder ?? resultHeaderIds;
const missingHeaderIds = resultHeaderIds.filter(
(headerId) => !orderedHeaderIds.includes(headerId),
);
return ["select", ...orderedHeaderIds, ...missingHeaderIds, "logs"];
};