Measured on @objectstack/console 17.2.0 (plugin-gantt, plugin-timeline, plugin-calendar), found while giving one object a kanban / gantt / timeline set that must colour consistently by status (objectstack-ai/duly#12).
The inversion
GanttConfigSchema.colorField is described as "Field that drives the bar color". The renderer's task mapping does this:
letre=a ? n[a] : void0;// a = colorField, n = the recordif(!re){// ← only when colorField is ABSENTlete=n.status??n.state??n.priority??n.severity;if(e!=null&&e!==""){lett=cnt(void0,e);t&&(re=unt(t));}}…
style: {…,backgroundColor: n.color||"#3b82f6",…}So with colorField: 'status', color becomes the raw stored value — "open" — and lands in backgroundColor: "open". That is not a colour; the browser drops the declaration and every bar falls back to the bg-primary class. All bars identical.
With the key absent, the fallback branch runs, maps the status value through the semantic-token helpers (cnt → unt) and produces a real hex per state. Bars separate by status.
Declaring the documented key is strictly worse than omitting it, and there is no error, no warning, and no console message either way.
The same key means three different things across the three renderers
| renderer | colorField: '<select field>' resolves to |
|---|
plugin-timeline | the authored option colour — it builds {value → option} from objectSchema.fields[colorField].options and reads option.color |
plugin-calendar | not a hex, so a stable hash of the string into a fixed palette — consistent per value, unrelated to the authored colour |
plugin-gantt | the raw value, straight into backgroundColor — invalid CSS, no colour at all |
An author who colours three lenses by one field to keep them reading as one system gets three unrelated results, one of which is "no colour". Nothing at author time distinguishes them; the key has one name and one .describe().
Suggested fix
Make gantt resolve colorField the way plugin-timeline already does — it has objectSchema in hand (it fetches it for labels and tooltip formatting), so the option lookup is available:
- if the field has
options and the record's value matches one with a color, use that colour; - else if the value already looks like a colour or a known palette token, use it (today's behaviour, which is the only one the current code supports);
- else fall through to the existing semantic-token derivation instead of emitting an invalid CSS value.
Aligning calendar onto the same ladder would make the three agree; timeline is already the reference implementation, so it is a matter of lifting that resolver into somewhere all three can call.
Worth stating in GanttConfigSchema/CalendarConfigSchema's .describe() afterwards whether the key means "field holding a colour" or "field to derive a colour from" — right now the name reads as the second and gantt implements the first.
What we shipped meanwhile
The gantt view in duly deliberately declares nocolorField, with the measurement written into the source comment so nobody "fixes" it back. The timeline view does declare it, because there it does the right thing.
Measured on
@objectstack/console17.2.0 (plugin-gantt,plugin-timeline,plugin-calendar), found while giving one object a kanban / gantt / timeline set that must colour consistently bystatus(objectstack-ai/duly#12).The inversion
GanttConfigSchema.colorFieldis described as "Field that drives the bar color". The renderer's task mapping does this:So with
colorField: 'status',colorbecomes the raw stored value —"open"— and lands inbackgroundColor: "open". That is not a colour; the browser drops the declaration and every bar falls back to thebg-primaryclass. All bars identical.With the key absent, the fallback branch runs, maps the status value through the semantic-token helpers (
cnt→unt) and produces a real hex per state. Bars separate by status.Declaring the documented key is strictly worse than omitting it, and there is no error, no warning, and no console message either way.
The same key means three different things across the three renderers
colorField: '<select field>'resolves toplugin-timeline{value → option}fromobjectSchema.fields[colorField].optionsand readsoption.colorplugin-calendarplugin-ganttbackgroundColor— invalid CSS, no colour at allAn author who colours three lenses by one field to keep them reading as one system gets three unrelated results, one of which is "no colour". Nothing at author time distinguishes them; the key has one name and one
.describe().Suggested fix
Make gantt resolve
colorFieldthe wayplugin-timelinealready does — it hasobjectSchemain hand (it fetches it for labels and tooltip formatting), so the option lookup is available:optionsand the record's value matches one with acolor, use that colour;Aligning calendar onto the same ladder would make the three agree; timeline is already the reference implementation, so it is a matter of lifting that resolver into somewhere all three can call.
Worth stating in
GanttConfigSchema/CalendarConfigSchema's.describe()afterwards whether the key means "field holding a colour" or "field to derive a colour from" — right now the name reads as the second and gantt implements the first.What we shipped meanwhile
The gantt view in
dulydeliberately declares nocolorField, with the measurement written into the source comment so nobody "fixes" it back. The timeline view does declare it, because there it does the right thing.