Merge pull request 'Say which legacy protocols are off when only some are' (#28) from feature/per-protocol-legacy-note into main
This commit was merged in pull request #28.
This commit is contained in:
commit
290bc63dbb
17 files changed
+135
-10
No files matched your search
@@ -0,0 +1,42 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { INBUXA_CAP, legacyProtocolsPartlyOff } from "../client";
|
||||
import { parseTenantLegacy } from "@/lib/admin/adminLegacyProtocols";
|
||||
import type { JmapSession } from "../types";
|
||||
|
||||
/**
|
||||
* INBUXA can switch IMAP, POP3 and ManageSieve off one at a time. The session
|
||||
* lists what is still allowed (`legacyAllowed`); the webmail names what isn't,
|
||||
* only while some but not all are off, and never from a server that doesn't
|
||||
* say.
|
||||
*/
|
||||
describe("legacyProtocolsPartlyOff", () => {
|
||||
const session = (cap: Record<string, unknown> | undefined) =>
|
||||
({
|
||||
accounts: { a: { name: "[email protected]", accountCapabilities: cap ? { [INBUXA_CAP]: cap } : {} } },
|
||||
}) as unknown as JmapSession;
|
||||
|
||||
it("names what is off when only some are", () => {
|
||||
const s = session({ legacyProtocols: "enabled", legacyAllowed: ["imap", "manageSieve", "submission"] });
|
||||
expect(legacyProtocolsPartlyOff(s, "a")).toEqual(["POP3"]);
|
||||
const two = session({ legacyProtocols: "enabled", legacyAllowed: ["pop3", "submission"] });
|
||||
expect(legacyProtocolsPartlyOff(two, "a")).toEqual(["IMAP", "ManageSieve"]);
|
||||
});
|
||||
|
||||
it("is empty with none off, all off, or an older server", () => {
|
||||
const all = ["imap", "pop3", "manageSieve", "submission"];
|
||||
expect(legacyProtocolsPartlyOff(session({ legacyProtocols: "enabled", legacyAllowed: all }), "a")).toEqual([]);
|
||||
expect(legacyProtocolsPartlyOff(session({ legacyProtocols: "disabled", legacyAllowed: [] }), "a")).toEqual([]);
|
||||
expect(legacyProtocolsPartlyOff(session({ legacyProtocols: "enabled" }), "a")).toEqual([]);
|
||||
expect(legacyProtocolsPartlyOff(null, "a")).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("parseTenantLegacy", () => {
|
||||
it("reads a tenant with only some off, and an older server's one switch", () => {
|
||||
expect(parseTenantLegacy({ legacyProtocols: "enabled", pop3: "disabled" }).partlyOff).toEqual(["POP3"]);
|
||||
const all = parseTenantLegacy({ legacyProtocols: "disabled", imap: "disabled", pop3: "disabled" });
|
||||
expect(all.off).toBe(true);
|
||||
expect(all.partlyOff).toEqual([]);
|
||||
expect(parseTenantLegacy({ legacyProtocols: "enabled" }).partlyOff).toEqual([]);
|
||||
});
|
||||
});
|
||||
@@ -37,6 +37,24 @@ export function legacyProtocolsOff(session: JmapSession | null, accountId: Id |
|
||||
return cap?.legacyProtocols === "disabled";
|
||||
}
|
||||
|
||||
/** The protocols the server can switch off one at a time, as it names them. */
|
||||
const SWITCHED = ["imap", "pop3", "manageSieve"] as const;
|
||||
const PROTOCOL_NAMES: Record<string, string> = { imap: "IMAP", pop3: "POP3", manageSieve: "ManageSieve" };
|
||||
|
||||
/**
|
||||
* Which of IMAP, POP3 and ManageSieve are off for this account, by name, when
|
||||
* only some are (INBUXA legacy-protocols, one switch per protocol). Empty when
|
||||
* none are, when all are (see `legacyProtocolsOff`), and from a server that
|
||||
* doesn't say which (`legacyAllowed`).
|
||||
*/
|
||||
export function legacyProtocolsPartlyOff(session: JmapSession | null, accountId: Id | null): string[] {
|
||||
if (!session || !accountId || legacyProtocolsOff(session, accountId)) return [];
|
||||
const cap = session.accounts[accountId]?.accountCapabilities?.[INBUXA_CAP] as { legacyAllowed?: unknown } | undefined;
|
||||
if (!Array.isArray(cap?.legacyAllowed)) return [];
|
||||
const allowed = cap.legacyAllowed;
|
||||
return SWITCHED.filter((p) => !allowed.includes(p)).map((p) => PROTOCOL_NAMES[p] ?? p);
|
||||
}
|
||||
|
||||
export class JmapMethodError extends Error {
|
||||
constructor(
|
||||
public readonly method: string,
|
||||
|
||||
@@ -3,8 +3,8 @@ import { CONFIRM_PHRASE, impactEntries, parseTenantLegacy, phraseMatches } from
|
||||
|
||||
describe("a tenant's legacy mail protocols switch, as the server sends it", () => {
|
||||
it("reads the switch, and tells an older server from nobody", () => {
|
||||
expect(parseTenantLegacy({ legacyProtocols: "disabled", recentLegacyUse: [] })).toEqual({ off: true, recent: [] });
|
||||
expect(parseTenantLegacy({ legacyProtocols: "enabled" })).toEqual({ off: false, recent: null });
|
||||
expect(parseTenantLegacy({ legacyProtocols: "disabled", recentLegacyUse: [] })).toEqual({ off: true, partlyOff: [], recent: [] });
|
||||
expect(parseTenantLegacy({ legacyProtocols: "enabled" })).toEqual({ off: false, partlyOff: [], recent: null });
|
||||
});
|
||||
|
||||
it("puts each account on the panel once, with every protocol and its latest use", () => {
|
||||
|
||||
@@ -34,7 +34,10 @@ export interface RecentUse {
|
||||
}
|
||||
|
||||
export interface TenantLegacy {
|
||||
/** All of IMAP, POP3 and ManageSieve off: the kill-all's state. */
|
||||
off: boolean;
|
||||
/** When only some are off, which, by name; set one at a time in the console. */
|
||||
partlyOff: string[];
|
||||
/** Null from a server too old to say who uses legacy apps -- not the same as nobody. */
|
||||
recent: RecentUse[] | null;
|
||||
}
|
||||
@@ -49,8 +52,13 @@ function parseRecent(raw: unknown): RecentUse[] | null {
|
||||
});
|
||||
}
|
||||
|
||||
const PROTOCOL_NAMES: [string, string][] = [["imap", "IMAP"], ["pop3", "POP3"], ["manageSieve", "ManageSieve"]];
|
||||
|
||||
export function parseTenantLegacy(raw: Record<string, unknown>): TenantLegacy {
|
||||
return { off: raw.legacyProtocols === "disabled", recent: parseRecent(raw.recentLegacyUse) };
|
||||
const off = raw.legacyProtocols === "disabled";
|
||||
// An older server sends only legacyProtocols, which stands for all three.
|
||||
const partlyOff = off ? [] : PROTOCOL_NAMES.filter(([key]) => raw[key] === "disabled").map(([, name]) => name);
|
||||
return { off, partlyOff, recent: parseRecent(raw.recentLegacyUse) };
|
||||
}
|
||||
|
||||
/** The tenant's switch, or null where the server has none (not INBUXA, or too old). */
|
||||
|
||||
@@ -1754,6 +1754,10 @@ export const catalog: Catalog = {
|
||||
// ── Spam filter: the language model's opinion (inbuxa) ──────────
|
||||
"Language model's opinion": "Einschätzung des Sprachmodells",
|
||||
"One of several signals the spam filter weighed": "Eines von mehreren Signalen, die der Spamfilter berücksichtigt hat",
|
||||
// inbuxa: legacy mail protocols, one switch per protocol
|
||||
"Your organization has turned off {protocols} for mail apps. Mail apps that use it can't connect to this account; others still can.": "Ihre Organisation hat {protocols} für Mail-Apps ausgeschaltet. Mail-Apps, die das nutzen, können sich nicht mit diesem Konto verbinden; andere schon.",
|
||||
"Some legacy mail protocols are off for your organization: {protocols}.": "Einige ältere Mailprotokolle sind für Ihre Organisation ausgeschaltet: {protocols}.",
|
||||
"Some are off for {tenant}: {protocols}. Switch them one at a time in the administration console.": "Einige sind für {tenant} aus: {protocols}. In der Verwaltungskonsole lassen sie sich einzeln ein- und ausschalten.",
|
||||
// inbuxa: deleting a person is the console's (audit-hold-lock spec)
|
||||
"Deleting, locking and legal holds are done in the administration console, which records why and keeps what a hold covers.": "Löschen, Sperren und rechtliche Aufbewahrungspflichten werden in der Verwaltungskonsole erledigt, die den Grund festhält und bewahrt, was eine Aufbewahrungspflicht umfasst.",
|
||||
"Open in the console": "In der Konsole öffnen",
|
||||
|
||||
@@ -1727,6 +1727,10 @@ export const catalog: Catalog = {
|
||||
// ── Spam filter: the language model's opinion (inbuxa) ──────────
|
||||
"Language model's opinion": "Opinión del modelo de lenguaje",
|
||||
"One of several signals the spam filter weighed": "Una de varias señales que el filtro de spam ha tenido en cuenta",
|
||||
// inbuxa: legacy mail protocols, one switch per protocol
|
||||
"Your organization has turned off {protocols} for mail apps. Mail apps that use it can't connect to this account; others still can.": "Su organización ha desactivado {protocols} para las aplicaciones de correo. Las que lo usan no pueden conectarse a esta cuenta; las demás sí.",
|
||||
"Some legacy mail protocols are off for your organization: {protocols}.": "Algunos protocolos de correo heredados están desactivados para su organización: {protocols}.",
|
||||
"Some are off for {tenant}: {protocols}. Switch them one at a time in the administration console.": "Algunos están desactivados para {tenant}: {protocols}. Actívelos o desactívelos uno a uno en la consola de administración.",
|
||||
// inbuxa: deleting a person is the console's (audit-hold-lock spec)
|
||||
"Deleting, locking and legal holds are done in the administration console, which records why and keeps what a hold covers.": "Eliminar, bloquear y las retenciones legales se gestionan en la consola de administración, que registra el motivo y conserva lo que cubre una retención.",
|
||||
"Open in the console": "Abrir en la consola",
|
||||
|
||||
@@ -1732,6 +1732,10 @@ export const catalog: Catalog = {
|
||||
// ── Spam filter: the language model's opinion (inbuxa) ──────────
|
||||
"Language model's opinion": "Avis du modèle de langage",
|
||||
"One of several signals the spam filter weighed": "Un signal parmi d'autres pris en compte par le filtre antispam",
|
||||
// inbuxa: legacy mail protocols, one switch per protocol
|
||||
"Your organization has turned off {protocols} for mail apps. Mail apps that use it can't connect to this account; others still can.": "Votre organisation a désactivé {protocols} pour les applications de messagerie. Celles qui l’utilisent ne peuvent pas se connecter à ce compte ; les autres le peuvent toujours.",
|
||||
"Some legacy mail protocols are off for your organization: {protocols}.": "Certains protocoles de messagerie historiques sont désactivés pour votre organisation : {protocols}.",
|
||||
"Some are off for {tenant}: {protocols}. Switch them one at a time in the administration console.": "Certains sont désactivés pour {tenant} : {protocols}. Activez-les ou désactivez-les un par un dans la console d’administration.",
|
||||
// inbuxa: deleting a person is the console's (audit-hold-lock spec)
|
||||
"Deleting, locking and legal holds are done in the administration console, which records why and keeps what a hold covers.": "La suppression, le verrouillage et les conservations légales se font dans la console d’administration, qui enregistre le motif et conserve ce qu’une conservation couvre.",
|
||||
"Open in the console": "Ouvrir dans la console",
|
||||
|
||||
@@ -1735,6 +1735,10 @@ export const catalog: Catalog = {
|
||||
// ── Spam filter: the language model's opinion (inbuxa) ──────────
|
||||
"Language model's opinion": "言語モデルの見解",
|
||||
"One of several signals the spam filter weighed": "迷惑メールフィルターが考慮した複数の判断材料のひとつ",
|
||||
// inbuxa: legacy mail protocols, one switch per protocol
|
||||
"Your organization has turned off {protocols} for mail apps. Mail apps that use it can't connect to this account; others still can.": "組織ではメールアプリ向けの {protocols} がオフになっています。これを使うメールアプリはこのアカウントに接続できませんが、ほかのアプリは接続できます。",
|
||||
"Some legacy mail protocols are off for your organization: {protocols}.": "組織では一部の従来のメールプロトコルがオフになっています: {protocols}。",
|
||||
"Some are off for {tenant}: {protocols}. Switch them one at a time in the administration console.": "{tenant} では一部がオフです: {protocols}。管理コンソールで 1 つずつ切り替えてください。",
|
||||
// inbuxa: deleting a person is the console's (audit-hold-lock spec)
|
||||
"Deleting, locking and legal holds are done in the administration console, which records why and keeps what a hold covers.": "削除、ロック、訴訟ホールドは管理コンソールで行います。コンソールでは理由が記録され、ホールドの対象は保持されます。",
|
||||
"Open in the console": "コンソールで開く",
|
||||
|
||||
@@ -1727,6 +1727,10 @@ export const catalog: Catalog = {
|
||||
// ── Spam filter: the language model's opinion (inbuxa) ──────────
|
||||
"Language model's opinion": "Oordeel van het taalmodel",
|
||||
"One of several signals the spam filter weighed": "Een van meerdere signalen die het spamfilter heeft meegewogen",
|
||||
// inbuxa: legacy mail protocols, one switch per protocol
|
||||
"Your organization has turned off {protocols} for mail apps. Mail apps that use it can't connect to this account; others still can.": "Uw organisatie heeft {protocols} uitgeschakeld voor mail-apps. Mail-apps die dat gebruiken, kunnen geen verbinding maken met dit account; andere nog wel.",
|
||||
"Some legacy mail protocols are off for your organization: {protocols}.": "Sommige verouderde mailprotocollen zijn uitgeschakeld voor uw organisatie: {protocols}.",
|
||||
"Some are off for {tenant}: {protocols}. Switch them one at a time in the administration console.": "Sommige zijn uit voor {tenant}: {protocols}. In de beheerconsole zijn ze één voor één aan en uit te zetten.",
|
||||
// inbuxa: deleting a person is the console's (audit-hold-lock spec)
|
||||
"Deleting, locking and legal holds are done in the administration console, which records why and keeps what a hold covers.": "Verwijderen, vergrendelen en juridische bewaarplichten gebeuren in de beheerconsole, die de reden vastlegt en bewaart wat onder een bewaarplicht valt.",
|
||||
"Open in the console": "Openen in de console",
|
||||
|
||||
@@ -1730,6 +1730,10 @@ export const catalog: Catalog = {
|
||||
// ── Spam filter: the language model's opinion (inbuxa) ──────────
|
||||
"Language model's opinion": "Opinião do modelo de linguagem",
|
||||
"One of several signals the spam filter weighed": "Um dos vários sinais considerados pelo filtro de spam",
|
||||
// inbuxa: legacy mail protocols, one switch per protocol
|
||||
"Your organization has turned off {protocols} for mail apps. Mail apps that use it can't connect to this account; others still can.": "Sua organização desativou {protocols} para aplicativos de e-mail. Os que usam isso não conseguem se conectar a esta conta; os outros ainda conseguem.",
|
||||
"Some legacy mail protocols are off for your organization: {protocols}.": "Alguns protocolos de e-mail legados estão desativados para sua organização: {protocols}.",
|
||||
"Some are off for {tenant}: {protocols}. Switch them one at a time in the administration console.": "Alguns estão desativados para {tenant}: {protocols}. Ative ou desative um de cada vez no console de administração.",
|
||||
// inbuxa: deleting a person is the console's (audit-hold-lock spec)
|
||||
"Deleting, locking and legal holds are done in the administration console, which records why and keeps what a hold covers.": "Excluir, bloquear e retenções legais são feitos no console de administração, que registra o motivo e preserva o que uma retenção abrange.",
|
||||
"Open in the console": "Abrir no console",
|
||||
|
||||
@@ -1729,6 +1729,10 @@ export const catalog: Catalog = {
|
||||
// ── Spam filter: the language model's opinion (inbuxa) ──────────
|
||||
"Language model's opinion": "Мнение языковой модели",
|
||||
"One of several signals the spam filter weighed": "Один из нескольких признаков, которые учёл спам-фильтр",
|
||||
// inbuxa: legacy mail protocols, one switch per protocol
|
||||
"Your organization has turned off {protocols} for mail apps. Mail apps that use it can't connect to this account; others still can.": "Ваша организация отключила {protocols} для почтовых приложений. Приложения, которые его используют, не могут подключиться к этому аккаунту; остальные могут.",
|
||||
"Some legacy mail protocols are off for your organization: {protocols}.": "Некоторые устаревшие почтовые протоколы отключены для вашей организации: {protocols}.",
|
||||
"Some are off for {tenant}: {protocols}. Switch them one at a time in the administration console.": "Для {tenant} отключены некоторые: {protocols}. Включайте и отключайте их по одному в консоли администрирования.",
|
||||
// inbuxa: deleting a person is the console's (audit-hold-lock spec)
|
||||
"Deleting, locking and legal holds are done in the administration console, which records why and keeps what a hold covers.": "Удаление, блокировка и юридическое удержание выполняются в консоли администрирования: она записывает причину и сохраняет всё, что охватывает удержание.",
|
||||
"Open in the console": "Открыть в консоли",
|
||||
|
||||
@@ -1723,6 +1723,10 @@ export const catalog: Catalog = {
|
||||
// ── Spam filter: the language model's opinion (inbuxa) ──────────
|
||||
"Language model's opinion": "Думка мовної моделі",
|
||||
"One of several signals the spam filter weighed": "Одна з кількох ознак, які врахував спам-фільтр",
|
||||
// inbuxa: legacy mail protocols, one switch per protocol
|
||||
"Your organization has turned off {protocols} for mail apps. Mail apps that use it can't connect to this account; others still can.": "Ваша організація вимкнула {protocols} для поштових програм. Програми, які його використовують, не можуть підключитися до цього облікового запису; інші можуть.",
|
||||
"Some legacy mail protocols are off for your organization: {protocols}.": "Деякі застарілі поштові протоколи вимкнено для вашої організації: {protocols}.",
|
||||
"Some are off for {tenant}: {protocols}. Switch them one at a time in the administration console.": "Для {tenant} вимкнено деякі: {protocols}. Вмикайте й вимикайте їх по одному в консолі адміністрування.",
|
||||
// inbuxa: deleting a person is the console's (audit-hold-lock spec)
|
||||
"Deleting, locking and legal holds are done in the administration console, which records why and keeps what a hold covers.": "Видалення, блокування та юридичне утримання виконуються в консолі адміністрування: вона записує причину й зберігає все, що охоплює утримання.",
|
||||
"Open in the console": "Відкрити в консолі",
|
||||
|
||||
@@ -1734,6 +1734,10 @@ export const catalog: Catalog = {
|
||||
// ── Spam filter: the language model's opinion (inbuxa) ──────────
|
||||
"Language model's opinion": "语言模型的判断",
|
||||
"One of several signals the spam filter weighed": "垃圾邮件过滤考虑的多个信号之一",
|
||||
// inbuxa: legacy mail protocols, one switch per protocol
|
||||
"Your organization has turned off {protocols} for mail apps. Mail apps that use it can't connect to this account; others still can.": "您的组织已为邮件应用关闭 {protocols}。使用它的邮件应用无法连接到此账户;其他应用仍可连接。",
|
||||
"Some legacy mail protocols are off for your organization: {protocols}.": "您的组织已关闭部分传统邮件协议:{protocols}。",
|
||||
"Some are off for {tenant}: {protocols}. Switch them one at a time in the administration console.": "{tenant} 已关闭部分协议:{protocols}。请在管理控制台中逐个开启或关闭。",
|
||||
// inbuxa: deleting a person is the console's (audit-hold-lock spec)
|
||||
"Deleting, locking and legal holds are done in the administration console, which records why and keeps what a hold covers.": "删除、锁定和法律保留均在管理控制台中进行,控制台会记录原因,并保留保留范围内的内容。",
|
||||
"Open in the console": "在控制台中打开",
|
||||
|
||||
@@ -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