Merge pull request #388 from microsoft/release_2.23.1

Release 2.23.1
This commit is contained in:
may-hartov 2024-04-16 15:23:18 +03:00 коммит произвёл GitHub
Родитель c4578b614e 6b29334fa2
Коммит 10d3360357
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
19 изменённых файлов: 921 добавлений и 991 удалений

2
.gitignore поставляемый
Просмотреть файл

@ -11,3 +11,5 @@ package-lock.json
demo/package-lock.json
.vscode
owners.txt
test/util.spec.ts
.config/tsaoptions.json

36
dist/powerbi-client.d.ts поставляемый
Просмотреть файл

@ -1,4 +1,4 @@
// powerbi-client v2.22.2
// powerbi-client v2.23.1
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
declare module "config" {
@ -12,6 +12,7 @@ declare module "config" {
declare module "errors" {
export const APINotSupportedForRDLError = "This API is currently not supported for RDL reports";
export const EmbedUrlNotSupported = "Embed URL is invalid for this scenario. Please use Power BI REST APIs to get the valid URL";
export const invalidEmbedUrlErrorMessage: string;
}
declare module "util" {
import { HttpPostMessage } from 'http-post-message';
@ -124,6 +125,11 @@ declare module "util" {
* @returns {boolean}
*/
export function isCreate(embedType: string): boolean;
/**
* Checks if the embedUrl has an allowed power BI domain
* @hidden
*/
export function validateEmbedUrl(embedUrl: string): boolean;
}
declare module "embed" {
import * as models from 'powerbi-models';
@ -151,6 +157,7 @@ declare module "embed" {
export type ITileEmbedConfiguration = models.ITileEmbedConfiguration;
export type IQnaEmbedConfiguration = models.IQnaEmbedConfiguration;
export type IQuickCreateConfiguration = models.IQuickCreateConfiguration;
export type IReportCreateConfiguration = models.IReportCreateConfiguration;
export type ILocaleSettings = models.ILocaleSettings;
export type IQnaSettings = models.IQnaSettings;
export type IEmbedSettings = models.ISettings;
@ -597,7 +604,7 @@ declare module "ifilterable" {
}
}
declare module "visualDescriptor" {
import { ExportDataType, FiltersOperations, ICloneVisualRequest, ICloneVisualResponse, IExportDataResult, IFilter, ISlicerState, ISortByVisualRequest, IVisualLayout, VisualContainerDisplayMode } from 'powerbi-models';
import { ExportDataType, FiltersOperations, ICloneVisualRequest, ICloneVisualResponse, IExportDataResult, IFilter, ISlicerState, ISmartNarratives, ISortByVisualRequest, IVisualLayout, VisualContainerDisplayMode } from 'powerbi-models';
import { IHttpPostMessageResponse } from 'http-post-message';
import { IFilterable } from "ifilterable";
import { IPageNode } from "page";
@ -794,11 +801,21 @@ declare module "visualDescriptor" {
* @returns {Promise<IHttpPostMessageResponse<void>>}
*/
resizeVisual(width: number, height: number): Promise<IHttpPostMessageResponse<void>>;
/**
* Get insights for single visual
*
* ```javascript
* visual.getSmartNarrativeInsights();
* ```
*
* @returns {Promise<ISmartNarratives>}
*/
getSmartNarrativeInsights(): Promise<ISmartNarratives>;
}
}
declare module "page" {
import { IHttpPostMessageResponse } from 'http-post-message';
import { DisplayOption, FiltersOperations, ICustomPageSize, IFilter, IVisual, LayoutType, PageSizeType, SectionVisibility, VisualContainerDisplayMode, IPageBackground, IPageWallpaper } from 'powerbi-models';
import { DisplayOption, FiltersOperations, ICustomPageSize, IFilter, IVisual, LayoutType, PageSizeType, SectionVisibility, VisualContainerDisplayMode, IPageBackground, IPageWallpaper, ISmartNarratives } from 'powerbi-models';
import { IFilterable } from "ifilterable";
import { IReportNode } from "report";
import { VisualDescriptor } from "visualDescriptor";
@ -894,6 +911,16 @@ declare module "page" {
* @hidden
*/
constructor(report: IReportNode, name: string, displayName?: string, isActivePage?: boolean, visibility?: SectionVisibility, defaultSize?: ICustomPageSize, defaultDisplayOption?: DisplayOption, mobileSize?: ICustomPageSize, background?: IPageBackground, wallpaper?: IPageWallpaper);
/**
* Get insights for report page
*
* ```javascript
* page.getSmartNarrativeInsights();
* ```
*
* @returns {Promise<ISmartNarratives>}
*/
getSmartNarrativeInsights(): Promise<ISmartNarratives>;
/**
* Gets all page level filters within the report.
*
@ -2940,12 +2967,13 @@ declare module "powerbi-client" {
export { Report } from "report";
export { Dashboard } from "dashboard";
export { Tile } from "tile";
export { IEmbedConfiguration, IQnaEmbedConfiguration, IVisualEmbedConfiguration, IReportEmbedConfiguration, IDashboardEmbedConfiguration, ITileEmbedConfiguration, IQuickCreateConfiguration, Embed, ILocaleSettings, IEmbedSettings, IQnaSettings, } from "embed";
export { IEmbedConfiguration, IQnaEmbedConfiguration, IVisualEmbedConfiguration, IReportEmbedConfiguration, IDashboardEmbedConfiguration, ITileEmbedConfiguration, IQuickCreateConfiguration, IReportCreateConfiguration, 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 { Create } from "create";
export { BasicFilterBuilder, AdvancedFilterBuilder, TopNFilterBuilder, RelativeDateFilterBuilder, RelativeTimeFilterBuilder } from "FilterBuilders/index";
global {
interface Window {

1741
dist/powerbi.js поставляемый

Разница между файлами не показана из-за своего большого размера Загрузить разницу

4
dist/powerbi.min.js поставляемый

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Просмотреть файл

@ -1,6 +1,6 @@
{
"name": "powerbi-client",
"version": "2.22.2",
"version": "2.23.1",
"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",
@ -79,9 +79,9 @@
},
"dependencies": {
"http-post-message": "^0.2",
"powerbi-models": "^1.12.3",
"powerbi-models": "^1.14.0",
"powerbi-router": "^0.1",
"window-post-message-proxy": "^0.2"
"window-post-message-proxy": "^0.2.7"
},
"publishConfig": {
"tag": "beta"

Просмотреть файл

@ -3,7 +3,7 @@
/** @ignore *//** */
const config = {
version: '2.22.2',
version: '2.23.1',
type: 'js'
};

Просмотреть файл

@ -3,9 +3,9 @@
import * as models from 'powerbi-models';
import * as sdkConfig from './config';
import { EmbedUrlNotSupported } from './errors';
import { EmbedUrlNotSupported, invalidEmbedUrlErrorMessage } from './errors';
import { ICustomEvent, IEvent, IEventHandler, Service } from './service';
import { addParamToUrl, assign, autoAuthInEmbedUrl, createRandomString, getTimeDiffInMilliseconds, remove, isCreate } from './util';
import { addParamToUrl, assign, autoAuthInEmbedUrl, createRandomString, getTimeDiffInMilliseconds, remove, isCreate, validateEmbedUrl } from './util';
declare global {
interface Document {
@ -50,6 +50,8 @@ export type IQnaEmbedConfiguration = models.IQnaEmbedConfiguration;
export type IQuickCreateConfiguration = models.IQuickCreateConfiguration;
export type IReportCreateConfiguration = models.IReportCreateConfiguration;
export type ILocaleSettings = models.ILocaleSettings;
export type IQnaSettings = models.IQnaSettings;
@ -571,7 +573,7 @@ export abstract class Embed {
const accessTokenProvider = eventHooks.accessTokenProvider;
if (!!accessTokenProvider) {
if ((['create', 'quickcreate', 'report'].indexOf(this.embedtype.toLowerCase()) === -1) || this.config.tokenType !== models.TokenType.Aad) {
if ((['create', 'quickcreate', 'report'].indexOf(this.embedtype.toLowerCase()) === -1) || this.config.tokenType !== models.TokenType.Aad) {
throw new Error("accessTokenProvider is only supported in report SaaS embed");
}
}
@ -632,10 +634,6 @@ export abstract class Embed {
// Trim spaces to fix user mistakes.
hostname = hostname.toLowerCase().trim();
if (hostname.indexOf("http://") === 0) {
throw new Error("HTTP is not allowed. HTTPS is required");
}
if (hostname.indexOf("https://") === 0) {
return `${hostname}/${endpoint}`;
}
@ -743,6 +741,9 @@ export abstract class Embed {
if (!this.iframe) {
const iframeContent = document.createElement("iframe");
const embedUrl = this.config.uniqueId ? addParamToUrl(this.config.embedUrl, 'uid', this.config.uniqueId) : this.config.embedUrl;
if (!validateEmbedUrl(embedUrl)) {
throw new Error(invalidEmbedUrlErrorMessage);
}
iframeContent.style.width = '100%';
iframeContent.style.height = '100%';

Просмотреть файл

@ -3,4 +3,5 @@
export const APINotSupportedForRDLError = "This API is currently not supported for RDL reports";
export const EmbedUrlNotSupported = "Embed URL is invalid for this scenario. Please use Power BI REST APIs to get the valid URL";
export const invalidEmbedUrlErrorMessage: string = "Invalid embed URL detected. Either URL hostname or protocol are invalid. Please use Power BI REST APIs to get the valid URL";

Просмотреть файл

@ -18,6 +18,7 @@ import {
VisualContainerDisplayMode,
IPageBackground,
IPageWallpaper,
ISmartNarratives,
} from 'powerbi-models';
import { IFilterable } from './ifilterable';
import { IReportNode, Report } from './report';
@ -139,6 +140,28 @@ export class Page implements IPageNode, IFilterable {
this.wallpaper = wallpaper;
}
/**
* Get insights for report page
*
* ```javascript
* page.getSmartNarrativeInsights();
* ```
*
* @returns {Promise<ISmartNarratives>}
*/
async getSmartNarrativeInsights(): Promise<ISmartNarratives > {
if (isRDLEmbed(this.report.config.embedUrl)) {
return Promise.reject(APINotSupportedForRDLError);
}
try {
const response = await this.report.service.hpm.get<ISmartNarratives>(`/report/pages/${this.name}/smartNarrativeInsights`, { uid: this.report.config.uniqueId }, this.report.iframe.contentWindow);
return response.body;
} catch (response) {
throw response.body;
}
}
/**
* Gets all page level filters within the report.
*

Просмотреть файл

@ -32,6 +32,7 @@ export {
IDashboardEmbedConfiguration,
ITileEmbedConfiguration,
IQuickCreateConfiguration,
IReportCreateConfiguration,
Embed,
ILocaleSettings,
IEmbedSettings,
@ -52,6 +53,9 @@ export {
export {
QuickCreate
} from './quickCreate';
export {
Create
} from './create';
export {
BasicFilterBuilder,
AdvancedFilterBuilder,

Просмотреть файл

@ -637,6 +637,10 @@ export class Report extends Embed implements IReportNode, IFilterable {
* ```
*/
async refresh(): Promise<void> {
if (isRDLEmbed(this.config.embedUrl)) {
return Promise.reject(APINotSupportedForRDLError);
}
try {
const response = await this.service.hpm.post<void>('/report/refresh', null, { uid: this.config.uniqueId }, this.iframe.contentWindow);
return response.body;

Просмотреть файл

@ -29,6 +29,7 @@ import { Visual } from './visual';
import * as utils from './util';
import { QuickCreate } from './quickCreate';
import * as sdkConfig from './config';
import { invalidEmbedUrlErrorMessage } from './errors';
export interface IEvent<T> {
type: string;
@ -667,6 +668,10 @@ export class Service implements IService {
* @param {HTMLElement} [element=undefined]
*/
preload(config: IComponentEmbedConfiguration | IEmbedConfigurationBase, element?: HTMLElement): HTMLIFrameElement {
if (!utils.validateEmbedUrl(config.embedUrl)) {
throw new Error(invalidEmbedUrlErrorMessage);
}
const iframeContent = document.createElement("iframe");
iframeContent.setAttribute("style", "display:none;");
iframeContent.setAttribute("src", config.embedUrl);

Просмотреть файл

@ -3,6 +3,22 @@
import { HttpPostMessage } from 'http-post-message';
/**
* @hidden
*/
const allowedPowerBiHostsRegex =
new RegExp(/(.+\.powerbi\.com$)|(.+\.fabric\.microsoft\.com$)|(.+\.analysis\.windows-int\.net$)|(.+\.analysis-df\.windows\.net$)/);
/**
* @hidden
*/
const allowedPowerBiHostsSovRegex = new RegExp(/^app\.powerbi\.cn$|^app(\.mil\.|\.high\.|\.)powerbigov\.us$|^app\.powerbi\.eaglex\.ic\.gov$|^app\.powerbi\.microsoft\.scloud$/);
/**
* @hidden
*/
const expectedEmbedUrlProtocol: string = "https:";
/**
* Raises a custom event with event data on the specified HTML element.
*
@ -194,7 +210,7 @@ export function autoAuthInEmbedUrl(embedUrl: string): boolean {
export function getRandomValue(): number {
// window.msCrypto for IE
const cryptoObj = window.crypto || window.msCrypto;
const cryptoObj = window.crypto || (window as any).msCrypto;
const randomValueArray = new Uint32Array(1);
cryptoObj.getRandomValues(randomValueArray);
@ -223,3 +239,21 @@ export function getTimeDiffInMilliseconds(start: Date, end: Date): number {
export function isCreate(embedType: string): boolean {
return embedType === 'create' || embedType === 'quickcreate';
}
/**
* Checks if the embedUrl has an allowed power BI domain
* @hidden
*/
export function validateEmbedUrl(embedUrl: string): boolean {
if (embedUrl) {
let url: URL;
try {
url = new URL(embedUrl.toLowerCase());
} catch(e) {
// invalid URL
return false;
}
return url.protocol === expectedEmbedUrlProtocol &&
(allowedPowerBiHostsRegex.test(url.hostname) || allowedPowerBiHostsSovRegex.test(url.hostname));
}
}

Просмотреть файл

@ -10,11 +10,12 @@ import {
IExportDataResult,
IFilter,
ISlicerState,
ISmartNarratives,
ISortByVisualRequest,
IUpdateFiltersRequest,
IVisualLayout,
VisualContainerDisplayMode,
VisualLevelFilters
VisualLevelFilters,
} from 'powerbi-models';
import { IHttpPostMessageResponse } from 'http-post-message';
import { IFilterable } from './ifilterable';
@ -319,4 +320,22 @@ export class VisualDescriptor implements IVisualNode, IFilterable {
return report.resizeVisual(pageName, visualName, width, height);
}
/**
* Get insights for single visual
*
* ```javascript
* visual.getSmartNarrativeInsights();
* ```
*
* @returns {Promise<ISmartNarratives>}
*/
async getSmartNarrativeInsights(): Promise<ISmartNarratives> {
try {
const response = await this.page.report.service.hpm.get<ISmartNarratives>(`/report/pages/${this.page.name}/visuals/${this.name}/smartNarrativeInsights`, { uid: this.page.report.config.uniqueId }, this.page.report.iframe.contentWindow);
return response.body;
} catch (response) {
throw response.body;
}
}
}

Просмотреть файл

@ -48,9 +48,10 @@ describe('SDK-to-HPM', function () {
};
spyOn(utils, "getTimeDiffInMilliseconds").and.callFake(() => 700); // Prevent requests from being throttled.
spyOn(utils, 'validateEmbedUrl').and.callFake(() => { return true; });
powerbi = new service.Service(spyHpmFactory, noop, spyRouterFactory, { wpmpName: 'SDK-to-HPM report wpmp' });
sdkSessionId = powerbi.getSdkSessionId();
});

Просмотреть файл

@ -31,6 +31,9 @@ describe('SDK-to-MockApp', function () {
powerbi = new service.Service(factories.hpmFactory, factories.wpmpFactory, factories.routerFactory, {
wpmpName: 'SDK-to-MockApp HostWpmp'
});
spyOn(utils, 'validateEmbedUrl').and.callFake(() => { return true; });
element = document.createElement('div');
element.id = "reportContainer1";
element.className = 'powerbi-report-container2';

Просмотреть файл

@ -5,6 +5,7 @@ import * as service from '../src/service';
import * as report from '../src/report';
import * as Wpmp from 'window-post-message-proxy';
import * as factories from '../src/factories';
import * as utils from '../src/util';
import { spyWpmp } from './utility/mockWpmp';
import { spyHpm } from './utility/mockHpm';
import { spyRouter } from './utility/mockRouter';
@ -17,6 +18,7 @@ describe('SDK-to-WPMP', function () {
let uniqueId: string;
beforeEach(function () {
spyOn(utils, 'validateEmbedUrl').and.callFake(() => { return true; });
const spyWpmpFactory: factories.IWpmpFactory = (_name?: string, _logMessages?: boolean) => {
return <Wpmp.WindowPostMessageProxy>spyWpmp;
};

Просмотреть файл

@ -6,6 +6,7 @@ import * as embed from '../src/embed';
import * as report from '../src/report';
import * as create from '../src/create';
import * as factories from '../src/factories';
import * as utils from '../src/util';
import { EmbedUrlNotSupported } from '../src/errors';
// Todo: remove JQuery usage from this tests file.
@ -42,6 +43,7 @@ describe('service', function () {
let element: HTMLDivElement;
beforeEach(function () {
spyOn(utils, 'validateEmbedUrl').and.callFake(() => { return true; });
powerbi = new service.Service(factories.hpmFactory, factories.wpmpFactory, factories.routerFactory);
powerbi.accessToken = 'ABC123';
element = document.createElement('div');

Просмотреть файл

@ -3,6 +3,7 @@
import * as service from '../src/service';
import * as factories from '../src/factories';
import * as utils from '../src/util';
// Avoid adding new tests to this file, create another spec file instead.
@ -12,6 +13,7 @@ describe('embed', function () {
let iframe: HTMLIFrameElement;
beforeEach(function () {
spyOn(utils, 'validateEmbedUrl').and.callFake(() => { return true; });
powerbi = new service.Service(factories.hpmFactory, factories.wpmpFactory, factories.routerFactory);
powerbi.accessToken = 'ABC123';
container = document.createElement('iframe');