import * as React from 'react' ; import { service , factories , Report , Embed , Dashboard , Tile , Qna , Visual , IEmbedSettings , IEmbedConfiguration , IQnaEmbedConfiguration , IVisualEmbedConfiguration , IReportEmbedConfiguration , IDashboardEmbedConfiguration , ITileEmbedConfiguration , } from 'powerbi-client' ; import { ReportLevelFilters } from 'powerbi-models' ; import isEqual from 'lodash.isequal' ; import { stringifyMap } from './utils' ; /**
 * Type for event handler function of embedded entity
 */ export type EventHandler = { ( event ? , embeddedEntity ? ) : void | null ; } ; /**
 * Props interface for PowerBIEmbed component
 */ export interface EmbedProps { embedConfig : IReportEmbedConfiguration | IDashboardEmbedConfiguration | ITileEmbedConfiguration | IQnaEmbedConfiguration | IVisualEmbedConfiguration | IEmbedConfiguration ; getEmbeddedComponent ? : { ( embeddedComponent ) : void ; } ; eventHandlers ? : Map < string , EventHandler > ; cssClassName ? : string ; phasedEmbedding ? : boolean ; service ? : service . Service ; } export enum EmbedType { Report = 'report' , Dashboard = 'dashboard' , Tile = 'tile' , Qna = 'qna' , Visual = 'visual' } /**
 * Base react component to embed Power BI entities like: reports, dashboards, tiles, visual and qna containers.
 */ export class PowerBIEmbed extends React . Component < EmbedProps > { private _embed ? : Embed ; private powerbi : service . Service ; private containerRef = React . createRef < HTMLDivElement > ( ) ; private prevEventHandlerMapString = '' ; private get embed ( ) : Embed | undefined { return this . _embed ; } ; private set embed ( newEmbedInstance ) { this . _embed = newEmbedInstance ; this . invokeGetEmbedCallback ( ) ; } ; constructor ( props ) { super ( props ) ; if ( this . props . service ) { this . powerbi = this . props . service ; } else { this . powerbi = new service . Service ( factories . hpmFactory , factories . wpmpFactory , factories . routerFactory ) ; } } ; componentDidMount ( ) { if ( this . containerRef . current ) { if ( this . props . embedConfig . accessToken && this . props . embedConfig . embedUrl ) { this . embedEntity ( ) ; } else { this . embed = this . powerbi . bootstrap ( this . containerRef . current , this . props . embedConfig ) ; } } if ( this . props . eventHandlers && this . embed ) { this . setEventHandlers ( this . embed , this . props . eventHandlers ) ; } } ; async componentDidUpdate ( prevProps ) { this . embedOrUpdateAccessToken ( prevProps ) ; if ( this . props . eventHandlers && this . embed ) { this . setEventHandlers ( this . embed , this . props . eventHandlers ) ; } if ( ! isEqual ( this . props . embedConfig . settings , prevProps . embedConfig . settings ) ) { await this . updateSettings ( ) ; } if ( this . props . embedConfig . type === EmbedType . Report ) { try { const embedConfig = this . props . embedConfig as IReportEmbedConfiguration ; const filters = embedConfig . filters as ReportLevelFilters [ ] ; const prevEmbedConfig = prevProps . embedConfig as IReportEmbedConfiguration ; if ( embedConfig . pageName && embedConfig . pageName !== prevEmbedConfig . pageName ) { await ( this . embed as Report ) . setPage ( embedConfig . pageName ) ; } if ( filters && ! isEqual ( filters , prevEmbedConfig . filters ) ) { await ( this . embed as Report ) . setFilters ( filters ) ; } else if ( ! filters && prevEmbedConfig . filters ) { await ( this . embed as Report ) . removeFilters ( ) ; } } catch ( err ) { console . error ( err ) ; } } } ; componentWillUnmount ( ) { if ( this . containerRef . current ) { this . powerbi . reset ( this . containerRef . current ) ; } } ; render ( ) { return ( < div ref = { this . containerRef } className = { this . props . cssClassName } > < /div>); } ; /**
     * Embed the powerbi entity (Load for phased embedding)
     */ private embedEntity ( ) { if ( ! this . containerRef . current ) { return ; } if ( this . props . phasedEmbedding && this . props . embedConfig . type === EmbedType . Report ) { this . embed = this . powerbi . load ( this . containerRef . current , this . props . embedConfig ) ; } else { if ( this . props . phasedEmbedding ) { console . error ( `Phased embedding is not supported for type ${ this . props . embedConfig . type }` ) ; } this . embed = this . powerbi . embed ( this . containerRef . current , this . props . embedConfig ) ; } } param prevProps returns private embedOrUpdateAccessToken ( prevProps ) { if ( ! this . props . embedConfig . accessToken || ! this . props . embedConfig . embedUrl ) { return ; } if ( this . containerRef . current && ( ! prevProps . embedConfig . accessToken || this . props . embedConfig . embedUrl !== prevProps . embedConfig . embedUrl ) ) { this . embedEntity ( ) ; } else if ( this . props . embedConfig . accessToken !== prevProps . embedConfig . accessToken && this . props . embedConfig . embedUrl === prevProps . embedConfig . embedUrl && this . embed ) { this . embed . setAccessToken ( this . props . embedConfig . accessToken ) . catch ( ( error ) => { console . error ( `setAccessToken error: ${ error }` ) ; } ) ; } } param embed param eventHandlers returns private setEventHandlers ( embed , eventHandlerMap ) { const eventHandlerMapString = stringifyMap ( this . props . eventHandlers ) ; if ( this . prevEventHandlerMapString === eventHandlerMapString ) { return ; } this . prevEventHandlerMapString = eventHandlerMapString ; let allowedEvents = Embed . allowedEvents ; const entityType = embed . embedtype ; switch ( entityType ) { case EmbedType . Report : allowedEvents = [ ... allowedEvents , ... Report . allowedEvents ] ; break ; case EmbedType . Dashboard : allowedEvents = [ ... allowedEvents , ... Dashboard . allowedEvents ] ; break ; case EmbedType . Tile : allowedEvents = [ ... allowedEvents , ... Tile . allowedEvents ] ; break ; case EmbedType . Qna : allowedEvents = [ ... allowedEvents , ... Qna . allowedEvents ] ; break ; case EmbedType . Visual : allowedEvents = [ ... allowedEvents , ... Visual . allowedEvents ] ; break ; default : console . error ( `Invalid embed type ${ entityType }` ) ; } const invalidEvents = [ ] ; eventHandlerMap . forEach ( ( eventHandlerMethod , eventName ) => { if ( allowedEvents . includes ( eventName ) ) { embed . off ( eventName ) ; if ( eventHandlerMethod ) { embed . on ( eventName , ( event ) : void => { eventHandlerMethod ( event , this . embed ) ; } ) ; } } else { invalidEvents . push ( eventName ) ; } } ) ; if ( invalidEvents . length ) { console . error ( `Following events are invalid: ${ invalidEvents . join ( ',' ) }` ) ; } } ; returns private invokeGetEmbedCallback ( ) { if ( this . props . getEmbeddedComponent && this . embed ) { this . props . getEmbeddedComponent ( this . embed ) ; } } ; returns private async updateSettings ( ) { if ( ! this . embed || ! this . props . embedConfig . settings ) { return ; } switch ( this . props . embedConfig . type ) { case EmbedType . Report : { const settings = this . props . embedConfig . settings as IEmbedSettings ; try { await ( this . embed as Report ) . updateSettings ( settings ) ; } catch ( error ) { console . error ( `Error in method updateSettings: ${ error }` ) ; } break ; } case EmbedType . Dashboard : case EmbedType . Tile : case EmbedType . Qna : case EmbedType . Visual : break ; default : console . error ( `Invalid embed type ${ this . props . embedConfig . type }` ) ; } } ; }