Skip to content

Commit 0a7dbe2

Browse files
refactor(vue3): migrate SignatureEngine to script setup ts
Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
1 parent e4f6fa9 commit 0a7dbe2

2 files changed

Lines changed: 137 additions & 36 deletions

File tree

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
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+
import { mount } from '@vue/test-utils'
8+
9+
import SignatureEngine from '../../../views/Settings/SignatureEngine.vue'
10+
11+
const loadStateMock = vi.fn()
12+
const emitMock = vi.fn()
13+
14+
vi.mock('@nextcloud/initial-state', () => ({
15+
loadState: (...args: unknown[]) => loadStateMock(...args),
16+
}))
17+
18+
vi.mock('@nextcloud/event-bus', () => ({
19+
emit: (...args: unknown[]) => emitMock(...args),
20+
}))
21+
22+
vi.mock('@nextcloud/l10n', () => ({
23+
t: vi.fn((_app: string, text: string) => text),
24+
translate: vi.fn((_app: string, text: string) => text),
25+
translatePlural: vi.fn((_app: string, singular: string, plural: string, count: number) => (count === 1 ? singular : plural)),
26+
n: vi.fn((_app: string, singular: string, plural: string, count: number) => (count === 1 ? singular : plural)),
27+
getLanguage: vi.fn(() => 'en'),
28+
getLocale: vi.fn(() => 'en'),
29+
isRTL: vi.fn(() => false),
30+
}))
31+
32+
const OCP = {
33+
AppConfig: {
34+
setValue: vi.fn(),
35+
},
36+
}
37+
38+
;(globalThis as typeof globalThis & { OCP: typeof OCP }).OCP = OCP
39+
40+
describe('SignatureEngine.vue', () => {
41+
beforeEach(() => {
42+
vi.clearAllMocks()
43+
loadStateMock.mockImplementation((_app: string, _key: string, fallback: unknown) => fallback)
44+
})
45+
46+
function createWrapper() {
47+
return mount(SignatureEngine, {
48+
global: {
49+
stubs: {
50+
NcSettingsSection: { template: '<div><slot /></div>' },
51+
NcSelect: true,
52+
},
53+
},
54+
})
55+
}
56+
57+
it('maps the initial state to the selected option', () => {
58+
loadStateMock.mockImplementation((_app: string, key: string, fallback: unknown) => {
59+
if (key === 'signature_engine') return 'PhpNative'
60+
return fallback
61+
})
62+
63+
const wrapper = createWrapper()
64+
65+
expect(wrapper.vm.selectedOption).toEqual({ id: 'PhpNative', label: 'Native' })
66+
})
67+
68+
it('updates the selected engine through the computed setter', () => {
69+
const wrapper = createWrapper()
70+
71+
wrapper.vm.selectedOption = { id: 'PhpNative', label: 'Native' }
72+
73+
expect(wrapper.vm.selectedEngineId).toBe('PhpNative')
74+
})
75+
76+
it('persists the engine and emits the change event on success', async () => {
77+
OCP.AppConfig.setValue.mockImplementation((_app: string, _key: string, _value: string, callbacks: { success: () => void }) => callbacks.success())
78+
const wrapper = createWrapper()
79+
80+
await wrapper.vm.saveEngine({ id: 'PhpNative', label: 'Native' })
81+
82+
expect(OCP.AppConfig.setValue).toHaveBeenCalledWith('libresign', 'signature_engine', 'PhpNative', expect.any(Object))
83+
expect(emitMock).toHaveBeenCalledWith('libresign:signature-engine:changed', 'PhpNative')
84+
})
85+
})

src/views/Settings/SignatureEngine.vue

Lines changed: 52 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -16,55 +16,71 @@
1616
</div>
1717
</NcSettingsSection>
1818
</template>
19-
<script>
19+
<script setup lang="ts">
2020
import { emit } from '@nextcloud/event-bus'
2121
import { loadState } from '@nextcloud/initial-state'
2222
import { t } from '@nextcloud/l10n'
23+
import { computed, ref } from 'vue'
2324
2425
import NcSelect from '@nextcloud/vue/components/NcSelect'
2526
import NcSettingsSection from '@nextcloud/vue/components/NcSettingsSection'
2627
27-
export default {
28+
defineOptions({
2829
name: 'SignatureEngine',
29-
components: {
30-
NcSettingsSection,
31-
NcSelect,
32-
},
33-
setup() {
34-
return { t }
30+
})
31+
32+
type SignatureEngineOption = {
33+
id: string
34+
label: string
35+
}
36+
37+
type AppConfigGlobal = {
38+
AppConfig: {
39+
setValue: (
40+
app: string,
41+
key: string,
42+
value: string,
43+
callbacks: { success: () => void }
44+
) => void
45+
}
46+
}
47+
48+
const selectedEngineId = ref(loadState('libresign', 'signature_engine', 'JSignPdf'))
49+
50+
const options = computed<SignatureEngineOption[]>(() => [
51+
{ id: 'JSignPdf', label: 'JSignPdf' },
52+
// TRANSLATORS "Native" refers to a signature engine that runs directly with PHP, without requiring external runtimes like Java
53+
{ id: 'PhpNative', label: t('libresign', 'Native') },
54+
])
55+
56+
const selectedOption = computed<SignatureEngineOption>({
57+
get() {
58+
return options.value.find((option) => option.id === selectedEngineId.value) ?? options.value[0]
3559
},
36-
data() {
37-
return {
38-
selectedEngineId: loadState('libresign', 'signature_engine', 'JSignPdf'),
39-
}
60+
set(value) {
61+
selectedEngineId.value = value?.id ?? 'JSignPdf'
4062
},
41-
computed: {
42-
options() {
43-
return [
44-
{ id: 'JSignPdf', label: 'JSignPdf' },
45-
// TRANSLATORS "Native" refers to a signature engine that runs directly with PHP, without requiring external runtimes like Java
46-
{ id: 'PhpNative', label: t('libresign', 'Native') },
47-
]
48-
},
49-
selectedOption: {
50-
get() {
51-
return this.options.find((o) => o.id === this.selectedEngineId) ?? this.options[0]
52-
},
53-
set(value) {
54-
this.selectedEngineId = value?.id ?? 'JSignPdf'
63+
})
64+
65+
function saveEngine(selected: SignatureEngineOption) {
66+
;(globalThis as typeof globalThis & { OCP: AppConfigGlobal }).OCP.AppConfig.setValue(
67+
'libresign',
68+
'signature_engine',
69+
selected.id,
70+
{
71+
success() {
72+
emit('libresign:signature-engine:changed', selected.id)
5573
},
5674
},
57-
},
58-
methods: {
59-
saveEngine(selected) {
60-
OCP.AppConfig.setValue('libresign', 'signature_engine', selected.id, {
61-
success() {
62-
emit('libresign:signature-engine:changed', selected.id)
63-
},
64-
})
65-
},
66-
},
75+
)
6776
}
77+
78+
defineExpose({
79+
selectedEngineId,
80+
options,
81+
selectedOption,
82+
saveEngine,
83+
})
6884
</script>
6985
<style scoped>
7086
.signature-engine-content {

0 commit comments

Comments
 (0)