diff --git a/FEATURES.md b/FEATURES.md index ba9d3fa..46f8f03 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -1265,10 +1265,11 @@ Stalwart shows the server's English until it is translated. A tenant is a separate organisation on the same server — its own people, domains and limits, and an administrator who manages only what is in it. It is a Stalwart Enterprise feature. On a server that does not report Enterprise — or -reports no edition at all — the page is only a notice that anyone inside a -tenant has only an ordinary user's permissions: no list, no search, nothing to -create. On Enterprise, for a role with `sysTenantQuery` and `sysTenantGet`, -under Access: +reports no edition at all — the page is only the notice *Tenants are a Stalwart +Enterprise feature.*: no list, no search, nothing to create. On Enterprise the +notice is left out, unless `SHOW_ENTERPRISE_NOTICES=1` asks for it above the +list, as the public demo does. On Enterprise, for a role with `sysTenantQuery` +and `sysTenantGet`, under Access: - **List and search** tenants, with each one's storage and account limit. - **Create and edit** a tenant's name, logo (an https address, drawn through the @@ -1713,6 +1714,7 @@ wizard, because either would be state. | Variable | Default | Does | | --- | --- | --- | | `STALWART_URL` | — | Where Stalwart is; the JMAP session is discovered at `/.well-known/jmap` | +| `SHOW_ENTERPRISE_NOTICES` | `0` | Say an Enterprise-only section (Tenants) is Enterprise-only even when the server is Enterprise. For a demo that reports Enterprise to show those sections; a real installation leaves it off | | `STALWART_ADMIN_URL` | — | Where a browser opens Stalwart's own administration, linked from the Administration dashboard. Separate from `STALWART_URL`, which is often an address only this server can reach; unset, the dashboard names Stalwart's administration without a link | | `APP_SECRET` | — | Key material for sealing sessions. **Required in production** — the server refuses to start without it | | `HOST` / `PORT` | `0.0.0.0` / `8080` | Listen address | diff --git a/server/src/app.ts b/server/src/app.ts index 5412386..a566947 100644 --- a/server/src/app.ts +++ b/server/src/app.ts @@ -896,7 +896,12 @@ function sessionExtras(session: LiveSession, info: AccountInfo = { locale: null, * session that may administer -- where the operator says its own * administration is. */ - server: { edition: info.edition, adminUrl: administrationAllowed(config.administration, session.remember) ? adminUrlFor(session.username) : null }, + server: { + edition: info.edition, + adminUrl: administrationAllowed(config.administration, session.remember) ? adminUrlFor(session.username) : null, + /** SHOW_ENTERPRISE_NOTICES: say "Enterprise feature" on Enterprise too, as the demo does. */ + enterpriseNotices: config.showEnterpriseNotices, + }, /** * Whether this session may administer: the installation offers it * (ADMINISTRATION) and the person signed in on a device marked as their own. diff --git a/server/src/config.ts b/server/src/config.ts index f9fc5d8..1bd9281 100644 --- a/server/src/config.ts +++ b/server/src/config.ts @@ -307,6 +307,13 @@ export const config = { */ stalwartAdminUrl: process.env.STALWART_ADMIN_URL ? httpUrl(process.env.STALWART_ADMIN_URL, "STALWART_ADMIN_URL") : "", stalwartAdminUrls: stalwartServers.adminUrls, + /** + * Say that an Enterprise-only section is Enterprise-only even on an + * Enterprise server. Off, as a real installation wants it; the public demo + * turns it on, because it reports Enterprise to show those sections and + * should not suggest they come without the licence. + */ + showEnterpriseNotices: bool("SHOW_ENTERPRISE_NOTICES", false), appSecret, trustProxy: bool("TRUST_PROXY", true), /** diff --git a/web/src/jmap/types.ts b/web/src/jmap/types.ts index a62d4f9..a210103 100644 --- a/web/src/jmap/types.ts +++ b/web/src/jmap/types.ts @@ -40,6 +40,8 @@ export interface JmapSession { edition?: string | null; /** Where Stalwart's own administration is (STALWART_ADMIN_URL), for a session that may administer. */ adminUrl?: string | null; + /** SHOW_ENTERPRISE_NOTICES: an Enterprise-only section says so even on Enterprise. */ + enterpriseNotices?: boolean; }; /** * False when this session may not administer: the operator turned it off, diff --git a/web/src/views/admin/TenantsAdmin.tsx b/web/src/views/admin/TenantsAdmin.tsx index 4ce4276..dcaa6bb 100644 --- a/web/src/views/admin/TenantsAdmin.tsx +++ b/web/src/views/admin/TenantsAdmin.tsx @@ -18,14 +18,17 @@ const PAGE_SIZE = 50; * Tenants: separate organisations on one server, each with its own people, * domains and limits. * - * The section is offered to whoever may read tenants, but on a server that does - * not report Enterprise the page is only the notice: tenants there hold nobody - * to anything beyond an ordinary user's permissions, so there is nothing worth - * creating or listing. A server that reports no edition at all counts as not - * Enterprise. + * 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 licence. */ 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 (
@@ -35,14 +38,19 @@ export function TenantsAdmin({ selectedId }: { selectedId?: string }) {

{t("Separate organisations on one server, each with its own people, domains and limits.")}

-

{t("Tenants are a Stalwart Enterprise feature.")}

+ ); } - return ; + return ; } -function EnterpriseTenants({ selectedId }: { selectedId?: string }) { +/** Said on every Tenants page, Enterprise or not. */ +function EnterpriseNotice({ warn }: { warn: boolean }) { + return

{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(""); @@ -119,6 +127,8 @@ function EnterpriseTenants({ selectedId }: { selectedId?: string }) { )} + {notice && } +