Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions .changeset/10222-retire-timeline-metafields-reads.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
'@object-ui/plugin-timeline': minor
'@object-ui/plugin-list': minor
---

Retire the undeclared timeline `metaFields` reads in both packages (objectui#10222).

The spec's `TimelineConfigSchema` is a strict object that declares no `metaFields` member and
refuses one, yet `ObjectTimeline` read it (through an `as any` cast) to pick the chip fields
beside each title, and `ListView` read it three times: two field collectors put the listed
fields into `$expand` / `$select`, and the status / priority auto-projection was skipped when
the list was present. All four reads are deleted.

**Behaviour change:** a stored interface-page view carrying `options.timeline.metaFields` falls
back to the default card labels (the built-in `status` / `priority` chips, limited to the fields
the object declares), and the fields that list named are no longer fetched for it. No such view
has been found; the stored rows are not censused. A timeline without the key renders and fetches
exactly what it did before, because `ListView` now projects `status` / `priority` for every
timeline view.

`cardFields` stays the reserved spelling if authored timeline chip fields are ever asked for;
nothing is declared.
28 changes: 19 additions & 9 deletions packages/plugin-list/src/ListView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1834,10 +1834,12 @@ export const ListView = React.forwardRef<ListViewHandle, ListViewProps>(({
v.coverField, v.imageField,
v.swimlaneField, v.valueField,
// Spec `columns` = the fields shown on each kanban card (legacy: cardFields).
// ⛔ No timeline chip-field list (the retired `metaFields`) is
// collected: the spec declares none, and the timeline no longer reads
// one (objectui#10222).
...(Array.isArray(v.columns) ? v.columns : []),
...(Array.isArray(v.cardFields) ? v.cardFields : []),
...(Array.isArray(v.visibleFields) ? v.visibleFields : []),
...(Array.isArray(v.metaFields) ? v.metaFields : []),
];
for (const f of candidates) {
if (typeof f === 'string' && f) collected.add(f);
Expand Down Expand Up @@ -2206,10 +2208,12 @@ export const ListView = React.forwardRef<ListViewHandle, ListViewProps>(({
v.coverField, v.imageField,
v.swimlaneField, v.valueField,
// Spec `columns` = the fields shown on each kanban card (legacy: cardFields).
// ⛔ No timeline chip-field list (the retired `metaFields`) is
// collected: the spec declares none, and the timeline no longer
// reads one (objectui#10222).
...(Array.isArray(v.columns) ? v.columns : []),
...(Array.isArray(v.cardFields) ? v.cardFields : []),
...(Array.isArray(v.visibleFields) ? v.visibleFields : []),
...(Array.isArray(v.metaFields) ? v.metaFields : []),
];
for (const f of candidates) addSpeculative(f);
};
Expand All @@ -2222,14 +2226,20 @@ export const ListView = React.forwardRef<ListViewHandle, ListViewProps>(({
collectViewFields(schema.timeline);
collectViewFields(schema.options?.timeline);
// Timeline plugin shows status / priority chips inline. Auto-include
// them when no explicit metaFields was configured so views like
// `task_timeline` ({ columns: ['subject', 'status'] }) still get
// priority badges out of the box. Gated through addSpeculative: only
// added when the object actually has these fields (a `product` with
// no status/priority must not get them, or the list goes empty).
// them for every timeline view so views like `task_timeline`
// ({ columns: ['subject', 'status'] }) still get priority badges out
// of the box. Gated through addSpeculative: only added when the
// object actually has these fields (a `product` with no
// status/priority must not get them, or the list goes empty).
//
// Unconditional on purpose (objectui#10222, ruling batch #223 item
// 5b, letter A): this used to be skipped when the block carried an
// undeclared `metaFields` list, which the spec refuses and the
// timeline no longer reads. The chips are always the built-in pair
// now, so their values are always fetched.
{
const tCfg: any = schema.timeline ?? schema.options?.timeline;
if (tCfg && !Array.isArray(tCfg.metaFields)) {
const tCfg = schema.timeline ?? schema.options?.timeline;
if (tCfg) {
addSpeculative('status');
addSpeculative('priority');
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,13 +198,29 @@ describe('ListView — speculative view bindings are FLS-gated (objectui#7216)',
});

// ── PIN 4: timeline `dateField` ─────────────────────────────────────────
//
// REWRITTEN by objectui#10222 (ruling batch #223 item 5b, letter A), not
// deleted: what it guards, the DENIED `dateField` binding, is unchanged.
// Its fixture used to carry `metaFields: ['region']` as the permitted
// binding beside it. That key is undeclared on the spec's timeline block and
// the projection no longer reads it, so it can no longer be the live
// control. It was never a discriminating one either: `region` is in
// `COLUMNS`, so it reached `$select` through the column path whatever the
// binding did. The permitted binding is now `endDateField: 'end_date'`,
// which only the timeline binding can put in `$select`, the same shape PIN
// 3 uses for gantt. That the retired key projects nothing is pinned in
// `ListView.timelineMetaFieldsRetired-10222.test.tsx`.
it('does not project a DENIED timeline date binding', async () => {
const select = await selectFor({
columns: COLUMNS,
timeline: { dateField: 'due_date', metaFields: ['region'] },
timeline: { dateField: 'due_date', endDateField: 'end_date' },
});
expect(select).not.toContain('due_date');
expect(select).toContain('region');
expect(
select,
'both bindings ride the same helper, so the pin is only meaningful if the permitted '
+ 'one survives the same call',
).toContain('end_date');
});

// ── PIN 5: calendar bindings ────────────────────────────────────────────
Expand Down Expand Up @@ -242,8 +258,10 @@ describe('ListView — speculative view bindings are FLS-gated (objectui#7216)',

// ── PIN 8: the timeline's AUTO-ADDED status / priority badge fields ─────
//
// These two are not authored anywhere — the builder adds them itself when a
// timeline is configured with no explicit `metaFields`. Nothing upstream can
// These two are not authored anywhere — the builder adds them itself for
// every configured timeline. (It used to skip them when the block carried a
// `metaFields` list; that undeclared key is retired and no longer read,
// objectui#10222, ruling batch #223 item 5b, letter A.) Nothing upstream can
// have filtered them, so this caller is the one with no other line of
// defence at all.
it('does not project the auto-added `status` / `priority` badges when denied', async () => {
Expand Down
Loading
Loading