Skip to content

Commit fb3c535

Browse files
os-zhuangCopilot
andcommitted
feat(app-crm): add compareTo to Opportunities by Stage bar chart
The bar widget previously had no filter or compareTo, so it served as a baseline 'all opportunities' breakdown. Adding a quarter-window filter + 'compareTo: previousPeriod' lets the dashboard demonstrate how a categorical (non-time-series) chart renders the comparison overlay: side-by-side muted bars per stage instead of a dashed line. This complements the three existing compareTo usages: - 'Won This Quarter' metric (previousPeriod, quarter macros) - 'Avg Deal Size YoY' metric (previousYear) - 'Pipeline Trend 90d' line chart ({ offset: '90d' }) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 3c1eb12 commit fb3c535

2 files changed

Lines changed: 243 additions & 6 deletions

File tree

examples/app-crm/dist/objectstack.json

Lines changed: 235 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -515,7 +515,7 @@
515515
{
516516
"name": "pipeline_dashboard",
517517
"label": "Pipeline Dashboard",
518-
"description": "Aggregate view of the sales pipeline.",
518+
"description": "Aggregate view of the sales pipeline with period-over-period comparisons.",
519519
"widgets": [
520520
{
521521
"id": "total_pipeline",
@@ -538,20 +538,133 @@
538538
"y": 0,
539539
"w": 4,
540540
"h": 2
541+
},
542+
"options": {
543+
"format": "currency",
544+
"currency": "USD"
545+
}
546+
},
547+
{
548+
"id": "won_this_quarter",
549+
"title": "Won This Quarter",
550+
"description": "Revenue closed-won in the current quarter, compared to the previous quarter.",
551+
"type": "metric",
552+
"object": "crm_opportunity",
553+
"filter": {
554+
"stage": "closed_won",
555+
"close_date": {
556+
"$gte": "{current_quarter_start}",
557+
"$lte": "{current_quarter_end}"
558+
}
559+
},
560+
"compareTo": "previousPeriod",
561+
"valueField": "amount",
562+
"aggregate": "sum",
563+
"layout": {
564+
"x": 4,
565+
"y": 0,
566+
"w": 4,
567+
"h": 2
568+
},
569+
"options": {
570+
"format": "currency",
571+
"currency": "USD"
572+
}
573+
},
574+
{
575+
"id": "avg_deal_size_yoy",
576+
"title": "Avg Deal Size (YoY)",
577+
"description": "Average won-deal value this year vs the same window last year.",
578+
"type": "metric",
579+
"object": "crm_opportunity",
580+
"filter": {
581+
"stage": "closed_won",
582+
"close_date": {
583+
"$gte": "{current_year_start}",
584+
"$lte": "{current_year_end}"
585+
}
586+
},
587+
"compareTo": "previousYear",
588+
"valueField": "amount",
589+
"aggregate": "avg",
590+
"layout": {
591+
"x": 8,
592+
"y": 0,
593+
"w": 4,
594+
"h": 2
595+
},
596+
"options": {
597+
"format": "currency",
598+
"currency": "USD"
599+
}
600+
},
601+
{
602+
"id": "pipeline_trend_90d",
603+
"title": "Pipeline Trend (90d)",
604+
"description": "Daily count of opportunities created in the last 90 days, with a sliding overlay of the prior 90-day window.",
605+
"type": "line",
606+
"object": "crm_opportunity",
607+
"filter": {
608+
"close_date": {
609+
"$gte": "{90_days_ago}",
610+
"$lte": "{today}"
611+
}
612+
},
613+
"compareTo": {
614+
"offset": "90d"
615+
},
616+
"categoryField": "close_date",
617+
"aggregate": "count",
618+
"layout": {
619+
"x": 0,
620+
"y": 2,
621+
"w": 8,
622+
"h": 4
541623
}
542624
},
543625
{
544626
"id": "opportunities_by_stage",
545627
"title": "Opportunities by Stage",
546-
"description": "Count of opportunities grouped by their pipeline stage.",
628+
"description": "Count grouped by stage with previous-quarter overlay (compareTo).",
547629
"type": "bar",
548630
"object": "crm_opportunity",
631+
"filter": {
632+
"close_date": {
633+
"$gte": "{current_quarter_start}",
634+
"$lte": "{current_quarter_end}"
635+
}
636+
},
637+
"compareTo": "previousPeriod",
549638
"categoryField": "stage",
550639
"aggregate": "count",
551640
"layout": {
552-
"x": 4,
553-
"y": 0,
554-
"w": 8,
641+
"x": 8,
642+
"y": 2,
643+
"w": 4,
644+
"h": 4
645+
}
646+
},
647+
{
648+
"id": "pipeline_by_industry",
649+
"title": "Open Pipeline by Stage ($)",
650+
"description": "Open-pipeline revenue split by pipeline stage. Pie/donut/funnel ignore `compareTo`.",
651+
"type": "pie",
652+
"object": "crm_opportunity",
653+
"filter": {
654+
"stage": {
655+
"$nin": [
656+
"closed_won",
657+
"closed_lost"
658+
]
659+
}
660+
},
661+
"categoryField": "stage",
662+
"valueField": "amount",
663+
"aggregate": "sum",
664+
"layout": {
665+
"x": 0,
666+
"y": 6,
667+
"w": 6,
555668
"h": 4
556669
}
557670
}
@@ -740,6 +853,32 @@
740853
"source": "daysFromNow(60)"
741854
}
742855
},
856+
{
857+
"name": "Initech — Expansion",
858+
"account": {
859+
"externalId": "Initech"
860+
},
861+
"stage": "prospecting",
862+
"amount": 80000,
863+
"probability": 20,
864+
"close_date": {
865+
"dialect": "cel",
866+
"source": "daysFromNow(45)"
867+
}
868+
},
869+
{
870+
"name": "Acme — Add-on Module",
871+
"account": {
872+
"externalId": "Acme Corp"
873+
},
874+
"stage": "qualification",
875+
"amount": 60000,
876+
"probability": 35,
877+
"close_date": {
878+
"dialect": "cel",
879+
"source": "daysFromNow(20)"
880+
}
881+
},
743882
{
744883
"name": "Initech — Pilot",
745884
"account": {
@@ -752,6 +891,97 @@
752891
"dialect": "cel",
753892
"source": "daysAgo(7)"
754893
}
894+
},
895+
{
896+
"name": "Acme — Support Tier Upgrade",
897+
"account": {
898+
"externalId": "Acme Corp"
899+
},
900+
"stage": "closed_won",
901+
"amount": 90000,
902+
"probability": 100,
903+
"close_date": {
904+
"dialect": "cel",
905+
"source": "daysAgo(14)"
906+
}
907+
},
908+
{
909+
"name": "Globex — Analytics Pack",
910+
"account": {
911+
"externalId": "Globex Ltd"
912+
},
913+
"stage": "closed_won",
914+
"amount": 110000,
915+
"probability": 100,
916+
"close_date": {
917+
"dialect": "cel",
918+
"source": "daysAgo(21)"
919+
}
920+
},
921+
{
922+
"name": "Initech — POC",
923+
"account": {
924+
"externalId": "Initech"
925+
},
926+
"stage": "closed_won",
927+
"amount": 25000,
928+
"probability": 100,
929+
"close_date": {
930+
"dialect": "cel",
931+
"source": "daysAgo(95)"
932+
}
933+
},
934+
{
935+
"name": "Globex — Initial Seats",
936+
"account": {
937+
"externalId": "Globex Ltd"
938+
},
939+
"stage": "closed_won",
940+
"amount": 145000,
941+
"probability": 100,
942+
"close_date": {
943+
"dialect": "cel",
944+
"source": "daysAgo(110)"
945+
}
946+
},
947+
{
948+
"name": "Acme — Year-Ago Renewal",
949+
"account": {
950+
"externalId": "Acme Corp"
951+
},
952+
"stage": "closed_won",
953+
"amount": 75000,
954+
"probability": 100,
955+
"close_date": {
956+
"dialect": "cel",
957+
"source": "daysAgo(380)"
958+
}
959+
},
960+
{
961+
"name": "Globex — Year-Ago Implementation",
962+
"account": {
963+
"externalId": "Globex Ltd"
964+
},
965+
"stage": "closed_won",
966+
"amount": 210000,
967+
"probability": 100,
968+
"close_date": {
969+
"dialect": "cel",
970+
"source": "daysAgo(400)"
971+
}
972+
},
973+
{
974+
"name": "Initech — Cancelled Eval",
975+
"account": {
976+
"externalId": "Initech"
977+
},
978+
"stage": "closed_lost",
979+
"amount": 15000,
980+
"probability": 0,
981+
"close_date": {
982+
"dialect": "cel",
983+
"source": "daysAgo(30)"
984+
}
755985
}
756986
]
757987
}

examples/app-crm/src/dashboards/pipeline.dashboard.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,10 +97,17 @@ export const PipelineDashboard: Dashboard = {
9797
id: 'opportunities_by_stage',
9898
type: 'bar',
9999
title: 'Opportunities by Stage',
100-
description: 'Count of opportunities grouped by their pipeline stage.',
100+
description: 'Count grouped by stage with previous-quarter overlay (compareTo).',
101101
object: 'crm_opportunity',
102102
aggregate: 'count',
103103
categoryField: 'stage',
104+
filter: {
105+
close_date: {
106+
$gte: '{current_quarter_start}',
107+
$lte: '{current_quarter_end}',
108+
},
109+
},
110+
compareTo: 'previousPeriod',
104111
layout: { x: 8, y: 2, w: 4, h: 4 },
105112
},
106113

0 commit comments

Comments
 (0)