Skip to content

Commit

Permalink
Merge d86a5a7 into 0a4cc7d
Browse files Browse the repository at this point in the history
  • Loading branch information
JonasDov committed Sep 20, 2024
2 parents 0a4cc7d + d86a5a7 commit 0ae693a
Show file tree
Hide file tree
Showing 6 changed files with 470 additions and 0 deletions.
11 changes: 11 additions & 0 deletions common/api/components-react.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,9 @@ export namespace ConvertedPrimitives {
export type Value = boolean | number | string | Date | Point | Id64String;
}

// @public
export function createMergedPropertyDataProvider(providers: IPropertyDataProvider[]): MergingPropertyDataProvider;

// @public
export function CustomizablePropertyRenderer(props: CustomizablePropertyRendererProps): React_3.JSX.Element;

Expand Down Expand Up @@ -1380,6 +1383,14 @@ export class MergedPropertyValueRenderer implements IPropertyValueRenderer {
render(_record: PropertyRecord, context?: PropertyValueRendererContext): string | number | boolean | Iterable<React_3.ReactNode> | React_3.JSX.Element | null | undefined;
}

// @public
export class MergingPropertyDataProvider implements IPropertyDataProvider {
constructor(providers: IPropertyDataProvider[]);
getData(): Promise<PropertyData>;
getSourceProviderFromPropertyRecord(record: PropertyRecord): IPropertyDataProvider | undefined;
onDataChanged: PropertyDataChangeEvent;
}

// @internal (undocumented)
export class MultilineTextPropertyValueRenderer implements IPropertyValueRenderer {
// (undocumented)
Expand Down
2 changes: 2 additions & 0 deletions common/api/summary/components-react.exports.csv
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ deprecated;ControlledSelectableContentProps
public;ControlledTree(props: ControlledTreeProps): React_3.JSX.Element
public;ControlledTreeProps
public;ConvertedPrimitives
public;createMergedPropertyDataProvider(providers: IPropertyDataProvider[]): MergingPropertyDataProvider
public;CustomizablePropertyRenderer(props: CustomizablePropertyRendererProps): React_3.JSX.Element
alpha;CustomNumberEditor
alpha;CustomNumberPropertyEditor
Expand Down Expand Up @@ -173,6 +174,7 @@ public;LoadedNodeHierarchy
public;LoadedNodeHierarchyItem
alpha;LocalizationProvider(props: React_3.ComponentProps
public;MergedPropertyValueRenderer
public;MergingPropertyDataProvider
internal;MultilineTextPropertyValueRenderer
internal;MultilineTextRenderer: React_3.FC
internal;MultiSelectionHandler
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@itwin/components-react",
"comment": "Add MergingPropertyDataProvider which combines multiple property data providers into a single one.",
"type": "none"
}
],
"packageName": "@itwin/components-react"
}
1 change: 1 addition & 0 deletions ui/components-react/src/components-react.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ export * from "./components-react/properties/ItemStyle";
export * from "./components-react/propertygrid/PropertyCategoryRendererManager";
export * from "./components-react/propertygrid/PropertyDataProvider";
export * from "./components-react/propertygrid/SimplePropertyDataProvider";
export * from "./components-react/propertygrid/MergingPropertyDataProvider";
export * from "./components-react/propertygrid/component/VirtualizedPropertyGrid";
export * from "./components-react/propertygrid/component/VirtualizedPropertyGridWithDataProvider";
export * from "./components-react/propertygrid/component/PropertyCategoryBlock";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
/** @packageDocumentation
* @module PropertyGrid
*/

import { PropertyRecord } from "@itwin/appui-abstract";
import type {
IPropertyDataProvider,
PropertyCategory,
PropertyData,
} from "./PropertyDataProvider";
import { PropertyDataChangeEvent } from "./PropertyDataProvider";

/**
* Implementation of [IPropertyDataProvider]. This provider merges any number of [IPropertyDataProvider] instances into a single one.
* @public
*/
export class MergingPropertyDataProvider implements IPropertyDataProvider {
/**
* Property data change event that is raised when any of the source providers raise this event.
*/
public onDataChanged = new PropertyDataChangeEvent();
private _sourceProviderExtendedDataKey = "source-provider";
private _providers: IPropertyDataProvider[];

constructor(providers: IPropertyDataProvider[]) {
this._providers = providers;

for (const provider of this._providers) {
provider.onDataChanged.addListener(() => this.onDataChanged.raiseEvent());
}
}

/**
* Returns merged property data from all source providers.
*/
public async getData(): Promise<PropertyData> {
const providersData = this._providers.map(async (provider) =>
this.getDataWithReferenceToProvider(provider)
);
const dataArray = await Promise.all(providersData);

return this.mergePropertyDataArray(dataArray);
}

private async getDataWithReferenceToProvider(
provider: IPropertyDataProvider
): Promise<PropertyData> {
const providerData = await provider.getData();
for (const categoryName in providerData.records) {
if (!providerData.records.hasOwnProperty(categoryName)) {
continue;
}

providerData.records[categoryName].forEach((categoryRecord) => {
categoryRecord.extendedData = {
...categoryRecord.extendedData,
[this._sourceProviderExtendedDataKey]: provider,
};
});
}
return providerData;
}

private mergePropertyDataArray(dataArray: PropertyData[]): PropertyData {
return {
label: this.mergeLabels(dataArray),
description: this.mergeDescriptions(dataArray),
categories: this.mergeCategories(dataArray),
records: this.mergeRecords(dataArray),
};
}

private mergeLabels(dataArray: PropertyData[]): PropertyRecord {
// We don't care about labels, just use the first one
if (dataArray.length > 0) {
return dataArray[0].label;
}

return PropertyRecord.fromString("");
}

private mergeDescriptions(dataArray: PropertyData[]): string | undefined {
// We don't care about descriptions, just use the first one
if (dataArray.length > 0) {
return dataArray[0].description;
}

return undefined;
}

private mergeCategories(dataArray: PropertyData[]): PropertyCategory[] {
const mergedCategories: PropertyCategory[] = [];
dataArray.forEach((data) => {
mergedCategories.push(...data.categories);
});

return mergedCategories;
}

private mergeRecords(dataArray: PropertyData[]): {
[categoryName: string]: PropertyRecord[];
} {
const mergedRecords: { [categoryName: string]: PropertyRecord[] } = {};
dataArray.forEach((data) => {
for (const categoryName in data.records) {
if (!data.records.hasOwnProperty(categoryName)) {
continue;
}

if (mergedRecords.hasOwnProperty(categoryName)) {
mergedRecords[categoryName].push(...data.records[categoryName]);
continue;
}

mergedRecords[categoryName] = data.records[categoryName];
}
});

return mergedRecords;
}

/**
* Determines source provider from a given [PropertyRecord].
*
* @returns
* - `undefined` if source provider can't be determined.
* - Source provider if it is found.
*/
public getSourceProviderFromPropertyRecord(
record: PropertyRecord
): IPropertyDataProvider | undefined {
if (
!record.extendedData ||
!record.extendedData.hasOwnProperty(this._sourceProviderExtendedDataKey)
) {
return undefined;
}

return record.extendedData[this._sourceProviderExtendedDataKey];
}
}

/**
* Function that creates MergingPropertyDataProvider
* @public
*/
export function createMergedPropertyDataProvider(
providers: IPropertyDataProvider[]
): MergingPropertyDataProvider {
return new MergingPropertyDataProvider(providers);
}
Loading

0 comments on commit 0ae693a

Please sign in to comment.