diff --git a/webapp/src/App.tsx b/webapp/src/App.tsx index d10d6ea..0a21c34 100644 --- a/webapp/src/App.tsx +++ b/webapp/src/App.tsx @@ -1116,6 +1116,7 @@ export default function App() { onBulkMoveVaultItems: vaultSendActions.bulkMoveVaultItems, onVerifyMasterPassword: vaultSendActions.verifyMasterPassword, onCreateFolder: vaultSendActions.createFolder, + onRenameFolder: vaultSendActions.renameFolder, onDeleteFolder: vaultSendActions.deleteFolder, onBulkDeleteFolders: vaultSendActions.bulkDeleteFolders, onDownloadVaultAttachment: vaultSendActions.downloadVaultAttachment, diff --git a/webapp/src/components/AppMainRoutes.tsx b/webapp/src/components/AppMainRoutes.tsx index 6ab5f27..f16edba 100644 --- a/webapp/src/components/AppMainRoutes.tsx +++ b/webapp/src/components/AppMainRoutes.tsx @@ -74,6 +74,7 @@ export interface AppMainRoutesProps { onBulkMoveVaultItems: (ids: string[], folderId: string | null) => Promise; onVerifyMasterPassword: (email: string, password: string) => Promise; onCreateFolder: (name: string) => Promise; + onRenameFolder: (folderId: string, name: string) => Promise; onDeleteFolder: (folderId: string) => Promise; onBulkDeleteFolders: (folderIds: string[]) => Promise; onDownloadVaultAttachment: (cipher: Cipher, attachmentId: string) => Promise; @@ -192,6 +193,7 @@ export default function AppMainRoutes(props: AppMainRoutesProps) { onVerifyMasterPassword={props.onVerifyMasterPassword} onNotify={props.onNotify} onCreateFolder={props.onCreateFolder} + onRenameFolder={props.onRenameFolder} onDeleteFolder={props.onDeleteFolder} onBulkDeleteFolders={props.onBulkDeleteFolders} onDownloadAttachment={props.onDownloadVaultAttachment} diff --git a/webapp/src/components/VaultPage.tsx b/webapp/src/components/VaultPage.tsx index c3a39a5..28a8b54 100644 --- a/webapp/src/components/VaultPage.tsx +++ b/webapp/src/components/VaultPage.tsx @@ -50,6 +50,7 @@ interface VaultPageProps { onVerifyMasterPassword: (email: string, password: string) => Promise; onNotify: (type: 'success' | 'error' | 'warning', text: string) => void; onCreateFolder: (name: string) => Promise; + onRenameFolder: (folderId: string, name: string) => Promise; onDeleteFolder: (folderId: string) => Promise; onBulkDeleteFolders: (folderIds: string[]) => Promise; onDownloadAttachment: (cipher: Cipher, attachmentId: string) => Promise; @@ -91,6 +92,8 @@ export default function VaultPage(props: VaultPageProps) { const [moveFolderId, setMoveFolderId] = useState('__none__'); const [createFolderOpen, setCreateFolderOpen] = useState(false); const [newFolderName, setNewFolderName] = useState(''); + const [pendingRenameFolder, setPendingRenameFolder] = useState(null); + const [renameFolderName, setRenameFolderName] = useState(''); const [pendingDeleteFolder, setPendingDeleteFolder] = useState(null); const [deleteAllFoldersOpen, setDeleteAllFoldersOpen] = useState(false); const [totpLive, setTotpLive] = useState<{ code: string; remain: number } | null>(null); @@ -699,6 +702,23 @@ function folderName(id: string | null | undefined): string { } } + async function confirmRenameFolder(): Promise { + if (!pendingRenameFolder) return; + const nextName = renameFolderName.trim(); + if (!nextName) { + props.onNotify('error', t('txt_folder_name_is_required')); + return; + } + setBusy(true); + try { + await props.onRenameFolder(pendingRenameFolder.id, nextName); + setPendingRenameFolder(null); + setRenameFolderName(''); + } finally { + setBusy(false); + } + } + async function confirmBulkRestore(): Promise { const ids = Object.entries(selectedMap) .filter(([, selected]) => selected) @@ -806,6 +826,10 @@ function folderName(id: string | null | undefined): string { onChangeFilter={setSidebarFilter} onOpenDeleteAllFolders={() => setDeleteAllFoldersOpen(true)} onOpenCreateFolder={() => setCreateFolderOpen(true)} + onOpenRenameFolder={(folder) => { + setPendingRenameFolder(folder); + setRenameFolderName(folder.decName || folder.name || ''); + }} onOpenDeleteFolder={setPendingDeleteFolder} /> @@ -986,6 +1010,8 @@ function folderName(id: string | null | undefined): string { folders={props.folders} createFolderOpen={createFolderOpen} newFolderName={newFolderName} + renameFolderOpen={!!pendingRenameFolder} + renameFolderName={renameFolderName} pendingDeleteFolder={pendingDeleteFolder} deleteAllFoldersOpen={deleteAllFoldersOpen} repromptOpen={repromptOpen} @@ -1036,6 +1062,12 @@ function folderName(id: string | null | undefined): string { setNewFolderName(''); }} onNewFolderNameChange={setNewFolderName} + onConfirmRenameFolder={() => void confirmRenameFolder()} + onCancelRenameFolder={() => { + setPendingRenameFolder(null); + setRenameFolderName(''); + }} + onRenameFolderNameChange={setRenameFolderName} onConfirmDeleteFolder={() => void confirmDeleteFolder()} onCancelDeleteFolder={() => setPendingDeleteFolder(null)} onConfirmDeleteAllFolders={() => void confirmDeleteAllFolders()} @@ -1051,7 +1083,3 @@ function folderName(id: string | null | undefined): string { ); } - - - - diff --git a/webapp/src/components/vault/VaultDialogs.tsx b/webapp/src/components/vault/VaultDialogs.tsx index 0d5e0af..9ffb057 100644 --- a/webapp/src/components/vault/VaultDialogs.tsx +++ b/webapp/src/components/vault/VaultDialogs.tsx @@ -19,6 +19,8 @@ interface VaultDialogsProps { folders: Folder[]; createFolderOpen: boolean; newFolderName: string; + renameFolderOpen: boolean; + renameFolderName: string; pendingDeleteFolder: Folder | null; deleteAllFoldersOpen: boolean; repromptOpen: boolean; @@ -42,6 +44,9 @@ interface VaultDialogsProps { onConfirmCreateFolder: () => void; onCancelCreateFolder: () => void; onNewFolderNameChange: (value: string) => void; + onConfirmRenameFolder: () => void; + onCancelRenameFolder: () => void; + onRenameFolderNameChange: (value: string) => void; onConfirmDeleteFolder: () => void; onCancelDeleteFolder: () => void; onConfirmDeleteAllFolders: () => void; @@ -150,6 +155,13 @@ export default function VaultDialogs(props: VaultDialogsProps) { + + + + void; onOpenDeleteAllFolders: () => void; onOpenCreateFolder: () => void; + onOpenRenameFolder: (folder: Folder) => void; onOpenDeleteFolder: (folder: Folder) => void; } @@ -113,6 +115,20 @@ export default function VaultSidebar(props: VaultSidebarProps) { {folder.decName || folder.name || folder.id} +