Skip to content

Commit bb1647a

Browse files
pringelmannChartman123
authored andcommitted
fix: resolve Vue 3 regression bugs from migration
- Replace `type` with `variant` for NcDialog button definitions - Replace `@change` with `@update:modelValue` for date picker events - Guard against stale grid option IDs crashing ResultsSummary and Submission - Skip file question answers when restoring an edited submission - Pass `optionType` when bulk-creating options to avoid null bucket crash - Default `contentValid` prop to `true` in Question.vue - Pass `isLoggedIn` to router-view in Forms.vue - Fix NcTextArea container height in OptionInputDialog Signed-off-by: Peter Ringelmann <peter.ringelmann@nextcloud.com>
1 parent f57ef85 commit bb1647a

10 files changed

Lines changed: 61 additions & 27 deletions

File tree

src/Forms.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@
120120
<template v-else>
121121
<router-view
122122
:form="selectedForm"
123+
isLoggedIn
123124
:sidebarOpened="sidebarOpened"
124125
@update:form="updateSelectedForm"
125126
@update:sidebarOpened="sidebarOpened = $event"

src/components/OptionInputDialog.vue

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,14 @@
1111
:buttons="buttons"
1212
size="normal"
1313
@update:open="$emit('update:open', $event)">
14-
<NcTextArea
15-
v-model="enteredOptions"
16-
:label="t('forms', 'Add multiple options (one per line)')"
17-
:placeholder="t('forms', 'Add multiple options (one per line)')"
18-
resize="vertical"
19-
rows="10" />
14+
<div class="options-text-area">
15+
<NcTextArea
16+
v-model="enteredOptions"
17+
:label="t('forms', 'Add multiple options (one per line)')"
18+
:placeholder="t('forms', 'Add multiple options (one per line)')"
19+
resize="vertical"
20+
rows="10" />
21+
</div>
2022
<NcSelect
2123
:inputLabel="t('forms', 'Options')"
2224
multiple
@@ -117,4 +119,8 @@ export default defineComponent({
117119
flex-direction: column;
118120
gap: 2px 0;
119121
}
122+
123+
.options-text-area {
124+
height: 210px;
125+
}
120126
</style>

src/components/Questions/Question.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ export default {
243243
244244
contentValid: {
245245
type: Boolean,
246-
default: false,
246+
default: true,
247247
},
248248
249249
warningInvalid: {

src/components/Questions/QuestionDate.vue

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@
9696
:disabledDate="disabledDates"
9797
:disabledTime="disabledTimes"
9898
rangeSeparator=" - "
99-
@change="onValueChange" />
99+
@update:modelValue="onValueChange" />
100100
</div>
101101
</Question>
102102
</template>
@@ -162,11 +162,11 @@ export default {
162162
163163
time() {
164164
if (this.extraSettings?.dateRange || this.extraSettings?.timeRange) {
165-
return this.values
165+
return this.values?.[0]
166166
? [this.parse(this.values[0]), this.parse(this.values[1])]
167167
: null
168168
}
169-
return this.values ? this.parse(this.values[0]) : null
169+
return this.values?.[0] ? this.parse(this.values[0]) : null
170170
},
171171
172172
/**

src/components/Results/ResultsSummary.vue

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -340,30 +340,42 @@ export default {
340340
for (const rowId of Object.keys(answerJson)) {
341341
const columnId = answerJson[rowId]
342342
343-
matrix[rowId][columnId].answersCount++
343+
if (matrix[rowId]?.[columnId]) {
344+
matrix[rowId][columnId].answersCount++
345+
}
344346
}
345347
} else if (
346348
this.question.extraSettings.questionType
347349
=== GridCellType.Checkbox
348350
) {
349351
for (const rowId of Object.keys(answerJson)) {
352+
if (!Array.isArray(answerJson[rowId])) {
353+
continue
354+
}
350355
for (const columnId of answerJson[rowId]) {
351-
matrix[rowId][columnId].answersCount++
356+
if (matrix[rowId]?.[columnId]) {
357+
matrix[rowId][columnId].answersCount++
358+
}
352359
}
353360
}
354361
} else if (
355362
this.question.extraSettings.questionType === GridCellType.Number
356363
) {
357364
for (const rowId of Object.keys(answerJson)) {
365+
if (!matrix[rowId]) {
366+
continue
367+
}
358368
for (const columnId of Object.keys(answerJson[rowId])) {
359369
if ('' === answerJson[rowId][columnId]) {
360370
continue
361371
}
362372
363-
matrix[rowId][columnId].totalValue += parseFloat(
364-
answerJson[rowId][columnId],
365-
)
366-
matrix[rowId][columnId].answersCount++
373+
if (matrix[rowId][columnId]) {
374+
matrix[rowId][columnId].totalValue += parseFloat(
375+
answerJson[rowId][columnId],
376+
)
377+
matrix[rowId][columnId].answersCount++
378+
}
367379
}
368380
}
369381
}

src/components/Results/Submission.vue

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ export default {
160160
&& question.extraSettings.questionType === 'radio'
161161
) {
162162
squashedAnswers = Object.keys(gridValue)
163+
.filter((key) => optionsPerId[key] && optionsPerId[gridValue[key]])
163164
.map((key) => {
164165
return (
165166
optionsPerId[key].text
@@ -173,11 +174,16 @@ export default {
173174
&& question.extraSettings.questionType === 'checkbox'
174175
) {
175176
squashedAnswers = Object.keys(gridValue)
177+
.filter((key) => optionsPerId[key] && Array.isArray(gridValue[key]))
176178
.map((key) => {
177179
return (
178180
optionsPerId[key].text
179181
+ ': '
180182
+ gridValue[key]
183+
.filter(
184+
(optionId) =>
185+
optionsPerId[optionId],
186+
)
181187
.map(
182188
(optionId) =>
183189
optionsPerId[optionId].text,

src/components/SidebarTabs/SettingsSidebarTab.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@
6969
:showSecond="false"
7070
:modelValue="expirationDate"
7171
type="datetime"
72-
@change="onExpirationDateChange" />
72+
@update:modelValue="onExpirationDateChange" />
7373
<NcCheckboxRadioSwitch
7474
:modelValue="form.showExpiration"
7575
:disabled="locked"

src/mixins/QuestionMixin.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { emit } from '@nextcloud/event-bus'
88
import { generateOcsUrl } from '@nextcloud/router'
99
import debounce from 'debounce'
1010
import Question from '../components/Questions/Question.vue'
11-
import { INPUT_DEBOUNCE_MS } from '../models/Constants.ts'
11+
import { INPUT_DEBOUNCE_MS, OptionType } from '../models/Constants.ts'
1212
import logger from '../utils/Logger.js'
1313
import OcsResponse2Data from '../utils/OcsResponse2Data.js'
1414

@@ -399,7 +399,8 @@ export default {
399399
},
400400
),
401401
{
402-
optionTexts: answers, // Send the entire array of answers at once
402+
optionTexts: answers,
403+
optionType: OptionType.Choice,
403404
},
404405
)
405406
const newServerOptions = OcsResponse2Data(response) // Assuming this function can handle arrays

src/views/Results.vue

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -402,15 +402,15 @@ export default {
402402
{
403403
label: t('forms', 'Unlink spreadsheet'),
404404
icon: IconLinkVariantOffSvg,
405-
type: 'error',
405+
variant: 'error',
406406
callback: () => {
407407
this.onUnlinkFile()
408408
},
409409
},
410410
{
411411
label: t('forms', 'Create spreadsheet'),
412412
icon: IconLinkSvg,
413-
type: 'primary',
413+
variant: 'primary',
414414
callback: () => {
415415
this.onLinkFile()
416416
},
@@ -421,15 +421,15 @@ export default {
421421
{
422422
label: t('forms', 'Cancel'),
423423
icon: IconCancelSvg,
424-
type: 'tertiary',
424+
variant: 'tertiary',
425425
callback: () => {
426426
this.showConfirmDeleteDialog = false
427427
},
428428
},
429429
{
430430
label: t('forms', 'Delete responses'),
431431
icon: IconDeleteSvg,
432-
type: 'error',
432+
variant: 'error',
433433
callback: () => {
434434
this.deleteAllSubmissionsConfirmed()
435435
},

src/views/Submit.vue

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -125,12 +125,12 @@
125125
v-for="(question, index) in validQuestions"
126126
ref="questions"
127127
:key="question.id"
128+
v-bind="question"
128129
readOnly
129130
:answerType="answerTypes[question.type]"
130131
:index="index + 1"
131132
:maxStringLengths="maxStringLengths"
132133
:values="answers[question.id]"
133-
v-bind="question"
134134
@keydown.enter="onKeydownEnter"
135135
@keydown.ctrl.enter="onKeydownCtrlEnter"
136136
@update:values="(values) => onUpdate(question, values)" />
@@ -438,7 +438,7 @@ export default {
438438
{
439439
label: t('forms', 'Submit'),
440440
icon: IconCheckSvg,
441-
type: 'primary',
441+
variant: 'primary',
442442
callback: () => this.onConfirmedSubmit(),
443443
},
444444
]
@@ -457,7 +457,7 @@ export default {
457457
{
458458
label: t('forms', 'Leave'),
459459
icon: IconCheckSvg,
460-
type: 'primary',
460+
variant: 'primary',
461461
callback: () => this.confirmButtonCallback(true),
462462
},
463463
]
@@ -476,7 +476,7 @@ export default {
476476
{
477477
label: t('forms', 'Clear'),
478478
icon: IconCheckSvg,
479-
type: 'primary',
479+
variant: 'primary',
480480
callback: () => this.onResetSubmission(),
481481
},
482482
]
@@ -678,6 +678,14 @@ export default {
678678
`option ${text} could not be mapped to an option for question ${questionId}`,
679679
)
680680
}
681+
} else if (question.type === 'file') {
682+
// File answers cannot be restored when editing a submission —
683+
// the uploaded file has already been moved to permanent storage
684+
// and the temporary uploadedFileId no longer exists.
685+
// The user must re-upload files if needed.
686+
logger.debug(
687+
`Skipping file answer for question ${questionId} — cannot restore uploaded files`,
688+
)
681689
} else {
682690
answers[questionId].push(text)
683691
}

0 commit comments

Comments
 (0)