@planning-inspectorate/dynamic-forms 3.6.2 → 3.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/components/task-list/index.njk +2 -2
- package/src/components/task-list/task-list-multi-section.njk +2 -2
- package/src/components/task-list/task-list-single-section.njk +2 -2
- package/src/components/unit-option-entry/question.js +2 -1
- package/src/components/utils/component-types.js +10 -10
- package/src/controller.js +2 -1
- package/src/lib/utils.js +10 -0
- package/src/lib/utils.test.js +17 -1
- package/src/questions/options-question.js +3 -2
- package/src/questions/options-question.test.js +83 -0
- package/src/questions/question-props.d.ts +65 -53
- package/src/validator/conditional-required-validator.js +2 -1
- package/src/validator/unit-option-entry-validator.js +2 -1
- package/src/validator/valid-option-validator.js +2 -1
- package/types/src/components/unit-option-entry/question.d.ts.map +1 -1
- package/types/src/components/utils/component-types.d.ts +9 -9
- package/types/src/controller.d.ts.map +1 -1
- package/types/src/lib/utils.d.ts +7 -0
- package/types/src/lib/utils.d.ts.map +1 -1
- package/types/src/questions/options-question.d.ts.map +1 -1
- package/types/src/validator/conditional-required-validator.d.ts.map +1 -1
- package/types/src/validator/unit-option-entry-validator.d.ts.map +1 -1
- package/types/src/validator/valid-option-validator.d.ts.map +1 -1
package/package.json
CHANGED
|
@@ -29,9 +29,9 @@
|
|
|
29
29
|
<div class="govuk-grid-row">
|
|
30
30
|
<div class="govuk-grid-column-full">
|
|
31
31
|
{% if summaryListData.sections | length > 1 %}
|
|
32
|
-
{{ multiTaskList(summaryListData.sections, journeyComplete, beforeSubmitButton) }}
|
|
32
|
+
{{ multiTaskList(summaryListData.sections, journeyComplete, beforeSubmitButton, submitButtonText) }}
|
|
33
33
|
{% elif summaryListData.sections | length == 1 %}
|
|
34
|
-
{{ singleTaskList(summaryListData.sections | first, journeyComplete, beforeSubmitButton) }}
|
|
34
|
+
{{ singleTaskList(summaryListData.sections | first, journeyComplete, beforeSubmitButton, submitButtonText) }}
|
|
35
35
|
{% endif %}
|
|
36
36
|
</div>
|
|
37
37
|
</div>
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
{% from "govuk/components/tag/macro.njk" import govukTag %}
|
|
3
3
|
{% from "govuk/components/button/macro.njk" import govukButton %}
|
|
4
4
|
|
|
5
|
-
{% macro multiTaskList(sections, journeyComplete, beforeSubmitButton) %}
|
|
5
|
+
{% macro multiTaskList(sections, journeyComplete, beforeSubmitButton, submitButtonText) %}
|
|
6
6
|
<ol class="app-task-list">
|
|
7
7
|
{% for section in sections %}
|
|
8
8
|
<li class="govuk-body govuk-!-margin-bottom-9">
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
<form action method="post">
|
|
47
47
|
<input type="hidden" name="_csrf" value="{{_csrf}}">
|
|
48
48
|
{{ govukButton({
|
|
49
|
-
text: "Accept & Submit",
|
|
49
|
+
text: submitButtonText | default("Accept & Submit", true),
|
|
50
50
|
type: "submit"
|
|
51
51
|
}) }}
|
|
52
52
|
</form>
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
{% from "govuk/components/button/macro.njk" import govukButton %}
|
|
4
4
|
{% from "govuk/components/warning-text/macro.njk" import govukWarningText %}
|
|
5
5
|
|
|
6
|
-
{% macro singleTaskList(section, journeyComplete, beforeSubmitButton) %}
|
|
6
|
+
{% macro singleTaskList(section, journeyComplete, beforeSubmitButton, submitButtonText) %}
|
|
7
7
|
{% if section.list.rows.length %}
|
|
8
8
|
{{ govukSummaryList(section.list) }}
|
|
9
9
|
{% endif %}
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
<form action method="post">
|
|
16
16
|
<input type="hidden" name="_csrf" value="{{_csrf}}">
|
|
17
17
|
{{ govukButton({
|
|
18
|
-
text: "Accept & Submit",
|
|
18
|
+
text: submitButtonText | default("Accept & Submit", true),
|
|
19
19
|
type: "submit"
|
|
20
20
|
}) }}
|
|
21
21
|
</form>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import nunjucks from 'nunjucks';
|
|
2
2
|
import { Question } from '../../questions/question.js';
|
|
3
3
|
import { conditionalIsJustHTML } from '../utils/question-utils.js';
|
|
4
|
+
import { toArray } from '#src/lib/utils.js';
|
|
4
5
|
|
|
5
6
|
const defaultOptionJoinString = ',';
|
|
6
7
|
|
|
@@ -132,7 +133,7 @@ export default class UnitOptionEntryQuestion extends Question {
|
|
|
132
133
|
const answers = {};
|
|
133
134
|
|
|
134
135
|
/** @type {string[]} */
|
|
135
|
-
const fields =
|
|
136
|
+
const fields = toArray(req.body[this.fieldName]);
|
|
136
137
|
const fieldValues = fields.map((x) => x.trim());
|
|
137
138
|
|
|
138
139
|
const selectedOptions = this.options.filter(({ value }) => {
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
export const COMPONENT_TYPES = Object.freeze({
|
|
2
|
-
|
|
2
|
+
ADDRESS: 'site-address',
|
|
3
3
|
BOOLEAN: 'boolean',
|
|
4
|
-
|
|
4
|
+
CHECKBOX: 'checkbox',
|
|
5
5
|
DATE: 'date',
|
|
6
6
|
DATE_PERIOD: 'date-period',
|
|
7
7
|
DATE_TIME: 'date-time',
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
SELECT: 'select',
|
|
11
|
-
SINGLE_LINE_INPUT: 'single-line-input',
|
|
8
|
+
EMAIL: 'email',
|
|
9
|
+
MANAGE_LIST: 'manage-list',
|
|
12
10
|
MULTI_FIELD_INPUT: 'multi-field-input',
|
|
13
11
|
NUMBER: 'number',
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
12
|
+
RADIO: 'radio',
|
|
13
|
+
SELECT: 'select',
|
|
14
|
+
SINGLE_LINE_INPUT: 'single-line-input',
|
|
15
|
+
TEXT_ENTRY: 'text-entry',
|
|
16
|
+
TEXT_ENTRY_REDACT: 'text-entry-redact',
|
|
17
|
+
UNIT_OPTION: 'unit-option'
|
|
18
18
|
});
|
package/src/controller.js
CHANGED
|
@@ -3,6 +3,7 @@ import questionUtils from './components/utils/question-utils.js';
|
|
|
3
3
|
import { answerObjectForManageListSaving } from '#src/components/manage-list/utils.js';
|
|
4
4
|
import { booleanToYesNoValue } from '#src/components/boolean/question.js';
|
|
5
5
|
import { MANAGE_LIST_ACTIONS } from '#src/components/manage-list/manage-list-actions.js';
|
|
6
|
+
import { toArray } from '#src/lib/utils.js';
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* @typedef {import('./journey/journey.js').Journey} Journey
|
|
@@ -64,7 +65,7 @@ function buildSectionRowViewModel(key, value, action) {
|
|
|
64
65
|
html: value
|
|
65
66
|
},
|
|
66
67
|
actions: {
|
|
67
|
-
items:
|
|
68
|
+
items: toArray(action)
|
|
68
69
|
}
|
|
69
70
|
};
|
|
70
71
|
}
|
package/src/lib/utils.js
CHANGED
|
@@ -28,3 +28,13 @@ export function trimTrailingSlash(str) {
|
|
|
28
28
|
if (typeof str !== 'string') return str;
|
|
29
29
|
return str.replace(/\/$/, '');
|
|
30
30
|
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Convert a value to an array, unless it is already
|
|
34
|
+
*
|
|
35
|
+
* @param {T|T[]} value
|
|
36
|
+
* @template T
|
|
37
|
+
*/
|
|
38
|
+
export function toArray(value) {
|
|
39
|
+
return Array.isArray(value) ? value : [value];
|
|
40
|
+
}
|
package/src/lib/utils.test.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { describe, it } from 'node:test';
|
|
2
2
|
import assert from 'node:assert';
|
|
3
|
-
import { trimTrailingSlash } from '#src/lib/utils.js';
|
|
3
|
+
import { toArray, trimTrailingSlash } from '#src/lib/utils.js';
|
|
4
4
|
|
|
5
5
|
describe('utils', () => {
|
|
6
6
|
describe('trimTrailingSlash', () => {
|
|
@@ -16,4 +16,20 @@ describe('utils', () => {
|
|
|
16
16
|
assert.strictEqual(trimTrailingSlash(5), 5);
|
|
17
17
|
});
|
|
18
18
|
});
|
|
19
|
+
describe('toArray', () => {
|
|
20
|
+
it('should create an array if a value is provided', () => {
|
|
21
|
+
const values = [true, false, 'string', 123, null, { hello: 'world' }];
|
|
22
|
+
for (const value of values) {
|
|
23
|
+
const asArray = toArray(value);
|
|
24
|
+
assert.ok(Array.isArray(asArray));
|
|
25
|
+
assert.strictEqual(asArray.length, 1);
|
|
26
|
+
assert.strictEqual(asArray[0], value);
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
it('should leave an array as-is', () => {
|
|
30
|
+
const array = [1, 'string', 2];
|
|
31
|
+
const asArray = toArray(array);
|
|
32
|
+
assert.strictEqual(array, asArray);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
19
35
|
});
|
|
@@ -2,6 +2,7 @@ import nunjucks from 'nunjucks';
|
|
|
2
2
|
import { Question } from './question.js';
|
|
3
3
|
import ValidOptionValidator from '../validator/valid-option-validator.js';
|
|
4
4
|
import { getConditionalFieldName } from '../components/utils/question-utils.js';
|
|
5
|
+
import { toArray } from '#src/lib/utils.js';
|
|
5
6
|
|
|
6
7
|
const defaultOptionJoinString = ',';
|
|
7
8
|
|
|
@@ -124,14 +125,14 @@ export default class OptionsQuestion extends Question {
|
|
|
124
125
|
async getDataToSave(req, journeyResponse) {
|
|
125
126
|
const answers = {};
|
|
126
127
|
|
|
127
|
-
const fields =
|
|
128
|
+
const fields = req.body[this.fieldName] !== undefined ? toArray(req.body[this.fieldName]) : [];
|
|
128
129
|
const fieldValues = fields.map((x) => x.trim());
|
|
129
130
|
|
|
130
131
|
const selectedOptions = this.options.filter(({ value }) => {
|
|
131
132
|
return fieldValues.includes(value);
|
|
132
133
|
});
|
|
133
134
|
|
|
134
|
-
if (
|
|
135
|
+
if (selectedOptions.length !== fieldValues.length)
|
|
135
136
|
throw new Error(`User submitted option(s) did not correlate with valid answers to ${this.fieldName} question`);
|
|
136
137
|
|
|
137
138
|
answers[this.fieldName] = fieldValues.join(this.optionJoinString);
|
|
@@ -220,4 +220,87 @@ describe('./src/dynamic-forms/question.js', () => {
|
|
|
220
220
|
assert.strictEqual(result.hello, 'hi');
|
|
221
221
|
});
|
|
222
222
|
});
|
|
223
|
+
describe('getDataToSave', () => {
|
|
224
|
+
it('should return selected options in object format', async () => {
|
|
225
|
+
const mockReq = {
|
|
226
|
+
body: {
|
|
227
|
+
[FIELDNAME]: 'blue'
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
const options = [
|
|
231
|
+
{
|
|
232
|
+
text: 'Blue',
|
|
233
|
+
value: 'blue'
|
|
234
|
+
},
|
|
235
|
+
{
|
|
236
|
+
text: 'Red',
|
|
237
|
+
value: 'red'
|
|
238
|
+
}
|
|
239
|
+
];
|
|
240
|
+
const expectedAnswer = {
|
|
241
|
+
answers: {
|
|
242
|
+
[FIELDNAME]: 'blue'
|
|
243
|
+
}
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
const question = getTestQuestion({ options });
|
|
247
|
+
const result = await question.getDataToSave(mockReq, {});
|
|
248
|
+
assert.deepStrictEqual(result, expectedAnswer);
|
|
249
|
+
});
|
|
250
|
+
it('if req.body field name is undefined then pass through with an empty answer', async () => {
|
|
251
|
+
const mockReq = {
|
|
252
|
+
body: {
|
|
253
|
+
[FIELDNAME]: undefined
|
|
254
|
+
}
|
|
255
|
+
};
|
|
256
|
+
const options = [
|
|
257
|
+
{
|
|
258
|
+
text: 'Blue',
|
|
259
|
+
value: 'blue'
|
|
260
|
+
},
|
|
261
|
+
{
|
|
262
|
+
text: 'Red',
|
|
263
|
+
value: 'red'
|
|
264
|
+
}
|
|
265
|
+
];
|
|
266
|
+
const expectedAnswer = {
|
|
267
|
+
answers: {
|
|
268
|
+
[FIELDNAME]: ''
|
|
269
|
+
}
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
const question = getTestQuestion({ options });
|
|
273
|
+
const result = await question.getDataToSave(mockReq, {});
|
|
274
|
+
assert.deepStrictEqual(result, expectedAnswer);
|
|
275
|
+
});
|
|
276
|
+
it('if submitted options contains invalid answers then throw error', async () => {
|
|
277
|
+
const mockReq = {
|
|
278
|
+
body: {
|
|
279
|
+
[FIELDNAME]: ['blue', 'green']
|
|
280
|
+
}
|
|
281
|
+
};
|
|
282
|
+
const options = [
|
|
283
|
+
{
|
|
284
|
+
text: 'Blue',
|
|
285
|
+
value: 'blue'
|
|
286
|
+
},
|
|
287
|
+
{
|
|
288
|
+
text: 'Red',
|
|
289
|
+
value: 'red'
|
|
290
|
+
}
|
|
291
|
+
];
|
|
292
|
+
|
|
293
|
+
const question = getTestQuestion({ options });
|
|
294
|
+
assert.rejects(
|
|
295
|
+
async () => question.getDataToSave(mockReq, {}),
|
|
296
|
+
(thrown) => {
|
|
297
|
+
assert.strictEqual(
|
|
298
|
+
thrown.message,
|
|
299
|
+
`User submitted option(s) did not correlate with valid answers to ${FIELDNAME} question`
|
|
300
|
+
);
|
|
301
|
+
return true;
|
|
302
|
+
}
|
|
303
|
+
);
|
|
304
|
+
});
|
|
305
|
+
});
|
|
223
306
|
});
|
|
@@ -1,40 +1,27 @@
|
|
|
1
1
|
import { DocType } from '@pins/common/src/document-types';
|
|
2
|
-
import {
|
|
3
|
-
import BaseValidator from '../validator/base-validator';
|
|
2
|
+
import { QuestionParameters } from '#question-types';
|
|
4
3
|
|
|
5
4
|
type QuestionTypes =
|
|
6
|
-
| 'checkbox'
|
|
7
|
-
| 'multi-file-upload'
|
|
8
5
|
| 'boolean'
|
|
9
|
-
| '
|
|
6
|
+
| 'checkbox'
|
|
10
7
|
| 'date'
|
|
11
8
|
| 'date-period'
|
|
12
|
-
| '
|
|
13
|
-
| '
|
|
14
|
-
| '
|
|
15
|
-
| 'single-line-input'
|
|
9
|
+
| 'date-time'
|
|
10
|
+
| 'email'
|
|
11
|
+
| 'manage-list'
|
|
16
12
|
| 'multi-field-input'
|
|
17
13
|
| 'number'
|
|
14
|
+
| 'radio'
|
|
15
|
+
| 'select'
|
|
16
|
+
| 'single-line-input'
|
|
18
17
|
| 'site-address'
|
|
19
|
-
| '
|
|
20
|
-
| '
|
|
18
|
+
| 'text-entry'
|
|
19
|
+
| 'text-entry-redact'
|
|
20
|
+
| 'unit-option';
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
type CommonQuestionProps = QuestionParameters & {
|
|
23
23
|
type: QuestionTypes;
|
|
24
|
-
|
|
25
|
-
question: string;
|
|
26
|
-
viewFolder?: string;
|
|
27
|
-
fieldName: string;
|
|
28
|
-
url?: string;
|
|
29
|
-
pageTitle?: string;
|
|
30
|
-
description?: string;
|
|
31
|
-
label?: string;
|
|
32
|
-
validators?: BaseValidator[];
|
|
33
|
-
html?: string;
|
|
34
|
-
hint?: string;
|
|
35
|
-
shouldDisplay?: (response: JourneyResponse) => boolean;
|
|
36
|
-
autocomplete?: string;
|
|
37
|
-
}
|
|
24
|
+
};
|
|
38
25
|
|
|
39
26
|
type Option =
|
|
40
27
|
| {
|
|
@@ -92,24 +79,14 @@ interface UnitOption {
|
|
|
92
79
|
};
|
|
93
80
|
}
|
|
94
81
|
|
|
95
|
-
type CheckboxQuestionProps = CommonQuestionProps & {
|
|
96
|
-
type: 'checkbox';
|
|
97
|
-
options: Option[];
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
type MultiFileUploadQuestionProps = CommonQuestionProps & {
|
|
101
|
-
type: 'multi-file-upload';
|
|
102
|
-
documentType: DocType;
|
|
103
|
-
};
|
|
104
|
-
|
|
105
82
|
type BooleanQuestionProps = CommonQuestionProps & {
|
|
106
83
|
type: 'boolean';
|
|
107
84
|
options?: Option[];
|
|
108
85
|
interfaceType?: 'checkbox' | 'radio';
|
|
109
86
|
};
|
|
110
87
|
|
|
111
|
-
type
|
|
112
|
-
type: '
|
|
88
|
+
type CheckboxQuestionProps = CommonQuestionProps & {
|
|
89
|
+
type: 'checkbox';
|
|
113
90
|
options: Option[];
|
|
114
91
|
};
|
|
115
92
|
|
|
@@ -117,51 +94,86 @@ type DateQuestionProps = CommonQuestionProps & {
|
|
|
117
94
|
type: 'date';
|
|
118
95
|
};
|
|
119
96
|
|
|
120
|
-
type
|
|
121
|
-
type: '
|
|
122
|
-
label?: string;
|
|
97
|
+
type DatePeriodQuestionProps = CommonQuestionProps & {
|
|
98
|
+
type: 'date-period';
|
|
123
99
|
};
|
|
124
100
|
|
|
125
|
-
type
|
|
126
|
-
type: '
|
|
127
|
-
|
|
128
|
-
|
|
101
|
+
type DateTimeQuestionProps = CommonQuestionProps & {
|
|
102
|
+
type: 'date-time';
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
type ManageListQuestionProps = CommonQuestionProps & {
|
|
106
|
+
type: 'manage-list';
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
type EmailQuestionProps = CommonQuestionProps & {
|
|
110
|
+
type: 'email';
|
|
129
111
|
};
|
|
130
112
|
|
|
131
113
|
type MultiFieldInputQuestionProps = CommonQuestionProps & {
|
|
132
114
|
type: 'multi-field-input';
|
|
133
|
-
label?: string;
|
|
134
115
|
inputAttributes?: Record<string, string>;
|
|
135
116
|
inputFields: InputField[];
|
|
136
117
|
formatType?: 'contactDetails' | 'standard';
|
|
137
118
|
};
|
|
138
119
|
|
|
120
|
+
type MultiFileUploadQuestionProps = CommonQuestionProps & {
|
|
121
|
+
type: 'multi-file-upload';
|
|
122
|
+
documentType: DocType;
|
|
123
|
+
};
|
|
124
|
+
|
|
139
125
|
type NumberEntryQuestionProps = CommonQuestionProps & {
|
|
140
126
|
type: 'number';
|
|
141
|
-
label?: string;
|
|
142
127
|
suffix?: string;
|
|
143
128
|
};
|
|
144
129
|
|
|
130
|
+
type RadioQuestionProps = CommonQuestionProps & {
|
|
131
|
+
type: 'radio';
|
|
132
|
+
options: Option[];
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
type SelectQuestionProps = CommonQuestionProps & {
|
|
136
|
+
type: 'select';
|
|
137
|
+
options: Option[];
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
type SingleLineInputQuestionProps = CommonQuestionProps & {
|
|
141
|
+
type: 'single-line-input';
|
|
142
|
+
inputAttributes?: Record<string, string>;
|
|
143
|
+
};
|
|
144
|
+
|
|
145
145
|
type SiteAddressQuestionProps = CommonQuestionProps & {
|
|
146
146
|
type: 'site-address';
|
|
147
147
|
};
|
|
148
148
|
|
|
149
|
+
type TextEntryQuestionProps = CommonQuestionProps & {
|
|
150
|
+
type: 'text-entry';
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
type TextEntryRedactQuestionProps = CommonQuestionProps & {
|
|
154
|
+
type: 'text-entry-redact';
|
|
155
|
+
};
|
|
156
|
+
|
|
149
157
|
type UnitOptionEntryQuestionProps = CommonQuestionProps & {
|
|
150
158
|
type: 'unit-option';
|
|
151
159
|
conditionalFieldName: string;
|
|
152
160
|
options: UnitOption[];
|
|
153
|
-
label?: string;
|
|
154
161
|
};
|
|
155
162
|
|
|
156
163
|
export type QuestionProps =
|
|
157
|
-
| CheckboxQuestionProps
|
|
158
|
-
| MultiFileUploadQuestionProps
|
|
159
164
|
| BooleanQuestionProps
|
|
160
|
-
|
|
|
165
|
+
| CheckboxQuestionProps
|
|
161
166
|
| DateQuestionProps
|
|
162
|
-
|
|
|
163
|
-
|
|
|
167
|
+
| DatePeriodQuestionProps
|
|
168
|
+
| DateTimeQuestionProps
|
|
169
|
+
| ManageListQuestionProps
|
|
170
|
+
| EmailQuestionProps
|
|
164
171
|
| MultiFieldInputQuestionProps
|
|
165
172
|
| NumberEntryQuestionProps
|
|
173
|
+
| RadioQuestionProps
|
|
174
|
+
| SelectQuestionProps
|
|
175
|
+
| SingleLineInputQuestionProps
|
|
166
176
|
| SiteAddressQuestionProps
|
|
177
|
+
| TextEntryQuestionProps
|
|
178
|
+
| TextEntryRedactQuestionProps
|
|
167
179
|
| UnitOptionEntryQuestionProps;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { body } from 'express-validator';
|
|
2
2
|
|
|
3
3
|
import BaseValidator from './base-validator.js';
|
|
4
|
+
import { toArray } from '#src/lib/utils.js';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* @typedef {import('../questions/question.js')} Question
|
|
@@ -52,7 +53,7 @@ export default class ConditionalRequiredValidator extends BaseValidator {
|
|
|
52
53
|
|
|
53
54
|
isValueIncluded(questionObj, value) {
|
|
54
55
|
return body(questionObj.fieldName).custom((existingValues) => {
|
|
55
|
-
existingValues =
|
|
56
|
+
existingValues = toArray(existingValues);
|
|
56
57
|
return existingValues.includes(value);
|
|
57
58
|
});
|
|
58
59
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { body } from 'express-validator';
|
|
2
2
|
|
|
3
3
|
import BaseValidator from './base-validator.js';
|
|
4
|
+
import { toArray } from '#src/lib/utils.js';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* @typedef {import('../questions/question.js')} Question
|
|
@@ -81,7 +82,7 @@ export default class UnitOptionEntryValidator extends BaseValidator {
|
|
|
81
82
|
|
|
82
83
|
isValueIncluded(questionObj, value) {
|
|
83
84
|
return body(questionObj.fieldName).custom((existingValues) => {
|
|
84
|
-
existingValues =
|
|
85
|
+
existingValues = toArray(existingValues);
|
|
85
86
|
return existingValues.includes(value);
|
|
86
87
|
});
|
|
87
88
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { body } from 'express-validator';
|
|
2
2
|
|
|
3
3
|
import BaseValidator from './base-validator.js';
|
|
4
|
+
import { toArray } from '#src/lib/utils.js';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* @typedef {import('../questions/options-question.js')} OptionsQuestion
|
|
@@ -33,7 +34,7 @@ export default class ValidOptionValidator extends BaseValidator {
|
|
|
33
34
|
return body(questionObj.fieldName)
|
|
34
35
|
.custom((value) => {
|
|
35
36
|
if (!value) return true;
|
|
36
|
-
value =
|
|
37
|
+
value = toArray(value);
|
|
37
38
|
return value.every((element) => questionObj.options.map((option) => option.value).includes(element));
|
|
38
39
|
})
|
|
39
40
|
.withMessage(this.errorMessage);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"question.d.ts","sourceRoot":"","sources":["../../../../src/components/unit-option-entry/question.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"question.d.ts","sourceRoot":"","sources":["../../../../src/components/unit-option-entry/question.js"],"names":[],"mappings":"AAOA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH;IACC,gCAAgC;IAChC,SADW,KAAK,CAAC,UAAU,CAAC,CACpB;IAqBP,0BAAgD;IAEhD,WAAkB;IAClB,yBAA+C;IAGhD;;;;;;;;;;;;OAYG;IACH,gDAVW,OAAO,UAAU,EAAE,OAAO,mBAC1B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,YACvB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,WACvB,OAAO,oCAAoC,EAAE,+BAA+B,GAC1E,OAAO,WAAW,EAAE,iBAAiB,GAAG;QAChD,QAAQ,EAAE,OAAO,WAAW,EAAE,iBAAiB,CAAC,UAAU,CAAC,GAAG;YAC5D,OAAO,EAAC,UAAU,EAAE,CAAA;SACrB,CAAA;KACF,CAmDH;IAED;;;;;OAKG,CACH,yCAHW,eAAe,GACb,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAC,CAgCzD;CAoBD;;;;;;;;;yBAvKY;IACR,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,SAAS,CAAC,EAAE,WAAW,CAAC;IACxB,WAAW,EAAE;QACX,SAAS,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;QACnB,KAAK,CAAC,EAAE,OAAO,CAAC;QACZ,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,IAAI,CAAC,EAAE,MAAM,CAAC;QAClB,gBAAgB,CAAC,EAAE,MAAM,CAAC;KAC3B,CAAA;CACH;yBA5BsB,6BAA6B"}
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
export const COMPONENT_TYPES: Readonly<{
|
|
2
|
-
|
|
2
|
+
ADDRESS: "site-address";
|
|
3
3
|
BOOLEAN: "boolean";
|
|
4
|
-
|
|
4
|
+
CHECKBOX: "checkbox";
|
|
5
5
|
DATE: "date";
|
|
6
6
|
DATE_PERIOD: "date-period";
|
|
7
7
|
DATE_TIME: "date-time";
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
SELECT: "select";
|
|
11
|
-
SINGLE_LINE_INPUT: "single-line-input";
|
|
8
|
+
EMAIL: "email";
|
|
9
|
+
MANAGE_LIST: "manage-list";
|
|
12
10
|
MULTI_FIELD_INPUT: "multi-field-input";
|
|
13
11
|
NUMBER: "number";
|
|
14
|
-
|
|
12
|
+
RADIO: "radio";
|
|
13
|
+
SELECT: "select";
|
|
14
|
+
SINGLE_LINE_INPUT: "single-line-input";
|
|
15
|
+
TEXT_ENTRY: "text-entry";
|
|
16
|
+
TEXT_ENTRY_REDACT: "text-entry-redact";
|
|
15
17
|
UNIT_OPTION: "unit-option";
|
|
16
|
-
EMAIL: "email";
|
|
17
|
-
MANAGE_LIST: "manage-list";
|
|
18
18
|
}>;
|
|
19
19
|
//# sourceMappingURL=component-types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../src/controller.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../src/controller.js"],"names":[],"mappings":"AAwEA;;;GAGG;AACH,qCAHW,MAAM,OAKhB;AAED;;;;;GAKG;AACH,sDAHW,MAAM,YACN,MAAM,gBA8DhB;AAED;;;;GAIG;AACH,2DA0CC;AAED;;;;;;;;;;GAUG;AAEH;;GAEG;AAEH;;;;GAIG;AACH,oCAJW,UAAU,gCACV,OAAO,OAuFjB;sBAtSY,OAAO,sBAAsB,EAAE,OAAO;uBACtC,OAAO,yBAAyB,EAAE,QAAQ;;;aAMzC,MAAM;YACN,MAAM;UAEjB;QAAiC,IAAI,EAA1B,KAAK,CAAE,OAAO,CAAC;KAC5B;;;SAIa;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE;WAChB;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE;;eAC1B,UAAU,EAAE;;;;UAKrB,MAAM;UACN,MAAM;;;;;;eA0KN,MAAM;iBACN,MAAM;sBACN,OAAO;;;;;;;yBAOR,CAAC,MAAM,EAAE,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC"}
|
package/types/src/lib/utils.d.ts
CHANGED
|
@@ -16,4 +16,11 @@ export function capitalize(str: string | any): string;
|
|
|
16
16
|
* @returns {string}
|
|
17
17
|
*/
|
|
18
18
|
export function trimTrailingSlash(str?: string): string;
|
|
19
|
+
/**
|
|
20
|
+
* Convert a value to an array, unless it is already
|
|
21
|
+
*
|
|
22
|
+
* @param {T|T[]} value
|
|
23
|
+
* @template T
|
|
24
|
+
*/
|
|
25
|
+
export function toArray<T>(value: T | T[]): T[];
|
|
19
26
|
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/lib/utils.js"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,8BAHW,MAAM,GACJ,MAAM,CAMlB;AAED;;;GAGG;AACH,gCAHW,MAAM,GAAC,GAAG,GACR,MAAM,CAKlB;AAED;;;;;GAKG;AACH,wCAHW,MAAM,GACJ,MAAM,CAKlB"}
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/lib/utils.js"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,8BAHW,MAAM,GACJ,MAAM,CAMlB;AAED;;;GAGG;AACH,gCAHW,MAAM,GAAC,GAAG,GACR,MAAM,CAKlB;AAED;;;;;GAKG;AACH,wCAHW,MAAM,GACJ,MAAM,CAKlB;AAED;;;;;GAKG;AACH,wBAFa,CAAC,SADH,CAAC,GAAC,CAAC,EAAE,OAKf"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"options-question.d.ts","sourceRoot":"","sources":["../../../src/questions/options-question.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"options-question.d.ts","sourceRoot":"","sources":["../../../src/questions/options-question.js"],"names":[],"mappings":"AAQA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH;;GAEG;AAEH;IAIC;;;OAGG;IACH,oBAHW,OAAO,iBAAiB,EAAE,kBAAkB,EAgBtD;IApBD,4BAA4B;IAC5B,SADW,KAAK,CAAC,MAAM,CAAC,CAChB;IAkBP,yBAA+C;IAGhD;;;;;;;;OAQG;IACH,kCAPW,OAAO,UAAU,EAAE,OAAO,WAC1B,OAAO,UAAU,EAAE,OAAO,mBAC1B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,YACvB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,WACvB,OAAO,oCAAoC,EAAE,+BAA+B,OAmDtF;CAmCD;qBA9IY;IACR,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,SAAS,CAAC,EAAE,WAAW,CAAC;IACxB,WAAW,CAAC,EAAE;QACZ,QAAQ,EAAE,MAAM,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;QACb,SAAS,EAAE,MAAM,CAAC;QACd,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,IAAI,CAAC,EAAE,MAAM,CAAC;QAClB,KAAK,CAAC,EAAE,OAAO,CAAC;QACZ,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,IAAI,CAAC,EAAE,MAAM,CAAA;KAClB,CAAC;IACA,eAAe,CAAC,EAAE;QAChB,IAAI,EAAE,MAAM,CAAC;KAChB,CAAA;CACH;+BAIU,GAAsC,GAAG;IAAE,QAAQ,EAAE;QAAE,OAAO,EAAE,MAAM,EAAE,CAAA;KAAE,CAAA;CAAE;yBAhChE,eAAe"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"conditional-required-validator.d.ts","sourceRoot":"","sources":["../../../src/validator/conditional-required-validator.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"conditional-required-validator.d.ts","sourceRoot":"","sources":["../../../src/validator/conditional-required-validator.js"],"names":[],"mappings":"AAKA;;GAEG;AAEH;;;GAGG;AACH;IAMC;;;OAGG;IACH,2BAFW,MAAM,EAQhB;IAED;;;OAGG;IACH,sBAFW,QAAQ,OAclB;IAED,+DAEC;IAED,2FAKC;CACD;;0BAzDyB,qBAAqB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"unit-option-entry-validator.d.ts","sourceRoot":"","sources":["../../../src/validator/unit-option-entry-validator.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"unit-option-entry-validator.d.ts","sourceRoot":"","sources":["../../../src/validator/unit-option-entry-validator.js"],"names":[],"mappings":"AAKA;;GAEG;AAEH;;;GAGG;AACH;IACC;;;;;;;;OAQG;IAEH,oEARG;QAAwB,YAAY;QACZ,IAAI;QACJ,GAAG;QACH,GAAG;QACJ,KAAK;QACJ,YAAY;KAAC,EAWvC;IALA,aAA2B;IAC3B,wBAAc;IACd,wBAAc;IACd,WAAkB;IAClB,qBAA0D;IAG3D;;;OAGG;IACH,sBAFW,QAAQ,OA4ClB;IAED,2FAKC;CACD;;0BAtFyB,qBAAqB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"valid-option-validator.d.ts","sourceRoot":"","sources":["../../../src/validator/valid-option-validator.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"valid-option-validator.d.ts","sourceRoot":"","sources":["../../../src/validator/valid-option-validator.js"],"names":[],"mappings":"AAKA;;GAEG;AAEH;;;GAGG;AACH;IACC;;;OAGG;IACH,2BAFW,MAAM,EAUhB;IAED;;;OAGG;IACH,sBAFW,eAAe,+CAUzB;CACD;;0BAvCyB,qBAAqB"}
|