Коммит
c4578b614e
|
@ -1,4 +1,4 @@
|
|||
// powerbi-client v2.21.1
|
||||
// powerbi-client v2.22.2
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
declare module "config" {
|
||||
|
@ -116,6 +116,14 @@ declare module "util" {
|
|||
* @returns {number}
|
||||
*/
|
||||
export function getTimeDiffInMilliseconds(start: Date, end: Date): number;
|
||||
/**
|
||||
* Checks if the embed type is for create
|
||||
*
|
||||
* @export
|
||||
* @param {string} embedType
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function isCreate(embedType: string): boolean;
|
||||
}
|
||||
declare module "embed" {
|
||||
import * as models from 'powerbi-models';
|
||||
|
@ -142,6 +150,7 @@ declare module "embed" {
|
|||
export type IDashboardEmbedConfiguration = models.IDashboardEmbedConfiguration;
|
||||
export type ITileEmbedConfiguration = models.ITileEmbedConfiguration;
|
||||
export type IQnaEmbedConfiguration = models.IQnaEmbedConfiguration;
|
||||
export type IQuickCreateConfiguration = models.IQuickCreateConfiguration;
|
||||
export type ILocaleSettings = models.ILocaleSettings;
|
||||
export type IQnaSettings = models.IQnaSettings;
|
||||
export type IEmbedSettings = models.ISettings;
|
||||
|
@ -249,13 +258,6 @@ declare module "embed" {
|
|||
* @hidden
|
||||
*/
|
||||
bootstrapConfig: IBootstrapEmbedConfiguration;
|
||||
/**
|
||||
* Gets or sets the configuration settings for creating report.
|
||||
*
|
||||
* @type {models.IReportCreateConfiguration}
|
||||
* @hidden
|
||||
*/
|
||||
createConfig: models.IReportCreateConfiguration;
|
||||
/**
|
||||
* Url used in the load request.
|
||||
*
|
||||
|
@ -299,19 +301,12 @@ declare module "embed" {
|
|||
*/
|
||||
constructor(service: Service, element: HTMLElement, config: IEmbedConfigurationBase, iframe?: HTMLIFrameElement, phasedRender?: boolean, isBootstrap?: boolean);
|
||||
/**
|
||||
* Sends createReport configuration data.
|
||||
*
|
||||
* ```javascript
|
||||
* createReport({
|
||||
* datasetId: '5dac7a4a-4452-46b3-99f6-a25915e0fe55',
|
||||
* accessToken: 'eyJ0eXA ... TaE2rTSbmg',
|
||||
* ```
|
||||
* Create is not supported by default
|
||||
*
|
||||
* @hidden
|
||||
* @param {models.IReportCreateConfiguration} config
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
createReport(config: models.IReportCreateConfiguration): Promise<void>;
|
||||
create(): Promise<void>;
|
||||
/**
|
||||
* Saves Report.
|
||||
*
|
||||
|
@ -1619,6 +1614,35 @@ declare module "report" {
|
|||
* @param zoomLevel zoom level to set
|
||||
*/
|
||||
setZoom(zoomLevel: number): Promise<void>;
|
||||
/**
|
||||
* Closes all open context menus and tooltips.
|
||||
*
|
||||
* ```javascript
|
||||
* report.closeAllOverlays()
|
||||
* .then(() => {
|
||||
* ...
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
closeAllOverlays(): Promise<void>;
|
||||
/**
|
||||
* Clears selected not popped out visuals, if flag is passed, all visuals selections will be cleared.
|
||||
*
|
||||
* ```javascript
|
||||
* report.clearSelectedVisuals()
|
||||
* .then(() => {
|
||||
* ...
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* @param {Boolean} [clearPopOutState=false]
|
||||
* If false / undefined visuals selection will not be cleared if one of visuals
|
||||
* is in popped out state (in focus, show as table, spotlight...)
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
clearSelectedVisuals(clearPopOutState?: boolean): Promise<void>;
|
||||
}
|
||||
}
|
||||
declare module "create" {
|
||||
|
@ -1633,6 +1657,13 @@ declare module "create" {
|
|||
* @extends {Embed}
|
||||
*/
|
||||
export class Create extends Embed {
|
||||
/**
|
||||
* Gets or sets the configuration settings for creating report.
|
||||
*
|
||||
* @type {IReportCreateConfiguration}
|
||||
* @hidden
|
||||
*/
|
||||
createConfig: IReportCreateConfiguration;
|
||||
constructor(service: Service, element: HTMLElement, config: IEmbedConfiguration | IReportCreateConfiguration, phasedRender?: boolean, isBootstrap?: boolean);
|
||||
/**
|
||||
* Gets the dataset ID from the first available location: createConfig or embed url.
|
||||
|
@ -1678,6 +1709,19 @@ declare module "create" {
|
|||
* @hidden
|
||||
*/
|
||||
static findIdFromEmbedUrl(url: string): string;
|
||||
/**
|
||||
* Sends create configuration data.
|
||||
*
|
||||
* ```javascript
|
||||
* create ({
|
||||
* datasetId: '5dac7a4a-4452-46b3-99f6-a25915e0fe55',
|
||||
* accessToken: 'eyJ0eXA ... TaE2rTSbmg',
|
||||
* ```
|
||||
*
|
||||
* @hidden
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
create(): Promise<void>;
|
||||
}
|
||||
}
|
||||
declare module "dashboard" {
|
||||
|
@ -2003,11 +2047,70 @@ declare module "visual" {
|
|||
private getFiltersLevelUrl;
|
||||
}
|
||||
}
|
||||
declare module "quickCreate" {
|
||||
import { IError, IQuickCreateConfiguration } from 'powerbi-models';
|
||||
import { Service } from "service";
|
||||
import { Embed, IEmbedConfigurationBase } from "embed";
|
||||
/**
|
||||
* A Power BI Quick Create component
|
||||
*
|
||||
* @export
|
||||
* @class QuickCreate
|
||||
* @extends {Embed}
|
||||
*/
|
||||
export class QuickCreate extends Embed {
|
||||
/**
|
||||
* Gets or sets the configuration settings for creating report.
|
||||
*
|
||||
* @type {IQuickCreateConfiguration}
|
||||
* @hidden
|
||||
*/
|
||||
createConfig: IQuickCreateConfiguration;
|
||||
constructor(service: Service, element: HTMLElement, config: IQuickCreateConfiguration, phasedRender?: boolean, isBootstrap?: boolean);
|
||||
/**
|
||||
* Override the getId abstract function
|
||||
* QuickCreate does not need any ID
|
||||
*
|
||||
* @returns {string}
|
||||
*/
|
||||
getId(): string;
|
||||
/**
|
||||
* Validate create report configuration.
|
||||
*/
|
||||
validate(config: IEmbedConfigurationBase): IError[];
|
||||
/**
|
||||
* Handle config changes.
|
||||
*
|
||||
* @hidden
|
||||
* @returns {void}
|
||||
*/
|
||||
configChanged(isBootstrap: boolean): void;
|
||||
/**
|
||||
* @hidden
|
||||
* @returns {string}
|
||||
*/
|
||||
getDefaultEmbedUrlEndpoint(): string;
|
||||
/**
|
||||
* Sends quickCreate configuration data.
|
||||
*
|
||||
* ```javascript
|
||||
* quickCreate({
|
||||
* accessToken: 'eyJ0eXA ... TaE2rTSbmg',
|
||||
* datasetCreateConfig: {}})
|
||||
* ```
|
||||
*
|
||||
* @hidden
|
||||
* @param {IQuickCreateConfiguration} createConfig
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
create(): Promise<void>;
|
||||
}
|
||||
}
|
||||
declare module "service" {
|
||||
import { WindowPostMessageProxy } from 'window-post-message-proxy';
|
||||
import { HttpPostMessage } from 'http-post-message';
|
||||
import { Router, IExtendedRequest, Response as IExtendedResponse } from 'powerbi-router';
|
||||
import { IReportCreateConfiguration } from 'powerbi-models';
|
||||
import { IQuickCreateConfiguration, IReportCreateConfiguration } from 'powerbi-models';
|
||||
import { Embed, IBootstrapEmbedConfiguration, IDashboardEmbedConfiguration, IEmbedConfiguration, IEmbedConfigurationBase, IQnaEmbedConfiguration, IReportEmbedConfiguration, ITileEmbedConfiguration, IVisualEmbedConfiguration } from "embed";
|
||||
export interface IEvent<T> {
|
||||
type: string;
|
||||
|
@ -2063,6 +2166,10 @@ declare module "service" {
|
|||
hpm: HttpPostMessage;
|
||||
}
|
||||
export type IComponentEmbedConfiguration = IReportEmbedConfiguration | IDashboardEmbedConfiguration | ITileEmbedConfiguration | IVisualEmbedConfiguration | IQnaEmbedConfiguration;
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
export type EmbedComponentFactory = (service: Service, element: HTMLElement, config: IEmbedConfigurationBase, phasedRender?: boolean, isBootstrap?: boolean) => Embed;
|
||||
/**
|
||||
* The Power BI Service embed component, which is the entry point to embed all other Power BI components into your application
|
||||
*
|
||||
|
@ -2088,7 +2195,7 @@ declare module "service" {
|
|||
accessToken: string;
|
||||
/** The Configuration object for the service*/
|
||||
private config;
|
||||
/** A list of Dashboard, Report and Tile components that have been embedded using this service instance. */
|
||||
/** A list of Power BI components that have been embedded using this service instance. */
|
||||
private embeds;
|
||||
/** TODO: Look for way to make hpm private without sacrificing ease of maintenance. This should be private but in embed needs to call methods.
|
||||
*
|
||||
|
@ -2102,6 +2209,10 @@ declare module "service" {
|
|||
wpmp: WindowPostMessageProxy;
|
||||
router: Router;
|
||||
private uniqueSessionId;
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
private registeredComponents;
|
||||
/**
|
||||
* Creates an instance of a Power BI Service.
|
||||
*
|
||||
|
@ -2120,6 +2231,14 @@ declare module "service" {
|
|||
* @returns {Embed}
|
||||
*/
|
||||
createReport(element: HTMLElement, config: IEmbedConfiguration | IReportCreateConfiguration): Embed;
|
||||
/**
|
||||
* Creates new dataset
|
||||
*
|
||||
* @param {HTMLElement} element
|
||||
* @param {IEmbedConfiguration} [config={}]
|
||||
* @returns {Embed}
|
||||
*/
|
||||
quickCreate(element: HTMLElement, config: IQuickCreateConfiguration): Embed;
|
||||
/**
|
||||
* TODO: Add a description here
|
||||
*
|
||||
|
@ -2175,10 +2294,25 @@ declare module "service" {
|
|||
* @private
|
||||
* @param {IPowerBiElement} element
|
||||
* @param {IEmbedConfigurationBase} config
|
||||
* @param {boolean} phasedRender
|
||||
* @param {boolean} isBootstrap
|
||||
* @returns {Embed}
|
||||
* @hidden
|
||||
*/
|
||||
private embedNew;
|
||||
/**
|
||||
* Given component type, creates embed component instance
|
||||
*
|
||||
* @private
|
||||
* @param {string} componentType
|
||||
* @param {HTMLElement} element
|
||||
* @param {IEmbedConfigurationBase} config
|
||||
* @param {boolean} phasedRender
|
||||
* @param {boolean} isBootstrap
|
||||
* @returns {Embed}
|
||||
* @hidden
|
||||
*/
|
||||
private createEmbedComponent;
|
||||
/**
|
||||
* Given an element that already contains an embed component, load with a new configuration.
|
||||
*
|
||||
|
@ -2263,6 +2397,15 @@ declare module "service" {
|
|||
* @returns {void}
|
||||
*/
|
||||
setSdkInfo(type: string, version: string): void;
|
||||
/**
|
||||
* API for registering external components
|
||||
*
|
||||
* @hidden
|
||||
* @param {string} componentType
|
||||
* @param {EmbedComponentFactory} embedComponentFactory
|
||||
* @param {string[]} routerEventUrls
|
||||
*/
|
||||
register(componentType: string, embedComponentFactory: EmbedComponentFactory, routerEventUrls: string[]): void;
|
||||
}
|
||||
}
|
||||
declare module "bookmarksManager" {
|
||||
|
@ -2797,11 +2940,12 @@ declare module "powerbi-client" {
|
|||
export { Report } from "report";
|
||||
export { Dashboard } from "dashboard";
|
||||
export { Tile } from "tile";
|
||||
export { IEmbedConfiguration, IQnaEmbedConfiguration, IVisualEmbedConfiguration, IReportEmbedConfiguration, IDashboardEmbedConfiguration, ITileEmbedConfiguration, Embed, ILocaleSettings, IEmbedSettings, IQnaSettings, } from "embed";
|
||||
export { IEmbedConfiguration, IQnaEmbedConfiguration, IVisualEmbedConfiguration, IReportEmbedConfiguration, IDashboardEmbedConfiguration, ITileEmbedConfiguration, IQuickCreateConfiguration, Embed, ILocaleSettings, IEmbedSettings, IQnaSettings, } from "embed";
|
||||
export { Page } from "page";
|
||||
export { Qna } from "qna";
|
||||
export { Visual } from "visual";
|
||||
export { VisualDescriptor } from "visualDescriptor";
|
||||
export { QuickCreate } from "quickCreate";
|
||||
export { BasicFilterBuilder, AdvancedFilterBuilder, TopNFilterBuilder, RelativeDateFilterBuilder, RelativeTimeFilterBuilder } from "FilterBuilders/index";
|
||||
global {
|
||||
interface Window {
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -161,7 +161,7 @@ gulp.task('min:js', 'Creates minified JavaScript file', function () {
|
|||
|
||||
// Create minified bundle without source map
|
||||
webpackConfig.mode = 'production';
|
||||
webpackConfig.devtool = 'none';
|
||||
webpackConfig.devtool = false;
|
||||
|
||||
return gulp.src(['./src/powerbi-client.ts'])
|
||||
.pipe(webpackStream({
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
var argv = require('yargs').argv;
|
||||
|
||||
var browserName = 'PhantomJS';
|
||||
var browserName = 'Chrome_headless';
|
||||
if (argv.chrome) {
|
||||
browserName = 'Chrome_headless'
|
||||
}
|
||||
|
@ -32,7 +32,6 @@ module.exports = function (config) {
|
|||
'karma-chrome-launcher',
|
||||
'karma-jasmine',
|
||||
'karma-spec-reporter',
|
||||
'karma-phantomjs-launcher',
|
||||
'karma-jasmine-html-reporter',
|
||||
'karma-junit-reporter'
|
||||
],
|
||||
|
|
25
package.json
25
package.json
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "powerbi-client",
|
||||
"version": "2.21.1",
|
||||
"version": "2.22.2",
|
||||
"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",
|
||||
|
@ -47,17 +47,17 @@
|
|||
"eslint-plugin-prefer-arrow": "^1.2.2",
|
||||
"gulp": "^4.0.2",
|
||||
"gulp-eslint": "^6.0.0",
|
||||
"gulp-flatten": "^0.2.0",
|
||||
"gulp-flatten": "^0.4.0",
|
||||
"gulp-gh-pages": "^0.5.4",
|
||||
"gulp-header": "^1.8.7",
|
||||
"gulp-header": "^2.0.9",
|
||||
"gulp-help-four": "^0.2.3",
|
||||
"gulp-rename": "^1.2.2",
|
||||
"gulp-replace": "^0.5.4",
|
||||
"gulp-typedoc": "^2.0.0",
|
||||
"gulp-typescript": "^4.0.1",
|
||||
"gulp-typescript": "^6.0.0-alpha.1",
|
||||
"gulp-watch": "^5.0.1",
|
||||
"gulp4-run-sequence": "^1.0.0",
|
||||
"http-server": "^0.12.1",
|
||||
"http-server": "^14.1.1",
|
||||
"ignore-loader": "^0.1.1",
|
||||
"jasmine-core": "3.10.1",
|
||||
"jquery": "^3.3.1",
|
||||
|
@ -68,24 +68,27 @@
|
|||
"karma-jasmine": "4.0.1",
|
||||
"karma-jasmine-html-reporter": "1.7.0",
|
||||
"karma-junit-reporter": "^2.0.1",
|
||||
"karma-phantomjs-launcher": "^1.0.4",
|
||||
"karma-spec-reporter": "0.0.32",
|
||||
"moment": "^2.14.1",
|
||||
"phantomjs-prebuilt": "^2.1.16",
|
||||
"ts-loader": "^6.2.2",
|
||||
"typedoc": "^0.15.0",
|
||||
"typedoc": "^0.23.23",
|
||||
"typescript": "~4.6.0",
|
||||
"webpack": "^4.44.2",
|
||||
"webpack-stream": "^5.2.1",
|
||||
"webpack": "^5.75.0",
|
||||
"webpack-stream": "^7.0.0",
|
||||
"yargs": "^16.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"http-post-message": "^0.2",
|
||||
"powerbi-models": "^1.11.0",
|
||||
"powerbi-models": "^1.12.3",
|
||||
"powerbi-router": "^0.1",
|
||||
"window-post-message-proxy": "^0.2"
|
||||
},
|
||||
"publishConfig": {
|
||||
"tag": "beta"
|
||||
},
|
||||
"overrides": {
|
||||
"glob-parent": "^6.0.2",
|
||||
"lodash.template": "^4.5.0",
|
||||
"micromatch": "^4.0.5"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
/** @ignore *//** */
|
||||
const config = {
|
||||
version: '2.21.1',
|
||||
version: '2.22.2',
|
||||
type: 'js'
|
||||
};
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
import { IReportCreateConfiguration, IError, validateCreateReport } from 'powerbi-models';
|
||||
import { Service } from './service';
|
||||
import { Embed, IEmbedConfigurationBase, IEmbedConfiguration } from './embed';
|
||||
import { Embed, IEmbedConfigurationBase, IEmbedConfiguration, ISessionHeaders } from './embed';
|
||||
import * as utils from './util';
|
||||
|
||||
/**
|
||||
|
@ -14,6 +14,14 @@ import * as utils from './util';
|
|||
* @extends {Embed}
|
||||
*/
|
||||
export class Create extends Embed {
|
||||
/**
|
||||
* Gets or sets the configuration settings for creating report.
|
||||
*
|
||||
* @type {IReportCreateConfiguration}
|
||||
* @hidden
|
||||
*/
|
||||
createConfig: IReportCreateConfiguration;
|
||||
|
||||
/*
|
||||
* @hidden
|
||||
*/
|
||||
|
@ -109,4 +117,39 @@ export class Create extends Embed {
|
|||
|
||||
return datasetId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends create configuration data.
|
||||
*
|
||||
* ```javascript
|
||||
* create ({
|
||||
* datasetId: '5dac7a4a-4452-46b3-99f6-a25915e0fe55',
|
||||
* accessToken: 'eyJ0eXA ... TaE2rTSbmg',
|
||||
* ```
|
||||
*
|
||||
* @hidden
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async create(): Promise<void> {
|
||||
const errors = validateCreateReport(this.createConfig);
|
||||
if (errors) {
|
||||
throw errors;
|
||||
}
|
||||
|
||||
try {
|
||||
const headers: ISessionHeaders = {
|
||||
uid: this.config.uniqueId,
|
||||
sdkSessionId: this.service.getSdkSessionId()
|
||||
};
|
||||
|
||||
if (!!this.eventHooks?.accessTokenProvider) {
|
||||
headers.tokenProviderSupplied = true;
|
||||
}
|
||||
|
||||
const response = await this.service.hpm.post<void>("/report/create", this.createConfig, headers, this.iframe.contentWindow);
|
||||
return response.body;
|
||||
} catch (response) {
|
||||
throw response.body;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
50
src/embed.ts
50
src/embed.ts
|
@ -5,7 +5,7 @@ import * as models from 'powerbi-models';
|
|||
import * as sdkConfig from './config';
|
||||
import { EmbedUrlNotSupported } from './errors';
|
||||
import { ICustomEvent, IEvent, IEventHandler, Service } from './service';
|
||||
import { addParamToUrl, assign, autoAuthInEmbedUrl, createRandomString, getTimeDiffInMilliseconds, remove } from './util';
|
||||
import { addParamToUrl, assign, autoAuthInEmbedUrl, createRandomString, getTimeDiffInMilliseconds, remove, isCreate } from './util';
|
||||
|
||||
declare global {
|
||||
interface Document {
|
||||
|
@ -48,6 +48,8 @@ export type ITileEmbedConfiguration = models.ITileEmbedConfiguration;
|
|||
|
||||
export type IQnaEmbedConfiguration = models.IQnaEmbedConfiguration;
|
||||
|
||||
export type IQuickCreateConfiguration = models.IQuickCreateConfiguration;
|
||||
|
||||
export type ILocaleSettings = models.ILocaleSettings;
|
||||
|
||||
export type IQnaSettings = models.IQnaSettings;
|
||||
|
@ -175,14 +177,6 @@ export abstract class Embed {
|
|||
*/
|
||||
bootstrapConfig: IBootstrapEmbedConfiguration;
|
||||
|
||||
/**
|
||||
* Gets or sets the configuration settings for creating report.
|
||||
*
|
||||
* @type {models.IReportCreateConfiguration}
|
||||
* @hidden
|
||||
*/
|
||||
createConfig: models.IReportCreateConfiguration;
|
||||
|
||||
/**
|
||||
* Url used in the load request.
|
||||
*
|
||||
|
@ -246,7 +240,7 @@ export abstract class Embed {
|
|||
|
||||
this.populateConfig(config, isBootstrap);
|
||||
|
||||
if (this.embedtype === 'create') {
|
||||
if (isCreate(this.embedtype)) {
|
||||
this.setIframe(false /* set EventListener to call create() on 'load' event*/, phasedRender, isBootstrap);
|
||||
} else {
|
||||
this.setIframe(true /* set EventListener to call load() on 'load' event*/, phasedRender, isBootstrap);
|
||||
|
@ -254,39 +248,13 @@ export abstract class Embed {
|
|||
}
|
||||
|
||||
/**
|
||||
* Sends createReport configuration data.
|
||||
*
|
||||
* ```javascript
|
||||
* createReport({
|
||||
* datasetId: '5dac7a4a-4452-46b3-99f6-a25915e0fe55',
|
||||
* accessToken: 'eyJ0eXA ... TaE2rTSbmg',
|
||||
* ```
|
||||
* Create is not supported by default
|
||||
*
|
||||
* @hidden
|
||||
* @param {models.IReportCreateConfiguration} config
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async createReport(config: models.IReportCreateConfiguration): Promise<void> {
|
||||
const errors = models.validateCreateReport(config);
|
||||
if (errors) {
|
||||
throw errors;
|
||||
}
|
||||
|
||||
try {
|
||||
const headers: ISessionHeaders = {
|
||||
uid: this.config.uniqueId,
|
||||
sdkSessionId: this.service.getSdkSessionId()
|
||||
};
|
||||
|
||||
if (!!this.eventHooks?.accessTokenProvider) {
|
||||
headers.tokenProviderSupplied = true;
|
||||
}
|
||||
|
||||
const response = await this.service.hpm.post<void>("/report/create", config, headers, this.iframe.contentWindow);
|
||||
return response.body;
|
||||
} catch (response) {
|
||||
throw response.body;
|
||||
}
|
||||
create(): Promise<void> {
|
||||
throw new Error(`no create support`);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -491,7 +459,7 @@ export abstract class Embed {
|
|||
throw new Error("Access token cannot be empty");
|
||||
}
|
||||
let embedType = this.config.type;
|
||||
embedType = (embedType === 'create' || embedType === 'visual' || embedType === 'qna') ? 'report' : embedType;
|
||||
embedType = (embedType === 'create' || embedType === 'visual' || embedType === 'qna' || embedType === 'quickCreate') ? 'report' : embedType;
|
||||
try {
|
||||
const response = await this.service.hpm.post<void>('/' + embedType + '/token', accessToken, { uid: this.config.uniqueId }, this.iframe.contentWindow);
|
||||
|
||||
|
@ -813,7 +781,7 @@ export abstract class Embed {
|
|||
this.element.addEventListener('ready', this.frontLoadHandler, false);
|
||||
}
|
||||
} else {
|
||||
this.iframe.addEventListener('load', () => this.createReport(this.createConfig), false);
|
||||
this.iframe.addEventListener('load', () => this.create(), false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@ export {
|
|||
IReportEmbedConfiguration,
|
||||
IDashboardEmbedConfiguration,
|
||||
ITileEmbedConfiguration,
|
||||
IQuickCreateConfiguration,
|
||||
Embed,
|
||||
ILocaleSettings,
|
||||
IEmbedSettings,
|
||||
|
@ -48,6 +49,9 @@ export {
|
|||
export {
|
||||
VisualDescriptor
|
||||
} from './visualDescriptor';
|
||||
export {
|
||||
QuickCreate
|
||||
} from './quickCreate';
|
||||
export {
|
||||
BasicFilterBuilder,
|
||||
AdvancedFilterBuilder,
|
||||
|
|
|
@ -0,0 +1,119 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
import { IError, IQuickCreateConfiguration, validateQuickCreate } from 'powerbi-models';
|
||||
import { Service } from './service';
|
||||
import { Embed, IEmbedConfigurationBase, ISessionHeaders } from './embed';
|
||||
|
||||
/**
|
||||
* A Power BI Quick Create component
|
||||
*
|
||||
* @export
|
||||
* @class QuickCreate
|
||||
* @extends {Embed}
|
||||
*/
|
||||
export class QuickCreate extends Embed {
|
||||
|
||||
/**
|
||||
* Gets or sets the configuration settings for creating report.
|
||||
*
|
||||
* @type {IQuickCreateConfiguration}
|
||||
* @hidden
|
||||
*/
|
||||
createConfig: IQuickCreateConfiguration;
|
||||
|
||||
/*
|
||||
* @hidden
|
||||
*/
|
||||
constructor(service: Service, element: HTMLElement, config: IQuickCreateConfiguration, phasedRender?: boolean, isBootstrap?: boolean) {
|
||||
super(service, element, config, /* iframe */ undefined, phasedRender, isBootstrap);
|
||||
|
||||
service.router.post(`/reports/${this.config.uniqueId}/eventHooks/:eventName`, async (req, _res) => {
|
||||
switch (req.params.eventName) {
|
||||
case "newAccessToken":
|
||||
req.body = req.body || {};
|
||||
req.body.report = this;
|
||||
await service.invokeSDKHook(this.eventHooks?.accessTokenProvider, req, _res);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Override the getId abstract function
|
||||
* QuickCreate does not need any ID
|
||||
*
|
||||
* @returns {string}
|
||||
*/
|
||||
getId(): string {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate create report configuration.
|
||||
*/
|
||||
validate(config: IEmbedConfigurationBase): IError[] {
|
||||
return validateQuickCreate(config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle config changes.
|
||||
*
|
||||
* @hidden
|
||||
* @returns {void}
|
||||
*/
|
||||
configChanged(isBootstrap: boolean): void {
|
||||
if (isBootstrap) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.createConfig = this.config as IQuickCreateConfiguration;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hidden
|
||||
* @returns {string}
|
||||
*/
|
||||
getDefaultEmbedUrlEndpoint(): string {
|
||||
return "quickCreate";
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends quickCreate configuration data.
|
||||
*
|
||||
* ```javascript
|
||||
* quickCreate({
|
||||
* accessToken: 'eyJ0eXA ... TaE2rTSbmg',
|
||||
* datasetCreateConfig: {}})
|
||||
* ```
|
||||
*
|
||||
* @hidden
|
||||
* @param {IQuickCreateConfiguration} createConfig
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async create(): Promise<void> {
|
||||
const errors = validateQuickCreate(this.createConfig);
|
||||
if (errors) {
|
||||
throw errors;
|
||||
}
|
||||
|
||||
try {
|
||||
const headers: ISessionHeaders = {
|
||||
uid: this.config.uniqueId,
|
||||
sdkSessionId: this.service.getSdkSessionId()
|
||||
};
|
||||
|
||||
if (!!this.eventHooks?.accessTokenProvider) {
|
||||
headers.tokenProviderSupplied = true;
|
||||
}
|
||||
|
||||
const response = await this.service.hpm.post<void>("/quickcreate", this.createConfig, headers, this.iframe.contentWindow);
|
||||
return response.body;
|
||||
} catch (response) {
|
||||
throw response.body;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -40,7 +40,6 @@ import { IFilterable } from './ifilterable';
|
|||
import { Page } from './page';
|
||||
import { BookmarksManager } from './bookmarksManager';
|
||||
import { VisualDescriptor } from './visualDescriptor';
|
||||
import * as assert from 'assert';
|
||||
|
||||
/**
|
||||
* A Report node within a report hierarchy
|
||||
|
@ -65,7 +64,7 @@ export interface IReportNode {
|
|||
*/
|
||||
export class Report extends Embed implements IReportNode, IFilterable {
|
||||
/** @hidden */
|
||||
static allowedEvents = ["filtersApplied", "pageChanged", "commandTriggered", "swipeStart", "swipeEnd", "bookmarkApplied", "dataHyperlinkClicked", "visualRendered", "visualClicked", "selectionChanged", "renderingStarted"];
|
||||
static allowedEvents = ["filtersApplied", "pageChanged", "commandTriggered", "swipeStart", "swipeEnd", "bookmarkApplied", "dataHyperlinkClicked", "visualRendered", "visualClicked", "selectionChanged", "renderingStarted", "blur"];
|
||||
/** @hidden */
|
||||
static reportIdAttribute = 'powerbi-report-id';
|
||||
/** @hidden */
|
||||
|
@ -111,7 +110,6 @@ export class Report extends Embed implements IReportNode, IFilterable {
|
|||
break;
|
||||
|
||||
default:
|
||||
assert(false, `${req.params.eventName} eventHook is not supported`);
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
@ -1179,4 +1177,63 @@ export class Report extends Embed implements IReportNode, IFilterable {
|
|||
async setZoom(zoomLevel: number): Promise<void> {
|
||||
await this.updateSettings({ zoomLevel: zoomLevel });
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes all open context menus and tooltips.
|
||||
*
|
||||
* ```javascript
|
||||
* report.closeAllOverlays()
|
||||
* .then(() => {
|
||||
* ...
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async closeAllOverlays(): Promise<void> {
|
||||
if (isRDLEmbed(this.config.embedUrl)) {
|
||||
return Promise.reject(APINotSupportedForRDLError);
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await this.service.hpm.post<void>('/report/closeAllOverlays', null, { uid: this.config.uniqueId }, this.iframe.contentWindow);
|
||||
return response.body;
|
||||
} catch (error) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears selected not popped out visuals, if flag is passed, all visuals selections will be cleared.
|
||||
*
|
||||
* ```javascript
|
||||
* report.clearSelectedVisuals()
|
||||
* .then(() => {
|
||||
* ...
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* @param {Boolean} [clearPopOutState=false]
|
||||
* If false / undefined visuals selection will not be cleared if one of visuals
|
||||
* is in popped out state (in focus, show as table, spotlight...)
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async clearSelectedVisuals(clearPopOutState?: boolean): Promise<void> {
|
||||
clearPopOutState = clearPopOutState === true;
|
||||
if (isRDLEmbed(this.config.embedUrl)) {
|
||||
return Promise.reject(APINotSupportedForRDLError);
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await this.service.hpm.post<void>(
|
||||
`/report/clearSelectedVisuals/${clearPopOutState.toString()}`,
|
||||
null,
|
||||
{ uid: this.config.uniqueId },
|
||||
this.iframe.contentWindow
|
||||
);
|
||||
return response.body;
|
||||
} catch (error) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
113
src/service.ts
113
src/service.ts
|
@ -7,7 +7,7 @@
|
|||
import { WindowPostMessageProxy } from 'window-post-message-proxy';
|
||||
import { HttpPostMessage } from 'http-post-message';
|
||||
import { Router, IExtendedRequest, Response as IExtendedResponse } from 'powerbi-router';
|
||||
import { IPage, IReportCreateConfiguration } from 'powerbi-models';
|
||||
import { IPage, IQuickCreateConfiguration, IReportCreateConfiguration } from 'powerbi-models';
|
||||
import {
|
||||
Embed,
|
||||
IBootstrapEmbedConfiguration,
|
||||
|
@ -27,6 +27,7 @@ import { Page } from './page';
|
|||
import { Qna } from './qna';
|
||||
import { Visual } from './visual';
|
||||
import * as utils from './util';
|
||||
import { QuickCreate } from './quickCreate';
|
||||
import * as sdkConfig from './config';
|
||||
|
||||
export interface IEvent<T> {
|
||||
|
@ -94,6 +95,11 @@ export interface IService {
|
|||
|
||||
export type IComponentEmbedConfiguration = IReportEmbedConfiguration | IDashboardEmbedConfiguration | ITileEmbedConfiguration | IVisualEmbedConfiguration | IQnaEmbedConfiguration;
|
||||
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
export type EmbedComponentFactory = (service: Service, element: HTMLElement, config: IEmbedConfigurationBase, phasedRender?: boolean, isBootstrap?: boolean) => Embed;
|
||||
|
||||
/**
|
||||
* The Power BI Service embed component, which is the entry point to embed all other Power BI components into your application
|
||||
*
|
||||
|
@ -133,7 +139,7 @@ export class Service implements IService {
|
|||
/** The Configuration object for the service*/
|
||||
private config: IServiceConfiguration;
|
||||
|
||||
/** A list of Dashboard, Report and Tile components that have been embedded using this service instance. */
|
||||
/** A list of Power BI components that have been embedded using this service instance. */
|
||||
private embeds: Embed[];
|
||||
|
||||
/** TODO: Look for way to make hpm private without sacrificing ease of maintenance. This should be private but in embed needs to call methods.
|
||||
|
@ -149,6 +155,11 @@ export class Service implements IService {
|
|||
router: Router;
|
||||
private uniqueSessionId: string;
|
||||
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
private registeredComponents: { [componentType: string]: EmbedComponentFactory } = {};
|
||||
|
||||
/**
|
||||
* Creates an instance of a Power BI Service.
|
||||
*
|
||||
|
@ -277,6 +288,23 @@ export class Service implements IService {
|
|||
return component;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new dataset
|
||||
*
|
||||
* @param {HTMLElement} element
|
||||
* @param {IEmbedConfiguration} [config={}]
|
||||
* @returns {Embed}
|
||||
*/
|
||||
quickCreate(element: HTMLElement, config: IQuickCreateConfiguration): Embed {
|
||||
config.type = 'quickCreate';
|
||||
const powerBiElement = element as IPowerBiElement;
|
||||
const component = new QuickCreate(this, powerBiElement, config);
|
||||
powerBiElement.powerBiEmbed = component;
|
||||
this.addOrOverwriteEmbed(component, element);
|
||||
|
||||
return component;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Add a description here
|
||||
*
|
||||
|
@ -377,6 +405,8 @@ export class Service implements IService {
|
|||
* @private
|
||||
* @param {IPowerBiElement} element
|
||||
* @param {IEmbedConfigurationBase} config
|
||||
* @param {boolean} phasedRender
|
||||
* @param {boolean} isBootstrap
|
||||
* @returns {Embed}
|
||||
* @hidden
|
||||
*/
|
||||
|
@ -390,18 +420,40 @@ export class Service implements IService {
|
|||
// Saves the type as part of the configuration so that it can be referenced later at a known location.
|
||||
config.type = componentType;
|
||||
|
||||
const Component = utils.find((embedComponent) => componentType === embedComponent.type.toLowerCase(), Service.components);
|
||||
if (!Component) {
|
||||
throw new Error(`Attempted to embed component of type: ${componentType} but did not find any matching component. Please verify the type you specified is intended.`);
|
||||
}
|
||||
|
||||
const component = new Component(this, element, config, phasedRender, isBootstrap);
|
||||
const component = this.createEmbedComponent(componentType, element, config, phasedRender, isBootstrap);
|
||||
element.powerBiEmbed = component;
|
||||
|
||||
this.addOrOverwriteEmbed(component, element);
|
||||
return component;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given component type, creates embed component instance
|
||||
*
|
||||
* @private
|
||||
* @param {string} componentType
|
||||
* @param {HTMLElement} element
|
||||
* @param {IEmbedConfigurationBase} config
|
||||
* @param {boolean} phasedRender
|
||||
* @param {boolean} isBootstrap
|
||||
* @returns {Embed}
|
||||
* @hidden
|
||||
*/
|
||||
private createEmbedComponent(componentType: string, element: HTMLElement, config: IEmbedConfigurationBase, phasedRender?: boolean, isBootstrap?: boolean): Embed {
|
||||
const Component = utils.find((embedComponent) => componentType === embedComponent.type.toLowerCase(), Service.components);
|
||||
if (Component) {
|
||||
return new Component(this, element, config, phasedRender, isBootstrap);
|
||||
}
|
||||
|
||||
// If component type is not legacy, search in registered components
|
||||
const registeredComponent = utils.find((registeredComponentType) => componentType.toLowerCase() === registeredComponentType.toLowerCase(), Object.keys(this.registeredComponents));
|
||||
if (!registeredComponent) {
|
||||
throw new Error(`Attempted to embed component of type: ${componentType} but did not find any matching component. Please verify the type you specified is intended.`);
|
||||
}
|
||||
|
||||
return this.registeredComponents[registeredComponent](this, element, config, phasedRender, isBootstrap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an element that already contains an embed component, load with a new configuration.
|
||||
*
|
||||
|
@ -433,7 +485,7 @@ export class Service implements IService {
|
|||
/**
|
||||
* When loading report after create we want to use existing Iframe to optimize load period
|
||||
*/
|
||||
if (config.type === "report" && component.config.type === "create") {
|
||||
if (config.type === "report" && utils.isCreate(component.config.type)) {
|
||||
const report = new Report(this, element, config, /* phasedRender */ false, /* isBootstrap */ false, element.powerBiEmbed.iframe);
|
||||
component.populateConfig(config, /* isBootstrap */ false);
|
||||
report.load();
|
||||
|
@ -641,8 +693,45 @@ export class Service implements IService {
|
|||
* @param {string} type
|
||||
* @returns {void}
|
||||
*/
|
||||
setSdkInfo(type: string, version: string): void {
|
||||
this.hpm.defaultHeaders['x-sdk-type'] = type;
|
||||
this.hpm.defaultHeaders['x-sdk-wrapper-version'] = version;
|
||||
setSdkInfo(type: string, version: string): void {
|
||||
this.hpm.defaultHeaders['x-sdk-type'] = type;
|
||||
this.hpm.defaultHeaders['x-sdk-wrapper-version'] = version;
|
||||
}
|
||||
|
||||
/**
|
||||
* API for registering external components
|
||||
*
|
||||
* @hidden
|
||||
* @param {string} componentType
|
||||
* @param {EmbedComponentFactory} embedComponentFactory
|
||||
* @param {string[]} routerEventUrls
|
||||
*/
|
||||
register(componentType: string, embedComponentFactory: EmbedComponentFactory, routerEventUrls: string[]): void {
|
||||
if (utils.find((embedComponent) => componentType.toLowerCase() === embedComponent.type.toLowerCase(), Service.components)) {
|
||||
throw new Error('The component name is reserved. Cannot register a component with this name.');
|
||||
}
|
||||
|
||||
if (utils.find((registeredComponentType) => componentType.toLowerCase() === registeredComponentType.toLowerCase(), Object.keys(this.registeredComponents))) {
|
||||
throw new Error('A component with this type is already registered.');
|
||||
}
|
||||
|
||||
this.registeredComponents[componentType] = embedComponentFactory;
|
||||
|
||||
routerEventUrls.forEach(url => {
|
||||
if (!url.includes(':uniqueId') || !url.includes(':eventName')) {
|
||||
throw new Error('Invalid router event URL');
|
||||
}
|
||||
|
||||
this.router.post(url, (req, _res) => {
|
||||
const event: IEvent<any> = {
|
||||
type: componentType,
|
||||
id: req.params.uniqueId as string,
|
||||
name: req.params.eventName as string,
|
||||
value: req.body
|
||||
};
|
||||
|
||||
this.handleEvent(event);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
11
src/util.ts
11
src/util.ts
|
@ -212,3 +212,14 @@ export function getRandomValue(): number {
|
|||
export function getTimeDiffInMilliseconds(start: Date, end: Date): number {
|
||||
return Math.abs(start.getTime() - end.getTime());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the embed type is for create
|
||||
*
|
||||
* @export
|
||||
* @param {string} embedType
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function isCreate(embedType: string): boolean {
|
||||
return embedType === 'create' || embedType === 'quickcreate';
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import * as embed from '../src/embed';
|
|||
import * as report from '../src/report';
|
||||
import * as visual from '../src/visual';
|
||||
import * as create from '../src/create';
|
||||
import * as quickCreate from '../src/quickCreate';
|
||||
import * as dashboard from '../src/dashboard';
|
||||
import * as page from '../src/page';
|
||||
import * as sdkConfig from '../src/config';
|
||||
|
@ -2135,7 +2136,7 @@ describe('SDK-to-HPM', function () {
|
|||
});
|
||||
});
|
||||
|
||||
describe('createReport', function () {
|
||||
describe('create', function () {
|
||||
let createElement: HTMLDivElement;
|
||||
let create: create.Create;
|
||||
|
||||
|
@ -2164,7 +2165,7 @@ describe('SDK-to-HPM', function () {
|
|||
createElement.remove();
|
||||
});
|
||||
|
||||
it('create.createReport() sends POST /report/create with configuration in body', async function () {
|
||||
it('create.create() sends POST /report/create with configuration in body', async function () {
|
||||
// Arrange
|
||||
const testData = {
|
||||
createConfiguration: {
|
||||
|
@ -2177,15 +2178,16 @@ describe('SDK-to-HPM', function () {
|
|||
};
|
||||
|
||||
spyHpm.post.and.returnValue(Promise.resolve(testData.response));
|
||||
create.createConfig = testData.createConfiguration;
|
||||
|
||||
// Act
|
||||
await create.createReport(testData.createConfiguration);
|
||||
await create.create();
|
||||
|
||||
// Assert
|
||||
expect(spyHpm.post).toHaveBeenCalledWith('/report/create', testData.createConfiguration, { uid: createUniqueId, sdkSessionId: sdkSessionId, tokenProviderSupplied: true }, jasmine.any(Object));
|
||||
});
|
||||
|
||||
it('create.createReport() returns promise that rejects with validation error if the create configuration is invalid', async function () {
|
||||
it('create.create() returns promise that rejects with validation error if the create configuration is invalid', async function () {
|
||||
// Arrange
|
||||
const testData = {
|
||||
createConfiguration: {
|
||||
|
@ -2204,7 +2206,8 @@ describe('SDK-to-HPM', function () {
|
|||
spyHpm.post.and.callFake(() => Promise.reject(testData.errorResponse));
|
||||
try {
|
||||
// Act
|
||||
await create.createReport(testData.createConfiguration);
|
||||
create.createConfig = testData.createConfiguration;
|
||||
await create.create();
|
||||
|
||||
} catch (error) {
|
||||
// Assert
|
||||
|
@ -2213,7 +2216,7 @@ describe('SDK-to-HPM', function () {
|
|||
}
|
||||
});
|
||||
|
||||
it('create.createReport() returns promise that resolves with null if create report was successful', async function () {
|
||||
it('create.create() returns promise that resolves with null if create report was successful', async function () {
|
||||
// Arrange
|
||||
const testData = {
|
||||
createConfiguration: {
|
||||
|
@ -2230,7 +2233,8 @@ describe('SDK-to-HPM', function () {
|
|||
spyHpm.post.and.returnValue(Promise.resolve(testData.response));
|
||||
|
||||
// Act
|
||||
const response = await create.createReport(testData.createConfiguration);
|
||||
create.createConfig = testData.createConfiguration;
|
||||
const response = await create.create();
|
||||
// Assert
|
||||
expect(spyHpm.post).toHaveBeenCalledWith('/report/create', testData.createConfiguration, { uid: createUniqueId, sdkSessionId: sdkSessionId, tokenProviderSupplied: true }, jasmine.any(Object));
|
||||
expect(response).toEqual(null);
|
||||
|
@ -2568,4 +2572,129 @@ describe('SDK-to-HPM', function () {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('quickCreate', function () {
|
||||
let quickCreateElement: HTMLDivElement;
|
||||
let quickCreate: quickCreate.QuickCreate;
|
||||
let quickCreateUniqueId = 'uniqueId';
|
||||
|
||||
// Arrange
|
||||
let testData = {
|
||||
createConfiguration: {
|
||||
type: 'quickCreate',
|
||||
accessToken: 'fakeToken',
|
||||
groupId: undefined,
|
||||
settings: undefined,
|
||||
tokenType: models.TokenType.Aad,
|
||||
theme: undefined,
|
||||
datasetCreateConfig: {
|
||||
locale: "fakeLocale",
|
||||
mashupDocument: "fakeMashup",
|
||||
},
|
||||
reportCreationMode: undefined
|
||||
},
|
||||
response: {
|
||||
body: null
|
||||
}
|
||||
};
|
||||
|
||||
beforeEach(async () => {
|
||||
quickCreateElement = document.createElement('div');
|
||||
quickCreateElement.className = 'powerbi-quickCreate-container';
|
||||
document.body.appendChild(quickCreateElement);
|
||||
|
||||
const quickCreateConfiguration = {
|
||||
accessToken: 'fakeToken',
|
||||
tokenType: models.TokenType.Aad,
|
||||
embedUrl: iframeSrc,
|
||||
datasetCreateConfig: {
|
||||
locale: "fakeLocale",
|
||||
mashupDocument: "fakeMashup",
|
||||
},
|
||||
eventHooks: { accessTokenProvider: function () { return null; } }
|
||||
};
|
||||
spyHpm.post.and.returnValue(Promise.resolve({}));
|
||||
quickCreate = <quickCreate.QuickCreate>powerbi.quickCreate(quickCreateElement, quickCreateConfiguration);
|
||||
createUniqueId = quickCreate.config.uniqueId;
|
||||
const createIframe = quickCreateElement.getElementsByTagName('iframe')[0];
|
||||
await new Promise<void>((resolve, _reject) => createIframe.addEventListener('load', () => resolve(null)));
|
||||
spyHpm.post.and.callThrough();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
powerbi.reset(quickCreateElement);
|
||||
quickCreateElement.remove();
|
||||
});
|
||||
|
||||
describe('quickCreate', function () {
|
||||
it('quickCreate.create() sends POST /quickcreate with configuration in body', async function () {
|
||||
spyHpm.post.and.returnValue(Promise.resolve(testData.response));
|
||||
quickCreate.createConfig = <models.IQuickCreateConfiguration>testData.createConfiguration;
|
||||
quickCreateUniqueId = quickCreate.config.uniqueId;
|
||||
|
||||
// Act
|
||||
await quickCreate.create();
|
||||
|
||||
// Assert
|
||||
let expectedHeaders = {
|
||||
uid: quickCreateUniqueId,
|
||||
sdkSessionId: sdkSessionId,
|
||||
tokenProviderSupplied: true
|
||||
};
|
||||
expect(spyHpm.post).toHaveBeenCalledWith('/quickcreate', testData.createConfiguration, expectedHeaders, jasmine.any(Object));
|
||||
});
|
||||
|
||||
it('quickCreate.create() returns promise that rejects with validation error if the create configuration is invalid', async function () {
|
||||
// Arrange
|
||||
const errorResponse = {
|
||||
body: {
|
||||
message: "invalid configuration object"
|
||||
}
|
||||
};
|
||||
|
||||
spyHpm.post.and.returnValue(Promise.reject(errorResponse));
|
||||
quickCreate.createConfig = <models.IQuickCreateConfiguration>testData.createConfiguration;
|
||||
quickCreateUniqueId = quickCreate.config.uniqueId;
|
||||
|
||||
spyHpm.post.and.callFake(() => Promise.reject(errorResponse));
|
||||
try {
|
||||
// Act
|
||||
await quickCreate.create();
|
||||
|
||||
} catch (error) {
|
||||
// Assert
|
||||
let expectedHeaders = {
|
||||
uid: quickCreateUniqueId,
|
||||
sdkSessionId: sdkSessionId,
|
||||
tokenProviderSupplied: true
|
||||
};
|
||||
expect(spyHpm.post).toHaveBeenCalledWith('/quickcreate', testData.createConfiguration, expectedHeaders, jasmine.any(Object));
|
||||
expect(error).toEqual(errorResponse.body);
|
||||
}
|
||||
});
|
||||
|
||||
it('quickCreate.create() returns promise that resolves with null if quick create was successful', async function () {
|
||||
spyHpm.post.and.returnValue(Promise.resolve(testData.response));
|
||||
quickCreate.createConfig = <models.IQuickCreateConfiguration>testData.createConfiguration;
|
||||
quickCreateUniqueId = quickCreate.config.uniqueId;
|
||||
|
||||
// Act
|
||||
const response = await quickCreate.create();
|
||||
expect(response).toEqual(null);
|
||||
|
||||
// Assert
|
||||
let expectedHeaders = {
|
||||
uid: quickCreateUniqueId,
|
||||
sdkSessionId: sdkSessionId,
|
||||
tokenProviderSupplied: true
|
||||
};
|
||||
expect(spyHpm.post).toHaveBeenCalledWith(
|
||||
'/quickcreate',
|
||||
testData.createConfiguration,
|
||||
expectedHeaders, jasmine.any(Object));
|
||||
expect(response).toEqual(null);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
@ -1191,4 +1191,53 @@ describe('Protocol', function () {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('quickCreate', function () {
|
||||
describe('create', function () {
|
||||
it('POST /quickcreate returns 400 if the request is invalid', async function () {
|
||||
// Arrange
|
||||
const testData = {
|
||||
uniqueId: 'uniqueId',
|
||||
create: {
|
||||
accessToken: "fakeToken",
|
||||
}
|
||||
};
|
||||
|
||||
spyApp.validateQuickCreate.and.callFake(() => Promise.reject(null));
|
||||
|
||||
// Act
|
||||
try {
|
||||
await hpm.post<models.IError>('/quickcreate', testData.create, { uid: testData.uniqueId });
|
||||
fail("POST to /quickcreate should fail");
|
||||
} catch (response) {
|
||||
// Assert
|
||||
expect(spyApp.validateQuickCreate).toHaveBeenCalledWith(testData.create);
|
||||
expect(response.statusCode).toEqual(400);
|
||||
}
|
||||
});
|
||||
|
||||
it('POST /quickCreate returns 202 if the request is valid', async function () {
|
||||
// Arrange
|
||||
const testData = {
|
||||
uniqueId: 'uniqueId',
|
||||
create: {
|
||||
accessToken: "fakeToken",
|
||||
}
|
||||
};
|
||||
|
||||
spyApp.validateQuickCreate.and.returnValue(Promise.resolve(null));
|
||||
// Act
|
||||
try {
|
||||
const response = await hpm.post<void>('/quickcreate', testData.create, { uid: testData.uniqueId });
|
||||
// Assert
|
||||
expect(spyApp.validateQuickCreate).toHaveBeenCalledWith(testData.create);
|
||||
expect(response.statusCode).toEqual(202);
|
||||
} catch (error) {
|
||||
console.log("hpm.post failed with", error);
|
||||
fail("hpm.post");
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
@ -643,7 +643,7 @@ describe('service', function () {
|
|||
.appendTo('#powerbi-fixture');
|
||||
|
||||
// Act
|
||||
const report = powerbi.createReport($reportContainer[0], { embedUrl: embedUrl, accessToken: accessToken, datasetId: testDatasetId });
|
||||
const report = powerbi.createReport($reportContainer[0], { embedUrl: embedUrl, accessToken: accessToken, datasetId: testDatasetId }) as create.Create;
|
||||
|
||||
// Assert
|
||||
expect(report.createConfig.datasetId).toEqual(testDatasetId);
|
||||
|
@ -658,7 +658,7 @@ describe('service', function () {
|
|||
.appendTo('#powerbi-fixture');
|
||||
|
||||
// Act
|
||||
const report = powerbi.createReport($reportContainer[0], { embedUrl: embedUrl, accessToken: accessToken });
|
||||
const report = powerbi.createReport($reportContainer[0], { embedUrl: embedUrl, accessToken: accessToken }) as create.Create;
|
||||
|
||||
// Assert
|
||||
expect(report.createConfig.datasetId).toEqual(testDatasetId);
|
||||
|
@ -675,7 +675,7 @@ describe('service', function () {
|
|||
.appendTo('#powerbi-fixture');
|
||||
|
||||
// Act
|
||||
const report = powerbi.createReport($reportContainer[0], { embedUrl: embedUrl, accessToken: accessToken, theme: theme });
|
||||
const report = powerbi.createReport($reportContainer[0], { embedUrl: embedUrl, accessToken: accessToken, theme: theme }) as create.Create;
|
||||
|
||||
// Assert
|
||||
expect(report.createConfig.theme).toEqual(theme);
|
||||
|
@ -691,7 +691,7 @@ describe('service', function () {
|
|||
.appendTo('#powerbi-fixture');
|
||||
|
||||
// Act
|
||||
const report = powerbi.createReport($reportContainer[0], { embedUrl: embedUrl, accessToken: accessToken });
|
||||
const report = powerbi.createReport($reportContainer[0], { embedUrl: embedUrl, accessToken: accessToken }) as create.Create;
|
||||
|
||||
// Assert
|
||||
expect(report.createConfig.theme).toBeUndefined();
|
||||
|
@ -1041,4 +1041,127 @@ describe('service', function () {
|
|||
expect(report2).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('quickCreate', function () {
|
||||
const embedUrl = `https://app.powerbi.com/quickcreate`;
|
||||
const accessToken = 'ABC123';
|
||||
|
||||
it('happy path', function () {
|
||||
// Arrange
|
||||
const component = $('<div></div>')
|
||||
.appendTo('#powerbi-fixture');
|
||||
|
||||
// Act
|
||||
const attemptCreate = (): void => {
|
||||
powerbi.quickCreate(component[0], {
|
||||
embedUrl: embedUrl,
|
||||
accessToken: accessToken,
|
||||
datasetCreateConfig: {
|
||||
locale: "fakeLocale",
|
||||
mashupDocument: "fakeMashup",
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// Assert
|
||||
expect(attemptCreate).not.toThrowError();
|
||||
});
|
||||
|
||||
it('if attempting to quickCreate without specifying an embed url, throw error', function () {
|
||||
// Arrange
|
||||
const component = $('<div></div>')
|
||||
.appendTo('#powerbi-fixture');
|
||||
|
||||
// Act
|
||||
const attemptCreate = (): void => {
|
||||
powerbi.quickCreate(component[0], {
|
||||
embedUrl: null,
|
||||
accessToken: accessToken,
|
||||
datasetCreateConfig: {
|
||||
locale: "fakeLocale",
|
||||
mashupDocument: "fakeMashup",
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// Assert
|
||||
expect(attemptCreate).toThrowError(Error);
|
||||
});
|
||||
|
||||
it('if attempting to quickCreate without specifying an access token, throw error', function () {
|
||||
// Arrange
|
||||
const component = $('<div></div>')
|
||||
.appendTo('#powerbi-fixture');
|
||||
|
||||
const originalToken = powerbi.accessToken;
|
||||
powerbi.accessToken = undefined;
|
||||
|
||||
// Act
|
||||
const attemptCreate = (): void => {
|
||||
powerbi.quickCreate(component[0], {
|
||||
embedUrl: embedUrl,
|
||||
accessToken: null,
|
||||
datasetCreateConfig: {
|
||||
locale: "fakeLocale",
|
||||
mashupDocument: "fakeMashup",
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// Assert
|
||||
expect(attemptCreate).toThrowError(Error);
|
||||
|
||||
// Cleanup
|
||||
powerbi.accessToken = originalToken;
|
||||
});
|
||||
});
|
||||
|
||||
describe('register components', function () {
|
||||
const registeredComponentType = 'fakeType';
|
||||
const embedConfig = {
|
||||
type: registeredComponentType,
|
||||
accessToken: "fakeAccessToken",
|
||||
embedUrl: "fakeEmbedUrl",
|
||||
id: "fakeReportId"
|
||||
};
|
||||
const createComponentFunc = (service, element, config): report.Report => new report.Report(service, element, config);
|
||||
const event = {
|
||||
type: registeredComponentType,
|
||||
id: 'fakeId',
|
||||
name: 'fakeName',
|
||||
value: 'fakeValue'
|
||||
};
|
||||
const routerEventUrls = ['/fakeComponent/:uniqueId/events/:eventName'];
|
||||
|
||||
it('happy path: register new component and then successfully embed', function () {
|
||||
powerbi.register(registeredComponentType, createComponentFunc, routerEventUrls);
|
||||
const myComponent = powerbi.embed(element, embedConfig);
|
||||
expect(myComponent).toBeDefined();
|
||||
});
|
||||
|
||||
it('should throw error if registering a component with legacy component type', function () {
|
||||
const attemptEmbed = (): void => {
|
||||
powerbi.register('report', createComponentFunc, routerEventUrls);
|
||||
};
|
||||
|
||||
expect(attemptEmbed).toThrowError(Error, 'The component name is reserved. Cannot register a component with this name.');
|
||||
});
|
||||
|
||||
it('should throw error if registering a component with existing type', function () {
|
||||
powerbi.register(registeredComponentType, createComponentFunc, routerEventUrls);
|
||||
const attemptEmbed = (): void => {
|
||||
powerbi.register(registeredComponentType, createComponentFunc, routerEventUrls);
|
||||
};
|
||||
|
||||
expect(attemptEmbed).toThrowError(Error, 'A component with this type is already registered.');
|
||||
});
|
||||
|
||||
it('should throw error if registering a component with invalid router event url', function () {
|
||||
const attemptEmbed = (): void => {
|
||||
powerbi.register(registeredComponentType, createComponentFunc, ['/fakeComponent/:invalidUniqueId/events/:eventName']);
|
||||
};
|
||||
|
||||
expect(attemptEmbed).toThrowError(Error, 'Invalid router event URL');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -40,6 +40,7 @@ export interface IApp {
|
|||
refreshData(): Promise<void>;
|
||||
exportData(): Promise<void>;
|
||||
validateCreateReport(config: models.IReportCreateConfiguration): Promise<models.IError[]>;
|
||||
validateQuickCreate(config: models.IQuickCreateConfiguration): Promise<models.IError[]>;
|
||||
switchMode(): Promise<void>;
|
||||
save(): Promise<void>;
|
||||
saveAs(saveAsParameters: models.ISaveAsParameters): Promise<void>;
|
||||
|
@ -84,6 +85,7 @@ export const mockAppSpyObj = {
|
|||
refreshData: jasmine.createSpy("refreshData").and.returnValue(Promise.resolve(null)),
|
||||
exportData: jasmine.createSpy("exportData").and.returnValue(Promise.resolve(null)),
|
||||
validateCreateReport: jasmine.createSpy("validateCreateReport").and.callFake(models.validateCreateReport),
|
||||
validateQuickCreate: jasmine.createSpy("validateQuickCreate").and.callFake(models.validateQuickCreate),
|
||||
switchMode: jasmine.createSpy("switchMode").and.returnValue(Promise.resolve(null)),
|
||||
save: jasmine.createSpy("save").and.returnValue(Promise.resolve(null)),
|
||||
saveAs: jasmine.createSpy("saveAs").and.returnValue(Promise.resolve(null)),
|
||||
|
@ -151,6 +153,8 @@ export const mockAppSpyObj = {
|
|||
mockAppSpyObj.exportData.and.callThrough();
|
||||
mockAppSpyObj.validateCreateReport.calls.reset();
|
||||
mockAppSpyObj.validateCreateReport.and.callThrough();
|
||||
mockAppSpyObj.validateQuickCreate.calls.reset();
|
||||
mockAppSpyObj.validateQuickCreate.and.callThrough();
|
||||
mockAppSpyObj.switchMode.calls.reset();
|
||||
mockAppSpyObj.switchMode.and.callThrough();
|
||||
mockAppSpyObj.save.calls.reset();
|
||||
|
|
|
@ -83,6 +83,19 @@ export function setupEmbedMockApp(iframeContentWindow: Window, parentWindow: Win
|
|||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Quick Create
|
||||
*/
|
||||
router.post('/quickcreate', (req, res) => {
|
||||
const createConfig = req.body;
|
||||
return app.validateQuickCreate(createConfig)
|
||||
.then(() => {
|
||||
res.send(202);
|
||||
}, error => {
|
||||
res.send(400, error);
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Report Embed
|
||||
*/
|
||||
|
|
Загрузка…
Ссылка в новой задаче