fix(frontend): English UI strings for session menu/dialogs; rename empty-guard + cancel test
- SessionMenu: anglicize all Italian labels (Vista divisa → Split view, etc.) - RenameDialog: add empty-name guard + change title to "Rename session" - DeleteConfirmDialog: translate title and description to English - SessionActions.test: add 2 new tests (empty name guard, cancel on DeleteConfirmDialog) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -12,9 +12,9 @@ export function DeleteConfirmDialog({ open, label, onOpenChange, onConfirm }: Pr
|
|||||||
return (
|
return (
|
||||||
<Dialog open={open} onOpenChange={onOpenChange}>
|
<Dialog open={open} onOpenChange={onOpenChange}>
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
<DialogHeader><DialogTitle>Elimina definitivamente</DialogTitle></DialogHeader>
|
<DialogHeader><DialogTitle>Delete permanently</DialogTitle></DialogHeader>
|
||||||
<DialogDescription>
|
<DialogDescription>
|
||||||
"{label}" verrà eliminata definitivamente, inclusi tutti i suoi documenti. L'operazione non è reversibile.
|
"{label}" will be permanently deleted, including all of its documents. This action cannot be undone.
|
||||||
</DialogDescription>
|
</DialogDescription>
|
||||||
<DialogFooter>
|
<DialogFooter>
|
||||||
<Button type="button" variant="outline" size="sm" onClick={() => onOpenChange(false)}>Cancel</Button>
|
<Button type="button" variant="outline" size="sm" onClick={() => onOpenChange(false)}>Cancel</Button>
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ export function RenameDialog({ open, initial, onOpenChange, onSubmit }: Props) {
|
|||||||
|
|
||||||
function submit(e: React.FormEvent) {
|
function submit(e: React.FormEvent) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
if (!name.trim()) return;
|
||||||
onSubmit(name.trim());
|
onSubmit(name.trim());
|
||||||
onOpenChange(false);
|
onOpenChange(false);
|
||||||
}
|
}
|
||||||
@@ -22,7 +23,7 @@ export function RenameDialog({ open, initial, onOpenChange, onSubmit }: Props) {
|
|||||||
return (
|
return (
|
||||||
<Dialog open={open} onOpenChange={onOpenChange}>
|
<Dialog open={open} onOpenChange={onOpenChange}>
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
<DialogHeader><DialogTitle>Rinomina sessione</DialogTitle></DialogHeader>
|
<DialogHeader><DialogTitle>Rename session</DialogTitle></DialogHeader>
|
||||||
<form onSubmit={submit} className="flex flex-col gap-3">
|
<form onSubmit={submit} className="flex flex-col gap-3">
|
||||||
<div>
|
<div>
|
||||||
<label className="mb-1.5 block text-xs font-medium text-muted-foreground" htmlFor="rename-name">Name</label>
|
<label className="mb-1.5 block text-xs font-medium text-muted-foreground" htmlFor="rename-name">Name</label>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { DeleteConfirmDialog } from "./DeleteConfirmDialog";
|
|||||||
test("RenameDialog submits the edited name", async () => {
|
test("RenameDialog submits the edited name", async () => {
|
||||||
const onSubmit = vi.fn();
|
const onSubmit = vi.fn();
|
||||||
render(<RenameDialog open initial="Vecchio" onOpenChange={vi.fn()} onSubmit={onSubmit} />);
|
render(<RenameDialog open initial="Vecchio" onOpenChange={vi.fn()} onSubmit={onSubmit} />);
|
||||||
const input = screen.getByLabelText(/name/i);
|
const input = screen.getByDisplayValue("Vecchio");
|
||||||
await userEvent.clear(input);
|
await userEvent.clear(input);
|
||||||
await userEvent.type(input, "Nuovo");
|
await userEvent.type(input, "Nuovo");
|
||||||
await userEvent.click(screen.getByRole("button", { name: /save/i }));
|
await userEvent.click(screen.getByRole("button", { name: /save/i }));
|
||||||
@@ -21,3 +21,19 @@ test("DeleteConfirmDialog confirms only on the destructive button", async () =>
|
|||||||
await userEvent.click(screen.getByRole("button", { name: /delete/i }));
|
await userEvent.click(screen.getByRole("button", { name: /delete/i }));
|
||||||
expect(onConfirm).toHaveBeenCalled();
|
expect(onConfirm).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("RenameDialog does not submit an empty name", async () => {
|
||||||
|
const onSubmit = vi.fn();
|
||||||
|
render(<RenameDialog open initial="Old" onOpenChange={vi.fn()} onSubmit={onSubmit} />);
|
||||||
|
const input = screen.getByDisplayValue("Old");
|
||||||
|
await userEvent.clear(input);
|
||||||
|
await userEvent.click(screen.getByRole("button", { name: /save/i }));
|
||||||
|
expect(onSubmit).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("DeleteConfirmDialog does not confirm when Cancel is clicked", async () => {
|
||||||
|
const onConfirm = vi.fn();
|
||||||
|
render(<DeleteConfirmDialog open label="X" onOpenChange={vi.fn()} onConfirm={onConfirm} />);
|
||||||
|
await userEvent.click(screen.getByRole("button", { name: /cancel/i }));
|
||||||
|
expect(onConfirm).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|||||||
@@ -29,10 +29,10 @@ export function SessionMenu({ session, groups, onView, onRename, onMove, onNewGr
|
|||||||
<Menu.Portal>
|
<Menu.Portal>
|
||||||
<Menu.Positioner side="bottom" align="end" sideOffset={4}>
|
<Menu.Positioner side="bottom" align="end" sideOffset={4}>
|
||||||
<Menu.Popup className="z-50 min-w-44 rounded-lg bg-popover p-1 text-popover-foreground shadow-md ring-1 ring-foreground/10 outline-none">
|
<Menu.Popup className="z-50 min-w-44 rounded-lg bg-popover p-1 text-popover-foreground shadow-md ring-1 ring-foreground/10 outline-none">
|
||||||
<Menu.Item className={itemCls} onClick={onView}>Vista divisa</Menu.Item>
|
<Menu.Item className={itemCls} onClick={onView}>Split view</Menu.Item>
|
||||||
<Menu.Item className={itemCls} onClick={onRename}>Rinomina</Menu.Item>
|
<Menu.Item className={itemCls} onClick={onRename}>Rename</Menu.Item>
|
||||||
<Menu.SubmenuRoot>
|
<Menu.SubmenuRoot>
|
||||||
<Menu.SubmenuTrigger className={itemCls}>Sposta nel gruppo ›</Menu.SubmenuTrigger>
|
<Menu.SubmenuTrigger className={itemCls}>Move to group ›</Menu.SubmenuTrigger>
|
||||||
<Menu.Portal>
|
<Menu.Portal>
|
||||||
<Menu.Positioner side="right" align="start">
|
<Menu.Positioner side="right" align="start">
|
||||||
<Menu.Popup className="z-50 min-w-44 rounded-lg bg-popover p-1 text-popover-foreground shadow-md ring-1 ring-foreground/10 outline-none">
|
<Menu.Popup className="z-50 min-w-44 rounded-lg bg-popover p-1 text-popover-foreground shadow-md ring-1 ring-foreground/10 outline-none">
|
||||||
@@ -40,18 +40,18 @@ export function SessionMenu({ session, groups, onView, onRename, onMove, onNewGr
|
|||||||
<Menu.Item key={g} className={itemCls} onClick={() => onMove(g)}>{g}</Menu.Item>
|
<Menu.Item key={g} className={itemCls} onClick={() => onMove(g)}>{g}</Menu.Item>
|
||||||
))}
|
))}
|
||||||
{session.group && (
|
{session.group && (
|
||||||
<Menu.Item className={itemCls} onClick={() => onMove("")}>Senza gruppo</Menu.Item>
|
<Menu.Item className={itemCls} onClick={() => onMove("")}>No group</Menu.Item>
|
||||||
)}
|
)}
|
||||||
<Menu.Item className={itemCls} onClick={onNewGroup}>Nuovo gruppo…</Menu.Item>
|
<Menu.Item className={itemCls} onClick={onNewGroup}>New group…</Menu.Item>
|
||||||
</Menu.Popup>
|
</Menu.Popup>
|
||||||
</Menu.Positioner>
|
</Menu.Positioner>
|
||||||
</Menu.Portal>
|
</Menu.Portal>
|
||||||
</Menu.SubmenuRoot>
|
</Menu.SubmenuRoot>
|
||||||
<Menu.Item className={itemCls} onClick={onArchiveToggle}>
|
<Menu.Item className={itemCls} onClick={onArchiveToggle}>
|
||||||
{session.archived ? "Ripristina" : "Archivia"}
|
{session.archived ? "Restore" : "Archive"}
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
<Menu.Separator className="my-1 h-px bg-border" />
|
<Menu.Separator className="my-1 h-px bg-border" />
|
||||||
<Menu.Item className={`${itemCls} text-destructive`} onClick={onDelete}>Elimina</Menu.Item>
|
<Menu.Item className={`${itemCls} text-destructive`} onClick={onDelete}>Delete</Menu.Item>
|
||||||
</Menu.Popup>
|
</Menu.Popup>
|
||||||
</Menu.Positioner>
|
</Menu.Positioner>
|
||||||
</Menu.Portal>
|
</Menu.Portal>
|
||||||
|
|||||||
Reference in New Issue
Block a user