Skip to content

Commit bf0dcba

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

2 files changed

Lines changed: 200 additions & 73 deletions

File tree

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
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 DownloadBinaries from '../../../views/Settings/DownloadBinaries.vue'
10+
11+
const generateOcsUrlMock = vi.fn((path: string) => path)
12+
const useConfigureCheckStoreMock = vi.fn()
13+
const listenMock = vi.fn()
14+
15+
vi.mock('@nextcloud/l10n', () => ({
16+
t: vi.fn((_app: string, text: string, params?: Record<string, string>) => {
17+
if (!params) {
18+
return text
19+
}
20+
21+
return Object.entries(params).reduce((message, [key, value]) => {
22+
return message.replace(`{${key}}`, value)
23+
}, text)
24+
}),
25+
translate: vi.fn((_app: string, text: string) => text),
26+
translatePlural: vi.fn((_app: string, singular: string, plural: string, count: number) => (count === 1 ? singular : plural)),
27+
n: vi.fn((_app: string, singular: string, plural: string, count: number) => (count === 1 ? singular : plural)),
28+
getLanguage: vi.fn(() => 'en'),
29+
getLocale: vi.fn(() => 'en'),
30+
isRTL: vi.fn(() => false),
31+
}))
32+
33+
vi.mock('@nextcloud/router', () => ({
34+
generateOcsUrl: (path: string) => generateOcsUrlMock(path),
35+
}))
36+
37+
vi.mock('../../../store/configureCheck.js', () => ({
38+
useConfigureCheckStore: (...args: unknown[]) => useConfigureCheckStoreMock(...args),
39+
}))
40+
41+
const EventSourceMock = vi.fn(function(this: { listen: (event: string, callback: (payload: string | unknown[]) => void) => void }) {
42+
this.listen = (event: string, callback: (payload: string | unknown[]) => void) => listenMock(event, callback)
43+
})
44+
45+
const OC = {
46+
EventSource: EventSourceMock,
47+
}
48+
49+
;(globalThis as typeof globalThis & { OC: typeof OC }).OC = OC
50+
51+
describe('DownloadBinaries.vue', () => {
52+
beforeEach(() => {
53+
vi.clearAllMocks()
54+
listenMock.mockClear()
55+
useConfigureCheckStoreMock.mockReturnValue({
56+
items: [],
57+
state: 'need download',
58+
downloadInProgress: false,
59+
})
60+
})
61+
62+
function createWrapper() {
63+
return mount(DownloadBinaries, {
64+
global: {
65+
stubs: {
66+
NcSettingsSection: { template: '<div><slot /></div>' },
67+
NcButton: { template: '<button><slot /><slot name="icon" /></button>' },
68+
NcNoteCard: { template: '<div><slot /></div>' },
69+
NcProgressBar: true,
70+
NcLoadingIcon: true,
71+
},
72+
},
73+
})
74+
}
75+
76+
it('computes the download label from the configure check state', () => {
77+
const wrapper = createWrapper()
78+
79+
expect(wrapper.vm.labelDownloadAllBinaries).toBe('Download binaries')
80+
expect(wrapper.vm.description).toContain('186MB')
81+
})
82+
83+
it('subscribes to install progress events and updates state on completion', () => {
84+
const wrapper = createWrapper()
85+
const listeners = new Map<string, (payload: string | unknown[]) => void>()
86+
87+
listenMock.mockImplementation((event: string, callback: (payload: string | unknown[]) => void) => {
88+
listeners.set(event, callback)
89+
})
90+
91+
wrapper.vm.installAndValidate()
92+
93+
expect(generateOcsUrlMock).toHaveBeenCalledWith('/apps/libresign/api/v1/admin/install-and-validate')
94+
expect(OC.EventSource).toHaveBeenCalledTimes(1)
95+
96+
listeners.get('total_size')?.('{"java":25}')
97+
expect(wrapper.vm.configureCheckStore.state).toBe('downloading binaries')
98+
expect(wrapper.vm.downloadStatus.java).toBe(25)
99+
100+
listeners.get('errors')?.('["network failed"]')
101+
expect(wrapper.vm.errors).toEqual(['network failed'])
102+
expect(wrapper.vm.configureCheckStore.state).toBe('need download')
103+
104+
listeners.get('done')?.([])
105+
expect(wrapper.vm.configureCheckStore.state).toBe('done')
106+
expect(wrapper.vm.configureCheckStore.downloadInProgress).toBe(false)
107+
expect(Object.keys(wrapper.vm.downloadStatus)).toHaveLength(0)
108+
})
109+
})

src/views/Settings/DownloadBinaries.vue

Lines changed: 91 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,10 @@
3131
</div>
3232
</NcSettingsSection>
3333
</template>
34-
<script>
34+
<script setup lang="ts">
3535
import { t } from '@nextcloud/l10n'
3636
import { generateOcsUrl } from '@nextcloud/router'
37+
import { computed, reactive, ref } from 'vue'
3738
3839
import NcButton from '@nextcloud/vue/components/NcButton'
3940
import NcLoadingIcon from '@nextcloud/vue/components/NcLoadingIcon'
@@ -43,78 +44,95 @@ import NcSettingsSection from '@nextcloud/vue/components/NcSettingsSection'
4344
4445
import { useConfigureCheckStore } from '../../store/configureCheck.js'
4546
46-
export default {
47+
defineOptions({
4748
name: 'DownloadBinaries',
48-
components: {
49-
NcSettingsSection,
50-
NcButton,
51-
NcNoteCard,
52-
NcProgressBar,
53-
NcLoadingIcon,
54-
},
55-
setup() {
56-
const configureCheckStore = useConfigureCheckStore()
57-
return { t, configureCheckStore }
58-
},
59-
data() {
60-
return {
61-
errors: [],
62-
downloadStatus: {
63-
java: 0,
64-
jsignpdf: 0,
65-
cfssl: 0,
66-
},
67-
}
68-
},
69-
computed: {
70-
labelDownloadAllBinaries() {
71-
if (this.configureCheckStore.state === 'in progress') {
72-
return t('libresign', 'Loading …')
73-
} else if (this.configureCheckStore.state === 'downloading binaries') {
74-
return t('libresign', 'Downloading binaries')
75-
} else if (this.configureCheckStore.state === 'need download') {
76-
return t('libresign', 'Download binaries')
77-
} else if (this.configureCheckStore.state === 'done') {
78-
return t('libresign', 'Validate setup')
79-
}
80-
return t('libresign', 'Download binaries')
81-
},
82-
description() {
83-
if (this.configureCheckStore.state === 'downloading binaries'
84-
|| this.configureCheckStore.state === 'need download'
85-
) {
86-
return t('libresign', 'Binaries required to work. Download size could be nearly {size}, please wait a moment.', { size: '186MB' })
87-
}
88-
return ''
89-
},
90-
},
91-
methods: {
92-
installAndValidate() {
93-
const self = this
94-
const updateEventSource = new OC.EventSource(generateOcsUrl('/apps/libresign/api/v1/admin/install-and-validate'))
95-
this.configureCheckStore.state = 'in progress'
96-
this.configureCheckStore.downloadInProgress = true
97-
this.errors = []
98-
updateEventSource.listen('total_size', function(message) {
99-
self.configureCheckStore.state = 'downloading binaries'
100-
const downloadStatus = JSON.parse(message)
101-
Object.keys(downloadStatus).forEach(service => {
102-
self.downloadStatus[service] = downloadStatus[service]
103-
})
104-
})
105-
updateEventSource.listen('configure_check', function(items) {
106-
self.configureCheckStore.items = items
107-
})
108-
updateEventSource.listen('errors', function(message) {
109-
self.errors = JSON.parse(message)
110-
self.configureCheckStore.state = 'need download'
111-
})
112-
updateEventSource.listen('done', function() {
113-
self.downloadStatus = {}
114-
self.configureCheckStore.state = 'done'
115-
self.configureCheckStore.downloadInProgress = false
116-
})
117-
},
118-
},
49+
})
50+
51+
type ConfigureCheckStore = {
52+
items: unknown[]
53+
state: string
54+
downloadInProgress: boolean
11955
}
56+
57+
type DownloadStatus = Record<string, number>
58+
59+
type EventSourceInstance = {
60+
listen: (event: string, callback: (payload: string | unknown[]) => void) => void
61+
}
62+
63+
type OCGlobal = {
64+
EventSource: new (url: string) => EventSourceInstance
65+
}
66+
67+
const configureCheckStore = useConfigureCheckStore() as ConfigureCheckStore
68+
const errors = ref<string[]>([])
69+
const downloadStatus = reactive<DownloadStatus>({
70+
java: 0,
71+
jsignpdf: 0,
72+
cfssl: 0,
73+
})
74+
75+
const labelDownloadAllBinaries = computed(() => {
76+
if (configureCheckStore.state === 'in progress') {
77+
return t('libresign', 'Loading …')
78+
}
79+
if (configureCheckStore.state === 'downloading binaries') {
80+
return t('libresign', 'Downloading binaries')
81+
}
82+
if (configureCheckStore.state === 'done') {
83+
return t('libresign', 'Validate setup')
84+
}
85+
return t('libresign', 'Download binaries')
86+
})
87+
88+
const description = computed(() => {
89+
if (configureCheckStore.state === 'downloading binaries' || configureCheckStore.state === 'need download') {
90+
return t('libresign', 'Binaries required to work. Download size could be nearly {size}, please wait a moment.', { size: '186MB' })
91+
}
92+
return ''
93+
})
94+
95+
function installAndValidate() {
96+
const updateEventSource = new (globalThis as typeof globalThis & { OC: OCGlobal }).OC.EventSource(
97+
generateOcsUrl('/apps/libresign/api/v1/admin/install-and-validate'),
98+
)
99+
100+
configureCheckStore.state = 'in progress'
101+
configureCheckStore.downloadInProgress = true
102+
errors.value = []
103+
104+
updateEventSource.listen('total_size', (message) => {
105+
configureCheckStore.state = 'downloading binaries'
106+
const nextDownloadStatus = JSON.parse(String(message)) as DownloadStatus
107+
Object.entries(nextDownloadStatus).forEach(([service, progress]) => {
108+
downloadStatus[service] = progress
109+
})
110+
})
111+
112+
updateEventSource.listen('configure_check', (items) => {
113+
configureCheckStore.items = Array.isArray(items) ? items : []
114+
})
115+
116+
updateEventSource.listen('errors', (message) => {
117+
errors.value = JSON.parse(String(message)) as string[]
118+
configureCheckStore.state = 'need download'
119+
})
120+
121+
updateEventSource.listen('done', () => {
122+
Object.keys(downloadStatus).forEach((service) => {
123+
delete downloadStatus[service]
124+
})
125+
configureCheckStore.state = 'done'
126+
configureCheckStore.downloadInProgress = false
127+
})
128+
}
129+
130+
defineExpose({
131+
configureCheckStore,
132+
errors,
133+
downloadStatus,
134+
labelDownloadAllBinaries,
135+
description,
136+
installAndValidate,
137+
})
120138
</script>

0 commit comments

Comments
 (0)