Skip to content
Merged
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
5 changes: 5 additions & 0 deletions .changeset/purple-seas-visit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@itwin/changed-elements-react": patch
---

- swap stage progress with overall loading progress during version comparison
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"loadingComparison": "Loading version comparison",
"loadingNamedVersions": "Loading named versions",
"comparisonNotActive": "No version comparison active.",
"LoadingResults": "Loading results: {{percent}}%",
"cantHideDuringContext": "Cannot show/hide unchanged while emphasizing/isolating/hiding. Clear it first.",
"comparisonGetStarted": "Click on the \"+\" comparison button to get started.",
"showAll": "Show All",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export abstract class ChangedElementDataCache {
/**
* Called whenever a request is done in bulk mode, useful for UI update of progress
*/
public updateFunction?: () => void;
public updateFunction?: (percent: number) => void;

constructor(protected _chunkSize: number = 500) {
// No-op
Expand Down Expand Up @@ -50,7 +50,7 @@ export abstract class ChangedElementDataCache {
const piece = await this._request(elements.slice(i, i + this._chunkSize));
result.push(...piece);
if (this.updateFunction) {
this.updateFunction();
this.updateFunction(Math.floor(i / elements.length * 100));
}
}
return result;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ import {
} from "./ElementQueries.js";
import { VersionCompareUtils, VersionCompareVerboseMessages } from "./VerboseMessages.js";
import { VersionCompare } from "./VersionCompare.js";
import { VersionCompareManager } from "./VersionCompareManager.js";
import { VersionCompareManager, VersionCompareProgressStage } from "./VersionCompareManager.js";
import { ProgressCoordinator } from "../widgets/ProgressCoordinator.js";

/** Changed property for a changed element */
export interface Checksums {
Expand Down Expand Up @@ -81,6 +82,7 @@ export class ChangedElementEntryCache {
}
private _currentIModel: IModelConnection | undefined;
private _targetIModel: IModelConnection | undefined;
private _progressCoordinator?: ProgressCoordinator<VersionCompareProgressStage>;
private _progressLoadingEvent?: BeEvent<(message: string) => void>;
private _currentLoadingMessage = "";
private _numSteps = 0;
Expand Down Expand Up @@ -132,8 +134,10 @@ export class ChangedElementEntryCache {
currentIModel: IModelConnection,
targetIModel: IModelConnection,
elements: Map<string, ChangedElement>,
progressCoordinator?: ProgressCoordinator<VersionCompareProgressStage>,
progressLoadingEvent?: BeEvent<(message: string) => void>,
) {
this._progressCoordinator = progressCoordinator;
this._progressLoadingEvent = progressLoadingEvent;
Comment thread
naronchen marked this conversation as resolved.
elements.forEach((element: ChangedElement, elementId: string) => {
const entry: ChangedElementEntry = {
Expand Down Expand Up @@ -605,6 +609,7 @@ export class ChangedElementEntryCache {
this._findTopParentChunkSize +
1;
this._setCurrentLoadingMessage("msg_findingParents", numTopParentQueries);
this._progressCoordinator?.updateProgress(VersionCompareProgressStage.FindParents);
const currentTopParents = await this._findTopParents(
this._currentIModel,
currentEntryIds,
Expand Down Expand Up @@ -643,22 +648,34 @@ export class ChangedElementEntryCache {
(unchangedCurrentTopParents.length + unchangedTargetTopParents.length) /
this._queryEntryChunkSize +
1;

this._progressCoordinator?.updateProgress(VersionCompareProgressStage.FindParents, 100);

this._setCurrentLoadingMessage("msg_obtainingElementData", numEntryQueries);
this._progressCoordinator?.updateProgress(VersionCompareProgressStage.ObtainElementData);

const OnObtainDataProgress = (percent: number) => {
this._progressCoordinator?.addProgress(
VersionCompareProgressStage.ObtainElementData,
percent / 2, // hardcoded to 50% cuz once called on currentIModel and once on targetIModel
);
}

const currentParentEntries = await queryEntryDataBulk(
this._currentIModel,
VersionCompare.manager?.wantFastParentLoad
? unchangedCurrentTopParents
: currentTopParents,
this._queryEntryChunkSize,
this._updateLoadingProgress,
OnObtainDataProgress,
);
const targetParentEntries = await queryEntryDataBulk(
this._targetIModel,
VersionCompare.manager?.wantFastParentLoad
? unchangedTargetTopParents
: targetTopParents,
this._queryEntryChunkSize,
this._updateLoadingProgress,
OnObtainDataProgress,
);

// Put all data into arrays
Expand Down Expand Up @@ -701,11 +718,15 @@ export class ChangedElementEntryCache {
}
}
}
this._progressCoordinator?.updateProgress(VersionCompareProgressStage.ObtainElementData, 100);

this._progressCoordinator?.updateProgress(VersionCompareProgressStage.FindChildren, 0);
// Load child elements of the root nodes if we are not using fast parent loading
if (this._childrenCache && !VersionCompare.manager?.wantFastParentLoad) {
// Set update function for UI updates
this._childrenCache.updateFunction = this._updateLoadingProgress;
this._childrenCache.updateFunction = (percent: number) => {
this._progressCoordinator?.addProgress(VersionCompareProgressStage.FindChildren, percent);
}
const numQueries = this._childrenCache.calculateNumberOfRequests(
parentEntries.length,
);
Expand All @@ -715,6 +736,7 @@ export class ChangedElementEntryCache {
// Clean-up usage of update function
this._childrenCache.updateFunction = undefined;
}
this._progressCoordinator?.updateProgress(VersionCompareProgressStage.FindChildren, 100);

// Put together all entries
const finalEntries: ChangedElementEntry[] = [];
Expand Down Expand Up @@ -743,11 +765,19 @@ export class ChangedElementEntryCache {
// For now, use the 6 steps (3 per iModel) to get the models
this._setCurrentLoadingMessage("loadingModelNodes", 6);
this._updateLoadingProgress();

this._progressCoordinator?.updateProgress(VersionCompareProgressStage.LoadIModelNodes);

const model_nodes_increment = 25; // 4 steps progress uin load changed model nodes

this._uiDataProvider = new ChangesTreeDataProvider(this._manager);
await this._uiDataProvider.loadChangedModelNodes(
this._currentIModel,
this._targetIModel,
() => this._progressCoordinator?.addProgress(VersionCompareProgressStage.LoadIModelNodes, model_nodes_increment),
);

this._progressCoordinator?.updateProgress(VersionCompareProgressStage.LoadIModelNodes, 100);
}
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import { IModelApp, IModelConnection, ModelState } from "@itwin/core-frontend";
import { ChangedElementEntryCache, type ChangedElement, type Checksums } from "./ChangedElementEntryCache.js";
import { ChangedElementsChildrenCache } from "./ChangedElementsChildrenCache.js";
import { ChangedElementsLabelsCache } from "./ChangedElementsLabelCache.js";
import { VersionCompareManager } from "./VersionCompareManager.js";
import { VersionCompareManager, VersionCompareProgressStage } from "./VersionCompareManager.js";
import { ProgressCoordinator } from "../widgets/ProgressCoordinator.js";

/** Properties that are not shown but still found by the agent */
const ignoredProperties = ["Checksum", "Version"];
Expand Down Expand Up @@ -449,11 +450,13 @@ export class ChangedElementsManager {
public async generateEntries(
currentIModel: IModelConnection,
targetIModel: IModelConnection,
progressCoordinator?: ProgressCoordinator<VersionCompareProgressStage>,
): Promise<void> {
this._entryCache.initialize(
currentIModel,
targetIModel,
this._changedElements,
progressCoordinator,
this._progressLoadingEvent,
);
}
Expand Down Expand Up @@ -542,6 +545,7 @@ export class ChangedElementsManager {
currentIModel: IModelConnection,
targetIModel: IModelConnection,
forward: boolean,
progressCoordinator?: ProgressCoordinator<VersionCompareProgressStage>,
progressLoadingEvent?: BeEvent<(message: string) => void>,
): Promise<Set<string>> {
// If we have model ids in the data already, simply accumulate the models from it instead of querying
Expand Down Expand Up @@ -596,6 +600,16 @@ export class ChangedElementsManager {
steps,
);

progressCoordinator?.updateProgress(
VersionCompareProgressStage.ComputeChangedModels,
Math.floor(((lastStep ?? 0) + currentStep) / (steps === 0 ? 1 : steps) * 100),
);

progressCoordinator?.updateProgress(
VersionCompareProgressStage.ComputeChangedModels,
Math.floor(((lastStep ?? 0) + currentStep) / (steps === 0 ? 1 : steps) * 100),
);

for await (const row of iModel.createQueryReader(ecsql, QueryBinder.from(piece), {
rowFormat: QueryRowFormat.UseJsPropertyNames,
})) {
Expand Down Expand Up @@ -1143,6 +1157,7 @@ export class ChangedElementsManager {
* @param forward Whether we are comparing to a newer iModel or an older one (normally the older)
* @param filterSpatial Whether to filter out non-spatial elements from the results
* @param progressLoadingEvent Event raised every time the processing continues to provide UI messages to the user
* @param onOverallProgress Event raised every time the processing continues to provide UI messages to the user
*/
public async initialize(
currentIModel: IModelConnection,
Expand All @@ -1151,6 +1166,7 @@ export class ChangedElementsManager {
wantedModelClasses?: string[],
forward?: boolean,
filterSpatial?: boolean,
progressCoordinator?: ProgressCoordinator<VersionCompareProgressStage>,
progressLoadingEvent?: BeEvent<(message: string) => void>,
): Promise<void> {
this._progressLoadingEvent = progressLoadingEvent;
Expand All @@ -1169,12 +1185,14 @@ export class ChangedElementsManager {
IModelApp.localization.getLocalizedString("VersionCompare:versionCompare.msg_computingChangedModels"),
);
}
progressCoordinator?.updateProgress(VersionCompareProgressStage.ComputeChangedModels);

// Find changed models
this._changedModels = await this.findChangedModels(
currentIModel,
targetIModel,
forward ?? false,
progressCoordinator,
progressLoadingEvent,
);

Expand All @@ -1183,14 +1201,15 @@ export class ChangedElementsManager {
IModelApp.localization.getLocalizedString("VersionCompare:versionCompare.msg_computingUnchangedModels"),
);
}
progressCoordinator?.updateProgress(VersionCompareProgressStage.ComputeChangedModels, 100);

// Find unchanged models
this._unchangedModels = await this.findUnchangedModels(
currentIModel,
this._changedModels,
);

await this.generateEntries(currentIModel, targetIModel);
await this.generateEntries(currentIModel, targetIModel, progressCoordinator);
}
}

Expand Down
8 changes: 5 additions & 3 deletions packages/changed-elements-react/src/api/ElementQueries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,14 +121,14 @@ export const queryEntryData = async (
* @param iModel IModel to query
* @param elementIds Ids of element to query for
* @param chunkSize Chunk size for each query. Defaults to 1000
* @param updateFunc [optional] called each time we process a chunk
* @param updateFunc [optional] called after each processed chunk with cumulative percent complete (0–100)
* @returns Array of query data
*/
export const queryEntryDataBulk = async (
iModel: IModelConnection,
elementIds: string[],
chunkSize = 1000,
updateFunc?: () => void,
updateFunc?: (percent: number) => void,
): Promise<ChangedElementQueryData[]> => {
if (elementIds.length < chunkSize) {
return queryEntryData(iModel, elementIds);
Expand All @@ -142,7 +142,9 @@ export const queryEntryDataBulk = async (
);
final.push(...data);
if (updateFunc) {
updateFunc();
const processed = Math.min(i + chunkSize, elementIds.length);
const percent = Math.floor((processed / elementIds.length) * 100);
updateFunc(percent);
}
}
return final;
Expand Down
Loading
Loading