Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

V2 Widget push #76

Merged
merged 67 commits into from
Feb 12, 2024
Merged
Show file tree
Hide file tree
Changes from 65 commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
e4a95a8
Init Commit
CalebGerman Jan 16, 2024
cf76d69
WIP Now Have Ability To Use V2
CalebGerman Jan 16, 2024
0593831
WIP Toasts
CalebGerman Jan 16, 2024
d6a2ff1
WIP Demo
CalebGerman Jan 17, 2024
ce884e2
WIP getting job status for each named entry
CalebGerman Jan 17, 2024
dbf84dc
Got Job Status Text To Appear. This Is A Check Point For Demo
CalebGerman Jan 17, 2024
265ef6f
Added Colored Text Good For a Demo
CalebGerman Jan 17, 2024
245fb05
Added Info Dialog And Info Button
CalebGerman Jan 18, 2024
131ad3a
Added Info Panel WIP
CalebGerman Jan 18, 2024
c08d315
Got Toast Working For Comparison Job
CalebGerman Jan 19, 2024
6d52df2
Reworked Info Button
CalebGerman Jan 19, 2024
448235a
Started refactoring code. Added types for jobStatus and named version…
CalebGerman Jan 22, 2024
54ba89e
WIP Working On V2 Widget
CalebGerman Jan 23, 2024
a1dce26
Got Refactored Functional Comps To Work
CalebGerman Jan 23, 2024
e684d87
Passing named versions as props now instead of paged result
CalebGerman Jan 23, 2024
2f41b90
Started Cleaning up PagedNamedVersion Loader
CalebGerman Jan 23, 2024
54cf3ed
Renamed clients and job status. Cleaned Up usePagedNamedVersionLoader
CalebGerman Jan 24, 2024
cf3358e
Moved And Renamed Files
CalebGerman Jan 24, 2024
14350ca
Fixed Import Ordering And Imports From Index File
CalebGerman Jan 24, 2024
26a18f1
Added comments for exported members
CalebGerman Jan 24, 2024
57224a8
Fixed Sorting Algo
CalebGerman Jan 24, 2024
8525cc5
Fixed sort function
CalebGerman Jan 24, 2024
d764f2d
Cleaned up sorting and now getting all change sets
CalebGerman Jan 25, 2024
f856ac4
WIP working on progress updates
CalebGerman Jan 25, 2024
6f662d1
WIP polling for job progress
CalebGerman Jan 25, 2024
c87268f
WIP polling
CalebGerman Jan 25, 2024
05935c9
Moved Polling To Modal
CalebGerman Jan 26, 2024
011304c
Added polling when widget is open and closed. But not at the same time
CalebGerman Jan 26, 2024
76d849c
Added way to keep track of dialog being open or not
CalebGerman Jan 29, 2024
817dc48
Added Ability To Check What Widget Is In Use
CalebGerman Feb 1, 2024
f2fe96c
Fixed user facing strings and updated job progress
CalebGerman Feb 2, 2024
2e3ca8a
Added comments to code and renamed things
CalebGerman Feb 2, 2024
d80d61d
Renamed scss class and removed unused scss file
CalebGerman Feb 2, 2024
d12091f
Updated file dir and added additional check for feedback button
CalebGerman Feb 2, 2024
29d2fda
Updated package.json and package lock
CalebGerman Feb 2, 2024
b200b90
Compensated for existing bug in API, but fix on client side is not th…
CalebGerman Feb 2, 2024
a3c7795
Worked around API bug. This will need to be patched in the future
CalebGerman Feb 2, 2024
7b84ac5
Break the loop instead of returning. Not sure if should be broken
CalebGerman Feb 2, 2024
cf9fff1
Fixed linting errors
CalebGerman Feb 2, 2024
07e6d4b
Adjusted to Pr comments
CalebGerman Feb 5, 2024
85d3f3a
Pushed Changes Addressing PR Comments
CalebGerman Feb 6, 2024
20262fb
Update packages/changed-elements-react/public/locales/en/VersionCompa…
CalebGerman Feb 6, 2024
3af13b0
Update packages/changed-elements-react/src/clients/ComparisonJobClien…
CalebGerman Feb 6, 2024
921b577
Update packages/changed-elements-react/src/widgets/ChangedElementsWid…
CalebGerman Feb 6, 2024
77df957
Update packages/changed-elements-react/src/widgets/V2Widget/componets…
CalebGerman Feb 6, 2024
d2383af
Update packages/changed-elements-react/src/widgets/V2Widget/hooks/use…
CalebGerman Feb 6, 2024
b5c3749
Update packages/changed-elements-react/src/widgets/V2Widget/componets…
CalebGerman Feb 6, 2024
f78f696
Update packages/changed-elements-react/src/widgets/V2Widget/componets…
CalebGerman Feb 6, 2024
70afecd
Update packages/changed-elements-react/src/widgets/V2Widget/componets…
CalebGerman Feb 6, 2024
b69a7e1
Update packages/changed-elements-react/src/widgets/V2Widget/componets…
CalebGerman Feb 6, 2024
6d72f10
Adjusted to comments on PR
CalebGerman Feb 6, 2024
9018716
Moved and renamed file dirs
CalebGerman Feb 6, 2024
2849487
Pushed changes addressing comments and fixing border color
CalebGerman Feb 7, 2024
fc3338f
reverted changes to scss
CalebGerman Feb 7, 2024
d140a00
reverted changes to scss
CalebGerman Feb 7, 2024
a5ce1dd
Update packages/changed-elements-react/src/widgets/comparisonJobWidge…
CalebGerman Feb 7, 2024
a73a01e
Renamed interface and var name
CalebGerman Feb 7, 2024
acfc922
Added comment and check for error status
CalebGerman Feb 8, 2024
94f489d
Added comment
CalebGerman Feb 8, 2024
88e0031
Update packages/changed-elements-react/src/widgets/comparisonJobWidge…
CalebGerman Feb 8, 2024
e1abc4d
Fixed style sheet clash
CalebGerman Feb 8, 2024
0882512
Now using util functions from utils
CalebGerman Feb 8, 2024
0d1c83e
Got rid of debug code
CalebGerman Feb 8, 2024
7d0fc2e
Patched issue with named current view id
CalebGerman Feb 8, 2024
1bd5658
Fixed env.ts The modal will no longer poll on connection close. Clean…
CalebGerman Feb 9, 2024
7529e3b
Updated imodel connection closed code and env.ts
CalebGerman Feb 12, 2024
81a1f24
Pushed changes to env.ts
CalebGerman Feb 12, 2024
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
Original file line number Diff line number Diff line change
@@ -1,9 +1,25 @@
{
"versionCompare": {
"versionPickerTitle": "Version Compare",
roluk marked this conversation as resolved.
Show resolved Hide resolved
"versionCompareInfo": "Discover what has changed between two iModel versions. To get started, click the + button, then choose the version to compare with. The data processing will begin in the background. Processing time may vary based on the data complexity. A notification will appear when results are available.",
"versionCompareLeaveFeedback": "Leave Feedback",
"versionCompareGettingStartedV2": "Click on the + comparison button to get started or check the progress of active comparison jobs.",
"versionComparisonStarting": "Comparison visualization starting.",
"versionCompare": "Version Compare",
"versionCompareBeta": "Version Compare",
"iModelVersions": "iModel versions",
"and": "and",
"jobProcessing": "are being processed in the background. You will receive a notification upon completion.",
"jobError":"An error occurred while processing changes between",
"jobComplete": "comparisons job is complete.",
"viewTheReport": "View The Report",
"withPrevious": "With previous",
"error": "Error",
"notProcessed": "Not Processed",
"queued": "Queued",
"available": "Available",
"compare": "Compare",
"progress": "Progress",
"comparisonLegend": "Comparison Legend",
"loadingComparison": "Loading version comparison",
"comparisonNotActive": "No version comparison active.",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
import { createContext, PropsWithChildren, ReactElement, useContext, useMemo } from "react";

import type { IModelsClient } from "./clients/iModelsClient.js";
import type { SavedFiltersManager } from "./SavedFiltersManager.js";
import { IComparisonJobClient } from "./clients/IComparisonJobClient.js";

export interface VersionCompareContextProps {
iModelsClient: IModelsClient;
savedFilters?: SavedFiltersManager | undefined;
comparisonJobClient?: IComparisonJobClient;
}

/**
Expand All @@ -20,9 +21,10 @@ export function VersionCompareContext(props: PropsWithChildren<VersionCompareCon
const value = useMemo(
() => ({
iModelsClient: props.iModelsClient,
comparisonJobClient: props.comparisonJobClient,
savedFilters: props.savedFilters,
}),
[props.iModelsClient, props.savedFilters],
[props.comparisonJobClient, props.iModelsClient, props.savedFilters],
);
return <versionCompareContext.Provider value={value}>{props.children}</versionCompareContext.Provider>;
}
Expand All @@ -44,6 +46,7 @@ Example:

export interface VersionCompareContextValue {
iModelsClient: IModelsClient;
comparisonJobClient?: IComparisonJobClient;
savedFilters: SavedFiltersManager | undefined;
}

Expand Down
129 changes: 128 additions & 1 deletion packages/changed-elements-react/src/api/VersionCompareManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import {
OutputMessagePriority
} from "@itwin/core-frontend";
import { KeySet } from "@itwin/presentation-common";

import type { NamedVersion } from "../clients/iModelsClient.js";
import { PropertyLabelCache } from "../dialogs/PropertyLabelCache.js";
import type { ChangedElementEntry } from "./ChangedElementEntryCache.js";
Expand Down Expand Up @@ -374,6 +373,134 @@ export class VersionCompareManager {
return success;
}

/**
* Starts comparison by opening a new iModelConnection and setting up the store.
* @param currentIModel Current IModelConnection to be used to compare against
* @param currentVersion Current Version of the iModel
* @param targetVersion Target Version of the iModel, an IModelConnection is opened to it
* @param changedElements Array of elements that have changed and need to be visualized
*/
public async startComparisonV2(
currentIModel: IModelConnection,
currentVersion: NamedVersion,
targetVersion: NamedVersion,
changedElements: ChangedElements[],
): Promise<boolean> {
this._currentIModel = currentIModel;

let success = true;
try {
if (!targetVersion.changesetId) {
throw new Error("Cannot compare to a version if it doesn't contain a changeset Id");
}

// Setup visualization handler
this._initializeVisualizationHandler();
// Raise event that comparison is starting
this.versionCompareStarting.raiseEvent();

if (!this._currentIModel.iModelId || !this._currentIModel.iTwinId) {
throw new Error("Cannot compare with an iModel lacking iModelId or iTwinId (aka projectId)");
}

this.loadingProgressEvent.raiseEvent(
IModelApp.localization.getLocalizedString("VersionCompare:versionCompare.msg_openingTarget"),
);

// Open the target version IModel
const changesetId = targetVersion.changesetId;
this._targetIModel = await CheckpointConnection.openRemote(
this._currentIModel.iTwinId,
this._currentIModel.iModelId,
IModelVersion.asOfChangeSet(changesetId),
);

// Keep metadata around for UI uses and other queries
this.currentVersion = currentVersion;
this.targetVersion = targetVersion;

this.loadingProgressEvent.raiseEvent(
IModelApp.localization.getLocalizedString("VersionCompare:versionCompare.msg_getChangedElements"),
);

this.loadingProgressEvent.raiseEvent(
IModelApp.localization.getLocalizedString("VersionCompare:versionCompare.msg_initializingComparison"),
);

let wantedModelClasses = [
GeometricModel2dState.classFullName,
GeometricModel3dState.classFullName,
];
if (this.options.wantedModelClasses) {
wantedModelClasses = this.options.wantedModelClasses;
}

await this.changedElementsManager.initialize(
this._currentIModel,
this._targetIModel,
changedElements,
this.wantAllModels ? undefined : wantedModelClasses,
false,
this.filterSpatial,
this.loadingProgressEvent,
);

const changedElementEntries = this.changedElementsManager.entryCache.getAll();

// We have parent Ids available if any entries contain undefined parent data
this._hasParentIds = changedElementEntries.some(
(entry) => entry.parent !== undefined && entry.parentClassId !== undefined,
);
// We have type of change available if any of the entries has a valid type of change value
this._hasTypeOfChange = changedElementEntries.some((entry) => entry.type !== 0);
// We have property filtering available if any of the entries has a valid array of changed properties
this._hasPropertiesForFiltering = changedElementEntries.some(
(entry) => entry.properties !== undefined && entry.properties.size !== 0,
);

// Get the entries
this.loadingProgressEvent.raiseEvent(
IModelApp.localization.getLocalizedString("VersionCompare:versionCompare.msg_findingAssemblies"),
);
await this.changedElementsManager.entryCache.initialLoad(changedElementEntries.map((entry) => entry.id));

// Reset the select tool to allow external iModels to be located
await IModelApp.toolAdmin.startDefaultTool();

// Enable visualization of version comparison
await this.enableVisualization(false);

// Raise event
this.versionCompareStarted.raiseEvent(this._currentIModel, this._targetIModel, changedElementEntries);
VersionCompareUtils.outputVerbose(VersionCompareVerboseMessages.versionCompareManagerStartedComparison);
} catch (ex) {
// Let user know comparison failed - TODO: Give better errors
const briefError = IModelApp.localization.getLocalizedString(
"VersionCompare:versionCompare.error_versionCompare",
);
const detailed = IModelApp.localization.getLocalizedString("VersionCompare:versionCompare.error_cantStart");
let errorMessage = "Unknown Error";
if (ex instanceof Error) {
errorMessage = ex.message;
} else if (typeof ex === "string") {
errorMessage = ex;
}

IModelApp.notifications.outputMessage(
new NotifyMessageDetails(OutputMessagePriority.Error, briefError, `${detailed}: ${errorMessage}`),
);
// Notify failure on starting comparison
this.versionCompareStartFailed.raiseEvent();
this._currentIModel = undefined;
this._targetIModel = undefined;

success = false;
VersionCompareUtils.outputVerbose(VersionCompareVerboseMessages.versionCompareManagerErrorStarting);
}

return success;
}

/**
* Enable visualization of version comparison.
* @param wantTargetModified Show modified elements from target comparison in single viewport
Expand Down
108 changes: 108 additions & 0 deletions packages/changed-elements-react/src/clients/ComparisonJobClient.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
import type {
ChangedElementsPayload, IComparisonJobClient, ComparisonJob, GetComparisonJobParams, GetComparisonJobResultParams,
PostComparisonJobParams,
DeleteComparisonJobParams
} from "./IComparisonJobClient.js";
import { callITwinApi, throwBadResponseCodeError } from "./iTwinApi.js";

export interface ComparisonJobClientParams {
baseUrl: string;
getAccessToken: () => Promise<string>;
}

export class ComparisonJobClient implements IComparisonJobClient {
private static readonly _acceptHeader = "application/vnd.bentley.itwin-platform.v2+json";
private _baseUrl: string;
private _getAccessToken: () => Promise<string>;

constructor(args: ComparisonJobClientParams) {
this._baseUrl = args.baseUrl;
this._getAccessToken = args.getAccessToken;
}

/**
* Deletes comparison job.
* @returns void
* @throws on a non 2XX response
*/
public async deleteComparisonJob(args: DeleteComparisonJobParams): Promise<void> {
return callITwinApi({
url: `${this._baseUrl}/comparisonJob/${args.jobId}/iTwin/${args.iTwinId}/iModel/${args.iModelId}`,
method: "DELETE",
getAccessToken: this._getAccessToken,
signal: args.signal,
headers: {
Accept: ComparisonJobClient._acceptHeader,
...args.headers,
},
}) as unknown as Promise<void>;
}

/**
* Gets comparison job.
* @returns ComparisonJob
* @throws on a non 2XX response.
*/
public async getComparisonJob(args: GetComparisonJobParams): Promise<ComparisonJob> {
return callITwinApi({
url: `${this._baseUrl}/comparisonJob/${args.jobId}/iTwin/${args.iTwinId}/iModel/${args.iModelId}`,
method: "GET",
getAccessToken: this._getAccessToken,
signal: args.signal,
headers: {
Accept: ComparisonJobClient._acceptHeader,
...args.headers,
},
}) as unknown as Promise<ComparisonJob>;
}

/**
* Gets changed elements for given comparisonJob.
* @returns ChangedElements
* @throws on a non 2XX response.
*/
public async getComparisonJobResult(args: GetComparisonJobResultParams): Promise<ChangedElementsPayload> {
const response = await fetch(
args.comparisonJob.comparison.href,
{
method: "GET",
headers: {
Accept: ComparisonJobClient._acceptHeader,
},
},
);

if (!response.ok) {
await throwBadResponseCodeError(response, "Changed Elements request failed.");
}
return response.json() as unknown as Promise<ChangedElementsPayload>;
}

/**
* Gets comparison job.
* @returns ComparisonJob
* @throws on a non 2XX response.
*/
public async postComparisonJob(args: PostComparisonJobParams): Promise<ComparisonJob> {
return callITwinApi({
url: `${this._baseUrl}/comparisonJob`,
method: "POST",
getAccessToken: this._getAccessToken,
signal: args.signal,
headers: {
Accept: ComparisonJobClient._acceptHeader,
...args.headers,
},
body: {
iTwinId: args.iTwinId,
iModelId: args.iModelId,
startChangesetId: args.startChangesetId,
endChangesetId: args.endChangesetId,
},
}) as unknown as Promise<ComparisonJob>;
}
}
Loading
Loading