Skip to content

Releases

DashCraft v0.2.0

Choose a tag to compare

@github-actions github-actions released this 25 Oct 13:43
4e3bbe2

Renders report pages offline, headlessly (pbiview render) and interactively in a Power BI Desktop-style app, from the data and engines of Phase 1. Also adds the remaining formats of FORMATS.md §5, PBIP local-cache data, a larger DAX library and session-derived columns.

Added

Report renderer (pbi-render)

  • Theme resolution: built-in fallback, base and custom themes deep-merged; ThemeDataColor{ColorId, Percent}; visualStyles precedence (visual objects → theme per type and preset → "*" → built-in defaults); primary and derived text classes.
  • Layout: page size and scaling (FitToPage, FitToWidth, ActualSize), page background and outspace, paint order (z, then tab order), visual groups, container chrome from visualContainerObjects (background, border with radius, drop shadow, padding, title with auto titles and wrapping).
  • Visual queries: queryState projections, report/page/visual filters, slicer selections and selected data points (per visualInteractions) → EVALUATE SUMMARIZECOLUMNS → Power BI-shaped DataViews (single, categorical, table, matrix) with totals and subtotals, implicit measures, default sorts, query limits and formatted cells. Report filters skip visuals with no relationship path to the filtered table. Filters that can't be applied are reported, never dropped silently.
  • Visuals: textbox (rich runs, lists, links, overflow scrollbar), shape/basicShape (22 shape kinds), actionButton (icons, text, actions), cardVisual, card, multiRowCard, kpi, slicer (dropdown, list, tiles, range) and advancedSlicerVisual, tableEx (auto-sized, wrapping, banded, scrollable), pivotTable (stepped or tabular, subtotals, expansion), pie and donut (leader-line labels), clustered/stacked/100% bar and column, line, area, stacked area, line + column combos (axes with nice ticks, legends, data labels, dataPoint colors, category scrolling). Other types draw a placeholder with their fields; failed queries draw ⚠ "Can't display this visual".
  • Service quirks reproduced: the new card's inner tile border and label clipping below ~100 px, honoured card font sizes, slicer header truncation, table auto-sizing and wrapping, pie label placement and truncation, Calibri metrics, browser line metrics.
  • Output: retained scene graph with hit ids → deterministic SVG and PNG (resvg, bundled Selawik fonts only: byte-identical on every OS).
  • Golden-image comparison (pbi_render::golden): page alignment, per-region Gaussian SSIM, diff heatmaps (written under target/ only).
  • Interactive rendering API: query_page_data + render_interactive_page (scroll, expansion, open dropdowns as an overlay, per-visual interactive geometry), InteractionState::from_page (selections saved in the report).

CLI

  • pbiview render: --png, --svg, --out-dir with --format png|svg|both, --report, --page (name, display name, index or part of it), --all-pages, --scale (default 2, at most 16), --slicer "SLICER=V1,V2" (!= to invert, = to clear), --now for reproducible clocks, --json per-visual status. Exit code 2 when the refresh or a visual fails.
  • refresh, measures, export --table and render take --source auto|m|cache; auto (the default) loads a PBIP's .pbi/cache.abf when present and notes it on stderr. refresh --json reports kind: "cache".
  • export --excel-safe turns on the CSV formula-injection guard.

Desktop app

  • Power BI Desktop-style shell (read-only): title bar with search (Alt+Q), ribbon with Desktop's tabs and groups (unsupported commands disabled with a tooltip), File backstage with persisted Recent files, view rail (Report, Table, Model, DAX query, TMDL), Filters / Visualizations / Data / Selection / Properties panes, formula bar, page tabs, status bar with zoom. Fluent UI System Icons (MIT) and Selawik (OFL); no Power BI assets.
  • Interactive report canvas: the page rendered by pbi-render as sanitized SVG; slicers (single and multi-select, Select all, dropdown popups, search, clear), cross-filtering from pie, bar, column, line, table and matrix points per visualInteractions, data-point and error tooltips, table and matrix scrolling, matrix expand/collapse, Back and page-navigation buttons (Web URL shown, never opened), Reset to default, keyboard focus. Renders are cancellable and query results are cached per page.
  • Filters pane cards follow view-mode rules (hidden cards, locks) and list the canvas's selections; the Measures panel evaluates in the canvas's filter context by default.
  • DAX query view (EVALUATE with DEFINE/ORDER BY, run selection, cancel, results with copy, quick queries), TMDL view (verbatim or generated), Model view diagram (diagramLayout.json positions or auto-layout), read-only Transform data editor, Design → Themes, Format pane cards.
  • Local data cache: a PBIP with .pbi/cache.abf loads its cached data on open, with a "Loaded cached data (as of …)" banner and Refresh from source.

Engines and session

  • DAX (pbi-dax): 210 functions (187 supported, 23 partial; up from about 120), including time intelligence, ALLSELECTED (shadow filter context), ISINSCOPE, ROLLUPADDISSUBTOTAL/ROLLUPGROUP in SUMMARIZECOLUMNS, RANKX, window functions (INDEX, OFFSET, WINDOW, RANK, ROWNUMBER), statistics, parent-child functions, USERELATIONSHIP and CROSSFILTER. Coverage table: crates/pbi-dax/FUNCTIONS.md, kept in sync by tests.
  • Storage engine (pbi-engine): per-filter-context relationship overrides (activate inactive relationships, change cross-filter direction).
  • Derived columns (pbi-session): Session::add_derived_column / remove_derived_column / derived_columns with DerivedColumn::People ("Parse people field"), Expression (DAX) and Array. Stored in the engine table, so DAX, SQL, the grid, statistics and exports (Parquet field metadata pbiview.derived = true) see them; re-applied in creation order after every refresh, cache load and CSV load; never saved to the model. Name collisions with a column or measure are errors.
  • PBIP local data cache: Session::load_cached_data maps <Model>.SemanticModel/.pbi/cache.abf onto the model by name (no M, no network). Calculated objects missing from the cache are computed; a missing table fails with a "refresh from source / Load CSV" hint; a missing data column loads as BLANK with SESSION005. RefreshOptions::source (Query, Cache, Auto), Session::cache_info, has_cached_data, RefreshKind::Cache.
  • CSV formula-injection guard: CsvExportOptions::escape_formulas (off by default) prefixes text cells and header names that start with =, +, -, @, TAB or CR with '; numbers, dates and booleans are never changed.

Formats

  • Excel Power Pivot (.xlsx/.xlsm): model and data from xl/model/item.data, with per-file Xpress (MS-XCA Plain LZ77) decompression and legacy XML metadata (compatibility level 1100/1103, .tbl.xml storage).
  • VPAX: model (from Model.bim or rebuilt from DaxModel.json) and VertiPaq Analyzer statistics.
  • RDL paginated reports: outline of data sources (connection strings always redacted), datasets, parameters and report items; DTDs refused, sizes capped.
  • Power Query: .pq/.m scripts, .pqt templates, dataflow model.json (CDM entities as tables with M partitions), Dataflow Gen2 definitions.
  • Custom visuals and connectors: .pbiviz metadata and .mez/.pqx listings; never executed.
  • PBIP .pbi/cache.abf metadata part (inspect → model.cacheAbf). New inspect --json sections (additive, schemaVersion 1): vpaxStats, paginatedReport, mashup, customVisual, connector.

Packaging

  • Original app icon (no Microsoft or Power BI marks), bundles for macOS (app + dmg, arm64 and x64), Windows (msi + nsis) and Linux (AppImage + deb), and file associations for .pbix, .pbit, .pbip, .bim and .vpax (viewer role, not claimed as default). The GUI binary is pbiview-app; the pbiview CLI ships as separate per-OS archives.
  • macOS document opens (Finder double-click, "Open With") reach the running app as an open-file-requested event; Windows and Linux pass the path on the command line.
  • Release workflow: tag/version consistency checks, release notes from this changelog, SHA-256 sums, CycloneDX + npm SBOMs, signing and notarization only when the secrets exist (unsigned builds otherwise). License inventory generated into THIRD_PARTY_NOTICES.md (scripts/license-inventory.py); see docs/packaging.md.

Tests and documentation

  • Golden-image regression tests against Power BI service exports (per-region SSIM ≥ 0.85; regions whose text uses fonts pbiview does not bundle, such as DIN titles and Calibri text, have documented lower thresholds). Card values are asserted on the rendered scene and SVG for each report.
  • Renderer unit and reference tests per visual family; CLI end-to-end render tests (determinism, JSON status, exit codes); app tests that drive the canvas through Tauri's mock runtime.
  • Docs: rewritten README with format and visual matrices, docs/CLI.md, docs/USER-GUIDE.md, docs/VISUALS.md, docs/ARCHITECTURE.md, final FORMATS.md, ADR-0006.

Changed

  • The app's "Parse people field" uses the pbi-session derived-column API: the column is now visible to measures, DAX queries, SQL filters and exports, not only the grid.
  • The app's former KPI strip is the Measures panel under the canvas, and the former Queries tab is Home → Transform data.
  • ADR-0005's interaction design is superseded by ADR-0006: selections are view state kept per page, not document commands.

Known gaps

  • Renderer: highlight interactions filter inst...
Read more