@@ -2,7 +2,6 @@ import { v1 } from '@docker/extension-api-client-types';
2
2
import CheckOutlined from '@mui/icons-material/CheckOutlined' ;
3
3
import CloseOutlined from '@mui/icons-material/CloseOutlined' ;
4
4
import {
5
- CircularProgress ,
6
5
IconButton ,
7
6
Stack ,
8
7
TextField ,
@@ -42,7 +41,6 @@ const ConfigEditor = ({
42
41
const [ localConfig , setLocalConfig ] = useState <
43
42
{ [ key : string ] : any } | undefined
44
43
> ( undefined ) ;
45
- const [ savingKeys , setSavingKeys ] = useState < Set < string > > ( new Set ( ) ) ;
46
44
47
45
// Use memoized flattenedConfig to ensure it only updates when config changes
48
46
// This MUST be called before any early returns to avoid conditional hook calls
@@ -86,7 +84,6 @@ const ConfigEditor = ({
86
84
< Stack >
87
85
{ Object . keys ( flattenedConfig ) . map ( ( key : string ) => {
88
86
const edited = localConfig [ key ] !== flattenedConfig [ key ] ;
89
- const isSaving = savingKeys . has ( key ) ;
90
87
91
88
return (
92
89
< Stack
@@ -105,54 +102,40 @@ const ConfigEditor = ({
105
102
onChange = { ( e ) =>
106
103
setLocalConfig ( { ...localConfig , [ key ] : e . target . value } )
107
104
}
108
- disabled = { isSaving }
109
105
/>
110
106
{ edited && (
111
- < >
112
- { isSaving ? (
113
- < CircularProgress size = { 24 } />
114
- ) : (
115
- < Stack direction = "row" spacing = { 1 } >
116
- < IconButton
117
- size = "small"
118
- onClick = { ( ) => {
119
- const newConfig = buildObjectFromFlattenedObject ( localConfig ) ;
120
-
121
- // Remove all attributes which are optional and which have the defautl value
122
- const schema = new JsonSchemaLibrary . Draft2019 ( catalogItem . config [ 0 ] ) ;
123
- const requiredAttributes = ( schema . rootSchema . required || [ ] ) as string [ ] ;
124
- const template = schema . getTemplate ( { } ) ;
125
- const requiredConfig = Object . fromEntries ( Object . entries ( newConfig ) . filter ( ( [ key , value ] ) => {
126
- return requiredAttributes . includes ( key ) || ( value !== template [ key ] ) ;
127
- } ) ) ;
128
-
129
- updateExistingConfig ( catalogItem . name , requiredConfig )
130
- } }
131
- disabled = { isSaving }
132
- >
133
- < CheckOutlined
134
- fontSize = "small"
135
- sx = { { color : 'success.main' } }
136
- />
137
- </ IconButton >
138
- < IconButton
139
- size = "small"
140
- onClick = { ( ) =>
141
- setLocalConfig ( {
142
- ...localConfig ,
143
- [ key ] : flattenedConfig [ key ] ,
144
- } )
145
- }
146
- disabled = { isSaving }
147
- >
148
- < CloseOutlined
149
- fontSize = "small"
150
- sx = { { color : 'error.main' } }
151
- />
152
- </ IconButton >
153
- </ Stack >
154
- ) }
155
- </ >
107
+ < Stack direction = "row" spacing = { 1 } >
108
+ < IconButton
109
+ size = "small"
110
+ onClick = { ( ) => {
111
+ const newConfig = sanitizeConfig ( localConfig , catalogItem ) ;
112
+ updateExistingConfig ( catalogItem . name , newConfig ) ;
113
+ setLocalConfig ( {
114
+ ...localConfig ,
115
+ [ key ] : newConfig [ key ] ,
116
+ } ) ;
117
+ } }
118
+ >
119
+ < CheckOutlined
120
+ fontSize = "small"
121
+ sx = { { color : 'success.main' } }
122
+ />
123
+ </ IconButton >
124
+ < IconButton
125
+ size = "small"
126
+ onClick = { ( ) =>
127
+ setLocalConfig ( {
128
+ ...localConfig ,
129
+ [ key ] : flattenedConfig [ key ] ,
130
+ } )
131
+ }
132
+ >
133
+ < CloseOutlined
134
+ fontSize = "small"
135
+ sx = { { color : 'error.main' } }
136
+ />
137
+ </ IconButton >
138
+ </ Stack >
156
139
) }
157
140
</ Stack >
158
141
) ;
@@ -162,4 +145,31 @@ const ConfigEditor = ({
162
145
) ;
163
146
} ;
164
147
165
- export default ConfigEditor ;
148
+ function sanitizeConfig ( config : { [ key : string ] : any ; } , catalogItem : CatalogItemRichened ) {
149
+ const newConfig = buildObjectFromFlattenedObject ( config ) ;
150
+
151
+ // Remove all attributes which are optional and which have the defautl value
152
+ const schema = new JsonSchemaLibrary . Draft2019 ( catalogItem . config [ 0 ] ) ;
153
+ const requiredAttributes = ( schema . rootSchema . required || [ ] ) as string [ ] ;
154
+ const template = schema . getTemplate ( { } ) ;
155
+ const requiredConfig = Object . fromEntries ( Object . entries ( newConfig ) . filter ( ( [ key , value ] ) => {
156
+ return requiredAttributes . includes ( key ) || ( value !== template [ key ] ) ;
157
+ } ) ) ;
158
+
159
+ // Use the right types for each attribute
160
+ const typedConfig = Object . fromEntries ( Object . entries ( requiredConfig ) . map ( ( [ key , value ] ) => {
161
+ const propertyType = schema . rootSchema . properties [ key ] . type ;
162
+ switch ( propertyType ) {
163
+ case "integer" :
164
+ return [ key , parseInt ( value ) || 0 ] ;
165
+ case "boolean" :
166
+ return [ key , ( value as string ) . toLowerCase ( ) === "true" ] ;
167
+ default :
168
+ return [ key , value ] ;
169
+ }
170
+ } ) ) ;
171
+
172
+ return typedConfig ;
173
+ }
174
+
175
+ export default ConfigEditor ;
0 commit comments