From b47f54da05f1b8637d7189e012160233bf4ef12f Mon Sep 17 00:00:00 2001 From: Satya Date: Wed, 8 Apr 2020 08:20:25 +0530 Subject: [PATCH 1/2] custom theme onload and on report object --- src/docs/Popup.jsx | 23 ++++++++++++++ src/docs/index.jsx | 62 ++++++++++++++++++++++++++++++++++++-- src/docs/styles.css | 59 ++++++++++++++++++++++++++++++++++++ src/docs/utils.js | 23 +++++++++++--- src/lib/config.js | 17 +++++++++-- src/lib/onEmbedHandlers.js | 6 ++-- src/lib/utils.js | 4 ++- 7 files changed, 183 insertions(+), 11 deletions(-) create mode 100644 src/docs/Popup.jsx diff --git a/src/docs/Popup.jsx b/src/docs/Popup.jsx new file mode 100644 index 0000000..13ebdc1 --- /dev/null +++ b/src/docs/Popup.jsx @@ -0,0 +1,23 @@ +import React, { useState } from 'react'; +import './styles.css'; + +const Popup = ({ handleClose, show }) => { + const showHideClassName = show ? "modal display-block" : "modal display-none"; + + const [ text, setText ] = useState(''); + + const handleText = (event) => { + setText(event.target.value); + } + + return ( +
+
+ + +
+
+ ); + }; + + export default Popup; \ No newline at end of file diff --git a/src/docs/index.jsx b/src/docs/index.jsx index 2b48f4b..d04ba93 100644 --- a/src/docs/index.jsx +++ b/src/docs/index.jsx @@ -1,5 +1,3 @@ -/* eslint-disable import/no-extraneous-dependencies */ - import React, { Component, Fragment } from 'react'; import { render } from 'react-dom'; import { CopyToClipboard } from 'react-copy-to-clipboard'; @@ -10,6 +8,7 @@ import 'react-splitter-layout/lib/index.css'; import './styles.css'; import Report from '../lib'; import { initializeState, embedTypes, defaultOptions } from './utils'; +import Popup from './Popup'; class Demo extends Component { constructor(props) { @@ -24,6 +23,9 @@ class Demo extends Component { this.onSelect = this.onSelect.bind(this); this.resetState = this.resetState.bind(this); this.saveReport = this.saveReport.bind(this); + this.showPopup = this.showPopup.bind(this); + this.hidePopup = this.hidePopup.bind(this); + this.resetTheme = this.resetTheme.bind(this); } getCode(view = true) { @@ -38,6 +40,7 @@ class Demo extends Component { pageName, reportMode, datasetId, + theme } = this.state; const viewAccessToken = accessToken && `${accessToken.slice(0, 10)}...`; @@ -71,6 +74,7 @@ class Demo extends Component { dashboardId="${dashboardId}" pageName="${pageName}" reportMode="${reportMode}" // "view" or "edit + theme="${JSON.stringify(theme)}" extraSettings={{ filterPaneEnabled: ${this.state.filterPaneEnabled === 'filter-true'}, @@ -164,6 +168,31 @@ class Demo extends Component { } } + showPopup = () => { + this.setState({ show: true }); + } + + async hidePopup(text) { + if(this.report) { + this.setState({ show: false }); + try { + await this.report.applyTheme({themeJson: JSON.parse(text)}); + } catch(err) { + console.log('error applying theme : '+JSON.stringify(err)); + } + } + } + + async resetTheme() { + if(this.report) { + try { + await this.report.resetTheme(); + } catch(err) { + console.log('error resetting report theme : '+JSON.stringify(err)); + } + } + } + render() { const { embedType, @@ -177,6 +206,8 @@ class Demo extends Component { flag, reportMode, datasetId, + theme, + show, } = this.state; const style = { @@ -226,6 +257,7 @@ class Demo extends Component { style={style.report} reportMode={this.state.reportMode} datasetId={datasetId} + theme={theme || {}} onLoad={report => { console.log('Report Loaded!'); this.report = report; @@ -365,6 +397,17 @@ class Demo extends Component { /> )} + + Custom Theme + + {!isCreateMode && reportFlag && ( @@ -531,6 +574,20 @@ class Demo extends Component { > Save + + )} @@ -548,6 +605,7 @@ class Demo extends Component { +
diff --git a/src/docs/styles.css b/src/docs/styles.css index 01ccc8d..b796100 100644 --- a/src/docs/styles.css +++ b/src/docs/styles.css @@ -122,12 +122,18 @@ input :required { grid-template-columns: 1fr; } +.code { + overflow-wrap: break-word; + word-break: break-word; +} + .code > pre { background: lightgrey; padding: 15px; font-size: 14px; margin: 0; min-height: 300px; + white-space: pre-wrap; } .codeHeader { @@ -177,6 +183,59 @@ footer { text-align: center; } +.config > * >textarea { + width: 90%; + border: 1px solid #bbb; + border-radius: 5px; + flex-wrap: wrap; + overflow-wrap: break-word; + text-overflow: clip; + resize: none; +} + +.modal { + position: fixed; + top: 0; + left: 0; + width:100%; + height: 100%; + background: rgba(0, 0, 0, 0.6); +} + +.modal .modal-main { + position:fixed; + background: white; + width: 50%; + height: auto; + top:50%; + left:50%; + transform: translate(-50%,-50%); + display: flex; + flex-direction: column; + padding: 10px; +} + +.modal-main .themeText { + border: 1px solid #bbb; + border-radius: 5px; + resize: none; +} + +.modal-main button { + align-self: flex-end; + width: 50px; + margin-top: 10px; +} + +.display-block { + display: block; +} + +.display-none { + display: none; +} + + @media only screen and (max-width: 900px) { .code { display: none; diff --git a/src/docs/utils.js b/src/docs/utils.js index 150f29a..ff4a3bc 100644 --- a/src/docs/utils.js +++ b/src/docs/utils.js @@ -1,3 +1,5 @@ +import { defaultEmbedToken, defaultEmbedUrl, defaultReportId } from './defaults'; + const defaultOptions = { report: { mode: 'view', @@ -18,9 +20,9 @@ const embedTypes = Object.keys(defaultOptions); const initializeState = type => ({ embedType: type, tokenType: 'Embed', - accessToken: '', - embedUrl: '', - embedId: '', + accessToken: defaultEmbedToken, + embedUrl: defaultEmbedUrl, + embedId: defaultReportId, pageName: '', dashboardId: '', permissions: 'All', @@ -31,10 +33,23 @@ const initializeState = type => ({ flag: false, reportMode: defaultOptions[type].mode, datasetId: '', + theme: { + "name": "Waveform", + "dataColors": ["#31B6FD", "#4584D3", "#5BD078", "#A5D028", "#F5C040", "#05E0DB", "#3153FD", "#4C45D3", "#5BD0B0", "#54D028", "#D0F540", "#057BE0"], + "background":"#FFFFFF", + "foreground": "#4584D3", + "tableAccent": "#31B6FD" +}, +show: false }); +const isObject = obj => { + return (typeof obj === "object" && obj !== null) || typeof obj === "function"; +} + export { embedTypes, defaultOptions, - initializeState + initializeState, + isObject, }; diff --git a/src/lib/config.js b/src/lib/config.js index 2ec6f99..d03f0bd 100644 --- a/src/lib/config.js +++ b/src/lib/config.js @@ -1,5 +1,5 @@ import { models } from 'powerbi-client'; -import { clean } from "./utils"; +import { clean, isEmpty } from "./utils"; import pbi from 'powerbi-client'; const createConfig = props => { @@ -16,7 +16,9 @@ const createConfig = props => { dashboardId, datasetId, reportMode, + theme, } = props; + if(reportMode === 'create') { return clean({ tokenType: models.TokenType[tokenType], @@ -43,15 +45,26 @@ const createConfig = props => { }, datasetId, reportMode, + theme: !isEmpty(theme)?{themeJson: theme}:null, }); } return null; }; + const validateCustomTheme = config => { + if(config.theme) { + err = pbi.models.validateCustomTheme(config.theme); + if(err) { + return [] + } + } + return []; + }; + const validateTypeConfig = config => { switch (config.type) { case 'report': - return pbi.models.validateReportLoad(config); + return pbi.models.validateReportLoad(config) && validateCustomTheme(config); case 'dashboard': return pbi.models.validateDashboardLoad(config); case 'tile': diff --git a/src/lib/onEmbedHandlers.js b/src/lib/onEmbedHandlers.js index 9abb625..3a2b483 100644 --- a/src/lib/onEmbedHandlers.js +++ b/src/lib/onEmbedHandlers.js @@ -7,11 +7,13 @@ const reportHandler = (report, reportMode, props) => { if(validateMode(reportMode) && reportMode !== "view") { report.switchMode(reportMode); } - validateAndInvokeCallback(props.onLoad, report); + if(props.theme) report.applyTheme(props.theme); }); - report.on('rendered', () => validateAndInvokeCallback(props.onRender, report)); + report.on('rendered', () => { + validateAndInvokeCallback(props.onRender, report); + }); report.on('error', event => validateAndInvokeCallback(props.onError, event.detail)); diff --git a/src/lib/utils.js b/src/lib/utils.js index 115099b..bb2a3e5 100644 --- a/src/lib/utils.js +++ b/src/lib/utils.js @@ -27,4 +27,6 @@ const validateAndInvokeCallback = (callback, data) => { } } -export { clean, validateMode, validateAndInvokeCallback }; +const isEmpty = (obj) => { return Object.keys(obj).length === 0 && obj.constructor === Object}; + +export { clean, validateMode, validateAndInvokeCallback, isEmpty }; From 22146dbd3ae439b5ad7e1d95fa59202579ecb475 Mon Sep 17 00:00:00 2001 From: Satya Date: Wed, 8 Apr 2020 08:24:14 +0530 Subject: [PATCH 2/2] fix docs utils --- src/docs/utils.js | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/src/docs/utils.js b/src/docs/utils.js index ff4a3bc..3149b21 100644 --- a/src/docs/utils.js +++ b/src/docs/utils.js @@ -1,5 +1,3 @@ -import { defaultEmbedToken, defaultEmbedUrl, defaultReportId } from './defaults'; - const defaultOptions = { report: { mode: 'view', @@ -20,9 +18,9 @@ const embedTypes = Object.keys(defaultOptions); const initializeState = type => ({ embedType: type, tokenType: 'Embed', - accessToken: defaultEmbedToken, - embedUrl: defaultEmbedUrl, - embedId: defaultReportId, + accessToken: '', + embedUrl: '', + embedId: '', pageName: '', dashboardId: '', permissions: 'All', @@ -33,13 +31,7 @@ const initializeState = type => ({ flag: false, reportMode: defaultOptions[type].mode, datasetId: '', - theme: { - "name": "Waveform", - "dataColors": ["#31B6FD", "#4584D3", "#5BD078", "#A5D028", "#F5C040", "#05E0DB", "#3153FD", "#4C45D3", "#5BD0B0", "#54D028", "#D0F540", "#057BE0"], - "background":"#FFFFFF", - "foreground": "#4584D3", - "tableAccent": "#31B6FD" -}, + theme: {}, show: false });