@@ -464,6 +464,10 @@ const InspectionDetailsPanel = ({
464464 h : number ;
465465 } | null > ( null ) ;
466466 const [ awaitingRedraw , setAwaitingRedraw ] = useState ( false ) ;
467+ const [ showResetModelConfirm , setShowResetModelConfirm ] = useState ( false ) ;
468+ const [ isResettingModel , setIsResettingModel ] = useState ( false ) ;
469+ const [ resetModelMessage , setResetModelMessage ] = useState < string | null > ( null ) ;
470+ const [ resetModelError , setResetModelError ] = useState < string | null > ( null ) ;
467471
468472 const transformer = useMemo (
469473 ( ) =>
@@ -935,6 +939,59 @@ const InspectionDetailsPanel = ({
935939 }
936940 } ;
937941
942+ const handleResetModelClick = ( ) => {
943+ setResetModelMessage ( null ) ;
944+ setResetModelError ( null ) ;
945+ setShowResetModelConfirm ( true ) ;
946+ } ;
947+
948+ const closeResetModelModal = ( ) => {
949+ if ( isResettingModel ) return ;
950+ setShowResetModelConfirm ( false ) ;
951+ } ;
952+
953+ const handleConfirmResetModel = async ( ) => {
954+ setIsResettingModel ( true ) ;
955+ setResetModelError ( null ) ;
956+ try {
957+ const username =
958+ typeof window !== "undefined" ? localStorage . getItem ( "username" ) || "" : "" ;
959+ const response = await fetch ( apiUrl ( `/api/inspections/model/reset` ) , {
960+ method : "POST" ,
961+ headers : {
962+ "content-type" : "application/json" ,
963+ "x-username" : username ,
964+ } ,
965+ } ) ;
966+ if ( ! response . ok ) {
967+ const text = await response . text ( ) ;
968+ throw new Error ( text || `Reset failed (${ response . status } )` ) ;
969+ }
970+ const payload : unknown = await response
971+ . json ( )
972+ . catch ( ( ) => null ) ;
973+ let actor : string | undefined ;
974+ if ( typeof payload === "object" && payload !== null ) {
975+ const candidate = ( payload as { resetBy ?: unknown } ) . resetBy ;
976+ if ( typeof candidate === "string" ) {
977+ actor = candidate ;
978+ }
979+ }
980+ setShowResetModelConfirm ( false ) ;
981+ setResetModelMessage (
982+ actor && actor . trim ( ) . length > 0
983+ ? `AI parameters reset to defaults by ${ actor } .`
984+ : "AI parameters reset to defaults."
985+ ) ;
986+ } catch ( error ) {
987+ const message =
988+ error instanceof Error ? error . message : "Failed to reset model parameters." ;
989+ setResetModelError ( message ) ;
990+ } finally {
991+ setIsResettingModel ( false ) ;
992+ }
993+ } ;
994+
938995 const closeFaultModal = ( ) => {
939996 setShowFaultModal ( false ) ;
940997 setPendingRect ( null ) ;
@@ -1337,12 +1394,36 @@ const InspectionDetailsPanel = ({
13371394 type = "checkbox"
13381395 className = "peer sr-only"
13391396 checked = { tuneModelEnabled }
1397+ disabled = { isResettingModel }
13401398 onChange = { ( event ) => setTuneModelEnabled ( event . target . checked ) }
13411399 />
13421400 < span className = "pointer-events-none absolute inset-0 rounded-full bg-gray-400 transition-colors peer-checked:bg-green-500" />
13431401 < span className = "pointer-events-none absolute left-1 top-1 h-3 w-3 rounded-full bg-white transition-transform peer-checked:translate-x-5" />
13441402 </ span >
13451403 </ label >
1404+ < button
1405+ type = "button"
1406+ onClick = { handleResetModelClick }
1407+ disabled = { isResettingModel }
1408+ className = "inline-flex items-center gap-2 px-3 py-1 text-sm border rounded custombutton disabled:opacity-60 disabled:cursor-not-allowed"
1409+ title = "Reset AI parameters to their defaults"
1410+ >
1411+ < svg
1412+ className = "w-4 h-4"
1413+ fill = "none"
1414+ stroke = "currentColor"
1415+ strokeWidth = { 1.5 }
1416+ strokeLinecap = "round"
1417+ strokeLinejoin = "round"
1418+ viewBox = "0 0 24 24"
1419+ >
1420+ < path d = "M4 4v6h6" />
1421+ < path d = "M20 20v-6h-6" />
1422+ < path d = "M20 9.5A7.5 7.5 0 0 0 11 2h-1" />
1423+ < path d = "M4 14.5A7.5 7.5 0 0 0 13 22h1" />
1424+ </ svg >
1425+ < span > { isResettingModel ? "Resetting…" : "Reset model" } </ span >
1426+ </ button >
13461427 < button onClick = { flushAndClose } className = "text-gray-400 hover:text-gray-600" disabled = { isClosing } >
13471428 < svg
13481429 className = "w-6 h-6"
@@ -1361,6 +1442,13 @@ const InspectionDetailsPanel = ({
13611442 </ div >
13621443 </ div >
13631444
1445+ { ! showResetModelConfirm && resetModelMessage && (
1446+ < div className = "mb-4 text-sm text-green-600" > { resetModelMessage } </ div >
1447+ ) }
1448+ { ! showResetModelConfirm && resetModelError && (
1449+ < div className = "mb-4 text-sm text-red-600" > { resetModelError } </ div >
1450+ ) }
1451+
13641452 < div className = "grid grid-cols-2 gap-4 mb-6" >
13651453 < div >
13661454 < label className = "block text-sm font-bold" > Inspection Number</ label >
@@ -2279,6 +2367,43 @@ const InspectionDetailsPanel = ({
22792367 </ div >
22802368 </ div >
22812369 </ div >
2370+ { /* Reset model confirmation */ }
2371+ { showResetModelConfirm && (
2372+ < div className = "fixed inset-0 z-50 flex items-center justify-center bg-black/50" >
2373+ < div className = "details-panel bg-white dark:bg-[#111] rounded shadow-lg p-5 w-96" >
2374+ < h3 className = "font-semibold text-gray-900 dark:text-white mb-2" >
2375+ Reset AI parameters?
2376+ </ h3 >
2377+ < p className = "text-sm text-gray-700 dark:text-gray-300 mb-4" >
2378+ This will restore all model tuning values to the factory defaults
2379+ and cannot be undone. Continue?
2380+ </ p >
2381+ { resetModelError && (
2382+ < div className = "mb-3 text-sm text-red-600" role = "alert" >
2383+ { resetModelError }
2384+ </ div >
2385+ ) }
2386+ < div className = "flex justify-end gap-2" >
2387+ < button
2388+ type = "button"
2389+ className = "px-3 py-1 text-sm border border-gray-300 dark:border-gray-600 rounded text-gray-900 dark:text-white disabled:opacity-60"
2390+ onClick = { closeResetModelModal }
2391+ disabled = { isResettingModel }
2392+ >
2393+ Cancel
2394+ </ button >
2395+ < button
2396+ type = "button"
2397+ className = "px-3 py-1 text-sm rounded bg-red-600 text-white disabled:opacity-60"
2398+ onClick = { handleConfirmResetModel }
2399+ disabled = { isResettingModel }
2400+ >
2401+ { isResettingModel ? "Resetting…" : "Yes, reset" }
2402+ </ button >
2403+ </ div >
2404+ </ div >
2405+ </ div >
2406+ ) }
22822407 { /* Fault selection modal */ }
22832408 { showFaultModal && pendingRect && (
22842409 < div className = "fixed inset-0 z-50 flex items-center justify-center bg-black/50" >
0 commit comments