@cobaltcore-dev/aurora 0.2.2 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client/AuroraApp.d.ts +10 -0
- package/dist/client/{ContentHeader-DtBiIwRY.mjs → ContentHeader-B_PWrxbw.mjs} +17 -17
- package/dist/client/{ContentHeader-DtBiIwRY.mjs.map → ContentHeader-B_PWrxbw.mjs.map} +1 -1
- package/dist/client/{DeleteFlavorModal-rmuYIafD.mjs → DeleteFlavorModal-BkPrQKyE.mjs} +146 -146
- package/dist/client/{DeleteFlavorModal-rmuYIafD.mjs.map → DeleteFlavorModal-BkPrQKyE.mjs.map} +1 -1
- package/dist/client/{EditSecurityGroupModal-B7Sz9puM.mjs → EditSecurityGroupModal-ad4uzlt0.mjs} +14 -14
- package/dist/client/{EditSecurityGroupModal-B7Sz9puM.mjs.map → EditSecurityGroupModal-ad4uzlt0.mjs.map} +1 -1
- package/dist/client/{FloatingIpActionModals-CfRJiZqD.mjs → FloatingIpActionModals-lKMwLuL8.mjs} +51 -51
- package/dist/client/{FloatingIpActionModals-CfRJiZqD.mjs.map → FloatingIpActionModals-lKMwLuL8.mjs.map} +1 -1
- package/dist/client/{ImageToastNotifications-Cw30RXsw.mjs → ImageToastNotifications--U13YiQ_.mjs} +328 -328
- package/dist/client/{ImageToastNotifications-Cw30RXsw.mjs.map → ImageToastNotifications--U13YiQ_.mjs.map} +1 -1
- package/dist/client/{ListToolbar-DuazvsAu.mjs → ListToolbar-C5lzTrit.mjs} +56 -56
- package/dist/client/{ListToolbar-DuazvsAu.mjs.map → ListToolbar-C5lzTrit.mjs.map} +1 -1
- package/dist/client/{RouteError-Cyto623-.mjs → RouteError-iP1Vd6bY.mjs} +2 -2
- package/dist/client/{RouteError-Cyto623-.mjs.map → RouteError-iP1Vd6bY.mjs.map} +1 -1
- package/dist/client/{_flavorId-B-1fYadl.mjs → _flavorId-BaNXUJhA.mjs} +49 -49
- package/dist/client/_flavorId-BaNXUJhA.mjs.map +1 -0
- package/dist/client/{_flavorId-BYfIHIV_.mjs → _flavorId-CnO76tuy.mjs} +10 -10
- package/dist/client/_flavorId-CnO76tuy.mjs.map +1 -0
- package/dist/client/{_floatingIpId-IrnN-ozB.mjs → _floatingIpId-C8G20nNt.mjs} +2 -2
- package/dist/client/{_floatingIpId-IrnN-ozB.mjs.map → _floatingIpId-C8G20nNt.mjs.map} +1 -1
- package/dist/client/{_floatingIpId-FQ5P2qMV.mjs → _floatingIpId-DdKnjdIV.mjs} +36 -36
- package/dist/client/{_floatingIpId-FQ5P2qMV.mjs.map → _floatingIpId-DdKnjdIV.mjs.map} +1 -1
- package/dist/client/{_imageId-Tx_9bqEc.mjs → _imageId-DdSbxFqG.mjs} +135 -135
- package/dist/client/_imageId-DdSbxFqG.mjs.map +1 -0
- package/dist/client/{_pcaId-CFuKY82d.mjs → _pcaId-DFkYJEb5.mjs} +136 -136
- package/dist/client/{_pcaId-CFuKY82d.mjs.map → _pcaId-DFkYJEb5.mjs.map} +1 -1
- package/dist/client/{_pcaId-Bck7S7gJ.mjs → _pcaId-DX_S-3hE.mjs} +2 -2
- package/dist/client/{_pcaId-Bck7S7gJ.mjs.map → _pcaId-DX_S-3hE.mjs.map} +1 -1
- package/dist/client/{_projectId-PSpuCKO7.mjs → _projectId-DYrcZ3E3.mjs} +9 -9
- package/dist/client/{_projectId-PSpuCKO7.mjs.map → _projectId-DYrcZ3E3.mjs.map} +1 -1
- package/dist/client/{_projectId-B1VjDd0Z.mjs → _projectId-Dha4XqX4.mjs} +3 -3
- package/dist/client/{_projectId-B1VjDd0Z.mjs.map → _projectId-Dha4XqX4.mjs.map} +1 -1
- package/dist/client/_projectId-DsSVV2EA.mjs +316 -0
- package/dist/client/_projectId-DsSVV2EA.mjs.map +1 -0
- package/dist/client/{_projectId-Pxp-RXK4.mjs → _projectId-KH5si25Q.mjs} +2 -2
- package/dist/client/{_projectId-Pxp-RXK4.mjs.map → _projectId-KH5si25Q.mjs.map} +1 -1
- package/dist/client/{_securityGroupId-VV2lUcGQ.mjs → _securityGroupId-DgaSqYex.mjs} +2 -2
- package/dist/client/{_securityGroupId-VV2lUcGQ.mjs.map → _securityGroupId-DgaSqYex.mjs.map} +1 -1
- package/dist/client/{_securityGroupId-Dqi6ddw4.mjs → _securityGroupId-O7FXfx0M.mjs} +306 -306
- package/dist/client/{_securityGroupId-Dqi6ddw4.mjs.map → _securityGroupId-O7FXfx0M.mjs.map} +1 -1
- package/dist/client/{about-B2AzqxFI.mjs → about-DN8n8sN8.mjs} +8 -8
- package/dist/client/{about-B2AzqxFI.mjs.map → about-DN8n8sN8.mjs.map} +1 -1
- package/dist/client/{build-Cf7iWbpH.mjs → build-CZRvXrAL.mjs} +1047 -1042
- package/dist/client/{build-Cf7iWbpH.mjs.map → build-CZRvXrAL.mjs.map} +1 -1
- package/dist/client/{constants-CCgR6fKI.mjs → constants-akdIBeTX.mjs} +6 -6
- package/dist/client/{constants-CCgR6fKI.mjs.map → constants-akdIBeTX.mjs.map} +1 -1
- package/dist/client/{containers-BWERuY0O.mjs → containers-BE2QiLBs.mjs} +748 -748
- package/dist/client/{containers-BWERuY0O.mjs.map → containers-BE2QiLBs.mjs.map} +1 -1
- package/dist/client/containers-Cs5vOeR2.mjs.map +1 -1
- package/dist/client/{containers-DovytjVP.mjs → containers-DmwhE9Uz.mjs} +6 -6
- package/dist/client/containers-DmwhE9Uz.mjs.map +1 -0
- package/dist/client/flavors-BXPYAFyQ.mjs.map +1 -1
- package/dist/client/{flavors-CUiALHcB.mjs → flavors-CY7A6--v.mjs} +2 -2
- package/dist/client/{flavors-CUiALHcB.mjs.map → flavors-CY7A6--v.mjs.map} +1 -1
- package/dist/client/{flavors-Bovz-I2U.mjs → flavors-pEcGkCut.mjs} +150 -150
- package/dist/client/{flavors-Bovz-I2U.mjs.map → flavors-pEcGkCut.mjs.map} +1 -1
- package/dist/client/{floatingips-BrjDiY2t.mjs → floatingips-BtL4d4m-.mjs} +118 -118
- package/dist/client/{floatingips-BrjDiY2t.mjs.map → floatingips-BtL4d4m-.mjs.map} +1 -1
- package/dist/client/{images-DaaCUXMI.mjs → images-C19gCFSy.mjs} +389 -389
- package/dist/client/{images-DaaCUXMI.mjs.map → images-C19gCFSy.mjs.map} +1 -1
- package/dist/client/images-DM9I8G0p.mjs.map +1 -1
- package/dist/client/{images-BZP3pBqj.mjs → images-I9gQfRa7.mjs} +2 -2
- package/dist/client/{images-BZP3pBqj.mjs.map → images-I9gQfRa7.mjs.map} +1 -1
- package/dist/client/index.d.ts +2 -1
- package/dist/client/index.js +416 -418
- package/dist/client/index.js.map +1 -1
- package/dist/client/objects-B4yrYf_a.mjs.map +1 -1
- package/dist/client/{objects-D4zBka5e.mjs → objects-BrYe_RaJ.mjs} +6 -6
- package/dist/client/objects-BrYe_RaJ.mjs.map +1 -0
- package/dist/client/{objects-Cw4Vu01M.mjs → objects-DOYFFn3Y.mjs} +1013 -1013
- package/dist/client/{objects-Cw4Vu01M.mjs.map → objects-DOYFFn3Y.mjs.map} +1 -1
- package/dist/client/{overview-2J54-loz.mjs → overview-BjRSFSBh.mjs} +2 -2
- package/dist/client/{overview-2J54-loz.mjs.map → overview-BjRSFSBh.mjs.map} +1 -1
- package/dist/client/{overview-BnmukbFh.mjs → overview-C4gjtc2q.mjs} +7 -7
- package/dist/client/{overview-BnmukbFh.mjs.map → overview-C4gjtc2q.mjs.map} +1 -1
- package/dist/client/{overview-D0AAvsmL.mjs → overview-CmQkJ4Hh.mjs} +2 -2
- package/dist/client/{overview-D0AAvsmL.mjs.map → overview-CmQkJ4Hh.mjs.map} +1 -1
- package/dist/client/{overview-BtIXpYBo.mjs → overview-DTLIAKkJ.mjs} +2 -2
- package/dist/client/{overview-BtIXpYBo.mjs.map → overview-DTLIAKkJ.mjs.map} +1 -1
- package/dist/client/{pca-V2aaOxZA.mjs → pca-CYFJxSZ2.mjs} +70 -70
- package/dist/client/{pca-V2aaOxZA.mjs.map → pca-CYFJxSZ2.mjs.map} +1 -1
- package/dist/client/{pca-BqZycwCu.mjs → pca-DzixU9Dl.mjs} +2 -2
- package/dist/client/{pca-BqZycwCu.mjs.map → pca-DzixU9Dl.mjs.map} +1 -1
- package/dist/client/projects-BsN4bvU2.mjs.map +1 -1
- package/dist/client/{projects-0feOw_b6.mjs → projects-BtyjXGq2.mjs} +2 -2
- package/dist/client/projects-BtyjXGq2.mjs.map +1 -0
- package/dist/client/projects-D3hOC1cy.mjs +95 -0
- package/dist/client/projects-D3hOC1cy.mjs.map +1 -0
- package/dist/client/{projects-jyIHL6DE.mjs → projects-DwVawmll.mjs} +2 -2
- package/dist/client/projects-DwVawmll.mjs.map +1 -0
- package/dist/client/{securitygroups-B4MkSBtI.mjs → securitygroups-DMCIDHQS.mjs} +114 -114
- package/dist/client/{securitygroups-B4MkSBtI.mjs.map → securitygroups-DMCIDHQS.mjs.map} +1 -1
- package/package.json +3 -3
- package/dist/client/_flavorId-B-1fYadl.mjs.map +0 -1
- package/dist/client/_flavorId-BYfIHIV_.mjs.map +0 -1
- package/dist/client/_imageId-Tx_9bqEc.mjs.map +0 -1
- package/dist/client/_projectId-Bs4W9hos.mjs +0 -283
- package/dist/client/_projectId-Bs4W9hos.mjs.map +0 -1
- package/dist/client/containers-DovytjVP.mjs.map +0 -1
- package/dist/client/objects-D4zBka5e.mjs.map +0 -1
- package/dist/client/projects-0feOw_b6.mjs.map +0 -1
- package/dist/client/projects-C1IYOvFQ.mjs +0 -144
- package/dist/client/projects-C1IYOvFQ.mjs.map +0 -1
- package/dist/client/projects-jyIHL6DE.mjs.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"objects-Cw4Vu01M.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","ObjectsTableView","rows","searchTerm","container","account","onFolderClick","onDeleteFolderSuccess","onDeleteFolderError","onDownloadError","onDeleteObjectSuccess","onDeleteObjectError","onCopyObjectSuccess","onCopyObjectError","onMoveObjectSuccess","onMoveObjectError","onTempUrlCopySuccess","onEditMetadataSuccess","onEditMetadataError","selectedObjects","setSelectedObjects","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","allCount","isAnyDownloading","style","paddingRight","gridColumnTemplate","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","autoDismiss","autoDismissTimeout","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","startTransition","Spinner","Button","Toast","Stack","trpcReact","useProjectId","ListToolbar","useNavigate","useParams","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","useLingui","projectId","navigate","fullPath","provider","containerName","encodedPrefix","sortDirection","search","searchParam","useSearch","currentPrefix","createFolderModalOpen","setCreateFolderModalOpen","uploadModalOpen","setUploadModalOpen","deleteAllModalOpen","setDeleteAllModalOpen","selectedObjects","setSelectedObjects","toastData","setToastData","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","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","div","onContainersClick","onPrefixClick","searchTerm","onSort","onSearch","actions","gap","onClick","disabled","rows","onFolderClick","onDeleteFolderSuccess","onDeleteFolderError","onDownloadError","onDeleteObjectSuccess","onDeleteObjectError","onCopyObjectSuccess","onCopyObjectError","onMoveObjectSuccess","onMoveObjectError","onTempUrlCopySuccess","onEditMetadataSuccess","onEditMetadataError","isOpen","objectNames","objectKeys","onClose","onSuccess","onError","onCancelled","useState","Modal","Button","TextInput","Stack","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","direction","gap","p","div","className","span","undefined","Date","toLocaleString","label","t","value","onChange","e","target","placeholder","autoFocus","variant","onClick","disabled","isPending","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","Message","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","readOnly","input","checked","isError","errorMessage","useState","useRef","useEffect","trpcReact","useProjectId","Modal","Stack","Spinner","ComboBox","ComboBoxOption","TextInput","Message","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","variant","div","strong","toFixed","onInputChange","handleSearchChange","placeholder","searchTerm","hiddenCount","totalBuckets","visibleBuckets","disabled","b","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","isError","copyErrorMessage","deleteErrorMessage","useState","useEffect","useRef","trpcReact","useProjectId","Modal","TextInput","Stack","Message","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","variant","div","p","contentType","etag","lastModified","distribution","label","onClick","icon","disabled","columns","onChange","target","placeholder","errortext","invalid","autoFocus","colSpan","useState","DataGrid","DataGridRow","DataGridCell","DataGridHeadCell","PopupMenu","PopupMenuItem","PopupMenuOptions","MdFolder","MdDescription","formatBytesBinary","DeleteObjectModal","CopyObjectModal","MoveObjectModal","EditMetadataModal","ObjectsTableView","bucketName","objects","folders","currentPrefix","onFolderClick","onDeleteObjectSuccess","onDeleteObjectError","onCopyObjectSuccess","onCopyObjectError","onMoveObjectSuccess","onMoveObjectError","onEditMetadataSuccess","onEditMetadataError","useLingui","deleteTarget","setDeleteTarget","copyTarget","setCopyTarget","moveTarget","setMoveTarget","editMetadataTarget","setEditMetadataTarget","stripPrefix","fullKey","replace","length","columns","colSpan","div","className","p","objectKey","key","objectSize","size","lastModified","isOpen","onClose","onSuccess","onError","map","folder","displayName","prefix","button","type","onClick","title","span","e","stopPropagation","label","t","obj","Date","toLocaleString","Breadcrumb","BreadcrumbItem","MdInventory2","MdOutlineInventory2","MdFolder","MdFolderOpen","prefixToSegments","prefix","parts","replace","split","filter","Boolean","map","label","i","slice","join","activeCrumbClass","ObjectsFileNavigation","bucketName","onPrefixClick","prefixSegments","isAtRoot","length","div","className","onClick","undefined","active","span","size","seg","isLast","useState","Modal","Button","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","direction","gap","p","div","className","span","label","onChange","e","target","placeholder","autoFocus","invalid","errortext","onKeyDown","key","isPending","variant","onClick","disabled","Stack","NotificationText","title","description","direction","gap","span","className","getFolderCreatedToast","folderPath","config","variant","autoDismiss","autoDismissTimeout","onDismiss","children","getFolderCreateErrorToast","errorMessage","getObjectDeletedToast","objectKey","displayName","split","filter","Boolean","pop","getObjectDeleteErrorToast","getObjectCopiedToast","targetBucket","targetKey","wasOverwritten","destination","getObjectCopyErrorToast","getObjectMovedToast","getObjectMoveErrorToast","getObjectMetadataUpdatedToast","getObjectMetadataUpdateErrorToast","useState","useEffect","startTransition","Spinner","Stack","Button","Toast","trpcReact","useProjectId","ListToolbar","ObjectsTableView","ObjectsFileNavigation","CreateFolderModal","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","encodedPrefix","sortBy","sortDirection","search","searchParam","useSearch","currentPrefix","continuationToken","setContinuationToken","undefined","allObjects","setAllObjects","allFolders","setAllFolders","hasMore","setHasMore","isCreateFolderModalOpen","setIsCreateFolderModalOpen","toastData","setToastData","handleToastDismiss","data","isLoading","error","storage","ceph","objects","list","useQuery","project_id","containerName","delimiter","maxKeys","enabled","actualObjects","filter","obj","stripped","key","replace","prev","folders","isTruncated","navigateToPrefix","loadMore","nextContinuationToken","stripPrefix","fullKey","filteredObjects","toLowerCase","includes","trim","filteredFolders","folder","sortedObjects","sort","a","b","comparison","localeCompare","aDate","lastModified","bDate","Date","getTime","size","sortedFolders","sortSettings","options","label","t","value","handleSearchChange","term","handleSortChange","newSort","resolvedSortBy","resolvedDirection","direction","gap","alignment","className","span","errorMessage","message","p","div","onPrefixClick","searchTerm","onSort","onSearch","actions","variant","onClick","onFolderClick","onDeleteObjectSuccess","objectKey","onDismiss","onDeleteObjectError","onCopyObjectSuccess","targetBucket","targetKey","wasOverwritten","onCopyObjectError","onMoveObjectSuccess","onMoveObjectError","onEditMetadataSuccess","onEditMetadataError","disabled","isOpen","onClose","onSuccess","folderPath","useParams","ErrorBoundary","Trans","SwiftObjects","ObjectBrowserView","Route","ObjectsDashboard","project","provider","containerName","from","select","params","projectId","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/ObjectsTableView.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Objects/ObjectsFileNavigation.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Objects/CreateFolderModal.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Objects/ObjectToastNotifications.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Objects/ObjectBrowserView.tsx","../../src/client/routes/_auth/projects/$projectId/storage/$provider/containers/$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/containers/$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 font-mono\" 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-mono font-semibold\">\"{folderDisplayName}\"</span> and all objects within it\n will be 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/containers/$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/containers/$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/containers/$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/containers/$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/containers/$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 mb-3 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// Define column template — 5 columns: checkbox | name | last modified | size | actions\nconst GRID_COLUMN_TEMPLATE = \"40px 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}\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}: 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 allCount = rows.length\n const isAnyDownloading = downloadingRow !== null || previewingRow !== null\n\n return (\n <>\n <div className=\"relative\">\n {/* Table Header with scrollbar padding */}\n <div style={{ paddingRight: `${scrollbarWidth}px` }}>\n <DataGrid\n columns={5}\n gridColumnTemplate={GRID_COLUMN_TEMPLATE}\n className=\"objects\"\n data-testid=\"objects-table-header\"\n >\n <DataGridRow>\n <DataGridHeadCell>\n <Checkbox checked={allSelected} onChange={handleSelectAll} data-testid=\"select-all-objects\" />\n </DataGridHeadCell>\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 - 550px)\" }}\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: GRID_COLUMN_TEMPLATE,\n alignItems: \"stretch\",\n }}\n data-testid={`object-row-${row.name}`}\n >\n {/* Checkbox — only for object rows; folders get an empty cell */}\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 {/* 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\n {/* Footer with count */}\n <div className=\"text-theme-light border-theme-background-lvl-2 border-t px-4 py-2 text-sm\">\n <Trans>{allCount} items</Trans>\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/containers/$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 { 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={t`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 autoDismissTimeout?: number\n}\n\nexport const getFolderCreatedToast = (folderName: string, config: ToastConfig): ToastProps => ({\n variant: \"success\",\n autoDismiss: true,\n autoDismissTimeout: config.autoDismissTimeout ?? 5000,\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 autoDismiss: true,\n autoDismissTimeout: config.autoDismissTimeout ?? 5000,\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 autoDismiss: true,\n autoDismissTimeout: config.autoDismissTimeout ?? 5000,\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 autoDismiss: true,\n autoDismissTimeout: config.autoDismissTimeout ?? 5000,\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 autoDismiss: true,\n autoDismissTimeout: config.autoDismissTimeout ?? 5000,\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 autoDismiss: true,\n autoDismissTimeout: config.autoDismissTimeout ?? 5000,\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 autoDismiss: true,\n autoDismissTimeout: config.autoDismissTimeout ?? 5000,\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 autoDismiss: true,\n autoDismissTimeout: config.autoDismissTimeout ?? 5000,\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 autoDismiss: true,\n autoDismissTimeout: config.autoDismissTimeout ?? 5000,\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 autoDismiss: true,\n autoDismissTimeout: config.autoDismissTimeout ?? 5000,\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 autoDismiss: true,\n autoDismissTimeout: config.autoDismissTimeout ?? 5000,\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 autoDismiss: true,\n autoDismissTimeout: config.autoDismissTimeout ?? 4000,\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 autoDismiss: true,\n autoDismissTimeout: config.autoDismissTimeout ?? 5000,\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 autoDismiss: true,\n autoDismissTimeout: config.autoDismissTimeout ?? 5000,\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 autoDismiss: true,\n autoDismissTimeout: config.autoDismissTimeout ?? 5000,\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 autoDismiss: true,\n autoDismissTimeout: config.autoDismissTimeout ?? 4000,\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 autoDismiss: true,\n autoDismissTimeout: config.autoDismissTimeout ?? 5000,\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 autoDismiss: true,\n autoDismissTimeout: config.autoDismissTimeout ?? 5000,\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 autoDismiss: true,\n autoDismissTimeout: config.autoDismissTimeout ?? 5000,\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, startTransition } from \"react\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { Spinner, Button, Toast, ToastProps, Stack } from \"@cloudoperators/juno-ui-components\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport { ObjectSummary } from \"@/server/Storage/types/swift\"\nimport { ListToolbar } from \"@/client/components/ListToolbar\"\nimport { SortSettings } from \"@/client/components/ListToolbar/types\"\nimport { useNavigate, useParams } from \"@tanstack/react-router\"\nimport { Route } from \"../../../$provider/containers/$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 = () => {\n const { t } = useLingui()\n const projectId = useProjectId()\n const navigate = useNavigate({ from: Route.fullPath })\n\n const { provider, containerName } = useParams({\n from: \"/_auth/projects/$projectId/storage/$provider/containers/$containerName/objects/\",\n })\n\n const { prefix: encodedPrefix, sortBy, sortDirection, search: searchParam = \"\" } = Route.useSearch()\n const currentPrefix = decodePrefix(encodedPrefix)\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 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/containers\",\n params: { projectId, provider },\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 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=\"fixed 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=\"fixed 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 return (\n <div className=\"relative\">\n <ObjectsFileNavigation\n containerName={containerName}\n currentPrefix={currentPrefix}\n onContainersClick={navigateToContainers}\n onPrefixClick={navigateToPrefix}\n />\n <ListToolbar\n sortSettings={sortSettings}\n searchTerm={searchParam}\n onSort={handleSortChange}\n onSearch={handleSearchChange}\n actions={\n <Stack direction=\"horizontal\" gap=\"2\">\n <Button variant=\"primary\" onClick={() => setCreateFolderModalOpen(true)}>\n <Trans>Create Folder</Trans>\n </Button>\n <Button onClick={() => setUploadModalOpen(true)}>\n <Trans>Upload Object</Trans>\n </Button>\n <Button variant=\"primary-danger\" onClick={() => setDeleteAllModalOpen(true)} disabled={!hasSelection}>\n {hasSelection ? <Trans>Delete All ({selectedCount})</Trans> : <Trans>Delete All</Trans>}\n </Button>\n </Stack>\n }\n />\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 />\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, Button, TextInput, Stack } 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 >\n <Stack direction=\"vertical\" gap=\"4\">\n <p>\n {isFolder ? (\n <Trans>Are you sure you want to delete this folder?</Trans>\n ) : (\n <Trans>Are you sure you want to delete this object?</Trans>\n )}\n </p>\n\n <div className=\"bg-theme-background-lvl-2 rounded p-4\">\n <Stack direction=\"vertical\" gap=\"2\">\n <div>\n <span className=\"text-juno-grey-light-1 text-sm\">\n <Trans>Name:</Trans>\n </span>\n <div className=\"mt-1 font-mono text-sm\">{displayName}</div>\n </div>\n\n {!isFolder && objectSize !== undefined && (\n <div>\n <span className=\"text-juno-grey-light-1 text-sm\">\n <Trans>Size:</Trans>\n </span>\n <div className=\"mt-1 font-mono text-sm\">{formatBytesBinary(objectSize)}</div>\n </div>\n )}\n\n {!isFolder && lastModified && (\n <div>\n <span className=\"text-juno-grey-light-1 text-sm\">\n <Trans>Last Modified:</Trans>\n </span>\n <div className=\"mt-1 font-mono text-sm\">{new Date(lastModified).toLocaleString()}</div>\n </div>\n )}\n\n <div>\n <span className=\"text-juno-grey-light-1 text-sm\">\n <Trans>Full Path:</Trans>\n </span>\n <div className=\"mt-1 font-mono text-sm break-all\">{objectKey}</div>\n </div>\n </Stack>\n </div>\n\n <div>\n <p className=\"text-juno-red mb-2 text-sm\">\n <Trans>This action cannot be undone.</Trans>\n </p>\n <TextInput\n label={t`Type DELETE to confirm`}\n value={confirmText}\n onChange={(e) => setConfirmText(e.target.value)}\n placeholder=\"DELETE\"\n autoFocus\n />\n </div>\n\n {deleteMutation.error && (\n <p className=\"text-juno-red text-sm\">\n <Trans>Error:</Trans> {deleteMutation.error.message}\n </p>\n )}\n </Stack>\n\n <div className=\"mt-6 flex justify-end gap-2\">\n <Button variant=\"subdued\" onClick={handleClose} disabled={deleteMutation.isPending}>\n <Trans>Cancel</Trans>\n </Button>\n <Button variant=\"primary-danger\" onClick={handleConfirm} disabled={!isConfirmValid || deleteMutation.isPending}>\n {deleteMutation.isPending ? <Trans>Deleting...</Trans> : <Trans>Delete</Trans>}\n </Button>\n </div>\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 {\n Modal,\n Stack,\n Spinner,\n ComboBox,\n ComboBoxOption,\n TextInput,\n Message,\n Button,\n} from \"@cloudoperators/juno-ui-components\"\nimport { MdFolder, MdDescription, MdCreateNewFolder, MdArrowBack } from \"react-icons/md\"\nimport { useVirtualizer } from \"@tanstack/react-virtual\"\nimport { useCopyMoveModalState } from \"./hooks/useCopyMoveModalState\"\n\nconst MAX_COMBO_OPTIONS = 50\n\ninterface CopyObjectModalProps {\n isOpen: boolean\n bucketName: string\n objectKey: string\n objectSize?: number\n onClose: () => void\n onSuccess?: (objectKey: string, targetBucket: string, targetKey: string, wasOverwritten: boolean) => void\n onError?: (objectKey: string, errorMessage: string) => void\n}\n\ninterface FolderRow {\n kind: \"folder\"\n name: string\n displayName: string\n}\n\ninterface ObjectRow {\n kind: \"object\"\n name: string\n displayName: string\n}\n\ntype BrowserRow = FolderRow | ObjectRow\n\nexport const CopyObjectModal = ({\n isOpen,\n bucketName,\n objectKey,\n objectSize,\n onClose,\n onSuccess,\n onError,\n}: CopyObjectModalProps) => {\n const { t } = useLingui()\n const projectId = useProjectId()\n const utils = trpcReact.useUtils()\n const submittedKeyRef = useRef(\"\")\n\n const [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 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 || 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 font-mono 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 font-mono 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 <TextInput\n label={t`Target path`}\n value={targetPathDisplay}\n readOnly\n className=\"font-mono\"\n helptext={t`The object will be copied to this path. Navigate folders above to change the destination.`}\n />\n\n {/* Warning if target exists */}\n {checkingTarget ? (\n <Message variant=\"info\">\n <Stack direction=\"horizontal\" alignment=\"center\" gap=\"2\">\n <Spinner size=\"small\" />\n <Trans>Checking if object exists...</Trans>\n </Stack>\n </Message>\n ) : targetExists ? (\n <Message variant=\"warning\">\n <Trans>An object with this name already exists at the destination and will be overwritten.</Trans>\n </Message>\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 <Message variant=\"danger\">\n <Trans>Failed to copy object: {errorMessage}</Trans>\n </Message>\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 {\n Modal,\n Stack,\n Spinner,\n ComboBox,\n ComboBoxOption,\n TextInput,\n Message,\n Button,\n} 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 font-mono\" 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 <Message variant=\"warning\">\n <div className=\"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 </Message>\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 font-mono 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 font-mono 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 <TextInput\n label={t`Target path`}\n value={targetPathDisplay}\n readOnly\n className=\"font-mono\"\n helptext={\n isUnchanged\n ? t`Cannot move to the same location. Please select a different bucket, folder, or change the name.`\n : t`The object will be moved to this path. Navigate folders above to change the destination.`\n }\n invalid={isUnchanged}\n />\n\n {/* Info: metadata is always copied */}\n <Message variant=\"info\">\n <Trans>Object metadata will be automatically copied during the move operation.</Trans>\n </Message>\n\n {(copyMutation.isError || deleteMutation.isError) &&\n (() => {\n const copyErrorMessage = copyMutation.error?.message ?? \"\"\n const deleteErrorMessage = deleteMutation.error?.message ?? \"\"\n return (\n <Message variant=\"danger\">\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 </Message>\n )\n })()}\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 Message,\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\">Properties of</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=\"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 <Message variant=\"danger\">\n <Trans>Failed to load object metadata: {metadataErrorMessage}</Trans>\n </Message>\n ) : (\n <Stack direction=\"vertical\" gap=\"6\">\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 <Message variant=\"warning\" className=\"mb-3\">\n <Trans>Metadata size exceeds the 2KB limit. Please remove or shorten some entries before saving.</Trans>\n </Message>\n )}\n\n <Stack direction=\"horizontal\" className=\"jn:bg-theme-background-lvl-1 mb-3 justify-end p-2\">\n <Button\n label={t`Add Property`}\n onClick={() => setIsAddingNew(true)}\n variant=\"primary\"\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=\"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\n {/* Mutation error */}\n {updateMutation.isError && (\n <Message variant=\"danger\">\n <Trans>Failed to update object: {mutationErrorMessage}</Trans>\n </Message>\n )}\n </Stack>\n )}\n </Modal>\n )\n}\n","import { useState } from \"react\"\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\"\n\ninterface ObjectsTableViewProps {\n bucketName: string\n objects: S3Object[]\n folders: S3FolderPrefix[]\n currentPrefix: string\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}\n\nexport function ObjectsTableView({\n bucketName,\n objects,\n folders,\n currentPrefix,\n onFolderClick,\n onDeleteObjectSuccess,\n onDeleteObjectError,\n onCopyObjectSuccess,\n onCopyObjectError,\n onMoveObjectSuccess,\n onMoveObjectError,\n onEditMetadataSuccess,\n onEditMetadataError,\n}: ObjectsTableViewProps) {\n const { t } = useLingui()\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\n // Strip current prefix from display names\n const stripPrefix = (fullKey: string) => (currentPrefix ? fullKey.replace(currentPrefix, \"\") : fullKey)\n\n if (folders.length === 0 && objects.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 <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\n {/* Folders first */}\n {folders.map((folder) => {\n const displayName = stripPrefix(folder.prefix).replace(/\\/$/, \"\")\n return (\n <DataGridRow key={folder.prefix}>\n <DataGridCell>\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(folder.prefix)}\n title={folder.prefix}\n >\n <MdFolder size={18} className=\"text-theme-light shrink-0\" />\n <span className=\"truncate font-mono text-sm\">{displayName}</span>\n </button>\n </DataGridCell>\n <DataGridCell>—</DataGridCell>\n <DataGridCell>—</DataGridCell>\n <DataGridCell onClick={(e) => e.stopPropagation()}>\n <div className=\"flex justify-end\">\n <PopupMenu>\n <PopupMenuOptions>\n <PopupMenuItem\n label={t`Delete`}\n onClick={() =>\n setDeleteTarget({\n key: folder.prefix,\n })\n }\n />\n </PopupMenuOptions>\n </PopupMenu>\n </div>\n </DataGridCell>\n </DataGridRow>\n )\n })}\n\n {/* Objects */}\n {objects.map((obj) => {\n const displayName = stripPrefix(obj.key)\n return (\n <DataGridRow key={obj.key}>\n <DataGridCell>\n <div className=\"flex items-center gap-2\">\n <MdDescription size={18} className=\"text-theme-light shrink-0\" />\n <span className=\"truncate font-mono text-sm\">{displayName}</span>\n </div>\n </DataGridCell>\n <DataGridCell>\n <span className=\"text-juno-grey-light-1 text-sm\">{formatBytesBinary(obj.size)}</span>\n </DataGridCell>\n <DataGridCell>\n <span className=\"text-juno-grey-light-1 text-sm\">\n {obj.lastModified ? new Date(obj.lastModified).toLocaleString() : \"—\"}\n </span>\n </DataGridCell>\n <DataGridCell onClick={(e) => e.stopPropagation()}>\n <div className=\"flex justify-end\">\n <PopupMenu>\n <PopupMenuOptions>\n <PopupMenuItem\n label={t`Copy`}\n onClick={() =>\n setCopyTarget({\n key: obj.key,\n size: obj.size,\n })\n }\n />\n <PopupMenuItem\n label={t`Move`}\n onClick={() =>\n setMoveTarget({\n key: obj.key,\n size: obj.size,\n })\n }\n />\n <PopupMenuItem label={t`Edit Metadata`} onClick={() => setEditMetadataTarget(obj.key)} />\n <PopupMenuItem\n label={t`Delete`}\n onClick={() =>\n setDeleteTarget({\n key: obj.key,\n size: obj.size,\n lastModified: obj.lastModified,\n })\n }\n />\n </PopupMenuOptions>\n </PopupMenu>\n </div>\n </DataGridCell>\n </DataGridRow>\n )\n })}\n </DataGrid>\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 )\n}\n","import { Breadcrumb, BreadcrumbItem } from \"@cloudoperators/juno-ui-components\"\nimport { 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 onPrefixClick: (prefix: string) => void\n}\n\nexport function ObjectsFileNavigation({ bucketName, prefix, onPrefixClick }: ObjectsFileNavigationProps) {\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 {/* Bucket name — inventory/box icon distinguishes it from folders;\n outlined when active (current root level), filled when navigable */}\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, Button, 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 open={isOpen} onCancel={handleClose} title={<Trans>Create New Folder</Trans>} size=\"large\">\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-juno-grey-light-1 text-sm\">\n <Trans>Current location:</Trans>\n </span>\n <div className=\"mt-1 font-mono 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-juno-grey-light-1 text-sm\">\n <Trans>Full path:</Trans>\n </span>\n <div className=\"mt-1 font-mono 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\n <div className=\"mt-6 flex justify-end gap-2\">\n <Button variant=\"subdued\" onClick={handleClose} disabled={createFolderMutation.isPending}>\n <Trans>Cancel</Trans>\n </Button>\n <Button variant=\"primary\" onClick={handleCreate} disabled={!isValid || createFolderMutation.isPending}>\n {createFolderMutation.isPending ? <Trans>Creating...</Trans> : <Trans>Create Folder</Trans>}\n </Button>\n </div>\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 autoDismissTimeout?: number\n}\n\n// ── Folder operations ──────────────────────────────────────────────────────────\n\nexport const getFolderCreatedToast = (folderPath: string, config: ToastConfig): ToastProps => ({\n variant: \"success\",\n autoDismiss: true,\n autoDismissTimeout: config.autoDismissTimeout ?? 5000,\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 autoDismiss: true,\n autoDismissTimeout: config.autoDismissTimeout ?? 5000,\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 autoDismiss: true,\n autoDismissTimeout: config.autoDismissTimeout ?? 5000,\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 autoDismiss: true,\n autoDismissTimeout: config.autoDismissTimeout ?? 5000,\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 autoDismiss: true,\n autoDismissTimeout: config.autoDismissTimeout ?? 5000,\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 autoDismiss: true,\n autoDismissTimeout: config.autoDismissTimeout ?? 5000,\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 autoDismiss: true,\n autoDismissTimeout: config.autoDismissTimeout ?? 5000,\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 autoDismiss: true,\n autoDismissTimeout: config.autoDismissTimeout ?? 5000,\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 autoDismiss: true,\n autoDismissTimeout: config.autoDismissTimeout ?? 5000,\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 autoDismiss: true,\n autoDismissTimeout: config.autoDismissTimeout ?? 5000,\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, startTransition } from \"react\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { Spinner, Stack, Button, Toast, ToastProps } from \"@cloudoperators/juno-ui-components\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport { ListToolbar } from \"@/client/components/ListToolbar\"\nimport { SortSettings } from \"@/client/components/ListToolbar/types\"\nimport { ObjectsTableView } from \"./ObjectsTableView\"\nimport { ObjectsFileNavigation } from \"./ObjectsFileNavigation\"\nimport { CreateFolderModal } from \"./CreateFolderModal\"\nimport { useNavigate } from \"@tanstack/react-router\"\nimport { Route } from \"@/client/routes/_auth/projects/$projectId/storage/$provider/containers/$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 { 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 [toastData, setToastData] = useState<ToastProps | null>(null)\n\n const handleToastDismiss = () => setToastData(null)\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 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 // 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 direction=\"horizontal\" gap=\"2\" alignment=\"center\" className=\"mt-8\">\n <Spinner />\n <span className=\"text-juno-grey-light-1 text-sm\">\n <Trans>Loading objects...</Trans>\n </span>\n </Stack>\n )\n }\n\n if (error) {\n const errorMessage = error.message\n return (\n <p className=\"text-juno-red mt-4 text-sm\">\n <Trans>Failed to load objects: {errorMessage}</Trans>\n </p>\n )\n }\n\n return (\n <div className=\"relative\">\n <ObjectsFileNavigation bucketName={bucketName} prefix={currentPrefix} onPrefixClick={navigateToPrefix} />\n\n <ListToolbar\n sortSettings={sortSettings}\n searchTerm={searchParam}\n onSort={handleSortChange}\n onSearch={handleSearchChange}\n actions={\n <Stack direction=\"horizontal\" gap=\"2\">\n <Button variant=\"primary\" onClick={() => setIsCreateFolderModalOpen(true)}>\n <Trans>Create Folder</Trans>\n </Button>\n </Stack>\n }\n />\n\n <ObjectsTableView\n bucketName={bucketName}\n objects={sortedObjects}\n folders={sortedFolders}\n currentPrefix={currentPrefix}\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 />\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 {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 { ObjectBrowserView } 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 containerName: string\n }\n) => {\n const { provider, projectId, 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/compute/overview\",\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\n if (provider !== \"swift\" && provider !== \"ceph\") {\n if (!fallbackProvider) {\n throw redirect({\n to: \"/projects/$projectId/compute/overview\",\n params: { projectId },\n })\n }\n throw redirect({\n to: \"/projects/$projectId/storage/$provider/containers/$containerName/objects\",\n params: { projectId, provider: fallbackProvider, containerName },\n })\n }\n\n if (provider === \"swift\" && !hasSwift) {\n if (!hasEffectiveCeph) {\n throw redirect({\n to: \"/projects/$projectId/compute/overview\",\n params: { projectId },\n })\n }\n\n throw redirect({\n to: \"/projects/$projectId/storage/$provider/containers/$containerName/objects\",\n params: { projectId, provider: \"ceph\", containerName },\n })\n }\n\n if (provider === \"ceph\" && !hasEffectiveCeph) {\n if (!hasSwift) {\n throw redirect({\n to: \"/projects/$projectId/compute/overview\",\n params: { projectId },\n })\n }\n\n throw redirect({\n to: \"/projects/$projectId/storage/$provider/containers/$containerName/objects\",\n params: { projectId, provider: \"swift\", containerName },\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(\"/_auth/projects/$projectId/storage/$provider/containers/$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/containers\" },\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)\n\nfunction ObjectsDashboard() {\n const { project, provider, containerName } = useParams({\n from: \"/_auth/projects/$projectId/storage/$provider/containers/$containerName/objects/\",\n select: (params) => ({\n project: params.projectId,\n provider: params.provider,\n containerName: params.containerName,\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 />\n case \"ceph\":\n return <ObjectBrowserView 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-DOYFFn3Y.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","ObjectsTableView","rows","searchTerm","container","account","onFolderClick","onDeleteFolderSuccess","onDeleteFolderError","onDownloadError","onDeleteObjectSuccess","onDeleteObjectError","onCopyObjectSuccess","onCopyObjectError","onMoveObjectSuccess","onMoveObjectError","onTempUrlCopySuccess","onEditMetadataSuccess","onEditMetadataError","selectedObjects","setSelectedObjects","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","allCount","isAnyDownloading","style","paddingRight","gridColumnTemplate","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","autoDismiss","autoDismissTimeout","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","startTransition","Spinner","Button","Toast","Stack","trpcReact","useProjectId","ListToolbar","useNavigate","useParams","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","useLingui","projectId","navigate","fullPath","provider","containerName","encodedPrefix","sortDirection","search","searchParam","useSearch","currentPrefix","createFolderModalOpen","setCreateFolderModalOpen","uploadModalOpen","setUploadModalOpen","deleteAllModalOpen","setDeleteAllModalOpen","selectedObjects","setSelectedObjects","toastData","setToastData","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","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","div","onContainersClick","onPrefixClick","searchTerm","onSort","onSearch","actions","gap","onClick","disabled","rows","onFolderClick","onDeleteFolderSuccess","onDeleteFolderError","onDownloadError","onDeleteObjectSuccess","onDeleteObjectError","onCopyObjectSuccess","onCopyObjectError","onMoveObjectSuccess","onMoveObjectError","onTempUrlCopySuccess","onEditMetadataSuccess","onEditMetadataError","isOpen","objectNames","objectKeys","onClose","onSuccess","onError","onCancelled","useState","Modal","Button","TextInput","Stack","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","direction","gap","p","div","className","span","undefined","Date","toLocaleString","label","t","value","onChange","e","target","placeholder","autoFocus","variant","onClick","disabled","isPending","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","Message","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","readOnly","input","checked","isError","errorMessage","useState","useRef","useEffect","trpcReact","useProjectId","Modal","Stack","Spinner","ComboBox","ComboBoxOption","TextInput","Message","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","variant","div","strong","toFixed","onInputChange","handleSearchChange","placeholder","searchTerm","hiddenCount","totalBuckets","visibleBuckets","disabled","b","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","isError","copyErrorMessage","deleteErrorMessage","useState","useEffect","useRef","trpcReact","useProjectId","Modal","TextInput","Stack","Message","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","variant","div","p","contentType","etag","lastModified","distribution","label","onClick","icon","disabled","columns","onChange","target","placeholder","errortext","invalid","autoFocus","colSpan","useState","DataGrid","DataGridRow","DataGridCell","DataGridHeadCell","PopupMenu","PopupMenuItem","PopupMenuOptions","MdFolder","MdDescription","formatBytesBinary","DeleteObjectModal","CopyObjectModal","MoveObjectModal","EditMetadataModal","ObjectsTableView","bucketName","objects","folders","currentPrefix","onFolderClick","onDeleteObjectSuccess","onDeleteObjectError","onCopyObjectSuccess","onCopyObjectError","onMoveObjectSuccess","onMoveObjectError","onEditMetadataSuccess","onEditMetadataError","useLingui","deleteTarget","setDeleteTarget","copyTarget","setCopyTarget","moveTarget","setMoveTarget","editMetadataTarget","setEditMetadataTarget","stripPrefix","fullKey","replace","length","columns","colSpan","div","className","p","objectKey","key","objectSize","size","lastModified","isOpen","onClose","onSuccess","onError","map","folder","displayName","prefix","button","type","onClick","title","span","e","stopPropagation","label","t","obj","Date","toLocaleString","Breadcrumb","BreadcrumbItem","MdInventory2","MdOutlineInventory2","MdFolder","MdFolderOpen","prefixToSegments","prefix","parts","replace","split","filter","Boolean","map","label","i","slice","join","activeCrumbClass","ObjectsFileNavigation","bucketName","onPrefixClick","prefixSegments","isAtRoot","length","div","className","onClick","undefined","active","span","size","seg","isLast","useState","Modal","Button","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","direction","gap","p","div","className","span","label","onChange","e","target","placeholder","autoFocus","invalid","errortext","onKeyDown","key","isPending","variant","onClick","disabled","Stack","NotificationText","title","description","direction","gap","span","className","getFolderCreatedToast","folderPath","config","variant","autoDismiss","autoDismissTimeout","onDismiss","children","getFolderCreateErrorToast","errorMessage","getObjectDeletedToast","objectKey","displayName","split","filter","Boolean","pop","getObjectDeleteErrorToast","getObjectCopiedToast","targetBucket","targetKey","wasOverwritten","destination","getObjectCopyErrorToast","getObjectMovedToast","getObjectMoveErrorToast","getObjectMetadataUpdatedToast","getObjectMetadataUpdateErrorToast","useState","useEffect","startTransition","Spinner","Stack","Button","Toast","trpcReact","useProjectId","ListToolbar","ObjectsTableView","ObjectsFileNavigation","CreateFolderModal","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","encodedPrefix","sortBy","sortDirection","search","searchParam","useSearch","currentPrefix","continuationToken","setContinuationToken","undefined","allObjects","setAllObjects","allFolders","setAllFolders","hasMore","setHasMore","isCreateFolderModalOpen","setIsCreateFolderModalOpen","toastData","setToastData","handleToastDismiss","data","isLoading","error","storage","ceph","objects","list","useQuery","project_id","containerName","delimiter","maxKeys","enabled","actualObjects","filter","obj","stripped","key","replace","prev","folders","isTruncated","navigateToPrefix","loadMore","nextContinuationToken","stripPrefix","fullKey","filteredObjects","toLowerCase","includes","trim","filteredFolders","folder","sortedObjects","sort","a","b","comparison","localeCompare","aDate","lastModified","bDate","Date","getTime","size","sortedFolders","sortSettings","options","label","t","value","handleSearchChange","term","handleSortChange","newSort","resolvedSortBy","resolvedDirection","direction","gap","alignment","className","span","errorMessage","message","p","div","onPrefixClick","searchTerm","onSort","onSearch","actions","variant","onClick","onFolderClick","onDeleteObjectSuccess","objectKey","onDismiss","onDeleteObjectError","onCopyObjectSuccess","targetBucket","targetKey","wasOverwritten","onCopyObjectError","onMoveObjectSuccess","onMoveObjectError","onEditMetadataSuccess","onEditMetadataError","disabled","isOpen","onClose","onSuccess","folderPath","useParams","ErrorBoundary","Trans","SwiftObjects","ObjectBrowserView","Route","ObjectsDashboard","project","provider","containerName","from","select","params","projectId","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/ObjectsTableView.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Objects/ObjectsFileNavigation.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Objects/CreateFolderModal.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Objects/ObjectToastNotifications.tsx","../../src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Objects/ObjectBrowserView.tsx","../../src/client/routes/_auth/projects/$projectId/storage/$provider/containers/$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/containers/$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 font-mono\" 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-mono font-semibold\">\"{folderDisplayName}\"</span> and all objects within it\n will be 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/containers/$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/containers/$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/containers/$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/containers/$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/containers/$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 mb-3 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// Define column template — 5 columns: checkbox | name | last modified | size | actions\nconst GRID_COLUMN_TEMPLATE = \"40px 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}\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}: 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 allCount = rows.length\n const isAnyDownloading = downloadingRow !== null || previewingRow !== null\n\n return (\n <>\n <div className=\"relative\">\n {/* Table Header with scrollbar padding */}\n <div style={{ paddingRight: `${scrollbarWidth}px` }}>\n <DataGrid\n columns={5}\n gridColumnTemplate={GRID_COLUMN_TEMPLATE}\n className=\"objects\"\n data-testid=\"objects-table-header\"\n >\n <DataGridRow>\n <DataGridHeadCell>\n <Checkbox checked={allSelected} onChange={handleSelectAll} data-testid=\"select-all-objects\" />\n </DataGridHeadCell>\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 - 550px)\" }}\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: GRID_COLUMN_TEMPLATE,\n alignItems: \"stretch\",\n }}\n data-testid={`object-row-${row.name}`}\n >\n {/* Checkbox — only for object rows; folders get an empty cell */}\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 {/* 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\n {/* Footer with count */}\n <div className=\"text-theme-light border-theme-background-lvl-2 border-t px-4 py-2 text-sm\">\n <Trans>{allCount} items</Trans>\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/containers/$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 { 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={t`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 autoDismissTimeout?: number\n}\n\nexport const getFolderCreatedToast = (folderName: string, config: ToastConfig): ToastProps => ({\n variant: \"success\",\n autoDismiss: true,\n autoDismissTimeout: config.autoDismissTimeout ?? 5000,\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 autoDismiss: true,\n autoDismissTimeout: config.autoDismissTimeout ?? 5000,\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 autoDismiss: true,\n autoDismissTimeout: config.autoDismissTimeout ?? 5000,\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 autoDismiss: true,\n autoDismissTimeout: config.autoDismissTimeout ?? 5000,\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 autoDismiss: true,\n autoDismissTimeout: config.autoDismissTimeout ?? 5000,\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 autoDismiss: true,\n autoDismissTimeout: config.autoDismissTimeout ?? 5000,\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 autoDismiss: true,\n autoDismissTimeout: config.autoDismissTimeout ?? 5000,\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 autoDismiss: true,\n autoDismissTimeout: config.autoDismissTimeout ?? 5000,\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 autoDismiss: true,\n autoDismissTimeout: config.autoDismissTimeout ?? 5000,\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 autoDismiss: true,\n autoDismissTimeout: config.autoDismissTimeout ?? 5000,\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 autoDismiss: true,\n autoDismissTimeout: config.autoDismissTimeout ?? 5000,\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 autoDismiss: true,\n autoDismissTimeout: config.autoDismissTimeout ?? 4000,\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 autoDismiss: true,\n autoDismissTimeout: config.autoDismissTimeout ?? 5000,\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 autoDismiss: true,\n autoDismissTimeout: config.autoDismissTimeout ?? 5000,\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 autoDismiss: true,\n autoDismissTimeout: config.autoDismissTimeout ?? 5000,\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 autoDismiss: true,\n autoDismissTimeout: config.autoDismissTimeout ?? 4000,\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 autoDismiss: true,\n autoDismissTimeout: config.autoDismissTimeout ?? 5000,\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 autoDismiss: true,\n autoDismissTimeout: config.autoDismissTimeout ?? 5000,\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 autoDismiss: true,\n autoDismissTimeout: config.autoDismissTimeout ?? 5000,\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, startTransition } from \"react\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { Spinner, Button, Toast, ToastProps, Stack } from \"@cloudoperators/juno-ui-components\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport { ObjectSummary } from \"@/server/Storage/types/swift\"\nimport { ListToolbar } from \"@/client/components/ListToolbar\"\nimport { SortSettings } from \"@/client/components/ListToolbar/types\"\nimport { useNavigate, useParams } from \"@tanstack/react-router\"\nimport { Route } from \"../../../$provider/containers/$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 = () => {\n const { t } = useLingui()\n const projectId = useProjectId()\n const navigate = useNavigate({ from: Route.fullPath })\n\n const { provider, containerName } = useParams({\n from: \"/_auth/projects/$projectId/storage/$provider/containers/$containerName/objects/\",\n })\n\n const { prefix: encodedPrefix, sortBy, sortDirection, search: searchParam = \"\" } = Route.useSearch()\n const currentPrefix = decodePrefix(encodedPrefix)\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 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/containers\",\n params: { projectId, provider },\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 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=\"fixed 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=\"fixed 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 return (\n <div className=\"relative\">\n <ObjectsFileNavigation\n containerName={containerName}\n currentPrefix={currentPrefix}\n onContainersClick={navigateToContainers}\n onPrefixClick={navigateToPrefix}\n />\n <ListToolbar\n sortSettings={sortSettings}\n searchTerm={searchParam}\n onSort={handleSortChange}\n onSearch={handleSearchChange}\n actions={\n <Stack direction=\"horizontal\" gap=\"2\">\n <Button variant=\"primary\" onClick={() => setCreateFolderModalOpen(true)}>\n <Trans>Create Folder</Trans>\n </Button>\n <Button onClick={() => setUploadModalOpen(true)}>\n <Trans>Upload Object</Trans>\n </Button>\n <Button variant=\"primary-danger\" onClick={() => setDeleteAllModalOpen(true)} disabled={!hasSelection}>\n {hasSelection ? <Trans>Delete All ({selectedCount})</Trans> : <Trans>Delete All</Trans>}\n </Button>\n </Stack>\n }\n />\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 />\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, Button, TextInput, Stack } 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 >\n <Stack direction=\"vertical\" gap=\"4\">\n <p>\n {isFolder ? (\n <Trans>Are you sure you want to delete this folder?</Trans>\n ) : (\n <Trans>Are you sure you want to delete this object?</Trans>\n )}\n </p>\n\n <div className=\"bg-theme-background-lvl-2 rounded p-4\">\n <Stack direction=\"vertical\" gap=\"2\">\n <div>\n <span className=\"text-juno-grey-light-1 text-sm\">\n <Trans>Name:</Trans>\n </span>\n <div className=\"mt-1 font-mono text-sm\">{displayName}</div>\n </div>\n\n {!isFolder && objectSize !== undefined && (\n <div>\n <span className=\"text-juno-grey-light-1 text-sm\">\n <Trans>Size:</Trans>\n </span>\n <div className=\"mt-1 font-mono text-sm\">{formatBytesBinary(objectSize)}</div>\n </div>\n )}\n\n {!isFolder && lastModified && (\n <div>\n <span className=\"text-juno-grey-light-1 text-sm\">\n <Trans>Last Modified:</Trans>\n </span>\n <div className=\"mt-1 font-mono text-sm\">{new Date(lastModified).toLocaleString()}</div>\n </div>\n )}\n\n <div>\n <span className=\"text-juno-grey-light-1 text-sm\">\n <Trans>Full Path:</Trans>\n </span>\n <div className=\"mt-1 font-mono text-sm break-all\">{objectKey}</div>\n </div>\n </Stack>\n </div>\n\n <div>\n <p className=\"text-juno-red mb-2 text-sm\">\n <Trans>This action cannot be undone.</Trans>\n </p>\n <TextInput\n label={t`Type DELETE to confirm`}\n value={confirmText}\n onChange={(e) => setConfirmText(e.target.value)}\n placeholder=\"DELETE\"\n autoFocus\n />\n </div>\n\n {deleteMutation.error && (\n <p className=\"text-juno-red text-sm\">\n <Trans>Error:</Trans> {deleteMutation.error.message}\n </p>\n )}\n </Stack>\n\n <div className=\"mt-6 flex justify-end gap-2\">\n <Button variant=\"subdued\" onClick={handleClose} disabled={deleteMutation.isPending}>\n <Trans>Cancel</Trans>\n </Button>\n <Button variant=\"primary-danger\" onClick={handleConfirm} disabled={!isConfirmValid || deleteMutation.isPending}>\n {deleteMutation.isPending ? <Trans>Deleting...</Trans> : <Trans>Delete</Trans>}\n </Button>\n </div>\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 {\n Modal,\n Stack,\n Spinner,\n ComboBox,\n ComboBoxOption,\n TextInput,\n Message,\n Button,\n} from \"@cloudoperators/juno-ui-components\"\nimport { MdFolder, MdDescription, MdCreateNewFolder, MdArrowBack } from \"react-icons/md\"\nimport { useVirtualizer } from \"@tanstack/react-virtual\"\nimport { useCopyMoveModalState } from \"./hooks/useCopyMoveModalState\"\n\nconst MAX_COMBO_OPTIONS = 50\n\ninterface CopyObjectModalProps {\n isOpen: boolean\n bucketName: string\n objectKey: string\n objectSize?: number\n onClose: () => void\n onSuccess?: (objectKey: string, targetBucket: string, targetKey: string, wasOverwritten: boolean) => void\n onError?: (objectKey: string, errorMessage: string) => void\n}\n\ninterface FolderRow {\n kind: \"folder\"\n name: string\n displayName: string\n}\n\ninterface ObjectRow {\n kind: \"object\"\n name: string\n displayName: string\n}\n\ntype BrowserRow = FolderRow | ObjectRow\n\nexport const CopyObjectModal = ({\n isOpen,\n bucketName,\n objectKey,\n objectSize,\n onClose,\n onSuccess,\n onError,\n}: CopyObjectModalProps) => {\n const { t } = useLingui()\n const projectId = useProjectId()\n const utils = trpcReact.useUtils()\n const submittedKeyRef = useRef(\"\")\n\n const [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 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 || 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 font-mono 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 font-mono 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 <TextInput\n label={t`Target path`}\n value={targetPathDisplay}\n readOnly\n className=\"font-mono\"\n helptext={t`The object will be copied to this path. Navigate folders above to change the destination.`}\n />\n\n {/* Warning if target exists */}\n {checkingTarget ? (\n <Message variant=\"info\">\n <Stack direction=\"horizontal\" alignment=\"center\" gap=\"2\">\n <Spinner size=\"small\" />\n <Trans>Checking if object exists...</Trans>\n </Stack>\n </Message>\n ) : targetExists ? (\n <Message variant=\"warning\">\n <Trans>An object with this name already exists at the destination and will be overwritten.</Trans>\n </Message>\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 <Message variant=\"danger\">\n <Trans>Failed to copy object: {errorMessage}</Trans>\n </Message>\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 {\n Modal,\n Stack,\n Spinner,\n ComboBox,\n ComboBoxOption,\n TextInput,\n Message,\n Button,\n} 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 font-mono\" 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 <Message variant=\"warning\">\n <div className=\"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 </Message>\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 font-mono 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 font-mono 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 <TextInput\n label={t`Target path`}\n value={targetPathDisplay}\n readOnly\n className=\"font-mono\"\n helptext={\n isUnchanged\n ? t`Cannot move to the same location. Please select a different bucket, folder, or change the name.`\n : t`The object will be moved to this path. Navigate folders above to change the destination.`\n }\n invalid={isUnchanged}\n />\n\n {/* Info: metadata is always copied */}\n <Message variant=\"info\">\n <Trans>Object metadata will be automatically copied during the move operation.</Trans>\n </Message>\n\n {(copyMutation.isError || deleteMutation.isError) &&\n (() => {\n const copyErrorMessage = copyMutation.error?.message ?? \"\"\n const deleteErrorMessage = deleteMutation.error?.message ?? \"\"\n return (\n <Message variant=\"danger\">\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 </Message>\n )\n })()}\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 Message,\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\">Properties of</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=\"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 <Message variant=\"danger\">\n <Trans>Failed to load object metadata: {metadataErrorMessage}</Trans>\n </Message>\n ) : (\n <Stack direction=\"vertical\" gap=\"6\">\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 <Message variant=\"warning\" className=\"mb-3\">\n <Trans>Metadata size exceeds the 2KB limit. Please remove or shorten some entries before saving.</Trans>\n </Message>\n )}\n\n <Stack direction=\"horizontal\" className=\"jn:bg-theme-background-lvl-1 mb-3 justify-end p-2\">\n <Button\n label={t`Add Property`}\n onClick={() => setIsAddingNew(true)}\n variant=\"primary\"\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=\"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\n {/* Mutation error */}\n {updateMutation.isError && (\n <Message variant=\"danger\">\n <Trans>Failed to update object: {mutationErrorMessage}</Trans>\n </Message>\n )}\n </Stack>\n )}\n </Modal>\n )\n}\n","import { useState } from \"react\"\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\"\n\ninterface ObjectsTableViewProps {\n bucketName: string\n objects: S3Object[]\n folders: S3FolderPrefix[]\n currentPrefix: string\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}\n\nexport function ObjectsTableView({\n bucketName,\n objects,\n folders,\n currentPrefix,\n onFolderClick,\n onDeleteObjectSuccess,\n onDeleteObjectError,\n onCopyObjectSuccess,\n onCopyObjectError,\n onMoveObjectSuccess,\n onMoveObjectError,\n onEditMetadataSuccess,\n onEditMetadataError,\n}: ObjectsTableViewProps) {\n const { t } = useLingui()\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\n // Strip current prefix from display names\n const stripPrefix = (fullKey: string) => (currentPrefix ? fullKey.replace(currentPrefix, \"\") : fullKey)\n\n if (folders.length === 0 && objects.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 <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\n {/* Folders first */}\n {folders.map((folder) => {\n const displayName = stripPrefix(folder.prefix).replace(/\\/$/, \"\")\n return (\n <DataGridRow key={folder.prefix}>\n <DataGridCell>\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(folder.prefix)}\n title={folder.prefix}\n >\n <MdFolder size={18} className=\"text-theme-light shrink-0\" />\n <span className=\"truncate font-mono text-sm\">{displayName}</span>\n </button>\n </DataGridCell>\n <DataGridCell>—</DataGridCell>\n <DataGridCell>—</DataGridCell>\n <DataGridCell onClick={(e) => e.stopPropagation()}>\n <div className=\"flex justify-end\">\n <PopupMenu>\n <PopupMenuOptions>\n <PopupMenuItem\n label={t`Delete`}\n onClick={() =>\n setDeleteTarget({\n key: folder.prefix,\n })\n }\n />\n </PopupMenuOptions>\n </PopupMenu>\n </div>\n </DataGridCell>\n </DataGridRow>\n )\n })}\n\n {/* Objects */}\n {objects.map((obj) => {\n const displayName = stripPrefix(obj.key)\n return (\n <DataGridRow key={obj.key}>\n <DataGridCell>\n <div className=\"flex items-center gap-2\">\n <MdDescription size={18} className=\"text-theme-light shrink-0\" />\n <span className=\"truncate font-mono text-sm\">{displayName}</span>\n </div>\n </DataGridCell>\n <DataGridCell>\n <span className=\"text-juno-grey-light-1 text-sm\">{formatBytesBinary(obj.size)}</span>\n </DataGridCell>\n <DataGridCell>\n <span className=\"text-juno-grey-light-1 text-sm\">\n {obj.lastModified ? new Date(obj.lastModified).toLocaleString() : \"—\"}\n </span>\n </DataGridCell>\n <DataGridCell onClick={(e) => e.stopPropagation()}>\n <div className=\"flex justify-end\">\n <PopupMenu>\n <PopupMenuOptions>\n <PopupMenuItem\n label={t`Copy`}\n onClick={() =>\n setCopyTarget({\n key: obj.key,\n size: obj.size,\n })\n }\n />\n <PopupMenuItem\n label={t`Move`}\n onClick={() =>\n setMoveTarget({\n key: obj.key,\n size: obj.size,\n })\n }\n />\n <PopupMenuItem label={t`Edit Metadata`} onClick={() => setEditMetadataTarget(obj.key)} />\n <PopupMenuItem\n label={t`Delete`}\n onClick={() =>\n setDeleteTarget({\n key: obj.key,\n size: obj.size,\n lastModified: obj.lastModified,\n })\n }\n />\n </PopupMenuOptions>\n </PopupMenu>\n </div>\n </DataGridCell>\n </DataGridRow>\n )\n })}\n </DataGrid>\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 )\n}\n","import { Breadcrumb, BreadcrumbItem } from \"@cloudoperators/juno-ui-components\"\nimport { 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 onPrefixClick: (prefix: string) => void\n}\n\nexport function ObjectsFileNavigation({ bucketName, prefix, onPrefixClick }: ObjectsFileNavigationProps) {\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 {/* Bucket name — inventory/box icon distinguishes it from folders;\n outlined when active (current root level), filled when navigable */}\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, Button, 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 open={isOpen} onCancel={handleClose} title={<Trans>Create New Folder</Trans>} size=\"large\">\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-juno-grey-light-1 text-sm\">\n <Trans>Current location:</Trans>\n </span>\n <div className=\"mt-1 font-mono 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-juno-grey-light-1 text-sm\">\n <Trans>Full path:</Trans>\n </span>\n <div className=\"mt-1 font-mono 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\n <div className=\"mt-6 flex justify-end gap-2\">\n <Button variant=\"subdued\" onClick={handleClose} disabled={createFolderMutation.isPending}>\n <Trans>Cancel</Trans>\n </Button>\n <Button variant=\"primary\" onClick={handleCreate} disabled={!isValid || createFolderMutation.isPending}>\n {createFolderMutation.isPending ? <Trans>Creating...</Trans> : <Trans>Create Folder</Trans>}\n </Button>\n </div>\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 autoDismissTimeout?: number\n}\n\n// ── Folder operations ──────────────────────────────────────────────────────────\n\nexport const getFolderCreatedToast = (folderPath: string, config: ToastConfig): ToastProps => ({\n variant: \"success\",\n autoDismiss: true,\n autoDismissTimeout: config.autoDismissTimeout ?? 5000,\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 autoDismiss: true,\n autoDismissTimeout: config.autoDismissTimeout ?? 5000,\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 autoDismiss: true,\n autoDismissTimeout: config.autoDismissTimeout ?? 5000,\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 autoDismiss: true,\n autoDismissTimeout: config.autoDismissTimeout ?? 5000,\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 autoDismiss: true,\n autoDismissTimeout: config.autoDismissTimeout ?? 5000,\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 autoDismiss: true,\n autoDismissTimeout: config.autoDismissTimeout ?? 5000,\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 autoDismiss: true,\n autoDismissTimeout: config.autoDismissTimeout ?? 5000,\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 autoDismiss: true,\n autoDismissTimeout: config.autoDismissTimeout ?? 5000,\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 autoDismiss: true,\n autoDismissTimeout: config.autoDismissTimeout ?? 5000,\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 autoDismiss: true,\n autoDismissTimeout: config.autoDismissTimeout ?? 5000,\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, startTransition } from \"react\"\nimport { Trans, useLingui } from \"@lingui/react/macro\"\nimport { Spinner, Stack, Button, Toast, ToastProps } from \"@cloudoperators/juno-ui-components\"\nimport { trpcReact } from \"@/client/trpcClient\"\nimport { useProjectId } from \"@/client/hooks/useProjectId\"\nimport { ListToolbar } from \"@/client/components/ListToolbar\"\nimport { SortSettings } from \"@/client/components/ListToolbar/types\"\nimport { ObjectsTableView } from \"./ObjectsTableView\"\nimport { ObjectsFileNavigation } from \"./ObjectsFileNavigation\"\nimport { CreateFolderModal } from \"./CreateFolderModal\"\nimport { useNavigate } from \"@tanstack/react-router\"\nimport { Route } from \"@/client/routes/_auth/projects/$projectId/storage/$provider/containers/$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 { 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 [toastData, setToastData] = useState<ToastProps | null>(null)\n\n const handleToastDismiss = () => setToastData(null)\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 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 // 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 direction=\"horizontal\" gap=\"2\" alignment=\"center\" className=\"mt-8\">\n <Spinner />\n <span className=\"text-juno-grey-light-1 text-sm\">\n <Trans>Loading objects...</Trans>\n </span>\n </Stack>\n )\n }\n\n if (error) {\n const errorMessage = error.message\n return (\n <p className=\"text-juno-red mt-4 text-sm\">\n <Trans>Failed to load objects: {errorMessage}</Trans>\n </p>\n )\n }\n\n return (\n <div className=\"relative\">\n <ObjectsFileNavigation bucketName={bucketName} prefix={currentPrefix} onPrefixClick={navigateToPrefix} />\n\n <ListToolbar\n sortSettings={sortSettings}\n searchTerm={searchParam}\n onSort={handleSortChange}\n onSearch={handleSearchChange}\n actions={\n <Stack direction=\"horizontal\" gap=\"2\">\n <Button variant=\"primary\" onClick={() => setIsCreateFolderModalOpen(true)}>\n <Trans>Create Folder</Trans>\n </Button>\n </Stack>\n }\n />\n\n <ObjectsTableView\n bucketName={bucketName}\n objects={sortedObjects}\n folders={sortedFolders}\n currentPrefix={currentPrefix}\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 />\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 {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 { ObjectBrowserView } 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 containerName: string\n }\n) => {\n const { provider, projectId, 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\n if (provider !== \"swift\" && provider !== \"ceph\") {\n if (!fallbackProvider) {\n throw redirect({\n to: \"/projects/$projectId\",\n params: { projectId },\n })\n }\n throw redirect({\n to: \"/projects/$projectId/storage/$provider/containers/$containerName/objects\",\n params: { projectId, provider: fallbackProvider, 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/containers/$containerName/objects\",\n params: { projectId, provider: \"ceph\", 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/containers/$containerName/objects\",\n params: { projectId, provider: \"swift\", containerName },\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(\"/_auth/projects/$projectId/storage/$provider/containers/$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/containers\" },\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)\n\nfunction ObjectsDashboard() {\n const { project, provider, containerName } = useParams({\n from: \"/_auth/projects/$projectId/storage/$provider/containers/$containerName/objects/\",\n select: (params) => ({\n project: params.projectId,\n provider: params.provider,\n containerName: params.containerName,\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 />\n case \"ceph\":\n return <ObjectBrowserView 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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"}
|