mirror of
https://github.com/bulwarkmail/native.git
synced 2026-11-01 00:07:01 +00:00
fix: keep accessibility presets off settings the organisation locks or limits
This commit is contained in:
@@ -5,7 +5,7 @@ import Button from '../Button';
|
||||
import { spacing } from '../../theme/tokens';
|
||||
import { useLocaleStore } from '../../stores/locale-store';
|
||||
import { usePolicyStore, useSettingHidden, useSettingLocked } from '../../stores/policy-store';
|
||||
import { policyAllowsValue } from '../../lib/org-policy';
|
||||
import { isLockedSetting, policyAllowsValue } from '../../lib/org-policy';
|
||||
import { APP_FONTS, FONT_SIZES, useSettingsStore, type AppFont, type FontSize } from '../../stores/settings-store';
|
||||
import { uiFontsBundled } from '../../theme/reading-fonts';
|
||||
import { toast } from '../../stores/toast-store';
|
||||
@@ -104,7 +104,15 @@ export function AccessibilitySettings() {
|
||||
|
||||
const applyPreset = (id: AccessibilityPresetId) => {
|
||||
const name = presetName(id);
|
||||
const changes = presetChanges(id, useSettingsStore.getState());
|
||||
// Settings the organisation pins or bounds stay as they are (webmail
|
||||
// accessibility-settings.tsx isSettingLocked, allowsValue).
|
||||
const rules = usePolicyStore.getState().rules;
|
||||
const changes = presetChanges(
|
||||
id,
|
||||
useSettingsStore.getState(),
|
||||
(key) => isLockedSetting(rules, key),
|
||||
(key, value) => policyAllowsValue(key, value, rules),
|
||||
);
|
||||
if (changes.length === 0) {
|
||||
toast.info(t('settings.accessibility.presets.nothing_changed', '{name}: your settings already match.', { name }));
|
||||
return;
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { presetChanges } from '../accessibility-presets';
|
||||
import { EMPTY_SETTINGS_RULES, isLockedSetting, policyAllowsValue, type SettingsRules } from '../org-policy';
|
||||
|
||||
// Presets leave alone what the organisation pins or bounds (webmail
|
||||
// lib/accessibility-presets.ts presetChanges with isSettingLocked and
|
||||
// allowsValue). The app's presetChanges changed locked settings too.
|
||||
|
||||
const read = (rel: string) => fs.readFileSync(path.resolve(__dirname, '..', '..', rel), 'utf8');
|
||||
|
||||
describe('accessibility presets and the organisation policy', () => {
|
||||
const state = { fontSize: 'medium' as const, showToolbarLabels: false };
|
||||
|
||||
it('skips a setting the organisation locked', () => {
|
||||
expect(presetChanges('low-vision', state, (key) => key === 'fontSize'))
|
||||
.toEqual([{ key: 'showToolbarLabels', from: false, to: true }]);
|
||||
});
|
||||
|
||||
it('skips a value the organisation does not allow', () => {
|
||||
const rules: SettingsRules = {
|
||||
...EMPTY_SETTINGS_RULES,
|
||||
restrictions: { fontSize: { allowedValues: ['medium', 'large'] } },
|
||||
};
|
||||
const changes = presetChanges(
|
||||
'low-vision',
|
||||
state,
|
||||
(key) => isLockedSetting(rules, key),
|
||||
(key, value) => policyAllowsValue(key, value, rules),
|
||||
);
|
||||
expect(changes).toEqual([{ key: 'showToolbarLabels', from: false, to: true }]);
|
||||
});
|
||||
|
||||
it('changes everything without a policy', () => {
|
||||
expect(presetChanges('low-vision', state).map((c) => c.key)).toEqual(['fontSize', 'showToolbarLabels']);
|
||||
});
|
||||
|
||||
it('passes the locks and bounds from Settings > Accessibility', () => {
|
||||
const src = read('components/settings/AccessibilitySettings.tsx');
|
||||
expect(src).toMatch(/presetChanges\(\s+id,\s+useSettingsStore\.getState\(\),\s+\(key\) => isLockedSetting\(rules, key\),\s+\(key, value\) => policyAllowsValue\(key, value, rules\),\s+\)/);
|
||||
});
|
||||
});
|
||||
@@ -45,11 +45,20 @@ export interface PresetChange {
|
||||
to: unknown;
|
||||
}
|
||||
|
||||
/** The changes a preset would make to `state`: only values that differ. */
|
||||
export function presetChanges(id: AccessibilityPresetId, state: Partial<PersistedSettings>): PresetChange[] {
|
||||
/**
|
||||
* The changes a preset would make to `state`: only values that differ, and
|
||||
* none the organisation has locked (`isLocked`) or bounded (`allows`, such
|
||||
* as a minimum toast duration).
|
||||
*/
|
||||
export function presetChanges(
|
||||
id: AccessibilityPresetId,
|
||||
state: Partial<PersistedSettings>,
|
||||
isLocked: (key: string) => boolean = () => false,
|
||||
allows: (key: string, value: unknown) => boolean = () => true,
|
||||
): PresetChange[] {
|
||||
const changes: PresetChange[] = [];
|
||||
for (const [key, to] of Object.entries(ACCESSIBILITY_PRESETS[id]) as Array<[keyof PersistedSettings, unknown]>) {
|
||||
if (!(key in state) || state[key] === to) continue;
|
||||
if (!(key in state) || state[key] === to || isLocked(key) || !allows(key, to)) continue;
|
||||
changes.push({ key, from: state[key], to });
|
||||
}
|
||||
return changes;
|
||||
|
||||
Reference in New Issue
Block a user