├── React
├── demo
│ ├── src
│ │ ├── public
│ │ │ └── favicon.ico
│ │ ├── assets
│ │ │ ├── GitHub_Icon.png
│ │ │ └── PowerBI_Icon.png
│ │ ├── constants
│ │ │ └── constants.ts
│ │ ├── index.tsx
│ │ ├── index.html
│ │ ├── components
│ │ │ ├── event-details-dialog
│ │ │ │ ├── EventDetailsDialogComponent.css
│ │ │ │ └── EventDetailsDialogComponent.tsx
│ │ │ └── embed-config-dialog
│ │ │ │ ├── EmbedConfigDialogComponent.css
│ │ │ │ └── EmbedConfigDialogComponent.tsx
│ │ ├── DemoApp.css
│ │ └── DemoApp.tsx
│ ├── tsconfig.json
│ ├── webpack.config.js
│ └── package.json
├── powerbi-client-react
│ ├── src
│ │ ├── powerbi-client-react.ts
│ │ ├── utils.ts
│ │ └── PowerBIEmbed.tsx
│ ├── test
│ │ ├── mockService.ts
│ │ ├── utils.spec.ts
│ │ └── PowerBIEmbed.spec.tsx
│ ├── config
│ │ ├── test
│ │ │ ├── tsconfig.json
│ │ │ ├── webpack.config.js
│ │ │ └── karma.conf.js
│ │ └── src
│ │ │ ├── tsconfig.json
│ │ │ └── webpack.config.js
│ ├── .eslintrc.js
│ └── package.json
└── .editorconfig
├── resources
└── react_wrapper_flow_diagram.png
├── .gitignore
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE.txt
├── LICENSE
├── SECURITY.md
└── README.md
/React/demo/src/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/powerbi-client-react/HEAD/React/demo/src/public/favicon.ico
--------------------------------------------------------------------------------
/React/demo/src/assets/GitHub_Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/powerbi-client-react/HEAD/React/demo/src/assets/GitHub_Icon.png
--------------------------------------------------------------------------------
/React/demo/src/assets/PowerBI_Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/powerbi-client-react/HEAD/React/demo/src/assets/PowerBI_Icon.png
--------------------------------------------------------------------------------
/resources/react_wrapper_flow_diagram.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/powerbi-client-react/HEAD/resources/react_wrapper_flow_diagram.png
--------------------------------------------------------------------------------
/React/powerbi-client-react/src/powerbi-client-react.ts:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | export {
5 | PowerBIEmbed,
6 | EmbedProps,
7 | EmbedType,
8 | EventHandler
9 | } from './PowerBIEmbed'
--------------------------------------------------------------------------------
/React/.editorconfig:
--------------------------------------------------------------------------------
1 | # Editor configuration, see https://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | charset = utf-8
6 | indent_style = space
7 | indent_size = 2
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
11 | [*.ts]
12 | quote_type = single
13 |
14 | [*.md]
15 | max_line_length = off
16 | trim_trailing_whitespace = false
17 |
--------------------------------------------------------------------------------
/React/powerbi-client-react/test/mockService.ts:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | const mockedMethods = ['init', 'embed', 'bootstrap', 'load', 'get', 'reset', 'preload', 'setSdkInfo'];
5 |
6 | const mockPowerBIService = jasmine.createSpyObj('mockService', mockedMethods);
7 |
8 | export { mockPowerBIService, mockedMethods };
--------------------------------------------------------------------------------
/React/demo/src/constants/constants.ts:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Microsoft Corporation.
2 | Licensed under the MIT License. */
3 |
4 | export const sampleTheme = {
5 | name: 'Sample Theme',
6 | dataColors: ['#990011', '#cc1144', '#ee7799', '#eebbcc', '#cc4477', '#cc5555', '#882222', '#a30e33'],
7 | background: '#ffffff',
8 | foreground: '#007799',
9 | tableAccent: '#990011',
10 | };
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # dependencies
2 | **/node_modules
3 | /.pnp
4 | .pnp.js
5 | **/package-lock.json
6 |
7 | # testing
8 | coverage
9 | compiledTests
10 |
11 | # production
12 | dist
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
25 | .vscode
26 |
27 | *.tgz
28 |
--------------------------------------------------------------------------------
/React/demo/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "include": [
3 | "./**/*.tsx",
4 | "./**/*.ts"
5 | ],
6 | "compilerOptions": {
7 | "target": "es6",
8 | "esModuleInterop": true,
9 | "allowSyntheticDefaultImports": true,
10 | "strict": true,
11 | "noErrorTruncation": true,
12 | "forceConsistentCasingInFileNames": true,
13 | "module": "ES6",
14 | "moduleResolution": "node",
15 | "resolveJsonModule": true,
16 | "jsx": "react",
17 | }
18 | }
--------------------------------------------------------------------------------
/React/demo/src/index.tsx:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | import 'react-app-polyfill/ie11'; // For IE compatibility
5 | import 'react-app-polyfill/stable'; // For IE compatibility
6 | import React from 'react';
7 | import { createRoot } from 'react-dom/client';
8 | import DemoApp from './DemoApp';
9 |
10 | const container = document.getElementById('root');
11 | const root = createRoot(container!);
12 | root.render();
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Microsoft Open Source Code of Conduct
2 |
3 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
4 |
5 | Resources:
6 |
7 | - [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/)
8 | - [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/)
9 | - Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns
10 |
--------------------------------------------------------------------------------
/React/demo/src/index.html:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | React Wrapper demo
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/React/powerbi-client-react/config/test/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "include": [
3 | "../../test/**/*.tsx",
4 | "../../test/**/*.ts"
5 | ],
6 | "compilerOptions": {
7 | "target": "ES5",
8 | "lib": [
9 | "ES2016",
10 | "dom"
11 | ],
12 | "types": ["jasmine"],
13 | "esModuleInterop": true,
14 | "allowSyntheticDefaultImports": true,
15 | "strict": false,
16 | "module": "esnext",
17 | "moduleResolution": "node",
18 | "resolveJsonModule": true,
19 | "jsx": "react"
20 | }
21 | }
--------------------------------------------------------------------------------
/React/powerbi-client-react/config/src/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "include": [
3 | "../../src/**/*.tsx",
4 | "../../src/**/*.ts"
5 | ],
6 | "compilerOptions": {
7 | "lib": ["ES2016"],
8 | "target": "es5",
9 | "esModuleInterop": false,
10 | "allowSyntheticDefaultImports": true,
11 | "strict": true,
12 | "noErrorTruncation": true,
13 | "module": "ES6",
14 | "moduleResolution": "node",
15 | "jsx": "react",
16 | "sourceMap": true,
17 | "noImplicitAny": true,
18 | "declaration": true,
19 | "outDir": "../../dist",
20 | }
21 | }
--------------------------------------------------------------------------------
/React/demo/webpack.config.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | const path = require('path');
5 |
6 | module.exports = {
7 | mode: 'development',
8 | entry: path.resolve('src/index.tsx'),
9 | output: {
10 | path: __dirname,
11 | filename: 'bundle.js'
12 | },
13 | module: {
14 | rules: [
15 | {
16 | test: /\.ts(x)?$/,
17 | loader: 'ts-loader'
18 | },
19 | {
20 | test: /\.css$/,
21 | use: [
22 | 'style-loader',
23 | 'css-loader'
24 | ]
25 | },
26 | ]
27 | },
28 | resolve: {
29 | extensions: [
30 | '.tsx',
31 | '.ts',
32 | '.js',
33 | ]
34 | },
35 | devtool: 'source-map',
36 | };
--------------------------------------------------------------------------------
/React/powerbi-client-react/config/test/webpack.config.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | const path = require('path');
5 |
6 | module.exports = {
7 | mode: 'development',
8 | entry: {
9 | PowerBIEmbedTest: path.resolve('test/PowerBIEmbed.spec.tsx'),
10 | utilsTest: path.resolve('test/utils.spec.ts'),
11 | },
12 | output: {
13 | path: path.resolve('compiledTests'),
14 | filename: '[name].spec.js'
15 | },
16 | devtool: 'source-map',
17 | module: {
18 | rules: [
19 | {
20 | test: /\.ts(x)?$/,
21 | loader: 'ts-loader',
22 | options: {
23 | configFile: path.resolve('config/test/tsconfig.json')
24 | },
25 | exclude: /node_modules/
26 | },
27 | ]
28 | },
29 | resolve: {
30 | extensions: [
31 | '.tsx',
32 | '.ts',
33 | '.js'
34 | ]
35 | },
36 | };
--------------------------------------------------------------------------------
/React/powerbi-client-react/config/src/webpack.config.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | const path = require('path');
5 |
6 | module.exports = {
7 | entry: path.resolve('src/PowerBIEmbed.tsx'),
8 | output: {
9 | library: 'powerbi-client-react',
10 | libraryTarget: 'umd',
11 | path: path.resolve('dist'),
12 | filename: 'powerbi-client-react.js'
13 | },
14 | externals: [
15 | 'react',
16 | 'powerbi-client',
17 | 'lodash.isequal'
18 | ],
19 | module: {
20 | rules: [
21 | {
22 | test: /\.ts(x)?$/,
23 | loader: 'ts-loader',
24 | options: {
25 | configFile: path.resolve('config/src/tsconfig.json')
26 | },
27 | exclude: /node_modules/
28 | },
29 | ]
30 | },
31 | resolve: {
32 | modules: ['node_modules'],
33 | extensions: [
34 | '.tsx',
35 | '.ts',
36 | '.js'
37 | ]
38 | },
39 | devtool: 'source-map',
40 | };
--------------------------------------------------------------------------------
/React/demo/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "powerbi-client-react-demo",
3 | "version": "1.1.0",
4 | "description": "Demo for usage of powerbi-client-react",
5 | "scripts": {
6 | "demo": "webpack-dev-server --static ./src/ --open"
7 | },
8 | "license": "MIT",
9 | "dependencies": {
10 | "@fluentui/web-components": "^2.6.1",
11 | "@microsoft/fast-react-wrapper": "^0.3.24",
12 | "powerbi-client-react": "^2.0.0",
13 | "powerbi-report-authoring": "^2.0.0",
14 | "react-app-polyfill": "^3.0.0"
15 | },
16 | "peerDependencies": {
17 | "react": ">= 18"
18 | },
19 | "devDependencies": {
20 | "@types/react": "^18.3.10",
21 | "@types/react-dom": "^18.3.0",
22 | "css-loader": "^3.5.3",
23 | "react": "^18.3.1",
24 | "react-dom": "^18.3.1",
25 | "style-loader": "^1.2.1",
26 | "ts-loader": "^9.4.2",
27 | "typescript": "^4.9.5",
28 | "webpack": "^5.71.0",
29 | "webpack-cli": "^4.9.2",
30 | "webpack-dev-server": "^4.11.1"
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | ## Setup
4 |
5 | Clone the repository:
6 | ```
7 | git clone
8 | ```
9 |
10 | Navigate to the cloned directory
11 |
12 | Navigate to the React\powerbi-client-react workspace folder:
13 | ```
14 | cd React\powerbi-client-react
15 | ```
16 |
17 | Install local dependencies:
18 | ```
19 | npm install
20 | ```
21 |
22 | ## Build:
23 | ```
24 | npm run build
25 | ```
26 | Or if using VScode: `Ctrl + Shift + B`
27 |
28 | ## Test
29 | ```
30 | npm test
31 | ```
32 | By default the tests run using ChromeHeadless browser
33 |
34 | The build and tests use webpack to compile all the source modules into bundled module that can be executed in the browser.
35 |
36 | ## Running the demo
37 |
38 | ```
39 | npm run demo
40 | ```
41 |
42 | Open the address to view in the browser:
43 |
44 | http://localhost:8080/
45 |
46 | ## Flow Diagram for the PowerBIEmbed Component:
47 | 
48 |
--------------------------------------------------------------------------------
/React/demo/src/components/event-details-dialog/EventDetailsDialogComponent.css:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Microsoft Corporation.
2 | Licensed under the MIT License. */
3 |
4 | h1 {
5 | margin: 5px 0;
6 | }
7 |
8 | pre {
9 | height: 348px;
10 | margin: 3.5px;
11 | }
12 |
13 | .close-icon-button {
14 | align-self: center;
15 | margin-bottom: 0;
16 | min-width: unset;
17 | }
18 |
19 | .dialog-header-event-details {
20 | display: flex;
21 | justify-content: space-between;
22 | text-align: start;
23 | }
24 |
25 | .dialog-main-event-details {
26 | align-items: flex-start;
27 | border: 1px solid #e8e8e8;
28 | display: flex;
29 | flex-direction: column;
30 | max-height: 400px;
31 | overflow-y: auto;
32 | }
33 |
34 | fluent-button.event-details-close-button {
35 | float: right;
36 | }
37 |
38 | fluent-button.event-details-close-button::part(control) {
39 | border: 1px solid #e8e8e8;
40 | margin-top: 8px;
41 | height: 32px;
42 | width: 80px;
43 | }
44 |
45 | fluent-dialog::part(control) {
46 | min-width: 300px;
47 | }
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | powerbi-client-react
2 |
3 | Copyright (c) Microsoft Corporation.
4 |
5 | MIT License
6 |
7 | Permission is hereby granted, free of charge, to any person obtaining a copy
8 | of this software and associated documentation files (the "Software"), to deal
9 | in the Software without restriction, including without limitation the rights
10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | copies of the Software, and to permit persons to whom the Software is
12 | furnished to do so, subject to the following conditions:
13 |
14 | The above copyright notice and this permission notice shall be included in all
15 | copies or substantial portions of the Software.
16 |
17 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | SOFTWARE.
24 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) Microsoft Corporation.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE
22 |
--------------------------------------------------------------------------------
/React/powerbi-client-react/src/utils.ts:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | import { EmbedProps } from "./PowerBIEmbed";
5 |
6 | /**
7 | * Get JSON string representation of the given map.
8 | *
9 | * @param map Map of event and corresponding handler method
10 | *
11 | * For example:
12 | * Input:
13 | * ```
14 | * Map([
15 | ['loaded', null],
16 | ['rendered', function () { console.log('Rendered'); }]
17 | ]);
18 | * ```
19 | * Output:
20 | * ```
21 | * `[["loaded",""],["rendered","function () { console.log('Rendered'); }"]]`
22 | * ```
23 | */
24 | export function stringifyMap(map: EmbedProps['eventHandlers']): string {
25 |
26 | // Return empty string for empty/null map
27 | if (!map) {
28 | return '';
29 | }
30 |
31 | // Get entries of map as array
32 | const mapEntries = Array.from(map);
33 |
34 | // Return JSON string
35 | return JSON.stringify(mapEntries.map((mapEntry) => {
36 |
37 | // Convert event handler method to a string containing its source code for comparison
38 | return [
39 | mapEntry[0],
40 | mapEntry[1] ? mapEntry[1].toString() : ''
41 | ];
42 | }));
43 | };
44 |
45 | // SDK information to be used with service instance
46 | export const SdkType = "powerbi-client-react";
47 | export const SdkWrapperVersion = "2.0.0";
--------------------------------------------------------------------------------
/React/powerbi-client-react/.eslintrc.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | module.exports = {
5 | parser: "@typescript-eslint/parser", // Specifies the ESLint parser
6 | extends: [
7 | "eslint:recommended",
8 | "plugin:react/recommended", // Uses the recommended rules from @eslint-plugin-react
9 | "plugin:@typescript-eslint/recommended" // Uses the recommended rules from @typescript-eslint/eslint-plugin
10 | ],
11 | parserOptions: {
12 | ecmaVersion: 2020, // Allows for the parsing of modern ECMAScript features
13 | sourceType: "module", // Allows for the use of imports
14 | ecmaFeatures: {
15 | jsx: true // Allows for the parsing of JSX
16 | },
17 | },
18 | rules: {
19 | "prefer-const": "warn",
20 | "no-var": "error",
21 | '@typescript-eslint/no-this-alias': [
22 | 'error',
23 | {
24 | allowDestructuring: true, // Allow `const { props, state } = this`; false by default
25 | allowedNames: ['thisObj'], // Allow `const self = this`; `[]` by default
26 | },
27 | ],
28 | '@typescript-eslint/no-empty-interface': [
29 | 'error',
30 | {
31 | allowSingleExtends: true
32 | }
33 | ],
34 | "@typescript-eslint/no-explicit-any": "off",
35 | "@typescript-eslint/no-extra-semi": "off"
36 | },
37 | settings: {
38 | react: {
39 | version: "detect" // Tells eslint-plugin-react to automatically detect the version of React to use
40 | }
41 | }
42 | };
--------------------------------------------------------------------------------
/React/demo/src/components/event-details-dialog/EventDetailsDialogComponent.tsx:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | import React from "react";
5 | import { provideFluentDesignSystem, fluentDialog, fluentButton } from '@fluentui/web-components';
6 | import { provideReactWrapper } from '@microsoft/fast-react-wrapper';
7 | import './EventDetailsDialogComponent.css';
8 |
9 | const { wrap } = provideReactWrapper(React, provideFluentDesignSystem());
10 |
11 | export const FluentDialog = wrap(fluentDialog());
12 | export const FluentButton = wrap(fluentButton());
13 |
14 | interface EventDetailsDialogProps {
15 | isOpen: boolean;
16 | onRequestClose: () => void;
17 | dataSelectedEventDetails: any;
18 | }
19 |
20 | const EventDetailsDialog = ({
21 | isOpen,
22 | onRequestClose,
23 | dataSelectedEventDetails,
24 | }: EventDetailsDialogProps) => {
25 | return (
26 | isOpen ? (
27 |
28 |
29 |
Event Details
30 |
31 |
32 |
33 |
{JSON.stringify(dataSelectedEventDetails, null, 2)}
34 |
35 | Close
36 |
37 | ) : null
38 | );
39 | };
40 |
41 | export default EventDetailsDialog;
--------------------------------------------------------------------------------
/React/powerbi-client-react/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "powerbi-client-react",
3 | "version": "2.0.0",
4 | "description": "React wrapper for powerbi-client library",
5 | "main": "dist/powerbi-client-react.js",
6 | "types": "dist/powerbi-client-react.d.ts",
7 | "files": [
8 | "dist"
9 | ],
10 | "scripts": {
11 | "prebuild": "npm run lint",
12 | "build": "webpack --mode=production --config config/src/webpack.config.js",
13 | "build:dev": "webpack --mode=development --config config/src/webpack.config.js",
14 | "pretest": "webpack --config config/test/webpack.config.js",
15 | "test": "karma start config/test/karma.conf.js",
16 | "demo": "cd ../demo && npm install && npm run demo",
17 | "lint": "eslint --fix src/**/*.{ts,tsx}"
18 | },
19 | "keywords": [
20 | "microsoft",
21 | "powerbi",
22 | "embedded",
23 | "react"
24 | ],
25 | "repository": {
26 | "type": "git",
27 | "url": "https://github.com/microsoft/powerbi-client-react.git"
28 | },
29 | "license": "MIT",
30 | "publishConfig": {
31 | "tag": "beta"
32 | },
33 | "dependencies": {
34 | "lodash.isequal": "^4.5.0",
35 | "powerbi-client": "^2.23.1"
36 | },
37 | "peerDependencies": {
38 | "react": ">= 18"
39 | },
40 | "devDependencies": {
41 | "@testing-library/react": "^16.0.1",
42 | "@types/jasmine": "^5.1.4",
43 | "@types/lodash.isequal": "^4.5.8",
44 | "@types/node": "^16.18.112",
45 | "@types/react": "^18.3.10",
46 | "@types/react-dom": "^18.3.0",
47 | "@typescript-eslint/eslint-plugin": "^5.42.0",
48 | "@typescript-eslint/parser": "^5.42.0",
49 | "eslint": "^7.4.0",
50 | "eslint-plugin-react": "^7.20.0",
51 | "jasmine-core": "^5.3.0",
52 | "karma": "^6.4.4",
53 | "karma-chrome-launcher": "^3.2.0",
54 | "karma-jasmine": "^5.1.0",
55 | "react": "^18.3.1",
56 | "react-dom": "^18.3.1",
57 | "ts-loader": "^9.4.1",
58 | "typescript": "^4.9.5",
59 | "webpack": "^5.71.0",
60 | "webpack-cli": "^4.9.2"
61 | }
62 | }
--------------------------------------------------------------------------------
/React/powerbi-client-react/config/test/karma.conf.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | let path = require('path');
5 |
6 | module.exports = function (config) {
7 | config.set({
8 |
9 | // base path that will be used to resolve all patterns (eg. files, exclude)
10 | basePath: '',
11 |
12 | // frameworks to use
13 | // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
14 | frameworks: ['jasmine'],
15 |
16 | // list of files / patterns to load in the browser
17 | files: [
18 | path.resolve('compiledTests/**/*spec.js')
19 | ],
20 |
21 | // preprocess matching files before serving them to the browser
22 | // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
23 | preprocessors: {
24 | },
25 |
26 | // test results reporter to use
27 | // possible values: 'dots', 'progress'
28 | // available reporters: https://npmjs.org/browse/keyword/karma-reporter
29 | reporters: ['progress'],
30 |
31 | // web server port
32 | port: 9876,
33 |
34 | // enable / disable colors in the output (reporters and logs)
35 | colors: true,
36 |
37 | // level of logging
38 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
39 | logLevel: config.LOG_INFO,
40 |
41 | // enable / disable watching file and executing tests whenever any file changes
42 | autoWatch: false,
43 |
44 | plugins: [
45 | require('karma-jasmine'),
46 | require('karma-chrome-launcher'),
47 | ],
48 |
49 | // start these browsers
50 | // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
51 | browsers: ["Chrome_headless"],
52 |
53 | customLaunchers: {
54 | 'Chrome_headless': {
55 | base: 'Chrome',
56 | flags: [
57 | '--no-sandbox',
58 | ]
59 | },
60 | },
61 |
62 | // Continuous Integration mode
63 | // if true, Karma captures browsers, runs the tests and exits
64 | singleRun: true,
65 |
66 | // Concurrency level
67 | // how many browser should be started simultaneous
68 | concurrency: Infinity
69 | })
70 | }
--------------------------------------------------------------------------------
/React/powerbi-client-react/test/utils.spec.ts:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | import { EventHandler } from '../src/PowerBIEmbed';
5 | import { stringifyMap } from '../src/utils';
6 |
7 | describe('tests of PowerBIEmbed', function () {
8 |
9 | let container: HTMLDivElement | null;
10 |
11 | beforeEach(function () {
12 | container = document.createElement('div');
13 | document.body.appendChild(container);
14 | });
15 |
16 | afterEach(function () {
17 | if (container){
18 | document.body.removeChild(container);
19 | container = null;
20 | }
21 | });
22 |
23 | // Tests for utils stringifyMap
24 | describe('tests PowerBIEmbed stringifyMap method', () => {
25 |
26 | it('stringifies the event handler map', () => {
27 |
28 | // Arrange
29 | const eventHandlerMap = new Map([
30 | ['loaded', function () { console.log('Report loaded'); }],
31 | ['rendered', function () { console.log('Rendered'); }]
32 | ]);
33 | const expectedString = `[["loaded","function () { console.log('Report loaded'); }"],["rendered","function () { console.log('Rendered'); }"]]`;
34 |
35 | // Act
36 | const jsonStringOutput = stringifyMap(eventHandlerMap);
37 |
38 | // Assert
39 | expect(jsonStringOutput).toBe(expectedString);
40 | });
41 |
42 | it('stringifies empty event handler map', () => {
43 |
44 | // Arrange
45 | const eventHandlerMap = new Map([]);
46 | const expectedString = `[]`;
47 |
48 | // Act
49 | const jsonStringOutput = stringifyMap(eventHandlerMap);
50 |
51 | // Assert
52 | expect(jsonStringOutput).toBe(expectedString);
53 | });
54 |
55 | it('stringifies null in event handler map', () => {
56 |
57 | // Arrange
58 | const eventHandlerMap = new Map([
59 | ['loaded', null],
60 | ['rendered', function () { console.log('Rendered'); }]
61 | ]);
62 | const expectedString = `[["loaded",""],["rendered","function () { console.log('Rendered'); }"]]`;
63 |
64 | // Act
65 | const jsonStringOutput = stringifyMap(eventHandlerMap);
66 |
67 | // Assert
68 | expect(jsonStringOutput).toBe(expectedString);
69 | });
70 | });
71 | });
--------------------------------------------------------------------------------
/React/demo/src/DemoApp.css:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Microsoft Corporation.
2 | Licensed under the MIT License. */
3 |
4 | body {
5 | font-family: 'Segoe UI';
6 | margin: 0;
7 | }
8 |
9 | button {
10 | background: #117865;
11 | border: 0;
12 | border-radius: 5px;
13 | color: #ffffff;
14 | cursor: pointer;
15 | font-size: 16px;
16 | height: 35px;
17 | margin-bottom: 8px;
18 | margin-right: 15px;
19 | min-width: 270px;
20 | overflow: hidden;
21 | text-overflow: ellipsis;
22 | white-space: nowrap;
23 | width: calc((100% / 3) - 120px);
24 | }
25 |
26 | .button-container {
27 | margin-left: auto;
28 | margin-right: auto;
29 | max-width: 1120px;
30 | }
31 |
32 | .container {
33 | display: flex;
34 | flex-direction: column;
35 | height: 100vh;
36 | }
37 |
38 | .controls {
39 | flex: 1;
40 | margin-top: 20px;
41 | text-align: center;
42 | }
43 |
44 | .display-message {
45 | align-items: center;
46 | display: flex;
47 | font: 400 18px/27px 'Segoe UI';
48 | height: 30px;
49 | justify-content: center;
50 | text-align: center;
51 | }
52 |
53 | .embed-report {
54 | margin-right: 0;
55 | margin-top: 18px;
56 | text-align: center;
57 | width: 180px;
58 | }
59 |
60 | .footer {
61 | align-items: center;
62 | background: #f7f8fa 0 0 no-repeat padding-box;
63 | display: flex;
64 | font: 400 16px/21px 'Segoe UI';
65 | height: 42px;
66 | justify-content: center;
67 | width: 100%;
68 | }
69 |
70 | .footer a {
71 | color: #3a3a3a;
72 | text-decoration: underline;
73 | }
74 |
75 | .footer * {
76 | padding: 0 3px;
77 | }
78 |
79 | .footer-icon {
80 | border-radius: 50%;
81 | height: 22px;
82 | vertical-align: middle;
83 | }
84 |
85 | .header {
86 | background: #117865 0 0 no-repeat padding-box;
87 | border: 1px solid #707070;
88 | color: #ffffff;
89 | font: 700 22px/27px 'Segoe UI';
90 | padding: 13px 13px 13px 36px;
91 | text-align: left;
92 | }
93 |
94 | iframe {
95 | border: none;
96 | }
97 |
98 | .position {
99 | margin-top: 40vh;
100 | }
101 |
102 | .report-container {
103 | height: 75vh;
104 | margin: 8px auto;
105 | width: 90%;
106 | }
107 |
108 | @media screen and (max-width: 980px) {
109 | p {
110 | font-size: 12px;
111 | }
112 | }
113 |
114 | @media screen and (max-width: 767px) {
115 | .display-message {
116 | font: 400 14px 'Segoe UI';
117 | }
118 |
119 | .footer {
120 | font: 400 8px 'Segoe UI';
121 | height: 64px;
122 | }
123 | }
--------------------------------------------------------------------------------
/React/demo/src/components/embed-config-dialog/EmbedConfigDialogComponent.css:
--------------------------------------------------------------------------------
1 | /* Copyright (c) Microsoft Corporation.
2 | Licensed under the MIT License. */
3 |
4 | p {
5 | margin: 10px 0;
6 | text-align: start;
7 | }
8 |
9 | span {
10 | font-weight: 500;
11 | }
12 |
13 | .close-icon-button {
14 | align-items: center;
15 | background: none;
16 | border: none;
17 | color: #000000;
18 | cursor: pointer;
19 | display: flex;
20 | font-size: 24px;
21 | justify-content: flex-end;
22 | margin-right: 0;
23 | padding: 0;
24 | width: 20px;
25 | }
26 |
27 | .dialog-buttons {
28 | background-color: none;
29 | border: none;
30 | display: flex;
31 | justify-content: flex-end;
32 | margin: 15px 0;
33 | }
34 |
35 | .dialog-field {
36 | margin: 5px 0;
37 | width: 100%;
38 | }
39 |
40 | .dialog-header {
41 | align-items: center;
42 | display: flex;
43 | justify-content: space-between;
44 | text-align: start;
45 | }
46 |
47 | .dialog-main {
48 | align-items: flex-start;
49 | display: flex;
50 | flex-direction: column;
51 | }
52 |
53 | .dialog-title {
54 | margin: 10px 0;
55 | }
56 |
57 | .run-button {
58 | margin: 0 10px;
59 | }
60 |
61 | fluent-button.close-button::part(control) {
62 | background-color: #ffffff;
63 | border: 1px solid #e0e0e0;
64 | color: #000000;
65 | cursor: pointer;
66 | }
67 |
68 | fluent-button.run-button.active::part(control) {
69 | background-color: #117865 !important;
70 | color: #ffffff !important;
71 | }
72 |
73 | fluent-button.run-button::part(control) {
74 | background-color: transparent !important;
75 | border: none;
76 | color: #000000;
77 | transition: background-color 0.3s;
78 | }
79 |
80 | fluent-button::part(control) {
81 | border: none;
82 | border-radius: 5px;
83 | cursor: pointer;
84 | font-size: 16px;
85 | font-weight: 500;
86 | height: 35px;
87 | width: 88px;
88 | }
89 |
90 | fluent-dialog::part(control) {
91 | background-color: #ffffff;
92 | border-radius: 8px;
93 | height: auto;
94 | padding: 24px;
95 | --neutral-fill-hover: none;
96 | --neutral-fill-rest: transparent;
97 | --neutral-stroke-control-rest: transparent;
98 | }
99 |
100 | fluent-text-field::part(control) {
101 | border: 1px solid #8a8886;
102 | border-radius: 2px;
103 | font-size: 16px;
104 | height: 28px;
105 | width: -webkit-fill-available;
106 | }
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ## Security
4 |
5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/).
6 |
7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://docs.microsoft.com/en-us/previous-versions/tn-archive/cc751383(v=technet.10)), please report it to us as described below.
8 |
9 | ## Reporting Security Issues
10 |
11 | **Please do not report security vulnerabilities through public GitHub issues.**
12 |
13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report).
14 |
15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://www.microsoft.com/en-us/msrc/pgp-key-msrc).
16 |
17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc).
18 |
19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:
20 |
21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
22 | * Full paths of source file(s) related to the manifestation of the issue
23 | * The location of the affected source code (tag/branch/commit or direct URL)
24 | * Any special configuration required to reproduce the issue
25 | * Step-by-step instructions to reproduce the issue
26 | * Proof-of-concept or exploit code (if possible)
27 | * Impact of the issue, including how an attacker might exploit the issue
28 |
29 | This information will help us triage your report more quickly.
30 |
31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://microsoft.com/msrc/bounty) page for more details about our active programs.
32 |
33 | ## Preferred Languages
34 |
35 | We prefer all communications to be in English.
36 |
37 | ## Policy
38 |
39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://www.microsoft.com/en-us/msrc/cvd).
40 |
41 |
--------------------------------------------------------------------------------
/React/demo/src/components/embed-config-dialog/EmbedConfigDialogComponent.tsx:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | import React, { useState, useEffect } from "react";
5 | import { provideFluentDesignSystem, fluentDialog, fluentButton, fluentTextField } from '@fluentui/web-components';
6 | import { provideReactWrapper } from '@microsoft/fast-react-wrapper';
7 | import './EmbedConfigDialogComponent.css';
8 |
9 | const { wrap } = provideReactWrapper(React, provideFluentDesignSystem());
10 |
11 | export const FluentDialog = wrap(fluentDialog());
12 | export const FluentButton = wrap(fluentButton());
13 | export const FluentTextField = wrap(fluentTextField());
14 |
15 | interface EmbedReportDialogProps {
16 | isOpen: boolean;
17 | onRequestClose: () => void;
18 | onEmbed: (embedUrl: string, accessToken: string) => void;
19 | }
20 |
21 | const EmbedConfigDialog = ({
22 | isOpen,
23 | onRequestClose,
24 | onEmbed,
25 | }: EmbedReportDialogProps) => {
26 | const [aadToken, setAadToken] = useState("");
27 | const [embedUrl, setEmbedUrl] = useState("");
28 | const [areFieldsFilled, setAreFieldsFilled] = useState(false);
29 |
30 | useEffect(() => {
31 | setAreFieldsFilled(!!aadToken && !!embedUrl);
32 | }, [aadToken, embedUrl]);
33 |
34 | const onAadTokenChange = (event: React.ChangeEvent): void => {
35 | setAadToken(event.target.value);
36 | }
37 |
38 | const onEmbedUrlChange = (event: React.ChangeEvent): void => {
39 | setEmbedUrl(event.target.value);
40 | }
41 |
42 | const runConfig = (): void => {
43 | if (aadToken && embedUrl) {
44 | onEmbed(embedUrl, aadToken);
45 | }
46 | };
47 |
48 | const hideEmbedConfigDialog = (): void => {
49 | setAadToken("");
50 | setEmbedUrl("");
51 | onRequestClose();
52 | };
53 |
54 | return (
55 | isOpen ? (
56 |
57 |
58 |
Use your own Microsoft Entra token
59 |
60 |
61 |
62 |
Follow the Microsoft Entra Token documentation to generate a Microsoft Entra Token.
63 |
Insert your Microsoft Entra token
64 |
65 |
66 |
Use the Get Report In Group REST API to get your embed URL.
67 |
Insert your embed URL
68 |
69 |
70 |
71 | Run
72 | Close
73 |
74 |
75 | ) : null
76 | );
77 | };
78 |
79 | export default EmbedConfigDialog;
--------------------------------------------------------------------------------
/React/powerbi-client-react/src/PowerBIEmbed.tsx:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | import * as React from 'react';
5 | import {
6 | service,
7 | factories,
8 | Report,
9 | Embed,
10 | Dashboard,
11 | Tile,
12 | Qna,
13 | Visual,
14 | IQnaEmbedConfiguration,
15 | IVisualEmbedConfiguration,
16 | IReportEmbedConfiguration,
17 | IDashboardEmbedConfiguration,
18 | ITileEmbedConfiguration,
19 | } from 'powerbi-client';
20 | import { IReportCreateConfiguration, IPaginatedReportLoadConfiguration } from 'powerbi-models';
21 | import isEqual from 'lodash.isequal';
22 | import { stringifyMap, SdkType, SdkWrapperVersion } from './utils';
23 |
24 | /**
25 | * Type for event handler function of embedded entity
26 | */
27 | export type EventHandler = ((event?: service.ICustomEvent, embeddedEntity?: Embed) => void) | null;
28 |
29 | /**
30 | * Props interface for PowerBIEmbed component
31 | */
32 | export interface EmbedProps {
33 |
34 | // Configuration for embedding the PowerBI entity (Required)
35 | embedConfig:
36 | | IReportEmbedConfiguration
37 | | IDashboardEmbedConfiguration
38 | | ITileEmbedConfiguration
39 | | IQnaEmbedConfiguration
40 | | IVisualEmbedConfiguration
41 | | IPaginatedReportLoadConfiguration
42 | | IReportCreateConfiguration;
43 |
44 | // Callback method to get the embedded PowerBI entity object (Optional)
45 | getEmbeddedComponent?: { (embeddedComponent: Embed): void };
46 |
47 | // Map of pair of event name and its handler method to be triggered on the event (Optional)
48 | eventHandlers?: Map;
49 |
50 | // CSS class to be set on the embedding container (Optional)
51 | cssClassName?: string;
52 |
53 | // Phased embedding flag (Optional)
54 | phasedEmbedding?: boolean;
55 |
56 | // Provide a custom implementation of PowerBI service (Optional)
57 | service?: service.Service;
58 | }
59 |
60 | export enum EmbedType {
61 | Create = 'create',
62 | Report = 'report',
63 | Dashboard = 'dashboard',
64 | Tile = 'tile',
65 | Qna = 'qna',
66 | Visual = 'visual'
67 | }
68 |
69 | /**
70 | * Base react component to embed Power BI entities like: reports, dashboards, tiles, visual and qna containers.
71 | */
72 | export class PowerBIEmbed extends React.Component {
73 |
74 | // Embedded entity
75 | // Note: Do not read or assign to this member variable directly, instead use the getter and setter
76 | private _embed?: Embed;
77 |
78 | // Powerbi service
79 | private powerbi: service.Service;
80 |
81 | // Ref to the HTML div element
82 | private containerRef = React.createRef();
83 |
84 | // JSON stringify of prev event handler map
85 | private prevEventHandlerMapString = '';
86 |
87 | // Getter for this._embed
88 | private get embed(): Embed | undefined {
89 | return this._embed;
90 | };
91 |
92 | // Setter for this._embed
93 | private set embed(newEmbedInstance: Embed | undefined) {
94 | this._embed = newEmbedInstance;
95 |
96 | // Invoke callback method in props to return this embed instance
97 | this.invokeGetEmbedCallback();
98 | };
99 |
100 | constructor(props: EmbedProps) {
101 | super(props);
102 |
103 | if (this.props.service) {
104 | this.powerbi = this.props.service;
105 | }
106 | else {
107 | this.powerbi = new service.Service(
108 | factories.hpmFactory,
109 | factories.wpmpFactory,
110 | factories.routerFactory);
111 | }
112 |
113 | this.powerbi.setSdkInfo(SdkType, SdkWrapperVersion);
114 | };
115 |
116 | componentDidMount(): void {
117 |
118 | // Check if HTML container is available
119 | if (this.containerRef.current) {
120 |
121 | // Decide to embed, load or bootstrap
122 | if (this.props.embedConfig.accessToken && this.props.embedConfig.embedUrl) {
123 | this.embedEntity();
124 | }
125 | else {
126 | this.embed = this.powerbi.bootstrap(this.containerRef.current, this.props.embedConfig);
127 | }
128 | }
129 |
130 | // Set event handlers if available
131 | if (this.props.eventHandlers && this.embed) {
132 | this.setEventHandlers(this.embed, this.props.eventHandlers);
133 | }
134 | };
135 |
136 | async componentDidUpdate(prevProps: EmbedProps): Promise {
137 |
138 | // Set event handlers if available
139 | if (this.props.eventHandlers && this.embed) {
140 | this.setEventHandlers(this.embed, this.props.eventHandlers);
141 | }
142 |
143 | // Re-embed when the current embedConfig differs from the previous embedConfig
144 | if(!isEqual(this.props.embedConfig, prevProps.embedConfig)){
145 | this.embedEntity();
146 | }
147 | };
148 |
149 | componentWillUnmount(): void {
150 | // Clean Up
151 | if (this.containerRef.current) {
152 | this.powerbi.reset(this.containerRef.current);
153 | }
154 |
155 | // Set the previous event handler map string to empty
156 | this.prevEventHandlerMapString = '';
157 | };
158 |
159 | render(): JSX.Element {
160 | return (
161 |
164 |
165 | )
166 | };
167 |
168 | /**
169 | * Embed the powerbi entity (Load for phased embedding)
170 | */
171 | private embedEntity(): void {
172 | // Ensure that the HTML container is rendered and available
173 | // Also check if the Embed URL and Access Token are present in current props
174 | if (!this.containerRef.current || !this.props.embedConfig.accessToken || !this.props.embedConfig.embedUrl) {
175 | return;
176 | }
177 |
178 | // Load when props.phasedEmbedding is true and embed type is report, embed otherwise
179 | if (this.props.phasedEmbedding && this.props.embedConfig.type === EmbedType.Report) {
180 | this.embed = this.powerbi.load(this.containerRef.current, this.props.embedConfig);
181 | }
182 | else {
183 | if (this.props.phasedEmbedding) {
184 | console.error(`Phased embedding is not supported for type ${this.props.embedConfig.type}`)
185 | }
186 |
187 | if (this.props.embedConfig.type === EmbedType.Create) {
188 | this.embed = this.powerbi.createReport(this.containerRef.current, this.props.embedConfig as IReportCreateConfiguration);
189 | }
190 | else {
191 | this.embed = this.powerbi.embed(this.containerRef.current, this.props.embedConfig);
192 | }
193 | }
194 | }
195 |
196 | /**
197 | * Sets all event handlers from the props on the embedded entity
198 | *
199 | * @param embed Embedded object
200 | * @param eventHandlers Array of eventhandlers to be set on embedded entity
201 | * @returns void
202 | */
203 | private setEventHandlers(
204 | embed: Embed,
205 | eventHandlerMap: Map
206 | ): void {
207 | // Get string representation of eventHandlerMap
208 | const eventHandlerMapString = stringifyMap(this.props.eventHandlers);
209 |
210 | // Check if event handler map changed
211 | if (this.prevEventHandlerMapString === eventHandlerMapString) {
212 | return;
213 | }
214 |
215 | // Update prev string representation of event handler map
216 | this.prevEventHandlerMapString = eventHandlerMapString;
217 |
218 | // List of allowed events
219 | let allowedEvents = Embed.allowedEvents;
220 |
221 | const entityType = embed.embedtype;
222 |
223 | // Append entity specific events
224 | switch (entityType) {
225 | case EmbedType.Create:
226 | break;
227 | case EmbedType.Report:
228 | allowedEvents = [...allowedEvents, ...Report.allowedEvents];
229 | break;
230 | case EmbedType.Dashboard:
231 | allowedEvents = [...allowedEvents, ...Dashboard.allowedEvents];
232 | break;
233 | case EmbedType.Tile:
234 | allowedEvents = [...allowedEvents, ...Tile.allowedEvents];
235 | break;
236 | case EmbedType.Qna:
237 | allowedEvents = [...allowedEvents, ...Qna.allowedEvents];
238 | break;
239 | case EmbedType.Visual:
240 | allowedEvents = [...allowedEvents, ...Visual.allowedEvents];
241 | break;
242 | default:
243 | console.error(`Invalid embed type ${entityType}`);
244 | }
245 |
246 | // Holds list of events which are not allowed
247 | const invalidEvents: Array = [];
248 |
249 | // Apply all provided event handlers
250 | eventHandlerMap.forEach((eventHandlerMethod, eventName) => {
251 | // Check if this event is allowed
252 | if (allowedEvents.includes(eventName)) {
253 |
254 | // Removes event handler for this event
255 | embed.off(eventName);
256 |
257 | // Event handler is effectively removed for this event when eventHandlerMethod is null
258 | if (eventHandlerMethod) {
259 |
260 | // Set single event handler
261 | embed.on(eventName, (event: service.ICustomEvent): void => {
262 | eventHandlerMethod(event, this.embed);
263 | });
264 | }
265 | }
266 | else {
267 |
268 | // Add this event name to the list of invalid events
269 | invalidEvents.push(eventName);
270 | }
271 | });
272 |
273 | // Handle invalid events
274 | if (invalidEvents.length) {
275 | console.error(`Following events are invalid: ${invalidEvents.join(',')}`);
276 | }
277 | };
278 |
279 | /**
280 | * Returns the embedded object via _getEmbed_ callback method provided in props
281 | *
282 | * @returns void
283 | */
284 | private invokeGetEmbedCallback(): void {
285 | if (this.props.getEmbeddedComponent && this.embed) {
286 | this.props.getEmbeddedComponent(this.embed);
287 | }
288 | };
289 | }
--------------------------------------------------------------------------------
/React/demo/src/DemoApp.tsx:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT License.
3 |
4 | import React, { useState, useEffect } from 'react';
5 | import { models, Report, Embed, service } from 'powerbi-client';
6 | import { IHttpPostMessageResponse } from 'http-post-message';
7 | import { PowerBIEmbed } from 'powerbi-client-react';
8 | import 'powerbi-report-authoring';
9 |
10 | import './DemoApp.css';
11 | import EmbedConfigDialog from './components/embed-config-dialog/EmbedConfigDialogComponent';
12 | import EventDetailsDialog from './components/event-details-dialog/EventDetailsDialogComponent';
13 | import { sampleTheme } from './constants/constants';
14 |
15 | // Root Component to demonstrate usage of embedded component
16 | function DemoApp (): JSX.Element {
17 |
18 | // PowerBI Report object (to be received via callback)
19 | const [report, setReport] = useState();
20 |
21 | // Track Report embedding status
22 | const [isEmbedded, setIsEmbedded] = useState(false);
23 |
24 | const [displayMessage, setMessage] = useState(`The report is bootstrapped. Click the Embed Report button to set the access token.`);
25 | const [isEmbedConfigDialogOpen, setIsEmbedConfigDialogOpen] = useState(false);
26 | const [isFilterPaneVisibleAndExpanded, setIsFilterPaneVisibleAndExpanded] = useState(true);
27 | const [isThemeApplied, setIsThemeApplied] = useState(false);
28 | const [isZoomedOut, setIsZoomedOut] = useState(false);
29 | const [isDataSelectedEvent, setIsDataSelectedEvent] = useState(false);
30 | const [isEventDetailsDialogVisible, setIsEventDetailsDialogVisible] = useState(false);
31 | const [dataSelectedEventDetails, setDataSelectedEventDetails] = useState(null);
32 |
33 | // Constants for zoom levels
34 | const zoomOutLevel = 0.5;
35 | const zoomInLevel = 0.9;
36 |
37 | // CSS Class to be passed to the embedded component
38 | const reportClass = 'report-container';
39 |
40 | // Pass the basic embed configurations to the embedded component to bootstrap the report on first load
41 | // Values for properties like embedUrl, accessToken and settings will be set on click of button
42 | const [sampleReportConfig, setReportConfig] = useState({
43 | type: 'report',
44 | embedUrl: undefined,
45 | tokenType: models.TokenType.Aad,
46 | accessToken: undefined,
47 | settings: undefined,
48 | });
49 |
50 | /**
51 | * Map of event handlers to be applied to the embedded report
52 | * Update event handlers for the report by redefining the map using the setEventHandlersMap function
53 | * Set event handler to null if event needs to be removed
54 | * More events can be provided from here
55 | * https://docs.microsoft.com/en-us/javascript/api/overview/powerbi/handle-events#report-events
56 | */
57 | const[eventHandlersMap, setEventHandlersMap] = useState