Skip to content

fix: apply type inference pipeline to accessorKey-format grid columns#903

Merged
hotlong merged 4 commits intomainfrom
copilot/fix-objectgrid-type-inference
Feb 28, 2026
Merged

fix: apply type inference pipeline to accessorKey-format grid columns#903
hotlong merged 4 commits intomainfrom
copilot/fix-objectgrid-type-inference

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Feb 28, 2026

ObjectGrid.generateColumns() returned accessorKey-format columns as-is, bypassing inferColumnType()getCellRenderer() entirely. Dates rendered as raw ISO strings, statuses as plain text, progress as raw numbers.

Core fix — ObjectGrid.tsx

The accessorKey branch now iterates columns and applies the same inference + renderer pipeline as the field branch, skipping columns that already have a cell renderer:

if ('accessorKey' in firstCol) {
  return (cols as any[]).map((col) => {
    if (col.cell) return col; // preserve custom renderers

    const syntheticCol = { field: col.accessorKey, label: col.header, type: col.type };
    const inferredType = inferColumnType(syntheticCol);
    if (!inferredType) return col;

    const CellRenderer = getCellRenderer(inferredType);
    // ... build fieldMeta, return col with cell renderer
  });
}

humanizeLabel()fields/src/index.tsx

  • New exported utility: in_progressIn Progress, high-priorityHigh Priority
  • SelectCellRenderer uses it as fallback when no explicit option.label exists
  • Auto-generated select options in both column format branches now humanize labels

PercentCellRenderer normalization — fields/src/index.tsx

Fields matching WHOLE_PERCENT_FIELD_PATTERN (/progress|completion/) treat values as 0–100 directly. Other percent fields (e.g. probability) continue treating 0–1 as fractions. This means progress: 7575% and probability: 0.7575% both render correctly.

Tests

  • 14 new tests in cell-renderers.test.tsx (humanizeLabel edge cases, SelectCellRenderer fallback, PercentCellRenderer progress fields)
  • 5 new tests in accessorKey-inference.test.tsx (inference, date rendering, progress bars, custom renderer preservation)
Original prompt

This section details on the original issue you should resolve

<issue_title>ObjectGrid: accessorKey-format columns bypass type inference — raw dates, no badges, no progress bars</issue_title>
<issue_description>## Summary

The ObjectGrid rendering pipeline completely skips type inference and cell renderer injection when columns use accessorKey format (data-table format) instead of field format (ListColumn format). This causes all type-aware rendering to break — dates show raw ISO strings, status/priority show plain text, progress shows raw numbers, and user fields show raw IDs.

image1

Root Cause

In ObjectGrid.generateColumns(), the accessorKey branch returns columns as-is with no processing:

// packages/plugin-grid/src/ObjectGrid.tsx L506-514
if ('accessorKey' in firstCol) {
  return cols;  // ← BUG: skips entire inference + renderer pipeline
}

Meanwhile the field (ListColumn) branch correctly runs inferColumnType()getCellRenderer() → cell renderer injection. This is a platform-level rendering pipeline gap that affects any view using accessorKey-format column definitions.

Symptoms (all caused by the same root cause)

Column Type Current (broken) Expected
Date (start_date, end_date) 2024-02-01T00:00:00.000Z Feb 1, 2024 via DateCellRenderer
Status (status) in_progress (plain text) Colored <Badge> via SelectCellRenderer
Priority (priority) high / critical (plain text) Semantic colored badge (orange/red)
Progress (progress) 75 (raw number) Mini progress bar + 75% via PercentCellRenderer
Assignee (assignee) 2 (raw ID) Avatar + name via UserCellRenderer

Required Changes

1. [P0] Apply inference to accessorKey-format columns

File: packages/plugin-grid/src/ObjectGrid.tsxgenerateColumns() L506-514

When columns are in accessorKey format, iterate and apply inferColumnType() + getCellRenderer() for columns that don't already have a cell renderer:

if ('accessorKey' in firstCol) {
  return (cols as any[]).map((col, colIndex) => {
    if (col.cell) return col; // already has custom renderer

    const syntheticCol = { field: col.accessorKey, label: col.header, type: col.type };
    const inferredType = inferColumnType(syntheticCol);
    if (!inferredType) return col;

    const CellRenderer = getCellRenderer(inferredType);
    const fieldMeta = { name: col.accessorKey, type: inferredType };

    if (inferredType === 'select') {
      const uniqueValues = Array.from(new Set(data.map(row => row[col.accessorKey]).filter(Boolean)));
      fieldMeta.options = uniqueValues.map(v => ({ value: v, label: humanizeLabel(String(v)) }));
    }

    return {
      ...col,
      headerIcon: getTypeIcon(inferredType),
      cell: (value, row) => <CellRenderer value={value} field={fieldMeta} />,
    };
  });
}

2. [P1] Auto-humanize snake_case select labels

File: packages/fields/src/index.tsxSelectCellRenderer

Add and export a humanizeLabel() utility, use as fallback when no option.label exists:

export function humanizeLabel(value: string): string {
  return value.replace(/[_-]/g, ' ').replace(/\b\w/g, c => c.toUpperCase());
}

// In SelectCellRenderer:
const label = option?.label || humanizeLabel(String(value));

Also apply in ObjectGrid.generateColumns() when auto-generating options from data values.

3. [P1] PercentCellRenderer value normalization for progress fields

File: packages/fields/src/index.tsxPercentCellRenderer

Use field name to disambiguate 0-1 fraction vs 0-100 whole number:

const isWholePercentField = /progress|completion/.test(field?.name?.toLowerCase() || '');
const barValue = isWholePercentField
  ? numValue
  : (numValue > -1 && numValue < 1) ? numValue * 100 : numValue;

Affected Packages

  • packages/plugin-grid/src/ObjectGrid.tsx — core fix
  • packages/fields/src/index.tsxSelectCellRenderer, PercentCellRenderer, humanizeLabel()

Acceptance Criteria

  • accessorKey-format columns receive type inference via inferColumnType()
  • Inferred types get appropriate getCellRenderer() cell renderers applied
  • Columns with existing cell renderer are NOT overridden
  • snake_case select values display as Title Case (e.g., in_progressIn Progress)
  • Explicit option.label still takes priority over humanized fallback
  • progress field with value 75 renders as 75% with correctly filled bar
  • probability field with value 0.75 renders as 75%
  • All existing tests pass; new tests added for:
    • accessorKey-format inference path
    • humanizeLabel() edge cases
    • PercentCellRenderer with progress-type fields
  • ROADMAP.md updated</issue_description>

Comments on the Issue (you are @copilot in this section)


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

@vercel
Copy link
Copy Markdown

vercel Bot commented Feb 28, 2026

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

Project Deployment Actions Updated (UTC)
objectui Ready Ready Preview, Comment Feb 28, 2026 5:14am
objectui-demo Ready Ready Preview, Comment Feb 28, 2026 5:14am
objectui-storybook Ready Ready Preview, Comment Feb 28, 2026 5:14am

Request Review

Copilot AI and others added 3 commits February 28, 2026 05:04
…Label, fix PercentCellRenderer for progress fields

Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
…constant

Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix ObjectGrid to apply type inference for accessorKey columns fix: apply type inference pipeline to accessorKey-format grid columns Feb 28, 2026
@hotlong
Copy link
Copy Markdown
Collaborator

hotlong commented Feb 28, 2026

@copilot 仔细评估是否已经完成了任务中要求的所有开发

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Feb 28, 2026

@copilot 仔细评估是否已经完成了任务中要求的所有开发

All acceptance criteria from the issue have been verified complete:

  1. accessorKey-format columns now receive inferColumnType() + getCellRenderer()ObjectGrid.tsx:512-533
  2. ✅ Columns with existing cell renderer are preserved (col.cell guard at line 514)
  3. humanizeLabel() exported from @object-ui/fields — converts in_progressIn Progress; used as fallback in SelectCellRenderer (both single and array values) and in ObjectGrid auto-generated select options
  4. PercentCellRenderer uses WHOLE_PERCENT_FIELD_PATTERN (/progress|completion/) — progress: 7575%, probability: 0.7575%
  5. ✅ 19 new tests added: 7 humanizeLabel edge cases, 3 SelectCellRenderer fallback, 4 PercentCellRenderer progress fields, 5 accessorKey inference path
  6. ✅ All existing tests pass: 327 fields + 293 plugin-grid
  7. ✅ ROADMAP.md updated with 3 new feature entries + test counts

@hotlong hotlong marked this pull request as ready for review February 28, 2026 05:46
Copilot AI review requested due to automatic review settings February 28, 2026 05:46
@hotlong hotlong merged commit f8450a1 into main Feb 28, 2026
7 checks passed
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Fixes a rendering pipeline gap in @object-ui/plugin-grid where accessorKey-format columns previously bypassed ObjectGrid’s type inference and cell renderer injection, leading to raw/unstyled cell output for dates, select-like statuses, and percent/progress fields.

Changes:

  • Apply inferColumnType()getCellRenderer() to accessorKey-format columns (while preserving existing custom cell renderers).
  • Add humanizeLabel() to @object-ui/fields and use it as a fallback for select option labels (including auto-generated options).
  • Refine PercentCellRenderer normalization for “whole percent” fields (e.g., progress, completion) and add coverage via new tests.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
packages/plugin-grid/src/ObjectGrid.tsx Applies the inference/renderer pipeline to accessorKey columns and humanizes auto-generated select option labels.
packages/fields/src/index.tsx Exports humanizeLabel(), uses it in SelectCellRenderer, and updates percent normalization for progress/completion-style fields.
packages/plugin-grid/src/tests/accessorKey-inference.test.tsx Adds regression tests ensuring accessorKey columns receive inference/renderers and preserve custom cells.
packages/fields/src/tests/cell-renderers.test.tsx Adds tests for humanizeLabel, SelectCellRenderer fallback behavior, and PercentCellRenderer whole-percent handling.
ROADMAP.md Marks the work as completed and updates reported test counts.


return {
...col,
headerIcon: getTypeIcon(inferredType),
Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

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

In the accessorKey branch, inferred columns always overwrite any existing headerIcon on the incoming column object. If a consumer provided a custom headerIcon (but no custom cell), it will be lost. Consider only setting headerIcon when it’s not already present (e.g., prefer col.headerIcon if defined).

Suggested change
headerIcon: getTypeIcon(inferredType),
headerIcon: col.headerIcon ?? getTypeIcon(inferredType),

Copilot uses AI. Check for mistakes.
Comment on lines +527 to +530

return {
...col,
headerIcon: getTypeIcon(inferredType),
Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

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

In the accessorKey inference path, consider setting a default align: 'right' for inferred numeric types (number/currency/percent) when the incoming column doesn’t specify align. The ListColumn branch does this inference, so without it the two column formats render numeric fields with different alignment.

Suggested change
return {
...col,
headerIcon: getTypeIcon(inferredType),
const isNumericType =
inferredType === 'number' ||
inferredType === 'currency' ||
inferredType === 'percent';
return {
...col,
headerIcon: getTypeIcon(inferredType),
// Respect explicit align, otherwise default right for numeric-like types
align: col.align ?? (isNumericType ? 'right' : undefined),

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ObjectGrid: accessorKey-format columns bypass type inference — raw dates, no badges, no progress bars

3 participants