mirror of
https://github.com/bulwarkmail/native.git
synced 2026-11-01 16:05:39 +00:00
feat: leave out the settings pages the organisation turns off
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { policyHiddenPages } from '../policy-pages';
|
||||
import { sanitizePolicy } from '../../../lib/org-policy';
|
||||
|
||||
const screen = fs.readFileSync(path.resolve(__dirname, '..', '..', '..', 'screens', 'SettingsScreen.tsx'), 'utf8');
|
||||
|
||||
describe('policyHiddenPages', () => {
|
||||
it('leaves every page without a policy or with the default gates', () => {
|
||||
expect(policyHiddenPages(null)).toEqual([]);
|
||||
expect(policyHiddenPages(sanitizePolicy({}))).toEqual([]);
|
||||
});
|
||||
|
||||
it('takes away the pages of the gates the policy turns off', () => {
|
||||
const policy = sanitizePolicy({
|
||||
features: {
|
||||
templatesEnabled: false,
|
||||
customKeywordsEnabled: false,
|
||||
sidebarAppsEnabled: false,
|
||||
themesEnabled: false,
|
||||
calendarEnabled: false,
|
||||
contactsEnabled: false,
|
||||
filesEnabled: false,
|
||||
},
|
||||
});
|
||||
expect(policyHiddenPages(policy).sort()).toEqual(
|
||||
['calendar', 'contacts', 'files', 'keywords', 'sidebar_apps', 'templates', 'themes'],
|
||||
);
|
||||
});
|
||||
|
||||
it('takes away Delegates and Recover deleted items when the policy hides them', () => {
|
||||
const policy = sanitizePolicy({
|
||||
restrictions: { delegation: { hidden: true }, deletedItemsRecovery: { hidden: true } },
|
||||
});
|
||||
expect(policyHiddenPages(policy).sort()).toEqual(['recovery', 'sharing']);
|
||||
const locked = sanitizePolicy({ restrictions: { delegation: { locked: true } } });
|
||||
expect(policyHiddenPages(locked)).toEqual([]);
|
||||
});
|
||||
|
||||
it('names pages the Settings list has', () => {
|
||||
const policy = sanitizePolicy({
|
||||
features: Object.fromEntries(['templatesEnabled', 'customKeywordsEnabled', 'sidebarAppsEnabled', 'themesEnabled', 'calendarEnabled', 'contactsEnabled', 'filesEnabled'].map((g) => [g, false])),
|
||||
restrictions: { delegation: { hidden: true }, deletedItemsRecovery: { hidden: true } },
|
||||
});
|
||||
for (const page of policyHiddenPages(policy)) expect(screen).toContain(`{ id: '${page}',`);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Settings list', () => {
|
||||
it('leaves out the pages the active policy takes away', () => {
|
||||
expect(screen).toContain('const policy = usePolicyStore((s) => s.effective);');
|
||||
expect(screen).toContain('for (const page of policyHiddenPages(policy)) set.add(page as Tab);');
|
||||
expect(screen).toContain('}, [recoveryAvailable, delegationAvailable, policy]);');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,42 @@
|
||||
import { isFeatureEnabled, type FeatureGate, type OrgPolicy } from '../../lib/org-policy';
|
||||
|
||||
/**
|
||||
* Settings pages a feature gate takes away, as the webmail's settings-app.tsx
|
||||
* leaves their tabs out: Templates (templatesEnabled, in Composing there),
|
||||
* Keywords (customKeywordsEnabled: Organize turns into Folders), Sidebar apps
|
||||
* (sidebarAppsEnabled: the app has no plugins, which keep Add-ons there),
|
||||
* Themes (themesEnabled, appearance-settings.tsx), and Calendar, Contacts and
|
||||
* Files with their apps.
|
||||
*/
|
||||
const GATED_PAGES: ReadonlyArray<[FeatureGate, string]> = [
|
||||
['templatesEnabled', 'templates'],
|
||||
['customKeywordsEnabled', 'keywords'],
|
||||
['sidebarAppsEnabled', 'sidebar_apps'],
|
||||
['themesEnabled', 'themes'],
|
||||
['calendarEnabled', 'calendar'],
|
||||
['contactsEnabled', 'contacts'],
|
||||
['filesEnabled', 'files'],
|
||||
];
|
||||
|
||||
/**
|
||||
* Pages a hidden restriction takes away: Delegates (`delegation`, webmail
|
||||
* settings-app supportsSharing) and Recover deleted items
|
||||
* (`deletedItemsRecovery`, webmail hooks/use-deleted-items-recovery.ts).
|
||||
*/
|
||||
const HIDDEN_PAGES: ReadonlyArray<[string, string]> = [
|
||||
['delegation', 'sharing'],
|
||||
['deletedItemsRecovery', 'recovery'],
|
||||
];
|
||||
|
||||
/** The settings pages the active account's policy leaves out, by page id. */
|
||||
export function policyHiddenPages(policy: OrgPolicy | null | undefined): string[] {
|
||||
if (!policy) return [];
|
||||
const out: string[] = [];
|
||||
for (const [gate, page] of GATED_PAGES) {
|
||||
if (!isFeatureEnabled(policy, gate)) out.push(page);
|
||||
}
|
||||
for (const [key, page] of HIDDEN_PAGES) {
|
||||
if (policy.restrictions[key]?.hidden === true) out.push(page);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
@@ -54,6 +54,8 @@ import { useAuthStore } from '../stores/auth-store';
|
||||
import { useManagedAccountStore } from '../stores/managed-account-store';
|
||||
import { useAccountStore } from '../stores/account-store';
|
||||
import { useSettingsStore } from '../stores/settings-store';
|
||||
import { usePolicyStore } from '../stores/policy-store';
|
||||
import { policyHiddenPages } from '../components/settings/policy-pages';
|
||||
import { useUpdatesStore } from '../stores/updates-store';
|
||||
import { SUPPORTED_LOCALES } from '../i18n';
|
||||
import { settingsSummary, type SummaryState } from '../lib/settings-summary';
|
||||
@@ -231,12 +233,15 @@ export default function SettingsScreen({ onLogout, onBack, onTabSelect }: Settin
|
||||
// list, not shown as "Not on this server", where the server lacks them.
|
||||
const recoveryAvailable = useDeletedItemsRecovery().available;
|
||||
const delegationAvailable = useDelegationAvailable();
|
||||
// Pages the organisation's policy takes away (feature gates, hidden pages).
|
||||
const policy = usePolicyStore((s) => s.effective);
|
||||
const hiddenTabs = React.useMemo(() => {
|
||||
const set = new Set<Tab>();
|
||||
if (!recoveryAvailable) set.add('recovery');
|
||||
if (!delegationAvailable) set.add('sharing');
|
||||
for (const page of policyHiddenPages(policy)) set.add(page as Tab);
|
||||
return set;
|
||||
}, [recoveryAvailable, delegationAvailable]);
|
||||
}, [recoveryAvailable, delegationAvailable, policy]);
|
||||
|
||||
// A shared/group account picked under "Shared with me" scopes Settings to
|
||||
// the panes that account can be managed in (webmail: scoped settings).
|
||||
|
||||
Reference in New Issue
Block a user