Say which legacy protocols are off when only some are
inbuxa can now switch IMAP, POP3 and ManageSieve off one at a time, server-wide and per organization, and the session lists what is still allowed for the account (legacyAllowed). Where the webmail said "legacy protocols are off", it now also covers the case where only some are: - Security & sessions, above app passwords: "Your organization has turned off POP3 for mail apps. Mail apps that use it can't connect to this account; others still can." - The Administration dashboard: "Some legacy mail protocols are off for your organization: POP3." - An organization's sheet in Administration: its switch stays the all-or-nothing one; when only some are off it names them and points to the console, where they're switched one at a time, and "Turn legacy protocols back on" turns them all back on. With every protocol off, the existing wording shows, as before. From a server that doesn't send legacyAllowed nothing new appears. 3 new strings in all nine catalogs, unreviewed. Tested: unit tests for reading the session and a tenant's switches; the existing tests updated for the new field; typecheck; the whole suite (1475 tests); and in headless Chrome against a local server with POP3 off, where Security & sessions showed the new note.
This commit is contained in:
1 parent
ac0f8789f6
commit
44f8e30c45
17 files changed
+135
-10
No files matched your search
@@ -1,7 +1,7 @@
|
||||
import { useEffect, useState, type ReactNode } from "react";
|
||||
import { Link } from "wouter";
|
||||
import { ArrowDownToLine, ArrowUpFromLine, ExternalLink, Globe, Hourglass, LayoutDashboard, MemoryStick, RefreshCw, ShieldCheck, Users } from "lucide-react";
|
||||
import { legacyProtocolsOff } from "@/jmap/client";
|
||||
import { legacyProtocolsOff, legacyProtocolsPartlyOff } from "@/jmap/client";
|
||||
import { useAppName } from "@/lib/brand";
|
||||
import { adminSections, dashboardCards, type DashboardCard } from "@/lib/admin/adminAccess";
|
||||
import { balancedColumns, countObjects, DASHBOARD_WINDOW_MS, isRefused, loadMetrics, summarizeMetrics, type MessageStats } from "@/lib/admin/adminDashboard";
|
||||
@@ -38,6 +38,7 @@ export function AdminDashboard() {
|
||||
const perms = usePermissions();
|
||||
const adminUrl = useSession((s) => s.session?.ihasmail?.server?.adminUrl ?? null);
|
||||
const legacyOff = useSession((s) => legacyProtocolsOff(s.session, s.accountId));
|
||||
const legacyPartlyOff = useSession((s) => legacyProtocolsPartlyOff(s.session, s.accountId).join(", "));
|
||||
const app = useAppName();
|
||||
const cards = dashboardCards(perms);
|
||||
const sections = adminSections(perms);
|
||||
@@ -113,6 +114,13 @@ export function AdminDashboard() {
|
||||
<span>{t("Legacy mail protocols are off for your organization. Only {app} and JMAP apps can sign in.", { app })}</span>
|
||||
</p>
|
||||
)}
|
||||
{legacyPartlyOff && (
|
||||
// INBUXA: one switch per protocol, some of them off
|
||||
<p className="admin-notice">
|
||||
<ShieldCheck size={16} />
|
||||
<span>{t("Some legacy mail protocols are off for your organization: {protocols}.", { protocols: legacyPartlyOff })}</span>
|
||||
</p>
|
||||
)}
|
||||
{shown.length ? (
|
||||
<div className="admin-cards-wrap">
|
||||
<div className="admin-cards">
|
||||
|
||||
@@ -68,10 +68,15 @@ export function TenantLegacyProtocols({ tenantId, tenantName }: { tenantId: stri
|
||||
<p>
|
||||
{state.off
|
||||
? t("Off for {tenant}. Only {app} and JMAP apps can sign in to its domains.", { tenant: tenantName, app })
|
||||
: t("On for {tenant}. Mail apps can use IMAP, POP3 and ManageSieve on its domains.", { tenant: tenantName })}
|
||||
: state.partlyOff.length > 0
|
||||
? t("Some are off for {tenant}: {protocols}. Switch them one at a time in the administration console.", {
|
||||
tenant: tenantName,
|
||||
protocols: state.partlyOff.join(", "),
|
||||
})
|
||||
: t("On for {tenant}. Mail apps can use IMAP, POP3 and ManageSieve on its domains.", { tenant: tenantName })}
|
||||
</p>
|
||||
|
||||
{canChange && state.off && (
|
||||
{canChange && (state.off || state.partlyOff.length > 0) && (
|
||||
<button className="btn" disabled={busy} onClick={() => void turn(false)}>
|
||||
{t("Turn legacy protocols back on")}
|
||||
</button>
|
||||
|
||||
@@ -62,7 +62,7 @@ describe("a tenant's legacy mail protocols switch", () => {
|
||||
});
|
||||
|
||||
it("shows who would notice and what it means, then asks for the exact phrase", async () => {
|
||||
api.state = { off: false, recent: [{ accountId: "a", name: "[email protected]", protocol: "imap", lastUsedAt: Date.now() - 2 * 86400_000 }] };
|
||||
api.state = { off: false, partlyOff: [], recent: [{ accountId: "a", name: "[email protected]", protocol: "imap", lastUsedAt: Date.now() - 2 * 86400_000 }] };
|
||||
signIn(["sysDomainGet", "sysDomainUpdate"]);
|
||||
await render();
|
||||
await act(async () => button(host, "Turn off legacy protocols…")!.click());
|
||||
@@ -84,7 +84,7 @@ describe("a tenant's legacy mail protocols switch", () => {
|
||||
});
|
||||
|
||||
it("turns it back on with one click", async () => {
|
||||
api.state = { off: true, recent: [] };
|
||||
api.state = { off: true, partlyOff: [], recent: [] };
|
||||
signIn(["sysDomainGet", "sysDomainUpdate"]);
|
||||
await render();
|
||||
await act(async () => button(host, "Turn legacy protocols back on")!.click());
|
||||
@@ -92,7 +92,7 @@ describe("a tenant's legacy mail protocols switch", () => {
|
||||
});
|
||||
|
||||
it("shows the state but no switch to someone who can't change domains", async () => {
|
||||
api.state = { off: true, recent: null };
|
||||
api.state = { off: true, partlyOff: [], recent: null };
|
||||
signIn(["sysDomainGet"]);
|
||||
await render();
|
||||
expect(host.textContent).toContain("Off for Acme Corp");
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import { useAppName } from "@/lib/brand";
|
||||
import { Copy, KeyRound, ShieldCheck, Smartphone } from "lucide-react";
|
||||
import { apiFetch, ApiError, legacyProtocolsOff } from "@/jmap/client";
|
||||
import { apiFetch, ApiError, legacyProtocolsOff, legacyProtocolsPartlyOff } from "@/jmap/client";
|
||||
import { useSession } from "@/store/session";
|
||||
import { formatFullDate } from "@/lib/format";
|
||||
import { toast } from "@/ui/toast";
|
||||
@@ -89,6 +89,14 @@ export function SecuritySettings() {
|
||||
{t("Your organization allows only {app} and JMAP apps, so phone and desktop mail apps can't connect to this account.", { app: appName })}
|
||||
</p>
|
||||
)}
|
||||
{legacyProtocolsPartlyOff(session, accountId).length > 0 && (
|
||||
// INBUXA: one switch per protocol; mail apps using the rest still work
|
||||
<p className="info-box mb-16">
|
||||
{t("Your organization has turned off {protocols} for mail apps. Mail apps that use it can't connect to this account; others still can.", {
|
||||
protocols: legacyProtocolsPartlyOff(session, accountId).join(", "),
|
||||
})}
|
||||
</p>
|
||||
)}
|
||||
{unsupported ? (
|
||||
<p className="hint">{t("App passwords are managed by your mail administrator.")}</p>
|
||||
) : (
|
||||
|
||||
Reference in new issue
Block a user