Each tenant's page carries its legacy protocols switch (LP-9 to LP-18)

A card above the tenant form: whether legacy mail protocols are on or off
for the organization, a one-click "Turn legacy protocols back on", and
"Turn off legacy protocols…", which opens -- before anything can change --
the impact panel with the tenant's own people (LP-15), the statement at
tenant scope and the typed confirmation (LP-16, LP-17). The statement reads
"everyone in {organization}" and names no ports and no firewall: a
tenant's switch closes nothing, other tenants share the ports (LP-13).

It reads and turns inbuxa:TenantProtocolPolicy, with the domain
permissions the server checks for it. It shows on the read-only tenant page
too: a tenant administrator reads its tenant without changing it (MT-12)
and may still turn the switch. Turning it back on while the server has
legacy protocols off is refused by the server, and the refusal is shown.

The banner (LP-18) falls back to the tenant's switch where the server's
can't be read -- inside a tenant -- and reads "off for your
organization".

The impact panel, statement and confirmation move to parts.tsx, shared by
Hardening and the tenant card; the statement takes its scope.

Checked by hand against a local server with a tenant, two of its users and
the admin signed in over IMAP: the tenant card's panel lists the tenant's
two users and not the admin; the statement reads "everyone in Example Co"
with no ports or firewall; turning it off makes the tenant's user get "NO
[ALERT] Your organization allows only INBUXA webmail and JMAP apps" over
IMAP; one click turns it back on; Hardening's panel lists all three. Not
checked by hand: the banner as a tenant administrator sees it.
This commit is contained in:
2026-09-21 13:39:56 -07:00
parent 2aff8c8a10
commit 11d85cd759
7 changed files with 484 additions and 172 deletions
+20 -3
View File
@@ -51,6 +51,10 @@ const LegacyProtocolsPage = lazyFeature(
() => import('@/features/hardening/LegacyProtocolsPage'),
(m) => m.LegacyProtocolsPage,
);
const TenantLegacyProtocols = lazyFeature(
() => import('@/features/hardening/TenantLegacyProtocols'),
(m) => m.TenantLegacyProtocols,
);
interface MainContentProps {
viewName?: string;
@@ -150,10 +154,23 @@ function renderView(schema: Schema | null, viewName?: string, id?: string, secti
return <TraceDetailView viewName={viewName} objectId={id} />;
}
const canUpdate = useAccountStore.getState().hasObjectPermission(resolved.permissionPrefix, 'Update');
if (!canUpdate) {
return <DynamicViewPage viewName={viewName} objectId={id} />;
const page = canUpdate ? (
<DynamicForm viewName={viewName} objectId={id} />
) : (
<DynamicViewPage viewName={viewName} objectId={id} />
);
// INBUXA: a tenant's page carries its legacy protocols switch (LP-9). A
// tenant admin reads its tenant without changing it (MT-12), and may
// still turn the switch, so it shows on the read-only page too.
if (resolved.objectName === 'x:Tenant') {
return (
<div className="space-y-4">
<TenantLegacyProtocols tenantId={id} />
{page}
</div>
);
}
return <DynamicForm viewName={viewName} objectId={id} />;
return page;
}
return <DynamicList viewName={viewName} />;