Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions docs/DataStructure.md
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,7 @@ Supported trigger types for conditional questions:
| `date` | `date_range` | Date - range including its bounds (`YYYY-MM-DD`) |
| `datetime` | `date_range` | Deprecated date and time (`YYYY-MM-DD HH:mm`) |
| `time` | `date_range` | Time - range including its bounds (`HH:mm`) |
| `file` | `file_uploaded` | File - whether a file was uploaded |

A branch is shown when any of its conditions matches. Several branches can be shown at once.

Expand Down Expand Up @@ -372,6 +373,14 @@ All options in `optionIds` must be selected for the condition to match.

`min` and `max` use the answer format of the trigger type and are optional.

#### file_uploaded (for file)

```json
{ "type": "file_uploaded", "fileUploaded": true }
```

`"fileUploaded": false` matches when no file was uploaded.

### Conditional Question Example

A complete conditional question structure:
Expand Down
2 changes: 2 additions & 0 deletions lib/Constants.php
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,7 @@ class Constants {
public const CONDITION_TYPE_OPTION_SELECTED = 'option_selected';
public const CONDITION_TYPE_OPTIONS_COMBINATION = 'options_combination';
public const CONDITION_TYPE_DATE_RANGE = 'date_range';
public const CONDITION_TYPE_FILE_UPLOADED = 'file_uploaded';

/**
* Trigger types allowed for conditional questions
Expand All @@ -274,6 +275,7 @@ class Constants {
self::ANSWER_TYPE_DATE => [self::CONDITION_TYPE_DATE_RANGE],
self::ANSWER_TYPE_DATETIME => [self::CONDITION_TYPE_DATE_RANGE],
self::ANSWER_TYPE_TIME => [self::CONDITION_TYPE_DATE_RANGE],
self::ANSWER_TYPE_FILE => [self::CONDITION_TYPE_FILE_UPLOADED],
];

/**
Expand Down
12 changes: 10 additions & 2 deletions lib/Service/SubmissionService.php
Original file line number Diff line number Diff line change
Expand Up @@ -1131,8 +1131,8 @@ private function evaluateBranchConditions(string $triggerType, array $triggerAns
// Option ids arrive as numbers or strings depending on the trigger component
$selectedOptionIds = array_map('strval', array_filter($triggerAnswer, 'is_scalar'));

// An unanswered trigger activates no branch
if ($triggerAnswer === [] || ($triggerAnswer[0] ?? '') === '') {
// An unanswered trigger activates no branch, except "no file uploaded" for file triggers
if ($triggerType !== Constants::ANSWER_TYPE_FILE && ($triggerAnswer === [] || ($triggerAnswer[0] ?? '') === '')) {
return false;
}

Expand All @@ -1159,6 +1159,14 @@ private function evaluateBranchConditions(string $triggerType, array $triggerAns
}
}
return false;
case Constants::ANSWER_TYPE_FILE:
$hasFile = !empty($triggerAnswer);
foreach ($conditions as $condition) {
if (($condition['fileUploaded'] ?? true) === $hasFile) {
return true;
}
}
return false;
case Constants::ANSWER_TYPE_DATE:
case Constants::ANSWER_TYPE_DATETIME:
case Constants::ANSWER_TYPE_TIME:
Expand Down
30 changes: 30 additions & 0 deletions src/components/Conditional/BranchConditionEditor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -50,19 +50,32 @@
class="condition-date-input" />
</div>
</template>

<!-- File-based conditions -->
<template v-else-if="triggerType === 'file'">
<div class="condition-row">
<NcCheckboxRadioSwitch
:modelValue="fileUploadedCondition"
@update:modelValue="onFileConditionChange">
{{ t('forms', 'File is uploaded') }}
</NcCheckboxRadioSwitch>
</div>
</template>
</div>
</template>

<script>
import { t } from '@nextcloud/l10n'
import moment from '@nextcloud/moment'
import NcCheckboxRadioSwitch from '@nextcloud/vue/components/NcCheckboxRadioSwitch'
import NcDateTimePicker from '@nextcloud/vue/components/NcDateTimePicker'
import NcSelect from '@nextcloud/vue/components/NcSelect'

export default {
name: 'BranchConditionEditor',

components: {
NcCheckboxRadioSwitch,
NcDateTimePicker,
NcSelect,
},
Expand Down Expand Up @@ -236,6 +249,13 @@ export default {
},
},

/**
* File uploaded condition
*/
fileUploadedCondition() {
return this.branch.conditions?.[0]?.fileUploaded ?? true
},

/**
* Date picker type based on trigger type
*/
Expand Down Expand Up @@ -288,6 +308,16 @@ export default {
this.emitUpdate({ conditions })
},

/**
* Handle file condition change
*
* @param {boolean} checked Whether file is uploaded condition is checked
*/
onFileConditionChange(checked) {
const conditions = [{ fileUploaded: checked }]
this.emitUpdate({ conditions })
},

/**
* Update a condition property
*
Expand Down
19 changes: 17 additions & 2 deletions src/components/Questions/QuestionConditional.vue
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,10 @@ export default defineComponent({
label: t('forms', 'Date and time'),
types: ['date', 'time'],
},
{
label: t('forms', 'Other'),
types: ['file'],
},
]

return groups.map((group) => ({
Expand Down Expand Up @@ -507,8 +511,11 @@ export default defineComponent({
},

activeBranches() {
// An unanswered trigger activates no branch
if (!this.triggerValues || this.triggerValues.length === 0) {
// An unanswered trigger activates no branch, except "no file uploaded" for file triggers
if (
(!this.triggerValues || this.triggerValues.length === 0)
&& this.triggerType !== 'file'
) {
return null
}
return this.branches.filter((branch) =>
Expand Down Expand Up @@ -968,6 +975,14 @@ export default defineComponent({
return false
}

if (this.triggerType === 'file') {
const hasFile =
this.triggerValues.length > 0 && this.triggerValues[0] !== ''
return branch.conditions.some(
(c) => (c.fileUploaded ?? true) === hasFile,
)
}

if (['date', 'time'].includes(this.triggerType)) {
const dateValue = this.triggerValues[0] || ''
if (!dateValue) {
Expand Down
10 changes: 10 additions & 0 deletions tests/Unit/Service/FormsServiceTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1946,6 +1946,16 @@ public static function dataAreExtraSettingsValid() {
'questionType' => Constants::ANSWER_TYPE_CONDITIONAL,
'expected' => true
],
'valid-conditional-file-trigger' => [
'extraSettings' => [
'triggerType' => Constants::ANSWER_TYPE_FILE,
'branches' => [
['id' => 'branch-1', 'conditions' => [['type' => 'file_uploaded', 'value' => true]]]
]
],
'questionType' => Constants::ANSWER_TYPE_CONDITIONAL,
'expected' => true
],
'invalid-conditional-missing-triggerType' => [
'extraSettings' => [
'branches' => [
Expand Down
Loading