1
votes

I am testing a react web app where I can display reports from Power BI. I am using powerbi-client-react to embed the reports. However, I face an issue when I load the component with an expired token, I get this error: Content not available screenshot.

So whenever that happens, I catch it with the error event handler, get a new token and update the powerbi report accessToken. However, it doesn't seem to reload/refresh the embed when I set the new accessToken in react. It only displays the screenshot above.

Error log screenshot.

Is there a way to force refresh the embed component with the new access token? or is my approach not correct? Any mistakes pointer would be appreciated.

import React from 'react';
import {models} from 'powerbi-client';
import {PowerBIEmbed} from 'powerbi-client-react';

// Bootstrap config
let embedConfigTest = {
  type: 'report', // Supported types: report, dashboard, tile, visual and qna
  id: reportId,
  embedUrl: powerBIEmbedURL,
  accessToken: null,
  tokenType: models.TokenType.Embed,
  pageView: 'fitToWidth',
  settings: {
    panes: {
      filters: {
        expanded: false,
        visible: false,
      },
    },
    background: models.BackgroundType.Transparent,
  },
};

const PowerBiReport = ({graphName, ...props}) => {
  let [embedToken, setEmbedToken] = React.useState();
  let [embedConfig, setEmbedConfig] = React.useState(embedConfigTest);

  React.useEffect(
    () => {
      setEmbedToken(EXPIRED_TOKEN);
      setEmbedConfig({
        ...embedConfig,
        accessToken: EXPIRED_TOKEN, // Initiate with known expired token
      });
    },
    [graphName]
  );

  const changeSettings = (newToken) => {
    setEmbedConfig({
      ...embedConfig,
      accessToken: newToken, 
    });
  };

  // Map of event handlers to be applied to the embedding report
  const eventHandlersMap = new Map([
    [
      'loaded',
      function() {
        console.log('Report has loaded');
      },
    ],
    [
      'rendered',
      function() {
        console.log('Report has rendered');
      },
    ],
    [
      'error',
      async function(event, embed) {
        if (event) {
          console.error(event.detail);
          console.log(embed);
          // Simulate getting a new token and update
          setEmbedToken(NEW_TOKEN);
          changeSettings(NEW_TOKEN);
        }
      },
    ],
  ]);

  return (
    <PowerBIEmbed
      embedConfig={embedConfig}
      eventHandlers={eventHandlersMap}
      cssClassName={'report-style-class'}
    />
  );
};

export default PowerBiReport;
2

2 Answers

1
votes

I ended up solving this issue, although not so beautiful.

I checked the powerbi-client wiki as it has dependency on it and found out that you could use embed.reload() in the embed object I get from the error function.

For some reason (I could not find out why), the error handler gets triggered twice, so to avoid refreshing the token twice, I had to create a dialog notifying the user that the token had expired and whenever that dialog is closed, I reload the powerbi report.

Exact wiki reference:

  1. Overriding Error Experience
  2. Reload a report
  3. Update embed token
0
votes

Thanks @vtCode. Here is a sample but the refresh can only happen in 15 secs interval.

import { PowerBIEmbed } from "powerbi-client-react";

export default function PowerBiContainer({ embeddedToken }) {
    const [report, setReport] = useState(null);
    useEffect(() => {
    if (report == null) return;
    report.refresh();
    }, [report, embeddedToken]);

    return (
        <PowerBIEmbed
        embedConfig={{ ...embedConfig, accessToken: embeddedToken }}
        getEmbeddedComponent={(embeddedReport) => setReport(embeddedReport)};
        />
    );
}

Alternatively, you can add the React "key" attribute which remounts the component when embededToken changes

<PowerBIEmbed key={embeddedToken} 
embedConfig={{ ...embedConfig, accessToken: embeddedToken }}
/>