Skip to content

Commit a4c84d5

Browse files
Naron/nv table loading (#234)
- refactored `NamedVersionSelector`: merged `namedVersionCompareSelector` with the changedElement widget components into one in their parent component, extracted the NV table so that it stays throughout the phase changes. - applied useContext for NamedVersionSelector content related props to flatten the structure --------- Co-authored-by: naronchen <naronchen@users.noreply.github.com> Co-authored-by: iTwin.js admin <38288322+imodeljs-admin@users.noreply.github.com> Co-authored-by: imodeljs-admin <imodeljs-admin@users.noreply.github.com>
1 parent ded75e2 commit a4c84d5

6 files changed

Lines changed: 138 additions & 167 deletions

File tree

.changeset/eighty-apples-care.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@itwin/changed-elements-react": patch
3+
---
4+
5+
Nvtable persists when loading comparison

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,4 @@ pnpm-debug.log*
1313
.env.*
1414

1515
packages/test-app-frontend/dist/
16+
.DS_Store

packages/changed-elements-react/src/NamedVersionSelector/NamedVersionSelector.tsx

Lines changed: 108 additions & 160 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import {
2626
runManagerStartComparisonV2
2727
} from "../widgets/comparisonJobWidget/common/versionCompareV2WidgetUtils.js";
2828
import { IconEx } from "./IconEx.js";
29-
import { namedVersionSelectorContext } from "./NamedVersionSelectorContext.js";
29+
import { NamedVersionSelectorContentContext, NamedVersionSelectorContentProps, namedVersionSelectorContext } from "./NamedVersionSelectorContext.js";
3030
import { Sticky } from "./Sticky.js";
3131
import { TextEx } from "./TextEx.js";
3232
import { useComparisonJobs } from "./useComparisonJobs.js";
@@ -61,8 +61,10 @@ export function NamedVersionSelectorWidget(props: Readonly<NamedVersionSelectorW
6161

6262
const { iModel, emptyState, manageVersions, feedbackUrl } = props;
6363

64+
const [targetgVersion, setTargetVersion] = useState<NamedVersion>();
6465
const [isComparing, setIsComparing] = useState(manager.isComparing);
6566
const [isComparisonStarted, setIsComparisonStarted] = useState(manager.isComparisonReady);
67+
6668
useEffect(
6769
() => {
6870
const cleanup = [
@@ -86,20 +88,51 @@ export function NamedVersionSelectorWidget(props: Readonly<NamedVersionSelectorW
8688
[manager],
8789
);
8890

91+
const { iModelsClient, comparisonJobClient } = useVersionCompare();
92+
if (!comparisonJobClient) {
93+
throw new Error("V2 Client is not initialized in given context.");
94+
}
95+
96+
const iTwinId = iModel.iTwinId as string;
97+
const iModelId = iModel.iModelId as string;
98+
const currentChangesetId = iModel.changeset.id;
99+
100+
const { isLoading, currentNamedVersion, entries, updateJobStatus } = useNamedVersionsList({
101+
iTwinId,
102+
iModelId,
103+
currentChangesetId,
104+
});
105+
89106
const widgetRef = useRef<ChangedElementsWidget>(null);
90107

91-
if (!isComparing) {
92-
return (
93-
<NamedVersionSelector
94-
iModel={iModel}
95-
manager={manager}
96-
emptyState={emptyState}
97-
manageVersions={manageVersions}
98-
feedbackUrl={feedbackUrl}
99-
documentationHref = {props.documentationHref}
100-
/>
101-
);
102-
}
108+
const onNamedVersionOpened = async (targetVersion?: NamedVersionEntry) => {
109+
setTargetVersion(targetVersion?.namedVersion);
110+
if (!targetVersion || !currentNamedVersion || targetVersion.job?.status !== "Completed") {
111+
return;
112+
}
113+
114+
await runManagerStartComparisonV2({
115+
comparisonJob: {
116+
comparisonJob: {
117+
status: "Completed",
118+
jobId: targetVersion.job.jobId,
119+
iTwinId,
120+
iModelId,
121+
startChangesetId: currentChangesetId,
122+
endChangesetId: targetVersion.namedVersion.targetChangesetId ?? "",
123+
comparison: {
124+
href: targetVersion.job.comparisonUrl,
125+
},
126+
},
127+
},
128+
comparisonJobClient,
129+
iModelConnection: iModel,
130+
targetVersion: targetVersion.namedVersion,
131+
currentVersion: currentNamedVersion,
132+
getToastsEnabled: () => true,
133+
iModelsClient,
134+
});
135+
};
103136

104137
return (
105138
<Widget>
@@ -110,6 +143,13 @@ export function NamedVersionSelectorWidget(props: Readonly<NamedVersionSelectorW
110143
<TextEx variant="title">
111144
{t("VersionCompare:versionCompare.versionPickerTitle")}
112145
</TextEx>
146+
147+
{
148+
!isComparisonStarted &&
149+
<ChangedElementsHeaderButtons documentationHref={props.documentationHref} onlyInfo />
150+
}
151+
152+
{isComparisonStarted &&
113153
<div>
114154
<ChangedElementsHeaderButtons
115155
useNewNamedVersionSelector
@@ -122,22 +162,52 @@ export function NamedVersionSelectorWidget(props: Readonly<NamedVersionSelectorW
122162
}
123163
documentationHref={props.documentationHref}
124164
/>
125-
</div>
165+
</div>}
166+
126167
</Widget.Header>
127-
<namedVersionSelectorContext.Consumer>
128-
{(value) => (
129-
<namedVersionSelectorContext.Provider value={{ ...value, contextExists: true }}>
130-
{props.manager?.currentVersion && isComparisonStarted &&
131-
<ActiveVersionsBox current={props.manager?.currentVersion} selected={props.manager?.targetVersion}></ActiveVersionsBox>}
132-
<ChangedElementsWidget
133-
ref={widgetRef}
134-
iModelConnection={iModel}
135-
manager={manager}
136-
usingExperimentalSelector
137-
/>
138-
</namedVersionSelectorContext.Provider>
139-
)}
140-
</namedVersionSelectorContext.Consumer>
168+
{
169+
currentNamedVersion &&
170+
<ActiveVersionsBox current={currentNamedVersion} selected={targetgVersion}></ActiveVersionsBox>
171+
}
172+
173+
{
174+
!isComparing &&
175+
<NamedVersionSelectorContentContext.Provider
176+
value={{
177+
iTwinId,
178+
iModelId,
179+
isLoading,
180+
currentNamedVersion,
181+
entries,
182+
updateJobStatus,
183+
onNamedVersionOpened,
184+
emptyState,
185+
manageVersions,
186+
}}
187+
>
188+
<NamedVersionSelectorContent />
189+
<div className="_cer_v1_feedback_btn_container">
190+
{feedbackUrl && <FeedbackButton feedbackUrl={feedbackUrl} />}
191+
</div>
192+
</NamedVersionSelectorContentContext.Provider>
193+
}
194+
195+
{
196+
isComparing &&
197+
<namedVersionSelectorContext.Consumer>
198+
{(value) => (
199+
<namedVersionSelectorContext.Provider value={{ ...value, contextExists: true }}>
200+
<ChangedElementsWidget
201+
ref={widgetRef}
202+
iModelConnection={iModel}
203+
manager={manager}
204+
usingExperimentalSelector
205+
/>
206+
</namedVersionSelectorContext.Provider>
207+
)}
208+
</namedVersionSelectorContext.Consumer>
209+
}
210+
141211
</Widget>
142212
);
143213
}
@@ -160,137 +230,24 @@ function LoadingState(): ReactElement {
160230
);
161231
}
162232

163-
164-
type LoadedStateProps = Omit<NamedVersionSelectorContentProps, "isLoading" | "currentNamedVersion"> & { currentNamedVersion: NamedVersion; };
165-
166-
function LoadedState(props: Readonly<LoadedStateProps>): ReactElement {
167-
return (
168-
<NamedVersionSelectorLoaded
169-
{...props}
170-
/>
171-
);
172-
}
173-
174-
type NamedVersionSelectorContentProps = {
175-
isLoading: boolean;
176-
entries: NamedVersionEntry[];
177-
currentNamedVersion: NamedVersion | undefined;
178-
iTwinId: string;
179-
iModelId: string;
180-
onNamedVersionOpened: (version: NamedVersionEntry) => void;
181-
updateJobStatus: ReturnType<typeof useNamedVersionsList>["updateJobStatus"];
182-
emptyState?: ReactNode;
183-
manageVersions?: ReactNode;
184-
};
185-
186-
function NamedVersionSelectorContent(
187-
props: Readonly<NamedVersionSelectorContentProps>,
188-
): ReactElement {
189-
if (!props.isLoading && props.entries.length === 0) {
233+
function NamedVersionSelectorContent(): ReactElement {
234+
const { isLoading, currentNamedVersion, ...restProps } = useContext(NamedVersionSelectorContentContext);
235+
if (!isLoading && restProps.entries.length === 0) {
190236
return <EmptyState />;
191237
}
192238

193-
if (!props.currentNamedVersion || (props.isLoading && props.entries.length === 0)) {
239+
if (!currentNamedVersion || (isLoading && restProps.entries.length === 0)) {
194240
return <LoadingState />;
195241
}
196242

197243
return (
198-
<LoadedState
199-
{...{ ...props, currentNamedVersion: props.currentNamedVersion }}
244+
<NamedVersionSelectorLoaded
245+
{...restProps}
246+
currentNamedVersion={currentNamedVersion}
200247
/>
201248
);
202249
}
203250

204-
interface NamedVersionSelectorProps {
205-
iModel: IModelConnection;
206-
manager: VersionCompareManager;
207-
emptyState?: ReactNode;
208-
manageVersions?: ReactNode;
209-
feedbackUrl?: string;
210-
documentationHref?: string;
211-
}
212-
213-
function NamedVersionSelector(props: Readonly<NamedVersionSelectorProps>): ReactElement {
214-
const { iModelsClient, comparisonJobClient } = useVersionCompare();
215-
if (!comparisonJobClient) {
216-
throw new Error("V2 Client is not initialized in given context.");
217-
}
218-
219-
const { iModel, manager, emptyState, manageVersions, feedbackUrl } = props;
220-
221-
const iTwinId = iModel.iTwinId as string;
222-
const iModelId = iModel.iModelId as string;
223-
const currentChangesetId = iModel.changeset.id;
224-
225-
const { isLoading, currentNamedVersion, entries, updateJobStatus } = useNamedVersionsList({
226-
iTwinId,
227-
iModelId,
228-
currentChangesetId,
229-
});
230-
231-
const [openedVersion, setOpenedVersion] = useState(manager.targetVersion);
232-
const onNamedVersionOpened = async (targetVersion?: NamedVersionEntry) => {
233-
setOpenedVersion(targetVersion?.namedVersion);
234-
if (!targetVersion || !currentNamedVersion || targetVersion.job?.status !== "Completed") {
235-
return;
236-
}
237-
238-
await runManagerStartComparisonV2({
239-
comparisonJob: {
240-
comparisonJob: {
241-
status: "Completed",
242-
jobId: targetVersion.job.jobId,
243-
iTwinId,
244-
iModelId,
245-
startChangesetId: currentChangesetId,
246-
endChangesetId: targetVersion.namedVersion.targetChangesetId ?? "",
247-
comparison: {
248-
href: targetVersion.job.comparisonUrl,
249-
},
250-
},
251-
},
252-
comparisonJobClient,
253-
iModelConnection: iModel,
254-
targetVersion: targetVersion.namedVersion,
255-
currentVersion: currentNamedVersion,
256-
getToastsEnabled: () => true,
257-
iModelsClient,
258-
});
259-
manager.versionCompareStopped.addOnce(() => setOpenedVersion(undefined));
260-
};
261-
262-
const namedVersionSelectorProps: Readonly<NamedVersionSelectorContentProps> = {
263-
isLoading,
264-
currentNamedVersion,
265-
entries,
266-
iTwinId,
267-
iModelId,
268-
onNamedVersionOpened,
269-
updateJobStatus,
270-
emptyState,
271-
manageVersions,
272-
};
273-
274-
return (
275-
<Widget>
276-
<Widget.Header>
277-
<TextEx variant="title">
278-
{t("VersionCompare:versionCompare.versionPickerTitle")}
279-
</TextEx>
280-
{currentNamedVersion && <ChangedElementsHeaderButtons documentationHref={props.documentationHref} onlyInfo />}
281-
</Widget.Header>
282-
{
283-
currentNamedVersion &&
284-
<ActiveVersionsBox current={currentNamedVersion} selected={openedVersion} />
285-
}
286-
<NamedVersionSelectorContent {...namedVersionSelectorProps} />
287-
<div className="_cer_v1_feedback_btn_container">
288-
{feedbackUrl && <FeedbackButton feedbackUrl={feedbackUrl} />}
289-
</div>
290-
</Widget>
291-
);
292-
}
293-
294251
interface WidgetProps {
295252
children?: ReactNode;
296253
}
@@ -394,18 +351,9 @@ function PlaceholderNamedVersionInfo(): ReactElement {
394351
);
395352
}
396353

397-
interface NamedVersionSelectorLoadedProps {
398-
iTwinId: string;
399-
iModelId: string;
400-
currentNamedVersion: NamedVersion;
401-
entries: NamedVersionEntry[];
402-
updateJobStatus: ReturnType<typeof useNamedVersionsList>["updateJobStatus"];
403-
onNamedVersionOpened: (version: NamedVersionEntry) => void;
404-
emptyState?: ReactNode;
405-
manageVersions?: ReactNode;
406-
}
354+
type LoadedStateProps = Omit<NamedVersionSelectorContentProps, "isLoading" | "currentNamedVersion"> & { currentNamedVersion: NamedVersion; };
407355

408-
function NamedVersionSelectorLoaded(props: Readonly<NamedVersionSelectorLoadedProps>): ReactElement {
356+
function NamedVersionSelectorLoaded(props: LoadedStateProps): ReactElement {
409357
const {
410358
iTwinId,
411359
iModelId,
@@ -518,7 +466,7 @@ function NamedVersionSelectorLoaded(props: Readonly<NamedVersionSelectorLoadedPr
518466
value={{ processResults, viewResults, initialLoad, checkStatus }}
519467
>
520468
{
521-
props.entries.map((entry) => (
469+
entries.map((entry) => (
522470
<NamedVersionListEntry key={entry.namedVersion.id} entry={entry} />
523471
))
524472
}

packages/changed-elements-react/src/NamedVersionSelector/NamedVersionSelectorContext.tsx

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@
22
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
33
* See LICENSE.md in the project root for license terms and full copyright notice.
44
*--------------------------------------------------------------------------------------------*/
5-
import { createContext } from "react";
5+
import { createContext, ReactNode } from "react";
66

7-
import type { NamedVersionEntry } from "./useNamedVersionsList.js";
7+
import type { NamedVersionEntry, useNamedVersionsList } from "./useNamedVersionsList.js";
8+
import { NamedVersion } from "../clients/iModelsClient.js";
89

910
export interface NamedVersionSelectorContextValue {
1011
/** Invoked when users request Named Version processinig. */
@@ -42,3 +43,19 @@ export const namedVersionSelectorContext = createContext<NamedVersionSelectorCon
4243
checkStatus: () => ({ cancel: () => { } }),
4344
contextExists: false,
4445
});
46+
47+
export type NamedVersionSelectorContentProps = {
48+
isLoading: boolean;
49+
entries: NamedVersionEntry[];
50+
currentNamedVersion: NamedVersion | undefined;
51+
iTwinId: string;
52+
iModelId: string;
53+
onNamedVersionOpened: (version: NamedVersionEntry) => void;
54+
updateJobStatus: ReturnType<typeof useNamedVersionsList>["updateJobStatus"];
55+
emptyState?: ReactNode;
56+
manageVersions?: ReactNode;
57+
};
58+
59+
export const NamedVersionSelectorContentContext = createContext<NamedVersionSelectorContentProps>(
60+
{} as NamedVersionSelectorContentProps,
61+
)

packages/changed-elements-react/src/VersionCompareContext.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,4 @@ export interface VersionCompareContextValue {
5757
}
5858

5959
const versionCompareContext = createContext<VersionCompareContextValue | undefined>(undefined);
60+

0 commit comments

Comments
 (0)