import { useEffect, useState } from "react"; import { useLocation } from "wouter"; import { Building2, ChevronLeft, ChevronRight, Plus, Search } from "lucide-react"; import { can, type RoleDef } from "@/lib/adminAccess"; import { describeDirectoryError, listRoles } from "@/lib/adminDirectory"; import { drawableLogo, getTenants, queryTenants, type DirectoryTenant } from "@/lib/adminTenants"; import { formatSize } from "@/lib/format"; import { proxiedImageUrl } from "@/lib/html"; import { plural, t } from "@/lib/i18n"; import { useSession } from "@/store/session"; import { Empty, Spinner } from "@/ui/misc"; import { usePermissions } from "./usePermissions"; import { TenantSheet } from "./TenantSheet"; const PAGE_SIZE = 50; /** * Tenants: separate organizations on one server, each with its own people, * domains and limits. * * The section is offered to whoever may read tenants. On a server that does not * report Enterprise -- or reports no edition -- the page is only a notice that * tenants are an Enterprise feature: tenants there hold nobody to anything * beyond an ordinary user's permissions, so there is nothing worth creating or * listing. On Enterprise the notice is left out, unless the installation asks * for it (SHOW_ENTERPRISE_NOTICES), as the public demo does so as not to * suggest tenants come without the license. */ export function TenantsAdmin({ selectedId }: { selectedId?: string }) { const edition = useSession((s) => s.session?.ihasmail?.server?.edition ?? null); const notices = useSession((s) => s.session?.ihasmail?.server?.enterpriseNotices === true); if (edition !== "enterprise") { return (
{t("Separate organizations on one server, each with its own people, domains and limits.")}
{t("Tenants are a Stalwart Enterprise feature.")}
; } function EnterpriseTenants({ selectedId, notice }: { selectedId?: string; notice: boolean }) { const [, navigate] = useLocation(); const perms = usePermissions(); const [text, setText] = useState(""); const [query, setQuery] = useState(""); const [position, setPosition] = useState(0); const [page, setPage] = useState<{ tenants: DirectoryTenant[]; total: number } | null>(null); const [error, setError] = useState