@almadar/std 13.3.0 → 13.5.0

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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "std-stats",
3
- "version": "1.0.0",
4
- "description": "std-stats — embeddable analytics-card atom. Drop into a dashboard\nmolecule alongside std-browse / std-search / std-filter; wire its\nITEMS_LOADED listener to the upstream collection's success emit, then\nconfigure `metrics` per call-site to declare WHICH aggregations to\nshow.\n\nAggregation runs in the lolo state machine (no custom React component\nbeyond stat-display): the ITEMS_LOADED transition uses array/map over\n@config.metrics with a chained `if` to dispatch each metric to the\nright reducer (array/len | array/sum | array/avg | array/min |\narray/max), and the resulting cards array drops into a data-list\nwhose renderItem maps each card to a stat-display pattern. The atom\nowns its own auxiliary entity (StatsItem) for UI state — explicit-\nbinding rule applies: every @entity.X is set explicitly via\n(set @entity.X ...) on each transition.\n\nEach entry in `metrics` is `{ aggregation, field, label, icon,\nformat, variant, max }` where:\n- aggregation count|sum|avg|min|max (default count)\n- field is the numeric entity field for sum/avg/min/max\n- label is the card title (required)\n- icon, format (number|currency|percent), variant\n (default|primary|success|warning|error|info), max are pass-through\n to the stat-display render.",
3
+ "version": "2.0.0",
4
+ "description": "std-stats — embeddable analytics-card atom. Drop into a dashboard\nmolecule alongside std-browse / std-search / std-filter; wire its\nITEMS_LOADED listener to the upstream collection's success emit, then\nconfigure `metrics` per call-site to declare WHICH aggregations to\nshow.\n\nAggregation runs in the lolo state machine (no custom React component\nbeyond stat-display): the ITEMS_LOADED transition uses array/map over\n@config.metrics, applies the per-metric `filter` predicate to\n@payload.data, then dispatches the chosen aggregation kind. Cards\ndrop into a data-list whose renderItem maps each card to a\nstat-display pattern. The atom owns an auxiliary entity (StatsItem)\nfor UI state — explicit-binding rule applies: every @entity.X is set\nexplicitly via (set @entity.X ...) on each transition.\n\nEach entry in `metrics` (all but `label` optional):\n- label string! card title\n- aggregation count|sum|avg|min|max default count what to compute\n- field string numeric entity field for sum/avg/min/max\n- filter SExpression row predicate (e.g. fn-form testing @row.status). Drops non-matching\n rows BEFORE aggregation. Omitted = all rows. Compiler statically\n unrolls array/map over @config.metrics so the fn-form is fully\n specialized into pure TS at codegen time.\n- format number|currency|percent default number value formatting\n- variant default|primary|success|warning|error|info color\n- icon string lucide icon name\n- prefix string prepended to displayed value (e.g. \"≈ \")\n- suffix string appended (e.g. \" /mo\", \" ms\")\n- max number optional denominator. >0 renders \"value / max\".\n- target number optional progress target. >0 renders a progress bar.\n- trend number signed delta vs previous period. >0 ↑ green, <0 ↓ red.\n\nFor dynamic max/target/trend (computed against @payload.data),\nschema authors today must precompute and pass literal numbers; an\nSExpression-evaluating slot is a future extension.",
5
5
  "orbitals": [
6
6
  {
7
7
  "name": "StatsItemOrbital",
@@ -21,16 +21,29 @@
21
21
  "items": {
22
22
  "type": "object",
23
23
  "properties": {
24
+ "value": {
25
+ "name": "value",
26
+ "type": "number"
27
+ },
24
28
  "max": {
25
29
  "name": "max",
26
30
  "type": "number"
27
31
  },
28
- "label": {
29
- "name": "label",
30
- "type": "string"
32
+ "format": {
33
+ "name": "format",
34
+ "type": "string",
35
+ "values": [
36
+ "number",
37
+ "currency",
38
+ "percent"
39
+ ]
31
40
  },
32
- "value": {
33
- "name": "value",
41
+ "target": {
42
+ "name": "target",
43
+ "type": "number"
44
+ },
45
+ "trend": {
46
+ "name": "trend",
34
47
  "type": "number"
35
48
  },
36
49
  "variant": {
@@ -45,18 +58,21 @@
45
58
  "info"
46
59
  ]
47
60
  },
61
+ "prefix": {
62
+ "name": "prefix",
63
+ "type": "string"
64
+ },
48
65
  "icon": {
49
66
  "name": "icon",
50
67
  "type": "string"
51
68
  },
52
- "format": {
53
- "name": "format",
54
- "type": "string",
55
- "values": [
56
- "number",
57
- "currency",
58
- "percent"
59
- ]
69
+ "label": {
70
+ "name": "label",
71
+ "type": "string"
72
+ },
73
+ "suffix": {
74
+ "name": "suffix",
75
+ "type": "string"
60
76
  }
61
77
  }
62
78
  }
@@ -111,21 +127,21 @@
111
127
  "main",
112
128
  {
113
129
  "type": "data-list",
114
- "fields": [],
115
130
  "entity": "@entity.cards",
116
131
  "renderItem": [
117
132
  "fn",
118
133
  "card",
119
134
  {
120
- "label": "@card.label",
121
- "format": "@card.format",
122
- "type": "stat-display",
123
135
  "variant": "@card.variant",
124
- "value": "@card.value",
136
+ "icon": "@card.icon",
137
+ "format": "@card.format",
125
138
  "max": "@card.max",
126
- "icon": "@card.icon"
139
+ "type": "stat-display",
140
+ "label": "@card.label",
141
+ "value": "@card.value"
127
142
  }
128
- ]
143
+ ],
144
+ "fields": []
129
145
  }
130
146
  ]
131
147
  ]
@@ -145,17 +161,11 @@
145
161
  "fn",
146
162
  "metric",
147
163
  {
148
- "icon": [
164
+ "trend": [
149
165
  "object/get",
150
166
  "@metric",
151
- "icon",
152
- ""
153
- ],
154
- "variant": [
155
- "object/get",
156
- "@metric",
157
- "variant",
158
- "default"
167
+ "trend",
168
+ 0.0
159
169
  ],
160
170
  "value": [
161
171
  "if",
@@ -171,7 +181,16 @@
171
181
  ],
172
182
  [
173
183
  "array/sum",
174
- "@payload.data",
184
+ [
185
+ "array/filter",
186
+ "@payload.data",
187
+ [
188
+ "object/get",
189
+ "@metric",
190
+ "filter",
191
+ true
192
+ ]
193
+ ],
175
194
  [
176
195
  "object/get",
177
196
  "@metric",
@@ -193,7 +212,16 @@
193
212
  ],
194
213
  [
195
214
  "array/avg",
196
- "@payload.data",
215
+ [
216
+ "array/filter",
217
+ "@payload.data",
218
+ [
219
+ "object/get",
220
+ "@metric",
221
+ "filter",
222
+ true
223
+ ]
224
+ ],
197
225
  [
198
226
  "object/get",
199
227
  "@metric",
@@ -215,7 +243,16 @@
215
243
  ],
216
244
  [
217
245
  "array/min",
218
- "@payload.data",
246
+ [
247
+ "array/filter",
248
+ "@payload.data",
249
+ [
250
+ "object/get",
251
+ "@metric",
252
+ "filter",
253
+ true
254
+ ]
255
+ ],
219
256
  [
220
257
  "object/get",
221
258
  "@metric",
@@ -237,7 +274,16 @@
237
274
  ],
238
275
  [
239
276
  "array/max",
240
- "@payload.data",
277
+ [
278
+ "array/filter",
279
+ "@payload.data",
280
+ [
281
+ "object/get",
282
+ "@metric",
283
+ "filter",
284
+ true
285
+ ]
286
+ ],
241
287
  [
242
288
  "object/get",
243
289
  "@metric",
@@ -247,28 +293,67 @@
247
293
  ],
248
294
  [
249
295
  "array/len",
250
- "@payload.data"
296
+ [
297
+ "array/filter",
298
+ "@payload.data",
299
+ [
300
+ "object/get",
301
+ "@metric",
302
+ "filter",
303
+ true
304
+ ]
305
+ ]
251
306
  ]
252
307
  ]
253
308
  ]
254
309
  ]
255
310
  ],
256
- "format": [
311
+ "max": [
257
312
  "object/get",
258
313
  "@metric",
259
- "format",
260
- "number"
314
+ "max",
315
+ 0.0
316
+ ],
317
+ "target": [
318
+ "object/get",
319
+ "@metric",
320
+ "target",
321
+ 0.0
322
+ ],
323
+ "suffix": [
324
+ "object/get",
325
+ "@metric",
326
+ "suffix",
327
+ ""
328
+ ],
329
+ "prefix": [
330
+ "object/get",
331
+ "@metric",
332
+ "prefix",
333
+ ""
261
334
  ],
262
335
  "label": [
263
336
  "object/get",
264
337
  "@metric",
265
338
  "label"
266
339
  ],
267
- "max": [
340
+ "icon": [
268
341
  "object/get",
269
342
  "@metric",
270
- "max",
271
- 0.0
343
+ "icon",
344
+ ""
345
+ ],
346
+ "variant": [
347
+ "object/get",
348
+ "@metric",
349
+ "variant",
350
+ "default"
351
+ ],
352
+ "format": [
353
+ "object/get",
354
+ "@metric",
355
+ "format",
356
+ "number"
272
357
  ]
273
358
  }
274
359
  ]
@@ -279,21 +364,25 @@
279
364
  "main",
280
365
  {
281
366
  "type": "data-list",
282
- "entity": "@entity.cards",
283
- "fields": [],
284
367
  "renderItem": [
285
368
  "fn",
286
369
  "card",
287
370
  {
288
- "icon": "@card.icon",
289
- "label": "@card.label",
290
371
  "variant": "@card.variant",
372
+ "type": "stat-display",
291
373
  "format": "@card.format",
374
+ "prefix": "@card.prefix",
375
+ "trend": "@card.trend",
376
+ "value": "@card.value",
377
+ "suffix": "@card.suffix",
292
378
  "max": "@card.max",
293
- "type": "stat-display",
294
- "value": "@card.value"
379
+ "icon": "@card.icon",
380
+ "label": "@card.label",
381
+ "target": "@card.target"
295
382
  }
296
- ]
383
+ ],
384
+ "fields": [],
385
+ "entity": "@entity.cards"
297
386
  }
298
387
  ]
299
388
  ]
@@ -64,39 +64,50 @@
64
64
  "ref": "Stats.traits.StatsItemStats",
65
65
  "name": "DashboardSummary",
66
66
  "config": {
67
- "title": "Summary",
68
67
  "metrics": [
69
68
  {
70
- "variant": "primary",
71
- "aggregation": "count",
69
+ "label": "Total Items",
72
70
  "icon": "list",
73
- "format": "number",
74
- "label": "Total Items"
71
+ "aggregation": "count",
72
+ "variant": "primary",
73
+ "format": "number"
75
74
  },
76
75
  {
77
- "variant": "success",
76
+ "aggregation": "count",
77
+ "label": "Active",
78
78
  "icon": "check-circle",
79
+ "variant": "success",
79
80
  "format": "number",
80
- "aggregation": "count",
81
- "label": "Active"
81
+ "filter": [
82
+ "fn",
83
+ "row",
84
+ [
85
+ "=",
86
+ "@row.status",
87
+ "active"
88
+ ]
89
+ ]
82
90
  },
83
91
  {
84
- "format": "currency",
85
92
  "variant": "info",
86
- "aggregation": "sum",
87
93
  "field": "amount",
94
+ "target": 10000.0,
95
+ "aggregation": "sum",
88
96
  "icon": "dollar-sign",
89
- "label": "Total Revenue"
97
+ "label": "Total Revenue",
98
+ "format": "currency"
90
99
  },
91
100
  {
92
- "variant": "default",
93
- "icon": "trending-up",
94
101
  "label": "Avg Units",
95
102
  "field": "units",
96
- "format": "number",
97
- "aggregation": "avg"
103
+ "aggregation": "avg",
104
+ "variant": "default",
105
+ "suffix": " units",
106
+ "icon": "trending-up",
107
+ "format": "number"
98
108
  }
99
- ]
109
+ ],
110
+ "title": "Summary"
100
111
  },
101
112
  "listens": [
102
113
  {
@@ -113,13 +124,13 @@
113
124
  "ref": "Graphs.traits.GraphItemGraph",
114
125
  "name": "DashboardCategoryChart",
115
126
  "config": {
127
+ "showLegend": false,
128
+ "title": "Items by Category",
116
129
  "subtitle": "Count across categories",
117
130
  "chartType": "bar",
118
- "height": 280.0,
119
- "title": "Items by Category",
120
- "categoryField": "category",
121
131
  "aggregation": "count",
122
- "showLegend": false
132
+ "height": 280.0,
133
+ "categoryField": "category"
123
134
  },
124
135
  "listens": [
125
136
  {
@@ -136,12 +147,12 @@
136
147
  "ref": "Graphs.traits.GraphItemGraph",
137
148
  "name": "DashboardStatusChart",
138
149
  "config": {
150
+ "title": "Status Mix",
151
+ "chartType": "donut",
152
+ "aggregation": "count",
139
153
  "showLegend": true,
140
154
  "categoryField": "status",
141
- "aggregation": "count",
142
- "height": 280.0,
143
- "title": "Status Mix",
144
- "chartType": "donut"
155
+ "height": 280.0
145
156
  },
146
157
  "listens": [
147
158
  {
@@ -159,6 +170,7 @@
159
170
  "name": "DashboardItemBrowse",
160
171
  "linkedEntity": "DashboardItem",
161
172
  "config": {
173
+ "displayPageSize": 5.0,
162
174
  "fields": [
163
175
  {
164
176
  "name": "name",
@@ -166,23 +178,22 @@
166
178
  "variant": "h4"
167
179
  },
168
180
  {
169
- "label": "Category",
170
181
  "name": "category",
182
+ "label": "Category",
171
183
  "variant": "caption"
172
184
  },
173
185
  {
174
186
  "name": "status",
175
- "label": "Status",
176
- "variant": "badge"
187
+ "variant": "badge",
188
+ "label": "Status"
177
189
  },
178
190
  {
191
+ "label": "Amount",
179
192
  "name": "amount",
180
- "variant": "caption",
181
- "label": "Amount"
193
+ "variant": "caption"
182
194
  }
183
195
  ],
184
- "pageSize": 100.0,
185
- "displayPageSize": 5.0
196
+ "pageSize": 100.0
186
197
  }
187
198
  },
188
199
  {
@@ -272,50 +283,50 @@
272
283
  "render-ui",
273
284
  "main",
274
285
  {
275
- "type": "stack",
276
- "gap": "lg",
277
286
  "children": [
278
287
  {
288
+ "align": "center",
279
289
  "type": "stack",
290
+ "direction": "horizontal",
291
+ "gap": "sm",
280
292
  "children": [
281
293
  {
282
- "type": "icon",
283
- "name": "bar-chart-2"
294
+ "name": "bar-chart-2",
295
+ "type": "icon"
284
296
  },
285
297
  {
286
- "type": "typography",
287
298
  "variant": "h2",
299
+ "type": "typography",
288
300
  "content": "Dashboard"
289
301
  }
290
- ],
291
- "align": "center",
292
- "gap": "sm",
293
- "direction": "horizontal"
302
+ ]
294
303
  },
295
304
  {
296
305
  "type": "divider"
297
306
  },
298
307
  "@trait.DashboardSummary",
299
308
  {
309
+ "cols": 2.0,
310
+ "gap": "md",
300
311
  "children": [
301
312
  "@trait.DashboardCategoryChart",
302
313
  "@trait.DashboardStatusChart"
303
314
  ],
304
- "gap": "md",
305
- "cols": 2.0,
306
315
  "type": "simple-grid"
307
316
  },
308
317
  {
309
318
  "type": "divider"
310
319
  },
311
320
  {
312
- "content": "Recent Items",
313
321
  "type": "typography",
314
- "variant": "h3"
322
+ "variant": "h3",
323
+ "content": "Recent Items"
315
324
  },
316
325
  "@trait.DashboardItemBrowse"
317
326
  ],
327
+ "gap": "lg",
318
328
  "className": "max-w-6xl mx-auto w-full p-4",
329
+ "type": "stack",
319
330
  "direction": "vertical"
320
331
  }
321
332
  ]
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "std-stats",
3
- "version": "1.0.0",
4
- "description": "std-stats — embeddable analytics-card atom. Drop into a dashboard\nmolecule alongside std-browse / std-search / std-filter; wire its\nITEMS_LOADED listener to the upstream collection's success emit, then\nconfigure `metrics` per call-site to declare WHICH aggregations to\nshow.\n\nAggregation runs in the lolo state machine (no custom React component\nbeyond stat-display): the ITEMS_LOADED transition uses array/map over\n@config.metrics with a chained `if` to dispatch each metric to the\nright reducer (array/len | array/sum | array/avg | array/min |\narray/max), and the resulting cards array drops into a data-list\nwhose renderItem maps each card to a stat-display pattern. The atom\nowns its own auxiliary entity (StatsItem) for UI state — explicit-\nbinding rule applies: every @entity.X is set explicitly via\n(set @entity.X ...) on each transition.\n\nEach entry in `metrics` is `{ aggregation, field, label, icon,\nformat, variant, max }` where:\n- aggregation count|sum|avg|min|max (default count)\n- field is the numeric entity field for sum/avg/min/max\n- label is the card title (required)\n- icon, format (number|currency|percent), variant\n (default|primary|success|warning|error|info), max are pass-through\n to the stat-display render.",
3
+ "version": "2.0.0",
4
+ "description": "std-stats — embeddable analytics-card atom. Drop into a dashboard\nmolecule alongside std-browse / std-search / std-filter; wire its\nITEMS_LOADED listener to the upstream collection's success emit, then\nconfigure `metrics` per call-site to declare WHICH aggregations to\nshow.\n\nAggregation runs in the lolo state machine (no custom React component\nbeyond stat-display): the ITEMS_LOADED transition uses array/map over\n@config.metrics, applies the per-metric `filter` predicate to\n@payload.data, then dispatches the chosen aggregation kind. Cards\ndrop into a data-list whose renderItem maps each card to a\nstat-display pattern. The atom owns an auxiliary entity (StatsItem)\nfor UI state — explicit-binding rule applies: every @entity.X is set\nexplicitly via (set @entity.X ...) on each transition.\n\nEach entry in `metrics` (all but `label` optional):\n- label string! card title\n- aggregation count|sum|avg|min|max default count what to compute\n- field string numeric entity field for sum/avg/min/max\n- filter SExpression row predicate (e.g. fn-form testing @row.status). Drops non-matching\n rows BEFORE aggregation. Omitted = all rows. Compiler statically\n unrolls array/map over @config.metrics so the fn-form is fully\n specialized into pure TS at codegen time.\n- format number|currency|percent default number value formatting\n- variant default|primary|success|warning|error|info color\n- icon string lucide icon name\n- prefix string prepended to displayed value (e.g. \"≈ \")\n- suffix string appended (e.g. \" /mo\", \" ms\")\n- max number optional denominator. >0 renders \"value / max\".\n- target number optional progress target. >0 renders a progress bar.\n- trend number signed delta vs previous period. >0 ↑ green, <0 ↓ red.\n\nFor dynamic max/target/trend (computed against @payload.data),\nschema authors today must precompute and pass literal numbers; an\nSExpression-evaluating slot is a future extension.",
5
5
  "orbitals": [
6
6
  {
7
7
  "name": "StatsItemOrbital",
@@ -21,16 +21,29 @@
21
21
  "items": {
22
22
  "type": "object",
23
23
  "properties": {
24
+ "value": {
25
+ "name": "value",
26
+ "type": "number"
27
+ },
24
28
  "max": {
25
29
  "name": "max",
26
30
  "type": "number"
27
31
  },
28
- "label": {
29
- "name": "label",
30
- "type": "string"
32
+ "format": {
33
+ "name": "format",
34
+ "type": "string",
35
+ "values": [
36
+ "number",
37
+ "currency",
38
+ "percent"
39
+ ]
31
40
  },
32
- "value": {
33
- "name": "value",
41
+ "target": {
42
+ "name": "target",
43
+ "type": "number"
44
+ },
45
+ "trend": {
46
+ "name": "trend",
34
47
  "type": "number"
35
48
  },
36
49
  "variant": {
@@ -45,18 +58,21 @@
45
58
  "info"
46
59
  ]
47
60
  },
61
+ "prefix": {
62
+ "name": "prefix",
63
+ "type": "string"
64
+ },
48
65
  "icon": {
49
66
  "name": "icon",
50
67
  "type": "string"
51
68
  },
52
- "format": {
53
- "name": "format",
54
- "type": "string",
55
- "values": [
56
- "number",
57
- "currency",
58
- "percent"
59
- ]
69
+ "label": {
70
+ "name": "label",
71
+ "type": "string"
72
+ },
73
+ "suffix": {
74
+ "name": "suffix",
75
+ "type": "string"
60
76
  }
61
77
  }
62
78
  }
@@ -111,21 +127,21 @@
111
127
  "main",
112
128
  {
113
129
  "type": "data-list",
114
- "fields": [],
115
130
  "entity": "@entity.cards",
116
131
  "renderItem": [
117
132
  "fn",
118
133
  "card",
119
134
  {
120
- "label": "@card.label",
121
- "format": "@card.format",
122
- "type": "stat-display",
123
135
  "variant": "@card.variant",
124
- "value": "@card.value",
136
+ "icon": "@card.icon",
137
+ "format": "@card.format",
125
138
  "max": "@card.max",
126
- "icon": "@card.icon"
139
+ "type": "stat-display",
140
+ "label": "@card.label",
141
+ "value": "@card.value"
127
142
  }
128
- ]
143
+ ],
144
+ "fields": []
129
145
  }
130
146
  ]
131
147
  ]
@@ -145,17 +161,11 @@
145
161
  "fn",
146
162
  "metric",
147
163
  {
148
- "icon": [
164
+ "trend": [
149
165
  "object/get",
150
166
  "@metric",
151
- "icon",
152
- ""
153
- ],
154
- "variant": [
155
- "object/get",
156
- "@metric",
157
- "variant",
158
- "default"
167
+ "trend",
168
+ 0.0
159
169
  ],
160
170
  "value": [
161
171
  "if",
@@ -171,7 +181,16 @@
171
181
  ],
172
182
  [
173
183
  "array/sum",
174
- "@payload.data",
184
+ [
185
+ "array/filter",
186
+ "@payload.data",
187
+ [
188
+ "object/get",
189
+ "@metric",
190
+ "filter",
191
+ true
192
+ ]
193
+ ],
175
194
  [
176
195
  "object/get",
177
196
  "@metric",
@@ -193,7 +212,16 @@
193
212
  ],
194
213
  [
195
214
  "array/avg",
196
- "@payload.data",
215
+ [
216
+ "array/filter",
217
+ "@payload.data",
218
+ [
219
+ "object/get",
220
+ "@metric",
221
+ "filter",
222
+ true
223
+ ]
224
+ ],
197
225
  [
198
226
  "object/get",
199
227
  "@metric",
@@ -215,7 +243,16 @@
215
243
  ],
216
244
  [
217
245
  "array/min",
218
- "@payload.data",
246
+ [
247
+ "array/filter",
248
+ "@payload.data",
249
+ [
250
+ "object/get",
251
+ "@metric",
252
+ "filter",
253
+ true
254
+ ]
255
+ ],
219
256
  [
220
257
  "object/get",
221
258
  "@metric",
@@ -237,7 +274,16 @@
237
274
  ],
238
275
  [
239
276
  "array/max",
240
- "@payload.data",
277
+ [
278
+ "array/filter",
279
+ "@payload.data",
280
+ [
281
+ "object/get",
282
+ "@metric",
283
+ "filter",
284
+ true
285
+ ]
286
+ ],
241
287
  [
242
288
  "object/get",
243
289
  "@metric",
@@ -247,28 +293,67 @@
247
293
  ],
248
294
  [
249
295
  "array/len",
250
- "@payload.data"
296
+ [
297
+ "array/filter",
298
+ "@payload.data",
299
+ [
300
+ "object/get",
301
+ "@metric",
302
+ "filter",
303
+ true
304
+ ]
305
+ ]
251
306
  ]
252
307
  ]
253
308
  ]
254
309
  ]
255
310
  ],
256
- "format": [
311
+ "max": [
257
312
  "object/get",
258
313
  "@metric",
259
- "format",
260
- "number"
314
+ "max",
315
+ 0.0
316
+ ],
317
+ "target": [
318
+ "object/get",
319
+ "@metric",
320
+ "target",
321
+ 0.0
322
+ ],
323
+ "suffix": [
324
+ "object/get",
325
+ "@metric",
326
+ "suffix",
327
+ ""
328
+ ],
329
+ "prefix": [
330
+ "object/get",
331
+ "@metric",
332
+ "prefix",
333
+ ""
261
334
  ],
262
335
  "label": [
263
336
  "object/get",
264
337
  "@metric",
265
338
  "label"
266
339
  ],
267
- "max": [
340
+ "icon": [
268
341
  "object/get",
269
342
  "@metric",
270
- "max",
271
- 0.0
343
+ "icon",
344
+ ""
345
+ ],
346
+ "variant": [
347
+ "object/get",
348
+ "@metric",
349
+ "variant",
350
+ "default"
351
+ ],
352
+ "format": [
353
+ "object/get",
354
+ "@metric",
355
+ "format",
356
+ "number"
272
357
  ]
273
358
  }
274
359
  ]
@@ -279,21 +364,25 @@
279
364
  "main",
280
365
  {
281
366
  "type": "data-list",
282
- "entity": "@entity.cards",
283
- "fields": [],
284
367
  "renderItem": [
285
368
  "fn",
286
369
  "card",
287
370
  {
288
- "icon": "@card.icon",
289
- "label": "@card.label",
290
371
  "variant": "@card.variant",
372
+ "type": "stat-display",
291
373
  "format": "@card.format",
374
+ "prefix": "@card.prefix",
375
+ "trend": "@card.trend",
376
+ "value": "@card.value",
377
+ "suffix": "@card.suffix",
292
378
  "max": "@card.max",
293
- "type": "stat-display",
294
- "value": "@card.value"
379
+ "icon": "@card.icon",
380
+ "label": "@card.label",
381
+ "target": "@card.target"
295
382
  }
296
- ]
383
+ ],
384
+ "fields": [],
385
+ "entity": "@entity.cards"
297
386
  }
298
387
  ]
299
388
  ]
@@ -64,39 +64,50 @@
64
64
  "ref": "Stats.traits.StatsItemStats",
65
65
  "name": "DashboardSummary",
66
66
  "config": {
67
- "title": "Summary",
68
67
  "metrics": [
69
68
  {
70
- "variant": "primary",
71
- "aggregation": "count",
69
+ "label": "Total Items",
72
70
  "icon": "list",
73
- "format": "number",
74
- "label": "Total Items"
71
+ "aggregation": "count",
72
+ "variant": "primary",
73
+ "format": "number"
75
74
  },
76
75
  {
77
- "variant": "success",
76
+ "aggregation": "count",
77
+ "label": "Active",
78
78
  "icon": "check-circle",
79
+ "variant": "success",
79
80
  "format": "number",
80
- "aggregation": "count",
81
- "label": "Active"
81
+ "filter": [
82
+ "fn",
83
+ "row",
84
+ [
85
+ "=",
86
+ "@row.status",
87
+ "active"
88
+ ]
89
+ ]
82
90
  },
83
91
  {
84
- "format": "currency",
85
92
  "variant": "info",
86
- "aggregation": "sum",
87
93
  "field": "amount",
94
+ "target": 10000.0,
95
+ "aggregation": "sum",
88
96
  "icon": "dollar-sign",
89
- "label": "Total Revenue"
97
+ "label": "Total Revenue",
98
+ "format": "currency"
90
99
  },
91
100
  {
92
- "variant": "default",
93
- "icon": "trending-up",
94
101
  "label": "Avg Units",
95
102
  "field": "units",
96
- "format": "number",
97
- "aggregation": "avg"
103
+ "aggregation": "avg",
104
+ "variant": "default",
105
+ "suffix": " units",
106
+ "icon": "trending-up",
107
+ "format": "number"
98
108
  }
99
- ]
109
+ ],
110
+ "title": "Summary"
100
111
  },
101
112
  "listens": [
102
113
  {
@@ -113,13 +124,13 @@
113
124
  "ref": "Graphs.traits.GraphItemGraph",
114
125
  "name": "DashboardCategoryChart",
115
126
  "config": {
127
+ "showLegend": false,
128
+ "title": "Items by Category",
116
129
  "subtitle": "Count across categories",
117
130
  "chartType": "bar",
118
- "height": 280.0,
119
- "title": "Items by Category",
120
- "categoryField": "category",
121
131
  "aggregation": "count",
122
- "showLegend": false
132
+ "height": 280.0,
133
+ "categoryField": "category"
123
134
  },
124
135
  "listens": [
125
136
  {
@@ -136,12 +147,12 @@
136
147
  "ref": "Graphs.traits.GraphItemGraph",
137
148
  "name": "DashboardStatusChart",
138
149
  "config": {
150
+ "title": "Status Mix",
151
+ "chartType": "donut",
152
+ "aggregation": "count",
139
153
  "showLegend": true,
140
154
  "categoryField": "status",
141
- "aggregation": "count",
142
- "height": 280.0,
143
- "title": "Status Mix",
144
- "chartType": "donut"
155
+ "height": 280.0
145
156
  },
146
157
  "listens": [
147
158
  {
@@ -159,6 +170,7 @@
159
170
  "name": "DashboardItemBrowse",
160
171
  "linkedEntity": "DashboardItem",
161
172
  "config": {
173
+ "displayPageSize": 5.0,
162
174
  "fields": [
163
175
  {
164
176
  "name": "name",
@@ -166,23 +178,22 @@
166
178
  "variant": "h4"
167
179
  },
168
180
  {
169
- "label": "Category",
170
181
  "name": "category",
182
+ "label": "Category",
171
183
  "variant": "caption"
172
184
  },
173
185
  {
174
186
  "name": "status",
175
- "label": "Status",
176
- "variant": "badge"
187
+ "variant": "badge",
188
+ "label": "Status"
177
189
  },
178
190
  {
191
+ "label": "Amount",
179
192
  "name": "amount",
180
- "variant": "caption",
181
- "label": "Amount"
193
+ "variant": "caption"
182
194
  }
183
195
  ],
184
- "pageSize": 100.0,
185
- "displayPageSize": 5.0
196
+ "pageSize": 100.0
186
197
  }
187
198
  },
188
199
  {
@@ -272,50 +283,50 @@
272
283
  "render-ui",
273
284
  "main",
274
285
  {
275
- "type": "stack",
276
- "gap": "lg",
277
286
  "children": [
278
287
  {
288
+ "align": "center",
279
289
  "type": "stack",
290
+ "direction": "horizontal",
291
+ "gap": "sm",
280
292
  "children": [
281
293
  {
282
- "type": "icon",
283
- "name": "bar-chart-2"
294
+ "name": "bar-chart-2",
295
+ "type": "icon"
284
296
  },
285
297
  {
286
- "type": "typography",
287
298
  "variant": "h2",
299
+ "type": "typography",
288
300
  "content": "Dashboard"
289
301
  }
290
- ],
291
- "align": "center",
292
- "gap": "sm",
293
- "direction": "horizontal"
302
+ ]
294
303
  },
295
304
  {
296
305
  "type": "divider"
297
306
  },
298
307
  "@trait.DashboardSummary",
299
308
  {
309
+ "cols": 2.0,
310
+ "gap": "md",
300
311
  "children": [
301
312
  "@trait.DashboardCategoryChart",
302
313
  "@trait.DashboardStatusChart"
303
314
  ],
304
- "gap": "md",
305
- "cols": 2.0,
306
315
  "type": "simple-grid"
307
316
  },
308
317
  {
309
318
  "type": "divider"
310
319
  },
311
320
  {
312
- "content": "Recent Items",
313
321
  "type": "typography",
314
- "variant": "h3"
322
+ "variant": "h3",
323
+ "content": "Recent Items"
315
324
  },
316
325
  "@trait.DashboardItemBrowse"
317
326
  ],
327
+ "gap": "lg",
318
328
  "className": "max-w-6xl mx-auto w-full p-4",
329
+ "type": "stack",
319
330
  "direction": "vertical"
320
331
  }
321
332
  ]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@almadar/std",
3
- "version": "13.3.0",
3
+ "version": "13.5.0",
4
4
  "description": "Standard library operators for Almadar (math, string, array, etc.)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",