- visual-types.svg: grid of 18 visual types with mini icons across 3 rows
(charts, cards/KPIs/tables, slicers/maps/decorative) + list of 14 more
- report-workflow.svg: 6-step flow (scaffold, pages, visuals, bind, theme, validate)
- chat-demo-report.svg: Claude chat example showing report commands in action
New SVGs:
- dual-layer.svg: hero graphic showing both Modeling + Report layers
- report-layer.svg: 4-column showcase of Visuals, Pages, Themes, Filters
Updated SVGs:
- banner.svg: "The First CLI for Both Power BI Modeling and Reporting"
- skills-hub.svg: 12 skills in two rows (7 modeling + 5 report) with stats bar
- architecture-flow.svg: dual-path showing TOM + PBIR backends
- before-after.svg: added report-layer pain points and solutions
README updated to feature new graphics.
- Run ruff format on all 26 unformatted files
- Fix mypy strict errors: add explicit typing for json.loads returns,
add pywin32/websockets to mypy ignore_missing_imports
- Remove yaml dependency from test_skill_triggering.py (use regex parser)
- Fix skill triggering test to handle both single-line and multi-line
description formats in YAML frontmatter
19 files from earlier v3 sessions were created on disk but never
staged/committed: 11 source modules (backends, preview, templates,
utils) and 8 test files (488 tests depend on these).
Without these files the package would be broken on install.
Found during pre-publish review.
Redesigned desktop_sync to use save-first-then-rewrite pattern:
1. Snapshot recently modified PBIR files (our changes)
2. Close Desktop WITH save (preserves user's unsaved modeling work)
3. Re-apply our PBIR snapshots (Desktop's save overwrote them)
4. Reopen Desktop
This is safe for users who have unsaved modeling-layer changes
(measures, relationships, etc.) in Desktop -- those are preserved
by the save step. Our report-layer changes survive via the snapshot
re-apply.
Power BI Desktop does not auto-detect PBIR file changes. When pbi-cli
writes to report JSON files while Desktop has the .pbip open, Desktop's
in-memory state overwrites CLI changes on save.
New desktop_sync module: after any report-layer write command (add visual,
set filter, apply theme, etc.), pbi-cli automatically closes Desktop
(dismissing the save dialog) and reopens the .pbip file so Desktop loads
the updated state.
Also fixes:
- Add --path option to bookmarks and format command groups
- Fix categorical filter literal types (integers use "L" suffix, not
string quotes) so filters work correctly in Desktop
Both groups were missing the --path/-p option that report, visual, and
filters already had, making them only work when CWD was inside the
.Report folder. Now all report-layer command groups consistently
support explicit path override.
Found during E2E testing with Power BI Desktop.
Pure-Python TMDL folder diff for CI/CD model change reporting.
No Power BI Desktop connection required. Handles direct and
SemanticModel folder layouts, strips lineageTags to avoid false
positives, and keys relationships by fromColumn->toColumn instead
of GUIDs. 18 tests covering all diff scenarios.
Adds page_binding key to the page_get() return dict using data.get("pageBinding"),
returning None for regular pages and the full binding dict for drillthrough pages.
Two new tests in TestPageGet cover both the None and present cases.
Register azureMap in SUPPORTED_VISUAL_TYPES and VISUAL_TYPE_ALIASES
(azure_map, map), add Category+Size data roles and role aliases, default
size 500x400, renderer color/icon, and template. All 4 new tests pass.
Confirmed from Sales_Report.Report Desktop export: kpi visuals have a
third queryState key TrendLine (date/axis column for the sparkline), and
gauge visuals have a second queryState key MaxValue (a measure role).
- kpi.json template: add TrendLine projection slot
- gauge.json template: add MaxValue projection slot
- VISUAL_DATA_ROLES: updated kpi and gauge role lists
- ROLE_ALIASES: added trend_line/trend aliases for kpi, max/max_value/target for gauge
- MEASURE_ROLES: added MaxValue (TrendLine binds to Column, not Measure)
- tests: 6 new tests covering template structure and alias resolution
- Add isinstance(qs["Values"], dict) assertion to card and multiRowCard tests
- Add inline comment on "Fields" in MEASURE_ROLES clarifying it is used by cardNew only
Real Power BI Desktop PBIR exports use "Values" as the queryState role key
for card and multiRowCard visuals. The previous "Fields" key was silently
ignored by Desktop, causing visual_bind to write bindings that had no effect.
Updated templates, VISUAL_DATA_ROLES, and ROLE_ALIASES accordingly. Added
two regression tests to lock in the correct role name.
Registers advancedSlicerVisual with aliases advanced_slicer, adv_slicer,
and tile_slicer. Includes template with Values queryState, data roles,
role aliases, default size (280x280), renderer color/icon, and tests.
visual_list now detects visual.json files with a top-level "visualGroup"
key (real Power BI group containers) and returns visual_type "group"
instead of "unknown" for them.
- Guard missing 'visual' key in visual_set_container with PbiCliError
- Detect no-op in visual_set_container when no args are provided
- Remove -g shorthand from set-container --page option
- Add is_hidden field to page_list and page_get return dicts
- Validate hex color format in page_set_background before writing
- Add tests for all new validation and behaviour