mirror of
https://github.com/bulwarkmail/native.git
synced 2026-11-02 00:06:23 +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 { spacing } from '../../theme/tokens';
|
||||||
import { useLocaleStore } from '../../stores/locale-store';
|
import { useLocaleStore } from '../../stores/locale-store';
|
||||||
import { usePolicyStore, useSettingHidden, useSettingLocked } from '../../stores/policy-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 { APP_FONTS, FONT_SIZES, useSettingsStore, type AppFont, type FontSize } from '../../stores/settings-store';
|
||||||
import { uiFontsBundled } from '../../theme/reading-fonts';
|
import { uiFontsBundled } from '../../theme/reading-fonts';
|
||||||
import { toast } from '../../stores/toast-store';
|
import { toast } from '../../stores/toast-store';
|
||||||
@@ -104,7 +104,15 @@ export function AccessibilitySettings() {
|
|||||||
|
|
||||||
const applyPreset = (id: AccessibilityPresetId) => {
|
const applyPreset = (id: AccessibilityPresetId) => {
|
||||||
const name = presetName(id);
|
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) {
|
if (changes.length === 0) {
|
||||||
toast.info(t('settings.accessibility.presets.nothing_changed', '{name}: your settings already match.', { name }));
|
toast.info(t('settings.accessibility.presets.nothing_changed', '{name}: your settings already match.', { name }));
|
||||||
return;
|
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;
|
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[] = [];
|
const changes: PresetChange[] = [];
|
||||||
for (const [key, to] of Object.entries(ACCESSIBILITY_PRESETS[id]) as Array<[keyof PersistedSettings, unknown]>) {
|
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 });
|
changes.push({ key, from: state[key], to });
|
||||||
}
|
}
|
||||||
return changes;
|
return changes;
|
||||||
|
|||||||
Reference in New Issue
Block a user