Skip to content

Commit

Permalink
Merge pull request #256 from AUS-DOH-Safety-and-Quality/improve-setti…
Browse files Browse the repository at this point in the history
…ngs-typing

Move common outlier settings to 'General" grouping, Improve typing for settings
  • Loading branch information
andrjohns authored Mar 18, 2024
2 parents 12a5401 + abb8b84 commit 562f605
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 36 deletions.
73 changes: 48 additions & 25 deletions src/Classes/settingsClass.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import * as powerbi from "powerbi-visuals-api"
type DataView = powerbi.default.DataView;
type DataViewCategorical = powerbi.default.DataViewCategorical;
type DataViewPropertyValue = powerbi.default.DataViewPropertyValue
type VisualObjectInstanceEnumerationObject = powerbi.default.VisualObjectInstanceEnumerationObject;
type VisualObjectInstance = powerbi.default.VisualObjectInstance;
Expand All @@ -10,10 +9,19 @@ import { extractConditionalFormatting } from "../Functions";
import { default as defaultSettings, type settingsValueTypes, settingsPaneGroupings, settingsPaneToggles } from "../defaultSettings";
import derivedSettingsClass from "./derivedSettingsClass";

type NestedKeysOf<T>
= T extends object
? { [K in keyof T]: K extends string ? K : never; }[keyof T]
: never;

export type defaultSettingsType = settingsValueTypes;
export type defaultSettingsKey = keyof defaultSettingsType;
export type defaultSettingsNestedKey = NestedKeysOf<defaultSettingsType[defaultSettingsKey]>;
export type settingsScalarTypes = number | string | boolean;

export type paneGroupingsNestedKey = "all" | NestedKeysOf<typeof settingsPaneGroupings[keyof typeof settingsPaneGroupings]>;
export type paneTogglesNestedKey = "all" | NestedKeysOf<typeof settingsPaneToggles[keyof typeof settingsPaneToggles]>;

/**
* This is the core class which controls the initialisation and
* updating of user-settings. Each member is its own class defining
Expand All @@ -35,56 +43,71 @@ export default class settingsClass {
// Get the names of all classes in settingsObject which have values to be updated
const allSettingGroups: string[] = Object.keys(this.settings);

allSettingGroups.forEach(settingGroup => {
const categoricalView: DataViewCategorical = inputView.categorical ? inputView.categorical : null;
const condFormatting: defaultSettingsType[defaultSettingsKey] = extractConditionalFormatting(categoricalView, settingGroup, this.settings)[0];
allSettingGroups.forEach((settingGroup: defaultSettingsKey) => {
const condFormatting: defaultSettingsType[defaultSettingsKey]
= extractConditionalFormatting(inputView?.categorical, settingGroup, this.settings)[0];

// Get the names of all settings in a given class and
// use those to extract and update the relevant values
const settingNames: string[] = Object.keys(this.settings[settingGroup]);
settingNames.forEach(settingName => {
this.settings[settingGroup][settingName] = condFormatting ? condFormatting[settingName] : defaultSettings[settingGroup][settingName]["default"]
settingNames.forEach((settingName: defaultSettingsNestedKey) => {
this.settings[settingGroup][settingName]
= condFormatting ? condFormatting[settingName] : defaultSettings[settingGroup][settingName]["default"]
})
})

this.derivedSettings.update(this.settings)
}

/**
* Function to extract all values for a given settings group, which are then
* rendered to the Settings pane in PowerBI
* Get the names of all settings in a given group, and remove any which are toggled off.
*
* @param settingGroupName
* @param inputData
* @returns An object where each element is the value for a given setting in the named group
* @returns
*/
createSettingsEntry(settingGroupName: string): VisualObjectInstanceEnumerationObject {
const settingNames: string[] = Object.keys(this.settings[settingGroupName]);
const settingsGrouped: boolean = Object.keys(settingsPaneGroupings).includes(settingGroupName);
const paneGroupings: Record<string, string[]>
= settingsGrouped ? JSON.parse(JSON.stringify(settingsPaneGroupings[settingGroupName]))
: { "all": settingNames };
getSettingNames(settingGroupName: defaultSettingsKey): Record<paneGroupingsNestedKey, defaultSettingsNestedKey[]> {
const settingsGrouped: boolean = Object.keys(settingsPaneGroupings)
.includes(settingGroupName);
const paneGroupings: Record<paneGroupingsNestedKey, defaultSettingsNestedKey[]>
= settingsGrouped
? JSON.parse(JSON.stringify(settingsPaneGroupings[settingGroupName]))
: { "all": Object.keys(this.settings[settingGroupName]) };

if (Object.keys(settingsPaneToggles).includes(settingGroupName)) {
const toggledSettings: Record<string, Record<string, string[]>>
= settingsGrouped ? settingsPaneToggles[settingGroupName]
: { "all": settingsPaneToggles[settingGroupName]};
const toggledSettings: Record<paneGroupingsNestedKey, typeof settingsPaneToggles[keyof typeof settingsPaneToggles]>
= settingsGrouped
? settingsPaneToggles[settingGroupName]
: { "all": settingsPaneToggles[settingGroupName]};

Object.keys(toggledSettings).forEach(toggleGroup => {
const possibleSettings: string[] = paneGroupings[toggleGroup];
Object.keys(toggledSettings).forEach((toggleGroup: paneGroupingsNestedKey) => {
let settingsToRemove: string[] = new Array<string>();
Object.keys(toggledSettings[toggleGroup]).forEach(settingToggle => {
Object.keys(toggledSettings[toggleGroup]).forEach((settingToggle: paneTogglesNestedKey) => {
if (this.settings[settingGroupName][settingToggle] !== true) {
settingsToRemove = settingsToRemove.concat(toggledSettings[toggleGroup][settingToggle])
}
})
paneGroupings[toggleGroup] = possibleSettings.filter(setting => !settingsToRemove.includes(setting))
paneGroupings[toggleGroup] = paneGroupings[toggleGroup].filter(setting => !settingsToRemove.includes(setting))
})
}
return paneGroupings;
}

/**
* Function to extract all values for a given settings group, which are then
* rendered to the Settings pane in PowerBI
*
* @param settingGroupName
* @param inputData
* @returns An object where each element is the value for a given setting in the named group
*/
createSettingsEntry(settingGroupName: defaultSettingsKey): VisualObjectInstanceEnumerationObject {
const paneGroupings: Record<paneGroupingsNestedKey, defaultSettingsNestedKey[]>
= this.getSettingNames(settingGroupName);

const rtnInstances = new Array<VisualObjectInstance>();
const rtnContainers = new Array<VisualObjectInstanceContainer>();

Object.keys(paneGroupings).forEach((currKey, idx) => {
Object.keys(paneGroupings).forEach((currKey: paneGroupingsNestedKey, idx) => {
const props = Object.fromEntries(
paneGroupings[currKey].map(currSetting => {
const settingValue: DataViewPropertyValue = this.settings[settingGroupName][currSetting]
Expand All @@ -106,7 +129,7 @@ export default class settingsClass {
properties: props,
propertyInstanceKind: Object.fromEntries(propertyKinds),
selector: dataViewWildcard.createDataViewWildcardSelector(dataViewWildcard.DataViewWildcardMatchingOption.InstancesAndTotals),
validValues: Object.fromEntries(Object.keys(defaultSettings[settingGroupName]).map((settingName) => {
validValues: Object.fromEntries(Object.keys(defaultSettings[settingGroupName]).map((settingName: defaultSettingsNestedKey) => {
return [settingName, defaultSettings[settingGroupName][settingName]?.["valid"]]
}))
})
Expand Down
17 changes: 8 additions & 9 deletions src/defaultSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,23 +179,22 @@ const defaultSettings = {
}
};

type RemoveValidEntry<T> = {
[K in keyof T as Exclude<K, "valid">]: T[K]
};
type Unwrap<T> = T[keyof RemoveValidEntry<T>];

type DefaultTypes<T> = T[Extract<keyof T, "default">];

export type settingsValueTypes = {
[K in keyof typeof defaultSettings]: {
[L in keyof typeof defaultSettings[K]]: Unwrap<typeof defaultSettings[K][L]>
[L in keyof typeof defaultSettings[K]]: DefaultTypes<typeof defaultSettings[K][L]>
}
}

export const settingsPaneGroupings = {
outliers: {
"Astronomical Points": ["process_flag_type", "improvement_direction", "astronomical", "astronomical_limit", "ast_colour_improvement", "ast_colour_deterioration", "ast_colour_neutral_low", "ast_colour_neutral_high"],
"Shifts": ["process_flag_type", "improvement_direction", "shift", "shift_n", "shift_colour_improvement", "shift_colour_deterioration", "shift_colour_neutral_low", "shift_colour_neutral_high"],
"Trends": ["process_flag_type", "improvement_direction", "trend", "trend_n", "trend_colour_improvement", "trend_colour_deterioration", "trend_colour_neutral_low", "trend_colour_neutral_high"],
"Two-In-Three": ["process_flag_type", "improvement_direction", "two_in_three", "two_in_three_highlight_series", "two_in_three_limit", "twointhree_colour_improvement", "twointhree_colour_deterioration", "twointhree_colour_neutral_low", "twointhree_colour_neutral_high"]
"General": ["process_flag_type", "improvement_direction"],
"Astronomical Points": ["astronomical", "astronomical_limit", "ast_colour_improvement", "ast_colour_deterioration", "ast_colour_neutral_low", "ast_colour_neutral_high"],
"Shifts": ["shift", "shift_n", "shift_colour_improvement", "shift_colour_deterioration", "shift_colour_neutral_low", "shift_colour_neutral_high"],
"Trends": ["trend", "trend_n", "trend_colour_improvement", "trend_colour_deterioration", "trend_colour_neutral_low", "trend_colour_neutral_high"],
"Two-In-Three": ["two_in_three", "two_in_three_highlight_series", "two_in_three_limit", "twointhree_colour_improvement", "twointhree_colour_deterioration", "twointhree_colour_neutral_low", "twointhree_colour_neutral_high"]
},
lines: {
"Main": ["show_main", "width_main", "type_main", "colour_main"],
Expand Down
4 changes: 2 additions & 2 deletions src/visual.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import * as d3 from "./D3 Plotting Functions/D3 Modules";
import { drawXAxis, drawYAxis, drawTooltipLine, drawLines,
drawDots, drawIcons, updateHighlighting, addContextMenu,
drawErrors, initialiseSVG } from "./D3 Plotting Functions"
import { viewModelClass } from "./Classes"
import { defaultSettingsKey, viewModelClass } from "./Classes"
import { validateDataView } from "./Functions";

export type svgBaseType = d3.Selection<SVGSVGElement, unknown, null, undefined>;
Expand Down Expand Up @@ -79,6 +79,6 @@ export class Visual implements powerbi.extensibility.IVisual {

// Function to render the properties specified in capabilities.json to the properties pane
public enumerateObjectInstances(options: EnumerateVisualObjectInstancesOptions): VisualObjectInstanceEnumerationObject {
return this.viewModel.inputSettings.createSettingsEntry(options.objectName);
return this.viewModel.inputSettings.createSettingsEntry(options.objectName as defaultSettingsKey);
}
}

0 comments on commit 562f605

Please sign in to comment.