Skip to content

Both grouped grids group by fields they never fetch — "By business unit" is one (empty) bucket holding every row #76

Description

@os-warren

Found by browser verification on merged main (19a0306) with the #75 seed loaded — 186 tasks across 5 business units.

The manager's org lens is broken, and it is broken in the way that reads as a data problem rather than a bug.

Measured

/_console/apps/ai.objectstack.duly/duly_task/view/by_unit renders one collapsible group:

Business unit
  ▾ (empty)   100

Every row is inside it. The rows themselves are correct — right records, right count, right sort. Only the grouping did nothing.

The data is fine. Straight from the store:

select business_unit, count(*) from duly_task group by 1
  9a_MClo_4ByhoRgj  61
  Q2UJSlOy4ICnWmTg  86
  b2usyCHDAho0owsx  31
  K36wAueKC2W1fz1k   7
  BUZwsjpNFv-cbyZA   1     → 186 rows, 0 nulls

And the dashboard's Not moving, by business unit chart groups the same field on the same data correctly, rendering Northgate Operations and Northgate Quality as separate bars.

Cause

The grid builds its query projection from columns alone. Captured on the page load:

GET /api/v1/data/duly_task?populate=owner&top=100&select=id,subject,status,due_date,period_key,…
  → record keys: id,subject,status,due_date,period_key,owner,source
  → business_unit: undefined

src/views/task.view.ts shares one columns const across every task lens:

const columns = [
  { field: 'subject' }, { field: 'status' }, { field: 'due_date' },
  { field: 'period_key' }, { field: 'owner' }, { field: 'source' },
];

business_unit is not in it, so it is never requested, so it is undefined on arrival, so objectui's buildSegmentLabel hits its first line — if (value === undefined || …) return '(empty)' — for all 186 rows.

Both grouped views are affected, and duty is affected twice

View Groups by In its columns?
task.view.ts → by_unit business_unit ❌
duty.view.ts → grouped lens business_unit ❌
duty.view.ts → grouped lens owner ❌

duty's columns are name, form, frequency, source, status — neither grouping field is among them, so that view collapses on both levels.

The kanban groupByFields are fine by luck: status (board) and owner (assignments) both happen to be displayed columns.

Filed upstream

objectstack-ai/objectui#7179 — the projection should union the grouping fields rather than requiring authors to mirror them in columns. Two config keys that are separate in the schema imply grouping by a non-displayed field is supported, and it silently is not.

That is the real fix and it is not ours. Do not wait for it — the workaround here is also just better UI.

Scope

  1. Add the grouping fields to the columns of both grouped views. On a by-unit view the unit column is worth showing anyway, so this is not a wart; on duty's grouped lens, add business_unit and owner. Keep the shared columns const for the lenses that want the current six, and give the grouped lenses their own list rather than widening every view to carry a column only one of them needs.

  2. Add a test that fails when a view groups or kanban-groups by a field its columns do not carry. This is the actual deliverable — the fix above is three lines and the guard is what stops it coming back. It belongs in test/metadata-bindings.test.ts alongside the other binding guards, and it must be written so it would have failed on 19a0306: assert that before you fix the views, and say so in the test's comment.

    Note carefully why the existing guard did not catch this, because it is the interesting part: test/metadata-bindings.test.ts resolves business_unit against duly_task's schema, and it resolves — it is a real, populated, correctly-typed lookup. Every binding was valid. The bug is a relationship between two config keys, not a dangling reference, and no amount of reference checking sees it.

  3. Leave sort alone unless you can measure a failure. Sorting is applied server-side through the query, not client-side over the projection, so a sort field outside columns is very likely fine — stalled sorts by last_update_at, schedule by visible_from, and both are outside the shared six. If you can show a sort silently not happening, that is a second finding and its own card; do not fold an unmeasured guess into this one, and do not widen the test to sort without evidence.

Acceptance

  • by_unit renders one group per business unit, each labelled with the unit's name, counts summing to the visible row total
  • the duty grouped lens groups on both levels
  • a test that fails on 19a0306 and passes after
  • verified in a browser against the seeded data, not only in tests — a screenshot of the grouped view in the PR

Gates

pnpm validate && pnpm typecheck && pnpm test && pnpm build.

Activity

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

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions