yamchart 0.4.11 → 0.4.12

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,9 +1,31 @@
1
1
  # {{name}}
2
2
 
3
+ This is a [Yamchart](https://github.com/simon-spenc/yamchart) project — Git-native BI dashboards defined as YAML configs and SQL models.
4
+
3
5
  ## Project Notes
4
6
 
5
- Add your project-specific notes, conventions, and context here.
7
+ Add your project-specific notes, conventions, and context here (e.g. database schema, naming conventions, team preferences).
8
+
9
+ ## Quick Start
10
+
11
+ ```bash
12
+ yamchart dev # Start dev server with hot reload
13
+ yamchart validate # Validate all config files
14
+ yamchart test # Run model assertions
15
+ yamchart tables # List database tables
16
+ yamchart describe <table> # Show table columns
17
+ yamchart search <keyword> # Find tables/columns
18
+ ```
19
+
20
+ ## File Structure
21
+
22
+ - `yamchart.yaml` — project config, default connection, theme, auth
23
+ - `connections/*.yaml` — database connections (DuckDB, Postgres, MySQL, SQLite, Snowflake)
24
+ - `models/*.sql` — SQL with Jinja templating (`{{ param }}`, `{% if %}`, `{{ ref('table') }}`)
25
+ - `charts/*.yaml` — chart definitions (line, bar, area, pie, donut, scatter, kpi, combo, heatmap, funnel, waterfall, gauge, table)
26
+ - `dashboards/*.yaml` — 12-column grid layouts with chart/text widgets, optional tabs
27
+ - `schedules/*.yaml` — cron-based Slack reports and threshold alerts
6
28
 
7
29
  ## Yamchart Reference
8
30
 
9
- See [docs/yamchart-reference.md](docs/yamchart-reference.md) for the full yamchart configuration reference including chart types, SQL models, dashboards, connections, and formatting options.
31
+ See [docs/yamchart-reference.md](docs/yamchart-reference.md) for the full configuration reference including all chart types, parameters, dashboard tabs, filters, connections, schedules, authentication, and formatting options.
@@ -6,11 +6,12 @@ Yamchart is a Git-native BI framework. Dashboards are defined as YAML configs an
6
6
 
7
7
  ```
8
8
  {{name}}/
9
- ├── yamchart.yaml # Project config + default connection
9
+ ├── yamchart.yaml # Project config, default connection, theme, auth
10
10
  ├── connections/ # Database connection configs (.yaml)
11
11
  ├── models/ # SQL models with Jinja templating (.sql)
12
12
  ├── charts/ # Chart definitions (.yaml)
13
- └── dashboards/ # Dashboard layouts (.yaml)
13
+ ├── dashboards/ # Dashboard layouts (.yaml)
14
+ └── schedules/ # Scheduled reports and alerts (.yaml)
14
15
  ```
15
16
 
16
17
  ## Commands
@@ -21,11 +22,16 @@ yamchart validate # Validate all config files
21
22
  yamchart validate --dry-run # Also test queries with EXPLAIN
22
23
  yamchart test # Run model @returns and @tests assertions
23
24
  yamchart test <model> # Test specific model
25
+ yamchart update # Check for and install updates
24
26
  yamchart tables # List tables in connected database
27
+ yamchart tables --schema public # Filter to a specific schema
25
28
  yamchart describe <table> # Show columns and types (accepts dbt model names)
26
29
  yamchart sample <table> # Show sample rows (default: 5, accepts dbt model names)
30
+ yamchart sample <table> -l 10 # Custom row limit
27
31
  yamchart search <keyword> # Find tables and columns matching keyword
28
- yamchart query "SELECT ..." # Execute ad-hoc SQL
32
+ yamchart query "SELECT ..." # Execute ad-hoc SQL (default limit: 100)
33
+ yamchart query "SELECT ..." --limit 500 # Custom row limit
34
+ yamchart reset-password --email <e> # Reset a user's password (requires auth enabled)
29
35
  ```
30
36
 
31
37
  ## SQL Models (`models/*.sql`)
@@ -35,9 +41,13 @@ Models are SQL files with metadata comments and Jinja templating.
35
41
  ```sql
36
42
  -- @name: model_name
37
43
  -- @description: What this model computes
44
+ -- @param start_date: date = 2025-01-01
45
+ -- @param category: string = All
38
46
  -- @returns:
39
- -- - column1: type
40
- -- - column2: type
47
+ -- - period: date
48
+ -- - revenue: number
49
+ -- @tests:
50
+ -- - SELECT * FROM ({{this}}) t WHERE revenue < 0
41
51
 
42
52
  SELECT
43
53
  date_trunc('{{ granularity }}', order_date) AS period,
@@ -47,16 +57,21 @@ WHERE order_date BETWEEN '{{ start_date }}' AND '{{ end_date }}'
47
57
  {% if category and category != 'All' %}
48
58
  AND category = '{{ category }}'
49
59
  {% endif %}
60
+ {% if user.department %}
61
+ AND department = '{{ user.department }}'
62
+ {% endif %}
50
63
  GROUP BY 1
51
64
  ORDER BY 1
52
65
  ```
53
66
 
54
67
  **Metadata tags:** `@name` (required), `@description`, `@param name: type = default`, `@returns` (column: type list), `@tests` (SQL assertions where zero rows = pass)
55
68
 
56
- **Templating:** `{{ variable }}` for substitution, `{% if %}` / `{% endif %}` for conditionals, `{{ ref('table') }}` for table references, `{{ user.attribute }}` for row-level security.
69
+ **Templating:** `{{ variable }}` for substitution, `{% if %}` / `{% endif %}` for conditionals, `{{ ref('table') }}` for table references, `{{ user.email|role|<attribute> }}` for row-level security.
57
70
 
58
71
  **Date parameters:** When a chart has `type: date_range`, the model receives `start_date` and `end_date` automatically.
59
72
 
73
+ **Tests:** `{{this}}` in `@tests` expands to the compiled SQL. Zero rows returned = pass; any rows = failure.
74
+
60
75
  ## Charts (`charts/*.yaml`)
61
76
 
62
77
  ### Common Structure
@@ -67,10 +82,16 @@ title: My Chart # Display title (required)
67
82
  description: Description # Optional
68
83
  source:
69
84
  model: model_name # SQL model to use
85
+ connection: prod # Optional — override default connection
70
86
  parameters: [] # Interactive filters (optional)
71
87
  chart:
72
88
  type: line # Chart type
73
89
  # ... type-specific config
90
+ drillDown: # Optional — right-click to navigate
91
+ chart: detail-chart
92
+ field: category
93
+ refresh: # Optional — caching/scheduling
94
+ cache_ttl: "30m"
74
95
  ```
75
96
 
76
97
  ### Chart Types
@@ -83,6 +104,8 @@ chart:
83
104
  y: { field: revenue, format: "$,.0f" }
84
105
  series:
85
106
  field: category # Multi-series by grouping field (optional)
107
+ stacking: stacked # Optional: stacked or percent (bar/area only)
108
+ gradient: true # Optional: auto gradient on fill
86
109
  ```
87
110
 
88
111
  **Pie / Donut** — part-to-whole:
@@ -91,6 +114,10 @@ chart:
91
114
  type: pie # or donut
92
115
  x: { field: segment, type: nominal }
93
116
  y: { field: amount, format: "$,.0f" }
117
+ centerValue: # Donut only — center display
118
+ field: total # 'total' sums all values, or use a field name
119
+ label: "Total"
120
+ format: "$,.0f"
94
121
  ```
95
122
 
96
123
  **Scatter** — correlations with optional size/group/regression:
@@ -99,28 +126,47 @@ chart:
99
126
  type: scatter
100
127
  x: { field: revenue, type: quantitative }
101
128
  y: { field: orders, type: quantitative }
102
- size: { field: avg_value, min: 8, max: 40 }
103
- group: { field: region }
104
- regression: { type: linear, show_equation: true, show_r_squared: true }
129
+ size: { field: avg_value, min: 8, max: 40, label: "Avg Value" } # Bubble encoding
130
+ group: { field: region } # Color by category
131
+ regression: # Trend line
132
+ type: linear
133
+ show_equation: true
134
+ show_r_squared: true
105
135
  ```
106
136
 
107
- **KPI** — single metric with comparison:
137
+ **KPI** — single metric with optional comparison:
108
138
  ```yaml
109
139
  chart:
110
140
  type: kpi
111
- value: { field: value }
141
+ value: { field: revenue }
112
142
  format: { type: currency, currency: USD, decimals: 0 }
113
- comparison: { enabled: true, field: previous_value, type: percent_change }
143
+ unit: "sessions" # Optional suffix label
144
+
145
+ # Option A: Auto comparison (server computes previous period)
146
+ comparison:
147
+ enabled: true
148
+ period: previous # Server shifts date range back automatically
149
+ type: percent_change # or absolute
150
+
151
+ # Option B: Manual comparison (use a column from query results)
152
+ comparison:
153
+ enabled: true
154
+ field: previous_value # Column name with the comparison value
155
+ label: "vs last month"
156
+ type: percent_change
114
157
  ```
115
158
 
159
+ > **Auto comparison:** `period: previous` runs the model a second time with the shifted date range. It infers the shift from the active date preset (e.g. `last_30_days` → previous 30 days). Displays period labels, change badge, and "vs" previous value automatically.
160
+
116
161
  **Heatmap** — two-dimensional intensity:
117
162
  ```yaml
118
163
  chart:
119
164
  type: heatmap
120
165
  x: { field: hour, type: ordinal }
121
166
  y: { field: day, type: ordinal }
122
- value: { field: count }
167
+ value: { field: count, label: "Count" }
123
168
  color_range: { min: '#EBF5FB', max: '#1A5276' }
169
+ show_values: true
124
170
  ```
125
171
 
126
172
  **Funnel** — conversion stages:
@@ -129,6 +175,7 @@ chart:
129
175
  type: funnel
130
176
  stage: { field: stage_name }
131
177
  value: { field: user_count }
178
+ show_conversion: true
132
179
  ```
133
180
 
134
181
  **Waterfall** — incremental deltas:
@@ -137,7 +184,11 @@ chart:
137
184
  type: waterfall
138
185
  category: { field: label }
139
186
  value: { field: amount }
140
- total_field: is_total
187
+ total_field: is_total # Column name marking total rows
188
+ colors:
189
+ increase: "#10B981"
190
+ decrease: "#EF4444"
191
+ total: "#3B82F6"
141
192
  ```
142
193
 
143
194
  **Gauge** — single metric dial:
@@ -151,6 +202,7 @@ chart:
151
202
  - { value: 60, color: '#EF4444' }
152
203
  - { value: 85, color: '#F59E0B' }
153
204
  - { value: 100, color: '#22C55E' }
205
+ format: ".1f"
154
206
  ```
155
207
 
156
208
  **Table** — sortable data table (renders all query columns by default):
@@ -178,7 +230,7 @@ chart:
178
230
 
179
231
  ### Multi-Series
180
232
 
181
- **Long format** — group by a field:
233
+ **Long format** — group by a field in the data:
182
234
  ```yaml
183
235
  series:
184
236
  field: region
@@ -191,19 +243,27 @@ series:
191
243
  ```yaml
192
244
  series:
193
245
  columns:
194
- - { field: revenue, name: Revenue, color: "#3B82F6" }
195
- - { field: cost, name: Cost, color: "#EF4444", style: dashed }
246
+ - field: revenue
247
+ name: Revenue
248
+ color: "#3B82F6"
249
+ - field: cost
250
+ name: Cost
251
+ color: "#EF4444"
252
+ style: dashed # solid, dashed, or dotted
253
+ opacity: 0.8 # 0–1
254
+ gradient: true # or { from: "#hex", to: "#hex" }
196
255
  ```
197
256
 
198
257
  ### Stacking
199
258
 
200
259
  ```yaml
201
260
  chart:
202
- type: bar
203
- stacking: stacked # or "percent" (normalizes to 100%)
261
+ type: bar # or area
262
+ stacking: stacked # normal stacking
263
+ stacking: percent # normalizes to 100%, caps y-axis, shows % labels
204
264
  ```
205
265
 
206
- ### Parameters
266
+ ### Parameters (Interactive Filters)
207
267
 
208
268
  ```yaml
209
269
  parameters:
@@ -213,23 +273,47 @@ parameters:
213
273
 
214
274
  - name: region
215
275
  type: select
276
+ label: Region
216
277
  options: [North, South, East, West]
217
278
  default: North
218
279
 
280
+ - name: tags
281
+ type: multi_select
282
+ options:
283
+ - value: a
284
+ label: Category A
285
+ - value: b
286
+ label: Category B
287
+
219
288
  - name: category
220
289
  type: dynamic_select
221
290
  source: { model: category_options, value_field: id, label_field: name }
291
+
292
+ - name: search_term
293
+ type: text
294
+
295
+ - name: min_revenue
296
+ type: number
297
+ default: 0
298
+
299
+ - name: is_active
300
+ type: boolean
301
+ default: true
222
302
  ```
223
303
 
224
- **Presets for date_range:** today, yesterday, last_7_days, last_30_days, last_90_days, last_365_days, this_week, last_week, this_month, last_month, this_quarter, last_quarter, this_year, last_year
304
+ **Parameter types:** `date_range`, `select`, `multi_select`, `dynamic_select`, `text`, `number`, `boolean`
305
+
306
+ **Date presets:** `last_7_days`, `last_30_days`, `last_90_days`, `last_12_months`, `year_to_date`, `month_to_date`, `quarter_to_date`, `previous_month`, `previous_quarter`, `previous_year`
225
307
 
226
308
  ### Drill-Down
227
309
 
310
+ Right-click any chart element to navigate to a related detail chart with filtered data.
311
+
228
312
  ```yaml
229
313
  drillDown:
230
314
  chart: detail-chart # Target chart name
231
- field: category # Field to pass as filter
232
- columns: # Optional table columns on landing
315
+ field: category # Field to pass as filter (defaults to x-axis field)
316
+ columns: # Optional table columns on landing page
233
317
  - { field: name, label: Name }
234
318
  - { field: revenue, label: Revenue, format: "$,.0f" }
235
319
  ```
@@ -239,27 +323,53 @@ drillDown:
239
323
  ```yaml
240
324
  chart:
241
325
  gradient: true # Auto gradient
326
+ gradient: { from: "#3B82F6", to: "#1E40AF" } # Custom gradient
327
+
242
328
  color: "#3B82F6" # Single color override
243
- color: # Conditional coloring
329
+
330
+ color: # Conditional coloring (bar charts)
244
331
  conditions:
245
332
  - { when: "> 0", color: "#10B981" }
246
333
  - { when: "< 0", color: "#EF4444" }
247
334
  default: "#6B7280"
248
335
  ```
249
336
 
337
+ ### Axis Schema
338
+
339
+ ```yaml
340
+ x:
341
+ field: date
342
+ type: temporal # temporal, quantitative, ordinal, or nominal
343
+ format: "$,.0f" # Optional d3-format / strftime string
344
+ label: "Date" # Optional axis label
345
+ ```
346
+
347
+ ### Caching
348
+
349
+ ```yaml
350
+ refresh:
351
+ cache_ttl: "30m" # Cache duration: 30s, 5m, 1h, 1d
352
+ schedule: "0 * * * *" # Optional cron for pre-warming
353
+ timezone: America/New_York # Optional
354
+ ```
355
+
250
356
  ## Dashboards (`dashboards/*.yaml`)
251
357
 
252
358
  12-column grid layout with chart and text widgets.
253
359
 
360
+ ### Basic Layout
361
+
254
362
  ```yaml
255
363
  name: overview
256
364
  title: Executive Overview
365
+ description: High-level business metrics
257
366
 
258
- filters:
367
+ filters: # Optional — dashboard-level filters (shared across all tabs)
259
368
  - { name: date_range, type: date_range, default: last_30_days }
369
+ - { name: region, type: select, options: [All, North, South], default: All }
260
370
 
261
371
  layout:
262
- gap: 16
372
+ gap: 16 # Pixels between widgets (default: 16)
263
373
  rows:
264
374
  - height: 180
265
375
  widgets:
@@ -277,7 +387,62 @@ layout:
277
387
  vs last month: {{revenue-kpi@previous_month}}
278
388
  ```
279
389
 
280
- **KPI references in text:** `{{chart}}`, `{{chart.field}}`, `{{chart@preset}}`
390
+ ### Dashboard Tabs
391
+
392
+ Split a dashboard into tabbed sub-pages. Use `tabs` instead of `layout` (mutually exclusive).
393
+
394
+ ```yaml
395
+ name: analytics
396
+ title: Analytics Dashboard
397
+
398
+ filters: # Dashboard-level — shown on all tabs
399
+ - { name: date_range, type: date_range, default: last_30_days }
400
+
401
+ tabs:
402
+ - name: overview
403
+ label: Overview
404
+ layout:
405
+ rows:
406
+ - height: 400
407
+ widgets:
408
+ - { type: chart, ref: revenue-trend, cols: 12 }
409
+
410
+ - name: details
411
+ label: Details
412
+ filters: # Tab-level — only shown on this tab
413
+ - { name: category, type: select, options: [All, A, B, C] }
414
+ layout:
415
+ rows:
416
+ - height: 400
417
+ widgets:
418
+ - { type: chart, ref: detail-table, cols: 12 }
419
+ ```
420
+
421
+ Tab navigation is reflected in the URL as `?tab=details`. Dashboard-level filters persist across tabs; tab-level filters are scoped to their tab.
422
+
423
+ ### KPI References in Text Widgets
424
+
425
+ Embed live KPI values in markdown text widgets:
426
+
427
+ | Syntax | Description |
428
+ |--------|-------------|
429
+ | `{{chartName}}` | Primary value from a KPI chart |
430
+ | `{{chart.field}}` | Specific field from chart results |
431
+ | `{{chart@preset}}` | Value with a date preset applied |
432
+ | `{{chart@2025-01-01..2025-12-31}}` | Value with a fixed date range |
433
+
434
+ ### Cross-Filtering
435
+
436
+ 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.
437
+
438
+ ### Edit Mode
439
+
440
+ The dashboard UI includes an edit mode for drag-and-drop layout editing:
441
+ - Resize and reposition widgets on the grid
442
+ - Add new chart or text widgets via the toolbar
443
+ - Double-click text widgets to edit markdown inline (KPI autocomplete via `{`)
444
+ - Undo/redo support
445
+ - Changes are saved back to the YAML file
281
446
 
282
447
  ## Connections (`connections/*.yaml`)
283
448
 
@@ -296,18 +461,137 @@ database: analytics
296
461
  user: ${DB_USER}
297
462
  password: ${DB_PASSWORD}
298
463
  ssl: true
464
+ schema: public
465
+
466
+ # MySQL
467
+ name: mysql-db
468
+ type: mysql
469
+ config: { host: ${DB_HOST}, port: 3306, database: mydb }
470
+ auth: { type: env, user_var: MYSQL_USER, password_var: MYSQL_PASSWORD }
471
+
472
+ # Snowflake
473
+ name: snow
474
+ type: snowflake
475
+ config: { account: xy12345, warehouse: COMPUTE_WH, database: ANALYTICS, schema: PUBLIC }
476
+ auth: { type: env, user_var: SF_USER, password_var: SF_PASSWORD }
477
+ # SSO: auth: { type: externalbrowser, user_var: SF_USER }
478
+
479
+ # SQLite
480
+ name: local-sqlite
481
+ type: sqlite
482
+ path: ./data/app.db
299
483
  ```
300
484
 
301
485
  **Supported:** DuckDB, PostgreSQL, MySQL, SQLite, Snowflake
302
486
 
303
487
  Use `${ENV_VAR}` for credentials. Never commit secrets.
304
488
 
489
+ ## Schedules (`schedules/*.yaml`)
490
+
491
+ ### Scheduled Report
492
+
493
+ Deliver chart data summaries to Slack on a cron schedule.
494
+
495
+ ```yaml
496
+ name: weekly_sales_report
497
+ type: report
498
+ schedule: "0 9 * * MON" # Cron (5-6 fields)
499
+ timezone: America/New_York # Optional
500
+ channel:
501
+ slack:
502
+ webhook_url: ${SLACK_WEBHOOK_URL}
503
+ channel: "#sales" # Optional display override
504
+ charts:
505
+ - revenue_by_region
506
+ - top_products
507
+ params:
508
+ date_range: last_7_days
509
+ message: "Weekly sales report" # Optional header text
510
+ ```
511
+
512
+ ### Threshold Alert
513
+
514
+ Monitor a chart value against a threshold with cooldown.
515
+
516
+ ```yaml
517
+ name: revenue_drop_alert
518
+ type: alert
519
+ schedule: "*/15 * * * *" # Check every 15 minutes
520
+ channel:
521
+ slack:
522
+ webhook_url: ${SLACK_WEBHOOK_URL}
523
+ chart: daily_revenue # Single chart
524
+ params:
525
+ date_range: last_7_days
526
+ condition:
527
+ field: revenue
528
+ operator: lt # lt, gt, lte, gte, eq
529
+ value: 1000
530
+ cooldown: "1h" # Min time between alerts (30s, 5m, 1h, 1d)
531
+ message: "Revenue dropped below $1,000! Current: ${{value}}"
532
+ ```
533
+
534
+ **Alert behavior:** Evaluates the first row of query results. Empty results skip evaluation. `{{value}}` in the message is replaced with the actual value. Cooldown is in-memory and resets on server restart.
535
+
536
+ ## Authentication (`yamchart.yaml`)
537
+
538
+ Optional built-in authentication for self-hosted deployments.
539
+
540
+ ```yaml
541
+ auth:
542
+ enabled: true
543
+ db_path: ~/.yamchart/auth.db # Optional (default shown)
544
+ session_ttl: "30d" # Optional (default: 30 days)
545
+ providers: # Optional SSO
546
+ google:
547
+ client_id: ${GOOGLE_CLIENT_ID}
548
+ client_secret: ${GOOGLE_CLIENT_SECRET}
549
+ microsoft:
550
+ client_id: ${MS_CLIENT_ID}
551
+ client_secret: ${MS_CLIENT_SECRET}
552
+ tenant: ${MS_TENANT_ID}
553
+ oidc:
554
+ client_id: ${OIDC_CLIENT_ID}
555
+ client_secret: ${OIDC_CLIENT_SECRET}
556
+ issuer: https://auth.example.com
557
+ display_name: "Company SSO"
558
+ ```
559
+
560
+ - First visit prompts a setup wizard to create an admin account
561
+ - **Roles:** admin (manage users + content), editor (content only), viewer (read-only)
562
+ - **User attributes:** Admins can set key-value pairs per user (e.g. `department: Sales`) for row-level security
563
+ - **RLS in SQL:** `{{ user.email }}`, `{{ user.role }}`, `{{ user.department }}` etc.
564
+ - **CLI recovery:** `yamchart reset-password --email user@example.com`
565
+
566
+ ## Project Config (`yamchart.yaml`)
567
+
568
+ ```yaml
569
+ version: "1"
570
+ name: my-project
571
+ description: Analytics dashboards
572
+
573
+ defaults:
574
+ connection: local # Default connection name
575
+ cache_ttl: "30m" # Default cache TTL
576
+ base_url: https://bi.example.com # For SSO callbacks and alert links
577
+ week_start: monday # sunday–saturday
578
+
579
+ theme:
580
+ palette: ["#3B82F6", "#EF4444", "#10B981", "#F59E0B"]
581
+ gradient: false
582
+ opacity: 1.0
583
+
584
+ auth:
585
+ enabled: false # Enable built-in authentication
586
+ ```
587
+
305
588
  ## Axis Types
306
589
 
307
590
  | Type | Use | Example |
308
591
  |------|-----|---------|
309
592
  | `temporal` | Dates/times | `2024-01-15` |
310
- | `ordinal` | Categories | `Electronics` |
593
+ | `ordinal` | Ordered categories | `Mon, Tue, Wed` |
594
+ | `nominal` | Unordered categories | `Electronics` |
311
595
  | `quantitative` | Numbers | `250.5` |
312
596
 
313
597
  ## Number Formats (d3-format)
@@ -318,12 +602,4 @@ Use `${ENV_VAR}` for credentials. Never commit secrets.
318
602
  | `,.0f` | 1,234 | Numbers |
319
603
  | `.2%` | 12.34% | Percentages |
320
604
  | `.2s` | 1.2M | SI prefix |
321
-
322
- ## Theme (`yamchart.yaml`)
323
-
324
- ```yaml
325
- theme:
326
- palette: ["#3B82F6", "#EF4444", "#10B981", "#F59E0B"]
327
- gradient: false
328
- opacity: 1.0
329
- ```
605
+ | `.2f` | 1.23 | Fixed decimals |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yamchart",
3
- "version": "0.4.11",
3
+ "version": "0.4.12",
4
4
  "description": "Git-native business intelligence dashboards",
5
5
  "type": "module",
6
6
  "license": "MIT",