bi-superpowers 1.0.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/.claude-plugin/marketplace.json +31 -0
- package/.claude-plugin/plugin.json +34 -0
- package/.claude-plugin/skill-manifest.json +79 -0
- package/.mcp.json +13 -0
- package/.plugin/plugin.json +14 -0
- package/LICENSE +21 -0
- package/README.md +849 -0
- package/bin/build-plugin.js +97 -0
- package/bin/cli.js +891 -0
- package/bin/commands/autoupdate.js +128 -0
- package/bin/commands/build-desktop.js +368 -0
- package/bin/commands/create-from-template.js +165 -0
- package/bin/commands/diff.js +435 -0
- package/bin/commands/install.js +542 -0
- package/bin/commands/lint.js +441 -0
- package/bin/commands/mcp-setup.js +255 -0
- package/bin/commands/session-update.js +204 -0
- package/bin/commands/smoke-test.js +20 -0
- package/bin/commands/uninstall.js +611 -0
- package/bin/commands/update-check.js +427 -0
- package/bin/commands/validate-cases.js +264 -0
- package/bin/commands/validate-projects.js +426 -0
- package/bin/commands/watch.js +251 -0
- package/bin/lib/agents.js +62 -0
- package/bin/lib/base-template-smoke.js +299 -0
- package/bin/lib/claude-hooks.js +160 -0
- package/bin/lib/generators/claude-plugin.js +529 -0
- package/bin/lib/generators/index.js +116 -0
- package/bin/lib/generators/shared.js +257 -0
- package/bin/lib/mcp-config.js +835 -0
- package/bin/lib/microsoft-mcp.js +206 -0
- package/bin/lib/powerbi-mcp-session.js +140 -0
- package/bin/lib/skills.js +164 -0
- package/bin/lib/template-scaffold.js +366 -0
- package/bin/mcp/powerbi-modeling-launcher.js +42 -0
- package/bin/postinstall.js +50 -0
- package/bin/utils/mcp-detect.js +346 -0
- package/bin/utils/tui.js +314 -0
- package/commands/bi-connect.md +520 -0
- package/commands/bi-dax.md +464 -0
- package/commands/bi-kickoff.md +550 -0
- package/commands/bi-modeling.md +485 -0
- package/commands/bi-performance.md +521 -0
- package/commands/bi-powerquery.md +229 -0
- package/commands/bi-refactor.md +249 -0
- package/commands/bi-scorecard.md +268 -0
- package/commands/bi-start.md +272 -0
- package/config.example.json +23 -0
- package/config.json +23 -0
- package/desktop-extension/manifest.json +30 -0
- package/desktop-extension/package.json +10 -0
- package/desktop-extension/server.js +137 -0
- package/package.json +94 -0
- package/skills/bi-connect/SKILL.md +522 -0
- package/skills/bi-connect/scripts/update-check.js +427 -0
- package/skills/bi-dax/SKILL.md +466 -0
- package/skills/bi-dax/scripts/update-check.js +427 -0
- package/skills/bi-kickoff/SKILL.md +552 -0
- package/skills/bi-kickoff/references/flow.html +78 -0
- package/skills/bi-kickoff/references/flow.md +62 -0
- package/skills/bi-kickoff/scripts/update-check.js +427 -0
- package/skills/bi-modeling/SKILL.md +487 -0
- package/skills/bi-modeling/scripts/update-check.js +427 -0
- package/skills/bi-performance/SKILL.md +523 -0
- package/skills/bi-performance/scripts/install-tabular-editor.ps1 +159 -0
- package/skills/bi-performance/scripts/run-bpa.ps1 +265 -0
- package/skills/bi-performance/scripts/update-check.js +427 -0
- package/skills/bi-powerquery/SKILL.md +231 -0
- package/skills/bi-powerquery/references/base-template-data-contract.md +323 -0
- package/skills/bi-powerquery/references/power-query-standards.md +74 -0
- package/skills/bi-powerquery/scripts/new-powerquery-staging.ps1 +371 -0
- package/skills/bi-powerquery/scripts/test-powerquery-contract.ps1 +225 -0
- package/skills/bi-powerquery/scripts/update-check.js +427 -0
- package/skills/bi-refactor/SKILL.md +251 -0
- package/skills/bi-refactor/references/flow.md +27 -0
- package/skills/bi-refactor/scripts/update-check.js +427 -0
- package/skills/bi-scorecard/SKILL.md +270 -0
- package/skills/bi-scorecard/examples/base-template-scorecard-overlay.json +82 -0
- package/skills/bi-scorecard/scripts/new-scorecard-blueprint-from-base-template.ps1 +124 -0
- package/skills/bi-scorecard/scripts/powerbi-goal-status-rules-api.ps1 +39 -0
- package/skills/bi-scorecard/scripts/powerbi-goal-values-api.ps1 +48 -0
- package/skills/bi-scorecard/scripts/powerbi-goals-api.ps1 +68 -0
- package/skills/bi-scorecard/scripts/powerbi-rest-common.ps1 +197 -0
- package/skills/bi-scorecard/scripts/powerbi-scorecards-api.ps1 +53 -0
- package/skills/bi-scorecard/scripts/update-check.js +427 -0
- package/skills/bi-start/SKILL.md +274 -0
- package/skills/bi-start/scripts/update-check.js +427 -0
- package/src/content/base.md +197 -0
- package/src/content/mcp-requirements.json +57 -0
- package/src/content/routing.md +201 -0
- package/src/content/skills/bi-connect.md +493 -0
- package/src/content/skills/bi-dax.md +437 -0
- package/src/content/skills/bi-kickoff/SKILL.md +523 -0
- package/src/content/skills/bi-kickoff/references/flow.html +78 -0
- package/src/content/skills/bi-kickoff/references/flow.md +62 -0
- package/src/content/skills/bi-modeling.md +458 -0
- package/src/content/skills/bi-performance/SKILL.md +494 -0
- package/src/content/skills/bi-performance/scripts/install-tabular-editor.ps1 +159 -0
- package/src/content/skills/bi-performance/scripts/run-bpa.ps1 +265 -0
- package/src/content/skills/bi-powerquery/SKILL.md +202 -0
- package/src/content/skills/bi-powerquery/references/base-template-data-contract.md +323 -0
- package/src/content/skills/bi-powerquery/references/power-query-standards.md +74 -0
- package/src/content/skills/bi-powerquery/scripts/new-powerquery-staging.ps1 +371 -0
- package/src/content/skills/bi-powerquery/scripts/test-powerquery-contract.ps1 +225 -0
- package/src/content/skills/bi-refactor/SKILL.md +222 -0
- package/src/content/skills/bi-refactor/references/flow.md +27 -0
- package/src/content/skills/bi-scorecard/SKILL.md +241 -0
- package/src/content/skills/bi-scorecard/examples/base-template-scorecard-blueprint.expected.json +105 -0
- package/src/content/skills/bi-scorecard/examples/base-template-scorecard-overlay.json +82 -0
- package/src/content/skills/bi-scorecard/scripts/new-scorecard-blueprint-from-base-template.ps1 +124 -0
- package/src/content/skills/bi-scorecard/scripts/powerbi-goal-status-rules-api.ps1 +39 -0
- package/src/content/skills/bi-scorecard/scripts/powerbi-goal-values-api.ps1 +48 -0
- package/src/content/skills/bi-scorecard/scripts/powerbi-goals-api.ps1 +68 -0
- package/src/content/skills/bi-scorecard/scripts/powerbi-rest-common.ps1 +197 -0
- package/src/content/skills/bi-scorecard/scripts/powerbi-scorecards-api.ps1 +53 -0
- package/src/content/skills/bi-start.md +266 -0
- package/templates/base-template/AGENTS.md +33 -0
- package/templates/base-template/base-template.Report/.platform +11 -0
- package/templates/base-template/base-template.Report/StaticResources/RegisteredResources/BISuperpowers.json +3888 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BaseThemes/CY18SU07.json +177 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BaseThemes/Fluent2-CY26SU03.json +4104 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/AccessibleCityPark.json +26 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/AccessibleDefault.json +26 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/AccessibleNeutral.json +26 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/AccessibleOrchid.json +26 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/AccessibleTidal.json +26 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Bloom.json +139 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/CityPark.json +40 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Classroom.json +40 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/ColorblindSafe.json +48 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/CopilotDefault.json +1861 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Divergent.json +127 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Electric.json +48 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Frontier.json +136 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/HighContrast.json +40 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Highrise.json +41 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Innovate.json +227 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/NewExecutive.json +41 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Solar.json +33 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Storm.json +25 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Sunset.json +48 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Temperature.json +33 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Tidal.json +100 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Twilight.json +40 -0
- package/templates/base-template/base-template.Report/definition/bookmarks/1d40d43c7ade66e8603c.bookmark.json +2297 -0
- package/templates/base-template/base-template.Report/definition/bookmarks/af068ff51c0ca3089ea7.bookmark.json +2300 -0
- package/templates/base-template/base-template.Report/definition/bookmarks/bookmarks.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/page.json +130 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/0352fd80d074693a65db/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/0352fd80d074693a65db/visual.json +669 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/1c5a14bf493697344b68/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/1c5a14bf493697344b68/visual.json +723 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/3486cf7624c5b109b4e5/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/3486cf7624c5b109b4e5/visual.json +333 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/4d8b989008edc0db28d1/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/4d8b989008edc0db28d1/visual.json +109 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/55e10ac7d76a1954f94f/mobile.json +31 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/55e10ac7d76a1954f94f/visual.json +378 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/57f52ecf4490f70e4da1/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/57f52ecf4490f70e4da1/visual.json +175 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/5f4d76bbc870118e9840/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/5f4d76bbc870118e9840/visual.json +468 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/73629e1abebb7a444b59/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/73629e1abebb7a444b59/visual.json +359 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/749cb1388c7e0a88161c/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/749cb1388c7e0a88161c/visual.json +690 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/90677f13cea5d1275990/visual.json +17 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/92cf92e3da10493adb78/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/92cf92e3da10493adb78/visual.json +468 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/9fe17b1971f68443fc15/mobile.json +10 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/9fe17b1971f68443fc15/visual.json +328 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/a30bd0950630ed94e8a3/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/a30bd0950630ed94e8a3/visual.json +578 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/a56e91d9400a835e4814/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/a56e91d9400a835e4814/visual.json +432 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/aded24cd205c0b528642/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/aded24cd205c0b528642/visual.json +801 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/af34b26f14a8a724c9a9/mobile.json +37 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/af34b26f14a8a724c9a9/visual.json +1318 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/b529688fe5a226643322/visual.json +209 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/c4c6f332d05e72e2eb06/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/c4c6f332d05e72e2eb06/visual.json +174 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/fa81f184e2cb0e8b087c/mobile.json +29 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/fa81f184e2cb0e8b087c/visual.json +241 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/page.json +130 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/07e9c4302e29029c5462/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/07e9c4302e29029c5462/visual.json +690 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/109ceede4bc015b0c006/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/109ceede4bc015b0c006/visual.json +468 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/118257e006d472277e10/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/118257e006d472277e10/visual.json +359 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/2caf02e0137c4a1280cc/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/2caf02e0137c4a1280cc/visual.json +669 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/311e76fe3c9edad68204/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/311e76fe3c9edad68204/visual.json +109 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/31c21f8cbeb3b208940a/visual.json +209 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/3ab72c25062437149b03/visual.json +17 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/5959867442abcb0ce2b3/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/5959867442abcb0ce2b3/visual.json +788 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/5b96e0f88d192b044a13/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/5b96e0f88d192b044a13/visual.json +592 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/64e749a63d0786000e22/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/64e749a63d0786000e22/visual.json +468 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/7ae1ca604edac6586ad0/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/7ae1ca604edac6586ad0/visual.json +1310 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/840300733885141a6603/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/840300733885141a6603/visual.json +175 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/a38448cdb203279273d2/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/a38448cdb203279273d2/visual.json +516 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/d1e86f213a3841d12e20/visual.json +328 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/d4a484c1bcc8ee3075e2/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/d4a484c1bcc8ee3075e2/visual.json +432 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/d87cb5cf06acca19bbb5/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/d87cb5cf06acca19bbb5/visual.json +241 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/e243da2677209ed69408/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/e243da2677209ed69408/visual.json +174 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/f3aaf24f5b22b67573b0/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/f3aaf24f5b22b67573b0/visual.json +333 -0
- package/templates/base-template/base-template.Report/definition/pages/pages.json +8 -0
- package/templates/base-template/base-template.Report/definition/report.json +89 -0
- package/templates/base-template/base-template.Report/definition/version.json +4 -0
- package/templates/base-template/base-template.Report/definition.pbir +9 -0
- package/templates/base-template/base-template.SemanticModel/.platform +11 -0
- package/templates/base-template/base-template.SemanticModel/definition/cultures/es-AR.tmdl +11185 -0
- package/templates/base-template/base-template.SemanticModel/definition/database.tmdl +3 -0
- package/templates/base-template/base-template.SemanticModel/definition/expressions.tmdl +234 -0
- package/templates/base-template/base-template.SemanticModel/definition/functions.tmdl +637 -0
- package/templates/base-template/base-template.SemanticModel/definition/model.tmdl +82 -0
- package/templates/base-template/base-template.SemanticModel/definition/relationships.tmdl +271 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Calendario.tmdl +200 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Campa/303/261as.tmdl +75 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Canales.tmdl +84 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Clientes.tmdl +143 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Devoluciones.tmdl +95 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Ejecuci/303/263n proyectos.tmdl" +130 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Entregas.tmdl +122 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Equipos m/303/251tricas.tmdl" +40 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Equipos.tmdl +73 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Horas.tmdl +122 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Interacciones clientes.tmdl +146 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Leads.tmdl +119 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Monedas.tmdl +44 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Movimientos financieros.tmdl +145 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/M/303/251tricas.tmdl +1294 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/N/303/263mina.tmdl +110 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Oportunidades.tmdl +135 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Presupuesto.tmdl +125 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Productos.tmdl +98 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Proyectos.tmdl +77 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Servicios.tmdl +75 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Tareas proyecto.tmdl +102 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Tipo de cambio.tmdl +67 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Ventas.tmdl +180 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/_Aux An/303/241lisis dimensiones.tmdl" +38 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/_Aux Comparaciones.tmdl +227 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/_Aux Compatibilidad m/303/251trica-dimensi/303/263n.tmdl" +68 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/_Aux Modelo configuraci/303/263n.tmdl" +44 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/_Aux Modo fechas.tmdl +36 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/_Aux M/303/251trica-Equipo.tmdl" +102 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/_Aux Overrides m/303/251trica-dimensi/303/263n.tmdl" +54 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/_Aux Per/303/255odos.tmdl" +182 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/_Aux Rango fechas modo.tmdl +36 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/_Aux Rango fechas.tmdl +27 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/_Aux Vista de calendario.tmdl +30 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/_GC C/303/241lculo.tmdl" +70 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/_GC Eje X.tmdl +63 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/_GC M/303/251trica.tmdl" +374 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/_GC Tipo c/303/241lculo.tmdl" +223 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/_PC Dimensi/303/263n.tmdl" +98 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/_PC Eje X.tmdl +68 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables//303/223rdenes servicio.tmdl" +151 -0
- package/templates/base-template/base-template.SemanticModel/definition.pbism +5 -0
- package/templates/base-template/base-template.SemanticModel/diagramLayout.json +568 -0
- package/templates/base-template/base-template.pbip +14 -0
- package/templates/base-template/template.manifest.json +41 -0
- package/theme/BISuperpowers.json +3888 -0
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
{
|
|
2
|
+
"scorecardName": "Dirección Andina Nexus",
|
|
3
|
+
"goals": [
|
|
4
|
+
{
|
|
5
|
+
"metricName": "Ventas",
|
|
6
|
+
"scorecardEnabled": true,
|
|
7
|
+
"goalName": "Ventas",
|
|
8
|
+
"owner": "direccion@example.com",
|
|
9
|
+
"cadence": "Monthly",
|
|
10
|
+
"startDate": "2026-01-01T00:00:00Z",
|
|
11
|
+
"dueDate": "2026-12-31T00:00:00Z",
|
|
12
|
+
"target": 12000000,
|
|
13
|
+
"statusRulePreset": "higher-is-better"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"metricName": "Margen %",
|
|
17
|
+
"scorecardEnabled": true,
|
|
18
|
+
"goalName": "Margen %",
|
|
19
|
+
"owner": "finance@example.com",
|
|
20
|
+
"cadence": "Quarterly",
|
|
21
|
+
"startDate": "2026-01-01T00:00:00Z",
|
|
22
|
+
"dueDate": "2026-12-31T00:00:00Z",
|
|
23
|
+
"target": 0.42,
|
|
24
|
+
"statusRulePreset": "higher-is-better"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"metricName": "EBITDA",
|
|
28
|
+
"scorecardEnabled": true,
|
|
29
|
+
"goalName": "EBITDA",
|
|
30
|
+
"owner": "finance@example.com",
|
|
31
|
+
"cadence": "Monthly",
|
|
32
|
+
"startDate": "2026-01-01T00:00:00Z",
|
|
33
|
+
"dueDate": "2026-12-31T00:00:00Z",
|
|
34
|
+
"target": 2800000,
|
|
35
|
+
"statusRulePreset": "higher-is-better"
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"metricName": "Margen operativo %",
|
|
39
|
+
"scorecardEnabled": true,
|
|
40
|
+
"goalName": "Margen operativo %",
|
|
41
|
+
"owner": "finance@example.com",
|
|
42
|
+
"cadence": "Quarterly",
|
|
43
|
+
"startDate": "2026-01-01T00:00:00Z",
|
|
44
|
+
"dueDate": "2026-12-31T00:00:00Z",
|
|
45
|
+
"target": 0.24,
|
|
46
|
+
"statusRulePreset": "higher-is-better"
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"metricName": "Cash collected",
|
|
50
|
+
"scorecardEnabled": true,
|
|
51
|
+
"goalName": "Cash collected",
|
|
52
|
+
"owner": "treasury@example.com",
|
|
53
|
+
"cadence": "Monthly",
|
|
54
|
+
"startDate": "2026-01-01T00:00:00Z",
|
|
55
|
+
"dueDate": "2026-12-31T00:00:00Z",
|
|
56
|
+
"target": 10500000,
|
|
57
|
+
"statusRulePreset": "higher-is-better"
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"metricName": "Retención %",
|
|
61
|
+
"scorecardEnabled": true,
|
|
62
|
+
"goalName": "Retención %",
|
|
63
|
+
"owner": "clientes@example.com",
|
|
64
|
+
"cadence": "Monthly",
|
|
65
|
+
"startDate": "2026-01-01T00:00:00Z",
|
|
66
|
+
"dueDate": "2026-12-31T00:00:00Z",
|
|
67
|
+
"target": 0.9,
|
|
68
|
+
"statusRulePreset": "higher-is-better"
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
"metricName": "Rentabilidad de proyectos",
|
|
72
|
+
"scorecardEnabled": true,
|
|
73
|
+
"goalName": "Rentabilidad de proyectos",
|
|
74
|
+
"owner": "proyectos@example.com",
|
|
75
|
+
"cadence": "Monthly",
|
|
76
|
+
"startDate": "2026-01-01T00:00:00Z",
|
|
77
|
+
"dueDate": "2026-12-31T00:00:00Z",
|
|
78
|
+
"target": 1600000,
|
|
79
|
+
"statusRulePreset": "higher-is-better"
|
|
80
|
+
}
|
|
81
|
+
]
|
|
82
|
+
}
|
package/src/content/skills/bi-scorecard/scripts/new-scorecard-blueprint-from-base-template.ps1
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
#requires -Version 7.0
|
|
2
|
+
|
|
3
|
+
param(
|
|
4
|
+
[string] $TemplateRoot = 'templates/base-template',
|
|
5
|
+
|
|
6
|
+
[Parameter(Mandatory = $true)]
|
|
7
|
+
[string] $OverlayPath
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
Set-StrictMode -Version Latest
|
|
11
|
+
$ErrorActionPreference = 'Stop'
|
|
12
|
+
# Pin stdout to UTF-8 so the blueprint JSON keeps "Métricas"/"Descripción" intact
|
|
13
|
+
# when Node decodes the pipe as UTF-8, regardless of the host console codepage.
|
|
14
|
+
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
|
|
15
|
+
|
|
16
|
+
function Read-Overlay {
|
|
17
|
+
param([string] $Path)
|
|
18
|
+
return Get-Content -LiteralPath $Path -Raw | ConvertFrom-Json -Depth 100
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function Get-MetricsTmdlPath {
|
|
22
|
+
param([string] $Root)
|
|
23
|
+
$path = Join-Path $Root 'base-template.SemanticModel/definition/tables/Métricas.tmdl'
|
|
24
|
+
if (-not (Test-Path -LiteralPath $path)) {
|
|
25
|
+
throw "Métricas.tmdl not found under $Root"
|
|
26
|
+
}
|
|
27
|
+
return $path
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function Convert-MetricRow {
|
|
31
|
+
param(
|
|
32
|
+
[string] $Row,
|
|
33
|
+
[string[]] $Columns
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
# Assumes the Métricas catalog uses uppercase TRUE/FALSE booleans and no
|
|
37
|
+
# embedded/doubled quotes ("") in text cells; a violating edit throws the
|
|
38
|
+
# "Unexpected ... row shape" error below rather than silently mis-parsing.
|
|
39
|
+
# Use a private name, not the automatic $matches variable (which any later
|
|
40
|
+
# -match would silently overwrite).
|
|
41
|
+
$tokenMatches = [regex]::Matches($Row, '"([^"]*)"|TRUE|FALSE|[-]?\d+(?:\.\d+)?')
|
|
42
|
+
$values = @($tokenMatches | ForEach-Object { $_.Value.Trim('"') })
|
|
43
|
+
if ($values.Count -ne $Columns.Count) {
|
|
44
|
+
throw "Unexpected Métricas DATATABLE row shape: $Row"
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
$rowByColumn = @{}
|
|
48
|
+
for ($i = 0; $i -lt $Columns.Count; $i++) {
|
|
49
|
+
$rowByColumn[$Columns[$i]] = $values[$i]
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return [ordered]@{
|
|
53
|
+
metricName = $rowByColumn['Métrica']
|
|
54
|
+
format = $rowByColumn['Formato']
|
|
55
|
+
formatType = $rowByColumn['Tipo de formato']
|
|
56
|
+
trendDirection = $rowByColumn['Tendencia']
|
|
57
|
+
description = $rowByColumn['Descripción']
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function Read-BaseTemplateMetrics {
|
|
62
|
+
param([string] $Path)
|
|
63
|
+
|
|
64
|
+
$content = Get-Content -LiteralPath $Path -Raw
|
|
65
|
+
$table = [regex]::Match(
|
|
66
|
+
$content,
|
|
67
|
+
'DATATABLE\s*\((?<header>[\s\S]*?),\s*\{(?<rows>[\s\S]*?)\n\s*\}\s*\)\s*$'
|
|
68
|
+
)
|
|
69
|
+
if (-not $table.Success) {
|
|
70
|
+
throw 'Could not locate the Métricas DATATABLE rows.'
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
$columns = @(
|
|
74
|
+
[regex]::Matches($table.Groups['header'].Value, '"([^"]+)"\s*,\s*(?:STRING|INTEGER|BOOLEAN)') |
|
|
75
|
+
ForEach-Object { $_.Groups[1].Value }
|
|
76
|
+
)
|
|
77
|
+
if ($columns.Count -eq 0) {
|
|
78
|
+
throw 'Could not locate the Métricas DATATABLE columns.'
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
$rowOptions = [System.Text.RegularExpressions.RegexOptions]::Singleline
|
|
82
|
+
$rows = [regex]::Matches($table.Groups['rows'].Value, '\{\s*(?<row>[^{}]*?)\s*\}', $rowOptions)
|
|
83
|
+
return @($rows | ForEach-Object { Convert-MetricRow -Row $_.Groups['row'].Value -Columns $columns })
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
$overlay = Read-Overlay -Path $OverlayPath
|
|
87
|
+
$metrics = Read-BaseTemplateMetrics -Path (Get-MetricsTmdlPath -Root $TemplateRoot)
|
|
88
|
+
$metricByName = @{}
|
|
89
|
+
foreach ($metric in $metrics) {
|
|
90
|
+
$metricByName[$metric.metricName] = $metric
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
$goals = @()
|
|
94
|
+
foreach ($goal in $overlay.goals) {
|
|
95
|
+
if (-not $goal.scorecardEnabled) {
|
|
96
|
+
continue
|
|
97
|
+
}
|
|
98
|
+
if (-not $metricByName.ContainsKey($goal.metricName)) {
|
|
99
|
+
throw "Overlay references metric not found in base-template: $($goal.metricName)"
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
$metric = $metricByName[$goal.metricName]
|
|
103
|
+
$goals += [ordered]@{
|
|
104
|
+
metricName = $goal.metricName
|
|
105
|
+
goalName = $goal.goalName
|
|
106
|
+
description = $metric.description
|
|
107
|
+
format = $metric.format
|
|
108
|
+
formatType = $metric.formatType
|
|
109
|
+
trendDirection = $metric.trendDirection
|
|
110
|
+
owner = $goal.owner
|
|
111
|
+
cadence = $goal.cadence
|
|
112
|
+
startDate = $goal.startDate
|
|
113
|
+
dueDate = $goal.dueDate
|
|
114
|
+
target = $goal.target
|
|
115
|
+
statusRulePreset = $goal.statusRulePreset
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
[ordered]@{
|
|
120
|
+
sourceTemplate = 'templates/base-template/base-template.pbip'
|
|
121
|
+
metricsTable = 'Métricas'
|
|
122
|
+
scorecardName = $overlay.scorecardName
|
|
123
|
+
goals = $goals
|
|
124
|
+
} | ConvertTo-Json -Depth 100
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
param(
|
|
2
|
+
[Parameter(Mandatory = $true)]
|
|
3
|
+
[ValidateSet('Get', 'Upsert', 'Delete')]
|
|
4
|
+
[string] $Action,
|
|
5
|
+
|
|
6
|
+
[Parameter(Mandatory = $true)]
|
|
7
|
+
[string] $GroupId,
|
|
8
|
+
|
|
9
|
+
[Parameter(Mandatory = $true)]
|
|
10
|
+
[string] $ScorecardId,
|
|
11
|
+
|
|
12
|
+
[Parameter(Mandatory = $true)]
|
|
13
|
+
[string] $GoalId,
|
|
14
|
+
|
|
15
|
+
[string] $BodyPath,
|
|
16
|
+
[string] $AccessToken,
|
|
17
|
+
[switch] $ConfirmWrite
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
. "$PSScriptRoot/powerbi-rest-common.ps1"
|
|
21
|
+
|
|
22
|
+
$encodedGoalId = ConvertTo-PowerBiPathSegment -Name 'GoalId' -Value $GoalId
|
|
23
|
+
$goalPath = (New-PowerBiScorecardPath -GroupId $GroupId -ScorecardId $ScorecardId -Suffix 'goals') + "($encodedGoalId)"
|
|
24
|
+
$statusRulesPath = "$goalPath/statusRules"
|
|
25
|
+
|
|
26
|
+
switch ($Action) {
|
|
27
|
+
'Get' {
|
|
28
|
+
Invoke-PowerBiRest -Method GET -Path $statusRulesPath -AccessToken $AccessToken
|
|
29
|
+
}
|
|
30
|
+
'Upsert' {
|
|
31
|
+
Assert-ConfirmedWrite -Action $Action -ConfirmWrite:$ConfirmWrite
|
|
32
|
+
Assert-RequiredValue -Name 'BodyPath' -Value $BodyPath
|
|
33
|
+
Invoke-PowerBiRest -Method POST -Path $statusRulesPath -Body (Read-JsonObject -Path $BodyPath) -AccessToken $AccessToken
|
|
34
|
+
}
|
|
35
|
+
'Delete' {
|
|
36
|
+
Assert-ConfirmedWrite -Action $Action -ConfirmWrite:$ConfirmWrite
|
|
37
|
+
Invoke-PowerBiRest -Method DELETE -Path $statusRulesPath -AccessToken $AccessToken
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
param(
|
|
2
|
+
[Parameter(Mandatory = $true)]
|
|
3
|
+
[ValidateSet('List', 'Create', 'Delete')]
|
|
4
|
+
[string] $Action,
|
|
5
|
+
|
|
6
|
+
[Parameter(Mandatory = $true)]
|
|
7
|
+
[string] $GroupId,
|
|
8
|
+
|
|
9
|
+
[Parameter(Mandatory = $true)]
|
|
10
|
+
[string] $ScorecardId,
|
|
11
|
+
|
|
12
|
+
[Parameter(Mandatory = $true)]
|
|
13
|
+
[string] $GoalId,
|
|
14
|
+
|
|
15
|
+
[string] $Timestamp,
|
|
16
|
+
[string] $BodyPath,
|
|
17
|
+
[string] $AccessToken,
|
|
18
|
+
[switch] $ConfirmWrite
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
. "$PSScriptRoot/powerbi-rest-common.ps1"
|
|
22
|
+
|
|
23
|
+
$encodedGoalId = ConvertTo-PowerBiPathSegment -Name 'GoalId' -Value $GoalId
|
|
24
|
+
$goalPath = (New-PowerBiScorecardPath -GroupId $GroupId -ScorecardId $ScorecardId -Suffix 'goals') + "($encodedGoalId)"
|
|
25
|
+
$goalValuesPath = "$goalPath/goalValues"
|
|
26
|
+
|
|
27
|
+
switch ($Action) {
|
|
28
|
+
'List' {
|
|
29
|
+
Invoke-PowerBiRest -Method GET -Path $goalValuesPath -AccessToken $AccessToken
|
|
30
|
+
}
|
|
31
|
+
'Create' {
|
|
32
|
+
Assert-ConfirmedWrite -Action $Action -ConfirmWrite:$ConfirmWrite
|
|
33
|
+
Assert-RequiredValue -Name 'BodyPath' -Value $BodyPath
|
|
34
|
+
Invoke-PowerBiRest -Method POST -Path $goalValuesPath -Body (Read-JsonObject -Path $BodyPath) -AccessToken $AccessToken
|
|
35
|
+
}
|
|
36
|
+
'Delete' {
|
|
37
|
+
Assert-ConfirmedWrite -Action $Action -ConfirmWrite:$ConfirmWrite
|
|
38
|
+
Assert-RequiredValue -Name 'Timestamp' -Value $Timestamp
|
|
39
|
+
# The timestamp is an OData datetime key and appears literally per the
|
|
40
|
+
# Power BI REST reference — goalValues(2021-12-14T00:00:00Z) — so do NOT
|
|
41
|
+
# percent-encode the colons (a strict OData parser rejects %3A). Validate
|
|
42
|
+
# the ISO-8601 instant instead, which also keeps the segment injection-safe.
|
|
43
|
+
if ($Timestamp -notmatch '^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?Z$') {
|
|
44
|
+
throw "Timestamp must be an ISO-8601 UTC instant like 2026-01-01T00:00:00Z (got: $Timestamp)"
|
|
45
|
+
}
|
|
46
|
+
Invoke-PowerBiRest -Method DELETE -Path "$goalValuesPath($Timestamp)" -AccessToken $AccessToken
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
param(
|
|
2
|
+
[Parameter(Mandatory = $true)]
|
|
3
|
+
[ValidateSet('List', 'Get', 'Create', 'Update', 'Delete', 'GetRefreshHistory', 'RefreshCurrentValue', 'RefreshTargetValue', 'DeleteCurrentValueConnection', 'DeleteTargetValueConnection')]
|
|
4
|
+
[string] $Action,
|
|
5
|
+
|
|
6
|
+
[Parameter(Mandatory = $true)]
|
|
7
|
+
[string] $GroupId,
|
|
8
|
+
|
|
9
|
+
[Parameter(Mandatory = $true)]
|
|
10
|
+
[string] $ScorecardId,
|
|
11
|
+
|
|
12
|
+
[string] $GoalId,
|
|
13
|
+
[string] $BodyPath,
|
|
14
|
+
[string] $AccessToken,
|
|
15
|
+
[switch] $ConfirmWrite
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
. "$PSScriptRoot/powerbi-rest-common.ps1"
|
|
19
|
+
|
|
20
|
+
$goalsPath = New-PowerBiScorecardPath -GroupId $GroupId -ScorecardId $ScorecardId -Suffix 'goals'
|
|
21
|
+
|
|
22
|
+
function Get-GoalPath {
|
|
23
|
+
Assert-RequiredValue -Name 'GoalId' -Value $GoalId
|
|
24
|
+
$encodedGoalId = ConvertTo-PowerBiPathSegment -Name 'GoalId' -Value $GoalId
|
|
25
|
+
return "$goalsPath($encodedGoalId)"
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
switch ($Action) {
|
|
29
|
+
'List' {
|
|
30
|
+
Invoke-PowerBiRest -Method GET -Path $goalsPath -AccessToken $AccessToken
|
|
31
|
+
}
|
|
32
|
+
'Get' {
|
|
33
|
+
Invoke-PowerBiRest -Method GET -Path (Get-GoalPath) -AccessToken $AccessToken
|
|
34
|
+
}
|
|
35
|
+
'Create' {
|
|
36
|
+
Assert-ConfirmedWrite -Action $Action -ConfirmWrite:$ConfirmWrite
|
|
37
|
+
Assert-RequiredValue -Name 'BodyPath' -Value $BodyPath
|
|
38
|
+
Invoke-PowerBiRest -Method POST -Path $goalsPath -Body (Read-JsonObject -Path $BodyPath) -AccessToken $AccessToken
|
|
39
|
+
}
|
|
40
|
+
'Update' {
|
|
41
|
+
Assert-ConfirmedWrite -Action $Action -ConfirmWrite:$ConfirmWrite
|
|
42
|
+
Assert-RequiredValue -Name 'BodyPath' -Value $BodyPath
|
|
43
|
+
Invoke-PowerBiRest -Method PATCH -Path (Get-GoalPath) -Body (Read-JsonObject -Path $BodyPath) -AccessToken $AccessToken
|
|
44
|
+
}
|
|
45
|
+
'Delete' {
|
|
46
|
+
Assert-ConfirmedWrite -Action $Action -ConfirmWrite:$ConfirmWrite
|
|
47
|
+
Invoke-PowerBiRest -Method DELETE -Path (Get-GoalPath) -AccessToken $AccessToken
|
|
48
|
+
}
|
|
49
|
+
'GetRefreshHistory' {
|
|
50
|
+
Invoke-PowerBiRest -Method GET -Path "$(Get-GoalPath)/GetRefreshHistory()" -AccessToken $AccessToken
|
|
51
|
+
}
|
|
52
|
+
'RefreshCurrentValue' {
|
|
53
|
+
Assert-ConfirmedWrite -Action $Action -ConfirmWrite:$ConfirmWrite
|
|
54
|
+
Invoke-PowerBiRest -Method POST -Path "$(Get-GoalPath)/RefreshGoalCurrentValue()" -AccessToken $AccessToken
|
|
55
|
+
}
|
|
56
|
+
'RefreshTargetValue' {
|
|
57
|
+
Assert-ConfirmedWrite -Action $Action -ConfirmWrite:$ConfirmWrite
|
|
58
|
+
Invoke-PowerBiRest -Method POST -Path "$(Get-GoalPath)/RefreshGoalTargetValue()" -AccessToken $AccessToken
|
|
59
|
+
}
|
|
60
|
+
'DeleteCurrentValueConnection' {
|
|
61
|
+
Assert-ConfirmedWrite -Action $Action -ConfirmWrite:$ConfirmWrite
|
|
62
|
+
Invoke-PowerBiRest -Method POST -Path "$(Get-GoalPath)/DeleteGoalCurrentValueConnection()" -AccessToken $AccessToken
|
|
63
|
+
}
|
|
64
|
+
'DeleteTargetValueConnection' {
|
|
65
|
+
Assert-ConfirmedWrite -Action $Action -ConfirmWrite:$ConfirmWrite
|
|
66
|
+
Invoke-PowerBiRest -Method POST -Path "$(Get-GoalPath)/DeleteGoalTargetValueConnection()" -AccessToken $AccessToken
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
#requires -Version 7.0
|
|
2
|
+
|
|
3
|
+
Set-StrictMode -Version Latest
|
|
4
|
+
$ErrorActionPreference = 'Stop'
|
|
5
|
+
# Pin stdout to UTF-8 so accented payload text (Spanish goal names/descriptions)
|
|
6
|
+
# survives when the caller (Node/MCP) decodes the pipe as UTF-8, regardless of the
|
|
7
|
+
# host console codepage (CP437/CP1252 on many Windows shells). ConvertFrom-Json
|
|
8
|
+
# -Depth below also requires PowerShell 7+.
|
|
9
|
+
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
|
|
10
|
+
|
|
11
|
+
function Get-PowerBiBearerToken {
|
|
12
|
+
param(
|
|
13
|
+
[string] $AccessToken
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
if ($AccessToken) {
|
|
17
|
+
return $AccessToken
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if ($env:POWERBI_ACCESS_TOKEN) {
|
|
21
|
+
return $env:POWERBI_ACCESS_TOKEN
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
$az = Get-Command az -ErrorAction SilentlyContinue
|
|
25
|
+
if ($az) {
|
|
26
|
+
$token = az account get-access-token --resource 'https://analysis.windows.net/powerbi/api' --query accessToken -o tsv
|
|
27
|
+
if ($LASTEXITCODE -eq 0 -and $token) {
|
|
28
|
+
return $token.Trim()
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
throw 'No Power BI access token found. Set POWERBI_ACCESS_TOKEN or sign in with Azure CLI.'
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function Read-JsonObject {
|
|
36
|
+
param(
|
|
37
|
+
[Parameter(Mandatory = $true)]
|
|
38
|
+
[string] $Path
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
if (-not (Test-Path -LiteralPath $Path)) {
|
|
42
|
+
throw "JSON file not found: $Path"
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return Get-Content -LiteralPath $Path -Raw | ConvertFrom-Json -Depth 100
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function ConvertTo-JsonBody {
|
|
49
|
+
param(
|
|
50
|
+
[Parameter(Mandatory = $true)]
|
|
51
|
+
[object] $InputObject
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
return $InputObject | ConvertTo-Json -Depth 100
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function Assert-ConfirmedWrite {
|
|
58
|
+
param(
|
|
59
|
+
[Parameter(Mandatory = $true)]
|
|
60
|
+
[string] $Action,
|
|
61
|
+
|
|
62
|
+
[switch] $ConfirmWrite
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
if (-not $ConfirmWrite) {
|
|
66
|
+
throw "Write action '$Action' requires -ConfirmWrite."
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function Assert-RequiredValue {
|
|
71
|
+
param(
|
|
72
|
+
[Parameter(Mandatory = $true)]
|
|
73
|
+
[string] $Name,
|
|
74
|
+
|
|
75
|
+
[AllowNull()]
|
|
76
|
+
[string] $Value
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
if ([string]::IsNullOrWhiteSpace($Value)) {
|
|
80
|
+
throw "$Name is required."
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function ConvertTo-PowerBiPathSegment {
|
|
85
|
+
param(
|
|
86
|
+
[Parameter(Mandatory = $true)]
|
|
87
|
+
[string] $Value,
|
|
88
|
+
|
|
89
|
+
[string] $Name = 'Value'
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
Assert-RequiredValue -Name $Name -Value $Value
|
|
93
|
+
return [System.Uri]::EscapeDataString($Value)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function Resolve-PowerBiRestUri {
|
|
97
|
+
param(
|
|
98
|
+
[Parameter(Mandatory = $true)]
|
|
99
|
+
[string] $BaseUri,
|
|
100
|
+
|
|
101
|
+
[Parameter(Mandatory = $true)]
|
|
102
|
+
[string] $Path
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
$parsedBaseUri = [System.Uri] $BaseUri
|
|
106
|
+
if (
|
|
107
|
+
-not $parsedBaseUri.IsAbsoluteUri -or
|
|
108
|
+
$parsedBaseUri.Scheme -ne 'https' -or
|
|
109
|
+
$parsedBaseUri.Host -ne 'api.powerbi.com' -or
|
|
110
|
+
$parsedBaseUri.UserInfo
|
|
111
|
+
) {
|
|
112
|
+
throw 'Power BI REST calls must target https://api.powerbi.com without userinfo.'
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return "$($BaseUri.TrimEnd('/'))/$($Path.TrimStart('/'))"
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function New-PowerBiScorecardPath {
|
|
119
|
+
param(
|
|
120
|
+
[Parameter(Mandatory = $true)]
|
|
121
|
+
[string] $GroupId,
|
|
122
|
+
|
|
123
|
+
[string] $ScorecardId,
|
|
124
|
+
|
|
125
|
+
[string] $Suffix
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
$encodedGroupId = ConvertTo-PowerBiPathSegment -Name 'GroupId' -Value $GroupId
|
|
129
|
+
$path = "groups/$encodedGroupId/scorecards"
|
|
130
|
+
if ($ScorecardId) {
|
|
131
|
+
$encodedScorecardId = ConvertTo-PowerBiPathSegment -Name 'ScorecardId' -Value $ScorecardId
|
|
132
|
+
$path = "$path($encodedScorecardId)"
|
|
133
|
+
}
|
|
134
|
+
if ($Suffix) {
|
|
135
|
+
$path = "$path/$Suffix"
|
|
136
|
+
}
|
|
137
|
+
return $path
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function Invoke-PowerBiRest {
|
|
141
|
+
param(
|
|
142
|
+
[Parameter(Mandatory = $true)]
|
|
143
|
+
[ValidateSet('GET', 'POST', 'PATCH', 'DELETE')]
|
|
144
|
+
[string] $Method,
|
|
145
|
+
|
|
146
|
+
[Parameter(Mandatory = $true)]
|
|
147
|
+
[string] $Path,
|
|
148
|
+
|
|
149
|
+
[object] $Body,
|
|
150
|
+
|
|
151
|
+
[string] $AccessToken,
|
|
152
|
+
|
|
153
|
+
[string] $BaseUri = 'https://api.powerbi.com/v1.0/myorg'
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
$uri = Resolve-PowerBiRestUri -BaseUri $BaseUri -Path $Path
|
|
157
|
+
$token = Get-PowerBiBearerToken -AccessToken $AccessToken
|
|
158
|
+
$headers = @{
|
|
159
|
+
Authorization = "Bearer $token"
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
$parameters = @{
|
|
163
|
+
Method = $Method
|
|
164
|
+
Uri = $uri
|
|
165
|
+
Headers = $headers
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if ($null -ne $Body) {
|
|
169
|
+
$parameters.ContentType = 'application/json'
|
|
170
|
+
$parameters.Body = ConvertTo-JsonBody -InputObject $Body
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
try {
|
|
174
|
+
$response = Invoke-RestMethod @parameters
|
|
175
|
+
}
|
|
176
|
+
catch {
|
|
177
|
+
# Map the common Power BI REST failures to an actionable message instead
|
|
178
|
+
# of surfacing a raw .NET HttpResponseException. Token expiry (401) is the
|
|
179
|
+
# routine case because az-CLI tokens expire in ~1 hour.
|
|
180
|
+
$status = $null
|
|
181
|
+
try { $status = [int]$_.Exception.Response.StatusCode } catch { }
|
|
182
|
+
$hint = switch ($status) {
|
|
183
|
+
401 { 'token missing/expired/invalid — re-run `az login` (az CLI tokens expire in ~1h) or refresh $env:POWERBI_ACCESS_TOKEN' }
|
|
184
|
+
403 { 'insufficient Power BI permissions for this workspace/scorecard' }
|
|
185
|
+
404 { 'workspace, scorecard, or goal not found — verify the GUID(s) in the request' }
|
|
186
|
+
429 { 'rate-limited by the Power BI API — wait a moment and retry' }
|
|
187
|
+
default { $_.Exception.Message }
|
|
188
|
+
}
|
|
189
|
+
$label = if ($status) { "HTTP $status" } else { 'request failed' }
|
|
190
|
+
[Console]::Error.WriteLine("Power BI REST $Method $uri : $label — $hint")
|
|
191
|
+
exit 1
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if ($null -ne $response) {
|
|
195
|
+
$response | ConvertTo-Json -Depth 100
|
|
196
|
+
}
|
|
197
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
param(
|
|
2
|
+
[Parameter(Mandatory = $true)]
|
|
3
|
+
[ValidateSet('List', 'Get', 'GetByReportId', 'Create', 'Update', 'Delete', 'MoveGoals')]
|
|
4
|
+
[string] $Action,
|
|
5
|
+
|
|
6
|
+
[Parameter(Mandatory = $true)]
|
|
7
|
+
[string] $GroupId,
|
|
8
|
+
|
|
9
|
+
[string] $ScorecardId,
|
|
10
|
+
[string] $ReportId,
|
|
11
|
+
[string] $BodyPath,
|
|
12
|
+
[string] $AccessToken,
|
|
13
|
+
[switch] $ConfirmWrite
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
. "$PSScriptRoot/powerbi-rest-common.ps1"
|
|
17
|
+
|
|
18
|
+
switch ($Action) {
|
|
19
|
+
'List' {
|
|
20
|
+
Invoke-PowerBiRest -Method GET -Path (New-PowerBiScorecardPath -GroupId $GroupId) -AccessToken $AccessToken
|
|
21
|
+
}
|
|
22
|
+
'Get' {
|
|
23
|
+
Assert-RequiredValue -Name 'ScorecardId' -Value $ScorecardId
|
|
24
|
+
Invoke-PowerBiRest -Method GET -Path (New-PowerBiScorecardPath -GroupId $GroupId -ScorecardId $ScorecardId) -AccessToken $AccessToken
|
|
25
|
+
}
|
|
26
|
+
'GetByReportId' {
|
|
27
|
+
$encodedGroupId = ConvertTo-PowerBiPathSegment -Name 'GroupId' -Value $GroupId
|
|
28
|
+
$encodedReportId = ConvertTo-PowerBiPathSegment -Name 'ReportId' -Value $ReportId
|
|
29
|
+
Invoke-PowerBiRest -Method GET -Path "groups/$encodedGroupId/scorecards/GetScorecardByReportId(reportId=$encodedReportId)" -AccessToken $AccessToken
|
|
30
|
+
}
|
|
31
|
+
'Create' {
|
|
32
|
+
Assert-ConfirmedWrite -Action $Action -ConfirmWrite:$ConfirmWrite
|
|
33
|
+
Assert-RequiredValue -Name 'BodyPath' -Value $BodyPath
|
|
34
|
+
Invoke-PowerBiRest -Method POST -Path (New-PowerBiScorecardPath -GroupId $GroupId) -Body (Read-JsonObject -Path $BodyPath) -AccessToken $AccessToken
|
|
35
|
+
}
|
|
36
|
+
'Update' {
|
|
37
|
+
Assert-ConfirmedWrite -Action $Action -ConfirmWrite:$ConfirmWrite
|
|
38
|
+
Assert-RequiredValue -Name 'ScorecardId' -Value $ScorecardId
|
|
39
|
+
Assert-RequiredValue -Name 'BodyPath' -Value $BodyPath
|
|
40
|
+
Invoke-PowerBiRest -Method PATCH -Path (New-PowerBiScorecardPath -GroupId $GroupId -ScorecardId $ScorecardId) -Body (Read-JsonObject -Path $BodyPath) -AccessToken $AccessToken
|
|
41
|
+
}
|
|
42
|
+
'Delete' {
|
|
43
|
+
Assert-ConfirmedWrite -Action $Action -ConfirmWrite:$ConfirmWrite
|
|
44
|
+
Assert-RequiredValue -Name 'ScorecardId' -Value $ScorecardId
|
|
45
|
+
Invoke-PowerBiRest -Method DELETE -Path (New-PowerBiScorecardPath -GroupId $GroupId -ScorecardId $ScorecardId) -AccessToken $AccessToken
|
|
46
|
+
}
|
|
47
|
+
'MoveGoals' {
|
|
48
|
+
Assert-ConfirmedWrite -Action $Action -ConfirmWrite:$ConfirmWrite
|
|
49
|
+
Assert-RequiredValue -Name 'ScorecardId' -Value $ScorecardId
|
|
50
|
+
Assert-RequiredValue -Name 'BodyPath' -Value $BodyPath
|
|
51
|
+
Invoke-PowerBiRest -Method POST -Path (New-PowerBiScorecardPath -GroupId $GroupId -ScorecardId $ScorecardId -Suffix 'MoveGoals()') -Body (Read-JsonObject -Path $BodyPath) -AccessToken $AccessToken
|
|
52
|
+
}
|
|
53
|
+
}
|