akshay5995 / powerbi-report-component

Easily embed your Microsoft PowerBI Report, Dashbord or Tile in your React App
http://akshay5995.github.io/powerbi-report-component
MIT License
55 stars 30 forks source link
dashboard embed filter fullscreen microsoft-powerbi-report powerbi powerbi-client powerbi-embedded powerbi-report props react report-visuals reports tile

PowerBI Report Component

downloads license vulnerabilities bundlephobia

It's a minimalistic React component for embedding a Microsoft PowerBI report, dashboard or tile into your React application.

Installation

npm i powerbi-report-component

Usage for Report

import React, {Component} from 'react';
import { Report } from 'powerbi-report-component';

class MyComponent extends Component {
  constructor(props) {
    super(props);
    this.report = null; // to store the loaded report's object to perform operations like print, full screen etc..
  }
  ...
  handleDataSelected = (data) => {
    // will be called when some chart or data element in your report clicked
  }

  handleReportLoad = (report) => {
    // will be called when report loads:
    // - scripts and data received from server, visuals are rendered on the browser
    // - flickering Power BI logo stops appearing but report is not fully ready to be consumed

    this.report = report; // get the report object from callback and store it.(optional)
  }

  handleReportRender = (report) => {
    // will be called when report renders:
    // - visuals finish rendering
    // - report is fully visible and ready for consumption

    this.report = report; // get the report object from callback and store it.(optional)
  }

  handlePageChange = (data) => {
    // will be called when pages in your report changes
  }

  handleTileClicked = (data) => {
    console.log('Data from tile', data);
  }

  render() {
    const reportStyle = {
        // style object for report component
    };
    const extraSettings = {
            filterPaneEnabled: false, //true
            navContentPaneEnabled: false, //true
            hideErrors: false // Use this *only* when you want to override error experience i.e, use onError
            // ... more custom settings
    };
    return (
    <div className="root">
        <Report
            tokenType="Embed" // "Aad"
            accessToken="" // accessToken goes here
            embedUrl="" // embedUrl goes here
            embedId="" // report or dashboard Id goes here
            pageName="" // set as current page of the report. Name to be obtained from the original report URL
            reportMode="View" // open report in a particular mode View/Edit/Create
            datasetId={datasetId} // required for reportMode = "Create" and optional for dynamic databinding in `report` on `View` mode
            groupId={groupId} // optional. Used when reportMode = "Create" and to chose the target workspace when the dataset is shared. 
            extraSettings={extraSettings}
            permissions="All" // View, For "Edit" mode permissions should be "All"
            style={reportStyle}
            onLoad={this.handleReportLoad}
            onRender={this.handleReportRender} // not allowed in "Create" mode
            onSelectData={this.handleDataSelected}
            onPageChange={this.handlePageChange}
            onTileClicked={this.handleTileClicked}
            onSave={this.handleReportSave} // works for "Edit" and "Create"
        />
    </div>
    );
  }
}

Visit here for more details on creating reports with shared dataset

Usage for Dashboard

import { Dashboard } from 'powerbi-report-component';

// inside render
<Dashboard
  tokenType={tokenType}
  accessToken={accessToken}
  embedUrl={embedUrl}
  embedId={embedId}
  style={style} // style object for dashboard component
  pageView={pageView} // 'fitToWidth' (default) , 'oneColumn', 'actualSize'
  onLoad={(dashboard) => {
    console.log('Dashboard Loaded!');
    this.dashboard = dashboard; // get the dashboard object from callback and store it.(optional)
  }}
  onTileClicked={(data) => {
    console.log('Data from tile', data);
  }}
/>

Usage for Tile

import { Tile } from 'powerbi-report-component';

// inside render
<Tile
  tokenType={tokenType}
  accessToken={accessToken}
  embedUrl={embedUrl}
  embedId={embedId}
  dashboardId={dashboardId}
  style={style} // style for tile component
  onClick={(data) => {
    console.log('Data from tile', data);
  }}
  onLoad={(data) => {
    console.log('Tile loaded', data);
  }}
/>

Usage for ReportVisual

import { ReportVisual } from 'powerbi-report-component';

// inside render
<ReportVisual
  tokenType={tokenType}
  accessToken={accessToken}
  embedUrl={embedUrl}
  embedId={embedId}
  pageName={pageName}
  visualName={visualName}
  style={style} // style for report visual component
  onSelectData={(data) => {
    console.log('Data from ReportVisual', data);
  }}
  onLoad={(reportVisual) => {
    console.log('ReportVisual loaded', data);
  }}
  onRender={(reportVisual) => {
    console.log('ReportVisual rendered', reportVisual);
  }}
/>

Like hooks ? You'll love this :)

useReport

Provides a more fine grained approach for embedding. (where you're in control)

import React, { useEffect, useRef } from 'react';
import { useReport } from 'powerbi-report-component';

const MyReport = ({ accessToken, embedUrl, embedId }) => {
  const reportRef = useRef(null);
  const [report, embed] = useReport();

  const myReportConfig = {
    embedType: 'report',
    tokenType: 'Embed',
    accessToken: accessToken,
    embedUrl: embedUrl,
    embedId: embedId,
    reportMode: "View", // "Edit"
    permissions: "View", // "All" (when using "Edit" mode)
    extraSettings: {
      filterPaneEnabled: false,
      navContentPaneEnabled: false,
    },
  };

  // important
  useEffect(() => {
    // call inside useEffect so the we have the reportRef (reference available)
    embed(reportRef, myReportConfig);
  }, []);

  const handleClick = () => {
    // you can use "report" from useReport like
    if (report) report.print();
  };

  return (
    <div className="report-container">
      <div className="report" ref={reportRef} />
      <button onClick={handleClick}>Print my report</button>
    </div>
  );
};

export default MyReport;

Passing in custom layout for useReport hook.

Example is taken from powerbi js wiki: Custom-Layout.

import { models } from 'powerbi-client'; // Import from the dependency

// Example layout config 
const layoutSettings = {
  layoutType: models.LayoutType.Custom,
  customLayout: {
    pageSize: {
      type: models.PageSizeType.Custom,
      width: 1600,
      height: 1200,
    },
    displayOption: models.DisplayOption.ActualSize,
    pagesLayout: {
      ReportSection1: {
        defaultLayout: {
          displayState: {
            mode: models.VisualContainerDisplayMode.Hidden,
          },
        },
        visualsLayout: {
          VisualContainer1: {
            x: 1,
            y: 1,
            z: 1,
            width: 400,
            height: 300,
            displayState: {
              mode: models.VisualContainerDisplayMode.Visible,
            },
          },
          VisualContainer2: {
            displayState: {
              mode: models.VisualContainerDisplayMode.Visible,
            },
          },
        },
      },
    },
  },
};

// Create your config
const myReportConfig = {
  embedType: 'report',
  tokenType: 'Embed',
  accessToken: accessToken,
  embedUrl: embedUrl,
  embedId: embedId,
  extraSettings: {
    filterPaneEnabled: false,
    navContentPaneEnabled: false,
    ...layoutSettings, // layout config
  },
};

// Inside your component
useEffect(() => {
  embed(reportRef, myReportConfig);
}, []);

useBootstrap

Provided performance gains on loading in an async way

import React, { useEffect, useRef } from 'react';
import { useBootstrap } from 'powerbi-report-component';

// Your configuration from server
const simulateAjaxCall = () => new Promise(function(resolve) {
  setTimeout(resolve.bind(null, {
    accessToken: "accessToken",
    embedUrl: "embedUrl",
    embedId: "embedId",
    reportMode: "View", // "Edit"
    permissions: "View", // "All" (when using "Edit" mode)
  }), 3000)
});

const MyReport = ({ accessToken, embedUrl, embedId }) => {
  const reportRef = useRef(null);
  const [report, bootstrap, embed] = useBootstrap();

  const initialReportConfig = {
    embedType: 'report',
    tokenType: 'Embed',
    extraSettings: {
      filterPaneEnabled: false,
      navContentPaneEnabled: false,
    },
  };

  const getMyConfigurationFromServer = () => {
    simulateAjaxCall().then(data => {
      // Embed the report once your configuration is received 
      embed(reportRef, {...initialReportConfig, ...data});
    });
  }

  // important
  useEffect(() => {
    // call inside useEffect so the we have the reportRef (reference available)
    bootstrap(reportRef, initialReportConfig);
  }, []);

  return (
    <div className="report-container">
      <div className="report" ref={reportRef} />
      <button onClick={getMyConfiguraionFromServer}>Get config from AJAX call</button>
    </div>
  );
};

export default MyReport;

Report features and props you can pass into the component

Inside your component where you're using { Report } component.

Constructor:

  ...
  constructor(props) {
    super(props);
    this.report = null; //used to store value of returned report object
  }
  ....

Callback passed to the onLoad or onRender prop

  handleReportLoad = (report) => {
    this.report = report; // get the report object from callback and store it.
  }

  handleReportRender = (report) => {
    this.report = report; // get the report object from callback and store it.
  }
  ...

using the this.report to perform operations

  ...

  setFullscreen = () => {
    if(this.report) this.report.fullscreen();
  }

  printReport = () => {
    if(this.report) this.report.print();
  }

  ...

  //Inside render

  <button onClick={this.setFullscreen}>Fullscreen</button>
  <button onClick={this.printReport}>Print</button>

  ...

For Report Level Filters:

  /*
    Example filter object used in microsoft's demo page:

    const filter = {
        $schema: "http://powerbi.com/product/schema#basic",
        target: {
          table: "Store",
          column: "Chain"
        },
        operator: "In",
        values: ["Lindseys"]
      };
  */
  ...

  setFilter = (filter) => this.report.setFilters([filter]).catch(function (errors) {
        console.log(errors);
    });

  getFilter = () => this.report.getFilters().then(function (filters) {
          console.log(filters);
      }).catch(function (errors) {
          console.log(errors);
      });

  removeFilters = () => this.report.removeFilters()
      .catch(function (errors) {
          console.log(errors);
      });

  ...

Report Page Change

  onPageChange={(data) =>
    console.log(`Page name :{data.newPage.displayName}`)
  }

Report Load

  onLoad={(report) => {
    console.log('Report Loaded!');
    this.report = report;
    }
  }
  onSave={(data) => {
    console.log('Report Saved! Event data: '+data);
    }
  }

Report Render

  onRender={(report) => {
    console.log('Report Rendered!');
    this.report = report;
    }
  }

Report Button Clicked

  onButtonClicked={(data) => {
    console.log(`Button ${data.title} of type ${data.type} Clicked!`);
    }
  }

Report Command Triggered

  onCommandTriggered={(extensionCommand) => {
    console.log('Extension Command Triggered!');
    }
  }

Report Data Element Clicked

  onSelectData={(data) =>
    console.log(`You clicked on chart: ${data.visual.title}`);
  }

Report Handle Errors

  onError={(data) =>
     console.log(`Error: ${data}`);
  }

Use ‘report’ object returned to parent component or from useReport for:

Note: you wouldn't use this if you're using report from useReport hook.

  1. Change Report Mode to View or Edit:
//mode can be "View" or "Edit"

changeMode = (mode) => this.report.switchMode(mode);
  1. Fullscreen
setFullscreen = () => this.report.fullscreen();
  1. Print Report
printReport = () => this.report.print();
  1. Set Filters
    //example filter from microsoft's demo page

    const filter = {
      $schema: "http://powerbi.com/product/schema#basic",
      target: {
        table: "Store",
        column: "Chain"
      },
      operator: "In",
      values: ["Lindseys"]
    };

    // using event handlers

    setFilter = (filter) => this.report.setFilters([filter]).catch(function (errors) {
      console.log(errors);
    });

    // during onload

    onLoad = (report) => {
      report.setFilters([filter]).catch(function (errors) {
        console.log(errors);
      });
      this.report = report;
    }
  }
  1. Get Filters
getFilter = () =>
  this.report
    .getFilters()
    .then(function (filters) {
      console.log(filters);
    })
    .catch(function (errors) {
      console.log(errors);
    });
  1. Remove Filters
removeFilters = () =>
  this.report.removeFilters().catch(function (errors) {
    console.log(errors);
  });
  1. Save edited report when in "Edit" mode

(note: you need to have enough permissions to save the report)

    async saveReport() {
    if (this.report) {
      try{
        await this.report.save();
      } catch (err) {
        console.log("Error saving report", err);
      }
    }
  }
  1. Show / Hide all visual headers:
toggleAllVisualHeaders = (bool) => {
  const newSettings = {
    visualSettings: {
      visualHeaders: [
        {
          settings: {
            visible: bool, // boolean variable
          },
        },
      ],
    },
  };
  this.report
    .updateSettings(newSettings)
    .then(function () {
      console.log('Visual header toggle successful.');
    })
    .catch(function (errors) {
      console.log(errors);
    });
};

Dashboard features and props you can pass into the component

Dashboard Load

  onLoad={(dashboard) => {
    console.log('Report Loaded!');
    this.dashboard = dashboard;
    }
  }

Dashboard Tile Click

onTileClicked = {(data) => {
  console.log('Data from tile', data);
}}

Use dashboard object returned to parent component for:

  1. Fullscreen
setFullscreen = () => this.dashboard.fullscreen();

Tile features and props you can pass into the component

Tile Load

  onLoad={(data) => {
    console.log('Data from tile', data);
  }}

Tile Click

onClick = {(data) => {
    console.log('Data from tile', data);
}}

For playground visit:

http://akshay5995.github.io/powerbi-report-component

You can find out how to generate token for your report using Powershell from this video.

Alternatives

  1. https://github.com/microsoft/powerbi-client-react bundlephobia