Merged PR 178588: Side channel JS SDK
From the end user's perspective, they will need to provide a third parameter to `powerbi.embed()` request. The new input may be extended in the future to support other event hooks. ```javascript powerbi.embed(..., config, { preQueryCallback: provideContext }) ``` The code in `service.ts` is similar to the event listeners we set in the [constructor](https://powerbi.visualstudio.com/Embedded/_git/powerbi-javascript?path=%2Fsrc%2Fservice.ts&version=GBmaster&line=168&lineEnd=168&lineStartColumn=5&lineEndColumn=21&lineStyle=plain&_a=contents)
This commit is contained in:
Родитель
51fbf9f652
Коммит
2a689943d4
|
@ -9,3 +9,4 @@ dist/powerbi.js.map
|
|||
*.js.map
|
||||
package-lock.json
|
||||
demo/package-lock.json
|
||||
.vscode
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
// Place your settings in this file to overwrite default and user settings.
|
||||
{
|
||||
"editor.tabSize": 2,
|
||||
"editor.insertSpaces": true,
|
||||
"editor.detectIndentation": false
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
{
|
||||
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||||
// for the documentation about the tasks.json format
|
||||
"version": "0.1.0",
|
||||
"command": "npm",
|
||||
"isShellCommand": true,
|
||||
"showOutput": "always",
|
||||
"suppressTaskName": true,
|
||||
"tasks": [
|
||||
{
|
||||
"taskName": "build",
|
||||
"args": [
|
||||
"run",
|
||||
"build"
|
||||
],
|
||||
"isBuildCommand": true
|
||||
},
|
||||
{
|
||||
"taskName": "test",
|
||||
"args": [
|
||||
"run",
|
||||
"test",
|
||||
"--",
|
||||
"--chrome"
|
||||
],
|
||||
"isTestCommand": true
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
// powerbi-client v2.18.3
|
||||
// powerbi-client v2.18.4
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
declare module "config" {
|
||||
|
@ -2127,6 +2127,10 @@ declare module "service" {
|
|||
* @hidden
|
||||
*/
|
||||
private embedExisting;
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
private registerApplicationContextHook;
|
||||
/**
|
||||
* Adds an event handler for DOMContentLoaded, which searches the DOM for elements that have the 'powerbi-embed-url' attribute,
|
||||
* and automatically attempts to embed a powerbi component based on information from other powerbi-* attributes.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// powerbi-client v2.18.3
|
||||
// powerbi-client v2.18.4
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
(function webpackUniversalModuleDefinition(root, factory) {
|
||||
|
@ -290,7 +290,7 @@ return /******/ (function(modules) { // webpackBootstrap
|
|||
/*! no static exports found */
|
||||
/***/ (function(module, exports, __webpack_require__) {
|
||||
|
||||
// powerbi-models v1.9.2
|
||||
// powerbi-models v1.9.3
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
(function webpackUniversalModuleDefinition(root, factory) {
|
||||
|
@ -7128,7 +7128,7 @@ exports.BookmarksManager = BookmarksManager;
|
|||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
/** @ignore */ /** */
|
||||
var config = {
|
||||
version: '2.18.3',
|
||||
version: '2.18.4',
|
||||
type: 'js'
|
||||
};
|
||||
exports.default = config;
|
||||
|
@ -7519,6 +7519,7 @@ var Embed = /** @class */ (function () {
|
|||
* @hidden
|
||||
*/
|
||||
function Embed(service, element, config, iframe, phasedRender, isBootstrap) {
|
||||
var _a;
|
||||
/** @hidden */
|
||||
this.allowedEvents = [];
|
||||
if (util_1.autoAuthInEmbedUrl(config.embedUrl)) {
|
||||
|
@ -7533,12 +7534,14 @@ var Embed = /** @class */ (function () {
|
|||
this.embedtype = config.type.toLowerCase();
|
||||
this.commands = [];
|
||||
this.groups = [];
|
||||
var registerQueryCallback = !!((_a = config.eventHooks) === null || _a === void 0 ? void 0 : _a.applicationContextProvider);
|
||||
delete config.eventHooks;
|
||||
this.populateConfig(config, isBootstrap);
|
||||
if (this.embedtype === 'create') {
|
||||
this.setIframe(false /* set EventListener to call create() on 'load' event*/, phasedRender, isBootstrap);
|
||||
this.setIframe(false /* set EventListener to call create() on 'load' event*/, phasedRender, isBootstrap, registerQueryCallback);
|
||||
}
|
||||
else {
|
||||
this.setIframe(true /* set EventListener to call load() on 'load' event*/, phasedRender, isBootstrap);
|
||||
this.setIframe(true /* set EventListener to call load() on 'load' event*/, phasedRender, isBootstrap, registerQueryCallback);
|
||||
}
|
||||
}
|
||||
/**
|
||||
|
@ -8012,11 +8015,13 @@ var Embed = /** @class */ (function () {
|
|||
*
|
||||
* @hidden
|
||||
*/
|
||||
Embed.prototype.setIframe = function (isLoad, phasedRender, isBootstrap) {
|
||||
Embed.prototype.setIframe = function (isLoad, phasedRender, isBootstrap, registerQueryCallback) {
|
||||
var _this = this;
|
||||
if (!this.iframe) {
|
||||
var iframeContent = document.createElement("iframe");
|
||||
var embedUrl = this.config.uniqueId ? util_1.addParamToUrl(this.config.embedUrl, 'uid', this.config.uniqueId) : this.config.embedUrl;
|
||||
if (!isBootstrap && registerQueryCallback)
|
||||
embedUrl = util_1.addParamToUrl(embedUrl, "registerQueryCallback", "true");
|
||||
iframeContent.style.width = '100%';
|
||||
iframeContent.style.height = '100%';
|
||||
iframeContent.setAttribute("src", embedUrl);
|
||||
|
@ -10363,6 +10368,42 @@ exports.Report = Report;
|
|||
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
};
|
||||
var __generator = (this && this.__generator) || function (thisArg, body) {
|
||||
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
||||
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
||||
function verb(n) { return function (v) { return step([n, v]); }; }
|
||||
function step(op) {
|
||||
if (f) throw new TypeError("Generator is already executing.");
|
||||
while (_) try {
|
||||
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
||||
if (y = 0, t) op = [op[0] & 2, t.value];
|
||||
switch (op[0]) {
|
||||
case 0: case 1: t = op; break;
|
||||
case 4: _.label++; return { value: op[1], done: false };
|
||||
case 5: _.label++; y = op[1]; op = [0]; continue;
|
||||
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
||||
default:
|
||||
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
||||
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
||||
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
||||
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
||||
if (t[2]) _.ops.pop();
|
||||
_.trys.pop(); continue;
|
||||
}
|
||||
op = body.call(thisArg, _);
|
||||
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
||||
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
||||
}
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.Service = void 0;
|
||||
var embed_1 = __webpack_require__(/*! ./embed */ "./src/embed.ts");
|
||||
|
@ -10518,6 +10559,7 @@ var Service = /** @class */ (function () {
|
|||
*/
|
||||
Service.prototype.embed = function (element, config) {
|
||||
if (config === void 0) { config = {}; }
|
||||
this.registerApplicationContextHook(config);
|
||||
return this.embedInternal(element, config);
|
||||
};
|
||||
/**
|
||||
|
@ -10532,6 +10574,7 @@ var Service = /** @class */ (function () {
|
|||
*/
|
||||
Service.prototype.load = function (element, config) {
|
||||
if (config === void 0) { config = {}; }
|
||||
this.registerApplicationContextHook(config);
|
||||
return this.embedInternal(element, config, /* phasedRender */ true, /* isBootstrap */ false);
|
||||
};
|
||||
/**
|
||||
|
@ -10636,6 +10679,40 @@ var Service = /** @class */ (function () {
|
|||
component.load(phasedRender);
|
||||
return component;
|
||||
};
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
Service.prototype.registerApplicationContextHook = function (config) {
|
||||
var _this = this;
|
||||
var _a;
|
||||
var applicationContextProvider = (_a = config === null || config === void 0 ? void 0 : config.eventHooks) === null || _a === void 0 ? void 0 : _a.applicationContextProvider;
|
||||
if (!applicationContextProvider) {
|
||||
return;
|
||||
}
|
||||
if (typeof applicationContextProvider !== 'function') {
|
||||
throw new Error("applicationContextProvider must be a function");
|
||||
}
|
||||
this.router.post("preQuery", function (req, _res) { return __awaiter(_this, void 0, void 0, function () {
|
||||
var result, error_1;
|
||||
return __generator(this, function (_a) {
|
||||
switch (_a.label) {
|
||||
case 0:
|
||||
_a.trys.push([0, 2, , 3]);
|
||||
return [4 /*yield*/, applicationContextProvider(req.body)];
|
||||
case 1:
|
||||
result = _a.sent();
|
||||
_res.send(200, result);
|
||||
return [3 /*break*/, 3];
|
||||
case 2:
|
||||
error_1 = _a.sent();
|
||||
_res.send(400, null);
|
||||
console.error(error_1);
|
||||
return [3 /*break*/, 3];
|
||||
case 3: return [2 /*return*/];
|
||||
}
|
||||
});
|
||||
}); });
|
||||
};
|
||||
/**
|
||||
* Adds an event handler for DOMContentLoaded, which searches the DOM for elements that have the 'powerbi-embed-url' attribute,
|
||||
* and automatically attempts to embed a powerbi component based on information from other powerbi-* attributes.
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "powerbi-client",
|
||||
"version": "2.18.3",
|
||||
"version": "2.18.4",
|
||||
"description": "JavaScript library for embedding Power BI into your apps. Provides service which makes it easy to embed different types of components and an object model which allows easy interaction with these components such as changing pages, applying filters, and responding to data selection.",
|
||||
"main": "dist/powerbi.js",
|
||||
"types": "dist/powerbi-client.d.ts",
|
||||
|
@ -81,7 +81,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"http-post-message": "^0.2",
|
||||
"powerbi-models": "^1.9.2",
|
||||
"powerbi-models": "^1.9.3",
|
||||
"powerbi-router": "^0.1",
|
||||
"window-post-message-proxy": "^0.2"
|
||||
},
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
/** @ignore *//** */
|
||||
const config = {
|
||||
version: '2.18.3',
|
||||
version: '2.18.4',
|
||||
type: 'js'
|
||||
};
|
||||
|
||||
|
|
15
src/embed.ts
15
src/embed.ts
|
@ -227,12 +227,15 @@ export abstract class Embed {
|
|||
this.commands = [];
|
||||
this.groups = [];
|
||||
|
||||
const registerQueryCallback = !!(<IEmbedConfiguration>config).eventHooks?.applicationContextProvider;
|
||||
delete (<IEmbedConfiguration>config).eventHooks;
|
||||
|
||||
this.populateConfig(config, isBootstrap);
|
||||
|
||||
if (this.embedtype === 'create') {
|
||||
this.setIframe(false /* set EventListener to call create() on 'load' event*/, phasedRender, isBootstrap);
|
||||
this.setIframe(false /* set EventListener to call create() on 'load' event*/, phasedRender, isBootstrap, registerQueryCallback);
|
||||
} else {
|
||||
this.setIframe(true /* set EventListener to call load() on 'load' event*/, phasedRender, isBootstrap);
|
||||
this.setIframe(true /* set EventListener to call load() on 'load' event*/, phasedRender, isBootstrap, registerQueryCallback);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -702,10 +705,14 @@ export abstract class Embed {
|
|||
*
|
||||
* @hidden
|
||||
*/
|
||||
private setIframe(isLoad: boolean, phasedRender?: boolean, isBootstrap?: boolean): void {
|
||||
private setIframe(isLoad: boolean, phasedRender?: boolean, isBootstrap?: boolean, registerQueryCallback?: boolean): void {
|
||||
if (!this.iframe) {
|
||||
const iframeContent = document.createElement("iframe");
|
||||
const embedUrl = this.config.uniqueId ? addParamToUrl(this.config.embedUrl, 'uid', this.config.uniqueId) : this.config.embedUrl;
|
||||
let embedUrl = this.config.uniqueId ? addParamToUrl(this.config.embedUrl, 'uid', this.config.uniqueId) : this.config.embedUrl;
|
||||
|
||||
if (!isBootstrap && registerQueryCallback)
|
||||
embedUrl = addParamToUrl(embedUrl, "registerQueryCallback", "true");
|
||||
|
||||
iframeContent.style.width = '100%';
|
||||
iframeContent.style.height = '100%';
|
||||
iframeContent.setAttribute("src", embedUrl);
|
||||
|
|
|
@ -300,6 +300,7 @@ export class Service implements IService {
|
|||
* @returns {Embed}
|
||||
*/
|
||||
embed(element: HTMLElement, config: IComponentEmbedConfiguration | IEmbedConfigurationBase = {}): Embed {
|
||||
this.registerApplicationContextHook(config as IEmbedConfiguration);
|
||||
return this.embedInternal(element, config);
|
||||
}
|
||||
|
||||
|
@ -314,6 +315,7 @@ export class Service implements IService {
|
|||
* @returns {Embed}
|
||||
*/
|
||||
load(element: HTMLElement, config: IComponentEmbedConfiguration | IEmbedConfigurationBase = {}): Embed {
|
||||
this.registerApplicationContextHook(config as IEmbedConfiguration);
|
||||
return this.embedInternal(element, config, /* phasedRender */ true, /* isBootstrap */ false);
|
||||
}
|
||||
|
||||
|
@ -440,6 +442,30 @@ export class Service implements IService {
|
|||
return component;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
private registerApplicationContextHook(config: IEmbedConfiguration): void {
|
||||
const applicationContextProvider = config?.eventHooks?.applicationContextProvider;
|
||||
if (!applicationContextProvider) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof applicationContextProvider !== 'function') {
|
||||
throw new Error("applicationContextProvider must be a function");
|
||||
}
|
||||
|
||||
this.router.post(`preQuery`, async (req, _res) => {
|
||||
try {
|
||||
let result = await applicationContextProvider(req.body);
|
||||
_res.send(200, result);
|
||||
} catch (error) {
|
||||
_res.send(400, null);
|
||||
console.error(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an event handler for DOMContentLoaded, which searches the DOM for elements that have the 'powerbi-embed-url' attribute,
|
||||
* and automatically attempts to embed a powerbi component based on information from other powerbi-* attributes.
|
||||
|
|
Загрузка…
Ссылка в новой задаче