feat: version 2.14.0 -- compartir grupo completo y destruir con cascada

Contraseñas: "Compartir grupo" aplica el mismo share de solo lectura a todas
las credenciales de un grupo de una vez (el grupo sigue sin ser una unidad
de permiso -- es una accion de conveniencia). El grupo y cada credencial se
marcan con el icono de compartido. "Destruir grupo" ahora tiene dos
opciones: solo desagrupar (como antes) o destruir tambien las N credenciales,
con advertencia explicita del conteo.

Fix de paso en ComboBox (afecta a toda la app): el panel se cerraba solo al
abrirse si el trigger estaba cerca del borde de un contenedor con scroll,
por un micro-scroll automatico del navegador al enfocar el boton.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Milton Gonzalez
2026-10-14 17:42:39 -05:00
parent dad73b841d
commit 7139f1604e
12 changed files with 151 additions and 24 deletions
+21 -2
View File
@@ -176,10 +176,14 @@ export async function updateGroup(id, payload, currentUser) {
return group;
}
export async function removeGroup(id, currentUser) {
// cascade=false (default): borrado "suave", las entradas quedan sin grupo (como siempre).
// cascade=true: ademas destruye TODAS las entradas del grupo -- irreversible, ver confirmacion
// fuerte en el frontend (ContrasenasPage.jsx#confirmDeleteGroup).
export async function removeGroup(id, currentUser, cascade = false) {
await getOwnGroupOr404(id, currentUser);
if (cascade) await repo.removeEntriesInGroup(id);
await repo.removeGroup(id);
await logAudit({ userId: currentUser.id, action: 'delete', entityType: 'vault_group', entityId: id });
await logAudit({ userId: currentUser.id, action: 'delete', entityType: 'vault_group', entityId: id, detail: { cascade } });
}
// --- Compartir una entrada (solo lectura) ---
@@ -207,6 +211,21 @@ export async function unshareEntry(id, targetUserId, currentUser) {
return shares;
}
// Compartir TODAS las entradas de un grupo de una vez (conveniencia desde el menu del grupo) --
// el grupo sigue sin ser una unidad de permiso: esto solo aplica el mismo share de siempre a
// cada entrada que tiene hoy ese group_id, una por una. Entradas que se agreguen al grupo
// despues NO heredan el share retroactivamente.
export async function shareGroup(groupId, targetUserId, currentUser) {
await getOwnGroupOr404(groupId, currentUser);
if (!targetUserId) throw new HttpError(400, 'Indica un usuario');
if (targetUserId === currentUser.id) throw new HttpError(400, 'No puedes compartir contigo mismo');
const targetUser = await usersRepo.findById(targetUserId);
if (!targetUser) throw new HttpError(404, 'Usuario no encontrado');
const sharedCount = await repo.shareGroupEntries(groupId, targetUserId);
await logAudit({ userId: currentUser.id, action: 'share', entityType: 'vault_group', entityId: groupId, detail: { userId: targetUserId, entriesCount: sharedCount } });
return { sharedCount };
}
// --- PIN ---
export async function getStatus(currentUser) {