@@ -203,8 +203,10 @@ async function pushMetadataAndAccess (ax: AxiosInstance, pluginsDir: string, dir
203203 if ( typeof metadata . category === 'string' ) patch . group = { fr : metadata . category }
204204 if ( typeof metadata . documentation === 'string' ) patch . documentation = metadata . documentation
205205
206+ let updatedArtefact : { thumbnail ?: unknown } | undefined
206207 try {
207- await ax . patch ( `/api/v1/artefacts/${ encodeURIComponent ( name ) } ` , patch )
208+ const patchRes = await ax . patch ( `/api/v1/artefacts/${ encodeURIComponent ( name ) } ` , patch )
209+ updatedArtefact = patchRes . data as { thumbnail ?: unknown }
208210 debug ( `${ dir } : PATCHed metadata into ${ name } ` )
209211 } catch ( err : any ) {
210212 const status = err ?. response ?. status
@@ -216,27 +218,31 @@ async function pushMetadataAndAccess (ax: AxiosInstance, pluginsDir: string, dir
216218 }
217219
218220 // Render the legacy mdi icon to an SVG and upload it as the artefact
219- // thumbnail. Failures are swallowed with a debug log — the artefact still
220- // shows up in the picker, just without an icon, and the operator can
221- // upload a thumbnail manually later .
221+ // thumbnail. Skipped if the artefact already has a thumbnail — re-runs of
222+ // this migration must not clobber a manually uploaded one. Upload failures
223+ // are swallowed with a debug log so a single bad icon doesn't fail the run .
222224 if ( typeof metadata . icon === 'string' && metadata . icon . trim ( ) ) {
223- const mdiPath = resolveMdiPath ( metadata . icon )
224- if ( ! mdiPath ) {
225- debug ( `${ dir } : unknown mdi icon "${ metadata . icon } ", skipping thumbnail` )
225+ if ( updatedArtefact ?. thumbnail ) {
226+ debug ( `${ dir } : artefact ${ name } already has a thumbnail, skipping mdi:${ metadata . icon } ` )
226227 } else {
227- try {
228- const svg = renderMdiSvg ( mdiPath )
229- const tform = new FormData ( )
230- tform . append ( 'file' , new Blob ( [ svg ] , { type : 'image/svg+xml' } ) , 'icon.svg' )
231- await ax . post ( `/api/v1/artefacts/${ encodeURIComponent ( name ) } /thumbnail` , tform , {
232- validateStatus : s => s === 201
233- } )
234- debug ( `${ dir } : uploaded thumbnail from mdi:${ metadata . icon } ` )
235- } catch ( err : any ) {
236- const status = err ?. response ?. status
237- const body = err ?. response ?. data
238- const bodyStr = typeof body === 'string' ? body : JSON . stringify ( body )
239- debug ( `${ dir } : thumbnail upload failed (${ status ?? 'no-response' } : ${ bodyStr ?? err ?. message } ) — leaving artefact without icon` )
228+ const mdiPath = resolveMdiPath ( metadata . icon )
229+ if ( ! mdiPath ) {
230+ debug ( `${ dir } : unknown mdi icon "${ metadata . icon } ", skipping thumbnail` )
231+ } else {
232+ try {
233+ const svg = renderMdiSvg ( mdiPath )
234+ const tform = new FormData ( )
235+ tform . append ( 'file' , new Blob ( [ svg ] , { type : 'image/svg+xml' } ) , 'icon.svg' )
236+ await ax . post ( `/api/v1/artefacts/${ encodeURIComponent ( name ) } /thumbnail` , tform , {
237+ validateStatus : s => s === 201
238+ } )
239+ debug ( `${ dir } : uploaded thumbnail from mdi:${ metadata . icon } ` )
240+ } catch ( err : any ) {
241+ const status = err ?. response ?. status
242+ const body = err ?. response ?. data
243+ const bodyStr = typeof body === 'string' ? body : JSON . stringify ( body )
244+ debug ( `${ dir } : thumbnail upload failed (${ status ?? 'no-response' } : ${ bodyStr ?? err ?. message } ) — leaving artefact without icon` )
245+ }
240246 }
241247 }
242248 }
0 commit comments