Skip to content

Commit 2606188

Browse files
committed
feat: simplify ConflictPicker by providing content only + preview resize
Signed-off-by: John Molakvoæ <skjnldsv@protonmail.com>
1 parent a47ad15 commit 2606188

9 files changed

Lines changed: 204 additions & 107 deletions

File tree

cypress/components/ConflictPicker.cy.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
/* eslint-disable no-unused-expressions */
22
// dist file might not be built when running eslint only
33
// eslint-disable-next-line import/no-unresolved,n/no-missing-import
4+
import type { ConflictResolutionResult } from '../../lib'
5+
46
import { File as NcFile } from '@nextcloud/files'
57
import { openConflictPicker } from '../../dist/index.mjs'
68

@@ -95,7 +97,7 @@ describe('ConflictPicker resolving', () => {
9597
cy.get('[data-cy-conflict-picker-input-incoming="all"] input').check({ force: true })
9698
cy.get('[data-cy-conflict-picker-submit]').click()
9799

98-
promise.then((results) => {
100+
promise.then((results: ConflictResolutionResult) => {
99101
expect(results.selected).to.deep.equal(images)
100102
expect(results.renamed).to.have.length(0)
101103

@@ -128,7 +130,7 @@ describe('ConflictPicker resolving', () => {
128130
cy.get('[data-cy-conflict-picker-input-existing="all"] input').check({ force: true })
129131
cy.get('[data-cy-conflict-picker-submit]').click()
130132

131-
promise.then((results) => {
133+
promise.then((results: ConflictResolutionResult) => {
132134
expect(results.selected).to.have.length(0)
133135
expect(results.renamed).to.have.length(0)
134136

@@ -163,7 +165,7 @@ describe('ConflictPicker resolving', () => {
163165
cy.get('[data-cy-conflict-picker-submit]').click()
164166

165167
// We only return the files to handle
166-
promise.then((results) => {
168+
promise.then((results: ConflictResolutionResult) => {
167169
expect(results.selected).to.deep.equal([images[0]])
168170
expect(results.renamed).to.have.length(0)
169171

@@ -197,7 +199,7 @@ describe('ConflictPicker resolving', () => {
197199
cy.get('[data-cy-conflict-picker-input-existing="all"] input').check({ force: true })
198200
cy.get('[data-cy-conflict-picker-submit]').click()
199201

200-
promise.then((results) => {
202+
promise.then((results: ConflictResolutionResult) => {
201203
expect(results.selected).to.have.length(0)
202204
expect(results.renamed).to.have.length(2)
203205
expect(results.renamed[0].name).to.equal('image1 (1).jpg')
@@ -231,7 +233,7 @@ describe('ConflictPicker resolving', () => {
231233
cy.get('[data-cy-conflict-picker-fieldset]').should('have.length', 3)
232234
cy.get('[data-cy-conflict-picker-skip]').click()
233235

234-
promise.then((results) => {
236+
promise.then((results: ConflictResolutionResult) => {
235237
expect(results.selected).to.have.length(0)
236238
expect(results.renamed).to.have.length(0)
237239

cypress/tsconfig.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"extends": [
3+
"@tsconfig/cypress/tsconfig.json",
4+
"../tsconfig.json"
5+
],
6+
"include": ["./**/*.ts"],
7+
"compilerOptions": {
8+
"types": ["cypress"]
9+
}
10+
}

lib/components/ConflictPicker.vue

Lines changed: 44 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,11 @@
3838
</fieldset>
3939

4040
<!-- Files loop -->
41-
<NodesPicker v-for="(node, index) in conflicts"
41+
<NodesPicker v-for="(node, index) in files"
4242
ref="nodesPicker"
4343
:key="node.fileid"
44-
:incoming="files[index]"
45-
:existing="conflicts[index]"
44+
:incoming="conflicts[index]"
45+
:existing="files[index]"
4646
:new-selected.sync="newSelected"
4747
:old-selected.sync="oldSelected" />
4848
</form>
@@ -72,6 +72,7 @@
7272

7373
<script lang="ts">
7474
import type { ConflictResolutionResult } from '../index.ts'
75+
import type { PropType } from 'vue'
7576
7677
import { basename, extname } from 'path'
7778
import { Node } from '@nextcloud/files'
@@ -88,6 +89,8 @@ import { n, t } from '../utils/l10n.ts'
8889
import logger from '../utils/logger.ts'
8990
import NodesPicker from './NodesPicker.vue'
9091
92+
export type NodesPickerRef = InstanceType<typeof NodesPicker>
93+
9194
export default Vue.extend({
9295
name: 'ConflictPicker',
9396
@@ -109,45 +112,42 @@ export default Vue.extend({
109112
110113
/** All the existing files in the current directory */
111114
content: {
112-
type: Array as () => Node[],
113-
required: true,
114-
},
115-
116-
/** Existing files to be replaced */
117-
conflicts: {
118-
type: Array as () => Node[],
115+
type: Array as PropType<Node[]>,
119116
required: true,
120117
},
121118
122119
/** New files being moved/uploaded */
123-
files: {
124-
type: Array as () => (Node|File)[],
120+
conflicts: {
121+
type: Array as PropType<(Node|File)[]>,
125122
required: true,
126123
},
127124
},
128125
129126
data() {
130127
return {
128+
// computed list of conflicting files already present in the directory
129+
files: [] as Node[],
130+
131131
opened: true,
132132
blockedTitle: t('You need to select at least one version of each file to continue.'),
133-
newSelected: [] as Node[],
133+
newSelected: [] as (Node|File)[],
134134
oldSelected: [] as Node[],
135135
}
136136
},
137137
138138
computed: {
139139
name() {
140140
if (this?.dirname?.trim?.() !== '') {
141-
return n('{count} file conflict in {dirname}', '{count} file conflicts in {dirname}', this.files.length, {
142-
count: this.files.length,
141+
return n('{count} file conflict in {dirname}', '{count} file conflicts in {dirname}', this.conflicts.length, {
142+
count: this.conflicts.length,
143143
dirname: this.dirname,
144144
})
145145
}
146-
return n('{count} file conflict', '{count} files conflict', this.files.length, { count: this.files.length })
146+
return n('{count} file conflict', '{count} files conflict', this.conflicts.length, { count: this.conflicts.length })
147147
},
148148
149149
skipButtonLabel() {
150-
return n('Skip this file', 'Skip {count} files', this.files.length, { count: this.files.length })
150+
return n('Skip this file', 'Skip {count} files', this.conflicts.length, { count: this.conflicts.length })
151151
},
152152
153153
// Select all incoming files
@@ -164,7 +164,7 @@ export default Vue.extend({
164164
},
165165
166166
isAllNewSelected() {
167-
return this.newSelected.length === this.files.length
167+
return this.newSelected.length === this.conflicts.length
168168
},
169169
isNoneNewSelected() {
170170
return this.newSelected.length === 0
@@ -187,7 +187,7 @@ export default Vue.extend({
187187
},
188188
189189
isAllOldSelected() {
190-
return this.oldSelected.length === this.conflicts.length
190+
return this.oldSelected.length === this.files.length
191191
},
192192
isNoneOldSelected() {
193193
return this.oldSelected.length === 0
@@ -203,26 +203,35 @@ export default Vue.extend({
203203
}
204204
// If we're in an intermediate state, we need to check
205205
// if all files have at least one version selected.
206-
return this.$refs?.nodesPicker?.every?.(picker => picker.isEnoughSelected)
206+
return (this.$refs?.nodesPicker as NodesPickerRef[])?.every?.(picker => picker.isEnoughSelected)
207207
},
208208
},
209209
210210
beforeMount() {
211-
if (this.files.length === 0 || this.conflicts.length === 0) {
212-
this.onCancel()
213-
throw new Error('ConflictPicker: files and conflicts must not be empty')
211+
// Using map keep the same order
212+
this.files = this.conflicts.map((conflict: File|Node) => {
213+
const name = (conflict instanceof File) ? conflict.name : conflict.basename
214+
return this.content.find((node: Node) => node.basename === name)
215+
}).filter(Boolean) as Node[]
216+
logger.debug('ConflictPicker initialised', { files: this.files, conflicts: this.conflicts, content: this.content })
217+
218+
if (this.conflicts.length === 0 || this.files.length === 0) {
219+
const error = new Error('ConflictPicker: files and conflicts must not be empty')
220+
this.onCancel(error)
221+
throw error
214222
}
215223
216-
if (this.files.length !== this.conflicts.length) {
217-
this.onCancel()
218-
throw new Error('ConflictPicker: files and conflicts must have the same length')
224+
if (this.conflicts.length !== this.files.length) {
225+
const error = new Error('ConflictPicker: files and conflicts must have the same length')
226+
this.onCancel(error)
227+
throw error
219228
}
220229
},
221230
222231
methods: {
223-
onCancel() {
232+
onCancel(error?: Error) {
224233
this.opened = false
225-
this.$emit('cancel')
234+
this.$emit('cancel', error)
226235
},
227236
228237
onSkip() {
@@ -288,9 +297,9 @@ export default Vue.extend({
288297
/**
289298
* Get a unique name for a file based
290299
* on the existing directory content.
291-
* @param name The original file name with extension
292-
* @param names The existing directory content names
293-
* @return A unique name
300+
* @param {string} name The original file name with extension
301+
* @param {string} names The existing directory content names
302+
* @return {string} A unique name
294303
* TODO: migrate to @nextcloud/files
295304
*/
296305
getUniqueName(name: string, names: string[]): string {
@@ -322,20 +331,20 @@ export default Vue.extend({
322331
}
323332
},
324333
325-
onSelectAllNew(selected) {
334+
onSelectAllNew(selected: boolean) {
326335
if (selected) {
327336
logger.debug('Selected all new files')
328-
this.newSelected = this.files
337+
this.newSelected = this.conflicts
329338
} else {
330339
logger.debug('Cleared new selection')
331340
this.newSelected = []
332341
}
333342
},
334343
335-
onSelectAllOld(selected) {
344+
onSelectAllOld(selected: boolean) {
336345
if (selected) {
337346
logger.debug('Selected all existing files')
338-
this.oldSelected = this.conflicts
347+
this.oldSelected = this.files
339348
} else {
340349
logger.debug('Cleared old selection')
341350
this.oldSelected = []

0 commit comments

Comments
 (0)