Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion src/FormattingSettingsInterfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,5 @@ export interface IFormattingSettingsSlice {
export interface IBuildFormattingSlicesParams {
slices: Slice[],
objectName: string,
sliceNames: { [name: string]: number; },
formattingSlices: visuals.FormattingSlice[]
}
108 changes: 63 additions & 45 deletions src/FormattingSettingsService.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import powerbi from "powerbi-visuals-api";

import { Cards, CardGroupEntity, CompositeCard, Model, SimpleCard, Slice, SimpleSlice } from "./FormattingSettingsComponents";
import { formattingSettings } from ".";
import { Cards, CardGroupEntity, CompositeCard, Group, Model, SimpleCard, Slice } from "./FormattingSettingsComponents";
import { IBuildFormattingSlicesParams, IFormattingSettingsService } from "./FormattingSettingsInterfaces";

import visuals = powerbi.visuals;
import ILocalizationManager = powerbi.extensibility.ILocalizationManager;
import visuals = powerbi.visuals;

export class FormattingSettingsService implements IFormattingSettingsService {
private localizationManager: ILocalizationManager;
Expand All @@ -28,7 +29,7 @@ export class FormattingSettingsService implements IFormattingSettingsService {
defaultSettings.cards?.forEach((card: Cards) => {
if (card instanceof CompositeCard) card.topLevelSlice?.setPropertiesValues(dataViewObjects, card.name);

const cardGroupInstances = <CardGroupEntity[]>(card instanceof SimpleCard ? [ card ] : card.groups);
const cardGroupInstances = <CardGroupEntity[]>(card instanceof SimpleCard ? [card] : card.groups);
cardGroupInstances.forEach((cardGroupInstance: CardGroupEntity) => {
// Set current top level toggle value
cardGroupInstance.topLevelSlice?.setPropertiesValues(dataViewObjects, card.name);
Expand Down Expand Up @@ -57,9 +58,9 @@ export class FormattingSettingsService implements IFormattingSettingsService {
let formattingModel = {
cards: []
}

formattingSettingsModel.cards
.filter(({visible = true}) => visible)
.filter(({ visible = true }) => visible)
.forEach((card: Cards) => {
let formattingCard: visuals.FormattingCard = {
displayName: (this.localizationManager && card.displayNameKey) ? this.localizationManager.getDisplayName(card.displayNameKey) : card.displayName,
Expand All @@ -80,33 +81,28 @@ export class FormattingSettingsService implements IFormattingSettingsService {
card.onPreProcess?.();

const isSimpleCard = card instanceof SimpleCard;
const cardGroupInstances = <CardGroupEntity[]>(isSimpleCard ?
[ card ].filter(({visible = true}) => visible) :
card.groups.filter(({visible = true}) => visible));
const cardGroupInstances = <CardGroupEntity[]>(isSimpleCard ?
[card].filter(({ visible = true }) => visible) :
card.groups.filter(({ visible = true }) => visible));
cardGroupInstances
.forEach((cardGroupInstance: CardGroupEntity) => {
const groupUid = cardGroupInstance.name + "-group";

// Build formatting group for each group
const formattingGroup: visuals.FormattingGroup = {
displayName: isSimpleCard ? undefined : (this.localizationManager && cardGroupInstance.displayNameKey)
? this.localizationManager.getDisplayName(cardGroupInstance.displayNameKey) : cardGroupInstance.displayName,
description: isSimpleCard ? undefined : (this.localizationManager && cardGroupInstance.descriptionKey)
? this.localizationManager.getDisplayName(cardGroupInstance.descriptionKey) : cardGroupInstance.description,
slices: [],
uid: groupUid,
collapsible: cardGroupInstance.collapsible,
delaySaveSlices: cardGroupInstance.delaySaveSlices,
disabled: cardGroupInstance.disabled,
disabledReason: cardGroupInstance.disabledReason,
}
displayName: isSimpleCard ? undefined : (this.localizationManager && cardGroupInstance.displayNameKey)
? this.localizationManager.getDisplayName(cardGroupInstance.displayNameKey) : cardGroupInstance.displayName,
description: isSimpleCard ? undefined : (this.localizationManager && cardGroupInstance.descriptionKey)
? this.localizationManager.getDisplayName(cardGroupInstance.descriptionKey) : cardGroupInstance.description,
slices: [],
uid: groupUid,
collapsible: cardGroupInstance.collapsible,
delaySaveSlices: cardGroupInstance.delaySaveSlices,
disabled: cardGroupInstance.disabled,
disabledReason: cardGroupInstance.disabledReason,
}
formattingCard.groups.push(formattingGroup);

// In case formatting model adds data points or top categories (Like when you modify specific visual category color).
// these categories use same object name and property name from capabilities and the generated uid will be the same for these formatting categories properties
// Solution => Save slice names to modify each slice uid to be unique by adding counter value to the new slice uid
const sliceNames: { [name: string]: number } = {};

// Build formatting container slice for each property
if (cardGroupInstance.container) {
const container = cardGroupInstance.container;
Expand All @@ -132,7 +128,7 @@ export class FormattingSettingsService implements IFormattingSettingsService {
}

// Build formatting slices and add them to current formatting container item
this.buildFormattingSlices({slices: containerItem.slices, objectName, sliceNames, formattingSlices: formattingContainerItem.slices});
this.buildFormattingSlices({ slices: containerItem.slices, objectName, formattingSlices: formattingContainerItem.slices });
formattingContainer.containerItems.push(formattingContainerItem);
});

Expand All @@ -143,10 +139,10 @@ export class FormattingSettingsService implements IFormattingSettingsService {
if (cardGroupInstance.topLevelSlice) {
let topLevelToggleSlice: visuals.FormattingSlice = cardGroupInstance.topLevelSlice.getFormattingSlice(objectName, this.localizationManager);
topLevelToggleSlice.suppressDisplayName = true;
(formattingGroup.displayName==undefined ? formattingCard : formattingGroup).topLevelToggle = (<visuals.EnabledSlice>topLevelToggleSlice);
(formattingGroup.displayName == undefined ? formattingCard : formattingGroup).topLevelToggle = (<visuals.EnabledSlice>topLevelToggleSlice);
}
// Build formatting slice for each property
this.buildFormattingSlices({slices: cardGroupInstance.slices, objectName, sliceNames, formattingSlices: formattingGroup.slices as visuals.FormattingSlice[]});
this.buildFormattingSlices({ slices: cardGroupInstance.slices, objectName, formattingSlices: formattingGroup.slices as visuals.FormattingSlice[] });
}

});
Expand All @@ -159,24 +155,46 @@ export class FormattingSettingsService implements IFormattingSettingsService {
return formattingModel;
}

private buildFormattingSlices({slices, objectName, sliceNames, formattingSlices }: IBuildFormattingSlicesParams) {
private buildFormattingSlices({ slices, objectName, formattingSlices }: IBuildFormattingSlicesParams) {
// In case formatting model adds data points or top categories (Like when you modify specific visual category color).
// these categories use same object name and property name from capabilities and the generated uid will be the same for these formatting categories properties
// Solution => Save slice names to modify each slice uid to be unique by adding counter value to the new slice uid
const sliceNames: { [name: string]: number } = {};

// We are also supporting slices with the same name if they differ in the selector field (not the altConstantSelector).
// If the slices with the same name have different selectors we keep the uid as is, else we change it.
// We recommend using different selectors in the selector field for slices with the same name.
const selectorsMap: Record<string, { [selector: string]: boolean }> = {}

// Filter slices based on their visibility
slices?.filter(({visible = true}) => visible)
slices?.filter(({ visible = true }) => visible)
.forEach((slice: Slice) => {
let formattingSlice: visuals.FormattingSlice = slice?.getFormattingSlice(objectName, this.localizationManager);

if (formattingSlice) {
// Modify formatting slice uid if needed
if (sliceNames[slice.name] === undefined) {
sliceNames[slice.name] = 0;
} else {
sliceNames[slice.name]++;
formattingSlice.uid = `${formattingSlice.uid}-${sliceNames[slice.name]}`;
}
let formattingSlice: visuals.FormattingSlice = slice?.getFormattingSlice(objectName, this.localizationManager);

if (formattingSlice) {
// Modify formatting slice uid if needed
const sliceName = slice.name;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why don't you use this variable below?

const sliceSelector = (slice as SimpleSlice).selector;
const stringifiedSelector = sliceSelector ? JSON.stringify(sliceSelector) : '';
if (sliceNames[sliceName] === undefined) {
selectorsMap[sliceName] = {};
sliceNames[sliceName] = 0;
if (sliceSelector) {
selectorsMap[sliceName][stringifiedSelector] = true;
}
} else {
sliceNames[sliceName]++;
const selectorExistsInMap = stringifiedSelector && selectorsMap[sliceName][stringifiedSelector];
if (sliceSelector && !selectorExistsInMap) {
selectorsMap[sliceName][stringifiedSelector] = true;
} else {
formattingSlice.uid = `${formattingSlice.uid}-${sliceNames[sliceName]}`;
}
}

formattingSlices.push(formattingSlice);
}
});
formattingSlices.push(formattingSlice);
}
});
}

private getRevertToDefaultDescriptor(card: Cards): visuals.FormattingDescriptor[] {
Expand All @@ -189,9 +207,9 @@ export class FormattingSettingsService implements IFormattingSettingsService {

if (card instanceof CompositeCard && card.topLevelSlice) revertToDefaultDescriptors.push(...card.topLevelSlice?.getRevertToDefaultDescriptor(card.name));

const cardGroupInstances = <CardGroupEntity[]>(card instanceof SimpleCard ?
[ card ].filter(({visible = true}) => visible) :
card.groups.filter(({visible = true}) => visible));
const cardGroupInstances = <CardGroupEntity[]>(card instanceof SimpleCard ?
[card].filter(({ visible = true }) => visible) :
card.groups.filter(({ visible = true }) => visible));
cardGroupInstances.forEach((cardGroupInstance: CardGroupEntity) => {
cardSlicesDefaultDescriptors = this.getSlicesRevertToDefaultDescriptor(card.name, cardGroupInstance.slices, sliceNames, cardGroupInstance.topLevelSlice);

Expand Down