@@ -38,23 +38,27 @@ export function ModuleForm({ module: m, testable = false }: Props) {
3838 } , [ m . fields ] ) ;
3939
4040 const [ values , setValues ] = useState < Record < string , unknown > > ( initial ) ;
41+ const [ baseline , setBaseline ] = useState < Record < string , unknown > > ( initial ) ;
4142 const [ errors , setErrors ] = useState < Record < string , string > > ( { } ) ;
4243 const [ busy , setBusy ] = useState ( false ) ;
44+ const [ saved , setSaved ] = useState ( false ) ;
4345
4446 // Reset the edit buffer whenever the underlying module changes (package
4547 // switch, or server-reloaded props after a save/reset).
4648 useEffect ( ( ) => {
4749 setValues ( initial ) ;
50+ setBaseline ( initial ) ;
4851 setErrors ( { } ) ;
52+ setSaved ( false ) ;
4953 } , [ initial ] ) ;
5054
5155 const modifiedFields = useMemo ( ( ) => {
5256 const s = new Set < string > ( ) ;
5357 for ( const name of Object . keys ( values ) ) {
54- if ( notEqual ( values [ name ] , initial [ name ] ) ) s . add ( name ) ;
58+ if ( notEqual ( values [ name ] , baseline [ name ] ) ) s . add ( name ) ;
5559 }
5660 return s ;
57- } , [ values , initial ] ) ;
61+ } , [ values , baseline ] ) ;
5862
5963 const defaultByName = useMemo ( ( ) => {
6064 const o : Record < string , unknown > = { } ;
@@ -76,6 +80,7 @@ export function ModuleForm({ module: m, testable = false }: Props) {
7680
7781 async function onSave ( ) {
7882 setBusy ( true ) ;
83+ setSaved ( false ) ;
7984 setErrors ( { } ) ;
8085 const changed : Record < string , unknown > = { } ;
8186 for ( const name of modifiedFields ) changed [ name ] = values [ name ] ;
@@ -92,12 +97,16 @@ export function ModuleForm({ module: m, testable = false }: Props) {
9297 }
9398 setErrors ( fieldErrs ) ;
9499 } else if ( resp . ok ) {
95- router . reload ( { only : [ 'modules' ] } ) ;
100+ // Keeping the form mounted lets the confirmation remain visible instead
101+ // of being discarded by an immediate Inertia reload.
102+ setBaseline ( { ...values } ) ;
103+ setSaved ( true ) ;
96104 }
97105 setBusy ( false ) ;
98106 }
99107
100108 async function onReset ( name : string ) {
109+ setSaved ( false ) ;
101110 await fetch ( `/api/settings/modules/${ m . package } /${ name } ` , { method : 'DELETE' } ) ;
102111 router . reload ( { only : [ 'modules' ] } ) ;
103112 }
@@ -109,7 +118,12 @@ export function ModuleForm({ module: m, testable = false }: Props) {
109118 < h2 className = "text-xl font-semibold" > { m . module_name } </ h2 >
110119 < p className = "text-xs font-mono text-muted-foreground" > { m . package } </ p >
111120 </ div >
112- < div className = "flex items-start gap-2" >
121+ < div className = "flex items-center gap-2" >
122+ { saved && (
123+ < p role = "status" className = "text-sm font-medium text-emerald-700" >
124+ { t ( keys . settings . modules_form . saved_toast ) }
125+ </ p >
126+ ) }
113127 { testable && < TestConnectionButton pkg = { m . package } /> }
114128 < button
115129 type = "button"
@@ -148,7 +162,10 @@ export function ModuleForm({ module: m, testable = false }: Props) {
148162 id = { `field-${ m . package } -${ f . name } ` }
149163 field = { f }
150164 value = { values [ f . name ] }
151- onChange = { ( name , v ) => setValues ( ( prev ) => ( { ...prev , [ name ] : v } ) ) }
165+ onChange = { ( name , v ) => {
166+ setSaved ( false ) ;
167+ setValues ( ( prev ) => ( { ...prev , [ name ] : v } ) ) ;
168+ } }
152169 />
153170 { isModified && (
154171 < button
0 commit comments