@cobaltcore-dev/aurora 0.7.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. package/README.md +101 -7
  2. package/dist/client/AuroraApp.d.ts +38 -0
  3. package/dist/client/{ContentHeader-kx1Th5Sq.mjs → ContentHeader-DqsGNvtD.mjs} +17 -17
  4. package/dist/client/{ContentHeader-kx1Th5Sq.mjs.map → ContentHeader-DqsGNvtD.mjs.map} +1 -1
  5. package/dist/client/{DeleteFlavorModal-C3cb7YiJ.mjs → DeleteFlavorModal-C3m7bQJu.mjs} +163 -163
  6. package/dist/client/{DeleteFlavorModal-C3cb7YiJ.mjs.map → DeleteFlavorModal-C3m7bQJu.mjs.map} +1 -1
  7. package/dist/client/{EditSecurityGroupModal-CpP54WIK.mjs → EditSecurityGroupModal-DKusxfta.mjs} +18 -18
  8. package/dist/client/{EditSecurityGroupModal-CpP54WIK.mjs.map → EditSecurityGroupModal-DKusxfta.mjs.map} +1 -1
  9. package/dist/client/{FiltersInput-DxcyR6Bp.mjs → FiltersInput-GzR4D0q6.mjs} +21 -21
  10. package/dist/client/{FiltersInput-DxcyR6Bp.mjs.map → FiltersInput-GzR4D0q6.mjs.map} +1 -1
  11. package/dist/client/{FloatingIpActionModals-BP8RWHbu.mjs → FloatingIpActionModals-CRvROJ3H.mjs} +51 -51
  12. package/dist/client/{FloatingIpActionModals-BP8RWHbu.mjs.map → FloatingIpActionModals-CRvROJ3H.mjs.map} +1 -1
  13. package/dist/client/{ImageToastNotifications-TZ3EfQg-.mjs → ImageToastNotifications-BuDXpTkl.mjs} +344 -344
  14. package/dist/client/{ImageToastNotifications-TZ3EfQg-.mjs.map → ImageToastNotifications-BuDXpTkl.mjs.map} +1 -1
  15. package/dist/client/{RouteError-QSV7qOoJ.mjs → RouteError-DVAiT0mT.mjs} +2 -2
  16. package/dist/client/{RouteError-QSV7qOoJ.mjs.map → RouteError-DVAiT0mT.mjs.map} +1 -1
  17. package/dist/client/{SortInput-CYv2_Pur.mjs → SortInput-VK7IYqQv.mjs} +6 -6
  18. package/dist/client/{SortInput-CYv2_Pur.mjs.map → SortInput-VK7IYqQv.mjs.map} +1 -1
  19. package/dist/client/{_flavorId-C2x43-6S.mjs → _flavorId-B9Vqkraj.mjs} +8 -8
  20. package/dist/client/{_flavorId-C2x43-6S.mjs.map → _flavorId-B9Vqkraj.mjs.map} +1 -1
  21. package/dist/client/{_flavorId-CR8ZUI-P.mjs → _flavorId-CFpNGz52.mjs} +62 -62
  22. package/dist/client/{_flavorId-CR8ZUI-P.mjs.map → _flavorId-CFpNGz52.mjs.map} +1 -1
  23. package/dist/client/{_floatingIpId-BCk41_Lb.mjs → _floatingIpId-B5GMSLeQ.mjs} +2 -2
  24. package/dist/client/{_floatingIpId-BCk41_Lb.mjs.map → _floatingIpId-B5GMSLeQ.mjs.map} +1 -1
  25. package/dist/client/{_floatingIpId-BGrOAmPT.mjs → _floatingIpId-C2-BeRmF.mjs} +27 -27
  26. package/dist/client/{_floatingIpId-BGrOAmPT.mjs.map → _floatingIpId-C2-BeRmF.mjs.map} +1 -1
  27. package/dist/client/_imageId-9NZytfNs.mjs +534 -0
  28. package/dist/client/{_imageId-CvfD832b.mjs.map → _imageId-9NZytfNs.mjs.map} +1 -1
  29. package/dist/client/_pcaId-BwTvJJgh.mjs +479 -0
  30. package/dist/client/_pcaId-BwTvJJgh.mjs.map +1 -0
  31. package/dist/client/{_pcaId-DOHycvCf.mjs → _pcaId-DUHQd0rB.mjs} +2 -2
  32. package/dist/client/{_pcaId-DOHycvCf.mjs.map → _pcaId-DUHQd0rB.mjs.map} +1 -1
  33. package/dist/client/{_projectId-DOgwFiqD.mjs → _projectId-B_2sZKk-.mjs} +2 -2
  34. package/dist/client/{_projectId-DOgwFiqD.mjs.map → _projectId-B_2sZKk-.mjs.map} +1 -1
  35. package/dist/client/{_projectId-MxcHrXW4.mjs → _projectId-CLgClx24.mjs} +3 -3
  36. package/dist/client/{_projectId-MxcHrXW4.mjs.map → _projectId-CLgClx24.mjs.map} +1 -1
  37. package/dist/client/_projectId-cW9aQ4Ag.mjs +271 -0
  38. package/dist/client/_projectId-cW9aQ4Ag.mjs.map +1 -0
  39. package/dist/client/{_securityGroupId-KKw4RPdH.mjs → _securityGroupId-DYxmXUOP.mjs} +319 -319
  40. package/dist/client/{_securityGroupId-KKw4RPdH.mjs.map → _securityGroupId-DYxmXUOP.mjs.map} +1 -1
  41. package/dist/client/{_securityGroupId-CJJanWiY.mjs → _securityGroupId-fhK1CuZh.mjs} +2 -2
  42. package/dist/client/{_securityGroupId-CJJanWiY.mjs.map → _securityGroupId-fhK1CuZh.mjs.map} +1 -1
  43. package/dist/client/{_storageType-DYjo-6ej.mjs → _storageType-2_fau4B5.mjs} +698 -698
  44. package/dist/client/{_storageType-DYjo-6ej.mjs.map → _storageType-2_fau4B5.mjs.map} +1 -1
  45. package/dist/client/{_storageType-4wSxI__0.mjs → _storageType-dRTFMKG3.mjs} +2 -2
  46. package/dist/client/{_storageType-4wSxI__0.mjs.map → _storageType-dRTFMKG3.mjs.map} +1 -1
  47. package/dist/client/{about-Bo9vxGHy.mjs → about-Nsxkyh9U.mjs} +2 -2
  48. package/dist/client/{about-Bo9vxGHy.mjs.map → about-Nsxkyh9U.mjs.map} +1 -1
  49. package/dist/client/{build-DeJcDjPi.mjs → build-BdRRmNf5.mjs} +3290 -3274
  50. package/dist/client/{build-DeJcDjPi.mjs.map → build-BdRRmNf5.mjs.map} +1 -1
  51. package/dist/client/{constants-BmcGYeR-.mjs → constants-J5nm9hbP.mjs} +15 -15
  52. package/dist/client/{constants-BmcGYeR-.mjs.map → constants-J5nm9hbP.mjs.map} +1 -1
  53. package/dist/client/{flavors-BxFVqgnb.mjs → flavors-_P7R-CeT.mjs} +2 -2
  54. package/dist/client/{flavors-BxFVqgnb.mjs.map → flavors-_P7R-CeT.mjs.map} +1 -1
  55. package/dist/client/{flavors-CfdgjsZY.mjs → flavors-m1qDHzeS.mjs} +238 -221
  56. package/dist/client/flavors-m1qDHzeS.mjs.map +1 -0
  57. package/dist/client/{floatingips-ByRb82wS.mjs → floatingips-Dq4DXQYb.mjs} +90 -90
  58. package/dist/client/{floatingips-ByRb82wS.mjs.map → floatingips-Dq4DXQYb.mjs.map} +1 -1
  59. package/dist/client/{images-CenluYV8.mjs → images-CpM-T_jM.mjs} +2 -2
  60. package/dist/client/{images-CenluYV8.mjs.map → images-CpM-T_jM.mjs.map} +1 -1
  61. package/dist/client/images-DHmVgQAh2.mjs +1890 -0
  62. package/dist/client/images-DHmVgQAh2.mjs.map +1 -0
  63. package/dist/client/{images-C_dX7nY6.mjs → images-Dbjo4yKn.mjs} +2 -2
  64. package/dist/client/{images-C_dX7nY6.mjs.map → images-Dbjo4yKn.mjs.map} +1 -1
  65. package/dist/client/index.d.ts +1 -1
  66. package/dist/client/index.js +382 -351
  67. package/dist/client/index.js.map +1 -1
  68. package/dist/client/{objects-gxSjvbvF.mjs → objects-DKWp9RtR.mjs} +2 -2
  69. package/dist/client/{objects-gxSjvbvF.mjs.map → objects-DKWp9RtR.mjs.map} +1 -1
  70. package/dist/client/{objects-BJM6YeuF.mjs → objects-DaCuy_CB.mjs} +1156 -1156
  71. package/dist/client/{objects-BJM6YeuF.mjs.map → objects-DaCuy_CB.mjs.map} +1 -1
  72. package/dist/client/{pca-Bl8NmoVZ.mjs → pca-C8zWTSSt.mjs} +2 -2
  73. package/dist/client/{pca-Bl8NmoVZ.mjs.map → pca-C8zWTSSt.mjs.map} +1 -1
  74. package/dist/client/pca-CK5-j7Kk.mjs +202 -0
  75. package/dist/client/pca-CK5-j7Kk.mjs.map +1 -0
  76. package/dist/client/{projects-pe2_dCnV.mjs → projects-CHYn7L5e.mjs} +2 -2
  77. package/dist/client/{projects-pe2_dCnV.mjs.map → projects-CHYn7L5e.mjs.map} +1 -1
  78. package/dist/client/{projects-D2iewAzu.mjs → projects-CeLhtLvf.mjs} +2 -2
  79. package/dist/client/{projects-D2iewAzu.mjs.map → projects-CeLhtLvf.mjs.map} +1 -1
  80. package/dist/client/{projects-CgclWI16.mjs → projects-ClViaUuv.mjs} +11 -11
  81. package/dist/client/{projects-CgclWI16.mjs.map → projects-ClViaUuv.mjs.map} +1 -1
  82. package/dist/client/{_projectId-BDSWnMGj.mjs → routeInfo-DlDJZnpg.mjs} +34 -8
  83. package/dist/client/routeInfo-DlDJZnpg.mjs.map +1 -0
  84. package/dist/client/{securitygroups-DahZkVYQ.mjs → securitygroups-CNFLu9zS.mjs} +112 -112
  85. package/dist/client/{securitygroups-DahZkVYQ.mjs.map → securitygroups-CNFLu9zS.mjs.map} +1 -1
  86. package/dist/client/{useListWithFiltering-DaYcu5AB.mjs → useListWithFiltering-v2A0-SZb.mjs} +9 -9
  87. package/dist/client/{useListWithFiltering-DaYcu5AB.mjs.map → useListWithFiltering-v2A0-SZb.mjs.map} +1 -1
  88. package/dist/server/index.d.ts +6 -1
  89. package/dist/server/index.js +37 -12
  90. package/package.json +4 -4
  91. package/dist/client/_imageId-CvfD832b.mjs +0 -534
  92. package/dist/client/_pcaId-BxBt5DXi.mjs +0 -459
  93. package/dist/client/_pcaId-BxBt5DXi.mjs.map +0 -1
  94. package/dist/client/_projectId-BDSWnMGj.mjs.map +0 -1
  95. package/dist/client/_projectId-DS4nR59B.mjs +0 -299
  96. package/dist/client/_projectId-DS4nR59B.mjs.map +0 -1
  97. package/dist/client/flavors-CfdgjsZY.mjs.map +0 -1
  98. package/dist/client/images-CKqIXUq52.mjs +0 -1873
  99. package/dist/client/images-CKqIXUq52.mjs.map +0 -1
  100. package/dist/client/pca-RSiWpJs9.mjs +0 -182
  101. package/dist/client/pca-RSiWpJs9.mjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"objects-BJM6YeuF.mjs","names":["useEffect","useRef","trpcReact","useProjectId","Modal","Stack","Spinner","useParams","DeleteFolderModal","isOpen","folder","onClose","onSuccess","onError","useLingui","projectId","containerName","from","utils","useUtils","submittedFolderNameRef","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","direction","alignment","gap","p","strong","useEffect","useRef","useState","trpcReact","useProjectId","Modal","Stack","Spinner","Checkbox","useParams","DeleteObjectModal","isOpen","object","onClose","onSuccess","onError","useLingui","projectId","containerName","from","utils","useUtils","keepSegments","setKeepSegments","displayNameRef","data","metadata","isLoading","isLoadingMetadata","error","metadataError","storage","swift","getObjectMetadata","useQuery","project_id","container","name","enabled","isSLO","staticLargeObject","isDLO","objectManifest","deleteObjectMutation","deleteObject","useMutation","listObjects","invalidate","current","message","onSettled","handleClose","reset","handleConfirm","displayName","mutate","multipartManifest","isPending","metadataErrorMessage","title","span","className","open","onCancel","confirmButtonLabel","t","confirmButtonVariant","onConfirm","cancelButtonLabel","size","disableConfirmButton","p","direction","alignment","gap","strong","label","checked","onChange","e","target","useState","useRef","useEffect","useCallback","trpcReact","useProjectId","Modal","Stack","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","objectRows","allBrowserRows","rowVirtualizer","count","getScrollElement","estimateSize","overscan","isPending","targetPathDisplay","initialPrefix","endsWith","isUnchanged","title","span","className","open","onCancel","confirmButtonLabel","onConfirm","cancelButtonLabel","size","disableConfirmButton","direction","alignment","gap","isError","errorMessage","p","label","onChange","onInputChange","placeholder","helptext","maxOptions","totalCount","disabled","required","div","variant","icon","onClick","button","type","ref","style","height","getTotalSize","position","getVirtualItems","virtualRow","row","index","isFolder","data-index","measureElement","top","left","width","transform","start","onKeyDown","invalid","errortext","autoFocus","readOnly","input","checked","useState","useRef","useEffect","useCallback","trpcReact","useProjectId","Modal","Stack","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","objectRows","allBrowserRows","rowVirtualizer","count","getScrollElement","estimateSize","overscan","isPending","targetPathDisplay","initialPrefix","endsWith","isUnchanged","title","span","className","open","onCancel","confirmButtonLabel","onConfirm","cancelButtonLabel","size","disableConfirmButton","direction","alignment","gap","isError","copyErrorMessage","deleteErrorMessage","p","div","label","onChange","invalid","errortext","required","onInputChange","placeholder","helptext","maxOptions","totalCount","disabled","variant","icon","onClick","button","type","ref","style","height","getTotalSize","position","getVirtualItems","virtualRow","row","index","isFolder","data-index","measureElement","top","left","width","transform","start","onKeyDown","autoFocus","readOnly","useEffect","useRef","useState","trpcReact","useProjectId","Modal","Stack","Spinner","TextInput","Icon","Select","SelectOption","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","strong","code","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","Spinner","DataGrid","DataGridRow","DataGridHeadCell","DataGridCell","Button","useParams","formatBytesBinary","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","date","toLocaleString","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","direction","alignment","gap","p","strong","div","contentType","etag","contentLength","lastModified","last_modified","label","onChange","target","setTimeout","invalid","errortext","placeholder","disabled","distribution","onClick","variant","icon","columns","autoFocus","colSpan","useRef","useEffect","useState","useVirtualizer","Checkbox","DataGrid","DataGridHeadCell","DataGridRow","DataGridCell","PopupMenu","PopupMenuItem","PopupMenuOptions","Spinner","MdFolder","MdDescription","formatBytesBinary","trpcClient","trpcReact","useProjectId","DeleteFolderModal","DeleteObjectModal","CopyObjectModal","MoveRenameObjectModal","GenerateTempUrlModal","EditObjectMetadataModal","BROWSER_PREVIEWABLE_TYPES","Set","isBrowserPreviewable","contentType","base","split","trim","toLowerCase","has","startsWith","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","parentRef","isMounted","current","scrollbarWidth","setScrollbarWidth","deleteFolderTarget","setDeleteFolderTarget","deleteObjectTarget","setDeleteObjectTarget","copyObjectTarget","setCopyObjectTarget","moveRenameObjectTarget","setMoveRenameObjectTarget","tempUrlTarget","setTempUrlTarget","editMetadataTarget","setEditMetadataTarget","downloadingRow","setDownloadingRow","downloadId","setDownloadId","previewingRow","setPreviewingRow","data","downloadProgress","storage","swift","watchDownloadProgress","useSubscription","enabled","streamObjectToBlob","row","activeDownloadId","content_type","filename","displayName","iterable","downloadObject","mutate","project_id","object","name","chunks","chunk","ct","fn","push","Uint8Array","from","atob","c","charCodeAt","blob","Blob","type","triggerAnchorDownload","url","anchor","document","createElement","href","download","body","appendChild","click","removeChild","setTimeout","URL","revokeObjectURL","handleDownload","crypto","randomUUID","createObjectURL","err","Error","message","String","handlePreviewOrDownload","previewing","previewTab","window","open","opener","location","close","width","offsetWidth","clientWidth","length","rowVirtualizer","count","getScrollElement","estimateSize","overscan","formatDate","dateString","d","Date","Number","isNaN","getTime","t","toLocaleString","selectableRows","filter","r","kind","selectedSet","allSelected","every","handleSelectAll","map","handleSelectObject","includes","n","columns","className","data-testid","colSpan","div","h3","p","isAnyDownloading","gridColumnTemplate","columnCount","style","paddingRight","checked","onChange","marginRight","ref","height","getTotalSize","position","getVirtualItems","virtualRow","index","isFolder","isDownloading","rowDisplayName","isSelected","data-index","measureElement","top","left","transform","start","display","gridTemplateColumns","alignItems","onClick","e","stopPropagation","button","title","size","span","disabled","progressPct","percent","last_modified","bytes","label","isOpen","folder","onClose","onSuccess","onError","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","useParams","CreateFolderModal","isOpen","currentPrefix","onClose","onSuccess","onError","useLingui","projectId","containerName","from","folderName","setFolderName","nameError","setNameError","utils","useUtils","submittedNameRef","createFolderMutation","storage","swift","createFolder","useMutation","listObjects","invalidate","current","error","message","onSettled","handleClose","reset","validateName","name","trimmed","trim","t","includes","handleNameChange","e","value","target","handleSubmit","folderPath","mutate","project_id","container","handleKeyDown","key","parentPath","title","span","className","open","onCancel","confirmButtonLabel","onConfirm","cancelButtonLabel","size","disableConfirmButton","isPending","direction","gap","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","trpcReact","Modal","Spinner","Stack","useProjectId","MAX_VISIBLE","DeleteObjectsModal","isOpen","objectNames","objectKeys","container","account","onClose","onSuccess","onError","useLingui","projectId","utils","useUtils","bulkDeleteMutation","storage","swift","bulkDelete","useMutation","result","listObjects","invalidate","errors","length","errorMessages","map","e","path","error","join","failedPaths","Set","deletedKeys","filter","key","has","encodeURIComponent","numberDeleted","partialResultMessage","t","message","onSettled","handleClose","reset","handleConfirm","objects","mutate","project_id","totalCount","visibleNames","slice","hiddenCount","isPending","title","open","onCancel","confirmButtonLabel","confirmButtonVariant","cancelButtonLabel","onConfirm","disableConfirmButton","disableCancelButton","disableCloseButton","size","distribution","alignment","className","variant","div","p","h3","ul","name","li","Stack","NotificationText","title","description","direction","gap","span","className","getFolderCreatedToast","folderName","config","variant","onDismiss","children","getFolderCreateErrorToast","errorMessage","getFolderDeletedToast","deletedCount","getFolderDeleteErrorToast","getObjectDownloadErrorToast","objectName","getObjectDeletedToast","getObjectDeleteErrorToast","getObjectCopiedToast","targetContainer","targetPath","destination","getObjectCopyErrorToast","getObjectMovedToast","getObjectMoveErrorToast","getTempUrlCopiedToast","getObjectMetadataUpdatedToast","getObjectMetadataUpdateErrorToast","getObjectUploadedToast","getObjectUploadCancelledToast","getObjectUploadErrorToast","getObjectsBulkDeletedToast","numberDeleted","getObjectsBulkDeleteErrorToast","useState","useEffect","useRef","startTransition","Button","Checkbox","DataGridToolbar","PopupMenu","PopupMenuItem","PopupMenuOptions","PopupMenuToggle","SearchInput","Spinner","Stack","Toast","trpcReact","useProjectId","SortInput","useNavigate","Route","ObjectsTableView","ObjectsFileNavigation","CreateFolderModal","UploadObjectModal","DeleteObjectsModal","getFolderCreatedToast","getFolderCreateErrorToast","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","toastData","setToastData","localSearchTerm","setLocalSearchTerm","debounceTimer","clearTimeout","current","handleToastDismiss","handleCreateFolderSuccess","folderName","onDismiss","handleCreateFolderError","errorMessage","handleUploadSuccess","objectName","handleUploadCancelled","handleUploadError","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","options","label","t","value","data","isLoading","error","storage","swift","listObjects","useQuery","project_id","container","format","navigateToContainers","to","params","navigateToPrefix","newPrefix","allRows","filteredRows","row","toLowerCase","trim","totalItemCount","filteredItemCount","sortedRows","sort","a","b","comparison","localeCompare","aDate","bDate","Date","getTime","aBytes","bBytes","handleSearchChange","term","handleSortChange","newSort","resolvedSortBy","resolvedDirection","className","distribution","alignment","direction","variant","size","message","hasSelection","selectedCount","selectedDisplayNames","map","find","r","selectableNames","allSelectableSelected","every","n","someSelectableSelected","some","handleToggleSelectAll","div","onContainersClick","onPrefixClick","gap","onSortByChange","v","onSortDirectionChange","dir","onClick","placeholder","data-testid","onInput","e","currentTarget","window","setTimeout","onSearch","onClear","checked","indeterminate","onChange","as","disabled","icon","_","plural","span","rows","searchTerm","onFolderClick","onDeleteFolderSuccess","onDeleteFolderError","onDownloadError","onDeleteObjectSuccess","onDeleteObjectError","onCopyObjectSuccess","onCopyObjectError","onMoveObjectSuccess","onMoveObjectError","onTempUrlCopySuccess","onEditMetadataSuccess","onEditMetadataError","isOpen","objectNames","objectKeys","onClose","onSuccess","onError","onCancelled","useState","Modal","TextInput","Stack","Message","trpcReact","useProjectId","formatBytesBinary","DeleteObjectModal","bucketName","objectKey","objectSize","lastModified","isOpen","onClose","onSuccess","onError","useLingui","projectId","confirmText","setConfirmText","utils","useUtils","deleteMutation","storage","ceph","objects","delete","useMutation","list","invalidate","handleClose","error","message","reset","handleConfirm","mutate","project_id","containerName","isFolder","endsWith","displayName","split","filter","Boolean","pop","isConfirmValid","open","onCancel","title","size","confirmButtonLabel","isPending","t","confirmButtonVariant","onConfirm","cancelButtonLabel","disableConfirmButton","disableCancelButton","disableCloseButton","direction","gap","variant","div","className","span","undefined","Date","toLocaleString","label","value","onChange","e","target","placeholder","autoFocus","helptext","p","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","Modal","Stack","Spinner","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","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","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","direction","alignment","gap","div","toFixed","label","onChange","onInputChange","handleSearchChange","placeholder","helptext","searchTerm","trim","hiddenCount","totalBuckets","visibleBuckets","disabled","required","b","variant","icon","onClick","startCreateFolder","button","type","navigateUp","ref","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","p","readOnly","input","checked","isError","errorMessage","useState","useRef","useEffect","trpcReact","useProjectId","Modal","Stack","Spinner","ComboBox","ComboBoxOption","TextInput","Button","MdFolder","MdDescription","MdCreateNewFolder","MdArrowBack","MdWarning","useVirtualizer","useCopyMoveModalState","validateObjectName","MAX_COMBO_OPTIONS","MoveObjectModal","isOpen","bucketName","objectKey","objectSize","onClose","onSuccess","onError","useLingui","projectId","utils","useUtils","submittedKeyRef","submittedTargetKeyRef","submittedTargetBucketRef","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","handleNewFolderKeyDown","e","createFolder","cancelCreateFolder","handleMove","t","trimmedName","trim","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","direction","alignment","gap","label","onChange","target","invalid","errortext","helptext","required","div","strong","isError","copyErrorMessage","deleteErrorMessage","p","toFixed","onInputChange","handleSearchChange","placeholder","searchTerm","hiddenCount","totalBuckets","visibleBuckets","disabled","b","variant","icon","onClick","startCreateFolder","button","type","navigateUp","ref","showNewFolderInput","style","height","getTotalSize","position","getVirtualItems","virtualRow","row","index","isFolder","data-index","measureElement","top","left","width","transform","start","navigateToPrefix","newFolderName","setNewFolderName","onKeyDown","newFolderError","autoFocus","readOnly","useState","useEffect","useRef","trpcReact","useProjectId","Modal","TextInput","Stack","Spinner","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","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","direction","alignment","gap","p","role","div","contentType","etag","lastModified","distribution","label","onClick","variant","icon","disabled","columns","onChange","target","placeholder","errortext","invalid","autoFocus","colSpan","trpcReact","Modal","Stack","Message","useProjectId","formatBytesBinary","RestoreVersionModal","isOpen","bucketName","objectKey","versionId","versionDate","versionSize","onClose","onSuccess","onError","useLingui","projectId","utils","useUtils","restoreMutation","storage","ceph","versioning","restoreVersion","useMutation","listObjectVersions","invalidate","objects","list","error","message","onSettled","reset","handleRestore","mutate","project_id","bucket","key","title","t","open","onCancel","confirmButtonLabel","onConfirm","cancelButtonLabel","disableConfirmButton","isPending","direction","gap","variant","div","className","label","p","code","Date","toLocaleString","undefined","useState","trpcReact","Modal","Stack","Message","TextInput","useProjectId","formatBytesBinary","DeleteVersionModal","isOpen","bucketName","objectKey","versionId","versionDate","versionSize","isDeleteMarker","onClose","onSuccess","onError","useLingui","projectId","confirmText","setConfirmText","utils","useUtils","deleteMutation","storage","ceph","versioning","deleteVersion","useMutation","listObjectVersions","invalidate","objects","list","handleClose","error","message","onSettled","reset","handleDelete","mutate","project_id","bucket","key","title","t","open","onCancel","confirmButtonLabel","onConfirm","cancelButtonLabel","disableConfirmButton","isPending","direction","gap","variant","div","className","label","p","code","Date","toLocaleString","undefined","value","onChange","e","target","placeholder","disabled","useEffect","useState","trpcReact","Modal","Stack","Message","DataGrid","DataGridRow","DataGridCell","DataGridHeadCell","Badge","PopupMenu","PopupMenuItem","PopupMenuOptions","Spinner","useProjectId","formatBytesBinary","RestoreVersionModal","DeleteVersionModal","ObjectVersionHistoryModal","isOpen","bucketName","objectKey","onClose","onRestoreVersion","onDeleteVersion","useLingui","projectId","restoreTarget","setRestoreTarget","deleteTarget","setDeleteTarget","data","isLoading","error","refetch","storage","ceph","versioning","listObjectVersions","useQuery","project_id","bucket","key","enabled","staleTime","versions","handleClose","title","t","open","onCancel","size","direction","gap","alignment","className","span","variant","message","length","columns","map","version","isLatest","isDeleteMarker","code","versionId","lastModified","Date","toLocaleString","etag","div","label","onClick","console","log","date","versionDate","versionSize","onSuccess","setTimeout","onError","useRef","useEffect","useState","useVirtualizer","DataGrid","DataGridRow","DataGridCell","DataGridHeadCell","PopupMenu","PopupMenuItem","PopupMenuOptions","MdFolder","MdDescription","formatBytesBinary","DeleteObjectModal","CopyObjectModal","MoveObjectModal","EditMetadataModal","ObjectVersionHistoryModal","GRID_COLUMN_TEMPLATE","ObjectsTableView","bucketName","objects","folders","currentPrefix","versioningEnabled","onFolderClick","onDeleteObjectSuccess","onDeleteObjectError","onCopyObjectSuccess","onCopyObjectError","onMoveObjectSuccess","onMoveObjectError","onEditMetadataSuccess","onEditMetadataError","onRestoreVersion","onDeleteVersion","useLingui","parentRef","scrollbarWidth","setScrollbarWidth","deleteTarget","setDeleteTarget","copyTarget","setCopyTarget","moveTarget","setMoveTarget","editMetadataTarget","setEditMetadataTarget","versionHistoryTarget","setVersionHistoryTarget","stripPrefix","fullKey","replace","rows","map","f","kind","prefix","displayName","o","key","size","lastModified","current","width","offsetWidth","clientWidth","length","rowVirtualizer","count","getScrollElement","estimateSize","overscan","columns","colSpan","div","className","p","objectKey","objectSize","isOpen","onClose","onSuccess","onError","style","paddingRight","gridColumnTemplate","data-testid","marginRight","ref","height","getTotalSize","position","getVirtualItems","virtualRow","row","index","isFolder","data-index","measureElement","top","left","transform","start","display","gridTemplateColumns","alignItems","button","type","onClick","title","span","Date","toLocaleString","e","stopPropagation","label","t","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","className","onClick","span","size","t","undefined","active","seg","isLast","useState","Modal","TextInput","Stack","trpcReact","useProjectId","validateFolderName","CreateFolderModal","bucketName","currentPrefix","isOpen","onClose","onSuccess","useLingui","projectId","folderName","setFolderName","validationError","setValidationError","utils","useUtils","data","objectsData","storage","ceph","objects","list","useQuery","project_id","containerName","prefix","undefined","delimiter","maxKeys","enabled","createFolderMutation","createFolder","useMutation","_data","variables","invalidate","submittedFullPath","folderPath","endsWith","handleClose","reset","handleFolderNameChange","value","existingFolders","folders","map","f","error","t","message","handleCreate","fullPath","trim","mutate","isValid","length","open","onCancel","title","size","confirmButtonLabel","isPending","onConfirm","confirmButtonVariant","cancelButtonLabel","disableConfirmButton","disableCancelButton","disableCloseButton","direction","gap","p","div","className","span","label","onChange","e","target","placeholder","autoFocus","invalid","errortext","onKeyDown","key","useState","trpcReact","Modal","Stack","Checkbox","useProjectId","EnableVersioningModal","isOpen","bucketName","onClose","onSuccess","onError","useLingui","projectId","confirmed","setConfirmed","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","div","p","className","ul","li","checked","onChange","e","target","label","disabled","trpcReact","Modal","Stack","useProjectId","SuspendVersioningModal","isOpen","bucketName","onClose","onSuccess","onError","useLingui","projectId","utils","useUtils","suspendMutation","storage","ceph","versioning","setStatus","useMutation","getStatus","invalidate","error","message","onSettled","reset","handleSuspend","mutate","project_id","bucket","status","title","t","open","onCancel","confirmButtonLabel","onConfirm","cancelButtonLabel","disableConfirmButton","isPending","direction","gap","div","p","className","ul","li","useEffect","useMemo","z","useForm","useStore","trpcReact","Modal","Stack","Textarea","Select","SelectOption","Button","Spinner","Message","Form","useProjectId","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","formSchema","object","policyText","string","min","t","max","refine","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","parsed","formatted","stringify","setFieldValue","reset","handleTemplateChange","templateValue","template","find","handleDelete","handleReset","isSubmitting","store","state","policyTextValue","values","selectedTemplateValue","originalPolicyText","isDirty","policySize","Blob","size","jsonValidationError","trim","Error","hasPolicy","isSaving","isPending","canSubmit","length","handleSave","handleSubmit","title","open","onCancel","confirmButtonLabel","onConfirm","cancelButtonLabel","disableConfirmButton","direction","gap","div","className","variant","e","preventDefault","p","code","onChange","disabled","map","Field","name","children","field","htmlFor","span","onClick","id","handleChange","target","onBlur","handleBlur","rows","placeholder","Stack","NotificationText","title","description","direction","gap","span","className","getFolderCreatedToast","folderPath","config","variant","onDismiss","children","getFolderCreateErrorToast","errorMessage","getObjectDeletedToast","objectKey","displayName","split","filter","Boolean","pop","getObjectDeleteErrorToast","getObjectCopiedToast","targetBucket","targetKey","wasOverwritten","destination","getObjectCopyErrorToast","getObjectMovedToast","getObjectMoveErrorToast","getObjectMetadataUpdatedToast","getObjectMetadataUpdateErrorToast","useState","useEffect","useRef","startTransition","Spinner","Stack","Button","Toast","Badge","Message","DataGridToolbar","SearchInput","trpcReact","useProjectId","SortInput","ObjectsTableView","ObjectsFileNavigation","CreateFolderModal","EnableVersioningModal","SuspendVersioningModal","BucketPolicyModal","useNavigate","Route","getFolderCreatedToast","getObjectDeletedToast","getObjectDeleteErrorToast","getObjectCopiedToast","getObjectCopyErrorToast","getObjectMovedToast","getObjectMoveErrorToast","getObjectMetadataUpdatedToast","getObjectMetadataUpdateErrorToast","encodePrefix","prefix","bytes","TextEncoder","encode","binString","Array","from","byte","String","fromCodePoint","join","btoa","decodePrefix","encoded","atob","Uint8Array","char","codePointAt","TextDecoder","decode","ObjectBrowserView","bucketName","useLingui","projectId","navigate","fullPath","provider","storageType","useParams","encodedPrefix","sortBy","sortDirection","search","searchParam","useSearch","currentPrefix","continuationToken","setContinuationToken","undefined","allObjects","setAllObjects","allFolders","setAllFolders","hasMore","setHasMore","isCreateFolderModalOpen","setIsCreateFolderModalOpen","isEnableVersioningModalOpen","setIsEnableVersioningModalOpen","isSuspendVersioningModalOpen","setIsSuspendVersioningModalOpen","isPolicyModalOpen","setIsPolicyModalOpen","toastData","setToastData","localSearchTerm","setLocalSearchTerm","debounceTimer","clearTimeout","current","handleToastDismiss","data","versioningStatus","storage","ceph","versioning","getStatus","useQuery","project_id","bucket","enabled","staleTime","policyData","bucketPolicy","get","retry","isLoading","error","objects","list","containerName","delimiter","maxKeys","actualObjects","filter","obj","stripped","key","replace","prev","folders","isTruncated","navigateToPrefix","navigateToBuckets","to","params","loadMore","nextContinuationToken","stripPrefix","fullKey","filteredObjects","toLowerCase","includes","trim","filteredFolders","folder","totalItemCount","length","filteredItemCount","sortedObjects","sort","a","b","comparison","localeCompare","aDate","lastModified","bDate","Date","getTime","size","sortedFolders","sortSettings","options","label","t","value","handleSearchChange","term","handleSortChange","newSort","resolvedSortBy","resolvedDirection","className","distribution","alignment","direction","variant","errorMessage","message","title","div","gap","h2","status","policy","onBucketsClick","onPrefixClick","onSortByChange","onSortDirectionChange","onClick","placeholder","data-testid","onInput","e","v","currentTarget","window","setTimeout","onSearch","onClear","versioningEnabled","onFolderClick","onDeleteObjectSuccess","objectKey","onDismiss","onDeleteObjectError","onCopyObjectSuccess","targetBucket","targetKey","wasOverwritten","onCopyObjectError","onMoveObjectSuccess","onMoveObjectError","onEditMetadataSuccess","onEditMetadataError","onRestoreVersion","onDeleteVersion","disabled","isOpen","onClose","onSuccess","folderPath","onError","useParams","ErrorBoundary","Trans","SwiftObjects","CephObjects","Route","ObjectsDashboard","project","provider","containerName","from","select","params","projectId","storageType","prefix","sortBy","sortDirection","search","useSearch","SplitComponent","component"],"sources":["../../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/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/ObjectToastNotifications.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Swift/Objects/index.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Objects/DeleteObjectModal.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/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Objects/EditMetadataModal.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Objects/RestoreVersionModal.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Objects/DeleteVersionModal.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/Buckets/EnableVersioningModal.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Buckets/SuspendVersioningModal.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Buckets/BucketPolicyModal.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Objects/ObjectToastNotifications.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Objects/ObjectBrowserView.tsx","../../src/client/routes/_auth/projects/$projectId/storage/$provider/$storageType/$containerName/objects/index.tsx?tsr-split=component"],"sourcesContent":["import { useEffect, useRef } from \"react\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport { Modal, Stack, Spinner } 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\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 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 }\n }, [isOpen])\n\n const handleClose = () => {\n deleteFolderMutation.reset()\n onClose()\n }\n\n const handleConfirm = () => {\n if (!folder) 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-[400px] 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}\n >\n {deleteFolderMutation.isPending ? (\n <Stack direction=\"horizontal\" alignment=\"center\" gap=\"2\" className=\"py-4\">\n <Spinner size=\"small\" />\n <Trans>Deleting folder and all its contents...</Trans>\n </Stack>\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 </Stack>\n )}\n </Modal>\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, Spinner, Checkbox } 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 // 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 }\n }, [isOpen])\n\n const handleClose = () => {\n deleteObjectMutation.reset()\n onClose()\n }\n\n const handleConfirm = () => {\n if (!object) return\n displayNameRef.current = object.displayName\n deleteObjectMutation.mutate({\n project_id: projectId,\n container: containerName,\n object: object.name,\n // Send multipartManifest=\"delete\" for SLOs only when the user has NOT\n // checked \"Keep segments\" — tells Swift to also delete all segment objects.\n // DLOs always use plain DELETE (segments are prefix-based, not enumerable).\n ...(isSLO && !keepSegments ? { multipartManifest: \"delete\" as const } : {}),\n })\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-[400px] items-center gap-1\">\n <span className=\"shrink-0\">\n <Trans>Delete object:</Trans>\n </span>\n <span className=\"truncate font-mono\" title={displayName}>\n {displayName}\n </span>\n </span>\n }\n open={isOpen}\n onCancel={handleClose}\n confirmButtonLabel={isPending ? t`Deleting...` : t`Delete`}\n confirmButtonVariant=\"primary-danger\"\n onConfirm={handleConfirm}\n cancelButtonLabel={t`Cancel`}\n size=\"small\"\n disableConfirmButton={isLoading || isPending || !!metadataError}\n >\n {metadataError && (\n <p className=\"text-theme-error mb-4\">\n <Trans>Failed to load object metadata: {metadataErrorMessage}</Trans>\n </p>\n )}\n {isPending ? (\n <Stack direction=\"horizontal\" alignment=\"center\" gap=\"2\" className=\"py-4\">\n <Spinner size=\"small\" />\n <Trans>Deleting...</Trans>\n </Stack>\n ) : isLoading ? (\n <Stack direction=\"horizontal\" alignment=\"center\" gap=\"2\" className=\"py-4\">\n <Spinner size=\"small\" />\n <Trans>Loading object info...</Trans>\n </Stack>\n ) : !metadataError ? (\n <Stack direction=\"vertical\" gap=\"4\">\n <p className=\"text-theme-default\">\n <Trans>\n Object <span className=\"font-mono font-semibold\">\"{displayName}\"</span> will be permanently deleted. This\n cannot be 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 </Stack>\n ) : null}\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 { Modal, Stack, Spinner, ComboBox, ComboBoxOption, TextInput, Button } 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 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 || !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-[500px] items-center gap-1\">\n <span className=\"shrink-0\">\n <Trans>Copy object:</Trans>\n </span>\n <span className=\"truncate font-mono\" title={displayName}>\n {displayName}\n </span>\n </span>\n }\n open={isOpen}\n onCancel={handleClose}\n confirmButtonLabel={isPending ? t`Copying...` : t`Copy`}\n onConfirm={handleCopy}\n cancelButtonLabel={t`Cancel`}\n size=\"large\"\n disableConfirmButton={isPending || isLoadingContainers || isUnchanged}\n >\n {isPending ? (\n <Stack direction=\"horizontal\" alignment=\"center\" gap=\"2\" className=\"py-8\">\n <Spinner size=\"small\" />\n <Trans>Copying object...</Trans>\n </Stack>\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 && <span className=\"text-theme-light truncate font-mono text-xs\">/ {currentPrefix}</span>}\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 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`new-folder-name`}\n invalid={!!newFolderError}\n errortext={newFolderError ?? undefined}\n autoFocus\n className=\"flex-1\"\n />\n <Button\n size=\"small\"\n variant=\"primary\"\n onClick={handleCreateFolder}\n disabled={!newFolderName.trim()}\n >\n <Trans>Create</Trans>\n </Button>\n <Button\n size=\"small\"\n variant=\"subdued\"\n onClick={() => {\n setShowNewFolderInput(false)\n setNewFolderName(\"\")\n setNewFolderError(null)\n }}\n >\n <Trans>Cancel</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=\"text-theme-light mb-1\">\n <Trans>The object will be copied to this path. Navigate folders above to change the destination.</Trans>\n </p>\n <TextInput label={t`Target path`} value={targetPathDisplay} readOnly className=\"font-mono\" />\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 { Modal, Stack, Spinner, ComboBox, ComboBoxOption, TextInput, Button } 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 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 || !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-[500px] items-center gap-1\">\n <span className=\"shrink-0\">\n <Trans>Move/Rename object:</Trans>\n </span>\n <span className=\"truncate font-mono\" title={object.displayName}>\n {object.displayName}\n </span>\n </span>\n }\n open={isOpen}\n onCancel={handleClose}\n confirmButtonLabel={isPending ? t`Moving...` : t`Move`}\n onConfirm={handleMove}\n cancelButtonLabel={t`Cancel`}\n size=\"large\"\n disableConfirmButton={isPending || isLoadingContainers || isUnchanged}\n >\n {isPending ? (\n <Stack direction=\"horizontal\" alignment=\"center\" gap=\"2\" className=\"py-8\">\n <Spinner size=\"small\" />\n <Trans>Moving object...</Trans>\n </Stack>\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=\"text-theme-light mb-1\">\n <Trans>You can rename the object by changing the name here.</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 && <span className=\"text-theme-light truncate font-mono text-xs\">/ {currentPrefix}</span>}\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 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`new-folder-name`}\n invalid={!!newFolderError}\n errortext={newFolderError ?? undefined}\n autoFocus\n className=\"flex-1\"\n />\n <Button\n size=\"small\"\n variant=\"primary\"\n onClick={handleCreateFolder}\n disabled={!newFolderName.trim()}\n >\n <Trans>Create</Trans>\n </Button>\n <Button\n size=\"small\"\n variant=\"subdued\"\n onClick={() => {\n setShowNewFolderInput(false)\n setNewFolderName(\"\")\n setNewFolderError(null)\n }}\n >\n <Trans>Cancel</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=\"text-theme-light mb-1\">\n <Trans>The object will be moved to this path. Navigate folders above to change the destination.</Trans>\n </p>\n <TextInput label={t`Target path`} value={targetPathDisplay} readOnly className=\"font-mono\" />\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 { Modal, Stack, Spinner, TextInput, Icon, Select, SelectOption } 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-[400px] items-center gap-1\">\n <span className=\"shrink-0\">\n <Trans>Share object:</Trans>\n </span>\n <span className=\"truncate font-mono\" 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`Close`}\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 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 <p className=\"text-theme-default\">\n <Trans>\n <strong>No Temp URL key configured.</strong> A temporary URL key must be set at the account or container\n level before temporary URLs can be generated. Contact your administrator to configure{\" \"}\n <code>X-Account-Meta-Temp-URL-Key</code> or <code>X-Container-Meta-Temp-URL-Key</code>.\n </Trans>\n </p>\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 font-mono 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 Spinner,\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 { 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 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 timeZone: \"UTC\",\n })\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-[400px] items-center gap-1\">\n <Trans>\n <span className=\"shrink-0\">Edit metadata:</span>{\" \"}\n <span className=\"truncate font-mono\" 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 <Stack direction=\"horizontal\" alignment=\"center\" gap=\"2\" className=\"py-8\">\n <Spinner size=\"small\" />\n <Trans>Loading object properties...</Trans>\n </Stack>\n ) : isMetaError ? (\n <p className=\"text-theme-error\">\n <Trans>Failed to load object metadata: {metadataErrorMessage}</Trans>\n </p>\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 className=\"font-mono\">{metadataRaw?.contentType ?? \"—\"}</span>\n\n <span className=\"text-theme-light text-right\">\n <Trans>MD5 checksum</Trans>\n </span>\n <span className=\"font-mono 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 font-mono 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 { useRef, useEffect, useState } from \"react\"\nimport { useVirtualizer } from \"@tanstack/react-virtual\"\nimport {\n Checkbox,\n DataGrid,\n DataGridHeadCell,\n DataGridRow,\n DataGridCell,\n PopupMenu,\n PopupMenuItem,\n PopupMenuOptions,\n Spinner,\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 { trpcClient, trpcReact } from \"@/client/trpcClient\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\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\"\n\n// MIME types natively previewable by all modern browsers.\n// Excludes types that require plugins or have inconsistent support.\nconst BROWSER_PREVIEWABLE_TYPES = new Set([\n // Images\n \"image/png\",\n \"image/jpeg\",\n \"image/gif\",\n \"image/webp\",\n \"image/avif\",\n \"image/bmp\",\n \"image/x-icon\",\n \"image/vnd.microsoft.icon\",\n // Video\n \"video/mp4\",\n \"video/webm\",\n \"video/ogg\",\n // Audio\n \"audio/mpeg\",\n \"audio/mp3\",\n \"audio/ogg\",\n \"audio/wav\",\n \"audio/webm\",\n \"audio/flac\",\n // Documents\n \"application/pdf\",\n // Safe text — plain content only, no script-executing types\n \"text/plain\",\n])\n\nconst isBrowserPreviewable = (contentType: string | undefined): boolean => {\n if (!contentType) return false\n // Strip parameters like charset (e.g. \"text/plain; charset=utf-8\" → \"text/plain\")\n const base = contentType.split(\";\")[0].trim().toLowerCase()\n if (BROWSER_PREVIEWABLE_TYPES.has(base)) return true\n // Allow image/*, video/*, audio/* subtypes broadly — these are passive media\n // that cannot execute scripts. Excluded: text/html, text/javascript, text/css,\n // application/json, application/xml and any other active/scriptable types.\n // image/svg+xml is also excluded — SVG can contain embedded <script> tags and\n // executes JavaScript when opened as a same-origin blob URL.\n if (base === \"image/svg+xml\") return false\n if (base.startsWith(\"image/\") || base.startsWith(\"video/\") || base.startsWith(\"audio/\")) return true\n return false\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 const parentRef = useRef<HTMLDivElement>(null)\n const isMounted = useRef(true)\n useEffect(() => {\n isMounted.current = true\n return () => {\n isMounted.current = false\n }\n }, [])\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 const [downloadingRow, setDownloadingRow] = useState<ObjectRow | null>(null)\n const [downloadId, setDownloadId] = useState<string | null>(null)\n const [previewingRow, setPreviewingRow] = useState<ObjectRow | null>(null)\n\n const { data: downloadProgress } = trpcReact.storage.swift.watchDownloadProgress.useSubscription(\n { downloadId: downloadId ?? \"\" },\n { enabled: !!downloadId && downloadingRow !== null }\n )\n\n // Shared streaming helper — fetches the object from the BFF and assembles a Blob.\n // downloadId is set before the mutation starts so the watchDownloadProgress\n // subscription is active from the very first byte.\n const streamObjectToBlob = async (\n row: ObjectRow,\n activeDownloadId: string\n ): Promise<{ blob: Blob; filename: string }> => {\n let contentType = row.content_type ?? \"application/octet-stream\"\n let filename = row.displayName\n\n const iterable = await trpcClient.storage.swift.downloadObject.mutate({\n project_id: projectId,\n container,\n object: row.name,\n filename: row.displayName,\n downloadId: activeDownloadId,\n ...(account ? { account } : {}),\n })\n\n const chunks: Uint8Array<ArrayBuffer>[] = []\n for await (const { chunk, contentType: ct, filename: fn } of iterable) {\n if (ct) contentType = ct\n if (fn) filename = fn\n chunks.push(Uint8Array.from(atob(chunk), (c) => c.charCodeAt(0)) as Uint8Array<ArrayBuffer>)\n }\n\n return { blob: new Blob(chunks, { type: contentType }), filename }\n }\n\n // Triggers a browser file-save for the given blob URL then revokes it after a\n // short delay to avoid racing the browser starting the download.\n const 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 const handleDownload = async (row: ObjectRow) => {\n const activeDownloadId = `${container}:${row.name}:${crypto.randomUUID()}`\n setDownloadingRow(row)\n setDownloadId(activeDownloadId)\n try {\n const { blob, filename } = await streamObjectToBlob(row, activeDownloadId)\n triggerAnchorDownload(URL.createObjectURL(blob), filename)\n } catch (err) {\n onDownloadError(row.displayName, err instanceof Error ? err.message : String(err))\n } finally {\n if (isMounted.current) {\n setDownloadingRow(null)\n setDownloadId(null)\n }\n }\n }\n\n const handlePreviewOrDownload = async (row: ObjectRow) => {\n const activeDownloadId = `${container}:${row.name}:${crypto.randomUUID()}`\n const previewing = isBrowserPreviewable(row.content_type)\n if (previewing) {\n setPreviewingRow(row)\n } else {\n setDownloadingRow(row)\n setDownloadId(activeDownloadId)\n }\n\n // Open a blank tab synchronously while still inside the click handler so\n // The popup is considered user-initiated and won't be blocked. Clear the\n // opener relationship immediately so previewed content cannot access the\n // current window, while still keeping the window reference for navigation\n // after streaming completes.\n const previewTab = previewing ? window.open(\"\", \"_blank\") : null\n if (previewTab) {\n previewTab.opener = null\n }\n\n try {\n const { blob, filename } = await streamObjectToBlob(row, activeDownloadId)\n const url = URL.createObjectURL(blob)\n if (previewing) {\n if (previewTab) {\n previewTab.location.href = url\n }\n // Revoke after a short delay to give the new tab time to load the blob\n setTimeout(() => URL.revokeObjectURL(url), 10000)\n } else {\n triggerAnchorDownload(url, filename)\n }\n } catch (err) {\n previewTab?.close()\n onDownloadError(row.displayName, err instanceof Error ? err.message : String(err))\n } finally {\n if (isMounted.current) {\n setPreviewingRow(null)\n setDownloadingRow(null)\n setDownloadId(null)\n }\n }\n }\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])\n\n const rowVirtualizer = useVirtualizer({\n count: rows.length,\n getScrollElement: () => parentRef.current,\n estimateSize: () => 48, // Estimated row height\n overscan: 10,\n })\n\n // Format date to localized string\n const formatDate = (dateString: string): string => {\n const d = new Date(dateString)\n return Number.isNaN(d.getTime()) ? t`N/A` : d.toLocaleString()\n }\n\n // Only object rows (not folders) are selectable\n const selectableRows = rows.filter((r): r is ObjectRow => r.kind === \"object\")\n const selectedSet = new Set(selectedObjects)\n const allSelected = selectableRows.length > 0 && selectableRows.every((r) => selectedSet.has(r.name))\n\n const handleSelectAll = () => {\n if (allSelected) {\n setSelectedObjects([])\n } else {\n setSelectedObjects(selectableRows.map((r) => r.name))\n }\n }\n\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 if (rows.length === 0) {\n return (\n <DataGrid columns={5} className=\"objects\" data-testid=\"no-objects\">\n <DataGridRow>\n <DataGridCell colSpan={5}>\n <div className=\"py-8 text-center\">\n <h3 className=\"text-lg font-semibold\">\n <Trans>No objects found</Trans>\n </h3>\n <p className=\"text-theme-light mt-2\">\n {searchTerm ? (\n <Trans>No objects match your search. Try adjusting your search term.</Trans>\n ) : (\n <Trans>This folder is empty.</Trans>\n )}\n </p>\n </div>\n </DataGridCell>\n </DataGridRow>\n </DataGrid>\n )\n }\n\n const isAnyDownloading = downloadingRow !== null || previewingRow !== null\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 <Checkbox checked={allSelected} onChange={handleSelectAll} data-testid=\"select-all-objects\" />\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 </DataGrid>\n </div>\n\n {/* Virtualized Table Body with dynamic height */}\n <div\n ref={parentRef}\n className=\"overflow-auto\"\n style={{ height: \"calc(100vh - 470px)\" }}\n data-testid=\"objects-table-body\"\n >\n <div\n style={{\n height: `${rowVirtualizer.getTotalSize()}px`,\n width: \"100%\",\n position: \"relative\",\n }}\n >\n {rowVirtualizer.getVirtualItems().map((virtualRow) => {\n const row = rows[virtualRow.index]\n const isFolder = row.kind === \"folder\"\n const isDownloading = !isFolder && downloadingRow?.name === row.name\n const rowDisplayName = row.displayName\n const isSelected = !isFolder && selectedObjects.includes(row.name)\n\n return (\n <div\n key={row.name}\n data-index={virtualRow.index}\n ref={rowVirtualizer.measureElement}\n className=\"juno-datagrid\"\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 <Checkbox\n checked={isSelected}\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 focus-visible:outline-2 disabled:cursor-wait disabled:opacity-60\"\n onClick={() => handlePreviewOrDownload(row as ObjectRow)}\n disabled={isAnyDownloading}\n data-testid={`preview-${row.name}`}\n title={\n isBrowserPreviewable((row as ObjectRow).content_type)\n ? t`Preview ${rowDisplayName}`\n : t`Download ${rowDisplayName}`\n }\n >\n {previewingRow?.name === row.name ? (\n <Spinner size=\"small\" className=\"shrink-0\" />\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 */}\n <DataGridCell>\n {isDownloading ? (\n <span className=\"flex min-w-0 flex-col gap-1\">\n {(() => {\n const progressPct = downloadProgress?.percent ?? null\n return (\n <>\n <span className=\"text-theme-light flex items-center gap-2 text-sm\">\n <Spinner size=\"small\" />\n {progressPct !== null ? <Trans>{progressPct}%</Trans> : <Trans>Downloading...</Trans>}\n </span>\n {progressPct !== 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: `${progressPct}%` }}\n />\n </div>\n )}\n </>\n )\n })()}\n </span>\n ) : !isFolder && row.last_modified ? (\n formatDate(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 disabled={isAnyDownloading}>\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`}\n disabled={isDownloading}\n onClick={() => handleDownload(row as ObjectRow)}\n data-testid={`download-action-${row.name}`}\n />\n <PopupMenuItem\n label={t`Edit Metadata`}\n onClick={() => setEditMetadataTarget(row as ObjectRow)}\n data-testid={`edit-metadata-action-${row.name}`}\n />\n <PopupMenuItem\n label={t`Copy`}\n onClick={() => setCopyObjectTarget(row as ObjectRow)}\n data-testid={`copy-action-${row.name}`}\n />\n <PopupMenuItem\n label={t`Move/Rename`}\n onClick={() => setMoveRenameObjectTarget(row as ObjectRow)}\n data-testid={`move-rename-action-${row.name}`}\n />\n <PopupMenuItem\n label={t`Share (Temporary URL)`}\n onClick={() => setTempUrlTarget(row as ObjectRow)}\n data-testid={`temp-url-action-${row.name}`}\n />\n <PopupMenuItem\n label={t`Delete`}\n onClick={() => setDeleteObjectTarget(row as ObjectRow)}\n data-testid={`delete-action-${row.name}`}\n />\n </>\n )}\n </PopupMenuOptions>\n </PopupMenu>\n </DataGridCell>\n </div>\n )\n })}\n </div>\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 } from \"@cloudoperators/juno-ui-components\"\nimport { useParams } from \"@tanstack/react-router\"\n\ninterface CreateFolderModalProps {\n isOpen: boolean\n currentPrefix: string\n onClose: () => void\n onSuccess?: (folderName: string) => void\n onError?: (folderName: string, errorMessage: string) => void\n}\n\nexport const CreateFolderModal = ({ isOpen, currentPrefix, onClose, onSuccess, onError }: 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\n const utils = trpcReact.useUtils()\n\n // useRef so the submitted name survives re-renders triggered by\n // createFolderMutation.reset() inside handleClose() before onSuccess/onError fire.\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 },\n onError: (error) => {\n onError?.(submittedNameRef.current, error.message)\n },\n onSettled: () => {\n handleClose()\n },\n })\n\n const handleClose = () => {\n setFolderName(\"\")\n setNameError(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 setNameError(null)\n return true\n }\n\n const handleNameChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const value = e.target.value\n setFolderName(value)\n if (nameError) validateName(value)\n }\n\n const handleSubmit = () => {\n if (!validateName(folderName)) return\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\") 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-[400px] items-center gap-1\">\n <span className=\"shrink-0\">\n <Trans>Create folder below:</Trans>\n </span>\n <span className=\"truncate font-mono\" 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 >\n <Stack direction=\"vertical\" gap=\"6\">\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-[400px] items-center gap-1\">\n <span className=\"shrink-0\">\n <Trans>Upload object to:</Trans>\n </span>\n <span className=\"truncate font-mono\" 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-mono 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 { Plural, Trans, useLingui } from \"@lingui/react/macro\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { Modal, Spinner, Stack } from \"@cloudoperators/juno-ui-components\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\n\n// Max number of object names shown in the list before truncating\nconst MAX_VISIBLE = 20\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 } = useLingui()\n const projectId = useProjectId()\n\n const utils = trpcReact.useUtils()\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 const handleClose = () => {\n bulkDeleteMutation.reset()\n onClose()\n }\n\n const handleConfirm = () => {\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 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={isPending ? t`Deleting...` : t`Delete`}\n confirmButtonVariant=\"primary-danger\"\n cancelButtonLabel={t`Cancel`}\n onConfirm={handleConfirm}\n disableConfirmButton={isPending}\n disableCancelButton={isPending}\n disableCloseButton={isPending}\n size=\"small\"\n >\n {isPending ? (\n <Stack distribution=\"center\" alignment=\"center\" className=\"py-4\">\n <Spinner variant=\"primary\" />\n </Stack>\n ) : (\n <div className=\"my-6\">\n <p className=\"text-theme-default mb-6\">\n <Trans>The selected objects will be permanently deleted. This cannot be undone.</Trans>\n </p>\n\n <div className=\"mb-6\">\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 font-mono 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 </div>\n )}\n </Modal>\n )\n}\n","import { ReactNode } from \"react\"\nimport { ToastProps } from \"@cloudoperators/juno-ui-components\"\nimport { Trans } from \"@lingui/react/macro\"\nimport { Stack } from \"@cloudoperators/juno-ui-components/index\"\n\ninterface NotificationTextProps {\n title: ReactNode\n description: ReactNode\n}\n\nfunction NotificationText({ title, description }: NotificationTextProps) {\n return (\n <Stack direction=\"vertical\" gap=\"1.5\">\n <span>{title}</span>\n <span className=\"text-theme-light\">{description}</span>\n </Stack>\n )\n}\n\ninterface ToastConfig {\n onDismiss: () => void\n}\n\nexport const getFolderCreatedToast = (folderName: string, config: ToastConfig): ToastProps => ({\n variant: \"success\",\n onDismiss: config.onDismiss,\n children: (\n <NotificationText\n title={<Trans>Folder Created</Trans>}\n description={<Trans>Folder \"{folderName}\" was successfully created.</Trans>}\n />\n ),\n})\n\nexport const getFolderCreateErrorToast = (\n folderName: string,\n errorMessage: string,\n config: ToastConfig\n): ToastProps => ({\n variant: \"error\",\n onDismiss: config.onDismiss,\n children: (\n <NotificationText\n title={<Trans>Failed to Create Folder</Trans>}\n description={\n <Trans>\n Could not create folder \"{folderName}\": {errorMessage}\n </Trans>\n }\n />\n ),\n})\n\nexport const getFolderDeletedToast = (folderName: string, deletedCount: number, config: ToastConfig): ToastProps => ({\n variant: \"success\",\n onDismiss: config.onDismiss,\n children: (\n <NotificationText\n title={<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 was permanently deleted.\n </Trans>\n ) : (\n <Trans>\n Folder \"{folderName}\" and {deletedCount} objects were permanently deleted.\n </Trans>\n )\n }\n />\n ),\n})\n\nexport const getFolderDeleteErrorToast = (\n folderName: string,\n errorMessage: string,\n config: ToastConfig\n): ToastProps => ({\n variant: \"error\",\n onDismiss: config.onDismiss,\n children: (\n <NotificationText\n title={<Trans>Failed to Delete Folder</Trans>}\n description={\n <Trans>\n Could not delete folder \"{folderName}\": {errorMessage}\n </Trans>\n }\n />\n ),\n})\n\nexport const getObjectDownloadErrorToast = (\n objectName: string,\n errorMessage: string,\n config: ToastConfig\n): ToastProps => ({\n variant: \"error\",\n onDismiss: config.onDismiss,\n children: (\n <NotificationText\n title={<Trans>Failed to Download</Trans>}\n description={\n <Trans>\n Could not download \"{objectName}\": {errorMessage}\n </Trans>\n }\n />\n ),\n})\n\nexport const getObjectDeletedToast = (objectName: string, config: ToastConfig): ToastProps => ({\n variant: \"success\",\n onDismiss: config.onDismiss,\n children: (\n <NotificationText\n title={<Trans>Object Deleted</Trans>}\n description={<Trans>Object \"{objectName}\" was permanently deleted.</Trans>}\n />\n ),\n})\n\nexport const getObjectDeleteErrorToast = (\n objectName: string,\n errorMessage: string,\n config: ToastConfig\n): ToastProps => ({\n variant: \"error\",\n onDismiss: config.onDismiss,\n children: (\n <NotificationText\n title={<Trans>Failed to Delete Object</Trans>}\n description={\n <Trans>\n Could not delete \"{objectName}\": {errorMessage}\n </Trans>\n }\n />\n ),\n})\n\nexport const getObjectCopiedToast = (\n objectName: string,\n targetContainer: string,\n targetPath: string,\n config: ToastConfig\n): ToastProps => {\n const destination = targetPath ? `${targetContainer}/${targetPath}` : targetContainer\n return {\n variant: \"success\",\n onDismiss: config.onDismiss,\n children: (\n <NotificationText\n title={<Trans>Object Copied</Trans>}\n description={\n <Trans>\n \"{objectName}\" was successfully copied to {destination}.\n </Trans>\n }\n />\n ),\n }\n}\n\nexport const getObjectCopyErrorToast = (objectName: string, errorMessage: string, config: ToastConfig): ToastProps => ({\n variant: \"error\",\n onDismiss: config.onDismiss,\n children: (\n <NotificationText\n title={<Trans>Failed to Copy Object</Trans>}\n description={\n <Trans>\n Could not copy \"{objectName}\": {errorMessage}\n </Trans>\n }\n />\n ),\n})\n\nexport const getObjectMovedToast = (\n objectName: string,\n targetContainer: string,\n targetPath: string,\n config: ToastConfig\n): ToastProps => {\n const destination = targetPath ? `${targetContainer}/${targetPath}` : targetContainer\n return {\n variant: \"success\",\n onDismiss: config.onDismiss,\n children: (\n <NotificationText\n title={<Trans>Object Moved</Trans>}\n description={\n <Trans>\n \"{objectName}\" was successfully moved to {destination}.\n </Trans>\n }\n />\n ),\n }\n}\n\nexport const getObjectMoveErrorToast = (objectName: string, errorMessage: string, config: ToastConfig): ToastProps => ({\n variant: \"error\",\n onDismiss: config.onDismiss,\n children: (\n <NotificationText\n title={<Trans>Failed to Move Object</Trans>}\n description={\n <Trans>\n Could not move \"{objectName}\": {errorMessage}\n </Trans>\n }\n />\n ),\n})\n\nexport const getTempUrlCopiedToast = (objectName: string, config: ToastConfig): ToastProps => ({\n variant: \"success\",\n onDismiss: config.onDismiss,\n children: (\n <NotificationText\n title={<Trans>URL Copied</Trans>}\n description={<Trans>Temporary URL for \"{objectName}\" was copied to clipboard.</Trans>}\n />\n ),\n})\n\nexport const getObjectMetadataUpdatedToast = (objectName: string, config: ToastConfig): ToastProps => ({\n variant: \"success\",\n onDismiss: config.onDismiss,\n children: (\n <NotificationText\n title={<Trans>Object Updated</Trans>}\n description={<Trans>Properties of \"{objectName}\" were successfully updated.</Trans>}\n />\n ),\n})\n\nexport const getObjectMetadataUpdateErrorToast = (\n objectName: string,\n errorMessage: string,\n config: ToastConfig\n): ToastProps => ({\n variant: \"error\",\n onDismiss: config.onDismiss,\n children: (\n <NotificationText\n title={<Trans>Failed to Update Object</Trans>}\n description={\n <Trans>\n Could not update \"{objectName}\": {errorMessage}\n </Trans>\n }\n />\n ),\n})\n\nexport const getObjectUploadedToast = (objectName: string, config: ToastConfig): ToastProps => ({\n variant: \"success\",\n onDismiss: config.onDismiss,\n children: (\n <NotificationText\n title={<Trans>Object Uploaded</Trans>}\n description={<Trans>\"{objectName}\" was successfully uploaded.</Trans>}\n />\n ),\n})\n\nexport const getObjectUploadCancelledToast = (objectName: string, config: ToastConfig): ToastProps => ({\n variant: \"warning\",\n onDismiss: config.onDismiss,\n children: (\n <NotificationText\n title={<Trans>Upload Cancelled</Trans>}\n description={<Trans>Upload of \"{objectName}\" was cancelled.</Trans>}\n />\n ),\n})\n\nexport const getObjectUploadErrorToast = (\n objectName: string,\n errorMessage: string,\n config: ToastConfig\n): ToastProps => ({\n variant: \"error\",\n onDismiss: config.onDismiss,\n children: (\n <NotificationText\n title={<Trans>Failed to Upload Object</Trans>}\n description={\n <Trans>\n Could not upload \"{objectName}\": {errorMessage}\n </Trans>\n }\n />\n ),\n})\n\nexport const getObjectsBulkDeletedToast = (numberDeleted: number, config: ToastConfig): ToastProps => ({\n variant: \"success\",\n onDismiss: config.onDismiss,\n children: (\n <NotificationText\n title={<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 />\n ),\n})\n\nexport const getObjectsBulkDeleteErrorToast = (errorMessage: string, config: ToastConfig): ToastProps => ({\n variant: \"error\",\n onDismiss: config.onDismiss,\n children: (\n <NotificationText\n title={<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 ),\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 Spinner,\n Stack,\n Toast,\n ToastProps,\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 { 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 getFolderCreatedToast,\n getFolderCreateErrorToast,\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 3 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 const [toastData, setToastData] = useState<ToastProps | null>(null)\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 handleToastDismiss = () => setToastData(null)\n\n const handleCreateFolderSuccess = (folderName: string) =>\n setToastData(getFolderCreatedToast(folderName, { onDismiss: handleToastDismiss }))\n const handleCreateFolderError = (folderName: string, errorMessage: string) =>\n setToastData(getFolderCreateErrorToast(folderName, errorMessage, { onDismiss: handleToastDismiss }))\n const handleUploadSuccess = (objectName: string) =>\n setToastData(getObjectUploadedToast(objectName, { onDismiss: handleToastDismiss }))\n const handleUploadCancelled = (objectName: string) =>\n setToastData(getObjectUploadCancelledToast(objectName, { onDismiss: handleToastDismiss }))\n const handleUploadError = (objectName: string, errorMessage: string) =>\n setToastData(getObjectUploadErrorToast(objectName, errorMessage, { onDismiss: handleToastDismiss }))\n const handleDeleteFolderSuccess = (folderName: string, deletedCount: number) => {\n const nestedCount = Math.max(0, deletedCount - 1)\n setToastData(getFolderDeletedToast(folderName, nestedCount, { onDismiss: handleToastDismiss }))\n }\n const handleDeleteFolderError = (folderName: string, errorMessage: string) =>\n setToastData(getFolderDeleteErrorToast(folderName, errorMessage, { onDismiss: handleToastDismiss }))\n const handleDownloadError = (objectName: string, errorMessage: string) =>\n setToastData(getObjectDownloadErrorToast(objectName, errorMessage, { onDismiss: handleToastDismiss }))\n const handleDeleteObjectSuccess = (objectName: string) => {\n setSelectedObjects((prev) => prev.filter((name) => name !== objectName))\n setToastData(getObjectDeletedToast(objectName, { onDismiss: handleToastDismiss }))\n }\n const handleDeleteObjectError = (objectName: string, errorMessage: string) =>\n setToastData(getObjectDeleteErrorToast(objectName, errorMessage, { onDismiss: handleToastDismiss }))\n const handleCopyObjectSuccess = (objectName: string, targetContainer: string, targetPath: string) =>\n setToastData(getObjectCopiedToast(objectName, targetContainer, targetPath, { onDismiss: handleToastDismiss }))\n const handleCopyObjectError = (objectName: string, errorMessage: string) =>\n setToastData(getObjectCopyErrorToast(objectName, errorMessage, { onDismiss: handleToastDismiss }))\n const handleMoveObjectSuccess = (objectName: string, targetContainer: string, targetPath: string) => {\n setSelectedObjects((prev) => prev.filter((name) => name !== objectName))\n setToastData(getObjectMovedToast(objectName, targetContainer, targetPath, { onDismiss: handleToastDismiss }))\n }\n const handleMoveObjectError = (objectName: string, errorMessage: string) =>\n setToastData(getObjectMoveErrorToast(objectName, errorMessage, { onDismiss: handleToastDismiss }))\n const handleTempUrlCopySuccess = (objectName: string) =>\n setToastData(getTempUrlCopiedToast(objectName, { onDismiss: handleToastDismiss }))\n const handleEditMetadataSuccess = (objectName: string) =>\n setToastData(getObjectMetadataUpdatedToast(objectName, { onDismiss: handleToastDismiss }))\n const handleEditMetadataError = (objectName: string, errorMessage: string) =>\n setToastData(getObjectMetadataUpdateErrorToast(objectName, errorMessage, { onDismiss: handleToastDismiss }))\n\n const handleBulkDeleteSuccess = (numberDeleted: number) => {\n setSelectedObjects([])\n setToastData(getObjectsBulkDeletedToast(numberDeleted, { onDismiss: handleToastDismiss }))\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 setToastData(getObjectsBulkDeleteErrorToast(errorMessage, { onDismiss: handleToastDismiss }))\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 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 comparison = new Date(aDate).getTime() - new Date(bDate).getTime()\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 (\n <Stack className=\"absolute inset-0\" distribution=\"center\" alignment=\"center\" direction=\"vertical\">\n <Spinner variant=\"primary\" size=\"large\" className=\"mb-2\" />\n <Trans>Loading Objects...</Trans>\n </Stack>\n )\n }\n\n if (error) {\n const errorMessage = error.message\n return (\n <Stack className=\"absolute inset-0\" distribution=\"center\" alignment=\"center\" direction=\"vertical\">\n <Trans>Error Loading Objects: {errorMessage}</Trans>\n </Stack>\n )\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 3 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 <ObjectsFileNavigation\n containerName={containerName}\n currentPrefix={currentPrefix}\n onContainersClick={navigateToContainers}\n onPrefixClick={navigateToPrefix}\n />\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 onSortByChange={(v) =>\n handleSortChange({ ...sortSettings, sortBy: v, sortDirection: sortSettings.sortDirection })\n }\n onSortDirectionChange={(dir) => handleSortChange({ ...sortSettings, sortDirection: dir })}\n />\n </Stack>\n <Button variant=\"primary\" className=\"whitespace-nowrap\" onClick={() => setCreateFolderModalOpen(true)}>\n <Trans>Create Folder</Trans>\n </Button>\n <Button className=\"whitespace-nowrap\" onClick={() => setUploadModalOpen(true)}>\n <Trans>Upload Object</Trans>\n </Button>\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 — bulk actions (gated) plus the item count. */}\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 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 onError={handleCreateFolderError}\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\n {toastData && (\n <Toast {...toastData} className=\"border-theme-light fixed top-5 right-5 z-50 rounded-lg border shadow-lg\" />\n )}\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 { formatBytesBinary } from \"@/client/utils/formatBytes\"\n\ninterface DeleteObjectModalProps {\n bucketName: string\n objectKey: string\n objectSize?: number\n lastModified?: string\n isOpen: 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 onClose,\n onSuccess,\n onError,\n}: DeleteObjectModalProps) {\n const { t } = useLingui()\n const projectId = useProjectId()\n const [confirmText, setConfirmText] = useState(\"\")\n const utils = trpcReact.useUtils()\n\n const deleteMutation = trpcReact.storage.ceph.objects.delete.useMutation({\n onSuccess: () => {\n utils.storage.ceph.objects.list.invalidate()\n onSuccess(objectKey)\n handleClose()\n },\n onError: (error) => {\n onError(objectKey, error.message)\n },\n })\n\n const handleClose = () => {\n setConfirmText(\"\")\n deleteMutation.reset()\n onClose()\n }\n\n const handleConfirm = () => {\n if (!projectId) return\n\n deleteMutation.mutate({\n project_id: projectId,\n containerName: bucketName,\n objectKey,\n })\n }\n\n const isFolder = objectKey.endsWith(\"/\")\n const displayName = objectKey.split(\"/\").filter(Boolean).pop() || objectKey\n const isConfirmValid = confirmText === \"DELETE\"\n\n return (\n <Modal\n open={isOpen}\n onCancel={handleClose}\n title={isFolder ? <Trans>Delete Folder</Trans> : <Trans>Delete Object</Trans>}\n size=\"large\"\n confirmButtonLabel={deleteMutation.isPending ? t`Deleting...` : t`Delete`}\n confirmButtonVariant=\"primary-danger\"\n onConfirm={handleConfirm}\n cancelButtonLabel={t`Cancel`}\n disableConfirmButton={!isConfirmValid || deleteMutation.isPending}\n disableCancelButton={deleteMutation.isPending}\n disableCloseButton={deleteMutation.isPending}\n >\n <Stack direction=\"vertical\" gap=\"4\">\n <Message variant=\"danger\">\n {isFolder ? (\n <Trans>\n Confirm deletion of {displayName}. This action cannot be undone and folder will be permanently deleted.\n </Trans>\n ) : (\n <Trans>\n Confirm deletion of {displayName}. This action cannot be undone and object will be permanently deleted.\n </Trans>\n )}\n </Message>\n\n <div className=\"bg-theme-background-lvl-2 rounded p-4\">\n <Stack direction=\"vertical\" gap=\"2\">\n <div>\n <span className=\"text-theme-light text-sm\">\n <Trans>Name:</Trans>\n </span>\n <div className=\"mt-1 text-sm\">{displayName}</div>\n </div>\n\n {!isFolder && objectSize !== undefined && (\n <div>\n <span className=\"text-theme-light text-sm\">\n <Trans>Size:</Trans>\n </span>\n <div className=\"mt-1 text-sm\">{formatBytesBinary(objectSize)}</div>\n </div>\n )}\n\n {!isFolder && lastModified && (\n <div>\n <span className=\"text-theme-light text-sm\">\n <Trans>Last Modified:</Trans>\n </span>\n <div className=\"mt-1 text-sm\">{new Date(lastModified).toLocaleString()}</div>\n </div>\n )}\n\n <div>\n <span className=\"text-theme-light text-sm\">\n <Trans>Full Path:</Trans>\n </span>\n <div className=\"mt-1 text-sm break-all\">{objectKey}</div>\n </div>\n </Stack>\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 helptext={t`This action cannot be undone.`}\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 </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 : []\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 { Modal, Stack, Spinner, ComboBox, ComboBoxOption, TextInput, Button } 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 [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 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 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 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 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-[500px] 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`}\n onConfirm={handleCopy}\n cancelButtonLabel={t`Cancel`}\n size=\"large\"\n disableConfirmButton={isPending || isLoadingBuckets || isUnchanged}\n >\n {isPending ? (\n <Stack direction=\"horizontal\" alignment=\"center\" gap=\"2\" className=\"py-8\">\n <Spinner size=\"small\" />\n <Trans>Copying object...</Trans>\n </Stack>\n ) : (\n <Stack direction=\"vertical\" gap=\"4\">\n {/* Source object info */}\n <div className=\"bg-theme-background-lvl-2 rounded p-3\">\n <div className=\"text-theme-light text-sm\">\n <Trans>Source:</Trans>\n </div>\n <div className=\"mt-1 text-sm\">{`${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\n {/* Target bucket — ComboBox with debounced search */}\n <ComboBox\n label={t`Target bucket`}\n value={modalState.targetBucket}\n onChange={handleBucketChange}\n onInputChange={modalState.handleSearchChange}\n placeholder={t`Type to search buckets...`}\n helptext={(() => {\n if (isLoadingBuckets) return t`Loading buckets...`\n if (modalState.searchTerm.trim().length === 0) return t`Start typing to search for a bucket`\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.visibleBuckets.map((b) => (\n <ComboBoxOption key={b.name} value={b.name}>\n {b.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={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 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 {/* Read-only target path */}\n <div>\n <p className=\"text-theme-light mb-1\">\n <Trans>The object will be copied to this path. Navigate folders above to change the destination.</Trans>\n </p>\n <TextInput label={t`Target path`} value={targetPathDisplay} readOnly />\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 { Modal, Stack, Spinner, ComboBox, ComboBoxOption, TextInput, Button } from \"@cloudoperators/juno-ui-components\"\nimport { MdFolder, MdDescription, MdCreateNewFolder, MdArrowBack, MdWarning } 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 [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 // 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 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 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 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-[500px] 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={handleClose}\n confirmButtonLabel={isPending ? t`Moving...` : t`Move`}\n onConfirm={handleMove}\n cancelButtonLabel={t`Cancel`}\n size=\"large\"\n disableConfirmButton={isPending || isLoadingBuckets || isUnchanged}\n >\n {isPending ? (\n <Stack direction=\"horizontal\" alignment=\"center\" gap=\"2\" className=\"py-8\">\n <Spinner size=\"small\" />\n <Trans>Moving object...</Trans>\n </Stack>\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 {/* Warning banner */}\n <div className=\"text-theme-default flex items-start gap-2\">\n <MdWarning size={20} className=\"shrink-0\" />\n <div>\n <strong>\n <Trans>Warning:</Trans>\n </strong>{\" \"}\n <Trans>This will delete the original object after copying it to the destination.</Trans>\n </div>\n </div>\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 {/* Source object info */}\n <div className=\"bg-theme-background-lvl-2 rounded p-3\">\n <div className=\"text-theme-light text-sm\">\n <Trans>Source:</Trans>\n </div>\n <div className=\"mt-1 text-sm\">{`${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\n {/* Target bucket */}\n <ComboBox\n label={t`Target bucket`}\n value={modalState.targetBucket}\n onChange={handleBucketChange}\n onInputChange={modalState.handleSearchChange}\n placeholder={t`Type to search buckets...`}\n helptext={(() => {\n if (isLoadingBuckets) return t`Loading buckets...`\n if (modalState.searchTerm.trim().length === 0) return t`Start typing to search for a bucket`\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.visibleBuckets.map((b) => (\n <ComboBoxOption key={b.name} value={b.name}>\n {b.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={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 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 {/* Target path preview */}\n <div>\n <p className=\"text-theme-light mb-1\">\n {isUnchanged ? (\n <Trans>\n Cannot move to the same location. Please select a different bucket, folder, or change the name.\n </Trans>\n ) : (\n <Trans>The object will be moved to this path. Navigate folders above to change the destination.</Trans>\n )}\n </p>\n <TextInput label={t`Target path`} value={targetPathDisplay} readOnly invalid={isUnchanged} />\n </div>\n\n {/* Info: metadata is always copied */}\n <p className=\"text-theme-default\">\n <Trans>Object metadata will be automatically copied during the move operation.</Trans>\n </p>\n </Stack>\n )}\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 Spinner,\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 // ── 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 onClose()\n }\n\n const handleSubmit = () => {\n if (!projectId) return\n\n if (isSizeExceeded) {\n return\n }\n\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-[400px] 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=\"large\"\n disableConfirmButton={isBusy || !hasChanges || hasEditing || isAddingNew || isSizeExceeded}\n >\n {isLoading ? (\n <Stack direction=\"horizontal\" alignment=\"center\" gap=\"2\" className=\"py-8\">\n <Spinner size=\"small\" />\n <Trans>Loading object properties...</Trans>\n </Stack>\n ) : isMetaError ? (\n <p className=\"text-theme-error\" role=\"alert\">\n <Trans>Failed to load object metadata: {metadataErrorMessage}</Trans>\n </p>\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 className=\"font-mono\">{objectDetails?.contentType ?? \"—\"}</span>\n\n <span className=\"text-theme-light text-right\">\n <Trans>ETag</Trans>\n </span>\n <span className=\"font-mono 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\n className={`font-mono text-xs ${isSizeExceeded ? \"text-theme-danger font-semibold\" : \"text-theme-light\"}`}\n >\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}>\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=\"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 { Trans, useLingui } from \"@lingui/react/macro\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { Modal, Stack, Message } from \"@cloudoperators/juno-ui-components\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport { formatBytesBinary } from \"@/client/utils/formatBytes\"\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\n const utils = trpcReact.useUtils()\n\n const restoreMutation = trpcReact.storage.ceph.versioning.restoreVersion.useMutation({\n onSuccess: () => {\n utils.storage.ceph.versioning.listObjectVersions.invalidate()\n utils.storage.ceph.objects.list.invalidate()\n onSuccess?.(objectKey, versionId)\n onClose()\n },\n onError: (error) => {\n onError?.(objectKey, error.message)\n onClose()\n },\n onSettled: () => {\n restoreMutation.reset()\n },\n })\n\n const handleRestore = () => {\n restoreMutation.mutate({\n project_id: projectId,\n bucket: bucketName,\n key: objectKey,\n versionId,\n })\n }\n\n if (!isOpen) return null\n\n return (\n <Modal\n title={t`Restore Version`}\n open={isOpen}\n onCancel={onClose}\n confirmButtonLabel={t`Restore Version`}\n onConfirm={handleRestore}\n cancelButtonLabel={t`Cancel`}\n disableConfirmButton={restoreMutation.isPending}\n >\n <Stack direction=\"vertical\" gap=\"4\">\n <Message variant=\"info\" title={t`How Restore Works`}>\n <Trans>\n This creates a new latest version with the content from the selected version. All existing versions\n (including the current latest) are preserved.\n </Trans>\n </Message>\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 <Message variant=\"warning\">\n <Trans>After restoring, this version's content will become the new latest version.</Trans>\n </Message>\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, Message, TextInput } from \"@cloudoperators/juno-ui-components\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport { formatBytesBinary } from \"@/client/utils/formatBytes\"\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 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 onClose,\n onSuccess,\n onError,\n}: DeleteVersionModalProps) => {\n const { t } = useLingui()\n const projectId = useProjectId()\n const [confirmText, setConfirmText] = useState(\"\")\n\n const utils = trpcReact.useUtils()\n\n const deleteMutation = trpcReact.storage.ceph.versioning.deleteVersion.useMutation({\n onSuccess: () => {\n utils.storage.ceph.versioning.listObjectVersions.invalidate()\n utils.storage.ceph.objects.list.invalidate()\n onSuccess?.(objectKey, versionId)\n handleClose()\n },\n onError: (error) => {\n onError?.(objectKey, error.message)\n handleClose()\n },\n onSettled: () => {\n deleteMutation.reset()\n },\n })\n\n const handleClose = () => {\n setConfirmText(\"\")\n onClose()\n }\n\n const handleDelete = () => {\n if (confirmText !== \"DELETE\") return\n\n deleteMutation.mutate({\n project_id: projectId,\n bucket: bucketName,\n key: objectKey,\n versionId,\n })\n }\n\n if (!isOpen) return null\n\n return (\n <Modal\n title={t`Delete Version Permanently`}\n open={isOpen}\n onCancel={handleClose}\n confirmButtonLabel={t`Delete Permanently`}\n onConfirm={handleDelete}\n cancelButtonLabel={t`Cancel`}\n disableConfirmButton={confirmText !== \"DELETE\" || deleteMutation.isPending}\n >\n <Stack direction=\"vertical\" gap=\"4\">\n <Message variant=\"error\" title={t`⚠️ Warning: Irreversible Action`}>\n <Trans>\n This will permanently delete this version. This operation cannot be undone. The version will be lost\n forever.\n </Trans>\n </Message>\n\n {isDeleteMarker && (\n <Message variant=\"info\">\n <Trans>\n This is a delete marker. Deleting it will \"undelete\" the object and restore the previous version as the\n current version.\n </Trans>\n </Message>\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 {!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 <label className=\"text-sm font-semibold\">\n <Trans>\n Type <code>DELETE</code> to confirm:\n </Trans>\n </label>\n <TextInput\n value={confirmText}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) => setConfirmText(e.target.value)}\n placeholder=\"DELETE\"\n className=\"mt-2\"\n disabled={deleteMutation.isPending}\n />\n </div>\n </Stack>\n </Modal>\n )\n}\n","import { useEffect, useState } from \"react\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport type { ObjectVersion } from \"@/server/Storage/types/versioning\"\nimport {\n Modal,\n Stack,\n Message,\n DataGrid,\n DataGridRow,\n DataGridCell,\n DataGridHeadCell,\n Badge,\n PopupMenu,\n PopupMenuItem,\n PopupMenuOptions,\n Spinner,\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}\n\nexport const ObjectVersionHistoryModal = ({\n isOpen,\n bucketName,\n objectKey,\n onClose,\n onRestoreVersion,\n onDeleteVersion,\n}: ObjectVersionHistoryModalProps) => {\n const { t } = useLingui()\n const projectId = useProjectId()\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\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 onClose()\n }\n\n if (!isOpen) return null\n\n return (\n <Modal title={t`Version History: ${objectKey}`} open={isOpen} onCancel={handleClose} size=\"large\">\n <Stack direction=\"vertical\" gap=\"4\">\n {isLoading && (\n <Stack direction=\"horizontal\" gap=\"2\" alignment=\"center\" className=\"py-8\">\n <Spinner />\n <span className=\"text-theme-light text-sm\">\n <Trans>Loading versions...</Trans>\n </span>\n </Stack>\n )}\n\n {error && (\n <Message variant=\"error\" title={t`Failed to load versions`}>\n {error.message}\n </Message>\n )}\n\n {!isLoading && !error && versions.length === 0 && (\n <Message variant=\"info\">\n <Trans>No versions found for this object.</Trans>\n </Message>\n )}\n\n {!isLoading && !error && versions.length > 0 && (\n <>\n <Message variant=\"info\">\n <Trans>\n Showing all versions of this object. The latest version is highlighted. Delete markers indicate when the\n object was deleted.\n </Trans>\n </Message>\n\n <DataGrid columns={6}>\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=\"font-mono 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 <PopupMenu>\n <PopupMenuOptions>\n {!isDeleteMarker && (\n <>\n <PopupMenuItem\n label={t`Download`}\n onClick={() => {\n // TODO: Generate download URL with versionId\n console.log(\"Download version:\", version.versionId)\n }}\n />\n {!isLatest && (\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 </>\n )}\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 </PopupMenuOptions>\n </PopupMenu>\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 onRestoreVersion?.(objectKey, versionId)\n // Invalidate is handled by RestoreVersionModal, but we refetch to ensure immediate update\n setTimeout(() => refetch(), 100)\n }}\n onError={() => {\n setRestoreTarget(null)\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 onDeleteVersion?.(objectKey, versionId)\n // Invalidate is handled by DeleteVersionModal, but we refetch to ensure immediate update\n setTimeout(() => refetch(), 100)\n }}\n onError={() => {\n setDeleteTarget(null)\n }}\n />\n </Modal>\n )\n}\n","import { useRef, useEffect, useState } from \"react\"\nimport { useVirtualizer } from \"@tanstack/react-virtual\"\nimport {\n DataGrid,\n DataGridRow,\n DataGridCell,\n DataGridHeadCell,\n PopupMenu,\n PopupMenuItem,\n PopupMenuOptions,\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 type { S3Object, S3FolderPrefix } from \"@/server/Storage/types/ceph\"\nimport { DeleteObjectModal } from \"./DeleteObjectModal\"\nimport { CopyObjectModal } from \"./CopyObjectModal\"\nimport { MoveObjectModal } from \"./MoveObjectModal\"\nimport { EditMetadataModal } from \"./EditMetadataModal\"\nimport { ObjectVersionHistoryModal } from \"./ObjectVersionHistoryModal\"\n\ntype FolderRow = { kind: \"folder\"; prefix: string; displayName: string }\ntype ObjectRow = {\n kind: \"object\"\n key: string\n size: number\n lastModified: string | undefined\n displayName: string\n}\ntype CephRow = FolderRow | ObjectRow\n\n// Define column template — 4 columns: name | size | last modified | actions\nconst GRID_COLUMN_TEMPLATE = \"minmax(200px, 3fr) minmax(100px, 1fr) minmax(180px, 2fr) 60px\"\n\ninterface ObjectsTableViewProps {\n bucketName: string\n objects: S3Object[]\n folders: S3FolderPrefix[]\n currentPrefix: string\n versioningEnabled?: boolean\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 onRestoreVersion?: (objectKey: string, versionId: string) => void\n onDeleteVersion?: (objectKey: string, versionId: string) => void\n}\n\nexport function ObjectsTableView({\n bucketName,\n objects,\n folders,\n currentPrefix,\n versioningEnabled = false,\n onFolderClick,\n onDeleteObjectSuccess,\n onDeleteObjectError,\n onCopyObjectSuccess,\n onCopyObjectError,\n onMoveObjectSuccess,\n onMoveObjectError,\n onEditMetadataSuccess,\n onEditMetadataError,\n onRestoreVersion,\n onDeleteVersion,\n}: ObjectsTableViewProps) {\n const { t } = useLingui()\n const parentRef = useRef<HTMLDivElement>(null)\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 [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\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\n const rows: CephRow[] = [\n ...folders.map(\n (f): FolderRow => ({\n kind: \"folder\",\n prefix: f.prefix,\n displayName: stripPrefix(f.prefix).replace(/\\/$/, \"\"),\n })\n ),\n ...objects.map(\n (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\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])\n\n const rowVirtualizer = useVirtualizer({\n count: rows.length,\n getScrollElement: () => parentRef.current,\n estimateSize: () => 48,\n overscan: 10,\n })\n\n if (rows.length === 0) {\n return (\n <>\n <DataGrid columns={4}>\n <DataGridRow>\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 />\n </DataGridRow>\n <DataGridRow>\n <DataGridCell colSpan={4}>\n <div className=\"py-8 text-center\">\n <p className=\"text-theme-light\">\n <Trans>No objects found.</Trans>\n </p>\n </div>\n </DataGridCell>\n </DataGridRow>\n </DataGrid>\n <DeleteObjectModal\n bucketName={bucketName}\n objectKey={deleteTarget?.key ?? \"\"}\n objectSize={deleteTarget?.size}\n lastModified={deleteTarget?.lastModified}\n isOpen={deleteTarget !== null}\n onClose={() => setDeleteTarget(null)}\n onSuccess={onDeleteObjectSuccess}\n onError={onDeleteObjectError}\n />\n </>\n )\n }\n\n return (\n <>\n <div className=\"relative\">\n {/* Table Header with scrollbar padding */}\n <div style={{ paddingRight: `${scrollbarWidth}px` }}>\n <DataGrid columns={4} gridColumnTemplate={GRID_COLUMN_TEMPLATE} data-testid=\"objects-table-header\">\n <DataGridRow>\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 </DataGrid>\n </div>\n\n {/* Virtualized Table Body with dynamic height */}\n <div\n ref={parentRef}\n className=\"overflow-auto\"\n style={{ height: \"calc(100vh - 500px)\" }}\n data-testid=\"objects-table-body\"\n >\n <div\n style={{\n height: `${rowVirtualizer.getTotalSize()}px`,\n width: \"100%\",\n position: \"relative\",\n }}\n >\n {rowVirtualizer.getVirtualItems().map((virtualRow) => {\n const row = rows[virtualRow.index]\n const isFolder = row.kind === \"folder\"\n\n return (\n <div\n key={isFolder ? row.prefix : row.key}\n data-index={virtualRow.index}\n ref={rowVirtualizer.measureElement}\n className=\"juno-datagrid\"\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: GRID_COLUMN_TEMPLATE,\n alignItems: \"stretch\",\n }}\n data-testid={isFolder ? `folder-row-${row.prefix}` : `object-row-${row.key}`}\n >\n {/* Name */}\n <DataGridCell>\n {isFolder ? (\n <button\n type=\"button\"\n className=\"flex min-w-0 items-center gap-2 rounded text-left hover:underline focus-visible:outline focus-visible:outline-2\"\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 ) : (\n <div className=\"flex items-center gap-2\">\n <MdDescription size={18} className=\"text-theme-light shrink-0\" />\n <span className=\"truncate text-sm\">{row.displayName}</span>\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>\n <span className=\"text-sm\">\n {!isFolder && row.lastModified ? new Date(row.lastModified).toLocaleString() : \"—\"}\n </span>\n </DataGridCell>\n\n {/* Actions */}\n <DataGridCell onClick={(e) => e.stopPropagation()}>\n <div className=\"flex justify-end\">\n <PopupMenu>\n <PopupMenuOptions>\n {isFolder ? (\n <PopupMenuItem label={t`Delete`} onClick={() => setDeleteTarget({ key: row.prefix })} />\n ) : (\n <>\n {versioningEnabled && (\n <PopupMenuItem\n label={t`View Versions`}\n onClick={() => setVersionHistoryTarget(row.key)}\n />\n )}\n <PopupMenuItem\n label={t`Copy`}\n onClick={() => setCopyTarget({ key: row.key, size: row.size })}\n />\n <PopupMenuItem\n label={t`Move`}\n onClick={() => setMoveTarget({ key: row.key, size: row.size })}\n />\n <PopupMenuItem label={t`Edit Metadata`} onClick={() => setEditMetadataTarget(row.key)} />\n <PopupMenuItem\n label={t`Delete`}\n onClick={() =>\n setDeleteTarget({\n key: row.key,\n size: row.size,\n lastModified: row.lastModified,\n })\n }\n />\n </>\n )}\n </PopupMenuOptions>\n </PopupMenu>\n </div>\n </DataGridCell>\n </div>\n )\n })}\n </div>\n </div>\n </div>\n\n <DeleteObjectModal\n bucketName={bucketName}\n objectKey={deleteTarget?.key ?? \"\"}\n objectSize={deleteTarget?.size}\n lastModified={deleteTarget?.lastModified}\n isOpen={deleteTarget !== null}\n onClose={() => setDeleteTarget(null)}\n onSuccess={onDeleteObjectSuccess}\n onError={onDeleteObjectError}\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 <ObjectVersionHistoryModal\n isOpen={versionHistoryTarget !== null}\n bucketName={bucketName}\n objectKey={versionHistoryTarget ?? \"\"}\n onClose={() => setVersionHistoryTarget(null)}\n onRestoreVersion={onRestoreVersion}\n onDeleteVersion={onDeleteVersion}\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 className=\"mb-2 px-2 pt-2\">\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 } from \"@cloudoperators/juno-ui-components\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\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 utils = trpcReact.useUtils()\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 // 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 })\n\n const handleClose = () => {\n setFolderName(\"\")\n setValidationError(null)\n createFolderMutation.reset()\n onClose()\n }\n\n const handleFolderNameChange = (value: string) => {\n setFolderName(value)\n // Get existing folder names for duplicate detection\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 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 const fullPath = currentPrefix + folderName.trim()\n\n createFolderMutation.mutate({\n project_id: projectId,\n containerName: bucketName,\n folderPath: fullPath,\n })\n }\n\n const isValid = !validationError && folderName.trim().length > 0\n\n return (\n <Modal\n open={isOpen}\n onCancel={handleClose}\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={!isValid || createFolderMutation.isPending}\n disableCancelButton={createFolderMutation.isPending}\n disableCloseButton={createFolderMutation.isPending}\n >\n <Stack direction=\"vertical\" gap=\"4\">\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 onKeyDown={(e) => {\n if (e.key === \"Enter\" && isValid && !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\n {createFolderMutation.error && (\n <p className=\"text-juno-red text-sm\">\n <Trans>Error:</Trans> {createFolderMutation.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\"\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 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 setConfirmed(false)\n enableMutation.reset()\n onClose()\n }\n\n const handleEnable = () => {\n if (!confirmed) return\n\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 <div>\n <p className=\"mb-3 text-sm\">\n <Trans>\n Versioning allows you to keep multiple variants of an object in the same bucket. This protects against\n accidental overwrites and deletions.\n </Trans>\n </p>\n <p className=\"text-theme-light mb-3 text-sm\">\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 </div>\n\n <div>\n <p className=\"mb-2 text-sm font-semibold\">\n <Trans>Benefits:</Trans>\n </p>\n <ul className=\"list-disc space-y-1 pl-5 text-sm\">\n <li>\n <Trans>Recover from accidental deletions</Trans>\n </li>\n <li>\n <Trans>Retrieve older versions of objects</Trans>\n </li>\n <li>\n <Trans>Maintain object history</Trans>\n </li>\n </ul>\n </div>\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\"\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 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 onClose()\n },\n })\n\n const handleSuspend = () => {\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={onClose}\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 { 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 {\n Modal,\n Stack,\n Textarea,\n Select,\n SelectOption,\n Button,\n Spinner,\n Message,\n Form,\n} from \"@cloudoperators/juno-ui-components\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\n\ninterface BucketPolicyModalProps {\n isOpen: boolean\n bucketName: string\n onClose: () => void\n onSuccess?: (bucketName: string) => void\n onError?: (bucketName: string, errorMessage: string) => 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 // Form schema with JSON validation\n const formSchema = z.object({\n policyText: z\n .string()\n .min(1, t`Policy cannot be empty`)\n .max(MAX_POLICY_SIZE, t`Policy document exceeds maximum size of 20KB`)\n .refine(\n (value) => {\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)\n handleClose()\n },\n onError: (error) => {\n onError?.(bucketName, error.message)\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 onSuccess?.(bucketName)\n handleClose()\n },\n onError: (error) => {\n onError?.(bucketName, error.message)\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 setMutation.mutate({\n project_id: projectId,\n bucketName,\n policy: value.policyText,\n })\n },\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 form.setFieldValue(\"selectedTemplate\", \"\")\n } catch {\n form.setFieldValue(\"policyText\", policyData.policyText)\n }\n } else if (policyData?.policy === null) {\n form.setFieldValue(\"policyText\", \"\")\n form.setFieldValue(\"selectedTemplate\", \"\")\n }\n }, [isOpen, policyData, form])\n\n const handleClose = () => {\n form.reset()\n setMutation.reset()\n deleteMutation.reset()\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 const handleDelete = () => {\n deleteMutation.mutate({\n project_id: projectId,\n bucketName,\n })\n }\n\n const handleReset = () => {\n if (policyData?.policyText) {\n try {\n const parsed = JSON.parse(policyData.policyText)\n form.setFieldValue(\"policyText\", JSON.stringify(parsed, null, 2))\n } catch {\n form.setFieldValue(\"policyText\", policyData.policyText)\n }\n } else {\n form.setFieldValue(\"policyText\", \"\")\n }\n form.setFieldValue(\"selectedTemplate\", \"\")\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 // Compute isDirty relative to the loaded policy, not form's defaultValues (which are empty strings).\n // This prevents false \"Unsaved changes\" indicator when the modal opens with existing policy.\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 isDirty = policyTextValue !== originalPolicyText\n\n const policySize = useMemo(() => {\n return new Blob([policyTextValue]).size\n }, [policyTextValue])\n\n // Validate JSON inline for immediate feedback\n const jsonValidationError = useMemo(() => {\n if (!policyTextValue.trim()) return null\n try {\n JSON.parse(policyTextValue)\n return null\n } catch (error) {\n return error instanceof Error ? error.message : \"Invalid JSON\"\n }\n }, [policyTextValue])\n\n const hasPolicy = !!policyData?.policy\n const isSaving = setMutation.isPending || deleteMutation.isPending || isSubmitting\n const canSubmit =\n !isSaving && !jsonValidationError && policyTextValue.trim().length > 0 && policySize <= MAX_POLICY_SIZE\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`Bucket Policy - ${bucketName}`}\n open={isOpen}\n onCancel={handleClose}\n confirmButtonLabel={t`Save Policy`}\n onConfirm={handleSave}\n cancelButtonLabel={t`Cancel`}\n disableConfirmButton={!canSubmit}\n size=\"large\"\n >\n <Stack direction=\"vertical\" gap=\"4\">\n {isPolicyLoading && (\n <div className=\"flex items-center justify-center py-8\">\n <Spinner variant=\"primary\" size=\"large\" />\n </div>\n )}\n\n {policyError && (\n <Message variant=\"error\" title={t`Failed to load policy`}>\n {policyError.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 text-sm\">\n <Trans>\n Define access permissions for this bucket using JSON policy document. The policy controls who can\n access the bucket and what actions they can perform.\n </Trans>\n </p>\n <p className=\"text-sm\">\n <Trans>\n URL format: <code className=\"text-xs\">https://ceph-endpoint/project_id:bucket_name/file_path</code>\n </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 <div className=\"mb-1.5 flex items-center justify-between\">\n <label htmlFor={field.name} className=\"juno-label\">\n <Trans>Policy JSON</Trans>\n </label>\n {isDirty && (\n <div className=\"flex items-center gap-2\">\n <span className=\"text-theme-warning text-xs\">\n <Trans>Unsaved changes</Trans>\n </span>\n <Button variant=\"subdued\" size=\"small\" onClick={handleReset} disabled={isSaving}>\n <Trans>Reset</Trans>\n </Button>\n </div>\n )}\n </div>\n <Textarea\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 rows={15}\n className=\"font-mono text-xs\"\n disabled={isSaving}\n placeholder={t`Enter bucket policy JSON...`}\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 {jsonValidationError && <span className=\"text-theme-error\">{jsonValidationError}</span>}\n </div>\n </>\n )}\n />\n </div>\n\n {hasPolicy && (\n <div className=\"border-theme-light border-t pt-4\">\n <Button variant=\"primary-danger\" onClick={handleDelete} disabled={isSaving}>\n <Trans>Delete Policy</Trans>\n </Button>\n <p className=\"text-theme-light mt-2 text-xs\">\n <Trans>Deleting the policy will remove all access restrictions defined by it.</Trans>\n </p>\n </div>\n )}\n </Stack>\n </Form>\n )}\n </Stack>\n </Modal>\n )\n}\n","import { ReactNode } from \"react\"\nimport { ToastProps } from \"@cloudoperators/juno-ui-components\"\nimport { Trans } from \"@lingui/react/macro\"\nimport { Stack } from \"@cloudoperators/juno-ui-components/index\"\n\ninterface NotificationTextProps {\n title: ReactNode\n description: ReactNode\n}\n\nfunction NotificationText({ title, description }: NotificationTextProps) {\n return (\n <Stack direction=\"vertical\" gap=\"1.5\">\n <span>{title}</span>\n <span className=\"text-theme-light\">{description}</span>\n </Stack>\n )\n}\n\ninterface ToastConfig {\n onDismiss: () => void\n}\n\n// ── Folder operations ──────────────────────────────────────────────────────────\n\nexport const getFolderCreatedToast = (folderPath: string, config: ToastConfig): ToastProps => ({\n variant: \"success\",\n onDismiss: config.onDismiss,\n children: (\n <NotificationText\n title={<Trans>Folder Created</Trans>}\n description={<Trans>Folder \"{folderPath}\" was successfully created.</Trans>}\n />\n ),\n})\n\nexport const getFolderCreateErrorToast = (\n folderPath: string,\n errorMessage: string,\n config: ToastConfig\n): ToastProps => ({\n variant: \"error\",\n onDismiss: config.onDismiss,\n children: (\n <NotificationText\n title={<Trans>Failed to Create Folder</Trans>}\n description={\n <Trans>\n Could not create folder \"{folderPath}\": {errorMessage}\n </Trans>\n }\n />\n ),\n})\n\n// ── Object delete ──────────────────────────────────────────────────────────────\n\nexport const getObjectDeletedToast = (objectKey: string, config: ToastConfig): ToastProps => {\n const displayName = objectKey.split(\"/\").filter(Boolean).pop() ?? objectKey\n return {\n variant: \"success\",\n onDismiss: config.onDismiss,\n children: (\n <NotificationText\n title={<Trans>Object Deleted</Trans>}\n description={<Trans>Object \"{displayName}\" was permanently deleted.</Trans>}\n />\n ),\n }\n}\n\nexport const getObjectDeleteErrorToast = (objectKey: string, errorMessage: string, config: ToastConfig): ToastProps => {\n const displayName = objectKey.split(\"/\").filter(Boolean).pop() ?? objectKey\n return {\n variant: \"error\",\n onDismiss: config.onDismiss,\n children: (\n <NotificationText\n title={<Trans>Failed to Delete Object</Trans>}\n description={\n <Trans>\n Could not delete \"{displayName}\": {errorMessage}\n </Trans>\n }\n />\n ),\n }\n}\n\n// ── Object copy ────────────────────────────────────────────────────────────────\n\nexport const getObjectCopiedToast = (\n objectKey: string,\n targetBucket: string,\n targetKey: string,\n config: ToastConfig,\n wasOverwritten?: boolean\n): ToastProps => {\n const displayName = objectKey.split(\"/\").filter(Boolean).pop() ?? objectKey\n const destination = `${targetBucket}/${targetKey}`\n return {\n variant: \"success\",\n onDismiss: config.onDismiss,\n children: (\n <NotificationText\n title={<Trans>Object Copied</Trans>}\n description={\n 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 ),\n }\n}\n\nexport const getObjectCopyErrorToast = (objectKey: string, errorMessage: string, config: ToastConfig): ToastProps => {\n const displayName = objectKey.split(\"/\").filter(Boolean).pop() ?? objectKey\n return {\n variant: \"error\",\n onDismiss: config.onDismiss,\n children: (\n <NotificationText\n title={<Trans>Failed to Copy Object</Trans>}\n description={\n <Trans>\n Could not copy \"{displayName}\": {errorMessage}\n </Trans>\n }\n />\n ),\n }\n}\n\n// ── Object move ────────────────────────────────────────────────────────────────\n\nexport const getObjectMovedToast = (\n objectKey: string,\n targetBucket: string,\n targetKey: string,\n config: ToastConfig\n): ToastProps => {\n const displayName = objectKey.split(\"/\").filter(Boolean).pop() ?? objectKey\n const destination = `${targetBucket}/${targetKey}`\n return {\n variant: \"success\",\n onDismiss: config.onDismiss,\n children: (\n <NotificationText\n title={<Trans>Object Moved</Trans>}\n description={\n <Trans>\n \"{displayName}\" was successfully moved to {destination}.\n </Trans>\n }\n />\n ),\n }\n}\n\nexport const getObjectMoveErrorToast = (objectKey: string, errorMessage: string, config: ToastConfig): ToastProps => {\n const displayName = objectKey.split(\"/\").filter(Boolean).pop() ?? objectKey\n return {\n variant: \"error\",\n onDismiss: config.onDismiss,\n children: (\n <NotificationText\n title={<Trans>Failed to Move Object</Trans>}\n description={\n <Trans>\n Could not move \"{displayName}\": {errorMessage}\n </Trans>\n }\n />\n ),\n }\n}\n\n// ── Object metadata update ─────────────────────────────────────────────────────\n\nexport const getObjectMetadataUpdatedToast = (objectKey: string, config: ToastConfig): ToastProps => {\n const displayName = objectKey.split(\"/\").filter(Boolean).pop() ?? objectKey\n return {\n variant: \"success\",\n onDismiss: config.onDismiss,\n children: (\n <NotificationText\n title={<Trans>Object Updated</Trans>}\n description={<Trans>Properties of \"{displayName}\" were successfully updated.</Trans>}\n />\n ),\n }\n}\n\nexport const getObjectMetadataUpdateErrorToast = (\n objectKey: string,\n errorMessage: string,\n config: ToastConfig\n): ToastProps => {\n const displayName = objectKey.split(\"/\").filter(Boolean).pop() ?? objectKey\n return {\n variant: \"error\",\n onDismiss: config.onDismiss,\n children: (\n <NotificationText\n title={<Trans>Failed to Update Object</Trans>}\n description={\n <Trans>\n Could not update \"{displayName}\": {errorMessage}\n </Trans>\n }\n />\n ),\n }\n}\n","import { useState, useEffect, useRef, startTransition } from \"react\"\nimport { Plural, Trans, useLingui } from \"@lingui/react/macro\"\nimport {\n Spinner,\n Stack,\n Button,\n Toast,\n ToastProps,\n Badge,\n Message,\n DataGridToolbar,\n SearchInput,\n} from \"@cloudoperators/juno-ui-components\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\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 { EnableVersioningModal } from \"../Buckets/EnableVersioningModal\"\nimport { SuspendVersioningModal } from \"../Buckets/SuspendVersioningModal\"\nimport { BucketPolicyModal } from \"../Buckets/BucketPolicyModal\"\nimport { useNavigate } from \"@tanstack/react-router\"\nimport { Route } from \"@/client/routes/_auth/projects/$projectId/storage/$provider/$storageType/$containerName/objects\"\nimport type { S3Object, S3FolderPrefix } from \"@/server/Storage/types/ceph\"\nimport {\n getFolderCreatedToast,\n getObjectDeletedToast,\n getObjectDeleteErrorToast,\n getObjectCopiedToast,\n getObjectCopyErrorToast,\n getObjectMovedToast,\n getObjectMoveErrorToast,\n getObjectMetadataUpdatedToast,\n getObjectMetadataUpdateErrorToast,\n} from \"./ObjectToastNotifications\"\n\n// Prefix encoding (reuse from Swift pattern)\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\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 navigate = useNavigate({ from: Route.fullPath })\n const { provider, storageType } = Route.useParams()\n const { prefix: encodedPrefix, sortBy, sortDirection, search: searchParam = \"\" } = Route.useSearch()\n const currentPrefix = decodePrefix(encodedPrefix)\n\n const [continuationToken, setContinuationToken] = useState<string | undefined>(undefined)\n const [allObjects, setAllObjects] = useState<S3Object[]>([])\n const [allFolders, setAllFolders] = useState<S3FolderPrefix[]>([])\n const [hasMore, setHasMore] = useState(false)\n const [isCreateFolderModalOpen, setIsCreateFolderModalOpen] = useState(false)\n const [isEnableVersioningModalOpen, setIsEnableVersioningModalOpen] = useState(false)\n const [isSuspendVersioningModalOpen, setIsSuspendVersioningModalOpen] = useState(false)\n const [isPolicyModalOpen, setIsPolicyModalOpen] = useState(false)\n const [toastData, setToastData] = useState<ToastProps | null>(null)\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 handleToastDismiss = () => setToastData(null)\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 bucket policy status\n const { data: policyData } = trpcReact.storage.ceph.bucketPolicy.get.useQuery(\n {\n project_id: projectId ?? \"\",\n bucketName,\n },\n {\n enabled: !!projectId,\n staleTime: 5 * 60 * 1000, // Cache for 5 minutes\n retry: false,\n }\n )\n\n const { data, isLoading, 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,\n },\n {\n enabled: !!projectId,\n }\n )\n\n // Update accumulated data when new data arrives\n useEffect(() => {\n if (data) {\n // Filter out the folder marker itself (object key === current prefix)\n // When inside \"first/\", S3 returns \"first/\" as an object - we don't want to show it\n const actualObjects = data.objects.filter((obj) => {\n const stripped = currentPrefix ? obj.key.replace(currentPrefix, \"\") : obj.key\n // Skip if stripped is empty (the folder marker itself) or just \"/\"\n return stripped !== \"\" && stripped !== \"/\"\n })\n\n if (continuationToken) {\n // Append to existing data (pagination)\n setAllObjects((prev) => [...prev, ...actualObjects])\n setAllFolders((prev) => [...prev, ...data.folders])\n } else {\n // First load - replace data\n setAllObjects(actualObjects)\n setAllFolders(data.folders)\n }\n // Update hasMore state\n setHasMore(data.isTruncated ?? false)\n }\n }, [data, continuationToken, currentPrefix])\n\n const navigateToPrefix = (prefix: string) => {\n // Reset pagination when navigating\n setContinuationToken(undefined)\n setAllObjects([])\n setAllFolders([])\n setHasMore(false)\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 setAllObjects([])\n setAllFolders([])\n setHasMore(false)\n\n navigate({\n to: \"/projects/$projectId/storage/$provider/$storageType\",\n params: { projectId, provider, storageType },\n })\n }\n\n const loadMore = () => {\n if (data?.nextContinuationToken) {\n setContinuationToken(data.nextContinuationToken)\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 const filteredFolders = allFolders.filter((folder) =>\n stripPrefix(folder.prefix).toLowerCase().includes(searchParam.toLowerCase().trim())\n )\n\n const totalItemCount = allObjects.length + allFolders.length\n const filteredItemCount = 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 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 (isLoading && !continuationToken) {\n return (\n <Stack className=\"absolute inset-0\" distribution=\"center\" alignment=\"center\" direction=\"vertical\">\n <Spinner variant=\"primary\" size=\"large\" className=\"mb-2\" />\n <Trans>Loading objects...</Trans>\n </Stack>\n )\n }\n\n if (error) {\n const errorMessage = error.message\n return (\n <Message variant=\"error\" title={t`Failed to load objects`}>\n {errorMessage}\n </Message>\n )\n }\n\n return (\n <div className=\"relative\">\n {/* Bucket header with versioning status badge */}\n <div className=\"mb-4 flex items-center justify-between\">\n <Stack direction=\"horizontal\" gap=\"3\" alignment=\"center\">\n <h2 className=\"text-xl font-semibold\">{bucketName}</h2>\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>Policy</Trans>\n </Badge>\n )}\n </Stack>\n </div>\n\n <ObjectsFileNavigation\n bucketName={bucketName}\n prefix={currentPrefix}\n onBucketsClick={navigateToBuckets}\n onPrefixClick={navigateToPrefix}\n />\n\n <Stack direction=\"vertical\">\n {/* Zone 1 — sort controls and the 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 onSortByChange={(value) =>\n handleSortChange({ ...sortSettings, sortBy: value, sortDirection: sortSettings.sortDirection })\n }\n onSortDirectionChange={(direction) => handleSortChange({ ...sortSettings, sortDirection: direction })}\n />\n </Stack>\n <Button variant=\"primary\" className=\"whitespace-nowrap\" onClick={() => setIsCreateFolderModalOpen(true)}>\n <Trans>Create Folder</Trans>\n </Button>\n {versioningStatus && versioningStatus.status === \"Enabled\" && (\n <Button\n variant=\"subdued\"\n className=\"whitespace-nowrap\"\n onClick={() => setIsSuspendVersioningModalOpen(true)}\n >\n <Trans>Suspend Versioning</Trans>\n </Button>\n )}\n {versioningStatus &&\n (versioningStatus.status === \"Unversioned\" || versioningStatus.status === \"Suspended\") && (\n <Button className=\"whitespace-nowrap\" onClick={() => setIsEnableVersioningModalOpen(true)}>\n <Trans>Enable Versioning</Trans>\n </Button>\n )}\n <Button variant=\"subdued\" className=\"whitespace-nowrap\" onClick={() => setIsPolicyModalOpen(true)}>\n <Trans>Bucket Policy</Trans>\n </Button>\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 — item count. Ceph objects has no bulk selection/delete, so this\n zone carries only the count (no select-all or Actions menu). */}\n <DataGridToolbar>\n <Stack distribution=\"start\" gap=\"2\" alignment=\"center\" className=\"text-sm\">\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 <ObjectsTableView\n bucketName={bucketName}\n objects={sortedObjects}\n folders={sortedFolders}\n currentPrefix={currentPrefix}\n versioningEnabled={versioningStatus?.status === \"Enabled\"}\n onFolderClick={navigateToPrefix}\n onDeleteObjectSuccess={(objectKey) => {\n setToastData(getObjectDeletedToast(objectKey, { onDismiss: handleToastDismiss }))\n }}\n onDeleteObjectError={(objectKey, errorMessage) => {\n setToastData(getObjectDeleteErrorToast(objectKey, errorMessage, { onDismiss: handleToastDismiss }))\n }}\n onCopyObjectSuccess={(objectKey, targetBucket, targetKey, wasOverwritten) => {\n setToastData(\n getObjectCopiedToast(objectKey, targetBucket, targetKey, { onDismiss: handleToastDismiss }, wasOverwritten)\n )\n }}\n onCopyObjectError={(objectKey, errorMessage) => {\n setToastData(getObjectCopyErrorToast(objectKey, errorMessage, { onDismiss: handleToastDismiss }))\n }}\n onMoveObjectSuccess={(objectKey, targetBucket, targetKey) => {\n setToastData(getObjectMovedToast(objectKey, targetBucket, targetKey, { onDismiss: handleToastDismiss }))\n }}\n onMoveObjectError={(objectKey, errorMessage) => {\n setToastData(getObjectMoveErrorToast(objectKey, errorMessage, { onDismiss: handleToastDismiss }))\n }}\n onEditMetadataSuccess={(objectKey) => {\n setToastData(getObjectMetadataUpdatedToast(objectKey, { onDismiss: handleToastDismiss }))\n }}\n onEditMetadataError={(objectKey, errorMessage) => {\n setToastData(getObjectMetadataUpdateErrorToast(objectKey, errorMessage, { onDismiss: handleToastDismiss }))\n }}\n onRestoreVersion={() => {\n // Version restored successfully - no toast\n }}\n onDeleteVersion={() => {\n // Version deleted successfully - no toast\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 setToastData(getFolderCreatedToast(folderPath, { onDismiss: handleToastDismiss }))\n navigateToPrefix(folderPath)\n }}\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 {toastData && <Toast {...toastData} />}\n </div>\n )\n}\n","import { createFileRoute, redirect, useParams } from \"@tanstack/react-router\"\nimport { getServiceIndex } from \"@/server/Authentication/helpers\"\nimport { ErrorBoundary } from \"react-error-boundary\"\nimport { Trans } from \"@lingui/react/macro\"\nimport { SwiftObjects } from \"../../../../-components/Swift/Objects\"\nimport { CephObjects } from \"../../../../-components/Ceph/Objects\"\nimport { z } from \"zod\"\nimport type { RouteInfo } from \"@/client/routes/routeInfo\"\n\nexport const checkServiceAvailability = (\n availableServices: {\n type: string\n name: string\n }[],\n params: {\n projectId: string\n provider: string\n storageType: string\n containerName: string\n }\n) => {\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// 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\nconst objectsSearchSchema = z.object({\n prefix: z.string().optional(),\n sortBy: z.enum([\"name\", \"last_modified\", \"bytes\", \"lastModified\", \"size\"]).optional(),\n sortDirection: z.enum([\"asc\", \"desc\"]).optional(),\n search: 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 isDetail: true,\n sectionCrumb: { labelKey: \"Storage\" },\n crumb: { useParamAsLabel: \"provider\", to: \"/projects/$projectId/storage/$provider/$storageType\" },\n } satisfies RouteInfo,\n validateSearch: objectsSearchSchema,\n head: ({ match }) => ({\n meta: [{ title: match.params.containerName }],\n }),\n component: () => {\n return <ObjectsDashboard />\n },\n notFoundComponent: () => {\n return (\n <p>\n <Trans>Storage container not found</Trans>\n </p>\n )\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 ObjectsDashboard() {\n const { project, provider, containerName } = useParams({\n from: \"/_auth/projects/$projectId/storage/$provider/$storageType/$containerName/objects/\",\n select: (params) => ({\n project: params.projectId,\n provider: params.provider,\n containerName: params.containerName,\n storageType: params.storageType,\n }),\n })\n\n const { prefix, sortBy, sortDirection, search } = Route.useSearch()\n\n return (\n <div>\n {project ? (\n <ErrorBoundary\n resetKeys={[project, provider, containerName, prefix, sortBy, sortDirection, search]}\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 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"],"mappings":"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"}
1
+ {"version":3,"file":"objects-DaCuy_CB.mjs","names":["useEffect","useRef","trpcReact","useProjectId","Modal","Stack","Spinner","useParams","DeleteFolderModal","isOpen","folder","onClose","onSuccess","onError","useLingui","projectId","containerName","from","utils","useUtils","submittedFolderNameRef","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","direction","alignment","gap","p","strong","useEffect","useRef","useState","trpcReact","useProjectId","Modal","Stack","Spinner","Checkbox","useParams","DeleteObjectModal","isOpen","object","onClose","onSuccess","onError","useLingui","projectId","containerName","from","utils","useUtils","keepSegments","setKeepSegments","displayNameRef","data","metadata","isLoading","isLoadingMetadata","error","metadataError","storage","swift","getObjectMetadata","useQuery","project_id","container","name","enabled","isSLO","staticLargeObject","isDLO","objectManifest","deleteObjectMutation","deleteObject","useMutation","listObjects","invalidate","current","message","onSettled","handleClose","reset","handleConfirm","displayName","mutate","multipartManifest","isPending","metadataErrorMessage","title","span","className","open","onCancel","confirmButtonLabel","t","confirmButtonVariant","onConfirm","cancelButtonLabel","size","disableConfirmButton","p","direction","alignment","gap","strong","label","checked","onChange","e","target","useState","useRef","useEffect","useCallback","trpcReact","useProjectId","Modal","Stack","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","objectRows","allBrowserRows","rowVirtualizer","count","getScrollElement","estimateSize","overscan","isPending","targetPathDisplay","initialPrefix","endsWith","isUnchanged","title","span","className","open","onCancel","confirmButtonLabel","onConfirm","cancelButtonLabel","size","disableConfirmButton","direction","alignment","gap","isError","errorMessage","p","label","onChange","onInputChange","placeholder","helptext","maxOptions","totalCount","disabled","required","div","variant","icon","onClick","button","type","ref","style","height","getTotalSize","position","getVirtualItems","virtualRow","row","index","isFolder","data-index","measureElement","top","left","width","transform","start","onKeyDown","invalid","errortext","autoFocus","readOnly","input","checked","useState","useRef","useEffect","useCallback","trpcReact","useProjectId","Modal","Stack","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","objectRows","allBrowserRows","rowVirtualizer","count","getScrollElement","estimateSize","overscan","isPending","targetPathDisplay","initialPrefix","endsWith","isUnchanged","title","span","className","open","onCancel","confirmButtonLabel","onConfirm","cancelButtonLabel","size","disableConfirmButton","direction","alignment","gap","isError","copyErrorMessage","deleteErrorMessage","p","div","label","onChange","invalid","errortext","required","onInputChange","placeholder","helptext","maxOptions","totalCount","disabled","variant","icon","onClick","button","type","ref","style","height","getTotalSize","position","getVirtualItems","virtualRow","row","index","isFolder","data-index","measureElement","top","left","width","transform","start","onKeyDown","autoFocus","readOnly","useEffect","useRef","useState","trpcReact","useProjectId","Modal","Stack","Spinner","TextInput","Icon","Select","SelectOption","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","strong","code","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","Spinner","DataGrid","DataGridRow","DataGridHeadCell","DataGridCell","Button","useParams","formatBytesBinary","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","date","toLocaleString","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","direction","alignment","gap","p","strong","div","contentType","etag","contentLength","lastModified","last_modified","label","onChange","target","setTimeout","invalid","errortext","placeholder","disabled","distribution","onClick","variant","icon","columns","autoFocus","colSpan","useRef","useEffect","useState","useVirtualizer","Checkbox","DataGrid","DataGridHeadCell","DataGridRow","DataGridCell","PopupMenu","PopupMenuItem","PopupMenuOptions","Spinner","MdFolder","MdDescription","formatBytesBinary","trpcClient","trpcReact","useProjectId","DeleteFolderModal","DeleteObjectModal","CopyObjectModal","MoveRenameObjectModal","GenerateTempUrlModal","EditObjectMetadataModal","BROWSER_PREVIEWABLE_TYPES","Set","isBrowserPreviewable","contentType","base","split","trim","toLowerCase","has","startsWith","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","parentRef","isMounted","current","scrollbarWidth","setScrollbarWidth","deleteFolderTarget","setDeleteFolderTarget","deleteObjectTarget","setDeleteObjectTarget","copyObjectTarget","setCopyObjectTarget","moveRenameObjectTarget","setMoveRenameObjectTarget","tempUrlTarget","setTempUrlTarget","editMetadataTarget","setEditMetadataTarget","downloadingRow","setDownloadingRow","downloadId","setDownloadId","previewingRow","setPreviewingRow","data","downloadProgress","storage","swift","watchDownloadProgress","useSubscription","enabled","streamObjectToBlob","row","activeDownloadId","content_type","filename","displayName","iterable","downloadObject","mutate","project_id","object","name","chunks","chunk","ct","fn","push","Uint8Array","from","atob","c","charCodeAt","blob","Blob","type","triggerAnchorDownload","url","anchor","document","createElement","href","download","body","appendChild","click","removeChild","setTimeout","URL","revokeObjectURL","handleDownload","crypto","randomUUID","createObjectURL","err","Error","message","String","handlePreviewOrDownload","previewing","previewTab","window","open","opener","location","close","width","offsetWidth","clientWidth","length","rowVirtualizer","count","getScrollElement","estimateSize","overscan","formatDate","dateString","d","Date","Number","isNaN","getTime","t","toLocaleString","selectableRows","filter","r","kind","selectedSet","allSelected","every","handleSelectAll","map","handleSelectObject","includes","n","columns","className","data-testid","colSpan","div","h3","p","isAnyDownloading","gridColumnTemplate","columnCount","style","paddingRight","checked","onChange","marginRight","ref","height","getTotalSize","position","getVirtualItems","virtualRow","index","isFolder","isDownloading","rowDisplayName","isSelected","data-index","measureElement","top","left","transform","start","display","gridTemplateColumns","alignItems","onClick","e","stopPropagation","button","title","size","span","disabled","progressPct","percent","last_modified","bytes","label","isOpen","folder","onClose","onSuccess","onError","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","useParams","CreateFolderModal","isOpen","currentPrefix","onClose","onSuccess","onError","useLingui","projectId","containerName","from","folderName","setFolderName","nameError","setNameError","utils","useUtils","submittedNameRef","createFolderMutation","storage","swift","createFolder","useMutation","listObjects","invalidate","current","error","message","onSettled","handleClose","reset","validateName","name","trimmed","trim","t","includes","handleNameChange","e","value","target","handleSubmit","folderPath","mutate","project_id","container","handleKeyDown","key","parentPath","title","span","className","open","onCancel","confirmButtonLabel","onConfirm","cancelButtonLabel","size","disableConfirmButton","isPending","direction","gap","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","trpcReact","Modal","Spinner","Stack","useProjectId","MAX_VISIBLE","DeleteObjectsModal","isOpen","objectNames","objectKeys","container","account","onClose","onSuccess","onError","useLingui","projectId","utils","useUtils","bulkDeleteMutation","storage","swift","bulkDelete","useMutation","result","listObjects","invalidate","errors","length","errorMessages","map","e","path","error","join","failedPaths","Set","deletedKeys","filter","key","has","encodeURIComponent","numberDeleted","partialResultMessage","t","message","onSettled","handleClose","reset","handleConfirm","objects","mutate","project_id","totalCount","visibleNames","slice","hiddenCount","isPending","title","open","onCancel","confirmButtonLabel","confirmButtonVariant","cancelButtonLabel","onConfirm","disableConfirmButton","disableCancelButton","disableCloseButton","size","distribution","alignment","className","variant","div","p","h3","ul","name","li","Stack","NotificationText","title","description","direction","gap","span","className","getFolderCreatedToast","folderName","config","variant","onDismiss","children","getFolderCreateErrorToast","errorMessage","getFolderDeletedToast","deletedCount","getFolderDeleteErrorToast","getObjectDownloadErrorToast","objectName","getObjectDeletedToast","getObjectDeleteErrorToast","getObjectCopiedToast","targetContainer","targetPath","destination","getObjectCopyErrorToast","getObjectMovedToast","getObjectMoveErrorToast","getTempUrlCopiedToast","getObjectMetadataUpdatedToast","getObjectMetadataUpdateErrorToast","getObjectUploadedToast","getObjectUploadCancelledToast","getObjectUploadErrorToast","getObjectsBulkDeletedToast","numberDeleted","getObjectsBulkDeleteErrorToast","useState","useEffect","useRef","startTransition","Button","Checkbox","DataGridToolbar","PopupMenu","PopupMenuItem","PopupMenuOptions","PopupMenuToggle","SearchInput","Spinner","Stack","Toast","trpcReact","useProjectId","SortInput","useNavigate","Route","ObjectsTableView","ObjectsFileNavigation","CreateFolderModal","UploadObjectModal","DeleteObjectsModal","getFolderCreatedToast","getFolderCreateErrorToast","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","toastData","setToastData","localSearchTerm","setLocalSearchTerm","debounceTimer","clearTimeout","current","handleToastDismiss","handleCreateFolderSuccess","folderName","onDismiss","handleCreateFolderError","errorMessage","handleUploadSuccess","objectName","handleUploadCancelled","handleUploadError","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","options","label","t","value","data","isLoading","error","storage","swift","listObjects","useQuery","project_id","container","format","navigateToContainers","to","params","navigateToPrefix","newPrefix","allRows","filteredRows","row","toLowerCase","trim","totalItemCount","filteredItemCount","sortedRows","sort","a","b","comparison","localeCompare","aDate","bDate","Date","getTime","aBytes","bBytes","handleSearchChange","term","handleSortChange","newSort","resolvedSortBy","resolvedDirection","className","distribution","alignment","direction","variant","size","message","hasSelection","selectedCount","selectedDisplayNames","map","find","r","selectableNames","allSelectableSelected","every","n","someSelectableSelected","some","handleToggleSelectAll","div","onContainersClick","onPrefixClick","gap","onSortByChange","v","onSortDirectionChange","dir","onClick","placeholder","data-testid","onInput","e","currentTarget","window","setTimeout","onSearch","onClear","checked","indeterminate","onChange","as","disabled","icon","_","plural","span","rows","searchTerm","onFolderClick","onDeleteFolderSuccess","onDeleteFolderError","onDownloadError","onDeleteObjectSuccess","onDeleteObjectError","onCopyObjectSuccess","onCopyObjectError","onMoveObjectSuccess","onMoveObjectError","onTempUrlCopySuccess","onEditMetadataSuccess","onEditMetadataError","isOpen","objectNames","objectKeys","onClose","onSuccess","onError","onCancelled","useState","Modal","TextInput","Stack","Message","trpcReact","useProjectId","formatBytesBinary","DeleteObjectModal","bucketName","objectKey","objectSize","lastModified","isOpen","onClose","onSuccess","onError","useLingui","projectId","confirmText","setConfirmText","utils","useUtils","deleteMutation","storage","ceph","objects","delete","useMutation","list","invalidate","handleClose","error","message","reset","handleConfirm","mutate","project_id","containerName","isFolder","endsWith","displayName","split","filter","Boolean","pop","isConfirmValid","open","onCancel","title","size","confirmButtonLabel","isPending","t","confirmButtonVariant","onConfirm","cancelButtonLabel","disableConfirmButton","disableCancelButton","disableCloseButton","direction","gap","variant","div","className","span","undefined","Date","toLocaleString","label","value","onChange","e","target","placeholder","autoFocus","helptext","p","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","Modal","Stack","Spinner","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","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","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","direction","alignment","gap","div","toFixed","label","onChange","onInputChange","handleSearchChange","placeholder","helptext","searchTerm","trim","hiddenCount","totalBuckets","visibleBuckets","disabled","required","b","variant","icon","onClick","startCreateFolder","button","type","navigateUp","ref","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","p","readOnly","input","checked","isError","errorMessage","useState","useRef","useEffect","trpcReact","useProjectId","Modal","Stack","Spinner","ComboBox","ComboBoxOption","TextInput","Button","MdFolder","MdDescription","MdCreateNewFolder","MdArrowBack","MdWarning","useVirtualizer","useCopyMoveModalState","validateObjectName","MAX_COMBO_OPTIONS","MoveObjectModal","isOpen","bucketName","objectKey","objectSize","onClose","onSuccess","onError","useLingui","projectId","utils","useUtils","submittedKeyRef","submittedTargetKeyRef","submittedTargetBucketRef","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","handleNewFolderKeyDown","e","createFolder","cancelCreateFolder","handleMove","t","trimmedName","trim","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","direction","alignment","gap","label","onChange","target","invalid","errortext","helptext","required","div","strong","isError","copyErrorMessage","deleteErrorMessage","p","toFixed","onInputChange","handleSearchChange","placeholder","searchTerm","hiddenCount","totalBuckets","visibleBuckets","disabled","b","variant","icon","onClick","startCreateFolder","button","type","navigateUp","ref","showNewFolderInput","style","height","getTotalSize","position","getVirtualItems","virtualRow","row","index","isFolder","data-index","measureElement","top","left","width","transform","start","navigateToPrefix","newFolderName","setNewFolderName","onKeyDown","newFolderError","autoFocus","readOnly","useState","useEffect","useRef","trpcReact","useProjectId","Modal","TextInput","Stack","Spinner","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","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","direction","alignment","gap","p","role","div","contentType","etag","lastModified","distribution","label","onClick","variant","icon","disabled","columns","onChange","target","placeholder","errortext","invalid","autoFocus","colSpan","trpcReact","Modal","Stack","Message","useProjectId","formatBytesBinary","RestoreVersionModal","isOpen","bucketName","objectKey","versionId","versionDate","versionSize","onClose","onSuccess","onError","useLingui","projectId","utils","useUtils","restoreMutation","storage","ceph","versioning","restoreVersion","useMutation","listObjectVersions","invalidate","objects","list","error","message","onSettled","reset","handleRestore","mutate","project_id","bucket","key","title","t","open","onCancel","confirmButtonLabel","onConfirm","cancelButtonLabel","disableConfirmButton","isPending","direction","gap","variant","div","className","label","p","code","Date","toLocaleString","undefined","useState","trpcReact","Modal","Stack","Message","TextInput","useProjectId","formatBytesBinary","DeleteVersionModal","isOpen","bucketName","objectKey","versionId","versionDate","versionSize","isDeleteMarker","onClose","onSuccess","onError","useLingui","projectId","confirmText","setConfirmText","utils","useUtils","deleteMutation","storage","ceph","versioning","deleteVersion","useMutation","listObjectVersions","invalidate","objects","list","handleClose","error","message","onSettled","reset","handleDelete","mutate","project_id","bucket","key","title","t","open","onCancel","confirmButtonLabel","onConfirm","cancelButtonLabel","disableConfirmButton","isPending","direction","gap","variant","div","className","label","p","code","Date","toLocaleString","undefined","value","onChange","e","target","placeholder","disabled","useEffect","useState","trpcReact","Modal","Stack","Message","DataGrid","DataGridRow","DataGridCell","DataGridHeadCell","Badge","PopupMenu","PopupMenuItem","PopupMenuOptions","Spinner","useProjectId","formatBytesBinary","RestoreVersionModal","DeleteVersionModal","ObjectVersionHistoryModal","isOpen","bucketName","objectKey","onClose","onRestoreVersion","onDeleteVersion","useLingui","projectId","restoreTarget","setRestoreTarget","deleteTarget","setDeleteTarget","data","isLoading","error","refetch","storage","ceph","versioning","listObjectVersions","useQuery","project_id","bucket","key","enabled","staleTime","versions","handleClose","title","t","open","onCancel","size","direction","gap","alignment","className","span","variant","message","length","columns","map","version","isLatest","isDeleteMarker","code","versionId","lastModified","Date","toLocaleString","etag","div","label","onClick","console","log","date","versionDate","versionSize","onSuccess","setTimeout","onError","useRef","useEffect","useState","useVirtualizer","DataGrid","DataGridRow","DataGridCell","DataGridHeadCell","PopupMenu","PopupMenuItem","PopupMenuOptions","MdFolder","MdDescription","formatBytesBinary","DeleteObjectModal","CopyObjectModal","MoveObjectModal","EditMetadataModal","ObjectVersionHistoryModal","GRID_COLUMN_TEMPLATE","ObjectsTableView","bucketName","objects","folders","currentPrefix","versioningEnabled","onFolderClick","onDeleteObjectSuccess","onDeleteObjectError","onCopyObjectSuccess","onCopyObjectError","onMoveObjectSuccess","onMoveObjectError","onEditMetadataSuccess","onEditMetadataError","onRestoreVersion","onDeleteVersion","useLingui","parentRef","scrollbarWidth","setScrollbarWidth","deleteTarget","setDeleteTarget","copyTarget","setCopyTarget","moveTarget","setMoveTarget","editMetadataTarget","setEditMetadataTarget","versionHistoryTarget","setVersionHistoryTarget","stripPrefix","fullKey","replace","rows","map","f","kind","prefix","displayName","o","key","size","lastModified","current","width","offsetWidth","clientWidth","length","rowVirtualizer","count","getScrollElement","estimateSize","overscan","columns","colSpan","div","className","p","objectKey","objectSize","isOpen","onClose","onSuccess","onError","style","paddingRight","gridColumnTemplate","data-testid","marginRight","ref","height","getTotalSize","position","getVirtualItems","virtualRow","row","index","isFolder","data-index","measureElement","top","left","transform","start","display","gridTemplateColumns","alignItems","button","type","onClick","title","span","Date","toLocaleString","e","stopPropagation","label","t","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","className","onClick","span","size","t","undefined","active","seg","isLast","useState","Modal","TextInput","Stack","trpcReact","useProjectId","validateFolderName","CreateFolderModal","bucketName","currentPrefix","isOpen","onClose","onSuccess","useLingui","projectId","folderName","setFolderName","validationError","setValidationError","utils","useUtils","data","objectsData","storage","ceph","objects","list","useQuery","project_id","containerName","prefix","undefined","delimiter","maxKeys","enabled","createFolderMutation","createFolder","useMutation","_data","variables","invalidate","submittedFullPath","folderPath","endsWith","handleClose","reset","handleFolderNameChange","value","existingFolders","folders","map","f","error","t","message","handleCreate","fullPath","trim","mutate","isValid","length","open","onCancel","title","size","confirmButtonLabel","isPending","onConfirm","confirmButtonVariant","cancelButtonLabel","disableConfirmButton","disableCancelButton","disableCloseButton","direction","gap","p","div","className","span","label","onChange","e","target","placeholder","autoFocus","invalid","errortext","onKeyDown","key","useState","trpcReact","Modal","Stack","Checkbox","useProjectId","EnableVersioningModal","isOpen","bucketName","onClose","onSuccess","onError","useLingui","projectId","confirmed","setConfirmed","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","div","p","className","ul","li","checked","onChange","e","target","label","disabled","trpcReact","Modal","Stack","useProjectId","SuspendVersioningModal","isOpen","bucketName","onClose","onSuccess","onError","useLingui","projectId","utils","useUtils","suspendMutation","storage","ceph","versioning","setStatus","useMutation","getStatus","invalidate","error","message","onSettled","reset","handleSuspend","mutate","project_id","bucket","status","title","t","open","onCancel","confirmButtonLabel","onConfirm","cancelButtonLabel","disableConfirmButton","isPending","direction","gap","div","p","className","ul","li","useEffect","useMemo","z","useForm","useStore","trpcReact","Modal","Stack","Textarea","Select","SelectOption","Button","Spinner","Message","Form","useProjectId","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","formSchema","object","policyText","string","min","t","max","refine","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","parsed","formatted","stringify","setFieldValue","reset","handleTemplateChange","templateValue","template","find","handleDelete","handleReset","isSubmitting","store","state","policyTextValue","values","selectedTemplateValue","originalPolicyText","isDirty","policySize","Blob","size","jsonValidationError","trim","Error","hasPolicy","isSaving","isPending","canSubmit","length","handleSave","handleSubmit","title","open","onCancel","confirmButtonLabel","onConfirm","cancelButtonLabel","disableConfirmButton","direction","gap","div","className","variant","e","preventDefault","p","code","onChange","disabled","map","Field","name","children","field","htmlFor","span","onClick","id","handleChange","target","onBlur","handleBlur","rows","placeholder","Stack","NotificationText","title","description","direction","gap","span","className","getFolderCreatedToast","folderPath","config","variant","onDismiss","children","getFolderCreateErrorToast","errorMessage","getObjectDeletedToast","objectKey","displayName","split","filter","Boolean","pop","getObjectDeleteErrorToast","getObjectCopiedToast","targetBucket","targetKey","wasOverwritten","destination","getObjectCopyErrorToast","getObjectMovedToast","getObjectMoveErrorToast","getObjectMetadataUpdatedToast","getObjectMetadataUpdateErrorToast","useState","useEffect","useRef","startTransition","Spinner","Stack","Button","Toast","Badge","Message","DataGridToolbar","SearchInput","trpcReact","useProjectId","SortInput","ObjectsTableView","ObjectsFileNavigation","CreateFolderModal","EnableVersioningModal","SuspendVersioningModal","BucketPolicyModal","useNavigate","Route","getFolderCreatedToast","getObjectDeletedToast","getObjectDeleteErrorToast","getObjectCopiedToast","getObjectCopyErrorToast","getObjectMovedToast","getObjectMoveErrorToast","getObjectMetadataUpdatedToast","getObjectMetadataUpdateErrorToast","encodePrefix","prefix","bytes","TextEncoder","encode","binString","Array","from","byte","String","fromCodePoint","join","btoa","decodePrefix","encoded","atob","Uint8Array","char","codePointAt","TextDecoder","decode","ObjectBrowserView","bucketName","useLingui","projectId","navigate","fullPath","provider","storageType","useParams","encodedPrefix","sortBy","sortDirection","search","searchParam","useSearch","currentPrefix","continuationToken","setContinuationToken","undefined","allObjects","setAllObjects","allFolders","setAllFolders","hasMore","setHasMore","isCreateFolderModalOpen","setIsCreateFolderModalOpen","isEnableVersioningModalOpen","setIsEnableVersioningModalOpen","isSuspendVersioningModalOpen","setIsSuspendVersioningModalOpen","isPolicyModalOpen","setIsPolicyModalOpen","toastData","setToastData","localSearchTerm","setLocalSearchTerm","debounceTimer","clearTimeout","current","handleToastDismiss","data","versioningStatus","storage","ceph","versioning","getStatus","useQuery","project_id","bucket","enabled","staleTime","policyData","bucketPolicy","get","retry","isLoading","error","objects","list","containerName","delimiter","maxKeys","actualObjects","filter","obj","stripped","key","replace","prev","folders","isTruncated","navigateToPrefix","navigateToBuckets","to","params","loadMore","nextContinuationToken","stripPrefix","fullKey","filteredObjects","toLowerCase","includes","trim","filteredFolders","folder","totalItemCount","length","filteredItemCount","sortedObjects","sort","a","b","comparison","localeCompare","aDate","lastModified","bDate","Date","getTime","size","sortedFolders","sortSettings","options","label","t","value","handleSearchChange","term","handleSortChange","newSort","resolvedSortBy","resolvedDirection","className","distribution","alignment","direction","variant","errorMessage","message","title","div","gap","h2","status","policy","onBucketsClick","onPrefixClick","onSortByChange","onSortDirectionChange","onClick","placeholder","data-testid","onInput","e","v","currentTarget","window","setTimeout","onSearch","onClear","versioningEnabled","onFolderClick","onDeleteObjectSuccess","objectKey","onDismiss","onDeleteObjectError","onCopyObjectSuccess","targetBucket","targetKey","wasOverwritten","onCopyObjectError","onMoveObjectSuccess","onMoveObjectError","onEditMetadataSuccess","onEditMetadataError","onRestoreVersion","onDeleteVersion","disabled","isOpen","onClose","onSuccess","folderPath","onError","useParams","ErrorBoundary","Trans","SwiftObjects","CephObjects","Route","ObjectsDashboard","project","provider","containerName","from","select","params","projectId","storageType","prefix","sortBy","sortDirection","search","useSearch","SplitComponent","component"],"sources":["../../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/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/ObjectToastNotifications.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Swift/Objects/index.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Objects/DeleteObjectModal.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/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Objects/EditMetadataModal.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Objects/RestoreVersionModal.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Objects/DeleteVersionModal.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/Buckets/EnableVersioningModal.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Buckets/SuspendVersioningModal.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Buckets/BucketPolicyModal.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Objects/ObjectToastNotifications.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Objects/ObjectBrowserView.tsx","../../src/client/routes/_auth/projects/$projectId/storage/$provider/$storageType/$containerName/objects/index.tsx?tsr-split=component"],"sourcesContent":["import { useEffect, useRef } from \"react\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport { Modal, Stack, Spinner } 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\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 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 }\n }, [isOpen])\n\n const handleClose = () => {\n deleteFolderMutation.reset()\n onClose()\n }\n\n const handleConfirm = () => {\n if (!folder) 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-[400px] 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}\n >\n {deleteFolderMutation.isPending ? (\n <Stack direction=\"horizontal\" alignment=\"center\" gap=\"2\" className=\"py-4\">\n <Spinner size=\"small\" />\n <Trans>Deleting folder and all its contents...</Trans>\n </Stack>\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 </Stack>\n )}\n </Modal>\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, Spinner, Checkbox } 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 // 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 }\n }, [isOpen])\n\n const handleClose = () => {\n deleteObjectMutation.reset()\n onClose()\n }\n\n const handleConfirm = () => {\n if (!object) return\n displayNameRef.current = object.displayName\n deleteObjectMutation.mutate({\n project_id: projectId,\n container: containerName,\n object: object.name,\n // Send multipartManifest=\"delete\" for SLOs only when the user has NOT\n // checked \"Keep segments\" — tells Swift to also delete all segment objects.\n // DLOs always use plain DELETE (segments are prefix-based, not enumerable).\n ...(isSLO && !keepSegments ? { multipartManifest: \"delete\" as const } : {}),\n })\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-[400px] items-center gap-1\">\n <span className=\"shrink-0\">\n <Trans>Delete object:</Trans>\n </span>\n <span className=\"truncate font-mono\" title={displayName}>\n {displayName}\n </span>\n </span>\n }\n open={isOpen}\n onCancel={handleClose}\n confirmButtonLabel={isPending ? t`Deleting...` : t`Delete`}\n confirmButtonVariant=\"primary-danger\"\n onConfirm={handleConfirm}\n cancelButtonLabel={t`Cancel`}\n size=\"small\"\n disableConfirmButton={isLoading || isPending || !!metadataError}\n >\n {metadataError && (\n <p className=\"text-theme-error mb-4\">\n <Trans>Failed to load object metadata: {metadataErrorMessage}</Trans>\n </p>\n )}\n {isPending ? (\n <Stack direction=\"horizontal\" alignment=\"center\" gap=\"2\" className=\"py-4\">\n <Spinner size=\"small\" />\n <Trans>Deleting...</Trans>\n </Stack>\n ) : isLoading ? (\n <Stack direction=\"horizontal\" alignment=\"center\" gap=\"2\" className=\"py-4\">\n <Spinner size=\"small\" />\n <Trans>Loading object info...</Trans>\n </Stack>\n ) : !metadataError ? (\n <Stack direction=\"vertical\" gap=\"4\">\n <p className=\"text-theme-default\">\n <Trans>\n Object <span className=\"font-mono font-semibold\">\"{displayName}\"</span> will be permanently deleted. This\n cannot be 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 </Stack>\n ) : null}\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 { Modal, Stack, Spinner, ComboBox, ComboBoxOption, TextInput, Button } 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 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 || !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-[500px] items-center gap-1\">\n <span className=\"shrink-0\">\n <Trans>Copy object:</Trans>\n </span>\n <span className=\"truncate font-mono\" title={displayName}>\n {displayName}\n </span>\n </span>\n }\n open={isOpen}\n onCancel={handleClose}\n confirmButtonLabel={isPending ? t`Copying...` : t`Copy`}\n onConfirm={handleCopy}\n cancelButtonLabel={t`Cancel`}\n size=\"large\"\n disableConfirmButton={isPending || isLoadingContainers || isUnchanged}\n >\n {isPending ? (\n <Stack direction=\"horizontal\" alignment=\"center\" gap=\"2\" className=\"py-8\">\n <Spinner size=\"small\" />\n <Trans>Copying object...</Trans>\n </Stack>\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 && <span className=\"text-theme-light truncate font-mono text-xs\">/ {currentPrefix}</span>}\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 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`new-folder-name`}\n invalid={!!newFolderError}\n errortext={newFolderError ?? undefined}\n autoFocus\n className=\"flex-1\"\n />\n <Button\n size=\"small\"\n variant=\"primary\"\n onClick={handleCreateFolder}\n disabled={!newFolderName.trim()}\n >\n <Trans>Create</Trans>\n </Button>\n <Button\n size=\"small\"\n variant=\"subdued\"\n onClick={() => {\n setShowNewFolderInput(false)\n setNewFolderName(\"\")\n setNewFolderError(null)\n }}\n >\n <Trans>Cancel</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=\"text-theme-light mb-1\">\n <Trans>The object will be copied to this path. Navigate folders above to change the destination.</Trans>\n </p>\n <TextInput label={t`Target path`} value={targetPathDisplay} readOnly className=\"font-mono\" />\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 { Modal, Stack, Spinner, ComboBox, ComboBoxOption, TextInput, Button } 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 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 || !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-[500px] items-center gap-1\">\n <span className=\"shrink-0\">\n <Trans>Move/Rename object:</Trans>\n </span>\n <span className=\"truncate font-mono\" title={object.displayName}>\n {object.displayName}\n </span>\n </span>\n }\n open={isOpen}\n onCancel={handleClose}\n confirmButtonLabel={isPending ? t`Moving...` : t`Move`}\n onConfirm={handleMove}\n cancelButtonLabel={t`Cancel`}\n size=\"large\"\n disableConfirmButton={isPending || isLoadingContainers || isUnchanged}\n >\n {isPending ? (\n <Stack direction=\"horizontal\" alignment=\"center\" gap=\"2\" className=\"py-8\">\n <Spinner size=\"small\" />\n <Trans>Moving object...</Trans>\n </Stack>\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=\"text-theme-light mb-1\">\n <Trans>You can rename the object by changing the name here.</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 && <span className=\"text-theme-light truncate font-mono text-xs\">/ {currentPrefix}</span>}\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 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`new-folder-name`}\n invalid={!!newFolderError}\n errortext={newFolderError ?? undefined}\n autoFocus\n className=\"flex-1\"\n />\n <Button\n size=\"small\"\n variant=\"primary\"\n onClick={handleCreateFolder}\n disabled={!newFolderName.trim()}\n >\n <Trans>Create</Trans>\n </Button>\n <Button\n size=\"small\"\n variant=\"subdued\"\n onClick={() => {\n setShowNewFolderInput(false)\n setNewFolderName(\"\")\n setNewFolderError(null)\n }}\n >\n <Trans>Cancel</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=\"text-theme-light mb-1\">\n <Trans>The object will be moved to this path. Navigate folders above to change the destination.</Trans>\n </p>\n <TextInput label={t`Target path`} value={targetPathDisplay} readOnly className=\"font-mono\" />\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 { Modal, Stack, Spinner, TextInput, Icon, Select, SelectOption } 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-[400px] items-center gap-1\">\n <span className=\"shrink-0\">\n <Trans>Share object:</Trans>\n </span>\n <span className=\"truncate font-mono\" 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`Close`}\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 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 <p className=\"text-theme-default\">\n <Trans>\n <strong>No Temp URL key configured.</strong> A temporary URL key must be set at the account or container\n level before temporary URLs can be generated. Contact your administrator to configure{\" \"}\n <code>X-Account-Meta-Temp-URL-Key</code> or <code>X-Container-Meta-Temp-URL-Key</code>.\n </Trans>\n </p>\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 font-mono 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 Spinner,\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 { 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 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 timeZone: \"UTC\",\n })\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-[400px] items-center gap-1\">\n <Trans>\n <span className=\"shrink-0\">Edit metadata:</span>{\" \"}\n <span className=\"truncate font-mono\" 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 <Stack direction=\"horizontal\" alignment=\"center\" gap=\"2\" className=\"py-8\">\n <Spinner size=\"small\" />\n <Trans>Loading object properties...</Trans>\n </Stack>\n ) : isMetaError ? (\n <p className=\"text-theme-error\">\n <Trans>Failed to load object metadata: {metadataErrorMessage}</Trans>\n </p>\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 className=\"font-mono\">{metadataRaw?.contentType ?? \"—\"}</span>\n\n <span className=\"text-theme-light text-right\">\n <Trans>MD5 checksum</Trans>\n </span>\n <span className=\"font-mono 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 font-mono 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 { useRef, useEffect, useState } from \"react\"\nimport { useVirtualizer } from \"@tanstack/react-virtual\"\nimport {\n Checkbox,\n DataGrid,\n DataGridHeadCell,\n DataGridRow,\n DataGridCell,\n PopupMenu,\n PopupMenuItem,\n PopupMenuOptions,\n Spinner,\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 { trpcClient, trpcReact } from \"@/client/trpcClient\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\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\"\n\n// MIME types natively previewable by all modern browsers.\n// Excludes types that require plugins or have inconsistent support.\nconst BROWSER_PREVIEWABLE_TYPES = new Set([\n // Images\n \"image/png\",\n \"image/jpeg\",\n \"image/gif\",\n \"image/webp\",\n \"image/avif\",\n \"image/bmp\",\n \"image/x-icon\",\n \"image/vnd.microsoft.icon\",\n // Video\n \"video/mp4\",\n \"video/webm\",\n \"video/ogg\",\n // Audio\n \"audio/mpeg\",\n \"audio/mp3\",\n \"audio/ogg\",\n \"audio/wav\",\n \"audio/webm\",\n \"audio/flac\",\n // Documents\n \"application/pdf\",\n // Safe text — plain content only, no script-executing types\n \"text/plain\",\n])\n\nconst isBrowserPreviewable = (contentType: string | undefined): boolean => {\n if (!contentType) return false\n // Strip parameters like charset (e.g. \"text/plain; charset=utf-8\" → \"text/plain\")\n const base = contentType.split(\";\")[0].trim().toLowerCase()\n if (BROWSER_PREVIEWABLE_TYPES.has(base)) return true\n // Allow image/*, video/*, audio/* subtypes broadly — these are passive media\n // that cannot execute scripts. Excluded: text/html, text/javascript, text/css,\n // application/json, application/xml and any other active/scriptable types.\n // image/svg+xml is also excluded — SVG can contain embedded <script> tags and\n // executes JavaScript when opened as a same-origin blob URL.\n if (base === \"image/svg+xml\") return false\n if (base.startsWith(\"image/\") || base.startsWith(\"video/\") || base.startsWith(\"audio/\")) return true\n return false\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 const parentRef = useRef<HTMLDivElement>(null)\n const isMounted = useRef(true)\n useEffect(() => {\n isMounted.current = true\n return () => {\n isMounted.current = false\n }\n }, [])\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 const [downloadingRow, setDownloadingRow] = useState<ObjectRow | null>(null)\n const [downloadId, setDownloadId] = useState<string | null>(null)\n const [previewingRow, setPreviewingRow] = useState<ObjectRow | null>(null)\n\n const { data: downloadProgress } = trpcReact.storage.swift.watchDownloadProgress.useSubscription(\n { downloadId: downloadId ?? \"\" },\n { enabled: !!downloadId && downloadingRow !== null }\n )\n\n // Shared streaming helper — fetches the object from the BFF and assembles a Blob.\n // downloadId is set before the mutation starts so the watchDownloadProgress\n // subscription is active from the very first byte.\n const streamObjectToBlob = async (\n row: ObjectRow,\n activeDownloadId: string\n ): Promise<{ blob: Blob; filename: string }> => {\n let contentType = row.content_type ?? \"application/octet-stream\"\n let filename = row.displayName\n\n const iterable = await trpcClient.storage.swift.downloadObject.mutate({\n project_id: projectId,\n container,\n object: row.name,\n filename: row.displayName,\n downloadId: activeDownloadId,\n ...(account ? { account } : {}),\n })\n\n const chunks: Uint8Array<ArrayBuffer>[] = []\n for await (const { chunk, contentType: ct, filename: fn } of iterable) {\n if (ct) contentType = ct\n if (fn) filename = fn\n chunks.push(Uint8Array.from(atob(chunk), (c) => c.charCodeAt(0)) as Uint8Array<ArrayBuffer>)\n }\n\n return { blob: new Blob(chunks, { type: contentType }), filename }\n }\n\n // Triggers a browser file-save for the given blob URL then revokes it after a\n // short delay to avoid racing the browser starting the download.\n const 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 const handleDownload = async (row: ObjectRow) => {\n const activeDownloadId = `${container}:${row.name}:${crypto.randomUUID()}`\n setDownloadingRow(row)\n setDownloadId(activeDownloadId)\n try {\n const { blob, filename } = await streamObjectToBlob(row, activeDownloadId)\n triggerAnchorDownload(URL.createObjectURL(blob), filename)\n } catch (err) {\n onDownloadError(row.displayName, err instanceof Error ? err.message : String(err))\n } finally {\n if (isMounted.current) {\n setDownloadingRow(null)\n setDownloadId(null)\n }\n }\n }\n\n const handlePreviewOrDownload = async (row: ObjectRow) => {\n const activeDownloadId = `${container}:${row.name}:${crypto.randomUUID()}`\n const previewing = isBrowserPreviewable(row.content_type)\n if (previewing) {\n setPreviewingRow(row)\n } else {\n setDownloadingRow(row)\n setDownloadId(activeDownloadId)\n }\n\n // Open a blank tab synchronously while still inside the click handler so\n // The popup is considered user-initiated and won't be blocked. Clear the\n // opener relationship immediately so previewed content cannot access the\n // current window, while still keeping the window reference for navigation\n // after streaming completes.\n const previewTab = previewing ? window.open(\"\", \"_blank\") : null\n if (previewTab) {\n previewTab.opener = null\n }\n\n try {\n const { blob, filename } = await streamObjectToBlob(row, activeDownloadId)\n const url = URL.createObjectURL(blob)\n if (previewing) {\n if (previewTab) {\n previewTab.location.href = url\n }\n // Revoke after a short delay to give the new tab time to load the blob\n setTimeout(() => URL.revokeObjectURL(url), 10000)\n } else {\n triggerAnchorDownload(url, filename)\n }\n } catch (err) {\n previewTab?.close()\n onDownloadError(row.displayName, err instanceof Error ? err.message : String(err))\n } finally {\n if (isMounted.current) {\n setPreviewingRow(null)\n setDownloadingRow(null)\n setDownloadId(null)\n }\n }\n }\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])\n\n const rowVirtualizer = useVirtualizer({\n count: rows.length,\n getScrollElement: () => parentRef.current,\n estimateSize: () => 48, // Estimated row height\n overscan: 10,\n })\n\n // Format date to localized string\n const formatDate = (dateString: string): string => {\n const d = new Date(dateString)\n return Number.isNaN(d.getTime()) ? t`N/A` : d.toLocaleString()\n }\n\n // Only object rows (not folders) are selectable\n const selectableRows = rows.filter((r): r is ObjectRow => r.kind === \"object\")\n const selectedSet = new Set(selectedObjects)\n const allSelected = selectableRows.length > 0 && selectableRows.every((r) => selectedSet.has(r.name))\n\n const handleSelectAll = () => {\n if (allSelected) {\n setSelectedObjects([])\n } else {\n setSelectedObjects(selectableRows.map((r) => r.name))\n }\n }\n\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 if (rows.length === 0) {\n return (\n <DataGrid columns={5} className=\"objects\" data-testid=\"no-objects\">\n <DataGridRow>\n <DataGridCell colSpan={5}>\n <div className=\"py-8 text-center\">\n <h3 className=\"text-lg font-semibold\">\n <Trans>No objects found</Trans>\n </h3>\n <p className=\"text-theme-light mt-2\">\n {searchTerm ? (\n <Trans>No objects match your search. Try adjusting your search term.</Trans>\n ) : (\n <Trans>This folder is empty.</Trans>\n )}\n </p>\n </div>\n </DataGridCell>\n </DataGridRow>\n </DataGrid>\n )\n }\n\n const isAnyDownloading = downloadingRow !== null || previewingRow !== null\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 <Checkbox checked={allSelected} onChange={handleSelectAll} data-testid=\"select-all-objects\" />\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 </DataGrid>\n </div>\n\n {/* Virtualized Table Body with dynamic height */}\n <div\n ref={parentRef}\n className=\"overflow-auto\"\n style={{ height: \"calc(100vh - 470px)\" }}\n data-testid=\"objects-table-body\"\n >\n <div\n style={{\n height: `${rowVirtualizer.getTotalSize()}px`,\n width: \"100%\",\n position: \"relative\",\n }}\n >\n {rowVirtualizer.getVirtualItems().map((virtualRow) => {\n const row = rows[virtualRow.index]\n const isFolder = row.kind === \"folder\"\n const isDownloading = !isFolder && downloadingRow?.name === row.name\n const rowDisplayName = row.displayName\n const isSelected = !isFolder && selectedObjects.includes(row.name)\n\n return (\n <div\n key={row.name}\n data-index={virtualRow.index}\n ref={rowVirtualizer.measureElement}\n className=\"juno-datagrid\"\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 <Checkbox\n checked={isSelected}\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 focus-visible:outline-2 disabled:cursor-wait disabled:opacity-60\"\n onClick={() => handlePreviewOrDownload(row as ObjectRow)}\n disabled={isAnyDownloading}\n data-testid={`preview-${row.name}`}\n title={\n isBrowserPreviewable((row as ObjectRow).content_type)\n ? t`Preview ${rowDisplayName}`\n : t`Download ${rowDisplayName}`\n }\n >\n {previewingRow?.name === row.name ? (\n <Spinner size=\"small\" className=\"shrink-0\" />\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 */}\n <DataGridCell>\n {isDownloading ? (\n <span className=\"flex min-w-0 flex-col gap-1\">\n {(() => {\n const progressPct = downloadProgress?.percent ?? null\n return (\n <>\n <span className=\"text-theme-light flex items-center gap-2 text-sm\">\n <Spinner size=\"small\" />\n {progressPct !== null ? <Trans>{progressPct}%</Trans> : <Trans>Downloading...</Trans>}\n </span>\n {progressPct !== 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: `${progressPct}%` }}\n />\n </div>\n )}\n </>\n )\n })()}\n </span>\n ) : !isFolder && row.last_modified ? (\n formatDate(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 disabled={isAnyDownloading}>\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`}\n disabled={isDownloading}\n onClick={() => handleDownload(row as ObjectRow)}\n data-testid={`download-action-${row.name}`}\n />\n <PopupMenuItem\n label={t`Edit Metadata`}\n onClick={() => setEditMetadataTarget(row as ObjectRow)}\n data-testid={`edit-metadata-action-${row.name}`}\n />\n <PopupMenuItem\n label={t`Copy`}\n onClick={() => setCopyObjectTarget(row as ObjectRow)}\n data-testid={`copy-action-${row.name}`}\n />\n <PopupMenuItem\n label={t`Move/Rename`}\n onClick={() => setMoveRenameObjectTarget(row as ObjectRow)}\n data-testid={`move-rename-action-${row.name}`}\n />\n <PopupMenuItem\n label={t`Share (Temporary URL)`}\n onClick={() => setTempUrlTarget(row as ObjectRow)}\n data-testid={`temp-url-action-${row.name}`}\n />\n <PopupMenuItem\n label={t`Delete`}\n onClick={() => setDeleteObjectTarget(row as ObjectRow)}\n data-testid={`delete-action-${row.name}`}\n />\n </>\n )}\n </PopupMenuOptions>\n </PopupMenu>\n </DataGridCell>\n </div>\n )\n })}\n </div>\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 } from \"@cloudoperators/juno-ui-components\"\nimport { useParams } from \"@tanstack/react-router\"\n\ninterface CreateFolderModalProps {\n isOpen: boolean\n currentPrefix: string\n onClose: () => void\n onSuccess?: (folderName: string) => void\n onError?: (folderName: string, errorMessage: string) => void\n}\n\nexport const CreateFolderModal = ({ isOpen, currentPrefix, onClose, onSuccess, onError }: 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\n const utils = trpcReact.useUtils()\n\n // useRef so the submitted name survives re-renders triggered by\n // createFolderMutation.reset() inside handleClose() before onSuccess/onError fire.\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 },\n onError: (error) => {\n onError?.(submittedNameRef.current, error.message)\n },\n onSettled: () => {\n handleClose()\n },\n })\n\n const handleClose = () => {\n setFolderName(\"\")\n setNameError(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 setNameError(null)\n return true\n }\n\n const handleNameChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const value = e.target.value\n setFolderName(value)\n if (nameError) validateName(value)\n }\n\n const handleSubmit = () => {\n if (!validateName(folderName)) return\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\") 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-[400px] items-center gap-1\">\n <span className=\"shrink-0\">\n <Trans>Create folder below:</Trans>\n </span>\n <span className=\"truncate font-mono\" 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 >\n <Stack direction=\"vertical\" gap=\"6\">\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-[400px] items-center gap-1\">\n <span className=\"shrink-0\">\n <Trans>Upload object to:</Trans>\n </span>\n <span className=\"truncate font-mono\" 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-mono 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 { Plural, Trans, useLingui } from \"@lingui/react/macro\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { Modal, Spinner, Stack } from \"@cloudoperators/juno-ui-components\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\n\n// Max number of object names shown in the list before truncating\nconst MAX_VISIBLE = 20\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 } = useLingui()\n const projectId = useProjectId()\n\n const utils = trpcReact.useUtils()\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 const handleClose = () => {\n bulkDeleteMutation.reset()\n onClose()\n }\n\n const handleConfirm = () => {\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 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={isPending ? t`Deleting...` : t`Delete`}\n confirmButtonVariant=\"primary-danger\"\n cancelButtonLabel={t`Cancel`}\n onConfirm={handleConfirm}\n disableConfirmButton={isPending}\n disableCancelButton={isPending}\n disableCloseButton={isPending}\n size=\"small\"\n >\n {isPending ? (\n <Stack distribution=\"center\" alignment=\"center\" className=\"py-4\">\n <Spinner variant=\"primary\" />\n </Stack>\n ) : (\n <div className=\"my-6\">\n <p className=\"text-theme-default mb-6\">\n <Trans>The selected objects will be permanently deleted. This cannot be undone.</Trans>\n </p>\n\n <div className=\"mb-6\">\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 font-mono 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 </div>\n )}\n </Modal>\n )\n}\n","import { ReactNode } from \"react\"\nimport { ToastProps } from \"@cloudoperators/juno-ui-components\"\nimport { Trans } from \"@lingui/react/macro\"\nimport { Stack } from \"@cloudoperators/juno-ui-components/index\"\n\ninterface NotificationTextProps {\n title: ReactNode\n description: ReactNode\n}\n\nfunction NotificationText({ title, description }: NotificationTextProps) {\n return (\n <Stack direction=\"vertical\" gap=\"1.5\">\n <span>{title}</span>\n <span className=\"text-theme-light\">{description}</span>\n </Stack>\n )\n}\n\ninterface ToastConfig {\n onDismiss: () => void\n}\n\nexport const getFolderCreatedToast = (folderName: string, config: ToastConfig): ToastProps => ({\n variant: \"success\",\n onDismiss: config.onDismiss,\n children: (\n <NotificationText\n title={<Trans>Folder Created</Trans>}\n description={<Trans>Folder \"{folderName}\" was successfully created.</Trans>}\n />\n ),\n})\n\nexport const getFolderCreateErrorToast = (\n folderName: string,\n errorMessage: string,\n config: ToastConfig\n): ToastProps => ({\n variant: \"error\",\n onDismiss: config.onDismiss,\n children: (\n <NotificationText\n title={<Trans>Failed to Create Folder</Trans>}\n description={\n <Trans>\n Could not create folder \"{folderName}\": {errorMessage}\n </Trans>\n }\n />\n ),\n})\n\nexport const getFolderDeletedToast = (folderName: string, deletedCount: number, config: ToastConfig): ToastProps => ({\n variant: \"success\",\n onDismiss: config.onDismiss,\n children: (\n <NotificationText\n title={<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 was permanently deleted.\n </Trans>\n ) : (\n <Trans>\n Folder \"{folderName}\" and {deletedCount} objects were permanently deleted.\n </Trans>\n )\n }\n />\n ),\n})\n\nexport const getFolderDeleteErrorToast = (\n folderName: string,\n errorMessage: string,\n config: ToastConfig\n): ToastProps => ({\n variant: \"error\",\n onDismiss: config.onDismiss,\n children: (\n <NotificationText\n title={<Trans>Failed to Delete Folder</Trans>}\n description={\n <Trans>\n Could not delete folder \"{folderName}\": {errorMessage}\n </Trans>\n }\n />\n ),\n})\n\nexport const getObjectDownloadErrorToast = (\n objectName: string,\n errorMessage: string,\n config: ToastConfig\n): ToastProps => ({\n variant: \"error\",\n onDismiss: config.onDismiss,\n children: (\n <NotificationText\n title={<Trans>Failed to Download</Trans>}\n description={\n <Trans>\n Could not download \"{objectName}\": {errorMessage}\n </Trans>\n }\n />\n ),\n})\n\nexport const getObjectDeletedToast = (objectName: string, config: ToastConfig): ToastProps => ({\n variant: \"success\",\n onDismiss: config.onDismiss,\n children: (\n <NotificationText\n title={<Trans>Object Deleted</Trans>}\n description={<Trans>Object \"{objectName}\" was permanently deleted.</Trans>}\n />\n ),\n})\n\nexport const getObjectDeleteErrorToast = (\n objectName: string,\n errorMessage: string,\n config: ToastConfig\n): ToastProps => ({\n variant: \"error\",\n onDismiss: config.onDismiss,\n children: (\n <NotificationText\n title={<Trans>Failed to Delete Object</Trans>}\n description={\n <Trans>\n Could not delete \"{objectName}\": {errorMessage}\n </Trans>\n }\n />\n ),\n})\n\nexport const getObjectCopiedToast = (\n objectName: string,\n targetContainer: string,\n targetPath: string,\n config: ToastConfig\n): ToastProps => {\n const destination = targetPath ? `${targetContainer}/${targetPath}` : targetContainer\n return {\n variant: \"success\",\n onDismiss: config.onDismiss,\n children: (\n <NotificationText\n title={<Trans>Object Copied</Trans>}\n description={\n <Trans>\n \"{objectName}\" was successfully copied to {destination}.\n </Trans>\n }\n />\n ),\n }\n}\n\nexport const getObjectCopyErrorToast = (objectName: string, errorMessage: string, config: ToastConfig): ToastProps => ({\n variant: \"error\",\n onDismiss: config.onDismiss,\n children: (\n <NotificationText\n title={<Trans>Failed to Copy Object</Trans>}\n description={\n <Trans>\n Could not copy \"{objectName}\": {errorMessage}\n </Trans>\n }\n />\n ),\n})\n\nexport const getObjectMovedToast = (\n objectName: string,\n targetContainer: string,\n targetPath: string,\n config: ToastConfig\n): ToastProps => {\n const destination = targetPath ? `${targetContainer}/${targetPath}` : targetContainer\n return {\n variant: \"success\",\n onDismiss: config.onDismiss,\n children: (\n <NotificationText\n title={<Trans>Object Moved</Trans>}\n description={\n <Trans>\n \"{objectName}\" was successfully moved to {destination}.\n </Trans>\n }\n />\n ),\n }\n}\n\nexport const getObjectMoveErrorToast = (objectName: string, errorMessage: string, config: ToastConfig): ToastProps => ({\n variant: \"error\",\n onDismiss: config.onDismiss,\n children: (\n <NotificationText\n title={<Trans>Failed to Move Object</Trans>}\n description={\n <Trans>\n Could not move \"{objectName}\": {errorMessage}\n </Trans>\n }\n />\n ),\n})\n\nexport const getTempUrlCopiedToast = (objectName: string, config: ToastConfig): ToastProps => ({\n variant: \"success\",\n onDismiss: config.onDismiss,\n children: (\n <NotificationText\n title={<Trans>URL Copied</Trans>}\n description={<Trans>Temporary URL for \"{objectName}\" was copied to clipboard.</Trans>}\n />\n ),\n})\n\nexport const getObjectMetadataUpdatedToast = (objectName: string, config: ToastConfig): ToastProps => ({\n variant: \"success\",\n onDismiss: config.onDismiss,\n children: (\n <NotificationText\n title={<Trans>Object Updated</Trans>}\n description={<Trans>Properties of \"{objectName}\" were successfully updated.</Trans>}\n />\n ),\n})\n\nexport const getObjectMetadataUpdateErrorToast = (\n objectName: string,\n errorMessage: string,\n config: ToastConfig\n): ToastProps => ({\n variant: \"error\",\n onDismiss: config.onDismiss,\n children: (\n <NotificationText\n title={<Trans>Failed to Update Object</Trans>}\n description={\n <Trans>\n Could not update \"{objectName}\": {errorMessage}\n </Trans>\n }\n />\n ),\n})\n\nexport const getObjectUploadedToast = (objectName: string, config: ToastConfig): ToastProps => ({\n variant: \"success\",\n onDismiss: config.onDismiss,\n children: (\n <NotificationText\n title={<Trans>Object Uploaded</Trans>}\n description={<Trans>\"{objectName}\" was successfully uploaded.</Trans>}\n />\n ),\n})\n\nexport const getObjectUploadCancelledToast = (objectName: string, config: ToastConfig): ToastProps => ({\n variant: \"warning\",\n onDismiss: config.onDismiss,\n children: (\n <NotificationText\n title={<Trans>Upload Cancelled</Trans>}\n description={<Trans>Upload of \"{objectName}\" was cancelled.</Trans>}\n />\n ),\n})\n\nexport const getObjectUploadErrorToast = (\n objectName: string,\n errorMessage: string,\n config: ToastConfig\n): ToastProps => ({\n variant: \"error\",\n onDismiss: config.onDismiss,\n children: (\n <NotificationText\n title={<Trans>Failed to Upload Object</Trans>}\n description={\n <Trans>\n Could not upload \"{objectName}\": {errorMessage}\n </Trans>\n }\n />\n ),\n})\n\nexport const getObjectsBulkDeletedToast = (numberDeleted: number, config: ToastConfig): ToastProps => ({\n variant: \"success\",\n onDismiss: config.onDismiss,\n children: (\n <NotificationText\n title={<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 />\n ),\n})\n\nexport const getObjectsBulkDeleteErrorToast = (errorMessage: string, config: ToastConfig): ToastProps => ({\n variant: \"error\",\n onDismiss: config.onDismiss,\n children: (\n <NotificationText\n title={<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 ),\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 Spinner,\n Stack,\n Toast,\n ToastProps,\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 { 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 getFolderCreatedToast,\n getFolderCreateErrorToast,\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 3 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 const [toastData, setToastData] = useState<ToastProps | null>(null)\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 handleToastDismiss = () => setToastData(null)\n\n const handleCreateFolderSuccess = (folderName: string) =>\n setToastData(getFolderCreatedToast(folderName, { onDismiss: handleToastDismiss }))\n const handleCreateFolderError = (folderName: string, errorMessage: string) =>\n setToastData(getFolderCreateErrorToast(folderName, errorMessage, { onDismiss: handleToastDismiss }))\n const handleUploadSuccess = (objectName: string) =>\n setToastData(getObjectUploadedToast(objectName, { onDismiss: handleToastDismiss }))\n const handleUploadCancelled = (objectName: string) =>\n setToastData(getObjectUploadCancelledToast(objectName, { onDismiss: handleToastDismiss }))\n const handleUploadError = (objectName: string, errorMessage: string) =>\n setToastData(getObjectUploadErrorToast(objectName, errorMessage, { onDismiss: handleToastDismiss }))\n const handleDeleteFolderSuccess = (folderName: string, deletedCount: number) => {\n const nestedCount = Math.max(0, deletedCount - 1)\n setToastData(getFolderDeletedToast(folderName, nestedCount, { onDismiss: handleToastDismiss }))\n }\n const handleDeleteFolderError = (folderName: string, errorMessage: string) =>\n setToastData(getFolderDeleteErrorToast(folderName, errorMessage, { onDismiss: handleToastDismiss }))\n const handleDownloadError = (objectName: string, errorMessage: string) =>\n setToastData(getObjectDownloadErrorToast(objectName, errorMessage, { onDismiss: handleToastDismiss }))\n const handleDeleteObjectSuccess = (objectName: string) => {\n setSelectedObjects((prev) => prev.filter((name) => name !== objectName))\n setToastData(getObjectDeletedToast(objectName, { onDismiss: handleToastDismiss }))\n }\n const handleDeleteObjectError = (objectName: string, errorMessage: string) =>\n setToastData(getObjectDeleteErrorToast(objectName, errorMessage, { onDismiss: handleToastDismiss }))\n const handleCopyObjectSuccess = (objectName: string, targetContainer: string, targetPath: string) =>\n setToastData(getObjectCopiedToast(objectName, targetContainer, targetPath, { onDismiss: handleToastDismiss }))\n const handleCopyObjectError = (objectName: string, errorMessage: string) =>\n setToastData(getObjectCopyErrorToast(objectName, errorMessage, { onDismiss: handleToastDismiss }))\n const handleMoveObjectSuccess = (objectName: string, targetContainer: string, targetPath: string) => {\n setSelectedObjects((prev) => prev.filter((name) => name !== objectName))\n setToastData(getObjectMovedToast(objectName, targetContainer, targetPath, { onDismiss: handleToastDismiss }))\n }\n const handleMoveObjectError = (objectName: string, errorMessage: string) =>\n setToastData(getObjectMoveErrorToast(objectName, errorMessage, { onDismiss: handleToastDismiss }))\n const handleTempUrlCopySuccess = (objectName: string) =>\n setToastData(getTempUrlCopiedToast(objectName, { onDismiss: handleToastDismiss }))\n const handleEditMetadataSuccess = (objectName: string) =>\n setToastData(getObjectMetadataUpdatedToast(objectName, { onDismiss: handleToastDismiss }))\n const handleEditMetadataError = (objectName: string, errorMessage: string) =>\n setToastData(getObjectMetadataUpdateErrorToast(objectName, errorMessage, { onDismiss: handleToastDismiss }))\n\n const handleBulkDeleteSuccess = (numberDeleted: number) => {\n setSelectedObjects([])\n setToastData(getObjectsBulkDeletedToast(numberDeleted, { onDismiss: handleToastDismiss }))\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 setToastData(getObjectsBulkDeleteErrorToast(errorMessage, { onDismiss: handleToastDismiss }))\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 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 comparison = new Date(aDate).getTime() - new Date(bDate).getTime()\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 (\n <Stack className=\"absolute inset-0\" distribution=\"center\" alignment=\"center\" direction=\"vertical\">\n <Spinner variant=\"primary\" size=\"large\" className=\"mb-2\" />\n <Trans>Loading Objects...</Trans>\n </Stack>\n )\n }\n\n if (error) {\n const errorMessage = error.message\n return (\n <Stack className=\"absolute inset-0\" distribution=\"center\" alignment=\"center\" direction=\"vertical\">\n <Trans>Error Loading Objects: {errorMessage}</Trans>\n </Stack>\n )\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 3 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 <ObjectsFileNavigation\n containerName={containerName}\n currentPrefix={currentPrefix}\n onContainersClick={navigateToContainers}\n onPrefixClick={navigateToPrefix}\n />\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 onSortByChange={(v) =>\n handleSortChange({ ...sortSettings, sortBy: v, sortDirection: sortSettings.sortDirection })\n }\n onSortDirectionChange={(dir) => handleSortChange({ ...sortSettings, sortDirection: dir })}\n />\n </Stack>\n <Button variant=\"primary\" className=\"whitespace-nowrap\" onClick={() => setCreateFolderModalOpen(true)}>\n <Trans>Create Folder</Trans>\n </Button>\n <Button className=\"whitespace-nowrap\" onClick={() => setUploadModalOpen(true)}>\n <Trans>Upload Object</Trans>\n </Button>\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 — bulk actions (gated) plus the item count. */}\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 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 onError={handleCreateFolderError}\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\n {toastData && (\n <Toast {...toastData} className=\"border-theme-light fixed top-5 right-5 z-50 rounded-lg border shadow-lg\" />\n )}\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 { formatBytesBinary } from \"@/client/utils/formatBytes\"\n\ninterface DeleteObjectModalProps {\n bucketName: string\n objectKey: string\n objectSize?: number\n lastModified?: string\n isOpen: 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 onClose,\n onSuccess,\n onError,\n}: DeleteObjectModalProps) {\n const { t } = useLingui()\n const projectId = useProjectId()\n const [confirmText, setConfirmText] = useState(\"\")\n const utils = trpcReact.useUtils()\n\n const deleteMutation = trpcReact.storage.ceph.objects.delete.useMutation({\n onSuccess: () => {\n utils.storage.ceph.objects.list.invalidate()\n onSuccess(objectKey)\n handleClose()\n },\n onError: (error) => {\n onError(objectKey, error.message)\n },\n })\n\n const handleClose = () => {\n setConfirmText(\"\")\n deleteMutation.reset()\n onClose()\n }\n\n const handleConfirm = () => {\n if (!projectId) return\n\n deleteMutation.mutate({\n project_id: projectId,\n containerName: bucketName,\n objectKey,\n })\n }\n\n const isFolder = objectKey.endsWith(\"/\")\n const displayName = objectKey.split(\"/\").filter(Boolean).pop() || objectKey\n const isConfirmValid = confirmText === \"DELETE\"\n\n return (\n <Modal\n open={isOpen}\n onCancel={handleClose}\n title={isFolder ? <Trans>Delete Folder</Trans> : <Trans>Delete Object</Trans>}\n size=\"large\"\n confirmButtonLabel={deleteMutation.isPending ? t`Deleting...` : t`Delete`}\n confirmButtonVariant=\"primary-danger\"\n onConfirm={handleConfirm}\n cancelButtonLabel={t`Cancel`}\n disableConfirmButton={!isConfirmValid || deleteMutation.isPending}\n disableCancelButton={deleteMutation.isPending}\n disableCloseButton={deleteMutation.isPending}\n >\n <Stack direction=\"vertical\" gap=\"4\">\n <Message variant=\"danger\">\n {isFolder ? (\n <Trans>\n Confirm deletion of {displayName}. This action cannot be undone and folder will be permanently deleted.\n </Trans>\n ) : (\n <Trans>\n Confirm deletion of {displayName}. This action cannot be undone and object will be permanently deleted.\n </Trans>\n )}\n </Message>\n\n <div className=\"bg-theme-background-lvl-2 rounded p-4\">\n <Stack direction=\"vertical\" gap=\"2\">\n <div>\n <span className=\"text-theme-light text-sm\">\n <Trans>Name:</Trans>\n </span>\n <div className=\"mt-1 text-sm\">{displayName}</div>\n </div>\n\n {!isFolder && objectSize !== undefined && (\n <div>\n <span className=\"text-theme-light text-sm\">\n <Trans>Size:</Trans>\n </span>\n <div className=\"mt-1 text-sm\">{formatBytesBinary(objectSize)}</div>\n </div>\n )}\n\n {!isFolder && lastModified && (\n <div>\n <span className=\"text-theme-light text-sm\">\n <Trans>Last Modified:</Trans>\n </span>\n <div className=\"mt-1 text-sm\">{new Date(lastModified).toLocaleString()}</div>\n </div>\n )}\n\n <div>\n <span className=\"text-theme-light text-sm\">\n <Trans>Full Path:</Trans>\n </span>\n <div className=\"mt-1 text-sm break-all\">{objectKey}</div>\n </div>\n </Stack>\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 helptext={t`This action cannot be undone.`}\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 </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 : []\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 { Modal, Stack, Spinner, ComboBox, ComboBoxOption, TextInput, Button } 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 [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 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 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 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 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-[500px] 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`}\n onConfirm={handleCopy}\n cancelButtonLabel={t`Cancel`}\n size=\"large\"\n disableConfirmButton={isPending || isLoadingBuckets || isUnchanged}\n >\n {isPending ? (\n <Stack direction=\"horizontal\" alignment=\"center\" gap=\"2\" className=\"py-8\">\n <Spinner size=\"small\" />\n <Trans>Copying object...</Trans>\n </Stack>\n ) : (\n <Stack direction=\"vertical\" gap=\"4\">\n {/* Source object info */}\n <div className=\"bg-theme-background-lvl-2 rounded p-3\">\n <div className=\"text-theme-light text-sm\">\n <Trans>Source:</Trans>\n </div>\n <div className=\"mt-1 text-sm\">{`${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\n {/* Target bucket — ComboBox with debounced search */}\n <ComboBox\n label={t`Target bucket`}\n value={modalState.targetBucket}\n onChange={handleBucketChange}\n onInputChange={modalState.handleSearchChange}\n placeholder={t`Type to search buckets...`}\n helptext={(() => {\n if (isLoadingBuckets) return t`Loading buckets...`\n if (modalState.searchTerm.trim().length === 0) return t`Start typing to search for a bucket`\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.visibleBuckets.map((b) => (\n <ComboBoxOption key={b.name} value={b.name}>\n {b.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={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 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 {/* Read-only target path */}\n <div>\n <p className=\"text-theme-light mb-1\">\n <Trans>The object will be copied to this path. Navigate folders above to change the destination.</Trans>\n </p>\n <TextInput label={t`Target path`} value={targetPathDisplay} readOnly />\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 { Modal, Stack, Spinner, ComboBox, ComboBoxOption, TextInput, Button } from \"@cloudoperators/juno-ui-components\"\nimport { MdFolder, MdDescription, MdCreateNewFolder, MdArrowBack, MdWarning } 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 [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 // 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 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 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 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-[500px] 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={handleClose}\n confirmButtonLabel={isPending ? t`Moving...` : t`Move`}\n onConfirm={handleMove}\n cancelButtonLabel={t`Cancel`}\n size=\"large\"\n disableConfirmButton={isPending || isLoadingBuckets || isUnchanged}\n >\n {isPending ? (\n <Stack direction=\"horizontal\" alignment=\"center\" gap=\"2\" className=\"py-8\">\n <Spinner size=\"small\" />\n <Trans>Moving object...</Trans>\n </Stack>\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 {/* Warning banner */}\n <div className=\"text-theme-default flex items-start gap-2\">\n <MdWarning size={20} className=\"shrink-0\" />\n <div>\n <strong>\n <Trans>Warning:</Trans>\n </strong>{\" \"}\n <Trans>This will delete the original object after copying it to the destination.</Trans>\n </div>\n </div>\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 {/* Source object info */}\n <div className=\"bg-theme-background-lvl-2 rounded p-3\">\n <div className=\"text-theme-light text-sm\">\n <Trans>Source:</Trans>\n </div>\n <div className=\"mt-1 text-sm\">{`${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\n {/* Target bucket */}\n <ComboBox\n label={t`Target bucket`}\n value={modalState.targetBucket}\n onChange={handleBucketChange}\n onInputChange={modalState.handleSearchChange}\n placeholder={t`Type to search buckets...`}\n helptext={(() => {\n if (isLoadingBuckets) return t`Loading buckets...`\n if (modalState.searchTerm.trim().length === 0) return t`Start typing to search for a bucket`\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.visibleBuckets.map((b) => (\n <ComboBoxOption key={b.name} value={b.name}>\n {b.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={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 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 {/* Target path preview */}\n <div>\n <p className=\"text-theme-light mb-1\">\n {isUnchanged ? (\n <Trans>\n Cannot move to the same location. Please select a different bucket, folder, or change the name.\n </Trans>\n ) : (\n <Trans>The object will be moved to this path. Navigate folders above to change the destination.</Trans>\n )}\n </p>\n <TextInput label={t`Target path`} value={targetPathDisplay} readOnly invalid={isUnchanged} />\n </div>\n\n {/* Info: metadata is always copied */}\n <p className=\"text-theme-default\">\n <Trans>Object metadata will be automatically copied during the move operation.</Trans>\n </p>\n </Stack>\n )}\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 Spinner,\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 // ── 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 onClose()\n }\n\n const handleSubmit = () => {\n if (!projectId) return\n\n if (isSizeExceeded) {\n return\n }\n\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-[400px] 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=\"large\"\n disableConfirmButton={isBusy || !hasChanges || hasEditing || isAddingNew || isSizeExceeded}\n >\n {isLoading ? (\n <Stack direction=\"horizontal\" alignment=\"center\" gap=\"2\" className=\"py-8\">\n <Spinner size=\"small\" />\n <Trans>Loading object properties...</Trans>\n </Stack>\n ) : isMetaError ? (\n <p className=\"text-theme-error\" role=\"alert\">\n <Trans>Failed to load object metadata: {metadataErrorMessage}</Trans>\n </p>\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 className=\"font-mono\">{objectDetails?.contentType ?? \"—\"}</span>\n\n <span className=\"text-theme-light text-right\">\n <Trans>ETag</Trans>\n </span>\n <span className=\"font-mono 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\n className={`font-mono text-xs ${isSizeExceeded ? \"text-theme-danger font-semibold\" : \"text-theme-light\"}`}\n >\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}>\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=\"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 { Trans, useLingui } from \"@lingui/react/macro\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { Modal, Stack, Message } from \"@cloudoperators/juno-ui-components\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport { formatBytesBinary } from \"@/client/utils/formatBytes\"\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\n const utils = trpcReact.useUtils()\n\n const restoreMutation = trpcReact.storage.ceph.versioning.restoreVersion.useMutation({\n onSuccess: () => {\n utils.storage.ceph.versioning.listObjectVersions.invalidate()\n utils.storage.ceph.objects.list.invalidate()\n onSuccess?.(objectKey, versionId)\n onClose()\n },\n onError: (error) => {\n onError?.(objectKey, error.message)\n onClose()\n },\n onSettled: () => {\n restoreMutation.reset()\n },\n })\n\n const handleRestore = () => {\n restoreMutation.mutate({\n project_id: projectId,\n bucket: bucketName,\n key: objectKey,\n versionId,\n })\n }\n\n if (!isOpen) return null\n\n return (\n <Modal\n title={t`Restore Version`}\n open={isOpen}\n onCancel={onClose}\n confirmButtonLabel={t`Restore Version`}\n onConfirm={handleRestore}\n cancelButtonLabel={t`Cancel`}\n disableConfirmButton={restoreMutation.isPending}\n >\n <Stack direction=\"vertical\" gap=\"4\">\n <Message variant=\"info\" title={t`How Restore Works`}>\n <Trans>\n This creates a new latest version with the content from the selected version. All existing versions\n (including the current latest) are preserved.\n </Trans>\n </Message>\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 <Message variant=\"warning\">\n <Trans>After restoring, this version's content will become the new latest version.</Trans>\n </Message>\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, Message, TextInput } from \"@cloudoperators/juno-ui-components\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport { formatBytesBinary } from \"@/client/utils/formatBytes\"\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 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 onClose,\n onSuccess,\n onError,\n}: DeleteVersionModalProps) => {\n const { t } = useLingui()\n const projectId = useProjectId()\n const [confirmText, setConfirmText] = useState(\"\")\n\n const utils = trpcReact.useUtils()\n\n const deleteMutation = trpcReact.storage.ceph.versioning.deleteVersion.useMutation({\n onSuccess: () => {\n utils.storage.ceph.versioning.listObjectVersions.invalidate()\n utils.storage.ceph.objects.list.invalidate()\n onSuccess?.(objectKey, versionId)\n handleClose()\n },\n onError: (error) => {\n onError?.(objectKey, error.message)\n handleClose()\n },\n onSettled: () => {\n deleteMutation.reset()\n },\n })\n\n const handleClose = () => {\n setConfirmText(\"\")\n onClose()\n }\n\n const handleDelete = () => {\n if (confirmText !== \"DELETE\") return\n\n deleteMutation.mutate({\n project_id: projectId,\n bucket: bucketName,\n key: objectKey,\n versionId,\n })\n }\n\n if (!isOpen) return null\n\n return (\n <Modal\n title={t`Delete Version Permanently`}\n open={isOpen}\n onCancel={handleClose}\n confirmButtonLabel={t`Delete Permanently`}\n onConfirm={handleDelete}\n cancelButtonLabel={t`Cancel`}\n disableConfirmButton={confirmText !== \"DELETE\" || deleteMutation.isPending}\n >\n <Stack direction=\"vertical\" gap=\"4\">\n <Message variant=\"error\" title={t`⚠️ Warning: Irreversible Action`}>\n <Trans>\n This will permanently delete this version. This operation cannot be undone. The version will be lost\n forever.\n </Trans>\n </Message>\n\n {isDeleteMarker && (\n <Message variant=\"info\">\n <Trans>\n This is a delete marker. Deleting it will \"undelete\" the object and restore the previous version as the\n current version.\n </Trans>\n </Message>\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 {!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 <label className=\"text-sm font-semibold\">\n <Trans>\n Type <code>DELETE</code> to confirm:\n </Trans>\n </label>\n <TextInput\n value={confirmText}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) => setConfirmText(e.target.value)}\n placeholder=\"DELETE\"\n className=\"mt-2\"\n disabled={deleteMutation.isPending}\n />\n </div>\n </Stack>\n </Modal>\n )\n}\n","import { useEffect, useState } from \"react\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport type { ObjectVersion } from \"@/server/Storage/types/versioning\"\nimport {\n Modal,\n Stack,\n Message,\n DataGrid,\n DataGridRow,\n DataGridCell,\n DataGridHeadCell,\n Badge,\n PopupMenu,\n PopupMenuItem,\n PopupMenuOptions,\n Spinner,\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}\n\nexport const ObjectVersionHistoryModal = ({\n isOpen,\n bucketName,\n objectKey,\n onClose,\n onRestoreVersion,\n onDeleteVersion,\n}: ObjectVersionHistoryModalProps) => {\n const { t } = useLingui()\n const projectId = useProjectId()\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\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 onClose()\n }\n\n if (!isOpen) return null\n\n return (\n <Modal title={t`Version History: ${objectKey}`} open={isOpen} onCancel={handleClose} size=\"large\">\n <Stack direction=\"vertical\" gap=\"4\">\n {isLoading && (\n <Stack direction=\"horizontal\" gap=\"2\" alignment=\"center\" className=\"py-8\">\n <Spinner />\n <span className=\"text-theme-light text-sm\">\n <Trans>Loading versions...</Trans>\n </span>\n </Stack>\n )}\n\n {error && (\n <Message variant=\"error\" title={t`Failed to load versions`}>\n {error.message}\n </Message>\n )}\n\n {!isLoading && !error && versions.length === 0 && (\n <Message variant=\"info\">\n <Trans>No versions found for this object.</Trans>\n </Message>\n )}\n\n {!isLoading && !error && versions.length > 0 && (\n <>\n <Message variant=\"info\">\n <Trans>\n Showing all versions of this object. The latest version is highlighted. Delete markers indicate when the\n object was deleted.\n </Trans>\n </Message>\n\n <DataGrid columns={6}>\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=\"font-mono 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 <PopupMenu>\n <PopupMenuOptions>\n {!isDeleteMarker && (\n <>\n <PopupMenuItem\n label={t`Download`}\n onClick={() => {\n // TODO: Generate download URL with versionId\n console.log(\"Download version:\", version.versionId)\n }}\n />\n {!isLatest && (\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 </>\n )}\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 </PopupMenuOptions>\n </PopupMenu>\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 onRestoreVersion?.(objectKey, versionId)\n // Invalidate is handled by RestoreVersionModal, but we refetch to ensure immediate update\n setTimeout(() => refetch(), 100)\n }}\n onError={() => {\n setRestoreTarget(null)\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 onDeleteVersion?.(objectKey, versionId)\n // Invalidate is handled by DeleteVersionModal, but we refetch to ensure immediate update\n setTimeout(() => refetch(), 100)\n }}\n onError={() => {\n setDeleteTarget(null)\n }}\n />\n </Modal>\n )\n}\n","import { useRef, useEffect, useState } from \"react\"\nimport { useVirtualizer } from \"@tanstack/react-virtual\"\nimport {\n DataGrid,\n DataGridRow,\n DataGridCell,\n DataGridHeadCell,\n PopupMenu,\n PopupMenuItem,\n PopupMenuOptions,\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 type { S3Object, S3FolderPrefix } from \"@/server/Storage/types/ceph\"\nimport { DeleteObjectModal } from \"./DeleteObjectModal\"\nimport { CopyObjectModal } from \"./CopyObjectModal\"\nimport { MoveObjectModal } from \"./MoveObjectModal\"\nimport { EditMetadataModal } from \"./EditMetadataModal\"\nimport { ObjectVersionHistoryModal } from \"./ObjectVersionHistoryModal\"\n\ntype FolderRow = { kind: \"folder\"; prefix: string; displayName: string }\ntype ObjectRow = {\n kind: \"object\"\n key: string\n size: number\n lastModified: string | undefined\n displayName: string\n}\ntype CephRow = FolderRow | ObjectRow\n\n// Define column template — 4 columns: name | size | last modified | actions\nconst GRID_COLUMN_TEMPLATE = \"minmax(200px, 3fr) minmax(100px, 1fr) minmax(180px, 2fr) 60px\"\n\ninterface ObjectsTableViewProps {\n bucketName: string\n objects: S3Object[]\n folders: S3FolderPrefix[]\n currentPrefix: string\n versioningEnabled?: boolean\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 onRestoreVersion?: (objectKey: string, versionId: string) => void\n onDeleteVersion?: (objectKey: string, versionId: string) => void\n}\n\nexport function ObjectsTableView({\n bucketName,\n objects,\n folders,\n currentPrefix,\n versioningEnabled = false,\n onFolderClick,\n onDeleteObjectSuccess,\n onDeleteObjectError,\n onCopyObjectSuccess,\n onCopyObjectError,\n onMoveObjectSuccess,\n onMoveObjectError,\n onEditMetadataSuccess,\n onEditMetadataError,\n onRestoreVersion,\n onDeleteVersion,\n}: ObjectsTableViewProps) {\n const { t } = useLingui()\n const parentRef = useRef<HTMLDivElement>(null)\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 [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\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\n const rows: CephRow[] = [\n ...folders.map(\n (f): FolderRow => ({\n kind: \"folder\",\n prefix: f.prefix,\n displayName: stripPrefix(f.prefix).replace(/\\/$/, \"\"),\n })\n ),\n ...objects.map(\n (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\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])\n\n const rowVirtualizer = useVirtualizer({\n count: rows.length,\n getScrollElement: () => parentRef.current,\n estimateSize: () => 48,\n overscan: 10,\n })\n\n if (rows.length === 0) {\n return (\n <>\n <DataGrid columns={4}>\n <DataGridRow>\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 />\n </DataGridRow>\n <DataGridRow>\n <DataGridCell colSpan={4}>\n <div className=\"py-8 text-center\">\n <p className=\"text-theme-light\">\n <Trans>No objects found.</Trans>\n </p>\n </div>\n </DataGridCell>\n </DataGridRow>\n </DataGrid>\n <DeleteObjectModal\n bucketName={bucketName}\n objectKey={deleteTarget?.key ?? \"\"}\n objectSize={deleteTarget?.size}\n lastModified={deleteTarget?.lastModified}\n isOpen={deleteTarget !== null}\n onClose={() => setDeleteTarget(null)}\n onSuccess={onDeleteObjectSuccess}\n onError={onDeleteObjectError}\n />\n </>\n )\n }\n\n return (\n <>\n <div className=\"relative\">\n {/* Table Header with scrollbar padding */}\n <div style={{ paddingRight: `${scrollbarWidth}px` }}>\n <DataGrid columns={4} gridColumnTemplate={GRID_COLUMN_TEMPLATE} data-testid=\"objects-table-header\">\n <DataGridRow>\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 </DataGrid>\n </div>\n\n {/* Virtualized Table Body with dynamic height */}\n <div\n ref={parentRef}\n className=\"overflow-auto\"\n style={{ height: \"calc(100vh - 500px)\" }}\n data-testid=\"objects-table-body\"\n >\n <div\n style={{\n height: `${rowVirtualizer.getTotalSize()}px`,\n width: \"100%\",\n position: \"relative\",\n }}\n >\n {rowVirtualizer.getVirtualItems().map((virtualRow) => {\n const row = rows[virtualRow.index]\n const isFolder = row.kind === \"folder\"\n\n return (\n <div\n key={isFolder ? row.prefix : row.key}\n data-index={virtualRow.index}\n ref={rowVirtualizer.measureElement}\n className=\"juno-datagrid\"\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: GRID_COLUMN_TEMPLATE,\n alignItems: \"stretch\",\n }}\n data-testid={isFolder ? `folder-row-${row.prefix}` : `object-row-${row.key}`}\n >\n {/* Name */}\n <DataGridCell>\n {isFolder ? (\n <button\n type=\"button\"\n className=\"flex min-w-0 items-center gap-2 rounded text-left hover:underline focus-visible:outline focus-visible:outline-2\"\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 ) : (\n <div className=\"flex items-center gap-2\">\n <MdDescription size={18} className=\"text-theme-light shrink-0\" />\n <span className=\"truncate text-sm\">{row.displayName}</span>\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>\n <span className=\"text-sm\">\n {!isFolder && row.lastModified ? new Date(row.lastModified).toLocaleString() : \"—\"}\n </span>\n </DataGridCell>\n\n {/* Actions */}\n <DataGridCell onClick={(e) => e.stopPropagation()}>\n <div className=\"flex justify-end\">\n <PopupMenu>\n <PopupMenuOptions>\n {isFolder ? (\n <PopupMenuItem label={t`Delete`} onClick={() => setDeleteTarget({ key: row.prefix })} />\n ) : (\n <>\n {versioningEnabled && (\n <PopupMenuItem\n label={t`View Versions`}\n onClick={() => setVersionHistoryTarget(row.key)}\n />\n )}\n <PopupMenuItem\n label={t`Copy`}\n onClick={() => setCopyTarget({ key: row.key, size: row.size })}\n />\n <PopupMenuItem\n label={t`Move`}\n onClick={() => setMoveTarget({ key: row.key, size: row.size })}\n />\n <PopupMenuItem label={t`Edit Metadata`} onClick={() => setEditMetadataTarget(row.key)} />\n <PopupMenuItem\n label={t`Delete`}\n onClick={() =>\n setDeleteTarget({\n key: row.key,\n size: row.size,\n lastModified: row.lastModified,\n })\n }\n />\n </>\n )}\n </PopupMenuOptions>\n </PopupMenu>\n </div>\n </DataGridCell>\n </div>\n )\n })}\n </div>\n </div>\n </div>\n\n <DeleteObjectModal\n bucketName={bucketName}\n objectKey={deleteTarget?.key ?? \"\"}\n objectSize={deleteTarget?.size}\n lastModified={deleteTarget?.lastModified}\n isOpen={deleteTarget !== null}\n onClose={() => setDeleteTarget(null)}\n onSuccess={onDeleteObjectSuccess}\n onError={onDeleteObjectError}\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 <ObjectVersionHistoryModal\n isOpen={versionHistoryTarget !== null}\n bucketName={bucketName}\n objectKey={versionHistoryTarget ?? \"\"}\n onClose={() => setVersionHistoryTarget(null)}\n onRestoreVersion={onRestoreVersion}\n onDeleteVersion={onDeleteVersion}\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 className=\"mb-2 px-2 pt-2\">\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 } from \"@cloudoperators/juno-ui-components\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\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 utils = trpcReact.useUtils()\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 // 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 })\n\n const handleClose = () => {\n setFolderName(\"\")\n setValidationError(null)\n createFolderMutation.reset()\n onClose()\n }\n\n const handleFolderNameChange = (value: string) => {\n setFolderName(value)\n // Get existing folder names for duplicate detection\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 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 const fullPath = currentPrefix + folderName.trim()\n\n createFolderMutation.mutate({\n project_id: projectId,\n containerName: bucketName,\n folderPath: fullPath,\n })\n }\n\n const isValid = !validationError && folderName.trim().length > 0\n\n return (\n <Modal\n open={isOpen}\n onCancel={handleClose}\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={!isValid || createFolderMutation.isPending}\n disableCancelButton={createFolderMutation.isPending}\n disableCloseButton={createFolderMutation.isPending}\n >\n <Stack direction=\"vertical\" gap=\"4\">\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 onKeyDown={(e) => {\n if (e.key === \"Enter\" && isValid && !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\n {createFolderMutation.error && (\n <p className=\"text-juno-red text-sm\">\n <Trans>Error:</Trans> {createFolderMutation.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\"\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 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 setConfirmed(false)\n enableMutation.reset()\n onClose()\n }\n\n const handleEnable = () => {\n if (!confirmed) return\n\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 <div>\n <p className=\"mb-3 text-sm\">\n <Trans>\n Versioning allows you to keep multiple variants of an object in the same bucket. This protects against\n accidental overwrites and deletions.\n </Trans>\n </p>\n <p className=\"text-theme-light mb-3 text-sm\">\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 </div>\n\n <div>\n <p className=\"mb-2 text-sm font-semibold\">\n <Trans>Benefits:</Trans>\n </p>\n <ul className=\"list-disc space-y-1 pl-5 text-sm\">\n <li>\n <Trans>Recover from accidental deletions</Trans>\n </li>\n <li>\n <Trans>Retrieve older versions of objects</Trans>\n </li>\n <li>\n <Trans>Maintain object history</Trans>\n </li>\n </ul>\n </div>\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\"\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 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 onClose()\n },\n })\n\n const handleSuspend = () => {\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={onClose}\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 { 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 {\n Modal,\n Stack,\n Textarea,\n Select,\n SelectOption,\n Button,\n Spinner,\n Message,\n Form,\n} from \"@cloudoperators/juno-ui-components\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\n\ninterface BucketPolicyModalProps {\n isOpen: boolean\n bucketName: string\n onClose: () => void\n onSuccess?: (bucketName: string) => void\n onError?: (bucketName: string, errorMessage: string) => 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 // Form schema with JSON validation\n const formSchema = z.object({\n policyText: z\n .string()\n .min(1, t`Policy cannot be empty`)\n .max(MAX_POLICY_SIZE, t`Policy document exceeds maximum size of 20KB`)\n .refine(\n (value) => {\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)\n handleClose()\n },\n onError: (error) => {\n onError?.(bucketName, error.message)\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 onSuccess?.(bucketName)\n handleClose()\n },\n onError: (error) => {\n onError?.(bucketName, error.message)\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 setMutation.mutate({\n project_id: projectId,\n bucketName,\n policy: value.policyText,\n })\n },\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 form.setFieldValue(\"selectedTemplate\", \"\")\n } catch {\n form.setFieldValue(\"policyText\", policyData.policyText)\n }\n } else if (policyData?.policy === null) {\n form.setFieldValue(\"policyText\", \"\")\n form.setFieldValue(\"selectedTemplate\", \"\")\n }\n }, [isOpen, policyData, form])\n\n const handleClose = () => {\n form.reset()\n setMutation.reset()\n deleteMutation.reset()\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 const handleDelete = () => {\n deleteMutation.mutate({\n project_id: projectId,\n bucketName,\n })\n }\n\n const handleReset = () => {\n if (policyData?.policyText) {\n try {\n const parsed = JSON.parse(policyData.policyText)\n form.setFieldValue(\"policyText\", JSON.stringify(parsed, null, 2))\n } catch {\n form.setFieldValue(\"policyText\", policyData.policyText)\n }\n } else {\n form.setFieldValue(\"policyText\", \"\")\n }\n form.setFieldValue(\"selectedTemplate\", \"\")\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 // Compute isDirty relative to the loaded policy, not form's defaultValues (which are empty strings).\n // This prevents false \"Unsaved changes\" indicator when the modal opens with existing policy.\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 isDirty = policyTextValue !== originalPolicyText\n\n const policySize = useMemo(() => {\n return new Blob([policyTextValue]).size\n }, [policyTextValue])\n\n // Validate JSON inline for immediate feedback\n const jsonValidationError = useMemo(() => {\n if (!policyTextValue.trim()) return null\n try {\n JSON.parse(policyTextValue)\n return null\n } catch (error) {\n return error instanceof Error ? error.message : \"Invalid JSON\"\n }\n }, [policyTextValue])\n\n const hasPolicy = !!policyData?.policy\n const isSaving = setMutation.isPending || deleteMutation.isPending || isSubmitting\n const canSubmit =\n !isSaving && !jsonValidationError && policyTextValue.trim().length > 0 && policySize <= MAX_POLICY_SIZE\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`Bucket Policy - ${bucketName}`}\n open={isOpen}\n onCancel={handleClose}\n confirmButtonLabel={t`Save Policy`}\n onConfirm={handleSave}\n cancelButtonLabel={t`Cancel`}\n disableConfirmButton={!canSubmit}\n size=\"large\"\n >\n <Stack direction=\"vertical\" gap=\"4\">\n {isPolicyLoading && (\n <div className=\"flex items-center justify-center py-8\">\n <Spinner variant=\"primary\" size=\"large\" />\n </div>\n )}\n\n {policyError && (\n <Message variant=\"error\" title={t`Failed to load policy`}>\n {policyError.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 text-sm\">\n <Trans>\n Define access permissions for this bucket using JSON policy document. The policy controls who can\n access the bucket and what actions they can perform.\n </Trans>\n </p>\n <p className=\"text-sm\">\n <Trans>\n URL format: <code className=\"text-xs\">https://ceph-endpoint/project_id:bucket_name/file_path</code>\n </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 <div className=\"mb-1.5 flex items-center justify-between\">\n <label htmlFor={field.name} className=\"juno-label\">\n <Trans>Policy JSON</Trans>\n </label>\n {isDirty && (\n <div className=\"flex items-center gap-2\">\n <span className=\"text-theme-warning text-xs\">\n <Trans>Unsaved changes</Trans>\n </span>\n <Button variant=\"subdued\" size=\"small\" onClick={handleReset} disabled={isSaving}>\n <Trans>Reset</Trans>\n </Button>\n </div>\n )}\n </div>\n <Textarea\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 rows={15}\n className=\"font-mono text-xs\"\n disabled={isSaving}\n placeholder={t`Enter bucket policy JSON...`}\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 {jsonValidationError && <span className=\"text-theme-error\">{jsonValidationError}</span>}\n </div>\n </>\n )}\n />\n </div>\n\n {hasPolicy && (\n <div className=\"border-theme-light border-t pt-4\">\n <Button variant=\"primary-danger\" onClick={handleDelete} disabled={isSaving}>\n <Trans>Delete Policy</Trans>\n </Button>\n <p className=\"text-theme-light mt-2 text-xs\">\n <Trans>Deleting the policy will remove all access restrictions defined by it.</Trans>\n </p>\n </div>\n )}\n </Stack>\n </Form>\n )}\n </Stack>\n </Modal>\n )\n}\n","import { ReactNode } from \"react\"\nimport { ToastProps } from \"@cloudoperators/juno-ui-components\"\nimport { Trans } from \"@lingui/react/macro\"\nimport { Stack } from \"@cloudoperators/juno-ui-components/index\"\n\ninterface NotificationTextProps {\n title: ReactNode\n description: ReactNode\n}\n\nfunction NotificationText({ title, description }: NotificationTextProps) {\n return (\n <Stack direction=\"vertical\" gap=\"1.5\">\n <span>{title}</span>\n <span className=\"text-theme-light\">{description}</span>\n </Stack>\n )\n}\n\ninterface ToastConfig {\n onDismiss: () => void\n}\n\n// ── Folder operations ──────────────────────────────────────────────────────────\n\nexport const getFolderCreatedToast = (folderPath: string, config: ToastConfig): ToastProps => ({\n variant: \"success\",\n onDismiss: config.onDismiss,\n children: (\n <NotificationText\n title={<Trans>Folder Created</Trans>}\n description={<Trans>Folder \"{folderPath}\" was successfully created.</Trans>}\n />\n ),\n})\n\nexport const getFolderCreateErrorToast = (\n folderPath: string,\n errorMessage: string,\n config: ToastConfig\n): ToastProps => ({\n variant: \"error\",\n onDismiss: config.onDismiss,\n children: (\n <NotificationText\n title={<Trans>Failed to Create Folder</Trans>}\n description={\n <Trans>\n Could not create folder \"{folderPath}\": {errorMessage}\n </Trans>\n }\n />\n ),\n})\n\n// ── Object delete ──────────────────────────────────────────────────────────────\n\nexport const getObjectDeletedToast = (objectKey: string, config: ToastConfig): ToastProps => {\n const displayName = objectKey.split(\"/\").filter(Boolean).pop() ?? objectKey\n return {\n variant: \"success\",\n onDismiss: config.onDismiss,\n children: (\n <NotificationText\n title={<Trans>Object Deleted</Trans>}\n description={<Trans>Object \"{displayName}\" was permanently deleted.</Trans>}\n />\n ),\n }\n}\n\nexport const getObjectDeleteErrorToast = (objectKey: string, errorMessage: string, config: ToastConfig): ToastProps => {\n const displayName = objectKey.split(\"/\").filter(Boolean).pop() ?? objectKey\n return {\n variant: \"error\",\n onDismiss: config.onDismiss,\n children: (\n <NotificationText\n title={<Trans>Failed to Delete Object</Trans>}\n description={\n <Trans>\n Could not delete \"{displayName}\": {errorMessage}\n </Trans>\n }\n />\n ),\n }\n}\n\n// ── Object copy ────────────────────────────────────────────────────────────────\n\nexport const getObjectCopiedToast = (\n objectKey: string,\n targetBucket: string,\n targetKey: string,\n config: ToastConfig,\n wasOverwritten?: boolean\n): ToastProps => {\n const displayName = objectKey.split(\"/\").filter(Boolean).pop() ?? objectKey\n const destination = `${targetBucket}/${targetKey}`\n return {\n variant: \"success\",\n onDismiss: config.onDismiss,\n children: (\n <NotificationText\n title={<Trans>Object Copied</Trans>}\n description={\n 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 ),\n }\n}\n\nexport const getObjectCopyErrorToast = (objectKey: string, errorMessage: string, config: ToastConfig): ToastProps => {\n const displayName = objectKey.split(\"/\").filter(Boolean).pop() ?? objectKey\n return {\n variant: \"error\",\n onDismiss: config.onDismiss,\n children: (\n <NotificationText\n title={<Trans>Failed to Copy Object</Trans>}\n description={\n <Trans>\n Could not copy \"{displayName}\": {errorMessage}\n </Trans>\n }\n />\n ),\n }\n}\n\n// ── Object move ────────────────────────────────────────────────────────────────\n\nexport const getObjectMovedToast = (\n objectKey: string,\n targetBucket: string,\n targetKey: string,\n config: ToastConfig\n): ToastProps => {\n const displayName = objectKey.split(\"/\").filter(Boolean).pop() ?? objectKey\n const destination = `${targetBucket}/${targetKey}`\n return {\n variant: \"success\",\n onDismiss: config.onDismiss,\n children: (\n <NotificationText\n title={<Trans>Object Moved</Trans>}\n description={\n <Trans>\n \"{displayName}\" was successfully moved to {destination}.\n </Trans>\n }\n />\n ),\n }\n}\n\nexport const getObjectMoveErrorToast = (objectKey: string, errorMessage: string, config: ToastConfig): ToastProps => {\n const displayName = objectKey.split(\"/\").filter(Boolean).pop() ?? objectKey\n return {\n variant: \"error\",\n onDismiss: config.onDismiss,\n children: (\n <NotificationText\n title={<Trans>Failed to Move Object</Trans>}\n description={\n <Trans>\n Could not move \"{displayName}\": {errorMessage}\n </Trans>\n }\n />\n ),\n }\n}\n\n// ── Object metadata update ─────────────────────────────────────────────────────\n\nexport const getObjectMetadataUpdatedToast = (objectKey: string, config: ToastConfig): ToastProps => {\n const displayName = objectKey.split(\"/\").filter(Boolean).pop() ?? objectKey\n return {\n variant: \"success\",\n onDismiss: config.onDismiss,\n children: (\n <NotificationText\n title={<Trans>Object Updated</Trans>}\n description={<Trans>Properties of \"{displayName}\" were successfully updated.</Trans>}\n />\n ),\n }\n}\n\nexport const getObjectMetadataUpdateErrorToast = (\n objectKey: string,\n errorMessage: string,\n config: ToastConfig\n): ToastProps => {\n const displayName = objectKey.split(\"/\").filter(Boolean).pop() ?? objectKey\n return {\n variant: \"error\",\n onDismiss: config.onDismiss,\n children: (\n <NotificationText\n title={<Trans>Failed to Update Object</Trans>}\n description={\n <Trans>\n Could not update \"{displayName}\": {errorMessage}\n </Trans>\n }\n />\n ),\n }\n}\n","import { useState, useEffect, useRef, startTransition } from \"react\"\nimport { Plural, Trans, useLingui } from \"@lingui/react/macro\"\nimport {\n Spinner,\n Stack,\n Button,\n Toast,\n ToastProps,\n Badge,\n Message,\n DataGridToolbar,\n SearchInput,\n} from \"@cloudoperators/juno-ui-components\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\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 { EnableVersioningModal } from \"../Buckets/EnableVersioningModal\"\nimport { SuspendVersioningModal } from \"../Buckets/SuspendVersioningModal\"\nimport { BucketPolicyModal } from \"../Buckets/BucketPolicyModal\"\nimport { useNavigate } from \"@tanstack/react-router\"\nimport { Route } from \"@/client/routes/_auth/projects/$projectId/storage/$provider/$storageType/$containerName/objects\"\nimport type { S3Object, S3FolderPrefix } from \"@/server/Storage/types/ceph\"\nimport {\n getFolderCreatedToast,\n getObjectDeletedToast,\n getObjectDeleteErrorToast,\n getObjectCopiedToast,\n getObjectCopyErrorToast,\n getObjectMovedToast,\n getObjectMoveErrorToast,\n getObjectMetadataUpdatedToast,\n getObjectMetadataUpdateErrorToast,\n} from \"./ObjectToastNotifications\"\n\n// Prefix encoding (reuse from Swift pattern)\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\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 navigate = useNavigate({ from: Route.fullPath })\n const { provider, storageType } = Route.useParams()\n const { prefix: encodedPrefix, sortBy, sortDirection, search: searchParam = \"\" } = Route.useSearch()\n const currentPrefix = decodePrefix(encodedPrefix)\n\n const [continuationToken, setContinuationToken] = useState<string | undefined>(undefined)\n const [allObjects, setAllObjects] = useState<S3Object[]>([])\n const [allFolders, setAllFolders] = useState<S3FolderPrefix[]>([])\n const [hasMore, setHasMore] = useState(false)\n const [isCreateFolderModalOpen, setIsCreateFolderModalOpen] = useState(false)\n const [isEnableVersioningModalOpen, setIsEnableVersioningModalOpen] = useState(false)\n const [isSuspendVersioningModalOpen, setIsSuspendVersioningModalOpen] = useState(false)\n const [isPolicyModalOpen, setIsPolicyModalOpen] = useState(false)\n const [toastData, setToastData] = useState<ToastProps | null>(null)\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 handleToastDismiss = () => setToastData(null)\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 bucket policy status\n const { data: policyData } = trpcReact.storage.ceph.bucketPolicy.get.useQuery(\n {\n project_id: projectId ?? \"\",\n bucketName,\n },\n {\n enabled: !!projectId,\n staleTime: 5 * 60 * 1000, // Cache for 5 minutes\n retry: false,\n }\n )\n\n const { data, isLoading, 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,\n },\n {\n enabled: !!projectId,\n }\n )\n\n // Update accumulated data when new data arrives\n useEffect(() => {\n if (data) {\n // Filter out the folder marker itself (object key === current prefix)\n // When inside \"first/\", S3 returns \"first/\" as an object - we don't want to show it\n const actualObjects = data.objects.filter((obj) => {\n const stripped = currentPrefix ? obj.key.replace(currentPrefix, \"\") : obj.key\n // Skip if stripped is empty (the folder marker itself) or just \"/\"\n return stripped !== \"\" && stripped !== \"/\"\n })\n\n if (continuationToken) {\n // Append to existing data (pagination)\n setAllObjects((prev) => [...prev, ...actualObjects])\n setAllFolders((prev) => [...prev, ...data.folders])\n } else {\n // First load - replace data\n setAllObjects(actualObjects)\n setAllFolders(data.folders)\n }\n // Update hasMore state\n setHasMore(data.isTruncated ?? false)\n }\n }, [data, continuationToken, currentPrefix])\n\n const navigateToPrefix = (prefix: string) => {\n // Reset pagination when navigating\n setContinuationToken(undefined)\n setAllObjects([])\n setAllFolders([])\n setHasMore(false)\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 setAllObjects([])\n setAllFolders([])\n setHasMore(false)\n\n navigate({\n to: \"/projects/$projectId/storage/$provider/$storageType\",\n params: { projectId, provider, storageType },\n })\n }\n\n const loadMore = () => {\n if (data?.nextContinuationToken) {\n setContinuationToken(data.nextContinuationToken)\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 const filteredFolders = allFolders.filter((folder) =>\n stripPrefix(folder.prefix).toLowerCase().includes(searchParam.toLowerCase().trim())\n )\n\n const totalItemCount = allObjects.length + allFolders.length\n const filteredItemCount = 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 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 (isLoading && !continuationToken) {\n return (\n <Stack className=\"absolute inset-0\" distribution=\"center\" alignment=\"center\" direction=\"vertical\">\n <Spinner variant=\"primary\" size=\"large\" className=\"mb-2\" />\n <Trans>Loading objects...</Trans>\n </Stack>\n )\n }\n\n if (error) {\n const errorMessage = error.message\n return (\n <Message variant=\"error\" title={t`Failed to load objects`}>\n {errorMessage}\n </Message>\n )\n }\n\n return (\n <div className=\"relative\">\n {/* Bucket header with versioning status badge */}\n <div className=\"mb-4 flex items-center justify-between\">\n <Stack direction=\"horizontal\" gap=\"3\" alignment=\"center\">\n <h2 className=\"text-xl font-semibold\">{bucketName}</h2>\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>Policy</Trans>\n </Badge>\n )}\n </Stack>\n </div>\n\n <ObjectsFileNavigation\n bucketName={bucketName}\n prefix={currentPrefix}\n onBucketsClick={navigateToBuckets}\n onPrefixClick={navigateToPrefix}\n />\n\n <Stack direction=\"vertical\">\n {/* Zone 1 — sort controls and the 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 onSortByChange={(value) =>\n handleSortChange({ ...sortSettings, sortBy: value, sortDirection: sortSettings.sortDirection })\n }\n onSortDirectionChange={(direction) => handleSortChange({ ...sortSettings, sortDirection: direction })}\n />\n </Stack>\n <Button variant=\"primary\" className=\"whitespace-nowrap\" onClick={() => setIsCreateFolderModalOpen(true)}>\n <Trans>Create Folder</Trans>\n </Button>\n {versioningStatus && versioningStatus.status === \"Enabled\" && (\n <Button\n variant=\"subdued\"\n className=\"whitespace-nowrap\"\n onClick={() => setIsSuspendVersioningModalOpen(true)}\n >\n <Trans>Suspend Versioning</Trans>\n </Button>\n )}\n {versioningStatus &&\n (versioningStatus.status === \"Unversioned\" || versioningStatus.status === \"Suspended\") && (\n <Button className=\"whitespace-nowrap\" onClick={() => setIsEnableVersioningModalOpen(true)}>\n <Trans>Enable Versioning</Trans>\n </Button>\n )}\n <Button variant=\"subdued\" className=\"whitespace-nowrap\" onClick={() => setIsPolicyModalOpen(true)}>\n <Trans>Bucket Policy</Trans>\n </Button>\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 — item count. Ceph objects has no bulk selection/delete, so this\n zone carries only the count (no select-all or Actions menu). */}\n <DataGridToolbar>\n <Stack distribution=\"start\" gap=\"2\" alignment=\"center\" className=\"text-sm\">\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 <ObjectsTableView\n bucketName={bucketName}\n objects={sortedObjects}\n folders={sortedFolders}\n currentPrefix={currentPrefix}\n versioningEnabled={versioningStatus?.status === \"Enabled\"}\n onFolderClick={navigateToPrefix}\n onDeleteObjectSuccess={(objectKey) => {\n setToastData(getObjectDeletedToast(objectKey, { onDismiss: handleToastDismiss }))\n }}\n onDeleteObjectError={(objectKey, errorMessage) => {\n setToastData(getObjectDeleteErrorToast(objectKey, errorMessage, { onDismiss: handleToastDismiss }))\n }}\n onCopyObjectSuccess={(objectKey, targetBucket, targetKey, wasOverwritten) => {\n setToastData(\n getObjectCopiedToast(objectKey, targetBucket, targetKey, { onDismiss: handleToastDismiss }, wasOverwritten)\n )\n }}\n onCopyObjectError={(objectKey, errorMessage) => {\n setToastData(getObjectCopyErrorToast(objectKey, errorMessage, { onDismiss: handleToastDismiss }))\n }}\n onMoveObjectSuccess={(objectKey, targetBucket, targetKey) => {\n setToastData(getObjectMovedToast(objectKey, targetBucket, targetKey, { onDismiss: handleToastDismiss }))\n }}\n onMoveObjectError={(objectKey, errorMessage) => {\n setToastData(getObjectMoveErrorToast(objectKey, errorMessage, { onDismiss: handleToastDismiss }))\n }}\n onEditMetadataSuccess={(objectKey) => {\n setToastData(getObjectMetadataUpdatedToast(objectKey, { onDismiss: handleToastDismiss }))\n }}\n onEditMetadataError={(objectKey, errorMessage) => {\n setToastData(getObjectMetadataUpdateErrorToast(objectKey, errorMessage, { onDismiss: handleToastDismiss }))\n }}\n onRestoreVersion={() => {\n // Version restored successfully - no toast\n }}\n onDeleteVersion={() => {\n // Version deleted successfully - no toast\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 setToastData(getFolderCreatedToast(folderPath, { onDismiss: handleToastDismiss }))\n navigateToPrefix(folderPath)\n }}\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 {toastData && <Toast {...toastData} />}\n </div>\n )\n}\n","import { createFileRoute, redirect, useParams } from \"@tanstack/react-router\"\nimport { getServiceIndex } from \"@/server/Authentication/helpers\"\nimport { ErrorBoundary } from \"react-error-boundary\"\nimport { Trans } from \"@lingui/react/macro\"\nimport { SwiftObjects } from \"../../../../-components/Swift/Objects\"\nimport { CephObjects } from \"../../../../-components/Ceph/Objects\"\nimport { z } from \"zod\"\nimport type { RouteInfo } from \"@/client/routes/routeInfo\"\n\nexport const checkServiceAvailability = (\n availableServices: {\n type: string\n name: string\n }[],\n params: {\n projectId: string\n provider: string\n storageType: string\n containerName: string\n }\n) => {\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// 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\nconst objectsSearchSchema = z.object({\n prefix: z.string().optional(),\n sortBy: z.enum([\"name\", \"last_modified\", \"bytes\", \"lastModified\", \"size\"]).optional(),\n sortDirection: z.enum([\"asc\", \"desc\"]).optional(),\n search: 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 isDetail: true,\n sectionCrumb: { labelKey: \"Storage\" },\n crumb: { useParamAsLabel: \"provider\", to: \"/projects/$projectId/storage/$provider/$storageType\" },\n } satisfies RouteInfo,\n validateSearch: objectsSearchSchema,\n head: ({ match }) => ({\n meta: [{ title: match.params.containerName }],\n }),\n component: () => {\n return <ObjectsDashboard />\n },\n notFoundComponent: () => {\n return (\n <p>\n <Trans>Storage container not found</Trans>\n </p>\n )\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 ObjectsDashboard() {\n const { project, provider, containerName } = useParams({\n from: \"/_auth/projects/$projectId/storage/$provider/$storageType/$containerName/objects/\",\n select: (params) => ({\n project: params.projectId,\n provider: params.provider,\n containerName: params.containerName,\n storageType: params.storageType,\n }),\n })\n\n const { prefix, sortBy, sortDirection, search } = Route.useSearch()\n\n return (\n <div>\n {project ? (\n <ErrorBoundary\n resetKeys={[project, provider, containerName, prefix, sortBy, sortDirection, search]}\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 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"],"mappings":"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"}