├── Azure-Function-Code └── ReportToken │ ├── host.json │ ├── Models │ ├── IndexConfig.cs │ ├── TileEmbedConfig.cs │ ├── ResultJson.cs │ └── EmbedConfig.cs │ ├── Services │ ├── IEmbedService.cs │ └── EmbedService.cs │ ├── local.settings.json │ ├── ReportToken.csproj │ ├── PowerBIEmbeddedToken.cs │ └── .gitignore ├── Images ├── AssociateCapacity.png ├── Create-Azure-AD-Tenent.png ├── CreatePowerBIEmbedded.png ├── FinalCreatePowerBIEmbedded.png └── Service-Principal-API-Permissions.png ├── PowerBI-Sample-Report └── US Sales Analysis.pbix ├── PowerBI-Embedded-JavaScript ├── User-Owns-Data │ ├── README.md │ └── power-bi-embedded-user-owns-data.html ├── index.html └── powerbi.min.js ├── PowerBI-Embedded-Sample.sln ├── .gitignore └── README.md /Azure-Function-Code/ReportToken/host.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0" 3 | } -------------------------------------------------------------------------------- /Images/AssociateCapacity.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AdamPaternostro/Azure-Power-BI-Embedded-Sample/HEAD/Images/AssociateCapacity.png -------------------------------------------------------------------------------- /Images/Create-Azure-AD-Tenent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AdamPaternostro/Azure-Power-BI-Embedded-Sample/HEAD/Images/Create-Azure-AD-Tenent.png -------------------------------------------------------------------------------- /Images/CreatePowerBIEmbedded.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AdamPaternostro/Azure-Power-BI-Embedded-Sample/HEAD/Images/CreatePowerBIEmbedded.png -------------------------------------------------------------------------------- /Images/FinalCreatePowerBIEmbedded.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AdamPaternostro/Azure-Power-BI-Embedded-Sample/HEAD/Images/FinalCreatePowerBIEmbedded.png -------------------------------------------------------------------------------- /Images/Service-Principal-API-Permissions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AdamPaternostro/Azure-Power-BI-Embedded-Sample/HEAD/Images/Service-Principal-API-Permissions.png -------------------------------------------------------------------------------- /PowerBI-Sample-Report/US Sales Analysis.pbix: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AdamPaternostro/Azure-Power-BI-Embedded-Sample/HEAD/PowerBI-Sample-Report/US Sales Analysis.pbix -------------------------------------------------------------------------------- /Azure-Function-Code/ReportToken/Models/IndexConfig.cs: -------------------------------------------------------------------------------- 1 | namespace ReportToken.Models 2 | { 3 | public class IndexConfig 4 | { 5 | public string DotNETSDK { get; internal set; } 6 | } 7 | } -------------------------------------------------------------------------------- /Azure-Function-Code/ReportToken/Models/TileEmbedConfig.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.PowerBI.Api.V2.Models; 2 | using System; 3 | 4 | namespace ReportToken.Models 5 | { 6 | public class TileEmbedConfig : EmbedConfig 7 | { 8 | public string dashboardId { get; set; } 9 | } 10 | } -------------------------------------------------------------------------------- /Azure-Function-Code/ReportToken/Models/ResultJson.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace ReportToken.Models 6 | { 7 | public class ResultJson 8 | { 9 | public string EmbedToken { get; set; } 10 | public string EmbedUrl { get; set; } 11 | public string ReportId { get; set; } 12 | 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Azure-Function-Code/ReportToken/Services/IEmbedService.cs: -------------------------------------------------------------------------------- 1 | using ReportToken.Models; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace ReportToken.Services 9 | { 10 | public interface IEmbedService 11 | { 12 | EmbedConfig EmbedConfig { get; } 13 | TileEmbedConfig TileEmbedConfig { get; } 14 | 15 | Task EmbedReport(string userName, string roles, string reportId); 16 | Task EmbedDashboard(); 17 | Task EmbedTile(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Azure-Function-Code/ReportToken/local.settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "IsEncrypted": false, 3 | "Values": { 4 | "AzureWebJobsStorage": "UseDevelopmentStorage=true", 5 | "FUNCTIONS_WORKER_RUNTIME": "dotnet", 6 | "AuthenticationType": "ServicePrincipal", 7 | "applicationId": "{{REPLACE-ME}}", 8 | "workspaceId": "{{REPLACE-ME}}", 9 | "authorityUrl": "https://login.microsoftonline.com/common/", 10 | "resourceUrl": "https://analysis.windows.net/powerbi/api", 11 | "apiUrl": "https://api.powerbi.com", 12 | "applicationSecret": "{{REPLACE-ME}}", 13 | "tenant": "{{REPLACE-ME}}", 14 | "pbiUsername": "Not-needed-we-are-using-a-service-principle.", 15 | "pbiPassword": "Not-needed-we-are-using-a-service-principle." 16 | } 17 | } -------------------------------------------------------------------------------- /Azure-Function-Code/ReportToken/ReportToken.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | netcoreapp2.1 4 | v2 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | PreserveNewest 14 | 15 | 16 | PreserveNewest 17 | Never 18 | 19 | 20 | -------------------------------------------------------------------------------- /Azure-Function-Code/ReportToken/Models/EmbedConfig.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.PowerBI.Api.V2.Models; 2 | using System; 3 | 4 | 5 | namespace ReportToken.Models 6 | { 7 | public class EmbedConfig 8 | { 9 | public string Id { get; set; } 10 | 11 | public string EmbedUrl { get; set; } 12 | 13 | public EmbedToken EmbedToken { get; set; } 14 | 15 | public int MinutesToExpiration 16 | { 17 | get 18 | { 19 | var minutesToExpiration = EmbedToken.Expiration.Value - DateTime.UtcNow; 20 | return (int)minutesToExpiration.TotalMinutes; 21 | } 22 | } 23 | 24 | public bool? IsEffectiveIdentityRolesRequired { get; set; } 25 | 26 | public bool? IsEffectiveIdentityRequired { get; set; } 27 | 28 | public bool EnableRLS { get; set; } 29 | 30 | public string Username { get; set; } 31 | 32 | public string Roles { get; set; } 33 | 34 | public string ErrorMessage { get; internal set; } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /PowerBI-Embedded-JavaScript/User-Owns-Data/README.md: -------------------------------------------------------------------------------- 1 | # This is a User Owns Data 2 | User owns data means we need a proper Azure AD account to login to Power BI from which we will get the User Id. 3 | 4 | To run this you will do the exact same steps as you did before, but when you need to register (or update_ your Azure AD Application (service principle) with a call back URL (http://localhost:13526/). 5 | 6 | To get an Azure AD token with the proper audience, you need to run this application: https://github.com/microsoft/PowerBI-Developer-Samples/tree/master/User%20Owns%20Data/integrate-web-app 7 | 8 | Use https://jwt.ms to view your token. Run Embed Report and put a break point to print out your access token: System.Diagnostics.Debug.WriteLine(accessToken.Value); 9 | "aud": "https://analysis.windows.net/powerbi/api" 10 | 11 | 12 | Once you have the proper token open the power-bi-embedded-user-owns-data.html and update the JavaScript: 13 | - accessToken 14 | - reportId 15 | - workSpaceId 16 | 17 | The JavaScript will make a REST API call to the PowerBI REST APL and get the embed URL for the report. 18 | 19 | The JavsScript will then run the report and embed into the page. 20 | 21 | The idea behind this is that your application will be authentication with Azure AD and then be showing reports. If you authenticate with another provider you should go with the App Owns Data model. 22 | -------------------------------------------------------------------------------- /PowerBI-Embedded-Sample.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29509.3 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReportToken", "Azure-Function-Code\ReportToken\ReportToken.csproj", "{9E6851EC-40BB-4725-A727-6BFDC3FAC151}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{E6550D2B-05D3-4E6F-98B7-986394639001}" 9 | ProjectSection(SolutionItems) = preProject 10 | README.md = README.md 11 | EndProjectSection 12 | EndProject 13 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "PowerBI-Embedded-JavaScript", "PowerBI-Embedded-JavaScript", "{F9E57E61-73EC-4032-9F91-D60327B32251}" 14 | ProjectSection(SolutionItems) = preProject 15 | PowerBI-Embedded-JavaScript\index.html = PowerBI-Embedded-JavaScript\index.html 16 | PowerBI-Embedded-JavaScript\powerbi.min.js = PowerBI-Embedded-JavaScript\powerbi.min.js 17 | EndProjectSection 18 | EndProject 19 | Global 20 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 21 | Debug|Any CPU = Debug|Any CPU 22 | Release|Any CPU = Release|Any CPU 23 | EndGlobalSection 24 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 25 | {9E6851EC-40BB-4725-A727-6BFDC3FAC151}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 26 | {9E6851EC-40BB-4725-A727-6BFDC3FAC151}.Debug|Any CPU.Build.0 = Debug|Any CPU 27 | {9E6851EC-40BB-4725-A727-6BFDC3FAC151}.Release|Any CPU.ActiveCfg = Release|Any CPU 28 | {9E6851EC-40BB-4725-A727-6BFDC3FAC151}.Release|Any CPU.Build.0 = Release|Any CPU 29 | EndGlobalSection 30 | GlobalSection(SolutionProperties) = preSolution 31 | HideSolutionNode = FALSE 32 | EndGlobalSection 33 | GlobalSection(ExtensibilityGlobals) = postSolution 34 | SolutionGuid = {A3113D75-B201-4031-98F0-55845D81F986} 35 | EndGlobalSection 36 | EndGlobal 37 | -------------------------------------------------------------------------------- /Azure-Function-Code/ReportToken/PowerBIEmbeddedToken.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Threading.Tasks; 4 | using Microsoft.AspNetCore.Mvc; 5 | using Microsoft.Azure.WebJobs; 6 | using Microsoft.Azure.WebJobs.Extensions.Http; 7 | using Microsoft.AspNetCore.Http; 8 | using Microsoft.Extensions.Logging; 9 | using Newtonsoft.Json; 10 | using ReportToken.Services; 11 | using ReportToken.Models; 12 | 13 | namespace ReportToken 14 | { 15 | public static class PowerBIEmbeddedToken 16 | { 17 | 18 | [FunctionName("PowerBIEmbeddedToken")] 19 | public static async Task Run( 20 | [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req, 21 | ILogger log) 22 | { 23 | try 24 | { 25 | log.LogInformation("Power BI Report Token Requested"); 26 | // string reportId = "0c94ccca-55f8-4cd8-95c4-2ce136ec5e22"; 27 | 28 | string reportId = req.Query["reportid"]; 29 | 30 | string requestBody = await new StreamReader(req.Body).ReadToEndAsync(); 31 | dynamic data = JsonConvert.DeserializeObject(requestBody); 32 | reportId = reportId ?? data?.reportId; 33 | 34 | log.LogInformation("reportId: " + reportId); 35 | 36 | if (!String.IsNullOrWhiteSpace(reportId)) 37 | { 38 | string username = null; 39 | string roles = null; 40 | 41 | 42 | IEmbedService m_embedService = new EmbedService(); 43 | var embedResult = await m_embedService.EmbedReport(username, roles, reportId); 44 | 45 | if (embedResult) 46 | { 47 | ResultJson resultJson = new ResultJson() 48 | { 49 | EmbedToken = m_embedService.EmbedConfig.EmbedToken.Token, 50 | EmbedUrl = m_embedService.EmbedConfig.EmbedUrl, 51 | ReportId = reportId 52 | }; 53 | 54 | string resultString = JsonConvert.SerializeObject(resultJson); 55 | 56 | return (ActionResult)new OkObjectResult(resultString); 57 | } 58 | else 59 | { 60 | return (ActionResult)new BadRequestObjectResult("Could not generate a token."); 61 | } 62 | } 63 | else 64 | { 65 | return (ActionResult)new BadRequestObjectResult("Report Id is empty or null."); 66 | } 67 | } 68 | catch (Exception ex) 69 | { 70 | log.LogInformation("Exception: " + ex.ToString()); 71 | return (ActionResult)new BadRequestObjectResult("An Exception has occurred."); 72 | } 73 | } // Run 74 | 75 | } // class 76 | 77 | } // namespace 78 | -------------------------------------------------------------------------------- /PowerBI-Embedded-JavaScript/User-Owns-Data/power-bi-embedded-user-owns-data.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Power BI - Embed Sample 8 | 9 | 10 | 11 |

Embedded Report (Pure JavaScript)

12 | 14 | 15 |

16 | 17 |

18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 27 | 28 | 29 | 31 | 32 | -------------------------------------------------------------------------------- /PowerBI-Embedded-JavaScript/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Power BI - Embed Sample 8 | 9 | 10 | 11 |

Embedded Report (Pure JavaScript)

12 |

13 | 15 |

16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 | 26 | 27 | 28 | 29 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /Azure-Function-Code/ReportToken/.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # Azure Functions localsettings file 5 | local.settings.json 6 | 7 | # User-specific files 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Build results 17 | [Dd]ebug/ 18 | [Dd]ebugPublic/ 19 | [Rr]elease/ 20 | [Rr]eleases/ 21 | x64/ 22 | x86/ 23 | bld/ 24 | [Bb]in/ 25 | [Oo]bj/ 26 | [Ll]og/ 27 | 28 | # Visual Studio 2015 cache/options directory 29 | .vs/ 30 | # Uncomment if you have tasks that create the project's static files in wwwroot 31 | #wwwroot/ 32 | 33 | # MSTest test Results 34 | [Tt]est[Rr]esult*/ 35 | [Bb]uild[Ll]og.* 36 | 37 | # NUNIT 38 | *.VisualState.xml 39 | TestResult.xml 40 | 41 | # Build Results of an ATL Project 42 | [Dd]ebugPS/ 43 | [Rr]eleasePS/ 44 | dlldata.c 45 | 46 | # DNX 47 | project.lock.json 48 | project.fragment.lock.json 49 | artifacts/ 50 | 51 | *_i.c 52 | *_p.c 53 | *_i.h 54 | *.ilk 55 | *.meta 56 | *.obj 57 | *.pch 58 | *.pdb 59 | *.pgc 60 | *.pgd 61 | *.rsp 62 | *.sbr 63 | *.tlb 64 | *.tli 65 | *.tlh 66 | *.tmp 67 | *.tmp_proj 68 | *.log 69 | *.vspscc 70 | *.vssscc 71 | .builds 72 | *.pidb 73 | *.svclog 74 | *.scc 75 | 76 | # Chutzpah Test files 77 | _Chutzpah* 78 | 79 | # Visual C++ cache files 80 | ipch/ 81 | *.aps 82 | *.ncb 83 | *.opendb 84 | *.opensdf 85 | *.sdf 86 | *.cachefile 87 | *.VC.db 88 | *.VC.VC.opendb 89 | 90 | # Visual Studio profiler 91 | *.psess 92 | *.vsp 93 | *.vspx 94 | *.sap 95 | 96 | # TFS 2012 Local Workspace 97 | $tf/ 98 | 99 | # Guidance Automation Toolkit 100 | *.gpState 101 | 102 | # ReSharper is a .NET coding add-in 103 | _ReSharper*/ 104 | *.[Rr]e[Ss]harper 105 | *.DotSettings.user 106 | 107 | # JustCode is a .NET coding add-in 108 | .JustCode 109 | 110 | # TeamCity is a build add-in 111 | _TeamCity* 112 | 113 | # DotCover is a Code Coverage Tool 114 | *.dotCover 115 | 116 | # NCrunch 117 | _NCrunch_* 118 | .*crunch*.local.xml 119 | nCrunchTemp_* 120 | 121 | # MightyMoose 122 | *.mm.* 123 | AutoTest.Net/ 124 | 125 | # Web workbench (sass) 126 | .sass-cache/ 127 | 128 | # Installshield output folder 129 | [Ee]xpress/ 130 | 131 | # DocProject is a documentation generator add-in 132 | DocProject/buildhelp/ 133 | DocProject/Help/*.HxT 134 | DocProject/Help/*.HxC 135 | DocProject/Help/*.hhc 136 | DocProject/Help/*.hhk 137 | DocProject/Help/*.hhp 138 | DocProject/Help/Html2 139 | DocProject/Help/html 140 | 141 | # Click-Once directory 142 | publish/ 143 | 144 | # Publish Web Output 145 | *.[Pp]ublish.xml 146 | *.azurePubxml 147 | # TODO: Comment the next line if you want to checkin your web deploy settings 148 | # but database connection strings (with potential passwords) will be unencrypted 149 | #*.pubxml 150 | *.publishproj 151 | 152 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 153 | # checkin your Azure Web App publish settings, but sensitive information contained 154 | # in these scripts will be unencrypted 155 | PublishScripts/ 156 | 157 | # NuGet Packages 158 | *.nupkg 159 | # The packages folder can be ignored because of Package Restore 160 | **/packages/* 161 | # except build/, which is used as an MSBuild target. 162 | !**/packages/build/ 163 | # Uncomment if necessary however generally it will be regenerated when needed 164 | #!**/packages/repositories.config 165 | # NuGet v3's project.json files produces more ignoreable files 166 | *.nuget.props 167 | *.nuget.targets 168 | 169 | # Microsoft Azure Build Output 170 | csx/ 171 | *.build.csdef 172 | 173 | # Microsoft Azure Emulator 174 | ecf/ 175 | rcf/ 176 | 177 | # Windows Store app package directories and files 178 | AppPackages/ 179 | BundleArtifacts/ 180 | Package.StoreAssociation.xml 181 | _pkginfo.txt 182 | 183 | # Visual Studio cache files 184 | # files ending in .cache can be ignored 185 | *.[Cc]ache 186 | # but keep track of directories ending in .cache 187 | !*.[Cc]ache/ 188 | 189 | # Others 190 | ClientBin/ 191 | ~$* 192 | *~ 193 | *.dbmdl 194 | *.dbproj.schemaview 195 | *.jfm 196 | *.pfx 197 | *.publishsettings 198 | node_modules/ 199 | orleans.codegen.cs 200 | 201 | # Since there are multiple workflows, uncomment next line to ignore bower_components 202 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 203 | #bower_components/ 204 | 205 | # RIA/Silverlight projects 206 | Generated_Code/ 207 | 208 | # Backup & report files from converting an old project file 209 | # to a newer Visual Studio version. Backup files are not needed, 210 | # because we have git ;-) 211 | _UpgradeReport_Files/ 212 | Backup*/ 213 | UpgradeLog*.XML 214 | UpgradeLog*.htm 215 | 216 | # SQL Server files 217 | *.mdf 218 | *.ldf 219 | 220 | # Business Intelligence projects 221 | *.rdl.data 222 | *.bim.layout 223 | *.bim_*.settings 224 | 225 | # Microsoft Fakes 226 | FakesAssemblies/ 227 | 228 | # GhostDoc plugin setting file 229 | *.GhostDoc.xml 230 | 231 | # Node.js Tools for Visual Studio 232 | .ntvs_analysis.dat 233 | 234 | # Visual Studio 6 build log 235 | *.plg 236 | 237 | # Visual Studio 6 workspace options file 238 | *.opt 239 | 240 | # Visual Studio LightSwitch build output 241 | **/*.HTMLClient/GeneratedArtifacts 242 | **/*.DesktopClient/GeneratedArtifacts 243 | **/*.DesktopClient/ModelManifest.xml 244 | **/*.Server/GeneratedArtifacts 245 | **/*.Server/ModelManifest.xml 246 | _Pvt_Extensions 247 | 248 | # Paket dependency manager 249 | .paket/paket.exe 250 | paket-files/ 251 | 252 | # FAKE - F# Make 253 | .fake/ 254 | 255 | # JetBrains Rider 256 | .idea/ 257 | *.sln.iml 258 | 259 | # CodeRush 260 | .cr/ 261 | 262 | # Python Tools for Visual Studio (PTVS) 263 | __pycache__/ 264 | *.pyc -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Aa][Rr][Mm]/ 27 | [Aa][Rr][Mm]64/ 28 | bld/ 29 | [Bb]in/ 30 | [Oo]bj/ 31 | [Ll]og/ 32 | [Ll]ogs/ 33 | 34 | # Visual Studio 2015/2017 cache/options directory 35 | .vs/ 36 | # Uncomment if you have tasks that create the project's static files in wwwroot 37 | #wwwroot/ 38 | 39 | # Visual Studio 2017 auto generated files 40 | Generated\ Files/ 41 | 42 | # MSTest test Results 43 | [Tt]est[Rr]esult*/ 44 | [Bb]uild[Ll]og.* 45 | 46 | # NUnit 47 | *.VisualState.xml 48 | TestResult.xml 49 | nunit-*.xml 50 | 51 | # Build Results of an ATL Project 52 | [Dd]ebugPS/ 53 | [Rr]eleasePS/ 54 | dlldata.c 55 | 56 | # Benchmark Results 57 | BenchmarkDotNet.Artifacts/ 58 | 59 | # .NET Core 60 | project.lock.json 61 | project.fragment.lock.json 62 | artifacts/ 63 | 64 | # StyleCop 65 | StyleCopReport.xml 66 | 67 | # Files built by Visual Studio 68 | *_i.c 69 | *_p.c 70 | *_h.h 71 | *.ilk 72 | *.meta 73 | *.obj 74 | *.iobj 75 | *.pch 76 | *.pdb 77 | *.ipdb 78 | *.pgc 79 | *.pgd 80 | *.rsp 81 | *.sbr 82 | *.tlb 83 | *.tli 84 | *.tlh 85 | *.tmp 86 | *.tmp_proj 87 | *_wpftmp.csproj 88 | *.log 89 | *.vspscc 90 | *.vssscc 91 | .builds 92 | *.pidb 93 | *.svclog 94 | *.scc 95 | 96 | # Chutzpah Test files 97 | _Chutzpah* 98 | 99 | # Visual C++ cache files 100 | ipch/ 101 | *.aps 102 | *.ncb 103 | *.opendb 104 | *.opensdf 105 | *.sdf 106 | *.cachefile 107 | *.VC.db 108 | *.VC.VC.opendb 109 | 110 | # Visual Studio profiler 111 | *.psess 112 | *.vsp 113 | *.vspx 114 | *.sap 115 | 116 | # Visual Studio Trace Files 117 | *.e2e 118 | 119 | # TFS 2012 Local Workspace 120 | $tf/ 121 | 122 | # Guidance Automation Toolkit 123 | *.gpState 124 | 125 | # ReSharper is a .NET coding add-in 126 | _ReSharper*/ 127 | *.[Rr]e[Ss]harper 128 | *.DotSettings.user 129 | 130 | # TeamCity is a build add-in 131 | _TeamCity* 132 | 133 | # DotCover is a Code Coverage Tool 134 | *.dotCover 135 | 136 | # AxoCover is a Code Coverage Tool 137 | .axoCover/* 138 | !.axoCover/settings.json 139 | 140 | # Visual Studio code coverage results 141 | *.coverage 142 | *.coveragexml 143 | 144 | # NCrunch 145 | _NCrunch_* 146 | .*crunch*.local.xml 147 | nCrunchTemp_* 148 | 149 | # MightyMoose 150 | *.mm.* 151 | AutoTest.Net/ 152 | 153 | # Web workbench (sass) 154 | .sass-cache/ 155 | 156 | # Installshield output folder 157 | [Ee]xpress/ 158 | 159 | # DocProject is a documentation generator add-in 160 | DocProject/buildhelp/ 161 | DocProject/Help/*.HxT 162 | DocProject/Help/*.HxC 163 | DocProject/Help/*.hhc 164 | DocProject/Help/*.hhk 165 | DocProject/Help/*.hhp 166 | DocProject/Help/Html2 167 | DocProject/Help/html 168 | 169 | # Click-Once directory 170 | publish/ 171 | 172 | # Publish Web Output 173 | *.[Pp]ublish.xml 174 | *.azurePubxml 175 | # Note: Comment the next line if you want to checkin your web deploy settings, 176 | # but database connection strings (with potential passwords) will be unencrypted 177 | *.pubxml 178 | *.publishproj 179 | 180 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 181 | # checkin your Azure Web App publish settings, but sensitive information contained 182 | # in these scripts will be unencrypted 183 | PublishScripts/ 184 | 185 | # NuGet Packages 186 | *.nupkg 187 | # NuGet Symbol Packages 188 | *.snupkg 189 | # The packages folder can be ignored because of Package Restore 190 | **/[Pp]ackages/* 191 | # except build/, which is used as an MSBuild target. 192 | !**/[Pp]ackages/build/ 193 | # Uncomment if necessary however generally it will be regenerated when needed 194 | #!**/[Pp]ackages/repositories.config 195 | # NuGet v3's project.json files produces more ignorable files 196 | *.nuget.props 197 | *.nuget.targets 198 | 199 | # Microsoft Azure Build Output 200 | csx/ 201 | *.build.csdef 202 | 203 | # Microsoft Azure Emulator 204 | ecf/ 205 | rcf/ 206 | 207 | # Windows Store app package directories and files 208 | AppPackages/ 209 | BundleArtifacts/ 210 | Package.StoreAssociation.xml 211 | _pkginfo.txt 212 | *.appx 213 | *.appxbundle 214 | *.appxupload 215 | 216 | # Visual Studio cache files 217 | # files ending in .cache can be ignored 218 | *.[Cc]ache 219 | # but keep track of directories ending in .cache 220 | !?*.[Cc]ache/ 221 | 222 | # Others 223 | ClientBin/ 224 | ~$* 225 | *~ 226 | *.dbmdl 227 | *.dbproj.schemaview 228 | *.jfm 229 | *.pfx 230 | *.publishsettings 231 | orleans.codegen.cs 232 | 233 | # Including strong name files can present a security risk 234 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 235 | #*.snk 236 | 237 | # Since there are multiple workflows, uncomment next line to ignore bower_components 238 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 239 | #bower_components/ 240 | 241 | # RIA/Silverlight projects 242 | Generated_Code/ 243 | 244 | # Backup & report files from converting an old project file 245 | # to a newer Visual Studio version. Backup files are not needed, 246 | # because we have git ;-) 247 | _UpgradeReport_Files/ 248 | Backup*/ 249 | UpgradeLog*.XML 250 | UpgradeLog*.htm 251 | ServiceFabricBackup/ 252 | *.rptproj.bak 253 | 254 | # SQL Server files 255 | *.mdf 256 | *.ldf 257 | *.ndf 258 | 259 | # Business Intelligence projects 260 | *.rdl.data 261 | *.bim.layout 262 | *.bim_*.settings 263 | *.rptproj.rsuser 264 | *- [Bb]ackup.rdl 265 | *- [Bb]ackup ([0-9]).rdl 266 | *- [Bb]ackup ([0-9][0-9]).rdl 267 | 268 | # Microsoft Fakes 269 | FakesAssemblies/ 270 | 271 | # GhostDoc plugin setting file 272 | *.GhostDoc.xml 273 | 274 | # Node.js Tools for Visual Studio 275 | .ntvs_analysis.dat 276 | node_modules/ 277 | 278 | # Visual Studio 6 build log 279 | *.plg 280 | 281 | # Visual Studio 6 workspace options file 282 | *.opt 283 | 284 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 285 | *.vbw 286 | 287 | # Visual Studio LightSwitch build output 288 | **/*.HTMLClient/GeneratedArtifacts 289 | **/*.DesktopClient/GeneratedArtifacts 290 | **/*.DesktopClient/ModelManifest.xml 291 | **/*.Server/GeneratedArtifacts 292 | **/*.Server/ModelManifest.xml 293 | _Pvt_Extensions 294 | 295 | # Paket dependency manager 296 | .paket/paket.exe 297 | paket-files/ 298 | 299 | # FAKE - F# Make 300 | .fake/ 301 | 302 | # CodeRush personal settings 303 | .cr/personal 304 | 305 | # Python Tools for Visual Studio (PTVS) 306 | __pycache__/ 307 | *.pyc 308 | 309 | # Cake - Uncomment if you are using it 310 | # tools/** 311 | # !tools/packages.config 312 | 313 | # Tabs Studio 314 | *.tss 315 | 316 | # Telerik's JustMock configuration file 317 | *.jmconfig 318 | 319 | # BizTalk build output 320 | *.btp.cs 321 | *.btm.cs 322 | *.odx.cs 323 | *.xsd.cs 324 | 325 | # OpenCover UI analysis results 326 | OpenCover/ 327 | 328 | # Azure Stream Analytics local run output 329 | ASALocalRun/ 330 | 331 | # MSBuild Binary and Structured Log 332 | *.binlog 333 | 334 | # NVidia Nsight GPU debugger configuration file 335 | *.nvuser 336 | 337 | # MFractors (Xamarin productivity tool) working folder 338 | .mfractor/ 339 | 340 | # Local History for Visual Studio 341 | .localhistory/ 342 | 343 | # BeatPulse healthcheck temp database 344 | healthchecksdb 345 | 346 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 347 | MigrationBackup/ 348 | 349 | # Ionide (cross platform F# VS Code tools) working folder 350 | .ionide/ 351 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Configure Power BI Embedded and call from JavaScript 2 | This GitHub repository is designed to help you setup and configure Power BI Embedded in your Azure subscription. 3 | The process of setting up Power BI Embedded can be confusing since it requires configuring several resource correctly 4 | (e.g. Azure Service Principal, Azure Security, Power BI, creating Embedded capacity, etc.) and you must tie them together correctly. 5 | The below steps will walk you through the entire process. I recorded a video to show you how to perform the process. 6 | 7 | Power BI Embedded is a great tool, but most report developers have issues when setting up and configuring Power BI Embedded since it requires help from IT. 8 | 9 | 10 | This will walk you through each and every step. 11 | 12 | The goal of this is: 13 | 1. Configure the Azure resources 14 | 2. Configure the Power BI resources 15 | 3. Deploy a report and test it using a simple HTML page with some JavaScript 16 | 4. You should then be able to embeded any report in any application 17 | 18 | 19 | ## Detail Steps 20 | This process will walk through the following 21 | - Create an Azure tenant. This step can be skipped unless you are doing a test configuration (like I performed in this sample). I show it since some users might want to test in an Azure subscription where they are not an Admin. 22 | - Create an Azure Service Principal. A Service Principal is analogous to a user. Service Principals should be used for automated processes in Azure and in this case we are using a service principal as the "unattended user" who will run the embedded reports. 23 | - Create a Power BI Account. You can use a free trial account for Power BI if you do not own a license. If you need a licence you need to contact your Office 365 admin (someone in your organization) and they can assign you a license. 24 | - Purchase a license: https://docs.microsoft.com/en-us/power-bi/service-admin-purchasing-power-bi-pro 25 | - Create a Power BI Workspace. This is where we will deploy your reports. 26 | - Configure Power BI to use the service principal created above 27 | - Deploy a sample report 28 | - Walk through the C# code in the PowerBI-Developer-Samples sample project provided by Microsoft and explain each element used in embedded (e.g. report token, report url and report id). 29 | - Deploy an Azure Function which will run the C# code from the PowerBI-Developer-Samples and return back a report token, url and id. The Azure Function means we can then call this from any system, web page or JavaScript code and have our reports easily embedded into any application. You do not want to author this code everytime you want to quickly embed a report. Embedding should take 2 minutes. 30 | - Create a simple HTML page with minimal JavaScript to show you how to embed a report. This allows you to the minimal code required to embed a report on a web page or single page application. 31 | 32 | #### Notes 33 | - I will not use the Power BI online wizard (https://app.powerbi.com/embedsetup/appownsdata) to create the Power BI setup. 34 | - Sometimes the wizard does not work due to how companies have configured their Azure Subscription. If you use the wizard, you must use it as a Global Azure Admin and that Admin must have a Power BI Pro account and they must have logged into https://app.powerbi.com/ before using the wizard. You also must go generate a key by hand. 35 | - This is for an App Owns Data example. This is typically used for deploying reports to external users. If you want to see an User Owns Data example please click [here](./PowerBI-Embedded-JavaScript/User-Owns-Data/README.md) 36 | 37 | ## What you will need 38 | - An Azure Subscription (you can get a free one for testing) 39 | - A Power BI Pro license (you can create free account for testing) 40 | - You will need to be a global Azure Admin or have an Admin that can help you through the process. The Admin should also be a Power BI Admin. Go find this person in your company and make friends with them. You should watch and understand the video and then work with them to setup the Azure and Power BI resources. You will need about 30 minutes of their time. 41 | - You will need to install on your machine (make sure you can install items on your machine) 42 | - Visual Studio Community (or higher edition): https://visualstudio.microsoft.com/vs/community/ 43 | - Azure Function local development tools (require Node.js to be installed). Details are below. 44 | - A resource group in Azure that you can deploy to. In an enterprise, typically an Admin will create the resource group and grant your Microsoft account Contributor access to the resource group. This is where we will create the Power BI capacity and Azure Function App. 45 | 46 | 47 | ## YouTube Video 48 | - https://youtu.be/FZjQmvwBAdU 49 | 50 | 51 | ## Optional: Create a new Azure tenant (Requires Azure AD Admin) 52 | You can skip these steps if you are doing this in your company's Azure subscription. Since this is a test I will show you in a test tenant. I am not a Global Azure AD admin at Microsoft so I use a test tenant to perform Power BI Embedded work. 53 | 1. Open the Azure Portal https://portal.azure.com 54 | 2. Click the menu in the top left and select Create a Resource 55 | 3. Search for Azure Active Directory 56 | 4. Click Create 57 | 5. Enter: 58 | - Organization name: Paternostro Embedded Test 59 | - Initial Domain Name: paternostroembeddedtest 60 | 6. Click Create (and wait) 61 | 62 | ## Optional: Create a user (Requires Azure AD Admin). 63 | You can skip this step if you did not perform the step above since you will use your real email (or Azure account) as the user. 64 | 1. Click on Manage new Directory 65 | 2. Click on Users 66 | 3. Click New User (e.g. adampaternostro@adamembeddedtenant.onmicrosoft.com) 67 | 4. Enter their information 68 | - Set their Role to Global Admin 69 | 70 | ## Create a Service Principle (Requires Azure AD Admin) 71 | 1. Go to Azure Active Directory 72 | 2. Create a new service principal 73 | - App Registrations 74 | - New Registration 75 | - Call it PowerBIEmbeddedSP 76 | - Web | https://PowerBIEmbeddedSP 77 | 4. Grant Permissions for the Service Principle to PowerBI 78 | - Click on API Permissions 79 | - Click on Add a Permission 80 | - Click on PowerBI Service 81 | - Click on Delegated Permissions 82 | - App.Read.All 83 | - Capacity.Read.All 84 | - Capacity.ReadWrite.All 85 | - Content.Create 86 | - Dashboard.Read.All 87 | - Dashboard.ReadWrite.All 88 | - Dataflow.Read.All 89 | - Dataflow.ReadWrite.All 90 | - Dataset.Read.All 91 | - Dataset.ReadWrite.All 92 | - Gateway.Read.All 93 | - Gateway.ReadWrite.All 94 | - Report.Read.All 95 | - Report.ReadWrite.All 96 | - StorageAccount.Read.All 97 | - StorageAccount.ReadWrite.All 98 | - Workspace.Read.All 99 | - Workspace.ReadWrite.All 100 | - Click on Add Permissions 101 | 102 | 103 | ## Create a Security Group (Requires Azure AD Admin) 104 | 1. Go to Azure Active Directory 105 | 2. Click on Groups 106 | 3. Create a new Group 107 | - Group Type: Security 108 | - Group Name: PowerBIEmbeddedGroup 109 | - Members: Add PowerBIEmbeddedSP 110 | - Click Create 111 | 112 | 113 | ## Create Power BI Account 114 | If you have a license you can skip this step 115 | 1. Login to https://app.powerbi.com/ 116 | 2. Click on Workspaces 117 | 3. Click Create a Workspace 118 | 4. Click Free Trial 119 | 120 | 121 | ## Configure Power BI to use Service Pricipal (Requires Azure AD Admin) 122 | 1. Login to https://app.powerbi.com/ 123 | 2. Click the gear icon on the top right 124 | 3. Click Admin portal 125 | - Click Tenant Settings 126 | - Scroll to "Allow Service principals to use Power BI APIs" 127 | - Click Enabled 128 | - Click "Specific Security Groups" 129 | - Add PowerBIEmbeddedGroup 130 | - Click Apply 131 | 132 | 133 | ## Create Power BI Workspace 134 | 1. Login to https://app.powerbi.com/ 135 | 2. Create a workspace 136 | - Click on Workspaces 137 | - Click Create a Workspace 138 | - Name it: EmbeddedReports 139 | - Click Save 140 | 3. Add security to the workspace 141 | - Click on Workspaces 142 | - Click on the "..." of the EmbeddedReport workspace 143 | - Select Workspace Access 144 | - Add PowerBIEmbeddedSP as an Admin 145 | - Click Add 146 | 147 | 148 | ## Create Sample Report 149 | 1. Click on Workspaces 150 | 2. Click on EmbeddedReports 151 | 3. Click Create | DataSets 152 | 4. Click Files 153 | 5. Click Samples 154 | 6. Click IT Spend Sample 155 | 7. Copy the Workspace ID and Report ID from the URL 156 | 157 | 158 | ## Run Sample Report using the Power BI Sample Application 159 | 1. Download sample from here (Zip file) https://github.com/Microsoft/PowerBI-Developer-Samples 160 | 2. Open in Visual Studio 161 | 3. Unblock Zip 162 | 4. Unzip the file 163 | 5. Go into AppOwnsData folder 164 | 6. Restore NuGet 165 | 7. Rebuild 166 | 8. Update web.config (set these values) 167 | ``` 168 | 169 | 170 | 171 | 172 | 173 | 174 | ``` 175 | 9. Run it and click on Embed Report 176 | 177 | 178 | ## Run Azure Function App 179 | 1. Make sure you have the Azure Function Tools installed 180 | - https://docs.microsoft.com/en-us/azure/azure-functions/functions-run-local 181 | - You will need Node.js installed and then install a Node package 182 | 2. Open PowerBI-Embedded-Sample.sln 183 | 3. Open local.settings.json and replace 184 | - applicationId 185 | - workspaceId 186 | - applicationSecret 187 | - tenant 188 | 4. Run the applicatoin 189 | 5. Copy the URL 190 | 6. Pass in the reportId to the URL 191 | - e.g. http://localhost:7071/api/PowerBIEmbeddedToken?reportId=123f9776-bd48-43e0-802a-0162359e1cfb 192 | 193 | 194 | ## Create a Function App in Azure 195 | 1. Open https://portal.azure.com 196 | 2. Create a Resource Group 197 | 3. Create a Function App 198 | - Name it what you like 199 | - Runtime Stack: .NET Core 200 | - Click Review and Create 201 | 202 | 203 | ## Publish Function App 204 | 1. Open Visual Studio 205 | 2. Open PowerBI-Embedded-Sample.sln 206 | 3. Right click on ReportToken 207 | 4. Click on Publish 208 | 5. In Azure Portal 209 | 6. Click on Function App 210 | 7. Click on Configuration 211 | 8. Add each of the values from the local.settings.json 212 | 213 | 214 | ## Run Function App 215 | 1. Click on the Function App in Azure 216 | 2. Click the Run button 217 | 3. In the test window add a Parmeter 218 | - reportId and your Power BI Report Id (Guid) 219 | 220 | 221 | ## Run a Web Page (basic JavaScript) to embed a Power BI report 222 | 1. Go to the Resource Group your Function App 223 | 2. Click on the storage account 224 | 3. Click on Containers 225 | 4. Create new Container (name it "powerbi") 226 | 5. Click on the Container 227 | 6. Upload the powerbi.min.js 228 | 7. Click Generate SAS token 229 | - Set the Start Date in the past 230 | - Set the Expiry Date in the future 231 | - Copy the Blob SAS token 232 | 8. Back in Visual Studio 233 | - Open the folder "PowerBI-Embedded-JavaScript" 234 | - Open index.html 235 | - Paste he SAS Token on line 28 236 | - Set the Function Name on line 34 237 | - Set the Function Code on line 35 238 | - Set the Report Id on line 14 239 | 9. Back in the Azure Portal 240 | - Upload the index.html to the same storage account and container 241 | - Generate a SAS token 242 | - Paste the SAS token in a browser (you might need to wait a minute for the SAS token to work) 243 | - Click the "Click to Run Report" button 244 | 10. Copy the storage account name 245 | - e.g. https://storageaccountadamp9397.blob.core.windows.net 246 | 11. Go back to your Function App 247 | - Click on Platform Features 248 | - Click on CORS 249 | - Add your storage account (e.g. https://storageaccountadamp9397.blob.core.windows.net) 250 | - Click Save 251 | 12. Rerun the index.html report in your browser 252 | 253 | 254 | # Create the Power BI Embedded Capacity 255 | Currently, you have been testing using Power BI resources. In order to distribute reports using Power BI embedded you must use your Premium Capacity or create Embedded capacity to ensure you in compliance with licensing. 256 | 1. Open the Azure Portal 257 | 2. Create a new resource Power BI Embedded 258 | 259 | ![alt tag](https://raw.githubusercontent.com/AdamPaternostro/Azure-Power-BI-Embedded-Sample/master/Images/CreatePowerBIEmbedded.png) 260 | 261 | ![alt tag](https://raw.githubusercontent.com/AdamPaternostro/Azure-Power-BI-Embedded-Sample/master/Images/FinalCreatePowerBIEmbedded.png) 262 | 263 | 3. Open https://app.powerbi.com 264 | 4. Click on Workspaces 265 | 5. On your workspaces click the "..." and select Workspace settings 266 | 6. Click on Premium 267 | 7. Assoicate your capacity 268 | 269 | ![alt tag](https://raw.githubusercontent.com/AdamPaternostro/Azure-Power-BI-Embedded-Sample/master/Images/AssociateCapacity.png) 270 | 271 | 8. In the Azure Portal you can pause/un-pause your Power BI Embedded Capacity for your development and QA testing. 272 | 273 | # Securing your Application 274 | - If you notice the index.html page has the Azure Function Key placed in the JavaScript. You should protect this Key and only place the key in pages that are secure (meaning the user went through a login page). 275 | - If there is no login page, then you should create a second Azure Function called RunReport"ABC" and have RunReport"ABC" function call the Power BI Function App which can protect pass the Power BI Function App key and the report id. 276 | - Even if there is a login page and you share this Power BI workspace with other reports that have sensitive data you should be aware a rogue user could start calling your Function App and passing in every Guid in existance (it will take them a long time). 277 | - My perferred option is to add a parameter to the Power BI Function App. 278 | - Option 1: The user id is securely passed and the user is verified having access to the report. 279 | - Option 2: Add a JWT token. A JWT is a signed token and the Function App would verify it was signed/generated by your organization. The token could contain the report id value (or other elements) and as long as the token is verified that it was not tampered with you would run the report (provided the user has access to the requested report). Now you do not need to worry about someone trying to guess report ids or trying to access reports they do not have access. 280 | 281 | 282 | # Links 283 | - Playground: https://microsoft.github.io/PowerBI-JavaScript/demo/v2-demo/index.html 284 | - Start / Stop: https://docs.microsoft.com/en-us/power-bi/developer/azure-pbie-pause-start. You could author a Azure Function or Azure Automation to schedule a suspend and resume of your Embedded capacity. 285 | - https://docs.microsoft.com/en-us/rest/api/power-bi-embedded/capacities/suspend 286 | - https://docs.microsoft.com/en-us/rest/api/power-bi-embedded/capacities/resume 287 | - Sample: https://docs.microsoft.com/en-us/power-bi/developer/embed-sample-for-customers 288 | - https://github.com/Microsoft/PowerBI-JavaScript/wiki/Embedding-Basics 289 | 290 | 291 | 292 | -------------------------------------------------------------------------------- /Azure-Function-Code/ReportToken/Services/EmbedService.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.IdentityModel.Clients.ActiveDirectory; 2 | using Microsoft.PowerBI.Api.V2; 3 | using Microsoft.PowerBI.Api.V2.Models; 4 | using Microsoft.Rest; 5 | using ReportToken.Models; 6 | using System; 7 | using System.Collections.Generic; 8 | using System.Collections.Specialized; 9 | using System.Configuration; 10 | using System.Linq; 11 | using System.Threading.Tasks; 12 | 13 | 14 | namespace ReportToken.Services 15 | { 16 | public class EmbedService : IEmbedService 17 | { 18 | private static readonly string AuthorityUrl = System.Environment.GetEnvironmentVariable("authorityUrl"); 19 | private static readonly string ResourceUrl = System.Environment.GetEnvironmentVariable("resourceUrl"); 20 | private static readonly string ApplicationId = System.Environment.GetEnvironmentVariable("applicationId"); 21 | private static readonly string ApiUrl = System.Environment.GetEnvironmentVariable("apiUrl"); 22 | private static readonly string WorkspaceId = System.Environment.GetEnvironmentVariable("workspaceId"); 23 | // private static readonly string ReportId = System.Environment.GetEnvironmentVariable("reportId"); 24 | 25 | private static readonly string AuthenticationType = System.Environment.GetEnvironmentVariable("AuthenticationType"); 26 | private static readonly string ApplicationSecret = System.Environment.GetEnvironmentVariable("applicationSecret"); 27 | private static readonly string Tenant = System.Environment.GetEnvironmentVariable("tenant"); 28 | private static readonly string Username = System.Environment.GetEnvironmentVariable("pbiUsername"); 29 | private static readonly string Password = System.Environment.GetEnvironmentVariable("pbiPassword"); 30 | 31 | public EmbedConfig EmbedConfig 32 | { 33 | get { return m_embedConfig; } 34 | } 35 | 36 | public TileEmbedConfig TileEmbedConfig 37 | { 38 | get { return m_tileEmbedConfig; } 39 | } 40 | 41 | private EmbedConfig m_embedConfig; 42 | private TileEmbedConfig m_tileEmbedConfig; 43 | private TokenCredentials m_tokenCredentials; 44 | 45 | public EmbedService() 46 | { 47 | m_tokenCredentials = null; 48 | m_embedConfig = new EmbedConfig(); 49 | m_tileEmbedConfig = new TileEmbedConfig(); 50 | } 51 | 52 | public async Task EmbedReport(string username, string roles, string reportId) 53 | { 54 | 55 | // Get token credentials for user 56 | var getCredentialsResult = await GetTokenCredentials(); 57 | if (!getCredentialsResult) 58 | { 59 | // The error message set in GetTokenCredentials 60 | return false; 61 | } 62 | 63 | try 64 | { 65 | // Create a Power BI Client object. It will be used to call Power BI APIs. 66 | using (var client = new PowerBIClient(new Uri(ApiUrl), m_tokenCredentials)) 67 | { 68 | // Get a list of reports. 69 | var reports = await client.Reports.GetReportsInGroupAsync(WorkspaceId); 70 | 71 | // No reports retrieved for the given workspace. 72 | if (reports.Value.Count() == 0) 73 | { 74 | m_embedConfig.ErrorMessage = "No reports were found in the workspace"; 75 | return false; 76 | } 77 | 78 | Report report; 79 | if (string.IsNullOrWhiteSpace(reportId)) 80 | { 81 | // Get the first report in the workspace. 82 | report = reports.Value.FirstOrDefault(); 83 | } 84 | else 85 | { 86 | report = reports.Value.FirstOrDefault(r => r.Id.Equals(reportId, StringComparison.InvariantCultureIgnoreCase)); 87 | } 88 | 89 | if (report == null) 90 | { 91 | m_embedConfig.ErrorMessage = "No report with the given ID was found in the workspace. Make sure ReportId is valid."; 92 | return false; 93 | } 94 | 95 | var datasets = await client.Datasets.GetDatasetByIdInGroupAsync(WorkspaceId, report.DatasetId); 96 | m_embedConfig.IsEffectiveIdentityRequired = datasets.IsEffectiveIdentityRequired; 97 | m_embedConfig.IsEffectiveIdentityRolesRequired = datasets.IsEffectiveIdentityRolesRequired; 98 | GenerateTokenRequest generateTokenRequestParameters; 99 | // This is how you create embed token with effective identities 100 | if (!string.IsNullOrWhiteSpace(username)) 101 | { 102 | var rls = new EffectiveIdentity(username, new List { report.DatasetId }); 103 | if (!string.IsNullOrWhiteSpace(roles)) 104 | { 105 | var rolesList = new List(); 106 | rolesList.AddRange(roles.Split(',')); 107 | rls.Roles = rolesList; 108 | } 109 | // Generate Embed Token with effective identities. 110 | generateTokenRequestParameters = new GenerateTokenRequest(accessLevel: "view", identities: new List { rls }); 111 | } 112 | else 113 | { 114 | // Generate Embed Token for reports without effective identities. 115 | generateTokenRequestParameters = new GenerateTokenRequest(accessLevel: "view"); 116 | } 117 | 118 | var tokenResponse = await client.Reports.GenerateTokenInGroupAsync(WorkspaceId, report.Id, generateTokenRequestParameters); 119 | 120 | if (tokenResponse == null) 121 | { 122 | m_embedConfig.ErrorMessage = "Failed to generate embed token."; 123 | return false; 124 | } 125 | 126 | // Generate Embed Configuration. 127 | m_embedConfig.EmbedToken = tokenResponse; 128 | m_embedConfig.EmbedUrl = report.EmbedUrl; 129 | m_embedConfig.Id = report.Id; 130 | 131 | System.Diagnostics.Debug.Print("EmbedToken:" + m_embedConfig.EmbedToken.Token); 132 | System.Diagnostics.Debug.Print("EmbedUrl:" + m_embedConfig.EmbedUrl); 133 | System.Diagnostics.Debug.Print("ReportId:" + m_embedConfig.Id); 134 | } 135 | } 136 | catch (HttpOperationException exc) 137 | { 138 | m_embedConfig.ErrorMessage = string.Format("Status: {0} ({1})\r\nResponse: {2}\r\nRequestId: {3}", exc.Response.StatusCode, (int)exc.Response.StatusCode, exc.Response.Content, exc.Response.Headers["RequestId"].FirstOrDefault()); 139 | return false; 140 | } 141 | 142 | return true; 143 | } 144 | 145 | public async Task EmbedDashboard() 146 | { 147 | // Get token credentials for user 148 | var getCredentialsResult = await GetTokenCredentials(); 149 | if (!getCredentialsResult) 150 | { 151 | // The error message set in GetTokenCredentials 152 | return false; 153 | } 154 | 155 | try 156 | { 157 | // Create a Power BI Client object. It will be used to call Power BI APIs. 158 | using (var client = new PowerBIClient(new Uri(ApiUrl), m_tokenCredentials)) 159 | { 160 | // Get a list of dashboards. 161 | var dashboards = await client.Dashboards.GetDashboardsInGroupAsync(WorkspaceId); 162 | 163 | // Get the first report in the workspace. 164 | var dashboard = dashboards.Value.FirstOrDefault(); 165 | 166 | if (dashboard == null) 167 | { 168 | m_embedConfig.ErrorMessage = "Workspace has no dashboards."; 169 | return false; 170 | } 171 | 172 | // Generate Embed Token. 173 | var generateTokenRequestParameters = new GenerateTokenRequest(accessLevel: "view"); 174 | var tokenResponse = await client.Dashboards.GenerateTokenInGroupAsync(WorkspaceId, dashboard.Id, generateTokenRequestParameters); 175 | 176 | if (tokenResponse == null) 177 | { 178 | m_embedConfig.ErrorMessage = "Failed to generate embed token."; 179 | return false; 180 | } 181 | 182 | // Generate Embed Configuration. 183 | m_embedConfig = new EmbedConfig() 184 | { 185 | EmbedToken = tokenResponse, 186 | EmbedUrl = dashboard.EmbedUrl, 187 | Id = dashboard.Id 188 | }; 189 | 190 | return true; 191 | } 192 | } 193 | catch (HttpOperationException exc) 194 | { 195 | m_embedConfig.ErrorMessage = string.Format("Status: {0} ({1})\r\nResponse: {2}\r\nRequestId: {3}", exc.Response.StatusCode, (int)exc.Response.StatusCode, exc.Response.Content, exc.Response.Headers["RequestId"].FirstOrDefault()); 196 | return false; 197 | } 198 | } 199 | 200 | public async Task EmbedTile() 201 | { 202 | // Get token credentials for user 203 | var getCredentialsResult = await GetTokenCredentials(); 204 | if (!getCredentialsResult) 205 | { 206 | // The error message set in GetTokenCredentials 207 | m_tileEmbedConfig.ErrorMessage = m_embedConfig.ErrorMessage; 208 | return false; 209 | } 210 | 211 | try 212 | { 213 | // Create a Power BI Client object. It will be used to call Power BI APIs. 214 | using (var client = new PowerBIClient(new Uri(ApiUrl), m_tokenCredentials)) 215 | { 216 | // Get a list of dashboards. 217 | var dashboards = await client.Dashboards.GetDashboardsInGroupAsync(WorkspaceId); 218 | 219 | // Get the first report in the workspace. 220 | var dashboard = dashboards.Value.FirstOrDefault(); 221 | 222 | if (dashboard == null) 223 | { 224 | m_tileEmbedConfig.ErrorMessage = "Workspace has no dashboards."; 225 | return false; 226 | } 227 | 228 | var tiles = await client.Dashboards.GetTilesInGroupAsync(WorkspaceId, dashboard.Id); 229 | 230 | // Get the first tile in the workspace. 231 | var tile = tiles.Value.FirstOrDefault(); 232 | 233 | // Generate Embed Token for a tile. 234 | var generateTokenRequestParameters = new GenerateTokenRequest(accessLevel: "view"); 235 | var tokenResponse = await client.Tiles.GenerateTokenInGroupAsync(WorkspaceId, dashboard.Id, tile.Id, generateTokenRequestParameters); 236 | 237 | if (tokenResponse == null) 238 | { 239 | m_tileEmbedConfig.ErrorMessage = "Failed to generate embed token."; 240 | return false; 241 | } 242 | 243 | // Generate Embed Configuration. 244 | m_tileEmbedConfig = new TileEmbedConfig() 245 | { 246 | EmbedToken = tokenResponse, 247 | EmbedUrl = tile.EmbedUrl, 248 | Id = tile.Id, 249 | dashboardId = dashboard.Id 250 | }; 251 | 252 | return true; 253 | } 254 | } 255 | catch (HttpOperationException exc) 256 | { 257 | m_embedConfig.ErrorMessage = string.Format("Status: {0} ({1})\r\nResponse: {2}\r\nRequestId: {3}", exc.Response.StatusCode, (int)exc.Response.StatusCode, exc.Response.Content, exc.Response.Headers["RequestId"].FirstOrDefault()); 258 | return false; 259 | } 260 | } 261 | 262 | /// 263 | /// Check if web.config embed parameters have valid values. 264 | /// 265 | /// Null if web.config parameters are valid, otherwise returns specific error string. 266 | private string GetWebConfigErrors() 267 | { 268 | // Application Id must have a value. 269 | if (string.IsNullOrWhiteSpace(ApplicationId)) 270 | { 271 | return "ApplicationId is empty. please register your application as Native app in https://dev.powerbi.com/apps and fill client Id in web.config."; 272 | } 273 | 274 | // Application Id must be a Guid object. 275 | Guid result; 276 | if (!Guid.TryParse(ApplicationId, out result)) 277 | { 278 | return "ApplicationId must be a Guid object. please register your application as Native app in https://dev.powerbi.com/apps and fill application Id in web.config."; 279 | } 280 | 281 | // Workspace Id must have a value. 282 | if (string.IsNullOrWhiteSpace(WorkspaceId)) 283 | { 284 | return "WorkspaceId is empty. Please select a group you own and fill its Id in web.config"; 285 | } 286 | 287 | // Workspace Id must be a Guid object. 288 | if (!Guid.TryParse(WorkspaceId, out result)) 289 | { 290 | return "WorkspaceId must be a Guid object. Please select a workspace you own and fill its Id in web.config"; 291 | } 292 | 293 | if (AuthenticationType.Equals("MasterUser")) 294 | { 295 | // Username must have a value. 296 | if (string.IsNullOrWhiteSpace(Username)) 297 | { 298 | return "Username is empty. Please fill Power BI username in web.config"; 299 | } 300 | 301 | // Password must have a value. 302 | if (string.IsNullOrWhiteSpace(Password)) 303 | { 304 | return "Password is empty. Please fill password of Power BI username in web.config"; 305 | } 306 | } 307 | else 308 | { 309 | if (string.IsNullOrWhiteSpace(ApplicationSecret)) 310 | { 311 | return "ApplicationSecret is empty. please register your application as Web app and fill appSecret in web.config."; 312 | } 313 | 314 | // Must fill tenant Id 315 | if (string.IsNullOrWhiteSpace(Tenant)) 316 | { 317 | return "Invalid Tenant. Please fill Tenant ID in Tenant under web.config"; 318 | } 319 | } 320 | 321 | return null; 322 | } 323 | 324 | private async Task DoAuthentication() 325 | { 326 | AuthenticationResult authenticationResult = null; 327 | //if (AuthenticationType.Equals("MasterUser")) 328 | //{ 329 | // var authenticationContext = new AuthenticationContext(AuthorityUrl); 330 | 331 | // // Authentication using master user credentials 332 | // var credential = new UserPasswordCredential(Username, Password); 333 | // authenticationResult = authenticationContext.AcquireTokenAsync(ResourceUrl, ApplicationId, credential).Result; 334 | //} 335 | //else 336 | //{ 337 | // For app only authentication, we need the specific tenant id in the authority url 338 | var tenantSpecificURL = AuthorityUrl.Replace("common", Tenant); 339 | var authenticationContext = new AuthenticationContext(tenantSpecificURL); 340 | 341 | // Authentication using app credentials 342 | var credential = new ClientCredential(ApplicationId, ApplicationSecret); 343 | authenticationResult = await authenticationContext.AcquireTokenAsync(ResourceUrl, credential); 344 | //} 345 | 346 | return authenticationResult; 347 | } 348 | 349 | private async Task GetTokenCredentials() 350 | { 351 | // var result = new EmbedConfig { Username = username, Roles = roles }; 352 | var error = GetWebConfigErrors(); 353 | if (error != null) 354 | { 355 | m_embedConfig.ErrorMessage = error; 356 | return false; 357 | } 358 | 359 | // Authenticate using created credentials 360 | AuthenticationResult authenticationResult = null; 361 | try 362 | { 363 | authenticationResult = await DoAuthentication(); 364 | } 365 | catch (AggregateException exc) 366 | { 367 | m_embedConfig.ErrorMessage = exc.InnerException.Message; 368 | return false; 369 | } 370 | 371 | if (authenticationResult == null) 372 | { 373 | m_embedConfig.ErrorMessage = "Authentication Failed."; 374 | return false; 375 | } 376 | 377 | m_tokenCredentials = new TokenCredentials(authenticationResult.AccessToken, "Bearer"); 378 | return true; 379 | } 380 | } 381 | } -------------------------------------------------------------------------------- /PowerBI-Embedded-JavaScript/powerbi.min.js: -------------------------------------------------------------------------------- 1 | /*! powerbi-client v2.5.1 | (c) 2016 Microsoft Corporation MIT */ 2 | !function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports["powerbi-client"]=e():t["powerbi-client"]=e()}(this,function(){return function(t){function e(a){if(r[a])return r[a].exports;var i=r[a]={exports:{},id:a,loaded:!1};return t[a].call(i.exports,i,i.exports,e),i.loaded=!0,i.exports}var r={};return e.m=t,e.c=r,e.p="",e(0)}([function(t,e,r){var a=r(1);e.service=a;var i=r(15);e.factories=i;var o=r(4);e.models=o;var n=r(5);e.Report=n.Report;var l=r(11);e.Dashboard=l.Dashboard;var s=r(12);e.Tile=s.Tile;var d=r(2);e.Embed=d.Embed;var u=r(6);e.Page=u.Page;var p=r(13);e.Qna=p.Qna;var c=r(14);e.Visual=c.Visual;var f=r(7);e.VisualDescriptor=f.VisualDescriptor;var h=new a.Service(i.hpmFactory,i.wpmpFactory,i.routerFactory);window.powerbi=h},function(t,e,r){var a=r(2),i=r(5),o=r(10),n=r(11),l=r(12),s=r(6),d=r(13),u=r(14),p=r(3),c=function(){function t(e,r,a,i){var o=this;void 0===i&&(i={}),this.wpmp=r(i.wpmpName,i.logMessages),this.hpm=e(this.wpmp,null,i.version,i.type),this.router=a(this.wpmp),this.router.post("/reports/:uniqueId/events/:eventName",function(t,e){var r={type:"report",id:t.params.uniqueId,name:t.params.eventName,value:t.body};o.handleEvent(r)}),this.router.post("/reports/:uniqueId/pages/:pageName/events/:eventName",function(t,e){var r={type:"report",id:t.params.uniqueId,name:t.params.eventName,value:t.body};o.handleEvent(r)}),this.router.post("/reports/:uniqueId/pages/:pageName/visuals/:visualName/events/:eventName",function(t,e){var r={type:"report",id:t.params.uniqueId,name:t.params.eventName,value:t.body};o.handleEvent(r)}),this.router.post("/dashboards/:uniqueId/events/:eventName",function(t,e){var r={type:"dashboard",id:t.params.uniqueId,name:t.params.eventName,value:t.body};o.handleEvent(r)}),this.router.post("/tile/:uniqueId/events/:eventName",function(t,e){var r={type:"tile",id:t.params.uniqueId,name:t.params.eventName,value:t.body};o.handleEvent(r)}),this.router.post("/qna/:uniqueId/events/:eventName",function(t,e){var r={type:"qna",id:t.params.uniqueId,name:t.params.eventName,value:t.body};o.handleEvent(r)}),this.embeds=[],this.config=p.assign({},t.defaultConfig,i),this.config.autoEmbedOnContentLoaded&&this.enableAutoEmbed()}return t.prototype.createReport=function(t,e){e.type="create";var r=t,a=new o.Create(this,r,e);return r.powerBiEmbed=a,this.addOrOverwriteEmbed(a,t),a},t.prototype.init=function(t,e){var r=this;void 0===e&&(e=void 0),t=t&&t instanceof HTMLElement?t:document.body;var i=Array.prototype.slice.call(t.querySelectorAll("["+a.Embed.embedUrlAttribute+"]"));return i.map(function(t){return r.embed(t,e)})},t.prototype.embed=function(t,e){return void 0===e&&(e={}),this.embedInternal(t,e)},t.prototype.load=function(t,e){return void 0===e&&(e={}),this.embedInternal(t,e,!0)},t.prototype.embedInternal=function(t,e,r){void 0===e&&(e={});var a,i=t;return a=i.powerBiEmbed?this.embedExisting(i,e,r):this.embedNew(i,e,r)},t.prototype.embedNew=function(e,r,o){var n=r.type||e.getAttribute(a.Embed.typeAttribute);if(!n)throw new Error("Attempted to embed using config "+JSON.stringify(r)+" on element "+e.outerHTML+", but could not determine what type of component to embed. You must specify a type in the configuration or as an attribute such as '"+a.Embed.typeAttribute+'="'+i.Report.type.toLowerCase()+"\"'.");r.type=n;var l=p.find(function(t){return n===t.type.toLowerCase()},t.components);if(!l)throw new Error("Attempted to embed component of type: "+n+" but did not find any matching component. Please verify the type you specified is intended.");var s=new l(this,e,r,o);return e.powerBiEmbed=s,this.addOrOverwriteEmbed(s,e),s},t.prototype.embedExisting=function(t,e,r){var a=p.find(function(e){return e.element===t},this.embeds);if(!a)throw new Error("Attempted to embed using config "+JSON.stringify(e)+" on element "+t.outerHTML+" which already has embedded comopnent associated, but could not find the existing comopnent in the list of active components. This could indicate the embeds list is out of sync with the DOM, or the component is referencing the incorrect HTML element.");if(e.type&&"qna"===e.type.toLowerCase())return this.embedNew(t,e);if("string"==typeof e.type&&e.type!==a.config.type){if("report"===e.type&&"create"===a.config.type){var o=new i.Report(this,t,e,(!1),t.powerBiEmbed.iframe);return o.load(e),t.powerBiEmbed=o,this.addOrOverwriteEmbed(a,t),o}throw new Error("Embedding on an existing element with a different type than the previous embed object is not supported. Attempted to embed using config "+JSON.stringify(e)+" on element "+t.outerHTML+", but the existing element contains an embed of type: "+this.config.type+" which does not match the new type: "+e.type)}return a.load(e,r),a},t.prototype.enableAutoEmbed=function(){var t=this;window.addEventListener("DOMContentLoaded",function(e){return t.init(document.body)},!1)},t.prototype.get=function(t){var e=t;if(!e.powerBiEmbed)throw new Error("You attempted to get an instance of powerbi component associated with element: "+t.outerHTML+" but there was no associated instance.");return e.powerBiEmbed},t.prototype.find=function(t){return p.find(function(e){return e.config.uniqueId===t},this.embeds)},t.prototype.addOrOverwriteEmbed=function(t,e){this.embeds=this.embeds.filter(function(t){return t.element.id!==e.id}),this.embeds.push(t)},t.prototype.reset=function(t){var e=t;if(e.powerBiEmbed){p.remove(function(t){return t===e.powerBiEmbed},this.embeds),delete e.powerBiEmbed;var r=t.querySelector("iframe");r&&(void 0!==r.remove?r.remove():r.parentElement.removeChild(r))}},t.prototype.handleTileEvents=function(t){"tile"===t.type&&this.handleEvent(t)},t.prototype.handleEvent=function(t){var e=p.find(function(e){return e.config.uniqueId===t.id},this.embeds);if(e){var r=t.value;if("pageChanged"===t.name){var a="newPage",i=r[a];if(!i)throw new Error("Page model not found at 'event.value."+a+"'.");r[a]=new s.Page(e,i.name,i.displayName,(!0))}p.raiseCustomEvent(e.element,t.name,r)}},t.prototype.preload=function(t,e){var r=document.createElement("iframe");r.setAttribute("style","display:none;"),r.setAttribute("src",t.embedUrl),r.setAttribute("scrolling","no"),r.setAttribute("allowfullscreen","false");var a=e;return a||(a=document.getElementsByTagName("body")[0]),a.appendChild(r),r.onload=function(){p.raiseCustomEvent(r,"preloaded",{})},r},t.components=[l.Tile,i.Report,n.Dashboard,d.Qna,u.Visual],t.defaultConfig={autoEmbedOnContentLoaded:!1,onError:function(){for(var t=[],e=0;e0?"&":"?";return t+=a+e+"="+r}e.raiseCustomEvent=r,e.findIndex=a,e.find=i,e.remove=o,e.assign=n,e.createRandomString=l,e.addParamToUrl=s},function(t,e,r){/*! powerbi-models v1.0.4 | (c) 2016 Microsoft Corporation MIT */ 3 | !function(e,r){t.exports=r()}(this,function(){return function(t){function e(a){if(r[a])return r[a].exports;var i=r[a]={exports:{},id:a,loaded:!1};return t[a].call(i.exports,i,i.exports,e),i.loaded=!0,i.exports}var r={};return e.m=t,e.c=r,e.p="",e(0)}([function(t,e,r){function a(t){return l(t)&&!!t.keys}function i(t){return o(t)===j.Basic&&!!t.keyValues}function o(t){if(t.filterType)return t.filterType;var e=t,r=t;return"string"==typeof e.operator&&Array.isArray(e.values)?j.Basic:"string"==typeof r.logicalOperator&&Array.isArray(r.conditions)?j.Advanced:j.Unknown}function n(t){return void 0!==t.table&&void 0!==t.measure}function l(t){return void 0!==t.table&&void 0!==t.column}function s(t){return void 0!==t.table&&void 0!==t.hierarchy&&void 0!==t.hierarchyLevel}function d(t){var e=t.message;return e||(e=t.path+" is invalid. Not meeting "+t.keyword+" constraint"),{message:e}}function u(t){var r=e.Validators.playBookmarkRequestValidator.validate(t);return r?r.map(d):void 0}function p(t){var r=e.Validators.addBookmarkRequestValidator.validate(t);return r?r.map(d):void 0}function c(t){var r=e.Validators.applyBookmarkByNameRequestValidator.validate(t);return r?r.map(d):void 0}function f(t){var r=e.Validators.applyBookmarkStateRequestValidator.validate(t);return r?r.map(d):void 0}function h(t){var r=e.Validators.settingsValidator.validate(t);return r?r.map(d):void 0}function v(t){var r=e.Validators.customPageSizeValidator.validate(t);return r?r.map(d):void 0}function y(t){var r=e.Validators.extentionValidator.validate(t);return r?r.map(d):void 0}function m(t){var r=e.Validators.reportLoadValidator.validate(t);return r?r.map(d):void 0}function g(t){var r=e.Validators.reportCreateValidator.validate(t);return r?r.map(d):void 0}function V(t){var r=e.Validators.dashboardLoadValidator.validate(t);return r?r.map(d):void 0}function w(t){var r=e.Validators.tileLoadValidator.validate(t);return r?r.map(d):void 0}function b(t){var r=e.Validators.pageValidator.validate(t);return r?r.map(d):void 0}function E(t){var r=e.Validators.filtersValidator.validate(t);return r?r.map(d):void 0}function P(t){var r=e.Validators.saveAsParametersValidator.validate(t);return r?r.map(d):void 0}function O(t){var r=e.Validators.loadQnaValidator.validate(t);return r?r.map(d):void 0}function T(t){var r=e.Validators.qnaInterpretInputDataValidator.validate(t);return r?r.map(d):void 0}function _(t){var r=e.Validators.exportDataRequestValidator.validate(t);return r?r.map(d):void 0}var k=this&&this.__extends||function(){var t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)e.hasOwnProperty(r)&&(t[r]=e[r])};return function(e,r){function a(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(a.prototype=r.prototype,new a)}}();Object.defineProperty(e,"__esModule",{value:!0}),e.Validators=r(1).Validators;var A;!function(t){t[t.Widescreen=0]="Widescreen",t[t.Standard=1]="Standard",t[t.Cortana=2]="Cortana",t[t.Letter=3]="Letter",t[t.Custom=4]="Custom"}(A=e.PageSizeType||(e.PageSizeType={}));var R;!function(t){t[t.FitToPage=0]="FitToPage",t[t.FitToWidth=1]="FitToWidth",t[t.ActualSize=2]="ActualSize"}(R=e.DisplayOption||(e.DisplayOption={}));var S;!function(t){t[t.Default=0]="Default",t[t.Transparent=1]="Transparent"}(S=e.BackgroundType||(e.BackgroundType={}));var x;!function(t){t[t.Visible=0]="Visible",t[t.Hidden=1]="Hidden"}(x=e.VisualContainerDisplayMode||(e.VisualContainerDisplayMode={}));var F;!function(t){t[t.Master=0]="Master",t[t.Custom=1]="Custom",t[t.MobilePortrait=2]="MobilePortrait",t[t.MobileLandscape=3]="MobileLandscape"}(F=e.LayoutType||(e.LayoutType={}));var q;!function(t){t[t.AlwaysVisible=0]="AlwaysVisible",t[t.HiddenInViewMode=1]="HiddenInViewMode"}(q=e.SectionVisibility||(e.SectionVisibility={}));var M;!function(t){t[t.Read=0]="Read",t[t.ReadWrite=1]="ReadWrite",t[t.Copy=2]="Copy",t[t.Create=4]="Create",t[t.All=7]="All"}(M=e.Permissions||(e.Permissions={}));var C;!function(t){t[t.View=0]="View",t[t.Edit=1]="Edit"}(C=e.ViewMode||(e.ViewMode={}));var I;!function(t){t[t.Aad=0]="Aad",t[t.Embed=1]="Embed"}(I=e.TokenType||(e.TokenType={}));var j;!function(t){t[t.Advanced=0]="Advanced",t[t.Basic=1]="Basic",t[t.Unknown=2]="Unknown",t[t.IncludeExclude=3]="IncludeExclude",t[t.RelativeDate=4]="RelativeDate",t[t.TopN=5]="TopN"}(j=e.FilterType||(e.FilterType={}));var N;!function(t){t[t.Days=0]="Days",t[t.Weeks=1]="Weeks",t[t.CalendarWeeks=2]="CalendarWeeks",t[t.Months=3]="Months",t[t.CalendarMonths=4]="CalendarMonths",t[t.Years=5]="Years",t[t.CalendarYears=6]="CalendarYears"}(N=e.RelativeDateFilterTimeUnit||(e.RelativeDateFilterTimeUnit={}));var L;!function(t){t[t.InLast=0]="InLast",t[t.InThis=1]="InThis",t[t.InNext=2]="InNext"}(L=e.RelativeDateOperators||(e.RelativeDateOperators={}));var U=function(){function t(t,e){this.target=t,this.filterType=e}return t.prototype.toJSON=function(){return{$schema:this.schemaUrl,target:this.target,filterType:this.filterType}},t}();e.Filter=U;var D=function(t){function e(r,a,i){var o=t.call(this,r,j.Unknown)||this;return o.message=a,o.notSupportedTypeName=i,o.schemaUrl=e.schemaUrl,o}return k(e,t),e.prototype.toJSON=function(){var e=t.prototype.toJSON.call(this);return e.message=this.message,e.notSupportedTypeName=this.notSupportedTypeName,e},e.schemaUrl="http://powerbi.com/product/schema#notSupported",e}(U);e.NotSupportedFilter=D;var W=function(t){function e(r,a,i){var o=t.call(this,r,j.IncludeExclude)||this;return o.values=i,o.isExclude=a,o.schemaUrl=e.schemaUrl,o}return k(e,t),e.prototype.toJSON=function(){var e=t.prototype.toJSON.call(this);return e.isExclude=this.isExclude,e.values=this.values,e},e.schemaUrl="http://powerbi.com/product/schema#includeExclude",e}(U);e.IncludeExcludeFilter=W;var B=function(t){function e(r,a,i){var o=t.call(this,r,j.TopN)||this;return o.operator=a,o.itemCount=i,o.schemaUrl=e.schemaUrl,o}return k(e,t),e.prototype.toJSON=function(){var e=t.prototype.toJSON.call(this);return e.operator=this.operator,e.itemCount=this.itemCount,e},e.schemaUrl="http://powerbi.com/product/schema#topN",e}(U);e.TopNFilter=B;var H=function(t){function e(r,a,i,o,n){var l=t.call(this,r,j.RelativeDate)||this;return l.operator=a,l.timeUnitsCount=i,l.timeUnitType=o,l.includeToday=n,l.schemaUrl=e.schemaUrl,l}return k(e,t),e.prototype.toJSON=function(){var e=t.prototype.toJSON.call(this);return e.operator=this.operator,e.timeUnitsCount=this.timeUnitsCount,e.timeUnitType=this.timeUnitType,e.includeToday=this.includeToday,e},e.schemaUrl="http://powerbi.com/product/schema#relativeDate",e}(U);e.RelativeDateFilter=H;var z=function(t){function e(r,a){for(var i=[],o=2;o0&&!i)throw new Error("You shold pass the values to be filtered for each key. You passed: no values and "+n+" keys");if(0===n&&i&&i.length>0)throw new Error("You passed key values but your target object doesn't contain the keys to be filtered");for(var l=0;l2)throw new Error("AdvancedFilters may not have more than two conditions. You passed: "+i.length);if(1===l.length&&"And"!==a)throw new Error('Logical Operator must be "And" when there is only one condition provided');return n.conditions=l,n}return k(e,t),e.prototype.toJSON=function(){var e=t.prototype.toJSON.call(this);return e.logicalOperator=this.logicalOperator,e.conditions=this.conditions,e},e.schemaUrl="http://powerbi.com/product/schema#advanced",e}(U);e.AdvancedFilter=Y,e.isFilterKeyColumnsTarget=a,e.isBasicFilterWithKeys=i,e.getFilterType=o,e.isMeasure=n,e.isColumn=l,e.isHierarchy=s;var Q;!function(t){t[t.Interactive=0]="Interactive",t[t.ResultOnly=1]="ResultOnly"}(Q=e.QnaMode||(e.QnaMode={}));var G;!function(t){t[t.Summarized=0]="Summarized",t[t.Underlying=1]="Underlying"}(G=e.ExportDataType||(e.ExportDataType={}));var $;!function(t){t[t.Off=0]="Off",t[t.Presentation=1]="Presentation"}($=e.BookmarksPlayMode||(e.BookmarksPlayMode={})),e.validatePlayBookmarkRequest=u,e.validateAddBookmarkRequest=p,e.validateApplyBookmarkByNameRequest=c,e.validateApplyBookmarkStateRequest=f,e.validateSettings=h,e.validateCustomPageSize=v,e.validateExtension=y,e.validateReportLoad=m,e.validateCreateReport=g,e.validateDashboardLoad=V,e.validateTileLoad=w,e.validatePage=b,e.validateFilter=E,e.validateSaveAsParameters=P,e.validateLoadQnaConfiguration=O,e.validateQnaInterpretInputData=T,e.validateExportDataRequest=_},function(t,e,r){Object.defineProperty(e,"__esModule",{value:!0});var a=r(2),i=r(3),o=r(5),n=r(6),l=r(7),s=r(8),d=r(9),u=r(10),p=r(11),c=r(12),f=r(13),h=r(14),v=r(15),y=r(16),m=r(17),g=r(18),V=r(19);e.Validators={advancedFilterTypeValidator:new a.EnumValidator([0]),advancedFilterValidator:new l.AdvancedFilterValidator,anyArrayValidator:new a.ArrayValidator([new d.AnyOfValidator([new a.StringValidator,new a.NumberValidator,new a.BooleanValidator])]),anyFilterValidator:new d.AnyOfValidator([new l.BasicFilterValidator,new l.AdvancedFilterValidator,new l.IncludeExcludeFilterValidator,new l.NotSupportedFilterValidator,new l.RelativeDateFilterValidator,new l.TopNFilterValidator]),anyValueValidator:new d.AnyOfValidator([new a.StringValidator,new a.NumberValidator,new a.BooleanValidator]),basicFilterTypeValidator:new a.EnumValidator([1]),basicFilterValidator:new l.BasicFilterValidator,playBookmarkRequestValidator:new n.PlayBookmarkRequestValidator,addBookmarkRequestValidator:new n.AddBookmarkRequestValidator,applyBookmarkByNameRequestValidator:new n.ApplyBookmarkByNameRequestValidator,applyBookmarkStateRequestValidator:new n.ApplyBookmarkStateRequestValidator,applyBookmarkValidator:new d.AnyOfValidator([new n.ApplyBookmarkByNameRequestValidator,new n.ApplyBookmarkStateRequestValidator]),backgroundValidator:new a.EnumValidator([0,1]),booleanArrayValidator:new a.BooleanArrayValidator,booleanValidator:new a.BooleanValidator,commandExtensionValidator:new i.CommandExtensionValidator,conditionItemValidator:new l.ConditionItemValidator,customLayoutValidator:new g.CustomLayoutValidator,customLayoutDisplayOptionValidator:new a.EnumValidator([0,1,2]),customPageSizeValidator:new h.CustomPageSizeValidator,dashboardLoadValidator:new c.DashboardLoadValidator,displayStateModeValidator:new a.EnumValidator([0,1]),displayStateValidator:new g.DisplayStateValidator,exportDataRequestValidator:new V.ExportDataRequestValidator,extensionPointsValidator:new i.ExtensionPointsValidator,extentionArrayValidator:new a.ArrayValidator([new i.ExtensionValidator]),extentionValidator:new i.ExtensionValidator,fieldRequiredValidator:new s.FieldRequiredValidator,filterColumnTargetValidator:new l.FilterColumnTargetValidator,filterConditionsValidator:new a.ArrayValidator([new l.ConditionItemValidator]),filterHierarchyTargetValidator:new l.FilterHierarchyTargetValidator,filterMeasureTargetValidator:new l.FilterMeasureTargetValidator,filterTargetValidator:new d.AnyOfValidator([new l.FilterColumnTargetValidator,new l.FilterHierarchyTargetValidator,new l.FilterMeasureTargetValidator]),filtersArrayValidator:new a.ArrayValidator([new d.AnyOfValidator([new l.BasicFilterValidator,new l.AdvancedFilterValidator,new l.RelativeDateFilterValidator])]),filtersValidator:new l.FilterValidator,includeExcludeFilterValidator:new l.IncludeExcludeFilterValidator,includeExludeFilterTypeValidator:new a.EnumValidator([3]),layoutTypeValidator:new a.EnumValidator([0,1,2,3]),loadQnaValidator:new v.LoadQnaValidator,menuExtensionValidator:new i.MenuExtensionValidator,notSupportedFilterTypeValidator:new a.EnumValidator([2]),notSupportedFilterValidator:new l.NotSupportedFilterValidator,numberArrayValidator:new a.NumberArrayValidator,numberValidator:new a.NumberValidator,pageLayoutValidator:new m.MapValidator([new a.StringValidator],[new g.VisualLayoutValidator]),pageSizeTypeValidator:new a.EnumValidator([0,1,2,3,4,5]),pageSizeValidator:new h.PageSizeValidator,pageValidator:new h.PageValidator,pageViewFieldValidator:new h.PageViewFieldValidator,pagesLayoutValidator:new m.MapValidator([new a.StringValidator],[new g.PageLayoutValidator]),permissionsValidator:new a.EnumValidator([0,1,2,4,7]),qnaInterpretInputDataValidator:new v.QnaInterpretInputDataValidator,qnaSettingValidator:new v.QnaSettingsValidator,relativeDateFilterOperatorValidator:new a.EnumValidator([0,1,2]),relativeDateFilterTimeUnitTypeValidator:new a.EnumValidator([0,1,2,3,4,5,6]),relativeDateFilterTypeValidator:new a.EnumValidator([4]),relativeDateFilterValidator:new l.RelativeDateFilterValidator,reportCreateValidator:new p.ReportCreateValidator,reportLoadValidator:new u.ReportLoadValidator,saveAsParametersValidator:new y.SaveAsParametersValidator,settingsValidator:new o.SettingsValidator,stringArrayValidator:new a.StringArrayValidator,stringValidator:new a.StringValidator,tileLoadValidator:new f.TileLoadValidator,tokenTypeValidator:new a.EnumValidator([0,1]),topNFilterTypeValidator:new a.EnumValidator([5]),topNFilterValidator:new l.TopNFilterValidator,viewModeValidator:new a.EnumValidator([0,1]),visualLayoutValidator:new g.VisualLayoutValidator}},function(t,e){var r=this&&this.__extends||function(){var t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)e.hasOwnProperty(r)&&(t[r]=e[r])};return function(e,r){function a(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(a.prototype=r.prototype,new a)}}();Object.defineProperty(e,"__esModule",{value:!0});var a=function(){function t(){}return t.prototype.validate=function(t,e,r){return null==t?null:"object"!=typeof t||Array.isArray(t)?[{message:void 0!==r?r+" must be an object":"input must be an object",path:e,keyword:"type"}]:null},t}();e.ObjectValidator=a;var i=function(){function t(t){this.itemValidators=t}return t.prototype.validate=function(t,e,r){if(null==t)return null;if(!Array.isArray(t))return[{message:r+" property is invalid",path:(e?e+".":"")+r,keyword:"type"}];for(var a=0;a2&&"[]"===n.slice(l-2)&&(s=!0,n=n.slice(0,l-2),r[n]||(r[n]=[])),i=o[1]?w(o[1]):""),s?r[n].push(i):r[n]=i}return r},recognize:function(t){var e,r,a,i=[this.rootState],o={},n=!1;if(a=t.indexOf("?"),a!==-1){var l=t.substr(a+1,t.length);t=t.substr(0,a),o=this.parseQueryString(l)}for(t=decodeURI(t),"/"!==t.charAt(0)&&(t="/"+t),e=t.length,e>1&&"/"===t.charAt(e-1)&&(t=t.substr(0,e-1),n=!0),r=0;r