Skip to content

Commit c2378b2

Browse files
committed
refactor: simplify signature text policy composable
Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
1 parent ac5cc98 commit c2378b2

2 files changed

Lines changed: 158 additions & 49 deletions

File tree

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2026 LibreSign contributors
3+
* SPDX-License-Identifier: AGPL-3.0-or-later
4+
*/
5+
6+
import { beforeEach, describe, expect, it, vi } from 'vitest'
7+
8+
const { initialState, policiesState } = vi.hoisted(() => ({
9+
initialState: {} as Record<string, unknown>,
10+
policiesState: {
11+
policies: {} as Record<string, { effectiveValue?: unknown }>,
12+
},
13+
}))
14+
15+
vi.mock('@nextcloud/initial-state', () => ({
16+
loadState: vi.fn((_app: string, key: string, defaultValue?: unknown) => {
17+
return key in initialState ? initialState[key] : defaultValue
18+
}),
19+
}))
20+
21+
vi.mock('../../../../store/policies', () => ({
22+
usePoliciesStore: () => policiesState,
23+
}))
24+
25+
import {
26+
getSignatureTextUiDefaults,
27+
useSignatureTextPolicy,
28+
} from '../../../../views/Settings/PolicyWorkbench/settings/signature-text/useSignatureTextPolicy'
29+
30+
describe('useSignatureTextPolicy', () => {
31+
beforeEach(() => {
32+
for (const key of Object.keys(initialState)) {
33+
delete initialState[key]
34+
}
35+
36+
policiesState.policies = {}
37+
})
38+
39+
it('reads canonical UI defaults without leaking effective render mode', () => {
40+
Object.assign(initialState, {
41+
default_signature_text_template: 'Default template',
42+
default_template_font_size: '11.5',
43+
default_signature_font_size: '14.5',
44+
default_signature_width: '120',
45+
default_signature_height: '80',
46+
signature_render_mode: 'DESCRIPTION_ONLY',
47+
})
48+
49+
expect(getSignatureTextUiDefaults()).toEqual({
50+
template: 'Default template',
51+
templateFontSize: 11.5,
52+
signatureFontSize: 14.5,
53+
signatureWidth: 120,
54+
signatureHeight: 80,
55+
renderMode: 'GRAPHIC_AND_DESCRIPTION',
56+
})
57+
})
58+
59+
it('prefers and normalizes the effective policy payload when available', () => {
60+
policiesState.policies = {
61+
signature_text: {
62+
effectiveValue: JSON.stringify({
63+
template: 'Policy template',
64+
template_font_size: '10.25',
65+
signature_font_size: '13.75',
66+
signature_width: '101',
67+
signature_height: '66',
68+
render_mode: 'SIGNAME_AND_DESCRIPTION',
69+
}),
70+
},
71+
}
72+
Object.assign(initialState, {
73+
signature_text_template_error: 'Template error',
74+
signature_text_parsed: '<p>Parsed</p>',
75+
})
76+
77+
const { values } = useSignatureTextPolicy()
78+
79+
expect(values.value).toEqual({
80+
template: 'Policy template',
81+
templateFontSize: 10.25,
82+
signatureFontSize: 13.75,
83+
signatureWidth: 101,
84+
signatureHeight: 66,
85+
renderMode: 'SIGNAME_AND_DESCRIPTION',
86+
templateError: 'Template error',
87+
parsed: '<p>Parsed</p>',
88+
})
89+
})
90+
91+
it('falls back to legacy initial state values when no effective policy exists', () => {
92+
Object.assign(initialState, {
93+
signature_text_template: 'Legacy template',
94+
template_font_size: '12.5',
95+
signature_font_size: '16.5',
96+
signature_width: '155',
97+
signature_height: '95',
98+
signature_render_mode: 'DESCRIPTION_ONLY',
99+
signature_text_template_error: '',
100+
signature_text_parsed: '<p>Legacy parsed</p>',
101+
})
102+
103+
const { values } = useSignatureTextPolicy()
104+
105+
expect(values.value).toEqual({
106+
template: 'Legacy template',
107+
templateFontSize: 12.5,
108+
signatureFontSize: 16.5,
109+
signatureWidth: 155,
110+
signatureHeight: 95,
111+
renderMode: 'DESCRIPTION_ONLY',
112+
templateError: '',
113+
parsed: '<p>Legacy parsed</p>',
114+
})
115+
})
116+
})

src/views/Settings/PolicyWorkbench/settings/signature-text/useSignatureTextPolicy.ts

Lines changed: 42 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -6,40 +6,49 @@
66
import { computed, type ComputedRef } from 'vue'
77
import { loadState } from '@nextcloud/initial-state'
88
import { usePoliciesStore } from '../../../../../store/policies'
9-
import { getDefaultSignatureTextPolicyConfig } from './model'
9+
import {
10+
getDefaultSignatureTextPolicyConfig,
11+
normalizeSignatureTextPolicyConfig,
12+
type SignatureTextPolicyConfig,
13+
} from './model'
1014

1115
const SIGNATURE_TEXT_DEFAULTS = getDefaultSignatureTextPolicyConfig()
1216

13-
interface SignatureTextValues {
14-
template: string
15-
templateFontSize: number
16-
signatureFontSize: number
17-
signatureWidth: number
18-
signatureHeight: number
19-
renderMode: string
17+
interface SignatureTextValues extends SignatureTextPolicyConfig {
2018
templateError: string
2119
parsed: string
2220
}
2321

24-
export interface SignatureTextUiDefaults {
22+
export type SignatureTextUiDefaults = SignatureTextPolicyConfig
23+
24+
function readSignatureTextState(keys: {
2525
template: string
26-
templateFontSize: number
27-
signatureFontSize: number
28-
signatureWidth: number
29-
signatureHeight: number
30-
renderMode: string
26+
templateFontSize: string
27+
signatureFontSize: string
28+
signatureWidth: string
29+
signatureHeight: string
30+
renderMode?: string
31+
}, defaultRenderMode: string): SignatureTextPolicyConfig {
32+
return normalizeSignatureTextPolicyConfig({
33+
template: loadState<string>('libresign', keys.template, SIGNATURE_TEXT_DEFAULTS.template),
34+
template_font_size: loadState<number>('libresign', keys.templateFontSize, SIGNATURE_TEXT_DEFAULTS.templateFontSize),
35+
signature_font_size: loadState<number>('libresign', keys.signatureFontSize, SIGNATURE_TEXT_DEFAULTS.signatureFontSize),
36+
signature_width: loadState<number>('libresign', keys.signatureWidth, SIGNATURE_TEXT_DEFAULTS.signatureWidth),
37+
signature_height: loadState<number>('libresign', keys.signatureHeight, SIGNATURE_TEXT_DEFAULTS.signatureHeight),
38+
render_mode: keys.renderMode
39+
? loadState<string>('libresign', keys.renderMode, defaultRenderMode)
40+
: defaultRenderMode,
41+
})
3142
}
3243

3344
export function getSignatureTextUiDefaults(): SignatureTextUiDefaults {
34-
return {
35-
template: loadState<string>('libresign', 'default_signature_text_template', SIGNATURE_TEXT_DEFAULTS.template),
36-
templateFontSize: Number(loadState<number>('libresign', 'default_template_font_size', SIGNATURE_TEXT_DEFAULTS.templateFontSize)),
37-
signatureFontSize: Number(loadState<number>('libresign', 'default_signature_font_size', SIGNATURE_TEXT_DEFAULTS.signatureFontSize)),
38-
signatureWidth: Number(loadState<number>('libresign', 'default_signature_width', SIGNATURE_TEXT_DEFAULTS.signatureWidth)),
39-
signatureHeight: Number(loadState<number>('libresign', 'default_signature_height', SIGNATURE_TEXT_DEFAULTS.signatureHeight)),
40-
// Reset must use canonical default, not current effective value.
41-
renderMode: 'GRAPHIC_AND_DESCRIPTION',
42-
}
45+
return readSignatureTextState({
46+
template: 'default_signature_text_template',
47+
templateFontSize: 'default_template_font_size',
48+
signatureFontSize: 'default_signature_font_size',
49+
signatureWidth: 'default_signature_width',
50+
signatureHeight: 'default_signature_height',
51+
}, 'GRAPHIC_AND_DESCRIPTION')
4352
}
4453

4554
export function useSignatureTextPolicy(): { values: ComputedRef<SignatureTextValues> } {
@@ -48,32 +57,16 @@ export function useSignatureTextPolicy(): { values: ComputedRef<SignatureTextVal
4857
const values = computed<SignatureTextValues>(() => {
4958
const signatureTextPolicy = policiesStore.policies.signature_text
5059

51-
// Use policy value when present; otherwise fallback to existing initial state values.
52-
let policyValue = SIGNATURE_TEXT_DEFAULTS
53-
54-
if (signatureTextPolicy?.effectiveValue) {
55-
const decoded = typeof signatureTextPolicy.effectiveValue === 'string'
56-
? JSON.parse(signatureTextPolicy.effectiveValue)
57-
: signatureTextPolicy.effectiveValue
58-
59-
policyValue = {
60-
template: String(decoded.template ?? SIGNATURE_TEXT_DEFAULTS.template),
61-
templateFontSize: Number(decoded.template_font_size ?? SIGNATURE_TEXT_DEFAULTS.templateFontSize),
62-
signatureFontSize: Number(decoded.signature_font_size ?? SIGNATURE_TEXT_DEFAULTS.signatureFontSize),
63-
signatureWidth: Number(decoded.signature_width ?? SIGNATURE_TEXT_DEFAULTS.signatureWidth),
64-
signatureHeight: Number(decoded.signature_height ?? SIGNATURE_TEXT_DEFAULTS.signatureHeight),
65-
renderMode: String(decoded.render_mode ?? SIGNATURE_TEXT_DEFAULTS.renderMode),
66-
}
67-
} else {
68-
policyValue = {
69-
template: loadState<string>('libresign', 'signature_text_template', SIGNATURE_TEXT_DEFAULTS.template),
70-
templateFontSize: Number(loadState<number>('libresign', 'template_font_size', SIGNATURE_TEXT_DEFAULTS.templateFontSize)),
71-
signatureFontSize: Number(loadState<number>('libresign', 'signature_font_size', SIGNATURE_TEXT_DEFAULTS.signatureFontSize)),
72-
signatureWidth: Number(loadState<number>('libresign', 'signature_width', SIGNATURE_TEXT_DEFAULTS.signatureWidth)),
73-
signatureHeight: Number(loadState<number>('libresign', 'signature_height', SIGNATURE_TEXT_DEFAULTS.signatureHeight)),
74-
renderMode: String(loadState<string>('libresign', 'signature_render_mode', 'GRAPHIC_AND_DESCRIPTION')),
75-
}
76-
}
60+
const policyValue = signatureTextPolicy?.effectiveValue
61+
? normalizeSignatureTextPolicyConfig(signatureTextPolicy.effectiveValue)
62+
: readSignatureTextState({
63+
template: 'signature_text_template',
64+
templateFontSize: 'template_font_size',
65+
signatureFontSize: 'signature_font_size',
66+
signatureWidth: 'signature_width',
67+
signatureHeight: 'signature_height',
68+
renderMode: 'signature_render_mode',
69+
}, 'GRAPHIC_AND_DESCRIPTION')
7770

7871
// Only non-policy values come from loadState (error/parsing results)
7972
return {

0 commit comments

Comments
 (0)