import * as React from 'react'; import * as ReactDOM from 'react-dom'; import * as uuid from 'uuid'; import * as invariant from 'invariant'; import { Component, Input, OnInit, OnDestroy, OnChanges, AfterViewInit, ViewEncapsulation, } from '@angular/core'; import { WindowRef } from '@core/common/global-refs'; import { idRef, areObjRefsEqual } from '@gooddata/sdk-ui-all'; import { Dashboard, IDashboardProps, DashboardDrillToDashboardResolved, DashboardEventHandler, isDashboardDrillToDashboardResolved, changeFilterContextSelection, isDashboardDrillToCustomUrlResolved, DashboardDrillToCustomUrlResolved, isDashboardInitialized, DashboardStoreAccessorRepository, DashboardFilterContextChanged, DashboardRenderResolved, isDashboardFilterContextChanged, } from '@gooddata/sdk-ui-dashboard'; import tigerFactory, { TigerTokenAuthProvider, } from '@gooddata/sdk-backend-tiger'; import { environment } from '@env/environment'; /* GoodData Dashboard Component: https://sdk.gooddata.com/gooddata-ui/docs/dashboard_component.html */ @Component({ selector: 'sp-good-data-dashboard-wrapper', templateUrl: './good-data-dashboard-wrapper.component.html', styleUrls: ['./good-data-dashboard-wrapper.component.scss'], encapsulation: ViewEncapsulation.None, }) export class GoodDataDashboardWrapperComponent implements OnInit, OnDestroy, OnChanges, AfterViewInit { @Input() usertoken!: string; @Input() dashboard!: string; @Input() workspace!: string; public rootDomID!: string; public backend: any; eventHandlers!: DashboardEventHandler[]; stateChange: any; storageName!: string; drillEvent = (null); constructor( private readonly windowRef: WindowRef, ) { } /* eslint-disable @typescript-eslint/no-unnecessary-type-assertion */ public isDrillToSameDashboard = (e: DashboardDrillToDashboardResolved) => !e.payload.drillDefinition.target || areObjRefsEqual(e.payload.drillDefinition.target, e.ctx.dashboardRef!); protected getRootDomNode(): Element | DocumentFragment { const node = document.getElementById(this.rootDomID)!; invariant(node, `Node '${ this.rootDomID }' not found!`); return node; } protected getDashboardProps(): IDashboardProps { const { dashboard, workspace, /* eslint-disable @typescript-eslint/no-unsafe-assignment */ backend, eventHandlers, } = this; return { dashboard: this.drillEvent ? this.drillEvent?.payload.drillDefinition.target : idRef(dashboard), workspace, /* eslint-disable @typescript-eslint/no-unsafe-assignment */ backend, eventHandlers, config: { isReadOnly: true, disableDefaultDrills: false, isWhiteLabeled: true }, // DashboardConfig - https://github.com/gooddata/gooddata-ui-sdk/blob/master/libs/sdk-ui-dashboard/src/model/types/commonTypes.ts onStateChange: this.stateChange, }; } private isMounted(): boolean { return this.rootDomID !== undefined && this.workspace !== undefined && this.dashboard !== undefined && this.usertoken !== undefined; } protected render() { if (this.isMounted()) { this.backend = tigerFactory() .onHostname(environment.GOODDATAURL) .withAuthentication( new TigerTokenAuthProvider(this.usertoken), ); this.storageName = `${ this.usertoken }|${ this.dashboard }`; /** * https://gdui-examples.herokuapp.com/dashboard/drill-to-dashboard */ /* eslint-disable @typescript-eslint/no-unnecessary-type-assertion */ const isDrillToSameDashboard = (e: DashboardDrillToDashboardResolved) => !e.payload.drillDefinition.target || areObjRefsEqual(e.payload.drillDefinition.target, e.ctx.dashboardRef!); this.stateChange = DashboardStoreAccessorRepository.getOnChangeHandlerForDashboard(this.dashboard); if (this.drillEvent) { // Drilled Down Dashboard this.eventHandlers = [{ /* eslint-disable arrow-parens */ eval: (e) => isDashboardInitialized(e), handler: (_, dispatch) => { if (this.drillEvent) { dispatch(changeFilterContextSelection(this.drillEvent.payload.filters)); } }, }, { /* eslint-disable arrow-parens */ eval: (e) => isDashboardDrillToCustomUrlResolved(e), handler: (e: DashboardDrillToCustomUrlResolved) => { // Open url in new tab this.windowRef.nativeWindow.open(e.payload.url, '_blank'); }, }]; } else { this.eventHandlers = [ { /* eslint-disable arrow-parens */ eval: (e) => isDashboardDrillToDashboardResolved(e) && isDrillToSameDashboard(e), handler: (e: DashboardDrillToDashboardResolved, dispatch) => { dispatch(changeFilterContextSelection(e.payload.filters)); }, }, // Handle drill to a different dashboard - propagate the drill event to a local state. { /* eslint-disable arrow-parens */ eval: (e) => isDashboardDrillToDashboardResolved(e) && !isDrillToSameDashboard(e), handler: (e: DashboardDrillToDashboardResolved) => { this.setDrillEvent(e); if (this.rootDomID) { ReactDOM.unmountComponentAtNode(this.getRootDomNode()); } this.render(); }, }, { eval: (e) => isDashboardDrillToCustomUrlResolved(e), handler: (e: DashboardDrillToCustomUrlResolved) => { // Open url in new tab this.windowRef.nativeWindow.open(e.payload.url, '_blank'); }, }, { eval: (e) => isDashboardFilterContextChanged(e), handler: (e: DashboardFilterContextChanged) => { this.updateDataFilter(e); }, }, { eval: (e) => isDashboardInitialized(e), handler: (e: DashboardRenderResolved, dispatch) => { this.retrieveAndSetDataFilters(dispatch); }, }, ]; } ReactDOM.render(React.createElement(Dashboard, this.getDashboardProps()), this.getRootDomNode()); } } ngOnInit() { this.rootDomID = uuid.v1(); } ngOnChanges() { if (this.rootDomID) { ReactDOM.unmountComponentAtNode(this.getRootDomNode()); } this.render(); } ngAfterViewInit() { this.render(); } ngOnDestroy() { // Uncomment if Angular issue that ngOnDestroy is called AFTER DOM node removal is resolved ReactDOM.unmountComponentAtNode(this.getRootDomNode()); } setDrillEvent(e: DashboardDrillToDashboardResolved | null) { this.drillEvent = e; } GoBack() { this.setDrillEvent(null); if (this.rootDomID) { ReactDOM.unmountComponentAtNode(this.getRootDomNode()); } this.render(); } // Save filters updateDataFilter(e: any) { /* eslint-disable @typescript-eslint/no-unsafe-member-access */ localStorage.setItem(this.storageName, JSON.stringify(e.payload.filterContext)); } // Set data filters retrieveAndSetDataFilters(dispatch: any) { let storageValue: any; if (localStorage.getItem(this.storageName) && localStorage.getItem(this.storageName) !== 'undefined') { storageValue = JSON.parse(localStorage.getItem(this.storageName) as string); } if (storageValue !== undefined) { /* eslint-disable @typescript-eslint/no-unsafe-call */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ dispatch(changeFilterContextSelection(storageValue.filters)); } } }