Skip to content

Commit f19c931

Browse files
committed
refactor: migrate filepicker to Vue3
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
1 parent 8aa8edf commit f19c931

15 files changed

Lines changed: 128 additions & 148 deletions

lib/components/FilePicker/FileList.spec.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ describe('FilePicker FileList', () => {
6262
const consoleWarning = vi.spyOn(console, 'warn')
6363

6464
const wrapper = shallowMount(FileList, {
65-
propsData: {
65+
props: {
6666
currentView: 'files',
6767
multiselect: false,
6868
allowPickDirectory: false,
@@ -80,7 +80,7 @@ describe('FilePicker FileList', () => {
8080

8181
it('header checkbox is not shown if multiselect is `false`', () => {
8282
const wrapper = shallowMount(FileList, {
83-
propsData: {
83+
props: {
8484
currentView: 'files',
8585
multiselect: false,
8686
allowPickDirectory: false,
@@ -95,7 +95,7 @@ describe('FilePicker FileList', () => {
9595

9696
it('header checkbox is shown if multiselect is `true`', async () => {
9797
const wrapper = shallowMount(FileList, {
98-
propsData: {
98+
props: {
9999
currentView: 'files',
100100
multiselect: true,
101101
allowPickDirectory: false,
@@ -111,15 +111,15 @@ describe('FilePicker FileList', () => {
111111
const selectAll = wrapper.find('[data-testid="select-all-checkbox"]')
112112
expect(selectAll.exists()).toBe(true)
113113
// there is an aria label
114-
expect(selectAll.props('ariaLabel')).toBeTruthy()
114+
expect(selectAll.attributes('arialabel')).toBeTruthy()
115115
// no checked
116-
expect(selectAll.props('modelValue')).toBe(false)
116+
expect(selectAll.attributes('modelvalue')).toBe('false')
117117
})
118118

119119
it('header checkbox is checked when all nodes are selected', async () => {
120120
const nodes = [...exampleNodes]
121121
const wrapper = shallowMount(FileList, {
122-
propsData: {
122+
props: {
123123
currentView: 'files',
124124
multiselect: true,
125125
allowPickDirectory: false,
@@ -131,14 +131,14 @@ describe('FilePicker FileList', () => {
131131
})
132132

133133
const selectAll = wrapper.find('[data-testid="select-all-checkbox"]')
134-
expect(selectAll.props('modelValue')).toBe(true)
134+
expect(selectAll.attributes('modelvalue')).toBe('true')
135135
})
136136

137137
describe('file list sorting', () => {
138138
it('is sorted initially by name', async () => {
139139
const nodes = [...exampleNodes]
140140
const wrapper = mount(FileList, {
141-
propsData: {
141+
props: {
142142
currentView: 'files',
143143
multiselect: true,
144144
allowPickDirectory: false,
@@ -169,7 +169,7 @@ describe('FilePicker FileList', () => {
169169
it('can sort descending by name', async () => {
170170
const nodes = [...exampleNodes]
171171
const wrapper = mount(FileList, {
172-
propsData: {
172+
props: {
173173
currentView: 'files',
174174
multiselect: true,
175175
allowPickDirectory: false,

lib/components/FilePicker/FileList.vue

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@
2020
<th :aria-sort="sortByName" class="row-name">
2121
<div class="header-wrapper">
2222
<span class="file-picker__header-preview" />
23-
<NcButton :wide="true"
24-
type="tertiary"
25-
data-test="file-picker_sort-name"
23+
<NcButton data-test="file-picker_sort-name"
24+
variant="tertiary"
25+
wide
2626
@click="toggleSorting('basename')">
2727
<template #icon>
2828
<IconSortAscending v-if="sortByName === 'ascending'" :size="20" />
@@ -34,7 +34,7 @@
3434
</div>
3535
</th>
3636
<th :aria-sort="sortBySize" class="row-size">
37-
<NcButton :wide="true" type="tertiary" @click="toggleSorting('size')">
37+
<NcButton variant="tertiary" wide @click="toggleSorting('size')">
3838
<template #icon>
3939
<IconSortAscending v-if="sortBySize === 'ascending'" :size="20" />
4040
<IconSortDescending v-else-if="sortBySize === 'descending'" :size="20" />
@@ -44,7 +44,7 @@
4444
</NcButton>
4545
</th>
4646
<th :aria-sort="sortByModified" class="row-modified">
47-
<NcButton :wide="true" type="tertiary" @click="toggleSorting('mtime')">
47+
<NcButton variant="tertiary" wide @click="toggleSorting('mtime')">
4848
<template #icon>
4949
<IconSortAscending v-if="sortByModified === 'ascending'" :size="20" />
5050
<IconSortDescending v-else-if="sortByModified === 'descending'" :size="20" />

lib/components/FilePicker/FileListRow.spec.ts

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ describe('FilePicker: FileListRow', () => {
2929
const consoleError = vi.spyOn(console, 'error')
3030

3131
const wrapper = shallowMount(FileListRow, {
32-
propsData: {
32+
props: {
3333
allowPickDirectory: true,
3434
selected: false,
3535
showCheckbox: true,
@@ -50,7 +50,7 @@ describe('FilePicker: FileListRow', () => {
5050

5151
it('shows checkbox based on `showCheckbox` property', async () => {
5252
const wrapper = shallowMount(FileListRow, {
53-
propsData: {
53+
props: {
5454
allowPickDirectory: true,
5555
selected: false,
5656
showCheckbox: true,
@@ -67,17 +67,19 @@ describe('FilePicker: FileListRow', () => {
6767

6868
it('Click checkbox triggers select', async () => {
6969
const wrapper = shallowMount(FileListRow, {
70-
propsData: {
70+
props: {
7171
allowPickDirectory: false,
7272
selected: false,
7373
showCheckbox: true,
7474
canPick: true,
7575
node,
7676
cropImagePreviews: true,
7777
},
78-
stubs: {
79-
NcCheckboxRadioSwitch: {
80-
template: '<label><input type="checkbox" @click="$emit(\'update:model-value\', true)" ></label>',
78+
global: {
79+
stubs: {
80+
NcCheckboxRadioSwitch: {
81+
template: '<label><input type="checkbox" @click="$emit(\'update:model-value\', true)" ></label>',
82+
},
8183
},
8284
},
8385
})
@@ -90,7 +92,7 @@ describe('FilePicker: FileListRow', () => {
9092

9193
it('Click element triggers select', async () => {
9294
const wrapper = shallowMount(FileListRow, {
93-
propsData: {
95+
props: {
9496
allowPickDirectory: false,
9597
selected: false,
9698
showCheckbox: true,
@@ -108,7 +110,7 @@ describe('FilePicker: FileListRow', () => {
108110

109111
it('Click element without checkbox triggers select', async () => {
110112
const wrapper = shallowMount(FileListRow, {
111-
propsData: {
113+
props: {
112114
allowPickDirectory: false,
113115
selected: false,
114116
showCheckbox: false,
@@ -126,7 +128,7 @@ describe('FilePicker: FileListRow', () => {
126128

127129
it('Enter triggers select', async () => {
128130
const wrapper = shallowMount(FileListRow, {
129-
propsData: {
131+
props: {
130132
allowPickDirectory: false,
131133
selected: false,
132134
showCheckbox: false,

lib/components/FilePicker/FileListRow.vue

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
{{ formatFileSize(node.size || 0) }}
3434
</td>
3535
<td class="row-modified">
36-
<NcDateTime :timestamp="node.mtime" :ignore-seconds="true" />
36+
<NcDateTime :timestamp ignore-seconds />
3737
</td>
3838
</tr>
3939
</template>
@@ -65,11 +65,13 @@ const props = defineProps<{
6565
6666
const emit = defineEmits<{
6767
/** Emitted when the selected state is changed */
68-
(e: 'update:selected', v: boolean): void
68+
'update:selected': [selected: boolean]
6969
/** Emitted when a directory was not selected but entered */
70-
(e: 'enter-directory', node: INode): void
70+
enterDirectory: [node: INode]
7171
}>()
7272
73+
const timestamp = computed(() => props.node.mtime ?? 0)
74+
7375
/**
7476
* The displayname of the current node (excluding file extension)
7577
*/
@@ -102,7 +104,7 @@ function toggleSelected() {
102104
*/
103105
function handleClick() {
104106
if (isDirectory.value) {
105-
emit('enter-directory', props.node)
107+
emit('enterDirectory', props.node)
106108
} else {
107109
toggleSelected()
108110
}
@@ -120,7 +122,7 @@ function handleKeyDown(event: KeyboardEvent) {
120122
</script>
121123

122124
<style scoped lang="scss">
123-
@use './FileList.scss';
125+
@use './FileList';
124126
125127
.file-picker {
126128
&__row {

lib/components/FilePicker/FilePicker.vue

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
- SPDX-License-Identifier: AGPL-3.0-or-later
44
-->
55
<template>
6-
<NcDialog :open.sync="isOpen"
6+
<NcDialog v-model:open="isOpen"
77
:container="container"
88
:buttons="dialogButtons"
99
:name="name"
@@ -13,16 +13,16 @@
1313
navigation-classes="file-picker__navigation"
1414
@update:open="handleClose">
1515
<template #navigation="{ isCollapsed }">
16-
<FilePickerNavigation :current-view.sync="currentView"
17-
:filter-string.sync="filterString"
18-
:is-collapsed="isCollapsed"
19-
:disabled-navigation="disabledNavigation" />
16+
<FilePickerNavigation v-model:current-view="currentView"
17+
v-model:filter-string="filterString"
18+
:is-collapsed
19+
:disabled-navigation />
2020
</template>
2121

2222
<div class="file-picker__main">
2323
<!-- Header title / file list breadcrumbs -->
2424
<FilePickerBreadcrumbs v-if="currentView === 'files'"
25-
:path.sync="currentPath"
25+
v-model:path="currentPath"
2626
:show-menu="allowPickDirectory"
2727
@create-node="onCreateFolder" />
2828
<div v-else class="file-picker__view">
@@ -32,8 +32,8 @@
3232
<!-- File list -->
3333
<!-- If loading or files found show file list, otherwise show empty content-->
3434
<FileList v-if="isLoading || filteredFiles.length > 0"
35-
:path.sync="currentPath"
36-
:selected-files.sync="selectedFiles"
35+
v-model:path="currentPath"
36+
v-model:selected-files="selectedFiles"
3737
:allow-pick-directory="allowPickDirectory"
3838
:current-view="currentView"
3939
:files="filteredFiles"
@@ -61,7 +61,7 @@
6161

6262
<script setup lang="ts">
6363
import type { Node } from '@nextcloud/files'
64-
import type { IFilePickerButton, IFilePickerButtonFactory, IFilePickerFilter } from '../types.ts'
64+
import type { IDialogButton, IFilePickerButton, IFilePickerButtonFactory, IFilePickerFilter } from '../types.ts'
6565
import type { IFilesViewId } from '../../composables/views.ts'
6666
6767
import IconFile from 'vue-material-design-icons/File.vue'
@@ -165,7 +165,7 @@ const dialogButtons = computed(() => {
165165
isHandlingCallback = true
166166
handleButtonClick(button.callback, nodes)
167167
},
168-
} as IFilePickerButton))
168+
} satisfies IDialogButton))
169169
})
170170
171171
/**

lib/components/FilePicker/FilePickerBreadcrumbs.vue

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
@click="emit('update:path', dir.path)" />
2020
</template>
2121
<template v-if="showMenu" #actions>
22-
<NcActions :open.sync="actionsOpen"
22+
<NcActions v-model:open="actionsOpen"
2323
:aria-label="t('Create directory')"
2424
:force-menu="true"
2525
:force-name="true"
@@ -30,7 +30,7 @@
3030
<IconPlus :size="20" />
3131
</template>
3232
<NcActionInput ref="nameInput"
33-
:value.sync="newNodeName"
33+
v-model="newNodeName"
3434
:label="t('New folder')"
3535
:placeholder="t('New folder name')"
3636
@submit="onSubmit"
@@ -45,8 +45,6 @@
4545
</template>
4646

4747
<script setup lang="ts">
48-
import type Vue from 'vue'
49-
5048
import IconFolder from 'vue-material-design-icons/Folder.vue'
5149
import IconHome from 'vue-material-design-icons/Home.vue'
5250
import IconPlus from 'vue-material-design-icons/Plus.vue'
@@ -55,7 +53,7 @@ import NcActions from '@nextcloud/vue/components/NcActions'
5553
import NcActionInput from '@nextcloud/vue/components/NcActionInput'
5654
import NcBreadcrumbs from '@nextcloud/vue/components/NcBreadcrumbs'
5755
import NcBreadcrumb from '@nextcloud/vue/components/NcBreadcrumb'
58-
import { computed, ref } from 'vue'
56+
import { computed, ref, useTemplateRef } from 'vue'
5957
import { t } from '../../utils/l10n'
6058
6159
const props = defineProps<{
@@ -83,7 +81,7 @@ const actionsOpen = ref(false)
8381
*/
8482
const newNodeName = ref('')
8583
86-
const nameInput = ref<Vue>()
84+
const nameInput = useTemplateRef('nameInput')
8785
8886
/**
8987
* Validate user folder name input

0 commit comments

Comments
 (0)