Added bookmarks support (#6)
* Added bookmarks support Added bookmarks support * Code review * Update documentation * Fix docs after review
This commit is contained in:
Родитель
7568b1bd34
Коммит
73ba661a7d
|
@ -37,3 +37,5 @@ pbiviz start
|
|||
3. Advanced selection with the Advanced Filter API
|
||||
- [Adding the Advanced Filter API to the project](doc/AddingAdvancedFilterAPI.md)
|
||||
- [Using the Advanced Filter API](doc/UsingAdvancedFilterAPI.md)
|
||||
4. Bookmarks support
|
||||
- [Adding bookmarks support to the project](doc/AddingBookmarksSuppoprt.md)
|
|
@ -0,0 +1,73 @@
|
|||
# Adding bookmarks support to the project
|
||||
|
||||
The main documentation about bookmarks can be found [here](https://github.com/Microsoft/PowerBI-visuals/blob/master/Tutorial/BookmarksSupport.md).
|
||||
|
||||
To add bookmarks support for the visual, you should update to version 3.0.0 or higher of `powerbi-visuals-utils-interactivityutils`.
|
||||
|
||||
In the update `updateOnRangeSelectonChange` method the visual creates an AdvancedFilter and applies the filter with one or two conditions and calls `applyAdvancedFilter`, where `applyAdvancedFilter` [calls](https://github.com/Microsoft/powerbi-visuals-sampleslicer/blob/master/src/sampleSlicer.ts#L795) `this.visualHost.applyJsonFilter` method.
|
||||
|
||||
In each update the visual [inspects and restores](https://github.com/Microsoft/powerbi-visuals-sampleslicer/pull/6/files#diff-5929da3be6a696fb9df5e3571baceb52R356) the persisted filter by using [`FilterManager.restoreFilter`](https://github.com/Microsoft/PowerBI-visuals/blob/master/Tutorial/BookmarksSupport.md#visuals-with-filter).
|
||||
|
||||
```typescript
|
||||
private restoreFilter(data: SampleSlicerData) {
|
||||
// restore advanced filter from visual properties
|
||||
let restoredFilter: IAdvancedFilter =
|
||||
FilterManager.restoreFilter(data && data.slicerSettings.general.filter) as IAdvancedFilter;
|
||||
// if filter was persisted, the visual retrieves the conditions of the advanced filter
|
||||
if (restoredFilter) {
|
||||
restoredFilter.target = this.getCallbacks().getAdvancedFilterColumnTarget();
|
||||
// reset to default
|
||||
// modify the values to match the filter values
|
||||
// in some cases we can receive values with only one condition
|
||||
if (restoredFilter.conditions.length === 1) {
|
||||
let value: {
|
||||
max?: any,
|
||||
min?: any
|
||||
} = {};
|
||||
|
||||
// get min and max values in the dataset
|
||||
let convertedValues = data.slicerDataPoints.map( (dataPoint: SampleSlicerDataPoint) => +dataPoint.category );
|
||||
value.min = d3.min(convertedValues);
|
||||
value.max = d3.max(convertedValues);
|
||||
|
||||
// if some conditions is missing, the visual adds the condition with matching value
|
||||
let operator = restoredFilter.conditions[0].operator;
|
||||
if (operator === "LessThanOrEqual" || operator === "LessThan") {
|
||||
restoredFilter.conditions.push({
|
||||
operator: "GreaterThan",
|
||||
value: value.min
|
||||
});
|
||||
}
|
||||
if (operator === "GreaterThanOrEqual" || operator === "GreaterThan") {
|
||||
restoredFilter.conditions.push({
|
||||
operator: "LessThan",
|
||||
value: value.max
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// create ValueRange object to apply current filter state to the slicer visual
|
||||
let rangeValue: ValueRange<number> = <ValueRange<number>>{};
|
||||
|
||||
restoredFilter.conditions.forEach( (condition: IAdvancedFilterCondition) => {
|
||||
let value = condition.value;
|
||||
let operator = condition.operator;
|
||||
if (operator === "LessThanOrEqual" || operator === "LessThan") {
|
||||
rangeValue.max = <number>value;
|
||||
}
|
||||
if (operator === "GreaterThanOrEqual" || operator === "GreaterThan") {
|
||||
rangeValue.min = <number>value;
|
||||
}
|
||||
});
|
||||
|
||||
// change visual state of slicer
|
||||
this.behavior.scalableRange.setValue(rangeValue);
|
||||
// change visual state of text boxes
|
||||
this.onRangeInputTextboxChange(rangeValue.min.toString(), RangeValueType.Start);
|
||||
this.onRangeInputTextboxChange(rangeValue.max.toString(), RangeValueType.End);
|
||||
}
|
||||
}
|
||||
```
|
||||
Resuming: in this method the visual restores the `restoredFilter` object, parses conditions for restoring saved values of the slicer and applies values to slicer and text boxes.
|
||||
|
||||
You **should not** persist the filter in the visual properties. Because Power BI saves filter for the visual. And `persistSelectionState`, `restorePersistedRangeSelectionState` and other methods [were removed](https://github.com/Microsoft/powerbi-visuals-sampleslicer/pull/6/files#diff-5929da3be6a696fb9df5e3571baceb52L809).
|
|
@ -8,7 +8,7 @@ For <b>discrete</b> cross-visual data-point selection the Sample Slicer visual r
|
|||
|
||||
ISelectionHandler holds the state of all discrete (possibly multiple) data-point selections. The handler is updated on each data-point selection event (each mouse click) and does NOT automatically propagate the event to the hosting application. The selection state is only propagated to the host when the method ISelectionHandler.applySelectionFilter() is invoked.
|
||||
|
||||
Below is the code executed on each slicer mouse click. The handler is updated with the select/unselect data point event and the complete discrete selection state is flushed to the hosting application. Additionally, the selection state is persisted to the visual's properties so the next time the visual is loaded the selection can be restored.
|
||||
Below is the code executed on each slicer mouse click. The handler is updated with the select/unselect data point event and the complete discrete selection state is flushed to the hosting application. Additionally, the selection state is persisted to the visual's properties as applyed filter, so the next time the visual is loaded the selection can be restored.
|
||||
|
||||
```
|
||||
/* update selection state */
|
||||
|
@ -16,9 +16,6 @@ Below is the code executed on each slicer mouse click. The handler is updated wi
|
|||
|
||||
/* send selection state to the host*/
|
||||
selectionHandler.applySelectionFilter();
|
||||
|
||||
/*persiste selection state to properties */
|
||||
this.persistSelectionState();
|
||||
```
|
||||
|
||||
An instance implementing ISelectionHandler interface is created by InteractivityUtils and supplied to SelectionBehavior class as an argument of SelectionBehavior::bindEvents() method call.
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "powerbi-visuals-sampleslicer",
|
||||
"version": "1.1.0",
|
||||
"version": "1.2.0",
|
||||
"author": {
|
||||
"name": "Microsoft"
|
||||
},
|
||||
|
@ -10,6 +10,7 @@
|
|||
"url": "git+https://github.com/Microsoft/powerbi-visuals-sampleslicer"
|
||||
},
|
||||
"scripts": {
|
||||
"postinstall": "pbiviz update 1.11.0",
|
||||
"pbiviz": "pbiviz",
|
||||
"start": "pbiviz start",
|
||||
"package": "pbiviz package",
|
||||
|
@ -23,7 +24,7 @@
|
|||
"powerbi-visuals-utils-colorutils": "^1.0.0",
|
||||
"powerbi-visuals-utils-dataviewutils": "^1.2.0",
|
||||
"powerbi-visuals-utils-formattingutils": "^2.1.0",
|
||||
"powerbi-visuals-utils-interactivityutils": "^1.0.0",
|
||||
"powerbi-visuals-utils-interactivityutils": "^3.0.0",
|
||||
"powerbi-visuals-utils-typeutils": "^1.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -35,7 +36,7 @@
|
|||
"@types/nouislider": "9.0.0",
|
||||
"jasmine": "2.6.0",
|
||||
"jasmine-jquery": "2.1.1",
|
||||
"powerbi-visuals-tools": "1.7.0",
|
||||
"powerbi-visuals-tools": "1.11.2",
|
||||
"tslint": "^5.4.3",
|
||||
"tslint-microsoft-contrib": "^5.0.0",
|
||||
"typescript": "^2.3.4"
|
||||
|
|
|
@ -4,12 +4,12 @@
|
|||
"displayName": "SampleSlicer",
|
||||
"guid": "SampleSlicer1448559807355",
|
||||
"visualClassName": "SampleSlicer",
|
||||
"version": "1.1.0",
|
||||
"version": "1.2.0",
|
||||
"description": "Use this slicer to select discrete numeric categories or range of numeric category values.",
|
||||
"supportUrl": "http://community.powerbi.com",
|
||||
"gitHubUrl": "https://github.com/Microsoft/powerbi-visuals-sampleslicer"
|
||||
},
|
||||
"apiVersion": "1.7.0",
|
||||
"apiVersion": "1.11.0",
|
||||
"author": {
|
||||
"name": "Microsoft"
|
||||
},
|
||||
|
|
|
@ -51,6 +51,9 @@ module powerbi.extensibility.visual {
|
|||
import TextProperties = powerbi.extensibility.utils.formatting.TextProperties;
|
||||
import textMeasurementService = powerbi.extensibility.utils.formatting.textMeasurementService;
|
||||
|
||||
import FilterManager = powerbi.extensibility.utils.filter.FilterManager;
|
||||
import AppliedFilter = powerbi.extensibility.utils.filter.AppliedFilter;
|
||||
|
||||
export const enum RangeValueType {
|
||||
Start,
|
||||
End
|
||||
|
@ -71,7 +74,6 @@ module powerbi.extensibility.visual {
|
|||
|
||||
export interface SampleSlicerCallbacks {
|
||||
getPersistedSelectionState?: () => powerbi.extensibility.ISelectionId[];
|
||||
persistSelectionState?: (selectionIds: string[]) => void;
|
||||
restorePersistedRangeSelectionState?: () => void;
|
||||
applyAdvancedFilter?: (filter: IAdvancedFilter) => void;
|
||||
getAdvancedFilterColumnTarget?: () => IFilterColumnTarget;
|
||||
|
@ -166,6 +168,7 @@ module powerbi.extensibility.visual {
|
|||
slicerSettings.general.selection = DataViewObjectsModule.getValue(dataView.metadata.objects, persistedSettingsDataViewObjectPropertyIdentifiers.general.selection, defaultSettings.general.selection);
|
||||
slicerSettings.general.rangeSelectionStart = DataViewObjectsModule.getValue(dataView.metadata.objects, persistedSettingsDataViewObjectPropertyIdentifiers.general.rangeSelectionStart, defaultSettings.general.selection);
|
||||
slicerSettings.general.rangeSelectionEnd = DataViewObjectsModule.getValue(dataView.metadata.objects, persistedSettingsDataViewObjectPropertyIdentifiers.general.rangeSelectionEnd, defaultSettings.general.selection);
|
||||
slicerSettings.general.filter = DataViewObjectsModule.getValue(dataView.metadata.objects, persistedSettingsDataViewObjectPropertyIdentifiers.general.filter, defaultSettings.general.filter);
|
||||
}
|
||||
|
||||
if (searchText) {
|
||||
|
@ -194,20 +197,6 @@ module powerbi.extensibility.visual {
|
|||
this.interactivityService = createInteractivityService(options.host);
|
||||
|
||||
this.settings = defaultSettings;
|
||||
|
||||
Object.defineProperty(window, "pageXOffset", {
|
||||
get: function () {
|
||||
return window.window.pageXOffset;
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(window, "pageYOffset", {
|
||||
get: function () {
|
||||
return window.window.pageYOffset;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
public update(options: VisualUpdateOptions) {
|
||||
|
@ -293,6 +282,60 @@ module powerbi.extensibility.visual {
|
|||
return [];
|
||||
}
|
||||
|
||||
private restoreFilter(data: SampleSlicerData) {
|
||||
let restoredFilter: IAdvancedFilter =
|
||||
FilterManager.restoreFilter(data && data.slicerSettings.general.filter) as IAdvancedFilter;
|
||||
if (restoredFilter) {
|
||||
restoredFilter.target = this.getCallbacks().getAdvancedFilterColumnTarget();
|
||||
// reset to default
|
||||
// this.onRangeInputTextboxChange("", RangeValueType.Start, true);
|
||||
// this.onRangeInputTextboxChange("", RangeValueType.End, true);
|
||||
// change value to correspond the filter values
|
||||
// in some case we can get value with one condition only
|
||||
if (restoredFilter.conditions.length === 1) {
|
||||
let value: {
|
||||
max?: any,
|
||||
min?: any
|
||||
} = {};
|
||||
|
||||
let convertedValues = data.slicerDataPoints.map( (dataPoint: SampleSlicerDataPoint) => +dataPoint.category );
|
||||
value.min = d3.min(convertedValues);
|
||||
value.max = d3.max(convertedValues);
|
||||
|
||||
let operator = restoredFilter.conditions[0].operator;
|
||||
if (operator === "LessThanOrEqual" || operator === "LessThan") {
|
||||
restoredFilter.conditions.push({
|
||||
operator: "GreaterThan",
|
||||
value: value.min
|
||||
});
|
||||
}
|
||||
if (operator === "GreaterThanOrEqual" || operator === "GreaterThan") {
|
||||
restoredFilter.conditions.push({
|
||||
operator: "LessThan",
|
||||
value: value.max
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let rangeValue: ValueRange<number> = <ValueRange<number>>{};
|
||||
|
||||
restoredFilter.conditions.forEach( (condition: IAdvancedFilterCondition) => {
|
||||
let value = condition.value;
|
||||
let operator = condition.operator;
|
||||
if (operator === "LessThanOrEqual" || operator === "LessThan") {
|
||||
rangeValue.max = <number>value;
|
||||
}
|
||||
if (operator === "GreaterThanOrEqual" || operator === "GreaterThan") {
|
||||
rangeValue.min = <number>value;
|
||||
}
|
||||
});
|
||||
|
||||
this.behavior.scalableRange.setValue(rangeValue);
|
||||
this.onRangeInputTextboxChange(rangeValue.min.toString(), RangeValueType.Start);
|
||||
this.onRangeInputTextboxChange(rangeValue.max.toString(), RangeValueType.End);
|
||||
}
|
||||
}
|
||||
|
||||
private updateInternal(resetScrollbarPosition: boolean) {
|
||||
// convert data to internal representation
|
||||
let data = SampleSlicer.converter(
|
||||
|
@ -307,6 +350,8 @@ module powerbi.extensibility.visual {
|
|||
return;
|
||||
}
|
||||
|
||||
this.restoreFilter(data);
|
||||
|
||||
if (this.slicerData) {
|
||||
if (this.isSelectionSaved) {
|
||||
this.isSelectionLoaded = true;
|
||||
|
@ -343,7 +388,6 @@ module powerbi.extensibility.visual {
|
|||
this.updateSliderInputTextboxes();
|
||||
}
|
||||
|
||||
|
||||
public createInputElement(control: JQuery): JQuery {
|
||||
let $element: JQuery = $('<input type="text"/>')
|
||||
.attr("type", "text")
|
||||
|
@ -399,7 +443,6 @@ module powerbi.extensibility.visual {
|
|||
this.$start = this.createInputElement($startControl);
|
||||
this.$end = this.createInputElement($endControl);
|
||||
|
||||
|
||||
let slicerContainer: Selection<any> = d3.select(this.$root.get(0))
|
||||
.append('div')
|
||||
.classed(SampleSlicer.ContainerSelector.className, true)
|
||||
|
@ -541,7 +584,7 @@ module powerbi.extensibility.visual {
|
|||
return value != null ? valueFormatter.format(value, "#") : '';
|
||||
}
|
||||
|
||||
private onRangeInputTextboxChange(inputString: string, rangeValueType: RangeValueType): void {
|
||||
private onRangeInputTextboxChange(inputString: string, rangeValueType: RangeValueType, supressFilter: boolean = false): void {
|
||||
// parse input
|
||||
let inputValue: number;
|
||||
if (!inputString) {
|
||||
|
@ -567,10 +610,13 @@ module powerbi.extensibility.visual {
|
|||
}
|
||||
range.max = inputValue;
|
||||
}
|
||||
this.behavior.scalableRange.setValue(range);
|
||||
|
||||
// trigger range change processing
|
||||
this.behavior.updateOnRangeSelectonChange();
|
||||
if (!supressFilter) {
|
||||
this.behavior.scalableRange.setValue(range);
|
||||
|
||||
// trigger range change processing
|
||||
this.behavior.updateOnRangeSelectonChange();
|
||||
}
|
||||
}
|
||||
|
||||
private enterSelection(rowSelection: Selection<any>): void {
|
||||
|
@ -783,8 +829,6 @@ module powerbi.extensibility.visual {
|
|||
: textMeasurementService.estimateSvgTextHeight(SampleSlicer.getSampleTextProperties(textSettings.textSize));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Callbacks consumed by the SelectionBehavior class
|
||||
* */
|
||||
|
@ -792,7 +836,7 @@ module powerbi.extensibility.visual {
|
|||
let callbacks: SampleSlicerCallbacks = {};
|
||||
|
||||
callbacks.applyAdvancedFilter = (filter: IAdvancedFilter): void => {
|
||||
this.visualHost.applyJsonFilter(filter, "general", "filter");
|
||||
this.visualHost.applyJsonFilter(filter, "general", "filter", FilterAction.merge );
|
||||
};
|
||||
|
||||
callbacks.getAdvancedFilterColumnTarget = (): IFilterColumnTarget => {
|
||||
|
@ -806,35 +850,6 @@ module powerbi.extensibility.visual {
|
|||
return target;
|
||||
};
|
||||
|
||||
callbacks.persistSelectionState = (selectionIds: string[]): void => {
|
||||
this.visualHost.persistProperties(<VisualObjectInstancesToPersist>{
|
||||
merge: [{
|
||||
objectName: "general",
|
||||
selector: null,
|
||||
properties: {
|
||||
selection: selectionIds && JSON.stringify(selectionIds) || "",
|
||||
rangeSelectionStart: JSON.stringify(this.formatValue(this.behavior.scalableRange.getValue().min)),
|
||||
rangeSelectionEnd: JSON.stringify(this.formatValue(this.behavior.scalableRange.getValue().max))
|
||||
}
|
||||
}]
|
||||
});
|
||||
this.isSelectionSaved = true;
|
||||
};
|
||||
|
||||
callbacks.restorePersistedRangeSelectionState = (): void => {
|
||||
let rangeSelectionStart: string = JSON.parse(this.slicerData.slicerSettings.general.rangeSelectionStart);
|
||||
let rangeSelectionEnd: string = JSON.parse(this.slicerData.slicerSettings.general.rangeSelectionEnd);
|
||||
|
||||
if (rangeSelectionStart) {
|
||||
this.$start.val(rangeSelectionStart);
|
||||
this.onRangeInputTextboxChange(rangeSelectionStart, RangeValueType.Start);
|
||||
}
|
||||
if (rangeSelectionEnd) {
|
||||
this.$end.val(rangeSelectionEnd);
|
||||
this.onRangeInputTextboxChange(rangeSelectionEnd, RangeValueType.End);
|
||||
}
|
||||
};
|
||||
|
||||
callbacks.getPersistedSelectionState = (): powerbi.extensibility.ISelectionId[] => {
|
||||
try {
|
||||
return JSON.parse(this.slicerData.slicerSettings.general.selection) || [];
|
||||
|
|
|
@ -74,10 +74,6 @@ module powerbi.extensibility.visual {
|
|||
|
||||
this.selectionHandler = selectionHandler;
|
||||
|
||||
if (!this.options.isSelectionLoaded) {
|
||||
this.restoreSelectionStateFromPersistedProperties();
|
||||
}
|
||||
|
||||
slicers.on("click", (dataPoint: SampleSlicerDataPoint, index: number) => {
|
||||
(d3.event as MouseEvent).preventDefault();
|
||||
|
||||
|
@ -88,9 +84,6 @@ module powerbi.extensibility.visual {
|
|||
|
||||
/* send selection state to the host*/
|
||||
selectionHandler.applySelectionFilter();
|
||||
|
||||
/*persiste selection state to properties */
|
||||
this.persistSelectionState();
|
||||
});
|
||||
|
||||
}
|
||||
|
@ -110,57 +103,16 @@ module powerbi.extensibility.visual {
|
|||
}
|
||||
|
||||
public clearAllDiscreteSelections() {
|
||||
|
||||
/* update state to clear all selections */
|
||||
this.selectionHandler.handleClearSelection();
|
||||
|
||||
/*persiste selection state to properties */
|
||||
this.persistSelectionState();
|
||||
if (this.selectionHandler) {
|
||||
this.selectionHandler.handleClearSelection();
|
||||
}
|
||||
}
|
||||
|
||||
public clearRangeSelection(): void {
|
||||
this.scalableRange = new ScalableRange();
|
||||
}
|
||||
|
||||
|
||||
public restoreSelectionStateFromPersistedProperties(): void {
|
||||
const savedSelectionIds: ISelectionId[] = this.callbacks.getPersistedSelectionState();
|
||||
|
||||
if (savedSelectionIds.length) {
|
||||
/* clear selection state */
|
||||
this.selectionHandler.handleClearSelection();
|
||||
|
||||
/* restore selection state from persisted properties */
|
||||
this.dataPoints
|
||||
.filter(dataPoint => {
|
||||
return savedSelectionIds.some((selectionId: ISelectionId) => {
|
||||
return (dataPoint.identity as any).getKey() === selectionId;
|
||||
});
|
||||
})
|
||||
.forEach((dataPoint: SampleSlicerDataPoint) => {
|
||||
this.selectionHandler.handleSelection(dataPoint, true);
|
||||
});
|
||||
|
||||
/* send selection state to the host */
|
||||
this.selectionHandler.applySelectionFilter();
|
||||
} else {
|
||||
this.callbacks.restorePersistedRangeSelectionState();
|
||||
}
|
||||
}
|
||||
|
||||
public persistSelectionState(): void {
|
||||
let selectedIds: ISelectionId[],
|
||||
selectionIdKeys: string[];
|
||||
|
||||
selectedIds = <ISelectionId[]>(<any>this.selectionHandler).selectedIds;
|
||||
|
||||
selectionIdKeys = selectedIds.map((selectionId: ISelectionId) => {
|
||||
return (selectionId as any).getKey();
|
||||
});
|
||||
|
||||
this.callbacks.persistSelectionState(selectionIdKeys);
|
||||
}
|
||||
|
||||
public styleSlicerInputs(slicers: Selection<any>, hasSelection: boolean) {
|
||||
let settings = this.slicerSettings;
|
||||
slicers.each(function (dataPoint: SampleSlicerDataPoint) {
|
||||
|
|
|
@ -34,6 +34,7 @@ module powerbi.extensibility.visual {
|
|||
rangeSelectionEnd: string;
|
||||
multiselect: boolean;
|
||||
selection: string;
|
||||
filter: any;
|
||||
};
|
||||
headerText: {
|
||||
marginLeft: number;
|
||||
|
@ -63,7 +64,8 @@ module powerbi.extensibility.visual {
|
|||
rangeSelectionStart: null,
|
||||
rangeSelectionEnd: null,
|
||||
multiselect: true,
|
||||
selection: null
|
||||
selection: null,
|
||||
filter: null
|
||||
},
|
||||
headerText: {
|
||||
marginLeft: 8,
|
||||
|
@ -91,7 +93,8 @@ module powerbi.extensibility.visual {
|
|||
multiselect: <DataViewObjectPropertyIdentifier>{ objectName: 'general', propertyName: 'multiselect' },
|
||||
selection: <DataViewObjectPropertyIdentifier>{ objectName: 'general', propertyName: 'selection' },
|
||||
rangeSelectionStart: <DataViewObjectPropertyIdentifier>{ objectName: 'general', propertyName: 'rangeSelectionStart' },
|
||||
rangeSelectionEnd: <DataViewObjectPropertyIdentifier>{ objectName: 'general', propertyName: 'rangeSelectionEnd' }
|
||||
rangeSelectionEnd: <DataViewObjectPropertyIdentifier>{ objectName: 'general', propertyName: 'rangeSelectionEnd' },
|
||||
filter: <DataViewObjectPropertyIdentifier>{ objectName: 'general', propertyName: 'filter' }
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
"declaration": true
|
||||
},
|
||||
"files": [
|
||||
".api/v1.7.0/PowerBI-visuals.d.ts",
|
||||
".api/v1.11.0/PowerBI-visuals.d.ts",
|
||||
"node_modules/powerbi-visuals-utils-dataviewutils/lib/index.d.ts",
|
||||
"node_modules/powerbi-visuals-utils-typeutils/lib/index.d.ts",
|
||||
"node_modules/powerbi-visuals-utils-svgutils/lib/index.d.ts",
|
||||
|
|
Загрузка…
Ссылка в новой задаче