@cobaltcore-dev/aurora 0.4.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (178) hide show
  1. package/README.md +73 -77
  2. package/dist/client/AuroraApp.d.ts +15 -0
  3. package/dist/client/{AuthProvider-D-5Jpa6F.mjs → AuthProvider-Co4d0WzB.mjs} +3 -3
  4. package/dist/client/{AuthProvider-D-5Jpa6F.mjs.map → AuthProvider-Co4d0WzB.mjs.map} +1 -1
  5. package/dist/client/{ContentHeader-BXZoN3B9.mjs → ContentHeader-kx1Th5Sq.mjs} +29 -29
  6. package/dist/client/{ContentHeader-BXZoN3B9.mjs.map → ContentHeader-kx1Th5Sq.mjs.map} +1 -1
  7. package/dist/client/DeleteFlavorModal-C3cb7YiJ.mjs +638 -0
  8. package/dist/client/DeleteFlavorModal-C3cb7YiJ.mjs.map +1 -0
  9. package/dist/client/{EditSecurityGroupModal-DK3WYikA.mjs → EditSecurityGroupModal-CpP54WIK.mjs} +22 -22
  10. package/dist/client/{EditSecurityGroupModal-DK3WYikA.mjs.map → EditSecurityGroupModal-CpP54WIK.mjs.map} +1 -1
  11. package/dist/client/{FiltersInput-OVeIJzIo.mjs → FiltersInput-DxcyR6Bp.mjs} +18 -18
  12. package/dist/client/{FiltersInput-OVeIJzIo.mjs.map → FiltersInput-DxcyR6Bp.mjs.map} +1 -1
  13. package/dist/client/{FloatingIpActionModals-Dok7fJss.mjs → FloatingIpActionModals-BP8RWHbu.mjs} +77 -77
  14. package/dist/client/{FloatingIpActionModals-Dok7fJss.mjs.map → FloatingIpActionModals-BP8RWHbu.mjs.map} +1 -1
  15. package/dist/client/ImageToastNotifications-TZ3EfQg-.mjs +1219 -0
  16. package/dist/client/ImageToastNotifications-TZ3EfQg-.mjs.map +1 -0
  17. package/dist/client/{RouteError-pDEWC_k7.mjs → RouteError-QSV7qOoJ.mjs} +6 -6
  18. package/dist/client/{RouteError-pDEWC_k7.mjs.map → RouteError-QSV7qOoJ.mjs.map} +1 -1
  19. package/dist/client/{SortInput-DXWSqSny.mjs → SortInput-CYv2_Pur.mjs} +6 -6
  20. package/dist/client/{SortInput-DXWSqSny.mjs.map → SortInput-CYv2_Pur.mjs.map} +1 -1
  21. package/dist/client/{_auth-CJj1Cnbm.mjs → _auth-DXJkv9QO.mjs} +3 -3
  22. package/dist/client/{_auth-CJj1Cnbm.mjs.map → _auth-DXJkv9QO.mjs.map} +1 -1
  23. package/dist/client/{_flavorId-BoNcxYmF.mjs → _flavorId-C2x43-6S.mjs} +15 -15
  24. package/dist/client/_flavorId-C2x43-6S.mjs.map +1 -0
  25. package/dist/client/_flavorId-CR8ZUI-P.mjs +194 -0
  26. package/dist/client/_flavorId-CR8ZUI-P.mjs.map +1 -0
  27. package/dist/client/{_floatingIpId-D33bOEmH.mjs → _floatingIpId-BCk41_Lb.mjs} +3 -3
  28. package/dist/client/{_floatingIpId-D33bOEmH.mjs.map → _floatingIpId-BCk41_Lb.mjs.map} +1 -1
  29. package/dist/client/{_floatingIpId-DF_BSJN6.mjs → _floatingIpId-BGrOAmPT.mjs} +48 -48
  30. package/dist/client/{_floatingIpId-DF_BSJN6.mjs.map → _floatingIpId-BGrOAmPT.mjs.map} +1 -1
  31. package/dist/client/_imageId-CvfD832b.mjs +534 -0
  32. package/dist/client/_imageId-CvfD832b.mjs.map +1 -0
  33. package/dist/client/_pcaId-BxBt5DXi.mjs +459 -0
  34. package/dist/client/_pcaId-BxBt5DXi.mjs.map +1 -0
  35. package/dist/client/{_pcaId-BYCoeK6_.mjs → _pcaId-DOHycvCf.mjs} +3 -3
  36. package/dist/client/{_pcaId-BYCoeK6_.mjs.map → _pcaId-DOHycvCf.mjs.map} +1 -1
  37. package/dist/client/_projectId-BDSWnMGj.mjs +46 -0
  38. package/dist/client/_projectId-BDSWnMGj.mjs.map +1 -0
  39. package/dist/client/{_projectId-OW2xkK43.mjs → _projectId-DOgwFiqD.mjs} +3 -3
  40. package/dist/client/{_projectId-OW2xkK43.mjs.map → _projectId-DOgwFiqD.mjs.map} +1 -1
  41. package/dist/client/_projectId-DS4nR59B.mjs +299 -0
  42. package/dist/client/_projectId-DS4nR59B.mjs.map +1 -0
  43. package/dist/client/{_projectId-BwLMEMGC.mjs → _projectId-MxcHrXW4.mjs} +21 -21
  44. package/dist/client/_projectId-MxcHrXW4.mjs.map +1 -0
  45. package/dist/client/{_securityGroupId-B-Z-CzLp.mjs → _securityGroupId-CJJanWiY.mjs} +3 -3
  46. package/dist/client/{_securityGroupId-B-Z-CzLp.mjs.map → _securityGroupId-CJJanWiY.mjs.map} +1 -1
  47. package/dist/client/{_securityGroupId-B1bOYRbX.mjs → _securityGroupId-KKw4RPdH.mjs} +445 -446
  48. package/dist/client/{_securityGroupId-B1bOYRbX.mjs.map → _securityGroupId-KKw4RPdH.mjs.map} +1 -1
  49. package/dist/client/{containers-BjWqjNOx.mjs → _storageType-4wSxI__0.mjs} +19 -16
  50. package/dist/client/_storageType-4wSxI__0.mjs.map +1 -0
  51. package/dist/client/_storageType-DYjo-6ej.mjs +3243 -0
  52. package/dist/client/_storageType-DYjo-6ej.mjs.map +1 -0
  53. package/dist/client/_storageType-zeSZe--V.mjs +7 -0
  54. package/dist/client/_storageType-zeSZe--V.mjs.map +1 -0
  55. package/dist/client/about-Bo9vxGHy.mjs +92 -0
  56. package/dist/client/{about-DLn1ShhF.mjs.map → about-Bo9vxGHy.mjs.map} +1 -1
  57. package/dist/client/aurora-DDzsst74.mjs +19 -0
  58. package/dist/client/{aurora-CRcxVUCo.mjs.map → aurora-DDzsst74.mjs.map} +1 -1
  59. package/dist/client/{build-BJDfnAyi.mjs → build-DeJcDjPi.mjs} +3802 -3376
  60. package/dist/client/build-DeJcDjPi.mjs.map +1 -0
  61. package/dist/client/{buildFilterParams-TeyosGyK.mjs → buildFilterParams-DoZzMKX9.mjs} +1 -1
  62. package/dist/client/{buildFilterParams-TeyosGyK.mjs.map → buildFilterParams-DoZzMKX9.mjs.map} +1 -1
  63. package/dist/client/{cn-C3laVXMm.mjs → cn-DM4Cy3jv.mjs} +1 -1
  64. package/dist/client/{cn-C3laVXMm.mjs.map → cn-DM4Cy3jv.mjs.map} +1 -1
  65. package/dist/client/constants-BmcGYeR-.mjs +153 -0
  66. package/dist/client/constants-BmcGYeR-.mjs.map +1 -0
  67. package/dist/client/{flavors-D8oElC2K.mjs → flavors-BxFVqgnb.mjs} +2 -2
  68. package/dist/client/{flavors-D8oElC2K.mjs.map → flavors-BxFVqgnb.mjs.map} +1 -1
  69. package/dist/client/flavors-CfdgjsZY.mjs +632 -0
  70. package/dist/client/flavors-CfdgjsZY.mjs.map +1 -0
  71. package/dist/client/{flavors-BXPYAFyQ.mjs → flavors-DWMZ6TuJ.mjs} +2 -2
  72. package/dist/client/{flavors-BXPYAFyQ.mjs.map → flavors-DWMZ6TuJ.mjs.map} +1 -1
  73. package/dist/client/{floatingips-Fa6ocNUu.mjs → floatingips-ByRb82wS.mjs} +138 -139
  74. package/dist/client/{floatingips-Fa6ocNUu.mjs.map → floatingips-ByRb82wS.mjs.map} +1 -1
  75. package/dist/client/{formatBytes-tQBEnPoL.mjs → formatBytes-CZv_XyCY.mjs} +1 -1
  76. package/dist/client/{formatBytes-tQBEnPoL.mjs.map → formatBytes-CZv_XyCY.mjs.map} +1 -1
  77. package/dist/client/{helpers--JWXi40U.mjs → helpers-1PpYf-fC.mjs} +1 -1
  78. package/dist/client/{helpers--JWXi40U.mjs.map → helpers-1PpYf-fC.mjs.map} +1 -1
  79. package/dist/client/hooks-dSArr2Ca.mjs +2 -0
  80. package/dist/client/images-CKqIXUq52.mjs +1873 -0
  81. package/dist/client/images-CKqIXUq52.mjs.map +1 -0
  82. package/dist/client/{images-tYfyOkX8.mjs → images-C_dX7nY6.mjs} +3 -3
  83. package/dist/client/{images-tYfyOkX8.mjs.map → images-C_dX7nY6.mjs.map} +1 -1
  84. package/dist/client/{images-CTLCY-yY.mjs → images-CenluYV8.mjs} +2 -2
  85. package/dist/client/{images-CTLCY-yY.mjs.map → images-CenluYV8.mjs.map} +1 -1
  86. package/dist/client/{images-DM9I8G0p.mjs → images-NBf2bV43.mjs} +2 -2
  87. package/dist/client/{images-DM9I8G0p.mjs.map → images-NBf2bV43.mjs.map} +1 -1
  88. package/dist/client/index.js +428 -477
  89. package/dist/client/index.js.map +1 -1
  90. package/dist/client/{md-BivyCkGC.mjs → md-CYTrL5dq.mjs} +58 -22
  91. package/dist/client/{md-BivyCkGC.mjs.map → md-CYTrL5dq.mjs.map} +1 -1
  92. package/dist/client/{network-rYLHyf15.mjs → network-DuZm76BZ.mjs} +2 -2
  93. package/dist/client/{network-rYLHyf15.mjs.map → network-DuZm76BZ.mjs.map} +1 -1
  94. package/dist/client/objects-BJM6YeuF.mjs +5708 -0
  95. package/dist/client/objects-BJM6YeuF.mjs.map +1 -0
  96. package/dist/client/objects-gxSjvbvF.mjs +101 -0
  97. package/dist/client/objects-gxSjvbvF.mjs.map +1 -0
  98. package/dist/client/objects-o2Cj_ndZ.mjs +8 -0
  99. package/dist/client/objects-o2Cj_ndZ.mjs.map +1 -0
  100. package/dist/client/{pca-COmKvp3J.mjs → pca-Bl8NmoVZ.mjs} +2 -2
  101. package/dist/client/{pca-COmKvp3J.mjs.map → pca-Bl8NmoVZ.mjs.map} +1 -1
  102. package/dist/client/pca-RSiWpJs9.mjs +182 -0
  103. package/dist/client/pca-RSiWpJs9.mjs.map +1 -0
  104. package/dist/client/projects-CgclWI16.mjs +105 -0
  105. package/dist/client/projects-CgclWI16.mjs.map +1 -0
  106. package/dist/client/{projects-DI_L4oDw.mjs → projects-D2iewAzu.mjs} +2 -2
  107. package/dist/client/{projects-DI_L4oDw.mjs.map → projects-D2iewAzu.mjs.map} +1 -1
  108. package/dist/client/{projects-Dl5XkXUP.mjs → projects-pe2_dCnV.mjs} +3 -3
  109. package/dist/client/{projects-Dl5XkXUP.mjs.map → projects-pe2_dCnV.mjs.map} +1 -1
  110. package/dist/client/{projects-HoQ0gE5Y.mjs → projects-yiK0HGSA.mjs} +2 -2
  111. package/dist/client/{projects-HoQ0gE5Y.mjs.map → projects-yiK0HGSA.mjs.map} +1 -1
  112. package/dist/client/{securitygroups-BjkmHk2J.mjs → securitygroups-DahZkVYQ.mjs} +139 -140
  113. package/dist/client/{securitygroups-BjkmHk2J.mjs.map → securitygroups-DahZkVYQ.mjs.map} +1 -1
  114. package/dist/client/{trpcClient-BxguzNYF.mjs → trpcClient-BzPUgiM2.mjs} +1 -1
  115. package/dist/client/{trpcClient-BxguzNYF.mjs.map → trpcClient-BzPUgiM2.mjs.map} +1 -1
  116. package/dist/client/{useErrorTranslation-TZVwIAzq.mjs → useErrorTranslation-Dc0eE8Zt.mjs} +1 -1
  117. package/dist/client/{useErrorTranslation-TZVwIAzq.mjs.map → useErrorTranslation-Dc0eE8Zt.mjs.map} +1 -1
  118. package/dist/client/useListWithFiltering-DaYcu5AB.mjs +157 -0
  119. package/dist/client/useListWithFiltering-DaYcu5AB.mjs.map +1 -0
  120. package/dist/client/{useModal-DxxlilRm.mjs → useModal-DCs1OJh7.mjs} +1 -1
  121. package/dist/client/{useModal-DxxlilRm.mjs.map → useModal-DCs1OJh7.mjs.map} +1 -1
  122. package/dist/client/{useProjectId-OQv2KBbG.mjs → useProjectId-DBc5lpoU.mjs} +1 -1
  123. package/dist/client/{useProjectId-OQv2KBbG.mjs.map → useProjectId-DBc5lpoU.mjs.map} +1 -1
  124. package/dist/server/index.js +1285 -435
  125. package/package.json +5 -4
  126. package/dist/client/DeleteFlavorModal-BusYn32r.mjs +0 -629
  127. package/dist/client/DeleteFlavorModal-BusYn32r.mjs.map +0 -1
  128. package/dist/client/ImageToastNotifications-BG9LPnXf.mjs +0 -1267
  129. package/dist/client/ImageToastNotifications-BG9LPnXf.mjs.map +0 -1
  130. package/dist/client/ListToolbar-BojRTNbo.mjs +0 -129
  131. package/dist/client/ListToolbar-BojRTNbo.mjs.map +0 -1
  132. package/dist/client/_flavorId-BRonXvCo.mjs +0 -188
  133. package/dist/client/_flavorId-BRonXvCo.mjs.map +0 -1
  134. package/dist/client/_flavorId-BoNcxYmF.mjs.map +0 -1
  135. package/dist/client/_imageId-BL0I5_pv.mjs +0 -527
  136. package/dist/client/_imageId-BL0I5_pv.mjs.map +0 -1
  137. package/dist/client/_pcaId-CbBhBrX1.mjs +0 -466
  138. package/dist/client/_pcaId-CbBhBrX1.mjs.map +0 -1
  139. package/dist/client/_projectId-5NiasyXm.mjs +0 -26
  140. package/dist/client/_projectId-5NiasyXm.mjs.map +0 -1
  141. package/dist/client/_projectId-BwLMEMGC.mjs.map +0 -1
  142. package/dist/client/_projectId-D35MN1kY.mjs +0 -316
  143. package/dist/client/_projectId-D35MN1kY.mjs.map +0 -1
  144. package/dist/client/about-DLn1ShhF.mjs +0 -92
  145. package/dist/client/aurora-CRcxVUCo.mjs +0 -19
  146. package/dist/client/build-BJDfnAyi.mjs.map +0 -1
  147. package/dist/client/constants-B-P2r5F1.mjs +0 -128
  148. package/dist/client/constants-B-P2r5F1.mjs.map +0 -1
  149. package/dist/client/containers-BjWqjNOx.mjs.map +0 -1
  150. package/dist/client/containers-DsRWc1L5.mjs +0 -7
  151. package/dist/client/containers-DsRWc1L5.mjs.map +0 -1
  152. package/dist/client/containers-J7WFA18U.mjs +0 -3120
  153. package/dist/client/containers-J7WFA18U.mjs.map +0 -1
  154. package/dist/client/flavors-qvgPSI7J.mjs +0 -613
  155. package/dist/client/flavors-qvgPSI7J.mjs.map +0 -1
  156. package/dist/client/hooks-DEjb9d1F.mjs +0 -2
  157. package/dist/client/images-CSFfefAu.mjs +0 -1901
  158. package/dist/client/images-CSFfefAu.mjs.map +0 -1
  159. package/dist/client/objects-BciXwZ00.mjs +0 -86
  160. package/dist/client/objects-BciXwZ00.mjs.map +0 -1
  161. package/dist/client/objects-Cdew99tK.mjs +0 -8
  162. package/dist/client/objects-Cdew99tK.mjs.map +0 -1
  163. package/dist/client/objects-DaElrban.mjs +0 -5340
  164. package/dist/client/objects-DaElrban.mjs.map +0 -1
  165. package/dist/client/overview-BMhjFMIV.mjs +0 -15
  166. package/dist/client/overview-BMhjFMIV.mjs.map +0 -1
  167. package/dist/client/overview-BYIRj7_X.mjs +0 -15
  168. package/dist/client/overview-BYIRj7_X.mjs.map +0 -1
  169. package/dist/client/overview-DRCKNBH2.mjs +0 -15
  170. package/dist/client/overview-DRCKNBH2.mjs.map +0 -1
  171. package/dist/client/overview-urYLOVQE.mjs +0 -173
  172. package/dist/client/overview-urYLOVQE.mjs.map +0 -1
  173. package/dist/client/pca-oc7J0_Xd.mjs +0 -167
  174. package/dist/client/pca-oc7J0_Xd.mjs.map +0 -1
  175. package/dist/client/projects-BUabCzvw.mjs +0 -95
  176. package/dist/client/projects-BUabCzvw.mjs.map +0 -1
  177. package/dist/client/useListWithFiltering-CbhHJO4V.mjs +0 -32
  178. package/dist/client/useListWithFiltering-CbhHJO4V.mjs.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"images-CSFfefAu.mjs","names":["useModal","useParams","useNavigate","Checkbox","DataGridCell","DataGridRow","Modal","PopupMenu","PopupMenuItem","PopupMenuOptions","Spinner","SizeDisplay","IMAGE_STATUSES","IMAGE_VISIBILITY","MEMBER_STATUSES","trpcReact","getImageAccessStatusUpdatedToast","getImageAccessStatusErrorToast","ImageTableRow","image","isSelected","isPending","isAccepted","permissions","onEditDetails","onEditMetadata","onDelete","onSelect","onActivationStatusChange","onManageAccess","onUpdateVisibility","setToastData","uploadId","uploadProgressPercent","onMemberStatusChanged","showSelectColumn","useLingui","id","name","status","visibility","size","disk_format","created_at","owner","imageName","t","projectId","from","navigate","utils","useUtils","updateMemberMutation","compute","updateImageMember","useMutation","onSuccess","listImagesWithPagination","invalidate","listSharedImagesByMemberStatus","handleMemberStatusChange","newStatus","mutateAsync","project_id","imageId","memberId","onDismiss","error","errorMessage","message","isImageOwner","isExternalImage","isMutating","acceptModalOpen","toggleAcceptModal","rejectModalOpen","toggleRejectModal","data-testid","onClick","to","params","e","stopPropagation","checked","onChange","protected","Date","toLocaleDateString","variant","label","canUpdateMember","canUpdate","DEACTIVATED","SHARED","canCreateMember","canDeleteMember","PRIVATE","canDelete","title","open","onCancel","confirmButtonLabel","onConfirm","ACCEPTED","p","strong","REJECTED","TRPCError","applyImageQueryParams","queryParams","input","sort_key","sort_dir","sort","limit","marker","status","visibility","owner","protected","isProtected","container_format","disk_format","size_min","size_max","min_ram","min_disk","tag","os_type","os_hidden","member_status","created_at","updated_at","append","sortKey","sortDir","undefined","toString","validateGlanceService","glance","code","message","validateUploadInput","imageId","fileSize","fileStream","trim","UUID_RE","test","pipe","Number","isFinite","validatedImageId","validatedFile","validatedFileSize","mapErrorResponseToTRPCError","error","context","operation","memberId","additionalInfo","baseMessage","entityInfo","memberInfo","extraInfo","statusCode","ImageErrorHandlers","upload","response","contentType","member","create","statusText","update","delete","list","get","handleZodParsingError","cause","wrapError","baseErrorMessage","withErrorHandling","operationName","formatBulkOperationError","Error","parseMultiValue","param","startsWith","replace","split","validateBulkImageIds","imageIds","length","chunkArray","array","size","chunks","i","push","slice","processBulkOperation","items","processor","options","chunkSize","delayBetweenChunks","results","successful","failed","chunk","chunkPromises","map","item","id","chunkResults","Promise","allSettled","forEach","result","value","resolve","setTimeout","promises","settledResults","diskFormatCompatibility","qcow2","raw","vmdk","vhd","vhdx","vdi","iso","ami","aki","ari","ploop","defaultContainerFormat","getCompatibleContainerFormats","diskFormat","getDefaultContainerFormat","isValidFormatCombination","containerFormat","compatible","includes","React","useState","useMemo","Modal","Form","FormRow","FormSection","TextInput","Select","SelectOption","Checkbox","Button","Spinner","Stack","Pill","Message","getCompatibleContainerFormats","getDefaultContainerFormat","isValidFormatCombination","DISK_FORMATS","IMAGE_VISIBILITY","cn","defaultImageValues","name","tags","visibility","PRIVATE","disk_format","undefined","container_format","protected","min_disk","min_ram","CreateImageModal","isOpen","onClose","onCreate","isLoading","isUploadPending","uploadProgressPercent","useLingui","properties","setProperties","tagsInput","setTagsInput","selectedFile","setSelectedFile","errors","setErrors","isDragging","setIsDragging","generalError","setGeneralError","isFormValid","trim","compatibleContainerFormats","validExtensions","supportedFileFormats","join","handleInputChange","e","value","type","checked","target","prev","newErrors","handleBlur","t","handleSelectChange","newDiskFormat","recommended","handleNumericChange","numValue","parseInt","isNaN","handleNumericBlur","validateAndSetFile","file","fileName","toLowerCase","isValidFile","some","ext","endsWith","handleFileChange","files","handleDragOver","preventDefault","stopPropagation","handleDragLeave","handleDrop","droppedFiles","dataTransfer","length","handleTagsInputChange","handleAddTag","trimmedTag","includes","handleTagKeyPress","key","handleRemoveTag","tagToRemove","filter","tag","validateForm","Object","keys","handleSubmit","imageData","handleClose","error","errorMessage","Error","message","open","onCancel","size","title","onConfirm","confirmButtonLabel","cancelButtonLabel","disableConfirmButton","closeable","closeOnEsc","distribution","alignment","className","variant","div","style","width","label","htmlFor","span","onDragOver","onDragLeave","onDrop","svg","aria-hidden","xmlns","fill","viewBox","path","stroke","strokeLinecap","strokeLinejoin","strokeWidth","d","p","input","id","onChange","accept","disabled","fillRule","clipRule","button","onClick","onBlur","required","errortext","placeholder","gap","direction","onKeyDown","helptext","wrap","map","pillKey","pillValue","loading","PUBLIC","SHARED","COMMUNITY","QCOW2","RAW","VMDK","VHD","VHDX","VDI","AMI","ARI","AKI","ISO","PLOOP","format","toUpperCase","String","React","Button","ButtonRow","Message","Modal","ModalFooter","Spinner","Stack","DeleteImagesModal","deletableImages","protectedImages","isOpen","isLoading","onClose","onDelete","useLingui","deletableCount","length","protectedCount","handleDelete","e","preventDefault","onCancel","size","title","t","open","modalFooter","className","variant","onClick","disabled","data-testid","distribution","alignment","div","text","h3","ul","map","imageId","li","span","React","Modal","Spinner","Stack","DeactivateImagesModal","activeImages","deactivatedImages","isOpen","isLoading","onClose","onDeactivate","useLingui","activeCount","length","deactivatedCount","handleDeactivate","e","preventDefault","onCancel","size","title","t","open","onConfirm","confirmButtonLabel","cancelButtonLabel","disableConfirmButton","distribution","alignment","variant","div","className","p","strong","h3","ul","map","imageId","li","span","React","Modal","Spinner","Stack","ActivateImagesModal","deactivatedImages","activeImages","isOpen","isLoading","onClose","onActivate","useLingui","deactivatedCount","length","activeCount","handleActivate","e","preventDefault","onCancel","size","title","t","open","onConfirm","confirmButtonLabel","cancelButtonLabel","disableConfirmButton","distribution","alignment","variant","div","className","p","strong","h3","ul","map","imageId","li","span","React","useState","useProjectId","Modal","Message","trpcReact","ImageMembersTable","ManageImageAccessModal","isOpen","onClose","image","permissions","canCreateMember","canDeleteMember","useLingui","projectId","message","setMessage","isAddingMember","setIsAddingMember","data","imageMembers","isLoading","isMembersLoading","compute","listImageMembers","useQuery","project_id","imageId","id","enabled","handleClose","imageName","name","onCancel","title","t","open","size","div","onDismiss","text","variant","type","className","canAdd","canRemove","useState","useProjectId","Checkbox","ContentHeading","DataGrid","DataGridCell","DataGridHeadCell","DataGridRow","Pagination","Spinner","Stack","Toast","trpcClient","trpcReact","TRPCClientError","EditImageDetailsModal","EditImageMetadataModal","ImageTableRow","DeleteImageModal","DeactivateImageModal","ActivateImageModal","CreateImageModal","DeleteImagesModal","DeactivateImagesModal","ActivateImagesModal","getImageUpdatedToast","getImageUpdateErrorToast","getImageCreatedToast","getImageDeletedToast","getImageDeleteErrorToast","getImageActivatedToast","getImageDeactivatedToast","getImageActivationErrorToast","getImageDeactivationErrorToast","getBulkDeleteSuccessToast","getBulkDeleteErrorToast","getBulkDeletePartialToast","getBulkActivateSuccessToast","getBulkActivateErrorToast","getBulkActivatePartialToast","getBulkDeactivateSuccessToast","getBulkDeactivateErrorToast","getBulkDeactivatePartialToast","getImageCreateErrorToast","getImageFileUploadErrorToast","getImageVisibilityUpdatedToast","getImageVisibilityUpdateErrorToast","ManageImageAccessModal","IMAGE_STATUSES","ImageListView","images","suggestedImages","acceptedImages","permissions","isFetching","currentPage","totalPages","onPageChange","children","selectedImages","setSelectedImages","deleteAllModalOpen","setDeleteAllModalOpen","deactivateAllModalOpen","setDeactivateAllModalOpen","activateAllModalOpen","setActivateAllModalOpen","createModalOpen","setCreateModalOpen","deletableImages","protectedImages","activeImages","deactivatedImages","onImageUpdated","onImageDeleted","onMemberStatusChanged","hasAnyBulkAction","projectId","toastData","setToastData","editDetailsModalOpen","setEditDetailsModalOpen","editMetadataModalOpen","setEditMetadataModalOpen","deleteModalOpen","setDeleteModalOpen","deactivateModalOpen","setDeactivateModalOpen","activateModalOpen","setActivateModalOpen","manageAccessModalOpen","setManageAccessModalOpen","selectedImage","setSelectedImage","isCreateInProgress","setCreateInProgress","uploadId","setUploadId","isUploadPending","setIsUploadPending","utils","useUtils","deleteImageMutation","compute","deleteImage","useMutation","onSuccess","listImagesWithPagination","invalidate","deactivateImageMutation","deactivateImage","getImageById","reactivateImageMutation","reactivateImage","deleteImagesMutation","deleteImages","activateImagesMutation","activateImages","deactivateImagesMutation","deactivateImages","updateImageMutation","updateImage","updatedImage","setData","project_id","imageId","id","createImageMutation","createImage","updateImageVisibilityMutation","updateImageVisibility","data","watchUploadProgress","useSubscription","enabled","isLoading","isPending","handleToastDismiss","handleUpdateImageVisibility","newVisibility","imageName","mutateAsync","visibility","onDismiss","error","errorMessage","message","t","convertToJsonPatchOperations","updatedProperties","originalImage","operations","Object","entries","forEach","key","value","path","undefined","push","op","propertyExists","handleSaveEdit","name","handleCreate","imageData","file","createdImage","uploadImage","mutate","context","headers","String","size","handleDelete","deletedImage","handleActivationStatusChange","status","DEACTIVATED","handleActivateSingle","image","handleDeactivateSingle","openEditDetailsModal","openEditMetadataModal","openDeleteModal","openManageAccessModal","closeEditDetailsModal","closeEditMetadataModal","closeDeleteModal","closeDeactivateModal","closeActivateModal","closeManageAccessModal","handleBulkDelete","imageIds","result","successCount","successful","length","failedCount","failed","totalCount","console","log","handleBulkActivate","handleBulkDeactivate","div","data-testid","colSpan","distribution","alignment","variant","className","direction","gap","span","columns","minContentColumns","checked","currentPageIds","map","every","includes","onChange","allSelected","filter","Set","isSelected","find","isAccepted","onEditDetails","onEditMetadata","onDelete","onManageAccess","showSelectColumn","onSelect","isImageSelected","onActivationStatusChange","onUpdateVisibility","uploadProgressPercent","percent","pages","onPressPrevious","Math","max","onPressNext","min","onSelectChange","page","p","isOpen","onClose","onSave","isDisabled","protected","canDelete","onDeactivate","onActivate","onCreate","parseFiltersFromUrl","searchParams","filters","status","values","startsWith","replace","split","forEach","value","push","name","visibility","disk_format","container_format","protected","buildFilterParams","selectedFilters","filterDefinitions","params","length","filterGroups","filter","sf","inactive","reduce","acc","Object","entries","filterName","filterDef","find","f","supportsMultiValue","join","applyFilterSelection","current","selected","alreadySelected","some","supportsMulti","buildUrlSearchParams","baseParams","newParams","search","sortBy","sortDirection","memberStatus","undefined","TRPCClientError","emptyResult","images","first","undefined","next","schema","listError","createImagesPromise","client","project","sortBy","sortDirection","searchTerm","filters","member_status","compute","listSharedImagesByMemberStatus","query","project_id","memberStatus","name","status","disk_format","container_format","protected","sort","then","catch","err","data","code","message","listImagesWithSearch","res","createPermissionsPromise","canUser","permission","canCreate","canDelete","canUpdate","canCreateMember","canDeleteMember","canUpdateMember","use","Suspense","useState","startTransition","useEffect","useRef","useCallback","useNavigate","useSearch","Button","Stack","Spinner","PopupMenu","PopupMenuItem","PopupMenuToggle","PopupMenuOptions","DataGridToolbar","SearchInput","Checkbox","TabNavigation","TabNavigationItem","SortInput","SelectedFilters","FiltersInput","ImageListView","CONTAINER_FORMATS","DISK_FORMATS","IMAGE_STATUSES","IMAGE_VISIBILITY","parseFiltersFromUrl","buildFilterParams","buildUrlSearchParams","applyFilterSelection","createImagesPromise","createPermissionsPromise","PAGE_SIZE","ImagesContent","imagesPromise","imageOverrides","deletedImageIds","permissionsPromise","searchTerm","setSearchTerm","sortSettings","handleSortChange","filterSettings","handleFilterChange","selectedImages","setSelectedImages","createModalOpen","setCreateModalOpen","deleteAllModalOpen","setDeleteAllModalOpen","deactivateAllModalOpen","setDeactivateAllModalOpen","activateAllModalOpen","setActivateAllModalOpen","memberStatusView","setMemberStatusView","isFetching","currentPage","onPageChange","onImageUpdated","onImageDeleted","onMemberStatusChanged","useLingui","imagesData","permissions","localSearchTerm","setLocalSearchTerm","debounceTimer","undefined","clearTimeout","current","listError","p","images","filter","img","has","id","map","get","totalPages","Math","max","ceil","length","safePage","min","paginatedImages","slice","activeFilterSettings","filters","f","filterName","selectedFilters","name","displayedImageIds","Set","image","validSelectedImages","imageId","deletableImages","find","protected","protectedImages","activeImages","status","ACTIVE","deactivatedImages","DEACTIVATED","isDeleteAllDisabled","canDelete","includes","every","isDeactivateAllDisabled","canUpdate","isActivateAllDisabled","memberStatusTabs","items","label","t","value","activeItem","onActiveItemChange","distribution","alignment","gap","item","options","sortBy","sortDirection","onSortByChange","v","onSortDirectionChange","dir","canCreate","onClick","variant","direction","onChange","selected","newSelected","placeholder","data-testid","onInput","e","currentTarget","window","setTimeout","onSearch","onClear","onDelete","filterToRemove","checked","indeterminate","pageIds","allSelected","as","size","icon","disabled","suggestedImages","acceptedImages","hasAnyBulkAction","Images","client","project","navigate","searchParams","strict","setSortSettings","setFilterSettings","displayName","values","Object","supportsMultiValue","search","page","memberStatus","setIsFetching","setImageOverrides","Map","setDeletedImageIds","setImagesPromise","Promise","handleImageUpdated","updatedImage","prev","set","handleImageDeleted","imageIds","next","Array","isArray","forEach","add","handleMemberStatusChanged","urlMemberStatus","urlMemberStatusFilter","effectiveFilters","newPromise","member_status","catch","finally","urlFilters","urlSortBy","urlSortDirection","urlSearchTerm","visibility","disk_format","container_format","newSortSettings","settings","toString","replace","newFilterSettings","handleSearchChange","term","searchValue","handleMemberStatusChange","view","handlePageChange","div","className","fallback","useLingui","Images","ContentHeader","Route","RouteComponent","t","projectId","useParams","trpcClient","useRouteContext","Error","component"],"sources":["../../src/client/routes/_auth/projects/$projectId/compute/-components/Images/-components/ImageTableRow.tsx","../../src/server/Compute/helpers/imageHelpers.ts","../../src/client/routes/_auth/projects/$projectId/compute/-components/Images/-components/CreateImageModal.tsx","../../src/client/routes/_auth/projects/$projectId/compute/-components/Images/-components/DeleteImagesModal.tsx","../../src/client/routes/_auth/projects/$projectId/compute/-components/Images/-components/DeactivateImagesModal.tsx","../../src/client/routes/_auth/projects/$projectId/compute/-components/Images/-components/ActivateImagesModal.tsx","../../src/client/routes/_auth/projects/$projectId/compute/-components/Images/-components/ManageImageAccessModal.tsx","../../src/client/routes/_auth/projects/$projectId/compute/-components/Images/-components/ImageListView.tsx","../../src/client/routes/_auth/projects/$projectId/compute/-components/Images/urlHelpers.ts","../../src/client/routes/_auth/projects/$projectId/compute/-components/Images/apiHelpers.ts","../../src/client/routes/_auth/projects/$projectId/compute/-components/Images/List.tsx","../../src/client/routes/_auth/projects/$projectId/compute/images/index.tsx?tsr-split=component"],"sourcesContent":["import { useModal } from \"@/client/utils/useModal\"\nimport { useParams, useNavigate } from \"@tanstack/react-router\"\nimport {\n Checkbox,\n DataGridCell,\n DataGridRow,\n Modal,\n PopupMenu,\n PopupMenuItem,\n PopupMenuOptions,\n Spinner,\n ToastProps,\n} from \"@cloudoperators/juno-ui-components\"\nimport { useLingui } from \"@lingui/react/macro\"\nimport { GlanceImage, ImageVisibility, MemberStatus } from \"@/server/Compute/types/image\"\nimport { SizeDisplay } from \"./SizeDisplay\"\nimport { IMAGE_STATUSES, IMAGE_VISIBILITY, MEMBER_STATUSES } from \"../../../-constants/filters\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { TRPCClientError } from \"@trpc/client\"\nimport { InferrableClientTypes } from \"@trpc/server/unstable-core-do-not-import\"\nimport { getImageAccessStatusUpdatedToast, getImageAccessStatusErrorToast } from \"./ImageToastNotifications\"\n\ninterface ImageTableRowProps {\n image: GlanceImage\n isPending: boolean\n isAccepted: boolean\n isSelected: boolean\n onEditDetails: (image: GlanceImage) => void\n onEditMetadata: (image: GlanceImage) => void\n onDelete: (image: GlanceImage) => void\n onSelect: (image: GlanceImage) => void\n onActivationStatusChange: (image: GlanceImage) => void\n onManageAccess: (image: GlanceImage) => void\n onUpdateVisibility: (imageId: string, newVisibility: ImageVisibility, imageName: string) => Promise<void>\n setToastData: (toast: ToastProps | null) => void\n permissions: {\n canCreate: boolean\n canDelete: boolean\n canUpdate: boolean\n canCreateMember: boolean\n canDeleteMember: boolean\n canUpdateMember: boolean\n }\n uploadId?: string | null\n uploadProgressPercent?: number\n onMemberStatusChanged?: () => void\n showSelectColumn?: boolean\n}\n\nexport function ImageTableRow({\n image,\n isSelected,\n isPending,\n isAccepted,\n permissions,\n onEditDetails,\n onEditMetadata,\n onDelete,\n onSelect,\n onActivationStatusChange,\n onManageAccess,\n onUpdateVisibility,\n setToastData,\n uploadId,\n uploadProgressPercent,\n onMemberStatusChanged,\n showSelectColumn = false,\n}: ImageTableRowProps) {\n const { t } = useLingui()\n const { id, name, status, visibility, size, disk_format, created_at, owner } = image\n const imageName = name || t`Unnamed`\n\n const { projectId } = useParams({\n from: \"/_auth/projects/$projectId/compute/images/\",\n })\n const navigate = useNavigate()\n\n const utils = trpcReact.useUtils()\n const updateMemberMutation = trpcReact.compute.updateImageMember.useMutation({\n onSuccess: () => {\n utils.compute.listImagesWithPagination.invalidate()\n utils.compute.listSharedImagesByMemberStatus.invalidate()\n },\n })\n\n const handleMemberStatusChange = async (newStatus: MemberStatus) => {\n try {\n await updateMemberMutation.mutateAsync({\n project_id: projectId,\n imageId: id,\n memberId: projectId,\n status: newStatus,\n })\n setToastData(getImageAccessStatusUpdatedToast(newStatus, { onDismiss: () => setToastData(null) }))\n onMemberStatusChanged?.()\n } catch (error) {\n const errorMessage = (error as TRPCClientError<InferrableClientTypes>)?.message\n setToastData(getImageAccessStatusErrorToast(errorMessage, { onDismiss: () => setToastData(null) }))\n }\n }\n\n const isImageOwner = projectId === owner\n const isExternalImage = isPending || isAccepted\n const isMutating = updateMemberMutation.isPending\n\n const [acceptModalOpen, toggleAcceptModal] = useModal()\n const [rejectModalOpen, toggleRejectModal] = useModal()\n\n return (\n <DataGridRow\n key={id}\n data-testid={`image-row-${id}`}\n onClick={() =>\n navigate({\n to: \"/projects/$projectId/compute/images/$imageId\",\n params: { projectId, imageId: id },\n })\n }\n >\n {showSelectColumn && (\n <DataGridCell onClick={(e) => e.stopPropagation()}>\n <Checkbox checked={isSelected} onChange={() => onSelect(image)} />\n </DataGridCell>\n )}\n\n <DataGridCell>{status}</DataGridCell>\n <DataGridCell>{imageName}</DataGridCell>\n <DataGridCell>{visibility}</DataGridCell>\n <DataGridCell>{image.protected ? t`Yes` : t`No`}</DataGridCell>\n <DataGridCell>\n {uploadId && uploadId === id ? `${uploadProgressPercent}%` : <SizeDisplay size={size} />}\n </DataGridCell>\n <DataGridCell>{disk_format || t`N/A`}</DataGridCell>\n <DataGridCell>{created_at ? new Date(created_at).toLocaleDateString() : t`N/A`}</DataGridCell>\n\n <DataGridCell onClick={(e) => e.stopPropagation()}>\n {isMutating ? (\n <Spinner variant=\"primary\" size=\"small\" />\n ) : (\n <PopupMenu>\n <PopupMenuOptions>\n <PopupMenuItem\n label={t`Show Details`}\n onClick={() =>\n navigate({\n to: \"/projects/$projectId/compute/images/$imageId\",\n params: { projectId, imageId: id },\n })\n }\n />\n\n {isExternalImage && permissions.canUpdateMember && (\n <>\n {isPending && <PopupMenuItem label={t`Accept`} onClick={toggleAcceptModal} />}\n <PopupMenuItem label={t`Reject`} onClick={toggleRejectModal} />\n </>\n )}\n\n {/* Own image: full actions */}\n {!isExternalImage && permissions.canUpdate && (\n <>\n <PopupMenuItem label={t`Edit Details`} onClick={() => onEditDetails(image)} />\n <PopupMenuItem label={t`Edit Metadata`} onClick={() => onEditMetadata(image)} />\n <PopupMenuItem\n label={image.status === IMAGE_STATUSES.DEACTIVATED ? t`Activate` : t`Deactivate`}\n onClick={() => onActivationStatusChange(image)}\n />\n {image.visibility === IMAGE_VISIBILITY.SHARED &&\n isImageOwner &&\n (permissions.canCreateMember || permissions.canDeleteMember) && (\n <PopupMenuItem label={t`Manage Access`} onClick={() => onManageAccess(image)} />\n )}\n {image.visibility === IMAGE_VISIBILITY.PRIVATE && (\n <PopupMenuItem\n label={t`Set to \"Shared\"`}\n onClick={() => onUpdateVisibility(image.id, IMAGE_VISIBILITY.SHARED, imageName)}\n />\n )}\n </>\n )}\n {!isExternalImage && permissions.canDelete && !image.protected && (\n <PopupMenuItem label={t`Delete`} onClick={() => onDelete(image)} />\n )}\n </PopupMenuOptions>\n </PopupMenu>\n )}\n\n {acceptModalOpen && (\n <Modal\n title={t`Accept Shared Image`}\n open={acceptModalOpen}\n onCancel={toggleAcceptModal}\n confirmButtonLabel={t`Accept`}\n onConfirm={() => {\n toggleAcceptModal()\n handleMemberStatusChange(MEMBER_STATUSES.ACCEPTED)\n }}\n >\n <p>\n {t`Accept access to image`} <strong>{imageName}</strong>? {t`It will appear in your image list.`}\n </p>\n </Modal>\n )}\n\n {rejectModalOpen && (\n <Modal\n title={t`Reject Shared Image`}\n open={rejectModalOpen}\n onCancel={toggleRejectModal}\n confirmButtonLabel={t`Reject`}\n onConfirm={() => {\n toggleRejectModal()\n handleMemberStatusChange(MEMBER_STATUSES.REJECTED)\n }}\n >\n <p>\n {t`Reject access to image`} <strong>{imageName}</strong>? {t`It will be removed from your image list.`}\n </p>\n </Modal>\n )}\n </DataGridCell>\n </DataGridRow>\n )\n}\n","import { TRPCError } from \"@trpc/server\"\nimport { ZodError } from \"zod\"\nimport { BulkOperationResult, ListImagesInput } from \"../types/image\"\nimport { SignalOpenstackApiError } from \"@cobaltcore-dev/signal-openstack\"\n\n/**\n * Applies sorting and filtering parameters to URLSearchParams for OpenStack Glance API calls\n * @param queryParams - URLSearchParams object to modify\n * @param input - Input object containing sorting and filtering parameters\n */\nexport function applyImageQueryParams(queryParams: URLSearchParams, input: Omit<ListImagesInput, \"project_id\">): void {\n const {\n sort_key,\n sort_dir,\n sort,\n limit,\n marker,\n status,\n visibility,\n owner,\n protected: isProtected,\n container_format,\n disk_format,\n size_min,\n size_max,\n min_ram,\n min_disk,\n tag,\n os_type,\n os_hidden,\n member_status,\n created_at,\n updated_at,\n } = input\n\n // Sorting parameters - always use the new sort syntax\n if (sort) {\n queryParams.append(\"sort\", sort)\n } else {\n // Construct sort parameter from sort_key and sort_dir (using defaults if not provided)\n const sortKey = sort_key || \"created_at\"\n const sortDir = sort_dir || \"desc\"\n queryParams.append(\"sort\", `${sortKey}:${sortDir}`)\n }\n\n // Pagination parameters\n if (limit !== undefined) {\n queryParams.append(\"limit\", limit.toString())\n }\n if (marker) {\n queryParams.append(\"marker\", marker)\n }\n\n // Basic filtering parameters\n // Note: `name` is intentionally excluded here — OpenStack Glance API does not support\n // wildcard or substring name filtering. Name-based filtering is applied server-side\n // after fetching results (see listImagesWithPagination procedure).\n if (status) {\n queryParams.append(\"status\", status)\n }\n // Only append visibility if it's not \"all\" (which means fetch all visibilities)\n if (visibility && visibility !== \"all\") {\n queryParams.append(\"visibility\", visibility)\n }\n if (owner) {\n queryParams.append(\"owner\", owner)\n }\n if (member_status) {\n queryParams.append(\"member_status\", member_status)\n }\n\n // Boolean parameters\n if (isProtected !== undefined) {\n queryParams.append(\"protected\", isProtected.toString())\n }\n if (os_hidden !== undefined) {\n queryParams.append(\"os_hidden\", os_hidden.toString())\n }\n\n // Format parameters\n if (container_format) {\n queryParams.append(\"container_format\", container_format)\n }\n if (disk_format) {\n queryParams.append(\"disk_format\", disk_format)\n }\n\n // Numeric parameters\n if (min_ram !== undefined) {\n queryParams.append(\"min_ram\", min_ram.toString())\n }\n if (min_disk !== undefined) {\n queryParams.append(\"min_disk\", min_disk.toString())\n }\n if (size_min !== undefined) {\n queryParams.append(\"size_min\", size_min.toString())\n }\n if (size_max !== undefined) {\n queryParams.append(\"size_max\", size_max.toString())\n }\n\n // Tag and OS filtering\n if (tag) {\n queryParams.append(\"tag\", tag)\n }\n if (os_type) {\n queryParams.append(\"os_type\", os_type)\n }\n\n // Time-based filtering with comparison operators\n if (created_at) {\n queryParams.append(\"created_at\", created_at)\n }\n if (updated_at) {\n queryParams.append(\"updated_at\", updated_at)\n }\n}\n\n/**\n * Validates that the OpenStack Glance service is available\n * @param glance - The OpenStack Glance service instance\n * @throws TRPCError if service is not available\n */\nexport function validateGlanceService(glance: unknown): asserts glance is NonNullable<typeof glance> {\n if (!glance) {\n throw new TRPCError({\n code: \"INTERNAL_SERVER_ERROR\",\n message: \"Failed to initialize OpenStack Glance service\",\n })\n }\n}\n\n/**\n * Validates streaming upload inputs with file size before uploading to OpenStack Glance\n *\n * @param imageId - OpenStack image ID (UUID string)\n * @param fileSize - File size in bytes from Content-Length header (0 if unknown)\n * @param fileStream - File data as Node.js ReadableStream\n *\n * @returns { validatedImageId: string; validatedFileSize: number; validatedFile: NodeJS.ReadableStream }\n *\n * @throws TRPCError(BAD_REQUEST) if imageId/fileStream invalid or fileSize negative\n * @throws TRPCError(INTERNAL_SERVER_ERROR) if fileSize not a finite number\n */\nexport function validateUploadInput(\n imageId: unknown,\n fileSize: unknown,\n fileStream: unknown\n): { validatedImageId: string; validatedFile: NodeJS.ReadableStream; validatedFileSize: number } {\n // Validate imageId\n if (!imageId) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"imageId is required\",\n })\n }\n\n if (typeof imageId !== \"string\") {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"imageId must be a string\",\n })\n }\n\n if (imageId.trim() === \"\") {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"imageId cannot be empty\",\n })\n }\n\n const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i\n if (!UUID_RE.test(imageId.trim())) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"imageId must be a valid UUID\",\n })\n }\n\n // Validate fileStream\n if (!fileStream) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"File not uploaded\",\n })\n }\n\n // Check if fileStream is a readable stream\n if (typeof fileStream !== \"object\" || !(\"pipe\" in fileStream) || typeof fileStream.pipe !== \"function\") {\n throw new TRPCError({\n code: \"INTERNAL_SERVER_ERROR\",\n message: \"Invalid file stream format\",\n })\n }\n\n // Validate fileSize (optional, but validate if provided)\n if (fileSize !== undefined && fileSize !== null) {\n if (typeof fileSize !== \"number\") {\n throw new TRPCError({\n code: \"INTERNAL_SERVER_ERROR\",\n message: \"Invalid fileSize format - must be a number\",\n })\n }\n\n if (fileSize < 0) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"fileSize cannot be negative\",\n })\n }\n\n if (!Number.isFinite(fileSize)) {\n throw new TRPCError({\n code: \"INTERNAL_SERVER_ERROR\",\n message: \"fileSize must be a finite number\",\n })\n }\n }\n\n // Return validated values\n return {\n validatedImageId: imageId.trim(),\n validatedFile: fileStream as NodeJS.ReadableStream,\n validatedFileSize: typeof fileSize === \"number\" ? fileSize : 0,\n }\n}\n\n/**\n * Maps Signal OpenStack API Error to appropriate TRPCError instances\n * @param error - The Signal OpenStack API Error\n * @param context - Additional context for error messages (e.g., imageId, operation type)\n * @returns TRPCError instance with appropriate code and message\n */\nexport function mapErrorResponseToTRPCError(\n error: SignalOpenstackApiError,\n context: {\n operation: string\n imageId?: string\n memberId?: string\n additionalInfo?: string\n }\n): TRPCError {\n const { operation, imageId, memberId, additionalInfo } = context\n const baseMessage = `Failed to ${operation}`\n const entityInfo = imageId ? ` image: ${imageId}` : \"\"\n const memberInfo = memberId ? `, member: ${memberId}` : \"\"\n const extraInfo = additionalInfo ? ` - ${additionalInfo}` : \"\"\n\n switch (error.statusCode) {\n case 400:\n return new TRPCError({\n code: \"BAD_REQUEST\",\n message: `${baseMessage}${entityInfo}${memberInfo}${extraInfo}`,\n })\n\n case 403:\n return new TRPCError({\n code: \"FORBIDDEN\",\n message: `Access forbidden - cannot ${operation}${entityInfo}${memberInfo}${extraInfo}`,\n })\n\n case 404:\n return new TRPCError({\n code: \"NOT_FOUND\",\n message: `${memberId ? \"Image or member\" : \"Image\"} not found${entityInfo}${memberInfo}`,\n })\n\n case 409:\n return new TRPCError({\n code: \"CONFLICT\",\n message: `Conflict - ${operation}${entityInfo}${memberInfo}${extraInfo}`,\n })\n\n case 413:\n return new TRPCError({\n code: \"PAYLOAD_TOO_LARGE\",\n message: `Request entity too large${entityInfo}${extraInfo}`,\n })\n\n case 415:\n return new TRPCError({\n code: \"BAD_REQUEST\",\n message: `Unsupported media type${entityInfo}${extraInfo}`,\n })\n\n default:\n return new TRPCError({\n code: \"INTERNAL_SERVER_ERROR\",\n message: `${baseMessage}: ${error.message || \"Unknown error\"}`,\n })\n }\n}\n\n/**\n * Handles specific error cases for image operations with custom messages\n */\nexport const ImageErrorHandlers = {\n /**\n * Handles errors specific to image upload operations\n */\n upload: (response: { statusCode?: number; message?: string }, imageId: string, contentType?: string) => {\n switch (response.statusCode) {\n case 404:\n return new TRPCError({\n code: \"NOT_FOUND\",\n message: `Image not found: ${imageId}`,\n })\n case 403:\n return new TRPCError({\n code: \"FORBIDDEN\",\n message: `Access forbidden - cannot upload to image: ${imageId}`,\n })\n case 409:\n return new TRPCError({\n code: \"CONFLICT\",\n message: `Image is not in a valid state for upload: ${imageId}`,\n })\n case 400:\n return new TRPCError({\n code: \"BAD_REQUEST\",\n message: `Invalid upload data for image: ${imageId}`,\n })\n case 413:\n return new TRPCError({\n code: \"PAYLOAD_TOO_LARGE\",\n message: `Image data too large for upload: ${imageId}`,\n })\n case 415:\n return new TRPCError({\n code: \"BAD_REQUEST\",\n message: `Unsupported content type for image upload: ${contentType || \"unknown\"}`,\n })\n default:\n return new TRPCError({\n code: \"INTERNAL_SERVER_ERROR\",\n message: `Failed to upload image: ${response.message || \"Unknown error\"}`,\n })\n }\n },\n\n /**\n * Handles errors specific to image member operations\n */\n member: {\n create: (response: { status?: number; statusText?: string }, imageId: string, member: string) => {\n switch (response.status) {\n case 404:\n return new TRPCError({\n code: \"NOT_FOUND\",\n message: `Image not found: ${imageId}`,\n })\n case 403:\n return new TRPCError({\n code: \"FORBIDDEN\",\n message: `Access forbidden - must be image owner to add members: ${imageId}`,\n })\n case 400:\n return new TRPCError({\n code: \"BAD_REQUEST\",\n message: `Invalid request - check image visibility is 'shared' and member ID is valid: ${imageId}`,\n })\n case 409:\n return new TRPCError({\n code: \"CONFLICT\",\n message: `Member already exists for image: ${imageId}, ${member}`,\n })\n default:\n return new TRPCError({\n code: \"INTERNAL_SERVER_ERROR\",\n message: `Failed to create image member: ${response.statusText || \"Unknown error\"}`,\n })\n }\n },\n\n update: (response: { status?: number; statusText?: string }, imageId: string, memberId: string, status: string) => {\n switch (response.status) {\n case 404:\n return new TRPCError({\n code: \"NOT_FOUND\",\n message: `Image or member not found: ${imageId}, ${memberId}`,\n })\n case 403:\n return new TRPCError({\n code: \"FORBIDDEN\",\n message: `Access forbidden - only the member can update their own status: ${imageId}, ${memberId}`,\n })\n case 400:\n return new TRPCError({\n code: \"BAD_REQUEST\",\n message: `Invalid status value: ${status}`,\n })\n default:\n return new TRPCError({\n code: \"INTERNAL_SERVER_ERROR\",\n message: `Failed to update image member: ${response.statusText || \"Unknown error\"}`,\n })\n }\n },\n\n delete: (response: { status?: number; statusText?: string }, imageId: string, memberId: string) => {\n switch (response.status) {\n case 404:\n return new TRPCError({\n code: \"NOT_FOUND\",\n message: `Image or member not found: ${imageId}, ${memberId}`,\n })\n case 403:\n return new TRPCError({\n code: \"FORBIDDEN\",\n message: `Access forbidden - must be image owner to delete members: ${imageId}, ${memberId}`,\n })\n default:\n return new TRPCError({\n code: \"INTERNAL_SERVER_ERROR\",\n message: `Failed to delete image member: ${response.statusText || \"Unknown error\"}`,\n })\n }\n },\n\n list: (response: { status?: number; statusText?: string }, imageId: string) => {\n switch (response.status) {\n case 404:\n return new TRPCError({\n code: \"NOT_FOUND\",\n message: `Image not found: ${imageId}`,\n })\n case 403:\n return new TRPCError({\n code: \"FORBIDDEN\",\n message: `Access forbidden - only shared images have members: ${imageId}`,\n })\n default:\n return new TRPCError({\n code: \"INTERNAL_SERVER_ERROR\",\n message: `Failed to fetch image members: ${response.statusText || \"Unknown error\"}`,\n })\n }\n },\n\n get: (response: { status?: number; statusText?: string }, imageId: string, memberId: string) => {\n switch (response.status) {\n case 404:\n return new TRPCError({\n code: \"NOT_FOUND\",\n message: `Image or member not found: ${imageId}, ${memberId}`,\n })\n case 403:\n return new TRPCError({\n code: \"FORBIDDEN\",\n message: `Access forbidden to image member: ${imageId}, ${memberId}`,\n })\n default:\n return new TRPCError({\n code: \"INTERNAL_SERVER_ERROR\",\n message: `Failed to fetch image member: ${response.statusText || \"Unknown error\"}`,\n })\n }\n },\n },\n\n /**\n * Handles errors specific to image visibility updates\n */\n visibility: (response: { status?: number; statusText?: string }, imageId: string, visibility: string) => {\n switch (response.status) {\n case 404:\n return new TRPCError({\n code: \"NOT_FOUND\",\n message: `Image not found: ${imageId}`,\n })\n case 403:\n return new TRPCError({\n code: \"FORBIDDEN\",\n message: `Access forbidden - cannot update image visibility: ${imageId}`,\n })\n case 409:\n return new TRPCError({\n code: \"CONFLICT\",\n message: `Image is not in a valid state for visibility update: ${imageId}`,\n })\n case 400:\n return new TRPCError({\n code: \"BAD_REQUEST\",\n message: `Invalid visibility value for image: ${visibility}`,\n })\n default:\n return new TRPCError({\n code: \"INTERNAL_SERVER_ERROR\",\n message: `Failed to update image visibility: ${response.statusText || \"Unknown error\"}`,\n })\n }\n },\n\n /**\n * Handles errors specific to image deletion\n */\n delete: (response: { status?: number; statusText?: string }, imageId: string) => {\n switch (response.status) {\n case 403:\n return new TRPCError({\n code: \"FORBIDDEN\",\n message: `Cannot delete protected image: ${imageId}`,\n })\n case 404:\n return new TRPCError({\n code: \"NOT_FOUND\",\n message: `Image not found: ${imageId}`,\n })\n default:\n return new TRPCError({\n code: \"INTERNAL_SERVER_ERROR\",\n message: `Failed to delete image: ${response.statusText || \"Unknown error\"}`,\n })\n }\n },\n}\n\n/**\n * Handles Zod parsing errors and converts them to TRPCError\n * @param error - The Zod parsing error\n * @param operation - The operation being performed for context\n * @returns TRPCError with parsing error details\n */\nexport function handleZodParsingError(error: ZodError, operation: string): TRPCError {\n return new TRPCError({\n code: \"INTERNAL_SERVER_ERROR\",\n message: `Invalid response format from OpenStack Glance API during ${operation}`,\n cause: error,\n })\n}\n\n/**\n * Generic error wrapper that preserves TRPCError instances and wraps other errors\n * @param error - The error to handle\n * @param operation - The operation being performed for context\n * @returns TRPCError instance\n */\nexport function wrapError(error: Error | string, operation: string): TRPCError {\n if (error instanceof TRPCError) {\n return error\n }\n\n const baseErrorMessage = `Error during ${operation}`\n\n return new TRPCError({\n code: \"INTERNAL_SERVER_ERROR\",\n message: typeof error !== \"string\" && error.message ? `${baseErrorMessage}: ${error.message}` : baseErrorMessage,\n cause: error,\n })\n}\n\n/**\n * Higher-order function to wrap async operations with consistent error handling\n * @param operation - The async operation to perform\n * @param operationName - Name of the operation for error context\n * @returns Promise that resolves to the operation result or throws TRPCError\n */\nexport async function withErrorHandling<T>(operation: () => Promise<T>, operationName: string): Promise<T> {\n try {\n return await operation()\n } catch (error) {\n throw wrapError(error as Error, operationName)\n }\n}\n\n/**\n * Helper to format bulk operation error messages\n * @param imageId - The image ID that failed\n * @param error - The error that occurred\n * @param operation - The operation being performed (e.g., \"delete\", \"activate\")\n * @returns Formatted error message\n */\nexport function formatBulkOperationError(imageId: string, error: unknown, operation: string): string {\n if (error instanceof TRPCError) {\n return error.message\n }\n if (error instanceof Error) {\n return `Failed to ${operation} image: ${error.message}`\n }\n if (typeof error === \"string\") {\n return `Failed to ${operation} image: ${error}`\n }\n return `Failed to ${operation} image: Unknown error`\n}\n\n/**\n * Validates that an array of image IDs is not empty\n * @param imageIds - Array of image IDs to validate\n * @param operation - The operation being performed for error context\n * @throws TRPCError if array is empty\n */\n/**\n * Parses a filter param that may be a single value or multi-value \"in:val1,val2\" format.\n * Returns an array of values to match against.\n */\nexport function parseMultiValue(param: string): string[] {\n return param.startsWith(\"in:\") ? param.replace(\"in:\", \"\").split(\",\") : [param]\n}\n\nexport function validateBulkImageIds(imageIds: string[], operation: string): void {\n if (imageIds.length === 0) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: `Cannot ${operation} - at least one image ID is required`,\n })\n }\n}\n\n/**\n * Chunks an array into smaller arrays of specified size\n * Useful for processing large batches in smaller groups\n * @param array - Array to chunk\n * @param size - Size of each chunk\n * @returns Array of chunks\n */\nexport function chunkArray<T>(array: T[], size: number): T[][] {\n const chunks: T[][] = []\n for (let i = 0; i < array.length; i += size) {\n chunks.push(array.slice(i, i + size))\n }\n return chunks\n}\n\n/**\n * Processes bulk operations with optional chunking and rate limiting\n * @param items - Items to process\n * @param processor - Async function to process each item\n * @param options - Processing options\n * @returns BulkOperationResult with successful and failed items\n */\nexport async function processBulkOperation<T extends { id: string }>(\n items: T[],\n processor: (item: T) => Promise<void>,\n options: {\n chunkSize?: number\n delayBetweenChunks?: number\n operation?: string // Operation name for error messages (e.g., \"delete\", \"activate\")\n } = {}\n): Promise<BulkOperationResult> {\n const { chunkSize, delayBetweenChunks, operation = \"process\" } = options\n const results: BulkOperationResult = {\n successful: [],\n failed: [],\n }\n\n // If chunking is enabled, process in chunks\n if (chunkSize && chunkSize > 0) {\n const chunks = chunkArray(items, chunkSize)\n\n for (let i = 0; i < chunks.length; i++) {\n const chunk = chunks[i]\n const chunkPromises = chunk.map(async (item) => {\n try {\n await processor(item)\n return { status: \"success\" as const, id: item.id }\n } catch (error) {\n return {\n status: \"failed\" as const,\n id: item.id,\n error: formatBulkOperationError(item.id, error, operation),\n }\n }\n })\n\n const chunkResults = await Promise.allSettled(chunkPromises)\n\n chunkResults.forEach((result) => {\n if (result.status === \"fulfilled\") {\n const value = result.value\n if (value.status === \"success\") {\n results.successful.push(value.id)\n } else {\n results.failed.push({ imageId: value.id, error: value.error })\n }\n }\n })\n\n // Add delay between chunks if specified\n if (delayBetweenChunks && i < chunks.length - 1) {\n await new Promise((resolve) => setTimeout(resolve, delayBetweenChunks))\n }\n }\n } else {\n // Process all items in parallel\n const promises = items.map(async (item) => {\n try {\n await processor(item)\n return { status: \"success\" as const, id: item.id }\n } catch (error) {\n return {\n status: \"failed\" as const,\n id: item.id,\n error: formatBulkOperationError(item.id, error, operation),\n }\n }\n })\n\n const settledResults = await Promise.allSettled(promises)\n\n settledResults.forEach((result) => {\n if (result.status === \"fulfilled\") {\n const value = result.value\n if (value.status === \"success\") {\n results.successful.push(value.id)\n } else {\n results.failed.push({ imageId: value.id, error: value.error })\n }\n }\n })\n }\n\n return results\n}\n\n/**\n * OpenStack Glance Image Format Compatibility Matrix\n * Official reference: https://docs.openstack.org/glance/latest/\n *\n * disk_format: The actual format of the underlying virtual machine image\n * container_format: The container format used to encapsulate the disk image\n */\n\n/**\n * Official OpenStack Glance compatibility matrix\n * Maps each disk_format to its compatible container_formats\n *\n * Reference table:\n * ┌────────────┬──────────────────────────────────┬─────────────┐\n * │disk_format │ compatible container_formats │ Recommended │\n * ├────────────┼──────────────────────────────────┼─────────────┤\n * │ qcow2 │ bare, ova, docker │ bare │\n * │ raw │ bare, ova, docker │ bare │\n * │ vmdk │ bare, ova │ bare │\n * │ vhd │ bare, ova │ bare │\n * │ vhdx │ bare, ova │ bare │\n * │ vdi │ bare, ova │ bare │\n * │ iso │ bare │ bare │\n * │ ami │ ami │ ami │\n * │ aki │ aki │ aki │\n * │ ari │ ari │ ari │\n * │ ploop │ bare │ bare │\n * └────────────┴──────────────────────────────────┴─────────────┘\n */\nexport const diskFormatCompatibility: Record<string, string[]> = {\n // QEMU Emulator - Recommended for OpenStack/KVM\n qcow2: [\"bare\", \"ova\", \"docker\"],\n\n // Uncompressed disk image\n raw: [\"bare\", \"ova\", \"docker\"],\n\n // VMware Virtual Machine Disk format\n vmdk: [\"bare\", \"ova\"],\n\n // Microsoft Virtual Hard Disk format\n vhd: [\"bare\", \"ova\"],\n\n // Microsoft Virtual Hard Disk Extended format\n vhdx: [\"bare\", \"ova\"],\n\n // Oracle VirtualBox Virtual Disk Image\n vdi: [\"bare\", \"ova\"],\n\n // Optical Disk Image - only bare container\n iso: [\"bare\"],\n\n // Amazon Machine Image - only ami container\n ami: [\"ami\"],\n\n // Amazon Kernel Image - only aki container\n aki: [\"aki\"],\n\n // Amazon Ramdisk Image - only ari container\n ari: [\"ari\"],\n\n // Virtuozzo/Parallels Loopback Disk\n ploop: [\"bare\"],\n}\n\n/**\n * Default (recommended) container_format for each disk_format\n * These are the best practice selections based on OpenStack documentation\n */\nexport const defaultContainerFormat: Record<string, string> = {\n // QEMU - Recommended bare for OpenStack KVM deployments\n qcow2: \"bare\",\n\n // Raw - Bare is most compatible\n raw: \"bare\",\n\n // VMware - Bare for OpenStack compatibility\n vmdk: \"bare\",\n\n // Hyper-V - Bare for OpenStack compatibility\n vhd: \"bare\",\n\n // Hyper-V Extended - Bare for OpenStack compatibility\n vhdx: \"bare\",\n\n // VirtualBox - Bare for OpenStack compatibility\n vdi: \"bare\",\n\n // ISO - Only bare available\n iso: \"bare\",\n\n // Amazon - Only ami available\n ami: \"ami\",\n\n // Amazon - Only aki available\n aki: \"aki\",\n\n // Amazon - Only ari available\n ari: \"ari\",\n\n // Parallels - Bare is the only option\n ploop: \"bare\",\n}\n\n/**\n * Get all compatible container formats for a given disk format\n * @param diskFormat - The disk format to check\n * @returns Array of compatible container formats, empty array if disk_format not found\n *\n * @example\n * getCompatibleContainerFormats('qcow2') // Returns: ['bare', 'ova', 'docker']\n * getCompatibleContainerFormats('iso') // Returns: ['bare']\n * getCompatibleContainerFormats('ami') // Returns: ['ami']\n */\nexport function getCompatibleContainerFormats(diskFormat: string): string[] {\n return diskFormatCompatibility[diskFormat] || []\n}\n\n/**\n * Get the recommended (default) container format for a given disk format\n * @param diskFormat - The disk format to check\n * @returns The recommended container format, or empty string if disk_format not found\n *\n * @example\n * getDefaultContainerFormat('qcow2') // Returns: 'bare'\n * getDefaultContainerFormat('vmdk') // Returns: 'bare'\n * getDefaultContainerFormat('ami') // Returns: 'ami'\n */\nexport function getDefaultContainerFormat(diskFormat: string): string {\n return defaultContainerFormat[diskFormat] || \"\"\n}\n\n/**\n * Check if a disk_format and container_format combination is valid\n * @param diskFormat - The disk format to validate\n * @param containerFormat - The container format to validate\n * @returns true if the combination is valid, false otherwise\n *\n * @example\n * isValidFormatCombination('qcow2', 'bare') // Returns: true\n * isValidFormatCombination('qcow2', 'ova') // Returns: true\n * isValidFormatCombination('iso', 'docker') // Returns: false\n */\nexport function isValidFormatCombination(diskFormat: string, containerFormat: string): boolean {\n const compatible = getCompatibleContainerFormats(diskFormat)\n return compatible.includes(containerFormat)\n}\n","import React, { useState, useMemo } from \"react\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport {\n Modal,\n Form,\n FormRow,\n FormSection,\n TextInput,\n Select,\n SelectOption,\n Checkbox,\n Button,\n Spinner,\n Stack,\n Pill,\n Message,\n} from \"@cloudoperators/juno-ui-components\"\nimport { CreateImageInput } from \"@/server/Compute/types/image\"\nimport {\n getCompatibleContainerFormats,\n getDefaultContainerFormat,\n isValidFormatCombination,\n} from \"@/server/Compute/helpers/imageHelpers\"\nimport { DISK_FORMATS, IMAGE_VISIBILITY } from \"../../../-constants/filters\"\nimport { cn } from \"@/client/utils/cn\"\n\ninterface CreateImageModalProps {\n isOpen: boolean\n onClose: () => void\n onCreate: (imageData: Omit<CreateImageInput, \"project_id\">, file: File) => Promise<void>\n isLoading?: boolean\n isUploadPending?: boolean\n uploadProgressPercent?: number\n}\n\ninterface ImageProperties {\n name: string\n tags: string[]\n visibility: string\n disk_format?: string\n container_format?: string\n protected: boolean\n min_disk: number\n min_ram: number\n}\n\nconst defaultImageValues: ImageProperties = {\n name: \"\",\n tags: [],\n visibility: IMAGE_VISIBILITY.PRIVATE,\n disk_format: undefined,\n container_format: undefined,\n protected: false,\n min_disk: 0,\n min_ram: 0,\n}\n\nexport const CreateImageModal: React.FC<CreateImageModalProps> = ({\n isOpen,\n onClose,\n onCreate,\n isLoading = false,\n isUploadPending = false,\n uploadProgressPercent,\n}) => {\n const { t } = useLingui()\n\n const [properties, setProperties] = useState<ImageProperties>({ ...defaultImageValues })\n const [tagsInput, setTagsInput] = useState<string>(\"\")\n const [selectedFile, setSelectedFile] = useState<File | null>(null)\n const [errors, setErrors] = useState<{ [key: string]: string }>({})\n const [isDragging, setIsDragging] = useState<boolean>(false)\n const [generalError, setGeneralError] = useState<string | null>(null)\n\n // Check if form is valid for submit button\n const isFormValid =\n properties.name.trim() !== \"\" &&\n selectedFile !== null &&\n properties.disk_format !== undefined &&\n properties.disk_format.trim() !== \"\" &&\n properties.container_format !== undefined &&\n properties.container_format.trim() !== \"\" &&\n properties.min_disk >= 0 &&\n properties.min_ram >= 0\n\n // Get compatible container formats for current disk_format\n const compatibleContainerFormats = useMemo(() => {\n return properties.disk_format ? getCompatibleContainerFormats(properties.disk_format) : []\n }, [properties.disk_format])\n\n const validExtensions = [\n \".qcow2\",\n \".raw\",\n \".vmdk\",\n \".vhd\",\n \".vhdx\",\n \".vdi\",\n \".ami\",\n \".ari\",\n \".aki\",\n \".iso\",\n \".ploop\",\n \".img\",\n ]\n const supportedFileFormats = validExtensions.join(\", \")\n\n const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const { name, value, type, checked } = e.target\n\n setProperties((prev) => ({\n ...prev,\n [name]: type === \"checkbox\" ? checked : value,\n }))\n\n if (errors[name]) {\n setErrors((prev) => {\n const newErrors = { ...prev }\n delete newErrors[name]\n return newErrors\n })\n }\n }\n\n const handleBlur = (e: React.FocusEvent<HTMLInputElement>) => {\n const { name, value } = e.target\n\n // Validate on blur\n if (name === \"name\" && (!value || value.trim() === \"\")) {\n setErrors((prev) => ({ ...prev, name: t`Image name is required` }))\n }\n }\n\n const handleSelectChange = (name: string, value: string | number | string[] | undefined) => {\n if (name === \"disk_format\") {\n // When disk_format changes, auto-update container_format to the default\n const newDiskFormat = value as string\n const recommended = getDefaultContainerFormat(newDiskFormat)\n\n setProperties((prev) => ({\n ...prev,\n disk_format: newDiskFormat,\n container_format: recommended,\n }))\n } else {\n setProperties((prev) => ({\n ...prev,\n [name]: value,\n }))\n }\n\n if (errors[name]) {\n setErrors((prev) => {\n const newErrors = { ...prev }\n delete newErrors[name]\n return newErrors\n })\n }\n }\n\n const handleNumericChange = (name: string, value: string) => {\n const numValue = value === \"\" ? 0 : parseInt(value, 10)\n\n if (!isNaN(numValue)) {\n setProperties((prev) => ({\n ...prev,\n [name]: numValue,\n }))\n\n if (errors[name]) {\n setErrors((prev) => {\n const newErrors = { ...prev }\n delete newErrors[name]\n return newErrors\n })\n }\n }\n }\n\n const handleNumericBlur = (name: string, value: number) => {\n if (value < 0) {\n if (name === \"min_disk\") {\n setErrors((prev) => ({ ...prev, min_disk: t`Minimum disk must be 0 or greater` }))\n } else if (name === \"min_ram\") {\n setErrors((prev) => ({ ...prev, min_ram: t`Minimum RAM must be 0 or greater` }))\n }\n }\n }\n\n const validateAndSetFile = (file: File) => {\n const fileName = file.name.toLowerCase()\n const isValidFile = validExtensions.some((ext) => fileName.endsWith(ext))\n\n if (isValidFile) {\n setSelectedFile(file)\n if (errors.file) {\n setErrors((prev) => {\n const newErrors = { ...prev }\n delete newErrors.file\n return newErrors\n })\n }\n } else {\n setErrors((prev) => ({\n ...prev,\n file: t`Invalid file format. Supported formats: ${supportedFileFormats}`,\n }))\n }\n }\n\n const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0]\n if (file) {\n validateAndSetFile(file)\n }\n }\n\n const handleDragOver = (e: React.DragEvent<HTMLLabelElement>) => {\n e.preventDefault()\n e.stopPropagation()\n setIsDragging(true)\n }\n\n const handleDragLeave = (e: React.DragEvent<HTMLLabelElement>) => {\n e.preventDefault()\n e.stopPropagation()\n setIsDragging(false)\n }\n\n const handleDrop = (e: React.DragEvent<HTMLLabelElement>) => {\n e.preventDefault()\n e.stopPropagation()\n setIsDragging(false)\n\n const droppedFiles = e.dataTransfer.files\n\n if (droppedFiles && droppedFiles.length > 0) {\n validateAndSetFile(droppedFiles[0])\n }\n }\n\n const handleTagsInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n setTagsInput(e.target.value)\n }\n\n const handleAddTag = () => {\n const trimmedTag = tagsInput.trim()\n\n if (trimmedTag === \"\") return\n\n if (properties.tags.includes(trimmedTag)) {\n setTagsInput(\"\")\n return\n }\n\n setProperties((prev) => ({\n ...prev,\n tags: [...prev.tags, trimmedTag],\n }))\n\n setTagsInput(\"\")\n }\n\n const handleTagKeyPress = (e: React.KeyboardEvent<HTMLInputElement>) => {\n if (e.key === \"Enter\") {\n e.preventDefault()\n handleAddTag()\n }\n }\n\n const handleRemoveTag = (tagToRemove: string) => {\n setProperties((prev) => ({\n ...prev,\n tags: prev.tags.filter((tag) => tag !== tagToRemove),\n }))\n }\n\n const validateForm = (): boolean => {\n const newErrors: { [key: string]: string } = {}\n\n if (!properties.name || properties.name.trim() === \"\") {\n newErrors.name = t`Image name is required`\n }\n\n if (!selectedFile) {\n newErrors.file = t`Image file is required`\n }\n\n if (!properties.disk_format || properties.disk_format.trim() === \"\") {\n newErrors.disk_format = t`Disk format is required`\n }\n\n if (!properties.container_format || properties.container_format.trim() === \"\") {\n newErrors.container_format = t`Container format is required`\n }\n\n // Validate format combination\n if (properties.disk_format && properties.container_format) {\n if (!isValidFormatCombination(properties.disk_format, properties.container_format)) {\n newErrors.container_format = t`Invalid format combination for selected disk format`\n }\n }\n\n if (properties.min_disk < 0) {\n newErrors.min_disk = t`Minimum disk must be 0 or greater`\n }\n\n if (properties.min_ram < 0) {\n newErrors.min_ram = t`Minimum RAM must be 0 or greater`\n }\n\n setErrors(newErrors)\n return Object.keys(newErrors).length === 0\n }\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault()\n setGeneralError(null)\n\n if (!validateForm()) {\n setGeneralError(t`Please fix the validation errors below.`)\n return\n }\n\n try {\n // Prepare image data without the file (file is uploaded separately)\n const imageData = {\n name: properties.name.trim(),\n tags: properties.tags,\n visibility: properties.visibility,\n disk_format: properties.disk_format,\n container_format: properties.container_format,\n protected: properties.protected,\n min_disk: properties.min_disk,\n min_ram: properties.min_ram,\n } as unknown as Omit<CreateImageInput, \"project_id\">\n\n // Call onCreate with imageData and file as separate arguments\n // File will be uploaded after image is created\n await onCreate(imageData, selectedFile!)\n handleClose()\n } catch (error) {\n // Display error in modal instead of toast\n const errorMessage = error instanceof Error ? error.message : t`Failed to create image. Please try again.`\n setGeneralError(errorMessage)\n }\n }\n\n const handleClose = () => {\n setProperties({ ...defaultImageValues })\n setTagsInput(\"\")\n setSelectedFile(null)\n setErrors({})\n setGeneralError(null)\n onClose()\n }\n\n return (\n <Modal\n open={isOpen}\n onCancel={isLoading ? undefined : handleClose}\n size=\"large\"\n title={t`Create New Image`}\n onConfirm={handleSubmit}\n confirmButtonLabel={t`Create Image`}\n cancelButtonLabel={t`Cancel`}\n disableConfirmButton={isLoading || !isFormValid}\n closeable={!isLoading}\n closeOnEsc={!isLoading}\n >\n {isLoading && !uploadProgressPercent && (\n <Stack distribution=\"center\" alignment=\"center\" className=\"mt-4\">\n <Spinner variant=\"primary\" />\n {!isUploadPending && <Trans>Creating image...</Trans>}\n {isUploadPending && <Trans>Pending file upload...</Trans>}\n </Stack>\n )}\n\n {isLoading && !!uploadProgressPercent && (\n <div className=\"bg-neutral-quaternary mt-4 w-full rounded-full\">\n <div\n className=\"bg-theme-info flex h-4 items-center justify-center rounded-full p-0.5 text-center text-xs leading-none font-medium text-white\"\n style={{ width: `${uploadProgressPercent}%` }}\n >\n {uploadProgressPercent}%\n </div>\n </div>\n )}\n\n {!isLoading && (\n <Form className=\"mb-6\">\n {generalError && (\n <Message variant=\"error\" className=\"mb-6\">\n {generalError}\n </Message>\n )}\n\n {/* File Upload Section */}\n <FormSection className=\"mb-6\">\n <FormRow>\n <div className=\"w-full\">\n <label htmlFor=\"image-file\" className=\"mb-2 block text-sm font-medium text-gray-900\">\n {t`Image File`}\n <span className=\"ml-1 text-red-500\">*</span>\n </label>\n <div className=\"flex w-full items-center justify-center\">\n <label\n htmlFor=\"image-file\"\n onDragOver={handleDragOver}\n onDragLeave={handleDragLeave}\n onDrop={handleDrop}\n className={cn(\n \"flex h-24 w-full cursor-pointer flex-col items-center justify-center rounded-lg border-2 border-dashed transition-all\",\n isDragging ? \"border-blue-500 bg-blue-50\" : \"border-gray-300 bg-gray-50 hover:bg-gray-100\"\n )}\n >\n <div className=\"flex flex-col items-center justify-center pt-3 pb-3\">\n <svg\n className={cn(\"mb-1 h-6 w-6 transition-colors\", isDragging ? \"text-blue-500\" : \"text-gray-500\")}\n aria-hidden=\"true\"\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 20 16\"\n >\n <path\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth=\"2\"\n d=\"M13 13h3a3 3 0 0 0 0-6h-.025A5.56 5.56 0 0 0 16 5.5 5.5 5.5 0 0 0 5.207 5.021C5.137 5.017 5.071 5 5 5a4 4 0 0 0 0 8h2.167M10 15V6m0 0L8 8m2-2 2 2\"\n />\n </svg>\n <p\n className={cn(\n \"text-xs transition-colors\",\n isDragging ? \"font-semibold text-blue-600\" : \"text-gray-500\"\n )}\n >\n {isDragging ? (\n <span>{t`Drop your image file here`}</span>\n ) : (\n <>\n <span className=\"font-semibold\">{t`Click to upload`}</span> {t`or drag and drop`}\n </>\n )}\n </p>\n <p className=\"text-xs text-gray-400\">{t`QCOW2, Raw, VMDK, VHD, VHDX, VDI, AMI, ARI, AKI, ISO, PLOOP`}</p>\n </div>\n <input\n id=\"image-file\"\n type=\"file\"\n className=\"hidden\"\n onChange={handleFileChange}\n accept={supportedFileFormats}\n disabled={isLoading}\n />\n </label>\n </div>\n {selectedFile && (\n <div className=\"mt-2 flex items-center justify-between rounded-lg border border-green-200 bg-green-50 p-2 text-xs\">\n <div className=\"flex items-center\">\n <svg className=\"mr-2 h-4 w-4 text-green-600\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path\n fillRule=\"evenodd\"\n d=\"M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z\"\n clipRule=\"evenodd\"\n />\n </svg>\n <span className=\"text-gray-700\">{selectedFile.name}</span>\n </div>\n <button\n type=\"button\"\n onClick={() => {\n setSelectedFile(null)\n // Clear file error when removing file\n if (errors.file) {\n setErrors((prev) => {\n const newErrors = { ...prev }\n delete newErrors.file\n return newErrors\n })\n }\n }}\n className=\"font-medium text-red-600 hover:text-red-800\"\n disabled={isLoading}\n >\n {t`Remove`}\n </button>\n </div>\n )}\n {errors.file && <p className=\"text-theme-error mt-1 text-xs text-red-600\">{errors.file}</p>}\n </div>\n </FormRow>\n </FormSection>\n\n {/* Basic Details Section */}\n <FormSection className=\"mb-6\">\n <FormRow className=\"mb-6\">\n <TextInput\n id=\"name\"\n name=\"name\"\n label={t`Image Name`}\n value={properties.name}\n onChange={handleInputChange}\n onBlur={handleBlur}\n required\n errortext={errors.name}\n placeholder={t`Ubuntu 22.04 LTS`}\n disabled={isLoading}\n />\n </FormRow>\n\n <FormRow className=\"mb-6\">\n <div className=\"w-full\">\n <Stack gap=\"1\" direction=\"horizontal\" alignment=\"start\">\n <div className=\"flex-1\">\n <TextInput\n id=\"tags\"\n name=\"tags\"\n label={t`Tags`}\n value={tagsInput}\n onChange={handleTagsInputChange}\n onKeyDown={handleTagKeyPress}\n helptext={t`Press Enter to add`}\n placeholder={t`production, linux`}\n disabled={isLoading}\n />\n </div>\n\n <Button variant=\"primary\" onClick={handleAddTag} disabled={isLoading || tagsInput.trim() === \"\"}>\n <Trans>Add</Trans>\n </Button>\n </Stack>\n\n {properties.tags.length > 0 && (\n <Stack gap=\"1\" wrap={true} alignment=\"center\" className=\"mt-1\">\n {properties.tags.map((tag) => (\n <Pill key={tag} closeable pillKey=\"\" pillValue={tag} onClose={() => handleRemoveTag(tag)} />\n ))}\n </Stack>\n )}\n </div>\n </FormRow>\n\n <FormRow className=\"mb-6\">\n <Select\n id=\"visibility\"\n name=\"visibility\"\n label={t`Visibility`}\n value={properties.visibility}\n onChange={(value) => handleSelectChange(\"visibility\", value)}\n disabled={isLoading}\n loading={isLoading}\n >\n <SelectOption value={IMAGE_VISIBILITY.PUBLIC} label={t`Public`} />\n <SelectOption value={IMAGE_VISIBILITY.PRIVATE} label={t`Private`} />\n <SelectOption value={IMAGE_VISIBILITY.SHARED} label={t`Shared`} />\n <SelectOption value={IMAGE_VISIBILITY.COMMUNITY} label={t`Community`} />\n </Select>\n </FormRow>\n\n <FormRow className=\"mb-6\">\n <Stack direction=\"horizontal\" gap=\"3\" distribution=\"evenly\" className=\"w-full\">\n <div className=\"flex-1\">\n <Select\n id=\"disk_format\"\n name=\"disk_format\"\n label={t`Disk Format`}\n value={properties.disk_format}\n onChange={(value) => handleSelectChange(\"disk_format\", value)}\n disabled={isLoading}\n loading={isLoading}\n required\n errortext={errors.disk_format}\n >\n <SelectOption value={DISK_FORMATS.QCOW2} label=\"QCOW2 - QEMU Emulator\" />\n <SelectOption value={DISK_FORMATS.RAW} label=\"Raw\" />\n <SelectOption value={DISK_FORMATS.VMDK} label=\"VMDK - Virtual Machine Disk\" />\n <SelectOption value={DISK_FORMATS.VHD} label=\"VHD - Virtual Hard Disk\" />\n <SelectOption value={DISK_FORMATS.VHDX} label=\"VHDX - Virtual Hard Disk Extended\" />\n <SelectOption value={DISK_FORMATS.VDI} label=\"VDI - Virtual Disk Image\" />\n <SelectOption value={DISK_FORMATS.AMI} label=\"AMI - Amazon Machine Image\" />\n <SelectOption value={DISK_FORMATS.ARI} label=\"ARI - Amazon Ramdisk Image\" />\n <SelectOption value={DISK_FORMATS.AKI} label=\"AKI - Amazon Kernel Image\" />\n <SelectOption value={DISK_FORMATS.ISO} label=\"ISO - Optical Disk Image\" />\n <SelectOption value={DISK_FORMATS.PLOOP} label=\"PLOOP - Virtuozzo/Parallels Loopback Disk\" />\n </Select>\n </div>\n <div className=\"flex-1\">\n <Select\n id=\"container_format\"\n name=\"container_format\"\n label={t`Container Format`}\n value={properties.container_format}\n onChange={(value) => handleSelectChange(\"container_format\", value)}\n disabled={isLoading || !properties.disk_format || !compatibleContainerFormats.length}\n required\n errortext={errors.container_format}\n helptext={!compatibleContainerFormats.length && t`Select disk format first`}\n >\n {compatibleContainerFormats.map((format) => (\n <SelectOption key={format} value={format} label={format.toUpperCase()} />\n ))}\n </Select>\n </div>\n </Stack>\n </FormRow>\n\n <FormRow className=\"mb-0\">\n <Checkbox\n id=\"protected\"\n name=\"protected\"\n label={t`Protected`}\n checked={properties.protected}\n onChange={handleInputChange}\n helptext={t`Prevent accidental deletion`}\n disabled={isLoading}\n />\n </FormRow>\n </FormSection>\n\n {/* Resource Requirements Section */}\n <FormSection className=\"mb-6\">\n <FormRow className=\"mb-0\">\n <Stack direction=\"horizontal\" gap=\"3\" distribution=\"evenly\" className=\"w-full\">\n <div className=\"flex-1\">\n <TextInput\n id=\"min_disk\"\n name=\"min_disk\"\n label={t`Min Disk (GB)`}\n type=\"number\"\n value={String(properties.min_disk)}\n onChange={(e) => handleNumericChange(\"min_disk\", e.target.value)}\n onBlur={() => handleNumericBlur(\"min_disk\", properties.min_disk)}\n helptext={t`Boot size`}\n errortext={errors.min_disk}\n disabled={isLoading}\n />\n </div>\n <div className=\"flex-1\">\n <TextInput\n id=\"min_ram\"\n name=\"min_ram\"\n label={t`Min RAM (MB)`}\n type=\"number\"\n value={String(properties.min_ram)}\n onChange={(e) => handleNumericChange(\"min_ram\", e.target.value)}\n onBlur={() => handleNumericBlur(\"min_ram\", properties.min_ram)}\n helptext={t`Boot RAM`}\n errortext={errors.min_ram}\n disabled={isLoading}\n />\n </div>\n </Stack>\n </FormRow>\n </FormSection>\n </Form>\n )}\n </Modal>\n )\n}\n","import React from \"react\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { Button, ButtonRow, Message, Modal, ModalFooter, Spinner, Stack } from \"@cloudoperators/juno-ui-components\"\n\ninterface DeleteImagesModalProps {\n deletableImages: Array<string>\n protectedImages: Array<string>\n isOpen: boolean\n isLoading: boolean\n onClose: () => void\n onDelete: (deletableImages: Array<string>) => void\n}\n\nexport const DeleteImagesModal: React.FC<DeleteImagesModalProps> = ({\n deletableImages,\n protectedImages,\n isOpen,\n isLoading,\n onClose,\n onDelete,\n}) => {\n const { t } = useLingui()\n\n const deletableCount = deletableImages.length\n const protectedCount = protectedImages.length\n\n const handleDelete = (e: React.MouseEvent<HTMLElement>) => {\n e.preventDefault()\n onDelete(deletableImages)\n }\n\n return (\n <Modal\n onCancel={onClose}\n size=\"small\"\n title={t`Delete Images`}\n open={isOpen}\n modalFooter={\n <ModalFooter className=\"flex justify-end\">\n <ButtonRow>\n <Button variant=\"default\" onClick={onClose}>\n <Trans>Cancel</Trans>\n </Button>\n <Button\n variant=\"primary-danger\"\n onClick={handleDelete}\n disabled={isLoading}\n data-testid={`delete-image-button`}\n >\n <Trans>Delete</Trans>\n </Button>\n </ButtonRow>\n </ModalFooter>\n }\n >\n {isLoading && (\n <Stack distribution=\"center\" alignment=\"center\">\n <Spinner variant=\"primary\" />\n </Stack>\n )}\n\n {!isLoading && (\n <div className=\"my-6\">\n {deletableCount > 0 && (\n <>\n {/* Header */}\n <Message\n text={t`You are about to delete ${deletableCount} image(s). This action cannot be undone.`}\n variant=\"danger\"\n className=\"mb-6\"\n />\n\n {/* Images to be deleted */}\n <div className=\"mb-6\">\n <h3 className=\"jn:text-theme-high mb-3 font-semibold\">\n <Trans>Images to be deleted ({deletableCount})</Trans>\n </h3>\n <div className=\"jn:bg-theme-background-lvl-1 max-h-24 overflow-y-auto rounded p-4\">\n <ul className=\"space-y-2\">\n {deletableImages.map((imageId) => (\n <li key={imageId} className=\"jn:text-theme-default font-mono\">\n {imageId}\n </li>\n ))}\n </ul>\n </div>\n </div>\n </>\n )}\n\n {/* Protected images (if any) */}\n {protectedCount > 0 && (\n <div className=\"mb-6\">\n <h3 className=\"jn:text-theme-high mb-3 font-semibold\">\n <Trans>Protected images (cannot be deleted)</Trans>\n </h3>\n <div className=\"jn:bg-theme-warning/10 max-h-24 overflow-y-auto rounded border border-yellow-500/20 p-4\">\n <ul className=\"space-y-2\">\n {protectedImages.map((imageId) => (\n <li key={imageId} className=\"jn:text-theme-default font-mono\">\n {imageId}\n </li>\n ))}\n </ul>\n </div>\n </div>\n )}\n\n {/* Summary */}\n <div className=\"jn:bg-theme-background-lvl-2 mb-6 rounded p-4\">\n {deletableCount > 0 && (\n <div className=\"mb-2 flex justify-between\">\n <span className=\"jn:text-theme-default\">\n <Trans>Images to delete:</Trans>\n </span>\n <span className=\"jn:text-theme-highest font-semibold\">{deletableCount}</span>\n </div>\n )}\n {protectedCount > 0 && (\n <div className=\"flex justify-between\">\n <span className=\"jn:text-theme-default\">\n <Trans>Protected (will be skipped):</Trans>\n </span>\n <span className=\"jn:text-theme-warning font-semibold\">{protectedCount}</span>\n </div>\n )}\n </div>\n </div>\n )}\n </Modal>\n )\n}\n","import React from \"react\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { Modal, Spinner, Stack } from \"@cloudoperators/juno-ui-components\"\n\ninterface DeactivateImagesModalProps {\n activeImages: Array<string>\n deactivatedImages: Array<string>\n isOpen: boolean\n isLoading: boolean\n onClose: () => void\n onDeactivate: (activeImages: Array<string>) => void\n}\n\nexport const DeactivateImagesModal: React.FC<DeactivateImagesModalProps> = ({\n activeImages,\n deactivatedImages,\n isOpen,\n isLoading,\n onClose,\n onDeactivate,\n}) => {\n const { t } = useLingui()\n\n const activeCount = activeImages.length\n const deactivatedCount = deactivatedImages.length\n\n const handleDeactivate = (e: React.MouseEvent<HTMLElement>) => {\n e.preventDefault()\n onDeactivate(activeImages)\n }\n\n return (\n <Modal\n onCancel={onClose}\n size=\"small\"\n title={t`Deactivate Images`}\n open={isOpen}\n onConfirm={(e) => {\n handleDeactivate(e)\n onClose()\n }}\n confirmButtonLabel={t`Deactivate`}\n cancelButtonLabel={t`Cancel`}\n disableConfirmButton={isLoading}\n >\n {isLoading && (\n <Stack distribution=\"center\" alignment=\"center\">\n <Spinner variant=\"primary\" />\n </Stack>\n )}\n\n {!isLoading && (\n <div className=\"my-6\">\n {activeCount > 0 && (\n <>\n <p className=\"mb-6\">\n <Trans>\n You are about to deactivate <strong>{activeCount} image(s)</strong>. Deactivated images cannot be used\n to launch new instances.\n </Trans>\n </p>\n\n {/* Images to be deactivated */}\n <div className=\"mb-6\">\n <h3 className=\"jn:text-theme-high mb-3 font-semibold\">\n <Trans>Images to be deactivated ({activeCount})</Trans>\n </h3>\n <div className=\"jn:bg-theme-background-lvl-1 max-h-24 overflow-y-auto rounded p-4\">\n <ul className=\"space-y-2\">\n {activeImages.map((imageId) => (\n <li key={imageId} className=\"jn:text-theme-default font-mono\">\n {imageId}\n </li>\n ))}\n </ul>\n </div>\n </div>\n </>\n )}\n\n {/* Already deactivated images (if any) */}\n {deactivatedCount > 0 && (\n <div className=\"mb-6\">\n <h3 className=\"jn:text-theme-high mb-3 font-semibold\">\n <Trans>Already deactivated (will be skipped)</Trans>\n </h3>\n <div className=\"jn:bg-theme-background-lvl-1 max-h-24 overflow-y-auto rounded p-4\">\n <ul className=\"space-y-2\">\n {deactivatedImages.map((imageId) => (\n <li key={imageId} className=\"jn:text-theme-default font-mono\">\n {imageId}\n </li>\n ))}\n </ul>\n </div>\n </div>\n )}\n\n {/* Summary */}\n <div className=\"jn:bg-theme-background-lvl-2 mb-6 rounded p-4\">\n {activeCount > 0 && (\n <div className=\"mb-2 flex justify-between\">\n <span className=\"jn:text-theme-default\">\n <Trans>Images to deactivate:</Trans>\n </span>\n <span className=\"jn:text-theme-highest font-semibold\">{activeCount}</span>\n </div>\n )}\n {deactivatedCount > 0 && (\n <div className=\"flex justify-between\">\n <span className=\"jn:text-theme-default\">\n <Trans>Already deactivated (will be skipped):</Trans>\n </span>\n <span className=\"jn:text-theme-warning font-semibold\">{deactivatedCount}</span>\n </div>\n )}\n </div>\n </div>\n )}\n </Modal>\n )\n}\n","import React from \"react\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { Modal, Spinner, Stack } from \"@cloudoperators/juno-ui-components\"\n\ninterface ActivateImagesModalProps {\n deactivatedImages: Array<string>\n activeImages: Array<string>\n isOpen: boolean\n isLoading: boolean\n onClose: () => void\n onActivate: (deactivatedImages: Array<string>) => void\n}\n\nexport const ActivateImagesModal: React.FC<ActivateImagesModalProps> = ({\n deactivatedImages,\n activeImages,\n isOpen,\n isLoading,\n onClose,\n onActivate,\n}) => {\n const { t } = useLingui()\n\n const deactivatedCount = deactivatedImages.length\n const activeCount = activeImages.length\n\n const handleActivate = (e: React.MouseEvent<HTMLElement>) => {\n e.preventDefault()\n onActivate(deactivatedImages)\n }\n\n return (\n <Modal\n onCancel={onClose}\n size=\"small\"\n title={t`Activate Images`}\n open={isOpen}\n onConfirm={handleActivate}\n confirmButtonLabel={t`Activate`}\n cancelButtonLabel={t`Cancel`}\n disableConfirmButton={isLoading}\n >\n {isLoading && (\n <Stack distribution=\"center\" alignment=\"center\">\n <Spinner variant=\"primary\" />\n </Stack>\n )}\n\n {!isLoading && (\n <div className=\"my-6\">\n {deactivatedCount > 0 && (\n <>\n <p className=\"mb-6\">\n <Trans>\n You are about to activate <strong>{deactivatedCount} image(s)</strong>. Activated images will be\n available for launching new instances.\n </Trans>\n </p>\n\n {/* Images to be activated */}\n <div className=\"mb-6\">\n <h3 className=\"jn:text-theme-high mb-3 font-semibold\">\n <Trans>Images to be activated ({deactivatedCount})</Trans>\n </h3>\n <div className=\"jn:bg-theme-background-lvl-1 max-h-24 overflow-y-auto rounded p-4\">\n <ul className=\"space-y-2\">\n {deactivatedImages.map((imageId) => (\n <li key={imageId} className=\"jn:text-theme-default font-mono\">\n {imageId}\n </li>\n ))}\n </ul>\n </div>\n </div>\n </>\n )}\n\n {/* Already active images (if any) */}\n {activeCount > 0 && (\n <div className=\"mb-6\">\n <h3 className=\"jn:text-theme-high mb-3 font-semibold\">\n <Trans>Already active (will be skipped)</Trans>\n </h3>\n <div className=\"jn:bg-theme-warning/10 max-h-24 overflow-y-auto rounded border border-yellow-500/20 p-4\">\n <ul className=\"space-y-2\">\n {activeImages.map((imageId) => (\n <li key={imageId} className=\"jn:text-theme-default font-mono\">\n {imageId}\n </li>\n ))}\n </ul>\n </div>\n </div>\n )}\n\n {/* Summary */}\n <div className=\"jn:bg-theme-background-lvl-2 mb-6 rounded p-4\">\n {deactivatedCount > 0 && (\n <div className=\"mb-2 flex justify-between\">\n <span className=\"jn:text-theme-default\">\n <Trans>Images to activate:</Trans>\n </span>\n <span className=\"jn:text-theme-highest font-semibold\">{deactivatedCount}</span>\n </div>\n )}\n {activeCount > 0 && (\n <div className=\"flex justify-between\">\n <span className=\"jn:text-theme-default\">\n <Trans>Already active (will be skipped):</Trans>\n </span>\n <span className=\"jn:text-theme-warning font-semibold\">{activeCount}</span>\n </div>\n )}\n </div>\n </div>\n )}\n </Modal>\n )\n}\n","import React, { useState } from \"react\"\nimport { useLingui } from \"@lingui/react/macro\"\nimport { useProjectId } from \"@/client/hooks\"\nimport { Modal, Message } from \"@cloudoperators/juno-ui-components\"\nimport { GlanceImage } from \"@/server/Compute/types/image\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { ImageMembersTable } from \"./ImageMembersTable\"\n\ninterface ManageImageAccessProps {\n isOpen: boolean\n onClose: () => void\n image: GlanceImage | null\n permissions: {\n canCreateMember: boolean\n canDeleteMember: boolean\n }\n}\n\nexport const ManageImageAccessModal: React.FC<ManageImageAccessProps> = ({\n isOpen,\n onClose,\n image,\n permissions: { canCreateMember, canDeleteMember },\n}) => {\n const { t } = useLingui()\n const projectId = useProjectId()\n\n const [message, setMessage] = useState<{ text: string; type: \"error\" | \"info\" } | null>(null)\n const [isAddingMember, setIsAddingMember] = useState(false)\n\n const { data: imageMembers, isLoading: isMembersLoading } = trpcReact.compute.listImageMembers.useQuery(\n { project_id: projectId, imageId: image?.id || \"\" },\n {\n enabled: isOpen && !!image?.id,\n }\n )\n\n const handleClose = () => {\n setMessage(null)\n setIsAddingMember(false)\n onClose()\n }\n\n if (!isOpen || !image) {\n return null\n }\n\n const imageName = image.name || image.id\n\n return (\n <Modal onCancel={handleClose} title={t`Manage Access for Image - ${imageName}`} open={isOpen} size=\"xl\">\n <div>\n {message && (\n <Message onDismiss={() => setMessage(null)} text={message.text} variant={message.type} className=\"mb-4\" />\n )}\n\n <ImageMembersTable\n projectId={projectId}\n image={image}\n imageMembers={imageMembers}\n isMembersLoading={isMembersLoading}\n canAdd={canCreateMember}\n canRemove={canDeleteMember}\n isAddingMember={isAddingMember}\n setIsAddingMember={setIsAddingMember}\n setMessage={setMessage}\n />\n </div>\n </Modal>\n )\n}\n","import { useState, ReactNode } from \"react\"\nimport { useProjectId } from \"@/client/hooks\"\nimport type { CreateImageInput, GlanceImage, ImageVisibility } from \"@/server/Compute/types/image\"\nimport {\n Checkbox,\n ContentHeading,\n DataGrid,\n DataGridCell,\n DataGridHeadCell,\n DataGridRow,\n Pagination,\n Spinner,\n Stack,\n Toast,\n ToastProps,\n} from \"@cloudoperators/juno-ui-components\"\nimport { trpcClient, trpcReact } from \"@/client/trpcClient\"\nimport { TRPCClientError } from \"@trpc/client\"\nimport { InferrableClientTypes } from \"@trpc/server/unstable-core-do-not-import\"\nimport { FastifyError } from \"fastify\"\nimport { Trans } from \"@lingui/react/macro\"\nimport { t } from \"@lingui/core/macro\"\nimport { EditImageDetailsModal } from \"./EditImageDetailsModal\"\nimport { EditImageMetadataModal } from \"./EditImageMetadataModal\"\nimport { ImageTableRow } from \"./ImageTableRow\"\nimport { DeleteImageModal } from \"./DeleteImageModal\"\nimport { DeactivateImageModal } from \"./DeactivateImageModal\"\nimport { ActivateImageModal } from \"./ActivateImageModal\"\nimport { CreateImageModal } from \"./CreateImageModal\"\nimport { DeleteImagesModal } from \"./DeleteImagesModal\"\nimport { DeactivateImagesModal } from \"./DeactivateImagesModal\"\nimport { ActivateImagesModal } from \"./ActivateImagesModal\"\nimport {\n getImageUpdatedToast,\n getImageUpdateErrorToast,\n getImageCreatedToast,\n getImageDeletedToast,\n getImageDeleteErrorToast,\n getImageActivatedToast,\n getImageDeactivatedToast,\n getImageActivationErrorToast,\n getImageDeactivationErrorToast,\n getBulkDeleteSuccessToast,\n getBulkDeleteErrorToast,\n getBulkDeletePartialToast,\n getBulkActivateSuccessToast,\n getBulkActivateErrorToast,\n getBulkActivatePartialToast,\n getBulkDeactivateSuccessToast,\n getBulkDeactivateErrorToast,\n getBulkDeactivatePartialToast,\n getImageCreateErrorToast,\n getImageFileUploadErrorToast,\n getImageVisibilityUpdatedToast,\n getImageVisibilityUpdateErrorToast,\n} from \"./ImageToastNotifications\"\nimport { ManageImageAccessModal } from \"./ManageImageAccessModal\"\nimport { IMAGE_STATUSES } from \"../../../-constants/filters\"\n\ninterface ImagePageProps {\n images: GlanceImage[]\n suggestedImages: GlanceImage[]\n acceptedImages: GlanceImage[]\n permissions: {\n canCreate: boolean\n canDelete: boolean\n canUpdate: boolean\n canCreateMember: boolean\n canDeleteMember: boolean\n canUpdateMember: boolean\n }\n isFetching?: boolean\n currentPage?: number\n totalPages?: number\n onPageChange?: (page: number) => void\n children?: ReactNode\n selectedImages: Array<string>\n setSelectedImages: (images: Array<string>) => void\n deleteAllModalOpen: boolean\n setDeleteAllModalOpen: (open: boolean) => void\n deactivateAllModalOpen: boolean\n setDeactivateAllModalOpen: (open: boolean) => void\n activateAllModalOpen: boolean\n setActivateAllModalOpen: (open: boolean) => void\n createModalOpen: boolean\n setCreateModalOpen: (open: boolean) => void\n deletableImages: Array<string>\n protectedImages: Array<string>\n activeImages: Array<string>\n deactivatedImages: Array<string>\n onImageUpdated: (image: GlanceImage) => void\n onImageDeleted: (imageIds: string | string[]) => void\n onMemberStatusChanged: () => void\n hasAnyBulkAction: boolean\n}\n\nexport function ImageListView({\n images,\n suggestedImages,\n acceptedImages,\n permissions,\n isFetching,\n currentPage = 1,\n totalPages = 1,\n onPageChange,\n children,\n selectedImages,\n setSelectedImages,\n deleteAllModalOpen,\n setDeleteAllModalOpen,\n deactivateAllModalOpen,\n setDeactivateAllModalOpen,\n activateAllModalOpen,\n setActivateAllModalOpen,\n createModalOpen,\n setCreateModalOpen,\n deletableImages,\n protectedImages,\n activeImages,\n deactivatedImages,\n onImageUpdated,\n onImageDeleted,\n onMemberStatusChanged,\n hasAnyBulkAction,\n}: ImagePageProps) {\n const projectId = useProjectId()\n const [toastData, setToastData] = useState<ToastProps | null>(null)\n\n const [editDetailsModalOpen, setEditDetailsModalOpen] = useState(false)\n const [editMetadataModalOpen, setEditMetadataModalOpen] = useState(false)\n const [deleteModalOpen, setDeleteModalOpen] = useState(false)\n const [deactivateModalOpen, setDeactivateModalOpen] = useState(false)\n const [activateModalOpen, setActivateModalOpen] = useState(false)\n const [manageAccessModalOpen, setManageAccessModalOpen] = useState(false)\n const [selectedImage, setSelectedImage] = useState<GlanceImage | null>(null)\n const [isCreateInProgress, setCreateInProgress] = useState(false)\n const [uploadId, setUploadId] = useState<string | null>(null)\n const [isUploadPending, setIsUploadPending] = useState(false)\n\n const utils = trpcReact.useUtils()\n\n const deleteImageMutation = trpcReact.compute.deleteImage.useMutation({\n onSuccess: () => {\n utils.compute.listImagesWithPagination.invalidate()\n },\n })\n\n const deactivateImageMutation = trpcReact.compute.deactivateImage.useMutation({\n onSuccess: () => {\n utils.compute.listImagesWithPagination.invalidate()\n utils.compute.getImageById.invalidate()\n },\n })\n\n const reactivateImageMutation = trpcReact.compute.reactivateImage.useMutation({\n onSuccess: () => {\n utils.compute.listImagesWithPagination.invalidate()\n utils.compute.getImageById.invalidate()\n },\n })\n\n const deleteImagesMutation = trpcReact.compute.deleteImages.useMutation({\n onSuccess: () => {\n utils.compute.listImagesWithPagination.invalidate()\n setSelectedImages([])\n },\n })\n\n const activateImagesMutation = trpcReact.compute.activateImages.useMutation({\n onSuccess: () => {\n utils.compute.listImagesWithPagination.invalidate()\n setSelectedImages([])\n },\n })\n\n const deactivateImagesMutation = trpcReact.compute.deactivateImages.useMutation({\n onSuccess: () => {\n utils.compute.listImagesWithPagination.invalidate()\n setSelectedImages([])\n },\n })\n\n const updateImageMutation = trpcReact.compute.updateImage.useMutation({\n onSuccess: (updatedImage) => {\n utils.compute.listImagesWithPagination.invalidate()\n utils.compute.getImageById.setData({ project_id: projectId, imageId: updatedImage.id }, updatedImage)\n },\n })\n\n const createImageMutation = trpcReact.compute.createImage.useMutation({\n onSuccess: () => {\n utils.compute.listImagesWithPagination.invalidate()\n },\n })\n\n const updateImageVisibilityMutation = trpcReact.compute.updateImageVisibility.useMutation({\n onSuccess: (updatedImage) => {\n onImageUpdated(updatedImage)\n },\n })\n\n const { data } = trpcReact.compute.watchUploadProgress.useSubscription(\n { project_id: projectId, uploadId: uploadId || \"\" },\n {\n enabled: !!uploadId && isUploadPending,\n }\n )\n\n const isLoading =\n deleteImageMutation.isPending ||\n deactivateImageMutation.isPending ||\n reactivateImageMutation.isPending ||\n deleteImagesMutation.isPending ||\n activateImagesMutation.isPending ||\n deactivateImagesMutation.isPending ||\n updateImageMutation.isPending\n\n const handleToastDismiss = () => setToastData(null)\n\n const handleUpdateImageVisibility = async (imageId: string, newVisibility: ImageVisibility, imageName: string) => {\n try {\n await updateImageVisibilityMutation.mutateAsync({\n project_id: projectId,\n imageId,\n visibility: newVisibility,\n })\n\n setToastData(\n getImageVisibilityUpdatedToast(imageName, newVisibility, {\n onDismiss: handleToastDismiss,\n })\n )\n } catch (error) {\n const errorMessage =\n (error as TRPCClientError<InferrableClientTypes>)?.message || t`Failed to update visibility to ${newVisibility}`\n\n setToastData(\n getImageVisibilityUpdateErrorToast(imageName, errorMessage, {\n onDismiss: handleToastDismiss,\n })\n )\n }\n }\n\n /**\n * Converts partial image properties to OpenStack JSON Patch operations\n * Determines whether to use 'add', 'replace', or 'remove' based on original image state\n */\n const convertToJsonPatchOperations = (\n updatedProperties: Partial<GlanceImage>,\n originalImage: GlanceImage\n ): Array<{ op: \"add\" | \"replace\" | \"remove\"; path: string; value?: unknown }> => {\n const operations: Array<{ op: \"add\" | \"replace\" | \"remove\"; path: string; value?: unknown }> = []\n\n Object.entries(updatedProperties).forEach(([key, value]) => {\n const path = `/${key}`\n\n if (value === null || value === undefined) {\n // Remove operation for null/undefined values (only if property exists)\n if (key in originalImage) {\n operations.push({ op: \"remove\", path })\n }\n } else {\n // Check if property exists in original image\n const propertyExists = key in originalImage\n\n if (propertyExists) {\n // Use 'replace' for existing properties\n operations.push({ op: \"replace\", path, value })\n } else {\n // Use 'add' for new properties\n operations.push({ op: \"add\", path, value })\n }\n }\n })\n\n return operations\n }\n\n const handleSaveEdit = async (updatedProperties: Partial<GlanceImage>): Promise<boolean> => {\n if (!selectedImage) return false\n\n const imageId = selectedImage.id\n const imageName = updatedProperties.name || selectedImage.name || imageId\n\n try {\n const operations = convertToJsonPatchOperations(updatedProperties, selectedImage)\n const updatedImage = await updateImageMutation.mutateAsync({ project_id: projectId, imageId, operations })\n setEditDetailsModalOpen(false)\n setToastData(getImageUpdatedToast(imageName, { onDismiss: handleToastDismiss }))\n setSelectedImage(updatedImage)\n onImageUpdated(updatedImage)\n return true\n } catch (error) {\n const { message } = error as TRPCClientError<InferrableClientTypes>\n setToastData(getImageUpdateErrorToast(imageName, message, { onDismiss: handleToastDismiss }))\n setSelectedImage(null)\n return false\n }\n }\n\n const handleCreate = async (imageData: Omit<CreateImageInput, \"project_id\">, file: File) => {\n const imageName = imageData.name || \"Unnamed\"\n\n try {\n setCreateInProgress(true)\n\n // Step 1: Create image with project_id\n const createdImage = await createImageMutation.mutateAsync({\n project_id: projectId,\n ...imageData,\n })\n\n // Step 2: Upload file via octetInputParser with metadata in custom headers.\n // trpcClient (vanilla) is used so we can pass operation context with headers.\n setUploadId(createdImage.id)\n setIsUploadPending(true)\n\n await trpcClient.compute.uploadImage.mutate(file, {\n context: {\n headers: {\n \"x-project-id\": projectId,\n \"x-upload-id\": createdImage.id,\n \"x-upload-size\": String(file.size),\n },\n },\n })\n\n // Show success notification and re-fetch image list\n setToastData(getImageCreatedToast(imageName, { onDismiss: handleToastDismiss }))\n utils.compute.listImagesWithPagination.invalidate()\n } catch (error) {\n // Show error notification based on failure point\n if (error instanceof TRPCClientError && error.data.path === \"compute.createImage\") {\n setToastData(getImageCreateErrorToast(imageName, error.message, { onDismiss: handleToastDismiss }))\n } else {\n // File upload failed\n const { message } = error as FastifyError\n\n setToastData(getImageFileUploadErrorToast(file.name, message, { onDismiss: handleToastDismiss }))\n }\n } finally {\n // Complete creation and close modal\n setCreateInProgress(false)\n setCreateModalOpen(false)\n setIsUploadPending(false)\n setUploadId(null)\n }\n }\n\n const handleDelete = async (deletedImage: GlanceImage) => {\n setEditDetailsModalOpen(false)\n setEditMetadataModalOpen(false)\n\n const imageName = deletedImage.name || deletedImage.id\n const imageId = deletedImage.id\n\n try {\n await deleteImageMutation.mutateAsync({ project_id: projectId, imageId })\n\n setToastData(getImageDeletedToast(imageName, { onDismiss: handleToastDismiss }))\n onImageDeleted(imageId)\n } catch (error) {\n const { message } = error as TRPCClientError<InferrableClientTypes>\n\n setToastData(getImageDeleteErrorToast(imageId, message, { onDismiss: handleToastDismiss }))\n }\n\n setSelectedImage(null)\n }\n\n const handleActivationStatusChange = async (updatedImage: GlanceImage) => {\n if (updatedImage.status !== IMAGE_STATUSES.DEACTIVATED) {\n // Deactivate: show confirmation modal\n setSelectedImage(updatedImage)\n setDeactivateModalOpen(true)\n } else {\n // Activate: show confirmation modal\n setSelectedImage(updatedImage)\n setActivateModalOpen(true)\n }\n }\n\n const handleActivateSingle = async (image: GlanceImage) => {\n const imageName = image.name || image.id\n const imageId = image.id\n\n try {\n await reactivateImageMutation.mutateAsync({ project_id: projectId, imageId })\n setActivateModalOpen(false)\n setSelectedImage(null)\n setToastData(getImageActivatedToast(imageName, { onDismiss: handleToastDismiss }))\n } catch (error) {\n const { message } = error as TRPCClientError<InferrableClientTypes>\n setToastData(getImageActivationErrorToast(imageId, message, { onDismiss: handleToastDismiss }))\n }\n }\n\n const handleDeactivateSingle = async (image: GlanceImage) => {\n const imageName = image.name || image.id\n const imageId = image.id\n\n try {\n await deactivateImageMutation.mutateAsync({ project_id: projectId, imageId })\n setDeactivateModalOpen(false)\n setSelectedImage(null)\n setToastData(getImageDeactivatedToast(imageName, { onDismiss: handleToastDismiss }))\n } catch (error) {\n const { message } = error as TRPCClientError<InferrableClientTypes>\n setToastData(getImageDeactivationErrorToast(imageId, message, { onDismiss: handleToastDismiss }))\n }\n }\n\n const openEditDetailsModal = (image: GlanceImage) => {\n setSelectedImage(image)\n setEditDetailsModalOpen(true)\n }\n\n const openEditMetadataModal = (image: GlanceImage) => {\n setSelectedImage(image)\n setEditMetadataModalOpen(true)\n }\n\n const openDeleteModal = (image: GlanceImage) => {\n setSelectedImage(image)\n setDeleteModalOpen(true)\n }\n\n const openManageAccessModal = (image: GlanceImage) => {\n setSelectedImage(image)\n setManageAccessModalOpen(true)\n }\n\n const closeEditDetailsModal = () => {\n setSelectedImage(null)\n setEditDetailsModalOpen(false)\n }\n\n const closeEditMetadataModal = () => {\n setSelectedImage(null)\n setEditMetadataModalOpen(false)\n }\n\n const closeDeleteModal = () => {\n setSelectedImage(null)\n setDeleteModalOpen(false)\n }\n\n const closeDeactivateModal = () => {\n setSelectedImage(null)\n setDeactivateModalOpen(false)\n }\n\n const closeActivateModal = () => {\n setSelectedImage(null)\n setActivateModalOpen(false)\n }\n\n const closeManageAccessModal = () => {\n setSelectedImage(null)\n setManageAccessModalOpen(false)\n }\n\n const handleBulkDelete = async (imageIds: Array<string>) => {\n setDeleteAllModalOpen(false)\n\n try {\n const result = await deleteImagesMutation.mutateAsync({ project_id: projectId, imageIds })\n\n const successCount = result.successful.length\n const failedCount = result.failed.length\n const totalCount = imageIds.length\n\n if (failedCount === 0) {\n setToastData(getBulkDeleteSuccessToast(successCount, totalCount, { onDismiss: handleToastDismiss }))\n } else if (successCount === 0) {\n setToastData(getBulkDeleteErrorToast(failedCount, totalCount, { onDismiss: handleToastDismiss }))\n } else {\n setToastData(getBulkDeletePartialToast(successCount, failedCount, { onDismiss: handleToastDismiss }))\n }\n\n if (result.successful.length > 0) onImageDeleted(result.successful)\n } catch (error) {\n const { message } = error as TRPCClientError<InferrableClientTypes>\n\n console.log(\"Bulk delete error: \", message)\n\n setToastData(\n getBulkDeleteErrorToast(imageIds.length, imageIds.length, {\n onDismiss: handleToastDismiss,\n })\n )\n }\n }\n\n const handleBulkActivate = async (imageIds: Array<string>) => {\n setActivateAllModalOpen(false)\n\n try {\n const result = await activateImagesMutation.mutateAsync({ project_id: projectId, imageIds })\n\n const successCount = result.successful.length\n const failedCount = result.failed.length\n const totalCount = imageIds.length\n\n if (failedCount === 0) {\n setToastData(getBulkActivateSuccessToast(successCount, totalCount, { onDismiss: handleToastDismiss }))\n } else if (successCount === 0) {\n setToastData(getBulkActivateErrorToast(failedCount, totalCount, { onDismiss: handleToastDismiss }))\n } else {\n setToastData(getBulkActivatePartialToast(successCount, failedCount, { onDismiss: handleToastDismiss }))\n }\n } catch (error) {\n const { message } = error as TRPCClientError<InferrableClientTypes>\n\n console.log(\"Bulk activate error: \", message)\n\n setToastData(\n getBulkActivateErrorToast(imageIds.length, imageIds.length, {\n onDismiss: handleToastDismiss,\n })\n )\n }\n }\n\n const handleBulkDeactivate = async (imageIds: Array<string>) => {\n setDeactivateAllModalOpen(false)\n\n try {\n const result = await deactivateImagesMutation.mutateAsync({ project_id: projectId, imageIds })\n\n const successCount = result.successful.length\n const failedCount = result.failed.length\n const totalCount = imageIds.length\n\n if (failedCount === 0) {\n setToastData(getBulkDeactivateSuccessToast(successCount, totalCount, { onDismiss: handleToastDismiss }))\n } else if (successCount === 0) {\n setToastData(getBulkDeactivateErrorToast(failedCount, totalCount, { onDismiss: handleToastDismiss }))\n } else {\n setToastData(getBulkDeactivatePartialToast(successCount, failedCount, { onDismiss: handleToastDismiss }))\n }\n } catch (error) {\n const { message } = error as TRPCClientError<InferrableClientTypes>\n\n console.log(\"Bulk deactivate error: \", message)\n\n setToastData(\n getBulkDeactivateErrorToast(imageIds.length, imageIds.length, {\n onDismiss: handleToastDismiss,\n })\n )\n }\n }\n\n if (isLoading) {\n return (\n <div data-testid=\"loading\">\n <DataGridRow>\n <DataGridCell colSpan={3}>\n <Stack distribution=\"center\" alignment=\"center\">\n <Spinner variant=\"primary\" />\n <Trans>Loading...</Trans>\n </Stack>\n </DataGridCell>\n </DataGridRow>\n </div>\n )\n }\n\n return (\n <>\n <>{children}</>\n\n <div className=\"relative\">\n {/* Loading overlay when refetching */}\n {isFetching && (\n <div className=\"bg-theme-background-lvl-0/50 absolute inset-0 z-10 flex items-center justify-center backdrop-blur-sm\">\n <Stack direction=\"vertical\" alignment=\"center\" gap=\"2\">\n <Spinner variant=\"primary\" size=\"large\" />\n <span className=\"text-theme-high font-medium\">\n <Trans>Loading images...</Trans>\n </span>\n </Stack>\n </div>\n )}\n\n {/* Images Table */}\n {images.length > 0 ? (\n <>\n <DataGrid\n columns={hasAnyBulkAction ? 9 : 8}\n minContentColumns={hasAnyBulkAction ? [0, 8] : [7]}\n className=\"images\"\n data-testid=\"images-table\"\n >\n {/* Table Header */}\n <DataGridRow>\n {hasAnyBulkAction && (\n <DataGridHeadCell>\n <Checkbox\n checked={(() => {\n const currentPageIds = images.map((image) => image.id)\n return currentPageIds.length > 0 && currentPageIds.every((id) => selectedImages.includes(id))\n })()}\n onChange={() => {\n const currentPageIds = images.map((image) => image.id)\n const allSelected = currentPageIds.every((id) => selectedImages.includes(id))\n if (allSelected) {\n return setSelectedImages(selectedImages.filter((id) => !currentPageIds.includes(id)))\n }\n return setSelectedImages([...new Set([...selectedImages, ...currentPageIds])])\n }}\n />\n </DataGridHeadCell>\n )}\n <DataGridHeadCell>\n <Trans>Status</Trans>\n </DataGridHeadCell>\n <DataGridHeadCell>\n <Trans>Image Name</Trans>\n </DataGridHeadCell>\n <DataGridHeadCell>\n <Trans>Visibility</Trans>\n </DataGridHeadCell>\n <DataGridHeadCell>\n <Trans>Protected</Trans>\n </DataGridHeadCell>\n <DataGridHeadCell>\n <Trans>Size</Trans>\n </DataGridHeadCell>\n <DataGridHeadCell>\n <Trans>Disk Format</Trans>\n </DataGridHeadCell>\n <DataGridHeadCell>\n <Trans>Created</Trans>\n </DataGridHeadCell>\n <DataGridHeadCell />\n </DataGridRow>\n\n {/* Table Body */}\n {images.map((image) => (\n <ImageTableRow\n image={image}\n isSelected={selectedImages.includes(image.id)}\n isPending={!!suggestedImages.find(({ id: imageId }) => imageId === image.id)}\n isAccepted={!!acceptedImages.find(({ id: imageId }) => imageId === image.id)}\n key={image.id}\n permissions={permissions}\n onEditDetails={openEditDetailsModal}\n onEditMetadata={openEditMetadataModal}\n onDelete={openDeleteModal}\n onManageAccess={openManageAccessModal}\n showSelectColumn={hasAnyBulkAction}\n onSelect={(image: GlanceImage) => {\n const isImageSelected = selectedImages.includes(image.id)\n\n if (isImageSelected) {\n return setSelectedImages(selectedImages.filter((imageId) => imageId !== image.id))\n }\n\n setSelectedImages([...selectedImages, image.id])\n }}\n onActivationStatusChange={handleActivationStatusChange}\n onUpdateVisibility={handleUpdateImageVisibility}\n setToastData={setToastData}\n uploadId={uploadId}\n uploadProgressPercent={data?.percent}\n onMemberStatusChanged={onMemberStatusChanged}\n />\n ))}\n </DataGrid>\n\n {/* Pagination */}\n {totalPages > 1 && (\n <div className=\"flex justify-center py-4\">\n <Pagination\n variant=\"input\"\n currentPage={currentPage}\n pages={totalPages}\n onPressPrevious={() => onPageChange?.(Math.max(currentPage - 1, 1))}\n onPressNext={() => onPageChange?.(Math.min(currentPage + 1, totalPages))}\n onSelectChange={(page) => onPageChange?.(page)}\n />\n </div>\n )}\n </>\n ) : (\n <DataGrid columns={7} minContentColumns={[0, 6]} className=\"images\" data-testid=\"no-images\">\n <DataGridRow>\n <DataGridCell colSpan={7}>\n <ContentHeading>\n <Trans>No images found</Trans>\n </ContentHeading>\n <p>\n <Trans>\n There are no images available for this project with the current filters applied. Try adjusting your\n filter criteria or create a new image.\n </Trans>\n </p>\n </DataGridCell>\n </DataGridRow>\n </DataGrid>\n )}\n {selectedImage && (\n <>\n <EditImageDetailsModal\n isOpen={editDetailsModalOpen}\n onClose={closeEditDetailsModal}\n image={selectedImage}\n onSave={handleSaveEdit}\n isLoading={updateImageMutation.isPending}\n />\n <EditImageMetadataModal\n isOpen={editMetadataModalOpen}\n onClose={closeEditMetadataModal}\n image={selectedImage}\n onSave={handleSaveEdit}\n isLoading={updateImageMutation.isPending}\n />\n <DeleteImageModal\n image={selectedImage}\n isOpen={deleteModalOpen}\n isLoading={isLoading}\n isDisabled={selectedImage.protected || !permissions.canDelete}\n onClose={closeDeleteModal}\n onDelete={handleDelete}\n />\n <DeactivateImageModal\n image={selectedImage}\n isOpen={deactivateModalOpen}\n isLoading={deactivateImageMutation.isPending}\n onClose={closeDeactivateModal}\n onDeactivate={handleDeactivateSingle}\n />\n <ActivateImageModal\n image={selectedImage}\n isOpen={activateModalOpen}\n isLoading={reactivateImageMutation.isPending}\n onClose={closeActivateModal}\n onActivate={handleActivateSingle}\n />\n <ManageImageAccessModal\n image={selectedImage}\n isOpen={manageAccessModalOpen}\n onClose={closeManageAccessModal}\n permissions={permissions}\n />\n </>\n )}\n\n <DeleteImagesModal\n isOpen={deleteAllModalOpen}\n deletableImages={deletableImages}\n protectedImages={protectedImages}\n isLoading={isLoading}\n onClose={() => setDeleteAllModalOpen(false)}\n onDelete={handleBulkDelete}\n />\n <DeactivateImagesModal\n isOpen={deactivateAllModalOpen}\n activeImages={activeImages}\n deactivatedImages={deactivatedImages}\n isLoading={isLoading}\n onClose={() => setDeactivateAllModalOpen(false)}\n onDeactivate={handleBulkDeactivate}\n />\n <ActivateImagesModal\n isOpen={activateAllModalOpen}\n deactivatedImages={deactivatedImages}\n activeImages={activeImages}\n isLoading={isLoading}\n onClose={() => setActivateAllModalOpen(false)}\n onActivate={handleBulkActivate}\n />\n <CreateImageModal\n isOpen={createModalOpen}\n onClose={() => {\n if (uploadId) {\n utils.compute.listImagesWithPagination.invalidate()\n }\n\n setCreateModalOpen(false)\n }}\n onCreate={handleCreate}\n isLoading={createImageMutation.isPending || isUploadPending || isCreateInProgress}\n isUploadPending={isUploadPending && !!uploadId}\n uploadProgressPercent={data?.percent}\n />\n </div>\n\n {toastData && (\n <Toast {...toastData} className=\"border-theme-light fixed top-5 right-5 z-50 rounded-lg border shadow-lg\" />\n )}\n </>\n )\n}\n","import { SelectedFilter, Filter } from \"@/client/components/ListToolbar/types\"\n\ntype ImagesSearchParams = {\n status?: string\n visibility?: string\n disk_format?: string\n container_format?: string\n protected?: string\n search?: string\n sortBy?: string\n sortDirection?: \"asc\" | \"desc\"\n memberStatus?: \"all\" | \"accepted\" | \"pending\"\n}\n\n/**\n * Parses URL search params into SelectedFilter array for ListToolbar\n */\nexport const parseFiltersFromUrl = (searchParams: ImagesSearchParams): SelectedFilter[] => {\n const filters: SelectedFilter[] = []\n\n // Status filter\n if (searchParams.status) {\n const values = searchParams.status.startsWith(\"in:\")\n ? searchParams.status.replace(\"in:\", \"\").split(\",\")\n : [searchParams.status]\n values.forEach((value: string) => {\n filters.push({ name: \"status\", value })\n })\n }\n\n // Visibility filter\n if (searchParams.visibility) {\n filters.push({ name: \"visibility\", value: searchParams.visibility })\n }\n\n // Disk format filter\n if (searchParams.disk_format) {\n const values = searchParams.disk_format.startsWith(\"in:\")\n ? searchParams.disk_format.replace(\"in:\", \"\").split(\",\")\n : [searchParams.disk_format]\n values.forEach((value: string) => {\n filters.push({ name: \"disk_format\", value })\n })\n }\n\n // Container format filter\n if (searchParams.container_format) {\n const values = searchParams.container_format.startsWith(\"in:\")\n ? searchParams.container_format.replace(\"in:\", \"\").split(\",\")\n : [searchParams.container_format]\n values.forEach((value: string) => {\n filters.push({ name: \"container_format\", value })\n })\n }\n\n // Protected filter\n if (searchParams.protected) {\n filters.push({ name: \"protected\", value: searchParams.protected })\n }\n\n return filters\n}\n\n/**\n * Builds filter parameters for API request from SelectedFilter array\n */\nexport const buildFilterParams = (\n selectedFilters: SelectedFilter[],\n filterDefinitions: Filter[]\n): Record<string, string> => {\n const params: Record<string, string> = {}\n\n if (!selectedFilters?.length) return params\n\n // Group selected filters by filter name\n const filterGroups = selectedFilters\n .filter((sf) => !sf.inactive)\n .reduce(\n (acc, sf) => {\n if (!acc[sf.name]) acc[sf.name] = []\n acc[sf.name].push(sf.value)\n return acc\n },\n {} as Record<string, string[]>\n )\n\n // Build parameters based on whether filter supports multiple values\n Object.entries(filterGroups).forEach(([filterName, values]) => {\n const filterDef = filterDefinitions.find((f) => f.filterName === filterName)\n\n if (filterDef?.supportsMultiValue && values.length > 1) {\n params[filterName] = `in:${values.join(\",\")}`\n } else {\n params[filterName] = values[0]\n }\n })\n\n return params\n}\n\n/**\n * Merges a newly selected filter into the current list.\n * - Ignores duplicates (same name + value).\n * - For single-value filters, replaces any existing entry with the same name.\n * - For multi-value filters, appends.\n */\nexport const applyFilterSelection = (\n current: SelectedFilter[],\n selected: SelectedFilter,\n filterDefinitions: Filter[]\n): SelectedFilter[] => {\n const alreadySelected = current.some((f) => f.name === selected.name && f.value === selected.value)\n if (alreadySelected) return current\n\n const supportsMulti = filterDefinitions.find((f) => f.filterName === selected.name)?.supportsMultiValue\n return supportsMulti ? [...current, selected] : [...current.filter((f) => f.name !== selected.name), selected]\n}\n\n/**\n * Builds URL search params object from filter settings for navigation\n */\nexport const buildUrlSearchParams = (\n selectedFilters: SelectedFilter[],\n filterDefinitions: Filter[],\n baseParams: {\n search?: string\n sortBy?: string\n sortDirection?: \"asc\" | \"desc\"\n memberStatus?: \"all\" | \"accepted\" | \"pending\"\n }\n): ImagesSearchParams => {\n const newParams: ImagesSearchParams = {\n search: baseParams.search,\n sortBy: baseParams.sortBy,\n sortDirection: baseParams.sortDirection,\n memberStatus: baseParams.memberStatus === \"all\" ? undefined : baseParams.memberStatus,\n }\n\n if (!selectedFilters?.length) return newParams\n\n const filterGroups = selectedFilters\n .filter((sf) => !sf.inactive)\n .reduce(\n (acc, sf) => {\n if (!acc[sf.name]) acc[sf.name] = []\n acc[sf.name].push(sf.value)\n return acc\n },\n {} as Record<string, string[]>\n )\n\n Object.entries(filterGroups).forEach(([filterName, values]) => {\n const filterDef = filterDefinitions.find((f) => f.filterName === filterName)\n\n if (filterDef?.supportsMultiValue && values.length > 1) {\n // Type assertion needed because we're dynamically setting filter fields\n ;(newParams as Record<string, string>)[filterName] = `in:${values.join(\",\")}`\n } else {\n ;(newParams as Record<string, string>)[filterName] = values[0]\n }\n })\n\n return newParams\n}\n","import { TrpcClient } from \"@/client/trpcClient\"\nimport { TRPCClientError } from \"@trpc/client\"\n\ntype ImageFilters = {\n status?: string\n visibility?: \"public\" | \"private\" | \"shared\" | \"community\" | \"all\"\n disk_format?: string\n container_format?: string\n protected?: string\n member_status?: \"pending\" | \"accepted\" | \"rejected\" | \"all\"\n}\n\nconst emptyResult = {\n images: [],\n first: undefined,\n next: undefined,\n schema: \"/v2/schemas/images\",\n listError: undefined as string | undefined,\n}\n\nexport const createImagesPromise = (\n client: TrpcClient,\n project: string,\n sortBy: string,\n sortDirection: string,\n searchTerm: string,\n filters: ImageFilters\n) => {\n if (filters.member_status && filters.member_status !== \"all\") {\n return client.compute.listSharedImagesByMemberStatus\n .query({\n project_id: project,\n memberStatus: filters.member_status,\n name: searchTerm || undefined,\n status: filters.status,\n disk_format: filters.disk_format,\n container_format: filters.container_format,\n protected: filters.protected,\n sort: `${sortBy}:${sortDirection}`,\n })\n .then((images) => ({ ...emptyResult, images }))\n .catch((err: unknown) => {\n if (err instanceof TRPCClientError && err.data?.code === \"FORBIDDEN\") {\n return { ...emptyResult, listError: err.message }\n }\n throw err\n })\n }\n\n return client.compute.listImagesWithSearch\n .query({\n project_id: project,\n sort: `${sortBy}:${sortDirection}`,\n name: searchTerm || undefined,\n ...filters,\n member_status: undefined,\n })\n .then((res) => ({ ...res, listError: undefined }))\n .catch((err: unknown) => {\n if (err instanceof TRPCClientError && err.data?.code === \"FORBIDDEN\") {\n return { ...emptyResult, listError: err.message }\n }\n throw err\n })\n}\n\nexport const createPermissionsPromise = (client: TrpcClient, project: string) => {\n return client.compute.canUser\n .query({\n project_id: project,\n permission: [\n \"images:create\",\n \"images:delete\",\n \"images:update\",\n \"images:create_member\",\n \"images:delete_member\",\n \"images:update_member\",\n ],\n })\n .then(([canCreate, canDelete, canUpdate, canCreateMember, canDeleteMember, canUpdateMember]) => ({\n canCreate,\n canDelete,\n canUpdate,\n canCreateMember,\n canDeleteMember,\n canUpdateMember: canUpdateMember ?? false,\n }))\n}\n","import { use, Suspense, useState, startTransition, useEffect, useRef, ReactNode, useCallback } from \"react\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { TrpcClient } from \"@/client/trpcClient\"\nimport { GlanceImage } from \"@/server/Compute/types/image\"\nimport { useNavigate, useSearch } from \"@tanstack/react-router\"\nimport {\n Button,\n Stack,\n Spinner,\n PopupMenu,\n PopupMenuItem,\n PopupMenuToggle,\n PopupMenuOptions,\n DataGridToolbar,\n SearchInput,\n Checkbox,\n TabNavigation,\n TabNavigationItem,\n} from \"@cloudoperators/juno-ui-components\"\nimport { SortInput } from \"@/client/components/ListToolbar/SortInput\"\nimport { SelectedFilters } from \"@/client/components/ListToolbar/SelectedFilters\"\nimport { FiltersInput } from \"@/client/components/ListToolbar/FiltersInput\"\nimport { FilterSettings, SortSettings } from \"@/client/components/ListToolbar/types\"\nimport { ImageListView } from \"./-components/ImageListView\"\nimport { CONTAINER_FORMATS, DISK_FORMATS, IMAGE_STATUSES, IMAGE_VISIBILITY } from \"../../-constants/filters\"\nimport { parseFiltersFromUrl, buildFilterParams, buildUrlSearchParams, applyFilterSelection } from \"./urlHelpers\"\nimport { createImagesPromise, createPermissionsPromise } from \"./apiHelpers\"\n\nconst PAGE_SIZE = 50\n\ninterface ImagesProps {\n client: TrpcClient\n project: string\n}\n\ntype ImagesSearchParams = {\n status?: string\n visibility?: string\n disk_format?: string\n container_format?: string\n protected?: string\n search?: string\n sortBy?: string\n sortDirection?: \"asc\" | \"desc\"\n memberStatus?: \"all\" | \"accepted\" | \"pending\"\n page?: number\n}\n\ntype RequiredSortSettings = {\n options: SortSettings[\"options\"]\n sortBy: string\n sortDirection: \"asc\" | \"desc\"\n}\n\ntype ImagesResult = {\n images: GlanceImage[]\n first?: string\n next?: string\n schema: string\n listError?: string\n}\n\ntype ImagesContentProps = {\n imagesPromise: Promise<ImagesResult>\n imageOverrides: Map<string, GlanceImage>\n deletedImageIds: Set<string>\n permissionsPromise: Promise<{\n canCreate: boolean\n canDelete: boolean\n canUpdate: boolean\n canCreateMember: boolean\n canDeleteMember: boolean\n canUpdateMember: boolean\n }>\n searchTerm: string\n setSearchTerm: (term: string) => void\n sortSettings: SortSettings\n handleSortChange: (settings: SortSettings) => void\n filterSettings: FilterSettings\n handleFilterChange: (settings: FilterSettings) => void\n selectedImages: Array<string>\n setSelectedImages: (images: Array<string>) => void\n createModalOpen: boolean\n setCreateModalOpen: (open: boolean) => void\n deleteAllModalOpen: boolean\n setDeleteAllModalOpen: (open: boolean) => void\n deactivateAllModalOpen: boolean\n setDeactivateAllModalOpen: (open: boolean) => void\n activateAllModalOpen: boolean\n setActivateAllModalOpen: (open: boolean) => void\n memberStatusView: \"all\" | \"pending\" | \"accepted\"\n setMemberStatusView: (view: \"all\" | \"pending\" | \"accepted\") => void\n isFetching: boolean\n currentPage: number\n onPageChange: (page: number) => void\n onImageUpdated: (image: GlanceImage) => void\n onImageDeleted: (imageIds: string | string[]) => void\n onMemberStatusChanged: () => void\n}\n\nfunction ImagesContent({\n imagesPromise,\n imageOverrides,\n deletedImageIds,\n permissionsPromise,\n searchTerm,\n setSearchTerm,\n sortSettings,\n handleSortChange,\n filterSettings,\n handleFilterChange,\n selectedImages,\n setSelectedImages,\n createModalOpen,\n setCreateModalOpen,\n deleteAllModalOpen,\n setDeleteAllModalOpen,\n deactivateAllModalOpen,\n setDeactivateAllModalOpen,\n activateAllModalOpen,\n setActivateAllModalOpen,\n memberStatusView,\n setMemberStatusView,\n isFetching,\n currentPage,\n onPageChange,\n onImageUpdated,\n onImageDeleted,\n onMemberStatusChanged,\n}: ImagesContentProps) {\n const { t } = useLingui()\n const imagesData = use(imagesPromise)\n const permissions = use(permissionsPromise)\n const [localSearchTerm, setLocalSearchTerm] = useState(searchTerm)\n const debounceTimer = useRef<number | undefined>(undefined)\n\n useEffect(() => () => clearTimeout(debounceTimer.current), [])\n\n if (imagesData.listError) {\n return <p>{imagesData.listError}</p>\n }\n\n const images = imagesData.images\n .filter((img) => !deletedImageIds.has(img.id))\n .map((img) => imageOverrides.get(img.id) ?? img)\n\n const totalPages = Math.max(1, Math.ceil(images.length / PAGE_SIZE))\n const safePage = Math.min(currentPage, totalPages)\n const paginatedImages = images.slice((safePage - 1) * PAGE_SIZE, safePage * PAGE_SIZE)\n\n useEffect(() => {\n if (currentPage !== 1 && currentPage > totalPages) onPageChange(1)\n }, [totalPages, currentPage, onPageChange])\n\n const activeFilterSettings =\n memberStatusView === \"pending\" || memberStatusView === \"accepted\"\n ? {\n ...filterSettings,\n filters: filterSettings.filters.filter((f) => f.filterName !== \"visibility\"),\n selectedFilters: (filterSettings.selectedFilters || []).filter((f) => f.name !== \"visibility\"),\n }\n : filterSettings\n\n const displayedImageIds = new Set(images.map((image: GlanceImage) => image.id))\n const validSelectedImages = selectedImages.filter((imageId) => displayedImageIds.has(imageId))\n\n const deletableImages = validSelectedImages.filter((imageId) => {\n const image = images.find((image: GlanceImage) => image.id === imageId)\n return image && !image.protected\n })\n const protectedImages = validSelectedImages.filter((imageId) => {\n const image = images.find((image: GlanceImage) => image.id === imageId)\n return image && image.protected\n })\n const activeImages = validSelectedImages.filter((imageId) => {\n const image = images.find((image: GlanceImage) => image.id === imageId)\n return image && image.status === IMAGE_STATUSES.ACTIVE\n })\n const deactivatedImages = validSelectedImages.filter((imageId) => {\n const image = images.find((image: GlanceImage) => image.id === imageId)\n return image && image.status === IMAGE_STATUSES.DEACTIVATED\n })\n\n const isDeleteAllDisabled =\n !permissions.canDelete ||\n validSelectedImages.length === 0 ||\n images\n .filter((image: GlanceImage) => validSelectedImages.includes(image.id))\n .every((image: GlanceImage) => image.protected)\n const isDeactivateAllDisabled =\n !permissions.canUpdate ||\n validSelectedImages.length === 0 ||\n images\n .filter((image: GlanceImage) => validSelectedImages.includes(image.id))\n .every((image: GlanceImage) => image.status === IMAGE_STATUSES.DEACTIVATED)\n const isActivateAllDisabled =\n !permissions.canUpdate ||\n validSelectedImages.length === 0 ||\n images\n .filter((image: GlanceImage) => validSelectedImages.includes(image.id))\n .every((image: GlanceImage) => image.status === IMAGE_STATUSES.ACTIVE)\n\n const memberStatusTabs = {\n items: [\n { label: t`All Images`, value: \"all\" },\n { label: t`Accepted Images`, value: \"accepted\" },\n { label: t`Suggested Images`, value: \"pending\" },\n ],\n activeItem: memberStatusView,\n onActiveItemChange: (value: ReactNode) => setMemberStatusView(value as \"all\" | \"pending\" | \"accepted\"),\n }\n\n return (\n <>\n {/* Zone 1 — tabs + sort + create / more actions, no background */}\n <Stack distribution=\"between\" alignment=\"center\" gap=\"2\">\n <TabNavigation activeItem={memberStatusView} onActiveItemChange={memberStatusTabs.onActiveItemChange}>\n {memberStatusTabs.items.map((item) => (\n <TabNavigationItem key={item.value} label={item.label} value={item.value} />\n ))}\n </TabNavigation>\n <Stack gap=\"0.5\" alignment=\"center\">\n <SortInput\n options={sortSettings.options}\n sortBy={sortSettings.sortBy}\n sortDirection={sortSettings.sortDirection ?? \"desc\"}\n onSortByChange={(v) =>\n handleSortChange({ ...sortSettings, sortBy: v, sortDirection: sortSettings.sortDirection })\n }\n onSortDirectionChange={(dir) => handleSortChange({ ...sortSettings, sortDirection: dir })}\n />\n {permissions.canCreate && (\n <Button onClick={() => setCreateModalOpen(true)} variant=\"primary\">\n <Trans>Create Image</Trans>\n </Button>\n )}\n </Stack>\n </Stack>\n\n {/* Zone 2 — filter + search + active filter pills */}\n <DataGridToolbar>\n <Stack direction=\"vertical\" gap=\"2\">\n <Stack distribution=\"between\" alignment=\"center\">\n <FiltersInput\n filters={activeFilterSettings.filters}\n onChange={(selected) => {\n const newSelected = applyFilterSelection(\n activeFilterSettings.selectedFilters || [],\n selected,\n activeFilterSettings.filters\n )\n if (newSelected === (activeFilterSettings.selectedFilters || [])) return\n handleFilterChange({ ...filterSettings, selectedFilters: newSelected })\n }}\n />\n <SearchInput\n placeholder={t`Search images...`}\n data-testid=\"searchbar\"\n value={localSearchTerm}\n onInput={(e: React.FormEvent<HTMLInputElement>) => {\n const v = e.currentTarget.value\n setLocalSearchTerm(v)\n clearTimeout(debounceTimer.current)\n debounceTimer.current = window.setTimeout(() => setSearchTerm(v), 500)\n }}\n onSearch={(v) => {\n clearTimeout(debounceTimer.current)\n setSearchTerm(typeof v === \"string\" ? v : \"\")\n }}\n onClear={() => {\n clearTimeout(debounceTimer.current)\n setLocalSearchTerm(\"\")\n setSearchTerm(\"\")\n }}\n />\n </Stack>\n {activeFilterSettings.selectedFilters && activeFilterSettings.selectedFilters.length > 0 && (\n <SelectedFilters\n selectedFilters={activeFilterSettings.selectedFilters}\n onDelete={(filterToRemove) =>\n handleFilterChange({\n ...filterSettings,\n selectedFilters: (filterSettings.selectedFilters || []).filter(\n (f) => !(f.name === filterToRemove.name && f.value === filterToRemove.value)\n ),\n })\n }\n onClear={() => handleFilterChange({ ...filterSettings, selectedFilters: [] })}\n />\n )}\n </Stack>\n </DataGridToolbar>\n\n {/* Zone 3 — select all + bulk actions (only when at least one bulk action is available) */}\n {(permissions.canDelete || permissions.canUpdate) && (\n <DataGridToolbar>\n <Stack distribution=\"between\" alignment=\"center\">\n <Stack gap=\"2\" alignment=\"center\">\n <Checkbox\n checked={\n validSelectedImages.length > 0 && paginatedImages.every((img) => validSelectedImages.includes(img.id))\n }\n indeterminate={\n validSelectedImages.length > 0 &&\n !paginatedImages.every((img) => validSelectedImages.includes(img.id))\n }\n onChange={() => {\n const pageIds = paginatedImages.map((img) => img.id)\n const allSelected = pageIds.every((id) => validSelectedImages.includes(id))\n if (allSelected) {\n setSelectedImages(validSelectedImages.filter((id) => !pageIds.includes(id)))\n } else {\n setSelectedImages([...new Set([...validSelectedImages, ...pageIds])])\n }\n }}\n />\n <PopupMenu>\n <PopupMenuToggle as=\"div\">\n <Button size=\"small\" icon=\"moreVert\" label={t`Actions`} />\n </PopupMenuToggle>\n <PopupMenuOptions>\n {permissions.canDelete && (\n <PopupMenuItem\n disabled={isDeleteAllDisabled}\n label={t`Delete Selected`}\n onClick={() => setDeleteAllModalOpen(true)}\n />\n )}\n {permissions.canUpdate && (\n <PopupMenuItem\n disabled={isDeactivateAllDisabled}\n label={t`Deactivate Selected`}\n onClick={() => setDeactivateAllModalOpen(true)}\n />\n )}\n {permissions.canUpdate && (\n <PopupMenuItem\n disabled={isActivateAllDisabled}\n label={t`Activate Selected`}\n onClick={() => setActivateAllModalOpen(true)}\n />\n )}\n </PopupMenuOptions>\n </PopupMenu>\n </Stack>\n </Stack>\n </DataGridToolbar>\n )}\n <ImageListView\n images={paginatedImages}\n suggestedImages={memberStatusView === \"pending\" ? paginatedImages : []}\n acceptedImages={memberStatusView === \"accepted\" ? paginatedImages : []}\n permissions={permissions}\n isFetching={isFetching}\n currentPage={safePage}\n totalPages={totalPages}\n onPageChange={onPageChange}\n selectedImages={selectedImages}\n setSelectedImages={setSelectedImages}\n deleteAllModalOpen={deleteAllModalOpen}\n setDeleteAllModalOpen={setDeleteAllModalOpen}\n deactivateAllModalOpen={deactivateAllModalOpen}\n setDeactivateAllModalOpen={setDeactivateAllModalOpen}\n activateAllModalOpen={activateAllModalOpen}\n setActivateAllModalOpen={setActivateAllModalOpen}\n createModalOpen={createModalOpen}\n setCreateModalOpen={setCreateModalOpen}\n deletableImages={deletableImages}\n protectedImages={protectedImages}\n activeImages={activeImages}\n deactivatedImages={deactivatedImages}\n onImageUpdated={onImageUpdated}\n onImageDeleted={onImageDeleted}\n onMemberStatusChanged={onMemberStatusChanged}\n hasAnyBulkAction={permissions.canDelete || permissions.canUpdate}\n />\n </>\n )\n}\n\nexport const Images = ({ client, project }: ImagesProps) => {\n const { t } = useLingui()\n const navigate = useNavigate()\n const searchParams = useSearch({ strict: false }) as ImagesSearchParams\n\n const [sortSettings, setSortSettings] = useState<RequiredSortSettings>({\n options: [\n { label: t`Created At`, value: \"created_at\" },\n { label: t`Updated At`, value: \"updated_at\" },\n { label: t`Name`, value: \"name\" },\n { label: t`Size`, value: \"size\" },\n { label: t`Status`, value: \"status\" },\n ],\n sortBy: searchParams.sortBy || \"created_at\",\n sortDirection: searchParams.sortDirection || \"desc\",\n })\n\n const [filterSettings, setFilterSettings] = useState<FilterSettings>({\n filters: [\n {\n displayName: t`Status`,\n filterName: \"status\",\n values: Object.values(IMAGE_STATUSES),\n supportsMultiValue: true,\n },\n {\n displayName: t`Visibility`,\n filterName: \"visibility\",\n values: Object.values(IMAGE_VISIBILITY),\n supportsMultiValue: false,\n },\n {\n displayName: t`Disk Format`,\n filterName: \"disk_format\",\n values: Object.values(DISK_FORMATS),\n supportsMultiValue: true,\n },\n {\n displayName: t`Container Format`,\n filterName: \"container_format\",\n values: Object.values(CONTAINER_FORMATS),\n supportsMultiValue: true,\n },\n {\n displayName: t`Protected`,\n filterName: \"protected\",\n values: [\"true\", \"false\"],\n supportsMultiValue: false,\n },\n ],\n selectedFilters: parseFiltersFromUrl(searchParams),\n })\n\n const [searchTerm, setSearchTerm] = useState(searchParams.search || \"\")\n const currentPage = searchParams.page ?? 1\n const [selectedImages, setSelectedImages] = useState<Array<string>>([])\n const [createModalOpen, setCreateModalOpen] = useState(false)\n const [deleteAllModalOpen, setDeleteAllModalOpen] = useState(false)\n const [deactivateAllModalOpen, setDeactivateAllModalOpen] = useState(false)\n const [activateAllModalOpen, setActivateAllModalOpen] = useState(false)\n const memberStatusView = searchParams.memberStatus ?? \"all\"\n\n const [isFetching, setIsFetching] = useState(true)\n const [imageOverrides, setImageOverrides] = useState<Map<string, GlanceImage>>(new Map())\n const [deletedImageIds, setDeletedImageIds] = useState<Set<string>>(new Set())\n const [imagesPromise, setImagesPromise] = useState<Promise<ImagesResult>>(\n () =>\n new Promise(() => {\n // Placeholder: replaced immediately by useEffect on mount\n }) as Promise<ImagesResult>\n )\n const [permissionsPromise] = useState(() => createPermissionsPromise(client, project))\n\n const handleImageUpdated = useCallback((updatedImage: GlanceImage) => {\n setImageOverrides((prev) => new Map(prev).set(updatedImage.id, updatedImage))\n }, [])\n\n const handleImageDeleted = useCallback((imageIds: string | string[]) => {\n setDeletedImageIds((prev) => {\n const next = new Set(prev)\n if (Array.isArray(imageIds)) imageIds.forEach((id) => next.add(id))\n else next.add(imageIds)\n return next\n })\n }, [])\n\n const handleMemberStatusChanged = useCallback(() => {\n setImageOverrides(new Map())\n setIsFetching(true)\n const urlMemberStatus = searchParams.memberStatus ?? \"all\"\n const urlMemberStatusFilter = urlMemberStatus === \"all\" ? undefined : urlMemberStatus\n startTransition(() => {\n const effectiveFilters =\n urlMemberStatus === \"pending\" || urlMemberStatus === \"accepted\"\n ? (filterSettings.selectedFilters || []).filter((f) => f.name !== \"visibility\")\n : filterSettings.selectedFilters || []\n const newPromise = createImagesPromise(\n client,\n project,\n sortSettings.sortBy,\n sortSettings.sortDirection,\n searchTerm,\n {\n ...buildFilterParams(effectiveFilters, filterSettings.filters),\n member_status: urlMemberStatusFilter,\n }\n )\n newPromise.catch(() => {}).finally(() => setIsFetching(false))\n setImagesPromise(newPromise as Promise<ImagesResult>)\n })\n }, [client, sortSettings, searchTerm, filterSettings, searchParams.memberStatus])\n\n useEffect(() => {\n const urlFilters = parseFiltersFromUrl(searchParams)\n const urlSortBy = searchParams.sortBy || \"created_at\"\n const urlSortDirection = searchParams.sortDirection || \"desc\"\n const urlSearchTerm = searchParams.search || \"\"\n\n setFilterSettings((prev) => ({ ...prev, selectedFilters: urlFilters }))\n setSortSettings((prev) => ({ ...prev, sortBy: urlSortBy, sortDirection: urlSortDirection }))\n setSearchTerm(urlSearchTerm)\n setSelectedImages([])\n setImageOverrides(new Map())\n\n setIsFetching(true)\n const urlMemberStatus = searchParams.memberStatus ?? \"all\"\n const urlMemberStatusFilter = urlMemberStatus === \"all\" ? undefined : urlMemberStatus\n startTransition(() => {\n const effectiveFilters =\n urlMemberStatus === \"pending\" || urlMemberStatus === \"accepted\"\n ? (urlFilters || []).filter((f) => f.name !== \"visibility\")\n : urlFilters || []\n const newPromise = createImagesPromise(client, project, urlSortBy, urlSortDirection, urlSearchTerm, {\n ...buildFilterParams(effectiveFilters, filterSettings.filters),\n member_status: urlMemberStatusFilter,\n })\n newPromise.catch(() => {}).finally(() => setIsFetching(false))\n setImagesPromise(newPromise as Promise<ImagesResult>)\n })\n }, [\n searchParams.status,\n searchParams.visibility,\n searchParams.disk_format,\n searchParams.container_format,\n searchParams.protected,\n searchParams.sortBy,\n searchParams.sortDirection,\n searchParams.search,\n searchParams.memberStatus,\n ])\n\n const handleSortChange = (newSortSettings: SortSettings) => {\n const settings: RequiredSortSettings = {\n options: newSortSettings.options,\n sortBy: newSortSettings.sortBy?.toString() || \"created_at\",\n sortDirection: newSortSettings.sortDirection || \"desc\",\n }\n setSortSettings(settings)\n navigate({\n search: ((prev: ImagesSearchParams) => ({\n ...prev,\n sortBy: settings.sortBy,\n sortDirection: settings.sortDirection,\n page: undefined,\n })) as unknown as true,\n replace: true,\n })\n }\n\n const handleFilterChange = (newFilterSettings: FilterSettings) => {\n setFilterSettings(newFilterSettings)\n navigate({\n search: ((prev: ImagesSearchParams) =>\n buildUrlSearchParams(newFilterSettings.selectedFilters || [], newFilterSettings.filters, {\n search: prev.search,\n sortBy: prev.sortBy,\n sortDirection: prev.sortDirection,\n memberStatus: prev.memberStatus,\n })) as unknown as true,\n replace: true,\n })\n }\n\n const handleSearchChange = (term: string | number | string[] | undefined) => {\n const searchValue = typeof term === \"string\" ? term : \"\"\n setSearchTerm(searchValue)\n navigate({\n search: ((prev: ImagesSearchParams) => ({\n ...prev,\n search: searchValue || undefined,\n page: undefined,\n })) as unknown as true,\n replace: true,\n })\n }\n\n const handleMemberStatusChange = (view: \"all\" | \"pending\" | \"accepted\") => {\n navigate({\n search: ((prev: ImagesSearchParams) => ({\n sortBy: prev.sortBy,\n sortDirection: prev.sortDirection,\n search: prev.search,\n memberStatus: view === \"all\" ? undefined : view,\n })) as unknown as true,\n })\n }\n\n const handlePageChange = useCallback(\n (page: number) => {\n navigate({\n search: ((prev: ImagesSearchParams) => ({\n ...prev,\n page: page === 1 ? undefined : page,\n })) as unknown as true,\n })\n },\n [navigate]\n )\n\n return (\n <div className=\"relative\">\n <Suspense\n fallback={\n <Stack className=\"fixed inset-0\" distribution=\"center\" alignment=\"center\" direction=\"vertical\">\n <Spinner variant=\"primary\" size=\"large\" className=\"mb-2\" />\n <Trans>Loading Images...</Trans>\n </Stack>\n }\n >\n <ImagesContent\n imagesPromise={imagesPromise}\n imageOverrides={imageOverrides}\n deletedImageIds={deletedImageIds}\n permissionsPromise={permissionsPromise}\n searchTerm={searchTerm}\n setSearchTerm={handleSearchChange}\n sortSettings={sortSettings}\n handleSortChange={handleSortChange}\n filterSettings={filterSettings}\n handleFilterChange={handleFilterChange}\n selectedImages={selectedImages}\n setSelectedImages={setSelectedImages}\n createModalOpen={createModalOpen}\n setCreateModalOpen={setCreateModalOpen}\n deleteAllModalOpen={deleteAllModalOpen}\n setDeleteAllModalOpen={setDeleteAllModalOpen}\n deactivateAllModalOpen={deactivateAllModalOpen}\n setDeactivateAllModalOpen={setDeactivateAllModalOpen}\n activateAllModalOpen={activateAllModalOpen}\n setActivateAllModalOpen={setActivateAllModalOpen}\n memberStatusView={memberStatusView}\n setMemberStatusView={handleMemberStatusChange}\n isFetching={isFetching}\n currentPage={currentPage}\n onPageChange={handlePageChange}\n onImageUpdated={handleImageUpdated}\n onImageDeleted={handleImageDeleted}\n onMemberStatusChanged={handleMemberStatusChanged}\n />\n </Suspense>\n </div>\n )\n}\n","import { createFileRoute } from \"@tanstack/react-router\"\nimport { t } from \"@lingui/core/macro\"\nimport { useLingui } from \"@lingui/react/macro\"\nimport { Images } from \"../-components/Images/List\"\nimport type { RouteInfo } from \"@/client/routes/routeInfo\"\nimport { ContentHeader } from \"@/client/components/ContentHeader/ContentHeader\"\n\nexport const Route = createFileRoute(\"/_auth/projects/$projectId/compute/images/\")({\n staticData: {\n section: \"compute\",\n service: \"images\",\n sectionCrumb: { labelKey: \"Compute\" },\n crumb: { labelKey: \"Images\" },\n } satisfies RouteInfo,\n head: () => ({ meta: [{ title: t`Images` }] }),\n component: RouteComponent,\n})\n\nfunction RouteComponent() {\n const { t } = useLingui()\n const { projectId } = Route.useParams()\n const { trpcClient } = Route.useRouteContext()\n\n if (!trpcClient) {\n throw new Error(\"trpcClient is not available in route context\")\n }\n\n return (\n <>\n <ContentHeader title={t`Images`} projectId={projectId} />\n <Images client={trpcClient} project={projectId} />\n </>\n )\n}\n"],"mappings":"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"}