Skip to content

Executive dashboard: global dateRange narrows widgets that declare their own time window, so YTD metrics report only the current quarter #499

Description

@yinlianghui

Description

On the Executive Overview dashboard, the dashboard-level dateRange filter is AND-ed on top of each widget's own close_date filter instead of being suppressed for widgets that already declare their own time window. The intersection of the two windows silently wins, so widgets labelled "YTD" or "last 12 months" actually report only the current quarter.

Four widgets in src/dashboards/executive.dashboard.ts are affected. Because the headline number still renders plausibly, there is no error to notice — the dashboard just reports the wrong figure to leadership.

Steps to Reproduce

  1. pnpm dev and open /_console/apps/app.objectstack.hotcrm/dashboard/executive_dashboard
  2. Leave the date filter at its default (this_quarter)
  3. Inspect the POST /api/v1/analytics/dataset/query responses (each response echoes its generated sql)

Expected vs Actual

A widget that declares its own close_date filter should own its time semantics; the dashboard dateRange should not be injected into it.

total_revenue_ytd — titled "Total Revenue (YTD)" / 年度累计收入, described "Closed-won revenue this year":

SELECT SUM("crm_opportunity"."amount") AS "total_amount" FROM "crm_opportunity"
WHERE "crm_opportunity"."stage" = $1
  AND "crm_opportunity"."close_date" >= $2   -- {current_year_start}, from the widget
  AND "crm_opportunity"."close_date" >= $3   -- quarter start, injected
  AND "crm_opportunity"."close_date" <= $4   -- quarter end,   injected

The card reads 781,012. That is this quarter's closed-won revenue, not YTD.

revenue_trend — titled "Revenue Trend", described "Closed-won revenue over the last 12 months". Same double bound; the chart renders 3 points inside July rather than 12 months.

revenue_by_industry — titled "YTD closed-won revenue split by customer industry". Same double bound; the donut is quarter-scoped.

pipeline_by_stage — this is the most misleading of the four. It reports open pipeline (stage NOT IN (closed_won, closed_lost)), but gets quarter-bounded anyway:

SELECT "crm_opportunity"."stage", SUM("crm_opportunity"."amount") FROM "crm_opportunity"
WHERE "crm_opportunity"."stage" NOT IN ($1, $2)
  AND "crm_opportunity"."close_date" >= $3
  AND "crm_opportunity"."close_date" <= $4
GROUP BY "crm_opportunity"."stage"

Open deals forecast to close next quarter are silently dropped, so total open pipeline is understated with no indication on screen.

Environment

  • Branch main @ 00c83e9, dev server on :4001
  • Affected file: src/dashboards/executive.dashboard.ts

Suggested Fix

Short term, in this repo: add filterBindings: { dateRange: false } to total_revenue_ytd, revenue_trend, revenue_by_industry, and pipeline_by_stage, matching the existing opt-outs on total_accounts / total_contacts / open_leads.

Longer term, the framework default looks wrong. Today dateRange is injected into every widget bound to an object that has the field, and opting out is manual and easy to forget — the failure mode is a silently incorrect number rather than an error. Worth considering: when a widget already constrains the dateRange field itself, let the widget's filter take precedence (or at least warn at build time). Related context in the ObjectStack 15 / framework#2501 note already recorded at src/dashboards/executive.dashboard.ts:91-97.

Once fixed, the titles and descriptions become accurate as written; no copy changes needed.

Activity

  1. yinlianghui commented on Jul 30, 2026

    @yinlianghui
    CollaboratorAuthor

    Fixed on main by #532 — its squash merge carried the dashboard commit fix(dashboards): stop global dateRange from narrowing widgets with own time windows (originally efa59ab8 on the yinlianghui fork).

    All 8 self-windowed widgets across the 4 dashboards (incl. the four Executive ones reported here) now declare filterBindings: { dateRange: false }, so the dashboard-level date picker is no longer AND-ed into their own close_date windows — Executive "Total Revenue (YTD)" reports the full year again. A metadata guard in test/metadata-references.test.ts keeps every self-windowed widget opted out.

    Closing as fixed.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions