From 0bde428fa065981c42fc5d92d9df570ec219ae1b Mon Sep 17 00:00:00 2001 From: Oliver Kieselbach Date: Sun, 6 Sep 2026 14:13:40 +0200 Subject: [PATCH] =?UTF-8?q?web:=20GA=20tenant=20modal=20=E2=80=94=20MCP=20?= =?UTF-8?q?switch=20and=20suspension=20moved=20down=20next=20to=20offboard?= =?UTF-8?q?ing?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Order at the end of the modal: MCP Access, Tenant Suspension, Offboard Tenant. Rarely used levers sit together; the frequently edited plan, contact and limit sections come first. Co-Authored-By: Claude Fable 5.1 --- .../components/TenantManagementSection.tsx | 160 +++++++++--------- 1 file changed, 80 insertions(+), 80 deletions(-) diff --git a/src/Web/autopilot-monitor-web/app/admin/components/TenantManagementSection.tsx b/src/Web/autopilot-monitor-web/app/admin/components/TenantManagementSection.tsx index 3af39db3..71a01615 100644 --- a/src/Web/autopilot-monitor-web/app/admin/components/TenantManagementSection.tsx +++ b/src/Web/autopilot-monitor-web/app/admin/components/TenantManagementSection.tsx @@ -726,86 +726,6 @@ function TenantManagementSectionInner({
- {/* Tenant Suspension */} -
-

Tenant Suspension

-

- Blocks sign-in and tenant auto-activation while the tenant's data stays in - place — this is the durable lock-out lever for abuse cases (offboarding below is - not: it deletes the suspension along with everything else). -

-
- - - {editingTenant.disabled && ( - <> -
- - setEditingTenant({ ...editingTenant, disabledReason: e.target.value })} - placeholder="Optional: Why is this tenant suspended?" - className="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:ring-2 focus:ring-red-500 focus:border-red-500" - /> -
-
- - setEditingTenant({ ...editingTenant, disabledUntil: e.target.value ? new Date(e.target.value).toISOString() : undefined })} - className="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:ring-2 focus:ring-red-500 focus:border-red-500" - /> -

Optional: Auto-enable after this date/time

-
- - )} -
-
- - {/* MCP switch (operator control, GA-only field — saved by the modal's generic Save) */} -
-

MCP Access

-

- Closes the MCP (AI assistant) surface for this tenant: its members cannot connect, - and no MCP call can read it as a target, delegated (MSP) reads included. Portal and - API access with a personal token stay unchanged. Platform roles bypass the switch. -

-
- - - {editingTenant.mcpDisabled && ( -
- - setEditingTenant({ ...editingTenant, mcpDisabledReason: e.target.value })} - placeholder="Optional: shown to every caller that is refused" - className="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:ring-2 focus:ring-amber-500 focus:border-amber-500" - /> -
- )} -
-
- {/* Plan & Trial (own save path — PATCH plan endpoint; the modal's generic Save does not touch these fields, the backend preserves them on PUT) */}
@@ -1244,6 +1164,86 @@ function TenantManagementSectionInner({ )}
+ {/* MCP switch (operator control, GA-only field — saved by the modal's generic Save) */} +
+

MCP Access

+

+ Closes the MCP (AI assistant) surface for this tenant: its members cannot connect, + and no MCP call can read it as a target, delegated (MSP) reads included. Portal and + API access with a personal token stay unchanged. Platform roles bypass the switch. +

+
+ + + {editingTenant.mcpDisabled && ( +
+ + setEditingTenant({ ...editingTenant, mcpDisabledReason: e.target.value })} + placeholder="Optional: shown to every caller that is refused" + className="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:ring-2 focus:ring-amber-500 focus:border-amber-500" + /> +
+ )} +
+
+ + {/* Tenant Suspension */} +
+

Tenant Suspension

+

+ Blocks sign-in and tenant auto-activation while the tenant's data stays in + place — this is the durable lock-out lever for abuse cases (offboarding below is + not: it deletes the suspension along with everything else). +

+
+ + + {editingTenant.disabled && ( + <> +
+ + setEditingTenant({ ...editingTenant, disabledReason: e.target.value })} + placeholder="Optional: Why is this tenant suspended?" + className="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:ring-2 focus:ring-red-500 focus:border-red-500" + /> +
+
+ + setEditingTenant({ ...editingTenant, disabledUntil: e.target.value ? new Date(e.target.value).toISOString() : undefined })} + className="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:ring-2 focus:ring-red-500 focus:border-red-500" + /> +

Optional: Auto-enable after this date/time

+
+ + )} +
+
+ {/* Danger Zone — offboarding cascade (own path: DELETE tenants/{id}/offboard; deliberately NOT part of the modal's Save button) */}