fix: normalize kanban groupBy matching for label-vs-value mismatch#450
fix: normalize kanban groupBy matching for label-vs-value mismatch#450
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Field.select() converts option values to snake_case (e.g. 'In Progress' → 'in_progress'), but seed data often uses the original label. The KanbanRenderer now builds a label→id mapping so data values match column IDs regardless of casing. Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Fixes Kanban groupBy grouping when record values use select labels (e.g. "In Progress") while Kanban column IDs use select option values (e.g. "in_progress"), preventing empty columns despite successful data fetches.
Changes:
- Adds a case-insensitive label/title→columnId normalization map when grouping flat
datainto Kanbancolumns. - Normalizes each record’s
groupBykey before assigning it to a column group.
| // Build label→id mapping so data values (labels like "In Progress") | ||
| // match column IDs (option values like "in_progress") | ||
| const labelToColumnId: Record<string, string> = {}; | ||
| columns.forEach((col: any) => { | ||
| if (col.id) labelToColumnId[String(col.id).toLowerCase()] = col.id; | ||
| if (col.title) labelToColumnId[String(col.title).toLowerCase()] = col.id; | ||
| }); |
There was a problem hiding this comment.
The groupBy normalization is only implemented for KanbanRenderer here. The separately-registered kanban-enhanced renderer in the same file still groups by const key = item[groupBy] (exact match), so the label-vs-value mismatch will still produce empty columns when consumers use the enhanced variant. Consider reusing the same label/title→id normalization logic in the kanban-enhanced registration (ideally via a shared helper) to keep behavior consistent across both renderers.
| // Build label→id mapping so data values (labels like "In Progress") | ||
| // match column IDs (option values like "in_progress") | ||
| const labelToColumnId: Record<string, string> = {}; | ||
| columns.forEach((col: any) => { | ||
| if (col.id) labelToColumnId[String(col.id).toLowerCase()] = col.id; | ||
| if (col.title) labelToColumnId[String(col.title).toLowerCase()] = col.id; | ||
| }); | ||
|
|
||
| // 1. Group data by key, normalizing via label→id mapping | ||
| const groups = data.reduce((acc, item) => { | ||
| const key = item[groupBy]; | ||
| const rawKey = String(item[groupBy] ?? ''); | ||
| const key = labelToColumnId[rawKey.toLowerCase()] ?? rawKey; | ||
| if (!acc[key]) acc[key] = []; | ||
| acc[key].push(item); | ||
| return acc; |
There was a problem hiding this comment.
The new label/title→id normalization for grouping is not covered by tests. Current tests only cover exact groupBy value matches (e.g. status: 'todo'), so this regression-prone behavior change should have a unit/integration test asserting that a record with item[groupBy] equal to a column title/label (e.g. "In Progress") is grouped into the column whose id is the normalized option value (e.g. "in_progress").
Kanban board view showed empty columns (0 cards) despite data being fetched successfully.
Root Cause
Field.select(['In Progress', 'Backlog', ...])auto-converts option values to snake_case (in_progress,backlog). Kanban columns are generated from these options usingopt.valueas column ID. However, seed data stores the original labels (status: 'In Progress'). The grouping logic used exact matching, so no data matched any column:Fix
'In Progress'resolves to column'in_progress'Before:
After:
💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.