From 44f5dd6636d4b23aa55383b8b8abe4c2f73bc88d Mon Sep 17 00:00:00 2001
From: Amey Pawar <138877912+ameyypawar@users.noreply.github.com>
Date: Sun, 7 Jun 2026 13:25:12 +0530
Subject: [PATCH] fix(frontend): respect forced column order for numeric column
names (#9463)
---
.../src/lib/components/DisplayResult.svelte | 18 +++++++++++++
.../lib/components/table/AutoDataTable.svelte | 5 ++--
.../lib/components/table/tableUtils.test.ts | 25 +++++++++++++++++++
.../src/lib/components/table/tableUtils.ts | 10 ++++++--
4 files changed, 54 insertions(+), 4 deletions(-)
create mode 100644 frontend/src/lib/components/table/tableUtils.test.ts
diff --git a/frontend/src/lib/components/DisplayResult.svelte b/frontend/src/lib/components/DisplayResult.svelte
index 3d94c33c21..707cda66e1 100644
--- a/frontend/src/lib/components/DisplayResult.svelte
+++ b/frontend/src/lib/components/DisplayResult.svelte
@@ -410,6 +410,23 @@
return json
}
+ // The explicit column order from a leading header row (see
+ // handleArrayOfObjectsHeaders). Returned as an array so the order survives:
+ // baking it into object keys loses integer-like names like "1234", which JS
+ // enumerates first in ascending numeric order.
+ function getForcedColumnOrder(json: any): string[] | undefined {
+ if (
+ Array.isArray(json) &&
+ json.length > 0 &&
+ Array.isArray(json[0]) &&
+ json[0].length > 0 &&
+ json[0].every((item) => typeof item === 'string')
+ ) {
+ return json[0]
+ }
+ return undefined
+ }
+
type InputObject = { [key: string]: number[] }
function objectOfArraysToObjects(input: InputObject): any[] {
@@ -643,6 +660,7 @@
? 'absolute inset-0 [&>div]:h-full [&>div]:min-h-[10rem]'
: ''}
objects={handleArrayOfObjectsHeaders(data)}
+ headerOrder={getForcedColumnOrder(data)}
/>
{:else if !forceJson && resultKind === 'html'}
diff --git a/frontend/src/lib/components/table/AutoDataTable.svelte b/frontend/src/lib/components/table/AutoDataTable.svelte
index b6f70d2307..ef835eb7f4 100644
--- a/frontend/src/lib/components/table/AutoDataTable.svelte
+++ b/frontend/src/lib/components/table/AutoDataTable.svelte
@@ -21,10 +21,11 @@
import DownloadCsv from './DownloadCsv.svelte'
interface Props {
objects?: Array>
+ headerOrder?: string[]
class?: string
}
- let { objects = [], class: className }: Props = $props()
+ let { objects = [], headerOrder, class: className }: Props = $props()
let currentPage = $state(1)
let perPage = $state(25)
@@ -37,7 +38,7 @@
let headers: string[] = $state([])
function recomputeObjectsAndHeaders(objects: Array>) {
- ;[headers, structuredObjects] = computeStructuredObjectsAndHeaders(objects)
+ ;[headers, structuredObjects] = computeStructuredObjectsAndHeaders(objects, headerOrder)
}
function adjustCurrentPage() {
diff --git a/frontend/src/lib/components/table/tableUtils.test.ts b/frontend/src/lib/components/table/tableUtils.test.ts
new file mode 100644
index 0000000000..b34a142f19
--- /dev/null
+++ b/frontend/src/lib/components/table/tableUtils.test.ts
@@ -0,0 +1,25 @@
+import { describe, it, expect } from 'vitest'
+import { computeStructuredObjectsAndHeaders } from './tableUtils'
+
+describe('computeStructuredObjectsAndHeaders', () => {
+ it('respects an explicit headerOrder when a column name is integer-like (#9183)', () => {
+ // "1234" must keep its specified position instead of jumping to the front,
+ // the way Object.keys() orders integer-like keys.
+ const headerOrder = ['Pokemon name', 'Type', '1234', 'Main strength']
+ const rows = [
+ { 'Pokemon name': 'Pikachu', Type: 'Electric', '1234': 'nil', 'Main strength': 'Speed' }
+ ]
+ const [headers] = computeStructuredObjectsAndHeaders(rows, headerOrder)
+ expect(headers).toEqual(['Pokemon name', 'Type', '1234', 'Main strength'])
+ })
+
+ it('appends keys not present in headerOrder, after the explicit ones', () => {
+ const [headers] = computeStructuredObjectsAndHeaders([{ a: 1, b: 2, c: 3 }], ['a', 'b'])
+ expect(headers).toEqual(['a', 'b', 'c'])
+ })
+
+ it('keeps the existing object-key behavior when no headerOrder is given', () => {
+ const [headers] = computeStructuredObjectsAndHeaders([{ x: 1, y: 2 }])
+ expect(headers).toEqual(['x', 'y'])
+ })
+})
diff --git a/frontend/src/lib/components/table/tableUtils.ts b/frontend/src/lib/components/table/tableUtils.ts
index db935ebe02..fa1d020c77 100644
--- a/frontend/src/lib/components/table/tableUtils.ts
+++ b/frontend/src/lib/components/table/tableUtils.ts
@@ -8,7 +8,10 @@ export function isEmail(value: string) {
return value?.includes('@')
}
-export function computeStructuredObjectsAndHeaders(objects: Array>): [
+export function computeStructuredObjectsAndHeaders(
+ objects: Array>,
+ headerOrder?: string[]
+): [
string[],
{
_id: number
@@ -18,7 +21,10 @@ export function computeStructuredObjectsAndHeaders(objects: Array {
let rowData = obj && typeof obj == 'object' ? obj : {}
if (Array.isArray(rowData)) {