From adcbf7021e8b34db1c1429ee16a48f38cff3a896 Mon Sep 17 00:00:00 2001 From: encimita <55883409+encimita@users.noreply.github.com> Date: Wed, 26 Jun 2024 07:16:12 +0200 Subject: [PATCH] [PowerBI] Add more flexible options for embedding, enable client resizing (#1332) #### Summary This PR tackles a few minor limitations with the Power BI embedded experiences. Allows to set the token for the embed experience separately, removes unnecessary logic to tweak the size of the part hosting the add-in, allows to set more granular settings for the embed experience. #### Work Item(s) Fixes [AB#538462](https://dynamicssmb2.visualstudio.com/1fcb79e7-ab07-432a-a3c6-6cf5a88ba4a5/_workitems/edit/538462) --- .../PowerBIManagement/js/PowerBIManagement.js | 360 +++++++++++------- .../src/PowerBIManagement.ControlAddin.al | 98 +++-- .../PowerBIManagement/js/PowerBIManagement.js | 360 +++++++++++------- .../stylesheets/PowerBIManagement.css | 2 +- 4 files changed, 497 insertions(+), 323 deletions(-) diff --git a/src/System Application/App/ControlAddIns/Resources/PowerBIManagement/js/PowerBIManagement.js b/src/System Application/App/ControlAddIns/Resources/PowerBIManagement/js/PowerBIManagement.js index fde3eb6bae..2b2c7a5387 100644 --- a/src/System Application/App/ControlAddIns/Resources/PowerBIManagement/js/PowerBIManagement.js +++ b/src/System Application/App/ControlAddIns/Resources/PowerBIManagement/js/PowerBIManagement.js @@ -9,20 +9,13 @@ var embed = null; var activePage = null; -var fullPageMode = false; - +var settingsObject = null; var models = null; -var embedWidth = null; -var embedHeight = null; -var manifestWidth = null; -var manifestHeight = null; +var pbiAuthToken = null; function Initialize() { models = window['powerbi-client'].models; - var controlAddInElement = document.getElementById('controlAddIn'); - manifestWidth = controlAddInElement.offsetWidth; - manifestHeight = controlAddInElement.offsetHeight; RaiseAddInReady(); } @@ -56,26 +49,106 @@ function RaiseReportVisualLoaded(correlationId) { Microsoft.Dynamics.NAV.InvokeExtensibilityMethod('ReportVisualLoaded', [correlationId]); } -// Exposed Functions +// Obsolete Functions function InitializeReport(reportLink, reportId, authToken, powerBIEnv) { // OBSOLETE EmbedReport(reportLink, reportId, authToken, ''); } +function EmbedReportWithOptions(reportLink, reportId, authToken, pageName, showPanes) { + // OBSOLETE + EmbedReport(reportLink, reportId, authToken, pageName) +} + function EmbedReport(reportLink, reportId, authToken, pageName) { - // OBSOLETE - EmbedReportWithOptions(reportLink, reportId, authToken, pageName, false) + // OBSOLETE + pbiAuthToken = authToken; + EmbedPowerBIReport(reportLink, reportId, pageName); } -function EmbedReportWithOptions(reportLink, reportId, authToken, pageName, showPanes) { +function EmbedDashboard(dashboardLink, dashboardId, authToken) { + // OBSOLETE + pbiAuthToken = authToken; + EmbedPowerBIDashboard(dashboardLink, dashboardId); +} + +function EmbedDashboardTile(dashboardTileLink, dashboardId, tileId, authToken) { + // OBSOLETE + pbiAuthToken = authToken; + EmbedPowerBIDashboardTile(dashboardTileLink, dashboardId, tileId); +} + +function EmbedReportVisual(reportVisualLink, reportId, pageName, visualName, authToken) { + // OBSOLETE + pbiAuthToken = authToken; + EmbedPowerBIReportVisual(reportVisualLink, reportId, pageName, visualName); +} + +function ViewMode() { + // OBSOLETE + embed.switchMode('View').catch(function (error) { + ProcessError('ViewMode', error); + }); +} + +function EditMode() { + // OBSOLETE + embed.switchMode('Edit').catch(function (error) { + ProcessError('EditMode', error); + }); +} + +function InitializeFrame(fullpage, ratio) { + // OBSOLETE + settingsObject = { + panes: { + bookmarks: { + visible: false + }, + fields: { + visible: fullpage, + expanded: false + }, + filters: { + visible: fullpage, + expanded: fullpage + }, + pageNavigation: { + visible: fullpage + }, + selection: { + visible: fullpage + }, + syncSlicers: { + visible: fullpage + }, + visualizations: { + visible: fullpage, + expanded: false + } + }, + + background: models.BackgroundType.Transparent, + + layoutType: models.LayoutType.Custom, + customLayout: { + displayOption: models.DisplayOption.FitToPage + } + } +} + +// Exposed Functions + +function EmbedPowerBIReport(reportLink, reportId, pageName) { ClearEmbedGlobals(); + ValidatePowerBIHost(reportLink); - var embedConfiguration = InitializeEmbedConfig(authToken, showPanes); + var embedConfiguration = InitializeEmbedConfig(); embedConfiguration.type = 'report'; embedConfiguration.id = SanitizeId(reportId); embedConfiguration.embedUrl = reportLink; - if (pageName && (pageName != '')){ + if (pageName && (pageName != '')) { embedConfiguration.pageName = pageName; } DisplayEmbed(embedConfiguration); @@ -89,36 +162,36 @@ function EmbedReportWithOptions(reportLink, reportId, authToken, pageName, showP var pageFilters = null; var embedCorrelationId = null; - var promises = - [ - embed.getCorrelationId().then(function (correlationId) { - embedCorrelationId = correlationId; - }), - - embed.getPages().then(function (pages) { - var pagesArray = pages.reduce(ReduceByNameFunction, []); - reportPages = JSON.stringify(pagesArray); - }), - - embed.getFilters().then(function (filters) { - reportFilters = JSON.stringify(filters); - }), - - embed.getActivePage().then(function (page) { - activePage = page; - return page.getFilters().then(function (filters) { - pageFilters = JSON.stringify(filters); - }); - }) - ] + var promises = + [ + embed.getCorrelationId().then(function (correlationId) { + embedCorrelationId = correlationId; + }), + + embed.getPages().then(function (pages) { + var pagesArray = pages.reduce(ReduceByNameFunction, []); + reportPages = JSON.stringify(pagesArray); + }), + + embed.getFilters().then(function (filters) { + reportFilters = JSON.stringify(filters); + }), + + embed.getActivePage().then(function (page) { + activePage = page; + return page.getFilters().then(function (filters) { + pageFilters = JSON.stringify(filters); + }); + }) + ] Promise.all(promises).then( - function (values) { - RaiseReportLoaded(reportFilters, reportPages, pageFilters, embedCorrelationId); - }, - function (error) { - ProcessError('LoadReportDetails', error); - }); + function (values) { + RaiseReportLoaded(reportFilters, reportPages, pageFilters, embedCorrelationId); + }, + function (error) { + ProcessError('LoadReportDetails', error); + }); }); embed.off("pageChanged"); @@ -127,16 +200,17 @@ function EmbedReportWithOptions(reportLink, reportId, authToken, pageName, showP activePage.getFilters().then(function (filters) { RaiseReportPageChanged(activePage.name, JSON.stringify(filters)); }, - function (error) { - ProcessError('LoadPageFilters', error); - }); + function (error) { + ProcessError('LoadPageFilters', error); + }); }); } -function EmbedDashboard(dashboardLink, dashboardId, authToken) { +function EmbedPowerBIDashboard(dashboardLink, dashboardId) { ClearEmbedGlobals(); - - var embedConfiguration = InitializeEmbedConfig(authToken, false); + ValidatePowerBIHost(dashboardLink); + + var embedConfiguration = InitializeEmbedConfig(); embedConfiguration.type = 'dashboard'; embedConfiguration.id = SanitizeId(dashboardId); embedConfiguration.embedUrl = dashboardLink; @@ -149,19 +223,20 @@ function EmbedDashboard(dashboardLink, dashboardId, authToken) { embed.getCorrelationId().then(function (correlationId) { RaiseDashboardLoaded(correlationId); }, - function (error) { - ProcessError('LoadDashboardCorrelationId', error); - }); + function (error) { + ProcessError('LoadDashboardCorrelationId', error); + }); }); } -function EmbedDashboardTile(dashboardTileLink, dashboardId, tileId, authToken) { +function EmbedPowerBIDashboardTile(dashboardTileLink, dashboardId, tileId) { ClearEmbedGlobals(); - - var embedConfiguration = InitializeEmbedConfig(authToken, false); + ValidatePowerBIHost(dashboardTileLink); + + var embedConfiguration = InitializeEmbedConfig(); embedConfiguration.type = 'tile'; embedConfiguration.id = SanitizeId(tileId); - embedConfiguration.dashboardId = SanitizeId(dashboardId); + embedConfiguration.dashboardId = SanitizeId(dashboardId); embedConfiguration.embedUrl = dashboardTileLink; DisplayEmbed(embedConfiguration); @@ -172,16 +247,17 @@ function EmbedDashboardTile(dashboardTileLink, dashboardId, tileId, authToken) { embed.getCorrelationId().then(function (correlationId) { RaiseDashboardTileLoaded(correlationId); }, - function (error) { - ProcessError('LoadDashboardTileCorrelationId', error); - }); + function (error) { + ProcessError('LoadDashboardTileCorrelationId', error); + }); }); } -function EmbedReportVisual(reportVisualLink, reportId, pageName, visualName, authToken) { +function EmbedPowerBIReportVisual(reportVisualLink, reportId, pageName, visualName) { ClearEmbedGlobals(); + ValidatePowerBIHost(reportVisualLink); - var embedConfiguration = InitializeEmbedConfig(authToken, false); + var embedConfiguration = InitializeEmbedConfig(); embedConfiguration.type = 'visual'; embedConfiguration.id = SanitizeId(reportId); embedConfiguration.pageName = SanitizeId(pageName); @@ -196,21 +272,9 @@ function EmbedReportVisual(reportVisualLink, reportId, pageName, visualName, aut embed.getCorrelationId().then(function (correlationId) { RaiseReportVisualLoaded(correlationId); }, - function (error) { - ProcessError('LoadReportVisualCorrelationId', error); - }); - }); -} - -function ViewMode() { - embed.switchMode('View').catch(function (error) { - ProcessError('ViewMode', error); - }); -} - -function EditMode() { - embed.switchMode('Edit').catch(function (error) { - ProcessError('EditMode', error); + function (error) { + ProcessError('LoadReportVisualCorrelationId', error); + }); }); } @@ -262,42 +326,63 @@ function SetPage(pageName) { }); } -function InitializeFrame(fullpage, ratio){ - fullPageMode = fullpage; - if (!ratio) ratio = '16:9'; // Default according to Power BI documentation - - var iframe = window.frameElement; +function SetToken(authToken) { + pbiAuthToken = authToken; +} - var maximumAllowedHeight = manifestHeight; - var maximumAllowedWidth = manifestWidth; - if (fullPageMode) { - // When opening a report fullscreen, maximize the real estate instead - iframe.style.removeProperty('max-height'); - iframe.style.removeProperty('max-width'); - maximumAllowedHeight = 720; - maximumAllowedWidth = 1280; +function SetSettings(showBookmarkSelection, showFilters, showPageSelection, showZoomBar, forceTransparentBackground, forceFitToPage, addBottomPadding) { + if (addBottomPadding) { + var iframe = window.frameElement; + iframe.style.paddingBottom = '42px'; + } + else { + var iframe = window.frameElement; + iframe.style.removeProperty('paddingBottom'); } - var arr = ratio.split(":"); - var ratioWidth = arr[0]; - var ratioHeight = arr[1]; - - var computedWidth = (maximumAllowedHeight / ratioHeight) * ratioWidth; - var computedHeight = (maximumAllowedWidth / ratioWidth) * ratioHeight; + settingsObject = { + panes: { + bookmarks: { + visible: showBookmarkSelection + }, + filters: { + visible: showFilters, + expanded: false + }, + pageNavigation: { + visible: showPageSelection + }, + fields: { // In edit mode, allows selecting fields to add to the report + visible: false + }, + selection: { // In edit mode, allows selecting visuals from a list instead of clicking in the UI + visible: false + }, + syncSlicers: { // In edit mode, allows syncing slicers through pages + visible: false + }, + visualizations: { // In edit mode, allows adding new visualizations + visible: false + } + }, - if (computedWidth <= maximumAllowedWidth) { - // Fit to width - embedWidth = computedWidth; - embedHeight = maximumAllowedHeight; + bars: { + statusBar: { + visible: showZoomBar + } + } } - else { - // Fit to height instead - embedWidth = maximumAllowedWidth; - embedHeight = computedHeight; + + if (forceTransparentBackground) { + settingsObject.background = models.BackgroundType.Transparent; } - iframe.style.height = Math.floor(embedHeight).toString() + 'px'; - iframe.style.width = Math.floor(embedWidth).toString() + 'px'; + if (forceFitToPage) { + settingsObject.layoutType = models.LayoutType.Custom; + settingsObject.customLayout = { + displayOption: models.DisplayOption.FitToPage + } + } } // Internal functions @@ -307,48 +392,18 @@ function ClearEmbedGlobals() { activePage = null; } -function InitializeEmbedConfig(authToken, showPanes) { +function InitializeEmbedConfig() { + if (!pbiAuthToken || (pbiAuthToken == '')) { + RaiseErrorOccurred('Initialize Config', 'No token was provided'); + } + var embedConfiguration = { tokenType: models.TokenType.Aad, - accessToken: authToken, + accessToken: pbiAuthToken, viewMode: models.ViewMode.View, permissions: models.Permissions.All, - settings: { - panes: { - bookmarks: { - visible: false - }, - fields: { - visible: fullPageMode && showPanes, - expanded: false - }, - filters: { - visible: fullPageMode && showPanes, - expanded: fullPageMode && showPanes - }, - pageNavigation: { - visible: showPanes - }, - selection: { - visible: fullPageMode && showPanes - }, - syncSlicers: { - visible: fullPageMode && showPanes - }, - visualizations: { - visible: fullPageMode && showPanes, - expanded: false - } - }, - - background: models.BackgroundType.Transparent, - - layoutType: models.LayoutType.Custom, - customLayout: { - displayOption: models.DisplayOption.FitToPage - } - } + settings: settingsObject }; return embedConfiguration; @@ -367,7 +422,7 @@ function DisplayEmbed(embedConfiguration) { embed = powerbi.embed(reportContainer, embedConfiguration); } -function RegisterCommonEmbedEvents(){ +function RegisterCommonEmbedEvents() { embed.off("error"); embed.on("error", function (event) { ProcessError('OnError', event); @@ -379,7 +434,7 @@ function ReduceByNameFunction(accumulator, current) { return accumulator; } -function SanitizeId(id){ +function SanitizeId(id) { // From: {79a5e047-a665-4c83-900b-f5ccf19e01c7} // To: 79a5e047-a665-4c83-900b-f5ccf19e01c7 return id.replace(/[{}]/g, ""); @@ -402,14 +457,23 @@ function LogErrorToConsole(operation, error) { console.error(error); } -function GetErrorMessage(error){ - if (error && error.message){ +function GetErrorMessage(error) { + if (error && error.message) { return error.message; } - if (error && error.detail && error.detail.message){ + if (error && error.detail && error.detail.message) { return error.detail.message; } - return ''; + return error.toString(); +} + +function ValidatePowerBIHost(embedUrl) { + var urlHost = GetHost(embedUrl); + if (!urlHost.endsWith(".powerbi.com") && !urlHost.endsWith('.analysis-df.windows.net')) { + var errorMsg = 'The host "' + urlHost + '" is not a valid Power BI host.'; + ProcessError('InvalidHost', errorMsg); + throw new Error(errorMsg); + } } diff --git a/src/System Application/App/ControlAddIns/src/PowerBIManagement.ControlAddin.al b/src/System Application/App/ControlAddIns/src/PowerBIManagement.ControlAddin.al index 3003880fac..8f9d2e6078 100644 --- a/src/System Application/App/ControlAddIns/src/PowerBIManagement.ControlAddin.al +++ b/src/System Application/App/ControlAddIns/src/PowerBIManagement.ControlAddin.al @@ -9,10 +9,11 @@ controladdin PowerBIManagement { RequestedHeight = 320; MinimumHeight = 180; - RequestedWidth = 300; - MinimumWidth = 200; VerticalStretch = true; VerticalShrink = true; + + RequestedWidth = 300; + MinimumWidth = 200; HorizontalStretch = true; HorizontalShrink = true; @@ -59,48 +60,30 @@ controladdin PowerBIManagement /// event ReportVisualLoaded(CorrelationId: Text); -#pragma warning disable AS0105 /// - /// Initializes the Power BI Embed into the page + /// Initializes the token to be used when embedding Power BI content /// - [Obsolete('This method is deprecated. Please use EmbedReport instead.', '24.0')] - procedure InitializeReport(ReportLink: Text; ReportId: Text; AuthToken: Text; PowerBIApi: Text); -#pragma warning restore AS0105 + procedure SetToken(AuthToken: Text); /// /// Initializes the Power BI embed Report into the page /// - procedure EmbedReport(ReportLink: Text; ReportId: Text; AuthToken: Text; PageName: Text); - - /// - /// Initializes the Power BI embed Report into the page, with additional options - /// - procedure EmbedReportWithOptions(ReportLink: Text; ReportId: Text; AuthToken: Text; PageName: Text; ShowPanes: Boolean); + procedure EmbedPowerBIReport(ReportLink: Text; ReportId: Text; PageName: Text); /// /// Initializes the Power BI embed Dashboard into the page /// - procedure EmbedDashboard(DashboardLink: Text; DashboardId: Text; AuthToken: Text); + procedure EmbedPowerBIDashboard(DashboardLink: Text; DashboardId: Text); /// /// Initializes the Power BI embed Dashboard Tile into the page /// - procedure EmbedDashboardTile(DashboardTileLink: Text; DashboardId: Text; TileId: Text; AuthToken: Text); + procedure EmbedPowerBIDashboardTile(DashboardTileLink: Text; DashboardId: Text; TileId: Text); /// /// Initializes the Power BI embed Report Visual into the page /// - procedure EmbedReportVisual(ReportVisualLink: Text; ReportId: Text; PageName: Text; VisualName: Text; AuthToken: Text); - - /// - /// Changes the current mode into View - /// - procedure ViewMode(); - - /// - /// Changes the current mode into Edit - /// - procedure EditMode(); + procedure EmbedPowerBIReportVisual(ReportVisualLink: Text; ReportId: Text; PageName: Text; VisualName: Text); /// /// Enters full screen mode for the current embed @@ -141,8 +124,71 @@ controladdin PowerBIManagement /// The name of the new page to set as active procedure SetPage(PageName: Text); + /// + /// Sets the properties for the embed experience + /// + ///Shows the bookmark selection pane. + ///Shows the filter pane to filter embed. + ///Shows the pane to select the report page. + ///Shows the bar that allows manual zoom in and zoom out for the embed. + ///Forces a transparent background to the embed. + ///Forces the Fit To Page behaviour for the embed. + ///Controls whether a padding is needed on the bottom of the page (useful in case the embed is the only element displayed on the page). + procedure SetSettings(ShowBookmarkSelection: Boolean; ShowFilters: Boolean; ShowPageSelection: Boolean; ShowZoomBar: Boolean; ForceTransparentBackground: Boolean; ForceFitToPage: Boolean; AddBottomPadding: Boolean); + +#if not CLEAN25 /// /// Sets the properties for the browser frame containing the embed /// + [Obsolete('Use SetSettings, SetToken and then EmbedReport instead.', '25.0')] procedure InitializeFrame(FullPage: Boolean; Ratio: Text); + + /// + /// Initializes the Power BI Embed into the page + /// + [Obsolete('Use SetSettings, SetToken and then EmbedReport instead.', '24.0')] + procedure InitializeReport(ReportLink: Text; ReportId: Text; AuthToken: Text; PowerBIApi: Text); + + /// + /// Initializes the Power BI embed Report into the page, with additional options + /// + [Obsolete('Use SetSettings, SetToken and then EmbedReport instead.', '25.0')] + procedure EmbedReportWithOptions(ReportLink: Text; ReportId: Text; AuthToken: Text; PageName: Text; ShowPanes: Boolean); + + /// + /// Changes the current mode into View + /// + [Obsolete('Switching between edit more and view mode is no longer supported. Only view mode will be supported going forward.', '25.0')] + procedure ViewMode(); + + /// + /// Changes the current mode into Edit + /// + [Obsolete('Switching between edit more and view mode is no longer supported. Only view mode will be supported going forward.', '25.0')] + procedure EditMode(); + + /// + /// Initializes the Power BI embed Report into the page + /// + [Obsolete('Call the procedure SetToken, and then use EmbedPowerBIReport instead.', '25.0')] + procedure EmbedReport(ReportLink: Text; ReportId: Text; AuthToken: Text; PageName: Text); + + /// + /// Initializes the Power BI embed Dashboard into the page + /// + [Obsolete('Call the procedure SetToken, and then use EmbedPowerBIDashboard instead.', '25.0')] + procedure EmbedDashboard(DashboardLink: Text; DashboardId: Text; AuthToken: Text); + + /// + /// Initializes the Power BI embed Dashboard Tile into the page + /// + [Obsolete('Call the procedure SetToken, and then use the EmbedPowerBIDashboardTile instead.', '25.0')] + procedure EmbedDashboardTile(DashboardTileLink: Text; DashboardId: Text; TileId: Text; AuthToken: Text); + + /// + /// Initializes the Power BI embed Report Visual into the page + /// + [Obsolete('Call the procedure SetToken, and then use EmbedPowerBIReportVisual instead.', '25.0')] + procedure EmbedReportVisual(ReportVisualLink: Text; ReportId: Text; PageName: Text; VisualName: Text; AuthToken: Text); +#endif } diff --git a/src/System Application/App/Resources/PowerBIManagement/js/PowerBIManagement.js b/src/System Application/App/Resources/PowerBIManagement/js/PowerBIManagement.js index fde3eb6bae..2b2c7a5387 100644 --- a/src/System Application/App/Resources/PowerBIManagement/js/PowerBIManagement.js +++ b/src/System Application/App/Resources/PowerBIManagement/js/PowerBIManagement.js @@ -9,20 +9,13 @@ var embed = null; var activePage = null; -var fullPageMode = false; - +var settingsObject = null; var models = null; -var embedWidth = null; -var embedHeight = null; -var manifestWidth = null; -var manifestHeight = null; +var pbiAuthToken = null; function Initialize() { models = window['powerbi-client'].models; - var controlAddInElement = document.getElementById('controlAddIn'); - manifestWidth = controlAddInElement.offsetWidth; - manifestHeight = controlAddInElement.offsetHeight; RaiseAddInReady(); } @@ -56,26 +49,106 @@ function RaiseReportVisualLoaded(correlationId) { Microsoft.Dynamics.NAV.InvokeExtensibilityMethod('ReportVisualLoaded', [correlationId]); } -// Exposed Functions +// Obsolete Functions function InitializeReport(reportLink, reportId, authToken, powerBIEnv) { // OBSOLETE EmbedReport(reportLink, reportId, authToken, ''); } +function EmbedReportWithOptions(reportLink, reportId, authToken, pageName, showPanes) { + // OBSOLETE + EmbedReport(reportLink, reportId, authToken, pageName) +} + function EmbedReport(reportLink, reportId, authToken, pageName) { - // OBSOLETE - EmbedReportWithOptions(reportLink, reportId, authToken, pageName, false) + // OBSOLETE + pbiAuthToken = authToken; + EmbedPowerBIReport(reportLink, reportId, pageName); } -function EmbedReportWithOptions(reportLink, reportId, authToken, pageName, showPanes) { +function EmbedDashboard(dashboardLink, dashboardId, authToken) { + // OBSOLETE + pbiAuthToken = authToken; + EmbedPowerBIDashboard(dashboardLink, dashboardId); +} + +function EmbedDashboardTile(dashboardTileLink, dashboardId, tileId, authToken) { + // OBSOLETE + pbiAuthToken = authToken; + EmbedPowerBIDashboardTile(dashboardTileLink, dashboardId, tileId); +} + +function EmbedReportVisual(reportVisualLink, reportId, pageName, visualName, authToken) { + // OBSOLETE + pbiAuthToken = authToken; + EmbedPowerBIReportVisual(reportVisualLink, reportId, pageName, visualName); +} + +function ViewMode() { + // OBSOLETE + embed.switchMode('View').catch(function (error) { + ProcessError('ViewMode', error); + }); +} + +function EditMode() { + // OBSOLETE + embed.switchMode('Edit').catch(function (error) { + ProcessError('EditMode', error); + }); +} + +function InitializeFrame(fullpage, ratio) { + // OBSOLETE + settingsObject = { + panes: { + bookmarks: { + visible: false + }, + fields: { + visible: fullpage, + expanded: false + }, + filters: { + visible: fullpage, + expanded: fullpage + }, + pageNavigation: { + visible: fullpage + }, + selection: { + visible: fullpage + }, + syncSlicers: { + visible: fullpage + }, + visualizations: { + visible: fullpage, + expanded: false + } + }, + + background: models.BackgroundType.Transparent, + + layoutType: models.LayoutType.Custom, + customLayout: { + displayOption: models.DisplayOption.FitToPage + } + } +} + +// Exposed Functions + +function EmbedPowerBIReport(reportLink, reportId, pageName) { ClearEmbedGlobals(); + ValidatePowerBIHost(reportLink); - var embedConfiguration = InitializeEmbedConfig(authToken, showPanes); + var embedConfiguration = InitializeEmbedConfig(); embedConfiguration.type = 'report'; embedConfiguration.id = SanitizeId(reportId); embedConfiguration.embedUrl = reportLink; - if (pageName && (pageName != '')){ + if (pageName && (pageName != '')) { embedConfiguration.pageName = pageName; } DisplayEmbed(embedConfiguration); @@ -89,36 +162,36 @@ function EmbedReportWithOptions(reportLink, reportId, authToken, pageName, showP var pageFilters = null; var embedCorrelationId = null; - var promises = - [ - embed.getCorrelationId().then(function (correlationId) { - embedCorrelationId = correlationId; - }), - - embed.getPages().then(function (pages) { - var pagesArray = pages.reduce(ReduceByNameFunction, []); - reportPages = JSON.stringify(pagesArray); - }), - - embed.getFilters().then(function (filters) { - reportFilters = JSON.stringify(filters); - }), - - embed.getActivePage().then(function (page) { - activePage = page; - return page.getFilters().then(function (filters) { - pageFilters = JSON.stringify(filters); - }); - }) - ] + var promises = + [ + embed.getCorrelationId().then(function (correlationId) { + embedCorrelationId = correlationId; + }), + + embed.getPages().then(function (pages) { + var pagesArray = pages.reduce(ReduceByNameFunction, []); + reportPages = JSON.stringify(pagesArray); + }), + + embed.getFilters().then(function (filters) { + reportFilters = JSON.stringify(filters); + }), + + embed.getActivePage().then(function (page) { + activePage = page; + return page.getFilters().then(function (filters) { + pageFilters = JSON.stringify(filters); + }); + }) + ] Promise.all(promises).then( - function (values) { - RaiseReportLoaded(reportFilters, reportPages, pageFilters, embedCorrelationId); - }, - function (error) { - ProcessError('LoadReportDetails', error); - }); + function (values) { + RaiseReportLoaded(reportFilters, reportPages, pageFilters, embedCorrelationId); + }, + function (error) { + ProcessError('LoadReportDetails', error); + }); }); embed.off("pageChanged"); @@ -127,16 +200,17 @@ function EmbedReportWithOptions(reportLink, reportId, authToken, pageName, showP activePage.getFilters().then(function (filters) { RaiseReportPageChanged(activePage.name, JSON.stringify(filters)); }, - function (error) { - ProcessError('LoadPageFilters', error); - }); + function (error) { + ProcessError('LoadPageFilters', error); + }); }); } -function EmbedDashboard(dashboardLink, dashboardId, authToken) { +function EmbedPowerBIDashboard(dashboardLink, dashboardId) { ClearEmbedGlobals(); - - var embedConfiguration = InitializeEmbedConfig(authToken, false); + ValidatePowerBIHost(dashboardLink); + + var embedConfiguration = InitializeEmbedConfig(); embedConfiguration.type = 'dashboard'; embedConfiguration.id = SanitizeId(dashboardId); embedConfiguration.embedUrl = dashboardLink; @@ -149,19 +223,20 @@ function EmbedDashboard(dashboardLink, dashboardId, authToken) { embed.getCorrelationId().then(function (correlationId) { RaiseDashboardLoaded(correlationId); }, - function (error) { - ProcessError('LoadDashboardCorrelationId', error); - }); + function (error) { + ProcessError('LoadDashboardCorrelationId', error); + }); }); } -function EmbedDashboardTile(dashboardTileLink, dashboardId, tileId, authToken) { +function EmbedPowerBIDashboardTile(dashboardTileLink, dashboardId, tileId) { ClearEmbedGlobals(); - - var embedConfiguration = InitializeEmbedConfig(authToken, false); + ValidatePowerBIHost(dashboardTileLink); + + var embedConfiguration = InitializeEmbedConfig(); embedConfiguration.type = 'tile'; embedConfiguration.id = SanitizeId(tileId); - embedConfiguration.dashboardId = SanitizeId(dashboardId); + embedConfiguration.dashboardId = SanitizeId(dashboardId); embedConfiguration.embedUrl = dashboardTileLink; DisplayEmbed(embedConfiguration); @@ -172,16 +247,17 @@ function EmbedDashboardTile(dashboardTileLink, dashboardId, tileId, authToken) { embed.getCorrelationId().then(function (correlationId) { RaiseDashboardTileLoaded(correlationId); }, - function (error) { - ProcessError('LoadDashboardTileCorrelationId', error); - }); + function (error) { + ProcessError('LoadDashboardTileCorrelationId', error); + }); }); } -function EmbedReportVisual(reportVisualLink, reportId, pageName, visualName, authToken) { +function EmbedPowerBIReportVisual(reportVisualLink, reportId, pageName, visualName) { ClearEmbedGlobals(); + ValidatePowerBIHost(reportVisualLink); - var embedConfiguration = InitializeEmbedConfig(authToken, false); + var embedConfiguration = InitializeEmbedConfig(); embedConfiguration.type = 'visual'; embedConfiguration.id = SanitizeId(reportId); embedConfiguration.pageName = SanitizeId(pageName); @@ -196,21 +272,9 @@ function EmbedReportVisual(reportVisualLink, reportId, pageName, visualName, aut embed.getCorrelationId().then(function (correlationId) { RaiseReportVisualLoaded(correlationId); }, - function (error) { - ProcessError('LoadReportVisualCorrelationId', error); - }); - }); -} - -function ViewMode() { - embed.switchMode('View').catch(function (error) { - ProcessError('ViewMode', error); - }); -} - -function EditMode() { - embed.switchMode('Edit').catch(function (error) { - ProcessError('EditMode', error); + function (error) { + ProcessError('LoadReportVisualCorrelationId', error); + }); }); } @@ -262,42 +326,63 @@ function SetPage(pageName) { }); } -function InitializeFrame(fullpage, ratio){ - fullPageMode = fullpage; - if (!ratio) ratio = '16:9'; // Default according to Power BI documentation - - var iframe = window.frameElement; +function SetToken(authToken) { + pbiAuthToken = authToken; +} - var maximumAllowedHeight = manifestHeight; - var maximumAllowedWidth = manifestWidth; - if (fullPageMode) { - // When opening a report fullscreen, maximize the real estate instead - iframe.style.removeProperty('max-height'); - iframe.style.removeProperty('max-width'); - maximumAllowedHeight = 720; - maximumAllowedWidth = 1280; +function SetSettings(showBookmarkSelection, showFilters, showPageSelection, showZoomBar, forceTransparentBackground, forceFitToPage, addBottomPadding) { + if (addBottomPadding) { + var iframe = window.frameElement; + iframe.style.paddingBottom = '42px'; + } + else { + var iframe = window.frameElement; + iframe.style.removeProperty('paddingBottom'); } - var arr = ratio.split(":"); - var ratioWidth = arr[0]; - var ratioHeight = arr[1]; - - var computedWidth = (maximumAllowedHeight / ratioHeight) * ratioWidth; - var computedHeight = (maximumAllowedWidth / ratioWidth) * ratioHeight; + settingsObject = { + panes: { + bookmarks: { + visible: showBookmarkSelection + }, + filters: { + visible: showFilters, + expanded: false + }, + pageNavigation: { + visible: showPageSelection + }, + fields: { // In edit mode, allows selecting fields to add to the report + visible: false + }, + selection: { // In edit mode, allows selecting visuals from a list instead of clicking in the UI + visible: false + }, + syncSlicers: { // In edit mode, allows syncing slicers through pages + visible: false + }, + visualizations: { // In edit mode, allows adding new visualizations + visible: false + } + }, - if (computedWidth <= maximumAllowedWidth) { - // Fit to width - embedWidth = computedWidth; - embedHeight = maximumAllowedHeight; + bars: { + statusBar: { + visible: showZoomBar + } + } } - else { - // Fit to height instead - embedWidth = maximumAllowedWidth; - embedHeight = computedHeight; + + if (forceTransparentBackground) { + settingsObject.background = models.BackgroundType.Transparent; } - iframe.style.height = Math.floor(embedHeight).toString() + 'px'; - iframe.style.width = Math.floor(embedWidth).toString() + 'px'; + if (forceFitToPage) { + settingsObject.layoutType = models.LayoutType.Custom; + settingsObject.customLayout = { + displayOption: models.DisplayOption.FitToPage + } + } } // Internal functions @@ -307,48 +392,18 @@ function ClearEmbedGlobals() { activePage = null; } -function InitializeEmbedConfig(authToken, showPanes) { +function InitializeEmbedConfig() { + if (!pbiAuthToken || (pbiAuthToken == '')) { + RaiseErrorOccurred('Initialize Config', 'No token was provided'); + } + var embedConfiguration = { tokenType: models.TokenType.Aad, - accessToken: authToken, + accessToken: pbiAuthToken, viewMode: models.ViewMode.View, permissions: models.Permissions.All, - settings: { - panes: { - bookmarks: { - visible: false - }, - fields: { - visible: fullPageMode && showPanes, - expanded: false - }, - filters: { - visible: fullPageMode && showPanes, - expanded: fullPageMode && showPanes - }, - pageNavigation: { - visible: showPanes - }, - selection: { - visible: fullPageMode && showPanes - }, - syncSlicers: { - visible: fullPageMode && showPanes - }, - visualizations: { - visible: fullPageMode && showPanes, - expanded: false - } - }, - - background: models.BackgroundType.Transparent, - - layoutType: models.LayoutType.Custom, - customLayout: { - displayOption: models.DisplayOption.FitToPage - } - } + settings: settingsObject }; return embedConfiguration; @@ -367,7 +422,7 @@ function DisplayEmbed(embedConfiguration) { embed = powerbi.embed(reportContainer, embedConfiguration); } -function RegisterCommonEmbedEvents(){ +function RegisterCommonEmbedEvents() { embed.off("error"); embed.on("error", function (event) { ProcessError('OnError', event); @@ -379,7 +434,7 @@ function ReduceByNameFunction(accumulator, current) { return accumulator; } -function SanitizeId(id){ +function SanitizeId(id) { // From: {79a5e047-a665-4c83-900b-f5ccf19e01c7} // To: 79a5e047-a665-4c83-900b-f5ccf19e01c7 return id.replace(/[{}]/g, ""); @@ -402,14 +457,23 @@ function LogErrorToConsole(operation, error) { console.error(error); } -function GetErrorMessage(error){ - if (error && error.message){ +function GetErrorMessage(error) { + if (error && error.message) { return error.message; } - if (error && error.detail && error.detail.message){ + if (error && error.detail && error.detail.message) { return error.detail.message; } - return ''; + return error.toString(); +} + +function ValidatePowerBIHost(embedUrl) { + var urlHost = GetHost(embedUrl); + if (!urlHost.endsWith(".powerbi.com") && !urlHost.endsWith('.analysis-df.windows.net')) { + var errorMsg = 'The host "' + urlHost + '" is not a valid Power BI host.'; + ProcessError('InvalidHost', errorMsg); + throw new Error(errorMsg); + } } diff --git a/src/System Application/App/Resources/PowerBIManagement/stylesheets/PowerBIManagement.css b/src/System Application/App/Resources/PowerBIManagement/stylesheets/PowerBIManagement.css index 43f2ed5c89..de33c0b414 100644 --- a/src/System Application/App/Resources/PowerBIManagement/stylesheets/PowerBIManagement.css +++ b/src/System Application/App/Resources/PowerBIManagement/stylesheets/PowerBIManagement.css @@ -1,4 +1,4 @@ iframe { border-style: none; - background-color: white; + background-color: transparent; } \ No newline at end of file