@cobaltcore-dev/aurora 1.3.0 → 2.0.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/dist/client/DeleteFlavorModal-C2MqUgGR.mjs +801 -0
- package/dist/client/DeleteFlavorModal-C2MqUgGR.mjs.map +1 -0
- package/dist/client/{FiltersInput-CKI6zWnm.mjs → FiltersInput-Becwxo_J.mjs} +36 -33
- package/dist/client/FiltersInput-Becwxo_J.mjs.map +1 -0
- package/dist/client/{FloatingIpActionModals-Ch8uozH9.mjs → FloatingIpActionModals-Cq10WljB.mjs} +2 -2
- package/dist/client/{FloatingIpActionModals-Ch8uozH9.mjs.map → FloatingIpActionModals-Cq10WljB.mjs.map} +1 -1
- package/dist/client/ImageToastNotifications-BWfzOUMc.mjs +1135 -0
- package/dist/client/ImageToastNotifications-BWfzOUMc.mjs.map +1 -0
- package/dist/client/RouteIdLevelDefaultError-CSseJ1yG.mjs +26 -0
- package/dist/client/RouteIdLevelDefaultError-CSseJ1yG.mjs.map +1 -0
- package/dist/client/{_flavorId-Dg7MS0Af.mjs → _flavorId-CaA4-Pnf.mjs} +4 -3
- package/dist/client/_flavorId-CaA4-Pnf.mjs.map +1 -0
- package/dist/client/_flavorId-DYv_StX22.mjs +276 -0
- package/dist/client/_flavorId-DYv_StX22.mjs.map +1 -0
- package/dist/client/_flavorId-YV3jCS5g.mjs +22 -0
- package/dist/client/_flavorId-YV3jCS5g.mjs.map +1 -0
- package/dist/client/{_floatingIpId-C9xfRWot.mjs → _floatingIpId-BeYElanB.mjs} +2 -2
- package/dist/client/{_floatingIpId-C9xfRWot.mjs.map → _floatingIpId-BeYElanB.mjs.map} +1 -1
- package/dist/client/{_floatingIpId-DNn6ABCB.mjs → _floatingIpId-Dpsc7GU4.mjs} +5 -5
- package/dist/client/{_floatingIpId-DNn6ABCB.mjs.map → _floatingIpId-Dpsc7GU4.mjs.map} +1 -1
- package/dist/client/_imageId-mfKp3JHn.mjs +558 -0
- package/dist/client/_imageId-mfKp3JHn.mjs.map +1 -0
- package/dist/client/_imageId-mpXUMCh_.mjs +22 -0
- package/dist/client/_imageId-mpXUMCh_.mjs.map +1 -0
- package/dist/client/{_imageId-8JIbFmGB.mjs → _imageId-pBSS0YcC.mjs} +4 -3
- package/dist/client/_imageId-pBSS0YcC.mjs.map +1 -0
- package/dist/client/{_projectId-B3wmSala.mjs → _projectId-AjgJX6Gl.mjs} +2 -2
- package/dist/client/_projectId-AjgJX6Gl.mjs.map +1 -0
- package/dist/client/{_projectId-DPzv0CCp.mjs → _projectId-BnTBxKfp.mjs} +4 -4
- package/dist/client/_projectId-BnTBxKfp.mjs.map +1 -0
- package/dist/client/{_projectId-DfeVJy0G.mjs → _projectId-CVrdJ52s.mjs} +2 -2
- package/dist/client/_projectId-CVrdJ52s.mjs.map +1 -0
- package/dist/client/_projectId-DgciZslU.mjs +92 -0
- package/dist/client/_projectId-DgciZslU.mjs.map +1 -0
- package/dist/client/{_securityGroupId-C6eHmrx_.mjs → _securityGroupId-AO3wnH8g.mjs} +2 -2
- package/dist/client/_securityGroupId-AO3wnH8g.mjs.map +1 -0
- package/dist/client/{_securityGroupId-DmplhDgt.mjs → _securityGroupId-Bq0ZyG6z.mjs} +750 -741
- package/dist/client/_securityGroupId-Bq0ZyG6z.mjs.map +1 -0
- package/dist/client/_storageType-c-DAu8qr.mjs +858 -0
- package/dist/client/_storageType-c-DAu8qr.mjs.map +1 -0
- package/dist/client/components/{Error → Errors}/RouteError.d.ts +5 -0
- package/dist/client/components/Errors/RouteIdLevelDefaultError.d.ts +17 -0
- package/dist/client/components/Errors/ServiceLevelDefaultError.d.ts +9 -0
- package/dist/client/components/ListToolbar/SelectedFilters.d.ts +7 -2
- package/dist/client/components/ListToolbar/types.d.ts +6 -0
- package/dist/client/components/ListToolbar/valueLabels.d.ts +11 -0
- package/dist/client/flavors-Bgq3KZmx.mjs +659 -0
- package/dist/client/flavors-Bgq3KZmx.mjs.map +1 -0
- package/dist/client/{flavors-B1SDOPDu.mjs → flavors-ZudiAiTU.mjs} +2 -2
- package/dist/client/{flavors-B1SDOPDu.mjs.map → flavors-ZudiAiTU.mjs.map} +1 -1
- package/dist/client/{floatingips-DrCvtXtT.mjs → floatingips-B1oLH8z6.mjs} +6 -6
- package/dist/client/{floatingips-DrCvtXtT.mjs.map → floatingips-B1oLH8z6.mjs.map} +1 -1
- package/dist/client/floatingips-BeQEkVH8.mjs +14 -0
- package/dist/client/floatingips-BeQEkVH8.mjs.map +1 -0
- package/dist/client/floatingips-BtLg3yEQ.mjs +22 -0
- package/dist/client/floatingips-BtLg3yEQ.mjs.map +1 -0
- package/dist/client/floatingips-Cz9k80cc.mjs.map +1 -1
- package/dist/client/{images-BGQv9kKT.mjs → images-CnTW3bpy.mjs} +810 -770
- package/dist/client/images-CnTW3bpy.mjs.map +1 -0
- package/dist/client/{images-CPmMa4SQ.mjs → images-DZHDYDQu.mjs} +2 -2
- package/dist/client/{images-CPmMa4SQ.mjs.map → images-DZHDYDQu.mjs.map} +1 -1
- package/dist/client/index.js +412 -409
- package/dist/client/index.js.map +1 -1
- package/dist/client/{objects-DVccbrL1.mjs → objects-25xsh4Ia.mjs} +2 -2
- package/dist/client/objects-25xsh4Ia.mjs.map +1 -0
- package/dist/client/objects-KXY6dgwq.mjs +82 -0
- package/dist/client/objects-KXY6dgwq.mjs.map +1 -0
- package/dist/client/objects-QryuClU3.mjs +82 -0
- package/dist/client/objects-QryuClU3.mjs.map +1 -0
- package/dist/client/{objects-BR3eeSNH.mjs → objects-jYQBFzwg.mjs} +4668 -4699
- package/dist/client/objects-jYQBFzwg.mjs.map +1 -0
- package/dist/client/projects-yiK0HGSA.mjs.map +1 -1
- package/dist/client/securitygroups--0PS2wbM.mjs +580 -0
- package/dist/client/securitygroups--0PS2wbM.mjs.map +1 -0
- package/dist/client/{securitygroups-DEJQBcxm.mjs → securitygroups-BRndk7wh.mjs} +2 -2
- package/dist/client/{securitygroups-DEJQBcxm.mjs.map → securitygroups-BRndk7wh.mjs.map} +1 -1
- package/dist/client/securitygroups-CdN4yAAw.mjs +14 -0
- package/dist/client/securitygroups-CdN4yAAw.mjs.map +1 -0
- package/dist/client/securitygroups-Cs2Op-tu.mjs +22 -0
- package/dist/client/securitygroups-Cs2Op-tu.mjs.map +1 -0
- package/dist/client/securitygroups-CtKne8UQ.mjs.map +1 -1
- package/dist/client/trpcClient.d.ts +6 -1
- package/dist/client/useModalTracking-BYd37pXm.mjs +37 -0
- package/dist/client/useModalTracking-BYd37pXm.mjs.map +1 -0
- package/dist/client/useSecurityGroupPermissions--hK4aR8Y.mjs +294 -0
- package/dist/client/useSecurityGroupPermissions--hK4aR8Y.mjs.map +1 -0
- package/dist/server/index.d.ts +6 -1
- package/dist/server/index.js +96 -30
- package/package.json +4 -4
- package/dist/client/DeleteFlavorModal-V44QCJBd.mjs +0 -773
- package/dist/client/DeleteFlavorModal-V44QCJBd.mjs.map +0 -1
- package/dist/client/FiltersInput-CKI6zWnm.mjs.map +0 -1
- package/dist/client/ImageToastNotifications-m6c3tVPb.mjs +0 -1152
- package/dist/client/ImageToastNotifications-m6c3tVPb.mjs.map +0 -1
- package/dist/client/_flavorId-Dg7MS0Af.mjs.map +0 -1
- package/dist/client/_flavorId-kHl-b8rI.mjs +0 -232
- package/dist/client/_flavorId-kHl-b8rI.mjs.map +0 -1
- package/dist/client/_imageId-8JIbFmGB.mjs.map +0 -1
- package/dist/client/_imageId-BBAlRioC.mjs +0 -574
- package/dist/client/_imageId-BBAlRioC.mjs.map +0 -1
- package/dist/client/_projectId-7Nl1MQTJ.mjs +0 -99
- package/dist/client/_projectId-7Nl1MQTJ.mjs.map +0 -1
- package/dist/client/_projectId-B3wmSala.mjs.map +0 -1
- package/dist/client/_projectId-DPzv0CCp.mjs.map +0 -1
- package/dist/client/_projectId-DfeVJy0G.mjs.map +0 -1
- package/dist/client/_securityGroupId-C6eHmrx_.mjs.map +0 -1
- package/dist/client/_securityGroupId-DmplhDgt.mjs.map +0 -1
- package/dist/client/_storageType-C5gS9eut.mjs +0 -845
- package/dist/client/_storageType-C5gS9eut.mjs.map +0 -1
- package/dist/client/flavors-D8_PzQUB.mjs +0 -628
- package/dist/client/flavors-D8_PzQUB.mjs.map +0 -1
- package/dist/client/images-BGQv9kKT.mjs.map +0 -1
- package/dist/client/objects-AERkhfiM.mjs +0 -66
- package/dist/client/objects-AERkhfiM.mjs.map +0 -1
- package/dist/client/objects-BR3eeSNH.mjs.map +0 -1
- package/dist/client/objects-DVccbrL1.mjs.map +0 -1
- package/dist/client/securitygroups-BjhgLBHm.mjs +0 -620
- package/dist/client/securitygroups-BjhgLBHm.mjs.map +0 -1
- package/dist/client/useModalTracking-BcOKTYRN.mjs +0 -33
- package/dist/client/useModalTracking-BcOKTYRN.mjs.map +0 -1
- package/dist/client/useSecurityGroupPermissions-BOyLQLdC.mjs +0 -227
- package/dist/client/useSecurityGroupPermissions-BOyLQLdC.mjs.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"objects-jYQBFzwg.mjs","names":["createFileRoute","redirect","z","getServiceIndex","checkServiceAvailability","availableServices","type","name","params","projectId","provider","serviceIndex","to","hasSwift","Boolean","hasCeph","cephFallbackEnabled","hasEffectiveCeph","fallbackProvider","fallbackStorageType","storageType","containersSearchSchema","object","sortBy","enum","optional","sortDirection","search","string","Route","staticData","section","service","analytics","RouteInfo","validateSearch","head","match","meta","title","component","lazyRouteComponent","$$splitComponentImporter","notFoundComponent","$$splitNotFoundComponentImporter","loader","context","trpcClient","auth","getAvailableServices","query","client","beforeLoad","redirect","getServiceIndex","checkServiceAvailability","availableServices","params","provider","projectId","storageType","containerName","serviceIndex","to","hasSwift","Boolean","hasCeph","cephFallbackEnabled","hasEffectiveCeph","fallbackProvider","fallbackStorageType","expectedStorageType","HAS_ZONE","parseSwiftDate","value","trimmed","trim","needsUtc","includes","test","normalized","date","Date","Number","isNaN","getTime","formatSwiftDate","locales","options","toLocaleString","useCallback","useLayoutEffect","useRef","useState","DEFAULT_BOTTOM_GAP","GAP","FOOTER_SELECTOR","MIN_HEIGHT","findBottomBoundary","footer","document","querySelector","getBoundingClientRect","top","window","scrollY","innerHeight","useAvailableViewportHeight","elementRef","element","setElement","height","setHeight","undefined","ref","node","current","frame","measure","bottom","available","Math","floor","next","max","previous","abs","scheduleMeasure","requestAnimationFrame","observer","ResizeObserver","observe","body","parentElement","addEventListener","cancelAnimationFrame","disconnect","removeEventListener","useVirtualizer","useAvailableViewportHeight","ROW_HEIGHT","OVERSCAN","useVirtualizedTableBody","count","rowHeight","overscan","ref","elementRef","height","virtualizer","getScrollElement","current","estimateSize","isMeasured","undefined","virtualItems","getVirtualItems","totalSize","getTotalSize","measureElement","useEffect","useRef","useState","trpcReact","useProjectId","Modal","Stack","Status","TextInput","useParams","CONFIRM_WORD","DeleteFolderModal","isOpen","folder","onClose","onSuccess","onError","useLingui","projectId","containerName","from","utils","useUtils","submittedFolderNameRef","confirmValue","setConfirmValue","isConfirmed","trim","deleteFolderMutation","storage","swift","deleteFolder","useMutation","deletedCount","listObjects","invalidate","project_id","container","current","error","message","onSettled","handleClose","reset","handleConfirm","displayName","mutate","folderPath","name","recursive","folderDisplayName","title","span","className","open","onCancel","confirmButtonLabel","isPending","t","confirmButtonVariant","onConfirm","cancelButtonLabel","size","disableConfirmButton","disableCancelButton","disableCloseButton","status","direction","gap","p","strong","label","placeholder","value","onChange","event","target","z","useForm","useStore","useEffect","useRef","useState","trpcReact","useProjectId","Modal","Stack","Status","Checkbox","Form","FormSection","TextInput","useParams","DeleteObjectModal","isOpen","object","onClose","onSuccess","onError","useLingui","projectId","containerName","from","utils","useUtils","formSchema","confirm","string","refine","value","message","t","form","defaultValues","validators","onSubmit","deleteObjectMutation","isPending","displayNameRef","current","displayName","mutate","project_id","container","name","isSLO","keepSegments","multipartManifest","canDelete","store","state","isSubmitting","values","setKeepSegments","data","metadata","isLoading","isLoadingMetadata","error","metadataError","storage","swift","getObjectMetadata","useQuery","enabled","staticLargeObject","isDLO","objectManifest","deleteObject","useMutation","listObjects","invalidate","onSettled","handleClose","reset","metadataErrorMessage","title","span","className","open","onCancel","confirmButtonLabel","confirmButtonVariant","onConfirm","handleSubmit","cancelButtonLabel","size","disableConfirmButton","status","body","direction","gap","p","strong","label","checked","onChange","e","target","id","preventDefault","Field","children","field","handleChange","placeholder","autoFocus","disabled","required","useState","useRef","useEffect","useCallback","trpcReact","useProjectId","Modal","Stack","Status","Spinner","ComboBox","ComboBoxOption","TextInput","Button","useParams","MdFolder","MdDescription","MdCreateNewFolder","MdArrowBack","useVirtualizer","buildRows","MAX_COMBO_OPTIONS","CopyObjectModal","isOpen","object","onClose","onSuccess","onError","useLingui","projectId","containerName","sourceContainer","from","utils","useUtils","submittedNameRef","targetContainer","setTargetContainer","currentPrefix","setCurrentPrefix","localFolders","setLocalFolders","newFolderName","setNewFolderName","newFolderError","setNewFolderError","showNewFolderInput","setShowNewFolderInput","copyMetadata","setCopyMetadata","containerSearch","setContainerSearch","debouncedSearch","setDebouncedSearch","debounceTimer","listRef","current","clearTimeout","prev","next","data","containers","isLoading","isLoadingContainers","storage","swift","listContainers","useQuery","project_id","enabled","objects","isLoadingObjects","listObjects","container","format","prefix","undefined","serverRows","containerLocalFolders","localFolderRows","filter","fp","withoutPrefix","startsWith","slice","length","parts","split","Boolean","some","r","name","map","kind","displayName","replace","rows","filteredContainers","trim","c","toLowerCase","includes","visibleContainers","hiddenCount","copyMutation","copyObject","useMutation","invalidate","handleClose","error","message","reset","handleContainerSearch","e","value","target","setTimeout","handleContainerChange","v","Array","isArray","String","handleFolderClick","folderName","handleNavigateUp","pop","join","validateNewFolderName","trimmed","t","newPath","handleCreateFolder","handleNewFolderKeyDown","key","handleCopy","destPath","mutate","destination","freshMetadata","folderRows","allBrowserRows","rowVirtualizer","count","getScrollElement","estimateSize","overscan","isPending","targetPathDisplay","initialPrefix","endsWith","isUnchanged","title","span","className","open","onCancel","confirmButtonLabel","onConfirm","cancelButtonLabel","size","disableConfirmButton","disableCancelButton","disableCloseButton","status","direction","gap","isError","errorMessage","p","label","onChange","onInputChange","placeholder","helptext","maxOptions","totalCount","disabled","required","div","variant","icon","onClick","button","type","data-testid","ref","alignment","style","height","getTotalSize","position","getVirtualItems","virtualRow","row","index","isFolder","data-index","measureElement","top","left","width","transform","start","onKeyDown","invalid","errortext","autoFocus","input","checked","useState","useRef","useEffect","useCallback","trpcReact","useProjectId","Modal","Stack","Status","Spinner","ComboBox","ComboBoxOption","TextInput","Button","useParams","MdFolder","MdDescription","MdCreateNewFolder","MdArrowBack","useVirtualizer","buildRows","MAX_COMBO_OPTIONS","MoveRenameObjectModal","isOpen","object","onClose","onSuccess","onError","useLingui","projectId","containerName","sourceContainer","from","utils","useUtils","submittedNameRef","targetContainer","setTargetContainer","currentPrefix","setCurrentPrefix","newObjectName","setNewObjectName","newObjectNameError","setNewObjectNameError","localFolders","setLocalFolders","newFolderName","setNewFolderName","newFolderError","setNewFolderError","showNewFolderInput","setShowNewFolderInput","containerSearch","setContainerSearch","debouncedSearch","setDebouncedSearch","debounceTimer","listRef","current","clearTimeout","prev","next","displayName","data","containers","isLoading","isLoadingContainers","storage","swift","listContainers","useQuery","project_id","enabled","objects","isLoadingObjects","listObjects","container","format","prefix","undefined","serverRows","containerLocalFolders","localFolderRows","filter","fp","withoutPrefix","startsWith","slice","length","parts","split","Boolean","some","r","name","map","kind","replace","rows","filteredContainers","trim","c","toLowerCase","includes","visibleContainers","hiddenCount","deleteMutation","deleteObject","useMutation","containersToInvalidate","Set","forEach","invalidate","error","message","onSettled","handleClose","copyMutation","copyObject","mutate","reset","handleContainerSearch","e","value","target","setTimeout","handleContainerChange","v","Array","isArray","String","handleFolderClick","folderName","handleNavigateUp","pop","join","validateNewFolderName","trimmed","t","newPath","validateObjectName","handleCreateFolder","handleNewFolderKeyDown","key","handleMove","trimmedName","destPath","destination","freshMetadata","folderRows","allBrowserRows","rowVirtualizer","count","getScrollElement","estimateSize","overscan","isPending","targetPathDisplay","initialPrefix","endsWith","isUnchanged","title","span","className","open","onCancel","confirmButtonLabel","onConfirm","cancelButtonLabel","size","disableConfirmButton","disableCancelButton","disableCloseButton","status","direction","gap","isError","copyErrorMessage","deleteErrorMessage","p","div","label","onChange","invalid","errortext","required","onInputChange","placeholder","helptext","maxOptions","totalCount","disabled","variant","icon","onClick","button","type","data-testid","ref","alignment","style","height","getTotalSize","position","getVirtualItems","virtualRow","row","index","isFolder","data-index","measureElement","top","left","width","transform","start","onKeyDown","autoFocus","useEffect","useRef","useState","trpcReact","useProjectId","Modal","Stack","Spinner","TextInput","Icon","Select","SelectOption","Message","useParams","CUSTOM_VALUE","GenerateTempUrlModal","isOpen","object","account","onClose","onCopySuccess","useLingui","projectId","containerName","from","EXPIRY_PRESETS","labelKey","t","seconds","selectedPreset","setSelectedPreset","String","customMinutes","setCustomMinutes","customMinutesError","setCustomMinutesError","copied","setCopied","tempUrl","setTempUrl","expiresAt","setExpiresAt","noKeyError","setNoKeyError","generalError","setGeneralError","copyError","setCopyError","displayNameRef","copyTimeoutRef","requestIdRef","handleGenerateSuccess","data","url","handleGenerateError","error","message","includes","generateMutation","storage","swift","generateTempUrl","useMutation","current","clearTimeout","reset","parseCustomMinutes","trim","mins","Number","isInteger","resolveExpiresIn","parseInt","handleGenerate","expiresIn","displayName","requestId","mutate","project_id","container","name","method","onSuccess","onError","handleCopy","navigator","clipboard","writeText","then","setTimeout","catch","handlePresetChange","value","defaultPreset","candidate","Array","isArray","validPresets","Set","map","p","nextPreset","has","handleCustomMinutesChange","e","target","isPending","isCustom","expiresAtFormatted","Date","toLocaleString","selectedPresetLabel","find","title","span","className","open","onCancel","confirmButtonLabel","onConfirm","cancelButtonLabel","size","disableConfirmButton","direction","gap","variant","role","aria-live","label","onChange","disabled","preset","invalid","errortext","undefined","placeholder","type","alignment","div","readOnly","button","onClick","aria-label","style","transform","icon","useState","useEffect","useRef","trpcReact","useProjectId","Modal","TextInput","Stack","Status","DataGrid","DataGridRow","DataGridHeadCell","DataGridCell","Button","useParams","formatBytesBinary","formatSwiftDate","VALID_KEY_RE","TIMESTAMP_RE","isValidTimestamp","value","test","d","Date","replace","isNaN","getTime","datePart","timePart","split","y","mo","day","map","Number","h","min","s","getUTCFullYear","getUTCMonth","getUTCDate","getUTCHours","getUTCMinutes","getUTCSeconds","validateMetaKey","key","trim","formatDate","iso","undefined","year","month","hour","minute","timeZone","formatUnixToTimestamp","unix","pad","n","String","padStart","EditObjectMetadataModal","isOpen","object","onClose","onSuccess","onError","useLingui","projectId","containerName","from","utils","useUtils","data","metadataRaw","isLoading","isError","isMetaError","error","metaError","storage","swift","getObjectMetadata","useQuery","project_id","container","name","enabled","refetchOnWindowFocus","uidRef","nextUid","current","expiresAt","setExpiresAt","expiresAtError","setExpiresAtError","metadata","setMetadata","metaErrors","setMetaErrors","isAddingNew","setIsAddingNew","newKey","setNewKey","newValue","setNewValue","newKeyError","setNewKeyError","originalExpiresAtRef","originalMetadataRef","displayNameRef","objectNameRef","expiresAtDebounceTimer","rawExpires","deleteAt","entries","Object","customMetadata","uid","isEditing","originalKey","originalValue","e","resetForm","clearTimeout","updateMutation","reset","hasChanges","length","originalMetadataByKey","Map","entry","some","get","hasEditing","updateObjectMetadata","useMutation","invalidate","listObjects","handleClose","message","handleSubmit","displayName","metadataRecord","mutate","Math","floor","handleEdit","index","prev","i","handleKeyChange","next","handleValueChange","handleSaveEdit","keyError","msg","t","isDuplicate","toLowerCase","handleCancelEdit","orig","filter","_","handleDeleteMeta","handleAddNew","handleCancelAdd","isPending","isBusy","isSLO","staticLargeObject","isDLO","objectManifest","metadataErrorMessage","mutationErrorMessage","title","span","className","open","onCancel","confirmButtonLabel","onConfirm","cancelButtonLabel","size","disableConfirmButton","status","body","direction","gap","p","strong","div","contentType","etag","contentLength","lastModified","last_modified","label","onChange","target","setTimeout","invalid","errortext","placeholder","disabled","alignment","distribution","onClick","variant","icon","columns","autoFocus","colSpan","getFolderCreatedToast","folderName","message","description","getFolderCreateErrorToast","errorMessage","getFolderDeletedToast","deletedCount","getFolderDeleteErrorToast","getContainerAccessErrorToast","containerName","getObjectDownloadStartedToast","getObjectDownloadCancelledToast","objectKey","displayName","split","filter","Boolean","pop","getObjectDownloadErrorToast","getObjectDeletedToast","objectName","getObjectDeleteErrorToast","getObjectCopiedToast","targetContainer","targetPath","destination","getObjectCopyErrorToast","getObjectMovedToast","getObjectMoveErrorToast","getTempUrlCopiedToast","getObjectMetadataUpdatedToast","getObjectMetadataUpdateErrorToast","getObjectUploadedToast","getObjectUploadCancelledToast","getObjectUploadErrorToast","getObjectsBulkDeletedToast","numberDeleted","getObjectsBulkDeleteErrorToast","span","className","toast","getBffEndpoint","getCsrfToken","DownloadWorker","getObjectDownloadStartedToast","transfers","Map","listeners","Set","snapshot","DOWNLOAD_TOAST_ID","downloadToastShown","syncDownloadToast","hasActiveTransfers","size","message","options","id","duration","Infinity","dismiss","emit","forEach","listener","CANCEL_TERMINATE_GRACE_MS","transferKey","container","objectKey","subscribeTransfers","add","delete","getTransfersSnapshot","triggerAnchorDownload","url","filename","anchor","document","createElement","href","download","body","appendChild","click","removeChild","setTimeout","URL","revokeObjectURL","openBlobInNewTab","target","rel","BROWSER_PREVIEWABLE_MIME_TYPES","isPreviewableContentType","contentType","base","split","trim","toLowerCase","has","startsWith","startObjectDownload","opts","kind","projectId","account","onError","key","downloadId","crypto","randomUUID","worker","err","Error","set","finish","get","terminate","onmessage","data","ok","createObjectURL","blob","cancelled","onerror","event","postMessage","type","bffEndpoint","location","origin","csrfToken","cancelObjectDownload","transfer","undefined","useEffect","useState","useSyncExternalStore","Checkbox","DataGrid","DataGridHeadCell","DataGridRow","DataGridCell","Icon","PopupMenu","PopupMenuItem","PopupMenuOptions","Spinner","toast","Tooltip","TooltipTrigger","TooltipContent","Status","MdFolder","MdDescription","formatBytesBinary","formatSwiftDate","trpcReact","useProjectId","useVirtualizedTableBody","DeleteFolderModal","DeleteObjectModal","CopyObjectModal","MoveRenameObjectModal","GenerateTempUrlModal","EditObjectMetadataModal","getObjectDownloadCancelledToast","startObjectDownload","cancelObjectDownload","subscribeTransfers","getTransfersSnapshot","transferKey","isPreviewableContentType","RowTransferProgress","downloadId","isPreviewing","data","progress","storage","swift","watchDownloadProgress","useSubscription","enabled","percent","span","className","size","div","style","width","GRID_COLUMN_TEMPLATE_WITH_SELECT","GRID_COLUMN_TEMPLATE_NO_SELECT","ObjectsTableView","rows","searchTerm","container","account","onFolderClick","onDeleteFolderSuccess","onDeleteFolderError","onDownloadError","onDeleteObjectSuccess","onDeleteObjectError","onCopyObjectSuccess","onCopyObjectError","onMoveObjectSuccess","onMoveObjectError","onTempUrlCopySuccess","onEditMetadataSuccess","onEditMetadataError","selectedObjects","setSelectedObjects","hasAnyBulkAction","useLingui","projectId","activeTransfers","scrollbarWidth","setScrollbarWidth","deleteFolderTarget","setDeleteFolderTarget","deleteObjectTarget","setDeleteObjectTarget","copyObjectTarget","setCopyObjectTarget","moveRenameObjectTarget","setMoveRenameObjectTarget","tempUrlTarget","setTempUrlTarget","editMetadataTarget","setEditMetadataTarget","handleDownload","row","kind","objectKey","name","filename","displayName","onError","handlePreviewOrDownload","handleCancelTransfer","objectName","transfer","message","options","warning","ref","tableBodyRef","elementRef","parentRef","height","bodyHeight","virtualItems","totalSize","measureElement","count","length","current","offsetWidth","clientWidth","handleSelectObject","includes","filter","n","gridColumnTemplate","columnCount","paddingRight","columns","data-testid","marginRight","colSpan","status","title","t","body","position","map","virtualRow","index","isFolder","activeTransfer","get","undefined","isDownloading","isStreaming","rowDisplayName","isSelected","data-index","top","left","transform","start","display","gridTemplateColumns","alignItems","onClick","e","stopPropagation","triggerEvent","placement","disabled","aria-label","checked","onChange","button","type","content_type","icon","last_modified","bytes","label","isOpen","folder","onClose","onSuccess","object","onCopySuccess","Breadcrumb","BreadcrumbItem","MdStorage","MdOutlineInventory2","MdInventory2","MdFolder","MdFolderOpen","prefixToSegments","prefix","parts","replace","split","filter","Boolean","map","label","i","slice","join","activeCrumbClass","ObjectsFileNavigation","containerName","currentPrefix","onContainersClick","onPrefixClick","useLingui","prefixSegments","isAtRoot","length","div","className","onClick","span","size","t","undefined","active","seg","isLast","useState","useRef","trpcReact","useProjectId","Modal","TextInput","Stack","Message","useParams","CreateFolderModal","isOpen","currentPrefix","onClose","onSuccess","existingRows","useLingui","projectId","containerName","from","folderName","setFolderName","nameError","setNameError","submitError","setSubmitError","utils","useUtils","submittedNameRef","createFolderMutation","storage","swift","createFolder","useMutation","listObjects","invalidate","current","handleClose","onError","error","data","code","t","message","reset","validateName","name","trimmed","trim","includes","newPath","some","row","kind","handleNameChange","e","value","target","handleSubmit","folderPath","mutate","project_id","container","handleKeyDown","key","isPending","parentPath","title","span","className","open","onCancel","confirmButtonLabel","onConfirm","cancelButtonLabel","size","disableConfirmButton","disableCancelButton","disableCloseButton","direction","gap","variant","dismissible","onDismiss","role","aria-live","data-testid","p","label","required","onChange","onKeyDown","invalid","errortext","undefined","disabled","autoFocus","placeholder","useState","useRef","Modal","Stack","Spinner","MdCloudUpload","trpcClient","trpcReact","cn","formatBytesBinary","UploadObjectModal","isOpen","currentPrefix","container","projectId","account","onClose","onSuccess","onError","onCancelled","useLingui","selectedFile","setSelectedFile","fileError","setFileError","isDragging","setIsDragging","uploadId","setUploadId","uploadError","setUploadError","isPending","setIsPending","submittedNameRef","fileInputRef","abortControllerRef","utils","useUtils","handleCancelUpload","current","abort","data","uploadProgress","storage","swift","watchUploadProgress","useSubscription","enabled","handleClose","resetAndClose","value","handleFileChange","e","file","target","files","handleDragOver","preventDefault","stopPropagation","handleDragLeave","handleDrop","dataTransfer","handleSubmit","t","objectName","name","activeUploadId","crypto","randomUUID","controller","AbortController","uploadContext","headers","type","String","size","uploadObject","mutate","context","signal","listObjects","invalidate","err","isAborted","Error","message","includes","progressPct","percent","parentPath","selectedObjectName","title","span","className","open","onCancel","confirmButtonLabel","onConfirm","cancelButtonLabel","disableConfirmButton","disableCloseButton","direction","gap","p","div","label","htmlFor","onDragOver","onDragLeave","onDrop","input","ref","id","onChange","disabled","svg","fill","viewBox","path","fillRule","d","clipRule","button","onClick","style","width","z","useForm","useStore","useEffect","trpcReact","Modal","Status","Stack","Form","FormSection","TextInput","useProjectId","useModalTracking","MAX_VISIBLE","CONFIRM_WORD","DeleteObjectsModal","isOpen","objectNames","objectKeys","container","account","onClose","onSuccess","onError","i18n","useLingui","projectId","utils","useUtils","trackClose","markSubmitted","resetTracking","actionPrefix","formSchema","object","confirm","string","transform","val","trim","refine","value","message","t","form","defaultValues","validators","onSubmit","bulkDeleteMutation","isPending","objects","map","key","encodeURIComponent","mutate","project_id","canDelete","store","state","isSubmitting","values","storage","swift","bulkDelete","useMutation","result","listObjects","invalidate","errors","length","errorMessages","e","path","error","join","failedPaths","Set","deletedKeys","filter","has","numberDeleted","partialResultMessage","onSettled","handleClose","reset","totalCount","visibleNames","slice","hiddenCount","title","open","onCancel","confirmButtonLabel","_","plural","confirmButtonVariant","cancelButtonLabel","onConfirm","handleSubmit","disableConfirmButton","disableCancelButton","disableCloseButton","size","status","className","direction","gap","p","div","h3","ul","name","li","id","preventDefault","Field","children","field","label","placeholder","onChange","handleChange","target","invalid","meta","errortext","undefined","disabled","autoFocus","required","useState","useEffect","useRef","startTransition","Button","Checkbox","DataGridToolbar","PopupMenu","PopupMenuItem","PopupMenuOptions","PopupMenuToggle","SearchInput","Status","Stack","toast","trpcReact","useProjectId","parseSwiftDate","SortInput","useNavigate","Route","ObjectsTableView","ObjectsFileNavigation","CreateFolderModal","UploadObjectModal","DeleteObjectsModal","getContainerAccessErrorToast","getFolderCreatedToast","getFolderDeletedToast","getFolderDeleteErrorToast","getObjectDownloadErrorToast","getObjectDeletedToast","getObjectDeleteErrorToast","getObjectCopiedToast","getObjectCopyErrorToast","getObjectMovedToast","getObjectMoveErrorToast","getTempUrlCopiedToast","getObjectMetadataUpdatedToast","getObjectMetadataUpdateErrorToast","getObjectUploadedToast","getObjectUploadCancelledToast","getObjectUploadErrorToast","getObjectsBulkDeletedToast","getObjectsBulkDeleteErrorToast","encodePrefix","prefix","bytes","TextEncoder","encode","binString","Array","from","byte","String","fromCodePoint","join","btoa","decodePrefix","encoded","atob","Uint8Array","char","codePointAt","TextDecoder","decode","buildRows","objects","folders","files","seenFolders","Set","obj","stripped","name","startsWith","slice","length","slashIdx","indexOf","folderPrefix","has","add","push","kind","displayName","content_type","endsWith","replace","last_modified","ALLOWED_SORT_KEYS","resolveSortBy","sortBy","includes","undefined","isArray","first","SwiftObjects","provider","containerName","i18n","useLingui","projectId","navigate","fullPath","encodedPrefix","sortDirection","search","searchParam","useSearch","storageType","useParams","currentPrefix","hasAnyBulkAction","createFolderModalOpen","setCreateFolderModalOpen","uploadModalOpen","setUploadModalOpen","deleteAllModalOpen","setDeleteAllModalOpen","selectedObjects","setSelectedObjects","localSearchTerm","setLocalSearchTerm","debounceTimer","clearTimeout","current","handleCreateFolderSuccess","folderName","message","options","success","handleUploadSuccess","objectName","handleUploadCancelled","warning","handleUploadError","errorMessage","error","handleDeleteFolderSuccess","deletedCount","nestedCount","Math","max","handleDeleteFolderError","handleDownloadError","handleDeleteObjectSuccess","prev","filter","handleDeleteObjectError","handleCopyObjectSuccess","targetContainer","targetPath","handleCopyObjectError","handleMoveObjectSuccess","handleMoveObjectError","handleTempUrlCopySuccess","handleEditMetadataSuccess","handleEditMetadataError","handleBulkDeleteSuccess","numberDeleted","handleBulkDeleteError","deletedKeys","key","sortSettings","label","t","value","data","isLoading","storage","swift","listObjects","useQuery","project_id","container","format","navigateToContainers","to","params","redirectedRef","navigateToPrefix","newPrefix","allRows","filteredRows","row","toLowerCase","trim","totalItemCount","filteredItemCount","sortedRows","sort","a","b","comparison","localeCompare","aDate","bDate","at","getTime","bt","aBytes","bBytes","handleSearchChange","term","handleSortChange","newSort","resolvedSortBy","resolvedDirection","status","title","hasSelection","selectedCount","selectedDisplayNames","map","find","r","selectableNames","allSelectableSelected","every","n","someSelectableSelected","some","handleToggleSelectAll","div","className","direction","distribution","alignment","gap","selectClassName","onSortByChange","v","onSortDirectionChange","dir","as","icon","onClick","data-testid","variant","placeholder","onInput","e","currentTarget","window","setTimeout","onSearch","onClear","onContainersClick","onPrefixClick","checked","indeterminate","onChange","disabled","size","_","plural","span","rows","searchTerm","onFolderClick","onDeleteFolderSuccess","onDeleteFolderError","onDownloadError","onDeleteObjectSuccess","onDeleteObjectError","onCopyObjectSuccess","onCopyObjectError","onMoveObjectSuccess","onMoveObjectError","onTempUrlCopySuccess","onEditMetadataSuccess","onEditMetadataError","isOpen","objectNames","objectKeys","onClose","onSuccess","onError","existingRows","onCancelled","trpcReact","PERMISSION_MAP","canCreateBucket","canDeleteBucket","canEmptyBucket","canUpdateVersioning","canCreateObject","canUpdateObject","canDeleteObject","canCopyObject","canMoveObject","canShareObject","canCreateFolder","canDeleteFolder","canDeleteVersion","canRestoreVersion","canUpdatePolicy","canDeletePolicy","canUpdateCors","canDeleteCors","canUpdateLifecycle","canDeleteLifecycle","canCreateCredential","PERMISSION_KEYS","Object","keys","PERMISSION_REQUEST","map","key","DEFAULT_PERMISSIONS","fromEntries","useCephPermissions","projectId","data","permissions","isLoading","isError","storage","canUser","useQuery","project_id","permission","enabled","Boolean","select","results","index","staleTime","Infinity","gcTime","getFolderCreatedToast","folderPath","message","description","getFolderCreateErrorToast","errorMessage","getObjectDeletedToast","objectKey","displayName","split","filter","Boolean","pop","getObjectDeleteErrorToast","createBulkDeleteToasts","entityType","isVersion","success","deletedCount","partial","errorCount","error","objectBulkDelete","getObjectsBulkDeletedToast","getObjectsBulkDeletePartialToast","getObjectsBulkDeleteErrorToast","getObjectCopiedToast","targetBucket","targetKey","wasOverwritten","destination","getObjectCopyErrorToast","getObjectMovedToast","getObjectMoveErrorToast","getPresignedUrlCopiedToast","getObjectMetadataUpdatedToast","getObjectMetadataUpdateErrorToast","getObjectUploadedToast","objectName","getObjectUploadCancelledToast","getObjectUploadErrorToast","getObjectDownloadStartedToast","getObjectDownloadCancelledToast","getObjectDownloadErrorToast","getVersionRestoredToast","getVersionRestoreErrorToast","getVersionDeletedToast","getVersionDeleteErrorToast","versionBulkDelete","getVersionsBulkDeletedToast","getVersionsBulkDeletePartialToast","getVersionsBulkDeleteErrorToast","toast","getBffEndpoint","getCsrfToken","DownloadWorker","getObjectDownloadStartedToast","transfers","Map","listeners","Set","snapshot","DOWNLOAD_TOAST_ID","downloadToastShown","syncDownloadToast","hasActiveTransfers","size","message","options","id","duration","Infinity","dismiss","emit","forEach","listener","CANCEL_TERMINATE_GRACE_MS","transferKey","bucketName","objectKey","subscribeTransfers","add","delete","getTransfersSnapshot","triggerAnchorDownload","url","filename","anchor","document","createElement","href","download","body","appendChild","click","removeChild","setTimeout","URL","revokeObjectURL","openBlobInNewTab","target","rel","BROWSER_PREVIEWABLE_MIME_TYPES","isPreviewableContentType","contentType","base","split","trim","toLowerCase","has","startsWith","startObjectDownload","opts","kind","projectId","onError","key","downloadId","crypto","randomUUID","worker","err","Error","set","finish","get","terminate","onmessage","data","ok","createObjectURL","blob","cancelled","onerror","event","postMessage","type","bffEndpoint","location","origin","csrfToken","cancelObjectDownload","transfer","undefined","z","useForm","useStore","Modal","Form","FormSection","TextInput","Stack","DescriptionList","DescriptionTerm","DescriptionDefinition","trpcReact","useProjectId","useModalTracking","formatBytesBinary","DeleteObjectModal","bucketName","objectKey","objectSize","lastModified","isOpen","versioningEnabled","onClose","onSuccess","onError","useLingui","projectId","utils","useUtils","trackClose","markSubmitted","resetTracking","actionPrefix","formSchema","object","confirm","string","refine","value","message","t","form","defaultValues","validators","onSubmit","deleteMutation","isPending","mutate","project_id","containerName","canDelete","store","state","isSubmitting","values","storage","ceph","objects","delete","useMutation","list","invalidate","containers","versioning","checkDeletedContent","handleClose","error","reset","isFolder","endsWith","displayName","split","filter","Boolean","pop","open","onCancel","title","size","confirmButtonLabel","confirmButtonVariant","onConfirm","handleSubmit","cancelButtonLabel","disableConfirmButton","disableCancelButton","disableCloseButton","direction","gap","p","className","undefined","Date","toLocaleString","id","e","preventDefault","Field","name","children","field","label","onChange","handleChange","target","placeholder","autoFocus","disabled","required","formatBulkDeleteErrors","errors","map","error","label","versionId","key","detail","code","message","filter","Boolean","join","useState","trpcReact","Modal","Stack","TextInput","useProjectId","useModalTracking","formatBytesBinary","formatBulkDeleteErrors","DeleteVersionModal","isOpen","bucketName","objectKey","versionId","versionDate","versionSize","isDeleteMarker","folderMarkerVersionId","allVersionIds","onClose","onSuccess","onError","useLingui","projectId","confirmText","setConfirmText","failureMessage","setFailureMessage","isFolder","endsWith","trackClose","markSubmitted","resetTracking","actionPrefix","utils","useUtils","deleteMutation","storage","ceph","objects","deleteVersionsBulk","useMutation","result","versioning","listObjectVersions","invalidate","checkDeletedContent","list","containers","errorCount","errors","handleClose","error","message","reset","isDeletingAllVersions","length","handleDelete","versions","key","map","vid","mutate","project_id","containerName","title","t","open","onCancel","confirmButtonLabel","onConfirm","cancelButtonLabel","disableConfirmButton","isPending","confirmButtonVariant","direction","gap","p","className","div","label","idx","code","Date","toLocaleString","undefined","value","onChange","e","target","placeholder","autoFocus","disabled","useState","trpcReact","Modal","Stack","useProjectId","useModalTracking","formatBytesBinary","formatBulkDeleteErrors","RestoreVersionModal","isOpen","bucketName","objectKey","versionId","versionDate","versionSize","onClose","onSuccess","onError","useLingui","projectId","failureMessage","setFailureMessage","trackClose","markSubmitted","resetTracking","actionPrefix","utils","useUtils","isFolder","endsWith","invalidateAfterRestore","storage","ceph","versioning","listObjectVersions","invalidate","checkDeletedContent","objects","list","containers","handleRestoreSuccess","handleClose","handleDeleteMarkerSuccess","result","errorCount","errors","restoreMutation","restoreVersion","useMutation","error","message","onSettled","reset","deleteVersionMutation","deleteVersionsBulk","handleRestore","mutate","project_id","containerName","versions","key","bucket","title","t","open","onCancel","confirmButtonLabel","onConfirm","cancelButtonLabel","disableConfirmButton","isPending","direction","gap","div","label","className","span","p","code","Date","toLocaleString","undefined","validateFolderName","name","existingNames","currentPrefix","trimmed","trim","type","message","msg","includes","length","newPath","validateObjectName","validateMetadataKey","key","VALID_KEY_RE","test","useState","useCallback","validateFolderName","useObjectBrowser","existingRows","onFolderCreated","useLingui","currentPrefix","setCurrentPrefix","newFolderName","setNewFolderName","newFolderError","setNewFolderError","showNewFolderInput","setShowNewFolderInput","navigateToPrefix","prefix","navigateUp","parts","replace","split","pop","newPrefix","length","join","startCreateFolder","cancelCreateFolder","handleSetNewFolderName","name","createFolder","existingNames","map","r","error","t","message","trimmed","trim","newPath","reset","useState","useRef","useEffect","useCallback","MAX_COMBO_OPTIONS","useBucketSearch","allBuckets","searchTerm","setSearchTerm","debouncedSearch","setDebouncedSearch","debounceTimer","current","clearTimeout","handleSearchChange","e","value","target","setTimeout","reset","filteredBuckets","trim","length","filter","b","name","toLowerCase","includes","visibleBuckets","slice","hiddenCount","useState","useCallback","useLocalFolders","localFolders","setLocalFolders","addFolder","bucket","path","prev","clearForBucket","next","reset","useState","useCallback","useObjectBrowser","useBucketSearch","useLocalFolders","useCopyMoveModalState","initialBucket","allBuckets","existingRows","localFoldersState","browserState","path","addFolder","targetBucket","bucketSearchState","setTargetBucket","handleBucketChange","bucket","reset","clearForBucket","resetAll","useState","useRef","useEffect","useCallback","trpcReact","useProjectId","useModalTracking","Modal","Stack","Spinner","Status","ComboBox","ComboBoxOption","TextInput","Button","MdFolder","MdDescription","MdCreateNewFolder","MdArrowBack","useVirtualizer","useCopyMoveModalState","MAX_COMBO_OPTIONS","CopyObjectModal","isOpen","bucketName","objectKey","objectSize","onClose","onSuccess","onError","useLingui","projectId","utils","useUtils","submittedKeyRef","trackClose","markSubmitted","resetTracking","actionPrefix","copyMetadata","setCopyMetadata","targetExists","setTargetExists","checkingTarget","setCheckingTarget","listRef","data","buckets","isLoading","isLoadingBuckets","storage","ceph","containers","list","useQuery","project_id","includeMetadata","enabled","modalState","initialBucket","allBuckets","existingRows","objectsData","isLoadingObjects","objects","containerName","targetBucket","prefix","currentPrefix","undefined","delimiter","maxKeys","resetAll","buildRows","folders","map","folder","kind","name","displayName","replace","filter","obj","stripped","key","serverRows","bucketLocalFolders","localFolders","localFolderRows","fp","withoutPrefix","startsWith","slice","length","parts","split","Boolean","some","r","rows","copyMutation","copy","useMutation","invalidate","targetKey","current","handleClose","error","message","pop","checkTargetExists","getDetails","fetch","reset","handleBucketChange","value","v","Array","isArray","String","setTargetBucket","trimmedSearch","searchTerm","trim","matchingBucket","find","b","handleNewFolderKeyDown","e","createFolder","cancelCreateFolder","handleCopy","mutate","sourceBucket","sourceKey","destinationBucket","destinationKey","folderRows","objectRows","allBrowserRows","rowVirtualizer","count","getScrollElement","estimateSize","overscan","isPending","targetPathDisplay","initialPrefix","endsWith","isUnchanged","title","span","className","open","onCancel","confirmButtonLabel","t","onConfirm","cancelButtonLabel","size","disableConfirmButton","disableCancelButton","disableCloseButton","status","direction","gap","label","onChange","onInputChange","handleSearchChange","placeholder","helptext","bucketsCount","hiddenCount","totalBuckets","visibleBuckets","disabled","required","div","variant","icon","onClick","startCreateFolder","button","type","navigateUp","ref","alignment","showNewFolderInput","style","height","getTotalSize","position","getVirtualItems","virtualRow","row","index","isFolder","data-index","measureElement","top","left","width","transform","start","navigateToPrefix","newFolderName","setNewFolderName","target","onKeyDown","invalid","newFolderError","errortext","autoFocus","toFixed","p","input","checked","isError","errorMessage","useState","useRef","useEffect","trpcReact","useProjectId","useModalTracking","Modal","Stack","Spinner","Status","ComboBox","ComboBoxOption","TextInput","Button","Divider","MdFolder","MdDescription","MdCreateNewFolder","MdArrowBack","useVirtualizer","useCopyMoveModalState","validateObjectName","MAX_COMBO_OPTIONS","MoveObjectModal","isOpen","bucketName","objectKey","objectSize","onClose","onSuccess","onError","useLingui","projectId","utils","useUtils","submittedKeyRef","submittedTargetKeyRef","submittedTargetBucketRef","trackClose","markSubmitted","resetTracking","actionPrefix","newObjectName","setNewObjectName","newObjectNameError","setNewObjectNameError","listRef","data","buckets","isLoading","isLoadingBuckets","storage","ceph","containers","list","useQuery","project_id","includeMetadata","enabled","modalState","initialBucket","allBuckets","existingRows","objectsData","isLoadingObjects","objects","containerName","targetBucket","prefix","currentPrefix","undefined","delimiter","maxKeys","displayName","split","filter","Boolean","pop","resetAll","buildRows","folders","map","folder","kind","name","replace","obj","stripped","key","serverRows","bucketLocalFolders","localFolders","localFolderRows","fp","withoutPrefix","startsWith","slice","length","parts","some","r","rows","deleteMutation","delete","useMutation","invalidate","current","error","message","onSettled","handleClose","copyMutation","copy","mutate","reset","handleBucketChange","value","v","Array","isArray","String","setTargetBucket","trimmedSearch","searchTerm","trim","matchingBucket","find","b","handleNewFolderKeyDown","e","createFolder","cancelCreateFolder","handleMove","t","trimmedName","targetKey","sourceBucket","sourceKey","destinationBucket","destinationKey","copyMetadata","folderRows","objectRows","allBrowserRows","rowVirtualizer","count","getScrollElement","estimateSize","overscan","isPending","targetPathDisplay","initialPrefix","endsWith","isUnchanged","title","span","className","open","onCancel","confirmButtonLabel","onConfirm","cancelButtonLabel","size","disableConfirmButton","disableCancelButton","disableCloseButton","status","direction","gap","label","onChange","target","invalid","errortext","helptext","required","isError","copyErrorMessage","deleteErrorMessage","p","onInputChange","handleSearchChange","placeholder","bucketsCount","hiddenCount","totalBuckets","visibleBuckets","disabled","div","variant","icon","onClick","startCreateFolder","button","type","navigateUp","ref","alignment","showNewFolderInput","style","height","getTotalSize","position","getVirtualItems","virtualRow","row","index","isFolder","data-index","measureElement","top","left","width","transform","start","navigateToPrefix","newFolderName","setNewFolderName","onKeyDown","newFolderError","autoFocus","toFixed","S3_MAX_KEYS_PER_REQUEST","S3_PRESIGN_MAX_EXPIRY_SECONDS","useEffect","useRef","useState","i18n","trpcReact","useProjectId","S3_PRESIGN_MAX_EXPIRY_SECONDS","Modal","Stack","Spinner","TextInput","Icon","Select","SelectOption","CUSTOM_VALUE","MAX_EXPIRY_SECONDS","MAX_EXPIRY_MINUTES","GeneratePresignedUrlModal","isOpen","bucketName","objectKey","onClose","onCopySuccess","useLingui","projectId","EXPIRY_PRESETS","labelKey","t","seconds","selectedPreset","setSelectedPreset","String","customMinutes","setCustomMinutes","customMinutesError","setCustomMinutesError","copied","setCopied","presignedUrl","setPresignedUrl","expiresAt","setExpiresAt","generalError","setGeneralError","copyError","setCopyError","objectKeyRef","copyTimeoutRef","requestIdRef","handleGenerateSuccess","data","url","handleGenerateError","error","message","generateMutation","storage","ceph","objects","generatePresignedUrl","useMutation","current","clearTimeout","reset","displayName","split","filter","Boolean","pop","parseCustomMinutes","trim","mins","Number","isInteger","resolveExpiresIn","parseInt","handleGenerate","expiresIn","requestId","mutate","project_id","containerName","onSuccess","onError","handleCopy","navigator","clipboard","writeText","then","setTimeout","catch","handlePresetChange","value","defaultPreset","candidate","Array","isArray","validPresets","Set","map","p","nextPreset","has","handleCustomMinutesChange","e","target","isPending","isCustom","expiresAtFormatted","Date","toLocaleString","locale","selectedPresetLabel","find","title","span","className","open","onCancel","confirmButtonLabel","onConfirm","cancelButtonLabel","size","disableConfirmButton","direction","gap","role","aria-live","label","onChange","disabled","preset","invalid","errortext","undefined","placeholder","type","alignment","div","readOnly","button","onClick","aria-label","style","transform","icon","useState","useEffect","useRef","trpcReact","useProjectId","useModalTracking","Modal","TextInput","Stack","Status","DataGrid","DataGridRow","DataGridHeadCell","DataGridCell","Button","formatBytesBinary","validateMetadataKey","formatDate","iso","date","Date","isNaN","getTime","toLocaleString","undefined","year","month","day","hour","minute","calculateMetadataSize","entries","totalBytes","entry","length","key","value","MAX_METADATA_BYTES","EditMetadataModal","isOpen","bucketName","objectKey","onClose","onSuccess","onError","useLingui","projectId","utils","useUtils","trackClose","markSubmitted","resetTracking","actionPrefix","data","objectDetails","isLoading","isError","isMetaError","error","metaError","storage","ceph","objects","getDetails","useQuery","project_id","containerName","enabled","refetchOnWindowFocus","uidRef","nextUid","current","metadata","setMetadata","metaErrors","setMetaErrors","isAddingNew","setIsAddingNew","newKey","setNewKey","newValue","setNewValue","newKeyError","setNewKeyError","originalMetadataRef","objectKeyRef","Object","map","uid","isEditing","originalKey","originalValue","e","resetForm","updateMutation","reset","hasChanges","originalMetadataByKey","Map","some","get","hasEditing","currentMetadataSize","isSizeExceeded","updateMetadata","useMutation","invalidate","list","handleClose","message","handleSubmit","metadataRecord","mutate","handleEdit","index","prev","i","handleKeyChange","next","handleValueChange","handleSaveEdit","t","isDuplicate","toLowerCase","handleCancelEdit","currentEntry","orig","find","filter","_","handleDeleteMeta","handleAddNew","trim","handleCancelAdd","displayName","split","Boolean","pop","isPending","isBusy","metadataErrorMessage","mutationErrorMessage","title","span","className","open","onCancel","confirmButtonLabel","onConfirm","cancelButtonLabel","size","disableConfirmButton","status","body","direction","gap","p","role","div","contentType","etag","lastModified","alignment","distribution","label","onClick","variant","icon","disabled","columns","gridColumnTemplate","onChange","target","placeholder","errortext","invalid","autoFocus","colSpan","useEffect","useState","trpcReact","useModalTracking","Modal","Stack","Status","Message","DataGrid","DataGridRow","DataGridCell","DataGridHeadCell","Badge","PopupMenu","PopupMenuItem","PopupMenuOptions","useProjectId","formatBytesBinary","RestoreVersionModal","DeleteVersionModal","ObjectVersionHistoryModal","isOpen","bucketName","objectKey","onClose","onRestoreVersion","onDeleteVersion","canRestoreVersion","canDeleteVersion","useLingui","projectId","trackClose","resetTracking","actionPrefix","restoreTarget","setRestoreTarget","deleteTarget","setDeleteTarget","feedbackMessage","setFeedbackMessage","data","isLoading","error","refetch","storage","ceph","versioning","listObjectVersions","useQuery","project_id","bucket","key","enabled","staleTime","versions","handleClose","title","span","className","open","onCancel","size","direction","gap","variant","dismissible","onDismiss","message","status","t","body","length","columns","minContentColumns","map","version","isLatest","isDeleteMarker","code","versionId","lastModified","Date","toLocaleString","etag","div","label","onClick","date","versionDate","versionSize","onSuccess","displayName","split","filter","Boolean","pop","setTimeout","onError","_objectKey","errorMessage","shortVersionId","slice","useEffect","useState","useSyncExternalStore","useMemo","DataGrid","DataGridRow","DataGridCell","DataGridHeadCell","PopupMenu","PopupMenuItem","PopupMenuOptions","Badge","Spinner","Icon","toast","Checkbox","Tooltip","TooltipTrigger","TooltipContent","Status","MdFolder","MdDescription","formatBytesBinary","trpcReact","useProjectId","useVirtualizedTableBody","getObjectDownloadCancelledToast","getPresignedUrlCopiedToast","startObjectDownload","cancelObjectDownload","subscribeTransfers","getTransfersSnapshot","transferKey","DeleteObjectModal","DeleteVersionModal","RestoreVersionModal","CopyObjectModal","MoveObjectModal","GeneratePresignedUrlModal","EditMetadataModal","ObjectVersionHistoryModal","RowTransferProgress","projectId","downloadId","isPreviewing","data","progress","storage","ceph","objects","watchDownloadProgress","useSubscription","project_id","enabled","percent","span","className","size","div","style","width","GRID_COLUMN_TEMPLATE_WITH_SELECT","GRID_COLUMN_TEMPLATE_NO_SELECT","ObjectsTableView","bucketName","folders","versions","currentPrefix","versioningEnabled","showingVersions","selectable","selectedItems","onToggleSelectKey","onFolderClick","onDeleteObjectSuccess","onDeleteObjectError","onCopyObjectSuccess","onCopyObjectError","onMoveObjectSuccess","onMoveObjectError","onEditMetadataSuccess","onEditMetadataError","onDownloadError","onRestoreVersion","onDeleteVersion","canCopyObject","canMoveObject","canUpdateObject","canShareObject","canDeleteObject","canDeleteFolder","canDeleteVersion","canRestoreVersion","isLoading","useLingui","activeTransfers","scrollbarWidth","setScrollbarWidth","deleteTarget","setDeleteTarget","restoreTarget","setRestoreTarget","deleteVersionTarget","setDeleteVersionTarget","copyTarget","setCopyTarget","moveTarget","setMoveTarget","editMetadataTarget","setEditMetadataTarget","versionHistoryTarget","setVersionHistoryTarget","presignedUrlTarget","setPresignedUrlTarget","handleDownload","row","kind","objectKey","key","filename","displayName","onError","handlePreviewOrDownload","handleCancelTransfer","rowKey","transfer","message","options","warning","stripPrefix","fullKey","replace","rows","map","f","prefix","isDeleted","deleteMarkerVersionId","folderMarkerVersionId","v","versionId","isLatest","isDeleteMarker","allVersionIds","lastModified","o","selectedItemsSet","Set","item","showSelection","gridColumnTemplate","columnCount","ref","tableBodyRef","elementRef","parentRef","height","bodyHeight","virtualItems","totalSize","measureElement","count","length","current","offsetWidth","clientWidth","paddingRight","columns","data-testid","marginRight","colSpan","status","title","t","body","position","virtualRow","index","isFolder","isVersion","isDeletedFile","activeTransfer","get","undefined","isDownloading","isStreaming","data-index","top","left","transform","start","display","gridTemplateColumns","alignItems","onClick","e","stopPropagation","isSelected","has","checked","disabled","onChange","aria-label","triggerEvent","placement","button","type","variant","icon","Date","toLocaleString","shouldShowFolderMenu","hasAnyRowAction","label","versionIdToDelete","objectSize","isOpen","onClose","onSuccess","versionSize","versionDate","onCopySuccess","success","Breadcrumb","BreadcrumbItem","MdStorage","MdInventory2","MdOutlineInventory2","MdFolder","MdFolderOpen","prefixToSegments","prefix","parts","replace","split","filter","Boolean","map","label","i","slice","join","activeCrumbClass","ObjectsFileNavigation","bucketName","onBucketsClick","onPrefixClick","useLingui","prefixSegments","isAtRoot","length","div","onClick","span","className","size","t","undefined","active","seg","isLast","useState","Modal","TextInput","Stack","Message","trpcReact","useProjectId","useModalTracking","validateFolderName","CreateFolderModal","bucketName","currentPrefix","isOpen","onClose","onSuccess","useLingui","projectId","folderName","setFolderName","validationError","setValidationError","submitError","setSubmitError","utils","useUtils","trackClose","markSubmitted","resetTracking","actionPrefix","data","objectsData","storage","ceph","objects","list","useQuery","project_id","containerName","prefix","undefined","delimiter","maxKeys","enabled","createFolderMutation","createFolder","useMutation","_data","variables","invalidate","containers","submittedFullPath","folderPath","endsWith","handleClose","onError","error","code","t","message","reset","handleFolderNameChange","value","existingFolders","folders","map","f","handleCreate","fullPath","trim","mutate","open","onCancel","title","size","confirmButtonLabel","isPending","onConfirm","confirmButtonVariant","cancelButtonLabel","disableConfirmButton","disableCancelButton","disableCloseButton","direction","gap","variant","dismissible","onDismiss","role","aria-live","data-testid","p","div","className","span","label","onChange","e","target","placeholder","autoFocus","invalid","errortext","disabled","onKeyDown","key","useState","useRef","Modal","Stack","Spinner","MdCloudUpload","trpcClient","trpcReact","cn","formatBytesBinary","UploadObjectModal","isOpen","currentPrefix","bucketName","projectId","onClose","onSuccess","onError","onCancelled","useLingui","selectedFile","setSelectedFile","fileError","setFileError","isDragging","setIsDragging","uploadId","setUploadId","uploadError","setUploadError","isPending","setIsPending","submittedNameRef","fileInputRef","abortControllerRef","utils","useUtils","handleCancelUpload","current","abort","data","uploadProgress","storage","ceph","objects","watchUploadProgress","useSubscription","project_id","enabled","handleClose","resetAndClose","value","handleFileChange","e","file","target","files","handleDragOver","preventDefault","stopPropagation","handleDragLeave","handleDrop","dataTransfer","handleSubmit","t","objectKey","name","activeUploadId","crypto","randomUUID","controller","AbortController","uploadContext","headers","type","String","size","uploadObject","mutate","context","signal","list","invalidate","err","isAborted","Error","message","includes","progressPct","percent","parentPath","selectedObjectName","title","span","className","open","onCancel","confirmButtonLabel","onConfirm","cancelButtonLabel","disableConfirmButton","disableCloseButton","direction","gap","p","div","label","htmlFor","onDragOver","onDragLeave","onDrop","input","ref","id","onChange","disabled","svg","fill","viewBox","path","fillRule","d","clipRule","button","onClick","style","width","useState","Modal","TextInput","Stack","trpcReact","useProjectId","useModalTracking","MAX_VISIBLE","MAX_ERROR_VISIBLE","DeleteObjectsModal","bucketName","objectKeys","versions","currentPrefix","versioningEnabled","isVersionMode","isOpen","onClose","onDeleted","onError","useLingui","projectId","confirmText","setConfirmText","result","setResult","utils","useUtils","trackClose","markSubmitted","resetTracking","actionPrefix","deleteBulkMutation","storage","ceph","objects","deleteBulk","useMutation","onSuccess","res","list","invalidate","containers","versioning","checkDeletedContent","deleted","map","d","key","errorCount","handleClose","error","message","deleteVersionsBulkMutation","deleteVersionsBulk","reset","handleConfirm","mutate","project_id","containerName","length","count","isConfirmValid","isPending","visibleErrors","errors","slice","hiddenErrorCount","open","onCancel","title","size","confirmButtonLabel","t","onConfirm","direction","gap","deletedCount","p","className","div","e","idx","displayName","replace","errorDetail","code","uniqueObjectKeys","Array","from","Set","v","displayObjectNames","visibleObjectNames","hiddenObjectCount","itemsToDisplay","visibleNames","hiddenCount","hiddenVersionsCount","confirmLabel","confirmButtonVariant","cancelButtonLabel","disableConfirmButton","disableCancelButton","disableCloseButton","label","name","versionId","value","onChange","target","placeholder","autoFocus","useState","trpcReact","Modal","Stack","Checkbox","useProjectId","useModalTracking","EnableVersioningModal","isOpen","bucketName","onClose","onSuccess","onError","useLingui","projectId","confirmed","setConfirmed","trackClose","markSubmitted","resetTracking","actionPrefix","utils","useUtils","enableMutation","storage","ceph","versioning","setStatus","useMutation","getStatus","invalidate","error","message","onSettled","handleClose","reset","handleEnable","mutate","project_id","bucket","status","title","t","open","onCancel","confirmButtonLabel","onConfirm","cancelButtonLabel","disableConfirmButton","isPending","direction","gap","p","checked","onChange","e","target","label","disabled","trpcReact","Modal","Stack","useProjectId","useModalTracking","SuspendVersioningModal","isOpen","bucketName","onClose","onSuccess","onError","useLingui","projectId","trackClose","markSubmitted","resetTracking","actionPrefix","utils","useUtils","suspendMutation","storage","ceph","versioning","setStatus","useMutation","getStatus","invalidate","error","message","onSettled","reset","handleClose","handleSuspend","mutate","project_id","bucket","status","title","t","open","onCancel","confirmButtonLabel","onConfirm","cancelButtonLabel","disableConfirmButton","isPending","direction","gap","div","p","className","ul","li","useRef","useCallback","useMemo","cn","JsonEditor","value","onChange","onBlur","disabled","placeholder","error","className","id","name","indentSize","showLineNumbers","testId","textareaRef","indent","repeat","handleChange","e","target","handleKeyDown","textarea","current","start","selectionStart","end","selectionEnd","key","preventDefault","shiftKey","lines","substring","split","currentLineStart","length","currentLine","startsWith","newValue","setTimeout","currentIndent","match","newIndent","trimmedLine","trim","endsWith","dedentedIndent","beforeLine","afterLine","lineNumbers","count","Math","max","Array","from","_","i","div","data-testid","style","minWidth","aria-hidden","undefined","map","num","ref","overflowX","overflowY","tabSize","onKeyDown","spellCheck","autoComplete","autoCorrect","autoCapitalize","aria-invalid","aria-describedby","span","useEffect","useMemo","z","useForm","useStore","trpcReact","Modal","Stack","Select","SelectOption","Status","Message","Form","JsonEditor","useProjectId","useModalTracking","POLICY_TEMPLATES","label","value","generator","bucketName","Version","Statement","Sid","Effect","Principal","Action","Resource","Condition","IpAddress","MAX_POLICY_SIZE","BucketPolicyModal","isOpen","onClose","onSuccess","onError","useLingui","projectId","utils","useUtils","trackClose","markSubmitted","resetTracking","actionPrefix","formSchema","object","policyText","string","max","t","refine","trim","JSON","parse","message","selectedTemplate","data","policyData","isLoading","isPolicyLoading","error","policyError","storage","ceph","bucketPolicy","get","useQuery","project_id","enabled","retry","setMutation","set","useMutation","invalidate","handleClose","deleteMutation","delete","form","defaultValues","validators","onSubmit","mutate","policy","findMatchingTemplate","template","templatePolicy","stringify","parsed","formatted","setFieldValue","matchingTemplate","reset","handleTemplateChange","templateValue","find","isSubmitting","store","state","policyTextValue","values","selectedTemplateValue","policySize","Blob","size","originalPolicyText","hasChanges","jsonSyntaxError","SyntaxError","isSaving","isPending","canSubmit","handleSave","handleSubmit","title","open","onCancel","confirmButtonLabel","onConfirm","cancelButtonLabel","disableConfirmButton","direction","gap","status","className","body","variant","e","preventDefault","div","p","onChange","disabled","map","Field","name","children","field","htmlFor","id","handleChange","onBlur","handleBlur","placeholder","span","useEffect","trpcReact","Modal","Stack","Status","Message","useProjectId","useModalTracking","DeleteBucketPolicyModal","isOpen","bucketName","onClose","onSuccess","onError","useLingui","projectId","utils","useUtils","trackClose","markSubmitted","resetTracking","actionPrefix","data","policyData","isLoading","isPolicyLoading","error","policyError","storage","ceph","bucketPolicy","get","useQuery","project_id","enabled","retry","deleteMutation","delete","useMutation","invalidate","name","handleClose","message","reset","handleDelete","mutate","hasPolicy","policy","isDeleting","isPending","title","t","open","onCancel","confirmButtonLabel","confirmButtonVariant","onConfirm","cancelButtonLabel","size","disableConfirmButton","direction","gap","status","className","body","p","strong","isError","variant","calculateBucketState","allVersions","isVersioningEnabled","bucketObjectCount","currentVersions","filter","v","isLatest","isDeleteMarker","realVersions","hasOnlyDeleteMarkers","length","hasOldVersionsOrDeleteMarkers","some","effectiveCurrentObjectCount","isBucketEmpty","useState","trpcReact","Modal","ModalFooter","Button","ButtonRow","TextInput","Stack","Checkbox","Status","useProjectId","calculateBucketState","useModalTracking","EmptyBucketModal","isOpen","bucket","onClose","onSuccess","onError","useLingui","projectId","confirmName","setConfirmName","nameError","setNameError","deleteVersionsAndMarkers","setDeleteVersionsAndMarkers","trackClose","markSubmitted","resetTracking","actionPrefix","utils","useUtils","data","versioningStatus","isLoading","isLoadingVersioning","error","versioningError","storage","ceph","versioning","getStatus","useQuery","project_id","name","enabled","staleTime","versionCheckData","isLoadingVersionCheck","versionCheckError","objects","list","containerName","maxKeys","delimiter","showVersions","isVersioningEnabled","status","allVersions","versions","isBucketEmpty","hasOnlyDeleteMarkers","hasOldVersionsOrDeleteMarkers","isVersionDataComplete","isTruncated","isBucketEmptyWithVersions","isTrulyEmpty","emptyBucketMutation","deleteAll","useMutation","onSettled","containers","invalidate","handleClose","reset","handleConfirmNameChange","e","value","target","handleSubmit","trim","t","bucketName","shouldDeleteVersions","mutate","includeVersionsAndDeleteMarkers","deletedCount","message","handleKeyDown","key","hasQueryError","title","open","onCancel","confirmButtonLabel","confirmButtonVariant","onConfirm","cancelButtonLabel","size","disableConfirmButton","isPending","direction","gap","div","className","p","label","required","onChange","onKeyDown","invalid","errortext","undefined","disabled","placeholder","autoFocus","modalFooter","variant","onClick","data-testid","checked","useState","useEffect","trpcReact","Modal","ModalFooter","ButtonRow","TextInput","Stack","Status","Button","useProjectId","calculateBucketState","useModalTracking","DeleteBucketModal","isOpen","bucket","onClose","onSuccess","onError","useLingui","projectId","confirmName","setConfirmName","nameError","setNameError","trackClose","markSubmitted","resetTracking","actionPrefix","utils","useUtils","data","versioningStatus","isLoading","isLoadingVersioning","storage","ceph","versioning","getStatus","useQuery","project_id","name","enabled","isVersioningEnabled","status","objects","isLoadingObjects","error","objectsError","list","containerName","maxKeys","delimiter","showVersions","deleteBucketMutation","containers","delete","useMutation","onSettled","invalidate","reset","handleClose","handleConfirmNameChange","e","value","target","handleSubmit","trim","t","bucketName","mutate","message","handleKeyDown","key","currentObjectCount","length","allVersions","versions","effectiveCurrentObjectCount","hasOldVersionsOrDeleteMarkers","hasCurrentObjects","hasVersionsInVersionedBucket","cannotDelete","errorMessage","title","open","onCancel","confirmButtonLabel","undefined","confirmButtonVariant","onConfirm","cancelButtonLabel","modalFooter","className","variant","onClick","data-testid","size","disableConfirmButton","isPending","direction","gap","body","div","p","ul","li","label","required","onChange","onKeyDown","invalid","errortext","disabled","placeholder","useState","trpcReact","Modal","TextInput","Stack","useProjectId","useModalTracking","DeleteVersionsModal","isOpen","bucket","onClose","onSuccess","onError","useLingui","projectId","confirmName","setConfirmName","nameError","setNameError","trackClose","markSubmitted","resetTracking","actionPrefix","utils","useUtils","deleteVersionsMutation","storage","ceph","objects","deleteAll","useMutation","onSettled","containers","list","invalidate","handleClose","reset","handleConfirmNameChange","e","value","target","handleSubmit","trim","name","t","bucketName","mutate","project_id","containerName","includeVersionsAndDeleteMarkers","deletedCount","error","message","handleKeyDown","key","title","open","onCancel","confirmButtonLabel","confirmButtonVariant","onConfirm","cancelButtonLabel","size","disableConfirmButton","isPending","direction","gap","p","className","label","required","onChange","onKeyDown","invalid","errortext","undefined","disabled","placeholder","autoFocus","encodePrefix","prefix","bytes","TextEncoder","encode","binString","Array","from","byte","String","fromCodePoint","join","btoa","decodePrefix","encoded","atob","Uint8Array","char","codePointAt","TextDecoder","fatal","decode","useState","useEffect","useRef","startTransition","useMemo","Status","Stack","Button","toast","DataGridToolbar","SearchInput","TabNavigation","TabNavigationItem","Checkbox","PopupMenu","PopupMenuItem","PopupMenuOptions","PopupMenuToggle","trpcReact","useProjectId","useCephPermissions","SortInput","ObjectsTableView","ObjectsFileNavigation","CreateFolderModal","UploadObjectModal","DeleteObjectsModal","EnableVersioningModal","SuspendVersioningModal","BucketPolicyModal","DeleteBucketPolicyModal","EmptyBucketModal","DeleteBucketModal","DeleteVersionsModal","useNavigate","Route","getFolderCreatedToast","getObjectDeletedToast","getObjectDeleteErrorToast","getObjectsBulkDeletedToast","getObjectsBulkDeletePartialToast","getObjectsBulkDeleteErrorToast","getVersionsBulkDeletedToast","getVersionsBulkDeletePartialToast","getVersionsBulkDeleteErrorToast","getObjectCopiedToast","getObjectCopyErrorToast","getObjectMovedToast","getObjectMoveErrorToast","getObjectMetadataUpdatedToast","getObjectMetadataUpdateErrorToast","getObjectDownloadErrorToast","getObjectUploadedToast","getObjectUploadCancelledToast","getObjectUploadErrorToast","encodePrefix","decodePrefix","ObjectBrowserView","bucketName","useLingui","projectId","permissions","navigate","from","fullPath","provider","storageType","useParams","prefix","encodedPrefix","sortBy","sortDirection","search","searchParam","tab","useSearch","currentPrefix","continuationToken","setContinuationToken","undefined","keyMarker","setKeyMarker","versionIdMarker","setVersionIdMarker","allObjects","setAllObjects","allFolders","setAllFolders","allVersions","setAllVersions","hasMore","setHasMore","isCreateFolderModalOpen","setIsCreateFolderModalOpen","isUploadModalOpen","setIsUploadModalOpen","isEnableVersioningModalOpen","setIsEnableVersioningModalOpen","isSuspendVersioningModalOpen","setIsSuspendVersioningModalOpen","isPolicyModalOpen","setIsPolicyModalOpen","isDeletePolicyModalOpen","setIsDeletePolicyModalOpen","isEmptyBucketModalOpen","setIsEmptyBucketModalOpen","isDeleteBucketModalOpen","setIsDeleteBucketModalOpen","isDeleteVersionsModalOpen","setIsDeleteVersionsModalOpen","selectedItems","setSelectedItems","isDeleteObjectsModalOpen","setIsDeleteObjectsModalOpen","hasAnyBulkAction","canDeleteVersion","canDeleteObject","localSearchTerm","setLocalSearchTerm","debounceTimer","clearTimeout","current","data","versioningStatus","storage","ceph","versioning","getStatus","useQuery","project_id","bucket","enabled","staleTime","folderDeletedStatus","checkDeletedContent","folders","map","f","status","length","isLoading","isFetching","error","objects","list","containerName","delimiter","maxKeys","showVersions","versions","actualVersions","filter","ver","stripped","key","replace","prev","actualObjects","obj","isTruncated","navigateToPrefix","navigateToBuckets","to","params","loadMore","nextKeyMarker","nextVersionIdMarker","nextContinuationToken","stripPrefix","fullKey","filteredObjects","toLowerCase","includes","trim","deletedFilesList","versionsByKey","reduce","acc","version","push","deletedFiles","Object","entries","forEach","sorted","sort","a","b","lastModified","Date","getTime","latestVersion","find","v","isLatest","isDeleteMarker","previousVersion","allVersionIds","versionId","isDeleted","deleteMarkerVersionId","deletedFoldersList","Array","isArray","filtered","folder","s","isFolderDeleted","folderMarkerVersionId","foldersWithDeleted","hasDeletedContent","folderDeleteMarkerVersionId","filteredFolders","sortedDeletedFiles","comparison","localeCompare","aDate","bDate","size","filteredDeletedFiles","totalItemCount","filteredItemCount","sortedObjects","sortedFolders","sortSettings","options","label","t","value","i18n","showSelection","makeItemKey","versionIdByKey","Map","selectedItemsSet","Set","item","selectableKeys","o","isItemSelected","has","allSelected","every","k","get","someSelected","some","selectedCount","handleToggleSelectKey","exists","handleToggleSelectAll","visibleItemKeys","newItems","existingKeys","toAdd","resetAccumulatedObjects","handleBulkDeleted","deletedKeys","errorCount","message","success","warning","handleBulkDeleteError","errorMessage","handleSearchChange","term","handleSortChange","newSort","resolvedSortBy","resolvedDirection","title","body","div","className","direction","distribution","alignment","gap","active","onClick","selectClassName","onSortByChange","onSortDirectionChange","canCreateFolder","as","icon","data-testid","canCreateObject","variant","placeholder","onInput","e","currentTarget","window","setTimeout","onSearch","onClear","onBucketsClick","onPrefixClick","checked","indeterminate","onChange","aria-label","disabled","_","plural","span","showingVersions","versioningEnabled","selectable","onToggleSelectKey","onFolderClick","canCopyObject","canMoveObject","canUpdateObject","canShareObject","canDeleteFolder","canRestoreVersion","onDeleteObjectSuccess","objectKey","onDeleteObjectError","onCopyObjectSuccess","targetBucket","targetKey","wasOverwritten","onCopyObjectError","onMoveObjectSuccess","onMoveObjectError","onEditMetadataSuccess","onEditMetadataError","onDownloadError","isOpen","onClose","onSuccess","folderPath","objectName","onError","onCancelled","objectKeys","flatMap","deletedFile","vid","isVersionMode","onDeleted","name","count","bytes","deletedCount","useState","trpcReact","Modal","TextInput","Stack","Checkbox","Message","useProjectId","useModalTracking","S3_BUCKET_NAME_REGEX","IP_ADDRESS_REGEX","RESERVED_PREFIXES","RESERVED_SUFFIXES","CreateBucketModal","isOpen","onClose","onSuccess","existingBuckets","useLingui","projectId","bucketName","setBucketName","nameError","setNameError","submitError","setSubmitError","enableVersioning","setEnableVersioning","trackClose","markSubmitted","resetTracking","actionPrefix","utils","useUtils","createBucketMutation","storage","ceph","containers","create","useMutation","list","invalidate","name","trim","handleClose","onError","error","data","code","t","message","reset","validateName","trimmed","length","test","includes","prefix","startsWith","suffix","endsWith","some","b","handleNameChange","e","value","target","handleSubmit","mutate","project_id","handleKeyDown","key","title","open","onCancel","confirmButtonLabel","isPending","onConfirm","cancelButtonLabel","size","disableConfirmButton","disableCancelButton","disableCloseButton","direction","gap","variant","dismissible","onDismiss","role","aria-live","data-testid","p","className","label","required","onChange","onKeyDown","invalid","errortext","undefined","disabled","autoFocus","placeholder","helptext","checked","useEffect","useState","useNavigate","useParams","Button","Checkbox","DataGrid","DataGridHeadCell","DataGridRow","DataGridCell","PopupMenu","PopupMenuItem","PopupMenuOptions","PopupMenuToggle","Status","formatBytesBinary","useVirtualizedTableBody","CreateBucketModal","EmptyBucketModal","DeleteBucketModal","BucketTableView","buckets","createModalOpen","setCreateModalOpen","onCreateSuccess","onEmptySuccess","onEmptyError","onDeleteSuccess","onDeleteError","existingBuckets","selectedBuckets","setSelectedBuckets","hasAnyBulkAction","canEmptyBucket","canDeleteBucket","projectId","provider","storageType","strict","useLingui","navigate","scrollbarWidth","setScrollbarWidth","emptyModalBucket","setEmptyModalBucket","deleteModalBucket","setDeleteModalBucket","ref","tableBodyRef","elementRef","parentRef","height","bodyHeight","virtualItems","totalSize","measureElement","count","length","current","width","offsetWidth","clientWidth","formatDate","dateString","date","Date","toLocaleString","t","handleSelectBucket","bucketName","includes","filter","name","isEmpty","columnCount","gridColumnTemplate","div","className","style","paddingRight","columns","minContentColumns","data-testid","marginRight","colSpan","status","title","body","position","map","virtualRow","bucket","index","isSelected","handleRowNavigate","to","params","containerName","data-index","top","left","transform","start","display","gridTemplateColumns","alignItems","tabIndex","onClick","onKeyDown","e","key","preventDefault","stopPropagation","checked","onChange","span","last_modified","creationDate","bytes","as","icon","aria-label","label","isOpen","onClose","onSuccess","onError","getBucketCreatedToast","bucketName","message","description","getBucketCreateErrorToast","errorMessage","getBucketEmptiedToast","deletedCount","getBucketEmptyErrorToast","getBucketDeletedToast","getBucketDeleteErrorToast","getBucketsEmptyCompleteToast","emptiedCount","totalDeleted","errors","hasErrors","length","totalBuckets","errorsLength","getVersioningEnabledToast","getVersioningEnableErrorToast","getVersioningSuspendedToast","getVersioningSuspendErrorToast","getBucketPolicySavedToast","getBucketPolicySaveErrorToast","getBucketPolicyDeletedToast","getBucketPolicyDeleteErrorToast","getVersionsDeletedToast","getVersionsDeleteErrorToast","getCorsSavedToast","getCorsSaveErrorToast","getCorsRuleDeletedToast","ruleId","getCorsRuleDeleteErrorToast","getCorsRulesDeletedToast","count","getCorsRulesDeleteErrorToast","getLifecycleSavedToast","getLifecycleSaveErrorToast","getLifecycleRuleDeletedToast","getLifecycleRuleDeleteErrorToast","getLifecycleRulesDeletedToast","getLifecycleRulesDeleteErrorToast","z","useForm","useStore","useState","trpcReact","Modal","Status","Stack","Form","FormSection","TextInput","useProjectId","useModalTracking","MAX_VISIBLE","EmptyBucketsModal","isOpen","buckets","onClose","onComplete","useLingui","projectId","progress","setProgress","trackClose","markSubmitted","resetTracking","actionPrefix","formSchema","object","confirm","string","refine","value","message","t","form","defaultValues","validators","onSubmit","emptyBucketMutation","isPending","emptiedCount","totalDeleted","errors","total","length","i","current","bucket","deleted","mutateAsync","project_id","containerName","name","err","Error","String","push","utils","storage","ceph","containers","list","invalidate","objects","handleClose","canEmpty","store","state","isSubmitting","values","useUtils","deleteAll","useMutation","reset","totalCount","visibleBuckets","slice","hiddenCount","progressCurrent","progressTotal","title","open","onCancel","confirmButtonLabel","confirmButtonVariant","cancelButtonLabel","onConfirm","handleSubmit","disableConfirmButton","disableCancelButton","disableCloseButton","size","status","className","direction","gap","p","div","map","id","e","preventDefault","Field","children","field","label","onChange","handleChange","target","placeholder","autoFocus","disabled","required","trpcReact","useProjectId","useCephPermissions","Button","Stack","Message","Status","toast","CredentialPrompt","onSuccess","useLingui","projectId","permissions","isLoading","isLoadingPermissions","isError","isPermissionsError","utils","useUtils","createMutation","storage","ceph","ec2Credentials","create","useMutation","list","invalidate","onError","err","errorMessage","message","error","direction","gap","className","h2","p","status","title","t","body","canCreateCredential","div","onClick","mutate","project_id","disabled","isPending","variant","toCorsRule","rule","AllowedMethods","useEffect","useState","trpcReact","Modal","Stack","Status","Message","useProjectId","useModalTracking","toCorsRule","DeleteCorsRuleModal","isOpen","bucketName","ruleIndex","ruleId","onClose","onSuccess","onError","onMutatingChange","useLingui","projectId","utils","useUtils","isVerifying","setIsVerifying","trackClose","markSubmitted","resetTracking","actionPrefix","data","corsData","isLoading","isCorsLoading","error","corsError","storage","ceph","cors","get","useQuery","project_id","enabled","retry","setMutation","set","useMutation","invalidate","handleClose","message","deleteMutation","delete","isPending","reset","handleDelete","freshData","fetch","freshRules","corsRules","cachedRule","freshRule","JSON","stringify","t","updatedRules","filter","_","index","length","mutate","corsConfiguration","CORSRules","map","ruleDisplayName","hasRules","isDeleting","title","open","onCancel","confirmButtonLabel","confirmButtonVariant","onConfirm","cancelButtonLabel","size","disableConfirmButton","direction","gap","status","className","body","p","strong","isError","variant","useState","DataGrid","DataGridHeadCell","DataGridRow","DataGridCell","Stack","PopupMenu","PopupMenuItem","PopupMenuOptions","Checkbox","Status","toast","DeleteCorsRuleModal","getCorsRuleDeletedToast","getCorsRuleDeleteErrorToast","CorsRulesTable","bucketName","rulesWithIndices","selectedIndices","onToggleSelectRule","onEditRule","onDeleteRule","isMutating","isFiltered","canUpdateCors","canDeleteCors","useLingui","isRowDeleteMutating","setIsRowDeleteMutating","deleteModalState","setDeleteModalState","isOpen","ruleIndex","ruleId","undefined","handleOpenDeleteModal","index","handleCloseDeleteModal","handleDeleteSuccess","message","options","success","handleDeleteError","_index","errorMessage","error","effectiveIsMutating","isEmpty","length","columnCount","direction","gap","columns","minContentColumns","span","className","t","colSpan","status","title","map","rule","originalIndex","key","ruleLabel","ID","String","hasAnyRowAction","data-testid","onClick","e","stopPropagation","checked","includes","onChange","aria-label","AllowedOrigins","join","AllowedMethods","AllowedHeaders","ExposeHeaders","MaxAgeSeconds","div","label","disabled","onClose","onSuccess","onError","onMutatingChange","useState","TextInput","Pill","Stack","Button","TagInput","label","value","onChange","placeholder","helptext","disabled","validate","id","name","required","inputValue","setInputValue","error","setError","handleKeyDown","e","key","trim","preventDefault","addTag","tag","result","valid","includes","undefined","removeTag","tagToRemove","filter","div","className","target","onKeyDown","invalid","errortext","variant","onClick","length","gap","wrap","alignment","distribution","map","index","pillValue","closeable","onClose","urlValidator","url","wildcardCount","match","wildcardMatch","protocol","domain","URL","urlObj","headerValidator","header","test","useEffect","useForm","useStore","Form","Stack","TextInput","CheckboxGroup","Checkbox","TagInput","urlValidator","headerValidator","ALLOWED_METHODS","CorsRuleForm","editingRule","onSubmit","formId","onValidationChange","useLingui","form","defaultValues","ID","AllowedOrigins","AllowedMethods","AllowedHeaders","ExposeHeaders","MaxAgeSeconds","toString","value","newRule","undefined","length","parseInt","allowedOriginsValue","store","state","values","allowedMethodsValue","canSubmit","div","id","e","preventDefault","handleSubmit","direction","gap","Field","name","field","label","t","onChange","handleChange","target","onBlur","handleBlur","placeholder","helptext","validate","required","map","method","checked","includes","current","filter","m","type","min","useEffect","useState","Modal","Status","Message","ModalFooter","ButtonRow","Button","trpcReact","useProjectId","useModalTracking","CorsRuleForm","toCorsRule","CorsRuleModal","isOpen","bucketName","editingIndex","onClose","onSuccess","onError","onMutatingChange","useLingui","projectId","utils","useUtils","isFormValid","setIsFormValid","trackClose","markSubmitted","resetTracking","actionPrefix","data","corsData","isLoading","isCorsLoading","error","corsError","storage","ceph","cors","get","useQuery","project_id","enabled","retry","staleTime","setMutation","set","useMutation","invalidate","handleClose","message","isPending","reset","handleSubmit","rule","currentRules","corsRules","updatedRules","freshData","fetch","freshRules","editingRule","freshRule","JSON","stringify","t","mutate","corsConfiguration","CORSRules","map","isSaving","formId","title","open","onCancel","size","modalFooter","className","variant","onClick","disabled","submitButton","document","querySelector","requestSubmit","status","body","isError","onSubmit","onValidationChange","useEffect","useState","trpcReact","Modal","Stack","Status","Message","useProjectId","useModalTracking","toCorsRule","MAX_VISIBLE_RULES","DeleteCorsRulesModal","isOpen","bucketName","ruleIndices","rules","onClose","onSuccess","onError","onMutatingChange","useLingui","projectId","utils","useUtils","isVerifying","setIsVerifying","trackClose","markSubmitted","resetTracking","actionPrefix","isLoading","isCorsLoading","error","corsError","storage","ceph","cors","get","useQuery","project_id","enabled","retry","setMutation","set","useMutation","invalidate","length","handleClose","message","deleteMutation","delete","isPending","reset","handleDelete","freshData","fetch","freshRules","corsRules","t","mismatches","index","cachedRule","freshRule","JSON","stringify","push","remainingRules","filter","_","includes","mutate","corsConfiguration","CORSRules","map","ruleCount","isDeleting","rulesToDeleteWithIndices","rule","visibleRules","slice","hiddenCount","confirmLabel","title","open","onCancel","confirmButtonLabel","confirmButtonVariant","onConfirm","cancelButtonLabel","size","disableConfirmButton","disableCancelButton","disableCloseButton","direction","gap","status","className","body","p","strong","div","displayName","ID","isError","variant","useState","startTransition","i18n","useNavigate","trpcReact","Status","Button","Stack","toast","Checkbox","PopupMenu","PopupMenuItem","PopupMenuOptions","PopupMenuToggle","DataGridToolbar","SearchInput","Divider","useProjectId","useCephPermissions","SortInput","Route","CorsRulesTable","CorsRuleModal","DeleteCorsRulesModal","getCorsSavedToast","getCorsSaveErrorToast","getCorsRulesDeletedToast","getCorsRulesDeleteErrorToast","CorsRulesTab","bucketName","useLingui","projectId","navigate","from","fullPath","permissions","corsSortBy","corsSortDirection","corsSearch","useSearch","data","corsData","isLoading","error","storage","ceph","cors","get","useQuery","project_id","enabled","retry","staleTime","isRuleModalOpen","setIsRuleModalOpen","editingRuleIndex","setEditingRuleIndex","isBulkDeleteModalOpen","setIsBulkDeleteModalOpen","isRuleModalMutating","setIsRuleModalMutating","isBulkDeleteMutating","setIsBulkDeleteMutating","selectedIndices","setSelectedIndices","sortSettings","options","label","t","value","sortBy","sortDirection","handleSearchChange","term","search","prev","undefined","handleSortChange","newSortSettings","resolvedSortBy","toString","resolvedDirection","handleAddRule","handleEditRule","index","handleToggleSelectRule","includes","filter","i","handleToggleSelectAll","allFilteredSelected","filteredIndices","Set","handleBulkDelete","handleDeleteRule","rules","corsRules","sortRules","sort","a","b","comparison","ID","localeCompare","AllowedOrigins","join","AllowedMethods","AllowedHeaders","ExposeHeaders","MaxAgeSeconds","filteredRulesWithIndices","map","rule","originalIndex","indexOf","ruleId","toLowerCase","length","every","someFilteredSelected","some","status","title","body","message","distribution","alignment","gap","className","selectClassName","selectWidth","onSortByChange","onSortDirectionChange","direction","canUpdateCors","variant","onClick","placeholder","data-testid","onInput","e","v","currentTarget","onSearch","onClear","canDeleteCors","checked","indeterminate","onChange","aria-label","disabled","as","size","icon","_","plural","span","rulesWithIndices","onToggleSelectRule","onEditRule","onDeleteRule","isMutating","isFiltered","isOpen","ruleIndices","onClose","onSuccess","count","success","onError","errorMessage","onMutatingChange","editingIndex","normalizeFilter","prefix","tags","hasPrefix","undefined","hasTags","length","Prefix","Tag","And","Tags","parseDaysValue","raw","trimmed","trim","ok","reason","test","value","Number","isSafeInteger","isValidExpiration","expiration","hasDays","Days","hasDate","Date","hasDeleteMarker","ExpiredObjectDeleteMarker","toLifecycleRule","rule","converted","ID","Status","Filter","NoncurrentVersionExpiration","NoncurrentVersionTransitions","AbortIncompleteMultipartUpload","Expiration","date","toISOString","Transitions","map","t","validateLifecycleRules","rules","errors","push","seenIds","Set","i","ruleLabel","has","add","hasExpiration","hasTransitions","hasNoncurrentExpiration","hasNoncurrentTransitions","hasAbortUpload","hasTagFilter","predicateCount","ObjectSizeGreaterThan","ObjectSizeLessThan","topLevelConditions","filter","Boolean","NoncurrentDays","j","transition","convertedRules","formatFilter","legacyPrefix","parts","Key","Value","andParts","forEach","tag","join","formatExpiration","toLocaleDateString","formatTransitions","transitions","time","StorageClass","formatNoncurrentExpiration","noncurrentExp","NewerNoncurrentVersions","formatNoncurrentTransitions","keep","useEffect","useState","Modal","Status","trpcReact","useProjectId","useModalTracking","validateLifecycleRules","DeleteLifecycleRuleModal","isOpen","bucketName","ruleIndex","ruleId","onClose","onSuccess","onError","onMutatingChange","useLingui","projectId","utils","useUtils","isVerifying","setIsVerifying","trackClose","markSubmitted","resetTracking","actionPrefix","data","lifecycleData","isLoading","error","queryError","storage","ceph","lifecycle","get","useQuery","project_id","enabled","retry","staleTime","deleteMutation","delete","useMutation","invalidate","handleClose","message","setMutation","set","isMutating","isPending","reset","handleConfirm","freshData","fetch","freshRules","rules","cachedRule","freshRule","JSON","stringify","t","remaining","filter","_","i","length","mutate","validation","ok","errorMsg","errors","join","lifecycleConfiguration","Rules","Error","String","ruleNumber","displayName","open","onCancel","title","size","confirmButtonLabel","confirmButtonVariant","onConfirm","cancelButtonLabel","disableConfirmButton","disableCancelButton","disableCloseButton","closeOnEsc","status","className","body","p","strong","useState","DataGrid","DataGridHeadCell","DataGridRow","DataGridCell","Stack","PopupMenu","PopupMenuItem","PopupMenuOptions","Checkbox","Status","toast","DeleteLifecycleRuleModal","getLifecycleRuleDeletedToast","getLifecycleRuleDeleteErrorToast","formatFilter","formatExpiration","formatTransitions","formatNoncurrentExpiration","formatNoncurrentTransitions","LifecycleRulesTable","bucketName","rulesWithIndices","selectedIndices","onToggleSelectRule","onEditRule","onDeleteRule","isMutating","isFiltered","canUpdateLifecycle","canDeleteLifecycle","useLingui","isRowDeleteMutating","setIsRowDeleteMutating","deleteModalState","setDeleteModalState","isOpen","ruleIndex","ruleId","undefined","handleOpenDeleteModal","index","handleCloseDeleteModal","handleDeleteSuccess","message","options","success","handleDeleteError","_index","errorMessage","error","effectiveIsMutating","isEmpty","length","columnCount","minContentColumns","direction","gap","columns","span","className","t","colSpan","status","title","map","rule","originalIndex","key","noncurrentExpirationText","NoncurrentVersionExpiration","noncurrentTransitionsText","NoncurrentVersionTransitions","noncurrentText","filter","join","transitionsText","Transitions","abortDays","AbortIncompleteMultipartUpload","DaysAfterInitiation","abortText","otherActionsText","ruleLabel","ID","String","hasAnyRowAction","data-testid","onClick","e","stopPropagation","checked","includes","onChange","aria-label","Filter","Prefix","Expiration","div","label","disabled","onClose","onSuccess","onError","onMutatingChange","useForm","useStore","useEffect","useState","Form","Stack","TextInput","Button","Checkbox","Message","Pill","Label","Divider","normalizeFilter","parseDaysValue","isValidExpiration","LifecycleRuleForm","editingRule","onSubmit","formId","onValidationChange","useLingui","getInitialValues","ID","Status","Prefix","tags","hasExpiration","expirationDays","hasNoncurrentExpiration","noncurrentDays","hasAbortUpload","abortDays","filter","Filter","expiration","Expiration","noncurrentExp","NoncurrentVersionExpiration","abort","AbortIncompleteMultipartUpload","prefix","Tag","And","Tags","undefined","Days","toString","NoncurrentDays","DaysAfterInitiation","form","defaultValues","value","trimmedPrefix","trim","length","newRule","exp","ok","Transitions","nc","NewerNoncurrentVersions","NoncurrentVersionTransitions","hasExpirationValue","store","state","values","hasNoncurrentExpirationValue","hasAbortUploadValue","expirationDaysValue","noncurrentDaysValue","abortDaysValue","tagsValue","statusValue","prefixValue","willExpireWholeBucket","daysError","checked","raw","result","reason","t","expirationDaysError","noncurrentDaysError","abortDaysError","canSubmit","hasAtLeastOneAction","r","hasPreservableNonDaysExpiration","validExpirationDays","newTagKey","setNewTagKey","newTagValue","setNewTagValue","tagError","setTagError","id","role","e","preventDefault","stopPropagation","handleSubmit","direction","gap","Field","name","field","label","onChange","handleChange","target","onBlur","handleBlur","placeholder","helptext","p","trimmed","addTag","key","some","tag","Key","currentTags","Value","removeTag","index","_","i","div","className","onKeyDown","invalid","errortext","disabled","onClick","wrap","alignment","distribution","map","pillKey","pillValue","onClose","closeable","style","color","text","required","variant","title","noncurrentTransitionCount","type","min","useEffect","useState","Modal","Status","Message","ModalFooter","ButtonRow","Button","trpcReact","useProjectId","useModalTracking","LifecycleRuleForm","validateLifecycleRules","LifecycleRuleModal","isOpen","bucketName","editingIndex","onClose","onSuccess","onError","onMutatingChange","useLingui","projectId","utils","useUtils","isFormValid","setIsFormValid","validationErrors","setValidationErrors","trackClose","markSubmitted","resetTracking","actionPrefix","data","lifecycleData","isLoading","isLifecycleLoading","error","lifecycleError","storage","ceph","lifecycle","get","useQuery","project_id","enabled","retry","staleTime","setMutation","set","useMutation","invalidate","handleClose","message","isPending","reset","handleSubmit","rule","updatedRules","freshData","fetch","rules","freshRules","editingRule","freshRule","JSON","stringify","t","validation","ok","errors","mutate","lifecycleConfiguration","Rules","Error","String","isSaving","open","onCancel","title","size","modalFooter","className","variant","onClick","disabled","document","querySelector","requestSubmit","status","body","length","ul","map","i","li","formId","onSubmit","onValidationChange","useEffect","useState","Modal","Status","Stack","trpcReact","useProjectId","useModalTracking","validateLifecycleRules","MAX_VISIBLE_RULES","DeleteLifecycleRulesModal","isOpen","bucketName","ruleIndices","rules","onClose","onSuccess","onError","onMutatingChange","useLingui","projectId","utils","useUtils","isVerifying","setIsVerifying","trackClose","markSubmitted","resetTracking","actionPrefix","isLoading","error","queryError","storage","ceph","lifecycle","get","useQuery","project_id","enabled","retry","staleTime","deleteMutation","delete","useMutation","invalidate","length","handleClose","message","setMutation","set","isMutating","isPending","reset","handleConfirm","freshData","fetch","freshRules","mismatches","index","cachedRule","freshRule","JSON","stringify","push","t","remaining","filter","_","i","includes","mutate","validation","ok","errorMsg","errors","join","lifecycleConfiguration","Rules","Error","String","ruleCount","rulesToDeleteWithIndices","map","rule","undefined","visibleRules","slice","hiddenCount","confirmLabel","open","onCancel","title","size","confirmButtonLabel","confirmButtonVariant","onConfirm","cancelButtonLabel","disableConfirmButton","disableCancelButton","disableCloseButton","closeOnEsc","status","className","body","direction","gap","p","strong","div","ruleNumber","ID","useState","startTransition","i18n","useNavigate","trpcReact","Status","Message","Button","Stack","toast","Checkbox","PopupMenu","PopupMenuItem","PopupMenuOptions","PopupMenuToggle","DataGridToolbar","SearchInput","Divider","useProjectId","useCephPermissions","SortInput","Route","LifecycleRulesTable","LifecycleRuleModal","DeleteLifecycleRulesModal","getLifecycleSavedToast","getLifecycleSaveErrorToast","getLifecycleRulesDeletedToast","getLifecycleRulesDeleteErrorToast","LifecycleRulesTab","bucketName","useLingui","projectId","navigate","from","fullPath","permissions","lifecycleSortBy","lifecycleSortDirection","lifecycleSearch","useSearch","data","lifecycleData","isLoading","error","storage","ceph","lifecycle","get","useQuery","project_id","enabled","retry","staleTime","isRuleModalOpen","setIsRuleModalOpen","editingRuleIndex","setEditingRuleIndex","isBulkDeleteModalOpen","setIsBulkDeleteModalOpen","isRuleModalMutating","setIsRuleModalMutating","isBulkDeleteMutating","setIsBulkDeleteMutating","selectedIndices","setSelectedIndices","sortSettings","options","label","t","value","sortBy","sortDirection","handleSearchChange","term","search","prev","undefined","handleSortChange","newSortSettings","resolvedSortBy","toString","resolvedDirection","handleAddRule","handleEditRule","index","handleToggleSelectRule","includes","filter","i","handleToggleSelectAll","allFilteredSelected","filteredIndices","Set","handleBulkDelete","handleDeleteRule","rules","skippedRuleCount","mutationsBlocked","sortRules","items","sort","a","b","comparison","rule","ID","localeCompare","Expiration","Days","rulesWithOriginalIndices","map","originalIndex","filteredRulesWithIndices","toLowerCase","length","every","someFilteredSelected","some","skippedRulesMessage","_","plural","status","title","body","message","variant","className","distribution","alignment","gap","selectClassName","onSortByChange","onSortDirectionChange","direction","canUpdateLifecycle","onClick","disabled","placeholder","data-testid","onInput","e","v","currentTarget","onSearch","onClear","canDeleteLifecycle","checked","indeterminate","onChange","aria-label","as","size","icon","span","rulesWithIndices","onToggleSelectRule","onEditRule","onDeleteRule","isMutating","isFiltered","isOpen","ruleIndices","onClose","onSuccess","count","success","onError","errorMessage","onMutatingChange","editingIndex","useState","useEffect","useRef","startTransition","useNavigate","SortInput","trpcReact","Button","Checkbox","DataGridToolbar","PopupMenu","PopupMenuItem","PopupMenuOptions","PopupMenuToggle","SearchInput","Stack","Status","toast","BucketTableView","getBucketCreatedToast","getBucketEmptiedToast","getBucketEmptyErrorToast","getBucketDeletedToast","getBucketDeleteErrorToast","getBucketsEmptyCompleteToast","EmptyBucketsModal","CredentialPrompt","useProjectId","useCephPermissions","Route","CreateBucketModal","DeleteBucketModal","DeleteBucketPolicyModal","EmptyBucketModal","DeleteVersionsModal","CorsRulesTab","CephCorsRules","LifecycleRulesTab","CephLifecycleRules","CephBuckets","i18n","useLingui","projectId","navigate","from","fullPath","sortBy","sortDirection","search","searchParam","useSearch","permissions","hasAnyBulkAction","canEmptyBucket","createModalOpen","setCreateModalOpen","emptyAllModalOpen","setEmptyAllModalOpen","selectedBuckets","setSelectedBuckets","localSearchTerm","setLocalSearchTerm","debounceTimer","undefined","clearTimeout","current","handleCreateSuccess","bucketName","message","options","success","handleEmptySuccess","deletedCount","handleEmptyError","errorMessage","error","handleDeleteSuccess","handleDeleteError","handleEmptyAllComplete","emptiedCount","totalDeleted","errors","length","failedBucketNames","Set","map","e","split","prev","filter","name","has","warning","sortSettings","label","t","value","data","buckets","isLoading","storage","ceph","containers","list","useQuery","project_id","includeMetadata","enabled","retry","sortBuckets","sort","a","b","comparison","localeCompare","count","bytes","last_modified","Date","getTime","filteredBuckets","bucket","toLowerCase","includes","sortedBuckets","handleSearchChange","term","handleSortChange","newSortSettings","resolvedSortBy","toString","resolvedDirection","status","title","onSuccess","window","location","reload","isAccessDenied","isAuthError","div","p","className","selectedBucketSummaries","c","hasSelection","selectedCount","totalCount","filteredCount","displayedNames","allSelected","every","n","someSelected","some","handleToggleSelectAll","direction","distribution","alignment","gap","selectClassName","onSortByChange","onSortDirectionChange","canCreateBucket","variant","onClick","placeholder","data-testid","onInput","v","currentTarget","setTimeout","onSearch","onClear","checked","indeterminate","onChange","as","disabled","size","icon","_","plural","span","trim","onCreateSuccess","existingBuckets","onEmptySuccess","onEmptyError","onDeleteSuccess","onDeleteError","canDeleteBucket","isOpen","onClose","onComplete","trpcReact","useProjectId","calculateBucketState","useBucketInfo","bucketName","enabled","projectId","data","bucketsData","isLoading","isLoadingBuckets","storage","ceph","containers","list","useQuery","project_id","staleTime","bucket","find","b","name","bucketObjectCount","count","versioningStatus","isLoadingVersioning","versioning","getStatus","policyData","isLoadingPolicy","bucketPolicy","get","retry","isLoadingCors","cors","lifecycle","versionCheckData","isLoadingVersionCheck","objects","containerName","maxKeys","delimiter","showVersions","isVersioningEnabled","status","allVersions","versions","hasOnlyDeleteMarkers","hasOldVersionsOrDeleteMarkers","isBucketEmpty","isBucketEmptyWithVersions","hasVersionsOrDeleteMarkers","length","Button","PopupMenu","PopupMenuItem","PopupMenuOptions","PopupMenuToggle","BucketHeaderActions","versioningStatus","hasPolicy","hasOldVersionsOrDeleteMarkers","isBucketEmpty","onOpenModal","canUpdateVersioning","canUpdatePolicy","canDeletePolicy","canEmptyBucket","canDeleteBucket","canDeleteVersions","useLingui","versioningState","status","undefined","canEnableVersioning","canSuspendVersioning","canToggleVersioning","canShowDeletePolicy","canShowEmptyBucket","canShowDeleteVersions","hasAnyAction","as","icon","title","t","aria-label","label","onClick","useState","useNavigate","toast","useProjectId","EnableVersioningModal","SuspendVersioningModal","BucketPolicyModal","DeleteBucketPolicyModal","EmptyBucketModal","DeleteBucketModal","DeleteVersionsModal","getVersioningEnabledToast","getVersioningEnableErrorToast","getVersioningSuspendedToast","getVersioningSuspendErrorToast","getBucketPolicySavedToast","getBucketPolicySaveErrorToast","getBucketPolicyDeletedToast","getBucketPolicyDeleteErrorToast","getVersionsDeletedToast","getVersionsDeleteErrorToast","getBucketEmptiedToast","getBucketEmptyErrorToast","getBucketDeletedToast","getBucketDeleteErrorToast","BucketModals","bucketName","provider","storageType","activeModal","onClose","navigate","projectId","handleDeleteBucketSuccess","message","options","success","to","params","handleDeleteBucketError","errorMessage","error","isOpen","onSuccess","onError","action","bucket","name","count","bytes","deletedCount","useBucketModals","setActiveModal","openModal","modal","closeModal","ModalsComponent","TabNavigation","TabNavigationItem","Route","BucketDetailTabs","useLingui","navigate","useNavigate","view","useSearch","label","t","active","onClick","search","prev","useState","useParams","Badge","Divider","ContentHeader","useBucketInfo","useCephPermissions","BucketHeaderActions","BucketModals","BucketDetailTabs","BucketHeader","bucketName","projectId","provider","storageType","from","activeModal","setActiveModal","versioningStatus","policyData","hasOldVersionsOrDeleteMarkers","isBucketEmpty","enabled","permissions","openModal","modal","closeModal","badges","status","variant","policy","actions","hasPolicy","Boolean","onOpenModal","canUpdateVersioning","canUpdatePolicy","canDeletePolicy","canEmptyBucket","canDeleteBucket","canDeleteVersions","canDeleteVersion","title","div","className","spacing","onClose","Button","PopupMenu","PopupMenuItem","PopupMenuOptions","PopupMenuToggle","ContainerHeaderActions","onOpenModal","useLingui","as","icon","title","t","aria-label","label","onClick","data-testid","useState","useEffect","useRef","Fragment","trpcReact","useProjectId","Modal","Textarea","Stack","Status","Checkbox","Badge","Button","Icon","Tooltip","TooltipTrigger","TooltipContent","Message","DescriptionList","DescriptionTerm","DescriptionDefinition","parseAclEntry","raw","entry","trim","type","description","requiresToken","startsWith","referrer","slice","isDeny","host","test","projectId","split","userId","includes","parseAclString","aclString","map","s","filter","Boolean","PUBLIC_READ_ENTRIES","isPublicRead","readAcl","entries","every","e","addPublicReadEntries","current","existing","merged","Set","join","removePublicReadEntries","aclEntryLabel","t","ManageContainerAccessModal","isOpen","container","onClose","onSuccess","onError","useLingui","setReadAcl","writeAcl","setWriteAcl","publicRead","setPublicRead","showPreview","setShowPreview","data","info","isLoading","isError","isMetaError","error","metaError","storage","swift","getContainerMetadata","useQuery","project_id","name","enabled","read","write","utils","useUtils","updateMutation","updateContainerMetadata","useMutation","invalidate","listContainers","handleClose","message","resetMutationRef","reset","handlePublicReadChange","checked","target","prev","handleReadAclChange","value","handleSubmit","mutate","isBusy","isPending","hasAnyAcl","length","parsedReadEntries","parsedWriteEntries","modalTitle","span","className","title","open","onCancel","confirmButtonLabel","onConfirm","cancelButtonLabel","size","disableConfirmButton","variant","errorMessage","div","status","body","direction","gap","AclFieldLabel","label","onChange","disabled","placeholder","rows","onClick","v","p","alignTerms","i","AclExample","code","a","href","rel","triggerEvent","icon","useState","useEffect","useRef","useCallback","trpcReact","Modal","TextInput","Stack","Status","DataGrid","DataGridRow","DataGridHeadCell","DataGridCell","Button","Checkbox","Tooltip","TooltipTrigger","TooltipContent","Icon","ComboBox","ComboBoxOption","useProjectId","RESERVED_META_KEYS","Set","MAX_COMBO_OPTIONS","VALID_KEY_RE","EditContainerMetadataModal","isOpen","container","onClose","onSuccess","useLingui","projectId","data","info","isLoading","isError","isMetaError","error","metaError","storage","swift","getContainerMetadata","useQuery","project_id","name","enabled","isPublicAccess","read","publicUrl","getContainerPublicUrl","containers","listContainers","containerSearch","setContainerSearch","debouncedSearch","setDebouncedSearch","debounceTimer","handleContainerSearch","e","value","target","current","clearTimeout","setTimeout","filteredContainers","trim","length","filter","c","toLowerCase","includes","visibleContainers","slice","hiddenCount","utils","useUtils","quotaBytes","setQuotaBytes","quotaBytesError","setQuotaBytesError","quotaCount","setQuotaCount","quotaCountError","setQuotaCountError","webIndex","setWebIndex","webListings","setWebListings","versionsEnabled","setVersionsEnabled","versionsLocation","setVersionsLocation","metadata","setMetadata","metaErrors","setMetaErrors","isAddingNew","setIsAddingNew","newKey","setNewKey","newValue","setNewValue","newKeyError","setNewKeyError","newValueError","setNewValueError","String","historyLocation","rawMetaForWeb","rawMeta","entries","Object","key","has","map","isNew","isEditing","originalKey","originalValue","resetForm","updateMutation","reset","updateContainerMetadata","useMutation","invalidate","handleClose","onError","validateQuotas","valid","isNaN","Number","isInteger","t","validateMetaKey","test","isDuplicate","some","handleAddNew","keyErr","handleCancelAdd","handleEdit","index","i","handleSaveEdit","entry","handleCancelEdit","handleDeleteMeta","_","handleKeyChange","prev","n","handleValueChange","handleSubmit","metadataToSet","removeMetadata","forEach","push","originalKeys","keys","k","currentOriginalKeys","Boolean","wasVersioned","previousLocation","mutate","undefined","removeVersionsLocation","isBusy","isPending","isMetaFailed","hasEditing","initialQuotaBytes","initialQuotaCount","initialVersionsEnabled","initialVersionsLocation","initialWebIndex","initialWebListings","initialMetadataKeys","metadataUnchanged","every","isUnchanged","displayedQuotaBytes","title","span","className","open","onCancel","confirmButtonLabel","onConfirm","cancelButtonLabel","size","disableConfirmButton","p","errorMessage","message","status","body","div","direction","gap","label","count","disabled","readOnly","bytesUsed","toLocaleString","bytes","onChange","placeholder","invalid","errortext","helptext","a","href","rel","checked","alignment","triggerEvent","icon","strong","onInputChange","maxOptions","totalCount","distribution","onClick","variant","columns","autoFocus","colSpan","z","useForm","useStore","useRef","trpcReact","useProjectId","Modal","ModalFooter","Button","ButtonRow","Form","FormSection","TextInput","Stack","Status","useModalTracking","EmptyContainerModal","isOpen","container","onClose","onSuccess","onError","useLingui","projectId","containerNameRef","trackClose","markSubmitted","resetTracking","actionPrefix","formSchema","object","confirm","string","refine","value","message","t","form","defaultValues","validators","onSubmit","emptyContainerMutation","isPending","current","name","mutate","project_id","canEmpty","store","state","isSubmitting","values","utils","useUtils","data","objects","isLoading","isLoadingObjects","error","objectsError","storage","swift","listObjects","useQuery","format","limit","enabled","emptyContainer","useMutation","deletedCount","listContainers","invalidate","onSettled","handleClose","reset","actualObjectCount","length","isTrulyEmpty","count","isConsistencyDelay","showEmptyInfo","modalTitle","span","className","title","open","onCancel","confirmButtonLabel","undefined","confirmButtonVariant","onConfirm","handleSubmit","cancelButtonLabel","modalFooter","variant","onClick","data-testid","size","disableConfirmButton","p","errorMessage","status","direction","gap","br","strong","div","map","obj","shown","total","id","e","preventDefault","Field","children","field","label","required","onChange","handleChange","target","invalid","meta","errors","errortext","join","disabled","autoFocus","placeholder","z","useForm","useStore","useState","useEffect","trpcReact","Modal","Form","FormSection","TextInput","Stack","Status","Checkbox","useProjectId","useModalTracking","DeleteContainerModal","isOpen","container","onClose","onSuccess","onError","useLingui","projectId","versionsConfirmed","setVersionsConfirmed","trackClose","markSubmitted","resetTracking","actionPrefix","formSchema","object","confirm","string","refine","value","message","t","form","defaultValues","validators","onSubmit","objectsError","metaError","deleteContainerMutation","isPending","isVersioned","mutate","project_id","name","canDelete","store","state","isSubmitting","values","utils","useUtils","data","objects","isLoading","isLoadingObjects","error","storage","swift","listObjects","useQuery","format","limit","enabled","containerMetadata","getContainerMetadata","versionsEnabled","versionsLocation","historyLocation","deleteContainer","useMutation","listContainers","invalidate","onSettled","handleClose","reset","actualObjectCount","length","hasObjects","count","isConsistencyDelay","hasPreflightError","modalTitle","span","className","title","open","onCancel","confirmButtonLabel","confirmButtonVariant","onConfirm","handleSubmit","cancelButtonLabel","undefined","size","disableConfirmButton","direction","gap","role","aria-live","p","errorMessage","status","br","strong","label","checked","onChange","e","target","id","preventDefault","Field","children","field","required","handleChange","invalid","meta","errors","errortext","map","join","disabled","autoFocus","placeholder","Stack","getContainerCreatedToast","containerName","message","description","getContainerCreatedWithWarningToast","reason","getContainerEmptiedToast","deletedCount","getContainerEmptyErrorToast","errorMessage","getContainerDeletedToast","getContainerDeleteErrorToast","getContainerUpdatedToast","getContainerUpdateErrorToast","getContainerAclUpdatedToast","getContainerAclUpdateErrorToast","getContainersEmptiedToast","emptiedCount","totalDeleted","getContainersEmptyErrorToast","span","className","getContainersEmptyCompleteToast","errors","hasErrors","length","hasSuccess","isPartial","severity","direction","gap","errorDetails","join","useState","useNavigate","useParams","toast","Status","ContentHeader","trpcReact","ContainerHeaderActions","ManageContainerAccessModal","EditContainerMetadataModal","EmptyContainerModal","DeleteContainerModal","getContainerAclUpdatedToast","getContainerAclUpdateErrorToast","getContainerUpdatedToast","getContainerEmptiedToast","getContainerEmptyErrorToast","getContainerDeletedToast","getContainerDeleteErrorToast","ContainerHeader","containerName","projectId","provider","storageType","from","navigate","useLingui","activeModal","setActiveModal","closeModal","data","containerInfo","error","containerInfoError","storage","swift","getContainerMetadata","useQuery","project_id","container","enabled","name","count","objectCount","bytes","bytesUsed","handleAclSuccess","message","options","success","handleAclError","errorMessage","handlePropertiesSuccess","handleEmptySuccess","deletedCount","handleEmptyError","handleDeleteSuccess","to","params","handleDeleteError","title","actions","onOpenModal","status","t","body","className","isOpen","onClose","onSuccess","onError","createFileRoute","useParams","checkServiceAvailability","ErrorBoundary","Trans","SwiftObjects","CephObjects","CephCorsRules","CephLifecycleRules","z","BucketHeader","ContainerHeader","useSetBreadcrumb","objectsSearchSchema","object","prefix","string","optional","sortBy","enum","default","sortDirection","search","tab","view","corsSortBy","corsSortDirection","corsSearch","lifecycleSortBy","lifecycleSortDirection","lifecycleSearch","Route","staticData","section","service","analytics","name","RouteInfo","validateSearch","head","match","meta","title","params","containerName","component","lazyRouteComponent","$$splitComponentImporter","notFoundComponent","$$splitNotFoundComponentImporter","errorComponent","$$splitErrorComponentImporter","loader","context","trpcClient","availableServices","auth","getAvailableServices","query","client","beforeLoad","ObjectsDashboard","projectId","provider","from","select","id","useSearch","undefined"],"sources":["../../src/client/routes/_auth/projects/$projectId/storage/$provider/$storageType/index.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/utils/serviceAvailability.ts","../../src/client/utils/formatSwiftDate.ts","../../src/client/hooks/useAvailableViewportHeight.ts","../../src/client/hooks/useVirtualizedTableBody.ts","../../src/client/routes/_auth/projects/$projectId/storage/-components/Swift/Objects/DeleteFolderModal.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Swift/Objects/DeleteObjectModal.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Swift/Objects/CopyObjectModal.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Swift/Objects/MoveRenameObjectModal.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Swift/Objects/GenerateTempUrlModal.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Swift/Objects/EditObjectMetadataModal.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Swift/Objects/ObjectToastNotifications.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Swift/Objects/stores/objectDownloadStore.ts","../../src/client/routes/_auth/projects/$projectId/storage/-components/Swift/Objects/ObjectsTableView.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Swift/Objects/ObjectsFileNavigation.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Swift/Objects/CreateFolderModal.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Swift/Objects/UploadObjectModal.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Swift/Objects/DeleteObjectsModal.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Swift/Objects/index.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/hooks/useCephPermissions.ts","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Objects/ObjectToastNotifications.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Objects/stores/objectDownloadStore.ts","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Objects/DeleteObjectModal.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Objects/utils/bulkDeleteErrors.ts","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Objects/DeleteVersionModal.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Objects/RestoreVersionModal.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Objects/utils/objectValidation.ts","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Objects/hooks/useObjectBrowser.ts","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Objects/hooks/useBucketSearch.ts","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Objects/hooks/useLocalFolders.ts","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Objects/hooks/useCopyMoveModalState.ts","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Objects/CopyObjectModal.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Objects/MoveObjectModal.tsx","../../src/server/Storage/constants.ts","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Objects/GeneratePresignedUrlModal.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Objects/EditMetadataModal.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Objects/ObjectVersionHistoryModal.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Objects/ObjectsTableView.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Objects/ObjectsFileNavigation.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Objects/CreateFolderModal.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Objects/UploadObjectModal.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Objects/DeleteObjectsModal.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Buckets/EnableVersioningModal.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Buckets/SuspendVersioningModal.tsx","../../src/client/components/JsonEditor.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Buckets/BucketPolicyModal.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Buckets/DeleteBucketPolicyModal.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/hooks/bucketStateHelpers.ts","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Buckets/EmptyBucketModal.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Buckets/DeleteBucketModal.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Buckets/DeleteVersionsModal.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/utils/prefixEncoding.ts","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Objects/ObjectBrowserView.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Buckets/CreateBucketModal.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Buckets/BucketTableView.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Buckets/BucketToastNotifications.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Buckets/EmptyBucketsModal.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Buckets/CredentialPrompt.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Buckets/utils/corsUtils.ts","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Buckets/DeleteCorsRuleModal.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Buckets/CorsRulesTable.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Buckets/TagInput.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Buckets/CorsRuleForm.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Buckets/CorsRuleModal.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Buckets/DeleteCorsRulesModal.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Buckets/CorsRulesTab.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Buckets/utils/lifecycleUtils.ts","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Buckets/DeleteLifecycleRuleModal.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Buckets/LifecycleRulesTable.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Buckets/LifecycleRuleForm.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Buckets/LifecycleRuleModal.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Buckets/DeleteLifecycleRulesModal.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Buckets/LifecycleRulesTab.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Buckets/index.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/hooks/useBucketInfo.ts","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Buckets/BucketHeaderActions.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Buckets/BucketModals.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Buckets/BucketDetailTabs.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Buckets/BucketHeader.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Swift/Containers/ContainerHeaderActions.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Swift/Containers/ManageContainerAccessModal.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Swift/Containers/EditContainerMetadataModal.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Swift/Containers/EmptyContainerModal.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Swift/Containers/DeleteContainerModal.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Swift/Containers/ContainerToastNotifications.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Swift/Containers/ContainerHeader.tsx","../../src/client/routes/_auth/projects/$projectId/storage/$provider/$storageType/$containerName/objects/index.tsx"],"sourcesContent":["import { createFileRoute, redirect, useParams } from \"@tanstack/react-router\"\nimport { z } from \"zod\"\nimport { getServiceIndex } from \"@/server/Authentication/helpers\"\nimport { ErrorBoundary } from \"react-error-boundary\"\nimport { SwiftContainers } from \"../../-components/Swift/Containers\"\nimport { CephBuckets } from \"../../-components/Ceph/Buckets\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport type { RouteInfo } from \"@/client/routes/routeInfo\"\nimport { ContentHeader } from \"@/client/components/ContentHeader/ContentHeader\"\n\n/**\n * Validates that the requested storage provider is available for the given project,\n * and redirects to an appropriate fallback route when it is not.\n *\n * Redirect rules (in priority order):\n * 1. No `object-store` service at all → redirect to the project overview.\n * 2. Unknown provider (neither \"swift\" nor \"ceph\") → redirect to the first\n * available provider, or to the project overview if none exist.\n * 3. Requested provider unavailable → redirect to the other provider,\n * or to the project overview if no alternative exists.\n *\n * Ceph has a temporary fallback flag (`cephFallbackEnabled`) that treats it as\n * available even when absent from the OpenStack service catalog.\n *\n * @throws {redirect} - Always throws a TanStack Router redirect; never returns normally\n * when the requested provider/project combination is unavailable.\n */\nexport const checkServiceAvailability = (\n availableServices: {\n type: string\n name: string\n }[],\n params: {\n projectId: string\n provider: string\n }\n) => {\n const { provider, projectId } = params\n\n const serviceIndex = getServiceIndex(availableServices)\n\n // Redirect to the \"Projects Overview\" page if no storage services available\n if (!serviceIndex[\"object-store\"]) {\n throw redirect({\n to: \"/projects/$projectId\",\n params: { projectId },\n })\n }\n\n // Check provider availability\n const hasSwift = Boolean(serviceIndex[\"object-store\"][\"swift\"])\n const hasCeph = Boolean(serviceIndex[\"object-store\"][\"ceph\"])\n\n // TEMPORARY: Allow Ceph access even if not in catalog (relies on env config)\n // TODO: Properly register Ceph in OpenStack service catalog\n const cephFallbackEnabled = true // Set to false once Ceph is in catalog\n\n // Effective availability includes fallback flag for Ceph\n const hasEffectiveCeph = hasCeph || cephFallbackEnabled\n const fallbackProvider = hasSwift ? \"swift\" : hasEffectiveCeph ? \"ceph\" : null\n const fallbackStorageType = hasSwift ? \"containers\" : hasEffectiveCeph ? \"buckets\" : null\n\n if (provider !== \"swift\" && provider !== \"ceph\") {\n if (!fallbackProvider || !fallbackStorageType) {\n throw redirect({\n to: \"/projects/$projectId\",\n params: { projectId },\n })\n }\n throw redirect({\n to: \"/projects/$projectId/storage/$provider/$storageType\",\n params: { ...params, provider: fallbackProvider, storageType: fallbackStorageType },\n })\n }\n\n if (provider === \"swift\" && !hasSwift) {\n if (!hasEffectiveCeph) {\n throw redirect({\n to: \"/projects/$projectId\",\n params: { projectId },\n })\n }\n\n throw redirect({\n to: \"/projects/$projectId/storage/$provider/$storageType\",\n params: { ...params, provider: \"ceph\", storageType: \"buckets\" },\n })\n }\n\n if (provider === \"ceph\" && !hasEffectiveCeph) {\n if (!hasSwift) {\n throw redirect({\n to: \"/projects/$projectId\",\n params: { projectId },\n })\n }\n\n throw redirect({\n to: \"/projects/$projectId/storage/$provider/$storageType\",\n params: { ...params, provider: \"swift\", storageType: \"containers\" },\n })\n }\n}\n\n// Search params schema\n// - sortBy: active sort column — persisted for deep links and back navigation\n// - sortDirection: \"asc\" | \"desc\" — persisted alongside sortBy\n// - search: active filter string — persisted so deep links preserve the current search\nconst containersSearchSchema = z.object({\n sortBy: z.enum([\"name\", \"count\", \"bytes\", \"last_modified\"]).optional(),\n sortDirection: z.enum([\"asc\", \"desc\"]).optional(),\n search: z.string().optional(),\n})\n\nexport const Route = createFileRoute(\"/_auth/projects/$projectId/storage/$provider/$storageType/\")({\n staticData: {\n section: \"storage\",\n service: \"containers\",\n analytics: {\n name: \"storage.objectstore.list\",\n },\n } satisfies RouteInfo,\n validateSearch: containersSearchSchema,\n head: ({ match }) => ({\n meta: [\n {\n title:\n match.params.provider === \"swift\"\n ? \"Object Storage (Swift)\"\n : match.params.provider === \"ceph\"\n ? \"Object Storage (Ceph)\"\n : \"Storage Overview\",\n },\n ],\n }),\n component: () => {\n return <StorageDashboard />\n },\n notFoundComponent: () => {\n return <p>Storage service not found</p>\n },\n loader: async ({ context }) => {\n const { trpcClient } = context\n const availableServices = await trpcClient?.auth.getAvailableServices.query()\n\n return {\n client: trpcClient,\n availableServices,\n }\n },\n beforeLoad: async ({ context, params }) => {\n const { trpcClient } = context\n const availableServices = await trpcClient?.auth.getAvailableServices.query()\n checkServiceAvailability(availableServices!, params)\n },\n})\n\nfunction StorageDashboard() {\n const { project, provider } = useParams({\n from: \"/_auth/projects/$projectId/storage/$provider/$storageType/\",\n select: (params) => {\n return { project: params.projectId, provider: params.provider, storageType: params.storageType }\n },\n })\n\n const { t } = useLingui()\n\n let pageTitle: string\n switch (provider) {\n case \"swift\":\n pageTitle = t`Object Storage (Swift)`\n break\n case \"ceph\":\n pageTitle = t`Object Storage (Ceph)`\n break\n default:\n pageTitle = t`Storage Overview`\n }\n\n return (\n <div>\n <ContentHeader title={pageTitle} projectId={project} />\n {project ? (\n <ErrorBoundary\n resetKeys={[project, provider]}\n fallback={\n <div className=\"p-4 text-center\">\n <Trans>Error loading component</Trans>\n </div>\n }\n >\n {(() => {\n switch (provider) {\n case \"swift\":\n return <SwiftContainers />\n case \"ceph\":\n return <CephBuckets />\n default:\n return <div>Storage Overview Page</div> // replace when available\n }\n })()}\n </ErrorBoundary>\n ) : (\n <div className=\"p-4 text-center\">\n <Trans>No project selected</Trans>\n </div>\n )}\n </div>\n )\n}\n","import { redirect } from \"@tanstack/react-router\"\nimport { getServiceIndex } from \"@/server/Authentication/helpers\"\n\ninterface ServiceInfo {\n type: string\n name: string\n}\n\ninterface RouteParams {\n projectId: string\n provider: string\n storageType: string\n containerName: string\n}\n\n/**\n * Validates storage service availability and redirects to appropriate provider/storage type.\n *\n * Redirect logic:\n * 1. If no object-store services available → redirect to project overview\n * 2. If provider is invalid → redirect to fallback provider (swift → ceph)\n * 3. If provider unavailable → redirect to available alternative\n * 4. If storageType doesn't match provider → canonicalize URL\n *\n * @throws redirect - TanStack Router redirect on validation failure\n */\nexport const checkServiceAvailability = (availableServices: ServiceInfo[], params: RouteParams) => {\n const { provider, projectId, storageType, containerName } = params\n\n const serviceIndex = getServiceIndex(availableServices)\n\n // Redirect to the \"Projects Overview\" page if no storage services available\n if (!serviceIndex[\"object-store\"]) {\n throw redirect({\n to: \"/projects/$projectId\",\n params: { projectId },\n })\n }\n\n // Check provider availability\n const hasSwift = Boolean(serviceIndex[\"object-store\"][\"swift\"])\n const hasCeph = Boolean(serviceIndex[\"object-store\"][\"ceph\"])\n\n // TEMPORARY: Allow Ceph access even if not in catalog (relies on env config)\n // TODO: Properly register Ceph in OpenStack service catalog\n const cephFallbackEnabled = true // Set to false once Ceph is in catalog\n\n // Effective availability includes fallback flag for Ceph\n const hasEffectiveCeph = hasCeph || cephFallbackEnabled\n const fallbackProvider = hasSwift ? \"swift\" : hasEffectiveCeph ? \"ceph\" : null\n const fallbackStorageType = hasSwift ? \"containers\" : hasEffectiveCeph ? \"buckets\" : null\n\n if (provider !== \"swift\" && provider !== \"ceph\") {\n if (!fallbackProvider || !fallbackStorageType) {\n throw redirect({\n to: \"/projects/$projectId\",\n params: { projectId },\n })\n }\n throw redirect({\n to: \"/projects/$projectId/storage/$provider/$storageType/$containerName/objects\",\n params: { projectId, provider: fallbackProvider, storageType: fallbackStorageType, containerName },\n })\n }\n\n if (provider === \"swift\" && !hasSwift) {\n if (!hasEffectiveCeph) {\n throw redirect({\n to: \"/projects/$projectId\",\n params: { projectId },\n })\n }\n\n throw redirect({\n to: \"/projects/$projectId/storage/$provider/$storageType/$containerName/objects\",\n params: { projectId, provider: \"ceph\", storageType: \"buckets\", containerName },\n })\n }\n\n if (provider === \"ceph\" && !hasEffectiveCeph) {\n if (!hasSwift) {\n throw redirect({\n to: \"/projects/$projectId\",\n params: { projectId },\n })\n }\n\n throw redirect({\n to: \"/projects/$projectId/storage/$provider/$storageType/$containerName/objects\",\n params: { projectId, provider: \"swift\", storageType: \"containers\", containerName },\n })\n }\n\n // Canonicalize the URL terminology for the resolved provider. Availability is\n // already settled above, so by this point provider is a valid, available\n // swift|ceph. The storageType segment is user-controllable and the router never\n // validates it, so a mismatched noun (e.g. ceph + \"containers\", swift + \"buckets\")\n // must redirect to the canonical path to keep URLs normalized.\n if (provider === \"swift\" || provider === \"ceph\") {\n const expectedStorageType = provider === \"swift\" ? \"containers\" : \"buckets\"\n if (storageType !== expectedStorageType) {\n throw redirect({\n to: \"/projects/$projectId/storage/$provider/$storageType/$containerName/objects\",\n params: { projectId, provider, storageType: expectedStorageType, containerName },\n })\n }\n }\n}\n","/**\n * Swift timestamp helpers.\n *\n * Swift returns `last_modified` in container and object listings as an ISO 8601\n * timestamp that is UTC but carries NO zone designator — e.g.\n * \"2024-03-01T08:00:00.000000\" (see OpenStack Swift bug #1169287: dates in the\n * JSON listings are UTC without a trailing \"Z\"). Per ISO 8601, a date-time with\n * no zone is interpreted as LOCAL time, so `new Date(\"...T08:00:00\")` treats the\n * value as local and the rendered time ends up shifted by the viewer's UTC\n * offset (#1236).\n *\n * These helpers treat a zone-less timestamp as UTC (by appending \"Z\" before\n * parsing) so it converts correctly to the viewer's local time. Timestamps that\n * already carry a zone — a trailing \"Z\" or an explicit ±hh:mm offset, as Ceph\n * returns — are left untouched.\n */\n\n// Matches a zone designator at the end of the string: \"Z\", or an offset like\n// \"+02:00\" / \"-0500\". The date part's own hyphens can't match because of the `$`\n// anchor.\nconst HAS_ZONE = /(Z|[+-]\\d{2}:?\\d{2})$/\n\n/**\n * Parse a Swift timestamp into a Date, treating a zone-less value as UTC.\n * Returns null for empty or unparseable input.\n */\nexport const parseSwiftDate = (value: string | null | undefined): Date | null => {\n if (!value) return null\n const trimmed = value.trim()\n if (!trimmed) return null\n\n // Only a full date-time (has a \"T\") that lacks a zone needs normalizing to\n // UTC. A date-only string (\"2024-03-01\") is already parsed as UTC by the\n // engine, and appending \"Z\" to it would make it invalid.\n const needsUtc = trimmed.includes(\"T\") && !HAS_ZONE.test(trimmed)\n const normalized = needsUtc ? `${trimmed}Z` : trimmed\n\n const date = new Date(normalized)\n return Number.isNaN(date.getTime()) ? null : date\n}\n\n/**\n * Format a Swift timestamp, defaulting to the viewer's local timezone (unless\n * overridden via `options.timeZone`).\n *\n * Returns null for empty/invalid input so callers can supply their own fallback\n * (e.g. a translated \"N/A\"). `locales`/`options` are passed straight through to\n * `Date.prototype.toLocaleString`.\n */\nexport const formatSwiftDate = (\n value: string | null | undefined,\n locales?: Intl.LocalesArgument,\n options?: Intl.DateTimeFormatOptions\n): string | null => {\n const date = parseSwiftDate(value)\n return date ? date.toLocaleString(locales, options) : null\n}\n","import { useCallback, useLayoutEffect, useRef, useState } from \"react\"\n\n/**\n * Fallback for the space below the element, used only when no page footer is\n * found (see `findBottomBoundary`). Roughly the default shell footer's height.\n */\nconst DEFAULT_BOTTOM_GAP = 52\n\n/** Cosmetic breathing room between the element and whatever sits below it. */\nconst GAP = 8\n\n/**\n * The app's own wrapper around the page footer slot (added in the root\n * layout). Deliberately not a component-library class, so the measurement\n * does not break when the shell's internal markup changes.\n */\nconst FOOTER_SELECTOR = \".app-page-footer\"\n\n/**\n * Floor for the measured height: below a few table rows the element is too\n * short to be worth showing. It deliberately wins over fitting the viewport —\n * see the note on the hook.\n */\nconst MIN_HEIGHT = 150\n\n/**\n * The bottom of the space the element may occupy, in viewport coordinates.\n *\n * The shell lays out header, content and footer as a flex column, so the page\n * footer's top edge is exactly where the content area ends — and it moves as\n * the footer's height changes, which a fixed offset cannot follow. The footer\n * is a sibling of the content area, not a descendant of the element, so it is\n * found by querying the document for the app's own footer wrapper rather than\n * walking the element's ancestors.\n *\n * `FOOTER_SELECTOR` targets a wrapper the app controls (added around the footer\n * slot in the root layout), not an internal shell class, so it does not depend\n * on the component library's markup.\n *\n * Falls back to the viewport bottom minus a constant when no footer is present\n * (embedded mode, or a layout without a footer slot).\n *\n * Returned in document coordinates (with `scrollY` added), so the measurement\n * in `useAvailableViewportHeight` is stable regardless of scroll position.\n */\nfunction findBottomBoundary(): number {\n const footer = document.querySelector<HTMLElement>(FOOTER_SELECTOR)\n if (footer) {\n return footer.getBoundingClientRect().top + window.scrollY - GAP\n }\n return window.scrollY + window.innerHeight - DEFAULT_BOTTOM_GAP\n}\n\n/**\n * Measures how much height an element can take without pushing the document\n * past the viewport.\n *\n * Both edges are measured, so nothing above or below the element has to be\n * guessed. The top comes from the element's own position, so a banner in the\n * page banner slot, a wrapped toolbar or a second line of breadcrumbs shrinks\n * the element rather than growing the page. The bottom comes from the page\n * footer (see `findBottomBoundary`), so a custom footer of any height is\n * accounted for too. Either way the element never grows past what is available\n * and produces a second (window) scrollbar.\n *\n * Apply the result as `height`, not `max-height`. With `max-height` the\n * element's size follows its content, and for a virtualized list that closes a\n * loop: measured rows change the total size, which changes the scroll\n * container, which makes the virtualizer recompute its range and measure\n * again. A fixed height keeps the container independent of what is inside it.\n *\n * Returns a callback ref rather than taking a ref object, so the measurement\n * also runs when the element mounts later than the component — e.g. after a\n * loading or empty state that renders no scroll container at all.\n *\n * One case is not covered, on purpose: when less than `MIN_HEIGHT` is\n * available — a very short window, or so much content above the element that\n * little room is left — the result is clamped and the document does scroll\n * after all. An element a row and a half tall is worse than a page scrollbar,\n * so the floor takes precedence over fitting the viewport.\n */\nexport function useAvailableViewportHeight<T extends HTMLElement>() {\n const elementRef = useRef<T | null>(null)\n const [element, setElement] = useState<T | null>(null)\n const [height, setHeight] = useState<number | undefined>(undefined)\n\n // Keeps elementRef usable by imperative consumers (virtualizer, measurements)\n // while element state drives the effect below.\n const ref = useCallback((node: T | null) => {\n elementRef.current = node\n setElement(node)\n }, [])\n\n useLayoutEffect(() => {\n if (!element) return\n\n let frame = 0\n\n const measure = () => {\n // Document coordinates for both edges (getBoundingClientRect is\n // viewport-relative, so add scrollY): the element's top and the top of\n // whatever bounds it from below (the page footer, or the viewport). Using\n // document coordinates keeps the difference stable regardless of scroll.\n const top = element.getBoundingClientRect().top + window.scrollY\n const bottom = findBottomBoundary()\n const available = Math.floor(bottom - top)\n // Clamping here can leave the element taller than the space available,\n // which lets the page scroll. That is the intended trade-off — see above.\n const next = Math.max(MIN_HEIGHT, available)\n // Ignore sub-pixel churn so a re-layout cannot toggle the value forever.\n setHeight((previous) => (previous !== undefined && Math.abs(previous - next) < 1 ? previous : next))\n }\n\n // Observers can fire for several targets within one frame; one measurement\n // per frame is enough and keeps getBoundingClientRect out of the middle of\n // a layout pass, where it forces a synchronous reflow every time.\n const scheduleMeasure = () => {\n if (frame !== 0) return\n frame = requestAnimationFrame(() => {\n frame = 0\n measure()\n })\n }\n\n measure()\n\n // ResizeObserver is an enhancement, not a requirement: where it is missing\n // (jsdom, older environments) the initial measurement and window resizes\n // still work, and the element must never be left unsized.\n const observer = typeof ResizeObserver === \"undefined\" ? null : new ResizeObserver(scheduleMeasure)\n if (observer) {\n observer.observe(document.body)\n // Ancestors too: inside a fixed-height shell the body never changes size,\n // but the container holding the banner does. The element itself is\n // deliberately not observed — its height is ours to set.\n for (let node = element.parentElement; node && node !== document.body; node = node.parentElement) {\n observer.observe(node)\n }\n // The footer bounds the element from below; a change in its height (custom\n // footer content) must trigger a re-measure even though it is not an\n // ancestor of the element.\n const footer = document.querySelector(FOOTER_SELECTOR)\n if (footer) observer.observe(footer)\n }\n\n window.addEventListener(\"resize\", scheduleMeasure)\n return () => {\n if (frame !== 0) cancelAnimationFrame(frame)\n observer?.disconnect()\n window.removeEventListener(\"resize\", scheduleMeasure)\n }\n }, [element])\n\n return { ref, elementRef, height }\n}\n","import { useVirtualizer } from \"@tanstack/react-virtual\"\nimport { useAvailableViewportHeight } from \"./useAvailableViewportHeight\"\n\nconst ROW_HEIGHT = 48\nconst OVERSCAN = 10\n\ninterface UseVirtualizedTableBodyOptions {\n /** Number of rows in the list. */\n count: number\n /** Estimated row height in px. */\n rowHeight?: number\n /** Rows to render beyond the visible range. */\n overscan?: number\n}\n\n/**\n * Everything a virtualized table body needs: a height measured from the space\n * actually left below it, and a virtualizer whose output is withheld until that\n * height is known.\n *\n * The gating is the part worth having in one place. An unsized scroll container\n * measures as tall as its content, so on the first commit the virtualizer would\n * size its range to the whole list and render every row once, before the real\n * height lands. Reading `virtualItems` / `totalSize` from here instead of from\n * the virtualizer directly makes that impossible to forget.\n *\n * Spread `ref` onto the scroll container and apply `height` to it as `height`,\n * not `max-height` — see useAvailableViewportHeight for why.\n */\nexport function useVirtualizedTableBody({\n count,\n rowHeight = ROW_HEIGHT,\n overscan = OVERSCAN,\n}: UseVirtualizedTableBodyOptions) {\n const { ref, elementRef, height } = useAvailableViewportHeight<HTMLDivElement>()\n\n const virtualizer = useVirtualizer({\n count,\n getScrollElement: () => elementRef.current,\n estimateSize: () => rowHeight,\n overscan,\n })\n\n // `undefined` is the only unmeasured state: once measured the height is\n // clamped to a minimum by useAvailableViewportHeight, so it is never 0.\n const isMeasured = height !== undefined\n\n return {\n /** Callback ref for the scroll container. */\n ref,\n /** The same node as a ref object, for imperative reads (scrollbar width). */\n elementRef,\n /** Measured height in px, or undefined until the container has mounted. */\n height,\n /** Empty until the height is known. */\n virtualItems: isMeasured ? virtualizer.getVirtualItems() : [],\n /** Zero until the height is known. */\n totalSize: isMeasured ? virtualizer.getTotalSize() : 0,\n /** Row ref callback for dynamic measurement. */\n measureElement: virtualizer.measureElement,\n }\n}\n","import { useEffect, useRef, useState } from \"react\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport { Modal, Stack, Status, TextInput } from \"@cloudoperators/juno-ui-components\"\nimport { useParams } from \"@tanstack/react-router\"\nimport { FolderRow } from \"./\"\n\ninterface DeleteFolderModalProps {\n isOpen: boolean\n folder: FolderRow | null\n onClose: () => void\n onSuccess?: (folderName: string, deletedCount: number) => void\n onError?: (folderName: string, errorMessage: string) => void\n}\n\n// User must type this word to enable the destructive action.\nconst CONFIRM_WORD = \"delete\"\n\nexport const DeleteFolderModal = ({ isOpen, folder, onClose, onSuccess, onError }: DeleteFolderModalProps) => {\n const { t } = useLingui()\n const projectId = useProjectId()\n const { containerName } = useParams({\n from: \"/_auth/projects/$projectId/storage/$provider/$storageType/$containerName/objects/\",\n })\n\n const utils = trpcReact.useUtils()\n\n // useRef so the folder display name survives re-renders triggered by\n // deleteFolderMutation.reset() inside handleClose() before onSuccess/onError fire.\n const submittedFolderNameRef = useRef(\"\")\n\n // Type-to-confirm guard. Deleting a folder destroys every object inside it,\n // so a single click is not enough — the user must type CONFIRM_WORD first.\n const [confirmValue, setConfirmValue] = useState(\"\")\n const isConfirmed = confirmValue.trim() === CONFIRM_WORD\n\n const deleteFolderMutation = trpcReact.storage.swift.deleteFolder.useMutation({\n onSuccess: (deletedCount) => {\n utils.storage.swift.listObjects.invalidate({ project_id: projectId, container: containerName })\n onSuccess?.(submittedFolderNameRef.current, deletedCount)\n },\n onError: (error) => {\n onError?.(submittedFolderNameRef.current, error.message)\n },\n onSettled: () => {\n handleClose()\n },\n })\n\n useEffect(() => {\n if (!isOpen) {\n deleteFolderMutation.reset()\n setConfirmValue(\"\")\n }\n }, [isOpen])\n\n const handleClose = () => {\n deleteFolderMutation.reset()\n setConfirmValue(\"\")\n onClose()\n }\n\n const handleConfirm = () => {\n if (!folder || !isConfirmed) return\n submittedFolderNameRef.current = folder.displayName\n deleteFolderMutation.mutate({\n project_id: projectId,\n container: containerName,\n folderPath: folder.name,\n recursive: true,\n })\n }\n\n if (!isOpen || !folder) return null\n\n const folderDisplayName = folder.displayName\n\n return (\n <Modal\n title={\n <span className=\"flex max-w-100 items-center gap-1\">\n <span className=\"shrink-0\">\n <Trans>Delete folder:</Trans>\n </span>\n <span className=\"truncate\" title={folderDisplayName}>\n {folderDisplayName}\n </span>\n </span>\n }\n open={isOpen}\n onCancel={handleClose}\n confirmButtonLabel={deleteFolderMutation.isPending ? t`Deleting...` : t`Delete`}\n confirmButtonVariant=\"primary-danger\"\n onConfirm={handleConfirm}\n cancelButtonLabel={t`Cancel`}\n size=\"small\"\n disableConfirmButton={deleteFolderMutation.isPending || !isConfirmed}\n disableCancelButton={deleteFolderMutation.isPending}\n disableCloseButton={deleteFolderMutation.isPending}\n >\n {deleteFolderMutation.isPending ? (\n <Status status=\"progress\" title={t`Deleting Folder and All Its Contents...`} className=\"mt-0\" />\n ) : (\n <Stack direction=\"vertical\" gap=\"4\">\n <p className=\"text-theme-default\">\n <Trans>\n Folder <span className=\"font-semibold\">\"{folderDisplayName}\"</span> and all objects within it will be\n permanently deleted. This cannot be undone.\n </Trans>\n </p>\n <p className=\"text-theme-default\">\n <Trans>\n Note: for <strong>static and dynamic large objects</strong> only the manifests are deleted — their\n segments outside this folder prefix are not affected.\n </Trans>\n </p>\n <TextInput\n label={t`Type \"${CONFIRM_WORD}\" to confirm`}\n placeholder={CONFIRM_WORD}\n value={confirmValue}\n onChange={(event) => setConfirmValue(event.target.value)}\n />\n </Stack>\n )}\n </Modal>\n )\n}\n","import { z } from \"zod\"\nimport { useForm, useStore } from \"@tanstack/react-form\"\nimport { useEffect, useRef, useState } from \"react\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport { Modal, Stack, Status, Checkbox, Form, FormSection, TextInput } from \"@cloudoperators/juno-ui-components\"\nimport { useParams } from \"@tanstack/react-router\"\nimport { ObjectRow } from \"./\"\n\nexport type DeleteObjectVariant = \"delete\"\n\ninterface DeleteObjectModalProps {\n isOpen: boolean\n object: ObjectRow | null\n onClose: () => void\n onSuccess?: (objectName: string) => void\n onError?: (objectName: string, errorMessage: string) => void\n}\n\nexport const DeleteObjectModal = ({ isOpen, object, onClose, onSuccess, onError }: DeleteObjectModalProps) => {\n const { t } = useLingui()\n const projectId = useProjectId()\n const { containerName } = useParams({\n from: \"/_auth/projects/$projectId/storage/$provider/$storageType/$containerName/objects/\",\n })\n\n const utils = trpcReact.useUtils()\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 (deleteObjectMutation.isPending || !object) return\n\n displayNameRef.current = object.displayName\n deleteObjectMutation.mutate({\n project_id: projectId,\n container: containerName,\n object: object.name,\n ...(isSLO && !keepSegments ? { multipartManifest: \"delete\" as const } : {}),\n })\n },\n })\n\n const canDelete = useStore(form.store, (state) => state.isSubmitting || state.values.confirm !== \"delete\")\n\n // keepSegments is only relevant for SLOs — toggled by a checkbox in the modal.\n const [keepSegments, setKeepSegments] = useState(false)\n\n // useRef so the object display name survives re-renders triggered by\n // deleteObjectMutation.reset() inside handleClose() before onSuccess/onError fire.\n const displayNameRef = useRef(\"\")\n\n // ── Metadata fetch ────────────────────────────────────────────────────────\n // Fetch object metadata on open to detect SLO/DLO — determines whether\n // multipartManifest=\"delete\" should be sent in the DELETE request.\n //\n // SLO: X-Static-Large-Object: True → staticLargeObject === true\n // DLO: X-Object-Manifest: <prefix> → objectManifest is set\n const {\n data: metadata,\n isLoading: isLoadingMetadata,\n error: metadataError,\n } = trpcReact.storage.swift.getObjectMetadata.useQuery(\n { project_id: projectId, container: containerName, object: object?.name ?? \"\" },\n { enabled: isOpen && object !== null }\n )\n\n const isSLO = metadata?.staticLargeObject === true\n const isDLO = !!metadata?.objectManifest\n\n const deleteObjectMutation = trpcReact.storage.swift.deleteObject.useMutation({\n onSuccess: () => {\n utils.storage.swift.listObjects.invalidate({ project_id: projectId, container: containerName })\n onSuccess?.(displayNameRef.current)\n },\n onError: (error) => {\n onError?.(displayNameRef.current, error.message)\n },\n onSettled: () => {\n handleClose()\n },\n })\n\n useEffect(() => {\n if (!isOpen) {\n deleteObjectMutation.reset()\n setKeepSegments(false)\n form.reset()\n }\n }, [isOpen])\n\n const handleClose = () => {\n deleteObjectMutation.reset()\n onClose()\n }\n\n if (!isOpen || !object) return null\n\n const displayName = object.displayName\n const isLoading = isLoadingMetadata\n const isPending = deleteObjectMutation.isPending\n const metadataErrorMessage = metadataError?.message ?? \"\"\n\n return (\n <Modal\n title={\n <span className=\"flex max-w-100 items-center gap-1\">\n <span className=\"shrink-0\">\n <Trans>Delete object:</Trans>\n </span>\n <span className=\"truncate\" title={displayName}>\n {displayName}\n </span>\n </span>\n }\n open={isOpen}\n onCancel={handleClose}\n confirmButtonLabel={isPending ? t`Deleting...` : t`Delete Object`}\n confirmButtonVariant=\"primary-danger\"\n onConfirm={form.handleSubmit}\n cancelButtonLabel={t`Cancel`}\n size=\"small\"\n disableConfirmButton={isLoading || isPending || !!metadataError || canDelete}\n >\n {isPending ? (\n <Status status=\"progress\" title={t`Deleting...`} className=\"mt-0\" />\n ) : isLoading ? (\n <Status status=\"progress\" title={t`Loading Object Info...`} className=\"mt-0\" />\n ) : metadataError ? (\n <Status status=\"error\" title={t`Failed to Load Object Metadata`} body={metadataErrorMessage} className=\"mt-0\" />\n ) : (\n <Stack direction=\"vertical\" gap=\"4\">\n <p className=\"text-theme-default\">\n <Trans>\n Object <span className=\"font-semibold\">\"{displayName}\"</span> will be permanently deleted. This cannot be\n undone.\n </Trans>\n </p>\n {isSLO && (\n <>\n <p className=\"text-theme-default\">\n <Trans>\n This is a <strong>static large object</strong>. By default, all associated segment objects will also\n be permanently deleted.\n </Trans>\n </p>\n <Checkbox\n label={t`Keep segments (delete manifest only)`}\n checked={keepSegments}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) => setKeepSegments(e.target.checked)}\n />\n </>\n )}\n {isDLO && (\n <p className=\"text-theme-default\">\n <Trans>\n This is a <strong>dynamic large object</strong>. Only the manifest will be deleted — its segment objects\n (stored under the manifest prefix) are <strong>not</strong> automatically removed and must be deleted\n separately.\n </Trans>\n </p>\n )}\n <Form\n className=\"mb-0\"\n id=\"delete-object-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 id={field.name}\n name={field.name}\n label={t`Type \"delete\" to confirm`}\n value={field.state.value}\n onChange={(e) => field.handleChange(e.target.value)}\n placeholder=\"delete\"\n autoFocus\n disabled={isPending}\n required\n />\n )}\n />\n </FormSection>\n </Form>\n </Stack>\n )}\n </Modal>\n )\n}\n","import { useState, useRef, useEffect, useCallback } from \"react\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport {\n Modal,\n Stack,\n Status,\n Spinner,\n ComboBox,\n ComboBoxOption,\n TextInput,\n Button,\n} from \"@cloudoperators/juno-ui-components\"\nimport { useParams } from \"@tanstack/react-router\"\nimport { MdFolder, MdDescription, MdCreateNewFolder, MdArrowBack } from \"react-icons/md\"\nimport { useVirtualizer } from \"@tanstack/react-virtual\"\nimport { ObjectRow, buildRows, BrowserRow } from \"./\"\nimport { ObjectSummary } from \"@/server/Storage/types/swift\"\n\nconst MAX_COMBO_OPTIONS = 50\n\ninterface CopyObjectModalProps {\n isOpen: boolean\n object: ObjectRow | null\n onClose: () => void\n onSuccess?: (objectName: string, targetContainer: string, targetPath: string) => void\n onError?: (objectName: string, errorMessage: string) => void\n}\n\nexport const CopyObjectModal = ({ isOpen, object, onClose, onSuccess, onError }: CopyObjectModalProps) => {\n const { t } = useLingui()\n const projectId = useProjectId()\n const { containerName: sourceContainer } = useParams({\n from: \"/_auth/projects/$projectId/storage/$provider/$storageType/$containerName/objects/\",\n })\n\n const utils = trpcReact.useUtils()\n const submittedNameRef = useRef(\"\")\n\n // ── State ─────────────────────────────────────────────────────────────────\n const [targetContainer, setTargetContainer] = useState(sourceContainer)\n const [currentPrefix, setCurrentPrefix] = useState(\"\")\n // Locally created folders — keyed by container, stored as full prefix paths.\n // These are merged into the fetched object list so newly created folders\n // appear immediately without waiting for a server refetch.\n const [localFolders, setLocalFolders] = useState<Record<string, string[]>>({})\n const [newFolderName, setNewFolderName] = useState(\"\")\n const [newFolderError, setNewFolderError] = useState<string | null>(null)\n const [showNewFolderInput, setShowNewFolderInput] = useState(false)\n const [copyMetadata, setCopyMetadata] = useState(true)\n const [containerSearch, setContainerSearch] = useState(\"\")\n const [debouncedSearch, setDebouncedSearch] = useState(\"\")\n const debounceTimer = useRef<ReturnType<typeof setTimeout> | null>(null)\n const listRef = useRef<HTMLDivElement>(null)\n\n // Clear pending debounce timer on unmount to prevent state updates after unmount\n useEffect(\n () => () => {\n if (debounceTimer.current) clearTimeout(debounceTimer.current)\n },\n []\n )\n\n // Reset browser state when modal opens or target container changes\n useEffect(() => {\n if (isOpen) {\n setCurrentPrefix(\"\")\n setLocalFolders((prev) => {\n const next = { ...prev }\n delete next[targetContainer]\n return next\n })\n setNewFolderName(\"\")\n setNewFolderError(null)\n setShowNewFolderInput(false)\n setContainerSearch(\"\")\n setDebouncedSearch(\"\")\n }\n }, [isOpen, targetContainer])\n\n useEffect(() => {\n if (!isOpen) {\n setTargetContainer(sourceContainer)\n setCurrentPrefix(\"\")\n setLocalFolders({})\n setNewFolderName(\"\")\n setNewFolderError(null)\n setShowNewFolderInput(false)\n setContainerSearch(\"\")\n setDebouncedSearch(\"\")\n }\n }, [isOpen, sourceContainer])\n\n // ── Data fetching ─────────────────────────────────────────────────────────\n\n const { data: containers, isLoading: isLoadingContainers } = trpcReact.storage.swift.listContainers.useQuery(\n { project_id: projectId },\n { enabled: isOpen }\n )\n\n const { data: objects, isLoading: isLoadingObjects } = trpcReact.storage.swift.listObjects.useQuery(\n { project_id: projectId, container: targetContainer, format: \"json\", prefix: currentPrefix || undefined },\n { enabled: isOpen && !!targetContainer }\n )\n\n // ── Rows: merge server data with locally created folders ──────────────────\n\n const serverRows = buildRows((objects ?? []) as ObjectSummary[], currentPrefix)\n const containerLocalFolders = localFolders[targetContainer] ?? []\n // Inject locally created folders that are at the current prefix level\n // and not yet reflected in the server response\n const localFolderRows: BrowserRow[] = containerLocalFolders\n .filter((fp) => {\n // fp is a full path like \"prefix/newfolder/\"\n // show it only if its parent prefix matches currentPrefix\n const withoutPrefix = fp.startsWith(currentPrefix) ? fp.slice(currentPrefix.length) : null\n if (!withoutPrefix) return false\n // At this level means only one segment left (e.g. \"newfolder/\")\n const parts = withoutPrefix.split(\"/\").filter(Boolean)\n return parts.length === 1\n })\n .filter((fp) => !serverRows.some((r) => r.name === fp))\n .map((fp) => ({\n kind: \"folder\" as const,\n name: fp,\n displayName: fp.slice(currentPrefix.length).replace(/\\/$/, \"\"),\n }))\n\n const rows: BrowserRow[] = [\n ...serverRows.filter((r) => r.kind === \"folder\"),\n ...localFolderRows,\n ...serverRows.filter((r) => r.kind === \"object\"),\n ]\n\n const filteredContainers =\n debouncedSearch.trim().length > 0\n ? (containers ?? []).filter((c) => c.name.toLowerCase().includes(debouncedSearch.toLowerCase()))\n : []\n\n const visibleContainers = filteredContainers.slice(0, MAX_COMBO_OPTIONS)\n const hiddenCount = filteredContainers.length - visibleContainers.length\n\n // ── Copy mutation ─────────────────────────────────────────────────────────\n\n const copyMutation = trpcReact.storage.swift.copyObject.useMutation({\n onSuccess: () => {\n utils.storage.swift.listObjects.invalidate({ project_id: projectId, container: targetContainer })\n onSuccess?.(submittedNameRef.current, targetContainer, currentPrefix)\n handleClose()\n },\n onError: (error) => {\n onError?.(submittedNameRef.current, error.message)\n },\n })\n\n // ── Handlers ──────────────────────────────────────────────────────────────\n\n const handleClose = () => {\n copyMutation.reset()\n onClose()\n }\n\n const handleContainerSearch = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {\n const value = e.target.value\n setContainerSearch(value)\n if (debounceTimer.current) clearTimeout(debounceTimer.current)\n debounceTimer.current = setTimeout(() => setDebouncedSearch(value), 300)\n }, [])\n\n const handleContainerChange = (value?: string | number | string[] | undefined) => {\n const v = Array.isArray(value) ? value[0] : typeof value === \"number\" ? String(value) : value\n if (v) {\n setTargetContainer(v)\n setCurrentPrefix(\"\")\n }\n }\n\n const handleFolderClick = (folderName: string) => {\n setCurrentPrefix(folderName)\n setShowNewFolderInput(false)\n setNewFolderName(\"\")\n setNewFolderError(null)\n }\n\n const handleNavigateUp = () => {\n if (!currentPrefix) return\n // Remove the last segment from the prefix\n const parts = currentPrefix.replace(/\\/$/, \"\").split(\"/\")\n parts.pop()\n setCurrentPrefix(parts.length > 0 ? parts.join(\"/\") + \"/\" : \"\")\n setShowNewFolderInput(false)\n setNewFolderName(\"\")\n setNewFolderError(null)\n }\n\n const validateNewFolderName = useCallback(\n (name: string): boolean => {\n const trimmed = name.trim()\n if (!trimmed) {\n setNewFolderError(t`Folder name is required`)\n return false\n }\n if (trimmed.includes(\"/\")) {\n setNewFolderError(t`Folder name cannot contain slashes`)\n return false\n }\n if (trimmed !== name) {\n setNewFolderError(t`Folder name cannot have leading or trailing whitespace`)\n return false\n }\n // Check duplicate against existing rows\n const newPath = `${currentPrefix}${trimmed}/`\n if (rows.some((r) => r.name === newPath)) {\n setNewFolderError(t`A folder with this name already exists`)\n return false\n }\n setNewFolderError(null)\n return true\n },\n [rows, currentPrefix, t]\n )\n\n const handleCreateFolder = () => {\n if (!validateNewFolderName(newFolderName)) return\n const trimmed = newFolderName.trim()\n const newPath = `${currentPrefix}${trimmed}/`\n setLocalFolders((prev) => ({\n ...prev,\n [targetContainer]: [...(prev[targetContainer] ?? []), newPath],\n }))\n setNewFolderName(\"\")\n setShowNewFolderInput(false)\n setNewFolderError(null)\n // Navigate into the newly created folder\n setCurrentPrefix(newPath)\n }\n\n const handleNewFolderKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === \"Enter\") handleCreateFolder()\n if (e.key === \"Escape\") {\n setShowNewFolderInput(false)\n setNewFolderName(\"\")\n setNewFolderError(null)\n }\n }\n\n const handleCopy = () => {\n if (!object) return\n submittedNameRef.current = object.displayName\n // destination format: \"/targetContainer/prefix/filename\" (plain text)\n // Encoding is handled in the router to avoid double-encoding.\n const destPath = `/${targetContainer}/${currentPrefix}${object.displayName}`\n copyMutation.mutate({\n project_id: projectId,\n container: sourceContainer,\n object: object.name,\n destination: destPath,\n freshMetadata: !copyMetadata,\n })\n }\n\n // ── Virtualized folder browser ─────────────────────────────────────────────\n // Must be declared before the early return to satisfy Rules of Hooks.\n const folderRows = rows.filter((r) => r.kind === \"folder\")\n // Files are kept in `rows` for folder-name duplicate detection but are not\n // rendered in the destination picker — only folders are valid destinations.\n const allBrowserRows = folderRows\n\n const rowVirtualizer = useVirtualizer({\n count: allBrowserRows.length,\n getScrollElement: () => listRef.current,\n estimateSize: () => 32,\n overscan: 5,\n })\n\n if (!isOpen || !object) return null\n\n const displayName = object.displayName\n const isPending = copyMutation.isPending\n const isLoading = isLoadingObjects\n\n // ── Read-only target path field value ─────────────────────────────────────\n const targetPathDisplay = `/${targetContainer}/${currentPrefix}${displayName}`\n\n // The initial prefix is the folder the source object lives in —\n // strip the displayName from the end of the full object name to get it.\n const initialPrefix = object.name.endsWith(object.displayName)\n ? object.name.slice(0, object.name.length - object.displayName.length)\n : \"\"\n\n // Disable submit when the destination is identical to the source location —\n // copying an object on top of itself is a no-op and would overwrite metadata.\n const isUnchanged = targetContainer === sourceContainer && currentPrefix === initialPrefix\n\n return (\n <Modal\n title={\n <span className=\"flex max-w-125 items-center gap-1\">\n <span className=\"shrink-0\">\n <Trans>Copy Object:</Trans>\n </span>\n <span className=\"truncate\" title={displayName}>\n {displayName}\n </span>\n </span>\n }\n open={isOpen}\n onCancel={handleClose}\n confirmButtonLabel={isPending ? t`Copying...` : t`Copy Object`}\n onConfirm={handleCopy}\n cancelButtonLabel={t`Cancel`}\n size=\"large\"\n disableConfirmButton={isPending || isLoadingContainers || isUnchanged}\n disableCancelButton={isPending || isLoadingContainers}\n disableCloseButton={isPending || isLoadingContainers || isUnchanged}\n >\n {isPending ? (\n <Status status=\"progress\" title={t`Copying Object...`} className=\"mt-0\" />\n ) : (\n <Stack direction=\"vertical\" gap=\"4\">\n {copyMutation.isError &&\n (() => {\n const errorMessage = copyMutation.error.message\n return (\n <p className=\"text-theme-error text-sm\">\n <Trans>Failed to copy object: {errorMessage}</Trans>\n </p>\n )\n })()}\n\n {/* Target container — ComboBox with debounced search to handle large lists */}\n <ComboBox\n label={t`Target container`}\n value={targetContainer}\n onChange={handleContainerChange}\n onInputChange={handleContainerSearch}\n placeholder={t`Type to search containers...`}\n helptext={(() => {\n if (isLoadingContainers) return t`Loading Containers...`\n if (containerSearch.trim().length === 0) return t`Start typing to search for a container`\n if (hiddenCount > 0) {\n const maxOptions = MAX_COMBO_OPTIONS\n const totalCount = filteredContainers.length\n return t`Showing first ${maxOptions} of ${totalCount} — refine your search to narrow results`\n }\n return undefined\n })()}\n disabled={isLoadingContainers || isPending}\n required\n >\n {visibleContainers.map((c) => (\n <ComboBoxOption key={c.name} value={c.name}>\n {c.name}\n </ComboBoxOption>\n ))}\n </ComboBox>\n\n {/* Folder browser */}\n <div>\n <div className=\"mb-1 flex items-center justify-between\">\n <span className=\"text-sm font-medium\">\n <Trans>Select destination folder</Trans>\n </span>\n <Button\n size=\"small\"\n variant=\"subdued\"\n icon=\"addCircle\"\n onClick={() => {\n setShowNewFolderInput(true)\n setNewFolderName(\"\")\n setNewFolderError(null)\n }}\n disabled={isPending}\n title={t`Create new folder here`}\n >\n <Trans>New Folder</Trans>\n </Button>\n </div>\n\n {/* Breadcrumb / back navigation */}\n <div className=\"border-theme-background-lvl-2 bg-theme-background-lvl-1 flex items-center gap-2 border-b px-3 py-2 text-sm\">\n {currentPrefix ? (\n <button\n type=\"button\"\n onClick={handleNavigateUp}\n className=\"text-theme-link hover:text-theme-default flex items-center gap-1\"\n >\n <MdArrowBack size={16} />\n <Trans>Back</Trans>\n </button>\n ) : (\n <span className=\"text-theme-light\">\n <Trans>Root</Trans>\n </span>\n )}\n {currentPrefix && (\n <span className=\"text-theme-light truncate text-sm\" data-testid=\"breadcrumb-prefix\">\n / {currentPrefix}\n </span>\n )}\n </div>\n\n {/* Object browser list */}\n <div ref={listRef} className=\"border-theme-background-lvl-2 max-h-56 overflow-y-auto rounded-b border\">\n {isLoading ? (\n <Stack direction=\"horizontal\" alignment=\"center\" gap=\"2\" className=\"py-6\">\n <Spinner size=\"small\" />\n <Trans>Loading...</Trans>\n </Stack>\n ) : allBrowserRows.length === 0 && !showNewFolderInput ? (\n <div className=\"text-theme-light px-4 py-6 text-center text-sm\">\n <Trans>This folder is empty — use New Folder to create one.</Trans>\n </div>\n ) : (\n <div style={{ height: `${rowVirtualizer.getTotalSize()}px`, position: \"relative\" }}>\n {rowVirtualizer.getVirtualItems().map((virtualRow) => {\n const row = allBrowserRows[virtualRow.index]\n const isFolder = row.kind === \"folder\"\n return (\n <div\n key={row.name}\n data-index={virtualRow.index}\n ref={rowVirtualizer.measureElement}\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n width: \"100%\",\n transform: `translateY(${virtualRow.start}px)`,\n }}\n >\n {isFolder ? (\n <button\n type=\"button\"\n className=\"hover:bg-theme-background-lvl-2 focus-visible:outline-theme-focus flex w-full items-center gap-2 px-4 py-2 text-left text-sm focus-visible:outline-2\"\n onClick={() => handleFolderClick(row.name)}\n >\n <MdFolder size={16} className=\"text-theme-light shrink-0\" />\n <span className=\"truncate\">{row.displayName}</span>\n </button>\n ) : (\n /* Files shown as non-clickable, dimmed — for context only */\n <span className=\"text-theme-light flex items-center gap-2 px-4 py-2 text-sm\">\n <MdDescription size={16} className=\"shrink-0\" />\n <span className=\"truncate\">{row.displayName}</span>\n </span>\n )}\n </div>\n )\n })}\n </div>\n )}\n\n {/* Inline new folder input */}\n {showNewFolderInput && (\n <div className=\"border-theme-background-lvl-2 border-t px-4 py-3\">\n <Stack direction=\"vertical\" gap=\"2\">\n <Stack direction=\"horizontal\" gap=\"2\" alignment=\"center\">\n <MdCreateNewFolder size={16} className=\"text-theme-light shrink-0\" />\n <TextInput\n value={newFolderName}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) => {\n setNewFolderName(e.target.value)\n // Clear error on change but don't re-validate on every keystroke\n if (newFolderError) setNewFolderError(null)\n }}\n onKeyDown={handleNewFolderKeyDown}\n placeholder={t`Folder name`}\n invalid={!!newFolderError}\n errortext={newFolderError ?? undefined}\n autoFocus\n className=\"flex-1\"\n />\n <Button\n size=\"small\"\n variant=\"subdued\"\n onClick={() => {\n setShowNewFolderInput(false)\n setNewFolderName(\"\")\n setNewFolderError(null)\n }}\n >\n <Trans>Discard</Trans>\n </Button>\n <Button\n size=\"small\"\n variant=\"primary\"\n onClick={handleCreateFolder}\n disabled={!newFolderName.trim()}\n >\n <Trans>Create</Trans>\n </Button>\n </Stack>\n </Stack>\n </div>\n )}\n </div>\n </div>\n\n {/* Read-only target path */}\n <div>\n <p className=\"mb-1\">\n <Trans>The object will be copied to this path. Navigate folders above to change the destination.</Trans>\n </p>\n <p className=\"text-sm\">{targetPathDisplay}</p>\n </div>\n\n {/* Copy metadata checkbox */}\n <label className=\"flex cursor-pointer items-center gap-2\">\n <input\n type=\"checkbox\"\n checked={copyMetadata}\n onChange={(e) => setCopyMetadata(e.target.checked)}\n className=\"h-4 w-4\"\n />\n <span className=\"text-sm\">\n <Trans>Copy metadata</Trans>\n </span>\n </label>\n </Stack>\n )}\n </Modal>\n )\n}\n","import { useState, useRef, useEffect, useCallback } from \"react\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport {\n Modal,\n Stack,\n Status,\n Spinner,\n ComboBox,\n ComboBoxOption,\n TextInput,\n Button,\n} from \"@cloudoperators/juno-ui-components\"\nimport { useParams } from \"@tanstack/react-router\"\nimport { MdFolder, MdDescription, MdCreateNewFolder, MdArrowBack } from \"react-icons/md\"\nimport { useVirtualizer } from \"@tanstack/react-virtual\"\nimport { ObjectRow, buildRows, BrowserRow } from \"./\"\nimport { ObjectSummary } from \"@/server/Storage/types/swift\"\n\nconst MAX_COMBO_OPTIONS = 50\n\ninterface MoveRenameObjectModalProps {\n isOpen: boolean\n object: ObjectRow | null\n onClose: () => void\n onSuccess?: (objectName: string, targetContainer: string, targetPath: string) => void\n onError?: (objectName: string, errorMessage: string) => void\n}\n\nexport const MoveRenameObjectModal = ({ isOpen, object, onClose, onSuccess, onError }: MoveRenameObjectModalProps) => {\n const { t } = useLingui()\n const projectId = useProjectId()\n const { containerName: sourceContainer } = useParams({\n from: \"/_auth/projects/$projectId/storage/$provider/$storageType/$containerName/objects/\",\n })\n\n const utils = trpcReact.useUtils()\n const submittedNameRef = useRef(\"\")\n\n // ── State ──────────────────────────────────────────────────────────────────\n const [targetContainer, setTargetContainer] = useState(sourceContainer)\n const [currentPrefix, setCurrentPrefix] = useState(\"\")\n const [newObjectName, setNewObjectName] = useState(\"\")\n const [newObjectNameError, setNewObjectNameError] = useState<string | null>(null)\n // Locally created folders — keyed by container, stored as full prefix paths.\n const [localFolders, setLocalFolders] = useState<Record<string, string[]>>({})\n const [newFolderName, setNewFolderName] = useState(\"\")\n const [newFolderError, setNewFolderError] = useState<string | null>(null)\n const [showNewFolderInput, setShowNewFolderInput] = useState(false)\n const [containerSearch, setContainerSearch] = useState(\"\")\n const [debouncedSearch, setDebouncedSearch] = useState(\"\")\n const debounceTimer = useRef<ReturnType<typeof setTimeout> | null>(null)\n const listRef = useRef<HTMLDivElement>(null)\n\n // Clear pending debounce timer on unmount to prevent state updates after unmount\n useEffect(\n () => () => {\n if (debounceTimer.current) clearTimeout(debounceTimer.current)\n },\n []\n )\n\n // Reset state when modal opens or target container changes\n useEffect(() => {\n if (isOpen) {\n setCurrentPrefix(\"\")\n setLocalFolders((prev) => {\n const next = { ...prev }\n delete next[targetContainer]\n return next\n })\n setNewFolderName(\"\")\n setNewFolderError(null)\n setShowNewFolderInput(false)\n setContainerSearch(\"\")\n setDebouncedSearch(\"\")\n setNewObjectNameError(null)\n }\n }, [isOpen, targetContainer])\n\n // Reset name field when object changes (modal reopened for a different object)\n useEffect(() => {\n if (isOpen && object) {\n setNewObjectName(object.displayName)\n }\n }, [isOpen, object])\n\n useEffect(() => {\n if (!isOpen) {\n setTargetContainer(sourceContainer)\n setCurrentPrefix(\"\")\n setLocalFolders({})\n setNewFolderName(\"\")\n setNewFolderError(null)\n setShowNewFolderInput(false)\n setContainerSearch(\"\")\n setDebouncedSearch(\"\")\n setNewObjectName(\"\")\n setNewObjectNameError(null)\n }\n }, [isOpen, sourceContainer])\n\n // ── Data fetching ──────────────────────────────────────────────────────────\n\n const { data: containers, isLoading: isLoadingContainers } = trpcReact.storage.swift.listContainers.useQuery(\n { project_id: projectId },\n { enabled: isOpen }\n )\n\n const { data: objects, isLoading: isLoadingObjects } = trpcReact.storage.swift.listObjects.useQuery(\n { project_id: projectId, container: targetContainer, format: \"json\", prefix: currentPrefix || undefined },\n { enabled: isOpen && !!targetContainer }\n )\n\n // ── Rows: merge server data with locally created folders ───────────────────\n\n const serverRows = buildRows((objects ?? []) as ObjectSummary[], currentPrefix)\n const containerLocalFolders = localFolders[targetContainer] ?? []\n const localFolderRows: BrowserRow[] = containerLocalFolders\n .filter((fp) => {\n const withoutPrefix = fp.startsWith(currentPrefix) ? fp.slice(currentPrefix.length) : null\n if (!withoutPrefix) return false\n const parts = withoutPrefix.split(\"/\").filter(Boolean)\n return parts.length === 1\n })\n .filter((fp) => !serverRows.some((r) => r.name === fp))\n .map((fp) => ({\n kind: \"folder\" as const,\n name: fp,\n displayName: fp.slice(currentPrefix.length).replace(/\\/$/, \"\"),\n }))\n\n const rows: BrowserRow[] = [\n ...serverRows.filter((r) => r.kind === \"folder\"),\n ...localFolderRows,\n ...serverRows.filter((r) => r.kind === \"object\"),\n ]\n\n const filteredContainers =\n debouncedSearch.trim().length > 0\n ? (containers ?? []).filter((c) => c.name.toLowerCase().includes(debouncedSearch.toLowerCase()))\n : []\n\n const visibleContainers = filteredContainers.slice(0, MAX_COMBO_OPTIONS)\n const hiddenCount = filteredContainers.length - visibleContainers.length\n\n // ── Move = copy + delete ───────────────────────────────────────────────────\n // Swift has no native move. We copy to the destination then delete the source.\n // Both mutations are chained: delete fires in copyMutation.onSuccess.\n\n const deleteMutation = trpcReact.storage.swift.deleteObject.useMutation({\n onSuccess: () => {\n // Invalidate only the two affected containers (source and destination)\n const containersToInvalidate = [...new Set([sourceContainer, targetContainer])]\n containersToInvalidate.forEach((container) =>\n utils.storage.swift.listObjects.invalidate({ project_id: projectId, container })\n )\n onSuccess?.(submittedNameRef.current, targetContainer, currentPrefix)\n },\n onError: (error) => {\n // Copy succeeded but delete failed — report as move error so the user\n // knows the source object still exists.\n onError?.(submittedNameRef.current, error.message)\n },\n onSettled: () => {\n handleClose()\n },\n })\n\n const copyMutation = trpcReact.storage.swift.copyObject.useMutation({\n onSuccess: () => {\n if (!object) return\n // Copy succeeded — now delete the source to complete the move.\n deleteMutation.mutate({\n project_id: projectId,\n container: sourceContainer,\n object: object.name,\n })\n },\n onError: (error) => {\n onError?.(submittedNameRef.current, error.message)\n handleClose()\n },\n })\n\n // ── Handlers ───────────────────────────────────────────────────────────────\n\n const handleClose = () => {\n copyMutation.reset()\n deleteMutation.reset()\n onClose()\n }\n\n const handleContainerSearch = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {\n const value = e.target.value\n setContainerSearch(value)\n if (debounceTimer.current) clearTimeout(debounceTimer.current)\n debounceTimer.current = setTimeout(() => setDebouncedSearch(value), 300)\n }, [])\n\n const handleContainerChange = (value?: string | number | string[] | undefined) => {\n const v = Array.isArray(value) ? value[0] : typeof value === \"number\" ? String(value) : value\n if (v) {\n setTargetContainer(v)\n setCurrentPrefix(\"\")\n }\n }\n\n const handleFolderClick = (folderName: string) => {\n setCurrentPrefix(folderName)\n setShowNewFolderInput(false)\n setNewFolderName(\"\")\n setNewFolderError(null)\n }\n\n const handleNavigateUp = () => {\n if (!currentPrefix) return\n const parts = currentPrefix.replace(/\\/$/, \"\").split(\"/\")\n parts.pop()\n setCurrentPrefix(parts.length > 0 ? parts.join(\"/\") + \"/\" : \"\")\n setShowNewFolderInput(false)\n setNewFolderName(\"\")\n setNewFolderError(null)\n }\n\n const validateNewFolderName = useCallback(\n (name: string): boolean => {\n const trimmed = name.trim()\n if (!trimmed) {\n setNewFolderError(t`Folder name is required`)\n return false\n }\n if (trimmed.includes(\"/\")) {\n setNewFolderError(t`Folder name cannot contain slashes`)\n return false\n }\n if (trimmed !== name) {\n setNewFolderError(t`Folder name cannot have leading or trailing whitespace`)\n return false\n }\n const newPath = `${currentPrefix}${trimmed}/`\n if (rows.some((r) => r.name === newPath)) {\n setNewFolderError(t`A folder with this name already exists`)\n return false\n }\n setNewFolderError(null)\n return true\n },\n [rows, currentPrefix, t]\n )\n\n const validateObjectName = useCallback(\n (name: string): boolean => {\n const trimmed = name.trim()\n if (!trimmed) {\n setNewObjectNameError(t`Object name is required`)\n return false\n }\n if (trimmed.includes(\"/\")) {\n setNewObjectNameError(t`Object name cannot contain slashes`)\n return false\n }\n if (trimmed !== name) {\n setNewObjectNameError(t`Object name cannot have leading or trailing whitespace`)\n return false\n }\n setNewObjectNameError(null)\n return true\n },\n [t]\n )\n\n const handleCreateFolder = () => {\n if (!validateNewFolderName(newFolderName)) return\n const trimmed = newFolderName.trim()\n const newPath = `${currentPrefix}${trimmed}/`\n setLocalFolders((prev) => ({\n ...prev,\n [targetContainer]: [...(prev[targetContainer] ?? []), newPath],\n }))\n setNewFolderName(\"\")\n setShowNewFolderInput(false)\n setNewFolderError(null)\n setCurrentPrefix(newPath)\n }\n\n const handleNewFolderKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === \"Enter\") handleCreateFolder()\n if (e.key === \"Escape\") {\n setShowNewFolderInput(false)\n setNewFolderName(\"\")\n setNewFolderError(null)\n }\n }\n\n const handleMove = () => {\n if (!object) return\n if (!validateObjectName(newObjectName)) return\n const trimmedName = newObjectName.trim()\n submittedNameRef.current = trimmedName\n // destination format: \"/targetContainer/prefix/newName\" (plain text)\n // Encoding is handled in the router to avoid double-encoding.\n const destPath = `/${targetContainer}/${currentPrefix}${trimmedName}`\n copyMutation.mutate({\n project_id: projectId,\n container: sourceContainer,\n object: object.name,\n destination: destPath,\n freshMetadata: false,\n })\n }\n\n // ── Virtualized folder browser ─────────────────────────────────────────────\n // Must be declared before the early return to satisfy Rules of Hooks.\n const folderRows = rows.filter((r) => r.kind === \"folder\")\n // Files are kept in `rows` for folder-name duplicate detection but are not\n // rendered in the destination picker — only folders are valid destinations.\n const allBrowserRows = folderRows\n\n const rowVirtualizer = useVirtualizer({\n count: allBrowserRows.length,\n getScrollElement: () => listRef.current,\n estimateSize: () => 32,\n overscan: 5,\n })\n\n if (!isOpen || !object) return null\n\n const isPending = copyMutation.isPending || deleteMutation.isPending\n const isLoading = isLoadingObjects\n\n // ── Read-only target path preview ──────────────────────────────────────────\n const targetPathDisplay = `/${targetContainer}/${currentPrefix}${newObjectName.trim() || object.displayName}`\n\n // The initial prefix is the folder the source object lives in —\n // strip the displayName from the end of the full object name to get it.\n const initialPrefix = object.name.endsWith(object.displayName)\n ? object.name.slice(0, object.name.length - object.displayName.length)\n : \"\"\n\n // Disable submit when the destination is identical to the source —\n // same container, same folder prefix, and same object name means nothing would change.\n const isUnchanged =\n targetContainer === sourceContainer &&\n currentPrefix === initialPrefix &&\n newObjectName.trim() === object.displayName\n\n return (\n <Modal\n title={\n <span className=\"flex max-w-125 items-center gap-1\">\n <span className=\"shrink-0\">\n <Trans>Move/Rename Object:</Trans>\n </span>\n <span className=\"truncate\" title={object.displayName}>\n {object.displayName}\n </span>\n </span>\n }\n open={isOpen}\n onCancel={handleClose}\n confirmButtonLabel={isPending ? t`Moving...` : t`Move/Rename Object`}\n onConfirm={handleMove}\n cancelButtonLabel={t`Cancel`}\n size=\"large\"\n disableConfirmButton={isPending || isLoadingContainers || isUnchanged}\n disableCancelButton={isPending || isLoadingContainers}\n disableCloseButton={isPending || isLoadingContainers || isUnchanged}\n >\n {isPending ? (\n <Status status=\"progress\" title={t`Moving Object...`} className=\"mt-0\" />\n ) : (\n <Stack direction=\"vertical\" gap=\"4\">\n {(copyMutation.isError || deleteMutation.isError) &&\n (() => {\n const copyErrorMessage = copyMutation.error?.message ?? \"\"\n const deleteErrorMessage = deleteMutation.error?.message ?? \"\"\n return (\n <p className=\"text-theme-error\">\n {copyMutation.isError ? (\n <Trans>Failed to move object: {copyErrorMessage}</Trans>\n ) : (\n <Trans>Object was copied but could not be deleted from the source: {deleteErrorMessage}</Trans>\n )}\n </p>\n )\n })()}\n\n {/* New object name */}\n <div>\n <p className=\"mb-1\">\n <Trans>Change the name, destination container, or folder to move this object.</Trans>\n </p>\n <TextInput\n label={t`New object name`}\n value={newObjectName}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) => {\n setNewObjectName(e.target.value)\n if (newObjectNameError) setNewObjectNameError(null)\n }}\n invalid={!!newObjectNameError}\n errortext={newObjectNameError ?? undefined}\n required\n />\n </div>\n\n {/* Target container */}\n <ComboBox\n label={t`Target container`}\n value={targetContainer}\n onChange={handleContainerChange}\n onInputChange={handleContainerSearch}\n placeholder={t`Type to search containers...`}\n helptext={(() => {\n if (isLoadingContainers) return t`Loading Containers...`\n if (containerSearch.trim().length === 0) return t`Start typing to search for a container`\n if (hiddenCount > 0) {\n const maxOptions = MAX_COMBO_OPTIONS\n const totalCount = filteredContainers.length\n return t`Showing first ${maxOptions} of ${totalCount} — refine your search to narrow results`\n }\n return undefined\n })()}\n disabled={isLoadingContainers || isPending}\n required\n >\n {visibleContainers.map((c) => (\n <ComboBoxOption key={c.name} value={c.name}>\n {c.name}\n </ComboBoxOption>\n ))}\n </ComboBox>\n\n {/* Folder browser */}\n <div>\n <div className=\"mb-1 flex items-center justify-between\">\n <span className=\"text-sm font-medium\">\n <Trans>Select destination folder</Trans>\n </span>\n <Button\n size=\"small\"\n variant=\"subdued\"\n icon=\"addCircle\"\n onClick={() => {\n setShowNewFolderInput(true)\n setNewFolderName(\"\")\n setNewFolderError(null)\n }}\n disabled={isPending}\n title={t`Create new folder here`}\n >\n <Trans>New Folder</Trans>\n </Button>\n </div>\n\n {/* Breadcrumb / back navigation */}\n <div className=\"border-theme-background-lvl-2 bg-theme-background-lvl-1 flex items-center gap-2 border-b px-3 py-2 text-sm\">\n {currentPrefix ? (\n <button\n type=\"button\"\n onClick={handleNavigateUp}\n className=\"text-theme-link hover:text-theme-default flex items-center gap-1\"\n >\n <MdArrowBack size={16} />\n <Trans>Back</Trans>\n </button>\n ) : (\n <span className=\"text-theme-light\">\n <Trans>Root</Trans>\n </span>\n )}\n {currentPrefix && (\n <span className=\"text-theme-light truncate text-sm\" data-testid=\"breadcrumb-prefix\">\n / {currentPrefix}\n </span>\n )}\n </div>\n\n {/* Object browser list */}\n <div ref={listRef} className=\"border-theme-background-lvl-2 max-h-56 overflow-y-auto rounded-b border\">\n {isLoading ? (\n <Stack direction=\"horizontal\" alignment=\"center\" gap=\"2\" className=\"py-6\">\n <Spinner size=\"small\" />\n <Trans>Loading...</Trans>\n </Stack>\n ) : allBrowserRows.length === 0 && !showNewFolderInput ? (\n <div className=\"text-theme-light px-4 py-6 text-center text-sm\">\n <Trans>This folder is empty — use New Folder to create one.</Trans>\n </div>\n ) : (\n <div style={{ height: `${rowVirtualizer.getTotalSize()}px`, position: \"relative\" }}>\n {rowVirtualizer.getVirtualItems().map((virtualRow) => {\n const row = allBrowserRows[virtualRow.index]\n const isFolder = row.kind === \"folder\"\n return (\n <div\n key={row.name}\n data-index={virtualRow.index}\n ref={rowVirtualizer.measureElement}\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n width: \"100%\",\n transform: `translateY(${virtualRow.start}px)`,\n }}\n >\n {isFolder ? (\n <button\n type=\"button\"\n className=\"hover:bg-theme-background-lvl-2 focus-visible:outline-theme-focus flex w-full items-center gap-2 px-4 py-2 text-left text-sm focus-visible:outline-2\"\n onClick={() => handleFolderClick(row.name)}\n >\n <MdFolder size={16} className=\"text-theme-light shrink-0\" />\n <span className=\"truncate\">{row.displayName}</span>\n </button>\n ) : (\n /* Files shown as non-clickable, dimmed — for context only */\n <span className=\"text-theme-light flex items-center gap-2 px-4 py-2 text-sm\">\n <MdDescription size={16} className=\"shrink-0\" />\n <span className=\"truncate\">{row.displayName}</span>\n </span>\n )}\n </div>\n )\n })}\n </div>\n )}\n\n {/* Inline new folder input */}\n {showNewFolderInput && (\n <div className=\"border-theme-background-lvl-2 border-t px-4 py-3\">\n <Stack direction=\"vertical\" gap=\"2\">\n <Stack direction=\"horizontal\" gap=\"2\" alignment=\"center\">\n <MdCreateNewFolder size={16} className=\"text-theme-light shrink-0\" />\n <TextInput\n value={newFolderName}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) => {\n setNewFolderName(e.target.value)\n if (newFolderError) setNewFolderError(null)\n }}\n onKeyDown={handleNewFolderKeyDown}\n placeholder={t`Folder name`}\n invalid={!!newFolderError}\n errortext={newFolderError ?? undefined}\n autoFocus\n className=\"flex-1\"\n />\n <Button\n size=\"small\"\n variant=\"subdued\"\n onClick={() => {\n setShowNewFolderInput(false)\n setNewFolderName(\"\")\n setNewFolderError(null)\n }}\n >\n <Trans>Discard</Trans>\n </Button>\n <Button\n size=\"small\"\n variant=\"primary\"\n onClick={handleCreateFolder}\n disabled={!newFolderName.trim()}\n >\n <Trans>Create</Trans>\n </Button>\n </Stack>\n </Stack>\n </div>\n )}\n </div>\n </div>\n\n {/* Read-only target path preview */}\n <div>\n <p className=\"mb-1\">\n <Trans>The object will be moved to this path. Navigate folders above to change the destination.</Trans>\n </p>\n <p className=\"text-sm\">{targetPathDisplay}</p>\n </div>\n </Stack>\n )}\n </Modal>\n )\n}\n","import { useEffect, useRef, useState, type ChangeEvent } from \"react\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport {\n Modal,\n Stack,\n Spinner,\n TextInput,\n Icon,\n Select,\n SelectOption,\n Message,\n} from \"@cloudoperators/juno-ui-components\"\nimport { useParams } from \"@tanstack/react-router\"\nimport { ObjectRow } from \"./\"\n\n// ── Expiry presets ────────────────────────────────────────────────────────────\n\ninterface ExpiryPreset {\n labelKey: string\n seconds: number\n}\n\nconst CUSTOM_VALUE = \"custom\"\n\n// ── Props ─────────────────────────────────────────────────────────────────────\n\ninterface GenerateTempUrlModalProps {\n isOpen: boolean\n object: ObjectRow | null\n account?: string\n onClose: () => void\n onCopySuccess?: (objectName: string) => void\n}\n\n// ── Component ─────────────────────────────────────────────────────────────────\n\nexport const GenerateTempUrlModal = ({\n isOpen,\n object,\n account,\n onClose,\n onCopySuccess,\n}: GenerateTempUrlModalProps) => {\n const { t } = useLingui()\n const projectId = useProjectId()\n const { containerName } = useParams({\n from: \"/_auth/projects/$projectId/storage/$provider/$storageType/$containerName/objects/\",\n })\n\n // Defined inside the component so t`` runs in the correct Lingui context,\n // ensuring labels are extracted and translated at render time.\n const EXPIRY_PRESETS: ExpiryPreset[] = [\n { labelKey: t`1 hour`, seconds: 3600 },\n { labelKey: t`24 hours`, seconds: 86400 },\n { labelKey: t`7 days`, seconds: 604800 },\n ]\n\n // Selected preset key (seconds as string) or \"custom\"\n const [selectedPreset, setSelectedPreset] = useState<string>(String(EXPIRY_PRESETS[1].seconds))\n // Custom duration in minutes (only active when selectedPreset === \"custom\")\n const [customMinutes, setCustomMinutes] = useState(\"\")\n const [customMinutesError, setCustomMinutesError] = useState<string | null>(null)\n const [copied, setCopied] = useState(false)\n\n // Generated URL state\n const [tempUrl, setTempUrl] = useState<string | null>(null)\n const [expiresAt, setExpiresAt] = useState<number | null>(null)\n // \"no key\" errors get special inline treatment\n const [noKeyError, setNoKeyError] = useState(false)\n const [generalError, setGeneralError] = useState<string | null>(null)\n const [copyError, setCopyError] = useState<string | null>(null)\n\n const displayNameRef = useRef(\"\")\n const copyTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null)\n // Incremented on every generate call and on modal close/reopen.\n // Callbacks check their captured requestId against the ref to discard\n // stale in-flight responses that arrive after the modal was closed or\n // a new request was started.\n const requestIdRef = useRef(0)\n\n const handleGenerateSuccess = (data: { url: string; expiresAt: number }) => {\n setTempUrl(data.url)\n setExpiresAt(data.expiresAt)\n setNoKeyError(false)\n setGeneralError(null)\n }\n\n const handleGenerateError = (error: { message: string }) => {\n if (error.message.includes(\"Temp URL key not configured\")) {\n setNoKeyError(true)\n setGeneralError(null)\n } else {\n setGeneralError(error.message)\n setNoKeyError(false)\n }\n }\n\n const generateMutation = trpcReact.storage.swift.generateTempUrl.useMutation()\n\n useEffect(() => {\n if (!isOpen) {\n requestIdRef.current += 1\n if (copyTimeoutRef.current) {\n clearTimeout(copyTimeoutRef.current)\n copyTimeoutRef.current = null\n }\n generateMutation.reset()\n setTempUrl(null)\n setExpiresAt(null)\n setSelectedPreset(String(EXPIRY_PRESETS[1].seconds))\n setCustomMinutes(\"\")\n setCustomMinutesError(null)\n setCopied(false)\n setNoKeyError(false)\n setGeneralError(null)\n setCopyError(null)\n }\n return () => {\n if (copyTimeoutRef.current) clearTimeout(copyTimeoutRef.current)\n }\n }, [isOpen])\n\n // Parses customMinutes as a strict positive integer.\n // Number() + Number.isInteger() rejects non-integer inputs such as \"1.5\" → 1.5\n // and \"10abc\" → NaN with parseInt, but null here.\n // Numeric formats accepted by Number() (for example, \"1e3\") are still allowed\n // if they evaluate to a positive integer.\n const parseCustomMinutes = (): number | null => {\n if (!customMinutes.trim()) return null\n const mins = Number(customMinutes)\n return Number.isInteger(mins) && mins > 0 ? mins : null\n }\n\n const resolveExpiresIn = (): number | null => {\n if (selectedPreset === CUSTOM_VALUE) {\n const mins = parseCustomMinutes()\n if (mins === null) return null\n return mins * 60\n }\n return parseInt(selectedPreset, 10)\n }\n\n const handleGenerate = () => {\n if (!object) return\n if (selectedPreset === CUSTOM_VALUE) {\n const mins = parseCustomMinutes()\n if (mins === null) {\n setCustomMinutesError(t`Please enter a valid number of minutes greater than 0`)\n return\n }\n setCustomMinutesError(null)\n }\n const expiresIn = resolveExpiresIn()\n if (expiresIn === null) return\n displayNameRef.current = object.displayName\n setTempUrl(null)\n setExpiresAt(null)\n setCopied(false)\n const requestId = ++requestIdRef.current\n generateMutation.mutate(\n {\n project_id: projectId,\n container: containerName,\n object: object.name,\n method: \"GET\",\n expiresIn,\n ...(account ? { account } : {}),\n },\n {\n onSuccess: (data) => {\n if (requestId !== requestIdRef.current) return\n handleGenerateSuccess(data)\n },\n onError: (error) => {\n if (requestId !== requestIdRef.current) return\n handleGenerateError(error)\n },\n }\n )\n }\n\n const handleCopy = () => {\n if (!tempUrl) return\n setCopyError(null)\n navigator.clipboard\n .writeText(tempUrl)\n .then(() => {\n setCopied(true)\n onCopySuccess?.(displayNameRef.current)\n if (copyTimeoutRef.current) clearTimeout(copyTimeoutRef.current)\n copyTimeoutRef.current = setTimeout(() => {\n copyTimeoutRef.current = null\n setCopied(false)\n }, 2000)\n })\n .catch(() => {\n setCopyError(t`Failed to copy the temporary URL to the clipboard`)\n })\n }\n\n const handlePresetChange = (value?: string | number | string[]) => {\n const defaultPreset = String(EXPIRY_PRESETS[1].seconds)\n const candidate =\n typeof value === \"string\"\n ? value\n : typeof value === \"number\"\n ? String(value)\n : Array.isArray(value) && typeof value[0] === \"string\"\n ? value[0]\n : \"\"\n const validPresets = new Set([...EXPIRY_PRESETS.map((p) => String(p.seconds)), CUSTOM_VALUE])\n const nextPreset = candidate && validPresets.has(candidate) ? candidate : defaultPreset\n setSelectedPreset(nextPreset)\n // Clear custom input state when switching away from custom\n if (nextPreset !== CUSTOM_VALUE) {\n setCustomMinutes(\"\")\n setCustomMinutesError(null)\n }\n // Reset generated URL when config changes\n setTempUrl(null)\n setExpiresAt(null)\n setCopied(false)\n setGeneralError(null)\n setCopyError(null)\n setNoKeyError(false)\n }\n\n const handleCustomMinutesChange = (e: ChangeEvent<HTMLInputElement>) => {\n setCustomMinutes(e.target.value)\n if (customMinutesError) setCustomMinutesError(null)\n // Reset generated URL when config changes\n setTempUrl(null)\n setExpiresAt(null)\n setCopied(false)\n setGeneralError(null)\n setCopyError(null)\n setNoKeyError(false)\n }\n\n if (!isOpen || !object) return null\n\n const displayName = object.displayName\n const isPending = generateMutation.isPending\n const isCustom = selectedPreset === CUSTOM_VALUE\n\n // Absolute expiry timestamp formatted for current locale\n const expiresAtFormatted = expiresAt ? new Date(expiresAt * 1000).toLocaleString() : null\n // Human-readable relative label for the selected preset — used as a plain\n // string inside the \"Expires in {label} — at {timestamp}\" interpolation.\n const selectedPresetLabel =\n selectedPreset === CUSTOM_VALUE\n ? customMinutes\n ? parseCustomMinutes() === 1\n ? t`1 minute`\n : t`${customMinutes} minutes`\n : null\n : (EXPIRY_PRESETS.find((p) => String(p.seconds) === selectedPreset)?.labelKey ?? null)\n\n return (\n <Modal\n title={\n <span className=\"flex max-w-100 items-center gap-1\">\n <span className=\"shrink-0\">\n <Trans>Share URL:</Trans>\n </span>\n <span className=\"truncate\" title={displayName}>\n {displayName}\n </span>\n </span>\n }\n open={isOpen}\n onCancel={onClose}\n confirmButtonLabel={isPending ? t`Generating...` : t`Generate URL`}\n onConfirm={handleGenerate}\n cancelButtonLabel={t`Cancel`}\n size=\"small\"\n disableConfirmButton={isPending || noKeyError || (isCustom && (!customMinutes.trim() || !!customMinutesError))}\n >\n <Stack direction=\"vertical\" gap=\"4\">\n <p className=\"text-theme-default\">\n <Trans>\n A temporary URL grants time-limited read access to this object without requiring authentication. Anyone with\n the link can download it until it expires.\n </Trans>\n </p>\n\n {/* No key configured error */}\n {noKeyError && (\n <Message variant=\"warning\">\n <Trans>\n No Temp URL key configured. A temporary URL key must be set at the account or container level before\n temporary URLs can be generated. Contact your administrator to configure X-Account-Meta-Temp-URL-Key or\n X-Container-Meta-Temp-URL-Key.\n </Trans>\n </Message>\n )}\n\n {/* General error */}\n {generalError && (\n <p className=\"text-theme-error\" role=\"alert\" aria-live=\"assertive\">\n <Trans>Failed to generate temporary URL: {generalError}</Trans>\n </p>\n )}\n\n {/* Clipboard copy error */}\n {copyError && (\n <p className=\"text-theme-error\" role=\"alert\" aria-live=\"assertive\">\n {copyError}\n </p>\n )}\n\n {/* Expiry selector */}\n <Select label={t`Expires in`} value={selectedPreset} onChange={handlePresetChange} disabled={isPending}>\n {EXPIRY_PRESETS.map((preset) => (\n <SelectOption key={preset.seconds} value={String(preset.seconds)} label={preset.labelKey} />\n ))}\n <SelectOption value={CUSTOM_VALUE} label={t`Custom`} />\n </Select>\n\n {/* Custom duration input */}\n {isCustom && (\n <TextInput\n label={t`Custom duration (minutes)`}\n value={customMinutes}\n onChange={handleCustomMinutesChange}\n invalid={!!customMinutesError}\n errortext={customMinutesError || undefined}\n disabled={isPending}\n placeholder=\"60\"\n type=\"number\"\n />\n )}\n\n {/* Loading state */}\n {isPending && (\n <Stack direction=\"horizontal\" alignment=\"center\" gap=\"2\" className=\"py-2\">\n <Spinner size=\"small\" />\n <Trans>Generating temporary URL...</Trans>\n </Stack>\n )}\n\n {/* Generated URL */}\n {tempUrl && (\n <Stack direction=\"vertical\" gap=\"2\">\n <div className=\"relative\">\n <TextInput label={t`Temporary URL`} value={tempUrl} readOnly className=\"pr-10 text-xs\" />\n <button\n type=\"button\"\n onClick={handleCopy}\n title={copied ? t`Copied!` : t`Copy URL`}\n aria-label={copied ? t`Copied!` : t`Copy URL`}\n className=\"text-theme-light hover:text-theme-default absolute top-1/2 right-2 inline-flex items-center transition-colors\"\n style={{ transform: \"translateY(-50%)\" }}\n >\n <Icon icon={copied ? \"checkCircle\" : \"contentCopy\"} size=\"18\" />\n </button>\n </div>\n {expiresAtFormatted && selectedPresetLabel && (\n <p className=\"text-theme-light text-xs\">\n <Trans>\n Expires in {selectedPresetLabel} — at {expiresAtFormatted}\n </Trans>\n </p>\n )}\n </Stack>\n )}\n </Stack>\n </Modal>\n )\n}\n","import { useState, useEffect, useRef } from \"react\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport {\n Modal,\n TextInput,\n Stack,\n Status,\n DataGrid,\n DataGridRow,\n DataGridHeadCell,\n DataGridCell,\n Button,\n} from \"@cloudoperators/juno-ui-components\"\nimport { useParams } from \"@tanstack/react-router\"\nimport { formatBytesBinary } from \"@/client/utils/formatBytes\"\nimport { formatSwiftDate } from \"@/client/utils/formatSwiftDate\"\nimport { ObjectRow } from \"./\"\n\n// ── Types ──────────────────────────────────────────────────────────────────────\n\ninterface MetadataEntry {\n uid: number\n key: string\n value: string\n isEditing?: boolean\n originalKey?: string\n originalValue?: string\n}\n\ninterface EditObjectMetadataModalProps {\n isOpen: boolean\n object: ObjectRow | null\n onClose: () => void\n onSuccess?: (objectName: string) => void\n onError?: (objectName: string, errorMessage: string) => void\n}\n\n// ── Helpers ────────────────────────────────────────────────────────────────────\n\n// RFC 7230 token: only printable ASCII letters, digits, and safe symbols allowed.\n// Using a positive allowlist avoids the ESLint no-control-regex rule.\nconst VALID_KEY_RE = /^[a-zA-Z0-9!#$%&'*+\\-.^_`|~]+$/\n\n// Expected format: \"YYYY-MM-DD HH:mm:ss\" (UTC).\n// Checks shape first, then rejects semantically invalid dates (e.g. month 13, day 30 in Feb)\n// by parsing as UTC and verifying the parts round-trip back to the same values.\nconst TIMESTAMP_RE = /^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}$/\n\nconst isValidTimestamp = (value: string): boolean => {\n if (!TIMESTAMP_RE.test(value)) return false\n const d = new Date(value.replace(\" \", \"T\") + \"Z\")\n if (isNaN(d.getTime())) return false\n const [datePart, timePart] = value.split(\" \")\n const [y, mo, day] = datePart.split(\"-\").map(Number)\n const [h, min, s] = timePart.split(\":\").map(Number)\n return (\n d.getUTCFullYear() === y &&\n d.getUTCMonth() + 1 === mo &&\n d.getUTCDate() === day &&\n d.getUTCHours() === h &&\n d.getUTCMinutes() === min &&\n d.getUTCSeconds() === s\n )\n}\n\ntype MetaKeyError = \"required\" | \"invalid-chars\" | \"no-alnum\"\n\nconst validateMetaKey = (key: string): MetaKeyError | null => {\n if (!key.trim()) return \"required\"\n if (!VALID_KEY_RE.test(key)) return \"invalid-chars\"\n if (!/[a-zA-Z0-9]/.test(key)) return \"no-alnum\"\n return null\n}\n\nconst formatDate = (iso: string): string =>\n // #1236: Swift timestamps are UTC without a \"Z\"; parse them as UTC (via\n // formatSwiftDate) so the value is correct. This view intentionally displays\n // in UTC (timeZone: \"UTC\"), unlike the list tables which show local time.\n formatSwiftDate(iso, undefined, {\n year: \"numeric\",\n month: \"short\",\n day: \"2-digit\",\n hour: \"2-digit\",\n minute: \"2-digit\",\n timeZone: \"UTC\",\n }) ?? \"—\"\n\n// Converts a Unix timestamp (seconds) to the \"YYYY-MM-DD HH:mm:ss\" field format (UTC)\nconst formatUnixToTimestamp = (unix: number): string => {\n const d = new Date(unix * 1000)\n const pad = (n: number) => String(n).padStart(2, \"0\")\n return `${d.getUTCFullYear()}-${pad(d.getUTCMonth() + 1)}-${pad(d.getUTCDate())} ${pad(d.getUTCHours())}:${pad(d.getUTCMinutes())}:${pad(d.getUTCSeconds())}`\n}\n\n// ── Component ──────────────────────────────────────────────────────────────────\n\nexport const EditObjectMetadataModal = ({\n isOpen,\n object,\n onClose,\n onSuccess,\n onError,\n}: EditObjectMetadataModalProps) => {\n const { t } = useLingui()\n const projectId = useProjectId()\n const { containerName } = useParams({\n from: \"/_auth/projects/$projectId/storage/$provider/$storageType/$containerName/objects/\",\n })\n\n const utils = trpcReact.useUtils()\n\n // ── Metadata fetch ─────────────────────────────────────────────────────────\n const {\n data: metadataRaw,\n isLoading,\n isError: isMetaError,\n error: metaError,\n } = trpcReact.storage.swift.getObjectMetadata.useQuery(\n { project_id: projectId, container: containerName, object: object?.name ?? \"\" },\n { enabled: isOpen && object !== null, refetchOnWindowFocus: false }\n )\n\n const uidRef = useRef(0)\n const nextUid = () => ++uidRef.current\n\n // ── Form state ─────────────────────────────────────────────────────────────\n const [expiresAt, setExpiresAt] = useState(\"\")\n const [expiresAtError, setExpiresAtError] = useState<string | null>(null)\n const [metadata, setMetadata] = useState<MetadataEntry[]>([])\n const [metaErrors, setMetaErrors] = useState<Record<string, string>>({})\n const [isAddingNew, setIsAddingNew] = useState(false)\n const [newKey, setNewKey] = useState(\"\")\n const [newValue, setNewValue] = useState(\"\")\n const [newKeyError, setNewKeyError] = useState<string | null>(null)\n\n // Track original state for change detection and cancel-edit rollback\n const originalExpiresAtRef = useRef(\"\")\n const originalMetadataRef = useRef<MetadataEntry[]>([])\n\n // Survives reset() inside handleClose() before onSuccess/onError fire\n const displayNameRef = useRef(\"\")\n const objectNameRef = useRef(\"\")\n const expiresAtDebounceTimer = useRef<ReturnType<typeof setTimeout> | null>(null)\n\n // ── Populate form when data arrives ───────────────────────────────────────\n useEffect(() => {\n if (!metadataRaw) return\n\n const rawExpires = metadataRaw.deleteAt != null ? formatUnixToTimestamp(metadataRaw.deleteAt) : \"\"\n setExpiresAt(rawExpires)\n originalExpiresAtRef.current = rawExpires\n\n const entries: MetadataEntry[] = Object.entries(metadataRaw.customMetadata ?? {}).map(([key, value]) => ({\n uid: nextUid(),\n key,\n value,\n isEditing: false,\n originalKey: key,\n originalValue: value,\n }))\n setMetadata(entries)\n originalMetadataRef.current = entries.map((e) => ({ ...e }))\n }, [metadataRaw])\n\n // Reset when closed\n useEffect(() => {\n if (!isOpen) resetForm()\n }, [isOpen])\n\n const resetForm = () => {\n if (expiresAtDebounceTimer.current) clearTimeout(expiresAtDebounceTimer.current)\n setExpiresAt(\"\")\n setExpiresAtError(null)\n setMetadata([])\n setMetaErrors({})\n setIsAddingNew(false)\n setNewKey(\"\")\n setNewValue(\"\")\n setNewKeyError(null)\n updateMutation.reset()\n }\n\n // ── Change detection ───────────────────────────────────────────────────────\n const hasChanges = (() => {\n if (expiresAt !== originalExpiresAtRef.current) return true\n if (metadata.length !== originalMetadataRef.current.length) return true\n const originalMetadataByKey = new Map(originalMetadataRef.current.map((entry) => [entry.key, entry.value]))\n return metadata.some((entry) => originalMetadataByKey.get(entry.key) !== entry.value)\n })()\n\n const hasEditing = metadata.some((e) => e.isEditing)\n\n // ── Mutation ───────────────────────────────────────────────────────────────\n const updateMutation = trpcReact.storage.swift.updateObjectMetadata.useMutation({\n onSuccess: () => {\n utils.storage.swift.getObjectMetadata.invalidate({\n project_id: projectId,\n container: containerName,\n object: objectNameRef.current,\n })\n utils.storage.swift.listObjects.invalidate({ project_id: projectId, container: containerName })\n onSuccess?.(displayNameRef.current)\n handleClose()\n },\n onError: (error) => {\n onError?.(displayNameRef.current, error.message)\n },\n })\n\n // ── Handlers ───────────────────────────────────────────────────────────────\n const handleClose = () => {\n resetForm()\n onClose()\n }\n\n const handleSubmit = () => {\n if (!object) return\n\n if (expiresAt.trim() && !isValidTimestamp(expiresAt.trim())) {\n setExpiresAtError(\"invalid\")\n return\n }\n setExpiresAtError(null)\n\n displayNameRef.current = object.displayName\n objectNameRef.current = object.name\n\n // Build metadata record from current entries (keys are X-Object-Meta-* suffixes).\n // Swift's POST metadata update replaces the full set — keys omitted from the\n // record are automatically removed server-side, so no explicit removeMetadata needed.\n const metadataRecord: Record<string, string> = {}\n for (const entry of metadata) {\n metadataRecord[entry.key] = entry.value\n }\n\n updateMutation.mutate({\n project_id: projectId,\n container: containerName,\n object: object.name,\n metadata: metadataRecord,\n ...(expiresAt.trim()\n ? { deleteAt: Math.floor(new Date(expiresAt.trim().replace(\" \", \"T\") + \"Z\").getTime() / 1000) }\n : {}),\n })\n }\n\n // ── Metadata row handlers ──────────────────────────────────────────────────\n const handleEdit = (index: number) => {\n setMetadata((prev) => prev.map((e, i) => (i === index ? { ...e, isEditing: true } : e)))\n }\n\n const handleKeyChange = (index: number, value: string) => {\n setMetadata((prev) => prev.map((e, i) => (i === index ? { ...e, key: value } : e)))\n if (metaErrors[`edit-${index}`]) {\n setMetaErrors((prev) => {\n const next = { ...prev }\n delete next[`edit-${index}`]\n return next\n })\n }\n }\n\n const handleValueChange = (index: number, value: string) => {\n setMetadata((prev) => prev.map((e, i) => (i === index ? { ...e, value } : e)))\n }\n\n const handleSaveEdit = (index: number) => {\n const entry = metadata[index]\n const keyError = validateMetaKey(entry.key)\n if (keyError) {\n const msg =\n keyError === \"required\"\n ? t`Key is required`\n : keyError === \"invalid-chars\"\n ? t`Key contains invalid characters`\n : t`Key must contain at least one alphanumeric character`\n setMetaErrors((prev) => ({ ...prev, [`edit-${index}`]: msg }))\n return\n }\n const isDuplicate = metadata.some((e, i) => i !== index && e.key.toLowerCase() === entry.key.toLowerCase())\n if (isDuplicate) {\n setMetaErrors((prev) => ({ ...prev, [`edit-${index}`]: t`Key already exists` }))\n return\n }\n setMetadata((prev) => prev.map((e, i) => (i === index ? { ...e, isEditing: false } : e)))\n setMetaErrors((prev) => {\n const next = { ...prev }\n delete next[`edit-${index}`]\n return next\n })\n }\n\n const handleCancelEdit = (index: number) => {\n const orig = originalMetadataRef.current[index]\n if (orig) {\n setMetadata((prev) => prev.map((e, i) => (i === index ? { ...orig, isEditing: false } : e)))\n } else {\n // Newly added row that was put into edit mode — drop it\n setMetadata((prev) => prev.filter((_, i) => i !== index))\n }\n setMetaErrors((prev) => {\n const next = { ...prev }\n delete next[`edit-${index}`]\n return next\n })\n }\n\n const handleDeleteMeta = (index: number) => {\n setMetadata((prev) => prev.filter((_, i) => i !== index))\n }\n\n const handleAddNew = () => {\n const keyError = validateMetaKey(newKey)\n if (keyError) {\n setNewKeyError(\n keyError === \"required\"\n ? t`Key is required`\n : keyError === \"invalid-chars\"\n ? t`Key contains invalid characters`\n : t`Key must contain at least one alphanumeric character`\n )\n return\n }\n const isDuplicate = metadata.some((e) => e.key.toLowerCase() === newKey.trim().toLowerCase())\n if (isDuplicate) {\n setNewKeyError(t`Key already exists`)\n return\n }\n setMetadata((prev) => [...prev, { uid: nextUid(), key: newKey.trim(), value: newValue, isEditing: false }])\n setNewKey(\"\")\n setNewValue(\"\")\n setNewKeyError(null)\n setIsAddingNew(false)\n }\n\n const handleCancelAdd = () => {\n setNewKey(\"\")\n setNewValue(\"\")\n setNewKeyError(null)\n setIsAddingNew(false)\n }\n\n if (!isOpen || !object) return null\n\n const displayName = object.displayName\n const isPending = updateMutation.isPending\n const isBusy = isPending || isLoading\n const isSLO = metadataRaw?.staticLargeObject === true\n const isDLO = !!metadataRaw?.objectManifest\n const metadataErrorMessage = metaError?.message ?? \"\"\n const mutationErrorMessage = updateMutation.error?.message ?? \"\"\n\n return (\n <Modal\n title={\n <span className=\"flex max-w-100 items-center gap-1\">\n <Trans>\n <span className=\"shrink-0\">Edit metadata:</span>{\" \"}\n <span className=\"truncate\" title={displayName}>\n {displayName}\n </span>\n </Trans>\n </span>\n }\n open={isOpen}\n onCancel={handleClose}\n confirmButtonLabel={isPending ? t`Saving...` : t`Update object`}\n onConfirm={handleSubmit}\n cancelButtonLabel={t`Cancel`}\n size={isAddingNew ? \"xl\" : \"large\"}\n disableConfirmButton={isBusy || !hasChanges || hasEditing || isAddingNew}\n >\n {isLoading ? (\n <Status status=\"progress\" title={t`Loading Object Properties...`} className=\"mt-0\" />\n ) : isMetaError ? (\n <Status status=\"error\" title={t`Failed to Load Object Metadata`} body={metadataErrorMessage} className=\"mt-0\" />\n ) : (\n <Stack direction=\"vertical\" gap=\"6\">\n {/* Mutation error */}\n {updateMutation.isError && (\n <p className=\"text-theme-error\">\n <Trans>Failed to update object: {mutationErrorMessage}</Trans>\n </p>\n )}\n\n {/* ── Large object notices ──────────────────────────────────────── */}\n {isSLO && (\n <p className=\"text-theme-default\">\n <Trans>\n This is a <strong>static large object (SLO)</strong> manifest. Metadata changes apply to the manifest\n only — segment objects are not affected.\n </Trans>\n </p>\n )}\n {isDLO && (\n <p className=\"text-theme-default\">\n <Trans>\n This is a <strong>dynamic large object (DLO)</strong> manifest. Metadata changes apply to the manifest\n only — segment objects are not affected.\n </Trans>\n </p>\n )}\n\n {/* ── Read-only properties ──────────────────────────────────────── */}\n <div>\n <p className=\"text-theme-default mb-3 text-sm font-semibold\">\n <Trans>Object properties</Trans>\n </p>\n <div className=\"grid grid-cols-[max-content_1fr] gap-x-6 gap-y-2 text-sm\">\n <span className=\"text-theme-light text-right\">\n <Trans>Content type</Trans>\n </span>\n <span>{metadataRaw?.contentType ?? \"—\"}</span>\n\n <span className=\"text-theme-light text-right\">\n <Trans>MD5 checksum</Trans>\n </span>\n <span className=\"break-all\">{metadataRaw?.etag ?? \"—\"}</span>\n\n <span className=\"text-theme-light text-right\">\n <Trans>Size</Trans>\n </span>\n <span>{metadataRaw?.contentLength != null ? formatBytesBinary(metadataRaw.contentLength) : \"—\"}</span>\n\n <span className=\"text-theme-light text-right\">\n <Trans>Last modified (UTC)</Trans>\n </span>\n <span>\n {metadataRaw?.lastModified\n ? formatDate(metadataRaw.lastModified)\n : object.last_modified\n ? formatDate(object.last_modified)\n : \"—\"}\n </span>\n </div>\n </div>\n\n {/* ── Expires at ───────────────────────────────────────────────── */}\n <div>\n <p className=\"text-theme-light mb-1\">\n <Trans>Enter a timestamp like \"YYYY-MM-DD HH:mm:ss\" to schedule automatic deletion.</Trans>\n </p>\n <TextInput\n label={t`Expires at (UTC)`}\n value={expiresAt}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) => {\n const value = e.target.value\n setExpiresAt(value)\n if (expiresAtDebounceTimer.current) clearTimeout(expiresAtDebounceTimer.current)\n expiresAtDebounceTimer.current = setTimeout(() => {\n if (value.trim() && !isValidTimestamp(value.trim())) {\n setExpiresAtError(\"invalid\")\n } else {\n setExpiresAtError(null)\n }\n }, 600)\n }}\n invalid={!!expiresAtError}\n errortext={expiresAtError ? t`Expected format: YYYY-MM-DD HH:mm:ss` : undefined}\n placeholder={t`YYYY-MM-DD HH:mm:ss`}\n disabled={isBusy}\n />\n </div>\n\n {/* ── Custom metadata ───────────────────────────────────────────── */}\n <div>\n <Stack direction=\"horizontal\" alignment=\"center\" distribution=\"between\">\n <p className=\"text-theme-default text-sm font-semibold\">\n <Trans>Metadata</Trans>\n </p>\n <p className=\"text-theme-light text-xs\">\n <Trans>Stored as X-Object-Meta-* headers. Keys are case-insensitive.</Trans>\n </p>\n </Stack>\n\n <Stack direction=\"horizontal\" className=\"jn:bg-theme-background-lvl-1 justify-end p-2\">\n <Button\n label={t`Add Property`}\n onClick={() => setIsAddingNew(true)}\n variant=\"primary\"\n size=\"small\"\n icon=\"addCircle\"\n disabled={isAddingNew || hasEditing || isBusy}\n />\n </Stack>\n\n <DataGrid columns={3}>\n <DataGridRow>\n <DataGridHeadCell>\n <Trans>Key</Trans>\n </DataGridHeadCell>\n <DataGridHeadCell>\n <Trans>Value</Trans>\n </DataGridHeadCell>\n <DataGridHeadCell>\n <Trans>Actions</Trans>\n </DataGridHeadCell>\n </DataGridRow>\n\n {/* New row */}\n {isAddingNew && (\n <DataGridRow>\n <DataGridCell>\n <TextInput\n value={newKey}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) => {\n setNewKey(e.target.value)\n if (newKeyError) setNewKeyError(null)\n }}\n placeholder={t`property_key`}\n errortext={newKeyError ?? undefined}\n invalid={!!newKeyError}\n autoFocus\n />\n </DataGridCell>\n <DataGridCell>\n <TextInput\n value={newValue}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) => setNewValue(e.target.value)}\n placeholder={t`Value`}\n />\n </DataGridCell>\n <DataGridCell>\n <Stack direction=\"horizontal\" gap=\"2\">\n <Button size=\"small\" variant=\"primary\" onClick={handleAddNew} icon=\"check\" title={t`Save`} />\n <Button\n size=\"small\"\n variant=\"subdued\"\n onClick={handleCancelAdd}\n icon=\"close\"\n title={t`Discard`}\n />\n </Stack>\n </DataGridCell>\n </DataGridRow>\n )}\n\n {/* Existing rows */}\n {metadata.map((entry, index) => (\n <DataGridRow key={entry.uid}>\n <DataGridCell>\n {entry.isEditing ? (\n <TextInput\n value={entry.key}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) => handleKeyChange(index, e.target.value)}\n errortext={metaErrors[`edit-${index}`]}\n invalid={!!metaErrors[`edit-${index}`]}\n />\n ) : (\n <span className=\"block max-w-xs truncate text-sm\" title={entry.key}>\n {entry.key}\n </span>\n )}\n </DataGridCell>\n <DataGridCell>\n {entry.isEditing ? (\n <TextInput\n value={entry.value}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) => handleValueChange(index, e.target.value)}\n />\n ) : (\n <span className=\"block max-w-md truncate text-sm\" title={entry.value}>\n {entry.value}\n </span>\n )}\n </DataGridCell>\n <DataGridCell>\n {entry.isEditing ? (\n <Stack direction=\"horizontal\" gap=\"2\">\n <Button\n size=\"small\"\n variant=\"primary\"\n onClick={() => handleSaveEdit(index)}\n icon=\"check\"\n title={t`Save`}\n />\n <Button\n size=\"small\"\n variant=\"subdued\"\n onClick={() => handleCancelEdit(index)}\n icon=\"close\"\n title={t`Discard`}\n />\n </Stack>\n ) : (\n <Stack direction=\"horizontal\" gap=\"2\">\n <Button\n size=\"small\"\n variant=\"subdued\"\n onClick={() => handleEdit(index)}\n icon=\"edit\"\n title={t`Edit`}\n disabled={isAddingNew || hasEditing || isBusy}\n />\n <Button\n size=\"small\"\n variant=\"default\"\n onClick={() => handleDeleteMeta(index)}\n icon=\"deleteForever\"\n title={t`Delete`}\n disabled={isAddingNew || hasEditing || isBusy}\n />\n </Stack>\n )}\n </DataGridCell>\n </DataGridRow>\n ))}\n\n {/* Empty state */}\n {metadata.length === 0 && !isAddingNew && (\n <DataGridRow>\n <DataGridCell colSpan={3} className=\"py-6 text-center\">\n <Stack alignment=\"center\">\n <span className=\"text-theme-light text-sm\">\n <Trans>No custom metadata. Click \"Add Property\" to create one.</Trans>\n </span>\n </Stack>\n </DataGridCell>\n </DataGridRow>\n )}\n </DataGrid>\n </div>\n </Stack>\n )}\n </Modal>\n )\n}\n","import { ReactNode } from \"react\"\nimport { NotificationOptions } from \"@cloudoperators/juno-ui-components\"\nimport { Trans } from \"@lingui/react/macro\"\n\n// ── Folder operations ──────────────────────────────────────────────────────────\n\nexport const getFolderCreatedToast = (folderName: string): { message: ReactNode } & NotificationOptions => ({\n message: <Trans>Folder Created</Trans>,\n description: <Trans>Folder \"{folderName}\" was successfully created.</Trans>,\n})\n\nexport const getFolderCreateErrorToast = (\n folderName: string,\n errorMessage: string\n): { message: ReactNode } & NotificationOptions => ({\n message: <Trans>Failed to Create Folder</Trans>,\n description: (\n <Trans>\n Could not create folder \"{folderName}\": {errorMessage}\n </Trans>\n ),\n})\n\nexport const getFolderDeletedToast = (\n folderName: string,\n deletedCount: number\n): { message: ReactNode } & NotificationOptions => ({\n message: <Trans>Folder Deleted</Trans>,\n description:\n deletedCount === 0 ? (\n <Trans>Folder \"{folderName}\" was permanently deleted.</Trans>\n ) : deletedCount === 1 ? (\n <Trans>\n Folder \"{folderName}\" and {deletedCount} object were permanently deleted.\n </Trans>\n ) : (\n <Trans>\n Folder \"{folderName}\" and {deletedCount} objects were permanently deleted.\n </Trans>\n ),\n})\n\nexport const getFolderDeleteErrorToast = (\n folderName: string,\n errorMessage: string\n): { message: ReactNode } & NotificationOptions => ({\n message: <Trans>Failed to Delete Folder</Trans>,\n description: (\n <Trans>\n Could not delete folder \"{folderName}\": {errorMessage}\n </Trans>\n ),\n})\n\n// ── Container access / existence ───────────────────────────────────────────────\n\n// Shown when the object listing for a container can't be loaded — the container\n// doesn't exist or the user has no access to it. Deliberately a single combined\n// message for both cases (#1142): distinguishing \"not found\" from \"forbidden\"\n// would leak whether a container exists to someone who can't access it. Raised\n// by SwiftObjects right before it redirects back to the container list.\nexport const getContainerAccessErrorToast = (containerName: string): { message: ReactNode } & NotificationOptions => ({\n message: <Trans>Couldn't Open Container</Trans>,\n description: (\n <Trans>Couldn't open container \"{containerName}\" — it may not exist, or you may not have access to it.</Trans>\n ),\n})\n\n// ── Object download ────────────────────────────────────────────────────────────\n\n// Shown while at least one download/preview transfer is in flight. Large objects\n// stream through the BFF before anything happens client-side (no native browser\n// download progress until the whole file has arrived), so this sets expectations\n// up front.\n//\n// This is a single, persistent toast — not one per file: the download store\n// raises it when the first transfer starts and dismisses it when the last one\n// finishes, so several concurrent downloads never stack up notifications. It is\n// rendered with a fixed id and `duration: Infinity` (see objectDownloadStore).\nexport const getObjectDownloadStartedToast = (): { message: ReactNode } & NotificationOptions => ({\n message: <Trans>Downloading...</Trans>,\n description: (\n <Trans>\n Downloading larger files may take a while. You can keep browsing containers and folders — downloads continue in\n the background, and this message disappears once they finish.\n </Trans>\n ),\n})\n\n// A cancelled transfer is a user-initiated outcome, not a failure — confirm it\n// so the disappearing progress spinner isn't the only feedback. Takes the full\n// object key and derives a basename display name, consistent with the store,\n// which passes the full key.\nexport const getObjectDownloadCancelledToast = (objectKey: string): { message: ReactNode } & NotificationOptions => {\n const displayName = objectKey.split(\"/\").filter(Boolean).pop() ?? objectKey\n return {\n message: <Trans>Download Cancelled</Trans>,\n description: <Trans>Download of \"{displayName}\" was cancelled.</Trans>,\n }\n}\n\nexport const getObjectDownloadErrorToast = (\n objectKey: string,\n errorMessage: string\n): { message: ReactNode } & NotificationOptions => {\n const displayName = objectKey.split(\"/\").filter(Boolean).pop() ?? objectKey\n return {\n message: <Trans>Failed to Download</Trans>,\n description: (\n <Trans>\n Could not download \"{displayName}\": {errorMessage}\n </Trans>\n ),\n }\n}\n\n// ── Object delete ──────────────────────────────────────────────────────────────\n\nexport const getObjectDeletedToast = (objectName: string): { message: ReactNode } & NotificationOptions => ({\n message: <Trans>Object Deleted</Trans>,\n description: <Trans>Object \"{objectName}\" was permanently deleted.</Trans>,\n})\n\nexport const getObjectDeleteErrorToast = (\n objectName: string,\n errorMessage: string\n): { message: ReactNode } & NotificationOptions => ({\n message: <Trans>Failed to Delete Object</Trans>,\n description: (\n <Trans>\n Could not delete \"{objectName}\": {errorMessage}\n </Trans>\n ),\n})\n\n// ── Object copy ────────────────────────────────────────────────────────────────\n\nexport const getObjectCopiedToast = (\n objectName: string,\n targetContainer: string,\n targetPath: string\n): { message: ReactNode } & NotificationOptions => {\n const destination = targetPath ? `${targetContainer}/${targetPath}` : targetContainer\n return {\n message: <Trans>Object Copied</Trans>,\n description: (\n <Trans>\n \"{objectName}\" was successfully copied to {destination}.\n </Trans>\n ),\n }\n}\n\nexport const getObjectCopyErrorToast = (\n objectName: string,\n errorMessage: string\n): { message: ReactNode } & NotificationOptions => ({\n message: <Trans>Failed to Copy Object</Trans>,\n description: (\n <Trans>\n Could not copy \"{objectName}\": {errorMessage}\n </Trans>\n ),\n})\n\n// ── Object move ────────────────────────────────────────────────────────────────\n\nexport const getObjectMovedToast = (\n objectName: string,\n targetContainer: string,\n targetPath: string\n): { message: ReactNode } & NotificationOptions => {\n const destination = targetPath ? `${targetContainer}/${targetPath}` : targetContainer\n return {\n message: <Trans>Object Moved</Trans>,\n description: (\n <Trans>\n \"{objectName}\" was successfully moved to {destination}.\n </Trans>\n ),\n }\n}\n\nexport const getObjectMoveErrorToast = (\n objectName: string,\n errorMessage: string\n): { message: ReactNode } & NotificationOptions => ({\n message: <Trans>Failed to Move Object</Trans>,\n description: (\n <Trans>\n Could not move \"{objectName}\": {errorMessage}\n </Trans>\n ),\n})\n\n// ── Temporary URL ──────────────────────────────────────────────────────────────\n\nexport const getTempUrlCopiedToast = (objectName: string): { message: ReactNode } & NotificationOptions => ({\n message: <Trans>URL Copied</Trans>,\n description: <Trans>Temporary URL for \"{objectName}\" was copied to clipboard.</Trans>,\n})\n\n// ── Object metadata update ─────────────────────────────────────────────────────\n\nexport const getObjectMetadataUpdatedToast = (objectName: string): { message: ReactNode } & NotificationOptions => ({\n message: <Trans>Object Updated</Trans>,\n description: <Trans>Properties of \"{objectName}\" were successfully updated.</Trans>,\n})\n\nexport const getObjectMetadataUpdateErrorToast = (\n objectName: string,\n errorMessage: string\n): { message: ReactNode } & NotificationOptions => ({\n message: <Trans>Failed to Update Object</Trans>,\n description: (\n <Trans>\n Could not update \"{objectName}\": {errorMessage}\n </Trans>\n ),\n})\n\n// ── Object upload ──────────────────────────────────────────────────────────────\n\nexport const getObjectUploadedToast = (objectName: string): { message: ReactNode } & NotificationOptions => ({\n message: <Trans>Object Uploaded</Trans>,\n description: <Trans>\"{objectName}\" was successfully uploaded.</Trans>,\n})\n\nexport const getObjectUploadCancelledToast = (objectName: string): { message: ReactNode } & NotificationOptions => ({\n message: <Trans>Upload Cancelled</Trans>,\n description: <Trans>Upload of \"{objectName}\" was cancelled.</Trans>,\n})\n\nexport const getObjectUploadErrorToast = (\n objectName: string,\n errorMessage: string\n): { message: ReactNode } & NotificationOptions => ({\n message: <Trans>Failed to Upload Object</Trans>,\n description: (\n <Trans>\n Could not upload \"{objectName}\": {errorMessage}\n </Trans>\n ),\n})\n\n// ── Bulk delete ────────────────────────────────────────────────────────────────\n\nexport const getObjectsBulkDeletedToast = (numberDeleted: number): { message: ReactNode } & NotificationOptions => ({\n message: <Trans>Objects Deleted</Trans>,\n description:\n numberDeleted === 1 ? (\n <Trans>{numberDeleted} object was permanently deleted.</Trans>\n ) : (\n <Trans>{numberDeleted} objects were permanently deleted.</Trans>\n ),\n})\n\nexport const getObjectsBulkDeleteErrorToast = (errorMessage: string): { message: ReactNode } & NotificationOptions => ({\n message: <Trans>Failed to Delete Objects</Trans>,\n description: (\n <span>\n <Trans>One or more objects could not be deleted:</Trans>\n <span className=\"mt-1 block text-xs whitespace-pre-wrap\">{errorMessage}</span>\n </span>\n ),\n})\n","// Module-scope registry of in-flight Swift object downloads.\n//\n// Why this lives outside React: ObjectBrowserView swaps ObjectsTableView out for\n// a <Spinner> whenever objects.list is loading (i.e. entering an uncached\n// folder). That unmounts the table — and if the table owned the workers, its\n// cleanup would abort them mid-stream (\"stream closed prematurely\") and lose the\n// progress state. Owning transfers here means a download survives folder\n// navigation, spinner swaps, and even leaving the container entirely — which is\n// what the download-started toast already promises the user.\n//\n// Components read the transfer map via useSyncExternalStore(subscribe, getSnapshot)\n// and re-render on change. The worker's onmessage callbacks run regardless of\n// whether any component is mounted, so a download that finishes while the user is\n// in another folder still saves the file.\n\nimport { toast } from \"@cloudoperators/juno-ui-components\"\nimport { getBffEndpoint, getCsrfToken } from \"@/client/trpcClient\"\nimport DownloadWorker from \"../workers/objectDownload.worker?worker&inline\"\nimport type { DownloadWorkerRequest, DownloadWorkerResponse } from \"../workers/objectDownload.worker\"\nimport { getObjectDownloadStartedToast } from \"../ObjectToastNotifications\"\n\nexport type TransferKind = \"download\" | \"preview\"\nexport type ActiveTransfer = { kind: TransferKind; downloadId: string; worker: Worker }\n\n// Keyed by transferKey() — container-scoped so the same object name in two\n// containers can't collide.\nconst transfers = new Map<string, ActiveTransfer>()\nconst listeners = new Set<() => void>()\n\n// useSyncExternalStore requires getSnapshot to return a stable reference between\n// changes, so we hand out a copy that's only rebuilt on mutation.\nlet snapshot: ReadonlyMap<string, ActiveTransfer> = new Map()\n\n// Fixed id so the \"Downloading...\" notification is a single toast for the whole\n// session rather than one per file — sonner (which backs Juno's toast) treats a\n// repeated id as an update, not a new notification. Distinct from the Ceph\n// store's id so the two backends' persistent toasts never dismiss each other.\nconst DOWNLOAD_TOAST_ID = \"swift-object-download\"\nlet downloadToastShown = false\n\n// Raise the toast when the first transfer starts, dismiss it when the last one\n// ends — however it ended (saved, failed, or cancelled). Living in the store\n// rather than in a component matters: the last transfer can finish while\n// ObjectsTableView is unmounted (the user navigated away), and the toast must\n// still be dismissed.\nconst syncDownloadToast = () => {\n const hasActiveTransfers = transfers.size > 0\n if (hasActiveTransfers && !downloadToastShown) {\n const { message, ...options } = getObjectDownloadStartedToast()\n // duration: Infinity — this toast is dismissed explicitly, not on a timer.\n toast(message, { ...options, id: DOWNLOAD_TOAST_ID, duration: Infinity })\n downloadToastShown = true\n } else if (!hasActiveTransfers && downloadToastShown) {\n toast.dismiss(DOWNLOAD_TOAST_ID)\n downloadToastShown = false\n }\n}\n\nconst emit = () => {\n snapshot = new Map(transfers)\n syncDownloadToast()\n listeners.forEach((listener) => listener())\n}\n\n// How long a cancelled worker gets to report back before it is forced down.\n//\n// Normally it replies almost immediately — the abort rejects its `for await`,\n// and the reply path terminates it. But that reply isn't guaranteed: if the\n// abort ever fails to unwind the stream, the worker would keep downloading and\n// buffering a file nobody wants, with no entry left in `transfers` to clean it\n// up. This bounds that window.\nconst CANCEL_TERMINATE_GRACE_MS = 5000\n\nexport const transferKey = (container: string, objectKey: string) => `${container}:${objectKey}`\n\nexport const subscribeTransfers = (listener: () => void) => {\n listeners.add(listener)\n return () => listeners.delete(listener)\n}\n\nexport const getTransfersSnapshot = (): ReadonlyMap<string, ActiveTransfer> => snapshot\n\n// ── DOM helpers (main thread only — the worker has no document) ────────────────\n\nconst triggerAnchorDownload = (url: string, filename: string) => {\n const anchor = document.createElement(\"a\")\n anchor.href = url\n anchor.download = filename\n document.body.appendChild(anchor)\n anchor.click()\n document.body.removeChild(anchor)\n setTimeout(() => URL.revokeObjectURL(url), 10000)\n}\n\n// Uses an anchor with target=\"_blank\" rather than window.open — anchors aren't\n// subject to the post-await popup-blocking window.open is, so the tab can be\n// opened after streaming completes, only for files we know are previewable.\nconst openBlobInNewTab = (url: string) => {\n const anchor = document.createElement(\"a\")\n anchor.href = url\n anchor.target = \"_blank\"\n anchor.rel = \"noopener noreferrer\"\n document.body.appendChild(anchor)\n anchor.click()\n document.body.removeChild(anchor)\n setTimeout(() => URL.revokeObjectURL(url), 60000)\n}\n\n// MIME types safe to preview in a browser tab. Decided from the Content-Type the\n// BFF actually returns, not from the filename.\n//\n// NOTE: intentionally excludes scriptable types (text/html, application/json,\n// application/xml) and SVG (can execute scripts when opened via blob URLs).\nconst BROWSER_PREVIEWABLE_MIME_TYPES = new Set([\"application/pdf\", \"text/plain\"])\n\nexport function isPreviewableContentType(contentType: string): boolean {\n const base = contentType.split(\";\")[0].trim().toLowerCase()\n if (BROWSER_PREVIEWABLE_MIME_TYPES.has(base)) return true\n if (base === \"image/svg+xml\") return false\n return base.startsWith(\"image/\") || base.startsWith(\"video/\") || base.startsWith(\"audio/\")\n}\n\n// ── Transfer lifecycle ────────────────────────────────────────────────────────\n\nexport function startObjectDownload(opts: {\n kind: TransferKind\n projectId: string\n container: string\n objectKey: string\n filename: string\n account?: string\n onError: (objectKey: string, message: string) => void\n}): void {\n const { kind, projectId, container, objectKey, filename, account, onError } = opts\n const key = transferKey(container, objectKey)\n\n // Ignore a second start for a row that's already transferring.\n if (transfers.has(key)) return\n\n const downloadId = `${container}:${objectKey}:${crypto.randomUUID()}`\n\n let worker: Worker\n try {\n // Inlined worker (Vite's ?worker&inline), NOT `new Worker(new URL(…))`.\n // Aurora ships as a library: a URL-referenced worker is emitted as a separate\n // asset and the reference is baked into our bundle as a plain string. The app\n // consuming this library re-bundles us, sees only that string, and never\n // copies the worker chunk into its own output — so the request 404s and lands\n // in the SPA fallback, which serves index.html and fails strict MIME checking\n // for module scripts. Inlining leaves no asset for a consumer to lose.\n worker = new DownloadWorker()\n } catch (err) {\n onError(objectKey, err instanceof Error ? err.message : \"Failed to start download worker\")\n return\n }\n\n transfers.set(key, { kind, downloadId, worker })\n emit()\n\n const finish = () => {\n // Only clear the entry we started — a newer transfer for the same row must\n // not be wiped by a stale one's cleanup. terminate() here is safe: the worker\n // has already reported back, so it's idle, never killed mid-stream.\n if (transfers.get(key)?.downloadId === downloadId) {\n transfers.delete(key)\n emit()\n }\n worker.terminate()\n }\n\n worker.onmessage = ({ data }: MessageEvent<DownloadWorkerResponse>) => {\n // A worker that was cancelled (or replaced) is no longer the row's transfer —\n // ignore its late reply so a download finishing at the moment of cancel\n // doesn't still save the file.\n if (transfers.get(key)?.worker !== worker) {\n worker.terminate()\n return\n }\n if (data.ok) {\n const url = URL.createObjectURL(data.blob)\n if (kind === \"preview\" && isPreviewableContentType(data.contentType)) {\n openBlobInNewTab(url)\n } else {\n triggerAnchorDownload(url, data.filename)\n }\n } else if (!data.cancelled) {\n onError(objectKey, data.message)\n }\n finish()\n }\n\n worker.onerror = (event) => {\n if (transfers.get(key)?.worker !== worker) {\n worker.terminate()\n return\n }\n onError(objectKey, event.message || \"Download worker failed\")\n finish()\n }\n\n worker.postMessage({\n type: \"start\",\n // The worker has its own module instance and never sees App's\n // setBffEndpoint() call — hand it the resolved endpoint explicitly.\n //\n // Absolute, not relative: the worker is inlined and therefore runs from a\n // blob: URL, whose location has an opaque path. Resolving \"/polaris-bff\"\n // against it throws (\"Failed to parse URL\"), so the endpoint has to carry its\n // own origin. An already-absolute endpoint passes through unchanged.\n bffEndpoint: new URL(getBffEndpoint(), location.origin).href,\n // Same story for CSRF: the worker's own token cache starts empty, and\n // fetching /csrf-token there is a round-trip we don't need. Null (nothing has\n // needed a token yet this session) is fine — the worker resolves one itself.\n csrfToken: getCsrfToken(),\n projectId,\n container,\n objectKey,\n filename,\n downloadId,\n ...(account ? { account } : {}),\n } satisfies DownloadWorkerRequest)\n}\n\n// Cancel an in-flight transfer. Removes it from the store immediately (so the UI\n// clears on the very next render, with no worker round-trip) and tells the worker\n// to abort its tRPC call, which tears down the request so the BFF stops reading\n// from Swift. The worker isn't terminated right away — it unwinds its own abort\n// and is dropped once idle, avoiding a mid-stream hard kill; a grace-period timer\n// forces it down if that never happens.\n//\n// Returns the cancelled transfer (or undefined if the row wasn't transferring) so\n// callers can tell a real cancellation apart from a no-op.\nexport function cancelObjectDownload(container: string, objectKey: string): ActiveTransfer | undefined {\n const key = transferKey(container, objectKey)\n const transfer = transfers.get(key)\n if (!transfer) return undefined\n\n transfer.worker.postMessage({ type: \"cancel\" } satisfies DownloadWorkerRequest)\n // Safety net for a worker that never reports back (see\n // CANCEL_TERMINATE_GRACE_MS). terminate() is idempotent, so this is a no-op in\n // the normal case where the worker already replied and was terminated.\n setTimeout(() => transfer.worker.terminate(), CANCEL_TERMINATE_GRACE_MS)\n transfers.delete(key)\n emit()\n return transfer\n}\n","import { useEffect, useState, useSyncExternalStore } from \"react\"\nimport {\n Checkbox,\n DataGrid,\n DataGridHeadCell,\n DataGridRow,\n DataGridCell,\n Icon,\n PopupMenu,\n PopupMenuItem,\n PopupMenuOptions,\n Spinner,\n toast,\n Tooltip,\n TooltipTrigger,\n TooltipContent,\n Status,\n} from \"@cloudoperators/juno-ui-components\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { MdFolder, MdDescription } from \"react-icons/md\"\nimport { formatBytesBinary } from \"@/client/utils/formatBytes\"\nimport { formatSwiftDate } from \"@/client/utils/formatSwiftDate\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport { useVirtualizedTableBody } from \"@/client/hooks/useVirtualizedTableBody\"\nimport { BrowserRow, FolderRow, ObjectRow } from \"./\"\nimport { DeleteFolderModal } from \"./DeleteFolderModal\"\nimport { DeleteObjectModal } from \"./DeleteObjectModal\"\nimport { CopyObjectModal } from \"./CopyObjectModal\"\nimport { MoveRenameObjectModal } from \"./MoveRenameObjectModal\"\nimport { GenerateTempUrlModal } from \"./GenerateTempUrlModal\"\nimport { EditObjectMetadataModal } from \"./EditObjectMetadataModal\"\nimport { getObjectDownloadCancelledToast } from \"./ObjectToastNotifications\"\nimport {\n startObjectDownload,\n cancelObjectDownload,\n subscribeTransfers,\n getTransfersSnapshot,\n transferKey,\n isPreviewableContentType,\n} from \"./stores/objectDownloadStore\"\n\n// The transfer lifecycle (worker, streaming, decode, Blob, DOM save) lives in\n// ./stores/objectDownloadStore so downloads survive this component unmounting\n// (ObjectBrowserView swaps in a <Spinner> while a folder loads). This component\n// only reads the store for UI and drives start/cancel.\n\n// Subscribes to live progress for a single in-flight transfer. Each active row\n// renders its own instance (keyed by downloadId), so concurrent transfers each\n// get an independent subscription rather than sharing one — starting a second\n// transfer never disrupts the first's progress. Swift's watchDownloadProgress\n// scopes to the project via the token server-side, so only downloadId is passed.\nfunction RowTransferProgress({ downloadId, isPreviewing }: { downloadId: string; isPreviewing: boolean }) {\n const { data: progress } = trpcReact.storage.swift.watchDownloadProgress.useSubscription(\n { downloadId },\n { enabled: !!downloadId }\n )\n const percent = progress?.percent\n\n return (\n <span className=\"flex w-full flex-1 flex-col gap-1\">\n <span className=\"text-theme-light flex items-center gap-2 text-sm\">\n <Spinner size=\"small\" />\n {percent != null ? (\n <Trans>{percent}%</Trans>\n ) : isPreviewing ? (\n <Trans>Loading Preview...</Trans>\n ) : (\n <Trans>Downloading...</Trans>\n )}\n </span>\n {percent != null && (\n <div className=\"bg-theme-background-lvl-2 h-1 w-full overflow-hidden rounded-full\">\n <div\n className=\"bg-theme-accent h-1 rounded-full transition-all duration-150\"\n style={{ width: `${percent}%` }}\n />\n </div>\n )}\n </span>\n )\n}\n\n// Column templates — 5 columns with the selection checkbox, 4 without it:\n// [checkbox |] name | last modified | size | actions\nconst GRID_COLUMN_TEMPLATE_WITH_SELECT = \"40px minmax(200px, 3fr) minmax(180px, 2fr) minmax(100px, 1fr) 60px\"\nconst GRID_COLUMN_TEMPLATE_NO_SELECT = \"minmax(200px, 3fr) minmax(180px, 2fr) minmax(100px, 1fr) 60px\"\n\ninterface ObjectsTableViewProps {\n rows: BrowserRow[]\n searchTerm: string\n container: string\n account?: string\n onFolderClick: (prefix: string) => void\n onDeleteFolderSuccess: (folderName: string, deletedCount: number) => void\n onDeleteFolderError: (folderName: string, errorMessage: string) => void\n onDownloadError: (objectName: string, errorMessage: string) => void\n onDeleteObjectSuccess: (objectName: string) => void\n onDeleteObjectError: (objectName: string, errorMessage: string) => void\n onCopyObjectSuccess: (objectName: string, targetContainer: string, targetPath: string) => void\n onCopyObjectError: (objectName: string, errorMessage: string) => void\n onMoveObjectSuccess: (objectName: string, targetContainer: string, targetPath: string) => void\n onMoveObjectError: (objectName: string, errorMessage: string) => void\n onTempUrlCopySuccess: (objectName: string) => void\n onEditMetadataSuccess: (objectName: string) => void\n onEditMetadataError: (objectName: string, errorMessage: string) => void\n selectedObjects: string[]\n setSelectedObjects: (objects: string[]) => void\n // When false, the selection column (header select-all + per-row checkboxes) is\n // dropped and the grid renders one fewer column. Defaults to true so existing\n // callers keep the selectable layout.\n hasAnyBulkAction?: boolean\n}\n\nexport const ObjectsTableView = ({\n rows,\n searchTerm,\n container,\n account,\n onFolderClick,\n onDeleteFolderSuccess,\n onDeleteFolderError,\n onDownloadError,\n onDeleteObjectSuccess,\n onDeleteObjectError,\n onCopyObjectSuccess,\n onCopyObjectError,\n onMoveObjectSuccess,\n onMoveObjectError,\n onTempUrlCopySuccess,\n onEditMetadataSuccess,\n onEditMetadataError,\n selectedObjects,\n setSelectedObjects,\n hasAnyBulkAction = true,\n}: ObjectsTableViewProps) => {\n const { t } = useLingui()\n const projectId = useProjectId()\n // In-flight transfers are owned by the module store (outside React) so they\n // survive this component unmounting during folder navigation. We only read\n // them here for rendering.\n const activeTransfers = useSyncExternalStore(subscribeTransfers, getTransfersSnapshot)\n const [scrollbarWidth, setScrollbarWidth] = useState(0)\n const [deleteFolderTarget, setDeleteFolderTarget] = useState<FolderRow | null>(null)\n const [deleteObjectTarget, setDeleteObjectTarget] = useState<ObjectRow | null>(null)\n const [copyObjectTarget, setCopyObjectTarget] = useState<ObjectRow | null>(null)\n const [moveRenameObjectTarget, setMoveRenameObjectTarget] = useState<ObjectRow | null>(null)\n const [tempUrlTarget, setTempUrlTarget] = useState<ObjectRow | null>(null)\n const [editMetadataTarget, setEditMetadataTarget] = useState<ObjectRow | null>(null)\n\n // The \"Downloading...\" notification is raised by the store (one toast for all\n // in-flight transfers, dismissed when the last finishes), so starting a\n // transfer here is just the call.\n //\n // Context-menu Download: always forces a file save, regardless of type.\n const handleDownload = (row: ObjectRow) => {\n startObjectDownload({\n kind: \"download\",\n projectId,\n container,\n objectKey: row.name,\n filename: row.displayName,\n account,\n onError: onDownloadError,\n })\n }\n\n // Row-click: preview previewable types in a new tab, download everything else.\n const handlePreviewOrDownload = (row: ObjectRow) => {\n startObjectDownload({\n kind: \"preview\",\n projectId,\n container,\n objectKey: row.name,\n filename: row.displayName,\n account,\n onError: onDownloadError,\n })\n }\n\n // Cancel the in-flight transfer for a row. The store drops the entry right away\n // (UI clears on the next render, no worker round-trip) and tells the worker to\n // abort its tRPC call, which tears down the fetch so the BFF stops reading.\n // Cancellation is a user action, so confirm it with a toast, not an error.\n const handleCancelTransfer = (objectName: string) => {\n const transfer = cancelObjectDownload(container, objectName)\n if (!transfer) return\n const { message, ...options } = getObjectDownloadCancelledToast(objectName)\n toast.warning(message, options)\n }\n\n // Height measured from the space actually left below the table, plus a\n // virtualizer that stays silent until that height is known.\n const {\n ref: tableBodyRef,\n elementRef: parentRef,\n height: bodyHeight,\n virtualItems,\n totalSize,\n measureElement,\n } = useVirtualizedTableBody({ count: rows.length })\n\n // Calculate scrollbar width\n // Pad the header right by scrollbar width to keep columns aligned with the body\n useEffect(() => {\n if (parentRef.current) {\n const width = parentRef.current.offsetWidth - parentRef.current.clientWidth\n setScrollbarWidth(width)\n }\n }, [rows.length, bodyHeight])\n\n // Only object rows (not folders) are selectable\n const handleSelectObject = (name: string) => {\n if (selectedObjects.includes(name)) {\n setSelectedObjects(selectedObjects.filter((n) => n !== name))\n } else {\n setSelectedObjects([...selectedObjects, name])\n }\n }\n\n // Selection column is gated by hasAnyBulkAction — drop the leading checkbox\n // track (and one column) when no bulk action is available.\n const gridColumnTemplate = hasAnyBulkAction ? GRID_COLUMN_TEMPLATE_WITH_SELECT : GRID_COLUMN_TEMPLATE_NO_SELECT\n const columnCount = hasAnyBulkAction ? 5 : 4\n\n return (\n <>\n <div className=\"relative\">\n {/* Table Header with scrollbar padding */}\n <div style={{ paddingRight: `${scrollbarWidth}px` }}>\n <DataGrid\n columns={columnCount}\n gridColumnTemplate={gridColumnTemplate}\n className=\"objects\"\n data-testid=\"objects-table-header\"\n >\n <DataGridRow>\n {hasAnyBulkAction && (\n <DataGridHeadCell>\n <span className=\"sr-only\">\n <Trans>Select</Trans>\n </span>\n </DataGridHeadCell>\n )}\n <DataGridHeadCell>\n <Trans>Object Name</Trans>\n </DataGridHeadCell>\n <DataGridHeadCell>\n <Trans>Last Modified</Trans>\n </DataGridHeadCell>\n <DataGridHeadCell>\n <Trans>Size</Trans>\n </DataGridHeadCell>\n <DataGridHeadCell style={{ marginRight: `-${scrollbarWidth}px` }} />\n </DataGridRow>\n\n {rows.length === 0 && (\n <DataGridRow>\n <DataGridCell colSpan={columnCount}>\n <Status\n status=\"empty\"\n title={t`No objects found`}\n body={\n searchTerm\n ? t`No objects match your search. Try adjusting your search term.`\n : t`This folder is empty.`\n }\n />\n </DataGridCell>\n </DataGridRow>\n )}\n </DataGrid>\n </div>\n\n {/* Virtualized Table Body — sized to the space actually left below the\n table, so banners above it shrink the table instead of growing the\n page. */}\n <div\n ref={tableBodyRef}\n className=\"overflow-auto\"\n style={{ height: `${bodyHeight ?? 0}px` }}\n data-testid=\"objects-table-body\"\n >\n <DataGrid\n columns={columnCount}\n gridColumnTemplate={gridColumnTemplate}\n style={{\n height: `${totalSize}px`,\n width: \"100%\",\n position: \"relative\",\n }}\n >\n {virtualItems.map((virtualRow) => {\n const row = rows[virtualRow.index]\n const isFolder = row.kind === \"folder\"\n const activeTransfer = !isFolder ? activeTransfers.get(transferKey(container, row.name)) : undefined\n const isDownloading = activeTransfer?.kind === \"download\"\n const isPreviewing = activeTransfer?.kind === \"preview\"\n const isStreaming = activeTransfer !== undefined\n const rowDisplayName = row.displayName\n const isSelected = !isFolder && selectedObjects.includes(row.name)\n\n return (\n <DataGridRow\n key={row.name}\n data-index={virtualRow.index}\n ref={measureElement}\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n width: \"100%\",\n transform: `translateY(${virtualRow.start}px)`,\n display: \"grid\",\n gridTemplateColumns: gridColumnTemplate,\n alignItems: \"stretch\",\n }}\n data-testid={`object-row-${row.name}`}\n >\n {/* Checkbox — only for object rows; folders get an empty cell.\n The whole column is omitted when no bulk action is available. */}\n {hasAnyBulkAction && (\n <DataGridCell onClick={(e) => e.stopPropagation()}>\n {isFolder ? (\n // Folders have no bulk-delete operation in Swift — show a\n // disabled checkbox with an explanatory tooltip so the column\n // stays aligned and the user understands why. Folder deletion\n // goes through the row menu (\"Delete Recursively\") instead.\n <Tooltip triggerEvent=\"hover\" placement=\"right\">\n <TooltipTrigger>\n <Checkbox\n disabled\n aria-label={t`Folders cannot be bulk-deleted. Use the row menu to delete a folder.`}\n data-testid={`select-folder-disabled-${row.name}`}\n />\n </TooltipTrigger>\n <TooltipContent>\n <Trans>Folders cannot be bulk-deleted. Use the row menu to delete a folder.</Trans>\n </TooltipContent>\n </Tooltip>\n ) : (\n <Checkbox\n checked={isSelected}\n disabled={isStreaming}\n onChange={() => handleSelectObject(row.name)}\n data-testid={`select-object-${row.name}`}\n />\n )}\n </DataGridCell>\n )}\n\n {/* Name */}\n <DataGridCell className=\"min-w-0 overflow-hidden\">\n {isFolder ? (\n <button\n type=\"button\"\n className=\"focus-visible:outline-theme-focus flex min-w-0 items-center gap-2 rounded text-left hover:underline focus-visible:outline focus-visible:outline-2\"\n onClick={() => onFolderClick(row.name)}\n data-testid={`folder-${row.name}`}\n title={row.displayName}\n >\n <MdFolder size={18} className=\"text-theme-light shrink-0\" />\n <span className=\"truncate\">{row.displayName}</span>\n </button>\n ) : (\n <button\n type=\"button\"\n className=\"focus-visible:outline-theme-focus flex min-w-0 items-center gap-2 rounded text-left hover:underline focus-visible:outline-2 disabled:cursor-wait disabled:opacity-60\"\n onClick={() => handlePreviewOrDownload(row as ObjectRow)}\n disabled={isStreaming}\n data-testid={`preview-${row.name}`}\n title={\n isStreaming\n ? isPreviewing\n ? t`Loading Preview...`\n : t`Downloading...`\n : isPreviewableContentType((row as ObjectRow).content_type ?? \"\")\n ? t`Preview ${rowDisplayName}`\n : t`Download ${rowDisplayName}`\n }\n >\n {isStreaming && isPreviewing ? (\n <Spinner size=\"small\" className=\"shrink-0\" data-testid={`preview-spinner-${row.name}`} />\n ) : (\n <MdDescription size={18} className=\"text-theme-light shrink-0\" />\n )}\n <span className=\"truncate\">{row.displayName}</span>\n </button>\n )}\n </DataGridCell>\n\n {/* Last Modified — doubles as the transfer progress + cancel cell\n while a download/preview is in flight. */}\n <DataGridCell onClick={(e) => e.stopPropagation()}>\n {isStreaming && activeTransfer && !isFolder ? (\n <div className=\"flex items-center gap-2\">\n <RowTransferProgress downloadId={activeTransfer.downloadId} isPreviewing={isPreviewing} />\n <button\n type=\"button\"\n onClick={() => handleCancelTransfer(row.name)}\n aria-label={t`Cancel`}\n title={t`Cancel`}\n className=\"focus-visible:outline-theme-focus text-theme-light hover:text-theme-danger shrink-0 cursor-pointer rounded focus-visible:outline-2\"\n data-testid={`cancel-transfer-${row.name}`}\n >\n <Icon icon=\"cancel\" size={18} />\n </button>\n </div>\n ) : !isFolder && row.last_modified ? (\n (formatSwiftDate(row.last_modified) ?? \"—\")\n ) : (\n \"—\"\n )}\n </DataGridCell>\n\n {/* Size */}\n <DataGridCell>{!isFolder ? formatBytesBinary(row.bytes) : \"—\"}</DataGridCell>\n\n {/* Actions */}\n <DataGridCell onClick={(e) => e.stopPropagation()}>\n <PopupMenu>\n <PopupMenuOptions>\n {isFolder ? (\n // Folder actions\n <PopupMenuItem\n label={t`Delete Recursively`}\n onClick={() => setDeleteFolderTarget(row as FolderRow)}\n data-testid={`delete-recursively-action-${row.name}`}\n />\n ) : (\n // File actions\n <>\n <PopupMenuItem\n label={isDownloading ? t`Downloading...` : t`Download Object`}\n disabled={isStreaming}\n onClick={() => handleDownload(row as ObjectRow)}\n data-testid={`download-action-${row.name}`}\n />\n <PopupMenuItem\n label={t`Edit Object Metadata`}\n disabled={isStreaming}\n onClick={() => setEditMetadataTarget(row as ObjectRow)}\n data-testid={`edit-metadata-action-${row.name}`}\n />\n <PopupMenuItem\n label={t`Copy Object`}\n disabled={isStreaming}\n onClick={() => setCopyObjectTarget(row as ObjectRow)}\n data-testid={`copy-action-${row.name}`}\n />\n <PopupMenuItem\n label={t`Move/Rename Object`}\n disabled={isStreaming}\n onClick={() => setMoveRenameObjectTarget(row as ObjectRow)}\n data-testid={`move-rename-action-${row.name}`}\n />\n <PopupMenuItem\n label={t`Share Object URL`}\n disabled={isStreaming}\n onClick={() => setTempUrlTarget(row as ObjectRow)}\n data-testid={`temp-url-action-${row.name}`}\n />\n <PopupMenuItem\n label={t`Delete Object`}\n disabled={isStreaming}\n onClick={() => setDeleteObjectTarget(row as ObjectRow)}\n data-testid={`delete-action-${row.name}`}\n />\n </>\n )}\n </PopupMenuOptions>\n </PopupMenu>\n </DataGridCell>\n </DataGridRow>\n )\n })}\n </DataGrid>\n </div>\n </div>\n\n <DeleteFolderModal\n isOpen={deleteFolderTarget !== null}\n folder={deleteFolderTarget}\n onClose={() => setDeleteFolderTarget(null)}\n onSuccess={onDeleteFolderSuccess}\n onError={onDeleteFolderError}\n />\n\n <DeleteObjectModal\n isOpen={deleteObjectTarget !== null}\n object={deleteObjectTarget}\n onClose={() => setDeleteObjectTarget(null)}\n onSuccess={onDeleteObjectSuccess}\n onError={onDeleteObjectError}\n />\n\n <CopyObjectModal\n isOpen={copyObjectTarget !== null}\n object={copyObjectTarget}\n onClose={() => setCopyObjectTarget(null)}\n onSuccess={onCopyObjectSuccess}\n onError={onCopyObjectError}\n />\n\n <MoveRenameObjectModal\n isOpen={moveRenameObjectTarget !== null}\n object={moveRenameObjectTarget}\n onClose={() => setMoveRenameObjectTarget(null)}\n onSuccess={onMoveObjectSuccess}\n onError={onMoveObjectError}\n />\n\n <GenerateTempUrlModal\n isOpen={tempUrlTarget !== null}\n object={tempUrlTarget}\n account={account}\n onClose={() => setTempUrlTarget(null)}\n onCopySuccess={onTempUrlCopySuccess}\n />\n\n <EditObjectMetadataModal\n isOpen={editMetadataTarget !== null}\n object={editMetadataTarget}\n onClose={() => setEditMetadataTarget(null)}\n onSuccess={onEditMetadataSuccess}\n onError={onEditMetadataError}\n />\n </>\n )\n}\n","import { Breadcrumb, BreadcrumbItem } from \"@cloudoperators/juno-ui-components\"\nimport { useLingui } from \"@lingui/react/macro\"\nimport { MdStorage, MdOutlineInventory2, MdInventory2, MdFolder, MdFolderOpen } from \"react-icons/md\"\n\n// ── Breadcrumb helpers ────────────────────────────────────────────────────────\n\n/**\n * Splits the current prefix into navigable breadcrumb segments.\n * e.g. \"a/b/c/\" → [{ label: \"a\", prefix: \"a/\" }, { label: \"b\", prefix: \"a/b/\" }, { label: \"c\", prefix: \"a/b/c/\" }]\n */\nfunction prefixToSegments(prefix: string): { label: string; prefix: string }[] {\n if (!prefix) return []\n // Remove trailing slash before splitting so we don't get a trailing empty segment\n const parts = prefix.replace(/\\/$/, \"\").split(\"/\").filter(Boolean)\n return parts.map((label, i) => ({\n label,\n prefix: parts.slice(0, i + 1).join(\"/\") + \"/\",\n }))\n}\n\n// Active crumb gets a pill background to match the design — visually marks the current location.\nconst activeCrumbClass = \"bg-theme-background-lvl-4 rounded px-2 py-0.5\"\n\n// ── ObjectsFileNavigation ─────────────────────────────────────────────────────\n\ninterface ObjectsFileNavigationProps {\n containerName: string\n currentPrefix: string\n onContainersClick: () => void\n onPrefixClick: (prefix: string) => void\n}\n\nexport const ObjectsFileNavigation = ({\n containerName,\n currentPrefix,\n onContainersClick,\n onPrefixClick,\n}: ObjectsFileNavigationProps) => {\n const { t } = useLingui()\n\n const prefixSegments = prefixToSegments(currentPrefix)\n\n // The last segment (deepest folder) is the active crumb — non-clickable.\n // All segments before it are clickable navigation targets.\n const isAtRoot = prefixSegments.length === 0\n\n return (\n <div className=\"mb-2 px-2 pt-2\">\n <Breadcrumb>\n {/* \"All containers\" root — always navigates back to the container list */}\n {/* TODO: BreadcrumbItem.label is typed as string but renders ReactNode — remove cast once Juno fixes the type */}\n <BreadcrumbItem\n onClick={onContainersClick}\n label={\n (\n <span className=\"flex items-center gap-1\">\n <MdStorage size={15} className=\"shrink-0\" />\n {t`All containers`}\n </span>\n ) as unknown as string\n }\n />\n\n {/* Container name — inventory/box icon distinguishes it from folders;\n outlined when active (current root level), filled when navigable */}\n {/* TODO: BreadcrumbItem.label is typed as string but renders ReactNode — remove cast once Juno fixes the type */}\n <BreadcrumbItem\n onClick={isAtRoot ? undefined : () => onPrefixClick(\"\")}\n active={isAtRoot}\n label={\n (\n <span className={`flex items-center gap-1 ${isAtRoot ? activeCrumbClass : \"\"}`}>\n {isAtRoot ? (\n <MdOutlineInventory2 size={15} className=\"shrink-0\" />\n ) : (\n <MdInventory2 size={15} className=\"shrink-0\" />\n )}\n {containerName}\n </span>\n ) as unknown as string\n }\n />\n\n {/* One crumb per prefix segment:\n - intermediate segments → MdFolder (filled, clickable)\n - last segment → MdFolderOpen (outlined, active/non-clickable) */}\n {/* TODO: BreadcrumbItem.label is typed as string but renders ReactNode — remove cast once Juno fixes the type */}\n {prefixSegments.map((seg, i) => {\n const isLast = i === prefixSegments.length - 1\n return (\n <BreadcrumbItem\n key={seg.prefix}\n onClick={isLast ? undefined : () => onPrefixClick(seg.prefix)}\n active={isLast}\n label={\n (\n <span className={`flex items-center gap-1 ${isLast ? activeCrumbClass : \"\"}`}>\n {isLast ? (\n <MdFolderOpen size={15} className=\"shrink-0\" />\n ) : (\n <MdFolder size={15} className=\"shrink-0\" />\n )}\n {seg.label}\n </span>\n ) as unknown as string\n }\n />\n )\n })}\n </Breadcrumb>\n </div>\n )\n}\n","import { useState, useRef } from \"react\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport { Modal, TextInput, Stack, Message } from \"@cloudoperators/juno-ui-components\"\nimport { useParams } from \"@tanstack/react-router\"\nimport { BrowserRow } from \"./\"\n\ninterface CreateFolderModalProps {\n isOpen: boolean\n currentPrefix: string\n onClose: () => void\n onSuccess?: (folderName: string) => void\n existingRows?: BrowserRow[]\n}\n\nexport const CreateFolderModal = ({\n isOpen,\n currentPrefix,\n onClose,\n onSuccess,\n existingRows = [],\n}: CreateFolderModalProps) => {\n const { t } = useLingui()\n const projectId = useProjectId()\n const { containerName } = useParams({\n from: \"/_auth/projects/$projectId/storage/$provider/$storageType/$containerName/objects/\",\n })\n\n const [folderName, setFolderName] = useState(\"\")\n const [nameError, setNameError] = useState<string | null>(null)\n const [submitError, setSubmitError] = useState<string | null>(null)\n\n const utils = trpcReact.useUtils()\n\n // useRef so the submitted name survives re-renders triggered by\n // createFolderMutation.reset() inside handleClose() before onSuccess fires.\n const submittedNameRef = useRef(\"\")\n\n const createFolderMutation = trpcReact.storage.swift.createFolder.useMutation({\n onSuccess: () => {\n utils.storage.swift.listObjects.invalidate()\n onSuccess?.(submittedNameRef.current)\n handleClose()\n },\n onError: (error) => {\n if (error.data?.code === \"CONFLICT\") {\n setNameError(t`A folder with this name already exists`)\n setSubmitError(null)\n } else {\n setSubmitError(error.message || t`The folder could not be created. Try again.`)\n }\n },\n })\n\n const handleClose = () => {\n setFolderName(\"\")\n setNameError(null)\n setSubmitError(null)\n createFolderMutation.reset()\n onClose()\n }\n\n const validateName = (name: string): boolean => {\n const trimmed = name.trim()\n if (!trimmed) {\n setNameError(t`Folder name is required`)\n return false\n }\n if (trimmed.includes(\"/\")) {\n setNameError(t`Folder name cannot contain slashes`)\n return false\n }\n if (trimmed !== name) {\n setNameError(t`Folder name cannot have leading or trailing whitespace`)\n return false\n }\n\n const newPath = `${currentPrefix}${trimmed}/`\n if (existingRows.some((row) => row.kind === \"folder\" && row.name === newPath)) {\n setNameError(t`A folder with this name already exists`)\n return false\n }\n\n setNameError(null)\n return true\n }\n\n const handleNameChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const value = e.target.value\n setFolderName(value)\n setSubmitError(null)\n if (nameError) validateName(value)\n }\n\n const handleSubmit = () => {\n if (!validateName(folderName)) return\n setSubmitError(null)\n submittedNameRef.current = folderName.trim()\n const folderPath = `${currentPrefix}${submittedNameRef.current}/`\n createFolderMutation.mutate({ project_id: projectId, container: containerName, folderPath })\n }\n\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === \"Enter\" && !createFolderMutation.isPending) handleSubmit()\n }\n\n // Display the path where the folder will be created, e.g. \"/ \" or \"test/ \"\n const parentPath = currentPrefix ? currentPrefix : \"/\"\n\n if (!isOpen) return null\n\n return (\n <Modal\n title={\n <span className=\"flex max-w-100 items-center gap-1\">\n <span className=\"shrink-0\">\n <Trans>Create folder below:</Trans>\n </span>\n <span className=\"truncate\" title={parentPath}>\n {parentPath}\n </span>\n </span>\n }\n open={isOpen}\n onCancel={handleClose}\n confirmButtonLabel={t`Create Folder`}\n onConfirm={handleSubmit}\n cancelButtonLabel={t`Cancel`}\n size=\"small\"\n disableConfirmButton={createFolderMutation.isPending || !folderName.trim()}\n disableCancelButton={createFolderMutation.isPending}\n disableCloseButton={createFolderMutation.isPending}\n >\n <Stack direction=\"vertical\" gap=\"6\">\n {submitError && (\n <Message\n variant=\"error\"\n dismissible\n onDismiss={() => setSubmitError(null)}\n role=\"alert\"\n aria-live=\"assertive\"\n data-testid=\"create-folder-error\"\n >\n {submitError}\n </Message>\n )}\n <p className=\"text-theme-default\">\n <Trans>\n Folders in object storage are virtual — they are created as zero-byte placeholder objects with a trailing\n slash. The folder will appear once created.\n </Trans>\n </p>\n <TextInput\n label={t`Folder name`}\n required\n value={folderName}\n onChange={handleNameChange}\n onKeyDown={handleKeyDown}\n invalid={!!nameError}\n errortext={nameError || undefined}\n disabled={createFolderMutation.isPending}\n autoFocus\n placeholder={t`folder-name`}\n />\n </Stack>\n </Modal>\n )\n}\n","import { useState, useRef } from \"react\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { Modal, Stack, Spinner } from \"@cloudoperators/juno-ui-components\"\nimport { MdCloudUpload } from \"react-icons/md\"\nimport { trpcClient, trpcReact } from \"@/client/trpcClient\"\nimport { cn } from \"@/client/utils/cn\"\nimport { formatBytesBinary } from \"@/client/utils/formatBytes\"\n\ninterface UploadObjectModalProps {\n isOpen: boolean\n currentPrefix: string\n container: string\n projectId: string\n account?: string\n onClose: () => void\n onSuccess?: (objectName: string) => void\n onError?: (objectName: string, errorMessage: string) => void\n onCancelled?: (objectName: string) => void\n}\n\nexport const UploadObjectModal = ({\n isOpen,\n currentPrefix,\n container,\n projectId,\n account,\n onClose,\n onSuccess,\n onError,\n onCancelled,\n}: UploadObjectModalProps) => {\n const { t } = useLingui()\n\n const [selectedFile, setSelectedFile] = useState<File | null>(null)\n const [fileError, setFileError] = useState<string | null>(null)\n const [isDragging, setIsDragging] = useState(false)\n const [uploadId, setUploadId] = useState<string | null>(null)\n const [uploadError, setUploadError] = useState<string | null>(null)\n const [isPending, setIsPending] = useState(false)\n\n const submittedNameRef = useRef(\"\")\n const fileInputRef = useRef<HTMLInputElement>(null)\n const abortControllerRef = useRef<AbortController | null>(null)\n\n const utils = trpcReact.useUtils()\n\n const handleCancelUpload = () => {\n abortControllerRef.current?.abort()\n }\n\n // Subscribe to upload progress — uploadId is set before the upload starts\n // so the subscription is active from the very first byte.\n const { data: uploadProgress } = trpcReact.storage.swift.watchUploadProgress.useSubscription(\n { uploadId: uploadId ?? \"\" },\n { enabled: !!uploadId && isPending }\n )\n\n const handleClose = () => {\n if (isPending) return\n resetAndClose()\n }\n\n const resetAndClose = () => {\n setSelectedFile(null)\n setFileError(null)\n setIsDragging(false)\n setUploadId(null)\n setUploadError(null)\n if (fileInputRef.current) fileInputRef.current.value = \"\"\n onClose()\n }\n\n const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0]\n if (file) {\n setFileError(null)\n setUploadError(null)\n setSelectedFile(file)\n }\n }\n\n const handleDragOver = (e: React.DragEvent<HTMLLabelElement>) => {\n e.preventDefault()\n e.stopPropagation()\n if (isPending) return\n setIsDragging(true)\n }\n\n const handleDragLeave = (e: React.DragEvent<HTMLLabelElement>) => {\n e.preventDefault()\n e.stopPropagation()\n if (isPending) return\n setIsDragging(false)\n }\n\n const handleDrop = (e: React.DragEvent<HTMLLabelElement>) => {\n e.preventDefault()\n e.stopPropagation()\n setIsDragging(false)\n if (isPending) return\n const file = e.dataTransfer.files?.[0]\n if (file) {\n setFileError(null)\n setUploadError(null)\n setSelectedFile(file)\n }\n }\n\n const handleSubmit = async () => {\n if (!selectedFile) {\n setFileError(t`Please select a file to upload`)\n return\n }\n\n const objectName = `${currentPrefix}${selectedFile.name}`\n const activeUploadId = `${container}:${objectName}:${crypto.randomUUID()}`\n submittedNameRef.current = selectedFile.name\n setUploadError(null)\n\n const controller = new AbortController()\n abortControllerRef.current = controller\n\n // Compute uploadId client-side before upload starts — subscription must be\n // active before the first progress event fires from the BFF.\n setUploadId(activeUploadId)\n setIsPending(true)\n\n try {\n // Metadata is sent as custom headers via tRPC operation context —\n // no shared mutable state, safe for concurrent uploads.\n const uploadContext = {\n headers: {\n \"x-upload-project-id\": projectId,\n \"x-upload-container\": container,\n \"x-upload-object\": objectName,\n \"x-upload-type\": selectedFile.type || \"application/octet-stream\",\n \"x-upload-size\": String(selectedFile.size),\n \"x-upload-id\": activeUploadId,\n ...(account ? { \"x-upload-account\": account } : {}),\n },\n }\n\n await trpcClient.storage.swift.uploadObject.mutate(selectedFile, {\n context: uploadContext,\n signal: controller.signal,\n })\n\n utils.storage.swift.listObjects.invalidate({ container })\n onSuccess?.(submittedNameRef.current)\n resetAndClose()\n } catch (err) {\n const isAborted =\n err instanceof Error &&\n (err.name === \"AbortError\" ||\n err.message === \"Request canceled\" ||\n err.message.includes(\"signal is aborted\") ||\n err.message.includes(\"aborted\"))\n if (isAborted) {\n onCancelled?.(submittedNameRef.current)\n resetAndClose()\n return\n }\n const message = err instanceof Error ? err.message : String(err)\n setUploadError(message)\n onError?.(submittedNameRef.current, message)\n } finally {\n setIsPending(false)\n setUploadId(null)\n abortControllerRef.current = null\n }\n }\n\n // isPending is tracked via useState above\n const progressPct = uploadProgress?.percent ?? null\n\n if (!isOpen) return null\n\n const parentPath = currentPrefix || \"/\"\n const selectedObjectName = selectedFile ? `${currentPrefix}${selectedFile.name}` : \"\"\n\n return (\n <Modal\n title={\n <span className=\"flex max-w-100 items-center gap-1\">\n <span className=\"shrink-0\">\n <Trans>Upload object to:</Trans>\n </span>\n <span className=\"truncate\" title={parentPath}>\n {parentPath}\n </span>\n </span>\n }\n open={isOpen}\n onCancel={isPending ? handleCancelUpload : handleClose}\n confirmButtonLabel={isPending ? t`Uploading...` : t`Upload`}\n onConfirm={handleSubmit}\n cancelButtonLabel={isPending ? t`Cancel upload` : t`Cancel`}\n size=\"small\"\n disableConfirmButton={isPending || !selectedFile}\n disableCloseButton={isPending}\n >\n <Stack direction=\"vertical\" gap=\"4\">\n {/* Upload error */}\n {uploadError && (\n <p className=\"text-theme-error\">\n <Trans>Upload failed: {uploadError}</Trans>\n </p>\n )}\n\n {/* Object path preview */}\n {selectedFile && !isPending && (\n <p className=\"text-theme-default\">\n <Trans>\n Object will be uploaded as: <span className=\"font-semibold\">{selectedObjectName}</span>\n </Trans>\n </p>\n )}\n\n {/* File drop zone — mirrors CreateImageModal pattern */}\n <div>\n <label\n htmlFor=\"upload-object-file\"\n className={cn(\n \"flex flex-col items-center justify-center rounded-lg border-2 border-dashed px-6 py-8 text-center transition-colors\",\n isDragging\n ? \"border-theme-accent bg-theme-background-lvl-2\"\n : isPending\n ? \"border-theme-background-lvl-4 pointer-events-none cursor-not-allowed opacity-60\"\n : \"border-theme-background-lvl-4 hover:border-theme-accent hover:bg-theme-background-lvl-1 cursor-pointer\"\n )}\n onDragOver={handleDragOver}\n onDragLeave={handleDragLeave}\n onDrop={handleDrop}\n >\n <MdCloudUpload className=\"text-theme-light mb-2\" size={40} />\n <p className=\"text-theme-default text-sm font-medium\">\n {isDragging ? (\n <span>{t`Drop your 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-theme-light mt-1 text-xs\">{t`Any file type`}</p>\n <input\n ref={fileInputRef}\n id=\"upload-object-file\"\n type=\"file\"\n className=\"hidden\"\n onChange={handleFileChange}\n disabled={isPending}\n />\n </label>\n\n {/* Selected file info */}\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 min-w-0 items-center gap-2\">\n <svg className=\"h-4 w-4 shrink-0 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=\"truncate text-gray-700\">{selectedFile.name}</span>\n <span className=\"shrink-0 text-gray-400\">({formatBytesBinary(selectedFile.size)})</span>\n </div>\n {!isPending && (\n <button\n type=\"button\"\n onClick={() => {\n setSelectedFile(null)\n setFileError(null)\n setUploadError(null)\n if (fileInputRef.current) fileInputRef.current.value = \"\"\n }}\n className=\"ml-2 shrink-0 font-medium text-red-600 hover:text-red-800\"\n >\n {t`Remove`}\n </button>\n )}\n </div>\n )}\n\n {fileError && <p className=\"mt-1 text-xs text-red-600\">{fileError}</p>}\n </div>\n\n {/* Upload progress */}\n {isPending && (\n <div className=\"flex flex-col gap-2\">\n <span className=\"text-theme-light flex items-center gap-2 text-sm\">\n <Spinner size=\"small\" />\n {progressPct !== null ? <Trans>Uploading... {progressPct}%</Trans> : <Trans>Uploading...</Trans>}\n </span>\n {progressPct !== null && (\n <div className=\"bg-theme-background-lvl-2 h-1.5 w-full overflow-hidden rounded-full\">\n <div\n className=\"bg-theme-accent h-1.5 rounded-full transition-all duration-150\"\n style={{ width: `${progressPct}%` }}\n />\n </div>\n )}\n </div>\n )}\n </Stack>\n </Modal>\n )\n}\n","import { z } from \"zod\"\nimport { useForm, useStore } from \"@tanstack/react-form\"\nimport { useEffect } from \"react\"\nimport { Plural, Trans, useLingui } from \"@lingui/react/macro\"\nimport { plural } from \"@lingui/core/macro\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { Modal, Status, Stack, Form, FormSection, TextInput } from \"@cloudoperators/juno-ui-components\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport { useModalTracking } from \"@/client/hooks/useModalTracking\"\n\n// Max number of object names shown in the list before truncating\nconst MAX_VISIBLE = 20\n\n// User must type this word to enable the destructive action.\nconst CONFIRM_WORD = \"delete\"\n\ninterface DeleteObjectsModalProps {\n isOpen: boolean\n /** Display names shown in the list (e.g. \"file.txt\", \"folder/file.txt\") */\n objectNames: string[]\n /** Full object keys passed to bulkDelete — same as objectNames in most cases */\n objectKeys: string[]\n container: string\n account?: string\n onClose: () => void\n onSuccess?: (numberDeleted: number) => void\n onError?: (errorMessage: string, deletedKeys: string[]) => void\n}\n\nexport const DeleteObjectsModal = ({\n isOpen,\n objectNames,\n objectKeys,\n container,\n account,\n onClose,\n onSuccess,\n onError,\n}: DeleteObjectsModalProps) => {\n const { t, i18n } = useLingui()\n const projectId = useProjectId()\n\n const utils = trpcReact.useUtils()\n\n const { trackClose, markSubmitted, resetTracking } = useModalTracking({\n isOpen,\n actionPrefix: \"storage.swift.objects.delete\",\n })\n\n const formSchema = z.object({\n confirm: z\n .string()\n .transform((val) => val.trim())\n .refine((value) => value === CONFIRM_WORD, {\n message: t`Type \"${CONFIRM_WORD}\" 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 (bulkDeleteMutation.isPending) return\n\n markSubmitted()\n // bulkDelete expects fully-qualified paths: /<container>/<object>\n // Each segment must be URL-encoded to match Swift's bulk-delete protocol —\n // object keys containing newlines or % would otherwise corrupt the request body.\n const objects = objectKeys.map((key) => `/${encodeURIComponent(container)}/${encodeURIComponent(key)}`)\n bulkDeleteMutation.mutate({\n project_id: projectId,\n objects,\n ...(account ? { account } : {}),\n })\n },\n })\n\n const canDelete = useStore(form.store, (state) => state.isSubmitting || state.values.confirm.trim() !== CONFIRM_WORD)\n\n // Type-to-confirm guard. Bulk deletion is irreversible, so a single click is\n // not enough — the user must type CONFIRM_WORD first.\n\n const bulkDeleteMutation = trpcReact.storage.swift.bulkDelete.useMutation({\n onSuccess: (result) => {\n utils.storage.swift.listObjects.invalidate({ container })\n if (result.errors.length > 0) {\n const errorMessages = result.errors.map((e) => `${e.path}: ${e.error}`).join(\"\\n\")\n // Derive keys that were actually deleted so the parent can prune them from selection\n const failedPaths = new Set(result.errors.map((e) => e.path))\n const deletedKeys = objectKeys.filter(\n (key) => !failedPaths.has(`/${encodeURIComponent(container)}/${encodeURIComponent(key)}`)\n )\n\n const { numberDeleted } = result\n\n const partialResultMessage =\n numberDeleted > 0\n ? `${t`${numberDeleted} objects were deleted successfully, but some deletions failed.`}\\n${errorMessages}`\n : errorMessages\n onError?.(partialResultMessage, deletedKeys)\n } else {\n onSuccess?.(result.numberDeleted)\n }\n },\n onError: (error) => {\n onError?.(error.message, [])\n },\n onSettled: () => {\n handleClose()\n },\n })\n\n useEffect(() => {\n if (!isOpen) {\n bulkDeleteMutation.reset()\n form.reset()\n resetTracking()\n }\n }, [isOpen, resetTracking])\n\n const handleClose = () => {\n trackClose()\n bulkDeleteMutation.reset()\n form.reset()\n resetTracking()\n onClose()\n }\n\n if (!isOpen || objectKeys.length === 0) return null\n\n const totalCount = objectKeys.length\n const visibleNames = objectNames.slice(0, MAX_VISIBLE)\n const hiddenCount = totalCount - visibleNames.length\n const isPending = bulkDeleteMutation.isPending\n\n return (\n <Modal\n title={<Plural value={totalCount} one=\"Delete # Object\" other=\"Delete # Objects\" />}\n open={isOpen}\n onCancel={handleClose}\n confirmButtonLabel={\n isPending ? t`Deleting...` : i18n._(plural(totalCount, { one: \"Delete Object\", other: \"Delete Objects\" }))\n }\n confirmButtonVariant=\"primary-danger\"\n cancelButtonLabel={t`Cancel`}\n onConfirm={form.handleSubmit}\n disableConfirmButton={isPending || canDelete}\n disableCancelButton={isPending}\n disableCloseButton={isPending}\n size=\"small\"\n >\n {isPending ? (\n <Status status=\"progress\" title={t`Deleting...`} className=\"mt-0\" />\n ) : (\n <Stack direction=\"vertical\" gap=\"4\">\n <p className=\"text-theme-default overflow-x-hidden wrap-anywhere\">\n <Trans>The selected objects will be permanently deleted. This cannot be undone.</Trans>\n </p>\n\n <div>\n <h3 className=\"jn:text-theme-high mb-3 font-semibold\">\n <Trans>Objects to be deleted ({totalCount})</Trans>\n </h3>\n <div className=\"jn:bg-theme-background-lvl-1 max-h-48 overflow-y-auto rounded p-4\">\n <ul className=\"space-y-1\">\n {visibleNames.map((name) => (\n <li key={name} className=\"jn:text-theme-default text-sm\">\n {name}\n </li>\n ))}\n </ul>\n {hiddenCount > 0 && (\n <p className=\"text-theme-light mt-2 text-xs\">\n <Trans>... and {hiddenCount} more</Trans>\n </p>\n )}\n </div>\n </div>\n\n <Form\n className=\"mb-0\"\n id=\"delete-objects-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 \"${CONFIRM_WORD}\" to confirm`}\n placeholder={CONFIRM_WORD}\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(\", \") ||\n undefined\n }\n disabled={isPending}\n autoFocus\n required\n />\n )}\n />\n </FormSection>\n </Form>\n </Stack>\n )}\n </Modal>\n )\n}\n","import { useState, useEffect, useRef, startTransition } from \"react\"\nimport { Plural, Trans, useLingui } from \"@lingui/react/macro\"\nimport { plural } from \"@lingui/core/macro\"\nimport {\n Button,\n Checkbox,\n DataGridToolbar,\n PopupMenu,\n PopupMenuItem,\n PopupMenuOptions,\n PopupMenuToggle,\n SearchInput,\n Status,\n Stack,\n toast,\n} from \"@cloudoperators/juno-ui-components\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport { ObjectSummary } from \"@/server/Storage/types/swift\"\nimport { parseSwiftDate } from \"@/client/utils/formatSwiftDate\"\nimport { SortInput } from \"@/client/components/ListToolbar/SortInput\"\nimport { SortSettings } from \"@/client/components/ListToolbar/types\"\nimport { useNavigate } from \"@tanstack/react-router\"\nimport { Route } from \"../../../$provider/$storageType/$containerName/objects\"\nimport { ObjectsTableView } from \"./ObjectsTableView\"\nimport { ObjectsFileNavigation } from \"./ObjectsFileNavigation\"\nimport { CreateFolderModal } from \"./CreateFolderModal\"\nimport { UploadObjectModal } from \"./UploadObjectModal\"\nimport { DeleteObjectsModal } from \"./DeleteObjectsModal\"\nimport {\n getContainerAccessErrorToast,\n getFolderCreatedToast,\n getFolderDeletedToast,\n getFolderDeleteErrorToast,\n getObjectDownloadErrorToast,\n getObjectDeletedToast,\n getObjectDeleteErrorToast,\n getObjectCopiedToast,\n getObjectCopyErrorToast,\n getObjectMovedToast,\n getObjectMoveErrorToast,\n getTempUrlCopiedToast,\n getObjectMetadataUpdatedToast,\n getObjectMetadataUpdateErrorToast,\n getObjectUploadedToast,\n getObjectUploadCancelledToast,\n getObjectUploadErrorToast,\n getObjectsBulkDeletedToast,\n getObjectsBulkDeleteErrorToast,\n} from \"./ObjectToastNotifications\"\n\n// ── Prefix helpers ────────────────────────────────────────────────────────────\n\nconst encodePrefix = (prefix: string): string => {\n const bytes = new TextEncoder().encode(prefix)\n const binString = Array.from(bytes, (byte) => String.fromCodePoint(byte)).join(\"\")\n return btoa(binString)\n}\n\nconst decodePrefix = (encoded: string | undefined): string => {\n if (!encoded) return \"\"\n try {\n const binString = atob(encoded)\n const bytes = Uint8Array.from(binString, (char) => char.codePointAt(0)!)\n return new TextDecoder().decode(bytes)\n } catch {\n return \"\"\n }\n}\n\n// ── Row types ─────────────────────────────────────────────────────────────────\n\nexport interface FolderRow {\n kind: \"folder\"\n name: string\n displayName: string\n}\n\nexport interface ObjectRow {\n kind: \"object\"\n name: string\n displayName: string\n bytes: number\n last_modified: string | undefined\n content_type: string | undefined\n}\n\nexport type BrowserRow = FolderRow | ObjectRow\n\n// ── Build folder + object rows from a flat Swift listing ──────────────────────\n\nexport function buildRows(objects: ObjectSummary[], prefix: string): BrowserRow[] {\n const folders: FolderRow[] = []\n const files: ObjectRow[] = []\n const seenFolders = new Set<string>()\n\n for (const obj of objects) {\n const stripped = obj.name.startsWith(prefix) ? obj.name.slice(prefix.length) : obj.name\n if (stripped === \"\" || stripped === \"/\") continue\n const slashIdx = stripped.indexOf(\"/\")\n if (slashIdx > 0) {\n const folderPrefix = prefix + stripped.slice(0, slashIdx + 1)\n if (!seenFolders.has(folderPrefix)) {\n seenFolders.add(folderPrefix)\n folders.push({ kind: \"folder\", name: folderPrefix, displayName: stripped.slice(0, slashIdx) })\n }\n continue\n }\n if (\n (obj.content_type === \"application/directory\" || obj.name.endsWith(\"/\")) &&\n (slashIdx === -1 || slashIdx === stripped.length - 1)\n ) {\n const folderPrefix = obj.name.endsWith(\"/\") ? obj.name : obj.name + \"/\"\n if (!seenFolders.has(folderPrefix)) {\n seenFolders.add(folderPrefix)\n folders.push({ kind: \"folder\", name: folderPrefix, displayName: stripped.replace(/\\/$/, \"\") })\n }\n continue\n }\n files.push({\n kind: \"object\",\n name: obj.name,\n displayName: stripped,\n bytes: obj.bytes,\n last_modified: obj.last_modified,\n content_type: obj.content_type,\n })\n }\n\n return [...folders, ...files]\n}\n\n// ── Sort key allowlist ────────────────────────────────────────────────────────\n\ntype SortKey = \"name\" | \"last_modified\" | \"bytes\"\nconst ALLOWED_SORT_KEYS: SortKey[] = [\"name\", \"last_modified\", \"bytes\"]\n\nconst resolveSortBy = (sortBy: SortSettings[\"sortBy\"]): SortKey | undefined => {\n if (typeof sortBy === \"string\") return ALLOWED_SORT_KEYS.includes(sortBy as SortKey) ? (sortBy as SortKey) : undefined\n if (typeof sortBy === \"number\") return ALLOWED_SORT_KEYS[sortBy]\n if (Array.isArray(sortBy)) {\n const first = sortBy[0]\n return typeof first === \"string\" && ALLOWED_SORT_KEYS.includes(first as SortKey) ? (first as SortKey) : undefined\n }\n return undefined\n}\n\n// ── SwiftObjects ──────────────────────────────────────────────────────────────\n\nexport const SwiftObjects = ({ provider, containerName }: { provider: string; containerName: string }) => {\n const { t, i18n } = useLingui()\n const projectId = useProjectId()\n const navigate = useNavigate({ from: Route.fullPath })\n\n const { prefix: encodedPrefix, sortBy, sortDirection, search: searchParam = \"\" } = Route.useSearch()\n const { storageType } = Route.useParams()\n const currentPrefix = decodePrefix(encodedPrefix)\n\n // Whether the list exposes any bulk action — drives the selection column in\n // ObjectsTableView and the Zone 4 bulk-action controls. Hardcoded to true for\n // now; the only bulk action today is the destructive Delete.\n //\n // TODO(perms): wire this to the real Swift object permission source\n // (e.g. a usePermissions hook or a tRPC permissions query) instead of\n // hardcoding it.\n const hasAnyBulkAction = true\n\n const [createFolderModalOpen, setCreateFolderModalOpen] = useState(false)\n const [uploadModalOpen, setUploadModalOpen] = useState(false)\n const [deleteAllModalOpen, setDeleteAllModalOpen] = useState(false)\n const [selectedObjects, setSelectedObjects] = useState<string[]>([])\n\n // Clear selection when prefix changes via browser back/forward or deep link,\n // since navigateToPrefix only clears it for in-app folder navigation\n useEffect(() => {\n setSelectedObjects([])\n }, [currentPrefix])\n\n // Local mirror of the committed search term so typing stays responsive while\n // the URL commit is debounced (see Zone 2 SearchInput below).\n const [localSearchTerm, setLocalSearchTerm] = useState(searchParam)\n const debounceTimer = useRef<number | undefined>(undefined)\n useEffect(() => () => clearTimeout(debounceTimer.current), [])\n\n // Keep the input in sync when the committed search term changes from outside\n // the input — browser back/forward, deep links, or programmatic navigation —\n // so the field never drifts from the URL-backed filter state. When the change\n // originated from our own debounced commit, searchParam already equals\n // localSearchTerm, so this is a no-op and won't disturb the caret.\n useEffect(() => {\n setLocalSearchTerm(searchParam)\n }, [searchParam])\n\n const handleCreateFolderSuccess = (folderName: string) => {\n const { message, ...options } = getFolderCreatedToast(folderName)\n toast.success(message, options)\n }\n const handleUploadSuccess = (objectName: string) => {\n const { message, ...options } = getObjectUploadedToast(objectName)\n toast.success(message, options)\n }\n const handleUploadCancelled = (objectName: string) => {\n const { message, ...options } = getObjectUploadCancelledToast(objectName)\n toast.warning(message, options)\n }\n const handleUploadError = (objectName: string, errorMessage: string) => {\n const { message, ...options } = getObjectUploadErrorToast(objectName, errorMessage)\n toast.error(message, options)\n }\n const handleDeleteFolderSuccess = (folderName: string, deletedCount: number) => {\n const nestedCount = Math.max(0, deletedCount - 1)\n const { message, ...options } = getFolderDeletedToast(folderName, nestedCount)\n toast.success(message, options)\n }\n const handleDeleteFolderError = (folderName: string, errorMessage: string) => {\n const { message, ...options } = getFolderDeleteErrorToast(folderName, errorMessage)\n toast.error(message, options)\n }\n const handleDownloadError = (objectName: string, errorMessage: string) => {\n const { message, ...options } = getObjectDownloadErrorToast(objectName, errorMessage)\n toast.error(message, options)\n }\n const handleDeleteObjectSuccess = (objectName: string) => {\n setSelectedObjects((prev) => prev.filter((name) => name !== objectName))\n const { message, ...options } = getObjectDeletedToast(objectName)\n toast.success(message, options)\n }\n const handleDeleteObjectError = (objectName: string, errorMessage: string) => {\n const { message, ...options } = getObjectDeleteErrorToast(objectName, errorMessage)\n toast.error(message, options)\n }\n const handleCopyObjectSuccess = (objectName: string, targetContainer: string, targetPath: string) => {\n const { message, ...options } = getObjectCopiedToast(objectName, targetContainer, targetPath)\n toast.success(message, options)\n }\n const handleCopyObjectError = (objectName: string, errorMessage: string) => {\n const { message, ...options } = getObjectCopyErrorToast(objectName, errorMessage)\n toast.error(message, options)\n }\n const handleMoveObjectSuccess = (objectName: string, targetContainer: string, targetPath: string) => {\n setSelectedObjects((prev) => prev.filter((name) => name !== objectName))\n const { message, ...options } = getObjectMovedToast(objectName, targetContainer, targetPath)\n toast.success(message, options)\n }\n const handleMoveObjectError = (objectName: string, errorMessage: string) => {\n const { message, ...options } = getObjectMoveErrorToast(objectName, errorMessage)\n toast.error(message, options)\n }\n const handleTempUrlCopySuccess = (objectName: string) => {\n const { message, ...options } = getTempUrlCopiedToast(objectName)\n toast.success(message, options)\n }\n const handleEditMetadataSuccess = (objectName: string) => {\n const { message, ...options } = getObjectMetadataUpdatedToast(objectName)\n toast.success(message, options)\n }\n const handleEditMetadataError = (objectName: string, errorMessage: string) => {\n const { message, ...options } = getObjectMetadataUpdateErrorToast(objectName, errorMessage)\n toast.error(message, options)\n }\n\n const handleBulkDeleteSuccess = (numberDeleted: number) => {\n setSelectedObjects([])\n const { message, ...options } = getObjectsBulkDeletedToast(numberDeleted)\n toast.success(message, options)\n }\n\n const handleBulkDeleteError = (errorMessage: string, deletedKeys: string[]) => {\n if (deletedKeys.length > 0) {\n setSelectedObjects((prev) => prev.filter((key) => !deletedKeys.includes(key)))\n }\n const { message, ...options } = getObjectsBulkDeleteErrorToast(errorMessage)\n toast.error(message, options)\n }\n\n const sortSettings: SortSettings = {\n options: [\n { label: t`Name`, value: \"name\" },\n { label: t`Last Modified`, value: \"last_modified\" },\n { label: t`Size`, value: \"bytes\" },\n ],\n sortBy: sortBy ?? undefined,\n sortDirection: sortDirection ?? \"asc\",\n }\n\n const {\n data: objects,\n isLoading,\n error,\n } = trpcReact.storage.swift.listObjects.useQuery({\n project_id: projectId,\n container: containerName,\n format: \"json\",\n prefix: currentPrefix || undefined,\n })\n\n const navigateToContainers = () => {\n navigate({\n to: \"/projects/$projectId/storage/$provider/$storageType\",\n params: { projectId, provider, storageType },\n })\n }\n\n // #1142: don't render the object browser for a container we can't read.\n // A failed listing means the container doesn't exist or the user has no\n // access to it — surface a single friendly toast (no technical error, no\n // not-found/forbidden distinction that would leak existence) and redirect\n // back to the container list. Redirect + toast are side effects, so they run\n // in an effect rather than during render.\n //\n // navigate (and the params it captures) are recreated each render, so they're\n // listed as deps honestly; a ref guards against firing the toast/redirect more\n // than once per error — it runs once when an error appears and resets when the\n // error clears.\n const redirectedRef = useRef(false)\n useEffect(() => {\n if (!error) {\n redirectedRef.current = false\n return\n }\n if (redirectedRef.current) return\n redirectedRef.current = true\n const { message, ...options } = getContainerAccessErrorToast(containerName)\n toast.error(message, options)\n navigate({\n to: \"/projects/$projectId/storage/$provider/$storageType\",\n params: { projectId, provider, storageType },\n })\n }, [error, containerName, navigate, projectId, provider, storageType])\n\n const navigateToPrefix = (newPrefix: string) => {\n // Reset selection when navigating into a different prefix level\n setSelectedObjects([])\n navigate({ search: (prev) => ({ ...prev, prefix: encodePrefix(newPrefix) }) })\n }\n\n const allRows = buildRows((objects ?? []) as ObjectSummary[], currentPrefix)\n const filteredRows = allRows.filter((row) => row.displayName.toLowerCase().includes(searchParam.toLowerCase().trim()))\n const totalItemCount = allRows.length\n const filteredItemCount = filteredRows.length\n const sortedRows = !sortBy\n ? filteredRows\n : [...filteredRows].sort((a, b) => {\n let comparison = 0\n switch (sortBy) {\n case \"name\":\n comparison = a.displayName.localeCompare(b.displayName)\n break\n case \"last_modified\": {\n const aDate = a.kind === \"object\" ? a.last_modified : undefined\n const bDate = b.kind === \"object\" ? b.last_modified : undefined\n if (!aDate || !bDate) break\n // #1236: Swift listing timestamps are UTC without a \"Z\" — parse them\n // as UTC so the ordering is correct (matters near DST boundaries). If\n // a (non-empty) value can't be parsed, leave the pair as equal so the\n // order is untouched (matches the old NaN behaviour).\n const at = parseSwiftDate(aDate)?.getTime()\n const bt = parseSwiftDate(bDate)?.getTime()\n comparison = at == null || bt == null ? 0 : at - bt\n break\n }\n case \"bytes\": {\n const aBytes = a.kind === \"object\" ? a.bytes : 0\n const bBytes = b.kind === \"object\" ? b.bytes : 0\n comparison = aBytes - bBytes\n break\n }\n }\n return (sortDirection ?? \"asc\") === \"desc\" ? -comparison : comparison\n })\n\n const handleSearchChange = (term: string | number | string[] | undefined) => {\n const value = typeof term === \"string\" ? term : \"\"\n startTransition(() => {\n navigate({ search: (prev) => ({ ...prev, search: value || undefined }) })\n })\n }\n\n const handleSortChange = (newSort: SortSettings) => {\n const resolvedSortBy = resolveSortBy(newSort.sortBy)\n const resolvedDirection = (newSort.sortDirection as \"asc\" | \"desc\") || \"asc\"\n startTransition(() => {\n navigate({\n search: (prev) => ({\n ...prev,\n sortBy: resolvedSortBy,\n sortDirection: resolvedSortBy ? resolvedDirection : undefined,\n }),\n })\n })\n }\n\n if (isLoading) {\n return <Status status=\"progress\" title={t`Loading Objects...`} />\n }\n\n // #1142: on load error we don't render the technical message anymore. The\n // effect above shows a toast and redirects to the container list; render\n // nothing while that happens (also covers the brief tick before navigation).\n if (error) {\n return null\n }\n\n const hasSelection = selectedObjects.length > 0\n const selectedCount = selectedObjects.length\n\n // Derive short display names for the modal list — selectedObjects holds full\n // keys (e.g. \"folder/sub/file.txt\") but the modal should show \"file.txt\".\n const selectedDisplayNames = selectedObjects.map((key) => sortedRows.find((r) => r.name === key)?.displayName ?? key)\n\n // Zone 4 select-all operates on the selectable (object, non-folder) rows in\n // the currently displayed (filtered + sorted) set.\n const selectableNames = sortedRows.filter((r): r is ObjectRow => r.kind === \"object\").map((r) => r.name)\n const allSelectableSelected = selectableNames.length > 0 && selectableNames.every((n) => selectedObjects.includes(n))\n const someSelectableSelected = selectableNames.some((n) => selectedObjects.includes(n))\n\n const handleToggleSelectAll = () => {\n if (allSelectableSelected) {\n setSelectedObjects((prev) => prev.filter((n) => !selectableNames.includes(n)))\n } else {\n setSelectedObjects((prev) => [...new Set([...prev, ...selectableNames])])\n }\n }\n\n return (\n <div className=\"relative\">\n <Stack direction=\"vertical\">\n {/* Zone 1 — sort controls + primary actions (plain Stack, no background) */}\n <Stack distribution=\"end\" alignment=\"center\" gap=\"2\" className=\"pb-2\">\n <Stack gap=\"0.5\" alignment=\"center\">\n <SortInput\n options={sortSettings.options}\n sortBy={sortSettings.sortBy}\n sortDirection={sortSettings.sortDirection ?? \"asc\"}\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 </Stack>\n <Stack gap=\"0.5\" alignment=\"center\">\n <PopupMenu className=\"flex items-center\">\n <PopupMenuToggle as=\"div\">\n <Button icon=\"moreVert\" title={t`More Actions`} />\n </PopupMenuToggle>\n <PopupMenuOptions>\n <PopupMenuItem\n label={t`Create Folder`}\n onClick={() => setCreateFolderModalOpen(true)}\n data-testid=\"create-folder-action\"\n />\n </PopupMenuOptions>\n </PopupMenu>\n <Button variant=\"primary\" className=\"whitespace-nowrap\" onClick={() => setUploadModalOpen(true)}>\n <Trans>Upload Object</Trans>\n </Button>\n </Stack>\n </Stack>\n\n {/* Zone 2 — debounced search. DataGridToolbar provides the background. */}\n <DataGridToolbar>\n <Stack direction=\"vertical\" gap=\"2\">\n <Stack distribution=\"end\" alignment=\"center\">\n <SearchInput\n placeholder={t`Search objects...`}\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(() => handleSearchChange(v), 500)\n }}\n onSearch={(v) => {\n clearTimeout(debounceTimer.current)\n handleSearchChange(typeof v === \"string\" ? v : \"\")\n }}\n onClear={() => {\n clearTimeout(debounceTimer.current)\n setLocalSearchTerm(\"\")\n handleSearchChange(\"\")\n }}\n />\n </Stack>\n </Stack>\n </DataGridToolbar>\n\n {/* Zone 3 — breadcrumb navigation in its own row (matches Ceph). */}\n <DataGridToolbar>\n <ObjectsFileNavigation\n containerName={containerName}\n currentPrefix={currentPrefix}\n onContainersClick={navigateToContainers}\n onPrefixClick={navigateToPrefix}\n />\n </DataGridToolbar>\n\n {/* Zone 4 — bulk actions (gated) plus the item count. Bulk actions sit\n on the left; the count is pushed right via ml-auto so it stays\n right-aligned regardless of whether the bulk block renders. */}\n <DataGridToolbar>\n <Stack distribution=\"start\" gap=\"2\" alignment=\"center\" className=\"text-sm\">\n {hasAnyBulkAction ? (\n <Stack gap=\"2\" alignment=\"center\">\n <Checkbox\n checked={allSelectableSelected}\n indeterminate={someSelectableSelected && !allSelectableSelected}\n onChange={handleToggleSelectAll}\n />\n <PopupMenu className=\"flex items-center\">\n <PopupMenuToggle as=\"div\">\n <Button disabled={!hasSelection} size=\"small\" icon=\"moreVert\" label={t`Actions`} />\n </PopupMenuToggle>\n {hasSelection && (\n <PopupMenuOptions>\n <PopupMenuItem\n disabled={!hasSelection}\n label={i18n._(\n plural(selectedCount, {\n one: \"Delete # Object\",\n other: \"Delete # Objects\",\n })\n )}\n onClick={() => setDeleteAllModalOpen(true)}\n />\n </PopupMenuOptions>\n )}\n </PopupMenu>\n </Stack>\n ) : (\n <span />\n )}\n\n <div className=\"text-theme-light ml-auto flex items-center gap-1\" data-testid=\"objects-info-block\">\n {searchParam.trim() ? (\n <Plural\n value={totalItemCount}\n one={`${filteredItemCount} of ${totalItemCount} item`}\n other={`${filteredItemCount} of ${totalItemCount} items`}\n />\n ) : (\n <Plural value={totalItemCount} one={`${totalItemCount} item`} other={`${totalItemCount} items`} />\n )}\n </div>\n </Stack>\n </DataGridToolbar>\n </Stack>\n <ObjectsTableView\n rows={sortedRows}\n searchTerm={searchParam}\n container={containerName}\n onFolderClick={navigateToPrefix}\n onDeleteFolderSuccess={handleDeleteFolderSuccess}\n onDeleteFolderError={handleDeleteFolderError}\n onDownloadError={handleDownloadError}\n onDeleteObjectSuccess={handleDeleteObjectSuccess}\n onDeleteObjectError={handleDeleteObjectError}\n onCopyObjectSuccess={handleCopyObjectSuccess}\n onCopyObjectError={handleCopyObjectError}\n onMoveObjectSuccess={handleMoveObjectSuccess}\n onMoveObjectError={handleMoveObjectError}\n onTempUrlCopySuccess={handleTempUrlCopySuccess}\n onEditMetadataSuccess={handleEditMetadataSuccess}\n onEditMetadataError={handleEditMetadataError}\n selectedObjects={selectedObjects}\n setSelectedObjects={setSelectedObjects}\n hasAnyBulkAction={hasAnyBulkAction}\n />\n\n <DeleteObjectsModal\n isOpen={deleteAllModalOpen}\n objectNames={selectedDisplayNames}\n objectKeys={selectedObjects}\n container={containerName}\n onClose={() => setDeleteAllModalOpen(false)}\n onSuccess={handleBulkDeleteSuccess}\n onError={handleBulkDeleteError}\n />\n\n <CreateFolderModal\n isOpen={createFolderModalOpen}\n currentPrefix={currentPrefix}\n onClose={() => setCreateFolderModalOpen(false)}\n onSuccess={handleCreateFolderSuccess}\n existingRows={allRows}\n />\n\n <UploadObjectModal\n projectId={projectId}\n isOpen={uploadModalOpen}\n currentPrefix={currentPrefix}\n container={containerName}\n onClose={() => setUploadModalOpen(false)}\n onSuccess={handleUploadSuccess}\n onCancelled={handleUploadCancelled}\n onError={handleUploadError}\n />\n </div>\n )\n}\n","import { trpcReact } from \"@/client/trpcClient\"\n\n/**\n * Mutation-only permissions for the Ceph/S3 Object Storage UI.\n *\n * Read/list/view/download actions are deliberately not represented here - this codebase's\n * established convention (see `useSecurityGroupPermissions`) is to gate mutations only, never\n * reads. There is nothing to query for those actions.\n */\nexport interface CephPermissions {\n canCreateBucket: boolean\n canDeleteBucket: boolean\n canEmptyBucket: boolean\n canUpdateVersioning: boolean\n canCreateObject: boolean\n canUpdateObject: boolean\n canDeleteObject: boolean\n canCopyObject: boolean\n canMoveObject: boolean\n canShareObject: boolean\n canCreateFolder: boolean\n canDeleteFolder: boolean\n canDeleteVersion: boolean\n canRestoreVersion: boolean\n canUpdatePolicy: boolean\n canDeletePolicy: boolean\n canUpdateCors: boolean\n canDeleteCors: boolean\n canUpdateLifecycle: boolean\n canDeleteLifecycle: boolean\n canCreateCredential: boolean\n}\n\n/**\n * Single source of truth mapping each `CephPermissions` key to the `storage:*` permission\n * string the server checks. The request array and the `select` key order below are both\n * derived from this map, so a reorder/insert here can't desync them the way two independently\n * maintained positional lists could - the `satisfies` clause fails to compile if a key is\n * missing or misspelled.\n *\n * Scope note: this only buys `CephPermissions`-key safety. `canUser`'s tRPC input is plain\n * `string` (not a literal union), so a typo'd permission string on the right-hand side still\n * only fails at runtime (see the module docblock in `permissionRouter.ts`).\n */\nconst PERMISSION_MAP = {\n canCreateBucket: \"storage:containers:create\",\n canDeleteBucket: \"storage:containers:delete\",\n canEmptyBucket: \"storage:containers:empty\",\n canUpdateVersioning: \"storage:containers:update_versioning\",\n canCreateObject: \"storage:objects:create\",\n canUpdateObject: \"storage:objects:update\",\n canDeleteObject: \"storage:objects:delete\",\n canCopyObject: \"storage:objects:copy\",\n canMoveObject: \"storage:objects:move\",\n canShareObject: \"storage:objects:share\",\n canCreateFolder: \"storage:folders:create\",\n canDeleteFolder: \"storage:folders:delete\",\n canDeleteVersion: \"storage:object_versions:delete\",\n canRestoreVersion: \"storage:object_versions:restore\",\n canUpdatePolicy: \"storage:container_policies:update\",\n canDeletePolicy: \"storage:container_policies:delete\",\n canUpdateCors: \"storage:container_cors_rules:update\",\n canDeleteCors: \"storage:container_cors_rules:delete\",\n canUpdateLifecycle: \"storage:container_lifecycle_rules:update\",\n canDeleteLifecycle: \"storage:container_lifecycle_rules:delete\",\n canCreateCredential: \"storage:credentials:create\",\n} as const satisfies Record<keyof CephPermissions, string>\n\n// Module-level constants, not computed in the hook body: this array is part of the tRPC query\n// key, so a fresh array identity on every render would defeat the `staleTime: Infinity` cache.\nconst PERMISSION_KEYS = Object.keys(PERMISSION_MAP) as (keyof CephPermissions)[]\nconst PERMISSION_REQUEST = PERMISSION_KEYS.map((key) => PERMISSION_MAP[key])\n\nconst DEFAULT_PERMISSIONS: CephPermissions = Object.fromEntries(\n PERMISSION_KEYS.map((key) => [key, false])\n) as unknown as CephPermissions\n\n/**\n * Hook to fetch Ceph/S3 Object Storage mutation permissions for the current user.\n * Uses React Query with infinite cache since permissions don't change during session.\n *\n * Defaults to all-false while loading or on error, so mutation controls stay hidden\n * (fail-closed) rather than being briefly or permanently shown for a permission the user\n * doesn't actually have - this also covers operators whose `storage.json` is missing one of\n * the newer Ceph rules.\n */\nexport function useCephPermissions(projectId: string) {\n const {\n data: permissions = DEFAULT_PERMISSIONS,\n isLoading,\n isError,\n } = trpcReact.storage.canUser.useQuery(\n {\n project_id: projectId || \"\",\n permission: PERMISSION_REQUEST,\n },\n {\n enabled: Boolean(projectId), // Only fetch if we have a project ID\n select: (results): CephPermissions =>\n Object.fromEntries(\n PERMISSION_KEYS.map((key, index) => [key, results[index] ?? false])\n ) as unknown as CephPermissions,\n staleTime: Infinity, // Permissions don't change during session\n gcTime: Infinity, // Keep in cache forever (previously cacheTime)\n }\n )\n\n return {\n permissions,\n isLoading,\n isError,\n }\n}\n","import { ReactNode } from \"react\"\nimport { NotificationOptions } from \"@cloudoperators/juno-ui-components\"\nimport { Trans, Plural } from \"@lingui/react/macro\"\n\n// ── Folder operations ──────────────────────────────────────────────────────────\n\nexport const getFolderCreatedToast = (folderPath: string): { message: ReactNode } & NotificationOptions => ({\n message: <Trans>Folder Created</Trans>,\n description: <Trans>Folder \"{folderPath}\" was successfully created.</Trans>,\n})\n\nexport const getFolderCreateErrorToast = (\n folderPath: string,\n errorMessage: string\n): { message: ReactNode } & NotificationOptions => ({\n message: <Trans>Failed to Create Folder</Trans>,\n description: (\n <Trans>\n Could not create folder \"{folderPath}\": {errorMessage}\n </Trans>\n ),\n})\n\n// ── Object delete ──────────────────────────────────────────────────────────────\n\nexport const getObjectDeletedToast = (objectKey: string): { message: ReactNode } & NotificationOptions => {\n const displayName = objectKey.split(\"/\").filter(Boolean).pop() ?? objectKey\n return {\n message: <Trans>Object Deleted</Trans>,\n description: <Trans>Object \"{displayName}\" was permanently deleted.</Trans>,\n }\n}\n\nexport const getObjectDeleteErrorToast = (\n objectKey: string,\n errorMessage: string\n): { message: ReactNode } & NotificationOptions => {\n const displayName = objectKey.split(\"/\").filter(Boolean).pop() ?? objectKey\n return {\n message: <Trans>Failed to Delete Object</Trans>,\n description: (\n <Trans>\n Could not delete \"{displayName}\": {errorMessage}\n </Trans>\n ),\n }\n}\n\n// ── Bulk delete (generic factory) ─────────────────────────────────────────────\n\ntype EntityType = \"object\" | \"version\"\n\nconst createBulkDeleteToasts = (entityType: EntityType) => {\n const isVersion = entityType === \"version\"\n\n return {\n success: (deletedCount: number): { message: ReactNode } & NotificationOptions => ({\n message: isVersion ? <Trans>Versions Deleted Permanently</Trans> : <Trans>Objects Deleted</Trans>,\n description: isVersion ? (\n <Plural\n value={deletedCount}\n one=\"# version was permanently deleted.\"\n other=\"# versions were permanently deleted.\"\n />\n ) : (\n <Plural value={deletedCount} one=\"# object was deleted.\" other=\"# objects were deleted.\" />\n ),\n }),\n\n partial: (deletedCount: number, errorCount: number): { message: ReactNode } & NotificationOptions => ({\n message: isVersion ? (\n <Trans>Some Versions Could Not Be Deleted</Trans>\n ) : (\n <Trans>Some Objects Could Not Be Deleted</Trans>\n ),\n description: (\n <Trans>\n {deletedCount} deleted, {errorCount} failed. See the details in the dialog.\n </Trans>\n ),\n }),\n\n error: (errorMessage: string): { message: ReactNode } & NotificationOptions => ({\n message: isVersion ? <Trans>Failed to Delete Versions</Trans> : <Trans>Failed to Delete Objects</Trans>,\n description: isVersion ? (\n <Trans>No versions were deleted: {errorMessage}</Trans>\n ) : (\n <Trans>No objects were deleted: {errorMessage}</Trans>\n ),\n }),\n }\n}\n\n// ── Bulk object delete ─────────────────────────────────────────────────────────\n\nconst objectBulkDelete = createBulkDeleteToasts(\"object\")\nexport const getObjectsBulkDeletedToast = objectBulkDelete.success\nexport const getObjectsBulkDeletePartialToast = objectBulkDelete.partial\nexport const getObjectsBulkDeleteErrorToast = objectBulkDelete.error\n\n// ── Object copy ────────────────────────────────────────────────────────────────\n\nexport const getObjectCopiedToast = (\n objectKey: string,\n targetBucket: string,\n targetKey: string,\n wasOverwritten?: boolean\n): { message: ReactNode } & NotificationOptions => {\n const displayName = objectKey.split(\"/\").filter(Boolean).pop() ?? objectKey\n const destination = `${targetBucket}/${targetKey}`\n return {\n message: <Trans>Object Copied</Trans>,\n description: wasOverwritten ? (\n <Trans>\n \"{displayName}\" was successfully copied to {destination} (existing object was replaced).\n </Trans>\n ) : (\n <Trans>\n \"{displayName}\" was successfully copied to {destination}.\n </Trans>\n ),\n }\n}\n\nexport const getObjectCopyErrorToast = (\n objectKey: string,\n errorMessage: string\n): { message: ReactNode } & NotificationOptions => {\n const displayName = objectKey.split(\"/\").filter(Boolean).pop() ?? objectKey\n return {\n message: <Trans>Failed to Copy Object</Trans>,\n description: (\n <Trans>\n Could not copy \"{displayName}\": {errorMessage}\n </Trans>\n ),\n }\n}\n\n// ── Object move ────────────────────────────────────────────────────────────────\n\nexport const getObjectMovedToast = (\n objectKey: string,\n targetBucket: string,\n targetKey: string\n): { message: ReactNode } & NotificationOptions => {\n const displayName = objectKey.split(\"/\").filter(Boolean).pop() ?? objectKey\n const destination = `${targetBucket}/${targetKey}`\n return {\n message: <Trans>Object Moved</Trans>,\n description: (\n <Trans>\n \"{displayName}\" was successfully moved to {destination}.\n </Trans>\n ),\n }\n}\n\nexport const getObjectMoveErrorToast = (\n objectKey: string,\n errorMessage: string\n): { message: ReactNode } & NotificationOptions => {\n const displayName = objectKey.split(\"/\").filter(Boolean).pop() ?? objectKey\n return {\n message: <Trans>Failed to Move Object</Trans>,\n description: (\n <Trans>\n Could not move \"{displayName}\": {errorMessage}\n </Trans>\n ),\n }\n}\n\n// ── Pre-signed URL ─────────────────────────────────────────────────────────────\n\n// Raised after a generated pre-signed URL is copied to the clipboard. Takes the\n// full object key and derives a basename display name, consistent with the\n// key-based toasts above.\nexport const getPresignedUrlCopiedToast = (objectKey: string): { message: ReactNode } & NotificationOptions => {\n const displayName = objectKey.split(\"/\").filter(Boolean).pop() ?? objectKey\n return {\n message: <Trans>URL Copied</Trans>,\n description: <Trans>Pre-signed URL for \"{displayName}\" was copied to clipboard.</Trans>,\n }\n}\n\n// ── Object metadata update ─────────────────────────────────────────────────────\n\nexport const getObjectMetadataUpdatedToast = (objectKey: string): { message: ReactNode } & NotificationOptions => {\n const displayName = objectKey.split(\"/\").filter(Boolean).pop() ?? objectKey\n return {\n message: <Trans>Object Updated</Trans>,\n description: <Trans>Properties of \"{displayName}\" were successfully updated.</Trans>,\n }\n}\n\nexport const getObjectMetadataUpdateErrorToast = (\n objectKey: string,\n errorMessage: string\n): { message: ReactNode } & NotificationOptions => {\n const displayName = objectKey.split(\"/\").filter(Boolean).pop() ?? objectKey\n return {\n message: <Trans>Failed to Update Object</Trans>,\n description: (\n <Trans>\n Could not update \"{displayName}\": {errorMessage}\n </Trans>\n ),\n }\n}\n\n// ── Object upload ──────────────────────────────────────────────────────────────\n\n// The upload modal passes the bare file name (not a full key), so these show it\n// as-is rather than deriving a basename like the key-based toasts above.\n\nexport const getObjectUploadedToast = (objectName: string): { message: ReactNode } & NotificationOptions => ({\n message: <Trans>Object Uploaded</Trans>,\n description: <Trans>\"{objectName}\" was successfully uploaded.</Trans>,\n})\n\n// A cancelled upload is a user-initiated outcome, not a failure — confirm it so\n// the disappearing progress bar isn't the only feedback.\nexport const getObjectUploadCancelledToast = (objectName: string): { message: ReactNode } & NotificationOptions => ({\n message: <Trans>Upload Cancelled</Trans>,\n description: <Trans>Upload of \"{objectName}\" was cancelled.</Trans>,\n})\n\nexport const getObjectUploadErrorToast = (\n objectName: string,\n errorMessage: string\n): { message: ReactNode } & NotificationOptions => ({\n message: <Trans>Failed to Upload Object</Trans>,\n description: (\n <Trans>\n Could not upload \"{objectName}\": {errorMessage}\n </Trans>\n ),\n})\n\n// ── Object download ────────────────────────────────────────────────────────────\n\n// Shown while at least one download/preview transfer is in flight. Large objects\n// stream through the BFF before anything happens client-side (no native browser\n// download progress until the whole file has arrived), so this sets expectations\n// up front.\n//\n// This is a single, persistent toast — not one per file: the download store\n// raises it when the first transfer starts and dismisses it when the last one\n// finishes, so several concurrent downloads never stack up notifications. It is\n// rendered with a fixed id and `duration: Infinity` (see objectDownloadStore).\nexport const getObjectDownloadStartedToast = (): { message: ReactNode } & NotificationOptions => ({\n message: <Trans>Downloading...</Trans>,\n description: (\n <Trans>\n Downloading larger files may take a while. You can keep browsing buckets and folders — downloads continue in the\n background, and this message disappears once they finish.\n </Trans>\n ),\n})\n\n// A cancelled transfer is a user-initiated outcome, not a failure — confirm it\n// so the disappearing progress spinner isn't the only feedback.\nexport const getObjectDownloadCancelledToast = (objectKey: string): { message: ReactNode } & NotificationOptions => {\n const displayName = objectKey.split(\"/\").filter(Boolean).pop() ?? objectKey\n return {\n message: <Trans>Download Cancelled</Trans>,\n description: <Trans>Download of \"{displayName}\" was cancelled.</Trans>,\n }\n}\n\nexport const getObjectDownloadErrorToast = (\n objectKey: string,\n errorMessage: string\n): { message: ReactNode } & NotificationOptions => {\n const displayName = objectKey.split(\"/\").filter(Boolean).pop() ?? objectKey\n return {\n message: <Trans>Failed to Download Object</Trans>,\n description: (\n <Trans>\n Could not download \"{displayName}\": {errorMessage}\n </Trans>\n ),\n }\n}\n\n// ── Version restore ────────────────────────────────────────────────────────\n\nexport const getVersionRestoredToast = (objectKey: string): { message: ReactNode } & NotificationOptions => {\n const displayName = objectKey.split(\"/\").filter(Boolean).pop() ?? objectKey\n return {\n message: <Trans>Version Restored</Trans>,\n description: <Trans>\"{displayName}\" was successfully restored.</Trans>,\n }\n}\n\nexport const getVersionRestoreErrorToast = (\n objectKey: string,\n errorMessage: string\n): { message: ReactNode } & NotificationOptions => {\n const displayName = objectKey.split(\"/\").filter(Boolean).pop() ?? objectKey\n return {\n message: <Trans>Failed to Restore Version</Trans>,\n description: (\n <Trans>\n Could not restore \"{displayName}\": {errorMessage}\n </Trans>\n ),\n }\n}\n\n// ── Version delete ─────────────────────────────────────────────────────────\n\nexport const getVersionDeletedToast = (objectKey: string): { message: ReactNode } & NotificationOptions => {\n const displayName = objectKey.split(\"/\").filter(Boolean).pop() ?? objectKey\n return {\n message: <Trans>Version Deleted</Trans>,\n description: <Trans>Version of \"{displayName}\" was permanently deleted.</Trans>,\n }\n}\n\nexport const getVersionDeleteErrorToast = (\n objectKey: string,\n errorMessage: string\n): { message: ReactNode } & NotificationOptions => {\n const displayName = objectKey.split(\"/\").filter(Boolean).pop() ?? objectKey\n return {\n message: <Trans>Failed to Delete Version</Trans>,\n description: (\n <Trans>\n Could not delete version of \"{displayName}\": {errorMessage}\n </Trans>\n ),\n }\n}\n\n// ── Bulk version delete ────────────────────────────────────────────────────────\n\nconst versionBulkDelete = createBulkDeleteToasts(\"version\")\nexport const getVersionsBulkDeletedToast = versionBulkDelete.success\nexport const getVersionsBulkDeletePartialToast = versionBulkDelete.partial\nexport const getVersionsBulkDeleteErrorToast = versionBulkDelete.error\n","// Module-scope registry of in-flight object downloads.\n//\n// Why this lives outside React: ObjectBrowserView swaps ObjectsTableView out for\n// a <Spinner> whenever objects.list is loading (i.e. entering an uncached\n// folder). That unmounts the table — and if the table owned the workers, its\n// cleanup would abort them mid-stream (\"stream closed prematurely\") and lose the\n// progress state. Owning transfers here means a download survives folder\n// navigation, spinner swaps, and even leaving the bucket entirely — which is what\n// the download-started toast already promises the user.\n//\n// Components read the transfer map via useSyncExternalStore(subscribe, getSnapshot)\n// and re-render on change. The worker's onmessage callbacks run regardless of\n// whether any component is mounted, so a download that finishes while the user is\n// in another folder still saves the file.\n\nimport { toast } from \"@cloudoperators/juno-ui-components\"\nimport { getBffEndpoint, getCsrfToken } from \"@/client/trpcClient\"\nimport DownloadWorker from \"../workers/objectDownload.worker?worker&inline\"\nimport type { DownloadWorkerRequest, DownloadWorkerResponse } from \"../workers/objectDownload.worker\"\nimport { getObjectDownloadStartedToast } from \"../ObjectToastNotifications\"\n\nexport type TransferKind = \"download\" | \"preview\"\nexport type ActiveTransfer = { kind: TransferKind; downloadId: string; worker: Worker }\n\n// Keyed by transferKey() — bucket-scoped so the same object key in two buckets\n// can't collide.\nconst transfers = new Map<string, ActiveTransfer>()\nconst listeners = new Set<() => void>()\n\n// useSyncExternalStore requires getSnapshot to return a stable reference between\n// changes, so we hand out a copy that's only rebuilt on mutation.\nlet snapshot: ReadonlyMap<string, ActiveTransfer> = new Map()\n\n// Fixed id so the \"Downloading...\" notification is a single toast for the whole\n// session rather than one per file — sonner (which backs Juno's toast) treats a\n// repeated id as an update, not a new notification.\nconst DOWNLOAD_TOAST_ID = \"ceph-object-download\"\nlet downloadToastShown = false\n\n// Raise the toast when the first transfer starts, dismiss it when the last one\n// ends — however it ended (saved, failed, or cancelled). Living in the store\n// rather than in a component matters: the last transfer can finish while\n// ObjectsTableView is unmounted (the user navigated away), and the toast must\n// still be dismissed.\nconst syncDownloadToast = () => {\n const hasActiveTransfers = transfers.size > 0\n if (hasActiveTransfers && !downloadToastShown) {\n const { message, ...options } = getObjectDownloadStartedToast()\n // duration: Infinity — this toast is dismissed explicitly, not on a timer.\n toast(message, { ...options, id: DOWNLOAD_TOAST_ID, duration: Infinity })\n downloadToastShown = true\n } else if (!hasActiveTransfers && downloadToastShown) {\n toast.dismiss(DOWNLOAD_TOAST_ID)\n downloadToastShown = false\n }\n}\n\nconst emit = () => {\n snapshot = new Map(transfers)\n syncDownloadToast()\n listeners.forEach((listener) => listener())\n}\n\n// How long a cancelled worker gets to report back before it is forced down.\n//\n// Normally it replies almost immediately — the abort rejects its `for await`,\n// and the reply path terminates it. But that reply isn't guaranteed: if the\n// abort ever fails to unwind the stream, the worker would keep downloading and\n// buffering a file nobody wants, with no entry left in `transfers` to clean it\n// up. This bounds that window.\nconst CANCEL_TERMINATE_GRACE_MS = 5000\n\nexport const transferKey = (bucketName: string, objectKey: string) => `${bucketName}:${objectKey}`\n\nexport const subscribeTransfers = (listener: () => void) => {\n listeners.add(listener)\n return () => listeners.delete(listener)\n}\n\nexport const getTransfersSnapshot = (): ReadonlyMap<string, ActiveTransfer> => snapshot\n\n// ── DOM helpers (main thread only — the worker has no document) ────────────────\n\nconst triggerAnchorDownload = (url: string, filename: string) => {\n const anchor = document.createElement(\"a\")\n anchor.href = url\n anchor.download = filename\n document.body.appendChild(anchor)\n anchor.click()\n document.body.removeChild(anchor)\n setTimeout(() => URL.revokeObjectURL(url), 10000)\n}\n\n// Uses an anchor with target=\"_blank\" rather than window.open — anchors aren't\n// subject to the post-await popup-blocking window.open is, so the tab can be\n// opened after streaming completes, only for files we know are previewable.\nconst openBlobInNewTab = (url: string) => {\n const anchor = document.createElement(\"a\")\n anchor.href = url\n anchor.target = \"_blank\"\n anchor.rel = \"noopener,noreferrer\"\n document.body.appendChild(anchor)\n anchor.click()\n document.body.removeChild(anchor)\n setTimeout(() => URL.revokeObjectURL(url), 60000)\n}\n\n// MIME types safe to preview in a browser tab. Decided from the Content-Type the\n// BFF actually returns (resolved server-side from the object key when S3 stores a\n// generic default), not from the filename — so it works for UUID-keyed objects.\n//\n// NOTE: intentionally excludes scriptable types (text/html, application/json,\n// application/xml) and SVG (can execute scripts when opened via blob URLs).\nconst BROWSER_PREVIEWABLE_MIME_TYPES = new Set([\"application/pdf\", \"text/plain\"])\n\nexport function isPreviewableContentType(contentType: string): boolean {\n const base = contentType.split(\";\")[0].trim().toLowerCase()\n if (BROWSER_PREVIEWABLE_MIME_TYPES.has(base)) return true\n if (base === \"image/svg+xml\") return false\n return base.startsWith(\"image/\") || base.startsWith(\"video/\") || base.startsWith(\"audio/\")\n}\n\n// ── Transfer lifecycle ────────────────────────────────────────────────────────\n\nexport function startObjectDownload(opts: {\n kind: TransferKind\n projectId: string\n bucketName: string\n objectKey: string\n filename: string\n onError: (objectKey: string, message: string) => void\n}): void {\n const { kind, projectId, bucketName, objectKey, filename, onError } = opts\n const key = transferKey(bucketName, objectKey)\n\n // Ignore a second start for a row that's already transferring.\n if (transfers.has(key)) return\n\n const downloadId = `${bucketName}:${objectKey}:${crypto.randomUUID()}`\n\n let worker: Worker\n try {\n // Inlined worker (Vite's ?worker&inline), NOT `new Worker(new URL(…))`.\n // Aurora ships as a library: a URL-referenced worker is emitted as a separate\n // asset and the reference is baked into our bundle as a plain string. The app\n // consuming this library re-bundles us, sees only that string, and never\n // copies the worker chunk into its own output — so the request 404s and lands\n // in the SPA fallback, which serves index.html and fails strict MIME checking\n // for module scripts. Inlining leaves no asset for a consumer to lose.\n worker = new DownloadWorker()\n } catch (err) {\n onError(objectKey, err instanceof Error ? err.message : \"Failed to start download worker\")\n return\n }\n\n transfers.set(key, { kind, downloadId, worker })\n emit()\n\n const finish = () => {\n // Only clear the entry we started — a newer transfer for the same row must\n // not be wiped by a stale one's cleanup. terminate() here is safe: the worker\n // has already reported back, so it's idle, never killed mid-stream.\n if (transfers.get(key)?.downloadId === downloadId) {\n transfers.delete(key)\n emit()\n }\n worker.terminate()\n }\n\n worker.onmessage = ({ data }: MessageEvent<DownloadWorkerResponse>) => {\n // A worker that was cancelled (or replaced) is no longer the row's transfer —\n // ignore its late reply so a download finishing at the moment of cancel\n // doesn't still save the file.\n if (transfers.get(key)?.worker !== worker) {\n worker.terminate()\n return\n }\n if (data.ok) {\n const url = URL.createObjectURL(data.blob)\n if (kind === \"preview\" && isPreviewableContentType(data.contentType)) {\n openBlobInNewTab(url)\n } else {\n triggerAnchorDownload(url, data.filename)\n }\n } else if (!data.cancelled) {\n onError(objectKey, data.message)\n }\n finish()\n }\n\n worker.onerror = (event) => {\n if (transfers.get(key)?.worker !== worker) {\n worker.terminate()\n return\n }\n onError(objectKey, event.message || \"Download worker failed\")\n finish()\n }\n\n worker.postMessage({\n type: \"start\",\n // The worker has its own module instance and never sees App's\n // setBffEndpoint() call — hand it the resolved endpoint explicitly.\n //\n // Absolute, not relative: the worker is inlined and therefore runs from a\n // blob: URL, whose location has an opaque path. Resolving \"/polaris-bff\"\n // against it throws (\"Failed to parse URL\"), so the endpoint has to carry its\n // own origin. An already-absolute endpoint passes through unchanged.\n bffEndpoint: new URL(getBffEndpoint(), location.origin).href,\n // Same story for CSRF: the worker's own token cache starts empty, and\n // fetching /csrf-token there is a round-trip we don't need. Null (nothing has\n // needed a token yet this session) is fine — the worker resolves one itself.\n csrfToken: getCsrfToken(),\n projectId,\n bucketName,\n objectKey,\n filename,\n downloadId,\n } satisfies DownloadWorkerRequest)\n}\n\n// Cancel an in-flight transfer. Removes it from the store immediately (so the UI\n// clears on the very next render, with no worker round-trip) and tells the worker\n// to abort its tRPC call, which tears down the request so the BFF stops reading\n// from S3. The worker isn't terminated right away — it unwinds its own abort and\n// is dropped once idle, avoiding a mid-stream hard kill; a grace-period timer\n// forces it down if that never happens.\n//\n// Returns the cancelled transfer (or undefined if the row wasn't transferring) so\n// callers can tell a real cancellation apart from a no-op.\nexport function cancelObjectDownload(bucketName: string, objectKey: string): ActiveTransfer | undefined {\n const key = transferKey(bucketName, objectKey)\n const transfer = transfers.get(key)\n if (!transfer) return undefined\n\n transfer.worker.postMessage({ type: \"cancel\" } satisfies DownloadWorkerRequest)\n // Safety net for a worker that never reports back (see\n // CANCEL_TERMINATE_GRACE_MS). terminate() is idempotent, so this is a no-op in\n // the normal case where the worker already replied and was terminated.\n setTimeout(() => transfer.worker.terminate(), CANCEL_TERMINATE_GRACE_MS)\n transfers.delete(key)\n emit()\n return transfer\n}\n","import { z } from \"zod\"\nimport { useForm, useStore } from \"@tanstack/react-form\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport {\n Modal,\n Form,\n FormSection,\n TextInput,\n Stack,\n DescriptionList,\n DescriptionTerm,\n DescriptionDefinition,\n} from \"@cloudoperators/juno-ui-components\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport { useModalTracking } from \"@/client/hooks/useModalTracking\"\nimport { formatBytesBinary } from \"@/client/utils/formatBytes\"\n\ninterface DeleteObjectModalProps {\n bucketName: string\n objectKey: string\n objectSize?: number\n lastModified?: string\n isOpen: boolean\n versioningEnabled?: boolean\n onClose: () => void\n onSuccess: (objectKey: string) => void\n onError: (objectKey: string, errorMessage: string) => void\n}\n\nexport function DeleteObjectModal({\n bucketName,\n objectKey,\n objectSize,\n lastModified,\n isOpen,\n versioningEnabled = false,\n onClose,\n onSuccess,\n onError,\n}: DeleteObjectModalProps) {\n const { t } = useLingui()\n const projectId = useProjectId()\n const utils = trpcReact.useUtils()\n\n const { trackClose, markSubmitted, resetTracking } = useModalTracking({\n isOpen,\n actionPrefix: \"storage.ceph.object.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 (deleteMutation.isPending || !projectId) return\n\n markSubmitted()\n deleteMutation.mutate({\n project_id: projectId,\n containerName: bucketName,\n objectKey,\n })\n },\n })\n\n const canDelete = useStore(form.store, (state) => state.isSubmitting || state.values.confirm !== \"delete\")\n\n const deleteMutation = trpcReact.storage.ceph.objects.delete.useMutation({\n onSuccess: () => {\n utils.storage.ceph.objects.list.invalidate()\n utils.storage.ceph.containers.list.invalidate()\n\n utils.storage.ceph.versioning.checkDeletedContent.invalidate()\n onSuccess(objectKey)\n handleClose()\n },\n onError: (error) => {\n onError(objectKey, error.message)\n },\n })\n\n const handleClose = () => {\n trackClose()\n form.reset()\n deleteMutation.reset()\n resetTracking()\n onClose()\n }\n\n const isFolder = objectKey.endsWith(\"/\")\n const displayName = objectKey.split(\"/\").filter(Boolean).pop() || objectKey\n\n return (\n <Modal\n open={isOpen}\n onCancel={handleClose}\n title={isFolder ? <Trans>Delete Folder \"{displayName}\"</Trans> : <Trans>Delete Object</Trans>}\n size=\"large\"\n confirmButtonLabel={deleteMutation.isPending ? t`Deleting...` : isFolder ? t`Delete Folder` : t`Delete Object`}\n confirmButtonVariant=\"primary-danger\"\n onConfirm={form.handleSubmit}\n cancelButtonLabel={t`Cancel`}\n disableConfirmButton={canDelete || deleteMutation.isPending}\n disableCancelButton={deleteMutation.isPending}\n disableCloseButton={deleteMutation.isPending}\n >\n <Stack direction=\"vertical\" gap=\"4\">\n <p className=\"text-theme-default overflow-x-hidden [overflow-wrap:anywhere]\">\n {isFolder ? (\n versioningEnabled ? (\n <Trans>\n Confirm deletion of {displayName}. All objects inside this folder will be marked as deleted but can be\n restored from version history.\n </Trans>\n ) : (\n <Trans>\n Confirm deletion of {displayName}. All objects inside this folder will be permanently deleted. This\n action cannot be undone.\n </Trans>\n )\n ) : versioningEnabled ? (\n <Trans>\n Confirm deletion of {displayName}. The object will be marked as deleted but can be restored from version\n history.\n </Trans>\n ) : (\n <Trans>\n Confirm deletion of {displayName}. The object will be permanently deleted. This action cannot be undone.\n </Trans>\n )}\n </p>\n\n {!isFolder ? (\n <DescriptionList>\n <DescriptionTerm>\n <Trans>Name</Trans>\n </DescriptionTerm>\n <DescriptionDefinition className=\"overflow-x-hidden [overflow-wrap:anywhere]\">\n {displayName}\n </DescriptionDefinition>\n\n <DescriptionTerm>\n <Trans>Size</Trans>\n </DescriptionTerm>\n <DescriptionDefinition>\n {objectSize !== undefined ? formatBytesBinary(objectSize) : \"-\"}\n </DescriptionDefinition>\n\n <DescriptionTerm>\n <Trans>Last Modified</Trans>\n </DescriptionTerm>\n <DescriptionDefinition>\n {lastModified ? new Date(lastModified).toLocaleString() : \"-\"}\n </DescriptionDefinition>\n\n <DescriptionTerm>\n <Trans>Full Path</Trans>\n </DescriptionTerm>\n <DescriptionDefinition className=\"overflow-x-hidden [overflow-wrap:anywhere]\">\n {objectKey}\n </DescriptionDefinition>\n </DescriptionList>\n ) : (\n <DescriptionList>\n <DescriptionTerm>\n <Trans>Name</Trans>\n </DescriptionTerm>\n <DescriptionDefinition className=\"overflow-x-hidden [overflow-wrap:anywhere]\">\n {displayName}\n </DescriptionDefinition>\n\n <DescriptionTerm>\n <Trans>Full Path</Trans>\n </DescriptionTerm>\n <DescriptionDefinition className=\"overflow-x-hidden [overflow-wrap:anywhere]\">\n {objectKey}\n </DescriptionDefinition>\n </DescriptionList>\n )}\n\n <Form\n className=\"mb-0\"\n id=\"delete-object-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 id={field.name}\n name={field.name}\n label={t`Type \"delete\" to confirm`}\n value={field.state.value}\n onChange={(e) => field.handleChange(e.target.value)}\n placeholder=\"delete\"\n autoFocus\n disabled={deleteMutation.isPending}\n required\n />\n )}\n />\n </FormSection>\n </Form>\n\n {deleteMutation.error && (\n <p className=\"text-juno-red text-sm\">\n <Trans>Error:</Trans> {deleteMutation.error.message}\n </p>\n )}\n </Stack>\n </Modal>\n )\n}\n","import type { DeleteObjectError } from \"@/server/Storage/types/ceph\"\n\n/**\n * S3's DeleteObjects reports per-item failures inline in an otherwise successful\n * (HTTP 200) response, so a *resolved* deleteVersionsBulk mutation can still carry\n * failures. Flatten those entries into one human-readable line for the small\n * single/two-item version modals, which have no room for a per-key results table\n * (DeleteObjectsModal renders the full breakdown for large selections instead).\n */\nexport const formatBulkDeleteErrors = (errors: DeleteObjectError[]): string =>\n errors\n .map((error) => {\n const label = error.versionId ? `${error.key} (${error.versionId})` : error.key\n const detail = [error.code, error.message].filter(Boolean).join(\": \")\n return detail ? `${label}: ${detail}` : label\n })\n .join(\"; \")\n","import { useState } from \"react\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { Modal, Stack, TextInput } from \"@cloudoperators/juno-ui-components\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport { useModalTracking } from \"@/client/hooks/useModalTracking\"\nimport { formatBytesBinary } from \"@/client/utils/formatBytes\"\nimport type { DeleteObjectsBulkOutput } from \"@/server/Storage/types/ceph\"\nimport { formatBulkDeleteErrors } from \"./utils/bulkDeleteErrors\"\n\ninterface DeleteVersionModalProps {\n isOpen: boolean\n bucketName: string\n objectKey: string\n versionId: string\n versionDate?: string\n versionSize?: number\n isDeleteMarker?: boolean\n folderMarkerVersionId?: string\n allVersionIds?: string[]\n onClose: () => void\n onSuccess?: (objectKey: string, versionId: string) => void\n onError?: (objectKey: string, errorMessage: string) => void\n}\n\nexport const DeleteVersionModal = ({\n isOpen,\n bucketName,\n objectKey,\n versionId,\n versionDate,\n versionSize,\n isDeleteMarker = false,\n folderMarkerVersionId,\n allVersionIds,\n onClose,\n onSuccess,\n onError,\n}: DeleteVersionModalProps) => {\n const { t } = useLingui()\n const projectId = useProjectId()\n const [confirmText, setConfirmText] = useState(\"\")\n const [failureMessage, setFailureMessage] = useState<string | null>(null)\n const isFolder = objectKey.endsWith(\"/\")\n\n const { trackClose, markSubmitted, resetTracking } = useModalTracking({\n isOpen,\n actionPrefix: \"storage.ceph.object.version.delete\",\n })\n\n const utils = trpcReact.useUtils()\n\n // Use bulk delete endpoint for all cases (single or multiple versions)\n // This simplifies logic and handles atomic folder deletion\n const deleteMutation = trpcReact.storage.ceph.objects.deleteVersionsBulk.useMutation({\n onSuccess: (result: DeleteObjectsBulkOutput) => {\n // Invalidate regardless of outcome: on a partial failure some versions really\n // were deleted, so the cached lists are stale either way.\n utils.storage.ceph.versioning.listObjectVersions.invalidate()\n utils.storage.ceph.versioning.checkDeletedContent.invalidate()\n utils.storage.ceph.objects.list.invalidate()\n utils.storage.ceph.containers.list.invalidate()\n // deleteVersionsBulk resolves even when S3 refused individual versions: those\n // come back in `errors` on an HTTP 200, not as a thrown error.\n if (result.errorCount > 0) {\n setFailureMessage(formatBulkDeleteErrors(result.errors))\n return\n }\n onSuccess?.(objectKey, versionId)\n handleClose()\n },\n onError: (error) => {\n onError?.(objectKey, error.message)\n },\n })\n\n const handleClose = () => {\n setConfirmText(\"\")\n setFailureMessage(null)\n resetTracking()\n deleteMutation.reset()\n onClose()\n }\n\n // Show \"all versions\" UI if array has multiple versions\n // Must be computed before handleDelete to ensure consistent behavior\n const isDeletingAllVersions = allVersionIds && allVersionIds.length > 0\n\n const handleDelete = () => {\n if (confirmText !== \"delete\") return\n\n setFailureMessage(null)\n markSubmitted()\n\n // Build versions array:\n // - For deleted folders: include both delete marker and folder marker\n // - For deleted files (with delete marker): include ALL versions (complete deletion)\n // - For regular versions: include only the version itself\n const versions =\n isFolder && isDeleteMarker && folderMarkerVersionId\n ? [\n { key: objectKey, versionId }, // Delete marker of the folder\n { key: objectKey, versionId: folderMarkerVersionId }, // Folder marker itself\n ]\n : isDeletingAllVersions\n ? allVersionIds.map((vid) => ({ key: objectKey, versionId: vid })) // Delete ALL versions\n : [{ key: objectKey, versionId }] // Single version\n\n deleteMutation.mutate({\n project_id: projectId,\n containerName: bucketName,\n versions,\n })\n }\n\n if (!isOpen) return null\n\n return (\n <Modal\n title={isDeletingAllVersions ? t`Delete All Versions` : t`Delete Version`}\n open={isOpen}\n onCancel={() => {\n trackClose()\n handleClose()\n }}\n confirmButtonLabel={isDeletingAllVersions ? t`Delete All Versions` : t`Delete Version`}\n onConfirm={handleDelete}\n cancelButtonLabel={t`Cancel`}\n disableConfirmButton={confirmText !== \"delete\" || deleteMutation.isPending}\n confirmButtonVariant=\"primary-danger\"\n >\n <Stack direction=\"vertical\" gap=\"4\">\n <p className=\"text-theme-default overflow-x-hidden [overflow-wrap:anywhere]\">\n {isDeletingAllVersions ? (\n <Trans>This object and all its versions will be permanently deleted and cannot be restored.</Trans>\n ) : (\n <Trans>This version will be permanently deleted and cannot be restored.</Trans>\n )}\n </p>\n\n <div className=\"space-y-3\">\n <div>\n <label className=\"text-sm font-semibold\">\n <Trans>Object:</Trans>\n </label>\n <p className=\"mt-1 overflow-x-hidden text-sm [overflow-wrap:anywhere]\">{objectKey}</p>\n </div>\n\n {isDeletingAllVersions ? (\n <div>\n <label className=\"text-sm font-semibold\">\n <Trans>Versions to delete:</Trans>\n </label>\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 {allVersionIds!.map((vid, idx) => (\n <code key={idx} className=\"block overflow-x-hidden text-xs [overflow-wrap:anywhere]\">\n {vid}\n </code>\n ))}\n </Stack>\n </div>\n </div>\n ) : (\n <div>\n <label className=\"text-sm font-semibold\">\n <Trans>Version ID:</Trans>\n </label>\n <p className=\"mt-1 overflow-x-hidden [overflow-wrap:anywhere]\">\n <code className=\"text-sm\">{versionId}</code>\n </p>\n </div>\n )}\n\n {!isDeleteMarker && versionDate && (\n <div>\n <label className=\"text-sm font-semibold\">\n <Trans>Date:</Trans>\n </label>\n <p className=\"mt-1 text-sm\">{new Date(versionDate).toLocaleString()}</p>\n </div>\n )}\n\n {!isDeleteMarker && versionSize !== undefined && (\n <div>\n <label className=\"text-sm font-semibold\">\n <Trans>Size:</Trans>\n </label>\n <p className=\"mt-1 text-sm\">{formatBytesBinary(versionSize)}</p>\n </div>\n )}\n </div>\n\n <div>\n <TextInput\n label={t`Type \"delete\" to confirm`}\n value={confirmText}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) => setConfirmText(e.target.value)}\n placeholder=\"delete\"\n autoFocus\n disabled={deleteMutation.isPending}\n />\n </div>\n\n {deleteMutation.error && (\n <p className=\"text-juno-red text-sm\">\n <Trans>Error:</Trans> {deleteMutation.error.message}\n </p>\n )}\n {failureMessage && (\n <p className=\"text-juno-red text-sm\">\n <Trans>Error:</Trans> {failureMessage}\n </p>\n )}\n </Stack>\n </Modal>\n )\n}\n","import { useState } from \"react\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { Modal, Stack } from \"@cloudoperators/juno-ui-components\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport { useModalTracking } from \"@/client/hooks/useModalTracking\"\nimport { formatBytesBinary } from \"@/client/utils/formatBytes\"\nimport type { DeleteObjectsBulkOutput } from \"@/server/Storage/types/ceph\"\nimport { formatBulkDeleteErrors } from \"./utils/bulkDeleteErrors\"\n\ninterface RestoreVersionModalProps {\n isOpen: boolean\n bucketName: string\n objectKey: string\n versionId: string\n versionDate?: string\n versionSize?: number\n onClose: () => void\n onSuccess?: (objectKey: string, versionId: string) => void\n onError?: (objectKey: string, errorMessage: string) => void\n}\n\nexport const RestoreVersionModal = ({\n isOpen,\n bucketName,\n objectKey,\n versionId,\n versionDate,\n versionSize,\n onClose,\n onSuccess,\n onError,\n}: RestoreVersionModalProps) => {\n const { t } = useLingui()\n const projectId = useProjectId()\n const [failureMessage, setFailureMessage] = useState<string | null>(null)\n\n const { trackClose, markSubmitted, resetTracking } = useModalTracking({\n isOpen,\n actionPrefix: \"storage.ceph.object.version.restore\",\n })\n\n const utils = trpcReact.useUtils()\n\n // For folders (keys ending with \"/\"), we delete the delete marker instead of copying\n const isFolder = objectKey.endsWith(\"/\")\n\n const invalidateAfterRestore = () => {\n utils.storage.ceph.versioning.listObjectVersions.invalidate()\n utils.storage.ceph.versioning.checkDeletedContent.invalidate()\n utils.storage.ceph.objects.list.invalidate()\n utils.storage.ceph.containers.list.invalidate()\n }\n\n // versioning.restoreVersion either succeeds or rejects — no per-item results.\n const handleRestoreSuccess = () => {\n invalidateAfterRestore()\n onSuccess?.(objectKey, versionId)\n handleClose()\n }\n\n // deleteVersionsBulk resolves even when S3 refused the delete marker: a per-item\n // failure comes back in `errors`, not as a thrown error. Treat it as a failure.\n const handleDeleteMarkerSuccess = (result: DeleteObjectsBulkOutput) => {\n invalidateAfterRestore()\n if (result.errorCount > 0) {\n setFailureMessage(formatBulkDeleteErrors(result.errors))\n return\n }\n onSuccess?.(objectKey, versionId)\n handleClose()\n }\n\n const restoreMutation = trpcReact.storage.ceph.versioning.restoreVersion.useMutation({\n onSuccess: handleRestoreSuccess,\n onError: (error) => {\n onError?.(objectKey, error.message)\n handleClose()\n },\n onSettled: () => {\n restoreMutation.reset()\n },\n })\n\n const deleteVersionMutation = trpcReact.storage.ceph.objects.deleteVersionsBulk.useMutation({\n onSuccess: handleDeleteMarkerSuccess,\n onError: (error) => {\n onError?.(objectKey, error.message)\n handleClose()\n },\n onSettled: () => {\n deleteVersionMutation.reset()\n },\n })\n\n const handleClose = () => {\n setFailureMessage(null)\n resetTracking()\n onClose()\n }\n\n const handleRestore = () => {\n setFailureMessage(null)\n markSubmitted()\n if (isFolder) {\n // For folders, delete the delete marker instead of copying\n deleteVersionMutation.mutate({\n project_id: projectId,\n containerName: bucketName,\n versions: [{ key: objectKey, versionId }],\n })\n } else {\n // For files, copy the old version to make it current\n restoreMutation.mutate({\n project_id: projectId,\n bucket: bucketName,\n key: objectKey,\n versionId,\n })\n }\n }\n\n if (!isOpen) return null\n\n return (\n <Modal\n title={isFolder ? t`Restore Folder` : t`Restore Version`}\n open={isOpen}\n onCancel={() => {\n trackClose()\n handleClose()\n }}\n confirmButtonLabel={isFolder ? t`Restore Folder` : t`Restore Version`}\n onConfirm={handleRestore}\n cancelButtonLabel={t`Cancel`}\n disableConfirmButton={restoreMutation.isPending || deleteVersionMutation.isPending}\n >\n <Stack direction=\"vertical\" gap=\"4\">\n {isFolder ? (\n <>\n <div>\n <label className=\"text-sm font-semibold\">\n <Trans>Folder name:</Trans>\n </label>{\" \"}\n <span className=\"text-sm\">{objectKey}</span>\n </div>\n <p className=\"text-sm\">\n <Trans>\n Only the folder itself will be restored. Objects inside this folder will remain deleted and must be\n restored individually.\n </Trans>\n </p>\n </>\n ) : (\n <>\n <div className=\"space-y-3\">\n <div>\n <label className=\"text-sm font-semibold\">\n <Trans>Object:</Trans>\n </label>\n <p className=\"mt-1 text-sm\">{objectKey}</p>\n </div>\n\n <div>\n <label className=\"text-sm font-semibold\">\n <Trans>Version ID:</Trans>\n </label>\n <p className=\"mt-1\">\n <code className=\"text-sm\">{versionId}</code>\n </p>\n </div>\n\n {versionDate && (\n <div>\n <label className=\"text-sm font-semibold\">\n <Trans>Date:</Trans>\n </label>\n <p className=\"mt-1 text-sm\">{new Date(versionDate).toLocaleString()}</p>\n </div>\n )}\n\n {versionSize !== undefined && (\n <div>\n <label className=\"text-sm font-semibold\">\n <Trans>Size:</Trans>\n </label>\n <p className=\"mt-1 text-sm\">{formatBytesBinary(versionSize)}</p>\n </div>\n )}\n </div>\n\n <p className=\"text-sm\">\n <Trans>After restoring, this version's content will become the new latest version.</Trans>\n </p>\n </>\n )}\n {failureMessage && (\n <p className=\"text-juno-red text-sm\">\n <Trans>Error:</Trans> {failureMessage}\n </p>\n )}\n </Stack>\n </Modal>\n )\n}\n","import type { MessageDescriptor } from \"@lingui/core\"\nimport { msg } from \"@lingui/core/macro\"\n\nexport interface ValidationError {\n type: \"required\" | \"invalid-chars\" | \"whitespace\" | \"duplicate\" | \"too-long\" | \"slashes\"\n message: MessageDescriptor\n}\n\n/**\n * Validates folder names for inline folder creation in object browser\n * Used in Copy/Move/Create folder modals\n */\nexport const validateFolderName = (\n name: string,\n existingNames: string[],\n currentPrefix = \"\"\n): ValidationError | null => {\n const trimmed = name.trim()\n\n if (!trimmed) {\n return {\n type: \"required\",\n message: msg`Folder name is required`,\n }\n }\n\n if (trimmed.includes(\"/\")) {\n return {\n type: \"slashes\",\n message: msg`Folder name cannot contain slashes`,\n }\n }\n\n if (trimmed !== name) {\n return {\n type: \"whitespace\",\n message: msg`Folder name cannot have leading or trailing whitespace`,\n }\n }\n\n if (trimmed.length > 255) {\n return {\n type: \"too-long\",\n message: msg`Folder name is too long (max 255 characters)`,\n }\n }\n\n // Check against existing folders at current level\n const newPath = `${currentPrefix}${trimmed}/`\n if (existingNames.includes(newPath)) {\n return {\n type: \"duplicate\",\n message: msg`A folder with this name already exists`,\n }\n }\n\n return null\n}\n\n/**\n * Validates object names for rename/move operations\n */\nexport const validateObjectName = (name: string): ValidationError | null => {\n const trimmed = name.trim()\n\n if (!trimmed) {\n return {\n type: \"required\",\n message: msg`Object name is required`,\n }\n }\n\n if (trimmed.includes(\"/\")) {\n return {\n type: \"slashes\",\n message: msg`Object name cannot contain slashes`,\n }\n }\n\n if (trimmed !== name) {\n return {\n type: \"whitespace\",\n message: msg`Object name cannot have leading or trailing whitespace`,\n }\n }\n\n return null\n}\n\n/**\n * Validates metadata keys for S3 custom metadata\n * S3 requires: alphanumeric, hyphen, underscore only\n */\nexport const validateMetadataKey = (key: string): ValidationError | null => {\n const VALID_KEY_RE = /^[a-zA-Z0-9_-]+$/\n\n if (!key.trim()) {\n return {\n type: \"required\",\n message: msg`Key is required`,\n }\n }\n\n if (!VALID_KEY_RE.test(key)) {\n return {\n type: \"invalid-chars\",\n message: msg`Key contains invalid characters (use only letters, digits, hyphens, underscores)`,\n }\n }\n\n if (!/[a-zA-Z0-9]/.test(key)) {\n return {\n type: \"invalid-chars\",\n message: msg`Key must contain at least one alphanumeric character`,\n }\n }\n\n return null\n}\n","import { useState, useCallback } from \"react\"\nimport { useLingui } from \"@lingui/react/macro\"\nimport { validateFolderName } from \"../utils/objectValidation\"\n\ninterface BrowserRow {\n kind: \"folder\" | \"object\"\n name: string\n displayName: string\n}\n\ninterface UseObjectBrowserResult {\n currentPrefix: string\n newFolderName: string\n newFolderError: string | null\n showNewFolderInput: boolean\n navigateToPrefix: (prefix: string) => void\n navigateUp: () => void\n startCreateFolder: () => void\n cancelCreateFolder: () => void\n setNewFolderName: (name: string) => void\n createFolder: () => string | null\n reset: () => void\n}\n\n/**\n * Manages object browser navigation and inline folder creation\n * Shared between Copy and Move modals\n */\nexport const useObjectBrowser = (\n existingRows: BrowserRow[],\n onFolderCreated?: (path: string) => void\n): UseObjectBrowserResult => {\n const { t } = useLingui()\n const [currentPrefix, setCurrentPrefix] = useState(\"\")\n const [newFolderName, setNewFolderName] = useState(\"\")\n const [newFolderError, setNewFolderError] = useState<string | null>(null)\n const [showNewFolderInput, setShowNewFolderInput] = useState(false)\n\n const navigateToPrefix = useCallback((prefix: string) => {\n setCurrentPrefix(prefix)\n setShowNewFolderInput(false)\n setNewFolderName(\"\")\n setNewFolderError(null)\n }, [])\n\n const navigateUp = useCallback(() => {\n if (!currentPrefix) return\n const parts = currentPrefix.replace(/\\/$/, \"\").split(\"/\")\n parts.pop()\n const newPrefix = parts.length > 0 ? parts.join(\"/\") + \"/\" : \"\"\n navigateToPrefix(newPrefix)\n }, [currentPrefix, navigateToPrefix])\n\n const startCreateFolder = useCallback(() => {\n setShowNewFolderInput(true)\n setNewFolderName(\"\")\n setNewFolderError(null)\n }, [])\n\n const cancelCreateFolder = useCallback(() => {\n setShowNewFolderInput(false)\n setNewFolderName(\"\")\n setNewFolderError(null)\n }, [])\n\n const handleSetNewFolderName = useCallback(\n (name: string) => {\n setNewFolderName(name)\n if (newFolderError) setNewFolderError(null)\n },\n [newFolderError]\n )\n\n const createFolder = useCallback((): string | null => {\n const existingNames = existingRows.map((r) => r.name)\n const error = validateFolderName(newFolderName, existingNames, currentPrefix)\n\n if (error) {\n setNewFolderError(t(error.message))\n return null\n }\n\n const trimmed = newFolderName.trim()\n const newPath = `${currentPrefix}${trimmed}/`\n\n onFolderCreated?.(newPath)\n setNewFolderName(\"\")\n setShowNewFolderInput(false)\n setNewFolderError(null)\n setCurrentPrefix(newPath)\n\n return newPath\n }, [newFolderName, existingRows, currentPrefix, onFolderCreated, t])\n\n const reset = useCallback(() => {\n setCurrentPrefix(\"\")\n setNewFolderName(\"\")\n setNewFolderError(null)\n setShowNewFolderInput(false)\n }, [])\n\n return {\n currentPrefix,\n newFolderName,\n newFolderError,\n showNewFolderInput,\n navigateToPrefix,\n navigateUp,\n startCreateFolder,\n cancelCreateFolder,\n setNewFolderName: handleSetNewFolderName,\n createFolder,\n reset,\n }\n}\n","import { useState, useRef, useEffect, useCallback } from \"react\"\n\nconst MAX_COMBO_OPTIONS = 50\n\ninterface UseBucketSearchResult {\n searchTerm: string\n debouncedSearch: string\n visibleBuckets: Array<{ name: string }>\n hiddenCount: number\n handleSearchChange: (e: React.ChangeEvent<HTMLInputElement>) => void\n reset: () => void\n}\n\n/**\n * Debounced bucket search with result limiting\n * Shared between Copy and Move modals\n */\nexport const useBucketSearch = (allBuckets: Array<{ name: string }> | undefined): UseBucketSearchResult => {\n const [searchTerm, setSearchTerm] = useState(\"\")\n const [debouncedSearch, setDebouncedSearch] = useState(\"\")\n const debounceTimer = useRef<ReturnType<typeof setTimeout> | null>(null)\n\n // Cleanup timer on unmount\n useEffect(\n () => () => {\n if (debounceTimer.current) clearTimeout(debounceTimer.current)\n },\n []\n )\n\n const handleSearchChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {\n const value = e.target.value\n setSearchTerm(value)\n if (debounceTimer.current) clearTimeout(debounceTimer.current)\n debounceTimer.current = setTimeout(() => setDebouncedSearch(value), 300)\n }, [])\n\n const reset = useCallback(() => {\n setSearchTerm(\"\")\n setDebouncedSearch(\"\")\n if (debounceTimer.current) clearTimeout(debounceTimer.current)\n }, [])\n\n // Filter and limit results\n const filteredBuckets =\n debouncedSearch.trim().length > 0\n ? (allBuckets ?? []).filter((b) => b.name.toLowerCase().includes(debouncedSearch.toLowerCase()))\n : (allBuckets ?? [])\n\n const visibleBuckets = filteredBuckets.slice(0, MAX_COMBO_OPTIONS)\n const hiddenCount = filteredBuckets.length - visibleBuckets.length\n\n return {\n searchTerm,\n debouncedSearch,\n visibleBuckets,\n hiddenCount,\n handleSearchChange,\n reset,\n }\n}\n","import { useState, useCallback } from \"react\"\n\ninterface UseLocalFoldersResult {\n localFolders: Record<string, string[]>\n addFolder: (bucket: string, path: string) => void\n clearForBucket: (bucket: string) => void\n reset: () => void\n}\n\n/**\n * Manages locally created folders (not yet persisted to S3)\n * Folders are created as empty prefixes when user navigates into them\n */\nexport const useLocalFolders = (): UseLocalFoldersResult => {\n const [localFolders, setLocalFolders] = useState<Record<string, string[]>>({})\n\n const addFolder = useCallback((bucket: string, path: string) => {\n setLocalFolders((prev) => ({\n ...prev,\n [bucket]: [...(prev[bucket] ?? []), path],\n }))\n }, [])\n\n const clearForBucket = useCallback((bucket: string) => {\n setLocalFolders((prev) => {\n const next = { ...prev }\n delete next[bucket]\n return next\n })\n }, [])\n\n const reset = useCallback(() => {\n setLocalFolders({})\n }, [])\n\n return {\n localFolders,\n addFolder,\n clearForBucket,\n reset,\n }\n}\n","import { useState, useCallback } from \"react\"\nimport { useObjectBrowser } from \"./useObjectBrowser\"\nimport { useBucketSearch } from \"./useBucketSearch\"\nimport { useLocalFolders } from \"./useLocalFolders\"\n\ninterface BrowserRow {\n kind: \"folder\" | \"object\"\n name: string\n displayName: string\n}\n\ninterface UseCopyMoveModalStateParams {\n initialBucket: string\n allBuckets: Array<{ name: string }>\n existingRows: BrowserRow[]\n}\n\n/**\n * Consolidated state management for Copy/Move modals\n * Combines browser navigation, bucket search, and local folder management\n */\nexport const useCopyMoveModalState = ({ initialBucket, allBuckets, existingRows }: UseCopyMoveModalStateParams) => {\n const localFoldersState = useLocalFolders()\n\n const browserState = useObjectBrowser(existingRows, (path) => {\n // When folder is created in browser, add to local folders\n localFoldersState.addFolder(targetBucket, path)\n })\n\n const bucketSearchState = useBucketSearch(allBuckets)\n\n // Target bucket state (not extracted to separate hook since it's simple)\n const [targetBucket, setTargetBucket] = useState(initialBucket)\n\n const handleBucketChange = useCallback(\n (bucket: string) => {\n setTargetBucket(bucket)\n browserState.reset()\n localFoldersState.clearForBucket(bucket)\n },\n [browserState, localFoldersState]\n )\n\n const resetAll = useCallback(() => {\n setTargetBucket(initialBucket)\n browserState.reset()\n bucketSearchState.reset()\n localFoldersState.reset()\n }, [initialBucket, browserState, bucketSearchState, localFoldersState])\n\n return {\n // Target bucket\n targetBucket,\n setTargetBucket: handleBucketChange,\n\n // Browser state\n ...browserState,\n\n // Bucket search\n ...bucketSearchState,\n\n // Local folders\n ...localFoldersState,\n\n // Reset all\n resetAll,\n }\n}\n","import { useState, useRef, useEffect, useCallback } from \"react\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport { useModalTracking } from \"@/client/hooks/useModalTracking\"\nimport {\n Modal,\n Stack,\n Spinner,\n Status,\n ComboBox,\n ComboBoxOption,\n TextInput,\n Button,\n} from \"@cloudoperators/juno-ui-components\"\nimport { MdFolder, MdDescription, MdCreateNewFolder, MdArrowBack } from \"react-icons/md\"\nimport { useVirtualizer } from \"@tanstack/react-virtual\"\nimport { useCopyMoveModalState } from \"./hooks/useCopyMoveModalState\"\n\nconst MAX_COMBO_OPTIONS = 50\n\ninterface CopyObjectModalProps {\n isOpen: boolean\n bucketName: string\n objectKey: string\n objectSize?: number\n onClose: () => void\n onSuccess?: (objectKey: string, targetBucket: string, targetKey: string, wasOverwritten: boolean) => void\n onError?: (objectKey: string, errorMessage: string) => void\n}\n\ninterface FolderRow {\n kind: \"folder\"\n name: string\n displayName: string\n}\n\ninterface ObjectRow {\n kind: \"object\"\n name: string\n displayName: string\n}\n\ntype BrowserRow = FolderRow | ObjectRow\n\nexport const CopyObjectModal = ({\n isOpen,\n bucketName,\n objectKey,\n objectSize,\n onClose,\n onSuccess,\n onError,\n}: CopyObjectModalProps) => {\n const { t } = useLingui()\n const projectId = useProjectId()\n const utils = trpcReact.useUtils()\n const submittedKeyRef = useRef(\"\")\n\n const { trackClose, markSubmitted, resetTracking } = useModalTracking({\n isOpen,\n actionPrefix: \"storage.ceph.object.copy\",\n })\n\n const [copyMetadata, setCopyMetadata] = useState(true)\n const [targetExists, setTargetExists] = useState(false)\n const [checkingTarget, setCheckingTarget] = useState(false)\n const listRef = useRef<HTMLDivElement>(null)\n\n // ── Data fetching ─────────────────────────────────────────────────────────\n\n const { data: buckets, isLoading: isLoadingBuckets } = trpcReact.storage.ceph.containers.list.useQuery(\n { project_id: projectId ?? \"\", includeMetadata: false },\n { enabled: isOpen && !!projectId }\n )\n\n // Initialize modal state with consolidated hook\n const modalState = useCopyMoveModalState({\n initialBucket: bucketName,\n allBuckets: buckets ?? [],\n existingRows: [], // Will be populated from objectsData\n })\n\n const { data: objectsData, isLoading: isLoadingObjects } = trpcReact.storage.ceph.objects.list.useQuery(\n {\n project_id: projectId ?? \"\",\n containerName: modalState.targetBucket,\n prefix: modalState.currentPrefix || undefined,\n delimiter: \"/\",\n maxKeys: 1000,\n },\n { enabled: isOpen && !!modalState.targetBucket && !!projectId }\n )\n\n // Reset state when modal opens or closes\n useEffect(() => {\n if (isOpen) {\n modalState.resetAll()\n }\n }, [isOpen])\n\n // ── Build rows from S3 response ───────────────────────────────────────────\n\n const buildRows = (): BrowserRow[] => {\n if (!objectsData) return []\n\n const folders: FolderRow[] = objectsData.folders.map((folder) => ({\n kind: \"folder\" as const,\n name: folder.prefix,\n displayName: modalState.currentPrefix\n ? folder.prefix.replace(modalState.currentPrefix, \"\").replace(/\\/$/, \"\")\n : folder.prefix.replace(/\\/$/, \"\"),\n }))\n\n const objects: ObjectRow[] = objectsData.objects\n .filter((obj) => {\n const stripped = modalState.currentPrefix ? obj.key.replace(modalState.currentPrefix, \"\") : obj.key\n return stripped !== \"\" && stripped !== \"/\"\n })\n .map((obj) => ({\n kind: \"object\" as const,\n name: obj.key,\n displayName: modalState.currentPrefix ? obj.key.replace(modalState.currentPrefix, \"\") : obj.key,\n }))\n\n return [...folders, ...objects]\n }\n\n // ── Rows: merge server data with locally created folders ──────────────────\n\n const serverRows = buildRows()\n const bucketLocalFolders = modalState.localFolders[modalState.targetBucket] ?? []\n const localFolderRows: BrowserRow[] = bucketLocalFolders\n .filter((fp) => {\n const withoutPrefix = fp.startsWith(modalState.currentPrefix) ? fp.slice(modalState.currentPrefix.length) : null\n if (!withoutPrefix) return false\n const parts = withoutPrefix.split(\"/\").filter(Boolean)\n return parts.length === 1\n })\n .filter((fp) => !serverRows.some((r) => r.name === fp))\n .map((fp) => ({\n kind: \"folder\" as const,\n name: fp,\n displayName: fp.slice(modalState.currentPrefix.length).replace(/\\/$/, \"\"),\n }))\n\n const rows: BrowserRow[] = [\n ...serverRows.filter((r) => r.kind === \"folder\"),\n ...localFolderRows,\n ...serverRows.filter((r) => r.kind === \"object\"),\n ]\n\n // ── Copy mutation ─────────────────────────────────────────────────────────\n\n const copyMutation = trpcReact.storage.ceph.objects.copy.useMutation({\n onSuccess: () => {\n utils.storage.ceph.objects.list.invalidate()\n utils.storage.ceph.containers.list.invalidate()\n const targetKey = `${modalState.currentPrefix}${displayName}`\n onSuccess?.(submittedKeyRef.current, modalState.targetBucket, targetKey, targetExists)\n handleClose()\n },\n onError: (error: { message: string }) => {\n onError?.(submittedKeyRef.current, error.message)\n },\n })\n\n // ── Check if target object exists ─────────────────────────────────────────\n\n const displayName = objectKey.split(\"/\").filter(Boolean).pop() ?? objectKey\n\n const checkTargetExists = useCallback(async () => {\n if (!projectId || !modalState.targetBucket) return\n\n const targetKey = `${modalState.currentPrefix}${displayName}`\n\n // Don't check if source and target are the same\n if (modalState.targetBucket === bucketName && targetKey === objectKey) {\n setTargetExists(false)\n return\n }\n\n setCheckingTarget(true)\n try {\n await utils.storage.ceph.objects.getDetails.fetch({\n project_id: projectId,\n containerName: modalState.targetBucket,\n objectKey: targetKey,\n })\n setTargetExists(true)\n } catch {\n setTargetExists(false)\n } finally {\n setCheckingTarget(false)\n }\n }, [projectId, modalState.targetBucket, modalState.currentPrefix, displayName, bucketName, objectKey, utils])\n\n useEffect(() => {\n if (isOpen) {\n checkTargetExists()\n }\n }, [isOpen, checkTargetExists])\n\n // ── Handlers ──────────────────────────────────────────────────────────────\n\n const handleClose = () => {\n copyMutation.reset()\n resetTracking()\n onClose()\n }\n\n const handleBucketChange = (value?: string | number | string[] | undefined) => {\n const v = Array.isArray(value) ? value[0] : typeof value === \"number\" ? String(value) : value\n if (v) {\n modalState.setTargetBucket(v)\n }\n }\n\n // Synchronize targetBucket with searchTerm when it matches an exact bucket name\n useEffect(() => {\n const trimmedSearch = modalState.searchTerm.trim()\n if (trimmedSearch && buckets) {\n const matchingBucket = buckets.find((b) => b.name === trimmedSearch)\n if (matchingBucket && matchingBucket.name !== modalState.targetBucket) {\n modalState.setTargetBucket(matchingBucket.name)\n }\n }\n }, [modalState.searchTerm, buckets, modalState.targetBucket, modalState])\n\n const handleNewFolderKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === \"Enter\") modalState.createFolder()\n if (e.key === \"Escape\") modalState.cancelCreateFolder()\n }\n\n const handleCopy = () => {\n if (!projectId) return\n markSubmitted()\n submittedKeyRef.current = objectKey\n const targetKey = `${modalState.currentPrefix}${displayName}`\n copyMutation.mutate({\n project_id: projectId,\n sourceBucket: bucketName,\n sourceKey: objectKey,\n destinationBucket: modalState.targetBucket,\n destinationKey: targetKey,\n copyMetadata,\n })\n }\n\n // ── Virtualized folder browser ─────────────────────────────────────────────\n\n const folderRows = rows.filter((r) => r.kind === \"folder\")\n const objectRows = rows.filter((r) => r.kind === \"object\")\n const allBrowserRows = [...folderRows, ...objectRows]\n\n const rowVirtualizer = useVirtualizer({\n count: allBrowserRows.length,\n getScrollElement: () => listRef.current,\n estimateSize: () => 32,\n overscan: 5,\n })\n\n if (!isOpen) return null\n\n const isPending = copyMutation.isPending\n const isLoading = isLoadingObjects\n\n const targetPathDisplay = `${modalState.targetBucket}/${modalState.currentPrefix}${displayName}`\n const initialPrefix = objectKey.endsWith(displayName) ? objectKey.slice(0, objectKey.length - displayName.length) : \"\"\n const isUnchanged = modalState.targetBucket === bucketName && modalState.currentPrefix === initialPrefix\n\n return (\n <Modal\n title={\n <span className=\"flex max-w-125 items-center gap-1\">\n <span className=\"shrink-0\">\n <Trans>Copy object:</Trans>\n </span>\n <span className=\"truncate\" title={displayName}>\n {displayName}\n </span>\n </span>\n }\n open={isOpen}\n onCancel={() => {\n trackClose()\n handleClose()\n }}\n confirmButtonLabel={isPending ? t`Copying...` : t`Copy Object`}\n onConfirm={handleCopy}\n cancelButtonLabel={t`Cancel`}\n size=\"large\"\n disableConfirmButton={isPending || isLoadingBuckets || isUnchanged}\n disableCancelButton={isPending || isLoadingBuckets}\n disableCloseButton={isPending || isLoadingBuckets || isUnchanged}\n >\n {isPending ? (\n <Status status=\"progress\" title={t`Copying Object...`} />\n ) : (\n <Stack direction=\"vertical\" gap=\"4\">\n {/* Target bucket — ComboBox with debounced search */}\n <ComboBox\n label={t`Target bucket`}\n value={modalState.searchTerm || undefined}\n onChange={handleBucketChange}\n onInputChange={modalState.handleSearchChange}\n placeholder={bucketName}\n helptext={(() => {\n if (isLoadingBuckets) return t`Loading buckets...`\n const bucketsCount = buckets?.length ?? 0\n if (!modalState.searchTerm.trim() && bucketsCount > MAX_COMBO_OPTIONS) {\n return t`There are ${bucketsCount} buckets, start typing to search`\n }\n if (modalState.hiddenCount > 0) {\n const totalBuckets = modalState.visibleBuckets.length + modalState.hiddenCount\n return t`Showing first ${MAX_COMBO_OPTIONS} of ${totalBuckets}, refine your search to narrow results`\n }\n return undefined\n })()}\n disabled={isLoadingBuckets || isPending}\n required\n >\n {!modalState.searchTerm.trim() && (buckets?.length ?? 0) > MAX_COMBO_OPTIONS ? (\n <ComboBoxOption key=\"__placeholder__\" value=\"\" disabled>\n {t`Start typing to search for a bucket`}\n </ComboBoxOption>\n ) : (\n modalState.visibleBuckets.map((b) => (\n <ComboBoxOption key={b.name} value={b.name}>\n {b.name}\n </ComboBoxOption>\n ))\n )}\n </ComboBox>\n\n {/* Folder browser */}\n <div>\n <div className=\"mb-1 flex items-center justify-between\">\n <span className=\"text-sm font-medium\">\n <Trans>Select destination folder within target bucket</Trans>\n </span>\n <Button\n size=\"small\"\n variant=\"subdued\"\n icon=\"addCircle\"\n onClick={modalState.startCreateFolder}\n disabled={isPending}\n title={t`Create new folder here`}\n >\n <Trans>New Folder</Trans>\n </Button>\n </div>\n\n {/* Breadcrumb / back navigation */}\n <div className=\"border-theme-background-lvl-2 bg-theme-background-lvl-1 flex items-center gap-2 border-b px-3 py-2 text-sm\">\n {modalState.currentPrefix ? (\n <button\n type=\"button\"\n onClick={modalState.navigateUp}\n className=\"text-theme-link hover:text-theme-default flex items-center gap-1\"\n >\n <MdArrowBack size={16} />\n <Trans>Back</Trans>\n </button>\n ) : (\n <span className=\"text-theme-light\">\n <Trans>Root</Trans>\n </span>\n )}\n {modalState.currentPrefix && (\n <span className=\"text-theme-light truncate text-xs\">/ {modalState.currentPrefix}</span>\n )}\n </div>\n\n {/* Object browser list */}\n <div ref={listRef} className=\"border-theme-background-lvl-2 max-h-56 overflow-y-auto rounded-b border\">\n {isLoading ? (\n <Stack direction=\"horizontal\" alignment=\"center\" gap=\"2\" className=\"py-6\">\n <Spinner size=\"small\" />\n <Trans>Loading...</Trans>\n </Stack>\n ) : allBrowserRows.length === 0 && !modalState.showNewFolderInput ? (\n <div className=\"text-theme-light px-4 py-6 text-center text-sm\">\n <Trans>This folder is empty, use New Folder to create one.</Trans>\n </div>\n ) : (\n <div style={{ height: `${rowVirtualizer.getTotalSize()}px`, position: \"relative\" }}>\n {rowVirtualizer.getVirtualItems().map((virtualRow) => {\n const row = allBrowserRows[virtualRow.index]\n const isFolder = row.kind === \"folder\"\n return (\n <div\n key={row.name}\n data-index={virtualRow.index}\n ref={rowVirtualizer.measureElement}\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n width: \"100%\",\n transform: `translateY(${virtualRow.start}px)`,\n }}\n >\n {isFolder ? (\n <button\n type=\"button\"\n className=\"hover:bg-theme-background-lvl-2 focus-visible:outline-theme-focus flex w-full items-center gap-2 px-4 py-2 text-left text-sm focus-visible:outline-2\"\n onClick={() => modalState.navigateToPrefix(row.name)}\n >\n <MdFolder size={16} className=\"text-theme-light shrink-0\" />\n <span className=\"truncate\">{row.displayName}</span>\n </button>\n ) : (\n <span className=\"text-theme-light flex items-center gap-2 px-4 py-2 text-sm\">\n <MdDescription size={16} className=\"shrink-0\" />\n <span className=\"truncate\">{row.displayName}</span>\n </span>\n )}\n </div>\n )\n })}\n </div>\n )}\n\n {/* Inline new folder input */}\n {modalState.showNewFolderInput && (\n <div className=\"border-theme-background-lvl-2 border-t px-4 py-3\">\n <Stack direction=\"vertical\" gap=\"2\">\n <Stack direction=\"horizontal\" gap=\"2\" alignment=\"center\">\n <MdCreateNewFolder size={16} className=\"text-theme-light shrink-0\" />\n <TextInput\n value={modalState.newFolderName}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) =>\n modalState.setNewFolderName(e.target.value)\n }\n onKeyDown={handleNewFolderKeyDown}\n placeholder={t`new-folder-name`}\n invalid={!!modalState.newFolderError}\n errortext={modalState.newFolderError ?? undefined}\n autoFocus\n className=\"flex-1\"\n />\n <Button\n size=\"small\"\n variant=\"primary\"\n onClick={modalState.createFolder}\n disabled={!modalState.newFolderName.trim()}\n >\n <Trans>Create</Trans>\n </Button>\n <Button size=\"small\" variant=\"subdued\" onClick={modalState.cancelCreateFolder}>\n <Trans>Cancel</Trans>\n </Button>\n </Stack>\n </Stack>\n </div>\n )}\n </div>\n </div>\n\n {/* Source + Target info box */}\n <div className=\"bg-theme-background-lvl-2 rounded p-3\">\n <Stack direction=\"vertical\" gap=\"2\">\n <div>\n <div className=\"text-theme-light mb-1 text-sm\">\n <Trans>Source</Trans>\n </div>\n <div className=\"text-sm break-all\">{`${bucketName}/${objectKey}`}</div>\n {objectSize !== undefined && (\n <div className=\"text-theme-light mt-1 text-xs\">{(objectSize / 1024).toFixed(2)} KB</div>\n )}\n </div>\n <div>\n <div className=\"text-theme-light mb-1 text-sm\">\n <Trans>Target path</Trans>\n </div>\n <div className=\"text-sm break-all\">{targetPathDisplay}</div>\n </div>\n </Stack>\n </div>\n\n {/* Warning if target exists */}\n {checkingTarget ? (\n <Stack direction=\"horizontal\" alignment=\"center\" gap=\"2\">\n <Spinner size=\"small\" />\n <span className=\"text-theme-light text-sm\">\n <Trans>Checking if object exists...</Trans>\n </span>\n </Stack>\n ) : targetExists ? (\n <p className=\"text-theme-default\">\n <Trans>An object with this name already exists at the destination and will be overwritten.</Trans>\n </p>\n ) : null}\n\n {/* Copy metadata checkbox */}\n <label className=\"flex cursor-pointer items-center gap-2\">\n <input\n type=\"checkbox\"\n checked={copyMetadata}\n onChange={(e) => setCopyMetadata(e.target.checked)}\n className=\"h-4 w-4\"\n />\n <span className=\"text-sm\">\n <Trans>Copy metadata</Trans>\n </span>\n </label>\n\n {copyMutation.isError &&\n (() => {\n const errorMessage = copyMutation.error.message\n return (\n <p className=\"text-theme-error\">\n <Trans>Failed to copy object: {errorMessage}</Trans>\n </p>\n )\n })()}\n </Stack>\n )}\n </Modal>\n )\n}\n","import { useState, useRef, useEffect } from \"react\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport { useModalTracking } from \"@/client/hooks/useModalTracking\"\nimport {\n Modal,\n Stack,\n Spinner,\n Status,\n ComboBox,\n ComboBoxOption,\n TextInput,\n Button,\n Divider,\n} from \"@cloudoperators/juno-ui-components\"\nimport { MdFolder, MdDescription, MdCreateNewFolder, MdArrowBack } from \"react-icons/md\"\nimport { useVirtualizer } from \"@tanstack/react-virtual\"\nimport { useCopyMoveModalState } from \"./hooks/useCopyMoveModalState\"\nimport { validateObjectName } from \"./utils/objectValidation\"\n\nconst MAX_COMBO_OPTIONS = 50\n\ninterface MoveObjectModalProps {\n isOpen: boolean\n bucketName: string\n objectKey: string\n objectSize?: number\n onClose: () => void\n onSuccess?: (objectKey: string, targetBucket: string, targetKey: string) => void\n onError?: (objectKey: string, errorMessage: string) => void\n}\n\ninterface FolderRow {\n kind: \"folder\"\n name: string\n displayName: string\n}\n\ninterface ObjectRow {\n kind: \"object\"\n name: string\n displayName: string\n}\n\ntype BrowserRow = FolderRow | ObjectRow\n\nexport const MoveObjectModal = ({\n isOpen,\n bucketName,\n objectKey,\n objectSize,\n onClose,\n onSuccess,\n onError,\n}: MoveObjectModalProps) => {\n const { t } = useLingui()\n const projectId = useProjectId()\n const utils = trpcReact.useUtils()\n const submittedKeyRef = useRef(\"\")\n const submittedTargetKeyRef = useRef(\"\")\n const submittedTargetBucketRef = useRef(\"\")\n\n const { trackClose, markSubmitted, resetTracking } = useModalTracking({\n isOpen,\n actionPrefix: \"storage.ceph.object.move\",\n })\n\n const [newObjectName, setNewObjectName] = useState(\"\")\n const [newObjectNameError, setNewObjectNameError] = useState<string | null>(null)\n const listRef = useRef<HTMLDivElement>(null)\n\n // ── Data fetching ─────────────────────────────────────────────────────────\n\n const { data: buckets, isLoading: isLoadingBuckets } = trpcReact.storage.ceph.containers.list.useQuery(\n { project_id: projectId ?? \"\", includeMetadata: false },\n { enabled: isOpen && !!projectId }\n )\n\n const modalState = useCopyMoveModalState({\n initialBucket: bucketName,\n allBuckets: buckets ?? [],\n existingRows: [],\n })\n\n const { data: objectsData, isLoading: isLoadingObjects } = trpcReact.storage.ceph.objects.list.useQuery(\n {\n project_id: projectId ?? \"\",\n containerName: modalState.targetBucket,\n prefix: modalState.currentPrefix || undefined,\n delimiter: \"/\",\n maxKeys: 1000,\n },\n { enabled: isOpen && !!modalState.targetBucket && !!projectId }\n )\n\n // Initialize object name when modal opens\n useEffect(() => {\n if (isOpen && objectKey) {\n const displayName = objectKey.split(\"/\").filter(Boolean).pop() ?? objectKey\n setNewObjectName(displayName)\n modalState.resetAll()\n }\n }, [isOpen, objectKey])\n\n useEffect(() => {\n if (!isOpen) {\n setNewObjectName(\"\")\n setNewObjectNameError(null)\n }\n }, [isOpen])\n\n // ── Build rows from S3 response ───────────────────────────────────────────\n\n const buildRows = (): BrowserRow[] => {\n if (!objectsData) return []\n\n const folders: FolderRow[] = objectsData.folders.map((folder) => ({\n kind: \"folder\" as const,\n name: folder.prefix,\n displayName: modalState.currentPrefix\n ? folder.prefix.replace(modalState.currentPrefix, \"\").replace(/\\/$/, \"\")\n : folder.prefix.replace(/\\/$/, \"\"),\n }))\n\n const objects: ObjectRow[] = objectsData.objects\n .filter((obj) => {\n const stripped = modalState.currentPrefix ? obj.key.replace(modalState.currentPrefix, \"\") : obj.key\n return stripped !== \"\" && stripped !== \"/\"\n })\n .map((obj) => ({\n kind: \"object\" as const,\n name: obj.key,\n displayName: modalState.currentPrefix ? obj.key.replace(modalState.currentPrefix, \"\") : obj.key,\n }))\n\n return [...folders, ...objects]\n }\n\n // ── Rows: merge server data with locally created folders ──────────────────\n\n const serverRows = buildRows()\n const bucketLocalFolders = modalState.localFolders[modalState.targetBucket] ?? []\n const localFolderRows: BrowserRow[] = bucketLocalFolders\n .filter((fp) => {\n const withoutPrefix = fp.startsWith(modalState.currentPrefix) ? fp.slice(modalState.currentPrefix.length) : null\n if (!withoutPrefix) return false\n const parts = withoutPrefix.split(\"/\").filter(Boolean)\n return parts.length === 1\n })\n .filter((fp) => !serverRows.some((r) => r.name === fp))\n .map((fp) => ({\n kind: \"folder\" as const,\n name: fp,\n displayName: fp.slice(modalState.currentPrefix.length).replace(/\\/$/, \"\"),\n }))\n\n const rows: BrowserRow[] = [\n ...serverRows.filter((r) => r.kind === \"folder\"),\n ...localFolderRows,\n ...serverRows.filter((r) => r.kind === \"object\"),\n ]\n\n // ── Move mutation = copy + delete ─────────────────────────────────────────\n\n const deleteMutation = trpcReact.storage.ceph.objects.delete.useMutation({\n onSuccess: () => {\n utils.storage.ceph.objects.list.invalidate()\n utils.storage.ceph.containers.list.invalidate()\n // Use captured target values instead of recomputing from mutable state\n onSuccess?.(submittedKeyRef.current, submittedTargetBucketRef.current, submittedTargetKeyRef.current)\n },\n onError: (error: { message: string }) => {\n onError?.(submittedKeyRef.current, error.message)\n },\n onSettled: () => {\n handleClose()\n },\n })\n\n const copyMutation = trpcReact.storage.ceph.objects.copy.useMutation({\n onSuccess: () => {\n deleteMutation.mutate({\n project_id: projectId ?? \"\",\n containerName: bucketName,\n objectKey,\n })\n },\n onError: (error: { message: string }) => {\n onError?.(submittedKeyRef.current, error.message)\n handleClose()\n },\n })\n\n // ── Handlers ──────────────────────────────────────────────────────────────\n\n const handleClose = () => {\n copyMutation.reset()\n deleteMutation.reset()\n resetTracking()\n onClose()\n }\n\n const handleBucketChange = (value?: string | number | string[] | undefined) => {\n const v = Array.isArray(value) ? value[0] : typeof value === \"number\" ? String(value) : value\n if (v) {\n modalState.setTargetBucket(v)\n }\n }\n\n // Synchronize targetBucket with searchTerm when it matches an exact bucket name\n useEffect(() => {\n const trimmedSearch = modalState.searchTerm.trim()\n if (trimmedSearch && buckets) {\n const matchingBucket = buckets.find((b) => b.name === trimmedSearch)\n if (matchingBucket && matchingBucket.name !== modalState.targetBucket) {\n modalState.setTargetBucket(matchingBucket.name)\n }\n }\n }, [modalState.searchTerm, buckets, modalState.targetBucket, modalState])\n\n const handleNewFolderKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === \"Enter\") modalState.createFolder()\n if (e.key === \"Escape\") modalState.cancelCreateFolder()\n }\n\n const handleMove = () => {\n if (!projectId) return\n\n const error = validateObjectName(newObjectName)\n if (error) {\n setNewObjectNameError(t(error.message))\n return\n }\n\n markSubmitted()\n const trimmedName = newObjectName.trim()\n const targetKey = `${modalState.currentPrefix}${trimmedName}`\n\n // Capture immutable values at submit time\n submittedKeyRef.current = objectKey\n submittedTargetKeyRef.current = targetKey\n submittedTargetBucketRef.current = modalState.targetBucket\n\n copyMutation.mutate({\n project_id: projectId,\n sourceBucket: bucketName,\n sourceKey: objectKey,\n destinationBucket: modalState.targetBucket,\n destinationKey: targetKey,\n copyMetadata: true,\n })\n }\n\n // ── Virtualized folder browser ─────────────────────────────────────────────\n\n const folderRows = rows.filter((r) => r.kind === \"folder\")\n const objectRows = rows.filter((r) => r.kind === \"object\")\n const allBrowserRows = [...folderRows, ...objectRows]\n\n const rowVirtualizer = useVirtualizer({\n count: allBrowserRows.length,\n getScrollElement: () => listRef.current,\n estimateSize: () => 32,\n overscan: 5,\n })\n\n if (!isOpen) return null\n\n const displayName = objectKey.split(\"/\").filter(Boolean).pop() ?? objectKey\n const isPending = copyMutation.isPending || deleteMutation.isPending\n const isLoading = isLoadingObjects\n\n const targetPathDisplay = `${modalState.targetBucket}/${modalState.currentPrefix}${newObjectName.trim() || displayName}`\n const initialPrefix = objectKey.endsWith(displayName) ? objectKey.slice(0, objectKey.length - displayName.length) : \"\"\n const isUnchanged =\n modalState.targetBucket === bucketName &&\n modalState.currentPrefix === initialPrefix &&\n newObjectName.trim() === displayName\n\n return (\n <Modal\n title={\n <span className=\"flex max-w-125 items-center gap-1\">\n <span className=\"shrink-0\">\n <Trans>Move/Rename object:</Trans>\n </span>\n <span className=\"truncate\" title={displayName}>\n {displayName}\n </span>\n </span>\n }\n open={isOpen}\n onCancel={() => {\n trackClose()\n handleClose()\n }}\n confirmButtonLabel={isPending ? t`Moving...` : t`Move/Rename Object`}\n onConfirm={handleMove}\n cancelButtonLabel={t`Cancel`}\n size=\"large\"\n disableConfirmButton={isPending || isLoadingBuckets || isUnchanged}\n disableCancelButton={isPending || isLoadingBuckets}\n disableCloseButton={isPending || isLoadingBuckets || isUnchanged}\n >\n {isPending ? (\n <Status status=\"progress\" title={t`Moving Object...`} className=\"mt-0\" />\n ) : (\n <Stack direction=\"vertical\" gap=\"4\">\n {/* New object name */}\n <TextInput\n label={t`New object name`}\n value={newObjectName}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) => {\n setNewObjectName(e.target.value)\n if (newObjectNameError) setNewObjectNameError(null)\n }}\n invalid={!!newObjectNameError}\n errortext={newObjectNameError ?? undefined}\n helptext={t`You can rename the object by changing the name here.`}\n required\n />\n\n <Divider className=\"my-2\" />\n\n {(copyMutation.isError || deleteMutation.isError) &&\n (() => {\n const copyErrorMessage = copyMutation.error?.message ?? \"\"\n const deleteErrorMessage = deleteMutation.error?.message ?? \"\"\n return (\n <p className=\"text-theme-error\">\n {copyMutation.isError ? (\n <Trans>Failed to move object: {copyErrorMessage}</Trans>\n ) : (\n <Trans>Object was copied but could not be deleted from the source: {deleteErrorMessage}</Trans>\n )}\n </p>\n )\n })()}\n\n {/* Target bucket */}\n <ComboBox\n label={t`Target bucket`}\n value={modalState.searchTerm || undefined}\n onChange={handleBucketChange}\n onInputChange={modalState.handleSearchChange}\n placeholder={bucketName}\n helptext={(() => {\n if (isLoadingBuckets) return t`Loading buckets...`\n const bucketsCount = buckets?.length ?? 0\n if (!modalState.searchTerm.trim() && bucketsCount > MAX_COMBO_OPTIONS) {\n return t`There are ${bucketsCount} buckets, start typing to search`\n }\n if (modalState.hiddenCount > 0) {\n const totalBuckets = modalState.visibleBuckets.length + modalState.hiddenCount\n return t`Showing first ${MAX_COMBO_OPTIONS} of ${totalBuckets}, refine your search to narrow results`\n }\n return undefined\n })()}\n disabled={isLoadingBuckets || isPending}\n required\n >\n {!modalState.searchTerm.trim() && (buckets?.length ?? 0) > MAX_COMBO_OPTIONS ? (\n <ComboBoxOption key=\"__placeholder__\" value=\"\" disabled>\n {t`Start typing to search for a bucket`}\n </ComboBoxOption>\n ) : (\n modalState.visibleBuckets.map((b) => (\n <ComboBoxOption key={b.name} value={b.name}>\n {b.name}\n </ComboBoxOption>\n ))\n )}\n </ComboBox>\n\n {/* Folder browser */}\n <div>\n <div className=\"mb-1 flex items-center justify-between\">\n <span className=\"text-sm font-medium\">\n <Trans>Select destination folder within target bucket</Trans>\n </span>\n <Button\n size=\"small\"\n variant=\"subdued\"\n icon=\"addCircle\"\n onClick={modalState.startCreateFolder}\n disabled={isPending}\n title={t`Create new folder here`}\n >\n <Trans>New Folder</Trans>\n </Button>\n </div>\n\n {/* Breadcrumb / back navigation */}\n <div className=\"border-theme-background-lvl-2 bg-theme-background-lvl-1 flex items-center gap-2 border-b px-3 py-2 text-sm\">\n {modalState.currentPrefix ? (\n <button\n type=\"button\"\n onClick={modalState.navigateUp}\n className=\"text-theme-link hover:text-theme-default flex items-center gap-1\"\n >\n <MdArrowBack size={16} />\n <Trans>Back</Trans>\n </button>\n ) : (\n <span className=\"text-theme-light\">\n <Trans>Root</Trans>\n </span>\n )}\n {modalState.currentPrefix && (\n <span className=\"text-theme-light truncate text-xs\">/ {modalState.currentPrefix}</span>\n )}\n </div>\n\n {/* Object browser list */}\n <div ref={listRef} className=\"border-theme-background-lvl-2 max-h-56 overflow-y-auto rounded-b border\">\n {isLoading ? (\n <Stack direction=\"horizontal\" alignment=\"center\" gap=\"2\" className=\"py-6\">\n <Spinner size=\"small\" />\n <Trans>Loading...</Trans>\n </Stack>\n ) : allBrowserRows.length === 0 && !modalState.showNewFolderInput ? (\n <div className=\"text-theme-light px-4 py-6 text-center text-sm\">\n <Trans>This folder is empty, use New Folder to create one.</Trans>\n </div>\n ) : (\n <div style={{ height: `${rowVirtualizer.getTotalSize()}px`, position: \"relative\" }}>\n {rowVirtualizer.getVirtualItems().map((virtualRow) => {\n const row = allBrowserRows[virtualRow.index]\n const isFolder = row.kind === \"folder\"\n return (\n <div\n key={row.name}\n data-index={virtualRow.index}\n ref={rowVirtualizer.measureElement}\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n width: \"100%\",\n transform: `translateY(${virtualRow.start}px)`,\n }}\n >\n {isFolder ? (\n <button\n type=\"button\"\n className=\"hover:bg-theme-background-lvl-2 focus-visible:outline-theme-focus flex w-full items-center gap-2 px-4 py-2 text-left text-sm focus-visible:outline-2\"\n onClick={() => modalState.navigateToPrefix(row.name)}\n >\n <MdFolder size={16} className=\"text-theme-light shrink-0\" />\n <span className=\"truncate\">{row.displayName}</span>\n </button>\n ) : (\n <span className=\"text-theme-light flex items-center gap-2 px-4 py-2 text-sm\">\n <MdDescription size={16} className=\"shrink-0\" />\n <span className=\"truncate\">{row.displayName}</span>\n </span>\n )}\n </div>\n )\n })}\n </div>\n )}\n\n {/* Inline new folder input */}\n {modalState.showNewFolderInput && (\n <div className=\"border-theme-background-lvl-2 border-t px-4 py-3\">\n <Stack direction=\"vertical\" gap=\"2\">\n <Stack direction=\"horizontal\" gap=\"2\" alignment=\"center\">\n <MdCreateNewFolder size={16} className=\"text-theme-light shrink-0\" />\n <TextInput\n value={modalState.newFolderName}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) =>\n modalState.setNewFolderName(e.target.value)\n }\n onKeyDown={handleNewFolderKeyDown}\n placeholder={t`new-folder-name`}\n invalid={!!modalState.newFolderError}\n errortext={modalState.newFolderError ?? undefined}\n autoFocus\n className=\"flex-1\"\n />\n <Button\n size=\"small\"\n variant=\"primary\"\n onClick={modalState.createFolder}\n disabled={!modalState.newFolderName.trim()}\n >\n <Trans>Create</Trans>\n </Button>\n <Button size=\"small\" variant=\"subdued\" onClick={modalState.cancelCreateFolder}>\n <Trans>Cancel</Trans>\n </Button>\n </Stack>\n </Stack>\n </div>\n )}\n </div>\n </div>\n\n {/* Source + Target info box */}\n <div className=\"bg-theme-background-lvl-2 rounded p-3\">\n <Stack direction=\"vertical\" gap=\"2\">\n <div>\n <div className=\"text-theme-light mb-1 text-sm\">\n <Trans>Source</Trans>\n </div>\n <div className=\"text-sm break-all\">{`${bucketName}/${objectKey}`}</div>\n {objectSize !== undefined && (\n <div className=\"text-theme-light mt-1 text-xs\">{(objectSize / 1024).toFixed(2)} KB</div>\n )}\n </div>\n <div>\n <div className=\"text-theme-light mb-1 text-sm\">\n <Trans>Target path</Trans>\n </div>\n <div className=\"text-sm break-all\">{targetPathDisplay}</div>\n </div>\n </Stack>\n </div>\n\n {isUnchanged && (\n <p className=\"text-theme-error text-sm\">\n <Trans>\n Cannot move to the same location. Please select a different bucket, folder, or change the name.\n </Trans>\n </p>\n )}\n </Stack>\n )}\n </Modal>\n )\n}\n","/**\n * Maximum number of keys returned per S3 ListObjects request.\n *\n * This is the AWS S3 maximum. We use this value as a performance trade-off:\n * - Fast response times for list operations\n * - Bucket metadata (count, size) are estimates for buckets > 1000 objects\n *\n * See: https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListObjectsV2.html\n */\nexport const S3_MAX_KEYS_PER_REQUEST = 1000\n\n/**\n * S3 SigV4 pre-signed URLs are valid for at most 7 days (604800 seconds); the\n * signer rejects anything larger. Caps `expiresIn` in the presigned-URL input\n * schema and rejects over-range custom durations in the UI before they reach\n * the BFF.\n */\nexport const S3_PRESIGN_MAX_EXPIRY_SECONDS = 604800\n","import { useEffect, useRef, useState, type ChangeEvent } from \"react\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { i18n } from \"@lingui/core\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport { S3_PRESIGN_MAX_EXPIRY_SECONDS } from \"@/server/Storage/constants\"\nimport { Modal, Stack, Spinner, TextInput, Icon, Select, SelectOption } from \"@cloudoperators/juno-ui-components\"\n\n// ── Expiry presets ────────────────────────────────────────────────────────────\n\ninterface ExpiryPreset {\n labelKey: string\n seconds: number\n}\n\nconst CUSTOM_VALUE = \"custom\"\n\n// S3 SigV4 pre-signed URLs are valid for at most 7 days. Reuse the BFF cap\n// (S3_PRESIGN_MAX_EXPIRY_SECONDS) so the UI and schema can't drift, and reject\n// the custom input inline instead of round-tripping to a 400.\nconst MAX_EXPIRY_SECONDS = S3_PRESIGN_MAX_EXPIRY_SECONDS\nconst MAX_EXPIRY_MINUTES = MAX_EXPIRY_SECONDS / 60\n\n// ── Props ─────────────────────────────────────────────────────────────────────\n\ninterface GeneratePresignedUrlModalProps {\n isOpen: boolean\n bucketName: string\n // Full object key, or null when no row is targeted (modal closed).\n objectKey: string | null\n onClose: () => void\n // Called with the full object key after a successful clipboard copy so the\n // caller can raise a confirmation toast.\n onCopySuccess?: (objectKey: string) => void\n}\n\n// ── Component ─────────────────────────────────────────────────────────────────\n\nexport const GeneratePresignedUrlModal = ({\n isOpen,\n bucketName,\n objectKey,\n onClose,\n onCopySuccess,\n}: GeneratePresignedUrlModalProps) => {\n const { t } = useLingui()\n const projectId = useProjectId()\n\n // Defined inside the component so t`` runs in the correct Lingui context,\n // ensuring labels are extracted and translated at render time.\n const EXPIRY_PRESETS: ExpiryPreset[] = [\n { labelKey: t`1 hour`, seconds: 3600 },\n { labelKey: t`24 hours`, seconds: 86400 },\n { labelKey: t`7 days`, seconds: 604800 },\n ]\n\n // Selected preset key (seconds as string) or \"custom\"\n const [selectedPreset, setSelectedPreset] = useState<string>(String(EXPIRY_PRESETS[1].seconds))\n // Custom duration in minutes (only active when selectedPreset === \"custom\")\n const [customMinutes, setCustomMinutes] = useState(\"\")\n const [customMinutesError, setCustomMinutesError] = useState<string | null>(null)\n const [copied, setCopied] = useState(false)\n\n // Generated URL state\n const [presignedUrl, setPresignedUrl] = useState<string | null>(null)\n const [expiresAt, setExpiresAt] = useState<number | null>(null)\n const [generalError, setGeneralError] = useState<string | null>(null)\n const [copyError, setCopyError] = useState<string | null>(null)\n\n const objectKeyRef = useRef(\"\")\n const copyTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null)\n // Incremented on every generate call and on modal close/reopen.\n // Callbacks check their captured requestId against the ref to discard\n // stale in-flight responses that arrive after the modal was closed or\n // a new request was started.\n const requestIdRef = useRef(0)\n\n const handleGenerateSuccess = (data: { url: string; expiresAt: number }) => {\n setPresignedUrl(data.url)\n setExpiresAt(data.expiresAt)\n setGeneralError(null)\n }\n\n const handleGenerateError = (error: { message: string }) => {\n setGeneralError(error.message)\n }\n\n const generateMutation = trpcReact.storage.ceph.objects.generatePresignedUrl.useMutation()\n\n useEffect(() => {\n if (!isOpen) {\n requestIdRef.current += 1\n if (copyTimeoutRef.current) {\n clearTimeout(copyTimeoutRef.current)\n copyTimeoutRef.current = null\n }\n generateMutation.reset()\n setPresignedUrl(null)\n setExpiresAt(null)\n setSelectedPreset(String(EXPIRY_PRESETS[1].seconds))\n setCustomMinutes(\"\")\n setCustomMinutesError(null)\n setCopied(false)\n setGeneralError(null)\n setCopyError(null)\n }\n return () => {\n if (copyTimeoutRef.current) clearTimeout(copyTimeoutRef.current)\n }\n }, [isOpen])\n\n // Derive a human-friendly display name from the full key (basename), matching\n // how the object toasts label objects.\n const displayName = objectKey ? (objectKey.split(\"/\").filter(Boolean).pop() ?? objectKey) : \"\"\n\n // Parses customMinutes as a strict positive integer.\n // Number() + Number.isInteger() rejects non-integer inputs such as \"1.5\" → 1.5\n // and \"10abc\" → NaN with parseInt, but null here.\n // Numeric formats accepted by Number() (for example, \"1e3\") are still allowed\n // if they evaluate to a positive integer.\n const parseCustomMinutes = (): number | null => {\n if (!customMinutes.trim()) return null\n const mins = Number(customMinutes)\n return Number.isInteger(mins) && mins > 0 ? mins : null\n }\n\n const resolveExpiresIn = (): number | null => {\n if (selectedPreset === CUSTOM_VALUE) {\n const mins = parseCustomMinutes()\n if (mins === null) return null\n return mins * 60\n }\n return parseInt(selectedPreset, 10)\n }\n\n const handleGenerate = () => {\n if (!objectKey) return\n if (selectedPreset === CUSTOM_VALUE) {\n const mins = parseCustomMinutes()\n if (mins === null) {\n setCustomMinutesError(t`Please enter a valid number of minutes greater than 0`)\n return\n }\n if (mins > MAX_EXPIRY_MINUTES) {\n setCustomMinutesError(t`A pre-signed URL can be valid for at most 7 days (${MAX_EXPIRY_MINUTES} minutes)`)\n return\n }\n setCustomMinutesError(null)\n }\n const expiresIn = resolveExpiresIn()\n if (expiresIn === null) return\n objectKeyRef.current = objectKey\n setPresignedUrl(null)\n setExpiresAt(null)\n setCopied(false)\n const requestId = ++requestIdRef.current\n generateMutation.mutate(\n {\n project_id: projectId,\n containerName: bucketName,\n objectKey,\n expiresIn,\n },\n {\n onSuccess: (data) => {\n if (requestId !== requestIdRef.current) return\n handleGenerateSuccess(data)\n },\n onError: (error) => {\n if (requestId !== requestIdRef.current) return\n handleGenerateError(error)\n },\n }\n )\n }\n\n const handleCopy = () => {\n if (!presignedUrl) return\n setCopyError(null)\n navigator.clipboard\n .writeText(presignedUrl)\n .then(() => {\n setCopied(true)\n onCopySuccess?.(objectKeyRef.current)\n if (copyTimeoutRef.current) clearTimeout(copyTimeoutRef.current)\n copyTimeoutRef.current = setTimeout(() => {\n copyTimeoutRef.current = null\n setCopied(false)\n }, 2000)\n })\n .catch(() => {\n setCopyError(t`Failed to copy the pre-signed URL to the clipboard`)\n })\n }\n\n const handlePresetChange = (value?: string | number | string[]) => {\n const defaultPreset = String(EXPIRY_PRESETS[1].seconds)\n const candidate =\n typeof value === \"string\"\n ? value\n : typeof value === \"number\"\n ? String(value)\n : Array.isArray(value) && typeof value[0] === \"string\"\n ? value[0]\n : \"\"\n const validPresets = new Set([...EXPIRY_PRESETS.map((p) => String(p.seconds)), CUSTOM_VALUE])\n const nextPreset = candidate && validPresets.has(candidate) ? candidate : defaultPreset\n setSelectedPreset(nextPreset)\n // Clear custom input state when switching away from custom\n if (nextPreset !== CUSTOM_VALUE) {\n setCustomMinutes(\"\")\n setCustomMinutesError(null)\n }\n // Reset generated URL when config changes\n setPresignedUrl(null)\n setExpiresAt(null)\n setCopied(false)\n setGeneralError(null)\n setCopyError(null)\n }\n\n const handleCustomMinutesChange = (e: ChangeEvent<HTMLInputElement>) => {\n setCustomMinutes(e.target.value)\n if (customMinutesError) setCustomMinutesError(null)\n // Reset generated URL when config changes\n setPresignedUrl(null)\n setExpiresAt(null)\n setCopied(false)\n setGeneralError(null)\n setCopyError(null)\n }\n\n if (!isOpen || !objectKey) return null\n\n const isPending = generateMutation.isPending\n const isCustom = selectedPreset === CUSTOM_VALUE\n\n // Absolute expiry timestamp formatted for the active Lingui locale (not the\n // browser's OS locale) so it matches the rest of the modal's localization.\n const expiresAtFormatted = expiresAt ? new Date(expiresAt * 1000).toLocaleString(i18n.locale) : null\n // Human-readable relative label for the selected preset — used as a plain\n // string inside the \"Expires in {label} — at {timestamp}\" interpolation.\n const selectedPresetLabel =\n selectedPreset === CUSTOM_VALUE\n ? customMinutes\n ? parseCustomMinutes() === 1\n ? t`1 minute`\n : t`${customMinutes} minutes`\n : null\n : (EXPIRY_PRESETS.find((p) => String(p.seconds) === selectedPreset)?.labelKey ?? null)\n\n return (\n <Modal\n title={\n <span className=\"flex max-w-100 items-center gap-1\">\n <span className=\"shrink-0\">\n <Trans>Share URL:</Trans>\n </span>\n <span className=\"truncate\" title={displayName}>\n {displayName}\n </span>\n </span>\n }\n open={isOpen}\n onCancel={onClose}\n confirmButtonLabel={isPending ? t`Generating...` : t`Generate URL`}\n onConfirm={handleGenerate}\n cancelButtonLabel={t`Cancel`}\n size=\"small\"\n disableConfirmButton={isPending || (isCustom && (!customMinutes.trim() || !!customMinutesError))}\n >\n <Stack direction=\"vertical\" gap=\"4\">\n <p className=\"text-theme-default\">\n <Trans>\n A pre-signed URL grants time-limited read access to this object without requiring authentication. Anyone\n with the link can download it until it expires.\n </Trans>\n </p>\n\n {/* General error */}\n {generalError && (\n <p className=\"text-theme-error\" role=\"alert\" aria-live=\"assertive\">\n <Trans>Failed to generate pre-signed URL: {generalError}</Trans>\n </p>\n )}\n\n {/* Clipboard copy error */}\n {copyError && (\n <p className=\"text-theme-error\" role=\"alert\" aria-live=\"assertive\">\n {copyError}\n </p>\n )}\n\n {/* Expiry selector */}\n <Select label={t`Expires in`} value={selectedPreset} onChange={handlePresetChange} disabled={isPending}>\n {EXPIRY_PRESETS.map((preset) => (\n <SelectOption key={preset.seconds} value={String(preset.seconds)} label={preset.labelKey} />\n ))}\n <SelectOption value={CUSTOM_VALUE} label={t`Custom`} />\n </Select>\n\n {/* Custom duration input */}\n {isCustom && (\n <TextInput\n label={t`Custom duration (minutes)`}\n value={customMinutes}\n onChange={handleCustomMinutesChange}\n invalid={!!customMinutesError}\n errortext={customMinutesError || undefined}\n disabled={isPending}\n placeholder=\"60\"\n type=\"number\"\n />\n )}\n\n {/* Loading state */}\n {isPending && (\n <Stack direction=\"horizontal\" alignment=\"center\" gap=\"2\" className=\"py-2\">\n <Spinner size=\"small\" />\n <Trans>Generating pre-signed URL...</Trans>\n </Stack>\n )}\n\n {/* Generated URL */}\n {presignedUrl && (\n <Stack direction=\"vertical\" gap=\"2\">\n <div className=\"relative\">\n <TextInput label={t`Pre-signed URL`} value={presignedUrl} readOnly className=\"pr-10 text-xs\" />\n <button\n type=\"button\"\n onClick={handleCopy}\n title={copied ? t`Copied!` : t`Copy URL`}\n aria-label={copied ? t`Copied!` : t`Copy URL`}\n className=\"text-theme-light hover:text-theme-default absolute top-1/2 right-2 inline-flex items-center transition-colors\"\n style={{ transform: \"translateY(-50%)\" }}\n >\n <Icon icon={copied ? \"checkCircle\" : \"contentCopy\"} size=\"18\" />\n </button>\n </div>\n {expiresAtFormatted && selectedPresetLabel && (\n <p className=\"text-theme-light text-xs\">\n <Trans>\n Expires in {selectedPresetLabel} — at {expiresAtFormatted}\n </Trans>\n </p>\n )}\n </Stack>\n )}\n </Stack>\n </Modal>\n )\n}\n","import { useState, useEffect, useRef } from \"react\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport { useModalTracking } from \"@/client/hooks/useModalTracking\"\nimport {\n Modal,\n TextInput,\n Stack,\n Status,\n DataGrid,\n DataGridRow,\n DataGridHeadCell,\n DataGridCell,\n Button,\n} from \"@cloudoperators/juno-ui-components\"\nimport { formatBytesBinary } from \"@/client/utils/formatBytes\"\nimport { validateMetadataKey } from \"./utils/objectValidation\"\n\n// ── Types ──────────────────────────────────────────────────────────────────────\n\ninterface MetadataEntry {\n uid: number\n key: string\n value: string\n isEditing?: boolean\n originalKey?: string\n originalValue?: string\n}\n\ninterface EditMetadataModalProps {\n isOpen: boolean\n bucketName: string\n objectKey: string\n onClose: () => void\n onSuccess?: (objectKey: string) => void\n onError?: (objectKey: string, errorMessage: string) => void\n}\n\n// ── Helpers ────────────────────────────────────────────────────────────────────\n\nconst formatDate = (iso: string): string => {\n const date = new Date(iso)\n if (isNaN(date.getTime())) return \"—\"\n return date.toLocaleString(undefined, {\n year: \"numeric\",\n month: \"short\",\n day: \"2-digit\",\n hour: \"2-digit\",\n minute: \"2-digit\",\n })\n}\n\n// Calculate metadata size in bytes (header format: \"x-amz-meta-key: value\\r\\n\")\nconst calculateMetadataSize = (entries: MetadataEntry[]): number => {\n let totalBytes = 0\n for (const entry of entries) {\n // Format: \"x-amz-meta-{key}: {value}\\r\\n\"\n totalBytes += \"x-amz-meta-\".length + entry.key.length + 2 + entry.value.length + 2\n }\n return totalBytes\n}\n\nconst MAX_METADATA_BYTES = 2048 // 2KB limit for S3 user metadata\n\n// ── Component ──────────────────────────────────────────────────────────────────\n\nexport const EditMetadataModal = ({\n isOpen,\n bucketName,\n objectKey,\n onClose,\n onSuccess,\n onError,\n}: EditMetadataModalProps) => {\n const { t } = useLingui()\n const projectId = useProjectId()\n const utils = trpcReact.useUtils()\n\n const { trackClose, markSubmitted, resetTracking } = useModalTracking({\n isOpen,\n actionPrefix: \"storage.ceph.object.metadata.edit\",\n })\n\n // ── Metadata fetch ─────────────────────────────────────────────────────────\n const {\n data: objectDetails,\n isLoading,\n isError: isMetaError,\n error: metaError,\n } = trpcReact.storage.ceph.objects.getDetails.useQuery(\n { project_id: projectId ?? \"\", containerName: bucketName, objectKey },\n { enabled: isOpen && !!projectId, refetchOnWindowFocus: false }\n )\n\n const uidRef = useRef(0)\n const nextUid = () => ++uidRef.current\n\n // ── Form state ─────────────────────────────────────────────────────────────\n const [metadata, setMetadata] = useState<MetadataEntry[]>([])\n const [metaErrors, setMetaErrors] = useState<Record<string, string>>({})\n const [isAddingNew, setIsAddingNew] = useState(false)\n const [newKey, setNewKey] = useState(\"\")\n const [newValue, setNewValue] = useState(\"\")\n const [newKeyError, setNewKeyError] = useState<string | null>(null)\n\n // Track original state for change detection and cancel-edit rollback\n const originalMetadataRef = useRef<MetadataEntry[]>([])\n\n // Survives reset() inside handleClose() before onSuccess/onError fire\n const objectKeyRef = useRef(\"\")\n\n // ── Populate form when data arrives ───────────────────────────────────────\n useEffect(() => {\n if (!objectDetails?.metadata) return\n\n const entries: MetadataEntry[] = Object.entries(objectDetails.metadata).map(([key, value]) => ({\n uid: nextUid(),\n key,\n value,\n isEditing: false,\n originalKey: key,\n originalValue: value,\n }))\n setMetadata(entries)\n originalMetadataRef.current = entries.map((e) => ({ ...e }))\n }, [objectDetails])\n\n // Reset when closed\n useEffect(() => {\n if (!isOpen) resetForm()\n }, [isOpen])\n\n const resetForm = () => {\n setMetadata([])\n setMetaErrors({})\n setIsAddingNew(false)\n setNewKey(\"\")\n setNewValue(\"\")\n setNewKeyError(null)\n updateMutation.reset()\n }\n\n // ── Change detection ───────────────────────────────────────────────────────\n const hasChanges = (() => {\n if (metadata.length !== originalMetadataRef.current.length) return true\n const originalMetadataByKey = new Map(originalMetadataRef.current.map((entry) => [entry.key, entry.value]))\n return metadata.some((entry) => originalMetadataByKey.get(entry.key) !== entry.value)\n })()\n\n const hasEditing = metadata.some((e) => e.isEditing)\n\n // Calculate current metadata size\n const currentMetadataSize = calculateMetadataSize(metadata)\n const isSizeExceeded = currentMetadataSize > MAX_METADATA_BYTES\n\n // ── Mutation ───────────────────────────────────────────────────────────────\n const updateMutation = trpcReact.storage.ceph.objects.updateMetadata.useMutation({\n onSuccess: () => {\n utils.storage.ceph.objects.getDetails.invalidate({\n project_id: projectId ?? \"\",\n containerName: bucketName,\n objectKey: objectKeyRef.current,\n })\n utils.storage.ceph.objects.list.invalidate()\n onSuccess?.(objectKeyRef.current)\n handleClose()\n },\n onError: (error) => {\n onError?.(objectKeyRef.current, error.message)\n },\n })\n\n // ── Handlers ───────────────────────────────────────────────────────────────\n const handleClose = () => {\n resetForm()\n resetTracking()\n onClose()\n }\n\n const handleSubmit = () => {\n if (!projectId) return\n\n if (isSizeExceeded) {\n return\n }\n\n markSubmitted()\n objectKeyRef.current = objectKey\n\n // Build metadata record from current entries\n const metadataRecord: Record<string, string> = {}\n for (const entry of metadata) {\n metadataRecord[entry.key] = entry.value\n }\n\n updateMutation.mutate({\n project_id: projectId,\n containerName: bucketName,\n objectKey,\n metadata: metadataRecord,\n })\n }\n\n // ── Metadata row handlers ──────────────────────────────────────────────────\n const handleEdit = (index: number) => {\n setMetadata((prev) => prev.map((e, i) => (i === index ? { ...e, isEditing: true } : e)))\n }\n\n const handleKeyChange = (index: number, value: string) => {\n setMetadata((prev) => prev.map((e, i) => (i === index ? { ...e, key: value } : e)))\n if (metaErrors[`edit-${index}`]) {\n setMetaErrors((prev) => {\n const next = { ...prev }\n delete next[`edit-${index}`]\n return next\n })\n }\n }\n\n const handleValueChange = (index: number, value: string) => {\n setMetadata((prev) => prev.map((e, i) => (i === index ? { ...e, value } : e)))\n }\n\n const handleSaveEdit = (index: number) => {\n const entry = metadata[index]\n const error = validateMetadataKey(entry.key)\n if (error) {\n setMetaErrors((prev) => ({ ...prev, [`edit-${index}`]: t(error.message) }))\n return\n }\n const isDuplicate = metadata.some((e, i) => i !== index && e.key.toLowerCase() === entry.key.toLowerCase())\n if (isDuplicate) {\n setMetaErrors((prev) => ({ ...prev, [`edit-${index}`]: t`Key already exists` }))\n return\n }\n setMetadata((prev) => prev.map((e, i) => (i === index ? { ...e, isEditing: false } : e)))\n setMetaErrors((prev) => {\n const next = { ...prev }\n delete next[`edit-${index}`]\n return next\n })\n }\n\n const handleCancelEdit = (index: number) => {\n const currentEntry = metadata[index]\n // Find original by uid, not by index (which shifts when rows are added/removed)\n const orig = originalMetadataRef.current.find((e) => e.uid === currentEntry.uid)\n if (orig) {\n setMetadata((prev) => prev.map((e, i) => (i === index ? { ...orig, isEditing: false } : e)))\n } else {\n // Newly added row that was put into edit mode — drop it\n setMetadata((prev) => prev.filter((_, i) => i !== index))\n }\n setMetaErrors((prev) => {\n const next = { ...prev }\n delete next[`edit-${index}`]\n return next\n })\n }\n\n const handleDeleteMeta = (index: number) => {\n setMetadata((prev) => prev.filter((_, i) => i !== index))\n }\n\n const handleAddNew = () => {\n const error = validateMetadataKey(newKey)\n if (error) {\n setNewKeyError(t(error.message))\n return\n }\n const isDuplicate = metadata.some((e) => e.key.toLowerCase() === newKey.trim().toLowerCase())\n if (isDuplicate) {\n setNewKeyError(t`Key already exists`)\n return\n }\n setMetadata((prev) => [...prev, { uid: nextUid(), key: newKey.trim(), value: newValue, isEditing: false }])\n setNewKey(\"\")\n setNewValue(\"\")\n setNewKeyError(null)\n setIsAddingNew(false)\n }\n\n const handleCancelAdd = () => {\n setNewKey(\"\")\n setNewValue(\"\")\n setNewKeyError(null)\n setIsAddingNew(false)\n }\n\n if (!isOpen) return null\n\n const displayName = objectKey.split(\"/\").filter(Boolean).pop() ?? objectKey\n const isPending = updateMutation.isPending\n const isBusy = isPending || isLoading\n const metadataErrorMessage = metaError?.message ?? \"\"\n const mutationErrorMessage = updateMutation.error?.message ?? \"\"\n\n return (\n <Modal\n title={\n <span className=\"flex max-w-100 items-center gap-1\">\n <Trans>\n <span className=\"shrink-0\">Edit metadata:</span>{\" \"}\n <span className=\"truncate\" title={displayName}>\n {displayName}\n </span>\n </Trans>\n </span>\n }\n open={isOpen}\n onCancel={() => {\n trackClose()\n handleClose()\n }}\n confirmButtonLabel={isPending ? t`Saving...` : t`Update object`}\n onConfirm={handleSubmit}\n cancelButtonLabel={t`Cancel`}\n size=\"large\"\n disableConfirmButton={isBusy || !hasChanges || hasEditing || isAddingNew || isSizeExceeded}\n >\n {isLoading ? (\n <Status status=\"progress\" title={t`Loading Object Properties...`} className=\"mt-0\" />\n ) : isMetaError ? (\n <Status status=\"error\" title={t`Failed to Load Object Metadata`} body={metadataErrorMessage} className=\"mt-0\" />\n ) : (\n <Stack direction=\"vertical\" gap=\"6\">\n {/* Mutation error */}\n {updateMutation.isError && (\n <p className=\"text-theme-error\" role=\"alert\">\n <Trans>Failed to update object: {mutationErrorMessage}</Trans>\n </p>\n )}\n\n {/* ── Read-only properties ──────────────────────────────────────── */}\n <div>\n <p className=\"text-theme-default mb-3 text-sm font-semibold\">\n <Trans>Object properties</Trans>\n </p>\n <div className=\"grid grid-cols-[max-content_1fr] gap-x-6 gap-y-2 text-sm\">\n <span className=\"text-theme-light text-right\">\n <Trans>Content type</Trans>\n </span>\n <span>{objectDetails?.contentType ?? \"—\"}</span>\n\n <span className=\"text-theme-light text-right\">\n <Trans>ETag</Trans>\n </span>\n <span className=\"break-all\">{objectDetails?.etag ?? \"—\"}</span>\n\n <span className=\"text-theme-light text-right\">\n <Trans>Size</Trans>\n </span>\n <span>{objectDetails?.size != null ? formatBytesBinary(objectDetails.size) : \"—\"}</span>\n\n <span className=\"text-theme-light text-right\">\n <Trans>Last modified</Trans>\n </span>\n <span>{objectDetails?.lastModified ? formatDate(objectDetails.lastModified) : \"—\"}</span>\n </div>\n </div>\n\n {/* ── Custom metadata ───────────────────────────────────────────── */}\n <div>\n <Stack direction=\"horizontal\" alignment=\"center\" distribution=\"between\" className=\"mb-3\">\n <p className=\"text-theme-default text-sm font-semibold\">\n <Trans>Metadata</Trans>\n </p>\n <div className=\"flex items-center gap-4\">\n <p className=\"text-theme-light text-xs\">\n <Trans>Stored as x-amz-meta-* headers. Keys are case-insensitive.</Trans>\n </p>\n <p className={`text-xs ${isSizeExceeded ? \"text-theme-danger font-semibold\" : \"text-theme-light\"}`}>\n {currentMetadataSize} / {MAX_METADATA_BYTES} bytes\n </p>\n </div>\n </Stack>\n\n {isSizeExceeded && (\n <p className=\"text-theme-default mb-3\" role=\"alert\">\n <Trans>Metadata size exceeds the 2KB limit. Please remove or shorten some entries before saving.</Trans>\n </p>\n )}\n\n <Stack direction=\"horizontal\" className=\"jn:bg-theme-background-lvl-1 justify-end p-2\">\n <Button\n label={t`Add Property`}\n onClick={() => setIsAddingNew(true)}\n variant=\"primary\"\n icon=\"addCircle\"\n size=\"small\"\n disabled={isAddingNew || hasEditing || isBusy}\n />\n </Stack>\n\n <DataGrid columns={3} gridColumnTemplate=\"minmax(150px, 1fr) minmax(200px, 2fr) minmax(120px, min-content)\">\n <DataGridRow>\n <DataGridHeadCell>\n <Trans>Key</Trans>\n </DataGridHeadCell>\n <DataGridHeadCell>\n <Trans>Value</Trans>\n </DataGridHeadCell>\n <DataGridHeadCell className=\"text-right\">\n <Trans>Actions</Trans>\n </DataGridHeadCell>\n </DataGridRow>\n\n {/* New row */}\n {isAddingNew && (\n <DataGridRow>\n <DataGridCell>\n <TextInput\n value={newKey}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) => {\n setNewKey(e.target.value)\n if (newKeyError) setNewKeyError(null)\n }}\n placeholder={t`property-key`}\n errortext={newKeyError ?? undefined}\n invalid={!!newKeyError}\n autoFocus\n />\n </DataGridCell>\n <DataGridCell>\n <TextInput\n value={newValue}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) => setNewValue(e.target.value)}\n placeholder={t`Value`}\n />\n </DataGridCell>\n <DataGridCell>\n <Stack direction=\"horizontal\" gap=\"2\" distribution=\"end\" className=\"whitespace-nowrap\">\n <Button size=\"small\" variant=\"primary\" onClick={handleAddNew} icon=\"check\" title={t`Save`} />\n <Button\n size=\"small\"\n variant=\"subdued\"\n onClick={handleCancelAdd}\n icon=\"close\"\n title={t`Discard`}\n />\n </Stack>\n </DataGridCell>\n </DataGridRow>\n )}\n\n {/* Existing rows */}\n {metadata.map((entry, index) => (\n <DataGridRow key={entry.uid}>\n <DataGridCell>\n {entry.isEditing ? (\n <TextInput\n value={entry.key}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) => handleKeyChange(index, e.target.value)}\n errortext={metaErrors[`edit-${index}`]}\n invalid={!!metaErrors[`edit-${index}`]}\n />\n ) : (\n <span className=\"block max-w-xs truncate text-sm\" title={entry.key}>\n {entry.key}\n </span>\n )}\n </DataGridCell>\n <DataGridCell>\n {entry.isEditing ? (\n <TextInput\n value={entry.value}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) => handleValueChange(index, e.target.value)}\n />\n ) : (\n <span className=\"block max-w-md truncate text-sm\" title={entry.value}>\n {entry.value}\n </span>\n )}\n </DataGridCell>\n <DataGridCell>\n {entry.isEditing ? (\n <Stack direction=\"horizontal\" gap=\"2\" distribution=\"end\" className=\"whitespace-nowrap\">\n <Button\n size=\"small\"\n variant=\"primary\"\n onClick={() => handleSaveEdit(index)}\n icon=\"check\"\n title={t`Save`}\n />\n <Button\n size=\"small\"\n variant=\"subdued\"\n onClick={() => handleCancelEdit(index)}\n icon=\"close\"\n title={t`Discard`}\n />\n </Stack>\n ) : (\n <Stack direction=\"horizontal\" gap=\"2\" distribution=\"end\" className=\"whitespace-nowrap\">\n <Button\n size=\"small\"\n variant=\"subdued\"\n onClick={() => handleEdit(index)}\n icon=\"edit\"\n title={t`Edit`}\n disabled={isAddingNew || hasEditing || isBusy}\n />\n <Button\n size=\"small\"\n variant=\"primary-danger\"\n onClick={() => handleDeleteMeta(index)}\n icon=\"deleteForever\"\n title={t`Delete`}\n disabled={isAddingNew || hasEditing || isBusy}\n />\n </Stack>\n )}\n </DataGridCell>\n </DataGridRow>\n ))}\n\n {/* Empty state */}\n {metadata.length === 0 && !isAddingNew && (\n <DataGridRow>\n <DataGridCell colSpan={3} className=\"py-6 text-center\">\n <Stack alignment=\"center\">\n <span className=\"text-theme-light text-sm\">\n <Trans>No custom metadata. Click \"Add Property\" to create one.</Trans>\n </span>\n </Stack>\n </DataGridCell>\n </DataGridRow>\n )}\n </DataGrid>\n </div>\n </Stack>\n )}\n </Modal>\n )\n}\n","import { useEffect, useState } from \"react\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { useModalTracking } from \"@/client/hooks/useModalTracking\"\nimport type { ObjectVersion } from \"@/server/Storage/types/versioning\"\nimport {\n Modal,\n Stack,\n Status,\n Message,\n DataGrid,\n DataGridRow,\n DataGridCell,\n DataGridHeadCell,\n Badge,\n PopupMenu,\n PopupMenuItem,\n PopupMenuOptions,\n} from \"@cloudoperators/juno-ui-components\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport { formatBytesBinary } from \"@/client/utils/formatBytes\"\nimport { RestoreVersionModal } from \"./RestoreVersionModal\"\nimport { DeleteVersionModal } from \"./DeleteVersionModal\"\n\ninterface ObjectVersionHistoryModalProps {\n isOpen: boolean\n bucketName: string\n objectKey: string\n onClose: () => void\n onRestoreVersion?: (objectKey: string, versionId: string) => void\n onDeleteVersion?: (objectKey: string, versionId: string) => void\n canRestoreVersion: boolean\n canDeleteVersion: boolean\n}\n\nexport const ObjectVersionHistoryModal = ({\n isOpen,\n bucketName,\n objectKey,\n onClose,\n onRestoreVersion,\n onDeleteVersion,\n canRestoreVersion,\n canDeleteVersion,\n}: ObjectVersionHistoryModalProps) => {\n const { t } = useLingui()\n const projectId = useProjectId()\n\n const { trackClose, resetTracking } = useModalTracking({\n isOpen,\n actionPrefix: \"storage.ceph.object.version.history\",\n })\n\n const [restoreTarget, setRestoreTarget] = useState<{\n versionId: string\n date?: string\n size?: number\n } | null>(null)\n const [deleteTarget, setDeleteTarget] = useState<{\n versionId: string\n date?: string\n size?: number\n isDeleteMarker: boolean\n } | null>(null)\n const [feedbackMessage, setFeedbackMessage] = useState<{\n variant: \"success\" | \"error\"\n message: string\n } | null>(null)\n\n const { data, isLoading, error, refetch } = trpcReact.storage.ceph.versioning.listObjectVersions.useQuery(\n {\n project_id: projectId ?? \"\",\n bucket: bucketName,\n key: objectKey,\n },\n {\n enabled: isOpen && !!projectId && !!bucketName && !!objectKey,\n staleTime: 0, // Always fetch fresh data when modal opens\n }\n )\n\n // Refetch when modal opens\n useEffect(() => {\n if (isOpen && projectId && bucketName && objectKey) {\n refetch()\n }\n }, [isOpen, projectId, bucketName, objectKey, refetch])\n\n // data is already ObjectVersion[] array\n const versions = data || []\n\n const handleClose = () => {\n setRestoreTarget(null)\n setDeleteTarget(null)\n setFeedbackMessage(null)\n resetTracking()\n onClose()\n }\n\n if (!isOpen) return null\n\n return (\n <Modal\n title={\n <span className=\"flex max-w-100 items-center gap-1 md:max-w-125 lg:max-w-250 xl:max-w-275\">\n <span className=\"shrink-0\">\n <Trans>Version History:</Trans>\n </span>\n <span className=\"truncate\" title={objectKey}>\n {objectKey}\n </span>\n </span>\n }\n open={isOpen}\n onCancel={() => {\n trackClose()\n handleClose()\n }}\n size=\"xl\"\n >\n <Stack direction=\"vertical\" gap=\"4\">\n {feedbackMessage && (\n <Message variant={feedbackMessage.variant} dismissible onDismiss={() => setFeedbackMessage(null)}>\n {feedbackMessage.message}\n </Message>\n )}\n\n {isLoading && <Status status=\"progress\" title={t`Loading Versions...`} className=\"mt-0\" />}\n\n {error && <Status status=\"error\" title={t`Failed to Load Versions`} body={error.message} className=\"mt-0\" />}\n\n {!isLoading && !error && versions.length === 0 && (\n <Status status=\"empty\" title={t`No Versions Found for This Object.`} className=\"mt-0\" />\n )}\n\n {!isLoading && !error && versions.length > 0 && (\n <>\n <DataGrid columns={6} minContentColumns={[5]}>\n <DataGridRow>\n <DataGridHeadCell>\n <Trans>Status</Trans>\n </DataGridHeadCell>\n <DataGridHeadCell>\n <Trans>Version ID</Trans>\n </DataGridHeadCell>\n <DataGridHeadCell>\n <Trans>Last Modified</Trans>\n </DataGridHeadCell>\n <DataGridHeadCell>\n <Trans>Size</Trans>\n </DataGridHeadCell>\n <DataGridHeadCell>\n <Trans>ETag</Trans>\n </DataGridHeadCell>\n <DataGridHeadCell>\n <Trans>Actions</Trans>\n </DataGridHeadCell>\n </DataGridRow>\n\n {versions.map((version: ObjectVersion) => {\n const isLatest = version.isLatest\n const isDeleteMarker = version.isDeleteMarker ?? false\n\n return (\n <DataGridRow key={version.versionId}>\n <DataGridCell>\n {isDeleteMarker ? (\n <Badge variant=\"error\">\n <Trans>Delete Marker</Trans>\n </Badge>\n ) : isLatest ? (\n <Badge variant=\"success\">\n <Trans>Latest</Trans>\n </Badge>\n ) : (\n <Badge variant=\"info\">\n <Trans>Older</Trans>\n </Badge>\n )}\n </DataGridCell>\n\n <DataGridCell>\n <code className=\"text-xs break-all\" title={version.versionId}>\n {version.versionId}\n </code>\n </DataGridCell>\n\n <DataGridCell>\n <span className=\"text-theme-light text-sm\">\n {version.lastModified ? new Date(version.lastModified).toLocaleString() : \"—\"}\n </span>\n </DataGridCell>\n\n <DataGridCell>\n <span className=\"text-theme-light text-sm\">\n {isDeleteMarker ? \"—\" : formatBytesBinary(version.size ?? 0)}\n </span>\n </DataGridCell>\n\n <DataGridCell>\n <span className=\"text-theme-light text-xs break-all\">\n {isDeleteMarker ? \"—\" : version.etag || \"—\"}\n </span>\n </DataGridCell>\n\n <DataGridCell>\n <div className=\"flex justify-end\">\n {/* Both items are gated mutations with no always-visible read action in\n this menu, so skip it entirely when neither applies. */}\n {((!isDeleteMarker && !isLatest && canRestoreVersion) || canDeleteVersion) && (\n <PopupMenu>\n <PopupMenuOptions>\n {!isDeleteMarker && !isLatest && canRestoreVersion && (\n <PopupMenuItem\n label={t`Restore`}\n onClick={() => {\n setRestoreTarget({\n versionId: version.versionId,\n date: version.lastModified,\n size: version.size,\n })\n }}\n />\n )}\n {canDeleteVersion && (\n <PopupMenuItem\n label={isDeleteMarker ? t`Delete Marker` : t`Delete Version`}\n onClick={() => {\n setDeleteTarget({\n versionId: version.versionId,\n date: version.lastModified,\n size: version.size,\n isDeleteMarker,\n })\n }}\n />\n )}\n </PopupMenuOptions>\n </PopupMenu>\n )}\n </div>\n </DataGridCell>\n </DataGridRow>\n )\n })}\n </DataGrid>\n </>\n )}\n </Stack>\n\n <RestoreVersionModal\n isOpen={restoreTarget !== null}\n bucketName={bucketName}\n objectKey={objectKey}\n versionId={restoreTarget?.versionId ?? \"\"}\n versionDate={restoreTarget?.date}\n versionSize={restoreTarget?.size}\n onClose={() => setRestoreTarget(null)}\n onSuccess={(objectKey, versionId) => {\n setRestoreTarget(null)\n const displayName = objectKey.split(\"/\").filter(Boolean).pop() ?? objectKey\n setFeedbackMessage({\n variant: \"success\",\n message: t`${displayName} was successfully restored`,\n })\n onRestoreVersion?.(objectKey, versionId)\n setTimeout(() => refetch(), 100)\n }}\n onError={(_objectKey, errorMessage) => {\n setRestoreTarget(null)\n setFeedbackMessage({\n variant: \"error\",\n message: t`Failed to restore version: ${errorMessage}`,\n })\n }}\n />\n\n <DeleteVersionModal\n isOpen={deleteTarget !== null}\n bucketName={bucketName}\n objectKey={objectKey}\n versionId={deleteTarget?.versionId ?? \"\"}\n versionDate={deleteTarget?.date}\n versionSize={deleteTarget?.size}\n isDeleteMarker={deleteTarget?.isDeleteMarker ?? false}\n onClose={() => setDeleteTarget(null)}\n onSuccess={(objectKey, versionId) => {\n setDeleteTarget(null)\n const shortVersionId = versionId.slice(0, 8)\n setFeedbackMessage({\n variant: \"success\",\n message: t`Version ${shortVersionId}... deleted successfully`,\n })\n onDeleteVersion?.(objectKey, versionId)\n setTimeout(() => refetch(), 100)\n }}\n onError={(_objectKey, errorMessage) => {\n setDeleteTarget(null)\n setFeedbackMessage({\n variant: \"error\",\n message: t`Failed to delete version: ${errorMessage}`,\n })\n }}\n />\n </Modal>\n )\n}\n","import { useEffect, useState, useSyncExternalStore, useMemo } from \"react\"\nimport {\n DataGrid,\n DataGridRow,\n DataGridCell,\n DataGridHeadCell,\n PopupMenu,\n PopupMenuItem,\n PopupMenuOptions,\n Badge,\n Spinner,\n Icon,\n toast,\n Checkbox,\n Tooltip,\n TooltipTrigger,\n TooltipContent,\n Status,\n} from \"@cloudoperators/juno-ui-components\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { MdFolder, MdDescription } from \"react-icons/md\"\nimport { formatBytesBinary } from \"@/client/utils/formatBytes\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport { useVirtualizedTableBody } from \"@/client/hooks/useVirtualizedTableBody\"\nimport type { S3Object, S3FolderPrefix, S3ObjectVersion } from \"@/server/Storage/types/ceph\"\nimport { getObjectDownloadCancelledToast, getPresignedUrlCopiedToast } from \"./ObjectToastNotifications\"\nimport {\n startObjectDownload,\n cancelObjectDownload,\n subscribeTransfers,\n getTransfersSnapshot,\n transferKey,\n} from \"./stores/objectDownloadStore\"\n\n// Extended version type for frontend use (includes isDeleted flag)\ntype S3ObjectVersionExtended = S3ObjectVersion & {\n isDeleted?: boolean // Flag for showing \"Deleted\" badge (file that can be restored)\n deleteMarkerVersionId?: string // VersionId of the delete marker (for permanent delete)\n allVersionIds?: string[] // All version IDs of this object (for complete deletion)\n}\nimport { DeleteObjectModal } from \"./DeleteObjectModal\"\nimport { DeleteVersionModal } from \"./DeleteVersionModal\"\nimport { RestoreVersionModal } from \"./RestoreVersionModal\"\nimport { CopyObjectModal } from \"./CopyObjectModal\"\nimport { MoveObjectModal } from \"./MoveObjectModal\"\nimport { GeneratePresignedUrlModal } from \"./GeneratePresignedUrlModal\"\nimport { EditMetadataModal } from \"./EditMetadataModal\"\nimport { ObjectVersionHistoryModal } from \"./ObjectVersionHistoryModal\"\n\n// The transfer lifecycle (worker, streaming, decode, Blob, DOM save) lives in\n// ./stores/objectDownloadStore so downloads survive this component unmounting\n// (ObjectBrowserView swaps in a <Spinner> while a folder loads). This component\n// only reads the store for UI and drives start/cancel.\n\n// Subscribes to live progress for a single in-flight transfer. Each active row\n// renders its own instance of this component (keyed by downloadId), so\n// concurrent transfers each get an independent subscription rather than\n// sharing one — starting a second transfer never disrupts the first's progress.\nfunction RowTransferProgress({\n projectId,\n downloadId,\n isPreviewing,\n}: {\n projectId: string\n downloadId: string\n isPreviewing: boolean\n}) {\n const { data: progress } = trpcReact.storage.ceph.objects.watchDownloadProgress.useSubscription(\n { project_id: projectId, downloadId },\n { enabled: !!downloadId }\n )\n const percent = progress?.percent\n\n return (\n <span className=\"flex w-full flex-1 flex-col gap-1\">\n <span className=\"text-theme-light flex items-center gap-2 text-sm\">\n <Spinner size=\"small\" />\n {percent != null ? (\n <Trans>{percent}%</Trans>\n ) : isPreviewing ? (\n <Trans>Loading preview...</Trans>\n ) : (\n <Trans>Downloading...</Trans>\n )}\n </span>\n {percent != null && (\n <div className=\"bg-theme-background-lvl-2 h-1 w-full overflow-hidden rounded-full\">\n <div\n className=\"bg-theme-accent h-1 rounded-full transition-all duration-150\"\n style={{ width: `${percent}%` }}\n />\n </div>\n )}\n </span>\n )\n}\n\ntype FolderRow = {\n kind: \"folder\"\n prefix: string\n displayName: string\n isDeleted?: boolean\n deleteMarkerVersionId?: string\n folderMarkerVersionId?: string\n}\ntype ObjectRow = {\n kind: \"object\"\n key: string\n size: number\n lastModified: string | undefined\n displayName: string\n}\ntype VersionRow = {\n kind: \"version\"\n key: string\n versionId: string\n isLatest: boolean\n isDeleteMarker: boolean\n isDeleted?: boolean // Flag for showing \"Deleted\" badge (file that can be restored)\n deleteMarkerVersionId?: string // VersionId of the delete marker (for permanent delete)\n allVersionIds?: string[] // All version IDs of this object (for complete deletion)\n size: number\n lastModified: string | undefined\n displayName: string\n}\ntype CephRow = FolderRow | ObjectRow | VersionRow\n\n// Define column templates — with and without selection column\nconst GRID_COLUMN_TEMPLATE_WITH_SELECT = \"40px minmax(200px, 3fr) minmax(100px, 1fr) minmax(180px, 2fr) 60px\"\nconst GRID_COLUMN_TEMPLATE_NO_SELECT = \"minmax(200px, 3fr) minmax(100px, 1fr) minmax(180px, 2fr) 60px\"\n\n// Selection item type\ntype SelectedItem = { key: string; versionId?: string }\n\ninterface ObjectsTableViewProps {\n bucketName: string\n objects: S3Object[]\n folders: Array<\n S3FolderPrefix & { isDeleted?: boolean; deleteMarkerVersionId?: string; folderMarkerVersionId?: string }\n >\n versions?: S3ObjectVersionExtended[] // When showing all versions (extended with isDeleted flag)\n currentPrefix: string\n versioningEnabled?: boolean\n showingVersions?: boolean // Flag to indicate we're in versions view mode\n selectable?: boolean\n selectedItems?: SelectedItem[]\n onToggleSelectKey?: (objectKey: string, versionId?: string) => void\n onFolderClick: (prefix: string) => void\n onDeleteObjectSuccess: (objectKey: string) => void\n onDeleteObjectError: (objectKey: string, errorMessage: string) => void\n onCopyObjectSuccess: (objectKey: string, targetBucket: string, targetKey: string, wasOverwritten: boolean) => void\n onCopyObjectError: (objectKey: string, errorMessage: string) => void\n onMoveObjectSuccess: (objectKey: string, targetBucket: string, targetKey: string) => void\n onMoveObjectError: (objectKey: string, errorMessage: string) => void\n onEditMetadataSuccess: (objectKey: string) => void\n onEditMetadataError: (objectKey: string, errorMessage: string) => void\n onDownloadError: (objectKey: string, errorMessage: string) => void\n onRestoreVersion?: (objectKey: string, versionId: string) => void\n onDeleteVersion?: (objectKey: string, versionId: string) => void\n // Download Object and View Versions are never gated — they're reads, and this codebase's\n // convention is to gate mutations only.\n canCopyObject: boolean\n canMoveObject: boolean\n canUpdateObject: boolean\n canShareObject: boolean\n canDeleteObject: boolean\n canDeleteFolder: boolean\n canDeleteVersion: boolean\n canRestoreVersion: boolean\n isLoading?: boolean\n}\n\nexport function ObjectsTableView({\n bucketName,\n objects,\n folders,\n versions,\n currentPrefix,\n versioningEnabled = false,\n showingVersions = false,\n selectable = false,\n selectedItems = [],\n onToggleSelectKey,\n onFolderClick,\n onDeleteObjectSuccess,\n onDeleteObjectError,\n onCopyObjectSuccess,\n onCopyObjectError,\n onMoveObjectSuccess,\n onMoveObjectError,\n onEditMetadataSuccess,\n onEditMetadataError,\n onDownloadError,\n onRestoreVersion,\n onDeleteVersion,\n canCopyObject,\n canMoveObject,\n canUpdateObject,\n canShareObject,\n canDeleteObject,\n canDeleteFolder,\n canDeleteVersion,\n canRestoreVersion,\n isLoading = false,\n}: ObjectsTableViewProps) {\n const { t } = useLingui()\n const projectId = useProjectId()\n // In-flight transfers are owned by the module store (outside React) so they\n // survive this component unmounting during folder navigation. We only read\n // them here for rendering.\n const activeTransfers = useSyncExternalStore(subscribeTransfers, getTransfersSnapshot)\n const [scrollbarWidth, setScrollbarWidth] = useState(0)\n const [deleteTarget, setDeleteTarget] = useState<{\n key: string\n size?: number\n lastModified?: string\n } | null>(null)\n const [restoreTarget, setRestoreTarget] = useState<{\n key: string\n versionId: string\n size?: number\n lastModified?: string\n } | null>(null)\n const [deleteVersionTarget, setDeleteVersionTarget] = useState<{\n key: string\n versionId: string\n size?: number\n lastModified?: string\n isDeleteMarker?: boolean\n folderMarkerVersionId?: string\n allVersionIds?: string[]\n } | null>(null)\n const [copyTarget, setCopyTarget] = useState<{\n key: string\n size?: number\n } | null>(null)\n const [moveTarget, setMoveTarget] = useState<{\n key: string\n size?: number\n } | null>(null)\n const [editMetadataTarget, setEditMetadataTarget] = useState<string | null>(null)\n const [versionHistoryTarget, setVersionHistoryTarget] = useState<string | null>(null)\n const [presignedUrlTarget, setPresignedUrlTarget] = useState<{ key: string } | null>(null)\n\n // The \"Downloading...\" notification is raised by the store (one toast for all\n // in-flight transfers, dismissed when the last finishes), so starting a\n // transfer here is just the call.\n //\n // Context-menu Download: always forces a file save, regardless of type.\n const handleDownload = (row: ObjectRow) => {\n startObjectDownload({\n kind: \"download\",\n projectId,\n bucketName,\n objectKey: row.key,\n filename: row.displayName,\n onError: onDownloadError,\n })\n }\n\n // Row-click: preview previewable types in a new tab, download everything else.\n const handlePreviewOrDownload = (row: ObjectRow) => {\n startObjectDownload({\n kind: \"preview\",\n projectId,\n bucketName,\n objectKey: row.key,\n filename: row.displayName,\n onError: onDownloadError,\n })\n }\n\n // Cancel the in-flight transfer for a row. The store drops the entry right away\n // (UI clears on the next render, no worker round-trip) and tells the worker to\n // abort its tRPC call, which tears down the fetch so the BFF stops reading.\n // Cancellation is a user action, so confirm it with a toast, not an error.\n const handleCancelTransfer = (rowKey: string) => {\n const transfer = cancelObjectDownload(bucketName, rowKey)\n if (!transfer) return\n const { message, ...options } = getObjectDownloadCancelledToast(rowKey)\n toast.warning(message, options)\n }\n\n // Strip current prefix from display names\n const stripPrefix = (fullKey: string) => (currentPrefix ? fullKey.replace(currentPrefix, \"\") : fullKey)\n\n // Build combined rows — folders first, then objects or versions\n const rows: CephRow[] =\n showingVersions && versions\n ? [\n ...folders.map((f): FolderRow => ({\n kind: \"folder\",\n prefix: f.prefix,\n displayName: stripPrefix(f.prefix).replace(/\\/$/, \"\"),\n isDeleted: f.isDeleted, // Carry over the isDeleted flag for deleted folder markers\n deleteMarkerVersionId: f.deleteMarkerVersionId, // Carry over delete marker versionId for restore\n folderMarkerVersionId: f.folderMarkerVersionId, // Carry over folder marker versionId for permanent delete\n })),\n ...versions.map((v): VersionRow => ({\n kind: \"version\",\n key: v.key,\n versionId: v.versionId,\n isLatest: v.isLatest,\n isDeleteMarker: v.isDeleteMarker,\n isDeleted: v.isDeleted, // Carry over the isDeleted flag\n deleteMarkerVersionId: v.deleteMarkerVersionId, // Carry over delete marker versionId for permanent delete\n allVersionIds: v.allVersionIds, // Carry over all version IDs for complete deletion\n size: v.size,\n lastModified: v.lastModified,\n displayName: stripPrefix(v.key),\n })),\n ]\n : [\n ...folders.map((f): FolderRow => ({\n kind: \"folder\",\n prefix: f.prefix,\n displayName: stripPrefix(f.prefix).replace(/\\/$/, \"\"),\n isDeleted: f.isDeleted, // Carry over the isDeleted flag for deleted folder markers\n deleteMarkerVersionId: f.deleteMarkerVersionId, // Carry over delete marker versionId for restore\n folderMarkerVersionId: f.folderMarkerVersionId, // Carry over folder marker versionId for permanent delete\n })),\n ...objects.map((o): ObjectRow => ({\n kind: \"object\",\n key: o.key,\n size: o.size,\n lastModified: o.lastModified,\n displayName: stripPrefix(o.key),\n })),\n ]\n\n const selectedItemsSet = useMemo(() => {\n return new Set(selectedItems.map((item) => `${item.key}|${item.versionId ?? \"\"}`))\n }, [selectedItems])\n\n // Derived selection values\n const showSelection = selectable // Show selection for all tabs, including versions/deleted\n const gridColumnTemplate = showSelection ? GRID_COLUMN_TEMPLATE_WITH_SELECT : GRID_COLUMN_TEMPLATE_NO_SELECT\n const columnCount = showSelection ? 5 : 4\n\n // Height measured from the space actually left below the table, plus a\n // virtualizer that stays silent until that height is known.\n const {\n ref: tableBodyRef,\n elementRef: parentRef,\n height: bodyHeight,\n virtualItems,\n totalSize,\n measureElement,\n } = useVirtualizedTableBody({ count: rows.length })\n\n // Calculate scrollbar width to keep the fixed header aligned with the scrollable body\n useEffect(() => {\n if (parentRef.current) {\n const width = parentRef.current.offsetWidth - parentRef.current.clientWidth\n setScrollbarWidth(width)\n }\n }, [rows.length, bodyHeight])\n\n return (\n <>\n <div className=\"relative\">\n {/* Table Header with scrollbar padding */}\n <div style={{ paddingRight: `${scrollbarWidth}px` }}>\n <DataGrid columns={columnCount} gridColumnTemplate={gridColumnTemplate} data-testid=\"objects-table-header\">\n <DataGridRow>\n {showSelection && (\n <DataGridHeadCell>\n <span className=\"sr-only\">\n <Trans>Select</Trans>\n </span>\n </DataGridHeadCell>\n )}\n <DataGridHeadCell>\n <Trans>Name</Trans>\n </DataGridHeadCell>\n <DataGridHeadCell>\n <Trans>Size</Trans>\n </DataGridHeadCell>\n <DataGridHeadCell>\n <Trans>Last Modified</Trans>\n </DataGridHeadCell>\n <DataGridHeadCell style={{ marginRight: `-${scrollbarWidth}px` }} />\n </DataGridRow>\n\n {!isLoading && rows.length === 0 && (\n <DataGridRow>\n <DataGridCell colSpan={columnCount}>\n <Status status=\"empty\" title={t`No objects found.`} body={t`There are no items to display.`} />\n </DataGridCell>\n </DataGridRow>\n )}\n </DataGrid>\n </div>\n\n {/* Virtualized Table Body — sized to the space actually left below the\n table, so banners above it shrink the table instead of growing the\n page. */}\n <div\n ref={tableBodyRef}\n className=\"overflow-auto\"\n style={{ height: `${bodyHeight ?? 0}px` }}\n data-testid=\"objects-table-body\"\n >\n <DataGrid\n columns={columnCount}\n gridColumnTemplate={gridColumnTemplate}\n style={{\n height: `${totalSize}px`,\n width: \"100%\",\n position: \"relative\",\n }}\n >\n {virtualItems.map((virtualRow) => {\n const row = rows[virtualRow.index]\n const isFolder = row.kind === \"folder\"\n const isVersion = row.kind === \"version\"\n const isDeletedFile = isVersion && row.isDeleted // File that was deleted (can be restored)\n const activeTransfer =\n row.kind === \"object\" ? activeTransfers.get(transferKey(bucketName, row.key)) : undefined\n const isDownloading = activeTransfer?.kind === \"download\"\n const isPreviewing = activeTransfer?.kind === \"preview\"\n const isStreaming = activeTransfer !== undefined\n const displayName = row.displayName\n\n return (\n <DataGridRow\n key={isFolder ? row.prefix : isVersion ? `${row.key}-${row.versionId}` : row.key}\n data-index={virtualRow.index}\n ref={measureElement}\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n width: \"100%\",\n transform: `translateY(${virtualRow.start}px)`,\n display: \"grid\",\n gridTemplateColumns: gridColumnTemplate,\n alignItems: \"stretch\",\n }}\n data-testid={isFolder ? `folder-row-${row.prefix}` : `object-row-${row.key}`}\n >\n {/* Selection column */}\n {showSelection && (\n <DataGridCell onClick={(e) => e.stopPropagation()}>\n {row.kind === \"object\" ? (\n (() => {\n const displayName = row.displayName\n const isSelected = selectedItemsSet.has(`${row.key}|`)\n return (\n <Checkbox\n checked={isSelected}\n disabled={isStreaming}\n onChange={() => onToggleSelectKey?.(row.key)}\n aria-label={t`Select ${displayName}`}\n data-testid={`select-object-${row.key}`}\n />\n )\n })()\n ) : row.kind === \"version\" ? (\n (() => {\n const displayName = row.displayName\n const isSelected = selectedItemsSet.has(`${row.key}|${row.versionId}`)\n return (\n <Checkbox\n checked={isSelected}\n onChange={() => onToggleSelectKey?.(row.key, row.versionId)}\n aria-label={t`Select ${displayName}`}\n data-testid={`select-version-${row.key}-${row.versionId}`}\n />\n )\n })()\n ) : row.kind === \"folder\" ? (\n <Tooltip triggerEvent=\"hover\" placement=\"right\">\n <TooltipTrigger>\n <Checkbox\n disabled\n aria-label={t`Folders cannot be bulk-deleted. Use the row menu to delete a folder.`}\n data-testid={`select-folder-disabled-${row.prefix}`}\n />\n </TooltipTrigger>\n <TooltipContent>\n <Trans>Folders cannot be bulk-deleted. Use the row menu to delete a folder.</Trans>\n </TooltipContent>\n </Tooltip>\n ) : null}\n </DataGridCell>\n )}\n {/* Name */}\n <DataGridCell>\n {isFolder ? (\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n className=\"flex min-w-0 items-center gap-2 rounded text-left hover:underline focus-visible:outline\"\n onClick={() => onFolderClick(row.prefix)}\n title={row.prefix}\n >\n <MdFolder size={18} className=\"text-theme-light shrink-0\" />\n <span className=\"truncate text-sm\">{row.displayName}</span>\n </button>\n {row.isDeleted && (\n <Badge variant=\"error\">\n <Trans>Deleted</Trans>\n </Badge>\n )}\n </div>\n ) : (\n <div className=\"flex items-center gap-2\">\n {isStreaming ? (\n <Spinner size=\"small\" className=\"shrink-0\" />\n ) : (\n <MdDescription size={18} className=\"text-theme-light shrink-0\" />\n )}\n <button\n type=\"button\"\n className=\"min-w-0 truncate text-left text-sm hover:underline focus-visible:outline disabled:cursor-wait disabled:no-underline\"\n onClick={row.kind === \"object\" ? () => handlePreviewOrDownload(row) : undefined}\n disabled={row.kind !== \"object\" || isStreaming}\n title={\n row.kind !== \"object\"\n ? t`Preview and download aren't available for older versions yet`\n : isStreaming\n ? isPreviewing\n ? t`Loading preview...`\n : t`Downloading...`\n : t`Open ${displayName}`\n }\n >\n {row.displayName}\n </button>\n {isDeletedFile && (\n <Badge variant=\"error\">\n <Trans>Deleted</Trans>\n </Badge>\n )}\n </div>\n )}\n </DataGridCell>\n\n {/* Size */}\n <DataGridCell>\n <span className=\"text-sm\">{isFolder ? \"—\" : formatBytesBinary(row.size)}</span>\n </DataGridCell>\n\n {/* Last Modified */}\n <DataGridCell onClick={(e) => e.stopPropagation()}>\n {isStreaming && activeTransfer && row.kind === \"object\" ? (\n <div className=\"flex items-center gap-2\">\n <RowTransferProgress\n projectId={projectId}\n downloadId={activeTransfer.downloadId}\n isPreviewing={isPreviewing}\n />\n <Icon\n icon=\"cancel\"\n size={18}\n onClick={() => handleCancelTransfer(row.key)}\n title={t`Cancel`}\n className=\"text-theme-light hover:text-theme-danger shrink-0 cursor-pointer\"\n data-testid={`cancel-transfer-${row.key}`}\n />\n </div>\n ) : (\n <span className=\"text-sm\">\n {!isFolder && row.lastModified ? new Date(row.lastModified).toLocaleString() : \"—\"}\n </span>\n )}\n </DataGridCell>\n\n {/* Actions */}\n <DataGridCell onClick={(e) => e.stopPropagation()}>\n <div className=\"flex justify-end\">\n {/* Show menu for: non-folders, non-version-view, or deleted folders in version view.\n The normal-object branch always keeps Download Object / View Versions visible\n (reads are never gated), so it can never end up empty. The folder and\n deleted-file branches only offer gated mutations, so we also check\n hasAnyRowAction there to avoid ever rendering an empty PopupMenu. */}\n {(() => {\n const shouldShowFolderMenu = !isFolder || !showingVersions || row.isDeleted\n if (!shouldShowFolderMenu) return null\n\n const hasAnyRowAction = isFolder\n ? row.isDeleted\n ? canRestoreVersion || canDeleteVersion\n : canDeleteFolder\n : isDeletedFile\n ? canRestoreVersion || canDeleteVersion\n : true // normal object: Download Object / View Versions are always visible\n\n if (!hasAnyRowAction) return null\n\n return (\n <PopupMenu>\n <PopupMenuOptions>\n {isFolder ? (\n row.isDeleted ? (\n // Deleted folder (has delete marker) - show Restore and Delete options\n <>\n {canRestoreVersion && (\n <PopupMenuItem\n label={t`Restore`}\n onClick={() => {\n // For folders, restoring means deleting the delete marker\n if (row.deleteMarkerVersionId) {\n setRestoreTarget({\n key: row.prefix,\n versionId: row.deleteMarkerVersionId,\n size: undefined,\n lastModified: undefined,\n })\n }\n }}\n />\n )}\n {/* Gated on canDeleteVersion, not canDeleteFolder - this permanently purges\n the delete marker/version, it's not a soft delete. */}\n {canDeleteVersion && (\n <PopupMenuItem\n label={t`Delete Folder`}\n onClick={() => {\n // Permanently delete the folder's delete marker and folder marker\n if (row.deleteMarkerVersionId) {\n setDeleteVersionTarget({\n key: row.prefix,\n versionId: row.deleteMarkerVersionId,\n size: undefined,\n lastModified: undefined,\n isDeleteMarker: true, // This version IS a delete marker\n folderMarkerVersionId: row.folderMarkerVersionId,\n // Show both IDs in the confirmation dialog\n allVersionIds: row.folderMarkerVersionId\n ? [row.deleteMarkerVersionId, row.folderMarkerVersionId]\n : undefined,\n })\n }\n }}\n />\n )}\n </>\n ) : (\n // Regular folder - show Delete option\n canDeleteFolder && (\n <PopupMenuItem\n label={t`Delete Folder`}\n onClick={() => setDeleteTarget({ key: row.prefix })}\n />\n )\n )\n ) : isDeletedFile ? (\n // For deleted files, show \"Restore\" and \"Delete\" actions\n <>\n {canRestoreVersion && (\n <PopupMenuItem\n label={t`Restore`}\n onClick={() => {\n if (row.kind === \"version\") {\n setRestoreTarget({\n key: row.key,\n versionId: row.versionId,\n size: row.size,\n lastModified: row.lastModified,\n })\n }\n }}\n />\n )}\n {/* Gated on canDeleteVersion, not canDeleteObject - this permanently purges\n the delete marker/version, it's not a soft delete. */}\n {canDeleteVersion && (\n <PopupMenuItem\n label={t`Delete Object`}\n onClick={() => {\n if (row.kind === \"version\") {\n // For deleted files, delete all versions completely\n const versionIdToDelete = row.deleteMarkerVersionId ?? row.versionId\n setDeleteVersionTarget({\n key: row.key,\n versionId: versionIdToDelete,\n size: row.size,\n lastModified: row.lastModified,\n isDeleteMarker: !!row.deleteMarkerVersionId,\n allVersionIds: row.allVersionIds, // Pass all version IDs for complete deletion\n })\n }\n }}\n />\n )}\n </>\n ) : (\n <>\n <PopupMenuItem\n label={isDownloading ? t`Downloading...` : t`Download Object`}\n disabled={row.kind !== \"object\" || isStreaming}\n onClick={row.kind === \"object\" ? () => handleDownload(row) : undefined}\n data-testid={`download-action-${row.key}`}\n />\n {versioningEnabled && !isVersion && (\n <PopupMenuItem\n label={t`View Versions`}\n disabled={isStreaming}\n onClick={() => setVersionHistoryTarget(row.key)}\n />\n )}\n {canCopyObject && (\n <PopupMenuItem\n label={t`Copy Object`}\n disabled={isStreaming}\n onClick={() => setCopyTarget({ key: row.key, size: row.size })}\n />\n )}\n {canMoveObject && (\n <PopupMenuItem\n label={t`Move/Rename Object`}\n disabled={isStreaming}\n onClick={() => setMoveTarget({ key: row.key, size: row.size })}\n />\n )}\n {canUpdateObject && (\n <PopupMenuItem\n label={t`Edit Object Metadata`}\n disabled={isStreaming}\n onClick={() => setEditMetadataTarget(row.key)}\n />\n )}\n {canShareObject && (\n <PopupMenuItem\n label={t`Share Object URL`}\n disabled={row.kind !== \"object\" || isStreaming}\n onClick={\n row.kind === \"object\"\n ? () => setPresignedUrlTarget({ key: row.key })\n : undefined\n }\n data-testid={`share-url-action-${row.key}`}\n />\n )}\n {canDeleteObject && (\n <PopupMenuItem\n label={t`Delete Object`}\n disabled={isStreaming}\n onClick={() =>\n setDeleteTarget({\n key: row.key,\n size: row.size,\n lastModified: row.lastModified,\n })\n }\n />\n )}\n </>\n )}\n </PopupMenuOptions>\n </PopupMenu>\n )\n })()}\n </div>\n </DataGridCell>\n </DataGridRow>\n )\n })}\n </DataGrid>\n </div>\n </div>\n\n <DeleteObjectModal\n bucketName={bucketName}\n objectKey={deleteTarget?.key ?? \"\"}\n objectSize={deleteTarget?.size}\n lastModified={deleteTarget?.lastModified}\n versioningEnabled={versioningEnabled}\n isOpen={deleteTarget !== null}\n onClose={() => setDeleteTarget(null)}\n onSuccess={onDeleteObjectSuccess}\n onError={onDeleteObjectError}\n />\n\n <RestoreVersionModal\n bucketName={bucketName}\n objectKey={restoreTarget?.key ?? \"\"}\n versionId={restoreTarget?.versionId ?? \"\"}\n versionSize={restoreTarget?.size}\n versionDate={restoreTarget?.lastModified}\n isOpen={restoreTarget !== null}\n onClose={() => setRestoreTarget(null)}\n onSuccess={(key, versionId) => {\n setRestoreTarget(null)\n onRestoreVersion?.(key, versionId)\n }}\n onError={() => {\n setRestoreTarget(null)\n // Error is shown in the modal itself via mutation error state\n }}\n />\n\n <DeleteVersionModal\n bucketName={bucketName}\n objectKey={deleteVersionTarget?.key ?? \"\"}\n versionId={deleteVersionTarget?.versionId ?? \"\"}\n versionSize={deleteVersionTarget?.size}\n versionDate={deleteVersionTarget?.lastModified}\n isDeleteMarker={deleteVersionTarget?.isDeleteMarker ?? false}\n folderMarkerVersionId={deleteVersionTarget?.folderMarkerVersionId}\n allVersionIds={deleteVersionTarget?.allVersionIds}\n isOpen={deleteVersionTarget !== null}\n onClose={() => setDeleteVersionTarget(null)}\n onSuccess={(key, versionId) => {\n setDeleteVersionTarget(null)\n onDeleteVersion?.(key, versionId)\n }}\n onError={() => {\n setDeleteVersionTarget(null)\n // Error is shown in the modal itself via mutation error state\n }}\n />\n\n <CopyObjectModal\n bucketName={bucketName}\n objectKey={copyTarget?.key ?? \"\"}\n objectSize={copyTarget?.size}\n isOpen={copyTarget !== null}\n onClose={() => setCopyTarget(null)}\n onSuccess={onCopyObjectSuccess}\n onError={onCopyObjectError}\n />\n\n <MoveObjectModal\n bucketName={bucketName}\n objectKey={moveTarget?.key ?? \"\"}\n objectSize={moveTarget?.size}\n isOpen={moveTarget !== null}\n onClose={() => setMoveTarget(null)}\n onSuccess={onMoveObjectSuccess}\n onError={onMoveObjectError}\n />\n\n <EditMetadataModal\n bucketName={bucketName}\n objectKey={editMetadataTarget ?? \"\"}\n isOpen={editMetadataTarget !== null}\n onClose={() => setEditMetadataTarget(null)}\n onSuccess={onEditMetadataSuccess}\n onError={onEditMetadataError}\n />\n\n <GeneratePresignedUrlModal\n bucketName={bucketName}\n objectKey={presignedUrlTarget?.key ?? null}\n isOpen={presignedUrlTarget !== null}\n onClose={() => setPresignedUrlTarget(null)}\n onCopySuccess={(objectKey) => {\n const { message, ...options } = getPresignedUrlCopiedToast(objectKey)\n toast.success(message, options)\n }}\n />\n\n <ObjectVersionHistoryModal\n isOpen={versionHistoryTarget !== null}\n bucketName={bucketName}\n objectKey={versionHistoryTarget ?? \"\"}\n onClose={() => setVersionHistoryTarget(null)}\n onRestoreVersion={onRestoreVersion}\n onDeleteVersion={onDeleteVersion}\n canRestoreVersion={canRestoreVersion}\n canDeleteVersion={canDeleteVersion}\n />\n </>\n )\n}\n","import { Breadcrumb, BreadcrumbItem } from \"@cloudoperators/juno-ui-components\"\nimport { useLingui } from \"@lingui/react/macro\"\nimport { MdStorage, MdInventory2, MdOutlineInventory2, MdFolder, MdFolderOpen } from \"react-icons/md\"\n\n// ── Breadcrumb helpers ────────────────────────────────────────────────────────\n\n/**\n * Splits the current prefix into navigable breadcrumb segments.\n * e.g. \"a/b/c/\" → [{ label: \"a\", prefix: \"a/\" }, { label: \"b\", prefix: \"a/b/\" }, { label: \"c\", prefix: \"a/b/c/\" }]\n */\nfunction prefixToSegments(prefix: string): { label: string; prefix: string }[] {\n if (!prefix) return []\n // Remove trailing slash before splitting so we don't get a trailing empty segment\n const parts = prefix.replace(/\\/$/, \"\").split(\"/\").filter(Boolean)\n return parts.map((label, i) => ({\n label,\n prefix: parts.slice(0, i + 1).join(\"/\") + \"/\",\n }))\n}\n\n// Active crumb gets a pill background to match the design — visually marks the current location.\nconst activeCrumbClass = \"bg-theme-background-lvl-4 rounded px-2 py-0.5\"\n\n// ── ObjectsFileNavigation ─────────────────────────────────────────────────────\n\ninterface ObjectsFileNavigationProps {\n bucketName: string\n prefix: string\n onBucketsClick: () => void\n onPrefixClick: (prefix: string) => void\n}\n\nexport function ObjectsFileNavigation({\n bucketName,\n prefix,\n onBucketsClick,\n onPrefixClick,\n}: ObjectsFileNavigationProps) {\n const { t } = useLingui()\n\n const prefixSegments = prefixToSegments(prefix)\n\n // The last segment (deepest folder) is the active crumb — non-clickable.\n // All segments before it are clickable navigation targets.\n const isAtRoot = prefixSegments.length === 0\n\n return (\n <div>\n <Breadcrumb>\n {/* \"All buckets\" root — always navigates back to the bucket list.\n Always clickable (you're inside a bucket whenever this view is shown).\n Mirrors the Swift \"All containers\" crumb so users can jump back to the\n top from the secondary breadcrumb instead of hunting in the global one. */}\n {/* TODO: BreadcrumbItem.label is typed as string but renders ReactNode — remove cast once Juno fixes the type */}\n <BreadcrumbItem\n onClick={onBucketsClick}\n label={\n (\n <span className=\"flex items-center gap-1\">\n <MdStorage size={15} className=\"shrink-0\" />\n {t`All buckets`}\n </span>\n ) as unknown as string\n }\n />\n\n {/* Bucket name — inventory/box icon distinguishes it from folders;\n outlined when active (current root level), filled when navigable */}\n {/* TODO: BreadcrumbItem.label is typed as string but renders ReactNode — remove cast once Juno fixes the type */}\n <BreadcrumbItem\n onClick={isAtRoot ? undefined : () => onPrefixClick(\"\")}\n active={isAtRoot}\n label={\n (\n <span className={`flex items-center gap-1 ${isAtRoot ? activeCrumbClass : \"\"}`}>\n {isAtRoot ? (\n <MdOutlineInventory2 size={15} className=\"shrink-0\" />\n ) : (\n <MdInventory2 size={15} className=\"shrink-0\" />\n )}\n {bucketName}\n </span>\n ) as unknown as string\n }\n />\n\n {/* One crumb per prefix segment:\n - intermediate segments → MdFolder (filled, clickable)\n - last segment → MdFolderOpen (outlined, active/non-clickable) */}\n {prefixSegments.map((seg, i) => {\n const isLast = i === prefixSegments.length - 1\n return (\n <BreadcrumbItem\n key={seg.prefix}\n onClick={isLast ? undefined : () => onPrefixClick(seg.prefix)}\n active={isLast}\n label={\n (\n <span className={`flex items-center gap-1 ${isLast ? activeCrumbClass : \"\"}`}>\n {isLast ? (\n <MdFolderOpen size={15} className=\"shrink-0\" />\n ) : (\n <MdFolder size={15} className=\"shrink-0\" />\n )}\n {seg.label}\n </span>\n ) as unknown as string\n }\n />\n )\n })}\n </Breadcrumb>\n </div>\n )\n}\n","import { useState } from \"react\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { Modal, TextInput, Stack, Message } from \"@cloudoperators/juno-ui-components\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport { useModalTracking } from \"@/client/hooks/useModalTracking\"\nimport { validateFolderName } from \"./utils/objectValidation\"\n\ninterface CreateFolderModalProps {\n bucketName: string\n currentPrefix: string\n isOpen: boolean\n onClose: () => void\n onSuccess: (folderPath: string) => void\n}\n\nexport function CreateFolderModal({ bucketName, currentPrefix, isOpen, onClose, onSuccess }: CreateFolderModalProps) {\n const { t } = useLingui()\n const projectId = useProjectId()\n const [folderName, setFolderName] = useState(\"\")\n const [validationError, setValidationError] = useState<string | null>(null)\n const [submitError, setSubmitError] = useState<string | null>(null)\n const utils = trpcReact.useUtils()\n\n const { trackClose, markSubmitted, resetTracking } = useModalTracking({\n isOpen,\n actionPrefix: \"storage.ceph.folder.create\",\n })\n\n // Fetch existing folders for duplicate detection\n const { data: objectsData } = trpcReact.storage.ceph.objects.list.useQuery(\n {\n project_id: projectId ?? \"\",\n containerName: bucketName,\n prefix: currentPrefix || undefined,\n delimiter: \"/\",\n maxKeys: 1000,\n },\n { enabled: isOpen && !!projectId && !!bucketName }\n )\n\n const createFolderMutation = trpcReact.storage.ceph.objects.createFolder.useMutation({\n onSuccess: (_data, variables) => {\n // Invalidate all object list queries to refresh the view\n utils.storage.ceph.objects.list.invalidate()\n // Invalidate bucket list to update object count\n utils.storage.ceph.containers.list.invalidate()\n // Use the exact path that was submitted (with trailing slash for display)\n const submittedFullPath = variables.folderPath.endsWith(\"/\") ? variables.folderPath : `${variables.folderPath}/`\n onSuccess(submittedFullPath)\n handleClose()\n },\n onError: (error) => {\n if (error.data?.code === \"CONFLICT\") {\n setValidationError(t`A folder with this name already exists`)\n setSubmitError(null)\n } else {\n setSubmitError(error.message || t`The folder could not be created. Try again.`)\n }\n\n resetTracking()\n },\n })\n\n const handleClose = () => {\n setFolderName(\"\")\n setValidationError(null)\n setSubmitError(null)\n createFolderMutation.reset()\n resetTracking()\n onClose()\n }\n\n const handleFolderNameChange = (value: string) => {\n setFolderName(value)\n setSubmitError(null)\n\n if (validationError) {\n const existingFolders = objectsData?.folders.map((f) => f.prefix) ?? []\n const error = validateFolderName(value, existingFolders, currentPrefix)\n setValidationError(error ? t(error.message) : null)\n }\n }\n\n const handleCreate = () => {\n if (!projectId) return\n\n const existingFolders = objectsData?.folders.map((f) => f.prefix) ?? []\n const error = validateFolderName(folderName, existingFolders, currentPrefix)\n if (error) {\n setValidationError(t(error.message))\n return\n }\n\n setSubmitError(null)\n markSubmitted()\n const fullPath = currentPrefix + folderName.trim()\n\n createFolderMutation.mutate({\n project_id: projectId,\n containerName: bucketName,\n folderPath: fullPath,\n })\n }\n\n return (\n <Modal\n open={isOpen}\n onCancel={() => {\n trackClose()\n handleClose()\n }}\n title={<Trans>Create New Folder</Trans>}\n size=\"large\"\n confirmButtonLabel={createFolderMutation.isPending ? t`Creating...` : t`Create Folder`}\n onConfirm={handleCreate}\n confirmButtonVariant=\"primary\"\n cancelButtonLabel={t`Cancel`}\n disableConfirmButton={createFolderMutation.isPending || !folderName.trim()}\n disableCancelButton={createFolderMutation.isPending}\n disableCloseButton={createFolderMutation.isPending}\n >\n <Stack direction=\"vertical\" gap=\"4\">\n {submitError && (\n <Message\n variant=\"error\"\n dismissible\n onDismiss={() => setSubmitError(null)}\n role=\"alert\"\n aria-live=\"assertive\"\n data-testid=\"create-folder-error\"\n >\n {submitError}\n </Message>\n )}\n <p>\n <Trans>Enter a name for the new folder.</Trans>\n </p>\n\n {currentPrefix && (\n <div className=\"bg-theme-background-lvl-2 rounded p-3\">\n <span className=\"text-theme-light text-sm\">\n <Trans>Current location:</Trans>\n </span>\n <div className=\"mt-1 text-sm\">{currentPrefix}</div>\n </div>\n )}\n\n <TextInput\n label={t`Folder Name`}\n value={folderName}\n onChange={(e) => handleFolderNameChange(e.target.value)}\n placeholder=\"my-folder\"\n autoFocus\n invalid={!!validationError}\n errortext={validationError || undefined}\n disabled={createFolderMutation.isPending}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" && !createFolderMutation.isPending) {\n handleCreate()\n }\n }}\n />\n\n <div className=\"bg-theme-background-lvl-1 rounded p-3\">\n <span className=\"text-theme-light text-sm\">\n <Trans>Full path:</Trans>\n </span>\n <div className=\"mt-1 text-sm break-all\">{currentPrefix + folderName.trim() + \"/\"}</div>\n </div>\n </Stack>\n </Modal>\n )\n}\n","import { useState, useRef } from \"react\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { Modal, Stack, Spinner } from \"@cloudoperators/juno-ui-components\"\nimport { MdCloudUpload } from \"react-icons/md\"\nimport { trpcClient, trpcReact } from \"@/client/trpcClient\"\nimport { cn } from \"@/client/utils/cn\"\nimport { formatBytesBinary } from \"@/client/utils/formatBytes\"\n\ninterface UploadObjectModalProps {\n isOpen: boolean\n currentPrefix: string\n bucketName: string\n projectId: string\n onClose: () => void\n onSuccess?: (objectName: string) => void\n onError?: (objectName: string, errorMessage: string) => void\n onCancelled?: (objectName: string) => void\n}\n\nexport const UploadObjectModal = ({\n isOpen,\n currentPrefix,\n bucketName,\n projectId,\n onClose,\n onSuccess,\n onError,\n onCancelled,\n}: UploadObjectModalProps) => {\n const { t } = useLingui()\n\n const [selectedFile, setSelectedFile] = useState<File | null>(null)\n const [fileError, setFileError] = useState<string | null>(null)\n const [isDragging, setIsDragging] = useState(false)\n const [uploadId, setUploadId] = useState<string | null>(null)\n const [uploadError, setUploadError] = useState<string | null>(null)\n const [isPending, setIsPending] = useState(false)\n\n const submittedNameRef = useRef(\"\")\n const fileInputRef = useRef<HTMLInputElement>(null)\n const abortControllerRef = useRef<AbortController | null>(null)\n\n const utils = trpcReact.useUtils()\n\n const handleCancelUpload = () => {\n abortControllerRef.current?.abort()\n }\n\n // Subscribe to upload progress — uploadId is set before the upload starts\n // so the subscription is active from the very first byte. The BFF scopes the\n // id with project_id, so we pass it here too (mirrors watchDownloadProgress).\n const { data: uploadProgress } = trpcReact.storage.ceph.objects.watchUploadProgress.useSubscription(\n { project_id: projectId, uploadId: uploadId ?? \"\" },\n { enabled: !!uploadId && !!projectId && isPending }\n )\n\n const handleClose = () => {\n if (isPending) return\n resetAndClose()\n }\n\n const resetAndClose = () => {\n setSelectedFile(null)\n setFileError(null)\n setIsDragging(false)\n setUploadId(null)\n setUploadError(null)\n if (fileInputRef.current) fileInputRef.current.value = \"\"\n onClose()\n }\n\n const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0]\n if (file) {\n setFileError(null)\n setUploadError(null)\n setSelectedFile(file)\n }\n }\n\n const handleDragOver = (e: React.DragEvent<HTMLLabelElement>) => {\n e.preventDefault()\n e.stopPropagation()\n if (isPending) return\n setIsDragging(true)\n }\n\n const handleDragLeave = (e: React.DragEvent<HTMLLabelElement>) => {\n e.preventDefault()\n e.stopPropagation()\n if (isPending) return\n setIsDragging(false)\n }\n\n const handleDrop = (e: React.DragEvent<HTMLLabelElement>) => {\n e.preventDefault()\n e.stopPropagation()\n setIsDragging(false)\n if (isPending) return\n const file = e.dataTransfer.files?.[0]\n if (file) {\n setFileError(null)\n setUploadError(null)\n setSelectedFile(file)\n }\n }\n\n const handleSubmit = async () => {\n if (!selectedFile) {\n setFileError(t`Please select a file to upload`)\n return\n }\n\n const objectKey = `${currentPrefix}${selectedFile.name}`\n const activeUploadId = `${bucketName}:${objectKey}:${crypto.randomUUID()}`\n submittedNameRef.current = selectedFile.name\n setUploadError(null)\n\n const controller = new AbortController()\n abortControllerRef.current = controller\n\n // Compute uploadId client-side before upload starts — the subscription must\n // be active before the first progress event fires from the BFF.\n setUploadId(activeUploadId)\n setIsPending(true)\n\n try {\n // Metadata is sent as custom headers via tRPC operation context —\n // no shared mutable state, safe for concurrent uploads.\n const uploadContext = {\n headers: {\n \"x-upload-project-id\": projectId,\n \"x-upload-container\": bucketName,\n \"x-upload-object\": objectKey,\n \"x-upload-type\": selectedFile.type || \"application/octet-stream\",\n \"x-upload-size\": String(selectedFile.size),\n \"x-upload-id\": activeUploadId,\n },\n }\n\n await trpcClient.storage.ceph.objects.uploadObject.mutate(selectedFile, {\n context: uploadContext,\n signal: controller.signal,\n })\n\n // Invalidate every list variant (matches the other Ceph object modals).\n utils.storage.ceph.objects.list.invalidate()\n onSuccess?.(submittedNameRef.current)\n resetAndClose()\n } catch (err) {\n const isAborted =\n err instanceof Error &&\n (err.name === \"AbortError\" ||\n err.message === \"Request canceled\" ||\n err.message.includes(\"signal is aborted\") ||\n err.message.includes(\"aborted\"))\n if (isAborted) {\n onCancelled?.(submittedNameRef.current)\n resetAndClose()\n return\n }\n const message = err instanceof Error ? err.message : String(err)\n setUploadError(message)\n onError?.(submittedNameRef.current, message)\n } finally {\n setIsPending(false)\n setUploadId(null)\n abortControllerRef.current = null\n }\n }\n\n // isPending is tracked via useState above\n const progressPct = uploadProgress?.percent ?? null\n\n if (!isOpen) return null\n\n const parentPath = currentPrefix || \"/\"\n const selectedObjectName = selectedFile ? `${currentPrefix}${selectedFile.name}` : \"\"\n\n return (\n <Modal\n title={\n <span className=\"flex max-w-100 items-center gap-1\">\n <span className=\"shrink-0\">\n <Trans>Upload object to:</Trans>\n </span>\n <span className=\"truncate\" title={parentPath}>\n {parentPath}\n </span>\n </span>\n }\n open={isOpen}\n onCancel={isPending ? handleCancelUpload : handleClose}\n confirmButtonLabel={isPending ? t`Uploading...` : t`Upload Object`}\n onConfirm={handleSubmit}\n cancelButtonLabel={isPending ? t`Cancel upload` : t`Cancel`}\n size=\"small\"\n disableConfirmButton={isPending || !selectedFile}\n disableCloseButton={isPending}\n >\n <Stack direction=\"vertical\" gap=\"4\">\n {/* Upload error */}\n {uploadError && (\n <p className=\"text-theme-error\">\n <Trans>Upload failed: {uploadError}</Trans>\n </p>\n )}\n\n {/* Object path preview */}\n {selectedFile && !isPending && (\n <p className=\"text-theme-default\">\n <Trans>\n Object will be uploaded as: <span className=\"font-semibold\">{selectedObjectName}</span>\n </Trans>\n </p>\n )}\n\n {/* File drop zone — mirrors CreateImageModal pattern */}\n <div>\n <label\n htmlFor=\"upload-object-file\"\n className={cn(\n \"flex flex-col items-center justify-center rounded-lg border-2 border-dashed px-6 py-8 text-center transition-colors\",\n isDragging\n ? \"border-theme-accent bg-theme-background-lvl-2\"\n : isPending\n ? \"border-theme-background-lvl-4 pointer-events-none cursor-not-allowed opacity-60\"\n : \"border-theme-background-lvl-4 hover:border-theme-accent hover:bg-theme-background-lvl-1 cursor-pointer\"\n )}\n onDragOver={handleDragOver}\n onDragLeave={handleDragLeave}\n onDrop={handleDrop}\n >\n <MdCloudUpload className=\"text-theme-light mb-2\" size={40} />\n <p className=\"text-theme-default text-sm font-medium\">\n {isDragging ? (\n <span>{t`Drop your 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-theme-light mt-1 text-xs\">{t`Any file type`}</p>\n <input\n ref={fileInputRef}\n id=\"upload-object-file\"\n type=\"file\"\n className=\"hidden\"\n onChange={handleFileChange}\n disabled={isPending}\n />\n </label>\n\n {/* Selected file info */}\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 min-w-0 items-center gap-2\">\n <svg className=\"h-4 w-4 shrink-0 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=\"truncate text-gray-700\">{selectedFile.name}</span>\n <span className=\"shrink-0 text-gray-400\">({formatBytesBinary(selectedFile.size)})</span>\n </div>\n {!isPending && (\n <button\n type=\"button\"\n onClick={() => {\n setSelectedFile(null)\n setFileError(null)\n setUploadError(null)\n if (fileInputRef.current) fileInputRef.current.value = \"\"\n }}\n className=\"ml-2 shrink-0 font-medium text-red-600 hover:text-red-800\"\n >\n {t`Remove`}\n </button>\n )}\n </div>\n )}\n\n {fileError && <p className=\"mt-1 text-xs text-red-600\">{fileError}</p>}\n </div>\n\n {/* Upload progress */}\n {isPending && (\n <div className=\"flex flex-col gap-2\">\n <span className=\"text-theme-light flex items-center gap-2 text-sm\">\n <Spinner size=\"small\" />\n {progressPct !== null ? <Trans>Uploading... {progressPct}%</Trans> : <Trans>Uploading...</Trans>}\n </span>\n {progressPct !== null && (\n <div className=\"bg-theme-background-lvl-2 h-1.5 w-full overflow-hidden rounded-full\">\n <div\n className=\"bg-theme-accent h-1.5 rounded-full transition-all duration-150\"\n style={{ width: `${progressPct}%` }}\n />\n </div>\n )}\n </div>\n )}\n </Stack>\n </Modal>\n )\n}\n","import { useState } from \"react\"\nimport { Trans, Plural, useLingui } from \"@lingui/react/macro\"\nimport { Modal, TextInput, Stack } from \"@cloudoperators/juno-ui-components\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport { useModalTracking } from \"@/client/hooks/useModalTracking\"\nimport type { DeleteObjectsBulkOutput } from \"@/server/Storage/types/ceph\"\n\ninterface DeleteObjectsModalProps {\n bucketName: string\n objectKeys: string[]\n versions: Array<{ key: string; versionId: string }>\n currentPrefix: string\n versioningEnabled?: boolean\n isVersionMode?: boolean\n isOpen: boolean\n onClose: () => void\n onDeleted: (deletedKeys: string[], errorCount: number) => void\n onError: (errorMessage: string) => void\n}\n\nconst MAX_VISIBLE = 20\nconst MAX_ERROR_VISIBLE = 100\n\nexport function DeleteObjectsModal({\n bucketName,\n objectKeys,\n versions,\n currentPrefix,\n versioningEnabled = false,\n isVersionMode = false,\n isOpen,\n onClose,\n onDeleted,\n onError,\n}: DeleteObjectsModalProps) {\n const { t } = useLingui()\n const projectId = useProjectId()\n const [confirmText, setConfirmText] = useState(\"\")\n const [result, setResult] = useState<DeleteObjectsBulkOutput | null>(null)\n const utils = trpcReact.useUtils()\n\n const { trackClose, markSubmitted, resetTracking } = useModalTracking({\n isOpen,\n actionPrefix: isVersionMode ? \"storage.ceph.versions.delete_bulk\" : \"storage.ceph.objects.delete_bulk\",\n })\n\n const deleteBulkMutation = trpcReact.storage.ceph.objects.deleteBulk.useMutation({\n onSuccess: (res) => {\n utils.storage.ceph.objects.list.invalidate()\n utils.storage.ceph.containers.list.invalidate()\n utils.storage.ceph.versioning.checkDeletedContent.invalidate()\n onDeleted(\n res.deleted.map((d) => d.key),\n res.errorCount\n )\n if (res.errorCount === 0) {\n handleClose()\n } else {\n setResult(res)\n }\n },\n onError: (error) => onError(error.message),\n })\n\n const deleteVersionsBulkMutation = trpcReact.storage.ceph.objects.deleteVersionsBulk.useMutation({\n onSuccess: (res) => {\n utils.storage.ceph.objects.list.invalidate()\n utils.storage.ceph.containers.list.invalidate()\n utils.storage.ceph.versioning.checkDeletedContent.invalidate()\n onDeleted(\n res.deleted.map((d) => d.key),\n res.errorCount\n )\n if (res.errorCount === 0) {\n handleClose()\n } else {\n setResult(res)\n }\n },\n onError: (error) => onError(error.message),\n })\n\n const handleClose = () => {\n setConfirmText(\"\")\n setResult(null)\n deleteBulkMutation.reset()\n deleteVersionsBulkMutation.reset()\n resetTracking()\n onClose()\n }\n\n const handleConfirm = () => {\n if (!projectId) return\n\n if (result === null) {\n // Step A: Confirm\n markSubmitted()\n if (isVersionMode) {\n deleteVersionsBulkMutation.mutate({\n project_id: projectId,\n containerName: bucketName,\n versions,\n })\n } else {\n deleteBulkMutation.mutate({\n project_id: projectId,\n containerName: bucketName,\n objectKeys,\n })\n }\n } else {\n // Step B: Close results view\n handleClose()\n }\n }\n\n if (!isOpen || (objectKeys.length === 0 && versions.length === 0)) return null\n\n const count = isVersionMode ? versions.length : objectKeys.length\n const isConfirmValid = confirmText === \"delete\"\n const isPending = isVersionMode ? deleteVersionsBulkMutation.isPending : deleteBulkMutation.isPending\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={() => {\n trackClose()\n handleClose()\n }}\n title={<Trans>Delete Results</Trans>}\n size=\"large\"\n confirmButtonLabel={t`Done`}\n onConfirm={handleConfirm}\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>\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, idx) => {\n const displayName = e.key.replace(currentPrefix, \"\") || e.key\n const errorDetail = e.code ? (e.message ? `${e.code}: ${e.message}` : e.code) : e.message || \"\"\n return (\n <div key={idx} className=\"border-theme-background-lvl-3 border-b pb-2 last:border-0 last:pb-0\">\n <div className=\"overflow-x-hidden font-medium [overflow-wrap:anywhere]\" title={e.key}>\n {displayName}\n </div>\n {errorDetail && <div className=\"text-juno-red mt-1 text-sm\">{errorDetail}</div>}\n </div>\n )\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 // For version mode: group by object key to show \"Objects\" and \"Versions\" separately\n const uniqueObjectKeys = isVersionMode ? Array.from(new Set(versions.map((v) => v.key))) : objectKeys\n const displayObjectNames = uniqueObjectKeys.map((key) => key.replace(currentPrefix, \"\") || key)\n const visibleObjectNames = displayObjectNames.slice(0, MAX_VISIBLE)\n const hiddenObjectCount = displayObjectNames.length - visibleObjectNames.length\n\n // For non-version mode (regular objects)\n const itemsToDisplay = objectKeys.map((key) => key.replace(currentPrefix, \"\") || key)\n const visibleNames = itemsToDisplay.slice(0, MAX_VISIBLE)\n const hiddenCount = count - visibleNames.length\n\n // For version mode: calculate hidden versions count\n const hiddenVersionsCount = versions.length - MAX_VISIBLE\n\n const confirmLabel = isPending\n ? t`Deleting...`\n : isVersionMode\n ? count === 1\n ? t`Delete Version`\n : t`Delete Versions`\n : count === 1\n ? t`Delete Object`\n : t`Delete Objects`\n\n return (\n <Modal\n open={isOpen}\n onCancel={() => {\n trackClose()\n handleClose()\n }}\n title={\n isVersionMode ? (\n <Plural value={count} one=\"Delete # Version\" other=\"Delete # Versions\" />\n ) : (\n <Plural value={count} one=\"Delete # Object\" other=\"Delete # Objects\" />\n )\n }\n size=\"large\"\n confirmButtonLabel={confirmLabel}\n confirmButtonVariant=\"primary-danger\"\n onConfirm={handleConfirm}\n cancelButtonLabel={t`Cancel`}\n disableConfirmButton={!isConfirmValid || isPending}\n disableCancelButton={isPending}\n disableCloseButton={isPending}\n >\n <Stack direction=\"vertical\" gap=\"4\">\n <p className=\"text-theme-default overflow-x-hidden [overflow-wrap:anywhere]\">\n {isVersionMode ? (\n <Trans>These objects and all their versions will be permanently deleted and cannot be restored.</Trans>\n ) : versioningEnabled ? (\n <Trans>The selected objects will be marked as deleted but can be restored from version history.</Trans>\n ) : (\n <Trans>The selected objects will be permanently deleted. This action cannot be undone.</Trans>\n )}\n </p>\n\n <div className=\"space-y-3\">\n {isVersionMode ? (\n <>\n <div>\n <label className=\"text-sm font-semibold\">\n <Plural value={displayObjectNames.length} one=\"Object:\" other=\"Objects to delete:\" />\n </label>\n {displayObjectNames.length === 1 ? (\n <p className=\"mt-1 overflow-x-hidden text-sm [overflow-wrap:anywhere]\">{displayObjectNames[0]}</p>\n ) : (\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 {visibleObjectNames.map((name, idx) => (\n <div\n key={idx}\n className=\"text-theme-default overflow-x-hidden text-sm [overflow-wrap:anywhere]\"\n >\n {name}\n </div>\n ))}\n {hiddenObjectCount > 0 && (\n <div className=\"text-theme-light pt-2 text-sm\">\n <Trans>… and {hiddenObjectCount} more</Trans>\n </div>\n )}\n </Stack>\n </div>\n )}\n </div>\n <div>\n <label className=\"text-sm font-semibold\">\n <Trans>Versions to delete:</Trans>\n </label>\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 {versions.slice(0, MAX_VISIBLE).map((v, idx) => (\n <code key={idx} className=\"block overflow-x-hidden text-xs [overflow-wrap:anywhere]\">\n {v.versionId}\n </code>\n ))}\n {versions.length > MAX_VISIBLE && (\n <div className=\"text-theme-light pt-2 text-sm\">\n <Trans>… and {hiddenVersionsCount} more</Trans>\n </div>\n )}\n </Stack>\n </div>\n </div>\n </>\n ) : (\n <div>\n <label className=\"text-sm font-semibold\">\n <Trans>Objects to delete:</Trans>\n </label>\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 {visibleNames.map((name, idx) => (\n <div key={idx} className=\"text-theme-default overflow-x-hidden text-sm [overflow-wrap:anywhere]\">\n {name}\n </div>\n ))}\n {hiddenCount > 0 && (\n <div className=\"text-theme-light pt-2 text-sm\">\n <Trans>… and {hiddenCount} more</Trans>\n </div>\n )}\n </Stack>\n </div>\n </div>\n )}\n </div>\n\n <div>\n <TextInput\n label={t`Type \"delete\" to confirm`}\n value={confirmText}\n onChange={(e) => setConfirmText(e.target.value)}\n placeholder=\"delete\"\n autoFocus\n />\n </div>\n\n {(deleteBulkMutation.error || deleteVersionsBulkMutation.error) && (\n <p className=\"text-juno-red text-sm\">\n <Trans>Error:</Trans> {(deleteBulkMutation.error || deleteVersionsBulkMutation.error)?.message}\n </p>\n )}\n </Stack>\n </Modal>\n )\n}\n","import { useState } from \"react\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { Modal, Stack, Checkbox } from \"@cloudoperators/juno-ui-components\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport { useModalTracking } from \"@/client/hooks/useModalTracking\"\n\ninterface EnableVersioningModalProps {\n isOpen: boolean\n bucketName: string\n onClose: () => void\n onSuccess?: (bucketName: string) => void\n onError?: (bucketName: string, errorMessage: string) => void\n}\n\nexport const EnableVersioningModal = ({\n isOpen,\n bucketName,\n onClose,\n onSuccess,\n onError,\n}: EnableVersioningModalProps) => {\n const { t } = useLingui()\n const projectId = useProjectId()\n const [confirmed, setConfirmed] = useState(false)\n\n const { trackClose, markSubmitted, resetTracking } = useModalTracking({\n isOpen,\n actionPrefix: \"storage.ceph.bucket.versioning.enable\",\n })\n\n const utils = trpcReact.useUtils()\n\n const enableMutation = trpcReact.storage.ceph.versioning.setStatus.useMutation({\n onSuccess: () => {\n utils.storage.ceph.versioning.getStatus.invalidate()\n onSuccess?.(bucketName)\n },\n onError: (error) => {\n onError?.(bucketName, error.message)\n },\n onSettled: () => {\n handleClose()\n },\n })\n\n const handleClose = () => {\n trackClose()\n setConfirmed(false)\n enableMutation.reset()\n resetTracking()\n onClose()\n }\n\n const handleEnable = () => {\n if (!confirmed) return\n\n markSubmitted()\n enableMutation.mutate({\n project_id: projectId,\n bucket: bucketName,\n status: \"Enabled\",\n })\n }\n\n if (!isOpen) return null\n\n return (\n <Modal\n title={t`Enable Versioning`}\n open={isOpen}\n onCancel={handleClose}\n confirmButtonLabel={t`Enable Versioning`}\n onConfirm={handleEnable}\n cancelButtonLabel={t`Cancel`}\n disableConfirmButton={!confirmed || enableMutation.isPending}\n >\n <Stack direction=\"vertical\" gap=\"4\">\n <p>\n <Trans>\n Once enabled, versioning cannot be fully disabled, it can only be suspended. Existing versions will remain\n even after suspension.\n </Trans>\n </p>\n\n <Checkbox\n checked={confirmed}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) => setConfirmed(e.target.checked)}\n label={t`I understand that enabling versioning is permanent`}\n disabled={enableMutation.isPending}\n />\n </Stack>\n </Modal>\n )\n}\n","import { Trans, useLingui } from \"@lingui/react/macro\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { Modal, Stack } from \"@cloudoperators/juno-ui-components\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport { useModalTracking } from \"@/client/hooks/useModalTracking\"\n\ninterface SuspendVersioningModalProps {\n isOpen: boolean\n bucketName: string\n onClose: () => void\n onSuccess?: (bucketName: string) => void\n onError?: (bucketName: string, errorMessage: string) => void\n}\n\nexport const SuspendVersioningModal = ({\n isOpen,\n bucketName,\n onClose,\n onSuccess,\n onError,\n}: SuspendVersioningModalProps) => {\n const { t } = useLingui()\n const projectId = useProjectId()\n\n const { trackClose, markSubmitted, resetTracking } = useModalTracking({\n isOpen,\n actionPrefix: \"storage.ceph.bucket.versioning.suspend\",\n })\n\n const utils = trpcReact.useUtils()\n\n const suspendMutation = trpcReact.storage.ceph.versioning.setStatus.useMutation({\n onSuccess: () => {\n utils.storage.ceph.versioning.getStatus.invalidate()\n onSuccess?.(bucketName)\n },\n onError: (error) => {\n onError?.(bucketName, error.message)\n },\n onSettled: () => {\n suspendMutation.reset()\n resetTracking()\n onClose()\n },\n })\n\n const handleClose = () => {\n trackClose()\n resetTracking()\n onClose()\n }\n\n const handleSuspend = () => {\n markSubmitted()\n suspendMutation.mutate({\n project_id: projectId,\n bucket: bucketName,\n status: \"Suspended\",\n })\n }\n\n if (!isOpen) return null\n\n return (\n <Modal\n title={t`Suspend Versioning`}\n open={isOpen}\n onCancel={handleClose}\n confirmButtonLabel={t`Suspend Versioning`}\n onConfirm={handleSuspend}\n cancelButtonLabel={t`Cancel`}\n disableConfirmButton={suspendMutation.isPending}\n >\n <Stack direction=\"vertical\" gap=\"4\">\n <div>\n <p className=\"mb-2 text-sm font-semibold\">\n <Trans>What happens when suspended:</Trans>\n </p>\n <ul className=\"list-disc space-y-1 pl-5 text-sm\">\n <li>\n <Trans>New uploads will overwrite the current version</Trans>\n </li>\n <li>\n <Trans>No new versions will be created</Trans>\n </li>\n <li>\n <Trans>Existing versions remain accessible</Trans>\n </li>\n <li>\n <Trans>You can re-enable versioning at any time</Trans>\n </li>\n </ul>\n </div>\n </Stack>\n </Modal>\n )\n}\n","import { useRef, useCallback, useMemo } from \"react\"\nimport { cn } from \"@/client/utils/cn\"\n\nexport interface JsonEditorProps {\n /** Current JSON string value */\n value: string\n /** Callback when value changes */\n onChange: (value: string) => void\n /** Callback when editor loses focus */\n onBlur?: () => void\n /** Whether the editor is disabled */\n disabled?: boolean\n /** Placeholder text when empty */\n placeholder?: string\n /** Error message to display (also shows error border) */\n error?: string | null\n /** Additional CSS class names (use height classes like h-96 to set fixed height) */\n className?: string\n /** HTML id attribute */\n id?: string\n /** HTML name attribute */\n name?: string\n /** Number of spaces for indentation (default: 2) */\n indentSize?: number\n /** Whether to show line numbers (default: true) */\n showLineNumbers?: boolean\n /** Test ID for testing */\n \"data-testid\"?: string\n}\n\n/**\n * A simple JSON editor component with line numbers and smart indentation.\n *\n * Features:\n * - Line numbers\n * - Tab key inserts spaces\n * - Enter key auto-indents based on context\n * - Closing braces/brackets auto-dedent\n * - Error state styling\n * - Accessible and keyboard-friendly\n */\nexport const JsonEditor = ({\n value,\n onChange,\n onBlur,\n disabled = false,\n placeholder = \"\",\n error,\n className = \"\",\n id,\n name,\n indentSize = 2,\n showLineNumbers = true,\n \"data-testid\": testId,\n}: JsonEditorProps) => {\n const textareaRef = useRef<HTMLTextAreaElement>(null)\n\n const indent = useMemo(() => \" \".repeat(indentSize), [indentSize])\n\n const handleChange = useCallback(\n (e: React.ChangeEvent<HTMLTextAreaElement>) => {\n onChange(e.target.value)\n },\n [onChange]\n )\n\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent<HTMLTextAreaElement>) => {\n if (disabled) return\n\n const textarea = textareaRef.current\n if (!textarea) return\n\n const start = textarea.selectionStart\n const end = textarea.selectionEnd\n\n if (e.key === \"Tab\") {\n e.preventDefault()\n\n if (e.shiftKey) {\n // Shift+Tab: dedent current line\n const lines = value.substring(0, start).split(\"\\n\")\n const currentLineStart = start - lines[lines.length - 1].length\n const currentLine = lines[lines.length - 1]\n\n if (currentLine.startsWith(indent)) {\n const newValue =\n value.substring(0, currentLineStart) + currentLine.substring(indentSize) + value.substring(start)\n onChange(newValue)\n setTimeout(() => {\n textarea.selectionStart = textarea.selectionEnd = start - indentSize\n }, 0)\n }\n } else {\n // Tab: insert indent\n const newValue = value.substring(0, start) + indent + value.substring(end)\n onChange(newValue)\n setTimeout(() => {\n textarea.selectionStart = textarea.selectionEnd = start + indentSize\n }, 0)\n }\n } else if (e.key === \"Enter\") {\n e.preventDefault()\n const lines = value.substring(0, start).split(\"\\n\")\n const currentLine = lines[lines.length - 1]\n const currentIndent = currentLine.match(/^\\s*/)?.[0] || \"\"\n\n let newIndent = currentIndent\n const trimmedLine = currentLine.trim()\n\n // Increase indent after opening brace/bracket\n if (trimmedLine.endsWith(\"{\") || trimmedLine.endsWith(\"[\")) {\n newIndent = currentIndent + indent\n }\n\n const newValue = value.substring(0, start) + \"\\n\" + newIndent + value.substring(end)\n onChange(newValue)\n\n setTimeout(() => {\n textarea.selectionStart = textarea.selectionEnd = start + 1 + newIndent.length\n }, 0)\n } else if (e.key === \"}\" || e.key === \"]\") {\n const lines = value.substring(0, start).split(\"\\n\")\n const currentLine = lines[lines.length - 1]\n\n // Auto-dedent when typing closing brace/bracket on whitespace-only line\n if (currentLine.match(/^\\s+$/) && currentLine.length >= indentSize) {\n e.preventDefault()\n const dedentedIndent = currentLine.substring(0, currentLine.length - indentSize)\n const beforeLine = value.substring(0, start - currentLine.length)\n const afterLine = value.substring(start)\n const newValue = beforeLine + dedentedIndent + e.key + afterLine\n onChange(newValue)\n\n setTimeout(() => {\n textarea.selectionStart = textarea.selectionEnd = start - currentLine.length + dedentedIndent.length + 1\n }, 0)\n }\n }\n },\n [disabled, value, onChange, indent, indentSize]\n )\n\n const lineNumbers = useMemo(() => {\n const count = Math.max(value.split(\"\\n\").length, 1)\n return Array.from({ length: count }, (_, i) => i + 1)\n }, [value])\n\n return (\n <div\n className={cn(\n \"bg-theme-background-lvl-1 overflow-hidden rounded border transition-[border-color,box-shadow] duration-150\",\n \"border-theme-background-lvl-3\",\n \"focus-within:border-theme-accent focus-within:ring-theme-accent focus-within:ring-2\",\n error && \"border-theme-error focus-within:ring-theme-error\",\n disabled && \"opacity-60\",\n className\n )}\n data-testid={testId}\n >\n <div className=\"flex h-full overflow-auto\">\n {showLineNumbers && (\n <div\n className=\"bg-theme-background-lvl-0 border-theme-background-lvl-3 text-theme-light shrink-0 border-r py-3 pr-3 pl-2 text-right font-mono text-xs leading-6 select-none\"\n style={{ minWidth: 40 }}\n aria-hidden=\"true\"\n data-testid={testId ? `${testId}-line-numbers` : undefined}\n >\n {lineNumbers.map((num) => (\n <div key={num}>{num}</div>\n ))}\n </div>\n )}\n\n <textarea\n ref={textareaRef}\n id={id}\n name={name}\n className={cn(\n \"text-theme-default min-w-0 flex-1 resize-none border-none bg-transparent p-3 font-mono text-xs leading-6 whitespace-pre outline-none\",\n \"placeholder:text-theme-light\",\n \"disabled:cursor-not-allowed\"\n )}\n style={{ overflowX: \"auto\", overflowY: \"hidden\", tabSize: 2 }}\n value={value}\n onChange={handleChange}\n onKeyDown={handleKeyDown}\n onBlur={onBlur}\n disabled={disabled}\n placeholder={placeholder}\n spellCheck={false}\n autoComplete=\"off\"\n autoCorrect=\"off\"\n autoCapitalize=\"off\"\n aria-invalid={!!error}\n aria-describedby={error && id ? `${id}-error` : undefined}\n data-testid={testId ? `${testId}-textarea` : undefined}\n />\n </div>\n {error && id && (\n <span id={`${id}-error`} className=\"sr-only\">\n {error}\n </span>\n )}\n </div>\n )\n}\n\nexport default JsonEditor\n","import { useEffect, useMemo } from \"react\"\nimport { z } from \"zod\"\nimport { useForm, useStore } from \"@tanstack/react-form\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { Modal, Stack, Select, SelectOption, Status, Message, Form } from \"@cloudoperators/juno-ui-components\"\nimport { JsonEditor } from \"@/client/components/JsonEditor\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport { useModalTracking } from \"@/client/hooks/useModalTracking\"\n\ninterface BucketPolicyModalProps {\n isOpen: boolean\n bucketName: string\n onClose: () => void\n onSuccess?: (bucketName: string, action: \"saved\" | \"deleted\") => void\n onError?: (bucketName: string, errorMessage: string, action: \"saved\" | \"deleted\") => void\n}\n\ninterface PolicyTemplate {\n label: string\n value: string\n generator: (bucketName: string) => object\n}\n\n// AWS/S3 Policy Version is NOT a creation date - it's the policy language version.\n// \"2012-10-17\" is the current (and recommended) version that supports all policy features.\n// Do not change this to a different date - S3 will reject or misinterpret the policy.\n// See: https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_version.html\nconst POLICY_TEMPLATES: PolicyTemplate[] = [\n {\n label: \"Public Read\",\n value: \"publicRead\",\n generator: (bucketName: string) => ({\n Version: \"2012-10-17\",\n Statement: [\n {\n Sid: \"PublicReadGetObject\",\n Effect: \"Allow\",\n Principal: \"*\",\n Action: \"s3:GetObject\",\n Resource: `arn:aws:s3:::${bucketName}/*`,\n },\n ],\n }),\n },\n {\n label: \"IP Restricted\",\n value: \"ipRestricted\",\n generator: (bucketName: string) => ({\n Version: \"2012-10-17\",\n Statement: [\n {\n Sid: \"IPRestrictedAccess\",\n Effect: \"Allow\",\n Principal: \"*\",\n Action: [\"s3:GetObject\", \"s3:PutObject\"],\n Resource: `arn:aws:s3:::${bucketName}/*`,\n Condition: {\n IpAddress: {\n \"aws:SourceIp\": \"192.168.0.0/16\",\n },\n },\n },\n ],\n }),\n },\n]\n\nconst MAX_POLICY_SIZE = 20480 // 20KB\n\nexport const BucketPolicyModal = ({ isOpen, bucketName, onClose, onSuccess, onError }: BucketPolicyModalProps) => {\n const { t } = useLingui()\n const projectId = useProjectId()\n const utils = trpcReact.useUtils()\n\n const { trackClose, markSubmitted, resetTracking } = useModalTracking({\n isOpen,\n actionPrefix: \"storage.ceph.bucket.policy\",\n })\n\n // Form schema - only validates JSON syntax and size, backend handles policy structure validation\n // Empty string is allowed (will trigger delete)\n const formSchema = z.object({\n policyText: z\n .string()\n .max(MAX_POLICY_SIZE, t`Policy document exceeds maximum size of 20KB`)\n .refine(\n (value) => {\n if (!value.trim()) return true // Empty is valid (will delete policy)\n try {\n JSON.parse(value)\n return true\n } catch {\n return false\n }\n },\n { message: t`Invalid JSON format` }\n ),\n selectedTemplate: z.string(),\n })\n\n // Query to fetch existing policy\n const {\n data: policyData,\n isLoading: isPolicyLoading,\n error: policyError,\n } = trpcReact.storage.ceph.bucketPolicy.get.useQuery(\n {\n project_id: projectId,\n bucketName,\n },\n {\n enabled: isOpen && !!projectId,\n retry: false,\n }\n )\n\n // Set mutation\n const setMutation = trpcReact.storage.ceph.bucketPolicy.set.useMutation({\n onSuccess: () => {\n utils.storage.ceph.bucketPolicy.get.invalidate()\n onSuccess?.(bucketName, \"saved\")\n handleClose()\n },\n onError: (error) => {\n onError?.(bucketName, error.message, \"saved\")\n },\n })\n\n // Delete mutation (for when policy is cleared)\n const deleteMutation = trpcReact.storage.ceph.bucketPolicy.delete.useMutation({\n onSuccess: () => {\n utils.storage.ceph.bucketPolicy.get.invalidate()\n onSuccess?.(bucketName, \"deleted\")\n handleClose()\n },\n onError: (error) => {\n onError?.(bucketName, error.message, \"deleted\")\n },\n })\n\n const form = useForm({\n defaultValues: {\n policyText: \"\",\n selectedTemplate: \"\",\n },\n validators: {\n onSubmit: formSchema,\n },\n onSubmit: async ({ value }) => {\n markSubmitted()\n if (!value.policyText.trim()) {\n // Empty policy = delete\n deleteMutation.mutate({\n project_id: projectId,\n bucketName,\n })\n } else {\n setMutation.mutate({\n project_id: projectId,\n bucketName,\n policy: value.policyText,\n })\n }\n },\n })\n\n // Check if a policy matches one of the predefined templates\n const findMatchingTemplate = (policyText: string): string => {\n try {\n const policy = JSON.parse(policyText)\n for (const template of POLICY_TEMPLATES) {\n const templatePolicy = template.generator(bucketName)\n if (JSON.stringify(policy) === JSON.stringify(templatePolicy)) {\n return template.value\n }\n }\n } catch {\n // Invalid JSON, no match\n }\n return \"\"\n }\n\n // Load policy data into form when modal opens or data changes\n useEffect(() => {\n if (!isOpen) return\n\n if (policyData?.policyText) {\n try {\n const parsed = JSON.parse(policyData.policyText)\n const formatted = JSON.stringify(parsed, null, 2)\n form.setFieldValue(\"policyText\", formatted)\n // Check if the loaded policy matches a template\n const matchingTemplate = findMatchingTemplate(policyData.policyText)\n form.setFieldValue(\"selectedTemplate\", matchingTemplate)\n } catch {\n form.setFieldValue(\"policyText\", policyData.policyText)\n form.setFieldValue(\"selectedTemplate\", \"\")\n }\n } else if (policyData?.policy === null) {\n form.setFieldValue(\"policyText\", \"\")\n form.setFieldValue(\"selectedTemplate\", \"\")\n }\n }, [isOpen, policyData, form, bucketName])\n\n const handleClose = () => {\n trackClose()\n form.reset()\n setMutation.reset()\n deleteMutation.reset()\n resetTracking()\n onClose()\n }\n\n const handleTemplateChange = (value: string | number | string[] | undefined) => {\n const templateValue = typeof value === \"string\" ? value : \"\"\n form.setFieldValue(\"selectedTemplate\", templateValue)\n\n if (!templateValue) return\n\n const template = POLICY_TEMPLATES.find((t) => t.value === templateValue)\n if (template) {\n const policy = template.generator(bucketName)\n form.setFieldValue(\"policyText\", JSON.stringify(policy, null, 2))\n }\n }\n\n // Subscribe to form state for reactivity\n const isSubmitting = useStore(form.store, (state) => state.isSubmitting)\n const policyTextValue = useStore(form.store, (state) => state.values.policyText)\n const selectedTemplateValue = useStore(form.store, (state) => state.values.selectedTemplate)\n\n const policySize = useMemo(() => {\n return new Blob([policyTextValue]).size\n }, [policyTextValue])\n\n // Compare current value with original to detect changes\n const originalPolicyText = useMemo(() => {\n if (!policyData?.policyText) return \"\"\n try {\n const parsed = JSON.parse(policyData.policyText)\n return JSON.stringify(parsed, null, 2)\n } catch {\n return policyData.policyText\n }\n }, [policyData?.policyText])\n\n const hasChanges = policyTextValue !== originalPolicyText\n\n // Validate JSON syntax only - backend handles policy structure validation\n const jsonSyntaxError = useMemo(() => {\n if (!policyTextValue.trim()) return null\n try {\n JSON.parse(policyTextValue)\n return null\n } catch (error) {\n if (error instanceof SyntaxError) {\n return error.message\n }\n return \"Invalid JSON\"\n }\n }, [policyTextValue])\n\n const isSaving = setMutation.isPending || deleteMutation.isPending || isSubmitting\n const canSubmit = !isSaving && !jsonSyntaxError && policySize <= MAX_POLICY_SIZE && hasChanges\n\n const handleSave = () => {\n form.handleSubmit()\n }\n\n if (!isOpen) return null\n\n return (\n <Modal\n key={bucketName} // Remount when bucket changes\n title={t`Edit/View Bucket Policy`}\n open={isOpen}\n onCancel={handleClose}\n confirmButtonLabel={t`Save`}\n onConfirm={handleSave}\n cancelButtonLabel={t`Cancel`}\n disableConfirmButton={!canSubmit}\n size=\"large\"\n >\n <Stack direction=\"vertical\" gap=\"4\">\n {isPolicyLoading && <Status status=\"progress\" title={t`Loading Policy...`} className=\"mt-0\" />}\n\n {policyError && (\n <Status status=\"error\" title={t`Failed to Load Policy`} body={policyError.message} className=\"mt-0\" />\n )}\n\n {setMutation.error && (\n <Message variant=\"error\" title={t`Failed to Save Policy`}>\n {setMutation.error.message}\n </Message>\n )}\n\n {deleteMutation.error && (\n <Message variant=\"error\" title={t`Failed to Delete Policy`}>\n {deleteMutation.error.message}\n </Message>\n )}\n\n {!isPolicyLoading && !policyError && (\n <Form\n onSubmit={(e) => {\n e.preventDefault()\n form.handleSubmit()\n }}\n >\n <Stack direction=\"vertical\" gap=\"4\">\n <div>\n <p className=\"mb-2\">\n <Trans>Define permissions for this bucket. You may use one of the predefined templates.</Trans>\n </p>\n <p>\n <Trans>Leaving the JSON field empty will remove the policy from the bucket.</Trans>\n </p>\n </div>\n\n <Select\n label={t`Policy Templates`}\n value={selectedTemplateValue}\n onChange={handleTemplateChange}\n disabled={isSaving}\n >\n <SelectOption value=\"\" label={t`Select a template...`} />\n {POLICY_TEMPLATES.map((template) => (\n <SelectOption\n key={template.value}\n value={template.value}\n label={template.value === \"publicRead\" ? t`Public Read` : t`IP Restricted`}\n />\n ))}\n </Select>\n\n <div>\n <form.Field\n name=\"policyText\"\n children={(field) => (\n <>\n <label htmlFor={field.name} className=\"juno-label mb-1.5\">\n <Trans>Policy JSON</Trans>\n </label>\n <JsonEditor\n id={field.name}\n name={field.name}\n value={field.state.value}\n onChange={field.handleChange}\n onBlur={field.handleBlur}\n className=\"h-96\"\n disabled={isSaving}\n placeholder={t`Enter bucket policy JSON...`}\n error={jsonSyntaxError}\n />\n <div className=\"mt-1 flex items-center justify-between text-xs\">\n <span className={policySize > MAX_POLICY_SIZE ? \"text-theme-error\" : \"text-theme-light\"}>\n <Trans>\n Size: {policySize} / {MAX_POLICY_SIZE} bytes\n </Trans>\n </span>\n {jsonSyntaxError && <span className=\"text-theme-error\">{jsonSyntaxError}</span>}\n </div>\n </>\n )}\n />\n </div>\n </Stack>\n </Form>\n )}\n </Stack>\n </Modal>\n )\n}\n","import { useEffect } from \"react\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { Modal, Stack, Status, Message } from \"@cloudoperators/juno-ui-components\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport { useModalTracking } from \"@/client/hooks/useModalTracking\"\n\ninterface DeleteBucketPolicyModalProps {\n isOpen: boolean\n bucketName: string\n onClose: () => void\n onSuccess?: (bucketName: string) => void\n onError?: (bucketName: string, errorMessage: string) => void\n}\n\nexport const DeleteBucketPolicyModal = ({\n isOpen,\n bucketName,\n onClose,\n onSuccess,\n onError,\n}: DeleteBucketPolicyModalProps) => {\n const { t } = useLingui()\n const projectId = useProjectId()\n const utils = trpcReact.useUtils()\n\n const { trackClose, markSubmitted, resetTracking } = useModalTracking({\n isOpen,\n actionPrefix: \"storage.ceph.bucket.policy.delete\",\n })\n\n // Query to verify policy exists\n const {\n data: policyData,\n isLoading: isPolicyLoading,\n error: policyError,\n } = trpcReact.storage.ceph.bucketPolicy.get.useQuery(\n {\n project_id: projectId,\n bucketName,\n },\n {\n enabled: isOpen && !!projectId,\n retry: false,\n }\n )\n\n // Delete mutation\n const deleteMutation = trpcReact.storage.ceph.bucketPolicy.delete.useMutation({\n onSuccess: () => {\n utils.storage.ceph.bucketPolicy.get.invalidate()\n const name = bucketName\n onSuccess?.(name)\n handleClose()\n },\n onError: (error) => {\n const name = bucketName\n onError?.(name, error.message)\n },\n })\n\n useEffect(() => {\n if (!isOpen) {\n deleteMutation.reset()\n resetTracking()\n }\n }, [isOpen, bucketName])\n\n const handleClose = () => {\n trackClose()\n deleteMutation.reset()\n resetTracking()\n onClose()\n }\n\n const handleDelete = () => {\n markSubmitted()\n deleteMutation.mutate({\n project_id: projectId,\n bucketName,\n })\n }\n\n if (!isOpen) return null\n\n const hasPolicy = !!policyData?.policy\n const isDeleting = deleteMutation.isPending\n\n return (\n <Modal\n title={t`Delete Bucket Policy`}\n open={isOpen}\n onCancel={handleClose}\n confirmButtonLabel={t`Delete Policy`}\n confirmButtonVariant=\"primary-danger\"\n onConfirm={handleDelete}\n cancelButtonLabel={t`Cancel`}\n size=\"small\"\n disableConfirmButton={isDeleting || isPolicyLoading || !hasPolicy || !!policyError}\n >\n <Stack direction=\"vertical\" gap=\"4\">\n {isPolicyLoading && <Status status=\"progress\" title={t`Loading Policy...`} className=\"mt-0\" />}\n\n {policyError && (\n <Status status=\"error\" title={t`Failed to Load Policy`} body={policyError.message} className=\"mt-0\" />\n )}\n\n {!isPolicyLoading && !policyError && !hasPolicy && (\n <Status\n status=\"empty\"\n title={t`No Policy Found`}\n body={t`This bucket does not have a policy attached.`}\n className=\"mt-0\"\n />\n )}\n\n {!isPolicyLoading && !policyError && hasPolicy && (\n <>\n <p className=\"text-theme-default\">\n <Trans>\n Are you sure you want to delete the policy for bucket <strong>{bucketName}</strong>?\n </Trans>\n </p>\n <p className=\"text-theme-default\">\n <Trans>\n Deleting the policy will remove all access restrictions defined by it. This action cannot be undone.\n </Trans>\n </p>\n </>\n )}\n\n {deleteMutation.isError && (\n <Message variant=\"error\" title={t`Failed to delete policy`}>\n {deleteMutation.error?.message}\n </Message>\n )}\n </Stack>\n </Modal>\n )\n}\n","import type { S3ObjectVersion } from \"@/server/Storage/types/ceph\"\n\n/**\n * Helper to calculate bucket state from versioning data\n *\n * @param allVersions - All versions/objects from the list query with showVersions=true\n * @param isVersioningEnabled - Whether bucket has versioning Enabled or Suspended\n * @param bucketObjectCount - Object count from bucket metadata (may be 0 even with objects due to how S3 counts)\n * @returns Calculated state flags for bucket emptiness and version status\n */\nexport function calculateBucketState(\n allVersions: S3ObjectVersion[],\n isVersioningEnabled: boolean,\n bucketObjectCount: number\n) {\n // Current objects = isLatest=true and not delete markers\n const currentVersions = allVersions.filter((v) => v.isLatest && !v.isDeleteMarker)\n\n // Real versions (not delete markers) - includes both current and old\n const realVersions = allVersions.filter((v) => !v.isDeleteMarker)\n\n // Check if there are ONLY delete markers (no real objects/versions at all)\n const hasOnlyDeleteMarkers = isVersioningEnabled && allVersions.length > 0 && realVersions.length === 0\n\n // Check if there are old versions (not current) or any delete markers\n // Used to determine if \"Delete Versions\" action is needed\n const hasOldVersionsOrDeleteMarkers =\n isVersioningEnabled && allVersions.some((v) => v.isDeleteMarker || (!v.isLatest && !v.isDeleteMarker))\n\n // Count current objects for bucket emptiness check\n // - For versioned buckets: use bucketObjectCount from metadata OR count current versions if metadata is 0\n // - For unversioned buckets: count all real versions (they are all current)\n const effectiveCurrentObjectCount = isVersioningEnabled\n ? bucketObjectCount > 0\n ? bucketObjectCount\n : currentVersions.length\n : bucketObjectCount + realVersions.length\n\n // Bucket is empty only if there are no current objects\n const isBucketEmpty = effectiveCurrentObjectCount === 0\n\n return {\n currentVersions,\n hasOnlyDeleteMarkers,\n hasOldVersionsOrDeleteMarkers,\n effectiveCurrentObjectCount,\n isBucketEmpty,\n }\n}\n","import { useState } from \"react\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport {\n Modal,\n ModalFooter,\n Button,\n ButtonRow,\n TextInput,\n Stack,\n Checkbox,\n Status,\n} from \"@cloudoperators/juno-ui-components\"\nimport { Bucket } from \"@/server/Storage/types/ceph\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport { calculateBucketState } from \"../hooks/bucketStateHelpers\"\nimport { useModalTracking } from \"@/client/hooks/useModalTracking\"\n\ninterface EmptyBucketModalProps {\n isOpen: boolean\n bucket: Bucket | null\n onClose: () => void\n onSuccess?: (bucketName: string, deletedCount: number) => void\n onError?: (bucketName: string, errorMessage: string) => void\n}\n\nexport const EmptyBucketModal = ({ isOpen, bucket, onClose, onSuccess, onError }: EmptyBucketModalProps) => {\n const { t } = useLingui()\n const projectId = useProjectId()\n const [confirmName, setConfirmName] = useState(\"\")\n const [nameError, setNameError] = useState<string | null>(null)\n const [deleteVersionsAndMarkers, setDeleteVersionsAndMarkers] = useState(false)\n\n const { trackClose, markSubmitted, resetTracking } = useModalTracking({\n isOpen,\n actionPrefix: \"storage.ceph.bucket.empty\",\n })\n\n const utils = trpcReact.useUtils()\n\n // Query versioning status for the bucket\n const {\n data: versioningStatus,\n isLoading: isLoadingVersioning,\n error: versioningError,\n } = trpcReact.storage.ceph.versioning.getStatus.useQuery(\n {\n project_id: projectId ?? \"\",\n bucket: bucket?.name ?? \"\",\n },\n {\n enabled: !!projectId && !!bucket && isOpen,\n // App-wide default staleTime is 60s (see App.tsx) — override it so every\n // open of this modal re-verifies live instead of serving cached data.\n staleTime: 0,\n }\n )\n\n // Query to check if bucket has versions/delete markers. Always runs (regardless of\n // versioning status) to get accurate live data for the truly-empty check below —\n // bucket.count from the list cache can be stale.\n // Use maxKeys=100 to get enough data - with maxKeys=1 we might miss current objects\n // if the first result is a delete marker\n const {\n data: versionCheckData,\n isLoading: isLoadingVersionCheck,\n error: versionCheckError,\n } = trpcReact.storage.ceph.objects.list.useQuery(\n {\n project_id: projectId ?? \"\",\n containerName: bucket?.name ?? \"\",\n maxKeys: 100,\n delimiter: \"\",\n showVersions: true,\n },\n {\n enabled: !!projectId && !!bucket && isOpen,\n // App-wide default staleTime is 60s (see App.tsx) — override it so every\n // open of this modal re-verifies live instead of serving cached data.\n staleTime: 0,\n }\n )\n\n // Check bucket state using shared helper. Pass 0 instead of bucket.count (list-cache\n // metadata, can be stale) — this modal exists specifically to be the live, authoritative\n // check, so it must rely on allVersions from the fresh query above, not the cached count.\n const isVersioningEnabled = versioningStatus?.status === \"Enabled\" || versioningStatus?.status === \"Suspended\"\n const allVersions = versionCheckData?.versions ?? []\n const { isBucketEmpty, hasOnlyDeleteMarkers, hasOldVersionsOrDeleteMarkers } = calculateBucketState(\n allVersions,\n isVersioningEnabled,\n 0\n )\n // objects.list only returns the first page (maxKeys: 100). If it's truncated, allVersions\n // is incomplete and can't be trusted to classify the bucket as empty/delete-markers-only —\n // fall back to the standard destructive form instead of risking a wrong \"safe\" branch.\n const isVersionDataComplete = !versionCheckData?.isTruncated\n const isBucketEmptyWithVersions = isVersionDataComplete && isBucketEmpty && hasOnlyDeleteMarkers\n // Bucket has zero current objects AND zero versions/delete markers of any kind —\n // genuinely nothing to empty (unlike isBucketEmptyWithVersions, which still has\n // delete markers to clean up). Distinct render branch below shows an info-only view.\n const isTrulyEmpty = isVersionDataComplete && isBucketEmpty && !hasOldVersionsOrDeleteMarkers\n\n const emptyBucketMutation = trpcReact.storage.ceph.objects.deleteAll.useMutation({\n onSettled: () => {\n // Invalidate both containers.list (to update bucket metadata) and objects.list (to refresh empty state)\n utils.storage.ceph.containers.list.invalidate()\n utils.storage.ceph.objects.list.invalidate()\n handleClose()\n },\n })\n\n const handleClose = () => {\n trackClose()\n setConfirmName(\"\")\n setNameError(null)\n setDeleteVersionsAndMarkers(false)\n emptyBucketMutation.reset()\n resetTracking()\n onClose()\n }\n\n const handleConfirmNameChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const value = e.target.value\n setConfirmName(value)\n if (nameError) setNameError(null)\n }\n\n const handleSubmit = () => {\n if (!bucket) return\n if (confirmName.trim() !== bucket.name) {\n setNameError(t`Bucket name does not match`)\n return\n }\n\n markSubmitted()\n\n // Capture bucket name before async operation to avoid dereferencing null bucket in callbacks\n const bucketName = bucket.name\n\n // If bucket is empty with only delete markers, always delete versions\n const shouldDeleteVersions = isBucketEmptyWithVersions || deleteVersionsAndMarkers\n\n emptyBucketMutation.mutate(\n {\n project_id: projectId,\n containerName: bucketName,\n includeVersionsAndDeleteMarkers: shouldDeleteVersions,\n },\n {\n onSuccess: (deletedCount) => {\n onSuccess?.(bucketName, deletedCount)\n },\n onError: (error) => {\n onError?.(bucketName, error.message)\n },\n }\n )\n }\n\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === \"Enter\") handleSubmit()\n }\n\n if (!isOpen || !bucket) return null\n\n const bucketName = bucket.name\n const isLoading = isLoadingVersioning || isLoadingVersionCheck\n const hasQueryError = !!versioningError || !!versionCheckError\n\n // If bucket is empty with only delete markers, show \"Delete Versions\" UI\n if (isBucketEmptyWithVersions && !isLoading) {\n return (\n <Modal\n title={t`Delete Versions`}\n open={isOpen}\n onCancel={handleClose}\n confirmButtonLabel={t`Delete Versions`}\n confirmButtonVariant=\"primary-danger\"\n onConfirm={handleSubmit}\n cancelButtonLabel={t`Cancel`}\n size=\"small\"\n disableConfirmButton={emptyBucketMutation.isPending || confirmName.trim() !== bucket.name || hasQueryError}\n >\n <Stack direction=\"vertical\" gap=\"6\">\n {hasQueryError && (\n <div className=\"bg-theme-danger-10 text-theme-danger rounded p-4\">\n <Trans>Unable to verify bucket versioning status. Please try again.</Trans>\n </div>\n )}\n\n <p className=\"text-theme-default m-0\">\n <Trans>\n This action will permanently delete all versions and delete markers. This will enable you to delete the\n bucket. This action cannot be undone.\n </Trans>\n </p>\n\n <TextInput\n label={t`Type the bucket name to confirm`}\n required\n value={confirmName}\n onChange={handleConfirmNameChange}\n onKeyDown={handleKeyDown}\n invalid={!!nameError}\n errortext={nameError || undefined}\n disabled={emptyBucketMutation.isPending || hasQueryError}\n placeholder={bucket.name}\n autoFocus\n />\n </Stack>\n </Modal>\n )\n }\n\n // Bucket is genuinely empty — nothing to delete, show an info-only view\n if (isTrulyEmpty && !isLoading) {\n return (\n <Modal\n title={t`Empty Bucket`}\n open={isOpen}\n onCancel={handleClose}\n size=\"small\"\n modalFooter={\n <ModalFooter className=\"flex justify-end\">\n <ButtonRow>\n <Button variant=\"primary\" onClick={handleClose} data-testid=\"empty-info-close-button\">\n <Trans>Close</Trans>\n </Button>\n </ButtonRow>\n </ModalFooter>\n }\n >\n {hasQueryError ? (\n <div className=\"bg-theme-danger-10 text-theme-danger rounded p-4\">\n {versioningError && versionCheckError ? (\n <Trans>Unable to verify bucket versioning status and contents. Please try again.</Trans>\n ) : versioningError ? (\n <Trans>Unable to verify bucket versioning status. Please try again.</Trans>\n ) : (\n <Trans>Unable to verify bucket contents. Please try again.</Trans>\n )}\n </div>\n ) : (\n <p className=\"text-theme-default py-2\">\n <Trans>This bucket is already empty.</Trans>\n </p>\n )}\n </Modal>\n )\n }\n\n // Otherwise show normal \"Empty Bucket\" UI\n return (\n <Modal\n title={t`Empty Bucket`}\n open={isOpen}\n onCancel={handleClose}\n confirmButtonLabel={t`Empty Bucket`}\n confirmButtonVariant=\"primary-danger\"\n onConfirm={handleSubmit}\n cancelButtonLabel={t`Cancel`}\n size=\"small\"\n disableConfirmButton={emptyBucketMutation.isPending || confirmName.trim() !== bucket.name || hasQueryError}\n >\n {isLoading ? (\n <Status status=\"progress\" title={t`Checking Bucket Contents...`} className=\"mt-0\" />\n ) : (\n <Stack direction=\"vertical\" gap=\"6\">\n {hasQueryError && (\n <div className=\"bg-theme-danger-10 text-theme-danger rounded p-4\">\n <Trans>Unable to verify bucket versioning status. Please try again.</Trans>\n </div>\n )}\n\n <p className=\"text-theme-default m-0\">\n {versioningStatus && versioningStatus.status !== \"Unversioned\" ? (\n <Trans>\n This action will permanently delete all objects from {bucketName}. You may choose to also delete all\n versions and delete markers. This will enable you to delete the bucket. This action cannot be undone.\n </Trans>\n ) : (\n <Trans>\n This action will permanently delete all objects from {bucketName}. This action cannot be undone.\n </Trans>\n )}\n </p>\n\n {versioningStatus && versioningStatus.status !== \"Unversioned\" && (\n <Checkbox\n checked={deleteVersionsAndMarkers}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) => setDeleteVersionsAndMarkers(e.target.checked)}\n label={t`Also delete all versions and all delete markers`}\n disabled={emptyBucketMutation.isPending || hasQueryError}\n />\n )}\n\n <TextInput\n label={t`Type the bucket name to confirm`}\n required\n value={confirmName}\n onChange={handleConfirmNameChange}\n onKeyDown={handleKeyDown}\n invalid={!!nameError}\n errortext={nameError || undefined}\n disabled={emptyBucketMutation.isPending || hasQueryError}\n placeholder={bucket.name}\n autoFocus\n />\n </Stack>\n )}\n </Modal>\n )\n}\n","import { useState, useEffect } from \"react\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { Modal, ModalFooter, ButtonRow, TextInput, Stack, Status, Button } from \"@cloudoperators/juno-ui-components\"\nimport type { Bucket } from \"@/server/Storage/types/ceph\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport { calculateBucketState } from \"../hooks/bucketStateHelpers\"\nimport { useModalTracking } from \"@/client/hooks/useModalTracking\"\n\ninterface DeleteBucketModalProps {\n isOpen: boolean\n bucket: Bucket | null\n onClose: () => void\n onSuccess?: (bucketName: string) => void\n onError?: (bucketName: string, errorMessage: string) => void\n}\n\nexport const DeleteBucketModal = ({ isOpen, bucket, onClose, onSuccess, onError }: DeleteBucketModalProps) => {\n const { t } = useLingui()\n const projectId = useProjectId()\n const [confirmName, setConfirmName] = useState(\"\")\n const [nameError, setNameError] = useState<string | null>(null)\n\n const { trackClose, markSubmitted, resetTracking } = useModalTracking({\n isOpen,\n actionPrefix: \"storage.ceph.bucket.delete\",\n })\n\n const utils = trpcReact.useUtils()\n\n // Fetch versioning status to determine if bucket has versioning enabled\n const { data: versioningStatus, isLoading: isLoadingVersioning } =\n trpcReact.storage.ceph.versioning.getStatus.useQuery(\n { project_id: projectId ?? \"\", bucket: bucket?.name ?? \"\" },\n { enabled: isOpen && bucket !== null }\n )\n\n const isVersioningEnabled = versioningStatus?.status === \"Enabled\" || versioningStatus?.status === \"Suspended\"\n\n // Fetch actual objects and versions to get accurate real-time state\n // Use showVersions=true to also detect delete markers in versioned buckets\n // Use delimiter=\"\" to get ALL objects including folder markers (zero-byte objects ending in \"/\")\n // Without this, folders are returned as CommonPrefixes and we can't accurately check if bucket is empty\n // Use maxKeys=100 to get enough objects/versions to accurately determine bucket state\n // (with maxKeys=1 we might miss current objects if the first result is a delete marker)\n const {\n data: objects,\n isLoading: isLoadingObjects,\n error: objectsError,\n } = trpcReact.storage.ceph.objects.list.useQuery(\n { project_id: projectId ?? \"\", containerName: bucket?.name ?? \"\", maxKeys: 100, delimiter: \"\", showVersions: true },\n { enabled: isOpen && bucket !== null }\n )\n\n const deleteBucketMutation = trpcReact.storage.ceph.containers.delete.useMutation({\n onSettled: () => {\n utils.storage.ceph.containers.list.invalidate()\n },\n })\n\n useEffect(() => {\n if (!isOpen) {\n setConfirmName(\"\")\n setNameError(null)\n deleteBucketMutation.reset()\n resetTracking()\n }\n }, [isOpen, bucket?.name])\n\n const handleClose = () => {\n setConfirmName(\"\")\n setNameError(null)\n deleteBucketMutation.reset()\n resetTracking()\n onClose()\n }\n\n const handleConfirmNameChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const value = e.target.value\n setConfirmName(value)\n if (nameError) setNameError(null)\n }\n\n const handleSubmit = () => {\n if (!bucket) return\n if (objectsError) return\n if (confirmName.trim() !== bucket.name) {\n setNameError(t`Bucket name does not match`)\n return\n }\n\n markSubmitted()\n\n // Capture bucket name before async operation to avoid dereferencing null bucket in callbacks\n const bucketName = bucket.name\n\n deleteBucketMutation.mutate(\n { project_id: projectId, bucketName },\n {\n onSuccess: () => {\n handleClose()\n onSuccess?.(bucketName)\n },\n onError: (error) => {\n handleClose()\n onError?.(bucketName, error.message)\n },\n }\n )\n }\n\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === \"Enter\") handleSubmit()\n }\n\n if (!isOpen || !bucket) return null\n\n // Calculate bucket state using shared helper\n // When showVersions=true, BFF returns all objects in \"versions\" array, not \"objects\"\n // So bucketObjectCount from objects?.objects is used only as a fallback\n const currentObjectCount = objects?.objects?.length ?? 0\n const allVersions = objects?.versions ?? []\n const { effectiveCurrentObjectCount, hasOldVersionsOrDeleteMarkers } = calculateBucketState(\n allVersions,\n isVersioningEnabled,\n currentObjectCount\n )\n\n // Bucket cannot be deleted if it has:\n // 1. Current objects (effectiveCurrentObjectCount > 0) - show \"Empty the bucket\"\n // 2. Old versions or any delete markers in a versioned bucket - show \"Delete all versions\"\n const hasCurrentObjects = effectiveCurrentObjectCount > 0\n const hasVersionsInVersionedBucket = hasOldVersionsOrDeleteMarkers\n const cannotDelete = hasCurrentObjects || hasVersionsInVersionedBucket\n const errorMessage = objectsError?.message\n const isLoading = isLoadingObjects || isLoadingVersioning\n\n return (\n <Modal\n title={t`Delete Bucket`}\n open={isOpen}\n onCancel={() => {\n trackClose()\n handleClose()\n }}\n confirmButtonLabel={cannotDelete ? undefined : t`Delete Bucket`}\n confirmButtonVariant={cannotDelete ? undefined : \"primary-danger\"}\n onConfirm={cannotDelete ? undefined : handleSubmit}\n cancelButtonLabel={cannotDelete ? undefined : t`Cancel`}\n modalFooter={\n cannotDelete ? (\n <ModalFooter className=\"flex justify-end\">\n <ButtonRow>\n <Button variant=\"primary\" onClick={handleClose} data-testid=\"delete-has-objects-close-button\">\n <Trans>Close</Trans>\n </Button>\n </ButtonRow>\n </ModalFooter>\n ) : undefined\n }\n size=\"small\"\n disableConfirmButton={\n deleteBucketMutation.isPending || isLoading || !!objectsError || confirmName.trim() !== bucket.name\n }\n >\n <Stack direction=\"vertical\" gap=\"6\">\n {objectsError && (\n <Status status=\"error\" title={t`Failed to Check Bucket Contents`} body={errorMessage} className=\"mt-0\" />\n )}\n\n {isLoading ? (\n <Status status=\"progress\" title={t`Checking Bucket Contents...`} className=\"mt-0\" />\n ) : cannotDelete ? (\n <div className=\"text-theme-default\">\n <p className=\"mb-4\">\n <Trans>This bucket cannot be deleted yet. Do the following to be able to delete the bucket:</Trans>\n </p>\n <ul className=\"list-disc space-y-1 pl-5\">\n {hasCurrentObjects && (\n <li>\n <Trans>Empty the bucket</Trans>\n </li>\n )}\n {hasVersionsInVersionedBucket && (\n <li>\n <Trans>Delete all versions and delete markers</Trans>\n </li>\n )}\n </ul>\n </div>\n ) : (\n <>\n <p className=\"text-theme-default\">\n <Trans>\n This action is irreversible. Deleting a bucket permanently removes it and cannot be undone. The bucket\n must be empty before deletion.\n </Trans>\n </p>\n\n <TextInput\n label={t`Type the bucket name to confirm`}\n required\n value={confirmName}\n onChange={handleConfirmNameChange}\n onKeyDown={handleKeyDown}\n invalid={!!nameError}\n errortext={nameError || undefined}\n disabled={deleteBucketMutation.isPending}\n placeholder={bucket.name}\n />\n </>\n )}\n </Stack>\n </Modal>\n )\n}\n","import { useState } from \"react\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { Modal, TextInput, Stack } from \"@cloudoperators/juno-ui-components\"\nimport { Bucket } from \"@/server/Storage/types/ceph\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport { useModalTracking } from \"@/client/hooks/useModalTracking\"\n\ninterface DeleteVersionsModalProps {\n isOpen: boolean\n bucket: Bucket | null\n onClose: () => void\n onSuccess?: (bucketName: string, deletedCount: number) => void\n onError?: (bucketName: string, errorMessage: string) => void\n}\n\nexport const DeleteVersionsModal = ({ isOpen, bucket, onClose, onSuccess, onError }: DeleteVersionsModalProps) => {\n const { t } = useLingui()\n const projectId = useProjectId()\n const [confirmName, setConfirmName] = useState(\"\")\n const [nameError, setNameError] = useState<string | null>(null)\n\n const { trackClose, markSubmitted, resetTracking } = useModalTracking({\n isOpen,\n actionPrefix: \"storage.ceph.bucket.versions.delete\",\n })\n\n const utils = trpcReact.useUtils()\n\n const deleteVersionsMutation = trpcReact.storage.ceph.objects.deleteAll.useMutation({\n onSettled: () => {\n // Invalidate both containers.list (to update bucket metadata) and objects.list (to refresh empty state)\n utils.storage.ceph.containers.list.invalidate()\n utils.storage.ceph.objects.list.invalidate()\n handleClose()\n },\n })\n\n const handleClose = () => {\n trackClose()\n setConfirmName(\"\")\n setNameError(null)\n deleteVersionsMutation.reset()\n resetTracking()\n onClose()\n }\n\n const handleConfirmNameChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const value = e.target.value\n setConfirmName(value)\n if (nameError) setNameError(null)\n }\n\n const handleSubmit = () => {\n if (!bucket) return\n if (confirmName.trim() !== bucket.name) {\n setNameError(t`Bucket name does not match`)\n return\n }\n\n markSubmitted()\n\n // Capture bucket name before async operation to avoid dereferencing null bucket in callbacks\n const bucketName = bucket.name\n\n // Always delete all versions and delete markers (includeVersionsAndDeleteMarkers: true)\n deleteVersionsMutation.mutate(\n {\n project_id: projectId,\n containerName: bucketName,\n includeVersionsAndDeleteMarkers: true,\n },\n {\n onSuccess: (deletedCount) => {\n onSuccess?.(bucketName, deletedCount)\n },\n onError: (error) => {\n onError?.(bucketName, error.message)\n },\n }\n )\n }\n\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === \"Enter\") handleSubmit()\n }\n\n if (!isOpen || !bucket) return null\n\n return (\n <Modal\n title={t`Delete Versions`}\n open={isOpen}\n onCancel={handleClose}\n confirmButtonLabel={t`Delete Versions`}\n confirmButtonVariant=\"primary-danger\"\n onConfirm={handleSubmit}\n cancelButtonLabel={t`Cancel`}\n size=\"small\"\n disableConfirmButton={deleteVersionsMutation.isPending || confirmName.trim() !== bucket.name}\n >\n <Stack direction=\"vertical\" gap=\"6\">\n <p className=\"text-theme-default m-0\">\n <Trans>\n This action will permanently delete all versions and delete markers. This will enable you to delete the\n bucket. This action cannot be undone.\n </Trans>\n </p>\n\n <TextInput\n label={t`Type the bucket name to confirm`}\n required\n value={confirmName}\n onChange={handleConfirmNameChange}\n onKeyDown={handleKeyDown}\n invalid={!!nameError}\n errortext={nameError || undefined}\n disabled={deleteVersionsMutation.isPending}\n placeholder={bucket.name}\n autoFocus\n className=\"overflow-x-hidden [overflow-wrap:anywhere]\"\n />\n </Stack>\n </Modal>\n )\n}\n","/**\n * Prefix encoding utilities for S3/Swift object storage\n *\n * Handles base64 encoding/decoding of folder prefixes to safely carry \"/\" chars in URLs.\n */\n\nexport const encodePrefix = (prefix: string): string => {\n const bytes = new TextEncoder().encode(prefix)\n const binString = Array.from(bytes, (byte) => String.fromCodePoint(byte)).join(\"\")\n return btoa(binString)\n}\n\nexport const decodePrefix = (encoded: string | undefined): string => {\n if (!encoded) return \"\"\n try {\n const binString = atob(encoded)\n const bytes = Uint8Array.from(binString, (char) => char.codePointAt(0)!)\n return new TextDecoder(\"utf-8\", { fatal: true }).decode(bytes)\n } catch {\n return \"\"\n }\n}\n","import { useState, useEffect, useRef, startTransition, useMemo } from \"react\"\nimport { Plural, Trans, useLingui } from \"@lingui/react/macro\"\nimport { plural } from \"@lingui/core/macro\"\nimport {\n Status,\n Stack,\n Button,\n toast,\n DataGridToolbar,\n SearchInput,\n TabNavigation,\n TabNavigationItem,\n Checkbox,\n PopupMenu,\n PopupMenuItem,\n PopupMenuOptions,\n PopupMenuToggle,\n} from \"@cloudoperators/juno-ui-components\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport { useCephPermissions } from \"../hooks/useCephPermissions\"\nimport { SortInput } from \"@/client/components/ListToolbar/SortInput\"\nimport { SortSettings } from \"@/client/components/ListToolbar/types\"\nimport { ObjectsTableView } from \"./ObjectsTableView\"\nimport { ObjectsFileNavigation } from \"./ObjectsFileNavigation\"\nimport { CreateFolderModal } from \"./CreateFolderModal\"\nimport { UploadObjectModal } from \"./UploadObjectModal\"\nimport { DeleteObjectsModal } from \"./DeleteObjectsModal\"\nimport { EnableVersioningModal } from \"../Buckets/EnableVersioningModal\"\nimport { SuspendVersioningModal } from \"../Buckets/SuspendVersioningModal\"\nimport { BucketPolicyModal } from \"../Buckets/BucketPolicyModal\"\nimport { DeleteBucketPolicyModal } from \"../Buckets/DeleteBucketPolicyModal\"\nimport { EmptyBucketModal } from \"../Buckets/EmptyBucketModal\"\nimport { DeleteBucketModal } from \"../Buckets/DeleteBucketModal\"\nimport { DeleteVersionsModal } from \"../Buckets/DeleteVersionsModal\"\nimport { useNavigate } from \"@tanstack/react-router\"\nimport { Route } from \"@/client/routes/_auth/projects/$projectId/storage/$provider/$storageType/$containerName/objects\"\nimport type { S3Object, S3FolderPrefix, S3ObjectVersion } from \"@/server/Storage/types/ceph\"\nimport {\n getFolderCreatedToast,\n getObjectDeletedToast,\n getObjectDeleteErrorToast,\n getObjectsBulkDeletedToast,\n getObjectsBulkDeletePartialToast,\n getObjectsBulkDeleteErrorToast,\n getVersionsBulkDeletedToast,\n getVersionsBulkDeletePartialToast,\n getVersionsBulkDeleteErrorToast,\n getObjectCopiedToast,\n getObjectCopyErrorToast,\n getObjectMovedToast,\n getObjectMoveErrorToast,\n getObjectMetadataUpdatedToast,\n getObjectMetadataUpdateErrorToast,\n getObjectDownloadErrorToast,\n getObjectUploadedToast,\n getObjectUploadCancelledToast,\n getObjectUploadErrorToast,\n} from \"./ObjectToastNotifications\"\nimport { encodePrefix, decodePrefix } from \"../../utils/prefixEncoding\"\n\ninterface ObjectBrowserViewProps {\n bucketName: string\n}\n\ntype SortKey = \"name\" | \"lastModified\" | \"size\" | \"last_modified\" | \"bytes\"\n\nexport function ObjectBrowserView({ bucketName }: ObjectBrowserViewProps) {\n const { t } = useLingui()\n const projectId = useProjectId()\n const { permissions } = useCephPermissions(projectId ?? \"\")\n const navigate = useNavigate({ from: Route.fullPath })\n const { provider, storageType } = Route.useParams()\n const { prefix: encodedPrefix, sortBy, sortDirection, search: searchParam = \"\", tab = \"all\" } = Route.useSearch()\n const currentPrefix = decodePrefix(encodedPrefix)\n\n const [continuationToken, setContinuationToken] = useState<string | undefined>(undefined)\n const [keyMarker, setKeyMarker] = useState<string | undefined>(undefined)\n const [versionIdMarker, setVersionIdMarker] = useState<string | undefined>(undefined)\n const [allObjects, setAllObjects] = useState<S3Object[]>([])\n const [allFolders, setAllFolders] = useState<S3FolderPrefix[]>([])\n const [allVersions, setAllVersions] = useState<S3ObjectVersion[]>([])\n const [hasMore, setHasMore] = useState(false)\n const [isCreateFolderModalOpen, setIsCreateFolderModalOpen] = useState(false)\n const [isUploadModalOpen, setIsUploadModalOpen] = useState(false)\n const [isEnableVersioningModalOpen, setIsEnableVersioningModalOpen] = useState(false)\n const [isSuspendVersioningModalOpen, setIsSuspendVersioningModalOpen] = useState(false)\n const [isPolicyModalOpen, setIsPolicyModalOpen] = useState(false)\n const [isDeletePolicyModalOpen, setIsDeletePolicyModalOpen] = useState(false)\n const [isEmptyBucketModalOpen, setIsEmptyBucketModalOpen] = useState(false)\n const [isDeleteBucketModalOpen, setIsDeleteBucketModalOpen] = useState(false)\n const [isDeleteVersionsModalOpen, setIsDeleteVersionsModalOpen] = useState(false)\n\n const [selectedItems, setSelectedItems] = useState<{ key: string; versionId?: string }[]>([])\n const [isDeleteObjectsModalOpen, setIsDeleteObjectsModalOpen] = useState(false)\n\n // The bulk action in the \"deleted\" tab permanently deletes versions/delete markers; in\n // \"all\" it deletes current objects - these are gated by different permissions.\n const hasAnyBulkAction = tab === \"deleted\" ? permissions.canDeleteVersion : permissions.canDeleteObject\n\n // Local mirror of the committed search term so typing stays responsive while\n // the URL commit is debounced (see Zone 2 SearchInput below).\n const [localSearchTerm, setLocalSearchTerm] = useState(searchParam)\n const debounceTimer = useRef<number | undefined>(undefined)\n useEffect(() => () => clearTimeout(debounceTimer.current), [])\n\n // Keep the input in sync when the committed search term changes from outside\n // the input — browser back/forward, deep links, or programmatic navigation —\n // so the field never drifts from the URL-backed filter state. When the change\n // originated from our own debounced commit, searchParam already equals\n // localSearchTerm, so this is a no-op and won't disturb the caret.\n useEffect(() => {\n setLocalSearchTerm(searchParam)\n }, [searchParam])\n\n // Reset accumulated data when tab changes (switching between All/Deleted views)\n useEffect(() => {\n setContinuationToken(undefined)\n setKeyMarker(undefined)\n setVersionIdMarker(undefined)\n setAllObjects([])\n setAllFolders([])\n setAllVersions([])\n setSelectedItems([])\n }, [tab])\n\n // Query versioning status for current bucket\n const { data: versioningStatus } = trpcReact.storage.ceph.versioning.getStatus.useQuery(\n {\n project_id: projectId ?? \"\",\n bucket: bucketName,\n },\n {\n enabled: !!projectId,\n staleTime: 5 * 60 * 1000, // Cache for 5 minutes\n }\n )\n\n // Query to check which folders contain deleted content\n // Need this in both tabs: \"deleted\" to show deleted folders, \"all\" to hide deleted folders\n const { data: folderDeletedStatus } = trpcReact.storage.ceph.versioning.checkDeletedContent.useQuery(\n {\n project_id: projectId ?? \"\",\n bucket: bucketName,\n folders: allFolders.map((f) => f.prefix),\n },\n {\n enabled: !!projectId && versioningStatus?.status === \"Enabled\" && allFolders.length > 0,\n staleTime: 30 * 1000, // Cache for 30 seconds\n }\n )\n\n const { data, isLoading, isFetching, error } = trpcReact.storage.ceph.objects.list.useQuery(\n {\n project_id: projectId ?? \"\",\n containerName: bucketName,\n prefix: currentPrefix || undefined,\n delimiter: \"/\",\n maxKeys: 1000,\n continuationToken: tab === \"deleted\" ? undefined : continuationToken,\n keyMarker: tab === \"deleted\" ? keyMarker : undefined,\n versionIdMarker: tab === \"deleted\" ? versionIdMarker : undefined,\n showVersions: tab === \"deleted\", // Load versions when showing deleted tab\n },\n {\n enabled: !!projectId,\n }\n )\n\n // Update accumulated data when new data arrives\n useEffect(() => {\n if (data) {\n if (tab === \"deleted\" && data.versions) {\n // When showing deleted files, use versions array\n const actualVersions = data.versions.filter((ver) => {\n const stripped = currentPrefix ? ver.key.replace(currentPrefix, \"\") : ver.key\n return stripped !== \"\" && stripped !== \"/\"\n })\n\n // For deleted tab, check keyMarker for pagination (not continuationToken)\n if (keyMarker) {\n setAllVersions((prev) => [...prev, ...actualVersions])\n setAllFolders((prev) => [...prev, ...data.folders])\n } else {\n setAllVersions(actualVersions)\n setAllFolders(data.folders)\n }\n } else {\n // Default: showing current versions only\n const actualObjects = data.objects.filter((obj) => {\n const stripped = currentPrefix ? obj.key.replace(currentPrefix, \"\") : obj.key\n return stripped !== \"\" && stripped !== \"/\"\n })\n\n if (continuationToken) {\n setAllObjects((prev) => [...prev, ...actualObjects])\n setAllFolders((prev) => [...prev, ...data.folders])\n } else {\n setAllObjects(actualObjects)\n setAllFolders(data.folders)\n }\n }\n setHasMore(data.isTruncated ?? false)\n }\n }, [data, continuationToken, keyMarker, currentPrefix, tab])\n\n const navigateToPrefix = (prefix: string) => {\n // Reset pagination when navigating\n setContinuationToken(undefined)\n setKeyMarker(undefined)\n setVersionIdMarker(undefined)\n setAllObjects([])\n setAllFolders([])\n setAllVersions([])\n setHasMore(false)\n setSelectedItems([])\n navigate({\n search: (prev) => ({\n ...prev,\n prefix: prefix ? encodePrefix(prefix) : undefined,\n }),\n })\n }\n\n const navigateToBuckets = () => {\n // Reset pagination/accumulated state before leaving the bucket\n setContinuationToken(undefined)\n setKeyMarker(undefined)\n setVersionIdMarker(undefined)\n setAllObjects([])\n setAllFolders([])\n setAllVersions([])\n setHasMore(false)\n setSelectedItems([])\n\n navigate({\n to: \"/projects/$projectId/storage/$provider/$storageType\",\n params: { projectId, provider, storageType },\n })\n }\n\n const loadMore = () => {\n if (tab === \"deleted\") {\n // Version pagination uses both keyMarker and versionIdMarker\n if (data?.nextKeyMarker) {\n setKeyMarker(data.nextKeyMarker)\n setVersionIdMarker(data.nextVersionIdMarker)\n }\n } else {\n // Regular pagination uses continuationToken\n if (data?.nextContinuationToken) {\n setContinuationToken(data.nextContinuationToken)\n }\n }\n }\n\n // Filter by search term\n const stripPrefix = (fullKey: string) => (currentPrefix ? fullKey.replace(currentPrefix, \"\") : fullKey)\n\n const filteredObjects = allObjects.filter((obj) =>\n stripPrefix(obj.key).toLowerCase().includes(searchParam.toLowerCase().trim())\n )\n\n // When showing deleted files: show the last real version before delete marker (the version we can restore)\n const deletedFilesList = (() => {\n if (tab !== \"deleted\") return []\n\n // Group versions by key\n const versionsByKey = allVersions.reduce((acc: Record<string, S3ObjectVersion[]>, version: S3ObjectVersion) => {\n if (!acc[version.key]) acc[version.key] = []\n acc[version.key].push(version)\n return acc\n }, {})\n\n const deletedFiles: Array<\n S3ObjectVersion & { isDeleted?: boolean; deleteMarkerVersionId?: string; allVersionIds?: string[] }\n > = []\n Object.entries(versionsByKey).forEach(([, versions]: [string, S3ObjectVersion[]]) => {\n // Sort by lastModified descending to find latest version\n const sorted = [...versions].sort((a, b) => {\n if (!a.lastModified || !b.lastModified) return 0\n return new Date(b.lastModified).getTime() - new Date(a.lastModified).getTime()\n })\n const latestVersion = sorted.find((v) => v.isLatest) || sorted[0]\n\n // If latest version is a delete marker, find the previous real version (the one to restore)\n if (latestVersion?.isDeleteMarker) {\n const previousVersion = sorted.find((v) => !v.isDeleteMarker)\n if (previousVersion) {\n // Add a flag to indicate this is a restorable deleted file\n // Store all versionIds for permanent delete (to delete all versions + delete markers)\n const allVersionIds = sorted.map((v) => v.versionId)\n deletedFiles.push({\n ...previousVersion,\n isDeleted: true, // Custom flag to show \"Deleted\" badge\n deleteMarkerVersionId: latestVersion.versionId, // Store delete marker versionId\n allVersionIds, // Store all version IDs for complete deletion\n })\n }\n }\n })\n\n return deletedFiles\n })()\n\n // Filter folders based on deleted content check from BFF\n // Also add isDeleted flag to folders whose marker is deleted\n const deletedFoldersList: Array<\n S3FolderPrefix & { isDeleted?: boolean; deleteMarkerVersionId?: string; folderMarkerVersionId?: string }\n > = (() => {\n if (tab !== \"deleted\") {\n // In \"All\" tab, exclude folders that are deleted (have delete marker as latest version)\n // or have no versions at all (permanently deleted)\n if (!folderDeletedStatus || !Array.isArray(folderDeletedStatus)) return allFolders // Show all while loading or if no data\n\n const filtered = allFolders.filter((folder) => {\n const status = folderDeletedStatus.find((s) => s.prefix === folder.prefix)\n // No status? Show folder (we don't know if it's deleted)\n if (!status) return true\n // Has status? Show only if not deleted AND has versions\n // If folderMarkerVersionId is undefined, the folder has no versions (was permanently deleted)\n return !status.isFolderDeleted && status.folderMarkerVersionId !== undefined\n })\n\n return filtered\n }\n\n if (!folderDeletedStatus || !Array.isArray(folderDeletedStatus)) return allFolders // Show all while loading or if no data\n\n // In \"Deleted\" tab: Filter folders that have deleted content or are themselves deleted\n const foldersWithDeleted = allFolders\n .filter((folder) => {\n const status = folderDeletedStatus.find((s) => s.prefix === folder.prefix)\n return status?.hasDeletedContent ?? false\n })\n .map((folder) => {\n const status = folderDeletedStatus.find((s) => s.prefix === folder.prefix)\n return {\n ...folder,\n isDeleted: status?.isFolderDeleted ?? false, // Add isDeleted flag for badge\n deleteMarkerVersionId: status?.folderDeleteMarkerVersionId, // Add delete marker versionId for restore\n folderMarkerVersionId: status?.folderMarkerVersionId, // Add folder marker versionId for permanent delete\n }\n })\n\n return foldersWithDeleted\n })()\n\n const filteredFolders = deletedFoldersList.filter((folder) =>\n stripPrefix(folder.prefix).toLowerCase().includes(searchParam.toLowerCase().trim())\n )\n\n // Sort deleted files (operates on full unfiltered list before search)\n const sortedDeletedFiles = !sortBy\n ? deletedFilesList\n : [...deletedFilesList].sort((a, b) => {\n let comparison = 0\n switch (sortBy) {\n case \"name\":\n comparison = stripPrefix(a.key).localeCompare(stripPrefix(b.key))\n break\n case \"lastModified\":\n case \"last_modified\": {\n const aDate = a.lastModified\n const bDate = b.lastModified\n if (!aDate || !bDate) break\n comparison = new Date(aDate).getTime() - new Date(bDate).getTime()\n break\n }\n case \"size\":\n case \"bytes\":\n comparison = a.size - b.size\n break\n }\n return sortDirection === \"desc\" ? -comparison : comparison\n })\n\n // Apply search filter to sorted deleted files (after sorting)\n const filteredDeletedFiles = sortedDeletedFiles.filter((v) =>\n stripPrefix(v.key).toLowerCase().includes(searchParam.toLowerCase().trim())\n )\n\n const totalItemCount =\n tab === \"deleted\" ? deletedFilesList.length + deletedFoldersList.length : allObjects.length + allFolders.length\n const filteredItemCount =\n tab === \"deleted\"\n ? filteredDeletedFiles.length + filteredFolders.length\n : filteredObjects.length + filteredFolders.length\n\n // Sort\n const sortedObjects = !sortBy\n ? filteredObjects\n : [...filteredObjects].sort((a, b) => {\n let comparison = 0\n switch (sortBy) {\n case \"name\":\n comparison = stripPrefix(a.key).localeCompare(stripPrefix(b.key))\n break\n case \"lastModified\":\n case \"last_modified\": {\n const aDate = a.lastModified\n const bDate = b.lastModified\n if (!aDate || !bDate) break\n comparison = new Date(aDate).getTime() - new Date(bDate).getTime()\n break\n }\n case \"size\":\n case \"bytes\":\n comparison = a.size - b.size\n break\n }\n return sortDirection === \"desc\" ? -comparison : comparison\n })\n\n const sortedFolders = !sortBy\n ? filteredFolders\n : [...filteredFolders].sort((a, b) => {\n if (sortBy === \"name\") {\n return sortDirection === \"desc\"\n ? stripPrefix(b.prefix).localeCompare(stripPrefix(a.prefix))\n : stripPrefix(a.prefix).localeCompare(stripPrefix(b.prefix))\n }\n return 0\n })\n\n const sortSettings: SortSettings = {\n options: [\n { label: t`Name`, value: \"name\" },\n { label: t`Last Modified`, value: \"lastModified\" },\n { label: t`Size`, value: \"size\" },\n ],\n sortBy: sortBy ?? undefined,\n sortDirection: sortDirection ?? \"asc\",\n }\n\n // Bulk selection derived values\n const { i18n } = useLingui()\n const showSelection = hasAnyBulkAction\n\n // Helper to build a unique identifier for selected items\n const makeItemKey = (key: string, versionId?: string) => `${key}|${versionId ?? \"\"}`\n\n // Performance optimization: Build a Map for O(1) version lookup instead of O(n) find()\n const versionIdByKey = useMemo(() => {\n if (tab !== \"deleted\") return new Map<string, string>()\n return new Map(filteredDeletedFiles.map((v) => [v.key, v.versionId]))\n }, [tab, filteredDeletedFiles])\n\n // Performance optimization: Build a Set for O(1) membership checks instead of O(m) some()\n const selectedItemsSet = useMemo(() => {\n return new Set(selectedItems.map((item) => makeItemKey(item.key, item.versionId)))\n }, [selectedItems])\n\n // Tab-specific selection logic\n const selectableKeys = tab === \"deleted\" ? filteredDeletedFiles.map((v) => v.key) : sortedObjects.map((o) => o.key)\n\n const isItemSelected = (key: string, versionId?: string) => selectedItemsSet.has(makeItemKey(key, versionId))\n\n const allSelected =\n selectableKeys.length > 0 &&\n selectableKeys.every((k) => {\n const versionId = tab === \"deleted\" ? versionIdByKey.get(k) : undefined\n return isItemSelected(k, versionId)\n })\n\n const someSelected = selectableKeys.some((k) => {\n const versionId = tab === \"deleted\" ? versionIdByKey.get(k) : undefined\n return isItemSelected(k, versionId)\n })\n\n const selectedCount = selectedItems.length\n\n const handleToggleSelectKey = (key: string, versionId?: string) => {\n setSelectedItems((prev) => {\n const exists = prev.some((item) => item.key === key && item.versionId === versionId)\n return exists\n ? prev.filter((item) => !(item.key === key && item.versionId === versionId))\n : [...prev, { key, versionId }]\n })\n }\n\n const handleToggleSelectAll = () => {\n setSelectedItems((prev) => {\n if (tab === \"deleted\") {\n const visibleItemKeys = new Set(filteredDeletedFiles.map((v) => makeItemKey(v.key, v.versionId)))\n if (allSelected) {\n // Deselect all visible versions\n return prev.filter((item) => !visibleItemKeys.has(makeItemKey(item.key, item.versionId)))\n } else {\n // Select all visible versions\n const newItems = filteredDeletedFiles.map((v) => ({ key: v.key, versionId: v.versionId }))\n const existingKeys = new Set(prev.map((item) => makeItemKey(item.key, item.versionId)))\n const toAdd = newItems.filter((item) => !existingKeys.has(makeItemKey(item.key, item.versionId)))\n return [...prev, ...toAdd]\n }\n } else {\n // Objects tab: select/deselect without versionId\n if (allSelected) {\n // Deselect all visible objects\n return prev.filter((item) => !selectableKeys.includes(item.key) || item.versionId !== undefined)\n } else {\n // Select all visible objects\n const existingKeys = new Set(prev.filter((item) => !item.versionId).map((item) => item.key))\n const toAdd = selectableKeys\n .filter((key) => !existingKeys.has(key))\n .map((key) => ({ key, versionId: undefined }))\n return [...prev, ...toAdd]\n }\n }\n })\n }\n\n const resetAccumulatedObjects = () => {\n setContinuationToken(undefined)\n setKeyMarker(undefined)\n setVersionIdMarker(undefined)\n setAllObjects([])\n setAllFolders([])\n setAllVersions([])\n setHasMore(false)\n }\n\n const handleBulkDeleted = (deletedKeys: string[], errorCount: number) => {\n // The list accumulates pages; a plain invalidate would refetch only the last\n // page and append it. Drop the accumulator so the refetch rebuilds page 1.\n resetAccumulatedObjects()\n\n // In Deleted tab, clear all selection after bulk delete (list is being refetched anyway)\n // In All tab, only clear successfully deleted items\n if (tab === \"deleted\") {\n setSelectedItems([])\n } else {\n setSelectedItems((prev) => prev.filter((item) => !deletedKeys.includes(item.key)))\n }\n\n if (tab === \"deleted\") {\n // Version deletion toasts\n if (errorCount === 0) {\n const { message, ...options } = getVersionsBulkDeletedToast(deletedKeys.length)\n toast.success(message, options)\n } else {\n const { message, ...options } = getVersionsBulkDeletePartialToast(deletedKeys.length, errorCount)\n toast.warning(message, options)\n }\n } else {\n // Object deletion toasts\n if (errorCount === 0) {\n const { message, ...options } = getObjectsBulkDeletedToast(deletedKeys.length)\n toast.success(message, options)\n } else {\n const { message, ...options } = getObjectsBulkDeletePartialToast(deletedKeys.length, errorCount)\n toast.warning(message, options)\n }\n }\n }\n\n const handleBulkDeleteError = (errorMessage: string) => {\n if (tab === \"deleted\") {\n const { message, ...options } = getVersionsBulkDeleteErrorToast(errorMessage)\n toast.error(message, options)\n } else {\n const { message, ...options } = getObjectsBulkDeleteErrorToast(errorMessage)\n toast.error(message, options)\n }\n }\n\n const handleSearchChange = (term: string | number | string[] | undefined) => {\n const value = typeof term === \"string\" ? term : \"\"\n startTransition(() => {\n navigate({\n search: (prev) => ({\n ...prev,\n search: value || undefined,\n }),\n })\n })\n }\n\n const handleSortChange = (newSort: SortSettings) => {\n const resolvedSortBy = newSort.sortBy as SortKey | undefined\n const resolvedDirection = (newSort.sortDirection as \"asc\" | \"desc\") || \"asc\"\n startTransition(() => {\n navigate({\n search: (prev) => ({\n ...prev,\n sortBy: resolvedSortBy,\n sortDirection: resolvedSortBy ? resolvedDirection : undefined,\n }),\n })\n })\n }\n\n if (error) {\n const errorMessage = error.message\n return <Status status=\"error\" title={t`Failed to Load Objects`} body={errorMessage} />\n }\n\n return (\n <div className=\"relative\">\n <Stack direction=\"vertical\">\n {/* Zone 1 — sort controls and page-level actions */}\n <Stack distribution=\"between\" alignment=\"end\" gap=\"2\" className=\"pb-2\">\n {/* Tabs row (shown only when versioning is enabled/suspended) */}\n {versioningStatus && versioningStatus.status !== \"Unversioned\" ? (\n <TabNavigation>\n <TabNavigationItem\n label={t`All`}\n active={tab === \"all\"}\n onClick={() => {\n navigate({\n search: (prev) => ({\n ...prev,\n tab: \"all\",\n // Reset prefix when switching from deleted to all\n // because the current folder might not exist in \"all\" view\n prefix: tab === \"deleted\" ? undefined : prev.prefix,\n }),\n })\n }}\n />\n <TabNavigationItem\n label={t`Deleted`}\n active={tab === \"deleted\"}\n onClick={() => {\n navigate({\n search: (prev) => ({\n ...prev,\n tab: \"deleted\",\n // Reset prefix when switching from all to deleted\n // because the current folder might not exist in \"deleted\" view\n prefix: tab === \"all\" ? undefined : prev.prefix,\n }),\n })\n }}\n />\n </TabNavigation>\n ) : (\n <div />\n )}\n\n <Stack gap=\"2\" alignment=\"center\">\n <Stack gap=\"0.5\" alignment=\"center\">\n <SortInput\n options={sortSettings.options}\n sortBy={sortSettings.sortBy}\n sortDirection={sortSettings.sortDirection ?? \"asc\"}\n selectClassName=\"min-w-40\"\n onSortByChange={(value) =>\n handleSortChange({ ...sortSettings, sortBy: value, sortDirection: sortSettings.sortDirection })\n }\n onSortDirectionChange={(direction) => handleSortChange({ ...sortSettings, sortDirection: direction })}\n />\n </Stack>\n <Stack gap=\"0.5\" alignment=\"center\">\n {permissions.canCreateFolder && (\n <PopupMenu className=\"flex items-center\">\n <PopupMenuToggle as=\"div\">\n <Button icon=\"moreVert\" title={t`More Actions`} />\n </PopupMenuToggle>\n <PopupMenuOptions>\n <PopupMenuItem\n label={t`Create Folder`}\n onClick={() => setIsCreateFolderModalOpen(true)}\n data-testid=\"create-folder-action\"\n />\n </PopupMenuOptions>\n </PopupMenu>\n )}\n {permissions.canCreateObject && (\n <Button variant=\"primary\" className=\"whitespace-nowrap\" onClick={() => setIsUploadModalOpen(true)}>\n <Trans>Upload Object</Trans>\n </Button>\n )}\n </Stack>\n </Stack>\n </Stack>\n\n {/* Zone 2 — debounced search. DataGridToolbar provides the background. */}\n <DataGridToolbar>\n <Stack direction=\"vertical\" gap=\"2\">\n <Stack distribution=\"end\" alignment=\"center\">\n <SearchInput\n placeholder={t`Search objects...`}\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(() => handleSearchChange(v), 500)\n }}\n onSearch={(v) => {\n clearTimeout(debounceTimer.current)\n handleSearchChange(typeof v === \"string\" ? v : \"\")\n }}\n onClear={() => {\n clearTimeout(debounceTimer.current)\n setLocalSearchTerm(\"\")\n handleSearchChange(\"\")\n }}\n />\n </Stack>\n </Stack>\n </DataGridToolbar>\n\n {/* Zone 3 — breadcrumb navigation in its own row */}\n <DataGridToolbar>\n <ObjectsFileNavigation\n bucketName={bucketName}\n prefix={currentPrefix}\n onBucketsClick={navigateToBuckets}\n onPrefixClick={navigateToPrefix}\n />\n </DataGridToolbar>\n\n {/* Zone 4 — item count. */}\n <DataGridToolbar>\n <Stack distribution=\"between\" gap=\"2\" alignment=\"center\" className=\"text-sm\">\n {showSelection ? (\n <Stack gap=\"2\" alignment=\"center\">\n <Checkbox\n checked={allSelected}\n indeterminate={someSelected && !allSelected}\n onChange={handleToggleSelectAll}\n aria-label={t`Select all objects`}\n data-testid=\"select-all-objects\"\n />\n <PopupMenu className=\"flex items-center\">\n <PopupMenuToggle as=\"div\">\n <Button disabled={selectedCount === 0} size=\"small\" icon=\"moreVert\" label={t`Actions`} />\n </PopupMenuToggle>\n {selectedCount > 0 && (\n <PopupMenuOptions>\n {tab === \"deleted\" ? (\n <PopupMenuItem\n label={i18n._(plural(selectedCount, { one: \"Delete # Version\", other: \"Delete # Versions\" }))}\n onClick={() => setIsDeleteObjectsModalOpen(true)}\n data-testid=\"bulk-delete-versions-action\"\n />\n ) : (\n <PopupMenuItem\n label={i18n._(plural(selectedCount, { one: \"Delete # Object\", other: \"Delete # Objects\" }))}\n onClick={() => setIsDeleteObjectsModalOpen(true)}\n data-testid=\"bulk-delete-action\"\n />\n )}\n </PopupMenuOptions>\n )}\n </PopupMenu>\n </Stack>\n ) : (\n <span />\n )}\n <div className=\"text-theme-light flex items-center gap-1\" data-testid=\"objects-info-block\">\n {searchParam.trim() ? (\n <Plural\n value={totalItemCount}\n one={`${filteredItemCount} of ${totalItemCount} item`}\n other={`${filteredItemCount} of ${totalItemCount} items`}\n />\n ) : (\n <Plural value={totalItemCount} one={`${totalItemCount} item`} other={`${totalItemCount} items`} />\n )}\n </div>\n </Stack>\n </DataGridToolbar>\n </Stack>\n\n {isLoading && !continuationToken && !keyMarker ? (\n <Status status=\"progress\" title={t`Loading Objects...`} />\n ) : (\n <ObjectsTableView\n bucketName={bucketName}\n objects={sortedObjects}\n folders={sortedFolders}\n versions={filteredDeletedFiles}\n showingVersions={tab === \"deleted\"}\n currentPrefix={currentPrefix}\n versioningEnabled={versioningStatus?.status === \"Enabled\"}\n selectable={showSelection}\n selectedItems={selectedItems}\n onToggleSelectKey={handleToggleSelectKey}\n onFolderClick={navigateToPrefix}\n canCopyObject={permissions.canCopyObject}\n canMoveObject={permissions.canMoveObject}\n canUpdateObject={permissions.canUpdateObject}\n canShareObject={permissions.canShareObject}\n canDeleteObject={permissions.canDeleteObject}\n canDeleteFolder={permissions.canDeleteFolder}\n canDeleteVersion={permissions.canDeleteVersion}\n canRestoreVersion={permissions.canRestoreVersion}\n isLoading={isFetching}\n onDeleteObjectSuccess={(objectKey) => {\n const { message, ...options } = getObjectDeletedToast(objectKey)\n toast.success(message, options)\n }}\n onDeleteObjectError={(objectKey, errorMessage) => {\n const { message, ...options } = getObjectDeleteErrorToast(objectKey, errorMessage)\n toast.error(message, options)\n }}\n onCopyObjectSuccess={(objectKey, targetBucket, targetKey, wasOverwritten) => {\n const { message, ...options } = getObjectCopiedToast(objectKey, targetBucket, targetKey, wasOverwritten)\n toast.success(message, options)\n }}\n onCopyObjectError={(objectKey, errorMessage) => {\n const { message, ...options } = getObjectCopyErrorToast(objectKey, errorMessage)\n toast.error(message, options)\n }}\n onMoveObjectSuccess={(objectKey, targetBucket, targetKey) => {\n const { message, ...options } = getObjectMovedToast(objectKey, targetBucket, targetKey)\n toast.success(message, options)\n }}\n onMoveObjectError={(objectKey, errorMessage) => {\n const { message, ...options } = getObjectMoveErrorToast(objectKey, errorMessage)\n toast.error(message, options)\n }}\n onEditMetadataSuccess={(objectKey) => {\n const { message, ...options } = getObjectMetadataUpdatedToast(objectKey)\n toast.success(message, options)\n }}\n onEditMetadataError={(objectKey, errorMessage) => {\n const { message, ...options } = getObjectMetadataUpdateErrorToast(objectKey, errorMessage)\n toast.error(message, options)\n }}\n onDownloadError={(objectKey, errorMessage) => {\n const { message, ...options } = getObjectDownloadErrorToast(objectKey, errorMessage)\n toast.error(message, options)\n }}\n />\n )}\n\n {hasMore && (\n <div className=\"mt-4 flex justify-center\">\n <Button onClick={loadMore} disabled={isLoading} variant=\"subdued\">\n {isLoading ? <Trans>Loading more...</Trans> : <Trans>Load More</Trans>}\n </Button>\n </div>\n )}\n\n <CreateFolderModal\n bucketName={bucketName}\n currentPrefix={currentPrefix}\n isOpen={isCreateFolderModalOpen}\n onClose={() => setIsCreateFolderModalOpen(false)}\n onSuccess={(folderPath) => {\n setIsCreateFolderModalOpen(false)\n const { message, ...options } = getFolderCreatedToast(folderPath)\n toast.success(message, options)\n }}\n />\n\n <UploadObjectModal\n isOpen={isUploadModalOpen}\n bucketName={bucketName}\n projectId={projectId ?? \"\"}\n currentPrefix={currentPrefix}\n onClose={() => setIsUploadModalOpen(false)}\n onSuccess={(objectName) => {\n setIsUploadModalOpen(false)\n const { message, ...options } = getObjectUploadedToast(objectName)\n toast.success(message, options)\n }}\n onError={(objectName, errorMessage) => {\n const { message, ...options } = getObjectUploadErrorToast(objectName, errorMessage)\n toast.error(message, options)\n }}\n onCancelled={(objectName) => {\n const { message, ...options } = getObjectUploadCancelledToast(objectName)\n toast.warning(message, options)\n }}\n />\n\n <DeleteObjectsModal\n bucketName={bucketName}\n objectKeys={tab === \"deleted\" ? [] : selectedItems.filter((item) => !item.versionId).map((item) => item.key)}\n versions={\n tab === \"deleted\"\n ? selectedItems\n .filter((item) => item.versionId)\n .flatMap((item) => {\n // Find the deleted file entry to get all version IDs (including delete marker)\n const deletedFile = filteredDeletedFiles.find((f) => f.key === item.key)\n if (deletedFile?.allVersionIds) {\n // Delete ALL versions including delete markers for complete removal\n return deletedFile.allVersionIds.map((vid) => ({ key: item.key, versionId: vid }))\n }\n // Fallback: if allVersionIds not found, delete just the selected version\n return [{ key: item.key, versionId: item.versionId! }]\n })\n : []\n }\n currentPrefix={currentPrefix}\n versioningEnabled={versioningStatus?.status === \"Enabled\"}\n isVersionMode={tab === \"deleted\"}\n isOpen={isDeleteObjectsModalOpen}\n onClose={() => setIsDeleteObjectsModalOpen(false)}\n onDeleted={handleBulkDeleted}\n onError={handleBulkDeleteError}\n />\n\n <EnableVersioningModal\n isOpen={isEnableVersioningModalOpen}\n bucketName={bucketName}\n onClose={() => setIsEnableVersioningModalOpen(false)}\n onSuccess={() => {\n setIsEnableVersioningModalOpen(false)\n }}\n onError={() => {\n setIsEnableVersioningModalOpen(false)\n }}\n />\n\n <SuspendVersioningModal\n isOpen={isSuspendVersioningModalOpen}\n bucketName={bucketName}\n onClose={() => setIsSuspendVersioningModalOpen(false)}\n onSuccess={() => {\n setIsSuspendVersioningModalOpen(false)\n }}\n onError={() => {\n setIsSuspendVersioningModalOpen(false)\n }}\n />\n\n <BucketPolicyModal\n isOpen={isPolicyModalOpen}\n bucketName={bucketName}\n onClose={() => setIsPolicyModalOpen(false)}\n />\n\n <DeleteBucketPolicyModal\n isOpen={isDeletePolicyModalOpen}\n bucketName={bucketName}\n onClose={() => setIsDeletePolicyModalOpen(false)}\n onSuccess={() => {\n setIsDeletePolicyModalOpen(false)\n }}\n onError={() => {\n setIsDeletePolicyModalOpen(false)\n }}\n />\n\n <EmptyBucketModal\n isOpen={isEmptyBucketModalOpen}\n bucket={{\n name: bucketName,\n count: 0, // We don't have these stats in this context\n bytes: 0,\n }}\n onClose={() => setIsEmptyBucketModalOpen(false)}\n onSuccess={(bucketName, deletedCount) => {\n setIsEmptyBucketModalOpen(false)\n toast.success(t`Successfully emptied bucket \"${bucketName}\". ${deletedCount} objects deleted.`)\n }}\n onError={(bucketName, errorMessage) => {\n setIsEmptyBucketModalOpen(false)\n toast.error(t`Failed to empty bucket \"${bucketName}\": ${errorMessage}`)\n }}\n />\n\n <DeleteBucketModal\n isOpen={isDeleteBucketModalOpen}\n bucket={{\n name: bucketName,\n count: 0,\n bytes: 0,\n }}\n onClose={() => setIsDeleteBucketModalOpen(false)}\n onSuccess={(bucketName) => {\n toast.success(t`Successfully deleted bucket \"${bucketName}\".`)\n // Navigate back to buckets list\n navigate({\n to: \"/projects/$projectId/storage/$provider/$storageType\",\n params: {\n projectId: projectId ?? \"\",\n provider: (provider as string) ?? \"ceph\",\n storageType: (storageType as string) ?? \"buckets\",\n },\n })\n }}\n onError={(bucketName, errorMessage) => {\n toast.error(t`Failed to delete bucket \"${bucketName}\": ${errorMessage}`)\n }}\n />\n\n <DeleteVersionsModal\n isOpen={isDeleteVersionsModalOpen}\n bucket={{\n name: bucketName,\n count: 0,\n bytes: 0,\n }}\n onClose={() => setIsDeleteVersionsModalOpen(false)}\n onSuccess={(bucketName, deletedCount) => {\n setIsDeleteVersionsModalOpen(false)\n toast.success(\n t`Successfully deleted ${deletedCount} versions and delete markers from bucket \"${bucketName}\".`\n )\n }}\n onError={(bucketName, errorMessage) => {\n setIsDeleteVersionsModalOpen(false)\n toast.error(t`Failed to delete versions from bucket \"${bucketName}\": ${errorMessage}`)\n }}\n />\n </div>\n )\n}\n","import { useState } from \"react\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { Modal, TextInput, Stack, Checkbox, Message } from \"@cloudoperators/juno-ui-components\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport { useModalTracking } from \"@/client/hooks/useModalTracking\"\nimport { Bucket } from \"@/server/Storage/types/ceph\"\n\ninterface CreateBucketModalProps {\n isOpen: boolean\n onClose: () => void\n onSuccess?: (bucketName: string) => void\n existingBuckets?: Bucket[]\n}\n\n// S3 bucket naming validation patterns\nconst S3_BUCKET_NAME_REGEX = /^[a-z0-9][a-z0-9.-]*[a-z0-9]$/\nconst IP_ADDRESS_REGEX = /^(\\d{1,3}\\.){3}\\d{1,3}$/\nconst RESERVED_PREFIXES = [\"xn--\", \"sthree-\", \"amzn-s3-demo-\"]\nconst RESERVED_SUFFIXES = [\"-s3alias\", \"--ol-s3\", \".mrap\", \"--x-s3\", \"--table-s3\"]\n\nexport const CreateBucketModal = ({ isOpen, onClose, onSuccess, existingBuckets = [] }: CreateBucketModalProps) => {\n const { t } = useLingui()\n const projectId = useProjectId()\n const [bucketName, setBucketName] = useState(\"\")\n const [nameError, setNameError] = useState<string | null>(null)\n const [submitError, setSubmitError] = useState<string | null>(null)\n const [enableVersioning, setEnableVersioning] = useState(false)\n\n const { trackClose, markSubmitted, resetTracking } = useModalTracking({\n isOpen,\n actionPrefix: \"storage.ceph.bucket.create\",\n })\n\n const utils = trpcReact.useUtils()\n\n const createBucketMutation = trpcReact.storage.ceph.containers.create.useMutation({\n onSuccess: () => {\n utils.storage.ceph.containers.list.invalidate()\n const name = bucketName.trim()\n onSuccess?.(name)\n handleClose()\n },\n onError: (error) => {\n if (error.data?.code === \"CONFLICT\") {\n setNameError(t`A bucket with this name already exists`)\n setSubmitError(null)\n } else {\n setSubmitError(error.message || t`The bucket could not be created. Try again or choose a different name.`)\n }\n\n resetTracking()\n },\n })\n\n const handleClose = () => {\n trackClose()\n setBucketName(\"\")\n setNameError(null)\n setSubmitError(null)\n setEnableVersioning(false)\n resetTracking()\n createBucketMutation.reset()\n onClose()\n }\n\n const validateName = (name: string): boolean => {\n const trimmed = name.trim()\n\n // Length validation\n if (!trimmed) {\n setNameError(t`Bucket name is required`)\n return false\n }\n if (trimmed.length < 3) {\n setNameError(t`Bucket name must be at least 3 characters`)\n return false\n }\n if (trimmed.length > 63) {\n setNameError(t`Bucket name must be 63 characters or fewer`)\n return false\n }\n\n // Character set validation (lowercase letters, numbers, periods, hyphens)\n if (!S3_BUCKET_NAME_REGEX.test(trimmed)) {\n setNameError(t`Bucket name must contain only lowercase letters, numbers, periods, and hyphens`)\n return false\n }\n\n // Must start and end with letter or number (already covered by regex, but explicit message)\n if (!/^[a-z0-9]/.test(trimmed) || !/[a-z0-9]$/.test(trimmed)) {\n setNameError(t`Bucket name must start and end with a letter or number`)\n return false\n }\n\n // No consecutive periods\n if (trimmed.includes(\"..\")) {\n setNameError(t`Bucket name must not contain consecutive periods`)\n return false\n }\n\n // Not formatted as IP address\n if (IP_ADDRESS_REGEX.test(trimmed)) {\n setNameError(t`Bucket name must not be formatted as an IP address`)\n return false\n }\n\n // Check reserved prefixes\n for (const prefix of RESERVED_PREFIXES) {\n if (trimmed.startsWith(prefix)) {\n setNameError(t`Bucket name must not start with reserved prefix \"${prefix}\"`)\n return false\n }\n }\n\n // Check reserved suffixes\n for (const suffix of RESERVED_SUFFIXES) {\n if (trimmed.endsWith(suffix)) {\n setNameError(t`Bucket name must not end with reserved suffix \"${suffix}\"`)\n return false\n }\n }\n\n // Fast path against the already-loaded bucket list — catches the common case\n // instantly, without waiting on the server's authoritative CONFLICT response.\n if (existingBuckets.some((b) => b.name === trimmed)) {\n setNameError(t`A bucket with this name already exists`)\n return false\n }\n\n setNameError(null)\n return true\n }\n\n const handleNameChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const value = e.target.value\n setBucketName(value)\n setSubmitError(null)\n if (nameError) validateName(value)\n }\n\n const handleSubmit = () => {\n if (!validateName(bucketName)) return\n setSubmitError(null)\n markSubmitted()\n createBucketMutation.mutate({\n project_id: projectId,\n bucketName: bucketName.trim(),\n enableVersioning,\n })\n }\n\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === \"Enter\") {\n handleSubmit()\n }\n }\n\n if (!isOpen) return null\n\n return (\n <Modal\n title={t`Create Bucket`}\n open={isOpen}\n onCancel={handleClose}\n confirmButtonLabel={createBucketMutation.isPending ? t`Creating...` : t`Create Bucket`}\n onConfirm={handleSubmit}\n cancelButtonLabel={t`Cancel`}\n size=\"small\"\n disableConfirmButton={createBucketMutation.isPending || !bucketName.trim()}\n disableCancelButton={createBucketMutation.isPending}\n disableCloseButton={createBucketMutation.isPending}\n >\n <Stack direction=\"vertical\" gap=\"6\">\n {submitError && (\n <Message\n variant=\"error\"\n dismissible\n onDismiss={() => setSubmitError(null)}\n role=\"alert\"\n aria-live=\"assertive\"\n data-testid=\"create-bucket-error\"\n >\n {submitError}\n </Message>\n )}\n <p className=\"text-theme-default\">\n <Trans>\n S3 bucket names must be 3-63 characters long and contain only lowercase letters, numbers, periods, and\n hyphens. They must start and end with a letter or number, and be globally unique within the cluster.\n </Trans>\n </p>\n <TextInput\n label={t`Bucket name`}\n required\n value={bucketName}\n onChange={handleNameChange}\n onKeyDown={handleKeyDown}\n invalid={!!nameError}\n errortext={nameError || undefined}\n disabled={createBucketMutation.isPending}\n autoFocus\n placeholder={t`my-bucket-name`}\n />\n <Checkbox\n label={t`Enable versioning`}\n helptext={t`Keep multiple versions of objects. Cannot be fully disabled once enabled, only suspended.`}\n checked={enableVersioning}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) => setEnableVersioning(e.target.checked)}\n disabled={createBucketMutation.isPending}\n />\n </Stack>\n </Modal>\n )\n}\n","import { useEffect, useState } from \"react\"\nimport { useNavigate, useParams } from \"@tanstack/react-router\"\nimport {\n Button,\n Checkbox,\n DataGrid,\n DataGridHeadCell,\n DataGridRow,\n DataGridCell,\n PopupMenu,\n PopupMenuItem,\n PopupMenuOptions,\n PopupMenuToggle,\n Status,\n} from \"@cloudoperators/juno-ui-components\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { Bucket } from \"@/server/Storage/types/ceph\"\nimport { formatBytesBinary } from \"@/client/utils/formatBytes\"\nimport { useVirtualizedTableBody } from \"@/client/hooks/useVirtualizedTableBody\"\nimport { CreateBucketModal } from \"./CreateBucketModal\"\nimport { EmptyBucketModal } from \"./EmptyBucketModal\"\nimport { DeleteBucketModal } from \"./DeleteBucketModal\"\n\ninterface BucketTableViewProps {\n buckets: Bucket[]\n createModalOpen: boolean\n setCreateModalOpen: (open: boolean) => void\n onCreateSuccess: (bucketName: string) => void\n onEmptySuccess: (bucketName: string, deletedCount: number) => void\n onEmptyError: (bucketName: string, errorMessage: string) => void\n onDeleteSuccess: (bucketName: string) => void\n onDeleteError: (bucketName: string, errorMessage: string) => void\n existingBuckets?: Bucket[]\n selectedBuckets: string[]\n setSelectedBuckets: (buckets: string[]) => void\n // When false, the selection column (header select-all + per-row checkboxes) is dropped.\n hasAnyBulkAction?: boolean\n canEmptyBucket: boolean\n canDeleteBucket: boolean\n}\n\nexport const BucketTableView = ({\n buckets,\n createModalOpen,\n setCreateModalOpen,\n onCreateSuccess,\n onEmptySuccess,\n onEmptyError,\n onDeleteSuccess,\n onDeleteError,\n existingBuckets = [],\n selectedBuckets,\n setSelectedBuckets,\n hasAnyBulkAction = true,\n canEmptyBucket,\n canDeleteBucket,\n}: BucketTableViewProps) => {\n const { projectId, provider, storageType } = useParams({ strict: false })\n const { t } = useLingui()\n const navigate = useNavigate()\n\n const [scrollbarWidth, setScrollbarWidth] = useState(0)\n const [emptyModalBucket, setEmptyModalBucket] = useState<Bucket | null>(null)\n const [deleteModalBucket, setDeleteModalBucket] = useState<Bucket | null>(null)\n\n // Height measured from the space actually left below the table, plus a\n // virtualizer that stays silent until that height is known.\n const {\n ref: tableBodyRef,\n elementRef: parentRef,\n height: bodyHeight,\n virtualItems,\n totalSize,\n measureElement,\n } = useVirtualizedTableBody({ count: buckets.length })\n\n // Calculate scrollbar width\n useEffect(() => {\n if (parentRef.current) {\n const width = parentRef.current.offsetWidth - parentRef.current.clientWidth\n setScrollbarWidth(width)\n }\n }, [buckets.length, bodyHeight])\n\n // Format date to localized string\n const formatDate = (dateString: string): string => {\n try {\n const date = new Date(dateString)\n return date.toLocaleString()\n } catch {\n return t`N/A`\n }\n }\n\n const handleSelectBucket = (bucketName: string) => {\n if (selectedBuckets.includes(bucketName)) {\n setSelectedBuckets(selectedBuckets.filter((name) => name !== bucketName))\n } else {\n setSelectedBuckets([...selectedBuckets, bucketName])\n }\n }\n const isEmpty = !buckets || buckets.length === 0\n\n // Column template — drops the leading 40px selection track when bulk actions are unavailable.\n // The header and the absolutely-positioned virtual rows must share an identical track string.\n const columnCount = hasAnyBulkAction ? 6 : 5\n const gridColumnTemplate = hasAnyBulkAction\n ? \"40px minmax(200px, 2fr) minmax(100px, 1fr) minmax(180px, 2fr) minmax(100px, 1fr) 60px\"\n : \"minmax(200px, 2fr) minmax(100px, 1fr) minmax(180px, 2fr) minmax(100px, 1fr) 60px\"\n\n return (\n <>\n <div className=\"relative\">\n {/* Table Header with scrollbar padding */}\n <div style={{ paddingRight: `${scrollbarWidth}px` }}>\n <DataGrid\n columns={columnCount}\n minContentColumns={[columnCount - 1]}\n gridColumnTemplate={gridColumnTemplate}\n className=\"buckets\"\n data-testid=\"buckets-table-header\"\n >\n <DataGridRow>\n {hasAnyBulkAction && <DataGridHeadCell />}\n <DataGridHeadCell>\n <Trans>Bucket Name</Trans>\n </DataGridHeadCell>\n <DataGridHeadCell>\n <Trans>Object Count</Trans>\n </DataGridHeadCell>\n <DataGridHeadCell>\n <Trans>Last Modified</Trans>\n </DataGridHeadCell>\n <DataGridHeadCell>\n <Trans>Total Size</Trans>\n </DataGridHeadCell>\n <DataGridHeadCell style={{ marginRight: `-${scrollbarWidth}px` }} />\n </DataGridRow>\n\n {isEmpty && (\n <DataGridRow>\n <DataGridCell colSpan={columnCount}>\n <Status\n status=\"empty\"\n title={t`No buckets found`}\n body={t`There are no buckets available with the current search criteria. Try adjusting your search term.`}\n />\n </DataGridCell>\n </DataGridRow>\n )}\n </DataGrid>\n </div>\n\n {/* Virtualized Table Body — sized to the space actually left below the\n table, so banners above it shrink the table instead of growing the\n page. */}\n <div\n ref={tableBodyRef}\n className=\"overflow-auto\"\n style={{ height: `${bodyHeight ?? 0}px` }}\n data-testid=\"buckets-table-body\"\n >\n <DataGrid\n columns={columnCount}\n minContentColumns={[columnCount - 1]}\n gridColumnTemplate={gridColumnTemplate}\n style={{\n height: `${totalSize}px`,\n width: \"100%\",\n position: \"relative\",\n }}\n >\n {virtualItems.map((virtualRow) => {\n const bucket = buckets[virtualRow.index]\n const isSelected = selectedBuckets.includes(bucket.name)\n\n const handleRowNavigate = () =>\n navigate({\n to: \"/projects/$projectId/storage/$provider/$storageType/$containerName/objects\",\n params: {\n projectId: projectId ?? \"\",\n provider: (provider as string) ?? \"ceph\",\n storageType: (storageType as string) ?? \"buckets\",\n containerName: bucket.name,\n },\n })\n\n return (\n <DataGridRow\n key={bucket.name}\n data-index={virtualRow.index}\n ref={measureElement}\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n width: \"100%\",\n transform: `translateY(${virtualRow.start}px)`,\n display: \"grid\",\n gridTemplateColumns: gridColumnTemplate,\n alignItems: \"stretch\",\n }}\n data-testid={`bucket-row-${bucket.name}`}\n tabIndex={0}\n onClick={handleRowNavigate}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault()\n handleRowNavigate()\n }\n }}\n >\n {hasAnyBulkAction && (\n <DataGridCell\n onClick={(e) => e.stopPropagation()}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.stopPropagation()\n }\n }}\n >\n <Checkbox\n checked={isSelected}\n onChange={() => handleSelectBucket(bucket.name)}\n data-testid={`select-bucket-${bucket.name}`}\n />\n </DataGridCell>\n )}\n <DataGridCell className=\"min-w-0 overflow-hidden\">\n <span className=\"block truncate\" title={bucket.name}>\n {bucket.name}\n </span>\n </DataGridCell>\n <DataGridCell>{bucket.count.toLocaleString()}</DataGridCell>\n <DataGridCell>{formatDate(bucket.last_modified || bucket.creationDate || \"\")}</DataGridCell>\n <DataGridCell>{formatBytesBinary(bucket.bytes)}</DataGridCell>\n <DataGridCell onClick={(e) => e.stopPropagation()}>\n <PopupMenu>\n <PopupMenuToggle as=\"div\">\n <Button\n icon=\"moreVert\"\n title={t`Bucket actions`}\n aria-label={t`Bucket actions`}\n className=\"!bg-transparent\"\n />\n </PopupMenuToggle>\n <PopupMenuOptions>\n <PopupMenuItem\n label={t`Show Details`}\n onClick={handleRowNavigate}\n data-testid={`show-details-action-${bucket.name}`}\n />\n {canEmptyBucket && (\n <PopupMenuItem\n label={t`Empty Bucket`}\n onClick={() => setEmptyModalBucket(bucket)}\n data-testid={`empty-action-${bucket.name}`}\n />\n )}\n {canDeleteBucket && (\n <PopupMenuItem\n label={t`Delete Bucket`}\n onClick={() => setDeleteModalBucket(bucket)}\n data-testid={`delete-action-${bucket.name}`}\n />\n )}\n </PopupMenuOptions>\n </PopupMenu>\n </DataGridCell>\n </DataGridRow>\n )\n })}\n </DataGrid>\n </div>\n </div>\n\n <CreateBucketModal\n isOpen={createModalOpen}\n onClose={() => setCreateModalOpen(false)}\n onSuccess={onCreateSuccess}\n existingBuckets={existingBuckets}\n />\n\n <EmptyBucketModal\n isOpen={emptyModalBucket !== null}\n bucket={emptyModalBucket}\n onClose={() => setEmptyModalBucket(null)}\n onSuccess={onEmptySuccess}\n onError={onEmptyError}\n />\n\n <DeleteBucketModal\n isOpen={deleteModalBucket !== null}\n bucket={deleteModalBucket}\n onClose={() => setDeleteModalBucket(null)}\n onSuccess={onDeleteSuccess}\n onError={onDeleteError}\n />\n </>\n )\n}\n","import { ReactNode } from \"react\"\nimport { NotificationOptions } from \"@cloudoperators/juno-ui-components\"\nimport { Trans, Plural } from \"@lingui/react/macro\"\n\ntype ToastReturnType = { message: ReactNode } & NotificationOptions\n\nexport const getBucketCreatedToast = (bucketName: string): ToastReturnType => ({\n message: <Trans>Bucket Created</Trans>,\n description: <Trans>Bucket \"{bucketName}\" was successfully created.</Trans>,\n})\n\nexport const getBucketCreateErrorToast = (bucketName: string, errorMessage: string): ToastReturnType => ({\n message: <Trans>Failed to Create Bucket</Trans>,\n description: (\n <Trans>\n Could not create bucket \"{bucketName}\": {errorMessage}\n </Trans>\n ),\n})\n\nexport const getBucketEmptiedToast = (bucketName: string, deletedCount: number): ToastReturnType => ({\n message: <Trans>Bucket Emptied</Trans>,\n description:\n deletedCount === 0 ? (\n <Trans>Bucket \"{bucketName}\" was already empty.</Trans>\n ) : deletedCount === 1 ? (\n <Trans>\n Bucket \"{bucketName}\" was successfully emptied. {deletedCount} object deleted.\n </Trans>\n ) : (\n <Trans>\n Bucket \"{bucketName}\" was successfully emptied. {deletedCount} objects deleted.\n </Trans>\n ),\n})\n\nexport const getBucketEmptyErrorToast = (bucketName: string, errorMessage: string): ToastReturnType => ({\n message: <Trans>Failed to Empty Bucket</Trans>,\n description: (\n <Trans>\n Could not empty bucket \"{bucketName}\": {errorMessage}\n </Trans>\n ),\n})\n\nexport const getBucketDeletedToast = (bucketName: string): ToastReturnType => ({\n message: <Trans>Bucket Deleted</Trans>,\n description: <Trans>Bucket \"{bucketName}\" was successfully deleted.</Trans>,\n})\n\nexport const getBucketDeleteErrorToast = (bucketName: string, errorMessage: string): ToastReturnType => ({\n message: <Trans>Failed to Delete Bucket</Trans>,\n description: (\n <Trans>\n Could not delete bucket \"{bucketName}\": {errorMessage}\n </Trans>\n ),\n})\n\nexport const getBucketsEmptyCompleteToast = (\n emptiedCount: number,\n totalDeleted: number,\n errors: string[]\n): ToastReturnType => {\n const hasErrors = errors.length > 0\n const totalBuckets = emptiedCount + errors.length\n const errorsLength = errors.length\n\n return {\n message: hasErrors ? <Trans>Empty All Completed with Errors</Trans> : <Trans>All Buckets Emptied</Trans>,\n description: hasErrors ? (\n <Trans>\n Successfully emptied {emptiedCount} of {totalBuckets}{\" \"}\n <Plural value={totalBuckets} one=\"bucket\" other=\"buckets\" />, deleting {totalDeleted}{\" \"}\n <Plural value={totalDeleted} one=\"object\" other=\"objects\" />. {errorsLength}{\" \"}\n <Plural value={errorsLength} one=\"bucket\" other=\"buckets\" /> failed.\n </Trans>\n ) : (\n <Trans>\n Successfully emptied {emptiedCount} <Plural value={emptiedCount} one=\"bucket\" other=\"buckets\" />, deleting{\" \"}\n {totalDeleted} <Plural value={totalDeleted} one=\"object\" other=\"objects\" />.\n </Trans>\n ),\n }\n}\n\n// ── Versioning operations ──────────────────────────────────────────────────\n\nexport const getVersioningEnabledToast = (bucketName: string): ToastReturnType => ({\n message: <Trans>Versioning Enabled</Trans>,\n description: <Trans>Versioning was successfully enabled for bucket \"{bucketName}\".</Trans>,\n})\n\nexport const getVersioningEnableErrorToast = (bucketName: string, errorMessage: string): ToastReturnType => ({\n message: <Trans>Failed to Enable Versioning</Trans>,\n description: (\n <Trans>\n Could not enable versioning for bucket \"{bucketName}\": {errorMessage}\n </Trans>\n ),\n})\n\nexport const getVersioningSuspendedToast = (bucketName: string): ToastReturnType => ({\n message: <Trans>Versioning Suspended</Trans>,\n description: <Trans>Versioning was successfully suspended for bucket \"{bucketName}\".</Trans>,\n})\n\nexport const getVersioningSuspendErrorToast = (bucketName: string, errorMessage: string): ToastReturnType => ({\n message: <Trans>Failed to Suspend Versioning</Trans>,\n description: (\n <Trans>\n Could not suspend versioning for bucket \"{bucketName}\": {errorMessage}\n </Trans>\n ),\n})\n\n// ── Bucket policy operations ───────────────────────────────────────────────\n\nexport const getBucketPolicySavedToast = (bucketName: string): ToastReturnType => ({\n message: <Trans>Bucket Policy Saved</Trans>,\n description: <Trans>Bucket policy was successfully saved for \"{bucketName}\".</Trans>,\n})\n\nexport const getBucketPolicySaveErrorToast = (bucketName: string, errorMessage: string): ToastReturnType => ({\n message: <Trans>Failed to Save Bucket Policy</Trans>,\n description: (\n <Trans>\n Could not save bucket policy for \"{bucketName}\": {errorMessage}\n </Trans>\n ),\n})\n\nexport const getBucketPolicyDeletedToast = (bucketName: string): ToastReturnType => ({\n message: <Trans>Policy Deleted</Trans>,\n description: <Trans>Bucket policy was successfully deleted from \"{bucketName}\".</Trans>,\n})\n\nexport const getBucketPolicyDeleteErrorToast = (bucketName: string, errorMessage: string): ToastReturnType => ({\n message: <Trans>Failed to Delete Policy</Trans>,\n description: (\n <Trans>\n Could not delete bucket policy from \"{bucketName}\": {errorMessage}\n </Trans>\n ),\n})\n\n// ── Delete versions operation ──────────────────────────────────────────────\n\nexport const getVersionsDeletedToast = (bucketName: string, deletedCount: number): ToastReturnType => ({\n message: <Trans>Versions Deleted</Trans>,\n description:\n deletedCount === 0 ? (\n <Trans>No versions to delete in bucket \"{bucketName}\".</Trans>\n ) : deletedCount === 1 ? (\n <Trans>\n Successfully deleted {deletedCount} version from bucket \"{bucketName}\".\n </Trans>\n ) : (\n <Trans>\n Successfully deleted {deletedCount} versions from bucket \"{bucketName}\".\n </Trans>\n ),\n})\n\nexport const getVersionsDeleteErrorToast = (bucketName: string, errorMessage: string): ToastReturnType => ({\n message: <Trans>Failed to Delete Versions</Trans>,\n description: (\n <Trans>\n Could not delete versions from bucket \"{bucketName}\": {errorMessage}\n </Trans>\n ),\n})\n\n// ── CORS configuration operations ──────────────────────────────────────────\n\nexport const getCorsSavedToast = (bucketName: string): ToastReturnType => ({\n message: <Trans>CORS Configuration Saved</Trans>,\n description: <Trans>CORS configuration was successfully saved for bucket \"{bucketName}\".</Trans>,\n})\n\nexport const getCorsSaveErrorToast = (bucketName: string, errorMessage: string): ToastReturnType => ({\n message: <Trans>Failed to Save CORS Configuration</Trans>,\n description: (\n <Trans>\n Could not save CORS configuration for bucket \"{bucketName}\": {errorMessage}\n </Trans>\n ),\n})\n\nexport const getCorsRuleDeletedToast = (bucketName: string, ruleId?: string): ToastReturnType => ({\n message: <Trans>CORS Rule Deleted</Trans>,\n description: ruleId ? (\n <Trans>\n Rule \"{ruleId}\" was successfully deleted from bucket \"{bucketName}\".\n </Trans>\n ) : (\n <Trans>CORS rule was successfully deleted from bucket \"{bucketName}\".</Trans>\n ),\n})\n\nexport const getCorsRuleDeleteErrorToast = (\n bucketName: string,\n errorMessage: string,\n ruleId?: string\n): ToastReturnType => ({\n message: <Trans>Failed to Delete CORS Rule</Trans>,\n description: ruleId ? (\n <Trans>\n Could not delete rule \"{ruleId}\" from bucket \"{bucketName}\": {errorMessage}\n </Trans>\n ) : (\n <Trans>\n Could not delete CORS rule from bucket \"{bucketName}\": {errorMessage}\n </Trans>\n ),\n})\n\nexport const getCorsRulesDeletedToast = (bucketName: string, count: number): ToastReturnType => ({\n message: <Plural value={count} one=\"CORS Rule Deleted\" other=\"CORS Rules Deleted\" />,\n description:\n count === 1 ? (\n <Trans>\n Successfully deleted {count} CORS rule from bucket \"{bucketName}\".\n </Trans>\n ) : (\n <Trans>\n Successfully deleted {count} CORS rules from bucket \"{bucketName}\".\n </Trans>\n ),\n})\n\nexport const getCorsRulesDeleteErrorToast = (\n bucketName: string,\n count: number,\n errorMessage: string\n): ToastReturnType => ({\n message: <Plural value={count} one=\"Failed to Delete CORS Rule\" other=\"Failed to Delete CORS Rules\" />,\n description:\n count === 1 ? (\n <Trans>\n Could not delete {count} CORS rule from bucket \"{bucketName}\": {errorMessage}\n </Trans>\n ) : (\n <Trans>\n Could not delete {count} CORS rules from bucket \"{bucketName}\": {errorMessage}\n </Trans>\n ),\n})\n\n// ── Per-rule Lifecycle operations ───────────────────────────────────────────\n\nexport const getLifecycleSavedToast = (bucketName: string): ToastReturnType => ({\n message: <Trans>Lifecycle Rule Saved</Trans>,\n description: <Trans>Lifecycle rule was successfully saved for bucket \"{bucketName}\".</Trans>,\n})\n\nexport const getLifecycleSaveErrorToast = (bucketName: string, errorMessage: string): ToastReturnType => ({\n message: <Trans>Failed to Save Lifecycle Rule</Trans>,\n description: (\n <Trans>\n Could not save lifecycle rule for bucket \"{bucketName}\": {errorMessage}\n </Trans>\n ),\n})\n\nexport const getLifecycleRuleDeletedToast = (bucketName: string, ruleId?: string): ToastReturnType => ({\n message: <Trans>Lifecycle Rule Deleted</Trans>,\n description: ruleId ? (\n <Trans>\n Rule \"{ruleId}\" was successfully deleted from bucket \"{bucketName}\".\n </Trans>\n ) : (\n <Trans>Lifecycle rule was successfully deleted from bucket \"{bucketName}\".</Trans>\n ),\n})\n\nexport const getLifecycleRuleDeleteErrorToast = (\n bucketName: string,\n errorMessage: string,\n ruleId?: string\n): ToastReturnType => ({\n message: <Trans>Failed to Delete Lifecycle Rule</Trans>,\n description: ruleId ? (\n <Trans>\n Could not delete rule \"{ruleId}\" from bucket \"{bucketName}\": {errorMessage}\n </Trans>\n ) : (\n <Trans>\n Could not delete lifecycle rule from bucket \"{bucketName}\": {errorMessage}\n </Trans>\n ),\n})\n\nexport const getLifecycleRulesDeletedToast = (bucketName: string, count: number): ToastReturnType => ({\n message: <Plural value={count} one=\"Lifecycle Rule Deleted\" other=\"Lifecycle Rules Deleted\" />,\n description:\n count === 1 ? (\n <Trans>\n Successfully deleted {count} lifecycle rule from bucket \"{bucketName}\".\n </Trans>\n ) : (\n <Trans>\n Successfully deleted {count} lifecycle rules from bucket \"{bucketName}\".\n </Trans>\n ),\n})\n\nexport const getLifecycleRulesDeleteErrorToast = (\n bucketName: string,\n count: number,\n errorMessage: string\n): ToastReturnType => ({\n message: <Plural value={count} one=\"Failed to Delete Lifecycle Rule\" other=\"Failed to Delete Lifecycle Rules\" />,\n description:\n count === 1 ? (\n <Trans>\n Could not delete {count} lifecycle rule from bucket \"{bucketName}\": {errorMessage}\n </Trans>\n ) : (\n <Trans>\n Could not delete {count} lifecycle rules from bucket \"{bucketName}\": {errorMessage}\n </Trans>\n ),\n})\n","import { z } from \"zod\"\nimport { useForm, useStore } from \"@tanstack/react-form\"\nimport { useState } from \"react\"\nimport { Trans, useLingui, Plural } from \"@lingui/react/macro\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { Modal, Status, Stack, Form, FormSection, TextInput } from \"@cloudoperators/juno-ui-components\"\nimport { Bucket } from \"@/server/Storage/types/ceph\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport { useModalTracking } from \"@/client/hooks/useModalTracking\"\n\nconst MAX_VISIBLE = 20\n\ninterface EmptyBucketsResult {\n emptiedCount: number\n totalDeleted: number\n errors: string[]\n}\n\ninterface EmptyBucketsModalProps {\n isOpen: boolean\n buckets: Bucket[]\n onClose: () => void\n onComplete?: (result: EmptyBucketsResult) => void\n}\n\nexport const EmptyBucketsModal = ({ isOpen, buckets, onClose, onComplete }: EmptyBucketsModalProps) => {\n const { t } = useLingui()\n const projectId = useProjectId()\n const [progress, setProgress] = useState<{ current: number; total: number } | null>(null)\n\n const { trackClose, markSubmitted, resetTracking } = useModalTracking({\n isOpen,\n actionPrefix: \"storage.ceph.buckets.empty\",\n })\n\n const formSchema = z.object({\n confirm: z.string().refine((value) => value === \"empty\", {\n message: t`Type \"empty\" 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 (emptyBucketMutation.isPending || progress !== null) return\n\n markSubmitted()\n let emptiedCount = 0\n let totalDeleted = 0\n const errors: string[] = []\n const total = buckets.length\n\n for (let i = 0; i < buckets.length; i++) {\n setProgress({ current: i + 1, total })\n const bucket = buckets[i]\n\n try {\n const deleted = await emptyBucketMutation.mutateAsync({\n project_id: projectId,\n containerName: bucket.name,\n })\n totalDeleted += deleted\n emptiedCount++\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n errors.push(`${bucket.name}: ${message}`)\n }\n }\n\n if (emptiedCount > 0) {\n await utils.storage.ceph.containers.list.invalidate()\n await utils.storage.ceph.objects.list.invalidate()\n }\n\n onComplete?.({ emptiedCount, totalDeleted, errors })\n handleClose()\n },\n })\n\n const canEmpty = useStore(form.store, (state) => state.isSubmitting || state.values.confirm !== \"empty\")\n\n const utils = trpcReact.useUtils()\n const emptyBucketMutation = trpcReact.storage.ceph.objects.deleteAll.useMutation()\n\n const handleClose = () => {\n trackClose()\n emptyBucketMutation.reset()\n setProgress(null)\n form.reset()\n resetTracking()\n onClose()\n }\n\n if (!isOpen || buckets.length === 0) return null\n\n const totalCount = buckets.length\n const visibleBuckets = buckets.slice(0, MAX_VISIBLE)\n const hiddenCount = totalCount - visibleBuckets.length\n const isPending = emptyBucketMutation.isPending || progress !== null\n const progressCurrent = progress?.current\n const progressTotal = progress?.total\n\n return (\n <Modal\n title={<Plural value={totalCount} one=\"Empty Bucket\" other=\"Empty Buckets\" />}\n open={isOpen}\n onCancel={handleClose}\n confirmButtonLabel={isPending ? t`Emptying...` : totalCount === 1 ? t`Empty Bucket` : t`Empty Buckets`}\n confirmButtonVariant=\"primary-danger\"\n cancelButtonLabel={t`Cancel`}\n onConfirm={form.handleSubmit}\n disableConfirmButton={isPending || canEmpty}\n disableCancelButton={isPending}\n disableCloseButton={isPending}\n size=\"small\"\n >\n {isPending ? (\n <Status\n status=\"progress\"\n title={progress ? t`Emptying Bucket ${progressCurrent} of ${progressTotal}, Please Wait...` : t`Emptying...`}\n className=\"mt-0\"\n />\n ) : (\n <Stack direction=\"vertical\" gap=\"4\">\n <p className=\"text-theme-default\">\n <Trans>\n This will permanently delete all objects from {totalCount} selected{\" \"}\n <Plural value={totalCount} one=\"bucket\" other=\"buckets\" />. This action cannot be undone.\n </Trans>\n </p>\n\n <div>\n <p className=\"text-sm font-semibold\">\n <Trans>Buckets to empty:</Trans>\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 {visibleBuckets.map((bucket) => (\n <div\n key={bucket.name}\n className=\"text-theme-default overflow-x-hidden text-sm [overflow-wrap:anywhere]\"\n >\n {bucket.name}\n </div>\n ))}\n {hiddenCount > 0 && (\n <div className=\"text-theme-light pt-2 text-sm\">\n <Trans>… and {hiddenCount} more</Trans>\n </div>\n )}\n </Stack>\n </div>\n </div>\n\n <Form\n className=\"mb-0\"\n id=\"empty-buckets-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 id={field.name}\n name={field.name}\n label={t`Type \"empty\" to confirm`}\n value={field.state.value}\n onChange={(e) => field.handleChange(e.target.value)}\n placeholder=\"empty\"\n autoFocus\n disabled={isPending}\n required\n />\n )}\n />\n </FormSection>\n </Form>\n </Stack>\n )}\n </Modal>\n )\n}\n","import { Trans, useLingui } from \"@lingui/react/macro\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport { useCephPermissions } from \"../hooks/useCephPermissions\"\nimport { Button, Stack, Message, Status, toast } from \"@cloudoperators/juno-ui-components\"\n\ninterface CredentialPromptProps {\n onSuccess: () => void\n}\n\nexport function CredentialPrompt({ onSuccess }: CredentialPromptProps) {\n const { t } = useLingui()\n const projectId = useProjectId()\n const { permissions, isLoading: isLoadingPermissions, isError: isPermissionsError } = useCephPermissions(projectId)\n const utils = trpcReact.useUtils()\n\n const createMutation = trpcReact.storage.ceph.ec2Credentials.create.useMutation({\n onSuccess: () => {\n utils.storage.ceph.ec2Credentials.list.invalidate()\n onSuccess()\n },\n onError: (err) => {\n const errorMessage = err.message\n toast.error(<Trans>Failed to create credential: {errorMessage}</Trans>)\n },\n })\n\n return (\n <Stack direction=\"vertical\" gap=\"4\" className=\"mt-8 max-w-lg\">\n <h2 className=\"text-lg font-semibold\">\n <Trans>S3 Object Storage: Setup Required</Trans>\n </h2>\n <p className=\"text-theme-default\">\n <Trans>\n To access S3 Object Storage, you need EC2 credentials (access key + secret key). These credentials\n authenticate your requests to the Ceph storage backend.\n </Trans>\n </p>\n <p className=\"text-theme-default text-sm\">\n <Trans>\n Click the button below to automatically generate credentials for this project. You only need to do this once.\n </Trans>\n </p>\n {isLoadingPermissions ? (\n <Status status=\"progress\" title={t`Checking Permissions...`} />\n ) : isPermissionsError ? (\n <Status\n status=\"error\"\n title={t`Could Not Check Permissions`}\n body={t`Could not verify whether you can create S3 credentials. Reload the page or try again later.`}\n />\n ) : permissions.canCreateCredential ? (\n <div>\n <Button\n onClick={() => projectId && createMutation.mutate({ project_id: projectId })}\n disabled={createMutation.isPending || !projectId}\n >\n {createMutation.isPending ? <Trans>Creating Credentials...</Trans> : <Trans>Create S3 Credentials</Trans>}\n </Button>\n </div>\n ) : (\n <Message variant=\"info\" title={t`Insufficient permissions`}>\n <Trans>\n You don't have permission to create S3 credentials. Please contact your administrator to request access to\n S3 Object Storage.\n </Trans>\n </Message>\n )}\n </Stack>\n )\n}\n","import type { CorsRuleRead } from \"@/server/Storage/types/ceph\"\n\n/**\n * Convert CorsRuleRead (lenient read schema) to CorsRule (strict write schema)\n *\n * Safe because the data passed validation when read from the server.\n * The only difference is narrowing AllowedMethods from string[] to the specific enum array.\n */\nexport function toCorsRule(\n rule: CorsRuleRead\n): CorsRuleRead & { AllowedMethods: Array<\"GET\" | \"PUT\" | \"POST\" | \"DELETE\" | \"HEAD\"> } {\n return {\n ...rule,\n AllowedMethods: rule.AllowedMethods as Array<\"GET\" | \"PUT\" | \"POST\" | \"DELETE\" | \"HEAD\">,\n }\n}\n","import { useEffect, useState } from \"react\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { Modal, Stack, Status, Message } from \"@cloudoperators/juno-ui-components\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport { useModalTracking } from \"@/client/hooks/useModalTracking\"\nimport { toCorsRule } from \"./utils/corsUtils\"\n\ninterface DeleteCorsRuleModalProps {\n isOpen: boolean\n bucketName: string\n ruleIndex: number\n ruleId?: string\n onClose: () => void\n onSuccess?: (ruleIndex: number) => void\n onError?: (ruleIndex: number, errorMessage: string) => void\n onMutatingChange?: (isMutating: boolean) => void\n}\n\nexport const DeleteCorsRuleModal = ({\n isOpen,\n bucketName,\n ruleIndex,\n ruleId,\n onClose,\n onSuccess,\n onError,\n onMutatingChange,\n}: DeleteCorsRuleModalProps) => {\n const { t } = useLingui()\n const projectId = useProjectId()\n const utils = trpcReact.useUtils()\n const [isVerifying, setIsVerifying] = useState(false)\n\n const { trackClose, markSubmitted, resetTracking } = useModalTracking({\n isOpen,\n actionPrefix: \"storage.ceph.cors.rule.delete\",\n })\n\n // Query to get current CORS rules\n const {\n data: corsData,\n isLoading: isCorsLoading,\n error: corsError,\n } = trpcReact.storage.ceph.cors.get.useQuery(\n {\n project_id: projectId,\n bucketName,\n },\n {\n enabled: isOpen && !!projectId,\n retry: false,\n }\n )\n\n // Set mutation (for updating with remaining rules)\n const setMutation = trpcReact.storage.ceph.cors.set.useMutation({\n onSuccess: () => {\n utils.storage.ceph.cors.get.invalidate()\n onSuccess?.(ruleIndex)\n handleClose()\n },\n onError: (error) => {\n onError?.(ruleIndex, error.message)\n },\n })\n\n // Delete mutation (for removing all CORS config when last rule is deleted)\n const deleteMutation = trpcReact.storage.ceph.cors.delete.useMutation({\n onSuccess: () => {\n utils.storage.ceph.cors.get.invalidate()\n onSuccess?.(ruleIndex)\n handleClose()\n },\n onError: (error) => {\n onError?.(ruleIndex, error.message)\n },\n })\n\n useEffect(() => {\n onMutatingChange?.(setMutation.isPending || deleteMutation.isPending)\n }, [setMutation.isPending, deleteMutation.isPending, onMutatingChange])\n\n useEffect(() => {\n if (!isOpen) {\n setMutation.reset()\n deleteMutation.reset()\n setIsVerifying(false)\n resetTracking()\n }\n }, [isOpen, ruleIndex])\n\n const handleClose = () => {\n trackClose()\n setMutation.reset()\n deleteMutation.reset()\n setIsVerifying(false)\n resetTracking()\n onClose()\n }\n\n const handleDelete = async () => {\n if (isVerifying) return\n\n markSubmitted()\n setIsVerifying(true)\n\n try {\n // Refetch to get fresh data\n const freshData = await utils.storage.ceph.cors.get.fetch({\n project_id: projectId,\n bucketName,\n })\n\n const freshRules = freshData?.corsRules ?? []\n const cachedRule = corsData?.corsRules?.[ruleIndex]\n const freshRule = freshRules[ruleIndex]\n\n // Freshness check\n if (!freshRule || JSON.stringify(freshRule) !== JSON.stringify(cachedRule)) {\n onError?.(ruleIndex, t`The CORS configuration has changed. Please refresh and try again.`)\n return\n }\n\n // Proceed with deletion using fresh data\n const updatedRules = freshRules.filter((_, index) => index !== ruleIndex)\n\n if (updatedRules.length === 0) {\n // If no rules left, delete the entire CORS configuration\n deleteMutation.mutate({\n project_id: projectId,\n bucketName,\n })\n } else {\n // Otherwise, update with the remaining rules\n setMutation.mutate({\n project_id: projectId,\n bucketName,\n corsConfiguration: {\n CORSRules: updatedRules.map(toCorsRule),\n },\n })\n }\n } catch {\n onError?.(ruleIndex, t`Failed to verify CORS configuration`)\n } finally {\n setIsVerifying(false)\n }\n }\n\n if (!isOpen) return null\n\n const ruleDisplayName = ruleId || `Rule #${ruleIndex + 1}`\n const hasRules = (corsData?.corsRules ?? []).length > 0\n const isDeleting = setMutation.isPending || deleteMutation.isPending\n\n return (\n <Modal\n title={t`Delete CORS Rule`}\n open={isOpen}\n onCancel={handleClose}\n confirmButtonLabel={t`Delete CORS Rule`}\n confirmButtonVariant=\"primary-danger\"\n onConfirm={handleDelete}\n cancelButtonLabel={t`Cancel`}\n size=\"small\"\n disableConfirmButton={isDeleting || isCorsLoading || !hasRules || !!corsError || isVerifying}\n >\n <Stack direction=\"vertical\" gap=\"4\">\n {isCorsLoading && <Status status=\"progress\" title={t`Loading CORS Rules...`} className=\"mt-0\" />}\n\n {corsError && (\n <Status status=\"error\" title={t`Failed to Load CORS Rules`} body={corsError.message} className=\"mt-0\" />\n )}\n\n {!isCorsLoading && !corsError && !hasRules && (\n <Status\n status=\"empty\"\n title={t`No Rules Found`}\n body={t`This bucket does not have any CORS rules.`}\n className=\"mt-0\"\n />\n )}\n\n {!isCorsLoading && !corsError && hasRules && (\n <>\n <p className=\"text-theme-default\">\n <Trans>\n Are you sure you want to delete <strong>{ruleDisplayName}</strong> from bucket{\" \"}\n <strong>{bucketName}</strong>?\n </Trans>\n </p>\n <p className=\"text-theme-default\">\n <Trans>This action cannot be undone.</Trans>\n </p>\n </>\n )}\n\n {setMutation.isError && (\n <Message variant=\"error\" title={t`Failed to delete rule`}>\n {setMutation.error?.message}\n </Message>\n )}\n\n {deleteMutation.isError && (\n <Message variant=\"error\" title={t`Failed to delete rule`}>\n {deleteMutation.error?.message}\n </Message>\n )}\n </Stack>\n </Modal>\n )\n}\n","import { useState } from \"react\"\nimport {\n DataGrid,\n DataGridHeadCell,\n DataGridRow,\n DataGridCell,\n Stack,\n PopupMenu,\n PopupMenuItem,\n PopupMenuOptions,\n Checkbox,\n Status,\n toast,\n} from \"@cloudoperators/juno-ui-components\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport type { CorsRuleRead } from \"@/server/Storage/types/ceph\"\nimport { DeleteCorsRuleModal } from \"./DeleteCorsRuleModal\"\nimport { getCorsRuleDeletedToast, getCorsRuleDeleteErrorToast } from \"./BucketToastNotifications\"\n\ninterface CorsRuleWithIndex {\n rule: CorsRuleRead\n originalIndex: number\n}\n\ninterface CorsRulesTableProps {\n bucketName: string\n rulesWithIndices: CorsRuleWithIndex[]\n selectedIndices: number[]\n onToggleSelectRule: (index: number) => void\n onEditRule: (index: number) => void\n onDeleteRule?: (index: number) => void\n isMutating?: boolean\n isFiltered?: boolean\n canUpdateCors: boolean\n canDeleteCors: boolean\n}\n\n/**\n * Data grid for displaying and managing CORS rules\n *\n * Displays up to 100 rules (S3 limit) in a simple table.\n * Supports search/filter by Rule ID.\n */\nexport function CorsRulesTable({\n bucketName,\n rulesWithIndices,\n selectedIndices,\n onToggleSelectRule,\n onEditRule,\n onDeleteRule,\n isMutating = false,\n isFiltered = false,\n canUpdateCors,\n canDeleteCors,\n}: CorsRulesTableProps) {\n const { t } = useLingui()\n\n const [isRowDeleteMutating, setIsRowDeleteMutating] = useState(false)\n\n const [deleteModalState, setDeleteModalState] = useState<{\n isOpen: boolean\n ruleIndex: number\n ruleId?: string\n }>({\n isOpen: false,\n ruleIndex: -1,\n ruleId: undefined,\n })\n\n const handleOpenDeleteModal = (index: number, ruleId?: string) => {\n setDeleteModalState({\n isOpen: true,\n ruleIndex: index,\n ruleId,\n })\n }\n\n const handleCloseDeleteModal = () => {\n setDeleteModalState({\n isOpen: false,\n ruleIndex: -1,\n ruleId: undefined,\n })\n }\n\n const handleDeleteSuccess = (index: number) => {\n const { message, ...options } = getCorsRuleDeletedToast(bucketName, deleteModalState.ruleId)\n toast.success(message, options)\n // Call parent callback if provided (for draft state updates in parent)\n onDeleteRule?.(index)\n }\n\n const handleDeleteError = (_index: number, errorMessage: string) => {\n const { message, ...options } = getCorsRuleDeleteErrorToast(bucketName, errorMessage, deleteModalState.ruleId)\n toast.error(message, options)\n }\n\n const effectiveIsMutating = isMutating || isRowDeleteMutating\n\n const isEmpty = rulesWithIndices.length === 0\n const columnCount = canDeleteCors ? 8 : 7\n\n return (\n <Stack direction=\"vertical\" gap=\"4\">\n {/* Rules Table */}\n <DataGrid columns={columnCount} minContentColumns={canDeleteCors ? [0, columnCount - 1] : [columnCount - 1]}>\n <DataGridRow>\n {canDeleteCors && (\n <DataGridHeadCell>\n <span className=\"sr-only\">\n <Trans>Select</Trans>\n </span>\n </DataGridHeadCell>\n )}\n <DataGridHeadCell>{t`Rule ID`}</DataGridHeadCell>\n <DataGridHeadCell>{t`Allowed Origins`}</DataGridHeadCell>\n <DataGridHeadCell>{t`Allowed Methods`}</DataGridHeadCell>\n <DataGridHeadCell>{t`Allowed Headers`}</DataGridHeadCell>\n <DataGridHeadCell>{t`Expose Headers`}</DataGridHeadCell>\n <DataGridHeadCell>{t`Max Age`}</DataGridHeadCell>\n <DataGridHeadCell></DataGridHeadCell>\n </DataGridRow>\n {isEmpty ? (\n <DataGridRow>\n <DataGridCell colSpan={columnCount}>\n {isFiltered ? (\n <Status status=\"no-matches\" title={t`No CORS Rules Matching the Current Search Criteria.`} />\n ) : (\n <Status status=\"empty\" title={t`There Are No CORS Rules for This Bucket`} />\n )}\n </DataGridCell>\n </DataGridRow>\n ) : (\n rulesWithIndices.map(({ rule, originalIndex }) => {\n // Rules are keyed by array index - they have no stable server-side id.\n // ID field is optional and may be absent or duplicated.\n // originalIndex is the contract with parent's onEditRule(index) / onDeleteRule(index).\n const key = originalIndex\n const ruleLabel = rule.ID || String(originalIndex + 1)\n const hasAnyRowAction = canUpdateCors || canDeleteCors\n\n return (\n <DataGridRow key={key} data-testid={`cors-rule-row-${originalIndex}`}>\n {canDeleteCors && (\n <DataGridCell onClick={(e) => e.stopPropagation()}>\n <Checkbox\n checked={selectedIndices.includes(originalIndex)}\n onChange={() => onToggleSelectRule(originalIndex)}\n aria-label={t`Select rule ${ruleLabel}`}\n data-testid={`select-rule-${originalIndex}`}\n />\n </DataGridCell>\n )}\n <DataGridCell>{rule.ID || t`—`}</DataGridCell>\n <DataGridCell className=\"break-all\">{rule.AllowedOrigins.join(\", \")}</DataGridCell>\n <DataGridCell>{rule.AllowedMethods.join(\", \")}</DataGridCell>\n <DataGridCell>\n {rule.AllowedHeaders && rule.AllowedHeaders.length > 0 ? rule.AllowedHeaders.join(\", \") : t`—`}\n </DataGridCell>\n <DataGridCell>\n {rule.ExposeHeaders && rule.ExposeHeaders.length > 0 ? rule.ExposeHeaders.join(\", \") : t`—`}\n </DataGridCell>\n <DataGridCell>{rule.MaxAgeSeconds !== undefined ? rule.MaxAgeSeconds : t`—`}</DataGridCell>\n <DataGridCell onClick={(e) => e.stopPropagation()} className=\"justify-end pr-0\">\n {hasAnyRowAction && (\n <div className=\"flex h-full items-center justify-end\">\n <PopupMenu>\n <PopupMenuOptions>\n {canUpdateCors && (\n <PopupMenuItem\n label={t`Edit CORS Rule`}\n onClick={() => onEditRule(originalIndex)}\n disabled={effectiveIsMutating}\n />\n )}\n {canDeleteCors && (\n <PopupMenuItem\n label={t`Delete CORS Rule`}\n onClick={() => handleOpenDeleteModal(originalIndex, rule.ID)}\n disabled={effectiveIsMutating}\n />\n )}\n </PopupMenuOptions>\n </PopupMenu>\n </div>\n )}\n </DataGridCell>\n </DataGridRow>\n )\n })\n )}\n </DataGrid>\n\n {/* Delete CORS Rule Modal */}\n <DeleteCorsRuleModal\n isOpen={deleteModalState.isOpen}\n bucketName={bucketName}\n ruleIndex={deleteModalState.ruleIndex}\n ruleId={deleteModalState.ruleId}\n onClose={handleCloseDeleteModal}\n onSuccess={handleDeleteSuccess}\n onError={handleDeleteError}\n onMutatingChange={setIsRowDeleteMutating}\n />\n </Stack>\n )\n}\n","import { useState, KeyboardEvent } from \"react\"\nimport { TextInput, Pill, Stack, Button } from \"@cloudoperators/juno-ui-components\"\nimport { Trans } from \"@lingui/react/macro\"\n\ninterface TagInputProps {\n label: string\n value: string[]\n onChange: (value: string[]) => void\n placeholder?: string\n helptext?: string\n disabled?: boolean\n validate?: (value: string) => { valid: boolean; error?: string }\n id?: string\n name?: string\n required?: boolean\n}\n\nexport const TagInput = ({\n label,\n value,\n onChange,\n placeholder,\n helptext,\n disabled = false,\n validate,\n id,\n name,\n required = false,\n}: TagInputProps) => {\n const [inputValue, setInputValue] = useState(\"\")\n const [error, setError] = useState<string | undefined>()\n\n const handleKeyDown = (e: KeyboardEvent<HTMLInputElement>) => {\n if (e.key === \"Enter\" && inputValue.trim()) {\n e.preventDefault()\n addTag(inputValue.trim())\n }\n }\n\n const addTag = (tag: string) => {\n if (!tag) return\n\n if (validate) {\n const result = validate(tag)\n if (!result.valid) {\n setError(result.error)\n return\n }\n }\n\n if (value.includes(tag)) {\n setError(\"This value already exists\")\n return\n }\n\n onChange([...value, tag])\n setInputValue(\"\")\n setError(undefined)\n }\n\n const removeTag = (tagToRemove: string) => {\n onChange(value.filter((tag) => tag !== tagToRemove))\n }\n\n return (\n <div>\n <div className=\"flex items-start gap-2\">\n <div className=\"flex-1\">\n <TextInput\n label={label}\n id={id}\n name={name}\n value={inputValue}\n onChange={(e) => {\n setInputValue(e.target.value)\n setError(undefined)\n }}\n onKeyDown={handleKeyDown}\n disabled={disabled}\n placeholder={placeholder}\n helptext={helptext}\n invalid={!!error}\n errortext={error}\n required={required}\n />\n </div>\n <Button\n variant=\"default\"\n onClick={() => {\n if (inputValue.trim()) {\n addTag(inputValue.trim())\n }\n }}\n disabled={disabled || !inputValue.trim()}\n >\n <Trans>Add</Trans>\n </Button>\n </div>\n\n {value.length > 0 && (\n <Stack gap=\"2\" wrap={true} alignment=\"start\" distribution=\"start\" className=\"mt-2\">\n {value.map((tag, index) => (\n <div key={`${tag}-${index}`} className=\"max-w-full break-all\">\n <Pill pillValue={tag} closeable onClose={() => removeTag(tag)} />\n </div>\n ))}\n </Stack>\n )}\n </div>\n )\n}\n\nexport const urlValidator = (url: string): { valid: boolean; error?: string } => {\n if (url === \"*\") {\n return { valid: true }\n }\n\n // AWS S3 spec: origin can contain only one * wildcard character\n const wildcardCount = (url.match(/\\*/g) || []).length\n if (wildcardCount > 1) {\n return { valid: false, error: \"Only one * wildcard allowed per origin\" }\n }\n\n // Handle wildcard subdomain patterns like https://*.example.com\n if (wildcardCount === 1) {\n const wildcardMatch = url.match(/^(https?):\\/\\/\\*\\.(.+\\..+)$/)\n if (!wildcardMatch) {\n return { valid: false, error: \"Invalid wildcard format. Use * alone or https://*.example.com pattern\" }\n }\n const [, protocol, domain] = wildcardMatch\n // Validate the domain part by constructing a temporary URL with a placeholder\n try {\n new URL(`${protocol}://placeholder.${domain}`)\n return { valid: true }\n } catch {\n return { valid: false, error: \"Invalid wildcard origin format. Expected: https://*.example.com\" }\n }\n }\n\n // Standard URL validation (no wildcards)\n try {\n const urlObj = new URL(url)\n if (![\"http:\", \"https:\"].includes(urlObj.protocol)) {\n return { valid: false, error: \"URL must use http or https protocol\" }\n }\n return { valid: true }\n } catch {\n return { valid: false, error: \"Invalid URL format. Expected: https://example.com\" }\n }\n}\n\nexport const headerValidator = (header: string): { valid: boolean; error?: string } => {\n if (header === \"*\") {\n return { valid: true }\n }\n\n if (!/^[a-zA-Z0-9-_]+$/.test(header)) {\n return {\n valid: false,\n error: \"Header name can only contain letters, numbers, hyphens, and underscores\",\n }\n }\n\n return { valid: true }\n}\n","import { useEffect } from \"react\"\nimport { useForm, useStore } from \"@tanstack/react-form\"\nimport { useLingui } from \"@lingui/react/macro\"\nimport { Form, Stack, TextInput, CheckboxGroup, Checkbox } from \"@cloudoperators/juno-ui-components\"\nimport type { CorsRuleRead } from \"@/server/Storage/types/ceph\"\nimport { TagInput, urlValidator, headerValidator } from \"./TagInput\"\n\ninterface CorsRuleFormProps {\n editingRule: CorsRuleRead | null\n onSubmit: (rule: CorsRuleRead) => void\n formId: string\n onValidationChange?: (isValid: boolean) => void\n}\n\nexport const ALLOWED_METHODS = [\"GET\", \"PUT\", \"POST\", \"DELETE\", \"HEAD\"] as const\n\nexport const CorsRuleForm = ({ editingRule, onSubmit, formId, onValidationChange }: CorsRuleFormProps) => {\n const { t } = useLingui()\n\n const form = useForm({\n defaultValues: {\n ID: editingRule?.ID || \"\",\n AllowedOrigins: editingRule?.AllowedOrigins || [],\n AllowedMethods: (editingRule?.AllowedMethods || []) as string[],\n AllowedHeaders: editingRule?.AllowedHeaders || [],\n ExposeHeaders: editingRule?.ExposeHeaders || [],\n MaxAgeSeconds: editingRule?.MaxAgeSeconds?.toString() || \"\",\n },\n onSubmit: async ({ value }) => {\n const newRule: CorsRuleRead = {\n ID: value.ID || undefined,\n AllowedOrigins: value.AllowedOrigins,\n AllowedMethods: value.AllowedMethods,\n AllowedHeaders: value.AllowedHeaders.length > 0 ? value.AllowedHeaders : undefined,\n ExposeHeaders: value.ExposeHeaders.length > 0 ? value.ExposeHeaders : undefined,\n MaxAgeSeconds: value.MaxAgeSeconds ? parseInt(value.MaxAgeSeconds, 10) : undefined,\n }\n\n onSubmit(newRule)\n },\n })\n\n const allowedOriginsValue = useStore(form.store, (state: typeof form.store.state) => state.values.AllowedOrigins)\n const allowedMethodsValue = useStore(form.store, (state: typeof form.store.state) => state.values.AllowedMethods)\n\n const canSubmit = allowedOriginsValue.length > 0 && allowedMethodsValue.length > 0\n\n // Notify parent about validation state changes\n useEffect(() => {\n onValidationChange?.(canSubmit)\n }, [canSubmit, onValidationChange])\n\n return (\n <div>\n <Form\n id={formId}\n onSubmit={(e) => {\n e.preventDefault()\n form.handleSubmit()\n }}\n >\n <Stack direction=\"vertical\" gap=\"4\">\n <form.Field name=\"ID\">\n {(field) => (\n <TextInput\n label={t`Rule ID`}\n id={field.name}\n name={field.name}\n value={field.state.value}\n onChange={(e) => field.handleChange(e.target.value)}\n onBlur={field.handleBlur}\n placeholder={t`e.g. allow-frontend-app`}\n helptext={t`Optional identifier for this rule (max 255 characters).`}\n />\n )}\n </form.Field>\n\n <form.Field name=\"AllowedOrigins\">\n {(field) => (\n <TagInput\n label={t`Allowed Origins`}\n id={field.name}\n name={field.name}\n value={field.state.value}\n onChange={(value) => field.handleChange(value)}\n placeholder={t`e.g. https://example.com or *`}\n helptext={t`Enter a URL and press Enter. Use * to allow all origins.`}\n validate={urlValidator}\n required={true}\n />\n )}\n </form.Field>\n\n <form.Field name=\"AllowedMethods\">\n {(field) => (\n <CheckboxGroup\n label={t`Allowed Methods`}\n helptext={t`Select HTTP methods allowed for cross-origin requests`}\n required={true}\n >\n {ALLOWED_METHODS.map((method) => (\n <Checkbox\n key={method}\n label={method}\n value={method}\n checked={field.state.value.includes(method)}\n onChange={(e) => {\n const checked = e.target.checked\n const current = field.state.value\n if (checked) {\n field.handleChange([...current, method])\n } else {\n field.handleChange(current.filter((m) => m !== method))\n }\n }}\n />\n ))}\n </CheckboxGroup>\n )}\n </form.Field>\n\n <form.Field name=\"AllowedHeaders\">\n {(field) => (\n <TagInput\n label={t`Allowed Headers`}\n id={field.name}\n name={field.name}\n value={field.state.value}\n onChange={(value) => field.handleChange(value)}\n placeholder={t`e.g. Authorization, Content-Type, or *`}\n helptext={t`Enter a header name and press Enter. Use * to allow all headers.`}\n validate={headerValidator}\n />\n )}\n </form.Field>\n\n <form.Field name=\"ExposeHeaders\">\n {(field) => (\n <TagInput\n label={t`Expose Headers`}\n id={field.name}\n name={field.name}\n value={field.state.value}\n onChange={(value) => field.handleChange(value)}\n placeholder={t`e.g. Etag, Content-Length`}\n helptext={t`Enter a header name and press Enter. These headers will be exposed to the browser.`}\n validate={headerValidator}\n />\n )}\n </form.Field>\n\n <form.Field name=\"MaxAgeSeconds\">\n {(field) => (\n <TextInput\n label={t`Max Age in Seconds`}\n id={field.name}\n name={field.name}\n type=\"number\"\n value={field.state.value}\n onChange={(e) => field.handleChange(e.target.value)}\n onBlur={field.handleBlur}\n placeholder={t`e.g. 3600 (1 hour) or 604800 (7 days)`}\n min=\"0\"\n helptext={t`How long browsers can cache preflight responses. Common values: 3600 (1 hour), 86400 (1 day), 604800 (1 week).`}\n />\n )}\n </form.Field>\n </Stack>\n </Form>\n </div>\n )\n}\n","import { useEffect, useState } from \"react\"\nimport { Modal, Status, Message, ModalFooter, ButtonRow, Button } from \"@cloudoperators/juno-ui-components\"\nimport { useLingui } from \"@lingui/react/macro\"\nimport { Trans } from \"@lingui/react/macro\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport { useModalTracking } from \"@/client/hooks/useModalTracking\"\nimport { CorsRuleForm } from \"./CorsRuleForm\"\nimport type { CorsRuleRead } from \"@/server/Storage/types/ceph\"\nimport { toCorsRule } from \"./utils/corsUtils\"\n\ninterface CorsRuleModalProps {\n isOpen: boolean\n bucketName: string\n editingIndex: number | null // null = adding, non-null = editing\n onClose: () => void\n onSuccess?: (bucketName: string) => void\n onError?: (bucketName: string, errorMessage: string) => void\n onMutatingChange?: (isMutating: boolean) => void\n}\n\n/**\n * Modal wrapper for CorsRuleForm\n *\n * Handles adding or editing a single CORS rule.\n * Loads current CORS configuration, adds/updates the rule, and calls cors.set.\n */\nexport const CorsRuleModal = ({\n isOpen,\n bucketName,\n editingIndex,\n onClose,\n onSuccess,\n onError,\n onMutatingChange,\n}: CorsRuleModalProps) => {\n const { t } = useLingui()\n const projectId = useProjectId()\n const utils = trpcReact.useUtils()\n const [isFormValid, setIsFormValid] = useState(false)\n\n const { trackClose, markSubmitted, resetTracking } = useModalTracking({\n isOpen,\n actionPrefix: \"storage.ceph.bucket.cors\",\n })\n\n // Query to get current CORS configuration\n const {\n data: corsData,\n isLoading: isCorsLoading,\n error: corsError,\n } = trpcReact.storage.ceph.cors.get.useQuery(\n {\n project_id: projectId,\n bucketName,\n },\n {\n enabled: isOpen && !!projectId,\n retry: false,\n staleTime: 5 * 60 * 1000,\n }\n )\n\n // Set mutation\n const setMutation = trpcReact.storage.ceph.cors.set.useMutation({\n onSuccess: () => {\n utils.storage.ceph.cors.get.invalidate()\n onSuccess?.(bucketName)\n handleClose()\n },\n onError: (error) => {\n onError?.(bucketName, error.message)\n },\n })\n\n useEffect(() => {\n onMutatingChange?.(setMutation.isPending)\n }, [setMutation.isPending, onMutatingChange])\n\n useEffect(() => {\n if (!isOpen) {\n setMutation.reset()\n setIsFormValid(false)\n resetTracking()\n }\n }, [isOpen, bucketName])\n\n const handleClose = () => {\n setMutation.reset()\n setIsFormValid(false)\n resetTracking()\n onClose()\n }\n\n const handleSubmit = async (rule: CorsRuleRead) => {\n markSubmitted()\n\n try {\n const currentRules = corsData?.corsRules ?? []\n let updatedRules: CorsRuleRead[]\n\n if (editingIndex === null) {\n // Adding new rule - no freshness check needed (appending is safe)\n updatedRules = [...currentRules, rule]\n } else {\n // Editing existing rule - perform freshness check\n const freshData = await utils.storage.ceph.cors.get.fetch({\n project_id: projectId,\n bucketName,\n })\n\n const freshRules = freshData?.corsRules ?? []\n const editingRule = corsData?.corsRules?.[editingIndex]\n const freshRule = freshRules[editingIndex]\n\n // Freshness check\n if (!freshRule || JSON.stringify(freshRule) !== JSON.stringify(editingRule)) {\n onError?.(bucketName, t`The CORS configuration has changed. Please refresh and try again.`)\n return\n }\n\n // Proceed with edit using fresh data\n updatedRules = [...freshRules]\n updatedRules[editingIndex] = rule\n }\n\n // Type assertion needed because CorsRuleRead has string[] for AllowedMethods\n // but the mutation expects the narrower type from the schema\n setMutation.mutate({\n project_id: projectId,\n bucketName,\n corsConfiguration: {\n CORSRules: updatedRules.map(toCorsRule),\n },\n })\n } catch {\n onError?.(bucketName, t`Failed to verify CORS configuration`)\n }\n }\n\n if (!isOpen) return null\n\n const editingRule =\n editingIndex !== null && corsData?.corsRules?.[editingIndex] ? corsData.corsRules[editingIndex] : null\n const isSaving = setMutation.isPending\n const formId = \"cors-rule-form\"\n\n return (\n <Modal\n title={editingRule ? t`Edit CORS Rule` : t`Create CORS Rule`}\n open={isOpen}\n onCancel={() => {\n trackClose()\n handleClose()\n }}\n size=\"large\"\n modalFooter={\n <ModalFooter className=\"bg-theme-background-lvl-0 sticky bottom-0 z-50 flex justify-end\">\n <ButtonRow>\n <Button\n variant=\"subdued\"\n onClick={() => {\n trackClose()\n handleClose()\n }}\n disabled={isSaving}\n >\n <Trans>Cancel</Trans>\n </Button>\n <Button\n variant=\"primary\"\n onClick={() => {\n const submitButton = document.querySelector(`#${formId}`) as HTMLFormElement\n submitButton?.requestSubmit()\n }}\n disabled={!isFormValid || isSaving || isCorsLoading || !!corsError}\n >\n {isSaving ? (\n editingRule ? (\n <Trans>Saving...</Trans>\n ) : (\n <Trans>Creating...</Trans>\n )\n ) : editingRule ? (\n <Trans>Save Changes</Trans>\n ) : (\n <Trans>Create CORS Rule</Trans>\n )}\n </Button>\n </ButtonRow>\n </ModalFooter>\n }\n >\n {isCorsLoading && <Status status=\"progress\" title={t`Loading CORS Configuration...`} className=\"mt-0\" />}\n\n {corsError && (\n <Status status=\"error\" title={t`Failed to Load CORS Configuration`} body={corsError.message} className=\"mt-0\" />\n )}\n\n {setMutation.isError && (\n <Message variant=\"error\" title={t`Failed to Save CORS Rule`}>\n {setMutation.error?.message}\n </Message>\n )}\n\n {!isCorsLoading && !corsError && (\n <CorsRuleForm\n key={editingIndex ?? \"new\"}\n editingRule={editingRule}\n onSubmit={handleSubmit}\n formId={formId}\n onValidationChange={setIsFormValid}\n />\n )}\n </Modal>\n )\n}\n","import { useEffect, useState } from \"react\"\nimport { Trans, useLingui, Plural } from \"@lingui/react/macro\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { Modal, Stack, Status, Message } from \"@cloudoperators/juno-ui-components\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport { useModalTracking } from \"@/client/hooks/useModalTracking\"\nimport type { CorsRuleRead } from \"@/server/Storage/types/ceph\"\nimport { toCorsRule } from \"./utils/corsUtils\"\n\nconst MAX_VISIBLE_RULES = 5\n\ninterface DeleteCorsRulesModalProps {\n isOpen: boolean\n bucketName: string\n ruleIndices: number[]\n rules: CorsRuleRead[]\n onClose: () => void\n onSuccess?: (bucketName: string, count: number) => void\n onError?: (bucketName: string, errorMessage: string, count: number) => void\n onMutatingChange?: (isMutating: boolean) => void\n}\n\n/**\n * Modal for bulk deletion of CORS rules\n *\n * Loads current CORS configuration, removes selected rules, and calls:\n * - `storage.ceph.cors.set` if rules remain after deletion\n * - `storage.ceph.cors.delete` if all rules are deleted\n */\nexport const DeleteCorsRulesModal = ({\n isOpen,\n bucketName,\n ruleIndices,\n rules,\n onClose,\n onSuccess,\n onError,\n onMutatingChange,\n}: DeleteCorsRulesModalProps) => {\n const { t } = useLingui()\n const projectId = useProjectId()\n const utils = trpcReact.useUtils()\n const [isVerifying, setIsVerifying] = useState(false)\n\n const { trackClose, markSubmitted, resetTracking } = useModalTracking({\n isOpen,\n actionPrefix: \"storage.ceph.cors.rules.bulk_delete\",\n })\n\n // Query to get current CORS configuration (for loading/error states only)\n // The freshness check in handleDelete refetches directly\n const { isLoading: isCorsLoading, error: corsError } = trpcReact.storage.ceph.cors.get.useQuery(\n {\n project_id: projectId,\n bucketName,\n },\n {\n enabled: isOpen && !!projectId,\n retry: false,\n }\n )\n\n // Set mutation (for partial deletion)\n const setMutation = trpcReact.storage.ceph.cors.set.useMutation({\n onSuccess: () => {\n utils.storage.ceph.cors.get.invalidate()\n onSuccess?.(bucketName, ruleIndices.length)\n handleClose()\n },\n onError: (error) => {\n onError?.(bucketName, error.message, ruleIndices.length)\n },\n })\n\n // Delete mutation (for deleting all rules)\n const deleteMutation = trpcReact.storage.ceph.cors.delete.useMutation({\n onSuccess: () => {\n utils.storage.ceph.cors.get.invalidate()\n onSuccess?.(bucketName, ruleIndices.length)\n handleClose()\n },\n onError: (error) => {\n onError?.(bucketName, error.message, ruleIndices.length)\n },\n })\n\n useEffect(() => {\n onMutatingChange?.(setMutation.isPending || deleteMutation.isPending)\n }, [setMutation.isPending, deleteMutation.isPending, onMutatingChange])\n\n useEffect(() => {\n if (!isOpen) {\n setMutation.reset()\n deleteMutation.reset()\n setIsVerifying(false)\n resetTracking()\n }\n }, [isOpen, bucketName])\n\n const handleClose = () => {\n trackClose()\n setMutation.reset()\n deleteMutation.reset()\n setIsVerifying(false)\n resetTracking()\n onClose()\n }\n\n const handleDelete = async () => {\n if (isVerifying) return\n\n markSubmitted()\n setIsVerifying(true)\n\n try {\n // Refetch to get fresh data\n const freshData = await utils.storage.ceph.cors.get.fetch({\n project_id: projectId,\n bucketName,\n })\n\n const freshRules = freshData?.corsRules ?? []\n\n if (freshRules.length === 0) {\n onError?.(bucketName, t`No CORS rules found`, ruleIndices.length)\n return\n }\n\n // Freshness check: verify each rule at its index matches what the user selected\n const mismatches: number[] = []\n for (const index of ruleIndices) {\n const cachedRule = rules[index]\n const freshRule = freshRules[index]\n\n if (!freshRule || JSON.stringify(freshRule) !== JSON.stringify(cachedRule)) {\n mismatches.push(index)\n }\n }\n\n if (mismatches.length > 0) {\n onError?.(bucketName, t`The CORS configuration has changed. Please refresh and try again.`, ruleIndices.length)\n return\n }\n\n // Proceed with deletion using fresh data\n const remainingRules = freshRules.filter((_, index) => !ruleIndices.includes(index))\n\n if (remainingRules.length === 0) {\n // Delete entire CORS configuration\n deleteMutation.mutate({\n project_id: projectId,\n bucketName,\n })\n } else {\n // Update with remaining rules\n setMutation.mutate({\n project_id: projectId,\n bucketName,\n corsConfiguration: {\n CORSRules: remainingRules.map(toCorsRule),\n },\n })\n }\n } catch {\n onError?.(bucketName, t`Failed to verify CORS configuration`, ruleIndices.length)\n } finally {\n setIsVerifying(false)\n }\n }\n\n if (!isOpen) return null\n\n const ruleCount = ruleIndices.length\n const isDeleting = setMutation.isPending || deleteMutation.isPending\n const rulesToDeleteWithIndices = rules\n .map((rule, index) => ({ rule, index }))\n .filter(({ index }) => ruleIndices.includes(index))\n const visibleRules = rulesToDeleteWithIndices.slice(0, MAX_VISIBLE_RULES)\n const hiddenCount = rulesToDeleteWithIndices.length - visibleRules.length\n const confirmLabel = isDeleting ? t`Deleting...` : ruleCount === 1 ? t`Delete CORS Rule` : t`Delete CORS Rules`\n\n return (\n <Modal\n title={<Plural value={ruleCount} one=\"Delete CORS Rule\" other=\"Delete CORS Rules\" />}\n open={isOpen}\n onCancel={handleClose}\n confirmButtonLabel={confirmLabel}\n confirmButtonVariant=\"primary-danger\"\n onConfirm={handleDelete}\n cancelButtonLabel={t`Cancel`}\n size=\"small\"\n disableConfirmButton={isDeleting || isCorsLoading || !!corsError || isVerifying}\n disableCancelButton={isDeleting || isVerifying}\n disableCloseButton={isDeleting || isVerifying}\n >\n <Stack direction=\"vertical\" gap=\"4\">\n {isCorsLoading && <Status status=\"progress\" title={t`Loading CORS Configuration...`} className=\"mt-0\" />}\n\n {corsError && (\n <Status\n status=\"error\"\n title={t`Failed to Load CORS Configuration`}\n body={corsError.message}\n className=\"mt-0\"\n />\n )}\n\n {!isCorsLoading && !corsError && (\n <>\n <p className=\"text-theme-default\">\n <Trans>\n Are you sure you want to delete <Plural value={ruleCount} one=\"# CORS rule\" other=\"# CORS rules\" /> from\n bucket <strong>{bucketName}</strong>?\n </Trans>\n </p>\n\n <div>\n <p className=\"text-sm font-semibold\">\n <Trans>Rules to delete:</Trans>\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 {visibleRules.map(({ rule, index }) => {\n const displayName = rule.ID || `Rule #${index + 1}`\n return (\n <div key={index} className=\"text-theme-default text-sm\">\n {displayName}\n </div>\n )\n })}\n {hiddenCount > 0 && (\n <div className=\"text-theme-light pt-2 text-sm\">\n <Trans>... and {hiddenCount} more</Trans>\n </div>\n )}\n </Stack>\n </div>\n </div>\n\n <p className=\"text-theme-default\">\n <Trans>This action cannot be undone.</Trans>\n </p>\n </>\n )}\n\n {(setMutation.isError || deleteMutation.isError) && (\n <Message variant=\"error\" title={t`Failed to delete CORS rules`}>\n {setMutation.error?.message || deleteMutation.error?.message}\n </Message>\n )}\n </Stack>\n </Modal>\n )\n}\n","import { useState, startTransition } from \"react\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { plural } from \"@lingui/core/macro\"\nimport { i18n } from \"@lingui/core\"\nimport { useNavigate } from \"@tanstack/react-router\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport {\n Status,\n Button,\n Stack,\n toast,\n Checkbox,\n PopupMenu,\n PopupMenuItem,\n PopupMenuOptions,\n PopupMenuToggle,\n DataGridToolbar,\n SearchInput,\n Divider,\n} from \"@cloudoperators/juno-ui-components\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport { useCephPermissions } from \"../hooks/useCephPermissions\"\nimport { SortInput } from \"@/client/components/ListToolbar/SortInput\"\nimport { SortSettings } from \"@/client/components/ListToolbar/types\"\nimport { Route } from \"@/client/routes/_auth/projects/$projectId/storage/$provider/$storageType/$containerName/objects\"\nimport { CorsRulesTable } from \"./CorsRulesTable\"\nimport { CorsRuleModal } from \"./CorsRuleModal\"\nimport { DeleteCorsRulesModal } from \"./DeleteCorsRulesModal\"\nimport {\n getCorsSavedToast,\n getCorsSaveErrorToast,\n getCorsRulesDeletedToast,\n getCorsRulesDeleteErrorToast,\n} from \"./BucketToastNotifications\"\nimport type { CorsRuleRead } from \"@/server/Storage/types/ceph\"\n\ninterface CorsRulesTabProps {\n bucketName: string\n}\n\n/**\n * CORS Rules tab container\n *\n * Manages CORS configuration for a Ceph bucket with full CRUD operations.\n * Each operation (add/edit/delete) immediately updates the server configuration.\n */\nexport function CorsRulesTab({ bucketName }: CorsRulesTabProps) {\n const { t } = useLingui()\n const projectId = useProjectId()\n const navigate = useNavigate({ from: Route.fullPath })\n const { permissions } = useCephPermissions(projectId)\n\n // Sort and search state are persisted in the URL\n const { corsSortBy, corsSortDirection, corsSearch = \"\" } = Route.useSearch()\n\n // Server state\n const {\n data: corsData,\n isLoading,\n error,\n } = trpcReact.storage.ceph.cors.get.useQuery(\n {\n project_id: projectId,\n bucketName,\n },\n {\n enabled: !!projectId,\n retry: false,\n staleTime: 5 * 60 * 1000, // 5 minutes, shared with useBucketInfo\n }\n )\n\n // Modal state\n const [isRuleModalOpen, setIsRuleModalOpen] = useState(false)\n const [editingRuleIndex, setEditingRuleIndex] = useState<number | null>(null)\n const [isBulkDeleteModalOpen, setIsBulkDeleteModalOpen] = useState(false)\n\n // Mutation state for modals (to disable row actions during mutations)\n const [isRuleModalMutating, setIsRuleModalMutating] = useState(false)\n const [isBulkDeleteMutating, setIsBulkDeleteMutating] = useState(false)\n\n // Selection state for bulk actions\n const [selectedIndices, setSelectedIndices] = useState<number[]>([])\n\n const sortSettings: SortSettings = {\n options: [\n { label: t`Rule ID`, value: \"ID\" },\n { label: t`Allowed Origins`, value: \"AllowedOrigins\" },\n { label: t`Allowed Methods`, value: \"AllowedMethods\" },\n { label: t`Allowed Headers`, value: \"AllowedHeaders\" },\n { label: t`Expose Headers`, value: \"ExposeHeaders\" },\n { label: t`Max Age`, value: \"MaxAgeSeconds\" },\n ],\n sortBy: corsSortBy ?? \"ID\",\n sortDirection: corsSortDirection ?? \"asc\",\n }\n\n const handleSearchChange = (term: string | number | string[] | undefined) => {\n const value = typeof term === \"string\" ? term : \"\"\n startTransition(() => {\n navigate({\n search: (prev) => ({ ...prev, corsSearch: value || undefined }),\n })\n })\n }\n\n const handleSortChange = (newSortSettings: SortSettings) => {\n const resolvedSortBy = (newSortSettings.sortBy?.toString() || \"ID\") as\n \"ID\" | \"AllowedOrigins\" | \"AllowedMethods\" | \"AllowedHeaders\" | \"ExposeHeaders\" | \"MaxAgeSeconds\"\n const resolvedDirection = (newSortSettings.sortDirection || \"asc\") as \"asc\" | \"desc\"\n startTransition(() => {\n navigate({\n search: (prev) => ({\n ...prev,\n corsSortBy: resolvedSortBy,\n corsSortDirection: resolvedDirection,\n }),\n })\n })\n }\n\n const handleAddRule = () => {\n setEditingRuleIndex(null)\n setIsRuleModalOpen(true)\n }\n\n const handleEditRule = (index: number) => {\n setEditingRuleIndex(index)\n setIsRuleModalOpen(true)\n }\n\n const handleToggleSelectRule = (index: number) => {\n setSelectedIndices((prev) => (prev.includes(index) ? prev.filter((i) => i !== index) : [...prev, index]))\n }\n\n const handleToggleSelectAll = () => {\n if (allFilteredSelected) {\n // Deselect all filtered rules\n setSelectedIndices((prev) => prev.filter((i) => !filteredIndices.includes(i)))\n } else {\n // Select all filtered rules\n setSelectedIndices((prev) => [...new Set([...prev, ...filteredIndices])])\n }\n }\n\n const handleBulkDelete = () => {\n setIsBulkDeleteModalOpen(true)\n }\n\n const handleDeleteRule = () => {\n // Clear selections after single-rule deletion to avoid stale indices\n setSelectedIndices([])\n }\n\n // Current rules from server\n const rules = corsData?.corsRules ?? []\n\n // Sort rules based on sort settings\n const sortRules = (rules: CorsRuleRead[]): CorsRuleRead[] => {\n return [...rules].sort((a, b) => {\n let comparison: number\n\n switch (corsSortBy ?? \"ID\") {\n case \"ID\":\n comparison = (a.ID || \"\").localeCompare(b.ID || \"\")\n break\n case \"AllowedOrigins\":\n comparison = a.AllowedOrigins.join(\", \").localeCompare(b.AllowedOrigins.join(\", \"))\n break\n case \"AllowedMethods\":\n comparison = a.AllowedMethods.join(\", \").localeCompare(b.AllowedMethods.join(\", \"))\n break\n case \"AllowedHeaders\":\n comparison = (a.AllowedHeaders || []).join(\", \").localeCompare((b.AllowedHeaders || []).join(\", \"))\n break\n case \"ExposeHeaders\":\n comparison = (a.ExposeHeaders || []).join(\", \").localeCompare((b.ExposeHeaders || []).join(\", \"))\n break\n case \"MaxAgeSeconds\":\n comparison = (a.MaxAgeSeconds ?? -1) - (b.MaxAgeSeconds ?? -1)\n break\n default:\n comparison = (a.ID || \"\").localeCompare(b.ID || \"\")\n }\n\n return (corsSortDirection ?? \"asc\") === \"desc\" ? -comparison : comparison\n })\n }\n\n // Filter rules based on search term (by Rule ID)\n const filteredRulesWithIndices = sortRules(rules)\n .map((rule) => ({ rule, originalIndex: rules.indexOf(rule) }))\n .filter(({ rule }) => {\n if (!corsSearch) return true\n const ruleId = rule.ID || \"\"\n return ruleId.toLowerCase().includes(corsSearch.toLowerCase())\n })\n\n // Get indices of filtered rules for select-all logic\n const filteredIndices = filteredRulesWithIndices.map(({ originalIndex }) => originalIndex)\n\n const allFilteredSelected = filteredIndices.length > 0 && filteredIndices.every((i) => selectedIndices.includes(i))\n const someFilteredSelected = filteredIndices.some((i) => selectedIndices.includes(i)) && !allFilteredSelected\n\n if (isLoading) {\n return <Status status=\"progress\" title={t`Loading CORS Configuration...`} />\n }\n\n if (error) {\n return <Status status=\"error\" title={t`Failed to Load CORS Configuration`} body={error.message} />\n }\n\n return (\n <>\n {/* Zone 1 — Sort controls and Create rule button (outside DataGridToolbar) */}\n <Stack distribution=\"end\" alignment=\"center\" gap=\"2\" className=\"pb-2\">\n <Stack gap=\"0.5\" alignment=\"center\">\n <SortInput\n options={sortSettings.options}\n sortBy={sortSettings.sortBy}\n sortDirection={sortSettings.sortDirection ?? \"asc\"}\n selectClassName=\"min-w-52\"\n selectWidth=\"auto\"\n onSortByChange={(value) =>\n handleSortChange({ ...sortSettings, sortBy: value, sortDirection: sortSettings.sortDirection })\n }\n onSortDirectionChange={(direction) => handleSortChange({ ...sortSettings, sortDirection: direction })}\n />\n </Stack>\n {permissions.canUpdateCors && (\n <Button variant=\"primary\" onClick={handleAddRule}>\n <Trans>Create CORS Rule</Trans>\n </Button>\n )}\n </Stack>\n\n {/* Zone 2 — Bulk actions toolbar (inside DataGridToolbar) */}\n <DataGridToolbar>\n <Stack direction=\"vertical\" gap=\"2\">\n <Stack distribution=\"end\" alignment=\"center\">\n <SearchInput\n placeholder={t`Search CORS rules...`}\n data-testid=\"cors-rules-searchbar\"\n value={corsSearch}\n onInput={(e) => {\n const v = e.currentTarget.value\n handleSearchChange(v)\n }}\n onSearch={(v) => handleSearchChange(typeof v === \"string\" ? v : \"\")}\n onClear={() => handleSearchChange(\"\")}\n />\n </Stack>\n <Divider />\n <Stack distribution=\"between\" gap=\"2\" alignment=\"center\" className=\"text-sm\">\n {permissions.canDeleteCors ? (\n <Stack gap=\"2\" alignment=\"center\">\n <Checkbox\n checked={allFilteredSelected}\n indeterminate={someFilteredSelected}\n onChange={handleToggleSelectAll}\n aria-label={t`Select all rules`}\n data-testid=\"select-all-rules\"\n disabled={filteredRulesWithIndices.length === 0}\n />\n <PopupMenu className=\"flex items-center\">\n <PopupMenuToggle as=\"div\">\n <Button disabled={selectedIndices.length === 0} size=\"small\" icon=\"moreVert\" label={t`Actions`} />\n </PopupMenuToggle>\n {selectedIndices.length > 0 && (\n <PopupMenuOptions>\n <PopupMenuItem\n label={i18n._(\n plural(selectedIndices.length, { one: \"Delete # Rule\", other: \"Delete # Rules\" })\n )}\n onClick={handleBulkDelete}\n data-testid=\"bulk-delete-rules-action\"\n />\n </PopupMenuOptions>\n )}\n </PopupMenu>\n </Stack>\n ) : (\n <span />\n )}\n <span className=\"theme-color-text-light\">\n {filteredRulesWithIndices.length} {filteredRulesWithIndices.length === 1 ? t`rule` : t`rules`}\n </span>\n </Stack>\n </Stack>\n </DataGridToolbar>\n\n {/* Table */}\n <CorsRulesTable\n bucketName={bucketName}\n rulesWithIndices={filteredRulesWithIndices}\n selectedIndices={selectedIndices}\n onToggleSelectRule={handleToggleSelectRule}\n onEditRule={handleEditRule}\n onDeleteRule={handleDeleteRule}\n isMutating={isRuleModalMutating || isBulkDeleteMutating}\n isFiltered={!!corsSearch}\n canUpdateCors={permissions.canUpdateCors}\n canDeleteCors={permissions.canDeleteCors}\n />\n\n {/* Bulk delete rules modal */}\n <DeleteCorsRulesModal\n isOpen={isBulkDeleteModalOpen}\n bucketName={bucketName}\n ruleIndices={selectedIndices}\n rules={rules}\n onClose={() => setIsBulkDeleteModalOpen(false)}\n onSuccess={(bucketName, count) => {\n setIsBulkDeleteModalOpen(false)\n setSelectedIndices([])\n const { message, ...options } = getCorsRulesDeletedToast(bucketName, count)\n toast.success(message, options)\n }}\n onError={(bucketName, errorMessage, count) => {\n const { message, ...options } = getCorsRulesDeleteErrorToast(bucketName, count, errorMessage)\n toast.error(message, options)\n }}\n onMutatingChange={setIsBulkDeleteMutating}\n />\n\n {/* Add/Edit rule modal */}\n <CorsRuleModal\n isOpen={isRuleModalOpen}\n bucketName={bucketName}\n editingIndex={editingRuleIndex}\n onClose={() => {\n setIsRuleModalOpen(false)\n setEditingRuleIndex(null)\n }}\n onSuccess={(bucketName) => {\n setIsRuleModalOpen(false)\n setEditingRuleIndex(null)\n const { message, ...options } = getCorsSavedToast(bucketName)\n toast.success(message, options)\n }}\n onError={(bucketName, errorMessage) => {\n const { message, ...options } = getCorsSaveErrorToast(bucketName, errorMessage)\n toast.error(message, options)\n }}\n onMutatingChange={setIsRuleModalMutating}\n />\n </>\n )\n}\n","import type {\n LifecycleRuleRead,\n LifecycleRule,\n LifecycleFilter,\n LifecycleTag,\n LifecycleExpiration,\n LifecycleTransition,\n LifecycleNoncurrentVersionExpiration,\n LifecycleNoncurrentVersionTransition,\n} from \"@/server/Storage/types/ceph\"\n\n/**\n * Normalizes filter structure for consistency and S3 API compliance.\n *\n * Intentional duplicate of `lifecycleMapper.normalizeFilter` — importing the server module\n * into the client bundle is the failure mode documented in the CORS postmortem. Keep\n * behaviourally identical; `lifecycleUtils.test.ts` mirrors `lifecycleMapper.test.ts`'s filter cases.\n *\n * Rules:\n * - No filter conditions → { Prefix: \"\" } (whole-bucket filter)\n * - Single condition → top-level (Prefix, Tag, ObjectSize*)\n * - Multiple conditions → { And: { ... } }\n * - Empty prefix is normalized to no prefix (omitted)\n *\n * @param prefix - Optional prefix string\n * @param tags - Optional array of tags\n * @returns Normalized LifecycleFilter or undefined\n */\nexport function normalizeFilter(prefix?: string, tags?: LifecycleTag[]): LifecycleFilter | undefined {\n const hasPrefix = prefix !== undefined && prefix !== \"\"\n const hasTags = tags !== undefined && tags.length > 0\n\n // No conditions at all → whole-bucket rule (empty prefix)\n if (!hasPrefix && !hasTags) {\n return { Prefix: \"\" }\n }\n\n // Single tag, no prefix → { Tag }\n if (!hasPrefix && hasTags && tags.length === 1) {\n return { Tag: tags[0] }\n }\n\n // Only prefix → { Prefix }\n if (hasPrefix && !hasTags) {\n return { Prefix: prefix }\n }\n\n // Multiple conditions (prefix + tags, or 2+ tags) → { And }\n if ((hasPrefix && hasTags) || (hasTags && tags.length > 1)) {\n return {\n And: {\n Prefix: hasPrefix ? prefix : undefined,\n Tags: hasTags ? tags : undefined,\n },\n }\n }\n\n // Fallback (shouldn't reach here)\n return { Prefix: \"\" }\n}\n\nexport type DaysParseResult = { ok: true; value: number } | { ok: false; reason: \"empty\" | \"invalid\" }\n\n/**\n * Parses a Days input string into a validated positive integer.\n *\n * Mirrors the server's `z.number().int().min(1)` constraint used for lifecycle rule Days fields\n * (Expiration.Days, NoncurrentVersionExpiration.NoncurrentDays, AbortIncompleteMultipartUpload.DaysAfterInitiation).\n * *\n * @param raw - Raw string value from a Days input field\n * @returns `{ ok: true, value }` for a valid positive integer, or `{ ok: false, reason }` otherwise\n * */\n\nexport function parseDaysValue(raw: string): DaysParseResult {\n const trimmed = raw.trim()\n if (trimmed === \"\") return { ok: false, reason: \"empty\" }\n if (!/^\\d+$/.test(trimmed)) return { ok: false, reason: \"invalid\" }\n const value = Number(trimmed)\n if (!Number.isSafeInteger(value) || value < 1) return { ok: false, reason: \"invalid\" }\n return { ok: true, value }\n}\n\n/**\n * Validate an Expiration object's structure against lifecycleExpirationSchema's refinements\n * (server write schema): exactly one of Days/Date/ExpiredObjectDeleteMarker must be set, and\n * ExpiredObjectDeleteMarker cannot combine with Days or Date.\n *\n * Used to guard against preserving/submitting an externally-authored Expiration (read via the\n * lenient read schema) that would fail server-side validation, e.g. `{}` or `{ Days, Date }`.\n *\n * Accepts the lenient read-schema shape (`LifecycleRuleRead[\"Expiration\"]`, where `Date` may be\n * a `Date` object) since callers check both freshly-built write-shape rules and rules read\n * straight from the server.\n *\n * @param expiration - Expiration to check, or undefined (treated as valid no expiration set)\n * @returns Whether the Expiration would satisfy the write schema's structural rules\n */\nexport function isValidExpiration(expiration: LifecycleRuleRead[\"Expiration\"]): boolean {\n if (!expiration) return true\n const hasDays = expiration.Days !== undefined\n const hasDate = expiration.Date !== undefined\n const hasDeleteMarker = expiration.ExpiredObjectDeleteMarker !== undefined\n\n if (!hasDays && !hasDate && !hasDeleteMarker) return false\n if (hasDays && hasDate) return false\n if (hasDeleteMarker && (hasDays || hasDate)) return false\n return true\n}\n\n/**\n * Convert LifecycleRuleRead (lenient read schema) to LifecycleRule (strict write schema)\n *\n * Performs real conversion, not just a cast:\n * - Narrows Status from string to \"Enabled\" | \"Disabled\"\n * - Converts Date objects to ISO strings for Expiration.Date and Transitions[].Date\n * - Preserves all other fields unchanged\n *\n * @param rule - Rule from server (read schema)\n * @returns Rule suitable for mutation (write schema)\n */\nexport function toLifecycleRule(rule: LifecycleRuleRead): LifecycleRule {\n const converted: Partial<LifecycleRule> = {\n ID: rule.ID,\n Status: rule.Status as \"Enabled\" | \"Disabled\",\n Prefix: rule.Prefix,\n Filter: rule.Filter as LifecycleRule[\"Filter\"],\n NoncurrentVersionExpiration: rule.NoncurrentVersionExpiration as LifecycleRule[\"NoncurrentVersionExpiration\"],\n NoncurrentVersionTransitions: rule.NoncurrentVersionTransitions as LifecycleRule[\"NoncurrentVersionTransitions\"],\n AbortIncompleteMultipartUpload:\n rule.AbortIncompleteMultipartUpload as LifecycleRule[\"AbortIncompleteMultipartUpload\"],\n }\n\n // Convert Expiration.Date if it's a Date object\n if (rule.Expiration?.Date) {\n const date = rule.Expiration.Date\n converted.Expiration = {\n ...rule.Expiration,\n Date: typeof date === \"string\" ? date : date.toISOString(),\n } as LifecycleRule[\"Expiration\"]\n } else if (rule.Expiration) {\n converted.Expiration = rule.Expiration as LifecycleRule[\"Expiration\"]\n }\n\n // Convert Transitions[].Date if any are Date objects\n if (rule.Transitions && rule.Transitions.length > 0) {\n converted.Transitions = rule.Transitions.map((t) => {\n if (t.Date) {\n const date = t.Date\n return {\n ...t,\n Date: typeof date === \"string\" ? date : date.toISOString(),\n }\n }\n return t\n }) as LifecycleRule[\"Transitions\"]\n }\n\n return converted as LifecycleRule\n}\n\n/**\n * Validate lifecycle rules against the write schema's structural requirements\n *\n * Mirrors lifecycleRuleSchema's refinements, plus additional checks:\n * - Must have at least one action\n * - Cannot have both Filter and legacy Prefix\n * - ExpiredObjectDeleteMarker incompatible with tag filters\n * - ExpiredObjectDeleteMarker cannot be combined with Days or Date\n * - AbortIncompleteMultipartUpload incompatible with tag filters\n * - And filter must have ≥2 predicates (per-tag counting)\n * - Top-level filter conditions must be wrapped in And\n * - ID ≤ 255 characters\n * - NoncurrentVersionExpiration must have NoncurrentDays\n * - Transitions must have either Days or Date (XOR)\n * - 1-100 rules with unique non-empty IDs\n *\n * @param rules - Rules to validate\n * @returns Success with converted rules, or failure with error messages\n */\nexport function validateLifecycleRules(\n rules: LifecycleRuleRead[]\n): { ok: true; rules: LifecycleRule[] } | { ok: false; errors: string[] } {\n const errors: string[] = []\n\n // Check rule count\n if (rules.length === 0) {\n errors.push(\"Lifecycle configuration must have at least one rule\")\n return { ok: false, errors }\n }\n if (rules.length > 100) {\n errors.push(`Lifecycle configuration can have at most 100 rules (found ${rules.length})`)\n return { ok: false, errors }\n }\n\n const seenIds = new Set<string>()\n\n for (let i = 0; i < rules.length; i++) {\n const rule = rules[i]\n const ruleLabel = rule.ID ? `Rule \"${rule.ID}\"` : `Rule #${i + 1}`\n\n // Check ID length\n if (rule.ID && rule.ID.length > 255) {\n errors.push(`${ruleLabel}: ID must be at most 255 characters`)\n }\n\n // Check for duplicate IDs\n if (rule.ID) {\n if (seenIds.has(rule.ID)) {\n errors.push(`${ruleLabel}: Duplicate rule ID`)\n }\n seenIds.add(rule.ID)\n }\n\n // Check Status is valid\n if (rule.Status !== \"Enabled\" && rule.Status !== \"Disabled\") {\n errors.push(`${ruleLabel}: Status must be \"Enabled\" or \"Disabled\" (found \"${rule.Status}\")`)\n }\n\n // Must have at least one action\n const hasExpiration = rule.Expiration !== undefined\n const hasTransitions = rule.Transitions !== undefined && rule.Transitions.length > 0\n const hasNoncurrentExpiration = rule.NoncurrentVersionExpiration !== undefined\n const hasNoncurrentTransitions =\n rule.NoncurrentVersionTransitions !== undefined && rule.NoncurrentVersionTransitions.length > 0\n const hasAbortUpload = rule.AbortIncompleteMultipartUpload !== undefined\n\n if (!hasExpiration && !hasTransitions && !hasNoncurrentExpiration && !hasNoncurrentTransitions && !hasAbortUpload) {\n errors.push(`${ruleLabel}: Must have at least one action`)\n }\n\n // Cannot have both Filter and legacy Prefix\n if (rule.Filter !== undefined && rule.Prefix !== undefined) {\n errors.push(`${ruleLabel}: Cannot have both Filter and legacy Prefix field set`)\n }\n\n // Expiration must specify exactly one of Days/Date/ExpiredObjectDeleteMarker mirrors\n // lifecycleExpirationSchema (server). Catches structurally invalid Expiration objects\n // (e.g. `{}` or `{ Days, Date }`) that the lenient read schema would otherwise let through.\n if (rule.Expiration !== undefined && !isValidExpiration(rule.Expiration)) {\n errors.push(`${ruleLabel}: Expiration must specify exactly one of Days, Date, or ExpiredObjectDeleteMarker`)\n }\n\n // ExpiredObjectDeleteMarker cannot be combined with tag-based filters\n if (rule.Expiration?.ExpiredObjectDeleteMarker === true) {\n const hasTagFilter =\n rule.Filter?.Tag !== undefined || (rule.Filter?.And?.Tags !== undefined && rule.Filter.And.Tags.length > 0)\n if (hasTagFilter) {\n errors.push(`${ruleLabel}: ExpiredObjectDeleteMarker cannot be combined with tag-based filters`)\n }\n }\n\n // AbortIncompleteMultipartUpload cannot be combined with tag-based filters mirrors lifecycleRuleSchema (server)\n if (rule.AbortIncompleteMultipartUpload !== undefined) {\n const hasTagFilter =\n rule.Filter?.Tag !== undefined || (rule.Filter?.And?.Tags !== undefined && rule.Filter.And.Tags.length > 0)\n if (hasTagFilter) {\n errors.push(`${ruleLabel}: AbortIncompleteMultipartUpload cannot be combined with tag-based filters`)\n }\n }\n\n // ExpiredObjectDeleteMarker is a distinct action — mirrors lifecycleExpirationSchema (server)\n if (\n rule.Expiration?.ExpiredObjectDeleteMarker === true &&\n (rule.Expiration.Days !== undefined || rule.Expiration.Date !== undefined)\n ) {\n errors.push(`${ruleLabel}: ExpiredObjectDeleteMarker cannot be combined with Days or Date`)\n }\n\n // And filter must have ≥2 predicates — per-tag counting, mirrors lifecycleFilterAndSchema (server)\n if (rule.Filter?.And) {\n const predicateCount =\n (rule.Filter.And.Prefix !== undefined && rule.Filter.And.Prefix !== \"\" ? 1 : 0) +\n (rule.Filter.And.Tags?.length ?? 0) +\n (rule.Filter.And.ObjectSizeGreaterThan !== undefined ? 1 : 0) +\n (rule.Filter.And.ObjectSizeLessThan !== undefined ? 1 : 0)\n if (predicateCount < 2) {\n errors.push(`${ruleLabel}: And filter must contain at least 2 predicates`)\n }\n }\n\n // Top-level conditions must not combine with each other or with And — mirrors lifecycleFilterSchema (server)\n if (rule.Filter) {\n const topLevelConditions = [\n rule.Filter.Prefix !== undefined,\n rule.Filter.Tag !== undefined,\n rule.Filter.ObjectSizeGreaterThan !== undefined,\n rule.Filter.ObjectSizeLessThan !== undefined,\n ].filter(Boolean).length\n if (topLevelConditions > 1 || (rule.Filter.And && topLevelConditions > 0)) {\n errors.push(\n `${ruleLabel}: Multiple filter conditions (Prefix, Tag, ObjectSize) must be wrapped in an And clause`\n )\n }\n }\n\n // NoncurrentVersionExpiration must have NoncurrentDays\n if (rule.NoncurrentVersionExpiration) {\n if (rule.NoncurrentVersionExpiration.NoncurrentDays === undefined) {\n errors.push(`${ruleLabel}: NoncurrentVersionExpiration must have NoncurrentDays`)\n }\n }\n\n // Transitions must have Days XOR Date\n if (rule.Transitions) {\n for (let j = 0; j < rule.Transitions.length; j++) {\n const transition = rule.Transitions[j]\n const hasDays = transition.Days !== undefined\n const hasDate = transition.Date !== undefined\n if (!hasDays && !hasDate) {\n errors.push(`${ruleLabel}: Transition #${j + 1} must have either Days or Date`)\n }\n if (hasDays && hasDate) {\n errors.push(`${ruleLabel}: Transition #${j + 1} cannot have both Days and Date`)\n }\n }\n }\n }\n\n if (errors.length > 0) {\n return { ok: false, errors }\n }\n\n // Convert all rules\n const convertedRules = rules.map((rule) => toLifecycleRule(rule))\n return { ok: true, rules: convertedRules }\n}\n\n/**\n * Format a lifecycle filter for display\n *\n * Handles legacy top-level Prefix field (item-23) and all Filter variants.\n *\n * @param filter - Filter object\n * @param legacyPrefix - Legacy top-level Prefix field\n * @returns Human-readable filter description\n */\nexport function formatFilter(filter: LifecycleFilter | undefined, legacyPrefix?: string): string {\n if (!filter) {\n // No Filter - check for legacy top-level Prefix\n if (legacyPrefix) {\n return `Prefix: ${legacyPrefix}`\n }\n return \"All objects\"\n }\n const parts: string[] = []\n\n if (filter.Prefix) parts.push(`Prefix: ${filter.Prefix}`)\n if (filter.Tag) parts.push(`Tag: ${filter.Tag.Key}=${filter.Tag.Value}`)\n if (filter.ObjectSizeGreaterThan !== undefined) parts.push(`Size > ${filter.ObjectSizeGreaterThan} bytes`)\n if (filter.ObjectSizeLessThan !== undefined) parts.push(`Size < ${filter.ObjectSizeLessThan} bytes`)\n\n if (filter.And) {\n const andParts: string[] = []\n if (filter.And.Prefix) andParts.push(`Prefix: ${filter.And.Prefix}`)\n if (filter.And.Tags) {\n filter.And.Tags.forEach((tag) => andParts.push(`Tag: ${tag.Key}=${tag.Value}`))\n }\n if (filter.And.ObjectSizeGreaterThan !== undefined)\n andParts.push(`Size > ${filter.And.ObjectSizeGreaterThan} bytes`)\n if (filter.And.ObjectSizeLessThan !== undefined) andParts.push(`Size < ${filter.And.ObjectSizeLessThan} bytes`)\n parts.push(andParts.join(\" AND \"))\n }\n\n return parts.length > 0 ? parts.join(\", \") : \"All objects\"\n}\n\n/**\n * Format lifecycle expiration for display\n *\n * @param expiration - Expiration configuration\n * @returns Human-readable expiration description\n */\nexport function formatExpiration(expiration: LifecycleExpiration | undefined): string {\n if (!expiration) return \"–\"\n if (expiration.Days) return `After ${expiration.Days} days`\n if (expiration.Date) {\n const date = typeof expiration.Date === \"string\" ? new Date(expiration.Date) : expiration.Date\n return `On ${date.toLocaleDateString()}`\n }\n if (expiration.ExpiredObjectDeleteMarker) return \"Clean up expired delete markers\"\n return \"–\"\n}\n\n/**\n * Format lifecycle transitions for display\n *\n * @param transitions - Array of transitions\n * @returns Human-readable transitions description\n */\nexport function formatTransitions(transitions: LifecycleTransition[] | undefined): string {\n if (!transitions || transitions.length === 0) return \"–\"\n return transitions\n .map((t) => {\n const time = t.Days ? `${t.Days} days` : t.Date ? new Date(t.Date).toLocaleDateString() : \"unknown\"\n return `${t.StorageClass} after ${time}`\n })\n .join(\"; \")\n}\n\n/**\n * Format noncurrent version expiration for display\n *\n * @param noncurrentExp - Noncurrent version expiration configuration\n * @returns Human-readable description\n */\nexport function formatNoncurrentExpiration(noncurrentExp: LifecycleNoncurrentVersionExpiration | undefined): string {\n if (!noncurrentExp) return \"–\"\n const parts: string[] = []\n if (noncurrentExp.NoncurrentDays) {\n parts.push(`After ${noncurrentExp.NoncurrentDays} days`)\n }\n if (noncurrentExp.NewerNoncurrentVersions !== undefined) {\n parts.push(`(keep ${noncurrentExp.NewerNoncurrentVersions} versions)`)\n }\n return parts.length > 0 ? parts.join(\" \") : \"–\"\n}\n\n/**\n * Format noncurrent version transitions for display\n *\n * @param transitions - Array of noncurrent version transitions\n * @returns Human-readable description\n */\nexport function formatNoncurrentTransitions(transitions: LifecycleNoncurrentVersionTransition[] | undefined): string {\n if (!transitions || transitions.length === 0) return \"–\"\n return transitions\n .map((t) => {\n const keep = t.NewerNoncurrentVersions !== undefined ? ` (keep ${t.NewerNoncurrentVersions})` : \"\"\n return `${t.StorageClass} after ${t.NoncurrentDays} days${keep}`\n })\n .join(\"; \")\n}\n","import { useEffect, useState } from \"react\"\nimport { Modal, Status } from \"@cloudoperators/juno-ui-components\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport { useModalTracking } from \"@/client/hooks/useModalTracking\"\nimport { validateLifecycleRules } from \"./utils/lifecycleUtils\"\n\ninterface DeleteLifecycleRuleModalProps {\n isOpen: boolean\n bucketName: string\n ruleIndex: number\n ruleId?: string\n onClose: () => void\n onSuccess?: (ruleIndex: number) => void\n onError?: (ruleIndex: number, errorMessage: string) => void\n onMutatingChange?: (isMutating: boolean) => void\n}\n\n/**\n * Modal to confirm deletion of a single lifecycle rule\n *\n * Refetches lifecycle configuration before deleting to avoid lost updates.\n * If deleting the last rule, calls lifecycle.delete instead of lifecycle.set.\n */\nexport const DeleteLifecycleRuleModal = ({\n isOpen,\n bucketName,\n ruleIndex,\n ruleId,\n onClose,\n onSuccess,\n onError,\n onMutatingChange,\n}: DeleteLifecycleRuleModalProps) => {\n const { t } = useLingui()\n const projectId = useProjectId()\n const utils = trpcReact.useUtils()\n const [isVerifying, setIsVerifying] = useState(false)\n\n const { trackClose, markSubmitted, resetTracking } = useModalTracking({\n isOpen,\n actionPrefix: \"storage.ceph.lifecycle.rule.delete\",\n })\n\n // Query current lifecycle configuration (for loading/error states only - fresh data fetched in handleConfirm)\n const {\n data: lifecycleData,\n isLoading,\n error: queryError,\n } = trpcReact.storage.ceph.lifecycle.get.useQuery(\n {\n project_id: projectId,\n bucketName,\n },\n {\n enabled: isOpen && !!projectId,\n retry: false,\n staleTime: 5 * 60 * 1000,\n }\n )\n\n // Delete mutation (when removing last rule)\n const deleteMutation = trpcReact.storage.ceph.lifecycle.delete.useMutation({\n onSuccess: () => {\n utils.storage.ceph.lifecycle.get.invalidate()\n onSuccess?.(ruleIndex)\n handleClose()\n },\n onError: (error) => {\n onError?.(ruleIndex, error.message)\n },\n })\n\n // Set mutation (when other rules remain)\n const setMutation = trpcReact.storage.ceph.lifecycle.set.useMutation({\n onSuccess: () => {\n utils.storage.ceph.lifecycle.get.invalidate()\n onSuccess?.(ruleIndex)\n handleClose()\n },\n onError: (error) => {\n onError?.(ruleIndex, error.message)\n },\n })\n\n const isMutating = deleteMutation.isPending || setMutation.isPending\n\n useEffect(() => {\n onMutatingChange?.(isMutating)\n }, [isMutating, onMutatingChange])\n\n useEffect(() => {\n if (!isOpen) {\n deleteMutation.reset()\n setMutation.reset()\n setIsVerifying(false)\n resetTracking()\n }\n }, [isOpen])\n\n const handleClose = () => {\n trackClose()\n deleteMutation.reset()\n setMutation.reset()\n setIsVerifying(false)\n resetTracking()\n onClose()\n }\n\n const handleConfirm = async () => {\n if (isVerifying) return\n\n markSubmitted()\n setIsVerifying(true)\n\n try {\n // Refetch to get fresh state\n const freshData = await utils.storage.ceph.lifecycle.get.fetch({\n project_id: projectId,\n bucketName,\n })\n\n const freshRules = freshData?.rules ?? []\n const cachedRule = lifecycleData?.rules?.[ruleIndex]\n const freshRule = freshRules[ruleIndex]\n\n // Freshness check: verify the rule at this index matches what the user selected\n if (!freshRule || JSON.stringify(freshRule) !== JSON.stringify(cachedRule)) {\n onError?.(ruleIndex, t`The lifecycle configuration has changed. Please refresh and try again.`)\n return\n }\n\n // Remove the rule\n const remaining = freshRules.filter((_, i) => i !== ruleIndex)\n\n if (remaining.length === 0) {\n // Last rule - delete entire configuration\n deleteMutation.mutate({\n project_id: projectId,\n bucketName,\n })\n } else {\n // Other rules remain - validate and set\n const validation = validateLifecycleRules(remaining)\n if (!validation.ok) {\n const errorMsg = validation.errors.join(\"; \")\n onError?.(ruleIndex, t`Cannot delete rule: ${errorMsg}`)\n return\n }\n\n setMutation.mutate({\n project_id: projectId,\n bucketName,\n lifecycleConfiguration: {\n Rules: validation.rules,\n },\n })\n }\n } catch (error) {\n onError?.(ruleIndex, error instanceof Error ? error.message : String(error))\n } finally {\n setIsVerifying(false)\n }\n }\n\n const ruleNumber = ruleIndex + 1\n const displayName = ruleId || t`Rule #${ruleNumber}`\n\n return (\n <Modal\n open={isOpen}\n onCancel={handleClose}\n title={t`Delete Lifecycle Rule`}\n size=\"small\"\n confirmButtonLabel={isMutating ? t`Deleting...` : t`Delete Lifecycle Rule`}\n confirmButtonVariant=\"primary-danger\"\n onConfirm={handleConfirm}\n cancelButtonLabel={t`Cancel`}\n disableConfirmButton={isMutating || isVerifying || isLoading || !!queryError}\n disableCancelButton={isMutating || isVerifying}\n disableCloseButton={isMutating || isVerifying}\n closeOnEsc={!(isMutating || isVerifying)}\n >\n {isLoading ? (\n <Status status=\"progress\" title={t`Loading Lifecycle Configuration...`} className=\"mt-0\" />\n ) : queryError ? (\n <Status\n status=\"error\"\n title={t`Failed to Load Lifecycle Configuration`}\n body={queryError.message}\n className=\"mt-0\"\n />\n ) : (\n <>\n <p>\n <Trans>\n Are you sure you want to delete lifecycle rule <strong>{displayName}</strong> from bucket{\" \"}\n <strong>{bucketName}</strong>?\n </Trans>\n </p>\n <p className=\"mt-2\">\n <Trans>This action cannot be undone.</Trans>\n </p>\n </>\n )}\n </Modal>\n )\n}\n","import { useState } from \"react\"\nimport {\n DataGrid,\n DataGridHeadCell,\n DataGridRow,\n DataGridCell,\n Stack,\n PopupMenu,\n PopupMenuItem,\n PopupMenuOptions,\n Checkbox,\n Status,\n toast,\n} from \"@cloudoperators/juno-ui-components\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport type { LifecycleRuleRead } from \"@/server/Storage/types/ceph\"\nimport { DeleteLifecycleRuleModal } from \"./DeleteLifecycleRuleModal\"\nimport { getLifecycleRuleDeletedToast, getLifecycleRuleDeleteErrorToast } from \"./BucketToastNotifications\"\nimport {\n formatFilter,\n formatExpiration,\n formatTransitions,\n formatNoncurrentExpiration,\n formatNoncurrentTransitions,\n} from \"./utils/lifecycleUtils\"\n\ninterface LifecycleRuleWithIndex {\n rule: LifecycleRuleRead\n originalIndex: number\n}\n\ninterface LifecycleRulesTableProps {\n bucketName: string\n rulesWithIndices: LifecycleRuleWithIndex[]\n selectedIndices: number[]\n onToggleSelectRule: (index: number) => void\n onEditRule: (index: number) => void\n onDeleteRule?: (index: number) => void\n isMutating?: boolean\n isFiltered?: boolean\n canUpdateLifecycle: boolean\n canDeleteLifecycle: boolean\n}\n\n/**\n * Data grid for displaying and managing lifecycle rules\n *\n * Displays up to 100 rules (S3 limit) in a simple table.\n * Supports search/filter by Rule ID.\n */\nexport function LifecycleRulesTable({\n bucketName,\n rulesWithIndices,\n selectedIndices,\n onToggleSelectRule,\n onEditRule,\n onDeleteRule,\n isMutating = false,\n isFiltered = false,\n canUpdateLifecycle,\n canDeleteLifecycle,\n}: LifecycleRulesTableProps) {\n const { t } = useLingui()\n\n const [isRowDeleteMutating, setIsRowDeleteMutating] = useState(false)\n\n const [deleteModalState, setDeleteModalState] = useState<{\n isOpen: boolean\n ruleIndex: number\n ruleId?: string\n }>({\n isOpen: false,\n ruleIndex: -1,\n ruleId: undefined,\n })\n\n const handleOpenDeleteModal = (index: number, ruleId?: string) => {\n setDeleteModalState({\n isOpen: true,\n ruleIndex: index,\n ruleId,\n })\n }\n\n const handleCloseDeleteModal = () => {\n setDeleteModalState({\n isOpen: false,\n ruleIndex: -1,\n ruleId: undefined,\n })\n }\n\n const handleDeleteSuccess = (index: number) => {\n const { message, ...options } = getLifecycleRuleDeletedToast(bucketName, deleteModalState.ruleId)\n toast.success(message, options)\n // Call parent callback if provided (for draft state updates in parent)\n onDeleteRule?.(index)\n }\n\n const handleDeleteError = (_index: number, errorMessage: string) => {\n const { message, ...options } = getLifecycleRuleDeleteErrorToast(bucketName, errorMessage, deleteModalState.ruleId)\n toast.error(message, options)\n }\n\n const effectiveIsMutating = isMutating || isRowDeleteMutating\n\n const isEmpty = rulesWithIndices.length === 0\n const columnCount = canDeleteLifecycle ? 8 : 7\n // minContentColumns is a zero-based column-index array. Dropping the leading select\n // column shifts the actions column from index 7 to 6.\n const minContentColumns = canDeleteLifecycle ? [0, 7] : [6]\n\n return (\n <Stack direction=\"vertical\" gap=\"4\">\n {/* Rules Table */}\n <DataGrid columns={columnCount} minContentColumns={minContentColumns}>\n <DataGridRow>\n {canDeleteLifecycle && (\n <DataGridHeadCell>\n <span className=\"sr-only\">\n <Trans>Select</Trans>\n </span>\n </DataGridHeadCell>\n )}\n <DataGridHeadCell>{t`Rule ID`}</DataGridHeadCell>\n <DataGridHeadCell>{t`Status`}</DataGridHeadCell>\n <DataGridHeadCell>{t`Scope`}</DataGridHeadCell>\n <DataGridHeadCell>{t`Expiration`}</DataGridHeadCell>\n <DataGridHeadCell>{t`Noncurrent Versions`}</DataGridHeadCell>\n <DataGridHeadCell>{t`Other Actions`}</DataGridHeadCell>\n <DataGridHeadCell></DataGridHeadCell>\n </DataGridRow>\n {isEmpty ? (\n <DataGridRow>\n <DataGridCell colSpan={columnCount}>\n {isFiltered ? (\n <Status status=\"no-matches\" title={t`No Lifecycle Rules Matching the Current Search Criteria.`} />\n ) : (\n <Status status=\"empty\" title={t`There Are No Lifecycle Rules for This Bucket`} />\n )}\n </DataGridCell>\n </DataGridRow>\n ) : (\n rulesWithIndices.map(({ rule, originalIndex }) => {\n // Rules are keyed by array index - they have no stable server-side id.\n // ID field is optional and may be absent or duplicated.\n // originalIndex is the contract with parent's onEditRule(index) / onDeleteRule(index).\n const key = originalIndex\n\n // Format noncurrent versions column (merge expiration + transitions)\n const noncurrentExpirationText = formatNoncurrentExpiration(\n rule.NoncurrentVersionExpiration as unknown as {\n NoncurrentDays: number\n NewerNoncurrentVersions?: number\n }\n )\n const noncurrentTransitionsText = formatNoncurrentTransitions(\n rule.NoncurrentVersionTransitions as unknown as {\n NoncurrentDays: number\n StorageClass: string\n NewerNoncurrentVersions?: number\n }[]\n )\n const noncurrentText =\n noncurrentExpirationText === \"–\" && noncurrentTransitionsText === \"–\"\n ? \"–\"\n : [noncurrentExpirationText, noncurrentTransitionsText].filter((t) => t !== \"–\").join(\"; \")\n\n // Format other actions column (transitions + abort)\n const transitionsText = formatTransitions(\n rule.Transitions as unknown as { StorageClass: string; Days?: number; Date?: string }[]\n )\n const abortDays = rule.AbortIncompleteMultipartUpload?.DaysAfterInitiation\n const abortText = abortDays !== undefined ? t`After ${abortDays} days` : \"–\"\n const otherActionsText =\n transitionsText === \"–\" && abortText === \"–\"\n ? \"–\"\n : [transitionsText, abortText].filter((t) => t !== \"–\").join(\"; \")\n\n const ruleLabel = rule.ID || String(originalIndex + 1)\n\n const hasAnyRowAction = canUpdateLifecycle || canDeleteLifecycle\n\n return (\n <DataGridRow key={key} data-testid={`lifecycle-rule-row-${originalIndex}`}>\n {canDeleteLifecycle && (\n <DataGridCell onClick={(e) => e.stopPropagation()}>\n <Checkbox\n checked={selectedIndices.includes(originalIndex)}\n onChange={() => onToggleSelectRule(originalIndex)}\n aria-label={t`Select rule ${ruleLabel}`}\n data-testid={`select-rule-${originalIndex}`}\n />\n </DataGridCell>\n )}\n <DataGridCell>{rule.ID || t`—`}</DataGridCell>\n <DataGridCell>{rule.Status}</DataGridCell>\n <DataGridCell className=\"break-all\">{formatFilter(rule.Filter, rule.Prefix)}</DataGridCell>\n <DataGridCell>\n {formatExpiration(\n rule.Expiration as unknown as { Days?: number; Date?: string; ExpiredObjectDeleteMarker?: boolean }\n )}\n </DataGridCell>\n <DataGridCell>{noncurrentText}</DataGridCell>\n <DataGridCell>{otherActionsText}</DataGridCell>\n <DataGridCell onClick={(e) => e.stopPropagation()} className=\"justify-end pr-0\">\n {hasAnyRowAction && (\n <div className=\"flex h-full items-center justify-end\">\n <PopupMenu>\n <PopupMenuOptions>\n {canUpdateLifecycle && (\n <PopupMenuItem\n label={t`Edit Lifecycle Rule`}\n onClick={() => onEditRule(originalIndex)}\n disabled={effectiveIsMutating}\n />\n )}\n {canDeleteLifecycle && (\n <PopupMenuItem\n label={t`Delete Lifecycle Rule`}\n onClick={() => handleOpenDeleteModal(originalIndex, rule.ID)}\n disabled={effectiveIsMutating}\n />\n )}\n </PopupMenuOptions>\n </PopupMenu>\n </div>\n )}\n </DataGridCell>\n </DataGridRow>\n )\n })\n )}\n </DataGrid>\n\n {/* Delete Lifecycle Rule Modal */}\n <DeleteLifecycleRuleModal\n isOpen={deleteModalState.isOpen}\n bucketName={bucketName}\n ruleIndex={deleteModalState.ruleIndex}\n ruleId={deleteModalState.ruleId}\n onClose={handleCloseDeleteModal}\n onSuccess={handleDeleteSuccess}\n onError={handleDeleteError}\n onMutatingChange={setIsRowDeleteMutating}\n />\n </Stack>\n )\n}\n","import { useForm, useStore } from \"@tanstack/react-form\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { useEffect, useState } from \"react\"\nimport {\n Form,\n Stack,\n TextInput,\n Button,\n Checkbox,\n Message,\n Pill,\n Label,\n Divider,\n} from \"@cloudoperators/juno-ui-components\"\nimport type { LifecycleRuleRead, LifecycleTag } from \"@/server/Storage/types/ceph\"\nimport { normalizeFilter, parseDaysValue, isValidExpiration } from \"./utils/lifecycleUtils\"\n\ninterface LifecycleRuleFormProps {\n editingRule: LifecycleRuleRead | null\n onSubmit: (rule: LifecycleRuleRead) => void\n formId: string\n onValidationChange?: (isValid: boolean) => void\n}\n\nexport const LifecycleRuleForm = ({ editingRule, onSubmit, formId, onValidationChange }: LifecycleRuleFormProps) => {\n const { t } = useLingui()\n\n // Extract values from editing rule\n const getInitialValues = () => {\n if (!editingRule) {\n return {\n ID: \"\",\n Status: \"Disabled\" as const,\n Prefix: \"\",\n tags: [] as LifecycleTag[],\n hasExpiration: false,\n expirationDays: \"\",\n hasNoncurrentExpiration: false,\n noncurrentDays: \"\",\n hasAbortUpload: false,\n abortDays: \"\",\n }\n }\n\n const filter = editingRule.Filter\n const expiration = editingRule.Expiration\n const noncurrentExp = editingRule.NoncurrentVersionExpiration\n const abort = editingRule.AbortIncompleteMultipartUpload\n\n // Extract prefix and tags from filter\n // Fall back to legacy top-level Prefix field if Filter is absent (item 23 fix)\n let prefix = \"\"\n let tags: LifecycleTag[] = []\n if (filter) {\n if (\"Prefix\" in filter && filter.Prefix) {\n prefix = filter.Prefix\n }\n if (\"Tag\" in filter && filter.Tag) {\n tags = [filter.Tag]\n }\n if (\"And\" in filter && filter.And) {\n if (filter.And.Prefix) prefix = filter.And.Prefix\n if (filter.And.Tags) tags = filter.And.Tags\n }\n } else if (editingRule.Prefix) {\n // Legacy top-level Prefix (no Filter present)\n prefix = editingRule.Prefix\n }\n\n return {\n ID: editingRule.ID || \"\",\n Status: (editingRule.Status || \"Disabled\") as \"Enabled\" | \"Disabled\",\n Prefix: prefix,\n tags,\n hasExpiration: expiration !== undefined,\n // Only populate expirationDays if the rule actually uses Days (item 24 fix)\n // If it uses Date or ExpiredObjectDeleteMarker, leave empty (preserve original on submit)\n expirationDays: expiration?.Days?.toString() || \"\",\n hasNoncurrentExpiration: noncurrentExp !== undefined,\n noncurrentDays: noncurrentExp?.NoncurrentDays?.toString() || \"\",\n hasAbortUpload: abort !== undefined,\n abortDays: abort?.DaysAfterInitiation?.toString() || \"\",\n }\n }\n\n const form = useForm({\n defaultValues: getInitialValues(),\n onSubmit: ({ value }) => {\n // Trim the Prefix so the submitted filter agrees with the whole-bucket warning shown to the user\n // (see willExpireWholeBucket below, which also checks the trimmed value).\n const trimmedPrefix = value.Prefix.trim()\n const filter = normalizeFilter(trimmedPrefix || undefined, value.tags.length > 0 ? value.tags : undefined)\n\n const newRule: LifecycleRuleRead = {\n ID: value.ID || undefined,\n Status: value.Status,\n Filter: filter,\n Prefix: undefined, // Clear legacy Prefix field (item 23 fix)\n }\n\n // If editing, preserve the existing Expiration field byte-identical if user didn't change it (item 24 fix)\n if (value.hasExpiration) {\n const exp = parseDaysValue(value.expirationDays)\n if (exp.ok) {\n newRule.Expiration = { Days: exp.value }\n } else if (editingRule?.Expiration && isValidExpiration(editingRule.Expiration)) {\n // Preserve the original Expiration (Date or ExpiredObjectDeleteMarker) unchanged.\n // Guarded by isValidExpiration so a structurally invalid, externally-authored\n // Expiration (e.g. `{}`) isn't silently resubmitted to fail server validation.\n newRule.Expiration = editingRule.Expiration\n }\n }\n\n // Preserve Transitions byte-identical (item 1 fix)\n if (editingRule?.Transitions) {\n newRule.Transitions = editingRule.Transitions\n }\n\n if (value.hasNoncurrentExpiration) {\n const nc = parseDaysValue(value.noncurrentDays)\n if (nc.ok) {\n newRule.NoncurrentVersionExpiration = {\n NoncurrentDays: nc.value,\n ...(editingRule?.NoncurrentVersionExpiration?.NewerNoncurrentVersions !== undefined && {\n NewerNoncurrentVersions: editingRule.NoncurrentVersionExpiration.NewerNoncurrentVersions,\n }),\n }\n }\n }\n\n // Preserve NoncurrentVersionTransitions if present (read-only)\n if (editingRule?.NoncurrentVersionTransitions) {\n newRule.NoncurrentVersionTransitions = editingRule.NoncurrentVersionTransitions\n }\n\n if (value.hasAbortUpload) {\n const abort = parseDaysValue(value.abortDays)\n if (abort.ok) {\n newRule.AbortIncompleteMultipartUpload = {\n DaysAfterInitiation: abort.value,\n }\n }\n }\n\n onSubmit(newRule)\n },\n })\n\n const hasExpirationValue = useStore(form.store, (state) => state.values.hasExpiration)\n const hasNoncurrentExpirationValue = useStore(form.store, (state) => state.values.hasNoncurrentExpiration)\n const hasAbortUploadValue = useStore(form.store, (state) => state.values.hasAbortUpload)\n const expirationDaysValue = useStore(form.store, (state) => state.values.expirationDays)\n const noncurrentDaysValue = useStore(form.store, (state) => state.values.noncurrentDays)\n const abortDaysValue = useStore(form.store, (state) => state.values.abortDays)\n const tagsValue = useStore(form.store, (state) => state.values.tags)\n const statusValue = useStore(form.store, (state) => state.values.Status)\n const prefixValue = useStore(form.store, (state) => state.values.Prefix)\n\n const willExpireWholeBucket =\n hasExpirationValue && !prefixValue.trim() && tagsValue.length === 0 && statusValue === \"Enabled\"\n\n // Only surface \"invalid\" (not \"empty\") so a freshly-checked box doesn't flash an error immediately.\n const daysError = (checked: boolean, raw: string) => {\n if (!checked) return undefined\n const result = parseDaysValue(raw)\n return !result.ok && result.reason === \"invalid\" ? t`Enter a whole number of days greater than 0` : undefined\n }\n const expirationDaysError = daysError(hasExpirationValue, expirationDaysValue)\n const noncurrentDaysError = daysError(hasNoncurrentExpirationValue, noncurrentDaysValue)\n const abortDaysError = daysError(hasAbortUploadValue, abortDaysValue)\n\n const canSubmit = () => {\n // Use the reactive values from useStore, not form.state.values\n const hasAtLeastOneAction =\n hasExpirationValue ||\n hasNoncurrentExpirationValue ||\n hasAbortUploadValue ||\n (editingRule?.Transitions !== undefined && editingRule.Transitions.length > 0) ||\n (editingRule?.NoncurrentVersionTransitions !== undefined && editingRule.NoncurrentVersionTransitions.length > 0)\n\n if (!hasAtLeastOneAction) return false\n\n // If expiration is checked, must have valid days OR we're preserving non-Days expiration from editing\n if (hasExpirationValue) {\n const r = parseDaysValue(expirationDaysValue)\n const hasPreservableNonDaysExpiration =\n editingRule?.Expiration &&\n editingRule.Expiration.Days === undefined &&\n isValidExpiration(editingRule.Expiration)\n const validExpirationDays = r.ok || (!r.ok && r.reason === \"empty\" && !!hasPreservableNonDaysExpiration)\n if (!validExpirationDays) return false\n }\n\n // If noncurrent expiration is checked, must have valid days\n if (hasNoncurrentExpirationValue && !parseDaysValue(noncurrentDaysValue).ok) return false\n\n // If abort is checked, must have valid days\n if (hasAbortUploadValue && !parseDaysValue(abortDaysValue).ok) return false\n\n if (hasAbortUploadValue && tagsValue.length > 0) return false\n\n return true\n }\n\n // Notify parent about validation state changes\n useEffect(() => {\n onValidationChange?.(canSubmit())\n }, [\n hasExpirationValue,\n hasNoncurrentExpirationValue,\n hasAbortUploadValue,\n expirationDaysValue,\n noncurrentDaysValue,\n abortDaysValue,\n tagsValue,\n editingRule,\n onValidationChange,\n ])\n\n // Tag editor state\n const [newTagKey, setNewTagKey] = useState(\"\")\n const [newTagValue, setNewTagValue] = useState(\"\")\n const [tagError, setTagError] = useState<string | undefined>()\n\n return (\n <Form\n id={formId}\n role=\"form\"\n onSubmit={(e) => {\n e.preventDefault()\n e.stopPropagation()\n form.handleSubmit()\n }}\n >\n <Stack direction=\"vertical\" gap=\"5\">\n {/* Rule ID */}\n <form.Field name=\"ID\">\n {(field) => (\n <TextInput\n label={t`Rule ID`}\n id={field.name}\n name={field.name}\n value={field.state.value}\n onChange={(e) => field.handleChange(e.target.value)}\n onBlur={field.handleBlur}\n placeholder={t`e.g. my-lifecycle-rule`}\n helptext={t`Optional unique identifier for the rule (max 255 characters)`}\n />\n )}\n </form.Field>\n\n <Divider />\n\n {/* Scope section - Filter by prefix and/or tags */}\n <p>\n <Trans>\n Prefix and tag filters define which objects a rule applies to. Without them, this rule will be applied to\n all objects in the bucket.\n </Trans>\n </p>\n\n <form.Field name=\"Prefix\">\n {(field) => (\n <TextInput\n label={t`Scope`}\n id={field.name}\n name={field.name}\n value={field.state.value}\n onChange={(e) => field.handleChange(e.target.value)}\n onBlur={() => {\n const trimmed = field.state.value.trim()\n if (trimmed !== field.state.value) {\n field.handleChange(trimmed)\n }\n field.handleBlur()\n }}\n placeholder={t`e.g. bucket/folder/subfolder`}\n helptext={t`Apply this rule only to objects with this prefix (leave empty for all objects)`}\n />\n )}\n </form.Field>\n\n {/* Tag editor */}\n <form.Field name=\"tags\">\n {(field) => {\n const addTag = () => {\n const key = newTagKey.trim()\n const value = newTagValue.trim()\n\n if (!key || !value) return\n\n if (field.state.value.some((tag) => tag.Key === key)) {\n setTagError(t`A tag with this key already exists.`)\n return\n }\n\n const currentTags = field.state.value\n field.handleChange([...currentTags, { Key: key, Value: value }])\n setNewTagKey(\"\")\n setNewTagValue(\"\")\n setTagError(undefined)\n }\n\n const removeTag = (index: number) => {\n const currentTags = field.state.value\n field.handleChange(currentTags.filter((_, i) => i !== index))\n }\n\n return (\n <Stack direction=\"vertical\" gap=\"2\">\n <div>\n <div className=\"flex items-start gap-2\">\n <div className=\"flex-1\">\n <TextInput\n label={t`Key`}\n value={newTagKey}\n onChange={(e) => {\n setNewTagKey(e.target.value)\n setTagError(undefined)\n }}\n onKeyDown={(e) => {\n if (e.key === \"Enter\") {\n e.preventDefault()\n addTag()\n }\n }}\n placeholder={t`e.g. environment`}\n invalid={!!tagError}\n errortext={tagError}\n disabled={hasAbortUploadValue}\n />\n </div>\n <div className=\"flex-1\">\n <TextInput\n label={t`Value`}\n value={newTagValue}\n onChange={(e) => setNewTagValue(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\") {\n e.preventDefault()\n addTag()\n }\n }}\n placeholder={t`e.g. production`}\n disabled={hasAbortUploadValue}\n />\n </div>\n <Button onClick={addTag} disabled={hasAbortUploadValue || !newTagKey.trim() || !newTagValue.trim()}>\n <Trans>Add</Trans>\n </Button>\n </div>\n {field.state.value.length > 0 && (\n <Stack gap=\"2\" wrap={true} alignment=\"start\" distribution=\"start\" className=\"mt-2\">\n {field.state.value.map((tag, index) => (\n <div key={`${tag.Key}-${tag.Value}-${index}`} className=\"max-w-full break-all\">\n <Pill pillKey={tag.Key} pillValue={tag.Value} onClose={() => removeTag(index)} closeable />\n </div>\n ))}\n </Stack>\n )}\n </div>\n <p className=\"juno-helptext mt-1 text-xs\" style={{ color: \"#7a7a7a\" }}>\n <Trans>\n Apply this rule only to objects with specific tags. Cannot be combined with Abort Incomplete\n Multipart Uploads.\n </Trans>\n </p>\n </Stack>\n )\n }}\n </form.Field>\n\n <Divider />\n\n {/* Actions section */}\n <Stack direction=\"vertical\" gap=\"2\">\n <Label text={t`Select at least one lifecycle action`} required />\n <Stack direction=\"vertical\" gap=\"4\">\n {/* Read-only notice for Transitions */}\n {editingRule?.Transitions && editingRule.Transitions.length > 0 && (\n <Message variant=\"info\" title={t`Storage Class Transitions (read-only)`}>\n <Trans>\n This rule has storage-class transitions that were configured outside Aurora. They are preserved\n unchanged when you save this rule.\n </Trans>\n </Message>\n )}\n\n {/* Read-only notice for NoncurrentVersionTransitions */}\n {editingRule?.NoncurrentVersionTransitions &&\n editingRule.NoncurrentVersionTransitions.length > 0 &&\n (() => {\n const noncurrentTransitionCount = editingRule.NoncurrentVersionTransitions.length\n return (\n <Message variant=\"info\" title={t`Noncurrent Version Transitions (Read-Only)`}>\n <Trans>\n This rule has {noncurrentTransitionCount} noncurrent version transition(s) configured. Transitions\n cannot be edited in this UI. Changing other fields will preserve the existing transitions.\n </Trans>\n </Message>\n )\n })()}\n\n {/* Expiration action */}\n <div>\n <form.Field name=\"hasExpiration\">\n {(field) => (\n <Checkbox\n id={field.name}\n name={field.name}\n checked={field.state.value}\n onChange={(e) => field.handleChange(e.target.checked)}\n label={t`Expire objects`}\n />\n )}\n </form.Field>\n\n {hasExpirationValue && (\n <div className=\"mt-2\">\n <form.Field name=\"expirationDays\">\n {(field) => (\n <TextInput\n label={t`Days until deletion`}\n id={field.name}\n name={field.name}\n type=\"number\"\n value={field.state.value}\n onChange={(e) => field.handleChange(e.target.value)}\n onBlur={field.handleBlur}\n placeholder=\"30\"\n min=\"1\"\n invalid={!!expirationDaysError}\n errortext={expirationDaysError}\n helptext={\n editingRule?.Expiration && !editingRule.Expiration.Days\n ? t`This rule uses Date or ExpiredObjectDeleteMarker expiration. Leave empty to preserve it, or enter days to switch to Days expiration.`\n : undefined\n }\n required={!editingRule?.Expiration || editingRule.Expiration.Days !== undefined}\n />\n )}\n </form.Field>\n </div>\n )}\n </div>\n\n {/* Noncurrent version expiration action */}\n <div>\n <form.Field name=\"hasNoncurrentExpiration\">\n {(field) => (\n <Checkbox\n id={field.name}\n name={field.name}\n checked={field.state.value}\n onChange={(e) => field.handleChange(e.target.checked)}\n label={t`Expire non-current versions`}\n />\n )}\n </form.Field>\n\n {hasNoncurrentExpirationValue && (\n <div className=\"mt-2\">\n <form.Field name=\"noncurrentDays\">\n {(field) => (\n <TextInput\n label={t`Days after becoming non-current`}\n id={field.name}\n name={field.name}\n type=\"number\"\n value={field.state.value}\n onChange={(e) => field.handleChange(e.target.value)}\n onBlur={field.handleBlur}\n placeholder=\"90\"\n min=\"1\"\n invalid={!!noncurrentDaysError}\n errortext={noncurrentDaysError}\n required={true}\n />\n )}\n </form.Field>\n </div>\n )}\n </div>\n\n {/* Abort incomplete multipart upload action */}\n <div>\n <form.Field name=\"hasAbortUpload\">\n {(field) => (\n <Checkbox\n id={field.name}\n name={field.name}\n checked={field.state.value}\n onChange={(e) => field.handleChange(e.target.checked)}\n label={t`Abort incomplete multipart uploads`}\n disabled={tagsValue.length > 0}\n helptext={tagsValue.length > 0 ? t`Cannot be combined with Tag Filters` : undefined}\n />\n )}\n </form.Field>\n\n {hasAbortUploadValue && (\n <div className=\"mt-2\">\n <form.Field name=\"abortDays\">\n {(field) => (\n <TextInput\n label={t`Days until cleanup`}\n id={field.name}\n name={field.name}\n type=\"number\"\n value={field.state.value}\n onChange={(e) => field.handleChange(e.target.value)}\n onBlur={field.handleBlur}\n placeholder=\"7\"\n min=\"1\"\n invalid={!!abortDaysError}\n errortext={abortDaysError}\n required={true}\n />\n )}\n </form.Field>\n </div>\n )}\n </div>\n </Stack>\n </Stack>\n\n <Divider />\n\n {/* Status */}\n <form.Field name=\"Status\">\n {(field) => (\n <div>\n <Checkbox\n id={field.name}\n name={field.name}\n checked={field.state.value === \"Enabled\"}\n onChange={(e) => field.handleChange(e.target.checked ? \"Enabled\" : \"Disabled\")}\n label={t`Enable rule`}\n />\n <p className=\"juno-helptext mt-1 text-xs\" style={{ color: \"#7a7a7a\" }}>\n <Trans>Leave unchecked to save without activating.</Trans>\n </p>\n </div>\n )}\n </form.Field>\n\n {willExpireWholeBucket && (\n <Message variant=\"warning\" title={t`Bucket expiration warning`}>\n <Trans>\n This rule has no prefix or tag filters, so it will expire all objects in the bucket. This can result in\n permanent data loss.\n </Trans>\n </Message>\n )}\n </Stack>\n </Form>\n )\n}\n","import { useEffect, useState } from \"react\"\nimport { Modal, Status, Message, ModalFooter, ButtonRow, Button } from \"@cloudoperators/juno-ui-components\"\nimport { useLingui } from \"@lingui/react/macro\"\nimport { Trans } from \"@lingui/react/macro\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport { useModalTracking } from \"@/client/hooks/useModalTracking\"\nimport { LifecycleRuleForm } from \"./LifecycleRuleForm\"\nimport type { LifecycleRuleRead } from \"@/server/Storage/types/ceph\"\nimport { validateLifecycleRules } from \"./utils/lifecycleUtils\"\n\ninterface LifecycleRuleModalProps {\n isOpen: boolean\n bucketName: string\n editingIndex: number | null // null = adding, non-null = editing\n onClose: () => void\n onSuccess?: (bucketName: string) => void\n onError?: (bucketName: string, errorMessage: string) => void\n onMutatingChange?: (isMutating: boolean) => void\n}\n\n/**\n * Modal wrapper for LifecycleRuleForm\n *\n * Handles adding or editing a single lifecycle rule.\n * Loads current lifecycle configuration, adds/updates the rule, and calls lifecycle.set.\n */\nexport const LifecycleRuleModal = ({\n isOpen,\n bucketName,\n editingIndex,\n onClose,\n onSuccess,\n onError,\n onMutatingChange,\n}: LifecycleRuleModalProps) => {\n const { t } = useLingui()\n const projectId = useProjectId()\n const utils = trpcReact.useUtils()\n const [isFormValid, setIsFormValid] = useState(false)\n const [validationErrors, setValidationErrors] = useState<string[]>([])\n\n const { trackClose, markSubmitted, resetTracking } = useModalTracking({\n isOpen,\n actionPrefix: \"storage.ceph.bucket.lifecycle\",\n })\n\n // Query to get current lifecycle configuration\n const {\n data: lifecycleData,\n isLoading: isLifecycleLoading,\n error: lifecycleError,\n } = trpcReact.storage.ceph.lifecycle.get.useQuery(\n {\n project_id: projectId,\n bucketName,\n },\n {\n enabled: isOpen && !!projectId,\n retry: false,\n staleTime: 5 * 60 * 1000,\n }\n )\n\n // Set mutation\n const setMutation = trpcReact.storage.ceph.lifecycle.set.useMutation({\n onSuccess: () => {\n utils.storage.ceph.lifecycle.get.invalidate()\n onSuccess?.(bucketName)\n handleClose()\n },\n onError: (error) => {\n onError?.(bucketName, error.message)\n },\n })\n\n useEffect(() => {\n onMutatingChange?.(setMutation.isPending)\n }, [setMutation.isPending, onMutatingChange])\n\n useEffect(() => {\n if (!isOpen) {\n setMutation.reset()\n setIsFormValid(false)\n setValidationErrors([])\n resetTracking()\n }\n }, [isOpen, bucketName])\n\n const handleClose = () => {\n trackClose()\n setMutation.reset()\n setIsFormValid(false)\n setValidationErrors([])\n resetTracking()\n onClose()\n }\n\n const handleSubmit = async (rule: LifecycleRuleRead) => {\n markSubmitted()\n setValidationErrors([])\n\n try {\n let updatedRules: LifecycleRuleRead[]\n\n if (editingIndex === null) {\n // lifecycle.set is a full replace, not an append — rebase on fresh server state\n // so a concurrent writer's rule isn't silently overwritten.\n const freshData = await utils.storage.ceph.lifecycle.get.fetch({\n project_id: projectId,\n bucketName,\n })\n updatedRules = [...(freshData?.rules ?? []), rule]\n } else {\n // Editing existing rule - perform freshness check\n const freshData = await utils.storage.ceph.lifecycle.get.fetch({\n project_id: projectId,\n bucketName,\n })\n\n const freshRules = freshData?.rules ?? []\n const editingRule = lifecycleData?.rules?.[editingIndex]\n const freshRule = freshRules[editingIndex]\n\n // Freshness check\n if (!freshRule || JSON.stringify(freshRule) !== JSON.stringify(editingRule)) {\n onError?.(bucketName, t`The lifecycle configuration has changed. Please refresh and try again.`)\n return\n }\n\n updatedRules = [...freshRules]\n updatedRules[editingIndex] = rule\n }\n\n // Validate the updated rules before mutating\n const validation = validateLifecycleRules(updatedRules)\n if (!validation.ok) {\n setValidationErrors(validation.errors)\n return\n }\n\n // Mutation with validated rules\n setMutation.mutate({\n project_id: projectId,\n bucketName,\n lifecycleConfiguration: {\n Rules: validation.rules,\n },\n })\n } catch (error) {\n onError?.(bucketName, error instanceof Error ? error.message : String(error))\n }\n }\n\n const editingRule = editingIndex !== null ? (lifecycleData?.rules?.[editingIndex] ?? null) : null\n\n const isSaving = setMutation.isPending\n\n return (\n <Modal\n key={editingIndex ?? \"new\"}\n open={isOpen}\n onCancel={handleClose}\n title={editingRule ? t`Edit Lifecycle Rule` : t`Create Lifecycle Rule`}\n size=\"large\"\n modalFooter={\n <ModalFooter className=\"bg-theme-background-lvl-0 sticky bottom-0 z-50 flex justify-end\">\n <ButtonRow>\n <Button variant=\"subdued\" onClick={handleClose} disabled={isSaving}>\n <Trans>Cancel</Trans>\n </Button>\n <Button\n variant=\"primary\"\n onClick={() => {\n document.querySelector<HTMLFormElement>(\"#lifecycle-rule-form\")?.requestSubmit()\n }}\n disabled={!isFormValid || isSaving || isLifecycleLoading || !!lifecycleError}\n >\n {isSaving ? (\n editingRule ? (\n <Trans>Saving...</Trans>\n ) : (\n <Trans>Creating...</Trans>\n )\n ) : editingRule ? (\n <Trans>Save Changes</Trans>\n ) : (\n <Trans>Create Lifecycle Rule</Trans>\n )}\n </Button>\n </ButtonRow>\n </ModalFooter>\n }\n >\n {isLifecycleLoading ? (\n <Status status=\"progress\" title={t`Loading Lifecycle Configuration...`} className=\"mt-0\" />\n ) : lifecycleError ? (\n <Status\n status=\"error\"\n title={t`Failed to Load Lifecycle Configuration`}\n body={lifecycleError.message}\n className=\"mt-0\"\n />\n ) : (\n <>\n {validationErrors.length > 0 && (\n <Message variant=\"error\" title={t`Validation Error`} className=\"mb-4\">\n <ul className=\"list-disc pl-5\">\n {validationErrors.map((error, i) => (\n <li key={i}>{error}</li>\n ))}\n </ul>\n </Message>\n )}\n <LifecycleRuleForm\n formId=\"lifecycle-rule-form\"\n editingRule={editingRule}\n onSubmit={handleSubmit}\n onValidationChange={setIsFormValid}\n />\n </>\n )}\n </Modal>\n )\n}\n","import { useEffect, useState } from \"react\"\nimport { Modal, Status, Stack } from \"@cloudoperators/juno-ui-components\"\nimport { Trans, Plural, useLingui } from \"@lingui/react/macro\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport { useModalTracking } from \"@/client/hooks/useModalTracking\"\nimport { validateLifecycleRules } from \"./utils/lifecycleUtils\"\nimport type { LifecycleRuleRead } from \"@/server/Storage/types/ceph\"\n\ninterface DeleteLifecycleRulesModalProps {\n isOpen: boolean\n bucketName: string\n ruleIndices: number[]\n rules: LifecycleRuleRead[]\n onClose: () => void\n onSuccess?: (bucketName: string, count: number) => void\n onError?: (bucketName: string, errorMessage: string, count: number) => void\n onMutatingChange?: (isMutating: boolean) => void\n}\n\nconst MAX_VISIBLE_RULES = 5\n\n/**\n * Modal to confirm bulk deletion of lifecycle rules\n *\n * Refetches lifecycle configuration before deleting to avoid lost updates.\n * If deleting all rules, calls lifecycle.delete instead of lifecycle.set.\n */\nexport const DeleteLifecycleRulesModal = ({\n isOpen,\n bucketName,\n ruleIndices,\n rules,\n onClose,\n onSuccess,\n onError,\n onMutatingChange,\n}: DeleteLifecycleRulesModalProps) => {\n const { t } = useLingui()\n const projectId = useProjectId()\n const utils = trpcReact.useUtils()\n const [isVerifying, setIsVerifying] = useState(false)\n\n const { trackClose, markSubmitted, resetTracking } = useModalTracking({\n isOpen,\n actionPrefix: \"storage.ceph.lifecycle.rules.bulk_delete\",\n })\n\n // Query current lifecycle configuration (for loading/error states only - fresh data fetched in handleConfirm)\n const { isLoading, error: queryError } = trpcReact.storage.ceph.lifecycle.get.useQuery(\n {\n project_id: projectId,\n bucketName,\n },\n {\n enabled: isOpen && !!projectId,\n retry: false,\n staleTime: 5 * 60 * 1000,\n }\n )\n\n // Delete mutation (when removing all rules)\n const deleteMutation = trpcReact.storage.ceph.lifecycle.delete.useMutation({\n onSuccess: () => {\n utils.storage.ceph.lifecycle.get.invalidate()\n onSuccess?.(bucketName, ruleIndices.length)\n handleClose()\n },\n onError: (error) => {\n onError?.(bucketName, error.message, ruleIndices.length)\n },\n })\n\n // Set mutation (when other rules remain)\n const setMutation = trpcReact.storage.ceph.lifecycle.set.useMutation({\n onSuccess: () => {\n utils.storage.ceph.lifecycle.get.invalidate()\n onSuccess?.(bucketName, ruleIndices.length)\n handleClose()\n },\n onError: (error) => {\n onError?.(bucketName, error.message, ruleIndices.length)\n },\n })\n\n const isMutating = deleteMutation.isPending || setMutation.isPending\n\n useEffect(() => {\n onMutatingChange?.(isMutating)\n }, [isMutating, onMutatingChange])\n\n useEffect(() => {\n if (!isOpen) {\n deleteMutation.reset()\n setMutation.reset()\n setIsVerifying(false)\n resetTracking()\n }\n }, [isOpen])\n\n const handleClose = () => {\n trackClose()\n deleteMutation.reset()\n setMutation.reset()\n setIsVerifying(false)\n resetTracking()\n onClose()\n }\n\n const handleConfirm = async () => {\n if (isVerifying) return\n\n markSubmitted()\n setIsVerifying(true)\n\n try {\n // Refetch to get fresh state\n const freshData = await utils.storage.ceph.lifecycle.get.fetch({\n project_id: projectId,\n bucketName,\n })\n\n const freshRules = freshData?.rules ?? []\n\n // Freshness check: verify each rule at its index matches what the user selected\n const mismatches: number[] = []\n for (const index of ruleIndices) {\n const cachedRule = rules[index]\n const freshRule = freshRules[index]\n\n if (!freshRule || JSON.stringify(freshRule) !== JSON.stringify(cachedRule)) {\n mismatches.push(index)\n }\n }\n\n if (mismatches.length > 0) {\n onError?.(\n bucketName,\n t`The lifecycle configuration has changed. Please refresh and try again.`,\n ruleIndices.length\n )\n return\n }\n\n // Remove the selected rules\n const remaining = freshRules.filter((_, i) => !ruleIndices.includes(i))\n\n if (remaining.length === 0) {\n // All rules deleted - delete entire configuration\n deleteMutation.mutate({\n project_id: projectId,\n bucketName,\n })\n } else {\n // Some rules remain - validate and set\n const validation = validateLifecycleRules(remaining)\n if (!validation.ok) {\n const errorMsg = validation.errors.join(\"; \")\n onError?.(bucketName, t`Cannot delete rules: ${errorMsg}`, ruleIndices.length)\n return\n }\n\n setMutation.mutate({\n project_id: projectId,\n bucketName,\n lifecycleConfiguration: {\n Rules: validation.rules,\n },\n })\n }\n } catch (error) {\n onError?.(bucketName, error instanceof Error ? error.message : String(error), ruleIndices.length)\n } finally {\n setIsVerifying(false)\n }\n }\n\n const ruleCount = ruleIndices.length\n const rulesToDeleteWithIndices = ruleIndices\n .map((i) => ({ rule: rules[i], index: i }))\n .filter(({ rule }) => rule !== undefined)\n const visibleRules = rulesToDeleteWithIndices.slice(0, MAX_VISIBLE_RULES)\n const hiddenCount = rulesToDeleteWithIndices.length - visibleRules.length\n\n const confirmLabel = isMutating\n ? t`Deleting...`\n : ruleCount === 1\n ? t`Delete Lifecycle Rule`\n : t`Delete Lifecycle Rules`\n\n return (\n <Modal\n open={isOpen}\n onCancel={handleClose}\n title={<Plural value={ruleCount} one=\"Delete Lifecycle Rule\" other=\"Delete Lifecycle Rules\" />}\n size=\"large\"\n confirmButtonLabel={confirmLabel}\n confirmButtonVariant=\"primary-danger\"\n onConfirm={handleConfirm}\n cancelButtonLabel={t`Cancel`}\n disableConfirmButton={isMutating || isVerifying || isLoading || !!queryError}\n disableCancelButton={isMutating || isVerifying}\n disableCloseButton={isMutating || isVerifying}\n closeOnEsc={!(isMutating || isVerifying)}\n >\n {isLoading ? (\n <Status status=\"progress\" title={t`Loading Lifecycle Configuration...`} className=\"mt-0\" />\n ) : queryError ? (\n <Status\n status=\"error\"\n title={t`Failed to Load Lifecycle Configuration`}\n body={queryError.message}\n className=\"mt-0\"\n />\n ) : (\n <Stack direction=\"vertical\" gap=\"4\">\n <p className=\"text-theme-default\">\n {ruleCount === 1 ? (\n <Trans>\n Are you sure you want to delete this lifecycle rule from bucket <strong>{bucketName}</strong>?\n </Trans>\n ) : (\n <Trans>\n Are you sure you want to delete {ruleCount} lifecycle rules from bucket <strong>{bucketName}</strong>?\n </Trans>\n )}\n </p>\n\n {rulesToDeleteWithIndices.length > 0 && (\n <div>\n <p className=\"text-sm font-semibold\">\n <Trans>Rules to delete:</Trans>\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 {visibleRules.map(({ rule, index }) => {\n const ruleNumber = index + 1\n return (\n <div key={index} className=\"text-theme-default text-sm\">\n {rule.ID || t`Rule #${ruleNumber}`}\n </div>\n )\n })}\n {hiddenCount > 0 && (\n <div className=\"text-theme-light pt-2 text-sm\">\n <Trans>... and {hiddenCount} more</Trans>\n </div>\n )}\n </Stack>\n </div>\n </div>\n )}\n\n <p className=\"text-theme-default\">\n <Trans>This action cannot be undone.</Trans>\n </p>\n </Stack>\n )}\n </Modal>\n )\n}\n","import { useState, startTransition } from \"react\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { plural } from \"@lingui/core/macro\"\nimport { i18n } from \"@lingui/core\"\nimport { useNavigate } from \"@tanstack/react-router\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport {\n Status,\n Message,\n Button,\n Stack,\n toast,\n Checkbox,\n PopupMenu,\n PopupMenuItem,\n PopupMenuOptions,\n PopupMenuToggle,\n DataGridToolbar,\n SearchInput,\n Divider,\n} from \"@cloudoperators/juno-ui-components\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport { useCephPermissions } from \"../hooks/useCephPermissions\"\nimport { SortInput } from \"@/client/components/ListToolbar/SortInput\"\nimport { SortSettings } from \"@/client/components/ListToolbar/types\"\nimport { Route } from \"@/client/routes/_auth/projects/$projectId/storage/$provider/$storageType/$containerName/objects\"\nimport { LifecycleRulesTable } from \"./LifecycleRulesTable\"\nimport { LifecycleRuleModal } from \"./LifecycleRuleModal\"\nimport { DeleteLifecycleRulesModal } from \"./DeleteLifecycleRulesModal\"\nimport {\n getLifecycleSavedToast,\n getLifecycleSaveErrorToast,\n getLifecycleRulesDeletedToast,\n getLifecycleRulesDeleteErrorToast,\n} from \"./BucketToastNotifications\"\nimport type { LifecycleRuleRead } from \"@/server/Storage/types/ceph\"\n\ninterface LifecycleRulesTabProps {\n bucketName: string\n}\n\n/**\n * Lifecycle Rules tab container\n *\n * Manages lifecycle configuration for a Ceph bucket with full CRUD operations.\n * Each operation (add/edit/delete) immediately updates the server configuration.\n */\nexport function LifecycleRulesTab({ bucketName }: LifecycleRulesTabProps) {\n const { t } = useLingui()\n const projectId = useProjectId()\n const navigate = useNavigate({ from: Route.fullPath })\n const { permissions } = useCephPermissions(projectId)\n\n // Sort and search state are persisted in the URL\n const { lifecycleSortBy, lifecycleSortDirection, lifecycleSearch = \"\" } = Route.useSearch()\n\n // Server state\n const {\n data: lifecycleData,\n isLoading,\n error,\n } = trpcReact.storage.ceph.lifecycle.get.useQuery(\n {\n project_id: projectId,\n bucketName,\n },\n {\n enabled: !!projectId,\n retry: false,\n staleTime: 5 * 60 * 1000, // 5 minutes, shared with useBucketInfo\n }\n )\n\n // Modal state\n const [isRuleModalOpen, setIsRuleModalOpen] = useState(false)\n const [editingRuleIndex, setEditingRuleIndex] = useState<number | null>(null)\n const [isBulkDeleteModalOpen, setIsBulkDeleteModalOpen] = useState(false)\n\n // Mutation state for modals (to disable row actions during mutations)\n const [isRuleModalMutating, setIsRuleModalMutating] = useState(false)\n const [isBulkDeleteMutating, setIsBulkDeleteMutating] = useState(false)\n\n // Selection state for bulk actions\n const [selectedIndices, setSelectedIndices] = useState<number[]>([])\n\n const sortSettings: SortSettings = {\n options: [\n { label: t`Rule ID`, value: \"ID\" },\n { label: t`Status`, value: \"Status\" },\n { label: t`Expiration`, value: \"Expiration\" },\n ],\n sortBy: lifecycleSortBy ?? \"ID\",\n sortDirection: lifecycleSortDirection ?? \"asc\",\n }\n\n const handleSearchChange = (term: string | number | string[] | undefined) => {\n const value = typeof term === \"string\" ? term : \"\"\n startTransition(() => {\n navigate({\n search: (prev) => ({ ...prev, lifecycleSearch: value || undefined }),\n })\n })\n }\n\n const handleSortChange = (newSortSettings: SortSettings) => {\n const resolvedSortBy = (newSortSettings.sortBy?.toString() || \"ID\") as \"ID\" | \"Status\" | \"Expiration\"\n const resolvedDirection = (newSortSettings.sortDirection || \"asc\") as \"asc\" | \"desc\"\n startTransition(() => {\n navigate({\n search: (prev) => ({\n ...prev,\n lifecycleSortBy: resolvedSortBy,\n lifecycleSortDirection: resolvedDirection,\n }),\n })\n })\n }\n\n const handleAddRule = () => {\n setEditingRuleIndex(null)\n setIsRuleModalOpen(true)\n }\n\n const handleEditRule = (index: number) => {\n setEditingRuleIndex(index)\n setIsRuleModalOpen(true)\n }\n\n const handleToggleSelectRule = (index: number) => {\n setSelectedIndices((prev) => (prev.includes(index) ? prev.filter((i) => i !== index) : [...prev, index]))\n }\n\n const handleToggleSelectAll = () => {\n if (allFilteredSelected) {\n // Deselect all filtered rules\n setSelectedIndices((prev) => prev.filter((i) => !filteredIndices.includes(i)))\n } else {\n // Select all filtered rules\n setSelectedIndices((prev) => [...new Set([...prev, ...filteredIndices])])\n }\n }\n\n const handleBulkDelete = () => {\n setIsBulkDeleteModalOpen(true)\n }\n\n const handleDeleteRule = () => {\n // Clear selections after single-rule deletion to avoid stale indices\n setSelectedIndices([])\n }\n\n // Current rules from server\n const rules = lifecycleData?.rules ?? []\n\n // Rules that failed to map/validate on read (see lifecycleRouter's `get`). `set` is a full replace,\n // so mutating while some rules are unreadable would silently delete them on the next save block\n // all mutating actions until they're fixed with an external tool.\n const skippedRuleCount = lifecycleData?.skippedRuleCount ?? 0\n const mutationsBlocked = skippedRuleCount > 0\n\n interface RuleWithOriginalIndex {\n rule: LifecycleRuleRead\n originalIndex: number\n }\n\n // Sort rules based on sort settings\n const sortRules = (items: RuleWithOriginalIndex[]): RuleWithOriginalIndex[] => {\n return [...items].sort((a, b) => {\n let comparison: number\n\n switch (lifecycleSortBy ?? \"ID\") {\n case \"ID\":\n comparison = (a.rule.ID || \"\").localeCompare(b.rule.ID || \"\")\n break\n case \"Status\":\n comparison = a.rule.Status.localeCompare(b.rule.Status)\n break\n case \"Expiration\":\n comparison = (a.rule.Expiration?.Days ?? -1) - (b.rule.Expiration?.Days ?? -1)\n break\n default:\n comparison = (a.rule.ID || \"\").localeCompare(b.rule.ID || \"\")\n }\n\n return (lifecycleSortDirection ?? \"asc\") === \"desc\" ? -comparison : comparison\n })\n }\n\n const rulesWithOriginalIndices = rules.map((rule, originalIndex) => ({\n rule,\n originalIndex,\n }))\n const filteredRulesWithIndices = sortRules(rulesWithOriginalIndices).filter(({ rule }) => {\n if (!lifecycleSearch) return true\n return (rule.ID || \"\").toLowerCase().includes(lifecycleSearch.toLowerCase())\n })\n\n // Get indices of filtered rules for select-all logic\n const filteredIndices = filteredRulesWithIndices.map(({ originalIndex }) => originalIndex)\n\n const allFilteredSelected = filteredIndices.length > 0 && filteredIndices.every((i) => selectedIndices.includes(i))\n const someFilteredSelected = filteredIndices.some((i) => selectedIndices.includes(i)) && !allFilteredSelected\n\n const skippedRulesMessage = i18n._(\n plural(skippedRuleCount, {\n one: \"# lifecycle rule on this bucket could not be read and is hidden from this table. Saving any change here replaces the entire lifecycle configuration, which would permanently delete it. Fix it with an external S3 tool (e.g. the AWS CLI) first, then reload this page.\",\n other:\n \"# lifecycle rules on this bucket could not be read and are hidden from this table. Saving any change here replaces the entire lifecycle configuration, which would permanently delete them. Fix them with an external S3 tool (e.g. the AWS CLI) first, then reload this page.\",\n })\n )\n\n if (isLoading) {\n return <Status status=\"progress\" title={t`Loading Lifecycle Configuration...`} />\n }\n\n if (error) {\n return <Status status=\"error\" title={t`Failed to Load Lifecycle Configuration`} body={error.message} />\n }\n\n return (\n <>\n {mutationsBlocked && (\n <Message variant=\"warning\" title={t`Lifecycle rules cannot be modified`} className=\"mb-2\">\n {skippedRulesMessage}\n </Message>\n )}\n\n {/* Zone 1 — Sort controls and Create rule button (outside DataGridToolbar) */}\n <Stack distribution=\"end\" alignment=\"center\" gap=\"2\" className=\"pb-2\">\n <Stack gap=\"0.5\" alignment=\"center\">\n <SortInput\n options={sortSettings.options}\n sortBy={sortSettings.sortBy}\n sortDirection={sortSettings.sortDirection ?? \"asc\"}\n selectClassName=\"w-40\"\n onSortByChange={(value) =>\n handleSortChange({ ...sortSettings, sortBy: value, sortDirection: sortSettings.sortDirection })\n }\n onSortDirectionChange={(direction) => handleSortChange({ ...sortSettings, sortDirection: direction })}\n />\n </Stack>\n {permissions.canUpdateLifecycle && (\n <Button variant=\"primary\" onClick={handleAddRule} disabled={mutationsBlocked}>\n <Trans>Create Lifecycle Rule</Trans>\n </Button>\n )}\n </Stack>\n\n {/* Zone 2 — Bulk actions toolbar (inside DataGridToolbar) */}\n <DataGridToolbar>\n <Stack direction=\"vertical\" gap=\"2\">\n <Stack distribution=\"end\" alignment=\"center\">\n <SearchInput\n placeholder={t`Search lifecycle rules...`}\n data-testid=\"lifecycle-rules-searchbar\"\n value={lifecycleSearch}\n onInput={(e) => {\n const v = e.currentTarget.value\n handleSearchChange(v)\n }}\n onSearch={(v) => handleSearchChange(typeof v === \"string\" ? v : \"\")}\n onClear={() => handleSearchChange(\"\")}\n />\n </Stack>\n <Divider />\n <Stack distribution=\"between\" gap=\"2\" alignment=\"center\" className=\"text-sm\">\n {permissions.canDeleteLifecycle ? (\n <Stack gap=\"2\" alignment=\"center\">\n <Checkbox\n checked={allFilteredSelected}\n indeterminate={someFilteredSelected}\n onChange={handleToggleSelectAll}\n aria-label={t`Select all rules`}\n data-testid=\"select-all-rules\"\n disabled={filteredRulesWithIndices.length === 0}\n />\n <PopupMenu className=\"flex items-center\">\n <PopupMenuToggle as=\"div\">\n <Button\n disabled={selectedIndices.length === 0 || mutationsBlocked}\n size=\"small\"\n icon=\"moreVert\"\n label={t`Actions`}\n />\n </PopupMenuToggle>\n {selectedIndices.length > 0 && !mutationsBlocked && (\n <PopupMenuOptions>\n <PopupMenuItem\n label={i18n._(\n plural(selectedIndices.length, {\n one: \"Delete # Lifecycle Rule\",\n other: \"Delete # Lifecycle Rules\",\n })\n )}\n onClick={handleBulkDelete}\n data-testid=\"bulk-delete-lifecycle-rules-action\"\n />\n </PopupMenuOptions>\n )}\n </PopupMenu>\n </Stack>\n ) : (\n <span />\n )}\n <span className=\"theme-color-text-light\">\n {filteredRulesWithIndices.length} {filteredRulesWithIndices.length === 1 ? t`rule` : t`rules`}\n </span>\n </Stack>\n </Stack>\n </DataGridToolbar>\n\n {/* Table */}\n <LifecycleRulesTable\n bucketName={bucketName}\n rulesWithIndices={filteredRulesWithIndices}\n selectedIndices={selectedIndices}\n onToggleSelectRule={handleToggleSelectRule}\n onEditRule={handleEditRule}\n onDeleteRule={handleDeleteRule}\n isMutating={isRuleModalMutating || isBulkDeleteMutating || mutationsBlocked}\n isFiltered={!!lifecycleSearch}\n canUpdateLifecycle={permissions.canUpdateLifecycle}\n canDeleteLifecycle={permissions.canDeleteLifecycle}\n />\n\n {/* Bulk delete rules modal */}\n <DeleteLifecycleRulesModal\n isOpen={isBulkDeleteModalOpen}\n bucketName={bucketName}\n ruleIndices={selectedIndices}\n rules={rules}\n onClose={() => setIsBulkDeleteModalOpen(false)}\n onSuccess={(bucketName, count) => {\n setIsBulkDeleteModalOpen(false)\n setSelectedIndices([])\n const { message, ...options } = getLifecycleRulesDeletedToast(bucketName, count)\n toast.success(message, options)\n }}\n onError={(bucketName, errorMessage, count) => {\n const { message, ...options } = getLifecycleRulesDeleteErrorToast(bucketName, count, errorMessage)\n toast.error(message, options)\n }}\n onMutatingChange={setIsBulkDeleteMutating}\n />\n\n {/* Add/Edit rule modal */}\n <LifecycleRuleModal\n isOpen={isRuleModalOpen}\n bucketName={bucketName}\n editingIndex={editingRuleIndex}\n onClose={() => {\n setIsRuleModalOpen(false)\n setEditingRuleIndex(null)\n }}\n onSuccess={(bucketName) => {\n setIsRuleModalOpen(false)\n setEditingRuleIndex(null)\n const { message, ...options } = getLifecycleSavedToast(bucketName)\n toast.success(message, options)\n }}\n onError={(bucketName, errorMessage) => {\n const { message, ...options } = getLifecycleSaveErrorToast(bucketName, errorMessage)\n toast.error(message, options)\n }}\n onMutatingChange={setIsRuleModalMutating}\n />\n </>\n )\n}\n","import { useState, useEffect, useRef, startTransition } from \"react\"\nimport { Plural, Trans, useLingui } from \"@lingui/react/macro\"\nimport { plural } from \"@lingui/core/macro\"\nimport { useNavigate } from \"@tanstack/react-router\"\nimport { SortInput } from \"@/client/components/ListToolbar/SortInput\"\nimport { SortSettings } from \"@/client/components/ListToolbar/types\"\nimport { Bucket } from \"@/server/Storage/types/ceph\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport {\n Button,\n Checkbox,\n DataGridToolbar,\n PopupMenu,\n PopupMenuItem,\n PopupMenuOptions,\n PopupMenuToggle,\n SearchInput,\n Stack,\n Status,\n toast,\n} from \"@cloudoperators/juno-ui-components\"\nimport { BucketTableView } from \"./BucketTableView\"\nimport {\n getBucketCreatedToast,\n getBucketEmptiedToast,\n getBucketEmptyErrorToast,\n getBucketDeletedToast,\n getBucketDeleteErrorToast,\n getBucketsEmptyCompleteToast,\n} from \"./BucketToastNotifications\"\nimport { EmptyBucketsModal } from \"./EmptyBucketsModal\"\nimport { CredentialPrompt } from \"./CredentialPrompt\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport { useCephPermissions } from \"../hooks/useCephPermissions\"\nimport { Route } from \"@/client/routes/_auth/projects/$projectId/storage/$provider/$storageType/index\"\n\nexport { CredentialPrompt } from \"./CredentialPrompt\"\nexport { CreateBucketModal } from \"./CreateBucketModal\"\nexport { DeleteBucketModal } from \"./DeleteBucketModal\"\nexport { DeleteBucketPolicyModal } from \"./DeleteBucketPolicyModal\"\nexport { EmptyBucketModal } from \"./EmptyBucketModal\"\nexport { EmptyBucketsModal } from \"./EmptyBucketsModal\"\nexport { DeleteVersionsModal } from \"./DeleteVersionsModal\"\nexport { CorsRulesTab as CephCorsRules } from \"./CorsRulesTab\"\nexport { LifecycleRulesTab as CephLifecycleRules } from \"./LifecycleRulesTab\"\nexport * from \"./BucketToastNotifications\"\n\nexport const CephBuckets = () => {\n const { t, i18n } = useLingui()\n const projectId = useProjectId()\n const navigate = useNavigate({ from: Route.fullPath })\n\n // Sort and search state are persisted in the URL so they survive navigation,\n // browser back/forward, and deep links.\n const { sortBy, sortDirection, search: searchParam = \"\" } = Route.useSearch()\n\n const { permissions } = useCephPermissions(projectId)\n const hasAnyBulkAction = permissions.canEmptyBucket\n\n const [createModalOpen, setCreateModalOpen] = useState(false)\n const [emptyAllModalOpen, setEmptyAllModalOpen] = useState(false)\n const [selectedBuckets, setSelectedBuckets] = useState<string[]>([])\n\n // Local mirror of the committed search term so typing stays responsive while\n // the URL commit is debounced (see Zone 2 SearchInput below).\n const [localSearchTerm, setLocalSearchTerm] = useState(searchParam)\n const debounceTimer = useRef<number | undefined>(undefined)\n useEffect(() => () => clearTimeout(debounceTimer.current), [])\n\n // Keep the input in sync when the committed search term changes from outside\n // the input — browser back/forward, deep links, or programmatic navigation —\n // so the field never drifts from the URL-backed filter state. When the change\n // originated from our own debounced commit, searchParam already equals\n // localSearchTerm, so this is a no-op and won't disturb the caret.\n useEffect(() => {\n setLocalSearchTerm(searchParam)\n }, [searchParam])\n\n const handleCreateSuccess = (bucketName: string) => {\n const { message, ...options } = getBucketCreatedToast(bucketName)\n\n toast.success(message, options)\n }\n\n const handleEmptySuccess = (bucketName: string, deletedCount: number) => {\n const { message, ...options } = getBucketEmptiedToast(bucketName, deletedCount)\n\n toast.success(message, options)\n }\n\n const handleEmptyError = (bucketName: string, errorMessage: string) => {\n const { message, ...options } = getBucketEmptyErrorToast(bucketName, errorMessage)\n\n toast.error(message, options)\n }\n\n const handleDeleteSuccess = (bucketName: string) => {\n const { message, ...options } = getBucketDeletedToast(bucketName)\n\n toast.success(message, options)\n }\n\n const handleDeleteError = (bucketName: string, errorMessage: string) => {\n const { message, ...options } = getBucketDeleteErrorToast(bucketName, errorMessage)\n\n toast.error(message, options)\n }\n\n const handleEmptyAllComplete = ({\n emptiedCount,\n totalDeleted,\n errors,\n }: {\n emptiedCount: number\n totalDeleted: number\n errors: string[]\n }) => {\n if (errors.length === 0) {\n setSelectedBuckets([])\n } else {\n // Extract the bucket name from each error string formatted as \"<bucketName>: <message>\".\n // Using exact name extraction avoids the false-positive substring match that\n // errorMessage.includes(bucketName) would produce (e.g. \"foo\" matched inside \"foobar\" error).\n const failedBucketNames = new Set(errors.map((e) => e.split(\": \")[0]))\n setSelectedBuckets((prev) => prev.filter((name) => failedBucketNames.has(name)))\n }\n\n const { message, ...options } = getBucketsEmptyCompleteToast(emptiedCount, totalDeleted, errors)\n\n if (errors.length > 0) {\n toast.warning(message, options)\n } else {\n toast.success(message, options)\n }\n }\n\n const sortSettings: SortSettings = {\n options: [\n { label: t`Bucket Name`, value: \"name\" },\n { label: t`Object Count`, value: \"count\" },\n { label: t`Total Size`, value: \"bytes\" },\n { label: t`Last Modified`, value: \"last_modified\" },\n ],\n sortBy: sortBy ?? \"name\",\n sortDirection: sortDirection ?? \"asc\",\n }\n\n // Fetch buckets from tRPC\n const {\n data: buckets,\n isLoading,\n error,\n } = trpcReact.storage.ceph.containers.list.useQuery(\n {\n project_id: projectId,\n includeMetadata: true, // Fetch full metadata for table view with sorting\n },\n {\n enabled: !!projectId,\n retry: false, // Don't retry on NO_CEPH_CREDENTIALS error\n }\n )\n\n // Sort buckets based on sort settings\n const sortBuckets = (buckets: Bucket[]): Bucket[] => {\n return [...buckets].sort((a, b) => {\n let comparison: number\n\n switch (sortBy ?? \"name\") {\n case \"name\":\n comparison = a.name.localeCompare(b.name)\n break\n case \"count\":\n comparison = a.count - b.count\n break\n case \"bytes\":\n comparison = a.bytes - b.bytes\n break\n case \"last_modified\":\n if (!a.last_modified && !b.last_modified) {\n return 0\n }\n if (!a.last_modified) {\n return 1\n }\n if (!b.last_modified) {\n return -1\n }\n comparison = new Date(a.last_modified).getTime() - new Date(b.last_modified).getTime()\n break\n default:\n comparison = a.name.localeCompare(b.name)\n }\n\n return (sortDirection ?? \"asc\") === \"desc\" ? -comparison : comparison\n })\n }\n\n // Filter buckets based on search term\n const filteredBuckets = (buckets || []).filter((bucket) =>\n bucket.name.toLowerCase().includes(searchParam.toLowerCase())\n )\n\n // Apply sorting to filtered buckets\n const sortedBuckets = sortBuckets(filteredBuckets)\n\n const handleSearchChange = (term: string | number | string[] | undefined) => {\n const value = typeof term === \"string\" ? term : \"\"\n startTransition(() => {\n navigate({\n search: (prev) => ({ ...prev, search: value || undefined }),\n })\n })\n }\n\n const handleSortChange = (newSortSettings: SortSettings) => {\n const resolvedSortBy = (newSortSettings.sortBy?.toString() || \"name\") as\n \"name\" | \"count\" | \"bytes\" | \"last_modified\"\n const resolvedDirection = (newSortSettings.sortDirection || \"asc\") as \"asc\" | \"desc\"\n startTransition(() => {\n navigate({\n search: (prev) => ({\n ...prev,\n sortBy: resolvedSortBy,\n sortDirection: resolvedDirection,\n }),\n })\n })\n }\n\n // Handle loading state\n if (isLoading) {\n return <Status status=\"progress\" title={t`Loading Buckets...`} />\n }\n\n // Handle error state\n if (error) {\n const errorMessage = error.message\n\n // Check if this is a NO_CEPH_CREDENTIALS error\n if (errorMessage === \"NO_CEPH_CREDENTIALS\") {\n return <CredentialPrompt onSuccess={() => window.location.reload()} />\n }\n\n // Render error message based on error type\n const isAccessDenied = errorMessage.includes(\"Access denied\") || errorMessage.includes(\"AccessDenied\")\n const isAuthError = errorMessage.includes(\"Invalid access key\") || errorMessage.includes(\"InvalidAccessKeyId\")\n\n return (\n <div>\n <p className=\"text-theme-default text-sm\">\n {isAccessDenied ? (\n <Trans>\n Your credentials are valid but you don't have permission to perform this operation. Please contact your\n administrator to grant you the necessary permissions.\n </Trans>\n ) : isAuthError ? (\n <Trans>\n Your S3 credentials are invalid or expired. Please try creating new credentials or contact your\n administrator.\n </Trans>\n ) : (\n <Trans>Failed to Load Buckets: {errorMessage}</Trans>\n )}\n </p>\n </div>\n )\n }\n\n // Resolve selected Bucket objects from the full unfiltered list so\n // the modal always operates on what was actually selected — not the filtered\n // subset currently visible in the table.\n const selectedBucketSummaries = (buckets || []).filter((c) => selectedBuckets.includes(c.name))\n const hasSelection = selectedBucketSummaries.length > 0\n const selectedCount = selectedBucketSummaries.length\n const totalCount = (buckets || []).length\n const filteredCount = filteredBuckets.length\n\n // Select-all operates on the currently displayed (filtered + sorted) rows.\n const displayedNames = sortedBuckets.map((c) => c.name)\n const allSelected = displayedNames.length > 0 && displayedNames.every((n) => selectedBuckets.includes(n))\n const someSelected = displayedNames.some((n) => selectedBuckets.includes(n))\n const handleToggleSelectAll = () => {\n if (allSelected) {\n setSelectedBuckets((prev) => prev.filter((n) => !displayedNames.includes(n)))\n } else {\n setSelectedBuckets((prev) => [...new Set([...prev, ...displayedNames])])\n }\n }\n\n return (\n <div className=\"relative\">\n <Stack direction=\"vertical\">\n {/* Zone 1 — sort controls and the create action (plain Stack, no background) */}\n <Stack distribution=\"end\" alignment=\"center\" gap=\"2\" className=\"pb-2\">\n <Stack gap=\"0.5\" alignment=\"center\">\n <SortInput\n options={sortSettings.options}\n sortBy={sortSettings.sortBy}\n sortDirection={sortSettings.sortDirection ?? \"asc\"}\n selectClassName=\"min-w-40\"\n onSortByChange={(value) =>\n handleSortChange({ ...sortSettings, sortBy: value, sortDirection: sortSettings.sortDirection })\n }\n onSortDirectionChange={(direction) => handleSortChange({ ...sortSettings, sortDirection: direction })}\n />\n </Stack>\n {permissions.canCreateBucket && (\n <Button variant=\"primary\" className=\"whitespace-nowrap\" onClick={() => setCreateModalOpen(true)}>\n <Trans>Create Bucket</Trans>\n </Button>\n )}\n </Stack>\n\n {/* Zone 2 — debounced search. DataGridToolbar provides the background.\n Ceph buckets expose no filterable dimensions yet, so there is no\n FiltersInput / SelectedFilters here. When filter dimensions are added,\n add FiltersInput alongside the search (switch the inner Stack to\n distribution=\"between\") and render SelectedFilters below. */}\n <DataGridToolbar>\n <Stack direction=\"vertical\" gap=\"2\">\n <Stack distribution=\"end\" alignment=\"center\">\n <SearchInput\n placeholder={t`Search buckets...`}\n data-testid=\"searchbar\"\n value={localSearchTerm}\n onInput={(e) => {\n const v = e.currentTarget.value\n setLocalSearchTerm(v)\n clearTimeout(debounceTimer.current)\n debounceTimer.current = window.setTimeout(() => handleSearchChange(v), 500)\n }}\n onSearch={(v) => {\n clearTimeout(debounceTimer.current)\n handleSearchChange(typeof v === \"string\" ? v : \"\")\n }}\n onClear={() => {\n clearTimeout(debounceTimer.current)\n setLocalSearchTerm(\"\")\n handleSearchChange(\"\")\n }}\n />\n </Stack>\n </Stack>\n </DataGridToolbar>\n\n {/* Zone 3 — bulk actions (gated) plus the bucket count. The bar also hosts the\n count info, which must always be visible, so it always renders; only the\n bulk controls are gated. */}\n <DataGridToolbar>\n <Stack distribution=\"between\" gap=\"2\" alignment=\"center\" className=\"text-sm\">\n {hasAnyBulkAction ? (\n <Stack gap=\"2\" alignment=\"center\">\n <Checkbox\n checked={allSelected}\n indeterminate={someSelected && !allSelected}\n onChange={handleToggleSelectAll}\n />\n <PopupMenu className=\"flex items-center\">\n <PopupMenuToggle as=\"div\">\n <Button disabled={!hasSelection} size=\"small\" icon=\"moreVert\" label={t`Actions`} />\n </PopupMenuToggle>\n {hasSelection && (\n <PopupMenuOptions>\n <PopupMenuItem\n disabled={!hasSelection}\n label={i18n._(\n plural(selectedCount, {\n one: \"Empty Bucket\",\n other: \"Empty Buckets\",\n })\n )}\n onClick={() => setEmptyAllModalOpen(true)}\n />\n </PopupMenuOptions>\n )}\n </PopupMenu>\n </Stack>\n ) : (\n <span />\n )}\n\n <div className=\"text-theme-light flex items-center gap-1\" data-testid=\"buckets-info-block\">\n {searchParam.trim() ? (\n <Plural\n value={totalCount}\n one={`${filteredCount} of ${totalCount} bucket`}\n other={`${filteredCount} of ${totalCount} buckets`}\n />\n ) : (\n <Plural value={totalCount} one={`${totalCount} bucket`} other={`${totalCount} buckets`} />\n )}\n </div>\n </Stack>\n </DataGridToolbar>\n </Stack>\n\n <BucketTableView\n buckets={sortedBuckets}\n createModalOpen={createModalOpen}\n setCreateModalOpen={setCreateModalOpen}\n onCreateSuccess={handleCreateSuccess}\n existingBuckets={buckets}\n onEmptySuccess={handleEmptySuccess}\n onEmptyError={handleEmptyError}\n onDeleteSuccess={handleDeleteSuccess}\n onDeleteError={handleDeleteError}\n selectedBuckets={selectedBuckets}\n setSelectedBuckets={setSelectedBuckets}\n hasAnyBulkAction={hasAnyBulkAction}\n canEmptyBucket={permissions.canEmptyBucket}\n canDeleteBucket={permissions.canDeleteBucket}\n />\n\n <EmptyBucketsModal\n isOpen={emptyAllModalOpen}\n buckets={selectedBucketSummaries}\n onClose={() => setEmptyAllModalOpen(false)}\n onComplete={handleEmptyAllComplete}\n />\n </div>\n )\n}\n","import { trpcReact } from \"@/client/trpcClient\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport { calculateBucketState } from \"./bucketStateHelpers\"\n\ninterface UseBucketInfoProps {\n bucketName: string\n enabled?: boolean\n}\n\ninterface BucketInfo {\n versioningStatus:\n | {\n status: \"Enabled\" | \"Suspended\" | \"Unversioned\"\n }\n | undefined\n policyData:\n | {\n policy: unknown\n }\n | undefined\n hasVersionsOrDeleteMarkers: boolean\n hasOldVersionsOrDeleteMarkers: boolean\n isBucketEmptyWithVersions: boolean\n isBucketEmpty: boolean\n isLoading: boolean\n}\n\n/**\n * Custom hook to fetch all bucket-related information\n *\n * Consolidates:\n * - Bucket metadata (count, size, etc.) from containers.list\n * - Versioning status query\n * - Bucket policy query\n * - CORS configuration query (prefetch only: warms the cache for CorsRulesTab)\n * - Lifecycle configuration query (prefetch only: warms the cache for LifecycleRulesTab)\n * - Version/delete marker check query\n *\n * Uses bucket.count from metadata (same as Buckets page) to determine if bucket is empty.\n * This ensures consistent behavior across Buckets page and Objects page.\n *\n * @param bucketName - The name of the bucket\n * @param enabled - Whether queries should be enabled (default: true)\n * @returns Bucket information and loading state\n */\nexport const useBucketInfo = ({ bucketName, enabled = true }: UseBucketInfoProps): BucketInfo => {\n const projectId = useProjectId()\n\n // Query bucket metadata to get accurate count (same as Buckets page)\n const { data: bucketsData, isLoading: isLoadingBuckets } = trpcReact.storage.ceph.containers.list.useQuery(\n {\n project_id: projectId ?? \"\",\n },\n {\n enabled: !!projectId && enabled,\n staleTime: 30 * 1000, // 30 seconds cache\n }\n )\n\n // Find the current bucket in the list\n const bucket = bucketsData?.find((b) => b.name === bucketName)\n const bucketObjectCount = bucket?.count ?? 0\n\n // Query versioning status\n const { data: versioningStatus, isLoading: isLoadingVersioning } =\n trpcReact.storage.ceph.versioning.getStatus.useQuery(\n {\n project_id: projectId ?? \"\",\n bucket: bucketName,\n },\n {\n enabled: !!projectId && enabled,\n staleTime: 5 * 60 * 1000, // Cache for 5 minutes\n }\n )\n\n // Query bucket policy status\n const { data: policyData, isLoading: isLoadingPolicy } = trpcReact.storage.ceph.bucketPolicy.get.useQuery(\n {\n project_id: projectId ?? \"\",\n bucketName: bucketName,\n },\n {\n enabled: !!projectId && enabled,\n staleTime: 5 * 60 * 1000, // Cache for 5 minutes\n retry: false,\n }\n )\n\n // Prefetch only: warms the shared cors.get cache consumed by CorsRulesTab (5 min staleTime).\n const { isLoading: isLoadingCors } = trpcReact.storage.ceph.cors.get.useQuery(\n {\n project_id: projectId ?? \"\",\n bucketName: bucketName,\n },\n {\n enabled: !!projectId && enabled,\n staleTime: 5 * 60 * 1000, // Cache for 5 minutes\n retry: false,\n }\n )\n\n // Prefetch lifecycle configuration (warms the shared lifecycle.get cache consumed by LifecycleRulesTab)\n trpcReact.storage.ceph.lifecycle.get.useQuery(\n {\n project_id: projectId ?? \"\",\n bucketName: bucketName,\n },\n {\n enabled: !!projectId && enabled,\n staleTime: 5 * 60 * 1000, // 5 minutes, shared with LifecycleRulesTab\n retry: false,\n }\n )\n\n // Query to check if bucket has objects/versions/delete markers\n // Use showVersions=true to detect all content types\n // This query works for both versioned and unversioned buckets:\n // - Unversioned: returns current objects in \"versions\" array\n // - Versioned: returns all versions and delete markers\n // Use maxKeys=100 to get enough data - with maxKeys=1 we might miss current objects\n // if the first result is a delete marker\n const { data: versionCheckData, isLoading: isLoadingVersionCheck } = trpcReact.storage.ceph.objects.list.useQuery(\n {\n project_id: projectId ?? \"\",\n containerName: bucketName,\n maxKeys: 100,\n delimiter: \"\",\n showVersions: true,\n },\n {\n enabled: !!projectId && enabled,\n staleTime: 30 * 1000, // 30 seconds cache\n }\n )\n\n const isVersioningEnabled = versioningStatus?.status === \"Enabled\" || versioningStatus?.status === \"Suspended\"\n\n // Calculate bucket state using shared helper\n const allVersions = versionCheckData?.versions ?? []\n const { hasOnlyDeleteMarkers, hasOldVersionsOrDeleteMarkers, isBucketEmpty } = calculateBucketState(\n allVersions,\n isVersioningEnabled,\n bucketObjectCount\n )\n\n // Show \"Delete Versions\" only when bucket is truly empty but has delete markers\n const isBucketEmptyWithVersions = isBucketEmpty && hasOnlyDeleteMarkers\n\n return {\n versioningStatus,\n policyData,\n hasVersionsOrDeleteMarkers: allVersions.length > 0,\n hasOldVersionsOrDeleteMarkers,\n isBucketEmptyWithVersions,\n isBucketEmpty,\n isLoading: isLoadingBuckets || isLoadingVersioning || isLoadingPolicy || isLoadingCors || isLoadingVersionCheck,\n }\n}\n","import { useLingui } from \"@lingui/react/macro\"\nimport { Button, PopupMenu, PopupMenuItem, PopupMenuOptions, PopupMenuToggle } from \"@cloudoperators/juno-ui-components\"\nimport type { ModalType } from \"./BucketModals\"\n\ninterface BucketHeaderActionsProps {\n versioningStatus?: {\n status: \"Enabled\" | \"Suspended\" | \"Unversioned\"\n }\n hasPolicy: boolean\n hasOldVersionsOrDeleteMarkers: boolean\n isBucketEmpty: boolean\n onOpenModal: (modal: ModalType) => void\n canUpdateVersioning: boolean\n canUpdatePolicy: boolean\n canDeletePolicy: boolean\n canEmptyBucket: boolean\n canDeleteBucket: boolean\n canDeleteVersions: boolean\n}\n\n/**\n * Bucket header actions component\n *\n * Displays:\n * - Policy button (primary or subdued based on whether policy exists)\n * - Actions dropdown with versioning, policy, and bucket management options\n *\n * Every item in this menu is a gated mutation with no always-visible read action, so the\n * whole menu is hidden (not just its items) when nothing is available otherwise it would\n * render as an empty popup for a read-only user.\n */\nexport const BucketHeaderActions = ({\n versioningStatus,\n hasPolicy,\n hasOldVersionsOrDeleteMarkers,\n isBucketEmpty,\n onOpenModal,\n canUpdateVersioning,\n canUpdatePolicy,\n canDeletePolicy,\n canEmptyBucket,\n canDeleteBucket,\n canDeleteVersions,\n}: BucketHeaderActionsProps) => {\n const { t } = useLingui()\n\n const versioningState = canUpdateVersioning ? versioningStatus?.status : undefined\n const canEnableVersioning = versioningState === \"Unversioned\" || versioningState === \"Suspended\"\n const canSuspendVersioning = versioningState === \"Enabled\"\n const canToggleVersioning = canEnableVersioning || canSuspendVersioning\n const canShowDeletePolicy = hasPolicy && canDeletePolicy\n const canShowEmptyBucket = !isBucketEmpty && canEmptyBucket\n const canShowDeleteVersions = hasOldVersionsOrDeleteMarkers && canDeleteVersions\n\n const hasAnyAction =\n canToggleVersioning ||\n canUpdatePolicy ||\n canShowDeletePolicy ||\n canShowEmptyBucket ||\n canShowDeleteVersions ||\n canDeleteBucket\n\n if (!hasAnyAction) {\n return null\n }\n\n return (\n <PopupMenu>\n <PopupMenuToggle as=\"div\">\n <Button icon=\"moreVert\" title={t`Bucket actions`} aria-label={t`Bucket actions`} />\n </PopupMenuToggle>\n <PopupMenuOptions>\n {canEnableVersioning && (\n <PopupMenuItem label={t`Enable Versioning`} onClick={() => onOpenModal(\"enableVersioning\")} />\n )}\n {canSuspendVersioning && (\n <PopupMenuItem label={t`Suspend Versioning`} onClick={() => onOpenModal(\"suspendVersioning\")} />\n )}\n {canUpdatePolicy && (\n <PopupMenuItem label={hasPolicy ? t`Edit Policy` : t`Add Policy`} onClick={() => onOpenModal(\"policy\")} />\n )}\n {canShowDeletePolicy && <PopupMenuItem label={t`Delete Policy`} onClick={() => onOpenModal(\"deletePolicy\")} />}\n {canShowEmptyBucket && <PopupMenuItem label={t`Empty Bucket`} onClick={() => onOpenModal(\"emptyBucket\")} />}\n {canShowDeleteVersions && (\n <PopupMenuItem label={t`Delete Versions`} onClick={() => onOpenModal(\"deleteVersions\")} />\n )}\n {canDeleteBucket && <PopupMenuItem label={t`Delete Bucket`} onClick={() => onOpenModal(\"deleteBucket\")} />}\n </PopupMenuOptions>\n </PopupMenu>\n )\n}\n","import { useState } from \"react\"\nimport { useNavigate } from \"@tanstack/react-router\"\nimport { toast } from \"@cloudoperators/juno-ui-components\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport { EnableVersioningModal } from \"./EnableVersioningModal\"\nimport { SuspendVersioningModal } from \"./SuspendVersioningModal\"\nimport { BucketPolicyModal } from \"./BucketPolicyModal\"\nimport { DeleteBucketPolicyModal } from \"./DeleteBucketPolicyModal\"\nimport { EmptyBucketModal } from \"./EmptyBucketModal\"\nimport { DeleteBucketModal } from \"./DeleteBucketModal\"\nimport { DeleteVersionsModal } from \"./DeleteVersionsModal\"\nimport {\n getVersioningEnabledToast,\n getVersioningEnableErrorToast,\n getVersioningSuspendedToast,\n getVersioningSuspendErrorToast,\n getBucketPolicySavedToast,\n getBucketPolicySaveErrorToast,\n getBucketPolicyDeletedToast,\n getBucketPolicyDeleteErrorToast,\n getVersionsDeletedToast,\n getVersionsDeleteErrorToast,\n getBucketEmptiedToast,\n getBucketEmptyErrorToast,\n getBucketDeletedToast,\n getBucketDeleteErrorToast,\n} from \"./BucketToastNotifications\"\n\nexport type ModalType =\n | \"enableVersioning\"\n | \"suspendVersioning\"\n | \"policy\"\n | \"deletePolicy\"\n | \"emptyBucket\"\n | \"deleteBucket\"\n | \"deleteVersions\"\n\ninterface BucketModalsProps {\n bucketName: string\n provider?: string\n storageType?: string\n activeModal: ModalType | null\n onClose: () => void\n}\n\n/**\n * Manages all bucket-related modals with unified state\n *\n * Consolidates 7 different modal states into a single component:\n * - Enable/Suspend Versioning\n * - Bucket Policy (View/Add/Delete)\n * - Empty Bucket / Delete Versions\n * - Delete Bucket\n */\nexport const BucketModals = ({ bucketName, provider, storageType, activeModal, onClose }: BucketModalsProps) => {\n const navigate = useNavigate()\n const projectId = useProjectId()\n\n const handleDeleteBucketSuccess = (bucketName: string) => {\n const { message, ...options } = getBucketDeletedToast(bucketName)\n toast.success(message, options)\n // Navigate back to buckets list after successful deletion\n navigate({\n to: \"/projects/$projectId/storage/$provider/$storageType\",\n params: {\n projectId: projectId ?? \"\",\n provider: provider ?? \"ceph\",\n storageType: storageType ?? \"buckets\",\n },\n })\n }\n\n const handleDeleteBucketError = (bucketName: string, errorMessage: string) => {\n const { message, ...options } = getBucketDeleteErrorToast(bucketName, errorMessage)\n toast.error(message, options)\n onClose()\n }\n\n return (\n <>\n <EnableVersioningModal\n isOpen={activeModal === \"enableVersioning\"}\n bucketName={bucketName}\n onClose={onClose}\n onSuccess={(bucketName) => {\n const { message, ...options } = getVersioningEnabledToast(bucketName)\n toast.success(message, options)\n onClose()\n }}\n onError={(bucketName, errorMessage) => {\n const { message, ...options } = getVersioningEnableErrorToast(bucketName, errorMessage)\n toast.error(message, options)\n onClose()\n }}\n />\n\n <SuspendVersioningModal\n isOpen={activeModal === \"suspendVersioning\"}\n bucketName={bucketName}\n onClose={onClose}\n onSuccess={(bucketName) => {\n const { message, ...options } = getVersioningSuspendedToast(bucketName)\n toast.success(message, options)\n onClose()\n }}\n onError={(bucketName, errorMessage) => {\n const { message, ...options } = getVersioningSuspendErrorToast(bucketName, errorMessage)\n toast.error(message, options)\n onClose()\n }}\n />\n\n <BucketPolicyModal\n isOpen={activeModal === \"policy\"}\n bucketName={bucketName}\n onClose={onClose}\n onSuccess={(bucketName, action) => {\n const { message, ...options } =\n action === \"deleted\" ? getBucketPolicyDeletedToast(bucketName) : getBucketPolicySavedToast(bucketName)\n toast.success(message, options)\n }}\n onError={(bucketName, errorMessage, action) => {\n const { message, ...options } =\n action === \"deleted\"\n ? getBucketPolicyDeleteErrorToast(bucketName, errorMessage)\n : getBucketPolicySaveErrorToast(bucketName, errorMessage)\n toast.error(message, options)\n }}\n />\n\n <DeleteBucketPolicyModal\n isOpen={activeModal === \"deletePolicy\"}\n bucketName={bucketName}\n onClose={onClose}\n onSuccess={(bucketName) => {\n const { message, ...options } = getBucketPolicyDeletedToast(bucketName)\n toast.success(message, options)\n onClose()\n }}\n onError={(bucketName, errorMessage) => {\n const { message, ...options } = getBucketPolicyDeleteErrorToast(bucketName, errorMessage)\n toast.error(message, options)\n onClose()\n }}\n />\n\n {/*\n EmptyBucketModal receives a placeholder bucket object with count: 0, bytes: 0.\n This is intentional - the modal fetches real-time bucket state (versioning status,\n object count, versions) via its own queries when opened. The placeholder only provides\n the bucket name for API calls and UI display. This ensures the modal always shows\n fresh data and avoids stale metadata from the parent component.\n */}\n <EmptyBucketModal\n isOpen={activeModal === \"emptyBucket\"}\n bucket={{\n name: bucketName,\n count: 0,\n bytes: 0,\n }}\n onClose={onClose}\n onSuccess={(bucketName, deletedCount) => {\n const { message, ...options } = getBucketEmptiedToast(bucketName, deletedCount)\n toast.success(message, options)\n onClose()\n }}\n onError={(bucketName, errorMessage) => {\n const { message, ...options } = getBucketEmptyErrorToast(bucketName, errorMessage)\n toast.error(message, options)\n onClose()\n }}\n />\n\n {/*\n DeleteBucketModal receives a placeholder bucket object with count: 0, bytes: 0.\n This is intentional - the modal fetches real-time bucket state (object list, versions)\n via its own queries when opened. The placeholder only provides the bucket name for\n API calls and UI display. This ensures the modal always shows fresh data and avoids\n stale metadata from the parent component.\n */}\n <DeleteBucketModal\n isOpen={activeModal === \"deleteBucket\"}\n bucket={{\n name: bucketName,\n count: 0,\n bytes: 0,\n }}\n onClose={onClose}\n onSuccess={handleDeleteBucketSuccess}\n onError={handleDeleteBucketError}\n />\n\n {/*\n DeleteVersionsModal receives a placeholder bucket object with count: 0, bytes: 0.\n This is intentional - the modal fetches real-time bucket state (versions, delete markers)\n via its own queries when opened. The placeholder only provides the bucket name for\n API calls and UI display. This ensures the modal always shows fresh data and avoids\n stale metadata from the parent component.\n */}\n <DeleteVersionsModal\n isOpen={activeModal === \"deleteVersions\"}\n bucket={{\n name: bucketName,\n count: 0,\n bytes: 0,\n }}\n onClose={onClose}\n onSuccess={(bucketName, deletedCount) => {\n const { message, ...options } = getVersionsDeletedToast(bucketName, deletedCount)\n toast.success(message, options)\n onClose()\n }}\n onError={(bucketName, errorMessage) => {\n const { message, ...options } = getVersionsDeleteErrorToast(bucketName, errorMessage)\n toast.error(message, options)\n onClose()\n }}\n />\n </>\n )\n}\n\n/**\n * Custom hook to manage bucket modal state (deprecated - use direct state in parent instead)\n *\n * @returns Object with openModal function and BucketModals component\n */\nexport const useBucketModals = (bucketName: string, provider?: string, storageType?: string) => {\n const [activeModal, setActiveModal] = useState<ModalType | null>(null)\n\n const openModal = (modal: ModalType) => setActiveModal(modal)\n\n const closeModal = () => setActiveModal(null)\n\n const ModalsComponent = () => (\n <BucketModals\n bucketName={bucketName}\n provider={provider}\n storageType={storageType}\n activeModal={activeModal}\n onClose={closeModal}\n />\n )\n\n return {\n openModal,\n activeModal,\n setActiveModal,\n ModalsComponent,\n }\n}\n","import { useLingui } from \"@lingui/react/macro\"\nimport { TabNavigation, TabNavigationItem } from \"@cloudoperators/juno-ui-components\"\nimport { Route } from \"@/client/routes/_auth/projects/$projectId/storage/$provider/$storageType/$containerName/objects\"\n\n/**\n * Tab navigation for bucket detail page\n *\n * Provides three tabs:\n * - Overview: object browser (default)\n * - CORS Rules: CORS configuration management\n * - Lifecycle Rules: lifecycle configuration management\n *\n * Tab state is persisted in the URL via the `view` search param.\n */\nexport const BucketDetailTabs = () => {\n const { t } = useLingui()\n const navigate = Route.useNavigate()\n const { view } = Route.useSearch()\n\n return (\n <TabNavigation>\n <TabNavigationItem\n label={t`Overview`}\n active={view === \"overview\"}\n onClick={() => {\n navigate({\n search: (prev) => ({\n ...prev,\n view: \"overview\",\n }),\n })\n }}\n />\n <TabNavigationItem\n label={t`CORS Rules`}\n active={view === \"cors-rules\"}\n onClick={() => {\n navigate({\n search: (prev) => ({\n ...prev,\n view: \"cors-rules\",\n }),\n })\n }}\n />\n <TabNavigationItem\n label={t`Lifecycle Rules`}\n active={view === \"lifecycle-rules\"}\n onClick={() => {\n navigate({\n search: (prev) => ({\n ...prev,\n view: \"lifecycle-rules\",\n }),\n })\n }}\n />\n </TabNavigation>\n )\n}\n","import { useState } from \"react\"\nimport { Trans } from \"@lingui/react/macro\"\nimport { useParams } from \"@tanstack/react-router\"\nimport { Badge, Divider } from \"@cloudoperators/juno-ui-components\"\nimport { ContentHeader } from \"@/client/components/ContentHeader/ContentHeader\"\nimport { useBucketInfo } from \"../hooks/useBucketInfo\"\nimport { useCephPermissions } from \"../hooks/useCephPermissions\"\nimport { BucketHeaderActions } from \"./BucketHeaderActions\"\nimport { BucketModals, type ModalType } from \"./BucketModals\"\nimport { BucketDetailTabs } from \"./BucketDetailTabs\"\n\ninterface BucketHeaderProps {\n bucketName: string\n}\n\n/**\n * Bucket header component with badges, actions, and modals\n *\n * Displays:\n * - Bucket name as title\n * - Badges for versioning status and policy\n * - Action buttons\n * - All bucket management modals\n */\nexport const BucketHeader = ({ bucketName }: BucketHeaderProps) => {\n const { projectId, provider, storageType } = useParams({\n from: \"/_auth/projects/$projectId/storage/$provider/$storageType/$containerName/objects/\",\n })\n\n const [activeModal, setActiveModal] = useState<ModalType | null>(null)\n\n // Fetch bucket information\n const { versioningStatus, policyData, hasOldVersionsOrDeleteMarkers, isBucketEmpty } = useBucketInfo({\n bucketName,\n enabled: true,\n })\n\n const { permissions } = useCephPermissions(projectId)\n\n const openModal = (modal: ModalType) => setActiveModal(modal)\n const closeModal = () => setActiveModal(null)\n\n // Build badges\n const badges = (\n <>\n {versioningStatus && versioningStatus.status === \"Enabled\" && (\n <Badge variant=\"success\">\n <Trans>Versioning Enabled</Trans>\n </Badge>\n )}\n {versioningStatus && versioningStatus.status === \"Suspended\" && (\n <Badge variant=\"warning\">\n <Trans>Versioning Suspended</Trans>\n </Badge>\n )}\n {policyData?.policy && (\n <Badge variant=\"info\">\n <Trans>Bucket Policy</Trans>\n </Badge>\n )}\n </>\n )\n\n // Build actions\n const actions = (\n <BucketHeaderActions\n versioningStatus={versioningStatus}\n hasPolicy={Boolean(policyData?.policy)}\n hasOldVersionsOrDeleteMarkers={hasOldVersionsOrDeleteMarkers}\n isBucketEmpty={isBucketEmpty}\n onOpenModal={openModal}\n canUpdateVersioning={permissions.canUpdateVersioning}\n canUpdatePolicy={permissions.canUpdatePolicy}\n canDeletePolicy={permissions.canDeletePolicy}\n canEmptyBucket={permissions.canEmptyBucket}\n canDeleteBucket={permissions.canDeleteBucket}\n canDeleteVersions={permissions.canDeleteVersion}\n />\n )\n\n return (\n <>\n <ContentHeader title={bucketName} projectId={projectId} badges={badges} actions={actions} />\n\n <div className=\"-mt-4 mb-8\">\n <BucketDetailTabs />\n <Divider spacing=\"0\" />\n </div>\n\n <BucketModals\n bucketName={bucketName}\n provider={provider}\n storageType={storageType}\n activeModal={activeModal}\n onClose={closeModal}\n />\n </>\n )\n}\n","import { useLingui } from \"@lingui/react/macro\"\nimport { Button, PopupMenu, PopupMenuItem, PopupMenuOptions, PopupMenuToggle } from \"@cloudoperators/juno-ui-components\"\n\nexport type ContainerModalType = \"manageAccess\" | \"editMetadata\" | \"emptyContainer\" | \"deleteContainer\"\n\ninterface ContainerHeaderActionsProps {\n onOpenModal: (modal: ContainerModalType) => void\n}\n\n/**\n * Container header actions component (Swift objects page)\n *\n * Unlike Ceph's BucketHeaderActions, this menu has no permission props and\n * nothing is conditionally hidden: Swift has no `canUser`/policy wiring\n * anywhere in this area yet (see the TODO(perms) note in\n * `Swift/Containers/index.tsx`), so there is no source of truth to gate on.\n * All four items are always shown once the parent has real container data.\n */\nexport const ContainerHeaderActions = ({ onOpenModal }: ContainerHeaderActionsProps) => {\n const { t } = useLingui()\n\n return (\n <PopupMenu>\n <PopupMenuToggle as=\"div\">\n <Button icon=\"moreVert\" title={t`Container actions`} aria-label={t`Container actions`} />\n </PopupMenuToggle>\n <PopupMenuOptions>\n <PopupMenuItem\n label={t`Manage Access`}\n onClick={() => onOpenModal(\"manageAccess\")}\n data-testid=\"container-actions-manage-access\"\n />\n <PopupMenuItem\n label={t`Preview and Edit metadata`}\n onClick={() => onOpenModal(\"editMetadata\")}\n data-testid=\"container-actions-edit-metadata\"\n />\n <PopupMenuItem\n label={t`Empty Container`}\n onClick={() => onOpenModal(\"emptyContainer\")}\n data-testid=\"container-actions-empty\"\n />\n <PopupMenuItem\n label={t`Delete Container`}\n onClick={() => onOpenModal(\"deleteContainer\")}\n data-testid=\"container-actions-delete\"\n />\n </PopupMenuOptions>\n </PopupMenu>\n )\n}\n","import { useState, useEffect, useRef, Fragment } from \"react\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { t } from \"@lingui/core/macro\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport {\n Modal,\n Textarea,\n Stack,\n Status,\n Checkbox,\n Badge,\n Button,\n Icon,\n Tooltip,\n TooltipTrigger,\n TooltipContent,\n Message,\n DescriptionList,\n DescriptionTerm,\n DescriptionDefinition,\n} from \"@cloudoperators/juno-ui-components\"\nimport { ContainerSummary } from \"@/server/Storage/types/swift\"\n\n// ── ACL parsing helpers ──────────────────────────────────────────────────────\n\ntype AclEntryType =\n | \"any-referrer\"\n | \"denied-referrer\"\n | \"specific-referrer\"\n | \"listing-access\"\n | \"all-project-users\"\n | \"specific-user-any-project\"\n | \"specific-user\"\n | \"unknown\"\n\ninterface ParsedAclEntry {\n raw: string\n type: AclEntryType\n host?: string\n projectId?: string\n userId?: string\n description: string\n requiresToken: boolean\n}\n\n/**\n * Parses a single ACL entry string into a human-readable representation.\n * Handles the following Swift ACL formats:\n * .r:* — public read (any referrer)\n * .rlistings — public container listing\n * PROJECT:USER — specific user from a specific project\n * PROJECT:* — all users from a project\n * *:USER — specific user from any project\n */\nfunction parseAclEntry(raw: string): ParsedAclEntry {\n const entry = raw.trim()\n\n if (entry === \".r:*\") {\n return { raw: entry, type: \"any-referrer\", description: \"\", requiresToken: false }\n }\n\n // .r:<referrer> or .r:-<referrer> — specific referrer granted (or denied) access\n if (entry.startsWith(\".r:\")) {\n const referrer = entry.slice(3)\n const isDeny = referrer.startsWith(\"-\")\n const host = isDeny ? referrer.slice(1) : referrer\n return {\n raw: entry,\n type: isDeny ? \"denied-referrer\" : \"specific-referrer\",\n host,\n description: \"\",\n requiresToken: false,\n }\n }\n\n if (entry === \".rlistings\") {\n return { raw: entry, type: \"listing-access\", description: \"\", requiresToken: false }\n }\n\n // PROJECT_ID:* — all users from a project\n if (/^[^:]+:\\*$/.test(entry) && !entry.startsWith(\"*\")) {\n const [projectId] = entry.split(\":\")\n return {\n raw: entry,\n type: \"all-project-users\",\n projectId,\n description: \"\",\n requiresToken: true,\n }\n }\n\n // *:USER_ID — specific user, any project\n if (entry.startsWith(\"*:\")) {\n const userId = entry.slice(2)\n return {\n raw: entry,\n type: \"specific-user-any-project\",\n userId,\n description: \"\",\n requiresToken: true,\n }\n }\n\n // PROJECT_ID:USER_ID\n if (entry.includes(\":\")) {\n const [projectId, userId] = entry.split(\":\")\n return {\n raw: entry,\n type: \"specific-user\",\n projectId,\n userId,\n description: \"\",\n requiresToken: true,\n }\n }\n\n // Fallback — unknown format\n return { raw: entry, type: \"unknown\", description: \"\", requiresToken: true }\n}\n\nfunction parseAclString(aclString: string): ParsedAclEntry[] {\n if (!aclString.trim()) return []\n return aclString\n .split(\",\")\n .map((s) => s.trim())\n .filter(Boolean)\n .map(parseAclEntry)\n}\n\n// ── Public read sentinel values ──────────────────────────────────────────────\n// const PUBLIC_READ_ACL = \".r:*,.rlistings\"\nconst PUBLIC_READ_ENTRIES = [\".r:*\", \".rlistings\"]\n\nfunction isPublicRead(readAcl: string): boolean {\n const entries = readAcl\n .split(\",\")\n .map((s) => s.trim())\n .filter(Boolean)\n return PUBLIC_READ_ENTRIES.every((e) => entries.includes(e))\n}\n\nfunction addPublicReadEntries(current: string): string {\n const existing = current\n .split(\",\")\n .map((s) => s.trim())\n .filter(Boolean)\n const merged = [...new Set([...PUBLIC_READ_ENTRIES, ...existing])]\n return merged.join(\",\")\n}\n\nfunction removePublicReadEntries(current: string): string {\n return current\n .split(\",\")\n .map((s) => s.trim())\n .filter((e) => !PUBLIC_READ_ENTRIES.includes(e))\n .join(\",\")\n}\n\n// ── ACL label rendering helper ──────────────────────────────────────────────\n\nfunction aclEntryLabel(entry: ParsedAclEntry): string {\n switch (entry.type) {\n case \"any-referrer\":\n return t`ANY referrer`\n case \"denied-referrer\": {\n const host = entry.host || \"\"\n return t`Denied referrer: ${host}`\n }\n case \"specific-referrer\": {\n const host = entry.host || \"\"\n return t`Specific referrer: ${host}`\n }\n case \"listing-access\":\n return t`Listing access`\n case \"all-project-users\": {\n const projectId = entry.projectId || \"\"\n return t`All users from project ${projectId}`\n }\n case \"specific-user-any-project\": {\n const userId = entry.userId || \"\"\n return t`User ${userId} (any project)`\n }\n case \"specific-user\": {\n const projectId = entry.projectId || \"\"\n const userId = entry.userId || \"\"\n return t`User ${userId} from project ${projectId}`\n }\n case \"unknown\":\n default:\n return entry.raw\n }\n}\n\n// ── Component ────────────────────────────────────────────────────────────────\n\ninterface ManageContainerAccessModalProps {\n isOpen: boolean\n container: ContainerSummary | null\n onClose: () => void\n onSuccess?: (containerName: string) => void\n onError?: (containerName: string, errorMessage: string) => void\n}\n\nexport const ManageContainerAccessModal = ({\n isOpen,\n container,\n onClose,\n onSuccess,\n onError,\n}: ManageContainerAccessModalProps) => {\n const { t } = useLingui()\n const projectId = useProjectId()\n\n const [readAcl, setReadAcl] = useState(\"\")\n const [writeAcl, setWriteAcl] = useState(\"\")\n const [publicRead, setPublicRead] = useState(false)\n const [showPreview, setShowPreview] = useState(false)\n\n // Auto-collapse preview when both ACL fields are cleared\n useEffect(() => {\n if (!readAcl.trim() && !writeAcl.trim()) setShowPreview(false)\n }, [readAcl, writeAcl])\n\n // ── Query ─────────────────────────────────────────────────────────────────\n const {\n data: info,\n isLoading,\n isError: isMetaError,\n error: metaError,\n } = trpcReact.storage.swift.getContainerMetadata.useQuery(\n { project_id: projectId, container: container?.name ?? \"\" },\n { enabled: isOpen && container !== null }\n )\n\n // ── Populate form when data arrives ──────────────────────────────────────\n useEffect(() => {\n if (!info) return\n const read = info.read ?? \"\"\n const write = info.write ?? \"\"\n setReadAcl(read)\n setWriteAcl(write)\n setPublicRead(isPublicRead(read))\n }, [info])\n\n // ── Mutation ──────────────────────────────────────────────────────────────\n const utils = trpcReact.useUtils()\n\n const updateMutation = trpcReact.storage.swift.updateContainerMetadata.useMutation({\n onSuccess: () => {\n utils.storage.swift.getContainerMetadata.invalidate({ project_id: projectId, container: container!.name })\n utils.storage.swift.listContainers.invalidate()\n onSuccess?.(container!.name)\n handleClose()\n },\n onError: (error) => {\n onError?.(container!.name, error.message)\n },\n })\n\n // Keep a stable ref to reset() so the cleanup effect below doesn't need\n // updateMutation in its dependency array (the mutation object is recreated\n // on every render, which would cause an infinite loop).\n const resetMutationRef = useRef(updateMutation.reset)\n resetMutationRef.current = updateMutation.reset\n\n const handleClose = () => {\n setReadAcl(\"\")\n setWriteAcl(\"\")\n setPublicRead(false)\n setShowPreview(false)\n updateMutation.reset()\n onClose()\n }\n\n // ── Reset when closed ────────────────────────────────────────────────────\n useEffect(() => {\n if (!isOpen) {\n setReadAcl(\"\")\n setWriteAcl(\"\")\n setPublicRead(false)\n resetMutationRef.current()\n }\n }, [isOpen])\n\n // ── Public read checkbox sync ─────────────────────────────────────────────\n const handlePublicReadChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const checked = e.target.checked\n setPublicRead(checked)\n setReadAcl((prev) => (checked ? addPublicReadEntries(prev) : removePublicReadEntries(prev)))\n }\n\n const handleReadAclChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {\n const value = e.target.value\n setReadAcl(value)\n setPublicRead(isPublicRead(value))\n }\n\n // ── Submit ────────────────────────────────────────────────────────────────\n const handleSubmit = () => {\n if (!container) return\n updateMutation.mutate({\n project_id: projectId,\n container: container.name,\n read: readAcl.trim(),\n write: writeAcl.trim(),\n })\n }\n\n if (!isOpen || !container) return null\n\n const isBusy = isLoading || updateMutation.isPending\n const hasAnyAcl = readAcl.trim().length > 0 || writeAcl.trim().length > 0\n\n const parsedReadEntries = parseAclString(readAcl)\n const parsedWriteEntries = parseAclString(writeAcl)\n\n const modalTitle = (\n <span className=\"flex items-center gap-2\">\n <Trans>Access Control for Container:</Trans>\n <span className=\"max-w-62.5 truncate\" title={container.name}>\n {container.name}\n </span>\n </span>\n )\n\n return (\n <Modal\n title={modalTitle}\n open={isOpen}\n onCancel={handleClose}\n confirmButtonLabel={t`Save`}\n onConfirm={handleSubmit}\n cancelButtonLabel={t`Cancel`}\n size=\"xl\"\n disableConfirmButton={isBusy || isMetaError}\n >\n {updateMutation.isError && (\n <Message variant=\"error\" className=\"mb-4\">\n {(() => {\n const errorMessage = updateMutation.error.message\n return <Trans>Failed to update ACLs: {errorMessage}</Trans>\n })()}\n </Message>\n )}\n <div className=\"max-h-[70vh] overflow-y-auto pr-1 pl-1\">\n {/* ── Info message ─────────────────────────────────────────────────── */}\n <div className=\"mb-4\">\n <Message variant=\"warning\" className=\"mb-4\">\n <Trans>\n Ensure that the Project ID and User ID you enter are correct. The system cannot validate these values —\n incorrect IDs may apply access to wrong projects and users.\n </Trans>\n </Message>\n </div>\n\n {isLoading ? (\n <Status status=\"progress\" title={t`Loading ACLs...`} className=\"mt-0\" />\n ) : isMetaError ? (\n <Status\n status=\"error\"\n title={t`Failed to Load Container ACLs`}\n body={metaError?.message ?? \"\"}\n className=\"mt-0\"\n />\n ) : (\n <>\n <div className=\"flex gap-6\">\n {/* ── Left: editable inputs ──────────────────────────────────── */}\n <div className=\"min-w-0 flex-1\">\n <Stack direction=\"vertical\" gap=\"6\">\n {/* Read ACLs */}\n <div>\n <AclFieldLabel label={t`Read ACLs`} />\n <Textarea\n value={readAcl}\n onChange={handleReadAclChange}\n disabled={isBusy || publicRead}\n placeholder={t`e.g. .r:*,.rlistings`}\n className=\"text-sm\"\n rows={3}\n />\n <Checkbox\n label={t`Public Read Access`}\n checked={publicRead}\n onChange={handlePublicReadChange}\n disabled={isBusy}\n className=\"mt-2\"\n />\n </div>\n\n {/* Write ACLs */}\n <div>\n <AclFieldLabel label={t`Write ACLs`} />\n <Textarea\n value={writeAcl}\n onChange={(e: React.ChangeEvent<HTMLTextAreaElement>) => {\n const value = e.target.value\n setWriteAcl(value)\n }}\n disabled={isBusy}\n placeholder={t`e.g. PROJECT_ID:USER_ID`}\n className=\"text-sm\"\n rows={3}\n />\n </div>\n\n {/* ── Preview toggle button — only shown when at least one ACL is set (only shown when ACL fields have content) ──────────────────────────── */}\n {hasAnyAcl && (\n <Button\n label={showPreview ? t`Hide ACLs Preview` : t`Show ACLs Preview`}\n onClick={() => setShowPreview((v) => !v)}\n variant=\"subdued\"\n disabled={isBusy}\n className=\"self-start\"\n />\n )}\n\n {/* ── Parsed ACL preview — inside left column, below button ── */}\n {showPreview && (parsedReadEntries.length > 0 || parsedWriteEntries.length > 0) && (\n <Stack direction=\"vertical\" gap=\"4\">\n {parsedReadEntries.length > 0 && (\n <div>\n <p className=\"text-theme-default mb-2 text-sm font-semibold\">\n <Trans>Read ACLs — Preview</Trans>\n </p>\n <div className=\"border-theme-background-lvl-3 rounded border p-3\">\n <DescriptionList className=\"grid-cols-2\" alignTerms=\"left\">\n {parsedReadEntries.map((entry, i) => (\n <Fragment key={i}>\n <DescriptionTerm className=\"col-span-1\">\n <span className=\"block truncate text-xs\" title={entry.raw}>\n {entry.raw}\n </span>\n </DescriptionTerm>\n <DescriptionDefinition className=\"col-span-1\">\n <span className=\"block truncate text-sm\" title={aclEntryLabel(entry)}>\n {aclEntryLabel(entry)}\n </span>\n <span className=\"text-theme-light block text-xs\">\n {entry.requiresToken ? (\n <Trans>valid token required: true</Trans>\n ) : (\n <Trans>valid token required: false</Trans>\n )}\n </span>\n </DescriptionDefinition>\n </Fragment>\n ))}\n </DescriptionList>\n </div>\n </div>\n )}\n\n {parsedWriteEntries.length > 0 && (\n <div>\n <p className=\"text-theme-default mb-2 text-sm font-semibold\">\n <Trans>Write ACLs — Preview</Trans>\n </p>\n <div className=\"border-theme-background-lvl-3 rounded border p-3\">\n <DescriptionList className=\"grid-cols-2\" alignTerms=\"left\">\n {parsedWriteEntries.map((entry, i) => (\n <Fragment key={i}>\n <DescriptionTerm className=\"col-span-1\">\n <span className=\"block truncate text-xs\" title={entry.raw}>\n {entry.raw}\n </span>\n </DescriptionTerm>\n <DescriptionDefinition className=\"col-span-1\">\n <span className=\"block truncate text-sm\" title={aclEntryLabel(entry)}>\n {aclEntryLabel(entry)}\n </span>\n <span className=\"text-theme-light block text-xs\">\n {entry.requiresToken ? (\n <Trans>valid token required: true</Trans>\n ) : (\n <Trans>valid token required: false</Trans>\n )}\n </span>\n </DescriptionDefinition>\n </Fragment>\n ))}\n </DescriptionList>\n </div>\n </div>\n )}\n </Stack>\n )}\n </Stack>\n </div>\n\n {/* ── Right: reference panel ─────────────────────────────────── */}\n <div className=\"border-theme-background-lvl-3 w-72 shrink-0 border-l pl-6\">\n <p className=\"text-theme-default mb-3 text-xs\">\n <Trans>Entries in ACLs are comma-separated. Examples:</Trans>\n </p>\n\n <Stack direction=\"vertical\" gap=\"4\">\n <AclExample\n code=\".r:*\"\n description={t`Any user has read access to objects. No token is required in the request.`}\n />\n <AclExample\n code=\".rlistings\"\n description={t`Any user can perform a HEAD or GET operation on the container provided the user also has read access on objects. No token is required.`}\n />\n <AclExample\n code=\"PROJECT_ID:USER_ID\"\n description={t`Grant access to a user from a different project.`}\n />\n <AclExample code=\"PROJECT_ID:*\" description={t`Grant access to all users from that project.`} />\n <AclExample\n code=\"*:USER_ID\"\n description={t`The specified user has access. A token for the user (scoped to any project) must be included in the request.`}\n />\n </Stack>\n\n <p className=\"text-theme-default mt-4 text-xs\">\n <Trans>\n For more details, have a look at the{\" \"}\n <a\n href=\"https://docs.openstack.org/swift/latest/overview_acl.html\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"text-theme-link underline\"\n >\n documentation\n </a>\n .\n </Trans>\n </p>\n </div>\n </div>\n </>\n )}\n\n {/* Note shown at the bottom of the modal body, just above the Save button */}\n {!isLoading && !isMetaError && (\n <p className=\"text-theme-light mt-4 text-xs\">\n <Trans>Changes take effect immediately after saving.</Trans>\n </p>\n )}\n </div>\n </Modal>\n )\n}\n\n// ── AclExample sub-component ─────────────────────────────────────────────────\n\ninterface AclExampleProps {\n code: string\n description: string\n}\n\nfunction AclExample({ code, description }: AclExampleProps) {\n return (\n <div>\n <Badge variant=\"info\" className=\"mb-1 text-xs\">\n {code}\n </Badge>\n <p className=\"text-theme-default text-xs leading-relaxed\">{description}</p>\n </div>\n )\n}\n\n// ── AclFieldLabel sub-component ──────────────────────────────────────────────\n\ninterface AclFieldLabelProps {\n label: string\n}\n\nfunction AclFieldLabel({ label }: AclFieldLabelProps) {\n return (\n <div className=\"mb-1 flex items-center gap-1\">\n <label className=\"text-theme-default text-sm font-semibold\">{label}</label>\n <Tooltip triggerEvent=\"hover\">\n <TooltipTrigger>\n <Icon icon=\"info\" size=\"14\" className=\"text-theme-light cursor-help\" />\n </TooltipTrigger>\n <TooltipContent className=\"z-10 max-w-87.5\">\n <Trans>\n Ensure ACL entries are valid — correct project IDs, user IDs, and formats are your responsibility. Invalid\n entries may silently grant or deny unintended access.\n </Trans>\n </TooltipContent>\n </Tooltip>\n </div>\n )\n}\n","import { useState, useEffect, useRef, useCallback } from \"react\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport {\n Modal,\n TextInput,\n Stack,\n Status,\n DataGrid,\n DataGridRow,\n DataGridHeadCell,\n DataGridCell,\n Button,\n Checkbox,\n Tooltip,\n TooltipTrigger,\n TooltipContent,\n Icon,\n ComboBox,\n ComboBoxOption,\n} from \"@cloudoperators/juno-ui-components\"\nimport { ContainerSummary } from \"@/server/Storage/types/swift\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\n\n// ── Reserved metadata keys that are exposed as dedicated fields ──────────────\nconst RESERVED_META_KEYS = new Set([\n \"quota-bytes\",\n \"quota-count\",\n \"web-index\",\n \"web-listings\",\n \"web-listings-css\",\n \"web-error\",\n])\n\nconst MAX_COMBO_OPTIONS = 50\n\n// RFC 7230 token allowlist — letters, digits, and safe symbols only.\n// Using a positive allowlist avoids the ESLint no-control-regex rule.\nconst VALID_KEY_RE = /^[a-zA-Z0-9!#$%&'*+\\-.^_`|~]+$/\n\ninterface MetadataEntry {\n key: string\n value: string\n isNew?: boolean\n isEditing?: boolean\n originalKey?: string\n originalValue?: string\n}\n\ninterface EditContainerMetadataModalProps {\n isOpen: boolean\n container: ContainerSummary | null\n onClose: () => void\n onSuccess?: (containerName: string) => void\n // Retained for API compatibility with callers, but intentionally NOT wired to\n // a toast: container-update is recoverable, so failures are shown inline in the\n // modal (see #1162). Kept optional so existing callers still type-check.\n onError?: (containerName: string, errorMessage: string) => void\n}\n\nexport const EditContainerMetadataModal = ({\n isOpen,\n container,\n onClose,\n onSuccess,\n}: EditContainerMetadataModalProps) => {\n const { t } = useLingui()\n const projectId = useProjectId()\n\n // ── Query ─────────────────────────────────────────────────────────────────\n const {\n data: info,\n isLoading,\n isError: isMetaError,\n error: metaError,\n } = trpcReact.storage.swift.getContainerMetadata.useQuery(\n { project_id: projectId, container: container?.name ?? \"\" },\n { enabled: isOpen && container !== null }\n )\n\n const isPublicAccess = info?.read === \".r:*,.rlistings\"\n\n const { data: publicUrl } = trpcReact.storage.swift.getContainerPublicUrl.useQuery(\n { project_id: projectId, container: container?.name ?? \"\" },\n { enabled: isOpen && container !== null && isPublicAccess }\n )\n\n const { data: containers } = trpcReact.storage.swift.listContainers.useQuery(\n { project_id: projectId },\n { enabled: isOpen }\n )\n\n const [containerSearch, setContainerSearch] = useState(\"\")\n const [debouncedSearch, setDebouncedSearch] = useState(\"\")\n const debounceTimer = useRef<ReturnType<typeof setTimeout> | null>(null)\n\n const handleContainerSearch = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {\n const value = e.target.value\n setContainerSearch(value)\n if (debounceTimer.current) clearTimeout(debounceTimer.current)\n debounceTimer.current = setTimeout(() => setDebouncedSearch(value), 300)\n }, [])\n\n const filteredContainers =\n debouncedSearch.trim().length > 0\n ? (containers ?? []).filter(\n (c) => c.name !== container?.name && c.name.toLowerCase().includes(debouncedSearch.toLowerCase())\n )\n : []\n\n const visibleContainers = filteredContainers.slice(0, MAX_COMBO_OPTIONS)\n const hiddenCount = filteredContainers.length - visibleContainers.length\n\n const utils = trpcReact.useUtils()\n\n // ── Form state ────────────────────────────────────────────────────────────\n // Quota fields\n const [quotaBytes, setQuotaBytes] = useState(\"\")\n const [quotaBytesError, setQuotaBytesError] = useState<string | null>(null)\n const [quotaCount, setQuotaCount] = useState(\"\")\n const [quotaCountError, setQuotaCountError] = useState<string | null>(null)\n\n // Static website fields\n const [webIndex, setWebIndex] = useState(\"\")\n const [webListings, setWebListings] = useState(false)\n\n // Versioning\n const [versionsEnabled, setVersionsEnabled] = useState(false)\n const [versionsLocation, setVersionsLocation] = useState(\"\")\n\n // Custom metadata\n const [metadata, setMetadata] = useState<MetadataEntry[]>([])\n const [metaErrors, setMetaErrors] = useState<Record<string, string>>({})\n const [isAddingNew, setIsAddingNew] = useState(false)\n const [newKey, setNewKey] = useState(\"\")\n const [newValue, setNewValue] = useState(\"\")\n const [newKeyError, setNewKeyError] = useState<string | null>(null)\n const [newValueError, setNewValueError] = useState<string | null>(null)\n\n // ── Populate form when data arrives ──────────────────────────────────────\n useEffect(() => {\n if (!info) return\n\n setQuotaBytes(info.quotaBytes != null ? String(info.quotaBytes) : \"\")\n setQuotaCount(info.quotaCount != null ? String(info.quotaCount) : \"\")\n setVersionsEnabled(!!(info.versionsEnabled || info.versionsLocation || info.historyLocation))\n setVersionsLocation(info.versionsLocation || info.historyLocation || \"\")\n\n const rawMetaForWeb = info.metadata ?? {}\n setWebIndex(rawMetaForWeb[\"web-index\"] ?? \"\")\n setWebListings(rawMetaForWeb[\"web-listings\"] === \"1\" || rawMetaForWeb[\"web-listings\"] === \"true\")\n\n // Custom metadata — exclude reserved keys\n const rawMeta = info.metadata ?? {}\n const entries: MetadataEntry[] = Object.entries(rawMeta)\n .filter(([key]) => !RESERVED_META_KEYS.has(key))\n .map(([key, value]) => ({\n key,\n value,\n isNew: false,\n isEditing: false,\n originalKey: key,\n originalValue: value,\n }))\n setMetadata(entries)\n }, [info])\n\n // Reset when closed\n useEffect(() => {\n if (!isOpen) {\n resetForm()\n }\n }, [isOpen])\n\n const resetForm = () => {\n setQuotaBytes(\"\")\n setQuotaBytesError(null)\n setQuotaCount(\"\")\n setQuotaCountError(null)\n setWebIndex(\"\")\n setWebListings(false)\n setVersionsEnabled(false)\n setVersionsLocation(\"\")\n setContainerSearch(\"\")\n setDebouncedSearch(\"\")\n if (debounceTimer.current) clearTimeout(debounceTimer.current)\n setMetadata([])\n setMetaErrors({})\n setIsAddingNew(false)\n setNewKey(\"\")\n setNewValue(\"\")\n setNewKeyError(null)\n setNewValueError(null)\n updateMutation.reset()\n }\n\n // ── Mutation ──────────────────────────────────────────────────────────────\n const updateMutation = trpcReact.storage.swift.updateContainerMetadata.useMutation({\n onSuccess: () => {\n utils.storage.swift.getContainerMetadata.invalidate({ container: container!.name })\n utils.storage.swift.listContainers.invalidate()\n onSuccess?.(container!.name)\n handleClose()\n },\n onError: () => {\n // #1162: container-metadata update is recoverable, so we surface the\n // failure via the inline banner in the modal body (updateMutation.isError)\n // and deliberately do NOT also fire a toast. The modal stays open so the\n // user can adjust and retry. Showing both was the double-error bug.\n },\n })\n\n // ── Validation ────────────────────────────────────────────────────────────\n const validateQuotas = (): boolean => {\n let valid = true\n if (\n quotaBytes !== \"\" &&\n (isNaN(Number(quotaBytes)) || !Number.isInteger(Number(quotaBytes)) || Number(quotaBytes) < 0)\n ) {\n setQuotaBytesError(t`Must be a whole number, 0 or greater`)\n valid = false\n } else {\n setQuotaBytesError(null)\n }\n if (\n quotaCount !== \"\" &&\n (isNaN(Number(quotaCount)) || !Number.isInteger(Number(quotaCount)) || Number(quotaCount) < 0)\n ) {\n setQuotaCountError(t`Must be a whole number, 0 or greater`)\n valid = false\n } else {\n setQuotaCountError(null)\n }\n return valid\n }\n\n const validateMetaKey = (key: string, originalKey?: string): string | null => {\n if (!key.trim()) return t`Key is required`\n if (!VALID_KEY_RE.test(key)) return t`Key contains invalid characters`\n if (!/[a-zA-Z0-9]/.test(key)) return t`Key must contain at least one alphanumeric character`\n if (RESERVED_META_KEYS.has(key.toLowerCase())) return t`This key is reserved and managed separately`\n const isDuplicate = metadata.some((e) => e.key.toLowerCase() === key.toLowerCase() && e.originalKey !== originalKey)\n if (isDuplicate) return t`A property with this key already exists`\n return null\n }\n\n // ── Metadata row handlers ─────────────────────────────────────────────────\n const handleAddNew = () => {\n const keyErr = validateMetaKey(newKey)\n if (keyErr) {\n setNewKeyError(keyErr)\n return\n }\n if (!newValue.trim()) {\n setNewValueError(t`Value is required`)\n return\n }\n\n setMetadata([...metadata, { key: newKey.trim(), value: newValue.trim(), isNew: true, isEditing: false }])\n setNewKey(\"\")\n setNewValue(\"\")\n setIsAddingNew(false)\n setNewKeyError(null)\n setNewValueError(null)\n }\n\n const handleCancelAdd = () => {\n setNewKey(\"\")\n setNewValue(\"\")\n setIsAddingNew(false)\n setNewKeyError(null)\n setNewValueError(null)\n }\n\n const handleEdit = (index: number) => {\n setMetadata(metadata.map((e, i) => (i === index ? { ...e, isEditing: true } : { ...e, isEditing: false })))\n setIsAddingNew(false)\n }\n\n const handleSaveEdit = (index: number) => {\n const entry = metadata[index]\n const keyErr = validateMetaKey(entry.key, entry.originalKey)\n if (keyErr) {\n setMetaErrors({ [`edit-${index}`]: keyErr })\n return\n }\n if (!entry.value.trim()) {\n setMetaErrors({ [`edit-${index}`]: t`Value is required` })\n return\n }\n\n setMetadata(\n metadata.map((e, i) => (i === index ? { ...e, isEditing: false, key: e.key.trim(), value: e.value.trim() } : e))\n )\n setMetaErrors({})\n }\n\n const handleCancelEdit = (index: number) => {\n setMetadata(\n metadata.map((e, i) =>\n i === index ? { ...e, isEditing: false, key: e.originalKey ?? e.key, value: e.originalValue ?? e.value } : e\n )\n )\n setMetaErrors({})\n }\n\n const handleDeleteMeta = (index: number) => {\n setMetadata(metadata.filter((_, i) => i !== index))\n setMetaErrors({})\n }\n\n const handleKeyChange = (index: number, value: string) => {\n setMetadata(metadata.map((e, i) => (i === index ? { ...e, key: value } : e)))\n setMetaErrors((prev) => {\n const n = { ...prev }\n delete n[`edit-${index}`]\n return n\n })\n }\n\n const handleValueChange = (index: number, value: string) => {\n setMetadata(metadata.map((e, i) => (i === index ? { ...e, value } : e)))\n setMetaErrors((prev) => {\n const n = { ...prev }\n delete n[`edit-${index}`]\n return n\n })\n }\n\n // ── Submit ────────────────────────────────────────────────────────────────\n const handleSubmit = () => {\n if (!container) return\n if (!validateQuotas()) return\n\n const rawMeta = info?.metadata ?? {}\n\n // Build custom metadata updates/removals\n const metadataToSet: Record<string, string> = {}\n const removeMetadata: string[] = []\n\n // New or changed entries\n metadata.forEach((entry) => {\n if (entry.isNew || entry.value !== entry.originalValue || entry.key !== entry.originalKey) {\n metadataToSet[entry.key] = entry.value\n // Key was renamed — remove the old key explicitly\n if (!entry.isNew && entry.originalKey && entry.key !== entry.originalKey) {\n removeMetadata.push(entry.originalKey)\n }\n }\n })\n\n // Deleted entries — keys that were in original but not in current list at all\n const originalKeys = Object.keys(rawMeta).filter((k) => !RESERVED_META_KEYS.has(k))\n const currentOriginalKeys = metadata.map((e) => e.originalKey).filter(Boolean) as string[]\n originalKeys.forEach((k) => {\n if (!currentOriginalKeys.includes(k) && !removeMetadata.includes(k)) removeMetadata.push(k)\n })\n\n // Web index / listings — only relevant when public access is enabled\n if (isPublicAccess) {\n if (webIndex) {\n metadataToSet[\"web-index\"] = webIndex\n } else if (info?.metadata?.[\"web-index\"]) {\n removeMetadata.push(\"web-index\")\n }\n if (webListings) {\n metadataToSet[\"web-listings\"] = \"1\"\n } else if (info?.metadata?.[\"web-listings\"]) {\n removeMetadata.push(\"web-listings\")\n }\n }\n\n // Determine versioning changes\n const wasVersioned = !!(info?.versionsEnabled || info?.versionsLocation || info?.historyLocation)\n const previousLocation = info?.versionsLocation || info?.historyLocation || \"\"\n\n updateMutation.mutate({\n project_id: projectId,\n container: container.name,\n metadata: metadataToSet,\n removeMetadata: removeMetadata.length ? removeMetadata : undefined,\n quotaBytes: quotaBytes !== \"\" ? Number(quotaBytes) : undefined,\n quotaCount: quotaCount !== \"\" ? Number(quotaCount) : undefined,\n // Enable versioning with selected container, update if location changed, or remove if disabled\n versionsLocation:\n versionsEnabled && (!wasVersioned || versionsLocation !== previousLocation) && versionsLocation\n ? versionsLocation\n : undefined,\n removeVersionsLocation: !versionsEnabled && wasVersioned ? true : undefined,\n })\n }\n\n const handleClose = () => {\n resetForm()\n onClose()\n }\n\n if (!isOpen || !container) return null\n\n const isBusy = isLoading || updateMutation.isPending\n const isMetaFailed = isMetaError && !isLoading\n const hasEditing = metadata.some((e) => e.isEditing)\n\n const initialQuotaBytes = info?.quotaBytes != null ? String(info.quotaBytes) : \"\"\n const initialQuotaCount = info?.quotaCount != null ? String(info.quotaCount) : \"\"\n const initialVersionsEnabled = !!info?.versionsEnabled\n const initialVersionsLocation = info?.versionsLocation || info?.historyLocation || \"\"\n const initialWebIndex = info?.metadata?.[\"web-index\"] ?? \"\"\n const initialWebListings = info?.metadata?.[\"web-listings\"] === \"1\" || info?.metadata?.[\"web-listings\"] === \"true\"\n const initialMetadataKeys = Object.keys(info?.metadata ?? {}).filter((k) => !RESERVED_META_KEYS.has(k))\n\n const metadataUnchanged =\n metadata.length === initialMetadataKeys.length &&\n metadata.every((e) => !e.isNew && e.key === e.originalKey && e.value === e.originalValue)\n\n const isUnchanged =\n quotaBytes === initialQuotaBytes &&\n quotaCount === initialQuotaCount &&\n versionsEnabled === initialVersionsEnabled &&\n versionsLocation === initialVersionsLocation &&\n webIndex === initialWebIndex &&\n webListings === initialWebListings &&\n metadataUnchanged\n\n // ── Render ────────────────────────────────────────────────────────────────\n const displayedQuotaBytes = info?.quotaBytes != null ? `${info.quotaBytes} B` : null\n\n return (\n <Modal\n title={\n <span className=\"flex max-w-125 items-center gap-2\">\n <span className=\"shrink-0\">\n <Trans>Container:</Trans>\n </span>\n <span className=\"truncate\" title={container.name}>\n {container.name}\n </span>\n </span>\n }\n open={isOpen}\n onCancel={handleClose}\n confirmButtonLabel={t`Save`}\n onConfirm={handleSubmit}\n cancelButtonLabel={t`Cancel`}\n size=\"large\"\n disableConfirmButton={isBusy || isAddingNew || hasEditing || isUnchanged || isMetaFailed}\n >\n {updateMutation.isError && (\n <p className=\"text-theme-error mb-4\">\n {(() => {\n const errorMessage = updateMutation.error.message\n return <Trans>Failed to update container: {errorMessage}</Trans>\n })()}\n </p>\n )}\n {isLoading ? (\n <Status status=\"progress\" title={t`Loading Container Properties...`} className=\"mt-0\" />\n ) : isMetaFailed ? (\n <Status\n status=\"error\"\n title={t`Failed to Load Container Properties`}\n body={metaError?.message ?? t`Unknown Error`}\n className=\"mt-0\"\n />\n ) : (\n <div className=\"max-h-[65vh] overflow-y-auto pr-1 pl-1\">\n <Stack direction=\"vertical\" gap=\"6\">\n {/* ── Read-only stats ─────────────────────────────────────────── */}\n <div className=\"grid grid-cols-2 gap-4\">\n <TextInput label={t`Object count`} value={String(container.count)} disabled readOnly />\n <TextInput\n label={t`Total size`}\n value={\n info?.bytesUsed != null\n ? `${info.bytesUsed.toLocaleString()} B`\n : `${container.bytes.toLocaleString()} B`\n }\n disabled\n readOnly\n />\n </div>\n\n {/* ── Quotas ──────────────────────────────────────────────────── */}\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <TextInput\n label={t`Object count quota`}\n value={quotaCount}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) => {\n setQuotaCount(e.target.value)\n if (quotaCountError) setQuotaCountError(null)\n }}\n placeholder={t`No limit`}\n invalid={!!quotaCountError}\n errortext={quotaCountError ?? undefined}\n disabled={isBusy}\n />\n </div>\n <div>\n <TextInput\n label={t`Total size quota`}\n value={quotaBytes}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) => {\n setQuotaBytes(e.target.value)\n if (quotaBytesError) setQuotaBytesError(null)\n }}\n placeholder={t`No limit`}\n invalid={!!quotaBytesError}\n errortext={quotaBytesError ?? undefined}\n disabled={isBusy}\n helptext={quotaBytes && displayedQuotaBytes ? displayedQuotaBytes : undefined}\n />\n </div>\n </div>\n\n {/* ── Public URL ──────────────────────────────────────────────── */}\n {isPublicAccess && publicUrl && (\n <div>\n <p className=\"text-theme-default mb-1 text-sm font-semibold\">\n <Trans>URL for public access</Trans>{\" \"}\n <a\n href={publicUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"text-theme-info text-xs font-normal underline\"\n >\n <Trans>Open in new tab</Trans>\n </a>\n </p>\n <TextInput value={publicUrl} disabled readOnly />\n </div>\n )}\n\n {/* ── Static website serving ───────────────────────────────────── */}\n <div>\n <p className=\"text-theme-default mb-3 text-sm font-semibold\">\n <Trans>Static website serving</Trans>\n </p>\n {isPublicAccess ? (\n <Stack direction=\"vertical\" gap=\"4\">\n <Stack direction=\"vertical\" gap=\"1\">\n <Checkbox\n label={t`Serve objects as index when file name is:`}\n checked={!!webIndex}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) => {\n if (!e.target.checked) setWebIndex(\"\")\n else if (!webIndex) setWebIndex(\"index.html\")\n }}\n disabled={isBusy}\n />\n <div className=\"pl-6\">\n <TextInput\n value={webIndex}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) => setWebIndex(e.target.value)}\n placeholder=\"index.html\"\n disabled={isBusy || !webIndex}\n className=\"flex-1\"\n />\n </div>\n </Stack>\n <Stack direction=\"horizontal\" alignment=\"start\" gap=\"2\">\n <Checkbox\n label={t`Enable file listing`}\n checked={webListings}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) => setWebListings(e.target.checked)}\n disabled={isBusy}\n />\n <Tooltip triggerEvent=\"hover\">\n <TooltipTrigger>\n <Icon icon=\"help\" size=\"16\" className=\"text-theme-light cursor-help\" />\n </TooltipTrigger>\n <TooltipContent className=\"z-10 max-w-55\">\n <Trans>If there is no index file, the URL displays a list of objects in the container.</Trans>\n </TooltipContent>\n </Tooltip>\n </Stack>\n </Stack>\n ) : (\n <p className=\"text-theme-default text-sm\">\n <Trans>\n Public read access is not enabled. Before configuring static website serving, go to{\" \"}\n <strong>Manage Access</strong> and enable public read access.\n </Trans>\n </p>\n )}\n </div>\n\n {/* ── Object versioning ────────────────────────────────────────── */}\n <div>\n <p className=\"text-theme-default mb-2 text-sm font-semibold\">\n <Trans>Object versioning</Trans>\n </p>\n\n {/* Case 1: server-side versioning active, no user changes yet */}\n {initialVersionsEnabled && !versionsLocation ? (\n <Checkbox\n label={t`Versioning is enabled`}\n checked\n onChange={(e: React.ChangeEvent<HTMLInputElement>) => {\n if (!e.target.checked) {\n setVersionsEnabled(false)\n setVersionsLocation(\"\")\n setContainerSearch(\"\")\n setDebouncedSearch(\"\")\n }\n }}\n disabled={true}\n />\n ) : !versionsEnabled && !versionsLocation ? (\n /* Case 2: nothing enabled, nothing selected */\n <Checkbox\n label={t`Store old object versions`}\n checked={false}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) => setVersionsEnabled(e.target.checked)}\n disabled={isBusy}\n />\n ) : (\n /* Case 3: checkbox checked or a container is selected */\n <Stack direction=\"vertical\" gap=\"1\">\n <Checkbox\n label={t`Store old object versions in container:`}\n checked={versionsEnabled}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) => {\n setVersionsEnabled(e.target.checked)\n if (!e.target.checked) {\n setVersionsLocation(\"\")\n setContainerSearch(\"\")\n setDebouncedSearch(\"\")\n }\n }}\n disabled={isBusy}\n />\n {versionsEnabled && (\n <div className=\"pl-6\">\n <ComboBox\n value={versionsLocation}\n onChange={(value: string) => setVersionsLocation(value)}\n onInputChange={handleContainerSearch}\n placeholder={t`Type to search containers...`}\n helptext={(() => {\n if (containerSearch.trim().length === 0) return t`Start typing to search for a container`\n if (hiddenCount > 0) {\n const maxOptions = MAX_COMBO_OPTIONS\n const totalCount = filteredContainers.length\n return t`Showing first ${maxOptions} of ${totalCount} — refine your search to narrow results`\n }\n return undefined\n })()}\n disabled={isBusy}\n >\n {visibleContainers.map((c) => (\n <ComboBoxOption key={c.name} value={c.name}>\n {c.name}\n </ComboBoxOption>\n ))}\n </ComboBox>\n </div>\n )}\n </Stack>\n )}\n </div>\n\n {/* ── Custom Metadata ──────────────────────────────────────────── */}\n <div>\n <Stack direction=\"horizontal\" alignment=\"center\" distribution=\"between\" className=\"mb-3\">\n <p className=\"text-theme-default text-sm font-semibold\">\n <Trans>Metadata</Trans>\n </p>\n <p className=\"text-theme-light text-xs\">\n <Trans>Reserved keys: web-index, web-listings, quota-count, quota-bytes</Trans>\n </p>\n </Stack>\n\n {/* Add Property button */}\n <Stack direction=\"horizontal\" className=\"jn:bg-theme-background-lvl-1 justify-end p-2\">\n <Button\n label={t`Add Property`}\n onClick={() => setIsAddingNew(true)}\n variant=\"primary\"\n icon=\"addCircle\"\n size=\"small\"\n disabled={isAddingNew || hasEditing || isBusy}\n />\n </Stack>\n\n <DataGrid columns={3}>\n <DataGridRow>\n <DataGridHeadCell>\n <Trans>Key</Trans>\n </DataGridHeadCell>\n <DataGridHeadCell>\n <Trans>Value</Trans>\n </DataGridHeadCell>\n <DataGridHeadCell>\n <Trans>Actions</Trans>\n </DataGridHeadCell>\n </DataGridRow>\n\n {/* New row input */}\n {isAddingNew && (\n <DataGridRow>\n <DataGridCell>\n <TextInput\n value={newKey}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) => {\n setNewKey(e.target.value)\n if (newKeyError) setNewKeyError(null)\n }}\n placeholder={t`property_key`}\n errortext={newKeyError ?? undefined}\n invalid={!!newKeyError}\n autoFocus\n />\n </DataGridCell>\n <DataGridCell>\n <TextInput\n value={newValue}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) => {\n setNewValue(e.target.value)\n if (newValueError) setNewValueError(null)\n }}\n placeholder={t`Value`}\n errortext={newValueError ?? undefined}\n invalid={!!newValueError}\n />\n </DataGridCell>\n <DataGridCell>\n <Stack direction=\"horizontal\" gap=\"2\">\n <Button size=\"small\" variant=\"primary\" onClick={handleAddNew} icon=\"check\" title={t`Save`} />\n <Button\n size=\"small\"\n variant=\"subdued\"\n onClick={handleCancelAdd}\n icon=\"close\"\n title={t`Discard`}\n />\n </Stack>\n </DataGridCell>\n </DataGridRow>\n )}\n\n {/* Existing metadata rows */}\n {metadata.map((entry, index) => (\n <DataGridRow key={index}>\n <DataGridCell>\n {entry.isEditing ? (\n <TextInput\n value={entry.key}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) => handleKeyChange(index, e.target.value)}\n errortext={metaErrors[`edit-${index}`]}\n invalid={!!metaErrors[`edit-${index}`]}\n />\n ) : (\n <span className=\"block max-w-xs truncate text-sm\" title={entry.key}>\n {entry.key}\n </span>\n )}\n </DataGridCell>\n <DataGridCell>\n {entry.isEditing ? (\n <TextInput\n value={entry.value}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) =>\n handleValueChange(index, e.target.value)\n }\n />\n ) : (\n <span className=\"block max-w-md truncate text-sm\" title={entry.value}>\n {entry.value}\n </span>\n )}\n </DataGridCell>\n <DataGridCell>\n {entry.isEditing ? (\n <Stack direction=\"horizontal\" gap=\"2\">\n <Button\n size=\"small\"\n variant=\"primary\"\n onClick={() => handleSaveEdit(index)}\n icon=\"check\"\n title={t`Save`}\n />\n <Button\n size=\"small\"\n variant=\"subdued\"\n onClick={() => handleCancelEdit(index)}\n icon=\"close\"\n title={t`Discard`}\n />\n </Stack>\n ) : (\n <Stack direction=\"horizontal\" gap=\"2\">\n <Button\n size=\"small\"\n variant=\"subdued\"\n onClick={() => handleEdit(index)}\n icon=\"edit\"\n title={t`Edit`}\n disabled={isAddingNew || hasEditing || isBusy}\n />\n <Button\n size=\"small\"\n variant=\"default\"\n onClick={() => handleDeleteMeta(index)}\n icon=\"deleteForever\"\n title={t`Delete`}\n disabled={isAddingNew || hasEditing || isBusy}\n />\n </Stack>\n )}\n </DataGridCell>\n </DataGridRow>\n ))}\n\n {/* Empty state */}\n {metadata.length === 0 && !isAddingNew && (\n <DataGridRow>\n <DataGridCell colSpan={3} className=\"py-6 text-center\">\n <Stack alignment=\"center\">\n <span className=\"text-theme-light text-sm\">\n <Trans>No custom metadata. Click \"Add Property\" to create one.</Trans>\n </span>\n </Stack>\n </DataGridCell>\n </DataGridRow>\n )}\n </DataGrid>\n </div>\n </Stack>\n </div>\n )}\n </Modal>\n )\n}\n","import { z } from \"zod\"\nimport { useForm, useStore } from \"@tanstack/react-form\"\nimport { useRef } from \"react\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport {\n Modal,\n ModalFooter,\n Button,\n ButtonRow,\n Form,\n FormSection,\n TextInput,\n Stack,\n Status,\n} from \"@cloudoperators/juno-ui-components\"\nimport { ContainerSummary, ObjectSummary } from \"@/server/Storage/types/swift\"\nimport { useModalTracking } from \"@/client/hooks/useModalTracking\"\n\ninterface EmptyContainerModalProps {\n isOpen: boolean\n container: ContainerSummary | null\n onClose: () => void\n onSuccess?: (containerName: string, deletedCount: number) => void\n onError?: (containerName: string, errorMessage: string) => void\n}\n\nexport const EmptyContainerModal = ({ isOpen, container, onClose, onSuccess, onError }: EmptyContainerModalProps) => {\n const { t } = useLingui()\n const projectId = useProjectId()\n const containerNameRef = useRef(\"\")\n\n const { trackClose, markSubmitted, resetTracking } = useModalTracking({\n isOpen,\n actionPrefix: \"storage.swift.container.empty\",\n })\n\n const formSchema = z.object({\n confirm: z.string().refine((value) => value === \"empty\", {\n message: t`Type \"empty\" 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 (!container || emptyContainerMutation.isPending) return\n\n containerNameRef.current = container.name\n markSubmitted()\n emptyContainerMutation.mutate({ project_id: projectId, container: container.name })\n },\n })\n\n const canEmpty = useStore(form.store, (state) => state.isSubmitting || state.values.confirm !== \"empty\")\n\n const utils = trpcReact.useUtils()\n\n // Fetch actual objects to get accurate real-time state —\n // container.count can lag due to Swift eventual consistency\n const {\n data: objects,\n isLoading: isLoadingObjects,\n error: objectsError,\n } = trpcReact.storage.swift.listObjects.useQuery(\n { project_id: projectId, container: container?.name ?? \"\", format: \"json\", limit: 100 },\n { enabled: isOpen && container !== null }\n )\n\n const emptyContainerMutation = trpcReact.storage.swift.emptyContainer.useMutation({\n onSuccess: (deletedCount) => {\n utils.storage.swift.listContainers.invalidate()\n utils.storage.swift.listObjects.invalidate({ project_id: projectId, container: containerNameRef.current })\n onSuccess?.(containerNameRef.current, deletedCount)\n },\n onError: (error) => {\n onError?.(containerNameRef.current, error.message)\n },\n onSettled: () => {\n handleClose()\n },\n })\n\n const handleClose = () => {\n trackClose()\n form.reset()\n emptyContainerMutation.reset()\n resetTracking()\n onClose()\n }\n\n if (!isOpen || !container) return null\n\n const actualObjectCount = objects?.length ?? 0\n\n // ── Case 2: container.count === 0 and listed objects === 0 ────────────────\n // Container is genuinely empty\n const isTrulyEmpty = !isLoadingObjects && container.count === 0 && actualObjectCount === 0\n\n // ── Case 3: container.count > 0 but listed objects === 0 ──────────────────\n // Swift eventual consistency delay — metadata not yet synced after recent delete\n const isConsistencyDelay = !isLoadingObjects && container.count > 0 && actualObjectCount === 0\n\n const showEmptyInfo = isTrulyEmpty || isConsistencyDelay\n\n const modalTitle = (\n <span className=\"flex max-w-100 items-center gap-2\">\n <span className=\"shrink-0\">\n <Trans>Empty:</Trans>\n </span>\n <span className=\"truncate\" title={container.name}>\n {container.name}\n </span>\n </span>\n )\n\n return (\n <Modal\n title={modalTitle}\n open={isOpen}\n onCancel={handleClose}\n confirmButtonLabel={showEmptyInfo ? undefined : t`Empty Container`}\n confirmButtonVariant=\"primary-danger\"\n onConfirm={showEmptyInfo ? undefined : form.handleSubmit}\n cancelButtonLabel={showEmptyInfo ? undefined : t`Cancel`}\n modalFooter={\n showEmptyInfo ? (\n <ModalFooter className=\"flex justify-end\">\n <ButtonRow>\n <Button variant=\"primary\" onClick={handleClose} data-testid=\"empty-info-close-button\">\n <Trans>Close</Trans>\n </Button>\n </ButtonRow>\n </ModalFooter>\n ) : undefined\n }\n size=\"large\"\n disableConfirmButton={isLoadingObjects || emptyContainerMutation.isPending || (!showEmptyInfo && canEmpty)}\n >\n {objectsError && (\n <p className=\"text-theme-error mb-4\">\n {(() => {\n const errorMessage = objectsError.message\n return <Trans>Failed to Load Container Objects: {errorMessage}</Trans>\n })()}\n </p>\n )}\n {isLoadingObjects ? (\n <Status status=\"progress\" title={t`Loading Objects...`} className=\"mt-0\" />\n ) : showEmptyInfo && !objectsError ? (\n // ── Case 2 & 3 ──────────────────────────────────────────────────────\n <p className=\"text-theme-default py-2\">\n {isTrulyEmpty ? (\n <Trans>This container is already empty.</Trans>\n ) : (\n <Trans>\n This container appears empty — the object count may not have synced yet due to a recent operation.\n </Trans>\n )}\n </p>\n ) : !objectsError ? (\n // ── Case 1: container has objects ────────────────────────────────────\n <Stack direction=\"vertical\" gap=\"6\">\n <p className=\"text-theme-default\">\n <Trans>\n This action is permanent. All objects in the container will be deleted and this cannot be undone.\n </Trans>\n <br />\n <Trans>\n <strong>Please note:</strong> for <strong>dynamic</strong> and <strong>static large objects</strong> only\n the manifests will be deleted. The related segments will not be deleted.\n </Trans>\n </p>\n\n {/* Object list preview — capped at first 100 */}\n <div>\n <p className=\"text-sm font-semibold\">\n <Trans>Objects to delete:</Trans>\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 {(objects as ObjectSummary[]).map((obj) => (\n <div key={obj.name} className=\"text-theme-default overflow-x-hidden text-sm wrap-anywhere\">\n {obj.name}\n </div>\n ))}\n {container.count > actualObjectCount && (\n <div className=\"text-theme-light pt-2 text-sm\">\n {(() => {\n const shown = actualObjectCount\n const total = container.count\n return (\n <Trans>\n Showing first {shown} of {total} objects\n </Trans>\n )\n })()}\n </div>\n )}\n </Stack>\n </div>\n </div>\n\n <Form\n className=\"mb-0\"\n id=\"empty-container-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 id={field.name}\n name={field.name}\n label={t`Type \"empty\" to confirm`}\n required\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(\", \") ||\n undefined\n }\n disabled={emptyContainerMutation.isPending}\n autoFocus\n placeholder=\"empty\"\n />\n )}\n />\n </FormSection>\n </Form>\n </Stack>\n ) : null}\n </Modal>\n )\n}\n","import { z } from \"zod\"\nimport { useForm, useStore } from \"@tanstack/react-form\"\nimport { useState, useEffect } from \"react\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { Modal, Form, FormSection, TextInput, Stack, Status, Checkbox } from \"@cloudoperators/juno-ui-components\"\nimport { ContainerSummary } from \"@/server/Storage/types/swift\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport { useModalTracking } from \"@/client/hooks/useModalTracking\"\n\ninterface DeleteContainerModalProps {\n isOpen: boolean\n container: ContainerSummary | null\n onClose: () => void\n onSuccess?: (containerName: string) => void\n onError?: (containerName: string, errorMessage: string) => void\n}\n\nexport const DeleteContainerModal = ({ isOpen, container, onClose, onSuccess, onError }: DeleteContainerModalProps) => {\n const { t } = useLingui()\n const projectId = useProjectId()\n const [versionsConfirmed, setVersionsConfirmed] = useState(false)\n\n const { trackClose, markSubmitted, resetTracking } = useModalTracking({\n isOpen,\n actionPrefix: \"storage.swift.container.delete\",\n })\n\n const formSchema = z.object({\n confirm: z.string().refine((value) => value === \"delete\", {\n message: t`The text must match \"delete\"`,\n }),\n })\n\n const form = useForm({\n defaultValues: {\n confirm: \"\",\n },\n validators: {\n onSubmit: formSchema,\n },\n onSubmit: async () => {\n if (!container || objectsError || metaError || deleteContainerMutation.isPending) return\n if (isVersioned && !versionsConfirmed) return\n\n markSubmitted()\n deleteContainerMutation.mutate({ project_id: projectId, container: container.name })\n },\n })\n\n const canDelete = useStore(form.store, (state) => state.isSubmitting || state.values.confirm !== \"delete\")\n\n const utils = trpcReact.useUtils()\n\n // Fetch actual objects to get accurate real-time state —\n // container.count can lag due to Swift eventual consistency\n const {\n data: objects,\n isLoading: isLoadingObjects,\n error: objectsError,\n } = trpcReact.storage.swift.listObjects.useQuery(\n { project_id: projectId, container: container?.name ?? \"\", format: \"json\", limit: 1 },\n { enabled: isOpen && container !== null }\n )\n\n // Fetch container metadata to check if versioning is enabled\n const { data: containerMetadata, error: metaError } = trpcReact.storage.swift.getContainerMetadata.useQuery(\n { project_id: projectId, container: container?.name ?? \"\" },\n { enabled: isOpen && container !== null }\n )\n\n // Swift versioning v2: x-versions-enabled header; v1: x-versions-location / x-history-location\n const isVersioned = !!(\n containerMetadata?.versionsEnabled ||\n containerMetadata?.versionsLocation ||\n containerMetadata?.historyLocation\n )\n\n const deleteContainerMutation = trpcReact.storage.swift.deleteContainer.useMutation({\n onSuccess: () => {\n utils.storage.swift.listContainers.invalidate()\n onSuccess?.(container!.name)\n },\n onError: (error) => {\n onError?.(container!.name, error.message)\n },\n onSettled: () => {\n handleClose()\n },\n })\n\n useEffect(() => {\n if (!isOpen) {\n setVersionsConfirmed(false)\n deleteContainerMutation.reset()\n form.reset()\n resetTracking()\n }\n }, [isOpen, container?.name, resetTracking])\n\n const handleClose = () => {\n trackClose()\n setVersionsConfirmed(false)\n deleteContainerMutation.reset()\n onClose()\n }\n\n if (!isOpen || !container) return null\n\n const actualObjectCount = objects?.length ?? 0\n\n // Container has objects — cannot delete, must empty first.\n // Also covers the Swift consistency delay where count > 0 but listed objects === 0:\n // we trust container.count here to avoid letting the user delete a non-empty container.\n const hasObjects = !isLoadingObjects && (actualObjectCount > 0 || container.count > 0)\n // Swift eventual consistency — count > 0 but listing returned 0 objects,\n // likely because a recent empty/delete hasn't propagated yet.\n const isConsistencyDelay = !isLoadingObjects && container.count > 0 && actualObjectCount === 0\n const hasPreflightError = !!(objectsError || metaError)\n\n const modalTitle = (\n <span className=\"flex max-w-100 items-center gap-2\">\n <span className=\"shrink-0\">\n <Trans>Delete container:</Trans>\n </span>\n <span className=\"truncate\" title={container.name}>\n {container.name}\n </span>\n </span>\n )\n\n return (\n <Modal\n title={modalTitle}\n open={isOpen}\n onCancel={handleClose}\n confirmButtonLabel={hasObjects ? t`Close` : t`Delete Container`}\n confirmButtonVariant={hasObjects ? \"primary\" : \"primary-danger\"}\n onConfirm={hasObjects ? handleClose : form.handleSubmit}\n cancelButtonLabel={hasObjects ? undefined : t`Cancel`}\n size=\"small\"\n disableConfirmButton={\n isLoadingObjects ||\n hasPreflightError ||\n deleteContainerMutation.isPending ||\n (!hasObjects && canDelete) ||\n (!hasObjects && isVersioned && !versionsConfirmed)\n }\n >\n {(objectsError || metaError) && (\n <Stack direction=\"vertical\" gap=\"2\" className=\"mb-4\" role=\"alert\" aria-live=\"assertive\">\n {objectsError && (\n <p className=\"text-theme-error\">\n {(() => {\n const errorMessage = objectsError.message\n return <Trans>Failed to Load Container Objects: {errorMessage}</Trans>\n })()}\n </p>\n )}\n {metaError && (\n <p className=\"text-theme-error\">\n {(() => {\n const errorMessage = metaError.message\n return <Trans>Failed to Load Container Properties: {errorMessage}</Trans>\n })()}\n </p>\n )}\n </Stack>\n )}\n {isLoadingObjects ? (\n <Status status=\"progress\" title={t`Loading...`} className=\"mt-0\" />\n ) : hasObjects ? (\n // ── Container has objects — block deletion ───────────────────────────\n <Stack direction=\"vertical\" gap=\"3\">\n <p className=\"text-theme-default\">\n <Trans>The container cannot be deleted as it contains objects. Empty the container first.</Trans>\n </p>\n {isConsistencyDelay && (\n <p className=\"text-theme-default\">\n <Trans>\n The container metadata reports objects but none were listed. This may be a temporary synchronization\n delay — please wait a moment and try again.\n </Trans>\n </p>\n )}\n </Stack>\n ) : (\n // ── Container is empty — allow deletion ──────────────────────────────\n <Stack direction=\"vertical\" gap=\"6\">\n <p className=\"text-theme-default\">\n <Trans>The container will be deleted. This action is permanent and cannot be undone.</Trans>\n <br />\n <Trans>\n To confirm type <strong>delete</strong> in the field below.\n </Trans>\n </p>\n {isVersioned && (\n <Checkbox\n label={t`I confirm that all existing versions will also be deleted`}\n checked={versionsConfirmed}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) => setVersionsConfirmed(e.target.checked)}\n />\n )}\n <Form\n className=\"mb-0\"\n id=\"delete-container-form\"\n onSubmit={(e) => {\n e.preventDefault()\n form.handleSubmit()\n }}\n >\n <FormSection>\n <form.Field\n name=\"confirm\"\n validators={{\n onSubmit: ({ value }) => {\n if (value !== \"delete\") {\n return t`The text must match \"delete\"`\n }\n return undefined\n },\n }}\n children={(field) => (\n <TextInput\n label={t`Type \"delete\" to confirm`}\n required\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}\n errortext={\n field.state.meta.errors.map((e) => (typeof e === \"string\" ? e : e?.message)).join(\", \") ||\n undefined\n }\n disabled={deleteContainerMutation.isPending}\n autoFocus\n placeholder=\"delete\"\n />\n )}\n />\n </FormSection>\n </Form>\n </Stack>\n )}\n </Modal>\n )\n}\n","import { ReactNode } from \"react\"\nimport { NotificationOptions, Stack } from \"@cloudoperators/juno-ui-components\"\nimport { Trans, Plural } from \"@lingui/react/macro\"\n\nexport const getContainerCreatedToast = (containerName: string): { message: ReactNode } & NotificationOptions => ({\n message: <Trans>Container Created</Trans>,\n description: <Trans>Container \"{containerName}\" was successfully created.</Trans>,\n})\n\nexport const getContainerCreatedWithWarningToast = (\n containerName: string,\n reason: string\n): { message: ReactNode } & NotificationOptions => ({\n message: <Trans>Container Created with Warnings</Trans>,\n description: (\n <Trans>\n Container \"{containerName}\" was created, but its settings could not be applied: {reason}\n </Trans>\n ),\n})\n\nexport const getContainerEmptiedToast = (\n containerName: string,\n deletedCount: number\n): { message: ReactNode } & NotificationOptions => ({\n message: <Trans>Container Emptied</Trans>,\n description:\n deletedCount === 0 ? (\n <Trans>Container \"{containerName}\" was already empty.</Trans>\n ) : deletedCount === 1 ? (\n <Trans>\n Container \"{containerName}\" was successfully emptied. {deletedCount} object deleted.\n </Trans>\n ) : (\n <Trans>\n Container \"{containerName}\" was successfully emptied. {deletedCount} objects deleted.\n </Trans>\n ),\n})\n\nexport const getContainerEmptyErrorToast = (\n containerName: string,\n errorMessage: string\n): { message: ReactNode } & NotificationOptions => ({\n message: <Trans>Failed to Empty Container</Trans>,\n description: (\n <Trans>\n Could not empty container \"{containerName}\": {errorMessage}\n </Trans>\n ),\n})\n\nexport const getContainerDeletedToast = (containerName: string): { message: ReactNode } & NotificationOptions => ({\n message: <Trans>Container Deleted</Trans>,\n description: <Trans>Container \"{containerName}\" was successfully deleted.</Trans>,\n})\n\nexport const getContainerDeleteErrorToast = (\n containerName: string,\n errorMessage: string\n): { message: ReactNode } & NotificationOptions => ({\n message: <Trans>Failed to Delete Container</Trans>,\n description: (\n <Trans>\n Could not delete container \"{containerName}\": {errorMessage}\n </Trans>\n ),\n})\n\nexport const getContainerUpdatedToast = (containerName: string): { message: ReactNode } & NotificationOptions => ({\n message: <Trans>Container Updated</Trans>,\n description: <Trans>Container \"{containerName}\" properties were successfully updated.</Trans>,\n})\n\nexport const getContainerUpdateErrorToast = (\n containerName: string,\n errorMessage: string\n): { message: ReactNode } & NotificationOptions => ({\n message: <Trans>Failed to Update Container</Trans>,\n description: (\n <Trans>\n Could not update container \"{containerName}\": {errorMessage}\n </Trans>\n ),\n})\n\nexport const getContainerAclUpdatedToast = (containerName: string): { message: ReactNode } & NotificationOptions => ({\n message: <Trans>Access Control Updated</Trans>,\n description: <Trans>ACLs for container \"{containerName}\" were successfully updated.</Trans>,\n})\n\nexport const getContainerAclUpdateErrorToast = (\n containerName: string,\n errorMessage: string\n): { message: ReactNode } & NotificationOptions => ({\n message: <Trans>Failed to Update Access Control</Trans>,\n description: (\n <Trans>\n Could not update ACLs for container \"{containerName}\": {errorMessage}\n </Trans>\n ),\n})\n\nexport const getContainersEmptiedToast = (\n emptiedCount: number,\n totalDeleted: number\n): { message: ReactNode } & NotificationOptions => ({\n message: <Trans>Containers Emptied</Trans>,\n description:\n totalDeleted === 0 ? (\n <Plural value={emptiedCount} one=\"# container was already empty.\" other=\"# containers were already empty.\" />\n ) : (\n <Trans>\n <Plural value={emptiedCount} one=\"# container\" other=\"# containers\" /> successfully emptied.{\" \"}\n <Plural value={totalDeleted} one=\"# object\" other=\"# objects\" /> deleted in total.\n </Trans>\n ),\n})\n\nexport const getContainersEmptyErrorToast = (errorMessage: string): { message: ReactNode } & NotificationOptions => ({\n message: <Trans>Failed to Empty Containers</Trans>,\n description: (\n <span className=\"whitespace-pre-line\">\n <Trans>One or more containers could not be emptied: {errorMessage}</Trans>\n </span>\n ),\n})\n\nexport type NotificationSeverity = \"success\" | \"warning\" | \"error\"\n\nexport const getContainersEmptyCompleteToast = (\n emptiedCount: number,\n totalDeleted: number,\n errors: string[]\n): { message: ReactNode; severity: NotificationSeverity } & NotificationOptions => {\n const hasErrors = errors.length > 0\n const hasSuccess = emptiedCount > 0\n const isPartial = hasErrors && hasSuccess\n\n return {\n // Severity is derived here alongside the title so the two never drift; the\n // caller dispatches toast.success / warning / error off this single value.\n severity: isPartial ? \"warning\" : hasErrors ? \"error\" : \"success\",\n message: isPartial ? (\n <Trans>Containers Partially Emptied</Trans>\n ) : hasErrors ? (\n <Trans>Failed to Empty Containers</Trans>\n ) : (\n <Trans>Containers Emptied</Trans>\n ),\n description: (\n <Stack direction=\"vertical\" gap=\"1\">\n {hasSuccess && (\n <span>\n <Trans>\n <Plural value={emptiedCount} one=\"# container\" other=\"# containers\" /> successfully emptied.{\" \"}\n <Plural value={totalDeleted} one=\"# object\" other=\"# objects\" /> deleted in total.\n </Trans>\n </span>\n )}\n {hasErrors && (\n <span className=\"whitespace-pre-line\">\n {(() => {\n const errorDetails = errors.join(\"\\n\")\n return <Trans>Failed: {errorDetails}</Trans>\n })()}\n </span>\n )}\n </Stack>\n ),\n }\n}\n","import { useState } from \"react\"\nimport { useNavigate, useParams } from \"@tanstack/react-router\"\nimport { useLingui } from \"@lingui/react/macro\"\nimport { toast, Status } from \"@cloudoperators/juno-ui-components\"\nimport { ContentHeader } from \"@/client/components/ContentHeader/ContentHeader\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport type { ContainerSummary } from \"@/server/Storage/types/swift\"\nimport { ContainerHeaderActions, type ContainerModalType } from \"./ContainerHeaderActions\"\nimport { ManageContainerAccessModal } from \"./ManageContainerAccessModal\"\nimport { EditContainerMetadataModal } from \"./EditContainerMetadataModal\"\nimport { EmptyContainerModal } from \"./EmptyContainerModal\"\nimport { DeleteContainerModal } from \"./DeleteContainerModal\"\nimport {\n getContainerAclUpdatedToast,\n getContainerAclUpdateErrorToast,\n getContainerUpdatedToast,\n getContainerEmptiedToast,\n getContainerEmptyErrorToast,\n getContainerDeletedToast,\n getContainerDeleteErrorToast,\n} from \"./ContainerToastNotifications\"\n\ninterface ContainerHeaderProps {\n containerName: string\n}\n\n/**\n * Container header component for the Swift in-container (objects) page.\n *\n * Mirrors Ceph's BucketHeader position/shape: a ContentHeader with the\n * container name and an overflow actions menu. Unlike BucketHeader, there\n * are no badges (Swift has no versioning/policy analog here) and no tabs.\n */\nexport const ContainerHeader = ({ containerName }: ContainerHeaderProps) => {\n const { projectId, provider, storageType } = useParams({\n from: \"/_auth/projects/$projectId/storage/$provider/$storageType/$containerName/objects/\",\n })\n const navigate = useNavigate()\n const { t } = useLingui()\n\n const [activeModal, setActiveModal] = useState<ContainerModalType | null>(null)\n const closeModal = () => setActiveModal(null)\n\n // The four modals genuinely consume container.count / container.bytes\n // (DeleteContainerModal's non-empty guard, EmptyContainerModal's object-count\n // hint, EditContainerMetadataModal's read-only size/count display) - unlike\n // Ceph's modals, a placeholder { count: 0, bytes: 0 } is not safe here. So we\n // fetch a real summary via getContainerMetadata (one HEAD request) instead of\n // listing every container in the account. Keep the input exactly\n // { project_id, container } so this query shares its cache entry with the\n // identical queries the modals below issue.\n const { data: containerInfo, error: containerInfoError } = trpcReact.storage.swift.getContainerMetadata.useQuery(\n { project_id: projectId, container: containerName },\n { enabled: !!projectId && !!containerName }\n )\n\n const container: ContainerSummary | null = containerInfo\n ? { name: containerName, count: containerInfo.objectCount, bytes: containerInfo.bytesUsed }\n : null\n\n const handleAclSuccess = (containerName: string) => {\n const { message, ...options } = getContainerAclUpdatedToast(containerName)\n toast.success(message, options)\n }\n\n const handleAclError = (containerName: string, errorMessage: string) => {\n const { message, ...options } = getContainerAclUpdateErrorToast(containerName, errorMessage)\n toast.error(message, options)\n }\n\n const handlePropertiesSuccess = (containerName: string) => {\n const { message, ...options } = getContainerUpdatedToast(containerName)\n toast.success(message, options)\n }\n // No onError handler wired for EditContainerMetadataModal: the modal declares\n // the prop for API compatibility but never calls it - update errors are shown\n // inline in the modal (see #1162 / #1191), not via toast.\n\n const handleEmptySuccess = (containerName: string, deletedCount: number) => {\n const { message, ...options } = getContainerEmptiedToast(containerName, deletedCount)\n toast.success(message, options)\n }\n\n const handleEmptyError = (containerName: string, errorMessage: string) => {\n const { message, ...options } = getContainerEmptyErrorToast(containerName, errorMessage)\n toast.error(message, options)\n }\n\n const handleDeleteSuccess = (containerName: string) => {\n const { message, ...options } = getContainerDeletedToast(containerName)\n toast.success(message, options)\n // The container we were browsing no longer exists - navigate back to the\n // container list instead of leaving the user on a now-dead objects page.\n navigate({\n to: \"/projects/$projectId/storage/$provider/$storageType\",\n params: { projectId, provider, storageType },\n })\n }\n\n const handleDeleteError = (containerName: string, errorMessage: string) => {\n const { message, ...options } = getContainerDeleteErrorToast(containerName, errorMessage)\n toast.error(message, options)\n }\n\n return (\n <>\n <ContentHeader\n title={containerName}\n projectId={projectId}\n actions={container ? <ContainerHeaderActions onOpenModal={setActiveModal} /> : null}\n />\n\n {containerInfoError && (\n <Status\n status=\"error\"\n title={t`Failed to Load Container Information`}\n body={containerInfoError.message}\n className=\"mb-4\"\n />\n )}\n\n <ManageContainerAccessModal\n isOpen={activeModal === \"manageAccess\"}\n container={container}\n onClose={closeModal}\n onSuccess={handleAclSuccess}\n onError={handleAclError}\n />\n\n <EditContainerMetadataModal\n isOpen={activeModal === \"editMetadata\"}\n container={container}\n onClose={closeModal}\n onSuccess={handlePropertiesSuccess}\n />\n\n <EmptyContainerModal\n isOpen={activeModal === \"emptyContainer\"}\n container={container}\n onClose={closeModal}\n onSuccess={handleEmptySuccess}\n onError={handleEmptyError}\n />\n\n <DeleteContainerModal\n isOpen={activeModal === \"deleteContainer\"}\n container={container}\n onClose={closeModal}\n onSuccess={handleDeleteSuccess}\n onError={handleDeleteError}\n />\n </>\n )\n}\n","import { createFileRoute, useNavigate, useParams } from \"@tanstack/react-router\"\nimport { Button } from \"@cloudoperators/juno-ui-components\"\nimport { checkServiceAvailability } from \"../../../../-components/utils/serviceAvailability\"\nimport { ErrorBoundary } from \"react-error-boundary\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { SwiftObjects } from \"../../../../-components/Swift/Objects\"\nimport { CephObjects } from \"../../../../-components/Ceph/Objects\"\nimport { CephCorsRules, CephLifecycleRules } from \"../../../../-components/Ceph/Buckets\"\nimport { z } from \"zod\"\nimport type { RouteInfo } from \"@/client/routes/routeInfo\"\nimport { RouteIdLevelDefaultError } from \"@/client/components/Errors/RouteIdLevelDefaultError\"\nimport { BucketHeader } from \"../../../../-components/Ceph/Buckets/BucketHeader\"\nimport { ContainerHeader } from \"../../../../-components/Swift/Containers/ContainerHeader\"\nimport { useSetBreadcrumb } from \"@/client/hooks/useSetBreadcrumb\"\n\nfunction ObjectStorageErrorComponent() {\n const { t } = useLingui()\n const navigate = useNavigate()\n const { projectId, provider, storageType } = Route.useParams()\n const isCeph = provider === \"ceph\"\n\n return (\n <RouteIdLevelDefaultError\n action={\n <Button\n variant=\"primary\"\n onClick={() =>\n navigate({\n to: \"/projects/$projectId/storage/$provider/$storageType\",\n params: { projectId, provider, storageType },\n })\n }\n >\n {isCeph ? t`Back to Buckets` : t`Back to Containers`}\n </Button>\n }\n />\n )\n}\n\n// Search params schema\n// - prefix: base64-encoded current folder path, safe to carry \"/\" chars in the URL\n// - sortBy: active sort column key — persisted so deep links and back navigation restore sort state\n// Accepts both Swift keys (last_modified, bytes) and Ceph keys (lastModified, size) for compatibility\n// - sortDirection: \"asc\" | \"desc\" — persisted alongside sortBy\n// - view: tab selection for Ceph bucket details page (overview shows objects, cors-rules shows CORS config, lifecycle-rules shows lifecycle config)\n// - corsSortBy: active sort column for CORS rules tab (ID, AllowedOrigins, etc.) — separate from objects sortBy\n// - corsSortDirection: \"asc\" | \"desc\" for CORS rules — separate from objects sortDirection\n// - corsSearch: search term for filtering CORS rules by Rule ID — separate from objects search\n// - lifecycleSortBy: active sort column for lifecycle rules tab (ID, Status, Expiration) — separate from objects sortBy\n// - lifecycleSortDirection: \"asc\" | \"desc\" for lifecycle rules — separate from objects sortDirection\n// - lifecycleSearch: search term for filtering lifecycle rules by Rule ID — separate from objects search\nconst objectsSearchSchema = z.object({\n prefix: z.string().optional(),\n sortBy: z.enum([\"name\", \"last_modified\", \"bytes\", \"lastModified\", \"size\"]).optional().default(\"name\"),\n sortDirection: z.enum([\"asc\", \"desc\"]).optional().default(\"asc\"),\n search: z.string().optional(),\n tab: z.enum([\"all\", \"deleted\"]).optional().default(\"all\"),\n view: z.enum([\"overview\", \"cors-rules\", \"lifecycle-rules\"]).optional().default(\"overview\"),\n corsSortBy: z\n .enum([\"ID\", \"AllowedOrigins\", \"AllowedMethods\", \"AllowedHeaders\", \"ExposeHeaders\", \"MaxAgeSeconds\"])\n .optional()\n .default(\"ID\"),\n corsSortDirection: z.enum([\"asc\", \"desc\"]).optional().default(\"asc\"),\n corsSearch: z.string().optional(),\n lifecycleSortBy: z.enum([\"ID\", \"Status\", \"Expiration\"]).optional().default(\"ID\"),\n lifecycleSortDirection: z.enum([\"asc\", \"desc\"]).optional().default(\"asc\"),\n lifecycleSearch: z.string().optional(),\n})\n\nexport const Route = createFileRoute(\n \"/_auth/projects/$projectId/storage/$provider/$storageType/$containerName/objects/\"\n)({\n staticData: {\n section: \"storage\",\n service: \"containers\",\n analytics: {\n name: \"storage.objectstore.detail\",\n },\n } satisfies RouteInfo,\n validateSearch: objectsSearchSchema,\n head: ({ match }) => ({\n meta: [{ title: match.params.containerName }],\n }),\n component: () => {\n return <ObjectsDashboard />\n },\n notFoundComponent: ObjectStorageErrorComponent,\n errorComponent: ObjectStorageErrorComponent,\n loader: async ({ context }) => {\n const { trpcClient } = context\n const availableServices = await trpcClient?.auth.getAvailableServices.query()\n\n return {\n client: trpcClient,\n availableServices,\n }\n },\n beforeLoad: async ({ context, params }) => {\n const { trpcClient } = context\n const availableServices = await trpcClient?.auth.getAvailableServices.query()\n checkServiceAvailability(availableServices!, params)\n },\n})\n\nexport function ObjectsDashboard() {\n const { projectId, provider, containerName } = useParams({\n from: \"/_auth/projects/$projectId/storage/$provider/$storageType/$containerName/objects/\",\n select: (params) => ({\n projectId: params.projectId,\n provider: params.provider,\n containerName: params.containerName,\n }),\n })\n\n useSetBreadcrumb(Route.id, containerName)\n\n const { prefix, sortBy, sortDirection, search, view } = Route.useSearch()\n\n return (\n <>\n {provider === \"ceph\" && <BucketHeader bucketName={containerName} />}\n {provider === \"swift\" && <ContainerHeader containerName={containerName} />}\n {/* Ceph gets extra breathing room below its header from BucketHeader's own\n tabs block; Swift has no such block, so pad the content wrapper directly\n to avoid the overflow menu sitting too close to the toolbar below it. */}\n <div className={provider === \"swift\" ? \"pt-4\" : undefined}>\n {projectId ? (\n <ErrorBoundary\n resetKeys={[projectId, provider, containerName, prefix, sortBy, sortDirection, search, view]}\n fallback={\n <div className=\"p-4 text-center\">\n <Trans>Error loading component</Trans>\n </div>\n }\n >\n {(() => {\n switch (provider) {\n case \"swift\":\n return <SwiftObjects provider={provider} containerName={containerName} />\n case \"ceph\":\n if (view === \"lifecycle-rules\") {\n return <CephLifecycleRules bucketName={containerName} />\n }\n if (view === \"cors-rules\") {\n return <CephCorsRules bucketName={containerName} />\n }\n return <CephObjects bucketName={containerName} />\n default:\n return (\n <div className=\"p-4\">\n <Trans>Objects: {containerName}</Trans>\n </div>\n )\n }\n })()}\n </ErrorBoundary>\n ) : (\n <div className=\"p-4 text-center\">\n <Trans>No project selected</Trans>\n </div>\n )}\n </div>\n </>\n )\n}\n"],"mappings":"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"}
|