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

Added new props for v2 widget and dialog provider that allows for job update call back and a toggle for toasts #87

Merged
merged 7 commits into from
Feb 26, 2024
2 changes: 2 additions & 0 deletions packages/changed-elements-react/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,5 @@ export * from "./widgets/ChangedElementsWidget.js";
export { ChangedElementsListComponent } from "./widgets/EnhancedElementsInspector.js";
export * from "./widgets/VersionCompareSelectWidget.js";
export * from "./widgets/comparisonJobWidget/components/VersionCompareSelectModal.js"
export * from "./widgets/comparisonJobWidget/components/VersionCompareDialogProvider.js"
export * from "./widgets/comparisonJobWidget/common/versionCompareToasts.js"
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,11 @@ import { ReportGeneratorDialog } from "../dialogs/ReportGeneratorDialog.js";
import { ChangedElementsInspector } from "./EnhancedElementsInspector.js";
import "./ChangedElementsWidget.scss";
import InfoButton from "./InformationButton.js";
import { V2DialogProvider, VersionCompareSelectDialogV2 } from "./comparisonJobWidget/components/VersionCompareSelectModal.js";
import { VersionCompareSelectDialogV2 } from "./comparisonJobWidget/components/VersionCompareSelectModal.js";
import { FeedbackButton } from "./FeedbackButton.js";
import { VersionCompareSelectDialog } from "./VersionCompareSelectWidget.js";
import { ComparisonJobUpdateType, VersionCompareSelectProviderV2 } from "./comparisonJobWidget/components/VersionCompareDialogProvider.js";
import { JobAndNamedVersions } from "./comparisonJobWidget/models/ComparisonJobModels.js";

export const changedElementsWidgetAttachToViewportEvent = new BeEvent<(vp: ScreenViewport) => void>();

Expand All @@ -41,8 +43,20 @@ export interface ChangedElementsWidgetProps {
rootElementRef?: React.Ref<HTMLDivElement>;
/**Optional. If true will use v2 dialog and will run comparison jobs for faster comparisons @beta.*/
useV2Widget?: boolean;
/**Optional. Supply a link for feedback. Should only be used if v2 is enabled*/
/** Optional. Supply a link for feedback. Should only be used if v2 is enabled*/
feedbackUrl?: string;
/** Optional. When enabled will toast messages regarding job status. If not defined will default to false and will not show toasts (Only for V2). */
enableComparisonJobUpdateToasts?: boolean;
/** On Job Update (Only for V2)
* Optional. a call back function for handling job updates.
* @param comparisonJobUpdateType param for the type of update:
* - "JobComplete" = invoked when job is completed
* - "JobError" = invoked on job error
* - "JobProgressing" = invoked on job is started
* - "ComparisonVisualizationStarting" = invoked on when version compare visualization is starting
* @param jobAndNamedVersion param contain job and named version info to be passed to call back
*/
onJobUpdate?: (comparisonJobUpdateType: ComparisonJobUpdateType, jobAndNamedVersions?: JobAndNamedVersions) => Promise<void>;
}

export interface ChangedElementsWidgetState {
Expand Down Expand Up @@ -394,14 +408,14 @@ export class ChangedElementsWidget extends Component<ChangedElementsWidgetProps,
/>
}
{this.props.useV2Widget ?
<V2DialogProvider>
<VersionCompareSelectProviderV2 onJobUpdate={this.props.onJobUpdate} enableComparisonJobUpdateToasts={this.props.enableComparisonJobUpdateToasts}>
{this.state.versionSelectDialogVisible &&
<VersionCompareSelectDialogV2
data-testid="⁠comparison-widget-v2-modal"
iModelConnection={this.props.iModelConnection}
onClose={this._handleVersionSelectDialogClose}
/>}
</V2DialogProvider> :
</VersionCompareSelectProviderV2> :
this.state.versionSelectDialogVisible &&
<VersionCompareSelectDialog
isOpen
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ import { NamedVersion } from "../../../clients/iModelsClient";
import { toaster } from "@itwin/itwinui-react";
import { ManagerStartComparisonV2Args, runManagerStartComparisonV2 } from "./versionCompareV2WidgetUtils";

/** Toast Comparison Job Processing.
* Outputs toast message following the pattern:
* Version Compare
* iModel versions <currentVersion> and <targetVersion> are being processed in the background. You will receive a notification upon completion.
*/
export const toastComparisonJobProcessing = (currentVersion: NamedVersion, targetVersion: NamedVersion) => {
IModelApp.notifications.outputMessage(
new NotifyMessageDetails(
Expand All @@ -20,6 +25,11 @@ export const toastComparisonJobProcessing = (currentVersion: NamedVersion, targe
);
};

/** Toast Comparison Job Error.
* Outputs toast message following the pattern:
* Version Compare
* An error occurred while processing changes between iModel versions <currentVersion> and <targetVersion>.
*/
export const toastComparisonJobError = (currentVersion: NamedVersion, targetVersion: NamedVersion) => {
IModelApp.notifications.outputMessage(
new NotifyMessageDetails(
Expand All @@ -33,6 +43,13 @@ export const toastComparisonJobError = (currentVersion: NamedVersion, targetVers
);
};

/** Toast Comparison Job Complete.
* Outputs toast message following the pattern:
* Version Compare
* iModel versions <currentVersion> and <targetVersion> comparison job is complete.
*
* Also has a link with the text "View The Report" and when clicked will start visualization on the comparison.
*/
export const toastComparisonJobComplete = (args: ManagerStartComparisonV2Args) => {
const title = IModelApp.localization.getLocalizedString("VersionCompare:versionCompare.viewTheReport");
toaster.closeAll();
Expand All @@ -52,13 +69,20 @@ export const toastComparisonJobComplete = (args: ManagerStartComparisonV2Args) =
iModelConnection: args.iModelConnection,
targetVersion: args.targetVersion,
currentVersion: args.currentVersion,
getToastsEnabled: args.getToastsEnabled,
runOnJobUpdate: args.runOnJobUpdate,
});
},
},
type: "persisting",
});
};

/** Toast Comparison Visualization Starting.
* Outputs toast message following the pattern:
* Version Compare
* Comparison Visualization Starting.
*/
export const toastComparisonVisualizationStarting = () => {
IModelApp.notifications.outputMessage(
new NotifyMessageDetails(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,37 @@ import { IModelConnection } from "@itwin/core-frontend";
import { ComparisonJobCompleted, ComparisonJobStarted, IComparisonJobClient } from "../../../clients/IComparisonJobClient";
import { NamedVersion } from "../../../clients/iModelsClient";
import { VersionCompare } from "../../../api/VersionCompare";
import { toastComparisonVisualizationStarting } from "./versionComapreToasts";
import { toastComparisonVisualizationStarting } from "./versionCompareToasts";
import { Logger } from "@itwin/core-bentley";
import { JobStatusAndJobProgress } from "../models/ComparisonJobModels";
import { JobAndNamedVersions, JobStatusAndJobProgress } from "../models/ComparisonJobModels";
import { VersionState } from "../models/VersionState";
import { ComparisonJobUpdateType } from "../components/VersionCompareDialogProvider";

export type ManagerStartComparisonV2Args = {
comparisonJob: ComparisonJobCompleted;
comparisonJobClient: IComparisonJobClient;
iModelConnection: IModelConnection;
targetVersion: NamedVersion;
currentVersion: NamedVersion;
getToastsEnabled: () => boolean;
runOnJobUpdate: (comparisonEventType: ComparisonJobUpdateType, jobAndNamedVersions?: JobAndNamedVersions) => Promise<void>;
};

export const runManagerStartComparisonV2 = async (args: ManagerStartComparisonV2Args) => {
if (VersionCompare.manager?.isComparing) {
return;
}
toastComparisonVisualizationStarting();
if (args.getToastsEnabled()) {
toastComparisonVisualizationStarting();
}

const jobAndNamedVersion: JobAndNamedVersions = {
comparisonJob: args.comparisonJob,
targetNamedVersion: args.targetVersion,
currentNamedVersion: args.currentVersion,
};
void args.runOnJobUpdate("ComparisonVisualizationStarting", jobAndNamedVersion);

const changedElements = await args.comparisonJobClient.getComparisonJobResult(args.comparisonJob);
VersionCompare.manager?.startComparisonV2(args.iModelConnection, args.currentVersion, args.targetVersion, [changedElements.changedElements]).catch((e) => {
Logger.logError(VersionCompare.logCategory, "Could not start version comparison: " + e);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
import React from "react";
import { JobAndNamedVersions } from "../models/ComparisonJobModels";

/** Comparison Job Update Type
* - "JobComplete" = job is completed
* - "JobError" = job error
* - "JobProcessing" = job is started
* - "ComparisonVisualizationStarting" = version compare visualization is starting
*/
export type ComparisonJobUpdateType = "JobComplete" | "JobError" | "JobProcessing" | "ComparisonVisualizationStarting";

export type V2Context = {
getDialogOpen: () => boolean;
openDialog: () => void;
closedDialog: () => void;
addRunningJob: (jobId: string, comparisonJob: JobAndNamedVersions) => void;
removeRunningJob: (jobId: string) => void;
getRunningJobs: () => JobAndNamedVersions[];
getPendingJobs: () => JobAndNamedVersions[];
addPendingJob: (jobId: string, comparisonJob: JobAndNamedVersions) => void;
removePendingJob: (jobId: string) => void;
getToastsEnabled: () => boolean;
runOnJobUpdate: (comparisonJobUpdateType: ComparisonJobUpdateType, jobAndNamedVersions?: JobAndNamedVersions) => Promise<void>;
};

export const V2DialogContext = React.createContext<V2Context>({} as V2Context);

export type V2DialogProviderProps = {
children: React.ReactNode;
// Optional. When enabled will toast messages regarding job status. If not defined will default to false and will not show toasts.
enableComparisonJobUpdateToasts?: boolean;
/** On Job Update
* Optional. a call back function for handling job updates.
* @param comparisonJobUpdateType param for the type of update:
* - "JobComplete" = invoked when job is completed
* - "JobError" = invoked on job error
* - "JobProcessing" = invoked on job is started
* - "ComparisonVisualizationStarting" = invoked on when version compare visualization is starting
* @param jobAndNamedVersion param contain job and named version info to be passed to call back
*/
onJobUpdate?: (comparisonJobUpdateType: ComparisonJobUpdateType, jobAndNamedVersions?: JobAndNamedVersions) => Promise<void>;
};

/** V2DialogProvider use comparison jobs for processing.
* Used for tracking if the dialog is open or closed.
* This is useful for managing toast messages associated with dialog.
* Also caches comparison jobs that are pending creation or are currently running. To help populate new modal ref.
* Example:
*<V2DialogProvider>
*{(isOpenCondition) &&
* <VersionCompareSelectDialogV2
* iModelConnection={this.props.iModelConnection}
* onClose={this._handleVersionSelectDialogClose}
* />}
*</V2DialogProvider>
*/
export function VersionCompareSelectProviderV2({ children, enableComparisonJobUpdateToasts, onJobUpdate }: V2DialogProviderProps) {
const dialogRunningJobs = React.useRef<Map<string, JobAndNamedVersions>>(new Map<string, JobAndNamedVersions>());
const dialogPendingJobs = React.useRef<Map<string, JobAndNamedVersions>>(new Map<string, JobAndNamedVersions>());
const addRunningJob = (jobId: string, jobAndNamedVersions: JobAndNamedVersions) => {
dialogRunningJobs.current.set(jobId, {
comparisonJob: jobAndNamedVersions.comparisonJob,
targetNamedVersion: jobAndNamedVersions.targetNamedVersion,
currentNamedVersion: jobAndNamedVersions.currentNamedVersion,
});
};
const removeRunningJob = (jobId: string) => {
dialogRunningJobs.current.delete(jobId);
};
const getRunningJobs = () => {
return Array.from(dialogRunningJobs.current.values());
};
const addPendingJob = (jobId: string, jobAndNamedVersions: JobAndNamedVersions) => {
dialogPendingJobs.current.set(jobId, {
comparisonJob: jobAndNamedVersions.comparisonJob,
targetNamedVersion: jobAndNamedVersions.targetNamedVersion,
currentNamedVersion: jobAndNamedVersions.currentNamedVersion,
});
};
const removePendingJob = (jobId: string) => {
dialogPendingJobs.current.delete(jobId);
};
const getPendingJobs = () => {
return Array.from(dialogPendingJobs.current.values());
};
const dialogOpenRef = React.useRef(false);
const openDialog = () => {
dialogOpenRef.current = true;
};
const closedDialog = () => {
dialogOpenRef.current = false;
};
const getDialogOpen = () => {
return dialogOpenRef.current;
};
const getToastsEnabled = () => {
return enableComparisonJobUpdateToasts ?? false;
};
const runOnJobUpdate = async (comparisonEventType: ComparisonJobUpdateType, jobAndNamedVersions?: JobAndNamedVersions) => {
if (onJobUpdate) {
void onJobUpdate(comparisonEventType, jobAndNamedVersions);
}
};
return (
<V2DialogContext.Provider value={{
openDialog, getDialogOpen: getDialogOpen, closedDialog, addRunningJob,
removeRunningJob, getRunningJobs, getPendingJobs, addPendingJob, removePendingJob,
getToastsEnabled, runOnJobUpdate,
}}>
{children}
</V2DialogContext.Provider>
);
}
Loading
Loading