@cobaltcore-dev/aurora 2.1.1 → 2.2.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.
- package/README.md +31 -25
- package/dist/client/AuroraApp.d.ts +9 -2
- package/dist/client/context/AppConfigContext.d.ts +44 -0
- package/dist/client/index.d.ts +2 -0
- package/dist/client/index.js +41221 -845
- package/dist/client/index.js.map +1 -1
- package/dist/client/trpcClient.d.ts +314 -0
- package/dist/client/utils/appConfigGating.d.ts +21 -0
- package/dist/server/index.d.ts +694 -3
- package/dist/server/index.js +1748 -722
- package/package.json +3 -3
- package/dist/client/AuthProvider-CVSAwW9f.mjs +0 -83
- package/dist/client/AuthProvider-CVSAwW9f.mjs.map +0 -1
- package/dist/client/ContentHeader-fKKZVu-o.mjs +0 -116
- package/dist/client/ContentHeader-fKKZVu-o.mjs.map +0 -1
- package/dist/client/DeleteFlavorModal-C4nAi7gY.mjs +0 -724
- package/dist/client/DeleteFlavorModal-C4nAi7gY.mjs.map +0 -1
- package/dist/client/DynamicBreadcrumbContext-CVcUQFou.mjs +0 -26
- package/dist/client/DynamicBreadcrumbContext-CVcUQFou.mjs.map +0 -1
- package/dist/client/FiltersInput-Becwxo_J.mjs +0 -85
- package/dist/client/FiltersInput-Becwxo_J.mjs.map +0 -1
- package/dist/client/FloatingIpActionModals-Cq10WljB.mjs +0 -466
- package/dist/client/FloatingIpActionModals-Cq10WljB.mjs.map +0 -1
- package/dist/client/RouteIdLevelDefaultError-DPF_x2tG.mjs +0 -26
- package/dist/client/RouteIdLevelDefaultError-DPF_x2tG.mjs.map +0 -1
- package/dist/client/Slot-CWb612-_.mjs +0 -28
- package/dist/client/Slot-CWb612-_.mjs.map +0 -1
- package/dist/client/SortInput-4g7nSTHW.mjs +0 -34
- package/dist/client/SortInput-4g7nSTHW.mjs.map +0 -1
- package/dist/client/StorageNotFound-B-zVinVD.mjs +0 -30
- package/dist/client/StorageNotFound-B-zVinVD.mjs.map +0 -1
- package/dist/client/TwoColumnDescriptionList-DKS42RKa.mjs +0 -28
- package/dist/client/TwoColumnDescriptionList-DKS42RKa.mjs.map +0 -1
- package/dist/client/_-CAsCx-Ay.mjs +0 -6
- package/dist/client/_-CAsCx-Ay.mjs.map +0 -1
- package/dist/client/_auth-SrDjHL6j.mjs +0 -12
- package/dist/client/_auth-SrDjHL6j.mjs.map +0 -1
- package/dist/client/_flavorId-BPvssEzn.mjs +0 -277
- package/dist/client/_flavorId-BPvssEzn.mjs.map +0 -1
- package/dist/client/_flavorId-CFUBcU-l.mjs +0 -27
- package/dist/client/_flavorId-CFUBcU-l.mjs.map +0 -1
- package/dist/client/_flavorId-CZcIp0Ih.mjs +0 -22
- package/dist/client/_flavorId-CZcIp0Ih.mjs.map +0 -1
- package/dist/client/_floatingIpId-B8r64AL9.mjs +0 -196
- package/dist/client/_floatingIpId-B8r64AL9.mjs.map +0 -1
- package/dist/client/_floatingIpId-lEobpOER.mjs +0 -26
- package/dist/client/_floatingIpId-lEobpOER.mjs.map +0 -1
- package/dist/client/_imageId-BAezmV0Y.mjs +0 -526
- package/dist/client/_imageId-BAezmV0Y.mjs.map +0 -1
- package/dist/client/_imageId-D-jqz3e3.mjs +0 -40
- package/dist/client/_imageId-D-jqz3e3.mjs.map +0 -1
- package/dist/client/_imageId-gMdrdnVt.mjs +0 -22
- package/dist/client/_imageId-gMdrdnVt.mjs.map +0 -1
- package/dist/client/_projectId-BYccdAtX.mjs +0 -77
- package/dist/client/_projectId-BYccdAtX.mjs.map +0 -1
- package/dist/client/_projectId-CBjZC1tv.mjs +0 -283
- package/dist/client/_projectId-CBjZC1tv.mjs.map +0 -1
- package/dist/client/_projectId-CLEa1zgw.mjs +0 -30
- package/dist/client/_projectId-CLEa1zgw.mjs.map +0 -1
- package/dist/client/_projectId-D3VOH5lN.mjs +0 -94
- package/dist/client/_projectId-D3VOH5lN.mjs.map +0 -1
- package/dist/client/_securityGroupId-BwgZnoiR.mjs +0 -29
- package/dist/client/_securityGroupId-BwgZnoiR.mjs.map +0 -1
- package/dist/client/_securityGroupId-Cz2NUHdB.mjs +0 -1819
- package/dist/client/_securityGroupId-Cz2NUHdB.mjs.map +0 -1
- package/dist/client/_serviceType-DS8DxsrP.mjs +0 -20
- package/dist/client/_serviceType-DS8DxsrP.mjs.map +0 -1
- package/dist/client/_serviceType-M8d9rOT6.mjs +0 -6
- package/dist/client/_serviceType-M8d9rOT6.mjs.map +0 -1
- package/dist/client/_storageType-BNpP1A2N.mjs +0 -13
- package/dist/client/_storageType-BNpP1A2N.mjs.map +0 -1
- package/dist/client/_storageType-BxSGKhAI.mjs +0 -15
- package/dist/client/_storageType-BxSGKhAI.mjs.map +0 -1
- package/dist/client/_storageType-DZYCmiLt.mjs +0 -30
- package/dist/client/_storageType-DZYCmiLt.mjs.map +0 -1
- package/dist/client/_storageType-UqAMP-8d.mjs +0 -859
- package/dist/client/_storageType-UqAMP-8d.mjs.map +0 -1
- package/dist/client/_storageType-u51_7OwJ.mjs +0 -7
- package/dist/client/_storageType-u51_7OwJ.mjs.map +0 -1
- package/dist/client/about-BmQTyLWc.mjs +0 -92
- package/dist/client/about-BmQTyLWc.mjs.map +0 -1
- package/dist/client/assets/__mocks__/svgMock.d.ts +0 -3
- package/dist/client/aurora-CIml-f2f.mjs +0 -19
- package/dist/client/aurora-CIml-f2f.mjs.map +0 -1
- package/dist/client/build-WuxXRAqf.mjs +0 -14530
- package/dist/client/build-WuxXRAqf.mjs.map +0 -1
- package/dist/client/cn-DM4Cy3jv.mjs +0 -10
- package/dist/client/cn-DM4Cy3jv.mjs.map +0 -1
- package/dist/client/flavors-CJVSNz6R.mjs +0 -15
- package/dist/client/flavors-CJVSNz6R.mjs.map +0 -1
- package/dist/client/flavors-CflJDIEH.mjs +0 -667
- package/dist/client/flavors-CflJDIEH.mjs.map +0 -1
- package/dist/client/flavors-DWMZ6TuJ.mjs +0 -8
- package/dist/client/flavors-DWMZ6TuJ.mjs.map +0 -1
- package/dist/client/floatingips-Cz9k80cc.mjs +0 -8
- package/dist/client/floatingips-Cz9k80cc.mjs.map +0 -1
- package/dist/client/floatingips-DXnRlLvV.mjs +0 -551
- package/dist/client/floatingips-DXnRlLvV.mjs.map +0 -1
- package/dist/client/floatingips-HRbuLxiN.mjs +0 -22
- package/dist/client/floatingips-HRbuLxiN.mjs.map +0 -1
- package/dist/client/floatingips-nN1kQmsu.mjs +0 -14
- package/dist/client/floatingips-nN1kQmsu.mjs.map +0 -1
- package/dist/client/formatBytes-CZv_XyCY.mjs +0 -38
- package/dist/client/formatBytes-CZv_XyCY.mjs.map +0 -1
- package/dist/client/helpers-1PpYf-fC.mjs +0 -6
- package/dist/client/helpers-1PpYf-fC.mjs.map +0 -1
- package/dist/client/hooks-D0yKIumu.mjs +0 -22
- package/dist/client/hooks-D0yKIumu.mjs.map +0 -1
- package/dist/client/imageHelpers-DBhL2ebL.mjs +0 -1272
- package/dist/client/imageHelpers-DBhL2ebL.mjs.map +0 -1
- package/dist/client/images-BsylWUiH.mjs +0 -2011
- package/dist/client/images-BsylWUiH.mjs.map +0 -1
- package/dist/client/images-NBf2bV43.mjs +0 -8
- package/dist/client/images-NBf2bV43.mjs.map +0 -1
- package/dist/client/images-zQq1nSVv.mjs +0 -15
- package/dist/client/images-zQq1nSVv.mjs.map +0 -1
- package/dist/client/md-kvaGCNAK.mjs +0 -336
- package/dist/client/md-kvaGCNAK.mjs.map +0 -1
- package/dist/client/network-DuZm76BZ.mjs +0 -8
- package/dist/client/network-DuZm76BZ.mjs.map +0 -1
- package/dist/client/objects-BudUAfWY.mjs +0 -12909
- package/dist/client/objects-BudUAfWY.mjs.map +0 -1
- package/dist/client/objects-Dc7sKUr8.mjs +0 -67
- package/dist/client/objects-Dc7sKUr8.mjs.map +0 -1
- package/dist/client/objects-Dw7oeTq2.mjs +0 -80
- package/dist/client/objects-Dw7oeTq2.mjs.map +0 -1
- package/dist/client/objects-_g7nGIn5.mjs +0 -25
- package/dist/client/objects-_g7nGIn5.mjs.map +0 -1
- package/dist/client/objects-eBxvY6_n.mjs +0 -78
- package/dist/client/objects-eBxvY6_n.mjs.map +0 -1
- package/dist/client/projects-yiK0HGSA.mjs +0 -7
- package/dist/client/projects-yiK0HGSA.mjs.map +0 -1
- package/dist/client/routeInfo-DP3v74Wg.mjs +0 -19
- package/dist/client/routeInfo-DP3v74Wg.mjs.map +0 -1
- package/dist/client/routes-CJj7SR_K.mjs +0 -10
- package/dist/client/routes-CJj7SR_K.mjs.map +0 -1
- package/dist/client/routes-xofA3ksU.mjs +0 -110
- package/dist/client/routes-xofA3ksU.mjs.map +0 -1
- package/dist/client/securitygroups-CSmsBzUb.mjs +0 -581
- package/dist/client/securitygroups-CSmsBzUb.mjs.map +0 -1
- package/dist/client/securitygroups-CtKne8UQ.mjs +0 -8
- package/dist/client/securitygroups-CtKne8UQ.mjs.map +0 -1
- package/dist/client/securitygroups-T7kaNFEp.mjs +0 -15
- package/dist/client/securitygroups-T7kaNFEp.mjs.map +0 -1
- package/dist/client/securitygroups-WLB1_IM6.mjs +0 -22
- package/dist/client/securitygroups-WLB1_IM6.mjs.map +0 -1
- package/dist/client/securitygroups-o0IXZM6S.mjs +0 -14
- package/dist/client/securitygroups-o0IXZM6S.mjs.map +0 -1
- package/dist/client/serviceCatalog-B3lKWC9V.mjs +0 -6
- package/dist/client/serviceCatalog-B3lKWC9V.mjs.map +0 -1
- package/dist/client/services-D1PbooD1.mjs +0 -6
- package/dist/client/services-D1PbooD1.mjs.map +0 -1
- package/dist/client/services-DEMVtFyn.mjs +0 -9
- package/dist/client/services-DEMVtFyn.mjs.map +0 -1
- package/dist/client/storageProviders-CJ5rOh13.mjs +0 -15
- package/dist/client/storageProviders-CJ5rOh13.mjs.map +0 -1
- package/dist/client/trpcClient-D7gpR7YG.mjs +0 -71
- package/dist/client/trpcClient-D7gpR7YG.mjs.map +0 -1
- package/dist/client/useBreadcrumbs-ha3IlaxX.mjs +0 -54
- package/dist/client/useBreadcrumbs-ha3IlaxX.mjs.map +0 -1
- package/dist/client/useErrorTranslation-Dc0eE8Zt.mjs +0 -83
- package/dist/client/useErrorTranslation-Dc0eE8Zt.mjs.map +0 -1
- package/dist/client/useModal-DCs1OJh7.mjs +0 -12
- package/dist/client/useModal-DCs1OJh7.mjs.map +0 -1
- package/dist/client/useModalTracking-BYd37pXm.mjs +0 -37
- package/dist/client/useModalTracking-BYd37pXm.mjs.map +0 -1
- package/dist/client/useProjectId-DBc5lpoU.mjs +0 -11
- package/dist/client/useProjectId-DBc5lpoU.mjs.map +0 -1
- package/dist/client/useSecurityGroupPermissions--hK4aR8Y.mjs +0 -294
- package/dist/client/useSecurityGroupPermissions--hK4aR8Y.mjs.map +0 -1
- package/dist/client/useSetBreadcrumb-tn7lBaQV.mjs +0 -19
- package/dist/client/useSetBreadcrumb-tn7lBaQV.mjs.map +0 -1
- package/dist/client/utils/trpcErrors.d.ts +0 -13
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"images-BsylWUiH.mjs","names":["useParams","useNavigate","Checkbox","DataGridCell","DataGridRow","PopupMenu","PopupMenuItem","PopupMenuOptions","PopupMenuSectionSeparator","Spinner","toast","SizeDisplay","IMAGE_STATUSES","IMAGE_VISIBILITY","MEMBER_STATUSES","trpcReact","getImageAccessStatusUpdatedToast","getImageAccessStatusErrorToast","ImageTableRow","image","isSelected","isPending","isAccepted","permissions","onEditDetails","onEditMetadata","onDelete","onSelect","onActivationStatusChange","onManageAccess","onUpdateVisibility","uploadId","uploadProgressPercent","onMemberStatusChanged","showSelectColumn","useLingui","id","name","status","visibility","size","disk_format","created_at","imageName","t","projectId","from","navigate","utils","useUtils","updateMemberMutation","compute","updateImageMember","useMutation","onSuccess","listImagesWithPagination","invalidate","listSharedImagesByMemberStatus","handleMemberStatusChange","newStatus","mutateAsync","project_id","imageId","memberId","message","options","info","error","errorMessage","isExternalImage","isOwnImage","owner","isMutating","data-testid","onClick","to","params","e","stopPropagation","checked","onChange","protected","Date","toLocaleDateString","variant","canUpdateMember","label","ACCEPTED","REJECTED","canUpdate","SHARED","canCreateMember","canDeleteMember","PRIVATE","DEACTIVATED","canDelete","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","Status","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","onCancelUpload","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","isUploading","isCreatingOnly","handleModalCancel","open","onCancel","size","title","onConfirm","confirmButtonLabel","cancelButtonLabel","disableConfirmButton","disableCancelButton","closeable","disableCloseButton","closeOnEsc","div","className","style","width","status","variant","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","gap","direction","alignment","onKeyDown","helptext","wrap","map","pillKey","pillValue","loading","PUBLIC","SHARED","COMMUNITY","distribution","QCOW2","RAW","VMDK","VHD","VHDX","VDI","AMI","ARI","AKI","ISO","PLOOP","format","toUpperCase","String","z","useForm","useStore","React","useState","Modal","Stack","Form","FormSection","TextInput","useModalTracking","MAX_VISIBLE","MAX_ERROR_VISIBLE","DeleteImagesModal","deletableImages","protectedImages","isOpen","isLoading","onClose","onDelete","useLingui","result","setResult","trackClose","markSubmitted","resetTracking","actionPrefix","formSchema","object","confirm","string","refine","value","message","t","form","defaultValues","validators","onSubmit","map","img","id","handleClose","canDelete","store","state","isSubmitting","values","deletableCount","length","protectedCount","reset","visibleErrors","errors","slice","hiddenErrorCount","open","onCancel","title","size","confirmButtonLabel","onConfirm","handleSubmit","direction","gap","deletedCount","errorCount","p","className","div","e","imageId","visibleDeletable","hiddenDeletableCount","visibleProtected","hiddenProtectedCount","confirmLabel","confirmButtonVariant","cancelButtonLabel","disableConfirmButton","disableCancelButton","disableCloseButton","image","span","name","preventDefault","Field","children","field","label","onChange","handleChange","target","invalid","meta","errortext","join","undefined","autoFocus","disabled","required","React","Modal","Status","DeactivateImagesModal","activeImages","deactivatedImages","isOpen","isLoading","onClose","onDeactivate","useLingui","activeCount","length","deactivatedCount","handleDeactivate","e","preventDefault","map","img","id","onCancel","size","title","open","onConfirm","confirmButtonLabel","t","cancelButtonLabel","disableConfirmButton","disableCancelButton","disableCloseButton","status","className","div","p","image","span","name","React","Modal","Status","ActivateImagesModal","deactivatedImages","activeImages","isOpen","isLoading","onClose","onActivate","useLingui","deactivatedCount","length","activeCount","handleActivate","e","preventDefault","map","img","id","onCancel","size","title","open","onConfirm","confirmButtonLabel","t","cancelButtonLabel","disableConfirmButton","disableCancelButton","disableCloseButton","status","className","div","p","image","span","name","useState","useRef","useProjectId","DataGrid","DataGridCell","DataGridHeadCell","DataGridRow","Pagination","Status","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","getImageUploadCancelledToast","getImageVisibilityUpdatedToast","getImageVisibilityUpdateErrorToast","ManageImageAccessModal","convertToJsonPatchOperations","IMAGE_STATUSES","ImageListView","images","permissions","isFetching","currentPage","totalPages","onPageChange","children","selectedImages","setSelectedImages","deleteAllModalOpen","setDeleteAllModalOpen","deactivateAllModalOpen","setDeactivateAllModalOpen","activateAllModalOpen","setActivateAllModalOpen","createModalOpen","setCreateModalOpen","deletableImages","protectedImages","activeImages","deactivatedImages","onImageUpdated","onImageDeleted","onMemberStatusChanged","hasAnyBulkAction","pendingSharedIds","acceptedSharedIds","projectId","editDetailsModalOpen","setEditDetailsModalOpen","editMetadataModalOpen","setEditMetadataModalOpen","deleteModalOpen","setDeleteModalOpen","deactivateModalOpen","setDeactivateModalOpen","activateModalOpen","setActivateModalOpen","manageAccessModalOpen","setManageAccessModalOpen","selectedImage","setSelectedImage","isCreateInProgress","setCreateInProgress","uploadId","setUploadId","isUploadPending","setIsUploadPending","uploadAbortControllerRef","uploadCancelledRef","useLingui","utils","useUtils","deleteImageMutation","compute","deleteImage","useMutation","deactivateImageMutation","deactivateImage","onSuccess","getImageById","invalidate","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","handleUpdateImageVisibility","newVisibility","imageName","mutateAsync","visibility","message","options","success","error","errorMessage","t","handleSaveEdit","updatedProperties","name","operations","handleCreate","imageData","file","createdImageId","createdImage","abortController","AbortController","current","uploadImage","mutate","signal","context","headers","String","size","cleanupError","cleanupMessage","path","uploadErrorMessage","handleCancelUpload","abort","info","handleDelete","deletedImage","handleActivationStatusChange","status","DEACTIVATED","handleActivateSingle","image","ACTIVE","handleDeactivateSingle","openEditDetailsModal","openEditMetadataModal","openDeleteModal","openManageAccessModal","closeEditDetailsModal","closeEditMetadataModal","listImagesWithPagination","closeDeleteModal","closeDeactivateModal","closeActivateModal","closeManageAccessModal","handleBulkDelete","imageIds","result","successCount","successful","length","failedCount","failed","totalCount","warning","console","log","handleBulkActivate","forEach","find","img","handleBulkDeactivate","updateCurrentPage","newPage","div","data-testid","colSpan","title","className","columns","minContentColumns","map","isSelected","includes","has","isAccepted","onEditDetails","onEditMetadata","onDelete","onManageAccess","showSelectColumn","onSelect","isImageSelected","filter","onActivationStatusChange","onUpdateVisibility","uploadProgressPercent","percent","body","variant","pages","onPressPrevious","Math","max","onPressNext","min","onSelectChange","selectedPage","onInputChange","onKeyDown","e","key","inputValue","target","value","parseInt","isNaN","isOpen","onClose","onSave","client","isDisabled","protected","canDelete","onDeactivate","onActivate","onCreate","onCancelUpload","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","marker","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","ErrorBoundary","trpcReact","useNavigate","useSearch","useProjectId","Button","Stack","Status","PopupMenu","PopupMenuItem","PopupMenuToggle","PopupMenuOptions","PopupMenuSectionSeparator","DataGridToolbar","SearchInput","Checkbox","TabNavigation","TabNavigationItem","SortInput","SelectedFilters","FiltersInput","ImageListView","CONTAINER_FORMATS","DISK_FORMATS","IMAGE_STATUSES","IMAGE_VISIBILITY","parseFiltersFromUrl","buildFilterParams","buildUrlSearchParams","applyFilterSelection","createImagesPromise","createPermissionsPromise","extractMarker","nextValue","undefined","includes","url","URL","searchParams","get","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","projectId","imagesData","permissions","localSearchTerm","setLocalSearchTerm","debounceTimer","sharedPendingQuery","compute","listSharedImagesByMemberStatus","useQuery","project_id","memberStatus","retry","sharedAcceptedQuery","pendingSharedIds","Set","data","map","img","id","acceptedSharedIds","clearTimeout","current","listError","p","images","filter","has","PAGE_SIZE","hasNextPage","next","totalItems","totalCount","length","totalPages","Math","max","ceil","safePage","min","activeFilterSettings","filters","f","filterName","selectedFilters","name","isServerPaginated","pageImages","slice","displayedImageIds","image","validSelectedImages","imageId","paginatedImages","imageById","Map","selectedImageObjects","Boolean","ownedSelectedImages","owner","deletableImages","protected","protectedImages","activeImages","status","ACTIVE","deactivatedImages","DEACTIVATED","isDeleteAllDisabled","canDelete","every","isDeactivateAllDisabled","canUpdate","isActivateAllDisabled","memberStatusTabs","items","label","t","value","activeItem","onActiveItemChange","distribution","alignment","gap","className","item","options","sortBy","sortDirection","selectClassName","onSortByChange","v","onSortDirectionChange","dir","canCreate","onClick","variant","direction","comboboxClassName","onChange","selected","newSelected","data-testid","onInput","e","currentTarget","window","setTimeout","onSearch","onClear","onDelete","filterToRemove","checked","indeterminate","pageIds","allSelected","as","size","icon","disabled","hasAnyBulkAction","Images","client","project","navigate","strict","setSortSettings","setFilterSettings","displayName","values","Object","supportsMultiValue","search","page","setIsFetching","setImageOverrides","setDeletedImageIds","pageMarkers","setPageMarkers","setImagesPromise","Promise","computeEffectiveFilters","handleImageUpdated","updatedImage","prev","set","handleImageDeleted","imageIds","Array","isArray","forEach","add","handleMemberStatusChanged","urlMemberStatus","urlMemberStatusFilter","effectiveFilters","marker","newPromise","member_status","then","result","nextPage","catch","finally","urlFilters","urlSortBy","urlSortDirection","urlSearchTerm","urlPage","visibility","disk_format","container_format","newSortSettings","settings","toString","replace","newFilterSettings","handleSearchChange","term","searchValue","handleMemberStatusChange","view","handlePageChange","div","fallbackRender","error","title","body","Error","message","fallback","useLingui","Images","ContentHeader","Route","RouteComponent","t","projectId","useParams","trpcClient","useRouteContext","Error","component"],"sources":["../../src/client/routes/_auth/projects/$projectId/compute/images/-components/ImageTableRow.tsx","../../src/server/Compute/helpers/imageHelpers.ts","../../src/client/routes/_auth/projects/$projectId/compute/images/-components/CreateImageModal.tsx","../../src/client/routes/_auth/projects/$projectId/compute/images/-components/DeleteImagesModal.tsx","../../src/client/routes/_auth/projects/$projectId/compute/images/-components/DeactivateImagesModal.tsx","../../src/client/routes/_auth/projects/$projectId/compute/images/-components/ActivateImagesModal.tsx","../../src/client/routes/_auth/projects/$projectId/compute/images/-components/ImageListView.tsx","../../src/client/routes/_auth/projects/$projectId/compute/images/urlHelpers.ts","../../src/client/routes/_auth/projects/$projectId/compute/images/apiHelpers.ts","../../src/client/routes/_auth/projects/$projectId/compute/images/-components/List.tsx","../../src/client/routes/_auth/projects/$projectId/compute/images/index.tsx?tsr-split=component"],"sourcesContent":["import { useParams, useNavigate } from \"@tanstack/react-router\"\nimport {\n Checkbox,\n DataGridCell,\n DataGridRow,\n PopupMenu,\n PopupMenuItem,\n PopupMenuOptions,\n PopupMenuSectionSeparator,\n Spinner,\n toast,\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 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 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 } = 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 const { message, ...options } = getImageAccessStatusUpdatedToast(newStatus)\n toast.info(message, options)\n onMemberStatusChanged?.()\n } catch (error) {\n const errorMessage = (error as TRPCClientError<InferrableClientTypes>)?.message\n const { message, ...options } = getImageAccessStatusErrorToast(errorMessage)\n toast.error(message, options)\n }\n }\n\n const isExternalImage = isPending || isAccepted\n const isOwnImage = image.owner === projectId\n const isMutating = updateMemberMutation.isPending\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 {isExternalImage && !isOwnImage && permissions.canUpdateMember && (\n <>\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 <PopupMenuSectionSeparator />\n {isPending && (\n <PopupMenuItem\n label={t`Accept`}\n onClick={() => handleMemberStatusChange(MEMBER_STATUSES.ACCEPTED)}\n />\n )}\n <PopupMenuItem label={t`Reject`} onClick={() => handleMemberStatusChange(MEMBER_STATUSES.REJECTED)} />\n </>\n )}\n\n {/* Show Details is available for any image the user can view,\n regardless of update permission. */}\n {!isExternalImage && (\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\n {/* Own image: mutation actions gated on update permission */}\n {!isExternalImage && permissions.canUpdate && (\n <>\n <PopupMenuItem label={t`Edit Details`} onClick={() => onEditDetails(image)} />\n <PopupMenuItem label={t`Edit Metadata`} onClick={() => onEditMetadata(image)} />\n <PopupMenuSectionSeparator />\n {image.visibility === IMAGE_VISIBILITY.SHARED &&\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 <PopupMenuItem\n label={image.status === IMAGE_STATUSES.DEACTIVATED ? t`Activate Image` : t`Deactivate Image`}\n onClick={() => onActivationStatusChange(image)}\n />\n </>\n )}\n {!isExternalImage && permissions.canDelete && !image.protected && (\n <>\n <PopupMenuSectionSeparator />\n <PopupMenuItem label={t`Delete Image`} onClick={() => onDelete(image)} />\n </>\n )}\n </PopupMenuOptions>\n </PopupMenu>\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 Status,\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 onCancelUpload?: () => void\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 onCancelUpload,\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 // During an active upload, repurpose the modal's footer Cancel button to\n // cancel the upload (and close). Outside of upload it behaves normally.\n const isUploading = isLoading && isUploadPending\n // Creating the image record (before the upload starts) is a brief,\n // non-cancellable step — disable the cancel action then.\n const isCreatingOnly = isLoading && !isUploadPending\n const handleModalCancel = isUploading ? onCancelUpload : isLoading ? undefined : handleClose\n\n return (\n <Modal\n open={isOpen}\n onCancel={handleModalCancel}\n size=\"large\"\n title={t`Create New Image`}\n onConfirm={isLoading ? undefined : handleSubmit}\n confirmButtonLabel={isLoading ? undefined : t`Create Image`}\n cancelButtonLabel={isUploading ? t`Cancel Upload` : t`Cancel`}\n disableConfirmButton={isLoading || !isFormValid}\n disableCancelButton={isCreatingOnly}\n closeable\n disableCloseButton={isLoading}\n closeOnEsc={!isLoading}\n >\n {isLoading && (\n <div className=\"mt-4\">\n {uploadProgressPercent ? (\n <div className=\"bg-neutral-quaternary 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 <Status\n status=\"progress\"\n title={isUploadPending ? t`Uploading File...` : t`Creating Image...`}\n className=\"mt-0\"\n />\n )}\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 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 or click Add to add a tag`}\n disabled={isLoading}\n />\n </div>\n\n <Button 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 { z } from \"zod\"\nimport { useForm, useStore } from \"@tanstack/react-form\"\nimport React, { useState } from \"react\"\nimport { Trans, useLingui, Plural } from \"@lingui/react/macro\"\nimport { Modal, Stack, Form, FormSection, TextInput } from \"@cloudoperators/juno-ui-components\"\nimport { useModalTracking } from \"@/client/hooks/useModalTracking\"\nimport { GlanceImage } from \"@/server/Compute/types/image\"\n\ninterface DeleteImagesModalProps {\n deletableImages: Array<GlanceImage>\n protectedImages: Array<GlanceImage>\n isOpen: boolean\n isLoading: boolean\n onClose: () => void\n onDelete: (deletableImageIds: Array<string>) => void\n}\n\ninterface DeleteResult {\n deletedCount: number\n errorCount: number\n errors: Array<{ imageId: string; message: string }>\n}\n\nconst MAX_VISIBLE = 20\nconst MAX_ERROR_VISIBLE = 100\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 const [result, setResult] = useState<DeleteResult | null>(null)\n\n const { trackClose, markSubmitted, resetTracking } = useModalTracking({\n isOpen,\n actionPrefix: \"compute.images.delete\",\n })\n\n const formSchema = z.object({\n confirm: z.string().refine((value) => value === \"delete\", {\n message: t`Type \"delete\" to confirm`,\n }),\n })\n\n const form = useForm({\n defaultValues: {\n confirm: \"\",\n },\n validators: {\n onSubmit: formSchema,\n },\n onSubmit: async () => {\n if (result === null && !isLoading) {\n // Step A: Confirm\n markSubmitted()\n onDelete(deletableImages.map((img) => img.id))\n // Note: Parent component should call setResult after getting backend response\n } else {\n // Step B: Close results view\n handleClose()\n }\n },\n })\n\n const canDelete = useStore(form.store, (state) => state.isSubmitting || state.values.confirm !== \"delete\")\n\n const deletableCount = deletableImages.length\n const protectedCount = protectedImages.length\n\n const handleClose = () => {\n trackClose()\n setResult(null)\n form.reset()\n resetTracking()\n onClose()\n }\n\n // Step B: Results view\n if (result !== null) {\n const visibleErrors = result.errors.slice(0, MAX_ERROR_VISIBLE)\n const hiddenErrorCount = result.errors.length - visibleErrors.length\n\n return (\n <Modal\n open={isOpen}\n onCancel={handleClose}\n title={<Trans>Delete Results</Trans>}\n size=\"large\"\n confirmButtonLabel={t`Done`}\n onConfirm={form.handleSubmit}\n >\n <Stack direction=\"vertical\" gap=\"4\">\n {(() => {\n const deletedCount = result.deletedCount\n const errorCount = result.errorCount\n return (\n <p className=\"text-theme-default\">\n <Trans id=\"deleteResults.summary\">\n {deletedCount} deleted, {errorCount} failed.\n </Trans>\n </p>\n )\n })()}\n\n {result.errors.length > 0 && (\n <div>\n <p className=\"text-theme-light mb-2 text-sm\">\n <Trans>Failed deletions:</Trans>\n </p>\n <div className=\"bg-theme-background-lvl-2 max-h-96 overflow-y-auto rounded p-4\">\n <Stack direction=\"vertical\" gap=\"2\">\n {visibleErrors.map((e) => (\n <div\n key={e.imageId}\n className=\"border-theme-background-lvl-3 border-b pb-2 last:border-0 last:pb-0\"\n >\n <div className=\"overflow-x-hidden font-medium [overflow-wrap:anywhere]\" title={e.imageId}>\n {e.imageId}\n </div>\n {e.message && <div className=\"text-juno-red mt-1 text-sm\">{e.message}</div>}\n </div>\n ))}\n {hiddenErrorCount > 0 && (\n <div className=\"text-theme-light pt-2 text-sm\">\n <Trans>… and {hiddenErrorCount} more failures</Trans>\n </div>\n )}\n </Stack>\n </div>\n </div>\n )}\n </Stack>\n </Modal>\n )\n }\n\n // Step A: Confirm view\n const visibleDeletable = deletableImages.slice(0, MAX_VISIBLE)\n const hiddenDeletableCount = deletableImages.length - visibleDeletable.length\n\n const visibleProtected = protectedImages.slice(0, MAX_VISIBLE)\n const hiddenProtectedCount = protectedImages.length - visibleProtected.length\n\n const confirmLabel = isLoading ? t`Deleting...` : deletableCount === 1 ? t`Delete Image` : t`Delete Images`\n\n return (\n <Modal\n open={isOpen}\n onCancel={handleClose}\n title={<Plural value={deletableCount} one=\"Delete # Image\" other=\"Delete # Images\" />}\n size=\"large\"\n confirmButtonLabel={confirmLabel}\n confirmButtonVariant=\"primary-danger\"\n onConfirm={form.handleSubmit}\n cancelButtonLabel={t`Cancel`}\n disableConfirmButton={canDelete || isLoading}\n disableCancelButton={isLoading}\n disableCloseButton={isLoading}\n >\n <Stack direction=\"vertical\" gap=\"4\">\n <p className=\"text-theme-default\">\n <Trans>The selected images will be permanently deleted. This action cannot be undone.</Trans>\n </p>\n\n <div className=\"space-y-3\">\n {protectedCount > 0 && (\n <div>\n <p className=\"text-sm font-semibold\">\n <Plural\n value={protectedCount}\n one=\"Image Protected from Deletion (#)\"\n other=\"Images Protected from Deletion (#)\"\n />\n </p>\n <div className=\"bg-theme-background-lvl-2 mt-2 max-h-48 overflow-y-auto rounded p-3\">\n <Stack direction=\"vertical\" gap=\"1\">\n {visibleProtected.map((image) => (\n <div key={image.id} className=\"text-theme-default text-sm\">\n <span className=\"font-medium\">{image.name || t`Unnamed`}</span>\n <span className=\"text-theme-light ml-2 text-xs\">({image.id})</span>\n </div>\n ))}\n {hiddenProtectedCount > 0 && (\n <div className=\"text-theme-light pt-2 text-sm\">\n <Trans>… and {hiddenProtectedCount} more</Trans>\n </div>\n )}\n </Stack>\n </div>\n </div>\n )}\n\n {deletableCount > 0 && (\n <div>\n <p className=\"text-sm font-semibold\">\n <Plural value={deletableCount} one=\"Image to delete (#)\" other=\"Images to delete (#)\" />\n </p>\n <div className=\"bg-theme-background-lvl-2 mt-2 max-h-48 overflow-y-auto rounded p-3\">\n <Stack direction=\"vertical\" gap=\"1\">\n {visibleDeletable.map((image) => (\n <div key={image.id} className=\"text-theme-default text-sm\">\n <span className=\"font-medium\">{image.name || t`Unnamed`}</span>\n <span className=\"text-theme-light ml-2 text-xs\">({image.id})</span>\n </div>\n ))}\n {hiddenDeletableCount > 0 && (\n <div className=\"text-theme-light pt-2 text-sm\">\n <Trans>… and {hiddenDeletableCount} more</Trans>\n </div>\n )}\n </Stack>\n </div>\n </div>\n )}\n </div>\n\n <Form\n className=\"mb-0\"\n id=\"delete-images-form\"\n onSubmit={(e) => {\n e.preventDefault()\n form.handleSubmit()\n }}\n >\n <FormSection>\n <form.Field\n name=\"confirm\"\n children={(field) => (\n <TextInput\n label={t`Type \"delete\" to confirm`}\n id={field.name}\n name={field.name}\n value={field.state.value}\n onChange={(e) => field.handleChange(e.target.value)}\n invalid={field.state.meta.errors.length > 0}\n errortext={\n field.state.meta.errors.map((e) => (typeof e === \"string\" ? e : e?.message)).join(\", \") || undefined\n }\n autoFocus\n disabled={isLoading}\n required\n />\n )}\n />\n </FormSection>\n </Form>\n </Stack>\n </Modal>\n )\n}\n","import React from \"react\"\nimport { Trans, useLingui, Plural } from \"@lingui/react/macro\"\nimport { Modal, Status } from \"@cloudoperators/juno-ui-components\"\nimport { GlanceImage } from \"@/server/Compute/types/image\"\n\ninterface DeactivateImagesModalProps {\n activeImages: Array<GlanceImage>\n deactivatedImages: Array<GlanceImage>\n isOpen: boolean\n isLoading: boolean\n onClose: () => void\n onDeactivate: (activeImageIds: 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.map((img) => img.id))\n }\n\n return (\n <Modal\n onCancel={onClose}\n size=\"small\"\n title={<Plural value={activeCount} one=\"Deactivate # Image\" other=\"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 disableCancelButton={isLoading}\n disableCloseButton={isLoading}\n >\n {isLoading ? (\n <Status status=\"progress\" title={t`Deactivating Images...`} className=\"mt-0\" />\n ) : (\n <div className=\"my-6\">\n {activeCount > 0 && (\n <>\n <p className=\"mb-6\">\n <Trans>Deactivated images cannot be used to launch instances.</Trans>\n </p>\n\n {deactivatedCount > 0 && (\n <div className=\"mb-6\">\n <p className=\"text-sm font-semibold\">\n <Plural\n value={deactivatedCount}\n one=\"Already deactivated (# will be skipped)\"\n other=\"Already deactivated (# will be skipped)\"\n />\n </p>\n <div className=\"jn:bg-theme-background-lvl-1 mt-2 max-h-24 overflow-y-auto rounded p-4\">\n <div className=\"space-y-1\">\n {deactivatedImages.map((image) => (\n <div key={image.id} className=\"text-theme-default text-sm\">\n <span className=\"font-medium\">{image.name || t`Unnamed`}</span>\n <span className=\"text-theme-light ml-2 text-xs\">({image.id})</span>\n </div>\n ))}\n </div>\n </div>\n </div>\n )}\n\n {/* Images to be deactivated */}\n <div className=\"mb-6\">\n <p className=\"text-sm font-semibold\">\n <Plural value={activeCount} one=\"Image to deactivate (#)\" other=\"Images to deactivate (#)\" />\n </p>\n <div className=\"jn:bg-theme-background-lvl-1 mt-2 max-h-24 overflow-y-auto rounded p-4\">\n <div className=\"space-y-1\">\n {activeImages.map((image) => (\n <div key={image.id} className=\"text-theme-default text-sm\">\n <span className=\"font-medium\">{image.name || t`Unnamed`}</span>\n <span className=\"text-theme-light ml-2 text-xs\">({image.id})</span>\n </div>\n ))}\n </div>\n </div>\n </div>\n </>\n )}\n </div>\n )}\n </Modal>\n )\n}\n","import React from \"react\"\nimport { Trans, useLingui, Plural } from \"@lingui/react/macro\"\nimport { Modal, Status } from \"@cloudoperators/juno-ui-components\"\nimport { GlanceImage } from \"@/server/Compute/types/image\"\n\ninterface ActivateImagesModalProps {\n deactivatedImages: Array<GlanceImage>\n activeImages: Array<GlanceImage>\n isOpen: boolean\n isLoading: boolean\n onClose: () => void\n onActivate: (deactivatedImageIds: 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.map((img) => img.id))\n }\n\n return (\n <Modal\n onCancel={onClose}\n size=\"small\"\n title={<Plural value={deactivatedCount} one=\"Activate # Image\" other=\"Activate # Images\" />}\n open={isOpen}\n onConfirm={handleActivate}\n confirmButtonLabel={t`Activate`}\n cancelButtonLabel={t`Cancel`}\n disableConfirmButton={isLoading}\n disableCancelButton={isLoading}\n disableCloseButton={isLoading}\n >\n {isLoading ? (\n <Status status=\"progress\" title={t`Activating Images...`} className=\"mt-0\" />\n ) : (\n <div className=\"my-6\">\n {deactivatedCount > 0 && (\n <>\n <p className=\"mb-6\">\n <Trans>Activated images will be available for launching new instances.</Trans>\n </p>\n\n {activeCount > 0 && (\n <div className=\"mb-6\">\n <p className=\"text-sm font-semibold\">\n <Plural\n value={activeCount}\n one=\"Already active (# will be skipped)\"\n other=\"Already active (# will be skipped)\"\n />\n </p>\n <div className=\"jn:bg-theme-background-lvl-1 mt-2 max-h-24 overflow-y-auto rounded p-4\">\n <div className=\"space-y-1\">\n {activeImages.map((image) => (\n <div key={image.id} className=\"text-theme-default text-sm\">\n <span className=\"font-medium\">{image.name || t`Unnamed`}</span>\n <span className=\"text-theme-light ml-2 text-xs\">({image.id})</span>\n </div>\n ))}\n </div>\n </div>\n </div>\n )}\n\n {/* Images to be activated */}\n <div className=\"mb-6\">\n <p className=\"text-sm font-semibold\">\n <Plural value={deactivatedCount} one=\"Image to activate (#)\" other=\"Images to activate (#)\" />\n </p>\n <div className=\"jn:bg-theme-background-lvl-1 mt-2 max-h-24 overflow-y-auto rounded p-4\">\n <div className=\"space-y-1\">\n {deactivatedImages.map((image) => (\n <div key={image.id} className=\"text-theme-default text-sm\">\n <span className=\"font-medium\">{image.name || t`Unnamed`}</span>\n <span className=\"text-theme-light ml-2 text-xs\">({image.id})</span>\n </div>\n ))}\n </div>\n </div>\n </div>\n </>\n )}\n </div>\n )}\n </Modal>\n )\n}\n","import { useState, useRef, ReactNode } from \"react\"\nimport { useProjectId } from \"@/client/hooks\"\nimport type { CreateImageInput, GlanceImage, ImageVisibility } from \"@/server/Compute/types/image\"\nimport {\n DataGrid,\n DataGridCell,\n DataGridHeadCell,\n DataGridRow,\n Pagination,\n Status,\n toast,\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, useLingui } from \"@lingui/react/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 getImageUploadCancelledToast,\n getImageVisibilityUpdatedToast,\n getImageVisibilityUpdateErrorToast,\n} from \"./ImageToastNotifications\"\nimport { ManageImageAccessModal } from \"./ManageImageAccessModal\"\nimport { convertToJsonPatchOperations } from \"../-utils/imageHelpers\"\nimport { IMAGE_STATUSES } from \"../../-constants/filters\"\n\ninterface ImagePageProps {\n images: 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<GlanceImage>\n protectedImages: Array<GlanceImage>\n activeImages: Array<GlanceImage>\n deactivatedImages: Array<GlanceImage>\n onImageUpdated: (image: GlanceImage) => void\n onImageDeleted: (imageIds: string | string[]) => void\n onMemberStatusChanged: () => void\n hasAnyBulkAction: boolean\n pendingSharedIds: Set<string>\n acceptedSharedIds: Set<string>\n}\n\nexport function ImageListView({\n images,\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 pendingSharedIds,\n acceptedSharedIds,\n}: ImagePageProps) {\n const projectId = useProjectId()\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 const uploadAbortControllerRef = useRef<AbortController | null>(null)\n const uploadCancelledRef = useRef(false)\n const { t } = useLingui()\n\n const utils = trpcReact.useUtils()\n\n const deleteImageMutation = trpcReact.compute.deleteImage.useMutation()\n\n const deactivateImageMutation = trpcReact.compute.deactivateImage.useMutation({\n onSuccess: () => {\n utils.compute.getImageById.invalidate()\n },\n })\n\n const reactivateImageMutation = trpcReact.compute.reactivateImage.useMutation({\n onSuccess: () => {\n utils.compute.getImageById.invalidate()\n },\n })\n\n const deleteImagesMutation = trpcReact.compute.deleteImages.useMutation({\n onSuccess: () => {\n setSelectedImages([])\n },\n })\n\n const activateImagesMutation = trpcReact.compute.activateImages.useMutation({\n onSuccess: () => {\n setSelectedImages([])\n },\n })\n\n const deactivateImagesMutation = trpcReact.compute.deactivateImages.useMutation({\n onSuccess: () => {\n setSelectedImages([])\n },\n })\n\n const updateImageMutation = trpcReact.compute.updateImage.useMutation({\n onSuccess: (updatedImage) => {\n utils.compute.getImageById.setData({ project_id: projectId, imageId: updatedImage.id }, updatedImage)\n },\n })\n\n const createImageMutation = trpcReact.compute.createImage.useMutation()\n\n const updateImageVisibilityMutation = trpcReact.compute.updateImageVisibility.useMutation()\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 handleUpdateImageVisibility = async (imageId: string, newVisibility: ImageVisibility, imageName: string) => {\n try {\n const updatedImage = await updateImageVisibilityMutation.mutateAsync({\n project_id: projectId,\n imageId,\n visibility: newVisibility,\n })\n\n onImageUpdated(updatedImage)\n\n const { message, ...options } = getImageVisibilityUpdatedToast(imageName, newVisibility)\n toast.success(message, options)\n } catch (error) {\n const errorMessage =\n (error as TRPCClientError<InferrableClientTypes>)?.message || t`Failed to update visibility to ${newVisibility}`\n\n const { message, ...options } = getImageVisibilityUpdateErrorToast(imageName, errorMessage)\n toast.error(message, options)\n }\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 const { message, ...options } = getImageUpdatedToast(imageName)\n toast.success(message, options)\n setSelectedImage(updatedImage)\n onImageUpdated(updatedImage)\n return true\n } catch (error) {\n const errorMessage = (error as TRPCClientError<InferrableClientTypes>)?.message ?? \"\"\n const { message, ...options } = getImageUpdateErrorToast(imageName, errorMessage)\n toast.error(message, options)\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 let createdImageId: string | null = null\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 createdImageId = createdImage.id\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 // An AbortController lets the user cancel the in-flight upload; aborting\n // drops the HTTP connection, which the server maps to an aborted request.\n const abortController = new AbortController()\n uploadAbortControllerRef.current = abortController\n uploadCancelledRef.current = false\n setUploadId(createdImage.id)\n setIsUploadPending(true)\n\n await trpcClient.compute.uploadImage.mutate(file, {\n signal: abortController.signal,\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\n const { message, ...options } = getImageCreatedToast(imageName)\n toast.success(message, options)\n\n // Optimistically add the created image to the list\n onImageUpdated(createdImage)\n\n // Trigger manual refetch through member status change handler\n onMemberStatusChanged()\n } catch (error) {\n // A user-initiated cancellation is not a failure. We reach this branch only\n // once the aborted upload promise has rejected, so the transfer has fully\n // terminated and it is safe to clean up the orphaned image record here\n // (avoids racing the still-running upload).\n if (uploadCancelledRef.current) {\n if (createdImageId) {\n try {\n await deleteImageMutation.mutateAsync({ project_id: projectId, imageId: createdImageId })\n onImageDeleted(createdImageId)\n } catch (cleanupError) {\n const cleanupMessage = (cleanupError as FastifyError)?.message ?? \"\"\n const { message, ...options } = getImageDeleteErrorToast(createdImageId, cleanupMessage)\n toast.error(message, options)\n }\n }\n return\n }\n\n // Show error notification based on failure point\n if (error instanceof TRPCClientError && error.data?.path === \"compute.createImage\") {\n const { message, ...options } = getImageCreateErrorToast(imageName, error.message)\n toast.error(message, options)\n } else {\n // File upload failed\n const uploadErrorMessage = (error as FastifyError)?.message ?? \"\"\n\n const { message, ...options } = getImageFileUploadErrorToast(file.name, uploadErrorMessage)\n toast.error(message, options)\n }\n } finally {\n // Complete creation and close modal. Reset the cancellation flag so a later\n // create request is not mistaken for a cancellation.\n uploadAbortControllerRef.current = null\n uploadCancelledRef.current = false\n setCreateInProgress(false)\n setCreateModalOpen(false)\n setIsUploadPending(false)\n setUploadId(null)\n }\n }\n\n const handleCancelUpload = () => {\n // Flag the cancellation and abort the transfer. handleCreate's catch block\n // runs once the aborted upload rejects and performs the orphan cleanup, so\n // we never race the still-running upload from here.\n uploadCancelledRef.current = true\n uploadAbortControllerRef.current?.abort()\n\n const { message, ...options } = getImageUploadCancelledToast()\n toast.info(message, options)\n // handleCreate's finally block resets state and closes the modal.\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 const { message, ...options } = getImageDeletedToast(imageName)\n toast.success(message, options)\n onImageDeleted(imageId)\n } catch (error) {\n const errorMessage = (error as TRPCClientError<InferrableClientTypes>)?.message ?? \"\"\n\n const { message, ...options } = getImageDeleteErrorToast(imageId, errorMessage)\n toast.error(message, options)\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\n // Optimistically update the local state\n const updatedImage = { ...image, status: IMAGE_STATUSES.ACTIVE }\n onImageUpdated(updatedImage)\n\n setActivateModalOpen(false)\n setSelectedImage(null)\n const { message, ...options } = getImageActivatedToast(imageName)\n toast.success(message, options)\n } catch (error) {\n const errorMessage = (error as TRPCClientError<InferrableClientTypes>)?.message ?? \"\"\n const { message, ...options } = getImageActivationErrorToast(imageId, errorMessage)\n toast.error(message, options)\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\n // Optimistically update the local state\n const updatedImage = { ...image, status: IMAGE_STATUSES.DEACTIVATED }\n onImageUpdated(updatedImage)\n\n setDeactivateModalOpen(false)\n setSelectedImage(null)\n const { message, ...options } = getImageDeactivatedToast(imageName)\n toast.success(message, options)\n } catch (error) {\n const errorMessage = (error as TRPCClientError<InferrableClientTypes>)?.message ?? \"\"\n const { message, ...options } = getImageDeactivationErrorToast(imageId, errorMessage)\n toast.error(message, options)\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 utils.compute.listImagesWithPagination.invalidate()\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 const { message, ...options } = getBulkDeleteSuccessToast(successCount, totalCount)\n toast.success(message, options)\n } else if (successCount === 0) {\n const { message, ...options } = getBulkDeleteErrorToast(failedCount, totalCount)\n toast.error(message, options)\n } else {\n const { message, ...options } = getBulkDeletePartialToast(successCount, failedCount)\n toast.warning(message, options)\n }\n\n if (result.successful.length > 0) onImageDeleted(result.successful)\n } catch (error) {\n const errorMessage = (error as TRPCClientError<InferrableClientTypes>)?.message ?? \"\"\n\n console.log(\"Bulk delete error: \", errorMessage)\n\n const { message, ...options } = getBulkDeleteErrorToast(imageIds.length, imageIds.length)\n toast.error(message, options)\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 // Optimistically update successful images\n result.successful.forEach((imageId) => {\n const image = images.find((img) => img.id === imageId)\n if (image) {\n onImageUpdated({ ...image, status: IMAGE_STATUSES.ACTIVE })\n }\n })\n\n if (failedCount === 0) {\n const { message, ...options } = getBulkActivateSuccessToast(successCount, totalCount)\n toast.success(message, options)\n } else if (successCount === 0) {\n const { message, ...options } = getBulkActivateErrorToast(failedCount, totalCount)\n toast.error(message, options)\n } else {\n const { message, ...options } = getBulkActivatePartialToast(successCount, failedCount)\n toast.warning(message, options)\n }\n } catch (error) {\n const errorMessage = (error as TRPCClientError<InferrableClientTypes>)?.message ?? \"\"\n\n console.log(\"Bulk activate error: \", errorMessage)\n\n const { message, ...options } = getBulkActivateErrorToast(imageIds.length, imageIds.length)\n toast.error(message, options)\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 // Optimistically update successful images\n result.successful.forEach((imageId) => {\n const image = images.find((img) => img.id === imageId)\n if (image) {\n onImageUpdated({ ...image, status: IMAGE_STATUSES.DEACTIVATED })\n }\n })\n\n if (failedCount === 0) {\n const { message, ...options } = getBulkDeactivateSuccessToast(successCount, totalCount)\n toast.success(message, options)\n } else if (successCount === 0) {\n const { message, ...options } = getBulkDeactivateErrorToast(failedCount, totalCount)\n toast.error(message, options)\n } else {\n const { message, ...options } = getBulkDeactivatePartialToast(successCount, failedCount)\n toast.warning(message, options)\n }\n } catch (error) {\n const errorMessage = (error as TRPCClientError<InferrableClientTypes>)?.message ?? \"\"\n\n console.log(\"Bulk deactivate error: \", errorMessage)\n\n const { message, ...options } = getBulkDeactivateErrorToast(imageIds.length, imageIds.length)\n toast.error(message, options)\n }\n }\n\n const updateCurrentPage = (newPage: number) => {\n if (newPage >= 1 && newPage <= totalPages) {\n onPageChange?.(newPage)\n }\n }\n\n if (isLoading) {\n return (\n <div data-testid=\"loading\">\n <DataGridRow>\n <DataGridCell colSpan={3}>\n <Status status=\"progress\" title={t`Loading...`} />\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 <Status status=\"progress\" title={t`Loading Images...`} />\n </div>\n )}\n\n {/* Images Table */}\n\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 && <DataGridHeadCell></DataGridHeadCell>}\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 {images.length > 0 ? (\n images.map((image) => (\n <ImageTableRow\n image={image}\n isSelected={selectedImages.includes(image.id)}\n isPending={pendingSharedIds.has(image.id)}\n isAccepted={acceptedSharedIds.has(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 uploadId={uploadId}\n uploadProgressPercent={data?.percent}\n onMemberStatusChanged={onMemberStatusChanged}\n />\n ))\n ) : (\n <DataGridRow>\n <DataGridCell colSpan={hasAnyBulkAction ? 9 : 8}>\n <Status\n status=\"empty\"\n title={t`No images found`}\n body={t`There are no images available for this project with the current filters applied. Try adjusting your filter criteria or create a new image.`}\n />\n </DataGridCell>\n </DataGridRow>\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={() => updateCurrentPage(Math.max(currentPage - 1, 1))}\n onPressNext={() => updateCurrentPage(Math.min(currentPage + 1, totalPages))}\n onSelectChange={(selectedPage: number) => {\n updateCurrentPage(selectedPage)\n }}\n onInputChange={() => {\n // Input change is handled by the Pagination component internally\n }}\n onKeyDown={(e: React.KeyboardEvent<HTMLInputElement>) => {\n if (e.key === \"Enter\") {\n const inputValue = (e.target as HTMLInputElement).value\n if (inputValue !== \"\") {\n const newPage = parseInt(inputValue, 10)\n if (!isNaN(newPage) && newPage >= 1 && newPage <= totalPages) {\n updateCurrentPage(newPage)\n }\n }\n }\n }}\n />\n </div>\n )}\n </>\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 key=\"edit-metadata-modal\"\n client={trpcClient}\n isOpen={editMetadataModalOpen}\n onClose={closeEditMetadataModal}\n image={selectedImage}\n projectId={projectId}\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={() => setCreateModalOpen(false)}\n onCreate={handleCreate}\n isLoading={createImageMutation.isPending || isUploadPending || isCreateInProgress}\n isUploadPending={isUploadPending && !!uploadId}\n uploadProgressPercent={data?.percent}\n onCancelUpload={handleCancelUpload}\n />\n </div>\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 marker?: string\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 marker,\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 { ErrorBoundary } from \"react-error-boundary\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { TrpcClient, trpcReact } from \"@/client/trpcClient\"\nimport { GlanceImage } from \"@/server/Compute/types/image\"\nimport { useNavigate, useSearch } from \"@tanstack/react-router\"\nimport { useProjectId } from \"@/client/hooks\"\nimport {\n Button,\n Stack,\n Status,\n PopupMenu,\n PopupMenuItem,\n PopupMenuToggle,\n PopupMenuOptions,\n PopupMenuSectionSeparator,\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 \"./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\n// Extract marker value from URL or return as-is if already a marker\nfunction extractMarker(nextValue: string | undefined): string | undefined {\n if (!nextValue) return undefined\n // If it's a full URL like \"/v2/images?marker=xyz\", extract just the marker value\n if (nextValue.includes(\"?\")) {\n const url = new URL(nextValue, \"http://dummy.com\")\n return url.searchParams.get(\"marker\") || undefined\n }\n return nextValue\n}\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 totalCount?: number\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 projectId = useProjectId()\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 // Fetch shared images to determine ownership for bulk actions\n const sharedPendingQuery = trpcReact.compute.listSharedImagesByMemberStatus.useQuery(\n { project_id: projectId, memberStatus: \"pending\" },\n { retry: false }\n )\n const sharedAcceptedQuery = trpcReact.compute.listSharedImagesByMemberStatus.useQuery(\n { project_id: projectId, memberStatus: \"accepted\" },\n { retry: false }\n )\n const pendingSharedIds = new Set((sharedPendingQuery.data ?? []).map((img) => img.id))\n const acceptedSharedIds = new Set((sharedAcceptedQuery.data ?? []).map((img) => img.id))\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 // Calculate total pages from API's totalCount if available\n const PAGE_SIZE = 50\n const hasNextPage = !!imagesData.next\n const totalItems = imagesData.totalCount ?? (hasNextPage ? PAGE_SIZE * (currentPage + 1) : images.length)\n const totalPages = Math.max(1, Math.ceil(totalItems / PAGE_SIZE))\n const safePage = Math.min(currentPage, totalPages)\n\n useEffect(() => {\n if (currentPage !== safePage) onPageChange(safePage)\n }, [currentPage, safePage, 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 // Detect pagination mode: server-paginated (totalCount present) vs client-paginated (member-status views)\n const isServerPaginated = imagesData.totalCount !== undefined\n const pageImages = isServerPaginated ? images : images.slice((safePage - 1) * PAGE_SIZE, safePage * PAGE_SIZE)\n const displayedImageIds = new Set(pageImages.map((image: GlanceImage) => image.id))\n const validSelectedImages = selectedImages.filter((imageId) => displayedImageIds.has(imageId))\n\n // For checkbox behavior: use images from current page\n const paginatedImages = pageImages\n\n // Build ID→image lookup once to avoid repeated O(n*m) finds\n const imageById = new Map(pageImages.map((image: GlanceImage) => [image.id, image]))\n const selectedImageObjects = validSelectedImages.map((id) => imageById.get(id)).filter(Boolean) as GlanceImage[]\n\n // Bulk mutations are available only for images owned by the current project\n const ownedSelectedImages = selectedImageObjects.filter((image) => image.owner === projectId)\n\n const deletableImages = ownedSelectedImages.filter((image) => image.protected !== true)\n const protectedImages = ownedSelectedImages.filter((image) => image.protected === true)\n const activeImages = ownedSelectedImages.filter((image) => image.status === IMAGE_STATUSES.ACTIVE)\n const deactivatedImages = ownedSelectedImages.filter((image) => image.status === IMAGE_STATUSES.DEACTIVATED)\n\n const isDeleteAllDisabled =\n !permissions.canDelete ||\n validSelectedImages.length === 0 ||\n pageImages\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 pageImages\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 pageImages\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\" className=\"pb-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=\"2\" alignment=\"center\">\n <SortInput\n options={sortSettings.options}\n sortBy={sortSettings.sortBy}\n sortDirection={sortSettings.sortDirection ?? \"desc\"}\n selectClassName=\"min-w-40\"\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 selectClassName=\"sm:min-w-40\"\n comboboxClassName=\"sm:min-w-40\"\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 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.canUpdate && (\n <PopupMenuItem\n disabled={isActivateAllDisabled}\n label={t`Activate Selected`}\n onClick={() => setActivateAllModalOpen(true)}\n />\n )}\n {permissions.canUpdate && (\n <PopupMenuItem\n disabled={isDeactivateAllDisabled}\n label={t`Deactivate Selected`}\n onClick={() => setDeactivateAllModalOpen(true)}\n />\n )}\n {permissions.canDelete && (\n <>\n <PopupMenuSectionSeparator />\n <PopupMenuItem\n disabled={isDeleteAllDisabled}\n label={t`Delete Selected`}\n onClick={() => setDeleteAllModalOpen(true)}\n />\n </>\n )}\n </PopupMenuOptions>\n </PopupMenu>\n </Stack>\n </Stack>\n </DataGridToolbar>\n )}\n <ImageListView\n images={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 pendingSharedIds={pendingSharedIds}\n acceptedSharedIds={acceptedSharedIds}\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`Image 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 [pageMarkers, setPageMarkers] = useState<Map<number, string | undefined>>(new Map([[1, undefined]]))\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 // Compute effective filters based on member status view\n // When viewing pending/accepted tabs, visibility filter is not applicable\n const computeEffectiveFilters = useCallback(\n (memberStatus: \"all\" | \"pending\" | \"accepted\" | undefined, selectedFilters: FilterSettings[\"selectedFilters\"]) => {\n return memberStatus === \"pending\" || memberStatus === \"accepted\"\n ? (selectedFilters || []).filter((f) => f.name !== \"visibility\")\n : selectedFilters || []\n },\n []\n )\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 = computeEffectiveFilters(urlMemberStatus, filterSettings.selectedFilters)\n const marker = pageMarkers.get(currentPage)\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 marker\n )\n newPromise\n .then((result) => {\n setPageMarkers((prev) => {\n if (!result.next) return prev\n const nextPage = currentPage + 1\n if (prev.has(nextPage)) return prev\n return new Map(prev).set(nextPage, extractMarker(result.next))\n })\n })\n .catch(() => {})\n .finally(() => setIsFetching(false))\n setImagesPromise(newPromise as Promise<ImagesResult>)\n })\n }, [client, sortSettings, searchTerm, filterSettings, searchParams.memberStatus, currentPage, pageMarkers])\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 const urlPage = searchParams.page ?? 1\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 = computeEffectiveFilters(urlMemberStatus, urlFilters)\n const marker = pageMarkers.get(urlPage)\n\n // If we don't have a marker for this page and it's not page 1, navigate to page 1\n if (!marker && urlPage > 1) {\n navigate({\n search: ((prev: ImagesSearchParams) => ({\n ...prev,\n page: undefined,\n })) as unknown as true,\n })\n setIsFetching(false)\n return\n }\n\n const newPromise = createImagesPromise(\n client,\n project,\n urlSortBy,\n urlSortDirection,\n urlSearchTerm,\n {\n ...buildFilterParams(effectiveFilters, filterSettings.filters),\n member_status: urlMemberStatusFilter,\n },\n marker\n )\n newPromise\n .then((result) => {\n setPageMarkers((prev) => {\n if (!result.next) return prev\n const nextPage = urlPage + 1\n if (prev.has(nextPage)) return prev\n return new Map(prev).set(nextPage, extractMarker(result.next))\n })\n })\n .catch(() => {})\n .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 searchParams.page,\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 setPageMarkers(new Map([[1, undefined]]))\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 setPageMarkers(new Map([[1, undefined]]))\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 setPageMarkers(new Map([[1, undefined]]))\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 setPageMarkers(new Map([[1, undefined]]))\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 <ErrorBoundary\n fallbackRender={({ error }) => (\n <Status\n status=\"error\"\n title={t`Failed to Load Images`}\n body={error instanceof Error ? error.message : t`An Unexpected Error Occurred.`}\n />\n )}\n >\n <Suspense fallback={<Status status=\"progress\" title={t`Loading Images...`} />}>\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 </ErrorBoundary>\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/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 analytics: {\n name: \"compute.images.list\",\n },\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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"}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { jsx as e } from "react/jsx-runtime";
|
|
2
|
-
import { Outlet as t } from "@tanstack/react-router";
|
|
3
|
-
//#region src/client/routes/_auth/projects/$projectId/compute/images.tsx?tsr-split=component
|
|
4
|
-
var n = () => /*#__PURE__*/ e(t, {});
|
|
5
|
-
//#endregion
|
|
6
|
-
export { n as component };
|
|
7
|
-
|
|
8
|
-
//# sourceMappingURL=images-NBf2bV43.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"images-NBf2bV43.mjs","names":["Outlet","SplitComponent","component"],"sources":["../../src/client/routes/_auth/projects/$projectId/compute/images.tsx?tsr-split=component"],"sourcesContent":["import { createFileRoute, Outlet, redirect } from \"@tanstack/react-router\"\nimport { z } from \"zod\"\nimport { getServiceIndex } from \"@/server/Authentication/helpers\"\nimport { msg } from \"@lingui/core/macro\"\nimport type { RouteInfo } from \"@/client/routes/routeInfo\"\n\nconst multiValueEnum = (allowedValues: string[]) => {\n return z.string().refine((val) => {\n const values = val.startsWith(\"in:\") ? val.replace(\"in:\", \"\").split(\",\") : [val]\n return values.every((v) => allowedValues.includes(v))\n })\n}\n\nconst imagesSearchFields = {\n status: multiValueEnum([\n \"queued\",\n \"saving\",\n \"active\",\n \"deactivated\",\n \"killed\",\n \"deleted\",\n \"pending_delete\",\n ]).optional(),\n visibility: z.enum([\"public\", \"private\", \"shared\", \"community\", \"all\"]).optional(),\n disk_format: multiValueEnum([\n \"ami\",\n \"ari\",\n \"aki\",\n \"vhd\",\n \"vhdx\",\n \"vmdk\",\n \"raw\",\n \"qcow2\",\n \"vdi\",\n \"iso\",\n \"ploop\",\n ]).optional(),\n container_format: multiValueEnum([\"ami\", \"ari\", \"aki\", \"bare\", \"ovf\", \"ova\", \"docker\"]).optional(),\n protected: z.enum([\"true\", \"false\"]).optional(),\n search: z.string().optional(),\n sortBy: z.enum([\"created_at\", \"updated_at\", \"name\", \"size\", \"status\"]).optional(),\n sortDirection: z.enum([\"asc\", \"desc\"]).optional(),\n memberStatus: z.enum([\"all\", \"accepted\", \"pending\"]).optional(),\n page: z.number().int().positive().optional(),\n}\n\nconst imagesSearchSchema = z.looseObject(imagesSearchFields)\n\nexport const Route = createFileRoute(\"/_auth/projects/$projectId/compute/images\")({\n staticData: {\n section: \"compute\",\n service: \"images\",\n crumb: { text: msg`Images` },\n } satisfies RouteInfo,\n validateSearch: (search) => {\n const result = imagesSearchSchema.safeParse(search)\n if (result.success) return result.data\n return {\n ...search,\n status: imagesSearchFields.status.safeParse(search.status).success ? search.status : undefined,\n visibility: imagesSearchFields.visibility.safeParse(search.visibility).success ? search.visibility : undefined,\n disk_format: imagesSearchFields.disk_format.safeParse(search.disk_format).success\n ? search.disk_format\n : undefined,\n container_format: imagesSearchFields.container_format.safeParse(search.container_format).success\n ? search.container_format\n : undefined,\n protected: imagesSearchFields.protected.safeParse(search.protected).success ? search.protected : undefined,\n search: imagesSearchFields.search.safeParse(search.search).success ? search.search : undefined,\n sortBy: imagesSearchFields.sortBy.safeParse(search.sortBy).success ? search.sortBy : undefined,\n sortDirection: imagesSearchFields.sortDirection.safeParse(search.sortDirection).success\n ? search.sortDirection\n : undefined,\n memberStatus: imagesSearchFields.memberStatus.safeParse(search.memberStatus).success\n ? search.memberStatus\n : undefined,\n page: imagesSearchFields.page.safeParse(search.page).success ? (search.page as number) : undefined,\n }\n },\n beforeLoad: async ({ context, params }) => {\n const { trpcClient } = context\n const { projectId } = params\n\n if (!trpcClient) {\n throw new Error(\"trpcClient is not available in route context\")\n }\n\n const availableServices = await trpcClient.auth.getAvailableServices.query()\n const serviceIndex = getServiceIndex(availableServices)\n\n if (!serviceIndex[\"image\"]?.[\"glance\"]) {\n throw redirect({\n to: \"/projects/$projectId\",\n params: { projectId },\n })\n }\n },\n component: () => <Outlet />,\n})\n"],"mappings":";;;AAA0E,IAAAC,UAiGvD,gBAAC,GAAA,CAAA,CAAA"}
|