Skip to content

Commit ca6b576

Browse files
committed
refactor(SidePanel): optimize form re-initialization logic with memoization
1 parent 42fdebb commit ca6b576

3 files changed

Lines changed: 25 additions & 17 deletions

File tree

‎src/App.tsx‎

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1059,7 +1059,7 @@ export default function App() {
10591059
setBusy(false);
10601060
}
10611061
},
1062-
[runtime, refreshResults, activePanel],
1062+
[runtime, refreshResults, activePanel, notify],
10631063
);
10641064

10651065
const handleAnalysis = useCallback(
@@ -1638,7 +1638,7 @@ export default function App() {
16381638
setBusy(false);
16391639
}
16401640
},
1641-
[runtime, pendingRoiGrid, refresh],
1641+
[runtime, pendingRoiGrid, refresh, confirm],
16421642
);
16431643

16441644
const handleSaveWorkspaceHdf5 = useCallback(async () => {
@@ -1729,7 +1729,7 @@ export default function App() {
17291729
}
17301730
};
17311731
input.click();
1732-
}, [runtime, refresh, setWorkspaceFilename, markClean]);
1732+
}, [runtime, refresh, setWorkspaceFilename, markClean, notify]);
17331733

17341734
const handleImportHdf5 = useCallback(() => {
17351735
// Open the H5 browser dialog with no preloaded file; the user picks
@@ -1766,7 +1766,7 @@ export default function App() {
17661766
setCurrentId(oids[oids.length - 1] ?? null);
17671767
await refresh(oids[oids.length - 1] ?? null);
17681768
},
1769-
[refresh],
1769+
[refresh, notify],
17701770
);
17711771

17721772
const handleSaveFile = useCallback(async () => {
@@ -1817,7 +1817,7 @@ export default function App() {
18171817
a.click();
18181818
document.body.removeChild(a);
18191819
URL.revokeObjectURL(url);
1820-
}, [runtime, currentId, data, imageData, activePanel]);
1820+
}, [runtime, currentId, data, imageData, activePanel, notify, prompt]);
18211821

18221822
/** Open the "Save to directory…" dialog with the current selection
18231823
* (falls back to the whole panel when nothing is explicitly selected,
@@ -2041,7 +2041,7 @@ export default function App() {
20412041
setBusy(false);
20422042
}
20432043
},
2044-
[runtime, pendingSaveToDir, activePanel],
2044+
[runtime, pendingSaveToDir, activePanel, confirm, notify],
20452045
);
20462046

20472047
const handleOpenFile = useCallback(async () => {
@@ -2256,6 +2256,10 @@ export default function App() {
22562256
toggleAIPanel,
22572257
selectedIds.length,
22582258
currentId,
2259+
handleDuplicateSelection,
2260+
handleMoveSelectionDown,
2261+
handleMoveSelectionUp,
2262+
handleRenameCurrent,
22592263
],
22602264
);
22612265

‎src/aiassistant/conversationExport.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ export function conversationToMarkdown(conv: Conversation): string {
114114
* result is a valid filename on Windows / macOS / Linux. */
115115
export function sanitizeFilename(name: string, maxLen = 80): string {
116116
const cleaned = name
117+
// eslint-disable-next-line no-control-regex -- intentional: strip ASCII control chars from filenames
117118
.replace(/[\\/:*?"<>|\u0000-\u001f]/g, " ")
118119
.replace(/\s+/g, " ")
119120
.trim();

‎src/components/SidePanel.tsx‎

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -601,6 +601,20 @@ function ProcessingPanel({
601601
[runtime, oid, onApplied],
602602
);
603603

604+
// Key on the canonical applied values (not ``refreshNonce``) so the
605+
// form is only re-initialised when the Python-side baseline actually
606+
// changes. ``refreshNonce`` bumps *before* the parent's async
607+
// ``getLastProcessing`` re-fetch resolves, so keying on it would
608+
// remount the form with the stale ``info.values`` snapshot — making
609+
// freshly-typed values appear to revert to the previous baseline
610+
// after Apply.
611+
// Computed unconditionally to satisfy the rules-of-hooks even when the
612+
// early-return branch below is taken.
613+
const valuesKey = useMemo(
614+
() => JSON.stringify(info.values ?? {}),
615+
[info.values],
616+
);
617+
604618
// Parameterless features: nothing to edit, just expose a "Re-apply"
605619
// button so the user can still trigger the recomputation.
606620
if (!info.has_params || !info.schema) {
@@ -626,17 +640,6 @@ function ProcessingPanel({
626640
</div>
627641
);
628642
}
629-
// Key on the canonical applied values (not ``refreshNonce``) so the
630-
// form is only re-initialised when the Python-side baseline actually
631-
// changes. ``refreshNonce`` bumps *before* the parent's async
632-
// ``getLastProcessing`` re-fetch resolves, so keying on it would
633-
// remount the form with the stale ``info.values`` snapshot — making
634-
// freshly-typed values appear to revert to the previous baseline
635-
// after Apply.
636-
const valuesKey = useMemo(
637-
() => JSON.stringify(info.values ?? {}),
638-
[info.values],
639-
);
640643
return (
641644
<div className="processing-panel">
642645
<ProcessingHeader info={info} />

0 commit comments

Comments
 (0)