🚸(frontend) disable application menu when no option is available

Previously the settings dropdown could open an empty menu when
the selected mailbox granted none of the required abilities, leaving
users to think the button was broken. The menu is now rendered as a
disabled button with an explanatory tooltip so the UI stays stable
across mailbox switches and the reason is surfaced to the user.
This commit is contained in:
jbpenrath
2026-04-15 00:01:40 +02:00
parent 78c1842d99
commit efbae5f517
4 changed files with 23 additions and 6 deletions

View File

@@ -116,13 +116,10 @@ test.describe("Import Message", () => {
.click();
await page.waitForLoadState("networkidle");
// The header settings menu should not contain the Import messages option
// as the user does not have admin rights to the shared mailbox
// The header settings button should be disabled because the user has no
// admin abilities on the shared mailbox, so no menu option is available.
const header = page.locator(".c__header");
const settingsButton = header.getByRole("button", { name: "More options" });
await settingsButton.click();
await expect(
page.getByRole("menuitem", { name: "Import messages" })
).not.toBeVisible();
await expect(settingsButton).toBeDisabled();
});
});

View File

@@ -423,6 +423,7 @@
"Monthly": "Monthly",
"More": "More",
"More options": "More options",
"More options (none available for this mailbox)": "More options (none available for this mailbox)",
"Move {{count}} threads_one": "Move {{count}} thread",
"Move {{count}} threads_other": "Move {{count}} threads",
"My auto-replies": "My auto-replies",
@@ -440,6 +441,7 @@
"New signature": "New signature",
"New template": "New template",
"No accesses": "No accesses",
"No action available for this mailbox": "No action available for this mailbox",
"No addresses found": "No addresses found",
"No attachments": "No attachments",
"No auto-replies found": "No auto-replies found",

View File

@@ -479,6 +479,7 @@
"Monthly": "Mensuel",
"More": "Plus",
"More options": "Plus d'options",
"More options (none available for this mailbox)": "Plus d'options (aucune disponible pour cette boîte aux lettres)",
"Move {{count}} threads_one": "Déplacer {{count}} conversation",
"Move {{count}} threads_many": "Déplacer {{count}} conversations",
"Move {{count}} threads_other": "Déplacer {{count}} conversations",
@@ -497,6 +498,7 @@
"New signature": "Nouvelle signature",
"New template": "Nouveau modèle",
"No accesses": "Aucun accès",
"No action available for this mailbox": "Aucune action disponible pour cette boîte aux lettres",
"No addresses found": "Aucune adresse trouvée",
"No attachments": "Aucune pièce jointe",
"No auto-replies found": "Aucune réponse automatique trouvée",

View File

@@ -152,6 +152,7 @@ const ApplicationMenu = () => {
}, [isDropdownOpen, selectedMailbox?.id]);
const taskStatus = useImportTaskStatus(taskId, { enabled: canImportMessages && isDropdownOpen });
const hasOptions = canAccessDomainAdmin || canImportMessages || canManageMessageTemplates || canManageIntegrations;
const importMessageOption = useMemo(() => {
let label = t("Import messages");
let icon = <Icon name="archive" type={IconType.OUTLINED} />;
@@ -181,6 +182,21 @@ const ApplicationMenu = () => {
}
}, [t, taskStatus]);
if (!hasOptions) {
return (
<Tooltip content={t("No action available for this mailbox")}>
<Button
disabled
onClick={(e) => e.preventDefault()}
icon={<Icon name="settings" type={IconType.OUTLINED} />}
aria-label={t("More options (none available for this mailbox)")}
color="neutral"
variant="tertiary"
/>
</Tooltip>
);
}
return (
<DropdownMenu
isOpen={isDropdownOpen}