Skip to content

Commit f59a439

Browse files
os-zhuangCopilot
andcommitted
docs(skills/ui): expand compareTo + add categoryGranularity section
* Refine the compareTo section so authors know: - the exact i18n trend labels metrics get - cartesian-vs-pie/donut/funnel behaviour (last is skipped) - the muted overlay opacity / dashArray defaults and the per-series overrides - that the shifted query reuses the original filter shape * Add a new 'Server-side date bucketing — categoryGranularity' section next to compareTo, covering: - the five bucket grains and the SQL functions emitted per driver - granularity selection rule of thumb (day/week/month/quarter/year) - interaction with compareTo (overlay aligns bucket-for-bucket) - the chartConfig.xAxis.format pairing authors must remember - a worked monthly-trend-with-YoY example * Cross-link the modifiers from the Widget Types intro so the Production Pattern section is no longer the only place they appear. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 901fa3a commit f59a439

1 file changed

Lines changed: 76 additions & 9 deletions

File tree

skills/objectstack-ui/SKILL.md

Lines changed: 76 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,9 @@ an `aggregate` measure or chart spec, and a `layout: {x,y,w,h}`.
248248

249249
See the **Production Pattern** section below for the full
250250
`Dashboard` shape with `refreshInterval`, header actions, date range,
251-
global filters, and widget options.
251+
global filters, widget options, and the period-over-period (`compareTo`)
252+
/ date-bucketing (`categoryGranularity`) modifiers available on every
253+
data-bound widget.
252254

253255
---
254256

@@ -491,15 +493,80 @@ no second `filter` is required.
491493
| `{ offset: '7d' }` | Shift by an explicit duration. Units: `d` (days), `w` (weeks), `M` (months), `y` (years). |
492494

493495
* **Metric widgets** — the prior-period value renders as a small caption
494-
beneath the headline number, alongside a green/red delta arrow.
495-
Authors should *not* hand-author `options.trend` when `compareTo` is
496-
set; the renderer wins and overwrites it.
497-
* **Chart widgets** — the comparison series is appended after the
498-
primary series with `variant: 'comparison'` and styled as a muted /
499-
dashed overlay. Single-series charts (bar / line / area) get an
500-
automatic second series; multi-series pivots are not yet supported.
496+
beneath the headline number, alongside a green/red delta arrow and an
497+
i18n label (`较上期` / `vs previous period`, `较去年` / `vs last year`,
498+
`较前7天` / `vs previous 7d`, etc.). Authors should *not* hand-author
499+
`options.trend` when `compareTo` is set; the renderer wins and overwrites
500+
it.
501+
* **Cartesian charts** (`line` / `area` / `bar` / `horizontal-bar` /
502+
`scatter`) — the comparison series is appended after the primary series
503+
with `variant: 'comparison'` and styled as a muted overlay (`opacity: 0.5`
504+
+ `strokeDasharray: '4 4'` for line/area/scatter; `opacity: 0.4` for
505+
bars). Override per-series with `series.dashArray` / `series.opacity`.
506+
* **Pie / donut / funnel**`compareTo` is silently ignored; there is no
507+
meaningful "two-period" composition for part-of-whole charts.
501508
* **Requirements**`compareTo` is a no-op when the filter contains no
502-
resolvable date macros and no global `dateRange` is configured.
509+
resolvable date macros and no global `dateRange` is configured. The
510+
shifted query reuses the original `filter` shape and replaces only the
511+
date-bound clauses.
512+
513+
```typescript
514+
// Metric — WoW delta
515+
{ id: 'done_this_week', type: 'metric', object: 'task',
516+
filter: { assignee: '{current_user_id}', status: 'done',
517+
completed_at: { $gte: '{week_start}' } },
518+
aggregate: 'count',
519+
compareTo: 'previousPeriod' }
520+
521+
// Bar — YoY overlay on a stable category set
522+
{ id: 'headcount_by_dept', type: 'bar', object: 'employee',
523+
filter: { status: { $ne: 'terminated' } },
524+
aggregate: 'count', categoryField: 'department',
525+
compareTo: 'previousYear' }
526+
```
527+
528+
### Server-side date bucketing — `categoryGranularity`
529+
530+
For any chart with `categoryField` pointing at a date/datetime field, set
531+
`categoryGranularity` to bucket values server-side. Without it every
532+
distinct timestamp becomes its own category, which collapses a 12-row
533+
seed dataset into a 12-point flat-line chart.
534+
535+
| Value | Bucket key |
536+
|:--|:--|
537+
| `'day'` | Calendar day (`YYYY-MM-DD`) |
538+
| `'week'` | ISO week (`YYYY-Www`) |
539+
| `'month'` | Calendar month (`YYYY-MM`) |
540+
| `'quarter'` | Calendar quarter (`YYYY-Qn`) |
541+
| `'year'` | Calendar year (`YYYY`) |
542+
543+
* **Engine support** — Postgres `date_trunc`, MySQL `date_format`, SQLite
544+
`strftime`, MongoDB `$dateTrunc`, in-memory `bucketDateValue` fallback.
545+
All emitted by the analytics service, not the client.
546+
* **Rule of thumb**`day` for ≤30d windows, `week` for ~90d, `month`
547+
for 6–12 months, `quarter` for multi-year, `year` for retention /
548+
compliance scopes.
549+
* **Combines with `compareTo`** — the comparison query is issued with the
550+
same granularity, so the muted overlay aligns bucket-for-bucket.
551+
* **xAxis format** — pair with a matching `chartConfig.xAxis.format`
552+
(`%b %d` for day, `%b %Y` for month, etc.) so the rendered labels
553+
match the bucket grain.
554+
555+
```typescript
556+
// Line chart — monthly trend with YoY overlay
557+
{ id: 'signed_by_month', type: 'line', object: 'contract',
558+
filter: { signed_date: { $gte: '{12_months_ago}' } },
559+
aggregate: 'count',
560+
categoryField: 'signed_date',
561+
categoryGranularity: 'month',
562+
compareTo: 'previousYear',
563+
chartConfig: {
564+
type: 'line',
565+
xAxis: { field: 'signed_date', format: '%b %Y' },
566+
yAxis: [{ field: 'value', format: '0,0' }],
567+
},
568+
}
569+
```
503570

504571
---
505572

0 commit comments

Comments
 (0)