Skip to content

[refactor] Break the antd ColumnsType coupling with a local ColumnDef - #5959

Open
ardaerzin wants to merge 1 commit into
obs/wp4-observability-chromefrom
obs/table-columndef-seam
Open

[refactor] Break the antd ColumnsType coupling with a local ColumnDef#5959
ardaerzin wants to merge 1 commit into
obs/wp4-observability-chromefrom
obs/table-columndef-seam

Conversation

@ardaerzin

Copy link
Copy Markdown
Contributor

Context

InfiniteVirtualTable is typed against antd's ColumnsType. That type reaches 22 files and 160 references across packages and both apps, and every new table column adds to it. The table itself has to come off antd eventually, since the target architecture is one antd-free app, and this type surface is what blocks every step of that port.

This is step 1 of the table port from docs/design/observability-packages/plan.md §8, pulled forward because it is mechanical, carries no visual risk, and lands independently.

Changes

ColumnDef<T> now lives in packages/agenta-ui/src/InfiniteVirtualTable/columnDef.ts, alongside ColumnGroupDef, ColumnDefs and the supporting scalars. antd's ColumnsType becomes an adapter applied at exactly one place:

columns={toAntdColumns(finalColumns)}

The table's rendering does not move. <Table virtual> stays exactly as it is. Only the type surface changes, so the later steps stop being blocked on a 22-file refactor.

One decision worth a reviewer's eye. Every function-valued column prop (render, onCell, onHeaderCell, shouldCellUpdate, onFilter) is declared with method syntax, not property syntax:

render(value: unknown, record: T, index: number): RenderedColumnCell

Method parameters are checked bivariantly, so a column may still write render: (date: string) => … and stay assignable. That is what antd was buying with any, obtained here without one. Property syntax with unknown would have broken about fifty call sites.

getObservabilityColumns.tsx also drops its last antd import, swapping Tag for the SpanIdChip built in obs/wp3.

Tests / notes

  • OSS, EE, mobile and @agenta/ui typecheck. @agenta/ui, @agenta/entity-ui and @agenta/observability-ui build and lint. @agenta/entity-ui's 325 tests pass.
  • Two corrections to the plan's measurement. packages/agenta-ui/src/utils/groupColumns.ts sits outside the directory that was measured but is antd-typed and feeds buildEntityColumns, so it had to move here or the package would not compile. And the observability types.d.ts antd import did not fall out for free: it also imported Avatar for an exported AvatarTreeContentProps, which turned out to have no references anywhere in oss, ee, packages or mobile, so it is deleted.
  • fromAntdColumns is exported but currently unused. It exists for the four raw <Table> call sites deliberately left on antd (MetadataSummaryTable, getAnnotationTableColumns, ConfigurationTable, DeploymentHistoryModal).

What to QA

No visual change is expected anywhere. The risk is a column silently losing its renderer, so spot-check the tables that were retyped.

  • Observability traces: all columns render, the span-id chip still shows, resizing a column still works.
  • Testsets and test cases tables: columns render and group headers still nest.
  • Evaluation runs and run details: columns render, including the ETL preview columns.
  • Prompts and Agents table sections: columns render.

…ColumnDef

Step 1 of the table port, pulled forward: mechanical, zero visual risk, and it
stops the type debt growing while every later table step stays blocked.
ColumnDef<T> lives in InfiniteVirtualTable and antd's ColumnsType becomes an
adapter applied once, at columns={toAntdColumns(finalColumns)}. The table's
rendering is untouched; <Table virtual> stays.

Function-valued column props are declared with method syntax, not property
syntax. Method params check bivariantly, so a column may still write
render: (date: string) => … and stay assignable. That is what antd bought with
any, obtained here without one; property syntax with unknown would have broken
about fifty call sites.

getObservabilityColumns also drops its last antd import, swapping Tag for the
SpanIdChip built in WP3.

Two things the plan had wrong. groupColumns.ts sits outside the directory the
measurement covered but is antd-typed and feeds buildEntityColumns, so it had
to move in the same change or the package would not compile. And the observability
types.d.ts antd import did not fall out for free: it also imported Avatar for an
exported AvatarTreeContentProps, which turned out to have no references anywhere
in oss, ee, packages or mobile, so it is deleted.

fromAntdColumns is exported but unused. It exists for the four raw <Table> call
sites deliberately left on antd.
@dosubot dosubot Bot added the size:XL This PR changes 500-999 lines, ignoring generated files. label Aug 12, 2026
@vercel

vercel Bot commented Aug 12, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
agenta-documentation Blocked Blocked Aug 12, 2026 12:18am

Request Review

@dosubot dosubot Bot added frontend refactoring A code change that neither fixes a bug nor adds a feature labels Aug 12, 2026
@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Summary by CodeRabbit

  • Refactor

    • Standardized table column handling across the app on a shared column format.
    • Improved compatibility between table-based views and the shared table components.
    • Updated infinite-table features like resizing, visibility, export, and grouped columns to work consistently with the new column format.
  • Bug Fixes

    • Kept table behavior unchanged while reducing the risk of mismatched column definitions in different screens.

Walkthrough

The change adds shared table column definition types, migrates virtual table and OSS column contracts from Ant Design types, and converts local columns to Ant Design columns at the rendering boundary. Observability span IDs now use SpanIdChip.

Changes

Shared table column type migration

Layer / File(s) Summary
Column contract and public exports
web/packages/agenta-ui/src/InfiniteVirtualTable/columnDef.ts, web/packages/agenta-ui/src/InfiniteVirtualTable/types.ts, web/packages/agenta-ui/src/InfiniteVirtualTable/index.ts
Defines ColumnDef, ColumnGroupDef, and ColumnDefs. Exports column utilities and conversion helpers.
Infinite virtual table column pipeline
web/packages/agenta-ui/src/InfiniteVirtualTable/columns/*, web/packages/agenta-ui/src/InfiniteVirtualTable/hooks/*, web/packages/agenta-ui/src/InfiniteVirtualTable/utils/*, web/packages/agenta-ui/src/utils/groupColumns.ts
Migrates builders, grouping, visibility, resizing, export, and metadata APIs to the shared column types.
Table rendering integration
web/packages/agenta-entity-ui/src/shared/EntityTable.tsx, web/packages/agenta-ui/src/InfiniteVirtualTable/components/InfiniteVirtualTableInner.tsx
Updates entity table column contracts and converts local columns before passing them to Ant Design.
OSS table column consumers
web/oss/src/components/**
Migrates table hooks, builders, grouping utilities, and component props to ColumnDef and ColumnDefs. Replaces the observability span ID tag renderer with SpanIdChip.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Mergeability Score: 🔵 Low · up to 8b055

The refactor remains mergeable with owner follow-up: grouped columns are currently exposed through a leaf-only return type, which can hide nested group headers from consumers, and fixed columns using "start"/"end" may behave inconsistently with the supported Ant Design 5.0 range.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 60.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the primary change: replacing direct antd ColumnsType coupling with a local ColumnDef type.
Description check ✅ Passed The description directly explains the type migration, adapter conversion, retained rendering behavior, tests, and QA focus.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 2
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch obs/table-columndef-seam

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown
Contributor

Railway Preview Environment

Preview URL https://gateway-pr-5959.up.railway.app/w
Project agenta-oss-clone-spike
Image tag pr-5959-08806b1
Status Deployed
Railway logs Open logs
Workflow logs View workflow run
Updated at 2026-08-12T00:30:23.701Z

@ardaerzin

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 13, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 127b3489-f8e0-44a4-ac4c-3a136f885a17

📥 Commits

Reviewing files that changed from the base of the PR and between 18f0e2c and 8b05572.

📒 Files selected for processing (34)
  • web/oss/src/components/EvalRunDetails/etl/useEtlColumns.tsx
  • web/oss/src/components/EvalRunDetails/utils/buildPreviewColumns.tsx
  • web/oss/src/components/EvaluationRunsTablePOC/hooks/useEvaluationRunsColumns/index.tsx
  • web/oss/src/components/SharedDrawers/TraceDrawer/components/TraceContent/components/LinkedSpansTabItem/index.tsx
  • web/oss/src/components/TestcasesTableNew/components/TestcasesTableShell.tsx
  • web/oss/src/components/TestcasesTableNew/utils/groupColumns.ts
  • web/oss/src/components/TestsetsTable/assets/createTestsetsColumns.tsx
  • web/oss/src/components/TestsetsTable/hooks/useTestsetsColumns.tsx
  • web/oss/src/components/pages/agents/AgentsTableSection.tsx
  • web/oss/src/components/pages/observability/assets/getObservabilityColumns.tsx
  • web/oss/src/components/pages/observability/assets/types.d.ts
  • web/oss/src/components/pages/prompts/components/PromptsTableSection.tsx
  • web/packages/agenta-entity-ui/src/shared/EntityTable.tsx
  • web/packages/agenta-ui/src/InfiniteVirtualTable/antdColumns.ts
  • web/packages/agenta-ui/src/InfiniteVirtualTable/columnDef.ts
  • web/packages/agenta-ui/src/InfiniteVirtualTable/columns/buildEntityColumns.tsx
  • web/packages/agenta-ui/src/InfiniteVirtualTable/columns/createStandardColumns.tsx
  • web/packages/agenta-ui/src/InfiniteVirtualTable/columns/createTableColumns.ts
  • web/packages/agenta-ui/src/InfiniteVirtualTable/columns/types.ts
  • web/packages/agenta-ui/src/InfiniteVirtualTable/components/InfiniteVirtualTableInner.tsx
  • web/packages/agenta-ui/src/InfiniteVirtualTable/hooks/useColumnDomRefs.ts
  • web/packages/agenta-ui/src/InfiniteVirtualTable/hooks/useColumnVisibility.ts
  • web/packages/agenta-ui/src/InfiniteVirtualTable/hooks/useColumnVisibilityControls.ts
  • web/packages/agenta-ui/src/InfiniteVirtualTable/hooks/useResizableColumns.ts
  • web/packages/agenta-ui/src/InfiniteVirtualTable/hooks/useScopedColumnVisibility.tsx
  • web/packages/agenta-ui/src/InfiniteVirtualTable/hooks/useSmartResizableColumns.ts
  • web/packages/agenta-ui/src/InfiniteVirtualTable/hooks/useTableExport.ts
  • web/packages/agenta-ui/src/InfiniteVirtualTable/hooks/useTableHeaderHeight.ts
  • web/packages/agenta-ui/src/InfiniteVirtualTable/hooks/useTableManager.tsx
  • web/packages/agenta-ui/src/InfiniteVirtualTable/hooks/useTypeChipColumns.tsx
  • web/packages/agenta-ui/src/InfiniteVirtualTable/index.ts
  • web/packages/agenta-ui/src/InfiniteVirtualTable/types.ts
  • web/packages/agenta-ui/src/InfiniteVirtualTable/utils/columnUtils.ts
  • web/packages/agenta-ui/src/utils/groupColumns.ts

Comment on lines +13 to +15
export type ColumnAlign = "start" | "end" | "left" | "right" | "center" | "justify" | "match-parent"

export type ColumnFixed = "start" | "end" | "left" | "right" | boolean

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n '"antd"\s*:' web/package.json
if [ -f web/pnpm-lock.yaml ]; then
  rg -n 'rc-table@|rc-table:' web/pnpm-lock.yaml
fi

Repository: Agenta-AI/agenta

Length of output: 154


🏁 Script executed:

set -euo pipefail

printf '%s\n' '--- candidate files ---'
git ls-files 'web/packages/agenta-ui/src/InfiniteVirtualTable/*' 'web/**/package.json' '*lock*' | head -200

printf '%s\n' '--- column definition ---'
cat -n web/packages/agenta-ui/src/InfiniteVirtualTable/columnDef.ts | sed -n '1,240p'

printf '%s\n' '--- dependency declarations ---'
find web -name package.json -print0 | xargs -0 grep -nE '"(antd|rc-table)"' || true

printf '%s\n' '--- lockfile references ---'
find . -maxdepth 3 -type f \( -name '*lock*' -o -name 'package.json' \) -print0 |
  xargs -0 grep -nE '(^|[[:space:]])rc-table(@|:)|(^|[[:space:]])antd(@|:)' 2>/dev/null | head -200 || true

Repository: Agenta-AI/agenta

Length of output: 15079


🏁 Script executed:

set -euo pipefail

printf '%s\n' '--- adapter implementation ---'
cat -n web/packages/agenta-ui/src/InfiniteVirtualTable/antdColumns.ts | sed -n '1,280p'

printf '%s\n' '--- all align/fixed uses ---'
rg -n --glob 'web/packages/agenta-ui/src/InfiniteVirtualTable/**' '\b(align|fixed)\b|ColumnAlign|ColumnFixed' web/packages/agenta-ui/src/InfiniteVirtualTable

printf '%s\n' '--- package and lockfile dependency context ---'
sed -n '1,120p' web/packages/agenta-ui/package.json
sed -n '6750,6845p' web/pnpm-lock.yaml
rg -n -C 4 'rc-table(@|:)|antd@6\.3\.7|rc-util@|`@ant-design/icons`@' web/pnpm-lock.yaml | head -240

Repository: Agenta-AI/agenta

Length of output: 20673


🏁 Script executed:

set -euo pipefail

printf '%s\n' '--- resolved antd dependency graph ---'
sed -n '16022,16085p' web/pnpm-lock.yaml
rg -n -C 3 '(`@rc-component/table`|rc-table)@' web/pnpm-lock.yaml || true

printf '%s\n' '--- table bridge call sites ---'
rg -n -C 5 'toAntdColumns|fromAntdColumns|<Table|AntdColumnsType' web/packages/agenta-ui/src/InfiniteVirtualTable web/packages/agenta-ui/src | head -260

printf '%s\n' '--- package manager metadata ---'
sed -n '1,90p' web/pnpm-lock.yaml
rg -n -C 3 '^  web/packages/agenta-ui:|antd:' web/pnpm-lock.yaml | head -100

Repository: Agenta-AI/agenta

Length of output: 39551


🏁 Script executed:

set -euo pipefail

python3 - <<'PY'
from urllib.request import urlopen
from urllib.error import HTTPError

urls = [
    "https://unpkg.com/antd@6.3.7/es/table/interface.d.ts",
    "https://unpkg.com/@rc-component/table@1.9.1/es/interface.d.ts",
    "https://unpkg.com/antd@5.0.0/es/table/interface.d.ts",
    "https://unpkg.com/rc-table@7.32.2/es/interface.d.ts",
]
for url in urls:
    print(f"--- {url} ---")
    try:
        text = urlopen(url, timeout=15).read().decode()
    except Exception as exc:
        print(f"FETCH_ERROR: {exc}")
        continue
    for i, line in enumerate(text.splitlines(), 1):
        if any(token in line for token in ("align", "fixed", "AlignType", "FixedType")):
            print(f"{i}:{line}")
PY

Repository: Agenta-AI/agenta

Length of output: 998


🏁 Script executed:

set -euo pipefail

for url in \
  'https://unpkg.com/antd@6.3.7/es/table/interface.d.ts' \
  'https://unpkg.com/@rc-component/table@1.9.1/es/interface.d.ts' \
  'https://unpkg.com/antd@5.0.0/es/table/interface.d.ts' \
  'https://unpkg.com/rc-table@7.32.2/es/interface.d.ts'
do
  printf '%s\n' "--- $url ---"
  curl -k -fsSL --max-time 20 "$url" |
    nl -ba |
    grep -E 'align|fixed|AlignType|FixedType' || true
done

Repository: Agenta-AI/agenta

Length of output: 954


🏁 Script executed:

set -euo pipefail

python3 - <<'PY'
from urllib.request import urlopen
import ssl

ctx = ssl._create_unverified_context()
urls = [
    "https://unpkg.com/antd@6.3.7/es/table/interface.d.ts",
    "https://unpkg.com/@rc-component/table@1.9.1/es/interface.d.ts",
    "https://unpkg.com/antd@5.0.0/es/table/interface.d.ts",
    "https://unpkg.com/rc-table@7.32.2/es/interface.d.ts",
]
for url in urls:
    print(f"--- {url} ---")
    try:
        text = urlopen(url, context=ctx, timeout=20).read().decode()
    except Exception as exc:
        print(f"FETCH_ERROR: {exc}")
        continue
    for i, line in enumerate(text.splitlines(), 1):
        if any(token in line for token in ("align", "fixed", "AlignType", "FixedType")):
            print(f"{i}:{line}")
PY

Repository: Agenta-AI/agenta

Length of output: 1546


🏁 Script executed:

set -euo pipefail

python3 - <<'PY'
from urllib.request import urlopen
import json, ssl

ctx = ssl._create_unverified_context()
urls = [
    "https://unpkg.com/antd@5.0.0/package.json",
    "https://unpkg.com/antd@6.3.7/package.json",
    "https://unpkg.com/rc-table@7.32.2/package.json",
    "https://unpkg.com/@rc-component/table@1.9.1/package.json",
]
for url in urls:
    print(f"--- {url} ---")
    try:
        data = json.loads(urlopen(url, context=ctx, timeout=20).read().decode())
    except Exception as exc:
        print(f"FETCH_ERROR: {exc}")
        continue
    print("version:", data.get("version"))
    print("table dependency:", {k: v for k, v in data.get("dependencies", {}).items()
                                if "table" in k or k == "rc-util"})
PY

Repository: Agenta-AI/agenta

Length of output: 613


🏁 Script executed:

set -euo pipefail

python3 - <<'PY'
from urllib.request import urlopen
import ssl

ctx = ssl._create_unverified_context()
for url in [
    "https://unpkg.com/rc-table@7.26.0/es/interface.d.ts",
    "https://unpkg.com/rc-table@7.26.0/package.json",
]:
    print(f"--- {url} ---")
    try:
        text = urlopen(url, context=ctx, timeout=20).read().decode()
    except Exception as exc:
        print(f"FETCH_ERROR: {exc}")
        continue
    for i, line in enumerate(text.splitlines(), 1):
        if any(token in line for token in ("FixedType", "AlignType", "fixed?:", "align?:")):
            print(f"{i}:{line}")
PY

Repository: Agenta-AI/agenta

Length of output: 475


🏁 Script executed:

set -euo pipefail

python3 - <<'PY'
from urllib.request import urlopen
import ssl, tarfile, io

ctx = ssl._create_unverified_context()
for package, version in [("rc-table", "7.26.0"), ("`@rc-component/table`", "1.9.1")]:
    url = f"https://registry.npmjs.org/{package}/{version}"
    print(f"--- {package}@{version} runtime references ---")
    try:
        meta = urlopen(url, context=ctx, timeout=20).read()
        import json
        data = json.loads(meta)
        tarball = urlopen(data["dist"]["tarball"], context=ctx, timeout=20).read()
        archive = tarfile.open(fileobj=io.BytesIO(tarball), mode="r:gz")
    except Exception as exc:
        print(f"FETCH_ERROR: {exc}")
        continue
    matches = 0
    for member in archive.getmembers():
        if not member.isfile() or not member.name.endswith((".js", ".mjs", ".ts", ".tsx")):
            continue
        text = archive.extractfile(member).read().decode("utf-8", "replace")
        if "fixed ===" in text or "fixed ==" in text or "textAlign" in text or "align:" in text:
            for i, line in enumerate(text.splitlines(), 1):
                if any(token in line for token in ("fixed ===", "fixed ==", "textAlign", "align:")):
                    print(f"{member.name}:{i}:{line.strip()}")
                    matches += 1
                    if matches >= 30:
                        break
        if matches >= 30:
            break
PY

Repository: Agenta-AI/agenta

Length of output: 6315


Preserve fixed-column behavior across the AntD peer range.

@agenta/ui supports antd >=5.0.0, but AntD 5.0.0 only fixes columns with true, "left", or "right". Restrict ColumnFixed to those values, or normalize "start" and "end" in toAntdColumns. AntD 6 supports the current union. ColumnAlign does not require this change.


/** Internal column type with ordering metadata for sorting during grouping */
type OrderedColumn<T> = ColumnType<T> & {__order?: number}
type OrderedColumn<T> = ColumnDef<T> & {__order?: number}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Return the grouped-column union.

groupColumnsRecursive adds {children} group columns, but its signatures report ColumnDef<T>[]. ColumnDef<T> is leaf-only. This erases the group-column contract from direct groupColumns consumers.

Return ColumnDefs<T> from both grouping functions. Type OrderedColumn<T> and countLeafColumns with the same union.

Proposed type fix
-import type {ColumnDef} from "../InfiniteVirtualTable/columnDef"
+import type {ColumnDef, ColumnDefs} from "../InfiniteVirtualTable/columnDef"

-type OrderedColumn<T> = ColumnDef<T> & {__order?: number}
+type OrderedColumn<T> = ColumnDefs<T>[number] & {__order?: number}

-function countLeafColumns<T>(columns: ColumnDef<T>[]): number {
+function countLeafColumns<T>(columns: ColumnDefs<T>): number {

-): ColumnDef<T>[] {
-    const result: ColumnDef<T>[] = []
+): ColumnDefs<T> {
+    const result: ColumnDefs<T> = []

-): ColumnDef<T>[] {
+): ColumnDefs<T> {

Also applies to: 102-105, 121-127, 136-136, 252-256

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

frontend refactoring A code change that neither fixes a bug nor adds a feature size:XL This PR changes 500-999 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant