yamchart 0.8.7 → 0.9.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.
- package/dist/{advisor-54JBE2EV.js → advisor-Z7TKPPBR.js} +10 -10
- package/dist/agent-KWKPAYT2.js +8 -0
- package/dist/{chunk-NCPWAWIM.js → chunk-AMHCOB4D.js} +4 -4
- package/dist/{chunk-5N3FYFBV.js → chunk-CWAWATL4.js} +34 -7
- package/dist/chunk-CWAWATL4.js.map +1 -0
- package/dist/{chunk-C7A7TKSY.js → chunk-E2QN2M7S.js} +77 -7
- package/dist/chunk-E2QN2M7S.js.map +1 -0
- package/dist/{chunk-YMQ4PWVJ.js → chunk-FZFBBB7K.js} +2 -2
- package/dist/{chunk-GLCEDWGH.js → chunk-G57J2WQM.js} +4 -4
- package/dist/chunk-ZA6AOQVZ.js +677 -0
- package/dist/chunk-ZA6AOQVZ.js.map +1 -0
- package/dist/{connection-utils-MXEF6X7K.js → connection-utils-CTPN7PV3.js} +4 -4
- package/dist/{describe-XKLBZEWG.js → describe-4NME6RCB.js} +5 -5
- package/dist/{dev-Z2R2DBWO.js → dev-6QGAB4ZH.js} +845 -70
- package/dist/dev-6QGAB4ZH.js.map +1 -0
- package/dist/{dist-LJR7TAW4.js → dist-4GUE24QV.js} +4 -2
- package/dist/{dist-GVNWQXFR.js → dist-7CRX2GIR.js} +2 -2
- package/dist/{dist-E2PVGIPT.js → dist-VNX77VV5.js} +4 -2
- package/dist/index.js +21 -21
- package/dist/public/assets/{EventManagement-DtPDwZ-w.js → EventManagement-MMsAkJKj.js} +2 -2
- package/dist/public/assets/ExplorePage-BSkSNgLT.js +1 -0
- package/dist/public/assets/{LoginPage-DBq1qDOK.js → LoginPage-vaI1dnyL.js} +1 -1
- package/dist/public/assets/PublicViewer-B-OKj2cg.js +1 -0
- package/dist/public/assets/{SetupWizard-hgd12cdr.js → SetupWizard-DvlVX2O6.js} +1 -1
- package/dist/public/assets/{ShareManagement-D82oEJJg.js → ShareManagement-ulvPrOAQ.js} +1 -1
- package/dist/public/assets/{UserManagement-CZsxY9aP.js → UserManagement-CvmpNy3o.js} +1 -1
- package/dist/public/assets/{index-B_fusLA_.css → index-CfyF2Wf-.css} +1 -1
- package/dist/public/assets/index-DD59fsOk.js +195 -0
- package/dist/public/assets/{index.es-BmKO-vE1.js → index.es-BeTaRWIv.js} +1 -1
- package/dist/public/assets/{jspdf.es.min-DMVrmE3G.js → jspdf.es.min-9haD1GSE.js} +3 -3
- package/dist/public/index.html +2 -2
- package/dist/{query-MXMFI5TB.js → query-Z75RKTHV.js} +4 -4
- package/dist/{sample-HDPYNAKS.js → sample-OIJNXQNC.js} +4 -4
- package/dist/{search-6CPEPJTI.js → search-YDCPIDZX.js} +5 -5
- package/dist/{source-resolver-PCASPRSD.js → source-resolver-4SUWXUGW.js} +5 -5
- package/dist/source-resolver-4SUWXUGW.js.map +1 -0
- package/dist/{sync-warehouse-XC7YYZKC.js → sync-warehouse-NZFDS6WK.js} +4 -4
- package/dist/{tables-26PNVZIC.js → tables-WJS2VI4L.js} +5 -5
- package/dist/templates/default/CLAUDE.md +1 -1
- package/dist/templates/default/docs/yamchart-reference.md +164 -2
- package/dist/templates/default/yamchart.yaml +3 -0
- package/dist/{test-APA44AIF.js → test-I4XOF7TZ.js} +5 -17
- package/dist/test-I4XOF7TZ.js.map +1 -0
- package/package.json +3 -2
- package/dist/chunk-5N3FYFBV.js.map +0 -1
- package/dist/chunk-C7A7TKSY.js.map +0 -1
- package/dist/dev-Z2R2DBWO.js.map +0 -1
- package/dist/public/assets/PublicViewer-Da8Cu1C1.js +0 -1
- package/dist/public/assets/index-DVSm0iiw.js +0 -187
- package/dist/test-APA44AIF.js.map +0 -1
- /package/dist/{advisor-54JBE2EV.js.map → advisor-Z7TKPPBR.js.map} +0 -0
- /package/dist/{connection-utils-MXEF6X7K.js.map → agent-KWKPAYT2.js.map} +0 -0
- /package/dist/{chunk-NCPWAWIM.js.map → chunk-AMHCOB4D.js.map} +0 -0
- /package/dist/{chunk-YMQ4PWVJ.js.map → chunk-FZFBBB7K.js.map} +0 -0
- /package/dist/{chunk-GLCEDWGH.js.map → chunk-G57J2WQM.js.map} +0 -0
- /package/dist/{dist-E2PVGIPT.js.map → connection-utils-CTPN7PV3.js.map} +0 -0
- /package/dist/{describe-XKLBZEWG.js.map → describe-4NME6RCB.js.map} +0 -0
- /package/dist/{dist-LJR7TAW4.js.map → dist-4GUE24QV.js.map} +0 -0
- /package/dist/{dist-GVNWQXFR.js.map → dist-7CRX2GIR.js.map} +0 -0
- /package/dist/{source-resolver-PCASPRSD.js.map → dist-VNX77VV5.js.map} +0 -0
- /package/dist/{query-MXMFI5TB.js.map → query-Z75RKTHV.js.map} +0 -0
- /package/dist/{sample-HDPYNAKS.js.map → sample-OIJNXQNC.js.map} +0 -0
- /package/dist/{search-6CPEPJTI.js.map → search-YDCPIDZX.js.map} +0 -0
- /package/dist/{sync-warehouse-XC7YYZKC.js.map → sync-warehouse-NZFDS6WK.js.map} +0 -0
- /package/dist/{tables-26PNVZIC.js.map → tables-WJS2VI4L.js.map} +0 -0
|
@@ -4,9 +4,9 @@ import {
|
|
|
4
4
|
import {
|
|
5
5
|
createConnector,
|
|
6
6
|
resolveConnection
|
|
7
|
-
} from "./chunk-
|
|
8
|
-
import "./chunk-
|
|
9
|
-
import "./chunk-
|
|
7
|
+
} from "./chunk-AMHCOB4D.js";
|
|
8
|
+
import "./chunk-E2QN2M7S.js";
|
|
9
|
+
import "./chunk-CWAWATL4.js";
|
|
10
10
|
import "./chunk-UND73EOB.js";
|
|
11
11
|
import "./chunk-DGUM43GV.js";
|
|
12
12
|
|
|
@@ -38,4 +38,4 @@ async function sampleTable(projectDir, table, options) {
|
|
|
38
38
|
export {
|
|
39
39
|
sampleTable
|
|
40
40
|
};
|
|
41
|
-
//# sourceMappingURL=sample-
|
|
41
|
+
//# sourceMappingURL=sample-OIJNXQNC.js.map
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
resolveSearchSource
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-FZFBBB7K.js";
|
|
4
4
|
import "./chunk-VJC24RKT.js";
|
|
5
5
|
import "./chunk-EHM6AMMA.js";
|
|
6
|
-
import "./chunk-
|
|
7
|
-
import "./chunk-
|
|
8
|
-
import "./chunk-
|
|
6
|
+
import "./chunk-AMHCOB4D.js";
|
|
7
|
+
import "./chunk-E2QN2M7S.js";
|
|
8
|
+
import "./chunk-CWAWATL4.js";
|
|
9
9
|
import "./chunk-UND73EOB.js";
|
|
10
10
|
import "./chunk-DGUM43GV.js";
|
|
11
11
|
|
|
@@ -25,4 +25,4 @@ async function searchDatabase(projectDir, keyword, options) {
|
|
|
25
25
|
export {
|
|
26
26
|
searchDatabase
|
|
27
27
|
};
|
|
28
|
-
//# sourceMappingURL=search-
|
|
28
|
+
//# sourceMappingURL=search-YDCPIDZX.js.map
|
|
@@ -2,12 +2,12 @@ import {
|
|
|
2
2
|
resolveDescribeSource,
|
|
3
3
|
resolveSearchSource,
|
|
4
4
|
resolveTablesSource
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-FZFBBB7K.js";
|
|
6
6
|
import "./chunk-VJC24RKT.js";
|
|
7
7
|
import "./chunk-EHM6AMMA.js";
|
|
8
|
-
import "./chunk-
|
|
9
|
-
import "./chunk-
|
|
10
|
-
import "./chunk-
|
|
8
|
+
import "./chunk-AMHCOB4D.js";
|
|
9
|
+
import "./chunk-E2QN2M7S.js";
|
|
10
|
+
import "./chunk-CWAWATL4.js";
|
|
11
11
|
import "./chunk-UND73EOB.js";
|
|
12
12
|
import "./chunk-DGUM43GV.js";
|
|
13
13
|
export {
|
|
@@ -15,4 +15,4 @@ export {
|
|
|
15
15
|
resolveSearchSource,
|
|
16
16
|
resolveTablesSource
|
|
17
17
|
};
|
|
18
|
-
//# sourceMappingURL=source-resolver-
|
|
18
|
+
//# sourceMappingURL=source-resolver-4SUWXUGW.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
import {
|
|
12
12
|
createConnector,
|
|
13
13
|
resolveConnection
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-AMHCOB4D.js";
|
|
15
15
|
import {
|
|
16
16
|
detail,
|
|
17
17
|
error,
|
|
@@ -20,8 +20,8 @@ import {
|
|
|
20
20
|
success,
|
|
21
21
|
warning
|
|
22
22
|
} from "./chunk-HJVVHYVN.js";
|
|
23
|
-
import "./chunk-
|
|
24
|
-
import "./chunk-
|
|
23
|
+
import "./chunk-E2QN2M7S.js";
|
|
24
|
+
import "./chunk-CWAWATL4.js";
|
|
25
25
|
import "./chunk-UND73EOB.js";
|
|
26
26
|
import "./chunk-DGUM43GV.js";
|
|
27
27
|
|
|
@@ -365,4 +365,4 @@ async function runSyncWarehouse(projectDir, options) {
|
|
|
365
365
|
export {
|
|
366
366
|
runSyncWarehouse
|
|
367
367
|
};
|
|
368
|
-
//# sourceMappingURL=sync-warehouse-
|
|
368
|
+
//# sourceMappingURL=sync-warehouse-NZFDS6WK.js.map
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
resolveTablesSource
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-FZFBBB7K.js";
|
|
4
4
|
import "./chunk-VJC24RKT.js";
|
|
5
5
|
import "./chunk-EHM6AMMA.js";
|
|
6
|
-
import "./chunk-
|
|
7
|
-
import "./chunk-
|
|
8
|
-
import "./chunk-
|
|
6
|
+
import "./chunk-AMHCOB4D.js";
|
|
7
|
+
import "./chunk-E2QN2M7S.js";
|
|
8
|
+
import "./chunk-CWAWATL4.js";
|
|
9
9
|
import "./chunk-UND73EOB.js";
|
|
10
10
|
import "./chunk-DGUM43GV.js";
|
|
11
11
|
|
|
@@ -27,4 +27,4 @@ async function listTables(projectDir, options) {
|
|
|
27
27
|
export {
|
|
28
28
|
listTables
|
|
29
29
|
};
|
|
30
|
-
//# sourceMappingURL=tables-
|
|
30
|
+
//# sourceMappingURL=tables-WJS2VI4L.js.map
|
|
@@ -25,7 +25,7 @@ yamchart advisor # AI-powered dbt model advisor
|
|
|
25
25
|
- `yamchart.yaml` — project config, default connection, theme, auth
|
|
26
26
|
- `connections/*.yaml` — database connections (DuckDB, Postgres, MySQL, SQLite, Snowflake)
|
|
27
27
|
- `models/*.sql` — SQL with Jinja templating (`{{ param }}`, `{% if %}`, `{{ ref('table') }}`)
|
|
28
|
-
- `charts/*.yaml` — chart definitions (line, bar, area, pie, donut, scatter, kpi, combo, heatmap, funnel, waterfall, gauge, table)
|
|
28
|
+
- `charts/*.yaml` — chart definitions (line, bar, area, pie, donut, scatter, kpi, combo, heatmap, funnel, waterfall, gauge, sankey, table)
|
|
29
29
|
- `dashboards/*.yaml` — 12-column grid layouts with chart/text widgets, optional tabs
|
|
30
30
|
- `schedules/*.yaml` — cron-based Slack reports and threshold alerts
|
|
31
31
|
|
|
@@ -259,6 +259,25 @@ chart:
|
|
|
259
259
|
format: ".1f"
|
|
260
260
|
```
|
|
261
261
|
|
|
262
|
+
**Sankey** — flow/navigation visualization using pre-aggregated source→target→value rows:
|
|
263
|
+
```yaml
|
|
264
|
+
chart:
|
|
265
|
+
type: sankey
|
|
266
|
+
source: { field: from_page } # Source node field
|
|
267
|
+
target: { field: to_page } # Target node field
|
|
268
|
+
value: { field: transitions } # Flow value field
|
|
269
|
+
levels: # Optional — explicit node depth ordering
|
|
270
|
+
- [Homepage, Blog, Resources] # Left column
|
|
271
|
+
- [Product, Solutions] # Middle column
|
|
272
|
+
- [Conversion] # Right column
|
|
273
|
+
orient: horizontal # horizontal (default) or vertical
|
|
274
|
+
node_width: 20 # Node bar width in px (default: 20)
|
|
275
|
+
node_gap: 12 # Gap between nodes in px (default: 12)
|
|
276
|
+
label_position: right # Label position: left, right, top, bottom, inside
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
Ideal for page navigation flows, conversion funnels, and resource allocation visualization. Nodes auto-arrange by flow when `levels` is omitted. Hover highlights connected paths. Right-click for drill-down/cross-filter.
|
|
280
|
+
|
|
262
281
|
**Table** — sortable data table with optional sticky columns, summary row, pagination, and overflow control:
|
|
263
282
|
```yaml
|
|
264
283
|
chart:
|
|
@@ -275,6 +294,11 @@ chart:
|
|
|
275
294
|
enabled: true
|
|
276
295
|
page_size: 50 # Default: 50, options shown: 25/50/100/All
|
|
277
296
|
mode: paginated # paginated (default) or infinite_scroll
|
|
297
|
+
server_side: true # Optional — force server-side LIMIT/OFFSET pagination
|
|
298
|
+
max_rows: 10000 # Optional — display cap (default: 10000, auto-activates server-side pagination)
|
|
299
|
+
export: # Optional — CSV export settings (enabled by default)
|
|
300
|
+
enabled: true
|
|
301
|
+
max_rows: 500000 # Export row cap (default: 500000)
|
|
278
302
|
```
|
|
279
303
|
|
|
280
304
|
Column headers are automatically humanized (`total_revenue` → "Total Revenue") unless an explicit `label` is set.
|
|
@@ -284,6 +308,9 @@ Column headers are automatically humanized (`total_revenue` → "Total Revenue")
|
|
|
284
308
|
**Overflow:** Per-column `overflow` controls long content: `ellipsis` (default — truncate with tooltip on hover), `wrap` (word-break), `hidden` (clip without tooltip). Useful for wallet addresses, hashes, or URLs.
|
|
285
309
|
**Font:** `font: mono` renders a column in monospace — ideal for hashes, IDs, and code values.
|
|
286
310
|
**Pagination:** When enabled, large tables show page controls (Previous/Next, page size selector with 25/50/100/All). `infinite_scroll` mode loads rows progressively as you scroll. Without pagination, all rows render (fine for small tables, slow for 1000+ rows).
|
|
311
|
+
**Server-side pagination:** Tables exceeding `max_rows` (default 10,000) automatically switch to server-side pagination with `LIMIT/OFFSET` queries, a parallel `COUNT(*)` for total rows, and server-computed summary aggregations. A notice banner shows "Showing first 10,000 of ~208,000 rows — use Export for full data". Set `pagination.server_side: true` to force this mode, or configure `max_rows` per-chart. Project-wide defaults: `defaults.table.max_display_rows` and `defaults.table.max_export_rows` in `yamchart.yaml`.
|
|
312
|
+
**Export:** CSV export is available on all table charts via the actions menu (three-dot icon). Downloads are bounded by `export.max_rows` (default 500K) to prevent runaway exports. The export endpoint streams CSV directly from the warehouse.
|
|
313
|
+
**Copy Table:** The actions menu includes "Copy Table" which copies all visible data as tab-delimited text to the clipboard (pastes into Excel/Sheets). Keyboard shortcuts: Cmd+A to select all, Cmd+C to copy. Click row numbers for row selection, Shift/Cmd+click headers for column selection.
|
|
287
314
|
|
|
288
315
|
**Pivot table** — transform flat query results into grouped, pivoted tables with subtotals and heatmap coloring:
|
|
289
316
|
```yaml
|
|
@@ -347,6 +374,82 @@ series:
|
|
|
347
374
|
gradient: true # or { from: "#hex", to: "#hex" }
|
|
348
375
|
```
|
|
349
376
|
|
|
377
|
+
**Rolling average** — compute moving average client-side:
|
|
378
|
+
```yaml
|
|
379
|
+
series:
|
|
380
|
+
columns:
|
|
381
|
+
- field: sessions
|
|
382
|
+
name: Daily Sessions
|
|
383
|
+
color: "#93C5FD"
|
|
384
|
+
opacity: 0.4
|
|
385
|
+
- field: sessions
|
|
386
|
+
name: 7-Day Avg
|
|
387
|
+
color: "#2563EB"
|
|
388
|
+
transform: { type: rolling_average, window: 7 }
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
**Range bands** — shaded area between two series (forecast confidence intervals):
|
|
392
|
+
```yaml
|
|
393
|
+
series:
|
|
394
|
+
columns:
|
|
395
|
+
- field: actual
|
|
396
|
+
name: Actual
|
|
397
|
+
color: "#2563EB"
|
|
398
|
+
- field: forecast_low
|
|
399
|
+
name: Forecast Range
|
|
400
|
+
color: "#93C5FD"
|
|
401
|
+
band: Forecast Upper # Pairs with another column by name
|
|
402
|
+
- field: forecast_high
|
|
403
|
+
name: Forecast Upper
|
|
404
|
+
color: "#93C5FD"
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
### Annotations
|
|
408
|
+
|
|
409
|
+
Add reference lines and markers to line, bar, area, and combo charts:
|
|
410
|
+
```yaml
|
|
411
|
+
chart:
|
|
412
|
+
type: line
|
|
413
|
+
annotations:
|
|
414
|
+
- type: line # Horizontal y-axis reference line
|
|
415
|
+
value: 1000
|
|
416
|
+
label: Target
|
|
417
|
+
color: "#22C55E"
|
|
418
|
+
style: dashed # solid, dashed, dotted
|
|
419
|
+
- type: band # Shaded y-axis range
|
|
420
|
+
from: 800
|
|
421
|
+
to: 1200
|
|
422
|
+
label: Target Zone
|
|
423
|
+
color: "rgba(34, 197, 94, 0.1)"
|
|
424
|
+
- type: x_line # Vertical x-axis marker (date or category)
|
|
425
|
+
x: "2026-03-13"
|
|
426
|
+
label: Launch
|
|
427
|
+
color: "#EF4444"
|
|
428
|
+
style: dashed
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
### Period-over-Period Comparisons
|
|
432
|
+
|
|
433
|
+
Overlay prior periods on the same chart to compare trends (WoW, MoM, YoY):
|
|
434
|
+
```yaml
|
|
435
|
+
chart:
|
|
436
|
+
type: line
|
|
437
|
+
x: { field: date, type: temporal }
|
|
438
|
+
y: { field: sessions }
|
|
439
|
+
compare:
|
|
440
|
+
- period: previous_week # Shifts dates back by 7 days
|
|
441
|
+
label: Last Week
|
|
442
|
+
style: dashed
|
|
443
|
+
opacity: 0.5
|
|
444
|
+
color: "#94A3B8"
|
|
445
|
+
- period: previous_year # Shifts dates back by 12 months
|
|
446
|
+
label: Last Year
|
|
447
|
+
style: dotted
|
|
448
|
+
opacity: 0.3
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
The server automatically re-queries the model with shifted date ranges and returns comparison data aligned by position (not date). Supported periods: `previous_week`, `previous_month`, `previous_quarter`, `previous_year`. Works with any date preset or custom range.
|
|
452
|
+
|
|
350
453
|
### Stacking
|
|
351
454
|
|
|
352
455
|
```yaml
|
|
@@ -400,7 +503,7 @@ parameters:
|
|
|
400
503
|
|
|
401
504
|
### Drill-Down
|
|
402
505
|
|
|
403
|
-
|
|
506
|
+
Right-click any chart element to open a context menu with options to cross-filter, view detail data, or navigate to a related chart.
|
|
404
507
|
|
|
405
508
|
```yaml
|
|
406
509
|
drillDown:
|
|
@@ -536,7 +639,7 @@ Press `⌘K` (Mac) or `Ctrl+K` (Windows/Linux) to open the search modal from any
|
|
|
536
639
|
|
|
537
640
|
### Cross-Filtering
|
|
538
641
|
|
|
539
|
-
|
|
642
|
+
Right-click any chart element on a dashboard to filter all other charts by the clicked dimension. Cross-filters are dashboard-scoped and auto-clear on navigation.
|
|
540
643
|
|
|
541
644
|
### Edit Mode
|
|
542
645
|
|
|
@@ -697,6 +800,9 @@ defaults:
|
|
|
697
800
|
cache_ttl: "30m" # Default cache TTL
|
|
698
801
|
base_url: https://bi.example.com # For SSO callbacks and alert links
|
|
699
802
|
week_start: monday # sunday–saturday
|
|
803
|
+
table: # Table chart defaults
|
|
804
|
+
max_display_rows: 10000 # Auto-switch to server-side pagination above this (default: 10000)
|
|
805
|
+
max_export_rows: 500000 # CSV export row cap (default: 500000)
|
|
700
806
|
|
|
701
807
|
theme:
|
|
702
808
|
base: modern # Preset: modern (default), executive, minimal
|
|
@@ -1053,6 +1159,62 @@ chart:
|
|
|
1053
1159
|
|
|
1054
1160
|
All goal types (fixed, cumulative, model) support a `zone` with `tolerance` (0–1). This renders a semi-transparent shaded band around the goal line at ±tolerance of the target value. For example, `tolerance: 0.10` on a target of 100,000 shades the 90,000–110,000 range.
|
|
1055
1161
|
|
|
1162
|
+
## AI Chat
|
|
1163
|
+
|
|
1164
|
+
AI chat adds an interactive assistant to the web UI. Enable it in `yamchart.yaml`:
|
|
1165
|
+
|
|
1166
|
+
```yaml
|
|
1167
|
+
features:
|
|
1168
|
+
chat: true
|
|
1169
|
+
```
|
|
1170
|
+
|
|
1171
|
+
Requires `ANTHROPIC_API_KEY` environment variable. When disabled or key is missing, all chat UI elements and endpoints are hidden.
|
|
1172
|
+
|
|
1173
|
+
### Built-in Agents
|
|
1174
|
+
|
|
1175
|
+
| Agent | Description |
|
|
1176
|
+
|-------|-------------|
|
|
1177
|
+
| Dashboard Analyst | Summarizes dashboards, explains trends, answers data questions, applies filters |
|
|
1178
|
+
| SQL Explorer | Runs ad-hoc SQL queries, compares periods, deep-dives into raw data |
|
|
1179
|
+
|
|
1180
|
+
### Custom Agents
|
|
1181
|
+
|
|
1182
|
+
Define project-specific agents in `agents/*.yaml`:
|
|
1183
|
+
|
|
1184
|
+
```yaml
|
|
1185
|
+
name: finance-analyst
|
|
1186
|
+
title: Finance Analyst
|
|
1187
|
+
description: Expert in revenue metrics, P&L, and financial KPIs
|
|
1188
|
+
system_prompt: |
|
|
1189
|
+
You are a finance analyst for {{project.name}}.
|
|
1190
|
+
Focus on revenue, margins, and cost metrics.
|
|
1191
|
+
tools:
|
|
1192
|
+
- query_model
|
|
1193
|
+
- compare_periods
|
|
1194
|
+
- get_dashboard_summary
|
|
1195
|
+
model: claude-sonnet-4-5-20250929 # optional model override
|
|
1196
|
+
models: # optional - restrict accessible models
|
|
1197
|
+
- revenue_*
|
|
1198
|
+
- costs_*
|
|
1199
|
+
```
|
|
1200
|
+
|
|
1201
|
+
### Available Tools
|
|
1202
|
+
|
|
1203
|
+
| Tool | Description |
|
|
1204
|
+
|------|-------------|
|
|
1205
|
+
| `query_model` | Execute a SQL model with parameters |
|
|
1206
|
+
| `get_chart_config` | Read a chart's full YAML config |
|
|
1207
|
+
| `get_dashboard_summary` | List charts, types, and cached KPI values |
|
|
1208
|
+
| `apply_filter` | Set a dashboard filter (updates UI in real-time) |
|
|
1209
|
+
| `run_sql` | Execute ad-hoc SQL against the connected database |
|
|
1210
|
+
| `compare_periods` | Run a model with two date ranges and diff results |
|
|
1211
|
+
|
|
1212
|
+
### Entry Points
|
|
1213
|
+
|
|
1214
|
+
- **Ask AI button** on chart headers and dashboard toolbar
|
|
1215
|
+
- **Cmd+K search** — "Ask AI: {query}" option when no exact match
|
|
1216
|
+
- **Sidebar chat tab** — general conversation without specific context
|
|
1217
|
+
|
|
1056
1218
|
## Number Formats (d3-format)
|
|
1057
1219
|
|
|
1058
1220
|
| Format | Output | Use |
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createConnector,
|
|
3
3
|
resolveConnection
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-AMHCOB4D.js";
|
|
5
5
|
import {
|
|
6
6
|
detail,
|
|
7
7
|
error,
|
|
@@ -10,15 +10,16 @@ import {
|
|
|
10
10
|
success,
|
|
11
11
|
warning
|
|
12
12
|
} from "./chunk-HJVVHYVN.js";
|
|
13
|
-
import "./chunk-
|
|
13
|
+
import "./chunk-E2QN2M7S.js";
|
|
14
14
|
import {
|
|
15
15
|
createTemplateContext,
|
|
16
16
|
expandDatePreset,
|
|
17
17
|
isDatePreset,
|
|
18
18
|
parseModelMetadata,
|
|
19
19
|
renderTemplate,
|
|
20
|
+
resolveDynamicDefault,
|
|
20
21
|
runAll
|
|
21
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-CWAWATL4.js";
|
|
22
23
|
import "./chunk-UND73EOB.js";
|
|
23
24
|
import "./chunk-DGUM43GV.js";
|
|
24
25
|
|
|
@@ -58,19 +59,6 @@ async function testProject(projectDir, modelFilter, options) {
|
|
|
58
59
|
await connector.disconnect();
|
|
59
60
|
}
|
|
60
61
|
}
|
|
61
|
-
function resolveDynamicDefault(value) {
|
|
62
|
-
const trimmed = value.trim().toLowerCase();
|
|
63
|
-
if (trimmed === "current_date()" || trimmed === "current_date" || trimmed === "now()" || trimmed.includes("current_date")) {
|
|
64
|
-
return formatISODate(/* @__PURE__ */ new Date());
|
|
65
|
-
}
|
|
66
|
-
return value;
|
|
67
|
-
}
|
|
68
|
-
function formatISODate(date) {
|
|
69
|
-
const y = date.getFullYear();
|
|
70
|
-
const m = String(date.getMonth() + 1).padStart(2, "0");
|
|
71
|
-
const d = String(date.getDate()).padStart(2, "0");
|
|
72
|
-
return `${y}-${m}-${d}`;
|
|
73
|
-
}
|
|
74
62
|
function compileWithDefaults(sql, metadata, refs) {
|
|
75
63
|
const params = {};
|
|
76
64
|
if (metadata.params) {
|
|
@@ -192,4 +180,4 @@ export {
|
|
|
192
180
|
formatTestOutput,
|
|
193
181
|
testProject
|
|
194
182
|
};
|
|
195
|
-
//# sourceMappingURL=test-
|
|
183
|
+
//# sourceMappingURL=test-I4XOF7TZ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/test.ts"],"sourcesContent":["import { readFile, readdir } from 'fs/promises';\nimport { join, extname } from 'path';\nimport {\n parseModelMetadata,\n runAll,\n renderTemplate,\n createTemplateContext,\n expandDatePreset,\n isDatePreset,\n resolveDynamicDefault,\n type TestSuiteResult,\n type TestModelInput,\n} from '@yamchart/query';\nimport type { ModelMetadata } from '@yamchart/schema';\nimport * as output from '../utils/output.js';\nimport { resolveConnection, createConnector } from './connection-utils.js';\n\nexport interface TestOptions {\n connection?: string;\n json?: boolean;\n}\n\nexport interface TestResult {\n success: boolean;\n suite: TestSuiteResult;\n connectionName: string;\n}\n\nexport async function testProject(\n projectDir: string,\n modelFilter: string | undefined,\n options: TestOptions,\n): Promise<TestResult> {\n const connection = await resolveConnection(projectDir, options.connection);\n const connector = createConnector(connection, projectDir);\n\n const modelsDir = join(projectDir, 'models');\n const allModels = await loadModels(modelsDir);\n\n let modelsToTest = allModels;\n if (modelFilter) {\n modelsToTest = allModels.filter((m) => m.name === modelFilter);\n if (modelsToTest.length === 0) {\n throw new Error(`Model \"${modelFilter}\" not found`);\n }\n }\n\n // Build refs map: model name -> model name (identity for standalone execution)\n const refs: Record<string, string> = {};\n for (const m of allModels) {\n refs[m.name] = m.name;\n }\n\n const testInputs: TestModelInput[] = [];\n for (const model of modelsToTest) {\n try {\n const compiledSql = compileWithDefaults(model.sql, model.metadata, refs);\n testInputs.push({ compiledSql, metadata: model.metadata });\n } catch {\n // If compilation fails, include raw SQL so the error is reported during test execution\n testInputs.push({ compiledSql: model.sql, metadata: model.metadata });\n }\n }\n\n try {\n await connector.connect();\n const suite = await runAll(testInputs, connector);\n return { success: suite.failed === 0, suite, connectionName: connection.name };\n } finally {\n await connector.disconnect();\n }\n}\n\nfunction compileWithDefaults(\n sql: string,\n metadata: ModelMetadata,\n refs: Record<string, string>,\n): string {\n const params: Record<string, unknown> = {};\n if (metadata.params) {\n for (const p of metadata.params) {\n if (p.default !== undefined) {\n params[p.name] = resolveDynamicDefault(p.default);\n }\n }\n }\n\n // Expand date presets into start_date/end_date\n if (typeof params.date_range === 'string' && isDatePreset(params.date_range)) {\n const range = expandDatePreset(params.date_range);\n if (range) {\n params.start_date = range.start_date;\n params.end_date = range.end_date;\n }\n }\n\n const context = createTemplateContext(params, refs);\n return renderTemplate(sql, context);\n}\n\ninterface LoadedModel {\n name: string;\n sql: string;\n metadata: ModelMetadata;\n}\n\nasync function loadModels(dir: string): Promise<LoadedModel[]> {\n const models: LoadedModel[] = [];\n\n let entries;\n try {\n entries = await readdir(dir, { withFileTypes: true });\n } catch {\n return models;\n }\n\n for (const entry of entries) {\n const fullPath = join(dir, entry.name);\n if (entry.isDirectory()) {\n const subModels = await loadModels(fullPath);\n models.push(...subModels);\n } else if (extname(entry.name) === '.sql') {\n const content = await readFile(fullPath, 'utf-8');\n try {\n const parsed = parseModelMetadata(content);\n models.push({ name: parsed.name, sql: parsed.sql, metadata: parsed });\n } catch {\n // Skip unparseable models\n }\n }\n }\n\n return models;\n}\n\nexport function formatTestOutput(result: TestResult, connectionName: string): void {\n const { suite } = result;\n\n const testedModels = suite.models.filter(\n (m) => m.schemaCheck || m.assertions.length > 0 || m.error,\n );\n\n output.header(`Testing ${suite.models.length} model(s) against ${connectionName}...`);\n\n for (const model of suite.models) {\n const hasChecks = model.schemaCheck || model.assertions.length > 0 || model.error;\n if (!hasChecks) continue;\n\n console.log(` ${model.modelName}`);\n\n if (model.error) {\n output.error(` error: ${model.error}`);\n continue;\n }\n\n if (model.schemaCheck) {\n formatSchemaCheck(model.schemaCheck);\n }\n\n for (const assertion of model.assertions) {\n formatAssertion(assertion);\n }\n\n output.newline();\n }\n\n // Summary line\n const totalChecks = suite.passed + suite.failed;\n const summary = `${testedModels.length} model(s), ${totalChecks} check(s): ${suite.passed} passed, ${suite.failed} failed`;\n const skippedSuffix = suite.skipped > 0 ? ` (${suite.skipped} skipped)` : '';\n const durationSuffix = ` (${suite.durationMs.toFixed(0)}ms)`;\n\n if (suite.failed === 0) {\n output.success(`${summary}${skippedSuffix}${durationSuffix}`);\n } else {\n output.error(`${summary}${skippedSuffix}${durationSuffix}`);\n }\n}\n\nfunction formatSchemaCheck(check: NonNullable<TestSuiteResult['models'][0]['schemaCheck']>): void {\n if (check.passed) {\n output.success(` schema: returns expected columns (${check.expectedColumns.join(', ')})`);\n return;\n }\n\n const issues: string[] = [];\n if (check.missingColumns.length > 0) {\n issues.push(`missing: ${check.missingColumns.join(', ')}`);\n }\n for (const m of check.typeMismatches) {\n issues.push(`${m.column}: expected ${m.expected}, got ${m.actual}`);\n }\n output.error(` schema: ${issues.join('; ')}`);\n}\n\nfunction formatAssertion(assertion: TestSuiteResult['models'][0]['assertions'][0]): void {\n const label = extractAssertionLabel(assertion.sql);\n\n if (assertion.warning) {\n output.warning(` ${label}`);\n output.detail(` ${assertion.warning}`);\n }\n\n if (assertion.error) {\n output.error(` test: ${label} -- error`);\n output.detail(` ${assertion.error}`);\n } else if (assertion.passed) {\n output.success(` test: ${label}`);\n } else {\n output.error(` test: ${label} -- ${assertion.violationCount} failing row(s)`);\n if (assertion.sampleViolations) {\n for (const row of assertion.sampleViolations.slice(0, 3)) {\n output.detail(` ${JSON.stringify(row)}`);\n }\n }\n }\n}\n\nfunction extractAssertionLabel(sql: string): string {\n const whereMatch = sql.match(/WHERE\\s+(.+?)$/i);\n if (whereMatch?.[1]) {\n const clause = whereMatch[1].trim();\n return clause.length > 60 ? clause.slice(0, 57) + '...' : clause;\n }\n return sql.length > 60 ? sql.slice(0, 57) + '...' : sql;\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "yamchart",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "Git-native business intelligence dashboards",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -66,8 +66,9 @@
|
|
|
66
66
|
"typescript": "^5.7.0",
|
|
67
67
|
"vitest": "^2.1.0",
|
|
68
68
|
"@yamchart/advisor": "0.1.0",
|
|
69
|
-
"@yamchart/config": "0.1.2",
|
|
70
69
|
"@yamchart/auth-local": "0.1.0",
|
|
70
|
+
"@yamchart/chat": "0.1.0",
|
|
71
|
+
"@yamchart/config": "0.1.2",
|
|
71
72
|
"@yamchart/query": "0.1.2",
|
|
72
73
|
"@yamchart/schema": "0.1.2",
|
|
73
74
|
"@yamchart/server": "0.1.2"
|