blixify-ui-web-mcp 0.1.60 → 0.1.61

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -89,6 +89,46 @@ Radar chart comparing multiple attributes across query groups:
89
89
  }
90
90
  ```
91
91
 
92
+ Grouped by any column, top 5 with the rest as "Others", highest first:
93
+
94
+ ```jsx
95
+ {
96
+ gridSize: 2,
97
+ type: "table",
98
+ title: "Leads by Agent",
99
+ spaceId: "leads",
100
+ query: [],
101
+ queryBaseType: "count",
102
+ groupBy: "agent",
103
+ sortBy: "value",
104
+ sortDirection: "desc",
105
+ topN: 5,
106
+ }
107
+ ```
108
+
109
+ Revenue per month as a running total, split by status:
110
+
111
+ ```jsx
112
+ {
113
+ gridSize: 2,
114
+ type: "bar",
115
+ title: "Revenue per Month",
116
+ spaceId: "orders",
117
+ query: [],
118
+ queryBaseType: "sum",
119
+ queryAttributeId: ["amount"],
120
+ queryBaseDateId: "paidAt",
121
+ queryDateInterval: "month",
122
+ cumulative: true,
123
+ segmentBy: "status",
124
+ }
125
+ ```
126
+
127
+ A chart that can't load or draw shows an error card in its place — a plain
128
+ message, Retry, and the technical cause under Details — and the other charts
129
+ keep drawing. Pass `structure` so a sum or average of a text column is caught
130
+ before any request is sent.
131
+
92
132
  Custom layout via renderSettings:
93
133
 
94
134
  ```jsx
@@ -114,6 +154,9 @@ Custom layout via renderSettings:
114
154
  | ---------------- | ------------------------------------------ | ------- | -------------------------------------------------------------------------------------------------------------------------------------- |
115
155
  | `gridSize` | `2 \| 3` | — | Override the grid column layout. Default is a responsive `1 → 2 → 4` column grid. `2` forces 2 cols, `3` forces 3 cols. |
116
156
  | `renderSettings` | `(charts: ReactElement, data: any) => any` | — | Custom render function. Receives the rendered charts element and the raw analytics data object. Use to wrap charts in a custom layout. |
157
+ | `structure` | `DataStructure[]` | — | The datasheet's columns. Groups read by their labels, and a chart measuring a column that is not a number shows why before any request. |
158
+ | `personOptions` | `Option[]` | — | Names for the user ids a `person` column groups by. |
159
+ | `onDrillDown` | `(drillDown: ChartDrillDown) => void` | — | Called when a bar, slice or table row is clicked, with its label and the query that finds its records. |
117
160
 
118
161
  ##### Charts
119
162
 
@@ -139,6 +182,13 @@ Custom layout via renderSettings:
139
182
  | `colors` | `string[]` | Custom color array for chart segments/bars/lines |
140
183
  | `orientation` | `"col" \| "row"` | Bar chart orientation. Defaults to `"row"`. |
141
184
  | `stackedVertical` | `boolean` | Enables stacked bars on bar charts |
185
+ | `groupBy` | `string` | Column of any type to group by in one request. A `reference` or `person` column reads by name. |
186
+ | `queryDateInterval`| `"day" \| "week" \| "month"` | With `queryBaseDateId`, buckets records by day, week or month. Defaults to the last 30 days, 12 weeks or 12 months. |
187
+ | `segmentBy` | `string` | Second column split into stacked series (bar, line, table), at most 10 values plus "Others". |
188
+ | `sortBy` | `"value" \| "label"` | Sort the groups. `sortDirection` is `"asc"` or `"desc"` (default). |
189
+ | `topN` | `number` | Keep the first N groups; the rest are added up as "Others" unless `showOthers` is `false` (averages never get "Others"). |
190
+ | `showPercent` | `boolean` | Show each group as a percentage of the total (count and sum, unsplit charts). |
191
+ | `cumulative` | `boolean` | Running total over the date buckets. |
142
192
 
143
193
  ##### WorkspaceDevSettings
144
194
 
@@ -513,14 +513,24 @@ const CHART_SCHEMA: DataStructure[] = [
513
513
  listSelection: ["web", "store", "phone"],
514
514
  listSelectionLabel: ["Web", "Store", "Phone"],
515
515
  },
516
+ { id: "agent", name: "Agent", type: "person" },
516
517
  { id: "amount", name: "Amount", type: "number" },
517
518
  { id: "items", name: "Items", type: "number" },
518
519
  { id: "createdAt", name: "Created At", type: "date" },
519
520
  ];
520
521
 
522
+ const CHART_MEMBERS = [
523
+ { key: "u1", label: "Aisha" },
524
+ { key: "u2", label: "Ben" },
525
+ { key: "u3", label: "Chong" },
526
+ { key: "u4", label: "Devi" },
527
+ { key: "u5", label: "Eli" },
528
+ ];
529
+
521
530
  const renderChartRecords = () => {
522
531
  const statuses = ["pending", "paid", "shipped", "cancelled"];
523
532
  const channels = ["web", "store", "phone"];
533
+ const agents = ["u1", "u2", "u3", "u1", "u4", "u1", "u2", "u5"];
524
534
  return Array.from({ length: 40 }, (_, index) => ({
525
535
  _id: `o${index + 1}`,
526
536
  orderNo: `ORD-${1000 + index}`,
@@ -528,7 +538,16 @@ const renderChartRecords = () => {
528
538
  channel: channels[(index * 5) % channels.length],
529
539
  amount: 20 + ((index * 37) % 180),
530
540
  items: 1 + ((index * 3) % 6),
531
- createdAt: new Date(Date.now() - (index % 7) * 24 * 60 * 60 * 1000),
541
+ agent: index % 9 === 0 ? undefined : agents[index % agents.length],
542
+ // INFO: half in the last week for the daily line, the rest over months
543
+ createdAt: new Date(
544
+ Date.now() -
545
+ (index % 2 === 0 ? index % 7 : (index * 11) % 300) *
546
+ 24 *
547
+ 60 *
548
+ 60 *
549
+ 1000,
550
+ ),
532
551
  }));
533
552
  };
534
553
 
@@ -552,12 +571,26 @@ const handleInstallChartMock = (store: any[]) => {
552
571
  return {};
553
572
  }
554
573
  };
555
- // INFO: "=" for chart groups, "search" for the search box — enough to show
574
+ // INFO: the conditions charts and their drill-downs send — enough to show
556
575
  // the table's filters reaching the charts
557
576
  const handleMatch = (record: any, query: any[] = []) =>
558
577
  query.every((eachQuery) => {
559
- if (eachQuery.type === "=")
560
- return record[eachQuery.queryId] === eachQuery.value;
578
+ const value = record[eachQuery.queryId];
579
+ // INFO: null matches a missing value too, as Mongo's { column: null }
580
+ if (eachQuery.type === "=") return (value ?? null) === eachQuery.value;
581
+ if (eachQuery.type === "in")
582
+ return eachQuery.value.includes(value ?? null);
583
+ if (eachQuery.type === "!in")
584
+ return !eachQuery.value.includes(value ?? null);
585
+ if (eachQuery.type === "exists")
586
+ return (value !== undefined && value !== null) === eachQuery.value;
587
+ if (eachQuery.type === "><")
588
+ return (
589
+ new Date(value) >= new Date(eachQuery.value[0]) &&
590
+ new Date(value) <= new Date(eachQuery.value[1])
591
+ );
592
+ if (eachQuery.type === "<")
593
+ return new Date(value) < new Date(eachQuery.value);
561
594
  if (eachQuery.type === "search")
562
595
  return Object.values(record).some((eachValue) =>
563
596
  String(eachValue)
@@ -602,6 +635,20 @@ const handleInstallChartMock = (store: any[]) => {
602
635
  );
603
636
  })
604
637
  : matched;
638
+ if (body.aggregate.groupId) {
639
+ const groups = new Map<any, any[]>();
640
+ inRange.forEach((eachRecord) => {
641
+ const key = eachRecord[body.aggregate.groupId] ?? null;
642
+ groups.set(key, [...(groups.get(key) ?? []), eachRecord]);
643
+ });
644
+ return {
645
+ _id: eachRange,
646
+ value: Array.from(groups.entries()).map(([key, records]) => ({
647
+ _id: key,
648
+ value: handleAggregate(records, body.aggregate),
649
+ })),
650
+ };
651
+ }
605
652
  return {
606
653
  _id: eachRange,
607
654
  value: handleAggregate(inRange, body.aggregate),
@@ -705,6 +752,55 @@ const ChartViewDemo = () => {
705
752
  seriesLabels: ["Pending", "Paid", "Shipped", "Cancelled"],
706
753
  queryBaseType: "count",
707
754
  },
755
+ {
756
+ title: "Top Agents",
757
+ type: "table",
758
+ gridSize: 2,
759
+ spaceId: CHART_COLLECTION,
760
+ query: [],
761
+ queryBaseType: "count",
762
+ groupBy: "agent",
763
+ sortBy: "value",
764
+ sortDirection: "desc",
765
+ topN: 3,
766
+ },
767
+ {
768
+ title: "Revenue Per Month",
769
+ type: "bar",
770
+ orientation: "col",
771
+ gridSize: 2,
772
+ spaceId: CHART_COLLECTION,
773
+ query: [],
774
+ queryBaseType: "sum",
775
+ queryAttributeId: ["amount"],
776
+ queryBaseDateId: "createdAt",
777
+ queryDateInterval: "month",
778
+ cumulative: true,
779
+ },
780
+ {
781
+ title: "Channel By Status",
782
+ type: "bar",
783
+ orientation: "col",
784
+ gridSize: 2,
785
+ spaceId: CHART_COLLECTION,
786
+ query: ["web", "store", "phone"].map((eachValue) => ({
787
+ type: "=" as const,
788
+ queryId: "channel",
789
+ value: eachValue,
790
+ })),
791
+ seriesLabels: ["Web", "Store", "Phone"],
792
+ queryBaseType: "count",
793
+ segmentBy: "status",
794
+ },
795
+ {
796
+ title: "Sum Of Order No",
797
+ type: "card",
798
+ gridSize: 2,
799
+ spaceId: CHART_COLLECTION,
800
+ query: [],
801
+ queryBaseType: "sum",
802
+ queryAttributeId: ["orderNo"],
803
+ },
708
804
  ],
709
805
  },
710
806
  ]);
@@ -719,7 +815,7 @@ const ChartViewDemo = () => {
719
815
  collectionId={CHART_COLLECTION}
720
816
  model={CHART_SCHEMA}
721
817
  localURLEndpoint=""
722
- devSettings={demoDevSettings}
818
+ devSettings={{ ...demoDevSettings, organisationMembers: CHART_MEMBERS }}
723
819
  lib={{ axios, Menu, Transition, papaParser: Papa }}
724
820
  limit={10}
725
821
  edit={{ allEditable: true }}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blixify-ui-web-mcp",
3
- "version": "0.1.60",
3
+ "version": "0.1.61",
4
4
  "license": "MIT",
5
5
  "main": "lib/mcp/server.js",
6
6
  "bin": {